diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 8ade1845..0d33a266 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -15,7 +15,7 @@ on: env: DOCKER_IMAGE: xatang/pyunit - PLATFORMS: linux/amd64,linux/arm64 + PLATFORMS: linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8 jobs: build-and-push: diff --git a/.gitignore b/.gitignore index 50dc68c8..dc506ac7 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ env/ # Database *.db +*.db-wal +*.db-shm *.sqlite *.sqlite3 diff --git a/README.md b/README.md index afbe4db6..99623c70 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ PyUnit is a custom firmware for [iDryer Unit](https://github.com/pavluchenkor/iD - 🔗 **WebSocket real-time updates** - 📋 **Embed pages** for Klipper HTTP camera integration - 🤖 **G-code macro generation** for Klipper -- 🐳 **Multi-platform Docker images** (amd64, arm64) +- 🐳 **Multi-platform Docker images** (amd64, arm64, arm/v7, arm/v8) -## � Screenshots +## 📸 Screenshots ### Dashboard Overview ![Dashboard](images/dashboard.png) @@ -42,7 +42,7 @@ PyUnit is a custom firmware for [iDryer Unit](https://github.com/pavluchenkor/iD ![Fluidd Integration](images/fluidd-integration.png) *PyUnit embedded control panel in Fluidd/Mainsail interface* -## � Quick Start +## 🚀 Quick Start ### One-Command Installation @@ -67,10 +67,21 @@ The script will automatically: ### Requirements - **OS:** Linux (Ubuntu, Debian, Raspbian, Armbian) -- **Architecture:** amd64 (x86_64) or arm64 (aarch64) +- **Architecture:** + - amd64 (x86_64) - Intel/AMD 64-bit + - arm64 (aarch64) - ARM 64-bit + - arm/v7 - ARMv7 32-bit + - arm/v8 - ARMv8 32-bit - **RAM:** 256MB minimum (512MB recommended) - **Disk:** ~1GB for Docker image +#### Additionally, you can add the following commands to the Fluidd or Mainsail console filters to avoid a flood of messages during firmware operation. +```bash +SET_LED LED=[led_name] INDEX= +SET_HEATER_TEMPERATURE HEATER=[heater_name] +SET_SERVO SERVO=[servo_name] +``` + ### Updates To update to the latest version: @@ -80,8 +91,30 @@ cd PyUnit ./run.sh ``` + Updates preserve your configuration and IP settings automatically. +### Uninstallation + +To completely remove PyUnit (container, volumes, images, network): + +```bash +cd PyUnit +chmod +x uninstall.sh +./uninstall.sh +``` + +This will remove: +- Docker container `pyunit` +- Docker volume `pyunit_pyunit_data` (all data will be lost!) +- Docker network `pyunit_pyunit_network` +- Docker images `xatang/pyunit:*` + +**Note:** Local files (pyunit.db, logs) are NOT deleted automatically. To remove them: +```bash +rm -f pyunit.db pyunit.db-wal pyunit.db-shm app.log dryer.log +``` + ## 🏗️ Architecture ### Backend (FastAPI + Python 3.11) @@ -179,7 +212,7 @@ sudo docker compose up -d **Starting a Drying Cycle:** 1. Select a dryer from the list 2. Choose a preset -3. Click **Start** - the dryer will +3. Click **Start** - the dryer will begin the drying process ### Configuration @@ -193,12 +226,26 @@ sudo docker compose up -d ### Klipper Integration +**Example Configuration:** + +A complete Klipper configuration example is available in `config_and_macros/U1.cfg.example`. This file contains: +- Heater configuration (`[heater_generic]`) +- Temperature sensor setup (`[temperature_sensor]`) +- LED control (`[neopixel]`) +- Servo configuration (`[servo]`) +- G-code macros for dryer control + +**⚠️ Important:** All module and sensor names in Klipper configuration **must be lowercase**: +- ✅ Correct: `idryer_u1_heater`, `idryer_u1_air`, `srv_u1` +- ❌ Wrong: `IDryer_U1_Heater`, `IDRYER_U1_AIR`, `SRV_U1` + **G-code Macros:** -1. Go to dryer detail page -2. Expand **Klipper G-code Macros** -3. Configure Python script path -4. Copy macros to `printer.cfg` -5. Use in Klipper: +1. To control the drying process via gcode macro, your printer must have the [gcode_shell_command](https://github.com/dw-0/kiauh/blob/master/docs/gcode_shell_command.md) extension installed. +2. After installation gcode_shell_command go to dryer detail page +3. Expand **Klipper G-code Macros** +4. Configure Python script path +5. Copy macros to `printer.cfg` +6. Use in Klipper: ```gcode OFF_DRYER ID=1 PRESET_DRYER ID=1 PRESET_ID=5 @@ -212,13 +259,13 @@ sudo docker compose up -d [camera pyunit_control] location: dryer service: http - target_fps: 15 + aspect_ratio: 4:3 stream_url: http://192.168.1.100:5000/embed/dryer/1/control [camera pyunit_chart] location: dryer service: http - target_fps: 15 + aspect_ratio: 4:3 stream_url: http://192.168.1.100:5000/embed/dryer/1/chart ``` diff --git a/api/cruds/dryer_crud.py b/api/cruds/dryer_crud.py index 4c689577..e9dc2caa 100644 --- a/api/cruds/dryer_crud.py +++ b/api/cruds/dryer_crud.py @@ -160,11 +160,50 @@ async def add_log(self, db: AsyncSession, log_data: schema.DryerLog) -> models.D await db.refresh(db_log) return schema.DryerLog.from_orm(db_log) if db_log else None - async def get_logs(self, db: AsyncSession) -> list[models.DryerLogs]: - """Return all dryer logs (no filtering).""" - result = await db.execute(select(models.DryerLogs)) + async def get_logs(self, db: AsyncSession, dryer_id: Optional[int] = None, + start_time: Optional[str] = None, end_time: Optional[str] = None, + limit: Optional[int] = None) -> list[models.DryerLogs]: + """Return dryer logs with optional filtering. + + Args: + db: Database session + dryer_id: Filter by specific dryer (None = all dryers) + start_time: ISO format datetime string for filtering logs after this time + end_time: ISO format datetime string for filtering logs before this time + limit: Maximum number of logs to return (most recent first) + """ + query = select(models.DryerLogs) + + if dryer_id is not None: + query = query.where(models.DryerLogs.dryer_id == dryer_id) + + if start_time: + from datetime import datetime + start_dt = datetime.fromisoformat(start_time.replace('Z', '+00:00')) + query = query.where(models.DryerLogs.timestamp >= start_dt) + + if end_time: + from datetime import datetime + end_dt = datetime.fromisoformat(end_time.replace('Z', '+00:00')) + query = query.where(models.DryerLogs.timestamp <= end_dt) + + # Order by timestamp descending (most recent first) + query = query.order_by(models.DryerLogs.timestamp.desc()) + + if limit: + query = query.limit(limit) + + result = await db.execute(query) db_logs = result.scalars().all() - return [schema.DryerLog.from_orm(log) for log in db_logs] if db_logs else None + + # Return in chronological order (oldest first) for historical data + logs_list = [schema.DryerLog.from_orm(log) for log in reversed(db_logs)] if db_logs else [] + + if dryer_id: + logger.debug("get_logs dryer_id=%s start=%s end=%s limit=%s returned=%d", + dryer_id, start_time, end_time, limit, len(logs_list)) + + return logs_list dryer_crud = DryerCRUD() \ No newline at end of file diff --git a/api/database.py b/api/database.py index 3417f804..abe8525c 100644 --- a/api/database.py +++ b/api/database.py @@ -11,6 +11,7 @@ from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker +from sqlalchemy import text, event from api.models import Base, Preset, MoonrakerConfig import subprocess from api.logger import get_logger @@ -25,9 +26,36 @@ engine = create_async_engine( DATABASE_URL, echo=False, - future=True + future=True, + connect_args={ + "timeout": 30, # Increase timeout for lock acquisition (default is 5) + "check_same_thread": False # Allow multi-threaded access + }, + pool_pre_ping=True, # Verify connections before use + pool_size=10, # Increase connection pool size + max_overflow=20 # Allow more overflow connections ) +# Configure SQLite PRAGMA settings for each connection +@event.listens_for(engine.sync_engine, "connect") +def set_sqlite_pragma(dbapi_conn, connection_record): + """Apply SQLite optimizations on each new connection. + + Critical for Orange Pi / SD card deployments: + - WAL mode: allows concurrent reads during writes + - synchronous=NORMAL: safe with WAL, much faster on slow storage + - cache_size: reduces SD card access + - temp_store: keeps temp data in RAM + """ + cursor = dbapi_conn.cursor() + cursor.execute("PRAGMA journal_mode=WAL") + cursor.execute("PRAGMA busy_timeout=30000") # 30 second timeout + cursor.execute("PRAGMA synchronous=NORMAL") # Trade durability for speed (safe with WAL) + cursor.execute("PRAGMA cache_size=-64000") # 64MB cache (negative = KB) + cursor.execute("PRAGMA temp_store=MEMORY") # Keep temp tables in RAM + cursor.close() + db_logger.debug("SQLite PRAGMAs applied to new connection") + # Reduce SQLAlchemy internal logger verbosity for _name in [ 'sqlalchemy.engine', @@ -91,7 +119,10 @@ def run_migrations(): async def init_db(): - """Create tables based on current SQLAlchemy metadata (non-destructive).""" + """Create tables based on current SQLAlchemy metadata (non-destructive). + + Note: PRAGMA settings are now applied automatically via engine.connect event. + """ async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) db_logger.info("Database schema ensured (create_all)") diff --git a/api/endpoints/common.py b/api/endpoints/common.py index 015dea56..7afb29ad 100644 --- a/api/endpoints/common.py +++ b/api/endpoints/common.py @@ -67,9 +67,24 @@ async def ws_info(): { "path": "/api/dashboard/dryers", "channel": "dryers_stats", - "purpose": "Historical + live dryer state updates (JSON objects)", + "purpose": "DEPRECATED: Historical + live dryer state updates for ALL dryers (JSON objects). Use /dashboard/dryer/{id} for better performance.", "client_send": "ignored (reserved for future commands)", - "server_send_example": {"history": [{"id": 1, "status": "DRYING"}]} + "server_send_example": {"history": [{"id": 1, "dryer_id": 1, "status": "drying", "temperature": 45.5}]}, + "deprecated": True, + "replacement": "/api/dashboard/dryer/{dryer_id}" + }, + { + "path": "/api/dashboard/dryer/{dryer_id}", + "channel": "dryer_{dryer_id}_stats", + "purpose": "RECOMMENDED: Optimized historical + live updates for a SINGLE dryer (JSON objects)", + "query_params": { + "start_time": "ISO datetime string (e.g., 2025-12-18T10:00:00Z) - filter logs after this time", + "end_time": "ISO datetime string - filter logs before this time", + "limit": "Maximum number of historical logs to load (default: 100, prevents memory issues)" + }, + "client_send": "ignored (reserved for future commands)", + "server_send_example": {"history": [{"id": 1, "dryer_id": 1, "status": "drying", "temperature": 45.5, "timestamp": "2025-12-18T12:00:00Z"}]}, + "benefits": "500x less data on connection, time-based filtering, single dryer focus" } ] logger.debug("GET /common/ws-info return %d channels", len(websockets)) diff --git a/api/endpoints/dashboard_page.py b/api/endpoints/dashboard_page.py index 6fb2f085..52ed560e 100644 --- a/api/endpoints/dashboard_page.py +++ b/api/endpoints/dashboard_page.py @@ -3,6 +3,34 @@ Provides: * WebSocket streaming of dryer log history and live updates * Control endpoint to set a preset (or reset to pending) for a running dryer + +WebSocket Endpoints: +------------------- +1. /dashboard/dryers (DEPRECATED - loads ALL logs from ALL dryers) + - Use for backward compatibility only + - Performance issue: sends all historical data on connection + +2. /dashboard/dryer/{dryer_id} (RECOMMENDED - optimized for single dryer) + - Query parameters: + * start_time: ISO datetime (e.g., "2025-12-18T10:00:00Z") - filter logs after this time + * end_time: ISO datetime - filter logs before this time + * limit: max number of historical logs (optional) - limits result set if needed + + Frontend Usage Example (TypeScript): + ----------------------------------- + // Connect to specific dryer with time filtering (no limit) + const dryerId = 1; + const oneHourAgo = new Date(Date.now() - 3600000).toISOString(); + const ws = new WebSocket( + `ws://localhost:8000/dashboard/dryer/${dryerId}?start_time=${oneHourAgo}` + ); + + // Or with time range (limit is optional) + const startTime = '2025-12-18T00:00:00Z'; + const endTime = '2025-12-18T23:59:59Z'; + const ws = new WebSocket( + `ws://localhost:8000/dashboard/dryer/${dryerId}?start_time=${startTime}&end_time=${endTime}` + ); """ from fastapi import APIRouter, HTTPException, Request, WebSocket, status, WebSocketDisconnect, Depends @@ -26,27 +54,114 @@ def get_app(request: Request): @router.websocket("/dryers") -async def dryers_stats_websocket(websocket: WebSocket, db: AsyncSession = Depends(get_db)): - """WebSocket endpoint streaming historical and live dryer logs. +async def dryers_stats_websocket( + websocket: WebSocket, + start_time: Optional[str] = None, + end_time: Optional[str] = None, + limit: Optional[int] = None, + db: AsyncSession = Depends(get_db) +): + """WebSocket endpoint streaming historical and live logs for ALL dryers. + + DEPRECATED: Use /dryer/{dryer_id} for better performance with single dryer pages. + + Query parameters: + - start_time: ISO datetime string (e.g., 2025-12-18T10:00:00Z) - logs after this time + - end_time: ISO datetime string - logs before this time + - limit: Maximum number of historical logs to load per dryer (optional) - Sends an initial history payload (if any) then keeps the connection open - until the client disconnects. + Sends filtered history then streams live updates for all dryers. """ - logger.debug("WS /dashboard/dryers connect") + logger.debug("WS /dashboard/dryers connect start=%s end=%s limit=%s (deprecated - consider /dryer/{id})", + start_time, end_time, limit) await webSocketManager.connect(websocket, 'dryers_stats') - old_logs = await dryer_crud.get_logs(db) - + + # Fetch filtered historical logs (all dryers) try: + old_logs = await dryer_crud.get_logs( + db, + start_time=start_time, + end_time=end_time, + limit=limit + ) history = {'history': [json.loads(log.json()) for log in old_logs]} await websocket.send_text(json.dumps(history)) + logger.debug("WS /dashboard/dryers sent %d historical logs", len(old_logs)) except Exception as e: # non-fatal, continue with live stream logger.warning("Failed to send history over WS error=%s", e) + + try: + while True: + try: + await websocket.receive_text() # currently ignored (keep-alive / future commands) + except RuntimeError as e: + # WebSocket not connected or already closed + logger.debug("WS receive error (client likely disconnected): %s", e) + break + except WebSocketDisconnect: + logger.debug("WS /dashboard/dryers disconnect (explicit)") + except Exception as e: + logger.error("WS /dashboard/dryers unexpected error: %s", e) + finally: + webSocketManager.disconnect(websocket) + logger.debug("WS /dashboard/dryers cleanup complete") + + +@router.websocket("/dryer/{dryer_id}") +async def dryer_stats_websocket( + websocket: WebSocket, + dryer_id: int, + start_time: Optional[str] = None, + end_time: Optional[str] = None, + limit: Optional[int] = None, + db: AsyncSession = Depends(get_db) +): + """WebSocket endpoint for a SINGLE dryer with optimized log filtering. + + Query parameters: + - start_time: ISO datetime string (e.g., 2025-12-18T10:00:00Z) - logs after this time + - end_time: ISO datetime string - logs before this time + - limit: Maximum number of historical logs to load (optional) + + Sends filtered history then streams live updates for this dryer only. + """ + logger.debug("WS /dashboard/dryer/%s connect start=%s end=%s limit=%s", + dryer_id, start_time, end_time, limit) + + # Register for live updates specific to this dryer + await webSocketManager.connect(websocket, f'dryer_{dryer_id}_stats') + + # Fetch filtered historical logs + try: + old_logs = await dryer_crud.get_logs( + db, + dryer_id=dryer_id, + start_time=start_time, + end_time=end_time, + limit=limit + ) + history = {'history': [json.loads(log.json()) for log in old_logs]} + await websocket.send_text(json.dumps(history)) + logger.debug("WS /dashboard/dryer/%s sent %d historical logs", dryer_id, len(old_logs)) + except Exception as e: + logger.warning("Failed to send history for dryer %s: %s", dryer_id, e) + + # Keep connection alive for live updates try: while True: - await websocket.receive_text() # currently ignored (keep-alive / future commands) + try: + # Client can send commands here (currently keep-alive only) + await websocket.receive_text() + except RuntimeError as e: + logger.debug("WS dryer/%s receive error: %s", dryer_id, e) + break except WebSocketDisconnect: + logger.debug("WS /dashboard/dryer/%s disconnect (explicit)", dryer_id) + except Exception as e: + logger.error("WS /dashboard/dryer/%s unexpected error: %s", dryer_id, e) + finally: webSocketManager.disconnect(websocket) - logger.debug("WS /dashboard/dryers disconnect") + logger.debug("WS /dashboard/dryer/%s cleanup complete", dryer_id) @router.post("/control/set-preset/{dryer_id}") diff --git a/api/endpoints/logs_page.py b/api/endpoints/logs_page.py index 4f6c8ac6..237f7ef1 100644 --- a/api/endpoints/logs_page.py +++ b/api/endpoints/logs_page.py @@ -23,13 +23,25 @@ async def app_log_websocket(websocket: WebSocket): for rotated in ("app.log.1", "app.log"): old_logs = await read_log_file(rotated) for log in old_logs: - await websocket.send_text(log) + try: + await websocket.send_text(log) + except Exception as e: + logger.debug("Failed to send log line: %s", e) + break try: while True: - await websocket.receive_text() # ignored (keep-alive) + try: + await websocket.receive_text() # ignored (keep-alive) + except RuntimeError as e: + logger.debug("WS receive error (client likely disconnected): %s", e) + break except WebSocketDisconnect: + logger.debug("WS /logs/app disconnect (explicit)") + except Exception as e: + logger.error("WS /logs/app unexpected error: %s", e) + finally: webSocketManager.disconnect(websocket) - logger.debug("WS /logs/app disconnect") + logger.debug("WS /logs/app cleanup complete") @router.websocket("/dryer") @@ -40,13 +52,25 @@ async def dryer_log_websocket(websocket: WebSocket): for rotated in ("dryer.log.1", "dryer.log"): old_logs = await read_log_file(rotated) for log in old_logs: - await websocket.send_text(log) + try: + await websocket.send_text(log) + except Exception as e: + logger.debug("Failed to send log line: %s", e) + break try: while True: - await websocket.receive_text() # ignored (keep-alive) + try: + await websocket.receive_text() # ignored (keep-alive) + except RuntimeError as e: + logger.debug("WS receive error (client likely disconnected): %s", e) + break except WebSocketDisconnect: + logger.debug("WS /logs/dryer disconnect (explicit)") + except Exception as e: + logger.error("WS /logs/dryer unexpected error: %s", e) + finally: webSocketManager.disconnect(websocket) - logger.debug("WS /logs/dryer disconnect") + logger.debug("WS /logs/dryer cleanup complete") async def read_log_file( diff --git a/api/logger.py b/api/logger.py index 5f5f1011..15656975 100644 --- a/api/logger.py +++ b/api/logger.py @@ -4,19 +4,93 @@ * Loads .env file early so LOG_LEVEL / DRYER_LOG_LEVEL are respected. * .env values have precedence by default (they overwrite existing env vars). * To preserve already set process environment variables set DOTENV_RESPECT_ENV=1. -* Rotating file handlers for app & dryer specific logs. +* Size-limited file handlers maintaining logs at ~4-5MB (removes old entries). +* Auto-truncation when size exceeds 5MB, trimming to 4MB (safe for Docker bind mounts). * WebSocket broadcast handlers for real-time log streaming to clients. * Convenience `get_logger` for consistent retrieval. """ import logging import os -from logging.handlers import RotatingFileHandler import asyncio from api.websocket_manager import WebSocketConnectionManager, webSocketManager +class SizeLimitedFileHandler(logging.FileHandler): + """FileHandler that maintains file size around maxBytes by truncating old entries. + + Unlike RotatingFileHandler, this doesn't try to rename files (which fails + with Docker bind mounts). Instead, it truncates old entries from the beginning + of the file when the limit is reached, keeping the file size stable around maxBytes. + """ + def __init__(self, filename, mode='a', encoding=None, maxBytes=0, targetBytes=None): + """ + Args: + filename: Path to log file + mode: File opening mode (typically 'a' for append) + encoding: File encoding + maxBytes: Maximum file size in bytes before truncation (0 = no limit) + targetBytes: Target size after truncation (default: maxBytes * 0.8) + """ + super().__init__(filename, mode, encoding) + self.maxBytes = maxBytes + self.targetBytes = targetBytes or int(maxBytes * 0.8) if maxBytes > 0 else 0 + self._check_counter = 0 + + def emit(self, record): + """Emit a record, checking file size periodically and truncating if needed.""" + try: + # Check file size every 100 records to avoid excessive I/O + self._check_counter += 1 + if self.maxBytes > 0 and self._check_counter >= 100: + self._check_counter = 0 + self.stream.flush() + if os.path.exists(self.baseFilename): + current_size = os.path.getsize(self.baseFilename) + if current_size > self.maxBytes: + self._truncate_to_target() + super().emit(record) + except Exception: + self.handleError(record) + + def _truncate_to_target(self): + """Truncate file to targetBytes by removing old entries from the beginning.""" + try: + self.stream.close() + + current_size = os.path.getsize(self.baseFilename) + bytes_to_remove = current_size - self.targetBytes + + if bytes_to_remove <= 0: + self.stream = self._open() + return + + # Read file and find position to cut + with open(self.baseFilename, 'r', encoding=self.encoding or 'utf-8') as f: + # Skip bytes_to_remove bytes, then find next newline + f.seek(bytes_to_remove) + # Read until next complete line + f.readline() # Skip partial line + # Keep everything from here + remaining_content = f.read() + + # Rewrite file with remaining content + with open(self.baseFilename, 'w', encoding=self.encoding or 'utf-8') as f: + f.write(f"--- Log truncated, removed ~{bytes_to_remove} bytes of old entries ---\n") + f.write(remaining_content) + + # Reopen stream + self.stream = self._open() + except Exception as e: + # If truncation fails, just continue logging + print(f"Failed to truncate log file {self.baseFilename}: {e}") + try: + self.stream = self._open() + except: + pass + + def _as_bool(value: str | None) -> bool: return (value or '').strip().lower() in {"1", "true", "yes", "on"} @@ -117,19 +191,24 @@ def setup_logging(): file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') console_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') - main_handler = RotatingFileHandler( + # Use SizeLimitedFileHandler to maintain log files around 5MB + # When file exceeds 5MB, old entries are removed to bring it down to ~4MB + # This keeps the file size stable without rotating files (Docker bind mount safe) + main_handler = SizeLimitedFileHandler( 'app.log', - maxBytes=5 * 1024 * 1024, - backupCount=1, - encoding='utf-8' + mode='a', + encoding='utf-8', + maxBytes=5 * 1024 * 1024, # 5 MB - trigger truncation + targetBytes=4 * 1024 * 1024 # 4 MB - target size after truncation ) main_handler.setFormatter(file_formatter) - dryer_handler = RotatingFileHandler( + dryer_handler = SizeLimitedFileHandler( 'dryer.log', - maxBytes=5 * 1024 * 1024, - backupCount=0, - encoding='utf-8' + mode='a', + encoding='utf-8', + maxBytes=5 * 1024 * 1024, # 5 MB - trigger truncation + targetBytes=4 * 1024 * 1024 # 4 MB - target size after truncation ) dryer_handler.setFormatter(file_formatter) diff --git a/api/tools/dryer_control.py b/api/tools/dryer_control.py index 7344ac6f..e6dcf02f 100644 --- a/api/tools/dryer_control.py +++ b/api/tools/dryer_control.py @@ -25,7 +25,7 @@ from api.cruds.dryer_crud import dryer_crud from simple_pid import PID from collections import deque -import numpy as np +import statistics from datetime import datetime import json from api.cruds.preset_crud import preset_crud @@ -445,7 +445,7 @@ def __init__(self, window_size): def update(self, new_value): self.window.append(new_value) - median_value = np.median(self.window) + median_value = statistics.median(self.window) return median_value class Heater_PID(object): diff --git a/api/websocket_manager.py b/api/websocket_manager.py index ec55658d..6931f013 100644 --- a/api/websocket_manager.py +++ b/api/websocket_manager.py @@ -5,10 +5,12 @@ `connection_type` (channel) string and `broadcast` can target a specific group or all active connections. Dead/broken connections are pruned during broadcast with lightweight debug logging. + +Supports dynamic channels like dryer_{id}_stats for per-dryer subscriptions. """ from fastapi import WebSocket -from typing import List +from typing import List, Dict import logging logger = logging.getLogger(__name__) @@ -20,33 +22,43 @@ class WebSocketConnectionManager: Supported connection types: - app_logs: general backend/application log lines - dryer_logs: dryer operational log messages - - dryers_stats: periodic telemetry / status payloads + - dryers_stats: periodic telemetry / status payloads (legacy - all dryers) + - dryer_{id}_stats: per-dryer telemetry (optimized, e.g., dryer_1_stats) - Any other connection type passed to `connect` is stored only in the - aggregate `active_connections` list and will receive broadcasts when the - `connection_type` parameter is `all`. + Dynamic channels are automatically created when first connection subscribes. """ def __init__(self): self.active_connections: List[WebSocket] = [] + # Legacy fixed channels self.app_logs_connections: List[WebSocket] = [] self.dryer_logs_connections: List[WebSocket] = [] self.dryers_stats_connections: List[WebSocket] = [] + # Dynamic channels (key = channel name, value = list of websockets) + self.dynamic_channels: Dict[str, List[WebSocket]] = {} async def connect(self, websocket: WebSocket, connection_type: str = "general"): """Accept a new WebSocket and classify by `connection_type`. - Duplicate additions are naturally avoided because each list holds - references only once (clients typically call connect a single time). + Supports both fixed channels (app_logs, dryer_logs, dryers_stats) + and dynamic channels (e.g., dryer_1_stats, dryer_2_stats). """ await websocket.accept() self.active_connections.append(websocket) + + # Fixed legacy channels if connection_type == "app_logs": self.app_logs_connections.append(websocket) elif connection_type == "dryer_logs": self.dryer_logs_connections.append(websocket) elif connection_type == "dryers_stats": self.dryers_stats_connections.append(websocket) + else: + # Dynamic channel (e.g., dryer_{id}_stats) + if connection_type not in self.dynamic_channels: + self.dynamic_channels[connection_type] = [] + self.dynamic_channels[connection_type].append(websocket) + logger.debug( "WebSocket connected type=%s active=%d", connection_type, len(self.active_connections) ) @@ -54,9 +66,13 @@ async def connect(self, websocket: WebSocket, connection_type: str = "general"): def disconnect(self, websocket: WebSocket): """Remove a WebSocket from all tracking lists if present.""" removed = False + + # Remove from main list if websocket in self.active_connections: self.active_connections.remove(websocket) removed = True + + # Remove from fixed channels if websocket in self.app_logs_connections: self.app_logs_connections.remove(websocket) removed = True @@ -66,15 +82,35 @@ def disconnect(self, websocket: WebSocket): if websocket in self.dryers_stats_connections: self.dryers_stats_connections.remove(websocket) removed = True + + # Remove from dynamic channels + empty_channels = [] + for channel_name, connections in self.dynamic_channels.items(): + if websocket in connections: + connections.remove(websocket) + removed = True + # Mark channel for cleanup if empty + if len(connections) == 0: + empty_channels.append(channel_name) + + # Cleanup empty dynamic channels to prevent memory leak + for channel_name in empty_channels: + del self.dynamic_channels[channel_name] + logger.debug("Removed empty dynamic channel: %s", channel_name) + if removed: logger.debug( - "WebSocket disconnected remaining=%d", len(self.active_connections) + "WebSocket disconnected remaining=%d dynamic_channels=%d", + len(self.active_connections), + len(self.dynamic_channels) ) async def broadcast(self, message: str, connection_type: str = "all"): """Send a text message to all or a specific connection type. - Broken connections encountered during send are removed via `disconnect`. + Supports fixed channels (app_logs, dryer_logs, dryers_stats) and + dynamic channels (dryer_{id}_stats). Broken connections encountered + during send are removed via `disconnect`. """ if connection_type == "all": targets = list(self.active_connections) @@ -84,16 +120,25 @@ async def broadcast(self, message: str, connection_type: str = "all"): targets = list(self.dryer_logs_connections) elif connection_type == "dryers_stats": targets = list(self.dryers_stats_connections) + elif connection_type in self.dynamic_channels: + # Dynamic channel (e.g., dryer_1_stats) + targets = list(self.dynamic_channels[connection_type]) else: - logger.debug("Unknown connection_type '%s' defaulting to all", connection_type) - targets = list(self.active_connections) + # Unknown channel - no subscribers, skip silently + logger.debug("No subscribers for channel '%s', skipping broadcast", connection_type) + return + dead_connections = [] for ws in targets: try: await ws.send_text(message) except Exception as exc: # noqa: BLE001 broad here to ensure cleanup - logger.debug("Dropping dead WebSocket during broadcast: %s", exc) - self.disconnect(ws) + logger.debug("Dropping dead WebSocket during broadcast channel=%s: %s", connection_type, exc) + dead_connections.append(ws) + + # Batch cleanup after iteration + for ws in dead_connections: + self.disconnect(ws) webSocketManager = WebSocketConnectionManager() \ No newline at end of file diff --git a/api/workers/status_worker.py b/api/workers/status_worker.py index 289f046b..eceef745 100644 --- a/api/workers/status_worker.py +++ b/api/workers/status_worker.py @@ -62,8 +62,27 @@ async def worker(self): except HTTPException: logger.error("Dryer missing during update dryer_id=%s", db_dryer.id) if update_result: - update_result = ','.join(update_result) - await webSocketManager.broadcast(f'[{update_result}]', 'dryers_stats') + update_result_str = ','.join(update_result) + aggregated_json = f'[{update_result_str}]' + + # Broadcast to legacy /dryers endpoint (all dryers) + await webSocketManager.broadcast(aggregated_json, 'dryers_stats') + + # Broadcast individual updates to dryer-specific channels + for log_json in update_result: + try: + import json + log_data = json.loads(log_json) + dryer_id = log_data.get('dryer_id') + if dryer_id: + # Send to dryer-specific WebSocket channel + await webSocketManager.broadcast( + f'[{log_json}]', + f'dryer_{dryer_id}_stats' + ) + except Exception as e: + logger.warning("Failed to parse/broadcast individual log: %s", e) + end_time = datetime.utcnow() delta_time = end_time - start_time # Aim for ~1 second loop time diff --git a/build.sh b/build.sh index 24a3d9e5..1f757e70 100644 --- a/build.sh +++ b/build.sh @@ -14,7 +14,7 @@ echo "" # Configuration - CHANGE THIS! DOCKER_USERNAME="xatang" # Your Docker Hub username DOCKER_IMAGE="${DOCKER_USERNAME}/pyunit" -VERSION="latest" # or use version like "2.0.0" +VERSION="latest" # or use version like "2.0.1" echo "Docker Image: ${DOCKER_IMAGE}:${VERSION}" echo "" @@ -63,12 +63,12 @@ echo "" # Build image for multiple platforms echo "=========================================" -echo "Building Docker image for AMD64 and ARM64..." +echo "Building Docker image for multiple platforms..." echo "=========================================" echo "" docker buildx build \ - --platform linux/amd64,linux/arm64 \ + --platform linux/amd64,linux/arm64,linux/arm/v7,linux/arm/v8 \ -t ${DOCKER_IMAGE}:${VERSION} \ --push \ . @@ -92,7 +92,9 @@ echo " https://hub.docker.com/r/${DOCKER_USERNAME}/pyunit" echo "" echo "Image supports:" echo " - linux/amd64 (x86_64)" -echo " - linux/arm64 (Orange Pi, Raspberry Pi)" +echo " - linux/arm64 (ARM 64-bit)" +echo " - linux/arm/v7 (ARMv7 32-bit)" +echo " - linux/arm/v8 (ARMv8 32-bit)" echo "" echo "Users can install with:" echo " ./install.sh" diff --git a/docker-compose.yml b/docker-compose.yml index 3094a7f7..5efcc778 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,11 +17,13 @@ services: volumes: - pyunit_data:/app/data - ./pyunit.db:/app/pyunit.db + - ./pyunit.db-wal:/app/pyunit.db-wal + - ./pyunit.db-shm:/app/pyunit.db-shm - ./app.log:/app/app.log - ./dryer.log:/app/dryer.log restart: unless-stopped healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:5000/docs"] + test: ["CMD", "curl", "-f", "http://localhost:5000/api/common/ping"] interval: 30s timeout: 10s retries: 3 diff --git a/main.py b/main.py index d0da0b7a..75fdd2d7 100644 --- a/main.py +++ b/main.py @@ -46,7 +46,7 @@ async def lifespan(app: FastAPI): app = FastAPI( title="PyUnit", description="Api for PyUnit", - version="2.0.0", + version="2.0.1", debug=True, lifespan=lifespan ) diff --git a/requirements.txt b/requirements.txt index 56fd7523..fdb1a692 100644 --- a/requirements.txt +++ b/requirements.txt @@ -29,12 +29,8 @@ certifi==2025.10.5 # Web utilities python-multipart==0.0.12 websockets==15.0.1 -websocket==0.2.1 h11==0.16.0 -# Numeric -numpy==2.3.3 - # PID control simple-pid==2.0.1 @@ -52,13 +48,5 @@ idna==3.10 charset-normalizer==3.4.4 sniffio==1.3.1 typing_extensions==4.15.0 -typing-inspection==0.4.1 propcache==0.3.2 colorama==0.4.6 - -# Gevent (if needed) -gevent==25.8.2 -zope.event==6.0 -zope.interface==8.0 -cffi==2.0.0 -pycparser==2.23 diff --git a/run.sh b/run.sh index ac0ce53b..31d3c584 100644 --- a/run.sh +++ b/run.sh @@ -137,6 +137,8 @@ fi echo "" echo "Initializing required files..." touch pyunit.db +touch pyunit.db-wal +touch pyunit.db-shm touch app.log touch dryer.log echo "✓ Files initialized" @@ -179,6 +181,33 @@ echo "" echo "Starting PyUnit..." sudo $DC down 2>/dev/null || true sudo $DC pull + +# Clean up old unused images to free disk space +echo "" +echo "Cleaning up old Docker images..." +DANGLING_IMAGES=$(sudo docker images -f "dangling=true" -q) +if [ -n "$DANGLING_IMAGES" ]; then + sudo docker rmi $DANGLING_IMAGES 2>/dev/null || true + echo "✓ Removed dangling images" +else + echo "✓ No dangling images to clean" +fi + +# Optionally clean old pyunit images (keep current tag only) +OLD_PYUNIT_IMAGES=$(sudo docker images xatang/pyunit --format "{{.Repository}}:{{.Tag}}" | grep -v "${DOCKER_TAG}" || true) +if [ -n "$OLD_PYUNIT_IMAGES" ]; then + echo "Found old PyUnit images:" + echo "$OLD_PYUNIT_IMAGES" + read -p "Remove old PyUnit images? (y/N): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "$OLD_PYUNIT_IMAGES" | xargs -r sudo docker rmi 2>/dev/null || true + echo "✓ Removed old PyUnit images" + else + echo "✓ Keeping old images" + fi +fi + sudo $DC up -d echo "" diff --git a/uninstall.sh b/uninstall.sh new file mode 100644 index 00000000..bc77f560 --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,88 @@ +#!/bin/bash +set -e + +echo "=========================================" +echo "PyUnit 2.0 - Uninstall Script" +echo "=========================================" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Configuration +CONTAINER_NAME="pyunit" +VOLUME_NAME="pyunit_pyunit_data" +NETWORK_NAME="pyunit_pyunit_network" +IMAGE_PREFIX="xatang/pyunit" + +# Ask for confirmation +echo "" +echo -e "${YELLOW}WARNING: This will remove:${NC}" +echo " - Docker container: $CONTAINER_NAME" +echo " - Docker volume: $VOLUME_NAME (all data will be lost!)" +echo " - Docker network: $NETWORK_NAME" +echo " - Docker images: ${IMAGE_PREFIX}:*" +echo "" +echo "Local files (pyunit.db, logs) will NOT be deleted." +echo "" +read -p "Are you sure you want to continue? (yes/no): " -r +echo "" + +if [[ ! $REPLY =~ ^[Yy][Ee][Ss]$ ]]; then + echo "Uninstall cancelled." + exit 0 +fi + +echo "Starting uninstall process..." +echo "" + +# Step 1: Stop and remove container +echo -e "${GREEN}[1/3]${NC} Stopping and removing container..." +if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then + docker stop "$CONTAINER_NAME" 2>/dev/null || true + docker rm "$CONTAINER_NAME" 2>/dev/null || true + echo " ✓ Container removed" +else + echo " ⓘ Container not found, skipping" +fi + +# Step 2: Remove volume +echo -e "${GREEN}[2/3]${NC} Removing Docker volume..." +if docker volume ls --format '{{.Name}}' | grep -q "^${VOLUME_NAME}$"; then + docker volume rm "$VOLUME_NAME" 2>/dev/null || true + echo " ✓ Volume removed" +else + echo " ⓘ Volume not found, skipping" +fi + +# Step 3: Remove images +echo -e "${GREEN}[3/4]${NC} Removing Docker images..." +IMAGES=$(docker images --format '{{.Repository}}:{{.Tag}}' | grep "^${IMAGE_PREFIX}:" || true) +if [ -n "$IMAGES" ]; then + echo "$IMAGES" | while read -r image; do + docker rmi "$image" 2>/dev/null || true + echo " ✓ Removed image: $image" + done +else + echo " ⓘ No images found, skipping" +fi + +# Step 4: Remove network +echo -e "${GREEN}[4/4]${NC} Removing Docker network..." +if docker network ls --format '{{.Name}}' | grep -q "^${NETWORK_NAME}$"; then + docker network rm "$NETWORK_NAME" 2>/dev/null || true + echo " ✓ Network removed" +else + echo " ⓘ Network not found, skipping" +fi + +echo "" +echo -e "${GREEN}=========================================${NC}" +echo -e "${GREEN}Uninstall completed successfully!${NC}" +echo -e "${GREEN}=========================================${NC}" +echo "" +echo "To remove local database and logs, run:" +echo " rm -f pyunit.db pyunit.db-wal pyunit.db-shm app.log dryer.log" +echo "" diff --git a/web/.angular/cache/20.3.1/pyunit/.tsbuildinfo b/web/.angular/cache/20.3.1/pyunit/.tsbuildinfo index 8b26793a..ad53a895 100644 --- a/web/.angular/cache/20.3.1/pyunit/.tsbuildinfo +++ b/web/.angular/cache/20.3.1/pyunit/.tsbuildinfo @@ -1 +1 @@ -{"fileNames":["../../../../node_modules/typescript/lib/lib.es5.d.ts","../../../../node_modules/typescript/lib/lib.es2015.d.ts","../../../../node_modules/typescript/lib/lib.es2016.d.ts","../../../../node_modules/typescript/lib/lib.es2017.d.ts","../../../../node_modules/typescript/lib/lib.es2018.d.ts","../../../../node_modules/typescript/lib/lib.es2019.d.ts","../../../../node_modules/typescript/lib/lib.es2020.d.ts","../../../../node_modules/typescript/lib/lib.es2021.d.ts","../../../../node_modules/typescript/lib/lib.es2022.d.ts","../../../../node_modules/typescript/lib/lib.dom.d.ts","../../../../node_modules/typescript/lib/lib.dom.iterable.d.ts","../../../../node_modules/typescript/lib/lib.dom.asynciterable.d.ts","../../../../node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../../../node_modules/typescript/lib/lib.scripthost.d.ts","../../../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../../node_modules/typescript/lib/lib.decorators.d.ts","../../../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../../node_modules/typescript/lib/lib.es2022.full.d.ts","../../../../node_modules/tslib/tslib.d.ts","../../../../node_modules/tslib/modules/index.d.ts","../../../../src/environments.ngtypecheck.ts","../../../../src/environments.ts","../../../../src/main.ngtypecheck.ts","../../../../node_modules/@angular/core/graph.d.d.ts","../../../../node_modules/@angular/core/event_dispatcher.d.d.ts","../../../../node_modules/@angular/core/chrome_dev_tools_performance.d.d.ts","../../../../node_modules/rxjs/dist/types/internal/subscription.d.ts","../../../../node_modules/rxjs/dist/types/internal/subscriber.d.ts","../../../../node_modules/rxjs/dist/types/internal/operator.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable.d.ts","../../../../node_modules/rxjs/dist/types/internal/types.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/audit.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/audittime.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/buffer.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/buffercount.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/buffertime.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/buffertoggle.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/bufferwhen.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/catcherror.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/combinelatestall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/combineall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/combinelatest.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/combinelatestwith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/concat.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/concatall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/concatmap.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/concatmapto.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/concatwith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/connect.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/count.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/debounce.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/debouncetime.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/defaultifempty.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/delay.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/delaywhen.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/dematerialize.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/distinct.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/distinctuntilchanged.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/distinctuntilkeychanged.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/elementat.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/endwith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/every.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/exhaustall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/exhaust.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/exhaustmap.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/expand.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/filter.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/finalize.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/find.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/findindex.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/first.d.ts","../../../../node_modules/rxjs/dist/types/internal/subject.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/groupby.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/ignoreelements.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/isempty.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/last.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/map.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/mapto.d.ts","../../../../node_modules/rxjs/dist/types/internal/notification.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/materialize.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/max.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/merge.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/mergeall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/mergemap.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/flatmap.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/mergemapto.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/mergescan.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/mergewith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/min.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/connectableobservable.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/multicast.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/observeon.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/onerrorresumenextwith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/pairwise.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/partition.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/pluck.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/publish.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/publishbehavior.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/publishlast.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/publishreplay.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/race.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/racewith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/reduce.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/repeat.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/repeatwhen.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/retry.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/retrywhen.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/refcount.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/sample.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/sampletime.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/scan.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/sequenceequal.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/share.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/sharereplay.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/single.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/skip.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/skiplast.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/skipuntil.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/skipwhile.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/startwith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/subscribeon.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/switchall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/switchmap.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/switchmapto.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/switchscan.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/take.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/takelast.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/takeuntil.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/takewhile.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/tap.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/throttle.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/throttletime.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/throwifempty.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/timeinterval.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/timeout.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/timeoutwith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/timestamp.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/toarray.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/window.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/windowcount.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/windowtime.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/windowtoggle.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/windowwhen.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/withlatestfrom.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/zip.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/zipall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/zipwith.d.ts","../../../../node_modules/rxjs/dist/types/operators/index.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/action.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler.d.ts","../../../../node_modules/rxjs/dist/types/internal/testing/testmessage.d.ts","../../../../node_modules/rxjs/dist/types/internal/testing/subscriptionlog.d.ts","../../../../node_modules/rxjs/dist/types/internal/testing/subscriptionloggable.d.ts","../../../../node_modules/rxjs/dist/types/internal/testing/coldobservable.d.ts","../../../../node_modules/rxjs/dist/types/internal/testing/hotobservable.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/asyncscheduler.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/timerhandle.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/asyncaction.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/virtualtimescheduler.d.ts","../../../../node_modules/rxjs/dist/types/internal/testing/testscheduler.d.ts","../../../../node_modules/rxjs/dist/types/testing/index.d.ts","../../../../node_modules/rxjs/dist/types/internal/symbol/observable.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/dom/animationframes.d.ts","../../../../node_modules/rxjs/dist/types/internal/behaviorsubject.d.ts","../../../../node_modules/rxjs/dist/types/internal/replaysubject.d.ts","../../../../node_modules/rxjs/dist/types/internal/asyncsubject.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/asapscheduler.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/asap.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/async.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/queuescheduler.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/queue.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/animationframescheduler.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/animationframe.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/identity.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/pipe.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/noop.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/isobservable.d.ts","../../../../node_modules/rxjs/dist/types/internal/lastvaluefrom.d.ts","../../../../node_modules/rxjs/dist/types/internal/firstvaluefrom.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/argumentoutofrangeerror.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/emptyerror.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/notfounderror.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/objectunsubscribederror.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/sequenceerror.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/unsubscriptionerror.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/bindcallback.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/bindnodecallback.d.ts","../../../../node_modules/rxjs/dist/types/internal/anycatcher.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/combinelatest.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/concat.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/connectable.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/defer.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/empty.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/forkjoin.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/from.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/fromevent.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/fromeventpattern.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/generate.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/iif.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/interval.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/merge.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/never.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/of.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/onerrorresumenext.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/pairs.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/partition.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/race.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/range.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/throwerror.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/timer.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/using.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/zip.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduled/scheduled.d.ts","../../../../node_modules/rxjs/dist/types/internal/config.d.ts","../../../../node_modules/rxjs/dist/types/index.d.ts","../../../../node_modules/@angular/core/effect.d.d.ts","../../../../node_modules/@angular/core/primitives/di/index.d.ts","../../../../node_modules/@angular/core/discovery.d.d.ts","../../../../node_modules/@angular/core/api.d.d.ts","../../../../node_modules/@angular/core/weak_ref.d.d.ts","../../../../node_modules/@angular/core/index.d.ts","../../../../node_modules/@angular/common/platform_location.d.d.ts","../../../../node_modules/@angular/common/common_module.d.d.ts","../../../../node_modules/@angular/common/xhr.d.d.ts","../../../../node_modules/@angular/common/index.d.ts","../../../../node_modules/@angular/platform-browser/browser.d.d.ts","../../../../node_modules/@angular/common/module.d.d.ts","../../../../node_modules/@angular/common/http/index.d.ts","../../../../node_modules/@angular/platform-browser/index.d.ts","../../../../src/app/app.config.ngtypecheck.ts","../../../../node_modules/@angular/router/router_module.d.d.ts","../../../../node_modules/@angular/router/index.d.ts","../../../../src/app/app.routes.ngtypecheck.ts","../../../../src/app/pages/presets/presets.ngtypecheck.ts","../../../../node_modules/@angular/forms/index.d.ts","../../../../src/app/services/toast.ngtypecheck.ts","../../../../src/app/services/toast.ts","../../../../src/app/pages/presets/presets.service.ngtypecheck.ts","../../../../src/app/pages/presets/presets.service.ts","../../../../src/app/services/logging.service.ngtypecheck.ts","../../../../src/app/services/logging.service.ts","../../../../src/app/pages/presets/presets.ts","../../../../src/app/pages/logs/logs.ngtypecheck.ts","../../../../src/app/pages/logs/logs.service.ngtypecheck.ts","../../../../src/app/pages/logs/logs.service.ts","../../../../src/app/pages/logs/logs.ts","../../../../src/app/pages/dashboard/dashboard.ngtypecheck.ts","../../../../src/app/pages/dashboard/dashboard-dryers/dashboard-dryers.ngtypecheck.ts","../../../../src/app/pages/dashboard/dashboard.service.ngtypecheck.ts","../../../../src/app/pages/dashboard/dashboard.service.ts","../../../../src/app/pages/dashboard/dashboard-dryers/dashboard-dryers.ts","../../../../src/app/pages/dashboard/dashboard-charts/dashboard-charts.ngtypecheck.ts","../../../../node_modules/highcharts/options/abands.d.ts","../../../../node_modules/highcharts/options/ad.d.ts","../../../../node_modules/highcharts/options/ao.d.ts","../../../../node_modules/highcharts/options/apo.d.ts","../../../../node_modules/highcharts/options/arcdiagram.d.ts","../../../../node_modules/highcharts/options/area.d.ts","../../../../node_modules/highcharts/options/arearange.d.ts","../../../../node_modules/highcharts/options/areaspline.d.ts","../../../../node_modules/highcharts/options/areasplinerange.d.ts","../../../../node_modules/highcharts/options/aroon.d.ts","../../../../node_modules/highcharts/options/aroonoscillator.d.ts","../../../../node_modules/highcharts/options/atr.d.ts","../../../../node_modules/highcharts/options/bar.d.ts","../../../../node_modules/highcharts/options/bb.d.ts","../../../../node_modules/highcharts/options/bellcurve.d.ts","../../../../node_modules/highcharts/options/boxplot.d.ts","../../../../node_modules/highcharts/options/bubble.d.ts","../../../../node_modules/highcharts/options/bullet.d.ts","../../../../node_modules/highcharts/options/candlestick.d.ts","../../../../node_modules/highcharts/options/cci.d.ts","../../../../node_modules/highcharts/options/chaikin.d.ts","../../../../node_modules/highcharts/options/cmf.d.ts","../../../../node_modules/highcharts/options/cmo.d.ts","../../../../node_modules/highcharts/options/column.d.ts","../../../../node_modules/highcharts/options/columnpyramid.d.ts","../../../../node_modules/highcharts/options/columnrange.d.ts","../../../../node_modules/highcharts/options/cylinder.d.ts","../../../../node_modules/highcharts/options/dema.d.ts","../../../../node_modules/highcharts/options/dependencywheel.d.ts","../../../../node_modules/highcharts/options/disparityindex.d.ts","../../../../node_modules/highcharts/options/dmi.d.ts","../../../../node_modules/highcharts/options/dpo.d.ts","../../../../node_modules/highcharts/options/dumbbell.d.ts","../../../../node_modules/highcharts/options/ema.d.ts","../../../../node_modules/highcharts/options/errorbar.d.ts","../../../../node_modules/highcharts/options/flags.d.ts","../../../../node_modules/highcharts/options/flowmap.d.ts","../../../../node_modules/highcharts/options/funnel.d.ts","../../../../node_modules/highcharts/options/gantt.d.ts","../../../../node_modules/highcharts/options/gauge.d.ts","../../../../node_modules/highcharts/options/geoheatmap.d.ts","../../../../node_modules/highcharts/options/heatmap.d.ts","../../../../node_modules/highcharts/options/heikinashi.d.ts","../../../../node_modules/highcharts/options/histogram.d.ts","../../../../node_modules/highcharts/options/hlc.d.ts","../../../../node_modules/highcharts/options/hollowcandlestick.d.ts","../../../../node_modules/highcharts/options/ikh.d.ts","../../../../node_modules/highcharts/options/item.d.ts","../../../../node_modules/highcharts/options/keltnerchannels.d.ts","../../../../node_modules/highcharts/options/klinger.d.ts","../../../../node_modules/highcharts/options/line.d.ts","../../../../node_modules/highcharts/options/linearregressionangle.d.ts","../../../../node_modules/highcharts/options/linearregression.d.ts","../../../../node_modules/highcharts/options/linearregressionintercept.d.ts","../../../../node_modules/highcharts/options/linearregressionslope.d.ts","../../../../node_modules/highcharts/options/lollipop.d.ts","../../../../node_modules/highcharts/options/macd.d.ts","../../../../node_modules/highcharts/options/map.d.ts","../../../../node_modules/highcharts/options/mapbubble.d.ts","../../../../node_modules/highcharts/options/mapline.d.ts","../../../../node_modules/highcharts/options/mappoint.d.ts","../../../../node_modules/highcharts/options/mfi.d.ts","../../../../node_modules/highcharts/options/momentum.d.ts","../../../../node_modules/highcharts/options/natr.d.ts","../../../../node_modules/highcharts/options/networkgraph.d.ts","../../../../node_modules/highcharts/options/obv.d.ts","../../../../node_modules/highcharts/options/ohlc.d.ts","../../../../node_modules/highcharts/options/organization.d.ts","../../../../node_modules/highcharts/options/packedbubble.d.ts","../../../../node_modules/highcharts/options/pareto.d.ts","../../../../node_modules/highcharts/options/pc.d.ts","../../../../node_modules/highcharts/options/pictorial.d.ts","../../../../node_modules/highcharts/options/pie.d.ts","../../../../node_modules/highcharts/options/pivotpoints.d.ts","../../../../node_modules/highcharts/options/pointandfigure.d.ts","../../../../node_modules/highcharts/options/polygon.d.ts","../../../../node_modules/highcharts/options/ppo.d.ts","../../../../node_modules/highcharts/options/priceenvelopes.d.ts","../../../../node_modules/highcharts/options/psar.d.ts","../../../../node_modules/highcharts/options/pyramid.d.ts","../../../../node_modules/highcharts/options/renko.d.ts","../../../../node_modules/highcharts/options/roc.d.ts","../../../../node_modules/highcharts/options/rsi.d.ts","../../../../node_modules/highcharts/options/sankey.d.ts","../../../../node_modules/highcharts/options/scatter.d.ts","../../../../node_modules/highcharts/options/series.d.ts","../../../../node_modules/highcharts/options/slowstochastic.d.ts","../../../../node_modules/highcharts/options/sma.d.ts","../../../../node_modules/highcharts/options/solidgauge.d.ts","../../../../node_modules/highcharts/options/spline.d.ts","../../../../node_modules/highcharts/options/stochastic.d.ts","../../../../node_modules/highcharts/options/streamgraph.d.ts","../../../../node_modules/highcharts/options/sunburst.d.ts","../../../../node_modules/highcharts/options/supertrend.d.ts","../../../../node_modules/highcharts/options/tema.d.ts","../../../../node_modules/highcharts/options/tiledwebmap.d.ts","../../../../node_modules/highcharts/options/tilemap.d.ts","../../../../node_modules/highcharts/options/timeline.d.ts","../../../../node_modules/highcharts/options/treegraph.d.ts","../../../../node_modules/highcharts/options/treemap.d.ts","../../../../node_modules/highcharts/options/trendline.d.ts","../../../../node_modules/highcharts/options/trix.d.ts","../../../../node_modules/highcharts/options/variablepie.d.ts","../../../../node_modules/highcharts/options/variwide.d.ts","../../../../node_modules/highcharts/options/vbp.d.ts","../../../../node_modules/highcharts/options/vector.d.ts","../../../../node_modules/highcharts/options/venn.d.ts","../../../../node_modules/highcharts/options/vwap.d.ts","../../../../node_modules/highcharts/options/waterfall.d.ts","../../../../node_modules/highcharts/options/williamsr.d.ts","../../../../node_modules/highcharts/options/windbarb.d.ts","../../../../node_modules/highcharts/options/wma.d.ts","../../../../node_modules/highcharts/options/wordcloud.d.ts","../../../../node_modules/highcharts/options/xrange.d.ts","../../../../node_modules/highcharts/options/zigzag.d.ts","../../../../node_modules/highcharts/globals.d.ts","../../../../node_modules/highcharts/highcharts.d.ts","../../../../node_modules/highcharts/modules/boost.d.ts","../../../../src/app/pages/dashboard/dashboard-charts/dashboard-charts.ts","../../../../src/app/pages/dashboard/dashboard.ts","../../../../src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.ngtypecheck.ts","../../../../src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.ts","../../../../src/app/common-ui/layout/layout.ngtypecheck.ts","../../../../src/app/common-ui/header/header.ngtypecheck.ts","../../../../src/app/common-ui/header/header.ts","../../../../src/app/common-ui/layout/layout.ts","../../../../src/app/pages/configs/configs.ngtypecheck.ts","../../../../src/app/pages/configs/moonraker-config/moonraker-config.ngtypecheck.ts","../../../../src/app/pages/configs/moonraker-config/moonraker-config.service.ngtypecheck.ts","../../../../src/app/pages/configs/moonraker-config/moonraker-config.service.ts","../../../../src/app/pages/configs/moonraker-config/moonraker-config.ts","../../../../src/app/pages/configs/dryer-config/dryer-config.ngtypecheck.ts","../../../../src/app/pages/configs/dryer-config/dryer-config.service.ngtypecheck.ts","../../../../src/app/pages/configs/dryer-config/dryer-config.service.ts","../../../../src/app/pages/configs/dryer-config/dryer-config.ts","../../../../src/app/pages/configs/configs.ts","../../../../src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.ngtypecheck.ts","../../../../src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.ts","../../../../src/app/pages/embed/dryer-control-embed/dryer-control-embed.ngtypecheck.ts","../../../../src/app/pages/embed/dryer-control-embed/dryer-control-embed.ts","../../../../src/app/app.routes.ts","../../../../src/app/services/global-error-handler.ngtypecheck.ts","../../../../src/app/services/global-error-handler.ts","../../../../src/app/app.initializer.ngtypecheck.ts","../../../../src/app/app.initializer.ts","../../../../src/app/app.config.ts","../../../../src/app/app.ngtypecheck.ts","../../../../src/app/common-ui/toast/toast.ngtypecheck.ts","../../../../src/app/common-ui/toast/toast.ts","../../../../src/app/app.ts","../../../../src/main.ts","../../../../src/app/services/config.service.ngtypecheck.ts","../../../../src/app/services/config.service.ts"],"fileIdsList":[[260,266,267],[260,266,269,272],[260,266,267,268,269],[266],[71],[69,70],[69,70,71,260,261,262],[69],[69,70,71,260,261,262,263,264,265],[260,266],[266,270],[266,270,271,273],[260,266,270,274,276],[260,266,270],[298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413],[298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415],[298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,414,415],[72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,88,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,128,129,130,131,132,133,134,135,136,137,138,139,141,142,143,144,145,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,191,192,193,195,204,206,207,208,209,210,211,213,214,216,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259],[117],[73,76],[75],[75,76],[72,73,74,76],[73,75,76,233],[76],[72,75,117],[75,76,233],[75,241],[73,75,76],[85],[108],[129],[75,76,117],[76,124],[75,76,117,135],[75,76,135],[76,176],[76,117],[72,76,194],[72,76,195],[217],[201,203],[212],[201],[72,76,194,201,202],[194,195,203],[215],[72,76,201,202,203],[74,75,76],[72,76],[73,75,195,196,197,198],[117,195,196,197,198],[195,197],[75,196,197,199,200,204],[72,75],[76,219],[77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,118,119,120,121,122,123,125,126,127,128,129,130,131,132,133,134,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192],[205],[64],[65],[65,266,273,275,277,438,440,442],[65,441],[65,277,278,287,291,417,419,423,433,435,437],[65,266,273,277,444,446],[65,266,277,421],[65,266,277,420,422],[65,266,270,282,445],[65,266,424,428,432],[65,67,260,266,273,430],[65,266,270,273,280,282,286,429,431],[65,67,260,266,273,426],[65,266,270,280,282,286,425,427],[65,260,266,270,280,286,295,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,414,415],[65,260,266,270,274,277,280,282,286,295,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,414,415,418],[65,266,270,277,280,282,286,293,295],[65,67,260,266,286,294],[65,266,292,295,296,416],[65,260,266,270,277,286,295,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,414,415,434],[65,260,266,270,277,282,286,295,436],[65,260,266,282,286,289],[65,67,266,270,274,280,286,288,290],[65,67,260,266,273,283],[65,266,270,273,279,280,282,284,286],[65,266,449],[65,266,286,439],[65,266,285],[65,266,281],[65,66],[65,68,274,443,447]],"fileInfos":[{"version":"94716a6063cac9426b59da38cd5a8299ed337972715c3b933f46288ad7d1de37","affectsGlobalScope":true,"impliedFormat":1},{"version":"97fda9a66baf7f1644a76c27160698be6bc5da3cddb7109d0f12d4c7def0f353","impliedFormat":1},{"version":"6ae308f5abdd675b08bd2b3d6b78018b08a148a1d84f8dea19a6794e5653eca9","impliedFormat":1},{"version":"5a174a590b47d8dab224a6e8b798d2033deb15423bd519258e9beb9401c1d08a","impliedFormat":1},{"version":"070a92b6c7b3061a032d072e87b845b9cdbc8692ba83c54ad73c5ac72a06e7f3","impliedFormat":1},{"version":"a914c8e64e5f910f90cd2e64d1b822a5ef0578862ead57520bcb67f895417b51","impliedFormat":1},{"version":"34fe0fa41bd124512ead7c3d91f2a74293d01ed81056932711c4a09c38f3be66","impliedFormat":1},{"version":"b37ee4d946ad2f6e52cb0ff9571966c6302be51032ba3ea97870bee115b9eacd","impliedFormat":1},{"version":"2f6e6fee948d386ccd3614b7dd1c53ad53424898f7f62bae60c0de87df9d9417","impliedFormat":1},{"version":"943cd359b1e074ea340c364e7c14a1878ac9aef3f1fc1b2a8080d3938042d4f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"eea76ce47dd717e742356873e38f89ce9007cdbe69c9ac1a5e0c8ba1123e2102","affectsGlobalScope":true,"impliedFormat":1},{"version":"c72fe06c11f813667237b6349eed2e242d3636a36e5693c1ad1c2aa33f1ca325","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d65581abfea69586274544cc81e7ae4103f1345650f8a206a66c9da336d73b0","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c11a33d4e5e3948f92c83b1a01cec02a102429466186da3576d49d1e4d2babb","affectsGlobalScope":true,"impliedFormat":1},{"version":"6666becd625655c6662a29a744786dffbf6d66c28f068f5137760ff419ac8adc","affectsGlobalScope":true,"impliedFormat":1},{"version":"345afca9429c9143e0016cdeee715a9bf39c55a2ff46954fe0c9d5764feaf895","affectsGlobalScope":true,"impliedFormat":1},{"version":"408ca1d716d3df0961a473392d55ef872a3e1ce6de4fb8dc7fd6001fba6a1c4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc3ed3562e3c791f2e74ecd3819d15ef58fd3b47939de9853db5dd808253b00f","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac6a91d78291f82d060a24001518a9f5f2a94324722df8c159691c08d39c6bf5","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ce0fcc6c7dc07b2a97cf3bdd4f3df2fdd7056e93acc52de8d15ced40c603602","affectsGlobalScope":true,"impliedFormat":1},{"version":"999e86d04e508d25e374dc1cf37aa4f7f733ad93a8076b20203b3028c7398fc3","affectsGlobalScope":true,"impliedFormat":1},{"version":"c1f9879f76b5409ceaad951b084533d8abc39451a72d6ec55dcc5b9e5f098309","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebfe68159fcc055c880a17b5d5a219dfafc662b48c1cd32a7d3eecc74a1efc70","affectsGlobalScope":true,"impliedFormat":1},{"version":"ee7bdffdbb8462f9973063563f8822e6e2b3b7ce05d4651e4879d00f1479899f","affectsGlobalScope":true,"impliedFormat":1},{"version":"9b0111e0b9c98b0bc610bdeb1486f14c60e8c08852552f692d57becf2fe42ea7","affectsGlobalScope":true,"impliedFormat":1},{"version":"6338d9121d2f1b5cf1c757c65949fc41e1e9e5300dc4105d55f8c27ebfcd5fe2","affectsGlobalScope":true,"impliedFormat":1},{"version":"e6a8f68eed8ff0386d27d17e4a162c21923e3b8c41f3353a9ad6ecfdd7cf2ddb","affectsGlobalScope":true,"impliedFormat":1},{"version":"4e9dccd4588b6a893b02963b1f00ade1b2cc244164cdb3ebb857e3c913d2f921","affectsGlobalScope":true,"impliedFormat":1},{"version":"7c4ffd61b251abb1c37ea129e861a12f462727c7fb8ef0989e582d9ea1c1d375","affectsGlobalScope":true,"impliedFormat":1},{"version":"c4ce7db6ecc881e6f3e0f446d17f18d29acdf703e66ff0df6cf0c6471a83a481","affectsGlobalScope":true,"impliedFormat":1},{"version":"9fe84185f18c70ba5e1a4bcc634b7144c525a7e045c204b60d358e4314d452e9","affectsGlobalScope":true,"impliedFormat":1},{"version":"84d43d8bf818f0a82dd57ac3cfb33ab8706a7d5b6978684342c0e3d17a4a7bc2","affectsGlobalScope":true,"impliedFormat":1},{"version":"45678430c8312f11ed1e429b1cd7d139a7adec4310598bc4c8ed6c2ff975ee4c","affectsGlobalScope":true,"impliedFormat":1},{"version":"d5b7aaa53a6c14f4239fb8c2625513d8573946a110bb88a355c0ba10d781d7d9","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3c08438c9c085e92b48a464b34c0ec0da55ff6459411cf6f02619043b5f474","affectsGlobalScope":true,"impliedFormat":1},{"version":"5b460121cb8201504e9becddb2e3dda74fa2561d14de92f452fed81ad794f2bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"03f5b59a2d05a77266490ec195365773e2947c6022962fd8104e0d23941b0648","affectsGlobalScope":true,"impliedFormat":1},{"version":"8283b753d7dd802450c38f8cd841dd0b1a0b246f9ab429e9b7fa5d8157fc2897","affectsGlobalScope":true,"impliedFormat":1},{"version":"7455bf53aacdd935681c5b701af026368e9eefd34f043605c514d1cce9d5bc7a","affectsGlobalScope":true,"impliedFormat":1},{"version":"9b7b68b72b0727055f8f823a766b888c1dc21aa7f0038e0190168967916eec28","affectsGlobalScope":true,"impliedFormat":1},{"version":"5503f40f563cb65c20d01ba44486450a837786393944ddd2e85e3a4fbaf8c205","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b312bc67316c027e88130f2fc3192eddcb714ce22b20e048c7cd3c878ffbf02","affectsGlobalScope":true,"impliedFormat":1},{"version":"692900ca89d92745df9fb1c425c73c4646fbb32d0806ac52eb6bd7bd234434fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"0069bee860a9c2ffbd29738234c7e72d849358355833913160ef46df10214e0f","affectsGlobalScope":true,"impliedFormat":1},{"version":"2a3f88bcd76a6b4b017a3d90e3e9500ef608ab110c6b0a692307a4fe71ba9e5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0089f4c24a96d79ea2f6d96cb475df1d63a8a129a0bf41a86f3ba00a4d566752","affectsGlobalScope":true,"impliedFormat":1},{"version":"820bd08ba14d07b36701dd25cbc54e0a21b3ea531c5d8f269d2db9046736a47b","affectsGlobalScope":true,"impliedFormat":1},{"version":"bb4ab2aceef0699b248072fd6459072c398049dc45d5e55ff0c2e51abc537820","affectsGlobalScope":true,"impliedFormat":1},{"version":"1b0048315f80cd412b02bd819ce0dfc0b5d682acc02da1d78037a8fc60b95260","affectsGlobalScope":true,"impliedFormat":1},{"version":"535c56a8849d541e0d1ed96ab68ea1742fb46a96d11dfd2b23843d3426ced988","affectsGlobalScope":true,"impliedFormat":1},{"version":"d1e388e9b1bcd2d29af3a6a6fe1627a25944bd3210f05c45f42e77acb7992a68","affectsGlobalScope":true,"impliedFormat":1},{"version":"562732440ea01ab3e998713ca4acf1041d07ba6857ee35bf874dcfa02033bffc","affectsGlobalScope":true,"impliedFormat":1},{"version":"0172bf6476c793a7ade0388f4e5d4fac45acf0d9f7958c40c893dfe7ca84b45f","affectsGlobalScope":true,"impliedFormat":1},{"version":"6ed037605cb3740c89ec8c3eaf21eafb20c56c64784f3d4eb9df506ce6417a6a","affectsGlobalScope":true,"impliedFormat":1},{"version":"4da1991bdb0fbcf81fb73e8af5d41e52decf2555a0b878d3493f5957bf47f079","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4c05910fafb3e62d1d7b03b2d6b5247ec7e50cc3c7e036716748fe3ed3f3531","affectsGlobalScope":true,"impliedFormat":1},{"version":"fd69d5107f90cd266ee098661a45946d7005832ef13381cedb04a8fc51093dcb","affectsGlobalScope":true,"impliedFormat":1},{"version":"a425d6c16c4d990f501c7bd399bdc7437cc73e1344b26594ce5e34dca1f88e10","affectsGlobalScope":true,"impliedFormat":1},{"version":"a37d801def41ad25cf62fc6808979546e71cb7a8212e3deda6bb2a373107bae3","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e5b3b6af88552d9589d69a52f41d0ceaaf0ecd8c159119fb9491a1b580a85f4","affectsGlobalScope":true,"impliedFormat":1},{"version":"4033c51052514a6c3e4564f22671fb7a1cc6aa7746943c2dbf7fb5aa60bb37e5","affectsGlobalScope":true,"impliedFormat":1},{"version":"b333b85aa74c3b92988940ab51d50c533c93e2bb0d78be2b5e9e948e76fece0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"4efaf900b38773fe2bd43b8af5a8b1114e9f857f0392682a68eaa2f4cf304217","impliedFormat":1},{"version":"a6a5253138c5432c68a1510c70fe78a644fe2e632111ba778e1978010d6edfec","impliedFormat":1},{"version":"9fb65d6c07733d72601985e1816141503d35f9b28488081cae5ae6a2864fbdbb","impliedFormat":99},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"f6f5822adc099090277082e3fe23bf1472d583d3eaa111b0d5cb9de25e026b16","signature":"27c30ba3d87fc6dd1f2f2a03111df5fe60638d5c6599213c02abdcb6e319270c"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"865aa0bbc9e488804b9cf53c12731233ef912d5f7a982bdb3e8d57204cbe050e","impliedFormat":99},{"version":"1f014232ccf15dfa70fef06df24f60f5210a0cae7274e68d9bcc645f024beb61","affectsGlobalScope":true,"impliedFormat":99},{"version":"c9069a4bf73de04db12e6a24be3ee3e13d4e0dfff5ed7c2c7f05b65f523bfab6","affectsGlobalScope":true,"impliedFormat":99},{"version":"1493c3eaf5af8e17c30a566f819c8fd51ea5e28b9701a7e638088fd6e532cb32","impliedFormat":1},{"version":"bbb9a2955c63192ed9106b322a307604c129e822a4ca922281d71b343c3b18c2","impliedFormat":1},{"version":"92cc7a3e17ef5d44f21cc3a25b1dc92f396ae77ac0049e4761f6d60e3269734f","impliedFormat":1},{"version":"4743d9f47dc30e93a9826dd2a342f63a00f3dc7bf4622d15e37d49bfd58e5bc5","impliedFormat":1},{"version":"404848c0b4345315b816d92bed640f7411ddd6b417596dcbd5df00f84d2943f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"0bfafe42767c045fa74210f3f93f42e3fa49b7a1fc4afa2382f9e3304bb89ccc","impliedFormat":1},{"version":"1f915f761eba3da5439ce15769ca22b435e7699160204bef775c2b78531a169c","impliedFormat":1},{"version":"07203713bbe9a638d4fc11895432f6ad8d13391fe4d4dcf12cb7d5d49ce2303d","impliedFormat":1},{"version":"e910acfee92e27859da5aeaadf07a76e189be8ab53d4783121efae63a1aff784","impliedFormat":1},{"version":"0c3de5c67592cd888a0eacb079c153751c05eb4eeb284d0a837be9ccd8782f19","impliedFormat":1},{"version":"1a955a0c4968b1df660c2136d788935776373e1c35ed386a7c9a4838c4cd1ecd","impliedFormat":1},{"version":"97317c0b2d9b90ebb9e0cc8fc30b5d286d581c83d0da16a160ded95c9ebdfa83","impliedFormat":1},{"version":"199f601640f125bf79573c17dd46361bafd4d0f995355afee979feef9b485967","impliedFormat":1},{"version":"4f856fda5803fe14a5f675d844437262a2321873ffe6b5b28f434ab3cd98c2e2","impliedFormat":1},{"version":"34a136c5fb572104624bdd5ca5051e7bd9a99c5c827f4d0cda0cb913fd9c63ed","impliedFormat":1},{"version":"8b1c38f1ad05371ca9da3b91366ba01391163487bc4004d678c2d78b7a7fb141","impliedFormat":1},{"version":"2346514a7f68d5be7daf65c3ab50e3ce7ea5828d439fc9dcdc7e3b21704d937e","impliedFormat":1},{"version":"8087f9490ac0bdaa8fe1821f8f2f7a66e239a26ec7a551fb2ff54aef36fa4810","impliedFormat":1},{"version":"3e59b4bfa62961dcd97d3c9bf579cc2f28b6dc2a4c17301e376d5a9f49b5b0b1","impliedFormat":1},{"version":"a1b7e3ad56479c74ebc615dd6dc72e7765e724f12ca8193af73a5320e56f710b","impliedFormat":1},{"version":"c4e4533d2892e5e882472b3ac14780d8d3d1a53a4464cf29aa71f63363ac6dd5","impliedFormat":1},{"version":"185679e7529529e66151a933d3546b0bd5935ebe9479c9d7e61b2a07c9263604","impliedFormat":1},{"version":"f943b91ae555f7310436b46e9bac14308b67df9618fa62d35efa1ed8bb79ea89","impliedFormat":1},{"version":"1b7bd5218e3b282dae675aa6d0be16b52fc2a82c1c3a55b58ff0e501234f05cc","impliedFormat":1},{"version":"9ab4c54973bc8a473b9a3da90b809d3071dc240287f17efa3b8a2d8def3aeb06","impliedFormat":1},{"version":"f45ce325b374417545115afb67c1e7a756a92ecce150a06824b86e0a6ca47706","impliedFormat":1},{"version":"d6d85b6961c7a8df0429dfec54e1d9976678e545fad661fe756b0cedf4aea544","impliedFormat":1},{"version":"904487dac11bf3a2f1c50246d50a3806fe147cda65a3868e711351a461b753e0","impliedFormat":1},{"version":"8a44c8aa5e0212efa9c0f8c2e2ffd034e911195c314a4c8d5846a872ddc97e63","impliedFormat":1},{"version":"b0f8a3e3b4bd666b93e0d9eb2d2b9539c0b5146e07c5fbe81e0fd9e1a56125d0","impliedFormat":1},{"version":"30ed7d9231f86e5ccc644ac7ffc6bc11caf6b3d9bbcd80ca0e4485ec4540f0a1","impliedFormat":1},{"version":"6c46b5172c65163cf65de721fff40c6dfcfb1d9fcdbd87a5ef9412b1abb8d4e5","impliedFormat":1},{"version":"1a4ad0b2a98fe67fb9e28df1a01f57a9c149838866ebb7e196a5b30f5b549b9a","impliedFormat":1},{"version":"3821e6b582b8b54bab0f624cc31e7425b1a1fcb1e3768aab0da55a3223ae83a1","impliedFormat":1},{"version":"6e9a977f8448b31f4b828e6ae8452a4f491a88afed6b92789600dc0972f56173","impliedFormat":1},{"version":"1c00c1150136b0996026b30c96ff509089b1098e86cf1eff9e3c23dbfa5c662b","impliedFormat":1},{"version":"4a1952149f3622a31734e6fabba2eb7e0aa94b01649d5d3dbb95faad3c6321e2","impliedFormat":1},{"version":"c223ca9542ad121fd582699bc4faca95afa46c71955ae56a2343a147846c4efc","impliedFormat":1},{"version":"a040fd513007d4955027d5a233dbb654f71ab46ab70c84d0d049fb4f53078101","impliedFormat":1},{"version":"fcc8b6f055d4eaed7f11b28d3f8dbd1d54396a354589c02605fff9fc2c16c274","impliedFormat":1},{"version":"69bf15663215f21aabe309cd4ede6b3ed7590ef4fde7c2ae5117a31978e359e3","impliedFormat":1},{"version":"b490395d5ea6a723d9d6a0028eba988ae16a59de482cfbf72411ac78b48424fc","impliedFormat":1},{"version":"4842ef2ff91ae856244623877738198e19f8d160337632b98508be788f59c031","impliedFormat":1},{"version":"a34be37eaef02d2d14779c2816f51bc26ee9f88c61d686b01a18d182b58d4812","impliedFormat":1},{"version":"1a715ed850ab3eaa76ee51309e996b7f96d17668817fa0d6a0fd99c25a0de8ef","impliedFormat":1},{"version":"e6a21dcebcbec4b1c6d6a90232676f270f8196167ef585558862bf604a6d6573","impliedFormat":1},{"version":"6b533b83efe999ec22904040615d3fa4d0d3599168949c1f05d5229adca10b33","impliedFormat":1},{"version":"f7b0d6a704e1abd68d344aee0cea3cb40266b4e6337474ce935482f2d26bc1d7","impliedFormat":1},{"version":"08665a0ec37cc8f79cc8a3f51a57685a983973b76651f47b0b04654ebfe1837f","impliedFormat":1},{"version":"821e02b86c41d06f374def3e6f7b89426951496cb381fc7e4437e1cec48bdfa9","impliedFormat":1},{"version":"966748c05b6fb548f03d41984399fa83500b5d06f7703fb4fb29856e03f62edb","impliedFormat":1},{"version":"20d63781d1056264d11d37057adb3cc6e95198f458a2c67f56efb8505e5ec1ad","impliedFormat":1},{"version":"07917b286c389afe937437a9383401829744599b14a681f409ad5d2837624ca9","impliedFormat":1},{"version":"50a2cd2ef62ccb86e2ba4d6c92147233da2340cdf6e1992b5fd0b35f1e945484","impliedFormat":1},{"version":"1f6ca37d2f71e6ce3d7703564a08fc121d34bbd5c75885df7c21c4e197c9ae0c","impliedFormat":1},{"version":"c2dae7c8810ec085307050640583bcf21b457c5763be87cb89447a5932513370","impliedFormat":1},{"version":"c549b7a5e56f5aeb79611ecde27d907a6dae4f6a80129a6e977968f43b2256ce","impliedFormat":1},{"version":"c0cf28f8d2b6f3399b3e7ca2f56998b947729614bd4f611c392b430be613d773","impliedFormat":1},{"version":"79048db5ba922ac904ff75cd8e283907f68ea47ce9a912f178c6aa3b007fbd7d","impliedFormat":1},{"version":"9c7d04e6f98fbd761fbaabe71591b36dbd53ac44c1cfc362ffa981b988be8725","impliedFormat":1},{"version":"614aba2f6213babb42e3c5ee200282ac6c66389066b1325287398579c7cc52c8","impliedFormat":1},{"version":"a12479cc337380b3a79fbeee319eb1d643bf57d234c6567a642fc1b5fb920a4a","impliedFormat":1},{"version":"af7145e387ff0e01e8a4875c67a170b04475a34b81317e3ad801f866f67fdf1d","impliedFormat":1},{"version":"42e21275c1baea771151c1f921ff38c5747f0261548915b023629ea456ada0e2","impliedFormat":1},{"version":"344a475c6703c0c7703fe83c721f6919ff918fb9e967d0362d3028f7bf7e0c32","impliedFormat":1},{"version":"25f5ac5f22edbea71a079803bd87f1dc323034cdbdc678898f18e1fedf3589a7","impliedFormat":1},{"version":"a4f5772da7b4c7c2225e6389fc4a4fe6ea356cb1e7d8c0a57e0afec83532ee3e","impliedFormat":1},{"version":"41f2cd991bf23126d5aeed9bc65e5ce2846168456bfe2d796a180e3dc9c8b068","impliedFormat":1},{"version":"4d9d715e262069f700a17663429d79e0b5ca2adf306d84b1fd0fddc1b8eeeb42","impliedFormat":1},{"version":"4fd435c4ddda5c923944e1b9c0bf1e7facb136c71e8253e37a627ff990347091","impliedFormat":1},{"version":"376f904b5439dd8dfcfa9f46e0785ed1a84fdcdf8dd102c4404cd1bb286ad110","impliedFormat":1},{"version":"5f80a436f4d302833f9bdc0471b495f40eb6c0273dc99337e053d1f637ddde82","impliedFormat":1},{"version":"b219f281ec13b4139f926f72900eedfd2b6bee5022ea50813a50ec25bf23d78c","impliedFormat":1},{"version":"afeedff5d41717e21bc8a7db3cf1e88d4c52ea9b602b5e6c9ac6376739e09b32","impliedFormat":1},{"version":"8ae6f06728175da554c055379108df7f6a6e87fc9a2c83e0789388e34d988ae5","impliedFormat":1},{"version":"05a5fae6ea4c69bc084b28561a9ea0e05ac79bbe2653753d65cebd3060aa2234","impliedFormat":1},{"version":"a68604c49bcac0578a76a5ec112027f7cd65c9e36b61a89b674a7a4e6d541c31","impliedFormat":1},{"version":"3129120392cc49620e2a2cc6923944f401fd7fbb8d5354efa725923f42a49752","impliedFormat":1},{"version":"5c251fd52f86fbf574d5e86afe410c1667e0bc547fbd9050ac0f2b2137e51998","impliedFormat":1},{"version":"ecc40d44eb097db337baf61aa909576eb59efabf49b298ee31089a7033938296","impliedFormat":1},{"version":"543681c6340482eb9d23611bdc462c31e51491ed202108a24800e9cbe62f01c9","impliedFormat":1},{"version":"37be8cdbc8e1567b1b23dca22a6167529b47eef9c1eeb6441973eb6caf0cef92","impliedFormat":1},{"version":"7a003085cee18c68f4e8a10bd984dc3f7a94eadc9d9ebc0be16eba972bac3aac","impliedFormat":1},{"version":"d3064e5eda936a0dc90b63f38b1343f9ac8a9f3d840bfbf92472c806c4c352ca","impliedFormat":1},{"version":"ea629eb9e08b5fe6c2d15d7040a10bc789d771e35fe9c3c86f2256c80efd0ae3","impliedFormat":1},{"version":"367f68f3a5a904c70719f8aa9d98a5440254c097aec898c77fd98b120b930aa1","impliedFormat":1},{"version":"6c0a7118d466f9afa75091aaeae3f36333470b679586c380a53e05392a395141","impliedFormat":1},{"version":"7e147e53926f4af25d29a5299323afa6da3e74718336529f86a8ce199e009727","impliedFormat":1},{"version":"0b53d30d952f92c1629e35e5fcd8caa5a5178e3c1720db71575e4354c8b292f5","impliedFormat":1},{"version":"91c4bb90cb6d8ee2194a09df44fd16bc441e71bf4a8023f66b3d6ac8f7b45e93","impliedFormat":1},{"version":"49183f4cdd8d7beb7b2457de3a6a7970c1c181ede9b1deb45364f489ef910d70","impliedFormat":1},{"version":"18f6a72615f9c6609761d373674227c95ad4f35dcadb2b018f0d985a77bbf627","impliedFormat":1},{"version":"030c158bd1dceb6acf1e44a8fb18665ba2382031183ab1aa1672b77d209a54f7","impliedFormat":1},{"version":"3ea889e2bf2b8b87f56640a3379becbba846404b7bd3ccb734e8dc2bc2195b7e","impliedFormat":1},{"version":"cfbd32c1dbe59c371d5798757ef44bbaa22dd68169f3f32c40f6f0e5f7ee5c29","impliedFormat":1},{"version":"7ffb4b87407053225e6f0f8fc5967bf9196f72b07006d79d53cacc16a99ba9e1","impliedFormat":1},{"version":"b40c98a600de2187f0a29696eff159c4615fc000761ead257d09dd8ab42e06ee","impliedFormat":1},{"version":"9a1f04530d69bddb5e245faead591c615519ce48c685a85d0cc7768ade384899","impliedFormat":1},{"version":"2163aba020fdf216a4c8801ff5e54bf7e58ae27a59a5b3d40ee528e4cf38bb40","impliedFormat":1},{"version":"c16a678061cc08d56d612935951d07c8a2215d93f2ad5989cef4dab77b1b12a6","impliedFormat":1},{"version":"1119a290d75174b65870309a4501d271900f76f02eb94dd4c9fb2455b2001d80","impliedFormat":1},{"version":"a6ae11110eff3b3288ed231e07cfe96b822e59e9a3da0462936a247909d22832","impliedFormat":1},{"version":"712ce28a408079645d596222d38708f491708bf79cbf60061b36de2dcb36f835","impliedFormat":1},{"version":"e15f6c847c82af7675f90f27e0e7c51029f1a402cd41df8cb76eb023b4b428d5","impliedFormat":1},{"version":"47aea4438d5c7af5c2868616c950bea43380e082a9082261f0ebdad2785faf75","impliedFormat":1},{"version":"ef1a2887863355b5b1181dcd8eac49c6c4e6fde2d80613ca4d83a1850e54890f","impliedFormat":1},{"version":"213183e1446951a6bfb55867c4cbdf612373b0f294c67356a02c3af2b221dad7","impliedFormat":1},{"version":"e3f6e6790d7bfd43189080e3908b993c47c4019ff48150395b673fec6699d149","impliedFormat":1},{"version":"653b2aceaba9cb2c241c687fbd1674211af956e14b9138d5b3813a4a15f9d6ea","impliedFormat":1},{"version":"7a37d37e2eb260740328df7f71da088048204b6f7a062092c6ff18a8361824d1","impliedFormat":1},{"version":"2d6062c344457ce10b74e2903c126e8c56d9cf626e95a5ecaaa90dfb6f4bc3ca","impliedFormat":1},{"version":"29351e8a7008d9510a2aa9b15733c1b1d02d5cf722a7ad74a0ab14ea4074fa2a","impliedFormat":1},{"version":"9cced96bcf7e90524ebc3e582b0cb79d9fb1a2b84df24ec272659a5ad4566706","impliedFormat":1},{"version":"92a3b0674f35953601751d430ae0edf45ae8d6e84ed27991486e1d222885fb8a","impliedFormat":1},{"version":"a7bbadb81ae63b0a953cd6f45b6a5bbb3450bda5d96d6eb436cf94dbd299a309","impliedFormat":1},{"version":"bc2c7f65888e1811fb76d7a46c4b2c83c0d86ac88d9be5a16343907fc14e0000","impliedFormat":1},{"version":"e46ed48eec643cc98b2b86522172e64395fad05445dab7e8febc4f45b53bc750","impliedFormat":1},{"version":"0b0b5a511a22238465ef38e4b98fc1455fd7d8a935e326f36a80fcfca40accbf","impliedFormat":1},{"version":"e927d547036ae8c3a03feb9c9d830b76b09ed0fe0c5ab70ad4f4ab9bd6327d1d","impliedFormat":1},{"version":"f13ba01cd83422d2ee521bde2d47eb61f2c23f54c4d04abefd0699b4d2346364","impliedFormat":1},{"version":"1846a10ab60c4a3e5d13fc9004d12b473bb590b0026c5ead7c2abc53aa7e0f56","impliedFormat":1},{"version":"839878e587bfa3d7645628a0b5d2e7d50e769ea0cabaa797ad64bf219ce40ab6","impliedFormat":1},{"version":"7dc6d80b032b4ac676a78735e04842a3ead6d65f2a5d4422581d4c694f432e71","impliedFormat":1},{"version":"dda44d95bf4743e9df1680d9ad466fb3a860dec08a54328964fa62132e4ec8b9","impliedFormat":1},{"version":"cbd78174fece32405f8eae97d37023d1b8c778068f598be997d6ac27893ae16d","impliedFormat":1},{"version":"6361c4cb51ec7d3d1a93d58eb4db082b57b900859d8682f28c570cd28de4ce07","impliedFormat":1},{"version":"da721c3919e18dab97eea18ac7ae15810ba0ed5269d292084b0f6ae43027e9f5","impliedFormat":1},{"version":"67577d877394a22ae5e9ed91add2d56e9d63bdbf0615c7f21a191e5ea708fd67","impliedFormat":1},{"version":"c48997cab85dad5b18119d7ae9e38b5dfac9d00b077b64e8d3f3684c5167c730","impliedFormat":1},{"version":"a2fbec1da1d2f34ec10ca6c8c01a199ab29102f6c3a9d528e80bb698e159c9bb","impliedFormat":1},{"version":"e58be6b62b31517b190186886d58225167539c0c6ba7e01641c02a2b167e6ddd","impliedFormat":1},{"version":"aeb7e9bdf4e31d3a29e92163c0ad99b6a4b28832247a1b73fea11067594ff5f1","impliedFormat":1},{"version":"0338f0d6e43bfe73bacf4d06bb04c6d96804c9799778604e654df64d4bab0e67","impliedFormat":1},{"version":"ce391fc6ae75503349c5d5538a729af1b1c8269e1d7bc54087651b018abfa081","impliedFormat":1},{"version":"4b7093ad677aab39d40aab7bac68ae97055d7b7bdb080209ee1c59c364a657cc","impliedFormat":1},{"version":"adb0eb48ada06b160b8a3aba6e72c979d4dde0ab96a553cf2fce262624bf394a","impliedFormat":1},{"version":"a637725c54a65ae32a68a28956ee5765b18e6239be4c88fc6ebf6741653cebed","impliedFormat":1},{"version":"7f3c0ee4bfcbe6ae9c7068cafc8850700ed9a888dbda89201d3d2d1bdd79a341","impliedFormat":1},{"version":"387c1c0bf86392903ebc8a32fd9b0f14d10e423a448f9aa05779405758908789","impliedFormat":1},{"version":"d19d9729edb0ed0a7ab8836a9f02e387cf5e85ec512d50021d2f8b56ddd7e348","impliedFormat":1},{"version":"bdc79b9bc3157f80d2696b5b23857b8f6285d69c3a0c206dc566e899a4faf792","impliedFormat":1},{"version":"bf25beb89ab958d34ba12b7d69076fe5f7d2e6f9f806cfec83a5bf70a853f98d","impliedFormat":1},{"version":"2e3c1b3d4b7556f029d135c58f7c50d84c6e922078a7677ebad64342e2591901","impliedFormat":1},{"version":"2ac37e6b83e3eb57f4e85f4ee9a6d87063d9eae0003269d15b6fc40ae6ca36b5","impliedFormat":1},{"version":"60570cc7ba076c23add06ead21fa72d1fd19c3e1b5a7766d4f82d7a309408139","impliedFormat":1},{"version":"99d23001a6eabf92d3aca206e9f28a2098da8e7ea4b32331cf1486b77099f482","impliedFormat":1},{"version":"43e848f969f7ad403d28749df3d46003eff3c98068b08bb18575556c7465fc21","impliedFormat":1},{"version":"f6d24615b5bef821976cb510db19ba15c12691b0191d7dcd0d9f6dc94764e75f","impliedFormat":1},{"version":"b828b5b866e01a20acfc791fec82efeb3a20a00cb508a8f61dd490b81a6003ed","impliedFormat":1},{"version":"4938db21214f998f41dd8d87982520f2155d803118bdca866e12785727507a73","impliedFormat":1},{"version":"de42b2bf19e510030a2572ed1884c4ab8c20db3e1e1969bfc6922193022699d6","impliedFormat":1},{"version":"187c9b65dc21e5e382415af52e3554d92494dc2b8060b6336fdf346ddc6184e0","impliedFormat":1},{"version":"4830bb822d461c5835d2b887f202b537b79cd5e365132da6611f67d307b824f4","impliedFormat":1},{"version":"a61f02064732a2ab23d322d9d8b9911d4c3685b86763a4d7ac1cda0fccd908ba","impliedFormat":1},{"version":"12abcc499df35e46c8fe1a614985645d09ce291d065083b6a95d2db31e31f1a9","impliedFormat":1},{"version":"b988dfb6db3545cc4a04ede9ee705c2c6779539952b8376b1ff90be3a4f74c4f","impliedFormat":1},{"version":"b3eaa7485622714ca8202766ad83484ac2403dbd4b56ed8789885b34be212bdd","impliedFormat":1},{"version":"26575c20f5749d53b4cd3893a707f3ad33f4a64a52c0c33416c3bd2f4243f7b1","impliedFormat":1},{"version":"fabbce92b2a45449d475810443ccd31ecf84f6c40674bf2a1513b86191a6bc3b","impliedFormat":1},{"version":"942ea7301220f5ca0a8b860f653dc6e8c9a42bc833392743fa0b2f2d49e13dfe","impliedFormat":1},{"version":"489dd22803fbb50f0676f65b414c1f1aaf038531b2575b4620eb4d0121947c7c","impliedFormat":1},{"version":"cbb1f813e11e2e0ebf6fbbfe11a66f5b8460e9af2e28cd1942d5ee5c6880a68c","impliedFormat":1},{"version":"00e801f4ad5ab37a22957acfe1e8deaea7f26990d39958fd49aae877949b679b","impliedFormat":1},{"version":"438af48c270447200a64aa2fa062c49a9b1e21bcdf1e6a79255848b13be60cfe","impliedFormat":1},{"version":"a9cf7e480caae93ee23070d81d0c85d3b612e26164c0dd96d5a69224432bf58b","impliedFormat":1},{"version":"f12dcbd0c3b88af16fff1b7c1d94fa7c7654d0df346e66e4d1a0c3a951cea026","impliedFormat":1},{"version":"50ac137becc59e676ab806f6548752fee9e061fa24cb94a869e1aee3ee3fe90d","impliedFormat":1},{"version":"5c138ee7068df5cae9db7c2562c73aa375567e116ec79593059195da2d01e6a6","impliedFormat":1},{"version":"0b4aa74c3cb6e64d7e93043f2ac08dfe1666774a924ff11133afe8fea92a7fe2","impliedFormat":1},{"version":"ac5ed6e44d3e276d6cd3791c0df588f19426a9f67a982ac380020ae858d982f5","impliedFormat":1},{"version":"6603ff43e2263755205079eeddb7607c150bad30e03a013c264ebaf4b79a35e1","impliedFormat":1},{"version":"77d286a5f29e29f6650837c8fd4fc77fb95234eac45ba543193c430812a9cc80","impliedFormat":1},{"version":"dd440ba4b5284fe6dd246c133b46e836e81309698a64eddb9fe608a9ca1cd051","impliedFormat":1},{"version":"6bd12d912af22e33f5755ff9c8c1e84201a6d9114e34d3bb6b0bdab0446cabef","impliedFormat":1},{"version":"d90684bfece77ac3e6d557f264ccc311186cb0877d4ab160f2c6e6e49d3b1ea1","impliedFormat":1},{"version":"39cc5ede3ab0213e333de67aa5860443bcd9cf53041ecdd5fe017285a054daf6","impliedFormat":1},{"version":"dc3f1db6b5365a9d60b76628d1635af1711a1e201a840a749cdd9bc073fbf2dc","impliedFormat":1},{"version":"5f18ef110553e1d69ee80b3b92cd7502dd2f26c6b092e4e3202c3a1c5336bbff","impliedFormat":1},{"version":"deed8885863add75e54dbaea097240f1fcdb8657ceeb342804167cc6c097d896","impliedFormat":1},{"version":"3ba670ceb39995847b90ef75256380e11a71ea72e698cc0ecf9df5282c8531d6","impliedFormat":1},{"version":"f6d19e26f405f05200ff73732d23f5b2b50e211d031abf328fc790884e4d1337","impliedFormat":1},{"version":"69508fcc170f5385914f6fde119fede5294b3d4402966dd262b229c94dc6b157","impliedFormat":1},{"version":"7b6239c431103ae44bcdbc8ecd85a58552345228d3a3380a99cfc5c3d49dd888","impliedFormat":1},{"version":"27e395faa7f7af921e104f5b9fc203ce26438c284413cd4a3a17797a1f523155","impliedFormat":1},{"version":"4284d200969ecedd970a284145ae5a4acf800059812eff9daaa83b676e9aa3c1","impliedFormat":1},{"version":"d6ec50c346e16574749e0284290d72226662914803b2c55ff42d0d1b0ae1bb28","impliedFormat":1},{"version":"4142ea9148909c7654644f97e743a9258c0095775385f4640f41a5a183bd1aae","impliedFormat":1},{"version":"aae67ca278fa75518ce62e0167dccdb8f66fb686bfc411a862c7bc15c8f5b753","impliedFormat":1},{"version":"f43ede2fe612f7af64a9e7b73a579eac2ad738fd23c94c180edd221720d1ac80","impliedFormat":1},{"version":"1e26b5f87bde13285f6f8edbca7c792214109a5a640bba156a46ecf0d57d735d","impliedFormat":99},{"version":"c340eada2b6d952b634af5648440a81d8f441e7a09c50f62b734a8d3600302cb","impliedFormat":99},{"version":"9e0d37cd4dbdcc3b1090c99e1187498cab9be5a8c73011ca19c79d7057568257","impliedFormat":99},{"version":"e9e15edd6c80ae41f9841ed7a5cfbe39a926af1c60dd8329ebf6846c78e69078","impliedFormat":99},{"version":"bb28f7603db016eeade3b21f4a7f80f149056ee5ad34321f7d59b41cceca6840","impliedFormat":99},{"version":"10c0c3523eb4342b1fb83551d084c5a9bc61f76dab08526222fb88a6a2baab0a","impliedFormat":99},{"version":"d37aeaa924fc052051f32002151436595f87d61f2e6438a225005eacddc4e7a6","impliedFormat":99},{"version":"88f325706ac03bcbbbd098e9db4f97006b390c4ff4576ca6ec6b95c95dcda2a8","impliedFormat":99},{"version":"aa5d8433f00cb073c36a915f1fa6a9742edbcd25d8097f3823141ce417321902","impliedFormat":99},{"version":"f0da9960c94bb3d56c3cbc1763d89ab2acabc4bdd22ae53292e1053b846b4690","impliedFormat":99},{"version":"002c9486c088eed3b31825d9f7fb8857542faf691ee01c59a3273b4ede328de7","impliedFormat":99},{"version":"2ab31151a6f9e3cc2c113cd7c50eebcde3d5bd8bb310c3b2c9bffdbb75150051","impliedFormat":99},{"version":"954c927fb0b5e739ddd9b78bbb87c741848596747a548a770e4d79abc97333e9","impliedFormat":99},{"version":"6ae9065d5d6c3988c265f93c5d54cb5955ba5c8986cba24b503790efe90be721","impliedFormat":99},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"87a87778968c619ccd148d444162699bb81c3112a95043108f74c139a93426a4","impliedFormat":99},{"version":"700705321fffd3a19d70bb3c861c2b107ca7aa091b634ec0e3412cf93dcfa414","impliedFormat":99},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"edc450b70efb377bcba5e7d3771098d4fe1ff5ab017fdb0d76e212f309dcc00a","impliedFormat":99},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"e34a2741735a829416584b82fdfd6a4eff8f03a1896ab32988748fb6ef9b17d8","signature":"7d9cf4757530ff5b7e7eda07f4a46dedfa7cfb7f9ef52bd9dea3cd2270f0975d"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"01ea0a8470b52d59c9561a1ec6dee988a5e422706f082e819cce589dd51a416c","signature":"b8ecc5bb26c116432f3a49906ffc1244d5da1e6a315921399814d36d679745c3"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"5d2ca6b8f8dbe48b668835c213f21d9eb4171249753e92c9f719dbd69251f003","signature":"02d5e2109f13356e8075ed4e189487e63e89c2d1db606d190db2c20f5d15a7bb"},{"version":"5ae2d539449c1a03f7a666b27c1695c5e4df07eb15b2198d35458838db123874","signature":"4f37d48689ab288e1b3186ffee475b2c56c5dbce80c4dc82f5727000c991ea1e"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"f5a3993982b37c9ea8fff6b59093705608cb0006e842ab056a9b6a0f95410566","signature":"86f47f3b7906dce9fde5e2416cd518136b277b53f23ced68a21c6d8c9d3f865b"},{"version":"e3dab7586a67eee723d40f18c6173d02d202204bdd0ac5f297cd346338ecec7b","signature":"e42e5cba86f81415a4ef682613f284cf80972780f725888734946fb9f93efcd8"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"21dce2a1c501212a964213f9ae31c10e9f0f7cc6a03ee0ad0f6de6011278210c","signature":"2feab8ffc9c6297adebe4939ea67404b3bbb88f3e64ca403a9f788fbfa67699b"},{"version":"bd68e0027b2c0982c238b52806108f689cdd22ec35b104ecd7ab0ba0c728a924","signature":"0f261c3a95c80d4290189c91041792169b38f7b13f79af11d56474f36bc91e30"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"3dba2c464bcecff3fe0677b9b62a54ebd255194de2f6c3239eb9f8433d78199e","impliedFormat":1},{"version":"75a153ce7aa9864e5f5b5aa0f6d15285ee8ee28be4b49a37895d8146c33c7073","impliedFormat":1},{"version":"b6db37355104b9985d7e7fd21d091f0d0efa878999f413a3a738589b08e253c5","impliedFormat":1},{"version":"84aa36cbcfaea3370371b6f572f122c11547a702dc5eb69447217b0bd4693947","impliedFormat":1},{"version":"411c31be8dea7f1151011450475b5ec7d50f2c586ba0025a8e30189023fed239","impliedFormat":1},{"version":"bf10451233f31689f8466df2957cfc289f2256769ef0a96bf8521ab06f019aab","impliedFormat":1},{"version":"7396a2a6653ddb10a864893b4e139b2229d7b4e0a86c50693a15e842f9ddb9ea","impliedFormat":1},{"version":"750079aafe5dc920cd8f5129d422c4e7528013d680aa168f6cf483ad61f99091","impliedFormat":1},{"version":"0cdfb9bca5949d79f319878de4665ffa2f5dfe58e2d52a3b5c720ca57aef5eca","impliedFormat":1},{"version":"29a5a2c65e62ff7d5ac29db7891cd2b2ef2f91e90e19caeedc06daf77391890b","impliedFormat":1},{"version":"898229164f6ccaa51c331689e64565d14f6679a4822f04f977641b6b6d3ef36c","impliedFormat":1},{"version":"43545961534d6cfc3151d870e209e02868423adbc7080fac8cfa01e2c574a381","impliedFormat":1},{"version":"06b19b4e2c49e119108463a5b6c62a250449556a7976be8ff2c442bd9503df1b","impliedFormat":1},{"version":"116d603dde86fa0b1a363ad1c8592c5e9acf352a62baa5993baa72b3be1a73df","impliedFormat":1},{"version":"629ea4dc5ccd0842ed3dcc9b2906a095df4bb2e32e4fe9504343d77c28eb211b","impliedFormat":1},{"version":"9aa80526f1ba5670338745a25b92fb080b9171e51f15fa0ca4d3b422f50ddceb","impliedFormat":1},{"version":"0f5b91ac7488a424a32ed88047e6c1adf416c20a8e58814f01394073a063ac17","impliedFormat":1},{"version":"0534185debbdc3717c3e7dd435d3a306bd006c89b9e5a404aea64b3c7eb60fc5","impliedFormat":1},{"version":"a6bb659bbfb51c0f1e493a045a4f5885186d61234ddc69c7ef11b6502ba6d6ec","impliedFormat":1},{"version":"417899f4834ad8101ce9a2da583f0827d4372c4c63e70e152f07eb054b363d03","impliedFormat":1},{"version":"f0d6103c0513c7592c8c1348ad33c9646dfea3c71deb98b220cd4911b4c99704","impliedFormat":1},{"version":"071f8795d98e0f7aec2e204ad4385ad485a7575acdf6218568de7979b8e51b2b","impliedFormat":1},{"version":"1ecb27d491a4de146d8f56c62888a5b04b44dc328a5fd9be284247e2155d4afa","impliedFormat":1},{"version":"1df8d8d25c95c443257484f90d5fc7d5de739c8921965701608bffee14db0c1c","impliedFormat":1},{"version":"2b72e84c91e140d3e776302b55da84e54deee8ced4661a7829fe91b982f095bf","impliedFormat":1},{"version":"b0e0ce3d80ffcab1129d3993ef5c860895b153fc395190d7fb0c706931ca49ad","impliedFormat":1},{"version":"4ab2224d23bfc186de35c1b8ff4480547ffb8f1b51a648bbc7a4f61835873747","impliedFormat":1},{"version":"2a41d2584aa23ed542817b4b68374df71126947755bf366e8614748a9fc442d9","impliedFormat":1},{"version":"7875a4964dbda7a14b5cb6b39f6db7bd6756e844f1018a514c23c5ea50e4e969","impliedFormat":1},{"version":"b835e569a60f0c19ce574ea06e7db9968b11fb8819c4423ce2309a5e3f2a825c","impliedFormat":1},{"version":"f78f7970f35f4342ca8a703bc6cd9841df453e895b9228d458142446e4bdf3ac","impliedFormat":1},{"version":"b0c8628db49c7a8c48304469badc0f74be4eeca8257d7cbd0c8208c18f28b90b","impliedFormat":1},{"version":"fc6a20c78e7bf202056f42a2b60e82bd7a5d9c13780d751796e03a5368d1b6fb","impliedFormat":1},{"version":"fe73b756a4cb6b8f9835e60a1e6325afe00df70d89aee7828f3db68e90fff170","impliedFormat":1},{"version":"668869416a940a99ee57f235b9322b131bae24c4259e7800587d8fc246b093cd","impliedFormat":1},{"version":"1c11d3ac1e05b93cac4af09345544e7ecee518f328d40c4d32a8da0942901c65","impliedFormat":1},{"version":"c452328f21d752bfd096a0eb5afc0eb710041d7fe3ca05c8ca07e33058bc9f23","impliedFormat":1},{"version":"1ba2050f909906f76d274235c55c7d8d91baa461069d891b42d3edafdedacf29","impliedFormat":1},{"version":"4c548f7686fd1a39b1843c659712c8cc6a5ee687f8d8f9e1b539e35f6713a180","impliedFormat":1},{"version":"c1f42f611654961fce032dfc82d357ec7acf807f70ef98696fbebf5cab15ce54","impliedFormat":1},{"version":"4e1c79b4384965d5d0ef05c0afe473d001516ca10709b0c14351a8167406ad1e","impliedFormat":1},{"version":"c1efd1c346e5dfda6a90f126e8e91d16cb67a2c698ac33686d15f01fa29d4b46","impliedFormat":1},{"version":"2d0b7c4e747368991be7170a8991a642aec4bc26c4337b882c968d7c012d3057","impliedFormat":1},{"version":"11eedfb03221b54bcf98db5f3d3055f37670801b1573b1e75e6ad499b92d9bff","impliedFormat":1},{"version":"18c24d488ac442fbda14236f584f1cbe9f9a2a6d81a663589b6e78cac4d87fc0","impliedFormat":1},{"version":"6015ded76f3fc76419a5751aa1e68f6525ac7c4eaf2d874b00d531900189c7ba","impliedFormat":1},{"version":"b28a2ee9fb473d25b105322eb74f40a7ae58bdf004a0a264a632bc3c7a88536e","impliedFormat":1},{"version":"cdb367e8b328b7c33a483e8d873b7d727f1533006143ec764b18afa2f002df0e","impliedFormat":1},{"version":"3380a3a9745d50cfff0eb9b14b29fa53c512fc21edd722038b2b3750c3de5d49","impliedFormat":1},{"version":"04b38bd5c3a8cfa11a8c418198ff45a87ef5079fcec00577666a9084c532213f","impliedFormat":1},{"version":"1bc1a937ecf83eab91791ea1cb9f854a49b377486102c5a0700392180eb8d70c","impliedFormat":1},{"version":"648f208d31b0513be0dbd8bd74b13eace512ddedb90d5c0b5167468c60413155","impliedFormat":1},{"version":"3ff72f7c6a6e0eb7e2f7c7d85d468bc367d23dc31be14842058a43d9d5dbd7af","impliedFormat":1},{"version":"d7d178b403d4cceb8dab81bd54dce348c7ac71ddb6547872a654c977247cf55f","impliedFormat":1},{"version":"8184db9ab7c212b6b661911f541699441abc1575be7426067853775592afbba4","impliedFormat":1},{"version":"27411cedae3a9dab5d54fa2e146d4fa6641eec0e52ade3da41c2d5bbdb119ae7","impliedFormat":1},{"version":"749228ac4274380c46cd574eac41cb6293b82030331f5c3eedac18c6bc2ab454","impliedFormat":1},{"version":"4b01b705c53e7f94311f758f2bbbe210859e6648d05fbb7998ecfd314370d4ff","impliedFormat":1},{"version":"333ea75ad88bd423fe08637296c912376d66969889916b19bfbeb89db2242407","impliedFormat":1},{"version":"3043b1bdf9d2e6b0aff6422a48f745f997eb57e43d3d42a5c6cf0848b2d794e0","impliedFormat":1},{"version":"a51b48204b2b924d47a60986e67c58b0caa7d73232c85f9e1c03a7ca636252de","impliedFormat":1},{"version":"3e4895172c2cbef8c2e54cd7fd96fb6c9922206d1388bf560f0fb8846ba88cd2","impliedFormat":1},{"version":"8bb9bdf953d0902b2328f89702c75097e1973e762dd8beebe80cd06a17a06017","impliedFormat":1},{"version":"b193927418aaf1e64b777157fe9ab79e5016875bcdf0ab28d2d2497c7e50b790","impliedFormat":1},{"version":"40fee0202063d1e93c0a07ab7c29a899183cd94a3fe260bba96ce49229969bf9","impliedFormat":1},{"version":"1b3b911468ce081d23979c6b3e818a3e66710a10c5656c8325075daf80ed1836","impliedFormat":1},{"version":"f01d0b70becee655497c184ec6e9f3f3e18cd15e7023c99c5c9388759dd66f7c","impliedFormat":1},{"version":"bf416cce4b8398cee52ed29e0f9c19690cce69278b945ea581378444058cfb53","impliedFormat":1},{"version":"367d3b4740e0648822a05ef5f4c7ce4a3cc9a562e24bf9463a6b523eb6031450","impliedFormat":1},{"version":"4b5e59098f037efedc336519d3fba3cb8083f5f792f1f0a2647f7b935de64877","impliedFormat":1},{"version":"d8beee6bff3a8294f7b923f6cf4a9cb5960bbb056ce48a0224f306053843648b","impliedFormat":1},{"version":"034c49f905a96eb8b576e6fe58f2c4883ff116603104bddc4bef0cf677eea7a8","impliedFormat":1},{"version":"d710349fdd281add4186ea89c121d66871f6c1799bb0e07e4da3244dba6b882c","impliedFormat":1},{"version":"03f6a000b6e4c295c4d565f855e3564df4e5ed5b242662893db9bade66520c72","impliedFormat":1},{"version":"f73f050e9065586cbc65c9b7fff8ef8eb97723fbd6d322b0fc13ee5f769de64e","impliedFormat":1},{"version":"aba45966aad51b62a211cf9dfb02d3bd30caaf2658321f0bf8724969ad794159","impliedFormat":1},{"version":"5c0eed6de692e5e46c09e83d08f16260963d649d1d60b01f574dfff43439a3a5","impliedFormat":1},{"version":"6a0563f249132eb9d2814cb120178ce9f23aafc915be71c97c121b168a7ec7ad","impliedFormat":1},{"version":"3f020db3efe0e85d4e394d7bffb2fab07b48f655cf5b981bedaff9178686a2cb","impliedFormat":1},{"version":"ccd7b69f26d5386d353f8c6e8a3fedca002ad07f475c9b30c4f11c2c3cc91679","impliedFormat":1},{"version":"ff70f47858b8d1fbe708cc14148464cddd0d6fb26b4078f45b2124b00d074560","impliedFormat":1},{"version":"49aa7ba1a6cd0cb6280bf1a78f0e3824ac5f5338bd8539b03ce1c8b26b693365","impliedFormat":1},{"version":"6c1deb9edcfb88c059aaa921929a6001e76239b65ce4191c2408c97d7322507a","impliedFormat":1},{"version":"ea8f1dbf77a0fa264342bff4d05ddb7ff7233540a84902e778495629dc1e0d72","impliedFormat":1},{"version":"f7b7a801993c12f9c4b2988fab4f7ec8b9123ccac2a2c433cbc1c6967abf3c4e","impliedFormat":1},{"version":"4d19f4e188ed7803e4733f44df1b969bf505dec6e7b6ccca4d9d101010f18446","impliedFormat":1},{"version":"6ce824bde7db1c3aaa70dfc072f6df22dd7c7852e1ec2fd8f10eff241d4ed484","impliedFormat":1},{"version":"43fb8e1045a5c42e76f1f95b50be3f1785c443fa1491394b319c4c55472658c4","impliedFormat":1},{"version":"6305b31d824411ad37256bdd409fd1ba0baad53e1f8f39bdfacf872b8a8a4f40","impliedFormat":1},{"version":"b245be05ea541bec1e4781feb43b47c851b9afd1036d5bba26663b0d2663d8ac","impliedFormat":1},{"version":"87db13f1becd33a3a23d50d2d4c80cab60a0b3f60f665043336b735501776707","impliedFormat":1},{"version":"8123d8f03cec556699a59a77d4472c13699c2ef77ee0c8ec43025acfffbfc2d9","impliedFormat":1},{"version":"f1b3f3d87fafd3a954d3c96e8f18be3bdb4903e8763dab8fa5824bcbf97d5a67","impliedFormat":1},{"version":"6f47739df2f8ed1528125dccb83dd1e1652a42f8b4592c0eb374862ed06fa438","impliedFormat":1},{"version":"aa77f41ec84aaf5adacfe4d6bd9b9f92630ada00a45700eca2a8b99e3c70c37b","impliedFormat":1},{"version":"3efa30630b397ff35c3b0dbbaba3761d2fd64aaae56ec1955d9cca59dd729f50","impliedFormat":1},{"version":"653590f7eb4941023bd6ca18c82d039ef6fdafb22c2bd6be172f113d7ffa2eb7","impliedFormat":1},{"version":"1398b43f50e28f5c57a73de6872d1c2f6c3a8f14f5a3591602385fe2d45f7f75","impliedFormat":1},{"version":"90a63041286c2b389329f2f7a9e12a1306a2d88dd2ae72bc36414a32182d22cb","impliedFormat":1},{"version":"08c1e69c030edc00b69aa924e33c5cd87064f1dbcb37ed23c3586945f3d5571b","impliedFormat":1},{"version":"2b9afe7454ec9f90de8d10790b1ded42f73589d53dd4040586801672c3e67fc6","impliedFormat":1},{"version":"9cb0615322ba0e12a9407dfda9958c899e942a24e1436d30e9b155fbe74857d1","impliedFormat":1},{"version":"a0cbc0c547c5dda3ed62de00d50df9132497280ce52305481f51d095c7e5c5f9","impliedFormat":1},{"version":"3cb9dc5a818a284140abede0a8fa6838184ad269ab7354cd80b1b84f00198293","impliedFormat":1},{"version":"735e25c92a3f5304d5b65d2c2b2aac1b0c9c407af9446e56f9017a111a56dfd2","impliedFormat":1},{"version":"8f1f74963197b427fe6512ba801b2e972a3037337635f49687b9b373fc00ee17","impliedFormat":1},{"version":"a00efec77b1a42338caa2b33b32ee33f566569dcbf998fd2a02b8e486d7723c7","impliedFormat":1},{"version":"72d4e5acf88da2251d8ab1c34f813c0e45a79eaf6c937666ef56942b8d7b200f","impliedFormat":1},{"version":"da568aed744774edd93a3bd5c25e732b78acfef83f79f1b1a1d4ec436cac97ce","impliedFormat":1},{"version":"9a45ac908610cb735a515517233e2bf06397e12a904cd88aaad541ae102ed467","impliedFormat":1},{"version":"d6e3e204d67cd62afe566ee54629b8ba40f649d81e9105e7062c11f28d8bb0a3","impliedFormat":1},{"version":"470d9033dfbd29b7f480a151c3e0a6235c085cf74df6444e7cd25ba623c1d0db","impliedFormat":1},{"version":"e103459e88e9a95f1cba5003182c88dc3e6ccb6162232c33755da96659b25c21","impliedFormat":1},{"version":"ebe3a8a7e1aadb529070c345b2f18775542a67abdacf80e8b367ca1cbd754584","impliedFormat":1},{"version":"c01bcebf1d775113fbe692ed5237c29527de9bcfb1cbbffd568a90664f749170","impliedFormat":1},{"version":"278a88af3bdddbf7cc7eab607de3f4f91ef905e21695f16c78d9f1878d3e5638","impliedFormat":1},{"version":"8a0721d211f480ccae97f8eb9786e6e408c8c859d7bac2d39b858d1a507574c0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebde9ed796bd0ffa6df0a0cbf5f9e0ba575d2049f11a9f5642b1321e32535a21","impliedFormat":1},{"version":"cd14bccf6439de8f3170f678b1d4989ae3c18a709657e48ab92bd16b13655c3b","signature":"e3399effdcfcb19fbf10356bad53a632f4d975d54322e6b2bdc5d7074fc049d3"},{"version":"105aa92d1b0275177c5f954cabea264715859f6f13d392458eaec9710bfc6846","signature":"a618d8ce1dfa16b905ea03e63dfc8aaa88a4cf17417532dbc16b1af891926eb5"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"31ca1cb803d4961fbdc683535d35f2e08dac2bdded0f2eda7e9a1e3b97bb6286","signature":"d88e0d8ba2e99eef1233b152c00bd0a5f3560f21843fc185db08cf6b572e5770"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"76022067f28f6cef2238c1db9b3365331bc63e6a722f5d6a4049e08bee4a8728","signature":"bda6ce7797ec2815a4da67c80a12bf05f933ea08783420bec3c9d68d1785444e"},{"version":"d6b8f6e44d4e3e2c4133b12b05b06a42935319cfeaa05328218525d7aae039dc","signature":"55206b710b854a59363078374ca44b29ef666665090d708f9829b116837fd34f"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"96702141df8658f192ed9ac72b21ff4f197ec2d73e04754bcb6aba2b94a83da9","signature":"791a8a6b2bff7c4dbb24a639587b1daf3291117d062cee6c3692e79cc9fbbf9d"},{"version":"8ceb92ea34823905682c0c27ff0c4b7bb99affbcbc976501f3b9f8ad78d87822","signature":"f8aae2890d61bc88251433668b2b57ad8ba3a49ceeb947d8bdbbc19a5c751649"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"b54e0feb683893a68b23b681f25bde8a9d800d0dca9e46b9452d11121d392328","signature":"eda69f1276cdd081f002458f2ecbb92da7a0292537c56b266f8c7b5dd0eab784"},{"version":"9e790989224eac05234eb7e01db0f82a62391cf842486d7d43d9491b617da510","signature":"27bbb77a4afaae56c74d43fa04120c30fd2f8dc27cf56122a26001725d22b9de"},{"version":"c8063edd5e289a023a07c3f71c3c346928484db2e7f819bd75ae7ff3e2fdfc32","signature":"999903506e61a5b259c34712be36590b96ec8375ea51361aeea159691728231d"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"3c7a05f2fbbb4aea030442940e4741668462fb991443467e58dbb5431e849f33","signature":"5c67a659b3c9148c849b47ef70dc3c0e61ab6c82eb6d8d5315ac67e85cdd04ba"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"4951925f6e298a6bdfde57c519e5d7f0a490896e6260276e7e9e1bbec3eb0bcb","signature":"525d83794a6e30134971eceb67c7fd1e60245aeb6850fe8d4ac2f5e94a164c78"},{"version":"841d964f34cfbc56a5a9c6e4bcc5ba2d20a82070ad38225956073c4934a53ed5","signature":"fe23f4b686e191a57f63331b1016a7c543e2f86cd96e678d9034ffa71f777ba3"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"7d474265a4fbe75d10af729593f2960de7edee5bfd1c5d6706c05c6ef154a39f","signature":"6af176444deba56bdf5e2440eec91b4c190d0942132d782e1e4af52e926efd1f"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"8a72c9da8b95e8343a6f16a65e6e3ee7c6ea8ca8a53123bf6bcead92d2d95e88","signature":"ef8634682715ac7a581efbcbf3656c5f07e4405a138bc222c98c40a073483281"},{"version":"14f3b951550cc376673897b55068eda7a4bbb817b4d7527083f6dd6a3133f051","signature":"55bb18d80ab4836734d6b6075750b673bec340bcaed10fed842407a1fdeb3657"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"4940a27c518427c56d10e2a1094fa688cbee7973de244bf08933a52402926f41","signature":"453e6e89124e33a3dcb5003b9f624594eb18efe0d0addcfd8393c830c2f6a9e1"},{"version":"23433e9ad6a837b0591d9956c0358f8da3775e592b708767ddf33e6db18382e8","signature":"d3f0ac692da385d451807d5612a1ef735657ae42b89180bcf21fae7b57f7a4f5"},{"version":"a53d8bf50034149a8d8b171377d40bfa2cb72535f30894af63a4429355332c76","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"8d1af2b325f39658cc8f0fb1371eeb1a9cd9ccec1df629a25e23cff813e45269","signature":"843eb8044483afd59ac9923676eadf3981e1dcf76b2fc3224c9e68c838a51e16","affectsGlobalScope":true}],"root":[[66,68],275,278,279,[281,297],[416,450]],"options":{"composite":false,"declaration":false,"declarationMap":false,"experimentalDecorators":true,"importHelpers":true,"inlineSourceMap":false,"inlineSources":false,"module":200,"noEmitOnError":false,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noPropertyAccessFromIndexSignature":true,"outDir":"../../../..","removeComments":false,"skipLibCheck":true,"strict":true,"target":9,"tsBuildInfoFile":"./.tsbuildinfo"},"referencedMap":[[268,1],[273,2],[270,3],[272,4],[267,4],[264,5],[71,6],[263,7],[261,8],[266,9],[280,10],[271,11],[274,12],[277,13],[276,14],[414,15],[415,16],[298,17],[299,17],[300,17],[301,17],[302,17],[303,17],[304,17],[305,17],[306,17],[307,17],[308,17],[309,17],[310,17],[311,17],[312,17],[313,17],[314,17],[315,17],[316,17],[317,17],[318,17],[319,17],[320,17],[321,17],[322,17],[323,17],[324,17],[325,17],[326,17],[327,17],[328,17],[329,17],[330,17],[331,17],[332,17],[333,17],[334,17],[335,17],[336,17],[337,17],[338,17],[339,17],[340,17],[341,17],[342,17],[343,17],[344,17],[345,17],[346,17],[347,17],[348,17],[350,17],[349,17],[351,17],[352,17],[353,17],[354,17],[355,17],[356,17],[357,17],[358,17],[359,17],[360,17],[361,17],[362,17],[363,17],[364,17],[365,17],[366,17],[367,17],[368,17],[369,17],[370,17],[371,17],[372,17],[373,17],[374,17],[375,17],[376,17],[377,17],[378,17],[379,17],[380,17],[381,17],[382,17],[383,17],[384,17],[385,17],[386,17],[387,17],[388,17],[389,17],[390,17],[391,17],[392,17],[393,17],[394,17],[395,17],[396,17],[397,17],[398,17],[399,17],[400,17],[401,17],[402,17],[403,17],[404,17],[405,17],[406,17],[407,17],[408,17],[409,17],[410,17],[411,17],[412,17],[260,18],[211,19],[209,19],[259,20],[224,21],[223,21],[124,22],[75,23],[231,22],[232,22],[234,24],[235,22],[236,25],[135,26],[237,22],[208,22],[238,22],[239,27],[240,22],[241,21],[242,28],[243,22],[244,22],[245,22],[246,22],[247,21],[248,22],[249,22],[250,22],[251,22],[252,29],[253,22],[254,22],[255,22],[256,22],[257,22],[74,20],[77,25],[78,25],[79,25],[80,25],[81,25],[82,25],[83,25],[84,22],[86,30],[87,25],[85,25],[88,25],[89,25],[90,25],[91,25],[92,25],[93,25],[94,22],[95,25],[96,25],[97,25],[98,25],[99,25],[100,22],[101,25],[102,25],[103,25],[104,25],[105,25],[106,25],[107,22],[109,31],[108,25],[110,25],[111,25],[112,25],[113,25],[114,29],[115,22],[116,22],[130,32],[118,33],[119,25],[120,25],[121,22],[122,25],[123,25],[125,34],[126,25],[127,25],[128,25],[129,25],[131,25],[132,25],[133,25],[134,25],[136,35],[137,25],[138,25],[139,25],[140,22],[141,25],[142,36],[143,36],[144,36],[145,22],[146,25],[147,25],[148,25],[153,25],[149,25],[150,22],[151,25],[152,22],[154,25],[155,25],[156,25],[157,25],[158,25],[159,25],[160,22],[161,25],[162,25],[163,25],[164,25],[165,25],[166,25],[167,25],[168,25],[169,25],[170,25],[171,25],[172,25],[173,25],[174,25],[175,25],[176,25],[177,37],[178,25],[179,25],[180,25],[181,25],[182,25],[183,25],[184,22],[185,22],[186,22],[187,22],[188,22],[189,25],[190,25],[191,25],[192,25],[210,38],[258,22],[195,39],[194,40],[218,41],[217,42],[213,43],[212,42],[214,44],[203,45],[201,46],[216,47],[215,44],[204,48],[117,49],[73,50],[72,25],[199,51],[200,52],[198,53],[196,25],[205,54],[76,55],[222,21],[220,56],[193,57],[206,58],[65,59],[275,60],[443,61],[441,60],[442,62],[444,60],[278,60],[438,63],[447,64],[421,60],[422,65],[420,60],[423,66],[445,60],[446,67],[424,60],[433,68],[429,60],[430,60],[431,69],[432,70],[425,60],[426,60],[427,71],[428,72],[297,60],[416,73],[418,60],[419,74],[293,60],[296,75],[292,60],[294,60],[295,76],[417,77],[434,60],[435,78],[436,60],[437,79],[288,60],[289,60],[290,80],[291,81],[279,60],[283,60],[284,82],[287,83],[449,60],[450,84],[439,60],[440,85],[285,60],[286,86],[281,60],[282,87],[66,60],[67,88],[68,60],[448,89]],"semanticDiagnosticsPerFile":[1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,66,68,275,278,279,281,283,285,288,289,292,293,294,297,418,420,421,424,425,426,429,430,434,436,439,441,444,445,449],"affectedFilesPendingEmit":[275,443,441,442,444,278,438,447,421,422,420,423,445,446,424,433,429,430,431,432,425,426,427,428,297,416,418,419,293,296,292,294,295,417,434,435,436,437,288,289,290,291,279,283,284,287,449,450,439,440,285,286,281,282,66,67,68,448],"version":"5.9.2"} \ No newline at end of file +{"fileNames":["../../../../node_modules/typescript/lib/lib.es5.d.ts","../../../../node_modules/typescript/lib/lib.es2015.d.ts","../../../../node_modules/typescript/lib/lib.es2016.d.ts","../../../../node_modules/typescript/lib/lib.es2017.d.ts","../../../../node_modules/typescript/lib/lib.es2018.d.ts","../../../../node_modules/typescript/lib/lib.es2019.d.ts","../../../../node_modules/typescript/lib/lib.es2020.d.ts","../../../../node_modules/typescript/lib/lib.es2021.d.ts","../../../../node_modules/typescript/lib/lib.es2022.d.ts","../../../../node_modules/typescript/lib/lib.dom.d.ts","../../../../node_modules/typescript/lib/lib.dom.iterable.d.ts","../../../../node_modules/typescript/lib/lib.dom.asynciterable.d.ts","../../../../node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../../../node_modules/typescript/lib/lib.scripthost.d.ts","../../../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../../node_modules/typescript/lib/lib.decorators.d.ts","../../../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../../../node_modules/typescript/lib/lib.es2022.full.d.ts","../../../../node_modules/tslib/tslib.d.ts","../../../../node_modules/tslib/modules/index.d.ts","../../../../src/environments.ngtypecheck.ts","../../../../src/environments.ts","../../../../src/main.ngtypecheck.ts","../../../../node_modules/@angular/core/graph.d.d.ts","../../../../node_modules/@angular/core/event_dispatcher.d.d.ts","../../../../node_modules/@angular/core/chrome_dev_tools_performance.d.d.ts","../../../../node_modules/rxjs/dist/types/internal/subscription.d.ts","../../../../node_modules/rxjs/dist/types/internal/subscriber.d.ts","../../../../node_modules/rxjs/dist/types/internal/operator.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable.d.ts","../../../../node_modules/rxjs/dist/types/internal/types.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/audit.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/audittime.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/buffer.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/buffercount.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/buffertime.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/buffertoggle.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/bufferwhen.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/catcherror.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/combinelatestall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/combineall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/combinelatest.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/combinelatestwith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/concat.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/concatall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/concatmap.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/concatmapto.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/concatwith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/connect.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/count.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/debounce.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/debouncetime.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/defaultifempty.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/delay.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/delaywhen.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/dematerialize.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/distinct.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/distinctuntilchanged.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/distinctuntilkeychanged.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/elementat.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/endwith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/every.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/exhaustall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/exhaust.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/exhaustmap.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/expand.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/filter.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/finalize.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/find.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/findindex.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/first.d.ts","../../../../node_modules/rxjs/dist/types/internal/subject.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/groupby.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/ignoreelements.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/isempty.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/last.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/map.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/mapto.d.ts","../../../../node_modules/rxjs/dist/types/internal/notification.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/materialize.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/max.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/merge.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/mergeall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/mergemap.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/flatmap.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/mergemapto.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/mergescan.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/mergewith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/min.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/connectableobservable.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/multicast.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/observeon.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/onerrorresumenextwith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/pairwise.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/partition.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/pluck.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/publish.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/publishbehavior.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/publishlast.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/publishreplay.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/race.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/racewith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/reduce.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/repeat.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/repeatwhen.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/retry.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/retrywhen.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/refcount.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/sample.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/sampletime.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/scan.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/sequenceequal.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/share.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/sharereplay.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/single.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/skip.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/skiplast.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/skipuntil.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/skipwhile.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/startwith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/subscribeon.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/switchall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/switchmap.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/switchmapto.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/switchscan.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/take.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/takelast.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/takeuntil.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/takewhile.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/tap.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/throttle.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/throttletime.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/throwifempty.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/timeinterval.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/timeout.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/timeoutwith.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/timestamp.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/toarray.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/window.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/windowcount.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/windowtime.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/windowtoggle.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/windowwhen.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/withlatestfrom.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/zip.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/zipall.d.ts","../../../../node_modules/rxjs/dist/types/internal/operators/zipwith.d.ts","../../../../node_modules/rxjs/dist/types/operators/index.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/action.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler.d.ts","../../../../node_modules/rxjs/dist/types/internal/testing/testmessage.d.ts","../../../../node_modules/rxjs/dist/types/internal/testing/subscriptionlog.d.ts","../../../../node_modules/rxjs/dist/types/internal/testing/subscriptionloggable.d.ts","../../../../node_modules/rxjs/dist/types/internal/testing/coldobservable.d.ts","../../../../node_modules/rxjs/dist/types/internal/testing/hotobservable.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/asyncscheduler.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/timerhandle.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/asyncaction.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/virtualtimescheduler.d.ts","../../../../node_modules/rxjs/dist/types/internal/testing/testscheduler.d.ts","../../../../node_modules/rxjs/dist/types/testing/index.d.ts","../../../../node_modules/rxjs/dist/types/internal/symbol/observable.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/dom/animationframes.d.ts","../../../../node_modules/rxjs/dist/types/internal/behaviorsubject.d.ts","../../../../node_modules/rxjs/dist/types/internal/replaysubject.d.ts","../../../../node_modules/rxjs/dist/types/internal/asyncsubject.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/asapscheduler.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/asap.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/async.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/queuescheduler.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/queue.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/animationframescheduler.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduler/animationframe.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/identity.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/pipe.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/noop.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/isobservable.d.ts","../../../../node_modules/rxjs/dist/types/internal/lastvaluefrom.d.ts","../../../../node_modules/rxjs/dist/types/internal/firstvaluefrom.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/argumentoutofrangeerror.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/emptyerror.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/notfounderror.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/objectunsubscribederror.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/sequenceerror.d.ts","../../../../node_modules/rxjs/dist/types/internal/util/unsubscriptionerror.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/bindcallback.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/bindnodecallback.d.ts","../../../../node_modules/rxjs/dist/types/internal/anycatcher.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/combinelatest.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/concat.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/connectable.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/defer.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/empty.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/forkjoin.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/from.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/fromevent.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/fromeventpattern.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/generate.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/iif.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/interval.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/merge.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/never.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/of.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/onerrorresumenext.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/pairs.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/partition.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/race.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/range.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/throwerror.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/timer.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/using.d.ts","../../../../node_modules/rxjs/dist/types/internal/observable/zip.d.ts","../../../../node_modules/rxjs/dist/types/internal/scheduled/scheduled.d.ts","../../../../node_modules/rxjs/dist/types/internal/config.d.ts","../../../../node_modules/rxjs/dist/types/index.d.ts","../../../../node_modules/@angular/core/effect.d.d.ts","../../../../node_modules/@angular/core/primitives/di/index.d.ts","../../../../node_modules/@angular/core/discovery.d.d.ts","../../../../node_modules/@angular/core/api.d.d.ts","../../../../node_modules/@angular/core/weak_ref.d.d.ts","../../../../node_modules/@angular/core/index.d.ts","../../../../node_modules/@angular/common/platform_location.d.d.ts","../../../../node_modules/@angular/common/common_module.d.d.ts","../../../../node_modules/@angular/common/xhr.d.d.ts","../../../../node_modules/@angular/common/index.d.ts","../../../../node_modules/@angular/platform-browser/browser.d.d.ts","../../../../node_modules/@angular/common/module.d.d.ts","../../../../node_modules/@angular/common/http/index.d.ts","../../../../node_modules/@angular/platform-browser/index.d.ts","../../../../src/app/app.config.ngtypecheck.ts","../../../../node_modules/@angular/router/router_module.d.d.ts","../../../../node_modules/@angular/router/index.d.ts","../../../../src/app/app.routes.ngtypecheck.ts","../../../../src/app/pages/presets/presets.ngtypecheck.ts","../../../../node_modules/@angular/forms/index.d.ts","../../../../src/app/services/toast.ngtypecheck.ts","../../../../src/app/services/toast.ts","../../../../src/app/pages/presets/presets.service.ngtypecheck.ts","../../../../src/app/pages/presets/presets.service.ts","../../../../src/app/services/logging.service.ngtypecheck.ts","../../../../src/app/services/logging.service.ts","../../../../src/app/pages/presets/presets.ts","../../../../src/app/pages/logs/logs.ngtypecheck.ts","../../../../src/app/pages/logs/logs.service.ngtypecheck.ts","../../../../src/app/pages/logs/logs.service.ts","../../../../src/app/pages/logs/logs.ts","../../../../src/app/pages/dashboard/dashboard.ngtypecheck.ts","../../../../src/app/pages/dashboard/dashboard-dryers/dashboard-dryers.ngtypecheck.ts","../../../../src/app/pages/dashboard/dashboard.service.ngtypecheck.ts","../../../../src/app/pages/dashboard/dashboard.service.ts","../../../../src/app/pages/dashboard/dashboard-dryers/dashboard-dryers.ts","../../../../src/app/pages/dashboard/dashboard-charts/dashboard-charts.ngtypecheck.ts","../../../../node_modules/highcharts/options/abands.d.ts","../../../../node_modules/highcharts/options/ad.d.ts","../../../../node_modules/highcharts/options/ao.d.ts","../../../../node_modules/highcharts/options/apo.d.ts","../../../../node_modules/highcharts/options/arcdiagram.d.ts","../../../../node_modules/highcharts/options/area.d.ts","../../../../node_modules/highcharts/options/arearange.d.ts","../../../../node_modules/highcharts/options/areaspline.d.ts","../../../../node_modules/highcharts/options/areasplinerange.d.ts","../../../../node_modules/highcharts/options/aroon.d.ts","../../../../node_modules/highcharts/options/aroonoscillator.d.ts","../../../../node_modules/highcharts/options/atr.d.ts","../../../../node_modules/highcharts/options/bar.d.ts","../../../../node_modules/highcharts/options/bb.d.ts","../../../../node_modules/highcharts/options/bellcurve.d.ts","../../../../node_modules/highcharts/options/boxplot.d.ts","../../../../node_modules/highcharts/options/bubble.d.ts","../../../../node_modules/highcharts/options/bullet.d.ts","../../../../node_modules/highcharts/options/candlestick.d.ts","../../../../node_modules/highcharts/options/cci.d.ts","../../../../node_modules/highcharts/options/chaikin.d.ts","../../../../node_modules/highcharts/options/cmf.d.ts","../../../../node_modules/highcharts/options/cmo.d.ts","../../../../node_modules/highcharts/options/column.d.ts","../../../../node_modules/highcharts/options/columnpyramid.d.ts","../../../../node_modules/highcharts/options/columnrange.d.ts","../../../../node_modules/highcharts/options/cylinder.d.ts","../../../../node_modules/highcharts/options/dema.d.ts","../../../../node_modules/highcharts/options/dependencywheel.d.ts","../../../../node_modules/highcharts/options/disparityindex.d.ts","../../../../node_modules/highcharts/options/dmi.d.ts","../../../../node_modules/highcharts/options/dpo.d.ts","../../../../node_modules/highcharts/options/dumbbell.d.ts","../../../../node_modules/highcharts/options/ema.d.ts","../../../../node_modules/highcharts/options/errorbar.d.ts","../../../../node_modules/highcharts/options/flags.d.ts","../../../../node_modules/highcharts/options/flowmap.d.ts","../../../../node_modules/highcharts/options/funnel.d.ts","../../../../node_modules/highcharts/options/gantt.d.ts","../../../../node_modules/highcharts/options/gauge.d.ts","../../../../node_modules/highcharts/options/geoheatmap.d.ts","../../../../node_modules/highcharts/options/heatmap.d.ts","../../../../node_modules/highcharts/options/heikinashi.d.ts","../../../../node_modules/highcharts/options/histogram.d.ts","../../../../node_modules/highcharts/options/hlc.d.ts","../../../../node_modules/highcharts/options/hollowcandlestick.d.ts","../../../../node_modules/highcharts/options/ikh.d.ts","../../../../node_modules/highcharts/options/item.d.ts","../../../../node_modules/highcharts/options/keltnerchannels.d.ts","../../../../node_modules/highcharts/options/klinger.d.ts","../../../../node_modules/highcharts/options/line.d.ts","../../../../node_modules/highcharts/options/linearregressionangle.d.ts","../../../../node_modules/highcharts/options/linearregression.d.ts","../../../../node_modules/highcharts/options/linearregressionintercept.d.ts","../../../../node_modules/highcharts/options/linearregressionslope.d.ts","../../../../node_modules/highcharts/options/lollipop.d.ts","../../../../node_modules/highcharts/options/macd.d.ts","../../../../node_modules/highcharts/options/map.d.ts","../../../../node_modules/highcharts/options/mapbubble.d.ts","../../../../node_modules/highcharts/options/mapline.d.ts","../../../../node_modules/highcharts/options/mappoint.d.ts","../../../../node_modules/highcharts/options/mfi.d.ts","../../../../node_modules/highcharts/options/momentum.d.ts","../../../../node_modules/highcharts/options/natr.d.ts","../../../../node_modules/highcharts/options/networkgraph.d.ts","../../../../node_modules/highcharts/options/obv.d.ts","../../../../node_modules/highcharts/options/ohlc.d.ts","../../../../node_modules/highcharts/options/organization.d.ts","../../../../node_modules/highcharts/options/packedbubble.d.ts","../../../../node_modules/highcharts/options/pareto.d.ts","../../../../node_modules/highcharts/options/pc.d.ts","../../../../node_modules/highcharts/options/pictorial.d.ts","../../../../node_modules/highcharts/options/pie.d.ts","../../../../node_modules/highcharts/options/pivotpoints.d.ts","../../../../node_modules/highcharts/options/pointandfigure.d.ts","../../../../node_modules/highcharts/options/polygon.d.ts","../../../../node_modules/highcharts/options/ppo.d.ts","../../../../node_modules/highcharts/options/priceenvelopes.d.ts","../../../../node_modules/highcharts/options/psar.d.ts","../../../../node_modules/highcharts/options/pyramid.d.ts","../../../../node_modules/highcharts/options/renko.d.ts","../../../../node_modules/highcharts/options/roc.d.ts","../../../../node_modules/highcharts/options/rsi.d.ts","../../../../node_modules/highcharts/options/sankey.d.ts","../../../../node_modules/highcharts/options/scatter.d.ts","../../../../node_modules/highcharts/options/series.d.ts","../../../../node_modules/highcharts/options/slowstochastic.d.ts","../../../../node_modules/highcharts/options/sma.d.ts","../../../../node_modules/highcharts/options/solidgauge.d.ts","../../../../node_modules/highcharts/options/spline.d.ts","../../../../node_modules/highcharts/options/stochastic.d.ts","../../../../node_modules/highcharts/options/streamgraph.d.ts","../../../../node_modules/highcharts/options/sunburst.d.ts","../../../../node_modules/highcharts/options/supertrend.d.ts","../../../../node_modules/highcharts/options/tema.d.ts","../../../../node_modules/highcharts/options/tiledwebmap.d.ts","../../../../node_modules/highcharts/options/tilemap.d.ts","../../../../node_modules/highcharts/options/timeline.d.ts","../../../../node_modules/highcharts/options/treegraph.d.ts","../../../../node_modules/highcharts/options/treemap.d.ts","../../../../node_modules/highcharts/options/trendline.d.ts","../../../../node_modules/highcharts/options/trix.d.ts","../../../../node_modules/highcharts/options/variablepie.d.ts","../../../../node_modules/highcharts/options/variwide.d.ts","../../../../node_modules/highcharts/options/vbp.d.ts","../../../../node_modules/highcharts/options/vector.d.ts","../../../../node_modules/highcharts/options/venn.d.ts","../../../../node_modules/highcharts/options/vwap.d.ts","../../../../node_modules/highcharts/options/waterfall.d.ts","../../../../node_modules/highcharts/options/williamsr.d.ts","../../../../node_modules/highcharts/options/windbarb.d.ts","../../../../node_modules/highcharts/options/wma.d.ts","../../../../node_modules/highcharts/options/wordcloud.d.ts","../../../../node_modules/highcharts/options/xrange.d.ts","../../../../node_modules/highcharts/options/zigzag.d.ts","../../../../node_modules/highcharts/globals.d.ts","../../../../node_modules/highcharts/highcharts.d.ts","../../../../node_modules/highcharts/modules/boost.d.ts","../../../../src/app/pages/dashboard/dashboard-charts/dashboard-charts.ts","../../../../src/app/pages/dashboard/dashboard.ts","../../../../src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.ngtypecheck.ts","../../../../src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.ts","../../../../src/app/common-ui/layout/layout.ngtypecheck.ts","../../../../src/app/common-ui/header/header.ngtypecheck.ts","../../../../src/app/common-ui/header/header.ts","../../../../src/app/common-ui/layout/layout.ts","../../../../src/app/pages/configs/configs.ngtypecheck.ts","../../../../src/app/pages/configs/moonraker-config/moonraker-config.ngtypecheck.ts","../../../../src/app/pages/configs/moonraker-config/moonraker-config.service.ngtypecheck.ts","../../../../src/app/pages/configs/moonraker-config/moonraker-config.service.ts","../../../../src/app/pages/configs/moonraker-config/moonraker-config.ts","../../../../src/app/pages/configs/dryer-config/dryer-config.ngtypecheck.ts","../../../../src/app/pages/configs/dryer-config/dryer-config.service.ngtypecheck.ts","../../../../src/app/pages/configs/dryer-config/dryer-config.service.ts","../../../../src/app/pages/configs/dryer-config/dryer-config.ts","../../../../src/app/pages/configs/configs.ts","../../../../src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.ngtypecheck.ts","../../../../src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.ts","../../../../src/app/pages/embed/dryer-control-embed/dryer-control-embed.ngtypecheck.ts","../../../../src/app/pages/embed/dryer-control-embed/dryer-control-embed.ts","../../../../src/app/app.routes.ts","../../../../src/app/services/global-error-handler.ngtypecheck.ts","../../../../src/app/services/global-error-handler.ts","../../../../src/app/app.initializer.ngtypecheck.ts","../../../../src/app/app.initializer.ts","../../../../src/app/app.config.ts","../../../../src/app/app.ngtypecheck.ts","../../../../src/app/common-ui/toast/toast.ngtypecheck.ts","../../../../src/app/common-ui/toast/toast.ts","../../../../src/app/app.ts","../../../../src/main.ts","../../../../src/app/services/config.service.ngtypecheck.ts","../../../../src/app/services/config.service.ts"],"fileIdsList":[[260,266,267],[260,266,269,272],[260,266,267,268,269],[266],[71],[69,70],[69,70,71,260,261,262],[69],[69,70,71,260,261,262,263,264,265],[260,266],[266,270],[266,270,271,273],[260,266,270,274,276],[260,266,270],[298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413],[298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415],[298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,414,415],[72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,88,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,128,129,130,131,132,133,134,135,136,137,138,139,141,142,143,144,145,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,191,192,193,195,204,206,207,208,209,210,211,213,214,216,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259],[117],[73,76],[75],[75,76],[72,73,74,76],[73,75,76,233],[76],[72,75,117],[75,76,233],[75,241],[73,75,76],[85],[108],[129],[75,76,117],[76,124],[75,76,117,135],[75,76,135],[76,176],[76,117],[72,76,194],[72,76,195],[217],[201,203],[212],[201],[72,76,194,201,202],[194,195,203],[215],[72,76,201,202,203],[74,75,76],[72,76],[73,75,195,196,197,198],[117,195,196,197,198],[195,197],[75,196,197,199,200,204],[72,75],[76,219],[77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,118,119,120,121,122,123,125,126,127,128,129,130,131,132,133,134,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192],[205],[64],[65],[65,266,273,275,277,438,440,442],[65,441],[65,277,278,287,291,417,419,423,433,435,437],[65,266,273,277,444,446],[65,266,277,421],[65,266,277,420,422],[65,266,270,282,445],[65,266,424,428,432],[65,67,260,266,273,430],[65,266,270,273,280,282,286,429,431],[65,67,260,266,273,426],[65,266,270,280,282,286,425,427],[65,260,266,270,280,286,295,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,414,415],[65,260,266,270,274,277,280,282,286,295,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,414,415,418],[65,266,270,277,280,282,286,293,295],[65,67,260,266,286,294],[65,266,292,295,296,416],[65,260,266,270,277,286,295,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,414,415,434],[65,260,266,270,277,282,286,295,436],[65,260,266,282,286,289],[65,67,266,270,274,280,286,288,290],[65,67,260,266,273,283],[65,266,270,273,279,280,282,284,286],[65,266,449],[65,266,286,439],[65,266,285],[65,266,281],[65,66],[65,68,274,443,447]],"fileInfos":[{"version":"94716a6063cac9426b59da38cd5a8299ed337972715c3b933f46288ad7d1de37","affectsGlobalScope":true,"impliedFormat":1},{"version":"97fda9a66baf7f1644a76c27160698be6bc5da3cddb7109d0f12d4c7def0f353","impliedFormat":1},{"version":"6ae308f5abdd675b08bd2b3d6b78018b08a148a1d84f8dea19a6794e5653eca9","impliedFormat":1},{"version":"5a174a590b47d8dab224a6e8b798d2033deb15423bd519258e9beb9401c1d08a","impliedFormat":1},{"version":"070a92b6c7b3061a032d072e87b845b9cdbc8692ba83c54ad73c5ac72a06e7f3","impliedFormat":1},{"version":"a914c8e64e5f910f90cd2e64d1b822a5ef0578862ead57520bcb67f895417b51","impliedFormat":1},{"version":"34fe0fa41bd124512ead7c3d91f2a74293d01ed81056932711c4a09c38f3be66","impliedFormat":1},{"version":"b37ee4d946ad2f6e52cb0ff9571966c6302be51032ba3ea97870bee115b9eacd","impliedFormat":1},{"version":"2f6e6fee948d386ccd3614b7dd1c53ad53424898f7f62bae60c0de87df9d9417","impliedFormat":1},{"version":"943cd359b1e074ea340c364e7c14a1878ac9aef3f1fc1b2a8080d3938042d4f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"eea76ce47dd717e742356873e38f89ce9007cdbe69c9ac1a5e0c8ba1123e2102","affectsGlobalScope":true,"impliedFormat":1},{"version":"c72fe06c11f813667237b6349eed2e242d3636a36e5693c1ad1c2aa33f1ca325","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d65581abfea69586274544cc81e7ae4103f1345650f8a206a66c9da336d73b0","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c11a33d4e5e3948f92c83b1a01cec02a102429466186da3576d49d1e4d2babb","affectsGlobalScope":true,"impliedFormat":1},{"version":"6666becd625655c6662a29a744786dffbf6d66c28f068f5137760ff419ac8adc","affectsGlobalScope":true,"impliedFormat":1},{"version":"345afca9429c9143e0016cdeee715a9bf39c55a2ff46954fe0c9d5764feaf895","affectsGlobalScope":true,"impliedFormat":1},{"version":"408ca1d716d3df0961a473392d55ef872a3e1ce6de4fb8dc7fd6001fba6a1c4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc3ed3562e3c791f2e74ecd3819d15ef58fd3b47939de9853db5dd808253b00f","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac6a91d78291f82d060a24001518a9f5f2a94324722df8c159691c08d39c6bf5","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ce0fcc6c7dc07b2a97cf3bdd4f3df2fdd7056e93acc52de8d15ced40c603602","affectsGlobalScope":true,"impliedFormat":1},{"version":"999e86d04e508d25e374dc1cf37aa4f7f733ad93a8076b20203b3028c7398fc3","affectsGlobalScope":true,"impliedFormat":1},{"version":"c1f9879f76b5409ceaad951b084533d8abc39451a72d6ec55dcc5b9e5f098309","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebfe68159fcc055c880a17b5d5a219dfafc662b48c1cd32a7d3eecc74a1efc70","affectsGlobalScope":true,"impliedFormat":1},{"version":"ee7bdffdbb8462f9973063563f8822e6e2b3b7ce05d4651e4879d00f1479899f","affectsGlobalScope":true,"impliedFormat":1},{"version":"9b0111e0b9c98b0bc610bdeb1486f14c60e8c08852552f692d57becf2fe42ea7","affectsGlobalScope":true,"impliedFormat":1},{"version":"6338d9121d2f1b5cf1c757c65949fc41e1e9e5300dc4105d55f8c27ebfcd5fe2","affectsGlobalScope":true,"impliedFormat":1},{"version":"e6a8f68eed8ff0386d27d17e4a162c21923e3b8c41f3353a9ad6ecfdd7cf2ddb","affectsGlobalScope":true,"impliedFormat":1},{"version":"4e9dccd4588b6a893b02963b1f00ade1b2cc244164cdb3ebb857e3c913d2f921","affectsGlobalScope":true,"impliedFormat":1},{"version":"7c4ffd61b251abb1c37ea129e861a12f462727c7fb8ef0989e582d9ea1c1d375","affectsGlobalScope":true,"impliedFormat":1},{"version":"c4ce7db6ecc881e6f3e0f446d17f18d29acdf703e66ff0df6cf0c6471a83a481","affectsGlobalScope":true,"impliedFormat":1},{"version":"9fe84185f18c70ba5e1a4bcc634b7144c525a7e045c204b60d358e4314d452e9","affectsGlobalScope":true,"impliedFormat":1},{"version":"84d43d8bf818f0a82dd57ac3cfb33ab8706a7d5b6978684342c0e3d17a4a7bc2","affectsGlobalScope":true,"impliedFormat":1},{"version":"45678430c8312f11ed1e429b1cd7d139a7adec4310598bc4c8ed6c2ff975ee4c","affectsGlobalScope":true,"impliedFormat":1},{"version":"d5b7aaa53a6c14f4239fb8c2625513d8573946a110bb88a355c0ba10d781d7d9","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3c08438c9c085e92b48a464b34c0ec0da55ff6459411cf6f02619043b5f474","affectsGlobalScope":true,"impliedFormat":1},{"version":"5b460121cb8201504e9becddb2e3dda74fa2561d14de92f452fed81ad794f2bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"03f5b59a2d05a77266490ec195365773e2947c6022962fd8104e0d23941b0648","affectsGlobalScope":true,"impliedFormat":1},{"version":"8283b753d7dd802450c38f8cd841dd0b1a0b246f9ab429e9b7fa5d8157fc2897","affectsGlobalScope":true,"impliedFormat":1},{"version":"7455bf53aacdd935681c5b701af026368e9eefd34f043605c514d1cce9d5bc7a","affectsGlobalScope":true,"impliedFormat":1},{"version":"9b7b68b72b0727055f8f823a766b888c1dc21aa7f0038e0190168967916eec28","affectsGlobalScope":true,"impliedFormat":1},{"version":"5503f40f563cb65c20d01ba44486450a837786393944ddd2e85e3a4fbaf8c205","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b312bc67316c027e88130f2fc3192eddcb714ce22b20e048c7cd3c878ffbf02","affectsGlobalScope":true,"impliedFormat":1},{"version":"692900ca89d92745df9fb1c425c73c4646fbb32d0806ac52eb6bd7bd234434fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"0069bee860a9c2ffbd29738234c7e72d849358355833913160ef46df10214e0f","affectsGlobalScope":true,"impliedFormat":1},{"version":"2a3f88bcd76a6b4b017a3d90e3e9500ef608ab110c6b0a692307a4fe71ba9e5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0089f4c24a96d79ea2f6d96cb475df1d63a8a129a0bf41a86f3ba00a4d566752","affectsGlobalScope":true,"impliedFormat":1},{"version":"820bd08ba14d07b36701dd25cbc54e0a21b3ea531c5d8f269d2db9046736a47b","affectsGlobalScope":true,"impliedFormat":1},{"version":"bb4ab2aceef0699b248072fd6459072c398049dc45d5e55ff0c2e51abc537820","affectsGlobalScope":true,"impliedFormat":1},{"version":"1b0048315f80cd412b02bd819ce0dfc0b5d682acc02da1d78037a8fc60b95260","affectsGlobalScope":true,"impliedFormat":1},{"version":"535c56a8849d541e0d1ed96ab68ea1742fb46a96d11dfd2b23843d3426ced988","affectsGlobalScope":true,"impliedFormat":1},{"version":"d1e388e9b1bcd2d29af3a6a6fe1627a25944bd3210f05c45f42e77acb7992a68","affectsGlobalScope":true,"impliedFormat":1},{"version":"562732440ea01ab3e998713ca4acf1041d07ba6857ee35bf874dcfa02033bffc","affectsGlobalScope":true,"impliedFormat":1},{"version":"0172bf6476c793a7ade0388f4e5d4fac45acf0d9f7958c40c893dfe7ca84b45f","affectsGlobalScope":true,"impliedFormat":1},{"version":"6ed037605cb3740c89ec8c3eaf21eafb20c56c64784f3d4eb9df506ce6417a6a","affectsGlobalScope":true,"impliedFormat":1},{"version":"4da1991bdb0fbcf81fb73e8af5d41e52decf2555a0b878d3493f5957bf47f079","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4c05910fafb3e62d1d7b03b2d6b5247ec7e50cc3c7e036716748fe3ed3f3531","affectsGlobalScope":true,"impliedFormat":1},{"version":"fd69d5107f90cd266ee098661a45946d7005832ef13381cedb04a8fc51093dcb","affectsGlobalScope":true,"impliedFormat":1},{"version":"a425d6c16c4d990f501c7bd399bdc7437cc73e1344b26594ce5e34dca1f88e10","affectsGlobalScope":true,"impliedFormat":1},{"version":"a37d801def41ad25cf62fc6808979546e71cb7a8212e3deda6bb2a373107bae3","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e5b3b6af88552d9589d69a52f41d0ceaaf0ecd8c159119fb9491a1b580a85f4","affectsGlobalScope":true,"impliedFormat":1},{"version":"4033c51052514a6c3e4564f22671fb7a1cc6aa7746943c2dbf7fb5aa60bb37e5","affectsGlobalScope":true,"impliedFormat":1},{"version":"b333b85aa74c3b92988940ab51d50c533c93e2bb0d78be2b5e9e948e76fece0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"4efaf900b38773fe2bd43b8af5a8b1114e9f857f0392682a68eaa2f4cf304217","impliedFormat":1},{"version":"a6a5253138c5432c68a1510c70fe78a644fe2e632111ba778e1978010d6edfec","impliedFormat":1},{"version":"9fb65d6c07733d72601985e1816141503d35f9b28488081cae5ae6a2864fbdbb","impliedFormat":99},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"f6f5822adc099090277082e3fe23bf1472d583d3eaa111b0d5cb9de25e026b16","signature":"27c30ba3d87fc6dd1f2f2a03111df5fe60638d5c6599213c02abdcb6e319270c"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"865aa0bbc9e488804b9cf53c12731233ef912d5f7a982bdb3e8d57204cbe050e","impliedFormat":99},{"version":"1f014232ccf15dfa70fef06df24f60f5210a0cae7274e68d9bcc645f024beb61","affectsGlobalScope":true,"impliedFormat":99},{"version":"c9069a4bf73de04db12e6a24be3ee3e13d4e0dfff5ed7c2c7f05b65f523bfab6","affectsGlobalScope":true,"impliedFormat":99},{"version":"1493c3eaf5af8e17c30a566f819c8fd51ea5e28b9701a7e638088fd6e532cb32","impliedFormat":1},{"version":"bbb9a2955c63192ed9106b322a307604c129e822a4ca922281d71b343c3b18c2","impliedFormat":1},{"version":"92cc7a3e17ef5d44f21cc3a25b1dc92f396ae77ac0049e4761f6d60e3269734f","impliedFormat":1},{"version":"4743d9f47dc30e93a9826dd2a342f63a00f3dc7bf4622d15e37d49bfd58e5bc5","impliedFormat":1},{"version":"404848c0b4345315b816d92bed640f7411ddd6b417596dcbd5df00f84d2943f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"0bfafe42767c045fa74210f3f93f42e3fa49b7a1fc4afa2382f9e3304bb89ccc","impliedFormat":1},{"version":"1f915f761eba3da5439ce15769ca22b435e7699160204bef775c2b78531a169c","impliedFormat":1},{"version":"07203713bbe9a638d4fc11895432f6ad8d13391fe4d4dcf12cb7d5d49ce2303d","impliedFormat":1},{"version":"e910acfee92e27859da5aeaadf07a76e189be8ab53d4783121efae63a1aff784","impliedFormat":1},{"version":"0c3de5c67592cd888a0eacb079c153751c05eb4eeb284d0a837be9ccd8782f19","impliedFormat":1},{"version":"1a955a0c4968b1df660c2136d788935776373e1c35ed386a7c9a4838c4cd1ecd","impliedFormat":1},{"version":"97317c0b2d9b90ebb9e0cc8fc30b5d286d581c83d0da16a160ded95c9ebdfa83","impliedFormat":1},{"version":"199f601640f125bf79573c17dd46361bafd4d0f995355afee979feef9b485967","impliedFormat":1},{"version":"4f856fda5803fe14a5f675d844437262a2321873ffe6b5b28f434ab3cd98c2e2","impliedFormat":1},{"version":"34a136c5fb572104624bdd5ca5051e7bd9a99c5c827f4d0cda0cb913fd9c63ed","impliedFormat":1},{"version":"8b1c38f1ad05371ca9da3b91366ba01391163487bc4004d678c2d78b7a7fb141","impliedFormat":1},{"version":"2346514a7f68d5be7daf65c3ab50e3ce7ea5828d439fc9dcdc7e3b21704d937e","impliedFormat":1},{"version":"8087f9490ac0bdaa8fe1821f8f2f7a66e239a26ec7a551fb2ff54aef36fa4810","impliedFormat":1},{"version":"3e59b4bfa62961dcd97d3c9bf579cc2f28b6dc2a4c17301e376d5a9f49b5b0b1","impliedFormat":1},{"version":"a1b7e3ad56479c74ebc615dd6dc72e7765e724f12ca8193af73a5320e56f710b","impliedFormat":1},{"version":"c4e4533d2892e5e882472b3ac14780d8d3d1a53a4464cf29aa71f63363ac6dd5","impliedFormat":1},{"version":"185679e7529529e66151a933d3546b0bd5935ebe9479c9d7e61b2a07c9263604","impliedFormat":1},{"version":"f943b91ae555f7310436b46e9bac14308b67df9618fa62d35efa1ed8bb79ea89","impliedFormat":1},{"version":"1b7bd5218e3b282dae675aa6d0be16b52fc2a82c1c3a55b58ff0e501234f05cc","impliedFormat":1},{"version":"9ab4c54973bc8a473b9a3da90b809d3071dc240287f17efa3b8a2d8def3aeb06","impliedFormat":1},{"version":"f45ce325b374417545115afb67c1e7a756a92ecce150a06824b86e0a6ca47706","impliedFormat":1},{"version":"d6d85b6961c7a8df0429dfec54e1d9976678e545fad661fe756b0cedf4aea544","impliedFormat":1},{"version":"904487dac11bf3a2f1c50246d50a3806fe147cda65a3868e711351a461b753e0","impliedFormat":1},{"version":"8a44c8aa5e0212efa9c0f8c2e2ffd034e911195c314a4c8d5846a872ddc97e63","impliedFormat":1},{"version":"b0f8a3e3b4bd666b93e0d9eb2d2b9539c0b5146e07c5fbe81e0fd9e1a56125d0","impliedFormat":1},{"version":"30ed7d9231f86e5ccc644ac7ffc6bc11caf6b3d9bbcd80ca0e4485ec4540f0a1","impliedFormat":1},{"version":"6c46b5172c65163cf65de721fff40c6dfcfb1d9fcdbd87a5ef9412b1abb8d4e5","impliedFormat":1},{"version":"1a4ad0b2a98fe67fb9e28df1a01f57a9c149838866ebb7e196a5b30f5b549b9a","impliedFormat":1},{"version":"3821e6b582b8b54bab0f624cc31e7425b1a1fcb1e3768aab0da55a3223ae83a1","impliedFormat":1},{"version":"6e9a977f8448b31f4b828e6ae8452a4f491a88afed6b92789600dc0972f56173","impliedFormat":1},{"version":"1c00c1150136b0996026b30c96ff509089b1098e86cf1eff9e3c23dbfa5c662b","impliedFormat":1},{"version":"4a1952149f3622a31734e6fabba2eb7e0aa94b01649d5d3dbb95faad3c6321e2","impliedFormat":1},{"version":"c223ca9542ad121fd582699bc4faca95afa46c71955ae56a2343a147846c4efc","impliedFormat":1},{"version":"a040fd513007d4955027d5a233dbb654f71ab46ab70c84d0d049fb4f53078101","impliedFormat":1},{"version":"fcc8b6f055d4eaed7f11b28d3f8dbd1d54396a354589c02605fff9fc2c16c274","impliedFormat":1},{"version":"69bf15663215f21aabe309cd4ede6b3ed7590ef4fde7c2ae5117a31978e359e3","impliedFormat":1},{"version":"b490395d5ea6a723d9d6a0028eba988ae16a59de482cfbf72411ac78b48424fc","impliedFormat":1},{"version":"4842ef2ff91ae856244623877738198e19f8d160337632b98508be788f59c031","impliedFormat":1},{"version":"a34be37eaef02d2d14779c2816f51bc26ee9f88c61d686b01a18d182b58d4812","impliedFormat":1},{"version":"1a715ed850ab3eaa76ee51309e996b7f96d17668817fa0d6a0fd99c25a0de8ef","impliedFormat":1},{"version":"e6a21dcebcbec4b1c6d6a90232676f270f8196167ef585558862bf604a6d6573","impliedFormat":1},{"version":"6b533b83efe999ec22904040615d3fa4d0d3599168949c1f05d5229adca10b33","impliedFormat":1},{"version":"f7b0d6a704e1abd68d344aee0cea3cb40266b4e6337474ce935482f2d26bc1d7","impliedFormat":1},{"version":"08665a0ec37cc8f79cc8a3f51a57685a983973b76651f47b0b04654ebfe1837f","impliedFormat":1},{"version":"821e02b86c41d06f374def3e6f7b89426951496cb381fc7e4437e1cec48bdfa9","impliedFormat":1},{"version":"966748c05b6fb548f03d41984399fa83500b5d06f7703fb4fb29856e03f62edb","impliedFormat":1},{"version":"20d63781d1056264d11d37057adb3cc6e95198f458a2c67f56efb8505e5ec1ad","impliedFormat":1},{"version":"07917b286c389afe937437a9383401829744599b14a681f409ad5d2837624ca9","impliedFormat":1},{"version":"50a2cd2ef62ccb86e2ba4d6c92147233da2340cdf6e1992b5fd0b35f1e945484","impliedFormat":1},{"version":"1f6ca37d2f71e6ce3d7703564a08fc121d34bbd5c75885df7c21c4e197c9ae0c","impliedFormat":1},{"version":"c2dae7c8810ec085307050640583bcf21b457c5763be87cb89447a5932513370","impliedFormat":1},{"version":"c549b7a5e56f5aeb79611ecde27d907a6dae4f6a80129a6e977968f43b2256ce","impliedFormat":1},{"version":"c0cf28f8d2b6f3399b3e7ca2f56998b947729614bd4f611c392b430be613d773","impliedFormat":1},{"version":"79048db5ba922ac904ff75cd8e283907f68ea47ce9a912f178c6aa3b007fbd7d","impliedFormat":1},{"version":"9c7d04e6f98fbd761fbaabe71591b36dbd53ac44c1cfc362ffa981b988be8725","impliedFormat":1},{"version":"614aba2f6213babb42e3c5ee200282ac6c66389066b1325287398579c7cc52c8","impliedFormat":1},{"version":"a12479cc337380b3a79fbeee319eb1d643bf57d234c6567a642fc1b5fb920a4a","impliedFormat":1},{"version":"af7145e387ff0e01e8a4875c67a170b04475a34b81317e3ad801f866f67fdf1d","impliedFormat":1},{"version":"42e21275c1baea771151c1f921ff38c5747f0261548915b023629ea456ada0e2","impliedFormat":1},{"version":"344a475c6703c0c7703fe83c721f6919ff918fb9e967d0362d3028f7bf7e0c32","impliedFormat":1},{"version":"25f5ac5f22edbea71a079803bd87f1dc323034cdbdc678898f18e1fedf3589a7","impliedFormat":1},{"version":"a4f5772da7b4c7c2225e6389fc4a4fe6ea356cb1e7d8c0a57e0afec83532ee3e","impliedFormat":1},{"version":"41f2cd991bf23126d5aeed9bc65e5ce2846168456bfe2d796a180e3dc9c8b068","impliedFormat":1},{"version":"4d9d715e262069f700a17663429d79e0b5ca2adf306d84b1fd0fddc1b8eeeb42","impliedFormat":1},{"version":"4fd435c4ddda5c923944e1b9c0bf1e7facb136c71e8253e37a627ff990347091","impliedFormat":1},{"version":"376f904b5439dd8dfcfa9f46e0785ed1a84fdcdf8dd102c4404cd1bb286ad110","impliedFormat":1},{"version":"5f80a436f4d302833f9bdc0471b495f40eb6c0273dc99337e053d1f637ddde82","impliedFormat":1},{"version":"b219f281ec13b4139f926f72900eedfd2b6bee5022ea50813a50ec25bf23d78c","impliedFormat":1},{"version":"afeedff5d41717e21bc8a7db3cf1e88d4c52ea9b602b5e6c9ac6376739e09b32","impliedFormat":1},{"version":"8ae6f06728175da554c055379108df7f6a6e87fc9a2c83e0789388e34d988ae5","impliedFormat":1},{"version":"05a5fae6ea4c69bc084b28561a9ea0e05ac79bbe2653753d65cebd3060aa2234","impliedFormat":1},{"version":"a68604c49bcac0578a76a5ec112027f7cd65c9e36b61a89b674a7a4e6d541c31","impliedFormat":1},{"version":"3129120392cc49620e2a2cc6923944f401fd7fbb8d5354efa725923f42a49752","impliedFormat":1},{"version":"5c251fd52f86fbf574d5e86afe410c1667e0bc547fbd9050ac0f2b2137e51998","impliedFormat":1},{"version":"ecc40d44eb097db337baf61aa909576eb59efabf49b298ee31089a7033938296","impliedFormat":1},{"version":"543681c6340482eb9d23611bdc462c31e51491ed202108a24800e9cbe62f01c9","impliedFormat":1},{"version":"37be8cdbc8e1567b1b23dca22a6167529b47eef9c1eeb6441973eb6caf0cef92","impliedFormat":1},{"version":"7a003085cee18c68f4e8a10bd984dc3f7a94eadc9d9ebc0be16eba972bac3aac","impliedFormat":1},{"version":"d3064e5eda936a0dc90b63f38b1343f9ac8a9f3d840bfbf92472c806c4c352ca","impliedFormat":1},{"version":"ea629eb9e08b5fe6c2d15d7040a10bc789d771e35fe9c3c86f2256c80efd0ae3","impliedFormat":1},{"version":"367f68f3a5a904c70719f8aa9d98a5440254c097aec898c77fd98b120b930aa1","impliedFormat":1},{"version":"6c0a7118d466f9afa75091aaeae3f36333470b679586c380a53e05392a395141","impliedFormat":1},{"version":"7e147e53926f4af25d29a5299323afa6da3e74718336529f86a8ce199e009727","impliedFormat":1},{"version":"0b53d30d952f92c1629e35e5fcd8caa5a5178e3c1720db71575e4354c8b292f5","impliedFormat":1},{"version":"91c4bb90cb6d8ee2194a09df44fd16bc441e71bf4a8023f66b3d6ac8f7b45e93","impliedFormat":1},{"version":"49183f4cdd8d7beb7b2457de3a6a7970c1c181ede9b1deb45364f489ef910d70","impliedFormat":1},{"version":"18f6a72615f9c6609761d373674227c95ad4f35dcadb2b018f0d985a77bbf627","impliedFormat":1},{"version":"030c158bd1dceb6acf1e44a8fb18665ba2382031183ab1aa1672b77d209a54f7","impliedFormat":1},{"version":"3ea889e2bf2b8b87f56640a3379becbba846404b7bd3ccb734e8dc2bc2195b7e","impliedFormat":1},{"version":"cfbd32c1dbe59c371d5798757ef44bbaa22dd68169f3f32c40f6f0e5f7ee5c29","impliedFormat":1},{"version":"7ffb4b87407053225e6f0f8fc5967bf9196f72b07006d79d53cacc16a99ba9e1","impliedFormat":1},{"version":"b40c98a600de2187f0a29696eff159c4615fc000761ead257d09dd8ab42e06ee","impliedFormat":1},{"version":"9a1f04530d69bddb5e245faead591c615519ce48c685a85d0cc7768ade384899","impliedFormat":1},{"version":"2163aba020fdf216a4c8801ff5e54bf7e58ae27a59a5b3d40ee528e4cf38bb40","impliedFormat":1},{"version":"c16a678061cc08d56d612935951d07c8a2215d93f2ad5989cef4dab77b1b12a6","impliedFormat":1},{"version":"1119a290d75174b65870309a4501d271900f76f02eb94dd4c9fb2455b2001d80","impliedFormat":1},{"version":"a6ae11110eff3b3288ed231e07cfe96b822e59e9a3da0462936a247909d22832","impliedFormat":1},{"version":"712ce28a408079645d596222d38708f491708bf79cbf60061b36de2dcb36f835","impliedFormat":1},{"version":"e15f6c847c82af7675f90f27e0e7c51029f1a402cd41df8cb76eb023b4b428d5","impliedFormat":1},{"version":"47aea4438d5c7af5c2868616c950bea43380e082a9082261f0ebdad2785faf75","impliedFormat":1},{"version":"ef1a2887863355b5b1181dcd8eac49c6c4e6fde2d80613ca4d83a1850e54890f","impliedFormat":1},{"version":"213183e1446951a6bfb55867c4cbdf612373b0f294c67356a02c3af2b221dad7","impliedFormat":1},{"version":"e3f6e6790d7bfd43189080e3908b993c47c4019ff48150395b673fec6699d149","impliedFormat":1},{"version":"653b2aceaba9cb2c241c687fbd1674211af956e14b9138d5b3813a4a15f9d6ea","impliedFormat":1},{"version":"7a37d37e2eb260740328df7f71da088048204b6f7a062092c6ff18a8361824d1","impliedFormat":1},{"version":"2d6062c344457ce10b74e2903c126e8c56d9cf626e95a5ecaaa90dfb6f4bc3ca","impliedFormat":1},{"version":"29351e8a7008d9510a2aa9b15733c1b1d02d5cf722a7ad74a0ab14ea4074fa2a","impliedFormat":1},{"version":"9cced96bcf7e90524ebc3e582b0cb79d9fb1a2b84df24ec272659a5ad4566706","impliedFormat":1},{"version":"92a3b0674f35953601751d430ae0edf45ae8d6e84ed27991486e1d222885fb8a","impliedFormat":1},{"version":"a7bbadb81ae63b0a953cd6f45b6a5bbb3450bda5d96d6eb436cf94dbd299a309","impliedFormat":1},{"version":"bc2c7f65888e1811fb76d7a46c4b2c83c0d86ac88d9be5a16343907fc14e0000","impliedFormat":1},{"version":"e46ed48eec643cc98b2b86522172e64395fad05445dab7e8febc4f45b53bc750","impliedFormat":1},{"version":"0b0b5a511a22238465ef38e4b98fc1455fd7d8a935e326f36a80fcfca40accbf","impliedFormat":1},{"version":"e927d547036ae8c3a03feb9c9d830b76b09ed0fe0c5ab70ad4f4ab9bd6327d1d","impliedFormat":1},{"version":"f13ba01cd83422d2ee521bde2d47eb61f2c23f54c4d04abefd0699b4d2346364","impliedFormat":1},{"version":"1846a10ab60c4a3e5d13fc9004d12b473bb590b0026c5ead7c2abc53aa7e0f56","impliedFormat":1},{"version":"839878e587bfa3d7645628a0b5d2e7d50e769ea0cabaa797ad64bf219ce40ab6","impliedFormat":1},{"version":"7dc6d80b032b4ac676a78735e04842a3ead6d65f2a5d4422581d4c694f432e71","impliedFormat":1},{"version":"dda44d95bf4743e9df1680d9ad466fb3a860dec08a54328964fa62132e4ec8b9","impliedFormat":1},{"version":"cbd78174fece32405f8eae97d37023d1b8c778068f598be997d6ac27893ae16d","impliedFormat":1},{"version":"6361c4cb51ec7d3d1a93d58eb4db082b57b900859d8682f28c570cd28de4ce07","impliedFormat":1},{"version":"da721c3919e18dab97eea18ac7ae15810ba0ed5269d292084b0f6ae43027e9f5","impliedFormat":1},{"version":"67577d877394a22ae5e9ed91add2d56e9d63bdbf0615c7f21a191e5ea708fd67","impliedFormat":1},{"version":"c48997cab85dad5b18119d7ae9e38b5dfac9d00b077b64e8d3f3684c5167c730","impliedFormat":1},{"version":"a2fbec1da1d2f34ec10ca6c8c01a199ab29102f6c3a9d528e80bb698e159c9bb","impliedFormat":1},{"version":"e58be6b62b31517b190186886d58225167539c0c6ba7e01641c02a2b167e6ddd","impliedFormat":1},{"version":"aeb7e9bdf4e31d3a29e92163c0ad99b6a4b28832247a1b73fea11067594ff5f1","impliedFormat":1},{"version":"0338f0d6e43bfe73bacf4d06bb04c6d96804c9799778604e654df64d4bab0e67","impliedFormat":1},{"version":"ce391fc6ae75503349c5d5538a729af1b1c8269e1d7bc54087651b018abfa081","impliedFormat":1},{"version":"4b7093ad677aab39d40aab7bac68ae97055d7b7bdb080209ee1c59c364a657cc","impliedFormat":1},{"version":"adb0eb48ada06b160b8a3aba6e72c979d4dde0ab96a553cf2fce262624bf394a","impliedFormat":1},{"version":"a637725c54a65ae32a68a28956ee5765b18e6239be4c88fc6ebf6741653cebed","impliedFormat":1},{"version":"7f3c0ee4bfcbe6ae9c7068cafc8850700ed9a888dbda89201d3d2d1bdd79a341","impliedFormat":1},{"version":"387c1c0bf86392903ebc8a32fd9b0f14d10e423a448f9aa05779405758908789","impliedFormat":1},{"version":"d19d9729edb0ed0a7ab8836a9f02e387cf5e85ec512d50021d2f8b56ddd7e348","impliedFormat":1},{"version":"bdc79b9bc3157f80d2696b5b23857b8f6285d69c3a0c206dc566e899a4faf792","impliedFormat":1},{"version":"bf25beb89ab958d34ba12b7d69076fe5f7d2e6f9f806cfec83a5bf70a853f98d","impliedFormat":1},{"version":"2e3c1b3d4b7556f029d135c58f7c50d84c6e922078a7677ebad64342e2591901","impliedFormat":1},{"version":"2ac37e6b83e3eb57f4e85f4ee9a6d87063d9eae0003269d15b6fc40ae6ca36b5","impliedFormat":1},{"version":"60570cc7ba076c23add06ead21fa72d1fd19c3e1b5a7766d4f82d7a309408139","impliedFormat":1},{"version":"99d23001a6eabf92d3aca206e9f28a2098da8e7ea4b32331cf1486b77099f482","impliedFormat":1},{"version":"43e848f969f7ad403d28749df3d46003eff3c98068b08bb18575556c7465fc21","impliedFormat":1},{"version":"f6d24615b5bef821976cb510db19ba15c12691b0191d7dcd0d9f6dc94764e75f","impliedFormat":1},{"version":"b828b5b866e01a20acfc791fec82efeb3a20a00cb508a8f61dd490b81a6003ed","impliedFormat":1},{"version":"4938db21214f998f41dd8d87982520f2155d803118bdca866e12785727507a73","impliedFormat":1},{"version":"de42b2bf19e510030a2572ed1884c4ab8c20db3e1e1969bfc6922193022699d6","impliedFormat":1},{"version":"187c9b65dc21e5e382415af52e3554d92494dc2b8060b6336fdf346ddc6184e0","impliedFormat":1},{"version":"4830bb822d461c5835d2b887f202b537b79cd5e365132da6611f67d307b824f4","impliedFormat":1},{"version":"a61f02064732a2ab23d322d9d8b9911d4c3685b86763a4d7ac1cda0fccd908ba","impliedFormat":1},{"version":"12abcc499df35e46c8fe1a614985645d09ce291d065083b6a95d2db31e31f1a9","impliedFormat":1},{"version":"b988dfb6db3545cc4a04ede9ee705c2c6779539952b8376b1ff90be3a4f74c4f","impliedFormat":1},{"version":"b3eaa7485622714ca8202766ad83484ac2403dbd4b56ed8789885b34be212bdd","impliedFormat":1},{"version":"26575c20f5749d53b4cd3893a707f3ad33f4a64a52c0c33416c3bd2f4243f7b1","impliedFormat":1},{"version":"fabbce92b2a45449d475810443ccd31ecf84f6c40674bf2a1513b86191a6bc3b","impliedFormat":1},{"version":"942ea7301220f5ca0a8b860f653dc6e8c9a42bc833392743fa0b2f2d49e13dfe","impliedFormat":1},{"version":"489dd22803fbb50f0676f65b414c1f1aaf038531b2575b4620eb4d0121947c7c","impliedFormat":1},{"version":"cbb1f813e11e2e0ebf6fbbfe11a66f5b8460e9af2e28cd1942d5ee5c6880a68c","impliedFormat":1},{"version":"00e801f4ad5ab37a22957acfe1e8deaea7f26990d39958fd49aae877949b679b","impliedFormat":1},{"version":"438af48c270447200a64aa2fa062c49a9b1e21bcdf1e6a79255848b13be60cfe","impliedFormat":1},{"version":"a9cf7e480caae93ee23070d81d0c85d3b612e26164c0dd96d5a69224432bf58b","impliedFormat":1},{"version":"f12dcbd0c3b88af16fff1b7c1d94fa7c7654d0df346e66e4d1a0c3a951cea026","impliedFormat":1},{"version":"50ac137becc59e676ab806f6548752fee9e061fa24cb94a869e1aee3ee3fe90d","impliedFormat":1},{"version":"5c138ee7068df5cae9db7c2562c73aa375567e116ec79593059195da2d01e6a6","impliedFormat":1},{"version":"0b4aa74c3cb6e64d7e93043f2ac08dfe1666774a924ff11133afe8fea92a7fe2","impliedFormat":1},{"version":"ac5ed6e44d3e276d6cd3791c0df588f19426a9f67a982ac380020ae858d982f5","impliedFormat":1},{"version":"6603ff43e2263755205079eeddb7607c150bad30e03a013c264ebaf4b79a35e1","impliedFormat":1},{"version":"77d286a5f29e29f6650837c8fd4fc77fb95234eac45ba543193c430812a9cc80","impliedFormat":1},{"version":"dd440ba4b5284fe6dd246c133b46e836e81309698a64eddb9fe608a9ca1cd051","impliedFormat":1},{"version":"6bd12d912af22e33f5755ff9c8c1e84201a6d9114e34d3bb6b0bdab0446cabef","impliedFormat":1},{"version":"d90684bfece77ac3e6d557f264ccc311186cb0877d4ab160f2c6e6e49d3b1ea1","impliedFormat":1},{"version":"39cc5ede3ab0213e333de67aa5860443bcd9cf53041ecdd5fe017285a054daf6","impliedFormat":1},{"version":"dc3f1db6b5365a9d60b76628d1635af1711a1e201a840a749cdd9bc073fbf2dc","impliedFormat":1},{"version":"5f18ef110553e1d69ee80b3b92cd7502dd2f26c6b092e4e3202c3a1c5336bbff","impliedFormat":1},{"version":"deed8885863add75e54dbaea097240f1fcdb8657ceeb342804167cc6c097d896","impliedFormat":1},{"version":"3ba670ceb39995847b90ef75256380e11a71ea72e698cc0ecf9df5282c8531d6","impliedFormat":1},{"version":"f6d19e26f405f05200ff73732d23f5b2b50e211d031abf328fc790884e4d1337","impliedFormat":1},{"version":"69508fcc170f5385914f6fde119fede5294b3d4402966dd262b229c94dc6b157","impliedFormat":1},{"version":"7b6239c431103ae44bcdbc8ecd85a58552345228d3a3380a99cfc5c3d49dd888","impliedFormat":1},{"version":"27e395faa7f7af921e104f5b9fc203ce26438c284413cd4a3a17797a1f523155","impliedFormat":1},{"version":"4284d200969ecedd970a284145ae5a4acf800059812eff9daaa83b676e9aa3c1","impliedFormat":1},{"version":"d6ec50c346e16574749e0284290d72226662914803b2c55ff42d0d1b0ae1bb28","impliedFormat":1},{"version":"4142ea9148909c7654644f97e743a9258c0095775385f4640f41a5a183bd1aae","impliedFormat":1},{"version":"aae67ca278fa75518ce62e0167dccdb8f66fb686bfc411a862c7bc15c8f5b753","impliedFormat":1},{"version":"f43ede2fe612f7af64a9e7b73a579eac2ad738fd23c94c180edd221720d1ac80","impliedFormat":1},{"version":"1e26b5f87bde13285f6f8edbca7c792214109a5a640bba156a46ecf0d57d735d","impliedFormat":99},{"version":"c340eada2b6d952b634af5648440a81d8f441e7a09c50f62b734a8d3600302cb","impliedFormat":99},{"version":"9e0d37cd4dbdcc3b1090c99e1187498cab9be5a8c73011ca19c79d7057568257","impliedFormat":99},{"version":"e9e15edd6c80ae41f9841ed7a5cfbe39a926af1c60dd8329ebf6846c78e69078","impliedFormat":99},{"version":"bb28f7603db016eeade3b21f4a7f80f149056ee5ad34321f7d59b41cceca6840","impliedFormat":99},{"version":"10c0c3523eb4342b1fb83551d084c5a9bc61f76dab08526222fb88a6a2baab0a","impliedFormat":99},{"version":"d37aeaa924fc052051f32002151436595f87d61f2e6438a225005eacddc4e7a6","impliedFormat":99},{"version":"88f325706ac03bcbbbd098e9db4f97006b390c4ff4576ca6ec6b95c95dcda2a8","impliedFormat":99},{"version":"aa5d8433f00cb073c36a915f1fa6a9742edbcd25d8097f3823141ce417321902","impliedFormat":99},{"version":"f0da9960c94bb3d56c3cbc1763d89ab2acabc4bdd22ae53292e1053b846b4690","impliedFormat":99},{"version":"002c9486c088eed3b31825d9f7fb8857542faf691ee01c59a3273b4ede328de7","impliedFormat":99},{"version":"2ab31151a6f9e3cc2c113cd7c50eebcde3d5bd8bb310c3b2c9bffdbb75150051","impliedFormat":99},{"version":"954c927fb0b5e739ddd9b78bbb87c741848596747a548a770e4d79abc97333e9","impliedFormat":99},{"version":"6ae9065d5d6c3988c265f93c5d54cb5955ba5c8986cba24b503790efe90be721","impliedFormat":99},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"87a87778968c619ccd148d444162699bb81c3112a95043108f74c139a93426a4","impliedFormat":99},{"version":"700705321fffd3a19d70bb3c861c2b107ca7aa091b634ec0e3412cf93dcfa414","impliedFormat":99},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"edc450b70efb377bcba5e7d3771098d4fe1ff5ab017fdb0d76e212f309dcc00a","impliedFormat":99},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"e34a2741735a829416584b82fdfd6a4eff8f03a1896ab32988748fb6ef9b17d8","signature":"7d9cf4757530ff5b7e7eda07f4a46dedfa7cfb7f9ef52bd9dea3cd2270f0975d"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"01ea0a8470b52d59c9561a1ec6dee988a5e422706f082e819cce589dd51a416c","signature":"b8ecc5bb26c116432f3a49906ffc1244d5da1e6a315921399814d36d679745c3"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"5d2ca6b8f8dbe48b668835c213f21d9eb4171249753e92c9f719dbd69251f003","signature":"02d5e2109f13356e8075ed4e189487e63e89c2d1db606d190db2c20f5d15a7bb"},{"version":"5ae2d539449c1a03f7a666b27c1695c5e4df07eb15b2198d35458838db123874","signature":"4f37d48689ab288e1b3186ffee475b2c56c5dbce80c4dc82f5727000c991ea1e"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"f5a3993982b37c9ea8fff6b59093705608cb0006e842ab056a9b6a0f95410566","signature":"86f47f3b7906dce9fde5e2416cd518136b277b53f23ced68a21c6d8c9d3f865b"},{"version":"e3dab7586a67eee723d40f18c6173d02d202204bdd0ac5f297cd346338ecec7b","signature":"e42e5cba86f81415a4ef682613f284cf80972780f725888734946fb9f93efcd8"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"59c6f081e2d1b577eed878b40824bbde805c75a78b40a61767a17238c1335ab1","signature":"020b01101c9b65206958707b11296b507c9977d19a3ffc2a21c0d1c56530c4ca"},"bd68e0027b2c0982c238b52806108f689cdd22ec35b104ecd7ab0ba0c728a924",{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"3dba2c464bcecff3fe0677b9b62a54ebd255194de2f6c3239eb9f8433d78199e","impliedFormat":1},{"version":"75a153ce7aa9864e5f5b5aa0f6d15285ee8ee28be4b49a37895d8146c33c7073","impliedFormat":1},{"version":"b6db37355104b9985d7e7fd21d091f0d0efa878999f413a3a738589b08e253c5","impliedFormat":1},{"version":"84aa36cbcfaea3370371b6f572f122c11547a702dc5eb69447217b0bd4693947","impliedFormat":1},{"version":"411c31be8dea7f1151011450475b5ec7d50f2c586ba0025a8e30189023fed239","impliedFormat":1},{"version":"bf10451233f31689f8466df2957cfc289f2256769ef0a96bf8521ab06f019aab","impliedFormat":1},{"version":"7396a2a6653ddb10a864893b4e139b2229d7b4e0a86c50693a15e842f9ddb9ea","impliedFormat":1},{"version":"750079aafe5dc920cd8f5129d422c4e7528013d680aa168f6cf483ad61f99091","impliedFormat":1},{"version":"0cdfb9bca5949d79f319878de4665ffa2f5dfe58e2d52a3b5c720ca57aef5eca","impliedFormat":1},{"version":"29a5a2c65e62ff7d5ac29db7891cd2b2ef2f91e90e19caeedc06daf77391890b","impliedFormat":1},{"version":"898229164f6ccaa51c331689e64565d14f6679a4822f04f977641b6b6d3ef36c","impliedFormat":1},{"version":"43545961534d6cfc3151d870e209e02868423adbc7080fac8cfa01e2c574a381","impliedFormat":1},{"version":"06b19b4e2c49e119108463a5b6c62a250449556a7976be8ff2c442bd9503df1b","impliedFormat":1},{"version":"116d603dde86fa0b1a363ad1c8592c5e9acf352a62baa5993baa72b3be1a73df","impliedFormat":1},{"version":"629ea4dc5ccd0842ed3dcc9b2906a095df4bb2e32e4fe9504343d77c28eb211b","impliedFormat":1},{"version":"9aa80526f1ba5670338745a25b92fb080b9171e51f15fa0ca4d3b422f50ddceb","impliedFormat":1},{"version":"0f5b91ac7488a424a32ed88047e6c1adf416c20a8e58814f01394073a063ac17","impliedFormat":1},{"version":"0534185debbdc3717c3e7dd435d3a306bd006c89b9e5a404aea64b3c7eb60fc5","impliedFormat":1},{"version":"a6bb659bbfb51c0f1e493a045a4f5885186d61234ddc69c7ef11b6502ba6d6ec","impliedFormat":1},{"version":"417899f4834ad8101ce9a2da583f0827d4372c4c63e70e152f07eb054b363d03","impliedFormat":1},{"version":"f0d6103c0513c7592c8c1348ad33c9646dfea3c71deb98b220cd4911b4c99704","impliedFormat":1},{"version":"071f8795d98e0f7aec2e204ad4385ad485a7575acdf6218568de7979b8e51b2b","impliedFormat":1},{"version":"1ecb27d491a4de146d8f56c62888a5b04b44dc328a5fd9be284247e2155d4afa","impliedFormat":1},{"version":"1df8d8d25c95c443257484f90d5fc7d5de739c8921965701608bffee14db0c1c","impliedFormat":1},{"version":"2b72e84c91e140d3e776302b55da84e54deee8ced4661a7829fe91b982f095bf","impliedFormat":1},{"version":"b0e0ce3d80ffcab1129d3993ef5c860895b153fc395190d7fb0c706931ca49ad","impliedFormat":1},{"version":"4ab2224d23bfc186de35c1b8ff4480547ffb8f1b51a648bbc7a4f61835873747","impliedFormat":1},{"version":"2a41d2584aa23ed542817b4b68374df71126947755bf366e8614748a9fc442d9","impliedFormat":1},{"version":"7875a4964dbda7a14b5cb6b39f6db7bd6756e844f1018a514c23c5ea50e4e969","impliedFormat":1},{"version":"b835e569a60f0c19ce574ea06e7db9968b11fb8819c4423ce2309a5e3f2a825c","impliedFormat":1},{"version":"f78f7970f35f4342ca8a703bc6cd9841df453e895b9228d458142446e4bdf3ac","impliedFormat":1},{"version":"b0c8628db49c7a8c48304469badc0f74be4eeca8257d7cbd0c8208c18f28b90b","impliedFormat":1},{"version":"fc6a20c78e7bf202056f42a2b60e82bd7a5d9c13780d751796e03a5368d1b6fb","impliedFormat":1},{"version":"fe73b756a4cb6b8f9835e60a1e6325afe00df70d89aee7828f3db68e90fff170","impliedFormat":1},{"version":"668869416a940a99ee57f235b9322b131bae24c4259e7800587d8fc246b093cd","impliedFormat":1},{"version":"1c11d3ac1e05b93cac4af09345544e7ecee518f328d40c4d32a8da0942901c65","impliedFormat":1},{"version":"c452328f21d752bfd096a0eb5afc0eb710041d7fe3ca05c8ca07e33058bc9f23","impliedFormat":1},{"version":"1ba2050f909906f76d274235c55c7d8d91baa461069d891b42d3edafdedacf29","impliedFormat":1},{"version":"4c548f7686fd1a39b1843c659712c8cc6a5ee687f8d8f9e1b539e35f6713a180","impliedFormat":1},{"version":"c1f42f611654961fce032dfc82d357ec7acf807f70ef98696fbebf5cab15ce54","impliedFormat":1},{"version":"4e1c79b4384965d5d0ef05c0afe473d001516ca10709b0c14351a8167406ad1e","impliedFormat":1},{"version":"c1efd1c346e5dfda6a90f126e8e91d16cb67a2c698ac33686d15f01fa29d4b46","impliedFormat":1},{"version":"2d0b7c4e747368991be7170a8991a642aec4bc26c4337b882c968d7c012d3057","impliedFormat":1},{"version":"11eedfb03221b54bcf98db5f3d3055f37670801b1573b1e75e6ad499b92d9bff","impliedFormat":1},{"version":"18c24d488ac442fbda14236f584f1cbe9f9a2a6d81a663589b6e78cac4d87fc0","impliedFormat":1},{"version":"6015ded76f3fc76419a5751aa1e68f6525ac7c4eaf2d874b00d531900189c7ba","impliedFormat":1},{"version":"b28a2ee9fb473d25b105322eb74f40a7ae58bdf004a0a264a632bc3c7a88536e","impliedFormat":1},{"version":"cdb367e8b328b7c33a483e8d873b7d727f1533006143ec764b18afa2f002df0e","impliedFormat":1},{"version":"3380a3a9745d50cfff0eb9b14b29fa53c512fc21edd722038b2b3750c3de5d49","impliedFormat":1},{"version":"04b38bd5c3a8cfa11a8c418198ff45a87ef5079fcec00577666a9084c532213f","impliedFormat":1},{"version":"1bc1a937ecf83eab91791ea1cb9f854a49b377486102c5a0700392180eb8d70c","impliedFormat":1},{"version":"648f208d31b0513be0dbd8bd74b13eace512ddedb90d5c0b5167468c60413155","impliedFormat":1},{"version":"3ff72f7c6a6e0eb7e2f7c7d85d468bc367d23dc31be14842058a43d9d5dbd7af","impliedFormat":1},{"version":"d7d178b403d4cceb8dab81bd54dce348c7ac71ddb6547872a654c977247cf55f","impliedFormat":1},{"version":"8184db9ab7c212b6b661911f541699441abc1575be7426067853775592afbba4","impliedFormat":1},{"version":"27411cedae3a9dab5d54fa2e146d4fa6641eec0e52ade3da41c2d5bbdb119ae7","impliedFormat":1},{"version":"749228ac4274380c46cd574eac41cb6293b82030331f5c3eedac18c6bc2ab454","impliedFormat":1},{"version":"4b01b705c53e7f94311f758f2bbbe210859e6648d05fbb7998ecfd314370d4ff","impliedFormat":1},{"version":"333ea75ad88bd423fe08637296c912376d66969889916b19bfbeb89db2242407","impliedFormat":1},{"version":"3043b1bdf9d2e6b0aff6422a48f745f997eb57e43d3d42a5c6cf0848b2d794e0","impliedFormat":1},{"version":"a51b48204b2b924d47a60986e67c58b0caa7d73232c85f9e1c03a7ca636252de","impliedFormat":1},{"version":"3e4895172c2cbef8c2e54cd7fd96fb6c9922206d1388bf560f0fb8846ba88cd2","impliedFormat":1},{"version":"8bb9bdf953d0902b2328f89702c75097e1973e762dd8beebe80cd06a17a06017","impliedFormat":1},{"version":"b193927418aaf1e64b777157fe9ab79e5016875bcdf0ab28d2d2497c7e50b790","impliedFormat":1},{"version":"40fee0202063d1e93c0a07ab7c29a899183cd94a3fe260bba96ce49229969bf9","impliedFormat":1},{"version":"1b3b911468ce081d23979c6b3e818a3e66710a10c5656c8325075daf80ed1836","impliedFormat":1},{"version":"f01d0b70becee655497c184ec6e9f3f3e18cd15e7023c99c5c9388759dd66f7c","impliedFormat":1},{"version":"bf416cce4b8398cee52ed29e0f9c19690cce69278b945ea581378444058cfb53","impliedFormat":1},{"version":"367d3b4740e0648822a05ef5f4c7ce4a3cc9a562e24bf9463a6b523eb6031450","impliedFormat":1},{"version":"4b5e59098f037efedc336519d3fba3cb8083f5f792f1f0a2647f7b935de64877","impliedFormat":1},{"version":"d8beee6bff3a8294f7b923f6cf4a9cb5960bbb056ce48a0224f306053843648b","impliedFormat":1},{"version":"034c49f905a96eb8b576e6fe58f2c4883ff116603104bddc4bef0cf677eea7a8","impliedFormat":1},{"version":"d710349fdd281add4186ea89c121d66871f6c1799bb0e07e4da3244dba6b882c","impliedFormat":1},{"version":"03f6a000b6e4c295c4d565f855e3564df4e5ed5b242662893db9bade66520c72","impliedFormat":1},{"version":"f73f050e9065586cbc65c9b7fff8ef8eb97723fbd6d322b0fc13ee5f769de64e","impliedFormat":1},{"version":"aba45966aad51b62a211cf9dfb02d3bd30caaf2658321f0bf8724969ad794159","impliedFormat":1},{"version":"5c0eed6de692e5e46c09e83d08f16260963d649d1d60b01f574dfff43439a3a5","impliedFormat":1},{"version":"6a0563f249132eb9d2814cb120178ce9f23aafc915be71c97c121b168a7ec7ad","impliedFormat":1},{"version":"3f020db3efe0e85d4e394d7bffb2fab07b48f655cf5b981bedaff9178686a2cb","impliedFormat":1},{"version":"ccd7b69f26d5386d353f8c6e8a3fedca002ad07f475c9b30c4f11c2c3cc91679","impliedFormat":1},{"version":"ff70f47858b8d1fbe708cc14148464cddd0d6fb26b4078f45b2124b00d074560","impliedFormat":1},{"version":"49aa7ba1a6cd0cb6280bf1a78f0e3824ac5f5338bd8539b03ce1c8b26b693365","impliedFormat":1},{"version":"6c1deb9edcfb88c059aaa921929a6001e76239b65ce4191c2408c97d7322507a","impliedFormat":1},{"version":"ea8f1dbf77a0fa264342bff4d05ddb7ff7233540a84902e778495629dc1e0d72","impliedFormat":1},{"version":"f7b7a801993c12f9c4b2988fab4f7ec8b9123ccac2a2c433cbc1c6967abf3c4e","impliedFormat":1},{"version":"4d19f4e188ed7803e4733f44df1b969bf505dec6e7b6ccca4d9d101010f18446","impliedFormat":1},{"version":"6ce824bde7db1c3aaa70dfc072f6df22dd7c7852e1ec2fd8f10eff241d4ed484","impliedFormat":1},{"version":"43fb8e1045a5c42e76f1f95b50be3f1785c443fa1491394b319c4c55472658c4","impliedFormat":1},{"version":"6305b31d824411ad37256bdd409fd1ba0baad53e1f8f39bdfacf872b8a8a4f40","impliedFormat":1},{"version":"b245be05ea541bec1e4781feb43b47c851b9afd1036d5bba26663b0d2663d8ac","impliedFormat":1},{"version":"87db13f1becd33a3a23d50d2d4c80cab60a0b3f60f665043336b735501776707","impliedFormat":1},{"version":"8123d8f03cec556699a59a77d4472c13699c2ef77ee0c8ec43025acfffbfc2d9","impliedFormat":1},{"version":"f1b3f3d87fafd3a954d3c96e8f18be3bdb4903e8763dab8fa5824bcbf97d5a67","impliedFormat":1},{"version":"6f47739df2f8ed1528125dccb83dd1e1652a42f8b4592c0eb374862ed06fa438","impliedFormat":1},{"version":"aa77f41ec84aaf5adacfe4d6bd9b9f92630ada00a45700eca2a8b99e3c70c37b","impliedFormat":1},{"version":"3efa30630b397ff35c3b0dbbaba3761d2fd64aaae56ec1955d9cca59dd729f50","impliedFormat":1},{"version":"653590f7eb4941023bd6ca18c82d039ef6fdafb22c2bd6be172f113d7ffa2eb7","impliedFormat":1},{"version":"1398b43f50e28f5c57a73de6872d1c2f6c3a8f14f5a3591602385fe2d45f7f75","impliedFormat":1},{"version":"90a63041286c2b389329f2f7a9e12a1306a2d88dd2ae72bc36414a32182d22cb","impliedFormat":1},{"version":"08c1e69c030edc00b69aa924e33c5cd87064f1dbcb37ed23c3586945f3d5571b","impliedFormat":1},{"version":"2b9afe7454ec9f90de8d10790b1ded42f73589d53dd4040586801672c3e67fc6","impliedFormat":1},{"version":"9cb0615322ba0e12a9407dfda9958c899e942a24e1436d30e9b155fbe74857d1","impliedFormat":1},{"version":"a0cbc0c547c5dda3ed62de00d50df9132497280ce52305481f51d095c7e5c5f9","impliedFormat":1},{"version":"3cb9dc5a818a284140abede0a8fa6838184ad269ab7354cd80b1b84f00198293","impliedFormat":1},{"version":"735e25c92a3f5304d5b65d2c2b2aac1b0c9c407af9446e56f9017a111a56dfd2","impliedFormat":1},{"version":"8f1f74963197b427fe6512ba801b2e972a3037337635f49687b9b373fc00ee17","impliedFormat":1},{"version":"a00efec77b1a42338caa2b33b32ee33f566569dcbf998fd2a02b8e486d7723c7","impliedFormat":1},{"version":"72d4e5acf88da2251d8ab1c34f813c0e45a79eaf6c937666ef56942b8d7b200f","impliedFormat":1},{"version":"da568aed744774edd93a3bd5c25e732b78acfef83f79f1b1a1d4ec436cac97ce","impliedFormat":1},{"version":"9a45ac908610cb735a515517233e2bf06397e12a904cd88aaad541ae102ed467","impliedFormat":1},{"version":"d6e3e204d67cd62afe566ee54629b8ba40f649d81e9105e7062c11f28d8bb0a3","impliedFormat":1},{"version":"470d9033dfbd29b7f480a151c3e0a6235c085cf74df6444e7cd25ba623c1d0db","impliedFormat":1},{"version":"e103459e88e9a95f1cba5003182c88dc3e6ccb6162232c33755da96659b25c21","impliedFormat":1},{"version":"ebe3a8a7e1aadb529070c345b2f18775542a67abdacf80e8b367ca1cbd754584","impliedFormat":1},{"version":"c01bcebf1d775113fbe692ed5237c29527de9bcfb1cbbffd568a90664f749170","impliedFormat":1},{"version":"278a88af3bdddbf7cc7eab607de3f4f91ef905e21695f16c78d9f1878d3e5638","impliedFormat":1},{"version":"8a0721d211f480ccae97f8eb9786e6e408c8c859d7bac2d39b858d1a507574c0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebde9ed796bd0ffa6df0a0cbf5f9e0ba575d2049f11a9f5642b1321e32535a21","impliedFormat":1},{"version":"f3c58b56d958dd5007089c5a87be1321b6907ffbfd0c4ca16e5c868604f4a816","signature":"8b11504a6587a3805e3dca9114d5a721e24e89e0b8664bd0b9205bb9acc6591c"},"b17e20b7c1903df1f2f043ffc5ab771a1d561c0c701c065156235b1cb3ff42a0",{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},"479dc00ea2253a00dcf99c655025d6fda6ced6b89d20936b4771742c5960a304",{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"76022067f28f6cef2238c1db9b3365331bc63e6a722f5d6a4049e08bee4a8728","signature":"bda6ce7797ec2815a4da67c80a12bf05f933ea08783420bec3c9d68d1785444e"},{"version":"d6b8f6e44d4e3e2c4133b12b05b06a42935319cfeaa05328218525d7aae039dc","signature":"55206b710b854a59363078374ca44b29ef666665090d708f9829b116837fd34f"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"96702141df8658f192ed9ac72b21ff4f197ec2d73e04754bcb6aba2b94a83da9","signature":"791a8a6b2bff7c4dbb24a639587b1daf3291117d062cee6c3692e79cc9fbbf9d"},{"version":"8ceb92ea34823905682c0c27ff0c4b7bb99affbcbc976501f3b9f8ad78d87822","signature":"f8aae2890d61bc88251433668b2b57ad8ba3a49ceeb947d8bdbbc19a5c751649"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"b54e0feb683893a68b23b681f25bde8a9d800d0dca9e46b9452d11121d392328","signature":"eda69f1276cdd081f002458f2ecbb92da7a0292537c56b266f8c7b5dd0eab784"},{"version":"9e790989224eac05234eb7e01db0f82a62391cf842486d7d43d9491b617da510","signature":"27bbb77a4afaae56c74d43fa04120c30fd2f8dc27cf56122a26001725d22b9de"},{"version":"c8063edd5e289a023a07c3f71c3c346928484db2e7f819bd75ae7ff3e2fdfc32","signature":"999903506e61a5b259c34712be36590b96ec8375ea51361aeea159691728231d"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"bec9f8f6421f9f0914f76a0fd3da2b8ef5c2c2f4982945af4f070c7f2bebbaec","signature":"10063900e6e288fc6c5d220a4a06bbbf74b4bdff73eb72dd2a53c15b88f98ee5"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},"a02f8c3a63223f320d39c00c6e433da213d626fb1641999035365a7ed8d8d71c","841d964f34cfbc56a5a9c6e4bcc5ba2d20a82070ad38225956073c4934a53ed5",{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"7d474265a4fbe75d10af729593f2960de7edee5bfd1c5d6706c05c6ef154a39f","signature":"6af176444deba56bdf5e2440eec91b4c190d0942132d782e1e4af52e926efd1f"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"8a72c9da8b95e8343a6f16a65e6e3ee7c6ea8ca8a53123bf6bcead92d2d95e88","signature":"ef8634682715ac7a581efbcbf3656c5f07e4405a138bc222c98c40a073483281"},"14f3b951550cc376673897b55068eda7a4bbb817b4d7527083f6dd6a3133f051",{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"4940a27c518427c56d10e2a1094fa688cbee7973de244bf08933a52402926f41","signature":"453e6e89124e33a3dcb5003b9f624594eb18efe0d0addcfd8393c830c2f6a9e1"},{"version":"23433e9ad6a837b0591d9956c0358f8da3775e592b708767ddf33e6db18382e8","signature":"d3f0ac692da385d451807d5612a1ef735657ae42b89180bcf21fae7b57f7a4f5"},"a53d8bf50034149a8d8b171377d40bfa2cb72535f30894af63a4429355332c76",{"version":"ddd578018a259d1c494c834bdd8707769d07d1eb64f87f5217560cd2181b9e93","signature":"da14a67372982ca6e605fea114900b492b3316618581634e0ce72afbcb09baca"},{"version":"8d1af2b325f39658cc8f0fb1371eeb1a9cd9ccec1df629a25e23cff813e45269","signature":"843eb8044483afd59ac9923676eadf3981e1dcf76b2fc3224c9e68c838a51e16","affectsGlobalScope":true}],"root":[[66,68],275,278,279,[281,297],[416,450]],"options":{"composite":false,"declaration":false,"declarationMap":false,"experimentalDecorators":true,"importHelpers":true,"inlineSourceMap":false,"inlineSources":false,"module":200,"noEmitOnError":false,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noImplicitReturns":true,"noPropertyAccessFromIndexSignature":true,"outDir":"../../../..","removeComments":false,"skipLibCheck":true,"strict":true,"target":9,"tsBuildInfoFile":"./.tsbuildinfo"},"referencedMap":[[268,1],[273,2],[270,3],[272,4],[267,4],[264,5],[71,6],[263,7],[261,8],[266,9],[280,10],[271,11],[274,12],[277,13],[276,14],[414,15],[415,16],[298,17],[299,17],[300,17],[301,17],[302,17],[303,17],[304,17],[305,17],[306,17],[307,17],[308,17],[309,17],[310,17],[311,17],[312,17],[313,17],[314,17],[315,17],[316,17],[317,17],[318,17],[319,17],[320,17],[321,17],[322,17],[323,17],[324,17],[325,17],[326,17],[327,17],[328,17],[329,17],[330,17],[331,17],[332,17],[333,17],[334,17],[335,17],[336,17],[337,17],[338,17],[339,17],[340,17],[341,17],[342,17],[343,17],[344,17],[345,17],[346,17],[347,17],[348,17],[350,17],[349,17],[351,17],[352,17],[353,17],[354,17],[355,17],[356,17],[357,17],[358,17],[359,17],[360,17],[361,17],[362,17],[363,17],[364,17],[365,17],[366,17],[367,17],[368,17],[369,17],[370,17],[371,17],[372,17],[373,17],[374,17],[375,17],[376,17],[377,17],[378,17],[379,17],[380,17],[381,17],[382,17],[383,17],[384,17],[385,17],[386,17],[387,17],[388,17],[389,17],[390,17],[391,17],[392,17],[393,17],[394,17],[395,17],[396,17],[397,17],[398,17],[399,17],[400,17],[401,17],[402,17],[403,17],[404,17],[405,17],[406,17],[407,17],[408,17],[409,17],[410,17],[411,17],[412,17],[260,18],[211,19],[209,19],[259,20],[224,21],[223,21],[124,22],[75,23],[231,22],[232,22],[234,24],[235,22],[236,25],[135,26],[237,22],[208,22],[238,22],[239,27],[240,22],[241,21],[242,28],[243,22],[244,22],[245,22],[246,22],[247,21],[248,22],[249,22],[250,22],[251,22],[252,29],[253,22],[254,22],[255,22],[256,22],[257,22],[74,20],[77,25],[78,25],[79,25],[80,25],[81,25],[82,25],[83,25],[84,22],[86,30],[87,25],[85,25],[88,25],[89,25],[90,25],[91,25],[92,25],[93,25],[94,22],[95,25],[96,25],[97,25],[98,25],[99,25],[100,22],[101,25],[102,25],[103,25],[104,25],[105,25],[106,25],[107,22],[109,31],[108,25],[110,25],[111,25],[112,25],[113,25],[114,29],[115,22],[116,22],[130,32],[118,33],[119,25],[120,25],[121,22],[122,25],[123,25],[125,34],[126,25],[127,25],[128,25],[129,25],[131,25],[132,25],[133,25],[134,25],[136,35],[137,25],[138,25],[139,25],[140,22],[141,25],[142,36],[143,36],[144,36],[145,22],[146,25],[147,25],[148,25],[153,25],[149,25],[150,22],[151,25],[152,22],[154,25],[155,25],[156,25],[157,25],[158,25],[159,25],[160,22],[161,25],[162,25],[163,25],[164,25],[165,25],[166,25],[167,25],[168,25],[169,25],[170,25],[171,25],[172,25],[173,25],[174,25],[175,25],[176,25],[177,37],[178,25],[179,25],[180,25],[181,25],[182,25],[183,25],[184,22],[185,22],[186,22],[187,22],[188,22],[189,25],[190,25],[191,25],[192,25],[210,38],[258,22],[195,39],[194,40],[218,41],[217,42],[213,43],[212,42],[214,44],[203,45],[201,46],[216,47],[215,44],[204,48],[117,49],[73,50],[72,25],[199,51],[200,52],[198,53],[196,25],[205,54],[76,55],[222,21],[220,56],[193,57],[206,58],[65,59],[275,60],[443,61],[441,60],[442,62],[444,60],[278,60],[438,63],[447,64],[421,60],[422,65],[420,60],[423,66],[445,60],[446,67],[424,60],[433,68],[429,60],[430,60],[431,69],[432,70],[425,60],[426,60],[427,71],[428,72],[297,60],[416,73],[418,60],[419,74],[293,60],[296,75],[292,60],[294,60],[295,76],[417,77],[434,60],[435,78],[436,60],[437,79],[288,60],[289,60],[290,80],[291,81],[279,60],[283,60],[284,82],[287,83],[449,60],[450,84],[439,60],[440,85],[285,60],[286,86],[281,60],[282,87],[66,60],[67,88],[68,60],[448,89]],"semanticDiagnosticsPerFile":[1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,66,68,275,278,279,281,283,285,288,289,292,293,294,296,297,417,418,419,420,421,424,425,426,429,430,434,436,437,438,439,441,443,444,445,448,449],"affectedFilesPendingEmit":[275,443,441,442,444,278,438,447,421,422,420,423,445,446,424,433,429,430,431,432,425,426,427,428,297,416,418,419,293,296,292,294,295,417,434,435,436,437,288,289,290,291,279,283,284,287,449,450,439,440,285,286,281,282,66,67,68,448],"version":"5.9.2"} \ No newline at end of file diff --git a/web/dist/pyunit/browser/index.html b/web/dist/pyunit/browser/index.html index f07f5df5..a6cdb733 100644 --- a/web/dist/pyunit/browser/index.html +++ b/web/dist/pyunit/browser/index.html @@ -6,12 +6,10 @@ - - - + diff --git a/web/package.json b/web/package.json index b15d310e..4971d9a3 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "pyunit", - "version": "2.0.0", + "version": "2.0.1", "scripts": { "ng": "ng", "start": "ng serve", diff --git a/web/src/app/pages/configs/moonraker-config/moonraker-config.html b/web/src/app/pages/configs/moonraker-config/moonraker-config.html index 8ea7407a..9e794c6b 100644 --- a/web/src/app/pages/configs/moonraker-config/moonraker-config.html +++ b/web/src/app/pages/configs/moonraker-config/moonraker-config.html @@ -51,7 +51,7 @@
IP address is required
Enter a valid IP address (e.g., 192.168.1.1)
-
Specify the Moonraker server IP address (e.g., 127.0.0.1 or 192.168.1.100)
+
Specify the IP address of the machine running Moonraker (e.g., 192.168.1.100). Do NOT use 127.0.0.1
diff --git a/web/src/app/pages/dashboard/dashboard-charts/dashboard-charts.html b/web/src/app/pages/dashboard/dashboard-charts/dashboard-charts.html index cf457574..5dc8fa5f 100644 --- a/web/src/app/pages/dashboard/dashboard-charts/dashboard-charts.html +++ b/web/src/app/pages/dashboard/dashboard-charts/dashboard-charts.html @@ -8,6 +8,23 @@

-
+
+ + +
+
+ Loading... +
+
+ + +
+
+
+ Loading... +
+
Loading data...
+
+
diff --git a/web/src/app/pages/dashboard/dashboard-charts/dashboard-charts.scss b/web/src/app/pages/dashboard/dashboard-charts/dashboard-charts.scss index c8410f4d..40eb40f5 100644 --- a/web/src/app/pages/dashboard/dashboard-charts/dashboard-charts.scss +++ b/web/src/app/pages/dashboard/dashboard-charts/dashboard-charts.scss @@ -1,6 +1,73 @@ -.chart-container { padding: 0.5rem 1rem 1rem; min-height:550px; display:flex; } +.chart-container { padding: 0.5rem 1rem 1rem; min-height:550px; display:flex; position: relative; } .highchart-root { width: 100%; height: 100%; min-height:550px; opacity:0; transform:translateY(6px); animation: chartFade .6s ease forwards .15s; } +.highchart-root.chart-hidden { + opacity: 0 !important; + visibility: hidden !important; + pointer-events: none; + animation: none !important; /* Disable animation when hidden */ +} @keyframes chartFade { to { opacity:1; transform:translateY(0); } } + +/* Initial chart loading (when no data) - solid background, spinner only */ +.chart-initial-loading { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: #212529; /* Explicit dark background */ + display: flex; + align-items: center; + justify-content: center; + z-index: 100; + border-radius: 8px; + animation: fadeIn 0.2s ease-in; + + .spinner-border { + width: 4rem; + height: 4rem; + border-width: 0.4rem; + } +} + +/* Chart loading overlay for reconnecting state (when has data) - transparent with blur */ +.chart-loading-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(33, 37, 41, 0.85); + backdrop-filter: blur(2px); + display: flex; + align-items: center; + justify-content: center; + z-index: 100; + border-radius: 8px; + animation: fadeIn 0.2s ease-in; + + .spinner-container { + text-align: center; + + .spinner-border { + width: 2.5rem; + height: 2.5rem; + } + + .loading-text { + margin-top: 0.75rem; + color: #f0f0f2; + font-size: 0.95rem; + font-weight: 500; + opacity: 0.9; + } + } +} + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} .card { background: #212529; border: 1px solid #2c3237; border-radius: 10px; min-height:550px; display:flex; flex-direction:column; } .card-header { border-bottom: 1px solid #2c3237; padding: .75rem 1rem; } .card-title { font-size: 1.1rem; margin: 0; } diff --git a/web/src/app/pages/dashboard/dashboard-charts/dashboard-charts.ts b/web/src/app/pages/dashboard/dashboard-charts/dashboard-charts.ts index e88edc07..ddc3e3f7 100644 --- a/web/src/app/pages/dashboard/dashboard-charts/dashboard-charts.ts +++ b/web/src/app/pages/dashboard/dashboard-charts/dashboard-charts.ts @@ -100,6 +100,10 @@ export class DashboardChartsPage implements OnInit, OnDestroy { { key: '12h', label: '12h' }, { key: 'all', label: 'All' }, ]; + connectionStatus: 'connecting' | 'open' | 'reconnecting' | 'closed' | 'error' = 'connecting'; + summaries: DryerStateSummary[] = []; + hasChartData = false; // Track if chart has been populated with data + isLoadingNewData = false; // Track when user changes time range constructor(private dashboard: DashboardService, private logger: LoggingService) {} @@ -107,9 +111,15 @@ export class DashboardChartsPage implements OnInit, OnDestroy { this.logger.debug('DashboardCharts', 'ngOnInit'); this.initChart(); this.subs.push( + this.dashboard.getConnectionStatus().subscribe(status => { + this.logger.debug('DashboardCharts', 'connection status', { status }); + this.connectionStatus = status; + }), this.dashboard.getSummaries().subscribe(sums => { this.logger.debug('DashboardCharts', 'summaries update', { count: sums.length }); + this.summaries = sums; this.updateSeries(sums); + // Don't stop loading indicator here - let updateSeries handle it }), this.dashboard.getTimeRange().subscribe(r => { this.logger.debug('DashboardCharts', 'time range changed', { from: this.timeRange, to: r }); @@ -279,9 +289,17 @@ export class DashboardChartsPage implements OnInit, OnDestroy { this.chart.redraw(); const dt = (performance.now() - t0).toFixed(1); this.logger.debug('DashboardCharts', 'updateSeries complete', { totalPoints, series: this.chart.series.length, dt }); - if (this.firstData && summaries.length) { + + // Only mark as having data if we actually rendered something + if (this.firstData && summaries.length > 0 && totalPoints > 0) { // Disable animation for subsequent incremental updates this.firstData = false; + this.hasChartData = true; // Mark that chart has been populated with data + } + + // Stop loading indicator after successful render with data + if (summaries.length > 0 && totalPoints > 0) { + this.isLoadingNewData = false; } } @@ -292,6 +310,7 @@ export class DashboardChartsPage implements OnInit, OnDestroy { setRange(r: TimeRangeKey) { if (r === this.timeRange) return; this.logger.info('DashboardCharts', 'user setRange', { to: r }); + this.isLoadingNewData = true; // Show loading immediately this.timeRange = r; this.dashboard.setTimeRange(r); } diff --git a/web/src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.html b/web/src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.html index ea2d0139..df5c34ab 100644 --- a/web/src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.html +++ b/web/src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.html @@ -7,52 +7,70 @@
-
+
+
-
-

{{ sm.name || ('Dryer '+dryerId) }}

- {{ sm.currentPresetName || '...' }} -
+
+

{{ sm.name || ('Dryer '+dryerId) }}

+ {{ sm.currentPresetName || '...' }} +
{{ getStatusLabel() }} -
-
-
-
{{ sm.temperature !== undefined ? sm.temperature.toFixed(1) : '--.-' }}°C
-
{{ sm.humidity !== undefined ? sm.humidity.toFixed(1) : '--.-' }}%
-
{{ formatTimeLeft(sm.timeLeftDryingSeconds) }}
-
-
{{ sm.heaterOn ? 'ON' : 'OFF' }}
-
{{ sm.servoOpen ? 'OPEN' : 'CLOSED' }}
+
+
+
{{ sm.temperature !== undefined ? sm.temperature.toFixed(1) : '--.-' }}°C
+
{{ sm.humidity !== undefined ? sm.humidity.toFixed(1) : '--.-' }}%
+
{{ formatTimeLeft(sm.timeLeftDryingSeconds) }}
+
+
+
{{ sm.heaterOn ? 'ON' : 'OFF' }}
+
{{ sm.servoOpen ? 'OPEN' : 'CLOSED' }}
+
-
-
+
- + +
-
-
Loading summary...
+
+
+ Loading... +
+
+ +
+
+ Loading... +
+
+
-
-
-

Presets

-
-
- -
-
(no presets)
+
+
+

Presets

+
+
+ +
+
(no presets)
+ +
+
+ Loading...
+
+
@@ -64,7 +82,26 @@

{{ r.label }}

-
+
+
+ + +
+
+ Loading... +
+
+ + +
+
+
+ Loading... +
+
Loading data...
+
+
+
diff --git a/web/src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.scss b/web/src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.scss index 85727fb7..80fc47be 100644 --- a/web/src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.scss +++ b/web/src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.scss @@ -16,7 +16,12 @@ .dryer-detail-page > .page-header { margin:15px 0 15px 0; } } .dryer-detail-page .card { background:var(--card-bg); border:1px solid var(--card-border); border-radius:10px; } -.top-cards { display:grid; grid-template-columns: 300px 1fr; align-items:stretch; gap:1rem; } +.top-cards { + display: grid; + grid-template-columns: 300px 1fr; + align-items: start; /* Changed from stretch to start to prevent height changes */ + gap: 1rem; +} @media (max-width: 1000px) { .top-cards { grid-template-columns: 1fr; } } @media (min-width:1400px){ .top-cards { grid-template-columns: 300px 1fr; } } .dryer-status-inline { font-size:.6rem; letter-spacing:.5px; padding:.25rem .45rem; border-radius:4px; text-transform:uppercase; font-weight:600; line-height:1; } @@ -35,11 +40,27 @@ .chart-placeholder { background:#1b2024; border:1px dashed #2c3237; border-radius:8px; } .chart-card { min-height:300px; } .chart-card #singleDryerChart { min-height:550px; } +.chart-container { + position: relative; + width: 100%; + height: 550px; /* Fixed height to prevent jumping */ + min-height: 550px; + contain: layout; /* Prevent layout thrashing */ +} /* Equal height cards: make inner cards flex columns */ -.status-card, .presets-card { display:flex; flex-direction:column; } -.presets-card .presets-buttons { margin-top:.25rem; } -.presets-card { overflow:auto; } +.status-card, .presets-card { + display: flex; + flex-direction: column; +} +.status-card { + min-height: 200px; /* Prevent status card from collapsing */ +} +.presets-card { + overflow: auto; + min-height: 200px; /* Prevent presets card from collapsing */ +} +.presets-card .presets-buttons { margin-top: .25rem; } /* G-code macros card */ .macros-card { @@ -133,4 +154,89 @@ } } +/* Initial chart loading (no data yet) - full spinner without blur */ +.chart-initial-loading { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: var(--card-bg); + display: flex; + align-items: center; + justify-content: center; + z-index: 10; + border-radius: 8px; + + .spinner-border { + width: 3rem; + height: 3rem; + border-width: 0.3rem; + } +} + +/* Chart loading overlay (reconnecting with existing data) */ +.chart-loading-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(33, 37, 41, 0.85); + backdrop-filter: blur(2px); + display: flex; + align-items: center; + justify-content: center; + z-index: 10; + border-radius: 8px; + animation: fadeIn 0.2s ease-in; + + .spinner-container { + text-align: center; + + .spinner-border { + width: 3rem; + height: 3rem; + border-width: 0.3rem; + } + .loading-text { + color: #dedce0; + font-size: 0.95rem; + font-weight: 500; + opacity: 0.9; + } + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +/* Card loading overlay (for status and presets cards) */ +.card-loading-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(33, 37, 41, 0.75); + backdrop-filter: blur(1px); + display: flex; + align-items: center; + justify-content: center; + z-index: 5; + border-radius: 10px; + animation: fadeIn 0.15s ease-in; + + .spinner-border-sm { + width: 1.5rem; + height: 1.5rem; + border-width: 0.2rem; + } +} diff --git a/web/src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.ts b/web/src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.ts index 07dd38e3..5eaa8b6c 100644 --- a/web/src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.ts +++ b/web/src/app/pages/dashboard/dashboard-dryer/dashboard-dryer.ts @@ -61,26 +61,40 @@ export class DashboardDryer implements OnInit, OnDestroy { constructor(private route: ActivatedRoute, private dashboard: DashboardService, private toast: ToastService, private logger: LoggingService) {} ngOnInit(): void { - // Ensure websocket connection is active when entering directly via deep link + // Get dryer ID from route first + this.subs.push(this.route.paramMap.subscribe(pm => { + const val = pm.get('dryerId'); + this.dryerId = val ? +val : NaN; + + // Connect in optimized 'single' mode for this specific dryer + if (Number.isFinite(this.dryerId) && !this.initiatedConnection) { + this.logger.info('DashboardDryer', 'Connecting in single mode', { dryerId: this.dryerId }); + try { + // No limit - load all logs for time range, frontend filtering handles performance + this.dashboard.connect('single', this.dryerId); + this.initiatedConnection = true; + } catch (err) { + this.logger.error('DashboardDryer', 'Failed to connect', err); + } + } + + this.pickSummary(); + })); + + // Fallback: ensure connection if status is closed/error if (this.dashboard.getConnectionStatus && typeof this.dashboard.getConnectionStatus === 'function') { const sub = this.dashboard.getConnectionStatus().subscribe(st => { - if (st === 'closed' || st === 'error') { - // Attempt a connect only once here; dashboard main page also calls connect. - if (!this.initiatedConnection) { - try { this.dashboard.connect(); this.initiatedConnection = true; } catch {} - } + if ((st === 'closed' || st === 'error') && !this.initiatedConnection && Number.isFinite(this.dryerId)) { + this.logger.warn('DashboardDryer', 'Connection lost, reconnecting', { status: st }); + try { + this.dashboard.connect('single', this.dryerId); + this.initiatedConnection = true; + } catch {} } }); this.subs.push(sub); - } else { - // Fallback: try connect immediately - try { this.dashboard.connect(); this.initiatedConnection = true; } catch {} } - this.subs.push(this.route.paramMap.subscribe(pm => { - const val = pm.get('dryerId'); - this.dryerId = val ? +val : NaN; - this.pickSummary(); - })); + this.subs.push(this.dashboard.getSummaries().subscribe(() => { this.pickSummary(); this.updateChart(); })); this.subs.push(this.dashboard.getConnectionStatus().subscribe((cs: any) => this.connectionStatus = cs)); this.subs.push(this.dashboard.getPresets().subscribe((ps: PresetShort[]) => { this.presets = ps; this.filterPresets(); })); @@ -341,7 +355,7 @@ export class DashboardDryer implements OnInit, OnDestroy { } async onStop() { - if (!this.summary || this.summary.status !== 'drying') return; + if (!this.summary || this.summary.status === 'pending') return; try { const res = await this.dashboard.stopDryer(this.dryerId); this.toast.show(`Stopped dryer #${this.dryerId}${res?.message ? ': '+res.message : ''}`, { classname: 'bg-warning text-dark', delay: 3000, dedupKey: 'stop-'+this.dryerId }); diff --git a/web/src/app/pages/dashboard/dashboard-dryers/dashboard-dryers.html b/web/src/app/pages/dashboard/dashboard-dryers/dashboard-dryers.html index 40469678..19dc9026 100644 --- a/web/src/app/pages/dashboard/dashboard-dryers/dashboard-dryers.html +++ b/web/src/app/pages/dashboard/dashboard-dryers/dashboard-dryers.html @@ -1,8 +1,8 @@ -
+
-

Status

+

Status

- Updated: {{ lastUpdated }} + Updated: {{ lastUpdated }}
@@ -53,13 +53,23 @@

{{ s.name || ('Dryer #' + s.dryerId) }}

-
- - +
+ +
+ + +
+
+
+ Loading... +
+
Updating data...
+
+
diff --git a/web/src/app/pages/dashboard/dashboard-dryers/dashboard-dryers.scss b/web/src/app/pages/dashboard/dashboard-dryers/dashboard-dryers.scss index 1cfddc59..0c590b39 100644 --- a/web/src/app/pages/dashboard/dashboard-dryers/dashboard-dryers.scss +++ b/web/src/app/pages/dashboard/dashboard-dryers/dashboard-dryers.scss @@ -40,3 +40,46 @@ .skeleton-line.long { width:90%; } .skeleton-shimmer { position:absolute; top:0; left:0; width:100%; height:100%; background:linear-gradient(110deg, rgba(255,255,255,0), rgba(255,255,255,0.07), rgba(255,255,255,0)); animation:shimmer 1.2s linear infinite; } @keyframes shimmer { from { transform:translateX(-100%); } to { transform:translateX(100%); } } + +/* Loading overlay for reconnecting */ +.card-loading-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(33, 37, 41, 0.85); + backdrop-filter: blur(2px); + display: flex; + align-items: center; + justify-content: center; + z-index: 10; + border-radius: 10px; + animation: fadeIn 0.2s ease-in; + + .spinner-container { + text-align: center; + + .spinner-border { + width: 2.5rem; + height: 2.5rem; + border-width: 0.3rem; + } + + .loading-text { + color: #dedce0; + font-size: 0.9rem; + font-weight: 500; + opacity: 0.9; + } + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} diff --git a/web/src/app/pages/dashboard/dashboard.service.ts b/web/src/app/pages/dashboard/dashboard.service.ts index ea20e405..65617e5d 100644 --- a/web/src/app/pages/dashboard/dashboard.service.ts +++ b/web/src/app/pages/dashboard/dashboard.service.ts @@ -5,6 +5,9 @@ import { LoggingService } from '../../services/logging.service'; import { environment } from '../../../environments'; import { BehaviorSubject, Observable, Subscription, timer } from 'rxjs'; +// WebSocket connection mode +export type WebSocketMode = 'all' | 'single'; + // Backend DryerShort (from /api/common/units) export interface DryerShort { id: number; @@ -69,6 +72,9 @@ interface InternalState { dryers: DryerShort[]; summaries: Map; timeRange: TimeRangeKey; + wsMode: WebSocketMode; // 'all' or 'single' + activeDryerId?: number; // for single mode + logLimit?: number; // saved limit for reconnections } @Injectable({ providedIn: 'root' }) @@ -85,13 +91,14 @@ export class DashboardService implements OnDestroy { private state: InternalState = { dryers: [], summaries: new Map(), - timeRange: '1h' + timeRange: '1h', + wsMode: 'all' // default to legacy mode for backward compatibility }; private dryers$ = new BehaviorSubject([]); private summaries$ = new BehaviorSubject([]); private timeRange$ = new BehaviorSubject('1h'); - private connectionStatus$ = new BehaviorSubject<'connecting' | 'open' | 'closed' | 'error'>('closed'); + private connectionStatus$ = new BehaviorSubject<'connecting' | 'reconnecting' | 'open' | 'closed' | 'error'>('closed'); // Throttling for summaries emission private summariesDirty = false; private summariesThrottleTimer?: any; @@ -107,41 +114,103 @@ export class DashboardService implements OnDestroy { private readonly INITIAL_UNITS_MAX_ATTEMPTS = 5; private initialUnitsRetryTimer?: any; - /** Explicitly initiate data + websocket connection. Safe to call multiple times. */ - connect() { + /** Explicitly initiate data + websocket connection. Safe to call multiple times. + * + * @param mode 'all' = legacy endpoint (all dryers), 'single' = optimized per-dryer endpoint + * @param dryerId Required when mode='single', specifies which dryer to monitor + * @param logLimit Max historical logs to load (optional, no default). Only for single mode. + */ + async connect(mode: WebSocketMode = 'all', dryerId?: number, logLimit?: number) { if (this.shouldReconnect && this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) { - return; // already connecting/connected + // Check if mode/dryer changed - reconnect if so + if (mode !== this.state.wsMode || (mode === 'single' && dryerId !== this.state.activeDryerId)) { + this.logger.info('DashboardSvc', 'connect() mode/dryer changed, reconnecting', { mode, dryerId }); + await this.disconnect(); + } else { + return; // already connecting/connected with same params + } + } + + // Validate single mode requires dryerId + if (mode === 'single' && !dryerId) { + this.logger.error('DashboardSvc', 'connect() single mode requires dryerId'); + return; } + // Full reset to avoid duplicated historical data when returning to page this.state.dryers = []; this.state.summaries.clear(); + this.state.wsMode = mode; + this.state.activeDryerId = dryerId; + this.state.logLimit = logLimit; // Save limit for reconnections this.pushSummaries(); // emit empty to allow UI to clear instantly this.shouldReconnect = true; this.reconnectAttempts = 0; this.connectionStatus$.next('connecting'); - this.logger.info('DashboardSvc', 'connect(): fetching units...'); - this.fetchDryers(false, true); // treat as initial fetch with retry support + this.logger.info('DashboardSvc', 'connect()', { mode, dryerId, logLimit: logLimit || 'none' }); + this.fetchDryers(false, true); // treat as initial fetch with retry support this.fetchPresets(); - this.openWebSocket(); + this.openWebSocket(logLimit); this.startUnitsRefreshTimer(); } /** Stop websocket + timers and prevent automatic reconnection until connect() called again. */ - disconnect() { - this.shouldReconnect = false; - this.clearReconnectTimeout(); - this.clearUnitsRefreshTimer(); - try { this.ws?.close(); } catch {} - this.ws = undefined; - this.connectionStatus$.next('closed'); + disconnect(clearData = true): Promise { + return new Promise((resolve) => { + this.shouldReconnect = false; + this.clearReconnectTimeout(); + this.clearUnitsRefreshTimer(); + + // Optionally clear summaries to prevent mixing old and new data + // When just changing time range, we keep data to avoid visual jump + if (clearData) { + this.state.summaries.clear(); + this.pushSummaries(); + } + + if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) { + // Save reference to current WebSocket to avoid race conditions + const wsToClose = this.ws; + this.ws = undefined; // Immediately clear to prevent new messages + + // Wait for WebSocket to actually close + const closeHandler = () => { + this.connectionStatus$.next('closed'); + resolve(); + }; + + // Set a timeout in case close doesn't fire + const timeout = setTimeout(() => { + this.connectionStatus$.next('closed'); + resolve(); + }, 1000); + + wsToClose.onclose = () => { + clearTimeout(timeout); + closeHandler(); + }; + + // Clear other handlers to prevent unexpected calls + wsToClose.onmessage = null; + wsToClose.onerror = null; + wsToClose.onopen = null; + + try { wsToClose.close(); } catch {} + } else { + // Already closed or no connection + this.ws = undefined; + this.connectionStatus$.next('closed'); + resolve(); + } + }); } // Public observables getDryers(): Observable { return this.dryers$.asObservable(); } getSummaries(): Observable { return this.summaries$.asObservable(); } getTimeRange(): Observable { return this.timeRange$.asObservable(); } - getConnectionStatus(): Observable<'connecting' | 'open' | 'closed' | 'error'> { return this.connectionStatus$.asObservable(); } + getConnectionStatus(): Observable<'connecting' | 'reconnecting' | 'open' | 'closed' | 'error'> { return this.connectionStatus$.asObservable(); } getPresets(): Observable { return this.presets$.asObservable(); } /** Stop (cancel preset) for a dryer: POST /dashboard/control/set-preset/{id} without preset id */ @@ -192,11 +261,34 @@ export class DashboardService implements OnDestroy { } catch (err: any) { throw err; } } - setTimeRange(range: TimeRangeKey) { + async setTimeRange(range: TimeRangeKey) { + const oldRange = this.state.timeRange; this.state.timeRange = range; this.timeRange$.next(range); - // Immediate push on range change (no throttle) for responsive UX - this.flushSummaries(); + + // Reconnect with new time filter for both single and all modes + if (oldRange !== range && this.shouldReconnect) { + this.logger.info('DashboardSvc', 'setTimeRange reconnecting', { + mode: this.state.wsMode, + oldRange, + newRange: range + }); + // Show reconnecting state for smooth UX + this.connectionStatus$.next('reconnecting'); + // Wait for disconnect to complete before reconnecting + // Don't clear data to avoid visual jump - new history will replace it + await this.disconnect(false); + + // Reconnect with appropriate mode + if (this.state.wsMode === 'single') { + await this.connect('single', this.state.activeDryerId, this.state.logLimit); + } else { + await this.connect('all', undefined, this.state.logLimit); + } + } else if (!this.shouldReconnect) { + // If not connected, just update local filtering + this.flushSummaries(); + } } private async fetchDryers(silent = false, isInitial = false) { @@ -286,9 +378,51 @@ export class DashboardService implements OnDestroy { } } - private openWebSocket() { + private openWebSocket(logLimit?: number) { if (!this.shouldReconnect) return; // guard - const url = `${environment.wsUrl}/dashboard/dryers`.replace('http', 'ws'); + + let url: string; + const timeRange = this.state.timeRange; + let startTime: string | undefined; + + // Calculate start_time based on current timeRange (for both single and all modes) + if (timeRange !== 'all') { + const windowMs = TIME_RANGE_WINDOWS_MS[timeRange]; + const startDate = new Date(Date.now() - windowMs); + startTime = startDate.toISOString(); + } + + if (this.state.wsMode === 'single' && this.state.activeDryerId) { + // Optimized endpoint: single dryer with time-based filtering + const baseUrl = `${environment.wsUrl}/dashboard/dryer/${this.state.activeDryerId}`.replace('http', 'ws'); + const params = new URLSearchParams(); + if (startTime) params.set('start_time', startTime); + if (logLimit !== undefined) params.set('limit', logLimit.toString()); + + url = `${baseUrl}?${params.toString()}`; + this.logger.info('DashboardSvc', 'openWebSocket single mode', { + dryerId: this.state.activeDryerId, + timeRange, + startTime, + limit: logLimit + }); + } else { + // All dryers mode: now also supports time filtering for performance + const baseUrl = `${environment.wsUrl}/dashboard/dryers`.replace('http', 'ws'); + const params = new URLSearchParams(); + if (startTime) params.set('start_time', startTime); + if (logLimit !== undefined) params.set('limit', logLimit.toString()); + + const queryString = params.toString(); + url = queryString ? `${baseUrl}?${queryString}` : baseUrl; + + this.logger.info('DashboardSvc', 'openWebSocket all mode', { + timeRange, + startTime, + limit: logLimit + }); + } + this.connectionStatus$.next('connecting'); this.ws = new WebSocket(url); @@ -339,7 +473,7 @@ export class DashboardService implements OnDestroy { this.clearReconnectTimeout(); this.logger.warn('DashboardSvc', 'scheduleReconnect', { attempt: this.reconnectAttempts, delay }); this.reconnectTimeout = setTimeout(() => { - if (!this.lifecycleDestroyed && this.shouldReconnect) this.openWebSocket(); + if (!this.lifecycleDestroyed && this.shouldReconnect) this.openWebSocket(); // uses saved state.wsMode and state.activeDryerId }, delay); } @@ -372,6 +506,18 @@ export class DashboardService implements OnDestroy { // Track which summaries became unsorted (out-of-order timestamps) to re-sort once. const unsortedSummaries = new Set(); + // If this is history (initial load), clear old logs for the dryers in this batch + // to avoid mixing old time range data with new time range data + if (isHistory && logs.length > 0) { + const dryerIdsInBatch = new Set(logs.map(l => l.dryer_id)); + dryerIdsInBatch.forEach(dryerId => { + const summary = this.state.summaries.get(dryerId); + if (summary) { + summary.logs = []; // Clear old logs when new history arrives + } + }); + } + logs.forEach(raw => { // Normalize timestamp to local epoch let ts = raw.timestamp; diff --git a/web/src/app/pages/dashboard/dashboard.ts b/web/src/app/pages/dashboard/dashboard.ts index ce116cfb..d7207050 100644 --- a/web/src/app/pages/dashboard/dashboard.ts +++ b/web/src/app/pages/dashboard/dashboard.ts @@ -13,7 +13,9 @@ export class DashboardPage implements OnInit, OnDestroy { constructor(private dashboard: DashboardService) {} ngOnInit(): void { - this.dashboard.connect(); + // Connect in 'all' mode (legacy) - shows all dryers + // For individual dryer pages, use connect('single', dryerId) instead + this.dashboard.connect('all'); } ngOnDestroy(): void { diff --git a/web/src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.html b/web/src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.html index 0590fad4..8367835a 100644 --- a/web/src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.html +++ b/web/src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.html @@ -15,6 +15,25 @@
-
+
+
+ + +
+
+ Loading... +
+
+ + +
+
+
+ Loading... +
+
Loading data...
+
+
+
diff --git a/web/src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.scss b/web/src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.scss index de00b281..96aa6a04 100644 --- a/web/src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.scss +++ b/web/src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.scss @@ -139,3 +139,68 @@ padding: 3px; } } + +/* Initial chart loading (when no data) - solid background, spinner only */ +.chart-initial-loading { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, #1a1d23 0%, #2a2d33 100%); + display: flex; + align-items: center; + justify-content: center; + z-index: 10; + border-radius: clamp(6px, 1vw, 10px); + animation: fadeIn 0.2s ease-in; + + .spinner-border { + width: clamp(2.5rem, 5vw, 3rem); + height: clamp(2.5rem, 5vw, 3rem); + border-width: clamp(0.25rem, 0.5vw, 0.35rem); + } +} + +/* Chart loading overlay for reconnecting state (when has data) - transparent with blur */ +.chart-loading-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(26, 29, 35, 0.85); + backdrop-filter: blur(2px); + display: flex; + align-items: center; + justify-content: center; + z-index: 10; + border-radius: clamp(6px, 1vw, 10px); + animation: fadeIn 0.2s ease-in; + + .spinner-container { + text-align: center; + + .spinner-border { + width: clamp(2rem, 4vw, 3rem); + height: clamp(2rem, 4vw, 3rem); + border-width: clamp(0.2rem, 0.4vw, 0.3rem); + } + + .loading-text { + color: #f0f0f2; + font-size: clamp(12px, 1.6vw, 15px); + font-weight: 500; + opacity: 0.9; + } + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} diff --git a/web/src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.ts b/web/src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.ts index 5222955e..e6d38e65 100644 --- a/web/src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.ts +++ b/web/src/app/pages/embed/dryer-chart-embed/dryer-chart-embed.ts @@ -22,6 +22,7 @@ export class DryerChartEmbed implements OnInit, OnDestroy { dryerId!: number; summary?: DryerStateSummary; private subs: Subscription[] = []; + connectionStatus: string = ''; // Chart related private chart?: Highcharts.Chart; @@ -54,31 +55,51 @@ export class DryerChartEmbed implements OnInit, OnDestroy { ngOnInit(): void { this.logger.info('DryerChartEmbed', 'ngOnInit'); + // Get dryer ID from route first + this.subs.push(this.route.paramMap.subscribe(pm => { + const val = pm.get('dryerId'); + this.dryerId = val ? +val : NaN; + + // Connect in optimized 'single' mode for this specific dryer + if (Number.isFinite(this.dryerId) && !this.initiatedConnection) { + this.logger.info('DryerChartEmbed', 'Connecting in single mode', { dryerId: this.dryerId }); + try { + // No limit - load all logs for time range, frontend filtering handles performance + this.dashboard.connect('single', this.dryerId); + this.initiatedConnection = true; + } catch (err) { + this.logger.error('DryerChartEmbed', 'Failed to connect', err); + } + } + + this.pickSummary(); + })); + // Ensure websocket connection if (this.dashboard.getConnectionStatus && typeof this.dashboard.getConnectionStatus === 'function') { const sub = this.dashboard.getConnectionStatus().subscribe(st => { - if (st === 'closed' || st === 'error') { - if (!this.initiatedConnection) { - try { this.dashboard.connect(); this.initiatedConnection = true; } catch {} - } + this.connectionStatus = st; + if ((st === 'closed' || st === 'error') && !this.initiatedConnection && Number.isFinite(this.dryerId)) { + try { + this.dashboard.connect('single', this.dryerId); + this.initiatedConnection = true; + } catch {} } }); this.subs.push(sub); - } else { - try { this.dashboard.connect(); this.initiatedConnection = true; } catch {} } - this.subs.push(this.route.paramMap.subscribe(pm => { - const val = pm.get('dryerId'); - this.dryerId = val ? +val : NaN; - this.pickSummary(); - })); - this.subs.push(this.dashboard.getSummaries().subscribe(() => { this.pickSummary(); this.updateChart(); })); + // Subscribe to time range changes (for reconnection with new data) + this.subs.push(this.dashboard.getTimeRange().subscribe((r: TimeRangeKey) => { + this.timeRange = r; + this.updateChart(true); + })); + // Init chart after view paint setTimeout(() => this.initChart()); } @@ -381,8 +402,10 @@ export class DryerChartEmbed implements OnInit, OnDestroy { onRangeChange(r: TimeRangeKey) { if (r === this.timeRange) return; - this.timeRange = r; - this.updateChart(true); + this.logger.info('DryerChartEmbed', 'Time range changed', { from: this.timeRange, to: r }); + // This will trigger reconnection in single mode with new start_time + this.dashboard.setTimeRange(r); + // timeRange will be updated via subscription to getTimeRange() } ngOnDestroy(): void { diff --git a/web/src/app/pages/embed/dryer-control-embed/dryer-control-embed.html b/web/src/app/pages/embed/dryer-control-embed/dryer-control-embed.html index f0b7cbfd..9bef5d5c 100644 --- a/web/src/app/pages/embed/dryer-control-embed/dryer-control-embed.html +++ b/web/src/app/pages/embed/dryer-control-embed/dryer-control-embed.html @@ -76,7 +76,7 @@
@@ -84,6 +84,10 @@
-
Loading...
+
+
+ Loading... +
+
diff --git a/web/src/app/pages/embed/dryer-control-embed/dryer-control-embed.ts b/web/src/app/pages/embed/dryer-control-embed/dryer-control-embed.ts index 7280c3b9..d60df39f 100644 --- a/web/src/app/pages/embed/dryer-control-embed/dryer-control-embed.ts +++ b/web/src/app/pages/embed/dryer-control-embed/dryer-control-embed.ts @@ -39,26 +39,38 @@ export class DryerControlEmbed implements OnInit, OnDestroy { ngOnInit(): void { this.logger.info('DryerControlEmbed', 'ngOnInit'); + // Get dryer ID from route first + this.subs.push(this.route.paramMap.subscribe(pm => { + const val = pm.get('dryerId'); + this.dryerId = val ? +val : NaN; + + // Connect in optimized 'single' mode for this specific dryer + if (Number.isFinite(this.dryerId) && !this.initiatedConnection) { + this.logger.info('DryerControlEmbed', 'Connecting in single mode', { dryerId: this.dryerId }); + try { + this.dashboard.connect('single', this.dryerId, 1); // Control only needs current state + this.initiatedConnection = true; + } catch (err) { + this.logger.error('DryerControlEmbed', 'Failed to connect', err); + } + } + + this.pickSummary(); + })); + // Ensure websocket connection if (this.dashboard.getConnectionStatus && typeof this.dashboard.getConnectionStatus === 'function') { const sub = this.dashboard.getConnectionStatus().subscribe(st => { - if (st === 'closed' || st === 'error') { - if (!this.initiatedConnection) { - try { this.dashboard.connect(); this.initiatedConnection = true; } catch {} - } + if ((st === 'closed' || st === 'error') && !this.initiatedConnection && Number.isFinite(this.dryerId)) { + try { + this.dashboard.connect('single', this.dryerId, 1); + this.initiatedConnection = true; + } catch {} } }); this.subs.push(sub); - } else { - try { this.dashboard.connect(); this.initiatedConnection = true; } catch {} } - this.subs.push(this.route.paramMap.subscribe(pm => { - const val = pm.get('dryerId'); - this.dryerId = val ? +val : NaN; - this.pickSummary(); - })); - this.subs.push(this.dashboard.getSummaries().subscribe(() => { this.pickSummary(); })); @@ -165,7 +177,7 @@ export class DryerControlEmbed implements OnInit, OnDestroy { } async onStop() { - if (!this.summary || this.summary.status !== 'drying') return; + if (!this.summary || this.summary.status === 'pending') return; try { const res = await this.dashboard.stopDryer(this.dryerId); this.toast.show(`Stopped dryer #${this.dryerId}${res?.message ? ': ' + res.message : ''}`, { diff --git a/web/src/index.html b/web/src/index.html index ab246466..d292ee2d 100644 --- a/web/src/index.html +++ b/web/src/index.html @@ -6,8 +6,6 @@ - -