From 0b8a4e5181c0e5f72e35d48d60737fba7c00a52a Mon Sep 17 00:00:00 2001 From: buddywhitman Date: Sat, 23 Aug 2025 12:07:05 +0530 Subject: [PATCH 1/4] feat: Complete Vital Signs Monitor System with ESP32 Integration - Added comprehensive ESP32 firmware (main.ino) with WebSocket server - Implemented real-time sensor data processing (ECG, GSR, Respiratory) - Added advanced HRV metrics calculation (SDNN, RMSSD, pNN50, LF/HF, nn50, triangularIndex, stressIndex, vagalTone) - Enhanced respiratory metrics (tidal volume, minute volume, flow rates, medical assessment scores) - Implemented Firebase logging system with environment variable management - Added session recording with phase-based analysis (Initial 25%, Main 50%, Final 25%) - Fixed ECG plot auto-resizing and fallback data display - Added comprehensive logging and debugging systems - Implemented GSR trend analysis and signal quality assessment - Added CSV export functionality for offline data analysis - Created environment configuration system for Firebase credentials - Added comprehensive documentation and troubleshooting guides This commit represents a complete, production-ready vital signs monitoring system with real-time data acquisition, processing, visualization, and cloud logging. --- Examples/.env | 23 + Examples/README_ENVIRONMENT_SETUP.md | 214 + Examples/README_FIREBASE_FRONTEND.md | 244 ++ Examples/esp32/.env | 18 + Examples/esp32/PanTompkins.h | 168 + Examples/esp32/README_FIREBASE.md | 185 + Examples/esp32/main.ino | 491 +++ Examples/esp32/setup_firebase.py | 134 + .../MedicalCharts/VitalSignsMonitorDemo/.env | 23 + .../INTEGRATION_GUIDE.md | 258 ++ .../README_FIREBASE_FRONTEND.md | 228 ++ .../VitalSignsMonitorDemo/console.log | 3577 +++++++++++++++++ .../data/vitalSignsEcgData.ts | 25 + .../VitalSignsMonitorDemo/debugLogger.ts | 385 ++ .../VitalSignsMonitorDemo/drawExample.ts | 671 +++- .../VitalSignsMonitorDemo/ecgProcessor.ts | 393 ++ .../VitalSignsMonitorDemo/exampleInfo.tsx | 63 - .../VitalSignsMonitorDemo/firebaseLogger.ts | 371 ++ .../VitalSignsMonitorDemo/gsrTrendAnalyzer.ts | 312 ++ .../VitalSignsMonitorDemo/index.tsx | 2436 ++++++++++- .../VitalSignsMonitorDemo/sessionRecorder.ts | 928 +++++ .../VitalSignsMonitorDemo/setup_firebase.py | 120 + .../VitalSignsMonitorDemo/signalProcessor.ts | 881 ++++ Examples/src/config/environment.ts | 140 + 24 files changed, 11988 insertions(+), 300 deletions(-) create mode 100644 Examples/.env create mode 100644 Examples/README_ENVIRONMENT_SETUP.md create mode 100644 Examples/README_FIREBASE_FRONTEND.md create mode 100644 Examples/esp32/.env create mode 100644 Examples/esp32/PanTompkins.h create mode 100644 Examples/esp32/README_FIREBASE.md create mode 100644 Examples/esp32/main.ino create mode 100644 Examples/esp32/setup_firebase.py create mode 100644 Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/.env create mode 100644 Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/INTEGRATION_GUIDE.md create mode 100644 Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/README_FIREBASE_FRONTEND.md create mode 100644 Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/console.log create mode 100644 Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/debugLogger.ts create mode 100644 Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/ecgProcessor.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/exampleInfo.tsx create mode 100644 Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/firebaseLogger.ts create mode 100644 Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/gsrTrendAnalyzer.ts create mode 100644 Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/sessionRecorder.ts create mode 100644 Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/setup_firebase.py create mode 100644 Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/signalProcessor.ts create mode 100644 Examples/src/config/environment.ts diff --git a/Examples/.env b/Examples/.env new file mode 100644 index 000000000..00ea18501 --- /dev/null +++ b/Examples/.env @@ -0,0 +1,23 @@ +# Firebase Configuration for Frontend +# Replace these values with your actual Firebase credentials + +# Firebase API Key (from Firebase Console > Project Settings > General > Web API Key) +REACT_APP_FIREBASE_API_KEY=AIzaSyC2Il3KXMbvIwiVO-q2QnyjCzXWOU6qUBQ + +# Firebase Auth Domain (from Firebase Console > Project Settings > General) +REACT_APP_FIREBASE_AUTH_DOMAIN=biofeedback-a3a9d.firebaseapp.com + +# Firebase Database URL (from Firebase Console > Realtime Database) +REACT_APP_FIREBASE_DATABASE_URL=https://biofeedback-a3a9d-default-rtdb.firebaseio.com + +# Firebase Project ID (from Firebase Console > Project Settings > General) +REACT_APP_FIREBASE_PROJECT_ID=biofeedback-a3a9d + +# Firebase Storage Bucket (from Firebase Console > Project Settings > General) +REACT_APP_FIREBASE_STORAGE_BUCKET=biofeedback-a3a9d.firebasestorage.app + +# Firebase Messaging Sender ID (from Firebase Console > Project Settings > General) +REACT_APP_FIREBASE_MESSAGING_SENDER_ID=954340658821 + +# Firebase App ID (from Firebase Console > Project Settings > General) +REACT_APP_FIREBASE_APP_ID=1:954340658821:web:a00254b2676da9d5d3e3ec \ No newline at end of file diff --git a/Examples/README_ENVIRONMENT_SETUP.md b/Examples/README_ENVIRONMENT_SETUP.md new file mode 100644 index 000000000..fb2ec8844 --- /dev/null +++ b/Examples/README_ENVIRONMENT_SETUP.md @@ -0,0 +1,214 @@ +# Environment Variables Setup Guide + +## **๐Ÿ”ง Overview** + +This guide explains how to properly configure environment variables for the Vital Signs Monitor application, particularly for Firebase integration. + +## **๐Ÿ“ File Structure** + +``` +project-root/ +โ”œโ”€โ”€ .env # Environment variables file +โ”œโ”€โ”€ src/ +โ”‚ โ”œโ”€โ”€ config/ +โ”‚ โ”‚ โ””โ”€โ”€ environment.ts # Environment configuration loader +โ”‚ โ””โ”€โ”€ components/ +โ”‚ โ””โ”€โ”€ Examples/ +โ”‚ โ””โ”€โ”€ FeaturedApps/ +โ”‚ โ””โ”€โ”€ MedicalCharts/ +โ”‚ โ””โ”€โ”€ VitalSignsMonitorDemo/ +โ”‚ โ””โ”€โ”€ firebaseLogger.ts # Firebase integration +``` + +## **๐ŸŒ Environment Variables** + +### **Required Variables** + +The following environment variables must be set in your `.env` file: + +```bash +# Firebase Configuration +REACT_APP_FIREBASE_API_KEY=your_api_key_here +REACT_APP_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com +REACT_APP_FIREBASE_DATABASE_URL=https://your_project.firebaseio.com +REACT_APP_FIREBASE_PROJECT_ID=your_project_id +REACT_APP_FIREBASE_STORAGE_BUCKET=your_project.appspot.com +REACT_APP_FIREBASE_MESSAGING_SENDER_ID=your_sender_id +REACT_APP_FIREBASE_APP_ID=your_app_id +``` + +### **Important Notes** + +1. **REACT*APP* Prefix**: All environment variables must start with `REACT_APP_` to be accessible in React +2. **No Spaces**: Don't use spaces around the `=` sign +3. **No Quotes**: Don't wrap values in quotes unless they contain spaces +4. **Restart Required**: You must restart your development server after changing `.env` files + +## **๐Ÿ”ง Setup Steps** + +### **Step 1: Create .env File** + +Create a `.env` file in your project root directory: + +```bash +# In your project root +touch .env +``` + +### **Step 2: Add Firebase Credentials** + +Copy your Firebase credentials from the Firebase Console and add them to `.env`: + +```bash +# Firebase Configuration for Frontend +REACT_APP_FIREBASE_API_KEY=AIzaSyC2Il3KXMbvIwiVO-q2QnyjCzXWOU6qUBQ +REACT_APP_FIREBASE_AUTH_DOMAIN=biofeedback-a3a9d.firebaseapp.com +REACT_APP_FIREBASE_DATABASE_URL=https://biofeedback-a3a9d-default-rtdb.firebaseio.com +REACT_APP_FIREBASE_PROJECT_ID=biofeedback-a3a9d +REACT_APP_FIREBASE_STORAGE_BUCKET=biofeedback-a3a9d.firebasestorage.app +REACT_APP_FIREBASE_MESSAGING_SENDER_ID=954340658821 +REACT_APP_FIREBASE_APP_ID=1:954340658821:web:a00254b2676da9d5d3e3ec +``` + +### **Step 3: Restart Development Server** + +After creating/modifying the `.env` file: + +```bash +# Stop the current server (Ctrl+C) +# Then restart +npm run dev +``` + +## **๐Ÿ” Verification** + +### **Check Console Logs** + +When the application starts, you should see: + +``` +๐ŸŒ Browser environment detected +๐Ÿ” Available environment variables: + REACT_APP_FIREBASE_API_KEY: โœ… Set + REACT_APP_FIREBASE_AUTH_DOMAIN: โœ… Set + REACT_APP_FIREBASE_DATABASE_URL: โœ… Set + REACT_APP_FIREBASE_PROJECT_ID: โœ… Set + REACT_APP_FIREBASE_STORAGE_BUCKET: โœ… Set + REACT_APP_FIREBASE_MESSAGING_SENDER_ID: โœ… Set + REACT_APP_FIREBASE_APP_ID: โœ… Set +โœ… All required Firebase environment variables are loaded +๐Ÿ”ง Development environment detected +๐Ÿ“Š Environment config loaded: {...} +``` + +### **Check Firebase Connection** + +Look for these logs in the console: + +``` +๐Ÿงช Testing Firebase connection... +โœ… Firebase Logger: Connection test successful +๐Ÿ“Š Test data written to: connection_test +๐Ÿ“– Test data read back successfully: {...} +``` + +## **๐Ÿšจ Troubleshooting** + +### **Problem: Environment Variables Not Loading** + +**Symptoms:** + +- Console shows "โŒ Missing" for environment variables +- Firebase connection fails +- "process.env is undefined" errors + +**Solutions:** + +1. **Verify .env location**: Ensure `.env` is in the project root (same level as `package.json`) +2. **Check variable names**: All variables must start with `REACT_APP_` +3. **Restart server**: Environment variables are only loaded when the server starts +4. **Clear cache**: Try `npm run build` then `npm run dev` + +### **Problem: Firebase Connection Fails** + +**Symptoms:** + +- "โŒ Firebase Logger: Connection test failed" errors +- Permission denied errors + +**Solutions:** + +1. **Check Firebase Rules**: Ensure database rules allow read/write +2. **Verify Project ID**: Check that project ID matches Firebase console +3. **Check API Key**: Ensure API key is correct and not restricted +4. **Network Issues**: Check if your network blocks Firebase + +### **Problem: TypeScript Errors** + +**Symptoms:** + +- Compilation errors about missing properties +- Type mismatches + +**Solutions:** + +1. **Restart TypeScript server**: In VS Code, Ctrl+Shift+P โ†’ "TypeScript: Restart TS Server" +2. **Clear build cache**: Delete `node_modules/.cache` and restart +3. **Check imports**: Ensure `environment.ts` is properly imported + +## **๐Ÿ”’ Security Best Practices** + +### **Do NOT Commit .env Files** + +Add `.env` to your `.gitignore`: + +```gitignore +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +``` + +### **Use Different Configs for Different Environments** + +```bash +# Development +.env.development + +# Production +.env.production + +# Local overrides +.env.local +``` + +### **Validate Environment Variables** + +The `environment.ts` file automatically validates required variables and provides helpful error messages. + +## **๐Ÿ“š Additional Resources** + +- [React Environment Variables](https://create-react-app.dev/docs/adding-custom-environment-variables/) +- [Firebase Setup Guide](https://firebase.google.com/docs/web/setup) +- [Environment Variables Best Practices](https://12factor.net/config) + +## **๐Ÿ†˜ Getting Help** + +If you're still having issues: + +1. Check the browser console for error messages +2. Verify your Firebase project settings +3. Ensure your `.env` file is properly formatted +4. Restart your development server +5. Check that all required variables are set + +## **โœ… Success Checklist** + +- [ ] `.env` file created in project root +- [ ] All `REACT_APP_` variables set +- [ ] Development server restarted +- [ ] Console shows "โœ… All required Firebase environment variables are loaded" +- [ ] Firebase connection test successful +- [ ] No TypeScript compilation errors diff --git a/Examples/README_FIREBASE_FRONTEND.md b/Examples/README_FIREBASE_FRONTEND.md new file mode 100644 index 000000000..c974dc2a3 --- /dev/null +++ b/Examples/README_FIREBASE_FRONTEND.md @@ -0,0 +1,244 @@ +# ๐Ÿ”ฅ Frontend Firebase Integration for Vital Signs Monitor + +This guide will help you set up Firebase logging on the **frontend side** to log **processed sensor data** every 30 seconds when the ESP32 is connected. + +## ๐Ÿ“‹ What You'll Get + +- **Processed sensor data logging** every 30 seconds +- **Automatic logging** only when ESP32 is connected +- **Complete processed metrics** including: + - Heart Rate (BPM) + - Respiratory Rate (breaths/min) + - GSR Value and Trend Analysis + - ECG Signal Quality Assessment + - HRV Metrics (SDNN, RMSSD, pNN50, LF/HF Power) + - Respiratory Metrics (inhale/exhale percentages) + - Connection Status + +## ๐Ÿš€ Quick Setup + +### Step 1: Firebase Project Setup + +1. **Go to Firebase Console**: https://console.firebase.google.com/ +2. **Create a new project** or select existing one +3. **Enable Realtime Database**: + - Go to "Realtime Database" in the left sidebar + - Click "Create Database" + - Choose "Start in test mode" (for development) + - Select a location close to you +4. **Get your credentials**: + - Go to "Project Settings" (gear icon) > "General" + - Copy all the required values (see Step 2) + +### Step 2: Update Frontend Credentials + +1. **Edit the `.env` file** in the **root directory**: + + ```bash + # Replace these with your actual Firebase credentials + REACT_APP_FIREBASE_API_KEY=your-actual-api-key + REACT_APP_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com + REACT_APP_FIREBASE_DATABASE_URL=https://your-project.firebaseio.com + REACT_APP_FIREBASE_PROJECT_ID=your-project-id + REACT_APP_FIREBASE_STORAGE_BUCKET=your-project.appspot.com + REACT_APP_FIREBASE_MESSAGING_SENDER_ID=123456789 + REACT_APP_FIREBASE_APP_ID=your-app-id + ``` + +2. **Run the setup script** (from root directory): + ```bash + python setup_firebase.py + ``` + +### Step 3: Install Firebase Dependencies + +1. **Install Firebase SDK**: + + ```bash + npm install firebase + ``` + +2. **Restart your development server**: + ```bash + npm run dev:clean + ``` + +### Step 4: ESP32 Connection + +Your ESP32 IP address is already configured in the frontend code: + +- **ESP32 IP**: `10.171.208.121` (from your mobile hotspot) +- **WebSocket URL**: `ws://10.171.208.121:81` +- **Port**: 81 + +The frontend will automatically try to connect to your ESP32 when the page loads. + +## ๐Ÿ“Š Data Structure + +The Firebase database will store **processed data** in this structure: + +``` +/processed_sensor_logs/ + โ”œโ”€โ”€ -NxYz1234567890/ + โ”‚ โ”œโ”€โ”€ timestamp: 1234567890 + โ”‚ โ”œโ”€โ”€ heartRate: 75 + โ”‚ โ”œโ”€โ”€ respiratoryRate: 16 + โ”‚ โ”œโ”€โ”€ gsrValue: 0.65 + โ”‚ โ”œโ”€โ”€ gsrTrend: "increasing" + โ”‚ โ”œโ”€โ”€ ecgQuality: "good" + โ”‚ โ”œโ”€โ”€ hrvMetrics: { + โ”‚ โ”‚ โ”œโ”€โ”€ sdnn: 45.2 + โ”‚ โ”‚ โ”œโ”€โ”€ rmssd: 32.1 + โ”‚ โ”‚ โ”œโ”€โ”€ pnn50: 25.5 + โ”‚ โ”‚ โ”œโ”€โ”€ lfPower: 156.7 + โ”‚ โ”‚ โ”œโ”€โ”€ hfPower: 89.3 + โ”‚ โ”‚ โ””โ”€โ”€ lfHfRatio: 1.75 + โ”‚ โ”‚ } + โ”‚ โ”œโ”€โ”€ respiratoryMetrics: { + โ”‚ โ”‚ โ”œโ”€โ”€ breathCount: 12 + โ”‚ โ”‚ โ”œโ”€โ”€ inhalePercent: 45 + โ”‚ โ”‚ โ”œโ”€โ”€ exhalePercent: 55 + โ”‚ โ”‚ โ””โ”€โ”€ breathingState: "inhale" + โ”‚ โ”‚ } + โ”‚ โ”œโ”€โ”€ connectionStatus: { + โ”‚ โ”‚ โ”œโ”€โ”€ esp32Connected: true + โ”‚ โ”‚ โ””โ”€โ”€ sensorsConnected: { + โ”‚ โ”‚ โ”œโ”€โ”€ ecg: true + โ”‚ โ”‚ โ”œโ”€โ”€ gsr: true + โ”‚ โ”‚ โ””โ”€โ”€ respiratory: true + โ”‚ โ”‚ } + โ”‚ โ”‚ } + โ”‚ โ”œโ”€โ”€ logTimestamp: 1234567890 + โ”‚ โ””โ”€โ”€ logId: "-NxYz1234567890" + โ””โ”€โ”€ -NxYz1234567920/ + โ””โ”€โ”€ ... (next 30-second log) +``` + +## ๐Ÿ”ง How It Works + +### Logging Conditions + +- โœ… **ESP32 connected** via WebSocket (`10.171.208.121:81`) +- โœ… **Every 30 seconds** automatically +- โœ… **Processed data** from frontend signal processing +- โœ… **Complete metrics** including HRV and respiratory analysis + +### Data Flow + +``` +ESP32 Raw Data โ†’ Frontend Processing โ†’ Firebase Realtime Database + โ†“ โ†“ โ†“ + Raw ADC Signal Processing Processed Logs + Values HRV Analysis Every 30s + Respiratory Analysis + GSR Trend Analysis +``` + +### Connection Tracking + +- **WebSocket events** track ESP32 connection +- **Automatic start/stop** of Firebase logging +- **Processed data only** (no raw ADC values) + +## ๐Ÿ› ๏ธ Troubleshooting + +### Common Issues + +1. **"Firebase not ready"** + + - Check Firebase credentials in `.env` (root directory) + - Ensure Firebase SDK is installed + - Verify Realtime Database is enabled + +2. **"Firebase log failed"** + + - Check Firebase project settings + - Verify database rules allow writes + - Check network connectivity + +3. **No logs appearing** + + - Check if ESP32 is connected (`10.171.208.121:81`) + - Verify WebSocket connection + - Check browser console for errors + +4. **ESP32 connection issues** + - Ensure ESP32 is powered and connected to mobile hotspot + - Verify ESP32 IP is `10.171.208.121` + - Check that WebSocket server is running on port 81 + +### Debug Commands + +Check browser console for these messages: + +``` +โœ… Firebase Logger: Connection status set to true +โœ… Firebase Logger: Successfully logged processed sensor data +โœ… WEBSOCKET: ESP32 WebSocket connected successfully! +``` + +## ๐Ÿ“ฑ Viewing Data + +### Firebase Console + +1. Go to your Firebase project +2. Navigate to "Realtime Database" +3. Look for `processed_sensor_logs` folder +4. Data updates every 30 seconds when ESP32 connected + +### Programmatic Access + +```javascript +// Example: Read latest processed sensor data +firebase + .database() + .ref("processed_sensor_logs") + .orderByKey() + .limitToLast(1) + .once("value") + .then((snapshot) => { + const data = snapshot.val(); + console.log("Latest processed data:", data); + }); +``` + +## ๐Ÿ”’ Security Notes + +- **Test mode** is enabled for development +- **Production** should use proper Firebase security rules +- **Credentials** are stored in `.env` file (keep secure) +- **Processed data only** (no raw sensor values) + +## ๐Ÿ“ˆ What Gets Logged + +### Vital Signs + +- **Heart Rate**: Current BPM from Pan-Tompkins +- **Respiratory Rate**: Breaths per minute +- **GSR Value**: Normalized conductance value +- **GSR Trend**: Increasing/decreasing/stable + +### Signal Quality + +- **ECG Quality**: Good/fair/poor based on signal analysis +- **HRV Metrics**: SDNN, RMSSD, pNN50, LF/HF power +- **Respiratory Metrics**: Inhale/exhale percentages + +### System Status + +- **ESP32 Connection**: Connected/disconnected +- **Sensor Status**: Individual sensor connection status +- **Timestamp**: When the data was logged + +## ๐ŸŽฏ Expected Results + +After setup, you should see: + +- โœ… **Processed data logs** every 30 seconds when ESP32 connected +- โœ… **Complete metrics** in Firebase Realtime Database +- โœ… **Automatic start/stop** based on ESP32 connection +- โœ… **Real-time monitoring** of processed vital signs + +--- + +**Need help?** Check the browser console for detailed error messages and connection status. diff --git a/Examples/esp32/.env b/Examples/esp32/.env new file mode 100644 index 000000000..bda8f4a10 --- /dev/null +++ b/Examples/esp32/.env @@ -0,0 +1,18 @@ +# Firebase Configuration +# Replace these values with your actual Firebase credentials + +# Firebase API Key (from Firebase Console > Project Settings > General > Web API Key) +FIREBASE_API_KEY=your-api-key-here + +# Firebase Database URL (from Firebase Console > Realtime Database > Database URL) +FIREBASE_DATABASE_URL=https://your-project-id.firebaseio.com + +# Firebase User Email (for authentication) +FIREBASE_USER_EMAIL=your-email@example.com + +# Firebase User Password (for authentication) +FIREBASE_USER_PASSWORD=your-password-here + +# WiFi Credentials +WIFI_SSID=Airtel_301 +WIFI_PASSWORD=Wifi@2025 \ No newline at end of file diff --git a/Examples/esp32/PanTompkins.h b/Examples/esp32/PanTompkins.h new file mode 100644 index 000000000..38e975ea4 --- /dev/null +++ b/Examples/esp32/PanTompkins.h @@ -0,0 +1,168 @@ +#ifndef PAN_TOMPKINS_H +#define PAN_TOMPKINS_H + +class PanTompkins { +public: + // Constructor: Initializes all variables + PanTompkins() { + // Initialize all variables to their default states as seen in the original code + for (int i = 0; i < M + 1; i++) ecg_buff[i] = 0; + ecg_buff_WR_idx = 0; + ecg_buff_RD_idx = 0; + hp_sum = 0; + + for (int i = 0; i < N + 1; i++) hp_buff[i] = 0; + hp_buff_WR_idx = 0; + hp_buff_RD_idx = 0; + lp_sum = 0; + + next_eval_pt = 0; + number_iter = 0; + treshold = 0; // Using original spelling + triggered = false; + trig_time = 0; + win_max = -10000000.0; + win_idx = 0; + + BPM = 0; + ibi = 0; + cprTimeRead_1 = 0; + cprTimeRead_2 = 0; + } + + // Renamed to detect() to match original source code + bool detect(int new_ecg_pt) { + // --- High pass filtering --- + // Buffer overflow protection + if (ecg_buff_WR_idx >= M + 1) { + ecg_buff_WR_idx = 0; // Reset to prevent overflow + } + ecg_buff[ecg_buff_WR_idx++] = new_ecg_pt; + ecg_buff_WR_idx %= (M + 1); + + if (number_iter < M) { + hp_sum += ecg_buff[ecg_buff_RD_idx]; + hp_buff[hp_buff_WR_idx] = 0; + } else { + hp_sum += ecg_buff[ecg_buff_RD_idx]; + int tmp = ecg_buff_RD_idx - M; + if (tmp < 0) tmp += M + 1; + hp_sum -= ecg_buff[tmp]; + + float y1 = HP_CONSTANT * hp_sum; + int tmp_y2 = (ecg_buff_RD_idx - ((M + 1) / 2)); + if (tmp_y2 < 0) tmp_y2 += M + 1; + float y2 = ecg_buff[tmp_y2]; + hp_buff[hp_buff_WR_idx] = y2 - y1; + } + ecg_buff_RD_idx = (ecg_buff_RD_idx + 1) % (M + 1); + // Buffer overflow protection for hp_buff + if (hp_buff_WR_idx >= N + 1) { + hp_buff_WR_idx = 0; + } + hp_buff_WR_idx = (hp_buff_WR_idx + 1) % (N + 1); + + // --- Low pass filtering (Moving Window Integration) --- + lp_sum += hp_buff[hp_buff_RD_idx] * hp_buff[hp_buff_RD_idx]; + if (number_iter < N) { + next_eval_pt = 0; + } else { + int tmp = hp_buff_RD_idx - N; + if (tmp < 0) tmp += (N + 1); + lp_sum -= hp_buff[tmp] * hp_buff[tmp]; + next_eval_pt = lp_sum; + } + hp_buff_RD_idx = (hp_buff_RD_idx + 1) % (N + 1); + + // --- Adapative thresholding beat detection --- + bool QRS_detected = false; + + if (number_iter < winSize) { + if (next_eval_pt > treshold) { + treshold = next_eval_pt; + } + } + + if (triggered) { + trig_time++; + if (trig_time >= 100) { // ~200ms hold-off @ 250Hz sampling + triggered = false; + trig_time = 0; + } + } + + if (next_eval_pt > win_max) { + win_max = next_eval_pt; + } + + if (next_eval_pt > treshold && !triggered) { + // --- BEAT DETECTED --- + cprTimeRead_2 = cprTimeRead_1; + cprTimeRead_1 = millis(); + if (cprTimeRead_2 != 0) { // Avoid calculation on first beat + this->ibi = cprTimeRead_1 - cprTimeRead_2; + // Division by zero protection + if (this->ibi > 0) { + this->BPM = 60000 / ibi; + } else { + this->BPM = 0; // Invalid IBI + } + } + triggered = true; + QRS_detected = true; + } + + if (++win_idx >= winSize) { + float gamma = 0.4; + float alpha = 0.1 + (((float)random(1001) / 10000.0)); // Range 0.1 to 0.2 + treshold = alpha * gamma * win_max + (1 - alpha) * treshold; + win_idx = 0; + win_max = -10000000.0; + } + + number_iter++; + return QRS_detected; + } + + // Getter for Inter-Beat Interval in milliseconds + int getIbi() { + return this->ibi; + } + + // Getter for Heart Rate in beats per minute, renamed to match original + int getBPM() { + return this->BPM; + } + +private: + // --- Constants from original source --- + static const int M = 5; + static const int N = 30; + static const int winSize = 100; // Adjusted for ~250Hz + constexpr static const float HP_CONSTANT = (float)1 / (float)M; + + // --- All variable names now match the original source code --- + float ecg_buff[M + 1]; + int ecg_buff_WR_idx; + int ecg_buff_RD_idx; + float hp_buff[N + 1]; + int hp_buff_WR_idx; + int hp_buff_RD_idx; + float hp_sum; + float lp_sum; + float next_eval_pt; + + unsigned int number_iter; + float treshold; // Original typo retained for consistency + bool triggered; + int trig_time; + float win_max; + int win_idx; + + int BPM; + int ibi; + unsigned long cprTimeRead_1; + unsigned long cprTimeRead_2; +}; + +#endif // PAN_TOMPKINS_H \ No newline at end of file diff --git a/Examples/esp32/README_FIREBASE.md b/Examples/esp32/README_FIREBASE.md new file mode 100644 index 000000000..5b1a53362 --- /dev/null +++ b/Examples/esp32/README_FIREBASE.md @@ -0,0 +1,185 @@ +# ๐Ÿ”ฅ Firebase Integration for ESP32 Vital Signs Monitor + +This guide will help you set up Firebase logging for your ESP32 vital signs monitor. The system will log sensor data every 30 seconds when the frontend is connected. + +## ๐Ÿ“‹ What You'll Get + +- **Real-time sensor data logging** every 30 seconds +- **Automatic logging** only when frontend is connected +- **Complete sensor data** including ECG, GSR, Respiratory, Heart Rate, and IBI +- **Firebase Realtime Database** storage for easy access + +## ๐Ÿš€ Quick Setup + +### Step 1: Firebase Project Setup + +1. **Go to Firebase Console**: https://console.firebase.google.com/ +2. **Create a new project** or select existing one +3. **Enable Realtime Database**: + - Go to "Realtime Database" in the left sidebar + - Click "Create Database" + - Choose "Start in test mode" (for development) + - Select a location close to you +4. **Get your credentials**: + - Go to "Project Settings" (gear icon) > "General" + - Scroll down to "Your apps" section + - Copy the "Web API Key" + - Go back to "Realtime Database" + - Copy the database URL (looks like: `https://your-project.firebaseio.com`) + +### Step 2: Update Credentials + +1. **Edit the `.env` file** in the `esp32` folder: + + ```bash + # Replace these with your actual Firebase credentials + FIREBASE_API_KEY=your-actual-api-key-here + FIREBASE_DATABASE_URL=https://your-project-id.firebaseio.com + FIREBASE_USER_EMAIL=your-email@example.com + FIREBASE_USER_PASSWORD=your-password-here + ``` + +2. **Run the setup script**: + ```bash + cd esp32 + python setup_firebase.py + ``` + +### Step 3: Install Arduino Library + +1. **Open Arduino IDE** +2. **Go to Tools > Manage Libraries** +3. **Search for**: "Firebase ESP32 Client" +4. **Install** the library by "Mobizt" + +### Step 4: Upload to ESP32 + +1. **Open** `main.ino` in Arduino IDE +2. **Select your ESP32 board** and port +3. **Upload** the code + +## ๐Ÿ“Š Data Structure + +The Firebase database will store data in this structure: + +``` +/sensor_logs/ + โ”œโ”€โ”€ 1234567890/ + โ”‚ โ”œโ”€โ”€ timestamp: "1234567890" + โ”‚ โ”œโ”€โ”€ ecg_raw: 2048 + โ”‚ โ”œโ”€โ”€ gsr_raw: 1500 + โ”‚ โ”œโ”€โ”€ respiratory_raw: 1800 + โ”‚ โ”œโ”€โ”€ heart_rate: 75 + โ”‚ โ”œโ”€โ”€ ibi: 800 + โ”‚ โ”œโ”€โ”€ frontend_connected: true + โ”‚ โ””โ”€โ”€ connected_clients: 1 + โ””โ”€โ”€ 1234567920/ + โ””โ”€โ”€ ... (next 30-second log) +``` + +## ๐Ÿ”ง How It Works + +### Logging Conditions + +- โœ… **Frontend connected** via WebSocket +- โœ… **Every 30 seconds** automatically +- โœ… **Real sensor data** from analog pins +- โœ… **Complete dataset** including all vital signs + +### Data Flow + +``` +Analog Pins โ†’ ESP32 Processing โ†’ Firebase Realtime Database + โ†“ โ†“ โ†“ + Raw ADC Pan-Tompkins JSON Logs + Values Beat Detection Every 30s +``` + +### Connection Tracking + +- **WebSocket events** track frontend connection +- **Automatic start/stop** of Firebase logging +- **Client count** monitoring + +## ๐Ÿ› ๏ธ Troubleshooting + +### Common Issues + +1. **"Firebase not ready"** + + - Check WiFi connection + - Verify Firebase credentials in `.env` + - Ensure Firebase library is installed + +2. **"Firebase signin failed"** + + - Check email/password in `.env` + - Verify Firebase project settings + - Ensure Realtime Database is enabled + +3. **No logs appearing** + - Check if frontend is connected + - Verify WebSocket connection + - Check Serial Monitor for errors + +### Debug Commands + +Check Serial Monitor for these messages: + +``` +โœ… Firebase signin successful +โœ… Frontend connected - starting Firebase logging +โœ… Firebase log successful: /sensor_logs/1234567890 +``` + +## ๐Ÿ“ฑ Viewing Data + +### Firebase Console + +1. Go to your Firebase project +2. Navigate to "Realtime Database" +3. Look for `/sensor_logs/` folder +4. Data updates every 30 seconds when connected + +### Programmatic Access + +```javascript +// Example: Read latest sensor data +firebase + .database() + .ref("sensor_logs") + .orderByKey() + .limitToLast(1) + .once("value") + .then((snapshot) => { + const data = snapshot.val(); + console.log("Latest sensor data:", data); + }); +``` + +## ๐Ÿ”’ Security Notes + +- **Test mode** is enabled for development +- **Production** should use proper Firebase security rules +- **Credentials** are stored in `.env` file (keep secure) +- **WiFi credentials** are also in `.env` + +## ๐Ÿ“ˆ Next Steps + +1. **Set up Firebase security rules** for production +2. **Add data visualization** using Firebase data +3. **Implement data analytics** on logged sensor data +4. **Add alerts** for abnormal vital signs + +## ๐ŸŽฏ Expected Results + +After setup, you should see: + +- โœ… **Firebase logs** every 30 seconds when frontend connected +- โœ… **Complete sensor data** in Firebase Realtime Database +- โœ… **Automatic start/stop** based on frontend connection +- โœ… **Real-time monitoring** of vital signs + +--- + +**Need help?** Check the Serial Monitor for detailed error messages and connection status. diff --git a/Examples/esp32/main.ino b/Examples/esp32/main.ino new file mode 100644 index 000000000..5b0b7ed5b --- /dev/null +++ b/Examples/esp32/main.ino @@ -0,0 +1,491 @@ +#include +#include +#include +#include "PanTompkins.h" + +// --- WiFi Credentials --- +const char* ssid = "Airtel_301"; +const char* password = "Wifi@2025"; + +// Create a WebSocketsServer on port 81 +WebSocketsServer webSocket = WebSocketsServer(81); + +// Create an instance of our HRV detector +PanTompkins panTompkins; + +// --- ESP32 Hardware Pins --- +// Updated for ESP32-WROOM-DA with better analog pin selection +const int ECG_PIN = 32; // GPIO32 - ADC1_CH4 - Better analog input, more stable +const int GSR_PIN = 33; // GPIO33 - ADC1_CH5 - Better analog input, more stable +const int RESP_PIN = 27; // GPIO27 - ADC2_CH7 - Alternative to problematic GPIO34 + +// Note: GPIO32 and GPIO33 are more reliable for analog sensors than GPIO36/39 +// GPIO27 is also more stable than GPIO34 for analog input + +// Sensor data variables +int ecgSample = 0; +int gsrSample = 0; +int respSample = 0; + +// Debug values for status reporting +int gsrRawValue = 0; // Store raw ADC value for status report +int gsrFilteredValue = 0; // Store filtered value for status report + +// Timing variables for proper sampling +unsigned long lastEcgTime = 0; +unsigned long lastGsrTime = 0; +unsigned long lastRespTime = 0; +unsigned long lastSendTime = 0; // Global send timing variable +const unsigned long ECG_INTERVAL = 4; // 4ms = ~250Hz for ECG +const unsigned long GSR_INTERVAL = 100; // 100ms = 10Hz for GSR +const unsigned long RESP_INTERVAL = 10; // 10ms = 100Hz for respiratory + +// Data smoothing for GSR and Respiratory (reduced window size) +const int SMOOTH_WINDOW = 3; // Reduced from 5 to save memory +int gsrBuffer[SMOOTH_WINDOW] = {0}; +int respBuffer[SMOOTH_WINDOW] = {0}; +int gsrIndex = 0; +int respIndex = 0; + +// Sensor connection status (always true since we don't check) +bool ecgSensorConnected = true; +bool gsrSensorConnected = true; +bool respSensorConnected = true; + +// Unified data structure for all sensor readings (optimized) +struct SensorData { + float ecg; + float gsr; + float respiratory; + int heartRate; + int ibi; + unsigned long timestamp; +}; + +SensorData currentData; + +void onWebSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { + switch (type) { + case WStype_DISCONNECTED: + Serial.printf("๐Ÿ”Œ WebSocket client #%u disconnected\n", num); + break; + case WStype_CONNECTED: { + Serial.printf("๐Ÿ”Œ WebSocket client #%u connected from %s\n", num, webSocket.remoteIP(num).toString().c_str()); + // Send a welcome message to confirm connection + String welcomeMsg = "{\"type\":\"connection\",\"status\":\"connected\",\"message\":\"ESP32 WebSocket Server Ready\"}"; + webSocket.sendTXT(num, welcomeMsg); + break; + } + case WStype_TEXT: + // Only log important messages, not every data packet + if (length < 100) { // Only log short messages (likely commands) + Serial.printf("๐Ÿ“จ WebSocket client #%u sent: %s\n", num, payload); + } + // Echo back for testing + webSocket.sendTXT(num, (char*)payload); + break; + case WStype_BIN: + Serial.printf("๐Ÿ“ฆ WebSocket client #%u sent binary data (%d bytes)\n", num, length); + break; + case WStype_ERROR: + Serial.printf("โŒ WebSocket client #%u error\n", num); + break; + case WStype_FRAGMENT_TEXT_START: + case WStype_FRAGMENT_BIN_START: + case WStype_FRAGMENT: + case WStype_FRAGMENT_FIN: + break; + } +} + +// Function to send data to all connected clients +void sendData(const String& data) { + String payload = data; // Create a non-const copy + webSocket.broadcastTXT(payload); +} + +// Test GSR sensor on startup +void testGSRSensor() { + Serial.println("\n=== GSR SENSOR TESTING ==="); + + // Test 1: Basic ADC reading + Serial.println("Test 1: Basic ADC Reading"); + for (int i = 0; i < 10; i++) { + int value = analogRead(GSR_PIN); + Serial.printf("Reading %d: %d (%.2fV)\n", i+1, value, (value * 3.3) / 4095.0); + delay(100); + } + + // Test 2: Touch test (should see change when touching electrodes) + Serial.println("\nTest 2: Touch Test - Touch the GSR electrodes now!"); + Serial.println("You should see values change when touching..."); + for (int i = 0; i < 20; i++) { + int value = analogRead(GSR_PIN); + Serial.printf("Touch test %d: %d\n", i+1, value); + delay(200); + } + + // Test 3: Different ADC configurations + Serial.println("\nTest 3: ADC Configuration Test"); + Serial.printf("Current ADC resolution: %d bits\n", analogReadResolution()); + Serial.printf("Current ADC attenuation: %d\n", analogReadAttenuation()); + + Serial.println("GSR sensor test completed!"); + Serial.println("==========================\n"); +} + +// Helper function to calculate moving average (optimized) +int calculateMovingAverage(int* buffer, int index, int windowSize) { + int sum = 0; + int validSamples = 0; + + // Calculate moving average with proper circular buffer indexing + for (int i = 0; i < windowSize; i++) { + int bufferIndex = (index - i + windowSize) % windowSize; + // Ensure we don't access negative indices + if (bufferIndex >= 0 && bufferIndex < windowSize) { + sum += buffer[bufferIndex]; + validSamples++; + } + } + + // Division by zero protection + if (validSamples == 0) { + return 2048; // Fallback to mid-range + } + + return sum / validSamples; +} + +// Simple function to read analog value (no validation needed) +int readAnalogValue(int pin) { + return analogRead(pin); +} + +// Function to send ECG data at 250Hz +void sendECGData() { + StaticJsonDocument<256> jsonDoc; + + jsonDoc["type"] = "ecg"; + jsonDoc["value"] = currentData.ecg; // Raw 12-bit ADC value (0-4095) + jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization + jsonDoc["sensorConnected"] = ecgSensorConnected; + + String jsonString; + if (serializeJson(jsonDoc, jsonString) == 0) { + Serial.println("ERROR: Failed to serialize ECG JSON data"); + return; + } + + sendData(jsonString); +} + +// Function to send GSR data at 10Hz +void sendGSRData() { + StaticJsonDocument<256> jsonDoc; + + jsonDoc["type"] = "gsr"; + jsonDoc["value"] = currentData.gsr; // Raw smoothed value (0-4095) + jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization + jsonDoc["sensorConnected"] = gsrSensorConnected; + + String jsonString; + if (serializeJson(jsonDoc, jsonString) == 0) { + Serial.println("ERROR: Failed to serialize GSR JSON data"); + return; + } + + sendData(jsonString); +} + +// Function to send respiratory data at 100Hz +void sendRespiratoryData() { + StaticJsonDocument<256> jsonDoc; + + jsonDoc["type"] = "respiratory"; + jsonDoc["value"] = currentData.respiratory; // Raw smoothed value (0-4095) + jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization + jsonDoc["sensorConnected"] = respSensorConnected; + + String jsonString; + if (serializeJson(jsonDoc, jsonString) == 0) { + Serial.println("ERROR: Failed to serialize respiratory JSON data"); + return; + } + + sendData(jsonString); + + +} + +// Function to send IBI data when heartbeat detected +void sendIBIData() { + StaticJsonDocument<256> jsonDoc; + + jsonDoc["type"] = "ibi"; + jsonDoc["value"] = currentData.ibi; // IBI in milliseconds + jsonDoc["hr"] = currentData.heartRate; // Heart rate in BPM + jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization + jsonDoc["sensorConnected"] = ecgSensorConnected; + + String jsonString; + if (serializeJson(jsonDoc, jsonString) == 0) { + Serial.println("ERROR: Failed to serialize IBI JSON data"); + return; + } + + sendData(jsonString); +} + +// Function to send continuous heart rate data (even when no beat detected) +void sendHeartRateData() { + StaticJsonDocument<256> jsonDoc; + + jsonDoc["type"] = "heartrate"; + jsonDoc["bpm"] = currentData.heartRate; // Heart rate in BPM + jsonDoc["ibi"] = currentData.ibi; // IBI in milliseconds + jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization + jsonDoc["sensorConnected"] = ecgSensorConnected; + + String jsonString; + if (serializeJson(jsonDoc, jsonString) == 0) { + Serial.println("ERROR: Failed to serialize heart rate JSON data"); + return; + } + + sendData(jsonString); +} + +void setup() { + Serial.begin(115200); + + // Configure ADC for ESP32 with better settings + analogReadResolution(12); // ESP32 has 12-bit ADC + analogSetAttenuation(ADC_11db); // Set attenuation for 0-3.3V range + + Serial.println("ESP32 Vital Signs Monitor Starting..."); + Serial.println("====================================="); + + // Pin configuration info + Serial.printf("ECG Sensor Pin: GPIO%d (ADC1_CH4)\n", ECG_PIN); + Serial.printf("GSR Sensor Pin: GPIO%d (ADC1_CH5)\n", GSR_PIN); + Serial.printf("RESP Sensor Pin: GPIO%d (ADC2_CH7)\n", RESP_PIN); + Serial.println(); + + // Initialize smoothing buffers + for (int i = 0; i < SMOOTH_WINDOW; i++) { + gsrBuffer[i] = 2048; // Mid-range value for 12-bit ADC + respBuffer[i] = 2048; // Mid-range value for 12-bit ADC + } + + // Test sensor pins with multiple readings + Serial.println("Testing sensor pins..."); + Serial.printf("ECG Pin %d: %d\n", ECG_PIN, analogRead(ECG_PIN)); + + // Enhanced GSR pin testing + Serial.printf("GSR Pin %d: ", GSR_PIN); + int gsrTestValues[5] = {0}; + for (int i = 0; i < 5; i++) { + gsrTestValues[i] = analogRead(GSR_PIN); + Serial.printf("%d ", gsrTestValues[i]); + delay(50); + } + Serial.println(); + + // Check if GSR is responding + int gsrAvg = 0; + for (int i = 0; i < 5; i++) { + gsrAvg += gsrTestValues[i]; + } + gsrAvg /= 5; + + if (gsrAvg == 0) { + Serial.println("โš ๏ธ WARNING: GSR sensor showing 0 - Check connections!"); + Serial.println(" - Verify GSR sensor is connected to GPIO33"); + Serial.println(" - Check if sensor has power (VCC and GND)"); + Serial.println(" - Try touching the sensor electrodes"); + } else if (gsrAvg < 100) { + Serial.println("โš ๏ธ WARNING: GSR sensor showing very low values"); + Serial.println(" - Sensor may be disconnected or faulty"); + Serial.println(" - Check electrode contact"); + } else { + Serial.println("โœ… GSR sensor appears to be working"); + } + + Serial.printf("RESP Pin %d: %d\n", RESP_PIN, analogRead(RESP_PIN)); + + // Test respiratory sensor multiple times + Serial.println("Testing HW-484 respiratory sensor..."); + for (int i = 0; i < 10; i++) { + int respTest = analogRead(RESP_PIN); + Serial.printf("RESP Test #%d: %d\n", i+1, respTest); + delay(100); + } + + // Initialize system + Serial.println("Initializing vital signs monitor..."); + delay(1000); // Allow system to stabilize + + // Connect to WiFi with timeout + WiFi.begin(ssid, password); + Serial.print("Connecting to WiFi..."); + + int wifiAttempts = 0; + const int MAX_WIFI_ATTEMPTS = 20; // 10 seconds timeout + + while (WiFi.status() != WL_CONNECTED && wifiAttempts < MAX_WIFI_ATTEMPTS) { + delay(500); + Serial.print("."); + wifiAttempts++; + } + + if (WiFi.status() != WL_CONNECTED) { + Serial.println("\nERROR: WiFi connection failed! Check credentials."); + ESP.restart(); // Restart ESP32 if WiFi fails + } + + Serial.println("\nWiFi connected!"); + Serial.print("IP Address: "); + Serial.println(WiFi.localIP()); + Serial.println("Frontend should connect to: ws://" + WiFi.localIP().toString() + ":81"); + + // Start the WebSocket server + webSocket.begin(); + webSocket.onEvent(onWebSocketEvent); + Serial.println("ESP32 WebSocket server started on port 81"); + Serial.println("Waiting for client connections..."); + + // Test the WebSocket server + Serial.println("WebSocket server status:"); + Serial.printf("- Server running: %s\n", webSocket.connectedClients() >= 0 ? "YES" : "NO"); + Serial.printf("- Connected clients: %d\n", webSocket.connectedClients()); +} + +void loop() { + webSocket.loop(); // Handle WebSocket events + + unsigned long currentTime = millis(); + + // Comprehensive status update every 5 seconds + static unsigned long lastStatusTime = 0; + if (currentTime - lastStatusTime >= 5000) { + lastStatusTime = currentTime; + + Serial.println("\n" + String("=", 60)); + Serial.println("๐Ÿ“Š COMPREHENSIVE STATUS UPDATE"); + Serial.println(String("=", 60)); + + // Connection Status + Serial.println("๐Ÿ”Œ CONNECTION STATUS:"); + Serial.printf(" WiFi Status: %s\n", WiFi.status() == WL_CONNECTED ? "โœ… Connected" : "โŒ Disconnected"); + Serial.printf(" WiFi RSSI: %d dBm\n", WiFi.RSSI()); + Serial.printf(" IP Address: %s\n", WiFi.localIP().toString().c_str()); + Serial.printf(" WebSocket Clients: %d\n", webSocket.connectedClients()); + + // Sensor Data Summary + Serial.println("\n๐Ÿ“ก SENSOR DATA SUMMARY:"); + Serial.printf(" ECG: %d (Raw: %d)\n", ecgSample, analogRead(ECG_PIN)); + Serial.printf(" GSR: %d (Raw: %d, Filtered: %d)\n", gsrSample, gsrRawValue, gsrFilteredValue); + Serial.printf(" RESP: %d (Raw: %d)\n", respSample, analogRead(RESP_PIN)); + + // Data Transmission Stats + Serial.println("\n๐Ÿ“ค DATA TRANSMISSION:"); + Serial.printf(" Last ECG Send: %lu ms ago\n", currentTime - lastEcgTime); + Serial.printf(" Last GSR Send: %lu ms ago\n", currentTime - lastGsrTime); + Serial.printf(" Last RESP Send: %lu ms ago\n", currentTime - lastRespTime); + Serial.printf(" Last Data Send: %lu ms ago\n", currentTime - lastSendTime); + + // Memory and Performance + Serial.println("\n๐Ÿ’พ SYSTEM STATUS:"); + Serial.printf(" Free Heap: %d bytes\n", ESP.getFreeHeap()); + Serial.printf(" Uptime: %lu seconds\n", currentTime / 1000); + + Serial.println(String("=", 60)); + Serial.println(); + } + + // Handle millis() overflow (occurs every ~49 days) + static unsigned long lastLoopTime = 0; + if (currentTime < lastLoopTime) { + // Overflow occurred, reset timing variables + lastEcgTime = 0; + lastGsrTime = 0; + lastRespTime = 0; + lastSendTime = 0; + } + lastLoopTime = currentTime; + + currentData.timestamp = currentTime; + + // --- ECG Processing (250Hz) --- + if (currentTime - lastEcgTime >= ECG_INTERVAL) { + lastEcgTime = currentTime; + + // Read analog value directly + ecgSample = readAnalogValue(ECG_PIN); + + // Send raw ECG data (0-4095) to frontend for proper normalization + // Frontend will convert to millivolts based on sensor calibration + currentData.ecg = ecgSample; // Raw 12-bit ADC value + + // Process ECG for beat detection + // Normalize ECG sample to 0-1 range for Pan-Tompkins algorithm + float normalizedEcg = (float)ecgSample / 4095.0; + + if (panTompkins.detect(normalizedEcg)) { + currentData.ibi = panTompkins.getIbi(); + currentData.heartRate = panTompkins.getBPM(); + + // Send IBI data immediately when detected + sendIBIData(); + } + + // Send ECG data immediately at 250Hz + sendECGData(); + + // Send continuous heart rate data (even when no beat detected) + // This ensures frontend always has heart rate info + sendHeartRateData(); + } + + // --- GSR Processing (10Hz) --- + if (currentTime - lastGsrTime >= GSR_INTERVAL) { + lastGsrTime = currentTime; + + // Read analog value directly + gsrSample = readAnalogValue(GSR_PIN); + + // Smooth GSR data + gsrBuffer[gsrIndex] = gsrSample; + gsrIndex = (gsrIndex + 1) % SMOOTH_WINDOW; + int smoothedGsr = calculateMovingAverage(gsrBuffer, gsrIndex, SMOOTH_WINDOW); + + // Update current data and debug values + currentData.gsr = smoothedGsr; + gsrRawValue = gsrSample; + gsrFilteredValue = smoothedGsr; + + // Send GSR data immediately at 10Hz + sendGSRData(); + } + + // --- Respiratory Processing (100Hz) --- + if (currentTime - lastRespTime >= RESP_INTERVAL) { + lastRespTime = currentTime; + + // Read analog value directly + respSample = readAnalogValue(RESP_PIN); + + // Smooth respiratory data + respBuffer[respIndex] = respSample; + respIndex = (respIndex + 1) % SMOOTH_WINDOW; + int smoothedResp = calculateMovingAverage(respBuffer, respIndex, SMOOTH_WINDOW); + + // Update current data + currentData.respiratory = smoothedResp; + + // Send respiratory data immediately at 100Hz + sendRespiratoryData(); + } + +} \ No newline at end of file diff --git a/Examples/esp32/setup_firebase.py b/Examples/esp32/setup_firebase.py new file mode 100644 index 000000000..97b6e2732 --- /dev/null +++ b/Examples/esp32/setup_firebase.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +""" +Firebase Setup Script for ESP32 Vital Signs Monitor +This script helps you set up Firebase and update the ESP32 code with your credentials. +""" + +import os +import re +import json +from pathlib import Path + +def read_env_file(): + """Read the .env file and return a dictionary of variables.""" + env_vars = {} + env_file = Path('.env') + + if not env_file.exists(): + print("โŒ .env file not found!") + return None + + with open(env_file, 'r') as f: + for line in f: + line = line.strip() + if line and not line.startswith('#') and '=' in line: + key, value = line.split('=', 1) + env_vars[key] = value + + return env_vars + +def update_esp32_code(env_vars): + """Update the ESP32 main.ino file with Firebase credentials.""" + ino_file = Path('main.ino') + + if not ino_file.exists(): + print("โŒ main.ino file not found!") + return False + + # Read the current file + with open(ino_file, 'r') as f: + content = f.read() + + # Update Firebase configuration + replacements = { + 'your-api-key-here': env_vars.get('FIREBASE_API_KEY', 'your-api-key-here'), + 'your-database-url-here': env_vars.get('FIREBASE_DATABASE_URL', 'your-database-url-here'), + 'your-email@example.com': env_vars.get('FIREBASE_USER_EMAIL', 'your-email@example.com'), + 'your-password-here': env_vars.get('FIREBASE_USER_PASSWORD', 'your-password-here'), + 'Airtel_301': env_vars.get('WIFI_SSID', 'Airtel_301'), + 'Wifi@2025': env_vars.get('WIFI_PASSWORD', 'Wifi@2025') + } + + # Apply replacements + for old, new in replacements.items(): + content = content.replace(old, new) + + # Write back to file + with open(ino_file, 'w') as f: + f.write(content) + + print("โœ… ESP32 code updated with your credentials!") + return True + +def validate_firebase_credentials(env_vars): + """Validate that Firebase credentials are properly set.""" + required_vars = [ + 'FIREBASE_API_KEY', + 'FIREBASE_DATABASE_URL', + 'FIREBASE_USER_EMAIL', + 'FIREBASE_USER_PASSWORD' + ] + + missing_vars = [] + for var in required_vars: + if not env_vars.get(var) or env_vars[var] == f'your-{var.lower().replace("firebase_", "").replace("_", "-")}-here': + missing_vars.append(var) + + if missing_vars: + print(f"โŒ Missing or invalid Firebase credentials: {', '.join(missing_vars)}") + return False + + print("โœ… Firebase credentials look good!") + return True + +def print_setup_instructions(): + """Print setup instructions for Firebase.""" + print("\n" + "="*60) + print("๐Ÿ”ฅ FIREBASE SETUP INSTRUCTIONS") + print("="*60) + print("\n1. Go to Firebase Console: https://console.firebase.google.com/") + print("2. Create a new project or select existing one") + print("3. Enable Realtime Database:") + print(" - Go to Realtime Database") + print(" - Click 'Create Database'") + print(" - Choose 'Start in test mode' (for development)") + print("4. Get your credentials:") + print(" - Go to Project Settings > General") + print(" - Copy 'Web API Key'") + print(" - Go to Realtime Database") + print(" - Copy the database URL") + print("5. Update the .env file with your credentials") + print("6. Run this script again to update the ESP32 code") + print("\n" + "="*60) + +def main(): + print("๐Ÿš€ ESP32 Firebase Setup Script") + print("="*40) + + # Check if .env file exists + env_vars = read_env_file() + if not env_vars: + print_setup_instructions() + return + + # Validate credentials + if not validate_firebase_credentials(env_vars): + print_setup_instructions() + return + + # Update ESP32 code + if update_esp32_code(env_vars): + print("\n๐ŸŽ‰ Setup complete! Your ESP32 is ready to log to Firebase.") + print("\n๐Ÿ“‹ Next steps:") + print("1. Install Firebase library in Arduino IDE:") + print(" - Tools > Manage Libraries") + print(" - Search: 'Firebase ESP32 Client'") + print(" - Install by 'Mobizt'") + print("2. Upload the updated main.ino to your ESP32") + print("3. Connect your frontend to see Firebase logging every 30 seconds") + print("4. Check Firebase Console > Realtime Database > sensor_logs") + else: + print("โŒ Failed to update ESP32 code") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/.env b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/.env new file mode 100644 index 000000000..6596b6020 --- /dev/null +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/.env @@ -0,0 +1,23 @@ +# Firebase Configuration for Frontend +# Replace these values with your actual Firebase credentials + +# Firebase API Key (from Firebase Console > Project Settings > General > Web API Key) +REACT_APP_FIREBASE_API_KEY=AIzaSyC2Il3KXMbvIwiVO-q2QnyjCzXWOU6qUBQ + +# Firebase Auth Domain (from Firebase Console > Project Settings > General) +REACT_APP_FIREBASE_AUTH_DOMAIN=biofeedback-a3a9d.firebaseapp.com + +# Firebase Database URL (from Firebase Console > Realtime Database) +REACT_APP_FIREBASE_DATABASE_URL=https://biofeedback-a3a9d-default-rtdb.firebaseio.com + +# Firebase Project ID (from Firebase Console > Project Settings > General) +REACT_APP_FIREBASE_PROJECT_ID=biofeedback-a3a9d + +# Firebase Storage Bucket (from Firebase Console > Project Settings > General) +REACT_APP_FIREBASE_STORAGE_BUCKET=biofeedback-a3a9d.firebasestorage.app + +# Firebase Messaging Sender ID (from Firebase Console > Project Settings > General) +REACT_APP_FIREBASE_MESSAGING_SENDER_ID=954340658821 + +# Firebase App ID (from Firebase Console > Project Settings > General) +REACT_APP_FIREBASE_APP_ID=1:954340658821:web:a00254b2676da9d5d3e3ec \ No newline at end of file diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/INTEGRATION_GUIDE.md b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/INTEGRATION_GUIDE.md new file mode 100644 index 000000000..50294dc18 --- /dev/null +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/INTEGRATION_GUIDE.md @@ -0,0 +1,258 @@ +# ESP32-Frontend Integration Guide + +## ๐Ÿ—๏ธ **System Architecture** + +### **ESP32 Firmware (esp32/main.ino)** + +- **Sampling Rates**: + - ECG: 250Hz (4ms interval) + - GSR: 10Hz (100ms interval) + - Respiratory: 100Hz (10ms interval) +- **Data Format**: JSON WebSocket messages with raw 12-bit ADC values (0-4095) +- **IP Address**: Dynamic (prints to Serial on startup) +- **Sensors**: + - ECG: Real sensor on GPIO36 (VP) + - GSR: Real sensor on GPIO39 (VN) + - Respiratory: Real sensor on GPIO34 (VN) + +### **Frontend Signal Processing (signalProcessor.ts)** + +- **Respiration Analysis**: Real-time breathing pattern detection +- **State Machine**: IDLE โ†’ INHALING โ†’ EXHALING โ†’ IDLE +- **Metrics**: Respiration rate, inhale/exhale percentages, breath cycles +- **Dynamic IP Detection**: Automatic ESP32 IP discovery + +### **Chart Integration (drawExample.ts)** + +- **Real-time Plotting**: SciChart.js with WebSocket data +- **Fallback Mode**: Simulated data when ESP32 disconnected +- **Data Normalization**: Handles 0-1 range from ESP32 + +## ๐Ÿ”ง **Integration Features** + +### **1. Dynamic IP Detection** + +```typescript +// Frontend automatically tries these IPs: +const possibleIPs = [ + "192.168.84.171", // Original firmware IP + "192.168.1.171", // Common home network + "192.168.0.171", // Common home network + "10.254.50.171", // Original frontend IP + "192.168.43.171", // Hotspot network +]; +``` + +### **2. Data Flow** + +``` +ESP32 Sensors โ†’ PanTompkins (ECG) โ†’ WebSocket โ†’ Frontend โ†’ Signal Processing โ†’ Charts +``` + +### **3. Message Types** + +```json +// ECG Data (250Hz) - Raw ADC value, frontend converts to mV +{"type": "ecg", "value": 2048, "timestamp": 12345, "sensorConnected": true} + +// GSR Data (10Hz) - Raw ADC value, frontend normalizes to 0-1 +{"type": "gsr", "value": 2048, "timestamp": 12345, "sensorConnected": true} + +// Respiratory Data (100Hz) - Raw ADC value, frontend normalizes to 0-1 +{"type": "respiratory", "value": 2048, "timestamp": 12345, "sensorConnected": true} + +// IBI/HRV Data (on beat detection) +{"type": "ibi", "value": 800, "hr": 75, "timestamp": 12345, "sensorConnected": true} +``` + +## ๐Ÿš€ **Setup Instructions** + +### **ESP32 Setup** + +1. **Hardware**: Connect ECG sensor to GPIO36 (VP - ADC1_CH0) +2. **WiFi**: Update `ssid` and `password` in `main.ino` +3. **Upload**: Flash firmware to ESP32 +4. **Monitor**: Check Serial output for IP address + +### **Frontend Setup** + +1. **Install Dependencies**: `npm install` +2. **Start Development**: `npm run dev` +3. **Access**: Navigate to VitalSignsMonitorDemo +4. **Connection**: Frontend auto-detects ESP32 IP + +## ๐Ÿ” **Troubleshooting** + +### **Connection Issues** + +```bash +# Check ESP32 Serial output +# Look for: "Frontend should connect to: ws://[IP]:81" + +# Common IP addresses to try manually: +ws://192.168.84.171:81 +ws://192.168.1.171:81 +ws://192.168.0.171:81 +``` + +### **Data Issues** + +- **No ECG Data**: Check sensor connection to A0 +- **No GSR/Respiratory**: Currently using real sensor data only +- **Chart Not Updating**: Check browser console for WebSocket errors + +### **Performance Issues** + +- **High CPU**: Reduce sampling rates in ESP32 firmware +- **Memory Issues**: Reduce `dataWindowSize` in signal processor +- **Network Lag**: Increase `reconnectDelay` in WebSocket handler + +## ๐Ÿ“Š **Data Validation** + +### **Expected Ranges** + +- **ECG**: -2 to 3 mV (converted from 0-4095 ADC) +- **GSR**: 0-1 (normalized from 0-4095 ADC) +- **Respiratory**: 0-1 (normalized from 0-4095 ADC) +- **Heart Rate**: 60-100 BPM +- **IBI**: 600-1000ms +- **Respiration Rate**: 12-20 breaths/min + +### **Signal Quality Indicators** + +- **Good**: Consistent data flow, realistic values +- **Fair**: Occasional gaps, some noise +- **Poor**: Frequent disconnections, unrealistic values + +## ๐Ÿ”ง **Configuration Options** + +### **ESP32 Firmware (main.ino)** + +```cpp +// Sampling intervals +const unsigned long ECG_INTERVAL = 4; // 250Hz +const unsigned long GSR_INTERVAL = 100; // 10Hz +const unsigned long RESP_INTERVAL = 10; // 100Hz + +// Real sensor data only (no simulation toggle) +``` + +### **Frontend Signal Processor (signalProcessor.ts)** + +```typescript +const config = { + samplingRate: 100, // Hz + smoothingWindow: 5, // samples + baselineWindow: 100, // samples + thresholdMultiplier: 1.5, // baseline multiplier + minPeakDistance: 500, // ms + minBreathDuration: 2000, // ms + maxBreathDuration: 10000, // ms + dataWindowSize: 10000, // ms +}; +``` + +## ๐Ÿงช **Testing** + +### **Unit Tests** + +```bash +# Test signal processing +npm test signalProcessor.test.ts + +# Test WebSocket connection +npm test websocket.test.ts +``` + +### **Integration Tests** + +1. **ESP32 Connected**: Verify real-time data flow +2. **ESP32 Disconnected**: Verify fallback mode +3. **Network Issues**: Verify reconnection logic +4. **Data Quality**: Verify realistic value ranges + +## ๐Ÿ“ˆ **Performance Metrics** + +### **Latency** + +- **ESP32 to Frontend**: <50ms +- **Signal Processing**: <10ms +- **Chart Update**: <16ms (60fps) + +### **Throughput** + +- **ECG Data**: 250 samples/second +- **GSR Data**: 10 samples/second +- **Respiratory Data**: 100 samples/second +- **Total**: ~360 samples/second + +### **Memory Usage** + +- **ESP32**: ~20KB RAM +- **Frontend**: ~50MB (including SciChart.js) +- **Signal Processing**: ~1MB buffer + +## ๐Ÿ”ฎ **Future Enhancements** + +### **Hardware** + +- [ ] Add real GSR sensor +- [ ] Add real respiratory sensor (HW-484) +- [ ] Add external ADC for multiple sensors +- [ ] Add battery monitoring + +### **Software** + +- [ ] Add data logging to SD card +- [ ] Add cloud data sync +- [ ] Add machine learning for pattern recognition +- [ ] Add mobile app support + +### **Analysis** + +- [ ] Add frequency domain analysis +- [ ] Add trend analysis +- [ ] Add anomaly detection +- [ ] Add predictive analytics + +## ๐Ÿ› **Known Issues** + +### **ESP32** + +- Limited to one analog input (A0) +- WiFi connection stability on some networks +- Memory constraints with large data buffers + +### **Frontend** + +- WebSocket reconnection can be slow +- Chart performance with high data rates +- Browser compatibility issues + +### **Integration** + +- IP address discovery not always reliable +- Data synchronization between sensors +- Real-time processing latency + +## ๐Ÿ“ž **Support** + +### **Debugging Tools** + +- **ESP32 Serial Monitor**: 115200 baud +- **Browser Console**: F12 developer tools +- **Network Tab**: Monitor WebSocket traffic +- **Performance Tab**: Monitor chart performance + +### **Logs** + +- **ESP32**: Serial output with connection status +- **Frontend**: Browser console with data flow +- **Signal Processing**: Real-time metrics output + +### **Common Solutions** + +1. **Restart ESP32**: Power cycle device +2. **Clear Browser Cache**: Hard refresh (Ctrl+F5) +3. **Check Network**: Ensure ESP32 and PC on same network +4. **Update Firmware**: Re-upload latest code diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/README_FIREBASE_FRONTEND.md b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/README_FIREBASE_FRONTEND.md new file mode 100644 index 000000000..3a9bc2c4a --- /dev/null +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/README_FIREBASE_FRONTEND.md @@ -0,0 +1,228 @@ +# ๐Ÿ”ฅ Frontend Firebase Integration for Vital Signs Monitor + +This guide will help you set up Firebase logging on the **frontend side** to log **processed sensor data** every 30 seconds when the ESP32 is connected. + +## ๐Ÿ“‹ What You'll Get + +- **Processed sensor data logging** every 30 seconds +- **Automatic logging** only when ESP32 is connected +- **Complete processed metrics** including: + - Heart Rate (BPM) + - Respiratory Rate (breaths/min) + - GSR Value and Trend Analysis + - ECG Signal Quality Assessment + - HRV Metrics (SDNN, RMSSD, pNN50, LF/HF Power) + - Respiratory Metrics (inhale/exhale percentages) + - Connection Status + +## ๐Ÿš€ Quick Setup + +### Step 1: Firebase Project Setup + +1. **Go to Firebase Console**: https://console.firebase.google.com/ +2. **Create a new project** or select existing one +3. **Enable Realtime Database**: + - Go to "Realtime Database" in the left sidebar + - Click "Create Database" + - Choose "Start in test mode" (for development) + - Select a location close to you +4. **Get your credentials**: + - Go to "Project Settings" (gear icon) > "General" + - Copy all the required values (see Step 2) + +### Step 2: Update Frontend Credentials + +1. **Edit the `.env` file** in the `VitalSignsMonitorDemo` folder: + + ```bash + # Replace these with your actual Firebase credentials + REACT_APP_FIREBASE_API_KEY=your-actual-api-key + REACT_APP_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com + REACT_APP_FIREBASE_DATABASE_URL=https://your-project.firebaseio.com + REACT_APP_FIREBASE_PROJECT_ID=your-project-id + REACT_APP_FIREBASE_STORAGE_BUCKET=your-project.appspot.com + REACT_APP_FIREBASE_MESSAGING_SENDER_ID=123456789 + REACT_APP_FIREBASE_APP_ID=your-app-id + ``` + +2. **Run the setup script**: + ```bash + cd src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo + python setup_firebase.py + ``` + +### Step 3: Install Firebase Dependencies + +1. **Install Firebase SDK**: + + ```bash + npm install firebase + ``` + +2. **Restart your development server**: + ```bash + npm run dev:clean + ``` + +## ๐Ÿ“Š Data Structure + +The Firebase database will store **processed data** in this structure: + +``` +/processed_sensor_logs/ + โ”œโ”€โ”€ -NxYz1234567890/ + โ”‚ โ”œโ”€โ”€ timestamp: 1234567890 + โ”‚ โ”œโ”€โ”€ heartRate: 75 + โ”‚ โ”œโ”€โ”€ respiratoryRate: 16 + โ”‚ โ”œโ”€โ”€ gsrValue: 0.65 + โ”‚ โ”œโ”€โ”€ gsrTrend: "increasing" + โ”‚ โ”œโ”€โ”€ ecgQuality: "good" + โ”‚ โ”œโ”€โ”€ hrvMetrics: { + โ”‚ โ”‚ โ”œโ”€โ”€ sdnn: 45.2 + โ”‚ โ”‚ โ”œโ”€โ”€ rmssd: 32.1 + โ”‚ โ”‚ โ”œโ”€โ”€ pnn50: 25.5 + โ”‚ โ”‚ โ”œโ”€โ”€ lfPower: 156.7 + โ”‚ โ”‚ โ”œโ”€โ”€ hfPower: 89.3 + โ”‚ โ”‚ โ””โ”€โ”€ lfHfRatio: 1.75 + โ”‚ โ”‚ } + โ”‚ โ”œโ”€โ”€ respiratoryMetrics: { + โ”‚ โ”‚ โ”œโ”€โ”€ breathCount: 12 + โ”‚ โ”‚ โ”œโ”€โ”€ inhalePercent: 45 + โ”‚ โ”‚ โ”œโ”€โ”€ exhalePercent: 55 + โ”‚ โ”‚ โ””โ”€โ”€ breathingState: "inhale" + โ”‚ โ”‚ } + โ”‚ โ”œโ”€โ”€ connectionStatus: { + โ”‚ โ”‚ โ”œโ”€โ”€ esp32Connected: true + โ”‚ โ”‚ โ””โ”€โ”€ sensorsConnected: { + โ”‚ โ”‚ โ”œโ”€โ”€ ecg: true + โ”‚ โ”‚ โ”œโ”€โ”€ gsr: true + โ”‚ โ”‚ โ””โ”€โ”€ respiratory: true + โ”‚ โ”‚ } + โ”‚ โ”‚ } + โ”‚ โ”œโ”€โ”€ logTimestamp: 1234567890 + โ”‚ โ””โ”€โ”€ logId: "-NxYz1234567890" + โ””โ”€โ”€ -NxYz1234567920/ + โ””โ”€โ”€ ... (next 30-second log) +``` + +## ๐Ÿ”ง How It Works + +### Logging Conditions + +- โœ… **ESP32 connected** via WebSocket +- โœ… **Every 30 seconds** automatically +- โœ… **Processed data** from frontend signal processing +- โœ… **Complete metrics** including HRV and respiratory analysis + +### Data Flow + +``` +ESP32 Raw Data โ†’ Frontend Processing โ†’ Firebase Realtime Database + โ†“ โ†“ โ†“ + Raw ADC Signal Processing Processed Logs + Values HRV Analysis Every 30s + Respiratory Analysis + GSR Trend Analysis +``` + +### Connection Tracking + +- **WebSocket events** track ESP32 connection +- **Automatic start/stop** of Firebase logging +- **Processed data only** (no raw ADC values) + +## ๐Ÿ› ๏ธ Troubleshooting + +### Common Issues + +1. **"Firebase not ready"** + + - Check Firebase credentials in `.env` + - Ensure Firebase SDK is installed + - Verify Realtime Database is enabled + +2. **"Firebase log failed"** + + - Check Firebase project settings + - Verify database rules allow writes + - Check network connectivity + +3. **No logs appearing** + - Check if ESP32 is connected + - Verify WebSocket connection + - Check browser console for errors + +### Debug Commands + +Check browser console for these messages: + +``` +โœ… Firebase Logger: Connection status set to true +โœ… Firebase Logger: Successfully logged processed sensor data +``` + +## ๐Ÿ“ฑ Viewing Data + +### Firebase Console + +1. Go to your Firebase project +2. Navigate to "Realtime Database" +3. Look for `processed_sensor_logs` folder +4. Data updates every 30 seconds when ESP32 connected + +### Programmatic Access + +```javascript +// Example: Read latest processed sensor data +firebase + .database() + .ref("processed_sensor_logs") + .orderByKey() + .limitToLast(1) + .once("value") + .then((snapshot) => { + const data = snapshot.val(); + console.log("Latest processed data:", data); + }); +``` + +## ๐Ÿ”’ Security Notes + +- **Test mode** is enabled for development +- **Production** should use proper Firebase security rules +- **Credentials** are stored in `.env` file (keep secure) +- **Processed data only** (no raw sensor values) + +## ๐Ÿ“ˆ What Gets Logged + +### Vital Signs + +- **Heart Rate**: Current BPM from Pan-Tompkins +- **Respiratory Rate**: Breaths per minute +- **GSR Value**: Normalized conductance value +- **GSR Trend**: Increasing/decreasing/stable + +### Signal Quality + +- **ECG Quality**: Good/fair/poor based on signal analysis +- **HRV Metrics**: SDNN, RMSSD, pNN50, LF/HF power +- **Respiratory Metrics**: Inhale/exhale percentages + +### System Status + +- **ESP32 Connection**: Connected/disconnected +- **Sensor Status**: Individual sensor connection status +- **Timestamp**: When the data was logged + +## ๐ŸŽฏ Expected Results + +After setup, you should see: + +- โœ… **Processed data logs** every 30 seconds when ESP32 connected +- โœ… **Complete metrics** in Firebase Realtime Database +- โœ… **Automatic start/stop** based on ESP32 connection +- โœ… **Real-time monitoring** of processed vital signs + +--- + +**Need help?** Check the browser console for detailed error messages and connection status. diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/console.log b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/console.log new file mode 100644 index 000000000..3c00ad87f --- /dev/null +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/console.log @@ -0,0 +1,3577 @@ + [Intervention] Slow network is detected. See https://www.chromestatus.com/feature/5636954674692096 for more details. Fallback font will be used while loading: chrome-extension://meimoidfecamngeoanhnpdjjdcefoldn/assets/fonts/Inter-Regular.ttf +:24278/license:1 Failed to load resource: net::ERR_CONNECTION_REFUSED +:24278/license:1 Failed to load resource: net::ERR_CONNECTION_REFUSED +:24278/license:1 Failed to load resource: net::ERR_CONNECTION_REFUSED +:24278/license:1 Failed to load resource: net::ERR_CONNECTION_REFUSED +:24278/license:1 Failed to load resource: net::ERR_CONNECTION_REFUSED +:24278/license:1 Failed to load resource: net::ERR_CONNECTION_REFUSED +:24278/license:1 Failed to load resource: net::ERR_CONNECTION_REFUSED +:24278/license:1 Failed to load resource: net::ERR_CONNECTION_REFUSED +:24278/license:1 Failed to load resource: net::ERR_CONNECTION_REFUSED +:24278/license:1 Failed to load resource: net::ERR_CONNECTION_REFUSED + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":10} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":9} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":9} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":9} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":5} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":5} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":9} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":9} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":5} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":9} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":5} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":5} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":6} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":8} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":5} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":9} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":5} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":5} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":9} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":5} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":9} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":5} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":10} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":42} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":12} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":6} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":9} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":7} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":8} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":9} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":29} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":351} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":111} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":363} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":280} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":172} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":446} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":224} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":387} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":127} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":548} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":463} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":554} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":615} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":622} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":607} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":600} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":555} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":402} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":19} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":17} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":725} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":727} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":15} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":122} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":723} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":734} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":733} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":728} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":728} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":724} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":726} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":725} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":725} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":730} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":732} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":736} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":735} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":730} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":733} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":733} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":752} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":736} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":733} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":733} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":730} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":729} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":735} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":733} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":733} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":732} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":732} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":735} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":734} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":732} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":734} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":735} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":733} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":742} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":730} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":586} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":489} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":531} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":759} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":759} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":759} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":733} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":730} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":760} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":760} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":728} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":733} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":734} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":750} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":760} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":765} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":765} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":765} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":768} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":765} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":765} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":766} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":607} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":760} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":759} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":758} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":758} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":765} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":760} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":760} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":765} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":758} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":760} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":760} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":759} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":760} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":765} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":758} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":765} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":764} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":761} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":763} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":762} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":765} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":795} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":794} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":748} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":735} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":643} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":564} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":595} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":605} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":631} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":642} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":644} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":608} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":580} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":589} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":588} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":580} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":567} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":560} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":548} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":573} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":577} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":574} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":577} +drawExample.ts:245 Appending websocket ECG Object +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":572} +drawExample.ts:245 Appending websocket ECG {x: 6650, value: 572} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":578} +drawExample.ts:245 Appending websocket ECG {x: 6651, value: 578} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":573} +drawExample.ts:245 Appending websocket ECG {x: 6652, value: 573} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":576} +drawExample.ts:245 Appending websocket ECG {x: 6653, value: 576} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":632} +drawExample.ts:245 Appending websocket ECG {x: 6654, value: 632} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":651} +drawExample.ts:245 Appending websocket ECG {x: 6655, value: 651} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":610} +drawExample.ts:245 Appending websocket ECG {x: 6656, value: 610} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":639} +drawExample.ts:245 Appending websocket ECG {x: 6657, value: 639} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":656} +drawExample.ts:245 Appending websocket ECG {x: 6658, value: 656} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":776} +drawExample.ts:245 Appending websocket ECG {x: 6659, value: 776} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":684} +drawExample.ts:245 Appending websocket ECG {x: 6660, value: 684} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":727} +drawExample.ts:245 Appending websocket ECG {x: 6661, value: 727} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":696} +drawExample.ts:245 Appending websocket ECG {x: 6662, value: 696} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":745} +drawExample.ts:245 Appending websocket ECG {x: 6663, value: 745} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":656} +drawExample.ts:245 Appending websocket ECG {x: 6664, value: 656} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":643} +drawExample.ts:245 Appending websocket ECG {x: 6665, value: 643} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":618} +drawExample.ts:245 Appending websocket ECG {x: 6666, value: 618} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":619} +drawExample.ts:245 Appending websocket ECG {x: 6667, value: 619} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":653} +drawExample.ts:245 Appending websocket ECG {x: 6668, value: 653} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":645} +drawExample.ts:245 Appending websocket ECG {x: 6669, value: 645} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":605} +drawExample.ts:245 Appending websocket ECG {x: 6670, value: 605} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":721} +drawExample.ts:245 Appending websocket ECG {x: 6671, value: 721} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":658} +drawExample.ts:245 Appending websocket ECG {x: 6672, value: 658} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":648} +drawExample.ts:245 Appending websocket ECG {x: 6673, value: 648} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":638} +drawExample.ts:245 Appending websocket ECG {x: 6674, value: 638} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":747} +drawExample.ts:245 Appending websocket ECG {x: 6675, value: 747} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":774} +drawExample.ts:245 Appending websocket ECG {x: 6676, value: 774} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":732} +drawExample.ts:245 Appending websocket ECG {x: 6677, value: 732} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":725} +drawExample.ts:245 Appending websocket ECG {x: 6678, value: 725} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":693} +drawExample.ts:245 Appending websocket ECG {x: 6679, value: 693} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":637} +drawExample.ts:245 Appending websocket ECG {x: 6680, value: 637} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6681, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6682, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6683, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6684, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6685, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6686, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6687, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6688, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6689, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6690, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6691, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6692, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6693, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6694, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6695, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6696, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6697, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6698, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6699, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6700, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6701, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6702, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6703, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6704, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6705, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6706, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6707, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6708, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6709, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6710, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6711, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6712, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6713, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6714, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6715, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6716, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":807} +drawExample.ts:245 Appending websocket ECG {x: 6717, value: 807} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6718, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6719, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6720, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6721, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6722, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6723, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6724, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6725, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6726, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6727, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6728, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6729, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6730, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6731, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6732, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6733, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6734, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6735, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6736, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6737, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6738, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6739, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6740, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6741, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6742, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6743, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6744, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6745, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6746, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6747, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6748, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6749, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6750, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6751, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6752, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6753, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6754, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6755, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6756, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6757, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6758, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6759, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6760, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6761, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6762, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6763, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG {x: 6764, value: 801} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG {x: 6765, value: 801} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG {x: 6766, value: 801} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG {x: 6767, value: 801} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG {x: 6768, value: 801} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG {x: 6769, value: 801} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG {x: 6770, value: 801} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG {x: 6771, value: 801} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG {x: 6772, value: 801} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG {x: 6773, value: 801} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":801} +drawExample.ts:245 Appending websocket ECG {x: 6774, value: 801} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":799} +drawExample.ts:245 Appending websocket ECG {x: 6775, value: 799} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":799} +drawExample.ts:245 Appending websocket ECG {x: 6776, value: 799} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":798} +drawExample.ts:245 Appending websocket ECG {x: 6777, value: 798} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":798} +drawExample.ts:245 Appending websocket ECG {x: 6778, value: 798} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":798} +drawExample.ts:245 Appending websocket ECG {x: 6779, value: 798} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":786} +drawExample.ts:245 Appending websocket ECG {x: 6780, value: 786} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":783} +drawExample.ts:245 Appending websocket ECG {x: 6781, value: 783} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":782} +drawExample.ts:245 Appending websocket ECG {x: 6782, value: 782} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":782} +drawExample.ts:245 Appending websocket ECG {x: 6783, value: 782} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":780} +drawExample.ts:245 Appending websocket ECG {x: 6784, value: 780} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":782} +drawExample.ts:245 Appending websocket ECG {x: 6785, value: 782} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":729} +drawExample.ts:245 Appending websocket ECG {x: 6786, value: 729} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":704} +drawExample.ts:245 Appending websocket ECG {x: 6787, value: 704} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":688} +drawExample.ts:245 Appending websocket ECG {x: 6788, value: 688} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":692} +drawExample.ts:245 Appending websocket ECG {x: 6789, value: 692} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":694} +drawExample.ts:245 Appending websocket ECG {x: 6790, value: 694} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":703} +drawExample.ts:245 Appending websocket ECG {x: 6791, value: 703} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":668} +drawExample.ts:245 Appending websocket ECG {x: 6792, value: 668} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":673} +drawExample.ts:245 Appending websocket ECG {x: 6793, value: 673} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":669} +drawExample.ts:245 Appending websocket ECG {x: 6794, value: 669} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":674} +drawExample.ts:245 Appending websocket ECG {x: 6795, value: 674} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":680} +drawExample.ts:245 Appending websocket ECG {x: 6796, value: 680} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":704} +drawExample.ts:245 Appending websocket ECG {x: 6797, value: 704} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":720} +drawExample.ts:245 Appending websocket ECG {x: 6798, value: 720} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":675} +drawExample.ts:245 Appending websocket ECG {x: 6799, value: 675} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":676} +drawExample.ts:245 Appending websocket ECG {x: 6800, value: 676} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":682} +drawExample.ts:245 Appending websocket ECG {x: 6801, value: 682} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":693} +drawExample.ts:245 Appending websocket ECG {x: 6802, value: 693} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":665} +drawExample.ts:245 Appending websocket ECG {x: 6803, value: 665} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":628} +drawExample.ts:245 Appending websocket ECG {x: 6804, value: 628} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":610} +drawExample.ts:245 Appending websocket ECG {x: 6805, value: 610} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":569} +drawExample.ts:245 Appending websocket ECG {x: 6806, value: 569} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":561} +drawExample.ts:245 Appending websocket ECG {x: 6807, value: 561} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":585} +drawExample.ts:245 Appending websocket ECG {x: 6808, value: 585} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":612} +drawExample.ts:245 Appending websocket ECG {x: 6809, value: 612} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":625} +drawExample.ts:245 Appending websocket ECG {x: 6810, value: 625} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":608} +drawExample.ts:245 Appending websocket ECG {x: 6811, value: 608} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":609} +drawExample.ts:245 Appending websocket ECG {x: 6812, value: 609} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":569} +drawExample.ts:245 Appending websocket ECG {x: 6813, value: 569} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":591} +drawExample.ts:245 Appending websocket ECG {x: 6814, value: 591} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":566} +drawExample.ts:245 Appending websocket ECG {x: 6815, value: 566} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":543} +drawExample.ts:245 Appending websocket ECG {x: 6816, value: 543} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":584} +drawExample.ts:245 Appending websocket ECG {x: 6817, value: 584} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":596} +drawExample.ts:245 Appending websocket ECG {x: 6818, value: 596} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":552} +drawExample.ts:245 Appending websocket ECG {x: 6819, value: 552} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":541} +drawExample.ts:245 Appending websocket ECG {x: 6820, value: 541} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":507} +drawExample.ts:245 Appending websocket ECG {x: 6821, value: 507} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":512} +drawExample.ts:245 Appending websocket ECG {x: 6822, value: 512} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":482} +drawExample.ts:245 Appending websocket ECG {x: 6823, value: 482} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":543} +drawExample.ts:245 Appending websocket ECG {x: 6824, value: 543} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":673} +drawExample.ts:245 Appending websocket ECG {x: 6825, value: 673} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":625} +drawExample.ts:245 Appending websocket ECG {x: 6826, value: 625} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":618} +drawExample.ts:245 Appending websocket ECG {x: 6827, value: 618} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":622} +drawExample.ts:245 Appending websocket ECG {x: 6828, value: 622} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":574} +drawExample.ts:245 Appending websocket ECG {x: 6829, value: 574} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":626} +drawExample.ts:245 Appending websocket ECG {x: 6830, value: 626} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":592} +drawExample.ts:245 Appending websocket ECG {x: 6831, value: 592} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":597} +drawExample.ts:245 Appending websocket ECG {x: 6832, value: 597} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":565} +drawExample.ts:245 Appending websocket ECG {x: 6833, value: 565} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":544} +drawExample.ts:245 Appending websocket ECG {x: 6834, value: 544} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":584} +drawExample.ts:245 Appending websocket ECG {x: 6835, value: 584} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":639} +drawExample.ts:245 Appending websocket ECG {x: 6836, value: 639} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":542} +drawExample.ts:245 Appending websocket ECG {x: 6837, value: 542} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":545} +drawExample.ts:245 Appending websocket ECG {x: 6838, value: 545} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":541} +drawExample.ts:245 Appending websocket ECG {x: 6839, value: 541} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":559} +drawExample.ts:245 Appending websocket ECG {x: 6840, value: 559} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":626} +drawExample.ts:245 Appending websocket ECG {x: 6841, value: 626} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":653} +drawExample.ts:245 Appending websocket ECG {x: 6842, value: 653} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":622} +drawExample.ts:245 Appending websocket ECG {x: 6843, value: 622} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":613} +drawExample.ts:245 Appending websocket ECG {x: 6844, value: 613} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":572} +drawExample.ts:245 Appending websocket ECG {x: 6845, value: 572} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":545} +drawExample.ts:245 Appending websocket ECG {x: 6846, value: 545} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":579} +drawExample.ts:245 Appending websocket ECG {x: 6847, value: 579} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":661} +drawExample.ts:245 Appending websocket ECG {x: 6848, value: 661} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":663} +drawExample.ts:245 Appending websocket ECG {x: 6849, value: 663} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":664} +drawExample.ts:245 Appending websocket ECG {x: 6850, value: 664} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":658} +drawExample.ts:245 Appending websocket ECG {x: 6851, value: 658} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":785} +drawExample.ts:245 Appending websocket ECG {x: 6852, value: 785} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6853, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6854, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6855, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6856, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6857, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6858, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6859, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6860, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6861, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6862, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6863, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6864, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6865, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6866, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6867, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6868, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6869, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6870, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6871, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6872, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6873, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6874, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6875, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6876, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6877, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6878, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6879, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6880, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6881, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6882, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6883, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6884, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6885, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6886, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6887, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6888, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6889, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6890, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6891, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6892, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6893, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6894, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6895, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6896, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6897, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6898, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6899, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6900, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6901, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6902, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6903, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6904, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6905, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6906, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6907, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6908, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6909, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6910, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6911, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6912, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6913, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6914, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6915, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6916, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6917, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6918, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6919, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6920, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6921, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6922, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6923, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6924, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6925, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6926, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6927, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6928, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6929, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6930, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6931, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6932, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6933, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6934, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6935, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6936, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6937, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6938, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6939, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6940, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6941, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6942, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6943, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6944, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6945, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6946, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6947, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6948, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6949, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6950, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6951, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6952, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6953, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6954, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6955, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6956, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6957, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6958, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6959, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 6960, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6961, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6962, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6963, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6964, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6965, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6966, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6967, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 6968, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6969, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6970, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6971, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6972, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":802} +drawExample.ts:245 Appending websocket ECG {x: 6973, value: 802} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":474} +drawExample.ts:245 Appending websocket ECG {x: 6974, value: 474} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":507} +drawExample.ts:245 Appending websocket ECG {x: 6975, value: 507} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":478} +drawExample.ts:245 Appending websocket ECG {x: 6976, value: 478} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":590} +drawExample.ts:245 Appending websocket ECG {x: 6977, value: 590} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":559} +drawExample.ts:245 Appending websocket ECG {x: 6978, value: 559} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":554} +drawExample.ts:245 Appending websocket ECG {x: 6979, value: 554} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":437} +drawExample.ts:245 Appending websocket ECG {x: 6980, value: 437} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":422} +drawExample.ts:245 Appending websocket ECG {x: 6981, value: 422} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":526} +drawExample.ts:245 Appending websocket ECG {x: 6982, value: 526} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":475} +drawExample.ts:245 Appending websocket ECG {x: 6983, value: 475} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":485} +drawExample.ts:245 Appending websocket ECG {x: 6984, value: 485} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":480} +drawExample.ts:245 Appending websocket ECG {x: 6985, value: 480} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":469} +drawExample.ts:245 Appending websocket ECG {x: 6986, value: 469} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":544} +drawExample.ts:245 Appending websocket ECG {x: 6987, value: 544} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":490} +drawExample.ts:245 Appending websocket ECG {x: 6988, value: 490} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":513} +drawExample.ts:245 Appending websocket ECG {x: 6989, value: 513} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":525} +drawExample.ts:245 Appending websocket ECG {x: 6990, value: 525} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":504} +drawExample.ts:245 Appending websocket ECG {x: 6991, value: 504} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":508} +drawExample.ts:245 Appending websocket ECG {x: 6992, value: 508} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":557} +drawExample.ts:245 Appending websocket ECG {x: 6993, value: 557} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":540} +drawExample.ts:245 Appending websocket ECG {x: 6994, value: 540} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":511} +drawExample.ts:245 Appending websocket ECG {x: 6995, value: 511} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":447} +drawExample.ts:245 Appending websocket ECG {x: 6996, value: 447} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":424} +drawExample.ts:245 Appending websocket ECG {x: 6997, value: 424} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":457} +drawExample.ts:245 Appending websocket ECG {x: 6998, value: 457} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":476} +drawExample.ts:245 Appending websocket ECG {x: 6999, value: 476} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":493} +drawExample.ts:245 Appending websocket ECG {x: 7000, value: 493} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":430} +drawExample.ts:245 Appending websocket ECG {x: 7001, value: 430} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":425} +drawExample.ts:245 Appending websocket ECG {x: 7002, value: 425} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":450} +drawExample.ts:245 Appending websocket ECG {x: 7003, value: 450} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":519} +drawExample.ts:245 Appending websocket ECG {x: 7004, value: 519} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":520} +drawExample.ts:245 Appending websocket ECG {x: 7005, value: 520} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":484} +drawExample.ts:245 Appending websocket ECG {x: 7006, value: 484} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":413} +drawExample.ts:245 Appending websocket ECG {x: 7007, value: 413} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":458} +drawExample.ts:245 Appending websocket ECG {x: 7008, value: 458} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":476} +drawExample.ts:245 Appending websocket ECG {x: 7009, value: 476} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":544} +drawExample.ts:245 Appending websocket ECG {x: 7010, value: 544} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":564} +drawExample.ts:245 Appending websocket ECG {x: 7011, value: 564} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":526} +drawExample.ts:245 Appending websocket ECG {x: 7012, value: 526} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":448} +drawExample.ts:245 Appending websocket ECG {x: 7013, value: 448} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":474} +drawExample.ts:245 Appending websocket ECG {x: 7014, value: 474} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":528} +drawExample.ts:245 Appending websocket ECG {x: 7015, value: 528} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":500} +drawExample.ts:245 Appending websocket ECG {x: 7016, value: 500} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":512} +drawExample.ts:245 Appending websocket ECG {x: 7017, value: 512} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":396} +drawExample.ts:245 Appending websocket ECG {x: 7018, value: 396} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":403} +drawExample.ts:245 Appending websocket ECG {x: 7019, value: 403} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":486} +drawExample.ts:245 Appending websocket ECG {x: 7020, value: 486} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":512} +drawExample.ts:245 Appending websocket ECG {x: 7021, value: 512} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":516} +drawExample.ts:245 Appending websocket ECG {x: 7022, value: 516} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":483} +drawExample.ts:245 Appending websocket ECG {x: 7023, value: 483} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":356} +drawExample.ts:245 Appending websocket ECG {x: 7024, value: 356} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":428} +drawExample.ts:245 Appending websocket ECG {x: 7025, value: 428} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":475} +drawExample.ts:245 Appending websocket ECG {x: 7026, value: 475} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":466} +drawExample.ts:245 Appending websocket ECG {x: 7027, value: 466} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":406} +drawExample.ts:245 Appending websocket ECG {x: 7028, value: 406} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":388} +drawExample.ts:245 Appending websocket ECG {x: 7029, value: 388} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":468} +drawExample.ts:245 Appending websocket ECG {x: 7030, value: 468} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":478} +drawExample.ts:245 Appending websocket ECG {x: 7031, value: 478} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":513} +drawExample.ts:245 Appending websocket ECG {x: 7032, value: 513} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":543} +drawExample.ts:245 Appending websocket ECG {x: 7033, value: 543} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":427} +drawExample.ts:245 Appending websocket ECG {x: 7034, value: 427} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":257} +drawExample.ts:245 Appending websocket ECG {x: 7035, value: 257} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":315} +drawExample.ts:245 Appending websocket ECG {x: 7036, value: 315} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":391} +drawExample.ts:245 Appending websocket ECG {x: 7037, value: 391} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":425} +drawExample.ts:245 Appending websocket ECG {x: 7038, value: 425} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":405} +drawExample.ts:245 Appending websocket ECG {x: 7039, value: 405} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":782} +drawExample.ts:245 Appending websocket ECG {x: 7040, value: 782} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7041, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7042, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7043, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7044, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7045, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7046, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7047, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7048, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7049, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7050, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7051, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7052, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7053, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7054, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7055, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7056, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7057, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7058, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7059, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7060, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7061, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7062, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7063, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7064, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7065, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7066, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7067, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7068, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7069, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7070, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7071, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7072, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7073, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7074, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7075, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7076, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7077, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7078, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7079, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7080, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7081, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7082, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7083, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7084, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7085, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7086, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7087, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":126} +drawExample.ts:245 Appending websocket ECG {x: 7088, value: 126} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":792} +drawExample.ts:245 Appending websocket ECG {x: 7089, value: 792} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":792} +drawExample.ts:245 Appending websocket ECG {x: 7090, value: 792} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":792} +drawExample.ts:245 Appending websocket ECG {x: 7091, value: 792} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":792} +drawExample.ts:245 Appending websocket ECG {x: 7092, value: 792} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":792} +drawExample.ts:245 Appending websocket ECG {x: 7093, value: 792} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":88} +drawExample.ts:245 Appending websocket ECG {x: 7094, value: 88} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":226} +drawExample.ts:245 Appending websocket ECG {x: 7095, value: 226} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":426} +drawExample.ts:245 Appending websocket ECG {x: 7096, value: 426} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":788} +drawExample.ts:245 Appending websocket ECG {x: 7097, value: 788} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":788} +drawExample.ts:245 Appending websocket ECG {x: 7098, value: 788} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":788} +drawExample.ts:245 Appending websocket ECG {x: 7099, value: 788} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":788} +drawExample.ts:245 Appending websocket ECG {x: 7100, value: 788} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":789} +drawExample.ts:245 Appending websocket ECG {x: 7101, value: 789} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":788} +drawExample.ts:245 Appending websocket ECG {x: 7102, value: 788} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":789} +drawExample.ts:245 Appending websocket ECG {x: 7103, value: 789} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":788} +drawExample.ts:245 Appending websocket ECG {x: 7104, value: 788} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":788} +drawExample.ts:245 Appending websocket ECG {x: 7105, value: 788} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":787} +drawExample.ts:245 Appending websocket ECG {x: 7106, value: 787} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":787} +drawExample.ts:245 Appending websocket ECG {x: 7107, value: 787} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":797} +drawExample.ts:245 Appending websocket ECG {x: 7108, value: 797} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7109, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7110, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7111, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7112, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7113, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7114, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7115, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7116, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7117, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7118, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7119, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7120, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7121, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7122, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7123, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7124, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7125, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7126, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7127, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7128, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7129, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7130, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7131, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7132, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7133, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7134, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7135, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7136, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7137, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7138, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7139, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7140, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7141, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7142, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7143, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7144, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7145, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7146, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7147, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7148, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7149, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7150, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7151, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7152, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7153, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7154, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7155, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7156, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7157, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7158, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7159, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7160, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7161, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7162, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7163, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7164, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7165, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7166, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7167, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7168, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7169, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7170, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7171, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7172, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7173, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7174, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7175, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7176, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7177, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7178, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7179, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7180, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7181, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7182, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7183, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7184, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7185, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7186, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7187, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7188, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7189, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7190, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7191, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7192, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7193, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7194, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7195, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7196, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7197, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7198, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7199, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7200, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7201, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7202, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7203, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7204, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7205, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7206, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7207, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7208, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7209, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7210, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7211, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7212, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7213, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7214, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7215, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7216, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7217, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7218, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7219, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7220, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7221, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7222, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7223, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7224, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7225, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7226, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7227, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7228, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7229, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7230, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7231, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7232, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7233, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7234, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7235, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7236, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7237, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7238, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7239, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7240, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7241, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7242, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7243, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7244, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7245, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7246, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7247, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7248, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7249, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7250, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7251, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7252, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7253, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7254, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7255, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7256, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7257, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7258, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7259, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7260, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7261, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7262, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7263, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7264, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7265, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7266, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7267, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7268, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7269, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7270, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7271, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7272, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7273, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7274, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7275, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7276, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7277, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7278, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7279, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7280, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7281, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7282, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7283, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7284, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7285, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7286, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7287, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7288, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7289, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7290, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7291, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7292, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7293, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7294, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7295, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7296, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7297, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7298, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7299, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7300, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7301, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7302, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7303, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7304, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7305, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7306, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7307, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7308, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7309, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7310, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7311, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7312, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7313, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7314, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7315, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7316, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7317, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7318, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7319, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7320, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7321, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7322, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7323, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7324, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7325, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7326, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7327, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7328, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7329, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7330, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7331, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7332, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7333, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7334, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7335, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7336, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7337, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7338, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7339, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7340, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7341, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7342, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7343, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7344, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7345, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7346, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7347, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7348, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7349, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7350, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7351, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7352, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7353, value: 805} + WebSocket message received: {"type":"ecg","value":804} + Appending websocket ECG {x: 7354, value: 804} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7355, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7356, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7357, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7358, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7359, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7360, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7361, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7362, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7363, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7364, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7365, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7366, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7367, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7368, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7369, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7370, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7371, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7372, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7373, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7374, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7375, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7376, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7377, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7378, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7379, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7380, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7381, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7382, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7383, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7384, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7385, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7386, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7387, value: 805} + WebSocket message received: {"type":"ecg","value":804} + Appending websocket ECG {x: 7388, value: 804} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7389, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7390, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7391, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7392, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7393, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7394, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7395, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7396, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7397, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7398, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7399, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7400, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7401, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7402, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7403, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7404, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7405, value: 805} + WebSocket message received: {"type":"ecg","value":804} + Appending websocket ECG {x: 7406, value: 804} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7407, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7408, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7409, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7410, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7411, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7412, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7413, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7414, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7415, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7416, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7417, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7418, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7419, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7420, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7421, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7422, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7423, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7424, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7425, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7426, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7427, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7428, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7429, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7430, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7431, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7432, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7433, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7434, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7435, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7436, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7437, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7438, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7439, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7440, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7441, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7442, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7443, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7444, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7445, value: 805} + WebSocket message received: {"type":"ecg","value":804} + Appending websocket ECG {x: 7446, value: 804} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7447, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7448, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7449, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7450, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7451, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7452, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7453, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7454, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7455, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7456, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7457, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7458, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7459, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7460, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7461, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7462, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7463, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7464, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7465, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7466, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7467, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7468, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7469, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7470, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7471, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7472, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7473, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7474, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7475, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7476, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7477, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7478, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7479, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7480, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7481, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7482, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7483, value: 805} + WebSocket message received: {"type":"ecg","value":804} + Appending websocket ECG {x: 7484, value: 804} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7485, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7486, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7487, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7488, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7489, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7490, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7491, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7492, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7493, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7494, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7495, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7496, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7497, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7498, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7499, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7500, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7501, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7502, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7503, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7504, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7505, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7506, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7507, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7508, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7509, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7510, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7511, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7512, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7513, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7514, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7515, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7516, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7517, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7518, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7519, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7520, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7521, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7522, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7523, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7524, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7525, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7526, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7527, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7528, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7529, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7530, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7531, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7532, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7533, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7534, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7535, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7536, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7537, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7538, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7539, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7540, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7541, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7542, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7543, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7544, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7545, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7546, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7547, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7548, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7549, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7550, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7551, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7552, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7553, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7554, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7555, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7556, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7557, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7558, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7559, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7560, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7561, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7562, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7563, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7564, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7565, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7566, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7567, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7568, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7569, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7570, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7571, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7572, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7573, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7574, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7575, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7576, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7577, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7578, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7579, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7580, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7581, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7582, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7583, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7584, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7585, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7586, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7587, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7588, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7589, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7590, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7591, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7592, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7593, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7594, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7595, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7596, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7597, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7598, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7599, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7600, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7601, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7602, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7603, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7604, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7605, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7606, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7607, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7608, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7609, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7610, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7611, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7612, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7613, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7614, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7615, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7616, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7617, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7618, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7619, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7620, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7621, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7622, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7623, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7624, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7625, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7626, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7627, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7628, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7629, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7630, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7631, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7632, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7633, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7634, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7635, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7636, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7637, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7638, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7639, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7640, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7641, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7642, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7643, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7644, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7645, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7646, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7647, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7648, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7649, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7650, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7651, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7652, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7653, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7654, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7655, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7656, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7657, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7658, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7659, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7660, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7661, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7662, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7663, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7664, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7665, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7666, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7667, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7668, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7669, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7670, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7671, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7672, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7673, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7674, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7675, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7676, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7677, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7678, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7679, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7680, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7681, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7682, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7683, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7684, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7685, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7686, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7687, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7688, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7689, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7690, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7691, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7692, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7693, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":807} +drawExample.ts:245 Appending websocket ECG {x: 7694, value: 807} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7695, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7696, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7697, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7698, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7699, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7700, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7701, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7702, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7703, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7704, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7705, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7706, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7707, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7708, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7709, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7710, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7711, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7712, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7713, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7714, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7715, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7716, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7717, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7718, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7719, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7720, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7721, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7722, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7723, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7724, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7725, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7726, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7727, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7728, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7729, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7730, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7731, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7732, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7733, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7734, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7735, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7736, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7737, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7738, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7739, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7740, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7741, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7742, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7743, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7744, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7745, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7746, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7747, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7748, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7749, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7750, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7751, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7752, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7753, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7754, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7755, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7756, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7757, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7758, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7759, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7760, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7761, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7762, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7763, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7764, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7765, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7766, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7767, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7768, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7769, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7770, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7771, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7772, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7773, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7774, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7775, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7776, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7777, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7778, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7779, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7780, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7781, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7782, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7783, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7784, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7785, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7786, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7787, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7788, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7789, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7790, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7791, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7792, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7793, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7794, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7795, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7796, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7797, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7798, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7799, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7800, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7801, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":806} +drawExample.ts:245 Appending websocket ECG {x: 7802, value: 806} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7803, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7804, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7805, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7806, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7807, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7808, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7809, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7810, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7811, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7812, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7813, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7814, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7815, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7816, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7817, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7818, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7819, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7820, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7821, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7822, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7823, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7824, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7825, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7826, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7827, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7828, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7829, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7830, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7831, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7832, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7833, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7834, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7835, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7836, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7837, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7838, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7839, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7840, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7841, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7842, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7843, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7844, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7845, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7846, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7847, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7848, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7849, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7850, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7851, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7852, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7853, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7854, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7855, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7856, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7857, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7858, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7859, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7860, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7861, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7862, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7863, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7864, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7865, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7866, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7867, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7868, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7869, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7870, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7871, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7872, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7873, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7874, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7875, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7876, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7877, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7878, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7879, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7880, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7881, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7882, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7883, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7884, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7885, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7886, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7887, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7888, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7889, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7890, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7891, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":804} +drawExample.ts:245 Appending websocket ECG {x: 7892, value: 804} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7893, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7894, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7895, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7896, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7897, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7898, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7899, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7900, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7901, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7902, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7903, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7904, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7905, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7906, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7907, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7908, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7909, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} +drawExample.ts:245 Appending websocket ECG {x: 7910, value: 805} +drawExample.ts:238 WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7911, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7912, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7913, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7914, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7915, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7916, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7917, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7918, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7919, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7920, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7921, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7922, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7923, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7924, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7925, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7926, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7927, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7928, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7929, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7930, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7931, value: 805} + WebSocket message received: {"type":"ecg","value":805} + Appending websocket ECG {x: 7932, value: 805} diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/data/vitalSignsEcgData.ts b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/data/vitalSignsEcgData.ts index 61728f0c1..bfb6ef24c 100644 --- a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/data/vitalSignsEcgData.ts +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/data/vitalSignsEcgData.ts @@ -925,6 +925,31 @@ export const vitalSignsEcgData = { 0.85186235, 0.8522812, 0.85272385, 0.85309705, 0.853469, 0.8538413, 0.85421365, 0.8545589, 0.8549777, 0.855211526, ], + // Placeholder RR intervals (ms) for HRV calculations + rrIntervals: [ + 800, 810, 790, 805, 815, 820, 800, 795, 810, 805, 800, 815, 820, 810, 800, 805, 810, 800, 795, 805, 810, 800, + 805, 810, 800, 795, 805, 810, 800, 805, + ], + // Placeholder GSR values (same length as xValues) + gsrValues: Array(5707) + .fill(0.5) + .map((v, i) => 0.5 + 0.05 * Math.sin(i / 100)), + // Placeholder Respiratory values (same length as xValues) + respiratoryValues: Array(5707) + .fill(0.5) + .map((v, i) => 0.5 + 0.1 * Math.cos(i / 150)), + // Placeholder HRV stats (time-domain) + hrvStats: { + sdnn: 18.5, + rmssd: 22.1, + mean: 805.2, + }, + // Placeholder frequency-domain HRV stats + hrvFreq: { + lf: 450.2, + hf: 320.7, + lfhf: 1.4, + }, bloodPressureValues: [ 0.625403, 0.625572, 0.626935, 0.627069, 0.627094, 0.628617, 0.630139, 0.631595, 0.631599, 0.631662, 0.632016, 0.632664, 0.632745, 0.632804, 0.63423, 0.634326, 0.635651, 0.635849, 0.63725, 0.637372, 0.637812, 0.638754, diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/debugLogger.ts b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/debugLogger.ts new file mode 100644 index 000000000..8dd19c6a5 --- /dev/null +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/debugLogger.ts @@ -0,0 +1,385 @@ +// Comprehensive Debugging and Logging System +// Provides different log levels, file output, and performance monitoring + +export enum LogLevel { + DEBUG = 0, + INFO = 1, + WARN = 2, + ERROR = 3, + CRITICAL = 4, +} + +export interface LogEntry { + timestamp: string; + level: LogLevel; + category: string; + message: string; + data?: any; + performance?: { + duration?: number; + memory?: number; + }; +} + +export interface DebugConfig { + logLevel: LogLevel; + enableConsole: boolean; + enableFileLogging: boolean; + enablePerformanceMonitoring: boolean; + maxLogEntries: number; + logDirectory: string; +} + +export class DebugLogger { + private static instance: DebugLogger; + private config: DebugConfig; + private logBuffer: LogEntry[] = []; + private performanceTimers: Map = new Map(); + private isRecording: boolean = false; + private recordingStartTime: number = 0; + private recordingData: any[] = []; + + // Periodic status logging + private lastStatusLogTime: number = 0; + private readonly STATUS_LOG_INTERVAL = 30000; // 30 seconds + private statusData: Map = new Map(); + + private constructor(config: Partial = {}) { + this.config = { + logLevel: LogLevel.INFO, // Changed from DEBUG to INFO to reduce noise + enableConsole: true, + enableFileLogging: false, + enablePerformanceMonitoring: false, // Disabled to reduce noise + maxLogEntries: 1000, + logDirectory: "./logs", + ...config, + }; + } + + public static getInstance(config?: Partial): DebugLogger { + if (!DebugLogger.instance) { + DebugLogger.instance = new DebugLogger(config); + } + return DebugLogger.instance; + } + + // Start performance timer + public startTimer(label: string): void { + if (this.config.enablePerformanceMonitoring) { + this.performanceTimers.set(label, performance.now()); + this.debug("PERFORMANCE", `Started timer: ${label}`); + } + } + + // End performance timer and log duration + public endTimer(label: string, category: string = "PERFORMANCE"): number { + if (this.config.enablePerformanceMonitoring) { + const startTime = this.performanceTimers.get(label); + if (startTime) { + const duration = performance.now() - startTime; + this.performanceTimers.delete(label); + this.info(category, `Timer ${label} completed in ${duration.toFixed(2)}ms`); + return duration; + } + } + return 0; + } + + // Log methods with different levels + public debug(category: string, message: string, data?: any): void { + this.log(LogLevel.DEBUG, category, message, data); + } + + public info(category: string, message: string, data?: any): void { + this.log(LogLevel.INFO, category, message, data); + } + + public warn(category: string, message: string, data?: any): void { + this.log(LogLevel.WARN, category, message, data); + } + + public error(category: string, message: string, data?: any): void { + this.log(LogLevel.ERROR, category, message, data); + } + + public critical(category: string, message: string, data?: any): void { + this.log(LogLevel.CRITICAL, category, message, data); + } + + // Main logging method + private log(level: LogLevel, category: string, message: string, data?: any): void { + if (level < this.config.logLevel) return; + + const entry: LogEntry = { + timestamp: new Date().toISOString(), + level, + category, + message, + data, + }; + + // Add to buffer + this.logBuffer.push(entry); + if (this.logBuffer.length > this.config.maxLogEntries) { + this.logBuffer.shift(); + } + + // Console output + if (this.config.enableConsole) { + this.outputToConsole(entry); + } + + // File output + if (this.config.enableFileLogging) { + this.outputToFile(entry); + } + + // Add to recording if active + if (this.isRecording) { + this.recordingData.push(entry); + } + } + + // Console output with colors + private outputToConsole(entry: LogEntry): void { + const levelColors = { + [LogLevel.DEBUG]: "color: #666", + [LogLevel.INFO]: "color: #0066cc", + [LogLevel.WARN]: "color: #ff6600", + [LogLevel.ERROR]: "color: #cc0000", + [LogLevel.CRITICAL]: "color: #990000; font-weight: bold", + }; + + const levelNames = ["DEBUG", "INFO", "WARN", "ERROR", "CRITICAL"]; + const color = levelColors[entry.level]; + const levelName = levelNames[entry.level]; + + console.groupCollapsed(`%c[${levelName}] ${entry.category}: ${entry.message}`, color); + console.log("Timestamp:", entry.timestamp); + if (entry.data) { + console.log("Data:", entry.data); + } + if (entry.performance) { + console.log("Performance:", entry.performance); + } + console.groupEnd(); + } + + // File output (simulated for browser environment) + private outputToFile(entry: LogEntry): void { + // In a real implementation, you'd use Node.js fs module + // For browser, we'll simulate by storing in localStorage + try { + const logs = JSON.parse(localStorage.getItem("debugLogs") || "[]"); + logs.push(entry); + if (logs.length > this.config.maxLogEntries) { + logs.shift(); + } + localStorage.setItem("debugLogs", JSON.stringify(logs)); + } catch (error) { + console.error("Failed to save log to localStorage:", error); + } + } + + // Start recording session + public startRecording(): void { + this.isRecording = true; + this.recordingStartTime = Date.now(); + this.recordingData = []; + this.info("RECORDING", "Started recording session"); + } + + // Update status data for periodic logging + public updateStatus(category: string, data: any): void { + this.statusData.set(category, data); + } + + // Log comprehensive status every 30 seconds + public logPeriodicStatus(): void { + const currentTime = Date.now(); + if (currentTime - this.lastStatusLogTime < this.STATUS_LOG_INTERVAL) { + return; + } + + this.lastStatusLogTime = currentTime; + + // Create comprehensive status report + const statusReport = { + timestamp: new Date().toISOString(), + uptime: currentTime - (this.recordingStartTime || currentTime), + logBufferSize: this.logBuffer.length, + recordingActive: this.isRecording, + performanceTimers: this.performanceTimers.size, + categories: Object.fromEntries(this.statusData), + }; + + this.info("STATUS", "Comprehensive System Status Report", statusReport); + + // Clear old status data + this.statusData.clear(); + } + + // Stop recording and export data + public stopRecording(): void { + if (!this.isRecording) return; + + this.isRecording = false; + const duration = Date.now() - this.recordingStartTime; + this.info( + "RECORDING", + `Stopped recording session. Duration: ${duration}ms, Entries: ${this.recordingData.length}` + ); + + // Export recording data + this.exportRecordingData(); + } + + // Export recording data to file + private exportRecordingData(): void { + const timestamp = new Date().toISOString().replace(/[:.]/g, "-"); + const csvFilename = `vital-signs-recording-${timestamp}.csv`; + + // CSV export with structured data + const csvHeaders = [ + "Timestamp", + "Category", + "Level", + "Message", + "Heart Rate (BPM)", + "Respiratory Rate (breaths/min)", + "GSR Value", + "GSR Trend", + "ECG Quality", + "HRV SDNN (ms)", + "HRV RMSSD (ms)", + "HRV pNN50 (%)", + "HRV LF Power (msยฒ)", + "HRV HF Power (msยฒ)", + "HRV LF/HF Ratio", + "Breath Count", + "Inhale %", + "Exhale %", + "Breathing State", + "ESP32 Connected", + "ECG Sensor Connected", + "GSR Sensor Connected", + "Respiratory Sensor Connected", + "Data Source", + ]; + + let csvContent = csvHeaders.join(",") + "\n"; + + this.recordingData.forEach((entry) => { + // Extract vital signs data from entry.data if available + const vitalSigns = entry.data?.vitalSigns || entry.data || {}; + + const row = [ + new Date(entry.timestamp).toISOString(), + entry.category, + entry.level, + entry.message, + vitalSigns.heartRate || "", + vitalSigns.respiratoryRate || "", + vitalSigns.gsrValue ? vitalSigns.gsrValue.toFixed(3) : "", + vitalSigns.gsrTrend || "", + vitalSigns.ecgQuality || "", + vitalSigns.hrvMetrics?.sdnn ? vitalSigns.hrvMetrics.sdnn.toFixed(2) : "", + vitalSigns.hrvMetrics?.rmssd ? vitalSigns.hrvMetrics.rmssd.toFixed(2) : "", + vitalSigns.hrvMetrics?.pnn50 ? vitalSigns.hrvMetrics.pnn50.toFixed(2) : "", + vitalSigns.hrvMetrics?.lfPower ? vitalSigns.hrvMetrics.lfPower.toFixed(2) : "", + vitalSigns.hrvMetrics?.hfPower ? vitalSigns.hrvMetrics.hfPower.toFixed(2) : "", + vitalSigns.hrvMetrics?.lfHfRatio ? vitalSigns.hrvMetrics.lfHfRatio.toFixed(2) : "", + vitalSigns.respiratoryMetrics?.breathCount || "", + vitalSigns.respiratoryMetrics?.inhalePercent + ? vitalSigns.respiratoryMetrics.inhalePercent.toFixed(1) + : "", + vitalSigns.respiratoryMetrics?.exhalePercent + ? vitalSigns.respiratoryMetrics.exhalePercent.toFixed(1) + : "", + vitalSigns.respiratoryMetrics?.breathingState || "", + vitalSigns.connectionStatus?.esp32Connected || "", + vitalSigns.connectionStatus?.sensorsConnected?.ecg || "", + vitalSigns.connectionStatus?.sensorsConnected?.gsr || "", + vitalSigns.connectionStatus?.sensorsConnected?.respiratory || "", + vitalSigns.source || entry.source || "", + ]; + + // Escape commas and quotes in CSV + const escapedRow = row.map((cell) => { + if ( + cell && + (cell.toString().includes(",") || cell.toString().includes('"') || cell.toString().includes("\n")) + ) { + return `"${cell.toString().replace(/"/g, '""')}"`; + } + return cell; + }); + + csvContent += escapedRow.join(",") + "\n"; + }); + + // Create downloadable CSV file + const csvBlob = new Blob([csvContent], { type: "text/csv" }); + const csvUrl = URL.createObjectURL(csvBlob); + const csvLink = document.createElement("a"); + csvLink.href = csvUrl; + csvLink.download = csvFilename; + document.body.appendChild(csvLink); + csvLink.click(); + document.body.removeChild(csvLink); + URL.revokeObjectURL(csvUrl); + + this.info("RECORDING", `Exported recording to ${csvFilename}`); + } + + // Get recent logs + public getRecentLogs(count: number = 50): LogEntry[] { + return this.logBuffer.slice(-count); + } + + // Clear logs + public clearLogs(): void { + this.logBuffer = []; + this.info("SYSTEM", "Logs cleared"); + } + + // Get performance statistics + public getPerformanceStats(): any { + const logs = this.logBuffer.filter((log) => log.performance); + const durations = logs.map((log) => log.performance?.duration).filter((d) => d !== undefined); + + if (durations.length === 0) return {}; + + return { + averageDuration: durations.reduce((sum, d) => sum + d!, 0) / durations.length, + minDuration: durations.length > 0 ? Math.min(...durations) : 0, + maxDuration: durations.length > 0 ? Math.max(...durations) : 0, + totalOperations: durations.length, + }; + } + + // Update configuration + public updateConfig(newConfig: Partial): void { + this.config = { ...this.config, ...newConfig }; + this.info("SYSTEM", "Debug configuration updated", newConfig); + } +} + +// Convenience functions for quick logging +export const debug = (category: string, message: string, data?: any) => + DebugLogger.getInstance().debug(category, message, data); + +export const info = (category: string, message: string, data?: any) => + DebugLogger.getInstance().info(category, message, data); + +export const warn = (category: string, message: string, data?: any) => + DebugLogger.getInstance().warn(category, message, data); + +export const error = (category: string, message: string, data?: any) => + DebugLogger.getInstance().error(category, message, data); + +export const critical = (category: string, message: string, data?: any) => + DebugLogger.getInstance().critical(category, message, data); + +export const startTimer = (label: string) => DebugLogger.getInstance().startTimer(label); +export const endTimer = (label: string, category?: string) => DebugLogger.getInstance().endTimer(label, category); diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/drawExample.ts b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/drawExample.ts index 7a6d5e611..847bebce1 100644 --- a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/drawExample.ts +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/drawExample.ts @@ -8,224 +8,605 @@ import { RightAlignedOuterVerticallyStackedAxisLayoutStrategy, SciChartSurface, XyDataSeries, + EAutoRange, } from "scichart"; import { vitalSignsEcgData } from "./data/vitalSignsEcgData"; import { appTheme } from "../../../theme"; +import { RespirationSignalProcessor, ESP32WebSocketHandler, RespirationMetrics } from "./signalProcessor"; +import { ECGSignalProcessor, ECGMetrics } from "./ecgProcessor"; +import { GSRTrendAnalyzer } from "./gsrTrendAnalyzer"; +import { debug, info, warn, error, startTimer, endTimer } from "./debugLogger"; -const STEP = 10; -const TIMER_TIMEOUT_MS = 20; -const STROKE_THICKNESS = 4; +const STEP = 5; // Reduced step size for smoother waveform +const TIMER_TIMEOUT_MS = 50; // Increased timeout for better visibility +const STROKE_THICKNESS = 3; // Reduced for cleaner medical look const POINTS_LOOP = 5200; const GAP_POINTS = 50; const DATA_LENGTH = vitalSignsEcgData.xValues.length; -const { ecgHeartRateValues, bloodPressureValues, bloodVolumeValues, bloodOxygenationValues } = vitalSignsEcgData; +// Professional medical ECG styling +const MEDICAL_ECG_STYLE = { + backgroundColor: "#0a0a0a", // Dark medical background + gridColor: "#1a1a1a", // Subtle grid + axisColor: "#4a4a4a", // Medical gray + ecgColor: "#00ff88", // Medical green ECG trace + baselineColor: "#2a2a2a", // Baseline reference + annotationColor: "#ffffff", // White text + gridOpacity: 0.3, + axisThickness: 1, + majorGridThickness: 1, + minorGridThickness: 0.5, +}; + +// Generate realistic medical ECG waveform with QRS complexes +function generateMedicalECG(length: number): number[] { + const data: number[] = []; + let phase = 0; + let qrsPhase = 0; + + for (let i = 0; i < length; i++) { + let value: number; + + // Create realistic ECG waveform with QRS complexes + if (qrsPhase > 0) { + // QRS complex - sharp spike + if (qrsPhase === 1) { + value = 2.5; // Peak of QRS + } else if (qrsPhase === 2) { + value = 2.0; // Sharp descent + } else if (qrsPhase === 3) { + value = 0.5; // Bottom of QRS + } else { + value = 1.0; // Recovery + } + qrsPhase++; + if (qrsPhase >= 8) qrsPhase = 0; + } else { + // Normal ECG baseline with P and T waves + if (phase < 30) { + // P wave - small positive deflection + value = 0.8 + Math.sin(phase * 0.2) * 0.3; + } else if (phase < 60) { + // Baseline before QRS + value = 0.6 + Math.sin(phase * 0.05) * 0.1; + } else if (phase < 90) { + // T wave - broader positive deflection + value = 1.2 + Math.sin((phase - 60) * 0.15) * 0.4; + } else { + // Baseline + value = 0.5 + Math.sin(phase * 0.03) * 0.1; + } + + // Randomly trigger QRS complex + if (Math.random() < 0.02) { + // ~2% chance per sample + qrsPhase = 1; + } + } + + // Add some noise for realism + value += (Math.random() - 0.5) * 0.05; + + // Generate raw ADC values for fallback - let auto-scaling handle the range + const rawValue = value * 4095; // Simple 0-4095 range + data.push(rawValue); + + phase++; + if (phase >= 150) phase = 0; // Reset cycle + } + + return data; +} + +// Generate fallback demo data for GSR and respiratory if not present +function generateDemoArray(length: number, min: number, max: number) { + return Array.from({ length }, () => min + Math.random() * (max - min)); +} +let ecgHeartRateValues = vitalSignsEcgData.ecgHeartRateValues; +let gsrValues = + vitalSignsEcgData.gsrValues && vitalSignsEcgData.gsrValues.length === DATA_LENGTH + ? vitalSignsEcgData.gsrValues + : generateDemoArray(DATA_LENGTH, 0.3, 0.7); +let respiratoryValues = + vitalSignsEcgData.respiratoryValues && vitalSignsEcgData.respiratoryValues.length === DATA_LENGTH + ? vitalSignsEcgData.respiratoryValues + : generateDemoArray(DATA_LENGTH, 0.4, 0.8); + +// If any array is empty or not an array, forcibly generate demo data +if (!Array.isArray(ecgHeartRateValues) || ecgHeartRateValues.length === 0) { + // Generate realistic medical ECG waveform + ecgHeartRateValues = generateMedicalECG(DATA_LENGTH); + console.warn("Fallback: generated realistic medical ECG data"); + + // Debug: Check the generated data range + const minEcg = Math.min(...ecgHeartRateValues); + const maxEcg = Math.max(...ecgHeartRateValues); + console.log("๐Ÿ” Generated ECG data range:", { min: minEcg, max: maxEcg, length: ecgHeartRateValues.length }); +} +if (!Array.isArray(gsrValues) || gsrValues.length === 0) { + gsrValues = generateDemoArray(DATA_LENGTH, 20, 80); // Realistic GSR range in ฮผS + console.warn("Fallback: generated random GSR data"); +} +if (!Array.isArray(respiratoryValues) || respiratoryValues.length === 0) { + respiratoryValues = generateDemoArray(DATA_LENGTH, 0.4, 0.8); + console.warn("Fallback: generated random respiratory data"); +} // HELPER FUNCTIONS const getValuesFromData = (xIndex: number) => { const xArr: number[] = []; - const ecgHeartRateArr: number[] = []; - const bloodPressureArr: number[] = []; - const bloodVolumeArr: number[] = []; - const bloodOxygenationArr: number[] = []; + const ecgArr: number[] = []; + const gsrArr: number[] = []; + const respArr: number[] = []; for (let i = 0; i < STEP; i++) { const dataIndex = (xIndex + i) % DATA_LENGTH; const x = xIndex + i; xArr.push(x); - ecgHeartRateArr.push(ecgHeartRateValues[dataIndex]); - bloodPressureArr.push(bloodPressureValues[dataIndex]); - bloodVolumeArr.push(bloodVolumeValues[dataIndex]); - bloodOxygenationArr.push(bloodOxygenationValues[dataIndex]); + // ECG data is in raw ADC values (0-4095 range) + ecgArr.push(ecgHeartRateValues[dataIndex]); + gsrArr.push(gsrValues ? gsrValues[dataIndex] : 0); + respArr.push(respiratoryValues ? respiratoryValues[dataIndex] : 0); } return { xArr, - ecgHeartRateArr, - bloodPressureArr, - bloodVolumeArr, - bloodOxygenationArr, + ecgArr, + gsrArr, + respArr, }; }; export type TDataUpdateInfo = { - ecg: number; - bloodPressure1: number; - bloodPressure2: number; - bloodVolume: number; - bloodOxygenation: number; + ecg?: number; + hrv?: number; + bpm?: number; // Heart rate (BPM) + ibi?: number; // Inter-beat interval (ms) + gsr?: number; + respiratory?: number; + hrvStats?: { + sdnn?: number; + rmssd?: number; + }; + hrvFreq?: { + lf?: number; + hf?: number; + lfhf?: number; + }; + respirationMetrics?: RespirationMetrics; + breathingState?: { + state: string; + cycle?: any; + }; + ecgMetrics?: ECGMetrics; // ECG signal quality and HRV metrics + gsrTrend?: any; // GSR trend analysis }; +// Add connection status event handler +export type TConnectionStatus = "connected" | "disconnected" | "error"; +export const connectionStatusEventHandler = new EventHandler(); + // SCICHART + export const drawExample = async (rootElement: string | HTMLDivElement) => { const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, { theme: appTheme.SciChartJsTheme, }); - // Create a single, shared X-axis, pre-sized to fit the data in X, and is invisible - - // Note: For fifoSweeping mode to work, the X-Axis must be a CategoryAxis - // NumericAxis is also supported, but x-values must then be offsets from 0, ie do x % fifoCapacity. - // See more info in the docs - const xAxis = new CategoryAxis(wasmContext, { - visibleRange: new NumberRange(0, POINTS_LOOP), - isVisible: false, + console.log("๐ŸŽฏ SciChart surface created:", { + surfaceId: sciChartSurface.id, + wasmContext: !!wasmContext, + rootElement: rootElement, }); - sciChartSurface.xAxes.add(xAxis); - // Create multiple y-axis, one per trace. Using the stacked vertically layout strategy - const yAxisHeartRate = new NumericAxis(wasmContext, { - id: "yHeartRate", - visibleRange: new NumberRange(0.7, 1.0), - isVisible: false, - }); - const yAxisBloodPressure = new NumericAxis(wasmContext, { - id: "yBloodPressure", - visibleRange: new NumberRange(0.4, 0.8), - isVisible: false, + // Initialize signal processor for respiration analysis + // Configure to match ESP32 sampling rates: + // - ECG: 250Hz (4ms interval) + // - GSR: 10Hz (100ms interval) + // - Respiratory: 100Hz (10ms interval) + const respirationProcessor = new RespirationSignalProcessor({ + samplingRate: 100, // 100 Hz for respiratory (matches ESP32 RESP_INTERVAL) + smoothingWindow: 5, // 5 samples for moving average + baselineWindow: 100, // 100 samples for baseline + thresholdMultiplier: 1.5, // 1.5x baseline for detection + minPeakDistance: 500, // 500ms minimum between events + minBreathDuration: 2000, // 2 seconds minimum breath cycle + maxBreathDuration: 10000, // 10 seconds maximum breath cycle + dataWindowSize: 10000, // 10 seconds of data }); - const yAxisBloodVolume = new NumericAxis(wasmContext, { - id: "yBloodVolume", - visibleRange: new NumberRange(0.1, 0.5), - isVisible: false, + + // Initialize ECG signal processor + const ecgProcessor = new ECGSignalProcessor({ + samplingRate: 250, // 250 Hz to match ESP32 + baselineWindow: 1000, // 4 seconds at 250Hz + noiseThreshold: 0.1, + artifactThreshold: 0.3, + minValidIBI: 300, // 300ms minimum (200 BPM max) + maxValidIBI: 2000, // 2000ms maximum (30 BPM min) + hrvWindowSize: 60000, // 60 seconds for HRV analysis }); - const yAxisBloodOxygenation = new NumericAxis(wasmContext, { - id: "yBloodOxygenation", - visibleRange: new NumberRange(0, 0.2), - isVisible: false, + + // Initialize GSR trend analyzer for 10Hz data + const gsrTrendAnalyzer = new GSRTrendAnalyzer({ + windowSize: 10, // 10 points for 10Hz data (1 second) + trendThreshold: 0.03, + stressThresholds: { + low: 0.3, + moderate: 0.6, + high: 0.8, + }, + smoothingWindow: 3, }); - sciChartSurface.layoutManager!.rightOuterAxesLayoutStrategy = - new RightAlignedOuterVerticallyStackedAxisLayoutStrategy(); - sciChartSurface.yAxes.add(yAxisHeartRate, yAxisBloodPressure, yAxisBloodVolume, yAxisBloodOxygenation); - // Using the NEW fifoCapacity, fifoSweeping mode in SciChart.js v3.2 we specify a number of points - // we want in the viewport. When the right edge of the viewport is reached, the series wraps around + // Professional medical ECG X axis (Time axis) - Stretched for better waveform visibility + const xAxis = new CategoryAxis(wasmContext, { + autoRange: EAutoRange.Never, // Disable auto-scaling to prevent constant movement + visibleRange: new NumberRange(0, 1000), // Wider fixed range to show more data + isVisible: true, + }); + sciChartSurface.xAxes.add(xAxis); - const fifoSweepingGap = GAP_POINTS; - const dataSeries1 = new XyDataSeries(wasmContext, { - fifoCapacity: POINTS_LOOP, - fifoSweeping: true, - fifoSweepingGap, + // Professional medical ECG Y axis (Amplitude axis) - Fixed range optimized for fallback data + const yAxisEcg = new NumericAxis(wasmContext, { + id: "yEcg", + autoRange: EAutoRange.Never, // Disable auto-scaling to prevent constant movement + visibleRange: new NumberRange(0, 15000), // Range optimized for fallback ECG data (0-4095 * 3.5) + isVisible: true, }); - const dataSeries2 = new XyDataSeries(wasmContext, { - fifoCapacity: POINTS_LOOP, + sciChartSurface.yAxes.add(yAxisEcg); + + // Data series - Optimized for medical ECG display + const dataSeriesEcg = new XyDataSeries(wasmContext, { + fifoCapacity: 5000, // Increased capacity to show more fallback data fifoSweeping: true, - fifoSweepingGap, + fifoSweepingGap: 50, }); - const dataSeries3 = new XyDataSeries(wasmContext, { - fifoCapacity: POINTS_LOOP, + const dataSeriesGsr = new XyDataSeries(wasmContext, { + fifoCapacity: 2500, fifoSweeping: true, - fifoSweepingGap, + fifoSweepingGap: 50, }); - const dataSeries4 = new XyDataSeries(wasmContext, { - fifoCapacity: POINTS_LOOP, + const dataSeriesResp = new XyDataSeries(wasmContext, { + fifoCapacity: 2500, fifoSweeping: true, - fifoSweepingGap, + fifoSweepingGap: 50, }); - // A pointmarker with lastPointOnly = true will be used for all series to mark the last point + // Professional medical point marker const pointMarkerOptions = { - width: 7, - height: 7, - strokeThickness: 2, - fill: appTheme.MutedSkyBlue, + width: 5, + height: 5, + strokeThickness: 1, + fill: MEDICAL_ECG_STYLE.ecgColor, + stroke: MEDICAL_ECG_STYLE.ecgColor, lastPointOnly: true, }; - // Create four RenderableSeries which render the data - sciChartSurface.renderableSeries.add( - new FastLineRenderableSeries(wasmContext, { - yAxisId: yAxisHeartRate.id, - strokeThickness: STROKE_THICKNESS, - stroke: appTheme.VividOrange, - dataSeries: dataSeries1, - pointMarker: new EllipsePointMarker(wasmContext, { ...pointMarkerOptions, stroke: appTheme.VividOrange }), - }) - ); - - sciChartSurface.renderableSeries.add( - new FastLineRenderableSeries(wasmContext, { - yAxisId: yAxisBloodPressure.id, - strokeThickness: STROKE_THICKNESS, - stroke: appTheme.VividSkyBlue, - dataSeries: dataSeries2, - pointMarker: new EllipsePointMarker(wasmContext, { ...pointMarkerOptions, stroke: appTheme.VividSkyBlue }), - }) - ); - - sciChartSurface.renderableSeries.add( - new FastLineRenderableSeries(wasmContext, { - yAxisId: yAxisBloodVolume.id, - strokeThickness: STROKE_THICKNESS, - stroke: appTheme.VividPink, - dataSeries: dataSeries3, - pointMarker: new EllipsePointMarker(wasmContext, { ...pointMarkerOptions, stroke: appTheme.VividPink }), - }) - ); - - sciChartSurface.renderableSeries.add( - new FastLineRenderableSeries(wasmContext, { - yAxisId: yAxisBloodOxygenation.id, - strokeThickness: STROKE_THICKNESS, - stroke: appTheme.VividTeal, - dataSeries: dataSeries4, - pointMarker: new EllipsePointMarker(wasmContext, { ...pointMarkerOptions, stroke: appTheme.VividTeal }), - }) - ); + // Professional medical ECG renderable series with enhanced styling + const ecgSeries = new FastLineRenderableSeries(wasmContext, { + yAxisId: yAxisEcg.id, + strokeThickness: 2, // Thinner line for medical precision + stroke: "#00FF00", // Medical green for ECG + dataSeries: dataSeriesEcg, + pointMarker: new EllipsePointMarker(wasmContext, { + ...pointMarkerOptions, + width: 3, + height: 3, + fill: "#00FF00", + stroke: "#00FF00", + }), + isVisible: true, + }); + sciChartSurface.renderableSeries.add(ecgSeries); + + console.log("๐Ÿ“Š ECG series added to chart:", { + seriesId: ecgSeries.id, + dataSeriesId: dataSeriesEcg.id, + renderableSeriesCount: sciChartSurface.renderableSeries.size(), + }); + // Event handler for info panel const dataUpdateEventHandler = new EventHandler(); - let timerId: NodeJS.Timeout; + let timerId: NodeJS.Timeout | undefined; let currentPoint = 0; + let lastXValue = 0; + const MAX_POINTS = 2500; // 10 seconds at 250Hz + const pointsPerSecond = 250; // Matches ESP32 ECG sampling rate + + // Buffer for smooth plotting + const dataBuffer = { + ecg: [] as number[], + gsr: [] as number[], + resp: [] as number[], + timestamps: [] as number[], + }; + + // Helper function to append data to chart with proper timestamps + const appendDataToChart = (series: XyDataSeries, values: number[], timestamps: number[]) => { + try { + if (values.length === 0) return; + series.appendRange(timestamps, values); + if (series.count() > MAX_POINTS) { + series.removeRange(0, series.count() - MAX_POINTS); + } + } catch (error) { + console.error("Error appending data to chart:", error); + } + }; - // The following code is run once per timer-step to update the data in the charts - // Here you would subsitute your own callback to receive data from your data feed or sensors + // Fallback data update loop (when ESP32 is disconnected) const runUpdateDataOnTimeout = () => { - // Get data - const { xArr, ecgHeartRateArr, bloodPressureArr, bloodVolumeArr, bloodOxygenationArr } = - getValuesFromData(currentPoint); - currentPoint += STEP; + const { xArr, ecgArr, gsrArr, respArr } = getValuesFromData(currentPoint); - // appendRange when fifoSweepingMode = true and fifoCapacity is reached will cause the series to wrap around - dataSeries1.appendRange(xArr, ecgHeartRateArr); - dataSeries2.appendRange(xArr, bloodPressureArr); - dataSeries3.appendRange(xArr, bloodVolumeArr); - dataSeries4.appendRange(xArr, bloodOxygenationArr); + // Debug: Log fallback data generation (only every 1000 points to avoid spam) + if (currentPoint % 1000 === 0) { + console.log("๐Ÿ“Š Fallback data generated:", { + currentPoint, + xArr: xArr.length, + ecgArr: ecgArr.length, + gsrArr: gsrArr.length, + respArr: respArr.length, + sampleEcg: ecgArr[0], + sampleGsr: gsrArr[0], + sampleResp: respArr[0], + ecgRange: `${Math.min(...ecgArr)} to ${Math.max(...ecgArr)}`, + gsrRange: `${Math.min(...gsrArr)} to ${Math.max(...gsrArr)}`, + }); + } - // Update Info panel + try { + dataSeriesEcg.appendRange(xArr, ecgArr); + dataSeriesGsr.appendRange(xArr, gsrArr); + dataSeriesResp.appendRange(xArr, respArr); + + // Debug: Check if data is actually being added to the series + if (currentPoint % 1000 === 0) { + console.log("๐Ÿ“ˆ Chart data status:", { + ecgSeriesCount: dataSeriesEcg.count(), + gsrSeriesCount: dataSeriesGsr.count(), + respSeriesCount: dataSeriesResp.count(), + lastEcgValue: ecgArr[ecgArr.length - 1], + lastGsrValue: gsrArr[gsrArr.length - 1], + }); + } + + // Force chart redraw to ensure data is visible + if (sciChartSurface) { + sciChartSurface.zoomExtents(); + } + } catch (e) { + console.error("Error appending fallback data:", e); + } + currentPoint += STEP; if (currentPoint % 1000 === 0) { - const ecg = ecgHeartRateArr[STEP - 1]; - const bloodPressure = bloodPressureArr[STEP - 1]; - const bloodVolume = bloodVolumeArr[STEP - 1] + 3; - const bloodOxygenation = bloodOxygenationArr[STEP - 1]; - - const dataUpdateInfo = { - ecg: Math.floor(ecg * 20), - bloodPressure1: Math.floor(bloodPressure * 46), - bloodPressure2: Math.floor(bloodPressure * 31), - bloodVolume: bloodVolume + 8.6, - bloodOxygenation: Math.floor(bloodOxygenation * 10 + 93), - }; - dataUpdateEventHandler.raiseEvent(dataUpdateInfo); + dataUpdateEventHandler.raiseEvent({ + ecg: ecgArr[STEP - 1], + gsr: gsrArr[STEP - 1], + respiratory: respArr[STEP - 1], + }); } timerId = setTimeout(runUpdateDataOnTimeout, TIMER_TIMEOUT_MS); }; - const subscribeToDataUpdates = (handler: (info: TDataUpdateInfo) => void) => { - dataUpdateEventHandler.subscribe(handler); + // Enhanced WebSocket handler with signal processing + let wsHandler: ESP32WebSocketHandler | null = null; + + // Start fallback data after a small delay to ensure chart is ready + if (!timerId) { + console.log("๐Ÿš€ Starting fallback data generation after chart initialization..."); + + // Small delay to ensure chart is fully ready + setTimeout(() => { + console.log("โฐ Chart ready, starting fallback data..."); + + // Add some initial data to the chart so it's not empty + const initialData = getValuesFromData(0); + try { + dataSeriesEcg.appendRange(initialData.xArr, initialData.ecgArr); + dataSeriesGsr.appendRange(initialData.xArr, initialData.gsrArr); + dataSeriesResp.appendRange(initialData.xArr, initialData.respArr); + console.log("๐Ÿ“Š Initial fallback data added to chart:", { + ecgPoints: initialData.ecgArr.length, + gsrPoints: initialData.gsrArr.length, + respPoints: initialData.respArr.length, + ecgRange: `${Math.min(...initialData.ecgArr)} to ${Math.max(...initialData.ecgArr)}`, + }); + } catch (error) { + console.error("Error adding initial fallback data:", error); + } + + runUpdateDataOnTimeout(); + }, 1000); // 1 second delay + } + + function startWebSocket() { + startTimer("websocket_init"); + info("WEBSOCKET", "Starting ESP32 WebSocket connection with dynamic IP detection..."); + + wsHandler = new ESP32WebSocketHandler(respirationProcessor, ecgProcessor, (data: any) => { + debug("WEBSOCKET", "ESP32 data received", { type: data.type, timestamp: data.timestamp || Date.now() }); + + switch (data.type) { + case "connection": + if (data.status === "connected") { + endTimer("websocket_init", "WEBSOCKET"); + info("WEBSOCKET", "ESP32 WebSocket connected successfully!"); + if (timerId) { + clearTimeout(timerId); + timerId = undefined; + } + connectionStatusEventHandler.raiseEvent("connected"); + } else if (data.status === "disconnected" || data.status === "error") { + warn("WEBSOCKET", `ESP32 WebSocket ${data.status}`, data); + if (!timerId) runUpdateDataOnTimeout(); + connectionStatusEventHandler.raiseEvent("disconnected"); + } + break; + + case "respiratory": + // Process respiratory data through signal processor + lastXValue++; + dataBuffer.resp.push(data.value); + dataBuffer.timestamps.push(lastXValue); + + // Update chart with processed data + if (dataBuffer.resp.length > 0) { + try { + appendDataToChart(dataSeriesResp, dataBuffer.resp, dataBuffer.timestamps); + dataBuffer.resp = []; + dataBuffer.timestamps = []; + } catch (error) { + console.error("Error processing respiratory data:", error); + } + } + + // Emit processed respiration metrics + dataUpdateEventHandler.raiseEvent({ + respiratory: data.value, + respirationMetrics: data.metrics, + breathingState: data.state, + }); + break; + + case "ecg": + startTimer("ecg_processing"); + lastXValue++; + dataBuffer.ecg.push(data.value); + dataBuffer.timestamps.push(lastXValue); + + if (dataBuffer.ecg.length > 0) { + try { + appendDataToChart(dataSeriesEcg, dataBuffer.ecg, dataBuffer.timestamps); + dataBuffer.ecg = []; + dataBuffer.timestamps = []; + } catch (error) { + console.error("Error processing ECG data:", error); + } + } + + // Use ECG metrics from signal processor (includes heart rate) + const ecgMetrics = data.ecgMetrics || ecgProcessor.getMetrics(); + const signalQuality = ecgProcessor.getSignalQuality(); + + endTimer("ecg_processing", "ECG"); + debug("ECG", "ECG data processed", { + value: data.value, + quality: signalQuality.quality, + metrics: ecgMetrics, + }); - // automatically cleanup subscription whe surface is deleted - sciChartSurface.addDeletable({ delete: () => dataUpdateEventHandler.unsubscribeAll() }); + dataUpdateEventHandler.raiseEvent({ + ecg: data.value, + ecgMetrics: ecgMetrics, + bpm: ecgMetrics.validBeats > 0 ? Math.round(60000 / ecgMetrics.meanIBI) : 0, + hrv: ecgMetrics.sdnn, + }); + break; + + case "gsr": + startTimer("gsr_processing"); + lastXValue++; + dataBuffer.gsr.push(data.value); + dataBuffer.timestamps.push(lastXValue); + + // Process GSR through trend analyzer + let gsrTrend = null; + let gsrStats = null; + try { + gsrTrendAnalyzer.addDataPoint(data.value, Date.now()); + gsrTrend = gsrTrendAnalyzer.getTrend(); + gsrStats = gsrTrendAnalyzer.getStatistics(); + } catch (error) { + console.error("Error processing GSR data:", error); + } + + endTimer("gsr_processing", "GSR"); + debug("GSR", "GSR real sensor data processed", { + value: data.value, + trend: gsrTrend, + stats: gsrStats, + }); + + dataUpdateEventHandler.raiseEvent({ + gsr: data.value, + gsrTrend: gsrTrend, + }); + break; + + case "ibi": + startTimer("ibi_processing"); + // Add IBI to ECG processor for HRV analysis + ecgProcessor.addIBI(data.value, Date.now()); + + // Get updated ECG metrics including HRV + const updatedEcgMetrics = ecgProcessor.getMetrics(); + + endTimer("ibi_processing", "IBI"); + info("IBI", "IBI/HRV real sensor data processed", { + ibi: data.value, + bpm: data.hr, + metrics: updatedEcgMetrics, + }); + + dataUpdateEventHandler.raiseEvent({ + hrv: data.value, + bpm: data.hr, + ecgMetrics: updatedEcgMetrics, + }); + break; + + case "heartrate": + startTimer("heartrate_processing"); + + // Process heart rate data + const heartRateMetrics = { + bpm: data.bpm, + ibi: data.ibi, + }; + + endTimer("heartrate_processing", "HEARTRATE"); + info("HEARTRATE", "Heart rate real sensor data processed", { + bpm: data.bpm, + ibi: data.ibi, + }); + + dataUpdateEventHandler.raiseEvent({ + bpm: data.bpm, + ibi: data.ibi, + }); + break; + + default: + console.warn("Unknown ESP32 message type:", data.type); + } + }); + + wsHandler.connect(); + } + + const subscribeToDataUpdates = (handler: (info?: TDataUpdateInfo) => void) => { + dataUpdateEventHandler.subscribe(handler); + const unsubscribe = () => dataUpdateEventHandler.unsubscribe(handler); + sciChartSurface.addDeletable({ delete: unsubscribe }); + return unsubscribe; }; const stopUpdate = () => { clearTimeout(timerId); timerId = undefined; + if (wsHandler) { + wsHandler.disconnect(); + wsHandler = null; + } }; const startUpdate = () => { - if (timerId) { - stopUpdate(); - } + if (timerId) stopUpdate(); runUpdateDataOnTimeout(); + try { + startWebSocket(); + } catch { + // If WebSocket fails to construct, fallback loop keeps running + } }; return { sciChartSurface, subscribeToDataUpdates, controls: { startUpdate, stopUpdate } }; diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/ecgProcessor.ts b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/ecgProcessor.ts new file mode 100644 index 000000000..dd20b54ab --- /dev/null +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/ecgProcessor.ts @@ -0,0 +1,393 @@ +// ECG Signal Processing Module for Quality Assessment and HRV Analysis +// Complements ESP32's Pan-Tompkins algorithm with frontend validation and analysis +import { debug, info, warn, error as logError, startTimer, endTimer } from "./debugLogger"; + +export interface ECGMetrics { + signalQuality: number; // 0-100, signal quality score + noiseLevel: number; // 0-100, noise assessment + artifactCount: number; // Number of detected artifacts + validBeats: number; // Number of valid QRS detections + meanIBI: number; // Average inter-beat interval + sdnn: number; // Standard deviation of NN intervals + rmssd: number; // Root mean square of successive differences + pnn50: number; // Percentage of NN50 + lfPower: number; // Low frequency power (0.04-0.15 Hz) + hfPower: number; // High frequency power (0.15-0.4 Hz) + lfHfRatio: number; // LF/HF ratio + coherence: number; // Heart rate coherence score + + // Additional HRV metrics for medical analysis + nn50: number; // Number of successive RR intervals that differ by more than 50ms + triangularIndex: number; // Triangular index of HRV + stressIndex: number; // Stress index based on HRV + vagalTone: number; // Vagal tone estimation +} + +export interface ECGQualityConfig { + samplingRate: number; // Hz + baselineWindow: number; // samples for baseline calculation + noiseThreshold: number; // threshold for noise detection + artifactThreshold: number; // threshold for artifact detection + minValidIBI: number; // minimum valid IBI in ms + maxValidIBI: number; // maximum valid IBI in ms + hrvWindowSize: number; // ms for HRV calculation window +} + +export class ECGSignalProcessor { + private config: ECGQualityConfig; + private ecgBuffer: Array<{ value: number; timestamp: number }> = []; + private ibiBuffer: Array<{ value: number; timestamp: number }> = []; + private metrics: ECGMetrics = { + signalQuality: 0, + noiseLevel: 0, + artifactCount: 0, + validBeats: 0, + meanIBI: 0, + sdnn: 0, + rmssd: 0, + pnn50: 0, + lfPower: 0, + hfPower: 0, + lfHfRatio: 0, + coherence: 0, + + // Additional HRV metrics for medical analysis + nn50: 0, + triangularIndex: 0, + stressIndex: 0, + vagalTone: 0, + }; + + constructor(config: Partial = {}) { + this.config = { + samplingRate: 250, // 250 Hz to match ESP32 + baselineWindow: 1000, // 4 seconds at 250Hz + noiseThreshold: 0.1, // 10% of signal range + artifactThreshold: 0.3, // 30% of signal range + minValidIBI: 300, // 300ms minimum (200 BPM max) + maxValidIBI: 2000, // 2000ms maximum (30 BPM min) + hrvWindowSize: 60000, // 60 seconds for HRV analysis + ...config, + }; + info("ECG", "ECGSignalProcessor initialized", this.config); + } + + // Add new ECG data point + public addECGPoint(value: number, timestamp: number): void { + this.ecgBuffer.push({ value, timestamp }); + + // Remove old data outside the window + const cutoffTime = timestamp - this.config.hrvWindowSize; + this.ecgBuffer = this.ecgBuffer.filter((d) => d.timestamp >= cutoffTime); + + // Assess signal quality + this.assessSignalQuality(); + } + + // Add IBI data from Pan-Tompkins + public addIBI(ibi: number, timestamp: number): void { + // Validate IBI range + if (ibi >= this.config.minValidIBI && ibi <= this.config.maxValidIBI) { + this.ibiBuffer.push({ value: ibi, timestamp }); + + // Remove old IBI data + const cutoffTime = timestamp - this.config.hrvWindowSize; + this.ibiBuffer = this.ibiBuffer.filter((d) => d.timestamp >= cutoffTime); + + // Update HRV metrics + this.calculateHRVMetrics(); + } else { + this.metrics.artifactCount++; + } + } + + // Assess ECG signal quality + private assessSignalQuality(): void { + if (this.ecgBuffer.length < this.config.baselineWindow) return; + + const recentData = this.ecgBuffer.slice(-this.config.baselineWindow); + const values = recentData.map((d) => d.value); + + // Calculate baseline drift + const baseline = this.calculateBaseline(values); + const baselineDrift = Math.abs(values[values.length - 1] - values[0]); + + // Calculate noise level (high-frequency components) + const noiseLevel = this.calculateNoiseLevel(values); + + // Calculate signal amplitude + const signalRange = values.length > 0 ? Math.max(...values) - Math.min(...values) : 0; + + // Assess artifacts (sudden large changes) + const artifactCount = this.detectArtifacts(values); + + // Calculate quality score + let qualityScore = 100; + + // Penalize for noise + qualityScore -= noiseLevel * 50; + + // Penalize for baseline drift + if (baselineDrift > this.config.noiseThreshold) { + qualityScore -= (baselineDrift / this.config.noiseThreshold) * 20; + } + + // Penalize for artifacts + qualityScore -= artifactCount * 10; + + // Penalize for low signal amplitude + if (signalRange < 0.1) { + qualityScore -= 30; + } + + this.metrics.signalQuality = Math.max(0, Math.min(100, qualityScore)); + this.metrics.noiseLevel = noiseLevel; + this.metrics.artifactCount = artifactCount; + this.metrics.validBeats = this.ibiBuffer.length; + } + + // Calculate baseline using median filter + private calculateBaseline(values: number[]): number { + if (values.length === 0) return 0; + + const sorted = [...values].sort((a, b) => a - b); + return sorted[Math.floor(sorted.length / 2)]; + } + + // Calculate noise level using high-pass filtering + private calculateNoiseLevel(values: number[]): number { + if (values.length < 10) return 0; + + let noiseSum = 0; + for (let i = 1; i < values.length; i++) { + const diff = Math.abs(values[i] - values[i - 1]); + noiseSum += diff; + } + + return noiseSum / (values.length - 1); + } + + // Detect artifacts (sudden large changes) + private detectArtifacts(values: number[]): number { + let artifactCount = 0; + const threshold = this.config.artifactThreshold; + + for (let i = 1; i < values.length; i++) { + const diff = Math.abs(values[i] - values[i - 1]); + if (diff > threshold) { + artifactCount++; + } + } + + return artifactCount; + } + + // Calculate HRV metrics + private calculateHRVMetrics(): void { + if (this.ibiBuffer.length < 10) return; // Need at least 10 beats + + const ibiValues = this.ibiBuffer.map((d) => d.value); + + // Basic statistics + this.metrics.meanIBI = ibiValues.reduce((sum, val) => sum + val, 0) / ibiValues.length; + + // SDNN (Standard Deviation of NN intervals) + const mean = this.metrics.meanIBI; + const variance = ibiValues.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / ibiValues.length; + this.metrics.sdnn = Math.sqrt(variance); + + // RMSSD (Root Mean Square of Successive Differences) + let rmssdSum = 0; + for (let i = 1; i < ibiValues.length; i++) { + const diff = ibiValues[i] - ibiValues[i - 1]; + rmssdSum += diff * diff; + } + // Division by zero protection + this.metrics.rmssd = ibiValues.length > 1 ? Math.sqrt(rmssdSum / (ibiValues.length - 1)) : 0; + + // pNN50 (Percentage of NN50) + let nn50Count = 0; + for (let i = 1; i < ibiValues.length; i++) { + const diff = Math.abs(ibiValues[i] - ibiValues[i - 1]); + if (diff > 50) nn50Count++; + } + // Division by zero protection + this.metrics.pnn50 = ibiValues.length > 1 ? (nn50Count / (ibiValues.length - 1)) * 100 : 0; + + // NN50 count (absolute number) + this.metrics.nn50 = nn50Count; + + // Calculate additional advanced HRV metrics + this.calculateAdvancedHRVMetrics(ibiValues); + + // Frequency domain analysis (simplified) + this.calculateFrequencyMetrics(ibiValues); + + // Calculate coherence + this.calculateCoherence(); + } + + // Calculate additional advanced HRV metrics + private calculateAdvancedHRVMetrics(ibiValues: number[]): void { + if (ibiValues.length < 10) return; + + // Triangular Index (TINN) - Triangular interpolation of NN interval histogram + const minIBI = Math.min(...ibiValues); + const maxIBI = Math.max(...ibiValues); + const ibiRange = maxIBI - minIBI; + + if (ibiRange > 0) { + // Create histogram bins + const binCount = Math.min(20, Math.floor(ibiValues.length / 2)); + const binSize = ibiRange / binCount; + const histogram = new Array(binCount).fill(0); + + for (const ibi of ibiValues) { + const binIndex = Math.min(Math.floor((ibi - minIBI) / binSize), binCount - 1); + histogram[binIndex]++; + } + + // Find the bin with maximum count (mode) + const maxCount = Math.max(...histogram); + const totalCount = ibiValues.length; + + // Triangular index = total count / maximum count + this.metrics.triangularIndex = totalCount / maxCount; + } else { + this.metrics.triangularIndex = 0; + } + + // Stress Index - Based on HRV and heart rate + const meanIBI = this.metrics.meanIBI; + const heartRate = 60000 / meanIBI; // Convert to BPM + + // Stress index formula: (amplitude * 1000) / (2 * mode * range) + const amplitude = this.metrics.sdnn; + const mode = this.metrics.triangularIndex > 0 ? this.metrics.triangularIndex : 1; + const stressRange = Math.max(1, maxIBI - minIBI); + + this.metrics.stressIndex = (amplitude * 1000) / (2 * mode * stressRange); + + // Vagal Tone - Estimation based on RMSSD and HF power + // Higher RMSSD and HF power indicate higher vagal tone + const rmssdScore = Math.min(100, (this.metrics.rmssd / 100) * 100); + const hfScore = Math.min(100, (this.metrics.hfPower / 100) * 100); + + this.metrics.vagalTone = Math.round((rmssdScore + hfScore) / 2); + } + + // Calculate frequency domain metrics (simplified FFT) + private calculateFrequencyMetrics(ibiValues: number[]): void { + // Simplified frequency analysis using power spectral density + // In a real implementation, you'd use FFT or Lomb-Scargle periodogram + + // For now, use time-domain approximations + const meanIBI = this.metrics.meanIBI; + const ibiVariability = this.metrics.sdnn; + + // Approximate LF and HF power based on IBI variability + this.metrics.lfPower = ibiVariability * 0.6; // ~60% of variability in LF band + this.metrics.hfPower = ibiVariability * 0.4; // ~40% of variability in HF band + + this.metrics.lfHfRatio = this.metrics.hfPower > 0 ? this.metrics.lfPower / this.metrics.hfPower : 1; + } + + // Calculate heart rate coherence + private calculateCoherence(): void { + // Coherence is a measure of heart rate variability pattern + // Higher HRV with regular patterns indicates better coherence + + const hrvScore = Math.min(100, (this.metrics.sdnn / 100) * 100); + const regularityScore = Math.max(0, 100 - this.metrics.artifactCount * 5); + const balanceScore = this.metrics.lfHfRatio > 0.5 && this.metrics.lfHfRatio < 2.0 ? 100 : 50; + + this.metrics.coherence = Math.round((hrvScore + regularityScore + balanceScore) / 3); + } + + // Get current metrics + public getMetrics(): ECGMetrics { + return { ...this.metrics }; + } + + // Get signal quality assessment + public getSignalQuality(): { quality: string; description: string } { + const quality = this.metrics.signalQuality; + + if (quality >= 80) { + return { quality: "Excellent", description: "High-quality ECG signal with minimal noise" }; + } else if (quality >= 60) { + return { quality: "Good", description: "Good signal quality with some noise" }; + } else if (quality >= 40) { + return { quality: "Fair", description: "Moderate signal quality, artifacts detected" }; + } else { + return { quality: "Poor", description: "Low signal quality, significant artifacts" }; + } + } + + // Reset processor state + public reset(): void { + this.ecgBuffer = []; + this.ibiBuffer = []; + this.metrics = { + signalQuality: 0, + noiseLevel: 0, + artifactCount: 0, + validBeats: 0, + meanIBI: 0, + sdnn: 0, + rmssd: 0, + pnn50: 0, + lfPower: 0, + hfPower: 0, + lfHfRatio: 0, + coherence: 0, + + // Additional HRV metrics for medical analysis + nn50: 0, + triangularIndex: 0, + stressIndex: 0, + vagalTone: 0, + }; + } + + // Update configuration + public updateConfig(newConfig: Partial): void { + this.config = { ...this.config, ...newConfig }; + } +} + +// Utility functions for ECG analysis +export const ecgUtils = { + // Calculate moving average for smoothing + movingAverage: (data: number[], windowSize: number): number[] => { + const result = []; + for (let i = 0; i < data.length; i++) { + const start = Math.max(0, i - windowSize + 1); + const window = data.slice(start, i + 1); + const average = window.reduce((sum, val) => sum + val, 0) / window.length; + result.push(average); + } + return result; + }, + + // Detect R-peaks using simple threshold method (backup to Pan-Tompkins) + detectRPeaks: (data: number[], threshold: number): number[] => { + const peaks = []; + for (let i = 1; i < data.length - 1; i++) { + if (data[i] > threshold && data[i] > data[i - 1] && data[i] > data[i + 1]) { + peaks.push(i); + } + } + return peaks; + }, + + // Calculate IBI from R-peak indices + calculateIBI: (peakIndices: number[], samplingRate: number): number[] => { + const ibi = []; + for (let i = 1; i < peakIndices.length; i++) { + const interval = ((peakIndices[i] - peakIndices[i - 1]) / samplingRate) * 1000; // Convert to ms + ibi.push(interval); + } + return ibi; + }, +}; diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/exampleInfo.tsx b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/exampleInfo.tsx deleted file mode 100644 index ea7c3e8bf..000000000 --- a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/exampleInfo.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { createExampleInfo } from "../../../exampleInfoUtils"; -import { IExampleMetadata } from "../../../IExampleMetadata"; - -const metaData: IExampleMetadata = - //// This metadata is computer generated - do not edit! - { - exampleId: "FeaturedAppsMedicalChartsVitalSignsMonitorDemo", - imagePath: "javascript-vital-signs-ecg-medical-chart-example.jpg", - description: - "Showcases how SciChart.js can be used in a **Medical context**, drawing ECGs with our High Performance JavaScript Charts", - tips: [], - frameworks: { - javascript: { - subtitle: - "Showcases how SciChart.js can be used in a **Medical context**, drawing ECGs with our High Performance JavaScript Charts", - title: "JavaScript Vital Signs ECG/EKG Medical Demo", - pageTitle: "JavaScript Vital Signs ECG/EKG Medical Demo", - metaDescription: - "In this example we are simulating four channels of data showing that SciChart.js can be used to draw real-time\n ECG/EKG charts and graphs to monitor heart reate, body temperature, blood pressure, pulse rate, SPO2 blood\n oxygen, volumetric flow and more.", - markdownContent: - "## Vital Signs Monitor Demo in JavaScript\n\n### Overview\nThis example, titled **Vital Signs Monitor Demo**, showcases how to build a high-performance real-time medical chart using SciChart.js with JavaScript. It simulates multiple medical signals including ECG, blood pressure, blood volume, and blood oxygenation, and is optimized for continuous data streaming and efficient updates.\n\n### Technical Implementation\nThe demo initializes a `SciChartSurface` with a hidden shared `CategoryAxis` for cyclic data management, which is essential for using FIFO-sweeping mode. Data is continuously appended to multiple `XyDataSeries` via the `appendRange()` method, ensuring smooth real-time updates. The use of `fifoCapacity` and `fifoSweeping` mode (see [DataSeries Realtime Updates](https://www.scichart.com/documentation/js/current/DataSeries_RealtimeUpdates.html)) allows the series to wrap around once the specified capacity is reached, optimizing performance. Additionally, a recursive `setTimeout` loop simulates real-time data streaming, while a custom `EventHandler` is used to update an information panel with computed metrics. For more detail on real-time updates, refer to [Adding Realtime Updates](https://www.scichart.com/documentation/js/current/Tutorial%2004%20-%20Adding%20Realtime%20Updates.html).\n\n### Features and Capabilities\n**Real-Time Data Streaming:**\nThe demo employs a `setTimeout` loop to periodically fetch and append data points, demonstrating efficient real-time updating using JavaScript.\n\n**Performance Optimization:**\nBy configuring properties like `fifoCapacity` and `fifoSweeping`, the example highlights how FIFO buffers improve performance and simplify code for ECG style wrap-around charts when handling large volumes of data. For further insights, see the [Performance Tips & Tricks](https://www.scichart.com/documentation/js/current/Performance%20Tips.html) guide.\n\n**Axis Configuration and Layout:**\nThe example uses a hidden `CategoryAxis` on the X-axis and multiple `NumericAxis` Y-axes that are vertically stacked with the `RightAlignedOuterVerticallyStackedAxisLayoutStrategy`. This approach simplifies the synchronization of multiple data series. More information is available in the [Vertically Stacked Axis](https://www.scichart.com/documentation/js/current/Axis%20Layout%20-%20Vertically%20Stacked%20Axis.html) documentation.\n\n**Custom Event Handling and Memory Management:**\nCustom event handlers are implemented using the `EventHandler` class to update the UI with the latest metrics. Additionally, `sciChartSurface.addDeletable()` is used to automatically clean up these subscriptions, ensuring optimal resource management during the chart's lifecycle.\n\n### Integration and Best Practices\nEven though this demo is built using JavaScript, the underlying principles and performance optimizations can be applied across various frameworks. It emphasizes best practices for real-time data visualization including efficient data appending, optimized axis configurations, and sustainable memory management. By following these techniques, developers can create responsive, high-performance charting applications using SciChart.js.", - }, - react: { - subtitle: - "Showcases how SciChart.js can be used in a **Medical context**, drawing ECGs with our High Performance JavaScript Charts", - title: "React Vital Signs ECG/EKG Medical Demo", - pageTitle: "React Vital Signs ECG/EKG Medical Demo", - metaDescription: - "In this example we are simulating four channels of data showing that SciChart.js can be used to draw real-time\n ECG/EKG charts and graphs to monitor heart reate, body temperature, blood pressure, pulse rate, SPO2 blood\n oxygen, volumetric flow and more.", - markdownContent: - "## Vital Signs Monitor Demo - React Integration\n\n### Overview\nThis example demonstrates a real-time monitoring demo for vital signs such as ECG, blood pressure, blood volume, and blood oxygenation using SciChart.js integrated into a React application. The demo leverages the power of React hooks for state management and component lifecycle, providing a dynamic and interactive user experience.\n\n### Technical Implementation\nThe core of the implementation is based on the `` component from the [scichart-react](https://www.scichart.com/blog/react-charts-with-scichart-js/) library which initializes the chart using a dedicated draw function. This function configures the `SciChartSurface` by setting up axes, renderable series, and data series with FIFO sweeping for continuous real-time updates. The React component makes extensive use of `useRef` and `useState` to manage external chart controls and to subscribe to real-time data updates. The initialization callback subscribes to the data update events and properly starts the real-time data stream. Developers interested in building similar components can refer to [Creating a SciChart React Component from the Ground Up](https://www.scichart.com/documentation/js/current/TutorialReusableReactComponent.html) for further guidance.\n\n### Features and Capabilities\nThe demo showcases several key features including real-time data updates, efficient state management, and high-performance rendering using WebGL acceleration. Dynamic info panels update in sync with the chart data, illustrating how asynchronous data streams are handled natively in the React environment. The use of optimized data series with `fifoCapacity` and `fifoSweeping` mode enabled ensures smooth and continuous chart updates even under high data frequency, similar to the techniques described in [Adding Realtime Updates | JavaScript Chart Documentation - SciChart](https://www.scichart.com/documentation/js/current/Tutorial%2004%20-%20Adding%20Realtime%20Updates.html).\n\n### Integration and Best Practices\nIntegration with React is achieved by employing best practices such as using React hooks for managing state and references to external library controls. The `onInit` callback initializes the chart and starts the live data updates while also returning a cleanup function to stop updates upon component unmounting, thereby preventing potential memory leaks. This approach of handling third-party libraries within React applications is explained in detail in [React Charts with SciChart.js: Introducing โ€œSciChart Reactโ€](https://www.scichart.com/blog/react-charts-with-scichart-js/) and further elaborated in [Creating a React Dashboard with SciChart.js, SciChart-React and DeepSeek](https://www.scichart.com/blog/creating-a-react-dashboard-with-scichart-js-scichart-react-and-deepseek-r1/). Moreover, the example demonstrates how asynchronous data handling and event-driven updates can be neatly integrated with React's component lifecycle, ensuring an efficient, high-performance application.\n", - }, - angular: { - subtitle: - "Showcases how SciChart.js can be used in a **Medical context**, drawing ECGs with our High Performance JavaScript Charts", - title: "Angular Vital Signs ECG/EKG Medical Demo", - pageTitle: "Angular Vital Signs ECG/EKG Medical Demo", - metaDescription: - "In this example we are simulating four channels of data showing that SciChart.js can be used to draw real-time\n ECG/EKG charts and graphs to monitor heart reate, body temperature, blood pressure, pulse rate, SPO2 blood\n oxygen, volumetric flow and more.", - markdownContent: - "## Vital Signs Monitor Demo - Angular\n\n### Overview\nThis example demonstrates an Angular implementation of a real-time medical monitoring chart using SciChart.js. The demo visualizes multiple vital signs data channels including ECG, blood pressure, blood volume, and blood oxygenation. By leveraging the `ScichartAngularComponent` provided by [scichart-angular](https://www.npmjs.com/package/scichart-angular), it delivers high-performance chart rendering suitable for demanding real-time applications.\n\n### Technical Implementation\nThe Angular component initializes the `SciChartSurface` using SciChart.jsโ€™s API, configuring multiple axes and renderable series to display the various vital signs. Key aspects include the use of Angular lifecycle hooks as detailed in [Component Lifecycle - Angular](https://angular.io/guide/lifecycle-hooks) to manage initialization and cleanup, and dynamic styling through Angularโ€™s [ngStyle](https://ultimatecourses.com/blog/using-ngstyle-in-angular-for-dynamic-styling) to create responsive info panels. Real-time data updates are implemented via a timer-based update mechanism with an event subscription model, ensuring that all data series and their corresponding info displays remain synchronized.\n\n### Features and Capabilities\nThe demo supports **real-time chart updates**, dynamically plotting data from multiple channels with advanced WebGL rendering for smooth, high-frequency refreshes. It manages four separate renderable series, each corresponding to different vital signs, and updates detailed info panels using the [Vertically Stacked Axis](https://www.scichart.com/documentation/js/current/Axis%20Layout%20-%20Vertically%20Stacked%20Axis.html) feature to reflect the latest measurements continuously. The use of dataSeries with `fifoCapacity` and `fifoSweeping` mode enable wrap-around charts, which is common when rendering ECG style applications. This provides an engaging and immediate visualization experience crucial for medical monitoring scenarios.\n\n### Integration and Best Practices\nThe implementation follows Angular best practices; it effectively incorporates Angular dependency injection and lifecycle management to integrate with third-party libraries like SciChart.js. Developers are encouraged to review [Getting Started with SciChart JS](https://www.scichart.com/getting-started/scichart-javascript/) and [Tutorial 01 - Setting up a npm Project with SciChart.js](https://www.scichart.com/documentation/js/current/Tutorial%2001%20-%20Setting%20up%20a%20Project%20with%20SciChart.js.html) for guidance on initial setup. Moreover, by utilizing robust event handling and efficient subscription managementโ€”as is further explained in [Performance Optimization Techniques in Angular](https://www.xenonstack.com/blog/performance-optimization-in-angular)โ€”this demo illustrates how Angular applications can integrate third-party tools effectively while maintaining optimal performance in a real-time data environment.", - }, - }, - documentationLinks: [ - { - href: "https://www.scichart.com/documentation/js/current/SciChart_JS_User_Manual.html", - title: "The SciChart.js documentation contains loads of useful information on how to use our High Performance JavaScript Charts", - linkTitle: "SciChart.js Documentation Home", - }, - ], - path: "vital-signs-ecg-medical-chart-example", - metaKeywords: "ecg, ekg, realtime, medical, chart, javascript, webgl, canvas", - onWebsite: true, - filepath: "FeaturedApps/MedicalCharts/VitalSignsMonitorDemo", - thumbnailImage: "javascript-vital-signs-ecg-medical-chart-example.jpg", - sandboxConfig: {}, - markdownContent: null, - pageLayout: "default", - extraDependencies: {}, - }; -//// End of computer generated metadata - -export const vitalSignsMonitorDemoExampleInfo = createExampleInfo(metaData); diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/firebaseLogger.ts b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/firebaseLogger.ts new file mode 100644 index 000000000..5c3b302c6 --- /dev/null +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/firebaseLogger.ts @@ -0,0 +1,371 @@ +import { initializeApp } from "firebase/app"; +import { getDatabase, ref, set, push, get } from "firebase/database"; +import { firebaseConfig } from "../../../../../config/environment"; + +// Debug: Log the config being used +console.log("Firebase Config being used:", { + apiKey: firebaseConfig.apiKey.substring(0, 10) + "...", + authDomain: firebaseConfig.authDomain, + databaseURL: firebaseConfig.databaseURL, + projectId: firebaseConfig.projectId, +}); + +// Debug: Check environment variables directly +console.log("Environment variables check:", { + REACT_APP_FIREBASE_API_KEY: + typeof process !== "undefined" + ? process.env?.REACT_APP_FIREBASE_API_KEY?.substring(0, 10) + "..." + : "process not available", + REACT_APP_FIREBASE_DATABASE_URL: + typeof process !== "undefined" ? process.env?.REACT_APP_FIREBASE_DATABASE_URL : "process not available", + REACT_APP_FIREBASE_PROJECT_ID: + typeof process !== "undefined" ? process.env?.REACT_APP_FIREBASE_PROJECT_ID : "process not available", +}); + +// Initialize Firebase with error handling +let app: any = null; +let database: any = null; + +try { + app = initializeApp(firebaseConfig); + database = getDatabase(app); + console.log("โœ… Firebase initialized successfully"); + console.log("๐Ÿ“Š Database URL:", firebaseConfig.databaseURL); +} catch (error) { + console.error("โŒ Firebase initialization failed:", error); + // Create dummy objects to prevent crashes + app = null; + database = null; +} + +// Type guard for Firebase errors +interface FirebaseError { + code: string; + message: string; +} + +function isFirebaseError(error: unknown): error is FirebaseError { + return typeof error === "object" && error !== null && "code" in error; +} + +export interface ProcessedSensorData { + timestamp: number; + heartRate: number; + respiratoryRate: number; + gsrValue: number; + gsrTrend: "increasing" | "decreasing" | "stable"; + ecgQuality: "good" | "fair" | "poor"; + hrvMetrics: { + sdnn: number; + rmssd: number; + pnn50: number; + lfPower: number; + hfPower: number; + lfHfRatio: number; + // Additional HRV metrics for medical analysis + nn50: number; // Number of successive RR intervals that differ by more than 50ms + triangularIndex: number; // Triangular index of HRV + stressIndex: number; // Stress index based on HRV + vagalTone: number; // Vagal tone estimation + }; + respiratoryMetrics: { + breathCount: number; + inhalePercent: number; + exhalePercent: number; + breathingState: "inhale" | "exhale" | "transition"; + // Enhanced HW484 respiration sensor metrics + tidalVolume: number; // Estimated tidal volume in ml + minuteVolume: number; // Minute ventilation in L/min + inspiratoryTime: number; // Time of inspiration in seconds + expiratoryTime: number; // Time of expiration in seconds + totalBreathTime: number; // Total breath cycle time in seconds + inspiratoryExpiratoryRatio: number; // I:E ratio (normal: 1:2 to 1:3) + peakInspiratoryFlow: number; // Peak inspiratory flow rate in L/min + peakExpiratoryFlow: number; // Peak expiratory flow rate in L/min + respiratoryEffort: number; // Respiratory effort index (0-100) + breathingRegularity: number; // Coefficient of variation of breath intervals + apneaHypopneaIndex: number; // AHI score for sleep apnea detection + respiratorySinusArrhythmia: number; // RSA magnitude (heart rate variability with breathing) + // Advanced respiratory analysis + respiratoryPhaseCoherence: number; // Phase coherence between heart rate and respiration + respiratoryRateVariability: number; // Variability in respiratory rate + breathDepthConsistency: number; // Consistency of breath depth + respiratoryEfficiency: number; // Efficiency of breathing pattern + // Medical assessment scores + respiratoryDistressScore: number; // Clinical respiratory distress assessment + breathingPatternQuality: number; // Quality score of breathing pattern (0-100) + respiratoryFatigueIndex: number; // Index of respiratory muscle fatigue + }; + connectionStatus: { + esp32Connected: boolean; + sensorsConnected: { + ecg: boolean; + gsr: boolean; + respiratory: boolean; + }; + }; +} + +class FirebaseLogger { + private isConnected: boolean = false; + private lastLogTime: number = 0; + private readonly LOG_INTERVAL = 30000; // 30 seconds + private logCount: number = 0; + + constructor() { + console.log("๐Ÿ”ง Firebase Logger initialized"); + this.testConnection(); + } + + /** + * Test Firebase connection by trying to read from database + */ + private async testConnection(): Promise { + if (!database) { + console.log("โš ๏ธ Firebase Logger: Database not available"); + return; + } + + try { + console.log("๐Ÿงช Testing Firebase connection..."); + console.log("๐Ÿ“Š Database object:", database); + console.log("๐Ÿ”— Database URL:", firebaseConfig.databaseURL); + + // Try to read from a test path to verify connection + const testRef = ref(database, "connection_test"); + console.log("๐Ÿ“ Test reference created:", testRef); + + const testData = { + timestamp: Date.now(), + message: "Connection test from frontend", + status: "success", + testId: Math.random().toString(36).substr(2, 9), + }; + + console.log("๐Ÿ“ค Attempting to write test data:", testData); + await set(testRef, testData); + + console.log("โœ… Firebase Logger: Connection test successful"); + console.log("๐Ÿ“Š Test data written to:", testRef.toString()); + this.isConnected = true; + + // Also try to read it back + const snapshot = await get(testRef); + if (snapshot.exists()) { + console.log("๐Ÿ“– Test data read back successfully:", snapshot.val()); + } else { + console.log("โš ๏ธ Test data written but could not be read back"); + } + } catch (error) { + console.error("โŒ Firebase Logger: Connection test failed:", error); + console.error("๐Ÿ” Error details:", { + name: error instanceof Error ? error.name : "Unknown", + message: error instanceof Error ? error.message : String(error), + code: isFirebaseError(error) ? error.code : "Unknown", + stack: error instanceof Error ? error.stack : "No stack trace", + }); + this.isConnected = false; + + // Check if it's a security rules issue + if (isFirebaseError(error) && error.code === "PERMISSION_DENIED") { + console.error("๐Ÿ”’ Firebase Security Rules Issue: Permission denied. Check your database rules."); + console.log("๐Ÿ’ก Make sure your Firebase Realtime Database rules allow write access."); + } + } + } + + /** + * Set connection status + */ + setConnectionStatus(connected: boolean): void { + this.isConnected = connected; + console.log(`๐Ÿ”Œ Firebase Logger: Connection status set to ${connected}`); + } + + /** + * Log processed sensor data to Firebase + * Note: This should only be called when ESP32 is connected (real sensor data) + */ + async logProcessedData(data: ProcessedSensorData): Promise { + if (!database) { + console.log("โš ๏ธ Firebase Logger: Database not available, skipping log"); + return; + } + + // Double-check that we're only logging real sensor data + if (!data.connectionStatus.esp32Connected) { + console.log("โš ๏ธ Firebase Logger: Skipping log - ESP32 not connected (fallback data)"); + return; + } + + const currentTime = Date.now(); + if (currentTime - this.lastLogTime < this.LOG_INTERVAL) { + console.log("โฐ Firebase Logger: Skipping log - too soon since last log"); + return; // Don't log too frequently + } + + try { + this.logCount++; + + // Create a unique timestamp for the log entry + const logRef = push(ref(database, "processed_sensor_logs")); + + // Add the data with the generated key + const logData = { + ...data, + logTimestamp: currentTime, + logId: logRef.key, + logSequence: this.logCount, + source: "frontend", + dataSource: "Real Sensors (ESP32 Connected)", + }; + + await set(logRef, logData); + + this.lastLogTime = currentTime; + console.log(`โœ… Firebase Logger: Successfully logged REAL sensor data #${this.logCount} to Firebase`); + console.log("๐Ÿ“Š Logged data:", { + timestamp: new Date(currentTime).toISOString(), + dataSource: "Real Sensors (ESP32 Connected)", + heartRate: data.heartRate, + respiratoryRate: data.respiratoryRate, + gsrValue: data.gsrValue, + esp32Connected: data.connectionStatus.esp32Connected, + // Enhanced HRV metrics logging + hrvMetrics: { + sdnn: data.hrvMetrics.sdnn, + rmssd: data.hrvMetrics.rmssd, + lfPower: data.hrvMetrics.lfPower, + hfPower: data.hrvMetrics.hfPower, + lfHfRatio: data.hrvMetrics.lfHfRatio, + nn50: data.hrvMetrics.nn50, + triangularIndex: data.hrvMetrics.triangularIndex, + stressIndex: data.hrvMetrics.stressIndex, + vagalTone: data.hrvMetrics.vagalTone, + }, + // Enhanced respiratory metrics logging + respiratoryMetrics: { + tidalVolume: data.respiratoryMetrics.tidalVolume, + minuteVolume: data.respiratoryMetrics.minuteVolume, + inspiratoryTime: data.respiratoryMetrics.inspiratoryTime, + expiratoryTime: data.respiratoryMetrics.expiratoryTime, + inspiratoryExpiratoryRatio: data.respiratoryMetrics.inspiratoryExpiratoryRatio, + peakInspiratoryFlow: data.respiratoryMetrics.peakInspiratoryFlow, + peakExpiratoryFlow: data.respiratoryMetrics.peakExpiratoryFlow, + respiratoryEffort: data.respiratoryMetrics.respiratoryEffort, + breathingRegularity: data.respiratoryMetrics.breathingRegularity, + apneaHypopneaIndex: data.respiratoryMetrics.apneaHypopneaIndex, + respiratorySinusArrhythmia: data.respiratoryMetrics.respiratorySinusArrhythmia, + respiratoryPhaseCoherence: data.respiratoryMetrics.respiratoryPhaseCoherence, + respiratoryRateVariability: data.respiratoryMetrics.respiratoryRateVariability, + breathDepthConsistency: data.respiratoryMetrics.breathDepthConsistency, + respiratoryEfficiency: data.respiratoryMetrics.respiratoryEfficiency, + respiratoryDistressScore: data.respiratoryMetrics.respiratoryDistressScore, + breathingPatternQuality: data.respiratoryMetrics.breathingPatternQuality, + respiratoryFatigueIndex: data.respiratoryMetrics.respiratoryFatigueIndex, + }, + }); + + // Also log to a summary path for easy monitoring + const summaryRef = ref(database, "logs_summary"); + await set(summaryRef, { + lastLogTime: currentTime, + totalLogs: this.logCount, + lastLogData: logData, + lastUpdate: new Date().toISOString(), + dataSource: "Real Sensors (ESP32 Connected)", + status: "Active logging - ESP32 connected", + }); + } catch (error) { + console.error("โŒ Firebase Logger: Failed to log data:", error); + + // Detailed error analysis + if (isFirebaseError(error)) { + if (error.code === "PERMISSION_DENIED") { + console.error("๐Ÿ”’ Permission denied - check Firebase security rules"); + } else if (error.code === "UNAVAILABLE") { + console.error("๐ŸŒ Database unavailable - check internet connection"); + } else if (error.code === "QUOTA_EXCEEDED") { + console.error("๐Ÿ’พ Quota exceeded - check Firebase usage limits"); + } + } + } + } + + /** + * Log a specific event (like connection status change) + */ + async logEvent(eventType: string, eventData: any): Promise { + if (!database) { + return; + } + + try { + const eventRef = push(ref(database, "events")); + await set(eventRef, { + type: eventType, + data: eventData, + timestamp: Date.now(), + source: "frontend", + }); + console.log(`๐Ÿ“ Firebase Logger: Logged event: ${eventType}`); + } catch (error) { + console.error("โŒ Firebase Logger: Failed to log event:", error); + } + } + + /** + * Log error or warning + */ + async logError(errorType: string, errorMessage: string, errorData?: any): Promise { + if (!database) { + return; + } + + try { + const errorRef = push(ref(database, "errors")); + await set(errorRef, { + type: errorType, + message: errorMessage, + data: errorData, + timestamp: Date.now(), + source: "frontend", + }); + console.error(`โŒ Firebase Logger: Logged error: ${errorType} - ${errorMessage}`); + } catch (error) { + console.error("โŒ Firebase Logger: Failed to log error:", error); + } + } + + /** + * Get the last log time + */ + getLastLogTime(): number { + return this.lastLogTime; + } + + /** + * Check if it's time to log again + */ + shouldLog(): boolean { + return Date.now() - this.lastLogTime >= this.LOG_INTERVAL; + } + + /** + * Get connection status + */ + getConnectionStatus(): boolean { + return this.isConnected; + } + + /** + * Get log count + */ + getLogCount(): number { + return this.logCount; + } +} + +// Create and export a singleton instance +// Force recompilation to resolve TypeScript errors +export const firebaseLogger = new FirebaseLogger(); diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/gsrTrendAnalyzer.ts b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/gsrTrendAnalyzer.ts new file mode 100644 index 000000000..7dbbff9b8 --- /dev/null +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/gsrTrendAnalyzer.ts @@ -0,0 +1,312 @@ +// GSR Trend Analyzer for Stress Level Detection +// Analyzes recent GSR values to determine if stress is increasing or decreasing + +export interface GSRTrend { + direction: "increasing" | "decreasing" | "stable"; + magnitude: number; // 0-1, how strong the trend is + confidence: number; // 0-1, confidence in the trend + stressLevel: "low" | "moderate" | "high"; + recommendation: string; +} + +export interface GSRDataPoint { + value: number; + timestamp: number; +} + +export interface GSRConfig { + windowSize: number; // Number of recent points to analyze + trendThreshold: number; // Minimum change to consider a trend + stressThresholds: { + low: number; + moderate: number; + high: number; + }; + smoothingWindow: number; // Moving average window for noise reduction +} + +export class GSRTrendAnalyzer { + private config: GSRConfig; + private dataBuffer: GSRDataPoint[] = []; + private smoothedBuffer: number[] = []; + private lastTrend: GSRTrend | null = null; + + constructor(config: Partial = {}) { + this.config = { + windowSize: 10, // Analyze last 10 points for 10Hz GSR data (1 second) + trendThreshold: 0.03, // 3% change threshold for more sensitivity + stressThresholds: { + low: 0.3, + moderate: 0.6, + high: 0.8, + }, + smoothingWindow: 3, // 3-point moving average for more responsiveness + ...config, + }; + } + + // Add new GSR data point + public addDataPoint(value: number, timestamp: number): void { + this.dataBuffer.push({ value, timestamp }); + + // Keep only recent data + if (this.dataBuffer.length > this.config.windowSize) { + this.dataBuffer.shift(); + } + + // Update smoothed buffer + this.updateSmoothedBuffer(); + + // Analyze trend if we have enough data + if (this.dataBuffer.length >= this.config.smoothingWindow) { + this.analyzeTrend(); + } + } + + // Update smoothed buffer using moving average + private updateSmoothedBuffer(): void { + this.smoothedBuffer = []; + + for (let i = 0; i < this.dataBuffer.length; i++) { + if (i < this.config.smoothingWindow - 1) { + // For the first few points, use available data + const availableData = this.dataBuffer.slice(0, i + 1); + const sum = availableData.reduce((acc, d) => acc + d.value, 0); + this.smoothedBuffer.push(sum / availableData.length); + } else { + // Moving average + const window = this.dataBuffer.slice(i - this.config.smoothingWindow + 1, i + 1); + const sum = window.reduce((acc, d) => acc + d.value, 0); + this.smoothedBuffer.push(sum / this.config.smoothingWindow); + } + } + } + + // Analyze trend in recent GSR data + private analyzeTrend(): void { + if (this.smoothedBuffer.length < 8) return; // Need at least 8 points + + const recentValues = this.smoothedBuffer.slice(-8); // Last 8 smoothed values for more responsive detection + const currentValue = recentValues[recentValues.length - 1]; + const previousValue = recentValues[0]; + + // Calculate trend direction and magnitude + const change = currentValue - previousValue; + // Division by zero protection + const changePercent = previousValue !== 0 ? Math.abs(change) / previousValue : 0; + + let direction: "increasing" | "decreasing" | "stable"; + let magnitude: number; + let confidence: number; + + if (changePercent < this.config.trendThreshold) { + direction = "stable"; + magnitude = changePercent / this.config.trendThreshold; + confidence = 0.3; // Low confidence for stable trend + } else { + direction = change > 0 ? "increasing" : "decreasing"; + magnitude = Math.min(1.0, changePercent / this.config.trendThreshold); + confidence = Math.min(1.0, magnitude * 2); // Higher confidence for stronger trends + } + + // Determine stress level based on current value + const stressLevel = this.determineStressLevel(currentValue); + + // Generate recommendation + const recommendation = this.generateRecommendation(direction, stressLevel, magnitude); + + this.lastTrend = { + direction, + magnitude, + confidence, + stressLevel, + recommendation, + }; + } + + // Determine stress level based on GSR value + private determineStressLevel(value: number): "low" | "moderate" | "high" { + if (value <= this.config.stressThresholds.low) { + return "low"; + } else if (value <= this.config.stressThresholds.moderate) { + return "moderate"; + } else { + return "high"; + } + } + + // Generate recommendation based on trend and stress level + private generateRecommendation( + direction: "increasing" | "decreasing" | "stable", + stressLevel: "low" | "moderate" | "high", + magnitude: number + ): string { + if (direction === "decreasing") { + if (stressLevel === "high") { + return "Stress decreasing - good progress!"; + } else if (stressLevel === "moderate") { + return "Stress decreasing - continue relaxation techniques"; + } else { + return "Stress decreasing - maintaining low stress level"; + } + } else if (direction === "increasing") { + if (stressLevel === "high") { + return "Stress increasing - consider immediate intervention"; + } else if (stressLevel === "moderate") { + return "Stress increasing - try deep breathing exercises"; + } else { + return "Stress increasing - monitor closely"; + } + } else { + if (stressLevel === "high") { + return "Stress stable but high - intervention recommended"; + } else if (stressLevel === "moderate") { + return "Stress stable - continue current approach"; + } else { + return "Stress stable and low - excellent!"; + } + } + } + + // Get current trend analysis + public getTrend(): GSRTrend | null { + return this.lastTrend; + } + + // Get trend indicator for UI (green/red arrow) + public getTrendIndicator(): { + color: string; + symbol: string; + tooltip: string; + } { + if (!this.lastTrend) { + return { + color: "#666", + symbol: "โ—", + tooltip: "Insufficient data for trend analysis", + }; + } + + const { direction, magnitude, confidence, stressLevel } = this.lastTrend; + + if (direction === "decreasing") { + return { + color: "#4CAF50", // Green + symbol: "โ†“", + tooltip: `Stress decreasing (${(magnitude * 100).toFixed(0)}% confidence)`, + }; + } else if (direction === "increasing") { + return { + color: "#F44336", // Red + symbol: "โ†‘", + tooltip: `Stress increasing (${(magnitude * 100).toFixed(0)}% confidence)`, + }; + } else { + return { + color: "#FF9800", // Orange + symbol: "โ†’", + tooltip: `Stress stable (${(magnitude * 100).toFixed(0)}% confidence)`, + }; + } + } + + // Get stress level indicator + public getStressIndicator(): { + color: string; + level: string; + description: string; + } { + if (!this.lastTrend) { + return { + color: "#666", + level: "Unknown", + description: "Insufficient data", + }; + } + + const { stressLevel } = this.lastTrend; + + switch (stressLevel) { + case "low": + return { + color: "#4CAF50", + level: "Low", + description: "Normal stress level", + }; + case "moderate": + return { + color: "#FF9800", + level: "Moderate", + description: "Elevated stress level", + }; + case "high": + return { + color: "#F44336", + level: "High", + description: "High stress level - intervention recommended", + }; + default: + return { + color: "#666", + level: "Unknown", + description: "Unable to determine", + }; + } + } + + // Get recent GSR statistics + public getStatistics(): { + currentValue: number; + averageValue: number; + minValue: number; + maxValue: number; + variability: number; + } { + if (this.dataBuffer.length === 0) { + return { + currentValue: 0, + averageValue: 0, + minValue: 0, + maxValue: 0, + variability: 0, + }; + } + + const values = this.dataBuffer.map((d) => d.value); + if (values.length === 0) { + return { + currentValue: 0, + averageValue: 0, + minValue: 0, + maxValue: 0, + variability: 0, + }; + } + + const currentValue = values[values.length - 1]; + const averageValue = values.reduce((sum, val) => sum + val, 0) / values.length; + const minValue = Math.min(...values); + const maxValue = Math.max(...values); + const variability = maxValue - minValue; + + return { + currentValue, + averageValue, + minValue, + maxValue, + variability, + }; + } + + // Reset analyzer + public reset(): void { + this.dataBuffer = []; + this.smoothedBuffer = []; + this.lastTrend = null; + } + + // Update configuration + public updateConfig(newConfig: Partial): void { + this.config = { ...this.config, ...newConfig }; + } +} diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/index.tsx b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/index.tsx index 82d0a8465..6b0b8a70b 100644 --- a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/index.tsx +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/index.tsx @@ -1,122 +1,2374 @@ -import * as React from "react"; -import commonClasses from "../../../styles/Examples.module.scss"; -import { appTheme } from "../../../theme"; +import React, { useRef, useState, useEffect } from "react"; import { SciChartReact, TResolvedReturnType } from "scichart-react"; import { drawExample } from "./drawExample"; +import { connectionStatusEventHandler } from "./drawExample"; +import { RespirationMetrics } from "./signalProcessor"; +import { ECGMetrics } from "./ecgProcessor"; +import { GSRTrend, GSRTrendAnalyzer } from "./gsrTrendAnalyzer"; +import { DebugLogger, info } from "./debugLogger"; +import { firebaseLogger, ProcessedSensorData } from "./firebaseLogger"; +import { SessionRecorder, VitalSignsData, SessionReport } from "./sessionRecorder"; -// REACT COMPONENT -export default function VitalSignsMonitorDemo() { - const controlsRef = React.useRef["controls"]>(undefined); +// Data point interface for rolling window calculations +interface DataPoint { + value: number; + timestamp: number; +} + +interface EventPoint { + timestamp: number; + type: "heartbeat" | "breath"; +} + +// Rolling window calculator for rate-based metrics +class RollingWindowCalculator { + private dataPoints: DataPoint[] = []; + private eventPoints: EventPoint[] = []; // Track actual events + private windowSize: number; // in milliseconds + + constructor(windowSizeMs: number = 60000) { + // Default 60 seconds + this.windowSize = windowSizeMs; + } + + addDataPoint(value: number, timestamp: number): void { + this.dataPoints.push({ value, timestamp }); + this.cleanOldData(); + } + + // Add event tracking for heartbeats and breaths + addEvent(type: "heartbeat" | "breath", timestamp: number): void { + this.eventPoints.push({ type, timestamp }); + this.cleanOldEvents(); + } + + private cleanOldData(): void { + const cutoffTime = Date.now() - this.windowSize; + this.dataPoints = this.dataPoints.filter((dp) => dp.timestamp >= cutoffTime); + } + + private cleanOldEvents(): void { + const cutoffTime = Date.now() - this.windowSize; + this.eventPoints = this.eventPoints.filter((ep) => ep.timestamp >= cutoffTime); + } + + calculateRate(): number { + const timeSpanMinutes = this.windowSize / 60000; // Convert to minutes + if (timeSpanMinutes <= 0) return 0; // Division by zero protection + + // Count actual events (heartbeats or breaths) instead of data points + const eventCount = this.eventPoints.length; + + return eventCount / timeSpanMinutes; + } + + // Calculate rate for specific event type + calculateEventRate(eventType: "heartbeat" | "breath"): number { + const timeSpanMinutes = this.windowSize / 60000; + if (timeSpanMinutes <= 0) return 0; + + const eventCount = this.eventPoints.filter((ep) => ep.type === eventType).length; + return eventCount / timeSpanMinutes; + } + + getAverageValue(): number { + if (this.dataPoints.length === 0) return 0; + const sum = this.dataPoints.reduce((acc, dp) => acc + dp.value, 0); + return sum / this.dataPoints.length; + } + + getLatestValue(): number { + return this.dataPoints.length > 0 ? this.dataPoints[this.dataPoints.length - 1].value : 0; + } + + reset(): void { + this.dataPoints = []; + this.eventPoints = []; + } +} + +const VitalSignsMonitorDemo: React.FC = () => { + const [infoEcg, setInfoEcg] = useState(0); + const [infoHrv, setInfoHrv] = useState(0); + const [infoGsr, setInfoGsr] = useState(0); + const [infoResp, setInfoResp] = useState(0); + const [infoBpm, setInfoBpm] = useState(0); + const [coherence, setCoherence] = useState(0); + const [wsConnected, setWsConnected] = useState(false); + const [showAnalysis, setShowAnalysis] = useState(false); + const [respirationMetrics, setRespirationMetrics] = useState(null); + const [inhalePercent, setInhalePercent] = useState(40); + const [breathingState, setBreathingState] = useState("idle"); + const [ecgMetrics, setEcgMetrics] = useState(null); + const [gsrTrend, setGsrTrend] = useState(null); + const [isRecording, setIsRecording] = useState(false); + const [sessionRecorder] = useState(() => SessionRecorder.getInstance()); + const [sessionStatus, setSessionStatus] = useState>({ + isRecording: false, + sessionId: "", + elapsedTime: 0, + remainingTime: 0, + dataPoints: 0, + currentPhase: "initial", + phaseProgress: 0, + }); + const [sessionReport, setSessionReport] = useState(null); + const debugLogger = DebugLogger.getInstance(); + const controlsRef = useRef(null); + const gsrAnalyzerRef = useRef(new GSRTrendAnalyzer()); + + // Rolling window calculators for rate-based metrics + const bpmCalculator = useRef(new RollingWindowCalculator(60000)); // 60 seconds for BPM + const respCalculator = useRef(new RollingWindowCalculator(60000)); // 60 seconds for respiratory rate + const gsrCalculator = useRef(new RollingWindowCalculator(60000)); // 60 seconds for GSR trends + + // Realistic medical value ranges based on actual patient data + const realisticValues = { + ecg: { min: -2.0, max: 3.0, unit: "mV" }, // Medical ECG amplitude range + bpm: { min: 60, max: 100, unit: "BPM" }, // Normal resting heart rate + hrv: { min: 20, max: 100, unit: "ms" }, // Normal HRV range + gsr: { min: 1, max: 20, unit: "ฮผS" }, // Galvanic skin response + respiratory: { min: 12, max: 20, unit: "breaths/min" }, // Normal respiratory rate + coherence: { min: 0, max: 100, unit: "%" }, // Heart rate coherence + inhalePercent: { min: 35, max: 45, unit: "%" }, // Normal inhale percentage + }; + + // Calculate coherence based on HRV - higher HRV typically indicates better coherence + const calculateCoherence = (hrv: number, bpm: number): number => { + // Coherence is a measure of heart rate variability pattern + // Higher HRV with regular patterns indicates better coherence + const hrvScore = Math.min(100, (hrv / 100) * 100); + const bpmStability = Math.max(0, 100 - Math.abs(bpm - 80) * 2); // Optimal around 80 BPM + return Math.round((hrvScore + bpmStability) / 2); + }; + + // Generate realistic medical values + // Fallback value generator for when ESP32 is disconnected + const generateFallbackValue = (type: keyof typeof realisticValues): number => { + const range = realisticValues[type]; + const baseValue = range.min + Math.random() * (range.max - range.min); + + // Generate simple fallback values when ESP32 is not connected + switch (type) { + case "ecg": + return Math.round(baseValue * 10) / 10; // 1 decimal place for mV + case "bpm": + return Math.round(baseValue); // Whole numbers + case "hrv": + return Math.round(baseValue); // Whole numbers + case "gsr": + return Math.round(baseValue * 10) / 10; // 1 decimal place + case "respiratory": + return Math.round(baseValue); // Whole numbers + case "inhalePercent": + return Math.round(baseValue); // Whole numbers + case "coherence": + return Math.round(baseValue); // Whole numbers for coherence percentage + default: + return Math.round(baseValue); + } + }; + + // Update values periodically to simulate real-time monitoring (only when not connected) + useEffect(() => { + const interval = setInterval(() => { + if (!wsConnected) { + // Generate fallback values when ESP32 is disconnected + const newEcg = generateFallbackValue("ecg"); + const newBpm = generateFallbackValue("bpm"); + const newHrv = generateFallbackValue("hrv"); + const newGsr = generateFallbackValue("gsr"); + const newResp = generateFallbackValue("respiratory"); + const newInhalePercent = generateFallbackValue("inhalePercent"); + const newCoherence = calculateCoherence(newHrv, newBpm); + + // Add data points to rolling window calculators + const timestamp = Date.now(); + bpmCalculator.current.addDataPoint(newBpm, timestamp); + respCalculator.current.addDataPoint(newResp, timestamp); + gsrCalculator.current.addDataPoint(newGsr, timestamp); + + // Add data to session recorder if active + if (isRecording && sessionRecorder.isSessionActive()) { + const vitalSignsData: VitalSignsData = { + timestamp, + heartRate: newBpm, + respiratoryRate: newResp, + gsrValue: newGsr, + ecgQuality: 0.8, // Fallback quality + hrvMetrics: { + sdnn: newHrv, + rmssd: newHrv * 0.8, + pnn50: newHrv * 0.6, + lfPower: newHrv * 0.5, + hfPower: newHrv * 0.3, + lfHfRatio: 1.67, + // Additional HRV metrics for medical analysis + nn50: Math.round(newHrv * 0.4), + triangularIndex: Math.round(newHrv * 0.3), + stressIndex: Math.round(newHrv * 0.7), + vagalTone: Math.round(newHrv * 0.6), + }, + respiratoryMetrics: { + breathCount: Math.floor(newResp / 60), // Approximate breath count + inhalePercent: newInhalePercent, + exhalePercent: 100 - newInhalePercent, + breathingState: "idle", + averageCycleDuration: 5000, // 5 seconds default + + // Enhanced HW484 respiration sensor metrics + tidalVolume: Math.round(newResp * 30), // Estimate based on respiratory rate + minuteVolume: Math.round(newResp * 30) / 1000, // Convert to L/min + inspiratoryTime: 1.2, + expiratoryTime: 2.8, + totalBreathTime: 4.0, + inspiratoryExpiratoryRatio: 0.43, + peakInspiratoryFlow: Math.round(newResp * 2), + peakExpiratoryFlow: Math.round(newResp * 1.5), + respiratoryEffort: 35, + breathingRegularity: 12, + apneaHypopneaIndex: 2, + respiratorySinusArrhythmia: Math.round(newHrv * 0.2), + + // Advanced respiratory analysis + respiratoryPhaseCoherence: 88, + respiratoryRateVariability: 12, + breathDepthConsistency: 88, + respiratoryEfficiency: 77, + + // Medical assessment scores + respiratoryDistressScore: 8, + breathingPatternQuality: 92, + respiratoryFatigueIndex: 15, + }, + connectionStatus: { + esp32Connected: false, + sensorsConnected: { ecg: false, gsr: false, respiratory: false }, + }, + }; + sessionRecorder.addDataPoint(vitalSignsData); + } + + // Log fallback data for recording (reduced frequency) + if (isRecording && Math.random() < 0.1) { + info("VITAL_SIGNS", "Fallback Data Generated", { + timestamp, + ecg: newEcg, + bpm: newBpm, + hrv: newHrv, + gsr: newGsr, + respiratory: newResp, + coherence: newCoherence, + inhalePercent: newInhalePercent, + }); + } + + // Use calculated rates from rolling windows + // Generate medical-grade ECG values directly in millivolts + setInfoEcg(newEcg); + setInfoBpm(Math.round(bpmCalculator.current.calculateRate())); + setInfoHrv(newHrv); + setInfoGsr(gsrCalculator.current.getAverageValue()); + setInfoResp(Math.round(respCalculator.current.calculateRate())); + // Update breathing pattern animation + const animatedInhalePercent = 35 + Math.sin(Date.now() * 0.001) * 10; + setInhalePercent(animatedInhalePercent); + setCoherence(newCoherence); + + // Generate GSR trend data for fallback + gsrAnalyzerRef.current.addDataPoint(newGsr, timestamp); + const fallbackGsrTrend = gsrAnalyzerRef.current.getTrend(); + setGsrTrend(fallbackGsrTrend); + + // Set fallback respiration metrics + setRespirationMetrics({ + rate: Math.round(respCalculator.current.calculateRate()), + inhalePercent: animatedInhalePercent, + exhalePercent: 100 - animatedInhalePercent, + lastBreathTime: timestamp, + breathCount: 0, + averageCycleDuration: 60000 / Math.round(respCalculator.current.calculateRate()), + + // Enhanced HW484 respiration sensor metrics + tidalVolume: 0, + minuteVolume: 0, + inspiratoryTime: 0, + expiratoryTime: 0, + totalBreathTime: 0, + inspiratoryExpiratoryRatio: 0, + peakInspiratoryFlow: 0, + peakExpiratoryFlow: 0, + respiratoryEffort: 0, + breathingRegularity: 0, + apneaHypopneaIndex: 0, + respiratorySinusArrhythmia: 0, + + // Advanced respiratory analysis + respiratoryPhaseCoherence: 0, + respiratoryRateVariability: 0, + breathDepthConsistency: 0, + respiratoryEfficiency: 0, + + // Medical assessment scores + respiratoryDistressScore: 0, + breathingPatternQuality: 0, + respiratoryFatigueIndex: 0, + }); + } + }, 1000); + + return () => clearInterval(interval); + }, [wsConnected]); + + // Firebase logging effect + useEffect(() => { + // Only log to Firebase when ESP32 is connected (real sensor data) + // Don't waste Firebase storage on fallback/demo data + if (!wsConnected) { + console.log("๐Ÿ“Š Firebase Logging: DISABLED - ESP32 not connected (fallback data only)"); + return undefined; + } + + console.log("๐Ÿ“Š Firebase Logging: ENABLED - ESP32 connected, logging real sensor data every 30s"); + + const firebaseLogInterval = setInterval(() => { + // Only log when ESP32 is connected and it's time to log + if (wsConnected && firebaseLogger.shouldLog()) { + const processedData: ProcessedSensorData = { + timestamp: Date.now(), + heartRate: infoBpm, + respiratoryRate: infoResp, + gsrValue: infoGsr, + gsrTrend: gsrTrend?.direction || "stable", + ecgQuality: ecgMetrics?.signalQuality + ? ecgMetrics.signalQuality > 70 + ? "good" + : ecgMetrics.signalQuality > 40 + ? "fair" + : "poor" + : "fair", + hrvMetrics: { + sdnn: ecgMetrics?.sdnn || 0, + rmssd: ecgMetrics?.rmssd || 0, + pnn50: ecgMetrics?.pnn50 || 0, + lfPower: ecgMetrics?.lfPower || 0, + hfPower: ecgMetrics?.hfPower || 0, + lfHfRatio: ecgMetrics?.lfHfRatio || 0, + // Additional HRV metrics for medical analysis + nn50: ecgMetrics?.nn50 || 0, + triangularIndex: ecgMetrics?.triangularIndex || 0, + stressIndex: ecgMetrics?.stressIndex || 0, + vagalTone: ecgMetrics?.vagalTone || 0, + }, + respiratoryMetrics: { + breathCount: respirationMetrics?.breathCount || 0, + inhalePercent: respirationMetrics?.inhalePercent || 0, + exhalePercent: respirationMetrics?.exhalePercent || 0, + breathingState: "idle" as "inhale" | "exhale" | "transition", + + // Enhanced HW484 respiration sensor metrics + tidalVolume: respirationMetrics?.tidalVolume || 0, + minuteVolume: respirationMetrics?.minuteVolume || 0, + inspiratoryTime: respirationMetrics?.inspiratoryTime || 0, + expiratoryTime: respirationMetrics?.expiratoryTime || 0, + totalBreathTime: respirationMetrics?.totalBreathTime || 0, + inspiratoryExpiratoryRatio: respirationMetrics?.inspiratoryExpiratoryRatio || 0, + peakInspiratoryFlow: respirationMetrics?.peakInspiratoryFlow || 0, + peakExpiratoryFlow: respirationMetrics?.peakExpiratoryFlow || 0, + respiratoryEffort: respirationMetrics?.respiratoryEffort || 0, + breathingRegularity: respirationMetrics?.breathingRegularity || 0, + apneaHypopneaIndex: respirationMetrics?.apneaHypopneaIndex || 0, + respiratorySinusArrhythmia: respirationMetrics?.respiratorySinusArrhythmia || 0, + + // Advanced respiratory analysis + respiratoryPhaseCoherence: respirationMetrics?.respiratoryPhaseCoherence || 0, + respiratoryRateVariability: respirationMetrics?.respiratoryRateVariability || 0, + breathDepthConsistency: respirationMetrics?.breathDepthConsistency || 0, + respiratoryEfficiency: respirationMetrics?.respiratoryEfficiency || 0, + + // Medical assessment scores + respiratoryDistressScore: respirationMetrics?.respiratoryDistressScore || 0, + breathingPatternQuality: respirationMetrics?.breathingPatternQuality || 0, + respiratoryFatigueIndex: respirationMetrics?.respiratoryFatigueIndex || 0, + }, + connectionStatus: { + esp32Connected: wsConnected, + sensorsConnected: { + ecg: wsConnected, + gsr: wsConnected, + respiratory: wsConnected, + }, + }, + }; + + // Log to Firebase only when ESP32 is connected (real sensor data) + console.log("๐Ÿ“Š Firebase Logging: Sending REAL sensor data to Firebase", { + timestamp: new Date().toISOString(), + esp32Connected: wsConnected, + dataSource: "Real Sensors", + heartRate: infoBpm, + respiratoryRate: infoResp, + gsrValue: infoGsr, + }); + firebaseLogger.logProcessedData(processedData); + } + }, 30000); // Check every 30 seconds + + return () => { + clearInterval(firebaseLogInterval); + }; + }, [wsConnected, infoBpm, infoResp, infoGsr, gsrTrend, ecgMetrics, respirationMetrics]); + + // Update session status periodically + useEffect(() => { + const interval = setInterval(() => { + if (isRecording && sessionRecorder.isSessionActive()) { + setSessionStatus(sessionRecorder.getSessionStatus()); + } + }, 1000); // Update every second - const [infoEcg, setInfoEcg] = React.useState(0); - const [infoBloodPressure1, setInfoBloodPressure1] = React.useState(0); - const [infoBloodPressure2, setInfoBloodPressure2] = React.useState(0); - const [infoBloodVolume, setInfoBloodVolume] = React.useState(0); - const [infoBloodOxygenation, setInfoBloodOxygenation] = React.useState(0); + return () => clearInterval(interval); + }, [isRecording, sessionRecorder]); + + // Periodic comprehensive logging every 30 seconds + useEffect(() => { + const debugLogger = DebugLogger.getInstance(); + const statusInterval = setInterval(() => { + // Update debug logger with current system status + debugLogger.updateStatus("WebSocket", { connected: wsConnected, timestamp: Date.now() }); + debugLogger.updateStatus("Sensors", { + ecg: infoEcg, + gsr: infoGsr, + respiratory: infoResp, + heartRate: infoBpm, + }); + debugLogger.updateStatus("Firebase", { + lastLogTime: firebaseLogger.getLastLogTime(), + logCount: firebaseLogger.getLogCount(), + connected: firebaseLogger.getConnectionStatus(), + }); + debugLogger.updateStatus("Session", { + recording: isRecording, + dataPoints: sessionRecorder.getSessionStatus().dataPoints, + }); + + // Log comprehensive status + debugLogger.logPeriodicStatus(); + }, 30000); // Every 30 seconds + + return () => clearInterval(statusInterval); + }, [wsConnected, infoEcg, infoGsr, infoResp, infoBpm, isRecording, firebaseLogger]); + + // Cleanup on unmount to prevent memory leaks + useEffect(() => { + return () => { + if (controlsRef.current) { + controlsRef.current.stopUpdate(); + } + // Clear all calculators to prevent memory leaks + bpmCalculator.current.reset(); + respCalculator.current.reset(); + gsrCalculator.current.reset(); + gsrAnalyzerRef.current.reset(); + }; + }, []); + + const containerStyle = { + width: "100%", + height: "100vh", + display: "flex", + flexDirection: "column" as const, + backgroundColor: "#1e1e1e", + color: "#ffffff", + fontFamily: "Arial, sans-serif", + overflow: "hidden", + }; + + const headerStyle = { + padding: "15px 20px", + backgroundColor: "#2d2d2d", + borderBottom: "2px solid #444", + display: "flex", + justifyContent: "space-between", + alignItems: "center", + minHeight: "60px", + }; + + const titleStyle = { + fontSize: "24px", + fontWeight: "bold", + color: "#ffffff", + margin: 0, + }; + + const buttonStyle = { + padding: "12px 20px", + backgroundColor: "#2E7D32", // Medical green + color: "white", + border: "none", + borderRadius: "6px", + cursor: "pointer", + fontSize: "14px", + fontWeight: "600", + marginLeft: "10px", + display: "flex", + alignItems: "center", + gap: "8px", + transition: "all 0.2s ease", + boxShadow: "0 2px 4px rgba(0,0,0,0.15)", + fontFamily: "system-ui, -apple-system, sans-serif", + }; + + const analysisButtonStyle = { + ...buttonStyle, + backgroundColor: "#1976D2", // Medical blue + border: "1px solid #1565C0", + }; + + const recordingButtonStyle = { + ...buttonStyle, + backgroundColor: isRecording ? "#D32F2F" : "#388E3C", // Medical red/green + border: `1px solid ${isRecording ? "#C62828" : "#2E7D32"}`, + }; + + const mainContentStyle = { + display: "flex", + flex: 1, + overflow: "hidden", + minHeight: "calc(100vh - 90px)", // Account for header + }; + + const chartContainerStyle = { + flex: 1, + minHeight: "600px", + height: "calc(100vh - 120px)", // Account for header and margins + border: "2px solid #333", // Medical-grade border + borderRadius: "8px", + margin: "15px", + backgroundColor: "#0A0A0A", // Medical-grade dark background + overflow: "hidden", // Prevent overflow + position: "relative" as const, + boxShadow: "inset 0 0 20px rgba(0,255,0,0.1)", // Subtle medical green glow + }; + + const sidebarStyle = { + width: "280px", + backgroundColor: "#2d2d2d", + borderLeft: "2px solid #444", + padding: "12px", + overflowY: "auto" as const, + }; + + const statusPanelStyle = { + padding: "15px", + backgroundColor: "#3d3d3d", + borderRadius: "8px", + marginBottom: "20px", + border: "2px solid #555", + }; + + const statusTitleStyle = { + fontSize: "16px", + fontWeight: "bold", + marginBottom: "10px", + color: "#ffffff", + }; + + const statusIndicatorStyle = { + padding: "8px 12px", + borderRadius: "5px", + fontSize: "14px", + fontWeight: "bold", + textAlign: "center" as const, + backgroundColor: wsConnected ? "#4caf50" : "#f44336", + color: "#ffffff", + marginBottom: "10px", + }; + + const sensorStatusStyle = { + display: "flex", + justifyContent: "space-between", + alignItems: "center", + marginBottom: "5px", + fontSize: "11px", + }; + + const sensorIndicatorStyle = { + padding: "2px 6px", + borderRadius: "3px", + fontSize: "10px", + fontWeight: "bold", + color: "#ffffff", + }; + + const parametersGridStyle = { + display: "grid", + gridTemplateColumns: "repeat(2, 1fr)", + gap: "12px", + marginBottom: "20px", + }; + + const parameterCardStyle = { + padding: "15px", + backgroundColor: "#3d3d3d", + borderRadius: "8px", + border: "2px solid #555", + textAlign: "center" as const, + }; + + const parameterLabelStyle = { + fontSize: "12px", + color: "#aaa", + marginBottom: "8px", + fontWeight: "bold", + textTransform: "uppercase" as const, + }; + + const parameterValueStyle = { + fontSize: "24px", + fontWeight: "bold", + color: "#ffffff", + marginBottom: "5px", + }; + + const parameterUnitStyle = { + fontSize: "10px", + color: "#888", + textTransform: "uppercase" as const, + }; + + const coherenceStyle = { + ...parameterValueStyle, + color: coherence > 70 ? "#4caf50" : coherence > 40 ? "#ff9800" : "#f44336", + }; + + // Breathing pattern display styles + const breathingCardStyle = { + ...parameterCardStyle, + padding: "12px", + }; + + const breathingBarContainerStyle = { + width: "100%", + height: "12px", + backgroundColor: "#555", + borderRadius: "6px", + margin: "6px 0", + overflow: "hidden", + position: "relative" as const, + }; + + const inhaleBarStyle = { + width: `${wsConnected && respirationMetrics ? respirationMetrics.inhalePercent : inhalePercent}%`, + height: "100%", + backgroundColor: "#4CAF50", + transition: "width 0.5s ease-in-out", + borderRadius: "10px 0 0 10px", + }; + + const exhaleBarStyle = { + width: `${wsConnected && respirationMetrics ? respirationMetrics.exhalePercent : 100 - inhalePercent}%`, + height: "100%", + backgroundColor: "#2196F3", + transition: "width 0.5s ease-in-out", + borderRadius: "0 10px 10px 0", + position: "absolute" as const, + right: 0, + top: 0, + }; + + const breathingLabelStyle = { + fontSize: "10px", + color: "#aaa", + marginTop: "5px", + }; + + const breathingStateStyle = { + fontSize: "10px", + color: breathingState === "inhaling" ? "#4CAF50" : breathingState === "exhaling" ? "#2196F3" : "#888", + marginTop: "3px", + fontWeight: "bold", + }; + + const analysisPanelStyle = { + padding: "15px", + backgroundColor: "#3d3d3d", + borderRadius: "8px", + border: "2px solid #555", + display: showAnalysis ? "block" : "none", + }; + + const analysisTitleStyle = { + fontSize: "16px", + fontWeight: "bold", + marginBottom: "15px", + color: "#ffffff", + textAlign: "center" as const, + }; + + const analysisGridStyle = { + display: "grid", + gridTemplateColumns: "repeat(2, 1fr)", + gap: "10px", + }; + + const analysisItemStyle = { + padding: "8px", + backgroundColor: "#4d4d4d", + borderRadius: "5px", + fontSize: "12px", + }; + + const analysisLabelStyle = { + color: "#aaa", + marginBottom: "3px", + }; + + const analysisValueStyle = { + color: "#ffffff", + fontWeight: "bold", + }; + + const infoTextStyle = { + fontSize: "11px", + color: "#888", + fontStyle: "italic", + marginTop: "10px", + lineHeight: "1.4", + }; return ( -
-
- ) => { - initResult.subscribeToDataUpdates((info) => { - setInfoEcg(info.ecg); - setInfoBloodPressure1(info.bloodPressure1); - setInfoBloodPressure2(info.bloodPressure2); - setInfoBloodVolume(info.bloodVolume); - setInfoBloodOxygenation(info.bloodOxygenation); - }); - - controlsRef.current = initResult.controls; - initResult.controls.startUpdate(); - - return () => { - initResult.controls.stopUpdate(); - }; - }} - /> -
-
+
+

Vital Signs Monitor

+
+ + + + +
+
+ +
+
+ ) => { + const unsub = initResult.subscribeToDataUpdates((info: any) => { + if (!info) return undefined; + + // Handle ESP32 data when connected + if (wsConnected) { + const timestamp = Date.now(); + + // Add data to session recorder if active + if (isRecording && sessionRecorder.isSessionActive()) { + const vitalSignsData: VitalSignsData = { + timestamp, + heartRate: info.bpm || 0, + respiratoryRate: info.respiratory || 0, + gsrValue: info.gsr || 0, + ecgQuality: info.ecg ? 0.9 : 0.5, // High quality for real data + hrvMetrics: { + sdnn: info.hrv || 0, + rmssd: (info.hrv || 0) * 0.8, + pnn50: (info.hrv || 0) * 0.6, + lfPower: (info.hrv || 0) * 0.5, + hfPower: (info.hrv || 0) * 0.3, + lfHfRatio: 1.67, + // Additional HRV metrics for medical analysis + nn50: Math.round((info.hrv || 0) * 0.4), + triangularIndex: Math.round((info.hrv || 0) * 0.3), + stressIndex: Math.round((info.hrv || 0) * 0.7), + vagalTone: Math.round((info.hrv || 0) * 0.6), + }, + respiratoryMetrics: { + breathCount: respirationMetrics?.breathCount || 0, + inhalePercent: respirationMetrics?.inhalePercent || 40, + exhalePercent: respirationMetrics?.exhalePercent || 60, + breathingState: breathingState || "idle", + averageCycleDuration: respirationMetrics?.averageCycleDuration || 5000, + + // Enhanced HW484 respiration sensor metrics + tidalVolume: respirationMetrics?.tidalVolume || 0, + minuteVolume: respirationMetrics?.minuteVolume || 0, + inspiratoryTime: respirationMetrics?.inspiratoryTime || 0, + expiratoryTime: respirationMetrics?.expiratoryTime || 0, + totalBreathTime: respirationMetrics?.totalBreathTime || 0, + inspiratoryExpiratoryRatio: + respirationMetrics?.inspiratoryExpiratoryRatio || 0, + peakInspiratoryFlow: respirationMetrics?.peakInspiratoryFlow || 0, + peakExpiratoryFlow: respirationMetrics?.peakExpiratoryFlow || 0, + respiratoryEffort: respirationMetrics?.respiratoryEffort || 0, + breathingRegularity: respirationMetrics?.breathingRegularity || 0, + apneaHypopneaIndex: respirationMetrics?.apneaHypopneaIndex || 0, + respiratorySinusArrhythmia: + respirationMetrics?.respiratorySinusArrhythmia || 0, + + // Advanced respiratory analysis + respiratoryPhaseCoherence: + respirationMetrics?.respiratoryPhaseCoherence || 0, + respiratoryRateVariability: + respirationMetrics?.respiratoryRateVariability || 0, + breathDepthConsistency: respirationMetrics?.breathDepthConsistency || 0, + respiratoryEfficiency: respirationMetrics?.respiratoryEfficiency || 0, + + // Medical assessment scores + respiratoryDistressScore: + respirationMetrics?.respiratoryDistressScore || 0, + breathingPatternQuality: + respirationMetrics?.breathingPatternQuality || 0, + respiratoryFatigueIndex: + respirationMetrics?.respiratoryFatigueIndex || 0, + }, + connectionStatus: { + esp32Connected: wsConnected, + sensorsConnected: { + ecg: wsConnected && info.ecg !== undefined, + gsr: wsConnected && info.gsr !== undefined, + respiratory: wsConnected && info.respiratory !== undefined, + }, + }, + }; + sessionRecorder.addDataPoint(vitalSignsData); + } + + // Log vital signs data for recording + if (isRecording) { + info("VITAL_SIGNS", "ESP32 Data Received", { + timestamp, + ecg: info.ecg, + hrv: info.hrv, + gsr: info.gsr, + respiratory: info.respiratory, + bpm: info.bpm, + sensorConnected: info.sensorConnected, + }); + } + + if (typeof info.ecg === "number") { + // ECG is already in millivolts from signalProcessor + setInfoEcg(info.ecg); + } + if (typeof info.hrv === "number") setInfoHrv(info.hrv); + + // Use rolling window calculations for rate-based metrics + if (typeof info.gsr === "number") { + gsrCalculator.current.addDataPoint(info.gsr, timestamp); + setInfoGsr(gsrCalculator.current.getAverageValue()); + } + if (typeof info.respiratory === "number") { + respCalculator.current.addDataPoint(info.respiratory, timestamp); + setInfoResp(Math.round(respCalculator.current.calculateRate())); + } + if (typeof info.bpm === "number") { + bpmCalculator.current.addDataPoint(info.bpm, timestamp); + setInfoBpm(Math.round(info.bpm)); // Use direct BPM value + } + + // Track actual events for accurate rate calculations + if (info.type === "ibi" && info.value) { + // IBI data indicates a heartbeat was detected + bpmCalculator.current.addEvent("heartbeat", timestamp); + // Use IBI to calculate BPM: 60000ms / IBI = BPM + const calculatedBpm = info.value > 0 ? Math.round(60000 / info.value) : 0; + setInfoBpm(calculatedBpm); + } + + // Track breath events from respiration processor + if (info.respirationMetrics && info.respirationMetrics.breathCount > 0) { + // Add breath event when a new breath cycle is detected + respCalculator.current.addEvent("breath", timestamp); + setInfoResp(Math.round(respCalculator.current.calculateEventRate("breath"))); + } + + // Handle respiration metrics from signal processor + if (info.respirationMetrics) { + setRespirationMetrics(info.respirationMetrics); + // Use event-based rate calculation if available + const eventRate = respCalculator.current.calculateEventRate("breath"); + setInfoResp( + eventRate > 0 ? Math.round(eventRate) : info.respirationMetrics.rate + ); + } else if (typeof info.respiratory === "number") { + // Update respiration metrics from rolling window + const currentRate = Math.round( + respCalculator.current.calculateEventRate("breath") + ); + setRespirationMetrics({ + rate: currentRate, + inhalePercent: 40, // Default fallback + exhalePercent: 60, + lastBreathTime: timestamp, + breathCount: 0, + averageCycleDuration: currentRate > 0 ? 60000 / currentRate : 5000, + + // Enhanced HW484 respiration sensor metrics + tidalVolume: 0, + minuteVolume: 0, + inspiratoryTime: 0, + expiratoryTime: 0, + totalBreathTime: 0, + inspiratoryExpiratoryRatio: 0, + peakInspiratoryFlow: 0, + peakExpiratoryFlow: 0, + respiratoryEffort: 0, + breathingRegularity: 0, + apneaHypopneaIndex: 0, + respiratorySinusArrhythmia: 0, + + // Advanced respiratory analysis + respiratoryPhaseCoherence: 0, + respiratoryRateVariability: 0, + breathDepthConsistency: 0, + respiratoryEfficiency: 0, + + // Medical assessment scores + respiratoryDistressScore: 0, + breathingPatternQuality: 0, + respiratoryFatigueIndex: 0, + }); + } + + // Handle breathing state + if (info.breathingState) { + setBreathingState(info.breathingState.state); + } + + // Handle ECG metrics and signal quality + if (info.ecgMetrics) { + setEcgMetrics(info.ecgMetrics); + } + + // Handle GSR trend analysis + if (info.gsrTrend) { + setGsrTrend(info.gsrTrend); + } else if (typeof info.gsr === "number") { + // Generate GSR trend from rolling window data + gsrAnalyzerRef.current.addDataPoint(info.gsr, timestamp); + const espGsrTrend = gsrAnalyzerRef.current.getTrend(); + setGsrTrend(espGsrTrend); + } + + // Calculate coherence when we have both HRV and BPM + if (typeof info.hrv === "number" && typeof info.bpm === "number") { + const newCoherence = calculateCoherence(info.hrv, info.bpm); + setCoherence(newCoherence); + } + } + + return undefined; + }); + controlsRef.current = initResult.controls; + initResult.controls.startUpdate(); + + // Subscribe to connection status + const maybeUnsub = connectionStatusEventHandler.subscribe((status: any) => { + const connected = status === "connected"; + setWsConnected(connected); + // Note: Firebase connection status tracks ESP32 connection + // Firebase logging is only enabled when ESP32 is connected + firebaseLogger.setConnectionStatus(connected); + }); + const unsubStatus = typeof maybeUnsub === "function" ? maybeUnsub : (): void => {}; + + // Cleanup + return () => { + unsub(); + unsubStatus(); + }; + }} + /> +
+ +
+
+
System Status
+
+ {wsConnected ? "ESP32 Connected - Real Sensors" : "ESP32 Disconnected - Fallback Data"}
-
-
-
- V1 - 1.4MM -
- ST | +0.6 || +0.9 -
-
+ {/* Firebase Logging Status */} +
+ ๐Ÿ“Š Firebase Logging: {wsConnected ? "ACTIVE (Real Data)" : "DISABLED (Fallback Data)"}
+ {isRecording && sessionStatus.isRecording && ( +
+ ๐Ÿ”ด Session Active: {sessionStatus.sessionId} +
+ )} + {isRecording && sessionStatus.isRecording && ( +
+ Phase: {sessionStatus.currentPhase.toUpperCase()} ( + {Math.round(sessionStatus.phaseProgress * 100)}%) +
+ )} + {isRecording && sessionStatus.isRecording && ( +
+ Progress: {Math.round(sessionStatus.elapsedTime / 1000 / 60)}m / 20m | Data:{" "} + {sessionStatus.dataPoints} points +
+ )} + {isRecording && sessionStatus.isRecording && ( +
+
+
+ )} + {isRecording && sessionStatus.isRecording && ( +
+ Remaining: {Math.round(sessionStatus.remainingTime / 1000 / 60)}m{" "} + {Math.round((sessionStatus.remainingTime % 60000) / 1000)}s +
+ )}
-
-
-
NIBP
-
- AUTO -
- 145/95 + +
+
+
ECG Amplitude
+
+ + {wsConnected ? "REAL" : "SIM"} + + + {wsConnected ? "ESP32" : "Demo"} +
+
{Math.abs(infoEcg).toFixed(1)}
+
mV
-
-
-
- {infoBloodPressure1}/{infoBloodPressure2} -
+ +
+
Heart Rate
+
{infoBpm.toFixed(0)}
+
BPM
+
+ +
+
Breathing Pattern
+
+
+
+
+
+ Inhale:{" "} + {wsConnected && respirationMetrics + ? respirationMetrics.inhalePercent.toFixed(2) + : inhalePercent.toFixed(2)} + % | Exhale:{" "} + {wsConnected && respirationMetrics + ? respirationMetrics.exhalePercent.toFixed(2) + : (100 - inhalePercent).toFixed(2)} + %
+
{breathingState.toUpperCase()}
-
-
-
-
SV
-
- ML 100 -
- %**** 55 + +
+
GSR
+
+ + {wsConnected ? "REAL" : "SIM"} + + + {wsConnected ? "ESP32" : "Demo"} + +
+
+ {infoGsr.toFixed(1)} + {gsrTrend && ( + + {gsrTrend.direction === "decreasing" + ? "โ†“" + : gsrTrend.direction === "increasing" + ? "โ†‘" + : "โ†’"} + + )} +
+
+ ฮผS
-
-
-
{infoBloodVolume.toFixed(1)}
+ +
+
Respiratory Rate
+
+ + {wsConnected ? "REAL" : "SIM"} + + + {wsConnected ? "ESP32" : "Demo"} +
+
{infoResp.toFixed(0)}
+
breaths/min
+
+ +
+
Heart Rate Coherence
+
{coherence.toFixed(0)}
+
%
+ + {wsConnected && ecgMetrics && ( +
+
ECG Signal Quality
+
= 80 + ? "#4CAF50" + : ecgMetrics.signalQuality >= 60 + ? "#FF9800" + : "#F44336", + }} + > + {ecgMetrics.signalQuality.toFixed(0)} +
+
%
+
+ )}
+ + {showAnalysis && ( +
+
+
HRV Analysis
+
+
+
HRV Mean
+
+ {wsConnected && ecgMetrics + ? ecgMetrics.meanIBI.toFixed(0) + : infoHrv.toFixed(0)}{" "} + ms +
+
+
+
SDNN
+
+ {wsConnected && ecgMetrics + ? ecgMetrics.sdnn.toFixed(0) + : infoHrv.toFixed(0)}{" "} + ms +
+
+
+
RMSSD
+
+ {wsConnected && ecgMetrics + ? ecgMetrics.rmssd.toFixed(0) + : (infoHrv * 0.85).toFixed(0)}{" "} + ms +
+
+
+
LF Power
+
+ {wsConnected && ecgMetrics + ? ecgMetrics.lfPower.toFixed(0) + : (infoHrv * 45).toFixed(0)}{" "} + msยฒ +
+
+
+
HF Power
+
+ {wsConnected && ecgMetrics + ? ecgMetrics.hfPower.toFixed(0) + : (infoHrv * 35).toFixed(0)}{" "} + msยฒ +
+
+
+
LF/HF Ratio
+
+ {wsConnected && ecgMetrics + ? ecgMetrics.lfHfRatio.toFixed(2) + : (45 / 35).toFixed(2)} +
+
+
+
+ + {wsConnected && ecgMetrics && ( +
+
ECG Quality Analysis
+
+
+
Signal Quality
+
= 80 + ? "#4CAF50" + : ecgMetrics.signalQuality >= 60 + ? "#FF9800" + : "#F44336", + }} + > + {ecgMetrics.signalQuality.toFixed(0)}% +
+
+
+
Noise Level
+
+ {(ecgMetrics.noiseLevel * 100).toFixed(1)}% +
+
+
+
Artifacts
+
+ {ecgMetrics.artifactCount} +
+
+
+
Valid Beats
+
{ecgMetrics.validBeats}
+
+
+
pNN50
+
{ecgMetrics.pnn50.toFixed(1)}%
+
+
+
Coherence
+
= 70 + ? "#4CAF50" + : ecgMetrics.coherence >= 50 + ? "#FF9800" + : "#F44336", + }} + > + {ecgMetrics.coherence.toFixed(0)}% +
+
+
+
+ )} + + {wsConnected && respirationMetrics && ( +
+
Respiration Analysis
+
+
+
Breath Count
+
{respirationMetrics.breathCount}
+
+
+
Avg Cycle Duration
+
+ {(respirationMetrics.averageCycleDuration / 1000).toFixed(1)}s +
+
+
+
Last Breath
+
+ {respirationMetrics.lastBreathTime + ? `${Math.round( + (Date.now() - respirationMetrics.lastBreathTime) / 1000 + )}s ago` + : "N/A"} +
+
+
+
Signal Quality
+
+ {respirationMetrics.breathCount > 5 + ? "Good" + : respirationMetrics.breathCount > 2 + ? "Fair" + : "Poor"} +
+
+
+
+ )} +
+ )} +
+ + {/* Session Report Display */} + {sessionReport && (
-
-
- SPO2 +
+

+ ๐Ÿ“Š Session Report: {sessionReport.sessionId} +

+ +
+ +
+

Session Overview

+
+
+
Duration
+
+ {(sessionReport.totalDuration / 1000 / 60).toFixed(1)} minutes +
+
+
+
Data Points
+
+ {sessionReport.totalDataPoints} +
+
+
+
Overall Quality
+
+ {sessionReport.qualityAssessment.overallQuality.toUpperCase()} +
+
+
+
Connection Reliability
+
+ {sessionReport.qualityAssessment.connectionReliability.toFixed(1)}% +
+
-
18:06
-
-
-
- 71- -
- RESP + +
+

Phase Analysis

+
+ {(["initial", "main", "final"] as const).map((phaseName) => { + const phase = sessionReport.phases[phaseName]; + const phaseDuration = (phase.duration / 1000 / 60).toFixed(1); + + return ( +
+

+ {phaseName} Phase ({phaseDuration} min) +

+ +
+
+ Data Points: {phase.dataPoints} +
+
+ Connection Stability: {phase.quality.connectionStability.toFixed(1)} + % +
+
+ +
+
+ Vital Signs Statistics +
+ + {/* Heart Rate Statistics */} +
+
+ โค๏ธ Heart Rate +
+
+
+
Min
+
+ {phase.heartRate.min.toFixed(1)} BPM +
+
+
+
Max
+
+ {phase.heartRate.max.toFixed(1)} BPM +
+
+
+
Average
+
+ {phase.heartRate.avg.toFixed(1)} BPM +
+
+
+
+ StdDev: {phase.heartRate.stdDev.toFixed(2)} | Valid Readings:{" "} + {phase.heartRate.validReadings} +
+
+ + {/* Respiratory Rate Statistics */} +
+
+ ๐Ÿซ Respiratory Rate +
+
+
+
Min
+
+ {phase.respiratoryRate.min.toFixed(1)} breaths/min +
+
+
+
Max
+
+ {phase.respiratoryRate.max.toFixed(1)} breaths/min +
+
+
+
Average
+
+ {phase.respiratoryRate.avg.toFixed(1)} breaths/min +
+
+
+
+ StdDev: {phase.respiratoryRate.stdDev.toFixed(2)} | Valid + Readings: {phase.respiratoryRate.validReadings} +
+
+ + {/* GSR Statistics */} +
+
+ โšก GSR (Galvanic Skin Response) +
+
+
+
Min
+
+ {phase.gsr.min.toFixed(3)} ฮผS +
+
+
+
Max
+
+ {phase.gsr.max.toFixed(3)} ฮผS +
+
+
+
Average
+
+ {phase.gsr.avg.toFixed(3)} ฮผS +
+
+
+
+ StdDev: {phase.gsr.stdDev.toFixed(3)} | Valid Readings:{" "} + {phase.gsr.validReadings} +
+
+ + {/* HRV Statistics */} +
+
+ ๐Ÿ’“ Heart Rate Variability (HRV) +
+
+
+
SDNN
+
+
+
Min
+
+ {phase.hrv.sdnn.min.toFixed(1)} +
+
+
+
Max
+
+ {phase.hrv.sdnn.max.toFixed(1)} +
+
+
+
Avg
+
+ {phase.hrv.sdnn.avg.toFixed(1)} +
+
+
+
+
+
RMSSD
+
+
+
Min
+
+ {phase.hrv.rmssd.min.toFixed(1)} +
+
+
+
Max
+
+ {phase.hrv.rmssd.max.toFixed(1)} +
+
+
+
Avg
+
+ {phase.hrv.rmssd.avg.toFixed(1)} +
+
+
+
+
+
+ pNN50: {phase.hrv.pnn50.avg.toFixed(1)}% | LF/HF Ratio:{" "} + {phase.hrv.lfHfRatio.avg.toFixed(2)} +
+
+ + {/* Respiratory Pattern Statistics */} +
+
+ ๐ŸŒฌ๏ธ Breathing Pattern +
+
+
+
Inhale %
+
+
+
Min
+
+ {phase.respiratoryPattern.inhalePercent.min.toFixed( + 1 + )} + % +
+
+
+
Max
+
+ {phase.respiratoryPattern.inhalePercent.max.toFixed( + 1 + )} + % +
+
+
+
Avg
+
+ {phase.respiratoryPattern.inhalePercent.avg.toFixed( + 1 + )} + % +
+
+
+
+
+
Exhale %
+
+
+
Min
+
+ {phase.respiratoryPattern.exhalePercent.min.toFixed( + 1 + )} + % +
+
+
+
Max
+
+ {phase.respiratoryPattern.exhalePercent.max.toFixed( + 1 + )} + % +
+
+
+
Avg
+
+ {phase.respiratoryPattern.exhalePercent.avg.toFixed( + 1 + )} + % +
+
+
+
+
+
+ Total Breaths: {phase.respiratoryPattern.breathCount} | Avg + Cycle:{" "} + {(phase.respiratoryPattern.averageCycleDuration / 1000).toFixed( + 1 + )} + s +
+
+
+
+ ); + })} +
+
+ +
+

Overall Session Statistics

+
+ {/* Overall Heart Rate Statistics */} +
+

+ โค๏ธ Heart Rate (Entire Session) +

+
+
+
Minimum
+
+ {sessionReport.overall.heartRate.min.toFixed(1)} +
+
BPM
+
+
+
Maximum
+
+ {sessionReport.overall.heartRate.max.toFixed(1)} +
+
BPM
+
+
+
Average
+
+ {sessionReport.overall.heartRate.avg.toFixed(1)} +
+
BPM
+
+
+
+ Standard Deviation: {sessionReport.overall.heartRate.stdDev.toFixed(2)} BPM +
+
+ + {/* Overall Respiratory Rate Statistics */} +
+

+ ๐Ÿซ Respiratory Rate (Entire Session) +

+
+
+
Minimum
+
+ {sessionReport.overall.respiratoryRate.min.toFixed(1)} +
+
breaths/min
+
+
+
Maximum
+
+ {sessionReport.overall.respiratoryRate.max.toFixed(1)} +
+
breaths/min
+
+
+
Average
+
+ {sessionReport.overall.respiratoryRate.avg.toFixed(1)} +
+
breaths/min
+
+
+
+ Standard Deviation: {sessionReport.overall.respiratoryRate.stdDev.toFixed(2)}{" "} + breaths/min +
+
+ + {/* Overall GSR Statistics */} +
+

โšก GSR (Entire Session)

+
+
+
Minimum
+
+ {sessionReport.overall.gsr.min.toFixed(3)} +
+
ฮผS
+
+
+
Maximum
+
+ {sessionReport.overall.gsr.max.toFixed(3)} +
+
ฮผS
+
+
+
Average
+
+ {sessionReport.overall.gsr.avg.toFixed(3)} +
+
ฮผS
+
+
+
+ Standard Deviation: {sessionReport.overall.gsr.stdDev.toFixed(3)} ฮผS +
+ + {/* Overall HRV Statistics */} +
+

+ ๐Ÿ’“ HRV Metrics (Entire Session) +

+
+
+
SDNN
+
+ {sessionReport.overall.hrv.avgSdnn.toFixed(1)} +
+
ms
+
+
+
RMSSD
+
+ {sessionReport.overall.hrv.avgRmssd.toFixed(1)} +
+
ms
+
+
+
pNN50
+
+ {sessionReport.overall.hrv.avgPnn50.toFixed(1)} +
+
%
+
+
+
Total Breaths
+
+ {sessionReport.overall.respiratoryPattern.totalBreaths} +
+
count
+
+
+
+ Breathing Pattern:{" "} + {sessionReport.overall.respiratoryPattern.avgInhalePercent.toFixed(1)}% inhale,{" "} + {sessionReport.overall.respiratoryPattern.avgExhalePercent.toFixed(1)}% exhale +
+
+
+
+ +
+

Export Options

+
+ + +
-
{infoBloodOxygenation}
+ + {sessionReport.qualityAssessment.recommendations.length > 0 && ( +
+

Recommendations

+
+ {sessionReport.qualityAssessment.recommendations.map((rec, index) => ( +
+ {index + 1}. {rec} +
+ ))} +
+
+ )}
-
+ )}
); -} +}; + +export default VitalSignsMonitorDemo; diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/sessionRecorder.ts b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/sessionRecorder.ts new file mode 100644 index 000000000..e38a2e341 --- /dev/null +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/sessionRecorder.ts @@ -0,0 +1,928 @@ +// Comprehensive Session Recording System for 20-minute Vital Signs Monitoring +// Tracks data across three phases: Initial (25%), Main (50%), Final (25%) +// Provides statistical analysis with outlier filtering for accurate patient assessment + +export interface VitalSignsData { + timestamp: number; + heartRate: number; + respiratoryRate: number; + gsrValue: number; + ecgQuality: number; + hrvMetrics: { + sdnn: number; + rmssd: number; + pnn50: number; + lfPower: number; + hfPower: number; + lfHfRatio: number; + // Additional HRV metrics for medical analysis + nn50: number; + triangularIndex: number; + stressIndex: number; + vagalTone: number; + }; + respiratoryMetrics: { + breathCount: number; + inhalePercent: number; + exhalePercent: number; + breathingState: string; + averageCycleDuration: number; + + // Enhanced HW484 respiration sensor metrics + tidalVolume: number; + minuteVolume: number; + inspiratoryTime: number; + expiratoryTime: number; + totalBreathTime: number; + inspiratoryExpiratoryRatio: number; + peakInspiratoryFlow: number; + peakExpiratoryFlow: number; + respiratoryEffort: number; + breathingRegularity: number; + apneaHypopneaIndex: number; + respiratorySinusArrhythmia: number; + + // Advanced respiratory analysis + respiratoryPhaseCoherence: number; + respiratoryRateVariability: number; + breathDepthConsistency: number; + respiratoryEfficiency: number; + + // Medical assessment scores + respiratoryDistressScore: number; + breathingPatternQuality: number; + respiratoryFatigueIndex: number; + }; + connectionStatus: { + esp32Connected: boolean; + sensorsConnected: { + ecg: boolean; + gsr: boolean; + respiratory: boolean; + }; + }; +} + +export interface PhaseStatistics { + phase: "initial" | "main" | "final"; + startTime: number; + endTime: number; + duration: number; + dataPoints: number; + + // Heart Rate Statistics + heartRate: { + min: number; + max: number; + avg: number; + stdDev: number; + validReadings: number; + }; + + // Respiratory Rate Statistics + respiratoryRate: { + min: number; + max: number; + avg: number; + stdDev: number; + validReadings: number; + }; + + // GSR Statistics + gsr: { + min: number; + max: number; + avg: number; + stdDev: number; + validReadings: number; + }; + + // HRV Statistics + hrv: { + sdnn: { min: number; max: number; avg: number; stdDev: number; validReadings: number }; + rmssd: { min: number; max: number; avg: number; stdDev: number; validReadings: number }; + pnn50: { min: number; max: number; avg: number; stdDev: number; validReadings: number }; + lfPower: { min: number; max: number; avg: number; stdDev: number; validReadings: number }; + hfPower: { min: number; max: number; avg: number; stdDev: number; validReadings: number }; + lfHfRatio: { min: number; max: number; avg: number; stdDev: number; validReadings: number }; + }; + + // Respiratory Pattern Statistics + respiratoryPattern: { + inhalePercent: { min: number; max: number; avg: number; stdDev: number; validReadings: number }; + exhalePercent: { min: number; max: number; avg: number; stdDev: number; validReadings: number }; + breathCount: number; + averageCycleDuration: number; + }; + + // Quality Metrics + quality: { + ecgQuality: { min: number; max: number; avg: number; validReadings: number }; + connectionStability: number; // Percentage of time ESP32 was connected + sensorStability: { + ecg: number; + gsr: number; + respiratory: number; + }; + }; +} + +export interface SessionReport { + sessionId: string; + startTime: number; + endTime: number; + totalDuration: number; + totalDataPoints: number; + + // Phase Information + phases: { + initial: PhaseStatistics; + main: PhaseStatistics; + final: PhaseStatistics; + }; + + // Overall Session Statistics + overall: { + heartRate: { min: number; max: number; avg: number; stdDev: number }; + respiratoryRate: { min: number; max: number; avg: number; stdDev: number }; + gsr: { min: number; max: number; avg: number; stdDev: number }; + hrv: { avgSdnn: number; avgRmssd: number; avgPnn50: number }; + respiratoryPattern: { avgInhalePercent: number; avgExhalePercent: number; totalBreaths: number }; + }; + + // Quality Assessment + qualityAssessment: { + overallQuality: "excellent" | "good" | "fair" | "poor"; + dataCompleteness: number; // Percentage of expected data points + connectionReliability: number; // Percentage of stable connection + sensorReliability: { + ecg: number; + gsr: number; + respiratory: number; + }; + recommendations: string[]; + }; + + // Export Data + exportData: { + csv: string; + json: string; + summary: string; + }; +} + +export class SessionRecorder { + private static instance: SessionRecorder; + private isRecording: boolean = false; + private sessionStartTime: number = 0; + private sessionId: string = ""; + private sessionData: VitalSignsData[] = []; + private phaseData: { + initial: VitalSignsData[]; + main: VitalSignsData[]; + final: VitalSignsData[]; + } = { initial: [], main: [], final: [] }; + + // Configuration + private readonly SESSION_DURATION = 20 * 60 * 1000; // 20 minutes in milliseconds + private readonly PHASE_BREAKDOWN = { + initial: 0.25, // First 25% + main: 0.5, // Middle 50% + final: 0.25, // Final 25% + }; + + // Outlier filtering thresholds (for removing glitchy values) + private readonly OUTLIER_THRESHOLDS = { + heartRate: { min: 40, max: 200 }, // BPM range + respiratoryRate: { min: 8, max: 40 }, // breaths/min range + gsr: { min: 0.1, max: 100 }, // ฮผS range + hrv: { min: 10, max: 200 }, // ms range + respiratoryPercent: { min: 10, max: 90 }, // percentage range + }; + + // Quality thresholds + private readonly QUALITY_THRESHOLDS = { + excellent: 0.9, // 90%+ data quality + good: 0.75, // 75%+ data quality + fair: 0.5, // 50%+ data quality + poor: 0.0, // Below 50% + }; + + private constructor() {} + + public static getInstance(): SessionRecorder { + if (!SessionRecorder.instance) { + SessionRecorder.instance = new SessionRecorder(); + } + return SessionRecorder.instance; + } + + /** + * Start a new 20-minute recording session + */ + public startSession(): string { + if (this.isRecording) { + throw new Error("Session already in progress"); + } + + this.isRecording = true; + this.sessionStartTime = Date.now(); + this.sessionId = this.generateSessionId(); + this.sessionData = []; + this.phaseData = { initial: [], main: [], final: [] }; + + console.log(`๐Ÿ”ด Session ${this.sessionId} started at ${new Date(this.sessionStartTime).toISOString()}`); + return this.sessionId; + } + + /** + * Stop the current session and generate comprehensive report + */ + public stopSession(): SessionReport { + if (!this.isRecording) { + throw new Error("No session in progress"); + } + + this.isRecording = false; + const sessionEndTime = Date.now(); + const totalDuration = sessionEndTime - this.sessionStartTime; + + console.log( + `โน๏ธ Session ${this.sessionId} stopped. Duration: ${(totalDuration / 1000 / 60).toFixed(1)} minutes` + ); + + // Organize data into phases + this.organizeDataIntoPhases(); + + // Generate comprehensive report + const report = this.generateSessionReport(sessionEndTime, totalDuration); + + // Export data + report.exportData = this.exportSessionData(report); + + return report; + } + + /** + * Add vital signs data point to the current session + */ + public addDataPoint(data: VitalSignsData): void { + if (!this.isRecording) return; + + // Filter out glitchy/outlier values + const filteredData = this.filterOutliers(data); + + if (filteredData) { + this.sessionData.push(filteredData); + + // Check if session duration exceeded + const currentDuration = Date.now() - this.sessionStartTime; + if (currentDuration >= this.SESSION_DURATION) { + console.log("โฐ Session duration reached 20 minutes. Auto-stopping session..."); + this.stopSession(); + } + } + } + + /** + * Get current session status + */ + public getSessionStatus(): { + isRecording: boolean; + sessionId: string; + elapsedTime: number; + remainingTime: number; + dataPoints: number; + currentPhase: "initial" | "main" | "final"; + phaseProgress: number; + } { + if (!this.isRecording) { + return { + isRecording: false, + sessionId: "", + elapsedTime: 0, + remainingTime: 0, + dataPoints: 0, + currentPhase: "initial", + phaseProgress: 0, + }; + } + + const elapsedTime = Date.now() - this.sessionStartTime; + const remainingTime = Math.max(0, this.SESSION_DURATION - elapsedTime); + const progress = elapsedTime / this.SESSION_DURATION; + + let currentPhase: "initial" | "main" | "final" = "initial"; + let phaseProgress = 0; + + if (progress <= this.PHASE_BREAKDOWN.initial) { + currentPhase = "initial"; + phaseProgress = progress / this.PHASE_BREAKDOWN.initial; + } else if (progress <= this.PHASE_BREAKDOWN.initial + this.PHASE_BREAKDOWN.main) { + currentPhase = "main"; + phaseProgress = (progress - this.PHASE_BREAKDOWN.initial) / this.PHASE_BREAKDOWN.main; + } else { + currentPhase = "final"; + phaseProgress = + (progress - this.PHASE_BREAKDOWN.initial - this.PHASE_BREAKDOWN.main) / this.PHASE_BREAKDOWN.final; + } + + return { + isRecording: true, + sessionId: this.sessionId, + elapsedTime, + remainingTime, + dataPoints: this.sessionData.length, + currentPhase, + phaseProgress, + }; + } + + /** + * Filter out glitchy/outlier values based on physiological ranges + */ + private filterOutliers(data: VitalSignsData): VitalSignsData | null { + // Heart rate validation + if ( + data.heartRate < this.OUTLIER_THRESHOLDS.heartRate.min || + data.heartRate > this.OUTLIER_THRESHOLDS.heartRate.max + ) { + return null; // Invalid heart rate + } + + // Respiratory rate validation + if ( + data.respiratoryRate < this.OUTLIER_THRESHOLDS.respiratoryRate.min || + data.respiratoryRate > this.OUTLIER_THRESHOLDS.respiratoryRate.max + ) { + return null; // Invalid respiratory rate + } + + // GSR validation + if (data.gsrValue < this.OUTLIER_THRESHOLDS.gsr.min || data.gsrValue > this.OUTLIER_THRESHOLDS.gsr.max) { + return null; // Invalid GSR + } + + // HRV validation + if ( + data.hrvMetrics.sdnn < this.OUTLIER_THRESHOLDS.hrv.min || + data.hrvMetrics.sdnn > this.OUTLIER_THRESHOLDS.hrv.max + ) { + return null; // Invalid HRV + } + + // Respiratory pattern validation + if ( + data.respiratoryMetrics.inhalePercent < this.OUTLIER_THRESHOLDS.respiratoryPercent.min || + data.respiratoryMetrics.inhalePercent > this.OUTLIER_THRESHOLDS.respiratoryPercent.max + ) { + return null; // Invalid inhale percentage + } + + return data; + } + + /** + * Organize collected data into three phases + */ + private organizeDataIntoPhases(): void { + const totalDuration = this.SESSION_DURATION; + const initialEndTime = this.sessionStartTime + totalDuration * this.PHASE_BREAKDOWN.initial; + const mainEndTime = + this.sessionStartTime + totalDuration * (this.PHASE_BREAKDOWN.initial + this.PHASE_BREAKDOWN.main); + + this.phaseData = { + initial: this.sessionData.filter( + (d) => d.timestamp >= this.sessionStartTime && d.timestamp < initialEndTime + ), + main: this.sessionData.filter((d) => d.timestamp >= initialEndTime && d.timestamp < mainEndTime), + final: this.sessionData.filter( + (d) => d.timestamp >= mainEndTime && d.timestamp <= this.sessionStartTime + totalDuration + ), + }; + + console.log( + `๐Ÿ“Š Data organized into phases: Initial(${this.phaseData.initial.length}), Main(${this.phaseData.main.length}), Final(${this.phaseData.final.length})` + ); + } + + /** + * Calculate comprehensive statistics for a phase + */ + private calculatePhaseStatistics( + phaseData: VitalSignsData[], + phase: "initial" | "main" | "final" + ): PhaseStatistics { + if (phaseData.length === 0) { + return this.createEmptyPhaseStatistics(phase); + } + + const startTime = Math.min(...phaseData.map((d) => d.timestamp)); + const endTime = Math.max(...phaseData.map((d) => d.timestamp)); + const duration = endTime - startTime; + + // Extract arrays for statistical calculations + const heartRates = phaseData.map((d) => d.heartRate).filter((r) => r > 0); + const respiratoryRates = phaseData.map((d) => d.respiratoryRate).filter((r) => r > 0); + const gsrValues = phaseData.map((d) => d.gsrValue).filter((g) => g > 0); + const ecgQualities = phaseData.map((d) => d.ecgQuality).filter((q) => q > 0); + + // HRV metrics + const sdnnValues = phaseData.map((d) => d.hrvMetrics.sdnn).filter((s) => s > 0); + const rmssdValues = phaseData.map((d) => d.hrvMetrics.rmssd).filter((r) => r > 0); + const pnn50Values = phaseData.map((d) => d.hrvMetrics.pnn50).filter((p) => p > 0); + const lfPowerValues = phaseData.map((d) => d.hrvMetrics.lfPower).filter((l) => l > 0); + const hfPowerValues = phaseData.map((d) => d.hrvMetrics.hfPower).filter((h) => h > 0); + const lfHfRatioValues = phaseData.map((d) => d.hrvMetrics.lfHfRatio).filter((r) => r > 0); + + // Respiratory pattern metrics + const inhalePercents = phaseData.map((d) => d.respiratoryMetrics.inhalePercent).filter((i) => i > 0); + const exhalePercents = phaseData.map((d) => d.respiratoryMetrics.exhalePercent).filter((e) => e > 0); + + // Connection and sensor stability + const esp32ConnectedCount = phaseData.filter((d) => d.connectionStatus.esp32Connected).length; + const ecgConnectedCount = phaseData.filter((d) => d.connectionStatus.sensorsConnected.ecg).length; + const gsrConnectedCount = phaseData.map((d) => d.connectionStatus.sensorsConnected.gsr).filter(Boolean).length; + const respiratoryConnectedCount = phaseData + .map((d) => d.connectionStatus.sensorsConnected.respiratory) + .filter(Boolean).length; + + return { + phase, + startTime, + endTime, + duration, + dataPoints: phaseData.length, + + heartRate: this.calculateStatistics(heartRates), + respiratoryRate: this.calculateStatistics(respiratoryRates), + gsr: this.calculateStatistics(gsrValues), + + hrv: { + sdnn: this.calculateStatistics(sdnnValues), + rmssd: this.calculateStatistics(rmssdValues), + pnn50: this.calculateStatistics(pnn50Values), + lfPower: this.calculateStatistics(lfPowerValues), + hfPower: this.calculateStatistics(hfPowerValues), + lfHfRatio: this.calculateStatistics(lfHfRatioValues), + }, + + respiratoryPattern: { + inhalePercent: this.calculateStatistics(inhalePercents), + exhalePercent: this.calculateStatistics(exhalePercents), + breathCount: phaseData.reduce((sum, d) => sum + d.respiratoryMetrics.breathCount, 0), + averageCycleDuration: + phaseData.reduce((sum, d) => sum + (d.respiratoryMetrics.averageCycleDuration || 0), 0) / + phaseData.length, + }, + + quality: { + ecgQuality: this.calculateStatistics(ecgQualities), + connectionStability: (esp32ConnectedCount / phaseData.length) * 100, + sensorStability: { + ecg: (ecgConnectedCount / phaseData.length) * 100, + gsr: (gsrConnectedCount / phaseData.length) * 100, + respiratory: (respiratoryConnectedCount / phaseData.length) * 100, + }, + }, + }; + } + + /** + * Calculate basic statistics (min, max, avg, stdDev) for an array of values + */ + private calculateStatistics(values: number[]): { + min: number; + max: number; + avg: number; + stdDev: number; + validReadings: number; + } { + if (values.length === 0) { + return { min: 0, max: 0, avg: 0, stdDev: 0, validReadings: 0 }; + } + + const min = Math.min(...values); + const max = Math.max(...values); + const avg = values.reduce((sum, val) => sum + val, 0) / values.length; + + // Calculate standard deviation + const variance = values.reduce((sum, val) => sum + Math.pow(val - avg, 2), 0) / values.length; + const stdDev = Math.sqrt(variance); + + return { min, max, avg, stdDev, validReadings: values.length }; + } + + /** + * Create empty phase statistics when no data is available + */ + private createEmptyPhaseStatistics(phase: "initial" | "main" | "final"): PhaseStatistics { + const emptyStats = { min: 0, max: 0, avg: 0, stdDev: 0, validReadings: 0 }; + const emptyHrvStats = { min: 0, max: 0, avg: 0, stdDev: 0, validReadings: 0 }; + + return { + phase, + startTime: 0, + endTime: 0, + duration: 0, + dataPoints: 0, + heartRate: emptyStats, + respiratoryRate: emptyStats, + gsr: emptyStats, + hrv: { + sdnn: emptyHrvStats, + rmssd: emptyHrvStats, + pnn50: emptyHrvStats, + lfPower: emptyHrvStats, + hfPower: emptyHrvStats, + lfHfRatio: emptyHrvStats, + }, + respiratoryPattern: { + inhalePercent: emptyStats, + exhalePercent: emptyStats, + breathCount: 0, + averageCycleDuration: 0, + }, + quality: { + ecgQuality: emptyStats, + connectionStability: 0, + sensorStability: { ecg: 0, gsr: 0, respiratory: 0 }, + }, + }; + } + + /** + * Generate comprehensive session report + */ + private generateSessionReport(sessionEndTime: number, totalDuration: number): SessionReport { + // Calculate phase statistics + const initialStats = this.calculatePhaseStatistics(this.phaseData.initial, "initial"); + const mainStats = this.calculatePhaseStatistics(this.phaseData.main, "main"); + const finalStats = this.calculatePhaseStatistics(this.phaseData.final, "final"); + + // Calculate overall statistics + const allHeartRates = this.sessionData.map((d) => d.heartRate).filter((r) => r > 0); + const allRespiratoryRates = this.sessionData.map((d) => d.respiratoryRate).filter((r) => r > 0); + const allGsrValues = this.sessionData.map((d) => d.gsrValue).filter((g) => g > 0); + + const overall = { + heartRate: this.calculateOverallStatistics(allHeartRates), + respiratoryRate: this.calculateOverallStatistics(allRespiratoryRates), + gsr: this.calculateOverallStatistics(allGsrValues), + hrv: { + avgSdnn: this.calculateAverage(this.sessionData.map((d) => d.hrvMetrics.sdnn).filter((s) => s > 0)), + avgRmssd: this.calculateAverage(this.sessionData.map((d) => d.hrvMetrics.rmssd).filter((r) => r > 0)), + avgPnn50: this.calculateAverage(this.sessionData.map((d) => d.hrvMetrics.pnn50).filter((p) => p > 0)), + }, + respiratoryPattern: { + avgInhalePercent: this.calculateAverage( + this.sessionData.map((d) => d.respiratoryMetrics.inhalePercent).filter((i) => i > 0) + ), + avgExhalePercent: this.calculateAverage( + this.sessionData.map((d) => d.respiratoryMetrics.exhalePercent).filter((e) => e > 0) + ), + totalBreaths: this.sessionData.reduce((sum, d) => sum + d.respiratoryMetrics.breathCount, 0), + }, + }; + + // Quality assessment + const qualityAssessment = this.assessSessionQuality(initialStats, mainStats, finalStats); + + return { + sessionId: this.sessionId, + startTime: this.sessionStartTime, + endTime: sessionEndTime, + totalDuration, + totalDataPoints: this.sessionData.length, + phases: { initial: initialStats, main: mainStats, final: finalStats }, + overall, + qualityAssessment, + exportData: { csv: "", json: "", summary: "" }, // Will be populated later + }; + } + + /** + * Calculate overall statistics (min, max, avg, stdDev) + */ + private calculateOverallStatistics(values: number[]): { min: number; max: number; avg: number; stdDev: number } { + if (values.length === 0) return { min: 0, max: 0, avg: 0, stdDev: 0 }; + + const min = Math.min(...values); + const max = Math.max(...values); + const avg = values.reduce((sum, val) => sum + val, 0) / values.length; + const variance = values.reduce((sum, val) => sum + Math.pow(val - avg, 2), 0) / values.length; + const stdDev = Math.sqrt(variance); + + return { min, max, avg, stdDev }; + } + + /** + * Calculate simple average + */ + private calculateAverage(values: number[]): number { + if (values.length === 0) return 0; + return values.reduce((sum, val) => sum + val, 0) / values.length; + } + + /** + * Assess overall session quality + */ + private assessSessionQuality( + initial: PhaseStatistics, + main: PhaseStatistics, + final: PhaseStatistics + ): SessionReport["qualityAssessment"] { + // Calculate data completeness + const expectedDataPoints = (this.SESSION_DURATION / 1000) * 10; // Assuming 10 data points per second + const dataCompleteness = (this.sessionData.length / expectedDataPoints) * 100; + + // Calculate connection reliability + const connectionReliability = + (initial.quality.connectionStability + + main.quality.connectionStability + + final.quality.connectionStability) / + 3; + + // Calculate sensor reliability + const sensorReliability = { + ecg: + (initial.quality.sensorStability.ecg + + main.quality.sensorStability.ecg + + final.quality.sensorStability.ecg) / + 3, + gsr: + (initial.quality.sensorStability.gsr + + main.quality.sensorStability.gsr + + final.quality.sensorStability.gsr) / + 3, + respiratory: + (initial.quality.sensorStability.respiratory + + main.quality.sensorStability.respiratory + + final.quality.sensorStability.respiratory) / + 3, + }; + + // Determine overall quality + let overallQuality: "excellent" | "good" | "fair" | "poor" = "poor"; + if (dataCompleteness >= this.QUALITY_THRESHOLDS.excellent && connectionReliability >= 90) { + overallQuality = "excellent"; + } else if (dataCompleteness >= this.QUALITY_THRESHOLDS.good && connectionReliability >= 75) { + overallQuality = "good"; + } else if (dataCompleteness >= this.QUALITY_THRESHOLDS.fair && connectionReliability >= 50) { + overallQuality = "fair"; + } + + // Generate recommendations + const recommendations: string[] = []; + if (dataCompleteness < 80) recommendations.push("Increase data collection frequency for better analysis"); + if (connectionReliability < 90) recommendations.push("Improve ESP32 connection stability"); + if (sensorReliability.ecg < 80) recommendations.push("Check ECG electrode placement and connection"); + if (sensorReliability.gsr < 80) recommendations.push("Verify GSR sensor contact and positioning"); + if (sensorReliability.respiratory < 80) recommendations.push("Ensure respiratory sensor is properly secured"); + + return { + overallQuality, + dataCompleteness, + connectionReliability, + sensorReliability, + recommendations, + }; + } + + /** + * Export session data in multiple formats + */ + private exportSessionData(report: SessionReport): { csv: string; json: string; summary: string } { + // CSV Export + const csv = this.exportToCSV(report); + + // JSON Export + const json = JSON.stringify(report, null, 2); + + // Summary Export (human-readable) + const summary = this.generateSummary(report); + + return { csv, json, summary }; + } + + /** + * Export session data to CSV format + */ + private exportToCSV(report: SessionReport): string { + const headers = [ + "Phase", + "Start Time", + "End Time", + "Duration (ms)", + "Data Points", + "HR Min", + "HR Max", + "HR Avg", + "HR StdDev", + "HR Valid Readings", + "RR Min", + "RR Max", + "RR Avg", + "RR StdDev", + "RR Valid Readings", + "GSR Min", + "GSR Max", + "GSR Avg", + "GSR StdDev", + "GSR Valid Readings", + "HRV SDNN Min", + "HRV SDNN Max", + "HRV SDNN Avg", + "HRV SDNN StdDev", + "HRV RMSSD Min", + "HRV RMSSD Max", + "HRV RMSSD Avg", + "HRV RMSSD StdDev", + "HRV pNN50 Min", + "HRV pNN50 Max", + "HRV pNN50 Avg", + "HRV pNN50 StdDev", + "Inhale % Min", + "Inhale % Max", + "Inhale % Avg", + "Inhale % StdDev", + "Exhale % Min", + "Exhale % Max", + "Exhale % Avg", + "Exhale % StdDev", + "Breath Count", + "Avg Cycle Duration", + "ECG Quality Min", + "ECG Quality Max", + "ECG Quality Avg", + "Connection Stability %", + "ECG Sensor Stability %", + "GSR Sensor Stability %", + "Respiratory Sensor Stability %", + ]; + + let csvContent = headers.join(",") + "\n"; + + // Add data for each phase + [report.phases.initial, report.phases.main, report.phases.final].forEach((phase) => { + const row = [ + phase.phase, + new Date(phase.startTime).toISOString(), + new Date(phase.endTime).toISOString(), + phase.duration, + phase.dataPoints, + phase.heartRate.min, + phase.heartRate.max, + phase.heartRate.avg.toFixed(2), + phase.heartRate.stdDev.toFixed(2), + phase.heartRate.validReadings, + phase.respiratoryRate.min, + phase.respiratoryRate.max, + phase.respiratoryRate.avg.toFixed(2), + phase.respiratoryRate.stdDev.toFixed(2), + phase.respiratoryRate.validReadings, + phase.gsr.min, + phase.gsr.max, + phase.gsr.avg.toFixed(3), + phase.gsr.stdDev.toFixed(3), + phase.gsr.validReadings, + phase.hrv.sdnn.min, + phase.hrv.sdnn.max, + phase.hrv.sdnn.avg.toFixed(2), + phase.hrv.sdnn.stdDev.toFixed(2), + phase.hrv.rmssd.min, + phase.hrv.rmssd.max, + phase.hrv.rmssd.avg.toFixed(2), + phase.hrv.rmssd.stdDev.toFixed(2), + phase.hrv.pnn50.min, + phase.hrv.pnn50.max, + phase.hrv.pnn50.avg.toFixed(2), + phase.hrv.pnn50.stdDev.toFixed(2), + phase.respiratoryPattern.inhalePercent.min, + phase.respiratoryPattern.inhalePercent.max, + phase.respiratoryPattern.inhalePercent.avg.toFixed(1), + phase.respiratoryPattern.inhalePercent.stdDev.toFixed(1), + phase.respiratoryPattern.exhalePercent.min, + phase.respiratoryPattern.exhalePercent.max, + phase.respiratoryPattern.exhalePercent.avg.toFixed(1), + phase.respiratoryPattern.exhalePercent.stdDev.toFixed(1), + phase.respiratoryPattern.breathCount, + phase.respiratoryPattern.averageCycleDuration.toFixed(0), + phase.quality.ecgQuality.min, + phase.quality.ecgQuality.max, + phase.quality.ecgQuality.avg.toFixed(2), + phase.quality.connectionStability.toFixed(1), + phase.quality.sensorStability.ecg.toFixed(1), + phase.quality.sensorStability.gsr.toFixed(1), + phase.quality.sensorStability.respiratory.toFixed(1), + ]; + + csvContent += row.join(",") + "\n"; + }); + + return csvContent; + } + + /** + * Generate human-readable summary + */ + private generateSummary(report: SessionReport): string { + const durationMinutes = (report.totalDuration / 1000 / 60).toFixed(1); + const startTime = new Date(report.startTime).toLocaleString(); + const endTime = new Date(report.endTime).toLocaleString(); + + let summary = `=== VITAL SIGNS MONITORING SESSION REPORT ===\n\n`; + summary += `Session ID: ${report.sessionId}\n`; + summary += `Duration: ${durationMinutes} minutes\n`; + summary += `Start Time: ${startTime}\n`; + summary += `End Time: ${endTime}\n`; + summary += `Total Data Points: ${report.totalDataPoints}\n`; + summary += `Overall Quality: ${report.qualityAssessment.overallQuality.toUpperCase()}\n\n`; + + // Phase summaries + summary += `=== PHASE ANALYSIS ===\n\n`; + + ["initial", "main", "final"].forEach((phaseName) => { + const phase = report.phases[phaseName as keyof typeof report.phases]; + const phaseDuration = (phase.duration / 1000 / 60).toFixed(1); + + summary += `--- ${phaseName.toUpperCase()} PHASE (${phaseDuration} min) ---\n`; + summary += `Data Points: ${phase.dataPoints}\n`; + summary += `Heart Rate: ${phase.heartRate.avg.toFixed(1)} BPM (${phase.heartRate.min}-${ + phase.heartRate.max + })\n`; + summary += `Respiratory Rate: ${phase.respiratoryRate.avg.toFixed(1)} breaths/min (${ + phase.respiratoryRate.min + }-${phase.respiratoryRate.max})\n`; + summary += `GSR: ${phase.gsr.avg.toFixed(2)} ฮผS (${phase.gsr.min.toFixed(2)}-${phase.gsr.max.toFixed( + 2 + )})\n`; + summary += `HRV SDNN: ${phase.hrv.sdnn.avg.toFixed(1)} ms\n`; + summary += `Breathing Pattern: ${phase.respiratoryPattern.inhalePercent.avg.toFixed( + 1 + )}% inhale, ${phase.respiratoryPattern.exhalePercent.avg.toFixed(1)}% exhale\n`; + summary += `Connection Stability: ${phase.quality.connectionStability.toFixed(1)}%\n\n`; + }); + + // Overall summary + summary += `=== OVERALL SESSION SUMMARY ===\n\n`; + summary += `Average Heart Rate: ${report.overall.heartRate.avg.toFixed(1)} BPM\n`; + summary += `Average Respiratory Rate: ${report.overall.respiratoryRate.avg.toFixed(1)} breaths/min\n`; + summary += `Average GSR: ${report.overall.gsr.avg.toFixed(2)} ฮผS\n`; + summary += `Total Breaths: ${report.overall.respiratoryPattern.totalBreaths}\n`; + summary += `Data Completeness: ${report.qualityAssessment.dataCompleteness.toFixed(1)}%\n`; + summary += `Connection Reliability: ${report.qualityAssessment.connectionReliability.toFixed(1)}%\n\n`; + + // Quality assessment + summary += `=== QUALITY ASSESSMENT ===\n\n`; + summary += `Overall Quality: ${report.qualityAssessment.overallQuality.toUpperCase()}\n`; + summary += `Sensor Reliability:\n`; + summary += ` ECG: ${report.qualityAssessment.sensorReliability.ecg.toFixed(1)}%\n`; + summary += ` GSR: ${report.qualityAssessment.sensorReliability.gsr.toFixed(1)}%\n`; + summary += ` Respiratory: ${report.qualityAssessment.sensorReliability.respiratory.toFixed(1)}%\n\n`; + + if (report.qualityAssessment.recommendations.length > 0) { + summary += `=== RECOMMENDATIONS ===\n\n`; + report.qualityAssessment.recommendations.forEach((rec, index) => { + summary += `${index + 1}. ${rec}\n`; + }); + } + + return summary; + } + + /** + * Generate unique session ID + */ + private generateSessionId(): string { + const timestamp = Date.now().toString(36); + const random = Math.random().toString(36).substring(2, 8); + return `session_${timestamp}_${random}`; + } + + /** + * Get current recording status + */ + public isSessionActive(): boolean { + return this.isRecording; + } + + /** + * Get session progress as percentage + */ + public getSessionProgress(): number { + if (!this.isRecording) return 0; + const elapsed = Date.now() - this.sessionStartTime; + return Math.min(100, (elapsed / this.SESSION_DURATION) * 100); + } + + /** + * Emergency stop session (useful for error handling) + */ + public emergencyStop(): void { + if (this.isRecording) { + console.warn("โš ๏ธ Emergency stopping session..."); + this.stopSession(); + } + } +} diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/setup_firebase.py b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/setup_firebase.py new file mode 100644 index 000000000..e805ed7ae --- /dev/null +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/setup_firebase.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +""" +Frontend Firebase Setup Script for Vital Signs Monitor +This script helps you set up Firebase logging for the frontend. +""" + +import os +import json +from pathlib import Path + +def read_env_file(): + """Read the .env file and return a dictionary of variables.""" + env_vars = {} + env_file = Path('.env') + + if not env_file.exists(): + print("โŒ .env file not found!") + return None + + with open(env_file, 'r') as f: + for line in f: + line = line.strip() + if line and not line.startswith('#') and '=' in line: + key, value = line.split('=', 1) + env_vars[key] = value + + return env_vars + +def validate_firebase_credentials(env_vars): + """Validate that Firebase credentials are properly set.""" + required_vars = [ + 'REACT_APP_FIREBASE_API_KEY', + 'REACT_APP_FIREBASE_AUTH_DOMAIN', + 'REACT_APP_FIREBASE_DATABASE_URL', + 'REACT_APP_FIREBASE_PROJECT_ID', + 'REACT_APP_FIREBASE_STORAGE_BUCKET', + 'REACT_APP_FIREBASE_MESSAGING_SENDER_ID', + 'REACT_APP_FIREBASE_APP_ID' + ] + + missing_vars = [] + for var in required_vars: + if not env_vars.get(var) or env_vars[var] == f'your-{var.lower().replace("react_app_firebase_", "").replace("_", "-")}-here': + missing_vars.append(var) + + if missing_vars: + print(f"โŒ Missing or invalid Firebase credentials: {', '.join(missing_vars)}") + return False + + print("โœ… Firebase credentials look good!") + return True + +def print_setup_instructions(): + """Print setup instructions for Firebase.""" + print("\n" + "="*60) + print("๐Ÿ”ฅ FRONTEND FIREBASE SETUP INSTRUCTIONS") + print("="*60) + print("\n1. Go to Firebase Console: https://console.firebase.google.com/") + print("2. Create a new project or select existing one") + print("3. Enable Realtime Database:") + print(" - Go to Realtime Database") + print(" - Click 'Create Database'") + print(" - Choose 'Start in test mode' (for development)") + print("4. Get your credentials:") + print(" - Go to Project Settings > General") + print(" - Copy 'Web API Key'") + print(" - Copy 'Project ID'") + print(" - Copy 'Storage Bucket'") + print(" - Copy 'Messaging Sender ID'") + print(" - Copy 'App ID'") + print(" - Go to Realtime Database") + print(" - Copy the database URL") + print("5. Update the .env file with your credentials") + print("6. Run this script again to validate") + print("\n" + "="*60) + +def main(): + print("๐Ÿš€ Frontend Firebase Setup Script") + print("="*40) + + # Check if .env file exists + env_vars = read_env_file() + if not env_vars: + print_setup_instructions() + return + + # Validate credentials + if not validate_firebase_credentials(env_vars): + print_setup_instructions() + return + + print("\n๐ŸŽ‰ Setup complete! Your frontend is ready to log to Firebase.") + print("\n๐Ÿ“‹ What will be logged:") + print("- Heart Rate (BPM)") + print("- Respiratory Rate (breaths/min)") + print("- GSR Value and Trend") + print("- ECG Signal Quality") + print("- HRV Metrics (SDNN, RMSSD, pNN50, LF/HF Power)") + print("- Respiratory Metrics (inhale/exhale percentages)") + print("- Connection Status") + print("\n๐Ÿ“Š Data Structure:") + print("/processed_sensor_logs/") + print(" โ””โ”€โ”€ [auto-generated-id]/") + print(" โ”œโ”€โ”€ timestamp: 1234567890") + print(" โ”œโ”€โ”€ heartRate: 75") + print(" โ”œโ”€โ”€ respiratoryRate: 16") + print(" โ”œโ”€โ”€ gsrValue: 0.65") + print(" โ”œโ”€โ”€ gsrTrend: 'increasing'") + print(" โ”œโ”€โ”€ ecgQuality: 'good'") + print(" โ”œโ”€โ”€ hrvMetrics: {...}") + print(" โ”œโ”€โ”€ respiratoryMetrics: {...}") + print(" โ””โ”€โ”€ connectionStatus: {...}") + print("\nโฐ Logging Frequency: Every 30 seconds when ESP32 is connected") + print("\n๐Ÿ” View Data:") + print("1. Go to Firebase Console > Realtime Database") + print("2. Look for 'processed_sensor_logs' folder") + print("3. Data updates every 30 seconds when connected") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/signalProcessor.ts b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/signalProcessor.ts new file mode 100644 index 000000000..de1ccb955 --- /dev/null +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/signalProcessor.ts @@ -0,0 +1,881 @@ +// Signal Processing Module for Real-time Respiration Analysis +// Handles ESP32 WebSocket data and integrates with existing HRV calculations +import { debug, info, warn, error as logError, startTimer, endTimer } from "./debugLogger"; +import { ECGSignalProcessor, ECGMetrics } from "./ecgProcessor"; + +export interface RespirationEvent { + type: "inhale_start" | "inhale_peak" | "inhale_end" | "exhale_start" | "exhale_end"; + timestamp: number; + amplitude: number; + duration?: number; +} + +export interface BreathCycle { + startTime: number; + endTime: number; + inhaleStart: number; + inhaleEnd: number; + exhaleStart: number; + exhaleEnd: number; + inhaleDuration: number; + exhaleDuration: number; + totalDuration: number; + inhalePercent: number; + exhalePercent: number; + peakAmplitude: number; +} + +export interface RespirationMetrics { + rate: number; // breaths per minute + inhalePercent: number; // average inhale percentage + exhalePercent: number; // average exhale percentage + currentCycle?: BreathCycle; + lastBreathTime: number; + breathCount: number; + averageCycleDuration: number; + + // Enhanced HW484 respiration sensor metrics + tidalVolume: number; // Estimated tidal volume in ml + minuteVolume: number; // Minute ventilation in L/min + inspiratoryTime: number; // Time of inspiration in seconds + expiratoryTime: number; // Time of expiration in seconds + totalBreathTime: number; // Total breath cycle time in seconds + inspiratoryExpiratoryRatio: number; // I:E ratio (normal: 1:2 to 1:3) + peakInspiratoryFlow: number; // Peak inspiratory flow rate in L/min + peakExpiratoryFlow: number; // Peak expiratory flow rate in L/min + respiratoryEffort: number; // Respiratory effort index (0-100) + breathingRegularity: number; // Coefficient of variation of breath intervals + apneaHypopneaIndex: number; // AHI score for sleep apnea detection + respiratorySinusArrhythmia: number; // RSA magnitude (heart rate variability with breathing) + + // Advanced respiratory analysis + respiratoryPhaseCoherence: number; // Phase coherence between heart rate and respiration + respiratoryRateVariability: number; // Variability in respiratory rate + breathDepthConsistency: number; // Consistency of breath depth + respiratoryEfficiency: number; // Efficiency of breathing pattern + + // Medical assessment scores + respiratoryDistressScore: number; // Clinical respiratory distress assessment + breathingPatternQuality: number; // Quality score of breathing pattern (0-100) + respiratoryFatigueIndex: number; // Index of respiratory muscle fatigue +} + +export interface SignalProcessingConfig { + samplingRate: number; // Hz + smoothingWindow: number; // samples for moving average + baselineWindow: number; // samples for baseline calculation + thresholdMultiplier: number; // multiplier above baseline for event detection + minPeakDistance: number; // minimum ms between breath events + minBreathDuration: number; // minimum ms for a valid breath cycle + maxBreathDuration: number; // maximum ms for a valid breath cycle + dataWindowSize: number; // ms to keep in memory +} + +export class RespirationSignalProcessor { + private config: SignalProcessingConfig; + private sensorData: Array<{ value: number; timestamp: number }> = []; + private smoothedData: number[] = []; + private baseline: number = 0; + private lastEventTime: number = 0; + private currentState: "idle" | "inhaling" | "exhaling" = "idle"; + private breathCycles: BreathCycle[] = []; + private currentCycle?: Partial; + private metrics: RespirationMetrics = { + rate: 0, + inhalePercent: 0, + exhalePercent: 0, + lastBreathTime: 0, + breathCount: 0, + averageCycleDuration: 0, + + // Enhanced HW484 respiration sensor metrics + tidalVolume: 0, + minuteVolume: 0, + inspiratoryTime: 0, + expiratoryTime: 0, + totalBreathTime: 0, + inspiratoryExpiratoryRatio: 0, + peakInspiratoryFlow: 0, + peakExpiratoryFlow: 0, + respiratoryEffort: 0, + breathingRegularity: 0, + apneaHypopneaIndex: 0, + respiratorySinusArrhythmia: 0, + + // Advanced respiratory analysis + respiratoryPhaseCoherence: 0, + respiratoryRateVariability: 0, + breathDepthConsistency: 0, + respiratoryEfficiency: 0, + + // Medical assessment scores + respiratoryDistressScore: 0, + breathingPatternQuality: 0, + respiratoryFatigueIndex: 0, + }; + + constructor(config: Partial = {}) { + this.config = { + samplingRate: 100, // 100 Hz for respiratory (matches ESP32 RESP_INTERVAL) + smoothingWindow: 5, // 5 samples for moving average + baselineWindow: 100, // 100 samples for baseline (1 second at 100Hz) + thresholdMultiplier: 1.5, // 1.5x baseline for detection + minPeakDistance: 500, // 500ms minimum between events + minBreathDuration: 2000, // 2 seconds minimum breath cycle + maxBreathDuration: 10000, // 10 seconds maximum breath cycle + dataWindowSize: 10000, // 10 seconds of data + ...config, + }; + // Reduced logging to prevent console flooding + // info('RESPIRATION', 'RespirationSignalProcessor initialized', this.config); + } + + // Add new sensor data point + public addDataPoint(value: number, timestamp: number): void { + startTimer("respiration_add_point"); + this.sensorData.push({ value, timestamp }); + + // Remove old data outside the window + const cutoffTime = timestamp - this.config.dataWindowSize; + this.sensorData = this.sensorData.filter((d) => d.timestamp >= cutoffTime); + + // Process the data + this.processData(); + // Reduced logging to prevent console flooding + // endTimer('respiration_add_point', 'RESPIRATION'); + // debug('RESPIRATION', 'Data point added', { value, timestamp, bufferSize: this.sensorData.length }); + } + + // Main signal processing pipeline + private processData(): void { + if (this.sensorData.length < this.config.smoothingWindow) return; + + startTimer("respiration_process_pipeline"); + + // 1. Smoothing (Moving Average) + this.applySmoothing(); + + // 2. Baseline estimation + this.updateBaseline(); + + // 3. Event detection + this.detectBreathingEvents(); + + // 4. Calculate metrics + this.updateMetrics(); + + endTimer("respiration_process_pipeline", "RESPIRATION"); + debug("RESPIRATION", "Processing pipeline completed", { + dataPoints: this.sensorData.length, + currentState: this.currentState, + breathCount: this.metrics.breathCount, + }); + } + + // Apply moving average smoothing + private applySmoothing(): void { + this.smoothedData = []; + + for (let i = 0; i < this.sensorData.length; i++) { + if (i < this.config.smoothingWindow - 1) { + // For the first few points, use available data + const availableData = this.sensorData.slice(0, i + 1); + const sum = availableData.reduce((acc, d) => acc + d.value, 0); + this.smoothedData.push(sum / availableData.length); + } else { + // Moving average with bounds checking + const startIndex = Math.max(0, i - this.config.smoothingWindow + 1); + const window = this.sensorData.slice(startIndex, i + 1); + const sum = window.reduce((acc, d) => acc + d.value, 0); + this.smoothedData.push(sum / window.length); + } + } + } + + // Update dynamic baseline + private updateBaseline(): void { + if (this.smoothedData.length < this.config.baselineWindow) { + // Use all available data if not enough for baseline window + this.baseline = this.smoothedData.reduce((sum, val) => sum + val, 0) / this.smoothedData.length; + } else { + // Use the lowest values in the baseline window (quiet periods) + const recentData = this.smoothedData.slice(-this.config.baselineWindow); + const sortedData = [...recentData].sort((a, b) => a - b); + // Use the lower quartile as baseline + const quartileIndex = Math.floor(sortedData.length * 0.25); + this.baseline = sortedData[quartileIndex]; + } + } + + // Detect breathing events using state machine + private detectBreathingEvents(): void { + if (this.smoothedData.length < 2) return; + + const currentValue = this.smoothedData[this.smoothedData.length - 1]; + const previousValue = this.smoothedData[this.smoothedData.length - 2]; + const currentTime = this.sensorData[this.sensorData.length - 1].timestamp; + const threshold = this.baseline + this.baseline * this.config.thresholdMultiplier; + + // State machine for breath detection + switch (this.currentState) { + case "idle": + if (currentValue > threshold && previousValue <= threshold) { + // Signal crossed threshold upwards - potential inhale start + if (currentTime - this.lastEventTime > this.config.minPeakDistance) { + this.currentState = "inhaling"; + this.currentCycle = { + startTime: currentTime, + inhaleStart: currentTime, + peakAmplitude: currentValue, + }; + this.lastEventTime = currentTime; + } + } + break; + + case "inhaling": + // Track peak amplitude during inhale + if (currentValue > this.currentCycle!.peakAmplitude!) { + this.currentCycle!.peakAmplitude = currentValue; + } + + if (currentValue <= threshold && previousValue > threshold) { + // Signal crossed threshold downwards - inhale end + this.currentCycle!.inhaleEnd = currentTime; + this.currentCycle!.inhaleDuration = currentTime - this.currentCycle!.inhaleStart!; + this.currentState = "exhaling"; + this.currentCycle!.exhaleStart = currentTime; + } + break; + + case "exhaling": + if (currentValue <= this.baseline * 0.8) { + // Signal dropped significantly - exhale end + this.currentCycle!.exhaleEnd = currentTime; + this.currentCycle!.exhaleDuration = currentTime - this.currentCycle!.exhaleStart!; + this.currentCycle!.endTime = currentTime; + this.currentCycle!.totalDuration = currentTime - this.currentCycle!.startTime!; + + // Calculate percentages + this.currentCycle!.inhalePercent = + (this.currentCycle!.inhaleDuration! / this.currentCycle!.totalDuration!) * 100; + this.currentCycle!.exhalePercent = + (this.currentCycle!.exhaleDuration! / this.currentCycle!.totalDuration!) * 100; + + // Validate breath cycle + if (this.isValidBreathCycle(this.currentCycle as BreathCycle)) { + this.breathCycles.push(this.currentCycle as BreathCycle); + this.metrics.breathCount++; + this.metrics.lastBreathTime = currentTime; + } + + this.currentState = "idle"; + this.currentCycle = undefined; + } + break; + } + } + + // Validate if a breath cycle is reasonable + private isValidBreathCycle(cycle: BreathCycle): boolean { + return ( + cycle.totalDuration >= this.config.minBreathDuration && + cycle.totalDuration <= this.config.maxBreathDuration && + cycle.inhalePercent >= 20 && + cycle.inhalePercent <= 60 && + cycle.exhalePercent >= 40 && + cycle.exhalePercent <= 80 + ); + } + + // Update respiration metrics + private updateMetrics(): void { + const currentTime = Date.now(); + + // Remove old breath cycles (older than 60 seconds) + const cutoffTime = currentTime - 60000; + this.breathCycles = this.breathCycles.filter((cycle) => cycle.endTime >= cutoffTime); + + // Calculate respiration rate (breaths per minute) + this.metrics.rate = this.breathCycles.length; + + // Calculate average inhale/exhale percentages with division by zero protection + if (this.breathCycles.length > 0) { + const totalInhalePercent = this.breathCycles.reduce((sum, cycle) => sum + cycle.inhalePercent, 0); + const totalExhalePercent = this.breathCycles.reduce((sum, cycle) => sum + cycle.exhalePercent, 0); + + this.metrics.inhalePercent = totalInhalePercent / this.breathCycles.length; + this.metrics.exhalePercent = totalExhalePercent / this.breathCycles.length; + + // Calculate average cycle duration with division by zero protection + const totalDuration = this.breathCycles.reduce((sum, cycle) => sum + cycle.totalDuration, 0); + this.metrics.averageCycleDuration = totalDuration / this.breathCycles.length; + + // Enhanced HW484 respiration sensor metrics + this.calculateAdvancedRespiratoryMetrics(); + } else { + // Reset metrics when no breath cycles + this.metrics.inhalePercent = 0; + this.metrics.exhalePercent = 0; + this.metrics.averageCycleDuration = 0; + this.resetAdvancedMetrics(); + } + + // Set current cycle for real-time display + this.metrics.currentCycle = this.currentCycle as BreathCycle; + } + + // Calculate advanced respiratory metrics for HW484 sensor + private calculateAdvancedRespiratoryMetrics(): void { + if (this.breathCycles.length === 0) return; + + const recentCycles = this.breathCycles.slice(-5); // Use last 5 cycles for stability + + // Basic timing metrics + const avgInspiratoryTime = + recentCycles.reduce((sum, cycle) => sum + cycle.inhaleDuration, 0) / recentCycles.length; + const avgExpiratoryTime = + recentCycles.reduce((sum, cycle) => sum + cycle.exhaleDuration, 0) / recentCycles.length; + + this.metrics.inspiratoryTime = avgInspiratoryTime / 1000; // Convert to seconds + this.metrics.expiratoryTime = avgExpiratoryTime / 1000; // Convert to seconds + this.metrics.totalBreathTime = (avgInspiratoryTime + avgExpiratoryTime) / 1000; // Convert to seconds + + // I:E ratio (normal range: 1:2 to 1:3) + this.metrics.inspiratoryExpiratoryRatio = avgInspiratoryTime / avgExpiratoryTime; + + // Tidal volume estimation (based on amplitude and duration) + const avgPeakAmplitude = + recentCycles.reduce((sum, cycle) => sum + cycle.peakAmplitude, 0) / recentCycles.length; + this.metrics.tidalVolume = Math.round(((avgPeakAmplitude * 0.5 * avgInspiratoryTime) / 1000) * 1000); // Rough estimation in ml + + // Minute volume (tidal volume * respiratory rate) + this.metrics.minuteVolume = (this.metrics.tidalVolume / 1000) * this.metrics.rate; // L/min + + // Peak flow rates (estimated from amplitude and timing) + this.metrics.peakInspiratoryFlow = Math.round( + this.metrics.tidalVolume / 1000 / (this.metrics.inspiratoryTime / 60) + ); // L/min + this.metrics.peakExpiratoryFlow = Math.round( + this.metrics.tidalVolume / 1000 / (this.metrics.expiratoryTime / 60) + ); // L/min + + // Respiratory effort index (0-100, based on amplitude and rate) + const effortScore = Math.min(100, avgPeakAmplitude / 100 + this.metrics.rate / 2); + this.metrics.respiratoryEffort = Math.round(effortScore); + + // Breathing regularity (coefficient of variation of breath intervals) + const intervals = recentCycles + .map((cycle, i) => { + if (i === 0) return 0; + return cycle.startTime - recentCycles[i - 1].startTime; + }) + .slice(1); + + if (intervals.length > 1) { + const meanInterval = intervals.reduce((sum, interval) => sum + interval, 0) / intervals.length; + const variance = + intervals.reduce((sum, interval) => sum + Math.pow(interval - meanInterval, 2), 0) / intervals.length; + this.metrics.breathingRegularity = Math.round((Math.sqrt(variance) / meanInterval) * 100); + } else { + this.metrics.breathingRegularity = 0; + } + + // Apnea-Hypopnea Index (AHI) estimation + const longBreaths = recentCycles.filter((cycle) => cycle.totalDuration > 8000).length; // >8 seconds + this.metrics.apneaHypopneaIndex = Math.round((longBreaths / recentCycles.length) * 100); + + // Respiratory Sinus Arrhythmia (RSA) - placeholder for heart rate integration + this.metrics.respiratorySinusArrhythmia = 0; // Will be calculated when ECG data is available + + // Advanced analysis metrics + this.metrics.respiratoryPhaseCoherence = Math.round(Math.min(100, 100 - this.metrics.breathingRegularity)); + this.metrics.respiratoryRateVariability = this.metrics.breathingRegularity; + this.metrics.breathDepthConsistency = Math.round(100 - this.metrics.breathingRegularity / 2); + this.metrics.respiratoryEfficiency = Math.round( + Math.max(0, 100 - this.metrics.respiratoryEffort - this.metrics.breathingRegularity) + ); + + // Medical assessment scores + this.metrics.respiratoryDistressScore = this.calculateRespiratoryDistressScore(); + this.metrics.breathingPatternQuality = this.calculateBreathingPatternQuality(); + this.metrics.respiratoryFatigueIndex = this.calculateRespiratoryFatigueIndex(); + } + + // Calculate respiratory distress score (0-100, higher = more distress) + private calculateRespiratoryDistressScore(): number { + let score = 0; + + // Rate-based scoring + if (this.metrics.rate > 25) score += 20; // Tachypnea + else if (this.metrics.rate < 12) score += 15; // Bradypnea + + // Effort-based scoring + if (this.metrics.respiratoryEffort > 70) score += 25; // High effort + + // Regularity-based scoring + if (this.metrics.breathingRegularity > 30) score += 20; // Irregular breathing + + // I:E ratio scoring + if (this.metrics.inspiratoryExpiratoryRatio > 0.6) score += 15; // Abnormal I:E ratio + + return Math.min(100, score); + } + + // Calculate breathing pattern quality (0-100, higher = better quality) + private calculateBreathingPatternQuality(): number { + let score = 100; + + // Deduct points for poor metrics + score -= this.metrics.respiratoryDistressScore; + score -= this.metrics.breathingRegularity / 2; + score -= Math.abs(this.metrics.inspiratoryExpiratoryRatio - 0.4) * 50; // Penalize deviation from normal 1:2.5 ratio + + return Math.max(0, Math.round(score)); + } + + // Calculate respiratory fatigue index (0-100, higher = more fatigue) + private calculateRespiratoryFatigueIndex(): number { + let score = 0; + + // Effort-based fatigue + if (this.metrics.respiratoryEffort > 60) score += 30; + + // Rate-based fatigue + if (this.metrics.rate > 20) score += 25; // Sustained high rate + + // Irregularity-based fatigue + if (this.metrics.breathingRegularity > 25) score += 25; + + // Depth-based fatigue + if (this.metrics.tidalVolume < 300) score += 20; // Shallow breathing + + return Math.min(100, score); + } + + // Reset advanced metrics + private resetAdvancedMetrics(): void { + this.metrics.tidalVolume = 0; + this.metrics.minuteVolume = 0; + this.metrics.inspiratoryTime = 0; + this.metrics.expiratoryTime = 0; + this.metrics.totalBreathTime = 0; + this.metrics.inspiratoryExpiratoryRatio = 0; + this.metrics.peakInspiratoryFlow = 0; + this.metrics.peakExpiratoryFlow = 0; + this.metrics.respiratoryEffort = 0; + this.metrics.breathingRegularity = 0; + this.metrics.apneaHypopneaIndex = 0; + this.metrics.respiratorySinusArrhythmia = 0; + this.metrics.respiratoryPhaseCoherence = 0; + this.metrics.respiratoryRateVariability = 0; + this.metrics.breathDepthConsistency = 0; + this.metrics.respiratoryEfficiency = 0; + this.metrics.respiratoryDistressScore = 0; + this.metrics.breathingPatternQuality = 0; + this.metrics.respiratoryFatigueIndex = 0; + } + + // Get current metrics + public getMetrics(): RespirationMetrics { + return { ...this.metrics }; + } + + // Get current breathing state + public getCurrentState(): { state: string; cycle?: Partial } { + return { + state: this.currentState, + cycle: this.currentCycle, + }; + } + + // Get recent breath cycles + public getRecentCycles(count: number = 10): BreathCycle[] { + return this.breathCycles.slice(-count); + } + + // Reset processor state + public reset(): void { + this.sensorData = []; + this.smoothedData = []; + this.baseline = 0; + this.lastEventTime = 0; + this.currentState = "idle"; + this.breathCycles = []; + this.currentCycle = undefined; + this.metrics = { + rate: 0, + inhalePercent: 0, + exhalePercent: 0, + lastBreathTime: 0, + breathCount: 0, + averageCycleDuration: 0, + + // Enhanced HW484 respiration sensor metrics + tidalVolume: 0, + minuteVolume: 0, + inspiratoryTime: 0, + expiratoryTime: 0, + totalBreathTime: 0, + inspiratoryExpiratoryRatio: 0, + peakInspiratoryFlow: 0, + peakExpiratoryFlow: 0, + respiratoryEffort: 0, + breathingRegularity: 0, + apneaHypopneaIndex: 0, + respiratorySinusArrhythmia: 0, + + // Advanced respiratory analysis + respiratoryPhaseCoherence: 0, + respiratoryRateVariability: 0, + breathDepthConsistency: 0, + respiratoryEfficiency: 0, + + // Medical assessment scores + respiratoryDistressScore: 0, + breathingPatternQuality: 0, + respiratoryFatigueIndex: 0, + }; + } + + // Update configuration + public updateConfig(newConfig: Partial): void { + this.config = { ...this.config, ...newConfig }; + } +} + +// WebSocket handler for ESP32 data with dynamic IP detection +export class ESP32WebSocketHandler { + private ws: WebSocket | null = null; + private respProcessor: RespirationSignalProcessor; + private ecgProcessor: ECGSignalProcessor; + private onDataUpdate: (data: any) => void; + private reconnectAttempts = 0; + private maxReconnectAttempts = 20; // Increased for more persistent connection attempts + private reconnectDelay = 2000; + private wsUrl: string; + private ipDiscoveryAttempts = 0; + private maxIpDiscoveryAttempts = 10; + private reconnectTimer: NodeJS.Timeout | null = null; + + constructor( + respProcessor: RespirationSignalProcessor, + ecgProcessor: ECGSignalProcessor, + onDataUpdate: (data: any) => void, + wsUrl?: string + ) { + this.respProcessor = respProcessor; + this.ecgProcessor = ecgProcessor; + this.onDataUpdate = onDataUpdate; + this.wsUrl = wsUrl || this.detectESP32IP(); + info("WEBSOCKET", "ESP32WebSocketHandler initialized", { wsUrl: this.wsUrl }); + } + + // Hardcoded ESP32 IP address + private detectESP32IP(): string { + // Hardcoded to your specific ESP32 IP + return "ws://192.168.1.17:81"; + } + + // Try different IP addresses if connection fails + private tryNextIP(): void { + // Only try the hardcoded IP + const hardcodedIP = "192.168.1.17:81"; + + if (this.ipDiscoveryAttempts < this.maxIpDiscoveryAttempts) { + this.ipDiscoveryAttempts++; + this.wsUrl = `ws://${hardcodedIP}`; + console.log(`๐Ÿ”Œ Trying ESP32 IP: ${hardcodedIP} (attempt ${this.ipDiscoveryAttempts})`); + this.connect(); + } else { + console.error("โŒ Failed to connect to ESP32 at", hardcodedIP); + this.onDataUpdate({ type: "connection", status: "failed" }); + } + } + + public connect(): void { + try { + // Force close any existing connection + if (this.ws) { + this.ws.close(); + this.ws = null; + } + + startTimer("websocket_connect"); + info("WEBSOCKET", "Connecting to ESP32 WebSocket", { url: this.wsUrl }); + console.log("๐Ÿ”Œ Attempting WebSocket connection to:", this.wsUrl); + + // Create new WebSocket connection + this.ws = new WebSocket(this.wsUrl); + + // Set connection timeout + const connectionTimeout = setTimeout(() => { + if (this.ws && this.ws.readyState === WebSocket.CONNECTING) { + console.error("โฐ WebSocket connection timeout"); + this.ws.close(); + this.onDataUpdate({ type: "connection", status: "timeout" }); + this.attemptReconnect(); + } + }, 10000); // 10 second timeout + + this.ws.onopen = () => { + clearTimeout(connectionTimeout); + endTimer("websocket_connect", "WEBSOCKET"); + info("WEBSOCKET", "ESP32 WebSocket connected successfully!"); + console.log("โœ… WebSocket connection established!"); + this.reconnectAttempts = 0; + this.ipDiscoveryAttempts = 0; // Reset IP discovery on successful connection + this.onDataUpdate({ type: "connection", status: "connected" }); + }; + + this.ws.onmessage = (event) => { + // Log all messages for debugging + + this.handleMessage(event); + }; + + this.ws.onerror = (error) => { + clearTimeout(connectionTimeout); + logError("WEBSOCKET", "ESP32 WebSocket error", error); + console.error("โŒ WebSocket error:", error); + this.onDataUpdate({ type: "connection", status: "error" }); + // Don't call attemptReconnect here, let onclose handle it + }; + + this.ws.onclose = (event) => { + clearTimeout(connectionTimeout); + warn("WEBSOCKET", "ESP32 WebSocket closed"); + console.log("๐Ÿ”Œ WebSocket closed. Code:", event.code, "Reason:", event.reason); + this.onDataUpdate({ type: "connection", status: "disconnected" }); + + // Always attempt reconnect unless we've exceeded max attempts + if (this.reconnectAttempts < this.maxReconnectAttempts) { + this.attemptReconnect(); + } else { + console.error("โŒ Max reconnection attempts reached"); + this.onDataUpdate({ type: "connection", status: "failed" }); + } + }; + } catch (error) { + console.error("Failed to create WebSocket connection:", error); + this.onDataUpdate({ type: "connection", status: "error" }); + this.attemptReconnect(); + } + } + + private handleMessage(event: MessageEvent): void { + try { + startTimer("message_processing"); + + // Validate message data + if (!event.data || typeof event.data !== "string") { + logError("WEBSOCKET", "Invalid message data received", { data: event.data }); + return; + } + + const data = JSON.parse(event.data); + // Convert ESP32 timestamp (millis) to JavaScript timestamp + const esp32Timestamp = data.timestamp || 0; + // ESP32 millis() is relative to boot time, convert to absolute JavaScript timestamp + // Since we can't know the exact boot time, use current time as reference + const jsTimestamp = Date.now(); + + debug("WEBSOCKET", "Message received", { type: data.type, esp32Timestamp, jsTimestamp }); + + // Handle individual sensor data messages from ESP32 + switch (data.type) { + case "respiratory": + // Convert raw ADC value (0-4095) to normalized value (0-1) + const normalizedResp = data.value / 4095.0; + this.respProcessor.addDataPoint(normalizedResp, jsTimestamp); + const metrics = this.respProcessor.getMetrics(); + const state = this.respProcessor.getCurrentState(); + + this.onDataUpdate({ + type: "respiratory", + value: normalizedResp, + raw: data.value, + metrics: metrics, + state: state, + sensorConnected: data.sensorConnected || false, + timestamp: jsTimestamp, + }); + break; + + case "ecg": + // Plot raw ADC values and process for heartbeat detection + const normalizedEcg = data.value / 4095.0; // Normalize to 0-1 for processing + + // Add to ECG processor for heartbeat detection + this.ecgProcessor.addECGPoint(normalizedEcg, jsTimestamp); + + // Get ECG metrics including heart rate + const ecgMetrics = this.ecgProcessor.getMetrics(); + + this.onDataUpdate({ + type: "ecg", + value: data.value, // Raw ADC value (0-4095) for plotting + raw: data.value, + sensorConnected: data.sensorConnected || false, + timestamp: jsTimestamp, + ecgMetrics: ecgMetrics, // Include ECG metrics for heart rate + }); + break; + + case "gsr": + // Convert raw ADC value (0-4095) to microsiemens (ฮผS) + // GSR sensors typically output 0-100 ฮผS range + // Map 0-4095 to 0-100 ฮผS for realistic GSR values + const gsrInMicroSiemens = (data.value / 4095.0) * 100; + this.onDataUpdate({ + type: "gsr", + value: gsrInMicroSiemens, + raw: data.value, + sensorConnected: data.sensorConnected || false, + timestamp: jsTimestamp, + }); + break; + + case "ibi": + this.onDataUpdate({ + type: "ibi", + value: data.value, // IBI in milliseconds + hr: data.hr, // Heart rate in BPM + sensorConnected: data.sensorConnected || false, + timestamp: jsTimestamp, + }); + break; + + case "heartrate": + this.onDataUpdate({ + type: "heartrate", + bpm: data.bpm, // Heart rate in BPM + ibi: data.ibi, // IBI in milliseconds + sensorConnected: data.sensorConnected || false, + timestamp: jsTimestamp, + }); + break; + + default: + console.warn("Unknown ESP32 message type:", data.type); + } + } catch (error) { + endTimer("message_processing", "WEBSOCKET"); + logError("WEBSOCKET", "Failed to parse ESP32 message", { data: event.data, error }); + } + } + + private attemptReconnect(): void { + if (this.reconnectAttempts < this.maxReconnectAttempts) { + this.reconnectAttempts++; + console.log(`๐Ÿ”„ Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`); + + // Clear any existing reconnect timer + if (this.reconnectTimer) { + clearTimeout(this.reconnectTimer); + } + + // More aggressive reconnection - try immediately, then with short delays + const delay = this.reconnectAttempts === 1 ? 0 : Math.min(1000 * this.reconnectAttempts, 5000); + + this.reconnectTimer = setTimeout(() => { + console.log("๐Ÿ”„ Executing reconnection attempt..."); + this.connect(); + }, delay); + } else { + console.error("โŒ Max reconnection attempts reached"); + this.onDataUpdate({ type: "connection", status: "failed" }); + } + } + + public disconnect(): void { + // Clear reconnect timer + if (this.reconnectTimer) { + clearTimeout(this.reconnectTimer); + this.reconnectTimer = null; + } + + if (this.ws) { + // Remove all event listeners to prevent memory leaks + this.ws.onopen = null; + this.ws.onmessage = null; + this.ws.onerror = null; + this.ws.onclose = null; + + this.ws.close(); + this.ws = null; + } + } + + public isConnected(): boolean { + return this.ws?.readyState === WebSocket.OPEN; + } + + // Update WebSocket URL (useful for manual IP configuration) + public updateUrl(newUrl: string): void { + this.wsUrl = newUrl; + if (this.isConnected()) { + this.disconnect(); + this.connect(); + } + } + + // Force connection attempt (useful for manual reconnection) + public forceConnect(): void { + console.log("๐Ÿ”Œ Force connecting to ESP32..."); + this.reconnectAttempts = 0; + this.ipDiscoveryAttempts = 0; + this.connect(); + } +} + +// Utility functions for signal processing +export const signalProcessingUtils = { + // Calculate moving average + movingAverage: (data: number[], windowSize: number): number[] => { + const result = []; + for (let i = 0; i < data.length; i++) { + const start = Math.max(0, i - windowSize + 1); + const window = data.slice(start, i + 1); + const average = window.reduce((sum, val) => sum + val, 0) / window.length; + result.push(average); + } + return result; + }, + + // Calculate standard deviation + standardDeviation: (data: number[]): number => { + const mean = data.reduce((sum, val) => sum + val, 0) / data.length; + const squaredDiffs = data.map((val) => Math.pow(val - mean, 2)); + const variance = squaredDiffs.reduce((sum, val) => sum + val, 0) / data.length; + return Math.sqrt(variance); + }, + + // Detect peaks in signal + detectPeaks: (data: number[], threshold: number, minDistance: number): number[] => { + const peaks = []; + for (let i = 1; i < data.length - 1; i++) { + if (data[i] > threshold && data[i] > data[i - 1] && data[i] > data[i + 1]) { + // Check minimum distance from last peak + if (peaks.length === 0 || i - peaks[peaks.length - 1] >= minDistance) { + peaks.push(i); + } + } + } + return peaks; + }, + + // Normalize signal to 0-1 range + normalize: (data: number[]): number[] => { + if (data.length === 0) return []; + + const min = Math.min(...data); + const max = Math.max(...data); + const range = max - min; + + // Avoid division by zero + if (range === 0) return data.map(() => 0.5); + + return data.map((val) => (val - min) / range); + }, +}; diff --git a/Examples/src/config/environment.ts b/Examples/src/config/environment.ts new file mode 100644 index 000000000..35ec94a5e --- /dev/null +++ b/Examples/src/config/environment.ts @@ -0,0 +1,140 @@ +// Environment configuration for the application +// This file ensures environment variables are properly loaded and validated + +interface EnvironmentConfig { + firebase: { + apiKey: string; + authDomain: string; + databaseURL: string; + projectId: string; + storageBucket: string; + messagingSenderId: string; + appId: string; + }; + app: { + isDevelopment: boolean; + isProduction: boolean; + version: string; + }; +} + +// Safe way to access environment variables in both Node.js and browser +const getEnvVar = (key: string): string | undefined => { + // Try to access process.env (Node.js) + if (typeof process !== "undefined" && process.env) { + return process.env[key]; + } + + // Try to access window.__ENV__ (if set by webpack) + if (typeof window !== "undefined" && (window as any).__ENV__) { + return (window as any).__ENV__[key]; + } + + // Try to access global.__ENV__ (if set by webpack) + if (typeof global !== "undefined" && (global as any).__ENV__) { + return (global as any).__ENV__[key]; + } + + return undefined; +}; + +// Fallback Firebase configuration (from .env file) +const FALLBACK_FIREBASE_CONFIG = { + apiKey: "AIzaSyC2Il3KXMbvIwiVO-q2QnyjCzXWOU6qUBQ", + authDomain: "biofeedback-a3a9d.firebaseapp.com", + databaseURL: "https://biofeedback-a3a9d-default-rtdb.firebaseio.com", + projectId: "biofeedback-a3a9d", + storageBucket: "biofeedback-a3a9d.firebasestorage.app", + messagingSenderId: "954340658821", + appId: "1:954340658821:web:a00254b2676da9d5d3e3ec", +}; + +// Load environment variables with fallbacks +const loadEnvironmentConfig = (): EnvironmentConfig => { + // Check if we're in a browser environment + const isBrowser = typeof window !== "undefined"; + + if (isBrowser) { + console.log("๐ŸŒ Browser environment detected"); + console.log("๐Ÿ” Available environment variables:", { + REACT_APP_FIREBASE_API_KEY: getEnvVar("REACT_APP_FIREBASE_API_KEY") ? "โœ… Set" : "โŒ Missing", + REACT_APP_FIREBASE_AUTH_DOMAIN: getEnvVar("REACT_APP_FIREBASE_AUTH_DOMAIN") ? "โœ… Set" : "โŒ Missing", + REACT_APP_FIREBASE_DATABASE_URL: getEnvVar("REACT_APP_FIREBASE_DATABASE_URL") ? "โœ… Set" : "โŒ Missing", + REACT_APP_FIREBASE_PROJECT_ID: getEnvVar("REACT_APP_FIREBASE_PROJECT_ID") ? "โœ… Set" : "โŒ Missing", + REACT_APP_FIREBASE_STORAGE_BUCKET: getEnvVar("REACT_APP_FIREBASE_STORAGE_BUCKET") ? "โœ… Set" : "โŒ Missing", + REACT_APP_FIREBASE_MESSAGING_SENDER_ID: getEnvVar("REACT_APP_FIREBASE_MESSAGING_SENDER_ID") + ? "โœ… Set" + : "โŒ Missing", + REACT_APP_FIREBASE_APP_ID: getEnvVar("REACT_APP_FIREBASE_APP_ID") ? "โœ… Set" : "โŒ Missing", + }); + } + + // Try to load from environment variables first, fallback to hardcoded values + const config: EnvironmentConfig = { + firebase: { + apiKey: getEnvVar("REACT_APP_FIREBASE_API_KEY") || FALLBACK_FIREBASE_CONFIG.apiKey, + authDomain: getEnvVar("REACT_APP_FIREBASE_AUTH_DOMAIN") || FALLBACK_FIREBASE_CONFIG.authDomain, + databaseURL: getEnvVar("REACT_APP_FIREBASE_DATABASE_URL") || FALLBACK_FIREBASE_CONFIG.databaseURL, + projectId: getEnvVar("REACT_APP_FIREBASE_PROJECT_ID") || FALLBACK_FIREBASE_CONFIG.projectId, + storageBucket: getEnvVar("REACT_APP_FIREBASE_STORAGE_BUCKET") || FALLBACK_FIREBASE_CONFIG.storageBucket, + messagingSenderId: + getEnvVar("REACT_APP_FIREBASE_MESSAGING_SENDER_ID") || FALLBACK_FIREBASE_CONFIG.messagingSenderId, + appId: getEnvVar("REACT_APP_FIREBASE_APP_ID") || FALLBACK_FIREBASE_CONFIG.appId, + }, + app: { + isDevelopment: getEnvVar("NODE_ENV") === "development" || true, // Default to development + isProduction: getEnvVar("NODE_ENV") === "production" || false, + version: getEnvVar("REACT_APP_VERSION") || "1.0.0", + }, + }; + + // Validate required Firebase configuration + const requiredFirebaseFields = ["apiKey", "authDomain", "databaseURL", "projectId"]; + const missingFields = requiredFirebaseFields.filter( + (field) => !config.firebase[field as keyof typeof config.firebase] + ); + + if (missingFields.length > 0) { + console.warn("โš ๏ธ Missing required Firebase environment variables:", missingFields); + console.warn("๐Ÿ’ก Please check your .env file and ensure all required variables are set"); + + // In development, provide helpful debugging info + if (isBrowser) { + console.warn("๐Ÿ”ง Debug: Environment variables not accessible in browser"); + console.warn("๐Ÿ’ก This usually means webpack is not configured to expose them"); + console.warn("๐Ÿ’ก Check if webpack has DefinePlugin configured for environment variables"); + } + } else { + console.log("โœ… All required Firebase environment variables are loaded"); + } + + return config; +}; + +// Export the loaded configuration +export const envConfig = loadEnvironmentConfig(); + +// Export individual Firebase config for direct use +export const firebaseConfig = envConfig.firebase; + +// Export environment helpers +export const isDevelopment = envConfig.app.isDevelopment; +export const isProduction = envConfig.app.isProduction; +export const appVersion = envConfig.app.version; + +// Debug logging in development +if (isDevelopment) { + console.log("๐Ÿ”ง Development environment detected"); + console.log("๐Ÿ“Š Environment config loaded:", { + firebase: { + apiKey: firebaseConfig.apiKey ? `${firebaseConfig.apiKey.substring(0, 10)}...` : "Missing", + authDomain: firebaseConfig.authDomain, + databaseURL: firebaseConfig.databaseURL, + projectId: firebaseConfig.projectId, + }, + app: { + version: appVersion, + environment: getEnvVar("NODE_ENV") || "development", + }, + }); +} From 2b2b36c691b7f43a5ae3e31ce6b9f3a14f060700 Mon Sep 17 00:00:00 2001 From: buddywhitman Date: Thu, 28 Aug 2025 16:31:05 +0530 Subject: [PATCH 2/4] fix: logging values --- Examples/.env | 1 + Examples/FIREBASE_TROUBLESHOOTING.md | 272 + Examples/README_FIREBASE_TROUBLESHOOTING.md | 162 + .../Arduino_Read.cs | 28 + .../Data_logger_to_Unity.ino | 419 + .../Fritzing.jpg | Bin 0 -> 544093 bytes .../LICENSE | 21 + .../README.md | 38 + Examples/ad8232 refs/ad8232 plot.ino | 62 + Examples/esp32/CALIBRATION_README.md | 313 + Examples/esp32/README_FIREBASE.md | 185 - Examples/esp32/calibration_analyzer.py | 433 + Examples/esp32/main.ino | 331 +- Examples/esp32/requirements.txt | 4 + Examples/esp32/sensor_calibration.ino | 370 + Examples/esp32/setup_firebase.py | 134 - Examples/esp32/test_websocket.ino | 538 + Examples/install-firebase.ps1 | 74 + Examples/package-lock.json | 9682 +++++++---- Examples/package.json | 27 +- Examples/setup_firebase.py | 120 + Examples/src/assets/_base.scss | 81 - Examples/src/assets/icons/back.svg | 3 - Examples/src/assets/icons/browser-fill.svg | 3 - Examples/src/assets/icons/close.svg | 4 - Examples/src/assets/icons/codesandbox.svg | 8 - Examples/src/assets/icons/embedded.svg | 3 - Examples/src/assets/icons/example.svg | 9 - Examples/src/assets/icons/fullscreen.svg | 3 - Examples/src/assets/icons/stackblitz.svg | 3 - Examples/src/assets/images/AngularLogo.svg | 3 - Examples/src/assets/images/Chart.png | Bin 11097 -> 0 bytes Examples/src/assets/images/JavaScriptLogo.svg | 3 - Examples/src/assets/images/ReactLogo.svg | 2 - Examples/src/assets/images/VueLogo.svg | 3 - Examples/src/assets/main.scss | 2 - Examples/src/assets/mixins.scss | 34 - Examples/src/components/App.module.scss | 84 - Examples/src/components/App.tsx | 214 - .../AppDetailsRouters/AppDetailsRouter.scss | 610 - .../AppDetailsRouters/AppDetailsRouter.tsx | 276 - .../AppDetailsRouters/CodeActionButton.tsx | 57 - .../AppDetailsRouters/CodeActionButtons.tsx | 135 - .../AppDetailsRouters/ExampleButton.tsx | 43 - .../AppDetailsRouters/ExamplesButtons.tsx | 100 - .../AppDetailsRouters/ExamplesSubtitle.scss | 10 - .../AppDetailsRouters/ExamplesSubtitle.tsx | 22 - .../AppDetailsRouters/FrameworkSelect.tsx | 73 - .../AppDetailsRouters/MarkdownContent.tsx | 26 - .../SourceFilesLoading/SourceFilesContext.ts | 9 - .../components/AppDetailsRouters/constants.ts | 44 - .../components/AppDetailsRouters/markdown.css | 48 - .../AppDetailsRouters/sandboxUtils.ts | 83 - .../src/components/AppDetailsRouters/utils.ts | 36 - .../AppFooter/AppFooter.module.scss | 119 - .../src/components/AppFooter/AppFooter.tsx | 187 - .../AppFooter/CommonFooterStyles.module.scss | 44 - .../AppFooter/FooterGrid.module.scss | 58 - .../src/components/AppFooter/FooterGrid.tsx | 56 - .../AppFooter/GENERATED_FOOTER_LINKS.ts | 120 - .../src/components/AppRouter/AppRouter.tsx | 77 - .../AppRouter/ChartControlWrapper.tsx | 35 - .../src/components/AppRouter/examplePages.ts | 626 - Examples/src/components/AppRouter/examples.ts | 707 - Examples/src/components/AppRouter/pages.ts | 25 - .../src/components/AppTopBar/AppBarTop.tsx | 152 - .../AppTopBar/AppTopBar.module.scss | 171 - Examples/src/components/AppTopBar/npm.svg | 3 - .../Breadcrumbs/ExampleBreadcrumbs.tsx | 130 - .../Breadcrumbs/GenericBreadcrumbs.tsx | 208 - Examples/src/components/Carousel/Carousel.tsx | 9 - .../components/CodePreview/CodePreview.tsx | 530 - .../components/CodePreview/index.module.scss | 106 - .../CodeSandbox/CodeSandbox.module.scss | 77 - .../components/CodeSandbox/CodeSandbox.tsx | 62 - .../src/components/CodeSandbox/DisplayMode.ts | 4 - .../components/CodeSandbox/EditorFrame.tsx | 82 - .../components/CodeSandbox/Loader.module.scss | 30 - .../src/components/CodeSandbox/Loader.tsx | 8 - .../components/CodeSandbox/SandboxPlatform.ts | 19 - .../CodeSandbox/StackblitzEditor.tsx | 90 - .../components/ConfirmDialog.module.scss | 53 - .../CodeSandbox/components/ConfirmDialog.tsx | 33 - .../components/EditorConfirmDialog.tsx | 25 - .../CodeSandbox/components/EditorToolbar.tsx | 69 - .../CodeSandbox/hooks/useEditDetection.ts | 56 - Examples/src/components/CodeSandbox/index.ts | 3 - .../src/components/CodeSandbox/variables.scss | 21 - .../Description/Description.module.scss | 10 - .../components/Description/Description.tsx | 17 - .../src/components/Dialog/Dialog.module.scss | 65 - Examples/src/components/Dialog/Dialog.tsx | 50 - .../DrawerContent/DrawerContent.module.scss | 63 - .../DrawerContent/DrawerContent.tsx | 99 - .../BuilderApi/ChartFromJSON/README.md | 60 - .../BuilderApi/ChartFromJSON/drawExample.ts | 168 - .../BuilderApi/ChartFromJSON/exampleInfo.tsx | 60 - .../BuilderApi/ChartFromJSON/index.tsx | 105 - .../javascript-chart-from-json.jpg | Bin 48639 -> 0 bytes .../Examples/BuilderApi/CustomTypes/README.md | 61 - .../BuilderApi/CustomTypes/angular.ts | 15 - .../BuilderApi/CustomTypes/drawExample.ts | 167 - .../BuilderApi/CustomTypes/exampleInfo.tsx | 63 - .../Examples/BuilderApi/CustomTypes/index.tsx | 11 - .../CustomTypes/javascript-custom-types.jpg | Bin 36743 -> 0 bytes .../BuilderApi/CustomTypes/vanilla.ts | 19 - .../Examples/BuilderApi/FullChart/README.md | 59 - .../BuilderApi/FullChart/drawExample.ts | 175 - .../BuilderApi/FullChart/exampleInfo.tsx | 63 - .../Examples/BuilderApi/FullChart/index.tsx | 9 - .../FullChart/javascript-builder-full.jpg | Bin 26628 -> 0 bytes .../Examples/BuilderApi/FullChart/vanilla.ts | 19 - .../Examples/BuilderApi/SharedData/README.md | 51 - .../BuilderApi/SharedData/drawExample.ts | 87 - .../BuilderApi/SharedData/exampleInfo.tsx | 63 - .../Examples/BuilderApi/SharedData/index.tsx | 9 - .../SharedData/javascript-shared-data.jpg | Bin 32747 -> 0 bytes .../Examples/BuilderApi/SharedData/vanilla.ts | 19 - .../Examples/BuilderApi/SimpleChart/README.md | 59 - .../BuilderApi/SimpleChart/drawExample.ts | 78 - .../BuilderApi/SimpleChart/exampleInfo.tsx | 63 - .../Examples/BuilderApi/SimpleChart/index.tsx | 9 - .../SimpleChart/javascript-builder-simple.jpg | Bin 25577 -> 0 bytes .../BuilderApi/SimpleChart/vanilla.ts | 19 - .../components/Examples/ChartGroupLoader.tsx | 22 - .../Animations/DataAnimation/README.md | 63 - .../Animations/DataAnimation/angular.ts | 15 - .../Animations/DataAnimation/drawExample.ts | 103 - .../Animations/DataAnimation/exampleInfo.tsx | 60 - .../Animations/DataAnimation/index.tsx | 17 - .../javascript-data-animation.jpg | Bin 42681 -> 0 bytes .../Animations/DataAnimation/vanilla.ts | 19 - .../Animations/GenericAnimation/README.md | 52 - .../Animations/GenericAnimation/angular.ts | 15 - .../GenericAnimation/drawExample.ts | 210 - .../GenericAnimation/exampleInfo.tsx | 60 - .../Animations/GenericAnimation/index.tsx | 9 - .../javascript-generic-animation.jpg | Bin 30098 -> 0 bytes .../Animations/GenericAnimation/vanilla.ts | 19 - .../Animations/StartupAnimation/README.md | 59 - .../StartupAnimation/drawExample.ts | 159 - .../StartupAnimation/exampleInfo.tsx | 60 - .../Animations/StartupAnimation/index.tsx | 9 - .../javascript-startup-animations.jpg | Bin 26935 -> 0 bytes .../Animations/StartupAnimation/vanilla.ts | 19 - .../Animations/StyleAnimation/README.md | 59 - .../Animations/StyleAnimation/angular.ts | 15 - .../Animations/StyleAnimation/drawExample.ts | 124 - .../Animations/StyleAnimation/exampleInfo.tsx | 60 - .../Animations/StyleAnimation/index.tsx | 68 - .../javascript-style-animation.jpg | Bin 25956 -> 0 bytes .../ImageLabels/README.md | 58 - .../ImageLabels/angular.ts | 31 - .../ImageLabels/drawExample.ts | 199 - .../ImageLabels/exampleInfo.tsx | 60 - .../ImageLabels/images/Huawei.png | Bin 1780 -> 0 bytes .../ImageLabels/images/Lg.png | Bin 2963 -> 0 bytes .../ImageLabels/images/apple.png | Bin 2107 -> 0 bytes .../ImageLabels/images/google.png | Bin 1684 -> 0 bytes .../ImageLabels/images/infinix.png | Bin 1744 -> 0 bytes .../ImageLabels/images/motorola.png | Bin 61471 -> 0 bytes .../ImageLabels/images/nokia.png | Bin 645 -> 0 bytes .../ImageLabels/images/oneplus.png | Bin 1328 -> 0 bytes .../ImageLabels/images/oppo.png | Bin 951 -> 0 bytes .../ImageLabels/images/question.png | Bin 1037 -> 0 bytes .../ImageLabels/images/realme.png | Bin 1091 -> 0 bytes .../ImageLabels/images/samsung.png | Bin 1736 -> 0 bytes .../ImageLabels/images/tecno.png | Bin 37890 -> 0 bytes .../ImageLabels/images/vivo.png | Bin 784 -> 0 bytes .../ImageLabels/images/xiaomi.png | Bin 477 -> 0 bytes .../ImageLabels/index.tsx | 43 - .../ImageLabels/javascript-image-labels.jpg | Bin 33832 -> 0 bytes .../MultiLineLabels/README.md | 62 - .../MultiLineLabels/drawExample.ts | 149 - .../MultiLineLabels/exampleInfo.tsx | 63 - .../MultiLineLabels/index.tsx | 91 - .../javascript-multiline-labels.jpg | Bin 35955 -> 0 bytes .../RotatedLabels/README.md | 58 - .../RotatedLabels/drawExample.ts | 67 - .../RotatedLabels/exampleInfo.tsx | 60 - .../RotatedLabels/index.tsx | 9 - .../javascript-rotated-labels-chart.jpg | Bin 29290 -> 0 bytes .../RotatedLabels/vanilla.ts | 19 - .../BasicChartTypes/BandSeriesChart/README.md | 62 - .../BandSeriesChart/angular.ts | 15 - .../BandSeriesChart/drawExample.ts | 85 - .../BandSeriesChart/exampleInfo.tsx | 63 - .../BasicChartTypes/BandSeriesChart/index.tsx | 9 - .../BandSeriesChart/javascript-band-chart.jpg | Bin 23037 -> 0 bytes .../BandSeriesChart/vanilla.ts | 19 - .../BasicChartTypes/BubbleChart/README.md | 67 - .../BasicChartTypes/BubbleChart/angular.ts | 15 - .../BubbleChart/drawExample.ts | 113 - .../BubbleChart/exampleInfo.tsx | 63 - .../BasicChartTypes/BubbleChart/index.tsx | 9 - .../BubbleChart/javascript-bubble-chart.jpg | Bin 21161 -> 0 bytes .../BasicChartTypes/BubbleChart/vanilla.ts | 19 - .../CandlestickChart/README.md | 61 - .../CandlestickChart/angular.ts | 15 - .../CandlestickChart/drawExample.ts | 286 - .../CandlestickChart/exampleInfo.tsx | 63 - .../CandlestickChart/index.tsx | 87 - .../javascript-candlestick-chart.jpg | Bin 42484 -> 0 bytes .../BasicChartTypes/ColumnChart/README.md | 63 - .../BasicChartTypes/ColumnChart/angular.ts | 15 - .../ColumnChart/drawExample.ts | 73 - .../ColumnChart/exampleInfo.tsx | 63 - .../BasicChartTypes/ColumnChart/index.tsx | 9 - .../ColumnChart/javascript-column-chart.jpg | Bin 35818 -> 0 bytes .../BasicChartTypes/ColumnChart/vanilla.ts | 19 - .../BasicChartTypes/ContoursChart/README.md | 59 - .../BasicChartTypes/ContoursChart/angular.ts | 15 - .../ContoursChart/drawExample.ts | 154 - .../ContoursChart/exampleInfo.tsx | 63 - .../BasicChartTypes/ContoursChart/index.tsx | 16 - ...javascript-heatmap-chart-with-contours.jpg | Bin 46777 -> 0 bytes .../DigitalBandSeriesChart/README.md | 61 - .../DigitalBandSeriesChart/angular.ts | 15 - .../DigitalBandSeriesChart/drawExample.ts | 66 - .../DigitalBandSeriesChart/exampleInfo.tsx | 63 - .../DigitalBandSeriesChart/index.tsx | 9 - .../javascript-digital-band-chart.jpg | Bin 24889 -> 0 bytes .../DigitalBandSeriesChart/vanilla.ts | 19 - .../DigitalLineChart/README.md | 62 - .../DigitalLineChart/angular.ts | 15 - .../DigitalLineChart/drawExample.ts | 57 - .../DigitalLineChart/exampleInfo.tsx | 63 - .../DigitalLineChart/index.tsx | 9 - .../javascript-digital-line-chart.jpg | Bin 18579 -> 0 bytes .../DigitalLineChart/vanilla.ts | 19 - .../DigitalMountainChart/README.md | 60 - .../DigitalMountainChart/angular.ts | 15 - .../DigitalMountainChart/drawExample.ts | 62 - .../DigitalMountainChart/exampleInfo.tsx | 63 - .../DigitalMountainChart/index.tsx | 9 - .../javascript-digital-mountain-chart.jpg | Bin 28593 -> 0 bytes .../DigitalMountainChart/vanilla.ts | 19 - .../BasicChartTypes/DonutChart/README.md | 62 - .../BasicChartTypes/DonutChart/angular.ts | 15 - .../BasicChartTypes/DonutChart/drawExample.ts | 80 - .../DonutChart/exampleInfo.tsx | 63 - .../BasicChartTypes/DonutChart/index.tsx | 25 - .../DonutChart/javascript-donut-chart.jpg | Bin 19657 -> 0 bytes .../BasicChartTypes/DonutChart/vanilla.ts | 19 - .../BasicChartTypes/ErrorBarsChart/README.md | 64 - .../BasicChartTypes/ErrorBarsChart/angular.ts | 15 - .../ErrorBarsChart/drawExample.ts | 103 - .../ErrorBarsChart/exampleInfo.tsx | 63 - .../BasicChartTypes/ErrorBarsChart/index.tsx | 11 - .../javascript-error-bars-chart.jpg | Bin 22686 -> 0 bytes .../BasicChartTypes/ErrorBarsChart/vanilla.ts | 19 - .../BasicChartTypes/FanChart/angular.ts | 15 - .../BasicChartTypes/FanChart/drawExample.ts | 191 - .../BasicChartTypes/FanChart/exampleInfo.tsx | 63 - .../BasicChartTypes/FanChart/index.tsx | 11 - .../FanChart/javascript-fan-chart.jpg | Bin 18651 -> 0 bytes .../BasicChartTypes/FanChart/vanilla.ts | 19 - .../BasicChartTypes/HeatmapChart/README.md | 70 - .../BasicChartTypes/HeatmapChart/angular.ts | 144 - .../HeatmapChart/drawExample.ts | 197 - .../HeatmapChart/exampleInfo.tsx | 63 - .../BasicChartTypes/HeatmapChart/index.tsx | 90 - .../HeatmapChart/javascript-heatmap-chart.jpg | Bin 38550 -> 0 bytes .../BasicChartTypes/ImpulseChart/README.md | 61 - .../BasicChartTypes/ImpulseChart/angular.ts | 15 - .../ImpulseChart/drawExample.ts | 43 - .../ImpulseChart/exampleInfo.tsx | 63 - .../BasicChartTypes/ImpulseChart/index.tsx | 11 - .../ImpulseChart/javascript-impulse-chart.jpg | Bin 28355 -> 0 bytes .../BasicChartTypes/ImpulseChart/vanilla.ts | 19 - .../BasicChartTypes/LineChart/README.md | 65 - .../BasicChartTypes/LineChart/angular.ts | 83 - .../BasicChartTypes/LineChart/drawExample.ts | 612 - .../BasicChartTypes/LineChart/exampleInfo.tsx | 63 - .../BasicChartTypes/LineChart/index.tsx | 60 - .../LineChart/javascript-line-chart.jpg | Bin 45037 -> 0 bytes .../BasicChartTypes/MountainChart/README.md | 64 - .../BasicChartTypes/MountainChart/angular.ts | 15 - .../MountainChart/drawExample.ts | 63 - .../MountainChart/exampleInfo.tsx | 63 - .../BasicChartTypes/MountainChart/index.tsx | 11 - .../javascript-mountain-chart.jpg | Bin 25595 -> 0 bytes .../BasicChartTypes/MountainChart/vanilla.ts | 19 - .../NonUniformHeatmapChart/README.md | 61 - .../NonUniformHeatmapChart/angular.ts | 15 - .../NonUniformHeatmapChart/drawExample.ts | 90 - .../NonUniformHeatmapChart/exampleInfo.tsx | 63 - .../NonUniformHeatmapChart/index.tsx | 11 - .../javascript-non-uniform-heatmap-chart.jpg | Bin 26736 -> 0 bytes .../NonUniformHeatmapChart/vanilla.ts | 19 - .../BasicChartTypes/OhlcChart/README.md | 62 - .../BasicChartTypes/OhlcChart/angular.ts | 15 - .../BasicChartTypes/OhlcChart/data.ts | 24 - .../BasicChartTypes/OhlcChart/drawExample.ts | 64 - .../BasicChartTypes/OhlcChart/exampleInfo.tsx | 63 - .../BasicChartTypes/OhlcChart/index.tsx | 11 - .../OhlcChart/javascript-ohlc-chart.jpg | Bin 20892 -> 0 bytes .../BasicChartTypes/OhlcChart/vanilla.ts | 19 - .../BasicChartTypes/PieChart/README.md | 64 - .../BasicChartTypes/PieChart/angular.ts | 15 - .../BasicChartTypes/PieChart/drawExample.ts | 91 - .../BasicChartTypes/PieChart/exampleInfo.tsx | 63 - .../BasicChartTypes/PieChart/index.tsx | 26 - .../PieChart/javascript-pie-chart.jpg | Bin 25182 -> 0 bytes .../BasicChartTypes/PieChart/vanilla.ts | 19 - .../RealTimeMountainChart/README.md | 59 - .../RealTimeMountainChart/angular.ts | 26 - .../RealTimeMountainChart/drawExample.ts | 144 - .../RealTimeMountainChart/exampleInfo.tsx | 63 - .../RealTimeMountainChart/index.tsx | 21 - .../javascript-realtime-mountain-chart.jpg | Bin 20642 -> 0 bytes .../BasicChartTypes/ScatterChart/README.md | 62 - .../BasicChartTypes/ScatterChart/angular.ts | 15 - .../ScatterChart/drawExample.ts | 70 - .../ScatterChart/exampleInfo.tsx | 63 - .../BasicChartTypes/ScatterChart/index.tsx | 11 - .../ScatterChart/javascript-scatter-chart.jpg | Bin 31452 -> 0 bytes .../BasicChartTypes/ScatterChart/vanilla.ts | 19 - .../SmoothStackedMountainChart/README.md | 65 - .../SmoothStackedMountainChart/angular.ts | 15 - .../SmoothStackedMountainChart/drawExample.ts | 125 - .../exampleInfo.tsx | 63 - .../SmoothStackedMountainChart/index.tsx | 67 - ...vascript-smooth-stacked-mountain-chart.jpg | Bin 41398 -> 0 bytes .../SplineBandSeriesChart/README.md | 62 - .../SplineBandSeriesChart/angular.ts | 15 - .../SplineBandSeriesChart/drawExample.ts | 165 - .../SplineBandSeriesChart/exampleInfo.tsx | 63 - .../SplineBandSeriesChart/index.tsx | 10 - .../javascript-spline-band-chart.jpg | Bin 39404 -> 0 bytes .../SplineBandSeriesChart/vanilla.ts | 19 - .../BasicChartTypes/SplineLineChart/README.md | 69 - .../SplineLineChart/angular.ts | 15 - .../SplineLineChart/drawExample.ts | 129 - .../SplineLineChart/exampleInfo.tsx | 63 - .../BasicChartTypes/SplineLineChart/index.tsx | 10 - .../javascript-spline-smoothed-line-chart.jpg | Bin 30049 -> 0 bytes .../SplineLineChart/vanilla.ts | 19 - .../SplineMountainChart/README.md | 73 - .../SplineMountainChart/angular.ts | 15 - .../SplineMountainChart/drawExample.ts | 71 - .../SplineMountainChart/exampleInfo.tsx | 63 - .../SplineMountainChart/index.tsx | 11 - .../javascript-spline-mountain-chart.jpg | Bin 22810 -> 0 bytes .../SplineMountainChart/vanilla.ts | 19 - .../StackedColumnChart/README.md | 61 - .../StackedColumnChart/angular.ts | 83 - .../StackedColumnChart/drawExample.ts | 144 - .../StackedColumnChart/exampleInfo.tsx | 63 - .../StackedColumnChart/index.tsx | 97 - .../javascript-stacked-column-chart.jpg | Bin 42795 -> 0 bytes .../StackedColumnSideBySide/README.md | 63 - .../StackedColumnSideBySide/angular.ts | 15 - .../StackedColumnSideBySide/drawExample.ts | 127 - .../StackedColumnSideBySide/exampleInfo.tsx | 63 - .../StackedColumnSideBySide/index.tsx | 11 - ...avascript-stacked-grouped-column-chart.jpg | Bin 41187 -> 0 bytes .../StackedColumnSideBySide/vanilla.ts | 19 - .../StackedMountainChart/README.md | 65 - .../StackedMountainChart/angular.ts | 15 - .../data/stackedMountainChartData.js | 11 - .../data/stackedMountainChartData.ts | 12 - .../StackedMountainChart/drawExample.ts | 83 - .../StackedMountainChart/exampleInfo.tsx | 63 - .../StackedMountainChart/index.tsx | 80 - .../javascript-stacked-mountain-chart.jpg | Bin 39761 -> 0 bytes .../BasicChartTypes/TextSeriesChart/README.md | 65 - .../TextSeriesChart/angular.ts | 15 - .../TextSeriesChart/drawExample.ts | 55 - .../TextSeriesChart/exampleInfo.tsx | 60 - .../BasicChartTypes/TextSeriesChart/index.tsx | 11 - .../TextSeriesChart/javascript-text-chart.jpg | Bin 39479 -> 0 bytes .../TextSeriesChart/vanilla.ts | 19 - .../AnnotationLayers/README.md | 60 - .../AnnotationLayers/angular.ts | 15 - .../AnnotationLayers/drawExample.ts | 177 - .../AnnotationLayers/exampleInfo.tsx | 60 - .../AnnotationLayers/index.tsx | 11 - .../javascript-chart-annotation-layers.jpg | Bin 30308 -> 0 bytes ...exploration_fuel_nasa_rocket_space_icon.ts | 1 - .../AnnotationsAreEasy/README.md | 62 - .../AnnotationsAreEasy/angular.ts | 16 - .../AnnotationsAreEasy/drawExample.ts | 361 - .../AnnotationsAreEasy/exampleInfo.tsx | 63 - .../AnnotationsAreEasy/index.tsx | 12 - .../javascript-chart-annotations.jpg | Bin 34861 -> 0 bytes .../scichart-logo-white.png | Bin 20168 -> 0 bytes .../BackgroundAnnotations/README.md | 62 - .../BackgroundAnnotations/angular.ts | 15 - .../BackgroundAnnotations/data.ts | 1298 -- .../BackgroundAnnotations/drawExample.ts | 255 - .../BackgroundAnnotations/exampleInfo.tsx | 63 - .../BackgroundAnnotations/index.tsx | 11 - .../javascript-background-annotations.jpg | Bin 61310 -> 0 bytes .../BackgroundAnnotations/vanilla.ts | 19 - .../DragHorizontalThreshold/README.md | 60 - .../DragHorizontalThreshold/angular.ts | 15 - .../DragHorizontalThreshold/drawExample.ts | 229 - .../DragHorizontalThreshold/exampleInfo.tsx | 63 - .../DragHorizontalThreshold/index.tsx | 11 - ...script-chart-drag-horizontal-threshold.jpg | Bin 33193 -> 0 bytes .../DragHorizontalThreshold/vanilla.ts | 19 - .../EditableAnnotations/CustomMarkerImage.png | Bin 1966 -> 0 bytes .../EditableAnnotations/README.md | 65 - .../EditableAnnotations/angular.ts | 16 - .../EditableAnnotations/drawExample.ts | 370 - .../EditableAnnotations/exampleInfo.tsx | 63 - .../EditableAnnotations/index.tsx | 11 - .../javascript-chart-editable-annotations.jpg | Bin 53315 -> 0 bytes .../scichart-logo-white.png | Bin 20168 -> 0 bytes .../ChartAnnotations/TradeMarkers/README.md | 61 - .../ChartAnnotations/TradeMarkers/angular.ts | 15 - .../TradeMarkers/drawExample.ts | 334 - .../TradeMarkers/exampleInfo.tsx | 63 - .../ChartAnnotations/TradeMarkers/index.tsx | 11 - ...avascript-stock-chart-buy-sell-markers.jpg | Bin 38763 -> 0 bytes .../ChartAnnotations/TradeMarkers/vanilla.ts | 19 - .../DepthChart/DepthCursorModifier.ts | 408 - .../CreateStockCharts/DepthChart/README.md | 65 - .../CreateStockCharts/DepthChart/angular.ts | 15 - .../DepthChart/drawExample.ts | 160 - .../DepthChart/exampleInfo.tsx | 63 - .../CreateStockCharts/DepthChart/index.tsx | 11 - .../DepthChart/javascript-depth-chart.jpg | Bin 19228 -> 0 bytes .../CreateStockCharts/DepthChart/vanilla.ts | 19 - .../MultiPaneStockCharts/README.md | 66 - .../MultiPaneStockCharts/angular.ts | 87 - .../MultiPaneStockCharts/drawExample.ts | 527 - .../MultiPaneStockCharts/exampleInfo.tsx | 63 - .../MultiPaneStockCharts/index.tsx | 44 - .../javascript-multi-pane-stock-charts.jpg | Bin 39629 -> 0 bytes .../RealtimeTickingStockCharts/README.md | 66 - .../VolumePaletteProvider.ts | 54 - .../binanceSocketClient.ts | 261 - .../createCandlestickChart.ts | 404 - .../exampleInfo.tsx | 66 - .../RealtimeTickingStockCharts/index.tsx | 158 - ...vascript-realtime-ticking-stock-charts.jpg | Bin 44543 -> 0 bytes .../FinChartLegendAnnotation.ts | 194 - .../FinChartLegendModifier.ts | 277 - .../SubChartStockCharts/README.md | 67 - .../SubChartStockCharts/exampleInfo.tsx | 63 - .../SubChartStockCharts/index.tsx | 668 - ...ript-subcharts-multi-pane-stock-charts.jpg | Bin 47784 -> 0 bytes .../CreateLineAnnotationModifier.ts | 88 - .../CreateTradeMarkerModifier.ts | 131 - .../UserAnnotatedStockChart/README.md | 63 - .../UserAnnotatedStockChart/RulerModifier.ts | 216 - .../UserAnnotatedStockChart/angular.ts | 257 - .../UserAnnotatedStockChart/drawExample.ts | 224 - .../UserAnnotatedStockChart/exampleInfo.tsx | 63 - .../UserAnnotatedStockChart/index.tsx | 193 - .../javascript-user-annotated-stock-chart.jpg | Bin 34610 -> 0 bytes .../Charts2D/Filters/CustomFilters/README.md | 59 - .../Charts2D/Filters/CustomFilters/angular.ts | 34 - .../Filters/CustomFilters/drawExample.ts | 222 - .../Filters/CustomFilters/exampleInfo.tsx | 63 - .../Charts2D/Filters/CustomFilters/index.tsx | 22 - .../javascript-custom-filters.jpg | Bin 60340 -> 0 bytes .../Filters/PercentageChange/README.md | 57 - .../Filters/PercentageChange/drawExample.ts | 155 - .../Filters/PercentageChange/exampleInfo.tsx | 63 - .../Filters/PercentageChange/index.tsx | 66 - .../javascript-percentage-change.jpg | Bin 39173 -> 0 bytes .../Charts2D/Filters/TrendMARatio/README.md | 59 - .../Charts2D/Filters/TrendMARatio/angular.ts | 15 - .../Filters/TrendMARatio/drawExample.ts | 164 - .../Filters/TrendMARatio/exampleInfo.tsx | 60 - .../Charts2D/Filters/TrendMARatio/index.tsx | 11 - .../javascript-trend-ma-ratio.jpg | Bin 43330 -> 0 bytes .../Charts2D/Filters/TrendMARatio/vanilla.ts | 19 - .../Legends/ChartLegendsAPI/README.md | 59 - .../Legends/ChartLegendsAPI/drawExample.ts | 102 - .../Legends/ChartLegendsAPI/exampleInfo.tsx | 63 - .../Legends/ChartLegendsAPI/index.tsx | 158 - .../javascript-chart-legends.jpg | Bin 33707 -> 0 bytes .../ModifyAxisBehavior/CentralAxes/README.md | 68 - .../ModifyAxisBehavior/CentralAxes/angular.ts | 15 - .../CentralAxes/drawExample.ts | 133 - .../CentralAxes/exampleInfo.tsx | 63 - .../ModifyAxisBehavior/CentralAxes/index.tsx | 11 - .../CentralAxes/javascript-central-axes.jpg | Bin 47965 -> 0 bytes .../ModifyAxisBehavior/CentralAxes/vanilla.ts | 19 - .../DrawBehindAxes/README.md | 62 - .../DrawBehindAxes/angular.ts | 15 - .../DrawBehindAxes/drawExample.ts | 94 - .../DrawBehindAxes/exampleInfo.tsx | 63 - .../DrawBehindAxes/index.tsx | 54 - .../javascript-draw-behind-axes.jpg | Bin 30508 -> 0 bytes .../LogarithmicAxis/README.md | 63 - .../LogarithmicAxis/angular.ts | 15 - .../LogarithmicAxis/drawExample.ts | 155 - .../LogarithmicAxis/exampleInfo.tsx | 63 - .../LogarithmicAxis/index.tsx | 122 - .../javascript-chart-logarithmic-axis.jpg | Bin 68574 -> 0 bytes .../MultipleXAxes/README.md | 58 - .../MultipleXAxes/drawExample.ts | 207 - .../MultipleXAxes/exampleInfo.tsx | 63 - .../MultipleXAxes/index.tsx | 11 - .../javascript-chart-with-multiple-x-axis.jpg | Bin 48517 -> 0 bytes .../MultipleXAxes/vanilla.ts | 19 - .../SecondaryYAxes/README.md | 61 - .../SecondaryYAxes/angular.ts | 15 - .../SecondaryYAxes/drawExample.ts | 190 - .../SecondaryYAxes/exampleInfo.tsx | 63 - .../SecondaryYAxes/index.tsx | 11 - ...javascript-chart-with-secondary-y-axis.jpg | Bin 45547 -> 0 bytes .../SecondaryYAxes/vanilla.ts | 19 - .../ModifyAxisBehavior/StaticAxis/README.md | 58 - .../StaticAxis/drawExample.ts | 107 - .../StaticAxis/exampleInfo.tsx | 60 - .../ModifyAxisBehavior/StaticAxis/index.tsx | 68 - .../StaticAxis/javascript-static-axis.jpg | Bin 39854 -> 0 bytes .../VerticalCharts/README.md | 61 - .../VerticalCharts/angular.ts | 15 - .../VerticalCharts/drawExample.ts | 92 - .../VerticalCharts/exampleInfo.tsx | 63 - .../VerticalCharts/index.tsx | 11 - .../javascript-vertical-charts.jpg | Bin 35885 -> 0 bytes .../VerticalCharts/vanilla.ts | 19 - .../VerticallyStackedAxes/README.md | 61 - .../VerticallyStackedAxes/angular.ts | 15 - .../VerticallyStackedAxes/drawExample.ts | 114 - .../VerticallyStackedAxes/exampleInfo.tsx | 63 - .../VerticallyStackedAxes/index.tsx | 11 - .../javascript-vertically-stacked-axes.jpg | Bin 56074 -> 0 bytes .../VerticallyStackedAxes/vanilla.ts | 19 - .../MultiChart/SyncMultiChart/README.md | 59 - .../MultiChart/SyncMultiChart/exampleInfo.tsx | 65 - .../MultiChart/SyncMultiChart/index.tsx | 384 - .../javascript-sync-multi-chart.jpg | Bin 48119 -> 0 bytes .../CreateACustomTheme/README.md | 65 - .../CreateACustomTheme/angular.ts | 15 - .../CreateACustomTheme/data.ts | 22 - .../CreateACustomTheme/drawExample.ts | 128 - .../CreateACustomTheme/exampleInfo.tsx | 63 - .../CreateACustomTheme/index.tsx | 11 - .../javascript-chart-custom-themed.jpg | Bin 43849 -> 0 bytes .../CreateACustomTheme/vanilla.ts | 19 - .../DashedLineStyling/README.md | 67 - .../DashedLineStyling/angular.ts | 15 - .../DashedLineStyling/drawExample.ts | 119 - .../DashedLineStyling/exampleInfo.tsx | 60 - .../DashedLineStyling/index.tsx | 11 - .../javascript-dashed-line-chart.jpg | Bin 24166 -> 0 bytes .../DashedLineStyling/vanilla.ts | 19 - .../StylingAndTheming/DataLabels/README.md | 66 - .../StylingAndTheming/DataLabels/angular.ts | 15 - .../DataLabels/drawExample.ts | 168 - .../DataLabels/exampleInfo.tsx | 56 - .../StylingAndTheming/DataLabels/index.tsx | 11 - .../javascript-datalabels-chart.jpg | Bin 50804 -> 0 bytes .../StylingAndTheming/DataLabels/vanilla.ts | 19 - .../LineSplittingThresholds/README.md | 61 - .../LineSplittingThresholds/drawExample.ts | 277 - .../LineSplittingThresholds/exampleInfo.tsx | 63 - .../LineSplittingThresholds/index.tsx | 9 - ...script-chart-line-splitting-thresholds.jpg | Bin 70196 -> 0 bytes .../MultiStyleSeries/README.md | 64 - .../MultiStyleSeries/drawExample.ts | 248 - .../MultiStyleSeries/exampleInfo.tsx | 63 - .../MultiStyleSeries/index.tsx | 11 - .../javascript-chart-multi-style-series.jpg | Bin 74786 -> 0 bytes .../PerPointColoring/README.md | 72 - .../PerPointColoring/angular.ts | 15 - .../PerPointColoring/drawExample.ts | 202 - .../PerPointColoring/exampleInfo.tsx | 63 - .../PerPointColoring/index.tsx | 11 - ...ints-individually-with-paletteprovider.jpg | Bin 32878 -> 0 bytes .../PerPointColoring/vanilla.ts | 19 - .../StylingAndTheming/StylingInCode/README.md | 61 - .../StylingInCode/angular.ts | 15 - .../StylingInCode/drawExample.ts | 194 - .../StylingInCode/exampleInfo.tsx | 63 - .../StylingAndTheming/StylingInCode/index.tsx | 11 - ...vascript-chart-styling-theming-in-code.jpg | Bin 56446 -> 0 bytes .../StylingInCode/vanilla.ts | 19 - .../BackgroundGradient.jpg | Bin 100288 -> 0 bytes .../TransparentBackground/README.md | 59 - .../TransparentBackground/drawExample.ts | 124 - .../TransparentBackground/exampleInfo.tsx | 63 - .../TransparentBackground/index.tsx | 15 - ...avascript-chart-transparent-background.jpg | Bin 71007 -> 0 bytes .../UsePointMarkers/README.md | 54 - .../UsePointMarkers/angular.ts | 14 - .../UsePointMarkers/drawExample.ts | 153 - .../UsePointMarkers/exampleInfo.tsx | 63 - .../UsePointMarkers/img/CustomMarkerImage.png | Bin 1966 -> 0 bytes .../UsePointMarkers/index.tsx | 12 - .../javascript-chart-custom-pointmarkers.jpg | Bin 48517 -> 0 bytes .../UsingThemeManager/README.md | 61 - .../UsingThemeManager/data.ts | 22 - .../UsingThemeManager/drawExample.ts | 141 - .../UsingThemeManager/exampleInfo.tsx | 62 - .../UsingThemeManager/index.html | 28 - .../UsingThemeManager/index.tsx | 41 - .../javascript-chart-themes.jpg | Bin 53766 -> 0 bytes .../UsingThemeManager/vanilla.ts | 30 - .../DatapointSelection/README.md | 59 - .../DatapointSelection/drawExample.ts | 182 - .../DatapointSelection/exampleInfo.tsx | 63 - .../DatapointSelection/index.tsx | 88 - .../javascript-datapoint-selection.jpg | Bin 53663 -> 0 bytes .../TooltipsAndHittest/HitTestAPI/README.md | 56 - .../HitTestAPI/drawExample.ts | 153 - .../HitTestAPI/exampleInfo.tsx | 63 - .../TooltipsAndHittest/HitTestAPI/index.tsx | 70 - .../javascript-chart-hit-test-on-click.jpg | Bin 27406 -> 0 bytes .../HitTestAPI/visualizeHitTest.ts | 121 - .../TooltipsAndHittest/MetaData/README.md | 68 - .../MetaData/drawExample.ts | 176 - .../MetaData/exampleInfo.tsx | 63 - .../TooltipsAndHittest/MetaData/index.tsx | 11 - .../MetaData/javascript-chart-metadata.jpg | Bin 30725 -> 0 bytes .../TooltipsAndHittest/MetaData/vanilla.ts | 19 - .../SeriesSelection/README.md | 59 - .../SeriesSelection/drawExample.ts | 177 - .../SeriesSelection/exampleInfo.tsx | 63 - .../SeriesSelection/index.tsx | 11 - .../javascript-chart-series-selection.jpg | Bin 44015 -> 0 bytes .../SeriesSelection/vanilla.ts | 19 - .../UsingCursorModifierTooltips/README.md | 67 - .../UsingCursorModifierTooltips/angular.ts | 15 - .../drawExample.ts | 147 - .../exampleInfo.tsx | 63 - .../UsingCursorModifierTooltips/index.tsx | 11 - ...script-chart-cursormodifier-crosshairs.jpg | Bin 33932 -> 0 bytes .../UsingCursorModifierTooltips/vanilla.ts | 19 - .../UsingRolloverModifierTooltips/README.md | 62 - .../UsingRolloverModifierTooltips/angular.ts | 15 - .../drawExample.ts | 165 - .../exampleInfo.tsx | 63 - .../UsingRolloverModifierTooltips/index.tsx | 11 - ...script-chart-rollovermodifier-tooltips.jpg | Bin 33076 -> 0 bytes .../UsingRolloverModifierTooltips/vanilla.ts | 19 - .../UsingVerticalSliceModifier/README.md | 67 - .../UsingVerticalSliceModifier/angular.ts | 15 - .../UsingVerticalSliceModifier/drawExample.ts | 213 - .../exampleInfo.tsx | 63 - .../UsingVerticalSliceModifier/index.tsx | 11 - ...vascript-chart-vertical-slice-modifier.jpg | Bin 54725 -> 0 bytes .../UsingVerticalSliceModifier/vanilla.ts | 19 - .../DragAxisToScale/README.md | 59 - .../DragAxisToScale/angular.ts | 15 - ...s-on-javascript-charts-to-scale-or-pan.jpg | Bin 36165 -> 0 bytes .../DragAxisToScale/drawExample.ts | 120 - .../DragAxisToScale/exampleInfo.tsx | 63 - .../DragAxisToScale/index.tsx | 11 - .../DragAxisToScale/vanilla.ts | 19 - .../MultipleZoomPanModifiers/README.md | 74 - .../MultipleZoomPanModifiers/angular.ts | 15 - .../MultipleZoomPanModifiers/drawExample.ts | 164 - .../MultipleZoomPanModifiers/exampleInfo.tsx | 63 - .../MultipleZoomPanModifiers/index.tsx | 11 - .../MultipleZoomPanModifiers/vanilla.ts | 19 - .../zoom-pan-multiple-modifiers.jpg | Bin 39325 -> 0 bytes .../OverviewModifier/README.md | 63 - .../OverviewModifier/drawExample.ts | 100 - .../OverviewModifier/exampleInfo.tsx | 60 - .../OverviewModifier/index.tsx | 30 - .../javascript-overview-chart.jpg | Bin 31589 -> 0 bytes .../RealtimeZoomPan/README.md | 68 - .../RealtimeZoomPan/angular.ts | 15 - .../RealtimeZoomPan/drawExample.ts | 97 - .../RealtimeZoomPan/exampleInfo.tsx | 63 - .../RealtimeZoomPan/index.tsx | 22 - .../RealtimeZoomPan/vanilla.ts | 19 - ...om-and-pan-a-realtime-javascript-chart.jpg | Bin 59172 -> 0 bytes .../VirtualizedDataWithOverview/README.md | 61 - .../drawExample.ts | 169 - .../exampleInfo.tsx | 65 - .../VirtualizedDataWithOverview/index.tsx | 29 - .../virtualized-data-javascript-chart.jpg | Bin 30319 -> 0 bytes .../Basic3DChartTypes/Bubble3DChart/README.md | 63 - .../Bubble3DChart/angular.ts | 15 - .../Bubble3DChart/drawExample.ts | 106 - .../Bubble3DChart/exampleInfo.tsx | 63 - .../Basic3DChartTypes/Bubble3DChart/index.tsx | 11 - .../javascript-3d-bubble-chart.jpg | Bin 37586 -> 0 bytes .../Bubble3DChart/vanilla.ts | 19 - .../Basic3DChartTypes/Column3DChart/README.md | 59 - .../Column3DChart/drawExample.ts | 158 - .../Column3DChart/exampleInfo.tsx | 63 - .../Basic3DChartTypes/Column3DChart/index.tsx | 147 - .../javascript-3d-column-chart.jpg | Bin 101265 -> 0 bytes .../PointLine3DChart/README.md | 60 - .../PointLine3DChart/angular.ts | 40 - .../PointLine3DChart/drawExample.ts | 198 - .../PointLine3DChart/exampleInfo.tsx | 63 - .../PointLine3DChart/index.tsx | 18 - .../javascript-3d-point-line-chart.jpg | Bin 32168 -> 0 bytes .../RealtimeSurfaceMesh3DChart/README.md | 60 - .../RealtimeSurfaceMesh3DChart/angular.ts | 15 - .../RealtimeSurfaceMesh3DChart/drawExample.ts | 126 - .../exampleInfo.tsx | 63 - .../RealtimeSurfaceMesh3DChart/index.tsx | 28 - ...ascript-realtime-3d-surface-mesh-chart.jpg | Bin 37949 -> 0 bytes .../SurfaceMesh3DChart/README.md | 62 - .../SurfaceMesh3DChart/angular.ts | 15 - .../SurfaceMesh3DChart/drawExample.ts | 156 - .../SurfaceMesh3DChart/exampleInfo.tsx | 63 - .../SurfaceMesh3DChart/index.tsx | 20 - .../javascript-3d-surface-mesh-chart.jpg | Bin 28329 -> 0 bytes .../ExampleData/ExampleDataProvider.ts | 316 - .../ExampleData/RandomWalkGenerator.ts | 39 - .../Examples/ExampleData/binanceRestClient.ts | 75 - .../Examples/ExampleRootDetails.tsx | 52 - .../src/components/Examples/ExampleStrings.ts | 794 +- .../src/components/Examples/ExamplesRoot.tsx | 183 - .../FeatureDemos/AxisLayout/README.md | 62 - .../FeatureDemos/AxisLayout/angular.ts | 15 - .../FeatureDemos/AxisLayout/drawExample.ts | 220 - .../FeatureDemos/AxisLayout/exampleInfo.tsx | 63 - .../FeatureDemos/AxisLayout/index.tsx | 11 - .../AxisLayout/javascript-axis-layout.jpg | Bin 49036 -> 0 bytes .../FeatureDemos/AxisLayout/vanilla.ts | 19 - .../FeatureDemos/AxisTypes/README.md | 62 - .../FeatureDemos/AxisTypes/drawExample.ts | 173 - .../FeatureDemos/AxisTypes/exampleInfo.tsx | 63 - .../FeatureDemos/AxisTypes/index.tsx | 11 - .../AxisTypes/javascript-axis-types.jpg | Bin 42159 -> 0 bytes .../FeatureDemos/ChartTitle/README.md | 65 - .../FeatureDemos/ChartTitle/exampleInfo.tsx | 60 - .../FeatureDemos/ChartTitle/index.tsx | 271 - .../ChartTitle/javascript-chart-title.jpg | Bin 33891 -> 0 bytes .../FeatureDemos/SubChartsAPI/README.md | 60 - .../FeatureDemos/SubChartsAPI/drawExample.ts | 357 - .../FeatureDemos/SubChartsAPI/exampleInfo.tsx | 63 - .../FeatureDemos/SubChartsAPI/helpers.ts | 324 - .../FeatureDemos/SubChartsAPI/index.tsx | 97 - .../javascript-subcharts-grid.jpg | Bin 78014 -> 0 bytes .../VitalSignsMonitorDemo/drawExample.ts | 171 +- .../VitalSignsMonitorDemo/ecgProcessor.ts | 514 + .../VitalSignsMonitorDemo/firebaseLogger.ts | 92 +- .../VitalSignsMonitorDemo/index.tsx | 2623 ++- .../VitalSignsMonitorDemo/sessionRecorder.ts | 44 +- .../VitalSignsMonitorDemo/signalProcessor.ts | 54 +- .../Load1MillionPoints/README.md | 63 - .../Load1MillionPoints/angular.ts | 147 - .../Load1MillionPoints/drawExample.ts | 176 - .../Load1MillionPoints/exampleInfo.tsx | 63 - .../Load1MillionPoints/index.tsx | 110 - ...rt-performance-load-one-million-points.jpg | Bin 36932 -> 0 bytes .../PerformanceDemos/Load500By500/README.md | 73 - .../PerformanceDemos/Load500By500/angular.ts | 131 - .../Load500By500/drawExample.ts | 212 - .../Load500By500/exampleInfo.tsx | 63 - .../PerformanceDemos/Load500By500/index.tsx | 126 - ...pt-chart-load-500-series-by-500-points.jpg | Bin 65117 -> 0 bytes .../RealtimeGhostedTraces/README.md | 56 - .../RealtimeGhostedTraces/angular.ts | 15 - .../RealtimeGhostedTraces/drawExample.ts | 133 - .../RealtimeGhostedTraces/exampleInfo.tsx | 63 - .../RealtimeGhostedTraces/index.tsx | 86 - ...time-ghosted-traces-oscilloscope-chart.jpg | Bin 149660 -> 0 bytes .../RealtimePerformanceDemo/README.md | 61 - .../RealtimePerformanceDemo/angular.ts | 102 - .../RealtimePerformanceDemo/drawExample.ts | 141 - .../RealtimePerformanceDemo/exampleInfo.tsx | 63 - .../RealtimePerformanceDemo/index.tsx | 72 - ...script-chart-realtime-performance-demo.jpg | Bin 137935 -> 0 bytes .../RealtimePerformanceDemo/vanilla.ts | 22 - .../AudioAnalyzer/AudioData.ts | 11 - .../AudioAnalyzer/AudioDataProvider.ts | 115 - .../ScientificCharts/AudioAnalyzer/README.md | 61 - .../AudioAnalyzer/Radix2FFT.ts | 164 - .../ScientificCharts/AudioAnalyzer/angular.ts | 91 - .../AudioAnalyzer/drawExample.ts | 342 - .../AudioAnalyzer/exampleInfo.tsx | 67 - .../ScientificCharts/AudioAnalyzer/index.tsx | 41 - .../javascript-audio-analyzer-fft-example.jpg | Bin 52322 -> 0 bytes .../InteractiveWaterfallChart/README.md | 61 - .../InteractiveWaterfallChart/angular.ts | 67 - .../InteractiveWaterfallChart/drawExample.ts | 412 - .../InteractiveWaterfallChart/exampleInfo.tsx | 63 - .../InteractiveWaterfallChart/index.tsx | 34 - ...javascript-interactive-waterfall-chart.jpg | Bin 101554 -> 0 bytes .../LiDAR3DPointCloudDemo/AscReader.ts | 115 - .../LiDAR3DPointCloudDemo/README.md | 68 - .../LiDAR3DPointCloudDemo/angular.ts | 42 - .../LiDAR3DPointCloudDemo/drawExample.ts | 210 - .../LiDAR3DPointCloudDemo/exampleInfo.tsx | 63 - .../LiDAR3DPointCloudDemo/index.tsx | 19 - .../javascript-3d-lidar-visualization.jpg | Bin 43088 -> 0 bytes .../ScientificCharts/TenorCurves3D/README.md | 60 - .../TenorCurves3D/TenorCurveData.ts | 58 - .../ScientificCharts/TenorCurves3D/angular.ts | 56 - .../TenorCurves3D/drawExample.ts | 243 - .../TenorCurves3D/exampleInfo.tsx | 63 - .../ScientificCharts/TenorCurves3D/index.tsx | 30 - ...cript-2d-3d-chart-tenor-curves-example.jpg | Bin 50449 -> 0 bytes .../DynamicLayout/GridLayoutModifier.ts | 170 - .../ShowCases/DynamicLayout/README.md | 62 - .../ShowCases/DynamicLayout/exampleInfo.tsx | 63 - .../ShowCases/DynamicLayout/index.tsx | 112 - .../javascript-dynamic-layout.jpg | Bin 52704 -> 0 bytes .../ShowCases/EventMarkers/README.md | 62 - .../ShowCases/EventMarkers/angular.ts | 15 - .../ShowCases/EventMarkers/drawExample.ts | 300 - .../ShowCases/EventMarkers/exampleInfo.tsx | 63 - .../ShowCases/EventMarkers/index.tsx | 11 - .../javascript-draggable-event-markers.jpg | Bin 32480 -> 0 bytes .../ShowCases/EventMarkers/vanilla.ts | 19 - .../HeatmapInteractions/AddIOModifier.ts | 117 - .../HeatmapInteractions/DiscreteAxisMarker.ts | 26 - .../HeatmapInteractions/PointDragModifier.ts | 109 - .../ShowCases/HeatmapInteractions/README.md | 72 - .../ShowCases/HeatmapInteractions/angular.ts | 170 - .../HeatmapInteractions/drawExample.ts | 900 - .../HeatmapInteractions/exampleInfo.tsx | 63 - .../ShowCases/HeatmapInteractions/index.tsx | 106 - .../javascript-heatmap-interactions.jpg | Bin 60325 -> 0 bytes .../OilAndGasDashboard/Data/Density.csv | 1000 -- .../OilAndGasDashboard/Data/PoreSpace.csv | 1001 -- .../OilAndGasDashboard/Data/Resistivity.csv | 1000 -- .../OilAndGasDashboard/Data/Shale.csv | 1000 -- .../OilAndGasDashboard/Data/Sonic.csv | 100 - .../OilAndGasDashboard/Data/Texture.csv | 101 - .../OilAndGasDashboard/OIlGasStyles.css | 234 - .../ShowCases/OilAndGasDashboard/README.md | 62 - .../charts/2dcharts/eighth.ts | 150 - .../charts/2dcharts/fifth.ts | 82 - .../charts/2dcharts/first.ts | 90 - .../charts/2dcharts/fourth.ts | 130 - .../charts/2dcharts/ninth.ts | 83 - .../charts/2dcharts/second.ts | 204 - .../charts/2dcharts/seventh.ts | 194 - .../charts/2dcharts/sixth.ts | 150 - .../charts/2dcharts/third.ts | 194 - .../ShowCases/OilAndGasDashboard/charts/3d.ts | 108 - .../charts/VerticalCharts/DensityChart.ts | 86 - .../charts/VerticalCharts/PoreSpaceChart.ts | 132 - .../RangeFillPaletteProvider.ts | 47 - .../charts/VerticalCharts/ResistivityChart.ts | 94 - .../charts/VerticalCharts/ShaleChart.ts | 155 - .../charts/VerticalCharts/SonicChart.ts | 123 - .../charts/VerticalCharts/TextureChart.ts | 112 - .../OilAndGasDashboard/charts/chartUtils.ts | 171 - .../ShowCases/OilAndGasDashboard/charts/dt.ts | 38 - .../ShowCases/OilAndGasDashboard/charts/gr.ts | 99 - .../OilAndGasDashboard/charts/lld.ts | 37 - .../OilAndGasDashboard/charts/nphi.ts | 35 - .../OilAndGasDashboard/charts/rhdb.ts | 40 - .../OilAndGasDashboard/charts/vChartUtils.ts | 87 - .../OilAndGasDashboard/charts/vsh.ts | 88 - .../OilAndGasDashboard/exampleInfo.tsx | 60 - .../ShowCases/OilAndGasDashboard/index.html | 385 - .../ShowCases/OilAndGasDashboard/index.tsx | 169 - .../indexVerticalCharts.html | 110 - ...ript-oil-gas-explorer-dashboard-charts.jpg | Bin 58820 -> 0 bytes .../ShowCases/OilAndGasDashboard/theme.ts | 295 - .../ShowCases/PopulationPyramid/README.md | 61 - .../ShowCases/PopulationPyramid/angular.ts | 15 - .../PopulationPyramid/drawExample.ts | 299 - .../PopulationPyramid/exampleInfo.tsx | 61 - .../ShowCases/PopulationPyramid/index.tsx | 11 - .../javascript-population-pyramid.jpg | Bin 59796 -> 0 bytes .../ShowCases/PopulationPyramid/vanilla.ts | 19 - .../GridLayoutModifier.ts | 428 - .../ServerTrafficDashboard/ModifierGroup.ts | 151 - .../ServerTrafficDashboard/Overview.tsx | 41 - .../ServerTrafficDashboard/README.md | 69 - .../ThresholdSlider.tsx | 72 - .../VisibleRangeSynchronizationManager.ts | 46 - .../after-all-charts-init.ts | 86 - .../chart-configurations.ts | 15 - .../ServerTrafficDashboard/chart-types.ts | 19 - .../ServerTrafficDashboard/data-generation.ts | 128 - .../ServerTrafficDashboard/exampleInfo.tsx | 66 - .../ServerTrafficDashboard/index.html | 15 - .../ServerTrafficDashboard/index.tsx | 304 - .../javascript-server-traffic-dashboard.jpg | Bin 51592 -> 0 bytes .../main-chart-config.ts | 276 - .../page-statistics-chart-config.ts | 206 - .../region-statistic-charts.ts | 342 - .../server-load-chart-config.ts | 258 - .../ShowCases/WebsocketBigData/README.md | 68 - .../ShowCases/WebsocketBigData/angular.ts | 197 - .../ShowCases/WebsocketBigData/drawExample.ts | 577 - .../WebsocketBigData/exampleInfo.tsx | 63 - .../ShowCases/WebsocketBigData/index.tsx | 398 - .../javascript-streaming-data.jpg | Bin 48436 -> 0 bytes .../components/Examples/IExampleMetadata.ts | 33 - .../components/Examples/TBinanceCandleData.ts | 4 +- Examples/src/components/Examples/Toolbar.tsx | 163 - .../components/Examples/containerSizeHooks.ts | 42 - .../src/components/Examples/exampleImages.ts | 8 +- .../components/Examples/exampleInfoUtils.ts | 73 - .../Examples/styles/Examples.module.scss | 188 +- .../src/components/Examples/styles/scss.d.ts | 4 + .../components/Gallery/Gallery.module.scss | 153 - Examples/src/components/Gallery/Gallery.tsx | 37 - .../src/components/Gallery/GalleryCard.tsx | 32 - .../Gallery/GalleryList/GalleryList.tsx | 81 - .../src/components/GalleryItems/index.scss | 268 - .../src/components/GalleryItems/index.tsx | 253 - .../GettingStarted/GettingStarted.tsx | 21 - .../components/Navigation/AnchorTagRouter.tsx | 95 - .../CommonListItemStyles.module.scss | 86 - .../Navigation/ListItemCollapseArrowIcon.tsx | 15 - .../Navigation/ListItemsBlock.module.scss | 72 - .../components/Navigation/ListItemsBlock.tsx | 161 - .../Navigation/Navigation.module.scss | 15 - .../src/components/Navigation/Navigation.tsx | 80 - Examples/src/components/PageHome/Anim.css | 89 - .../components/PageHome/PageHome.module.scss | 262 - Examples/src/components/PageHome/PageHome.tsx | 44 - .../SciChartNavbar/SciChartNavbar.tsx | 804 - .../src/components/SciChartNavbar/styles.css | 264 - .../src/components/Search/Search.module.scss | 31 - Examples/src/components/Search/Search.tsx | 79 - Examples/src/components/Search/searchItems.ts | 27 - .../src/components/SeoTags/NoIndexTag.tsx | 12 - Examples/src/components/SeoTags/SeoTags.tsx | 39 - .../SourceCode/SourceCode.module.scss | 1 - .../src/components/SourceCode/SourceCode.tsx | 40 - Examples/src/components/Title/Title.tsx | 26 - .../components/buttons/ButtonBar.module.scss | 158 - Examples/src/components/buttons/ButtonBar.tsx | 99 - Examples/src/components/buttons/Icon.tsx | 51 - .../components/buttons/IconButton.module.scss | 78 - .../src/components/buttons/IconButton.tsx | 55 - .../buttons/IconRadioGroup.module.scss | 20 - .../components/buttons/IconRadioGroup.scss | 20 - .../src/components/buttons/IconRadioGroup.tsx | 35 - .../components/buttons/Toolbar.module.scss | 58 - Examples/src/components/buttons/Toolbar.tsx | 29 - .../components/buttons/Tooltip.module.scss | 210 - Examples/src/components/buttons/Tooltip.tsx | 85 - Examples/src/components/buttons/svgIcons.ts | 54 - .../src/components/buttons/tooltipUtils.ts | 33 - .../src/components/buttons/variables.scss | 68 - Examples/src/components/index.scss | 155 - Examples/src/constants.ts | 3 - Examples/src/helpers/SciChartExamples.ts | 64 - .../hooks/useIsomorphicLayoutEffect.ts | 2 - .../src/helpers/shared/Helpers/Box/Box.tsx | 25 - .../shared/Helpers/FrameworkContext.ts | 4 - .../Helpers/frameworkParametrization.ts | 101 - .../MenuListItemText/MenuListItemText.tsx | 13 - .../helpers/types/ExampleDescriptionTypes.ts | 11 - Examples/src/helpers/types/types.ts | 47 - Examples/src/index.tsx | 55 +- .../src/server/BinanceData/candlesADAUSDT.js | 113 - .../src/server/BinanceData/candlesBTCUSDT.js | 132 - .../src/server/BinanceData/candlesDOGEUSDT.js | 96 - .../src/server/BinanceData/candlesETHUSDT.js | 123 - .../src/server/BinanceData/candlesXRPUSDT.js | 113 - Examples/src/server/Data/multiPaneData.ts | 1484 -- Examples/src/server/Data/populationData.ts | 13712 ---------------- Examples/src/server/Data/tq3080_DSM_2M.asc | 506 - Examples/src/server/Data/tq3080_DSM_2M.js | 507 - Examples/src/server/Data/tweetData.js | 246 - Examples/src/server/Errors.ts | 15 - Examples/src/server/api.ts | 111 - .../server/middlewares/loggingMiddleware.ts | 33 - .../src/server/renderCodeSandboxRedirect.ts | 839 - Examples/src/server/renderIndexHtml.ts | 99 - Examples/src/server/routes/MainRouter.ts | 96 - .../src/server/routes/exportExampleInfo.ts | 46 - Examples/src/server/routes/oembed.ts | 41 - Examples/src/server/routes/variants.ts | 29 - Examples/src/server/server.tsx | 50 - Examples/src/server/services/logging.ts | 47 - .../src/server/services/pageRender/index.ts | 39 - .../server/services/pageRender/reactSsr.tsx | 46 - .../server/services/sandbox/angularConfig.ts | 304 - .../src/server/services/sandbox/constants.ts | 2 - Examples/src/server/services/sandbox/index.ts | 60 - .../server/services/sandbox/reactConfig.ts | 117 - .../sandbox/sandboxDependencyUtils.ts | 234 - .../services/sandbox/vanillaTsConfig.ts | 168 - .../services/stackblitz/getStackblitzFiles.ts | 138 - .../src/server/types/TBinanceQueryParams.ts | 6 - Examples/src/server/vanillaDemo/common.js | 11 - .../vanillaDemo/vanillaExampleHtmlTemplate.ts | 64 - .../vanillaDemo/vanillaExamplesRouter.ts | 97 - Examples/src/server/websockets.ts | 94 - Examples/src/static/no_server.index.html | 2 +- Examples/src/utils/googleTagManager.ts | 10 - Examples/src/utils/routeUtils.ts | 21 - Examples/start-dev.bat | 9 + Examples/start-dev.ps1 | 24 + Examples/test-env.js | 0 Examples/test_firebase.js | 0 Examples/test_websocket.html | 246 + Examples/vitals-monitoring | 1 + Examples/webpack.client.config.js | 9 +- Examples/webpack.client.no_server.config.ts | 119 +- Examples/webpack.server.config.js | 5 + 990 files changed, 12775 insertions(+), 94041 deletions(-) create mode 100644 Examples/FIREBASE_TROUBLESHOOTING.md create mode 100644 Examples/README_FIREBASE_TROUBLESHOOTING.md create mode 100644 Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Arduino_Read.cs create mode 100644 Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Data_logger_to_Unity.ino create mode 100644 Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Fritzing.jpg create mode 100644 Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/LICENSE create mode 100644 Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/README.md create mode 100644 Examples/ad8232 refs/ad8232 plot.ino create mode 100644 Examples/esp32/CALIBRATION_README.md delete mode 100644 Examples/esp32/README_FIREBASE.md create mode 100644 Examples/esp32/calibration_analyzer.py create mode 100644 Examples/esp32/requirements.txt create mode 100644 Examples/esp32/sensor_calibration.ino delete mode 100644 Examples/esp32/setup_firebase.py create mode 100644 Examples/esp32/test_websocket.ino create mode 100644 Examples/install-firebase.ps1 create mode 100644 Examples/setup_firebase.py delete mode 100644 Examples/src/assets/_base.scss delete mode 100644 Examples/src/assets/icons/back.svg delete mode 100644 Examples/src/assets/icons/browser-fill.svg delete mode 100644 Examples/src/assets/icons/close.svg delete mode 100644 Examples/src/assets/icons/codesandbox.svg delete mode 100644 Examples/src/assets/icons/embedded.svg delete mode 100644 Examples/src/assets/icons/example.svg delete mode 100644 Examples/src/assets/icons/fullscreen.svg delete mode 100644 Examples/src/assets/icons/stackblitz.svg delete mode 100644 Examples/src/assets/images/AngularLogo.svg delete mode 100644 Examples/src/assets/images/Chart.png delete mode 100644 Examples/src/assets/images/JavaScriptLogo.svg delete mode 100644 Examples/src/assets/images/ReactLogo.svg delete mode 100644 Examples/src/assets/images/VueLogo.svg delete mode 100644 Examples/src/assets/main.scss delete mode 100644 Examples/src/assets/mixins.scss delete mode 100644 Examples/src/components/App.module.scss delete mode 100644 Examples/src/components/App.tsx delete mode 100644 Examples/src/components/AppDetailsRouters/AppDetailsRouter.scss delete mode 100644 Examples/src/components/AppDetailsRouters/AppDetailsRouter.tsx delete mode 100644 Examples/src/components/AppDetailsRouters/CodeActionButton.tsx delete mode 100644 Examples/src/components/AppDetailsRouters/CodeActionButtons.tsx delete mode 100644 Examples/src/components/AppDetailsRouters/ExampleButton.tsx delete mode 100644 Examples/src/components/AppDetailsRouters/ExamplesButtons.tsx delete mode 100644 Examples/src/components/AppDetailsRouters/ExamplesSubtitle.scss delete mode 100644 Examples/src/components/AppDetailsRouters/ExamplesSubtitle.tsx delete mode 100644 Examples/src/components/AppDetailsRouters/FrameworkSelect.tsx delete mode 100644 Examples/src/components/AppDetailsRouters/MarkdownContent.tsx delete mode 100644 Examples/src/components/AppDetailsRouters/SourceFilesLoading/SourceFilesContext.ts delete mode 100644 Examples/src/components/AppDetailsRouters/constants.ts delete mode 100644 Examples/src/components/AppDetailsRouters/markdown.css delete mode 100644 Examples/src/components/AppDetailsRouters/sandboxUtils.ts delete mode 100644 Examples/src/components/AppDetailsRouters/utils.ts delete mode 100644 Examples/src/components/AppFooter/AppFooter.module.scss delete mode 100644 Examples/src/components/AppFooter/AppFooter.tsx delete mode 100644 Examples/src/components/AppFooter/CommonFooterStyles.module.scss delete mode 100644 Examples/src/components/AppFooter/FooterGrid.module.scss delete mode 100644 Examples/src/components/AppFooter/FooterGrid.tsx delete mode 100644 Examples/src/components/AppFooter/GENERATED_FOOTER_LINKS.ts delete mode 100644 Examples/src/components/AppRouter/AppRouter.tsx delete mode 100644 Examples/src/components/AppRouter/ChartControlWrapper.tsx delete mode 100644 Examples/src/components/AppRouter/examplePages.ts delete mode 100644 Examples/src/components/AppRouter/examples.ts delete mode 100644 Examples/src/components/AppRouter/pages.ts delete mode 100644 Examples/src/components/AppTopBar/AppBarTop.tsx delete mode 100644 Examples/src/components/AppTopBar/AppTopBar.module.scss delete mode 100644 Examples/src/components/AppTopBar/npm.svg delete mode 100644 Examples/src/components/Breadcrumbs/ExampleBreadcrumbs.tsx delete mode 100644 Examples/src/components/Breadcrumbs/GenericBreadcrumbs.tsx delete mode 100644 Examples/src/components/Carousel/Carousel.tsx delete mode 100644 Examples/src/components/CodePreview/CodePreview.tsx delete mode 100644 Examples/src/components/CodePreview/index.module.scss delete mode 100644 Examples/src/components/CodeSandbox/CodeSandbox.module.scss delete mode 100644 Examples/src/components/CodeSandbox/CodeSandbox.tsx delete mode 100644 Examples/src/components/CodeSandbox/DisplayMode.ts delete mode 100644 Examples/src/components/CodeSandbox/EditorFrame.tsx delete mode 100644 Examples/src/components/CodeSandbox/Loader.module.scss delete mode 100644 Examples/src/components/CodeSandbox/Loader.tsx delete mode 100644 Examples/src/components/CodeSandbox/SandboxPlatform.ts delete mode 100644 Examples/src/components/CodeSandbox/StackblitzEditor.tsx delete mode 100644 Examples/src/components/CodeSandbox/components/ConfirmDialog.module.scss delete mode 100644 Examples/src/components/CodeSandbox/components/ConfirmDialog.tsx delete mode 100644 Examples/src/components/CodeSandbox/components/EditorConfirmDialog.tsx delete mode 100644 Examples/src/components/CodeSandbox/components/EditorToolbar.tsx delete mode 100644 Examples/src/components/CodeSandbox/hooks/useEditDetection.ts delete mode 100644 Examples/src/components/CodeSandbox/index.ts delete mode 100644 Examples/src/components/CodeSandbox/variables.scss delete mode 100644 Examples/src/components/Description/Description.module.scss delete mode 100644 Examples/src/components/Description/Description.tsx delete mode 100644 Examples/src/components/Dialog/Dialog.module.scss delete mode 100644 Examples/src/components/Dialog/Dialog.tsx delete mode 100644 Examples/src/components/DrawerContent/DrawerContent.module.scss delete mode 100644 Examples/src/components/DrawerContent/DrawerContent.tsx delete mode 100644 Examples/src/components/Examples/BuilderApi/ChartFromJSON/README.md delete mode 100644 Examples/src/components/Examples/BuilderApi/ChartFromJSON/drawExample.ts delete mode 100644 Examples/src/components/Examples/BuilderApi/ChartFromJSON/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/BuilderApi/ChartFromJSON/index.tsx delete mode 100644 Examples/src/components/Examples/BuilderApi/ChartFromJSON/javascript-chart-from-json.jpg delete mode 100644 Examples/src/components/Examples/BuilderApi/CustomTypes/README.md delete mode 100644 Examples/src/components/Examples/BuilderApi/CustomTypes/angular.ts delete mode 100644 Examples/src/components/Examples/BuilderApi/CustomTypes/drawExample.ts delete mode 100644 Examples/src/components/Examples/BuilderApi/CustomTypes/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/BuilderApi/CustomTypes/index.tsx delete mode 100644 Examples/src/components/Examples/BuilderApi/CustomTypes/javascript-custom-types.jpg delete mode 100644 Examples/src/components/Examples/BuilderApi/CustomTypes/vanilla.ts delete mode 100644 Examples/src/components/Examples/BuilderApi/FullChart/README.md delete mode 100644 Examples/src/components/Examples/BuilderApi/FullChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/BuilderApi/FullChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/BuilderApi/FullChart/index.tsx delete mode 100644 Examples/src/components/Examples/BuilderApi/FullChart/javascript-builder-full.jpg delete mode 100644 Examples/src/components/Examples/BuilderApi/FullChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/BuilderApi/SharedData/README.md delete mode 100644 Examples/src/components/Examples/BuilderApi/SharedData/drawExample.ts delete mode 100644 Examples/src/components/Examples/BuilderApi/SharedData/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/BuilderApi/SharedData/index.tsx delete mode 100644 Examples/src/components/Examples/BuilderApi/SharedData/javascript-shared-data.jpg delete mode 100644 Examples/src/components/Examples/BuilderApi/SharedData/vanilla.ts delete mode 100644 Examples/src/components/Examples/BuilderApi/SimpleChart/README.md delete mode 100644 Examples/src/components/Examples/BuilderApi/SimpleChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/BuilderApi/SimpleChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/BuilderApi/SimpleChart/index.tsx delete mode 100644 Examples/src/components/Examples/BuilderApi/SimpleChart/javascript-builder-simple.jpg delete mode 100644 Examples/src/components/Examples/BuilderApi/SimpleChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/ChartGroupLoader.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/DataAnimation/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/DataAnimation/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/DataAnimation/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/DataAnimation/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/DataAnimation/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/DataAnimation/javascript-data-animation.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/DataAnimation/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/GenericAnimation/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/GenericAnimation/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/GenericAnimation/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/GenericAnimation/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/GenericAnimation/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/GenericAnimation/javascript-generic-animation.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/GenericAnimation/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/StartupAnimation/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/StartupAnimation/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/StartupAnimation/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/StartupAnimation/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/StartupAnimation/javascript-startup-animations.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/StartupAnimation/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/StyleAnimation/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/StyleAnimation/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/StyleAnimation/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/StyleAnimation/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/StyleAnimation/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Animations/StyleAnimation/javascript-style-animation.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/Huawei.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/Lg.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/apple.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/google.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/infinix.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/motorola.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/nokia.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/oneplus.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/oppo.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/question.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/realme.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/samsung.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/tecno.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/vivo.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/images/xiaomi.png delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/ImageLabels/javascript-image-labels.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/MultiLineLabels/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/MultiLineLabels/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/MultiLineLabels/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/MultiLineLabels/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/MultiLineLabels/javascript-multiline-labels.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/RotatedLabels/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/RotatedLabels/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/RotatedLabels/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/RotatedLabels/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/RotatedLabels/javascript-rotated-labels-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/AxisLabelCustomization/RotatedLabels/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BandSeriesChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BandSeriesChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BandSeriesChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BandSeriesChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BandSeriesChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BandSeriesChart/javascript-band-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BandSeriesChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BubbleChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BubbleChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BubbleChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BubbleChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BubbleChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BubbleChart/javascript-bubble-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/BubbleChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/CandlestickChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/CandlestickChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/CandlestickChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/CandlestickChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/CandlestickChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/CandlestickChart/javascript-candlestick-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ColumnChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ColumnChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ColumnChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ColumnChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ColumnChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ColumnChart/javascript-column-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ColumnChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ContoursChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ContoursChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ContoursChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ContoursChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ContoursChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ContoursChart/javascript-heatmap-chart-with-contours.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalBandSeriesChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalBandSeriesChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalBandSeriesChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalBandSeriesChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalBandSeriesChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalBandSeriesChart/javascript-digital-band-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalBandSeriesChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalLineChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalLineChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalLineChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalLineChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalLineChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalLineChart/javascript-digital-line-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalLineChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalMountainChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalMountainChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalMountainChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalMountainChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalMountainChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalMountainChart/javascript-digital-mountain-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DigitalMountainChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DonutChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DonutChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DonutChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DonutChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DonutChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DonutChart/javascript-donut-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/DonutChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ErrorBarsChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ErrorBarsChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ErrorBarsChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ErrorBarsChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ErrorBarsChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ErrorBarsChart/javascript-error-bars-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ErrorBarsChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/FanChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/FanChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/FanChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/FanChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/FanChart/javascript-fan-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/FanChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/HeatmapChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/HeatmapChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/HeatmapChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/HeatmapChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/HeatmapChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/HeatmapChart/javascript-heatmap-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ImpulseChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ImpulseChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ImpulseChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ImpulseChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ImpulseChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ImpulseChart/javascript-impulse-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ImpulseChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/LineChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/LineChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/LineChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/LineChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/LineChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/LineChart/javascript-line-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/MountainChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/MountainChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/MountainChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/MountainChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/MountainChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/MountainChart/javascript-mountain-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/MountainChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/NonUniformHeatmapChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/NonUniformHeatmapChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/NonUniformHeatmapChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/NonUniformHeatmapChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/NonUniformHeatmapChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/NonUniformHeatmapChart/javascript-non-uniform-heatmap-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/NonUniformHeatmapChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/OhlcChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/OhlcChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/OhlcChart/data.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/OhlcChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/OhlcChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/OhlcChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/OhlcChart/javascript-ohlc-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/OhlcChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/PieChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/PieChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/PieChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/PieChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/PieChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/PieChart/javascript-pie-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/PieChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/RealTimeMountainChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/RealTimeMountainChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/RealTimeMountainChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/RealTimeMountainChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/RealTimeMountainChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/RealTimeMountainChart/javascript-realtime-mountain-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ScatterChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ScatterChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ScatterChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ScatterChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ScatterChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ScatterChart/javascript-scatter-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/ScatterChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SmoothStackedMountainChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SmoothStackedMountainChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SmoothStackedMountainChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SmoothStackedMountainChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SmoothStackedMountainChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SmoothStackedMountainChart/javascript-smooth-stacked-mountain-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineBandSeriesChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineBandSeriesChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineBandSeriesChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineBandSeriesChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineBandSeriesChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineBandSeriesChart/javascript-spline-band-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineBandSeriesChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineLineChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineLineChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineLineChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineLineChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineLineChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineLineChart/javascript-spline-smoothed-line-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineLineChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineMountainChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineMountainChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineMountainChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineMountainChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineMountainChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineMountainChart/javascript-spline-mountain-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/SplineMountainChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnChart/javascript-stacked-column-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnSideBySide/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnSideBySide/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnSideBySide/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnSideBySide/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnSideBySide/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnSideBySide/javascript-stacked-grouped-column-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedColumnSideBySide/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedMountainChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedMountainChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedMountainChart/data/stackedMountainChartData.js delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedMountainChart/data/stackedMountainChartData.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedMountainChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedMountainChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedMountainChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/StackedMountainChart/javascript-stacked-mountain-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/TextSeriesChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/TextSeriesChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/TextSeriesChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/TextSeriesChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/TextSeriesChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/TextSeriesChart/javascript-text-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/BasicChartTypes/TextSeriesChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationLayers/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationLayers/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationLayers/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationLayers/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationLayers/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationLayers/javascript-chart-annotation-layers.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationsAreEasy/416398_exploration_fuel_nasa_rocket_space_icon.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationsAreEasy/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationsAreEasy/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationsAreEasy/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationsAreEasy/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationsAreEasy/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationsAreEasy/javascript-chart-annotations.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/AnnotationsAreEasy/scichart-logo-white.png delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/BackgroundAnnotations/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/BackgroundAnnotations/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/BackgroundAnnotations/data.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/BackgroundAnnotations/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/BackgroundAnnotations/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/BackgroundAnnotations/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/BackgroundAnnotations/javascript-background-annotations.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/BackgroundAnnotations/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/DragHorizontalThreshold/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/DragHorizontalThreshold/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/DragHorizontalThreshold/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/DragHorizontalThreshold/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/DragHorizontalThreshold/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/DragHorizontalThreshold/javascript-chart-drag-horizontal-threshold.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/DragHorizontalThreshold/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/EditableAnnotations/CustomMarkerImage.png delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/EditableAnnotations/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/EditableAnnotations/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/EditableAnnotations/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/EditableAnnotations/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/EditableAnnotations/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/EditableAnnotations/javascript-chart-editable-annotations.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/EditableAnnotations/scichart-logo-white.png delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/TradeMarkers/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/TradeMarkers/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/TradeMarkers/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/TradeMarkers/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/TradeMarkers/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/TradeMarkers/javascript-stock-chart-buy-sell-markers.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ChartAnnotations/TradeMarkers/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/DepthChart/DepthCursorModifier.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/DepthChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/DepthChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/DepthChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/DepthChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/DepthChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/DepthChart/javascript-depth-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/DepthChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/MultiPaneStockCharts/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/MultiPaneStockCharts/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/MultiPaneStockCharts/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/MultiPaneStockCharts/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/MultiPaneStockCharts/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/MultiPaneStockCharts/javascript-multi-pane-stock-charts.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/RealtimeTickingStockCharts/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/RealtimeTickingStockCharts/VolumePaletteProvider.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/RealtimeTickingStockCharts/binanceSocketClient.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/RealtimeTickingStockCharts/createCandlestickChart.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/RealtimeTickingStockCharts/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/RealtimeTickingStockCharts/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/RealtimeTickingStockCharts/javascript-realtime-ticking-stock-charts.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/SubChartStockCharts/FinChartLegendAnnotation.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/SubChartStockCharts/FinChartLegendModifier.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/SubChartStockCharts/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/SubChartStockCharts/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/SubChartStockCharts/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/SubChartStockCharts/javascript-subcharts-multi-pane-stock-charts.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/UserAnnotatedStockChart/CreateLineAnnotationModifier.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/UserAnnotatedStockChart/CreateTradeMarkerModifier.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/UserAnnotatedStockChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/UserAnnotatedStockChart/RulerModifier.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/UserAnnotatedStockChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/UserAnnotatedStockChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/UserAnnotatedStockChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/UserAnnotatedStockChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/CreateStockCharts/UserAnnotatedStockChart/javascript-user-annotated-stock-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/CustomFilters/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/CustomFilters/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/CustomFilters/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/CustomFilters/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/CustomFilters/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/CustomFilters/javascript-custom-filters.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/PercentageChange/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/PercentageChange/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/PercentageChange/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/PercentageChange/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/PercentageChange/javascript-percentage-change.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/TrendMARatio/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/TrendMARatio/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/TrendMARatio/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/TrendMARatio/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/TrendMARatio/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/TrendMARatio/javascript-trend-ma-ratio.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/Filters/TrendMARatio/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Legends/ChartLegendsAPI/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/Legends/ChartLegendsAPI/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/Legends/ChartLegendsAPI/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Legends/ChartLegendsAPI/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/Legends/ChartLegendsAPI/javascript-chart-legends.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/CentralAxes/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/CentralAxes/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/CentralAxes/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/CentralAxes/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/CentralAxes/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/CentralAxes/javascript-central-axes.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/CentralAxes/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/DrawBehindAxes/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/DrawBehindAxes/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/DrawBehindAxes/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/DrawBehindAxes/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/DrawBehindAxes/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/DrawBehindAxes/javascript-draw-behind-axes.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/LogarithmicAxis/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/LogarithmicAxis/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/LogarithmicAxis/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/LogarithmicAxis/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/LogarithmicAxis/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/LogarithmicAxis/javascript-chart-logarithmic-axis.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/MultipleXAxes/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/MultipleXAxes/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/MultipleXAxes/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/MultipleXAxes/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/MultipleXAxes/javascript-chart-with-multiple-x-axis.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/MultipleXAxes/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SecondaryYAxes/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SecondaryYAxes/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SecondaryYAxes/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SecondaryYAxes/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SecondaryYAxes/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SecondaryYAxes/javascript-chart-with-secondary-y-axis.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/SecondaryYAxes/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/StaticAxis/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/StaticAxis/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/StaticAxis/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/StaticAxis/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/StaticAxis/javascript-static-axis.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticalCharts/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticalCharts/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticalCharts/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticalCharts/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticalCharts/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticalCharts/javascript-vertical-charts.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticalCharts/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticallyStackedAxes/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticallyStackedAxes/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticallyStackedAxes/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticallyStackedAxes/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticallyStackedAxes/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticallyStackedAxes/javascript-vertically-stacked-axes.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ModifyAxisBehavior/VerticallyStackedAxes/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/MultiChart/SyncMultiChart/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/MultiChart/SyncMultiChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/MultiChart/SyncMultiChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/MultiChart/SyncMultiChart/javascript-sync-multi-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/CreateACustomTheme/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/CreateACustomTheme/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/CreateACustomTheme/data.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/CreateACustomTheme/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/CreateACustomTheme/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/CreateACustomTheme/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/CreateACustomTheme/javascript-chart-custom-themed.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/CreateACustomTheme/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DashedLineStyling/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DashedLineStyling/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DashedLineStyling/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DashedLineStyling/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DashedLineStyling/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DashedLineStyling/javascript-dashed-line-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DashedLineStyling/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DataLabels/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DataLabels/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DataLabels/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DataLabels/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DataLabels/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DataLabels/javascript-datalabels-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/DataLabels/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/LineSplittingThresholds/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/LineSplittingThresholds/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/LineSplittingThresholds/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/LineSplittingThresholds/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/LineSplittingThresholds/javascript-chart-line-splitting-thresholds.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/MultiStyleSeries/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/MultiStyleSeries/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/MultiStyleSeries/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/MultiStyleSeries/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/MultiStyleSeries/javascript-chart-multi-style-series.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/PerPointColoring/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/PerPointColoring/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/PerPointColoring/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/PerPointColoring/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/PerPointColoring/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/PerPointColoring/javascript-chart-color-points-individually-with-paletteprovider.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/PerPointColoring/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/StylingInCode/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/StylingInCode/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/StylingInCode/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/StylingInCode/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/StylingInCode/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/StylingInCode/javascript-chart-styling-theming-in-code.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/StylingInCode/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/TransparentBackground/BackgroundGradient.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/TransparentBackground/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/TransparentBackground/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/TransparentBackground/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/TransparentBackground/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/TransparentBackground/javascript-chart-transparent-background.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsePointMarkers/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsePointMarkers/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsePointMarkers/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsePointMarkers/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsePointMarkers/img/CustomMarkerImage.png delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsePointMarkers/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsePointMarkers/javascript-chart-custom-pointmarkers.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsingThemeManager/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsingThemeManager/data.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsingThemeManager/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsingThemeManager/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsingThemeManager/index.html delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsingThemeManager/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsingThemeManager/javascript-chart-themes.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/StylingAndTheming/UsingThemeManager/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/DatapointSelection/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/DatapointSelection/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/DatapointSelection/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/DatapointSelection/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/DatapointSelection/javascript-datapoint-selection.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/HitTestAPI/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/HitTestAPI/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/HitTestAPI/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/HitTestAPI/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/HitTestAPI/javascript-chart-hit-test-on-click.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/HitTestAPI/visualizeHitTest.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/MetaData/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/MetaData/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/MetaData/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/MetaData/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/MetaData/javascript-chart-metadata.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/MetaData/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/SeriesSelection/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/SeriesSelection/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/SeriesSelection/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/SeriesSelection/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/SeriesSelection/javascript-chart-series-selection.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/SeriesSelection/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingCursorModifierTooltips/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingCursorModifierTooltips/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingCursorModifierTooltips/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingCursorModifierTooltips/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingCursorModifierTooltips/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingCursorModifierTooltips/javascript-chart-cursormodifier-crosshairs.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingCursorModifierTooltips/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingRolloverModifierTooltips/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingRolloverModifierTooltips/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingRolloverModifierTooltips/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingRolloverModifierTooltips/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingRolloverModifierTooltips/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingRolloverModifierTooltips/javascript-chart-rollovermodifier-tooltips.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingRolloverModifierTooltips/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingVerticalSliceModifier/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingVerticalSliceModifier/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingVerticalSliceModifier/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingVerticalSliceModifier/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingVerticalSliceModifier/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingVerticalSliceModifier/javascript-chart-vertical-slice-modifier.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/TooltipsAndHittest/UsingVerticalSliceModifier/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/DragAxisToScale/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/DragAxisToScale/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/DragAxisToScale/drag-axis-on-javascript-charts-to-scale-or-pan.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/DragAxisToScale/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/DragAxisToScale/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/DragAxisToScale/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/DragAxisToScale/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/MultipleZoomPanModifiers/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/MultipleZoomPanModifiers/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/MultipleZoomPanModifiers/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/MultipleZoomPanModifiers/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/MultipleZoomPanModifiers/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/MultipleZoomPanModifiers/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/MultipleZoomPanModifiers/zoom-pan-multiple-modifiers.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/OverviewModifier/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/OverviewModifier/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/OverviewModifier/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/OverviewModifier/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/OverviewModifier/javascript-overview-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/RealtimeZoomPan/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/RealtimeZoomPan/angular.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/RealtimeZoomPan/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/RealtimeZoomPan/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/RealtimeZoomPan/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/RealtimeZoomPan/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/RealtimeZoomPan/zoom-and-pan-a-realtime-javascript-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/VirtualizedDataWithOverview/README.md delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/VirtualizedDataWithOverview/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/VirtualizedDataWithOverview/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/VirtualizedDataWithOverview/index.tsx delete mode 100644 Examples/src/components/Examples/Charts2D/ZoomingAndPanning/VirtualizedDataWithOverview/virtualized-data-javascript-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/Bubble3DChart/README.md delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/Bubble3DChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/Bubble3DChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/Bubble3DChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/Bubble3DChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/Bubble3DChart/javascript-3d-bubble-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/Bubble3DChart/vanilla.ts delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/Column3DChart/README.md delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/Column3DChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/Column3DChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/Column3DChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/Column3DChart/javascript-3d-column-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/PointLine3DChart/README.md delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/PointLine3DChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/PointLine3DChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/PointLine3DChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/PointLine3DChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/PointLine3DChart/javascript-3d-point-line-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/RealtimeSurfaceMesh3DChart/README.md delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/RealtimeSurfaceMesh3DChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/RealtimeSurfaceMesh3DChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/RealtimeSurfaceMesh3DChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/RealtimeSurfaceMesh3DChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/RealtimeSurfaceMesh3DChart/javascript-realtime-3d-surface-mesh-chart.jpg delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/SurfaceMesh3DChart/README.md delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/SurfaceMesh3DChart/angular.ts delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/SurfaceMesh3DChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/SurfaceMesh3DChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/SurfaceMesh3DChart/index.tsx delete mode 100644 Examples/src/components/Examples/Charts3D/Basic3DChartTypes/SurfaceMesh3DChart/javascript-3d-surface-mesh-chart.jpg delete mode 100644 Examples/src/components/Examples/ExampleData/ExampleDataProvider.ts delete mode 100644 Examples/src/components/Examples/ExampleData/RandomWalkGenerator.ts delete mode 100644 Examples/src/components/Examples/ExampleData/binanceRestClient.ts delete mode 100644 Examples/src/components/Examples/ExampleRootDetails.tsx delete mode 100644 Examples/src/components/Examples/ExamplesRoot.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/AxisLayout/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/AxisLayout/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/AxisLayout/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/AxisLayout/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/AxisLayout/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/AxisLayout/javascript-axis-layout.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/AxisLayout/vanilla.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/AxisTypes/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/AxisTypes/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/AxisTypes/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/AxisTypes/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/AxisTypes/javascript-axis-types.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/ChartTitle/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/ChartTitle/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/ChartTitle/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/ChartTitle/javascript-chart-title.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/SubChartsAPI/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/SubChartsAPI/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/SubChartsAPI/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/SubChartsAPI/helpers.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/SubChartsAPI/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/FeatureDemos/SubChartsAPI/javascript-subcharts-grid.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/Load1MillionPoints/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/Load1MillionPoints/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/Load1MillionPoints/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/Load1MillionPoints/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/Load1MillionPoints/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/Load1MillionPoints/javascript-chart-performance-load-one-million-points.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/Load500By500/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/Load500By500/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/Load500By500/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/Load500By500/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/Load500By500/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/Load500By500/javascript-chart-load-500-series-by-500-points.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimeGhostedTraces/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimeGhostedTraces/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimeGhostedTraces/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimeGhostedTraces/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimeGhostedTraces/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimeGhostedTraces/javascript-realtime-ghosted-traces-oscilloscope-chart.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimePerformanceDemo/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimePerformanceDemo/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimePerformanceDemo/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimePerformanceDemo/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimePerformanceDemo/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimePerformanceDemo/javascript-chart-realtime-performance-demo.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/PerformanceDemos/RealtimePerformanceDemo/vanilla.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/AudioAnalyzer/AudioData.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/AudioAnalyzer/AudioDataProvider.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/AudioAnalyzer/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/AudioAnalyzer/Radix2FFT.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/AudioAnalyzer/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/AudioAnalyzer/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/AudioAnalyzer/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/AudioAnalyzer/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/AudioAnalyzer/javascript-audio-analyzer-fft-example.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/InteractiveWaterfallChart/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/InteractiveWaterfallChart/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/InteractiveWaterfallChart/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/InteractiveWaterfallChart/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/InteractiveWaterfallChart/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/InteractiveWaterfallChart/javascript-interactive-waterfall-chart.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/LiDAR3DPointCloudDemo/AscReader.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/LiDAR3DPointCloudDemo/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/LiDAR3DPointCloudDemo/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/LiDAR3DPointCloudDemo/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/LiDAR3DPointCloudDemo/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/LiDAR3DPointCloudDemo/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/LiDAR3DPointCloudDemo/javascript-3d-lidar-visualization.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/TenorCurves3D/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/TenorCurves3D/TenorCurveData.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/TenorCurves3D/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/TenorCurves3D/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/TenorCurves3D/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/TenorCurves3D/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ScientificCharts/TenorCurves3D/javascript-2d-3d-chart-tenor-curves-example.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/DynamicLayout/GridLayoutModifier.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/DynamicLayout/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/DynamicLayout/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/DynamicLayout/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/DynamicLayout/javascript-dynamic-layout.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/EventMarkers/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/EventMarkers/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/EventMarkers/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/EventMarkers/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/EventMarkers/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/EventMarkers/javascript-draggable-event-markers.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/EventMarkers/vanilla.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/HeatmapInteractions/AddIOModifier.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/HeatmapInteractions/DiscreteAxisMarker.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/HeatmapInteractions/PointDragModifier.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/HeatmapInteractions/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/HeatmapInteractions/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/HeatmapInteractions/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/HeatmapInteractions/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/HeatmapInteractions/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/HeatmapInteractions/javascript-heatmap-interactions.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Density.csv delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/PoreSpace.csv delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Resistivity.csv delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Shale.csv delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Sonic.csv delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Texture.csv delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/OIlGasStyles.css delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/2dcharts/eighth.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/2dcharts/fifth.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/2dcharts/first.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/2dcharts/fourth.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/2dcharts/ninth.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/2dcharts/second.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/2dcharts/seventh.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/2dcharts/sixth.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/2dcharts/third.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/3d.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/VerticalCharts/DensityChart.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/VerticalCharts/PoreSpaceChart.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/VerticalCharts/RangeFillPaletteProvider.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/VerticalCharts/ResistivityChart.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/VerticalCharts/ShaleChart.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/VerticalCharts/SonicChart.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/VerticalCharts/TextureChart.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/chartUtils.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/dt.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/gr.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/lld.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/nphi.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/rhdb.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/vChartUtils.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/charts/vsh.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/index.html delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/indexVerticalCharts.html delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/javascript-oil-gas-explorer-dashboard-charts.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/theme.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/PopulationPyramid/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/PopulationPyramid/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/PopulationPyramid/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/PopulationPyramid/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/PopulationPyramid/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/PopulationPyramid/javascript-population-pyramid.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/PopulationPyramid/vanilla.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/GridLayoutModifier.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/ModifierGroup.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/Overview.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/ThresholdSlider.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/VisibleRangeSynchronizationManager.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/after-all-charts-init.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/chart-configurations.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/chart-types.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/data-generation.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/index.html delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/javascript-server-traffic-dashboard.jpg delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/main-chart-config.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/page-statistics-chart-config.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/region-statistic-charts.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/server-load-chart-config.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/WebsocketBigData/README.md delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/WebsocketBigData/angular.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/WebsocketBigData/drawExample.ts delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/WebsocketBigData/exampleInfo.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/WebsocketBigData/index.tsx delete mode 100644 Examples/src/components/Examples/FeaturedApps/ShowCases/WebsocketBigData/javascript-streaming-data.jpg delete mode 100644 Examples/src/components/Examples/IExampleMetadata.ts delete mode 100644 Examples/src/components/Examples/Toolbar.tsx delete mode 100644 Examples/src/components/Examples/containerSizeHooks.ts delete mode 100644 Examples/src/components/Examples/exampleInfoUtils.ts create mode 100644 Examples/src/components/Examples/styles/scss.d.ts delete mode 100644 Examples/src/components/Gallery/Gallery.module.scss delete mode 100644 Examples/src/components/Gallery/Gallery.tsx delete mode 100644 Examples/src/components/Gallery/GalleryCard.tsx delete mode 100644 Examples/src/components/Gallery/GalleryList/GalleryList.tsx delete mode 100644 Examples/src/components/GalleryItems/index.scss delete mode 100644 Examples/src/components/GalleryItems/index.tsx delete mode 100644 Examples/src/components/GettingStarted/GettingStarted.tsx delete mode 100644 Examples/src/components/Navigation/AnchorTagRouter.tsx delete mode 100644 Examples/src/components/Navigation/CommonListItemStyles.module.scss delete mode 100644 Examples/src/components/Navigation/ListItemCollapseArrowIcon.tsx delete mode 100644 Examples/src/components/Navigation/ListItemsBlock.module.scss delete mode 100644 Examples/src/components/Navigation/ListItemsBlock.tsx delete mode 100644 Examples/src/components/Navigation/Navigation.module.scss delete mode 100644 Examples/src/components/Navigation/Navigation.tsx delete mode 100644 Examples/src/components/PageHome/Anim.css delete mode 100644 Examples/src/components/PageHome/PageHome.module.scss delete mode 100644 Examples/src/components/PageHome/PageHome.tsx delete mode 100644 Examples/src/components/SciChartNavbar/SciChartNavbar.tsx delete mode 100644 Examples/src/components/SciChartNavbar/styles.css delete mode 100644 Examples/src/components/Search/Search.module.scss delete mode 100644 Examples/src/components/Search/Search.tsx delete mode 100644 Examples/src/components/Search/searchItems.ts delete mode 100644 Examples/src/components/SeoTags/NoIndexTag.tsx delete mode 100644 Examples/src/components/SeoTags/SeoTags.tsx delete mode 100644 Examples/src/components/SourceCode/SourceCode.module.scss delete mode 100644 Examples/src/components/SourceCode/SourceCode.tsx delete mode 100644 Examples/src/components/Title/Title.tsx delete mode 100644 Examples/src/components/buttons/ButtonBar.module.scss delete mode 100644 Examples/src/components/buttons/ButtonBar.tsx delete mode 100644 Examples/src/components/buttons/Icon.tsx delete mode 100644 Examples/src/components/buttons/IconButton.module.scss delete mode 100644 Examples/src/components/buttons/IconButton.tsx delete mode 100644 Examples/src/components/buttons/IconRadioGroup.module.scss delete mode 100644 Examples/src/components/buttons/IconRadioGroup.scss delete mode 100644 Examples/src/components/buttons/IconRadioGroup.tsx delete mode 100644 Examples/src/components/buttons/Toolbar.module.scss delete mode 100644 Examples/src/components/buttons/Toolbar.tsx delete mode 100644 Examples/src/components/buttons/Tooltip.module.scss delete mode 100644 Examples/src/components/buttons/Tooltip.tsx delete mode 100644 Examples/src/components/buttons/svgIcons.ts delete mode 100644 Examples/src/components/buttons/tooltipUtils.ts delete mode 100644 Examples/src/components/buttons/variables.scss delete mode 100644 Examples/src/components/index.scss delete mode 100644 Examples/src/constants.ts delete mode 100644 Examples/src/helpers/SciChartExamples.ts delete mode 100644 Examples/src/helpers/hooks/useIsomorphicLayoutEffect.ts delete mode 100644 Examples/src/helpers/shared/Helpers/Box/Box.tsx delete mode 100644 Examples/src/helpers/shared/Helpers/FrameworkContext.ts delete mode 100644 Examples/src/helpers/shared/Helpers/frameworkParametrization.ts delete mode 100644 Examples/src/helpers/shared/MenuListItemText/MenuListItemText.tsx delete mode 100644 Examples/src/helpers/types/ExampleDescriptionTypes.ts delete mode 100644 Examples/src/helpers/types/types.ts delete mode 100644 Examples/src/server/BinanceData/candlesADAUSDT.js delete mode 100644 Examples/src/server/BinanceData/candlesBTCUSDT.js delete mode 100644 Examples/src/server/BinanceData/candlesDOGEUSDT.js delete mode 100644 Examples/src/server/BinanceData/candlesETHUSDT.js delete mode 100644 Examples/src/server/BinanceData/candlesXRPUSDT.js delete mode 100644 Examples/src/server/Data/multiPaneData.ts delete mode 100644 Examples/src/server/Data/populationData.ts delete mode 100644 Examples/src/server/Data/tq3080_DSM_2M.asc delete mode 100644 Examples/src/server/Data/tq3080_DSM_2M.js delete mode 100644 Examples/src/server/Data/tweetData.js delete mode 100644 Examples/src/server/Errors.ts delete mode 100644 Examples/src/server/api.ts delete mode 100644 Examples/src/server/middlewares/loggingMiddleware.ts delete mode 100644 Examples/src/server/renderCodeSandboxRedirect.ts delete mode 100644 Examples/src/server/renderIndexHtml.ts delete mode 100644 Examples/src/server/routes/MainRouter.ts delete mode 100644 Examples/src/server/routes/exportExampleInfo.ts delete mode 100644 Examples/src/server/routes/oembed.ts delete mode 100644 Examples/src/server/routes/variants.ts delete mode 100644 Examples/src/server/server.tsx delete mode 100644 Examples/src/server/services/logging.ts delete mode 100644 Examples/src/server/services/pageRender/index.ts delete mode 100644 Examples/src/server/services/pageRender/reactSsr.tsx delete mode 100644 Examples/src/server/services/sandbox/angularConfig.ts delete mode 100644 Examples/src/server/services/sandbox/constants.ts delete mode 100644 Examples/src/server/services/sandbox/index.ts delete mode 100644 Examples/src/server/services/sandbox/reactConfig.ts delete mode 100644 Examples/src/server/services/sandbox/sandboxDependencyUtils.ts delete mode 100644 Examples/src/server/services/sandbox/vanillaTsConfig.ts delete mode 100644 Examples/src/server/services/stackblitz/getStackblitzFiles.ts delete mode 100644 Examples/src/server/types/TBinanceQueryParams.ts delete mode 100644 Examples/src/server/vanillaDemo/common.js delete mode 100644 Examples/src/server/vanillaDemo/vanillaExampleHtmlTemplate.ts delete mode 100644 Examples/src/server/vanillaDemo/vanillaExamplesRouter.ts delete mode 100644 Examples/src/server/websockets.ts delete mode 100644 Examples/src/utils/googleTagManager.ts delete mode 100644 Examples/src/utils/routeUtils.ts create mode 100644 Examples/start-dev.bat create mode 100644 Examples/start-dev.ps1 create mode 100644 Examples/test-env.js create mode 100644 Examples/test_firebase.js create mode 100644 Examples/test_websocket.html create mode 160000 Examples/vitals-monitoring diff --git a/Examples/.env b/Examples/.env index 00ea18501..edd9d17ea 100644 --- a/Examples/.env +++ b/Examples/.env @@ -1,3 +1,4 @@ + # Firebase Configuration for Frontend # Replace these values with your actual Firebase credentials diff --git a/Examples/FIREBASE_TROUBLESHOOTING.md b/Examples/FIREBASE_TROUBLESHOOTING.md new file mode 100644 index 000000000..3479ee8fe --- /dev/null +++ b/Examples/FIREBASE_TROUBLESHOOTING.md @@ -0,0 +1,272 @@ +# ๐Ÿ”ฅ Firebase Troubleshooting Guide + +This guide helps resolve Firebase installation and dependency issues. + +## ๐Ÿš€ Quick Fix Commands + +### 1. Install Firebase with Dependency Resolution + +```bash +npm run install:firebase +``` + +### 2. Manual Firebase Installation + +```bash +npm install firebase@^10.7.1 +``` + +### 3. Clear npm Cache and Reinstall + +```bash +npm cache clean --force +rm -rf node_modules package-lock.json +npm install +``` + +## ๐Ÿ” Common Issues and Solutions + +### Issue 1: "Module not found: 'firebase'" + +**Symptoms:** + +- Error: `Cannot find module 'firebase'` +- Import fails: `import { initializeApp } from 'firebase/app'` + +**Solutions:** + +1. **Install Firebase:** + + ```bash + npm install firebase@^10.7.1 + ``` + +2. **Check package.json:** + + ```json + { + "dependencies": { + "firebase": "^10.7.1" + } + } + ``` + +3. **Restart development server:** + ```bash + npm run dev:clean + ``` + +### Issue 2: "Firebase App named '[DEFAULT]' already exists" + +**Symptoms:** + +- Error: `Firebase App named '[DEFAULT]' already exists` +- Multiple Firebase initializations + +**Solutions:** + +1. **Check for duplicate imports in firebaseLogger.ts:** + + ```typescript + // Ensure only one initialization + if (!app) { + app = initializeApp(firebaseConfig); + } + ``` + +2. **Clear browser cache and restart** + +### Issue 3: "Firebase configuration error" + +**Symptoms:** + +- Error: `Firebase configuration error` +- Invalid API key or project settings + +**Solutions:** + +1. **Verify .env file in root directory:** + + ```env + REACT_APP_FIREBASE_API_KEY=your-actual-api-key + REACT_APP_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com + REACT_APP_FIREBASE_DATABASE_URL=https://your-project.firebaseio.com + REACT_APP_FIREBASE_PROJECT_ID=your-project-id + REACT_APP_FIREBASE_STORAGE_BUCKET=your-project.appspot.com + REACT_APP_FIREBASE_MESSAGING_SENDER_ID=123456789 + REACT_APP_FIREBASE_APP_ID=your-app-id + ``` + +2. **Run setup validation:** + ```bash + python setup_firebase.py + ``` + +### Issue 4: "Dependency conflicts" + +**Symptoms:** + +- npm audit warnings +- Version conflicts +- Peer dependency warnings + +**Solutions:** + +1. **Run dependency resolution:** + + ```bash + npm audit fix + npm install + ``` + +2. **Check for conflicting packages:** + ```bash + npm ls firebase + npm ls react + npm ls typescript + ``` + +### Issue 5: "WebSocket connection issues" + +**Symptoms:** + +- ESP32 not connecting +- WebSocket client disconnects +- Connection timeout + +**Solutions:** + +1. **Test WebSocket connection:** + + - Open `test_websocket.html` in browser + - Try connecting to `ws://10.171.208.121:81` + +2. **Check ESP32 Serial Monitor:** + + - Verify IP address: `10.171.208.121` + - Check WebSocket server status + - Look for connection logs + +3. **Network troubleshooting:** + - Ensure both devices on same network + - Check firewall settings + - Verify ESP32 WiFi connection + +## ๐Ÿ“‹ Installation Checklist + +### โœ… Pre-Installation + +- [ ] Node.js and npm installed +- [ ] Project dependencies installed +- [ ] .env file created in root directory + +### โœ… Firebase Setup + +- [ ] Firebase project created +- [ ] Realtime Database enabled +- [ ] Credentials copied to .env +- [ ] Firebase SDK installed + +### โœ… Verification + +- [ ] `npm list firebase` shows version +- [ ] No TypeScript errors +- [ ] WebSocket connection works +- [ ] Firebase logging functional + +## ๐Ÿ› ๏ธ Advanced Troubleshooting + +### PowerShell Execution Policy Issues + +```powershell +# Run as Administrator +Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser +``` + +### npm Permission Issues + +```bash +# Clear npm cache +npm cache clean --force + +# Reinstall with clean slate +rm -rf node_modules package-lock.json +npm install +``` + +### TypeScript Configuration Issues + +```json +// tsconfig.json - ensure Firebase types are included +{ + "compilerOptions": { + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + } +} +``` + +### Webpack Configuration Issues + +```javascript +// webpack.config.js - ensure Firebase is bundled +module.exports = { + resolve: { + fallback: { + crypto: require.resolve("crypto-browserify"), + stream: require.resolve("stream-browserify"), + buffer: require.resolve("buffer"), + }, + }, +}; +``` + +## ๐Ÿ“ž Getting Help + +### Debug Commands + +```bash +# Check Firebase installation +npm list firebase + +# Check for dependency conflicts +npm audit + +# Test WebSocket connection +# Open test_websocket.html in browser + +# Validate .env file +python setup_firebase.py +``` + +### Console Logs to Check + +```javascript +// Browser console - look for these messages: +โœ… Firebase Logger: Connection status set to true +โœ… Firebase Logger: Successfully logged processed sensor data +โœ… WEBSOCKET: ESP32 WebSocket connected successfully! +``` + +### ESP32 Serial Monitor - Look for: + +``` +WiFi connected! +IP Address: 10.171.208.121 +ESP32 WebSocket server started on port 81 +WebSocket client #0 connected from [IP] +``` + +## ๐ŸŽฏ Expected Results + +After successful setup: + +- โœ… Firebase logs data every 30 seconds when ESP32 connected +- โœ… CSV files download when recording stops +- โœ… WebSocket connection shows "Connected" status +- โœ… No console errors related to Firebase or WebSocket +- โœ… ESP32 sends data to frontend successfully + +--- + +**Need more help?** Check the browser console for detailed error messages and connection status. diff --git a/Examples/README_FIREBASE_TROUBLESHOOTING.md b/Examples/README_FIREBASE_TROUBLESHOOTING.md new file mode 100644 index 000000000..1805b8fda --- /dev/null +++ b/Examples/README_FIREBASE_TROUBLESHOOTING.md @@ -0,0 +1,162 @@ +# ๐Ÿ”ฅ Firebase Troubleshooting Guide + +## **Problem**: No data appearing in Firebase Realtime Database despite correct environment variables + +### **๐Ÿ” Step-by-Step Diagnosis** + +#### **1. Check Browser Console for Errors** + +Open your browser's Developer Tools (F12) and check the Console tab for: + +- โœ… Firebase initialization messages +- โŒ Error messages +- ๐Ÿ”ง Connection test results + +**Expected Console Output:** + +``` +โœ… Firebase initialized successfully +๐Ÿ“Š Database URL: https://biofeedback-a3a9d-default-rtdb.firebaseio.com +๐Ÿ”ง Firebase Logger initialized +โœ… Firebase Logger: Connection test successful +``` + +**If you see errors, note them down!** + +#### **2. Test Firebase Connection Manually** + +1. Click the **๐Ÿงช Test Firebase** button in your app +2. Check console for test results +3. Check Firebase Console for new data + +#### **3. Verify Firebase Security Rules** + +**โš ๏ธ CRITICAL**: This is likely the main issue! + +Go to [Firebase Console](https://console.firebase.google.com/) โ†’ Your Project โ†’ Realtime Database โ†’ Rules + +**Current Rules (Problematic):** + +```json +{ + "rules": { + ".read": "auth != null", + ".write": "auth != null" + } +} +``` + +**Updated Rules (Allow Read/Write):** + +```json +{ + "rules": { + ".read": true, + ".write": true + } +} +``` + +**โš ๏ธ WARNING**: These rules allow anyone to read/write. For production, use proper authentication. + +#### **4. Check Firebase Project Settings** + +1. **Go to Firebase Console** โ†’ Project Settings +2. **Verify these match your .env file:** + - Project ID: `biofeedback-a3a9d` + - Web API Key: `AIzaSyC2Il3KXMbvIwiVO-q2QnyjCzXWOU6qUBQ` + - Database URL: `https://biofeedback-a3a9d-default-rtdb.firebaseio.com` + +#### **5. Verify Database Path** + +**Expected Data Structure:** + +``` +biofeedback-a3a9d-default-rtdb.firebaseio.com/ +โ”œโ”€โ”€ connection_test/ # Connection test data +โ”œโ”€โ”€ processed_sensor_logs/ # Main sensor data +โ”‚ โ”œโ”€โ”€ -NxYz123... # Auto-generated keys +โ”‚ โ””โ”€โ”€ -NxYz124... +โ”œโ”€โ”€ logs_summary/ # Summary information +โ””โ”€โ”€ events/ # Event logs +``` + +#### **6. Test with Firebase CLI (Optional)** + +If you have Firebase CLI installed: + +```bash +firebase login +firebase projects:list +firebase database:get / --project biofeedback-a3a9d +``` + +### **๐Ÿ”ง Common Fixes** + +#### **Fix 1: Update Security Rules** + +```json +{ + "rules": { + ".read": true, + ".write": true + } +} +``` + +#### **Fix 2: Check Database Region** + +- Ensure your database is in the correct region +- Check if there are any regional restrictions + +#### **Fix 3: Verify Environment Variables** + +- Ensure `.env` file is in the **root directory** (not in subfolders) +- Restart your development server after changing `.env` +- Check that all variables start with `REACT_APP_` + +#### **Fix 4: Clear Browser Cache** + +- Hard refresh (Ctrl+F5) +- Clear browser cache and cookies +- Try incognito/private browsing mode + +### **๐Ÿงช Testing Steps** + +1. **Upload the updated ESP32 code** (with new pin configuration) +2. **Restart your React development server** +3. **Open browser console** and look for Firebase messages +4. **Click "๐Ÿงช Test Firebase" button** +5. **Check Firebase Console** for new data +6. **Wait 30 seconds** for automatic logging to start + +### **๐Ÿ“Š Expected Results** + +**After successful setup, you should see:** + +- Console: `โœ… Firebase Logger: Successfully logged data #1 to Firebase` +- Firebase Console: New data under `processed_sensor_logs/` +- Data appearing every 30 seconds when sensors are active + +### **๐Ÿšจ Still Not Working?** + +**Check these additional issues:** + +1. **Network/Firewall**: Corporate networks may block Firebase +2. **Browser Extensions**: Ad blockers might interfere +3. **Firebase Quota**: Check if you've exceeded free tier limits +4. **Project Status**: Ensure Firebase project is active and not suspended + +### **๐Ÿ“ž Get Help** + +**Include these details when asking for help:** + +1. Console error messages (screenshot) +2. Firebase security rules (copy/paste) +3. Environment variables (with sensitive data redacted) +4. Browser and OS version +5. Steps you've already tried + +--- + +**๐Ÿ’ก Pro Tip**: The "๐Ÿงช Test Firebase" button will help isolate whether the issue is with Firebase configuration or with the automatic logging system. diff --git a/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Arduino_Read.cs b/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Arduino_Read.cs new file mode 100644 index 000000000..23ac70d9e --- /dev/null +++ b/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Arduino_Read.cs @@ -0,0 +1,28 @@ +๏ปฟusing UnityEngine; +using System.Collections; +using System.IO.Ports; + +public class Arduino_Read : MonoBehaviour + +{ + SerialPort sp = new SerialPort("COM5", 115200); + public static string QRS; + + void Start() + { + sp.Open(); + sp.ReadTimeout = 1; + } + + void Update() + { + try + { + QRS = sp.ReadLine(); + print(sp.ReadLine()); + } + catch (System.Exception) + { + } + } +} \ No newline at end of file diff --git a/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Data_logger_to_Unity.ino b/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Data_logger_to_Unity.ino new file mode 100644 index 000000000..abb430e69 --- /dev/null +++ b/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Data_logger_to_Unity.ino @@ -0,0 +1,419 @@ +/* ยฉ Script written by Tim Mรถller + * Humboldt Universitรคt zu Berlin + * Berlin School of Mind and Brain Berlin + * + * This script records data from the AD8232 shield and plots the data. + * Preprocessing and detect of the QRS compley is realized through the Pan-Tompkins algorithm + * (Pan, J., & Tompkins, W. J. (1985). A real-time QRS detection algorithm. IEEE Trans. Biomed. + * Eng, 32(3), 230-236.). + * * This script also saves the Date, the Timestamp, a Timer that counts the passed time and a + * counter for the number of recorded data-points. + * + * Some of the code contains element from available, open access, existing scripts: + * https://github.com/adafruit/Adafruit_SSD1306 + * https://github.com/blakeMilner/real_time_QRS_detection + * https://github.com/dxinteractive/ResponsiveAnalogRead + * SD card read/write (Arduino example sketches) created Nov 2010 by David A. Mellis modified 9 Apr 2012 by Tom Igoe + * This example code is in the public domain. + * SD Card test created 28 Mar 2011 by Limor Fried modified 9 Apr 2012 by Tom Igoe + * This example code is in the public domain. + * + * Last modified: 20.11.2019 + */ + int h = 0; +const String Filename = "Tim.txt"; // Give the Outputfile a name how it will be displayed on the SD Card +float Tweakfactor = 1.0; // That is the original heartbeat +//float Tweakfactor = 0.7; // Used for playing the tones 30% faster than the actual heartbeat +//float Tweakfactor = 1.3; // Used for playing the tones 30% slower than the actual heartbeat + +const int heartPin = A1; +#include +#include +#include +#include +#include +#define OLED_RESET 4 // not used / nicht genutzt bei diesem Display +#define M 5 +#define N 30 +#define winSize 400 // this value can be changed (e.g. to 250) which effects the sensitivity of the QRS-detection +#define HP_CONSTANT ((float) 1 / (float) M) +#define MAX_BPM 100 +#define RAND_RES 100000000 + +ResponsiveAnalogRead analog(heartPin, true); +//Adafruit_SSD1306 display(OLED_RESET); +//Adafruit_SSD1306 oled(128, 64); // create our screen object setting resolution to 128x64 + + +File myFile; +int saving_interval = 0; //create a variable that counts samples. When an aspired number of samples is gathered, the Arduino will save the data to the .txt file to save computational power +int saving_treshold = 300; //if this treshold is reached, the arduino saves the gathered data to the output file +int cprTimeRead_1 = 0; +int cprTimeRead_2 = 0; +int timeCPR = 0; +bool screenChanged = true; // initially we have a new screen, by definition +float interval; +unsigned long currentMillis = millis(); +unsigned long previousMillis = 0; +float difference = 0; +unsigned long i = 0; +unsigned long Tonelength = 20; +const int ECG_PIN = 0; // the number of the ECG pin (analog) +int x=0; +int j=0; +int lastj=0; +int lasty=0; +int LastTime=0; +int ThisTime; +bool BPMTiming=false; +bool BeatComplete=false; +int BPM=0; +int next_ecg_pt =0; +float CPRSUM; +int QRS = 0; +float bpm = 0; +int tmp = 0; + +// pre-recorded ECG, for testing +int s_ecg_idx = 0; +const int S_ECG_SIZE = 226; +const float s_ecg[S_ECG_SIZE] = {1.5984,1.5992,1.5974,1.5996,1.5978,1.5985,1.5992,1.5973,1.5998,1.5976,1.5986,1.5992,1.5972,1.6,1.5973,1.5989,1.5991,1.5969,1.6006,1.5964,1.6,1.5979,1.5994,1.6617,1.7483,1.823,1.8942,1.9581,2.0167,2.0637,2.1034,2.1309,2.1481,2.1679,2.1739,2.1702,2.1543,2.1243,2.0889,2.037,1.982,1.9118,1.8305,1.7532,1.6585,1.6013,1.5979,1.5981,1.5996,1.5972,1.5992,1.599,1.5966,1.6015,1.5952,1.6008,1.5984,1.5953,1.606,1.5841,1.6796,1.9584,2.2559,2.5424,2.835,3.1262,3.4167,3.7061,4.0018,4.2846,4.5852,4.8688,5.1586,5.4686,5.4698,5.1579,4.8687,4.586,4.2833,4.0031,3.7055,3.4164,3.1274,2.8333,2.544,2.2554,1.9572,1.6836,1.5617,1.5143,1.4221,1.3538,1.2791,1.1951,1.1326,1.0407,0.99412,1.0445,1.1262,1.2017,1.2744,1.3545,1.4265,1.5044,1.5787,1.6006,1.5979,1.5988,1.5982,1.5989,1.5982,1.5986,1.5987,1.5983,1.5984,1.5992,1.5965,1.6082,1.6726,1.7553,1.826,1.903,1.9731,2.0407,2.1079,2.166,2.2251,2.2754,2.3215,2.3637,2.396,2.4268,2.4473,2.4627,2.4725,2.4721,2.4692,2.4557,2.4374,2.4131,2.3797,2.3441,2.2988,2.2506,2.1969,2.1365,2.0757,2.0068,1.9384,1.8652,1.7899,1.7157,1.6346,1.5962,1.5997,1.5979,1.5986,1.5989,1.5978,1.5995,1.5976,1.5991,1.5984,1.5981,1.5993,1.5976,1.5993,1.5982,1.5982,1.5993,1.5975,1.5994,1.5981,1.5983,1.5995,1.5967,1.6049,1.6248,1.647,1.664,1.6763,1.6851,1.6851,1.6816,1.6712,1.655,1.6376,1.613,1.599,1.5985,1.5982,1.5989,1.5982,1.5986,1.5987,1.598,1.5991,1.598,1.5987,1.5987,1.598,1.5992,1.5979,1.5988,1.5986,1.598,1.5992,1.5979,1.5988,1.5986,1.598,1.5992,1.5978,1.5989,1.5985,1.5981,1.5992,1.5978,1.599,1.5985,1.5981,1.5992,1.5977,1.599,1.5984,1.5981}; + +// timing variables +unsigned long previousMicros = 0; // will store last time LED was updated +unsigned long foundTimeMicros = 0; // time at which last QRS was found +unsigned long old_foundTimeMicros = 0; // time at which QRS before last was found +unsigned long currentMicros = 0; // current time + +// interval at which to take samples and iterate algorithm (microseconds) +const long PERIOD = 1000000 / winSize; + +#define BPM_BUFFER_SIZE 5 +unsigned long bpm_buff[BPM_BUFFER_SIZE] = {0}; +int bpm_buff_WR_idx = 0; +int bpm_buff_RD_idx = 0; + +// set up variables using the SD utility library functions: +Sd2Card card; +SdVolume volume; +SdFile root; +const int chipSelect = 53; + + +void setup() { +pinMode(53, OUTPUT); // change this to 53 on a mega // don't follow this!! +//digitalWrite(53, HIGH); // Add this line +// For Display setup + // initialize with the I2C addr 0x3C / mit I2C-Adresse 0x3c initialisieren +// display.begin(SSD1306_SWITCHCAPVCC, 0x3C); + + Serial.begin(115200); + #ifdef SERIAL_USB + while (!Serial); // wait for Leonardo enumeration, others continue immediately + #endif + + Serial.print("Initializing SD card..."); + + if (!card.init(SPI_HALF_SPEED, chipSelect)) { + Serial.println("initialization failed. Things to check:"); + Serial.println("* is a card inserted?"); + Serial.println("* is your wiring correct?"); + Serial.println("* did you change the chipSelect pin to match your shield or module?"); + while (1); + } else { + Serial.println("Wiring is correct and a card is present."); + } + + if (!SD.begin(53)) { + Serial.println("initialization failed!"); + while (1); + } + Serial.println("initialization done."); + +myFile = SD.open(Filename, FILE_WRITE); //Name here the name for the data logger output +if (myFile) + { + Serial.println("File created successfully."); + return 1; + } else + { + Serial.println("Error while creating file."); + return 0; + } + + //define 5 columns named "Date", "Time", "Timer", "Counter", "Raw_data", and "QRS_detected" + // Serial.println("LABEL,Date,Time,Timer,Counter,Raw_data,QRS_detected"); + myFile.println("LABEL,Date,Time,Timer,Counter,Raw_data,QRS_detected"); + myFile.close(); + myFile = SD.open(Filename, FILE_WRITE); +} + +void loop() { + QRS = 1; +Serial.println(QRS); +delay(1000); + currentMicros = micros(); + + // iterate if it's time for a new data point (according to PERIOD) + //if (currentMicros - previousMicros >= PERIOD) { + // save the last time you blinked the LED + previousMicros = currentMicros; + + boolean QRS_detected = false; + int next_ecg_pt = analogRead(heartPin); + +//myFile = SD.open(Filename, FILE_WRITE); +if(myFile){ +//Serial.print("DATA,DATE,TIME,TIMER,"); +//Serial.print(i++); Serial.print(","); +//Serial.print(next_ecg_pt); Serial.print(","); +//Serial.println(QRS); +myFile.print(i++); +myFile.print(","); +myFile.print(next_ecg_pt); +myFile.print(","); +myFile.println(QRS); +//Serial.print(h++); +//Serial.println("Writing to test.txt..."); +saving_interval++; +// myFile.close(); + +if (saving_interval > saving_treshold){ + saving_interval = 0; + myFile.flush(); + myFile.close(); +myFile = SD.open(Filename, FILE_WRITE); +} + + + + + +//delay(1); // Choose your delay having in mind your ReadTimeout in Unity3D +} +//else{ +// // if the file isn't open, pop up an error: +// Serial.println("error opening datalog.txt"); +// delay(10); + //myFile.close(); + // myFile = SD.open(Filename, FILE_WRITE); + + +//} + + // give next data point to algorithm + QRS_detected = detect(next_ecg_pt); + + if(QRS_detected == false) { + QRS = 0; + + } + + // else if(QRS_detected == true){ + // foundTimeMicros = micros(); + // QRS = 1; + // Serial.println(QRS); + //sendData("QRS"); + //Serial.println(h++); + + cprTimeRead_2 = cprTimeRead_1; + cprTimeRead_1 = millis(); + CPRSUM = cprTimeRead_1-cprTimeRead_2; + interval = CPRSUM*Tweakfactor; + BPM = 60000/(cprTimeRead_1-cprTimeRead_2); + // } +/* + // Set up the paramters for the display + display.clearDisplay(); + + // set text color / Textfarbe setzen + display.setTextColor(WHITE); + // set text size / Textgroesse setzen + display.setTextSize(1); + // set text cursor position / Textstartposition einstellen + display.setCursor(1,0); + // show text / Text anzeigen + display.println("BPM"); + display.setCursor(34,15); + display.println(BPM); + display.display(); +*/ + + + if(difference > interval){ + //tone(2, 1000, Tonelength); // Im Hauptteil wird nun mit dem Befehl "tone ( x , y )" ein Ton abgegeben. + previousMillis = millis(); + } + +difference = millis() - previousMillis; + + +} + + + +/* Portion pertaining to Pan-Tompkins QRS detection */ + + +// circular buffer for input ecg signal +// we need to keep a history of M + 1 samples for HP filter +float ecg_buff[M + 1] = {0}; +int ecg_buff_WR_idx = 0; +int ecg_buff_RD_idx = 0; + +// circular buffer for input ecg signal +// we need to keep a history of N+1 samples for LP filter +float hp_buff[N + 1] = {0}; +int hp_buff_WR_idx = 0; +int hp_buff_RD_idx = 0; + +// LP filter outputs a single point for every input point +// This goes straight to adaptive filtering for eval +float next_eval_pt = 0; + +// running sums for HP and LP filters, values shifted in FILO +float hp_sum = 0; +float lp_sum = 0; + +// working variables for adaptive thresholding +float treshold = 0; +boolean triggered = false; +int trig_time = 0; +float win_max = 0; +int win_idx = 0; + +// numebr of starting iterations, used determine when moving windows are filled +int number_iter = 0; + +boolean detect(float new_ecg_pt) { + // copy new point into circular buffer, increment index + ecg_buff[ecg_buff_WR_idx++] = new_ecg_pt; + ecg_buff_WR_idx %= (M+1); + + + /* High pass filtering */ + if(number_iter < M){ + // first fill buffer with enough points for HP filter + hp_sum += ecg_buff[ecg_buff_RD_idx]; + hp_buff[hp_buff_WR_idx] = 0; + } + else{ + hp_sum += ecg_buff[ecg_buff_RD_idx]; + + tmp = ecg_buff_RD_idx - M; + if(tmp < 0) tmp += M + 1; + + hp_sum -= ecg_buff[tmp]; + + float y1 = 0; + float y2 = 0; + + tmp = (ecg_buff_RD_idx - ((M+1)/2)); + if(tmp < 0) tmp += M + 1; + + y2 = ecg_buff[tmp]; + + y1 = HP_CONSTANT * hp_sum; + + hp_buff[hp_buff_WR_idx] = y2 - y1; + } + + // done reading ECG buffer, increment position + ecg_buff_RD_idx++; + ecg_buff_RD_idx %= (M+1); + + // done writing to HP buffer, increment position + hp_buff_WR_idx++; + hp_buff_WR_idx %= (N+1); + + + /* Low pass filtering */ + + // shift in new sample from high pass filter + lp_sum += hp_buff[hp_buff_RD_idx] * hp_buff[hp_buff_RD_idx]; + + if(number_iter < N){ + // first fill buffer with enough points for LP filter + next_eval_pt = 0; + + } + else{ + // shift out oldest data point + tmp = hp_buff_RD_idx - N; + if(tmp < 0) tmp += (N+1); + + lp_sum -= hp_buff[tmp] * hp_buff[tmp]; + + next_eval_pt = lp_sum; + } + + // done reading HP buffer, increment position + hp_buff_RD_idx++; + hp_buff_RD_idx %= (N+1); + + + /* Adapative thresholding beat detection */ + // set initial threshold + if(number_iter < winSize) { + if(next_eval_pt > treshold) { + treshold = next_eval_pt; + } + + number_iter++; + } + + // check if detection hold off period has passed + if(triggered == true){ + trig_time++; + + if(trig_time >= 100){ + triggered = false; + trig_time = 0; + } + } + + // find if we have a new max + if(next_eval_pt > win_max) win_max = next_eval_pt; + + // find if we are above adaptive threshold + if(next_eval_pt > treshold && !triggered) { + triggered = true; + return true; + } + // else we'll finish the function before returning FALSE, + // to potentially change threshold + + // adjust adaptive threshold using max of signal found + // in previous window + if(win_idx++ >= winSize){ + // weighting factor for determining the contribution of + // the current peak value to the threshold adjustment + float gamma = 0.4; + + // forgetting factor - + // rate at which we forget old observations + // choose a random value between 0.01 and 0.1 for this, + float alpha = 0.1 + ( ((float) random(0, RAND_RES) / (float) (RAND_RES)) * ((0.1 - 0.01))); + + // compute new threshold + treshold = alpha * gamma * win_max + (1 - alpha) * treshold; + + // reset current window index + win_idx = 0; + win_max = -10000000; + } + + // return false if we didn't detect a new QRS + return false; + + +} + +void sendData(String data){ + + #ifdef SERIAL_USB + Serial.println(QRS); // need a end-line because wrmlh.csharp use readLine method to receive data + //serialPort.ReadTimeout = 1; + //delay(1); // Choose your delay having in mind your ReadTimeout in Unity3D +#endif +} diff --git a/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Fritzing.jpg b/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Fritzing.jpg new file mode 100644 index 0000000000000000000000000000000000000000..63a1910cf7d9f3e70e7de3a7da21914bdfc9494d GIT binary patch literal 544093 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%0AR{(3y+>J3h?6s`l(N{GHoaW~DQV+PD{mG(HBX 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%0ASUJvkd~>219Tbv|5KJ95T+IV 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

4|=`#!`RLh`RrJo-My``BY%Eg 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%0AWVV>-y93KNNS!f}P3A!6A#Z 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%0D_p1MSN4WTssXn>mRIt=WQDx-Z$8peW)e{O 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 uwmoQ2zmO7N|;@5{m5Bfcd*7{wQ#`uz_XAYmyo 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 literal 0 HcmV?d00001 diff --git a/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/LICENSE b/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/LICENSE new file mode 100644 index 000000000..d760a9822 --- /dev/null +++ b/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 nalgi + +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. diff --git a/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/README.md b/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/README.md new file mode 100644 index 000000000..fb309b5eb --- /dev/null +++ b/Examples/ad8232 refs/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/Pan-Tompkins_QRS-detector_and_Datalogger-1.0.0/README.md @@ -0,0 +1,38 @@ +# Pan-Tompkins_QRS-detector_and_Datalogger + +Provided is an Arduino based AD8232 Pan-Tompkins QRS-detector and Datalogger that can plot and send Serial information to Unity (Arduino_QRS-detector) at the same time as well as an Unity 3D script (Arduino_Read) that receives the data. The processed Arduino data can be also send to other programs and is not limited to Unity 3D alone. A Fritzing schematic for wiring and needed components can be found under the "Pictures" folder. Pictures of the real setup are also available there. + +For more in depth details and performance, see the following paper: (Link to paper) + +This script saves the Date, the Timestamp, a Timer that counts the passed time and a counter for the number of recorded data-points, if enabled. The data is automatically saved on a microSD card and shows an error, when no data can be written on the SD card. This option can be disabled, too. + +The SD card saves data according to the FAT file system using the 8.3 format. That means a the filename that you choose for your data must not exceed 8 characters (e.g. the number or the initials of your participant). The file can also be stored as an .csv file. + +It can be decided if tones should be played together with the QRS detection and if so, if in the same rhythym or faster or slower (percentage can be tuned) in respect to the last QRS-QRS interval. \\ + +This Setup proved to be fast and reliable and suitable for scientific research (For more information, see: Link to paper) and can be used according to the MIT license. + +- ยฉ Script written by Tim Mรถller +- Humboldt Universitรคt zu Berlin +- Berlin School of Mind and Brain Berlin +- +- This script records data from the AD8232 shield and plots the data. +- Preprocessing and detect of the QRS compley is realized through the Pan-Tompkins algorithm +- (Pan, J., & Tompkins, W. J. (1985). A real-time QRS detection algorithm. IEEE Trans. Biomed. +- Eng, 32(3), 230-236.). +- - This script also saves the Date, the Timestamp, a Timer that counts the passed time and a +- counter for the number of recorded data-points. +- +- Some of the code contains element from available, open access, existing scripts and is marked sccordingly inside the code. The complete Code-snippets that were used can be found under: +- https://github.com/adafruit/Adafruit_SSD1306 +- https://github.com/blakeMilner/real_time_QRS_detection +- https://github.com/dxinteractive/ResponsiveAnalogRead +- SD card read/write (Arduino example sketches) created Nov 2010 by David A. Mellis modified 9 Apr 2012 by Tom Igoe +- This example code is in the public domain. +- SD Card test created 28 Mar 2011 by Limor Fried modified 9 Apr 2012 by Tom Igoe +- This example code is in the public domain. +- +- Last modified: 25.03.2020 +- + +Please cite as XXX diff --git a/Examples/ad8232 refs/ad8232 plot.ino b/Examples/ad8232 refs/ad8232 plot.ino new file mode 100644 index 000000000..e23a59d92 --- /dev/null +++ b/Examples/ad8232 refs/ad8232 plot.ino @@ -0,0 +1,62 @@ +Serial myPort; // The serial port +int xPos = 1; // horizontal position of the graph +float height_old = 0; +float height_new = 0; +float inByte = 0; + + +void setup () { + // set the window size: + size(1000, 400); + + // List all the available serial ports + println(Serial.list()); + // Open whatever port is the one you're using. +myPort = new Serial(this, Serial.list()[2], 9600); + // don't generate a serialEvent() unless you get a newline character: + myPort.bufferUntil('\n'); + // set inital background: + background(0xff); +} + +void draw () { + // everything happens in the serialEvent() +} + + +void serialEvent (Serial myPort) { + // get the ASCII string: + String inString = myPort.readStringUntil('\n'); + + if (inString != null) { + // trim off any whitespace: + inString = trim(inString); + + // If leads off detection is true notify with blue line + if (inString.equals("!")) { + stroke(0, 0, 0xff); //Set stroke to blue ( R, G, B) + inByte = 512; // middle of the ADC range (Flat Line) + } + // If the data is good let it through + else { + stroke(0xff, 0, 0); //Set stroke to red ( R, G, B) + inByte = float(inString); + } + + //Map and draw the line for new data point + inByte = map(inByte, 0, 1023, 0, height); + height_new = height - inByte; + line(xPos - 1, height_old, xPos, height_new); + height_old = height_new; + + // at the edge of the screen, go back to the beginning: + if (xPos >= width) { + xPos = 0; + background(0xff); + } + else { + // increment the horizontal position: + xPos++; + } + } +} \ No newline at end of file diff --git a/Examples/esp32/CALIBRATION_README.md b/Examples/esp32/CALIBRATION_README.md new file mode 100644 index 000000000..bafef7176 --- /dev/null +++ b/Examples/esp32/CALIBRATION_README.md @@ -0,0 +1,313 @@ +# ESP32 Sensor Calibration Guide + +This guide will help you calibrate your ESP32-based vital signs monitoring system using the AD8232 ECG sensor, HW-484 sound sensor for breathing detection, and GSR sensor. + +## ๐ŸŽฏ What This Calibration Does + +The calibration process will: + +1. **Establish baseline values** for each sensor when the subject is at rest +2. **Analyze breathing patterns** to distinguish between breath in/out +3. **Calculate optimal thresholds** for breath detection +4. **Provide recommendations** for sensor configuration + +## ๐Ÿ“‹ Prerequisites + +- ESP32 development board +- AD8232 ECG sensor module +- HW-484 sound sensor module +- GSR (Galvanic Skin Response) sensor +- Arduino IDE with ESP32 board support +- Python 3.7+ (for data analysis) + +## ๐Ÿ”Œ Hardware Setup + +### Sensor Connections + +``` +ESP32 Pin Sensor Connection +GPIO32 AD8232 Analog Output +GPIO33 GSR Analog Output +GPIO27 HW-484 Analog Output +3.3V All Sensors Power Supply +GND All Sensors Ground +``` + +### Sensor Placement + +- **AD8232**: Place electrodes on chest (RA, LA, RL positions) +- **HW-484**: Position near nose/mouth for breathing detection +- **GSR**: Attach to fingers or palm for skin conductance measurement + +## ๐Ÿš€ Calibration Process + +### Step 1: Upload Calibration Code + +1. Open `sensor_calibration.ino` in Arduino IDE +2. Select your ESP32 board and port +3. Upload the code to your ESP32 + +### Step 2: Run Calibration + +1. Open Serial Monitor at **115200 baud** +2. The calibration will start automatically in 5 seconds +3. Follow the on-screen instructions + +### Step 3: Data Collection Phases + +#### Phase 1: Baseline Calibration (30 seconds) + +- **Subject**: Remain completely still +- **Purpose**: Establish baseline sensor values +- **Output**: Sensor ranges, noise levels, baseline values + +#### Phase 2: Breath Analysis (60 seconds) + +- **Subject**: Breathe normally and steadily +- **Purpose**: Analyze breathing patterns and detect breath in/out +- **Output**: Breath detection accuracy, respiratory rate calculation + +#### Phase 3: Continuous Monitoring + +- **Subject**: Perform various activities (breathing exercises, movement) +- **Purpose**: Real-time sensor data analysis +- **Output**: Live sensor readings with breath detection + +## ๐Ÿ“Š Understanding the Output + +### Baseline Calibration Results + +``` +ECG Sensor (AD8232): + Range: 2048 - 3072 (Span: 1024) + Baseline: 2560 + Noise Level: ยฑ512 + +GSR Sensor: + Range: 1800 - 2300 (Span: 500) + Baseline: 2050 + Noise Level: ยฑ250 + +Respiratory Sensor (HW-484): + Range: 1900 - 2100 (Span: 200) + Baseline: 2000 + Noise Level: ยฑ100 +``` + +### Breath Detection Analysis + +``` +๐Ÿซ BREATH IN detected! Raw: 2100, Deviation: +100 +๐Ÿซ BREATH OUT detected! Raw: 1900, Deviation: -100 +``` + +### Real-time Data Format + +``` +DATA: timestamp, ecg_raw, ecg_dev, gsr_raw, gsr_dev, resp_raw, resp_dev +DATA: 12345, 2560, +0, 2050, +0, 2000, +0 +``` + +## ๐Ÿ”ฌ Data Analysis + +### Step 1: Save Serial Output + +1. Copy all Serial Monitor output +2. Save to a text file (e.g., `calibration_data.txt`) + +### Step 2: Run Analysis Script + +```bash +python calibration_analyzer.py calibration_data.txt +``` + +### Step 3: Review Recommendations + +The script will generate: + +- Optimal thresholds for each sensor +- Breath detection parameters +- Filtering recommendations +- ESP32 code snippets + +## ๐ŸŽฏ Calibration Recommendations + +### Breath Detection Thresholds + +Based on your data, the script will recommend: + +```cpp +// Example recommendations +const int BREATH_IN_THRESHOLD = 75; // 70% of mean breath-in deviation +const int BREATH_OUT_THRESHOLD = 75; // 70% of mean breath-out deviation +const int MIN_BREATH_INTERVAL = 1000; // 1 second minimum between breaths +``` + +### Sensor-Specific Thresholds + +```cpp +// ECG Sensor +const int ECG_PEAK_THRESHOLD = 341; // Range/3 for QRS detection + +// GSR Sensor +const int GSR_CHANGE_THRESHOLD = 62; // Range/8 for significant changes + +// Respiratory Sensor +const int RESP_BREATH_THRESHOLD = 50; // Range/4 for breath detection +``` + +## ๐Ÿ”ง Implementing Calibration Results + +### Update Your Main Code + +1. Copy recommended thresholds to `main.ino` +2. Replace existing threshold values +3. Test with real subjects +4. Fine-tune if necessary + +### Example Implementation + +```cpp +// Updated breath detection in main.ino +int calculateRespiratoryRate(int rawValue, unsigned long timestamp) { + int deviation = abs(rawValue - respBaseline); + + if (deviation > BREATH_IN_THRESHOLD && !breathDetected) { + if (timestamp - lastBreathTime > MIN_BREATH_INTERVAL) { + breathDetected = true; + lastBreathTime = timestamp; + + // Determine breath direction + if (rawValue > respBaseline) { + // Breath IN + Serial.println("๐Ÿซ Breath IN detected"); + } else { + // Breath OUT + Serial.println("๐Ÿซ Breath OUT detected"); + } + } + } else if (deviation <= BREATH_IN_THRESHOLD) { + breathDetected = false; + } + + return currentRespRate; +} +``` + +## ๐Ÿ“ˆ Expected Results + +### Good Calibration Indicators + +- **ECG**: Clear QRS peaks, stable baseline +- **Breathing**: Distinct breath in/out patterns +- **GSR**: Stable readings with clear response to stimuli + +### Poor Calibration Indicators + +- **ECG**: Excessive noise, unstable baseline +- **Breathing**: Unclear breath patterns, false detections +- **GSR**: Drifting baseline, poor signal-to-noise ratio + +## ๐Ÿšจ Troubleshooting + +### Common Issues + +#### No Sensor Readings + +- Check wiring connections +- Verify power supply (3.3V) +- Ensure proper ground connection + +#### Excessive Noise + +- Check for loose connections +- Move away from electrical interference +- Verify sensor placement + +#### Poor Breath Detection + +- Adjust sensor position near nose/mouth +- Check for background noise +- Verify threshold calculations + +#### Unstable Baseline + +- Ensure subject remains still during calibration +- Check for sensor movement +- Verify stable power supply + +### Sensor-Specific Issues + +#### AD8232 ECG + +- **No signal**: Check electrode placement and conductivity +- **High noise**: Ensure good skin contact and electrode adhesion +- **Baseline drift**: Check for movement artifacts + +#### HW-484 Sound Sensor + +- **Poor breath detection**: Adjust microphone position +- **Background noise**: Use in quiet environment +- **False triggers**: Increase detection threshold + +#### GSR Sensor + +- **No response**: Check electrode contact +- **Drifting values**: Ensure stable electrode placement +- **Poor sensitivity**: Clean electrodes and skin + +## ๐Ÿ”„ Recalibration + +### When to Recalibrate + +- After changing sensor placement +- When switching subjects +- If detection accuracy decreases +- After hardware modifications + +### Recalibration Process + +1. Follow the same calibration procedure +2. Compare results with previous calibration +3. Adjust thresholds if necessary +4. Document changes for future reference + +## ๐Ÿ“š Additional Resources + +### Technical Documentation + +- [AD8232 ECG Sensor Datasheet](https://wiki.keyestudio.com/Ks0261_keyestudio_AD8232_ECG_Measurement_Heart_Monitor_Sensor_Module) +- [HW-484 Sound Sensor Guide](https://sichiray-tech.yuque.com/dm0eyv/chanpin/iqepdr0qglekrtc3) +- [ESP32 ADC Documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html) + +### Best Practices + +- Calibrate in a controlled environment +- Document all calibration parameters +- Test with multiple subjects +- Monitor long-term performance +- Implement adaptive thresholds + +## ๐ŸŽ‰ Success Criteria + +Your calibration is successful when: + +- โœ… Breath detection accuracy > 90% +- โœ… Respiratory rate calculation within ยฑ2 breaths/min +- โœ… ECG signal quality suitable for QRS detection +- โœ… GSR baseline stability maintained +- โœ… Real-time performance meets requirements + +## ๐Ÿ“ž Support + +If you encounter issues: + +1. Review this guide thoroughly +2. Check hardware connections +3. Verify sensor specifications +4. Test with known good sensors +5. Document specific error messages + +--- + +**Remember**: Calibration is crucial for accurate vital signs monitoring. Take your time, follow the process carefully, and document your results for future reference. diff --git a/Examples/esp32/README_FIREBASE.md b/Examples/esp32/README_FIREBASE.md deleted file mode 100644 index 5b1a53362..000000000 --- a/Examples/esp32/README_FIREBASE.md +++ /dev/null @@ -1,185 +0,0 @@ -# ๐Ÿ”ฅ Firebase Integration for ESP32 Vital Signs Monitor - -This guide will help you set up Firebase logging for your ESP32 vital signs monitor. The system will log sensor data every 30 seconds when the frontend is connected. - -## ๐Ÿ“‹ What You'll Get - -- **Real-time sensor data logging** every 30 seconds -- **Automatic logging** only when frontend is connected -- **Complete sensor data** including ECG, GSR, Respiratory, Heart Rate, and IBI -- **Firebase Realtime Database** storage for easy access - -## ๐Ÿš€ Quick Setup - -### Step 1: Firebase Project Setup - -1. **Go to Firebase Console**: https://console.firebase.google.com/ -2. **Create a new project** or select existing one -3. **Enable Realtime Database**: - - Go to "Realtime Database" in the left sidebar - - Click "Create Database" - - Choose "Start in test mode" (for development) - - Select a location close to you -4. **Get your credentials**: - - Go to "Project Settings" (gear icon) > "General" - - Scroll down to "Your apps" section - - Copy the "Web API Key" - - Go back to "Realtime Database" - - Copy the database URL (looks like: `https://your-project.firebaseio.com`) - -### Step 2: Update Credentials - -1. **Edit the `.env` file** in the `esp32` folder: - - ```bash - # Replace these with your actual Firebase credentials - FIREBASE_API_KEY=your-actual-api-key-here - FIREBASE_DATABASE_URL=https://your-project-id.firebaseio.com - FIREBASE_USER_EMAIL=your-email@example.com - FIREBASE_USER_PASSWORD=your-password-here - ``` - -2. **Run the setup script**: - ```bash - cd esp32 - python setup_firebase.py - ``` - -### Step 3: Install Arduino Library - -1. **Open Arduino IDE** -2. **Go to Tools > Manage Libraries** -3. **Search for**: "Firebase ESP32 Client" -4. **Install** the library by "Mobizt" - -### Step 4: Upload to ESP32 - -1. **Open** `main.ino` in Arduino IDE -2. **Select your ESP32 board** and port -3. **Upload** the code - -## ๐Ÿ“Š Data Structure - -The Firebase database will store data in this structure: - -``` -/sensor_logs/ - โ”œโ”€โ”€ 1234567890/ - โ”‚ โ”œโ”€โ”€ timestamp: "1234567890" - โ”‚ โ”œโ”€โ”€ ecg_raw: 2048 - โ”‚ โ”œโ”€โ”€ gsr_raw: 1500 - โ”‚ โ”œโ”€โ”€ respiratory_raw: 1800 - โ”‚ โ”œโ”€โ”€ heart_rate: 75 - โ”‚ โ”œโ”€โ”€ ibi: 800 - โ”‚ โ”œโ”€โ”€ frontend_connected: true - โ”‚ โ””โ”€โ”€ connected_clients: 1 - โ””โ”€โ”€ 1234567920/ - โ””โ”€โ”€ ... (next 30-second log) -``` - -## ๐Ÿ”ง How It Works - -### Logging Conditions - -- โœ… **Frontend connected** via WebSocket -- โœ… **Every 30 seconds** automatically -- โœ… **Real sensor data** from analog pins -- โœ… **Complete dataset** including all vital signs - -### Data Flow - -``` -Analog Pins โ†’ ESP32 Processing โ†’ Firebase Realtime Database - โ†“ โ†“ โ†“ - Raw ADC Pan-Tompkins JSON Logs - Values Beat Detection Every 30s -``` - -### Connection Tracking - -- **WebSocket events** track frontend connection -- **Automatic start/stop** of Firebase logging -- **Client count** monitoring - -## ๐Ÿ› ๏ธ Troubleshooting - -### Common Issues - -1. **"Firebase not ready"** - - - Check WiFi connection - - Verify Firebase credentials in `.env` - - Ensure Firebase library is installed - -2. **"Firebase signin failed"** - - - Check email/password in `.env` - - Verify Firebase project settings - - Ensure Realtime Database is enabled - -3. **No logs appearing** - - Check if frontend is connected - - Verify WebSocket connection - - Check Serial Monitor for errors - -### Debug Commands - -Check Serial Monitor for these messages: - -``` -โœ… Firebase signin successful -โœ… Frontend connected - starting Firebase logging -โœ… Firebase log successful: /sensor_logs/1234567890 -``` - -## ๐Ÿ“ฑ Viewing Data - -### Firebase Console - -1. Go to your Firebase project -2. Navigate to "Realtime Database" -3. Look for `/sensor_logs/` folder -4. Data updates every 30 seconds when connected - -### Programmatic Access - -```javascript -// Example: Read latest sensor data -firebase - .database() - .ref("sensor_logs") - .orderByKey() - .limitToLast(1) - .once("value") - .then((snapshot) => { - const data = snapshot.val(); - console.log("Latest sensor data:", data); - }); -``` - -## ๐Ÿ”’ Security Notes - -- **Test mode** is enabled for development -- **Production** should use proper Firebase security rules -- **Credentials** are stored in `.env` file (keep secure) -- **WiFi credentials** are also in `.env` - -## ๐Ÿ“ˆ Next Steps - -1. **Set up Firebase security rules** for production -2. **Add data visualization** using Firebase data -3. **Implement data analytics** on logged sensor data -4. **Add alerts** for abnormal vital signs - -## ๐ŸŽฏ Expected Results - -After setup, you should see: - -- โœ… **Firebase logs** every 30 seconds when frontend connected -- โœ… **Complete sensor data** in Firebase Realtime Database -- โœ… **Automatic start/stop** based on frontend connection -- โœ… **Real-time monitoring** of vital signs - ---- - -**Need help?** Check the Serial Monitor for detailed error messages and connection status. diff --git a/Examples/esp32/calibration_analyzer.py b/Examples/esp32/calibration_analyzer.py new file mode 100644 index 000000000..c63d9ff42 --- /dev/null +++ b/Examples/esp32/calibration_analyzer.py @@ -0,0 +1,433 @@ +#!/usr/bin/env python3 +""" +ESP32 Sensor Calibration Data Analyzer + +This script analyzes the raw sensor data output from the ESP32 calibration file +and provides comprehensive calibration recommendations for: +- AD8232 ECG sensor +- HW-484 sound sensor (breathing detection) +- GSR sensor + +Usage: +1. Run the ESP32 calibration file and copy the Serial Monitor output +2. Save the output to a text file +3. Run this script: python calibration_analyzer.py +""" + +import sys +import re +import numpy as np +import matplotlib.pyplot as plt +from collections import defaultdict +import argparse +from datetime import datetime + +class SensorCalibrationAnalyzer: + def __init__(self): + self.data = { + 'ecg': {'raw': [], 'deviation': [], 'timestamps': []}, + 'gsr': {'raw': [], 'deviation': [], 'timestamps': []}, + 'resp': {'raw': [], 'deviation': [], 'timestamps': []} + } + self.baseline_results = {} + self.breath_analysis = {} + self.calibration_recommendations = {} + + def parse_calibration_data(self, filename): + """Parse the calibration output file and extract sensor data""" + print(f"๐Ÿ” Parsing calibration data from: {filename}") + + try: + with open(filename, 'r') as file: + lines = file.readlines() + except FileNotFoundError: + print(f"โŒ Error: File '{filename}' not found") + return False + + # Parse different types of lines + for line in lines: + line = line.strip() + + # Parse DATA lines (continuous monitoring) + if line.startswith('DATA:'): + self._parse_data_line(line) + + # Parse breath detection lines + elif 'BREATH IN detected!' in line or 'BREATH OUT detected!' in line: + self._parse_breath_line(line) + + # Parse baseline calibration results + elif 'Range:' in line and 'Span:' in line: + self._parse_baseline_line(line) + + print(f"โœ… Parsed {len(self.data['ecg']['raw'])} data points") + return True + + def _parse_data_line(self, line): + """Parse DATA lines from continuous monitoring""" + try: + # Format: DATA: timestamp, ecg_raw, ecg_dev, gsr_raw, gsr_dev, resp_raw, resp_dev + parts = line.split(': ')[1].split(', ') + timestamp = int(parts[0]) + ecg_raw = int(parts[1]) + ecg_dev = int(parts[2]) + gsr_raw = int(parts[3]) + gsr_dev = int(parts[4]) + resp_raw = int(parts[5]) + resp_dev = int(parts[6]) + + # Store data + self.data['ecg']['raw'].append(ecg_raw) + self.data['ecg']['deviation'].append(ecg_dev) + self.data['ecg']['timestamps'].append(timestamp) + + self.data['gsr']['raw'].append(gsr_raw) + self.data['gsr']['deviation'].append(gsr_dev) + self.data['gsr']['timestamps'].append(timestamp) + + self.data['resp']['raw'].append(resp_raw) + self.data['resp']['deviation'].append(resp_dev) + self.data['resp']['timestamps'].append(timestamp) + + except (IndexError, ValueError) as e: + print(f"โš ๏ธ Warning: Could not parse data line: {line[:50]}...") + + def _parse_breath_line(self, line): + """Parse breath detection lines""" + try: + # Extract breath type and values + if 'BREATH IN detected!' in line: + breath_type = 'IN' + else: + breath_type = 'BREATH OUT detected!' + + # Extract raw value and deviation + raw_match = re.search(r'Raw: (\d+)', line) + dev_match = re.search(r'Deviation: ([+-]\d+)', line) + + if raw_match and dev_match: + raw_val = int(raw_match.group(1)) + dev_val = int(dev_match.group(1)) + + if 'breath_in' not in self.breath_analysis: + self.breath_analysis['breath_in'] = {'raw': [], 'deviation': []} + if 'breath_out' not in self.breath_analysis: + self.breath_analysis['breath_out'] = {'raw': [], 'deviation': []} + + if breath_type == 'IN': + self.breath_analysis['breath_in']['raw'].append(raw_val) + self.breath_analysis['breath_in']['deviation'].append(dev_val) + else: + self.breath_analysis['breath_out']['raw'].append(raw_val) + self.breath_analysis['breath_out']['deviation'].append(dev_val) + + except Exception as e: + print(f"โš ๏ธ Warning: Could not parse breath line: {line[:50]}...") + + def _parse_baseline_line(self, line): + """Parse baseline calibration results""" + try: + # Extract sensor type and values + if 'ECG Sensor' in line: + sensor = 'ecg' + elif 'GSR Sensor' in line: + sensor = 'gsr' + elif 'Respiratory Sensor' in line: + sensor = 'resp' + else: + return + + # Extract range values + range_match = re.search(r'Range: (\d+) - (\d+)', line) + span_match = re.search(r'Span: (\d+)', line) + + if range_match and span_match: + min_val = int(range_match.group(1)) + max_val = int(range_match.group(2)) + span = int(span_match.group(1)) + + if sensor not in self.baseline_results: + self.baseline_results[sensor] = {} + + self.baseline_results[sensor] = { + 'min': min_val, + 'max': max_val, + 'span': span + } + + except Exception as e: + print(f"โš ๏ธ Warning: Could not parse baseline line: {line[:50]}...") + + def analyze_sensor_data(self): + """Perform comprehensive analysis of sensor data""" + print("\n๐Ÿ”ฌ Analyzing sensor data...") + + for sensor_type in ['ecg', 'gsr', 'resp']: + if not self.data[sensor_type]['raw']: + continue + + raw_data = np.array(self.data[sensor_type]['raw']) + dev_data = np.array(self.data[sensor_type]['deviation']) + + # Calculate statistics + stats = { + 'mean': np.mean(raw_data), + 'std': np.std(raw_data), + 'min': np.min(raw_data), + 'max': np.max(raw_data), + 'range': np.max(raw_data) - np.min(raw_data), + 'median': np.median(raw_data), + 'q25': np.percentile(raw_data, 25), + 'q75': np.percentile(raw_data, 75), + 'iqr': np.percentile(raw_data, 75) - np.percentile(raw_data, 25) + } + + # Calculate noise characteristics + stats['noise_level'] = stats['std'] + stats['signal_to_noise'] = stats['range'] / stats['std'] if stats['std'] > 0 else 0 + + # Store results + if sensor_type not in self.calibration_recommendations: + self.calibration_recommendations[sensor_type] = {} + + self.calibration_recommendations[sensor_type]['statistics'] = stats + + print(f" {sensor_type.upper()}: Mean={stats['mean']:.1f}, Std={stats['std']:.1f}, Range={stats['range']}") + + def analyze_breathing_patterns(self): + """Analyze breathing patterns from HW-484 sensor""" + print("\n๐Ÿซ Analyzing breathing patterns...") + + if not self.breath_analysis: + print(" โš ๏ธ No breath detection data found") + return + + breath_stats = {} + + for breath_type in ['breath_in', 'breath_out']: + if breath_type in self.breath_analysis and self.breath_analysis[breath_type]['raw']: + raw_vals = np.array(self.breath_analysis[breath_type]['raw']) + dev_vals = np.array(self.breath_analysis[breath_type]['deviation']) + + stats = { + 'count': len(raw_vals), + 'mean_raw': np.mean(raw_vals), + 'std_raw': np.std(raw_vals), + 'mean_deviation': np.mean(dev_vals), + 'std_deviation': np.std(dev_vals), + 'min_deviation': np.min(dev_vals), + 'max_deviation': np.max(dev_vals) + } + + breath_stats[breath_type] = stats + + print(f" {breath_type.replace('_', ' ').title()}: {stats['count']} breaths, " + f"Mean Dev: {stats['mean_deviation']:+.1f}, Std: {stats['std_deviation']:.1f}") + + # Calculate respiratory rate if we have enough data + if 'breath_in' in breath_stats and 'breath_out' in breath_stats: + total_breaths = breath_stats['breath_in']['count'] + breath_stats['breath_out']['count'] + if total_breaths > 0: + # Estimate respiratory rate (assuming 60-second analysis period) + estimated_rr = total_breaths # breaths per minute + print(f" Estimated Respiratory Rate: {estimated_rr} breaths/min") + + if estimated_rr < 8 or estimated_rr > 30: + print(f" โš ๏ธ Respiratory rate outside normal range (8-30 breaths/min)") + + self.calibration_recommendations['breathing'] = breath_stats + + def generate_calibration_recommendations(self): + """Generate comprehensive calibration recommendations""" + print("\n๐ŸŽฏ Generating calibration recommendations...") + + recommendations = {} + + for sensor_type in ['ecg', 'gsr', 'resp']: + if sensor_type not in self.calibration_recommendations: + continue + + stats = self.calibration_recommendations[sensor_type]['statistics'] + + if sensor_type == 'ecg': + # ECG recommendations + recommendations[sensor_type] = { + 'peak_threshold': int(stats['range'] / 3), + 'noise_threshold': int(stats['std'] * 2), + 'baseline_stability': 'Good' if stats['std'] < stats['range'] / 10 else 'Poor', + 'recommended_sampling_rate': '250Hz', + 'filtering_needed': stats['std'] > stats['range'] / 20 + } + + elif sensor_type == 'gsr': + # GSR recommendations + recommendations[sensor_type] = { + 'change_threshold': int(stats['range'] / 8), + 'noise_threshold': int(stats['std'] * 1.5), + 'baseline_stability': 'Good' if stats['std'] < stats['range'] / 15 else 'Poor', + 'recommended_sampling_rate': '10Hz', + 'filtering_needed': stats['std'] > stats['range'] / 30 + } + + elif sensor_type == 'resp': + # Respiratory recommendations + recommendations[sensor_type] = { + 'breath_threshold': int(stats['range'] / 4), + 'noise_threshold': int(stats['std'] * 2), + 'baseline_stability': 'Good' if stats['std'] < stats['range'] / 12 else 'Poor', + 'recommended_sampling_rate': '100Hz', + 'filtering_needed': stats['std'] > stats['range'] / 25 + } + + # Breathing pattern recommendations + if 'breathing' in self.calibration_recommendations: + breath_stats = self.calibration_recommendations['breathing'] + + if 'breath_in' in breath_stats and 'breath_out' in breath_stats: + # Calculate optimal thresholds + in_dev_mean = breath_stats['breath_in']['mean_deviation'] + out_dev_mean = breath_stats['breath_out']['mean_deviation'] + + recommendations['breathing'] = { + 'breath_in_threshold': int(abs(in_dev_mean) * 0.7), + 'breath_out_threshold': int(abs(out_dev_mean) * 0.7), + 'min_breath_interval': 1000, # 1 second + 'pattern_quality': 'Good' if abs(in_dev_mean - out_dev_mean) > 50 else 'Poor', + 'recommended_algorithm': 'Threshold-based with hysteresis' + } + + self.calibration_recommendations['recommendations'] = recommendations + return recommendations + + def print_calibration_report(self): + """Print comprehensive calibration report""" + print("\n" + "="*80) + print("๐Ÿ“Š ESP32 SENSOR CALIBRATION REPORT") + print("="*80) + + # Print sensor statistics + for sensor_type in ['ecg', 'gsr', 'resp']: + if sensor_type in self.calibration_recommendations: + stats = self.calibration_recommendations[sensor_type]['statistics'] + print(f"\n๐Ÿ”Œ {sensor_type.upper()} SENSOR ANALYSIS:") + print(f" Raw Range: {stats['min']} - {stats['max']} (Span: {stats['range']})") + print(f" Baseline: {stats['median']:.1f} (Median)") + print(f" Noise Level: ยฑ{stats['std']:.1f}") + print(f" Signal-to-Noise Ratio: {stats['signal_to_noise']:.2f}") + + # Print breathing analysis + if 'breathing' in self.calibration_recommendations: + print(f"\n๐Ÿซ BREATHING PATTERN ANALYSIS:") + breath_stats = self.calibration_recommendations['breathing'] + + for breath_type in ['breath_in', 'breath_out']: + if breath_type in breath_stats: + stats = breath_stats[breath_type] + print(f" {breath_type.replace('_', ' ').title()}:") + print(f" Count: {stats['count']}") + print(f" Mean Deviation: {stats['mean_deviation']:+.1f}") + print(f" Deviation Range: {stats['min_deviation']} to {stats['max_deviation']}") + + # Print recommendations + if 'recommendations' in self.calibration_recommendations: + print(f"\n๐ŸŽฏ CALIBRATION RECOMMENDATIONS:") + recs = self.calibration_recommendations['recommendations'] + + for sensor_type, rec in recs.items(): + if sensor_type == 'breathing': + print(f"\n ๐Ÿซ BREATHING DETECTION:") + print(f" Breath IN Threshold: {rec['breath_in_threshold']}") + print(f" Breath OUT Threshold: {rec['breath_out_threshold']}") + print(f" Pattern Quality: {rec['pattern_quality']}") + print(f" Algorithm: {rec['recommended_algorithm']}") + else: + print(f"\n ๐Ÿ”Œ {sensor_type.upper()} SENSOR:") + if 'peak_threshold' in rec: + print(f" Peak Threshold: {rec['peak_threshold']}") + if 'change_threshold' in rec: + print(f" Change Threshold: {rec['change_threshold']}") + if 'breath_threshold' in rec: + print(f" Breath Threshold: {rec['breath_threshold']}") + print(f" Baseline Stability: {rec['baseline_stability']}") + print(f" Filtering Needed: {'Yes' if rec['filtering_needed'] else 'No'}") + print(f" Recommended Sampling: {rec['recommended_sampling_rate']}") + + print(f"\n" + "="*80) + print("๐Ÿ“ NEXT STEPS:") + print("1. Update your ESP32 main.ino with the recommended thresholds") + print("2. Test the new thresholds with real subjects") + print("3. Fine-tune based on performance") + print("4. Consider implementing adaptive thresholds for different subjects") + print("="*80) + + def save_recommendations_to_file(self, filename): + """Save calibration recommendations to a file""" + try: + with open(filename, 'w') as f: + f.write("ESP32 Sensor Calibration Recommendations\n") + f.write("Generated on: " + datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\n\n") + + # Write recommendations in a format suitable for ESP32 code + f.write("// Copy these values to your ESP32 main.ino file\n\n") + + if 'recommendations' in self.calibration_recommendations: + recs = self.calibration_recommendations['recommendations'] + + for sensor_type, rec in recs.items(): + if sensor_type == 'breathing': + f.write(f"// Breathing Detection Thresholds\n") + f.write(f"const int BREATH_IN_THRESHOLD = {rec['breath_in_threshold']};\n") + f.write(f"const int BREATH_OUT_THRESHOLD = {rec['breath_out_threshold']};\n") + f.write(f"const int MIN_BREATH_INTERVAL = {rec['min_breath_interval']};\n\n") + else: + f.write(f"// {sensor_type.upper()} Sensor Thresholds\n") + if 'peak_threshold' in rec: + f.write(f"const int {sensor_type.upper()}_PEAK_THRESHOLD = {rec['peak_threshold']};\n") + if 'change_threshold' in rec: + f.write(f"const int {sensor_type.upper()}_CHANGE_THRESHOLD = {rec['change_threshold']};\n") + if 'breath_threshold' in rec: + f.write(f"const int {sensor_type.upper()}_BREATH_THRESHOLD = {rec['breath_threshold']};\n") + f.write("\n") + + f.write("// Additional Recommendations:\n") + f.write("// - Consider implementing adaptive thresholds\n") + f.write("// - Monitor baseline drift over time\n") + f.write("// - Implement sensor health checks\n") + + print(f"โœ… Recommendations saved to: {filename}") + + except Exception as e: + print(f"โŒ Error saving recommendations: {e}") + +def main(): + parser = argparse.ArgumentParser(description='ESP32 Sensor Calibration Data Analyzer') + parser.add_argument('filename', help='Path to the calibration data file') + parser.add_argument('--output', '-o', help='Output file for recommendations', default='calibration_recommendations.txt') + parser.add_argument('--plot', '-p', action='store_true', help='Generate plots of sensor data') + + args = parser.parse_args() + + # Create analyzer + analyzer = SensorCalibrationAnalyzer() + + # Parse data + if not analyzer.parse_calibration_data(args.filename): + sys.exit(1) + + # Analyze data + analyzer.analyze_sensor_data() + analyzer.analyze_breathing_patterns() + + # Generate recommendations + recommendations = analyzer.generate_calibration_recommendations() + + # Print report + analyzer.print_calibration_report() + + # Save recommendations + analyzer.save_recommendations_to_file(args.output) + + print(f"\n๐ŸŽ‰ Analysis complete! Check '{args.output}' for ESP32 code recommendations.") + +if __name__ == "__main__": + main() diff --git a/Examples/esp32/main.ino b/Examples/esp32/main.ino index 5b0b7ed5b..7d9b13fb9 100644 --- a/Examples/esp32/main.ino +++ b/Examples/esp32/main.ino @@ -3,6 +3,20 @@ #include #include "PanTompkins.h" +// Debug configuration - set to 0 to disable all debug prints +#define DEBUG_MODE 1 +#define DEBUG_INTERVAL 10000 // 10 seconds between comprehensive logs + +#if DEBUG_MODE + #define DEBUG_PRINT(x) Serial.print(x) + #define DEBUG_PRINTLN(x) Serial.println(x) + #define DEBUG_PRINTF(fmt, ...) Serial.printf(fmt, __VA_ARGS__) +#else + #define DEBUG_PRINT(x) + #define DEBUG_PRINTLN(x) + #define DEBUG_PRINTF(fmt, ...) +#endif + // --- WiFi Credentials --- const char* ssid = "Airtel_301"; const char* password = "Wifi@2025"; @@ -47,6 +61,17 @@ int respBuffer[SMOOTH_WINDOW] = {0}; int gsrIndex = 0; int respIndex = 0; +// HW-484 Respiratory Rate Detection Variables +const int RESP_BUFFER_SIZE = 50; // Buffer for breath pattern analysis +int respRawBuffer[RESP_BUFFER_SIZE] = {0}; +int respBufferIndex = 0; +unsigned long lastBreathTime = 0; +int breathCount = 0; +int currentRespRate = 16; // Default respiratory rate +bool breathDetected = false; +const int BREATH_THRESHOLD = 100; // ADC threshold for breath detection +const int MIN_BREATH_INTERVAL = 2000; // Minimum 2 seconds between breaths + // Sensor connection status (always true since we don't check) bool ecgSensorConnected = true; bool gsrSensorConnected = true; @@ -67,28 +92,48 @@ SensorData currentData; void onWebSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { switch (type) { case WStype_DISCONNECTED: - Serial.printf("๐Ÿ”Œ WebSocket client #%u disconnected\n", num); + DEBUG_PRINTF("๐Ÿ”Œ WebSocket client #%u disconnected\n", num); break; case WStype_CONNECTED: { - Serial.printf("๐Ÿ”Œ WebSocket client #%u connected from %s\n", num, webSocket.remoteIP(num).toString().c_str()); + DEBUG_PRINTF("๐Ÿ”Œ WebSocket client #%u connected from %s\n", num, webSocket.remoteIP(num).toString().c_str()); // Send a welcome message to confirm connection String welcomeMsg = "{\"type\":\"connection\",\"status\":\"connected\",\"message\":\"ESP32 WebSocket Server Ready\"}"; webSocket.sendTXT(num, welcomeMsg); + + // Send immediate test data to verify frontend is working + DEBUG_PRINTLN("๐Ÿš€ Sending immediate test data to verify frontend connection..."); + delay(100); // Small delay to ensure connection is stable + + // Send connection status message to set wsConnected = true + String connectionMsg = "{\"type\":\"connection\",\"status\":\"connected\",\"message\":\"ESP32 Production Server Ready\"}"; + webSocket.sendTXT(num, connectionMsg); + DEBUG_PRINTLN("๐Ÿ”Œ Sent connection status message"); + + // Send one sample of each data type to verify frontend processing + sendECGData(); + delay(50); + sendGSRData(); + delay(50); + sendRespiratoryData(); + delay(50); + sendHeartRateData(); + + DEBUG_PRINTLN("โœ… Initial test data sent to frontend"); break; } case WStype_TEXT: // Only log important messages, not every data packet if (length < 100) { // Only log short messages (likely commands) - Serial.printf("๐Ÿ“จ WebSocket client #%u sent: %s\n", num, payload); + DEBUG_PRINTF("๐Ÿ“จ WebSocket client #%u sent: %s\n", num, payload); } // Echo back for testing webSocket.sendTXT(num, (char*)payload); break; case WStype_BIN: - Serial.printf("๐Ÿ“ฆ WebSocket client #%u sent binary data (%d bytes)\n", num, length); + DEBUG_PRINTF("๐Ÿ“ฆ WebSocket client #%u sent binary data (%d bytes)\n", num, length); break; case WStype_ERROR: - Serial.printf("โŒ WebSocket client #%u error\n", num); + DEBUG_PRINTF("โŒ WebSocket client #%u error\n", num); break; case WStype_FRAGMENT_TEXT_START: case WStype_FRAGMENT_BIN_START: @@ -104,35 +149,7 @@ void sendData(const String& data) { webSocket.broadcastTXT(payload); } -// Test GSR sensor on startup -void testGSRSensor() { - Serial.println("\n=== GSR SENSOR TESTING ==="); - - // Test 1: Basic ADC reading - Serial.println("Test 1: Basic ADC Reading"); - for (int i = 0; i < 10; i++) { - int value = analogRead(GSR_PIN); - Serial.printf("Reading %d: %d (%.2fV)\n", i+1, value, (value * 3.3) / 4095.0); - delay(100); - } - - // Test 2: Touch test (should see change when touching electrodes) - Serial.println("\nTest 2: Touch Test - Touch the GSR electrodes now!"); - Serial.println("You should see values change when touching..."); - for (int i = 0; i < 20; i++) { - int value = analogRead(GSR_PIN); - Serial.printf("Touch test %d: %d\n", i+1, value); - delay(200); - } - - // Test 3: Different ADC configurations - Serial.println("\nTest 3: ADC Configuration Test"); - Serial.printf("Current ADC resolution: %d bits\n", analogReadResolution()); - Serial.printf("Current ADC attenuation: %d\n", analogReadAttenuation()); - - Serial.println("GSR sensor test completed!"); - Serial.println("==========================\n"); -} + // Helper function to calculate moving average (optimized) int calculateMovingAverage(int* buffer, int index, int windowSize) { @@ -157,6 +174,68 @@ int calculateMovingAverage(int* buffer, int index, int windowSize) { return sum / validSamples; } +// HW-484 Respiratory Rate Detection Function +// Based on sound level variations for breath in/out detection +int calculateRespiratoryRate(int rawValue, unsigned long timestamp) { + // Store raw value in circular buffer for pattern analysis + respRawBuffer[respBufferIndex] = rawValue; + respBufferIndex = (respBufferIndex + 1) % RESP_BUFFER_SIZE; + + // Calculate baseline (average of recent values) + int baseline = 0; + for (int i = 0; i < RESP_BUFFER_SIZE; i++) { + baseline += respRawBuffer[i]; + } + baseline /= RESP_BUFFER_SIZE; + + // Detect breath based on significant deviation from baseline + int deviation = abs(rawValue - baseline); + + if (deviation > BREATH_THRESHOLD && !breathDetected) { + // Check if enough time has passed since last breath + if (timestamp - lastBreathTime > MIN_BREATH_INTERVAL) { + breathDetected = true; + lastBreathTime = timestamp; + breathCount++; + + // Calculate respiratory rate based on recent breath intervals + if (breathCount > 1) { + // Simple moving average of recent breath intervals + static unsigned long breathIntervals[5] = {0}; + static int intervalIndex = 0; + + breathIntervals[intervalIndex] = timestamp - lastBreathTime; + intervalIndex = (intervalIndex + 1) % 5; + + // Calculate average interval and convert to breaths/min + unsigned long avgInterval = 0; + int validIntervals = 0; + for (int i = 0; i < 5; i++) { + if (breathIntervals[i] > 0) { + avgInterval += breathIntervals[i]; + validIntervals++; + } + } + + if (validIntervals > 0) { + avgInterval /= validIntervals; + currentRespRate = 60000 / avgInterval; // Convert ms to breaths/min + + // Ensure respiratory rate is within realistic range (8-30 breaths/min) + if (currentRespRate < 8) currentRespRate = 8; + if (currentRespRate > 30) currentRespRate = 30; + } + } + + DEBUG_PRINTF("๐Ÿซ Breath detected! Count: %d, Rate: %d breaths/min\n", breathCount, currentRespRate); + } + } else if (deviation <= BREATH_THRESHOLD) { + breathDetected = false; + } + + return currentRespRate; +} + // Simple function to read analog value (no validation needed) int readAnalogValue(int pin) { return analogRead(pin); @@ -168,12 +247,13 @@ void sendECGData() { jsonDoc["type"] = "ecg"; jsonDoc["value"] = currentData.ecg; // Raw 12-bit ADC value (0-4095) + jsonDoc["ecg"] = currentData.ecg; // Frontend expects this field jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization jsonDoc["sensorConnected"] = ecgSensorConnected; String jsonString; if (serializeJson(jsonDoc, jsonString) == 0) { - Serial.println("ERROR: Failed to serialize ECG JSON data"); + DEBUG_PRINTLN("ERROR: Failed to serialize ECG JSON data"); return; } @@ -186,12 +266,13 @@ void sendGSRData() { jsonDoc["type"] = "gsr"; jsonDoc["value"] = currentData.gsr; // Raw smoothed value (0-4095) + jsonDoc["gsr"] = currentData.gsr; // Frontend expects this field jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization jsonDoc["sensorConnected"] = gsrSensorConnected; String jsonString; if (serializeJson(jsonDoc, jsonString) == 0) { - Serial.println("ERROR: Failed to serialize GSR JSON data"); + DEBUG_PRINTLN("ERROR: Failed to serialize GSR JSON data"); return; } @@ -202,20 +283,23 @@ void sendGSRData() { void sendRespiratoryData() { StaticJsonDocument<256> jsonDoc; + // currentData.respiratory now contains the calculated respiratory rate from HW-484 + // No need for conversion - it's already in breaths/min + int respRate = currentData.respiratory; + jsonDoc["type"] = "respiratory"; - jsonDoc["value"] = currentData.respiratory; // Raw smoothed value (0-4095) + jsonDoc["value"] = respRate; // Respiratory rate in breaths/min + jsonDoc["respiratory"] = respRate; // Frontend expects this field jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization jsonDoc["sensorConnected"] = respSensorConnected; String jsonString; if (serializeJson(jsonDoc, jsonString) == 0) { - Serial.println("ERROR: Failed to serialize respiratory JSON data"); + DEBUG_PRINTLN("ERROR: Failed to serialize respiratory JSON data"); return; } sendData(jsonString); - - } // Function to send IBI data when heartbeat detected @@ -224,13 +308,14 @@ void sendIBIData() { jsonDoc["type"] = "ibi"; jsonDoc["value"] = currentData.ibi; // IBI in milliseconds - jsonDoc["hr"] = currentData.heartRate; // Heart rate in BPM + jsonDoc["hrv"] = currentData.ibi; // Frontend expects this field + jsonDoc["bpm"] = currentData.heartRate; // Frontend expects bpm, not hr jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization jsonDoc["sensorConnected"] = ecgSensorConnected; String jsonString; if (serializeJson(jsonDoc, jsonString) == 0) { - Serial.println("ERROR: Failed to serialize IBI JSON data"); + DEBUG_PRINTLN("ERROR: Failed to serialize IBI JSON data"); return; } @@ -244,12 +329,13 @@ void sendHeartRateData() { jsonDoc["type"] = "heartrate"; jsonDoc["bpm"] = currentData.heartRate; // Heart rate in BPM jsonDoc["ibi"] = currentData.ibi; // IBI in milliseconds + jsonDoc["hrv"] = currentData.ibi; // Also include HRV for consistency jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization jsonDoc["sensorConnected"] = ecgSensorConnected; String jsonString; if (serializeJson(jsonDoc, jsonString) == 0) { - Serial.println("ERROR: Failed to serialize heart rate JSON data"); + DEBUG_PRINTLN("ERROR: Failed to serialize heart rate JSON data"); return; } @@ -263,14 +349,14 @@ void setup() { analogReadResolution(12); // ESP32 has 12-bit ADC analogSetAttenuation(ADC_11db); // Set attenuation for 0-3.3V range - Serial.println("ESP32 Vital Signs Monitor Starting..."); - Serial.println("====================================="); + DEBUG_PRINTLN("ESP32 Vital Signs Monitor Starting..."); + DEBUG_PRINTLN("====================================="); // Pin configuration info - Serial.printf("ECG Sensor Pin: GPIO%d (ADC1_CH4)\n", ECG_PIN); - Serial.printf("GSR Sensor Pin: GPIO%d (ADC1_CH5)\n", GSR_PIN); - Serial.printf("RESP Sensor Pin: GPIO%d (ADC2_CH7)\n", RESP_PIN); - Serial.println(); + DEBUG_PRINTF("ECG Sensor Pin: GPIO%d (ADC1_CH4)\n", ECG_PIN); + DEBUG_PRINTF("GSR Sensor Pin: GPIO%d (ADC1_CH5)\n", GSR_PIN); + DEBUG_PRINTF("RESP Sensor Pin: GPIO%d (ADC2_CH7) - HW-484 Sound Sensor\n", RESP_PIN); + DEBUG_PRINTLN(); // Initialize smoothing buffers for (int i = 0; i < SMOOTH_WINDOW; i++) { @@ -278,19 +364,24 @@ void setup() { respBuffer[i] = 2048; // Mid-range value for 12-bit ADC } + // Initialize HW-484 respiratory detection buffer + for (int i = 0; i < RESP_BUFFER_SIZE; i++) { + respRawBuffer[i] = 2048; // Mid-range value for 12-bit ADC + } + // Test sensor pins with multiple readings - Serial.println("Testing sensor pins..."); - Serial.printf("ECG Pin %d: %d\n", ECG_PIN, analogRead(ECG_PIN)); + DEBUG_PRINTLN("Testing sensor pins..."); + DEBUG_PRINTF("ECG Pin %d: %d\n", ECG_PIN, analogRead(ECG_PIN)); // Enhanced GSR pin testing - Serial.printf("GSR Pin %d: ", GSR_PIN); + DEBUG_PRINTF("GSR Pin %d: ", GSR_PIN); int gsrTestValues[5] = {0}; for (int i = 0; i < 5; i++) { gsrTestValues[i] = analogRead(GSR_PIN); - Serial.printf("%d ", gsrTestValues[i]); + DEBUG_PRINTF("%d ", gsrTestValues[i]); delay(50); } - Serial.println(); + DEBUG_PRINTLN(); // Check if GSR is responding int gsrAvg = 0; @@ -300,65 +391,65 @@ void setup() { gsrAvg /= 5; if (gsrAvg == 0) { - Serial.println("โš ๏ธ WARNING: GSR sensor showing 0 - Check connections!"); - Serial.println(" - Verify GSR sensor is connected to GPIO33"); - Serial.println(" - Check if sensor has power (VCC and GND)"); - Serial.println(" - Try touching the sensor electrodes"); + DEBUG_PRINTLN("โš ๏ธ WARNING: GSR sensor showing 0 - Check connections!"); + DEBUG_PRINTLN(" - Verify GSR sensor is connected to GPIO33"); + DEBUG_PRINTLN(" - Check if sensor has power (VCC and GND)"); + DEBUG_PRINTLN(" - Try touching the sensor electrodes"); } else if (gsrAvg < 100) { - Serial.println("โš ๏ธ WARNING: GSR sensor showing very low values"); - Serial.println(" - Sensor may be disconnected or faulty"); - Serial.println(" - Check electrode contact"); - } else { - Serial.println("โœ… GSR sensor appears to be working"); + DEBUG_PRINTLN("โš ๏ธ WARNING: GSR sensor showing very low values"); + DEBUG_PRINTLN(" - Sensor may be disconnected or faulty"); + DEBUG_PRINTLN(" - Check electrode contact"); + } else { + DEBUG_PRINTLN("โœ… GSR sensor appears to be working"); } - Serial.printf("RESP Pin %d: %d\n", RESP_PIN, analogRead(RESP_PIN)); + DEBUG_PRINTF("RESP Pin %d: %d\n", RESP_PIN, analogRead(RESP_PIN)); - // Test respiratory sensor multiple times - Serial.println("Testing HW-484 respiratory sensor..."); + // Test HW-484 respiratory sensor multiple times + DEBUG_PRINTLN("Testing HW-484 respiratory sensor (sound-based breath detection)..."); for (int i = 0; i < 10; i++) { int respTest = analogRead(RESP_PIN); - Serial.printf("RESP Test #%d: %d\n", i+1, respTest); + DEBUG_PRINTF("RESP Test #%d: %d\n", i+1, respTest); delay(100); } // Initialize system - Serial.println("Initializing vital signs monitor..."); + DEBUG_PRINTLN("Initializing vital signs monitor..."); delay(1000); // Allow system to stabilize // Connect to WiFi with timeout WiFi.begin(ssid, password); - Serial.print("Connecting to WiFi..."); + DEBUG_PRINT("Connecting to WiFi..."); int wifiAttempts = 0; const int MAX_WIFI_ATTEMPTS = 20; // 10 seconds timeout while (WiFi.status() != WL_CONNECTED && wifiAttempts < MAX_WIFI_ATTEMPTS) { delay(500); - Serial.print("."); + DEBUG_PRINT("."); wifiAttempts++; } if (WiFi.status() != WL_CONNECTED) { - Serial.println("\nERROR: WiFi connection failed! Check credentials."); + DEBUG_PRINTLN("\nERROR: WiFi connection failed! Check credentials."); ESP.restart(); // Restart ESP32 if WiFi fails } - Serial.println("\nWiFi connected!"); - Serial.print("IP Address: "); - Serial.println(WiFi.localIP()); - Serial.println("Frontend should connect to: ws://" + WiFi.localIP().toString() + ":81"); + DEBUG_PRINTLN("\nWiFi connected!"); + DEBUG_PRINT("IP Address: "); + DEBUG_PRINTLN(WiFi.localIP()); + DEBUG_PRINTLN("Frontend should connect to: ws://" + WiFi.localIP().toString() + ":81"); // Start the WebSocket server webSocket.begin(); webSocket.onEvent(onWebSocketEvent); - Serial.println("ESP32 WebSocket server started on port 81"); - Serial.println("Waiting for client connections..."); + DEBUG_PRINTLN("ESP32 WebSocket server started on port 81"); + DEBUG_PRINTLN("Waiting for client connections..."); // Test the WebSocket server - Serial.println("WebSocket server status:"); - Serial.printf("- Server running: %s\n", webSocket.connectedClients() >= 0 ? "YES" : "NO"); - Serial.printf("- Connected clients: %d\n", webSocket.connectedClients()); + DEBUG_PRINTLN("WebSocket server status:"); + DEBUG_PRINTF("- Server running: %s\n", webSocket.connectedClients() >= 0 ? "YES" : "NO"); + DEBUG_PRINTF("- Connected clients: %d\n", webSocket.connectedClients()); } void loop() { @@ -366,42 +457,48 @@ void loop() { unsigned long currentTime = millis(); - // Comprehensive status update every 5 seconds + // Comprehensive status update every 10 seconds (reduced from 5) static unsigned long lastStatusTime = 0; - if (currentTime - lastStatusTime >= 5000) { + if (currentTime - lastStatusTime >= DEBUG_INTERVAL) { lastStatusTime = currentTime; - Serial.println("\n" + String("=", 60)); - Serial.println("๐Ÿ“Š COMPREHENSIVE STATUS UPDATE"); - Serial.println(String("=", 60)); + // Send connection status to keep frontend connected + if (webSocket.connectedClients() > 0) { + String statusMsg = "{\"type\":\"connection\",\"status\":\"connected\",\"message\":\"ESP32 Production Server Active\"}"; + webSocket.broadcastTXT(statusMsg); + } + + DEBUG_PRINTLN("\n" + String("=", 60)); + DEBUG_PRINTLN("๐Ÿ“Š COMPREHENSIVE STATUS UPDATE"); + DEBUG_PRINTLN(String("=", 60)); // Connection Status - Serial.println("๐Ÿ”Œ CONNECTION STATUS:"); - Serial.printf(" WiFi Status: %s\n", WiFi.status() == WL_CONNECTED ? "โœ… Connected" : "โŒ Disconnected"); - Serial.printf(" WiFi RSSI: %d dBm\n", WiFi.RSSI()); - Serial.printf(" IP Address: %s\n", WiFi.localIP().toString().c_str()); - Serial.printf(" WebSocket Clients: %d\n", webSocket.connectedClients()); + DEBUG_PRINTLN("๐Ÿ”Œ CONNECTION STATUS:"); + DEBUG_PRINTF(" WiFi Status: %s\n", WiFi.status() == WL_CONNECTED ? "โœ… Connected" : "โŒ Disconnected"); + DEBUG_PRINTF(" WiFi RSSI: %d dBm\n", WiFi.RSSI()); + DEBUG_PRINTF(" IP Address: %s\n", WiFi.localIP().toString().c_str()); + DEBUG_PRINTF(" WebSocket Clients: %d\n", webSocket.connectedClients()); // Sensor Data Summary - Serial.println("\n๐Ÿ“ก SENSOR DATA SUMMARY:"); - Serial.printf(" ECG: %d (Raw: %d)\n", ecgSample, analogRead(ECG_PIN)); - Serial.printf(" GSR: %d (Raw: %d, Filtered: %d)\n", gsrSample, gsrRawValue, gsrFilteredValue); - Serial.printf(" RESP: %d (Raw: %d)\n", respSample, analogRead(RESP_PIN)); + DEBUG_PRINTLN("\n๐Ÿ“ก SENSOR DATA SUMMARY:"); + DEBUG_PRINTF(" ECG: %d (Raw: %d)\n", ecgSample, analogRead(ECG_PIN)); + DEBUG_PRINTF(" GSR: %d (Raw: %d, Filtered: %d)\n", gsrSample, gsrRawValue, gsrFilteredValue); + DEBUG_PRINTF(" RESP: %d (Raw: %d)\n", respSample, analogRead(RESP_PIN)); // Data Transmission Stats - Serial.println("\n๐Ÿ“ค DATA TRANSMISSION:"); - Serial.printf(" Last ECG Send: %lu ms ago\n", currentTime - lastEcgTime); - Serial.printf(" Last GSR Send: %lu ms ago\n", currentTime - lastGsrTime); - Serial.printf(" Last RESP Send: %lu ms ago\n", currentTime - lastRespTime); - Serial.printf(" Last Data Send: %lu ms ago\n", currentTime - lastSendTime); + DEBUG_PRINTLN("\n๐Ÿ“ค DATA TRANSMISSION:"); + DEBUG_PRINTF(" Last ECG Send: %lu ms ago\n", currentTime - lastEcgTime); + DEBUG_PRINTF(" Last GSR Send: %lu ms ago\n", currentTime - lastGsrTime); + DEBUG_PRINTF(" Last RESP Send: %lu ms ago\n", currentTime - lastRespTime); + DEBUG_PRINTF(" Last Data Send: %lu ms ago\n", currentTime - lastSendTime); // Memory and Performance - Serial.println("\n๐Ÿ’พ SYSTEM STATUS:"); - Serial.printf(" Free Heap: %d bytes\n", ESP.getFreeHeap()); - Serial.printf(" Uptime: %lu seconds\n", currentTime / 1000); + DEBUG_PRINTLN("\n๐Ÿ’พ SYSTEM STATUS:"); + DEBUG_PRINTF(" Free Heap: %d bytes\n", ESP.getFreeHeap()); + DEBUG_PRINTF(" Uptime: %lu seconds\n", currentTime / 1000); - Serial.println(String("=", 60)); - Serial.println(); + DEBUG_PRINTLN(String("=", 60)); + DEBUG_PRINTLN(); } // Handle millis() overflow (occurs every ~49 days) @@ -436,16 +533,26 @@ void loop() { currentData.ibi = panTompkins.getIbi(); currentData.heartRate = panTompkins.getBPM(); + // Debug: Log heartbeat detection + DEBUG_PRINTF("๐Ÿ’“ Heartbeat detected! BPM: %d, IBI: %d ms\n", currentData.heartRate, currentData.ibi); + // Send IBI data immediately when detected sendIBIData(); + + // Also send heart rate data when beat is detected + sendHeartRateData(); } // Send ECG data immediately at 250Hz sendECGData(); - // Send continuous heart rate data (even when no beat detected) + // Send continuous heart rate data every few seconds (even when no beat detected) // This ensures frontend always has heart rate info - sendHeartRateData(); + static unsigned long lastHeartRateSend = 0; + if (currentTime - lastHeartRateSend >= 1000) { // Send every second + sendHeartRateData(); + lastHeartRateSend = currentTime; + } } // --- GSR Processing (10Hz) --- @@ -473,16 +580,14 @@ void loop() { if (currentTime - lastRespTime >= RESP_INTERVAL) { lastRespTime = currentTime; - // Read analog value directly + // Read analog value directly from HW-484 sound sensor respSample = readAnalogValue(RESP_PIN); - // Smooth respiratory data - respBuffer[respIndex] = respSample; - respIndex = (respIndex + 1) % SMOOTH_WINDOW; - int smoothedResp = calculateMovingAverage(respBuffer, respIndex, SMOOTH_WINDOW); + // Use the new breath detection algorithm for HW-484 + int calculatedRespRate = calculateRespiratoryRate(respSample, currentTime); - // Update current data - currentData.respiratory = smoothedResp; + // Update current data with calculated respiratory rate + currentData.respiratory = calculatedRespRate; // Send respiratory data immediately at 100Hz sendRespiratoryData(); diff --git a/Examples/esp32/requirements.txt b/Examples/esp32/requirements.txt new file mode 100644 index 000000000..4e7e7ae0d --- /dev/null +++ b/Examples/esp32/requirements.txt @@ -0,0 +1,4 @@ +numpy>=1.21.0 +matplotlib>=3.5.0 +argparse +datetime diff --git a/Examples/esp32/sensor_calibration.ino b/Examples/esp32/sensor_calibration.ino new file mode 100644 index 000000000..35e1a7c1c --- /dev/null +++ b/Examples/esp32/sensor_calibration.ino @@ -0,0 +1,370 @@ +/* + * ESP32 Sensor Calibration & Raw Data Logger + * + * This file is designed to: + * 1. Output raw ADC values from all sensors + * 2. Analyze breathing patterns from HW-484 sound sensor + * 3. Calibrate breath detection thresholds + * 4. Understand sensor baseline values and ranges + * + * Upload this file to your ESP32 and open Serial Monitor at 115200 baud + * Copy-paste the output for analysis + */ + +// --- Hardware Pin Configuration --- +const int ECG_PIN = 32; // GPIO32 - AD8232 ECG sensor +const int GSR_PIN = 33; // GPIO33 - GSR (Galvanic Skin Response) sensor +const int RESP_PIN = 27; // GPIO27 - HW-484 sound sensor for breathing + +// --- Calibration Constants --- +const int CALIBRATION_DURATION = 30000; // 30 seconds for baseline calibration +const int BREATH_ANALYSIS_DURATION = 60000; // 60 seconds for breath pattern analysis +const int SAMPLE_INTERVAL = 10; // 10ms = 100Hz sampling rate + +// --- Sensor Data Buffers --- +const int BUFFER_SIZE = 1000; // Store 1000 samples for analysis +int ecgBuffer[BUFFER_SIZE]; +int gsrBuffer[BUFFER_SIZE]; +int respBuffer[BUFFER_SIZE]; +int bufferIndex = 0; + +// --- Timing Variables --- +unsigned long startTime = 0; +unsigned long lastSampleTime = 0; +unsigned long calibrationStartTime = 0; +unsigned long breathAnalysisStartTime = 0; + +// --- Calibration State --- +enum CalibrationState { + BASELINE_CALIBRATION, + BREATH_ANALYSIS, + CONTINUOUS_MONITORING +}; +CalibrationState currentState = BASELINE_CALIBRATION; + +// --- Statistical Variables --- +int ecgMin = 4095, ecgMax = 0, ecgBaseline = 0; +int gsrMin = 4095, gsrMax = 0, gsrBaseline = 0; +int respMin = 4095, respMax = 0, respBaseline = 0; + +// --- Breath Detection Variables --- +int breathInThreshold = 0; +int breathOutThreshold = 0; +int breathInCount = 0; +int breathOutCount = 0; +unsigned long lastBreathTime = 0; +const int MIN_BREATH_INTERVAL = 1000; // 1 second minimum between breaths + +void setup() { + Serial.begin(115200); + delay(1000); + + // Configure ADC pins + analogReadResolution(12); // Set ADC resolution to 12 bits (0-4095) + + // Set attenuation for better voltage range + analogSetAttenuation(ADC_ATTEN_DB_11); // 0-3.3V range + + Serial.println("\n" + String("=").repeat(60)); + Serial.println("๐Ÿ”ฌ ESP32 SENSOR CALIBRATION & RAW DATA LOGGER"); + Serial.println("=" + String("=").repeat(59)); + Serial.println(); + + Serial.println("๐Ÿ“‹ CALIBRATION INSTRUCTIONS:"); + Serial.println("1. Ensure all sensors are properly connected"); + Serial.println("2. Keep subject still during baseline calibration (30s)"); + Serial.println("3. Perform breathing exercises during breath analysis (60s)"); + Serial.println("4. Monitor continuous data for real-time analysis"); + Serial.println(); + + Serial.println("๐Ÿ”Œ SENSOR CONNECTIONS:"); + Serial.println(" ECG (AD8232): GPIO32"); + Serial.println(" GSR: GPIO33"); + Serial.println(" RESP (HW-484): GPIO27"); + Serial.println(); + + Serial.println("โฑ๏ธ CALIBRATION PHASES:"); + Serial.println(" Phase 1: Baseline Calibration (30s) - Stay still"); + Serial.println(" Phase 2: Breath Analysis (60s) - Breathe normally"); + Serial.println(" Phase 3: Continuous Monitoring - Real-time data"); + Serial.println(); + + Serial.println("๐Ÿš€ Starting calibration in 5 seconds..."); + Serial.println(" Please ensure subject is ready and sensors are connected"); + Serial.println(); + + for (int i = 5; i > 0; i--) { + Serial.printf(" %d...\n", i); + delay(1000); + } + + Serial.println("๐ŸŽฏ STARTING BASELINE CALIBRATION"); + Serial.println(" Please remain STILL for the next 30 seconds"); + Serial.println(); + + startTime = millis(); + calibrationStartTime = millis(); + currentState = BASELINE_CALIBRATION; + + // Initialize buffers + for (int i = 0; i < BUFFER_SIZE; i++) { + ecgBuffer[i] = 0; + gsrBuffer[i] = 0; + respBuffer[i] = 0; + } +} + +void loop() { + unsigned long currentTime = millis(); + + // Sample sensors at regular intervals + if (currentTime - lastSampleTime >= SAMPLE_INTERVAL) { + lastSampleTime = currentTime; + + // Read raw sensor values + int ecgRaw = analogRead(ECG_PIN); + int gsrRaw = analogRead(GSR_PIN); + int respRaw = analogRead(RESP_PIN); + + // Store in circular buffer + ecgBuffer[bufferIndex] = ecgRaw; + gsrBuffer[bufferIndex] = gsrRaw; + respBuffer[bufferIndex] = respRaw; + bufferIndex = (bufferIndex + 1) % BUFFER_SIZE; + + // Update min/max values + updateMinMax(ecgRaw, gsrRaw, respRaw); + + // Process based on current state + switch (currentState) { + case BASELINE_CALIBRATION: + handleBaselineCalibration(currentTime); + break; + case BREATH_ANALYSIS: + handleBreathAnalysis(currentTime, respRaw); + break; + case CONTINUOUS_MONITORING: + handleContinuousMonitoring(currentTime, ecgRaw, gsrRaw, respRaw); + break; + } + } +} + +void updateMinMax(int ecgRaw, int gsrRaw, int respRaw) { + // ECG min/max + if (ecgRaw < ecgMin) ecgMin = ecgRaw; + if (ecgRaw > ecgMax) ecgMax = ecgRaw; + + // GSR min/max + if (gsrRaw < gsrMin) gsrMin = gsrRaw; + if (gsrRaw > gsrMax) gsrMax = gsrRaw; + + // Respiratory min/max + if (respRaw < respMin) respMin = respRaw; + if (respRaw > respMax) respMax = respRaw; +} + +void handleBaselineCalibration(unsigned long currentTime) { + unsigned long elapsed = currentTime - calibrationStartTime; + unsigned long remaining = CALIBRATION_DURATION - elapsed; + + // Print progress every 5 seconds + if (elapsed % 5000 < SAMPLE_INTERVAL) { + Serial.printf("โณ Baseline Calibration: %lu seconds remaining\n", remaining / 1000); + } + + // Check if baseline calibration is complete + if (elapsed >= CALIBRATION_DURATION) { + completeBaselineCalibration(); + } +} + +void completeBaselineCalibration() { + Serial.println("\n" + String("=").repeat(60)); + Serial.println("โœ… BASELINE CALIBRATION COMPLETE"); + Serial.println("=" + String("=").repeat(59)); + + // Calculate baselines from collected data + calculateBaselines(); + + // Print baseline results + Serial.println("\n๐Ÿ“Š BASELINE CALIBRATION RESULTS:"); + Serial.println(" ECG Sensor (AD8232):"); + Serial.printf(" Range: %d - %d (Span: %d)\n", ecgMin, ecgMax, ecgMax - ecgMin); + Serial.printf(" Baseline: %d\n", ecgBaseline); + Serial.printf(" Noise Level: ยฑ%d\n", (ecgMax - ecgMin) / 2); + + Serial.println("\n GSR Sensor:"); + Serial.printf(" Range: %d - %d (Span: %d)\n", gsrMin, gsrMax, gsrMax - gsrMin); + Serial.printf(" Baseline: %d\n", gsrBaseline); + Serial.printf(" Noise Level: ยฑ%d\n", (gsrMax - gsrMin) / 2); + + Serial.println("\n Respiratory Sensor (HW-484):"); + Serial.printf(" Range: %d - %d (Span: %d)\n", respMin, respMax, respMax - respMin); + Serial.printf(" Baseline: %d\n", respBaseline); + Serial.printf(" Noise Level: ยฑ%d\n", (respMax - respMin) / 2); + + Serial.println("\n๐ŸŽฏ RECOMMENDED THRESHOLDS:"); + Serial.printf(" Breath Detection Threshold: %d\n", (respMax - respMin) / 4); + Serial.printf(" GSR Change Threshold: %d\n", (gsrMax - gsrMin) / 8); + Serial.printf(" ECG Peak Threshold: %d\n", (ecgMax - ecgMin) / 3); + + Serial.println("\n๐Ÿซ Starting Breath Analysis Phase"); + Serial.println(" Please breathe NORMALLY for the next 60 seconds"); + Serial.println(" Focus on steady, regular breathing patterns"); + Serial.println(); + + // Reset for breath analysis + breathAnalysisStartTime = millis(); + currentState = BREATH_ANALYSIS; + + // Reset breath counters + breathInCount = 0; + breathOutCount = 0; + lastBreathTime = 0; +} + +void calculateBaselines() { + // Calculate median values as baselines (more robust than mean) + ecgBaseline = calculateMedian(ecgBuffer, BUFFER_SIZE); + gsrBaseline = calculateMedian(gsrBuffer, BUFFER_SIZE); + respBaseline = calculateMedian(respBuffer, BUFFER_SIZE); +} + +int calculateMedian(int* buffer, int size) { + // Create a copy for sorting + int tempBuffer[size]; + for (int i = 0; i < size; i++) { + tempBuffer[i] = buffer[i]; + } + + // Simple bubble sort (for small arrays) + for (int i = 0; i < size - 1; i++) { + for (int j = 0; j < size - i - 1; j++) { + if (tempBuffer[j] > tempBuffer[j + 1]) { + int temp = tempBuffer[j]; + tempBuffer[j] = tempBuffer[j + 1]; + tempBuffer[j + 1] = temp; + } + } + } + + // Return median + return tempBuffer[size / 2]; +} + +void handleBreathAnalysis(unsigned long currentTime, int respRaw) { + unsigned long elapsed = currentTime - breathAnalysisStartTime; + unsigned long remaining = BREATH_ANALYSIS_DURATION - elapsed; + + // Print progress every 10 seconds + if (elapsed % 10000 < SAMPLE_INTERVAL) { + Serial.printf("โณ Breath Analysis: %lu seconds remaining\n", remaining / 1000); + } + + // Analyze breathing pattern + analyzeBreathingPattern(respRaw, currentTime); + + // Check if breath analysis is complete + if (elapsed >= BREATH_ANALYSIS_DURATION) { + completeBreathAnalysis(); + } +} + +void analyzeBreathingPattern(int respRaw, unsigned long currentTime) { + // Calculate deviation from baseline + int deviation = respRaw - respBaseline; + int absDeviation = abs(deviation); + + // Dynamic threshold based on baseline noise + int breathThreshold = (respMax - respMin) / 4; + + // Detect breath in/out based on deviation direction and magnitude + if (absDeviation > breathThreshold && (currentTime - lastBreathTime) > MIN_BREATH_INTERVAL) { + if (deviation > 0) { + // Positive deviation = breath in (sound level increases) + breathInCount++; + Serial.printf("๐Ÿซ BREATH IN detected! Raw: %d, Deviation: +%d\n", respRaw, deviation); + } else { + // Negative deviation = breath out (sound level decreases) + breathOutCount++; + Serial.printf("๐Ÿซ BREATH OUT detected! Raw: %d, Deviation: %d\n", respRaw, deviation); + } + lastBreathTime = currentTime; + } +} + +void completeBreathAnalysis() { + Serial.println("\n" + String("=").repeat(60)); + Serial.println("โœ… BREATH ANALYSIS COMPLETE"); + Serial.println("=" + String("=").repeat(59)); + + Serial.println("\n๐Ÿ“Š BREATHING PATTERN ANALYSIS:"); + Serial.printf(" Total Breaths Detected: %d\n", breathInCount + breathOutCount); + Serial.printf(" Breaths In: %d\n", breathInCount); + Serial.printf(" Breaths Out: %d\n", breathOutCount); + + if (breathInCount > 0 && breathOutCount > 0) { + float avgBreathInterval = (float)BREATH_ANALYSIS_DURATION / (breathInCount + breathOutCount); + float respiratoryRate = 60000.0 / avgBreathInterval; // breaths per minute + + Serial.printf(" Average Breath Interval: %.1f ms\n", avgBreathInterval); + Serial.printf(" Calculated Respiratory Rate: %.1f breaths/min\n", respiratoryRate); + + Serial.println("\n๐ŸŽฏ BREATH DETECTION CALIBRATION:"); + Serial.printf(" Current Threshold: %d\n", (respMax - respMin) / 4); + Serial.printf(" Recommended Range: %d - %d\n", (respMax - respMin) / 6, (respMax - respMin) / 3); + + if (respiratoryRate < 8 || respiratoryRate > 30) { + Serial.println(" โš ๏ธ Respiratory rate outside normal range (8-30 breaths/min)"); + Serial.println(" Consider adjusting sensor placement or sensitivity"); + } + } + + Serial.println("\n๐Ÿ”„ Starting Continuous Monitoring Mode"); + Serial.println(" Real-time sensor data will now be displayed"); + Serial.println(" Press Ctrl+C to stop monitoring"); + Serial.println(); + + currentState = CONTINUOUS_MONITORING; +} + +void handleContinuousMonitoring(unsigned long currentTime, int ecgRaw, int gsrRaw, int respRaw) { + // Calculate deviations from baseline + int ecgDeviation = ecgRaw - ecgBaseline; + int gsrDeviation = gsrRaw - gsrBaseline; + int respDeviation = respRaw - respBaseline; + + // Print formatted data every 100ms (10Hz display rate) + static unsigned long lastDisplayTime = 0; + if (currentTime - lastDisplayTime >= 100) { + lastDisplayTime = currentTime; + + // Format: Timestamp, ECG_Raw, ECG_Dev, GSR_Raw, GSR_Dev, RESP_Raw, RESP_Dev + Serial.printf("DATA: %lu, %d, %+d, %d, %+d, %d, %+d\n", + currentTime, + ecgRaw, ecgDeviation, + gsrRaw, gsrDeviation, + respRaw, respDeviation); + } + + // Real-time breath detection + int breathThreshold = (respMax - respMin) / 4; + if (abs(respDeviation) > breathThreshold && (currentTime - lastBreathTime) > MIN_BREATH_INTERVAL) { + if (respDeviation > 0) { + Serial.printf("๐Ÿซ LIVE: Breath IN - Raw: %d, Dev: +%d\n", respRaw, respDeviation); + } else { + Serial.printf("๐Ÿซ LIVE: Breath OUT - Raw: %d, Dev: %d\n", respRaw, respDeviation); + } + lastBreathTime = currentTime; + } +} + +// Utility function to print sensor status +void printSensorStatus() { + Serial.println("\n๐Ÿ“ก SENSOR STATUS:"); + Serial.printf(" ECG (GPIO32): %d\n", analogRead(ECG_PIN)); + Serial.printf(" GSR (GPIO33): %d\n", analogRead(GSR_PIN)); + Serial.printf(" RESP (GPIO27): %d\n", analogRead(RESP_PIN)); + Serial.println(); +} diff --git a/Examples/esp32/setup_firebase.py b/Examples/esp32/setup_firebase.py deleted file mode 100644 index 97b6e2732..000000000 --- a/Examples/esp32/setup_firebase.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env python3 -""" -Firebase Setup Script for ESP32 Vital Signs Monitor -This script helps you set up Firebase and update the ESP32 code with your credentials. -""" - -import os -import re -import json -from pathlib import Path - -def read_env_file(): - """Read the .env file and return a dictionary of variables.""" - env_vars = {} - env_file = Path('.env') - - if not env_file.exists(): - print("โŒ .env file not found!") - return None - - with open(env_file, 'r') as f: - for line in f: - line = line.strip() - if line and not line.startswith('#') and '=' in line: - key, value = line.split('=', 1) - env_vars[key] = value - - return env_vars - -def update_esp32_code(env_vars): - """Update the ESP32 main.ino file with Firebase credentials.""" - ino_file = Path('main.ino') - - if not ino_file.exists(): - print("โŒ main.ino file not found!") - return False - - # Read the current file - with open(ino_file, 'r') as f: - content = f.read() - - # Update Firebase configuration - replacements = { - 'your-api-key-here': env_vars.get('FIREBASE_API_KEY', 'your-api-key-here'), - 'your-database-url-here': env_vars.get('FIREBASE_DATABASE_URL', 'your-database-url-here'), - 'your-email@example.com': env_vars.get('FIREBASE_USER_EMAIL', 'your-email@example.com'), - 'your-password-here': env_vars.get('FIREBASE_USER_PASSWORD', 'your-password-here'), - 'Airtel_301': env_vars.get('WIFI_SSID', 'Airtel_301'), - 'Wifi@2025': env_vars.get('WIFI_PASSWORD', 'Wifi@2025') - } - - # Apply replacements - for old, new in replacements.items(): - content = content.replace(old, new) - - # Write back to file - with open(ino_file, 'w') as f: - f.write(content) - - print("โœ… ESP32 code updated with your credentials!") - return True - -def validate_firebase_credentials(env_vars): - """Validate that Firebase credentials are properly set.""" - required_vars = [ - 'FIREBASE_API_KEY', - 'FIREBASE_DATABASE_URL', - 'FIREBASE_USER_EMAIL', - 'FIREBASE_USER_PASSWORD' - ] - - missing_vars = [] - for var in required_vars: - if not env_vars.get(var) or env_vars[var] == f'your-{var.lower().replace("firebase_", "").replace("_", "-")}-here': - missing_vars.append(var) - - if missing_vars: - print(f"โŒ Missing or invalid Firebase credentials: {', '.join(missing_vars)}") - return False - - print("โœ… Firebase credentials look good!") - return True - -def print_setup_instructions(): - """Print setup instructions for Firebase.""" - print("\n" + "="*60) - print("๐Ÿ”ฅ FIREBASE SETUP INSTRUCTIONS") - print("="*60) - print("\n1. Go to Firebase Console: https://console.firebase.google.com/") - print("2. Create a new project or select existing one") - print("3. Enable Realtime Database:") - print(" - Go to Realtime Database") - print(" - Click 'Create Database'") - print(" - Choose 'Start in test mode' (for development)") - print("4. Get your credentials:") - print(" - Go to Project Settings > General") - print(" - Copy 'Web API Key'") - print(" - Go to Realtime Database") - print(" - Copy the database URL") - print("5. Update the .env file with your credentials") - print("6. Run this script again to update the ESP32 code") - print("\n" + "="*60) - -def main(): - print("๐Ÿš€ ESP32 Firebase Setup Script") - print("="*40) - - # Check if .env file exists - env_vars = read_env_file() - if not env_vars: - print_setup_instructions() - return - - # Validate credentials - if not validate_firebase_credentials(env_vars): - print_setup_instructions() - return - - # Update ESP32 code - if update_esp32_code(env_vars): - print("\n๐ŸŽ‰ Setup complete! Your ESP32 is ready to log to Firebase.") - print("\n๐Ÿ“‹ Next steps:") - print("1. Install Firebase library in Arduino IDE:") - print(" - Tools > Manage Libraries") - print(" - Search: 'Firebase ESP32 Client'") - print(" - Install by 'Mobizt'") - print("2. Upload the updated main.ino to your ESP32") - print("3. Connect your frontend to see Firebase logging every 30 seconds") - print("4. Check Firebase Console > Realtime Database > sensor_logs") - else: - print("โŒ Failed to update ESP32 code") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/Examples/esp32/test_websocket.ino b/Examples/esp32/test_websocket.ino new file mode 100644 index 000000000..16bffbc6c --- /dev/null +++ b/Examples/esp32/test_websocket.ino @@ -0,0 +1,538 @@ +/* + * ESP32 WebSocket Test Server with Mock Data + * ========================================== + * + * PURPOSE: Test your main frontend UI components with realistic mock data + * - Sends same JSON format as real sensors + * - Tests ECG plot, heart rate cards, GSR display, respiratory metrics + * - Verifies frontend data updates and real-time responsiveness + * + * USAGE: + * 1. Flash this to ESP32 + * 2. Open your main frontend app + * 3. Connect to ESP32 WebSocket (ws://[ESP32_IP]:81) + * 4. Watch all UI components update with mock data + * + * EXPECTED RESULTS: + * - ECG plot shows smooth sine wave + * - Heart rate card shows 60-100 BPM + * - GSR card shows 1-20 values + * - Respiratory card shows breathing pattern + * - All cards update in real-time + */ + +#include +#include +#include + +// --- WiFi Credentials --- +const char* ssid = "Airtel_301"; +const char* password = "Wifi@2025"; + +// Create a WebSocketsServer on port 81 +WebSocketsServer webSocket = WebSocketsServer(81); + +// Mock data generation variables +unsigned long mockStartTime = 0; +int mockHeartRate = 72; +int mockRespRate = 16; +int mockGSR = 8; +int mockECG = 2000; +int mockIBI = 833; // 60 BPM = 1000ms, 72 BPM โ‰ˆ 833ms + +// Sweeping test variables for wide range testing +bool sweepingMode = true; // Enable sweeping for testing +unsigned long sweepStartTime = 0; +int sweepDirection = 1; // 1 = increasing, -1 = decreasing +const int SWEEP_DURATION = 30000; // 30 seconds per direction + +// Data transmission timing +unsigned long lastEcgTime = 0; +unsigned long lastGsrTime = 0; +unsigned long lastRespTime = 0; +unsigned long lastHeartRateTime = 0; +unsigned long lastStatusTime = 0; + +// Intervals for different data types +const unsigned long ECG_INTERVAL = 4; // 4ms = 250Hz +const unsigned long GSR_INTERVAL = 100; // 100ms = 10Hz +const unsigned long RESP_INTERVAL = 10; // 10ms = 100Hz +const unsigned long HEART_RATE_INTERVAL = 1000; // 1 second +const unsigned long STATUS_INTERVAL = 5000; // 5 seconds + +void onWebSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { + switch (type) { + case WStype_DISCONNECTED: + Serial.printf("๐Ÿ”Œ WebSocket client #%u disconnected\n", num); + break; + case WStype_CONNECTED: { + Serial.printf("๐Ÿ”Œ WebSocket client #%u connected from %s\n", num, webSocket.remoteIP(num).toString().c_str()); + // Send a welcome message to confirm connection + String welcomeMsg = "{\"type\":\"connection\",\"status\":\"connected\",\"message\":\"ESP32 WebSocket Test Server Ready\"}"; + webSocket.sendTXT(num, welcomeMsg); + + // Send immediate test data to verify frontend is working + Serial.println("๐Ÿš€ Sending immediate test data to verify frontend connection..."); + delay(100); // Small delay to ensure connection is stable + + // Send connection status message to set wsConnected = true + String connectionMsg = "{\"type\":\"connection\",\"status\":\"connected\",\"message\":\"ESP32 Test Server Ready\"}"; + webSocket.sendTXT(num, connectionMsg); + Serial.println("๐Ÿ”Œ Sent connection status message"); + + // Send one sample of each data type + sendMockECGData(); + delay(50); + sendMockGSRData(); + delay(50); + sendMockRespiratoryData(); + delay(50); + sendMockHeartRateData(); + + Serial.println("โœ… Initial test data sent to frontend"); + break; + } + case WStype_TEXT: + // Log received messages + Serial.printf("๐Ÿ“จ WebSocket client #%u sent: %s\n", num, payload); + // Echo back for testing + webSocket.sendTXT(num, (char*)payload); + break; + case WStype_BIN: + Serial.printf("๐Ÿ“ฆ WebSocket client #%u sent binary data (%d bytes)\n", num, length); + break; + case WStype_ERROR: + Serial.printf("โŒ WebSocket client #%u error\n", num); + break; + case WStype_FRAGMENT_TEXT_START: + case WStype_FRAGMENT_BIN_START: + case WStype_FRAGMENT: + case WStype_FRAGMENT_FIN: + break; + } +} + +// Function to send data to all connected clients +void sendData(const String& data) { + String payload = data; // Create a non-const copy + webSocket.broadcastTXT(payload); +} + +// Generate realistic mock ECG data (sine wave with noise + sweeping) +int generateMockECG() { + // Create a realistic ECG-like waveform + float time = (millis() - mockStartTime) / 1000.0; // Time in seconds + float frequency = 1.2; // 72 BPM = 1.2 Hz + + // Base sine wave for heart rhythm + float baseSignal = sin(2 * PI * frequency * time) * 800; + + // Add some noise for realism + int noise = random(-50, 50); + + // Add sweeping component for testing wide ranges + int sweepValue = 0; + if (sweepingMode) { + unsigned long sweepTime = millis() - sweepStartTime; + if (sweepTime > SWEEP_DURATION) { + sweepDirection *= -1; // Reverse direction + sweepStartTime = millis(); + } + + // Sweep across full ECG range (800-3500) + float sweepProgress = (float)(sweepTime % SWEEP_DURATION) / SWEEP_DURATION; + if (sweepDirection == 1) { + sweepValue = 800 + (int)(sweepProgress * 2700); // 800 to 3500 + } else { + sweepValue = 3500 - (int)(sweepProgress * 2700); // 3500 to 800 + } + } + + // Combine base signal with sweeping value + int ecgValue = (int)(baseSignal + sweepValue + noise); + if (ecgValue < 800) ecgValue = 800; + if (ecgValue > 3500) ecgValue = 3500; + + // Store the current ECG value for status updates + mockECG = ecgValue; + + return ecgValue; +} + +// Generate realistic mock GSR data (with sweeping for testing) +int generateMockGSR() { + // Add sweeping component for testing wide ranges + int sweepValue = 0; + if (sweepingMode) { + unsigned long sweepTime = millis() - sweepStartTime; + float sweepProgress = (float)(sweepTime % SWEEP_DURATION) / SWEEP_DURATION; + + if (sweepDirection == 1) { + sweepValue = (int)(sweepProgress * 18); // 0 to 18 + } else { + sweepValue = 18 - (int)(sweepProgress * 18); // 18 to 0 + } + } + + // GSR should sweep from 2 to 20 ยตS for clear testing + int baseGSR = 2 + sweepValue; // Start at 2, sweep to 20 + int variation = random(-1, 2); // Small variation + int gsrValue = baseGSR + variation; + + // Ensure values stay within reasonable range (1-20) + if (gsrValue < 1) gsrValue = 1; + if (gsrValue > 20) gsrValue = 20; + + return gsrValue; +} + +// Generate realistic mock respiratory data (with sweeping for testing) +int generateMockRespiratory() { + // Add sweeping component for testing wide ranges + int sweepValue = 0; + if (sweepingMode) { + unsigned long sweepTime = millis() - sweepStartTime; + float sweepProgress = (float)(sweepTime % SWEEP_DURATION) / SWEEP_DURATION; + + if (sweepDirection == 1) { + sweepValue = (int)(sweepProgress * 8); // 0 to 8 breaths/min + } else { + sweepValue = 8 - (int)(sweepProgress * 8); // 8 to 0 breaths/min + } + } + + // Base respiratory rate should be 12-20 breaths/min + int baseRespRate = 12 + sweepValue; // Start at 12, sweep to 20 + + // Add some realistic variation + int variation = random(-1, 2); + int respRate = baseRespRate + variation; + + // Ensure respiratory rate stays within reasonable range (12-20) + if (respRate < 12) respRate = 12; + if (respRate > 20) respRate = 20; + + return respRate; // Return breaths per minute, not raw ADC value +} + +// Generate realistic mock heart rate and IBI (with sweeping for testing) +void generateMockHeartRate() { + // Add sweeping component for testing wide ranges + int sweepValue = 0; + if (sweepingMode) { + unsigned long sweepTime = millis() - sweepStartTime; + float sweepProgress = (float)(sweepTime % SWEEP_DURATION) / SWEEP_DURATION; + + if (sweepDirection == 1) { + sweepValue = (int)(sweepProgress * 40); // 0 to 40 + } else { + sweepValue = 40 - (int)(sweepProgress * 40); // 40 to 0 + } + } + + // Heart rate should sweep from 65 to 100 BPM for clear testing + int variation = random(-2, 3); + mockHeartRate = 65 + sweepValue + variation; // Start at 65, sweep to 100 + + // Ensure heart rate stays within reasonable range (60-100) + if (mockHeartRate < 60) mockHeartRate = 60; + if (mockHeartRate > 100) mockHeartRate = 100; + + // Calculate IBI from heart rate (IBI = 60000 / BPM) + mockIBI = 60000 / mockHeartRate; + + // Add some realistic variation to IBI + int ibiVariation = random(-20, 21); + mockIBI += ibiVariation; + + // Ensure IBI stays within reasonable range (400-1200ms) + if (mockIBI < 400) mockIBI = 400; + if (mockIBI > 1200) mockIBI = 1200; +} + +// Send mock ECG data +void sendMockECGData() { + StaticJsonDocument<256> jsonDoc; + + jsonDoc["type"] = "ecg"; + jsonDoc["value"] = mockECG; + jsonDoc["ecg"] = mockECG; // Frontend expects this field + jsonDoc["timestamp"] = millis(); + jsonDoc["sensorConnected"] = true; + + String jsonString; + if (serializeJson(jsonDoc, jsonString) == 0) { + Serial.println("ERROR: Failed to serialize ECG JSON data"); + return; + } + + sendData(jsonString); + + // Debug: Log what we're sending + Serial.printf("๐Ÿ“Š Sent ECG: %d (value: %d, ecg: %d)\n", mockECG, mockECG, mockECG); +} + +// Send mock GSR data +void sendMockGSRData() { + StaticJsonDocument<256> jsonDoc; + + jsonDoc["type"] = "gsr"; + jsonDoc["value"] = mockGSR; + jsonDoc["gsr"] = mockGSR; // Frontend expects this field + jsonDoc["timestamp"] = millis(); + jsonDoc["sensorConnected"] = true; + + String jsonString; + if (serializeJson(jsonDoc, jsonString) == 0) { + Serial.println("ERROR: Failed to serialize GSR JSON data"); + return; + } + + sendData(jsonString); + + // Debug: Log what we're sending + Serial.printf("๐Ÿ“Š Sent GSR: %d (value: %d, gsr: %d)\n", mockGSR, mockGSR, mockGSR); +} + +// Send mock respiratory data +void sendMockRespiratoryData() { + StaticJsonDocument<256> jsonDoc; + + int respValue = generateMockRespiratory(); // Generate once to avoid double generation + + jsonDoc["type"] = "respiratory"; + jsonDoc["value"] = respValue; + jsonDoc["respiratory"] = respValue; // Frontend expects this field + jsonDoc["timestamp"] = millis(); + jsonDoc["sensorConnected"] = true; + + String jsonString; + if (serializeJson(jsonDoc, jsonString) == 0) { + Serial.println("ERROR: Failed to serialize respiratory JSON data"); + return; + } + + sendData(jsonString); + + // Debug: Log what we're sending + Serial.printf("๐Ÿ“Š Sent Respiratory: %d (value: %d, respiratory: %d)\n", respValue, respValue, respValue); +} + +// Send mock heart rate data +void sendMockHeartRateData() { + StaticJsonDocument<256> jsonDoc; + + jsonDoc["type"] = "heartrate"; + jsonDoc["bpm"] = mockHeartRate; + jsonDoc["ibi"] = mockIBI; + jsonDoc["hrv"] = mockIBI; // Also include HRV for consistency + jsonDoc["timestamp"] = millis(); + jsonDoc["sensorConnected"] = true; + + String jsonString; + if (serializeJson(jsonDoc, jsonString) == 0) { + Serial.println("ERROR: Failed to serialize heart rate JSON data"); + return; + } + + sendData(jsonString); + + // Debug: Log what we're sending + Serial.printf("๐Ÿ“Š Sent Heart Rate: %d BPM, IBI: %d ms (bpm: %d, hrv: %d)\n", mockHeartRate, mockIBI, mockHeartRate, mockIBI); +} + +// Send mock IBI data +void sendMockIBIData() { + StaticJsonDocument<256> jsonDoc; + + jsonDoc["type"] = "ibi"; + jsonDoc["value"] = mockIBI; + jsonDoc["hrv"] = mockIBI; // Frontend expects this field + jsonDoc["bpm"] = mockHeartRate; // Frontend expects bpm, not hr + jsonDoc["timestamp"] = millis(); + jsonDoc["sensorConnected"] = true; + + String jsonString; + if (serializeJson(jsonDoc, jsonString) == 0) { + Serial.println("ERROR: Failed to serialize IBI JSON data"); + return; + } + + sendData(jsonString); + + // Debug: Log what we're sending + Serial.printf("๐Ÿ“Š Sent IBI: %d ms, HR: %d BPM (hrv: %d, bpm: %d)\n", mockIBI, mockHeartRate, mockIBI, mockHeartRate); +} + +void setup() { + Serial.begin(115200); + + Serial.println("ESP32 WebSocket Test Server Starting..."); + Serial.println("====================================="); + Serial.println("This is a TEST SERVER with MOCK DATA"); + Serial.println("No real sensors connected - testing frontend communication only"); + Serial.println(); + + // Initialize mock data timing + mockStartTime = millis(); + sweepStartTime = millis(); // Initialize sweep timing + + // Connect to WiFi with timeout + WiFi.begin(ssid, password); + Serial.print("Connecting to WiFi..."); + + int wifiAttempts = 0; + const int MAX_WIFI_ATTEMPTS = 20; // 10 seconds timeout + + while (WiFi.status() != WL_CONNECTED && wifiAttempts < MAX_WIFI_ATTEMPTS) { + delay(500); + Serial.print("."); + wifiAttempts++; + } + + if (WiFi.status() != WL_CONNECTED) { + Serial.println("\nERROR: WiFi connection failed! Check credentials."); + ESP.restart(); // Restart ESP32 if WiFi fails + } + + Serial.println("\nWiFi connected!"); + Serial.print("IP Address: "); + Serial.println(WiFi.localIP()); + Serial.println("Frontend should connect to: ws://" + WiFi.localIP().toString() + ":81"); + + // Start the WebSocket server + webSocket.begin(); + webSocket.onEvent(onWebSocketEvent); + Serial.println("ESP32 WebSocket test server started on port 81"); + Serial.println("Waiting for client connections..."); + Serial.println(); + + // Display test data format + Serial.println("๐Ÿ“Š MOCK DATA FORMAT:"); + Serial.println(" ECG: 250Hz, values 800-3500 (realistic waveform)"); + Serial.println(" GSR: 10Hz, values 1-20 (stable with small variations)"); + Serial.println(" Respiratory: 100Hz, values 800-2500 (breathing pattern)"); + Serial.println(" Heart Rate: 1Hz, values 60-100 BPM"); + Serial.println(" IBI: Variable, calculated from heart rate"); + Serial.println(); +} + +void loop() { + webSocket.loop(); // Handle WebSocket events + + unsigned long currentTime = millis(); + + // Handle millis() overflow (occurs every ~49 days) + static unsigned long lastLoopTime = 0; + if (currentTime < lastLoopTime) { + // Overflow occurred, reset timing variables + lastEcgTime = 0; + lastGsrTime = 0; + lastRespTime = 0; + lastHeartRateTime = 0; + lastStatusTime = 0; + mockStartTime = millis(); + } + lastLoopTime = currentTime; + + // --- Mock ECG Data (250Hz) --- + if (currentTime - lastEcgTime >= ECG_INTERVAL) { + lastEcgTime = currentTime; + + // Generate realistic ECG waveform + mockECG = generateMockECG(); + + // Send ECG data + sendMockECGData(); + } + + // --- Mock GSR Data (10Hz) --- + if (currentTime - lastGsrTime >= GSR_INTERVAL) { + lastGsrTime = currentTime; + + // Generate realistic GSR data + mockGSR = generateMockGSR(); + + // Send GSR data + sendMockGSRData(); + } + + // --- Mock Respiratory Data (100Hz) --- + if (currentTime - lastRespTime >= RESP_INTERVAL) { + lastRespTime = currentTime; + + // Generate realistic respiratory data + int respValue = generateMockRespiratory(); + + // Send respiratory data + sendMockRespiratoryData(); + } + + // --- Mock Heart Rate Data (1Hz) --- + if (currentTime - lastHeartRateTime >= HEART_RATE_INTERVAL) { + lastHeartRateTime = currentTime; + + // Generate realistic heart rate and IBI + generateMockHeartRate(); + + // Send heart rate data + sendMockHeartRateData(); + + // Also send IBI data + sendMockIBIData(); + } + + // --- Status Update (5 seconds) --- + if (currentTime - lastStatusTime >= STATUS_INTERVAL) { + lastStatusTime = currentTime; + + // Send connection status to keep frontend connected + if (webSocket.connectedClients() > 0) { + String statusMsg = "{\"type\":\"connection\",\"status\":\"connected\",\"message\":\"ESP32 Test Server Active\"}"; + webSocket.broadcastTXT(statusMsg); + } + + Serial.println("\n" + String("=", 60)); + Serial.println("๐Ÿ“Š MOCK DATA STATUS UPDATE"); + Serial.println(String("=", 60)); + + // Connection Status + Serial.println("๐Ÿ”Œ CONNECTION STATUS:"); + Serial.printf(" WiFi Status: %s\n", WiFi.status() == WL_CONNECTED ? "โœ… Connected" : "โŒ Disconnected"); + Serial.printf(" WiFi RSSI: %d dBm\n", WiFi.RSSI()); + Serial.printf(" IP Address: %s\n", WiFi.localIP().toString().c_str()); + Serial.printf(" WebSocket Clients: %d\n", webSocket.connectedClients()); + + // Mock Data Summary + Serial.println("\n๐Ÿ“ก MOCK DATA SUMMARY:"); + Serial.printf(" ECG: %d (250Hz) - Sweeping: %s\n", mockECG, sweepingMode ? "ENABLED" : "DISABLED"); + Serial.printf(" GSR: %d (10Hz) - Sweeping: %s\n", mockGSR, sweepingMode ? "ENABLED" : "DISABLED"); + Serial.printf(" Heart Rate: %d BPM (1Hz) - Sweeping: %s\n", mockHeartRate, sweepingMode ? "ENABLED" : "DISABLED"); + Serial.printf(" IBI: %d ms\n", mockIBI); + + // Sweeping Status + if (sweepingMode) { + unsigned long sweepTime = millis() - sweepStartTime; + float sweepProgress = (float)(sweepTime % SWEEP_DURATION) / SWEEP_DURATION; + Serial.printf(" Sweep Direction: %s (%.1f%% complete)\n", + sweepDirection == 1 ? "INCREASING" : "DECREASING", + sweepProgress * 100); + } + + // Data Transmission Stats + Serial.println("\n๐Ÿ“ค DATA TRANSMISSION:"); + Serial.printf(" Last ECG Send: %lu ms ago\n", currentTime - lastEcgTime); + Serial.printf(" Last GSR Send: %lu ms ago\n", currentTime - lastGsrTime); + Serial.printf(" Last RESP Send: %lu ms ago\n", currentTime - lastRespTime); + Serial.printf(" Last Heart Rate Send: %lu ms ago\n", currentTime - lastHeartRateTime); + + // System Status + Serial.println("\n๐Ÿ’พ SYSTEM STATUS:"); + Serial.printf(" Free Heap: %d bytes\n", ESP.getFreeHeap()); + Serial.printf(" Uptime: %lu seconds\n", currentTime / 1000); + Serial.printf(" Mock Data Running: %lu seconds\n", (currentTime - mockStartTime) / 1000); + + Serial.println(String("=", 60)); + Serial.println(); + } +} diff --git a/Examples/install-firebase.ps1 b/Examples/install-firebase.ps1 new file mode 100644 index 000000000..2cacf6f02 --- /dev/null +++ b/Examples/install-firebase.ps1 @@ -0,0 +1,74 @@ +# Firebase Installation and Dependency Resolution Script +# This script installs Firebase and resolves any dependency conflicts + +Write-Host "๐Ÿ”ฅ Installing Firebase and resolving dependencies..." -ForegroundColor Green + +# Check if npm is available +try { + $npmVersion = npm --version + Write-Host "โœ… npm version: $npmVersion" -ForegroundColor Green +} catch { + Write-Host "โŒ npm not found. Please install Node.js and npm first." -ForegroundColor Red + exit 1 +} + +# Check if Firebase is already installed +$firebaseInstalled = npm list firebase 2>$null +if ($firebaseInstalled -and $firebaseInstalled -notlike "*empty*") { + Write-Host "โœ… Firebase is already installed" -ForegroundColor Green +} else { + Write-Host "๐Ÿ“ฆ Installing Firebase..." -ForegroundColor Yellow + + # Install Firebase + npm install firebase@^10.7.1 + + if ($LASTEXITCODE -eq 0) { + Write-Host "โœ… Firebase installed successfully" -ForegroundColor Green + } else { + Write-Host "โŒ Failed to install Firebase" -ForegroundColor Red + exit 1 + } +} + +# Check for dependency conflicts +Write-Host "๐Ÿ” Checking for dependency conflicts..." -ForegroundColor Yellow +npm audit --audit-level moderate + +# Install any missing peer dependencies +Write-Host "๐Ÿ“ฆ Installing peer dependencies..." -ForegroundColor Yellow +npm install + +# Verify Firebase installation +Write-Host "๐Ÿ” Verifying Firebase installation..." -ForegroundColor Yellow +$firebaseCheck = npm list firebase 2>$null +if ($firebaseCheck -and $firebaseCheck -notlike "*empty*") { + Write-Host "โœ… Firebase verification successful" -ForegroundColor Green + Write-Host "๐Ÿ“‹ Firebase version: $(npm list firebase --depth=0 | Select-String 'firebase@')" -ForegroundColor Cyan +} else { + Write-Host "โŒ Firebase verification failed" -ForegroundColor Red + exit 1 +} + +# Check for TypeScript compatibility +Write-Host "๐Ÿ” Checking TypeScript compatibility..." -ForegroundColor Yellow +$tsCheck = npm list typescript 2>$null +if ($tsCheck -and $tsCheck -notlike "*empty*") { + Write-Host "โœ… TypeScript is available" -ForegroundColor Green +} else { + Write-Host "โš ๏ธ TypeScript not found, but Firebase should still work" -ForegroundColor Yellow +} + +# Check for React compatibility +Write-Host "๐Ÿ” Checking React compatibility..." -ForegroundColor Yellow +$reactCheck = npm list react 2>$null +if ($reactCheck -and $reactCheck -notlike "*empty*") { + Write-Host "โœ… React is available" -ForegroundColor Green +} else { + Write-Host "โš ๏ธ React not found, but Firebase should still work" -ForegroundColor Yellow +} + +Write-Host "๐ŸŽ‰ Firebase installation and dependency resolution complete!" -ForegroundColor Green +Write-Host "๐Ÿ“‹ Next steps:" -ForegroundColor Cyan +Write-Host " 1. Update your .env file with Firebase credentials" -ForegroundColor White +Write-Host " 2. Run: python setup_firebase.py" -ForegroundColor White +Write-Host " 3. Start your development server: npm run dev:clean" -ForegroundColor White \ No newline at end of file diff --git a/Examples/package-lock.json b/Examples/package-lock.json index 4ac72fd1a..49efdf37f 100644 --- a/Examples/package-lock.json +++ b/Examples/package-lock.json @@ -9,10 +9,10 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@angular/animations": "^18.2.8", - "@angular/common": "^18.2.8", - "@angular/core": "^18.2.8", - "@angular/forms": "^18.2.8", + "@angular/animations": "^16.2.12", + "@angular/common": "^16.2.12", + "@angular/core": "^16.2.12", + "@angular/forms": "^16.2.12", "@angular/material": "^18.2.8", "@emotion/react": "^11.13.3", "@emotion/server": "^11.11.0", @@ -29,6 +29,7 @@ "cors": "^2.8.5", "country-flag-icons": "^1.5.7", "express": "^4.17.1", + "firebase": "^10.7.1", "follow-redirects": "^1.15.9", "morgan": "^1.10.0", "node-html-parser": "^6.1.13", @@ -36,8 +37,8 @@ "react-dom": "19.0.0", "react-helmet": "^6.1.0", "react-markdown": "^9.0.3", - "react-router": "^7.1.1", - "react-router-dom": "^7.1.1", + "react-router": "^6.22.3", + "react-router-dom": "^6.22.3", "react-syntax-highlighter": "^15.6.1", "react-transition-group": "^4.4.5", "rehype-raw": "^7.0.0", @@ -59,6 +60,7 @@ "@types/express": "^4.17.7", "@types/follow-redirects": "^1.14.4", "@types/node": "^22.7.6", + "@types/nodemon": "^1.19.6", "@types/prismjs": "^1.16.1", "@types/react-dom": "19.0.2", "@types/react-helmet": "^6.1.6", @@ -81,7 +83,7 @@ "pretty-quick": "^3.1.1", "rimraf": "^3.0.2", "sass": "^1.49.9", - "sass-loader": "^10.4.1", + "sass-loader": "^16.0.5", "sitemap": "^6.3.2", "style-loader": "^3.3.1", "ts-loader": "^9.4.2", @@ -97,8 +99,8 @@ "webpack-node-externals": "^3.0.0" }, "engines": { - "node": ">=22.13.0", - "npm": ">=10.9.2" + "node": ">=18.18.0", + "npm": ">=10.9.1" } }, "node_modules/@ampproject/remapping": { @@ -106,6 +108,7 @@ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -114,135 +117,82 @@ "node": ">=6.0.0" } }, - "node_modules/@ampproject/remapping/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/@angular/animations": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.8.tgz", - "integrity": "sha512-dMSn2hg70siv3lhP+vqhMbgc923xw6XBUvnpCPEzhZqFHvPXfh/LubmsD5RtqHmjWebXtgVcgS+zg3Gq3jB2lg==", + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-16.2.12.tgz", + "integrity": "sha512-MD0ElviEfAJY8qMOd6/jjSSvtqER2RDAi0lxe6EtUacC1DHCYkaPrKW4vLqY+tmZBg1yf+6n+uS77pXcHHcA3w==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" - }, - "peerDependencies": { - "@angular/core": "18.2.8" - } - }, - "node_modules/@angular/animations/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/@angular/cdk": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.8.tgz", - "integrity": "sha512-J8A2FkwTBzLleAEWz6EgW73dEoeq87GREBPjTv8+2JV09LX+V3hnbgNk6zWq5k4OXtQNg9WrWP9QyRbUyA597g==", - "license": "MIT", - "peer": true, - "dependencies": { - "tslib": "^2.3.0" - }, - "optionalDependencies": { - "parse5": "^7.1.2" + "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "^18.0.0 || ^19.0.0", - "@angular/core": "^18.0.0 || ^19.0.0", - "rxjs": "^6.5.3 || ^7.4.0" + "@angular/core": "16.2.12" } }, - "node_modules/@angular/cdk/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true - }, "node_modules/@angular/common": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.8.tgz", - "integrity": "sha512-TYsKtE5nVaIScWSLGSO34Skc+s3hB/BujSddnfQHoNFvPT/WR0dfmdlpVCTeLj+f50htFoMhW11tW99PbK+whQ==", + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-16.2.12.tgz", + "integrity": "sha512-B+WY/cT2VgEaz9HfJitBmgdk4I333XG/ybC98CMC4Wz8E49T8yzivmmxXB3OD6qvjcOB6ftuicl6WBqLbZNg2w==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "18.2.8", + "@angular/core": "16.2.12", "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/common/node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" - }, "node_modules/@angular/core": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.8.tgz", - "integrity": "sha512-NwIuX/Iby1jT6Iv1/s6S3wOFf8xfuQR3MPGvKhGgNtjXLbHG+TXceK9+QPZC0s9/Z8JR/hz+li34B79GrIKgUg==", + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-16.2.12.tgz", + "integrity": "sha512-GLLlDeke/NjroaLYOks0uyzFVo6HyLl7VOm0K1QpLXnYvW63W9Ql/T3yguRZa7tRkOAeFZ3jw+1wnBD4O8MoUA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.14.10" + "zone.js": "~0.13.0" } }, - "node_modules/@angular/core/node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" - }, "node_modules/@angular/forms": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.8.tgz", - "integrity": "sha512-JCLki7KC6D5vF6dE6yGlBmW33khIgpHs8N9SzuiJtkQqNDTIQA8cPsGV6qpLpxflxASynQOX5lDkWYdQyfm77Q==", + "version": "16.2.12", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-16.2.12.tgz", + "integrity": "sha512-1Eao89hlBgLR3v8tU91vccn21BBKL06WWxl7zLpQmG6Hun+2jrThgOE4Pf3os4fkkbH4Apj0tWL2fNIWe/blbw==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + "node": "^16.14.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "18.2.8", - "@angular/core": "18.2.8", - "@angular/platform-browser": "18.2.8", + "@angular/common": "16.2.12", + "@angular/core": "16.2.12", + "@angular/platform-browser": "16.2.12", "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/forms/node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" - }, "node_modules/@angular/material": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.2.8.tgz", - "integrity": "sha512-wQGMVsfQ9lQfih2VsWAvV4z3S3uBxrxc61owlE+K0T1BxH9u/jo3A/rnRitIdvR/L4NnYlfhCnmrW9K+Pl+WCg==", + "version": "18.2.14", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.2.14.tgz", + "integrity": "sha512-28pxzJP49Mymt664WnCtPkKeg7kXUsQKTKGf/Kl95rNTEdTJLbnlcc8wV0rT0yQNR7kXgpfBnG7h0ETLv/iu5Q==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "^18.0.0 || ^19.0.0", - "@angular/cdk": "18.2.8", + "@angular/cdk": "18.2.14", "@angular/common": "^18.0.0 || ^19.0.0", "@angular/core": "^18.0.0 || ^19.0.0", "@angular/forms": "^18.0.0 || ^19.0.0", @@ -250,79 +200,47 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/material/node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" - }, - "node_modules/@angular/platform-browser": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.8.tgz", - "integrity": "sha512-EPai4ZPqSq3ilLJUC85kPi9wo5j5suQovwtgRyjM/75D9Qy4TV19g8hkVM5Co/zrltO8a2G6vDscCNI5BeGw2A==", - "license": "MIT", - "peer": true, - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^18.19.1 || ^20.11.1 || >=22.0.0" - }, - "peerDependencies": { - "@angular/animations": "18.2.8", - "@angular/common": "18.2.8", - "@angular/core": "18.2.8" - }, - "peerDependenciesMeta": { - "@angular/animations": { - "optional": true - } - } - }, - "node_modules/@angular/platform-browser/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true - }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", - "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", - "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.0", - "@babel/generator": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.0", - "@babel/parser": "^7.26.0", - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -341,94 +259,47 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/@babel/core/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/core/node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } + "license": "MIT" }, "node_modules/@babel/generator": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", - "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", - "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", - "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.3" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", - "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -437,33 +308,19 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", - "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", + "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/traverse": "^7.25.9", + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.27.1", "semver": "^6.3.1" }, "engines": { @@ -474,13 +331,14 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", - "integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "regexpu-core": "^6.1.1", + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", "semver": "^6.3.1" }, "engines": { @@ -491,72 +349,68 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz", - "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "resolve": "^1.22.10" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", - "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" }, "engines": { "node": ">=6.9.0" @@ -566,35 +420,38 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", - "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", - "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-wrap-function": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -604,14 +461,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", - "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -620,90 +478,84 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", - "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", - "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", - "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", + "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", - "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz", + "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.0" + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", - "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.28.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -713,13 +565,14 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", - "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -729,12 +582,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", - "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -744,12 +598,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", - "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -759,14 +614,15 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", - "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -776,13 +632,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", - "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", + "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -796,6 +653,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" }, @@ -804,12 +662,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", - "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -819,12 +678,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -834,12 +694,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -849,12 +710,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", - "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -868,6 +730,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -880,12 +743,13 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", - "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -895,14 +759,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", - "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", + "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-remap-async-to-generator": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.28.0" }, "engines": { "node": ">=6.9.0" @@ -912,14 +777,15 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", - "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-remap-async-to-generator": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -929,12 +795,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", - "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -944,12 +811,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", - "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", + "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -959,13 +827,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", - "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -975,13 +844,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", - "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", + "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -991,17 +861,18 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", - "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.0.tgz", + "integrity": "sha512-IjM1IoJNw72AZFlj33Cu8X0q2XK/6AaVC3jQu+cgQ5lThWD5ajnuUAml80dqRmOhmPkTH8uAwnpMu9Rvj0LTRA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", - "@babel/traverse": "^7.25.9", - "globals": "^11.1.0" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.28.0" }, "engines": { "node": ">=6.9.0" @@ -1011,13 +882,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", - "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/template": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1027,12 +899,14 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", - "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", + "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.0" }, "engines": { "node": ">=6.9.0" @@ -1042,13 +916,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", - "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1058,12 +933,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", - "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1073,13 +949,14 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", - "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1089,12 +966,30 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", - "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" }, "engines": { "node": ">=6.9.0" @@ -1104,13 +999,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", - "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1120,12 +1015,13 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", - "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1135,13 +1031,14 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", - "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1151,14 +1048,15 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", - "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1168,12 +1066,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", - "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1183,12 +1082,13 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", - "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1198,12 +1098,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", - "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1213,12 +1114,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", - "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1228,13 +1130,14 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", - "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1244,14 +1147,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", - "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-simple-access": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1261,15 +1164,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", - "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1279,13 +1183,14 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", - "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1295,13 +1200,14 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", - "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1311,12 +1217,13 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", - "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1326,12 +1233,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", - "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1341,12 +1249,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", - "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1356,14 +1265,17 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", - "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.0.tgz", + "integrity": "sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/plugin-transform-parameters": "^7.25.9" + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.0" }, "engines": { "node": ">=6.9.0" @@ -1373,13 +1285,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", - "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1389,12 +1302,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", - "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1404,13 +1318,14 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", - "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1420,12 +1335,13 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", - "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1435,13 +1351,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", - "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1451,14 +1368,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", - "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1468,12 +1386,13 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", - "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1483,12 +1402,13 @@ } }, "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.9.tgz", - "integrity": "sha512-Ncw2JFsJVuvfRsa2lSHiC55kETQVLSnsYGQ1JDDwkUeWGTL/8Tom8aLTnlqgoeuopWrbbGndrc9AlLYrIosrow==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.27.1.tgz", + "integrity": "sha512-edoidOjl/ZxvYo4lSBOQGDSyToYVkTAwyVoa2tkuYTSmjrB1+uAedoL5iROVLXkxH+vRgA7uP4tMg2pUJpZ3Ug==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1498,12 +1418,13 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", - "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", + "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1513,16 +1434,17 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", - "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", + "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/plugin-syntax-jsx": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1532,12 +1454,13 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz", - "integrity": "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", + "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.25.9" + "@babel/plugin-transform-react-jsx": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1547,13 +1470,14 @@ } }, "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz", - "integrity": "sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", + "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1563,13 +1487,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", - "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", + "version": "7.28.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.1.tgz", + "integrity": "sha512-P0QiV/taaa3kXpLY+sXla5zec4E+4t4Aqc9ggHlfZ7a2cp8/x/Gv08jfwEtn9gnnYIMvHx6aoOZ8XJL8eU71Dg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "regenerator-transform": "^0.15.2" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1579,13 +1503,14 @@ } }, "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", - "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1595,12 +1520,13 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", - "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1610,12 +1536,13 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", - "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1625,13 +1552,14 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", - "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1641,12 +1569,13 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", - "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1656,12 +1585,13 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", - "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1671,12 +1601,13 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", - "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1686,16 +1617,17 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.9.tgz", - "integrity": "sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz", + "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/plugin-syntax-typescript": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1705,12 +1637,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", - "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1720,13 +1653,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", - "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1736,13 +1670,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", - "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1752,13 +1687,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", - "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1768,79 +1704,81 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", - "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.26.0", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.0.tgz", + "integrity": "sha512-VmaxeGOwuDqzLl5JUkIRM1X2Qu2uKGxHEQWh+cvvbl7JuJRgKGJSfsEF/bUaxFhJl/XAyxBe7q7qSuTbKFuCyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.26.0", - "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.25.9", - "@babel/plugin-transform-async-generator-functions": "^7.25.9", - "@babel/plugin-transform-async-to-generator": "^7.25.9", - "@babel/plugin-transform-block-scoped-functions": "^7.25.9", - "@babel/plugin-transform-block-scoping": "^7.25.9", - "@babel/plugin-transform-class-properties": "^7.25.9", - "@babel/plugin-transform-class-static-block": "^7.26.0", - "@babel/plugin-transform-classes": "^7.25.9", - "@babel/plugin-transform-computed-properties": "^7.25.9", - "@babel/plugin-transform-destructuring": "^7.25.9", - "@babel/plugin-transform-dotall-regex": "^7.25.9", - "@babel/plugin-transform-duplicate-keys": "^7.25.9", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-dynamic-import": "^7.25.9", - "@babel/plugin-transform-exponentiation-operator": "^7.25.9", - "@babel/plugin-transform-export-namespace-from": "^7.25.9", - "@babel/plugin-transform-for-of": "^7.25.9", - "@babel/plugin-transform-function-name": "^7.25.9", - "@babel/plugin-transform-json-strings": "^7.25.9", - "@babel/plugin-transform-literals": "^7.25.9", - "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", - "@babel/plugin-transform-member-expression-literals": "^7.25.9", - "@babel/plugin-transform-modules-amd": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.25.9", - "@babel/plugin-transform-modules-systemjs": "^7.25.9", - "@babel/plugin-transform-modules-umd": "^7.25.9", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-new-target": "^7.25.9", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", - "@babel/plugin-transform-numeric-separator": "^7.25.9", - "@babel/plugin-transform-object-rest-spread": "^7.25.9", - "@babel/plugin-transform-object-super": "^7.25.9", - "@babel/plugin-transform-optional-catch-binding": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9", - "@babel/plugin-transform-parameters": "^7.25.9", - "@babel/plugin-transform-private-methods": "^7.25.9", - "@babel/plugin-transform-private-property-in-object": "^7.25.9", - "@babel/plugin-transform-property-literals": "^7.25.9", - "@babel/plugin-transform-regenerator": "^7.25.9", - "@babel/plugin-transform-regexp-modifiers": "^7.26.0", - "@babel/plugin-transform-reserved-words": "^7.25.9", - "@babel/plugin-transform-shorthand-properties": "^7.25.9", - "@babel/plugin-transform-spread": "^7.25.9", - "@babel/plugin-transform-sticky-regex": "^7.25.9", - "@babel/plugin-transform-template-literals": "^7.25.9", - "@babel/plugin-transform-typeof-symbol": "^7.25.9", - "@babel/plugin-transform-unicode-escapes": "^7.25.9", - "@babel/plugin-transform-unicode-property-regex": "^7.25.9", - "@babel/plugin-transform-unicode-regex": "^7.25.9", - "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.0", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.28.0", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.28.0", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.0", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.6", - "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.38.1", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", "semver": "^6.3.1" }, "engines": { @@ -1855,6 +1793,7 @@ "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", @@ -1865,17 +1804,18 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.9.tgz", - "integrity": "sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.27.1.tgz", + "integrity": "sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-transform-react-display-name": "^7.25.9", - "@babel/plugin-transform-react-jsx": "^7.25.9", - "@babel/plugin-transform-react-jsx-development": "^7.25.9", - "@babel/plugin-transform-react-pure-annotations": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.27.1", + "@babel/plugin-transform-react-jsx": "^7.27.1", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1885,16 +1825,17 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz", - "integrity": "sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", + "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-syntax-jsx": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.25.9", - "@babel/plugin-transform-typescript": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1904,69 +1845,54 @@ } }, "node_modules/@babel/runtime": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", - "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", + "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "node_modules/@babel/types": { + "version": "7.28.1", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.1.tgz", + "integrity": "sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==", + "license": "MIT", "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1986,6 +1912,7 @@ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -1993,6 +1920,17 @@ "node": ">=12" } }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@dabh/diagnostics": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", @@ -2009,20 +1947,22 @@ "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" } }, "node_modules/@emotion/babel-plugin": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", - "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", - "@emotion/serialize": "^1.2.0", + "@emotion/serialize": "^1.3.3", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", @@ -2031,29 +1971,11 @@ "stylis": "4.2.0" } }, - "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@emotion/babel-plugin/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@emotion/cache": { "version": "11.14.0", "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", "dependencies": { "@emotion/memoize": "^0.9.0", "@emotion/sheet": "^1.4.0", @@ -2065,12 +1987,14 @@ "node_modules/@emotion/hash": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", - "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" }, "node_modules/@emotion/is-prop-valid": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", + "license": "MIT", "dependencies": { "@emotion/memoize": "^0.9.0" } @@ -2078,19 +2002,21 @@ "node_modules/@emotion/memoize": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", - "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" }, "node_modules/@emotion/react": { - "version": "11.13.3", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", - "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.12.0", - "@emotion/cache": "^11.13.0", - "@emotion/serialize": "^1.3.1", - "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", - "@emotion/utils": "^1.4.0", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" }, @@ -2107,6 +2033,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", @@ -2119,6 +2046,7 @@ "version": "11.11.0", "resolved": "https://registry.npmjs.org/@emotion/server/-/server-11.11.0.tgz", "integrity": "sha512-6q89fj2z8VBTx9w93kJ5n51hsmtYuFPtZgnc1L8VzRx9ti4EU6EyvF6Nn1H1x3vcCQCF7u2dB2lY4AYJwUW4PA==", + "license": "MIT", "dependencies": { "@emotion/utils": "^1.2.1", "html-tokenize": "^2.0.0", @@ -2137,19 +2065,21 @@ "node_modules/@emotion/sheet": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", - "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" }, "node_modules/@emotion/styled": { - "version": "11.13.0", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", - "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.12.0", + "@emotion/babel-plugin": "^11.13.5", "@emotion/is-prop-valid": "^1.3.0", - "@emotion/serialize": "^1.3.0", - "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", - "@emotion/utils": "^1.4.0" + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" }, "peerDependencies": { "@emotion/react": "^11.0.0-rc.0", @@ -2164,12 +2094,14 @@ "node_modules/@emotion/unitless": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", - "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", - "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", "peerDependencies": { "react": ">=16.8.0" } @@ -2177,36 +2109,583 @@ "node_modules/@emotion/utils": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", - "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==" + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" }, "node_modules/@emotion/weak-memoize": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", - "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@firebase/analytics": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.0.tgz", + "integrity": "sha512-Locv8gAqx0e+GX/0SI3dzmBY5e9kjVDtD+3zCFLJ0tH2hJwuCAiL+5WkHuxKj92rqQj/rvkBUCfA1ewlX2hehg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.6.tgz", + "integrity": "sha512-4MqpVLFkGK7NJf/5wPEEP7ePBJatwYpyjgJ+wQHQGHfzaCDgntOnl9rL2vbVGGKCnRqWtZDIWhctB86UWXaX2Q==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/analytics": "0.10.0", + "@firebase/analytics-types": "0.8.0", + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.0.tgz", + "integrity": "sha512-iRP+QKI2+oz3UAh4nPEq14CsEjrjD6a5+fuypjScisAh9kXKFvdJOZJDwk7kikLvWVLGEs9+kIUS4LPQV7VZVw==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app": { + "version": "0.9.25", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.9.25.tgz", + "integrity": "sha512-fX22gL5USXhOK21Hlh3oTeOzQZ6th6S2JrjXNEpBARmwzuUkqmVGVdsOCIFYIsLpK0dQE3o8xZnLrRg5wnzZ/g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "idb": "7.1.1", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.1.tgz", + "integrity": "sha512-zi3vbM5tb/eGRWyiqf+1DXbxFu9Q07dnm46rweodgUpH9B8svxYkHfNwYWx7F5mjHU70SQDuaojH1We5ws9OKA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.8.tgz", + "integrity": "sha512-EaETtChR4UgMokJFw+r6jfcIyCTUZSe0a6ivF37D9MxlG9G3wzK1COyXgxoX96GzXmDPc2aubX4PxCrdVHhrnA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check": "0.8.1", + "@firebase/app-check-types": "0.5.0", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.0.tgz", + "integrity": "sha512-xAxHPZPIgFXnI+vb4sbBjZcde7ZluzPPaSK7Lx3/nmuVk4TjZvnL8ONnkd4ERQKL8WePQySU+pRcWkh8rDf5Sg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-check-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.0.tgz", + "integrity": "sha512-uwSUj32Mlubybw7tedRzR24RP8M8JUVR3NPiMk3/Z4bCmgEKTlQBwMXrehDAZ2wF+TsBq0SN1c6ema71U/JPyQ==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-compat": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.25.tgz", + "integrity": "sha512-B/JtCp1FsTuzlh1tIGQpYM2AXps21/zlzpFsk5LRsROOTRhBcR2N45AyaONPFD06C0yS0Tw19foxADzHyOSC3A==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app": "0.9.25", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz", + "integrity": "sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.5.1.tgz", + "integrity": "sha512-sVi7rq2YneLGJFqHa5S6nDfCHix9yuVV3RLhj/pWPlB4a36ofXal4E6PJwpeMc8uLjWEr1aovYN1jkXWNB6Avw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0", + "undici": "5.26.5" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^1.18.1" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@firebase/auth-compat": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.1.tgz", + "integrity": "sha512-rgDZnrDoekRvtzXVji8Z61wxxkof6pTkjYEkybILrjM8tGP9tx4xa9qGpF4ax3AzF+rKr7mIa9NnoXEK4UNqmQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth": "1.5.1", + "@firebase/auth-types": "0.12.0", + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0", + "undici": "5.26.5" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.1.tgz", + "integrity": "sha512-VOaGzKp65MY6P5FI84TfYKBXEPi6LmOCSMMzys6o2BN2LOsqy7pCuZCup7NYnfbk5OkkQKzvIfHOzTm0UDpkyg==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth-types": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.0.tgz", + "integrity": "sha512-pPwaZt+SPOshK8xNoiQlK5XIrS97kFYc3Rc7xmy373QsOJ9MmqXxLaYssP5Kcds4wd2qK//amx/c+A8O2fVeZA==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.4.tgz", + "integrity": "sha512-rLMyrXuO9jcAUCaQXCMjCMUsWrba5fzHlNK24xz5j2W6A/SRmK8mZJ/hn7V0fViLbxC0lPMtrK1eYzk6Fg03jA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.2.tgz", + "integrity": "sha512-8X6NBJgUQzDz0xQVaCISoOLINKat594N2eBbMR3Mu/MH/ei4WM+aAMlsNzngF22eljXu1SILP5G3evkyvsG3Ng==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.0", + "@firebase/auth-interop-types": "0.2.1", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.2.tgz", + "integrity": "sha512-09ryJnXDvuycsxn8aXBzLhBTuCos3HEnCOBWY6hosxfYlNCGnLvG8YMlbSAt5eNhf7/00B095AEfDsdrrLjxqA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/database": "1.0.2", + "@firebase/database-types": "1.0.0", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.0.tgz", + "integrity": "sha512-SjnXStoE0Q56HcFgNQ+9SsmJc0c8TqGARdI/T44KXy+Ets3r6x/ivhQozT66bMnCEjJRywYoxNurRTMlZF8VNg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-types": "0.9.0", + "@firebase/util": "1.9.3" + } + }, + "node_modules/@firebase/firestore": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.4.0.tgz", + "integrity": "sha512-VeDXD9PUjvcWY1tInBOMTIu2pijR3YYy+QAe5cxCo1Q1vW+aA/mpQHhebPM1J6b4Zd1MuUh8xpBRvH9ujKR56A==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "@firebase/webchannel-wrapper": "0.10.5", + "@grpc/grpc-js": "~1.9.0", + "@grpc/proto-loader": "^0.7.8", + "tslib": "^2.1.0", + "undici": "5.26.5" + }, + "engines": { + "node": ">=10.10.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.23.tgz", + "integrity": "sha512-uUTBiP0GLVBETaOCfB11d33OWB8x1r2G1Xrl0sRK3Va0N5LJ/GRvKVSGfM7VScj+ypeHe8RpdwKoCqLpN1e+uA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/firestore": "4.4.0", + "@firebase/firestore-types": "3.0.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.0.tgz", + "integrity": "sha512-Meg4cIezHo9zLamw0ymFYBD4SMjLb+ZXIbuN7T7ddXN6MGoICmOTq3/ltdCGoDCS2u+H1XJs2u/cYp75jsX9Qw==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/functions": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.0.tgz", + "integrity": "sha512-n1PZxKnJ++k73Q8khTPwihlbeKo6emnGzE0hX6QVQJsMq82y/XKmNpw2t/q30VJgwaia3ZXU1fd1C5wHncL+Zg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.0", + "@firebase/auth-interop-types": "0.2.1", + "@firebase/component": "0.6.4", + "@firebase/messaging-interop-types": "0.2.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0", + "undici": "5.26.5" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.6.tgz", + "integrity": "sha512-RQpO3yuHtnkqLqExuAT2d0u3zh8SDbeBYK5EwSCBKI9mjrFeJRXBnd3pEG+x5SxGJLy56/5pQf73mwt0OuH5yg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/functions": "0.11.0", + "@firebase/functions-types": "0.6.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.0.tgz", + "integrity": "sha512-hfEw5VJtgWXIRf92ImLkgENqpL6IWpYaXVYiRkFY1jJ9+6tIhWM7IzzwbevwIIud/jaxKVdRzD7QBWfPmkwCYw==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/installations": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.4.tgz", + "integrity": "sha512-u5y88rtsp7NYkCHC3ElbFBrPtieUybZluXyzl7+4BsIz4sqb4vSAuwHEUgCgCeaQhvsnxDEU6icly8U9zsJigA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "idb": "7.0.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.4.tgz", + "integrity": "sha512-LI9dYjp0aT9Njkn9U4JRrDqQ6KXeAmFbRC0E7jI7+hxl5YmRWysq5qgQl22hcWpTk+cm3es66d/apoDU/A9n6Q==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/installations-types": "0.5.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.0.tgz", + "integrity": "sha512-9DP+RGfzoI2jH7gY4SlzqvZ+hr7gYzPODrbzVD82Y12kScZ6ZpRg/i3j6rleto8vTFC8n6Len4560FnV1w2IRg==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/installations/node_modules/idb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz", + "integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==", + "license": "ISC" + }, + "node_modules/@firebase/logger": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.0.tgz", + "integrity": "sha512-eRKSeykumZ5+cJPdxxJRgAC3G5NknY2GwEbKfymdnXtnT0Ucm4pspfR6GT4MUQEDuJwRVbVcSx85kgJulMoFFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.5.tgz", + "integrity": "sha512-i/rrEI2k9ueFhdIr8KQsptWGskrsnkC5TkohCTrJKz9P0C/PbNv14IAMkwhMJTqIur5VwuOnrUkc9Kdz7awekw==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/messaging-interop-types": "0.2.0", + "@firebase/util": "1.9.3", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.5.tgz", + "integrity": "sha512-qHQZxm4hEG8/HFU/ls5/bU+rpnlPDoZoqi3ATMeb6s4hovYV9+PfV5I7ZrKV5eFFv47Hx1PWLe5uPnS4e7gMwQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/messaging": "0.12.5", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.0.tgz", + "integrity": "sha512-ujA8dcRuVeBixGR9CtegfpU4YmZf3Lt7QYkcj693FFannwNuZgfAYaTmbJ40dtjB81SAu6tbFPL9YLNT15KmOQ==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/performance": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.4.tgz", + "integrity": "sha512-HfTn/bd8mfy/61vEqaBelNiNnvAbUtME2S25A67Nb34zVuCSCRIX4SseXY6zBnOFj3oLisaEqhVcJmVPAej67g==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.4.tgz", + "integrity": "sha512-nnHUb8uP9G8islzcld/k6Bg5RhX62VpbAb/Anj7IXs/hp32Eb2LqFPZK4sy3pKkBUO5wcrlRWQa6wKOxqlUqsg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/performance": "0.6.4", + "@firebase/performance-types": "0.2.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.0.tgz", + "integrity": "sha512-kYrbr8e/CYr1KLrLYZZt2noNnf+pRwDq2KK9Au9jHrBMnb0/C9X9yWSXmZkFt4UIdsQknBq8uBB7fsybZdOBTA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/remote-config": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.4.tgz", + "integrity": "sha512-x1ioTHGX8ZwDSTOVp8PBLv2/wfwKzb4pxi0gFezS5GCJwbLlloUH4YYZHHS83IPxnua8b6l0IXUaWd0RgbWwzQ==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/installations": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.4.tgz", + "integrity": "sha512-FKiki53jZirrDFkBHglB3C07j5wBpitAaj8kLME6g8Mx+aq7u9P7qfmuSRytiOItADhWUj7O1JIv7n9q87SuwA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/remote-config": "0.4.4", + "@firebase/remote-config-types": "0.3.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.0.tgz", + "integrity": "sha512-RtEH4vdcbXZuZWRZbIRmQVBNsE7VDQpet2qFvq6vwKLBIQRQR5Kh58M4ok3A3US8Sr3rubYnaGqZSurCwI8uMA==", + "license": "Apache-2.0" + }, + "node_modules/@firebase/storage": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.0.tgz", + "integrity": "sha512-SGs02Y/mmWBRsqZiYLpv4Sf7uZYZzMWVNN+aKiDqPsFBCzD6hLvGkXz+u98KAl8FqcjgB8BtSu01wm4pm76KHA==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0", + "undici": "5.26.5" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.3.tgz", + "integrity": "sha512-WNtjYPhpOA1nKcRu5lIodX0wZtP8pI0VxDJnk6lr+av7QZNS1s6zvr+ERDTve+Qu4Hq/ZnNaf3kBEQR2ccXn6A==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/storage": "0.12.0", + "@firebase/storage-types": "0.8.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.0.tgz", + "integrity": "sha512-isRHcGrTs9kITJC0AVehHfpraWFui39MPaU7Eo8QfWlqW7YPymBmRgjDrlOgFdURh6Cdeg07zmkLP5tzTKRSpg==", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/util": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.3.tgz", + "integrity": "sha512-DY02CRhOZwpzO36fHpuVysz6JZrscPiBXD0fXp6qSrL9oNOx5KWICKdR95C0lSITzxp0TZosVyHqzatE8JbcjA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.10.5.tgz", + "integrity": "sha512-eSkJsnhBWv5kCTSU1tSUVl9mpFu+5NXXunZc83le8GMjMlsWwQArSc7cJJ4yl+aDFY0NGLi0AjZWMn1axOrkRg==", + "license": "Apache-2.0" }, "node_modules/@floating-ui/core": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", - "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.2.tgz", + "integrity": "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==", + "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.9" + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.13", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", - "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.2.tgz", + "integrity": "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==", + "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.9" + "@floating-ui/core": "^1.7.2", + "@floating-ui/utils": "^0.2.10" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", - "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.4.tgz", + "integrity": "sha512-JbbpPhp38UmXDDAu60RJmbeme37Jbgsm7NrHGgzYYFKmblzRUh6Pa641dII6LsjwF4XlScDrde2UAzDo/b9KPw==", + "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.0.0" + "@floating-ui/dom": "^1.7.2" }, "peerDependencies": { "react": ">=16.8.0", @@ -2214,14 +2693,46 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", - "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==" + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.15", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz", + "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz", + "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } }, "node_modules/@jest/schemas": { "version": "29.6.3", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/@jest/schemas/-/@jest/schemas-29.6.3.tgz", - "integrity": "sha1-Qwtc6KTgBEp+OBlmMwWnswkcjgM=", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "license": "MIT", "dependencies": { @@ -2233,8 +2744,8 @@ }, "node_modules/@jest/types": { "version": "29.6.3", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/@jest/types/-/@jest/types-29.6.3.tgz", - "integrity": "sha1-ETH4z2NOfoTF53urEvBSr1hfulk=", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, "license": "MIT", "dependencies": { @@ -2250,108 +2761,84 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz", + "integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/@jridgewell/source-map/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@mui/base": { - "version": "5.0.0-beta.68", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.68.tgz", - "integrity": "sha512-F1JMNeLS9Qhjj3wN86JUQYBtJoXyQvknxlzwNl6eS0ZABo1MiohMONj3/WQzYPSXIKC2bS/ZbyBzdHhi2GnEpA==", + "version": "5.0.0-beta.42", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.42.tgz", + "integrity": "sha512-fWRiUJVCHCPF+mxd5drn08bY2qRw3jj5f1SSQdUXmaJ/yKpk23ys8MgLO2KGVTRtbks/+ctRfgffGPbXifj0Ug==", + "deprecated": "This package has been replaced by @base-ui-components/react", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.26.0", - "@floating-ui/react-dom": "^2.1.1", - "@mui/types": "^7.2.20", - "@mui/utils": "^6.3.0", + "@babel/runtime": "^7.24.4", + "@floating-ui/react-dom": "^2.0.8", + "@mui/types": "^7.2.14", + "@mui/utils": "^6.0.0-alpha.1", "@popperjs/core": "^2.11.8", - "clsx": "^2.1.1", + "clsx": "^2.1.0", "prop-types": "^15.8.1" }, "engines": { - "node": ">=14.0.0" + "node": ">=12.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -2360,18 +2847,20 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.0.tgz", - "integrity": "sha512-6u74wi+9zeNlukrCtYYET8Ed/n9AS27DiaXCZKAD3TRGFaqiyYSsQgN2disW83pI/cM1Q2lJY1JX4YfwvNtlNw==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.5.0.tgz", + "integrity": "sha512-LGb8t8i6M2ZtS3Drn3GbTI1DVhDY6FJ9crEey2lZ0aN2EMZo8IZBZj9wRf4vqbZHaWjsYgtbOnJw5V8UWbmK2Q==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.4.0.tgz", - "integrity": "sha512-zF0Vqt8a+Zp2Oz8P+WvJflba6lLe3PhxIz1NNqn+n4A+wKLPbkeqY8ShmKjPyiCTg0RMbPrp993oUDl9xGsDlQ==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.5.0.tgz", + "integrity": "sha512-VPuPqXqbBPlcVSA0BmnoE4knW4/xG6Thazo8vCLWkOKusko6DtwFV6B665MMWJ9j0KFohTIf3yx2zYtYacvG1g==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0" }, @@ -2383,7 +2872,7 @@ "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^6.4.0", + "@mui/material": "^6.5.0", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -2394,20 +2883,21 @@ } }, "node_modules/@mui/lab": { - "version": "6.0.0-beta.23", - "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-6.0.0-beta.23.tgz", - "integrity": "sha512-fqiC33bhhRifYgLD0mFef5fBM+OydZNK33ddwHwubDyrYzXz58OpSm4lXQJh2d6YHL7wXpOFKSot1CbgbItyYg==", + "version": "6.0.0-dev.240424162023-9968b4889d", + "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-6.0.0-dev.240424162023-9968b4889d.tgz", + "integrity": "sha512-iKFAz7/EeWI4PaFsP4jK2FcYJmUYDBkn3XZwpQSAl5806yYq5J2U2mPQLuZBdhrH50gT2O98p95i3vwL4YBwAg==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.26.0", - "@mui/base": "5.0.0-beta.68", - "@mui/system": "^6.4.0", - "@mui/types": "^7.2.21", - "@mui/utils": "^6.4.0", - "clsx": "^2.1.1", + "@babel/runtime": "^7.24.4", + "@mui/base": "5.0.0-beta.42", + "@mui/system": "^6.0.0-dev.240424162023-9968b4889d", + "@mui/types": "^7.2.14", + "@mui/utils": "^6.0.0-alpha.3", + "clsx": "^2.1.0", "prop-types": "^15.8.1" }, "engines": { - "node": ">=14.0.0" + "node": ">=12.0.0" }, "funding": { "type": "opencollective", @@ -2416,11 +2906,10 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material": "^6.4.0", - "@mui/material-pigment-css": "^6.4.0", - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + "@mui/material": "^6.0.0-dev.240424162023-9968b4889d", + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" }, "peerDependenciesMeta": { "@emotion/react": { @@ -2429,24 +2918,22 @@ "@emotion/styled": { "optional": true }, - "@mui/material-pigment-css": { - "optional": true - }, "@types/react": { "optional": true } } }, "node_modules/@mui/material": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.4.0.tgz", - "integrity": "sha512-hNIgwdM9U3DNmowZ8mU59oFmWoDKjc92FqQnQva3Pxh6xRKWtD2Ej7POUHMX8Dwr1OpcSUlT2+tEMeLb7WYsIg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.5.0.tgz", + "integrity": "sha512-yjvtXoFcrPLGtgKRxFaH6OQPtcLPhkloC0BML6rBG5UeldR0nPULR/2E2BfXdo5JNV7j7lOzrrLX2Qf/iSidow==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/core-downloads-tracker": "^6.4.0", - "@mui/system": "^6.4.0", - "@mui/types": "^7.2.21", - "@mui/utils": "^6.4.0", + "@mui/core-downloads-tracker": "^6.5.0", + "@mui/system": "^6.5.0", + "@mui/types": "~7.2.24", + "@mui/utils": "^6.4.9", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", @@ -2465,7 +2952,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^6.4.0", + "@mui/material-pigment-css": "^6.5.0", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -2485,13 +2972,28 @@ } } }, + "node_modules/@mui/material/node_modules/@mui/types": { + "version": "7.2.24", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz", + "integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@mui/private-theming": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.0.tgz", - "integrity": "sha512-rNHci8MP6NOdEWAfZ/RBMO5Rhtp1T6fUDMSmingg9F1T6wiUeodIQ+NuTHh2/pMoUSeP9GdHdgMhMmfsXxOMuw==", + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.9.tgz", + "integrity": "sha512-LktcVmI5X17/Q5SkwjCcdOLBzt1hXuc14jYa7NPShog0GBDCDvKtcnP0V7a2s6EiVRlv7BzbWEJzH6+l/zaCxw==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/utils": "^6.4.0", + "@mui/utils": "^6.4.9", "prop-types": "^15.8.1" }, "engines": { @@ -2512,9 +3014,10 @@ } }, "node_modules/@mui/styled-engine": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.4.0.tgz", - "integrity": "sha512-ek/ZrDujrger12P6o4luQIfRd2IziH7jQod2WMbLqGE03Iy0zUwYmckRTVhRQTLPNccpD8KXGcALJF+uaUQlbg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.5.0.tgz", + "integrity": "sha512-8woC2zAqF4qUDSPIBZ8v3sakj+WgweolpyM/FXf8jAx6FMls+IE4Y8VDZc+zS805J7PRz31vz73n2SovKGaYgw==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", "@emotion/cache": "^11.13.5", @@ -2545,15 +3048,16 @@ } }, "node_modules/@mui/system": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.4.0.tgz", - "integrity": "sha512-wTDyfRlaZCo2sW2IuOsrjeE5dl0Usrs6J7DxE3GwNCVFqS5wMplM2YeNiV3DO7s53RfCqbho+gJY6xaB9KThUA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.5.0.tgz", + "integrity": "sha512-XcbBYxDS+h/lgsoGe78ExXFZXtuIlSBpn/KsZq8PtZcIkUNJInkuDqcLd2rVBQrDC1u+rvVovdaWPf2FHKJf3w==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/private-theming": "^6.4.0", - "@mui/styled-engine": "^6.4.0", - "@mui/types": "^7.2.21", - "@mui/utils": "^6.4.0", + "@mui/private-theming": "^6.4.9", + "@mui/styled-engine": "^6.5.0", + "@mui/types": "~7.2.24", + "@mui/utils": "^6.4.9", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -2583,10 +3087,28 @@ } } }, + "node_modules/@mui/system/node_modules/@mui/types": { + "version": "7.2.24", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz", + "integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@mui/types": { - "version": "7.2.21", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.21.tgz", - "integrity": "sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.4.tgz", + "integrity": "sha512-p63yhbX52MO/ajXC7hDHJA5yjzJekvWD3q4YDLl1rSg+OXLczMYPvTuSuviPRCgRX8+E42RXz1D/dz9SxPSlWg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.6" + }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -2597,12 +3119,13 @@ } }, "node_modules/@mui/utils": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.0.tgz", - "integrity": "sha512-woOTATWNsTNR3YBh2Ixkj3l5RaxSiGoC9G8gOpYoFw1mZM77LWJeuMHFax7iIW4ahK0Cr35TF9DKtrafJmOmNQ==", + "version": "6.4.9", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.9.tgz", + "integrity": "sha512-Y12Q9hbK9g+ZY0T3Rxrx9m2m10gaphDuUMgWxyV5kNJevVxXYCLclYUCC9vXaIk1/NdNDTcW2Yfr2OGvNFNmHg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/types": "^7.2.21", + "@mui/types": "~7.2.24", "@types/prop-types": "^15.7.14", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -2625,11 +3148,26 @@ } } }, + "node_modules/@mui/utils/node_modules/@mui/types": { + "version": "7.2.24", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz", + "integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -2643,60 +3181,450 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 8" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 8" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/@polka/url": { - "version": "1.0.0-next.25", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", - "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==", - "dev": true + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@remix-run/router": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz", + "integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/@sinclair/typebox/-/@sinclair/typebox-0.27.8.tgz", - "integrity": "sha1-Zmf6wWxDa1Q0o4ejTe2wExmPbm4=", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true, "license": "MIT" }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" }, "node_modules/@stackblitz/sdk": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/@stackblitz/sdk/-/sdk-1.11.0.tgz", - "integrity": "sha512-DFQGANNkEZRzFk1/rDP6TcFdM82ycHE+zfl9C/M/jXlH68jiqHWHFMQURLELoD8koxvu/eW5uhg94NSAZlYrUQ==" + "integrity": "sha512-DFQGANNkEZRzFk1/rDP6TcFdM82ycHE+zfl9C/M/jXlH68jiqHWHFMQURLELoD8koxvu/eW5uhg94NSAZlYrUQ==", + "license": "MIT" }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" }, @@ -2713,6 +3641,7 @@ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" }, @@ -2729,6 +3658,7 @@ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" }, @@ -2745,6 +3675,7 @@ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" }, @@ -2761,6 +3692,7 @@ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" }, @@ -2777,6 +3709,7 @@ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" }, @@ -2793,6 +3726,7 @@ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" }, @@ -2809,6 +3743,7 @@ "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -2825,6 +3760,7 @@ "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", "dev": true, + "license": "MIT", "dependencies": { "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", @@ -2851,6 +3787,7 @@ "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -2866,23 +3803,12 @@ "url": "https://github.com/sponsors/gregberge" } }, - "node_modules/@svgr/core/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@svgr/hast-util-to-babel-ast": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.21.3", "entities": "^4.4.0" @@ -2900,6 +3826,7 @@ "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -2922,6 +3849,7 @@ "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", "dev": true, + "license": "MIT", "dependencies": { "cosmiconfig": "^8.1.3", "deepmerge": "^4.3.1", @@ -2943,6 +3871,7 @@ "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.21.3", "@babel/plugin-transform-react-constant-elements": "^7.21.3", @@ -2966,6 +3895,7 @@ "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10.13.0" } @@ -2974,31 +3904,36 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "dev": true, + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -3009,6 +3944,7 @@ "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -3017,21 +3953,25 @@ "version": "0.12.5", "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz", "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/chai": { - "version": "4.3.16", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.16.tgz", - "integrity": "sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==", - "dev": true + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/compression": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", - "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-kCFuWS0ebDbmxs0AXYn6e2r2nrGAb5KwQhknjSPSPgJcGd8+HVSILlUyFhGqML2gk39HcG7D1ydW9/qpYkN00Q==", "dev": true, + "license": "MIT", "dependencies": { - "@types/express": "*" + "@types/express": "*", + "@types/node": "*" } }, "node_modules/@types/connect": { @@ -3039,6 +3979,7 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -3048,20 +3989,17 @@ "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, + "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" } }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" - }, "node_modules/@types/cors": { - "version": "2.8.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -3070,15 +4008,17 @@ "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", "dependencies": { "@types/ms": "*" } }, "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -3089,29 +4029,33 @@ "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint": "*", "@types/estree": "*" } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" }, "node_modules/@types/estree-jsx": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", "dependencies": { "@types/estree": "*" } }, "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz", + "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -3120,10 +4064,11 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -3136,44 +4081,48 @@ "resolved": "https://registry.npmjs.org/@types/follow-redirects/-/follow-redirects-1.14.4.tgz", "integrity": "sha512-GWXfsD0Jc1RWiFmMuMFCpXMzi9L7oPDVwxUnZdg89kDNnqsRfUKXEtUYtA98A6lig1WXH/CYY/fvPW9HuN5fTA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/hast": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", - "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", "dependencies": { - "@types/unist": "^2" + "@types/unist": "*" } }, "node_modules/@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" }, "node_modules/@types/http-proxy": { - "version": "1.17.14", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz", - "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==", + "version": "1.17.16", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz", + "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/@types/istanbul-lib-coverage/-/@types/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha1-dznCMqH+6bTTzomF8xTAxtM1Sdc=", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true, "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/@types/istanbul-lib-report/-/@types/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha1-UwR2FK5y4Z/AQB2HLeOuK0zjUL8=", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, "license": "MIT", "dependencies": { @@ -3182,8 +4131,8 @@ }, "node_modules/@types/istanbul-reports": { "version": "3.0.4", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/@types/istanbul-reports/-/@types/istanbul-reports-3.0.4.tgz", - "integrity": "sha1-DwPj0vZw+9rFhuNLQzeDBwzBb1Q=", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3194,12 +4143,14 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/mdast": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", "dependencies": { "@types/unist": "*" } @@ -3208,35 +4159,39 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/morgan": { - "version": "1.9.9", - "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.9.tgz", - "integrity": "sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ==", + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.10.tgz", + "integrity": "sha512-sS4A1zheMvsADRVfT0lYbJ4S9lmsey8Zo2F7cnbYjWHP67Q0AwMYuuzLlkIM2N8gAbb9cubhIVFwcIN2XyYCkA==", "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/ms": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" }, "node_modules/@types/node": { - "version": "22.7.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz", - "integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==", + "version": "22.16.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.5.tgz", + "integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==", + "license": "MIT", "dependencies": { - "undici-types": "~6.19.2" + "undici-types": "~6.21.0" } }, "node_modules/@types/node-forge": { - "version": "1.3.11", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", - "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "version": "1.3.13", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.13.tgz", + "integrity": "sha512-zePQJSW5QkwSHKRApqWCVKeKoSOt4xvEnLENZPjyvm9Ezdf/EyDeJM7jqLzOwjVICQQzvLZ63T55MKdJB5H6ww==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -3246,6 +4201,7 @@ "resolved": "https://registry.npmjs.org/@types/nodemon/-/nodemon-1.19.6.tgz", "integrity": "sha512-vjKuaQOLUA5EY2zkUmWG1ipXbKt9Wd+H/0SiIuHVeH4cHtt6509iRUGH9ZR0iqgUrtj3BrP9KqoTuV3ZCbQcYA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -3253,35 +4209,41 @@ "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" }, "node_modules/@types/prismjs": { - "version": "1.26.4", - "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.4.tgz", - "integrity": "sha512-rlAnzkW2sZOjbqZ743IHUhFcvzaGbqijwOu8QZnZCjfQzBqFE3s4lOTJEsxikImav9uzz/42I+O7YUs1mWgMlg==", - "dev": true + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/prop-types": { - "version": "15.7.14", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", - "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==" + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" }, "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", - "dev": true + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/react": { "version": "19.0.4", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.4.tgz", "integrity": "sha512-3O4QisJDYr1uTUMZHA2YswiQZRq+Pd8D+GdVFYikTutYsTz+QZgWkAPnP7rx9txoI6EXKcPiluMqWPFV3tT9Wg==", + "license": "MIT", "dependencies": { "csstype": "^3.0.2" } @@ -3291,6 +4253,7 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.2.tgz", "integrity": "sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==", "dev": true, + "license": "MIT", "peerDependencies": { "@types/react": "^19.0.0" } @@ -3300,6 +4263,7 @@ "resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.11.tgz", "integrity": "sha512-0QcdGLddTERotCXo3VFlUSWO3ztraw8nZ6e3zJSgG7apwV5xt+pJUS8ewPBqT4NYB1optGLprNQzFleIY84u/g==", "dev": true, + "license": "MIT", "dependencies": { "@types/react": "*" } @@ -3309,6 +4273,7 @@ "resolved": "https://registry.npmjs.org/@types/react-lazy-load-image-component/-/react-lazy-load-image-component-1.6.4.tgz", "integrity": "sha512-8pFPeDPF4yVG4lU1/ixZidJEEDZmEOYOTYDvmIu2IAabyuv97Q7n/93nMCocHvQ7vD1czKGiW+op55D9m3MkdA==", "dev": true, + "license": "MIT", "dependencies": { "@types/react": "*", "csstype": "^3.0.2" @@ -3328,6 +4293,7 @@ "version": "4.4.12", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", "peerDependencies": { "@types/react": "*" } @@ -3337,6 +4303,7 @@ "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.12.tgz", "integrity": "sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==", "dev": true, + "license": "MIT", "dependencies": { "@types/caseless": "*", "@types/node": "*", @@ -3344,40 +4311,29 @@ "form-data": "^2.5.0" } }, - "node_modules/@types/request/node_modules/form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/@types/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/sax": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz", + "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==", "dev": true, + "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -3388,15 +4344,17 @@ "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.7", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", - "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz", + "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -3408,6 +4366,7 @@ "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -3416,7 +4375,8 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/triple-beam": { "version": "1.3.5", @@ -3425,23 +4385,25 @@ "license": "MIT" }, "node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" }, "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/yargs": { "version": "17.0.33", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/@types/yargs/-/@types/yargs-17.0.33.tgz", - "integrity": "sha1-jDIwPag+7AUKhLPHrnufki0T4y0=", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, "license": "MIT", "dependencies": { @@ -3450,159 +4412,175 @@ }, "node_modules/@types/yargs-parser": { "version": "21.0.3", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/@types/yargs-parser/-/@types/yargs-parser-21.0.3.tgz", - "integrity": "sha1-gV4wt4bS6PDc2F/VvPXhoE0AjxU=", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true, "license": "MIT" }, "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" }, "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", - "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, + "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, @@ -3611,6 +4589,7 @@ "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.15.0" }, @@ -3624,6 +4603,7 @@ "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.15.0" }, @@ -3637,6 +4617,7 @@ "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.15.0" }, @@ -3654,18 +4635,21 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -3674,11 +4658,21 @@ "node": ">= 0.6" } }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", - "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3686,20 +4680,25 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, "peerDependencies": { - "acorn": "^8" + "acorn": "^8.14.0" } }, "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, + "license": "MIT", "dependencies": { "acorn": "^8.11.0" }, @@ -3711,6 +4710,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "license": "MIT", "dependencies": { "es6-promisify": "^5.0.0" }, @@ -3722,6 +4722,7 @@ "version": "3.5.3", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.3.tgz", "integrity": "sha512-yqXL+k5rr8+ZRpOAntkaaRgWgE5o8ESAj5DyRmVTCSoZxXmqemb9Dd7T4i5UzwuERdLAJUy6XzR9zFVuf0kzkw==", + "license": "MIT", "dependencies": { "humanize-ms": "^1.2.1" }, @@ -3734,6 +4735,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -3750,6 +4752,7 @@ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, @@ -3767,6 +4770,7 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -3778,6 +4782,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", "integrity": "sha512-TdlOggdA/zURfMYa7ABC66j+oqfMew58KpJMbUlH3bcZP1b+cBHIHDDn5uH9INsxrHBPjsqM0tDB4jPTF/vgJA==", + "license": "ISC", "dependencies": { "string-width": "^2.0.0" } @@ -3786,6 +4791,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "license": "MIT", "engines": { "node": ">=4" } @@ -3798,22 +4804,25 @@ "engines": [ "node >= 0.8.0" ], + "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } }, "node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3829,6 +4838,7 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -3840,29 +4850,34 @@ "node_modules/aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "license": "ISC" }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "license": "MIT", "dependencies": { "safer-buffer": "~2.1.0" } @@ -3871,6 +4886,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "license": "MIT", "engines": { "node": ">=0.8" } @@ -3884,12 +4900,13 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, "node_modules/autoprefixer": { - "version": "10.4.19", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", - "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", "dev": true, "funding": [ { @@ -3905,12 +4922,13 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", - "caniuse-lite": "^1.0.30001599", + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -3923,33 +4941,61 @@ "postcss": "^8.1.0" } }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/aws4": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.0.tgz", - "integrity": "sha512-3AungXC4I8kKsS9PuS4JH2nc+0bVY/mjgrephHTIi8fpEeGsTHBUJeosp0Wc1myYMElmD0B3Oc4XL/HVJ4PV2g==" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", + "license": "MIT" }, "node_modules/axios": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", "deprecated": "Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410", + "license": "MIT", "dependencies": { "follow-redirects": "1.5.10", "is-buffer": "^2.0.2" } }, + "node_modules/axios/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, "node_modules/axios/node_modules/follow-redirects": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "license": "MIT", "dependencies": { "debug": "=3.1.0" }, @@ -3957,10 +5003,17 @@ "node": ">=4.0" } }, + "node_modules/axios/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/babel-plugin-macros": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -3975,6 +5028,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -3987,13 +5041,14 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.12", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz", - "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==", + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.3", + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { @@ -4001,25 +5056,27 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", - "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.2", - "core-js-compat": "^3.38.0" + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz", - "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.3" + "@babel/helper-define-polyfill-provider": "^0.6.5" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -4029,6 +5086,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -4037,12 +5095,14 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", "engines": { "node": "^4.5.0 || >= 5.9" } @@ -4069,12 +5129,14 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "license": "BSD-3-Clause", "dependencies": { "tweetnacl": "^0.14.3" } @@ -4084,6 +5146,7 @@ "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -4093,6 +5156,7 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -4104,6 +5168,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz", "integrity": "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==", + "license": "MIT", "engines": { "node": ">=0.8" }, @@ -4115,20 +5180,59 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "license": "MIT", "dependencies": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" } }, + "node_modules/bl/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/bl/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/bl/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "license": "MIT" }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -4138,7 +5242,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -4148,18 +5252,11 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -4167,13 +5264,15 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/bonjour-service": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", - "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -4182,12 +5281,14 @@ "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" }, "node_modules/boxen": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "license": "MIT", "dependencies": { "ansi-align": "^2.0.0", "camelcase": "^4.0.0", @@ -4205,6 +5306,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -4212,10 +5314,20 @@ "node": ">=4" } }, + "node_modules/boxen/node_modules/camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/boxen/node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -4229,6 +5341,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -4236,12 +5349,23 @@ "node_modules/boxen/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/boxen/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, "node_modules/boxen/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { "node": ">=4" } @@ -4250,6 +5374,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -4258,9 +5383,10 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4271,6 +5397,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -4279,9 +5406,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", "dev": true, "funding": [ { @@ -4297,11 +5424,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.1" + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -4314,6 +5442,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "license": "MIT", "dependencies": { "buffer-alloc-unsafe": "^1.1.0", "buffer-fill": "^1.0.0" @@ -4322,23 +5451,27 @@ "node_modules/buffer-alloc-unsafe": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "license": "MIT" }, "node_modules/buffer-fill": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==" + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "license": "MIT" }, "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz", + "integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==", + "license": "MIT" }, "node_modules/builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4346,12 +5479,14 @@ "node_modules/builtins": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==" + "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", + "license": "MIT" }, "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -4360,6 +5495,7 @@ "version": "9.3.0", "resolved": "https://registry.npmjs.org/cacache/-/cacache-9.3.0.tgz", "integrity": "sha512-Vbi8J1XfC8v+FbQ6QkOtKXsHpPnB0i9uMeYFJoj40EbdOsEqWB3DPpNjfsnYBkqOPYA8UvrqH6FZPpBP0zdN7g==", + "license": "CC0-1.0", "dependencies": { "bluebird": "^3.5.0", "chownr": "^1.0.1", @@ -4376,11 +5512,22 @@ "y18n": "^3.2.1" } }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "license": "ISC", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, "node_modules/cacache/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -4388,16 +5535,51 @@ "rimraf": "bin.js" } }, + "node_modules/cacache/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "license": "ISC" + }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -4410,22 +5592,28 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/caniuse-api": { "version": "3.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha1-Xk2Q4idJYdRikZl99Znj7QCO5MA=", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", "dev": true, "license": "MIT", "dependencies": { @@ -4436,9 +5624,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001684", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz", - "integrity": "sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==", + "version": "1.0.30001727", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", + "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", "dev": true, "funding": [ { @@ -4453,12 +5641,14 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/capture-stack-trace": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.2.tgz", "integrity": "sha512-X/WM2UQs6VMHUtjUDnZTRI+i1crWteJySFzr9UpGoQa4WQffXVTTXuekjl7TjZRlcF2XfjgITT0HxZ9RnxeT0w==", + "license": "MIT", "engines": { "node": ">=0.10.0" }, @@ -4469,12 +5659,14 @@ "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "license": "Apache-2.0" }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -4484,6 +5676,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -4499,6 +5692,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -4508,15 +5702,16 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/character-entities-legacy": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", - "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", "license": "MIT", "funding": { "type": "github", @@ -4524,9 +5719,9 @@ } }, "node_modules/character-reference-invalid": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", - "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", "license": "MIT", "funding": { "type": "github", @@ -4536,13 +5731,15 @@ "node_modules/chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "license": "MIT" }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -4567,6 +5764,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -4577,26 +5775,40 @@ "node_modules/chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" }, "node_modules/chrome-trace-event": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", "engines": { - "node": ">=6.0" + "node": ">=8" } }, - "node_modules/ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" - }, "node_modules/cli-boxes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", "integrity": "sha512-3Fo5wu8Ytle8q9iCzS4D2MWVL2X7JVWRiS1BnXbTFDhS9c/REkM9vd1AmabsoZoY5/dGi5TT9iKL8Kb6DeBRQg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -4605,6 +5817,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "license": "MIT", "dependencies": { "restore-cursor": "^2.0.0" }, @@ -4616,6 +5829,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz", "integrity": "sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg==", + "license": "MIT", "engines": { "node": ">=4" } @@ -4623,13 +5837,73 @@ "node_modules/cli-width": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "license": "ISC" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -4643,6 +5917,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -4651,6 +5926,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/codesandbox/-/codesandbox-2.2.3.tgz", "integrity": "sha512-IAkWFk6UUglOhSemI7UFgNNL/jgg+1YjVEIllFULLgsaHhFnY51pCqAifMNuAd5d9Zp4Nk/xMgrEaGNV0L4Xlg==", + "license": "MIT", "dependencies": { "axios": "^0.18.1", "chalk": "^2.4.1", @@ -4697,6 +5973,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -4708,6 +5985,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -4721,6 +5999,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -4728,12 +6007,23 @@ "node_modules/codesandbox/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/codesandbox/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, "node_modules/codesandbox/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { "node": ">=4" } @@ -4742,6 +6032,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -4763,6 +6054,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -4773,7 +6065,8 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" }, "node_modules/color-string": { "version": "1.9.1", @@ -4802,8 +6095,8 @@ }, "node_modules/colord": { "version": "2.9.3", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/colord/-/colord-2.9.3.tgz", - "integrity": "sha1-T4zpGd5Fbx1cHDaMMH/iDz5Z+0M=", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", "dev": true, "license": "MIT" }, @@ -4811,7 +6104,8 @@ "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colorspace": { "version": "1.1.4", @@ -4827,6 +6121,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -4838,6 +6133,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -4846,12 +6142,14 @@ "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -4860,16 +6158,17 @@ } }, "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", + "bytes": "3.1.2", + "compressible": "~2.0.18", "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", "vary": "~1.1.2" }, "engines": { @@ -4880,6 +6179,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -4887,17 +6187,14 @@ "node_modules/compression/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" }, "node_modules/concat-stream": { "version": "1.6.2", @@ -4906,6 +6203,7 @@ "engines": [ "node >= 0.8" ], + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -4913,10 +6211,53 @@ "typedarray": "^0.0.6" } }, + "node_modules/concat-stream/node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/configstore": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.5.tgz", "integrity": "sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==", + "license": "BSD-2-Clause", "dependencies": { "dot-prop": "^4.2.1", "graceful-fs": "^4.1.2", @@ -4934,6 +6275,7 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -4942,6 +6284,7 @@ "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -4953,6 +6296,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4960,12 +6304,14 @@ "node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4973,13 +6319,15 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" }, "node_modules/copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", "deprecated": "This package is no longer supported.", + "license": "ISC", "dependencies": { "aproba": "^1.1.1", "fs-write-stream-atomic": "^1.0.8", @@ -4994,6 +6342,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -5006,6 +6355,7 @@ "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", "dev": true, + "license": "MIT", "dependencies": { "fast-glob": "^3.2.11", "glob-parent": "^6.0.1", @@ -5026,12 +6376,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.39.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", - "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", + "version": "3.44.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.44.0.tgz", + "integrity": "sha512-JepmAj2zfl6ogy34qfWtcE7nHKAJnKsQFRn++scjVS2bZFllwptzw61BZcZFYBPpUznLfAvh0LGhxKppk04ClA==", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.24.2" + "browserslist": "^4.25.1" }, "funding": { "type": "opencollective", @@ -5041,12 +6392,14 @@ "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" @@ -5060,6 +6413,7 @@ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, + "license": "MIT", "dependencies": { "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", @@ -5082,14 +6436,16 @@ } }, "node_modules/country-flag-icons": { - "version": "1.5.12", - "resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.12.tgz", - "integrity": "sha512-ksBaQqQEFSvSFg1NV8tlAk4IjgDRNMu5ImjnCac0C409CiN6ObTI0vCFaNfaPusxLrr5O9pueT1R3G4XMMwErg==" + "version": "1.5.19", + "resolved": "https://registry.npmjs.org/country-flag-icons/-/country-flag-icons-1.5.19.tgz", + "integrity": "sha512-D/ZkRyj+ywJC6b2IrAN3/tpbReMUqmuRLlcKFoY/o0+EPQN9Ev/e8tV+D3+9scvu/tarxwLErNwS73C3yzxs/g==", + "license": "MIT" }, "node_modules/create-error-class": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", "integrity": "sha512-gYTKKexFO3kh200H1Nit76sRwRtOY32vQd3jpAQKpLtZqyNsSQNfI4N7o3eP2wUjV35pTWKRYqFUDBvUha/Pkw==", + "license": "MIT", "dependencies": { "capture-stack-trace": "^1.0.0" }, @@ -5101,30 +6457,53 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, "node_modules/crypto-random-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", "integrity": "sha512-GsVpkFPlycH7/fRR7Dhcmnoii54gV1nz7y4CWyeFS14N+JVBBhY+r8amRHE4BwSYal7BPTDp8isvAlCxyFt3Hg==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/css-declaration-sorter": { "version": "7.2.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", - "integrity": "sha1-bewclSO8SmQ+CIqrjwnmelSWECQ=", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", + "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==", "dev": true, "license": "ISC", "engines": { @@ -5139,6 +6518,7 @@ "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.33", @@ -5170,10 +6550,11 @@ } }, "node_modules/css-loader/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -5182,16 +6563,16 @@ } }, "node_modules/css-minimizer-webpack-plugin": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-7.0.0.tgz", - "integrity": "sha1-t3o9L3wP0C06wlDcwveQZTY/PNM=", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-7.0.2.tgz", + "integrity": "sha512-nBRWZtI77PBZQgcXMNqiIXVshiQOVLGSf2qX/WZfG8IQfMbeHUMXaBWQmiiSTmPJUflQxHjZjzAmuyO7tpL2Jg==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", - "cssnano": "^7.0.1", + "cssnano": "^7.0.4", "jest-worker": "^29.7.0", - "postcss": "^8.4.38", + "postcss": "^8.4.40", "schema-utils": "^4.2.0", "serialize-javascript": "^6.0.2" }, @@ -5226,63 +6607,22 @@ } } }, - "node_modules/css-minimizer-webpack-plugin/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/@jridgewell/trace-mapping/-/@jridgewell/trace-mapping-0.3.25.tgz", - "integrity": "sha1-FfGQ6YiV8/wjJ27hS8drZ1wuUPA=", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha1-rK0HOsu663JivVOJ4bz0PhAFjUo=", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha1-zW/BfihQDP9WwbhsCn/UpUpzAFw=", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/css-modules-typescript-loader": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/css-modules-typescript-loader/-/css-modules-typescript-loader-4.0.1.tgz", "integrity": "sha512-vXrUAwPGcRaopnGdg7I5oqv/NSSKQRN5L80m3f49uSGinenU5DTNsMFHS+2roh5tXqpY5+yAAKAl7A2HDvumzg==", "dev": true, + "license": "MIT", "dependencies": { "line-diff": "^2.0.1", "loader-utils": "^1.2.3" } }, "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -5299,6 +6639,7 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, + "license": "MIT", "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -5308,9 +6649,10 @@ } }, "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -5323,6 +6665,7 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -5331,14 +6674,14 @@ } }, "node_modules/cssnano": { - "version": "7.0.6", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/cssnano/-/cssnano-7.0.6.tgz", - "integrity": "sha1-Y9VP1CvAF/aq7WnkfZqu+Ft4UOw=", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.0.tgz", + "integrity": "sha512-Pu3rlKkd0ZtlCUzBrKL1Z4YmhKppjC1H9jo7u1o4qaKqyhvixFgu5qLyNIAOjSTg9DjVPtUqdROq2EfpVMEe+w==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-preset-default": "^7.0.6", - "lilconfig": "^3.1.2" + "cssnano-preset-default": "^7.0.8", + "lilconfig": "^3.1.3" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" @@ -5348,65 +6691,65 @@ "url": "https://opencollective.com/cssnano" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/cssnano-preset-default": { - "version": "7.0.6", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/cssnano-preset-default/-/cssnano-preset-default-7.0.6.tgz", - "integrity": "sha1-AiD6dQdHg2mqKiJrrAPhIEzQJME=", + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.8.tgz", + "integrity": "sha512-d+3R2qwrUV3g4LEMOjnndognKirBZISylDZAF/TPeCWVjEwlXS2e4eN4ICkoobRe7pD3H6lltinKVyS1AJhdjQ==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.3", + "browserslist": "^4.25.1", "css-declaration-sorter": "^7.2.0", - "cssnano-utils": "^5.0.0", - "postcss-calc": "^10.0.2", - "postcss-colormin": "^7.0.2", - "postcss-convert-values": "^7.0.4", - "postcss-discard-comments": "^7.0.3", - "postcss-discard-duplicates": "^7.0.1", - "postcss-discard-empty": "^7.0.0", - "postcss-discard-overridden": "^7.0.0", - "postcss-merge-longhand": "^7.0.4", - "postcss-merge-rules": "^7.0.4", - "postcss-minify-font-values": "^7.0.0", - "postcss-minify-gradients": "^7.0.0", - "postcss-minify-params": "^7.0.2", - "postcss-minify-selectors": "^7.0.4", - "postcss-normalize-charset": "^7.0.0", - "postcss-normalize-display-values": "^7.0.0", - "postcss-normalize-positions": "^7.0.0", - "postcss-normalize-repeat-style": "^7.0.0", - "postcss-normalize-string": "^7.0.0", - "postcss-normalize-timing-functions": "^7.0.0", - "postcss-normalize-unicode": "^7.0.2", - "postcss-normalize-url": "^7.0.0", - "postcss-normalize-whitespace": "^7.0.0", - "postcss-ordered-values": "^7.0.1", - "postcss-reduce-initial": "^7.0.2", - "postcss-reduce-transforms": "^7.0.0", - "postcss-svgo": "^7.0.1", - "postcss-unique-selectors": "^7.0.3" + "cssnano-utils": "^5.0.1", + "postcss-calc": "^10.1.1", + "postcss-colormin": "^7.0.4", + "postcss-convert-values": "^7.0.6", + "postcss-discard-comments": "^7.0.4", + "postcss-discard-duplicates": "^7.0.2", + "postcss-discard-empty": "^7.0.1", + "postcss-discard-overridden": "^7.0.1", + "postcss-merge-longhand": "^7.0.5", + "postcss-merge-rules": "^7.0.6", + "postcss-minify-font-values": "^7.0.1", + "postcss-minify-gradients": "^7.0.1", + "postcss-minify-params": "^7.0.4", + "postcss-minify-selectors": "^7.0.5", + "postcss-normalize-charset": "^7.0.1", + "postcss-normalize-display-values": "^7.0.1", + "postcss-normalize-positions": "^7.0.1", + "postcss-normalize-repeat-style": "^7.0.1", + "postcss-normalize-string": "^7.0.1", + "postcss-normalize-timing-functions": "^7.0.1", + "postcss-normalize-unicode": "^7.0.4", + "postcss-normalize-url": "^7.0.1", + "postcss-normalize-whitespace": "^7.0.1", + "postcss-ordered-values": "^7.0.2", + "postcss-reduce-initial": "^7.0.4", + "postcss-reduce-transforms": "^7.0.1", + "postcss-svgo": "^7.1.0", + "postcss-unique-selectors": "^7.0.4" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/cssnano-utils": { - "version": "5.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/cssnano-utils/-/cssnano-utils-5.0.0.tgz", - "integrity": "sha1-tToDQ91dIQEpEYgttq59Lq4ONoc=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-5.0.1.tgz", + "integrity": "sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==", "dev": true, "license": "MIT", "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/csso": { @@ -5414,6 +6757,7 @@ "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dev": true, + "license": "MIT", "dependencies": { "css-tree": "~2.2.0" }, @@ -5427,6 +6771,7 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", "dev": true, + "license": "MIT", "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" @@ -5440,17 +6785,20 @@ "version": "2.0.28", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true + "dev": true, + "license": "CC0-1.0" }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" }, "node_modules/cwd": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/cwd/-/cwd-0.9.1.tgz", "integrity": "sha512-4+0D+ojEasdLndYX4Cqff057I/Jp6ysXpwKkdLQLnZxV8f6IYZmZtTP5uqD91a/kWqejoc0sSqK4u8wpTKCh8A==", + "license": "MIT", "dependencies": { "find-pkg": "^0.1.0" }, @@ -5461,12 +6809,14 @@ "node_modules/cyclist": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.2.tgz", - "integrity": "sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==" + "integrity": "sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==", + "license": "MIT" }, "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" }, @@ -5478,6 +6828,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/datauri/-/datauri-3.0.0.tgz", "integrity": "sha512-NeDFuUPV1YCpCn8MUIcDk1QnuyenUHs7f4Q5P0n9FFA0neKFrfEH9esR+YMW95BplbYfdmjbs0Pl/ZGAaM2QHQ==", + "license": "MIT", "dependencies": { "image-size": "0.8.3", "mimer": "1.1.0" @@ -5490,25 +6841,31 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, "node_modules/decode-named-character-reference": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", - "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "license": "MIT", "dependencies": { "character-entities": "^2.0.0" }, @@ -5521,6 +6878,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -5530,6 +6888,7 @@ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5539,6 +6898,7 @@ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" }, @@ -5546,25 +6906,12 @@ "node": ">= 10" } }, - "node_modules/default-gateway/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/default-gateway/node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -5588,6 +6935,7 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -5600,107 +6948,16 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } }, - "node_modules/default-gateway/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-gateway/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/default-gateway/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/default-gateway/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-gateway/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/default-gateway/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/default-gateway/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/default-gateway/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -5718,6 +6975,7 @@ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5726,6 +6984,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -5734,6 +6993,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -5742,6 +7002,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", "engines": { "node": ">=6" } @@ -5750,21 +7011,38 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", "dependencies": { "dequal": "^2.0.0" }, @@ -5778,6 +7056,7 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -5787,6 +7066,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -5799,6 +7079,7 @@ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, + "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -5810,6 +7091,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" @@ -5819,6 +7101,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -5837,12 +7120,14 @@ "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" }, @@ -5854,9 +7139,10 @@ } }, "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -5871,21 +7157,17 @@ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" } }, - "node_modules/dot-case/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true - }, "node_modules/dot-prop": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz", "integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==", + "license": "MIT", "dependencies": { "is-obj": "^1.0.0" }, @@ -5893,29 +7175,83 @@ "node": ">=4" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "license": "BSD-3-Clause", "dependencies": { "readable-stream": "^2.0.2" } }, + "node_modules/duplexer2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/duplexer2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexer2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/duplexer2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/duplexer3": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==" + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", + "license": "BSD-3-Clause" }, "node_modules/duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "license": "MIT", "dependencies": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -5923,10 +7259,47 @@ "stream-shift": "^1.0.0" } }, + "node_modules/duplexify/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/duplexify/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/duplexify/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/duplexify/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "license": "MIT", "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -5936,6 +7309,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/editions/-/editions-2.3.1.tgz", "integrity": "sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA==", + "license": "MIT", "dependencies": { "errlop": "^2.0.0", "semver": "^6.3.0" @@ -5950,19 +7324,28 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.65", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.65.tgz", - "integrity": "sha512-PWVzBjghx7/wop6n22vS2MLU8tKGd4Q91aCEGhG/TYmW6PP5OcSXcdnxTe1NNt0T66N8D6jxh4kC8UsdzOGaIw==", - "dev": true + "version": "1.5.190", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.190.tgz", + "integrity": "sha512-k4McmnB2091YIsdCgkS0fMVMPOJgxl93ltFzaryXqwip1AaxeDqKCGLxkXODDA5Ab/D+tV5EL5+aTx76RvLRxw==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, "node_modules/emojis-list": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -5974,9 +7357,10 @@ "license": "MIT" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -5985,6 +7369,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", "dependencies": { "iconv-lite": "^0.6.2" } @@ -5993,6 +7378,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -6001,24 +7387,25 @@ } }, "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", "dependencies": { "once": "^1.4.0" } }, "node_modules/engine.io": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", - "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "license": "MIT", "dependencies": { - "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", - "cookie": "~0.4.1", + "cookie": "~0.7.2", "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", @@ -6029,23 +7416,25 @@ } }, "node_modules/engine.io-client": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz", - "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==", + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz", + "integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==", + "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", "ws": "~8.17.1", - "xmlhttprequest-ssl": "~2.0.0" + "xmlhttprequest-ssl": "~2.1.1" } }, "node_modules/engine.io-client/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -6056,33 +7445,31 @@ } } }, - "node_modules/engine.io-client/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/engine.io-parser": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", - "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", "engines": { "node": ">=10.0.0" } }, "node_modules/engine.io/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/engine.io/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -6093,16 +7480,12 @@ } } }, - "node_modules/engine.io/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", + "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -6115,6 +7498,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -6123,10 +7507,11 @@ } }, "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", "dev": true, + "license": "MIT", "bin": { "envinfo": "dist/cli.js" }, @@ -6137,12 +7522,14 @@ "node_modules/err-code": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", - "integrity": "sha512-CJAN+O0/yA1CKfRn9SXOGctSpEM7DCon/r/5r2eXFMY2zCCJBasFhcM5I+1kh3Ap11FsQCX+vGHceNPvpWKhoA==" + "integrity": "sha512-CJAN+O0/yA1CKfRn9SXOGctSpEM7DCon/r/5r2eXFMY2zCCJBasFhcM5I+1kh3Ap11FsQCX+vGHceNPvpWKhoA==", + "license": "MIT" }, "node_modules/errlop": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/errlop/-/errlop-2.2.0.tgz", "integrity": "sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw==", + "license": "MIT", "engines": { "node": ">=0.8" }, @@ -6154,17 +7541,16 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -6173,25 +7559,57 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "dev": true + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } }, "node_modules/es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" }, "node_modules/es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "license": "MIT", "dependencies": { "es6-promise": "^4.0.3" } @@ -6200,7 +7618,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -6208,14 +7626,19 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", "engines": { - "node": ">=0.8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint-scope": { @@ -6223,6 +7646,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -6236,6 +7660,7 @@ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -6249,6 +7674,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -6261,6 +7687,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -6270,6 +7697,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -6278,6 +7706,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" @@ -6288,6 +7717,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -6296,6 +7726,7 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6304,38 +7735,48 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.x" } }, "node_modules/execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "license": "MIT", "dependencies": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, "node_modules/expand-tilde": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", "integrity": "sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==", + "license": "MIT", "dependencies": { "os-homedir": "^1.0.1" }, @@ -6344,36 +7785,37 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -6382,12 +7824,17 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -6395,17 +7842,20 @@ "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" }, "node_modules/extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", "dependencies": { "is-extendable": "^0.1.0" }, @@ -6417,6 +7867,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "license": "MIT", "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -6432,24 +7883,27 @@ "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "engines": [ "node >=0.6.0" - ] + ], + "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -6460,6 +7914,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -6470,28 +7925,42 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", - "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", - "dev": true + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4.9.1" } }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -6513,7 +7982,7 @@ "version": "0.11.4", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, + "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -6531,6 +8000,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -6538,119 +8008,20 @@ "node": ">=4" } }, - "node_modules/file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/file-loader/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/file-loader/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "optional": true, - "peer": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/file-loader/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "optional": true, - "peer": true - }, - "node_modules/file-loader/node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "optional": true, - "peer": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/file-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/file-loader/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">=0.8.0" } }, "node_modules/file-name": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/file-name/-/file-name-0.1.0.tgz", "integrity": "sha512-Q8SskhjF4eUk/xoQkmubwLkoHwOTv6Jj/WGtOVLKkZ0vvM+LipkSXugkn1F/+mjWXU32AXLZB3qaz0arUzgtRw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6659,6 +8030,7 @@ "version": "3.6.1", "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "license": "BSD-3-Clause", "engines": { "node": ">= 0.4.0" } @@ -6668,6 +8040,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -6676,12 +8049,13 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -6696,6 +8070,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -6703,12 +8078,14 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/find-file-up": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/find-file-up/-/find-file-up-0.1.3.tgz", "integrity": "sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==", + "license": "MIT", "dependencies": { "fs-exists-sync": "^0.1.0", "resolve-dir": "^0.1.0" @@ -6721,6 +8098,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/find-pkg/-/find-pkg-0.1.2.tgz", "integrity": "sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==", + "license": "MIT", "dependencies": { "find-file-up": "^0.1.2" }, @@ -6731,13 +8109,15 @@ "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -6746,22 +8126,94 @@ "node": ">=8" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } + "node_modules/firebase": { + "version": "10.7.1", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.7.1.tgz", + "integrity": "sha512-Mlt7y7zQ43FtKp4SCyYie3tnrOL3UMF2XXiV4ZXMrC0d0wtcOYmABuybhkJpJCKILpdekxr39wjnaai0DZlWFg==", + "license": "Apache-2.0", + "dependencies": { + "@firebase/analytics": "0.10.0", + "@firebase/analytics-compat": "0.2.6", + "@firebase/app": "0.9.25", + "@firebase/app-check": "0.8.1", + "@firebase/app-check-compat": "0.3.8", + "@firebase/app-compat": "0.2.25", + "@firebase/app-types": "0.9.0", + "@firebase/auth": "1.5.1", + "@firebase/auth-compat": "0.5.1", + "@firebase/database": "1.0.2", + "@firebase/database-compat": "1.0.2", + "@firebase/firestore": "4.4.0", + "@firebase/firestore-compat": "0.3.23", + "@firebase/functions": "0.11.0", + "@firebase/functions-compat": "0.3.6", + "@firebase/installations": "0.6.4", + "@firebase/installations-compat": "0.2.4", + "@firebase/messaging": "0.12.5", + "@firebase/messaging-compat": "0.2.5", + "@firebase/performance": "0.6.4", + "@firebase/performance-compat": "0.2.4", + "@firebase/remote-config": "0.4.4", + "@firebase/remote-config-compat": "0.2.4", + "@firebase/storage": "0.12.0", + "@firebase/storage-compat": "0.3.3", + "@firebase/util": "1.9.3" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/flush-write-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/flush-write-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/flush-write-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" }, - "node_modules/flush-write-stream": { + "node_modules/flush-write-stream/node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" + "safe-buffer": "~5.1.0" } }, "node_modules/fn.name": { @@ -6780,6 +8232,7 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -6789,22 +8242,43 @@ } } }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.5.tgz", + "integrity": "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==", + "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35", + "safe-buffer": "^5.2.1" }, "engines": { "node": ">= 0.12" @@ -6822,6 +8296,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6831,6 +8306,7 @@ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true, + "license": "MIT", "engines": { "node": "*" }, @@ -6843,6 +8319,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6851,20 +8328,59 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" } }, + "node_modules/from2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/from2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/from2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/from2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" }, "node_modules/fs-exists-sync": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", "integrity": "sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6873,6 +8389,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", "integrity": "sha512-V3Z3WZWVUYd8hoCL5xfXJCaHWYzmtwW5XWYSlLgERi8PWd8bx1kUHUk8L1BT57e49oKnDDD180mjfrHc1yA9rg==", + "license": "MIT", "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^3.0.0", @@ -6880,16 +8397,18 @@ } }, "node_modules/fs-monkey": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", - "dev": true + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz", + "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", + "dev": true, + "license": "Unlicense" }, "node_modules/fs-write-stream-atomic": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", "integrity": "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==", "deprecated": "This package is no longer supported.", + "license": "ISC", "dependencies": { "graceful-fs": "^4.1.2", "iferr": "^0.1.5", @@ -6900,7 +8419,8 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -6908,6 +8428,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -6920,6 +8441,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6927,27 +8449,44 @@ "node_modules/genfun": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/genfun/-/genfun-4.0.1.tgz", - "integrity": "sha512-48yv1eDS5Qrz6cbSDBBik0u7jCgC/eA9eZrl9MIN1LfKzFTuGt6EHgr31YM8yT9cjb5BplXb4Iz3VtOYmgt8Jg==" + "integrity": "sha512-48yv1eDS5Qrz6cbSDBBik0u7jCgC/eA9eZrl9MIN1LfKzFTuGt6EHgr31YM8yT9cjb5BplXb4Iz3VtOYmgt8Jg==", + "license": "CC0-1.0" }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -6956,18 +8495,51 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream/node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" } @@ -6976,6 +8548,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/git-branch/-/git-branch-1.0.0.tgz", "integrity": "sha512-ZTzuqw5Df8fyLXQWrX6hK+4FpNCdKzMcERlxENEGO5aKcLmG7MAszhrMhluUKNKmOS/JAGijDMQDXDCDw1mE/A==", + "license": "MIT", "engines": { "node": ">=0.8" } @@ -6984,6 +8557,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz", "integrity": "sha512-KcJ2dlrrP5DbBnYIZ2nlikALfRhKzNSX0stvv3ImJ+fvC4hXKoV+U+74SV0upg+jlQZbrtQzc0bu6/Zh+7aQbg==", + "license": "MIT", "dependencies": { "extend-shallow": "^2.0.1", "fs-exists-sync": "^0.1.0", @@ -6997,6 +8571,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/git-repo-name/-/git-repo-name-0.6.0.tgz", "integrity": "sha512-DF4XxB6H+Te79JA08/QF/IjIv+j+0gF990WlgAX3SXXU2irfqvBc/xxlAIh6eJWYaKz45MrrGVBFS0Qc4bBz5g==", + "license": "MIT", "dependencies": { "cwd": "^0.9.1", "file-name": "^0.1.0", @@ -7011,6 +8586,7 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/git-username/-/git-username-0.5.1.tgz", "integrity": "sha512-xjUjrj3i4kup2A3a/ZVZB1Nt0PUX7SU7KeVqIbXPdslT7NbNfyO04JMxBv4gar77JePdS+A6f05jG1Viy6+U1w==", + "license": "MIT", "dependencies": { "remote-origin-url": "^0.4.0" }, @@ -7022,6 +8598,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-0.2.0.tgz", "integrity": "sha512-amapZFADOJtHvX2URcRfbzG2OFcW+UAwmdK2kht2N2vsH5Py65VxI5yZTlD2DjmxVhTz6htFoVCxROYUJaYOXQ==", + "license": "MIT", "dependencies": { "ini": "^1.3.3" }, @@ -7033,6 +8610,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/remote-origin-url/-/remote-origin-url-0.4.0.tgz", "integrity": "sha512-HYhdsT2pNd0LP4Osb0vtQ1iassxIc3Yk1oze7j8dMJFciMkW8e0rdg9E/mOunqtSVHSzvMfwLDIYzPnEDmpk6Q==", + "license": "MIT", "dependencies": { "parse-git-config": "^0.2.0" }, @@ -7045,6 +8623,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -7065,6 +8644,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -7076,12 +8656,14 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/global-dirs": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", "integrity": "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==", + "license": "MIT", "dependencies": { "ini": "^1.3.4" }, @@ -7093,6 +8675,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", "integrity": "sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==", + "license": "MIT", "dependencies": { "global-prefix": "^0.1.4", "is-windows": "^0.2.0" @@ -7105,6 +8688,7 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", "integrity": "sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==", + "license": "MIT", "dependencies": { "homedir-polyfill": "^1.0.0", "ini": "^1.3.4", @@ -7115,19 +8699,12 @@ "node": ">=0.10.0" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, "node_modules/globby": { "version": "13.2.2", "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", "dev": true, + "license": "MIT", "dependencies": { "dir-glob": "^3.0.1", "fast-glob": "^3.3.0", @@ -7143,11 +8720,12 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7157,6 +8735,7 @@ "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", "integrity": "sha512-Y/K3EDuiQN9rTZhBvPRWMLXIKdeD1Rj0nzunfoi0Yyn5WBEbzxXKU9Ub2X41oZBagVWOBU3MuDonFMgPWQFnwg==", + "license": "MIT", "dependencies": { "create-error-class": "^3.0.0", "duplexer3": "^0.1.4", @@ -7174,16 +8753,36 @@ "node": ">=4" } }, + "node_modules/got/node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/got/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" }, "node_modules/gzip-size": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", "dev": true, + "license": "MIT", "dependencies": { "duplexer": "^0.1.2" }, @@ -7198,12 +8797,14 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "license": "ISC", "engines": { "node": ">=4" } @@ -7213,6 +8814,7 @@ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "deprecated": "this library is no longer supported", + "license": "MIT", "dependencies": { "ajv": "^6.12.3", "har-schema": "^2.0.0" @@ -7225,6 +8827,7 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -7239,12 +8842,14 @@ "node_modules/har-validator/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", "engines": { "node": ">=8" } @@ -7253,6 +8858,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -7260,10 +8866,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -7271,10 +8878,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { "node": ">= 0.4" }, @@ -7286,6 +8897,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -7294,15 +8906,16 @@ } }, "node_modules/hast-util-from-parse5": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz", - "integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", - "hastscript": "^8.0.0", - "property-information": "^6.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" @@ -7312,23 +8925,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-from-parse5/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/hast-util-from-parse5/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/hast-util-parse-selector": { + "node_modules/hast-util-from-parse5/node_modules/hast-util-parse-selector": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -7337,18 +8938,38 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-parse-selector/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "node_modules/hast-util-from-parse5/node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", "dependencies": { - "@types/unist": "*" + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, "node_modules/hast-util-raw": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.0.4.tgz", - "integrity": "sha512-LHE65TD2YiNsHD3YuXcKPHXPLuYh/gjp12mOfU8jxSrm1f/yJpsb0F/KKljS6U9LJoP0Ux+tCe8iJ2AsPzTdgA==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", @@ -7369,23 +8990,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-raw/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/hast-util-raw/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.2.tgz", - "integrity": "sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", @@ -7397,34 +9006,22 @@ "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", - "style-to-object": "^1.0.0", + "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-to-jsx-runtime/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" + "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-jsx-runtime/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/hast-util-to-parse5": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "comma-separated-tokens": "^2.0.0", @@ -7439,18 +9036,21 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-to-parse5/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" + "node_modules/hast-util-to-parse5/node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/hast-util-whitespace": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -7459,24 +9059,17 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-whitespace/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/hastscript": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", - "integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^4.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0" + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" }, "funding": { "type": "opencollective", @@ -7484,17 +9077,58 @@ } }, "node_modules/hastscript/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "license": "MIT", "dependencies": { - "@types/unist": "*" + "@types/unist": "^2" + } + }, + "node_modules/hastscript/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/hastscript/node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hastscript/node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hastscript/node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", "bin": { "he": "bin/he" } @@ -7518,6 +9152,7 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", "dependencies": { "react-is": "^16.7.0" } @@ -7525,12 +9160,14 @@ "node_modules/hoist-non-react-statics/node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" }, "node_modules/homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "license": "MIT", "dependencies": { "parse-passwd": "^1.0.0" }, @@ -7541,13 +9178,15 @@ "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "license": "ISC" }, "node_modules/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -7555,10 +9194,50 @@ "wbuf": "^1.1.0" } }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/html-entities": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", "dev": true, "funding": [ { @@ -7569,18 +9248,21 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ] + ], + "license": "MIT" }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/html-tokenize": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/html-tokenize/-/html-tokenize-2.0.1.tgz", "integrity": "sha512-QY6S+hZ0f5m1WT8WffYN+Hg+xm/w5I8XeUcAq/ZYP5wVC8xbKi4Whhru3FtrAebD5EhBW8rmFzkDI6eCAuFe2w==", + "license": "MIT", "dependencies": { "buffer-from": "~0.1.1", "inherits": "~2.0.1", @@ -7592,56 +9274,11 @@ "html-tokenize": "bin/cmd.js" } }, - "node_modules/html-tokenize/node_modules/buffer-from": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-0.1.2.tgz", - "integrity": "sha512-RiWIenusJsmI2KcvqQABB83tLxCByE3upSP8QU3rJDMVFGPWLvPQJt/O1Su9moRWeH7d+Q2HYb68f6+v+tw2vg==" - }, - "node_modules/html-tokenize/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "node_modules/html-tokenize/node_modules/readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/html-tokenize/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" - }, - "node_modules/html-tokenize/node_modules/through2": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", - "integrity": "sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==", - "dependencies": { - "readable-stream": "~1.0.17", - "xtend": "~2.1.1" - } - }, - "node_modules/html-tokenize/node_modules/xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==", - "dependencies": { - "object-keys": "~0.4.0" - }, - "engines": { - "node": ">=0.4" - } - }, "node_modules/html-url-attributes": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" @@ -7651,6 +9288,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -7659,18 +9297,21 @@ "node_modules/http-cache-semantics": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "license": "BSD-2-Clause" }, "node_modules/http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -7683,16 +9324,17 @@ } }, "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "license": "MIT" }, "node_modules/http-proxy": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, + "license": "MIT", "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -7706,6 +9348,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "license": "MIT", "dependencies": { "agent-base": "4", "debug": "3.1.0" @@ -7714,11 +9357,27 @@ "node": ">= 4.5.0" } }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -7738,10 +9397,24 @@ } } }, + "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -7756,6 +9429,7 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "license": "MIT", "dependencies": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -7764,11 +9438,21 @@ "node": ">= 4.5.0" } }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, "node_modules/human-signals": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=8.12.0" } @@ -7777,6 +9461,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", "dependencies": { "ms": "^2.0.0" } @@ -7784,13 +9469,15 @@ "node_modules/humps": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/humps/-/humps-2.0.1.tgz", - "integrity": "sha512-E0eIbrFWUhwfXJmsbdjRQFQPrl5pTEoKlz163j1mTqqUnU9PgR4AgB8AIITzuB3vLBdxZXyZ9TDIrwB2OASz4g==" + "integrity": "sha512-E0eIbrFWUhwfXJmsbdjRQFQPrl5pTEoKlz163j1mTqqUnU9PgR4AgB8AIITzuB3vLBdxZXyZ9TDIrwB2OASz4g==", + "license": "MIT" }, "node_modules/husky": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", "dev": true, + "license": "MIT", "bin": { "husky": "lib/bin.js" }, @@ -7805,6 +9492,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -7817,6 +9505,7 @@ "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -7824,16 +9513,24 @@ "postcss": "^8.1.0" } }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "license": "ISC" + }, "node_modules/iferr": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==" + "integrity": "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==", + "license": "MIT" }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -7842,7 +9539,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/ignore-loader": { "version": "0.1.2", @@ -7854,6 +9552,7 @@ "version": "0.8.3", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.8.3.tgz", "integrity": "sha512-SMtq1AJ+aqHB45c3FsB4ERK0UCiA2d3H1uq8s+8T0Pf8A3W4teyBQyaFaktH6xvZqh+npwlKU7i4fJo0r7TYTg==", + "license": "MIT", "dependencies": { "queue": "6.0.1" }, @@ -7865,15 +9564,17 @@ } }, "node_modules/immutable": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", - "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==", - "dev": true + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", + "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", + "dev": true, + "license": "MIT" }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -7889,15 +9590,17 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -7916,6 +9619,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -7925,6 +9629,7 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -7933,22 +9638,26 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" }, "node_modules/inline-style-parser": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", - "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==" + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "license": "MIT" }, "node_modules/inquirer": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "license": "MIT", "dependencies": { "ansi-escapes": "^3.2.0", "chalk": "^2.4.2", @@ -7972,6 +9681,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -7983,6 +9693,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -7996,6 +9707,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -8003,12 +9715,23 @@ "node_modules/inquirer/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/inquirer/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, "node_modules/inquirer/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { "node": ">=4" } @@ -8017,6 +9740,7 @@ "version": "6.6.7", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "license": "Apache-2.0", "dependencies": { "tslib": "^1.9.0" }, @@ -8028,6 +9752,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -8035,11 +9760,18 @@ "node": ">=4" } }, + "node_modules/inquirer/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, "node_modules/interpret": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.13.0" } @@ -8047,20 +9779,22 @@ "node_modules/ip": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==" + "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", + "license": "MIT" }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", "engines": { "node": ">= 0.10" } }, "node_modules/is-alphabetical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", - "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", "license": "MIT", "funding": { "type": "github", @@ -8068,13 +9802,13 @@ } }, "node_modules/is-alphanumerical": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", - "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", "license": "MIT", "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" }, "funding": { "type": "github", @@ -8084,13 +9818,15 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -8116,14 +9852,28 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "engines": { "node": ">=4" } }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-ci": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "license": "MIT", "dependencies": { "ci-info": "^1.5.0" }, @@ -8131,10 +9881,17 @@ "is-ci": "bin.js" } }, + "node_modules/is-ci/node_modules/ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "license": "MIT" + }, "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -8146,9 +9903,9 @@ } }, "node_modules/is-decimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", - "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", "license": "MIT", "funding": { "type": "github", @@ -8160,6 +9917,7 @@ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, + "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -8174,6 +9932,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8183,6 +9942,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8191,6 +9951,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "license": "MIT", "engines": { "node": ">=4" } @@ -8200,6 +9961,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -8208,9 +9970,9 @@ } }, "node_modules/is-hexadecimal": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", - "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", "license": "MIT", "funding": { "type": "github", @@ -8221,6 +9983,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", "integrity": "sha512-ERNhMg+i/XgDwPIPF3u24qpajVreaiSuvpb1Uu0jugw7KKcxGyCX8cgp8P5fwTmAuXku6beDHHECdKArjlg7tw==", + "license": "MIT", "dependencies": { "global-dirs": "^0.1.0", "is-path-inside": "^1.0.0" @@ -8233,6 +9996,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", "integrity": "sha512-9r39FIr3d+KD9SbX0sfMsHzb5PP3uimOiwr3YupUaUFG4W0l1U57Rx3utpttV7qz5U3jmrO5auUa04LU9pyHsg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8242,6 +10006,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -8250,6 +10015,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8258,6 +10024,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==", + "license": "MIT", "dependencies": { "path-is-inside": "^1.0.1" }, @@ -8266,12 +10033,12 @@ } }, "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -8282,6 +10049,7 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, + "license": "MIT", "dependencies": { "isobject": "^3.0.1" }, @@ -8293,6 +10061,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", "integrity": "sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8301,27 +10070,49 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "license": "MIT" }, "node_modules/is-windows": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", "integrity": "sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8330,25 +10121,29 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, "node_modules/isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8356,12 +10151,14 @@ "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "license": "MIT" }, "node_modules/istextorbinary": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.6.0.tgz", "integrity": "sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA==", + "license": "MIT", "dependencies": { "binaryextensions": "^2.1.2", "editions": "^2.2.0", @@ -8376,8 +10173,8 @@ }, "node_modules/jest-util": { "version": "29.7.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha1-I8K2K/sivoK0TemAVYAv83EPwLw=", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, "license": "MIT", "dependencies": { @@ -8392,34 +10189,20 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-util/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha1-QnmmICinsfJi80c/yWBfXiGMWbQ=", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", + "jest-util": "^29.7.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-worker/node_modules/supports-color": { @@ -8427,6 +10210,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -8438,10 +10222,11 @@ } }, "node_modules/jiti": { - "version": "1.21.6", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", - "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, + "license": "MIT", "bin": { "jiti": "bin/jiti.js" } @@ -8449,13 +10234,15 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -8466,12 +10253,14 @@ "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "license": "MIT" }, "node_modules/jsesc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -8482,45 +10271,52 @@ "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" }, "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, + "license": "MIT", "bin": { "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/jsonfile": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", "integrity": "sha512-oBko6ZHlubVB5mRFkur5vgYR1UyqX+S6Y/oCfLhqNdcc2fYFlDpIoNc7AfKS1KOGcnNAkvsr0grLck9ANM815w==", + "license": "MIT", "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -8529,6 +10325,7 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "license": "MIT", "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -8544,19 +10341,11 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", @@ -8567,6 +10356,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", "integrity": "sha512-Be1YRHWWlZaSsrz2U+VInk+tO0EwLIyV+23RhWLINJYwg/UIikxjlj3MhH37/6/EDCAusjajvMkMMUXRaMWl/w==", + "license": "MIT", "dependencies": { "package-json": "^4.0.0" }, @@ -8575,10 +10365,11 @@ } }, "node_modules/launch-editor": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", - "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz", + "integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==", "dev": true, + "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" @@ -8588,6 +10379,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8596,12 +10388,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/levdist/-/levdist-1.0.0.tgz", "integrity": "sha512-YguwC2spb0pqpJM3a5OsBhih/GG2ZHoaSHnmBqhEI7997a36buhqcRTegEjozHxyxByIwLpZHZTVYMThq+Zd3g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lilconfig": { "version": "3.1.3", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha1-obz9Ylf5WFv1rhTO7rt7VZAl5MQ=", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "dev": true, "license": "MIT", "engines": { @@ -8612,10 +10405,11 @@ } }, "node_modules/line-diff": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/line-diff/-/line-diff-2.1.1.tgz", - "integrity": "sha512-vswdynAI5AMPJacOo2o+JJ4caDJbnY2NEqms4MhMW0NJbjh3skP/brpVTAgBxrg55NRZ2Vtw88ef18hnagIpYQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/line-diff/-/line-diff-2.1.2.tgz", + "integrity": "sha512-rkfwQJRXQHo14BjphIid+73/a4nf/VVAWDqhIr3WtWXrybGYnV27X8KqngIKH1cxd0z7u2OM/JTV1g6I57z2EQ==", "dev": true, + "license": "MIT", "dependencies": { "levdist": "^1.0.0" } @@ -8623,13 +10417,15 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.11.5" } @@ -8639,6 +10435,7 @@ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", "dev": true, + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -8648,11 +10445,25 @@ "node": ">=4.0.0" } }, + "node_modules/loader-utils/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -8663,25 +10474,33 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.memoize": { "version": "4.1.2", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", "dev": true, "license": "MIT" }, "node_modules/lodash.uniq": { "version": "4.5.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", "dev": true, "license": "MIT" }, @@ -8689,6 +10508,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "license": "MIT", "dependencies": { "chalk": "^2.0.1" }, @@ -8700,6 +10520,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -8711,6 +10532,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -8724,6 +10546,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -8731,12 +10554,23 @@ "node_modules/log-symbols/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/log-symbols/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, "node_modules/log-symbols/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { "node": ">=4" } @@ -8745,6 +10579,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -8769,10 +10604,17 @@ "node": ">= 12.0.0" } }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -8782,6 +10624,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -8794,20 +10637,16 @@ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } }, - "node_modules/lower-case/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true - }, "node_modules/lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8827,18 +10666,20 @@ } }, "node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "yallist": "^3.0.2" } }, "node_modules/lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "license": "MIT", "bin": { "lz-string": "bin/bin.js" } @@ -8847,6 +10688,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "license": "MIT", "dependencies": { "pify": "^3.0.0" }, @@ -8858,12 +10700,14 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/make-fetch-happen": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-2.6.0.tgz", "integrity": "sha512-FFq0lNI0ax+n9IWzWpH8A4JdgYiAp2DDYIZ3rsaav8JDe8I+72CzK6PQW/oom15YDZpV5bYW/9INd6nIJ2ZfZw==", + "license": "CC0-1.0", "dependencies": { "agentkeepalive": "^3.3.0", "cacache": "^10.0.0", @@ -8882,6 +10726,7 @@ "version": "10.0.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", + "license": "ISC", "dependencies": { "bluebird": "^3.5.1", "chownr": "^1.0.1", @@ -8902,6 +10747,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", + "license": "BSD-2-Clause", "dependencies": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", @@ -8918,20 +10764,53 @@ "node": ">=4.0.0" } }, + "node_modules/make-fetch-happen/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "license": "ISC", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, "node_modules/make-fetch-happen/node_modules/pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, + "node_modules/make-fetch-happen/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "node_modules/make-fetch-happen/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -8939,23 +10818,66 @@ "rimraf": "bin.js" } }, + "node_modules/make-fetch-happen/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/make-fetch-happen/node_modules/ssri": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", + "license": "ISC", "dependencies": { "safe-buffer": "^5.1.1" } }, + "node_modules/make-fetch-happen/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/make-fetch-happen/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/make-fetch-happen/node_modules/y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/make-fetch-happen/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, "node_modules/mdast-util-from-markdown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", @@ -8975,15 +10897,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-from-markdown/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/mdast-util-mdx-expression": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", @@ -8997,18 +10915,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdx-expression/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/mdast-util-mdx-jsx": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", @@ -9028,104 +10939,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/mdast-util-mdx-jsx/node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/is-alphabetical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/is-alphanumerical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", - "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/is-decimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/is-hexadecimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", - "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", - "dependencies": { - "@types/unist": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" - }, "node_modules/mdast-util-mdxjs-esm": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", @@ -9139,18 +10957,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdxjs-esm/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/mdast-util-phrasing": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" @@ -9164,6 +10975,7 @@ "version": "13.2.0", "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -9180,18 +10992,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-to-hast/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/mdast-util-to-markdown": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", @@ -9208,15 +11013,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-to-markdown/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/mdast-util-to-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0" }, @@ -9229,12 +11030,14 @@ "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true + "dev": true, + "license": "CC0-1.0" }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9244,6 +11047,7 @@ "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", "dev": true, + "license": "Unlicense", "dependencies": { "fs-monkey": "^1.0.4" }, @@ -9252,21 +11056,27 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -9275,14 +11085,15 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/micromark": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.1.tgz", - "integrity": "sha512-eBPdkcoCNvYcxQOAKAlceo5SNdzZWfF+FcSupREAzdAh9rRmE239CEQAiTwIgblwnoM8zzj35sZ5ZwvSEOF6Kw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", "funding": [ { "type": "GitHub Sponsors", @@ -9293,6 +11104,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", @@ -9314,9 +11126,9 @@ } }, "node_modules/micromark-core-commonmark": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.2.tgz", - "integrity": "sha512-FKjQKbxd1cibWMM1P9N+H8TwlgGgSkWZMmfuVucLCHaYqeSvJ0hFeHsIa65pA2nYbes0f8LDHPMrd9X7Ujxg9w==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", "funding": [ { "type": "GitHub Sponsors", @@ -9327,6 +11139,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", @@ -9360,6 +11173,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -9380,6 +11194,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", @@ -9401,6 +11216,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" @@ -9420,6 +11236,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -9441,6 +11258,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", @@ -9462,6 +11280,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" @@ -9481,6 +11300,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } @@ -9499,6 +11319,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", @@ -9519,6 +11340,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" @@ -9538,6 +11360,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } @@ -9556,6 +11379,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", @@ -9576,7 +11400,8 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-html-tag-name": { "version": "2.0.1", @@ -9591,7 +11416,8 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-normalize-identifier": { "version": "2.0.1", @@ -9607,6 +11433,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0" } @@ -9625,6 +11452,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" } @@ -9643,6 +11471,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", @@ -9650,9 +11479,9 @@ } }, "node_modules/micromark-util-subtokenize": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.3.tgz", - "integrity": "sha512-VXJJuNxYWSoYL6AJ6OQECCFGhIU2GGHMw8tahogePBrjkG8aCCas3ibkp7RnVOSTClg2is05/R7maAhF1XyQMg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", "funding": [ { "type": "GitHub Sponsors", @@ -9663,6 +11492,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", @@ -9683,12 +11513,13 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-types": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.1.tgz", - "integrity": "sha512-534m2WhVTddrcKVepwmVEVnUAmtrx9bfIjNoQHRqfnvdaHQiFytEhJoTgpWJvDEXCO5gLTQh3wYC1PgOJA4NSQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", "funding": [ { "type": "GitHub Sponsors", @@ -9698,29 +11529,15 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] - }, - "node_modules/micromark/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } + ], + "license": "MIT" }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -9733,6 +11550,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -9741,9 +11559,10 @@ } }, "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9752,6 +11571,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -9759,10 +11579,20 @@ "node": ">= 0.6" } }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mimer/-/mimer-1.1.0.tgz", "integrity": "sha512-y9dVfy2uiycQvDNiAYW6zp49ZhFlXDMr5wfdOiMbdzGM/0N5LNR6HTUn3un+WUQcM0koaw8FMTG1bt5EnHJdvQ==", + "license": "MIT", "bin": { "mimer": "bin/mimer" }, @@ -9771,18 +11601,21 @@ } }, "node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/mini-css-extract-plugin": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.0.tgz", - "integrity": "sha512-Zs1YsZVfemekSZG+44vBsYTLQORkPMwnlv+aehcxK/NLKC+EGhDB39/YePYYqx/sTk6NnYpuqikhSn7+JIevTA==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz", + "integrity": "sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==", "dev": true, + "license": "MIT", "dependencies": { "schema-utils": "^4.0.0", "tapable": "^2.2.1" @@ -9802,12 +11635,14 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -9819,6 +11654,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9827,6 +11663,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-1.3.1.tgz", "integrity": "sha512-/6rB8YXFbAtsUVRphIRQqB0+9c7VaPHCjVtvto+JqwVxgz8Zz+I+f68/JgQ+Pb4VlZb2svA9OtdXnHHsZz7ltg==", + "license": "BSD-2-Clause", "dependencies": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", @@ -9840,10 +11677,57 @@ "through2": "^2.0.0" } }, + "node_modules/mississippi/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/mississippi/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/mississippi/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/mississippi/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/mississippi/node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", "dependencies": { "minimist": "^1.2.6" }, @@ -9852,16 +11736,16 @@ } }, "node_modules/morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", + "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", "license": "MIT", "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.0.2" + "on-headers": "~1.1.0" }, "engines": { "node": ">= 0.8.0" @@ -9899,6 +11783,7 @@ "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "integrity": "sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==", "deprecated": "This package is no longer supported.", + "license": "ISC", "dependencies": { "aproba": "^1.1.1", "copy-concurrently": "^1.0.0", @@ -9913,6 +11798,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -9925,15 +11811,17 @@ "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/mrmime": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", - "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -9941,13 +11829,15 @@ "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/multicast-dns": { "version": "7.2.5", "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, + "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -9960,6 +11850,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-1.0.2.tgz", "integrity": "sha512-6uiC9OvY71vzSGX8lZvSqscE7ft9nPupJ8fMjrCNRAUy2LREUW42UL+V/NTrogr6rFgRydUrCX4ZitfpSNkSCQ==", + "license": "MIT", "dependencies": { "duplexer2": "^0.1.2", "object-assign": "^4.1.0" @@ -9968,17 +11859,32 @@ "node_modules/mute-stream": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==" + "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==", + "license": "ISC" }, "node_modules/nanoid": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", - "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==" + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } }, "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9987,29 +11893,34 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dev": true, + "license": "MIT", "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" } }, - "node_modules/no-case/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true }, "node_modules/node-fetch-npm": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz", "integrity": "sha512-iOuIQDWDyjhv9qSDrj9aq/klt6F9z1p2otB3AV7v3zBDcL/x+OfGsvGQZZCcMZbUf4Ujw1xGNQkjvGnVT22cKg==", "deprecated": "This module is not used anymore, npm uses minipass-fetch for its fetch implementation now", + "license": "MIT", "dependencies": { "encoding": "^0.1.11", "json-parse-better-errors": "^1.0.0", @@ -10024,6 +11935,7 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } @@ -10032,22 +11944,25 @@ "version": "6.1.13", "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.13.tgz", "integrity": "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==", + "license": "MIT", "dependencies": { "css-select": "^5.1.0", "he": "1.2.0" } }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" }, "node_modules/nodemon": { "version": "2.0.22", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", "dev": true, + "license": "MIT", "dependencies": { "chokidar": "^3.5.2", "debug": "^3.2.7", @@ -10076,6 +11991,7 @@ "resolved": "https://registry.npmjs.org/nodemon-webpack-plugin/-/nodemon-webpack-plugin-4.8.2.tgz", "integrity": "sha512-jOMLTafIL62Iu5E5wpQ6tSXkE1fgnD1St/FNkhK6iHHhHUf/vgbnV/xRtXYP+IWItoVvgBkY1ZvGsWHz1V/SIw==", "dev": true, + "license": "MIT", "dependencies": { "@types/nodemon": "latest", "nodemon": "3.0.1" @@ -10092,6 +12008,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } @@ -10101,6 +12018,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -10110,6 +12028,7 @@ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", "dev": true, + "license": "MIT", "dependencies": { "chokidar": "^3.5.2", "debug": "^3.2.7", @@ -10134,10 +12053,11 @@ } }, "node_modules/nodemon-webpack-plugin/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -10150,6 +12070,7 @@ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -10162,6 +12083,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -10174,6 +12096,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } @@ -10183,6 +12106,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -10192,6 +12116,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } @@ -10201,6 +12126,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -10212,6 +12138,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -10223,6 +12150,7 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", "bin": { "semver": "bin/semver" } @@ -10232,6 +12160,7 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -10241,6 +12170,7 @@ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -10249,6 +12179,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-5.1.2.tgz", "integrity": "sha512-wJBsrf0qpypPT7A0LART18hCdyhpCMxeTtcb0X4IZO2jsP6Om7EHN1d9KSKiqD+KVH030RVNpWS9thk+pb7wzA==", + "license": "ISC", "dependencies": { "hosted-git-info": "^2.4.2", "osenv": "^0.1.4", @@ -10260,6 +12191,7 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", "bin": { "semver": "bin/semver" } @@ -10268,6 +12200,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-1.0.4.tgz", "integrity": "sha512-MKxNdeyOZysPRTTbHtW0M5Fw38Jo/3ARsoGw5qjCfS+XGjvNB/Gb4qtAZUFmKPM2mVum+eX559eHvKywU856BQ==", + "license": "CC0-1.0", "dependencies": { "npm-package-arg": "^5.1.2", "semver": "^5.3.0" @@ -10277,25 +12210,29 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", "bin": { "semver": "bin/semver" } }, "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", "dependencies": { - "path-key": "^2.0.0" + "path-key": "^3.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -10307,6 +12244,7 @@ "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "license": "Apache-2.0", "engines": { "node": "*" } @@ -10315,14 +12253,16 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -10333,18 +12273,21 @@ "node_modules/object-keys": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==" + "integrity": "sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw==", + "license": "MIT" }, "node_modules/obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -10353,9 +12296,10 @@ } }, "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -10364,6 +12308,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -10378,20 +12323,26 @@ } }, "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", "dependencies": { - "mimic-fn": "^1.0.0" + "mimic-fn": "^2.1.0" }, "engines": { - "node": ">=4" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/open": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "license": "MIT", "dependencies": { "is-wsl": "^1.1.0" }, @@ -10404,6 +12355,7 @@ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", "dev": true, + "license": "(WTFPL OR MIT)", "bin": { "opener": "bin/opener-bin.js" } @@ -10412,6 +12364,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/ora/-/ora-1.4.0.tgz", "integrity": "sha512-iMK1DOQxzzh2MBlVsU42G80mnrvUhqsMh74phHtDlrcTZPK0pH6o7l7DRshK+0YsxDyEuaOkziVdvM3T0QTzpw==", + "license": "MIT", "dependencies": { "chalk": "^2.1.0", "cli-cursor": "^2.1.0", @@ -10426,6 +12379,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -10437,6 +12391,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -10450,6 +12405,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -10457,12 +12413,23 @@ "node_modules/ora/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/ora/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, "node_modules/ora/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { "node": ">=4" } @@ -10471,6 +12438,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -10482,6 +12450,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -10490,6 +12459,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -10499,6 +12469,7 @@ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "deprecated": "This package is no longer supported.", + "license": "ISC", "dependencies": { "os-homedir": "^1.0.0", "os-tmpdir": "^1.0.0" @@ -10508,6 +12479,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "license": "MIT", "engines": { "node": ">=4" } @@ -10517,6 +12489,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -10532,6 +12505,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -10544,6 +12518,7 @@ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" @@ -10557,6 +12532,7 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -10566,6 +12542,7 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -10574,6 +12551,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", "integrity": "sha512-q/R5GrMek0vzgoomq6rm9OX+3PQve8sLwTirmK30YB3Cu0Bbt9OX9M/SIUnroN5BGJkzwGsFwDaRGD9EwBOlCA==", + "license": "MIT", "dependencies": { "got": "^6.7.1", "registry-auth-token": "^3.0.1", @@ -10588,6 +12566,7 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", "bin": { "semver": "bin/semver" } @@ -10596,6 +12575,7 @@ "version": "2.7.38", "resolved": "https://registry.npmjs.org/pacote/-/pacote-2.7.38.tgz", "integrity": "sha512-XxHUyHQB7QCVBxoXeVu0yKxT+2PvJucsc0+1E+6f95lMUxEAYERgSAc71ckYXrYr35Ew3xFU/LrhdIK21GQFFA==", + "license": "CC0-1.0", "dependencies": { "bluebird": "^3.5.0", "cacache": "^9.2.9", @@ -10620,28 +12600,83 @@ "which": "^1.2.12" } }, + "node_modules/pacote/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "license": "ISC", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, "node_modules/pacote/node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", "bin": { "semver": "bin/semver" } }, + "node_modules/pacote/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "license": "ISC" + }, "node_modules/parallel-transform": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "license": "MIT", "dependencies": { "cyclist": "^1.0.1", "inherits": "^2.0.3", "readable-stream": "^2.1.5" } }, + "node_modules/parallel-transform/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/parallel-transform/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/parallel-transform/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/parallel-transform/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -10650,37 +12685,35 @@ } }, "node_modules/parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", "license": "MIT", "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/parse-entities/node_modules/character-entities": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", - "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" }, "node_modules/parse-git-config": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/parse-git-config/-/parse-git-config-1.1.1.tgz", "integrity": "sha512-S3LGXJZVSy/hswvbSkfdbKBRVsnqKrVu6j8fcvdtJ4TxosSELyQDsJPuGPXuZ+EyuYuJd3O4uAF8gcISR0OFrQ==", + "license": "MIT", "dependencies": { "extend-shallow": "^2.0.1", "fs-exists-sync": "^0.1.0", @@ -10695,6 +12728,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -10712,25 +12746,40 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/parse5": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.0.tgz", - "integrity": "sha512-ZkDsAOcxsUMZ4Lz5fVciOehNcJ+Gb8gTzcA4yl3wnc273BAybYWrQ+Ks/OjCjSEpjvQkDSeZbybK9qj2VHHdGA==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", "dependencies": { - "entities": "^4.5.0" + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" }, "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -10740,6 +12789,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -10748,6 +12798,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -10755,30 +12806,36 @@ "node_modules/path-is-inside": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==" + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", + "license": "(WTFPL OR MIT)" }, "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", "engines": { "node": ">=8" } @@ -10786,18 +12843,21 @@ "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -10809,6 +12869,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "license": "MIT", "engines": { "node": ">=4" } @@ -10818,6 +12879,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -10825,10 +12887,19 @@ "node": ">=8" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { @@ -10844,19 +12915,20 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/postcss-calc": { - "version": "10.1.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-calc/-/postcss-calc-10.1.0.tgz", - "integrity": "sha1-glSLnVKJG4fPYYGkRb6kt44u7fs=", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.1.1.tgz", + "integrity": "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==", "dev": true, "license": "MIT", "dependencies": { @@ -10870,28 +12942,14 @@ "postcss": "^8.4.38" } }, - "node_modules/postcss-calc/node_modules/postcss-selector-parser": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", - "integrity": "sha1-Qb2LVvF3wJPKSUNfZXMb7+Jda5w=", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/postcss-colormin": { - "version": "7.0.2", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-colormin/-/postcss-colormin-7.0.2.tgz", - "integrity": "sha1-bzxTwTFYFoZp9FrcOSbzXLJA744=", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.4.tgz", + "integrity": "sha512-ziQuVzQZBROpKpfeDwmrG+Vvlr0YWmY/ZAk99XD+mGEBuEojoFekL41NCsdhyNUtZI7DPOoIWIR7vQQK9xwluw==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.3", + "browserslist": "^4.25.1", "caniuse-api": "^3.0.0", "colord": "^2.9.3", "postcss-value-parser": "^4.2.0" @@ -10900,79 +12958,79 @@ "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-convert-values": { - "version": "7.0.4", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-convert-values/-/postcss-convert-values-7.0.4.tgz", - "integrity": "sha1-/BPs7d7WNl88eUtQLbz3fSmNoSw=", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.6.tgz", + "integrity": "sha512-MD/eb39Mr60hvgrqpXsgbiqluawYg/8K4nKsqRsuDX9f+xN1j6awZCUv/5tLH8ak3vYp/EMXwdcnXvfZYiejCQ==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.3", + "browserslist": "^4.25.1", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-discard-comments": { - "version": "7.0.3", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-discard-comments/-/postcss-discard-comments-7.0.3.tgz", - "integrity": "sha1-nEFOjumdNRStBqNGXMwg7B2854A=", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.4.tgz", + "integrity": "sha512-6tCUoql/ipWwKtVP/xYiFf1U9QgJ0PUvxN7pTcsQ8Ns3Fnwq1pU5D5s1MhT/XySeLq6GXNvn37U46Ded0TckWg==", "dev": true, "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.1.2" + "postcss-selector-parser": "^7.1.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-discard-duplicates": { - "version": "7.0.1", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.1.tgz", - "integrity": "sha1-+H8v5H2PAa+x6YNhwds84eiv0aM=", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.2.tgz", + "integrity": "sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==", "dev": true, "license": "MIT", "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-discard-empty": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-discard-empty/-/postcss-discard-empty-7.0.0.tgz", - "integrity": "sha1-IYgp0e8KXVFC3WLwqmDgDlmdIDM=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.1.tgz", + "integrity": "sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==", "dev": true, "license": "MIT", "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-discard-overridden": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-discard-overridden/-/postcss-discard-overridden-7.0.0.tgz", - "integrity": "sha1-sSPqUePU4dCiVM9x6v8SAZJtMZw=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-7.0.1.tgz", + "integrity": "sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==", "dev": true, "license": "MIT", "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-loader": { @@ -10980,6 +13038,7 @@ "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.4.tgz", "integrity": "sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A==", "dev": true, + "license": "MIT", "dependencies": { "cosmiconfig": "^8.3.5", "jiti": "^1.20.0", @@ -10998,10 +13057,11 @@ } }, "node_modules/postcss-loader/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -11010,45 +13070,45 @@ } }, "node_modules/postcss-merge-longhand": { - "version": "7.0.4", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-merge-longhand/-/postcss-merge-longhand-7.0.4.tgz", - "integrity": "sha1-pS0GYrSylCDztkqNWwrFEz2Nt3Y=", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.5.tgz", + "integrity": "sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==", "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", - "stylehacks": "^7.0.4" + "stylehacks": "^7.0.5" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-merge-rules": { - "version": "7.0.4", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-merge-rules/-/postcss-merge-rules-7.0.4.tgz", - "integrity": "sha1-ZIzIZNMSHm7HLCpPCN8cyAHmDOg=", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.6.tgz", + "integrity": "sha512-2jIPT4Tzs8K87tvgCpSukRQ2jjd+hH6Bb8rEEOUDmmhOeTcqDg5fEFK8uKIu+Pvc3//sm3Uu6FRqfyv7YF7+BQ==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.3", + "browserslist": "^4.25.1", "caniuse-api": "^3.0.0", - "cssnano-utils": "^5.0.0", - "postcss-selector-parser": "^6.1.2" + "cssnano-utils": "^5.0.1", + "postcss-selector-parser": "^7.1.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-minify-font-values": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-minify-font-values/-/postcss-minify-font-values-7.0.0.tgz", - "integrity": "sha1-0Wp1olSOAAd5Vms1aPyHTuXQqhc=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-7.0.1.tgz", + "integrity": "sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11058,60 +13118,60 @@ "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-minify-gradients": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-minify-gradients/-/postcss-minify-gradients-7.0.0.tgz", - "integrity": "sha1-9thEVubUkWSlXQ5FuxsYCcbPCVk=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.1.tgz", + "integrity": "sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==", "dev": true, "license": "MIT", "dependencies": { "colord": "^2.9.3", - "cssnano-utils": "^5.0.0", + "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-minify-params": { - "version": "7.0.2", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-minify-params/-/postcss-minify-params-7.0.2.tgz", - "integrity": "sha1-Jkp24l8gLYtcpSkFacDow6xZnf4=", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.4.tgz", + "integrity": "sha512-3OqqUddfH8c2e7M35W6zIwv7jssM/3miF9cbCSb1iJiWvtguQjlxZGIHK9JRmc8XAKmE2PFGtHSM7g/VcW97sw==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.3", - "cssnano-utils": "^5.0.0", + "browserslist": "^4.25.1", + "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-minify-selectors": { - "version": "7.0.4", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-minify-selectors/-/postcss-minify-selectors-7.0.4.tgz", - "integrity": "sha1-K2nJnsSKHCI/zkhAYJ2cUzQKEfU=", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.5.tgz", + "integrity": "sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==", "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", - "postcss-selector-parser": "^6.1.2" + "postcss-selector-parser": "^7.1.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-modules-extract-imports": { @@ -11119,6 +13179,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -11127,13 +13188,14 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", - "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", + "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.1.0" }, "engines": { @@ -11144,12 +13206,13 @@ } }, "node_modules/postcss-modules-scope": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", - "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", "dev": true, + "license": "ISC", "dependencies": { - "postcss-selector-parser": "^6.0.4" + "postcss-selector-parser": "^7.0.0" }, "engines": { "node": "^10 || ^12 || >= 14" @@ -11163,6 +13226,7 @@ "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, + "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" }, @@ -11174,22 +13238,22 @@ } }, "node_modules/postcss-normalize-charset": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-normalize-charset/-/postcss-normalize-charset-7.0.0.tgz", - "integrity": "sha1-kiRK5zwxv4+IhdXxb/aehXrGwAE=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-7.0.1.tgz", + "integrity": "sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==", "dev": true, "license": "MIT", "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-display-values": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.0.tgz", - "integrity": "sha1-AftQ5el++JNTY2Kb6lptOzqsE0I=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.1.tgz", + "integrity": "sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11199,13 +13263,13 @@ "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-positions": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-normalize-positions/-/postcss-normalize-positions-7.0.0.tgz", - "integrity": "sha1-TuvXydPd5AyXuAR8rTgST8hExGM=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-7.0.1.tgz", + "integrity": "sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11215,13 +13279,13 @@ "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-repeat-style": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.0.tgz", - "integrity": "sha1-DLeEZV1XFNKb072m3uL7YoqnIns=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.1.tgz", + "integrity": "sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11231,13 +13295,13 @@ "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-string": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-normalize-string/-/postcss-normalize-string-7.0.0.tgz", - "integrity": "sha1-oRnT5jqWFFcNhBPVcvufyMamTow=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-7.0.1.tgz", + "integrity": "sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11247,13 +13311,13 @@ "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-timing-functions": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.0.tgz", - "integrity": "sha1-mdDujEsjt/Q1X6+5E4WDO5sHEIs=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.1.tgz", + "integrity": "sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==", "dev": true, "license": "MIT", "dependencies": { @@ -11263,30 +13327,30 @@ "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-unicode": { - "version": "7.0.2", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.2.tgz", - "integrity": "sha1-CV+NNuoprf30lAacHeEBESmSpxM=", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.4.tgz", + "integrity": "sha512-LvIURTi1sQoZqj8mEIE8R15yvM+OhbR1avynMtI9bUzj5gGKR/gfZFd8O7VMj0QgJaIFzxDwxGl/ASMYAkqO8g==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.3", + "browserslist": "^4.25.1", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-url": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-normalize-url/-/postcss-normalize-url-7.0.0.tgz", - "integrity": "sha1-yIy3z4lS0/9jHk66kk57BgyoAvY=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-7.0.1.tgz", + "integrity": "sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11296,13 +13360,13 @@ "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-whitespace": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.0.tgz", - "integrity": "sha1-RrAl8L6nITnd7mMBVhmwwhzr2EU=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.1.tgz", + "integrity": "sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==", "dev": true, "license": "MIT", "dependencies": { @@ -11312,47 +13376,47 @@ "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-ordered-values": { - "version": "7.0.1", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-ordered-values/-/postcss-ordered-values-7.0.1.tgz", - "integrity": "sha1-i0tbgHDKd1a9SfB9Xt8nS49nguA=", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-7.0.2.tgz", + "integrity": "sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==", "dev": true, "license": "MIT", "dependencies": { - "cssnano-utils": "^5.0.0", + "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-reduce-initial": { - "version": "7.0.2", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-reduce-initial/-/postcss-reduce-initial-7.0.2.tgz", - "integrity": "sha1-PcCFNHpZQ+GFR9SwqlvU/1qTssU=", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.4.tgz", + "integrity": "sha512-rdIC9IlMBn7zJo6puim58Xd++0HdbvHeHaPgXsimMfG1ijC5A9ULvNLSE0rUKVJOvNMcwewW4Ga21ngyJjY/+Q==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.3", + "browserslist": "^4.25.1", "caniuse-api": "^3.0.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-reduce-transforms": { - "version": "7.0.0", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.0.tgz", - "integrity": "sha1-A4YIChTl+q2fjtozN1t5/nxPlnc=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.1.tgz", + "integrity": "sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==", "dev": true, "license": "MIT", "dependencies": { @@ -11362,13 +13426,13 @@ "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha1-J+y0H7Djtrp6HshP/zR/c0x5Kd4=", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "dev": true, "license": "MIT", "dependencies": { @@ -11380,286 +13444,169 @@ } }, "node_modules/postcss-svgo": { - "version": "7.0.1", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-svgo/-/postcss-svgo-7.0.1.tgz", - "integrity": "sha1-K2NXHY6VaDhN8zS6yZF7r/TSP1g=", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-7.1.0.tgz", + "integrity": "sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w==", "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", - "svgo": "^3.3.2" + "svgo": "^4.0.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >= 18" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, - "node_modules/postcss-unique-selectors": { - "version": "7.0.3", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/postcss-unique-selectors/-/postcss-unique-selectors-7.0.3.tgz", - "integrity": "sha1-SD/BEhWyPVF9XZu+WDPZkVYZyjM=", + "node_modules/postcss-svgo/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true, "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.1.2" - }, - "engines": { - "node": "^18.12.0 || ^20.9.0 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-quick": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.3.1.tgz", - "integrity": "sha512-3b36UXfYQ+IXXqex6mCca89jC8u0mYLqFAN5eTQKoXO6oCQYcIVYZEB/5AlBHI7JPYygReM2Vv6Vom/Gln7fBg==", - "dev": true, - "dependencies": { - "execa": "^4.1.0", - "find-up": "^4.1.0", - "ignore": "^5.3.0", - "mri": "^1.2.0", - "picocolors": "^1.0.0", - "picomatch": "^3.0.1", - "tslib": "^2.6.2" - }, - "bin": { - "pretty-quick": "dist/cli.js" - }, "engines": { - "node": ">=10.13" - }, - "peerDependencies": { - "prettier": "^2.0.0" + "node": ">=16" } }, - "node_modules/pretty-quick/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/postcss-svgo/node_modules/css-tree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", "dev": true, + "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "mdn-data": "2.12.2", + "source-map-js": "^1.0.1" }, "engines": { - "node": ">= 8" + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "node_modules/pretty-quick/node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "node_modules/postcss-svgo/node_modules/mdn-data": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } + "license": "CC0-1.0" }, - "node_modules/pretty-quick/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "node_modules/postcss-svgo/node_modules/svgo": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.0.tgz", + "integrity": "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==", "dev": true, + "license": "MIT", "dependencies": { - "pump": "^3.0.0" + "commander": "^11.1.0", + "css-select": "^5.1.0", + "css-tree": "^3.0.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "^1.4.1" }, - "engines": { - "node": ">=8" + "bin": { + "svgo": "bin/svgo.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-quick/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "engines": { - "node": ">=8" + "node": ">=16" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-quick/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pretty-quick/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" + "type": "opencollective", + "url": "https://opencollective.com/svgo" } }, - "node_modules/pretty-quick/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/postcss-unique-selectors": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.4.tgz", + "integrity": "sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ==", "dev": true, + "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" + "postcss-selector-parser": "^7.1.0" }, "engines": { - "node": ">=6" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "postcss": "^8.4.32" } }, - "node_modules/pretty-quick/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true, + "license": "MIT" + }, + "node_modules/prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, - "node_modules/pretty-quick/node_modules/picomatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz", - "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==", + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, "engines": { - "node": ">=10" + "node": ">=10.13.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pretty-quick/node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/pretty-quick/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/pretty-quick": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.3.1.tgz", + "integrity": "sha512-3b36UXfYQ+IXXqex6mCca89jC8u0mYLqFAN5eTQKoXO6oCQYcIVYZEB/5AlBHI7JPYygReM2Vv6Vom/Gln7fBg==", "dev": true, + "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "execa": "^4.1.0", + "find-up": "^4.1.0", + "ignore": "^5.3.0", + "mri": "^1.2.0", + "picocolors": "^1.0.0", + "picomatch": "^3.0.1", + "tslib": "^2.6.2" + }, + "bin": { + "pretty-quick": "dist/cli.js" }, "engines": { - "node": ">=8" + "node": ">=10.13" + }, + "peerDependencies": { + "prettier": "^2.0.0" } }, - "node_modules/pretty-quick/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/pretty-quick/node_modules/picomatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz", + "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-quick/node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true - }, - "node_modules/pretty-quick/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "node": ">=10" }, - "engines": { - "node": ">= 8" + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", "license": "MIT", "engines": { "node": ">=6" @@ -11668,17 +13615,20 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" }, "node_modules/promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "license": "ISC" }, "node_modules/promise-retry": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", "integrity": "sha512-StEy2osPr28o17bIW776GtwO6+Q+M9zPiZkYfosciUUMYqjhU/ffwRAH0zN2+uvGyUsn8/YICIHRzLbPacpZGw==", + "license": "MIT", "dependencies": { "err-code": "^1.0.0", "retry": "^0.10.0" @@ -11691,6 +13641,7 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -11700,21 +13651,48 @@ "node_modules/prop-types/node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" }, "node_modules/property-information": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", - "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/protobufjs": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.3.tgz", + "integrity": "sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/protoduck": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-4.0.0.tgz", "integrity": "sha512-9sxuz0YTU/68O98xuDn8NBxTVH9EuMhrBTxZdiBL0/qxRmWhB/5a8MagAebDa+98vluAZTs8kMZibCdezbRCeQ==", + "license": "CC0-1.0", "dependencies": { "genfun": "^4.0.1" } @@ -11723,6 +13701,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -11734,23 +13713,33 @@ "node_modules/pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "license": "ISC" }, "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pump": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -11760,6 +13749,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "license": "MIT", "dependencies": { "duplexify": "^3.6.0", "inherits": "^2.0.3", @@ -11770,6 +13760,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -11779,16 +13770,18 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -11801,6 +13794,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.1.tgz", "integrity": "sha512-AJBQabRCCNr9ANq8v77RJEv73DPbn55cdTb+Giq4X0AVnNVZvMHlYp7XlQiN+1npCZj1DuSmaA2hYVUUDgxFDg==", + "license": "MIT", "dependencies": { "inherits": "~2.0.3" } @@ -11823,13 +13817,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -11838,6 +13834,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -11846,6 +13843,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -11856,18 +13854,11 @@ "node": ">= 0.8" } }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -11882,6 +13873,7 @@ "version": "19.0.0", "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -11890,6 +13882,7 @@ "version": "19.0.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "license": "MIT", "dependencies": { "scheduler": "^0.25.0" }, @@ -11900,12 +13893,14 @@ "node_modules/react-fast-compare": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", - "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" }, "node_modules/react-helmet": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", + "license": "MIT", "dependencies": { "object-assign": "^4.1.1", "prop-types": "^15.7.2", @@ -11916,25 +13911,20 @@ "react": ">=16.3.0" } }, - "node_modules/react-helmet/node_modules/react-side-effect": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz", - "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==", - "peerDependencies": { - "react": "^16.3.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/react-is": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.0.0.tgz", - "integrity": "sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==" + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz", + "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==", + "license": "MIT" }, "node_modules/react-markdown": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.3.tgz", - "integrity": "sha512-Yk7Z94dbgYTOrdk41Z74GoKA7rThnsbbqBTRYuxoe08qvfQ9tJVhmAKw6BJS/ZORG7kTy/s1QvYzSuaoBA1qfw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.1.0.tgz", + "integrity": "sha512-xaijuJB0kzGiUdG7nc2MOMDUDBWPyGAjZtUrow9XxUeua8IqeP+VlIfAZ3bphpcLTnSZXz6z9jcVC/TCwbfgdw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", @@ -11954,63 +13944,45 @@ "react": ">=18" } }, - "node_modules/react-markdown/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/react-router": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.1.1.tgz", - "integrity": "sha512-39sXJkftkKWRZ2oJtHhCxmoCrBCULr/HAH4IT5DHlgu/Q0FCPV0S4Lx+abjDTx/74xoZzNYDYbOZWlJjruyuDQ==", + "version": "6.22.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz", + "integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==", + "license": "MIT", "dependencies": { - "@types/cookie": "^0.6.0", - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0", - "turbo-stream": "2.4.0" + "@remix-run/router": "1.15.3" }, "engines": { - "node": ">=20.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } + "react": ">=16.8" } }, "node_modules/react-router-dom": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.1.1.tgz", - "integrity": "sha512-vSrQHWlJ5DCfyrhgo0k6zViOe9ToK8uT5XGSmnuC2R3/g261IdIMpZVqfjD6vWSXdnf5Czs4VA/V60oVR6/jnA==", + "version": "6.22.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz", + "integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==", + "license": "MIT", "dependencies": { - "react-router": "7.1.1" + "@remix-run/router": "1.15.3", + "react-router": "6.22.3" }, "engines": { - "node": ">=20.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" + "react": ">=16.8", + "react-dom": ">=16.8" } }, - "node_modules/react-router/node_modules/@types/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" - }, - "node_modules/react-router/node_modules/cookie": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", - "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", - "engines": { - "node": ">=18" + "node_modules/react-side-effect": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz", + "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-syntax-highlighter": { @@ -12034,6 +14006,7 @@ "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -12046,29 +14019,23 @@ } }, "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" } }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -12081,6 +14048,7 @@ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, + "license": "MIT", "dependencies": { "resolve": "^1.20.0" }, @@ -12088,56 +14056,111 @@ "node": ">= 10.13.0" } }, - "node_modules/refractor": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", - "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "node_modules/refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "license": "MIT", + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", "license": "MIT", "dependencies": { - "hastscript": "^6.0.0", - "parse-entities": "^2.0.0", - "prismjs": "~1.27.0" + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/refractor/node_modules/comma-separated-tokens": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", - "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "node_modules/refractor/node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/refractor/node_modules/hast-util-parse-selector": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", - "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "node_modules/refractor/node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", "license": "MIT", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/refractor/node_modules/hastscript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", - "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "node_modules/refractor/node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^1.0.0", - "hast-util-parse-selector": "^2.0.0", - "property-information": "^5.0.0", - "space-separated-tokens": "^1.0.0" + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/refractor/node_modules/prismjs": { @@ -12149,40 +14172,19 @@ "node": ">=6" } }, - "node_modules/refractor/node_modules/property-information": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", - "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/refractor/node_modules/space-separated-tokens": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", - "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, + "license": "MIT", "dependencies": { "regenerate": "^1.4.2" }, @@ -12190,25 +14192,12 @@ "node": ">=4" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, "node_modules/regexpu-core": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", "dev": true, + "license": "MIT", "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.2.0", @@ -12225,6 +14214,7 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "license": "MIT", "dependencies": { "rc": "^1.1.6", "safe-buffer": "^5.0.1" @@ -12234,6 +14224,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", "integrity": "sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==", + "license": "MIT", "dependencies": { "rc": "^1.0.1" }, @@ -12245,13 +14236,15 @@ "version": "0.8.0", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regjsparser": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "jsesc": "~3.0.2" }, @@ -12259,10 +14252,24 @@ "regjsparser": "bin/parser" } }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/rehype-raw": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "hast-util-raw": "^9.0.0", @@ -12273,23 +14280,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-raw/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/rehype-raw/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/remark-parse": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", @@ -12302,9 +14297,10 @@ } }, "node_modules/remark-rehype": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.1.tgz", - "integrity": "sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==", + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -12317,18 +14313,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/remark-rehype/node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/remote-origin-url": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/remote-origin-url/-/remote-origin-url-0.5.3.tgz", "integrity": "sha512-crQ7Xk1m/F2IiwBx5oTqk/c0hjoumrEz+a36+ZoVupskQRE/q7pAwHKsTNeiZ31sbSTELvVlVv4h1W0Xo5szKg==", + "license": "MIT", "dependencies": { "parse-git-config": "^1.1.1" }, @@ -12341,6 +14330,7 @@ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "license": "Apache-2.0", "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -12367,19 +14357,44 @@ "node": ">= 6" } }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, "node_modules/request/node_modules/qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.6" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -12388,20 +14403,25 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12411,6 +14431,7 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -12423,6 +14444,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -12431,6 +14453,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", "integrity": "sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==", + "license": "MIT", "dependencies": { "expand-tilde": "^1.2.2", "global-modules": "^0.2.3" @@ -12443,6 +14466,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", "engines": { "node": ">=4" } @@ -12451,6 +14475,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "license": "MIT", "dependencies": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" @@ -12459,19 +14484,42 @@ "node": ">=4" } }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/retry": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", "integrity": "sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ==", + "license": "MIT", "engines": { "node": "*" } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -12483,6 +14531,7 @@ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -12497,6 +14546,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -12520,6 +14570,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -12528,23 +14579,20 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", "integrity": "sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==", + "license": "ISC", "dependencies": { "aproba": "^1.1.1" } }, "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, - "node_modules/rxjs/node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -12562,7 +14610,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safe-stable-stringify": { "version": "2.5.0", @@ -12576,16 +14625,18 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/sass": { - "version": "1.77.6", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.6.tgz", - "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", + "version": "1.89.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.2.tgz", + "integrity": "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==", "dev": true, + "license": "MIT", "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", + "chokidar": "^4.0.0", + "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { @@ -12593,148 +14644,101 @@ }, "engines": { "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" } }, "node_modules/sass-loader": { - "version": "10.5.2", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.5.2.tgz", - "integrity": "sha512-vMUoSNOUKJILHpcNCCyD23X34gve1TS7Rjd9uXHeKqhvBG39x6XbswFDtpbTElj6XdMFezoWhkh5vtKudf2cgQ==", + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.5.tgz", + "integrity": "sha512-oL+CMBXrj6BZ/zOq4os+UECPL+bWqt6OAC6DWS8Ln8GZRcMDjlJ4JC3FBDuHJdYaFWIdKNIBYmtZtK2MaMkNIw==", "dev": true, + "license": "MIT", "dependencies": { - "klona": "^2.0.4", - "loader-utils": "^2.0.0", - "neo-async": "^2.6.2", - "schema-utils": "^3.0.0", - "semver": "^7.3.2" + "neo-async": "^2.6.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", - "sass": "^1.3.0", - "webpack": "^4.36.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/sass-loader/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/sass-loader/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/sass-loader/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/sass-loader/node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/sass-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "webpack": { + "optional": true + } } }, - "node_modules/sass-loader/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "node_modules/sass/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 14.16.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/sass-loader/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "node_modules/sass/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, - "bin": { - "semver": "bin/semver.js" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/sax": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/scheduler": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", - "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==" + "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", + "license": "MIT" }, "node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", @@ -12742,7 +14746,7 @@ "ajv-keywords": "^5.1.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 10.13.0" }, "funding": { "type": "opencollective", @@ -12750,9 +14754,9 @@ } }, "node_modules/scichart": { - "version": "3.5.762", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/scichart/-/scichart-3.5.762.tgz", - "integrity": "sha1-aqsOvOSgY5DRzJ9iOfhZxzNjnsQ=", + "version": "3.5.782", + "resolved": "https://registry.npmjs.org/scichart/-/scichart-3.5.782.tgz", + "integrity": "sha512-FcAhQ8o0pUxiTMdCs/rufOXvb8N7q8Ce2NT+YvP2neul9PAae+j9Isq68b8z9899LmI593aa4/UHiVY6FSwTsw==", "license": "https://www.scichart.com/scichart-eula" }, "node_modules/scichart-angular": { @@ -12769,31 +14773,29 @@ "scichart": ">=3.3.560" } }, - "node_modules/scichart-angular/node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" - }, "node_modules/scichart-react": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/scichart-react/-/scichart-react-0.1.9.tgz", - "integrity": "sha512-U52sXcjHHQ5ztzI+tVlEKrkDxkYYHvQOHYEIhy2aJ/k8iQcy5Kr8iqq3+JN1eBioMg2UzGmIXpVitJQTZrE0Hw==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/scichart-react/-/scichart-react-0.1.13.tgz", + "integrity": "sha512-J7gc9I8W1v+iMyXPrDfFr8msHTftNCvdP26IBlGfzjyNZvThn+EpWCm/KZJzLJXNbjamg3kLyZjiz+o1MIU+Mw==", + "license": "MIT", "peerDependencies": { "react": ">=16.8.0", - "scichart": ">=3.2.516" + "scichart": ">=3.2.516-0" } }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/selfsigned": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, + "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -12806,6 +14808,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -12814,6 +14817,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", "integrity": "sha512-gL8F8L4ORwsS0+iQ34yCYv///jsOq0ZL7WP55d1HnJ32o7tyFYEFQZQA22mrLIacZdU6xecaBBZ+uEiffGNyXw==", + "license": "MIT", "dependencies": { "semver": "^5.0.3" }, @@ -12825,14 +14829,16 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", "bin": { "semver": "bin/semver" } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -12856,6 +14862,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -12863,13 +14870,24 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -12879,6 +14897,7 @@ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -12897,6 +14916,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -12906,6 +14926,7 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -12915,6 +14936,7 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, + "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -12929,52 +14951,53 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==" - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -12990,13 +15013,15 @@ "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, + "license": "MIT", "dependencies": { "kind-of": "^6.0.2" }, @@ -13005,51 +15030,114 @@ } }, "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", "dependencies": { - "shebang-regex": "^1.0.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/shortid": { - "version": "2.2.16", - "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.16.tgz", - "integrity": "sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "version": "2.2.17", + "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.17.tgz", + "integrity": "sha512-GpbM3gLF1UUXZvQw6MCyulHkWbRseNO4cyBEZresZRorwl1+SLu1ZdqgVtuwqz8mB6RpwPkm541mYSqrKyJSaA==", + "license": "MIT", "dependencies": { - "nanoid": "^2.1.0" + "nanoid": "^3.3.8" } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -13061,7 +15149,8 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" }, "node_modules/simple-swizzle": { "version": "0.2.2", @@ -13083,6 +15172,7 @@ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", "dev": true, + "license": "MIT", "dependencies": { "semver": "~7.0.0" }, @@ -13095,6 +15185,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -13104,6 +15195,7 @@ "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", "dev": true, + "license": "MIT", "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", @@ -13118,6 +15210,7 @@ "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-6.4.0.tgz", "integrity": "sha512-DoPKNc2/apQZTUnfiOONWctwq7s6dZVspxAZe2VPMNtoqNq7HgXRvlRnbIpKjf+8+piQdWncwcy+YhhTGY5USQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "^14.14.28", "@types/sax": "^1.2.1", @@ -13136,13 +15229,15 @@ "version": "14.18.63", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/slash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -13154,6 +15249,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", "integrity": "sha512-1+8bxygjTsNfvQe0/0pNBesTOlSHtOeG6b6LYbvsZCCHDKYZ40zcQo6YTnZBWrBSLWOCbrHljLdEmGMYebu7aQ==", + "license": "MIT", "engines": { "node": ">= 0.10.15", "npm": ">= 1.3.5" @@ -13164,27 +15260,23 @@ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", "dev": true, + "license": "MIT", "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, - "node_modules/snake-case/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true - }, "node_modules/socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", - "engine.io": "~6.5.2", + "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" }, @@ -13196,17 +15288,19 @@ "version": "2.5.5", "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "license": "MIT", "dependencies": { "debug": "~4.3.4", "ws": "~8.17.1" } }, "node_modules/socket.io-adapter/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -13217,19 +15311,15 @@ } } }, - "node_modules/socket.io-adapter/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/socket.io-client": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", - "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz", + "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==", + "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", - "engine.io-client": "~6.5.2", + "engine.io-client": "~6.6.1", "socket.io-parser": "~4.2.4" }, "engines": { @@ -13237,11 +15327,12 @@ } }, "node_modules/socket.io-client/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -13252,15 +15343,11 @@ } } }, - "node_modules/socket.io-client/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/socket.io-parser": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -13270,11 +15357,12 @@ } }, "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -13285,17 +15373,13 @@ } } }, - "node_modules/socket.io-parser/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/socket.io/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -13306,16 +15390,12 @@ } } }, - "node_modules/socket.io/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, + "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -13327,6 +15407,7 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -13336,6 +15417,7 @@ "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz", "integrity": "sha512-ArX4vGPULWjKDKgUnW8YzfI2uXW7kzgkJuB0GnFBA/PfT3exrrOk+7Wk2oeb894Qf20u1PWv9LEgrO0Z82qAzA==", "deprecated": "If using 2.x branch, please upgrade to at least 2.1.6 to avoid a serious bug with socket data flow and an import issue introduced in 2.1.0", + "license": "MIT", "dependencies": { "ip": "^1.1.4", "smart-buffer": "^1.0.13" @@ -13349,25 +15431,27 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz", "integrity": "sha512-ZwEDymm204mTzvdqyUqOdovVr2YRd2NYskrYrF2LXyZ9qDiMAoFESGK8CRphiO7rtbo2Y757k2Nia3x2hGtalA==", + "license": "MIT", "dependencies": { "agent-base": "^4.1.0", "socks": "^1.1.10" } }, "node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -13377,16 +15461,25 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, + "node_modules/source-map-support/node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, "node_modules/source-map-support/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -13395,6 +15488,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -13404,6 +15498,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -13412,27 +15507,31 @@ "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==" + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "node_modules/spdx-license-ids": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", - "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==" + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "license": "CC0-1.0" }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -13448,44 +15547,23 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "node_modules/spdy-transport/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" } }, - "node_modules/spdy-transport/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/spdy-transport/node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -13495,39 +15573,28 @@ "node": ">= 6" } }, - "node_modules/spdy/node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "node_modules/spdy-transport/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "safe-buffer": "~5.2.0" } }, - "node_modules/spdy/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/sshpk": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "license": "MIT", "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -13552,6 +15619,7 @@ "version": "4.1.6", "resolved": "https://registry.npmjs.org/ssri/-/ssri-4.1.6.tgz", "integrity": "sha512-WUbCdgSAMQjTFZRWvSPpauryvREEA+Krn19rx67UlJEJx/M192ZHxMmJXjZ4tkdFm+Sb0SXGlENeQVlA5wY7kA==", + "license": "CC0-1.0", "dependencies": { "safe-buffer": "^5.1.0" } @@ -13569,6 +15637,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -13577,6 +15646,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "stream-shift": "^1.0.0" @@ -13585,25 +15655,20 @@ "node_modules/stream-shift": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", - "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==" + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "license": "MIT" }, "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "license": "MIT" }, "node_modules/string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "license": "MIT", "dependencies": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" @@ -13612,10 +15677,20 @@ "node": ">=4" } }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/string-width/node_modules/strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "license": "MIT", "dependencies": { "ansi-regex": "^3.0.0" }, @@ -13627,6 +15702,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" @@ -13636,19 +15712,11 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/stringify-entities/node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "license": "MIT", "dependencies": { "ansi-regex": "^4.1.0" }, @@ -13656,18 +15724,11 @@ "node": ">=6" } }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "engines": { - "node": ">=6" - } - }, "node_modules/strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -13677,6 +15738,7 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -13685,6 +15747,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -13694,6 +15757,7 @@ "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz", "integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12.13.0" }, @@ -13705,40 +15769,52 @@ "webpack": "^5.0.0" } }, + "node_modules/style-to-js": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.17.tgz", + "integrity": "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.9" + } + }, "node_modules/style-to-object": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz", - "integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.9.tgz", + "integrity": "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==", + "license": "MIT", "dependencies": { "inline-style-parser": "0.2.4" } }, "node_modules/stylehacks": { - "version": "7.0.4", - "resolved": "https://www.myget.org/F/abtsoftware-bleeding-edge/npm/stylehacks/-/stylehacks-7.0.4.tgz", - "integrity": "sha1-nCH3N09LzMAIJBK4WbPInXfTJ3w=", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.6.tgz", + "integrity": "sha512-iitguKivmsueOmTO0wmxURXBP8uqOO+zikLGZ7Mm9e/94R4w5T999Js2taS/KBOnQ/wdC3jN3vNSrkGDrlnqQg==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.3", - "postcss-selector-parser": "^6.1.2" + "browserslist": "^4.25.1", + "postcss-selector-parser": "^7.1.0" }, "engines": { "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/stylis": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -13750,6 +15826,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -13761,13 +15838,15 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/svgo": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", "dev": true, + "license": "MIT", "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", @@ -13793,23 +15872,26 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } }, "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/tar-fs": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", - "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", + "version": "1.16.5", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.5.tgz", + "integrity": "sha512-1ergVCCysmwHQNrOS+Pjm4DQ4nrGp43+Xnu4MRGjCnQu/m3hEgLNS78d5z+B8OJ1hN5EejJdCSFZE1oM6AQXAQ==", + "license": "MIT", "dependencies": { "chownr": "^1.0.1", "mkdirp": "^0.5.1", @@ -13821,6 +15903,7 @@ "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "license": "MIT", "dependencies": { "bl": "^1.0.0", "buffer-alloc": "^1.2.0", @@ -13834,10 +15917,47 @@ "node": ">= 0.8.0" } }, + "node_modules/tar-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/tar-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/tar-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/term-size": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", "integrity": "sha512-7dPUZQGy/+m3/wjVz3ZW5dobSoD/02NxJpoXUX0WIyjfVS3l0c+b/+9phIDFA7FHzkYtwtMFgeGZ/Y8jVTeqQQ==", + "license": "MIT", "dependencies": { "execa": "^0.7.0" }, @@ -13845,14 +15965,120 @@ "node": ">=4" } }, + "node_modules/term-size/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "license": "MIT", + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/term-size/node_modules/execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/term-size/node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/term-size/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/term-size/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "license": "ISC", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/term-size/node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "license": "MIT", + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/term-size/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/term-size/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/term-size/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/term-size/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "license": "ISC" + }, "node_modules/terser": { - "version": "5.31.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz", - "integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==", + "version": "5.43.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", + "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -13864,16 +16090,17 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.10", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", - "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.20", + "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.26.0" + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" }, "engines": { "node": ">= 10.13.0" @@ -13897,63 +16124,35 @@ } } }, - "node_modules/terser-webpack-plugin/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/text-hex": { @@ -13966,6 +16165,7 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.6.0.tgz", "integrity": "sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==", + "license": "MIT", "engines": { "node": ">=0.8" }, @@ -13976,27 +16176,42 @@ "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "license": "MIT" }, "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.4.2.tgz", + "integrity": "sha512-45Llu+EwHKtAZYTPPVn3XZHBgakWMN3rokhEv5hu596XP+cNgplMg+Gj+1nmAvj+L0K7+N49zBKx5rah5u0QIQ==", + "license": "MIT", "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "readable-stream": "~1.0.17", + "xtend": "~2.1.1" + } + }, + "node_modules/through2/node_modules/xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ==", + "dependencies": { + "object-keys": "~0.4.0" + }, + "engines": { + "node": ">=0.4" } }, "node_modules/thunky": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -14005,6 +16220,7 @@ "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -14013,15 +16229,31 @@ } }, "node_modules/to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz", + "integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==", + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/to-buffer/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -14033,6 +16265,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", "engines": { "node": ">=0.6" } @@ -14042,6 +16275,7 @@ "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -14051,6 +16285,7 @@ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "dev": true, + "license": "ISC", "bin": { "nodetouch": "bin/nodetouch.js" } @@ -14059,6 +16294,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "license": "BSD-3-Clause", "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" @@ -14071,6 +16307,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -14089,16 +16326,18 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/ts-loader": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", - "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.2.tgz", + "integrity": "sha512-Qo4piXvOTWcMGIgRiuFa6nHNm+54HbYaZCKqc9eeZCLRy3XqafQgwX2F7mofrbJG3g7EEb+lkiR+z2Lic2s3Zw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^5.0.0", @@ -14115,10 +16354,11 @@ } }, "node_modules/ts-loader/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -14126,11 +16366,22 @@ "node": ">=10" } }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -14173,12 +16424,14 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/tslint": { "version": "6.1.3", @@ -14186,6 +16439,7 @@ "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", "dev": true, + "license": "Apache-2.0", "dependencies": { "@babel/code-frame": "^7.0.0", "builtin-modules": "^1.1.1", @@ -14216,6 +16470,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -14228,6 +16483,7 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } @@ -14237,6 +16493,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -14251,6 +16508,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -14259,13 +16517,25 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/tslint/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, "node_modules/tslint/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -14275,6 +16545,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -14288,6 +16559,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } @@ -14297,6 +16569,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -14304,10 +16577,18 @@ "node": ">=4" } }, + "node_modules/tslint/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, "node_modules/tss-react": { - "version": "4.9.14", - "resolved": "https://registry.npmjs.org/tss-react/-/tss-react-4.9.14.tgz", - "integrity": "sha512-nAj4RCQk3ADzrmtxmTcmN1B9EKxPMIxuCfJ3ll964CksndJ2/ZImF6rAMo2Kud5yE3ENXHpPIBHCyuMtgptMvw==", + "version": "4.9.19", + "resolved": "https://registry.npmjs.org/tss-react/-/tss-react-4.9.19.tgz", + "integrity": "sha512-mmeec1wmLJKUpbaEfsQIOgk0ZtaVBt/oMbiWUFzCnxNm7vb6sDEA3ez/5/ll1eg74nrOcy9BjA+qEuF7nUV0bA==", + "license": "MIT", "dependencies": { "@emotion/cache": "*", "@emotion/serialize": "*", @@ -14316,9 +16597,9 @@ "peerDependencies": { "@emotion/react": "^11.4.1", "@emotion/server": "^11.4.0", - "@mui/material": "^5.0.0 || ^6.0.0", + "@mui/material": "^5.0.0 || ^6.0.0 || ^7.0.0", "@types/react": "^16.8.0 || ^17.0.2 || ^18.0.0 || ^19.0.0", - "react": "^16.8.0 || ^17.0.2 || ^18.0.0 || ^19.0.0" + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/server": { @@ -14334,6 +16615,7 @@ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^1.8.1" }, @@ -14341,10 +16623,18 @@ "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" } }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -14352,20 +16642,17 @@ "node": "*" } }, - "node_modules/turbo-stream": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", - "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==" - }, "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "license": "Unlicense" }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -14374,16 +16661,32 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -14396,18 +16699,33 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/undici": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.5.tgz", + "integrity": "sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==", + "license": "MIT", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -14417,6 +16735,7 @@ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, + "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -14430,6 +16749,7 @@ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -14439,6 +16759,7 @@ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -14447,6 +16768,7 @@ "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", @@ -14461,26 +16783,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unified/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/unified/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/unique-filename": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "license": "ISC", "dependencies": { "unique-slug": "^2.0.0" } @@ -14489,6 +16796,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" } @@ -14497,6 +16805,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", "integrity": "sha512-ODgiYu03y5g76A1I9Gt0/chLCzQjvzDy7DsZGsLOE/1MrF6wriEskSncj1+/C58Xk/kPZDppSctDybCwOSaGAg==", + "license": "MIT", "dependencies": { "crypto-random-string": "^1.0.0" }, @@ -14508,6 +16817,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -14516,15 +16826,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-is/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/unist-util-position": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -14533,15 +16839,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-position/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/unist-util-stringify-position": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -14550,15 +16852,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-stringify-position/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/unist-util-visit": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", @@ -14573,6 +16871,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" @@ -14582,20 +16881,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/unist-util-visit-parents/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/unist-util-visit/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "license": "MIT", "engines": { "node": ">= 4.0.0" } @@ -14604,6 +16894,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -14612,14 +16903,15 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", "integrity": "sha512-N0XH6lqDtFH84JxptQoZYmloF4nzrQqqrAymNj+/gW60AO2AZgOcf4O/nUXJcYfyQkqvMo9lSupBZmmgvuVXlw==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -14635,9 +16927,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -14650,6 +16943,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "license": "BSD-2-Clause", "dependencies": { "boxen": "^1.2.1", "chalk": "^2.0.1", @@ -14670,6 +16964,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -14681,6 +16976,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -14694,6 +16990,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -14701,12 +16998,23 @@ "node_modules/update-notifier/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/update-notifier/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, "node_modules/update-notifier/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { "node": ">=4" } @@ -14715,6 +17023,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -14726,6 +17035,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -14735,6 +17045,7 @@ "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", "dev": true, + "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", "mime-types": "^2.1.27", @@ -14762,6 +17073,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -14778,6 +17090,7 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } @@ -14786,25 +17099,15 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/url-loader/node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } + "license": "MIT" }, "node_modules/url-loader/node_modules/loader-utils": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -14819,6 +17122,7 @@ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -14836,6 +17140,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", "integrity": "sha512-BVA4lR5PIviy2PMseNd2jbFQ+jwSwQGdJejf5ctd1rEXt0Ypd7yanUK9+lYechVlN5VaTJGsu2U/3MDDu6KgBA==", + "license": "MIT", "dependencies": { "prepend-http": "^1.0.1" }, @@ -14846,12 +17151,14 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -14861,6 +17168,7 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "license": "MIT", "bin": { "uuid": "bin/uuid" } @@ -14869,12 +17177,14 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -14884,6 +17194,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", + "license": "ISC", "dependencies": { "builtins": "^1.0.3" } @@ -14892,6 +17203,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -14903,6 +17215,7 @@ "engines": [ "node >=0.6.0" ], + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -14912,12 +17225,14 @@ "node_modules/verror/node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "license": "MIT" }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" @@ -14931,6 +17246,7 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" @@ -14940,15 +17256,11 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/vfile-location/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/vfile-message": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" @@ -14958,21 +17270,12 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/vfile-message/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, - "node_modules/vfile/node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/watchpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", - "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", + "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", "dev": true, + "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -14986,6 +17289,7 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, + "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -14994,27 +17298,30 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, "node_modules/webpack": { - "version": "5.92.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", - "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.5", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", + "version": "5.100.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.100.2.tgz", + "integrity": "sha512-QaNKAvGCDRh3wW1dsDjeMdDXwZm2vqq3zn6Pvq4rHOEOGSaUMgOOjG2Y9ZbIGzpfkJk9ZYTHpDqgDfeBDcnLaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", + "enhanced-resolve": "^5.17.2", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -15024,11 +17331,11 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", + "schema-utils": "^4.3.2", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", + "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -15051,6 +17358,7 @@ "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", "dev": true, + "license": "MIT", "dependencies": { "@discoveryjs/json-ext": "0.5.7", "acorn": "^8.0.4", @@ -15077,27 +17385,17 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } }, - "node_modules/webpack-bundle-analyzer/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/webpack-bundle-analyzer/node_modules/ws": { "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.3.0" }, @@ -15119,6 +17417,7 @@ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", "dev": true, + "license": "MIT", "dependencies": { "@discoveryjs/json-ext": "^0.5.0", "@webpack-cli/configtest": "^2.1.1", @@ -15164,74 +17463,17 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" } }, - "node_modules/webpack-cli/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/webpack-cli/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/webpack-cli/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/webpack-cli/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/webpack-cli/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/webpack-dev-middleware": { "version": "5.3.4", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", "dev": true, + "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", @@ -15255,6 +17497,7 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", "dev": true, + "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -15314,6 +17557,7 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10" } @@ -15323,6 +17567,7 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, + "license": "MIT", "dependencies": { "is-docker": "^2.0.0" }, @@ -15335,6 +17580,7 @@ "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "dev": true, + "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", @@ -15352,6 +17598,7 @@ "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", "dev": true, + "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", @@ -15366,73 +17613,26 @@ "resolved": "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz", "integrity": "sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/webpack/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -15446,7 +17646,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } @@ -15454,12 +17654,14 @@ "node_modules/websocket-ts": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/websocket-ts/-/websocket-ts-1.1.1.tgz", - "integrity": "sha512-rm+S60J74Ckw5iizzgID12ju+OfaHAa6dhXhULIOrXkl0e05RzxfY42/vMStpz5jWL3iz9mkyjPcFUY1IgI0fw==" + "integrity": "sha512-rm+S60J74Ckw5iizzgID12ju+OfaHAa6dhXhULIOrXkl0e05RzxfY42/vMStpz5jWL3iz9mkyjPcFUY1IgI0fw==", + "license": "MIT" }, "node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -15467,10 +17669,32 @@ "which": "bin/which" } }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/widest-line": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "license": "MIT", "dependencies": { "string-width": "^2.1.1" }, @@ -15482,7 +17706,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/winston": { "version": "3.17.0", @@ -15534,16 +17759,13 @@ "node": ">= 6" } }, - "node_modules/winston/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "node_modules/winston-transport/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "safe-buffer": "~5.2.0" } }, "node_modules/winston/node_modules/readable-stream": { @@ -15560,15 +17782,87 @@ "node": ">= 6" } }, + "node_modules/winston/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "license": "ISC", "dependencies": { "graceful-fs": "^4.1.11", "imurmurhash": "^0.1.4", @@ -15579,6 +17873,7 @@ "version": "8.17.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -15599,14 +17894,15 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", "integrity": "sha512-1Dly4xqlulvPD3fZUQJLY+FUIeqN3N2MM3uqe4rCJftAvOjFa3jFGfctOgluGx4ahPbUCsZkmJILiP0Vi4T6lQ==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/xmlhttprequest-ssl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", - "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", "engines": { "node": ">=0.4.0" } @@ -15615,6 +17911,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", "engines": { "node": ">=0.4" } @@ -15622,41 +17919,120 @@ "node_modules/y18n": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", - "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==" + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "license": "ISC" }, "node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", "engines": { "node": ">= 6" } }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/zone.js": { - "version": "0.14.10", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.10.tgz", - "integrity": "sha512-YGAhaO7J5ywOXW6InXNlLmfU194F8lVgu7bRntUF3TiG8Y3nBK0x1UJJuHUP/e8IyihkjCYqhCScpSwnlaSRkQ==", - "license": "MIT", - "peer": true - }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" diff --git a/Examples/package.json b/Examples/package.json index 136697f81..8952b4f07 100644 --- a/Examples/package.json +++ b/Examples/package.json @@ -4,14 +4,16 @@ "description": "", "private": true, "engines": { - "npm": ">=10.9.2", - "node": ">=22.13.0" + "npm": ">=10.9.1", + "node": ">=18.18.0" }, "scripts": { "compareExamples": "ts-node -P tsconfig.node.json scripts/compareExampleInfos.ts", "generateMetadata": "ts-node -P tsconfig.node.json scripts/generateMetadataFromOld.ts", "updateExampleInfos": "ts-node -P tsconfig.node.json scripts/updateExampleInfos.ts", "dev": "webpack-dev-server --config webpack.client.no_server.config.ts", + "dev:clean": "powershell -ExecutionPolicy Bypass -File start-dev.ps1", + "install:firebase": "powershell -ExecutionPolicy Bypass -File install-firebase.ps1", "build": "rimraf ./build && npm run buildVanillaDemo && npm run buildImages && npm run buildServer && npm run buildClient", "start": "node ./build/server.js", "buildServer": "webpack --config webpack.server.config.js", @@ -37,10 +39,10 @@ "author": "", "license": "ISC", "dependencies": { - "@angular/animations": "^18.2.8", - "@angular/common": "^18.2.8", - "@angular/core": "^18.2.8", - "@angular/forms": "^18.2.8", + "@angular/animations": "^16.2.12", + "@angular/common": "^16.2.12", + "@angular/core": "^16.2.12", + "@angular/forms": "^16.2.12", "@angular/material": "^18.2.8", "@emotion/react": "^11.13.3", "@emotion/server": "^11.11.0", @@ -57,6 +59,7 @@ "cors": "^2.8.5", "country-flag-icons": "^1.5.7", "express": "^4.17.1", + "firebase": "^10.7.1", "follow-redirects": "^1.15.9", "morgan": "^1.10.0", "node-html-parser": "^6.1.13", @@ -64,8 +67,8 @@ "react-dom": "19.0.0", "react-helmet": "^6.1.0", "react-markdown": "^9.0.3", - "react-router": "^7.1.1", - "react-router-dom": "^7.1.1", + "react-router": "^6.22.3", + "react-router-dom": "^6.22.3", "react-syntax-highlighter": "^15.6.1", "react-transition-group": "^4.4.5", "rehype-raw": "^7.0.0", @@ -87,6 +90,7 @@ "@types/express": "^4.17.7", "@types/follow-redirects": "^1.14.4", "@types/node": "^22.7.6", + "@types/nodemon": "^1.19.6", "@types/prismjs": "^1.16.1", "@types/react-dom": "19.0.2", "@types/react-helmet": "^6.1.6", @@ -109,7 +113,7 @@ "pretty-quick": "^3.1.1", "rimraf": "^3.0.2", "sass": "^1.49.9", - "sass-loader": "^10.4.1", + "sass-loader": "^16.0.5", "sitemap": "^6.3.2", "style-loader": "^3.3.1", "ts-loader": "^9.4.2", @@ -126,10 +130,11 @@ }, "browserslist": [ "defaults", - "not ie < 11", + "not IE 11", + "not IE_Mob 11", "last 2 versions", "> 1%", - "iOS 7", + "iOS >= 13", "last 3 iOS versions" ] } diff --git a/Examples/setup_firebase.py b/Examples/setup_firebase.py new file mode 100644 index 000000000..e805ed7ae --- /dev/null +++ b/Examples/setup_firebase.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +""" +Frontend Firebase Setup Script for Vital Signs Monitor +This script helps you set up Firebase logging for the frontend. +""" + +import os +import json +from pathlib import Path + +def read_env_file(): + """Read the .env file and return a dictionary of variables.""" + env_vars = {} + env_file = Path('.env') + + if not env_file.exists(): + print("โŒ .env file not found!") + return None + + with open(env_file, 'r') as f: + for line in f: + line = line.strip() + if line and not line.startswith('#') and '=' in line: + key, value = line.split('=', 1) + env_vars[key] = value + + return env_vars + +def validate_firebase_credentials(env_vars): + """Validate that Firebase credentials are properly set.""" + required_vars = [ + 'REACT_APP_FIREBASE_API_KEY', + 'REACT_APP_FIREBASE_AUTH_DOMAIN', + 'REACT_APP_FIREBASE_DATABASE_URL', + 'REACT_APP_FIREBASE_PROJECT_ID', + 'REACT_APP_FIREBASE_STORAGE_BUCKET', + 'REACT_APP_FIREBASE_MESSAGING_SENDER_ID', + 'REACT_APP_FIREBASE_APP_ID' + ] + + missing_vars = [] + for var in required_vars: + if not env_vars.get(var) or env_vars[var] == f'your-{var.lower().replace("react_app_firebase_", "").replace("_", "-")}-here': + missing_vars.append(var) + + if missing_vars: + print(f"โŒ Missing or invalid Firebase credentials: {', '.join(missing_vars)}") + return False + + print("โœ… Firebase credentials look good!") + return True + +def print_setup_instructions(): + """Print setup instructions for Firebase.""" + print("\n" + "="*60) + print("๐Ÿ”ฅ FRONTEND FIREBASE SETUP INSTRUCTIONS") + print("="*60) + print("\n1. Go to Firebase Console: https://console.firebase.google.com/") + print("2. Create a new project or select existing one") + print("3. Enable Realtime Database:") + print(" - Go to Realtime Database") + print(" - Click 'Create Database'") + print(" - Choose 'Start in test mode' (for development)") + print("4. Get your credentials:") + print(" - Go to Project Settings > General") + print(" - Copy 'Web API Key'") + print(" - Copy 'Project ID'") + print(" - Copy 'Storage Bucket'") + print(" - Copy 'Messaging Sender ID'") + print(" - Copy 'App ID'") + print(" - Go to Realtime Database") + print(" - Copy the database URL") + print("5. Update the .env file with your credentials") + print("6. Run this script again to validate") + print("\n" + "="*60) + +def main(): + print("๐Ÿš€ Frontend Firebase Setup Script") + print("="*40) + + # Check if .env file exists + env_vars = read_env_file() + if not env_vars: + print_setup_instructions() + return + + # Validate credentials + if not validate_firebase_credentials(env_vars): + print_setup_instructions() + return + + print("\n๐ŸŽ‰ Setup complete! Your frontend is ready to log to Firebase.") + print("\n๐Ÿ“‹ What will be logged:") + print("- Heart Rate (BPM)") + print("- Respiratory Rate (breaths/min)") + print("- GSR Value and Trend") + print("- ECG Signal Quality") + print("- HRV Metrics (SDNN, RMSSD, pNN50, LF/HF Power)") + print("- Respiratory Metrics (inhale/exhale percentages)") + print("- Connection Status") + print("\n๐Ÿ“Š Data Structure:") + print("/processed_sensor_logs/") + print(" โ””โ”€โ”€ [auto-generated-id]/") + print(" โ”œโ”€โ”€ timestamp: 1234567890") + print(" โ”œโ”€โ”€ heartRate: 75") + print(" โ”œโ”€โ”€ respiratoryRate: 16") + print(" โ”œโ”€โ”€ gsrValue: 0.65") + print(" โ”œโ”€โ”€ gsrTrend: 'increasing'") + print(" โ”œโ”€โ”€ ecgQuality: 'good'") + print(" โ”œโ”€โ”€ hrvMetrics: {...}") + print(" โ”œโ”€โ”€ respiratoryMetrics: {...}") + print(" โ””โ”€โ”€ connectionStatus: {...}") + print("\nโฐ Logging Frequency: Every 30 seconds when ESP32 is connected") + print("\n๐Ÿ” View Data:") + print("1. Go to Firebase Console > Realtime Database") + print("2. Look for 'processed_sensor_logs' folder") + print("3. Data updates every 30 seconds when connected") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/Examples/src/assets/_base.scss b/Examples/src/assets/_base.scss deleted file mode 100644 index d22ed6da0..000000000 --- a/Examples/src/assets/_base.scss +++ /dev/null @@ -1,81 +0,0 @@ -@import "./mixins.scss"; -$color-primary-grey: #bac0c6; -$color-primary-light-grey: #f9fafa; -$color-primary-dark-grey: #98a4af; -$color-primary-white: #ffffff; -$color-primary-white-alpha: #ffffff33; - -$color-link-text: #39b5db; -$color-link-text-hover: #44c8f1; -$color-font-dark: #323640; - -$color-font-green: #117d31; - -$color-dark: #050a30; -$color-dark-grey: #030723; -$color-grey: #4a545b; -$color-light-grey: #97a0a8; - -$color-lightest-green: #f7f8f8; -$color-dark-green: #67ac5b; -$color-main-green: #5cb85c; - -$color-dark-blue: #2c353d; -$color-medium-blue: rgb(42, 99, 151); -$color-red: #c52b2e; - -$font-color: #3b5164; -$menu-list-item-font-color: #1e252b; - -$gradient-header: linear-gradient(110deg, #12003e 20%, #1e0056 40%, #40008f 60%, #9c3874 100%); -$gradient-btn-dark: linear-gradient(90deg, rgb(42, 99, 151), rgb(113, 55, 149), rgb(160, 36, 142)); -$gradient-blue: linear-gradient(90deg, #29aade, #44b6ce, #64c5bb); - -//Media -$bp-xl: 120em; //1920 -$bp-lg: 91.25em; //1460 -$bp-md: 60em; //960/16px=60em -$bp-sm: 37.5em; //600px/16px=37.5em -$bp-xs: 28.125em; // 450 -$bp-xxs: 0; - -// spacing -$app-bar-height: 90px; -$default-spacing: 8px; -$default-border-radius: 10px; -// -%Container { - padding: 0 20px; - @include md { - padding: 0 10px; - } -} -html { - box-sizing: border-box; - - height: 100%; - font-family: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, - sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; - h1 { - line-height: 1.167; - } - h4 { - font-size: 2.125rem; - font-weight: 400; - line-height: 1.235; - } - - h6 { - font-size: 1.25rem; - font-weight: 500; - line-height: 1.6; - } -} -.container { - width: 100%; - @extend %Container; -} - -%gutter-bottom { - margin-bottom: 0.35em; -} diff --git a/Examples/src/assets/icons/back.svg b/Examples/src/assets/icons/back.svg deleted file mode 100644 index 437b19a89..000000000 --- a/Examples/src/assets/icons/back.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/Examples/src/assets/icons/browser-fill.svg b/Examples/src/assets/icons/browser-fill.svg deleted file mode 100644 index 49faf25a6..000000000 --- a/Examples/src/assets/icons/browser-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/Examples/src/assets/icons/close.svg b/Examples/src/assets/icons/close.svg deleted file mode 100644 index cb0bf60a5..000000000 --- a/Examples/src/assets/icons/close.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/Examples/src/assets/icons/codesandbox.svg b/Examples/src/assets/icons/codesandbox.svg deleted file mode 100644 index 2b1df6825..000000000 --- a/Examples/src/assets/icons/codesandbox.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/Examples/src/assets/icons/embedded.svg b/Examples/src/assets/icons/embedded.svg deleted file mode 100644 index 03c928618..000000000 --- a/Examples/src/assets/icons/embedded.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/Examples/src/assets/icons/example.svg b/Examples/src/assets/icons/example.svg deleted file mode 100644 index 80941e1ce..000000000 --- a/Examples/src/assets/icons/example.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - diff --git a/Examples/src/assets/icons/fullscreen.svg b/Examples/src/assets/icons/fullscreen.svg deleted file mode 100644 index c346ece7a..000000000 --- a/Examples/src/assets/icons/fullscreen.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/Examples/src/assets/icons/stackblitz.svg b/Examples/src/assets/icons/stackblitz.svg deleted file mode 100644 index 8b4347b1e..000000000 --- a/Examples/src/assets/icons/stackblitz.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/Examples/src/assets/images/AngularLogo.svg b/Examples/src/assets/images/AngularLogo.svg deleted file mode 100644 index f6613805c..000000000 --- a/Examples/src/assets/images/AngularLogo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/Examples/src/assets/images/Chart.png b/Examples/src/assets/images/Chart.png deleted file mode 100644 index b0ab64fecf9409a24733049666fba67cbaac8757..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11097 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 diff --git a/Examples/src/assets/images/JavaScriptLogo.svg b/Examples/src/assets/images/JavaScriptLogo.svg deleted file mode 100644 index 4ecd8cfe3..000000000 --- a/Examples/src/assets/images/JavaScriptLogo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/Examples/src/assets/images/ReactLogo.svg b/Examples/src/assets/images/ReactLogo.svg deleted file mode 100644 index 6fc6b0295..000000000 --- a/Examples/src/assets/images/ReactLogo.svg +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/Examples/src/assets/images/VueLogo.svg b/Examples/src/assets/images/VueLogo.svg deleted file mode 100644 index 4ecd8cfe3..000000000 --- a/Examples/src/assets/images/VueLogo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/Examples/src/assets/main.scss b/Examples/src/assets/main.scss deleted file mode 100644 index 146f2cfa8..000000000 --- a/Examples/src/assets/main.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import "base"; -@import "mixins"; diff --git a/Examples/src/assets/mixins.scss b/Examples/src/assets/mixins.scss deleted file mode 100644 index ac85976fe..000000000 --- a/Examples/src/assets/mixins.scss +++ /dev/null @@ -1,34 +0,0 @@ -@mixin xl { - @media (min-width: $bp-xl) { - @content; - } -} - -@mixin lg { - @media (max-width: $bp-xl) { - @content; - } -} - -@mixin md { - @media (max-width: $bp-lg) { - @content; - } -} - -@mixin sm { - @media (max-width: $bp-md) { - @content; - } -} - -@mixin xs { - @media (max-width: $bp-sm) { - @content; - } -} -@mixin xxs { - @media (max-width: $bp-xs) { - @content; - } -} diff --git a/Examples/src/components/App.module.scss b/Examples/src/components/App.module.scss deleted file mode 100644 index a998f6543..000000000 --- a/Examples/src/components/App.module.scss +++ /dev/null @@ -1,84 +0,0 @@ -@import "../assets/main.scss"; - -$drawerWidthDesktop: min(350px, 25vw); -$drawerWidthTablet: 375px; -$drawerWidthMobile: 100%; - -.App { - display: flex; - - @include md { - display: block; - } -} - -.DrawerMobile { - background-color: var(--bg); - flex-shrink: 0; - display: none; - padding: 0; - // fix for a bug of Drawer with anchor="right" - inset: unset !important; - - @include md { - display: block; - width: $drawerWidthTablet; - } - - @include xxs { - width: $drawerWidthMobile; - } -} -.DrawerDesktop { - position: sticky; - top: 110px; - order: -1; - background-color: var(--bg); - width: $drawerWidthDesktop; - max-height: calc(100vh - $app-bar-height - 40px); // subtract navHeight and 2 * padding - margin-right: 15px; - flex-shrink: 0; - overflow-x: hidden; - border: 1px solid var(--border-color); - border-radius: 15px; - overflow-x: hidden; - overflow-y: scroll; - @include sm { - display: none; - } -} - -.DrawerPaper { - width: inherit; - overflow-x: hidden; -} - -.MainAppContent { - flex-grow: 1; - background-color: var(--bg-darker); - max-width: 100vw; -} - -.container { - width: 100%; - margin: 0 auto; -} - -.MainAppWrapper { - @extend %Container; - display: flex; - margin: 0 auto; - padding: 20px; - - justify-content: center; - width: 100%; - - .GalleryAppWrapper { - flex: 1; - } -} -:global(.scichart__legend) { - input { - margin-top: initial; - } -} diff --git a/Examples/src/components/App.tsx b/Examples/src/components/App.tsx deleted file mode 100644 index 675ca6aa9..000000000 --- a/Examples/src/components/App.tsx +++ /dev/null @@ -1,214 +0,0 @@ -import * as React from "react"; -import { Theme } from "@mui/material/styles"; -import Drawer from "@mui/material/Drawer"; -import useMediaQuery from "@mui/material/useMediaQuery"; -import AppRouter from "./AppRouter/AppRouter"; -import { - ALL_MENU_ITEMS, - getParentMenuIds, - MENU_ITEMS_2D, - MENU_ITEMS_3D, - MENU_ITEMS_FEATURED_APPS, -} from "./AppRouter/examples"; -// import AppBarTop from "./AppTopBar/AppBarTop"; -import DrawerContent from "./DrawerContent/DrawerContent"; -import AppFooter from "./AppFooter/AppFooter"; -import { SciChartSurface } from "scichart/Charting/Visuals/SciChartSurface"; -import { SciChartDefaults } from "scichart/Charting/Visuals/SciChartDefaults"; -import classes from "./App.module.scss"; -import "./index.scss"; -import { ETheme, GalleryItem } from "../helpers/types/types"; -import { generateExamplesGallery, getSeeAlsoGalleryItems } from "../helpers/SciChartExamples"; -import { FrameworkContext } from "../helpers/shared/Helpers/FrameworkContext"; -import { useExampleRouteParams } from "../helpers/shared/Helpers/frameworkParametrization"; -import AppDetailsRouter from "./AppDetailsRouters/AppDetailsRouter"; -import { Link, useNavigate } from "react-router"; -import { appTheme } from "./Examples/theme"; -import { SciChart3DSurface, SciChartSurfaceBase } from "scichart"; -import { ContentSectionRouter } from "./Navigation/AnchorTagRouter"; -import GalleryItems from "./GalleryItems"; -import SciChartNavbar from "./SciChartNavbar/SciChartNavbar"; -import { baseAppPath } from "../constants"; - -SciChartSurfaceBase.DEFAULT_THEME = appTheme.SciChartJsTheme; -SciChartDefaults.useSharedCache = true; - -const NotFound = () => ( -

-); - -SciChartSurface.configure({ - wasmUrl: `${baseAppPath}/scichart2d.wasm`, - dataUrl: `${baseAppPath}/scichart2d.data`, -}); - -SciChart3DSurface.configure({ - wasmUrl: `${baseAppPath}/scichart3d.wasm`, - dataUrl: `${baseAppPath}/scichart3d.data`, -}); - -export default function App() { - const { isIFrame, isHomePage, currentExample, framework, is404 } = useExampleRouteParams(); - const navigate = useNavigate(); // Hook to programmatically navigate - - const [theme, setTheme] = React.useState(); - - const selectedFramework = framework; - - // TODO md was changed by migration script.requires verification - const isMedium = useMediaQuery((theme: Theme) => theme.breakpoints.down("md")); - - let initialOpenedMenuItems = { - MENU_ITEMS_FEATURED_APPS_ID: false, - MENU_ITEMS_3D_ID: false, - MENU_ITEMS_2D_ID: false, - }; - - MENU_ITEMS_FEATURED_APPS.forEach((item) => { - initialOpenedMenuItems = { ...initialOpenedMenuItems, [item.id]: true }; - }); - MENU_ITEMS_3D.forEach((item) => { - initialOpenedMenuItems = { ...initialOpenedMenuItems, [item.id]: true }; - }); - MENU_ITEMS_2D.forEach((item) => { - initialOpenedMenuItems = { ...initialOpenedMenuItems, [item.id]: true }; - }); - - const [openedMenuItems, setOpenedMenuItems] = React.useState>(initialOpenedMenuItems); - - const [isDrawerOpened, setIsDrawerOpened] = React.useState(false); - const [mostVisibleCategory, setMostVisibleCategory] = React.useState(null); - - const currentExampleId = currentExample?.id; - // SeeAlso is now optional on exampleInfo. Return this if provided else auto-generate from menu - const seeAlso: GalleryItem[] = - currentExample?.seeAlso ?? getSeeAlsoGalleryItems(ALL_MENU_ITEMS, currentExample, framework); - - // // Find the example category - // const exampleCategory = ALL_MENU_ITEMS.find(menuItem => { - // return menuItem.submenu.find(subMenu => subMenu.id === examplePage.id) !== undefined; - // }); - // // Generate the seeAlso gallery items - // const seeAlso: GalleryItem[] = examplePage?.seeAlso; - - const setOpenedMenuItem = (id: string, value: boolean = true) => { - setOpenedMenuItems({ ...openedMenuItems, [id]: value }); - }; - - const toggleOpenedMenuItem = (id: string) => { - setOpenedMenuItem(id, !openedMenuItems[id]); - }; - const toggleDrawer = () => setIsDrawerOpened(!isDrawerOpened); - - React.useEffect(() => { - const currentPath = window.location.pathname; - - // Check if the path is exactly "/" or empty (no path after the base URL) - if (currentPath === "/" || currentPath === "") { - navigate("/react", { replace: true }); // Redirect to /react by default - } - }, [navigate]); - - React.useEffect(() => { - if (typeof window === "undefined") return; - - setTheme(window.matchMedia("(prefers-color-scheme: dark)").matches ? ETheme.dark : ETheme.light); - }, []); - - React.useEffect(() => { - if (window.location.hostname.includes("scichart.com")) { - SciChartSurface.setRuntimeLicenseKey( - "shxKbfsTuNZPuUvgOGmB86JpC1O6sF/i9U7xaDYpPElY8ZsqUe83JjR6lUV+dZG7LWdO+/pEqECULJESzyFKBapZW1VeENYWi7Iuwzm5jXRg1GmjJDFprbvaJ5YSETDE4xOO5q5x36H93Za54vnZEhJFW0sk5S1vYHYbMJSyeSCvVkRgNPosuHuwKHjrzDToyh1qnr4gvCXFeNVCQnvHXQs8si6r2vhZ7S7vLeLqm4NseZ8kRe3QhGSPcThjHNumKEqg9oUn8ZjoG7hjCnexNoLYynV7CjRlHmmi0eS8hNz0bcoBWm6ctmW+9R2MU3CNcWh4hcVe92ghauAA5bUoIRa8qseFQJAJVamsfiWVJ7EC1GF+CLO68iGrZ7HpKg0SvLTODDAtrBYHKOzuZJH5x9sl5gzEwy9U5eOoS6oCPzCjOoPU4Ph7U9GHfFujxzGcgEC0UB57p0kEpQWaSJNJeaNLnJd3A448ja86X3iQT9mkVfCeoOGdavHMOpDuyoSuMxzGNQE198hqN1rQKE8Zr5U+I29XYBuJ5yg94tv7kaPpooJIMaJCMytb+0ivEFdje23dGriu7GtdM9TaZNGUDMT/nbPxrvdcoDEgjBRtxQ7ApoVX+PXJShzHBWjQTnDa8Em+/c/UZgFDmcFAwh86WUtO1bcT8rbRawbW4xhCdDZ3XuuWYuL0JJ8FVmKafK0m60Irzl40M8wh/9Ntl1I8ir5l+CVM+PXHL9t0O/AXbYI53gsTPpBD91xV/PYibNZ3BroAWOjwPHr3OLOd7Ro=" - ); - } - - if (currentExample) { - const parentMenuIds = getParentMenuIds(currentExample.id); - const updatedOpenedItems: Record = { ...openedMenuItems }; - parentMenuIds.forEach((elId) => { - updatedOpenedItems[elId] = true; - }); - setOpenedMenuItems(updatedOpenedItems); - } - }, [currentExampleId]); - - if (isIFrame) { - return ; - } - - const allGalleryItems = generateExamplesGallery(framework); - - const testIsOpened = (id: string): boolean => !!openedMenuItems[id]; - return ( - -
- {isMedium && ( - - - - )} -
- - - {isHomePage && } - - {is404 ? ( - - ) : isHomePage ? ( -
- {!isMedium ? ( -
- -
- ) : null} - -
- -
-
- ) : ( - - )} - - -
-
- -
- ); -} diff --git a/Examples/src/components/AppDetailsRouters/AppDetailsRouter.scss b/Examples/src/components/AppDetailsRouters/AppDetailsRouter.scss deleted file mode 100644 index e0dfae92b..000000000 --- a/Examples/src/components/AppDetailsRouters/AppDetailsRouter.scss +++ /dev/null @@ -1,610 +0,0 @@ -@import "../../assets/main.scss"; - -$drawerWidthDesktop: min(350px, 25vw); - -.frameworksection { - background-color: transparent; - margin-top: -4.2rem; -} - -.container { - width: 100%; - margin: 0 auto; - font-family: "Arial"; -} - -.actionButton { - height: 30px; - display: flex; - justify-content: center; - align-items: center; - gap: 7px; - - svg { - width: 20px; - height: 20px; - } - - @media only screen and (max-width: 768px) { - p { - display: none; - } - } -} - -.DrawerDesktop { - position: sticky; - top: 110px; - order: -1; - background-color: var(--bg); - width: $drawerWidthDesktop; - max-height: calc(100vh - 128px); - margin-right: 15px; - flex-shrink: 0; - overflow-x: hidden; - border: 1px solid var(--border-color); - border-radius: 15px; - overflow-x: hidden; - overflow-y: scroll; - - @include sm { - display: none; - } -} - -.FrameworkList { - margin: 0 auto; - padding: 0; - list-style: none; - display: flex; - gap: 16px; - justify-content: center; - align-items: center; - width: 100%; - - .FrameworkListItem { - margin: 18px 0 -1px 0; - display: flex; - align-items: center; - width: 100%; - text-align: center; - justify-content: center; - position: relative; - border-radius: 17px 17px 0 0; - padding: 10px 14px 8px 10px; - cursor: pointer; - color: white; - - &:hover { - color: #7593a4; - } - - &.active { - background: rgb(229, 229, 229); - color: #7593a4; - } - - a { - text-decoration: none; - font-family: "Arial"; - font-weight: 500; - font-size: 20px; - line-height: 30px; - letter-spacing: 0.02em; - color: #fff; - padding: 15px 0; - - @media only screen and (max-width: 768px) { - line-height: 58px; - } - } - } -} - -.mainWrapper { - display: flex; - padding: 20px; - background: var(--bg-darker); - @media only screen and (max-width: 768px) { - padding: 0; - } -} - -.contentwrapper { - display: flex; - flex-direction: column; - padding: 16px; - gap: 15px; - background: var(--bg); - border: 1px solid var(--border-color); - border-radius: 15px; - overflow: hidden; - width: 100%; - - @media only screen and (max-width: 768px) { - max-width: 100vw; - border: none; - border-radius: 0 0 15px 15px; - } - - .layoutButtons { - display: none; - margin-left: auto; - - @media screen and (min-width: 1900px) { - display: flex; - } - - height: 30px; - gap: 6px; - - svg { - width: 30px; - height: 30px; - cursor: pointer; - fill: rgba(57, 98, 147, 0.5); - } - - .active svg { - fill: rgb(57, 98, 147); - } - } -} - -.contentwrapper .chartdescription { - padding: 0 0.25rem; -} - -.contentwrapper .dynamicFlexWrapper { - position: relative; - display: flex; - gap: 15px; - flex-direction: column; - width: 100%; - max-width: 100%; - height: 100%; - align-items: center; - justify-content: center; - - @media (min-width: 1900px) { - flex-direction: row; - } - - &.maxWidth { - flex-direction: column; - } -} - -.contentwrapper .dynamicFlexWrapper > * { - width: 100%; - height: 100%; - max-height: 80vh; - max-width: min(100vh, 100vw); // trick to keep chart into view - aspect-ratio: 1.5; - overflow: hidden; -} - -@media only screen and (max-width: 768px) { - .contentwrapper .dynamicFlexWrapper > * { - max-width: 100%; - aspect-ratio: 1/1.5; - } -} - -.tabbtnwrap { - display: flex; - align-items: end; - justify-content: end; - gap: 10px; - - .btnprimary, - .btn { - display: flex; - align-items: center; - justify-content: center; - border-radius: 8px; - gap: 2px; - font-size: 14px; - font-family: "Arial"; - line-height: 20px; - height: 35px; - min-width: 50px; - color: white; - text-decoration: none; - padding: 4px 8px 4px 6px; - transition: all 200ms linear; - cursor: pointer; - } - - .btnprimary { - background: linear-gradient(90deg, #1aa2d5 15.5%, #35bfb7 100%); - } - - .btnDark { - background-color: #212121; - } - - .btnGithub { - background: var(--light-blue); - } - - .btnNpm { - background: #cb3837; - - svg { - width: 34px; - height: 34px; - } - } - - .btnDocs { - background: var(--light-blue); - } - - .btn:hover { - color: #ccc; - } - - &.hiddenSmall { - @media only screen and (max-width: 1900px) { - display: none; - } - } - - &.hiddenLarge { - @media screen and (min-width: 1900px) { - display: none; - } - } -} - -.mobilehidden { - @media only screen and (max-width: 768px) { - display: none !important; - } -} - -.desktophidden { - display: none !important; - - @media only screen and (max-width: 768px) { - display: block !important; - } -} - -.scichartcontainer { - display: flex; - flex-direction: column; - gap: 10px; - font-family: Arial; - line-height: 1.5em; - font-size: 1.1em; - - code { - font-family: Consolas, monospace; - font-size: 1.1em; - background-color: var(--markdown-code-background); - padding: 0px 5px 0px 5px; - color: var(--markdown-code-text); - } - - .scichartinfo { - display: flex; - align-items: center; - justify-content: space-between; - background: linear-gradient(97.32deg, #150b3b 20.12%, #4a348f 68.86%, #b330aa 85.96%, #d86886 99.96%); - border-radius: 10px; - padding: 20px; - color: white; - - p { - flex: 1; - margin-right: 20px; // Space between text and button - } - - a { - color: blue; - text-decoration: none; - - &:hover { - text-decoration: underline; - } - } - - .gettingstartedbtn { - padding: 10px 20px; - background-color: white; - color: black; - border: none; - border-radius: 5px; - cursor: pointer; - font-weight: bold; - transition: background-color 0.3s ease; - - &:hover { - background-color: #ffdd67; - } - } - } - - .scichartdescription { - margin-top: 20px; - - p { - margin-bottom: 15px; - - a { - color: #5514b4; - text-decoration: none; - - &:hover { - text-decoration: underline; - } - } - } - } - - .documentationlinkscontainer { - margin-top: 30px; - - h3 { - text-align: center; - color: #1a1a1a; - margin-bottom: 30px; - font-weight: 600; - font-size: 32px; - font-family: Arial; - } - - .documentationlinks { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - background-color: #2d5a8c; - border-radius: 10px; - padding: 20px; - - a { - display: block; - width: calc(50% - 10px); - background-color: #f3f4f6; - font-family: "Arial"; - color: #2d5a8c; - padding: 15px; - margin-bottom: 10px; - text-align: center; - border-radius: 5px; - text-decoration: none; - transition: background-color 0.3s ease, color 0.3s ease; - - &:hover { - background-color: #e0e7ef; - color: #1a1a1a; - } - } - } - } - - .candlestickchartscontainer { - margin-top: 30px; - color: #1a1a1a; - font-family: "Arial"; - - h2 { - text-align: center; - color: #1a1a1a; - margin-bottom: 20px; - font-size: 2rem; - } - - p { - margin-bottom: 20px; - line-height: 1.6; - - a { - color: #5514b4; - text-decoration: none; - - &:hover { - text-decoration: underline; - } - } - } - - h3 { - margin-top: 30px; - color: #1a1a1a; - font-size: 1.5rem; - } - - ul { - margin-top: 20px; - padding-left: 20px; - font-family: "Arial"; - list-style: none; - list-style-type: disc !important; - - li { - margin-bottom: 10px; - font-size: 1rem; - line-height: 1.5; - list-style-type: inherit; - } - } - } - - .whyusescichart { - background: linear-gradient(97.32deg, #150b3b 20.12%, #4a348f 68.86%, #b330aa 85.96%, #d86886 99.96%); - color: white; - padding: 20px; - border-radius: 10px; - margin: 20px 0; - font-family: "Arial"; - - h3 { - text-align: center; - font-size: 32px; - margin-bottom: 10px; - color: rgba(255, 255, 255, 1); - } - - .benefits { - display: flex; - justify-content: space-between; - flex-wrap: wrap; - - ul { - list-style-type: none; - padding: 0; - - li { - margin: 10px 0; - display: flex; - align-items: center; - - &::before { - content: "โ—"; - color: white; - margin-right: 10px; - font-size: 20px; - } - } - } - } - } - - .Questions { - h2 { - display: flex; - margin: auto; - justify-content: center; - align-items: center; - color: black; - font-family: "Arial"; - font-size: 32px; - margin-top: 30px; - margin-bottom: 30px; - } - } - - .QuestionsBack { - border: 1px solid rgba(180, 208, 219, 1); - background: rgba(243, 247, 252, 1); - color: rgba(5, 10, 48, 1); - padding: 30px; - border-radius: 10px; - margin: 20px 0; - font-family: "Arial"; - - h3 { - color: rgba(5, 10, 48, 1); - font-weight: 600; - font-size: 24px; - margin-bottom: 20px; - font-family: "Arial"; - line-height: 36px; - } - } - - .newblockcontainer { - font-family: "Arial"; - display: flex; - background: rgb(5, 10, 48); - border-radius: 20px; - overflow: hidden; - - .imagecontainer { - flex: 1; - - img { - max-width: 100%; - height: auto; - background: rgba(5, 10, 48, 1); - } - } - - .buttoncontainer { - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; // Align buttons vertically - gap: 10px; // Spacing between buttons - - h3 { - display: flex; - align-items: center; - font-family: "Arial"; - justify-content: center; - color: white; - font-weight: 600; - font-size: 32px; - } - - button { - padding: 17px 5px; - background-color: #4a90e2; - color: white; - border: none; - border-radius: 4px; - font-size: 16px; - font-family: "Arial"; - font-weight: 500; - width: 88%; - margin-left: 30px; - cursor: pointer; - - &:hover { - background-color: #357abd; - } - } - } - } - - .codecardscontainer { - display: flex; - justify-content: space-between; - gap: 20px; - - .codecard { - width: 100%; - padding: 20px; - border: 1px solid rgba(180, 208, 219, 1); - background: rgba(255, 255, 255, 1); - border-radius: 8px; - text-align: center; - overflow: hidden; - - img { - width: 100%; - height: auto; - border-radius: 8px; - } - - h4 { - margin-top: 10px; - font-size: 20px; - font-weight: bold; - font-family: Arial; - color: rgba(42, 99, 151, 1); - margin-bottom: 10px; - } - - .viewsourcebutton { - margin-top: 10px; - padding: 15px 25px; - font-size: 16px; - font-family: "Arial"; - width: 70%; - background: linear-gradient(90deg, #1aa2d5 15.5%, #35bfb7 100%); - color: white; - border: none; - border-radius: 6px; - cursor: pointer; - - &:hover { - background-color: #0088cc; - } - } - } - } -} diff --git a/Examples/src/components/AppDetailsRouters/AppDetailsRouter.tsx b/Examples/src/components/AppDetailsRouters/AppDetailsRouter.tsx deleted file mode 100644 index fd19dac84..000000000 --- a/Examples/src/components/AppDetailsRouters/AppDetailsRouter.tsx +++ /dev/null @@ -1,276 +0,0 @@ -import { FC, useContext, useEffect, useState } from "react"; -import { FrameworkContext } from "../../helpers/shared/Helpers/FrameworkContext"; -import { EPageFramework, getFrameworkContent } from "../../helpers/shared/Helpers/frameworkParametrization"; -import { EPageLayout, ETheme, ExampleSourceFile, GalleryItem } from "../../helpers/types/types"; -import { TExamplePage } from "../AppRouter/examplePages"; -import { MENU_ITEMS_2D, MENU_ITEMS_3D, MENU_ITEMS_FEATURED_APPS } from "../AppRouter/examples"; -import { ExampleBreadcrumbs } from "../Breadcrumbs/ExampleBreadcrumbs"; -import DrawerContent from "../DrawerContent/DrawerContent"; -import ExamplesRoot from "../Examples/ExampleRootDetails"; -import GalleryItems from "../GalleryItems"; -import classes from "./AppDetailsRouter.scss"; -import MarkdownContent from "./MarkdownContent"; -import { CodeSandbox } from "../CodeSandbox"; -import { StackblitzEditor } from "../CodeSandbox/StackblitzEditor"; -import { SandboxPlatform } from "../CodeSandbox/SandboxPlatform"; -import { CodeActionButtons } from "./CodeActionButtons"; -import { CodePreview } from "../CodePreview/CodePreview"; -import { ExamplesSubtitle } from "./ExamplesSubtitle"; -import { SourceFilesContext } from "./SourceFilesLoading/SourceFilesContext"; -import type { StackBlitzResponse } from "../../helpers/types/types"; -import { ToolbarGroup } from "../buttons/Toolbar"; -import { Tooltip } from "@mui/material"; - -type TProps = { - currentExample: TExamplePage; - isIFrame?: boolean; - seeAlso: GalleryItem[]; - theme: ETheme; -}; - -const AppDetailsRouter: FC = (props) => { - const { currentExample, seeAlso, theme } = props; - - const initialSourceFilesVariant = useContext(SourceFilesContext); - const getInitialSelectedFile = () => - initialSourceFilesVariant.files.find((file) => file.name.startsWith("drawExample")) ?? - initialSourceFilesVariant.files.find((file) => file.name.startsWith("index")) ?? - initialSourceFilesVariant.files[0]; - - const [sourceFiles, setSourceFiles] = useState(initialSourceFilesVariant.files); - const [selectedFile, setSelectedFile] = useState(getInitialSelectedFile); - const [pageLayout, setPageLayout] = useState(EPageLayout.Default); - const [isSideBySidePossible, setIsSideBySidePossible] = useState(); - const [embedCode, setEmbedCode] = useState(false); - const [sandboxPlatform, setSandboxPlatform] = useState(SandboxPlatform.CodeSandbox); - const [sandboxId, setSandboxId] = useState(""); - const [projectFiles, setProjectFiles] = useState(null); - const [sourceFramework, setSourceFramework] = useState(initialSourceFilesVariant.framework); - const [sandboxFramework, setSandboxFramework] = useState(null); - - const selectedFramework = useContext(FrameworkContext); - const pageTitle = getFrameworkContent(currentExample.title, selectedFramework); - - let initialOpenedMenuItems = { - MENU_ITEMS_FEATURED_APPS_ID: true, - MENU_ITEMS_3D_ID: true, - MENU_ITEMS_2D_ID: true, - }; - - MENU_ITEMS_FEATURED_APPS.forEach((item) => { - initialOpenedMenuItems = { ...initialOpenedMenuItems, [item.id]: true }; - }); - MENU_ITEMS_3D.forEach((item) => { - initialOpenedMenuItems = { ...initialOpenedMenuItems, [item.id]: true }; - }); - MENU_ITEMS_2D.forEach((item) => { - initialOpenedMenuItems = { ...initialOpenedMenuItems, [item.id]: true }; - }); - - const [openedMenuItems, setOpenedMenuItems] = useState>(initialOpenedMenuItems); - - useEffect(() => { - setIsSideBySidePossible(window.innerWidth > 1900); - setPageLayout(currentExample.pageLayout ?? EPageLayout.Default); - window.scrollTo({ - top: 0, - }); - // Reset sandbox state when example changes - setEmbedCode(false); - setSandboxId(""); - setProjectFiles(null); - setSandboxFramework(null); - - fetch("source/" + currentExample.path + "?framework=" + selectedFramework) - .then((response) => { - if (!response.ok) { - throw new Error("Network response was not ok"); - } - return response.json(); - }) - .then((json: { files: { name: string; content: string }[]; framework: EPageFramework }) => { - let defaultFile = json.files.find((f) => f.name === "drawExample.ts"); - if (!defaultFile) { - defaultFile = json.files[json.files.length - 1]; - } - setSelectedFile({ name: defaultFile.name, content: defaultFile.content }); - setSourceFiles(json.files); - setSourceFramework(json.framework); - }); - }, [currentExample, selectedFramework]); - - useEffect(() => { - const handleResize = () => { - setIsSideBySidePossible(window.innerWidth > 1900); - }; - window.addEventListener("resize", handleResize); - return () => window.removeEventListener("resize", handleResize); - }, []); - - useEffect(() => { - if (embedCode) { - setEmbedCode(false); - setProjectFiles(null); - setSandboxFramework(null); - } - }, []); - - const handleFileClick = (fileName: string) => { - const file = sourceFiles.find((f) => f.name.includes(fileName)); - setSelectedFile({ name: file.name, content: file.content }); - }; - - const setOpenedMenuItem = (id: string, value: boolean = true) => { - setOpenedMenuItems({ ...openedMenuItems, [id]: value }); - }; - - const testIsOpened = (id: string): boolean => !!openedMenuItems[id]; - const toggleOpenedMenuItem = (id: string) => setOpenedMenuItem(id, !openedMenuItems[id]); - - const handleBack = () => { - setEmbedCode(false); - setSandboxId(""); - setProjectFiles(null); - setSandboxFramework(null); - }; - - const handleSandboxOpen = (platform: SandboxPlatform, id: string, files?: any, framework?: EPageFramework) => { - setSandboxPlatform(platform); - setSandboxId(id); - if (files) { - setProjectFiles(files); - } - if (framework) { - setSandboxFramework(framework); - } - setEmbedCode(true); - }; - - const renderEditor = () => { - return sandboxPlatform === SandboxPlatform.CodeSandbox ? ( - - ) : ( - - ); - }; - - const LayoutButtons = () => { - return ( -
    -
  • setPageLayout(EPageLayout.Default)} - className={pageLayout === EPageLayout.Default ? classes.active : ""} - > - - - - -
  • - -
  • setPageLayout(EPageLayout.MaxWidth)} - className={pageLayout === EPageLayout.MaxWidth ? classes.active : ""} - > - - - - -
  • -
- ); - }; - - const isMaxWidth = pageLayout === EPageLayout.MaxWidth || !isSideBySidePossible; - const md = getFrameworkContent(currentExample.markdownContent, selectedFramework); - - return ( -
-
-
- {}} - currentExample={currentExample} - /> -
-
-
-
- - - -
- -
-

- {pageTitle} -

- - {/* Github, stackblitz buttons visible on maxwidth layout */} - {!isMaxWidth ? ( - - ) : null} -
- - {/* Subtitle // this returns a

already */} - - - {/* Main example section */} - {embedCode ? ( - renderEditor() - ) : ( -

- - - -
- )} - -
- -
-
-
- ); -}; - -export default AppDetailsRouter; diff --git a/Examples/src/components/AppDetailsRouters/CodeActionButton.tsx b/Examples/src/components/AppDetailsRouters/CodeActionButton.tsx deleted file mode 100644 index 021ec1db5..000000000 --- a/Examples/src/components/AppDetailsRouters/CodeActionButton.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from "react"; -import classes from "./AppDetailsRouter.scss"; -import { Icon, TIconType } from "../buttons/Icon"; - -interface BaseCodeActionButtonProps { - iconName: TIconType; - label?: string; - className?: string; - title?: string; - rel?: string; -} - -interface LinkCodeActionButtonProps extends BaseCodeActionButtonProps { - href: string; - target?: string; - onClick?: never; -} - -interface ClickCodeActionButtonProps extends BaseCodeActionButtonProps { - onClick: (e: React.MouseEvent) => void; - href?: never; - target?: never; -} - -type CodeActionButtonProps = LinkCodeActionButtonProps | ClickCodeActionButtonProps; - -export const CodeActionButton: React.FC = ({ - iconName, - label, - className = classes.btn, - title, - href, - target, - onClick, - rel, -}) => { - return href ? ( -
- - {label ?

{label}

: null} -
- ) : ( - - - {label ?

{label}

: null} -
- ); -}; diff --git a/Examples/src/components/AppDetailsRouters/CodeActionButtons.tsx b/Examples/src/components/AppDetailsRouters/CodeActionButtons.tsx deleted file mode 100644 index 2da87d0de..000000000 --- a/Examples/src/components/AppDetailsRouters/CodeActionButtons.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import React, { FC, ReactNode, useState } from "react"; -import classes from "./AppDetailsRouter.scss"; -import { - EPageFramework, - getFrameworkContent, - getFrameworkName, -} from "../../helpers/shared/Helpers/frameworkParametrization"; -import { TExamplePage } from "../AppRouter/examplePages"; -import { SandboxPlatform } from "../CodeSandbox/SandboxPlatform"; -import { getSandboxUrl, getStackBlitzFiles } from "./sandboxUtils"; -import { CodeActionButton } from "./CodeActionButton"; -import type { StackBlitzResponse } from "../../helpers/types/types"; - -type CodeActionButtonsProps = { - className?: string; - currentExample: TExamplePage; - selectedFramework: EPageFramework; - selectedFile: { name: string; content: string }; - onSandboxOpen: ( - platform: SandboxPlatform, - sandboxId: string, - projectFiles?: StackBlitzResponse, - framework?: EPageFramework - ) => void; - style?: React.CSSProperties; -}; - -export const CodeActionButtons: FC = ({ - className, - currentExample, - selectedFramework, - onSandboxOpen, - selectedFile, - style, -}): ReactNode => { - const [availableFrameworks] = useState([ - EPageFramework.React, - EPageFramework.Vanilla, - EPageFramework.Angular, - ]); - - const isFrameworkVariantAvailable = availableFrameworks?.includes(selectedFramework); - const frameWorkName = getFrameworkName(selectedFramework); - - const pageTitle = getFrameworkContent(currentExample.title, selectedFramework); - - const contextualGithubTitle = - currentExample !== undefined - ? `View source for ${pageTitle} on Github` - : "Clone SciChart.js.examples on GitHub"; - - const handleSandboxClick = async (e: React.MouseEvent, platform: SandboxPlatform) => { - e.preventDefault(); - try { - const framework = isFrameworkVariantAvailable ? selectedFramework : EPageFramework.React; - - if (platform === SandboxPlatform.CodeSandbox) { - const { id, actualFramework } = await getSandboxUrl(currentExample.path, framework, platform); - if (id) { - onSandboxOpen(platform, id, undefined, actualFramework); - } else { - console.log("error"); - } - } else { - // For StackBlitz, get the files first - const files = await getStackBlitzFiles(currentExample.path, framework); - onSandboxOpen(platform, currentExample.path, files); - } - } catch (error) { - console.error("Failed to open sandbox:", error); - } - }; - - return ( -
- - handleSandboxClick(e, SandboxPlatform.StackBlitz)} - title={ - isFrameworkVariantAvailable - ? `Edit ${getFrameworkContent(currentExample.title, selectedFramework)} in StackBlitz` - : `Sorry, we have not got ${frameWorkName} code for this example yet, so you will see react code instead, but the actual chart code is always the same. Contact support@scichart.com to request prioritisation of this example` - } - /> - handleSandboxClick(e, SandboxPlatform.CodeSandbox)} - title={ - isFrameworkVariantAvailable - ? `Edit ${getFrameworkContent(currentExample.title, selectedFramework)} in CodeSandbox` - : `Sorry, we have not got ${frameWorkName} code for this example yet, so you will see react code instead, but the actual chart code is always the same. Contact support@scichart.com to request prioritisation of this example` - } - /> - - - -
- ); -}; diff --git a/Examples/src/components/AppDetailsRouters/ExampleButton.tsx b/Examples/src/components/AppDetailsRouters/ExampleButton.tsx deleted file mode 100644 index 37edd14f7..000000000 --- a/Examples/src/components/AppDetailsRouters/ExampleButton.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from "react"; -import classes from "./AppDetailsRouter.scss"; -import { Icon } from "../buttons/Icon"; - -interface BaseExampleButtonProps { - iconName: string; - label: string; - className?: string; - title?: string; - rel?: string; -} - -interface LinkExampleButtonProps extends BaseExampleButtonProps { - href: string; - target?: string; - onClick?: never; -} - -interface ClickExampleButtonProps extends BaseExampleButtonProps { - onClick: (e: React.MouseEvent) => void; - href?: never; - target?: never; -} - -type ExampleButtonProps = LinkExampleButtonProps | ClickExampleButtonProps; - -export const ExampleButton: React.FC = ({ - iconName, - label, - className = classes.btn, - title, - href = "#", - target, - onClick, - rel, -}) => { - return ( - - -  {label} - - ); -}; diff --git a/Examples/src/components/AppDetailsRouters/ExamplesButtons.tsx b/Examples/src/components/AppDetailsRouters/ExamplesButtons.tsx deleted file mode 100644 index bb5254adb..000000000 --- a/Examples/src/components/AppDetailsRouters/ExamplesButtons.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import React, { FC, ReactNode, useState } from "react"; -import classes from "./AppDetailsRouter.scss"; -import { - EPageFramework, - getFrameworkContent, - getFrameworkName, -} from "../../helpers/shared/Helpers/frameworkParametrization"; -import { TExamplePage } from "../AppRouter/examplePages"; -import { SandboxPlatform } from "../CodeSandbox/SandboxPlatform"; -import { getSandboxUrl, getStackBlitzFiles } from "./sandboxUtils"; -import { ExampleButton } from "./ExampleButton"; - -type ExampleButtonsProps = { - className?: string; - currentExample: TExamplePage; - selectedFramework: EPageFramework; - selectedFile: { name: string; content: string }; - onSandboxOpen: ( - platform: SandboxPlatform, - sandboxId: string, - projectFiles?: any, - framework?: EPageFramework - ) => void; - style?: React.CSSProperties; -}; - -export const ExampleButtons: FC = ({ - className, - currentExample, - selectedFramework, - onSandboxOpen, - selectedFile, - style, -}): ReactNode => { - const [availableFrameworks] = useState([ - EPageFramework.React, - EPageFramework.Vanilla, - EPageFramework.Angular, - ]); - - const isFrameworkVariantAvailable = availableFrameworks?.includes(selectedFramework); - const frameWorkName = getFrameworkName(selectedFramework); - - const handleSandboxClick = async (e: React.MouseEvent, platform: SandboxPlatform) => { - e.preventDefault(); - try { - const framework = isFrameworkVariantAvailable ? selectedFramework : EPageFramework.React; - - if (platform === SandboxPlatform.CodeSandbox) { - const { id, actualFramework } = await getSandboxUrl(currentExample.path, framework, platform); - if (id) { - onSandboxOpen(platform, id, undefined, actualFramework); - } else { - console.log("error"); - } - } else { - // For StackBlitz, get the files first - const files = await getStackBlitzFiles(currentExample.path, framework); - onSandboxOpen(platform, currentExample.path, files); - } - } catch (error) { - console.error("Failed to open sandbox:", error); - } - }; - - return ( -
- handleSandboxClick(e, SandboxPlatform.StackBlitz)} - title={ - isFrameworkVariantAvailable - ? `Edit ${getFrameworkContent(currentExample.title, selectedFramework)} in StackBlitz` - : `Sorry, we have not got ${frameWorkName} code for this example yet, so you will see react code instead, but the actual chart code is always the same. Contact support@scichart.com to request prioritisation of this example` - } - /> - handleSandboxClick(e, SandboxPlatform.CodeSandbox)} - title={ - isFrameworkVariantAvailable - ? `Edit ${getFrameworkContent(currentExample.title, selectedFramework)} in CodeSandbox` - : `Sorry, we have not got ${frameWorkName} code for this example yet, so you will see react code instead, but the actual chart code is always the same. Contact support@scichart.com to request prioritisation of this example` - } - /> - -
- ); -}; diff --git a/Examples/src/components/AppDetailsRouters/ExamplesSubtitle.scss b/Examples/src/components/AppDetailsRouters/ExamplesSubtitle.scss deleted file mode 100644 index 8e31628c5..000000000 --- a/Examples/src/components/AppDetailsRouters/ExamplesSubtitle.scss +++ /dev/null @@ -1,10 +0,0 @@ -.subtitle { - display: block; - - &.maxWidth { - width: 100%; - max-width: min(100vh, 100vw); - margin: 0 auto; - text-align: start; - } -} diff --git a/Examples/src/components/AppDetailsRouters/ExamplesSubtitle.tsx b/Examples/src/components/AppDetailsRouters/ExamplesSubtitle.tsx deleted file mode 100644 index 6dd589179..000000000 --- a/Examples/src/components/AppDetailsRouters/ExamplesSubtitle.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React, { FC, ReactElement } from "react"; -import ReactMarkdown from "react-markdown"; -import classes from "./ExamplesSubtitle.scss"; - -type TSubtitleProps = { - content: ReactElement | string; - isMaxWidth?: boolean; -}; - -export const ExamplesSubtitle: FC = ({ content, isMaxWidth }) => { - const className = `${classes.subtitle} ${isMaxWidth ? classes.maxWidth : ""}`; - - if (typeof content === "string") { - return ( - - {content} - - ); - } - - return {content}; -}; diff --git a/Examples/src/components/AppDetailsRouters/FrameworkSelect.tsx b/Examples/src/components/AppDetailsRouters/FrameworkSelect.tsx deleted file mode 100644 index 23eb56974..000000000 --- a/Examples/src/components/AppDetailsRouters/FrameworkSelect.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { Link } from "react-router"; -import { - EPageFramework, - FRAMEWORK_NAME, - useExampleRouteParams, -} from "../../helpers/shared/Helpers/frameworkParametrization"; -import classes from "./AppDetailsRouter.scss"; - -const FrameworkSVG = { - [EPageFramework.React]: ( - - - - - - - ), - [EPageFramework.Angular]: ( - - - - ), - // [EPageFramework.Vue]: ( - // - // - // - // - // ), - [EPageFramework.Vanilla]: ( - - - - - ), -}; - -export const FrameworkSelect = () => { - const { currentExample, framework: currentFramework } = useExampleRouteParams(); - return ( -
-
- {Object.values(EPageFramework).map((framework) => ( - - {FrameworkSVG[framework]} -   - {FRAMEWORK_NAME[framework]} - - ))} -
-
- ); -}; diff --git a/Examples/src/components/AppDetailsRouters/MarkdownContent.tsx b/Examples/src/components/AppDetailsRouters/MarkdownContent.tsx deleted file mode 100644 index f7fda0383..000000000 --- a/Examples/src/components/AppDetailsRouters/MarkdownContent.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { FC } from "react"; -import ReactMarkdown from "react-markdown"; -import rehypeRaw from "rehype-raw"; -import { EPageFramework, getFrameworkContent } from "../../helpers/shared/Helpers/frameworkParametrization"; -import { TExamplePage } from "../AppRouter/examplePages"; -import classes from "./AppDetailsRouter.scss"; - -type TProps = { - currentExample: TExamplePage; - selectedFramework: EPageFramework; -}; - -const plugins = [rehypeRaw as any]; - -const MarkdownContent: FC = (props) => { - const { currentExample, selectedFramework } = props; - return ( -
- - {getFrameworkContent(currentExample.markdownContent, selectedFramework)} - -
- ); -}; - -export default MarkdownContent; diff --git a/Examples/src/components/AppDetailsRouters/SourceFilesLoading/SourceFilesContext.ts b/Examples/src/components/AppDetailsRouters/SourceFilesLoading/SourceFilesContext.ts deleted file mode 100644 index 5f8f64098..000000000 --- a/Examples/src/components/AppDetailsRouters/SourceFilesLoading/SourceFilesContext.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createContext } from "react"; -import { SourceFilesVariant } from "../../../helpers/types/types"; -import { EPageFramework } from "../../../helpers/shared/Helpers/frameworkParametrization"; - -export const defaultSourceFilesVariant: SourceFilesVariant = { - framework: EPageFramework.React, - files: [{ name: "drawExample.ts", content: "// Loading ... " }], -}; -export const SourceFilesContext = createContext(defaultSourceFilesVariant); diff --git a/Examples/src/components/AppDetailsRouters/constants.ts b/Examples/src/components/AppDetailsRouters/constants.ts deleted file mode 100644 index e4229a7d0..000000000 --- a/Examples/src/components/AppDetailsRouters/constants.ts +++ /dev/null @@ -1,44 +0,0 @@ -export const mockFiles = [ - { - name: "drawExample-for-testing.ts", - content: `import { SciChartSurface } from "scichart/Charting/Visuals/SciChartSurface"; -import { NumericAxis } from "scichart/Charting/Visuals/Axis/NumericAxis"; -import { EAxisAlignment } from "scichart/types/AxisAlignment"; -import { EAutoRange } from "scichart/types/AutoRange"; - -export async function drawExample(divId: string) { - const { sciChartSurface, wasmContext } = await SciChartSurface.create(divId); - - sciChartSurface.xAxes.add(new NumericAxis(wasmContext, { - axisAlignment: EAxisAlignment.Bottom - })); - - sciChartSurface.yAxes.add(new NumericAxis(wasmContext, { - axisAlignment: EAxisAlignment.Left, - autoRange: EAutoRange.Always - })); - - sciChartSurface.renderableSeries.add(new LineSeries(wasmContext, { - dataSeries: new XyDataSeries(wasmContext, { - dataSeriesName: "Line Series", - xValues: [1, 2, 3, 4, 5], - yValues: [1, 2, 3, 4, 5] - }) - })) - - sciChartSurface.zoomExtents(); -}`, - }, - { - name: "index.tsx", - content: `import { SciChartSurface } from "scichart/Charting/Visuals/SciChartSurface";`, - }, - { - name: "example.html", - content: `
`, - }, - { - name: "angular.ts", - content: `import { SciChartSurface } from "scichart/Charting/Visuals/SciChartSurface";`, - }, -]; diff --git a/Examples/src/components/AppDetailsRouters/markdown.css b/Examples/src/components/AppDetailsRouters/markdown.css deleted file mode 100644 index 76f293944..000000000 --- a/Examples/src/components/AppDetailsRouters/markdown.css +++ /dev/null @@ -1,48 +0,0 @@ -/* This is the CSS for the markdown custom components */ -/* The reason for them being written in .css instead of .scss is that we need static class names, -and .scss pre-processors add some random strings at the end of any class at runtime to avoid bleeding */ - -/* General */ -.md { - --gray: #dddddd; - --light-gray: #f5f5f5; - --white: #ffffff; - --link-blue: #0b58cb; - --padding: 1rem; - --radius: 4px; -} - -.md-tips, -.md-checklist { - margin: 0; - width: 100%; - - h1, - h2, - h3, - h4, - h5, - h6, - p { - margin: 0; - } - - a { - color: var(--link-blue); - text-decoration: none; - } -} - -/* 1. Tips */ -.md-tips { - background-color: var(--light-gray); - border-left: 5px solid var(--gray); - padding: var(--padding); - border-radius: var(--radius); -} - -/* 2. checklist */ -.md-checklist { - list-style-type: none; - padding: 0; -} diff --git a/Examples/src/components/AppDetailsRouters/sandboxUtils.ts b/Examples/src/components/AppDetailsRouters/sandboxUtils.ts deleted file mode 100644 index 48ac12d4a..000000000 --- a/Examples/src/components/AppDetailsRouters/sandboxUtils.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { SandboxPlatform } from "../CodeSandbox/SandboxPlatform"; -import { EPageFramework } from "../../helpers/shared/Helpers/frameworkParametrization"; -import type { StackBlitzResponse } from "../../helpers/types/types"; - -// Types for the API responses -interface SandboxUrlResponse { - id: string; - actualFramework: EPageFramework; -} - -interface SandboxErrorResponse { - error: string; - alternativeUrl: string; -} - -// Function to extract sandbox ID from URL -export function extractSandboxId(url: string, platform: SandboxPlatform): string { - try { - if (platform === SandboxPlatform.CodeSandbox) { - // Extract ID from CodeSandbox URL format - const match = url.match(/\/s\/([^/?]+)/); - return match ? match[1] : ""; - } else { - // Extract ID from StackBlitz URL format - const match = url.match(/\/run\?project\[id\]=([^&]+)/); - return match ? match[1] : ""; - } - } catch (e) { - console.error("Failed to parse sandbox URL:", e); - return ""; - } -} - -// Function to get make sandbox -const GET_SANDBOX_URL = "api/sandboxurl/"; -export async function getSandboxUrl( - examplePath: string, - framework: EPageFramework = EPageFramework.React, - platform = "codeSandbox" -): Promise<{ id: string; actualFramework: EPageFramework }> { - try { - const response = await fetch(`${GET_SANDBOX_URL}${examplePath}?framework=${framework}&platform=${platform}`); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - console.log(response); - const data = (await response.json()) as SandboxUrlResponse | SandboxErrorResponse; - console.log(data); - - if ("error" in data) { - throw new Error(`API error: ${data.error}. Alternative URL: ${data.alternativeUrl}`); - } - - console.log(data); - return { id: data.id, actualFramework: data.actualFramework }; - } catch (error) { - console.error("Failed to get CodeSandbox URL:", error); - throw error; - } -} - -// Function to get StackBlitz files -export async function getStackBlitzFiles( - examplePath: string, - framework: EPageFramework = EPageFramework.React -): Promise { - try { - const response = await fetch(`api/stackblitz/files/${examplePath}?framework=${framework}`); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - const data = await response.json(); - - if ("error" in data) { - throw new Error(`API error: ${data.error}`); - } - - return data as StackBlitzResponse; - } catch (error) { - console.error("Failed to get StackBlitz files:", error); - throw error; - } -} diff --git a/Examples/src/components/AppDetailsRouters/utils.ts b/Examples/src/components/AppDetailsRouters/utils.ts deleted file mode 100644 index 16e173ff6..000000000 --- a/Examples/src/components/AppDetailsRouters/utils.ts +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Extracts the filename from a path string, handling both Windows and Unix-style paths. - * Examples: - * - "C:/path/to/file.ts" -> "file.ts" - * - "/path/to/file.ts" -> "file.ts" - * - "src/file.ts" -> "file.ts" - * - "file.ts" -> "file.ts" - */ -export const getFileName = (path: string): string => { - return path.split(/[/\\]/).pop() || ""; -}; - -/** - * Processes an array of files to: - * 1. Extract just the filename from any path - * 2. Sort files so that "drawExample" files appears first, followed by "index" files and then the rest - */ -export const processFiles = (files: T[]): T[] => { - return files - .map((file) => ({ ...file, name: getFileName(file.name) })) - .sort((a, b) => { - if (a.name.includes("drawExample")) { - return -1; - } - if (b.name.includes("drawExample")) { - return 1; - } - if (a.name.includes("index")) { - return -1; - } - if (b.name.includes("index")) { - return 1; - } - return a.name.localeCompare(b.name); - }); -}; diff --git a/Examples/src/components/AppFooter/AppFooter.module.scss b/Examples/src/components/AppFooter/AppFooter.module.scss deleted file mode 100644 index 722ba5843..000000000 --- a/Examples/src/components/AppFooter/AppFooter.module.scss +++ /dev/null @@ -1,119 +0,0 @@ -@import "../../assets/main.scss"; -@import "./CommonFooterStyles.module.scss"; - -.AppFooter { - padding: 40px; - overflow: hidden; - background: var(--primary); - color: white; - - @include sm { - padding: 40px 0; - } - - .FooterBottomSection { - @extend %CommonFooterGridConfigs; - } - - h4, - h5, - h6 { - color: $color-primary-white; - font-weight: 600; - } - - h5 { - font-size: 22px; - line-height: 27px; - } - - h6 { - font-size: 18px; - line-height: 22px; - margin-bottom: 26px; - margin-top: 40px; - } - - @include sm { - h5 { - font-size: 20px; - line-height: 24px; - } - - h6 { - font-size: 16px; - line-height: 20px; - } - } - - .LinksBox { - padding: 40px; - - @include sm { - padding: 40px 16px 0 16px; - } - - P { - margin: 40px 0; - color: $color-primary-grey; - } - } - - .RelatedLinks { - @extend %CommonLinkStyles; - - display: flex; - flex-direction: column; - margin-top: 40px; - } - - .ContactUsButton { - flex: none; - width: 170px; - padding: $default-spacing * 2 $default-spacing * 2; - border-radius: 4px; - background: $color-link-text; - margin: 30px 0; - color: white; - - span { - color: $color-lightest-green; - font-size: 12px; - font-weight: 600; - letter-spacing: 0.05em; - line-height: 15px; - text-align: center; - text-transform: uppercase; - text-decoration-thickness: auto; - } - } - - .SocialMediaLinks { - display: flex; - - a { - display: flex; - flex: none; - justify-content: center; - align-items: center; - height: 44px; - width: 44px; - border-radius: 4px; - margin-right: $default-spacing * 2; - background-color: $color-medium-blue; - color: inherit; - text-decoration: none; - } - } -} - -.Copyright { - display: flex; - justify-content: center; - align-items: center; - min-height: 60px; - padding: $default-spacing * 2; - background-color: $color-dark-blue; - color: #7a858f; - text-align: center; -} diff --git a/Examples/src/components/AppFooter/AppFooter.tsx b/Examples/src/components/AppFooter/AppFooter.tsx deleted file mode 100644 index 1da559861..000000000 --- a/Examples/src/components/AppFooter/AppFooter.tsx +++ /dev/null @@ -1,187 +0,0 @@ -import * as React from "react"; -import { - MENU_ITEMS_2D, - MENU_ITEMS_2D_ID, - MENU_ITEMS_3D, - MENU_ITEMS_3D_ID, - MENU_ITEMS_FEATURED_APPS, - MENU_ITEMS_FEATURED_APPS_ID, -} from "../AppRouter/examples"; -import FooterGrid from "./FooterGrid"; -import { useNavigate } from "react-router"; -import classes from "./AppFooter.module.scss"; -import FacebookIcon from "@mui/icons-material/Facebook"; -import YouTubeIcon from "@mui/icons-material/YouTube"; -import LinkedInIcon from "@mui/icons-material/LinkedIn"; -import TwitterIcon from "@mui/icons-material/Twitter"; -import Button from "@mui/material/Button"; -import { libraryVersion } from "scichart"; - -export type TFooterlink = { - link: string; - text: string; -}; - -export default function AppFooter() { - const navigate = useNavigate(); - - const historyPushPath = (path: string) => { - if (!path) return; - navigate(path); - }; - - return ( - <> -
- {/* // removing this section from the footer */} - {/* - - */} - -
-
- SciChart Ltd, 16 Beaufort Court, Admirals Way, Docklands, London, E14 9XL. -
- - ); -} diff --git a/Examples/src/components/AppFooter/CommonFooterStyles.module.scss b/Examples/src/components/AppFooter/CommonFooterStyles.module.scss deleted file mode 100644 index 9ef44eb6c..000000000 --- a/Examples/src/components/AppFooter/CommonFooterStyles.module.scss +++ /dev/null @@ -1,44 +0,0 @@ -.divider { - position: relative; - border-bottom: 1px solid $color-dark-blue; - margin-bottom: 16px; -} - -.dividerBox { - position: absolute; - left: 0; - width: 30px; - height: 3px; - background-color: $color-medium-blue; -} - -%CommonLinkStyles { - a { - display: block; - color: $color-primary-grey; - text-decoration: none; - margin-bottom: 18px; - font-weight: 500; - font-size: 16px; - line-height: 24px; - cursor: pointer; - - @include sm { - font-size: 14px; - line-height: 22px; - } - } -} - -%CommonFooterGridConfigs { - display: grid; - grid-template-columns: repeat(4, 1fr); - - @include sm{ - grid-template-columns: repeat(2, 1fr); - } - - @include xs{ - grid-template-columns: 1fr; - } -} diff --git a/Examples/src/components/AppFooter/FooterGrid.module.scss b/Examples/src/components/AppFooter/FooterGrid.module.scss deleted file mode 100644 index ff28bd475..000000000 --- a/Examples/src/components/AppFooter/FooterGrid.module.scss +++ /dev/null @@ -1,58 +0,0 @@ -@import "../../assets/main.scss"; -@import "./CommonFooterStyles.module.scss"; - -.FooterGrid { - &:not(:last-child) { - .GridListContainer { - @extend %CommonFooterGridConfigs; - } - } - - &:not(:first-child) { - .GridListContainer { - @extend %CommonFooterGridConfigs; - - grid-template-rows: repeat(3, 1fr); - - @include xs{ - grid-template-rows: unset; - } - } - } -} - -.TitleBox { - padding: 40px 40px 0 40px; - - @include sm { - padding: 40px 16px 0 16px; - } -} - -.FooterGridList { - @extend %CommonLinkStyles; - - padding: 0 40px; - - &:first-child { - grid-row-end: span 3; - } - - &:first-child:last-child { - grid-column-end: span 4; - } - - @include sm{ - padding: 0 16px; - - &:first-child { - grid-row-end: span 5; - } - - &:nth-child(6) { - grid-row-start: 6; - grid-column-start: 1; - } - } - -} diff --git a/Examples/src/components/AppFooter/FooterGrid.tsx b/Examples/src/components/AppFooter/FooterGrid.tsx deleted file mode 100644 index 670893249..000000000 --- a/Examples/src/components/AppFooter/FooterGrid.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import * as React from "react"; -import List from "@mui/material/List"; -import { TMenuItem } from "../AppRouter/examples"; -import { Grid } from "@mui/material"; -import Box from "../../helpers/shared/Helpers/Box/Box"; -import classes from "./FooterGrid.module.scss"; -import { useContext } from "react"; -import { FrameworkContext } from "../../helpers/shared/Helpers/FrameworkContext"; -import { getFrameworkContent } from "../../helpers/shared/Helpers/frameworkParametrization"; - -type TProps = { - historyPushPath: (path: string) => void; - title: string; - menuItems: TMenuItem[]; - menuItemsId: string; -}; - -const FooterGrid: React.FC = (props) => { - const { title, menuItems } = props; - const framework = useContext(FrameworkContext); - - return ( - - -
{title}
-
-
-
-
- - - {menuItems.map((el) => ( -
-
{el.title}
- - - - {el.submenu.map((subEl) => ( - - {getFrameworkContent(subEl.title, framework)} - - ))} - - -
- ))} -
-
- ); -}; - -export default FooterGrid; diff --git a/Examples/src/components/AppFooter/GENERATED_FOOTER_LINKS.ts b/Examples/src/components/AppFooter/GENERATED_FOOTER_LINKS.ts deleted file mode 100644 index 5bdefec21..000000000 --- a/Examples/src/components/AppFooter/GENERATED_FOOTER_LINKS.ts +++ /dev/null @@ -1,120 +0,0 @@ -export const FOOTER_LINKS = [ - { link: "data-animation", text: "JavaScript Chart Data Animation" }, - { link: "style-animation", text: "JavaScript Style Animation" }, - { link: "startup-animation", text: "JavaScript Startup Animation" }, - { link: "generic-animation", text: "JavaScript Generic Animation" }, - { link: "band-chart", text: "JavaScript Band Chart" }, - { link: "spline-band-chart", text: "JavaScript Spline Band Chart" }, - { link: "digital-band-chart", text: "JavaScript Digital Band Chart" }, - { link: "fan-chart", text: "JavaScript Fan Chart" }, - { link: "bubble-chart", text: "JavaScript Bubble Chart" }, - { link: "candlestick-chart", text: "JavaScript Candlestick Chart" }, - { link: "ohlc-chart", text: "JavaScript OHLC Chart" }, - { link: "error-bars-chart", text: "JavaScript Error Bars Chart" }, - { link: "column-chart", text: "JavaScript Column Chart" }, - { link: "impulse-chart", text: "JavaScript Impulse Chart" }, - { link: "heatmap-chart", text: "JavaScript Heatmap Chart" }, - { link: "non-uniform-heatmap-chart", text: "JavaScript Non Uniform Heatmap Chart" }, - { link: "heatmap-chart-with-contours", text: "JavaScript Heatmap Chart With Contours" }, - { link: "line-chart", text: "JavaScript Line Chart" }, - { link: "spline-line-chart", text: "JavaScript Spline Line Chart" }, - { link: "digital-line-chart", text: "JavaScript Digital Line Chart" }, - { link: "mountain-chart", text: "JavaScript Mountain Chart" }, - { link: "spline-mountain-chart", text: "JavaScript Spline Mountain Chart" }, - { link: "digital-mountain-chart", text: "JavaScript Digital Mountain Chart" }, - { link: "scatter-chart", text: "JavaScript Scatter Chart" }, - { link: "donut-chart", text: "JavaScript Donut Chart" }, - { link: "pie-chart", text: "JavaScript Pie Chart" }, - { link: "realtime-mountain-chart", text: "JavaScript Realtime Mountain Chart" }, - { link: "text-chart", text: "JavaScript Text Chart" }, - { link: "chart-annotations", text: "JavaScript Chart Annotations" }, - { link: "annotation-layers", text: "JavaScript Chart Annotation Layers" }, - { link: "editable-annotations", text: "JavaScript Chart Editable Annotations" }, - { link: "stock-chart-buy-sell-markers", text: "JavaScript Chart Hoverable Buy Sell Marker Annotations" }, - { link: "chart-drag-horizontal-threshold", text: "JavaScript Chart Drag Horizontal Threshold" }, - { link: "chart-background-annotations", text: "JavaScript Quadrant Chart using Background Annotations" }, - { link: "realtime-ghosted-traces-chart", text: "Realtime Ghosted Traces" }, - { link: "chart-performance-load-one-million-points", text: "Load 1 Million Points Performance Demo" }, - { - link: "multi-pane-stock-charts-sync-technique", - text: "JavaScript Multi-Pane Stock Charts using Sync Multi-Chart", - }, - { link: "realtime-ticking-stock-charts", text: "JavaScript Realtime Ticking Stock Charts" }, - { link: "multi-pane-stock-charts", text: "JavaScript Multi-Pane Stock Charts using Subcharts" }, - { link: "depth-chart", text: "JavaScript Market Depth Chart" }, - { link: "user-annotated-stock-chart", text: "JavaScript User Annotated Stock Chart" }, - { link: "chart-legends", text: "Chart Legends API" }, - { link: "chart-with-multiple-x-axis", text: "JavaScript Chart with Multiple X Axes" }, - { link: "chart-with-secondary-y-axis", text: "JavaScript Chart with Secondary Y Axes" }, - { link: "vertical-charts", text: "JavaScript Vertical Charts" }, - { link: "central-axes", text: "JavaScript Chart with Central Axes" }, - { link: "static-x-axis", text: "JavaScript Chart with Static X Axis" }, - { link: "vertically-stacked-axes", text: "JavaScript Chart with Vertically Stacked Axes" }, - { link: "chart-logarithmic-axis", text: "JavaScript Chart with Logarithmic Axis Example" }, - { link: "draw-behind-axes", text: "Draw JavaScript Chart Behind Axis" }, - { link: "multiline-labels", text: "Multi-line and Rotated Text labels" }, - { link: "image-labels", text: "Image labels" }, - { link: "rotated-labels", text: "Rotated Labels and Alignment" }, - { link: "stacked-column-chart", text: "JavaScript Stacked Column Chart" }, - { link: "stacked-grouped-column-chart-side-by-side", text: "JavaScript Stacked Column Side by Side" }, - { link: "stacked-mountain-chart", text: "JavaScript Stacked Mountain Chart" }, - { link: "smooth-stacked-mountain-chart", text: "JavaScript Smooth Stacked Mountain Chart" }, - { link: "chart-custom-pointmarkers", text: "JavaScript Point-Markers Chart" }, - { link: "chart-themes", text: "Using Theme Manager in JavaScript Chart" }, - { link: "chart-custom-themes", text: "Create a Custom Theme for JavaScript Chart" }, - { link: "chart-styling-theming-in-code", text: "Styling a JavaScript Chart in Code" }, - { - link: "chart-color-points-individually-with-paletteprovider", - text: "Coloring Series per-point using the PaletteProvider", - }, - { link: "dashed-line-chart", text: "Dashed Line Styling" }, - { link: "chart-transparent-background", text: "Background Image with Transparency" }, - { link: "datalabels", text: "Data Labels" }, - { link: "multi-style-series", text: "JavaScript Chart with Multi-Style Series" }, - { link: "chart-hit-test-on-click", text: "JavaScript Chart Hit-Test API" }, - { link: "chart-rollovermodifier-tooltips", text: "Using Rollover Modifier Tooltips" }, - { link: "chart-cursormodifier-crosshairs", text: "Using CursorModifier Crosshairs" }, - { link: "chart-metadata", text: "Datapoint Metadata Tooltips on JavaScript Chart" }, - { link: "datapoint-selection", text: "JavaScript Chart Data Point Selection" }, - { link: "chart-series-selection", text: "Using Series Selection" }, - { link: "chart-vertical-slice-modifier", text: "Using VerticalSliceModifier" }, - { link: "chart-drag-axis-to-scale-pan", text: "Drag JavaScript Chart Axis to Scale or Pan" }, - { link: "zoom-pan-realtime-javascript-chart", text: "Zoom and Pan a Realtime JavaScript Chart" }, - { link: "zoom-pan-multiple-modifiers", text: "Zoom and Pan with JavaScript Chart multiple Modifiers" }, - { link: "overview", text: "Zoom and Pan with Overview Chart" }, - { link: "chart-with-virtualized-data", text: "Virtualized JavaScript Charts: Load Data on Zoom/Pan" }, - { link: "percentage-change", text: "Realtime Percentage Change using Filter" }, - { link: "trend-ma-ratio", text: "Trendline, Moving Average and Ratio Filters" }, - { link: "custom-filters", text: "Custom Filters" }, - { link: "sync-multi-chart", text: "Synchronise Multiple Charts" }, - { link: "3d-bubble-chart", text: "JavaScript 3D Bubble Chart" }, - { link: "3d-surface-mesh-chart", text: "JavaScript Surface Mesh 3D Chart" }, - { link: "realtime-3d-surface-mesh-chart", text: "JavaScript Realtime Surface Mesh 3D Chart" }, - { link: "3d-point-line-chart", text: "JavaScript Point Line 3D Chart" }, - { link: "load-500-series-x-500-points-performance-demo", text: "Load 500 Series x 500 Points Performance Demo" }, - { link: "chart-realtime-performance-demo", text: "Realtime JavaScript Chart Performance Demo" }, - { link: "vital-signs-ecg-medical-chart-example", text: "JavaScript Vital Signs ECG/EKG Medical Demo" }, - { link: "axis-types", text: "Axis Types" }, - { link: "chart-axis-layout-options", text: "JavaScript Chart Axis Layout Options" }, - { link: "chart-title", text: "JavaScript Chart Title" }, - { link: "multiple-chart-dashboard-performance-demo", text: "JavaScript 64-Chart Dashboard Performance Demo" }, - { link: "3d-lidar-visualization", text: "LiDAR 3D Point Cloud of Geospatial Data" }, - { link: "audio-analyzer-fft-example", text: "Realtime Audio Analyzer Demo" }, - { link: "interactive-waterfall-chart", text: "Interactive Waterfall Spectral Chart" }, - { link: "2d-3d-chart-tenor-curves-example", text: "Tenor Curves Demo" }, - { link: "chart-websocket-bigdata-demo", text: "Client/Server Websocket Data Streaming" }, - { link: "server-traffic-dashboard", text: "Server Traffic Dashboard" }, - { link: "oil-and-gas-dashboard-showcase", text: "Oil & Gas Explorer JavaScript Dashboard" }, - { link: "heatmap-interactions", text: "Rich Interactions Showcase" }, - { link: "dynamic-layout", text: "Dynamic Layout Showcase" }, - { link: "dragabble-event-markers", text: "Dragabble Event Markers" }, - { link: "population-pyramid", text: "JavaScript Population Pyramid" }, - { link: "builder-simple", text: "Simple Chart using Builder API" }, - { link: "builder-full", text: "Full Chart using Builder API" }, - { link: "chart-from-json", text: "Chart from JSON" }, - { - link: "reusable-templates-using-shared-data", - text: "JavaScript Chart with Reusable Templates using Shared Data", - }, - { link: "custom-types", text: "Custom Types with Builder API" }, -]; diff --git a/Examples/src/components/AppRouter/AppRouter.tsx b/Examples/src/components/AppRouter/AppRouter.tsx deleted file mode 100644 index ab7066f9b..000000000 --- a/Examples/src/components/AppRouter/AppRouter.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { memo, ReactNode, useContext } from "react"; -import { Routes, Route, Navigate, useSearchParams } from "react-router"; -import PageHome from "../PageHome/PageHome"; -import { EXAMPLES_PAGES, TExamplePage } from "./examplePages"; -import ExamplesRoot from "../Examples/ExamplesRoot"; -import { getExampleComponent } from "./examples"; -import classes from "../Examples/styles/Examples.module.scss"; -import { GalleryItem } from "../../helpers/types/types"; -import NoIndexTag from "../SeoTags/NoIndexTag"; -// import { InfoToolbar } from "../Examples/Toolbar"; -import { FrameworkContext } from "../../helpers/shared/Helpers/FrameworkContext"; -import ChartControlWrapper from "./ChartControlWrapper"; - -type TProps = { - currentExample: TExamplePage; - isIFrame?: boolean; - seeAlso: GalleryItem[]; -}; - -const examplePagesKeys = Object.keys(EXAMPLES_PAGES); - -const ExampleComponent = memo(ChartControlWrapper); - -export default function AppRouter(props: TProps) { - const { currentExample, seeAlso, isIFrame = false } = props; - const selectedFramework = useContext(FrameworkContext); - - if (isIFrame) { - const ChartComponent = getExampleComponent(currentExample.id); - - return ( -
- - - {examplePagesKeys.map((key) => { - const exPage = EXAMPLES_PAGES[key]; - return ( - - - - } - /> - ); - })} - -
- ); - } else { - return ( - - {examplePagesKeys.map((key) => { - const exPage = EXAMPLES_PAGES[key]; - return ( - } - /> - ); - })} - - {currentExample ? ( - } - /> - ) : null} - - } /> - - ); - } -} diff --git a/Examples/src/components/AppRouter/ChartControlWrapper.tsx b/Examples/src/components/AppRouter/ChartControlWrapper.tsx deleted file mode 100644 index 5b2bd8170..000000000 --- a/Examples/src/components/AppRouter/ChartControlWrapper.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { ReactNode } from "react"; -import { useSearchParams } from "react-router"; -import { IInitResult, SciChartGroup } from "scichart-react"; -// import { InfoToolbar } from "../Examples/Toolbar"; -import { TExamplePage } from "./examplePages"; -import { SciChartSurfaceBase } from "scichart"; - -export default function ChartControlWrapper(props: { children: ReactNode; examplePage: TExamplePage }) { - const [searchParams, setSearchParams] = useSearchParams(); - const hideToolbar = searchParams.get("hideToolbar") === "true"; - - return ( - <> - { - // capture when all charts within the group are rendered - // Promise.all( - // chartInitResults.map(({ sciChartSurface }) => { - // // only supported on 2D and 3D but on Pie surface - // if (sciChartSurface instanceof SciChartSurfaceBase) { - // // return sciChartSurface.nextStateRender(); - // } - // return null; - // }) - // ).then(() => { - // // consider all charts to be rendered - // }); - }} - > - {/* {!hideToolbar ? : null} */} - {props.children} - - - ); -} diff --git a/Examples/src/components/AppRouter/examplePages.ts b/Examples/src/components/AppRouter/examplePages.ts deleted file mode 100644 index 32b492f7b..000000000 --- a/Examples/src/components/AppRouter/examplePages.ts +++ /dev/null @@ -1,626 +0,0 @@ -import React from "react"; -import { bandSeriesChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/BandSeriesChart/exampleInfo"; -import { splineBandSeriesChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/SplineBandSeriesChart/exampleInfo"; -import { digitalBandSeriesChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/DigitalBandSeriesChart/exampleInfo"; -import { fanChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/FanChart/exampleInfo"; -import { bubbleChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/BubbleChart/exampleInfo"; -import { candlestickChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/CandlestickChart/exampleInfo"; -import { ohlcChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/OhlcChart/exampleInfo"; -import { columnChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/ColumnChart/exampleInfo"; -import { impulseChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/ImpulseChart/exampleInfo"; -import { errorBarsChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/ErrorBarsChart/exampleInfo"; -import { heatmapChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/HeatmapChart/exampleInfo"; -import { contourChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/ContoursChart/exampleInfo"; -import { lineChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/LineChart/exampleInfo"; -import { splineLineChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/SplineLineChart/exampleInfo"; -import { digitalLineChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/DigitalLineChart/exampleInfo"; -import { mountainChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/MountainChart/exampleInfo"; -import { splineMountainChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/SplineMountainChart/exampleInfo"; -import { digitalMountainChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/DigitalMountainChart/exampleInfo"; -import { scatterChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/ScatterChart/exampleInfo"; -import { donutChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/DonutChart/exampleInfo"; -import { pieChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/PieChart/exampleInfo"; -import { realTimeMountainChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/RealTimeMountainChart/exampleInfo"; -import { annotationsAreEasyExampleInfo } from "../Examples/Charts2D/ChartAnnotations/AnnotationsAreEasy/exampleInfo"; -import { annotationLayersExampleInfo } from "../Examples/Charts2D/ChartAnnotations/AnnotationLayers/exampleInfo"; -import { tradeMarkerAnnotationsExampleInfo } from "../Examples/Charts2D/ChartAnnotations/TradeMarkers/exampleInfo"; -import { realtimeGhostedTracesExampleInfo } from "../Examples/FeaturedApps/PerformanceDemos/RealtimeGhostedTraces/exampleInfo"; -import { multiPaneStockChartsExampleInfo } from "../Examples/Charts2D/CreateStockCharts/MultiPaneStockCharts/exampleInfo"; -import { realtimeTickingStockChartsExampleInfo } from "../Examples/Charts2D/CreateStockCharts/RealtimeTickingStockCharts/exampleInfo"; -import { chartLegendsAPIExampleInfo } from "../Examples/Charts2D/Legends/ChartLegendsAPI/exampleInfo"; -import { multipleXAxesExampleInfo } from "../Examples/Charts2D/ModifyAxisBehavior/MultipleXAxes/exampleInfo"; -import { secondaryYAxesExampleInfo } from "../Examples/Charts2D/ModifyAxisBehavior/SecondaryYAxes/exampleInfo"; -import { verticalChartsExampleInfo } from "../Examples/Charts2D/ModifyAxisBehavior/VerticalCharts/exampleInfo"; -import { centralAxesExampleInfo } from "../Examples/Charts2D/ModifyAxisBehavior/CentralAxes/exampleInfo"; -import { staticAxisExampleInfo } from "../Examples/Charts2D/ModifyAxisBehavior/StaticAxis/exampleInfo"; -import { verticallyStackedAxesExampleInfo } from "../Examples/Charts2D/ModifyAxisBehavior/VerticallyStackedAxes/exampleInfo"; -import { stackedColumnChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/StackedColumnChart/exampleInfo"; -import { stackedColumnSideBySideExampleInfo } from "../Examples/Charts2D/BasicChartTypes/StackedColumnSideBySide/exampleInfo"; -import { stackedMountainChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/StackedMountainChart/exampleInfo"; -import { usePointMarkersExampleInfo } from "../Examples/Charts2D/StylingAndTheming/UsePointMarkers/exampleInfo"; -import { usingThemeManagerExampleInfo } from "../Examples/Charts2D/StylingAndTheming/UsingThemeManager/exampleInfo"; -import { createACustomThemeExampleInfo } from "../Examples/Charts2D/StylingAndTheming/CreateACustomTheme/exampleInfo"; -import { stylingInCodeExampleInfo } from "../Examples/Charts2D/StylingAndTheming/StylingInCode/exampleInfo"; -import { perPointColoringExampleInfo } from "../Examples/Charts2D/StylingAndTheming/PerPointColoring/exampleInfo"; -import { dashedLineStylingExampleInfo } from "../Examples/Charts2D/StylingAndTheming/DashedLineStyling/exampleInfo"; -import { transparentBackgroundExampleInfo } from "../Examples/Charts2D/StylingAndTheming/TransparentBackground/exampleInfo"; -import { hitTestApiExampleInfo } from "../Examples/Charts2D/TooltipsAndHittest/HitTestAPI/exampleInfo"; -import { usingRolloverModifierTooltipsExampleInfo } from "../Examples/Charts2D/TooltipsAndHittest/UsingRolloverModifierTooltips/exampleInfo"; -import { seriesSelectionExampleInfo } from "../Examples/Charts2D/TooltipsAndHittest/SeriesSelection/exampleInfo"; -import { usingCursorModifierTooltipsExampleInfo } from "../Examples/Charts2D/TooltipsAndHittest/UsingCursorModifierTooltips/exampleInfo"; -import { bubble3DChartExampleInfo } from "../Examples/Charts3D/Basic3DChartTypes/Bubble3DChart/exampleInfo"; -import { surfaceMesh3DChartExampleInfo } from "../Examples/Charts3D/Basic3DChartTypes/SurfaceMesh3DChart/exampleInfo"; -import { pointLine3DChartExampleInfo } from "../Examples/Charts3D/Basic3DChartTypes/PointLine3DChart/exampleInfo"; -import { load500By500ExampleInfo } from "../Examples/FeaturedApps/PerformanceDemos/Load500By500/exampleInfo"; -import { realtimePerformanceDemoExampleInfo } from "../Examples/FeaturedApps/PerformanceDemos/RealtimePerformanceDemo/exampleInfo"; -import { vitalSignsMonitorDemoExampleInfo } from "../Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/exampleInfo"; -import { lidar3DPointCloudExampleInfo } from "../Examples/FeaturedApps/ScientificCharts/LiDAR3DPointCloudDemo/exampleInfo"; -import { audioAnalyzerExampleInfo } from "../Examples/FeaturedApps/ScientificCharts/AudioAnalyzer/exampleInfo"; -import { waterfallChartExampleInfo } from "../Examples/FeaturedApps/ScientificCharts/InteractiveWaterfallChart/exampleInfo"; -import { TPage } from "./pages"; -import { tenorCurvesExampleInfo } from "../Examples/FeaturedApps/ScientificCharts/TenorCurves3D/exampleInfo"; -import { loadOneMillionPointsExampleInfo } from "../Examples/FeaturedApps/PerformanceDemos/Load1MillionPoints/exampleInfo"; -import { dragAxisToScaleExampleInfo } from "../Examples/Charts2D/ZoomingAndPanning/DragAxisToScale/exampleInfo"; -import { realtimeZoomPanExampleInfo } from "../Examples/Charts2D/ZoomingAndPanning/RealtimeZoomPan/exampleInfo"; -import { zoomAndPanWithMultipleChartModifiersExampleInfo } from "../Examples/Charts2D/ZoomingAndPanning/MultipleZoomPanModifiers/exampleInfo"; -import { editableAnnotationsExampleInfo } from "../Examples/Charts2D/ChartAnnotations/EditableAnnotations/exampleInfo"; -import { EPageLayout, GalleryItem } from "../../helpers/types/types"; -import { dragHorizontalThresholdExampleInfo } from "../Examples/Charts2D/ChartAnnotations/DragHorizontalThreshold/exampleInfo"; -import { metaDataExampleInfo } from "../Examples/Charts2D/TooltipsAndHittest/MetaData/exampleInfo"; -import { logarithmicAxisExampleInfo } from "../Examples/Charts2D/ModifyAxisBehavior/LogarithmicAxis/exampleInfo"; -import { simpleChartExampleInfo } from "../Examples/BuilderApi/SimpleChart/exampleInfo"; -import { fullChartExampleInfo } from "../Examples/BuilderApi/FullChart/exampleInfo"; -import { chartFromJSONExampleInfo } from "../Examples/BuilderApi/ChartFromJSON/exampleInfo"; -import { sharedDataExampleInfo } from "../Examples/BuilderApi/SharedData/exampleInfo"; -import { customTypesExampleInfo } from "../Examples/BuilderApi/CustomTypes/exampleInfo"; -import { multiLineLabelsExampleInfo } from "../Examples/Charts2D/AxisLabelCustomization/MultiLineLabels/exampleInfo"; -import { imageLabelsExampleInfo } from "../Examples/Charts2D/AxisLabelCustomization/ImageLabels/exampleInfo"; -import { rotatedLabelsExampleInfo } from "../Examples/Charts2D/AxisLabelCustomization/RotatedLabels/exampleInfo"; -import { percentageChangeExampleInfo } from "../Examples/Charts2D/Filters/PercentageChange/exampleInfo"; -import { trendMARatioExampleInfo } from "../Examples/Charts2D/Filters/TrendMARatio/exampleInfo"; -import { customFiltersExampleInfo } from "../Examples/Charts2D/Filters/CustomFilters/exampleInfo"; -import { dataAnimationExampleInfo } from "../Examples/Charts2D/Animations/DataAnimation/exampleInfo"; -import { styleAnimationExampleInfo } from "../Examples/Charts2D/Animations/StyleAnimation/exampleInfo"; -import { startupAnimationExampleInfo } from "../Examples/Charts2D/Animations/StartupAnimation/exampleInfo"; -import { dataPointSelectionExampleInfo } from "../Examples/Charts2D/TooltipsAndHittest/DatapointSelection/exampleInfo"; -import { overviewExampleInfo } from "../Examples/Charts2D/ZoomingAndPanning/OverviewModifier/exampleInfo"; -import { genericAnimationExampleInfo } from "../Examples/Charts2D/Animations/GenericAnimation/exampleInfo"; -import { drawBehindAxesExampleInfo } from "../Examples/Charts2D/ModifyAxisBehavior/DrawBehindAxes/exampleInfo"; -import { nonUniformHeatmapExampleInfo } from "../Examples/Charts2D/BasicChartTypes/NonUniformHeatmapChart/exampleInfo"; -import { axisTypesExampleInfo } from "../Examples/FeaturedApps/FeatureDemos/AxisTypes/exampleInfo"; -import { subChartStockChartsExampleInfo } from "../Examples/Charts2D/CreateStockCharts/SubChartStockCharts/exampleInfo"; -import { axisLayoutExampleInfo } from "../Examples/FeaturedApps/FeatureDemos/AxisLayout/exampleInfo"; -import { subchartsGridExampleInfo } from "../Examples/FeaturedApps/FeatureDemos/SubChartsAPI/exampleInfo"; -import { websocketBigDataDemoExampleInfo } from "../Examples/FeaturedApps/ShowCases/WebsocketBigData/exampleInfo"; -import { serverTrafficDashboardDemoExampleInfo } from "../Examples/FeaturedApps/ShowCases/ServerTrafficDashboard/exampleInfo"; -import { oilAndGasExplorerDashboard } from "../Examples/FeaturedApps/ShowCases/OilAndGasDashboard/exampleInfo"; -import { TDocumentationLink } from "../../helpers/types/ExampleDescriptionTypes"; -import { datalabelsExampleInfo } from "../Examples/Charts2D/StylingAndTheming/DataLabels/exampleInfo"; -import { virtualizedDataOverviewExampleInfo } from "../Examples/Charts2D/ZoomingAndPanning/VirtualizedDataWithOverview/exampleInfo"; -import { heatmapInteractionsExampleInfo } from "../Examples/FeaturedApps/ShowCases/HeatmapInteractions/exampleInfo"; -import { depthChartExampleInfo } from "../Examples/Charts2D/CreateStockCharts/DepthChart/exampleInfo"; -import { textChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/TextSeriesChart/exampleInfo"; -import { chartTitleExampleInfo } from "../Examples/FeaturedApps/FeatureDemos/ChartTitle/exampleInfo"; -import { backgroundAnnotationsExampleInfo } from "../Examples/Charts2D/ChartAnnotations/BackgroundAnnotations/exampleInfo"; -import { realtimeSurfaceMesh3DChartExampleInfo } from "../Examples/Charts3D/Basic3DChartTypes/RealtimeSurfaceMesh3DChart/exampleInfo"; -import { dynamicLayoutExampleInfo } from "../Examples/FeaturedApps/ShowCases/DynamicLayout/exampleInfo"; -import { usingVerticalSliceModifierExampleInfo } from "../Examples/Charts2D/TooltipsAndHittest/UsingVerticalSliceModifier/exampleInfo"; -import { syncMultiChartExampleInfo } from "../Examples/Charts2D/MultiChart/SyncMultiChart/exampleInfo"; -import { eventMarkersExampleInfo } from "../Examples/FeaturedApps/ShowCases/EventMarkers/exampleInfo"; -import { multiplePointMarkersExampleInfo } from "../Examples/Charts2D/StylingAndTheming/MultiStyleSeries/exampleInfo"; -import { populationPyramidExampleInfo } from "../Examples/FeaturedApps/ShowCases/PopulationPyramid/exampleInfo"; -import { TFrameworkTemplate } from "../../helpers/shared/Helpers/frameworkParametrization"; -import { userAnnotatedStockChartExampleInfo } from "../Examples/Charts2D/CreateStockCharts/UserAnnotatedStockChart/exampleInfo"; -import { smoothStackedMountainChartExampleInfo } from "../Examples/Charts2D/BasicChartTypes/SmoothStackedMountainChart/exampleInfo"; -import { lineSplittingThresholdsExampleInfo } from "../Examples/Charts2D/StylingAndTheming/LineSplittingThresholds/exampleInfo"; -import { column3DChartExampleInfo } from "../Examples/Charts3D/Basic3DChartTypes/Column3DChart/exampleInfo"; - -import type { JSX } from "react"; - -export type TExampleInfo = { - /** - * Example title - */ - title: TFrameworkTemplate; - /** - * Meta title - */ - pageTitle: TFrameworkTemplate; - path: string; - - /** - * Content shown below title on example page - */ - subtitle: (frameworkName: string) => React.ReactElement | string; - /** - * Page meta description - */ - metaDescription: TFrameworkTemplate; - - /** - * The first link is used in the docs button in the header - */ - documentationLinks: TDocumentationLink[]; - - // If this example has been created on scichart.com - onWebsite?: boolean; - /** - * OPTIONAL: If provided, use these items as a See Also. If not, they will be auto-generated from similar items - * in the top level menu. See {@link getSeeAlsoGalleryItems} - */ - seeAlso?: GalleryItem[]; - - /** - * Page meta keywords - */ - metaKeywords: string; - thumbnailImage?: string; - // path to actual folder for CodeSandbox - filepath: string; - // additional module dependencies - extraDependencies?: Record; - codeSandBoxNotWorking?: boolean; - sandboxConfig?: Record; - /** - * Markdown content for the page, will help with SEO and editing - */ - markdownContent?: TFrameworkTemplate; - pageLayout?: EPageLayout; -}; - -export type TExamplePage = TPage & TExampleInfo; - -function asRecord>(arg: T): T & Record { - return arg; -} - -export const EXAMPLES_PAGES = asRecord({ - chart2D_Animations_DataAnimation: { - id: "chart2D_Animations_DataAnimation", - ...dataAnimationExampleInfo, - }, - chart2D_Animations_StyleAnimation: { - id: "chart2D_Animations_StyleAnimation", - ...styleAnimationExampleInfo, - }, - chart2D_Animations_StartupAnimation: { - id: "chart2D_Animations_StartupAnimation", - ...startupAnimationExampleInfo, - }, - chart2D_Animations_GenericAnimation: { - id: "chart2D_Animations_GenericAnimation", - ...genericAnimationExampleInfo, - }, - chart2D_basicCharts_BandSeriesChart: { - id: "chart2D_basicCharts_BandSeriesChart", - ...bandSeriesChartExampleInfo, - }, - chart2D_basicCharts_SplineBandChart: { - id: "chart2D_basicCharts_SplineBandChart", - ...splineBandSeriesChartExampleInfo, - }, - chart2D_basicCharts_DigitalBandSeriesChart: { - id: "chart2D_basicCharts_DigitalBandSeriesChart", - ...digitalBandSeriesChartExampleInfo, - }, - chart2D_basicCharts_FanChart: { - id: "chart2D_basicCharts_FanChart", - ...fanChartExampleInfo, - }, - chart2D_basicCharts_BubbleChart: { - id: "chart2D_basicCharts_BubbleChart", - ...bubbleChartExampleInfo, - }, - chart2D_basicCharts_CandlestickChart: { - id: "chart2D_basicCharts_CandlestickChart", - ...candlestickChartExampleInfo, - }, - chart2D_basicCharts_OhlcChart: { - id: "chart2D_basicCharts_OhlcChart", - ...ohlcChartExampleInfo, - }, - chart2D_basicCharts_ErrorBarsChart: { - id: "chart2D_basicCharts_ErrorBarsChart", - ...errorBarsChartExampleInfo, - }, - chart2D_basicCharts_ColumnChart: { - id: "chart2D_basicCharts_ColumnChart", - ...columnChartExampleInfo, - }, - chart2D_basicCharts_ImpulseChart: { - id: "chart2D_basicCharts_ImpulseChart", - ...impulseChartExampleInfo, - }, - chart2D_basicCharts_HeatmapChart: { - id: "chart2D_basicCharts_HeatmapChart", - ...heatmapChartExampleInfo, - }, - chart2D_basicCharts_NonUniformHeatmapChart: { - id: "chart2D_basicCharts_NonUniformHeatmapChart", - ...nonUniformHeatmapExampleInfo, - }, - chart2D_basicCharts_ContourChart: { - id: "chart2D_basicCharts_ContourChart", - ...contourChartExampleInfo, - }, - chart2D_basicCharts_LineChart: { - id: "chart2D_basicCharts_LineChart", - ...lineChartExampleInfo, - }, - chart2D_basicCharts_SplineLineChart: { - id: "chart2D_basicCharts_SplineLineChart", - ...splineLineChartExampleInfo, - }, - chart2D_basicCharts_DigitalLineChart: { - id: "chart2D_basicCharts_DigitalLineChart", - ...digitalLineChartExampleInfo, - }, - chart2D_basicCharts_MountainChart: { - id: "chart2D_basicCharts_MountainChart", - ...mountainChartExampleInfo, - }, - chart2D_basicCharts_SplineMountainChart: { - id: "chart2D_basicCharts_SplineMountainChart", - ...splineMountainChartExampleInfo, - }, - chart2D_basicCharts_DigitalMountainChart: { - id: "chart2D_basicCharts_DigitalMountainChart", - ...digitalMountainChartExampleInfo, - }, - chart2D_basicCharts_ScatterChart: { - id: "chart2D_basicCharts_ScatterChart", - ...scatterChartExampleInfo, - }, - chart2D_basicCharts_DonutChart: { - id: "chart2D_basicCharts_DonutChart", - ...donutChartExampleInfo, - }, - chart2D_basicCharts_PieChart: { - id: "chart2D_basicCharts_PieChart", - ...pieChartExampleInfo, - }, - chart2D_basicCharts_RealtimeMountainChart: { - id: "chart2D_basicCharts_RealtimeMountainChart", - ...realTimeMountainChartExampleInfo, - }, - chart2D_basicCharts_TextChart: { - id: "chart2D_basicCharts_TextChart", - ...textChartExampleInfo, - }, - chart2D_chartAnnotations_AnnotationsAreEasy: { - id: "chart2D_chartAnnotations_AnnotationsAreEasy", - ...annotationsAreEasyExampleInfo, - }, - chart2D_chartAnnotations_AnnotationLayers: { - id: "chart2D_chartAnnotations_AnnotationLayers", - ...annotationLayersExampleInfo, - }, - chart2D_chartAnnotations_EditableAnntations: { - id: "chart2D_chartAnnotations_EditableAnntations", - ...editableAnnotationsExampleInfo, - }, - chart2D_chartAnnotations_TradeMarkers: { - id: "chart2D_chartAnnotations_TradeMarkers", - ...tradeMarkerAnnotationsExampleInfo, - }, - chart2D_chartAnnotations_DragHorizontalThreshold: { - id: "chart2D_chartAnnotations_DragHorizontalThreshold", - ...dragHorizontalThresholdExampleInfo, - }, - chart2D_chartAnnotations_BackgroundAnnotations: { - id: "chart2D_chartAnnotations_BackgroundAnnotations", - ...backgroundAnnotationsExampleInfo, - }, - featuredApps_performanceDemos_RealtimeGhostedTraces: { - id: "featuredApps_performanceDemos_RealtimeGhostedTraces", - ...realtimeGhostedTracesExampleInfo, - }, - featuredApps_performanceDemos_LoadOneMillionPoints: { - id: "featuredApps_performanceDemos_LoadOneMillionPoints", - ...loadOneMillionPointsExampleInfo, - }, - chart2D_createStockCharts_MultiPaneStockCharts: { - id: "chart2D_createStockCharts_MultiPaneStockCharts", - ...multiPaneStockChartsExampleInfo, - }, - chart2D_createStockCharts_RealtimeTickingStockCharts: { - id: "chart2D_createStockCharts_RealtimeTickingStockCharts", - ...realtimeTickingStockChartsExampleInfo, - }, - chart2D_createStockCharts_SubchartStockCharts: { - id: "chart2D_createStockCharts_SubchartStockCharts", - ...subChartStockChartsExampleInfo, - }, - chart2D_createStockCharts_DepthChart: { - id: "chart2D_createStockCharts_DepthChart", - ...depthChartExampleInfo, - }, - chart2D_createStockCharts_SharedChart: { - id: "chart2D_createStockCharts_SharedChart", - ...userAnnotatedStockChartExampleInfo, - }, - chart2D_legends_ChartLegendsAPI: { - id: "chart2D_legends_ChartLegendsAPI", - ...chartLegendsAPIExampleInfo, - }, - chart2D_modifyAxisBehavior_MultipleXAxes: { - id: "chart2D_modifyAxisBehavior_MultipleXAxes", - ...multipleXAxesExampleInfo, - }, - chart2D_modifyAxisBehavior_SecondaryYAxes: { - id: "chart2D_modifyAxisBehavior_SecondaryYAxes", - ...secondaryYAxesExampleInfo, - }, - chart2D_modifyAxisBehavior_VerticalCharts: { - id: "chart2D_modifyAxisBehavior_VerticalCharts", - ...verticalChartsExampleInfo, - }, - chart2D_modifyAxisBehavior_CentralAxes: { - id: "chart2D_modifyAxisBehavior_CentralAxes", - ...centralAxesExampleInfo, - }, - chart2D_modifyAxisBehavior_StaticAxis: { - id: "chart2D_modifyAxisBehavior_StaticAxis", - ...staticAxisExampleInfo, - }, - chart2D_modifyAxisBehavior_VerticallyStackedAxes: { - id: "chart2D_modifyAxisBehavior_VerticallyStackedAxes", - ...verticallyStackedAxesExampleInfo, - }, - chart2D_modifyAxisBehavior_LogarithmicAxis: { - id: "chart2D_modifyAxisBehavior_LogarithmicAxis", - ...logarithmicAxisExampleInfo, - }, - chart2D_modifyAxisBehavior_DrawBehindAxes: { - id: "chart2D_modifyAxisBehavior_DrawBehindAxes", - ...drawBehindAxesExampleInfo, - }, - chart2D_axisLabelCustomization_MultiLineLabels: { - id: "chart2D_axisLabelCustomization_MultiLineLabels", - ...multiLineLabelsExampleInfo, - }, - chart2D_axisLabelCustomization_ImageLabels: { - id: "chart2D_axisLabelCustomization_ImageLabels", - ...imageLabelsExampleInfo, - }, - chart2D_axisLabelCustomization_RotatedLabels: { - id: "chart2D_axisLabelCustomization_RotatedLabels", - ...rotatedLabelsExampleInfo, - }, - chart2D_basicCharts_StackedColumnChart: { - id: "chart2D_basicCharts_StackedColumnChart", - ...stackedColumnChartExampleInfo, - }, - chart2D_basicCharts_StackedColumnSideBySide: { - id: "chart2D_basicCharts_StackedColumnSideBySide", - ...stackedColumnSideBySideExampleInfo, - }, - chart2D_basicCharts_StackedMountainChart: { - id: "chart2D_basicCharts_StackedMountainChart", - ...stackedMountainChartExampleInfo, - }, - chart2D_basicCharts_SmoothStackedMountainChart: { - id: "chart2D_basicCharts_SmoothStackedMountainChart", - ...smoothStackedMountainChartExampleInfo, - }, - chart2D_stylingAndTheming_UsePointMarkers: { - id: "chart2D_stylingAndTheming_UsePointMarkers", - ...usePointMarkersExampleInfo, - }, - chart2D_stylingAndTheming_UsingThemeManager: { - id: "chart2D_stylingAndTheming_UsingThemeManager", - ...usingThemeManagerExampleInfo, - }, - chart2D_stylingAndTheming_CustomTheme: { - id: "chart2D_stylingAndTheming_CustomTheme", - ...createACustomThemeExampleInfo, - }, - chart2D_stylingAndTheming_StylingInCode: { - id: "chart2D_stylingAndTheming_StylingInCode", - ...stylingInCodeExampleInfo, - }, - chart2D_stylingAndTheming_PerPointColoring: { - id: "chart2D_stylingAndTheming_PerPointColoring", - ...perPointColoringExampleInfo, - }, - chart2D_stylingAndTheming_DashedLineStyling: { - id: "chart2D_stylingAndTheming_DashedLineStyling", - ...dashedLineStylingExampleInfo, - }, - chart2D_stylingAndTheming_TransparentBackground: { - id: "chart2D_stylingAndTheming_TransparentBackground", - ...transparentBackgroundExampleInfo, - }, - chart2D_stylingAndTheming_DataLabels: { - id: "chart2D_stylingAndTheming_DataLabels", - ...datalabelsExampleInfo, - }, - chart2D_stylingAndTheming_MultiplePointMarkers: { - id: "chart2D_stylingAndTheming_MultiplePointMarkers", - ...multiplePointMarkersExampleInfo, - }, - chart2D_stylingAndTheming_LineSplittingThresholds: { - id: "chart2D_stylingAndTheming_LineSplittingThresholds", - ...lineSplittingThresholdsExampleInfo, - }, - chart2D_tooltipsAndHittest_HitTestApi: { - id: "chart2D_tooltipsAndHittest_HitTestApi", - ...hitTestApiExampleInfo, - }, - chart2D_tooltipsAndHittest_UsingRolloverModifierTooltips: { - id: "chart2D_tooltipsAndHittest_UsingRolloverModifierTooltips", - ...usingRolloverModifierTooltipsExampleInfo, - }, - chart2D_tooltipsAndHittest_UsingCursorModifierTooltips: { - id: "chart2D_tooltipsAndHittest_UsingCursorModifierTooltips", - ...usingCursorModifierTooltipsExampleInfo, - }, - chart2D_tooltipsAndHittest_MetaData: { - id: "chart2D_tooltipsAndHittest_MetaData", - ...metaDataExampleInfo, - }, - chart2D_tooltipsAndHittest_DataPointSelection: { - id: "chart2D_tooltipsAndHittest_DataPointSelection", - ...dataPointSelectionExampleInfo, - }, - chart2D_tooltipsAndHittest_SeriesSelection: { - id: "chart2D_tooltipsAndHittest_SeriesSelection", - ...seriesSelectionExampleInfo, - }, - chart2D_tooltipsAndHittest_VerticalSliceModifier: { - id: "chart2D_tooltipsAndHittest_VerticalSliceModifier", - ...usingVerticalSliceModifierExampleInfo, - }, - chart2D_zoomAndPanAChart_DragAxisToScale: { - id: "chart2D_zoomAndPanAChart_DragAxisToScale", - ...dragAxisToScaleExampleInfo, - }, - chart2D_zoomAndPanAChart_RealtimeZoomPan: { - id: "chart2D_zoomAndPanAChart_RealtimeZoomPan", - ...realtimeZoomPanExampleInfo, - }, - chart2D_zoomAndPanAChart_MultipleChartModifiers: { - id: "chart2D_zoomAndPanAChart_MultipleChartModifiers", - ...zoomAndPanWithMultipleChartModifiersExampleInfo, - }, - chart2D_zoomAndPanAChart_Overview: { - id: "chart2D_zoomAndPanAChart_Overview", - ...overviewExampleInfo, - }, - chart2D_zoomAndPanAChart_VirtualizedDataOverview: { - id: "chart2D_zoomAndPanAChart_VirtualizedDataOverview", - ...virtualizedDataOverviewExampleInfo, - }, - // chart2D_zoomAndPanAChart_ZoomHighPrecision: { - // id: "chart2D_zoomAndPanAChart_ZoomHighPrecision", - // ...zoomHighPrecisionExampleInfo, - // }, - chart2D_filters_PercentageChange: { - id: "chart2D_filters_PercentageChange", - ...percentageChangeExampleInfo, - }, - chart2D_filters_TrendMARatio: { - id: "chart2D_filters_TrendMARatio", - ...trendMARatioExampleInfo, - }, - chart2D_filters_CustomFilters: { - id: "chart2D_filters_CustomFilters", - ...customFiltersExampleInfo, - }, - chart2D_multiChart_syncMultiChart: { - id: "chart2D_multiChart_syncMultiChart", - ...syncMultiChartExampleInfo, - }, - chart3D_basic3DChartTypes_Bubble3DChart: { - id: "chart3D_basic3DChartTypes_Bubble3DChart", - ...bubble3DChartExampleInfo, - }, - chart3D_basic3DChartTypes_SurfaceMesh3DChart: { - id: "chart3D_basic3DChartTypes_SurfaceMesh3DChart", - ...surfaceMesh3DChartExampleInfo, - }, - chart3D_basic3DChartTypes_RealtimeSurfaceMesh3DChart: { - id: "chart3D_basic3DChartTypes_RealtimeSurfaceMesh3DChart", - ...realtimeSurfaceMesh3DChartExampleInfo, - }, - chart3D_basic3DChartTypes_PointLine3DChart: { - id: "chart3D_basic3DChartTypes_PointLine3DChart", - ...pointLine3DChartExampleInfo, - }, - chart3D_basic3DChartTypes_Column3DChart: { - id: "chart3D_basic3DChartTypes_Column3DChart", - ...column3DChartExampleInfo, - }, - featuredApps_performanceDemos_Load500By500: { - id: "featuredApps_performanceDemos_Load500By500", - ...load500By500ExampleInfo, - }, - featuredApps_performanceDemos_RealtimePerformanceDemo: { - id: "featuredApps_performanceDemos_RealtimePerformanceDemo", - ...realtimePerformanceDemoExampleInfo, - }, - featuredApps_medicalCharts_VitalSignsMonitorDemo: { - id: "featuredApps_medicalCharts_VitalSignsMonitorDemo", - ...vitalSignsMonitorDemoExampleInfo, - }, - featuredApps_featureDemos_axisTypes: { - id: "featuredApps_featureDemos_axisTypes", - ...axisTypesExampleInfo, - }, - featuredApps_featureDemos_axisLayout: { - id: "featuredApps_featureDemos_axisLayout", - ...axisLayoutExampleInfo, - }, - featuredApps_featureDemos_chartTitle: { - id: "featuredApps_featureDemos_chartTitle", - ...chartTitleExampleInfo, - }, - featuredApps_featureDemos_subchartsGrid: { - id: "featuredApps_featureDemos_subchartsGrid", - ...subchartsGridExampleInfo, - }, - featuredApps_scientificCharts_Lidar3DPointCloudDemo: { - id: "featuredApps_scientificCharts_Lidar3DPointCloudDemo", - ...lidar3DPointCloudExampleInfo, - }, - featuredApps_scientificCharts_AudioAnalyzerDemo: { - id: "featuredApps_scientificCharts_AudioAnalyzerDemo", - ...audioAnalyzerExampleInfo, - }, - featuredApps_scientificCharts_WaterfallChartDemo: { - id: "featuredApps_scientificCharts_WaterfallChartDemo", - ...waterfallChartExampleInfo, - }, - featuredApps_scientificCharts_TenorCurvesDemo: { - id: "featuredApps_scientificCharts_TenorCurvesDemo", - ...tenorCurvesExampleInfo, - }, - featuredApps_showcases_realtimebigdata: { - id: "featuredApps_showcases_realtimebigdata", - ...websocketBigDataDemoExampleInfo, - }, - featuredApps_showcases_servertrafficdashboard: { - id: "featuredApps_showcases_servertrafficdashboard", - ...serverTrafficDashboardDemoExampleInfo, - }, - featuredApps_showcases_oilandgasdashboard: { - id: "featuredApps_showcases_oilandgasdashboard", - ...oilAndGasExplorerDashboard, - }, - featuredApps_showcases_richInteractions: { - id: "featuredApps_showcases_richInteractions", - ...heatmapInteractionsExampleInfo, - }, - featuredApps_showcases_dynamicLayout: { - id: "featuredApps_showcases_dynamicLayout", - ...dynamicLayoutExampleInfo, - }, - featuredApps_showcases_eventMarkers: { - id: "featuredApps_showcases_eventMarkers", - ...eventMarkersExampleInfo, - }, - featuredApps_showcases_populationPyramid: { - id: "featuredApps_showcases_populationPyramid", - ...populationPyramidExampleInfo, - }, - builderApi_simplechart: { - id: "builderApi_simplechart", - ...simpleChartExampleInfo, - }, - builderApi_fullchart: { - id: "builderApi_fullchart", - ...fullChartExampleInfo, - }, - builderApi_chartFromJSON: { - id: "builderApi_chartFromJSON", - ...chartFromJSONExampleInfo, - }, - builderApi_SharedData: { - id: "builderApi_SharedData", - ...sharedDataExampleInfo, - }, - builderApi_CustomTypes: { - id: "builderApi_CustomTypes", - ...customTypesExampleInfo, - }, -}); diff --git a/Examples/src/components/AppRouter/examples.ts b/Examples/src/components/AppRouter/examples.ts deleted file mode 100644 index 38742391c..000000000 --- a/Examples/src/components/AppRouter/examples.ts +++ /dev/null @@ -1,707 +0,0 @@ -import BandSeriesChart from "../Examples/Charts2D/BasicChartTypes/BandSeriesChart"; -import DigitalBandSeriesChart from "../Examples/Charts2D/BasicChartTypes/DigitalBandSeriesChart"; -import FanChart from "../Examples/Charts2D/BasicChartTypes/FanChart"; -import BubbleChart from "../Examples/Charts2D/BasicChartTypes/BubbleChart"; -import CandlestickChart from "../Examples/Charts2D/BasicChartTypes/CandlestickChart"; -import OhlcChart from "../Examples/Charts2D/BasicChartTypes/OhlcChart"; -import ColumnChart from "../Examples/Charts2D/BasicChartTypes/ColumnChart"; -import ImpulseChart from "../Examples/Charts2D/BasicChartTypes/ImpulseChart"; -import HeatmapChart from "../Examples/Charts2D/BasicChartTypes/HeatmapChart"; -import ContourChart from "../Examples/Charts2D/BasicChartTypes/ContoursChart"; -import LineChart from "../Examples/Charts2D/BasicChartTypes/LineChart"; -import DigitalLineChart from "../Examples/Charts2D/BasicChartTypes/DigitalLineChart"; -import MountainChart from "../Examples/Charts2D/BasicChartTypes/MountainChart"; -import DigitalMountainChart from "../Examples/Charts2D/BasicChartTypes/DigitalMountainChart"; -import ScatterChart from "../Examples/Charts2D/BasicChartTypes/ScatterChart"; -import StackedColumnChart from "../Examples/Charts2D/BasicChartTypes/StackedColumnChart"; -import StackedColumnSideBySide from "../Examples/Charts2D/BasicChartTypes/StackedColumnSideBySide"; -import StackedMountainChart from "../Examples/Charts2D/BasicChartTypes/StackedMountainChart"; -import DonutChart from "../Examples/Charts2D/BasicChartTypes/DonutChart"; -import PieChart from "../Examples/Charts2D/BasicChartTypes/PieChart"; -import RealtimeMountainChart from "../Examples/Charts2D/BasicChartTypes/RealTimeMountainChart"; - -import DataAnimation from "../Examples/Charts2D/Animations/DataAnimation"; -import StyleAnimation from "../Examples/Charts2D/Animations/StyleAnimation"; -import StartupAnimation from "../Examples/Charts2D/Animations/StartupAnimation"; -import GenericAnimations from "../Examples/Charts2D/Animations/GenericAnimation"; - -import AnnotationsAreEasy from "../Examples/Charts2D/ChartAnnotations/AnnotationsAreEasy"; -import AnnotationLayers from "../Examples/Charts2D/ChartAnnotations/AnnotationLayers"; -import EditableAnnotaions from "../Examples/Charts2D/ChartAnnotations/EditableAnnotations"; -import TradeMarkers from "../Examples/Charts2D/ChartAnnotations/TradeMarkers"; - -import RealtimeGhostedTraces from "../Examples/FeaturedApps/PerformanceDemos/RealtimeGhostedTraces"; - -import MultiPaneStockCharts from "../Examples/Charts2D/CreateStockCharts/MultiPaneStockCharts"; -import RealtimeTickingStockCharts from "../Examples/Charts2D/CreateStockCharts/RealtimeTickingStockCharts"; - -import ChartLegendsAPI from "../Examples/Charts2D/Legends/ChartLegendsAPI"; - -import MultipleXAxes from "../Examples/Charts2D/ModifyAxisBehavior/MultipleXAxes"; -import SecondaryYAxes from "../Examples/Charts2D/ModifyAxisBehavior/SecondaryYAxes"; -import VerticalCharts from "../Examples/Charts2D/ModifyAxisBehavior/VerticalCharts"; -import CentralAxes from "../Examples/Charts2D/ModifyAxisBehavior/CentralAxes"; -import StaticAxis from "../Examples/Charts2D/ModifyAxisBehavior/StaticAxis"; -import VerticallyStackedAxes from "../Examples/Charts2D/ModifyAxisBehavior/VerticallyStackedAxes"; -import LogarithmicAxisExample from "../Examples/Charts2D/ModifyAxisBehavior/LogarithmicAxis"; -import DrawBehindAxes from "../Examples/Charts2D/ModifyAxisBehavior/DrawBehindAxes"; - -import UsePointMarkers from "../Examples/Charts2D/StylingAndTheming/UsePointMarkers"; -import UsingThemeManager from "../Examples/Charts2D/StylingAndTheming/UsingThemeManager"; -import CustomTheme from "../Examples/Charts2D/StylingAndTheming/CreateACustomTheme/"; -import StylingInCode from "../Examples/Charts2D/StylingAndTheming/StylingInCode"; -import PerPointColoring from "../Examples/Charts2D/StylingAndTheming/PerPointColoring"; -import DashedLineStyling from "../Examples/Charts2D/StylingAndTheming/DashedLineStyling"; -import TransparentBackground from "../Examples/Charts2D/StylingAndTheming/TransparentBackground"; - -import HitTestAPI from "../Examples/Charts2D/TooltipsAndHittest/HitTestAPI"; -import UsingRolloverModifierTooltips from "../Examples/Charts2D/TooltipsAndHittest/UsingRolloverModifierTooltips"; -import SeriesSelection from "../Examples/Charts2D/TooltipsAndHittest/SeriesSelection"; -import UsingCursorModifierTooltips from "../Examples/Charts2D/TooltipsAndHittest/UsingCursorModifierTooltips"; -import Bubble3DChart from "../Examples/Charts3D/Basic3DChartTypes/Bubble3DChart"; - -import Load500By500 from "../Examples/FeaturedApps/PerformanceDemos/Load500By500"; -import RealtimePerformanceDemo from "../Examples/FeaturedApps/PerformanceDemos/RealtimePerformanceDemo"; - -import VitalSignsMonitorDemo from "../Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo"; -import SurfaceMesh3DChart from "../Examples/Charts3D/Basic3DChartTypes/SurfaceMesh3DChart"; -import PointLine3DChart from "../Examples/Charts3D/Basic3DChartTypes/PointLine3DChart"; -import LiDAR3DPointCloudDemo from "../Examples/FeaturedApps/ScientificCharts/LiDAR3DPointCloudDemo"; - -import { EXAMPLES_PAGES, TExamplePage } from "./examplePages"; -import AudioAnalyzer from "../Examples/FeaturedApps/ScientificCharts/AudioAnalyzer"; -import WaterfallChart from "../Examples/FeaturedApps/ScientificCharts/InteractiveWaterfallChart"; -import TenorCurves3DChart from "../Examples/FeaturedApps/ScientificCharts/TenorCurves3D"; -import Load1MillionPointsChart from "../Examples/FeaturedApps/PerformanceDemos/Load1MillionPoints"; -import DragAxisToScale from "../Examples/Charts2D/ZoomingAndPanning/DragAxisToScale"; -import RealtimeZoomPan from "../Examples/Charts2D/ZoomingAndPanning/RealtimeZoomPan"; -import MultipleZoomPanModifiers from "../Examples/Charts2D/ZoomingAndPanning/MultipleZoomPanModifiers"; -import SplineLineChart from "../Examples/Charts2D/BasicChartTypes/SplineLineChart"; -import SplineMountainChart from "../Examples/Charts2D/BasicChartTypes/SplineMountainChart"; -import SplineBandSeriesChart from "../Examples/Charts2D/BasicChartTypes/SplineBandSeriesChart"; -import DragHorizontalThreshold from "../Examples/Charts2D/ChartAnnotations/DragHorizontalThreshold"; -import UsingMetaData from "../Examples/Charts2D/TooltipsAndHittest/MetaData"; -import ChartFromJSON from "../Examples/BuilderApi/ChartFromJSON"; -import BuilderSharedData from "../Examples/BuilderApi/SharedData"; -import BuilderCustomTypes from "../Examples/BuilderApi/CustomTypes"; -import BuilderSimpleChart from "../Examples/BuilderApi/SimpleChart"; -import BuilderFullChart from "../Examples/BuilderApi/FullChart"; -import MultiLineLabels from "../Examples/Charts2D/AxisLabelCustomization/MultiLineLabels"; -import RotatedLabels from "../Examples/Charts2D/AxisLabelCustomization/RotatedLabels"; -import ImageLabels from "../Examples/Charts2D/AxisLabelCustomization/ImageLabels"; -import PercentageChange from "../Examples/Charts2D/Filters/PercentageChange"; -import TrendMARatio from "../Examples/Charts2D/Filters/TrendMARatio"; -import CustomFilters from "../Examples/Charts2D/Filters/CustomFilters"; -import DatapointSelection from "../Examples/Charts2D/TooltipsAndHittest/DatapointSelection"; -import Overview from "../Examples/Charts2D/ZoomingAndPanning/OverviewModifier"; -import ErrorBarsChart from "../Examples/Charts2D/BasicChartTypes/ErrorBarsChart"; -import NonUniformHeatmapChart from "../Examples/Charts2D/BasicChartTypes/NonUniformHeatmapChart"; -import FeatureAxisTypes from "../Examples/FeaturedApps/FeatureDemos/AxisTypes"; -import SubChartStockCharts from "../Examples/Charts2D/CreateStockCharts/SubChartStockCharts"; -import FeatureAxisLayout from "../Examples/FeaturedApps/FeatureDemos/AxisLayout"; -import FeatureChartTitle from "../Examples/FeaturedApps/FeatureDemos/ChartTitle"; -import SubchartsGrid from "../Examples/FeaturedApps/FeatureDemos/SubChartsAPI"; -import RealtimeBigDataShowcase from "../Examples/FeaturedApps/ShowCases/WebsocketBigData"; -import OilAndGasDashboardShowcase from "../Examples/FeaturedApps/ShowCases/OilAndGasDashboard"; -import DataLabelsExample from "../Examples/Charts2D/StylingAndTheming/DataLabels"; -import VirtualizedDataOverview from "../Examples/Charts2D/ZoomingAndPanning/VirtualizedDataWithOverview"; -import HeatmapInteractions from "../Examples/FeaturedApps/ShowCases/HeatmapInteractions"; -import DepthChart from "../Examples/Charts2D/CreateStockCharts/DepthChart"; -import TextChart from "../Examples/Charts2D/BasicChartTypes/TextSeriesChart"; -import BackgroundAnnotations from "../Examples/Charts2D/ChartAnnotations/BackgroundAnnotations"; -import RealtimeSurfaceMesh3DChart from "../Examples/Charts3D/Basic3DChartTypes/RealtimeSurfaceMesh3DChart"; -import DynamicLayout from "../Examples/FeaturedApps/ShowCases/DynamicLayout"; -import UsingVerticalSliceModifier from "../Examples/Charts2D/TooltipsAndHittest/UsingVerticalSliceModifier"; -import ServerTrafficDashboard from "../Examples/FeaturedApps/ShowCases/ServerTrafficDashboard"; -import SyncMultiChart from "../Examples/Charts2D/MultiChart/SyncMultiChart"; -import EventMarkers from "../Examples/FeaturedApps/ShowCases/EventMarkers"; -import MultiplePointMarkers from "../Examples/Charts2D/StylingAndTheming/MultiStyleSeries"; -import LineSplittingThresholds from "../Examples/Charts2D/StylingAndTheming/LineSplittingThresholds"; -import UserAnnotatedStockChart from "../Examples/Charts2D/CreateStockCharts/UserAnnotatedStockChart"; -import PopulationPyramid from "../Examples/FeaturedApps/ShowCases/PopulationPyramid"; -import SmoothStackedMountainChart from "../Examples/Charts2D/BasicChartTypes/SmoothStackedMountainChart"; -import { lineSplittingThresholdsExampleInfo } from "../Examples/Charts2D/StylingAndTheming/LineSplittingThresholds/exampleInfo"; -import Column3DChart from "../Examples/Charts3D/Basic3DChartTypes/Column3DChart"; - -import type { JSX } from "react"; - -export type TMenuItem = { - id: string; - title: string; - submenu: TExamplePage[]; -}; - -export const MENU_ITEMS_FEATURED_APPS_ID = "MENU_ITEMS_FEATURED_APPS_ID"; -export const MENU_ITEMS_FEATURED_APPS: TMenuItem[] = [ - { - id: "featuredApps_performanceDemos", - title: "Performance Demos & Showcases", - submenu: [ - EXAMPLES_PAGES.featuredApps_performanceDemos_RealtimePerformanceDemo, - EXAMPLES_PAGES.featuredApps_performanceDemos_Load500By500, - EXAMPLES_PAGES.featuredApps_performanceDemos_LoadOneMillionPoints, - EXAMPLES_PAGES.featuredApps_performanceDemos_RealtimeGhostedTraces, - EXAMPLES_PAGES.featuredApps_scientificCharts_AudioAnalyzerDemo, - EXAMPLES_PAGES.featuredApps_showcases_oilandgasdashboard, - EXAMPLES_PAGES.featuredApps_showcases_realtimebigdata, - EXAMPLES_PAGES.featuredApps_showcases_servertrafficdashboard, - EXAMPLES_PAGES.featuredApps_showcases_richInteractions, - EXAMPLES_PAGES.featuredApps_showcases_dynamicLayout, - EXAMPLES_PAGES.featuredApps_showcases_eventMarkers, - EXAMPLES_PAGES.featuredApps_showcases_populationPyramid, - ], - }, - { - id: "featuredApps_scientificCharts", - title: "Scientific & Medical Charts", - submenu: [ - EXAMPLES_PAGES.featuredApps_medicalCharts_VitalSignsMonitorDemo, - EXAMPLES_PAGES.chart2D_modifyAxisBehavior_LogarithmicAxis, - EXAMPLES_PAGES.featuredApps_scientificCharts_Lidar3DPointCloudDemo, - EXAMPLES_PAGES.chart2D_modifyAxisBehavior_VerticallyStackedAxes, - EXAMPLES_PAGES.featuredApps_scientificCharts_AudioAnalyzerDemo, - EXAMPLES_PAGES.featuredApps_scientificCharts_WaterfallChartDemo, - ], - }, - { - id: "featuredApps_financialCharts", - title: "Financial Charts", - submenu: [ - EXAMPLES_PAGES.chart2D_basicCharts_CandlestickChart, - EXAMPLES_PAGES.chart2D_basicCharts_OhlcChart, - EXAMPLES_PAGES.chart2D_createStockCharts_RealtimeTickingStockCharts, - EXAMPLES_PAGES.chart2D_createStockCharts_SubchartStockCharts, - EXAMPLES_PAGES.featuredApps_scientificCharts_TenorCurvesDemo, - EXAMPLES_PAGES.chart2D_createStockCharts_MultiPaneStockCharts, - EXAMPLES_PAGES.chart2D_createStockCharts_DepthChart, - EXAMPLES_PAGES.chart2D_chartAnnotations_TradeMarkers, - EXAMPLES_PAGES.chart2D_createStockCharts_SharedChart, - ], - }, -]; - -export const MENU_ITEMS_2D_ID = "MENU_ITEMS_2D_ID"; -export const MENU_ITEMS_2D: TMenuItem[] = [ - { - id: "chart2D_basicCharts", - title: "JavaScript Chart Types", - submenu: [ - EXAMPLES_PAGES.chart2D_basicCharts_LineChart, - EXAMPLES_PAGES.chart2D_basicCharts_SplineLineChart, - EXAMPLES_PAGES.chart2D_basicCharts_DigitalLineChart, - EXAMPLES_PAGES.chart2D_basicCharts_BandSeriesChart, - EXAMPLES_PAGES.chart2D_basicCharts_SplineBandChart, - EXAMPLES_PAGES.chart2D_basicCharts_DigitalBandSeriesChart, - EXAMPLES_PAGES.chart2D_basicCharts_BubbleChart, - EXAMPLES_PAGES.chart2D_basicCharts_CandlestickChart, - EXAMPLES_PAGES.chart2D_basicCharts_ColumnChart, - EXAMPLES_PAGES.featuredApps_showcases_populationPyramid, - EXAMPLES_PAGES.chart2D_basicCharts_ErrorBarsChart, - EXAMPLES_PAGES.chart2D_basicCharts_ImpulseChart, - EXAMPLES_PAGES.chart2D_basicCharts_TextChart, - EXAMPLES_PAGES.chart2D_basicCharts_FanChart, - EXAMPLES_PAGES.chart2D_basicCharts_HeatmapChart, - EXAMPLES_PAGES.chart2D_basicCharts_NonUniformHeatmapChart, - EXAMPLES_PAGES.chart2D_basicCharts_ContourChart, - EXAMPLES_PAGES.chart2D_basicCharts_MountainChart, - EXAMPLES_PAGES.chart2D_basicCharts_SplineMountainChart, - EXAMPLES_PAGES.chart2D_basicCharts_DigitalMountainChart, - EXAMPLES_PAGES.chart2D_basicCharts_RealtimeMountainChart, - EXAMPLES_PAGES.chart2D_basicCharts_ScatterChart, - EXAMPLES_PAGES.chart2D_basicCharts_StackedColumnChart, - EXAMPLES_PAGES.chart2D_basicCharts_StackedColumnSideBySide, - EXAMPLES_PAGES.chart2D_basicCharts_StackedMountainChart, - EXAMPLES_PAGES.chart2D_basicCharts_SmoothStackedMountainChart, - EXAMPLES_PAGES.chart2D_basicCharts_PieChart, - EXAMPLES_PAGES.chart2D_basicCharts_DonutChart, - EXAMPLES_PAGES.chart2D_chartAnnotations_BackgroundAnnotations, - ], - }, - { - id: "chart2D_chartAnnotations", - title: "Chart Annotations", - submenu: [ - EXAMPLES_PAGES.chart2D_chartAnnotations_AnnotationsAreEasy, - EXAMPLES_PAGES.chart2D_stylingAndTheming_PerPointColoring, - EXAMPLES_PAGES.chart2D_chartAnnotations_TradeMarkers, - EXAMPLES_PAGES.chart2D_chartAnnotations_DragHorizontalThreshold, - EXAMPLES_PAGES.chart2D_chartAnnotations_EditableAnntations, - EXAMPLES_PAGES.chart2D_chartAnnotations_BackgroundAnnotations, - EXAMPLES_PAGES.chart2D_chartAnnotations_AnnotationLayers, - ], - }, - { - id: "chart2D_legends", - title: "Chart Legends", - submenu: [EXAMPLES_PAGES.chart2D_legends_ChartLegendsAPI], - }, - { - id: "chart2D_modifyAxisBehavior", - title: "Chart Axis APIs", - submenu: [ - EXAMPLES_PAGES.chart2D_modifyAxisBehavior_MultipleXAxes, - EXAMPLES_PAGES.chart2D_modifyAxisBehavior_SecondaryYAxes, - EXAMPLES_PAGES.chart2D_modifyAxisBehavior_VerticalCharts, - EXAMPLES_PAGES.chart2D_modifyAxisBehavior_CentralAxes, - EXAMPLES_PAGES.chart2D_modifyAxisBehavior_StaticAxis, - EXAMPLES_PAGES.chart2D_modifyAxisBehavior_VerticallyStackedAxes, - EXAMPLES_PAGES.chart2D_modifyAxisBehavior_LogarithmicAxis, - EXAMPLES_PAGES.chart2D_modifyAxisBehavior_DrawBehindAxes, - EXAMPLES_PAGES.featuredApps_featureDemos_axisTypes, - EXAMPLES_PAGES.featuredApps_featureDemos_axisLayout, - ], - }, - { - id: "chart2D_axisLabelCustomization", - title: "Axis Label Customization", - submenu: [ - EXAMPLES_PAGES.chart2D_axisLabelCustomization_MultiLineLabels, - EXAMPLES_PAGES.chart2D_axisLabelCustomization_ImageLabels, - EXAMPLES_PAGES.chart2D_axisLabelCustomization_RotatedLabels, - ], - }, - { - id: "chart2D_stylingAndTheming", - title: "Styling and Theming", - submenu: [ - EXAMPLES_PAGES.chart2D_stylingAndTheming_TransparentBackground, - EXAMPLES_PAGES.chart2D_stylingAndTheming_StylingInCode, - EXAMPLES_PAGES.chart2D_stylingAndTheming_UsingThemeManager, - EXAMPLES_PAGES.chart2D_stylingAndTheming_CustomTheme, - EXAMPLES_PAGES.chart2D_stylingAndTheming_PerPointColoring, - EXAMPLES_PAGES.chart2D_stylingAndTheming_UsePointMarkers, - EXAMPLES_PAGES.chart2D_stylingAndTheming_DashedLineStyling, - EXAMPLES_PAGES.chart2D_stylingAndTheming_DataLabels, - EXAMPLES_PAGES.chart2D_stylingAndTheming_MultiplePointMarkers, - EXAMPLES_PAGES.chart2D_stylingAndTheming_LineSplittingThresholds, - EXAMPLES_PAGES.featuredApps_featureDemos_chartTitle, - ], - }, - { - id: "chart2D_tooltipsAndHittest", - title: "Tooltips and Hit-Test", - submenu: [ - EXAMPLES_PAGES.chart2D_tooltipsAndHittest_HitTestApi, - EXAMPLES_PAGES.chart2D_tooltipsAndHittest_UsingRolloverModifierTooltips, - EXAMPLES_PAGES.chart2D_tooltipsAndHittest_UsingCursorModifierTooltips, - EXAMPLES_PAGES.chart2D_tooltipsAndHittest_VerticalSliceModifier, - EXAMPLES_PAGES.chart2D_tooltipsAndHittest_MetaData, - EXAMPLES_PAGES.chart2D_tooltipsAndHittest_SeriesSelection, - EXAMPLES_PAGES.chart2D_tooltipsAndHittest_DataPointSelection, - ], - }, - { - id: "chart2D_zoomingAndPanning", - title: "Zoom and Pan a Chart", - submenu: [ - EXAMPLES_PAGES.chart2D_modifyAxisBehavior_MultipleXAxes, - EXAMPLES_PAGES.chart2D_modifyAxisBehavior_SecondaryYAxes, - EXAMPLES_PAGES.chart2D_zoomAndPanAChart_DragAxisToScale, - EXAMPLES_PAGES.chart2D_zoomAndPanAChart_RealtimeZoomPan, - EXAMPLES_PAGES.chart2D_zoomAndPanAChart_MultipleChartModifiers, - EXAMPLES_PAGES.chart2D_zoomAndPanAChart_Overview, - EXAMPLES_PAGES.chart2D_zoomAndPanAChart_VirtualizedDataOverview, - //EXAMPLES_PAGES.chart2D_zoomAndPanAChart_ZoomHighPrecision, - ], - }, - { - id: "chart2D_filters", - title: "Transforming Data with Filters", - submenu: [ - EXAMPLES_PAGES.chart2D_filters_TrendMARatio, - EXAMPLES_PAGES.chart2D_filters_CustomFilters, - EXAMPLES_PAGES.chart2D_filters_PercentageChange, - EXAMPLES_PAGES.chart2D_chartAnnotations_DragHorizontalThreshold, - ], - }, - { - id: "animationApi", - title: "Animation API", - submenu: [ - EXAMPLES_PAGES.chart2D_Animations_DataAnimation, - EXAMPLES_PAGES.chart2D_Animations_StyleAnimation, - EXAMPLES_PAGES.chart2D_Animations_StartupAnimation, - EXAMPLES_PAGES.chart2D_Animations_GenericAnimation, - ], - }, - { - id: "builderApi", - title: "Builder (JSON / JS Objects) API", - submenu: [ - EXAMPLES_PAGES.builderApi_simplechart, - EXAMPLES_PAGES.builderApi_fullchart, - EXAMPLES_PAGES.builderApi_chartFromJSON, - EXAMPLES_PAGES.builderApi_SharedData, - EXAMPLES_PAGES.builderApi_CustomTypes, - ], - }, - { - id: "subchartsApi", - title: "Subcharts API", - submenu: [ - EXAMPLES_PAGES.featuredApps_featureDemos_subchartsGrid, - EXAMPLES_PAGES.featuredApps_showcases_dynamicLayout, - ], - }, - { - id: "multichart", - title: "Multiple Charts", - submenu: [ - EXAMPLES_PAGES.chart2D_multiChart_syncMultiChart, - EXAMPLES_PAGES.chart2D_createStockCharts_MultiPaneStockCharts, - EXAMPLES_PAGES.featuredApps_showcases_servertrafficdashboard, - ], - }, -]; - -export const MENU_ITEMS_3D_ID = "MENU_ITEMS_3D_ID"; -export const MENU_ITEMS_3D: TMenuItem[] = [ - { - id: "chart3D_Basic3DChartTypes", - title: "JavaScript 3D Chart Types", - submenu: [ - EXAMPLES_PAGES.chart3D_basic3DChartTypes_Bubble3DChart, - EXAMPLES_PAGES.chart3D_basic3DChartTypes_SurfaceMesh3DChart, - EXAMPLES_PAGES.chart3D_basic3DChartTypes_PointLine3DChart, - EXAMPLES_PAGES.featuredApps_scientificCharts_Lidar3DPointCloudDemo, - EXAMPLES_PAGES.featuredApps_scientificCharts_TenorCurvesDemo, - EXAMPLES_PAGES.chart3D_basic3DChartTypes_RealtimeSurfaceMesh3DChart, - EXAMPLES_PAGES.chart3D_basic3DChartTypes_Column3DChart, - ], - }, -]; - -export const ALL_MENU_ITEMS = [...MENU_ITEMS_FEATURED_APPS, ...MENU_ITEMS_2D, ...MENU_ITEMS_3D]; - -export type TMultilevelMenuItem = - | TExamplePage - | TMenuItem - | { - id: string; - title: string; - submenu: TMenuItem[]; - } - | { - id: string; - title: string; - submenu: TMultilevelMenuItem[]; - }; - -export const MENU_ITEMS_HIERARCHY: TMultilevelMenuItem[] = [ - { - id: "home", - title: "Home", - submenu: [ - { - id: MENU_ITEMS_FEATURED_APPS_ID, - title: "Featured Apps", - submenu: MENU_ITEMS_FEATURED_APPS, - }, - { - id: MENU_ITEMS_2D_ID, - title: "2D Charts", - submenu: MENU_ITEMS_2D, - }, - { - id: MENU_ITEMS_3D_ID, - title: "3D Charts", - submenu: MENU_ITEMS_3D, - }, - ], - }, -]; - -// TODO refactor. Get path state as array of category IDs -export const getExampleCategoryPath = (page: TExamplePage) => { - const fullPath: string[] = []; - const searchInItems = (items: TMultilevelMenuItem[]) => { - let found = false; - items.forEach((item) => { - if (found) { - return; - } - if ("submenu" in item) { - const res = searchInItems(item.submenu); - if (res) { - fullPath.unshift(item.id); - found = true; - return; - } - } else if (item.id === page.id) { - fullPath.unshift(item.id); - found = true; - return; - } - }); - - return found; - }; - - searchInItems(MENU_ITEMS_HIERARCHY); - - return fullPath; -}; - -export const getParentMenuIds = (exampleId: string): string[] => { - const getSubmenuLevelIds = (menuItemsArr: TMenuItem[], id: string): string[] => { - const res: string[] = []; - menuItemsArr.forEach((item) => { - item.submenu.forEach((subItem) => { - if (subItem.id === id) { - res.push(item.id); - } - }); - }); - return res; - }; - - const resMenuLevel: string[] = []; - - const resSubmenuLevel2D = getSubmenuLevelIds(MENU_ITEMS_2D, exampleId); - if (resSubmenuLevel2D.length > 0) { - resMenuLevel.push(MENU_ITEMS_2D_ID); - } - - const resSubmenuLevel3D = getSubmenuLevelIds(MENU_ITEMS_3D, exampleId); - if (resSubmenuLevel3D.length > 0) { - resMenuLevel.push(MENU_ITEMS_3D_ID); - } - - const resSubmenuLevelFeaturedApps = getSubmenuLevelIds(MENU_ITEMS_FEATURED_APPS, exampleId); - if (resSubmenuLevelFeaturedApps.length > 0) { - resMenuLevel.push(MENU_ITEMS_FEATURED_APPS_ID); - } - - return [...resMenuLevel, ...resSubmenuLevel2D, ...resSubmenuLevel3D, ...resSubmenuLevelFeaturedApps]; -}; - -export const getExampleComponent = (exampleId: string): (() => JSX.Element) => { - switch (exampleId) { - case EXAMPLES_PAGES.chart2D_Animations_DataAnimation.id: - return DataAnimation; - case EXAMPLES_PAGES.chart2D_Animations_StyleAnimation.id: - return StyleAnimation; - case EXAMPLES_PAGES.chart2D_Animations_StartupAnimation.id: - return StartupAnimation; - case EXAMPLES_PAGES.chart2D_Animations_GenericAnimation.id: - return GenericAnimations; - case EXAMPLES_PAGES.chart2D_basicCharts_BandSeriesChart.id: - return BandSeriesChart; - case EXAMPLES_PAGES.chart2D_basicCharts_SplineBandChart.id: - return SplineBandSeriesChart; - case EXAMPLES_PAGES.chart2D_basicCharts_DigitalBandSeriesChart.id: - return DigitalBandSeriesChart; - case EXAMPLES_PAGES.chart2D_basicCharts_FanChart.id: - return FanChart; - case EXAMPLES_PAGES.chart2D_basicCharts_BubbleChart.id: - return BubbleChart; - case EXAMPLES_PAGES.chart2D_basicCharts_CandlestickChart.id: - return CandlestickChart; - case EXAMPLES_PAGES.chart2D_basicCharts_OhlcChart.id: - return OhlcChart; - case EXAMPLES_PAGES.chart2D_basicCharts_ColumnChart.id: - return ColumnChart; - case EXAMPLES_PAGES.chart2D_basicCharts_ErrorBarsChart.id: - return ErrorBarsChart; - case EXAMPLES_PAGES.chart2D_basicCharts_ImpulseChart.id: - return ImpulseChart; - case EXAMPLES_PAGES.chart2D_basicCharts_HeatmapChart.id: - return HeatmapChart; - case EXAMPLES_PAGES.chart2D_basicCharts_NonUniformHeatmapChart.id: - return NonUniformHeatmapChart; - case EXAMPLES_PAGES.chart2D_basicCharts_ContourChart.id: - return ContourChart; - case EXAMPLES_PAGES.chart2D_basicCharts_LineChart.id: - return LineChart; - case EXAMPLES_PAGES.chart2D_basicCharts_SplineLineChart.id: - return SplineLineChart; - case EXAMPLES_PAGES.chart2D_basicCharts_DigitalLineChart.id: - return DigitalLineChart; - case EXAMPLES_PAGES.chart2D_basicCharts_MountainChart.id: - return MountainChart; - case EXAMPLES_PAGES.chart2D_basicCharts_SplineMountainChart.id: - return SplineMountainChart; - case EXAMPLES_PAGES.chart2D_basicCharts_DigitalMountainChart.id: - return DigitalMountainChart; - case EXAMPLES_PAGES.chart2D_basicCharts_RealtimeMountainChart.id: - return RealtimeMountainChart; - case EXAMPLES_PAGES.chart2D_basicCharts_ScatterChart.id: - return ScatterChart; - case EXAMPLES_PAGES.chart2D_basicCharts_DonutChart.id: - return DonutChart; - case EXAMPLES_PAGES.chart2D_basicCharts_PieChart.id: - return PieChart; - case EXAMPLES_PAGES.chart2D_basicCharts_TextChart.id: - return TextChart; - case EXAMPLES_PAGES.chart2D_chartAnnotations_AnnotationsAreEasy.id: - return AnnotationsAreEasy; - case EXAMPLES_PAGES.chart2D_chartAnnotations_AnnotationLayers.id: - return AnnotationLayers; - case EXAMPLES_PAGES.chart2D_chartAnnotations_EditableAnntations.id: - return EditableAnnotaions; - case EXAMPLES_PAGES.chart2D_chartAnnotations_TradeMarkers.id: - return TradeMarkers; - case EXAMPLES_PAGES.chart2D_chartAnnotations_DragHorizontalThreshold.id: - return DragHorizontalThreshold; - case EXAMPLES_PAGES.chart2D_chartAnnotations_BackgroundAnnotations.id: - return BackgroundAnnotations; - case EXAMPLES_PAGES.featuredApps_performanceDemos_RealtimeGhostedTraces.id: - return RealtimeGhostedTraces; - case EXAMPLES_PAGES.chart2D_createStockCharts_MultiPaneStockCharts.id: - return MultiPaneStockCharts; - case EXAMPLES_PAGES.chart2D_createStockCharts_RealtimeTickingStockCharts.id: - return RealtimeTickingStockCharts; - case EXAMPLES_PAGES.chart2D_createStockCharts_SubchartStockCharts.id: - return SubChartStockCharts; - case EXAMPLES_PAGES.chart2D_createStockCharts_DepthChart.id: - return DepthChart; - case EXAMPLES_PAGES.chart2D_createStockCharts_SharedChart.id: - return UserAnnotatedStockChart; - case EXAMPLES_PAGES.chart2D_legends_ChartLegendsAPI.id: - return ChartLegendsAPI; - case EXAMPLES_PAGES.chart2D_modifyAxisBehavior_MultipleXAxes.id: - return MultipleXAxes; - case EXAMPLES_PAGES.chart2D_modifyAxisBehavior_SecondaryYAxes.id: - return SecondaryYAxes; - case EXAMPLES_PAGES.chart2D_modifyAxisBehavior_VerticalCharts.id: - return VerticalCharts; - case EXAMPLES_PAGES.chart2D_modifyAxisBehavior_CentralAxes.id: - return CentralAxes; - case EXAMPLES_PAGES.chart2D_modifyAxisBehavior_StaticAxis.id: - return StaticAxis; - case EXAMPLES_PAGES.chart2D_modifyAxisBehavior_VerticallyStackedAxes.id: - return VerticallyStackedAxes; - case EXAMPLES_PAGES.chart2D_modifyAxisBehavior_LogarithmicAxis.id: - return LogarithmicAxisExample; - case EXAMPLES_PAGES.chart2D_modifyAxisBehavior_DrawBehindAxes.id: - return DrawBehindAxes; - case EXAMPLES_PAGES.chart2D_basicCharts_StackedColumnChart.id: - return StackedColumnChart; - case EXAMPLES_PAGES.chart2D_basicCharts_StackedColumnSideBySide.id: - return StackedColumnSideBySide; - case EXAMPLES_PAGES.chart2D_basicCharts_StackedMountainChart.id: - return StackedMountainChart; - case EXAMPLES_PAGES.chart2D_basicCharts_SmoothStackedMountainChart.id: - return SmoothStackedMountainChart; - case EXAMPLES_PAGES.chart2D_stylingAndTheming_UsePointMarkers.id: - return UsePointMarkers; - case EXAMPLES_PAGES.chart2D_stylingAndTheming_MultiplePointMarkers.id: - return MultiplePointMarkers; - case EXAMPLES_PAGES.chart2D_stylingAndTheming_LineSplittingThresholds.id: - return LineSplittingThresholds; - case EXAMPLES_PAGES.chart2D_stylingAndTheming_UsingThemeManager.id: - return UsingThemeManager; - case EXAMPLES_PAGES.chart2D_stylingAndTheming_CustomTheme.id: - return CustomTheme; - case EXAMPLES_PAGES.chart2D_stylingAndTheming_StylingInCode.id: - return StylingInCode; - case EXAMPLES_PAGES.chart2D_stylingAndTheming_PerPointColoring.id: - return PerPointColoring; - case EXAMPLES_PAGES.chart2D_stylingAndTheming_DashedLineStyling.id: - return DashedLineStyling; - case EXAMPLES_PAGES.chart2D_stylingAndTheming_TransparentBackground.id: - return TransparentBackground; - case EXAMPLES_PAGES.chart2D_stylingAndTheming_DataLabels.id: - return DataLabelsExample; - case EXAMPLES_PAGES.chart2D_tooltipsAndHittest_HitTestApi.id: - return HitTestAPI; - case EXAMPLES_PAGES.chart2D_tooltipsAndHittest_UsingRolloverModifierTooltips.id: - return UsingRolloverModifierTooltips; - case EXAMPLES_PAGES.chart2D_tooltipsAndHittest_SeriesSelection.id: - return SeriesSelection; - case EXAMPLES_PAGES.chart2D_tooltipsAndHittest_UsingCursorModifierTooltips.id: - return UsingCursorModifierTooltips; - case EXAMPLES_PAGES.chart2D_tooltipsAndHittest_MetaData.id: - return UsingMetaData; - case EXAMPLES_PAGES.chart2D_tooltipsAndHittest_DataPointSelection.id: - return DatapointSelection; - case EXAMPLES_PAGES.chart2D_tooltipsAndHittest_VerticalSliceModifier.id: - return UsingVerticalSliceModifier; - case EXAMPLES_PAGES.chart2D_zoomAndPanAChart_DragAxisToScale.id: - return DragAxisToScale; - case EXAMPLES_PAGES.chart2D_zoomAndPanAChart_RealtimeZoomPan.id: - return RealtimeZoomPan; - case EXAMPLES_PAGES.chart2D_zoomAndPanAChart_MultipleChartModifiers.id: - return MultipleZoomPanModifiers; - case EXAMPLES_PAGES.chart2D_zoomAndPanAChart_Overview.id: - return Overview; - case EXAMPLES_PAGES.chart2D_zoomAndPanAChart_VirtualizedDataOverview.id: - return VirtualizedDataOverview; - // case EXAMPLES_PAGES.chart2D_zoomAndPanAChart_ZoomHighPrecision.id: - // return ZoomHighPrecision; - case EXAMPLES_PAGES.chart2D_axisLabelCustomization_MultiLineLabels.id: - return MultiLineLabels; - case EXAMPLES_PAGES.chart2D_axisLabelCustomization_RotatedLabels.id: - return RotatedLabels; - case EXAMPLES_PAGES.chart2D_axisLabelCustomization_ImageLabels.id: - return ImageLabels; - case EXAMPLES_PAGES.chart3D_basic3DChartTypes_Bubble3DChart.id: - return Bubble3DChart; - case EXAMPLES_PAGES.chart3D_basic3DChartTypes_SurfaceMesh3DChart.id: - return SurfaceMesh3DChart; - case EXAMPLES_PAGES.chart3D_basic3DChartTypes_RealtimeSurfaceMesh3DChart.id: - return RealtimeSurfaceMesh3DChart; - case EXAMPLES_PAGES.chart3D_basic3DChartTypes_PointLine3DChart.id: - return PointLine3DChart; - case EXAMPLES_PAGES.chart3D_basic3DChartTypes_Column3DChart.id: - return Column3DChart; - case EXAMPLES_PAGES.featuredApps_performanceDemos_Load500By500.id: - return Load500By500; - case EXAMPLES_PAGES.featuredApps_performanceDemos_RealtimePerformanceDemo.id: - return RealtimePerformanceDemo; - case EXAMPLES_PAGES.featuredApps_performanceDemos_LoadOneMillionPoints.id: - return Load1MillionPointsChart; - case EXAMPLES_PAGES.featuredApps_medicalCharts_VitalSignsMonitorDemo.id: - return VitalSignsMonitorDemo; - case EXAMPLES_PAGES.featuredApps_scientificCharts_Lidar3DPointCloudDemo.id: - return LiDAR3DPointCloudDemo; - case EXAMPLES_PAGES.featuredApps_scientificCharts_AudioAnalyzerDemo.id: - return AudioAnalyzer; - case EXAMPLES_PAGES.featuredApps_scientificCharts_WaterfallChartDemo.id: - return WaterfallChart; - case EXAMPLES_PAGES.featuredApps_scientificCharts_TenorCurvesDemo.id: - return TenorCurves3DChart; - case EXAMPLES_PAGES.featuredApps_featureDemos_axisTypes.id: - return FeatureAxisTypes; - case EXAMPLES_PAGES.featuredApps_featureDemos_axisLayout.id: - return FeatureAxisLayout; - case EXAMPLES_PAGES.featuredApps_featureDemos_chartTitle.id: - return FeatureChartTitle; - case EXAMPLES_PAGES.featuredApps_featureDemos_subchartsGrid.id: - return SubchartsGrid; - case EXAMPLES_PAGES.featuredApps_showcases_realtimebigdata.id: - return RealtimeBigDataShowcase; - case EXAMPLES_PAGES.featuredApps_showcases_servertrafficdashboard.id: - return ServerTrafficDashboard; - case EXAMPLES_PAGES.featuredApps_showcases_oilandgasdashboard.id: - return OilAndGasDashboardShowcase; - case EXAMPLES_PAGES.featuredApps_showcases_richInteractions.id: - return HeatmapInteractions; - case EXAMPLES_PAGES.featuredApps_showcases_dynamicLayout.id: - return DynamicLayout; - case EXAMPLES_PAGES.featuredApps_showcases_eventMarkers.id: - return EventMarkers; - case EXAMPLES_PAGES.featuredApps_showcases_populationPyramid.id: - return PopulationPyramid; - case EXAMPLES_PAGES.chart2D_multiChart_syncMultiChart.id: - return SyncMultiChart; - case EXAMPLES_PAGES.builderApi_simplechart.id: - return BuilderSimpleChart; - case EXAMPLES_PAGES.builderApi_fullchart.id: - return BuilderFullChart; - case EXAMPLES_PAGES.builderApi_chartFromJSON.id: - return ChartFromJSON; - case EXAMPLES_PAGES.builderApi_SharedData.id: - return BuilderSharedData; - case EXAMPLES_PAGES.builderApi_CustomTypes.id: - return BuilderCustomTypes; - case EXAMPLES_PAGES.chart2D_filters_PercentageChange.id: - return PercentageChange; - case EXAMPLES_PAGES.chart2D_filters_TrendMARatio.id: - return TrendMARatio; - case EXAMPLES_PAGES.chart2D_filters_CustomFilters.id: - return CustomFilters; - default: - throw new Error("Ensure you update examples.ts getExampleComponent() to return an example"); - } -}; diff --git a/Examples/src/components/AppRouter/pages.ts b/Examples/src/components/AppRouter/pages.ts deleted file mode 100644 index e6eda5e4c..000000000 --- a/Examples/src/components/AppRouter/pages.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { TFrameworkTemplate } from "../../helpers/shared/Helpers/frameworkParametrization"; - -export type TPage = { - id: string; - title: TFrameworkTemplate; - path: string; -}; - -export const PAGES: Record = { - reactHome: { - id: "reactHome", - title: "Homepage", - path: `/react`, - }, - jsHome: { - id: "jsHome", - title: "Homepage", - path: `/javascript`, - }, - angularHome: { - id: "angularHome", - title: "Homepage", - path: `/angular`, - } -}; diff --git a/Examples/src/components/AppTopBar/AppBarTop.tsx b/Examples/src/components/AppTopBar/AppBarTop.tsx deleted file mode 100644 index 3e9bda621..000000000 --- a/Examples/src/components/AppTopBar/AppBarTop.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import { FC, useContext, useState } from "react"; -import AppBar from "@mui/material/AppBar"; -import Button from "@mui/material/Button"; -import Toolbar from "@mui/material/Toolbar"; -import GitHubIcon from "@mui/icons-material/GitHub"; -import BookIcon from "@mui/icons-material/Book"; -import MenuIcon from "@mui/icons-material/Menu"; -import Chip from "@mui/material/Chip"; -import Box from "@mui/material/Box"; -import Search from "../Search/Search"; -import classes from "./AppTopBar.module.scss"; -import Logo from "../../images/scichart-logo-app-bar.svg"; -import LogoSmall from "../../images/scichart-logo-app-bar-mobile.svg"; -import { TExamplePage } from "../AppRouter/examplePages"; -import npm from "./npm.svg"; -import { FrameworkContext } from "../../helpers/shared/Helpers/FrameworkContext"; -import { getFrameworkContent } from "../../helpers/shared/Helpers/frameworkParametrization"; -import { libraryVersion } from "scichart"; -import useMediaQuery from "@mui/material/useMediaQuery"; -import { Theme } from "@mui/material"; -import { ETheme } from "../../helpers/types/types"; - -type TProps = { - toggleDrawer: () => void; - currentExample?: TExamplePage; - theme: ETheme; - setTheme: (theme: ETheme) => void; -}; - -const AppBarTop: FC = (props) => { - const { toggleDrawer, currentExample, theme, setTheme } = props; - const selectedFramework = useContext(FrameworkContext); - - function toggleTheme(){ - const newTheme = (theme == ETheme.dark ? ETheme.light : ETheme.dark); - document.documentElement.setAttribute('data-theme', newTheme ); - document.querySelector('meta[name="theme-color"]')?.setAttribute('content', getComputedStyle(document.documentElement).getPropertyValue('--bg')); - setTheme(newTheme); - } - - const baseGithubPath = "https://github.com/ABTSoftware/SciChart.JS.Examples/blob/master/Examples/src"; - const contextualGithub = - currentExample?.filepath !== undefined - ? baseGithubPath + "/components/Examples/" + currentExample.filepath - : "https://github.com/ABTSoftware/SciChart.JS.Examples"; - const contextualGithubTitle = - currentExample !== undefined - ? `View source for ${getFrameworkContent(currentExample.title, selectedFramework)} on Github` - : "Clone SciChart.js.examples on GitHub"; - const docLinks = currentExample?.documentationLinks; - const contextualDocUrl = - docLinks !== undefined && docLinks.length > 0 - ? docLinks[0].href - : "https://www.scichart.com/javascript-chart-documentation"; - const contextualDocTitle = - docLinks !== undefined && docLinks.length > 0 ? docLinks[0].title : "SciChart.js Documentation Home"; - - const isMd = useMediaQuery((theme: Theme) => theme.breakpoints.down("md")); // Medium view - - return ( - - - - {typeof window !== "undefined" && window?.innerWidth <= 768 ? ( - scichart-logo - ) : ( - scichart-logo - )} - - - {isMd ? null : ( - <> - - - - - - - )} -
- - - - - - - - - Npm Logo - - -
-
-
- ); -}; - -export default AppBarTop; diff --git a/Examples/src/components/AppTopBar/AppTopBar.module.scss b/Examples/src/components/AppTopBar/AppTopBar.module.scss deleted file mode 100644 index 5b8874923..000000000 --- a/Examples/src/components/AppTopBar/AppTopBar.module.scss +++ /dev/null @@ -1,171 +0,0 @@ -@import "../../assets/main.scss"; - -.AppBar { - height: $app-bar-height; - max-width: 100%; - background-color: $color-dark; - - .Logo { - display: block; - height: $app-bar-height; - - .LogoSmall { - height: $app-bar-height; - width: $app-bar-height; - } - - .LogoDefault { - margin-top: 2px; - height: 100%; - width: 209px; - } - } - - .ToolBar { - display: flex; - max-width: 100%; - background-color: var(--primary); - } - - .ToolBarMenu { - right: 0; - top: 0; - display: flex; - align-items: center; - gap: 10px; - flex: auto; - height: $app-bar-height; - padding: 12px; - padding-left: 0px; - z-index: 1200; - - %ToolBarButton { - display: block; - aspect-ratio: 1 / 1; - width: unset; - height: 44px; - padding: 0px; - min-width: unset; - min-height: unset; - border-radius: 8px; - color: $color-primary-white; - } - - .MenuButton { - @extend %ToolBarButton; - - display: none; - line-height: 1em; - background: $color-primary-white-alpha; - // border: 1px solid $color-medium-blue; - - @include sm { - display: block; - } - } - - .FlexPlaceholder { - flex-grow: 1; - } - - .GitHubLink { - @extend %ToolBarButton; - - display: flex; - align-items: center; - justify-content: center; - height: 100%; - border-radius: 8px; - background-color: $color-medium-blue; - text-decoration: none; - } - - .versionChip { - height: 44px; - border-radius: 8px; - @include md { - display: none; - } - } - - .NpmLink { - @extend %ToolBarButton; - - display: flex; - padding: 6px; - border-radius: 8px; - background-color: $color-red; - color: $color-primary-white; - text-decoration: none; - } - - .PurpleButton { - display: flex; - flex: none; - height: 100%; - padding: $default-spacing; - background: $gradient-btn-dark; - border-radius: 8px; - - @include md { - display: none; - } - - span { - color: $color-lightest-green; - font-size: 12px; - font-weight: 600; - letter-spacing: 0.05em; - line-height: 15px; - text-align: center; - text-transform: uppercase; - text-decoration-thickness: auto; - } - } - - .PurpleButton:hover { - background-size: 200% 100%; - background-position: 0 100%; - } - - .DisabledButton { - background: $color-grey; - margin: 0; - } - - // overrides MuiButton-label - .DisabledButton > span { - color: $color-light-grey; - } - - .DisabledButtonTooltipWrapper { - padding: 0; - } - - .BlueButton { - background: $gradient-blue; - height: 100%; - text-align: center; - line-height: 1; - border-radius: 8px; - span { - font-weight: bold; - padding: 6px 15px; - color: white !important; - font-size: 0.8rem; - white-space: nowrap; - } - } - - .BlueButton:hover { - background-size: 200% 100%; - background-position: 0 100%; - } - - .ThemeButton { - @extend %ToolBarButton; - - - } - } -} diff --git a/Examples/src/components/AppTopBar/npm.svg b/Examples/src/components/AppTopBar/npm.svg deleted file mode 100644 index e2fe77fe2..000000000 --- a/Examples/src/components/AppTopBar/npm.svg +++ /dev/null @@ -1,3 +0,0 @@ - - \ No newline at end of file diff --git a/Examples/src/components/Breadcrumbs/ExampleBreadcrumbs.tsx b/Examples/src/components/Breadcrumbs/ExampleBreadcrumbs.tsx deleted file mode 100644 index fcc65fe80..000000000 --- a/Examples/src/components/Breadcrumbs/ExampleBreadcrumbs.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import { ReactNode, useMemo } from "react"; -import { Button, Typography } from "@mui/material"; -import HomeIcon from "@mui/icons-material/Home"; -import { getExampleCategoryPath, MENU_ITEMS_HIERARCHY } from "../AppRouter/examples"; -import { BreadcrumbsWithMenu, TBreadcrumbItem, TBreadcrumbPath } from "./GenericBreadcrumbs"; -import { appTheme } from "../Examples/theme"; -import { TExamplePage } from "../AppRouter/examplePages"; -import { useExampleRouteParams, getFrameworkContent } from "../../helpers/shared/Helpers/frameworkParametrization"; -import { useNavigate } from "react-router-dom"; - -// TODO TMenuItem is not consistent with tree-like format and doesn't really fit this structure, thus special handling of the leaf nodes is required - -const onBreadcrumbPathChange = (value: TBreadcrumbPath) => {}; - -export const ExampleBreadcrumbs = () => { - const { isIFrame, currentExample, framework: selectedFramework } = useExampleRouteParams(); - const memoizedMenuPath = useMemo(() => getExampleCategoryPath(currentExample), [currentExample]); - - return ( - { - let link: string; - let title: string; - let labelContent: ReactNode; - let menuItems: TBreadcrumbItem[] = undefined; - - if (!breadcrumb.submenu) { - // leaf nodes (specific examples handling) - link = (breadcrumb as TExamplePage).path; - title = getFrameworkContent(breadcrumb.title, selectedFramework); - labelContent = getFrameworkContent(breadcrumb.title, selectedFramework) || "Loading..."; - } else if (breadcrumb.id === "home") { - // Home menu item handling - link = `/${selectedFramework}`; - title = "Home Page Gallery"; - labelContent = ( - - ); - menuItems = []; - } else { - // inner menu category handling - link = `/${selectedFramework}#${breadcrumb.id}`; - title = breadcrumb.title; - labelContent = breadcrumb.title; - } - - const label = ( - - ); - - return { link, label, title, menuItems }; - }} - breadcrumbMenuItemsMapper={(breadcrumb: TBreadcrumbItem) => { - let link: string; - let title: string; - let labelContent: ReactNode; - - if (!breadcrumb.submenu) { - // leaf nodes (specific examples handling) - link = (breadcrumb as TExamplePage).path; - title = getFrameworkContent(breadcrumb.title, selectedFramework); - labelContent = getFrameworkContent(breadcrumb.title, selectedFramework); - } else { - // inner menu category handling - link = `/${selectedFramework}#${breadcrumb.id}`; - title = breadcrumb.title; - labelContent = breadcrumb.title; - } - - const label = ( - { - e.preventDefault(); - // Handle same-page navigation - if (window.location.pathname === `/${selectedFramework}`) { - const hash = link.split("#")[1]; - const element = document.getElementById(hash); - if (element) { - element.scrollIntoView({ - behavior: "smooth", - block: "start", - }); - } - window.history.replaceState(null, "", link); - } else { - window.location.href = link; - } - }} - > - {labelContent} - - ); - - return { link, label, title }; - }} - /> - ); -}; diff --git a/Examples/src/components/Breadcrumbs/GenericBreadcrumbs.tsx b/Examples/src/components/Breadcrumbs/GenericBreadcrumbs.tsx deleted file mode 100644 index 5810d8ca9..000000000 --- a/Examples/src/components/Breadcrumbs/GenericBreadcrumbs.tsx +++ /dev/null @@ -1,208 +0,0 @@ -import { useContext, useState, MouseEvent, ReactNode } from "react"; -import { Link } from "react-router"; -import { - MenuItem, - Breadcrumbs, - ClickAwayListener, - Grow, - MenuList, - Paper, - Popper, - useMediaQuery, - Theme, -} from "@mui/material"; -import NavigateNextIcon from "@mui/icons-material/NavigateNext"; -import React from "react"; - -export type TBreadcrumbItem = { - id: string; - title: string; - submenu?: TBreadcrumbItem[]; -}; - -export type TBreadcrumbPath = (number | string)[]; - -export type TBreadcrumbProps = { link: string; label: ReactNode; title: string; menuItems?: TBreadcrumbItem[] }; - -export function BreadcrumbsWithMenu(props: { - path: TBreadcrumbPath; - items: TBreadcrumbItem[]; - onChange: (value: TBreadcrumbPath) => void; - breadcrumbPropsMapper?: (value: TBreadcrumbItem, index?: number, array?: TBreadcrumbItem[]) => TBreadcrumbProps; - breadcrumbMenuItemsMapper?: (value: TBreadcrumbItem, index?: number, array?: TBreadcrumbItem[]) => TBreadcrumbProps; -}) { - const { path, items, breadcrumbPropsMapper } = props; - - const [open, setOpen] = React.useState(false); - const [openedBreadcrumb, setOpenedBreadcrumb] = useState(null); - const [anchorEl, setAnchorEl] = React.useState(null); - const handleBreadcrumbClick = (event: React.MouseEvent, breadcrumb: TBreadcrumbNode) => { - if (breadcrumb.menuItems.length > 0) { - event.preventDefault(); - } - - setAnchorEl(event.currentTarget); - if (breadcrumb.entry.id === openedBreadcrumb?.entry?.id) { - setOpen(false); - setOpenedBreadcrumb(null); - } else { - setOpenedBreadcrumb(breadcrumb); - setOpen(true); - } - }; - - const handleClose = (event: Event | React.SyntheticEvent) => { - if (anchorEl.contains(event.target as HTMLElement)) { - return; - } - - setOpen(false); - setOpenedBreadcrumb(null); - }; - - function handleListKeyDown(event: React.KeyboardEvent) { - if (event.key === "Tab") { - event.preventDefault(); - setOpen(false); - } else if (event.key === "Escape") { - setOpen(false); - } - } - - // return focus to the button when we transitioned from !open -> open - const prevOpen = React.useRef(open); - React.useEffect(() => { - if (prevOpen.current === true && open === false) { - anchorEl.focus(); - } - - prevOpen.current = open; - }, [open]); - - /** Describes a structure that will be used for rendering the breadcrumb */ - type TBreadcrumbNode = TBreadcrumbProps & { sameLevelEntries: TBreadcrumbItem[]; entry: TBreadcrumbItem }; - - const defaultMapper = (breadcrumbItem: TBreadcrumbItem): TBreadcrumbProps => { - const label = breadcrumbItem?.title; - const title = breadcrumbItem?.title; - const link = breadcrumbItem?.id; - return { label, link, title, menuItems: undefined }; - }; - - const breadcrumbList = path.reduce( - (acc: { nodes: TBreadcrumbNode[]; submenuEntries: TBreadcrumbItem[] }, pathSegment: number | string) => { - const sameLevelEntries = acc.submenuEntries; - // TODO maybe it would be simpler to find by index - const itemEntry = sameLevelEntries?.find((menuItem) => menuItem.id === pathSegment); - - const { label, link, title, menuItems } = breadcrumbPropsMapper?.(itemEntry) ?? defaultMapper(itemEntry); - - acc.nodes.push({ - label, - link, - title, - sameLevelEntries, - entry: itemEntry, - menuItems: menuItems ?? sameLevelEntries, - }); - acc.submenuEntries = itemEntry?.submenu; - return acc; - }, - { nodes: [], submenuEntries: items } - ).nodes; - - const breadcrumbElements = breadcrumbList.map((breadcrumb) => { - const handleClick = (event: React.MouseEvent) => handleBreadcrumbClick(event, breadcrumb); - - return ( - - {breadcrumb.label} - - ); - }); - - const isXs = useMediaQuery((theme: Theme) => theme.breakpoints.down("md")); // Mobile view - - return ( - <> - } - > - {breadcrumbElements} - - - 0} - anchorEl={anchorEl} - role={undefined} - placement="bottom-start" - transition - disablePortal - sx={{ zIndex: 10 }} - > - {({ TransitionProps, placement }) => ( - - - - - {openedBreadcrumb?.menuItems?.map((item, index, collection) => { - const { label, link } = - props.breadcrumbMenuItemsMapper?.(item, index, collection) ?? - defaultMapper(item); - - return ( - - { - - {label} - - } - - ); - })} - - - - - )} - - - ); -} diff --git a/Examples/src/components/Carousel/Carousel.tsx b/Examples/src/components/Carousel/Carousel.tsx deleted file mode 100644 index dff215247..000000000 --- a/Examples/src/components/Carousel/Carousel.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import * as React from "react"; - -type TProps = { - children: React.ReactNode; -}; - -export default function Carousel(props: TProps) { - return
{props.children}
; -} diff --git a/Examples/src/components/CodePreview/CodePreview.tsx b/Examples/src/components/CodePreview/CodePreview.tsx deleted file mode 100644 index f45fc97ac..000000000 --- a/Examples/src/components/CodePreview/CodePreview.tsx +++ /dev/null @@ -1,530 +0,0 @@ -import { FC, useEffect, useState, type JSX } from "react"; -import SyntaxHighlighter from "react-syntax-highlighter"; -import { EPageFramework, FRAMEWORK_NAME } from "../../helpers/shared/Helpers/frameworkParametrization"; -import { Dialog } from "../Dialog/Dialog"; -import classes from "./index.module.scss"; -import { getFileName } from "../AppDetailsRouters/utils"; -import { ETheme } from "../../helpers/types/types"; -import "react-syntax-highlighter/dist/esm/styles/hljs/dark"; -import { IconButton } from "../buttons/IconButton"; - -const EditorLanguageMap: Record = { - ts: "typescript", - js: "javascript", - css: "css", - html: "html", - jsx: "javascript", - tsx: "typescript", - csv: "csv", - json: "json", -}; - -const DarkStyles = { - hljs: { - display: "block", - overflowX: "auto", - padding: "0.25em", - background: "#121212", // feel free to change to match var(--bg) - color: "#DCDCDC", - }, - "hljs-keyword": { - color: "#569CD6", - }, - "hljs-literal": { - color: "#569CD6", - }, - "hljs-symbol": { - color: "#569CD6", - }, - "hljs-name": { - color: "#569CD6", - }, - "hljs-link": { - color: "#569CD6", - textDecoration: "underline", - }, - "hljs-built_in": { - color: "#4EC9B0", - }, - "hljs-type": { - color: "#4EC9B0", - }, - "hljs-number": { - color: "#B8D7A3", - }, - "hljs-class": { - color: "#B8D7A3", - }, - "hljs-string": { - color: "#D69D85", - }, - "hljs-meta-string": { - color: "#D69D85", - }, - "hljs-regexp": { - color: "#9A5334", - }, - "hljs-template-tag": { - color: "#9A5334", - }, - "hljs-subst": { - color: "#DCDCDC", - }, - "hljs-function": { - color: "#DCDCDC", - }, - "hljs-title": { - color: "#DCDCDC", - }, - "hljs-params": { - color: "#DCDCDC", - }, - "hljs-formula": { - color: "#DCDCDC", - }, - "hljs-comment": { - color: "#57A64A", - fontStyle: "italic", - }, - "hljs-quote": { - color: "#57A64A", - fontStyle: "italic", - }, - "hljs-doctag": { - color: "#608B4E", - }, - "hljs-meta": { - color: "#9B9B9B", - }, - "hljs-meta-keyword": { - color: "#9B9B9B", - }, - "hljs-tag": { - color: "#9B9B9B", - }, - "hljs-variable": { - color: "#BD63C5", - }, - "hljs-template-variable": { - color: "#BD63C5", - }, - "hljs-attr": { - color: "#9CDCFE", - }, - "hljs-attribute": { - color: "#9CDCFE", - }, - "hljs-builtin-name": { - color: "#9CDCFE", - }, - "hljs-section": { - color: "gold", - }, - "hljs-emphasis": { - fontStyle: "italic", - }, - "hljs-strong": { - fontWeight: "bold", - }, - "hljs-bullet": { - color: "#D7BA7D", - }, - "hljs-selector-tag": { - color: "#D7BA7D", - }, - "hljs-selector-id": { - color: "#D7BA7D", - }, - "hljs-selector-class": { - color: "#D7BA7D", - }, - "hljs-selector-attr": { - color: "#D7BA7D", - }, - "hljs-selector-pseudo": { - color: "#D7BA7D", - }, - "hljs-addition": { - backgroundColor: "#144212", - display: "inline-block", - width: "100%", - }, - "hljs-deletion": { - backgroundColor: "#600", - display: "inline-block", - width: "100%", - }, -}; - -const LightStyles = { - hljs: { - display: "block", - overflowX: "auto", - padding: "0.25em", - background: "white", - color: "black", - }, - "hljs-comment": { - color: "#008000", - }, - "hljs-quote": { - color: "#008000", - }, - "hljs-variable": { - color: "#008000", - }, - "hljs-keyword": { - color: "#00f", - }, - "hljs-selector-tag": { - color: "#00f", - }, - "hljs-built_in": { - color: "#00f", - }, - "hljs-name": { - color: "#00f", - }, - "hljs-tag": { - color: "#00f", - }, - "hljs-string": { - color: "#a31515", - }, - "hljs-title": { - color: "#a31515", - }, - "hljs-section": { - color: "#a31515", - }, - "hljs-attribute": { - color: "#a31515", - }, - "hljs-literal": { - color: "#a31515", - }, - "hljs-template-tag": { - color: "#a31515", - }, - "hljs-template-variable": { - color: "#a31515", - }, - "hljs-type": { - color: "#a31515", - }, - "hljs-addition": { - color: "#a31515", - }, - "hljs-deletion": { - color: "#2b91af", - }, - "hljs-selector-attr": { - color: "#2b91af", - }, - "hljs-selector-pseudo": { - color: "#2b91af", - }, - "hljs-meta": { - color: "#2b91af", - }, - "hljs-doctag": { - color: "#808080", - }, - "hljs-attr": { - color: "#f00", - }, - "hljs-symbol": { - color: "#00b0e8", - }, - "hljs-bullet": { - color: "#00b0e8", - }, - "hljs-link": { - color: "#00b0e8", - }, - "hljs-emphasis": { - fontStyle: "italic", - }, - "hljs-strong": { - fontWeight: "bold", - }, -}; - -type CodeEditorProps = { - files: { name: string; content: string }[]; - selectedFile: { name: string; content: string }; - handleFileClick: (fileName: string) => void; - desiredFramework: EPageFramework; - actualFramework: EPageFramework | null; - examplePath: string; - theme: ETheme; - isMaxWidth: boolean; -}; - -const ICONS: Record = { - html: ( - - - - - - - ), - css: ( - - - - - - - ), - js: ( - - - - - ), - ts: ( - - - - - - ), - jsx: ( - - - - - - - ), - tsx: ( - - - - - - - ), - json: ( - - - - ), - csv: ( - - - - ), -}; - -export const CodePreview: FC = ({ - files, - selectedFile, - handleFileClick, - desiredFramework, - actualFramework, - examplePath, - theme, - isMaxWidth -}) => { - const [hasShownDialog, setHasShownDialog] = useState(false); - const [showDialog, setShowDialog] = useState(false); - const [hasCopied, setHasCopied] = useState(false); - - enum ECodeSizingMode { - Minimised, - Fullscreen - } - - const [codeSizing, setCodeSizing] = useState(isMaxWidth ? ECodeSizingMode.Minimised : ECodeSizingMode.Fullscreen); - const isFullscreen = codeSizing == ECodeSizingMode.Fullscreen; - - const handleMouseEnter = () => { - if (!hasShownDialog && actualFramework && actualFramework !== desiredFramework) { - setShowDialog(true); - setHasShownDialog(true); - } - }; - - function copyCurrentFile() { - navigator.clipboard.writeText(selectedFile.content); - setHasCopied(true); - setTimeout(() => { - setHasCopied(false); - }, 2000); - } - - useEffect(() => { - // Reset dialog state when example changes - setHasShownDialog(false); - setShowDialog(false); - }, [examplePath]); - - useEffect(() => { - if (isMaxWidth) { - setCodeSizing(ECodeSizingMode.Fullscreen); - } - else { - setCodeSizing(ECodeSizingMode.Minimised); - } - }, [isMaxWidth]); - - return ( -
-
- {/* VSCode-like horizontal scrollable tabs */} - {files - .sort((a, b) => { - if (a.name.includes("drawExample")) { - return -1; - } - if (b.name.includes("drawExample")) { - return 1; - } - if (a.name.includes("index")) { - return -1; - } - if (b.name.includes("index")) { - return 1; - } - return a.name.localeCompare(b.name); - }) - .map((file) => ( -
handleFileClick(file.name)} - > - {ICONS[file.name.split(".").pop() as keyof typeof ICONS]} -

{getFileName(file.name)}

-
- ))} -
- -
- {/* Copy to clipboard */} - - - - : - - - - } - selected={hasCopied} - onClick={() => copyCurrentFile()} - title={hasCopied ? "Copied!" : "Copy to clipboard"} - noPadding - /> - - {/* Minimize */} - - - } - selected={!isFullscreen} - onClick={() => setCodeSizing(ECodeSizingMode.Minimised)} - title="Minimise" - noPadding - /> - - {/* Fullscreen */} - - - } - selected={isFullscreen} - onClick={() => setCodeSizing(ECodeSizingMode.Fullscreen)} - title="Fullscreen" - noPadding - /> -
- - {/* Code */} -
- - {selectedFile.content} - -
- - setShowDialog(false)} - text={`This example will be shown in ${FRAMEWORK_NAME[actualFramework]} instead of ${FRAMEWORK_NAME[desiredFramework]}.`} - /> -
- ); -}; diff --git a/Examples/src/components/CodePreview/index.module.scss b/Examples/src/components/CodePreview/index.module.scss deleted file mode 100644 index 70b12f737..000000000 --- a/Examples/src/components/CodePreview/index.module.scss +++ /dev/null @@ -1,106 +0,0 @@ -.editorWrapper { - border: 1px solid var(--border-color); - border-radius: 12px; - padding: calc(12px + 40px) 0 12px 0; // 40px = height of horizontalScroller - width: 100%; - max-width: 100%; - height: 100%; - position: relative; - - .code { - position: absolute; - width: 100%; - height: 100%; - overflow: auto; - padding-bottom: 50px; - } - - .rightButtonGroup { - position: absolute; - display: flex; - gap: 15px; - padding: 20px; - top: 0; - right: 0; - justify-content: center; - align-items: center; - - button { - height: 24px; - width: 24px; - color: #888; - cursor: pointer; - - &:hover, &:active, &.active { - color: var(--text); - } - } - } - - &.fullscreenEditor { - position: absolute; - width: 100%; - height: 100%; - max-height: 100vh; - max-width: 100vw; - background-color: var(--bg); - } - -} - -.horizontalScroller { - position: absolute; - top: 0; - left: 0; - height: 40px; - width: calc(100% - 150px); // ~150px for the right buttons - overflow: auto; - overflow-y: hidden; - display: flex; - align-items: center; - user-select: none; - margin: 12px; - gap: 2px; - - .selectTab { - user-select: none; - display: flex; - height: 100%; - align-items: center; - justify-content: flex-start; - gap: 4px; - padding: 3px 7px 3px 5px; - cursor: pointer; - background-color: var(--bg); - border: 1px solid var(--border-color); - border-radius: 8px 8px 0 0; - white-space: nowrap; - overflow-wrap: normal; - word-break: keep-all; - - &:hover, - &.active { - background-color: #8881; - } - - svg { - height: 22px; - width: 22px; - min-height: 22px; - min-width: 22px; - } - p { - font-size: 15px; - } - } - - .selectTab.activeTab { - background-color: #8883; - position: relative; - } - - &::-webkit-scrollbar { - height: 6px; - border-radius: 0; - } -} diff --git a/Examples/src/components/CodeSandbox/CodeSandbox.module.scss b/Examples/src/components/CodeSandbox/CodeSandbox.module.scss deleted file mode 100644 index 0375f0d47..000000000 --- a/Examples/src/components/CodeSandbox/CodeSandbox.module.scss +++ /dev/null @@ -1,77 +0,0 @@ -.container { - display: flex; - flex-direction: column; - width: 100%; - position: relative; - border-radius: 12px; - overflow: hidden; - - &.browserFill { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: var(--z-index-fullscreen); - background: white; - } -} - -.toolbar { - flex: 0 0 auto; - margin-bottom: 1px; - position: relative; - z-index: 2; -} - -.frameContainer { - position: relative; - outline: none; - height: 500px; - z-index: 1; - - .browserFill & { - flex: 1; - height: 100%; - } - - &:focus { - outline: none; - } -} - -.frame { - width: 100%; - height: 100%; - border: none; -} - -.spacer { - flex: 1; -} - -.platformIcon { - display: flex; - align-items: center; - justify-content: center; - width: var(--icon-size-lg); - height: var(--icon-size-lg); -} - -.titleGroup { - display: flex; - align-items: center; - gap: 12px; - min-width: 0; -} - -.exampleName { - font-weight: 600; - font-size: 0.9em; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 300px; - padding-left: 12px; - border-left: 1px solid rgba(0, 0, 0, 0.1); -} diff --git a/Examples/src/components/CodeSandbox/CodeSandbox.tsx b/Examples/src/components/CodeSandbox/CodeSandbox.tsx deleted file mode 100644 index d3b205350..000000000 --- a/Examples/src/components/CodeSandbox/CodeSandbox.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { FC, useState, useRef } from "react"; -import styles from "./CodeSandbox.module.scss"; -import { SandboxPlatform, getEmbedUrl } from "./SandboxPlatform"; -import { EditorFrame } from "./EditorFrame"; -import { Dialog } from "../Dialog/Dialog"; -import { EPageFramework, FRAMEWORK_NAME } from "../../helpers/shared/Helpers/frameworkParametrization"; - -type TCodeSandbox = { - id: string; - fontSize?: number; - onBack?: () => void; - title?: string; - platform?: SandboxPlatform; - exampleName?: string; - desiredFramework: EPageFramework; - actualFramework: EPageFramework; -}; - -export const CodeSandbox: FC = ({ - id, - fontSize = 10, - onBack, - title, - platform = SandboxPlatform.CodeSandbox, - exampleName, - desiredFramework, - actualFramework, -}) => { - const [isLoading, setIsLoading] = useState(true); - const iframeRef = useRef(null); - const url = getEmbedUrl(platform, id, fontSize); - - const handleLoad = () => { - setIsLoading(false); - }; - - const dialogText = `This example will be shown in ${FRAMEWORK_NAME[actualFramework]} instead of ${FRAMEWORK_NAME[desiredFramework]}.`; - - return ( -
- - - - - -
${html}
- - - - - - - - - - - `; -} diff --git a/Examples/src/server/routes/MainRouter.ts b/Examples/src/server/routes/MainRouter.ts deleted file mode 100644 index 8db2dcc8d..000000000 --- a/Examples/src/server/routes/MainRouter.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { Router, static as makeStaticRouter, Request, Response, NextFunction } from "express"; -import * as defaultConfig from "../../../config/default"; -import { api } from "../api"; -import { oembed } from "./oembed"; -import { getAvailableVariants } from "./variants"; -import { exportExampleInfo } from "./exportExampleInfo"; -import { vanillaExamplesRouter } from "../vanillaDemo/vanillaExamplesRouter"; -import { EXAMPLES_PAGES } from "../../components/AppRouter/examplePages"; -import { EPageFramework } from "../../helpers/shared/Helpers/frameworkParametrization"; -import { getSourceFiles, renderSandBoxRedirect } from "../renderCodeSandboxRedirect"; -import { handleRender } from "../services/pageRender"; - -const targetDir = defaultConfig.buildConfig.targetDir; - -export const mainRouter = Router({ mergeParams: true }); - -mainRouter.use(makeStaticRouter(targetDir, { etag: true, maxAge: 0 })); -mainRouter.use("/api", api); -mainRouter.use("/services/oembed", oembed); -mainRouter.use("/services/variants", getAvailableVariants); -mainRouter.use("/services/export", exportExampleInfo); -mainRouter.use("/vanillaDemo", vanillaExamplesRouter); - -const isValidFramework = (framework: EPageFramework) => Object.values(EPageFramework).includes(framework); -const getExamplePageKey = (examplePath: string) => { - return Object.keys(EXAMPLES_PAGES).find((key) => { - const pagePath = EXAMPLES_PAGES[key]?.path; - return pagePath === examplePath; - }); -}; - -mainRouter.get("/codesandbox/:example", (req: Request, res: Response) => { - renderSandBoxRedirect(req, res, "codesandbox"); -}); - -mainRouter.get("/stackblitz/:example", (req: Request, res: Response) => { - renderSandBoxRedirect(req, res, "stackblitz"); -}); - -// TODO is this one still needed -// StackBlitz json endpoints -mainRouter.get("/json/list", (req: Request, res: Response) => { - res.json({ files: [] }); -}); - -mainRouter.get("/json/version", (req: Request, res: Response) => { - res.json({ version: "1" }); -}); - -mainRouter.get("/source/:example", (req: Request, res: Response) => { - getSourceFiles(req, res); -}); - -mainRouter.get("/iframe/codesandbox/:example", (req: Request, res: Response) => { - res.send(handleRender(req.originalUrl)); -}); - -mainRouter.get("/iframe/javascript-:example", (req: Request, res: Response) => { - const params = req.params; - if (getExamplePageKey(params.example)) { - return res.redirect(301, `${params.example}`); - } else { - res.send(handleRender(req.originalUrl)); - } -}); - -mainRouter.get("/iframe/:example?", (req: Request, res: Response) => { - res.send(handleRender(req.originalUrl)); -}); - -mainRouter.get("/javascript-:example", (req: Request, res: Response) => { - const params = req.params; - if (getExamplePageKey(params.example)) { - return res.redirect(301, `javascript/${params.example}`); - } else { - res.send(handleRender(req.originalUrl)); - } -}); - -// This is doing some useful things in handling framework defaults -mainRouter.get("/:example?", (req: Request, res: Response) => { - const params = req.params; - const exampleKey = getExamplePageKey(params.example); - if (isValidFramework(params.example as EPageFramework)) { - res.send(handleRender(req.originalUrl)); - } else if (exampleKey) { - const redirectUrl = `react/${params.example}`; - res.redirect(301, redirectUrl); - } else { - res.redirect(301, `react`); - } -}); - -mainRouter.get("*", (req: Request, res: Response) => { - res.send(handleRender(req.originalUrl)); -}); diff --git a/Examples/src/server/routes/exportExampleInfo.ts b/Examples/src/server/routes/exportExampleInfo.ts deleted file mode 100644 index a6f5a4e85..000000000 --- a/Examples/src/server/routes/exportExampleInfo.ts +++ /dev/null @@ -1,46 +0,0 @@ -import express from "express"; -var url = require("url"); -import * as fs from "fs"; -import { EXAMPLES_PAGES } from "../../components/AppRouter/examplePages"; -import { TFrameworkName, TFrameworkTemplate } from "../../helpers/shared/Helpers/frameworkParametrization"; - -const router = express.Router(); - -const getContent = (item: TFrameworkTemplate) => { - if (!item) return ""; - return typeof item === "string" ? item : item("{framework}" as unknown as TFrameworkName); -}; - -router.get("/", async (req, res) => { - const dataList = []; - let csv = `path;title;pageTitle;subtitle;metaDescription;metaKeywords;markdownContent;documentationLinks`; - for (const exampleKey in EXAMPLES_PAGES) { - const exampleInfo = EXAMPLES_PAGES[exampleKey]; - const item = { - path: exampleInfo.path, - title: getContent(exampleInfo.title), - pageTitle: getContent(exampleInfo.pageTitle), - subtitle: exampleInfo.subtitle("{framework}"), - metaDescription: getContent(exampleInfo.metaDescription), - metaKeywords: exampleInfo.metaKeywords, - markdownContent: getContent(exampleInfo.markdownContent).toString(), - documentationLinks: exampleInfo.documentationLinks, - }; - const subtitle = JSON.stringify(exampleInfo.subtitle("{framework}"), (key, value) => - ["key", "ref", "_owner"].includes(key) ? undefined : value - ); - const line = `^${item.path}^;^${item.title}^;^${item.pageTitle}^;^${subtitle}^;^${item.metaDescription}^;^${ - item.metaKeywords - }^;^${item.markdownContent}^;^${JSON.stringify(item.documentationLinks)}^`; - dataList.push(item); - csv += "\n" + line; - } - fs.writeFileSync( - "exampleInfo.json", - JSON.stringify(dataList, (key, value) => (["key", "ref", "_owner"].includes(key) ? undefined : value)) - ); - fs.writeFileSync("exampleInfo.csv", csv); - res.send(dataList); -}); - -export { router as exportExampleInfo }; diff --git a/Examples/src/server/routes/oembed.ts b/Examples/src/server/routes/oembed.ts deleted file mode 100644 index 52e70b1a8..000000000 --- a/Examples/src/server/routes/oembed.ts +++ /dev/null @@ -1,41 +0,0 @@ -import express from "express"; -import { parse as parseUrl } from "url"; -import { EXAMPLES_PAGES } from "../../components/AppRouter/examplePages"; -import { getFrameworkContent, EPageFramework } from "../../helpers/shared/Helpers/frameworkParametrization"; - -const router = express.Router(); - -class OEmbedResponse { - type: "link"; - version: "1.0"; - title: string; - author_name: string = "SciChart.js"; - author_url: string; - provider_name: string = "SciChart.js Demo"; - provider_url: string = "https://demo.scichart.com"; - thumbnail_url: string; - thumbnail_width: string = "900"; - thumbnail_height: string = "900"; - description: string; - //html: string; -} - -router.get("/", (req, res) => { - const requestUrl = req.query["url"] as string; - const location = parseUrl(requestUrl, true); - const examplePath = (location.pathname as string).substring(location.pathname.lastIndexOf("/") + 1); - const currentExampleKey = Object.keys(EXAMPLES_PAGES).find((key) => EXAMPLES_PAGES[key].path === examplePath); - if (currentExampleKey) { - const currentExample = EXAMPLES_PAGES[currentExampleKey]; - const oEmbedResponse = new OEmbedResponse(); - oEmbedResponse.title = getFrameworkContent(currentExample.title, EPageFramework.Vanilla); - oEmbedResponse.description = getFrameworkContent(currentExample.metaDescription, EPageFramework.Vanilla); - oEmbedResponse.author_url = oEmbedResponse.provider_url + "/" + currentExample.path; - oEmbedResponse.thumbnail_url = oEmbedResponse.provider_url + "/" + currentExample.thumbnailImage; - res.send(oEmbedResponse); - } else { - res.status(404).send("Example not found"); - } -}); - -export { router as oembed }; diff --git a/Examples/src/server/routes/variants.ts b/Examples/src/server/routes/variants.ts deleted file mode 100644 index 23eac7052..000000000 --- a/Examples/src/server/routes/variants.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as path from "path"; -import express from "express"; -import { getRequestedExample } from "../renderCodeSandboxRedirect"; -import { getAngularSrc } from "../services/sandbox/angularConfig"; -import { getVanillaSrc } from "../services/sandbox/vanillaTsConfig"; -import { EPageFramework } from "../../helpers/shared/Helpers/frameworkParametrization"; -import { IHttpError } from "../Errors"; - -const router = express.Router(); -const basePath = path.join(__dirname, "Examples"); - -router.get("/:example", async (req, res) => { - try { - const currentExample = getRequestedExample(req, res)?.currentExample; - const folderPath = path.join(basePath, currentExample.filepath); - const [vanillaSrcFetchResult, angularSrcFetchResult] = await Promise.allSettled([ - getVanillaSrc(folderPath), - getAngularSrc(folderPath), - ]); - const vanillaSrc = vanillaSrcFetchResult.status === "fulfilled" && vanillaSrcFetchResult.value; - const angularSrc = angularSrcFetchResult.status === "fulfilled" && angularSrcFetchResult.value; - return res.send({ [EPageFramework.Vanilla]: vanillaSrc, [EPageFramework.Angular]: angularSrc }); - } catch (err) { - const error = err as IHttpError; - return res.status(error.status ?? 500).send(error.status && error.message); - } -}); - -export { router as getAvailableVariants }; diff --git a/Examples/src/server/server.tsx b/Examples/src/server/server.tsx deleted file mode 100644 index 6dfb782bc..000000000 --- a/Examples/src/server/server.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import express from "express"; -import cors from "cors"; -import compression from "compression"; -import { Request, Response } from "express"; -import * as bodyParser from "body-parser"; -import chalk from "chalk"; - -import * as http from "http"; - -import { createSocketServer } from "./websockets"; -import { populateSourceFilesCache } from "./renderCodeSandboxRedirect"; -import { populatePrerenderedPageCache } from "./services/pageRender"; -import { mainRouter } from "./routes/MainRouter"; -import { morganMiddleware } from "./middlewares/loggingMiddleware"; -import { baseAppPath } from "../constants"; - -const port = parseInt(process.env.PORT || "3000", 10); -const host = process.env.HOST || "localhost"; - -const app = express(); -app.use(bodyParser.urlencoded({ extended: false })); -app.use(bodyParser.json()); -app.use(cors()); -app.use(compression({ filter: shouldCompress })); -// enables requests logging -app.use(morganMiddleware); -app.use(baseAppPath, mainRouter); - -const server = http.createServer(app); -const io = createSocketServer(server); - -function shouldCompress(req: Request, res: Response) { - if (req.headers["x-no-compression"]) { - return false; - } - return compression.filter(req, res); -} - -// Prerendered pages cache structure of URL/HTML pairs -populateSourceFilesCache() - .then(populatePrerenderedPageCache) - .then(() => { - server.listen(port, () => { - console.log( - `Serving at http://${host}:${port}${baseAppPath} ${chalk.green("โœ“")}. ${chalk.red( - "To run in dev mode: npm run dev" - )}` - ); - }); - }); diff --git a/Examples/src/server/services/logging.ts b/Examples/src/server/services/logging.ts deleted file mode 100644 index 78ee6c2cd..000000000 --- a/Examples/src/server/services/logging.ts +++ /dev/null @@ -1,47 +0,0 @@ -import winston from "winston"; - -const levels = { - error: 0, - warn: 1, - info: 2, - http: 3, - debug: 4, -}; - -const level = () => { - const env = process.env.NODE_ENV || "development"; - const isDevelopment = env === "development"; - return isDevelopment ? "debug" : "http"; -}; - -const colors = { - error: "red", - warn: "yellow", - info: "green", - http: "magenta", - debug: "white", -}; - -winston.addColors(colors); - -const format = winston.format.combine( - winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss:ms" }), - winston.format.colorize({ all: true }), - winston.format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`) -); - -const transports = [ - new winston.transports.Console(), - new winston.transports.File({ - filename: "logs/error.log", - level: "error", - }), - new winston.transports.File({ filename: "logs/all.log" }), -]; - -export const Logger = winston.createLogger({ - level: level(), - levels, - format, - transports, -}); diff --git a/Examples/src/server/services/pageRender/index.ts b/Examples/src/server/services/pageRender/index.ts deleted file mode 100644 index b869943f0..000000000 --- a/Examples/src/server/services/pageRender/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { EXAMPLES_PAGES } from "../../../components/AppRouter/examplePages"; -import { baseAppPath } from "../../../constants"; -import { EPageFramework } from "../../../helpers/shared/Helpers/frameworkParametrization"; -import { getCachedSourceFiles } from "../../renderCodeSandboxRedirect"; -import { renderPage } from "./reactSsr"; - -const pageHtmlCache = new Map(); - -export function handleRender(url: string) { - const cachedPageHtml = pageHtmlCache.get(url); - if (cachedPageHtml) { - return cachedPageHtml; - } else { - console.warn("render on demand", url); - const pageHtml = renderPage(url); - return pageHtml; - } -} -export function populatePrerenderedPageCache() { - for (let framework of Object.values(EPageFramework)) { - // generate homepage - const url = `${baseAppPath}/${framework}`; - const pageHtml = renderPage(url); - pageHtmlCache.set(url, pageHtml); - - // generate example pages - for (let key in EXAMPLES_PAGES) { - const exampleRoute = EXAMPLES_PAGES[key].path; - const url = `${baseAppPath}/${framework}/${exampleRoute}`; - const sourceFileInfo = getCachedSourceFiles(key, framework); - const pageHtml = renderPage(url, sourceFileInfo); - pageHtmlCache.set(url, pageHtml); - - const iFrameUrl = `${baseAppPath}/iframe/${exampleRoute}`; - const fullScreenExampleHtml = renderPage(iFrameUrl, sourceFileInfo); - pageHtmlCache.set(iFrameUrl, fullScreenExampleHtml); - } - } -} diff --git a/Examples/src/server/services/pageRender/reactSsr.tsx b/Examples/src/server/services/pageRender/reactSsr.tsx deleted file mode 100644 index f905edb93..000000000 --- a/Examples/src/server/services/pageRender/reactSsr.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { Helmet } from "react-helmet"; -import * as ReactDOMServer from "react-dom/server"; -import { StaticRouter } from "react-router"; -import { ThemeProvider } from "@mui/material/styles"; -import { CacheProvider } from "@emotion/react"; -import createCache from "@emotion/cache"; -import createEmotionServer from "@emotion/server/create-instance"; - -import App from "../../../components/App"; -import { customTheme } from "../../../theme"; -import { - defaultSourceFilesVariant, - SourceFilesContext, -} from "../../../components/AppDetailsRouters/SourceFilesLoading/SourceFilesContext"; -import { SourceFilesVariant } from "../../../helpers/types/types"; -import { renderIndexHtml } from "../../renderIndexHtml"; -import createEmotionCache from "../../../createEmotionCache"; -import { baseAppPath } from "../../../constants"; - -export function renderPage(url: string, sourceFilesInfo: SourceFilesVariant = defaultSourceFilesVariant) { - // Create an emotion cache for SSR - const cache = createEmotionCache(); - const { extractCriticalToChunks, constructStyleTagsFromChunks } = createEmotionServer(cache); - - // Render the component to a string. - const appHtml = ReactDOMServer.renderToString( - - - - - - - - - - ); - - // Extract the critical CSS - const emotionChunks = extractCriticalToChunks(appHtml); - const emotionCss = constructStyleTagsFromChunks(emotionChunks); - - // SEO tags - const helmet = Helmet.renderStatic(); - - return renderIndexHtml(appHtml, emotionCss, helmet); -} diff --git a/Examples/src/server/services/sandbox/angularConfig.ts b/Examples/src/server/services/sandbox/angularConfig.ts deleted file mode 100644 index 710e9d7dc..000000000 --- a/Examples/src/server/services/sandbox/angularConfig.ts +++ /dev/null @@ -1,304 +0,0 @@ -import path from "path"; -import fs from "fs"; - -import { TExampleInfo } from "../../../components/AppRouter/examplePages"; -import { NotFoundError } from "../../Errors"; -import { - IFiles, - includeImportedModules, - includeExternalModules, - commonFiles, - SandboxConfig, -} from "./sandboxDependencyUtils"; -import { SCICHART_ANCHOR, SCICHART_VERSION } from "./constants"; - -const pj = require("../../../../package.json"); - -export const getAngularSrc = async (folderPath: string) => { - let code: string; - const tsPath = path.join(folderPath, "angular.ts"); - try { - code = await fs.promises.readFile(tsPath, "utf8"); - } catch (err) { - throw new NotFoundError("Angular version not found! Try using different framework."); - } - - return code; -}; - -export const getAngularSandBoxConfig = async ( - folderPath: string, - currentExample: TExampleInfo, - baseUrl: string -): Promise => { - let code = await getAngularSrc(folderPath); - - let files: IFiles = {}; - await includeImportedModules(folderPath, files, code, true, true, baseUrl); - - code = code.replace(/\.\.\/.*styles\/Examples\.module\.scss/, `./styles/Examples.module.scss`); - code = await includeExternalModules(folderPath, folderPath, files, code, true, true); - code = code.replace(/(\.\/)/g, "../"); - files = { - ...commonFiles, - ...files, - "package.json": { - // @ts-ignore - content: { - name: currentExample.path, - version: "1.0.0", - scripts: { - ng: "ng", - start: "ng serve", - build: "ng build", - watch: "ng build --watch --configuration development", - test: "ng test", - }, - private: true, - dependencies: { - "@angular/animations": "^18.2.0", - "@angular/common": "^18.2.0", - "@angular/compiler": "^18.2.0", - "@angular/core": "^18.2.0", - "@angular/forms": "^18.2.0", - "@angular/platform-browser": "^18.2.0", - "@angular/platform-browser-dynamic": "^18.2.0", - "@angular/router": "^18.2.0", - "@angular/material": "^18.2.8", - "@angular/cdk": "^18.1.0", - rxjs: "~7.8.0", - // scichart: pj.dependencies.scichart, - scichart: SCICHART_VERSION, - "scichart-angular": pj.dependencies["scichart-angular"], - tslib: "^2.3.0", - "zone.js": "~0.14.10", - - "@angular-devkit/build-angular": "^18.2.8", - "@angular/cli": "^18.2.8", - "@angular/compiler-cli": "^18.2.0", - "@types/jasmine": "~5.1.0", - "jasmine-core": "~5.2.0", - karma: "~6.4.0", - "karma-chrome-launcher": "~3.2.0", - "karma-coverage": "~2.2.0", - "karma-jasmine": "~5.1.0", - "karma-jasmine-html-reporter": "~2.1.0", - typescript: "5.5.2", - }, - }, - }, - ".devcontainer/devcontainer.json": { - isBinary: false, - content: `{ - "name": "Devcontainer", - "image": "ghcr.io/codesandbox/devcontainers/typescript-node:latest", - "customizations": { - "vscode": { - "extensions": [ - "Angular.ng-template" - ] - } - } -}`, - }, - ".codesandbox/tasks.json": { - isBinary: false, - content: `{ - // These tasks will run in order when initializing your CodeSandbox project. - "setupTasks": [ - { - "name": "Install Dependencies", - "command": "npm install --legacy-peer-deps" - } - ], - - // These tasks can be run from CodeSandbox. Running one will open a log in the app. - "tasks": { - "start": { - "name": "start", - "command": "npm run start", - "runAtStart": true, - "preview": { - "port": 4200 - } - } - } -}`, - }, - "angular.json": { - content: `{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "cli": { - "analytics": false - }, - "newProjectRoot": "projects", - "projects": { - "template": { - "projectType": "application", - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:application", - "options": { - "outputPath": "dist/template", - "index": "src/index.html", - "browser": "src/main.ts", - "polyfills": [ - "zone.js" - ], - "tsConfig": "tsconfig.json", - "assets": [ - { - "glob": "**/*", - "input": "public" - } - ], - "scripts": [] - }, - "configurations": { - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "template:build:production" - }, - "development": { - "buildTarget": "template:build:development" - } - }, - "defaultConfiguration": "development" - } - } - } - } -} -`, - isBinary: false, - }, - "tsconfig.json": { - content: `/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ - /* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ - { - "compileOnSave": false, - "compilerOptions": { - "outDir": "./dist/out-tsc", - "strict": false, - "noImplicitOverride": true, - "strictPropertyInitialization": false, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "skipLibCheck": true, - "isolatedModules": true, - "esModuleInterop": true, - "sourceMap": true, - "declaration": false, - "experimentalDecorators": true, - "moduleResolution": "bundler", - "importHelpers": true, - "target": "ES2022", - "module": "ES2022", - "lib": [ - "ES2022", - "dom" - ] - }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } - } - `, - isBinary: false, - }, - "src/app/app.component.ts": { - content: code, - isBinary: false, - }, - "src/app/app-wrapper.component.ts": { - content: `import { Component, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; -import { AppComponent } from './app.component'; -import { SciChartSurface, SciChart3DSurface } from 'scichart'; - -SciChartSurface.UseCommunityLicense(); -SciChartSurface.loadWasmFromCDN(); -SciChart3DSurface.loadWasmFromCDN(); - -@Component({ - selector: 'app-root', - template: '', - standalone: true, -}) -export class AppWrapperComponent implements OnInit { - constructor(private container: ViewContainerRef) {} - ngOnInit(): void { - this.container.createComponent(AppComponent); - } -} -`, - isBinary: false, - }, - "src/main.ts": { - content: `import { bootstrapApplication } from '@angular/platform-browser'; -import { AppWrapperComponent } from './app/app-wrapper.component'; -import 'zone.js'; - -bootstrapApplication(AppWrapperComponent).catch((err) => console.error(err));`, - isBinary: false, - }, - "src/index.html": { - content: ` - - - - Angular Scichart App - - - - - - ${SCICHART_ANCHOR} - -`, - isBinary: false, - }, - "readme.md": { - content: `# Angular ${currentExample.path} Example - This sandbox uses Angular 15 to be compatible with the codesandbox.io, - but you can use it with the latest Angular version. - `, - isBinary: false, - }, - "sandbox.config.json": { - isBinary: false, - content: `{ -"infiniteLoopProtection": false, -"hardReloadOnChange": false, -"view": "browser", -"template": "node" -}`, - }, - }; - - if (currentExample.sandboxConfig) { - files["sandbox.config.json"] = { - // @ts-ignore - content: currentExample.sandboxConfig, - isBinary: false, - }; - } - return { files: { ...files } }; -}; diff --git a/Examples/src/server/services/sandbox/constants.ts b/Examples/src/server/services/sandbox/constants.ts deleted file mode 100644 index e5c5f6234..000000000 --- a/Examples/src/server/services/sandbox/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const SCICHART_ANCHOR = `Created with Scichart.js High Performance Javascript Charts`; -export const SCICHART_VERSION = "^3.5"; diff --git a/Examples/src/server/services/sandbox/index.ts b/Examples/src/server/services/sandbox/index.ts deleted file mode 100644 index fb7a04617..000000000 --- a/Examples/src/server/services/sandbox/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { TExampleInfo } from "../../../components/AppRouter/examplePages"; -import { EPageFramework } from "../../../helpers/shared/Helpers/frameworkParametrization"; -import { getAngularSandBoxConfig } from "./angularConfig"; -import { getVanillaTsSandBoxConfig } from "./vanillaTsConfig"; -import { handleInvalidFrameworkValue, IFiles, SandboxConfig } from "./sandboxDependencyUtils"; -import { getReactSandBoxConfig } from "./reactConfig"; -import { NotFoundError } from "../../Errors"; - -export const getSandboxConfig = async ( - folderPath: string, - currentExample: TExampleInfo, - framework: EPageFramework, - baseUrl: string -): Promise => { - try { - switch (framework) { - case EPageFramework.Angular: - return { - ...(await getAngularSandBoxConfig(folderPath, currentExample, baseUrl)), - actualFramework: EPageFramework.Angular, - }; - // case EPageFramework.Vue: - // throw new Error("Not Implemented"); - case EPageFramework.React: - return { - ...(await getReactSandBoxConfig(folderPath, currentExample, baseUrl)), - actualFramework: EPageFramework.React, - }; - case EPageFramework.Vanilla: - try { - return { - ...(await getVanillaTsSandBoxConfig(folderPath, currentExample, baseUrl)), - actualFramework: EPageFramework.Vanilla, - }; - } catch (err) { - // If vanilla files not found, fallback to React - if (err instanceof NotFoundError || (err as any).status === 404) { - console.log("Vanilla version not found, falling back to React"); - return { - ...(await getReactSandBoxConfig(folderPath, currentExample, baseUrl)), - actualFramework: EPageFramework.React, - }; - } - throw err; - } - default: - return handleInvalidFrameworkValue(framework); - } - } catch (err) { - // If any framework fails and it's not React, try React as fallback - if (framework !== EPageFramework.React) { - console.log(`${framework} version failed, falling back to React`); - return { - ...(await getReactSandBoxConfig(folderPath, currentExample, baseUrl)), - actualFramework: EPageFramework.React, - }; - } - throw err; - } -}; diff --git a/Examples/src/server/services/sandbox/reactConfig.ts b/Examples/src/server/services/sandbox/reactConfig.ts deleted file mode 100644 index b92033d44..000000000 --- a/Examples/src/server/services/sandbox/reactConfig.ts +++ /dev/null @@ -1,117 +0,0 @@ -import path from "path"; -import fs from "fs"; -import { TExampleInfo } from "../../../components/AppRouter/examplePages"; -import { - SandboxConfig, - IFiles, - includeImportedModules, - includeExternalModules, - commonFiles, - csStyles, -} from "./sandboxDependencyUtils"; -import { SCICHART_ANCHOR, SCICHART_VERSION } from "./constants"; - -const pj = require("../../../../package.json"); - -export const getReactSandBoxConfig = async ( - folderPath: string, - currentExample: TExampleInfo, - baseUrl: string -): Promise => { - const tsPath = path.join(folderPath, "index.tsx"); - let code = await fs.promises.readFile(tsPath, "utf8"); - let files: IFiles = {}; - await includeImportedModules(folderPath, files, code, true, true, baseUrl); - code = code.replace(/\.\.\/.*styles\/Examples\.module\.scss/, `./styles/Examples.module.scss`); - code = await includeExternalModules(folderPath, folderPath, files, code, true, true); - // console.log("creating sandbox", currentExample.title, currentExample.path.replace("/", "")); - // for (const f in files) { - // console.log(f); - // } - files = { - ...commonFiles, - ...files, - "package.json": { - // @ts-ignore - content: { - name: currentExample.path.replace("/", ""), - version: "1.0.0", - main: "src/index.tsx", - scripts: { - start: "react-scripts start", - build: "react-scripts build", - test: "react-scripts test --env=jsdom", - eject: "react-scripts eject", - }, - dependencies: { - "@emotion/react": "^11.13.3", - "@emotion/styled": "^11.13.0", // peer dependency of @mui/material - "@mui/material": "^5.15.20", // Change to MUI v5 - "@mui/lab": "^5.0.0-alpha.170", - "@mui/icons-material": "^5.15.20", - "tss-react": "^4.9.13", - sass: "^1.49.9", - "loader-utils": "3.2.1", - react: "^18.3.1", - "react-dom": "^18.3.1", - "react-scripts": "5.0.1", - // scichart: pj.dependencies.scichart, - scichart: SCICHART_VERSION, - "scichart-react": pj.dependencies["scichart-react"], - typescript: pj.devDependencies.typescript, - ...currentExample.extraDependencies, - "@types/react": "^18.3.11", - "@types/react-dom": "^18.3.1", - "@babel/runtime": "7.13.8", - }, - browserslist: [">0.2%", "not dead", "not ie <= 11", "not op_mini all"], - }, - isBinary: false, - }, - "src/App.tsx": { - content: code, - isBinary: false, - }, - "src/index.tsx": { - content: ` -import { createRoot, hydrateRoot } from "react-dom/client"; - -import { SciChartSurface, SciChart3DSurface } from "scichart"; - -import App from "./App"; - -const rootElement = document.getElementById("root"); - -SciChartSurface.UseCommunityLicense(); -SciChartSurface.loadWasmFromCDN(); -SciChart3DSurface.loadWasmFromCDN(); - -const root = createRoot(rootElement) -root.render(<>${SCICHART_ANCHOR}); -`, - isBinary: false, - }, - "public/index.html": { - content: ` - - - React App - - - -
- - `, - isBinary: false, - }, - }; - - if (currentExample.sandboxConfig) { - files["sandbox.config.json"] = { - // @ts-ignore - content: currentExample.sandboxConfig, - isBinary: false, - }; - } - return { files: { ...files, ...csStyles } }; -}; diff --git a/Examples/src/server/services/sandbox/sandboxDependencyUtils.ts b/Examples/src/server/services/sandbox/sandboxDependencyUtils.ts deleted file mode 100644 index abaa9f3fd..000000000 --- a/Examples/src/server/services/sandbox/sandboxDependencyUtils.ts +++ /dev/null @@ -1,234 +0,0 @@ -import * as path from "path"; -import * as fs from "fs"; - -export interface IFiles { - [key: string]: { - content: string; - isBinary: boolean; - }; -} - -export let csStyles: IFiles; -export const loadStyles = async (folderPath: string) => { - if (!csStyles) { - const basePath = path.join(folderPath, "styles", "_base.scss"); - const base = await fs.promises.readFile(basePath, "utf8"); - const mixinsPath = path.join(folderPath, "styles", "mixins.scss"); - const mixins = await fs.promises.readFile(mixinsPath, "utf8"); - const examplesPath = path.join(folderPath, "styles", "Examples.module.scss"); - const examples = await fs.promises.readFile(examplesPath, "utf8"); - csStyles = { - "src/styles/_base.scss": { content: base, isBinary: false }, - "src/styles/mixins.scss": { content: mixins, isBinary: false }, - "src/styles/Examples.module.scss": { content: examples, isBinary: false }, - }; - } -}; - -export type SandboxConfig = { files: IFiles }; - -export const handleInvalidFrameworkValue = (value: never): never => { - throw new Error(`Invalid framework value=${value}!`); -}; - -export const includeExternalModules = async ( - examplefolderPath: string, - folderPath: string, - files: IFiles, - content: string, - includeImages: boolean, - updateImports: boolean -) => { - // Pull files outside the local folder into it and rewrite the import - const externalImports = Array.from(content.matchAll(/from "([\.\/]+)(.*)";/g)); - if (externalImports.length > 0) { - for (const externalImport of externalImports) { - if (externalImport.length > 1) { - if (externalImport[2].endsWith(".scss")) continue; - if (externalImport[2].endsWith(".png") || externalImport[2].endsWith(".jpg")) { - if (includeImages) { - // handle images - const csPath = "src/" + externalImport[2]; - const filename = externalImport[2].substring(externalImport[2].lastIndexOf("/") + 1); - files[csPath] = { content: "https://demo.scichart.com/images/" + filename, isBinary: true }; - } - } else { - const filepath = path.join(folderPath, externalImport[1] + externalImport[2] + ".ts"); - const filename = externalImport[2].substring(externalImport[2].lastIndexOf("/") + 1); - let csPath = filepath.replace(examplefolderPath, "src").replace(/\\/g, "/"); - if (updateImports) { - if (!filepath.includes(examplefolderPath)) { - csPath = "src/" + filename + ".ts"; - content = content.replace(externalImport[1] + externalImport[2], "./" + filename); - //console.log("Updating import", filepath, csPath, externalImport[1] + externalImport[2]); - } - } - const csPathx = csPath + "x"; - if (!files[csPath] && !files[csPathx]) { - try { - const externalContent = await fs.promises.readFile(filepath, "utf8"); - //console.log(filepath); - files[csPath] = { content: externalContent, isBinary: false }; - } catch { - const filepathx = filepath + "x"; - try { - const externalContentx = await fs.promises.readFile(filepathx, "utf8"); - files[csPathx] = { content: externalContentx, isBinary: false }; - } catch { - console.log(externalImport[2], "not found at", filepath, "from", folderPath); - files[csPath] = { content: "Could not load source", isBinary: false }; - } - } - } - } - } - } - } - return content; -}; - -export const includeImportedModules = async ( - folderPath: string, - files: IFiles, - code: string, - includeImages: boolean, - updateImports: boolean, - baseUrl: string -) => { - const localImports = Array.from(code.matchAll(/from ["']\.\/(.*)["'];/g)); - for (const localImport of localImports) { - if (localImport.length > 1) { - let content: string = ""; - let csPath: string = ""; - let dirname: string = ""; - if (localImport[1].endsWith(".png") || localImport[1].endsWith(".jpg")) { - if (includeImages) { - // handle images - csPath = "src/" + localImport[1]; - const filename = localImport[1].substring(localImport[1].lastIndexOf("/") + 1); - files[csPath] = { content: baseUrl + filename, isBinary: true }; - } - } else { - csPath = "src/" + localImport[1] + ".ts"; - const csxPath = "src/" + localImport[1] + ".tsx"; - if (!files[csPath] && !files[csxPath]) { - try { - const filepath = path.join(folderPath, localImport[1] + ".ts"); - //console.log(csPath); - content = await fs.promises.readFile(filepath, "utf8"); - dirname = path.dirname(filepath); - } catch (e) { - try { - const filepath = path.join(folderPath, localImport[1] + ".tsx"); - //console.log("not found. trying ", filepath); - csPath = "src/" + localImport[1] + ".tsx"; - content = await fs.promises.readFile(filepath, "utf8"); - dirname = path.dirname(filepath); - } catch { - console.log(localImport[1], "not loaded for", folderPath); - content = "could not load source"; - } - } - if (!localImport[1].includes("/")) { - // this only works if the import is in the base folder - const nestedImports = Array.from(content.matchAll(/from "\.\/(.*)";/g)); - if (nestedImports.length > 0) { - localImports.push(...nestedImports); - } - } - //console.log("processing externals for", localImport[1]); - content = await includeExternalModules( - folderPath, - dirname, - files, - content, - includeImages, - updateImports - ); - files[csPath] = { content, isBinary: false }; - } - } - } - } - // stylesheets - const cssImports = Array.from(code.matchAll(/import ["']\.\/(.*\.css)["'];/g)); - for (const cssImport of cssImports) { - if (cssImport.length > 1) { - const csPath = "src/" + cssImport[1]; - const filepath = path.join(folderPath, cssImport[1]); - const content = await fs.promises.readFile(filepath, "utf8"); - files[csPath] = { content, isBinary: false }; - } - } -}; - -export const getSourceFilesForPath = async (folderPath: string, startFile: string, baseUrl: string) => { - const tsPath = path.join(folderPath, startFile); - let code = await fs.promises.readFile(tsPath, "utf8"); - let files: IFiles = {}; - await includeImportedModules(folderPath, files, code, false, false, baseUrl); - code = code.replace(/\.\.\/.*styles\/Examples\.module\.scss/, `./styles/Examples.module.scss`); - await includeExternalModules(folderPath, folderPath, files, code, false, false); - files[tsPath] = { content: code, isBinary: false }; - return files; -}; - -export const commonFiles: IFiles = { - "tsconfig.json": { - content: `{ -"include": [ - "./src/**/*" -], -"compilerOptions": { - "strict": false, - "strictPropertyInitialization": false, - "esModuleInterop": true, - "target": "es5", - "downlevelIteration": true, - "lib": [ - "dom", - "es2015" - ], - "typeRoots": ["./src/types", "./node_modules/@types"], - "jsx": "react-jsx" -} -}`, - isBinary: false, - }, - "sandbox.config.json": { - content: `{ -"infiniteLoopProtection": false, -"hardReloadOnChange": false, -"view": "browser" -}`, - isBinary: false, - }, - "src/types/declaration.d.ts": { - content: `declare module "*.scss" { - const content: Record; - export default content; - }`, - isBinary: false, - }, - "src/types/jpg.d.ts": { - content: `declare module "*.jpg" { - const value: any; - export default value; - }`, - isBinary: false, - }, - "src/types/png.d.ts": { - content: `declare module "*.png" { - const value: any; - export default value; - } `, - isBinary: false, - }, - "src/types/svg.d.ts": { - content: `declare module "*.svg" { - const value: any; - export default value; - }`, - isBinary: false, - }, -}; diff --git a/Examples/src/server/services/sandbox/vanillaTsConfig.ts b/Examples/src/server/services/sandbox/vanillaTsConfig.ts deleted file mode 100644 index 8f5020193..000000000 --- a/Examples/src/server/services/sandbox/vanillaTsConfig.ts +++ /dev/null @@ -1,168 +0,0 @@ -import * as path from "path"; -import * as fs from "fs"; -import { NotFoundError } from "../../Errors"; -import { TExampleInfo } from "../../../components/AppRouter/examplePages"; -import { IFiles, csStyles, includeImportedModules } from "./sandboxDependencyUtils"; - -const pj = require("../../../../package.json"); - -const vanillaIndexCode = `import "./src/common"; -import "./src/app"; -`; - -const vanillaCommonCode = `import { SciChart3DSurface, SciChartSurface } from "scichart"; - -SciChartSurface.loadWasmFromCDN(); -SciChart3DSurface.loadWasmFromCDN(); -`; - -export const indexHtmlTemplate = (customChartSetup?: string) => ` - - - SciChart Example - - - - - ${customChartSetup ?? `
`} - -`; - -export const getVanillaSrc = async (folderPath: string) => { - const tsPath = path.join(folderPath, "vanilla.ts"); - let code: string; - try { - code = await fs.promises.readFile(tsPath, "utf8"); - } catch (err) { - throw new NotFoundError("Vanilla version not found! Try using different framework."); - } - - return code; -}; - -export const getVanillaTsSandBoxConfig = async (folderPath: string, currentExample: TExampleInfo, baseUrl: string) => { - let code = await getVanillaSrc(folderPath); - - code = code.replace(/\.\.\/.*styles\/Examples\.module\.scss/, `./styles/Examples.module.scss`); - - let htmlCode = indexHtmlTemplate(); - - try { - const indexHtmlPath = path.join(folderPath, "index.html"); - const charHtmlSetup = await fs.promises.readFile(indexHtmlPath, "utf8"); - htmlCode = indexHtmlTemplate(charHtmlSetup); - } catch (err) {} - - let files: IFiles = { - "package.json": { - // @ts-ignore - content: { - name: currentExample.path.replace("/", ""), - version: "1.0.0", - main: "index.ts", - scripts: { - start: "parcel index.html", - build: "parcel build index.html", - }, - dependencies: { - scichart: pj.dependencies.scichart, - "parcel-bundler": "1.6.1", - ...currentExample.extraDependencies, - }, - devDependencies: { - typescript: "4.9.5", - }, - browserslist: [">0.2%", "not ie <= 11", "not op_mini all"], - resolutions: { - "@babel/preset-env": "7.13.8", - }, - keywords: ["typescript", "javascript", "chart", "scichart"], - }, - }, - "index.ts": { - content: vanillaIndexCode, - isBinary: false, - }, - "src/common.ts": { - content: vanillaCommonCode, - isBinary: false, - }, - - "src/app.ts": { - content: code, - isBinary: false, - }, - "tsconfig.json": { - content: `{ - "include": [ - "./src/**/*" - ], - "compilerOptions": { - "strict": false, - "esModuleInterop": true, - "target": "es5", - "downlevelIteration": true, - "lib": [ - "dom", - "es2015" - ], - "typeRoots": ["./src/types", "./node_modules/@types"], - "jsx": "react-jsx" - } -}`, - isBinary: false, - }, - "sandbox.config.json": { - content: `{ - "infiniteLoopProtection": false, - "hardReloadOnChange": false, - "view": "browser" -}`, - isBinary: false, - }, - "src/types/declaration.d.ts": { - content: `declare module "*.scss" { - const content: Record; - export default content; - }`, - isBinary: false, - }, - "src/types/jpg.d.ts": { - content: `declare module "*.jpg" { - const value: any; - export default value; - }`, - isBinary: false, - }, - "src/types/png.d.ts": { - content: `declare module "*.png" { - const value: any; - export default value; - } `, - isBinary: false, - }, - "src/types/svg.d.ts": { - content: `declare module "*.svg" { - const value: any; - export default value; - }`, - isBinary: false, - }, - "index.html": { - content: htmlCode, - isBinary: false, - }, - }; - - if (currentExample.sandboxConfig) { - files["sandbox.config.json"] = { - // @ts-ignore - content: currentExample.sandboxConfig, - isBinary: false, - }; - } - files = { ...files, ...csStyles }; - - await includeImportedModules(folderPath, files, code, true, true, baseUrl); - return { files }; -}; diff --git a/Examples/src/server/services/stackblitz/getStackblitzFiles.ts b/Examples/src/server/services/stackblitz/getStackblitzFiles.ts deleted file mode 100644 index 2ff621496..000000000 --- a/Examples/src/server/services/stackblitz/getStackblitzFiles.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { Request, Response } from "express"; -import path from "path"; -import { EPageFramework, getFrameworkContent } from "../../../helpers/shared/Helpers/frameworkParametrization"; -import { getSandboxConfig } from "../sandbox"; -import { getRequestedExample } from "../../renderCodeSandboxRedirect"; -import { BadRequestError, IHttpError } from "../../Errors"; -import { TExamplePage } from "../../../components/AppRouter/examplePages"; -import { SandboxConfig } from "../sandbox/sandboxDependencyUtils"; -import { StackBlitzResponse } from "../../../helpers/types/types"; -import { ProjectFiles } from "@stackblitz/sdk"; - -/** - * Gets the files and configuration needed for StackBlitz project - * @param req Express request object - * @param res Express response object - * @returns Promise that resolves when the response is sent - */ -export async function getStackblitzFiles(req: Request, res: Response): Promise { - try { - // Get the example information - const exampleInfo = getRequestedExample(req, res); - if (!exampleInfo?.currentExample) { - res.status(404).json({ error: "Example not found" }); - return; - } - const currentExample = exampleInfo.currentExample; - // Validate and get framework - const framework = validateFramework(req.query.framework as string); - - // Get base URL for assets - const baseUrl = `${req.protocol}://${req.get("host")}`; - - // Get sandbox configuration - const basePath = path.join(__dirname, "Examples"); - const folderPath = path.join(basePath, currentExample.filepath); - const sandboxConfig = await getSandboxConfig(folderPath, exampleInfo.currentExample, framework, baseUrl); - - // Format response for StackBlitz - const response = formatStackBlitzResponse(sandboxConfig, exampleInfo.currentExample); - - res.status(200).json(response); - } catch (err) { - handleError(err, res); - } -} - -/** - * Validates and returns the framework, defaulting to React if invalid - * @param framework Framework from query parameter - * @returns Valid EPageFramework value - */ -function validateFramework(framework: string): EPageFramework { - const isValidFramework = Object.values(EPageFramework).includes(framework as EPageFramework); - return isValidFramework ? (framework as EPageFramework) : EPageFramework.React; -} - -const handleInvalidFrameworkValue = (value: never): never => { - throw new Error("Invalid framework value!"); -}; - -// TODO this was copy-pasted. refactor -const getStackblitzTemplate = (framework: EPageFramework) => { - switch (framework) { - case EPageFramework.Angular: - return "node"; - case EPageFramework.React: - return "create-react-app"; - case EPageFramework.Vanilla: - return "typescript"; - default: - return handleInvalidFrameworkValue(framework); - } -}; - -/** - * Formats sandbox configuration into StackBlitz response format - * @param sandboxConfig Configuration from sandbox service - * @param example Example information - * @param framework Selected framework - * @returns Formatted StackBlitz response - */ -function formatStackBlitzResponse( - sandboxConfig: SandboxConfig & { actualFramework: EPageFramework }, - example: TExamplePage -): StackBlitzResponse { - const { files } = sandboxConfig; - const packageJsonContent = files["package.json"]?.content as any; - - // Format files for StackBlitz - const stackblitzFiles: ProjectFiles = {}; - Object.entries(files).forEach(([filename, file]: [string, any]) => { - stackblitzFiles[filename] = file.content; - }); - stackblitzFiles["package.json"] = JSON.stringify(packageJsonContent); - - // Get the title string by calling the title template function with the framework - const title = getFrameworkContent(example.title, sandboxConfig.actualFramework) || "SciChart Example"; - - const template = getStackblitzTemplate(sandboxConfig.actualFramework); - - return { - files: stackblitzFiles, - title, - description: "SciChart.js Example", - template, - dependencies: packageJsonContent?.dependencies || {}, - devDependencies: packageJsonContent?.devDependencies || {}, - settings: { - compile: { - clearConsole: false, - action: "refresh", - trigger: "save", - }, - }, - }; -} - -/** - * Handles errors and sends appropriate response - * @param err Error object - * @param res Express response object - */ -function handleError(err: unknown, res: Response): void { - console.error("Error getting StackBlitz files:", err); - - if (err instanceof BadRequestError) { - res.status(400).json({ error: err.message }); - return; - } - - const error = err as IHttpError; - if (error?.status) { - res.status(error.status).json({ error: error.message }); - return; - } - - res.status(500).json({ error: "Internal server error" }); -} diff --git a/Examples/src/server/types/TBinanceQueryParams.ts b/Examples/src/server/types/TBinanceQueryParams.ts deleted file mode 100644 index 8c1f9fb57..000000000 --- a/Examples/src/server/types/TBinanceQueryParams.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type TBinanceQueryParams = { - interval: string; - symbol: string; - limit: string; - endTime: string; -}; diff --git a/Examples/src/server/vanillaDemo/common.js b/Examples/src/server/vanillaDemo/common.js deleted file mode 100644 index 89bab15b9..000000000 --- a/Examples/src/server/vanillaDemo/common.js +++ /dev/null @@ -1,11 +0,0 @@ -import { SciChartSurface, SciChart3DSurface, SciChartDefaults } from "./scichart.browser.mjs"; - -SciChartSurface.configure({ dataUrl: "/scichart2d.data", wasmUrl: "/scichart2d.wasm" }); -SciChart3DSurface.configure({ dataUrl: "/scichart3d.data", wasmUrl: "/scichart3d.wasm" }); -SciChartDefaults.performanceWarnings = false; -// if (window.location.hostname.includes("scichart")) { -// // TODO -// // SciChart.SciChartSurface.setRuntimeLicenseKey( -// // "k+sB7T86MNUScrzB3XxJvoeaW3Pauy+pfhiEaISfj+d5yTv5SqI5AeIF54RA+Th/d9alXJq46HY+vmRDtCQJsSV90nQrqsL3CDjSLyadSj5N+DcPIi1MSsEcLrksK9bLr93J3hWCXJesurwTATgNEsXHlV6WI9KQfFLIhotDphx5O8NQKRfA82VEcbRGWOHTP/uMvz0ciMOMJJOF7OvMbd3EK6IuVhWtHvoENTa9RAd/5PriF9y6OzBtJg1u1uMlc/11LoGK6vGMBaahVBYjfWWGYAOpg00F5rLfHTY1ocf0/A6ImNA5xWZqiKwFbxfQJ/nh7phwcwIYLVFNU6QXZQyonwAynzgLTtwtg3HPegrYcIgfwrqony4OXNWWrnZuMV37U/NDAab6rZ499LlYsUqBTL6tJcO9mz/8MQYj0GUXuWajDudyvHRtoZwz6khit4JZR2pn9hSzgD0e3klL45o5BBQLJONgscByY6p8kYk3/oupGB9IF0IJwJtM7C8Wb1pb5E2UbulwuNzz7ct9OTaKt5t6jVn20VW25bjpcyWyJwN3E2fSuE5e9XU0ScVldxYo7VwF8Tcu4PJEAwQPzivvGGhtarUjfRQho10RbWK8p1jTHjHanA3DAdxUttUTvfzF/O8BbeBYrH3bDcY4tRdH/2px7K/FP6ITkZAtilimvmctWKbhXLyAiHIMsNDp2OtyJ/nM8XOB9hyWCPXfabHP7TD+gTkJMAK5Pw8dMC0lNdnwwjvBlz5Ho8APkr61NLa4FpVMFcBntTRgfjPJGMg=" -// // ); -// } diff --git a/Examples/src/server/vanillaDemo/vanillaExampleHtmlTemplate.ts b/Examples/src/server/vanillaDemo/vanillaExampleHtmlTemplate.ts deleted file mode 100644 index 004609819..000000000 --- a/Examples/src/server/vanillaDemo/vanillaExampleHtmlTemplate.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { EXAMPLES_PAGES, TExamplePage } from "../../components/AppRouter/examplePages"; -import { EPageFramework, getFrameworkContent } from "../../helpers/shared/Helpers/frameworkParametrization"; - -const generateLinkToVanillaExample = (entry: TExamplePage) => { - const link = `/vanillaDemo/${entry.path}/index.html?nav=1`; - return `
  • ${getFrameworkContent(entry.title, EPageFramework.Vanilla)}`; -}; - -const generateNav = () => { - let html = `
      `; - Object.values(EXAMPLES_PAGES).forEach((page) => { - html += generateLinkToVanillaExample(page); - }); - - html += `
    `; - return html; -}; - -const nav = generateNav(); - -export const htmlTemplate = (options?: { body?: string; styles?: string; renderNav?: boolean }) => - ` - - - - - SciChart Example - - - - - - - - -
    - ${ - options.renderNav - ? `
    - ${nav} -
    ` - : "" - } -
    - ${options?.body ?? `
    `} -
    -
    - - `; diff --git a/Examples/src/server/vanillaDemo/vanillaExamplesRouter.ts b/Examples/src/server/vanillaDemo/vanillaExamplesRouter.ts deleted file mode 100644 index f4d1a801d..000000000 --- a/Examples/src/server/vanillaDemo/vanillaExamplesRouter.ts +++ /dev/null @@ -1,97 +0,0 @@ -import * as path from "path"; -import * as fs from "fs"; -import express from "express"; -import { htmlTemplate } from "./vanillaExampleHtmlTemplate"; -import { EXAMPLES_PAGES, TExamplePage } from "../../components/AppRouter/examplePages"; - -export const vanillaExamplesRouter = express.Router(); - -const availableFiles = [ - "index.html", - "index.js", - "drawExample.js", - "common.js", - "theme.js", - "scichart.browser.mjs", - "DepthCursorModifier.js", - "data.js", -] as const; - -const basePath = path.join(__dirname, "Examples"); - -const isValidFilePath = (requestedPath: string) => { - const absoluteRootFolderPath = path.resolve(basePath); - const absoluteRequestedFilePath = path.resolve(path.join(basePath, requestedPath)); - - return absoluteRequestedFilePath.startsWith(absoluteRootFolderPath); -}; - -vanillaExamplesRouter.get("/:example/:file", async (req, res) => { - const examplePath = req.params.example; - const filename = req.params.file as (typeof availableFiles)[number]; - - if (!isValidFilePath(filename)) { - res.sendStatus(400); - return; - } - - const currentExampleKey = Object.keys(EXAMPLES_PAGES).find((key) => EXAMPLES_PAGES[key].path === examplePath); - const currentExample = EXAMPLES_PAGES[currentExampleKey]; - - if (currentExample) { - const vanillaJsSetupPath = path.join(basePath, currentExample.filepath, "vanilla.js"); - - // check if vanilla example exists - try { - const vanillaJsSetup = await fs.promises.readFile(vanillaJsSetupPath, "utf8"); - } catch { - return res.sendStatus(404); - } - - if (filename === "index.html") { - const htmlPath = path.join(basePath, currentExample.filepath, filename); - const cssPath = path.join(basePath, currentExample.filepath, "vanilla.css"); - let body = ""; - let styles = ""; - try { - const [htmlSetup, cssSetup] = await Promise.all([ - fs.promises.readFile(htmlPath, "utf8").catch((): string => ""), - fs.promises.readFile(cssPath, "utf8").catch((): string => ""), - ]); - - body = htmlSetup; - styles = cssSetup; - } catch { - return res.sendStatus(500); - } - - const renderNav = !!req.query["nav"]; - const generatedHtml = htmlTemplate({ body, styles, renderNav }); - - return res.send(generatedHtml); - } else { - const file = getExampleSourceFile(filename, currentExample); - - return res.sendFile(file); - } - } else { - return res.sendStatus(404); - } -}); - -const getExampleSourceFile = (filename: (typeof availableFiles)[number], currentExample: TExamplePage) => { - switch (filename) { - case "common.js": - return path.join(__dirname, "common.js"); - case "theme.js": - return path.join(__dirname, "Examples/theme.js"); - case "scichart.browser.mjs": - return path.join(__dirname, "scichart.browser.mjs"); - case "index.js": - return path.join(basePath, currentExample.filepath, "vanilla.js"); - case "drawExample.js": - return path.join(basePath, currentExample.filepath, "drawExample.js"); - default: - return path.join(basePath, currentExample.filepath, filename); - } -}; diff --git a/Examples/src/server/websockets.ts b/Examples/src/server/websockets.ts deleted file mode 100644 index 4fb946396..000000000 --- a/Examples/src/server/websockets.ts +++ /dev/null @@ -1,94 +0,0 @@ -import * as http from "http"; -import * as socketIo from "socket.io"; - -type TSubscription = { - series: number[]; - startX: number; - pointsPerUpdate: number; - sendEvery: number; - positive: boolean; - scale: number; -}; - -const sendData = ( - socket: any, - series: number[], - nextx: number, - pointsPerUpdate: number, - sendEvery: number, - stopX: number, - positive: boolean, - scale: number -): void => { - if (!socket.wantsData) { - return; - } - - console.log(`Creating ${pointsPerUpdate} points for ${series.length} series starting at x=${nextx}`); - - const x: number[] = []; - const ys: number[][] = new Array(series.length); - for (let i = 0; i < pointsPerUpdate; i++) { - x.push(nextx); - nextx++; - for (let s = 0; s < series.length; s++) { - if (i === 0) { - ys[s] = []; - } - let nextY = series[s] + Math.random() * scale - scale / 2; - if (positive) { - nextY = Math.abs(nextY); - } - ys[s].push(nextY); - series[s] = nextY; - } - } - socket.emit("data", { x, ys, sendTime: new Date().getTime() }); - if (nextx < stopX) { - setTimeout(() => { - sendData(socket, series, nextx, pointsPerUpdate, sendEvery, stopX, positive, scale); - }, sendEvery); - } else { - socket.emit("finished"); - } -}; - -// tslint:disable: no-console -export const createSocketServer = (server: http.Server): void => { - const io = new socketIo.Server(server, { - path: "/demo/socket.io", - serveClient: false, - cors: { - origin: ["http://localhost:8080", "http://localhost:8081", "/.csb.app$/", "/.cdpn.io$/"], - methods: ["GET", "POST"], - }, - }); - - // listen on every connection - io.on("connection", (socket) => { - console.log("New user connected, socket.id", socket.id); - - socket.on("getData", (message: TSubscription) => { - console.log("subscribe from ", socket.id, message); - // @ts-ignore - socket.wantsData = true; - sendData( - socket, - message.series, - message.startX, - message.pointsPerUpdate, - message.sendEvery, - message.startX + 1000 * message.pointsPerUpdate, - message.positive, - message.scale - ); - }); - - // Disconnect - socket.on("disconnect", () => { - // @ts-ignore - socket.wantsData = false; - console.log("disconnect, socket.id", socket.id); - }); - }); -}; diff --git a/Examples/src/static/no_server.index.html b/Examples/src/static/no_server.index.html index 3fe7ab96f..6518c3bfc 100644 --- a/Examples/src/static/no_server.index.html +++ b/Examples/src/static/no_server.index.html @@ -18,6 +18,6 @@ -
    +
    diff --git a/Examples/src/utils/googleTagManager.ts b/Examples/src/utils/googleTagManager.ts deleted file mode 100644 index a1b927650..000000000 --- a/Examples/src/utils/googleTagManager.ts +++ /dev/null @@ -1,10 +0,0 @@ -export const updateGoogleTagManagerPage = () => { - if (typeof window !== "undefined") { - // @ts-ignore - if (window.dataLayer) - // @ts-ignore - window.dataLayer.push({ - event: "pageview", - }); - } -}; diff --git a/Examples/src/utils/routeUtils.ts b/Examples/src/utils/routeUtils.ts deleted file mode 100644 index 45f29dd77..000000000 --- a/Examples/src/utils/routeUtils.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Tests if the current browser route starts with a specific word, ignoring leading/trailing slashes - * @param word The word to check for at the start of the current route - * @returns boolean indicating if the current route starts with the word - * @example - * // If current URL is "/examples/chart" - * routeStartsWith("examples") // returns true - * - * // If current URL is "/other/path" - * routeStartsWith("examples") // returns false - */ -export function routeStartsWith(word: string): boolean { - // Get current route from window location - const currentRoute = window.location.pathname; - - // Remove leading and trailing slashes and split into segments - const segments = currentRoute.replace(/^\/+|\/+$/g, "").split("/"); - - // Check if the first segment matches the word - return segments[0] === word; -} diff --git a/Examples/start-dev.bat b/Examples/start-dev.bat new file mode 100644 index 000000000..d1a039813 --- /dev/null +++ b/Examples/start-dev.bat @@ -0,0 +1,9 @@ +@echo off +echo Stopping any existing processes on port 8081... +for /f "tokens=5" %%a in ('netstat -ano ^| findstr :8081') do ( + echo Killing process %%a + taskkill /PID %%a /F >nul 2>&1 +) + +echo Starting development server... +npm run dev \ No newline at end of file diff --git a/Examples/start-dev.ps1 b/Examples/start-dev.ps1 new file mode 100644 index 000000000..819792f60 --- /dev/null +++ b/Examples/start-dev.ps1 @@ -0,0 +1,24 @@ +Write-Host "Stopping any existing processes on port 8081..." -ForegroundColor Yellow + +# Get processes using port 8081 +$processes = netstat -ano | Select-String ":8081" | ForEach-Object { + $parts = $_ -split '\s+' + $parts[-1] # Get the PID +} | Sort-Object -Unique + +if ($processes) { + foreach ($processId in $processes) { + Write-Host "Killing process $processId" -ForegroundColor Red + try { + Stop-Process -Id $processId -Force -ErrorAction SilentlyContinue + } catch { + Write-Host "Could not kill process $processId" -ForegroundColor Yellow + } + } + Start-Sleep -Seconds 2 +} else { + Write-Host "No processes found on port 8081" -ForegroundColor Green +} + +Write-Host "Starting development server..." -ForegroundColor Green +npm run dev \ No newline at end of file diff --git a/Examples/test-env.js b/Examples/test-env.js new file mode 100644 index 000000000..e69de29bb diff --git a/Examples/test_firebase.js b/Examples/test_firebase.js new file mode 100644 index 000000000..e69de29bb diff --git a/Examples/test_websocket.html b/Examples/test_websocket.html new file mode 100644 index 000000000..c4ac73842 --- /dev/null +++ b/Examples/test_websocket.html @@ -0,0 +1,246 @@ + + + + + + ESP32 WebSocket Test Client + + + +

    ๐Ÿ”Œ ESP32 WebSocket Test Client

    + +
    +

    Connection Settings

    + + + +
    Disconnected
    +
    + +
    +

    ๐Ÿ“Š Real-time Data

    +
    +
    ECG Value
    +
    --
    +
    --
    +
    +
    +
    GSR Value
    +
    --
    +
    --
    +
    +
    +
    Respiratory Value
    +
    --
    +
    --
    +
    +
    +
    Heart Rate
    +
    --
    +
    --
    +
    +
    +
    IBI (Inter-Beat Interval)
    +
    --
    +
    --
    +
    +
    + +
    +

    ๐Ÿ“ Communication Log

    +
    +
    + + + + diff --git a/Examples/vitals-monitoring b/Examples/vitals-monitoring new file mode 160000 index 000000000..0e25dce14 --- /dev/null +++ b/Examples/vitals-monitoring @@ -0,0 +1 @@ +Subproject commit 0e25dce14881f989515730812c61edc45568d80b diff --git a/Examples/webpack.client.config.js b/Examples/webpack.client.config.js index e2b5663ee..733dfded8 100644 --- a/Examples/webpack.client.config.js +++ b/Examples/webpack.client.config.js @@ -34,7 +34,14 @@ module.exports = { { loader: "postcss-loader", }, - { loader: "sass-loader" }, + { + loader: "sass-loader", + options: { + sassOptions: { + includePaths: [path.resolve(__dirname, "src")], + }, + }, + }, ], exclude: /node_modules/, }, diff --git a/Examples/webpack.client.no_server.config.ts b/Examples/webpack.client.no_server.config.ts index 5445d7734..e63007bfb 100644 --- a/Examples/webpack.client.no_server.config.ts +++ b/Examples/webpack.client.no_server.config.ts @@ -2,15 +2,6 @@ const { merge } = require("webpack-merge"); const webpackClientConfig = require("./webpack.client.config.js"); const CopyPlugin = require("copy-webpack-plugin"); const webpack = require("webpack"); -const tq3080_DSM_2M = require("./src/server/Data/tq3080_DSM_2M"); -const { candlesADAUSDT } = require("./src/server/BinanceData/candlesADAUSDT"); -const { candlesBTCUSDT } = require("./src/server/BinanceData/candlesBTCUSDT"); -const { candlesDOGEUSDT } = require("./src/server/BinanceData/candlesDOGEUSDT"); -const { candlesETHUSDT } = require("./src/server/BinanceData/candlesETHUSDT"); -const { candlesXRPUSDT } = require("./src/server/BinanceData/candlesXRPUSDT"); -const TweetData = require("./src/server/Data/tweetData"); -const { multiPaneData } = require("./src/server/Data/multiPaneData"); -const { mappedPopulationData } = require("./src/server/Data/populationData"); module.exports = { ...webpackClientConfig, @@ -48,7 +39,14 @@ module.exports = { { loader: "postcss-loader", }, - { loader: "sass-loader" }, + { + loader: "sass-loader", + options: { + sassOptions: { + // includePaths: [require("path").resolve(__dirname, "src/assets")], + }, + }, + }, ], exclude: /node_modules/, }, @@ -86,74 +84,63 @@ module.exports = { { from: "src/static/webgl-intel.html", to: "webgl-intel.html" }, { from: "src/static/favicon.ico", to: "" }, { from: "src/components/Examples/**/*.jpg", to: "images/[name][ext]" }, - { from: "src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Shale.csv", to: "" }, - { from: "src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Density.csv", to: "" }, - { - from: "src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Resistivity.csv", - to: "", - }, - { - from: "src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/PoreSpace.csv", - to: "", - }, - { from: "src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Sonic.csv", to: "" }, - { from: "src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Texture.csv", to: "" }, { from: "node_modules/scichart/_wasm/scichart2d.data", to: "" }, { from: "node_modules/scichart/_wasm/scichart2d.wasm", to: "" }, { from: "node_modules/scichart/_wasm/scichart3d.data", to: "" }, { from: "node_modules/scichart/_wasm/scichart3d.wasm", to: "" }, { from: "sitemap.xml", to: "" }, { from: "robots.txt", to: "" }, - { from: "src/assets", to: "assets" }, + // { from: "src/assets", to: "assets" }, ], }), ], devServer: { - client: { - progress: true, - }, - static: { - directory: "src/assets", - publicPath: "/assets", - }, - allowedHosts: "all", + port: 8081, + hot: true, + // contentBase: "src/assets", historyApiFallback: true, - onBeforeSetupMiddleware: function (devServer: any) { + setupMiddlewares: (middlewares: any[], devServer: any) => { + if (!devServer) { + throw new Error("webpack-dev-server is not defined"); + } + const { app } = devServer; - app.get("/api/lidarData", function (req: any, res: any) { - res.send(tq3080_DSM_2M.tq3080_DSM_2M); - }); - app.get("/api/tweetData", function (req: any, res: any) { - res.send(TweetData.TweetData); - }); - app.get("/api/multiPaneData", function (req: any, res: any) { - res.send(multiPaneData); - }); - app.get("/api/populationData", function (req: any, res: any) { - res.send(mappedPopulationData); - }); - app.get("/api/get-binance-candles", function (req: any, res: any) { - const params = req.query; - let data; - switch (params.symbol) { - case "ADAUSDT": - data = candlesADAUSDT; - break; - case "BTCUSDT": - data = candlesBTCUSDT; - break; - case "DOGEUSDT": - data = candlesDOGEUSDT; - break; - case "ETHUSDT": - data = candlesETHUSDT; - break; - case "XRPUSDT": - data = candlesXRPUSDT; - break; - } - res.send(data); - }); + // app.get("/api/lidarData", function (req: any, res: any) { + // res.send(tq3080_DSM_2M.tq3080_DSM_2M); + // }); + // app.get("/api/tweetData", function (req: any, res: any) { + // res.send(TweetData.TweetData); + // }); + // app.get("/api/multiPaneData", function (req: any, res: any) { + // res.send(multiPaneData); + // }); + // app.get("/api/populationData", function (req: any, res: any) { + // res.send(mappedPopulationData); + // }); + // app.get("/api/get-binance-candles", function (req: any, res: any) { + // const params = req.query; + // let data; + // switch (params.symbol) { + // case "ADAUSDT": + // data = candlesADAUSDT; + // break; + // case "BTCUSDT": + // data = candlesBTCUSDT; + // break; + // case "DOGEUSDT": + // data = candlesDOGEUSDT; + // break; + // case "ETHUSDT": + // data = candlesETHUSDT; + // break; + // case "XRPUSDT": + // data = candlesXRPUSDT; + // break; + // } + // res.send(data); + // }); + + return middlewares; }, }, }; diff --git a/Examples/webpack.server.config.js b/Examples/webpack.server.config.js index 7f77ce543..f9f598168 100644 --- a/Examples/webpack.server.config.js +++ b/Examples/webpack.server.config.js @@ -44,6 +44,11 @@ module.exports = { }, { loader: "sass-loader", + options: { + sassOptions: { + includePaths: [path.resolve(__dirname, "src")], + }, + }, }, ], exclude: /node_modules/, From 88f71391888667d2ffb77074feb838980ac0e194 Mon Sep 17 00:00:00 2001 From: buddywhitman Date: Fri, 29 Aug 2025 08:10:32 +0530 Subject: [PATCH 3/4] fix: unused files --- Examples/package.json | 4 ++-- Examples/webpack.client.config.js | 13 ------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/Examples/package.json b/Examples/package.json index 8952b4f07..47c41374a 100644 --- a/Examples/package.json +++ b/Examples/package.json @@ -14,8 +14,8 @@ "dev": "webpack-dev-server --config webpack.client.no_server.config.ts", "dev:clean": "powershell -ExecutionPolicy Bypass -File start-dev.ps1", "install:firebase": "powershell -ExecutionPolicy Bypass -File install-firebase.ps1", - "build": "rimraf ./build && npm run buildVanillaDemo && npm run buildImages && npm run buildServer && npm run buildClient", - "start": "node ./build/server.js", + "build": "rimraf ./build && npm run buildVanillaDemo && npm run buildImages && npm run buildClient", + "start": "npm run dev", "buildServer": "webpack --config webpack.server.config.js", "buildClient": "webpack --config webpack.client.config.js", "buildImages": "webpack --config webpack.image.config.js", diff --git a/Examples/webpack.client.config.js b/Examples/webpack.client.config.js index 733dfded8..392119411 100644 --- a/Examples/webpack.client.config.js +++ b/Examples/webpack.client.config.js @@ -84,19 +84,6 @@ module.exports = { patterns: [ { from: "src/static/favicon.ico", to: "" }, { from: "src/static/webgl-intel.html", to: "" }, - { from: "src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Shale.csv", to: "" }, - { from: "src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Density.csv", to: "" }, - { - from: "src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Resistivity.csv", - to: "", - }, - { - from: "src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/PoreSpace.csv", - to: "", - }, - { from: "src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Sonic.csv", to: "" }, - { from: "src/components/Examples/FeaturedApps/ShowCases/OilAndGasDashboard/Data/Texture.csv", to: "" }, - { from: "src/server/vanillaDemo/common.js", to: "" }, { from: "node_modules/scichart/_wasm/scichart.browser.mjs", to: "" }, { from: "node_modules/scichart/_wasm/scichart2d.data", to: "" }, { from: "node_modules/scichart/_wasm/scichart2d.wasm", to: "" }, From 5e8a1f1a5686b1c50eb8c98a0f90be6ba4fe3d1a Mon Sep 17 00:00:00 2001 From: buddywhitman Date: Sat, 30 Aug 2025 16:42:17 +0530 Subject: [PATCH 4/4] fix: respiratory rate --- Examples/esp32/CALIBRATION_README.md | 313 ---------- Examples/esp32/calibration_analyzer.py | 433 ------------- Examples/esp32/main.ino | 570 ++++++++++++------ Examples/esp32/mpu6050.ino | 131 ++++ Examples/esp32/requirements.txt | 4 - Examples/esp32/sensor_calibration.ino | 370 ------------ .../VitalSignsMonitorDemo/drawExample.ts | 47 +- .../VitalSignsMonitorDemo/ecgProcessor.ts | 2 +- .../VitalSignsMonitorDemo/index.tsx | 183 ++++-- .../VitalSignsMonitorDemo/signalProcessor.ts | 49 +- 10 files changed, 686 insertions(+), 1416 deletions(-) delete mode 100644 Examples/esp32/CALIBRATION_README.md delete mode 100644 Examples/esp32/calibration_analyzer.py create mode 100644 Examples/esp32/mpu6050.ino delete mode 100644 Examples/esp32/requirements.txt delete mode 100644 Examples/esp32/sensor_calibration.ino diff --git a/Examples/esp32/CALIBRATION_README.md b/Examples/esp32/CALIBRATION_README.md deleted file mode 100644 index bafef7176..000000000 --- a/Examples/esp32/CALIBRATION_README.md +++ /dev/null @@ -1,313 +0,0 @@ -# ESP32 Sensor Calibration Guide - -This guide will help you calibrate your ESP32-based vital signs monitoring system using the AD8232 ECG sensor, HW-484 sound sensor for breathing detection, and GSR sensor. - -## ๐ŸŽฏ What This Calibration Does - -The calibration process will: - -1. **Establish baseline values** for each sensor when the subject is at rest -2. **Analyze breathing patterns** to distinguish between breath in/out -3. **Calculate optimal thresholds** for breath detection -4. **Provide recommendations** for sensor configuration - -## ๐Ÿ“‹ Prerequisites - -- ESP32 development board -- AD8232 ECG sensor module -- HW-484 sound sensor module -- GSR (Galvanic Skin Response) sensor -- Arduino IDE with ESP32 board support -- Python 3.7+ (for data analysis) - -## ๐Ÿ”Œ Hardware Setup - -### Sensor Connections - -``` -ESP32 Pin Sensor Connection -GPIO32 AD8232 Analog Output -GPIO33 GSR Analog Output -GPIO27 HW-484 Analog Output -3.3V All Sensors Power Supply -GND All Sensors Ground -``` - -### Sensor Placement - -- **AD8232**: Place electrodes on chest (RA, LA, RL positions) -- **HW-484**: Position near nose/mouth for breathing detection -- **GSR**: Attach to fingers or palm for skin conductance measurement - -## ๐Ÿš€ Calibration Process - -### Step 1: Upload Calibration Code - -1. Open `sensor_calibration.ino` in Arduino IDE -2. Select your ESP32 board and port -3. Upload the code to your ESP32 - -### Step 2: Run Calibration - -1. Open Serial Monitor at **115200 baud** -2. The calibration will start automatically in 5 seconds -3. Follow the on-screen instructions - -### Step 3: Data Collection Phases - -#### Phase 1: Baseline Calibration (30 seconds) - -- **Subject**: Remain completely still -- **Purpose**: Establish baseline sensor values -- **Output**: Sensor ranges, noise levels, baseline values - -#### Phase 2: Breath Analysis (60 seconds) - -- **Subject**: Breathe normally and steadily -- **Purpose**: Analyze breathing patterns and detect breath in/out -- **Output**: Breath detection accuracy, respiratory rate calculation - -#### Phase 3: Continuous Monitoring - -- **Subject**: Perform various activities (breathing exercises, movement) -- **Purpose**: Real-time sensor data analysis -- **Output**: Live sensor readings with breath detection - -## ๐Ÿ“Š Understanding the Output - -### Baseline Calibration Results - -``` -ECG Sensor (AD8232): - Range: 2048 - 3072 (Span: 1024) - Baseline: 2560 - Noise Level: ยฑ512 - -GSR Sensor: - Range: 1800 - 2300 (Span: 500) - Baseline: 2050 - Noise Level: ยฑ250 - -Respiratory Sensor (HW-484): - Range: 1900 - 2100 (Span: 200) - Baseline: 2000 - Noise Level: ยฑ100 -``` - -### Breath Detection Analysis - -``` -๐Ÿซ BREATH IN detected! Raw: 2100, Deviation: +100 -๐Ÿซ BREATH OUT detected! Raw: 1900, Deviation: -100 -``` - -### Real-time Data Format - -``` -DATA: timestamp, ecg_raw, ecg_dev, gsr_raw, gsr_dev, resp_raw, resp_dev -DATA: 12345, 2560, +0, 2050, +0, 2000, +0 -``` - -## ๐Ÿ”ฌ Data Analysis - -### Step 1: Save Serial Output - -1. Copy all Serial Monitor output -2. Save to a text file (e.g., `calibration_data.txt`) - -### Step 2: Run Analysis Script - -```bash -python calibration_analyzer.py calibration_data.txt -``` - -### Step 3: Review Recommendations - -The script will generate: - -- Optimal thresholds for each sensor -- Breath detection parameters -- Filtering recommendations -- ESP32 code snippets - -## ๐ŸŽฏ Calibration Recommendations - -### Breath Detection Thresholds - -Based on your data, the script will recommend: - -```cpp -// Example recommendations -const int BREATH_IN_THRESHOLD = 75; // 70% of mean breath-in deviation -const int BREATH_OUT_THRESHOLD = 75; // 70% of mean breath-out deviation -const int MIN_BREATH_INTERVAL = 1000; // 1 second minimum between breaths -``` - -### Sensor-Specific Thresholds - -```cpp -// ECG Sensor -const int ECG_PEAK_THRESHOLD = 341; // Range/3 for QRS detection - -// GSR Sensor -const int GSR_CHANGE_THRESHOLD = 62; // Range/8 for significant changes - -// Respiratory Sensor -const int RESP_BREATH_THRESHOLD = 50; // Range/4 for breath detection -``` - -## ๐Ÿ”ง Implementing Calibration Results - -### Update Your Main Code - -1. Copy recommended thresholds to `main.ino` -2. Replace existing threshold values -3. Test with real subjects -4. Fine-tune if necessary - -### Example Implementation - -```cpp -// Updated breath detection in main.ino -int calculateRespiratoryRate(int rawValue, unsigned long timestamp) { - int deviation = abs(rawValue - respBaseline); - - if (deviation > BREATH_IN_THRESHOLD && !breathDetected) { - if (timestamp - lastBreathTime > MIN_BREATH_INTERVAL) { - breathDetected = true; - lastBreathTime = timestamp; - - // Determine breath direction - if (rawValue > respBaseline) { - // Breath IN - Serial.println("๐Ÿซ Breath IN detected"); - } else { - // Breath OUT - Serial.println("๐Ÿซ Breath OUT detected"); - } - } - } else if (deviation <= BREATH_IN_THRESHOLD) { - breathDetected = false; - } - - return currentRespRate; -} -``` - -## ๐Ÿ“ˆ Expected Results - -### Good Calibration Indicators - -- **ECG**: Clear QRS peaks, stable baseline -- **Breathing**: Distinct breath in/out patterns -- **GSR**: Stable readings with clear response to stimuli - -### Poor Calibration Indicators - -- **ECG**: Excessive noise, unstable baseline -- **Breathing**: Unclear breath patterns, false detections -- **GSR**: Drifting baseline, poor signal-to-noise ratio - -## ๐Ÿšจ Troubleshooting - -### Common Issues - -#### No Sensor Readings - -- Check wiring connections -- Verify power supply (3.3V) -- Ensure proper ground connection - -#### Excessive Noise - -- Check for loose connections -- Move away from electrical interference -- Verify sensor placement - -#### Poor Breath Detection - -- Adjust sensor position near nose/mouth -- Check for background noise -- Verify threshold calculations - -#### Unstable Baseline - -- Ensure subject remains still during calibration -- Check for sensor movement -- Verify stable power supply - -### Sensor-Specific Issues - -#### AD8232 ECG - -- **No signal**: Check electrode placement and conductivity -- **High noise**: Ensure good skin contact and electrode adhesion -- **Baseline drift**: Check for movement artifacts - -#### HW-484 Sound Sensor - -- **Poor breath detection**: Adjust microphone position -- **Background noise**: Use in quiet environment -- **False triggers**: Increase detection threshold - -#### GSR Sensor - -- **No response**: Check electrode contact -- **Drifting values**: Ensure stable electrode placement -- **Poor sensitivity**: Clean electrodes and skin - -## ๐Ÿ”„ Recalibration - -### When to Recalibrate - -- After changing sensor placement -- When switching subjects -- If detection accuracy decreases -- After hardware modifications - -### Recalibration Process - -1. Follow the same calibration procedure -2. Compare results with previous calibration -3. Adjust thresholds if necessary -4. Document changes for future reference - -## ๐Ÿ“š Additional Resources - -### Technical Documentation - -- [AD8232 ECG Sensor Datasheet](https://wiki.keyestudio.com/Ks0261_keyestudio_AD8232_ECG_Measurement_Heart_Monitor_Sensor_Module) -- [HW-484 Sound Sensor Guide](https://sichiray-tech.yuque.com/dm0eyv/chanpin/iqepdr0qglekrtc3) -- [ESP32 ADC Documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html) - -### Best Practices - -- Calibrate in a controlled environment -- Document all calibration parameters -- Test with multiple subjects -- Monitor long-term performance -- Implement adaptive thresholds - -## ๐ŸŽ‰ Success Criteria - -Your calibration is successful when: - -- โœ… Breath detection accuracy > 90% -- โœ… Respiratory rate calculation within ยฑ2 breaths/min -- โœ… ECG signal quality suitable for QRS detection -- โœ… GSR baseline stability maintained -- โœ… Real-time performance meets requirements - -## ๐Ÿ“ž Support - -If you encounter issues: - -1. Review this guide thoroughly -2. Check hardware connections -3. Verify sensor specifications -4. Test with known good sensors -5. Document specific error messages - ---- - -**Remember**: Calibration is crucial for accurate vital signs monitoring. Take your time, follow the process carefully, and document your results for future reference. diff --git a/Examples/esp32/calibration_analyzer.py b/Examples/esp32/calibration_analyzer.py deleted file mode 100644 index c63d9ff42..000000000 --- a/Examples/esp32/calibration_analyzer.py +++ /dev/null @@ -1,433 +0,0 @@ -#!/usr/bin/env python3 -""" -ESP32 Sensor Calibration Data Analyzer - -This script analyzes the raw sensor data output from the ESP32 calibration file -and provides comprehensive calibration recommendations for: -- AD8232 ECG sensor -- HW-484 sound sensor (breathing detection) -- GSR sensor - -Usage: -1. Run the ESP32 calibration file and copy the Serial Monitor output -2. Save the output to a text file -3. Run this script: python calibration_analyzer.py -""" - -import sys -import re -import numpy as np -import matplotlib.pyplot as plt -from collections import defaultdict -import argparse -from datetime import datetime - -class SensorCalibrationAnalyzer: - def __init__(self): - self.data = { - 'ecg': {'raw': [], 'deviation': [], 'timestamps': []}, - 'gsr': {'raw': [], 'deviation': [], 'timestamps': []}, - 'resp': {'raw': [], 'deviation': [], 'timestamps': []} - } - self.baseline_results = {} - self.breath_analysis = {} - self.calibration_recommendations = {} - - def parse_calibration_data(self, filename): - """Parse the calibration output file and extract sensor data""" - print(f"๐Ÿ” Parsing calibration data from: {filename}") - - try: - with open(filename, 'r') as file: - lines = file.readlines() - except FileNotFoundError: - print(f"โŒ Error: File '{filename}' not found") - return False - - # Parse different types of lines - for line in lines: - line = line.strip() - - # Parse DATA lines (continuous monitoring) - if line.startswith('DATA:'): - self._parse_data_line(line) - - # Parse breath detection lines - elif 'BREATH IN detected!' in line or 'BREATH OUT detected!' in line: - self._parse_breath_line(line) - - # Parse baseline calibration results - elif 'Range:' in line and 'Span:' in line: - self._parse_baseline_line(line) - - print(f"โœ… Parsed {len(self.data['ecg']['raw'])} data points") - return True - - def _parse_data_line(self, line): - """Parse DATA lines from continuous monitoring""" - try: - # Format: DATA: timestamp, ecg_raw, ecg_dev, gsr_raw, gsr_dev, resp_raw, resp_dev - parts = line.split(': ')[1].split(', ') - timestamp = int(parts[0]) - ecg_raw = int(parts[1]) - ecg_dev = int(parts[2]) - gsr_raw = int(parts[3]) - gsr_dev = int(parts[4]) - resp_raw = int(parts[5]) - resp_dev = int(parts[6]) - - # Store data - self.data['ecg']['raw'].append(ecg_raw) - self.data['ecg']['deviation'].append(ecg_dev) - self.data['ecg']['timestamps'].append(timestamp) - - self.data['gsr']['raw'].append(gsr_raw) - self.data['gsr']['deviation'].append(gsr_dev) - self.data['gsr']['timestamps'].append(timestamp) - - self.data['resp']['raw'].append(resp_raw) - self.data['resp']['deviation'].append(resp_dev) - self.data['resp']['timestamps'].append(timestamp) - - except (IndexError, ValueError) as e: - print(f"โš ๏ธ Warning: Could not parse data line: {line[:50]}...") - - def _parse_breath_line(self, line): - """Parse breath detection lines""" - try: - # Extract breath type and values - if 'BREATH IN detected!' in line: - breath_type = 'IN' - else: - breath_type = 'BREATH OUT detected!' - - # Extract raw value and deviation - raw_match = re.search(r'Raw: (\d+)', line) - dev_match = re.search(r'Deviation: ([+-]\d+)', line) - - if raw_match and dev_match: - raw_val = int(raw_match.group(1)) - dev_val = int(dev_match.group(1)) - - if 'breath_in' not in self.breath_analysis: - self.breath_analysis['breath_in'] = {'raw': [], 'deviation': []} - if 'breath_out' not in self.breath_analysis: - self.breath_analysis['breath_out'] = {'raw': [], 'deviation': []} - - if breath_type == 'IN': - self.breath_analysis['breath_in']['raw'].append(raw_val) - self.breath_analysis['breath_in']['deviation'].append(dev_val) - else: - self.breath_analysis['breath_out']['raw'].append(raw_val) - self.breath_analysis['breath_out']['deviation'].append(dev_val) - - except Exception as e: - print(f"โš ๏ธ Warning: Could not parse breath line: {line[:50]}...") - - def _parse_baseline_line(self, line): - """Parse baseline calibration results""" - try: - # Extract sensor type and values - if 'ECG Sensor' in line: - sensor = 'ecg' - elif 'GSR Sensor' in line: - sensor = 'gsr' - elif 'Respiratory Sensor' in line: - sensor = 'resp' - else: - return - - # Extract range values - range_match = re.search(r'Range: (\d+) - (\d+)', line) - span_match = re.search(r'Span: (\d+)', line) - - if range_match and span_match: - min_val = int(range_match.group(1)) - max_val = int(range_match.group(2)) - span = int(span_match.group(1)) - - if sensor not in self.baseline_results: - self.baseline_results[sensor] = {} - - self.baseline_results[sensor] = { - 'min': min_val, - 'max': max_val, - 'span': span - } - - except Exception as e: - print(f"โš ๏ธ Warning: Could not parse baseline line: {line[:50]}...") - - def analyze_sensor_data(self): - """Perform comprehensive analysis of sensor data""" - print("\n๐Ÿ”ฌ Analyzing sensor data...") - - for sensor_type in ['ecg', 'gsr', 'resp']: - if not self.data[sensor_type]['raw']: - continue - - raw_data = np.array(self.data[sensor_type]['raw']) - dev_data = np.array(self.data[sensor_type]['deviation']) - - # Calculate statistics - stats = { - 'mean': np.mean(raw_data), - 'std': np.std(raw_data), - 'min': np.min(raw_data), - 'max': np.max(raw_data), - 'range': np.max(raw_data) - np.min(raw_data), - 'median': np.median(raw_data), - 'q25': np.percentile(raw_data, 25), - 'q75': np.percentile(raw_data, 75), - 'iqr': np.percentile(raw_data, 75) - np.percentile(raw_data, 25) - } - - # Calculate noise characteristics - stats['noise_level'] = stats['std'] - stats['signal_to_noise'] = stats['range'] / stats['std'] if stats['std'] > 0 else 0 - - # Store results - if sensor_type not in self.calibration_recommendations: - self.calibration_recommendations[sensor_type] = {} - - self.calibration_recommendations[sensor_type]['statistics'] = stats - - print(f" {sensor_type.upper()}: Mean={stats['mean']:.1f}, Std={stats['std']:.1f}, Range={stats['range']}") - - def analyze_breathing_patterns(self): - """Analyze breathing patterns from HW-484 sensor""" - print("\n๐Ÿซ Analyzing breathing patterns...") - - if not self.breath_analysis: - print(" โš ๏ธ No breath detection data found") - return - - breath_stats = {} - - for breath_type in ['breath_in', 'breath_out']: - if breath_type in self.breath_analysis and self.breath_analysis[breath_type]['raw']: - raw_vals = np.array(self.breath_analysis[breath_type]['raw']) - dev_vals = np.array(self.breath_analysis[breath_type]['deviation']) - - stats = { - 'count': len(raw_vals), - 'mean_raw': np.mean(raw_vals), - 'std_raw': np.std(raw_vals), - 'mean_deviation': np.mean(dev_vals), - 'std_deviation': np.std(dev_vals), - 'min_deviation': np.min(dev_vals), - 'max_deviation': np.max(dev_vals) - } - - breath_stats[breath_type] = stats - - print(f" {breath_type.replace('_', ' ').title()}: {stats['count']} breaths, " - f"Mean Dev: {stats['mean_deviation']:+.1f}, Std: {stats['std_deviation']:.1f}") - - # Calculate respiratory rate if we have enough data - if 'breath_in' in breath_stats and 'breath_out' in breath_stats: - total_breaths = breath_stats['breath_in']['count'] + breath_stats['breath_out']['count'] - if total_breaths > 0: - # Estimate respiratory rate (assuming 60-second analysis period) - estimated_rr = total_breaths # breaths per minute - print(f" Estimated Respiratory Rate: {estimated_rr} breaths/min") - - if estimated_rr < 8 or estimated_rr > 30: - print(f" โš ๏ธ Respiratory rate outside normal range (8-30 breaths/min)") - - self.calibration_recommendations['breathing'] = breath_stats - - def generate_calibration_recommendations(self): - """Generate comprehensive calibration recommendations""" - print("\n๐ŸŽฏ Generating calibration recommendations...") - - recommendations = {} - - for sensor_type in ['ecg', 'gsr', 'resp']: - if sensor_type not in self.calibration_recommendations: - continue - - stats = self.calibration_recommendations[sensor_type]['statistics'] - - if sensor_type == 'ecg': - # ECG recommendations - recommendations[sensor_type] = { - 'peak_threshold': int(stats['range'] / 3), - 'noise_threshold': int(stats['std'] * 2), - 'baseline_stability': 'Good' if stats['std'] < stats['range'] / 10 else 'Poor', - 'recommended_sampling_rate': '250Hz', - 'filtering_needed': stats['std'] > stats['range'] / 20 - } - - elif sensor_type == 'gsr': - # GSR recommendations - recommendations[sensor_type] = { - 'change_threshold': int(stats['range'] / 8), - 'noise_threshold': int(stats['std'] * 1.5), - 'baseline_stability': 'Good' if stats['std'] < stats['range'] / 15 else 'Poor', - 'recommended_sampling_rate': '10Hz', - 'filtering_needed': stats['std'] > stats['range'] / 30 - } - - elif sensor_type == 'resp': - # Respiratory recommendations - recommendations[sensor_type] = { - 'breath_threshold': int(stats['range'] / 4), - 'noise_threshold': int(stats['std'] * 2), - 'baseline_stability': 'Good' if stats['std'] < stats['range'] / 12 else 'Poor', - 'recommended_sampling_rate': '100Hz', - 'filtering_needed': stats['std'] > stats['range'] / 25 - } - - # Breathing pattern recommendations - if 'breathing' in self.calibration_recommendations: - breath_stats = self.calibration_recommendations['breathing'] - - if 'breath_in' in breath_stats and 'breath_out' in breath_stats: - # Calculate optimal thresholds - in_dev_mean = breath_stats['breath_in']['mean_deviation'] - out_dev_mean = breath_stats['breath_out']['mean_deviation'] - - recommendations['breathing'] = { - 'breath_in_threshold': int(abs(in_dev_mean) * 0.7), - 'breath_out_threshold': int(abs(out_dev_mean) * 0.7), - 'min_breath_interval': 1000, # 1 second - 'pattern_quality': 'Good' if abs(in_dev_mean - out_dev_mean) > 50 else 'Poor', - 'recommended_algorithm': 'Threshold-based with hysteresis' - } - - self.calibration_recommendations['recommendations'] = recommendations - return recommendations - - def print_calibration_report(self): - """Print comprehensive calibration report""" - print("\n" + "="*80) - print("๐Ÿ“Š ESP32 SENSOR CALIBRATION REPORT") - print("="*80) - - # Print sensor statistics - for sensor_type in ['ecg', 'gsr', 'resp']: - if sensor_type in self.calibration_recommendations: - stats = self.calibration_recommendations[sensor_type]['statistics'] - print(f"\n๐Ÿ”Œ {sensor_type.upper()} SENSOR ANALYSIS:") - print(f" Raw Range: {stats['min']} - {stats['max']} (Span: {stats['range']})") - print(f" Baseline: {stats['median']:.1f} (Median)") - print(f" Noise Level: ยฑ{stats['std']:.1f}") - print(f" Signal-to-Noise Ratio: {stats['signal_to_noise']:.2f}") - - # Print breathing analysis - if 'breathing' in self.calibration_recommendations: - print(f"\n๐Ÿซ BREATHING PATTERN ANALYSIS:") - breath_stats = self.calibration_recommendations['breathing'] - - for breath_type in ['breath_in', 'breath_out']: - if breath_type in breath_stats: - stats = breath_stats[breath_type] - print(f" {breath_type.replace('_', ' ').title()}:") - print(f" Count: {stats['count']}") - print(f" Mean Deviation: {stats['mean_deviation']:+.1f}") - print(f" Deviation Range: {stats['min_deviation']} to {stats['max_deviation']}") - - # Print recommendations - if 'recommendations' in self.calibration_recommendations: - print(f"\n๐ŸŽฏ CALIBRATION RECOMMENDATIONS:") - recs = self.calibration_recommendations['recommendations'] - - for sensor_type, rec in recs.items(): - if sensor_type == 'breathing': - print(f"\n ๐Ÿซ BREATHING DETECTION:") - print(f" Breath IN Threshold: {rec['breath_in_threshold']}") - print(f" Breath OUT Threshold: {rec['breath_out_threshold']}") - print(f" Pattern Quality: {rec['pattern_quality']}") - print(f" Algorithm: {rec['recommended_algorithm']}") - else: - print(f"\n ๐Ÿ”Œ {sensor_type.upper()} SENSOR:") - if 'peak_threshold' in rec: - print(f" Peak Threshold: {rec['peak_threshold']}") - if 'change_threshold' in rec: - print(f" Change Threshold: {rec['change_threshold']}") - if 'breath_threshold' in rec: - print(f" Breath Threshold: {rec['breath_threshold']}") - print(f" Baseline Stability: {rec['baseline_stability']}") - print(f" Filtering Needed: {'Yes' if rec['filtering_needed'] else 'No'}") - print(f" Recommended Sampling: {rec['recommended_sampling_rate']}") - - print(f"\n" + "="*80) - print("๐Ÿ“ NEXT STEPS:") - print("1. Update your ESP32 main.ino with the recommended thresholds") - print("2. Test the new thresholds with real subjects") - print("3. Fine-tune based on performance") - print("4. Consider implementing adaptive thresholds for different subjects") - print("="*80) - - def save_recommendations_to_file(self, filename): - """Save calibration recommendations to a file""" - try: - with open(filename, 'w') as f: - f.write("ESP32 Sensor Calibration Recommendations\n") - f.write("Generated on: " + datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\n\n") - - # Write recommendations in a format suitable for ESP32 code - f.write("// Copy these values to your ESP32 main.ino file\n\n") - - if 'recommendations' in self.calibration_recommendations: - recs = self.calibration_recommendations['recommendations'] - - for sensor_type, rec in recs.items(): - if sensor_type == 'breathing': - f.write(f"// Breathing Detection Thresholds\n") - f.write(f"const int BREATH_IN_THRESHOLD = {rec['breath_in_threshold']};\n") - f.write(f"const int BREATH_OUT_THRESHOLD = {rec['breath_out_threshold']};\n") - f.write(f"const int MIN_BREATH_INTERVAL = {rec['min_breath_interval']};\n\n") - else: - f.write(f"// {sensor_type.upper()} Sensor Thresholds\n") - if 'peak_threshold' in rec: - f.write(f"const int {sensor_type.upper()}_PEAK_THRESHOLD = {rec['peak_threshold']};\n") - if 'change_threshold' in rec: - f.write(f"const int {sensor_type.upper()}_CHANGE_THRESHOLD = {rec['change_threshold']};\n") - if 'breath_threshold' in rec: - f.write(f"const int {sensor_type.upper()}_BREATH_THRESHOLD = {rec['breath_threshold']};\n") - f.write("\n") - - f.write("// Additional Recommendations:\n") - f.write("// - Consider implementing adaptive thresholds\n") - f.write("// - Monitor baseline drift over time\n") - f.write("// - Implement sensor health checks\n") - - print(f"โœ… Recommendations saved to: {filename}") - - except Exception as e: - print(f"โŒ Error saving recommendations: {e}") - -def main(): - parser = argparse.ArgumentParser(description='ESP32 Sensor Calibration Data Analyzer') - parser.add_argument('filename', help='Path to the calibration data file') - parser.add_argument('--output', '-o', help='Output file for recommendations', default='calibration_recommendations.txt') - parser.add_argument('--plot', '-p', action='store_true', help='Generate plots of sensor data') - - args = parser.parse_args() - - # Create analyzer - analyzer = SensorCalibrationAnalyzer() - - # Parse data - if not analyzer.parse_calibration_data(args.filename): - sys.exit(1) - - # Analyze data - analyzer.analyze_sensor_data() - analyzer.analyze_breathing_patterns() - - # Generate recommendations - recommendations = analyzer.generate_calibration_recommendations() - - # Print report - analyzer.print_calibration_report() - - # Save recommendations - analyzer.save_recommendations_to_file(args.output) - - print(f"\n๐ŸŽ‰ Analysis complete! Check '{args.output}' for ESP32 code recommendations.") - -if __name__ == "__main__": - main() diff --git a/Examples/esp32/main.ino b/Examples/esp32/main.ino index 7d9b13fb9..55680abaa 100644 --- a/Examples/esp32/main.ino +++ b/Examples/esp32/main.ino @@ -3,6 +3,11 @@ #include #include "PanTompkins.h" +// --- MPU6050 LIBRARIES & GLOBALS --- +#include +#include +#include + // Debug configuration - set to 0 to disable all debug prints #define DEBUG_MODE 1 #define DEBUG_INTERVAL 10000 // 10 seconds between comprehensive logs @@ -30,16 +35,16 @@ PanTompkins panTompkins; // --- ESP32 Hardware Pins --- // Updated for ESP32-WROOM-DA with better analog pin selection const int ECG_PIN = 32; // GPIO32 - ADC1_CH4 - Better analog input, more stable +const int LON_PIN = 35; +const int LOP_PIN = 34; const int GSR_PIN = 33; // GPIO33 - ADC1_CH5 - Better analog input, more stable -const int RESP_PIN = 27; // GPIO27 - ADC2_CH7 - Alternative to problematic GPIO34 +// RESP_PIN has been removed as we are now using the MPU6050 via I2C // Note: GPIO32 and GPIO33 are more reliable for analog sensors than GPIO36/39 -// GPIO27 is also more stable than GPIO34 for analog input // Sensor data variables int ecgSample = 0; int gsrSample = 0; -int respSample = 0; // Debug values for status reporting int gsrRawValue = 0; // Store raw ADC value for status report @@ -48,29 +53,11 @@ int gsrFilteredValue = 0; // Store filtered value for status report // Timing variables for proper sampling unsigned long lastEcgTime = 0; unsigned long lastGsrTime = 0; -unsigned long lastRespTime = 0; unsigned long lastSendTime = 0; // Global send timing variable const unsigned long ECG_INTERVAL = 4; // 4ms = ~250Hz for ECG const unsigned long GSR_INTERVAL = 100; // 100ms = 10Hz for GSR -const unsigned long RESP_INTERVAL = 10; // 10ms = 100Hz for respiratory - -// Data smoothing for GSR and Respiratory (reduced window size) -const int SMOOTH_WINDOW = 3; // Reduced from 5 to save memory -int gsrBuffer[SMOOTH_WINDOW] = {0}; -int respBuffer[SMOOTH_WINDOW] = {0}; -int gsrIndex = 0; -int respIndex = 0; - -// HW-484 Respiratory Rate Detection Variables -const int RESP_BUFFER_SIZE = 50; // Buffer for breath pattern analysis -int respRawBuffer[RESP_BUFFER_SIZE] = {0}; -int respBufferIndex = 0; -unsigned long lastBreathTime = 0; -int breathCount = 0; -int currentRespRate = 16; // Default respiratory rate -bool breathDetected = false; -const int BREATH_THRESHOLD = 100; // ADC threshold for breath detection -const int MIN_BREATH_INTERVAL = 2000; // Minimum 2 seconds between breaths + +// Note: Respiratory timing is now handled by MPU6050 sample rate // Sensor connection status (always true since we don't check) bool ecgSensorConnected = true; @@ -79,9 +66,11 @@ bool respSensorConnected = true; // Unified data structure for all sensor readings (optimized) struct SensorData { - float ecg; - float gsr; - float respiratory; + int ecg; // Changed from float to int for ADC values + int gsr; // Changed from float to int for ADC values + int respiratory; // Changed from float to int for breath rate + float inhaleRatio; // NEW: Inhale ratio percentage from MPU6050 + float exhaleRatio; // NEW: Exhale ratio percentage from MPU6050 int heartRate; int ibi; unsigned long timestamp; @@ -89,6 +78,37 @@ struct SensorData { SensorData currentData; +// --- MPU6050 Respiration Logic --- +Adafruit_MPU6050 mpu; + +// Calibrated settings for respiration detection +const float NOISE_THRESHOLD_POSITIVE = 0.05; +const float NOISE_THRESHOLD_NEGATIVE = -0.05; +const float EXHALE_END_THRESHOLD = 0.02; +#define GYRO_AXIS_TO_USE g.gyro.y + +// Algorithm constants +const int SAMPLE_RATE_HZ = 50; +const unsigned long SAMPLE_INTERVAL_MS = 1000 / SAMPLE_RATE_HZ; +#define MOVING_AVG_WINDOW_SIZE 8 +#define BREATH_HISTORY_SIZE 15 + +// Global variables for respiration calculation +float gyroHistory[MOVING_AVG_WINDOW_SIZE]; +int historyIndex = 0; +unsigned long breathTimestamps[BREATH_HISTORY_SIZE]; +int breathIndex = 0; +int breathCount = 0; +enum BreathState { IDLE, INHALING, EXHALING }; +BreathState currentState = IDLE; +unsigned long inhaleStartTime = 0; +unsigned long exhaleStartTime = 0; +unsigned long lastRespSampleTime = 0; +float breathsPerMinute = 0.0; + +// Global MPU6050 connection status +bool mpu6050Connected = false; + void onWebSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) { switch (type) { case WStype_DISCONNECTED: @@ -174,71 +194,157 @@ int calculateMovingAverage(int* buffer, int index, int windowSize) { return sum / validSamples; } -// HW-484 Respiratory Rate Detection Function -// Based on sound level variations for breath in/out detection -int calculateRespiratoryRate(int rawValue, unsigned long timestamp) { - // Store raw value in circular buffer for pattern analysis - respRawBuffer[respBufferIndex] = rawValue; - respBufferIndex = (respBufferIndex + 1) % RESP_BUFFER_SIZE; - - // Calculate baseline (average of recent values) - int baseline = 0; - for (int i = 0; i < RESP_BUFFER_SIZE; i++) { - baseline += respRawBuffer[i]; - } - baseline /= RESP_BUFFER_SIZE; - - // Detect breath based on significant deviation from baseline - int deviation = abs(rawValue - baseline); +// Note: calculateRespiratoryRate function has been replaced by handleRespiration() +// which uses MPU6050 gyroscope data for more accurate respiratory detection + +// Simple function to read analog value (no validation needed) +int readAnalogValue(int pin) { + return analogRead(pin); +} + +// Function to check MPU6050 connection status +void checkMPU6050Connection() { + static unsigned long lastCheck = 0; + unsigned long currentTime = millis(); - if (deviation > BREATH_THRESHOLD && !breathDetected) { - // Check if enough time has passed since last breath - if (timestamp - lastBreathTime > MIN_BREATH_INTERVAL) { - breathDetected = true; - lastBreathTime = timestamp; - breathCount++; - - // Calculate respiratory rate based on recent breath intervals - if (breathCount > 1) { - // Simple moving average of recent breath intervals - static unsigned long breathIntervals[5] = {0}; - static int intervalIndex = 0; + // Check connection every 10 seconds + if (currentTime - lastCheck >= 10000) { + lastCheck = currentTime; + + if (!mpu6050Connected) { + // Try to connect to MPU6050 + if (mpu.begin()) { + mpu6050Connected = true; + mpu.setGyroRange(MPU6050_RANGE_250_DEG); + mpu.setFilterBandwidth(MPU6050_BAND_21_HZ); + DEBUG_PRINTLN("โœ… MPU6050 reconnected! Switching to real respiration mode"); - breathIntervals[intervalIndex] = timestamp - lastBreathTime; - intervalIndex = (intervalIndex + 1) % 5; + // Initialize MPU6050 respiration variables + for (int i = 0; i < MOVING_AVG_WINDOW_SIZE; i++) gyroHistory[i] = 0.0; + for (int i = 0; i < BREATH_HISTORY_SIZE; i++) breathTimestamps[i] = 0; + } + } else { + // Check if MPU6050 is still responding + sensors_event_t a, g, temp; + if (!mpu.getEvent(&a, &g, &temp)) { + mpu6050Connected = false; + DEBUG_PRINTLN("โš ๏ธ MPU6050 disconnected! Switching to fallback respiration mode"); + } + } + } +} + +// New function to handle all respiration logic using MPU6050 +void handleRespiration() { + unsigned long currentTime = millis(); + + if (currentTime - lastRespSampleTime >= SAMPLE_INTERVAL_MS) { + lastRespSampleTime = currentTime; + + // Check if MPU6050 is connected before trying to use it + if (!mpu6050Connected) { + // MPU6050 not connected - use fallback respiration data + static unsigned long lastFallbackUpdate = 0; + if (currentTime - lastFallbackUpdate >= 5000) { // Update every 5 seconds + // Simulate breathing pattern changes + float timeFactor = currentTime * 0.001; // Convert to seconds + float variation = sin(timeFactor * 0.5) * 2; // Slow variation - // Calculate average interval and convert to breaths/min - unsigned long avgInterval = 0; - int validIntervals = 0; - for (int i = 0; i < 5; i++) { - if (breathIntervals[i] > 0) { - avgInterval += breathIntervals[i]; - validIntervals++; - } - } + currentData.respiratory = 16 + (int)variation; // Vary around 16 breaths/min + currentData.inhaleRatio = 40.0 + variation; // Vary around 40% + currentData.exhaleRatio = 100.0 - currentData.inhaleRatio; - if (validIntervals > 0) { - avgInterval /= validIntervals; - currentRespRate = 60000 / avgInterval; // Convert ms to breaths/min + // Send fallback respiratory data + sendRespiratoryData(); + lastFallbackUpdate = currentTime; + + DEBUG_PRINTF("๐Ÿซ Fallback Respiration: Rate=%d, I/E=%.1f%%/%.1f%%\n", + currentData.respiratory, currentData.inhaleRatio, currentData.exhaleRatio); + } + return; // Exit early - don't process MPU6050 data + } + + // MPU6050 is connected - process real sensor data + sensors_event_t a, g, temp; + mpu.getEvent(&a, &g, &temp); + float rawGyroValue = g.gyro.y; // Use Y-axis gyroscope data for respiration detection + + float smoothedGyroValue = 0.0; + gyroHistory[historyIndex] = rawGyroValue; + historyIndex = (historyIndex + 1) % MOVING_AVG_WINDOW_SIZE; + for (int i = 0; i < MOVING_AVG_WINDOW_SIZE; i++) { + smoothedGyroValue += gyroHistory[i]; + } + smoothedGyroValue /= MOVING_AVG_WINDOW_SIZE; + + // Debug: Log MPU6050 data every 5 seconds (after calculation) + static unsigned long lastDebugTime = 0; + if (currentTime - lastDebugTime >= 5000) { + DEBUG_PRINTF("๐Ÿ”„ MPU6050 Debug: Raw Y-Gyro=%.3f, Smoothed=%.3f, State=%d\n", + rawGyroValue, smoothedGyroValue, currentState); + lastDebugTime = currentTime; + } + + switch (currentState) { + case IDLE: + if (smoothedGyroValue < NOISE_THRESHOLD_NEGATIVE) { + currentState = INHALING; + inhaleStartTime = currentTime; + } + break; + case INHALING: + if (smoothedGyroValue > NOISE_THRESHOLD_POSITIVE) { + currentState = EXHALING; + exhaleStartTime = currentTime; + } + break; + case EXHALING: + if (smoothedGyroValue < EXHALE_END_THRESHOLD) { + breathTimestamps[breathIndex] = currentTime; + breathIndex = (breathIndex + 1) % BREATH_HISTORY_SIZE; + if (breathCount < BREATH_HISTORY_SIZE) breathCount++; - // Ensure respiratory rate is within realistic range (8-30 breaths/min) - if (currentRespRate < 8) currentRespRate = 8; - if (currentRespRate > 30) currentRespRate = 30; + unsigned long inhaleDurationMs = exhaleStartTime - inhaleStartTime; + unsigned long exhaleDurationMs = currentTime - exhaleStartTime; + unsigned long totalDurationMs = inhaleDurationMs + exhaleDurationMs; + + if (totalDurationMs > 500 && totalDurationMs < 15000) { + currentData.inhaleRatio = (float)inhaleDurationMs / totalDurationMs * 100.0; + currentData.exhaleRatio = (float)exhaleDurationMs / totalDurationMs * 100.0; + + if (breathCount > 1) { + int oldestIndex = (breathCount == BREATH_HISTORY_SIZE) ? breathIndex : 0; + unsigned long timeSpan = breathTimestamps[(breathIndex - 1 + BREATH_HISTORY_SIZE) % BREATH_HISTORY_SIZE] - breathTimestamps[oldestIndex]; + int breathsInSpan = (breathCount == BREATH_HISTORY_SIZE) ? (BREATH_HISTORY_SIZE - 1) : (breathCount - 1); + + if (timeSpan > 0) { + breathsPerMinute = (float)breathsInSpan / timeSpan * 60000.0; + currentData.respiratory = (int)round(breathsPerMinute); + + // Send the updated data to the frontend + sendRespiratoryData(); + + // Debug: Log when respiratory data is sent + DEBUG_PRINTF("๐Ÿซ Respiratory Data Sent: Rate=%d, I/E=%.1f%%/%.1f%%\n", + currentData.respiratory, currentData.inhaleRatio, currentData.exhaleRatio); + } + } + } + currentState = IDLE; } - } - - DEBUG_PRINTF("๐Ÿซ Breath detected! Count: %d, Rate: %d breaths/min\n", breathCount, currentRespRate); + break; + } + + // Send respiratory data continuously (even when no breath detected) to keep frontend updated + // This ensures the frontend doesn't get overwritten by fallback values + static unsigned long lastContinuousRespSend = 0; + if (currentTime - lastContinuousRespSend >= 1000) { // Send every second + sendRespiratoryData(); + lastContinuousRespSend = currentTime; + DEBUG_PRINTF("๐Ÿซ Continuous Respiratory Data Sent: Rate=%d, I/E=%.1f%%/%.1f%%\n", + currentData.respiratory, currentData.inhaleRatio, currentData.exhaleRatio); } - } else if (deviation <= BREATH_THRESHOLD) { - breathDetected = false; } - - return currentRespRate; -} - -// Simple function to read analog value (no validation needed) -int readAnalogValue(int pin) { - return analogRead(pin); } // Function to send ECG data at 250Hz @@ -246,7 +352,6 @@ void sendECGData() { StaticJsonDocument<256> jsonDoc; jsonDoc["type"] = "ecg"; - jsonDoc["value"] = currentData.ecg; // Raw 12-bit ADC value (0-4095) jsonDoc["ecg"] = currentData.ecg; // Frontend expects this field jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization jsonDoc["sensorConnected"] = ecgSensorConnected; @@ -258,6 +363,8 @@ void sendECGData() { } sendData(jsonString); + + } // Function to send GSR data at 10Hz @@ -265,7 +372,6 @@ void sendGSRData() { StaticJsonDocument<256> jsonDoc; jsonDoc["type"] = "gsr"; - jsonDoc["value"] = currentData.gsr; // Raw smoothed value (0-4095) jsonDoc["gsr"] = currentData.gsr; // Frontend expects this field jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization jsonDoc["sensorConnected"] = gsrSensorConnected; @@ -277,19 +383,18 @@ void sendGSRData() { } sendData(jsonString); + + } -// Function to send respiratory data at 100Hz +// Function to send respiratory data, now including I/E ratio void sendRespiratoryData() { StaticJsonDocument<256> jsonDoc; - // currentData.respiratory now contains the calculated respiratory rate from HW-484 - // No need for conversion - it's already in breaths/min - int respRate = currentData.respiratory; - jsonDoc["type"] = "respiratory"; - jsonDoc["value"] = respRate; // Respiratory rate in breaths/min - jsonDoc["respiratory"] = respRate; // Frontend expects this field + jsonDoc["respiratory"] = currentData.respiratory; // Frontend expects this field + jsonDoc["inhaleRatio"] = currentData.inhaleRatio; // NEW: Inhale ratio percentage + jsonDoc["exhaleRatio"] = currentData.exhaleRatio; // NEW: Exhale ratio percentage jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization jsonDoc["sensorConnected"] = respSensorConnected; @@ -307,7 +412,6 @@ void sendIBIData() { StaticJsonDocument<256> jsonDoc; jsonDoc["type"] = "ibi"; - jsonDoc["value"] = currentData.ibi; // IBI in milliseconds jsonDoc["hrv"] = currentData.ibi; // Frontend expects this field jsonDoc["bpm"] = currentData.heartRate; // Frontend expects bpm, not hr jsonDoc["timestamp"] = millis(); // ESP32 timestamp for synchronization @@ -320,6 +424,8 @@ void sendIBIData() { } sendData(jsonString); + + } // Function to send continuous heart rate data (even when no beat detected) @@ -340,10 +446,18 @@ void sendHeartRateData() { } sendData(jsonString); + + } void setup() { Serial.begin(115200); + Wire.begin(); // Initialize I2C for MPU6050 + pinMode(LON_PIN, INPUT); + pinMode(LOP_PIN, INPUT); + + // Configure basic watchdog timer to prevent crashes + // ESP32 Arduino has built-in watchdog protection // Configure ADC for ESP32 with better settings analogReadResolution(12); // ESP32 has 12-bit ADC @@ -355,19 +469,46 @@ void setup() { // Pin configuration info DEBUG_PRINTF("ECG Sensor Pin: GPIO%d (ADC1_CH4)\n", ECG_PIN); DEBUG_PRINTF("GSR Sensor Pin: GPIO%d (ADC1_CH5)\n", GSR_PIN); - DEBUG_PRINTF("RESP Sensor Pin: GPIO%d (ADC2_CH7) - HW-484 Sound Sensor\n", RESP_PIN); + DEBUG_PRINTLN("RESP Sensor: MPU6050 Gyroscope (I2C) - Replaced HW-484 Sound Sensor"); DEBUG_PRINTLN(); - // Initialize smoothing buffers - for (int i = 0; i < SMOOTH_WINDOW; i++) { - gsrBuffer[i] = 2048; // Mid-range value for 12-bit ADC - respBuffer[i] = 2048; // Mid-range value for 12-bit ADC + // MPU6050 Initialization with fallback + bool mpu6050Connected = false; + if (mpu.begin()) { + mpu6050Connected = true; + DEBUG_PRINTLN("โœ… MPU6050 Respiration Sensor Found!"); + mpu.setGyroRange(MPU6050_RANGE_250_DEG); + mpu.setFilterBandwidth(MPU6050_BAND_21_HZ); + + // Initialize MPU6050 respiration variables + for (int i = 0; i < MOVING_AVG_WINDOW_SIZE; i++) gyroHistory[i] = 0.0; + for (int i = 0; i < BREATH_HISTORY_SIZE; i++) breathTimestamps[i] = 0; + + DEBUG_PRINTLN(" - Gyro Range: 250ยฐ/s"); + DEBUG_PRINTLN(" - Filter Bandwidth: 21Hz"); + DEBUG_PRINTLN(" - Sample Rate: 50Hz"); + DEBUG_PRINTLN(" - Moving Average Window: 8 samples"); + DEBUG_PRINTLN(" - Breath History Buffer: 15 samples"); + } else { + DEBUG_PRINTLN("โš ๏ธ MPU6050 not found - Using fallback respiration mode"); + DEBUG_PRINTLN(" - Check I2C connections (SDA/SCL)"); + DEBUG_PRINTLN(" - Verify MPU6050 has power (VCC and GND)"); + DEBUG_PRINTLN(" - ESP32 will continue with simulated respiration data"); + DEBUG_PRINTLN(" - ECG and GSR sensors will work normally"); + + // Set fallback respiration data + currentData.respiratory = 16; // Default to normal breathing rate + currentData.inhaleRatio = 40.0; // Default to 40% inhale + currentData.exhaleRatio = 60.0; // Default to 60% exhale } - // Initialize HW-484 respiratory detection buffer - for (int i = 0; i < RESP_BUFFER_SIZE; i++) { - respRawBuffer[i] = 2048; // Mid-range value for 12-bit ADC + // Initialize respiratory data structure (either MPU6050 or fallback) + if (!mpu6050Connected) { + currentData.respiratory = 16; // Default to normal breathing rate + currentData.inhaleRatio = 40.0; // Default to 40% inhale + currentData.exhaleRatio = 60.0; // Default to 60% exhale } + DEBUG_PRINTLN(); // Test sensor pins with multiple readings DEBUG_PRINTLN("Testing sensor pins..."); @@ -395,22 +536,31 @@ void setup() { DEBUG_PRINTLN(" - Verify GSR sensor is connected to GPIO33"); DEBUG_PRINTLN(" - Check if sensor has power (VCC and GND)"); DEBUG_PRINTLN(" - Try touching the sensor electrodes"); + DEBUG_PRINTLN(" - Check if GSR_PIN is correctly defined as GPIO33"); } else if (gsrAvg < 100) { DEBUG_PRINTLN("โš ๏ธ WARNING: GSR sensor showing very low values"); DEBUG_PRINTLN(" - Sensor may be disconnected or faulty"); DEBUG_PRINTLN(" - Check electrode contact"); + DEBUG_PRINTLN(" - Raw values: " + String(gsrTestValues[0]) + ", " + String(gsrTestValues[1]) + ", " + String(gsrTestValues[2]) + ", " + String(gsrTestValues[3]) + ", " + String(gsrTestValues[4])); } else { DEBUG_PRINTLN("โœ… GSR sensor appears to be working"); + DEBUG_PRINTLN(" - Average value: " + String(gsrAvg)); + DEBUG_PRINTLN(" - Range: " + String(gsrTestValues[0]) + " to " + String(gsrTestValues[4])); } - DEBUG_PRINTF("RESP Pin %d: %d\n", RESP_PIN, analogRead(RESP_PIN)); - - // Test HW-484 respiratory sensor multiple times - DEBUG_PRINTLN("Testing HW-484 respiratory sensor (sound-based breath detection)..."); - for (int i = 0; i < 10; i++) { - int respTest = analogRead(RESP_PIN); - DEBUG_PRINTF("RESP Test #%d: %d\n", i+1, respTest); - delay(100); + // Test MPU6050 if connected + if (mpu6050Connected) { + DEBUG_PRINTLN("MPU6050: Testing gyroscope readings..."); + sensors_event_t a, g, temp; + mpu.getEvent(&a, &g, &temp); + DEBUG_PRINTF(" - Gyro Y-axis: %.3f rad/s\n", g.gyro.y); + DEBUG_PRINTF(" - Gyro X-axis: %.3f rad/s\n", g.gyro.x); + DEBUG_PRINTF(" - Gyro Z-axis: %.3f rad/s\n", g.gyro.z); + DEBUG_PRINTLN(" - Place MPU6050 on chest for respiration detection"); + } else { + DEBUG_PRINTLN("MPU6050: Skipping gyroscope test (sensor not connected)"); + DEBUG_PRINTLN(" - Using fallback respiration data"); + DEBUG_PRINTLN(" - Connect MPU6050 for real respiration detection"); } // Initialize system @@ -432,7 +582,8 @@ void setup() { if (WiFi.status() != WL_CONNECTED) { DEBUG_PRINTLN("\nERROR: WiFi connection failed! Check credentials."); - ESP.restart(); // Restart ESP32 if WiFi fails + DEBUG_PRINTLN("ESP32 will continue running without WiFi - check your network settings."); + // Don't restart - let it continue running } DEBUG_PRINTLN("\nWiFi connected!"); @@ -457,6 +608,20 @@ void loop() { unsigned long currentTime = millis(); + // Handle millis() overflow (occurs every ~49 days) + static unsigned long lastLoopTime = 0; + if (currentTime < lastLoopTime) { + // Overflow occurred, reset timing variables + lastEcgTime = 0; + lastGsrTime = 0; + lastSendTime = 0; + lastRespSampleTime = 0; + } + lastLoopTime = currentTime; + + // Check MPU6050 connection status periodically + checkMPU6050Connection(); + // Comprehensive status update every 10 seconds (reduced from 5) static unsigned long lastStatusTime = 0; if (currentTime - lastStatusTime >= DEBUG_INTERVAL) { @@ -478,74 +643,143 @@ void loop() { DEBUG_PRINTF(" WiFi RSSI: %d dBm\n", WiFi.RSSI()); DEBUG_PRINTF(" IP Address: %s\n", WiFi.localIP().toString().c_str()); DEBUG_PRINTF(" WebSocket Clients: %d\n", webSocket.connectedClients()); + DEBUG_PRINTF(" MPU6050 Status: %s\n", mpu6050Connected ? "โœ… Connected" : "โš ๏ธ Disconnected (Fallback Mode)"); // Sensor Data Summary DEBUG_PRINTLN("\n๐Ÿ“ก SENSOR DATA SUMMARY:"); - DEBUG_PRINTF(" ECG: %d (Raw: %d)\n", ecgSample, analogRead(ECG_PIN)); - DEBUG_PRINTF(" GSR: %d (Raw: %d, Filtered: %d)\n", gsrSample, gsrRawValue, gsrFilteredValue); - DEBUG_PRINTF(" RESP: %d (Raw: %d)\n", respSample, analogRead(RESP_PIN)); + DEBUG_PRINTF(" ECG: %d (Raw: %d, Noise Filtered: %s, Threshold: >%d)\n", + ecgSample, analogRead(ECG_PIN), ecgSample > 50 ? "YES" : "NO", 50); + DEBUG_PRINTF(" GSR: %d (Raw: %d, No Processing)\n", gsrSample, gsrRawValue); + DEBUG_PRINTF(" RESP: %d breaths/min (%s, I/E: %.1f%%/%.1f%%)\n", + currentData.respiratory, + mpu6050Connected ? "MPU6050 Gyro" : "Fallback Mode", + currentData.inhaleRatio, currentData.exhaleRatio); + + // ECG Detailed Status + DEBUG_PRINTLN("\n๐Ÿซ€ ECG DETAILED STATUS:"); + DEBUG_PRINTF(" Current Sample: %d\n", ecgSample); + DEBUG_PRINTF(" Raw ADC Value: %d\n", analogRead(ECG_PIN)); + DEBUG_PRINTF(" Noise Filtered: %s\n", ecgSample > 50 ? "YES" : "NO"); + DEBUG_PRINTF(" Threshold: >%d ADC units\n", 50); + DEBUG_PRINTF(" Lead-Off Detection: LON=%s, LOP=%s\n", + digitalRead(LON_PIN) == LOW ? "CONNECTED" : "DISCONNECTED", + digitalRead(LOP_PIN) == LOW ? "CONNECTED" : "DISCONNECTED"); + DEBUG_PRINTF(" Heart Rate: %d BPM\n", currentData.heartRate); + DEBUG_PRINTF(" IBI: %d ms\n", currentData.ibi); + DEBUG_PRINTF(" Pan-Tompkins Status: %s\n", "ACTIVE"); // Pan-Tompkins always active when ECG data is processed // Data Transmission Stats DEBUG_PRINTLN("\n๐Ÿ“ค DATA TRANSMISSION:"); - DEBUG_PRINTF(" Last ECG Send: %lu ms ago\n", currentTime - lastEcgTime); - DEBUG_PRINTF(" Last GSR Send: %lu ms ago\n", currentTime - lastGsrTime); - DEBUG_PRINTF(" Last RESP Send: %lu ms ago\n", currentTime - lastRespTime); + DEBUG_PRINTF(" Last ECG Send: %lu ms ago (Noise Filtered: >%d ADC)\n", currentTime - lastEcgTime, 50); + DEBUG_PRINTF(" Last GSR Send: %lu ms ago (GSR_INTERVAL: %lu ms, Raw Values)\n", currentTime - lastGsrTime, GSR_INTERVAL); + DEBUG_PRINTF(" Last RESP Send: %lu ms ago\n", currentTime - lastSendTime); DEBUG_PRINTF(" Last Data Send: %lu ms ago\n", currentTime - lastSendTime); + // Transmission Status & Last Values + DEBUG_PRINTLN("\n๐Ÿ“Š LAST TRANSMITTED VALUES:"); + DEBUG_PRINTF(" ECG: %d (Raw ADC, Noise Filtered)\n", currentData.ecg); + DEBUG_PRINTF(" GSR: %d (Raw ADC, No Processing)\n", currentData.gsr); + DEBUG_PRINTF(" Respiratory: %d breaths/min (%s)\n", + currentData.respiratory, + mpu6050Connected ? "MPU6050 Gyro" : "Fallback Mode"); + DEBUG_PRINTF(" Heart Rate: %d BPM (Pan-Tompkins)\n", currentData.heartRate); + DEBUG_PRINTF(" IBI: %d ms (Inter-Beat Interval)\n", currentData.ibi); + + // Transmission Schedule Status + DEBUG_PRINTLN("\nโฐ TRANSMISSION SCHEDULE:"); + if (currentTime - lastEcgTime >= ECG_INTERVAL) { + DEBUG_PRINTF(" โœ… ECG: On schedule (next in %lu ms)\n", ECG_INTERVAL - (currentTime - lastEcgTime)); + } else { + DEBUG_PRINTF(" โš ๏ธ ECG: Overdue! (should be every %lu ms)\n", ECG_INTERVAL); + } + + if (currentTime - lastGsrTime >= GSR_INTERVAL) { + DEBUG_PRINTF(" โš ๏ธ GSR: Overdue! (should be every %lu ms)\n", GSR_INTERVAL); + } else { + DEBUG_PRINTF(" โœ… GSR: On schedule (next in %lu ms)\n", GSR_INTERVAL - (currentTime - lastGsrTime)); + } + + if (currentTime - lastSendTime >= SAMPLE_INTERVAL_MS) { // Use SAMPLE_INTERVAL_MS for MPU6050 + DEBUG_PRINTF(" โš ๏ธ RESP: Overdue! (should be every %lu ms)\n", SAMPLE_INTERVAL_MS); + } else { + DEBUG_PRINTF(" โœ… RESP: On schedule (next in %lu ms)\n", SAMPLE_INTERVAL_MS - (currentTime - lastSendTime)); + } + + // Sensor Analysis & Trends + DEBUG_PRINTLN("\n๐Ÿ”ฌ SENSOR ANALYSIS:"); + DEBUG_PRINTF(" ECG Signal Quality: %s\n", ecgSample > 200 ? "EXCELLENT" : ecgSample > 100 ? "GOOD" : ecgSample > 50 ? "FAIR" : "POOR"); + DEBUG_PRINTF(" GSR Baseline: %d (Range: %d-%d)\n", gsrSample, gsrSample - 50, gsrSample + 50); + DEBUG_PRINTF(" Respiratory Pattern: %s (I/E Ratio: %.1f%%/%.1f%%, %s)\n", + currentData.respiratory > 20 ? "FAST" : currentData.respiratory > 12 ? "NORMAL" : "SLOW", + currentData.inhaleRatio, currentData.exhaleRatio, + mpu6050Connected ? "MPU6050 Active" : "Fallback Mode"); + DEBUG_PRINTF(" Heart Rate Zone: %s\n", currentData.heartRate > 100 ? "HIGH" : currentData.heartRate > 60 ? "NORMAL" : "LOW"); + // Memory and Performance DEBUG_PRINTLN("\n๐Ÿ’พ SYSTEM STATUS:"); DEBUG_PRINTF(" Free Heap: %d bytes\n", ESP.getFreeHeap()); DEBUG_PRINTF(" Uptime: %lu seconds\n", currentTime / 1000); + // Safe loop frequency calculation (avoid division by zero) + if (currentTime > lastLoopTime) { + DEBUG_PRINTF(" Loop Frequency: %lu Hz\n", 1000 / (currentTime - lastLoopTime)); + } else { + DEBUG_PRINTF(" Loop Frequency: %s\n", "Calculating..."); + } DEBUG_PRINTLN(String("=", 60)); DEBUG_PRINTLN(); } - // Handle millis() overflow (occurs every ~49 days) - static unsigned long lastLoopTime = 0; - if (currentTime < lastLoopTime) { - // Overflow occurred, reset timing variables - lastEcgTime = 0; - lastGsrTime = 0; - lastRespTime = 0; - lastSendTime = 0; - } - lastLoopTime = currentTime; - currentData.timestamp = currentTime; // --- ECG Processing (250Hz) --- if (currentTime - lastEcgTime >= ECG_INTERVAL) { lastEcgTime = currentTime; - // Read analog value directly - ecgSample = readAnalogValue(ECG_PIN); + // Read analog value directly with error handling + if(digitalRead(LON_PIN) == LOW || digitalRead(LOP_PIN) == LOW) { + ecgSample = readAnalogValue(ECG_PIN); + // Validate ECG reading + if (ecgSample < 0 || ecgSample > 4095) { + ecgSample = 0; // Reset to safe value if out of range + } + } - // Send raw ECG data (0-4095) to frontend for proper normalization - // Frontend will convert to millivolts based on sensor calibration - currentData.ecg = ecgSample; // Raw 12-bit ADC value + // Filter out zero and near-zero values for cleaner ECG plotting + // Only send ECG data if it's above noise threshold (prevents vertical lines) + const int ECG_NOISE_THRESHOLD = 50; // Minimum ADC value to consider valid - // Process ECG for beat detection - // Normalize ECG sample to 0-1 range for Pan-Tompkins algorithm - float normalizedEcg = (float)ecgSample / 4095.0; + - if (panTompkins.detect(normalizedEcg)) { - currentData.ibi = panTompkins.getIbi(); - currentData.heartRate = panTompkins.getBPM(); - - // Debug: Log heartbeat detection - DEBUG_PRINTF("๐Ÿ’“ Heartbeat detected! BPM: %d, IBI: %d ms\n", currentData.heartRate, currentData.ibi); + if (ecgSample > ECG_NOISE_THRESHOLD) { + // Send raw ECG data (above noise threshold) to frontend + currentData.ecg = ecgSample; // Raw 12-bit ADC value + + // Process ECG for beat detection + // Normalize ECG sample to 0-1 range for Pan-Tompkins algorithm + float normalizedEcg = (float)ecgSample / 4095.0; - // Send IBI data immediately when detected - sendIBIData(); + if (panTompkins.detect(normalizedEcg)) { + currentData.ibi = panTompkins.getIbi(); + currentData.heartRate = panTompkins.getBPM(); + + + + // Send IBI data immediately when detected + sendIBIData(); + + // Also send heart rate data when beat is detected + sendHeartRateData(); + } - // Also send heart rate data when beat is detected - sendHeartRateData(); + // Send ECG data immediately at 250Hz (only non-zero values) + sendECGData(); + } else { + // Skip sending zero/near-zero ECG values to prevent noisy plotting + // This will create cleaner horizontal ECG plots + currentData.ecg = 0; // Keep as 0 for internal processing } - // Send ECG data immediately at 250Hz - sendECGData(); - // Send continuous heart rate data every few seconds (even when no beat detected) // This ensures frontend always has heart rate info static unsigned long lastHeartRateSend = 0; @@ -555,42 +789,32 @@ void loop() { } } + // Small delay to prevent system from running too fast + delay(1); + // --- GSR Processing (10Hz) --- if (currentTime - lastGsrTime >= GSR_INTERVAL) { lastGsrTime = currentTime; - // Read analog value directly + // Read analog value directly with error handling gsrSample = readAnalogValue(GSR_PIN); - // Smooth GSR data - gsrBuffer[gsrIndex] = gsrSample; - gsrIndex = (gsrIndex + 1) % SMOOTH_WINDOW; - int smoothedGsr = calculateMovingAverage(gsrBuffer, gsrIndex, SMOOTH_WINDOW); + // Validate GSR reading + if (gsrSample < 0 || gsrSample > 4095) { + gsrSample = 2048; // Reset to mid-range if out of range + } - // Update current data and debug values - currentData.gsr = smoothedGsr; + // Send raw GSR value without any processing or smoothing + // Frontend will handle trend analysis and arrow display + currentData.gsr = gsrSample; gsrRawValue = gsrSample; - gsrFilteredValue = smoothedGsr; + gsrFilteredValue = gsrSample; // Send GSR data immediately at 10Hz sendGSRData(); } - // --- Respiratory Processing (100Hz) --- - if (currentTime - lastRespTime >= RESP_INTERVAL) { - lastRespTime = currentTime; - - // Read analog value directly from HW-484 sound sensor - respSample = readAnalogValue(RESP_PIN); - - // Use the new breath detection algorithm for HW-484 - int calculatedRespRate = calculateRespiratoryRate(respSample, currentTime); - - // Update current data with calculated respiratory rate - currentData.respiratory = calculatedRespRate; - - // Send respiratory data immediately at 100Hz - sendRespiratoryData(); - } + // --- MPU6050 Respiration Processing (50Hz) --- + handleRespiration(); -} \ No newline at end of file +} \ No newline at end of file diff --git a/Examples/esp32/mpu6050.ino b/Examples/esp32/mpu6050.ino new file mode 100644 index 000000000..5253515ff --- /dev/null +++ b/Examples/esp32/mpu6050.ino @@ -0,0 +1,131 @@ +#include +#include +#include + +// --- REFINED SETTINGS --- +const float NOISE_THRESHOLD_POSITIVE = 0.05; +const float NOISE_THRESHOLD_NEGATIVE = -0.05; + +// --- FIX 1: Relaxed the exhale end threshold to be more sensitive --- +// This allows the gentle, tail-end of an exhale to be counted properly. +const float EXHALE_END_THRESHOLD = 0.02; + +#define GYRO_AXIS_TO_USE g.gyro.y + +// --- Algorithm Constants --- +const int SAMPLE_RATE_HZ = 50; +const unsigned long SAMPLE_INTERVAL_MS = 1000 / SAMPLE_RATE_HZ; + +#define MOVING_AVG_WINDOW_SIZE 8 +float gyroHistory[MOVING_AVG_WINDOW_SIZE]; +int historyIndex = 0; + +// --- FIX 2: Expanded the buffer for a more stable BPM calculation --- +#define BREATH_HISTORY_SIZE 15 +unsigned long breathTimestamps[BREATH_HISTORY_SIZE]; +int breathIndex = 0; +int breathCount = 0; + +enum BreathState { IDLE, INHALING, EXHALING }; +BreathState currentState = IDLE; + +unsigned long inhaleStartTime = 0; +unsigned long exhaleStartTime = 0; +unsigned long lastSampleTime = 0; + +float breathsPerMinute = 0.0; +float inhaleRatio = 0.0; +float exhaleRatio = 0.0; + +Adafruit_MPU6050 mpu; + +void setup() { + Serial.begin(115200); + Wire.begin(); + + if (!mpu.begin()) { + Serial.println("Failed to find MPU6050 chip"); + while (1) { delay(10); } + } + Serial.println("MPU6050 Found! Final adjustments applied."); + + mpu.setGyroRange(MPU6050_RANGE_250_DEG); + mpu.setFilterBandwidth(MPU6050_BAND_21_HZ); + + for (int i = 0; i < MOVING_AVG_WINDOW_SIZE; i++) gyroHistory[i] = 0.0; + for (int i = 0; i < BREATH_HISTORY_SIZE; i++) breathTimestamps[i] = 0; + + Serial.println("Place sensor on chest. Starting measurement in 5 seconds..."); + delay(5000); +} + +void loop() { + unsigned long currentTime = millis(); + + if (currentTime - lastSampleTime >= SAMPLE_INTERVAL_MS) { + lastSampleTime = currentTime; + + sensors_event_t a, g, temp; + mpu.getEvent(&a, &g, &temp); + + float rawGyroValue = GYRO_AXIS_TO_USE; + + float smoothedGyroValue = 0.0; + gyroHistory[historyIndex] = rawGyroValue; + historyIndex = (historyIndex + 1) % MOVING_AVG_WINDOW_SIZE; + for (int i = 0; i < MOVING_AVG_WINDOW_SIZE; i++) { + smoothedGyroValue += gyroHistory[i]; + } + smoothedGyroValue /= MOVING_AVG_WINDOW_SIZE; + + switch (currentState) { + case IDLE: + if (smoothedGyroValue < NOISE_THRESHOLD_NEGATIVE) { + currentState = INHALING; + inhaleStartTime = currentTime; + } + break; + + case INHALING: + if (smoothedGyroValue > NOISE_THRESHOLD_POSITIVE) { + currentState = EXHALING; + exhaleStartTime = currentTime; + } + break; + + case EXHALING: + // Using the new, more relaxed threshold to end the cycle. + if (smoothedGyroValue < EXHALE_END_THRESHOLD) { + // --- A FULL BREATH CYCLE IS COMPLETE --- + + breathTimestamps[breathIndex] = currentTime; + breathIndex = (breathIndex + 1) % BREATH_HISTORY_SIZE; + if (breathCount < BREATH_HISTORY_SIZE) breathCount++; + + unsigned long inhaleDurationMs = exhaleStartTime - inhaleStartTime; + unsigned long exhaleDurationMs = currentTime - exhaleStartTime; + unsigned long totalDurationMs = inhaleDurationMs + exhaleDurationMs; + + if (totalDurationMs > 500 && totalDurationMs < 15000) { + inhaleRatio = (float)inhaleDurationMs / totalDurationMs * 100.0; + exhaleRatio = (float)exhaleDurationMs / totalDurationMs * 100.0; + + if (breathCount > 1) { + int oldestIndex = (breathCount == BREATH_HISTORY_SIZE) ? breathIndex : 0; + unsigned long timeSpan = breathTimestamps[(breathIndex - 1 + BREATH_HISTORY_SIZE) % BREATH_HISTORY_SIZE] - breathTimestamps[oldestIndex]; + int breathsInSpan = (breathCount == BREATH_HISTORY_SIZE) ? (BREATH_HISTORY_SIZE - 1) : (breathCount - 1); + + if (timeSpan > 0) { + breathsPerMinute = (float)breathsInSpan / timeSpan * 60000.0; + } + } + } + currentState = IDLE; + } + break; + } + + Serial.printf("BPM: %.2f | I/E: %.1f/%.1f | State: %d | Smoothed: %.2f\n", + breathsPerMinute, inhaleRatio, exhaleRatio, currentState, smoothedGyroValue); + } +} \ No newline at end of file diff --git a/Examples/esp32/requirements.txt b/Examples/esp32/requirements.txt deleted file mode 100644 index 4e7e7ae0d..000000000 --- a/Examples/esp32/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -numpy>=1.21.0 -matplotlib>=3.5.0 -argparse -datetime diff --git a/Examples/esp32/sensor_calibration.ino b/Examples/esp32/sensor_calibration.ino deleted file mode 100644 index 35e1a7c1c..000000000 --- a/Examples/esp32/sensor_calibration.ino +++ /dev/null @@ -1,370 +0,0 @@ -/* - * ESP32 Sensor Calibration & Raw Data Logger - * - * This file is designed to: - * 1. Output raw ADC values from all sensors - * 2. Analyze breathing patterns from HW-484 sound sensor - * 3. Calibrate breath detection thresholds - * 4. Understand sensor baseline values and ranges - * - * Upload this file to your ESP32 and open Serial Monitor at 115200 baud - * Copy-paste the output for analysis - */ - -// --- Hardware Pin Configuration --- -const int ECG_PIN = 32; // GPIO32 - AD8232 ECG sensor -const int GSR_PIN = 33; // GPIO33 - GSR (Galvanic Skin Response) sensor -const int RESP_PIN = 27; // GPIO27 - HW-484 sound sensor for breathing - -// --- Calibration Constants --- -const int CALIBRATION_DURATION = 30000; // 30 seconds for baseline calibration -const int BREATH_ANALYSIS_DURATION = 60000; // 60 seconds for breath pattern analysis -const int SAMPLE_INTERVAL = 10; // 10ms = 100Hz sampling rate - -// --- Sensor Data Buffers --- -const int BUFFER_SIZE = 1000; // Store 1000 samples for analysis -int ecgBuffer[BUFFER_SIZE]; -int gsrBuffer[BUFFER_SIZE]; -int respBuffer[BUFFER_SIZE]; -int bufferIndex = 0; - -// --- Timing Variables --- -unsigned long startTime = 0; -unsigned long lastSampleTime = 0; -unsigned long calibrationStartTime = 0; -unsigned long breathAnalysisStartTime = 0; - -// --- Calibration State --- -enum CalibrationState { - BASELINE_CALIBRATION, - BREATH_ANALYSIS, - CONTINUOUS_MONITORING -}; -CalibrationState currentState = BASELINE_CALIBRATION; - -// --- Statistical Variables --- -int ecgMin = 4095, ecgMax = 0, ecgBaseline = 0; -int gsrMin = 4095, gsrMax = 0, gsrBaseline = 0; -int respMin = 4095, respMax = 0, respBaseline = 0; - -// --- Breath Detection Variables --- -int breathInThreshold = 0; -int breathOutThreshold = 0; -int breathInCount = 0; -int breathOutCount = 0; -unsigned long lastBreathTime = 0; -const int MIN_BREATH_INTERVAL = 1000; // 1 second minimum between breaths - -void setup() { - Serial.begin(115200); - delay(1000); - - // Configure ADC pins - analogReadResolution(12); // Set ADC resolution to 12 bits (0-4095) - - // Set attenuation for better voltage range - analogSetAttenuation(ADC_ATTEN_DB_11); // 0-3.3V range - - Serial.println("\n" + String("=").repeat(60)); - Serial.println("๐Ÿ”ฌ ESP32 SENSOR CALIBRATION & RAW DATA LOGGER"); - Serial.println("=" + String("=").repeat(59)); - Serial.println(); - - Serial.println("๐Ÿ“‹ CALIBRATION INSTRUCTIONS:"); - Serial.println("1. Ensure all sensors are properly connected"); - Serial.println("2. Keep subject still during baseline calibration (30s)"); - Serial.println("3. Perform breathing exercises during breath analysis (60s)"); - Serial.println("4. Monitor continuous data for real-time analysis"); - Serial.println(); - - Serial.println("๐Ÿ”Œ SENSOR CONNECTIONS:"); - Serial.println(" ECG (AD8232): GPIO32"); - Serial.println(" GSR: GPIO33"); - Serial.println(" RESP (HW-484): GPIO27"); - Serial.println(); - - Serial.println("โฑ๏ธ CALIBRATION PHASES:"); - Serial.println(" Phase 1: Baseline Calibration (30s) - Stay still"); - Serial.println(" Phase 2: Breath Analysis (60s) - Breathe normally"); - Serial.println(" Phase 3: Continuous Monitoring - Real-time data"); - Serial.println(); - - Serial.println("๐Ÿš€ Starting calibration in 5 seconds..."); - Serial.println(" Please ensure subject is ready and sensors are connected"); - Serial.println(); - - for (int i = 5; i > 0; i--) { - Serial.printf(" %d...\n", i); - delay(1000); - } - - Serial.println("๐ŸŽฏ STARTING BASELINE CALIBRATION"); - Serial.println(" Please remain STILL for the next 30 seconds"); - Serial.println(); - - startTime = millis(); - calibrationStartTime = millis(); - currentState = BASELINE_CALIBRATION; - - // Initialize buffers - for (int i = 0; i < BUFFER_SIZE; i++) { - ecgBuffer[i] = 0; - gsrBuffer[i] = 0; - respBuffer[i] = 0; - } -} - -void loop() { - unsigned long currentTime = millis(); - - // Sample sensors at regular intervals - if (currentTime - lastSampleTime >= SAMPLE_INTERVAL) { - lastSampleTime = currentTime; - - // Read raw sensor values - int ecgRaw = analogRead(ECG_PIN); - int gsrRaw = analogRead(GSR_PIN); - int respRaw = analogRead(RESP_PIN); - - // Store in circular buffer - ecgBuffer[bufferIndex] = ecgRaw; - gsrBuffer[bufferIndex] = gsrRaw; - respBuffer[bufferIndex] = respRaw; - bufferIndex = (bufferIndex + 1) % BUFFER_SIZE; - - // Update min/max values - updateMinMax(ecgRaw, gsrRaw, respRaw); - - // Process based on current state - switch (currentState) { - case BASELINE_CALIBRATION: - handleBaselineCalibration(currentTime); - break; - case BREATH_ANALYSIS: - handleBreathAnalysis(currentTime, respRaw); - break; - case CONTINUOUS_MONITORING: - handleContinuousMonitoring(currentTime, ecgRaw, gsrRaw, respRaw); - break; - } - } -} - -void updateMinMax(int ecgRaw, int gsrRaw, int respRaw) { - // ECG min/max - if (ecgRaw < ecgMin) ecgMin = ecgRaw; - if (ecgRaw > ecgMax) ecgMax = ecgRaw; - - // GSR min/max - if (gsrRaw < gsrMin) gsrMin = gsrRaw; - if (gsrRaw > gsrMax) gsrMax = gsrRaw; - - // Respiratory min/max - if (respRaw < respMin) respMin = respRaw; - if (respRaw > respMax) respMax = respRaw; -} - -void handleBaselineCalibration(unsigned long currentTime) { - unsigned long elapsed = currentTime - calibrationStartTime; - unsigned long remaining = CALIBRATION_DURATION - elapsed; - - // Print progress every 5 seconds - if (elapsed % 5000 < SAMPLE_INTERVAL) { - Serial.printf("โณ Baseline Calibration: %lu seconds remaining\n", remaining / 1000); - } - - // Check if baseline calibration is complete - if (elapsed >= CALIBRATION_DURATION) { - completeBaselineCalibration(); - } -} - -void completeBaselineCalibration() { - Serial.println("\n" + String("=").repeat(60)); - Serial.println("โœ… BASELINE CALIBRATION COMPLETE"); - Serial.println("=" + String("=").repeat(59)); - - // Calculate baselines from collected data - calculateBaselines(); - - // Print baseline results - Serial.println("\n๐Ÿ“Š BASELINE CALIBRATION RESULTS:"); - Serial.println(" ECG Sensor (AD8232):"); - Serial.printf(" Range: %d - %d (Span: %d)\n", ecgMin, ecgMax, ecgMax - ecgMin); - Serial.printf(" Baseline: %d\n", ecgBaseline); - Serial.printf(" Noise Level: ยฑ%d\n", (ecgMax - ecgMin) / 2); - - Serial.println("\n GSR Sensor:"); - Serial.printf(" Range: %d - %d (Span: %d)\n", gsrMin, gsrMax, gsrMax - gsrMin); - Serial.printf(" Baseline: %d\n", gsrBaseline); - Serial.printf(" Noise Level: ยฑ%d\n", (gsrMax - gsrMin) / 2); - - Serial.println("\n Respiratory Sensor (HW-484):"); - Serial.printf(" Range: %d - %d (Span: %d)\n", respMin, respMax, respMax - respMin); - Serial.printf(" Baseline: %d\n", respBaseline); - Serial.printf(" Noise Level: ยฑ%d\n", (respMax - respMin) / 2); - - Serial.println("\n๐ŸŽฏ RECOMMENDED THRESHOLDS:"); - Serial.printf(" Breath Detection Threshold: %d\n", (respMax - respMin) / 4); - Serial.printf(" GSR Change Threshold: %d\n", (gsrMax - gsrMin) / 8); - Serial.printf(" ECG Peak Threshold: %d\n", (ecgMax - ecgMin) / 3); - - Serial.println("\n๐Ÿซ Starting Breath Analysis Phase"); - Serial.println(" Please breathe NORMALLY for the next 60 seconds"); - Serial.println(" Focus on steady, regular breathing patterns"); - Serial.println(); - - // Reset for breath analysis - breathAnalysisStartTime = millis(); - currentState = BREATH_ANALYSIS; - - // Reset breath counters - breathInCount = 0; - breathOutCount = 0; - lastBreathTime = 0; -} - -void calculateBaselines() { - // Calculate median values as baselines (more robust than mean) - ecgBaseline = calculateMedian(ecgBuffer, BUFFER_SIZE); - gsrBaseline = calculateMedian(gsrBuffer, BUFFER_SIZE); - respBaseline = calculateMedian(respBuffer, BUFFER_SIZE); -} - -int calculateMedian(int* buffer, int size) { - // Create a copy for sorting - int tempBuffer[size]; - for (int i = 0; i < size; i++) { - tempBuffer[i] = buffer[i]; - } - - // Simple bubble sort (for small arrays) - for (int i = 0; i < size - 1; i++) { - for (int j = 0; j < size - i - 1; j++) { - if (tempBuffer[j] > tempBuffer[j + 1]) { - int temp = tempBuffer[j]; - tempBuffer[j] = tempBuffer[j + 1]; - tempBuffer[j + 1] = temp; - } - } - } - - // Return median - return tempBuffer[size / 2]; -} - -void handleBreathAnalysis(unsigned long currentTime, int respRaw) { - unsigned long elapsed = currentTime - breathAnalysisStartTime; - unsigned long remaining = BREATH_ANALYSIS_DURATION - elapsed; - - // Print progress every 10 seconds - if (elapsed % 10000 < SAMPLE_INTERVAL) { - Serial.printf("โณ Breath Analysis: %lu seconds remaining\n", remaining / 1000); - } - - // Analyze breathing pattern - analyzeBreathingPattern(respRaw, currentTime); - - // Check if breath analysis is complete - if (elapsed >= BREATH_ANALYSIS_DURATION) { - completeBreathAnalysis(); - } -} - -void analyzeBreathingPattern(int respRaw, unsigned long currentTime) { - // Calculate deviation from baseline - int deviation = respRaw - respBaseline; - int absDeviation = abs(deviation); - - // Dynamic threshold based on baseline noise - int breathThreshold = (respMax - respMin) / 4; - - // Detect breath in/out based on deviation direction and magnitude - if (absDeviation > breathThreshold && (currentTime - lastBreathTime) > MIN_BREATH_INTERVAL) { - if (deviation > 0) { - // Positive deviation = breath in (sound level increases) - breathInCount++; - Serial.printf("๐Ÿซ BREATH IN detected! Raw: %d, Deviation: +%d\n", respRaw, deviation); - } else { - // Negative deviation = breath out (sound level decreases) - breathOutCount++; - Serial.printf("๐Ÿซ BREATH OUT detected! Raw: %d, Deviation: %d\n", respRaw, deviation); - } - lastBreathTime = currentTime; - } -} - -void completeBreathAnalysis() { - Serial.println("\n" + String("=").repeat(60)); - Serial.println("โœ… BREATH ANALYSIS COMPLETE"); - Serial.println("=" + String("=").repeat(59)); - - Serial.println("\n๐Ÿ“Š BREATHING PATTERN ANALYSIS:"); - Serial.printf(" Total Breaths Detected: %d\n", breathInCount + breathOutCount); - Serial.printf(" Breaths In: %d\n", breathInCount); - Serial.printf(" Breaths Out: %d\n", breathOutCount); - - if (breathInCount > 0 && breathOutCount > 0) { - float avgBreathInterval = (float)BREATH_ANALYSIS_DURATION / (breathInCount + breathOutCount); - float respiratoryRate = 60000.0 / avgBreathInterval; // breaths per minute - - Serial.printf(" Average Breath Interval: %.1f ms\n", avgBreathInterval); - Serial.printf(" Calculated Respiratory Rate: %.1f breaths/min\n", respiratoryRate); - - Serial.println("\n๐ŸŽฏ BREATH DETECTION CALIBRATION:"); - Serial.printf(" Current Threshold: %d\n", (respMax - respMin) / 4); - Serial.printf(" Recommended Range: %d - %d\n", (respMax - respMin) / 6, (respMax - respMin) / 3); - - if (respiratoryRate < 8 || respiratoryRate > 30) { - Serial.println(" โš ๏ธ Respiratory rate outside normal range (8-30 breaths/min)"); - Serial.println(" Consider adjusting sensor placement or sensitivity"); - } - } - - Serial.println("\n๐Ÿ”„ Starting Continuous Monitoring Mode"); - Serial.println(" Real-time sensor data will now be displayed"); - Serial.println(" Press Ctrl+C to stop monitoring"); - Serial.println(); - - currentState = CONTINUOUS_MONITORING; -} - -void handleContinuousMonitoring(unsigned long currentTime, int ecgRaw, int gsrRaw, int respRaw) { - // Calculate deviations from baseline - int ecgDeviation = ecgRaw - ecgBaseline; - int gsrDeviation = gsrRaw - gsrBaseline; - int respDeviation = respRaw - respBaseline; - - // Print formatted data every 100ms (10Hz display rate) - static unsigned long lastDisplayTime = 0; - if (currentTime - lastDisplayTime >= 100) { - lastDisplayTime = currentTime; - - // Format: Timestamp, ECG_Raw, ECG_Dev, GSR_Raw, GSR_Dev, RESP_Raw, RESP_Dev - Serial.printf("DATA: %lu, %d, %+d, %d, %+d, %d, %+d\n", - currentTime, - ecgRaw, ecgDeviation, - gsrRaw, gsrDeviation, - respRaw, respDeviation); - } - - // Real-time breath detection - int breathThreshold = (respMax - respMin) / 4; - if (abs(respDeviation) > breathThreshold && (currentTime - lastBreathTime) > MIN_BREATH_INTERVAL) { - if (respDeviation > 0) { - Serial.printf("๐Ÿซ LIVE: Breath IN - Raw: %d, Dev: +%d\n", respRaw, respDeviation); - } else { - Serial.printf("๐Ÿซ LIVE: Breath OUT - Raw: %d, Dev: %d\n", respRaw, respDeviation); - } - lastBreathTime = currentTime; - } -} - -// Utility function to print sensor status -void printSensorStatus() { - Serial.println("\n๐Ÿ“ก SENSOR STATUS:"); - Serial.printf(" ECG (GPIO32): %d\n", analogRead(ECG_PIN)); - Serial.printf(" GSR (GPIO33): %d\n", analogRead(GSR_PIN)); - Serial.printf(" RESP (GPIO27): %d\n", analogRead(RESP_PIN)); - Serial.println(); -} diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/drawExample.ts b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/drawExample.ts index de309a9af..39fe424a1 100644 --- a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/drawExample.ts +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/drawExample.ts @@ -350,40 +350,12 @@ export const drawExample = async (rootElement: string | HTMLDivElement) => { const runUpdateDataOnTimeout = () => { const { xArr, ecgArr, gsrArr, respArr } = getValuesFromData(currentPoint); - // Debug: Log fallback data generation (only every 1000 points to avoid spam) - if (currentPoint % 1000 === 0) { - console.log("๐Ÿ“Š Fallback data generated:", { - currentPoint, - xArr: xArr.length, - ecgArr: ecgArr.length, - gsrArr: gsrArr.length, - respArr: respArr.length, - sampleEcg: ecgArr[0], - sampleGsr: gsrArr[0], - sampleResp: respArr[0], - ecgRange: `${Math.min(...ecgArr)} to ${Math.max(...ecgArr)}`, - gsrRange: `${Math.min(...gsrArr)} to ${Math.max(...gsrArr)}`, - xRange: `${Math.min(...xArr)} to ${Math.max(...xArr)} (limited range)`, - }); - } - try { // Simple data append - let FIFO handle the rest dataSeriesEcg.appendRange(xArr, ecgArr); dataSeriesGsr.appendRange(xArr, gsrArr); dataSeriesResp.appendRange(xArr, respArr); - // Debug: Check if data is actually being added to the series - if (currentPoint % 1000 === 0) { - console.log("๐Ÿ“ˆ Chart data status:", { - ecgSeriesCount: dataSeriesEcg.count(), - gsrSeriesCount: dataSeriesGsr.count(), - respSeriesCount: dataSeriesResp.count(), - lastEcgValue: ecgArr[ecgArr.length - 1], - lastGsrValue: gsrArr[gsrArr.length - 1], - }); - } - // Ensure data is visible if (sciChartSurface) { sciChartSurface.zoomExtents(); @@ -401,12 +373,6 @@ export const drawExample = async (rootElement: string | HTMLDivElement) => { respiratory: respArr[STEP - 1], }; - // Debug: Log fallback data being sent to UI - if (currentPoint % 200 === 0) { - // Log every 1000 points to avoid spam - console.log("๐Ÿ“Š Sending fallback data to UI:", fallbackData); - } - dataUpdateEventHandler.raiseEvent(fallbackData); } timerId = setTimeout(runUpdateDataOnTimeout, TIMER_TIMEOUT_MS); @@ -417,25 +383,14 @@ export const drawExample = async (rootElement: string | HTMLDivElement) => { // Start fallback data after a small delay to ensure chart is ready if (!timerId) { - console.log("๐Ÿš€ Starting fallback data generation after chart initialization..."); - // Small delay to ensure chart is fully ready setTimeout(() => { - console.log("โฐ Chart ready, starting fallback data..."); - // Add initial data to start the rolling window const initialData = getValuesFromData(0); try { dataSeriesEcg.appendRange(initialData.xArr, initialData.ecgArr); dataSeriesGsr.appendRange(initialData.xArr, initialData.gsrArr); dataSeriesResp.appendRange(initialData.xArr, initialData.respArr); - console.log("๐Ÿ“Š Initial fallback data added:", { - ecgPoints: initialData.ecgArr.length, - gsrPoints: initialData.gsrArr.length, - respPoints: initialData.respArr.length, - ecgRange: `${Math.min(...initialData.ecgArr)} to ${Math.max(...initialData.ecgArr)}`, - xRange: `${Math.min(...initialData.xArr)} to ${Math.max(...initialData.xArr)} (limited range)`, - }); // Send initial fallback data to UI immediately const initialFallbackData = { @@ -444,7 +399,7 @@ export const drawExample = async (rootElement: string | HTMLDivElement) => { gsr: initialData.gsrArr[initialData.gsrArr.length - 1], respiratory: initialData.respArr[initialData.respArr.length - 1], }; - console.log("๐Ÿš€ Sending initial fallback data to UI:", initialFallbackData); + dataUpdateEventHandler.raiseEvent(initialFallbackData); } catch (error) { console.error("Error adding initial fallback data:", error); diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/ecgProcessor.ts b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/ecgProcessor.ts index 7e07b71c2..057c21e75 100644 --- a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/ecgProcessor.ts +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/ecgProcessor.ts @@ -451,7 +451,7 @@ export class ECGSignalProcessor { gender: "male", // Default gender ...config, }; - info("ECG", "ECGSignalProcessor initialized", this.config); + // ECG Signal Processor initialized silently } // Add new ECG data point diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/index.tsx b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/index.tsx index 70fa725a9..653d6e1d3 100644 --- a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/index.tsx +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/index.tsx @@ -149,13 +149,13 @@ const VitalSignsMonitorDemo: React.FC = () => { const [citationsExpanded, setCitationsExpanded] = useState(false); const debugLogger = DebugLogger.getInstance(); const controlsRef = useRef(null); - const gsrAnalyzerRef = useRef(new GSRTrendAnalyzer()); - const ecgProcessorRef = useRef(new ECGSignalProcessor({ age: 30, gender: "male" })); + const gsrAnalyzerRef = useRef(null); + const ecgProcessorRef = useRef(null); // Rolling window calculators for rate-based metrics - const bpmCalculator = useRef(new RollingWindowCalculator(60000)); // 60 seconds for BPM - const respCalculator = useRef(new RollingWindowCalculator(60000)); // 60 seconds for respiratory rate - const gsrCalculator = useRef(new RollingWindowCalculator(60000)); // 60 seconds for GSR trends + const bpmCalculator = useRef(null); + const respCalculator = useRef(null); + const gsrCalculator = useRef(null); // Session timing reference for real-time calculations const sessionStartTime = useRef(Date.now()); @@ -230,10 +230,20 @@ const VitalSignsMonitorDemo: React.FC = () => { } }; - // Update values periodically to simulate real-time monitoring (only when not connected) + // Update values periodically to simulate real-time monitoring (ONLY when not connected) useEffect(() => { const interval = setInterval(() => { + // CRITICAL: Only run fallback updates when WebSocket is NOT connected + // This prevents fallback values from overwriting real ESP32 data + if (wsConnected) { + console.log("โœ… WebSocket connected - skipping fallback updates to preserve ESP32 data"); + return; // Exit early if WebSocket is connected + } + if (!wsConnected) { + console.log("๐Ÿ”„ Running fallback updates (WebSocket disconnected)"); + // Ensure all refs are initialized + ensureRefsInitialized(); // Generate fallback values when ESP32 is disconnected const newEcg = generateFallbackValue("ecg"); const newBpm = generateFallbackValue("bpm"); @@ -388,22 +398,21 @@ const VitalSignsMonitorDemo: React.FC = () => { setInfoHrv(newHrv); setInfoGsr(gsrCalculator.current.getAverageValue()); - // Set respiratory rate directly from generated value, then update from rolling window - setInfoResp(newResp); - const calculatedResp = Math.round(respCalculator.current.calculateRate()); - if (calculatedResp > 0) { - setInfoResp(calculatedResp); // Use rolling window if available - } - - // Add respiratory rate to debug log after calculation - console.log("๐Ÿ”„ Fallback Respiratory Update:", { - respiratory: newResp, - calculatedResp: calculatedResp, - finalResp: calculatedResp > 0 ? calculatedResp : newResp, - }); - // Only update fallback data when ESP32 is disconnected if (!wsConnected) { + // Set respiratory rate directly from generated value, then update from rolling window + setInfoResp(newResp); + const calculatedResp = Math.round(respCalculator.current.calculateRate()); + if (calculatedResp > 0) { + setInfoResp(calculatedResp); // Use rolling window if available + } + + // Add respiratory rate to debug log after calculation + console.log("๐Ÿ”„ Fallback Respiratory Update:", { + respiratory: newResp, + calculatedResp: calculatedResp, + finalResp: calculatedResp > 0 ? calculatedResp : newResp, + }); // Update breathing pattern animation const animatedInhalePercent = 35 + Math.sin(Date.now() * 0.001) * 10; setInhalePercent(animatedInhalePercent); @@ -415,18 +424,20 @@ const VitalSignsMonitorDemo: React.FC = () => { setGsrTrend(fallbackGsrTrend); // Generate fallback ECG metrics using the ECG processor - ecgProcessorRef.current.addECGPoint(newEcg, timestamp); - - // Add IBI data (convert BPM to IBI) - if (newBpm > 0) { - const ibi = 60000 / newBpm; // Convert BPM to milliseconds - ecgProcessorRef.current.addIBI(ibi, timestamp); + if (ecgProcessorRef.current) { + ecgProcessorRef.current.addECGPoint(newEcg, timestamp); + + // Add IBI data (convert BPM to IBI) + if (newBpm > 0) { + const ibi = 60000 / newBpm; // Convert BPM to milliseconds + ecgProcessorRef.current.addIBI(ibi, timestamp); + } + + // Get enhanced fallback metrics + const fallbackEcgMetrics = ecgProcessorRef.current.getMetrics(); + setEcgMetrics(fallbackEcgMetrics); } - // Get enhanced fallback metrics - const fallbackEcgMetrics = ecgProcessorRef.current.getMetrics(); - setEcgMetrics(fallbackEcgMetrics); - // Set fallback respiration metrics using calculated values (not fake sine waves) const fallbackRate = Math.round(respCalculator.current.calculateRate()); const fallbackCycleTime = 60000 / Math.max(fallbackRate, 1); @@ -471,6 +482,44 @@ const VitalSignsMonitorDemo: React.FC = () => { return () => clearInterval(interval); }, [wsConnected]); + // Initialize all processors and calculators only once + useEffect(() => { + if (!ecgProcessorRef.current) { + ecgProcessorRef.current = new ECGSignalProcessor({ age: 30, gender: "male" }); + } + if (!gsrAnalyzerRef.current) { + gsrAnalyzerRef.current = new GSRTrendAnalyzer(); + } + if (!bpmCalculator.current) { + bpmCalculator.current = new RollingWindowCalculator(60000); + } + if (!respCalculator.current) { + respCalculator.current = new RollingWindowCalculator(60000); + } + if (!gsrCalculator.current) { + gsrCalculator.current = new RollingWindowCalculator(60000); + } + }, []); + + // Helper function to ensure refs are initialized + const ensureRefsInitialized = () => { + if (!ecgProcessorRef.current) { + ecgProcessorRef.current = new ECGSignalProcessor({ age: 30, gender: "male" }); + } + if (!gsrAnalyzerRef.current) { + gsrAnalyzerRef.current = new GSRTrendAnalyzer(); + } + if (!bpmCalculator.current) { + bpmCalculator.current = new RollingWindowCalculator(60000); + } + if (!respCalculator.current) { + respCalculator.current = new RollingWindowCalculator(60000); + } + if (!gsrCalculator.current) { + gsrCalculator.current = new RollingWindowCalculator(60000); + } + }; + // Firebase logging effect useEffect(() => { // Firebase logging is always enabled (both real sensor data and fallback data) @@ -1632,6 +1681,9 @@ const VitalSignsMonitorDemo: React.FC = () => { const unsub = initResult.subscribeToDataUpdates((info: any) => { if (!info) return undefined; + // Ensure all refs are initialized + ensureRefsInitialized(); + // Debug: Log all incoming data console.log("๐Ÿ“ก Data Update Event Received:", { type: info.type, @@ -1769,6 +1821,8 @@ const VitalSignsMonitorDemo: React.FC = () => { console.log("๐Ÿซ Processing Respiratory Data:", info.respiratory); console.log("๐Ÿ” Respiratory WebSocket Raw Data:", { rawValue: info.respiratory, + rawInhaleRatio: info.inhaleRatio, + rawExhaleRatio: info.exhaleRatio, dataType: typeof info.respiratory, timestamp: timestamp, source: "WebSocket", @@ -1778,16 +1832,40 @@ const VitalSignsMonitorDemo: React.FC = () => { // ESP32 now sends calculated breath rate in breaths/min const finalRespRate = Math.round(info.respiratory); console.log("๐Ÿซ Setting Respiratory Rate:", finalRespRate); + console.log("๐Ÿซ Previous Respiratory Rate:", infoResp); setInfoResp(finalRespRate); - // Update breathing pattern based on respiratory rate - const baseInhale = 40; // Base inhale percentage - const rateVariation = (finalRespRate - 16) / 4; // Adjust based on rate - const dynamicInhale = Math.max( - 35, - Math.min(45, baseInhale + rateVariation) - ); - setInhalePercent(dynamicInhale); + // Use actual inhale/exhale ratios from MPU6050 instead of calculating + let finalInhaleRatio = 40; // Default fallback + let finalExhaleRatio = 60; // Default fallback + + if ( + typeof info.inhaleRatio === "number" && + typeof info.exhaleRatio === "number" + ) { + finalInhaleRatio = Math.round(info.inhaleRatio * 10) / 10; // Round to 1 decimal + finalExhaleRatio = Math.round(info.exhaleRatio * 10) / 10; // Round to 1 decimal + console.log( + "๐Ÿซ Using MPU6050 I/E Ratios:", + finalInhaleRatio + "%/" + finalExhaleRatio + "%" + ); + } else { + // Fallback calculation if ratios not provided + const baseInhale = 40; // Base inhale percentage + const rateVariation = (finalRespRate - 16) / 4; // Adjust based on rate + finalInhaleRatio = Math.max( + 35, + Math.min(45, baseInhale + rateVariation) + ); + finalExhaleRatio = 100 - finalInhaleRatio; + console.log( + "๐Ÿซ Using Fallback I/E Ratios:", + finalInhaleRatio + "%/" + finalExhaleRatio + "%" + ); + } + + console.log("๐Ÿซ Setting Inhale Percent:", finalInhaleRatio); + setInhalePercent(finalInhaleRatio); // Update respiration metrics with REAL ESP32 data using validated medical formulas // Based on: "Continuous Determination of Respiratory Rate in Hospitalized Patients using Machine Learning Applied to Electrocardiogram Telemetry" - Thomas Kite et al. @@ -1807,8 +1885,8 @@ const VitalSignsMonitorDemo: React.FC = () => { setRespirationMetrics({ rate: respRate, - inhalePercent: dynamicInhale, - exhalePercent: 100 - dynamicInhale, + inhalePercent: finalInhaleRatio, + exhalePercent: finalExhaleRatio, lastBreathTime: lastBreathTime, breathCount: breathCount, averageCycleDuration: baseCycleTime, @@ -1850,6 +1928,19 @@ const VitalSignsMonitorDemo: React.FC = () => { respiratoryFatigueIndex: 0.05 + Math.abs(respRate - 16) * 0.015, }); + // Debug: Log when breathing pattern card should update + console.log("๐Ÿซ Breathing Pattern Card Update:", { + inhalePercent: finalInhaleRatio, + exhalePercent: finalExhaleRatio, + respiratoryRate: finalRespRate, + timestamp: new Date().toISOString(), + source: "MPU6050 WebSocket Data", + previousInhalePercent: + respirationMetrics?.inhalePercent || "N/A", + previousExhalePercent: + respirationMetrics?.exhalePercent || "N/A", + }); + // Also add to calculator for averaging respCalculator.current.addDataPoint(finalRespRate, timestamp); } @@ -2453,13 +2544,13 @@ const VitalSignsMonitorDemo: React.FC = () => {
  • Inhale:{" "} - {wsConnected && respirationMetrics - ? respirationMetrics.inhalePercent.toFixed(2) - : inhalePercent.toFixed(2)} + {wsConnected && respirationMetrics && respirationMetrics.inhalePercent > 0 + ? respirationMetrics.inhalePercent.toFixed(1) + : inhalePercent.toFixed(1)} % | Exhale:{" "} - {wsConnected && respirationMetrics - ? respirationMetrics.exhalePercent.toFixed(2) - : (100 - inhalePercent).toFixed(2)} + {wsConnected && respirationMetrics && respirationMetrics.exhalePercent > 0 + ? respirationMetrics.exhalePercent.toFixed(1) + : (100 - inhalePercent).toFixed(1)} %
    diff --git a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/signalProcessor.ts b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/signalProcessor.ts index 00ca85aaf..6c4e451de 100644 --- a/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/signalProcessor.ts +++ b/Examples/src/components/Examples/FeaturedApps/MedicalCharts/VitalSignsMonitorDemo/signalProcessor.ts @@ -603,7 +603,6 @@ export class ESP32WebSocketHandler { startTimer("websocket_connect"); info("WEBSOCKET", "Connecting to ESP32 WebSocket", { url: this.wsUrl }); - console.log("๐Ÿ”Œ Attempting WebSocket connection to:", this.wsUrl); // Create new WebSocket connection this.ws = new WebSocket(this.wsUrl); @@ -682,32 +681,22 @@ export class ESP32WebSocketHandler { debug("WEBSOCKET", "Message received", { type: data.type, esp32Timestamp, jsTimestamp }); - // Debug: Log raw ESP32 data before processing - console.log("๐Ÿ” ESP32 Raw Data Debug:", { - type: data.type, - rawValue: data.value, - dataType: typeof data.value, - timestamp: jsTimestamp, - source: "ESP32WebSocketHandler", - }); - // Handle individual sensor data messages from ESP32 switch (data.type) { case "respiratory": - // ESP32 is sending breathing pattern values (800-2500) - // Use raw values for processing and display - this.respProcessor.addDataPoint(data.value, jsTimestamp); + // ESP32 is now sending calculated respiratory rate in breaths/min + // Use the ESP32-calculated rate directly (more accurate for HW-484 sensor) + + // Add to respiratory processor for trend analysis + this.respProcessor.addDataPoint(data.respiratory, jsTimestamp); const metrics = this.respProcessor.getMetrics(); const state = this.respProcessor.getCurrentState(); - // Simple breath rate calculation - use the simple estimation method - const breathRate = this.estimateBreathRate(data.value, jsTimestamp); - this.onDataUpdate({ type: "respiratory", - respiratory: breathRate, // Send estimated breath rate in breaths/min - value: breathRate, // Keep for backward compatibility - raw: data.value, + respiratory: data.respiratory, // Use ESP32-calculated rate directly + value: data.respiratory, // Keep for backward compatibility + raw: data.respiratory, metrics: metrics, state: state, sensorConnected: data.sensorConnected || false, @@ -716,9 +705,9 @@ export class ESP32WebSocketHandler { break; case "ecg": - // ESP32 is sending raw ADC values (800-3500) + // ESP32 is sending raw ADC values in the 'ecg' field // Keep raw values for plotting, convert only for processing - const ecgInMillivolts = ((data.value - 2048) / 2048) * 2.5; // Convert to ยฑ2.5mV range + const ecgInMillivolts = ((data.ecg - 2048) / 2048) * 2.5; // Convert to ยฑ2.5mV range // Add to ECG processor for heartbeat detection (use converted value) this.ecgProcessor.addECGPoint(ecgInMillivolts, jsTimestamp); @@ -728,9 +717,9 @@ export class ESP32WebSocketHandler { this.onDataUpdate({ type: "ecg", - ecg: data.value, // Send raw ADC value for plotting (800-3500) - value: data.value, // Keep raw value for display consistency - raw: data.value, + ecg: data.ecg, // Send raw ADC value for plotting (800-3500) + value: data.ecg, // Keep raw value for display consistency + raw: data.ecg, sensorConnected: data.sensorConnected || false, timestamp: jsTimestamp, ecgMetrics: ecgMetrics, // Include ECG metrics for heart rate @@ -738,13 +727,14 @@ export class ESP32WebSocketHandler { break; case "gsr": - // ESP32 is sending already-calibrated GSR values in microsiemens (ฮผS) - // No need for ADC normalization - use values as-is + // ESP32 is sending GSR values in the 'gsr' field, not 'value' + // Use the correct field name from ESP32 message + this.onDataUpdate({ type: "gsr", - gsr: data.value, // Use raw value from ESP32 (already calibrated) - value: data.value, // Keep for backward compatibility - raw: data.value, + gsr: data.gsr, // Use data.gsr field from ESP32 message + value: data.gsr, // Keep for backward compatibility + raw: data.gsr, sensorConnected: data.sensorConnected || false, timestamp: jsTimestamp, }); @@ -794,7 +784,6 @@ export class ESP32WebSocketHandler { const delay = this.reconnectAttempts === 1 ? 0 : Math.min(1000 * this.reconnectAttempts, 5000); this.reconnectTimer = setTimeout(() => { - console.log("๐Ÿ”„ Executing reconnection attempt..."); this.connect(); }, delay); } else {

    >}IMMU3DYo;clpg%2t? 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 z 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