From ecbf4c9977c9bbbdac257a2ecc75900cafd87951 Mon Sep 17 00:00:00 2001 From: AddisonTech Date: Fri, 16 Oct 2026 16:00:12 +0000 Subject: [PATCH 01/10] Model a 2N data center in the simulator Utility, generator, ATS, switchboard, UPS A/B, PDUs and cooling with physically consistent values and demo scenarios that drive alarms. --- backend/alarm_engine.py | 73 ------ backend/config.py | 389 +++++++++++++++++++--------- backend/simulator.py | 545 +++++++++++++++++++++++++++++++--------- 3 files changed, 705 insertions(+), 302 deletions(-) delete mode 100644 backend/alarm_engine.py diff --git a/backend/alarm_engine.py b/backend/alarm_engine.py deleted file mode 100644 index 0ba70b3..0000000 --- a/backend/alarm_engine.py +++ /dev/null @@ -1,73 +0,0 @@ -"""Alarm processing engine aligned with ISA 18.2 principles.""" - -from typing import Dict, Any -from config import ALARM_THRESHOLDS, METERS -from database import upsert_alarm, clear_alarm - -# Build nominal lookup from config -_NOMINALS = {m["id"]: m for m in METERS} - - -def _get_nominal(meter_id: int, key: str) -> float: - return _NOMINALS[meter_id][key] - - -def process_reading(reading: Dict[str, Any]): - """Evaluate a single reading against alarm thresholds.""" - mid = reading["meter_id"] - nom_v = _get_nominal(mid, "nominal_voltage") - nom_i = _get_nominal(mid, "nominal_current") - - v = reading["voltage"] - i = reading["current"] - pf = reading["power_factor"] - freq = reading["frequency"] - - t = ALARM_THRESHOLDS - - # --- Voltage alarms --- - if v > nom_v * t["voltage_high_critical"]: - upsert_alarm(mid, "voltage", "High Voltage Critical", - v, nom_v * t["voltage_high_critical"], priority=1) - elif v > nom_v * t["voltage_high_warning"]: - upsert_alarm(mid, "voltage", "High Voltage Warning", - v, nom_v * t["voltage_high_warning"], priority=2) - clear_alarm(mid, "voltage") # clear critical if only warning now - elif v < nom_v * t["voltage_low_critical"]: - upsert_alarm(mid, "voltage", "Low Voltage Critical", - v, nom_v * t["voltage_low_critical"], priority=1) - elif v < nom_v * t["voltage_low_warning"]: - upsert_alarm(mid, "voltage", "Low Voltage Warning", - v, nom_v * t["voltage_low_warning"], priority=2) - else: - clear_alarm(mid, "voltage") - - # --- Current alarms --- - if i > nom_i * t["current_high_critical"]: - upsert_alarm(mid, "current", "Overcurrent Critical", - i, nom_i * t["current_high_critical"], priority=1) - elif i > nom_i * t["current_high_warning"]: - upsert_alarm(mid, "current", "High Current Warning", - i, nom_i * t["current_high_warning"], priority=2) - else: - clear_alarm(mid, "current") - - # --- Power factor alarms --- - if pf < t["pf_low_critical"]: - upsert_alarm(mid, "power_factor", "Low Power Factor Critical", - pf, t["pf_low_critical"], priority=1) - elif pf < t["pf_low_warning"]: - upsert_alarm(mid, "power_factor", "Low Power Factor Warning", - pf, t["pf_low_warning"], priority=3) - else: - clear_alarm(mid, "power_factor") - - # --- Frequency alarms --- - if freq > t["freq_high_critical"] or freq < t["freq_low_critical"]: - upsert_alarm(mid, "frequency", "Frequency Deviation Critical", - freq, 60.0, priority=1) - elif freq > t["freq_high_warning"] or freq < t["freq_low_warning"]: - upsert_alarm(mid, "frequency", "Frequency Deviation Warning", - freq, 60.0, priority=3) - else: - clear_alarm(mid, "frequency") diff --git a/backend/config.py b/backend/config.py index 36cd81e..4353a67 100644 --- a/backend/config.py +++ b/backend/config.py @@ -1,126 +1,287 @@ -"""System configuration for Power Dashboard.""" +"""System configuration for Power Dashboard. -# Polling interval in seconds -POLL_INTERVAL = 5 +Runtime settings come from environment variables so the same code runs the +public demo (simulated data) and a real site (Modbus TCP polling). +""" -# Database -DB_PATH = "power_dashboard.db" +import os -# WebSocket broadcast interval (seconds) -WS_INTERVAL = 2 +VERSION = "1.1.0" + + +def _env_bool(name: str, default: bool) -> bool: + raw = os.getenv(name) + if raw is None: + return default + return raw.strip().lower() in ("1", "true", "yes", "on") + + +def _env_float(name: str, default: float) -> float: + raw = os.getenv(name) + return float(raw) if raw not in (None, "") else default + + +# --------------------------------------------------------------------------- +# Runtime settings +# --------------------------------------------------------------------------- + +# "simulator" (default, used by the public demo) or "modbus" +DATA_SOURCE = os.getenv("DATA_SOURCE", "simulator").strip().lower() + +# Path to the Modbus device map (only used when DATA_SOURCE=modbus) +MODBUS_CONFIG = os.getenv("MODBUS_CONFIG", "modbus_config.json") + +# Scan rate for the live feed and alarm evaluation (seconds) +POLL_INTERVAL = _env_float("POLL_INTERVAL", 2.0) + +# How often a scan is written to the history table (seconds) +HISTORY_INTERVAL = _env_float("HISTORY_INTERVAL", 10.0) + +# SQLite database file +DB_PATH = os.getenv("DB_PATH", "power_dashboard.db") + +# Days of readings kept before pruning +RETENTION_DAYS = int(_env_float("RETENTION_DAYS", 7)) + +# Simulator: hours of history generated on startup so trends are never empty +BACKFILL_HOURS = _env_float("BACKFILL_HOURS", 24) + +# Simulator: seconds between automatic demo events (min, max) +SIM_EVENT_MIN = _env_float("SIM_EVENT_MIN", 150) +SIM_EVENT_MAX = _env_float("SIM_EVENT_MAX", 360) + +# Simulator: delay before the first live event after startup (seconds) +SIM_FIRST_EVENT = _env_float("SIM_FIRST_EVENT", 25) + +# Simulator: optional fixed random seed for repeatable runs +SIM_SEED = os.getenv("SIM_SEED") + +# Allow visitors to trigger demo events from the UI (simulator only) +DEMO_EVENTS_ENABLED = _env_bool("DEMO_EVENTS_ENABLED", True) + +# Comma separated list of allowed browser origins, "*" for any +CORS_ORIGINS = [o.strip() for o in os.getenv("CORS_ORIGINS", "*").split(",") if o.strip()] + +# ISA 18.2 shelving is time limited. Durations offered to the operator (minutes) +SHELVE_DURATIONS_MIN = [5, 15, 60] +SHELVE_MAX_MIN = 60 + +# Nominal system frequency +NOMINAL_FREQUENCY = 60.0 + + +# --------------------------------------------------------------------------- +# Facility topology +# +# A small 2N data center: utility service and standby generator feed an +# automatic transfer switch, which feeds the main switchboard. Two UPS +# systems (A side and B side) each feed two PDUs. Mechanical (cooling) load +# is fed directly from the switchboard. +# --------------------------------------------------------------------------- -# Meter hierarchy definition METERS = [ { - "id": 1, - "name": "Utility Feed", - "description": "Main utility supply point", - "type": "utility", - "parent_id": None, - "nominal_voltage": 480.0, - "nominal_current": 800.0, - "ct_ratio": 800, - "pt_ratio": 1, - }, - { - "id": 2, - "name": "Main Switchgear", - "description": "Main distribution switchgear", - "type": "switchgear", - "parent_id": 1, - "nominal_voltage": 480.0, - "nominal_current": 750.0, - "ct_ratio": 750, - "pt_ratio": 1, - }, - { - "id": 3, - "name": "Panel A", - "description": "Distribution Panel A - IT Load", - "type": "panel", - "parent_id": 2, - "nominal_voltage": 480.0, - "nominal_current": 400.0, - "ct_ratio": 400, - "pt_ratio": 1, - }, - { - "id": 4, - "name": "Panel B", - "description": "Distribution Panel B - Cooling Load", - "type": "panel", - "parent_id": 2, - "nominal_voltage": 480.0, - "nominal_current": 350.0, - "ct_ratio": 350, - "pt_ratio": 1, - }, - { - "id": 5, - "name": "Server Row A1", - "description": "Server row PDU - Rack group A1", - "type": "meter", - "parent_id": 3, - "nominal_voltage": 480.0, - "nominal_current": 120.0, - "ct_ratio": 120, - "pt_ratio": 1, - }, - { - "id": 6, - "name": "Server Row A2", - "description": "Server row PDU - Rack group A2", - "type": "meter", - "parent_id": 3, - "nominal_voltage": 480.0, - "nominal_current": 120.0, - "ct_ratio": 120, - "pt_ratio": 1, - }, - { - "id": 7, - "name": "CRAC Unit 1", - "description": "Computer Room Air Conditioner 1", - "type": "meter", - "parent_id": 4, - "nominal_voltage": 480.0, - "nominal_current": 180.0, - "ct_ratio": 180, - "pt_ratio": 1, - }, - { - "id": 8, - "name": "CRAC Unit 2", - "description": "Computer Room Air Conditioner 2", - "type": "meter", - "parent_id": 4, - "nominal_voltage": 480.0, - "nominal_current": 170.0, - "ct_ratio": 170, - "pt_ratio": 1, + "id": "UTIL-1", "name": "Utility Service", "type": "utility", "parent_id": None, + "description": "Utility service entrance, 480 V secondary of the service transformer", + "nominal_voltage": 480.0, "rated_current": 1600.0, "rated_kva": 1330.0, + }, + { + "id": "GEN-1", "name": "Standby Generator", "type": "generator", "parent_id": None, + "description": "750 kW diesel standby generator", + "nominal_voltage": 480.0, "rated_current": 1128.0, "rated_kva": 937.5, + }, + { + "id": "ATS-1", "name": "Automatic Transfer Switch", "type": "ats", "parent_id": None, + "description": "Open transition ATS, utility normal / generator emergency", + "nominal_voltage": 480.0, "rated_current": 1600.0, "rated_kva": 1330.0, + }, + { + "id": "MSB-1", "name": "Main Switchboard", "type": "switchgear", "parent_id": "ATS-1", + "description": "480 V main switchboard", + "nominal_voltage": 480.0, "rated_current": 1600.0, "rated_kva": 1330.0, + }, + { + "id": "UPS-A", "name": "UPS A", "type": "ups", "parent_id": "MSB-1", + "description": "400 kVA double conversion UPS, A side", + "nominal_voltage": 480.0, "rated_current": 481.0, "rated_kva": 400.0, + }, + { + "id": "UPS-B", "name": "UPS B", "type": "ups", "parent_id": "MSB-1", + "description": "400 kVA double conversion UPS, B side", + "nominal_voltage": 480.0, "rated_current": 481.0, "rated_kva": 400.0, + }, + { + "id": "MECH-1", "name": "Mechanical Panel", "type": "panel", "parent_id": "MSB-1", + "description": "Cooling plant: CRAH units, pumps, condenser fans", + "nominal_voltage": 480.0, "rated_current": 400.0, "rated_kva": 332.0, + }, + { + "id": "PDU-A1", "name": "PDU A1", "type": "pdu", "parent_id": "UPS-A", + "description": "150 kVA PDU, 480 to 208/120 V, server rows 1 and 2", + "nominal_voltage": 208.0, "rated_current": 416.0, "rated_kva": 150.0, + }, + { + "id": "PDU-A2", "name": "PDU A2", "type": "pdu", "parent_id": "UPS-A", + "description": "150 kVA PDU, 480 to 208/120 V, server rows 3 and 4", + "nominal_voltage": 208.0, "rated_current": 416.0, "rated_kva": 150.0, + }, + { + "id": "PDU-B1", "name": "PDU B1", "type": "pdu", "parent_id": "UPS-B", + "description": "150 kVA PDU, 480 to 208/120 V, server rows 1 and 2", + "nominal_voltage": 208.0, "rated_current": 416.0, "rated_kva": 150.0, + }, + { + "id": "PDU-B2", "name": "PDU B2", "type": "pdu", "parent_id": "UPS-B", + "description": "150 kVA PDU, 480 to 208/120 V, server rows 3 and 4", + "nominal_voltage": 208.0, "rated_current": 416.0, "rated_kva": 150.0, }, ] -# Alarm thresholds per meter type -ALARM_THRESHOLDS = { - "voltage_high_critical": 1.10, # 110% of nominal - "voltage_high_warning": 1.05, # 105% of nominal - "voltage_low_warning": 0.95, # 95% of nominal - "voltage_low_critical": 0.90, # 90% of nominal - "current_high_critical": 1.00, # 100% of nominal (full load) - "current_high_warning": 0.85, # 85% of nominal - "pf_low_warning": 0.85, # Power factor warning - "pf_low_critical": 0.75, # Power factor critical - "freq_high_warning": 60.5, # Hz - "freq_high_critical": 61.0, # Hz - "freq_low_warning": 59.5, # Hz - "freq_low_critical": 59.0, # Hz -} +METERS_BY_ID = {m["id"]: m for m in METERS} + + +# --------------------------------------------------------------------------- +# Alarm priorities (ISA 18.2: priority reflects consequence severity and the +# time available for the operator to respond) +# --------------------------------------------------------------------------- -# ISA 18.2 Priority labels ALARM_PRIORITIES = { - 1: "Critical", - 2: "High", - 3: "Medium", - 4: "Low", + 1: {"label": "Critical", "response": "Respond immediately (under 5 min)"}, + 2: {"label": "High", "response": "Respond promptly (under 15 min)"}, + 3: {"label": "Medium", "response": "Respond within the shift (under 1 h)"}, + 4: {"label": "Low", "response": "Respond when practical"}, } + + +# --------------------------------------------------------------------------- +# Master alarm database +# +# Each alarm was rationalized: one alarm per abnormal condition that needs an +# operator response, with a documented consequence and corrective action. +# +# kind HI / HIHI / LO / LOLO compare an analog value to a setpoint. +# DISCRETE alarms when the value is true. +# deadband hysteresis in engineering units before the alarm can clear +# on_delay consecutive scans in alarm before annunciating (anti-chatter) +# off_delay consecutive scans normal before returning to normal +# suppress designed (state based) suppression rule, see alarms.py +# --------------------------------------------------------------------------- + +def _pdu_alarms(pdu: str): + return [ + { + "tag": f"{pdu}.LOAD.HI", "meter_id": pdu, "parameter": "load_pct", "kind": "HI", + "setpoint": 80.0, "deadband": 3.0, "priority": 3, "on_delay": 2, "off_delay": 2, + "unit": "%", + "message": f"{pdu} load high", + "consequence": "Reduced margin before the PDU main breaker trips.", + "response": "Check for new rack load or a failed partner PDU. Plan load rebalancing.", + }, + { + "tag": f"{pdu}.LOAD.HIHI", "meter_id": pdu, "parameter": "load_pct", "kind": "HIHI", + "setpoint": 90.0, "deadband": 3.0, "priority": 2, "on_delay": 2, "off_delay": 2, + "unit": "%", + "message": f"{pdu} load very high", + "consequence": "PDU breaker trip drops every server on this side.", + "response": "Shed or move load now. Confirm the partner PDU can carry the racks.", + }, + ] + + +def _ups_alarms(ups: str): + return [ + { + "tag": f"{ups}.ONBATT", "meter_id": ups, "parameter": "on_battery", "kind": "DISCRETE", + "setpoint": 1, "deadband": 0, "priority": 1, "on_delay": 0, "off_delay": 1, + "unit": "", + "message": f"{ups} on battery", + "consequence": "Critical load is on limited battery runtime.", + "response": "Verify generator start and ATS transfer. Watch battery runtime.", + }, + { + "tag": f"{ups}.LOAD.HI", "meter_id": ups, "parameter": "load_pct", "kind": "HI", + "setpoint": 50.0, "deadband": 2.0, "priority": 2, "on_delay": 2, "off_delay": 2, + "unit": "%", + "message": f"{ups} load above 2N limit", + "consequence": "If the other side fails, this UPS cannot carry the full IT load.", + "response": "Rebalance IT load between A and B sides below 50 percent each.", + }, + { + "tag": f"{ups}.BATT.LO", "meter_id": ups, "parameter": "battery_soc", "kind": "LO", + "setpoint": 60.0, "deadband": 5.0, "priority": 2, "on_delay": 1, "off_delay": 2, + "unit": "%", + "message": f"{ups} battery charge low", + "consequence": "Reduced ride through time on the next utility event.", + "response": "Confirm the rectifier is charging. Avoid planned transfers until recharged.", + }, + ] + + +ALARM_POINTS = [ + { + "tag": "UTIL-1.FAIL", "meter_id": "UTIL-1", "parameter": "source_failed", "kind": "DISCRETE", + "setpoint": 1, "deadband": 0, "priority": 2, "on_delay": 0, "off_delay": 1, + "unit": "", + "message": "Utility power failure", + "consequence": "Facility is running on UPS battery and standby generator.", + "response": "Confirm generator pickup. Notify the utility and facility manager.", + }, + { + "tag": "UTIL-1.V.LO", "meter_id": "UTIL-1", "parameter": "voltage", "kind": "LO", + "setpoint": 432.0, "deadband": 4.8, "priority": 3, "on_delay": 0, "off_delay": 1, + "unit": "V", + "message": "Utility voltage low (sag)", + "consequence": "UPS may transfer to battery. Motors may drop out.", + "response": "Check UPS mode and mechanical equipment restart.", + "suppress": {"meter_id": "UTIL-1", "parameter": "source_failed", "equals": True, + "reason": "Utility failure alarm is active (cascade suppression)"}, + }, + { + "tag": "GEN-1.F.LO", "meter_id": "GEN-1", "parameter": "frequency", "kind": "LO", + "setpoint": 59.5, "deadband": 0.1, "priority": 3, "on_delay": 0, "off_delay": 1, + "unit": "Hz", + "message": "Generator frequency low", + "consequence": "UPS may stay on battery if frequency is out of tolerance.", + "response": "Check generator governor and block load step.", + "suppress": {"meter_id": "GEN-1", "parameter": "running", "equals": False, + "reason": "Generator not running (state based suppression)"}, + }, + { + "tag": "ATS-1.EMERG", "meter_id": "ATS-1", "parameter": "on_emergency", "kind": "DISCRETE", + "setpoint": 1, "deadband": 0, "priority": 3, "on_delay": 0, "off_delay": 1, + "unit": "", + "message": "ATS on emergency source", + "consequence": "Facility depends on generator fuel and runtime.", + "response": "Check fuel level and generator load. Track utility restoration.", + }, + { + "tag": "MSB-1.LOAD.HI", "meter_id": "MSB-1", "parameter": "load_pct", "kind": "HI", + "setpoint": 80.0, "deadband": 3.0, "priority": 3, "on_delay": 3, "off_delay": 3, + "unit": "%", + "message": "Main switchboard load high", + "consequence": "Main breaker approaching continuous rating.", + "response": "Review facility load growth and defer non critical load.", + }, + *_ups_alarms("UPS-A"), + *_ups_alarms("UPS-B"), + { + "tag": "MECH-1.PF.LO", "meter_id": "MECH-1", "parameter": "power_factor", "kind": "LO", + "setpoint": 0.85, "deadband": 0.01, "priority": 4, "on_delay": 2, "off_delay": 2, + "unit": "", + "message": "Mechanical panel power factor low", + "consequence": "Higher current and possible utility power factor penalty.", + "response": "Check the capacitor bank and VFD bypass status.", + }, + { + "tag": "MECH-1.LOAD.HI", "meter_id": "MECH-1", "parameter": "load_pct", "kind": "HI", + "setpoint": 85.0, "deadband": 3.0, "priority": 3, "on_delay": 3, "off_delay": 3, + "unit": "%", + "message": "Mechanical panel load high", + "consequence": "Cooling plant near feeder capacity.", + "response": "Check for stuck dampers or a failed CRAH unit forcing others to full speed.", + }, + *_pdu_alarms("PDU-A1"), + *_pdu_alarms("PDU-A2"), + *_pdu_alarms("PDU-B1"), + *_pdu_alarms("PDU-B2"), +] diff --git a/backend/simulator.py b/backend/simulator.py index 063a367..eab1806 100644 --- a/backend/simulator.py +++ b/backend/simulator.py @@ -1,129 +1,444 @@ -"""Modbus device simulator for Power Dashboard. +"""Data center power system simulator. -Generates realistic electrical meter readings using sine-wave modulation, -Gaussian noise, and occasional fault injection to simulate real power meters. +Models a small 2N data center so the public demo runs without hardware: + + Utility ---+ + +--> ATS --> Main Switchboard --+--> UPS A --> PDU A1, PDU A2 + Generator -+ +--> UPS B --> PDU B1, PDU B2 + +--> Mechanical panel + +Values are computed bottom up so they stay physically consistent: IT load at +each PDU rolls up through transformer and UPS losses to the switchboard, and +the switchboard load appears on whichever source the ATS has selected. + +Equipment behaves like the real thing: the generator cranks and warms up, the +ATS waits for a stable source before transferring, UPS systems ride through on +battery and recharge afterward, and cooling load drops out and restarts when +the switchboard loses power. + +Scenarios inject abnormal conditions (utility outage, voltage sag, PDU +overload, low power factor) so the alarm system has something to show. They +fire automatically at random intervals and can be triggered on demand. """ import math import random -import time from datetime import datetime, timezone -from typing import Dict, Any - -from config import METERS - - -class MeterSimulator: - """Simulates a single power meter with realistic electrical values.""" - - def __init__(self, meter_cfg: dict): - self.meter_id = meter_cfg["id"] - self.name = meter_cfg["name"] - self.nominal_voltage = meter_cfg["nominal_voltage"] - self.nominal_current = meter_cfg["nominal_current"] - - # Internal state - self._energy_kwh = random.uniform(1000, 50000) - self._phase_offset = random.uniform(0, 2 * math.pi) - self._drift = 0.0 - self._fault_active = False - self._fault_type = None - self._fault_counter = 0 - self._last_demand_window = [] - self._start_time = time.time() - - # Load profile: base load as fraction of nominal - self._base_load = random.uniform(0.45, 0.72) - - def _inject_fault(self): - """Occasionally inject a fault condition.""" - if not self._fault_active and random.random() < 0.0015: - self._fault_type = random.choice([ - "voltage_sag", "current_spike", "pf_drop", "freq_deviation" - ]) - self._fault_active = True - self._fault_counter = random.randint(3, 12) - - if self._fault_active: - self._fault_counter -= 1 - if self._fault_counter <= 0: - self._fault_active = False - self._fault_type = None - - def read(self) -> Dict[str, Any]: - """Return a simulated meter reading.""" - self._inject_fault() - - t = time.time() - self._start_time - - # Base voltage: 480V nominal with slow sine oscillation + noise - v_swing = math.sin(t / 47 + self._phase_offset) * 3.5 - v_noise = random.gauss(0, 0.4) - voltage = self.nominal_voltage + v_swing + v_noise - - # Current: follows a daily load profile approximated with a sine wave - load_cycle = 0.82 + 0.18 * math.sin(t / 3600 * math.pi - math.pi / 2) - i_base = self.nominal_current * self._base_load * load_cycle - i_noise = random.gauss(0, i_base * 0.015) - current = max(0.0, i_base + i_noise) - - # Power factor - pf_base = 0.92 + math.sin(t / 120 + self._phase_offset) * 0.025 - pf = min(1.0, max(0.70, pf_base + random.gauss(0, 0.005))) - - # Frequency - freq = 60.0 + math.sin(t / 23) * 0.08 + random.gauss(0, 0.03) - - # Apply faults - if self._fault_active: - ft = self._fault_type - p = self._fault_counter / 12 - if ft == "voltage_sag": - voltage *= (0.88 + 0.07 * p) - elif ft == "current_spike": - current *= (1.25 - 0.15 * p) - elif ft == "pf_drop": - pf *= (0.78 + 0.12 * p) - elif ft == "freq_deviation": - freq += (0.6 - 0.3 * p) * random.choice([-1, 1]) - - # Power - power_kw = (voltage * current * pf * math.sqrt(3)) / 1000.0 - - # Demand (15-minute rolling average approximation) - self._last_demand_window.append(power_kw) - if len(self._last_demand_window) > 180: - self._last_demand_window.pop(0) - demand_kw = sum(self._last_demand_window) / len(self._last_demand_window) - - # Energy accumulation - self._energy_kwh += power_kw * (5 / 3600) +from typing import Any, Dict, Optional, Tuple + +from config import METERS, METERS_BY_ID, NOMINAL_FREQUENCY + +SQRT3 = math.sqrt(3) + +SCENARIOS = { + "utility_outage": { + "label": "Utility outage", + "description": "Utility power is lost. UPS systems carry the IT load on battery, the " + "generator starts, the ATS transfers, then retransfers when utility returns.", + }, + "voltage_sag": { + "label": "Utility voltage sag", + "description": "A short utility voltage dip to about 85 percent. UPS systems ride " + "through on battery for a few seconds.", + }, + "pdu_overload": { + "label": "PDU overload", + "description": "New servers push one PDU past its load alarm limits, then the load " + "is rebalanced.", + }, + "pf_drop": { + "label": "Low power factor", + "description": "The cooling plant capacitor bank drops out and the mechanical panel " + "power factor falls below its alarm limit.", + }, +} + +# Base IT load per PDU (kW) and the cooling load ratio +_PDU_BASE_KW = {"PDU-A1": 74.0, "PDU-A2": 66.0, "PDU-B1": 71.0, "PDU-B2": 63.0} +_PDU_EFFICIENCY = 0.975 +_UPS_EFFICIENCY = 0.955 +_UPS_BATTERY_KWH = 50.0 +_UPS_CHARGE_KW = 10.0 +_HOUSE_KW = 18.0 +_MECH_RATIO = 0.48 + +# Equipment timing (seconds) +_GEN_START_DELAY = 2.0 # utility must be bad this long before engine start +_GEN_CRANK_TIME = 6.0 # crank to rated voltage and frequency +_ATS_GEN_STABLE = 4.0 # generator must be stable before transfer +_ATS_RETRANSFER = 30.0 # utility must be stable before retransfer +_GEN_COOLDOWN = 30.0 # unloaded run after retransfer +_UPS_WALK_IN = 3.0 # rectifier walk in after input returns +_MECH_RESTART = 20.0 # cooling equipment restart ramp + + +def _iso(epoch: float) -> str: + return datetime.fromtimestamp(epoch, timezone.utc).isoformat(timespec="milliseconds") + + +class FacilitySimulator: + """Stateful simulator. Call step(now) once per scan.""" + def __init__(self, seed: Optional[int] = None, auto_events: bool = True, + event_interval: Tuple[float, float] = (150.0, 360.0), + first_event_delay: float = 25.0): + self.rng = random.Random(seed) + self.auto_events = auto_events + self.event_interval = event_interval + self.first_event_delay = first_event_delay + + self._t_last: Optional[float] = None + self._next_event_at: Optional[float] = None + self.scenario: Optional[Dict[str, Any]] = None + + # Slow random walks (Ornstein Uhlenbeck) keep values drifting naturally + self._walk: Dict[str, float] = {k: 0.0 for k in ( + "util_v", "util_f", "gen_v", "mech", "mech_pf", *_PDU_BASE_KW.keys())} + + # Meter registers + sizes = {"utility": 1.2e6, "generator": 4.0e3, "ats": 1.2e6, "switchgear": 1.2e6, + "ups": 4.5e5, "panel": 4.0e5, "pdu": 2.0e5} + self._energy = {m["id"]: sizes[m["type"]] * self.rng.uniform(0.6, 1.4) for m in METERS} + self._demand: Dict[str, Optional[float]] = {m["id"]: None for m in METERS} + + # Equipment state + self.gen_state = "STANDBY" + self._gen_since = 0.0 + self._gen_running_since: Optional[float] = None + self.ats_position = "UTILITY" + self._transfer_at: Optional[float] = None + self._util_bad_since: Optional[float] = None + self._util_good_since: Optional[float] = 0.0 + self._source_ok_since: Optional[float] = 0.0 + self._mech_restart_since: Optional[float] = None + self.ups = { + side: {"soc": 100.0, "on_battery": False, "input_ok_since": 0.0} + for side in ("UPS-A", "UPS-B") + } + + # ------------------------------------------------------------------ + # Scenarios + # ------------------------------------------------------------------ + + def trigger(self, name: str, now: float, **params) -> Dict[str, Any]: + """Start a scenario. Raises KeyError if unknown, RuntimeError if busy.""" + if name not in SCENARIOS: + raise KeyError(name) + if self.scenario is not None: + raise RuntimeError(f"Scenario '{self.scenario['name']}' is still running") + + rng = self.rng + if name == "utility_outage": + p = {"duration": params.get("duration", rng.uniform(90, 150))} + elif name == "voltage_sag": + p = {"duration": params.get("duration", rng.uniform(4, 8)), + "depth": params.get("depth", rng.uniform(0.84, 0.875))} + elif name == "pdu_overload": + ramp = params.get("ramp", 40.0) + hold = params.get("hold", rng.uniform(60, 90)) + p = {"pdu": params.get("pdu", rng.choice(list(_PDU_BASE_KW))), + "target_pct": params.get("target_pct", rng.uniform(86, 95)), + "ramp": ramp, "hold": hold, "duration": 2 * ramp + hold} + else: # pf_drop + p = {"duration": params.get("duration", rng.uniform(70, 130)), + "pf": params.get("pf", rng.uniform(0.78, 0.82))} + + self.scenario = {"name": name, "label": SCENARIOS[name]["label"], + "started_at": now, "params": p} + return self.scenario_info(now) + + def scenario_info(self, now: float) -> Optional[Dict[str, Any]]: + if self.scenario is None: + return None return { - "meter_id": self.meter_id, - "voltage": round(voltage, 2), - "current": round(current, 2), - "power_kw": round(power_kw, 2), - "power_factor": round(pf, 4), - "energy_kwh": round(self._energy_kwh, 2), - "frequency": round(freq, 3), - "demand_kw": round(demand_kw, 2), - "timestamp": datetime.now(timezone.utc).isoformat(), + "name": self.scenario["name"], + "label": self.scenario["label"], + "started_at": _iso(self.scenario["started_at"]), + "elapsed_s": round(now - self.scenario["started_at"], 1), } + def _scenario_elapsed(self, name: str, now: float) -> Optional[float]: + if self.scenario and self.scenario["name"] == name: + return now - self.scenario["started_at"] + return None + + def _update_scenario(self, now: float): + sc = self.scenario + if sc is not None: + elapsed = now - sc["started_at"] + done = elapsed >= sc["params"]["duration"] + if sc["name"] == "utility_outage": + done = done and self.ats_position == "UTILITY" and self.gen_state == "STANDBY" + if done: + self.scenario = None + self._schedule_next(now) + + if self._next_event_at is None: + self._next_event_at = now + self.first_event_delay -class DeviceSimulator: - """Manages all meter simulators.""" + if self.auto_events and self.scenario is None and now >= self._next_event_at: + weights = {"voltage_sag": 0.3, "pdu_overload": 0.25, "pf_drop": 0.25, + "utility_outage": 0.2} + name = self.rng.choices(list(weights), weights=list(weights.values()))[0] + self.trigger(name, now) - def __init__(self): - self._meters: Dict[int, MeterSimulator] = {} - for cfg in METERS: - self._meters[cfg["id"]] = MeterSimulator(cfg) + def _schedule_next(self, now: float): + lo, hi = self.event_interval + self._next_event_at = now + self.rng.uniform(lo, hi) - def read_all(self) -> Dict[int, Dict[str, Any]]: - return {mid: m.read() for mid, m in self._meters.items()} + def schedule_event_at(self, at: float): + """Set the time of the next automatic event.""" + self._next_event_at = at - def read_meter(self, meter_id: int) -> Dict[str, Any]: - if meter_id not in self._meters: - raise ValueError(f"Meter {meter_id} not found") - return self._meters[meter_id].read() + # ------------------------------------------------------------------ + # Helpers + # ------------------------------------------------------------------ + + def _ou(self, key: str, dt: float, sigma: float, tau: float) -> float: + """Advance an Ornstein Uhlenbeck random walk with mean 0.""" + decay = math.exp(-dt / tau) + x = self._walk[key] * decay + sigma * math.sqrt(1 - decay * decay) * self.rng.gauss(0, 1) + self._walk[key] = x + return x + + def _noise(self, sigma: float) -> float: + return self.rng.gauss(0, sigma) + + def _register(self, mid: str, kw: float, dt: float) -> Tuple[float, float]: + self._energy[mid] += max(kw, 0.0) * dt / 3600.0 + d = self._demand[mid] + d = kw if d is None else d + (kw - d) * min(1.0, dt / 900.0) # 15 min demand + self._demand[mid] = d + return self._energy[mid], d + + # ------------------------------------------------------------------ + # Main step + # ------------------------------------------------------------------ + + def step(self, now: float) -> Dict[str, Dict[str, Any]]: + dt = 2.0 if self._t_last is None else min(max(now - self._t_last, 0.0), 3600.0) + self._t_last = now + self._update_scenario(now) + + hour = (now % 86400) / 3600.0 + it_profile = 1.0 + 0.04 * math.sin(2 * math.pi * (hour - 10) / 24) + temp_profile = 1.0 + 0.12 * math.sin(2 * math.pi * (hour - 9) / 24) + + # --- Utility source ------------------------------------------------ + outage_t = self._scenario_elapsed("utility_outage", now) + util_available = not (outage_t is not None and outage_t < self.scenario["params"]["duration"]) + sag_t = self._scenario_elapsed("voltage_sag", now) + v_factor = 1.0 + if sag_t is not None and sag_t < self.scenario["params"]["duration"]: + v_factor = self.scenario["params"]["depth"] + + util_walk_v = self._ou("util_v", dt, 2.5, 600) + util_walk_f = self._ou("util_f", dt, 0.012, 120) + if util_available: + v_util = (482.0 + util_walk_v + self._noise(0.6)) * v_factor + f_util = NOMINAL_FREQUENCY + util_walk_f + self._noise(0.004) + else: + v_util, f_util = 0.0, 0.0 + util_ok = v_util >= 0.80 * 480.0 # ATS normal source dropout + + if util_ok: + self._util_bad_since = None + if self._util_good_since is None: + self._util_good_since = now + else: + self._util_good_since = None + if self._util_bad_since is None: + self._util_bad_since = now + + # --- Generator and ATS controller ----------------------------------- + start_signal = (self._util_bad_since is not None and now - self._util_bad_since >= _GEN_START_DELAY) \ + or self.ats_position == "GENERATOR" + + if self.gen_state == "STANDBY" and start_signal: + self.gen_state, self._gen_since = "CRANKING", now + elif self.gen_state == "CRANKING": + if not start_signal: + self.gen_state, self._gen_since = "STANDBY", now + elif now - self._gen_since >= _GEN_CRANK_TIME: + self.gen_state, self._gen_since = "RUNNING", now + self._gen_running_since = now + elif self.gen_state == "RUNNING" and not start_signal and self.ats_position == "UTILITY": + self.gen_state, self._gen_since = "COOLDOWN", now + elif self.gen_state == "COOLDOWN": + if start_signal: + self.gen_state, self._gen_since = "RUNNING", now + self._gen_running_since = now + elif now - self._gen_since >= _GEN_COOLDOWN: + self.gen_state, self._gen_since = "STANDBY", now + self._gen_running_since = None + + gen_running = self.gen_state in ("RUNNING", "COOLDOWN") + if self.ats_position == "UTILITY" and not util_ok and self.gen_state == "RUNNING" \ + and now - self._gen_running_since >= _ATS_GEN_STABLE: + self.ats_position, self._transfer_at = "GENERATOR", now + elif self.ats_position == "GENERATOR" and util_ok \ + and now - self._util_good_since >= _ATS_RETRANSFER: + self.ats_position, self._transfer_at = "UTILITY", now + + gen_walk_v = self._ou("gen_v", dt, 1.5, 60) + if gen_running: + v_gen = 480.0 + gen_walk_v + self._noise(0.8) + f_gen = NOMINAL_FREQUENCY + self._noise(0.04) + if self.ats_position == "GENERATOR" and self._transfer_at is not None: + since = now - self._transfer_at + if since < 6.0: # frequency dip from the block load step + f_gen -= 1.2 * math.exp(-since / 1.5) + elif self.gen_state == "CRANKING": + ramp = min(1.0, (now - self._gen_since) / _GEN_CRANK_TIME) + v_gen, f_gen = 480.0 * ramp, NOMINAL_FREQUENCY * ramp + else: + v_gen, f_gen = 0.0, 0.0 + + if self.ats_position == "UTILITY": + v_src, f_src = v_util, f_util + else: + v_src, f_src = v_gen, f_gen + src_live = v_src >= 0.5 * 480.0 + if src_live: + if self._source_ok_since is None: + self._source_ok_since = now + else: + self._source_ok_since = None + + # --- PDUs (IT load) -------------------------------------------------- + readings: Dict[str, Dict[str, Any]] = {} + overload_t = self._scenario_elapsed("pdu_overload", now) + ups_out: Dict[str, Dict[str, float]] = {"UPS-A": {"kw": 0.0, "kvar": 0.0}, + "UPS-B": {"kw": 0.0, "kvar": 0.0}} + it_total = 0.0 + for pdu, base in _PDU_BASE_KW.items(): + cfg = METERS_BY_ID[pdu] + walk = self._ou(pdu, dt, 0.025, 1800) + kw = base * it_profile * (1 + walk) * (1 + self._noise(0.006)) + if overload_t is not None and self.scenario["params"]["pdu"] == pdu: + p = self.scenario["params"] + target_kw = cfg["rated_kva"] * p["target_pct"] / 100.0 * 0.98 + shape = min(1.0, overload_t / p["ramp"], + max(0.0, (p["duration"] - overload_t) / p["ramp"])) + kw = kw * (1 - shape) + target_kw * shape + pf = min(0.995, 0.98 + self._noise(0.003)) + kva = kw / pf + v = 208.0 * (1 - 0.012 * kva / cfg["rated_kva"]) + self._noise(0.25) + side = "UPS-A" if pdu.startswith("PDU-A") else "UPS-B" + kw_in = kw / _PDU_EFFICIENCY + ups_out[side]["kw"] += kw_in + ups_out[side]["kvar"] += kw_in * math.tan(math.acos(0.97)) + it_total += kw + readings[pdu] = self._reading(pdu, now, dt, v, kva, kw, pf, f_src or NOMINAL_FREQUENCY, + status="Normal") + + # --- UPS ------------------------------------------------------------- + input_ok = 0.88 * 480.0 <= v_src <= 1.12 * 480.0 and 55.0 <= f_src <= 65.0 + ups_in_kw = 0.0 + for side, st in self.ups.items(): + cfg = METERS_BY_ID[side] + if input_ok: + if st["input_ok_since"] is None: + st["input_ok_since"] = now + else: + st["input_ok_since"] = None + st["on_battery"] = st["input_ok_since"] is None or now - st["input_ok_since"] < _UPS_WALK_IN + + out_kw = ups_out[side]["kw"] + out_kva = math.hypot(out_kw, ups_out[side]["kvar"]) + if st["on_battery"]: + st["soc"] = max(0.0, st["soc"] - out_kw / 0.96 * dt / 3600.0 / _UPS_BATTERY_KWH * 100.0) + in_kw = 0.0 + else: + charge = _UPS_CHARGE_KW if st["soc"] < 100.0 else 0.0 + st["soc"] = min(100.0, st["soc"] + charge * dt / 3600.0 / _UPS_BATTERY_KWH * 100.0) + in_kw = out_kw / _UPS_EFFICIENCY + charge + ups_in_kw += in_kw + runtime = st["soc"] / 100.0 * _UPS_BATTERY_KWH / max(out_kw, 1.0) * 60.0 + v_out = 480.0 + self._noise(0.4) + readings[side] = self._reading( + side, now, dt, v_out, out_kva, out_kw, out_kw / out_kva if out_kva else 1.0, + NOMINAL_FREQUENCY if st["on_battery"] else (f_src or NOMINAL_FREQUENCY), + status="On Battery" if st["on_battery"] else "Online", + on_battery=st["on_battery"], battery_soc=round(st["soc"], 1), + battery_runtime_min=round(runtime, 1), input_kw=round(in_kw, 1), + ) + + # --- Mechanical panel (not on UPS) ----------------------------------- + cfg = METERS_BY_ID["MECH-1"] + mech_walk = self._ou("mech", dt, 0.04, 900) + pf_walk = self._ou("mech_pf", dt, 0.008, 300) + mech_pf = 0.90 + pf_walk + self._noise(0.002) + pf_t = self._scenario_elapsed("pf_drop", now) + if pf_t is not None: + p = self.scenario["params"] + shape = min(1.0, pf_t / 10.0, max(0.0, (p["duration"] - pf_t) / 10.0)) + mech_pf = mech_pf * (1 - shape) + (p["pf"] + self._noise(0.004)) * shape + if src_live: + if self._mech_restart_since is not None: + ramp = min(1.0, (now - self._mech_restart_since) / _MECH_RESTART) + if ramp >= 1.0: + self._mech_restart_since = None + else: + ramp = 1.0 + mech_kw = _MECH_RATIO * it_total * temp_profile * (1 + mech_walk) * ramp + mech_status = "Restarting" if ramp < 1.0 else "Normal" + house_kw = _HOUSE_KW + else: + self._mech_restart_since = now + mech_kw, house_kw, mech_status = 0.0, 0.0, "De-energized" + mech_kva = mech_kw / mech_pf + mech_v = v_src * (1 - 0.006 * mech_kva / cfg["rated_kva"]) if src_live else 0.0 + readings["MECH-1"] = self._reading("MECH-1", now, dt, mech_v, mech_kva, mech_kw, + mech_pf if mech_kw > 0 else 0.0, f_src, status=mech_status) + + # --- Main switchboard and ATS ---------------------------------------- + total_kw = ups_in_kw + mech_kw + house_kw + total_kvar = ups_in_kw * math.tan(math.acos(0.99)) \ + + mech_kw * math.tan(math.acos(max(mech_pf, 0.5))) \ + + house_kw * math.tan(math.acos(0.95)) + total_kva = math.hypot(total_kw, total_kvar) + msb_pf = total_kw / total_kva if total_kva else 0.0 + msb_v = v_src * (1 - 0.004 * total_kva / 1330.0) if src_live else 0.0 + readings["MSB-1"] = self._reading("MSB-1", now, dt, msb_v, total_kva, total_kw, msb_pf, f_src, + status="Energized" if src_live else "De-energized") + on_gen = self.ats_position == "GENERATOR" + readings["ATS-1"] = self._reading( + "ATS-1", now, dt, v_src, total_kva, total_kw, msb_pf, f_src, + status="On Generator" if on_gen else "On Utility", + position=self.ats_position, on_emergency=on_gen, + ) + + # --- Sources --------------------------------------------------------- + util_load = (total_kva, total_kw, msb_pf) if not on_gen else (0.0, 0.0, 0.0) + util_status = "Failed" if not util_available else ("Sag" if v_factor < 1.0 else "Normal") + readings["UTIL-1"] = self._reading("UTIL-1", now, dt, v_util, *util_load, f_util, + status=util_status, source_failed=not util_available) + gen_load = (total_kva, total_kw, msb_pf) if on_gen else (0.0, 0.0, 0.0) + readings["GEN-1"] = self._reading("GEN-1", now, dt, v_gen, *gen_load, f_gen, + status=self.gen_state.title(), + running=self.gen_state == "RUNNING", + gen_state=self.gen_state) + + return {m["id"]: readings[m["id"]] for m in METERS} + + def _reading(self, mid: str, now: float, dt: float, voltage: float, kva: float, kw: float, + pf: float, freq: float, status: str, **extra) -> Dict[str, Any]: + cfg = METERS_BY_ID[mid] + current = kva * 1000.0 / (SQRT3 * voltage) if voltage > 1.0 else 0.0 + energy, demand = self._register(mid, kw, dt) + return { + "meter_id": mid, + "timestamp": _iso(now), + "epoch": round(now, 3), + "voltage": round(max(voltage, 0.0), 1), + "current": round(current, 1), + "power_kw": round(kw, 1), + "power_factor": round(pf, 3), + "frequency": round(max(freq, 0.0), 2), + "energy_kwh": round(energy, 1), + "demand_kw": round(demand, 1), + "load_pct": round(current / cfg["rated_current"] * 100.0, 1), + "status": status, + **extra, + } From a8b3ab28d16cecb120c5fe264a1cd79b309eb29a Mon Sep 17 00:00:00 2001 From: AddisonTech Date: Fri, 16 Oct 2026 16:00:19 +0000 Subject: [PATCH 02/10] Add ISA 18.2 alarm state machine Acknowledge, return to normal, time limited shelving, designed suppression, deadband and on/off delays, alarm rate KPIs. --- backend/alarms.py | 423 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 backend/alarms.py diff --git a/backend/alarms.py b/backend/alarms.py new file mode 100644 index 0000000..2ca21bc --- /dev/null +++ b/backend/alarms.py @@ -0,0 +1,423 @@ +"""Alarm management aligned with ANSI/ISA-18.2. + +Each configured alarm point runs the ISA 18.2 alarm state model: + + A NORMAL process normal, nothing to acknowledge + B UNACK process abnormal, alarm not yet acknowledged + C ACKED process abnormal, alarm acknowledged by the operator + D RTN_UNACK process returned to normal before anyone acknowledged it + F SHELVED temporarily removed from service by the operator (time limited) + G SUPPRESSED suppressed by design, based on plant state + +Transitions: + + NORMAL --condition--> UNACK + UNACK --acknowledge--> ACKED + UNACK --clears--> RTN_UNACK + ACKED --clears--> NORMAL + RTN_UNACK --acknowledge--> NORMAL + RTN_UNACK --condition--> UNACK (re-alarm) + any of A to D --shelve--> SHELVED --unshelve or timer--> UNACK or NORMAL + any of A to D --design rule--> SUPPRESSED --rule clears--> UNACK or NORMAL + +Conditions use a deadband (hysteresis) and on/off delays so a noisy value +near the setpoint does not chatter. Every transition is written to the +alarm journal through registered listeners. + +This module is pure Python with no I/O so it can be tested in isolation. +""" + +import threading +from collections import deque +from datetime import datetime, timezone +from enum import Enum +from typing import Any, Callable, Dict, Iterable, List, Optional + +from config import ALARM_PRIORITIES, SHELVE_MAX_MIN + + +class AlarmState(str, Enum): + NORMAL = "NORMAL" + UNACK = "UNACK" + ACKED = "ACKED" + RTN_UNACK = "RTN_UNACK" + SHELVED = "SHELVED" + SUPPRESSED = "SUPPRESSED" + + +STATE_LABELS = { + AlarmState.NORMAL: "Normal", + AlarmState.UNACK: "Unacknowledged", + AlarmState.ACKED: "Acknowledged", + AlarmState.RTN_UNACK: "Returned to normal, unacknowledged", + AlarmState.SHELVED: "Shelved", + AlarmState.SUPPRESSED: "Suppressed by design", +} + +# States shown on the operator's active alarm list +ANNUNCIATED = (AlarmState.UNACK, AlarmState.ACKED, AlarmState.RTN_UNACK) +# States that still need an acknowledgement +NEEDS_ACK = (AlarmState.UNACK, AlarmState.RTN_UNACK) + +# Journal event types +EV_ALARM = "ALARM" +EV_ACK = "ACK" +EV_RTN = "RTN" +EV_SHELVE = "SHELVE" +EV_UNSHELVE = "UNSHELVE" +EV_SUPPRESS = "SUPPRESS" +EV_UNSUPPRESS = "UNSUPPRESS" + +# ISA 18.2 performance targets for annunciated alarms per operator per 10 minutes +RATE_ACCEPTABLE = 1 +RATE_MANAGEABLE = 2 +RATE_FLOOD = 10 +RATE_WINDOW_S = 600 + + +class AlarmActionError(Exception): + """An operator action is not valid in the alarm's current state.""" + + +def _iso(epoch: float) -> str: + return datetime.fromtimestamp(epoch, timezone.utc).isoformat(timespec="milliseconds") + + +class AlarmPoint: + """Runtime state for one configured alarm.""" + + def __init__(self, definition: Dict[str, Any], meter_name: str): + self.d = definition + self.tag: str = definition["tag"] + self.meter_name = meter_name + self.state = AlarmState.NORMAL + self.condition = False + self._on_count = 0 + self._off_count = 0 + self.value: Optional[float] = None + self.alarm_value: Optional[float] = None + self.activated_at: Optional[float] = None + self.ack_at: Optional[float] = None + self.ack_by: Optional[str] = None + self.rtn_at: Optional[float] = None + self.shelved_at: Optional[float] = None + self.shelved_until: Optional[float] = None + self.shelved_by: Optional[str] = None + self.shelve_reason: Optional[str] = None + self.suppress_reason: Optional[str] = None + self.evaluated = False + + # Condition with deadband and debounce ----------------------------------- + + def _raw(self, value) -> bool: + kind, sp, db = self.d["kind"], self.d["setpoint"], self.d.get("deadband", 0.0) + if kind == "DISCRETE": + return bool(value) == bool(sp) + if kind in ("HI", "HIHI"): + return value > (sp - db if self.condition else sp) + if kind in ("LO", "LOLO"): + return value < (sp + db if self.condition else sp) + raise ValueError(f"Unknown alarm kind {kind}") + + def in_alarm_now(self) -> bool: + """Current value against the setpoint, ignoring deadband and delays.""" + if self.value is None: + return False + was, self.condition = self.condition, False + try: + return self._raw(self.value) + finally: + self.condition = was + + def update_condition(self, value) -> bool: + """Feed a new value. Returns the debounced condition.""" + self.value = value + raw = self._raw(value) + if raw: + self._off_count = 0 + if not self.condition: + self._on_count += 1 + if self._on_count > self.d.get("on_delay", 0): + self.condition = True + self._on_count = 0 + else: + self._on_count = 0 + if self.condition: + self._off_count += 1 + if self._off_count > self.d.get("off_delay", 0): + self.condition = False + self._off_count = 0 + return self.condition + + def to_dict(self) -> Dict[str, Any]: + d = self.d + pr = d["priority"] + return { + "tag": self.tag, + "meter_id": d["meter_id"], + "meter_name": self.meter_name, + "message": d["message"], + "kind": d["kind"], + "parameter": d["parameter"], + "priority": pr, + "priority_label": ALARM_PRIORITIES[pr]["label"], + "state": self.state.value, + "state_label": STATE_LABELS[self.state], + "condition_active": self.condition, + "value": _num(self.value), + "alarm_value": _num(self.alarm_value), + "setpoint": d["setpoint"], + "unit": d.get("unit", ""), + "activated_at": _iso(self.activated_at) if self.activated_at else None, + "ack_at": _iso(self.ack_at) if self.ack_at else None, + "ack_by": self.ack_by, + "rtn_at": _iso(self.rtn_at) if self.rtn_at else None, + "shelved_at": _iso(self.shelved_at) if self.shelved_at else None, + "shelved_until": _iso(self.shelved_until) if self.shelved_until else None, + "shelved_by": self.shelved_by, + "shelve_reason": self.shelve_reason, + "suppress_reason": self.suppress_reason, + "consequence": d.get("consequence"), + "response": d.get("response"), + } + + +def _num(v): + if isinstance(v, bool): + return int(v) + return v + + +class AlarmManager: + """Evaluates alarm points against readings and handles operator actions.""" + + def __init__(self, definitions: Iterable[Dict[str, Any]], meter_names: Dict[str, str]): + self.points: Dict[str, AlarmPoint] = { + d["tag"]: AlarmPoint(d, meter_names.get(d["meter_id"], d["meter_id"])) + for d in definitions + } + self._listeners: List[Callable[[Dict[str, Any]], None]] = [] + self._recent_alarms: deque = deque() + self._lock = threading.RLock() + + # Listeners -------------------------------------------------------------- + + def add_listener(self, fn: Callable[[Dict[str, Any]], None]): + self._listeners.append(fn) + + def _emit(self, p: AlarmPoint, event: str, now: float, operator: str = "system", + note: Optional[str] = None): + if event == EV_ALARM: + self._recent_alarms.append(now) + record = { + "epoch": now, + "timestamp": _iso(now), + "tag": p.tag, + "meter_id": p.d["meter_id"], + "meter_name": p.meter_name, + "event": event, + "state": p.state.value, + "priority": p.d["priority"], + "value": _num(p.value), + "setpoint": p.d["setpoint"], + "unit": p.d.get("unit", ""), + "message": p.d["message"], + "operator": operator, + "note": note, + } + for fn in self._listeners: + fn(record) + + # Scan evaluation -------------------------------------------------------- + + def evaluate(self, readings: Dict[str, Dict[str, Any]], now: float) -> bool: + """Evaluate every alarm point against one scan. Returns True if anything changed.""" + changed = False + with self._lock: + for p in self.points.values(): + before = p.state + self._evaluate_point(p, readings, now) + changed = changed or p.state != before + return changed + + def _evaluate_point(self, p: AlarmPoint, readings, now: float): + reading = readings.get(p.d["meter_id"]) + value = reading.get(p.d["parameter"]) if reading else None + if value is None: + return # bad or missing data: hold the last state + condition = p.update_condition(value) + + # Time limited shelving + if p.state == AlarmState.SHELVED: + if p.shelved_until is not None and now >= p.shelved_until: + self._unshelve(p, now, "system", "Shelve time expired") + return + + # Designed (state based) suppression + rule = p.d.get("suppress") + suppressed = False + if rule: + src = readings.get(rule["meter_id"]) + if src is not None and src.get(rule["parameter"]) is not None: + suppressed = bool(src.get(rule["parameter"])) == bool(rule["equals"]) + else: + suppressed = p.state == AlarmState.SUPPRESSED + first_scan = not p.evaluated + p.evaluated = True + if suppressed and p.state != AlarmState.SUPPRESSED: + p.state = AlarmState.SUPPRESSED + p.suppress_reason = rule.get("reason") + if not first_scan: # starting up suppressed is not an event + self._emit(p, EV_SUPPRESS, now, note=p.suppress_reason) + return + if p.state == AlarmState.SUPPRESSED: + if suppressed: + return + p.suppress_reason = None + self._return_to_service(p, now, EV_UNSUPPRESS, "system", "Suppression condition cleared") + return + + # Core ISA 18.2 state model + if p.state == AlarmState.NORMAL and condition: + self._annunciate(p, now) + elif p.state == AlarmState.RTN_UNACK and condition: + self._annunciate(p, now) + elif p.state == AlarmState.UNACK and not condition: + p.state = AlarmState.RTN_UNACK + p.rtn_at = now + self._emit(p, EV_RTN, now) + elif p.state == AlarmState.ACKED and not condition: + p.state = AlarmState.NORMAL + p.rtn_at = now + self._emit(p, EV_RTN, now) + + def _annunciate(self, p: AlarmPoint, now: float): + p.state = AlarmState.UNACK + p.activated_at = now + p.alarm_value = p.value + p.ack_at = p.ack_by = p.rtn_at = None + self._emit(p, EV_ALARM, now) + + def _return_to_service(self, p: AlarmPoint, now: float, event: str, operator: str, note: str): + # Re-evaluate from the live value so a stale debounced condition from + # while the alarm was out of service does not annunciate. + p.condition = p.in_alarm_now() + p.state = AlarmState.NORMAL + self._emit(p, event, now, operator, note) + if p.condition: + self._annunciate(p, now) + + # Operator actions ------------------------------------------------------- + + def _get(self, tag: str) -> AlarmPoint: + if tag not in self.points: + raise KeyError(tag) + return self.points[tag] + + def acknowledge(self, tag: str, now: float, operator: str = "operator") -> Dict[str, Any]: + with self._lock: + p = self._get(tag) + if p.state == AlarmState.UNACK: + p.state = AlarmState.ACKED + elif p.state == AlarmState.RTN_UNACK: + p.state = AlarmState.NORMAL + else: + raise AlarmActionError(f"{tag} is {STATE_LABELS[p.state].lower()}, nothing to acknowledge") + p.ack_at, p.ack_by = now, operator + self._emit(p, EV_ACK, now, operator) + return p.to_dict() + + def shelve(self, tag: str, minutes: float, now: float, operator: str = "operator", + reason: Optional[str] = None) -> Dict[str, Any]: + with self._lock: + p = self._get(tag) + if p.state in (AlarmState.SHELVED, AlarmState.SUPPRESSED): + raise AlarmActionError(f"{tag} is {STATE_LABELS[p.state].lower()}") + if not 0 < minutes <= SHELVE_MAX_MIN: + raise AlarmActionError(f"Shelve time must be between 1 and {SHELVE_MAX_MIN} minutes") + p.state = AlarmState.SHELVED + p.shelved_at = now + p.shelved_until = now + minutes * 60 + p.shelved_by = operator + p.shelve_reason = (reason or "").strip() or "Shelved by operator" + self._emit(p, EV_SHELVE, now, operator, f"{p.shelve_reason} ({minutes:g} min)") + return p.to_dict() + + def unshelve(self, tag: str, now: float, operator: str = "operator") -> Dict[str, Any]: + with self._lock: + p = self._get(tag) + if p.state != AlarmState.SHELVED: + raise AlarmActionError(f"{tag} is not shelved") + self._unshelve(p, now, operator, "Unshelved by operator") + return p.to_dict() + + def _unshelve(self, p: AlarmPoint, now: float, operator: str, note: str): + p.shelved_at = p.shelved_until = p.shelved_by = p.shelve_reason = None + self._return_to_service(p, now, EV_UNSHELVE, operator, note) + + # Views ------------------------------------------------------------------ + + def alarm_list(self) -> List[Dict[str, Any]]: + """Every alarm point that is not NORMAL, highest priority and newest first.""" + with self._lock: + items = [p.to_dict() for p in self.points.values() if p.state != AlarmState.NORMAL] + items.sort(key=lambda a: (a["priority"], -(_ts(a["activated_at"])))) + return items + + def definitions(self) -> List[Dict[str, Any]]: + out = [] + for p in self.points.values(): + d = {k: v for k, v in p.d.items() if k != "suppress"} + d["meter_name"] = p.meter_name + d["priority_label"] = ALARM_PRIORITIES[d["priority"]]["label"] + d["suppression"] = p.d["suppress"]["reason"] if p.d.get("suppress") else None + out.append(d) + return out + + def alarm_rate(self, now: float) -> int: + with self._lock: + while self._recent_alarms and self._recent_alarms[0] < now - RATE_WINDOW_S: + self._recent_alarms.popleft() + return len(self._recent_alarms) + + def summary(self, now: float) -> Dict[str, Any]: + with self._lock: + states = [p.state for p in self.points.values()] + annunciated = [p for p in self.points.values() if p.state in ANNUNCIATED] + unacked = [p for p in annunciated if p.state in NEEDS_ACK] + rate = self.alarm_rate(now) + top = min(unacked, key=lambda p: (p.d["priority"], -(p.activated_at or 0)), default=None) + + if rate >= RATE_FLOOD: + rate_status = "Flood" + elif rate > RATE_MANAGEABLE: + rate_status = "Above target" + elif rate > RATE_ACCEPTABLE: + rate_status = "Manageable" + else: + rate_status = "Acceptable" + + by_priority = {str(k): 0 for k in ALARM_PRIORITIES} + for p in annunciated: + by_priority[str(p.d["priority"])] += 1 + + return { + "annunciated": len(annunciated), + "in_alarm": states.count(AlarmState.UNACK) + states.count(AlarmState.ACKED), + "unacknowledged": len(unacked), + "acknowledged": states.count(AlarmState.ACKED), + "rtn_unack": states.count(AlarmState.RTN_UNACK), + "shelved": states.count(AlarmState.SHELVED), + "suppressed": states.count(AlarmState.SUPPRESSED), + "by_priority": by_priority, + "alarm_rate_10min": rate, + "rate_status": rate_status, + "highest_unacked": top.to_dict() if top else None, + "configured": len(states), + } + + +def _ts(iso: Optional[str]) -> float: + if not iso: + return 0.0 + return datetime.fromisoformat(iso).timestamp() From a4f1aa01cf40a22ef8c9f09ff71d78431c90d64f Mon Sep 17 00:00:00 2001 From: AddisonTech Date: Fri, 16 Oct 2026 16:00:19 +0000 Subject: [PATCH 03/10] Rework API, WebSocket feed and storage Snapshot plus live readings and alarm pushes over WebSocket, alarm journal, downsampled history, startup backfill, optional Modbus TCP. --- backend/collector.py | 291 ++++++++++++++++++++---- backend/database.py | 350 ++++++++++++----------------- backend/main.py | 250 ++++++++++++++------- backend/modbus_config.example.json | 37 +++ backend/modbus_source.py | 134 +++++++++++ backend/requirements-modbus.txt | 1 + 6 files changed, 733 insertions(+), 330 deletions(-) create mode 100644 backend/modbus_config.example.json create mode 100644 backend/modbus_source.py create mode 100644 backend/requirements-modbus.txt diff --git a/backend/collector.py b/backend/collector.py index 7469420..fb03dcf 100644 --- a/backend/collector.py +++ b/backend/collector.py @@ -1,68 +1,263 @@ -"""Background data collection service.""" +"""Scan loop: read the data source, evaluate alarms, store history, push to clients.""" import asyncio import json import logging -from datetime import datetime, timezone -from typing import Set +import random +import time +from typing import Any, Callable, Dict, List, Optional, Set -from simulator import DeviceSimulator -from database import insert_reading, prune_old_readings -from alarm_engine import process_reading -from config import POLL_INTERVAL +import config +import database +from alarms import ANNUNCIATED, NEEDS_ACK, AlarmManager, AlarmState +from simulator import SCENARIOS, FacilitySimulator logger = logging.getLogger(__name__) -_simulator = DeviceSimulator() -_latest_readings: dict = {} -_websocket_clients: Set = set() +BACKFILL_STEP_S = 60.0 +BACKFILL_EVENT_STEP_S = 5.0 # finer steps while an event plays out +SIM_OPERATOR = "operator (simulated)" -def get_latest_readings_cache() -> dict: - return _latest_readings +class Collector: + """Owns the live state of the system and the set of WebSocket clients.""" + def __init__(self, source: str = None, clock: Callable[[], float] = time.time): + self.source = (source or config.DATA_SOURCE) + self.clock = clock + self.started_at = clock() + self.meter_names = {m["id"]: m["name"] for m in config.METERS} + self.alarms = AlarmManager(config.ALARM_POINTS, self.meter_names) + self.alarms.add_listener(database.insert_alarm_event) + self.latest: Dict[str, Dict[str, Any]] = {} + self.clients: Set[Any] = set() + self.ready = False + self.scan_count = 0 + self._last_history = 0.0 + self._last_prune = 0.0 + self._task: Optional[asyncio.Task] = None -def register_ws_client(ws): - _websocket_clients.add(ws) + self.sim: Optional[FacilitySimulator] = None + self.modbus = None + if self.source == "modbus": + from modbus_source import ModbusSource, load_config + self.modbus = ModbusSource(load_config(config.MODBUS_CONFIG)) + else: + self.source = "simulator" + seed = int(config.SIM_SEED) if config.SIM_SEED else None + self.sim = FacilitySimulator( + seed=seed, + event_interval=(config.SIM_EVENT_MIN, config.SIM_EVENT_MAX), + first_event_delay=config.SIM_FIRST_EVENT, + ) + @property + def simulated(self) -> bool: + return self.sim is not None -def unregister_ws_client(ws): - _websocket_clients.discard(ws) + # ------------------------------------------------------------------ + # Startup + # ------------------------------------------------------------------ + def initialize(self): + """Prepare storage. A simulated demo starts fresh with backfilled history.""" + database.init_db(reset=self.simulated) + if self.simulated and config.BACKFILL_HOURS > 0: + t0 = time.perf_counter() + self.backfill(config.BACKFILL_HOURS, self.clock()) + logger.info("Backfilled %.0f h of simulated history in %.2f s", + config.BACKFILL_HOURS, time.perf_counter() - t0) -async def broadcast_readings(): - """Push latest readings to all connected WebSocket clients.""" - if not _websocket_clients or not _latest_readings: - return - payload = json.dumps({"type": "readings", "data": list(_latest_readings.values())}) - dead = set() - for ws in _websocket_clients: + def backfill(self, hours: float, now: float): + """Run the simulator over the past few hours so trends and history are populated. + + Events are spaced out the way a real site sees them, and a simulated + operator acknowledges alarms shortly after they annunciate. + """ + sim = self.sim + live_interval, live_first = sim.event_interval, sim.first_event_delay + sim.event_interval, sim.first_event_delay = (1800.0, 5400.0), 600.0 + rng = random.Random(sim.rng.random()) + + events: List[Dict[str, Any]] = [] + mgr = AlarmManager(config.ALARM_POINTS, self.meter_names) + mgr.add_listener(events.append) + rows: List[Dict[str, Any]] = [] + + t = now - hours * 3600 + quiet_from = now - 900 # no new events in the last 15 minutes + while t < now: + sim.auto_events = t < quiet_from + readings = sim.step(t) + rows.extend(readings.values()) + mgr.evaluate(readings, t) + for p in mgr.points.values(): + if p.state in NEEDS_ACK and p.activated_at is not None \ + and t - p.activated_at >= rng.uniform(30, 150): + mgr.acknowledge(p.tag, t, SIM_OPERATOR) + t += BACKFILL_EVENT_STEP_S if sim.scenario else BACKFILL_STEP_S + + database.insert_readings(rows) + database.insert_alarm_events(events) + sim.auto_events = True + sim.event_interval, sim.first_event_delay = live_interval, live_first + sim.schedule_event_at(now + live_first) # first live event soon after startup + self._last_history = now + + async def start(self): + self.initialize() + await self.scan_once() + self.ready = True + self._task = asyncio.create_task(self._run()) + + async def stop(self): + if self._task: + self._task.cancel() + try: + await self._task + except asyncio.CancelledError: + pass + if self.modbus: + self.modbus.close() + + # ------------------------------------------------------------------ + # Scan loop + # ------------------------------------------------------------------ + + async def _run(self): + while True: + started = self.clock() + await asyncio.sleep(max(0.05, config.POLL_INTERVAL - (self.clock() - started))) + try: + await self.scan_once() + except Exception: + logger.exception("Scan failed") + + async def scan_once(self, now: Optional[float] = None) -> Dict[str, Dict[str, Any]]: + now = self.clock() if now is None else now + if self.sim: + readings = self.sim.step(now) + else: + readings = await self.modbus.read_all(now) + self.latest.update(readings) + self.scan_count += 1 + + alarms_changed = self.alarms.evaluate(readings, now) + + if now - self._last_history >= config.HISTORY_INTERVAL: + database.insert_readings(r for r in readings.values() if r.get("voltage") is not None) + self._last_history = now + if now - self._last_prune >= 3600: + database.prune(config.RETENTION_DAYS, now) + self._last_prune = now + + await self.broadcast({"type": "readings", "data": { + "readings": list(readings.values()), + "system": self.system_status(now), + }}) + if alarms_changed or self.scan_count % 5 == 0: + await self.broadcast_alarms(now) + return readings + + # ------------------------------------------------------------------ + # Views + # ------------------------------------------------------------------ + + def alarm_payload(self, now: Optional[float] = None) -> Dict[str, Any]: + now = self.clock() if now is None else now + return {"alarms": self.alarms.alarm_list(), "summary": self.alarms.summary(now)} + + def system_status(self, now: Optional[float] = None) -> Dict[str, Any]: + now = self.clock() if now is None else now + r = self.latest + facility_kw = r.get("MSB-1", {}).get("power_kw") or 0.0 + it_kw = sum((r.get(m["id"], {}).get("power_kw") or 0.0) + for m in config.METERS if m["type"] == "pdu") + ups_runtime = [r[u].get("battery_runtime_min") for u in ("UPS-A", "UPS-B") + if u in r and r[u].get("battery_runtime_min") is not None] + + in_alarm = [p for p in self.alarms.points.values() + if p.state in (AlarmState.UNACK, AlarmState.ACKED)] + priorities = {p.d["priority"] for p in in_alarm} + if 1 in priorities: + health = "critical" + elif 2 in priorities: + health = "warning" + elif priorities: + health = "caution" + else: + health = "normal" + + online = sum(1 for v in r.values() if v.get("comm_ok", True)) + return { + "health": health, + "data_source": self.source, + "simulated": self.simulated, + "facility_kw": round(facility_kw, 1), + "it_kw": round(it_kw, 1), + "pue": round(facility_kw / it_kw, 2) if facility_kw > 0 and it_kw > 0 else None, + "power_source": r.get("ATS-1", {}).get("position"), + "utility_status": r.get("UTIL-1", {}).get("status"), + "generator_status": r.get("GEN-1", {}).get("status"), + "ups_min_runtime_min": min(ups_runtime) if ups_runtime else None, + "annunciated_alarms": sum(1 for p in self.alarms.points.values() if p.state in ANNUNCIATED), + "meter_count": len(config.METERS), + "meters_online": online, + "scenario": self.sim.scenario_info(now) if self.sim else None, + "server_time": now, + } + + def demo_info(self) -> Dict[str, Any]: + return { + "simulated": self.simulated, + "events_enabled": self.simulated and config.DEMO_EVENTS_ENABLED, + "scenarios": [{"name": k, **v} for k, v in SCENARIOS.items()] if self.simulated else [], + "poll_interval_s": config.POLL_INTERVAL, + "version": config.VERSION, + } + + def snapshot(self) -> Dict[str, Any]: + now = self.clock() + return { + "meters": config.METERS, + "readings": list(self.latest.values()), + "system": self.system_status(now), + "demo": self.demo_info(), + **self.alarm_payload(now), + } + + # ------------------------------------------------------------------ + # Demo events + # ------------------------------------------------------------------ + + def trigger_event(self, name: str) -> Dict[str, Any]: + if not self.simulated or not config.DEMO_EVENTS_ENABLED: + raise PermissionError("Demo events are only available in simulation mode") + now = self.clock() + info = self.sim.trigger(name, now) + return info + + # ------------------------------------------------------------------ + # WebSocket clients + # ------------------------------------------------------------------ + + def register(self, ws): + self.clients.add(ws) + + def unregister(self, ws): + self.clients.discard(ws) + + async def _send(self, ws, text: str): try: - await ws.send_text(payload) + await asyncio.wait_for(ws.send_text(text), timeout=5) except Exception: - dead.add(ws) - for ws in dead: - _websocket_clients.discard(ws) + self.clients.discard(ws) + async def broadcast(self, message: Dict[str, Any]): + if not self.clients: + return + text = json.dumps(message, separators=(",", ":")) + await asyncio.gather(*(self._send(ws, text) for ws in list(self.clients))) -async def collection_loop(): - """Main polling loop: read all meters, store, process alarms, broadcast.""" - prune_counter = 0 - while True: - try: - readings = _simulator.read_all() - for meter_id, reading in readings.items(): - insert_reading(reading) - process_reading(reading) - _latest_readings[meter_id] = reading - - await broadcast_readings() - prune_counter += 1 - if prune_counter >= 720: # every hour at 5s interval - prune_old_readings(days=7) - prune_counter = 0 - - except Exception as exc: - logger.error("Collection loop error: %s", exc) - - await asyncio.sleep(POLL_INTERVAL) + async def broadcast_alarms(self, now: Optional[float] = None): + await self.broadcast({"type": "alarms", "data": self.alarm_payload(now)}) diff --git a/backend/database.py b/backend/database.py index 9d30137..cc67d2b 100644 --- a/backend/database.py +++ b/backend/database.py @@ -1,214 +1,158 @@ -"""Database layer for Power Dashboard using SQLite.""" +"""SQLite storage for meter history and the alarm event journal.""" import sqlite3 -import json -from datetime import datetime, timezone -from typing import List, Dict, Any, Optional -from config import DB_PATH, METERS - - -def get_connection() -> sqlite3.Connection: - conn = sqlite3.connect(DB_PATH) - conn.row_factory = sqlite3.Row - conn.execute("PRAGMA journal_mode=WAL") - conn.execute("PRAGMA synchronous=NORMAL") - return conn - - -def init_db(): - """Initialize database schema.""" - conn = get_connection() - cur = conn.cursor() - - cur.executescript(""" - CREATE TABLE IF NOT EXISTS meters ( - id INTEGER PRIMARY KEY, - name TEXT NOT NULL, - description TEXT, - type TEXT, - parent_id INTEGER, - nominal_voltage REAL, - nominal_current REAL, - ct_ratio INTEGER, - pt_ratio INTEGER, - created_at TEXT DEFAULT (datetime('now')) - ); - - CREATE TABLE IF NOT EXISTS readings ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - meter_id INTEGER NOT NULL, - voltage REAL, - current REAL, - power_kw REAL, - power_factor REAL, - energy_kwh REAL, - frequency REAL, - demand_kw REAL, - timestamp TEXT NOT NULL, - FOREIGN KEY (meter_id) REFERENCES meters(id) - ); - - CREATE INDEX IF NOT EXISTS idx_readings_meter_ts - ON readings(meter_id, timestamp DESC); - - CREATE TABLE IF NOT EXISTS alarms ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - meter_id INTEGER NOT NULL, - parameter TEXT NOT NULL, - condition TEXT NOT NULL, - value REAL NOT NULL, - threshold REAL NOT NULL, - priority INTEGER NOT NULL, - state TEXT NOT NULL DEFAULT 'active', - acknowledged INTEGER NOT NULL DEFAULT 0, - ack_time TEXT, - ack_by TEXT, - raised_at TEXT NOT NULL, - cleared_at TEXT, - FOREIGN KEY (meter_id) REFERENCES meters(id) - ); - - CREATE INDEX IF NOT EXISTS idx_alarms_state - ON alarms(state, meter_id); - """) - - # Seed meter definitions - for m in METERS: - cur.execute(""" - INSERT OR IGNORE INTO meters - (id, name, description, type, parent_id, nominal_voltage, nominal_current, ct_ratio, pt_ratio) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) - """, (m["id"], m["name"], m["description"], m["type"], m["parent_id"], - m["nominal_voltage"], m["nominal_current"], m["ct_ratio"], m["pt_ratio"])) - - conn.commit() - conn.close() - - -def insert_reading(reading: Dict[str, Any]): - conn = get_connection() - conn.execute(""" - INSERT INTO readings (meter_id, voltage, current, power_kw, power_factor, - energy_kwh, frequency, demand_kw, timestamp) - VALUES (:meter_id, :voltage, :current, :power_kw, :power_factor, - :energy_kwh, :frequency, :demand_kw, :timestamp) - """, reading) - conn.commit() - conn.close() - - -def get_latest_readings() -> List[Dict]: - conn = get_connection() - rows = conn.execute(""" - SELECT r.*, m.name AS meter_name, m.type, m.parent_id, - m.nominal_voltage, m.nominal_current - FROM readings r - JOIN meters m ON m.id = r.meter_id - WHERE r.id IN ( - SELECT MAX(id) FROM readings GROUP BY meter_id +import threading +import time +from typing import Any, Dict, Iterable, List, Optional + +import config + +HISTORY_FIELDS = ("voltage", "current", "power_kw", "power_factor", "frequency", + "energy_kwh", "demand_kw", "load_pct") + +PERIODS = {"1h": 3600, "24h": 86400, "7d": 7 * 86400} +HISTORY_POINTS = 360 # target points per trend after downsampling + +_lock = threading.Lock() +_conn: Optional[sqlite3.Connection] = None + + +def _db() -> sqlite3.Connection: + global _conn + if _conn is None: + _conn = sqlite3.connect(config.DB_PATH, check_same_thread=False) + _conn.row_factory = sqlite3.Row + if config.DB_PATH != ":memory:": + _conn.execute("PRAGMA journal_mode=WAL") + _conn.execute("PRAGMA synchronous=NORMAL") + return _conn + + +def close(): + global _conn + with _lock: + if _conn is not None: + _conn.close() + _conn = None + + +def init_db(reset: bool = False): + """Create tables. reset=True clears stored data (used for a fresh demo).""" + with _lock: + db = _db() + if reset: + db.executescript("DROP TABLE IF EXISTS meter_readings; DROP TABLE IF EXISTS alarm_events;") + db.executescript(""" + CREATE TABLE IF NOT EXISTS meter_readings ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + meter_id TEXT NOT NULL, + epoch REAL NOT NULL, + timestamp TEXT NOT NULL, + voltage REAL, + current REAL, + power_kw REAL, + power_factor REAL, + frequency REAL, + energy_kwh REAL, + demand_kw REAL, + load_pct REAL + ); + CREATE INDEX IF NOT EXISTS idx_meter_readings_meter_epoch + ON meter_readings(meter_id, epoch); + + CREATE TABLE IF NOT EXISTS alarm_events ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + epoch REAL NOT NULL, + timestamp TEXT NOT NULL, + tag TEXT NOT NULL, + meter_id TEXT NOT NULL, + meter_name TEXT, + event TEXT NOT NULL, + state TEXT NOT NULL, + priority INTEGER NOT NULL, + value REAL, + setpoint REAL, + unit TEXT, + message TEXT, + operator TEXT, + note TEXT + ); + CREATE INDEX IF NOT EXISTS idx_alarm_events_epoch ON alarm_events(epoch); + """) + db.commit() + + +def insert_readings(readings: Iterable[Dict[str, Any]]): + rows = [ + (r["meter_id"], r["epoch"], r["timestamp"], *(r.get(f) for f in HISTORY_FIELDS)) + for r in readings + ] + with _lock: + db = _db() + db.executemany( + f"INSERT INTO meter_readings (meter_id, epoch, timestamp, {', '.join(HISTORY_FIELDS)}) " + f"VALUES (?, ?, ?, {', '.join('?' * len(HISTORY_FIELDS))})", + rows, ) - ORDER BY m.id - """).fetchall() - conn.close() + db.commit() + + +def get_meter_history(meter_id: str, period: str = "1h", now: Optional[float] = None) -> List[Dict]: + """Return averaged history buckets for one meter, oldest first.""" + span = PERIODS[period] + now = time.time() if now is None else now + bucket = max(span / HISTORY_POINTS, 1.0) + avgs = ", ".join(f"ROUND(AVG({f}), 3) AS {f}" for f in HISTORY_FIELDS) + with _lock: + rows = _db().execute( + f""" + SELECT CAST(epoch / ? AS INTEGER) * ? AS epoch, {avgs} + FROM meter_readings + WHERE meter_id = ? AND epoch >= ? + GROUP BY CAST(epoch / ? AS INTEGER) + ORDER BY epoch ASC + """, + (bucket, bucket, meter_id, now - span, bucket), + ).fetchall() return [dict(r) for r in rows] -def get_meter_history(meter_id: int, period: str = "1h") -> List[Dict]: - period_map = {"1h": "1 hours", "24h": "24 hours", "7d": "7 days"} - interval = period_map.get(period, "1 hours") - conn = get_connection() - rows = conn.execute(f""" - SELECT * FROM readings - WHERE meter_id = ? - AND timestamp >= datetime('now', '-{interval}') - ORDER BY timestamp ASC - """, (meter_id,)).fetchall() - conn.close() - return [dict(r) for r in rows] - - -def get_all_meters() -> List[Dict]: - conn = get_connection() - rows = conn.execute("SELECT * FROM meters ORDER BY id").fetchall() - conn.close() - return [dict(r) for r in rows] +def insert_alarm_event(event: Dict[str, Any]): + insert_alarm_events([event]) -def upsert_alarm(meter_id: int, parameter: str, condition: str, - value: float, threshold: float, priority: int) -> Optional[int]: - """Insert new alarm if one does not already exist for this meter+parameter.""" - conn = get_connection() - existing = conn.execute(""" - SELECT id FROM alarms - WHERE meter_id=? AND parameter=? AND state='active' - """, (meter_id, parameter)).fetchone() - - if existing: - conn.close() - return existing["id"] - - now = datetime.now(timezone.utc).isoformat() - cur = conn.execute(""" - INSERT INTO alarms (meter_id, parameter, condition, value, threshold, priority, state, raised_at) - VALUES (?, ?, ?, ?, ?, ?, 'active', ?) - """, (meter_id, parameter, condition, value, threshold, priority, now)) - alarm_id = cur.lastrowid - conn.commit() - conn.close() - return alarm_id - - -def clear_alarm(meter_id: int, parameter: str): - """Clear active alarm when condition resolves.""" - now = datetime.now(timezone.utc).isoformat() - conn = get_connection() - conn.execute(""" - UPDATE alarms SET state='cleared', cleared_at=? - WHERE meter_id=? AND parameter=? AND state='active' - """, (now, meter_id, parameter)) - conn.commit() - conn.close() - - -def get_active_alarms() -> List[Dict]: - conn = get_connection() - rows = conn.execute(""" - SELECT a.*, m.name AS meter_name - FROM alarms a JOIN meters m ON m.id = a.meter_id - WHERE a.state = 'active' - ORDER BY a.priority ASC, a.raised_at DESC - """).fetchall() - conn.close() - return [dict(r) for r in rows] - - -def get_alarm_history(limit: int = 200) -> List[Dict]: - conn = get_connection() - rows = conn.execute(""" - SELECT a.*, m.name AS meter_name - FROM alarms a JOIN meters m ON m.id = a.meter_id - ORDER BY a.raised_at DESC LIMIT ? - """, (limit,)).fetchall() - conn.close() +def insert_alarm_events(events: Iterable[Dict[str, Any]]): + cols = ("epoch", "timestamp", "tag", "meter_id", "meter_name", "event", "state", + "priority", "value", "setpoint", "unit", "message", "operator", "note") + rows = [tuple(e.get(c) for c in cols) for e in events] + if not rows: + return + with _lock: + db = _db() + db.executemany( + f"INSERT INTO alarm_events ({', '.join(cols)}) VALUES ({', '.join('?' * len(cols))})", + rows, + ) + db.commit() + + +def get_alarm_events(limit: int = 200, tag: Optional[str] = None) -> List[Dict]: + sql = "SELECT * FROM alarm_events" + args: list = [] + if tag: + sql += " WHERE tag = ?" + args.append(tag) + sql += " ORDER BY epoch DESC, id DESC LIMIT ?" + args.append(limit) + with _lock: + rows = _db().execute(sql, args).fetchall() return [dict(r) for r in rows] -def acknowledge_alarm(alarm_id: int, ack_by: str = "operator"): - now = datetime.now(timezone.utc).isoformat() - conn = get_connection() - conn.execute(""" - UPDATE alarms SET acknowledged=1, ack_time=?, ack_by=? - WHERE id=? - """, (now, ack_by, alarm_id)) - conn.commit() - conn.close() - - -def prune_old_readings(days: int = 7): - """Remove readings older than specified days to manage DB size.""" - conn = get_connection() - conn.execute(""" - DELETE FROM readings WHERE timestamp < datetime('now', ? || ' days') - """, (f"-{days}",)) - conn.commit() - conn.close() +def prune(days: int, now: Optional[float] = None): + cutoff = (time.time() if now is None else now) - days * 86400 + with _lock: + db = _db() + db.execute("DELETE FROM meter_readings WHERE epoch < ?", (cutoff,)) + db.execute("DELETE FROM alarm_events WHERE epoch < ?", (cutoff,)) + db.commit() diff --git a/backend/main.py b/backend/main.py index 4bfdf6c..f69b25b 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,142 +1,234 @@ """FastAPI application entry point for Power Dashboard.""" -import asyncio import json import logging from contextlib import asynccontextmanager from typing import Optional -from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException +from fastapi import FastAPI, HTTPException, Request, WebSocket, WebSocketDisconnect from fastapi.middleware.cors import CORSMiddleware +from pydantic import BaseModel, Field -from database import ( - init_db, get_all_meters, get_latest_readings, get_meter_history, - get_active_alarms, get_alarm_history, acknowledge_alarm -) -from collector import ( - collection_loop, register_ws_client, unregister_ws_client, - get_latest_readings_cache, broadcast_readings -) -from config import METERS, WS_INTERVAL +import config +import database +from alarms import AlarmActionError +from collector import Collector -logging.basicConfig(level=logging.INFO) +logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s") logger = logging.getLogger(__name__) @asynccontextmanager async def lifespan(app: FastAPI): - init_db() - task = asyncio.create_task(collection_loop()) - logger.info("Power Dashboard collection loop started") + collector = Collector() + app.state.collector = collector + await collector.start() + logger.info("Power Dashboard %s started (data source: %s)", config.VERSION, collector.source) yield - task.cancel() + await collector.stop() + database.close() app = FastAPI( title="Power Dashboard API", - description="Real-time Electrical Power Monitoring System", - version="1.0.0", + description="Real-time data center electrical power monitoring with ISA 18.2 alarm management", + version=config.VERSION, lifespan=lifespan, ) app.add_middleware( CORSMiddleware, - allow_origins=["*"], + allow_origins=config.CORS_ORIGINS, allow_credentials=False, allow_methods=["*"], allow_headers=["*"], ) -# REST Endpoints +def _collector(request: Request) -> Collector: + return request.app.state.collector + + +def _operator(name: Optional[str]) -> str: + name = (name or "").strip()[:40] + return name or "operator" + + +class OperatorAction(BaseModel): + operator: Optional[str] = None + + +class ShelveRequest(BaseModel): + minutes: float = Field(15, gt=0, le=config.SHELVE_MAX_MIN) + reason: Optional[str] = Field(None, max_length=200) + operator: Optional[str] = None + + +# --------------------------------------------------------------------------- +# Health and configuration +# --------------------------------------------------------------------------- + +@app.get("/api/health") +def health(request: Request): + c = _collector(request) + return { + "status": "ok" if c.ready else "starting", + "version": config.VERSION, + "data_source": c.source, + "uptime_s": round(c.clock() - c.started_at, 1), + "clients": len(c.clients), + } + + +@app.get("/api/config") +def get_config(request: Request): + c = _collector(request) + return { + "version": config.VERSION, + "data_source": c.source, + "poll_interval_s": config.POLL_INTERVAL, + "history_interval_s": config.HISTORY_INTERVAL, + "retention_days": config.RETENTION_DAYS, + "shelve_durations_min": config.SHELVE_DURATIONS_MIN, + "shelve_max_min": config.SHELVE_MAX_MIN, + "priorities": config.ALARM_PRIORITIES, + "meters": config.METERS, + } + + +# --------------------------------------------------------------------------- +# Meters +# --------------------------------------------------------------------------- @app.get("/api/meters") -def list_meters(): - meters = get_all_meters() - readings_cache = get_latest_readings_cache() - result = [] - for m in meters: - reading = readings_cache.get(m["id"], {}) - result.append({**m, "current_reading": reading}) - return result +def list_meters(request: Request): + latest = _collector(request).latest + return [{**m, "current_reading": latest.get(m["id"], {})} for m in config.METERS] @app.get("/api/meters/{meter_id}") -def meter_detail(meter_id: int): - meters = {m["id"]: m for m in get_all_meters()} - if meter_id not in meters: +def meter_detail(meter_id: str, request: Request): + if meter_id not in config.METERS_BY_ID: raise HTTPException(status_code=404, detail="Meter not found") - reading = get_latest_readings_cache().get(meter_id, {}) - return {**meters[meter_id], "current_reading": reading} + reading = _collector(request).latest.get(meter_id, {}) + return {**config.METERS_BY_ID[meter_id], "current_reading": reading} @app.get("/api/meters/{meter_id}/history") -def meter_history(meter_id: int, period: str = "1h"): - if period not in ("1h", "24h", "7d"): +def meter_history(meter_id: str, period: str = "1h"): + if meter_id not in config.METERS_BY_ID: + raise HTTPException(status_code=404, detail="Meter not found") + if period not in database.PERIODS: raise HTTPException(status_code=400, detail="period must be 1h, 24h, or 7d") - return get_meter_history(meter_id, period) + return database.get_meter_history(meter_id, period) + + +@app.get("/api/system/status") +def system_status(request: Request): + return _collector(request).system_status() + +# --------------------------------------------------------------------------- +# Alarms (ISA 18.2) +# --------------------------------------------------------------------------- @app.get("/api/alarms") -def active_alarms(): - return get_active_alarms() +def alarms(request: Request): + return _collector(request).alarm_payload() @app.get("/api/alarms/history") -def alarms_history(limit: int = 200): - return get_alarm_history(limit) +def alarm_history(limit: int = 200, tag: Optional[str] = None): + return database.get_alarm_events(min(max(limit, 1), 1000), tag) -@app.post("/api/alarms/{alarm_id}/acknowledge") -def ack_alarm(alarm_id: int, ack_by: str = "operator"): - acknowledge_alarm(alarm_id, ack_by) - return {"status": "acknowledged", "alarm_id": alarm_id} +@app.get("/api/alarms/definitions") +def alarm_definitions(request: Request): + return _collector(request).alarms.definitions() -@app.get("/api/system/status") -def system_status(): - cache = get_latest_readings_cache() - active = get_active_alarms() - - total_power = sum(r.get("power_kw", 0) for r in cache.values()) - pf_values = [r["power_factor"] for r in cache.values() if r.get("power_factor")] - avg_pf = round(sum(pf_values) / len(pf_values), 4) if pf_values else 0.0 - - critical_count = sum(1 for a in active if a["priority"] == 1) - high_count = sum(1 for a in active if a["priority"] == 2) - - if critical_count > 0: - health = "critical" - elif high_count > 0: - health = "warning" - elif len(active) > 0: - health = "caution" - else: - health = "normal" +async def _alarm_action(request: Request, fn, *args, **kwargs): + c = _collector(request) + try: + result = fn(*args, now=c.clock(), **kwargs) + except KeyError: + raise HTTPException(status_code=404, detail="Alarm tag not found") + except AlarmActionError as exc: + raise HTTPException(status_code=409, detail=str(exc)) + await c.broadcast_alarms() + return result - return { - "health": health, - "total_power_kw": round(total_power, 2), - "avg_power_factor": avg_pf, - "active_alarm_count": len(active), - "critical_alarm_count": critical_count, - "high_alarm_count": high_count, - "meter_count": len(METERS), - "meters_online": len(cache), - } +@app.post("/api/alarms/{tag}/acknowledge") +async def acknowledge(tag: str, request: Request, body: Optional[OperatorAction] = None): + c = _collector(request) + return await _alarm_action(request, c.alarms.acknowledge, tag, + operator=_operator(body.operator if body else None)) -# WebSocket + +@app.post("/api/alarms/{tag}/shelve") +async def shelve(tag: str, body: ShelveRequest, request: Request): + c = _collector(request) + return await _alarm_action(request, c.alarms.shelve, tag, body.minutes, + operator=_operator(body.operator), reason=body.reason) + + +@app.post("/api/alarms/{tag}/unshelve") +async def unshelve(tag: str, request: Request, body: Optional[OperatorAction] = None): + c = _collector(request) + return await _alarm_action(request, c.alarms.unshelve, tag, + operator=_operator(body.operator if body else None)) + + +# --------------------------------------------------------------------------- +# Demo (simulation only) +# --------------------------------------------------------------------------- + +@app.get("/api/demo") +def demo(request: Request): + c = _collector(request) + return {**c.demo_info(), "active_scenario": c.sim.scenario_info(c.clock()) if c.sim else None} + + +@app.post("/api/demo/events/{name}") +async def trigger_event(name: str, request: Request): + c = _collector(request) + try: + info = c.trigger_event(name) + except PermissionError as exc: + raise HTTPException(status_code=403, detail=str(exc)) + except KeyError: + raise HTTPException(status_code=404, detail="Unknown scenario") + except RuntimeError as exc: + raise HTTPException(status_code=409, detail=str(exc)) + return info + + +# --------------------------------------------------------------------------- +# WebSocket live feed +# +# On connect the server sends a "snapshot" with everything the UI needs. After +# that it pushes "readings" every scan and "alarms" whenever the alarm list +# changes. Clients may send {"type": "ping"} and get {"type": "pong"} back. +# --------------------------------------------------------------------------- @app.websocket("/ws/live") async def websocket_live(websocket: WebSocket): + c: Collector = websocket.app.state.collector await websocket.accept() - register_ws_client(websocket) + await websocket.send_text(json.dumps({"type": "snapshot", "data": c.snapshot()}, + separators=(",", ":"))) + c.register(websocket) try: while True: - # Keep connection alive; data is pushed by broadcast_readings - await asyncio.sleep(1) + text = await websocket.receive_text() + try: + msg = json.loads(text) + except ValueError: + continue + if isinstance(msg, dict) and msg.get("type") == "ping": + await websocket.send_text('{"type":"pong"}') except WebSocketDisconnect: pass finally: - unregister_ws_client(websocket) + c.unregister(websocket) diff --git a/backend/modbus_config.example.json b/backend/modbus_config.example.json new file mode 100644 index 0000000..4a3df61 --- /dev/null +++ b/backend/modbus_config.example.json @@ -0,0 +1,37 @@ +{ + "defaults": { + "port": 502, + "timeout": 2.0, + "word_order": "big" + }, + "devices": [ + { + "meter_id": "UTIL-1", + "host": "meter-util.example.internal", + "unit_id": 1, + "registers": { + "voltage": { "address": 3000, "type": "float32", "function": "holding" }, + "current": { "address": 3002, "type": "float32", "function": "holding" }, + "power_kw": { "address": 3004, "type": "float32", "function": "holding" }, + "power_factor": { "address": 3006, "type": "float32", "function": "holding" }, + "frequency": { "address": 3008, "type": "float32", "function": "holding" }, + "energy_kwh": { "address": 3010, "type": "uint32", "function": "holding", "scale": 0.1 }, + "demand_kw": { "address": 3012, "type": "float32", "function": "holding" } + } + }, + { + "meter_id": "UPS-A", + "host": "ups-a.example.internal", + "unit_id": 1, + "registers": { + "voltage": { "address": 100, "type": "uint16", "function": "input", "scale": 0.1 }, + "current": { "address": 101, "type": "uint16", "function": "input", "scale": 0.1 }, + "power_kw": { "address": 102, "type": "uint16", "function": "input", "scale": 0.1 }, + "power_factor": { "address": 103, "type": "uint16", "function": "input", "scale": 0.001 }, + "frequency": { "address": 104, "type": "uint16", "function": "input", "scale": 0.01 }, + "battery_soc": { "address": 110, "type": "uint16", "function": "input" }, + "on_battery": { "address": 0, "type": "bool", "function": "discrete" } + } + } + ] +} diff --git a/backend/modbus_source.py b/backend/modbus_source.py new file mode 100644 index 0000000..2fb583c --- /dev/null +++ b/backend/modbus_source.py @@ -0,0 +1,134 @@ +"""Modbus TCP data source for real power meters. + +Enabled with DATA_SOURCE=modbus. The device map is a JSON file (see +modbus_config.example.json) that lists each meter's host, unit id, and the +register for every value. Requires the optional dependency in +requirements-modbus.txt (pymodbus). + +Readings come back in the same shape the simulator produces, so the alarm +engine, history, and front end work unchanged. A meter that fails to answer +is reported with status "Comm Fail" and empty values; alarms on that meter +hold their last state until communication returns. +""" + +import json +import logging +import struct +from datetime import datetime, timezone +from typing import Any, Dict, List, Optional + +from config import METERS_BY_ID + +logger = logging.getLogger(__name__) + +REGISTER_COUNT = {"int16": 1, "uint16": 1, "int32": 2, "uint32": 2, "float32": 2, "bool": 1} +NUMERIC_FIELDS = ("voltage", "current", "power_kw", "power_factor", "frequency", + "energy_kwh", "demand_kw", "load_pct") + + +def decode(registers: List[int], data_type: str, word_order: str = "big") -> float: + """Decode raw 16 bit registers into a value.""" + if data_type == "bool": + return bool(registers[0]) + if data_type == "uint16": + return registers[0] + if data_type == "int16": + return struct.unpack(">h", struct.pack(">H", registers[0]))[0] + words = list(registers[:2]) + if word_order == "little": + words.reverse() + raw = struct.pack(">HH", *words) + fmt = {"int32": ">i", "uint32": ">I", "float32": ">f"}[data_type] + return struct.unpack(fmt, raw)[0] + + +def load_config(path: str) -> Dict[str, Any]: + with open(path, encoding="utf-8") as fh: + cfg = json.load(fh) + for dev in cfg.get("devices", []): + if dev["meter_id"] not in METERS_BY_ID: + raise ValueError(f"Modbus device references unknown meter {dev['meter_id']}") + return cfg + + +class ModbusSource: + """Polls every configured device once per scan.""" + + def __init__(self, cfg: Dict[str, Any], client_factory=None): + self.cfg = cfg + self.defaults = cfg.get("defaults", {}) + self._clients: Dict[str, Any] = {} + if client_factory is None: + from pymodbus.client import AsyncModbusTcpClient # optional dependency + + def client_factory(host, port, timeout): + return AsyncModbusTcpClient(host, port=port, timeout=timeout) + self._factory = client_factory + + async def _client(self, host: str, port: int): + key = f"{host}:{port}" + client = self._clients.get(key) + if client is None: + client = self._factory(host, port, self.defaults.get("timeout", 2.0)) + self._clients[key] = client + if not client.connected: + await client.connect() + return client + + async def _read_register(self, client, unit: int, spec: Dict[str, Any]): + function = spec.get("function", "holding") + address = spec["address"] + dtype = spec.get("type", "float32") + count = REGISTER_COUNT[dtype] + if function == "coil": + rr = await client.read_coils(address, count=1, slave=unit) + elif function == "discrete": + rr = await client.read_discrete_inputs(address, count=1, slave=unit) + elif function == "input": + rr = await client.read_input_registers(address, count=count, slave=unit) + else: + rr = await client.read_holding_registers(address, count=count, slave=unit) + if rr.isError(): + raise IOError(f"Modbus error reading {address}: {rr}") + if function in ("coil", "discrete"): + return bool(rr.bits[0]) + value = decode(rr.registers, dtype, spec.get("word_order", self.defaults.get("word_order", "big"))) + if isinstance(value, bool): + return value + return value * spec.get("scale", 1.0) + + async def read_device(self, dev: Dict[str, Any], now: float) -> Dict[str, Any]: + mid = dev["meter_id"] + reading: Dict[str, Any] = { + "meter_id": mid, + "timestamp": datetime.fromtimestamp(now, timezone.utc).isoformat(timespec="milliseconds"), + "epoch": round(now, 3), + **{f: None for f in NUMERIC_FIELDS}, + } + try: + client = await self._client(dev["host"], dev.get("port", self.defaults.get("port", 502))) + for field, spec in dev["registers"].items(): + reading[field] = await self._read_register(client, dev.get("unit_id", 1), spec) + except Exception as exc: # comm failure: report it, keep polling others + logger.warning("Modbus read failed for %s: %s", mid, exc) + return {**reading, **{f: None for f in NUMERIC_FIELDS}, "status": "Comm Fail", "comm_ok": False} + + rated = METERS_BY_ID[mid]["rated_current"] + if reading["load_pct"] is None and reading["current"] is not None and rated: + reading["load_pct"] = round(reading["current"] / rated * 100.0, 1) + reading["status"] = dev.get("status_label", "Online") + reading["comm_ok"] = True + return reading + + async def read_all(self, now: float) -> Dict[str, Dict[str, Any]]: + out = {} + for dev in self.cfg.get("devices", []): + out[dev["meter_id"]] = await self.read_device(dev, now) + return out + + def close(self): + for client in self._clients.values(): + try: + client.close() + except Exception: + pass diff --git a/backend/requirements-modbus.txt b/backend/requirements-modbus.txt new file mode 100644 index 0000000..5ae2f13 --- /dev/null +++ b/backend/requirements-modbus.txt @@ -0,0 +1 @@ +pymodbus==3.6.9 From f957a7a1a25bdc7d38bc327c1d467beca7af0c11 Mon Sep 17 00:00:00 2001 From: AddisonTech Date: Fri, 16 Oct 2026 16:00:19 +0000 Subject: [PATCH 04/10] Add backend tests for simulator, alarms and WebSocket feed --- .gitignore | 3 + backend/requirements-dev.txt | 3 + backend/tests/conftest.py | 15 ++ backend/tests/test_alarms.py | 273 ++++++++++++++++++++++++++++ backend/tests/test_api_websocket.py | 131 +++++++++++++ backend/tests/test_modbus.py | 71 ++++++++ backend/tests/test_simulator.py | 164 +++++++++++++++++ 7 files changed, 660 insertions(+) create mode 100644 backend/requirements-dev.txt create mode 100644 backend/tests/conftest.py create mode 100644 backend/tests/test_alarms.py create mode 100644 backend/tests/test_api_websocket.py create mode 100644 backend/tests/test_modbus.py create mode 100644 backend/tests/test_simulator.py diff --git a/.gitignore b/.gitignore index ba0d1a1..350de40 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ dist/ Thumbs.db .idea/ .vscode/ + +# Tests +.pytest_cache/ diff --git a/backend/requirements-dev.txt b/backend/requirements-dev.txt new file mode 100644 index 0000000..b918a15 --- /dev/null +++ b/backend/requirements-dev.txt @@ -0,0 +1,3 @@ +-r requirements.txt +pytest==8.3.3 +httpx==0.27.2 diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py new file mode 100644 index 0000000..261622d --- /dev/null +++ b/backend/tests/conftest.py @@ -0,0 +1,15 @@ +import os +import sys +import tempfile + +# Settings must be in place before config.py is imported +_tmp = tempfile.mkdtemp(prefix="power-dashboard-tests-") +os.environ.setdefault("DB_PATH", os.path.join(_tmp, "test.db")) +os.environ.setdefault("BACKFILL_HOURS", "1") +os.environ.setdefault("POLL_INTERVAL", "0.2") +os.environ.setdefault("HISTORY_INTERVAL", "0.2") +os.environ.setdefault("SIM_SEED", "7") +os.environ.setdefault("SIM_FIRST_EVENT", "100000") +os.environ["DATA_SOURCE"] = "simulator" + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) diff --git a/backend/tests/test_alarms.py b/backend/tests/test_alarms.py new file mode 100644 index 0000000..acbe34d --- /dev/null +++ b/backend/tests/test_alarms.py @@ -0,0 +1,273 @@ +import pytest + +import config +from alarms import AlarmActionError, AlarmManager, AlarmState +from simulator import FacilitySimulator + +T0 = 1_760_000_000.0 + +HI = { + "tag": "PDU-1.LOAD.HI", "meter_id": "PDU-1", "parameter": "load_pct", "kind": "HI", + "setpoint": 80.0, "deadband": 3.0, "priority": 3, "on_delay": 0, "off_delay": 0, + "message": "PDU load high", "unit": "%", +} +LO = { + "tag": "UTIL.V.LO", "meter_id": "UTIL", "parameter": "voltage", "kind": "LO", + "setpoint": 432.0, "deadband": 5.0, "priority": 3, "on_delay": 0, "off_delay": 0, + "message": "Voltage low", + "suppress": {"meter_id": "UTIL", "parameter": "failed", "equals": True, "reason": "Utility failed"}, +} +DISCRETE = { + "tag": "UPS.ONBATT", "meter_id": "UPS", "parameter": "on_battery", "kind": "DISCRETE", + "setpoint": 1, "deadband": 0, "priority": 1, "on_delay": 0, "off_delay": 0, + "message": "UPS on battery", +} + + +class Harness: + def __init__(self, *defs): + self.mgr = AlarmManager(defs, {}) + self.events = [] + self.mgr.add_listener(self.events.append) + self.t = T0 + + def scan(self, **values): + """values: meter_id -> dict of parameters""" + self.t += 2 + return self.mgr.evaluate(values, self.t) + + def load(self, pct): + return self.scan(**{"PDU-1": {"load_pct": pct}}) + + def state(self, tag="PDU-1.LOAD.HI"): + return self.mgr.points[tag].state + + def kinds(self): + return [e["event"] for e in self.events] + + +def test_alarm_ack_then_clear(): + h = Harness(HI) + h.load(50) + assert h.state() == AlarmState.NORMAL + assert h.load(85) is True + assert h.state() == AlarmState.UNACK + h.mgr.acknowledge(HI["tag"], h.t, "jdoe") + assert h.state() == AlarmState.ACKED + assert h.mgr.points[HI["tag"]].ack_by == "jdoe" + h.load(70) + assert h.state() == AlarmState.NORMAL + assert h.kinds() == ["ALARM", "ACK", "RTN"] + + +def test_return_to_normal_unacknowledged_then_ack(): + h = Harness(HI) + h.load(85) + h.load(70) + assert h.state() == AlarmState.RTN_UNACK + item = h.mgr.alarm_list()[0] + assert item["state_label"] == "Returned to normal, unacknowledged" + h.mgr.acknowledge(HI["tag"], h.t) + assert h.state() == AlarmState.NORMAL + assert h.mgr.alarm_list() == [] + assert h.kinds() == ["ALARM", "RTN", "ACK"] + + +def test_rtn_unack_realarms(): + h = Harness(HI) + h.load(85) + h.load(70) + h.load(88) + assert h.state() == AlarmState.UNACK + assert h.kinds() == ["ALARM", "RTN", "ALARM"] + + +def test_ack_is_rejected_when_nothing_to_acknowledge(): + h = Harness(HI) + h.load(50) + with pytest.raises(AlarmActionError): + h.mgr.acknowledge(HI["tag"], h.t) + h.load(85) + h.mgr.acknowledge(HI["tag"], h.t) + with pytest.raises(AlarmActionError): + h.mgr.acknowledge(HI["tag"], h.t) + with pytest.raises(KeyError): + h.mgr.acknowledge("NOPE", h.t) + + +def test_deadband_prevents_chatter(): + h = Harness(HI) + h.load(81) + h.mgr.acknowledge(HI["tag"], h.t) + for v in (79.5, 80.5, 78.0, 79.9, 77.5): # inside the 3% deadband + h.load(v) + assert h.state() == AlarmState.ACKED + h.load(76.9) + assert h.state() == AlarmState.NORMAL + assert h.kinds().count("ALARM") == 1 + + +def test_on_and_off_delay(): + h = Harness({**HI, "on_delay": 2, "off_delay": 1}) + h.load(85) + h.load(85) + assert h.state() == AlarmState.NORMAL + h.load(70) # a single normal scan resets the on delay + h.load(85) + h.load(85) + assert h.state() == AlarmState.NORMAL + h.load(85) + assert h.state() == AlarmState.UNACK + h.load(70) + assert h.state() == AlarmState.UNACK + h.load(70) + assert h.state() == AlarmState.RTN_UNACK + + +def test_lo_and_discrete_kinds(): + h = Harness(LO, DISCRETE) + h.scan(UTIL={"voltage": 480, "failed": False}, UPS={"on_battery": False}) + assert h.state("UTIL.V.LO") == AlarmState.NORMAL + assert h.state("UPS.ONBATT") == AlarmState.NORMAL + h.scan(UTIL={"voltage": 410, "failed": False}, UPS={"on_battery": True}) + assert h.state("UTIL.V.LO") == AlarmState.UNACK + assert h.state("UPS.ONBATT") == AlarmState.UNACK + h.scan(UTIL={"voltage": 434, "failed": False}, UPS={"on_battery": False}) + assert h.state("UTIL.V.LO") == AlarmState.UNACK # within deadband + assert h.state("UPS.ONBATT") == AlarmState.RTN_UNACK + + +def test_missing_value_holds_state(): + h = Harness(HI) + h.load(85) + h.scan() # meter offline + h.scan(**{"PDU-1": {"load_pct": None}}) + assert h.state() == AlarmState.UNACK + assert h.kinds() == ["ALARM"] + + +def test_shelve_hides_alarm_and_expires(): + h = Harness(HI) + h.load(85) + h.mgr.shelve(HI["tag"], 5, h.t, "jdoe", "Known overload during migration") + assert h.state() == AlarmState.SHELVED + p = h.mgr.points[HI["tag"]] + assert p.shelve_reason == "Known overload during migration" + summary = h.mgr.summary(h.t) + assert summary["shelved"] == 1 and summary["annunciated"] == 0 + + h.load(95) + assert h.state() == AlarmState.SHELVED # no annunciation while shelved + h.t += 5 * 60 + h.load(95) + assert h.state() == AlarmState.UNACK # timer expired, condition still active + assert h.kinds() == ["ALARM", "SHELVE", "UNSHELVE", "ALARM"] + assert h.events[2]["note"] == "Shelve time expired" + + +def test_unshelve_when_condition_cleared_returns_to_normal(): + h = Harness(HI) + h.load(85) + h.mgr.shelve(HI["tag"], 15, h.t) + h.load(60) + h.mgr.unshelve(HI["tag"], h.t) + assert h.state() == AlarmState.NORMAL + with pytest.raises(AlarmActionError): + h.mgr.unshelve(HI["tag"], h.t) + + +def test_shelve_limits(): + h = Harness(HI) + h.load(85) + with pytest.raises(AlarmActionError): + h.mgr.shelve(HI["tag"], config.SHELVE_MAX_MIN + 1, h.t) + with pytest.raises(AlarmActionError): + h.mgr.shelve(HI["tag"], 0, h.t) + h.mgr.shelve(HI["tag"], 5, h.t) + with pytest.raises(AlarmActionError): + h.mgr.shelve(HI["tag"], 5, h.t) + + +def test_designed_suppression(): + h = Harness(LO) + h.scan(UTIL={"voltage": 480, "failed": False}) + h.scan(UTIL={"voltage": 0, "failed": True}) + assert h.state("UTIL.V.LO") == AlarmState.SUPPRESSED + assert h.mgr.points["UTIL.V.LO"].suppress_reason == "Utility failed" + assert h.kinds() == ["SUPPRESS"] + # Utility back at normal voltage: return to service without a stale alarm + h.scan(UTIL={"voltage": 481, "failed": False}) + assert h.state("UTIL.V.LO") == AlarmState.NORMAL + assert h.kinds() == ["SUPPRESS", "UNSUPPRESS"] + # Utility back but low: return to service straight into alarm + h.scan(UTIL={"voltage": 0, "failed": True}) + h.scan(UTIL={"voltage": 420, "failed": False}) + assert h.state("UTIL.V.LO") == AlarmState.UNACK + + +def test_starting_suppressed_is_silent(): + h = Harness(LO) + h.scan(UTIL={"voltage": 0, "failed": True}) + assert h.state("UTIL.V.LO") == AlarmState.SUPPRESSED + assert h.events == [] + + +def test_summary_rate_and_priorities(): + h = Harness(HI, DISCRETE) + h.scan(**{"PDU-1": {"load_pct": 85}}, UPS={"on_battery": True}) + s = h.mgr.summary(h.t) + assert s["annunciated"] == 2 and s["unacknowledged"] == 2 + assert s["by_priority"]["1"] == 1 and s["by_priority"]["3"] == 1 + assert s["highest_unacked"]["tag"] == "UPS.ONBATT" + assert s["alarm_rate_10min"] == 2 and s["rate_status"] == "Manageable" + + # Chatter between the states to build up a flood + for _ in range(10): + h.scan(**{"PDU-1": {"load_pct": 60}}, UPS={"on_battery": False}) + h.scan(**{"PDU-1": {"load_pct": 85}}, UPS={"on_battery": True}) + assert h.mgr.summary(h.t)["rate_status"] == "Flood" + # Older than 10 minutes drops out of the rate window + assert h.mgr.summary(h.t + 601)["alarm_rate_10min"] == 0 + + +def test_alarm_list_orders_by_priority(): + h = Harness(HI, DISCRETE) + h.scan(**{"PDU-1": {"load_pct": 85}}, UPS={"on_battery": True}) + tags = [a["tag"] for a in h.mgr.alarm_list()] + assert tags == ["UPS.ONBATT", "PDU-1.LOAD.HI"] + + +def test_configured_alarm_database_is_valid(): + tags = [d["tag"] for d in config.ALARM_POINTS] + assert len(tags) == len(set(tags)) + for d in config.ALARM_POINTS: + assert d["meter_id"] in config.METERS_BY_ID + assert d["priority"] in config.ALARM_PRIORITIES + assert d["kind"] in ("HI", "HIHI", "LO", "LOLO", "DISCRETE") + assert d["response"] and d["consequence"] + + +def test_outage_through_real_alarm_database(): + """The simulator and the configured alarms together tell the outage story.""" + sim = FacilitySimulator(seed=5, auto_events=False) + names = {m["id"]: m["name"] for m in config.METERS} + mgr = AlarmManager(config.ALARM_POINTS, names) + events = [] + mgr.add_listener(events.append) + + t = T0 + for _ in range(10): + mgr.evaluate(sim.step(t), t) + t += 2 + assert events == [] # quiet plant, no standing alarms + + sim.trigger("utility_outage", t, duration=40) + for _ in range(80): + mgr.evaluate(sim.step(t), t) + t += 2 + + alarmed = {e["tag"] for e in events if e["event"] == "ALARM"} + assert {"UTIL-1.FAIL", "UPS-A.ONBATT", "UPS-B.ONBATT", "ATS-1.EMERG"} <= alarmed + assert "UTIL-1.V.LO" not in alarmed # cascade suppressed by the failure alarm + states = {a["tag"]: a["state"] for a in mgr.alarm_list()} + assert states.get("UPS-A.ONBATT") == "RTN_UNACK" # ran on battery, nobody acked diff --git a/backend/tests/test_api_websocket.py b/backend/tests/test_api_websocket.py new file mode 100644 index 0000000..5ee387e --- /dev/null +++ b/backend/tests/test_api_websocket.py @@ -0,0 +1,131 @@ +import json +import time + +import pytest +from fastapi.testclient import TestClient + +from main import app + + +@pytest.fixture(scope="module") +def client(): + with TestClient(app) as c: + yield c + + +def receive_until(ws, predicate, limit=200): + """Read messages until one matches. Returns that message.""" + for _ in range(limit): + msg = json.loads(ws.receive_text()) + if predicate(msg): + return msg + raise AssertionError("expected message never arrived") + + +def test_health(client): + body = client.get("/api/health").json() + assert body["status"] == "ok" + assert body["data_source"] == "simulator" + assert body["version"] == "1.1.0" + + +def test_websocket_sends_snapshot_on_connect(client): + with client.websocket_connect("/ws/live") as ws: + msg = json.loads(ws.receive_text()) + assert msg["type"] == "snapshot" + data = msg["data"] + assert len(data["meters"]) == 11 + assert {r["meter_id"] for r in data["readings"]} == {m["id"] for m in data["meters"]} + assert data["demo"]["simulated"] is True + assert {s["name"] for s in data["demo"]["scenarios"]} >= {"utility_outage", "voltage_sag"} + assert "summary" in data and "alarms" in data + assert data["system"]["health"] in ("normal", "caution", "warning", "critical") + + +def test_websocket_streams_readings(client): + with client.websocket_connect("/ws/live") as ws: + ws.receive_text() # snapshot + first = receive_until(ws, lambda m: m["type"] == "readings") + second = receive_until(ws, lambda m: m["type"] == "readings") + assert len(first["data"]["readings"]) == 11 + assert second["data"]["readings"][0]["epoch"] > first["data"]["readings"][0]["epoch"] + assert first["data"]["system"]["facility_kw"] > 0 + + +def test_websocket_ping_pong(client): + with client.websocket_connect("/ws/live") as ws: + ws.receive_text() + ws.send_text(json.dumps({"type": "ping"})) + receive_until(ws, lambda m: m["type"] == "pong") + + +def test_alarm_lifecycle_over_rest_and_websocket(client): + """Trigger an outage, see the alarm arrive live, acknowledge, shelve, unshelve.""" + with client.websocket_connect("/ws/live") as ws: + ws.receive_text() + r = client.post("/api/demo/events/utility_outage") + assert r.status_code == 200 and r.json()["name"] == "utility_outage" + assert client.post("/api/demo/events/voltage_sag").status_code == 409 + + def has_state(tag, state): + def check(m): + return m["type"] == "alarms" and any( + a["tag"] == tag and a["state"] == state for a in m["data"]["alarms"]) + return check + + msg = receive_until(ws, has_state("UPS-A.ONBATT", "UNACK")) + summary = msg["data"]["summary"] + assert summary["highest_unacked"]["priority"] == 1 + + r = client.post("/api/alarms/UPS-A.ONBATT/acknowledge", json={"operator": "tester"}) + assert r.status_code == 200 + assert r.json()["state"] in ("ACKED", "NORMAL") + receive_until(ws, lambda m: m["type"] == "alarms" and all( + a["state"] != "UNACK" for a in m["data"]["alarms"] if a["tag"] == "UPS-A.ONBATT")) + + r = client.post("/api/alarms/UTIL-1.FAIL/shelve", + json={"minutes": 5, "reason": "Utility crew on site", "operator": "tester"}) + assert r.status_code == 200 and r.json()["state"] == "SHELVED" + receive_until(ws, has_state("UTIL-1.FAIL", "SHELVED")) + assert client.post("/api/alarms/UTIL-1.FAIL/unshelve").json()["state"] != "SHELVED" + + history = client.get("/api/alarms/history?limit=500").json() + kinds = {(e["tag"], e["event"]) for e in history} + assert ("UPS-A.ONBATT", "ALARM") in kinds + assert ("UPS-A.ONBATT", "ACK") in kinds + assert ("UTIL-1.FAIL", "SHELVE") in kinds + assert ("UTIL-1.FAIL", "UNSHELVE") in kinds + ack = next(e for e in history if e["tag"] == "UPS-A.ONBATT" and e["event"] == "ACK") + assert ack["operator"] == "tester" + + +def test_alarm_action_errors(client): + assert client.post("/api/alarms/NOPE/acknowledge").status_code == 404 + assert client.post("/api/alarms/MSB-1.LOAD.HI/acknowledge").status_code == 409 + assert client.post("/api/alarms/MSB-1.LOAD.HI/shelve", json={"minutes": 999}).status_code == 422 + assert client.post("/api/alarms/MSB-1.LOAD.HI/unshelve").status_code == 409 + + +def test_meters_and_history(client): + meters = client.get("/api/meters").json() + assert len(meters) == 11 + by_id = {m["id"]: m for m in meters} + # PDUs sit behind the UPS, so they stay energized even if an outage is in progress + assert by_id["PDU-A1"]["current_reading"]["voltage"] > 200 + assert client.get("/api/meters/UPS-A").json()["type"] == "ups" + assert client.get("/api/meters/NOPE").status_code == 404 + hist = client.get("/api/meters/MSB-1/history?period=1h").json() + assert len(hist) > 30 # backfilled on startup + epochs = [h["epoch"] for h in hist] + assert epochs == sorted(epochs) + assert time.time() - epochs[-1] < 120 + assert client.get("/api/meters/MSB-1/history?period=2y").status_code == 400 + + +def test_definitions_and_config(client): + defs = client.get("/api/alarms/definitions").json() + assert any(d["suppression"] for d in defs) + cfg = client.get("/api/config").json() + assert cfg["data_source"] == "simulator" + assert cfg["shelve_max_min"] == 60 + assert client.post("/api/demo/events/nope").status_code == 404 diff --git a/backend/tests/test_modbus.py b/backend/tests/test_modbus.py new file mode 100644 index 0000000..3fd1b1a --- /dev/null +++ b/backend/tests/test_modbus.py @@ -0,0 +1,71 @@ +import asyncio +import struct + +from modbus_source import ModbusSource, decode + + +def float_regs(value): + hi, lo = struct.unpack(">HH", struct.pack(">f", value)) + return [hi, lo] + + +def test_decode_types(): + assert decode([0xFFFF], "int16") == -1 + assert decode([0xFFFF], "uint16") == 65535 + assert abs(decode(float_regs(480.5), "float32") - 480.5) < 1e-4 + assert abs(decode(list(reversed(float_regs(59.98))), "float32", "little") - 59.98) < 1e-4 + assert decode([0x0001, 0x0000], "uint32") == 65536 + assert decode([1], "bool") is True + + +class FakeResult: + def __init__(self, registers=None, bits=None, error=False): + self.registers, self.bits, self._error = registers, bits, error + + def isError(self): + return self._error + + +class FakeClient: + def __init__(self, fail=False): + self.connected = False + self.fail = fail + + async def connect(self): + self.connected = True + + async def read_holding_registers(self, address, count, slave): + if self.fail: + return FakeResult(error=True) + return FakeResult(registers={3000: float_regs(481.0), 3002: float_regs(800.0)}[address]) + + async def read_discrete_inputs(self, address, count, slave): + return FakeResult(bits=[True]) + + def close(self): + pass + + +def make_source(fail=False): + cfg = {"devices": [{ + "meter_id": "UTIL-1", "host": "meter.example.internal", "unit_id": 1, + "registers": { + "voltage": {"address": 3000, "type": "float32"}, + "current": {"address": 3002, "type": "float32"}, + }, + }]} + return ModbusSource(cfg, client_factory=lambda host, port, timeout: FakeClient(fail)) + + +def test_modbus_reading_shape(): + out = asyncio.run(make_source().read_all(1_760_000_000.0)) + r = out["UTIL-1"] + assert r["voltage"] == 481.0 and r["current"] == 800.0 + assert r["load_pct"] == 50.0 # 800 A on a 1600 A service + assert r["comm_ok"] is True and r["status"] == "Online" + + +def test_modbus_comm_failure_is_reported(): + r = asyncio.run(make_source(fail=True).read_all(1_760_000_000.0))["UTIL-1"] + assert r["comm_ok"] is False and r["status"] == "Comm Fail" + assert r["voltage"] is None diff --git a/backend/tests/test_simulator.py b/backend/tests/test_simulator.py new file mode 100644 index 0000000..ccc8c9b --- /dev/null +++ b/backend/tests/test_simulator.py @@ -0,0 +1,164 @@ +import pytest + +from config import METERS, METERS_BY_ID +from simulator import SCENARIOS, FacilitySimulator + +T0 = 1_760_000_000.0 +FIELDS = ("voltage", "current", "power_kw", "power_factor", "frequency", + "energy_kwh", "demand_kw", "load_pct", "status", "timestamp", "epoch") + + +def run(sim, start, seconds, step=1.0): + """Step the simulator and return the list of scans.""" + out, t = [], start + while t < start + seconds: + out.append(sim.step(t)) + t += step + return out + + +def quiet_sim(seed=1): + return FacilitySimulator(seed=seed, auto_events=False) + + +def test_every_meter_reports_all_fields(): + r = quiet_sim().step(T0) + assert set(r) == {m["id"] for m in METERS} + for mid, reading in r.items(): + assert reading["meter_id"] == mid + for f in FIELDS: + assert f in reading, f"{mid} missing {f}" + + +def test_normal_operation_values_are_believable(): + sim = quiet_sim() + for scan in run(sim, T0, 600, step=2): + for mid, r in scan.items(): + cfg = METERS_BY_ID[mid] + if cfg["type"] == "generator": + assert r["status"] == "Standby" and r["voltage"] == 0 + continue + assert abs(r["voltage"] - cfg["nominal_voltage"]) / cfg["nominal_voltage"] < 0.03 + assert 59.9 < r["frequency"] < 60.1 + assert 5 < r["load_pct"] < 75 + assert 0.8 < r["power_factor"] <= 1.0 + assert scan["ATS-1"]["position"] == "UTILITY" + assert not scan["UPS-A"]["on_battery"] and not scan["UPS-B"]["on_battery"] + + +def test_power_balances_through_the_hierarchy(): + r = quiet_sim().step(T0) + pdu_a = r["PDU-A1"]["power_kw"] + r["PDU-A2"]["power_kw"] + # UPS output covers its PDUs plus transformer losses + assert pdu_a < r["UPS-A"]["power_kw"] < pdu_a * 1.05 + # Switchboard carries both UPS inputs, cooling, and house load + floor = r["UPS-A"]["input_kw"] + r["UPS-B"]["input_kw"] + r["MECH-1"]["power_kw"] + assert floor < r["MSB-1"]["power_kw"] < floor + 25 + # On utility, the ATS and the utility meter see the switchboard load + assert r["UTIL-1"]["power_kw"] == r["ATS-1"]["power_kw"] == r["MSB-1"]["power_kw"] + # A plausible PUE for a small facility + it = sum(r[p]["power_kw"] for p in ("PDU-A1", "PDU-A2", "PDU-B1", "PDU-B2")) + assert 1.3 < r["MSB-1"]["power_kw"] / it < 2.0 + + +def test_values_move_and_energy_accumulates(): + scans = run(quiet_sim(), T0, 300, step=2) + kw = {s["MSB-1"]["power_kw"] for s in scans} + assert len(kw) > 20 + energy = [s["UTIL-1"]["energy_kwh"] for s in scans] + assert energy == sorted(energy) and energy[-1] > energy[0] + + +def test_same_seed_is_repeatable(): + a = run(quiet_sim(seed=42), T0, 60, step=2) + b = run(quiet_sim(seed=42), T0, 60, step=2) + assert a == b + + +def test_utility_outage_sequence(): + sim = quiet_sim() + sim.step(T0) + sim.trigger("utility_outage", T0 + 1, duration=60) + scans = run(sim, T0 + 1, 200, step=1) + + def first(pred): + return next(i for i, s in enumerate(scans) if pred(s)) + + lost = first(lambda s: s["UTIL-1"]["source_failed"]) + on_batt = first(lambda s: s["UPS-A"]["on_battery"] and s["UPS-B"]["on_battery"]) + cranking = first(lambda s: s["GEN-1"]["gen_state"] == "CRANKING") + running = first(lambda s: s["GEN-1"]["gen_state"] == "RUNNING") + on_gen = first(lambda s: s["ATS-1"]["position"] == "GENERATOR") + ups_back = first(lambda s: s["ATS-1"]["position"] == "GENERATOR" and not s["UPS-A"]["on_battery"]) + assert lost == on_batt == 0 + assert 0 < cranking < running < on_gen < ups_back + + # While on battery the critical IT load is still served + assert scans[on_batt]["PDU-A1"]["power_kw"] > 50 + assert scans[on_batt]["MSB-1"]["power_kw"] == 0 + # The block load step dips generator frequency + assert scans[on_gen]["GEN-1"]["frequency"] < 59.5 + # On generator, the generator meter carries the facility + assert scans[ups_back + 5]["GEN-1"]["power_kw"] > 300 + assert scans[ups_back + 5]["UTIL-1"]["power_kw"] == 0 + + back = first(lambda s: not s["UTIL-1"]["source_failed"]) + retransfer = first(lambda s: s["ATS-1"]["position"] == "UTILITY" and scans.index(s) > on_gen) + assert retransfer - back >= 29 # retransfer delay + assert scans[-1]["GEN-1"]["gen_state"] == "STANDBY" + assert sim.scenario is None + assert scans[-1]["UPS-A"]["battery_soc"] < 100 # still recharging + + +def test_voltage_sag_rides_through_on_battery_without_generator(): + sim = quiet_sim() + sim.step(T0) + sim.trigger("voltage_sag", T0 + 1, duration=5, depth=0.85) + scans = run(sim, T0 + 1, 20) + assert min(s["UTIL-1"]["voltage"] for s in scans) < 432 + assert any(s["UPS-A"]["on_battery"] for s in scans) + assert all(s["GEN-1"]["gen_state"] == "STANDBY" for s in scans) + assert not scans[-1]["UPS-A"]["on_battery"] + + +def test_pdu_overload_crosses_alarm_limits(): + sim = quiet_sim() + sim.step(T0) + sim.trigger("pdu_overload", T0 + 1, pdu="PDU-B2", target_pct=93, hold=60) + scans = run(sim, T0 + 1, 160, step=2) + peak = max(s["PDU-B2"]["load_pct"] for s in scans) + assert peak > 90 + assert max(s["PDU-A1"]["load_pct"] for s in scans) < 75 + assert scans[-1]["PDU-B2"]["load_pct"] < 75 + + +def test_power_factor_drop(): + sim = quiet_sim() + sim.step(T0) + sim.trigger("pf_drop", T0 + 1, duration=60, pf=0.79) + scans = run(sim, T0 + 1, 80, step=2) + assert min(s["MECH-1"]["power_factor"] for s in scans) < 0.82 + assert scans[-1]["MECH-1"]["power_factor"] > 0.85 + + +def test_trigger_validation(): + sim = quiet_sim() + sim.step(T0) + with pytest.raises(KeyError): + sim.trigger("meteor_strike", T0) + sim.trigger("pf_drop", T0) + with pytest.raises(RuntimeError): + sim.trigger("voltage_sag", T0 + 1) + + +def test_automatic_events_fire_and_finish(): + sim = FacilitySimulator(seed=3, auto_events=True, event_interval=(20, 30), first_event_delay=5) + seen = set() + t = T0 + for _ in range(1500): + sim.step(t) + if sim.scenario: + seen.add(sim.scenario["name"]) + t += 2 + assert seen <= set(SCENARIOS) + assert len(seen) >= 3 From 12c5b0f3e6af07b2188914157232e588cacc60b3 Mon Sep 17 00:00:00 2001 From: AddisonTech Date: Fri, 16 Oct 2026 16:15:49 +0000 Subject: [PATCH 05/10] Suppress mechanical PF alarm while the panel is de-energized Also use equipment names in alarm messages and blank PUE while UPS systems carry the IT load on battery. --- backend/collector.py | 4 ++- backend/config.py | 14 +++++--- backend/simulator.py | 3 +- backend/tests/test_alarms.py | 1 + frontend/src/services/websocket.js | 56 ------------------------------ 5 files changed, 15 insertions(+), 63 deletions(-) delete mode 100644 frontend/src/services/websocket.js diff --git a/backend/collector.py b/backend/collector.py index fb03dcf..2e95fc4 100644 --- a/backend/collector.py +++ b/backend/collector.py @@ -176,6 +176,8 @@ def system_status(self, now: Optional[float] = None) -> Dict[str, Any]: ups_runtime = [r[u].get("battery_runtime_min") for u in ("UPS-A", "UPS-B") if u in r and r[u].get("battery_runtime_min") is not None] + on_battery = any(r.get(u, {}).get("on_battery") for u in ("UPS-A", "UPS-B")) + in_alarm = [p for p in self.alarms.points.values() if p.state in (AlarmState.UNACK, AlarmState.ACKED)] priorities = {p.d["priority"] for p in in_alarm} @@ -195,7 +197,7 @@ def system_status(self, now: Optional[float] = None) -> Dict[str, Any]: "simulated": self.simulated, "facility_kw": round(facility_kw, 1), "it_kw": round(it_kw, 1), - "pue": round(facility_kw / it_kw, 2) if facility_kw > 0 and it_kw > 0 else None, + "pue": round(facility_kw / it_kw, 2) if facility_kw > 0 and it_kw > 0 and not on_battery else None, "power_source": r.get("ATS-1", {}).get("position"), "utility_status": r.get("UTIL-1", {}).get("status"), "generator_status": r.get("GEN-1", {}).get("status"), diff --git a/backend/config.py b/backend/config.py index 4353a67..dbb2b36 100644 --- a/backend/config.py +++ b/backend/config.py @@ -168,12 +168,13 @@ def _env_float(name: str, default: float) -> float: # --------------------------------------------------------------------------- def _pdu_alarms(pdu: str): + name = METERS_BY_ID[pdu]["name"] return [ { "tag": f"{pdu}.LOAD.HI", "meter_id": pdu, "parameter": "load_pct", "kind": "HI", "setpoint": 80.0, "deadband": 3.0, "priority": 3, "on_delay": 2, "off_delay": 2, "unit": "%", - "message": f"{pdu} load high", + "message": f"{name} load high", "consequence": "Reduced margin before the PDU main breaker trips.", "response": "Check for new rack load or a failed partner PDU. Plan load rebalancing.", }, @@ -181,7 +182,7 @@ def _pdu_alarms(pdu: str): "tag": f"{pdu}.LOAD.HIHI", "meter_id": pdu, "parameter": "load_pct", "kind": "HIHI", "setpoint": 90.0, "deadband": 3.0, "priority": 2, "on_delay": 2, "off_delay": 2, "unit": "%", - "message": f"{pdu} load very high", + "message": f"{name} load very high", "consequence": "PDU breaker trip drops every server on this side.", "response": "Shed or move load now. Confirm the partner PDU can carry the racks.", }, @@ -189,12 +190,13 @@ def _pdu_alarms(pdu: str): def _ups_alarms(ups: str): + name = METERS_BY_ID[ups]["name"] return [ { "tag": f"{ups}.ONBATT", "meter_id": ups, "parameter": "on_battery", "kind": "DISCRETE", "setpoint": 1, "deadband": 0, "priority": 1, "on_delay": 0, "off_delay": 1, "unit": "", - "message": f"{ups} on battery", + "message": f"{name} on battery", "consequence": "Critical load is on limited battery runtime.", "response": "Verify generator start and ATS transfer. Watch battery runtime.", }, @@ -202,7 +204,7 @@ def _ups_alarms(ups: str): "tag": f"{ups}.LOAD.HI", "meter_id": ups, "parameter": "load_pct", "kind": "HI", "setpoint": 50.0, "deadband": 2.0, "priority": 2, "on_delay": 2, "off_delay": 2, "unit": "%", - "message": f"{ups} load above 2N limit", + "message": f"{name} load above 2N limit", "consequence": "If the other side fails, this UPS cannot carry the full IT load.", "response": "Rebalance IT load between A and B sides below 50 percent each.", }, @@ -210,7 +212,7 @@ def _ups_alarms(ups: str): "tag": f"{ups}.BATT.LO", "meter_id": ups, "parameter": "battery_soc", "kind": "LO", "setpoint": 60.0, "deadband": 5.0, "priority": 2, "on_delay": 1, "off_delay": 2, "unit": "%", - "message": f"{ups} battery charge low", + "message": f"{name} battery charge low", "consequence": "Reduced ride through time on the next utility event.", "response": "Confirm the rectifier is charging. Avoid planned transfers until recharged.", }, @@ -271,6 +273,8 @@ def _ups_alarms(ups: str): "message": "Mechanical panel power factor low", "consequence": "Higher current and possible utility power factor penalty.", "response": "Check the capacitor bank and VFD bypass status.", + "suppress": {"meter_id": "MECH-1", "parameter": "energized", "equals": False, + "reason": "Panel de-energized (state based suppression)"}, }, { "tag": "MECH-1.LOAD.HI", "meter_id": "MECH-1", "parameter": "load_pct", "kind": "HI", diff --git a/backend/simulator.py b/backend/simulator.py index eab1806..86d1e26 100644 --- a/backend/simulator.py +++ b/backend/simulator.py @@ -390,7 +390,8 @@ def step(self, now: float) -> Dict[str, Dict[str, Any]]: mech_kva = mech_kw / mech_pf mech_v = v_src * (1 - 0.006 * mech_kva / cfg["rated_kva"]) if src_live else 0.0 readings["MECH-1"] = self._reading("MECH-1", now, dt, mech_v, mech_kva, mech_kw, - mech_pf if mech_kw > 0 else 0.0, f_src, status=mech_status) + mech_pf if mech_kw > 0 else 0.0, f_src, status=mech_status, + energized=src_live) # --- Main switchboard and ATS ---------------------------------------- total_kw = ups_in_kw + mech_kw + house_kw diff --git a/backend/tests/test_alarms.py b/backend/tests/test_alarms.py index acbe34d..9ea1d58 100644 --- a/backend/tests/test_alarms.py +++ b/backend/tests/test_alarms.py @@ -269,5 +269,6 @@ def test_outage_through_real_alarm_database(): alarmed = {e["tag"] for e in events if e["event"] == "ALARM"} assert {"UTIL-1.FAIL", "UPS-A.ONBATT", "UPS-B.ONBATT", "ATS-1.EMERG"} <= alarmed assert "UTIL-1.V.LO" not in alarmed # cascade suppressed by the failure alarm + assert "MECH-1.PF.LO" not in alarmed # no nuisance alarm from a de-energized panel states = {a["tag"]: a["state"] for a in mgr.alarm_list()} assert states.get("UPS-A.ONBATT") == "RTN_UNACK" # ran on battery, nobody acked diff --git a/frontend/src/services/websocket.js b/frontend/src/services/websocket.js deleted file mode 100644 index 0076ace..0000000 --- a/frontend/src/services/websocket.js +++ /dev/null @@ -1,56 +0,0 @@ -import { useState, useEffect, useRef, useCallback } from 'react' - -const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000' -const WS_URL = API_URL.replace(/^https:\/\//, 'wss://').replace(/^http:\/\//, 'ws://') + '/ws/live' -const RECONNECT_DELAY = 3000 - -export function useWebSocket() { - const [readings, setReadings] = useState({}) - const [connected, setConnected] = useState(false) - const wsRef = useRef(null) - const timerRef = useRef(null) - - const connect = useCallback(() => { - if (wsRef.current?.readyState === WebSocket.OPEN) return - - const ws = new WebSocket(WS_URL) - wsRef.current = ws - - ws.onopen = () => { - setConnected(true) - if (timerRef.current) clearTimeout(timerRef.current) - } - - ws.onmessage = (evt) => { - try { - const msg = JSON.parse(evt.data) - if (msg.type === 'readings') { - setReadings(prev => { - const next = { ...prev } - for (const r of msg.data) { - next[r.meter_id] = r - } - return next - }) - } - } catch (_) {} - } - - ws.onclose = () => { - setConnected(false) - timerRef.current = setTimeout(connect, RECONNECT_DELAY) - } - - ws.onerror = () => ws.close() - }, []) - - useEffect(() => { - connect() - return () => { - if (timerRef.current) clearTimeout(timerRef.current) - wsRef.current?.close() - } - }, [connect]) - - return { readings, connected } -} From 6e4a841cddbdd62ef5a389a031155d61b7dd798c Mon Sep 17 00:00:00 2001 From: AddisonTech Date: Fri, 16 Oct 2026 16:15:49 +0000 Subject: [PATCH 06/10] Rebuild the front end for the live demo Cold start wake screen, About this demo panel with event triggers, ISA 18.2 alarm list with acknowledge and shelve, alarm journal and database, new one-line diagram, responsive layout for phones, lazy loaded chart pages, and feed reducer tests. --- frontend/.env.example | 6 +- frontend/index.html | 23 +- frontend/package-lock.json | 2532 +++++++++++++++++++++++ frontend/package.json | 12 +- frontend/src/App.css | 1011 +++++---- frontend/src/App.jsx | 149 +- frontend/src/components/AboutPanel.jsx | 136 ++ frontend/src/components/AlarmBanner.jsx | 50 + frontend/src/components/Badges.jsx | 22 + frontend/src/components/Sparkline.jsx | 86 + frontend/src/components/StateLegend.jsx | 39 + frontend/src/components/WakeScreen.jsx | 84 + frontend/src/index.css | 135 +- frontend/src/lib/alarms.js | 29 + frontend/src/lib/format.js | 48 + frontend/src/lib/operator.js | 24 + frontend/src/pages/Alarms.jsx | 390 +++- frontend/src/pages/Dashboard.jsx | 277 ++- frontend/src/pages/Meters.jsx | 286 +-- frontend/src/pages/OneLineDiagram.jsx | 330 +-- frontend/src/pages/SettingsPage.jsx | 139 +- frontend/src/pages/Trending.jsx | 197 +- frontend/src/services/LiveFeed.jsx | 132 ++ frontend/src/services/api.js | 41 +- frontend/src/services/endpoints.js | 12 + frontend/src/services/feed.js | 79 + frontend/src/services/feed.test.js | 86 + frontend/vite.config.js | 8 +- 28 files changed, 5190 insertions(+), 1173 deletions(-) create mode 100644 frontend/package-lock.json create mode 100644 frontend/src/components/AboutPanel.jsx create mode 100644 frontend/src/components/AlarmBanner.jsx create mode 100644 frontend/src/components/Badges.jsx create mode 100644 frontend/src/components/Sparkline.jsx create mode 100644 frontend/src/components/StateLegend.jsx create mode 100644 frontend/src/components/WakeScreen.jsx create mode 100644 frontend/src/lib/alarms.js create mode 100644 frontend/src/lib/format.js create mode 100644 frontend/src/lib/operator.js create mode 100644 frontend/src/services/LiveFeed.jsx create mode 100644 frontend/src/services/endpoints.js create mode 100644 frontend/src/services/feed.js create mode 100644 frontend/src/services/feed.test.js diff --git a/frontend/.env.example b/frontend/.env.example index 5934e2e..8116fa6 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -1 +1,5 @@ -VITE_API_URL=http://localhost:8000 +# Base URL of the backend API. Leave empty for local development: the Vite +# dev server proxies /api and /ws to http://localhost:8000. +# For a production build hosted separately from the API, set the API URL: +# VITE_API_URL=https://your-api.onrender.com +VITE_API_URL= diff --git a/frontend/index.html b/frontend/index.html index 67b1b2f..b43a095 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,14 +2,25 @@ - - Power Dashboard | EPMS - - - + + Power Dashboard | Data Center Power Monitoring + + + + + + + + + -
+
⚡ Loading Power Dashboard...
+ diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..1dfa88d --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,2532 @@ +{ + "name": "power-dashboard", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "power-dashboard", + "version": "1.0.0", + "dependencies": { + "lucide-react": "^0.379.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.23.1", + "recharts": "^2.12.7" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.3.0", + "vite": "^5.2.0", + "vitest": "^2.1.9" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.10.tgz", + "integrity": "sha512-EMCx3AGZ3WfAl6ht7AyQoPm2Lh+BGYEMdc4Q6Hf7uSCDOZFuLq44qNwL+iaim8VlyYhRAo4X43+weadK8ZB4Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.10.tgz", + "integrity": "sha512-NpugTzbKgGrNe45Ui32cN8vCFFMxVtP/9rtfwv0nP5FRDAjvYBxJcLVpYA9mr1jxP6cnIT7x9LUzuDTbWYYNRA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.10.tgz", + "integrity": "sha512-B3lYAs2nkKskbgQ1nfy8Ma9ao9Q1rntTAQHrzzyDuj+TSO+X3le6PfWwqDvodsb+OumE10eMFfuMCTQSQ5iuIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.9", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.4", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.4.tgz", + "integrity": "sha512-q7j5geK7xs3UJSdm9/iytUNclBnLmYx1EnSeCFXHPeutdqgIMeFeHtUZgS3EhlKxdBEAu8OwtJCwmLrEzpSs7Q==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.64.7.tgz", + "integrity": "sha512-GFF2tHk0NqYVObrK0+/ps/LEXsV/v2q6Lyiy7mZr+Ej24fpQScvqK2ziz9NHeEQYnKWKym38Ml7dZbPtC9tuAw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.64.7.tgz", + "integrity": "sha512-BOymcXJFYYXqluDidj6sLelNjXruC3u1BqVxLn2OPCXH9xaPSOTH+MS4uychsGI1NU7tJoiv9KvqijDHFe+hhQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.64.7.tgz", + "integrity": "sha512-jgVpGweIbls2H5jfBB70tnX52abMd5pJr3xmtoDILx6JdmGl+Un+tMb9R+MbHPVB46tTBpY8emtn7M71SnQhEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.64.7.tgz", + "integrity": "sha512-AVMpt94mrXH7WjyWKmd9nT4RC5yM0AN3Lt6A89xVIsuLDi3dDX6dxMytLbW36FlppY9JsoqUoS3LUUpUrYxiMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.64.7.tgz", + "integrity": "sha512-Nje29c/MyajxRNFGU05oyeTDS6SWdMg/wWMSlZSBTBju5BKz2NVc0kFiFSQGzRELNiB+CBk/ZvAVsWsENgjGag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.64.7.tgz", + "integrity": "sha512-xxgN5/kMzCNz/NYJ4t49B0/WS6InNlWv6xvgwUQqNnWM9WJMMwMUGWrAxdNEgYWdHL0sMnuh8I87StGrIMTA+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.64.7.tgz", + "integrity": "sha512-5U/9gVn/X657I8+NHoHO9Wnfyd0lEXwqbslobRoB9TC8SwYzOitcIr6TLE7531Q/NWs3L4mb+YOGzlf3vHIeYw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.64.7.tgz", + "integrity": "sha512-hcDS0a/Y8ggM3dcOfzH7UpSaogCViWTtNDSl0EXpWIj8g8/r86ITqptjil2hayTXS0Umzb+Yt3mjgpQVFVf2+A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.64.7.tgz", + "integrity": "sha512-awbAr4N7Qd/yjZAQBEEPzgcPveYG2Gi5L6gq1/Bp+3SMRjn5F68Wv1zKsntzvvoioBR6yKvhLtWqu11am1TsxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.64.7.tgz", + "integrity": "sha512-Ut7xQJfeLhzu2yN3rHzVvL9ccyPJvN4aCdP1V7hJ5lGxX/eCzgB9SiMk/Md3J+rWWZgvoYsDW4BUFggJr32pBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.64.7.tgz", + "integrity": "sha512-trqoni/vHkuM5oo5iQhoKPh6fjjD7E80pMgCXWgGxU8vSRPUlwvG8GeYvEEcB6eJAxNa99WH9iVHPHelgtKiHA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.64.7.tgz", + "integrity": "sha512-gvlUy0XFIwtUWiQmhc+4GT2Knm3KosinpUVhr7CtTFA78gFDnE5NWwMPzHrJsYpKkh2LlY7yvBIboN1FAV6Xeg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.64.7.tgz", + "integrity": "sha512-8yS/kSXTJ/47Z62JW+C2AJ3vd/8zZw016vFjtNpZwmZlwJumLua4s1i78dkYuSSqQ+0aIMxJcBp/4uIwp2ehjA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.64.7.tgz", + "integrity": "sha512-mxVSKvvty0hOP1AFo/l4Kpv3i3HK0zx4rYUrirZDToYlWhS3xzmIkq3vUJ7rtrM2cPyXveDyDT6M1FfXZ9hTRA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.64.7.tgz", + "integrity": "sha512-lEse1zra1CagM+uHH2bl28GInDsZZ45NJzHei2OMaXQFzZWKBO1hFo07rS0xB6ayV4WU360UrSmPDSyCMpYsUQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.64.7.tgz", + "integrity": "sha512-d/cqCoiG9WMZ5VuJZ5Qdlv9g97QyoGwnmvHccvGhKSacTy7xFrAS+jMcJSBdMNOw1oacSkl6p7K6O/DRYTKL3g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.64.7.tgz", + "integrity": "sha512-kVEA//CeDOZZP1XCH2JBgqXb9+ALlwuA/4civaazMVdgzaSQC9WM38w65zG/LLk0lA7F9Od19CSBZW7J9mCbNg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.64.7.tgz", + "integrity": "sha512-14oLfDsOSr0TSntT/34jRg/V8B2XW/Jomh9zX9CjIM9gwwNlI1OCymS/GVn0DV32h67eRf7U0GGem0rvfXgNwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.64.7.tgz", + "integrity": "sha512-dFVtPfjZqAnUPpPY4Bfg+87yo1IBW9HiY8iCFtg49Pn46MfZTebSHZh8PL6SOsgyt9LQP8Nj/sE6jm3aWpySmQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.64.7.tgz", + "integrity": "sha512-Dm9CZ2SM3u2NgvBj4awW/gGqkOwzH8f6MSYIJE6+bKcKLI+T0+LhpD6vtetTfrIIx+rLXDf5RJqBP6v7V5O+wg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.64.7.tgz", + "integrity": "sha512-oaxsvS2mL6+78741CT2HCORBvy1USg3Wqpt5qvZwy3aMXRMl4zxyDo8maeFRWJkF3dp0Wbi71fKH5Gr9YI3vYA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.64.7.tgz", + "integrity": "sha512-UKZz1Y4mxUqkWh60uH7B1aZn6UcAimPk4ipRktpb3wfZq7JrzZYyAXTwiafkb3T+kd5P3Sf+vzcRdsDks4WtjQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.64.7.tgz", + "integrity": "sha512-WWkSuC1J+mZJnsDh0mRaCAFSWfQdl6y3fDjZeWElI6zHo8CcOSG5lY3yurKJjEq+FrX0WD60sFrVVpbHqzMmrw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.64.7.tgz", + "integrity": "sha512-u9bp2yXCI3/BUjUxY6uWknAY32pfvvDCPysyUTySotx0dj3ydlFHrRQYfn/b/kZgnfjyEwySMtI7Ga054uiysQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.64.7.tgz", + "integrity": "sha512-EhX6N3XPMEnVU5cRfNgzPOKcSucsbu3nNNWuoAaEuKIqmddBKHN5b9d4rPe65T1I+FaOT176JKiZNsUBp3rqbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-kVd74ta9eof3eJOvbNd1vGKS/XERRyQbT26Og63hIsvDO84cjD5gEOhsXf26w3FSoNlPVz84DOFcKv/oou+fMw==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@vitest/expect": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.9.tgz", + "integrity": "sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.9.tgz", + "integrity": "sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "2.1.9", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.9.tgz", + "integrity": "sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.9.tgz", + "integrity": "sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "2.1.9", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.9.tgz", + "integrity": "sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.9.tgz", + "integrity": "sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.9.tgz", + "integrity": "sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "2.1.9", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.29", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.29.tgz", + "integrity": "sha512-YeesxhUmR4h5y5V8KF8iBCqJb8YFrBJ++XBTeGcWIaQOYXGN19JM0FoiOjAhwuDoln8owMgXcWBmgHtYSkky2w==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.29.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.3.tgz", + "integrity": "sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.26", + "caniuse-lite": "^1.0.30001813", + "electron-to-chromium": "^1.5.439", + "node-releases": "^2.0.57", + "update-browserslist-db": "^1.3.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001816", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001816.tgz", + "integrity": "sha512-+8Yx7BXCoqk6IF8yTicjfUR6D/ldJzdlsodlEOiOSPmhK844WIgk67/zIQaGAOxNkZyyvBlrRFnLvqKIoqbAFw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.458", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.458.tgz", + "integrity": "sha512-/hIH2gRSmxrf4/X4Nw/t/Wc8PVS22l8/3HnWjWTWsTOM5dsnMUPZF/+u+yr3LqweNuTBJE1rq6qAQzKkZVwMfA==", + "dev": true, + "license": "ISC" + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-equals": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.5.tgz", + "integrity": "sha512-yKEpcFuRPu/pTQL2VB8YKE2yFldrLlIsoWtJeBnAdqEhvu21OgkFT0C8njf/xYc2LSZGEr3K9JGjthHJxnVLvQ==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.379.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.379.0.tgz", + "integrity": "sha512-KcdeVPqmhRldldAAgptb8FjIunM2x2Zy26ZBh1RsEUcdLIvsEmbcw7KpzFYUy5BbpGeWhPu9Z9J5YXfStiXwhg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.59", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.59.tgz", + "integrity": "sha512-5qr2okC4ItAI0hG5SaV0HoYMpnM/Y6+Oqr7AmPYy/2uEoGvS+GbSKLeRxSS1uAdu59yz0ouzcuXievSgg///WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.30", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.30.tgz", + "integrity": "sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.20", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.30.6", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.6.tgz", + "integrity": "sha512-5HfK7k5im7LTOB0EqCQmfvy4C13G92Ssj1VTmouTK3AJvyjKTnFuCV0vcMAD/JS+JC4DvDIBRrlAeJIFjh5VWg==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.6", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.6.tgz", + "integrity": "sha512-0RHKZz7wwffvkU+2MFVT2NnjK44ssLEV+m0CAJaS2Ksmorrwj7WxH00jO0SOCW26/tINUnJHToXblDs33I38YQ==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.4", + "react-router": "6.30.6" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-smooth": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", + "license": "MIT", + "dependencies": { + "fast-equals": "^5.0.1", + "prop-types": "^15.8.1", + "react-transition-group": "^4.4.5" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/recharts": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", + "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", + "deprecated": "1.x and 2.x branches are no longer active. Bump to Recharts v3 to receive latest features and bugfixes. See https://github.com/recharts/recharts/wiki/3.0-migration-guide", + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.21", + "react-is": "^18.3.1", + "react-smooth": "^4.0.4", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "license": "MIT", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/rollup": { + "version": "4.64.7", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.64.7.tgz", + "integrity": "sha512-aCiJONoZp0lNGJ6sYqspLkh6UXaWEey/7Ko2TZyXQ4kgzAhDUxAgbt/oulXKmD+zFHXw1k+RF6ZZWOrjp7DZnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.64.7", + "@rollup/rollup-android-arm64": "4.64.7", + "@rollup/rollup-darwin-arm64": "4.64.7", + "@rollup/rollup-darwin-x64": "4.64.7", + "@rollup/rollup-freebsd-arm64": "4.64.7", + "@rollup/rollup-freebsd-x64": "4.64.7", + "@rollup/rollup-linux-arm-gnueabihf": "4.64.7", + "@rollup/rollup-linux-arm-musleabihf": "4.64.7", + "@rollup/rollup-linux-arm64-gnu": "4.64.7", + "@rollup/rollup-linux-arm64-musl": "4.64.7", + "@rollup/rollup-linux-loong64-gnu": "4.64.7", + "@rollup/rollup-linux-loong64-musl": "4.64.7", + "@rollup/rollup-linux-ppc64-gnu": "4.64.7", + "@rollup/rollup-linux-ppc64-musl": "4.64.7", + "@rollup/rollup-linux-riscv64-gnu": "4.64.7", + "@rollup/rollup-linux-riscv64-musl": "4.64.7", + "@rollup/rollup-linux-s390x-gnu": "4.64.7", + "@rollup/rollup-linux-x64-gnu": "4.64.7", + "@rollup/rollup-linux-x64-musl": "4.64.7", + "@rollup/rollup-openbsd-x64": "4.64.7", + "@rollup/rollup-openharmony-arm64": "4.64.7", + "@rollup/rollup-win32-arm64-msvc": "4.64.7", + "@rollup/rollup-win32-ia32-msvc": "4.64.7", + "@rollup/rollup-win32-x64-gnu": "4.64.7", + "@rollup/rollup-win32-x64-msvc": "4.64.7", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.4.tgz", + "integrity": "sha512-t8wonIOdQyOjtPd2VktlBu6QjTVTks6v8bSi7kd0r2Vll8TK1JYDZtRRdbmCHOAMphkZgrzK+L+vXK4pyZ8t4A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/victory-vendor": { + "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.9.tgz", + "integrity": "sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.9.tgz", + "integrity": "sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.9", + "@vitest/mocker": "2.1.9", + "@vitest/pretty-format": "^2.1.9", + "@vitest/runner": "2.1.9", + "@vitest/snapshot": "2.1.9", + "@vitest/spy": "2.1.9", + "@vitest/utils": "2.1.9", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.9", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.9", + "@vitest/ui": "2.1.9", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/frontend/package.json b/frontend/package.json index b92490c..9b5f64b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,22 +1,24 @@ { "name": "power-dashboard", "private": true, - "version": "1.0.0", + "version": "1.1.0", "type": "module", "scripts": { "dev": "vite", "build": "vite build", - "preview": "vite preview" + "preview": "vite preview", + "test": "vitest run" }, "dependencies": { + "lucide-react": "^0.379.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.23.1", - "recharts": "^2.12.7", - "lucide-react": "^0.379.0" + "recharts": "^2.12.7" }, "devDependencies": { "@vitejs/plugin-react": "^4.3.0", - "vite": "^5.2.0" + "vite": "^5.2.0", + "vitest": "^2.1.9" } } diff --git a/frontend/src/App.css b/frontend/src/App.css index 2f2e98b..1c10069 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,430 +1,721 @@ -.app-layout { - display: flex; - height: 100vh; - overflow: hidden; -} +/* ===================================================================== */ +/* Layout */ +/* ===================================================================== */ + +.app-layout { display: flex; height: 100vh; height: 100dvh; overflow: hidden; } -/* Sidebar */ .sidebar { - width: 220px; + width: var(--sidebar-w); flex-shrink: 0; background: var(--bg-surface); border-right: 1px solid var(--border); display: flex; flex-direction: column; - overflow-y: auto; } - .sidebar-brand { - display: flex; - align-items: center; - gap: 10px; - padding: 20px 18px 16px; + display: flex; align-items: center; gap: 10px; + height: 56px; padding: 0 18px; border-bottom: 1px solid var(--border); } +.brand-icon { color: var(--accent); flex-shrink: 0; } +.brand-text { font-weight: 700; font-size: 15px; letter-spacing: 0.01em; white-space: nowrap; } -.brand-icon { color: var(--accent); } - -.brand-text { - font-weight: 700; - font-size: 16px; - letter-spacing: 0.08em; - color: var(--text-primary); -} - -.sidebar-nav { - display: flex; - flex-direction: column; - padding: 12px 8px; - gap: 2px; -} - +.sidebar-nav { display: flex; flex-direction: column; gap: 2px; padding: 12px 10px; flex: 1; } .nav-item { - display: flex; - align-items: center; - gap: 10px; + position: relative; + display: flex; align-items: center; gap: 11px; padding: 9px 12px; border-radius: var(--r-md); color: var(--text-secondary); - font-size: 13.5px; font-weight: 500; + border: 1px solid transparent; transition: background 0.15s, color 0.15s; - position: relative; -} - -.nav-item:hover { - background: var(--bg-elevated); - color: var(--text-primary); -} - -.nav-item.active { - background: var(--accent-dim); - color: var(--accent); - border: 1px solid var(--accent-border); } +.nav-item:hover { background: var(--bg-elevated); color: var(--text-primary); } +.nav-item.active { background: var(--accent-dim); color: var(--accent); border-color: var(--accent-border); } .nav-badge { margin-left: auto; - background: var(--status-crit); - color: white; - font-size: 10px; - font-weight: 700; - padding: 1px 6px; + min-width: 20px; padding: 1px 6px; border-radius: 10px; - min-width: 18px; - text-align: center; + font-size: 11px; font-weight: 700; text-align: center; + color: #0b0e12; background: var(--p4); +} +.nav-badge.p1 { background: var(--p1); color: #fff; } +.nav-badge.p2 { background: var(--p2); } +.nav-badge.p3 { background: var(--p3); } + +.sidebar-about { + display: flex; align-items: center; gap: 10px; + margin: 10px; padding: 9px 12px; + border-radius: var(--r-md); + background: none; border: 1px dashed var(--border-bright); + color: var(--text-secondary); font-weight: 500; } +.sidebar-about:hover { color: var(--text-primary); border-color: var(--accent-border); } + +.main-area { flex: 1; min-width: 0; display: flex; flex-direction: column; background: var(--bg-base); } -/* Topbar */ .topbar { - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 24px; - height: 52px; + display: flex; align-items: center; justify-content: space-between; gap: 12px; + height: 56px; padding: 0 20px; background: var(--bg-surface); border-bottom: 1px solid var(--border); flex-shrink: 0; } - -.topbar-title { - font-size: 15px; - font-weight: 600; - color: var(--text-primary); - letter-spacing: 0.02em; -} - -.topbar-right { - display: flex; - align-items: center; - gap: 16px; +.topbar-left { display: flex; align-items: center; gap: 10px; min-width: 0; } +.topbar-title { font-size: 15px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.topbar-right { display: flex; align-items: center; gap: 10px; } +.mobile-only { display: none; } + +.sim-pill { + display: inline-flex; align-items: center; gap: 6px; + padding: 4px 10px; border-radius: 999px; + background: var(--accent-dim); border: 1px solid var(--accent-border); + color: var(--accent); font-size: 12px; font-weight: 600; +} +.conn-pill { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; } +.conn-pill.live { color: var(--ok); } +.conn-pill.down { color: var(--p2); } +.conn-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; } +.conn-pill.live .conn-dot { box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.18); } +.conn-pill.down .conn-dot { animation: alarm-flash 1s infinite; } + +.icon-btn { + display: inline-flex; align-items: center; justify-content: center; + width: 32px; height: 32px; border-radius: var(--r-md); + background: none; border: 1px solid transparent; color: var(--text-secondary); +} +.icon-btn:hover { background: var(--bg-elevated); color: var(--text-primary); } + +.page-content { flex: 1; overflow-y: auto; padding: 20px 24px 32px; } +.page-content.stale { opacity: 0.6; transition: opacity 0.3s; } +.page { max-width: 1440px; margin: 0 auto; display: flex; flex-direction: column; gap: 18px; } +.page-loading { padding: 60px; text-align: center; color: var(--text-muted); } + +.page-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; flex-wrap: wrap; } +.page-header h2 { font-size: 20px; font-weight: 650; } +.page-header p { color: var(--text-secondary); font-size: 13px; } + +.bottom-nav { display: none; } + +/* ===================================================================== */ +/* Banners */ +/* ===================================================================== */ + +.event-banner { + display: flex; align-items: center; gap: 8px; + padding: 7px 20px; + background: var(--accent-dim); color: var(--accent); + border-bottom: 1px solid var(--accent-border); + font-size: 13px; } - -.conn-status { - display: flex; - align-items: center; - gap: 5px; - font-size: 12px; - font-weight: 500; +.alarm-banner { + display: flex; align-items: center; gap: 10px; + padding: 8px 20px; + border-bottom: 1px solid var(--border); + background: var(--bg-surface); + border-left: 4px solid var(--p4); } -.conn-ok { color: var(--status-ok); } -.conn-err { color: var(--status-crit); } +.alarm-banner.p1 { border-left-color: var(--p1); background: linear-gradient(90deg, var(--p1-dim), var(--bg-surface) 60%); } +.alarm-banner.p2 { border-left-color: var(--p2); background: linear-gradient(90deg, var(--p2-dim), var(--bg-surface) 60%); } +.alarm-banner.p3 { border-left-color: var(--p3); background: linear-gradient(90deg, var(--p3-dim), var(--bg-surface) 60%); } +.alarm-banner-msg { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.alarm-banner-actions { display: flex; gap: 6px; flex-shrink: 0; } -.topbar-alarm-count { - display: flex; - align-items: center; - gap: 5px; - font-size: 12px; - color: var(--status-warn); - font-weight: 500; -} +/* ===================================================================== */ +/* Common components */ +/* ===================================================================== */ -/* Main area */ -.main-area { - flex: 1; - display: flex; - flex-direction: column; - overflow: hidden; - background: var(--bg-base); +.card { + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: var(--r-lg); + padding: 16px 18px; + min-width: 0; +} +.card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; } +.card-head.wrap { flex-wrap: wrap; } +.card-head h3, .section-title { + display: flex; align-items: center; gap: 7px; + font-size: 12px; font-weight: 650; letter-spacing: 0.06em; text-transform: uppercase; + color: var(--text-secondary); } +.link { display: inline-flex; align-items: center; gap: 4px; color: var(--accent); font-size: 13px; font-weight: 500; } -.page-content { - flex: 1; - overflow-y: auto; - padding: 24px; -} +.btn { + display: inline-flex; align-items: center; justify-content: center; gap: 6px; + padding: 8px 14px; + border-radius: var(--r-md); + font-size: 13px; font-weight: 550; + border: 1px solid transparent; + transition: background 0.15s, border-color 0.15s, color 0.15s; + white-space: nowrap; +} +.btn-sm { padding: 5px 10px; font-size: 12px; } +.btn-primary { background: var(--accent); color: #0b0e12; } +.btn-primary:hover { filter: brightness(1.1); } +.btn-ghost { background: transparent; color: var(--text-secondary); border-color: var(--border-bright); } +.btn-ghost:hover { background: var(--bg-elevated); color: var(--text-primary); } +.btn-ack { background: var(--text-primary); color: #0b0e12; } +.btn-ack:hover { filter: brightness(0.9); } -/* Page header */ -.page-header { - margin-bottom: 24px; -} +.seg { display: inline-flex; gap: 2px; padding: 2px; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: var(--r-md); } +.seg-btn { padding: 4px 11px; border-radius: 6px; background: none; border: none; color: var(--text-secondary); font-size: 12px; font-weight: 550; } +.seg-btn:hover { color: var(--text-primary); } +.seg-btn.active { background: var(--accent-dim); color: var(--accent); } -.page-header h2 { - font-size: 20px; - font-weight: 600; +select, input[type="text"] { + background: var(--bg-elevated); + border: 1px solid var(--border-bright); color: var(--text-primary); - margin-bottom: 4px; -} - -.page-header p { - color: var(--text-secondary); - font-size: 13px; + padding: 6px 10px; + border-radius: var(--r-md); + font: inherit; font-size: 13px; + outline: none; } - -/* Grid layouts */ -.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; } -.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; } -.grid-auto { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; } - -/* Stat card */ +select:focus, input[type="text"]:focus { border-color: var(--accent); } + +.empty-state { padding: 32px 12px; text-align: center; color: var(--text-muted); display: flex; flex-direction: column; gap: 12px; align-items: center; } +.form-error { color: var(--p1); font-size: 12px; margin-top: 6px; } + +.status-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex-shrink: 0; background: var(--energized); } +.status-dot.off { background: var(--dead); } +.status-dot.p1 { background: var(--p1); } +.status-dot.p2 { background: var(--p2); } +.status-dot.p3 { background: var(--p3); } +.status-dot.p4 { background: var(--p4); } + +/* Priority and state badges */ +.prio-badge { + display: inline-flex; align-items: center; + padding: 2px 7px; border-radius: var(--r-sm); + font-size: 11px; font-weight: 700; letter-spacing: 0.02em; + white-space: nowrap; border: 1px solid transparent; +} +.prio-badge.p1 { background: var(--p1-dim); color: var(--p1); border-color: rgba(239, 68, 68, 0.4); } +.prio-badge.p2 { background: var(--p2-dim); color: var(--p2); border-color: rgba(249, 115, 22, 0.4); } +.prio-badge.p3 { background: var(--p3-dim); color: var(--p3); border-color: rgba(234, 179, 8, 0.4); } +.prio-badge.p4 { background: var(--p4-dim); color: var(--p4); border-color: rgba(167, 139, 250, 0.4); } +.prio-label { font-weight: 600; margin-left: 5px; } + +.state-badge { + --c: var(--p4); + display: inline-flex; align-items: center; gap: 6px; + padding: 2px 8px; border-radius: 999px; + font-size: 11px; font-weight: 650; white-space: nowrap; + border: 1px solid var(--c); color: var(--c); +} +.state-badge.p1 { --c: var(--p1); } +.state-badge.p2 { --c: var(--p2); } +.state-badge.p3 { --c: var(--p3); } +.state-icon { width: 8px; height: 8px; border-radius: 50%; background: var(--c); } +/* Unacknowledged: solid and flashing */ +.state-badge.state-unack { background: var(--c); color: #0b0e12; } +.state-badge.state-unack .state-icon { background: #0b0e12; animation: alarm-flash 1s infinite; } +/* Acknowledged: steady outline */ +.state-badge.state-acked .state-icon { background: var(--c); } +/* Returned to normal, unacknowledged: dashed and flashing hollow */ +.state-badge.state-rtn_unack { border-style: dashed; color: var(--text-secondary); } +.state-badge.state-rtn_unack .state-icon { background: none; border: 2px solid var(--c); animation: alarm-flash 1s infinite; } +/* Out of the alarm list */ +.state-badge.state-shelved, .state-badge.state-suppressed, .state-badge.state-normal { --c: var(--text-muted); } +.state-badge.state-suppressed { font-style: italic; } + +/* Stat cards */ +.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 14px; } .stat-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--r-lg); - padding: 20px; -} - -.stat-card-label { - font-size: 11px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.08em; + padding: 14px 16px; + min-width: 0; + display: flex; flex-direction: column; gap: 4px; + border-top: 3px solid var(--border); +} +.stat-card-label { font-size: 11px; font-weight: 650; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-muted); } +.stat-card-value { font-size: 26px; font-weight: 700; font-family: var(--font-mono); line-height: 1.15; } +.stat-card-value.small-value { font-size: 20px; } +.stat-card-unit { font-size: 13px; font-weight: 500; color: var(--text-muted); margin-left: 5px; } +.stat-card-sub { font-size: 12px; color: var(--text-secondary); } +.stat-card.tone-warn { border-top-color: var(--p3); } +.stat-card.tone-crit, .stat-card.tone-p1 { border-top-color: var(--p1); } +.stat-card.tone-p2 { border-top-color: var(--p2); } +.stat-card.tone-p3 { border-top-color: var(--p3); } +.stat-card.tone-p4 { border-top-color: var(--p4); } +.stat-card.tone-crit .stat-card-value, .stat-card.tone-p1 .stat-card-value { color: var(--p1); } + +.sparkline { width: 100%; display: block; margin-top: 6px; } +.spark-line { fill: none; stroke: var(--accent); stroke-width: 1.5; } +.spark-fill { fill: var(--accent-dim); stroke: none; } + +.area-chart-wrap { width: 100%; } +.area-chart { display: block; } +.area-line { fill: none; stroke: var(--accent); stroke-width: 1.8; } +.area-fill { fill: var(--accent-dim); } +.grid-line { stroke: var(--grid); stroke-width: 1; } +.axis-text { fill: var(--text-muted); font-size: 11px; font-family: var(--font-mono); } +.chart-empty { display: flex; align-items: center; justify-content: center; color: var(--text-muted); } + +.kv { display: flex; flex-direction: column; } +.kv > div { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; border-bottom: 1px solid var(--border); font-size: 13px; } +.kv > div:last-child { border-bottom: none; } +.kv dt { color: var(--text-secondary); } +.kv dd { text-align: right; overflow-wrap: anywhere; } + +.table-wrap { overflow-x: auto; } +.data-table { font-size: 13px; } +.data-table th { + padding: 8px 10px; + font-size: 11px; font-weight: 650; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); - margin-bottom: 8px; -} - -.stat-card-value { - font-size: 28px; - font-weight: 700; - font-family: var(--font-mono); - color: var(--text-primary); - line-height: 1; - margin-bottom: 4px; -} - -.stat-card-sub { - font-size: 12px; - color: var(--text-secondary); + border-bottom: 1px solid var(--border); + white-space: nowrap; } +.data-table td { padding: 9px 10px; border-bottom: 1px solid var(--border); vertical-align: top; } +.data-table tbody tr:hover td { background: var(--bg-hover); } +.empty-cell { text-align: center; color: var(--text-muted); padding: 24px; } -/* Status dot */ -.status-dot { - width: 8px; - height: 8px; - border-radius: 50%; - display: inline-block; - flex-shrink: 0; -} -.status-dot.ok { background: var(--status-ok); box-shadow: 0 0 6px var(--status-ok); } -.status-dot.warn { background: var(--status-warn); box-shadow: 0 0 6px var(--status-warn); } -.status-dot.crit { background: var(--status-crit); box-shadow: 0 0 6px var(--status-crit); animation: pulse-crit 1.2s infinite; } -.status-dot.off { background: var(--status-off); } +/* ===================================================================== */ +/* Dashboard */ +/* ===================================================================== */ -@keyframes pulse-crit { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.4; } -} - -/* Meter tile */ -.meter-tile { - background: var(--bg-card); - border: 1px solid var(--border); +.intro-card { + display: flex; gap: 14px; align-items: flex-start; + padding: 14px 16px; + background: linear-gradient(120deg, var(--accent-dim), transparent 70%), var(--bg-card); + border: 1px solid var(--accent-border); border-radius: var(--r-lg); - padding: 16px; - cursor: pointer; - transition: border-color 0.15s, background 0.15s; -} -.meter-tile:hover { background: var(--bg-hover); border-color: var(--border-bright); } -.meter-tile.status-ok { border-left: 3px solid var(--status-ok); } -.meter-tile.status-warn { border-left: 3px solid var(--status-warn); } -.meter-tile.status-crit { border-left: 3px solid var(--status-crit); } - -.meter-tile-header { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 12px; } +.intro-icon { color: var(--accent); flex-shrink: 0; margin-top: 2px; } +.intro-text { flex: 1; color: var(--text-secondary); } +.intro-text strong { color: var(--text-primary); } +.intro-actions { margin-top: 10px; display: flex; gap: 8px; flex-wrap: wrap; } -.meter-tile-name { - font-weight: 600; - font-size: 13px; -} +.dash-row { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: 14px; } +.alarm-card .empty-state { padding: 20px; } -.meter-tile-metrics { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 8px; -} - -.metric-cell { - display: flex; - flex-direction: column; - gap: 2px; -} - -.metric-label { - font-size: 10px; - text-transform: uppercase; - letter-spacing: 0.06em; - color: var(--text-muted); -} - -.metric-value { - font-size: 15px; - font-weight: 600; - font-family: var(--font-mono); - color: var(--text-primary); -} - -.metric-unit { - font-size: 10px; - color: var(--text-muted); - font-family: var(--font-mono); -} - -/* Buttons */ -.btn { - display: inline-flex; - align-items: center; - gap: 6px; - padding: 7px 14px; +.mini-alarms { list-style: none; display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; } +.mini-alarms li { + display: flex; align-items: center; gap: 10px; + padding: 7px 10px; + background: var(--bg-elevated); border-radius: var(--r-md); + border-left: 3px solid var(--p4); font-size: 13px; - font-weight: 500; - border: none; - transition: background 0.15s, opacity 0.15s; -} - -.btn-primary { - background: var(--accent); - color: #000; } -.btn-primary:hover { opacity: 0.85; } - -.btn-ghost { - background: transparent; - color: var(--text-secondary); +.mini-alarms li.p1 { border-left-color: var(--p1); } +.mini-alarms li.p2 { border-left-color: var(--p2); } +.mini-alarms li.p3 { border-left-color: var(--p3); } +.mini-alarms li.more { border-left-color: transparent; justify-content: center; } +.mini-alarm-text { flex: 1; min-width: 0; } +.mini-alarm-text .muted { font-size: 12px; } + +.equip-group { display: flex; flex-direction: column; gap: 10px; } +.equip-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; } +.equip-tile { + text-align: left; + display: flex; flex-direction: column; gap: 8px; + padding: 13px 14px; + background: var(--bg-card); border: 1px solid var(--border); -} -.btn-ghost:hover { background: var(--bg-elevated); color: var(--text-primary); } - -.btn-warn { - background: var(--status-warn-dim); - color: var(--status-warn); - border: 1px solid rgba(245,158,11,0.3); -} -.btn-warn:hover { background: rgba(245,158,11,0.2); } - -/* Table */ -.data-table { - width: 100%; - border-spacing: 0; -} - -.data-table th { - padding: 10px 14px; - font-size: 11px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.06em; - color: var(--text-muted); - border-bottom: 1px solid var(--border); - background: var(--bg-surface); -} - -.data-table td { - padding: 11px 14px; - font-size: 13px; - border-bottom: 1px solid var(--border); - color: var(--text-primary); -} - -.data-table tr:hover td { background: var(--bg-hover); } - -.data-table tr.priority-1 td { border-left: 3px solid var(--status-crit); } -.data-table tr.priority-2 td { border-left: 3px solid var(--status-warn); } -.data-table tr.priority-3 td { border-left: 3px solid var(--accent); } -.data-table tr.priority-4 td { border-left: 3px solid var(--border-bright); } - -/* Tab bar */ -.tab-bar { - display: flex; - gap: 4px; - border-bottom: 1px solid var(--border); - margin-bottom: 20px; -} - + border-left: 4px solid var(--border-bright); + border-radius: var(--r-lg); + transition: background 0.15s, border-color 0.15s; +} +.equip-tile:hover { background: var(--bg-hover); border-color: var(--border-bright); } +.equip-tile.off { border-left-color: var(--dead); } +.equip-tile.off .metric-value { color: var(--text-muted); } +.equip-tile.has-alarm.p1 { border-left-color: var(--p1); } +.equip-tile.has-alarm.p2 { border-left-color: var(--p2); } +.equip-tile.has-alarm.p3 { border-left-color: var(--p3); } +.equip-tile.has-alarm.p4 { border-left-color: var(--p4); } +.equip-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; } +.equip-name { font-weight: 600; } +.equip-id { font-size: 11px; color: var(--text-muted); } +.equip-status { font-size: 12px; color: var(--text-secondary); font-weight: 500; } +.status-on-battery, .status-failed { color: var(--p1) !important; font-weight: 650 !important; } +.status-on-generator, .status-sag, .status-running, .status-cranking, .status-restarting { color: var(--p3) !important; } +.status-de-energized, .status-standby, .status-comm-fail { color: var(--text-muted) !important; } +.equip-metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; } +.metric-value { font-family: var(--font-mono); font-weight: 600; font-size: 15px; } +.metric-unit { font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); margin-left: 3px; } +.load-bar { height: 5px; background: var(--bg-elevated); border-radius: 3px; overflow: hidden; } +.load-bar-fill { height: 100%; background: var(--energized); border-radius: 3px; transition: width 0.4s; } +.load-bar-fill.p3 { background: var(--p3); } +.load-bar-fill.p2 { background: var(--p2); } +.equip-extra { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-secondary); } +.equip-alarm { font-size: 12px; color: var(--text-primary); font-weight: 500; } + +/* ===================================================================== */ +/* Alarms */ +/* ===================================================================== */ + +.help-card { padding: 18px; } +.prio-counts { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin-top: 4px; } +.prio-count { display: flex; flex-direction: column; align-items: center; padding: 4px 0; border-radius: var(--r-md); background: var(--bg-elevated); color: var(--text-muted); } +.prio-count .mono { font-size: 18px; font-weight: 700; } +.prio-count small { font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em; } +.prio-count.on.p1 { color: var(--p1); background: var(--p1-dim); } +.prio-count.on.p2 { color: var(--p2); background: var(--p2-dim); } +.prio-count.on.p3 { color: var(--p3); background: var(--p3-dim); } +.prio-count.on.p4 { color: var(--p4); background: var(--p4-dim); } + +.tab-bar { display: flex; gap: 2px; border-bottom: 1px solid var(--border); margin: -4px -2px 14px; overflow-x: auto; scrollbar-width: none; } .tab-btn { - padding: 8px 16px; - background: none; - border: none; - color: var(--text-secondary); - font-size: 13px; - font-weight: 500; - border-bottom: 2px solid transparent; + display: inline-flex; align-items: center; gap: 6px; + padding: 8px 13px; + background: none; border: none; border-bottom: 2px solid transparent; + color: var(--text-secondary); font-weight: 550; white-space: nowrap; margin-bottom: -1px; - transition: color 0.15s, border-color 0.15s; } .tab-btn:hover { color: var(--text-primary); } .tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); } +.tab-count { font-size: 11px; padding: 0 6px; border-radius: 8px; background: var(--bg-elevated); color: var(--text-secondary); } -/* Period selector */ -.period-selector { - display: flex; - gap: 4px; -} -.period-btn { - padding: 5px 12px; - border-radius: var(--r-sm); - background: var(--bg-elevated); - border: 1px solid var(--border); - color: var(--text-secondary); - font-size: 12px; - font-weight: 500; - transition: all 0.15s; -} -.period-btn:hover { color: var(--text-primary); } -.period-btn.active { - background: var(--accent-dim); - border-color: var(--accent-border); - color: var(--accent); -} - -/* Gauge */ -.gauge-container { - display: flex; - flex-direction: column; - align-items: center; - gap: 8px; -} - -.gauge-label { - font-size: 11px; - text-transform: uppercase; - letter-spacing: 0.06em; - color: var(--text-muted); -} - -.gauge-value { - font-size: 22px; - font-weight: 700; - font-family: var(--font-mono); -} +.list-toolbar { display: flex; justify-content: flex-end; margin-bottom: 10px; } -/* Select */ -select { +.alarm-list { display: flex; flex-direction: column; gap: 6px; } +.alarm-list-head, .alarm-main { + display: grid; + grid-template-columns: 28px 76px minmax(0, 1fr) 130px 104px 118px 190px; + grid-template-areas: "exp time desc val prio state act"; + align-items: center; gap: 10px; +} +.alarm-expand { grid-area: exp; } +.alarm-time { grid-area: time; } +.alarm-desc { grid-area: desc; } +.alarm-val { grid-area: val; } +.alarm-prio { grid-area: prio; } +.alarm-state { grid-area: state; } +.alarm-actions { grid-area: act; } +.alarm-list-head { padding: 0 12px 4px; font-size: 11px; font-weight: 650; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); } +.alarm-row { background: var(--bg-elevated); border: 1px solid var(--border); - color: var(--text-primary); - padding: 6px 10px; + border-left: 4px solid var(--p4); border-radius: var(--r-md); - font-size: 13px; - font-family: var(--font-sans); - cursor: pointer; - outline: none; + padding: 9px 12px; } -select:focus { border-color: var(--accent); } - -/* Input */ -input[type="text"], input[type="date"] { - background: var(--bg-elevated); - border: 1px solid var(--border); - color: var(--text-primary); - padding: 6px 10px; - border-radius: var(--r-md); +.alarm-row.p1 { border-left-color: var(--p1); } +.alarm-row.p2 { border-left-color: var(--p2); } +.alarm-row.p3 { border-left-color: var(--p3); } +.alarm-row.state-unack.p1 { background: linear-gradient(90deg, var(--p1-dim), var(--bg-elevated) 50%); } +.alarm-row.state-rtn_unack, .alarm-row.state-shelved, .alarm-row.state-suppressed { border-left-style: dashed; } +.alarm-row.state-shelved, .alarm-row.state-suppressed { opacity: 0.85; } +.alarm-expand { width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center; background: none; border: none; color: var(--text-muted); border-radius: 6px; } +.alarm-expand:hover { background: var(--bg-hover); color: var(--text-primary); } +.alarm-cell { display: flex; flex-direction: column; min-width: 0; } +.alarm-msg { font-weight: 600; } +.alarm-desc .muted { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.alarm-actions { flex-direction: row; gap: 6px; justify-content: flex-end; align-items: center; flex-wrap: wrap; } +.alarm-actions .muted { display: inline-flex; align-items: center; gap: 4px; } +.alarm-details { + display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px 20px; + margin: 10px 0 2px 38px; padding-top: 10px; border-top: 1px solid var(--border); font-size: 13px; - font-family: var(--font-sans); - outline: none; } -input:focus { border-color: var(--accent); } - -/* Checkbox */ -input[type="checkbox"] { accent-color: var(--accent); cursor: pointer; } - -/* Value flash animation */ -@keyframes value-flash { - 0% { color: var(--accent); } - 100% { color: var(--text-primary); } +.alarm-details dt { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted); } + +.shelve-form { + display: flex; flex-wrap: wrap; align-items: center; gap: 8px; + margin: 10px 0 0 38px; padding: 10px; border-radius: var(--r-md); + background: var(--bg-card); border: 1px solid var(--border); +} +.shelve-form input { flex: 1; min-width: 200px; } +.shelve-label { font-size: 12px; color: var(--text-secondary); } +.shelve-actions { display: flex; gap: 6px; } +.shelve-form .small { flex-basis: 100%; } + +.journal-filter { margin-bottom: 12px; flex-wrap: wrap; } +.ev-tag { font-size: 11px; font-weight: 650; padding: 2px 7px; border-radius: var(--r-sm); background: var(--bg-elevated); color: var(--text-secondary); white-space: nowrap; } +.ev-tag.ev-alarm { color: var(--p1); background: var(--p1-dim); } +.ev-tag.ev-ack { color: var(--accent); background: var(--accent-dim); } +.ev-tag.ev-rtn { color: var(--ok); background: rgba(34, 197, 94, 0.12); } +.db-intro { margin-bottom: 12px; font-size: 13px; } + +/* State legend */ +.state-legend { display: flex; flex-direction: column; gap: 14px; } +.state-flow { display: flex; flex-direction: column; gap: 8px; overflow-x: auto; } +.flow-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } +.flow-node { padding: 4px 10px; border-radius: 999px; border: 1px solid var(--border-bright); font-size: 12px; font-weight: 600; white-space: nowrap; } +.flow-node.unack { background: var(--p2); color: #0b0e12; border-color: var(--p2); } +.flow-node.acked { border-color: var(--p2); color: var(--p2); } +.flow-node.rtn { border: 1px dashed var(--p2); color: var(--text-secondary); } +.flow-arrow { display: inline-flex; flex-direction: column; align-items: center; font-size: 10px; color: var(--text-muted); line-height: 1; } +.flow-arrow span { font-size: 16px; } +.state-list { display: flex; flex-direction: column; gap: 8px; } +.state-list-row { display: grid; grid-template-columns: 120px 1fr; gap: 12px; align-items: start; font-size: 13px; } +.state-list-row dd { color: var(--text-secondary); } + +/* ===================================================================== */ +/* One-line diagram */ +/* ===================================================================== */ + +.ol-layout { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 14px; align-items: start; } +.ol-layout:has(> :only-child) { grid-template-columns: minmax(0, 1fr); } +.ol-card { padding: 12px; } +.ol-legend { display: flex; gap: 16px; flex-wrap: wrap; font-size: 12px; color: var(--text-secondary); padding: 0 4px 8px; } +.ol-legend span { display: inline-flex; align-items: center; gap: 6px; } +.lg { display: inline-block; width: 22px; height: 0; border-top: 3px solid; } +.lg-flow { border-color: var(--flow); } +.lg-live { border-color: var(--energized); } +.lg-dead { border-color: var(--dead); border-top-style: dashed; } +.ol-scroll { overflow-x: auto; } +.ol-svg { display: block; width: 100%; max-width: 1000px; height: auto; margin: 0 auto; } +.ol-svg.ol-wide { min-width: 680px; } +.ol-svg.ol-narrow { max-width: 440px; } + +.wire { stroke-width: 3; stroke-linejoin: round; } +.wire-live { stroke: var(--energized); } +.wire-dead { stroke: var(--dead); stroke-dasharray: 6 5; } +.wire-flow { stroke: var(--flow); stroke-width: 3.5; } +.bus { stroke-width: 6; stroke-linecap: round; } +.bus-live { stroke: var(--flow); } +.bus-dead { stroke: var(--dead); } +.ol-wire-label { fill: var(--text-muted); font-size: 11px; font-family: var(--font-mono); } + +.ol-node { cursor: pointer; } +.ol-box { fill: var(--bg-elevated); stroke: var(--border-bright); stroke-width: 1.5; transition: stroke 0.2s; } +.ol-node:hover .ol-box { stroke: var(--text-secondary); } +.ol-node.selected .ol-box { stroke: var(--accent); stroke-width: 2.5; } +.ol-node.dead .ol-box { fill: var(--bg-card); } +.ol-node.alarmed.p1 .ol-box { stroke: var(--p1); stroke-width: 2.5; } +.ol-node.alarmed.p2 .ol-box { stroke: var(--p2); stroke-width: 2.5; } +.ol-node.alarmed.p3 .ol-box { stroke: var(--p3); stroke-width: 2.5; } +.ol-node.alarmed.p4 .ol-box { stroke: var(--p4); stroke-width: 2.5; } +.ol-name { fill: var(--text-primary); font-size: 13px; font-weight: 650; } +.ol-status { fill: var(--text-secondary); font-size: 11.5px; font-weight: 500; } +.ol-status.status-on-battery, .ol-status.status-failed { fill: var(--p1); font-weight: 700; } +.ol-status.status-on-generator, .ol-status.status-running, .ol-status.status-cranking, .ol-status.status-sag, .ol-status.status-restarting { fill: var(--p3); } +.ol-status.status-de-energized, .ol-status.status-standby { fill: var(--text-muted); } +.ol-values { fill: var(--text-secondary); font-size: 11.5px; font-family: var(--font-mono); white-space: pre; } +.ol-node.dead .ol-values, .ol-node.dead .ol-name { fill: var(--text-muted); } +.ol-alarm-dot { fill: var(--p4); } +.ol-node.p1 .ol-alarm-dot { fill: var(--p1); animation: alarm-flash 1s infinite; } +.ol-node.p2 .ol-alarm-dot { fill: var(--p2); } +.ol-node.p3 .ol-alarm-dot { fill: var(--p3); } +.ol-detail { display: flex; flex-direction: column; gap: 10px; position: sticky; top: 0; } + +/* ===================================================================== */ +/* Meters and trends */ +/* ===================================================================== */ + +.meters-layout { flex-direction: row; align-items: flex-start; } +.meter-list { width: 210px; flex-shrink: 0; position: sticky; top: 0; } +.meter-select-label, .meter-select { display: none; } +.meter-buttons { display: flex; flex-direction: column; gap: 3px; } +.meter-btn { + display: flex; align-items: center; gap: 9px; + padding: 8px 10px; border-radius: var(--r-md); + background: none; border: 1px solid transparent; + text-align: left; font-size: 13px; color: var(--text-secondary); +} +.meter-btn:hover { background: var(--bg-elevated); color: var(--text-primary); } +.meter-btn.active { background: var(--accent-dim); border-color: var(--accent-border); color: var(--accent); } +.meter-btn-name { flex: 1; } +.meter-detail { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 14px; } +.status-chip { padding: 4px 12px; border-radius: 999px; background: var(--bg-elevated); border: 1px solid var(--border-bright); font-size: 12px; font-weight: 600; } + +.gauges { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; } +.gauge { display: flex; flex-direction: column; align-items: center; } +.gauge-svg { width: 100%; max-width: 150px; } +.gauge-track { fill: none; stroke: var(--bg-elevated); stroke-width: 9; stroke-linecap: round; } +.gauge-fill { fill: none; stroke: var(--energized); stroke-width: 9; stroke-linecap: round; transition: d 0.4s; } +.g-warn .gauge-fill { stroke: var(--p3); } +.g-crit .gauge-fill { stroke: var(--p2); } +.gauge-value { fill: var(--text-primary); font-family: var(--font-mono); font-size: 16px; font-weight: 700; } +.gauge-unit { fill: var(--text-muted); font-size: 9px; } +.gauge-label { font-size: 11px; font-weight: 650; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); } + +.trend-controls { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } +.trend-card-controls { display: flex; flex-direction: column; gap: 14px; } +.control-row { display: flex; gap: 24px; flex-wrap: wrap; } +.control-group { display: flex; flex-direction: column; gap: 6px; } +.control-label { font-size: 11px; font-weight: 650; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); } +.chip-row { display: flex; flex-wrap: wrap; gap: 6px; } +.chip { padding: 4px 11px; border-radius: 999px; background: var(--bg-elevated); border: 1px solid var(--border-bright); color: var(--text-secondary); font-size: 12px; font-weight: 550; } +.chip.on { background: var(--bg-card); } + +/* ===================================================================== */ +/* System page */ +/* ===================================================================== */ + +.settings-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; } +.settings-grid .span-2 { grid-column: span 2; } +.settings-grid .card > p { margin-top: 10px; } +.operator-form { display: flex; flex-direction: column; gap: 8px; } +.operator-row { display: flex; gap: 8px; } +.operator-row input { flex: 1; min-width: 0; } + +/* ===================================================================== */ +/* About modal */ +/* ===================================================================== */ + +.modal-backdrop { + position: fixed; inset: 0; z-index: 50; + background: rgba(5, 7, 10, 0.72); + display: flex; align-items: flex-start; justify-content: center; + padding: 5vh 16px; overflow-y: auto; +} +.modal { + width: 100%; max-width: 680px; + background: var(--bg-card); + border: 1px solid var(--border-bright); + border-radius: var(--r-lg); + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); +} +.modal-head { display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; border-bottom: 1px solid var(--border); } +.modal-head h2 { font-size: 18px; } +.modal-body { padding: 18px 20px 22px; display: flex; flex-direction: column; gap: 20px; } +.modal-body section { display: flex; flex-direction: column; gap: 8px; } +.modal-body h3 { font-size: 12px; font-weight: 650; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-muted); } +.modal-body p { color: var(--text-secondary); } +.modal-body .btn { align-self: flex-start; } +.sim-notice { + display: flex; gap: 12px; align-items: flex-start; + padding: 12px 14px; border-radius: var(--r-md); + background: var(--accent-dim); border: 1px solid var(--accent-border); color: var(--text-secondary); +} +.sim-notice svg { color: var(--accent); flex-shrink: 0; margin-top: 2px; } +.sim-notice strong { color: var(--text-primary); } + +.scenario-list { display: flex; flex-direction: column; gap: 8px; } +.scenario-btn { + display: flex; gap: 12px; align-items: flex-start; text-align: left; + padding: 10px 12px; border-radius: var(--r-md); + background: var(--bg-elevated); border: 1px solid var(--border-bright); +} +.scenario-btn:not(:disabled):hover { border-color: var(--accent); } +.scenario-btn svg { color: var(--accent); margin-top: 3px; flex-shrink: 0; } +.scenario-btn span { display: flex; flex-direction: column; } +.scenario-btn small { color: var(--text-secondary); font-size: 12px; } +.scenario-running { display: flex; align-items: center; gap: 8px; color: var(--accent); font-size: 13px; font-weight: 600; } +.pulse-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); animation: alarm-flash 1s infinite; } + +/* ===================================================================== */ +/* Wake screen (shown while the hosted server starts) */ +/* ===================================================================== */ + +.wake-screen { min-height: 100%; display: flex; align-items: center; justify-content: center; padding: 24px 16px; } +.wake-card { width: 100%; max-width: 560px; display: flex; flex-direction: column; gap: 14px; } +.wake-brand { display: flex; align-items: center; gap: 8px; color: var(--accent); font-weight: 700; font-size: 15px; } +.wake-card h1 { font-size: 24px; font-weight: 650; line-height: 1.25; } +.wake-text { color: var(--text-secondary); } +.wake-progress { height: 6px; background: var(--bg-elevated); border-radius: 3px; overflow: hidden; } +.wake-progress-bar { height: 100%; background: var(--accent); border-radius: 3px; transition: width 0.5s ease-out; } +.wake-elapsed { font-size: 12px; color: var(--text-muted); text-align: right; margin-top: -8px; } +.wake-steps { list-style: none; display: flex; flex-direction: column; gap: 8px; } +.wake-step { display: flex; align-items: center; gap: 10px; color: var(--text-muted); } +.wake-step.active { color: var(--text-primary); } +.wake-step.done { color: var(--text-secondary); } +.wake-step-icon { + width: 20px; height: 20px; border-radius: 50%; flex-shrink: 0; + display: inline-flex; align-items: center; justify-content: center; + border: 1px solid var(--border-bright); +} +.wake-step.done .wake-step-icon { background: var(--ok); border-color: var(--ok); color: #0b0e12; } +.wake-step.active .wake-step-icon { border-color: var(--accent); color: var(--accent); } +.wake-slow { padding: 12px 14px; border-radius: var(--r-md); background: var(--p3-dim); border: 1px solid rgba(234, 179, 8, 0.35); display: flex; flex-direction: column; gap: 10px; align-items: flex-start; } +.wake-preview { margin-top: 6px; padding: 14px 16px; border-radius: var(--r-lg); background: var(--bg-card); border: 1px solid var(--border); } +.wake-preview-title { font-size: 11px; font-weight: 650; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-muted); margin-bottom: 8px; } +.wake-preview ul { padding-left: 18px; color: var(--text-secondary); display: flex; flex-direction: column; gap: 4px; font-size: 13px; } + +/* ===================================================================== */ +/* Responsive */ +/* ===================================================================== */ + +@media (max-width: 1180px) { + .alarm-list-head { display: none; } + .alarm-main { + grid-template-columns: 28px 90px minmax(0, 1fr) auto; + grid-template-areas: + "exp desc desc prio" + "exp time val state" + "exp act act act"; + row-gap: 6px; + } + .alarm-main .alarm-expand { align-self: start; } + .alarm-main .alarm-prio, .alarm-main .alarm-state { align-items: flex-end; } + .alarm-main .alarm-val { flex-direction: row; gap: 8px; align-items: baseline; } + .alarm-main .alarm-actions { justify-content: flex-start; } + .alarm-main .alarm-actions:empty { display: none; } +} + +@media (max-width: 1100px) { + :root { --sidebar-w: 68px; } + .sidebar-brand { justify-content: center; padding: 0; } + .brand-text, .nav-label { display: none; } + .nav-item, .sidebar-about { justify-content: center; padding: 10px; } + .nav-badge { position: absolute; top: 2px; right: 2px; margin: 0; min-width: 18px; font-size: 10px; padding: 0 5px; } + .dash-row { grid-template-columns: minmax(0, 1fr); } + .ol-layout { grid-template-columns: minmax(0, 1fr); } + .ol-detail { position: static; } +} + +@media (max-width: 720px) { + .sidebar { display: none; } + .mobile-only { display: inline-block; } + .topbar { padding: 0 12px; height: 52px; } + .topbar-title { font-size: 14px; } + .sim-pill span, .conn-pill span:last-child { display: none; } + .sim-pill { padding: 5px 7px; } + .page-content { padding: 14px 12px calc(var(--bottom-nav-h) + 18px); } + .page { gap: 14px; } + .alarm-banner, .event-banner { padding-left: 12px; padding-right: 12px; } + .alarm-banner { flex-wrap: wrap; } + .alarm-banner-msg { flex-basis: calc(100% - 140px); } + .alarm-banner-actions { width: 100%; } + .alarm-banner-actions .btn { flex: 1; } + + .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; grid-auto-flow: dense; } + .kpi-grid > .stat-card:last-child:nth-child(odd) { grid-column: span 2; } + .kpi-alarms > .stat-card:nth-child(2) { grid-column: span 2; } + .ol-card { padding: 8px; } + .stat-card { padding: 12px; } + .stat-card-value { font-size: 21px; } + .equip-grid { grid-template-columns: repeat(auto-fill, minmax(155px, 1fr)); gap: 10px; } + .equip-metrics .metric-value { font-size: 13px; } + + .meters-layout { flex-direction: column; align-items: stretch; } + .meter-list { width: 100%; position: static; display: flex; flex-direction: column; gap: 6px; } + .meter-buttons { display: none; } + .meter-select-label { display: block; font-size: 11px; font-weight: 650; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); } + .meter-select { display: block; width: 100%; padding: 9px 10px; font-size: 14px; } + .gauges { grid-template-columns: repeat(2, 1fr); row-gap: 14px; } + + .settings-grid { grid-template-columns: minmax(0, 1fr); } + .settings-grid .span-2 { grid-column: auto; } + + .alarm-main { + grid-template-columns: 24px minmax(0, 1fr) auto; + grid-template-areas: + "exp desc prio" + "exp val state" + "act act act"; + column-gap: 8px; + } + .alarm-main .alarm-time { display: none; } + .alarm-main .alarm-val { flex-direction: column; gap: 0; } + .alarm-details, .shelve-form { margin-left: 0; } + .state-list-row { grid-template-columns: 1fr; gap: 4px; } + + .bottom-nav { + display: grid; grid-template-columns: repeat(6, 1fr); + position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; + height: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom)); + padding-bottom: env(safe-area-inset-bottom); + background: var(--bg-surface); + border-top: 1px solid var(--border); + } + .bottom-item { + display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; + font-size: 10.5px; font-weight: 550; color: var(--text-muted); + } + .bottom-item.active { color: var(--accent); } + .bottom-icon { position: relative; display: inline-flex; } + .bottom-icon .nav-badge { position: absolute; top: -6px; right: -12px; margin: 0; min-width: 17px; font-size: 10px; padding: 0 4px; } + + .modal-backdrop { padding: 0; align-items: stretch; } + .modal { max-width: none; border-radius: 0; border: none; min-height: 100%; } } -.value-updated { animation: value-flash 0.8s ease-out; } diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 4bc8f2b..c04060e 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,91 +1,120 @@ -import React, { useState, useEffect, useCallback } from 'react' -import { BrowserRouter, Routes, Route, NavLink, useLocation } from 'react-router-dom' -import { LayoutDashboard, GitBranch, Gauge, Bell, TrendingUp, Settings, Zap, AlertTriangle, CheckCircle, XCircle } from 'lucide-react' +import React, { Suspense, lazy, useCallback, useState } from 'react' +import { BrowserRouter, Routes, Route, NavLink, Navigate } from 'react-router-dom' +import { LayoutDashboard, GitBranch, Gauge, Bell, TrendingUp, Settings, Zap, Info, FlaskConical } from 'lucide-react' +import { LiveFeedProvider, useFeed } from './services/LiveFeed' +import WakeScreen from './components/WakeScreen' +import AboutPanel from './components/AboutPanel' +import AlarmBanner from './components/AlarmBanner' import Dashboard from './pages/Dashboard' import OneLineDiagram from './pages/OneLineDiagram' -import Meters from './pages/Meters' import Alarms from './pages/Alarms' -import Trending from './pages/Trending' import SettingsPage from './pages/SettingsPage' -import { useWebSocket } from './services/websocket' import './App.css' -function AppShell() { - const { readings, connected } = useWebSocket() - const [alarmCount, setAlarmCount] = useState(0) - const location = useLocation() +// Chart heavy pages load on demand to keep the first load small +const Meters = lazy(() => import('./pages/Meters')) +const Trending = lazy(() => import('./pages/Trending')) - useEffect(() => { - fetch('/api/alarms') - .then(r => r.json()) - .then(d => setAlarmCount(d.length)) - .catch(() => {}) - }, [readings]) +const NAV = [ + { to: '/', icon: LayoutDashboard, label: 'Overview' }, + { to: '/one-line', icon: GitBranch, label: 'One-Line' }, + { to: '/meters', icon: Gauge, label: 'Meters' }, + { to: '/alarms', icon: Bell, label: 'Alarms', alarms: true }, + { to: '/trending', icon: TrendingUp, label: 'Trends' }, + { to: '/settings', icon: Settings, label: 'System' }, +] - const navItems = [ - { to: '/', icon: LayoutDashboard, label: 'Dashboard' }, - { to: '/one-line', icon: GitBranch, label: 'One-Line' }, - { to: '/meters', icon: Gauge, label: 'Meters' }, - { to: '/alarms', icon: Bell, label: 'Alarms', badge: alarmCount }, - { to: '/trending', icon: TrendingUp, label: 'Trending' }, - { to: '/settings', icon: Settings, label: 'Settings' }, - ] +function ConnectionPill({ phase }) { + const live = phase === 'live' + return ( +
+ + {live ? 'Live' : 'Reconnecting'} +
+ ) +} + +function Shell() { + const feed = useFeed() + const [aboutOpen, setAboutOpen] = useState(false) + const openAbout = useCallback(() => setAboutOpen(true), []) + const closeAbout = useCallback(() => setAboutOpen(false), []) + + if (!feed.hasData) { + return + } + + const unacked = feed.summary?.unacknowledged ?? 0 + const topPriority = feed.summary?.highest_unacked?.priority return (
- {/* Sidebar */} - {/* Main area */}
- {/* Top bar */}
-

Power Dashboard

+
+ +

Data Center Power Monitoring

+
-
- {connected ? : } - {connected ? 'Live' : 'Disconnected'} -
- {alarmCount > 0 && ( -
- - {alarmCount} active alarm{alarmCount !== 1 ? 's' : ''} -
+ {feed.system?.simulated && ( + )} + +
- {/* Page content */} -
- - } /> - } /> - } /> - } /> - } /> - } /> - + + +
+ Loading...
}> + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
+ + + + ) } @@ -93,7 +122,9 @@ function AppShell() { export default function App() { return ( - + + + ) } diff --git a/frontend/src/components/AboutPanel.jsx b/frontend/src/components/AboutPanel.jsx new file mode 100644 index 0000000..61a0102 --- /dev/null +++ b/frontend/src/components/AboutPanel.jsx @@ -0,0 +1,136 @@ +import React, { useEffect, useRef, useState } from 'react' +import { X, FlaskConical, Play, Github } from 'lucide-react' +import { useFeed } from '../services/LiveFeed' +import { api } from '../services/api' +import StateLegend from './StateLegend' + +const REPO_URL = 'https://github.com/AddisonTech/power-dashboard' + +export function ScenarioButtons({ onDone }) { + const { demo, system } = useFeed() + const [busy, setBusy] = useState(null) + const [error, setError] = useState(null) + const running = system?.scenario + + if (!demo?.events_enabled) { + return

Demo events are disabled on this server.

+ } + + const fire = async (name) => { + setBusy(name) + setError(null) + try { + await api.triggerEvent(name) + onDone?.() + } catch (e) { + setError(e.message) + } finally { + setBusy(null) + } + } + + return ( +
+ {running && ( +
+ {running.label} in progress +
+ )} + {demo.scenarios.map(s => ( + + ))} + {error &&

{error}

} +
+ ) +} + +export default function AboutPanel({ open, onClose }) { + const closeRef = useRef(null) + + useEffect(() => { + if (!open) return undefined + closeRef.current?.focus() + const onKey = e => { if (e.key === 'Escape') onClose() } + window.addEventListener('keydown', onKey) + return () => window.removeEventListener('keydown', onKey) + }, [open, onClose]) + + if (!open) return null + + return ( +
+
e.stopPropagation()}> +
+

About this demo

+ +
+ +
+
+ +
+ All data on this site is simulated. No real facility, customer, or + equipment is connected. A Python simulator models a small data center and updates every + 2 seconds. +
+
+ +
+

What is modeled

+

+ A 2N data center of about 450 kW: a 480 V utility service and a 750 kW standby generator + feed an automatic transfer switch, then the main switchboard. Two 400 kVA UPS systems + (A side and B side) each feed two 150 kVA PDUs at 208 V, and the cooling plant runs from + its own panel. Values roll up from the IT load through transformer and UPS losses, so + the numbers add up the way a real site does. +

+
+ +
+

Try it

+

+ Events also happen on their own every few minutes. The event rate is faster than a real + site so there is always something to look at. +

+ +
+ +
+

ISA 18.2 alarm handling

+

+ Every alarm in the master alarm database is rationalized with a priority, a consequence, + and an operator response. Alarms follow the ISA 18.2 state model, use deadbands and + delays to prevent chatter, can be shelved for a limited time with a logged reason, and + some are suppressed by design (for example, generator alarms while the generator is off). + Every transition is written to the alarm journal. +

+ +
+ +
+

Real hardware

+

+ The same backend polls Modbus TCP meters when started with DATA_SOURCE=modbus and + a register map. The alarm engine, history, and this interface work the same either way. +

+
+ +
+

Stack

+

Python, FastAPI, WebSocket, SQLite, React, Vite. Hosted on Render.

+ + Source on GitHub + +
+
+
+
+ ) +} diff --git a/frontend/src/components/AlarmBanner.jsx b/frontend/src/components/AlarmBanner.jsx new file mode 100644 index 0000000..6416fff --- /dev/null +++ b/frontend/src/components/AlarmBanner.jsx @@ -0,0 +1,50 @@ +import React, { useEffect, useState } from 'react' +import { Link } from 'react-router-dom' +import { Activity } from 'lucide-react' +import { useFeed } from '../services/LiveFeed' +import { api } from '../services/api' +import { getOperator } from '../lib/operator' +import { ago } from '../lib/format' +import { PriorityBadge, StateBadge } from './Badges' + +// Highest priority unacknowledged alarm, always visible under the top bar +export default function AlarmBanner() { + const { summary, system } = useFeed() + const [, tick] = useState(0) + useEffect(() => { + const t = setInterval(() => tick(n => n + 1), 1000) + return () => clearInterval(t) + }, []) + + const top = summary?.highest_unacked + const scenario = system?.scenario + + return ( + <> + {scenario && ( +
+ + Demo event in progress: {scenario.label} +
+ )} + {top && ( +
+ + + + {top.message} + {top.meter_name}, {ago(top.activated_at)} + + + + + {summary.unacknowledged > 1 ? `All ${summary.unacknowledged}` : 'Alarms'} + + +
+ )} + + ) +} diff --git a/frontend/src/components/Badges.jsx b/frontend/src/components/Badges.jsx new file mode 100644 index 0000000..c3523b1 --- /dev/null +++ b/frontend/src/components/Badges.jsx @@ -0,0 +1,22 @@ +import React from 'react' +import { PRIORITY, STATES } from '../lib/alarms' + +export function PriorityBadge({ priority, compact = false }) { + const p = PRIORITY[priority] || PRIORITY[4] + return ( + + P{priority}{!compact && {p.label}} + + ) +} + +export function StateBadge({ state, priority }) { + const s = STATES[state] || STATES.NORMAL + const p = PRIORITY[priority] || PRIORITY[4] + return ( + + + ) +} diff --git a/frontend/src/components/Sparkline.jsx b/frontend/src/components/Sparkline.jsx new file mode 100644 index 0000000..b2f139c --- /dev/null +++ b/frontend/src/components/Sparkline.jsx @@ -0,0 +1,86 @@ +import React, { useEffect, useRef, useState } from 'react' + +// Lightweight SVG line, used where pulling in a chart library is not worth it +export function Sparkline({ data, height = 36, className = '' }) { + if (!data || data.length < 2) return
+ const min = Math.min(...data) + const max = Math.max(...data) + const span = max - min || 1 + const w = 100 + const pts = data.map((v, i) => [(i / (data.length - 1)) * w, height - 2 - ((v - min) / span) * (height - 4)]) + const line = pts.map(([x, y], i) => `${i ? 'L' : 'M'}${x.toFixed(2)},${y.toFixed(2)}`).join(' ') + return ( + + ) +} + +function useWidth() { + const ref = useRef(null) + const [width, setWidth] = useState(0) + useEffect(() => { + const el = ref.current + if (!el) return undefined + setWidth(el.clientWidth) + if (typeof ResizeObserver === 'undefined') return undefined + const ro = new ResizeObserver(([entry]) => setWidth(Math.round(entry.contentRect.width))) + ro.observe(el) + return () => ro.disconnect() + }, []) + return [ref, width] +} + +// Small time series chart with axis labels for the dashboard +export function AreaChart(props) { + const [ref, width] = useWidth() + return ( +
+ {width > 0 && } +
+ ) +} + +function AreaChartSvg({ points, width, height = 180, unit = '', format = v => v.toFixed(0) }) { + if (!points || points.length < 2) { + return
Collecting data...
+ } + const ys = points.map(p => p.v) + let min = Math.min(...ys) + let max = Math.max(...ys) + const pad = (max - min) * 0.15 || max * 0.05 || 1 + min = Math.max(0, min - pad) + max = max + pad + const t0 = points[0].t + const t1 = points[points.length - 1].t + const W = width + const H = height + const left = 44 + const bottom = 20 + const x = t => left + ((t - t0) / (t1 - t0 || 1)) * (W - left - 4) + const y = v => 6 + (1 - (v - min) / (max - min)) * (H - bottom - 10) + const line = points.map((p, i) => `${i ? 'L' : 'M'}${x(p.t).toFixed(1)},${y(p.v).toFixed(1)}`).join(' ') + const ticks = [min, (min + max) / 2, max] + const timeTicks = [t0, (t0 + t1) / 2, t1] + const fmtTime = t => new Date(t * 1000).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }) + + return ( + + {ticks.map((v, i) => ( + + + {format(v)}{unit} + + ))} + {timeTicks.map((t, i) => ( + {fmtTime(t)} + ))} + + + + ) +} diff --git a/frontend/src/components/StateLegend.jsx b/frontend/src/components/StateLegend.jsx new file mode 100644 index 0000000..538817b --- /dev/null +++ b/frontend/src/components/StateLegend.jsx @@ -0,0 +1,39 @@ +import React from 'react' +import { STATES } from '../lib/alarms' +import { StateBadge } from './Badges' + +// The ISA 18.2 alarm state model, in a form a visitor can follow +export default function StateLegend({ compact = false }) { + return ( +
+
+
+ Normal + condition→ + Unacknowledged + acknowledge→ + Acknowledged + clears→ + Normal +
+
+ Unacknowledged + clears→ + Returned to normal, unack + acknowledge→ + Normal +
+
+ {!compact && ( +
+ {['UNACK', 'ACKED', 'RTN_UNACK', 'SHELVED', 'SUPPRESSED'].map(s => ( +
+
+
{STATES[s].help}
+
+ ))} +
+ )} +
+ ) +} diff --git a/frontend/src/components/WakeScreen.jsx b/frontend/src/components/WakeScreen.jsx new file mode 100644 index 0000000..ac7c6c1 --- /dev/null +++ b/frontend/src/components/WakeScreen.jsx @@ -0,0 +1,84 @@ +import React, { useEffect, useState } from 'react' +import { Zap, Check, Loader2, RotateCcw } from 'lucide-react' + +const EXPECTED_S = 50 +const SLOW_S = 90 + +function Step({ done, active, children }) { + return ( +
  • + + {done ? : active ? : null} + + {children} +
  • + ) +} + +export default function WakeScreen({ serverAwake, startedAt, retry }) { + const [now, setNow] = useState(Date.now()) + useEffect(() => { + const t = setInterval(() => setNow(Date.now()), 500) + return () => clearInterval(t) + }, []) + + const elapsed = Math.max(0, Math.floor((now - startedAt) / 1000)) + const quick = elapsed < 4 && !serverAwake + const slow = elapsed >= SLOW_S && !serverAwake + const pct = serverAwake ? 92 : Math.min(88, (elapsed / EXPECTED_S) * 88) + + const title = quick + ? 'Connecting to the live system' + : serverAwake + ? 'Server is awake, starting the live feed' + : 'Waking up the demo server' + + return ( +
    +
    +
    + Power Dashboard +
    +

    {title}

    + + {!quick && ( +

    + This portfolio demo is hosted on a free tier that sleeps when nobody is using it. + The first visit after a quiet period takes about 30 to 60 seconds while the server + starts. After that, everything updates live every 2 seconds. +

    + )} + + +
    + ) +} diff --git a/frontend/src/index.css b/frontend/src/index.css index 616a929..23ce1c2 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,39 +1,53 @@ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } +/* + * HMI color philosophy (ISA-101 style): normal equipment is shown in neutral + * grays so that color is reserved for abnormal conditions and alarm priority. + */ :root { - --bg-base: #0a0a0a; - --bg-surface: #111111; - --bg-elevated: #1a1a1a; - --bg-card: #1e1e1e; - --bg-hover: #252525; - --border: #2a2a2a; - --border-bright: #383838; - - --text-primary: #e8e8e8; - --text-secondary: #a0a0a0; - --text-muted: #606060; - - --accent: #00b4d8; - --accent-dim: rgba(0, 180, 216, 0.15); - --accent-border: rgba(0, 180, 216, 0.3); - - --status-ok: #22c55e; - --status-ok-dim: rgba(34, 197, 94, 0.12); - --status-warn: #f59e0b; - --status-warn-dim: rgba(245, 158, 11, 0.12); - --status-crit: #ef4444; - --status-crit-dim: rgba(239, 68, 68, 0.12); - --status-off: #4b5563; - - --font-mono: 'JetBrains Mono', 'Courier New', monospace; - --font-sans: 'Inter', system-ui, sans-serif; + color-scheme: dark; + + --bg-base: #0b0e12; + --bg-surface: #10141a; + --bg-card: #151a21; + --bg-elevated: #1b212a; + --bg-hover: #1f2630; + --border: #262e3a; + --border-bright:#35404f; + --grid: #1f2630; + + --text-primary: #e7eaf0; + --text-secondary: #a3adbd; + --text-muted: #707a8b; + + --accent: #60a5fa; + --accent-dim: rgba(96, 165, 250, 0.14); + --accent-border: rgba(96, 165, 250, 0.38); + + /* Alarm priorities */ + --p1: #ef4444; + --p2: #f97316; + --p3: #eab308; + --p4: #a78bfa; + --p1-dim: rgba(239, 68, 68, 0.14); + --p2-dim: rgba(249, 115, 22, 0.14); + --p3-dim: rgba(234, 179, 8, 0.14); + --p4-dim: rgba(167, 139, 250, 0.14); + + --ok: #22c55e; + --energized: #9aa4b4; + --flow: #60a5fa; + --dead: #2c3440; + + --font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, Consolas, monospace; + --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; --r-sm: 4px; --r-md: 8px; --r-lg: 12px; - --shadow: 0 2px 8px rgba(0,0,0,0.4); - --shadow-lg: 0 4px 24px rgba(0,0,0,0.6); + --sidebar-w: 228px; + --bottom-nav-h: 62px; } html, body, #root { @@ -43,50 +57,35 @@ html, body, #root { font-family: var(--font-sans); font-size: 14px; line-height: 1.5; + -webkit-font-smoothing: antialiased; } -/* Scrollbar */ -::-webkit-scrollbar { width: 6px; height: 6px; } -::-webkit-scrollbar-track { background: var(--bg-base); } -::-webkit-scrollbar-thumb { background: var(--border-bright); border-radius: 3px; } -::-webkit-scrollbar-thumb:hover { background: #4a4a4a; } +::-webkit-scrollbar { width: 8px; height: 8px; } +::-webkit-scrollbar-track { background: transparent; } +::-webkit-scrollbar-thumb { background: var(--border-bright); border-radius: 4px; } + +button { cursor: pointer; font-family: inherit; font-size: inherit; color: inherit; } +button:disabled { cursor: not-allowed; opacity: 0.5; } +a { text-decoration: none; color: inherit; } +table { border-collapse: collapse; width: 100%; } +th { text-align: left; } +code { font-family: var(--font-mono); font-size: 0.92em; background: var(--bg-elevated); padding: 1px 5px; border-radius: 4px; } + +:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } -/* Utility */ .mono { font-family: var(--font-mono); } -.text-ok { color: var(--status-ok); } -.text-warn { color: var(--status-warn); } -.text-crit { color: var(--status-crit); } -.text-muted { color: var(--text-muted); } -.text-secondary { color: var(--text-secondary); } - -.badge { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 2px 8px; - border-radius: var(--r-sm); - font-size: 11px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.05em; -} -.badge-ok { background: var(--status-ok-dim); color: var(--status-ok); } -.badge-warn { background: var(--status-warn-dim); color: var(--status-warn); } -.badge-crit { background: var(--status-crit-dim); color: var(--status-crit); } - -.card { - background: var(--bg-card); - border: 1px solid var(--border); - border-radius: var(--r-lg); - padding: 20px; -} +.muted { color: var(--text-muted); } +.small { font-size: 12px; } +.nowrap { white-space: nowrap; } -button { - cursor: pointer; - font-family: var(--font-sans); -} +@keyframes spin { to { transform: rotate(360deg); } } +.spin { animation: spin 1s linear infinite; } -a { text-decoration: none; color: inherit; } +@keyframes alarm-flash { + 0%, 55% { opacity: 1; } + 56%, 100% { opacity: 0.25; } +} -table { border-collapse: collapse; width: 100%; } -th { text-align: left; } +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { animation: none !important; transition: none !important; } +} diff --git a/frontend/src/lib/alarms.js b/frontend/src/lib/alarms.js new file mode 100644 index 0000000..e79394f --- /dev/null +++ b/frontend/src/lib/alarms.js @@ -0,0 +1,29 @@ +export const PRIORITY = { + 1: { label: 'Critical', cls: 'p1' }, + 2: { label: 'High', cls: 'p2' }, + 3: { label: 'Medium', cls: 'p3' }, + 4: { label: 'Low', cls: 'p4' }, +} + +// ISA 18.2 alarm states +export const STATES = { + NORMAL: { label: 'Normal', short: 'Normal', help: 'Process normal. Nothing to acknowledge.' }, + UNACK: { label: 'Unacknowledged', short: 'Unack', help: 'Process is abnormal and no operator has acknowledged it yet. Flashes until acknowledged.' }, + ACKED: { label: 'Acknowledged', short: 'Acked', help: 'Process is still abnormal. The operator has acknowledged it and is responding.' }, + RTN_UNACK: { label: 'Returned to normal, unacknowledged', short: 'RTN unack', help: 'The process recovered before anyone acknowledged. Still needs an acknowledgement so the event is not missed.' }, + SHELVED: { label: 'Shelved', short: 'Shelved', help: 'Temporarily removed from the alarm list by the operator, for a limited time with a logged reason.' }, + SUPPRESSED: { label: 'Suppressed by design', short: 'Suppressed', help: 'Automatically hidden by a designed rule based on plant state, such as generator alarms while the generator is off.' }, +} + +export const EVENT_LABELS = { + ALARM: 'Alarm', + ACK: 'Acknowledged', + RTN: 'Return to normal', + SHELVE: 'Shelved', + UNSHELVE: 'Unshelved', + SUPPRESS: 'Suppressed', + UNSUPPRESS: 'Unsuppressed', +} + +export const ANNUNCIATED = ['UNACK', 'ACKED', 'RTN_UNACK'] +export const NEEDS_ACK = ['UNACK', 'RTN_UNACK'] diff --git a/frontend/src/lib/format.js b/frontend/src/lib/format.js new file mode 100644 index 0000000..14acf8b --- /dev/null +++ b/frontend/src/lib/format.js @@ -0,0 +1,48 @@ +export function num(v, digits = 1) { + return v == null || Number.isNaN(v) ? '--' : Number(v).toFixed(digits) +} + +export function kw(v) { + if (v == null) return '--' + return v >= 1000 ? `${(v / 1000).toFixed(2)} MW` : `${v.toFixed(0)} kW` +} + +export function timeOf(iso) { + if (!iso) return '--' + return new Date(iso).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit', hourCycle: 'h23' }) +} + +export function dateTimeOf(iso) { + if (!iso) return '--' + const d = new Date(iso) + return `${d.toLocaleDateString([], { month: 'short', day: 'numeric' })} ${timeOf(iso)}` +} + +export function ago(iso, now = Date.now()) { + if (!iso) return '' + const s = Math.max(0, Math.round((now - new Date(iso).getTime()) / 1000)) + if (s < 60) return `${s}s ago` + if (s < 3600) return `${Math.floor(s / 60)}m ago` + return `${Math.floor(s / 3600)}h ${Math.floor((s % 3600) / 60)}m ago` +} + +export function until(iso, now = Date.now()) { + if (!iso) return '' + const s = Math.max(0, Math.round((new Date(iso).getTime() - now) / 1000)) + const m = Math.floor(s / 60) + return m > 0 ? `${m}m ${s % 60}s` : `${s}s` +} + +export function alarmValue(a, v = a.value) { + if (v == null) return '--' + if (a.kind === 'DISCRETE') return v ? 'Active' : 'Normal' + const digits = a.unit === '' ? 3 : a.unit === 'Hz' ? 2 : 1 + return `${Number(v).toFixed(digits)}${a.unit ? ` ${a.unit}` : ''}` +} + +export function setpointText(a) { + if (a.kind === 'DISCRETE') return 'discrete' + const op = a.kind.startsWith('HI') ? '>' : '<' + const digits = a.unit === '' ? 2 : 1 + return `${op} ${Number(a.setpoint).toFixed(digits)}${a.unit ? ` ${a.unit}` : ''}` +} diff --git a/frontend/src/lib/operator.js b/frontend/src/lib/operator.js new file mode 100644 index 0000000..c3b7a0e --- /dev/null +++ b/frontend/src/lib/operator.js @@ -0,0 +1,24 @@ +// The name recorded in the alarm journal for acknowledge and shelve actions. +const KEY = 'pd.operator' + +export function getOperator() { + try { + return localStorage.getItem(KEY) || 'demo visitor' + } catch { + return 'demo visitor' + } +} + +export function setOperator(name) { + try { + localStorage.setItem(KEY, name) + } catch { /* storage unavailable */ } +} + +export function readFlag(key) { + try { return localStorage.getItem(key) === '1' } catch { return false } +} + +export function writeFlag(key, on) { + try { on ? localStorage.setItem(key, '1') : localStorage.removeItem(key) } catch { /* ignore */ } +} diff --git a/frontend/src/pages/Alarms.jsx b/frontend/src/pages/Alarms.jsx index 4b0bfb1..7d0a8f1 100644 --- a/frontend/src/pages/Alarms.jsx +++ b/frontend/src/pages/Alarms.jsx @@ -1,120 +1,326 @@ -import React, { useState, useEffect } from 'react' -import { Bell, CheckSquare, Clock, Filter } from 'lucide-react' +import React, { useCallback, useEffect, useState } from 'react' +import { ChevronDown, ChevronRight, Clock, HelpCircle } from 'lucide-react' +import { useFeed } from '../services/LiveFeed' import { api } from '../services/api' +import { PriorityBadge, StateBadge } from '../components/Badges' +import StateLegend from '../components/StateLegend' +import { ANNUNCIATED, NEEDS_ACK, EVENT_LABELS, PRIORITY, STATES } from '../lib/alarms' +import { alarmValue, setpointText, dateTimeOf, ago, until, timeOf } from '../lib/format' +import { getOperator } from '../lib/operator' -const PRIORITY_LABELS = { 1: 'Critical', 2: 'High', 3: 'Medium', 4: 'Low' } -const PRIORITY_CLASSES = { 1: 'crit', 2: 'warn', 3: 'accent', 4: 'off' } +const SHELVE_OPTIONS = [5, 15, 60] +const TABS = [ + { key: 'active', label: 'Alarm list' }, + { key: 'shelved', label: 'Shelved' }, + { key: 'suppressed', label: 'Suppressed' }, + { key: 'history', label: 'Journal' }, + { key: 'database', label: 'Alarm database' }, +] -function AlarmRow({ alarm, onAck }) { - const pClass = PRIORITY_CLASSES[alarm.priority] || 'off' +function useNow(ms = 1000) { + const [now, setNow] = useState(Date.now()) + useEffect(() => { + const t = setInterval(() => setNow(Date.now()), ms) + return () => clearInterval(t) + }, [ms]) + return now +} + +function ShelveForm({ alarm, onDone, onCancel }) { + const [minutes, setMinutes] = useState(15) + const [reason, setReason] = useState('') + const [error, setError] = useState(null) + const submit = async (e) => { + e.preventDefault() + try { + await api.shelve(alarm.tag, minutes, reason || 'Shelved from the demo', getOperator()) + onDone() + } catch (err) { + setError(err.message) + } + } return ( - - {new Date(alarm.raised_at).toLocaleString()} - {alarm.meter_name} - {alarm.condition} - {alarm.value?.toFixed(3)} - {alarm.threshold?.toFixed(3)} - - - P{alarm.priority} {PRIORITY_LABELS[alarm.priority]} - - - - {alarm.state === 'active' && !alarm.acknowledged ? ( - - ) : alarm.acknowledged ? ( - ACK - ) : ( - Cleared - )} - - + ))} +
    + setReason(e.target.value)} aria-label="Shelve reason" /> +
    + + +
    + {error &&

    {error}

    } +

    ISA 18.2 shelving is time limited. The alarm returns automatically when the timer runs out.

    + + ) +} + +function AlarmRow({ alarm, now }) { + const [open, setOpen] = useState(false) + const [shelving, setShelving] = useState(false) + const [error, setError] = useState(null) + const needsAck = NEEDS_ACK.includes(alarm.state) + + const act = useCallback(async (fn) => { + setError(null) + try { await fn() } catch (e) { setError(e.message) } + }, []) + + return ( +
    +
    + +
    + {timeOf(alarm.activated_at || alarm.shelved_at)} + {ago(alarm.activated_at || alarm.shelved_at, now)} +
    +
    +
    {alarm.message}
    +
    {alarm.tag}, {alarm.meter_name}
    + {alarm.state === 'SUPPRESSED' &&
    {alarm.suppress_reason}
    } +
    +
    + {alarmValue(alarm)} + {alarm.kind === 'DISCRETE' ? 'discrete signal' : `limit ${setpointText(alarm)}`} +
    +
    +
    +
    + {needsAck && ( + + )} + {ANNUNCIATED.includes(alarm.state) && ( + + )} + {alarm.state === 'SHELVED' && ( + <> + {until(alarm.shelved_until, now)} left + + + )} +
    +
    + {shelving && ( + setShelving(false)} onCancel={() => setShelving(false)} /> + )} + {error &&

    {error}

    } + {open && ( +
    +
    Consequence
    {alarm.consequence}
    +
    Operator response
    {alarm.response}
    +
    Value at alarm
    {alarmValue(alarm, alarm.alarm_value)}
    +
    Current value
    {alarmValue(alarm)}
    + {alarm.ack_at &&
    Acknowledged
    {dateTimeOf(alarm.ack_at)} by {alarm.ack_by}
    } + {alarm.rtn_at &&
    Returned to normal
    {dateTimeOf(alarm.rtn_at)}
    } + {alarm.shelve_reason &&
    Shelved
    {alarm.shelve_reason}, by {alarm.shelved_by}, until {timeOf(alarm.shelved_until)}
    } + {alarm.suppress_reason &&
    Suppression rule
    {alarm.suppress_reason}
    } +
    + )} +
    + ) +} + +function AlarmList({ alarms, empty, now }) { + if (alarms.length === 0) return

    {empty}

    + return ( +
    +
    + TimeAlarmValuePriorityStateAction +
    + {alarms.map(a => )} +
    + ) +} + +function Journal({ refreshKey }) { + const [rows, setRows] = useState(null) + const [filter, setFilter] = useState('ALL') + useEffect(() => { + let cancelled = false + api.getAlarmHistory(300).then(r => { if (!cancelled) setRows(r) }).catch(() => {}) + return () => { cancelled = true } + }, [refreshKey]) + + if (!rows) return

    Loading journal...

    + const shown = filter === 'ALL' ? rows : rows.filter(r => r.event === filter) + return ( + <> +
    + {['ALL', 'ALARM', 'ACK', 'RTN', 'SHELVE', 'SUPPRESS'].map(f => ( + + ))} +
    +
    + + + + + + {shown.map(e => ( + + + + + + + + + + ))} + {shown.length === 0 && } + +
    TimeEventAlarmPriorityValueState afterBy
    {dateTimeOf(e.timestamp)}{EVENT_LABELS[e.event] || e.event} +
    {e.message}
    +
    {e.tag}{e.note ? `, ${e.note}` : ''}
    +
    {e.value == null ? '--' : alarmValue({ unit: e.unit, kind: e.unit === '' && e.setpoint === 1 ? 'DISCRETE' : 'HI' }, e.value)}{STATES[e.state]?.short || e.state}{e.operator}
    No journal entries
    +
    + + ) +} + +function AlarmDatabase() { + const [defs, setDefs] = useState(null) + useEffect(() => { api.getAlarmDefs().then(setDefs).catch(() => {}) }, []) + if (!defs) return

    Loading alarm database...

    + return ( + <> +

    + The master alarm database. Each alarm was rationalized: it has one cause, a priority based on + consequence and time to respond, and a documented operator response. Deadbands and delays + keep noisy signals from chattering. +

    +
    + + + + + + {defs.map(d => ( + + + + + + + + + + ))} + +
    TagAlarmLimitDeadbandDelay on/offPriorityOperator response
    {d.tag} +
    {d.message}
    + {d.suppression &&
    Suppressed when: {d.suppression}
    } +
    {setpointText(d)}{d.kind === 'DISCRETE' ? '--' : `${d.deadband} ${d.unit}`}{d.on_delay} / {d.off_delay} scans{d.response}
    +
    + ) } export default function Alarms() { + const { alarms, summary } = useFeed() const [tab, setTab] = useState('active') - const [active, setActive] = useState([]) - const [history, setHistory] = useState([]) - const [loading, setLoading] = useState(false) - - const load = () => { - setLoading(true) - Promise.all([api.getAlarms(), api.getAlarmHistory()]) - .then(([a, h]) => { setActive(a); setHistory(h) }) - .finally(() => setLoading(false)) - } + const [showHelp, setShowHelp] = useState(false) + const now = useNow() - useEffect(() => { - load() - const t = setInterval(load, 10000) - return () => clearInterval(t) - }, []) + const active = alarms.filter(a => ANNUNCIATED.includes(a.state)) + const shelved = alarms.filter(a => a.state === 'SHELVED') + const suppressed = alarms.filter(a => a.state === 'SUPPRESSED') + const counts = { active: active.length, shelved: shelved.length, suppressed: suppressed.length } + const unackedActive = active.filter(a => NEEDS_ACK.includes(a.state)) - const ack = (id) => { - api.acknowledgeAlarm(id).then(load) + const ackAll = async () => { + for (const a of unackedActive) { + try { await api.acknowledge(a.tag, getOperator()) } catch { /* already handled */ } + } } - const displayed = tab === 'active' ? active : history + const rateTone = { Acceptable: '', Manageable: 'p3', 'Above target': 'p2', Flood: 'p1' }[summary?.rate_status] || '' return ( -
    +
    -

    Alarm Management

    -

    ISA 18.2 aligned alarm management system

    +
    +

    Alarms

    +

    Alarm management following ANSI/ISA-18.2

    +
    +
    - {/* Summary */} -
    - {[ - { label: 'Active Alarms', value: active.length, color: 'var(--status-crit)' }, - { label: 'Critical (P1)', value: active.filter(a=>a.priority===1).length, color: 'var(--status-crit)' }, - { label: 'High (P2)', value: active.filter(a=>a.priority===2).length, color: 'var(--status-warn)' }, - { label: 'Total History', value: history.length, color: 'var(--text-secondary)' }, - ].map(({ label, value, color }) => ( -
    -
    {label}
    -
    {value}
    + {showHelp &&
    } + +
    +
    +
    Unacknowledged
    +
    {summary?.unacknowledged ?? 0}
    +
    {summary?.rtn_unack ?? 0} returned to normal
    +
    +
    +
    Alarm list by priority
    +
    + {Object.entries(PRIORITY).map(([p, info]) => ( +
    + {summary?.by_priority?.[p] ?? 0} + {info.label} +
    + ))}
    - ))} +
    +
    +
    Alarm rate, last 10 min
    +
    {summary?.alarm_rate_10min ?? 0}
    +
    {summary?.rate_status} (ISA 18.2 target: about 1, flood at 10)
    +
    +
    +
    Out of the list
    +
    {(summary?.shelved ?? 0) + (summary?.suppressed ?? 0)}
    +
    {summary?.shelved ?? 0} shelved, {summary?.suppressed ?? 0} suppressed by design
    +
    -
    - - +
    + {TABS.map(t => ( + + ))}
    -
    - - - - - - - - - - - - - - {displayed.length === 0 ? ( - - ) : ( - displayed.map(a => ) - )} - -
    TimestampMeterConditionValueThresholdPriorityAction
    - {tab === 'active' ? 'No active alarms' : 'No alarm history'} -
    -
    + {tab === 'active' && ( + <> + {unackedActive.length > 1 && ( +
    + +
    + )} + + + )} + {tab === 'shelved' && } + {tab === 'suppressed' && ( + + )} + {tab === 'history' && } + {tab === 'database' && }
    ) diff --git a/frontend/src/pages/Dashboard.jsx b/frontend/src/pages/Dashboard.jsx index 7b4ee09..fa8e829 100644 --- a/frontend/src/pages/Dashboard.jsx +++ b/frontend/src/pages/Dashboard.jsx @@ -1,151 +1,198 @@ -import React, { useState, useEffect } from 'react' -import { useNavigate } from 'react-router-dom' -import { Zap, Activity, AlertTriangle, CheckCircle } from 'lucide-react' -import { LineChart, Line, ResponsiveContainer, Tooltip } from 'recharts' +import React, { useEffect, useMemo, useState } from 'react' +import { Link, useNavigate } from 'react-router-dom' +import { FlaskConical, X, ArrowRight, BatteryCharging, Plug, Server, Gauge as GaugeIcon, Bell } from 'lucide-react' +import { useFeed } from '../services/LiveFeed' +import { alarmsByMeter } from '../services/feed' import { api } from '../services/api' +import { Sparkline, AreaChart } from '../components/Sparkline' +import { PriorityBadge, StateBadge } from '../components/Badges' +import { ANNUNCIATED } from '../lib/alarms' +import { num, ago } from '../lib/format' +import { readFlag, writeFlag } from '../lib/operator' -function getStatus(reading) { - if (!reading) return 'off' - const v = reading.voltage - const nom = 480 - if (v > nom * 1.10 || v < nom * 0.90) return 'crit' - if (v > nom * 1.05 || v < nom * 0.95) return 'warn' - if (reading.power_factor < 0.75) return 'crit' - if (reading.power_factor < 0.85) return 'warn' - return 'ok' -} +const GROUPS = [ + { title: 'Sources', ids: ['UTIL-1', 'GEN-1', 'ATS-1'] }, + { title: 'Distribution', ids: ['MSB-1', 'MECH-1'] }, + { title: 'UPS', ids: ['UPS-A', 'UPS-B'] }, + { title: 'PDUs', ids: ['PDU-A1', 'PDU-A2', 'PDU-B1', 'PDU-B2'] }, +] + +const INTRO_KEY = 'pd.intro.dismissed' -function SparkLine({ data, color = '#00b4d8' }) { - if (!data || data.length < 2) return
    +function LoadBar({ pct }) { + const v = Math.max(0, Math.min(100, pct || 0)) + const cls = v >= 90 ? 'p2' : v >= 80 ? 'p3' : '' return ( - - - - - +
    +
    +
    ) } -function MeterTile({ meter, reading, onClick }) { - const status = getStatus(reading) - const statusClass = status === 'crit' ? 'status-crit' : status === 'warn' ? 'status-warn' : 'status-ok' - +function EquipmentTile({ meter, reading, alarm, onClick }) { + const r = reading || {} + const isUps = meter.type === 'ups' + const off = (r.voltage ?? 0) < 1 return ( -
    -
    - {meter.name} - -
    -
    -
    - Voltage - {reading?.voltage?.toFixed(1) ?? '--'} - V -
    -
    - Current - {reading?.current?.toFixed(1) ?? '--'} - A + + ) +} + +function Kpi({ label, value, unit, sub, children, tone }) { + return ( +
    +
    {label}
    +
    + {value}{unit && {unit}}
    + {sub &&
    {sub}
    } + {children}
    ) } -export default function Dashboard({ readings }) { +export default function Dashboard({ onAbout }) { + const { meters, meterById, readings, spark, system, alarms, summary } = useFeed() const navigate = useNavigate() - const [status, setStatus] = useState(null) - const [meters, setMeters] = useState([]) - const [history, setHistory] = useState([]) + const [introHidden, setIntroHidden] = useState(() => readFlag(INTRO_KEY)) + const [points, setPoints] = useState([]) + // Last hour of facility load, then extend with live scans useEffect(() => { - api.getSystemStatus().then(setStatus).catch(() => {}) - api.getMeters().then(setMeters).catch(() => {}) + let cancelled = false + api.getMeterHistory('MSB-1', '1h') + .then(rows => { if (!cancelled) setPoints(prev => [...rows.map(r => ({ t: r.epoch, v: r.power_kw })), ...prev]) }) + .catch(() => {}) + return () => { cancelled = true } }, []) - // Refresh status when readings update - useEffect(() => { - api.getSystemStatus().then(setStatus).catch(() => {}) - }, [readings]) - - // Build sparkline history from readings over time + const msb = readings['MSB-1'] useEffect(() => { - setHistory(prev => { - const totalPower = Object.values(readings).reduce((s, r) => s + (r.power_kw || 0), 0) - const next = [...prev, { v: totalPower, t: Date.now() }] - return next.slice(-60) + if (!msb) return + setPoints(prev => { + const last = prev[prev.length - 1] + if (last && msb.epoch - last.t < 10) return prev + return [...prev.filter(p => p.t > msb.epoch - 3600), { t: msb.epoch, v: msb.power_kw }] }) - }, [readings]) + }, [msb]) - const healthColor = status?.health === 'critical' ? 'var(--status-crit)' - : status?.health === 'warning' ? 'var(--status-warn)' - : 'var(--status-ok)' + const byMeter = useMemo(() => alarmsByMeter(alarms), [alarms]) + const annunciated = alarms.filter(a => ANNUNCIATED.includes(a.state)) - return ( -
    -
    -

    System Overview

    -

    Real-time electrical distribution monitoring

    -
    + const hideIntro = () => { setIntroHidden(true); writeFlag(INTRO_KEY, true) } - {/* Summary cards */} -
    -
    -
    Total Load
    -
    {status?.total_power_kw?.toFixed(1) ?? '--'}
    -
    kW
    - -
    -
    -
    Avg Power Factor
    -
    - {status?.avg_power_factor?.toFixed(3) ?? '--'} + const onGen = system?.power_source === 'GENERATOR' + const runtime = system?.ups_min_runtime_min + const anyOnBattery = readings['UPS-A']?.on_battery || readings['UPS-B']?.on_battery + + return ( +
    + {!introHidden && system?.simulated && ( +
    + +
    + Live demo on simulated data. This dashboard monitors a simulated 2N data + center in real time. Events like utility outages and PDU overloads happen every few minutes, + or you can trigger one and watch the ISA 18.2 alarm system respond. +
    + +
    -
    System average
    +
    -
    -
    Active Alarms
    -
    0 ? 'var(--status-crit)' : 'var(--status-ok)' - }}> - {status?.active_alarm_count ?? '--'} -
    -
    - {status?.critical_alarm_count > 0 - ? `${status.critical_alarm_count} critical` - : 'No critical alarms'} + )} + +
    + + + + + v + (spark['PDU-A2']?.[i] || 0) + (spark['PDU-B1']?.[i] || 0) + (spark['PDU-B2']?.[i] || 0))} /> + + + + +
    + +
    +
    +
    +

    Facility load, last hour

    + {num(system?.facility_kw, 0)} kW now
    +
    -
    -
    System Health
    -
    - {status?.health?.toUpperCase() ?? '--'} + +
    +
    +

    Alarm list

    + Manage
    -
    {status?.meters_online ?? 0} / {status?.meter_count ?? 0} meters online
    + {annunciated.length === 0 ? ( +
    +

    No active alarms.

    + +
    + ) : ( +
      + {annunciated.slice(0, 6).map(a => ( +
    • + +
      +
      {a.message}
      +
      {a.meter_name}, {ago(a.activated_at)}
      +
      + +
    • + ))} + {annunciated.length > 6 &&
    • +{annunciated.length - 6} more
    • } +
    + )}
    - {/* Meter grid */} -
    -

    METER OVERVIEW

    -
    -
    - {meters.map(m => ( - navigate(`/meters?id=${m.id}`)} - /> - ))} -
    + {GROUPS.map(g => ( +
    +

    + {g.title === 'Sources' ? : g.title === 'PDUs' ? : } + {g.title} +

    +
    + {g.ids.filter(id => meterById[id]).map(id => ( + navigate(`/meters?id=${id}`)} /> + ))} +
    +
    + ))} + {meters.length === 0 &&

    No meters configured.

    }
    ) } diff --git a/frontend/src/pages/Meters.jsx b/frontend/src/pages/Meters.jsx index 1074795..39f7b55 100644 --- a/frontend/src/pages/Meters.jsx +++ b/frontend/src/pages/Meters.jsx @@ -1,168 +1,180 @@ -import React, { useState, useEffect } from 'react' +import React, { useEffect, useMemo, useState } from 'react' import { useSearchParams } from 'react-router-dom' -import { - LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, ReferenceLine -} from 'recharts' +import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, ReferenceLine } from 'recharts' +import { useFeed } from '../services/LiveFeed' +import { alarmsByMeter } from '../services/feed' import { api } from '../services/api' +import { PriorityBadge, StateBadge } from '../components/Badges' +import { ANNUNCIATED } from '../lib/alarms' +import { num } from '../lib/format' -function GaugeArc({ value, min, max, warn, crit, label, unit, size = 120 }) { - const pct = Math.min(1, Math.max(0, (value - min) / (max - min))) - const angle = -210 + pct * 240 - const r = size / 2 - 12 - const cx = size / 2, cy = size / 2 - - const toXY = (deg, radius) => ({ - x: cx + radius * Math.cos((deg * Math.PI) / 180), - y: cy + radius * Math.sin((deg * Math.PI) / 180), - }) +const PERIODS = ['1h', '24h', '7d'] +const TREND_FIELDS = { + power_kw: { label: 'Power', unit: 'kW' }, + load_pct: { label: 'Load', unit: '%' }, + voltage: { label: 'Voltage', unit: 'V' }, + current: { label: 'Current', unit: 'A' }, + power_factor: { label: 'Power factor', unit: '' }, + frequency: { label: 'Frequency', unit: 'Hz' }, +} - const arcPath = (startDeg, endDeg, radius) => { - const s = toXY(startDeg, radius) - const e = toXY(endDeg, radius) - const large = endDeg - startDeg > 180 ? 1 : 0 - return `M${s.x},${s.y} A${radius},${radius} 0 ${large},1 ${e.x},${e.y}` +function Gauge({ value, min, max, warn, crit, low = false, label, unit, digits = 1 }) { + const v = value ?? min + const pct = Math.min(1, Math.max(0, (v - min) / (max - min))) + const size = 120 + const r = 46 + const cx = size / 2 + const cy = size / 2 + 6 + const start = -210 + const sweep = 240 + const pt = (deg, rad) => [cx + rad * Math.cos((deg * Math.PI) / 180), cy + rad * Math.sin((deg * Math.PI) / 180)] + const arc = (a0, a1) => { + const [x0, y0] = pt(a0, r) + const [x1, y1] = pt(a1, r) + return `M${x0},${y0} A${r},${r} 0 ${a1 - a0 > 180 ? 1 : 0},1 ${x1},${y1}` } - - const color = value >= crit ? '#ef4444' : value >= warn ? '#f59e0b' : '#22c55e' - + const abnormal = value != null && (low ? value <= crit : value >= crit) + const caution = value != null && !abnormal && (low ? value <= warn : value >= warn) + const cls = abnormal ? 'g-crit' : caution ? 'g-warn' : 'g-ok' return ( -
    - - - - - - - {value?.toFixed(unit === 'Hz' ? 3 : 1)} - - {unit} +
    + + + {pct > 0.002 && } + {num(value, digits)} + {unit}
    {label}
    ) } -export default function Meters({ readings }) { - const [searchParams, setSearchParams] = useSearchParams() - const [meters, setMeters] = useState([]) - const [history, setHistory] = useState([]) +export default function Meters() { + const { meters, meterById, readings, alarms } = useFeed() + const [params, setParams] = useSearchParams() + const selectedId = meterById[params.get('id')] ? params.get('id') : meters[0]?.id + const meter = meterById[selectedId] + const r = readings[selectedId] || {} const [period, setPeriod] = useState('1h') - const selectedId = parseInt(searchParams.get('id') || '1', 10) - - useEffect(() => { - api.getMeters().then(setMeters).catch(() => {}) - }, []) + const [field, setField] = useState('power_kw') + const [history, setHistory] = useState([]) + const byMeter = useMemo(() => alarmsByMeter(alarms), [alarms]) + const meterAlarms = alarms.filter(a => a.meter_id === selectedId && ANNUNCIATED.includes(a.state)) useEffect(() => { - api.getMeterHistory(selectedId, period).then(rows => { - setHistory(rows.map(r => ({ - ...r, - time: new Date(r.timestamp).toLocaleTimeString(), - }))) - }).catch(() => {}) + if (!selectedId) return undefined + let cancelled = false + api.getMeterHistory(selectedId, period) + .then(rows => { if (!cancelled) setHistory(rows) }) + .catch(() => {}) + return () => { cancelled = true } }, [selectedId, period]) - const meter = meters.find(m => m.id === selectedId) - const reading = readings[selectedId] || {} - const nomV = meter?.nominal_voltage || 480 - const nomI = meter?.nominal_current || 100 + if (!meter) return null + const nomV = meter.nominal_voltage + const tf = TREND_FIELDS[field] + const tickFmt = t => new Date(t * 1000).toLocaleTimeString([], period === '7d' + ? { month: 'short', day: 'numeric' } : { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }) return ( -
    - {/* Meter list */} -
    -
    - Meters +
    +
    + - {/* Detail panel */} -
    - {meter && ( - <> -
    -
    -

    {meter.name}

    -

    {meter.description}

    -
    -
    +
    +
    +
    +

    {meter.name} {meter.id}

    +

    {meter.description}

    +
    + {r.status || '--'} +
    - {/* Gauges */} -
    - - - - +
    + + + + +
    + +
    + {[ + ['Power', num(r.power_kw), 'kW'], + ['Current', num(r.current), 'A'], + ['Demand (15 min)', num(r.demand_kw), 'kW'], + ['Energy', r.energy_kwh != null ? Math.round(r.energy_kwh).toLocaleString() : '--', 'kWh'], + ...(meter.type === 'ups' ? [ + ['Battery', num(r.battery_soc), '%'], + ['Runtime', num(r.battery_runtime_min, 0), 'min'], + ] : []), + ...(meter.type === 'ats' ? [['Position', r.position === 'GENERATOR' ? 'Emergency' : 'Normal', '']] : []), + ...(meter.type === 'generator' ? [['Engine', r.gen_state ? r.gen_state.toLowerCase() : '--', '']] : []), + ].map(([label, value, unit]) => ( +
    +
    {label}
    +
    {value}{unit && {unit}}
    + ))} +
    - {/* Key metrics */} -
    - {[ - { label: 'Power', value: reading.power_kw?.toFixed(2), unit: 'kW' }, - { label: 'Demand', value: reading.demand_kw?.toFixed(2), unit: 'kW' }, - { label: 'Energy', value: reading.energy_kwh?.toFixed(1), unit: 'kWh' }, - { label: 'Load', value: ((reading.current / nomI) * 100)?.toFixed(1), unit: '%' }, - ].map(({ label, value, unit }) => ( -
    -
    {label}
    -
    {value ?? '--'}
    -
    {unit}
    -
    + {meterAlarms.length > 0 && ( +
    +

    Alarms on this meter

    +
      + {meterAlarms.map(a => ( +
    • + +
      {a.message}
      + +
    • ))} -
    + +
    + )} - {/* Trend chart */} -
    -
    - POWER TREND -
    - {['1h', '24h', '7d'].map(p => ( - - ))} -
    +
    +
    +

    Trend

    +
    + +
    + {PERIODS.map(p => ( + + ))}
    - - - - - - - - - -
    - - )} +
    + + + + + + new Date(t * 1000).toLocaleString()} formatter={v => [`${v} ${tf.unit}`, tf.label]} /> + {field === 'load_pct' && } + + + +
    ) diff --git a/frontend/src/pages/OneLineDiagram.jsx b/frontend/src/pages/OneLineDiagram.jsx index 6c9f743..f782fd7 100644 --- a/frontend/src/pages/OneLineDiagram.jsx +++ b/frontend/src/pages/OneLineDiagram.jsx @@ -1,168 +1,204 @@ -import React, { useState } from 'react' - -const LAYOUT = { - utility: { x: 400, y: 50, w: 120, h: 50 }, - switchgear: { x: 400, y: 160, w: 120, h: 50 }, - panelA: { x: 220, y: 280, w: 110, h: 50 }, - panelB: { x: 580, y: 280, w: 110, h: 50 }, - rowA1: { x: 130, y: 400, w: 100, h: 45 }, - rowA2: { x: 310, y: 400, w: 100, h: 45 }, - crac1: { x: 500, y: 400, w: 100, h: 45 }, - crac2: { x: 660, y: 400, w: 100, h: 45 }, +import React, { useEffect, useMemo, useState } from 'react' +import { Link } from 'react-router-dom' +import { X } from 'lucide-react' +import { useFeed } from '../services/LiveFeed' +import { alarmsByMeter } from '../services/feed' +import { PriorityBadge, StateBadge } from '../components/Badges' +import { ANNUNCIATED } from '../lib/alarms' +import { num } from '../lib/format' + +// Two layouts: landscape for desktop, portrait for phones. Positions are +// node center x and top y in SVG units. +const LAYOUTS = { + wide: { + width: 900, height: 560, busY: 318, busX: [150, 850], srcY: 100, pduY: 450, atsIn: 40, labelGap: 30, + nodes: { + 'UTIL-1': { x: 300, y: 16, w: 160 }, + 'GEN-1': { x: 620, y: 16, w: 160 }, + 'ATS-1': { x: 460, y: 128, w: 224 }, + 'MSB-1': { x: 460, y: 232, w: 190 }, + 'UPS-A': { x: 230, y: 350, w: 150 }, + 'UPS-B': { x: 530, y: 350, w: 150 }, + 'MECH-1': { x: 770, y: 350, w: 150 }, + 'PDU-A1': { x: 150, y: 482, w: 136 }, + 'PDU-A2': { x: 310, y: 482, w: 136 }, + 'PDU-B1': { x: 450, y: 482, w: 136 }, + 'PDU-B2': { x: 610, y: 482, w: 136 }, + }, + }, + narrow: { + width: 400, height: 672, busY: 312, busX: [10, 390], srcY: 96, pduY: 436, atsIn: 30, labelGap: 22, + nodes: { + 'UTIL-1': { x: 102, y: 10, w: 184 }, + 'GEN-1': { x: 298, y: 10, w: 184 }, + 'ATS-1': { x: 200, y: 122, w: 230 }, + 'MSB-1': { x: 200, y: 222, w: 230 }, + 'UPS-A': { x: 104, y: 334, w: 182 }, + 'UPS-B': { x: 296, y: 334, w: 182 }, + 'PDU-A1': { x: 54, y: 462, w: 96 }, + 'PDU-A2': { x: 151, y: 462, w: 96 }, + 'PDU-B1': { x: 249, y: 462, w: 96 }, + 'PDU-B2': { x: 346, y: 462, w: 96 }, + 'MECH-1': { x: 200, y: 598, w: 230 }, + }, + }, } - -const METER_KEYS = [null, 'utility', 'switchgear', 'panelA', 'panelB', 'rowA1', 'rowA2', 'crac1', 'crac2'] - -function getStatusColor(reading, nomV = 480, nomI = 100) { - if (!reading) return '#4b5563' - const v = reading.voltage - if (v > nomV * 1.10 || v < nomV * 0.90 || reading.power_factor < 0.75) return '#ef4444' - if (v > nomV * 1.05 || v < nomV * 0.95 || reading.power_factor < 0.85) return '#f59e0b' - return '#22c55e' +const H = 64 + +function useNarrow(query = '(max-width: 720px)') { + const get = () => typeof window !== 'undefined' && window.matchMedia?.(query).matches + const [narrow, setNarrow] = useState(get) + useEffect(() => { + const mq = window.matchMedia?.(query) + if (!mq) return undefined + const on = () => setNarrow(mq.matches) + mq.addEventListener('change', on) + return () => mq.removeEventListener('change', on) + }, [query]) + return narrow } -function MeterNode({ nodeKey, reading, meter, selected, onClick }) { - const pos = LAYOUT[nodeKey] - const color = getStatusColor(reading, meter?.nominal_voltage, meter?.nominal_current) - - return ( - - - - {meter?.name ?? nodeKey} - - - {reading ? `${reading.voltage?.toFixed(0)}V ${reading.current?.toFixed(0)}A` : 'No data'} - - - {reading ? `${reading.power_kw?.toFixed(1)}kW PF${reading.power_factor?.toFixed(2)}` : ''} - - - - ) +function Wire({ d, state }) { + return } -function Bus({ x, y1, y2, label }) { +function Node({ n, id, meter, reading, alarm, selected, onSelect }) { + const compact = n.w < 120 + const r = reading || {} + const dead = (r.voltage ?? 0) < 1 + const statusCls = (r.status || '').toLowerCase().replace(/\s+/g, '-') + let line2 = compact ? `${num(r.power_kw, 0)}kW ${num(r.load_pct, 0)}%` : `${num(r.power_kw, 0)} kW ${num(r.load_pct, 0)}%` + if (meter.type === 'ups') line2 = `${num(r.power_kw, 0)} kW batt ${num(r.battery_soc, 0)}%` + if (meter.type === 'generator' && dead) line2 = '0 kW' + if (meter.type === 'ats') line2 = `${num(r.power_kw, 0)} kW ${r.position === 'GENERATOR' ? 'E' : 'N'} closed` + return ( - - - - {label && ( - {label} - )} + onSelect(id)} role="button" tabIndex={0} + onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && onSelect(id)} + aria-label={`${meter.name}, ${r.status || 'no data'}`}> + + {meter.name} + {r.status || '--'} + {line2} + {alarm && } ) } -export default function OneLineDiagram({ readings }) { +export default function OneLineDiagram() { + const { meterById, readings, alarms } = useFeed() const [selected, setSelected] = useState(null) - - const nodeKeys = ['utility', 'switchgear', 'panelA', 'panelB', 'rowA1', 'rowA2', 'crac1', 'crac2'] - const metersByKey = {} - METER_KEYS.forEach((key, idx) => { - if (key) metersByKey[key] = { - id: idx, - name: key === 'utility' ? 'Utility Feed' - : key === 'switchgear' ? 'Main Switchgear' - : key === 'panelA' ? 'Panel A' - : key === 'panelB' ? 'Panel B' - : key === 'rowA1' ? 'Server Row A1' - : key === 'rowA2' ? 'Server Row A2' - : key === 'crac1' ? 'CRAC Unit 1' - : 'CRAC Unit 2', - nominal_voltage: 480, - nominal_current: [800, 750, 400, 350, 120, 120, 180, 170][idx - 1] || 100, - } - }) - - const selectedReading = selected ? readings[METER_KEYS.indexOf(selected)] : null + const byMeter = useMemo(() => alarmsByMeter(alarms), [alarms]) + + const live = id => (readings[id]?.voltage ?? 0) > 50 + const onGen = readings['ATS-1']?.position === 'GENERATOR' + const msbLive = live('MSB-1') + const wire = (energized, carrying) => (!energized ? 'dead' : carrying ? 'flow' : 'live') + + const L = LAYOUTS[useNarrow() ? 'narrow' : 'wide'] + const NODES = L.nodes + const bottom = id => NODES[id].y + H + const ats = NODES['ATS-1'] + const { busY, srcY, pduY } = L + const select = id => setSelected(s => (s === id ? null : id)) + const sel = selected && meterById[selected] + const selReading = selected ? readings[selected] || {} : null + const selAlarms = selected ? alarms.filter(a => a.meter_id === selected && ANNUNCIATED.includes(a.state)) : [] return ( -
    -
    -
    - ELECTRICAL DISTRIBUTION ONE-LINE DIAGRAM +
    +
    +
    +

    One-line diagram

    +

    Live power path from the sources to the IT load. Select any equipment for details.

    - - {/* Background */} - - - {/* Buses */} - - - - {/* Panel connections */} - - - - - - - {/* Sub-meter connections */} - - - - - - - - - - - - - {/* Nodes */} - {nodeKeys.map((key, i) => ( - setSelected(selected === key ? null : key)} - /> - ))} - - {/* Labels */} - Power Dashboard - Electrical Distribution System -
    - {/* Side panel */} - {selected && selectedReading && ( -
    -
    - {metersByKey[selected]?.name?.toUpperCase() ?? selected.toUpperCase()} +
    +
    +
    + Carrying load + Energized + De-energized +
    +
    + + {/* Sources to ATS */} + + + N + E + + {/* ATS to switchboard to bus */} + + + + 480 V MAIN BUS + + {/* Bus to UPS and mechanical */} + {['UPS-A', 'UPS-B', 'MECH-1'].map(id => ( + 0)} /> + ))} + + {/* UPS to PDUs */} + {[['UPS-A', ['PDU-A1', 'PDU-A2']], ['UPS-B', ['PDU-B1', 'PDU-B2']]].map(([ups, pdus]) => ( + + + + {pdus.map(p => )} + + ))} + + {Object.keys(NODES).filter(id => meterById[id]).map(id => ( + + ))} +
    - {[ - ['Voltage', selectedReading.voltage?.toFixed(2), 'V'], - ['Current', selectedReading.current?.toFixed(2), 'A'], - ['Power', selectedReading.power_kw?.toFixed(2), 'kW'], - ['Power Factor', selectedReading.power_factor?.toFixed(4), ''], - ['Frequency', selectedReading.frequency?.toFixed(3), 'Hz'], - ['Demand', selectedReading.demand_kw?.toFixed(2), 'kW'], - ['Energy', selectedReading.energy_kwh?.toFixed(1), 'kWh'], - ].map(([label, val, unit]) => ( -
    - {label} - - {val} {unit} - -
    - ))} -
    - )} + + {sel && ( +
    +
    +

    {sel.name}

    + +
    +

    {sel.description}

    +
    + {[ + ['Status', selReading.status], + ['Voltage', `${num(selReading.voltage)} V`], + ['Current', `${num(selReading.current)} A`], + ['Power', `${num(selReading.power_kw)} kW`], + ['Power factor', num(selReading.power_factor, 3)], + ['Frequency', `${num(selReading.frequency, 2)} Hz`], + ['Load', `${num(selReading.load_pct)} %`], + ['Demand (15 min)', `${num(selReading.demand_kw)} kW`], + ...(sel.type === 'ups' ? [ + ['Battery charge', `${num(selReading.battery_soc)} %`], + ['Battery runtime', `${num(selReading.battery_runtime_min, 0)} min`], + ['Input power', `${num(selReading.input_kw)} kW`], + ] : []), + ].map(([k, v]) =>
    {k}
    {v}
    )} +
    + {selAlarms.length > 0 && ( +
      + {selAlarms.map(a => ( +
    • + +
      {a.message}
      + +
    • + ))} +
    + )} + Open meter detail +
    + )} +
    ) } diff --git a/frontend/src/pages/SettingsPage.jsx b/frontend/src/pages/SettingsPage.jsx index 4d1f044..c30a6de 100644 --- a/frontend/src/pages/SettingsPage.jsx +++ b/frontend/src/pages/SettingsPage.jsx @@ -1,79 +1,96 @@ -import React from 'react' -import { Settings, Database, Wifi, Bell } from 'lucide-react' +import React, { useEffect, useState } from 'react' +import { Wifi, Database, User, Cpu } from 'lucide-react' +import { useFeed } from '../services/LiveFeed' +import { api } from '../services/api' +import { API_URL, WS_URL } from '../services/endpoints' +import { getOperator, setOperator } from '../lib/operator' +import { PriorityBadge } from '../components/Badges' -const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000' -const WS_URL = API_URL.replace(/^https:\/\//, 'wss://').replace(/^http:\/\//, 'ws://') + '/ws/live' +function Rows({ rows }) { + return ( +
    + {rows.map(([k, v]) =>
    {k}
    {v}
    )} +
    + ) +} export default function SettingsPage() { + const { system, demo } = useFeed() + const [cfg, setCfg] = useState(null) + const [name, setName] = useState(getOperator) + const [saved, setSaved] = useState(false) + + useEffect(() => { api.getConfig().then(setCfg).catch(() => {}) }, []) + + const save = (e) => { + e.preventDefault() + setOperator(name.trim() || 'demo visitor') + setSaved(true) + setTimeout(() => setSaved(false), 1500) + } + return ( -
    +
    -

    Settings

    -

    System configuration and preferences

    +
    +

    System

    +

    Data source, connection, and alarm configuration

    +
    -
    +
    -
    - CONNECTION -
    -
    - {[ - { label: 'API Endpoint', value: API_URL }, - { label: 'WebSocket', value: WS_URL }, - { label: 'Poll Interval', value: '5 seconds' }, - { label: 'WS Broadcast Rate', value: '2 seconds' }, - ].map(({ label, value }) => ( -
    - {label} - {value} -
    - ))} -
    +

    Data source

    + +

    + Real meters are polled over Modbus TCP when the backend runs with DATA_SOURCE=modbus and a + register map. See the README for setup. +

    -
    - ALARM THRESHOLDS -
    -
    - {[ - { label: 'Voltage High Critical', value: '110% of nominal' }, - { label: 'Voltage High Warning', value: '105% of nominal' }, - { label: 'Voltage Low Warning', value: '95% of nominal' }, - { label: 'Voltage Low Critical', value: '90% of nominal' }, - { label: 'Current High Critical', value: '100% of nominal' }, - { label: 'Current High Warning', value: '85% of nominal' }, - { label: 'Power Factor Warning', value: 'PF < 0.85' }, - { label: 'Power Factor Critical', value: 'PF < 0.75' }, - { label: 'Frequency Warning', value: '59.5 - 60.5 Hz' }, - { label: 'Frequency Critical', value: '59.0 - 61.0 Hz' }, - ].map(({ label, value }) => ( -
    - {label} - {value} -
    - ))} -
    +

    Connection

    +
    -
    - DATA RETENTION -
    -
    - {[ - { label: 'Reading Retention', value: '7 days' }, - { label: 'Alarm History', value: 'Indefinite' }, - { label: 'Database', value: 'SQLite (power_dashboard.db)' }, - { label: 'Prune Interval', value: 'Every 1 hour' }, - ].map(({ label, value }) => ( -
    - {label} - {value} -
    +

    Operator

    +
    + +
    + setName(e.target.value)} /> + +
    +
    +
    + +
    +

    Retention

    + +
    + +
    +

    Alarm priorities

    +

    Priority comes from the consequence of not responding and the time available to respond.

    +
    + {cfg && Object.entries(cfg.priorities).map(([p, info]) => ( +
    {info.response}
    ))} -
    +
    diff --git a/frontend/src/pages/Trending.jsx b/frontend/src/pages/Trending.jsx index 17aeac8..0a0411e 100644 --- a/frontend/src/pages/Trending.jsx +++ b/frontend/src/pages/Trending.jsx @@ -1,144 +1,129 @@ -import React, { useState, useEffect } from 'react' +import React, { useEffect, useMemo, useState } from 'react' import { Download } from 'lucide-react' -import { - LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, - Legend, ResponsiveContainer -} from 'recharts' +import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts' +import { useFeed } from '../services/LiveFeed' import { api } from '../services/api' -const COLORS = ['#00b4d8', '#22c55e', '#f59e0b', '#a78bfa', '#ef4444', '#fb923c', '#34d399', '#60a5fa'] -const PARAMETERS = ['power_kw', 'voltage', 'current', 'power_factor', 'demand_kw', 'frequency'] +const COLORS = ['#60a5fa', '#34d399', '#f59e0b', '#c084fc', '#f472b6', '#22d3ee', '#a3e635', '#fb923c'] +const PARAMETERS = { + power_kw: 'Power (kW)', + load_pct: 'Load (% of rating)', + current: 'Current (A)', + voltage: 'Voltage (V)', + power_factor: 'Power factor', + frequency: 'Frequency (Hz)', + demand_kw: 'Demand (kW)', +} export default function Trending() { - const [meters, setMeters] = useState([]) - const [selectedMeters, setSelectedMeters] = useState([1, 2]) + const { meters } = useFeed() + const [selected, setSelected] = useState(['UTIL-1', 'UPS-A', 'UPS-B', 'MECH-1']) const [parameter, setParameter] = useState('power_kw') const [period, setPeriod] = useState('1h') - const [chartData, setChartData] = useState([]) + const [series, setSeries] = useState({}) const [loading, setLoading] = useState(false) useEffect(() => { - api.getMeters().then(setMeters).catch(() => {}) - }, []) - - useEffect(() => { - if (selectedMeters.length === 0) return + let cancelled = false setLoading(true) - Promise.all(selectedMeters.map(id => api.getMeterHistory(id, period))) - .then(results => { - // Merge by timestamp index - const merged = {} - results.forEach((rows, idx) => { - rows.forEach(row => { - const key = row.timestamp - if (!merged[key]) merged[key] = { time: new Date(row.timestamp).toLocaleTimeString() } - merged[key][`m${selectedMeters[idx]}`] = row[parameter] - }) - }) - setChartData(Object.values(merged).sort((a, b) => a.time > b.time ? 1 : -1)) - }) - .finally(() => setLoading(false)) - }, [selectedMeters, parameter, period]) + Promise.all(selected.map(id => api.getMeterHistory(id, period).then(rows => [id, rows]).catch(() => [id, []]))) + .then(results => { if (!cancelled) setSeries(Object.fromEntries(results)) }) + .finally(() => { if (!cancelled) setLoading(false) }) + return () => { cancelled = true } + }, [selected, period]) - const toggleMeter = (id) => { - setSelectedMeters(prev => - prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id] - ) - } + // History buckets share boundaries across meters, so merge on epoch + const data = useMemo(() => { + const merged = {} + for (const id of selected) { + for (const row of series[id] || []) { + merged[row.epoch] = merged[row.epoch] || { epoch: row.epoch } + merged[row.epoch][id] = row[parameter] + } + } + return Object.values(merged).sort((a, b) => a.epoch - b.epoch) + }, [series, selected, parameter]) + + const toggle = id => setSelected(prev => (prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id])) const exportCSV = () => { - const headers = ['time', ...selectedMeters.map(id => `Meter_${id}_${parameter}`)] - const rows = chartData.map(row => headers.map(h => row[h] ?? '').join(',')) - const csv = [headers.join(','), ...rows].join('\n') - const blob = new Blob([csv], { type: 'text/csv' }) + const header = ['timestamp_utc', ...selected.map(id => `${id}_${parameter}`)] + const rows = data.map(r => [new Date(r.epoch * 1000).toISOString(), ...selected.map(id => r[id] ?? '')].join(',')) + const blob = new Blob([[header.join(','), ...rows].join('\n')], { type: 'text/csv' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') - a.href = url; a.download = `trending_${parameter}_${period}.csv`; a.click() + a.href = url + a.download = `trend_${parameter}_${period}.csv` + a.click() URL.revokeObjectURL(url) } + const tickFmt = t => new Date(t * 1000).toLocaleString([], period === '7d' + ? { month: 'short', day: 'numeric' } : { hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }) + return ( -
    +
    -

    Trending

    -

    Multi-meter historical comparison

    +
    +

    Trends

    +

    Compare meters over time. History is averaged into about 360 points per period.

    +
    +
    - {/* Controls */} -
    -
    -
    -
    - Meters -
    -
    - {meters.map(m => ( - - ))} -
    +
    +
    +
    Meters
    +
    + {meters.map(m => { + const idx = selected.indexOf(m.id) + return ( + + ) + })}
    - -
    -
    - Parameter -
    - setParameter(e.target.value)} aria-label="Parameter"> + {Object.entries(PARAMETERS).map(([k, v]) => )}
    - -
    -
    - Period -
    -
    +
    +
    Period
    +
    {['1h', '24h', '7d'].map(p => ( - + ))}
    - -
    - -
    - {/* Chart */}
    - {loading ? ( -
    Loading...
    + {selected.length === 0 ? ( +

    Select one or more meters.

    + ) : loading && !data.length ? ( +

    Loading...

    ) : ( - - - - - - - - {selectedMeters.map((id, i) => ( - m.id === id)?.name || `Meter ${id}`} - stroke={COLORS[i % COLORS.length]} - dot={false} - strokeWidth={1.5} - /> + + + + + + new Date(t * 1000).toLocaleString()} /> + + {selected.map((id, i) => ( + m.id === id)?.name || id} + stroke={COLORS[i % COLORS.length]} dot={false} strokeWidth={1.6} isAnimationActive={false} connectNulls /> ))} diff --git a/frontend/src/services/LiveFeed.jsx b/frontend/src/services/LiveFeed.jsx new file mode 100644 index 0000000..da7845d --- /dev/null +++ b/frontend/src/services/LiveFeed.jsx @@ -0,0 +1,132 @@ +import React, { createContext, useCallback, useContext, useEffect, useReducer, useRef, useState } from 'react' +import { api } from './api' +import { WS_URL } from './endpoints' +import { initialFeed, reduceFeed } from './feed' + +const FeedContext = createContext(null) + +const STALE_MS = 15000 // no message for this long means the socket is dead +const MAX_BACKOFF_MS = 8000 + +function feedReducer(state, msg) { + return reduceFeed(state, msg) +} + +/** + * Connection phases: + * connecting first attempt, nothing heard yet + * live receiving data + * reconnecting had data, lost the socket, retrying in the background + * + * Before the first snapshot the app shows the wake screen. The hosting free + * tier sleeps when idle, so the health check doubles as a wake up call. + */ +export function LiveFeedProvider({ children }) { + const [feed, dispatch] = useReducer(feedReducer, initialFeed) + const [phase, setPhase] = useState('connecting') + const [serverAwake, setServerAwake] = useState(false) + const [startedAt, setStartedAt] = useState(() => Date.now()) + const [attempt, setAttempt] = useState(0) + + const wsRef = useRef(null) + const timerRef = useRef(null) + const backoffRef = useRef(1000) + const lastMsgRef = useRef(0) + const hasDataRef = useRef(false) + const aliveRef = useRef(true) + + const connect = useCallback(() => { + if (!aliveRef.current) return + clearTimeout(timerRef.current) + let ws + try { + ws = new WebSocket(WS_URL) + } catch { + timerRef.current = setTimeout(connect, backoffRef.current) + return + } + wsRef.current = ws + setAttempt(a => a + 1) + + ws.onopen = () => { + backoffRef.current = 1000 + lastMsgRef.current = Date.now() + } + ws.onmessage = (evt) => { + let msg + try { msg = JSON.parse(evt.data) } catch { return } + lastMsgRef.current = Date.now() + dispatch(msg) + if (msg.type === 'snapshot') { + hasDataRef.current = true + setServerAwake(true) + setPhase('live') + } + } + ws.onclose = () => { + if (wsRef.current !== ws || !aliveRef.current) return + wsRef.current = null + setPhase(hasDataRef.current ? 'reconnecting' : 'connecting') + timerRef.current = setTimeout(connect, backoffRef.current) + backoffRef.current = Math.min(backoffRef.current * 1.6, MAX_BACKOFF_MS) + } + ws.onerror = () => ws.close() + }, []) + + // Open the socket and watch for a silent (stale) connection + useEffect(() => { + aliveRef.current = true + connect() + const watchdog = setInterval(() => { + const ws = wsRef.current + if (ws && ws.readyState === WebSocket.OPEN && Date.now() - lastMsgRef.current > STALE_MS) { + ws.close() + } + }, 5000) + return () => { + aliveRef.current = false + clearInterval(watchdog) + clearTimeout(timerRef.current) + wsRef.current?.close() + } + }, [connect]) + + // Wake the server with plain HTTP until the feed is up (a sleeping host + // starts on HTTP traffic; WebSocket attempts alone can fail fast) + useEffect(() => { + if (phase === 'live') return undefined + let cancelled = false + let timer + const poke = async () => { + try { + const h = await api.health(20000) + if (cancelled) return + if (h?.status === 'ok') { + setServerAwake(true) + // Server is up but the socket is still waiting on a retry: go now + if (!wsRef.current) { backoffRef.current = 1000; connect() } + } + } catch { /* still asleep or unreachable */ } + if (!cancelled) timer = setTimeout(poke, 4000) + } + poke() + return () => { cancelled = true; clearTimeout(timer) } + }, [phase, connect]) + + const retry = useCallback(() => { + setStartedAt(Date.now()) + backoffRef.current = 1000 + wsRef.current?.close() + wsRef.current = null + connect() + }, [connect]) + + const value = { ...feed, phase, serverAwake, startedAt, attempt, retry, hasData: !!feed.snapshotAt } + return {children} +} + +export function useFeed() { + const ctx = useContext(FeedContext) + if (!ctx) throw new Error('useFeed must be used inside LiveFeedProvider') + return ctx +} diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index 094de64..0988699 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -1,17 +1,34 @@ -const BASE = (import.meta.env.VITE_API_URL || 'http://localhost:8000') + '/api' +import { API_URL } from './endpoints' -async function request(path, options = {}) { - const res = await fetch(`${BASE}${path}`, options) - if (!res.ok) throw new Error(`API error ${res.status}`) - return res.json() +const BASE = `${API_URL}/api` + +async function request(path, { method = 'GET', body, timeout = 15000 } = {}) { + const ctrl = new AbortController() + const timer = setTimeout(() => ctrl.abort(), timeout) + try { + const res = await fetch(`${BASE}${path}`, { + method, + signal: ctrl.signal, + headers: body ? { 'Content-Type': 'application/json' } : undefined, + body: body ? JSON.stringify(body) : undefined, + }) + const data = await res.json().catch(() => null) + if (!res.ok) throw new Error(data?.detail || `Request failed (${res.status})`) + return data + } finally { + clearTimeout(timer) + } } export const api = { - getMeters: () => request('/meters'), - getMeter: (id) => request(`/meters/${id}`), - getMeterHistory: (id, period) => request(`/meters/${id}/history?period=${period}`), - getAlarms: () => request('/alarms'), - getAlarmHistory: (limit=200) => request(`/alarms/history?limit=${limit}`), - acknowledgeAlarm: (id) => request(`/alarms/${id}/acknowledge`, { method: 'POST' }), - getSystemStatus: () => request('/system/status'), + health: (timeout) => request('/health', { timeout }), + getConfig: () => request('/config'), + getMeterHistory: (id, period) => request(`/meters/${encodeURIComponent(id)}/history?period=${period}`), + getAlarmHistory: (limit = 200) => request(`/alarms/history?limit=${limit}`), + getAlarmDefs: () => request('/alarms/definitions'), + acknowledge: (tag, operator) => request(`/alarms/${encodeURIComponent(tag)}/acknowledge`, { method: 'POST', body: { operator } }), + shelve: (tag, minutes, reason, operator) => + request(`/alarms/${encodeURIComponent(tag)}/shelve`, { method: 'POST', body: { minutes, reason, operator } }), + unshelve: (tag, operator) => request(`/alarms/${encodeURIComponent(tag)}/unshelve`, { method: 'POST', body: { operator } }), + triggerEvent: (name) => request(`/demo/events/${encodeURIComponent(name)}`, { method: 'POST' }), } diff --git a/frontend/src/services/endpoints.js b/frontend/src/services/endpoints.js new file mode 100644 index 0000000..a973a53 --- /dev/null +++ b/frontend/src/services/endpoints.js @@ -0,0 +1,12 @@ +// Backend location. Leave VITE_API_URL empty to use the same origin +// (the Vite dev server proxies /api and /ws to the local backend). +export const API_URL = (import.meta.env.VITE_API_URL || '').trim().replace(/\/+$/, '') + +export function buildWsUrl(apiUrl = API_URL, loc = globalThis.location) { + if (apiUrl) return apiUrl.replace(/^http/, 'ws') + '/ws/live' + if (!loc) return '/ws/live' + const proto = loc.protocol === 'https:' ? 'wss:' : 'ws:' + return `${proto}//${loc.host}/ws/live` +} + +export const WS_URL = buildWsUrl() diff --git a/frontend/src/services/feed.js b/frontend/src/services/feed.js new file mode 100644 index 0000000..01c8c56 --- /dev/null +++ b/frontend/src/services/feed.js @@ -0,0 +1,79 @@ +// Pure state handling for the WebSocket feed (kept free of React so it is easy to test). + +export const SPARK_POINTS = 90 // 3 minutes at a 2 second scan + +export const initialFeed = { + meters: [], + meterById: {}, + readings: {}, + spark: {}, + system: null, + alarms: [], + summary: null, + demo: null, + snapshotAt: null, + lastMessageAt: null, +} + +function pushSpark(spark, readings) { + const next = { ...spark } + for (const r of readings) { + if (r.power_kw == null) continue + const arr = next[r.meter_id] ? next[r.meter_id].slice(-(SPARK_POINTS - 1)) : [] + arr.push(r.power_kw) + next[r.meter_id] = arr + } + return next +} + +function mergeReadings(prev, list) { + const next = { ...prev } + for (const r of list) next[r.meter_id] = r + return next +} + +export function reduceFeed(state, msg, now = Date.now()) { + if (!msg || typeof msg !== 'object') return state + const d = msg.data || {} + switch (msg.type) { + case 'snapshot': + return { + ...state, + meters: d.meters || [], + meterById: Object.fromEntries((d.meters || []).map(m => [m.id, m])), + readings: mergeReadings({}, d.readings || []), + spark: state.snapshotAt ? state.spark : pushSpark({}, d.readings || []), + system: d.system || null, + alarms: d.alarms || [], + summary: d.summary || null, + demo: d.demo || null, + snapshotAt: now, + lastMessageAt: now, + } + case 'readings': + return { + ...state, + readings: mergeReadings(state.readings, d.readings || []), + spark: pushSpark(state.spark, d.readings || []), + system: d.system || state.system, + lastMessageAt: now, + } + case 'alarms': + return { ...state, alarms: d.alarms || [], summary: d.summary || state.summary, lastMessageAt: now } + case 'pong': + return { ...state, lastMessageAt: now } + default: + return state + } +} + +// Highest priority (lowest number) annunciated alarm per meter +export function alarmsByMeter(alarms) { + const out = {} + for (const a of alarms) { + if (!['UNACK', 'ACKED', 'RTN_UNACK'].includes(a.state)) continue + const cur = out[a.meter_id] + if (!cur || a.priority < cur.priority) out[a.meter_id] = a + } + return out +} diff --git a/frontend/src/services/feed.test.js b/frontend/src/services/feed.test.js new file mode 100644 index 0000000..a94af6d --- /dev/null +++ b/frontend/src/services/feed.test.js @@ -0,0 +1,86 @@ +import { describe, expect, it } from 'vitest' +import { SPARK_POINTS, alarmsByMeter, initialFeed, reduceFeed } from './feed' +import { buildWsUrl } from './endpoints' + +const meters = [{ id: 'UTIL-1', name: 'Utility' }, { id: 'UPS-A', name: 'UPS A' }] +const reading = (id, kw, epoch = 1) => ({ meter_id: id, power_kw: kw, epoch }) + +const snapshot = { + type: 'snapshot', + data: { + meters, + readings: [reading('UTIL-1', 400), reading('UPS-A', 140)], + system: { health: 'normal' }, + alarms: [], + summary: { unacknowledged: 0 }, + demo: { simulated: true }, + }, +} + +describe('reduceFeed', () => { + it('loads a snapshot', () => { + const s = reduceFeed(initialFeed, snapshot, 1000) + expect(s.meterById['UPS-A'].name).toBe('UPS A') + expect(s.readings['UTIL-1'].power_kw).toBe(400) + expect(s.spark['UTIL-1']).toEqual([400]) + expect(s.snapshotAt).toBe(1000) + expect(s.demo.simulated).toBe(true) + }) + + it('merges live readings and keeps a bounded sparkline', () => { + let s = reduceFeed(initialFeed, snapshot) + for (let i = 0; i < SPARK_POINTS + 20; i++) { + s = reduceFeed(s, { type: 'readings', data: { readings: [reading('UTIL-1', 400 + i, i)], system: { health: 'caution' } } }) + } + expect(s.readings['UTIL-1'].power_kw).toBe(400 + SPARK_POINTS + 19) + expect(s.readings['UPS-A'].power_kw).toBe(140) // untouched meter kept + expect(s.spark['UTIL-1']).toHaveLength(SPARK_POINTS) + expect(s.system.health).toBe('caution') + }) + + it('replaces the alarm list on an alarms message', () => { + const alarms = [{ tag: 'UPS-A.ONBATT', meter_id: 'UPS-A', priority: 1, state: 'UNACK' }] + const s = reduceFeed(reduceFeed(initialFeed, snapshot), { type: 'alarms', data: { alarms, summary: { unacknowledged: 1 } } }) + expect(s.alarms).toEqual(alarms) + expect(s.summary.unacknowledged).toBe(1) + }) + + it('a reconnect snapshot keeps the sparkline history', () => { + let s = reduceFeed(initialFeed, snapshot) + s = reduceFeed(s, { type: 'readings', data: { readings: [reading('UTIL-1', 410, 2)] } }) + s = reduceFeed(s, snapshot) + expect(s.spark['UTIL-1']).toEqual([400, 410]) + }) + + it('ignores unknown or malformed messages', () => { + const s = reduceFeed(initialFeed, snapshot) + expect(reduceFeed(s, { type: 'mystery' })).toBe(s) + expect(reduceFeed(s, null)).toBe(s) + }) +}) + +describe('alarmsByMeter', () => { + it('picks the highest priority annunciated alarm per meter', () => { + const out = alarmsByMeter([ + { meter_id: 'UPS-A', priority: 2, state: 'ACKED' }, + { meter_id: 'UPS-A', priority: 1, state: 'RTN_UNACK' }, + { meter_id: 'GEN-1', priority: 3, state: 'SUPPRESSED' }, + { meter_id: 'PDU-A1', priority: 3, state: 'SHELVED' }, + ]) + expect(out['UPS-A'].priority).toBe(1) + expect(out['GEN-1']).toBeUndefined() + expect(out['PDU-A1']).toBeUndefined() + }) +}) + +describe('buildWsUrl', () => { + it('derives the socket URL from the API URL', () => { + expect(buildWsUrl('https://api.example.com')).toBe('wss://api.example.com/ws/live') + expect(buildWsUrl('http://localhost:8000')).toBe('ws://localhost:8000/ws/live') + }) + + it('falls back to the page origin', () => { + expect(buildWsUrl('', { protocol: 'https:', host: 'demo.example.com' })).toBe('wss://demo.example.com/ws/live') + expect(buildWsUrl('', { protocol: 'http:', host: 'localhost:5173' })).toBe('ws://localhost:5173/ws/live') + }) +}) diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 474ebd5..740f141 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -6,10 +6,10 @@ export default defineConfig({ server: { proxy: { '/api': 'http://localhost:8000', - '/ws': { - target: 'ws://localhost:8000', - ws: true, - }, + '/ws': { target: 'ws://localhost:8000', ws: true }, }, }, + test: { + environment: 'node', + }, }) From f570b4e1edf9d1785f52be2d290089413cfa23bd Mon Sep 17 00:00:00 2001 From: AddisonTech Date: Fri, 16 Oct 2026 16:19:26 +0000 Subject: [PATCH 07/10] Add Render Blueprint and pin pydantic Static front end plus API web service, both deploying from main with build filters, health check, and an SPA rewrite for deep links. --- backend/requirements.txt | 1 + render.yaml | 64 ++++++++++++++++++++++++++++++++++++++ screenshots/settings.webp | Bin 25106 -> 0 bytes 3 files changed, 65 insertions(+) create mode 100644 render.yaml delete mode 100644 screenshots/settings.webp diff --git a/backend/requirements.txt b/backend/requirements.txt index c83aa69..1eab1e7 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,2 +1,3 @@ fastapi==0.111.0 uvicorn[standard]==0.29.0 +pydantic==2.14.1 diff --git a/render.yaml b/render.yaml new file mode 100644 index 0000000..4f56161 --- /dev/null +++ b/render.yaml @@ -0,0 +1,64 @@ +# Render Blueprint for Power Dashboard +# https://render.com/docs/blueprint-spec +# +# Two services deploy from main on every merge: +# power-dashboard static front end (always on, served from the CDN) +# power-dashboard-api FastAPI backend running the simulator +# +# The front end stays up while the free tier API sleeps, so visitors see the +# wake screen instead of a blank page. Build filters keep a docs only change +# from redeploying anything. + +services: + - type: web + name: power-dashboard-api + runtime: python + plan: free + branch: main + autoDeployTrigger: commit + rootDir: backend + buildCommand: pip install -r requirements.txt + startCommand: uvicorn main:app --host 0.0.0.0 --port $PORT + healthCheckPath: /api/health + buildFilter: + paths: + - backend/** + ignoredPaths: + - backend/tests/** + envVars: + - key: PYTHON_VERSION + value: 3.13.1 + - key: DATA_SOURCE + value: simulator + - key: CORS_ORIGINS + value: "*" + + - type: web + name: power-dashboard + runtime: static + branch: main + autoDeployTrigger: commit + rootDir: frontend + buildCommand: npm ci && npm run build + staticPublishPath: dist + buildFilter: + paths: + - frontend/** + ignoredPaths: + - frontend/src/**/*.test.js + routes: + # Client side routing: deep links like /alarms load the app + - type: rewrite + source: /* + destination: /index.html + headers: + - path: /assets/* + name: Cache-Control + value: public, max-age=31536000, immutable + - path: /index.html + name: Cache-Control + value: no-cache + envVars: + # Public URL of power-dashboard-api, for example https://power-dashboard-api.onrender.com + - key: VITE_API_URL + sync: false diff --git a/screenshots/settings.webp b/screenshots/settings.webp deleted file mode 100644 index 6895c8c69651e3f9354745b1ea83d01005ec59a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25106 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%0AJ<&1(^I-$rxszJe2RHXmdI@Cd? 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 From 26a595f080bdcc738147c00a4b4e807757f0506b Mon Sep 17 00:00:00 2001 From: AddisonTech Date: Fri, 16 Oct 2026 16:19:26 +0000 Subject: [PATCH 08/10] Run backend and front end tests in CI --- .github/workflows/ci.yml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0bb802d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,38 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +jobs: + backend: + runs-on: ubuntu-latest + defaults: + run: + working-directory: backend + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.13" + cache: pip + cache-dependency-path: backend/requirements*.txt + - run: pip install -r requirements-dev.txt + - run: python -m pytest -q + + frontend: + runs-on: ubuntu-latest + defaults: + run: + working-directory: frontend + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + cache-dependency-path: frontend/package-lock.json + - run: npm ci + - run: npm test + - run: npm run build From 4a5ee3b31493c74f4fe1e04b0426522f9088969d Mon Sep 17 00:00:00 2001 From: AddisonTech Date: Fri, 16 Oct 2026 16:19:26 +0000 Subject: [PATCH 09/10] Update README and screenshots for 1.1.0 --- README.md | 261 +++++++++++++++++++++++-------------- frontend/package-lock.json | 4 +- screenshots/alarms.webp | Bin 10214 -> 73076 bytes screenshots/dashboard.webp | Bin 26798 -> 62338 bytes screenshots/journal.webp | Bin 0 -> 66772 bytes screenshots/meters.webp | Bin 26304 -> 51254 bytes screenshots/mobile.webp | Bin 0 -> 77414 bytes screenshots/one-line.webp | Bin 14112 -> 46122 bytes screenshots/trending.webp | Bin 15272 -> 59610 bytes 9 files changed, 164 insertions(+), 101 deletions(-) create mode 100644 screenshots/journal.webp create mode 100644 screenshots/mobile.webp diff --git a/README.md b/README.md index d79f624..bfc12f0 100644 --- a/README.md +++ b/README.md @@ -1,105 +1,146 @@ -# Power Dashboard - Electrical Power Monitoring System +# Power Dashboard -A full-stack, real-time Electrical Power Monitoring System (EPMS) dashboard designed for industrial data center and facility power distribution environments. The system continuously polls simulated power meters, stores time-series readings, evaluates alarm conditions against ISA 18.2 thresholds, and delivers live data to a web-based SCADA-style interface via WebSocket. +Real time electrical power monitoring for a data center, with alarm management that follows ANSI/ISA-18.2. -**Live Demo:** [https://power-dashboard-vd3w.onrender.com](https://power-dashboard-vd3w.onrender.com) +### Live demo: [power-dashboard-vd3w.onrender.com](https://power-dashboard-vd3w.onrender.com) -> **Note:** The free tier backend may take 30-50 seconds to wake up on first load. +The demo runs on **simulated data**: no real facility, customer, or equipment is connected. It is hosted on a free tier that sleeps when idle, so the first visit after a quiet period shows a short "waking up" screen for about 30 to 60 seconds. After that everything updates live every 2 seconds. + +![Dashboard during a simulated utility outage](screenshots/dashboard.webp) --- -## Screenshots +## What it shows -### Dashboard Overview -![Dashboard](screenshots/dashboard.webp) +- **A simulated 2N data center.** Utility service and a standby generator feed an automatic transfer switch, then the main switchboard. Two UPS systems (A and B side) each feed two PDUs, and the cooling plant runs from its own panel. Values roll up from the IT load through transformer and UPS losses, so the numbers add up the way a real site does. +- **Equipment that behaves like equipment.** During a utility outage the UPS systems carry the IT load on battery, the generator cranks and comes up to speed, the ATS transfers, the frequency dips when the block load lands, cooling restarts, and the ATS retransfers once utility power has been stable. +- **ISA 18.2 alarm handling** with acknowledge, shelve, return to normal, designed suppression, an alarm journal, and a master alarm database. See [Alarm management](#alarm-management-isa-182). +- **A live one-line diagram** that follows the power path, showing which conductors are carrying load, energized, or dead. +- **Meter detail and trends** for every device, with 1 hour, 24 hour, and 7 day history and CSV export. +- **Try it yourself.** Open *About this demo* and trigger a utility outage, voltage sag, PDU overload, or power factor drop. Events also happen on their own every few minutes. -### One-Line Diagram -![One-Line Diagram](screenshots/one-line.webp) +--- -### Meter Detail -![Meters](screenshots/meters.webp) +## Alarm management (ISA 18.2) -### Alarm Management -![Alarms](screenshots/alarms.webp) +Every alarm point runs the ISA 18.2 alarm state model: -### Trending -![Trending](screenshots/trending.webp) +| State | Meaning | Shown as | +|---|---|---| +| Normal | Process normal, nothing to acknowledge | Not in the alarm list | +| Unacknowledged | Process abnormal, no operator has acknowledged it | Solid priority color, flashing | +| Acknowledged | Process still abnormal, operator is responding | Steady outline | +| Returned to normal, unacknowledged | Process recovered before anyone acknowledged | Dashed outline, flashing, still needs an acknowledgement | +| Shelved | Removed from the list by the operator for a limited time with a logged reason | Shelved tab with a countdown | +| Suppressed by design | Hidden by a designed rule based on plant state | Suppressed tab with the rule shown | -### Settings -![Settings](screenshots/settings.webp) +``` +Normal --condition--> Unacknowledged --acknowledge--> Acknowledged --clears--> Normal + Unacknowledged --clears--> Returned to normal, unack --acknowledge--> Normal +``` + +What else is implemented: + +- **Rationalized master alarm database.** Each alarm has one cause, a priority, a documented consequence, and an operator response. The full table is on the *Alarm database* tab. +- **Priorities by consequence and time to respond:** Critical (under 5 min), High (under 15 min), Medium (within the shift), Low (when practical). +- **Chatter control:** deadbands (hysteresis) on analog alarms and on/off delays counted in scans. +- **Time limited shelving** (5, 15, or 60 minutes, 60 maximum). When the timer runs out the alarm returns to service and re-annunciates if the condition is still present. +- **Designed suppression:** the utility low voltage alarm is suppressed while the utility failure alarm is active, generator frequency alarms are suppressed while the generator is not running, and the cooling plant power factor alarm is suppressed while its panel is de-energized. This prevents the nuisance alarms a simple threshold system would raise during an outage. +- **Alarm journal:** every alarm, acknowledgement, return to normal, shelve, unshelve, and suppression event is recorded with time, value, and operator. +- **Performance KPIs:** annunciated alarm rate over the last 10 minutes compared with the ISA 18.2 targets (about 1 per 10 minutes acceptable, 2 manageable, 10 or more is a flood), plus counts by priority and state. The demo deliberately runs events faster than a real site, so the rate often shows "Above target". + +![Alarm list with an expanded alarm showing consequence and operator response](screenshots/alarms.webp) --- -## Demo +## Screenshots + +| One-line diagram during an outage | Alarm journal | +|---|---| +| ![One-line diagram](screenshots/one-line.webp) | ![Alarm journal](screenshots/journal.webp) | +| **Meter detail** | **Trends** | +| ![Meter detail](screenshots/meters.webp) | ![Trends](screenshots/trending.webp) | -> Start the backend and frontend locally using the instructions below. The dashboard will populate with live simulated data within 5 seconds of startup. +One-line diagram on a phone --- -## Architecture +## Simulated equipment + +| ID | Equipment | Rating | +|---|---|---| +| UTIL-1 | Utility service, 480 V | 1600 A | +| GEN-1 | Standby diesel generator | 750 kW | +| ATS-1 | Automatic transfer switch, open transition | 1600 A | +| MSB-1 | Main switchboard, 480 V | 1600 A | +| UPS-A, UPS-B | Double conversion UPS, A and B side | 400 kVA each | +| PDU-A1, PDU-A2, PDU-B1, PDU-B2 | PDU, 480 to 208/120 V | 150 kVA each | +| MECH-1 | Mechanical panel (CRAH units, pumps, fans) | 400 A | -### Backend -- **FastAPI** serves REST endpoints and a WebSocket broadcast channel. -- **SQLite** (WAL mode) stores meter readings and alarm records. -- **Simulator** generates realistic 3-phase power readings using sine-wave load profiles, Gaussian noise, and periodic fault injection (voltage sag, current spike, PF drop, frequency deviation). -- **Alarm Engine** evaluates every reading against ISA 18.2-aligned thresholds and writes prioritized alarm records to the database. -- **Collector** runs an async polling loop every 5 seconds, inserting readings and broadcasting to all connected WebSocket clients. +Total load is about 450 kW with roughly 290 kW of IT load (PUE around 1.6). IT load follows a gentle daily profile, cooling load follows a simulated outdoor temperature, and every value drifts with slow random walks plus measurement noise. -### Frontend -- **React 18** single-page application built with **Vite**. -- **Recharts** for trend charts and sparklines. -- **Lucide React** for iconography. -- **React Router v6** for client-side navigation. -- WebSocket hook with automatic reconnection delivers sub-5-second live updates to all views. +Demo scenarios: -### Data Flow +| Scenario | What happens | +|---|---| +| Utility outage | UPS on battery, generator start, ATS transfer, generator frequency dip, cooling restart, retransfer after 30 s of stable utility, generator cooldown | +| Utility voltage sag | Utility drops to about 85 percent for a few seconds, UPS systems ride through on battery | +| PDU overload | One PDU ramps past 80 and 90 percent load, which can also push its UPS past the 2N limit, then rebalances | +| Low power factor | The cooling plant capacitor bank drops out and power factor falls below 0.85 | + +--- + +## Architecture ``` -Simulator - | - v (every 5s) -Collector Loop - |---> SQLite (readings table) - |---> Alarm Engine ---> SQLite (alarms table) - |---> WebSocket Broadcast - | - v - React Frontend - (readings state) - | - Dashboard / One-Line / Meters / Alarms / Trending + Simulator or Modbus TCP meters + | + v every 2 s + Collector scan loop ------------> SQLite (history every 10 s, alarm journal) + | + +--> Alarm manager (ISA 18.2 state machine) + | + v + WebSocket /ws/live ------------> React front end + REST /api/* <------------ (acknowledge, shelve, history, demo events) ``` ---- +- **Backend:** FastAPI. A single collector owns the scan loop, the latest readings, the alarm manager, and the set of WebSocket clients. On startup in simulation mode it generates 24 hours of history (with past events and simulated operator acknowledgements) in well under a second, so trends and the journal are never empty. +- **WebSocket feed:** on connect the server sends a `snapshot` (meters, readings, alarms, summary, demo info). After that it pushes `readings` every scan and `alarms` whenever the alarm list changes or an operator acts. Clients can send `{"type": "ping"}` and get a `pong`. +- **Front end:** React and Vite. The live feed is a single WebSocket with automatic reconnection and a stale connection watchdog. Chart heavy pages are loaded on demand, so the first load is about 72 kB of gzipped JavaScript. +- **Cold starts:** the static front end never sleeps. While the API wakes up it shows a progress screen and pings `/api/health` (which is also what wakes the server), then switches to the live view as soon as the first snapshot arrives. If the connection drops later, the page keeps the last data, dims it, and shows "Reconnecting". -## Tech Stack +### Stack -| Layer | Technology | Version | -|-------------|-----------------------------------|-----------| -| API Server | FastAPI | 0.111.0 | -| ASGI Runner | Uvicorn (with standard extras) | 0.29.0 | -| Database | SQLite (via stdlib sqlite3) | built-in | -| Frontend | React | 18.3.1 | -| Build Tool | Vite | 5.2.0 | -| Charts | Recharts | 2.12.7 | -| Icons | Lucide React | 0.379.0 | -| Routing | React Router DOM | 6.23.1 | +| Layer | Technology | +|---|---| +| API and WebSocket | Python 3.13, FastAPI 0.111, Uvicorn | +| Storage | SQLite (WAL mode) | +| Field protocol | Modbus TCP via pymodbus (optional) | +| Front end | React 18, Vite 5, React Router 6 | +| Charts and icons | Recharts (trend pages), inline SVG, Lucide | +| Tests | pytest, FastAPI TestClient, Vitest | +| Hosting | Render (static site plus web service), GitHub Actions CI | --- -## Installation +## Run it locally + +Requirements: Python 3.11 or newer and Node 18 or newer. -### Backend +**Backend** (terminal 1): ```bash cd backend +python -m venv .venv +source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r requirements.txt uvicorn main:app --reload --port 8000 ``` -The API will be available at `http://localhost:8000`. Interactive API docs are at `http://localhost:8000/docs`. +API docs are at http://localhost:8000/docs. -### Frontend +**Front end** (terminal 2): ```bash cd frontend @@ -107,60 +148,82 @@ npm install npm run dev ``` -The dashboard will be available at `http://localhost:5173`. +Open http://localhost:5173. The Vite dev server proxies `/api` and `/ws` to the backend, so no configuration is needed. ---- +**Tests:** -## Environment Variables +```bash +cd backend && pip install -r requirements-dev.txt && python -m pytest -q +cd frontend && npm test +``` -### Frontend +The backend suite covers the simulator (physical consistency, the outage sequence, every scenario), the alarm state machine (every ISA 18.2 transition, deadband, delays, shelving, suppression, KPIs), the WebSocket feed (snapshot, streaming, ping, live alarm updates after operator actions), the REST API, and Modbus decoding. The front end suite covers the feed reducer and URL handling. -| Variable | Description | Default | -|----------|-------------|---------| -| `VITE_API_URL` | Base URL of the backend API (used for HTTP requests and WebSocket connections) | `http://localhost:8000` | +--- -Create a `frontend/.env` file (or copy `frontend/.env.example`) and set `VITE_API_URL` to your deployed backend URL before running `npm run build`. For example, when deploying to Render: +## Configuration -``` -VITE_API_URL=https://power-dashboard-api.onrender.com -``` +Backend settings are environment variables (see `backend/config.py`): -The WebSocket URL is derived automatically from `VITE_API_URL` by replacing `http://` with `ws://` (or `https://` with `wss://`). +| Variable | Default | Purpose | +|---|---|---| +| `DATA_SOURCE` | `simulator` | `simulator` for the demo, `modbus` for real meters | +| `MODBUS_CONFIG` | `modbus_config.json` | Device and register map when `DATA_SOURCE=modbus` | +| `POLL_INTERVAL` | `2` | Scan interval in seconds | +| `HISTORY_INTERVAL` | `10` | Seconds between stored history rows | +| `RETENTION_DAYS` | `7` | Days of history and journal kept | +| `BACKFILL_HOURS` | `24` | Simulated history generated at startup | +| `SIM_EVENT_MIN`, `SIM_EVENT_MAX` | `150`, `360` | Seconds between automatic demo events | +| `SIM_SEED` | random | Fixed seed for repeatable simulation | +| `DEMO_EVENTS_ENABLED` | `true` | Allow visitors to trigger events from the UI | +| `CORS_ORIGINS` | `*` | Comma separated allowed origins | +| `DB_PATH` | `power_dashboard.db` | SQLite file | ---- +Front end: `VITE_API_URL` is the API base URL used at build time. Leave it empty when the front end and API share an origin or when using the dev proxy. +### Real hardware (Modbus TCP) -## Features +```bash +cd backend +pip install -r requirements-modbus.txt +cp modbus_config.example.json modbus_config.json # edit hosts, unit ids, registers +DATA_SOURCE=modbus uvicorn main:app --port 8000 +``` -1. **Live WebSocket feed** - All meter readings streamed to the browser with under 5-second latency, with automatic reconnection on disconnect. -2. **8-meter hierarchy simulation** - Utility Feed, Main Switchgear, two distribution panels (IT and Cooling), and four sub-meters (Server Row A1/A2, CRAC Unit 1/2). -3. **Realistic simulator** - Sine-wave load profiles, Gaussian noise, gradual drift, and stochastic fault injection producing voltage sags, current spikes, power factor drops, and frequency deviations. -4. **ISA 18.2 alarm engine** - Four-parameter alarm evaluation (voltage, current, power factor, frequency) with four priority levels (Critical, High, Medium, Low) and full acknowledgement workflow. -5. **One-line SVG diagram** - Interactive electrical distribution single-line diagram with live status color coding and per-node detail panel. -6. **Per-meter analog gauges** - Arc gauges for voltage, current, power factor, and frequency with threshold-aware color states. -7. **Historical trending** - Multi-meter, multi-parameter trend chart with 1h/24h/7d period selection and CSV export. -8. **Alarm management table** - Active and history tabs with inline acknowledgement and ISA 18.2 priority row styling. -9. **Automatic data pruning** - Readings older than 7 days are removed hourly; alarm history is retained indefinitely. +Each device entry maps a meter ID to a host, unit ID, and the register for each value (holding, input, coil, or discrete; `float32`, `int16`, `uint16`, `int32`, `uint32`, or `bool`; optional scale and word order). A meter that stops answering is shown as "Comm Fail" and its alarms hold their last state until communication returns. The alarm engine, history, and UI work the same as in the demo. --- -## Configuration +## Deployment (Render) + +`render.yaml` is a Render Blueprint with two services that deploy from `main` on every merge: -All tunable parameters are in `backend/config.py`: +- **power-dashboard-api**: Python web service in `backend/`, started with `uvicorn main:app --host 0.0.0.0 --port $PORT`, health checked at `/api/health`, running the simulator. +- **power-dashboard**: static site built from `frontend/` with `npm ci && npm run build`, published from `dist`, with a rewrite to `index.html` so deep links such as `/alarms` work. Set `VITE_API_URL` to the API service's public URL. -- `POLL_INTERVAL` - Simulator polling rate in seconds (default: 5). -- `WS_INTERVAL` - WebSocket broadcast interval in seconds (default: 2). -- `DB_PATH` - SQLite database file path (default: `power_dashboard.db`). -- `METERS` - Full meter hierarchy definition including nominal voltage, nominal current, CT ratio, and PT ratio. -- `ALARM_THRESHOLDS` - Per-parameter alarm thresholds expressed as multipliers of nominal values or absolute values for frequency. +Build filters mean a change under `backend/` only redeploys the API, a change under `frontend/` only redeploys the site, and documentation changes redeploy nothing. GitHub Actions runs both test suites and the production build on every pull request and push to `main`. --- -## Future Enhancements +## Project layout + +``` +backend/ + main.py FastAPI app, REST endpoints, WebSocket + collector.py Scan loop, backfill, broadcast + simulator.py Data center power system model and scenarios + alarms.py ISA 18.2 alarm state machine + config.py Settings, topology, master alarm database + database.py SQLite history and alarm journal + modbus_source.py Modbus TCP polling (optional) + tests/ +frontend/ + src/services/ WebSocket feed, REST client + src/pages/ Overview, One-Line, Meters, Alarms, Trends, System + src/components/ Wake screen, About panel, alarm banner, badges, charts +render.yaml Render Blueprint +``` + +## License -- **Real Modbus polling** - Replace the simulator with `pymodbus` to connect to physical Modbus TCP/RTU meters. -- **BACnet integration** - Add BACnet/IP support for building automation system interoperability. -- **Cloud deployment** - Containerize with Docker and deploy to cloud infrastructure with PostgreSQL replacing SQLite. -- **ML predictive maintenance** - Apply time-series anomaly detection to identify degrading equipment before alarm thresholds are reached. -- **User authentication** - Role-based access control for operator, engineer, and administrator tiers. -- **Email/SMS notifications** - Push alarm notifications via SMTP or SMS gateway on critical priority events. +MIT, see [LICENSE](LICENSE). diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 1dfa88d..1a3e166 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "power-dashboard", - "version": "1.0.0", + "version": "1.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "power-dashboard", - "version": "1.0.0", + "version": "1.1.0", "dependencies": { "lucide-react": "^0.379.0", "react": "^18.3.1", diff --git a/screenshots/alarms.webp b/screenshots/alarms.webp index 796339948a8c2543246352635c4c1cf5dbb09b64..da41d58a0dc92d13f3141a59603f32727300a4ad 100644 GIT binary patch literal 73076 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 E0b#7YS^xk5 diff --git a/screenshots/dashboard.webp b/screenshots/dashboard.webp index facd7eca3f03666b6def51e5e82d290341b18595..d0aa475e0371e376c5e9fe129e2cde03ca153f44 100644 GIT binary patch literal 62338 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 WGZFdV0000*bN~PV000000002A#P*2* literal 26798 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 diff --git a/screenshots/journal.webp b/screenshots/journal.webp new file mode 100644 index 0000000000000000000000000000000000000000..329db8f05e364e8c47dde51801b4590f9a7af561 GIT binary patch literal 66772 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

    #zw*)V~^{e1AQ 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%0A|Pe|W;i zKqpVQeqV=aok@<>`GWP2Gqp4cu{{<)0+9QNOkdrC?e_X z$J+F20u--U--iLxUHJs60FRfL`c{2wAeM~<0VYDg#F4kZmlb|Ea#J1 zJnX|&tFb@61#8MlkoTCnyD>8-k@42Gm?EVJ<(8qW#o)8yl&bRcpqr!%6jttR+qV}o zc&IZ=c881CRRUE0}B#D4R{Fi4|no`fArO3MKYYQ*P`j-+E>AN!$)A+6R6uOfEZ zCD6gP=i#Dxp}d{_*DLnXV}6er>Z{MDpyVS6LGh5qDJmWstH*WOeZDHgyI=G@jXdq? zVt)R+KAAkGYH+QoE7d0P2hs_6G^0(o|CHZ@cge=GwyGlDvqqXH)}7Bb#$VP7wdf8`f?h$9dnR{mW_2Xj=_1bpsA%^y z;5X3Xq|2UV3AO#?R*CqlOA92fI2gkUNuZ{pL0)Y75H+Cde?+*}(_fd^C^G#~8ar9q z^LW+QX(hacw_B&7lx89?W8ViIrhhQRLBBMj;jCecDyR{>UG2Q;D`pnXLxee~wt)ic z-RehdlkeKJ3O272T5KB39r~HHbLo~VhrWl_aPJL~C*_I)r5YXP^9K*&*bT@0v4rsx zNu%AkWK$GGO8vh_w7dSWtnus$wMJrtWobr44xsa!U&NKT8rA4(uyY3s`vUTG1;mW1 zWwKOc6{IoqrI|W2u_N#;`k5v^)2@xPWKLTtjqPIm7jtx@20mSp#Bu!~u9i0RZ?*dE@;g4GGCPg|FZ+o4aVeKUSp`nq(>I!)iu053+z*c9Qy+hX_ z5>k+?FJ3_b&V)tHcm-pvy>CNG{H(Od_)2SSf88T1TdBIz8Zp4L@1#LPolNv*AGR8E^?XN}fbKN85DtHCQ==h5d0~dHL?J zJPtsGW?-~bR=t{U7@t*IwI3-aMpV1wbXR!bp}aJ7?Y_RPiKgrg@hhzqifn8$%dlOp z+@T;DBf-MC#Dw?BjX+%}386=ai>sPH ze(^oE7jM_LcZPXtHN71S$cTQF+b9eg91e3-d|f1EppC?YfC5A9{cKGUz+%J1LUZom z!aN1Tu@g`(DRG3MX12OrXzq&pB{$mno@g<=qNxNddl^phfi5C9R|cShhvL^^q-${y zjnjoT$Ml*pJKBW0Eh3ksC|pbVlB@CuOyUm-{doD{ktDFms|RRjQtfCeG~~c!XG~54 zMg(zyVgn2lWF05nT6jKEXNf{lQ*rI?B!=o+2f-B)lzWVX(zrq?Wz`vr&Ny~v{LUFi zsPv1mCZi38e<|r=5(cmn^SHd)Idn?RLLxFg@Tt%yo=MDCj1r12zX!W7#2#uuAmizn ziCXW}nk;(!dn0MX8UMTa3gRb5B&hJy;1n5CM6f|EueZ_BxHM}gli#vDr6XU*{@2{Q z3*|$0Bj!NuoO$2ApQ&IhFbu2ky=+5=78el0@kC}JK}p3jp z$qBpM!PaEA^&+&wnN7-yqVo8AT^n`Y!BUZZ(Ooe7l(brOq_DHc^Lrgh<`2*O<-9sP zP?3Gsy7WSc)C06Uy%cH!AoHMjjXgTjEHix%bITekHVzwM%tv|DlBkgU^6|8mc-DlB z{AIyRVWeojQ~hr>{_MypF36FK7aCtF0){W{=PN^VpdpC2$J67Q;71fGCju9~J->yl z>D^Oh#pughVVM`zNKkT6tDw&juYqBpK;ap5eVY-B5L_C{K+m3PG2G~0q) zUll7wINKpdIMiW}zwxP&+VnT2G4jG2220CKS>#nC&*7H3!C@muZuJ73pnL^9okQvIw^ zCf;Imk}4c9kY*z@jly5lBz6iHV*GfW)VVT9r#~78zZ+p^wUSDJW0SPshrxw5DO(Zv zDAd^BOD0)cmBk9D*y;PyQR4iI;KN3ot zHvyGYj&A(38-OC?;`1&Q>=u9{IY#9rtKbsXO@bph1}l$xVb)OQjSIoy3_2v?gi%4M zjd_zU*AFj@WYl}r)I`GA97y=M!Ub~WUxcWj7O%iql2KT(WQoMc1LV3dj_7~>3&{h` zF6Kx>S)_^S36H~|z(}Qw+M6beC6T?v$Vi51vf`s9A6oX?1A$pISV-=Y8j0PH0jA;+pn52}XODe{Tr zZsbuB)xzQEf%Xgdi}i*{RvDHyAE;;{UDRdPyw7}OoHN~2V66|#dL@*!rP}Tb-aB)R zUCWz=AR@^=azWRwekn53a++E()3OokG=8HqW*2mfN}t)px9DwZaYE57heUJuI2x#$&Z!}g29IafkGY{Mn0`*WGeP37)`t{VI0kiUPc+2{}bs_oU0(EQ6MBEBS zoWW2vcM5@I*_a|wI>dgKFtsD)+zvUm#zN?)?aqfYa!CMQd>I@ewPEb;ns-!px#qX zz#6VR0IDMQP+D8!T$pGL3S%CloKG~aedc5OV?e>V%u^wl+?d86_J>7EP|IfAt1w>- zxWIBfiJ#aY8hLb6jl-Qz*-4E}a&{L}UEf{dqyJ?gTIlz#_{PiqN+0EzJ}3=Z%vekp zns(X&ItelzCkplgKMOfon9>8MS&YUCkv-6wlCfJNYxX8R#uFexBiB5fX2hCPssz7GWP z&O~&w2tk#s8V3)8H$j%AuLG0Rx?s(b59+AYbfJIB@8CoaPJI-&St`AL7<-?M;}A3q zk>Yomx0_NHBshsZh2i@KrG+;q*VCuxz!sM4prbD=!cz~!3>3!U{OWp{3wRi%$|#XX z90NSUaPWY<{Zh=}&r_lWW}+&TK#yPD(3CO%PQomu@#mynH?Uh|WJfdps6Q$vYjsKv zKKrJ(4)zGf`@~XWWt#9ZT}ozq7(EZl`S^k&0T_0T`I>5202SxPUM9>s7dDML3AbEQ zij?gu`@EF)O`^~nv+2q0;$g6%f;8tV@Oa++U7WWS-tg}Li^IgS4_6Abvkl*T7&A$N zf(5`Fv$F*Li?V!Ffw9o9-FlD3u>v^p(L&1CVAQ2GCQSUZIj^Ojx51&5GOyeYyqRIA zyW-PzP?-+CdUFze_g#rmy@xsVHC0;jdS+5?84spMXHfleQ3c}c_nZthFB*v8BRmcL!gDyt`)ecoGd{L7*ue@#{Oaa1q>1@D%G zgZXZ9zG_{Qm#R>3qE`yW9zdt6uPx);ntO2w_?29zF@4%q;8pfgYZ`+Zwf?9=zw(^Z z?xcJnKpVfKdu>t(JhHUUQTp>Z_F$A{5%iZsVsq{N2oL9poK6iw=npbZi=PMLn;0)( z!kDqXznx`6FE~W#4>r*>VzB;I6s(v=ROm22TsnUcljou&#Ba?$8lj#dxkq}gs%GzT zK|n5W|A*POxl#Si^Jy(n8u_AqXNC05s#Q`zzrl$s=NxLn%41C_ZhVjMQaoBCTfv#q z(M&!@E(JZ~4>PKFZ+oP9lFhWh$!@3YMS9aMvGsgHUfRafgL8Z{BvxBJ`03rW^ zib)lfc2`J|qpD)mq9U>GF|(WMB>-1%Cu%m+B6Z&o<3I}*TZVIt0a#twpoB&E4r9tt%VvmNd5F{TCazqhcM~-{n-(Fp(n;zm;+w4|14* zGx!_hy#AT^jA}pA2a2KWHNWYD$dtP+0nEum)fxQkK1idxp623OxLpzpVsc_FXHk#r zc?qo2a0kaZE29<4(Z0GmZeFW+pZO7y3ssT9pWXb=glL~iwMJprnPzrJYsozF&(|pq z_Ff1d7ih1;lc`^bu8GD%NpNE_P$Z5l0*_v+C$FJz=3@J#(ncbuIUY2KEb{Lk6D*fd zv>CNM86QF+j9lM&F<$ScsEP%a-_33T0F!-$u1r? zn?6=4X3kUi$Zx+V>2(a{7gZ(4DS4Ajn38ZeO8Bc9VB+**@Z~vpX94tUo;*TooDwT~ ztKh(AS6~oD)GXiu1%Hju*?c$aF{^902$DMjoWa*Uzye1UzGSkDrE1cGf6pX(pUPX) zhRpd{U&X9hh1SiVYrEl8zV=OMU6P4twlqapiCa)?!{lzIcEO>;1X!^^EMp1 zgI&zJ8fea8VF~wEHF4<%BPZ&OWI$`y@&5OtFrj_wcKnd{OsJcHe?Vh$6i7bE!hslF zXoX_o*7p{UO_LO<1xu?(#v<1w%EucFq3Hh=ePn6|q5FD#&Ro7Sc9Uu<%1^L$8na@u&Svsa`Pi1?^?`>!@k0XM+|kQRN&#h zpQo}JM9TApH(d&d{I8n?^U=mj<=`w=5Y>#RW(0OI$+AiCU#q^w8=idmrr@fDyGg?I z5;QGXHM0eS+MPv~0lzaw7xhisCQ{r_$lcZrGC}6bnh01b-e2`0p~#TqO|affEGICE zJW~xd6@wSp#?D>sT5}oqe7|JRQglFrGma^GDkM4qdXJhp?;qxP_SsW@OrC-9gdP^o z;3nZ|I4CXb`5ty3B*LBIX*J6iVxs?b5EtWOTDuk{^*Ct*+h zG;_JRGBW1n8|qbw2}`ZH zofhIOeZkl@B7pPq-3Xpv$GWPu%lCb~c@PhOT=mgn$tVqfPu&|QLCR`iR^P%*9JI}M zu8s(7vHK$YI)h*=DG~PmC{0rjH@FY5T&T2m&{@ zrqie?j%pZmH(2Wm6I)KqfkFba3y%#cpt(h;gwo}d&+@oQ;gibY!~jSUDtComphX|s z$n%VKaO9Z4hRREzs&5HLX_YuT5%3S#xaX(W1GEQx<{5jK&_u%;iDihq4^%!K-zSX- zJ}c7tBGX%#Q7Py!@=_e{x7R8D?zOwtaAUKIDhH$+^I&*f6PjNVcXBzD^NhpGHG&WP zF+U@oiD<~pq;>OTCks#fYX7T>Y$HxhO8lQ28(HcK- zDkhK~LK3>sYTQLt2-3|BsSOj{A#ZP7G8Q9v z)p3MXr;*g+XfB`|vhQf56r6q@5J2WBX8C$3Dt+27kh?Ku))LT2h4J*vdUsZSGQUn5 zz*;7|+zwCrJMmKTA*%#7YXu{qK&?jhXtxc7snoYbe(OJ|%PL4$44H(K%{$$vT5+g$ zLMZ#CHk$6=NlAol6{Ka>$X&@;@bUx?^9Z}bWus>iYJ(=Mm>!S$Iwa;@wN>Hq9CrZ& zSf7UY-d@*8)|&sv<>X665E{-0vt(wPGDF}fKYPu-1)GCf9Us25@SA!L%0QeT&0XH- z3x~(>V#Vw|ndYgu*|m5O(~woyFu+Y)SG z-pBv|mcf2)r+zK5MI5$xL|H;|`sa^Cpy!q)NJ7F>Y0Xt5Y{y19L7NsZ(8|aAyV(B< z7#t8S>Gxc~?j1J7}$#C!rx8qCsEVdB5 zV?zmCuKlK_r=YOzk4zYSAt^L%Z1y#B(V~ioyOZ3?ECn#Q3ilIjEA}5^@v;@;>nxT` z;I~6EKD+~7KxShUT=YYmTm2W)r}B3YAbBQ6T9t_1T1dcJPD`lWK-L=t2`3^ky9&Q{ zbIm_lT9U-b1w;yGCAlYlI4;zU=e2(ecmYN8RJV)5T1WUB9JK`mRuP56FO4#;mK)Uv zZGovl@~9{KL3M=b{X_0M^foqv-EeVZw{^Vv>K^i*a^Tofp7OgVZ{A%qP6-p2;arp$gQ>WJA7n<-%>K!)TIdai zkW(zYQ`_aJZiYVmkv1|tybFC^MssIWW9IcqXGyAm7+{5x)C!iR^PuYKF?HH;1lz1Q z5ld`ar#LHRdj7cm#)*C|(YfmSf{E%EDD}Ng1^)bSldf6z9RAW|n`o6hNQoHjscAbI zWjDccwo`aR=$9dESLExF#2%dUp(YnMp-N9xJ)MLHn#2OhHeq1&e(pno3tWNNRYKr@ zzd}n3lcF!|6HfnlL0B-AuRYBt-LSA`R_Bf zGjFtP&5w!}T|+&yYcF7(srmb-raY(mia=Dltp1BmbZP01KZs-yHBVcS+3z zF(=&Z8qA+wK)(#e<-$*N($1P>sk>3B+4{GzpTx)t`VdEe`tH=J{TXQPDDG% z`C|lWsjs?uVvR@3>lVCr5kbq}&*?lCtx4GG{w*_fDk1fGkyCL<+MO;Ws?-Y#sCLD! zJpq90gW9!^5i=NxNUtcVN5luH*R_ZTVCBL!y;KC-^@;`D7V5sNhq>pM6@C?lcD(@# zdZ!qez!}OsPv?m{RGrm8008hJ(4M!5f=y67coEydE8;1801GlauOsdJLlJC{d(yM{ z@6RkQ0|T~l0>RRU=X4Q-5c6y?oW|U67vNg{O@3`d;G<4M~l{CMe-qd#SyrNMS$)lKUk? ziLA2Mj7eg!DtHslKtm0L?_I}d-^v0Y?rfO^z2syZebo!v_8$0n@X0;Fm_QmnFU4!- zobGAB`_-gwE;q2sTeFubyiG19l(t@tjse|1q6(LXZKTaa=q90Pcy#Mmz5b+>z87}f&)fF(a)66b4 zj)he2-5Z$?KmE{u6bRHbno+BI6;dq{WySSfNIm!`y8+P?F>f?s>ft@uRA4OkZ7V0^ zujDp(ZAU59vW5A^QrGiXTbKl4KzOgt@%y2Ct@q3&hfZGis6pG6R@XxN7Cuo|}O5Bf?_TiW7ZYd?M?9Tzl)crR?w?2K`i23wKMKE@qlQAdXDvgE|$fQ z{hp6)jQ&l5%VSCm|(8ZSJv`tHa%a|zPes^MASV@J7KP8tvrRwdf zhJI=j%6(<4*WfD`6?cLu5Oj}QR@7ErIp%nR9+Ni#Y=}HN?;&#EV7uy<{z+8>d}Qkv zxX+w`&}DNba4~mOKhUf!F8Aim;%+R|xLfieAuDpt@kKZV4Ob4qeDUk0hBhd)% zeNM#HLlp9$>guY+eA;>|Hl3~tKUC0&`BjvH{DLAvy!=dI=mrcfOu4PV=e^>EtMyJ5 z2uE`A*g#q9#+k+INRV+6?&E1M4k!*>F~h}NO; z+73GiVrUPSBw`W;Di#^CBiV{0_#*FKBIE1qJ~&tJOqWuqK0n8ekFY~3#HlE;5Kq4m zhg`BU`SK9tcCsKjL2Kadf%m?yuo@zW2&(b8P@ppn_{A8``f=!$ie5yqGc$b_w4J!UQQwFTp7{ZkBnK5OgC7sK z*@sShqy;_}qb}@*=4^>$ejg4XIE46!;zMgUdNbkzMxm^4OVn+^RNkBI=pUG{vUkZK z9(t1@8#wCEAZ;kHBNGe@G0~&a^^!C>PdYXkU(z&7e1#6V2Th?TgSl>#u{?7po3Hn? znt7{ZLU)EASA=bG=M_z7p=m5;}ML3`7HYZa(z1~RXZ6P*2BEtq=UIHTOaM5tSj<1+K6L;A!z zJ+|v@Q81~S&-Bc_`*v!A*I)G9jG}$)(f;2Taw`8+I%Pu7QY86<`iz9zSv#ie$0a`# zNo>H+|NU`}nL9wpRWJqCZGffSIk)+N96&R2nW5k8e{4FhbP$*{F)Kqey7E!8Zzn+> z2+|u1bh$DxBgX}QmlJi^Pe71B+IZa~iO$Z_ORXSolk>azarvke;^c+0FWTu{JaI^ zl&3gRA&$q5rU1CMOFs_y=DGW?`gCr1$5$iMPHcdWc#1d4$>V7ixc~3V4fGa~g+409 zRV8=6qFg!;D1MlQO?P6{JHgu<<_bu8J7@W*nili;%auO)eVqA7F2+B;va0Rq5u|5- zPOH3ifB?CfqkW+L?biGvZcRv(v^9|mn)`RgXzt9(Yz7}XS9-%6O6^gpft3M88(67| z?kid^_h_qXC-gR-^D1yLmSN06HFuB2^5CyX)-gAgAPwC$E6MWpSWiFMD+R5TCI-M! zVMYF5$;-hRITELy}x`Qz@l6R-IA>rdxJ~tVd~yoSP$GWVSej)Kr7%zt%Zk^v$X4 zq7^wV=AR0BmqpG6v+FSyL2@jA39Z;F0k(P<%$*^l1Dr>7W|J3+P zb%5gDEaoC)9k*Cafs2Ky^>$PUf`^cyM!ez zO@fE>&$)2oZPhnN#=!}*n_(A`&?;}#tswe^Jn~qcAHiy$2b+TA^YU&!dtWcq@J&L+ z)u9fY?UZ@@3>g#{T#woy1J$nSRO?!MZ!aqWvwFVaLokX~*_d2m5BwS*zi(HgD}@xj zh-FmU4r|f*XkxaJPf)r~8K(8CL{hpxrd}7P^ldR@+_xDd4g<7m%rUr1Wz$|JL{iR7&VH z%P8M0WT2@n!;*t449%xCnR42w+yf>yhvExQ^79xGK7e%MsXb_GxGKdbGBo(za#qAm z4V_$n-Khlx`&UH)IV=eZKDl5NicF>Iph?I;9hdrMcq}r zpQOpQ_(CH1{2;6@E-jj$lOwz=A>W<}&b$_%Wx=spt;)nffaUYR zDV3=4@=?&6NmgUJwcJ$G2%$>mu*c9lrx` zvtNiNXlgnP`5N37WpB3>Jsi#Lh_}zjI=ko!*{pN7_pk)@OF*uj{|&_ z2>PcnijH$)7^Ux_I1;3St|M(5ylEsdr}vl>J(&6(F}EIs{{lFV=kAadUD!Ij zHXkBI3CH}xA8%HP^jUZ}Cb}8xKB>646Dt`zn`aPXI)&;|X2||y>9}*Z7hy2o1FJ|e zB3qQ?5a3VuEskq`{6BtF?b?WN)akAMlF#5wvNGmuz@pRBJKxFCSH07i&|@QTOTEit ztJ>ZtQ;;j_*Qs*6X%ZN4C$U!R&Mu7SwzE;iZlB(yJ4YQ6Rn_$p{YoDBzoAvG5R6vw zjGI+0BgrLjQ!2I3rE#R~%dc_pif&!Qmm*3$DVL;e@_V%EzJwp`C79Xs@j|cZ<(*qb zPTO{jm?N-(d=ATARG88|C?Ihu9}kB@wF!D=``uJ(P+>^OUJAq~U=pW0Ol%SFfrKT* zoXp#Q1HD3ZkX?q@IZ=Z}oGHF?J&&lndjsL%@7&g;0){Yth^ln{&WOzvcNY9%0T z8p®Y~d`4&pJK8EUx5-gIwvV8iDNte!JzzzwH}6Qozc`n3n+2q3DX8j@vthwQbA zgh9zAvLQTmuN1|vMjfKt4_09DPubVS1h}){LANc-bDqYmE^O%v}8=Unpi@_c4dG%C5#>{2Ez=A}ks0IG;uC@2fo}xwRK19^#ON z{|!ZicmvD(B=Kpb8!v+igB~=oPn*%Hq5a)s);lmSHenwWJ}XW^ZUdm=y+kiK^$xto zdeB~*SVwXfV)J7{0Q9CDc_&x1_UtJ6tt?1n0!*josbio71^Umv6zSfgNt)chhHrw0 z$8l?$%>*NLjq%}M(QM-S8c!|(XkbC++PiAoTbaXJfL1oaU}UnySk0} z*R``%N{*#6ZgFN68Z7V_b`a)s^3YfY5KJ0q1?Cf^`?|E-Db$@fD1xNg0hj0m!+fwN zxRMe>l$q;HmSO`B`o7PSaSAF~m#^znYxE_6$psU)q0)~wW#eH1P20xw^ZgR9;p474y?ia#0JY$0A&+u zL-{gfE7r!WZA_I06zx3W2LziX>kMgnhDu|}RqI3yxo8D~W72FY^P^RoH*t=o&-Pz~ zv<;7uvcr0t9_PYLAQa1QX_}LHGWy8;V9Oqqi352+)iyGsIfytJYH`7Ue0?14_k(_L z8cCOjWijG6U5+>?T0B!Mv7pxg6^o_SKn|l>y*ITksl{W*&gE(agk`Xz zS#8wm%(|-E(8QA>T)8B0BRN0xkb{ntGPV(Fkh1PefB*mh0000jYwzf3%Uq-BXn_TG cU+BGu;DHNinBE8wwwaCKfeUGv*#iIo0F$YQ2LJ#7 literal 0 HcmV?d00001 diff --git a/screenshots/meters.webp b/screenshots/meters.webp index dd00d4c81fd18d7c122e6ae950df44a751543da9..a316626b1a4f305f65b63e7140091377438aa29e 100644 GIT binary patch literal 51254 zcma%iWpo_NnxvQ+EoNqBi!5fzV##7=X0^~_W@fUO*+Z>y3e%Vxc8+z|zwKW8KyuaRz9j3h5y>)E>M!m(~1%U;x zkKI)FcE^I(z~PS_ucMdOk2RptJo4St1<^~_oL4{K=X=GY;QP=!)4SfK-u_P^!BU_# zaO#}sV++{aD)^{(PxL0x3&;cn0J~0;ULAmf`@mO)H@$T`|Cp7S58rO0cL5>6drv>l zzGu7J%Tv82fDy3aE&3VxXlo5n4@dx-k9 zH2G?mhbH`vh=us`YxsCK7F+EsO)9#5t1V^!;bC#%y2y4>J4gj*EgNxjm~`5sh$E$r zH|T1z8@`|P8B+*NfJd;7CT)I zAat}|ca^4jr!j%)==ri~^O}9(MnT>GYlx9j$%f<8CE|$R7rk*rNSV*Bq52i6 zGcbYUf}GQcOyA!1>))sm&h;KDY+9L^V^u(Z{5)Irjk&dyt_~1*9_!(O8Dd=4-p=em zPYH0mlK%$#yUCr33F6@YY9ifS{_iFl|G(z*>$i#UZ6eQ@Vp92u1``uf#acPurMej^ zUT2C(_pM}j^jPA6{q8NHeGV(?mT5I5;X0@sBh-DUWd}dgFHfT7i!8xz~H(!|deSzEt zznh#}Y0px4?gnsG*|R=F-GhlEam)wPEB>0Y=e2qo1*3@@>uS})0qe0;vtZid zD71)1l=AcuV(itY-o~hgeT#W?1*u~ps+cjDc2?)e>Hrd(srx3R4kDAFg zpj29$P6dU4a6>kq^>Cr*3~(GjoP_`^z@h_~bzX%KMp}d2(C*Q2s{W7#p_YXM4Ly(^^N3Iamv48Dk@R zpIyY;JOUV8Gbi%I3<5;47NkSuEz0289c-8QmS){IM#%W|SzO-1&&}eUg$gd|LXRw7B9_QF>}ou7{S!sJRj0SuE%NX)QANF9zoMzY(lkJJ$3M zg0q0{&wqUoChMQaxYI1}#zhW5IC!_q#yAR5!nLQ)K zKOersTrcrSXbded|t56pV!$%&V*%^38Lin zh`wAM0l%F3zF}S~wQ8yknT656D!Kd7;Dm(0rSEi?v}&iUdfDRJ>dLa(>|6{A{B_fR zSrVoIlwWihgDat1E%+5PUjrY|;9eQxmgu~g+M{dSA(WR)4PTjXv>EevS*|ur2FoAm z&xcvtVAS95>MsHo#%n&DwlEl-C(p2oNTwc53ckt{Gik{*>MwGih6w_f;2QkapExU0 z4bcHl*8Tv_q6-Twq#;>NRSR^=xTpU_@u&@P--+-pww1f?H36RZ_r&B;pgn^{B0m{S zLw>VMI%zh?qv3s@2hxTq)f*x)Y6x>)_uda=d()asVx;5sA1+xGl)-RRcjle@SO+j( z2=m8ENyHR$Cxp-m1koWmIKsnvbl1Lk+-Xsbx-IAQ3l63!U!n@7xj5Q1aM zQ{m#*e)Dd?R?jOd)fvw({4}uWw{=q3NQ&I;9 z2;;+?$tB}xn6s5k?{}hDVWEsbrJM5E+fjKBrYVZ&{qFxjCjZuCCe_SPRmZ6=m!E7a z^{Yxx7dD6CD~xxc>L%go5#B$`XPdj?(p+xVdHRuV4#l~wW8ZM0)D*q zZZW7+6)x)UQ#qs3HR;{*1L{j4{Rn5^EU9Uh`#;7=BjsEy>5~2+_+P;E55E?HxOPjW zff=GW>Vez(Rmd%W&fU;>9!i`V!D|A<>T^5yu)~s|ycVv7s#+FKDyYyizSJk~rx5ye zL>3YKuqyAG4h1bGDBOV8TPG(B<8KB+y+uT8`EfeJJ9uzDnLb~S^<-&0Mru;uyJNwR zQp~D0iV43UQzmp6j!2Xf3p(0n8uhCuamHTZZcJE)m;4qDNgn>0t;4KTo&w~!_n5B1 z=Lp4BDHcIq&Pcb*YkgauT+N8f#N>3>7&}aJqsGaT5ob1%@u8pQIftW$Ky-z#k%qsx zGg8uDZ3*^~_b@mK?_YQsTY#C94O!m9`tE_fo3l?0f$s`r&du#qTgkz7r2tM^b0{81re^Cn)LCd;}fk|fU;eQ_)_qZ^hlf%Zd1qq|6v75KfGb;>4 zJMz5F0n_$gi%9+a)F&M#qM_|rY*f#1anXQkbE9U@a~%w0+hft+GS36JG*B*HLSKH= zyhrb(VP0RI$q;SLY!2Db_h|NBMsh?lErN~?|IJL9opsR!v16~O6pWg6HE22ragIr6 z86ATWJ4Np3dqLAsWae6;3kU~iIucVskl{4xM4}>6bqMr&vU!cf zia9Cbwb|oI*Z2DV6Tui^)k=%cl7d;!IWGBy11T2O!aO6Z7*;5uCJcMwn7)+~$L4GV z-!+o)wa>Hyf!@ah}EP z-J2Z$0 zS*zZ2_-f~{Efbznnbe#H}=Gi zf^@3u&rK;vmY^oNfAP6Y#iHD+fAOdeU)q4i@3VCU_!xdPj(s#i8C|*tBlIcJ|B}zTw9*~&10IY91EI*SgU63I zdx$2HUIU2m%MSUkFs$p`seCW~II%+?Up)F=(s z8JRp~YzVU({!4SOS$@}P2O87fBHA{q=KN9Xms<|-2RFYckHakRk-ByPVINdaIlHow zg&3>UWR8FPEOlVv!GSa=@u3SN1P5uB(0tJLEpimI9ttG#Z^*)RJ0H2!sU4s1uupH+W#>@F%G_jMuay6I@ynqp$rIT(D-Q+ zgleJFs6nP%>rLS|E~wgloNA@GY17t17hLLo0&P4tTK*4oGhzS-1tAzkHhUgiWlfjO z6473@(%-esQ;1e;-)xK)JWi*(!az&5GY$g7ph|z)Jyl>&3yW(U8YG7G5a#AOvJO7J z90QOfN*EB$T1R#8v_)8FEDOPl#pnY*#XyVQ7LdOs!V?Dd(D$z0B=|?T8P4Qs|DyXz z2e%yvfAce;uE0=^I#5@$v-`p(Vg` zO<^?#y!VVuER9?T2swVjrbuY_nOjLu2pq|F1H8Le?lpQ)l@mw5#b9>*d-sUIN^i(W zaO__mk%AKi`qkj1I1!IU+TGV%YijZ@yT`ejJ;@xxeadP0$L1*RED$geDGFZyV*}gY zw)ln60#&L%`2W75b>8^v-wsT0DaK_DEIxHkSb7hvoH^0XPoiQFQMe#$<6>Gj0xzgh zC9zazEYoa%I4g7E1$|6^hh_GU&C11XK)y22%eDHDsmX{;h*$O0n$mxushUV6`wtcm z<~qBE1R7QAavTxUf&wvf@Ms>>NJMtTpvv@D{Wv(pw{@aA&PAl(8(vpNj!4 ze?kp0={PE*_jXbdDz}|CNUQ$fbFjL&WgX@ppx#CM5bj7;q>b)5K@s&3nK}$X`3uV? zb-iJT;I{$_avX!#z{zoLVkF5yt$WHKq%UcHUnnAv`7LXGy< z2GkdgsK7C7fNOxD3~Kp|daZ)@-!a2G)}O%Y$TEK_jofU^a1^zHWF9a}oTy@*Yi7u^ zo%{7x240}xtV#hBadW?V0Kfqwy%M&*SpvG=HTat%z5Xq+fB@$T2K4~hxyDa}oFDuD8VzK1wHJDhTE#W-+hTBE4~qblBQOwi znwp?Zt8YWWhpI3_l?Bd=TmQQ&-ZMu=uqa3b>ein`wynkd#D2wYk6<4h`8(A9+rY>V zIiDzt5>d_K&vqDR#+T17{)3_a6$3$O1bOPBEc3(vV?G~Y|DHBb&2%GWdtP}d)nhBc z{}>(pTbiV`n#WtjTHXHXubDDe{<}&^Lo23akN<1L@^7x_PwMh7O}tDd7ufZG8#@Qg zzX2H8|H1UXLPio1TaF)33)>l(lBIeaXlpxj5cl?BP{~4PjV|eM0hWyUf6UWs(BFwt z&{xZ5#c)MiLNHDsO z1H6*qlktm*tEA{X!B+aw4n*@`6Iq_#L9(l!Yw%db}gNt z8UE{V=}}RsaXW2p{Hb)@l#JqtOOfPJ>1Mf8aM^kc$qF6dn6Z;LWr7i(K#_=o8?ygb zamJ0o+ArWLK8oP6Os)tp_3z{iK@wp);SK2P>XCS(N3fn52u<)%8S#zDanSfgNosYY(dhYQ!#@Dn+Hl+RQeyZs`x+>J!0gfc>E-f*-R9NE^D6`LV0|0mUiw>rbKU?^ zRvQ2d&#_9SV)X&PPWH1I{mF~h8y&TH42)L!#k9on?_WPM8NhV&1Nrz+K{F=a3Nqd1 zoakRY`pM@9^80}07+hiq+BeOIJW@}7!GYt~Qf@T142}(TEZQ4?Ko;^IJP)koW*ryd zaSLgFtCebBG@FHKCK{B_A}*Xp9DC=beQ1cE>8?W$NFp*XEu61my05fK(!hI>4O)tW zf5=T8A$W}K88}=HCM??&qK6i1pih%slMC%GF?jvBg%s??VakO+r1+3??2Sz`Buw6a z+g-^X-%UB%wMvC?oxu+zWDCmg&jN#!Yi)Z!ihiSlt|jwVF$6t;!~nT$wBF32=jt74_40%-rYf)vU3o=5IJNBa$7RS{sz`BNO3#3D{H9~cY4C<4RCPe-Tkp0 zvk$K$lFAq)^y=4u&pJv~g*h82;XodRYr7QQA~by7+(V+FhR(>s;zwmhYA!-!ocwao9EpykZ z@iZeV3I$h#e=VV@dTOZGpdfCGJuQO*QH!Vh3&vtpPz2e>1f~H)6f#wifUt`Ztr{cI zx^`a6dT!(3JWuk#cE@FVBrMrRye$a2HqrCkWR|`8%dc7Yz8ey$x&|14ex^KMZv_~U z*qwR$2wk!=q$sG`A+P^a2HJ$$3mv=6$v5i4+{!BN1o17?i0&9EeY0l?wc7TPG24t1 zt#j@7aaT5*!%v!`5^Xx3rYWjg?^qlr5-IJzAJOVr&S$q*%Do5C5Iab=1dp3CzpisE2G)wMxlp!1gZn{+JBri zrTOy47~01D=)}C#qjZvWdWT|sul6)^w`TC`KXLHChkGBASrycFuBuYtlJpGnL9Z;n8n|V(KjlmTE?z>#Z-g+Fq+!66c@-hXi7UDOAKyUt(ETo+C1gLoi4Dcc&2zP2-03c1S8?| zph@u<2llmTo@+eY1W>Qdd}6-NeCq5UL%CdV!!cI(Bq$8c*fWFgE|Q{hHrUt=Cg;wap&k zXy&aKdAj!8jSwf}h_H!W$Eh*?S`eNZrrj_&@ceCHG>`9Gv*O*VYzt0{lBL4CYEw{tDLSEw zXNK-uXZ9?bVusGhd3KEUce=ki7F7*mXJcg)}eK>zo&K^$*Qq9o62_&wt#gzod6)4FhH|_~% zLDm+uecK7Ld4W=U4lc&M!^}zqpRrZ>khv@8UYi0zGIlvxEs?78DyY7or}#mGu9DeFV%(AV z)6eDT-(?tWhXODN?jcK+1^sv~RDL~OO&Z1=Iw4Twra3mTpo@|~nv{sUewR-2j;=S3 z!q%94D^wQ@P=;Zb3B2a2ETogdVK!EA^!ZGJPyu%0{WhuMEep>TCaX^herU4T!*Mso zy0DIFnf7~C!1+yk&N_8t*Zl18^7tG%PhBSB1pHjIhLqXe^pcp;?-~2p_B*L zdzA$$l4@TY<70I>Gx=TNvGZ(m!Zp^VJd(nG6;w}pV*3k9me@yUvzexTT{taQ`(-lZ zy?M*TeOXY4rgIkA$@S|7(fXw{&=U0x#J?gEb5Ktv1`Xx?d6LS+I7EGTC2X^2Hjl#i zn-o;+wI?E*$R3R{1|2JXtci%TOcREWvxjza_W!u_qYOOqOXk z7tG-IJ;+3N8Z{*^>LHVgYeiiKrnTkq?B^0{pOpM(!*#OdW%$r(wo4k1u+d>9e>L*d zhPUPQO((e=-5`K8t&*}8O^Ro`;F~|Cl7WPeJuc7(w_7d3NEpf|55pIuGpfDrtB#!b z`JK|ZTaasR>?hmzHJuZ3MMSX2em5m4KXWMm>CrQz^3#s*IVOezUtUTmIf>`aqP?#g zw&iWLVva>K3Jr}#keX2MzKn{*aeXMiQCPeYN;PT6ecnk!T#G&qy*op5Fb+Dxh?(QK zvtFtpa9XwvxT-@O7-X7lPitxu6{yCE`KoOk-k8{t(K`pZXm%G#8|cTQck;UorJfL|%r zR-5}fExSS2S`ofrQC{&jbe~*%y(z3gD|ZZEm+QRwDzdh{9#Pv;2e%6S6FJ59e)+Pj z0a%}n+r|SERTgetD3UfTEQ6QxkHpxqIy@0U^ff*FWjb9(JZyb?kYt%RyQ>FzpECuF zoV>_<``DfzP@YUVGZ7(WuJbU>4HOo1q9Y+EL$e2jcZI8UWiaAv0lM)FGZZ~+eb@-GfZ*E}{Zy%rzws89PZHFq9|Exk3OWuXOK z&U#pMMN+_f)TpV@@AOLwR!HI5@!uMn!d{!Y5cUOL3@KM1M`l<4 zA;X@d^AVq%yKvn?--k>{XiuHC9uNm{<73!go;=`(O>(DNH5{}u+;J38*7M%%qxq}l z9&(hRfSQn5!9`j(3OzHbg2++AgE3pnZU^Etg@yitawoSR-y8YZaJZbzoaf$z7!>*$fev1)m&IO9d6G`Lr z;(#yiJ*~$Hbyi(GZfN)d3&vS!&tA&UIdCnvsTkcsoNPG697|t?Zmry=hz($IKeWQ$ z+5P^{h;H%^ug#OqtyqDrLQ6|l+jY=cZBz@jJN{#ZQY->P{E`blfgMS>80}@?RJ=x5 z8-FEKFHk*dGGV|8CHjk*awGjk!Po5!mughZ!WLm-Ia|y0FJI5BzHE>@>bSU8CcW+M z;9-_FFmRYmIr1QVFJ=wtB~y3>@oX-@L4r2I0wI5-hf+B$(Pz|+wnIt#r0ZudRsXr{ z0fYP}DDJ)*&IWHv!&?u`_FCfMB&CazA_xd*Fxn4IA7Mg=)VoBOQ@KuVHPquTBzb*L z?F3GwdM@kgs-Kn)YE@R6fgmQxF@pe&!EdUCZGmTJCUUaw^FQnH#a-eg0Tpu9^w~RI zoH2|YdF^V^(4P238rh1tc5MjJRbYr6mljq^=n58N>!u-5#XZl5BCLBk`o@r%w8h55 zW@7Vww!&H%L`0wk#}oPampX=7vFhzGkc*a6z+ABkYw$7Pest-1l@&3@IVdlc@`dC9 zq}*;19kAdzgLM+nM?8w4982UH@985cXxuOl>$~w_ZV3pAEQ@Cj+zD+&*wS3K<(|8R z4)lm4nxWgbVJfwl@Z4*@L%c&DO(H(9wM5q&P|WB0M_AkXIa70yHG3Vn3r&so$i{88mgiZtIHj+8$9o{&6_o~OTfc@OY4m6+V;CntiB=$1@8ukr7{9Cv00X&G@hiI$g=9bdPRNb+mK@J85A*# z%N9G?_ZrLOz>6JwGsEVd?TWe;iqUpz$7MYEKD4{|nVZ7@;xcIp$hk+bSTOeAUC?}I8^l$<#-hrj%}g*#V2NY!~(`l=Hr zwuE1Y3-WLVJe0mrYFHf|&SI5Yn^RWfU4}@Y_xzuSi_|;qrAF?89W5dVP!h1M@;#2Q6 zQW|O%Nzyrr;|LJqJ=LXQbPu$2xZWiS`sq;^I3>G5GGfFEsP(yUYHOrSoSO;J7u&7X zlt*R95q}0^=n`xx4IS}C-$BqPl?K%vM4sc!UB{y4-X|5H4z+$-IX*7b0n#2}I`62M zu(@Q>Osf6}d3=cPYEbtt2h^ruz-+MQTPq>$^i&C6E~Y3VvGPDyGivZ@ejx~okyL%u zwe+%L47<+VU{`u@H%bmJ+zXY2AB zNWjzk1#0IPd%+3>T=$taGQgML1haF{87*R{R=uC6*ej~k-<=nzs@99`pdANm&RXXz6#I<=5QL4W4QFp=$tU=bk^8puFfH2ch zikDDjBM(bBN!Y^hBmUVBfW=+edne)FwW*r*2jGz`fz`oyC8$dU9A)ZdCyNDSpdhl+Z#QnunL;8({Jjv z?EK7cEJMe87iRLH-p;c`joq(&^-Djya|f{@>eHv&y+wZilrQ_Yq7v00o++e4_ia_+ z7Kt$lK7m5NKuDhap*|BFwOMP=vf=4_3G71TBZoaMCeO$7lE+_4j2$v_@e7F05jX2O zFg`L-piyy_3uUY(jT!NiNtli5%Y0@+@NUZ)Wg0)EUgp<6^?^v3_XfHZAJatI4mL%P zMVWD5YZC5^^6O{$a0~+2l3ky+)!Oe}P9(y5cTC`~XR4it4h&X*4pZC&J$G<;2<^jowC=3K4V0IVOJ*bO&Cuj|uG`P+>F9>)~H^`z512uE-2DU->Z| zlfmfRkYa=!ItCN`6sucdUL~&7=j>mJo#2yt)^Ac1Joxc5@(cx&xEf-tbSAyn+P$$Z ziv#qkI(kp&mD~~jCRXnK8;v3|O6`a-qNNg>qBb3em&cuju_L5%!)6J53KEF;KA~g| zOjz>$&^X-Mee^uQ2$W5YvCK*)3asKAKb=xc@m9lI#6=~7gu*+N{ z*pfskI2*#e=CHj2`~?PgEZ`@)`eh5-9VOs3a&%OFLB@rhuD4cusSB=q94pHPMgF3g0hEiDPm_RKX*CY#Ve6U7r>UpIYO zUCOI|f7b%v<}B*FW}6TGemELpiyR^H_18qKYnVWeVOh)vLA!=*M4iq6a^{uKaL$>{s^Go-nvl z#nmpsXd@apcPj&vab5Ph#x%WZi(QPjt#Ocj0Uc!U`Q#~->-M=z**s=OqRQyb;EaMR2aTkT^e1O#CrD%&jEs$ zf#Y&Z?+YG=qrQVE<2tvr%|kE^+n+L9XMd%>80;tzQfeDlv#)IyvvPv1lJFd*S9)vA zJ%V(Is9hf{)j3+1+-__0`bTr*KHh6LsGDH~IPe6aa*@D@ot4CG814oD}P*N zgYd{rxP_qIc;&>9M~ZN#3E<+dCe#?jnjKvrKSvb5|4eCRtZxJOLHs6@?gCP%E$NXR zEE5w)JP&=_@4uI>R6Z_JAUv)K(1FiZ>6} zj!AH00QOkxe1F?`8{LzbY6k6}Ed8->KX(ep192n|GXO8%i-N(P=)ajwJiv6uH7Zh; zPi>O&n4w$;YEtyZty+ks;II5e5Th!XVf>+CH-zkm_Nz9*#W0W&27NdXU#9x&soJJe zg+}Ja;BeU5gL<}M$bhzUFkNkz2ohDde+5mOh78zK1`cv&z%0r4VC&uX#pO|8YO%qr z%+P07E#6?=GBp4Xh1VAXNb+A}C!T@+(sNEX z!PRe9cGmvn>ojO{Z@~Sv8=CitPmcEKKHNc;D7K2_sAaUp4%NM!Eg%%qho3!VRUPntc*j%(H#y*?o7%SB`ck3F^%>s7K7yIxwab?cW8Xkgc|`PEg)B3{<-(z* zV;e!uFwT53$bxFCL+veh8YW%2K_}cmZIM+Vb1?94Asv9hPP6JGJRk-E@%j2eD->A*yit;7w}+STlnFd2m1~$;qvry6(k(Z;qA}hP&?C*qy0hD}74t56 z9MYx{&rEm1J$Z~2*c8joKsZ^POf}TS9Xq6@HDvcT4e|hd%rkpMND93#EKJ_^QsYZgc3m)X)$UD}fLIvqG zd^`YGuubkQ-o>;P|4iYP@>7MJ_x6s>i5jjTyokl-uxOKPHe5Rn8_lTTNe1Wo!`=c`2i>8q6E(FchWYgJ4o+G`) zAR;Xs7i)R78Bi0(E+!lhWJBo1Q<9*w9wsvzYh>vgax+=fxKDR0+>f=qFax z>T}1~oE$(kFl6ADr3m@tMK!bFz;23Onc3H;Cm)WxE*$OQQ!1Dh45fZ2=@!NTt+1?F zz!HCi_DP7Lw#snUcFIDvyi-OK%vps0Y6V^-;?v%o!3KzggDi$`gsC)Yn={T? zo`_LlMovSzB0*2C41~1cc)tx|Y?A$v?%5nAdaGr9TLr3ecwUQ=Z~0z=T-|`AF9n|feA!zP^W%EV*iikDo2gNA0#3SWNDTFZmk+YCO_qbs zK+Mb)8R9|Su2K{ zGO_k17e%yGHq=hbPZu)>`u&8e^Z~+cfXw0WDNPpg4jruk8Os8ABoiiYI&sT^#vplxzoGQ01NsP=4Tfr1j5~F$)QXWSzq-xMP zDi=#(X+Ijj{V3Tf+=MKWh!>`uR!i#Hdxi_2tUHB#YS(L?4L&hy?Y;#`S3e! zS=nE~@K;mFX9v+`4w8q#mUqiyqA|86(dZ6OAuQM{&VmDg7`)u0<{6Ty^f)H^3pAb3 zIqc?9U0$~~!KQMT$IhYnqd_409k*9r3rIctzx2#;oZQ{eDV@(T;K6RErOwhTJnDX% zCb7l)I{XsIrwNuLI?zfkhQ%g-CB~a>+~pEnkY;xmBK$$ZX02zvz7K6@YF^6bhj7f| zPXj^c!!Y!g;N`vqrUi18Q|Y!*F2#c*F{$v3j4#y+$jGEb=SUzeVu!Waz~GPPs3*Gp znahrtS06>HsnfmtVCB65VTo$i>s#-uAeCDZRcHzYQK6w9btWX_vNy*n6c&@g+R{Y* z32|RHYxQI&S0$9r?ABeHAvMFb_xYDt|1+a}oPWnp)t~N5QH#r=02?trgkzjhZ0HS7 zt*>XJYDz$# zO*Y4rfvjAWGFe)A-A0QKc{|s@@t9ekk$RPaW3X?JEm8#jPozyYb+{Qg z`;s_>L7U5r9rzOj5S1@x&gurJz~KsCy{Yr^E*{gtA-A$r5RVXJR*|3;k_Qc$dxPXT z_Mw>H4ngBff#xIKFPh+5v6tAIz=-z!li)i&id6^)!>bsg4mnR-7L7(AWlE8_L!4a~*jF%2^a2C=9`rbo zPCfT)7-V-^`XD6H-f+Wo_af`TT@9PQ_rW&M3R)C>7)Z9g)l|-S;VCjEY`g=a5so1) z6{2Z&OwPCFK-d1WETdtnJ&~+1g003gOLl7=XUkL{fxcXsL;t-opdc@c4vfFRJvKWa z;TWf+Bp^;NQz}g*dKo%n&5+D=v~t5W2OdYnOu{e@OQ&^nS-3L@r`@peM+YqvVFhpA z0?Ona{9Ea}PYDuX1r!}iWny{#?K&}sRS9E==lvTV8|D-?@)!pgl1a^0!Onp;Avo#a z%%vFh>`aWpYBiV+YLz@>!3v@8!Je;`S_*hcR{0|G%cc9=>jDhL!8%#2b#3S=d;?B!L>&bAyHz{*fkjxKSwzeg*1 zd*Ab3^-?}IW_Ql~vzeva;POQZ9X3nLYOSu!e8-Iit~J%Y+oqpVdfV-5y<%p6()VR0 z``(r3QD}HmlH~o|A7#1*Wr8E>jxY^RUpA&h3 z>Tf@5n{b&#vymD%&sbIgtov!cL_# zf?6(SD@HAYDY6BqsHt_AU%4~pXO{St^x!OxaeiOcZC5e= z-XycpJr?U|p68DkRy`UsEET#3wxO~dzpBi-J?!2+toP<9MO!X;Y(=oef`qHmqK=BJtGeTK}9LL z$f7~Ln8DiXHIvH7*`t)mHZ)A6(1jV(lsbt?*+xZB_5NT2?&&t?t3B)(zlg?uYPtH~ z+fB?CZzW|*^2j`mpEp0-vonLfvTDr3bb1+feT$g@ZU?(`Bl(nPye`@6D;Yz>zK&j} zo`%16()q@r@ZI3wZLRx1MhMqjb9jP5Q%bQxzZi;mzFQ8SgR#ivO8G0k+nS*+X(s$A zBx0HwHA0uz(02zSjg{9wC83#cyPX^A>RgHPw2 zl6ckWI#{RA@&v0zXb^>^OP(s2qV`hD%3o^5-03gq+KO6LLk%+^Ut0?6%O#5V=z??2 z_=Y}P+_RD!2m%5|TIhhr_nH0EW!8w7K-Ctv@fXLKhIAlu_p%??CzD^T4D09 z(#IUEE2=`My$LkqOrJ@=Mv7b+8IVTp`|@|hUxYv7MIoy0`H;$~R>%*HQxRg)PudiL zR(=ZEsgfrGwjkEP4)c;lsq=r?^JA!QeH1ch(Md!pMd=kUjxKSVQtg=g-jU~|JV4|6 zSoC5br_4mq8N99KszY08bYo2;A&y>ME$~{rq1uks-H6`E+|t_;Libix6Ho*$doyuU zAI!p*PU9zWo$h@PuZ**BD%#`jbKX?rr$-ZY>qF&114A6@q?VYX;T@l2R;#?AWT5z{ z+N8Nd306MiXZoqH zgaxq;ma69{95UIcDv^0^p0uKBT4irV%m3>vRUu_6Z!uA4jvlkKBjxEs8MaO2$I;NV>dySD|DP*VeS57Oi}PswZh>C{AIv`7QU$%hX!?U-ij!8=R_7UzagoQOpQ5TJBhbczt2ml ziNf;yd)y;*CCZHlCy>gQ*~FMFjtbAYORCX~hj4sqZnJltrLpWoPn{UGUMaXlR;b^o zrXEKA%kGT<_q2FwF4sAM*@SWH=8WPHnG&f1%B>4F3OF8WRcd#(MIO>!Y-^gb7%ITv|7hm#<9A`3 zh;|L(>K@k`hqe=wu=)PZbJ%Wnitlf>E(#_6p`u@Pfe7JX9kFhMwe$!PARo+azj9xd zKiwEPCC#ZlYSVU_iG ziE)ytG-p7t7q&W>3913`9QoElPVjus6zcvAalDvlS&Bx#!ZBh2_y+A^ErKfGIpC#6 z{DR5(C=p^B2cUOW|Gh5+4VFLmFf~NAO~ip$@^d>11kL3AdZP_IvfK?NY%62}sX}*j zQ`9%aUxG27(Pu14Uw7GK$m{cRX`V>Nl9#m&Y=WDx{(AA$w7bD><1Lvpx@grnDtCys z93NO{!TrD@9Yw)}qUm=wSLNxOAmD-oQ({O#`HocG0eBP<>dyDDnwV;_z|d4i5OWFW zOyo#wj=Us^pp=_u3r)}3Q)H^_Mol-gY(o9M2yTNr_kRFrK$pMin{;v3X9fnSL);bp zPw~?-LGf9i9wOR+00000000000DyN5edZqtP*|j>+75(}Y!ljb06=;9az`hK=#QeM{am@8G?JeN13t zh`{YXL_Y^7jCbnc^1-6sqtUE;kMo^Z&7mUX;-LZ6J`h_Q-EPH zA9I?7@IxC5Pt)qaFV+kldomX>K>xfdeKBqs&ox$+F? z(Q7bKh_`d+IwJwXQvX|1@nqwrcqHucgGvB=l`pC@@3(g=WPOO}jR@T5CA>&;&o|1Q z;&-kEZ1z?|9U&hP-yApSD_gAeDN;$*^b^8t&@^eey*$%CQJjGN3PR1WF8WxTCmL8W zm5n&`ZUQ=13x}}?p7mu#Ou4e3S5GrqG%l;4O@F;reunp9j9}XDLgWH+x^<$PI6c@U zt`iJ7O2URD0{y?IT*4cM0sX*yqNVl=fa-XU+uK>ba5c0vrMXaT53ww>K{$lSjm(*? z&j}wb#!$%B{NSd6wm?6P5+Z?rr?Kml_KXsrnWbmVX&IFbhGRODc;|cHbAq{TKWqfM-S&60DdaNKI39U$8`rV4 z?)~t*0)?06ElYn6j_G;ff;|p0LfSq3p<+gD2)<6Qeds(o5`GKP)A(PtI+=TG%eX)s zwz7otG2y7*z3yKyqvs9@>^kr+gvHFCV)V)5Ta3j@%4a8ebhdfCdWw*B`I-NUKGW>OR5_9I(ZGl+1kPZ zpTGbB1-k8J<55}+H=A_v9Uhabf%m=)2{16mLXRhrGagqZevWnnp$g=Oux%92q+TY9 z#Kg=ve6hK8sz7H@>iNoLGtmv1S+=((Q}XM$?$6hn>-SXWf_5schSppkO>=@=SV|&^ zzn{7Y>eY`aLD)?ZKmYubZ>t=WtabJ>*kXcGW^(QaiK^ktuO&?Wl!q4R%!1OG8@7Tu zSHCw^#Ox?tua~x~R^%p?_9-RS4Z?ls*fF~#O(A`0B8Ep8Rr8pwrxqz;M2*T#ZTY+-QtClB@JwrMZYB@0QfEkaALBqC=5Die0A5g_Nu&}c>4 z%d(RlU0H7p=%e*O0bxo)ezv^U;ilq9Je$>UT3tX}PJ2J%2ZGw@P{mYt3EaCi%de=P z;kPxqY27oc?TCq86U#I8yXC31smMR#WeX8IF8~!CH;c(4Ul!E47LbND-7wFdW%n_tC{CMwk`C>m!8XIpU@Y;!Wud4= zC-}?Qm|Tta0P>nZLvo!TquwKGqHuv4rA$XpXFEW7DK8PX{e!nNVEg$fqp1^EyKIW} zW!@j~jCJbRF-oM7knHexTH5dix8JqBN~kO1I>o6)sPCUG7!jklC=B&%whG$qsknQ0 zuUpeg`}E{axLg7w>_heqQ;CokXy;D&XgqF=Cug~6ldi!`wTatTNBYS?L(wc8{_PWr z@@Z!Eq5$$~{uP3?OW(LO&%BGF zEwQ@nMyCZHfAevU(IW?^>1u~8NG~6>>&>Oz^-$BfuGW#Oz}jkNZT+?)SsD@m;EEG6j8WO$G)In!cI!jJ-&AI1yZ6DMN(5i#g79m^ zm5mMukHs^J{O#k0{=lI@bny)$v0Vy|!cnI_HJWvxwHCU9!s>1<+M&6y4#4=%^woD| z5Z8^9z9x(CG;R6$4H$%Sdqm6XMzi?|m`ed;Mm^QjP#TaKYfoN@CD64j=JbS;=^o?s z>HTK$#uhxX+5X`w0mx*F)Ua9&qBgCW1#xONqog)>ODT3N$DEm^auu%J1V% zwtRjxMEEv*G$!(f5rtQ|ovs5CRHL&EXD8$r`Qa|tLYN9daQx8h+#mn|0bCFDhM&Z^ zpr%;k5j@+Fh@=qx#_i8U9I`Ocg&!W>VHkC$SKkcMq`6cRZnc6SJ+&T%#yvB1-TY06 zb%M&ICR`=ED!?^5CW{I3z4zcqcn;jzI2g;{5^2&Vo9fTWxp2mU?mq%DTHbp8#f?MHHMKt-{G2xf^oE+Gx%icP(7f06(!b}ECP{ALt$NR0;dVA-?D-3Xg|)ngmP_FvP{ z42^2C2HhhP5v$*@pl=!Y%9qMsunLGC9S{RO7Bg~9o5rm>=l($s)Z1ER`A`Yy;a?O3 zD_lGm?~`PUY%4+-&nR`TS` zKG|?7h#hF6n3@~jkjf6CBMetRkPy5lrel702V&>oyHCl_MKzvgCF9Po$8X%%0y zN|F1r4>9WsCu&&-2eo2?rXNz!EUCKl*!H?okfvm^kQZf(fW0rwIp#_%6aSp;gXQs8?` z!Ty(gRE5F+9B5+9xTUDe{+wK(G@tMuUy2#d%m#=fjnnK(i5b2+ zwDJ}$$%VzzNJu=e7oLpMnjj<63JXbXva^kE!?agdPhDL36N7(cu^qsJC!+3CeK!A+ z`u(z^GM9T4o^5Kq-e?D%v6>3LxeK4?OoKz8I(|WXK;@0p-DJ7BOpTdSuRlPlFJ&f0 zwTze`SCVTJKObQPXwZQ4IQhdG92>3793FOHzGE5&3X5T27KN7)03|?hsy%8%W|8hX z3=GsP1$D(%K>B0|D84WmsQd3vr^%*xx_%&g8o_PAEGQm9y}KRdP@DywoX!1_1krvZ z{A`?W+9;`SsG87?$S6^>EL2s^)t=KKIgDqKaqXhqfBGLwlwn?+Dcm8i9&&fZ&=n-L zTnTxq-QCTgH8BK zpk7nYb>5^N?ZqDLb-MaNOkwyPM^uT|ec3R4RMiX>&J8jmq7^itz2hJ<@8E_07Y5+E zH@Vn#M)6m)Nqcv9A=Y|0u!o2(V$hDw&0CLWMNn7e$V0X|4}{nc=;e;KqdDeuQiLV! zEt#L~_{Sg*c#mP-vbv*o3{#-WY~&FPz&i#6&-zJxu5~}@{%5dDi&F$7jLkccVm-h8 zTi(F`9RPD>m^rVj>-Vk#VR!G~{>E!2)3J#qr0~MKo80>zfZ`Dn>@BuuHztAZ;A%l_ zk0gb{93v>l+V(f9$Y&cWErITIwI%r=aNeltfCyW9000078S*#i6A~xyVbc#rccyi* z>I$S~Jdii1%obJH{J%|h9;QSFwi_o}FMr5J75Fx}{S{9)C3laB85+I+&-u=?yWGr? zsNNl46vGRVHOI8CvKM2NiITrMosPBYML2UQT>2qR?70ERC8#K&l&9bS^=%l={1hTv zx`(5Th}P^goPkavUoTno(WCuW8?{mCMEK7+1W@l@*lgv~{we4%PUc5<4v8`l_@y+8K5{+FkO9iQKRV>^(AX6nG zWokCcdN(R5q!ltc_h*YTT#?0Es#|zzCKR0%9o5KfB6vJwooF%1X>c)V2P-jXe`{>}KiS zc^Ch+5!}7m4E{zJ;eYQ>-u`B;GQ~daJDr0{i6S(@Tp}M(pSEOpo94r1MH>*LKFw_h zWrMXiURw_{tlJ0_n)*wW&|pNcc@+v-*06Ul;Rx7D)cJF}S$52M)9));NTd-;WsRDM z7%~>eQk>a*L`$cPpjX zMV%d)mO>?YQCDtw#HipHc_tuXs~^&XxO3006Ys{OMT$2Yf3>!be+{-t>~y^I2v+Ue z{dEMhZ~t`8_4q>jZfq+A4%Nu~_x&JO)MV%io*NX66&X!!SG1p51ULQ6Y&*PjHEDTJ zn&wsK#C)<(%e}jLNLZ&!bL>_PPaJX}&zWH%^mmPtBzMcd&9g6xqMKk%eU~X()f+8R zNH-7f+gRDkhrb^5TT3a4lC8y%42Ncqi9j0N`Zxdjm9fk?kQK9G53#coS+WA4S(~wy zmcbprGe#siY%wE>qLjvuqv^-BSQ}|;^>twSD|}jWJ@A+kWQLU#NZATA6amDnr5|m& zXwPzJCsAp@`>2r-gSoc1lhuMjMcRcFp6KBTJO&eb(vl8QStZ=6I2T9CLMJorawe%c z6&q8P7^C1tGHHe1nRTUHlF718un%fL>_W034phCNyAOi1r!T16b(gndsOW_^t>*%) zzEqr2N5Upt5)(Ya{6S*Mjp4(syC@zh)*Vi*dXJ=#vcO~8cQaqhzB_>aU-7GMQ95q= z`;gyj!{88bFtQzM^h_bx&`Of9+$yNfh32Euqeh!!7OU+80KthIP6dxbw+DFJQIUqI zklmt~05C87IU#t3LTpf$A9Fs+vc+n6P4xhfm<`f*uhOn=^2LUCne%dD`(Hd!|4N>_ zbJ(sU1|bGrk?C%F#<>Brvusn^K%_u~MUtmidB~PFhkDOW?G27389+tROAlm{uK<{d z`m`k7Q&J388C7gfElHKK;4_IcBwjCTrNmJtwNKG7d6=$27ht)hxW}IYxJW+hj!5sT zq-|8$s)~_}XwZ&+T==$@^FH>kM@(Jnb8lE)Iu+sQqTVn)2C_J|!Kr-OT^-fl-;Ku= z8}WP?;7Be z;ok;_@ZlWkPhkw!M|NNy+w;X_F6-)X0>{;+m+HyqvEX-TBTWLFWt+*#Qy>3NF&3d z6^`0Rk!pVx8GSPY+t0cxHV$sUW68a=zPNtvqMG2LV+R-6k35o^fi?%8e1#*uLT;an z0ryGs@Y=H&rHKC=ekJg%3yz_hCbp*b(e@##y#NflDk=Pr|3AfptpEQ|1xXs^f@I)E@zJv~YK!-J6YVa? z^?7TDT8H4F@kQ?_?0t#KnL|X{3Vt{de84n?D;vyHj`-?AF#Z5$1t-UXo~@vfp;9Qt z000000000KFVdeLwmDDTPwb0^BO#ujk%* z4lK4YFX|wcuK$^DOt$om%0ecH!t!Psxn=M;5J>D#JohI- zWz0M0DQrejf~dAw(RxiF?}m541F@v~7=aS3&BOS}6L5cv^$hxvE-Vq6>N0;WhwG>T^)HcyrDH>%vwtb#E(K_REM{Q1-r*?q5sf}|>ovG5)hVAd zd8A<-vX;~5?&TbX8SN;t*Gc3=97wfS=D& zB;;XLyTDdW**E|I0000WJt!IEa2~ORK7!V`Xo;tlo?8`K(O?RsXs%yM7ws#)Kt>WiReaQ44TDdFc^(rk4D`|{!4qUv@Lgu98PlJt%mLnY$G9-(ftuvPD@mVYGf3B{K95$U=R3eu5D{EsCc{*;tB@_z$f5(&Fptr;~JpJkw zKv`8C!4EEYCA$g~aBd7_Z96Qy%E}D({_VlUHxIjdd#sLxgIZiSqZ)n7cM`ZE-Xg7% zWv2||NnlKl&<3*Mn^jv&WN%TJ_EIQ$3f&*zUur6ofKOYDTBccmPn(LjQ>;O?(EE%z zyHdhP@p%ZOHb8+3qMdljK-ns+e#XV=ZfY~{}i0=7{0l8#vm@&$jYLy{3 zagj5k2yR`2$Lj(D^wbbor68l2^6_1Civ(U;I78W;E)fQ-$58#uXse&ljDFGL-&B>hZItdz4bM)EnSY`hpvtm(~wl_D<^zJv@?{q@}b&-453)UQQe7~ z8Qwdi&%cfd6G|{pPxLO7ur|&DFIIcmpe_@BKwXl+Ox3`c6+z3FtagZmuIC0%AaHGP zJ&i3*oiocT%GUnk6A3Fkq}_s8n^M-VTe~Mc-iuHPf7pB_G3AXFRma097LmLX;xDj$NM(GSgQ=($L0BFjPrVr|<`R zXW%mKl;9>DmR4r6eUAF>^TdoVQ>|0aVDpxjH+NSn6Xw;WBJqh3MAWBU_XQjv3pzii6ce)M0J2m z@UP%%9OsE>+1{?LmWof4Y6-to%s45YVDy9I*@5`R9nKD$g$xJB6iK0rxVN-K~c2mOt)RTiG(dnQRDI-8jeKZkw--9#_k zd}i(EUr>{J|IaPfekR$Q$1lh#RM#_q+|Q7hu%S>(m)Itk9P6NXiEpE@G+p{aube(C zN0eivoBbl*@fu>wt@cT9>z4v|GQdo?+^rAA_Rp=0mj^TV@^cg?a}+ z&dQU>HsI9)ARl#a%PqskZ=c0R8?4srMnv{l-lJ%N)ZD6Q*|tB z>?oKZx5`OcMkNa;Jw6N`!O=vGg`T}REjcUKbb*D?;q`T(6nNyd7m|ip;C(EJKB5y~ zvJ!ydhX}plphB~vl%GPxWbm#sEi?&FSMVpJVCrKI3C{Z`aw-Zn%CS-QN%5KcXK7@s z?wO&My_E0jWkOuc1b=2uy@n0at-dH7qx707t(gkHHV91VOYTK#auD$C9@moS-UUwX zV@e4?N0dJ49OMa3|9$3yN%V8&!8CMKy}RaZ1#N^1ThH>b=2TEjM(`R$0Ofccw=1OO zOW9cN>2HObI9^%?1;mZhY4qPxv`nn+N{|I^{hvYAx}8U$V&WUoGDWrW=$WmO0p7~k zX{2D$mg8NysX#<<1N5pE_O#S#jfiaYZ%c!&Zam!@_zd2+ejYr-Ar;CPf9um8js@O` z>0*$`i;^MU^9i_6TJCUo-8%S)E|3-LTx3S&%cLOD3ajGxnk(ARdz`x1J_&TLCK7i4 zZO8wx{+|DRax--LQ@H}z6>Q_PlhFH!ygDT0+v}L$ra~d^qOzVk02t?frq$TX+s)qd79<&B zyfKc+CR0*9{SP~RIj&eO0I*dZO*i`2yo;*Dq-T+6Ra?bja7s5^vXgz9Y>c;4IfbTzE`ipsH# z)Kc{JYQX)dwb7}pNk1W^K)A!>q1DKjcRhZgs}x{}jVt_+SeA7_{HV(MV|vg704r&d zKd^30jtPIAU!p~UTXK_u`74SCo$e>Yf{@-i3j3T~c*BmZh=OlwbqE@9V0m8=c*iut z_&EcJBO9{-ER5*-W_x{qoBjsa8E%gCBQNb|O)})jM#ee@>+{wx=+qBS3#QO-oaO)59&0g26hG8n!X4G*6cpdr)^{YIHmuApG zMpZc${5lZSqq1Q7ZrYn-RjzWFe!%QnF8wngcZL&Kvbw1_#wnEO83*| zhBq+X+naA+w|u<*Mm+MG_(eS?(JO#-erd#~xEA^RZF3aog(7A$=ekK}3wEt!TUbSK zR1k}8$V_`#Gs?FrFRC~KSXo4A8|P+JAja*Mmm_| zc%1=BV+=tLiox6JO@yg~4hgt=_%sy?!sf2l2_|91yOkbIL9!wi*qDOQhQq{*mdY_3 zv3~({PxW*g1wuyx%a1EUF&|4rbrcKU_#*ugfa(0u&Yrv+1fo-la!pd7&?Bff=oi?x zP}SH83*3+%)Z(iEELph=f2V8)k8`Kqq5&HyJoc=-xJhi>St4};`i!MxQgILGVDi}B zUab_B_3(&SHRq*!Xn8s<5)8>ykp=N;juwoiJH%a|ir~~eBmY&B`SZy1JWLZa);7@w?!D?2T6OAks}&AJTm+JHkp8YCRg?euS;DM!9=E|r z%uOy`Ns+yYlPY`g=7(L2UoYkL=tC_Wl6b2$8M?{FFdocC@qr-F(m8bgeH@EYC(H{_B=k05Sp-Ku2P&AA4-45%-wq@eyfoWUKNXOOm^jGY(KxRndUA;t5v?~& zEKyWwvryWn&gr)kL2XQjK{k}tlHmSYFuOl&DoLP7piElD-UU8QJY_7(XU^B6wsOaM z;J7Q4wp#l!r=2qEQxOOW*q{iwzeb1)pepk*byL$-VqAUA1e4MCnOB8%aMC8e(SPGu zItb=n;DS+oI3YC_umc%$2))?dK0ypC0_G=|`>LDnO+N;OZt=O^~dY zXSWvnqtB(8)8fKYOQ%lno!kD9Ih z;~f+<6P>MPFc$`smpq4z7R*=pxw6NYs`Id(>MI75`*Fvwh!W%0;hW>@1yRK3MK;_| zXU9$-JRg53b;%x+i{_ixVFdBK?#=MZh|0c7TKm6644~8V`GQC4cGdQbe%^k0*iDCN z?7*2)dMUF0>f%!Y9d&F1V^77zdi&&*&pL-^JDdSgc*QtqOtF?fPmp+)iG6oc{-ZK_ zy|X;S-s^=A#;(JHXyxNP*;!Vw;W;jBbO^od9)m^U!r{(Z61kBVHsH|Zukd@h_X9P; zkZT@Gj3Dw|M(_Ed@Ds2m65bCKN;uN)sFzsd1IHP8y+MKmY}Y`!ba0#P)w&s>Rko2*g;NU+tT_k81*wLC*SurNwf)^7kGa8o4tr@j&3 zsKeXECmk^)tPS+#o&vEWl#7iM=gCPB3Lix_9!$c6M~EpgR0p6cu=r{6;JYP0+$a=v zNo5Un%5Q{hCRrM^X@qH`BlttgP?VtQ^WfyC#5JKC&q9H(Ybjf!ihA4C@fp_m1PAhy z2;1)5;e8K~L#JxmSu9S&!{=`!)CHD#mwjU8!W;9de^5rlG(e3y``+QYK1`0`>7k&W z#wD#g^DBZ0_PN1V9_p)x#+B+=?#&XoQ4ER3;CyV4eN4|X-A!Zsqx?B1Dp6^*HWO`W z-4B#Zi#9ctksRane?t(F@L0CF-i_EzQl^rT`N?XtU4CTCGAsX7$N870(aj% zH~mAXNz)HKfa-#Ai5<`Tb?Vl!ntR&so-LeZe(q7ys2bc@X8WUJO@w<-rOM5b@syjy zhDZkqGH*f;GoGufKm3B67l<^X4xx?@7Y}9CsrFa6nvitfufvhsV!{$rk*H<)TGr%b z9V?2e8bX4-H7I@b$*CbGJsjRg8qU@b{vG=HP&RHU@{OI{v|rKzIGJ5_?!?j6F^q2` zcDHQEj&E}Ncc67q)CpD^!mA8}8eN`r%&OEzMdshJD3p-Hhj2hHo)l4ek{`9kXW=vL zTadIYim~8I9J3;@afrY{thzCr_i=129@08NCw^mgh0S=cMZ%v9G^Okj|Ni)cFS;yS zA5BR-R0K?fs_`^G9E9w3b$Gaw3N^N-&yx)fIe(qMns03`{!L)ll*!6(^hP0Cr#k;L=LyNpw@OR5n64y8l>( zprJ36ONu0L{1!-vGANDnaDNp`X;-FVBD15nm8N~*_p`j`3RUw?S{=5|8^UrOTe{@L z@{E-IIcaVfQ{>)|-Cv4wr{}$I;i1e7x_<>v+;{tHe|=)>u{%lu(0m4a4Xtkc>tD4+ zi|UYdh#F1SLwO$h_VMw{O6F^C6URe$Q?To%&t1ORA>c-J#Y%Pi;pfS`&mFfQjB!f? z_%N-&CY<}*lTSGnvgp(YsX<@2L=s}E;AUhM1l=aZhaGNkn2&Dk5Lu}8hU1{)SZfAK z(&oP(YOGWxL!4rBrFF_}|3SD1QXBSg0!FVUFP~s}0joU|fX!V6^L%O1mgAEFFT&4> zMRb4q5@>l8fwI#|r7k|2k=fao+W^d_nxPvm)~T_X1+FYJ1I0&mj=MP~>}z#k=D<3X z#fN9kcKW|#xXWo>nML3UHWoSESD%Fn-70#-TXZES@PB z*!vG~;LP)`<)d%evE5UKoVdW_Cy`)1^S<<{PPYMKwkv%D8n_UDjI((|r2Bq}7)(-w zi|^B)pT7Iwk(ILJ?Z*xRKE``kVQAxSDfWSiCjq{H91)-koQ-s5T(OeoO{rWu)Il?> zvn=O$4&hZ~i~8jiTT&zkbnQqWgadkIF?UZ-l9zug zKJFC@U($2GxP6Ih+33w4To@un2-@v|5N_s@pz8X=QoJ|L3=r|IxaqWm6L836I&4bF zlH%pH03gwqqAy*zn~?WZ9HxO`P+7ImLufN9M9$H7I(`Ey{8!m*-TRI&bgx?D}zr)ucW!gaUWr$^z5vC2z`??`O4!%j* z`qxdIdq<&f#V;?S9ZkY6u!0YO>IWG5-!Ac;X~0Rde7e5VKPA3rMuHekelhsv5bwn(O8HF%_#D_2E=a`1_t-5=P7@SA%Is-fE-H9ixP*&#Z} zM486@t+{hZ+rJz)xObu<&E15U5%$Pf^9g=>dk(XJ+3(`EpJ)7e5s$G3kmW=soT?S_ zE5##JWD>#yptt@Eyngk^@UF5DsSSc)z{I2iw`kfLb7t_Y?va|U5FWyPXy?6I!t<2Y0e=^_Jn8-9=MK|xZrxbF_w zaqlrYOMv6BI{SVnbLFs%vAqnIqYrHdOIJd9{l;>U+;GEif&v@-cjg8xOR?EBXvbs} zY;WR17ARyp&dkOvtji#?)T)^}A!ejRfH>t$xx?P~OU&Qx^yJ?bw|Ly|5eAT^e5p?4 zn+PM8hd9$8-)>#g%!`kvV2M^1LtiuP}XyvW`@xkc=73YH*#&wA$+1z7`w~_Wrx@@MAT{| z)p2!fcy_m=+{sLt%9JvxNIaG z4w1aIH$=dtYmZW+$kKe-7~IL#zjJ@&`$O@AM`*nJq|U-*eP&jYZ7Pt=LNBr|M`8sG zU#pc=W_tz8)-}0XM3o9LW2X=C08&N$)V2NI@57a+J-}L5uVZ^dEw9wielRcoEv+8{ zetNNK$J+I3yU@Ul`kg=xCd)?C+p8%P6VW}bQh?~$hrLUw;5N0g72O@n8w%Q3$a5Fx zv_&_?$iwMGqMTW{8t=yHK9hSkYt68XS(%)i_+_@b(0F~x{|dUe(t);v=z?E7a|t93 zfpld<)W|zJ*0J1morAU>zbDot;hpj$D5UkfMw?lN5C0-_IS|0vn&kyv+^>nS(<WUR|784YA6pwy9jBxr z%K8}V8p6M1oRiHJD49r5XF}6eYlLD9gn{qs+924~Df~*EB5sv87_38j#KCr*UeJ`^ z=M(=x9GK@F#S~g-(uJ$jJ&OulmaQPS#Bn{c&9f^}#5DAc%E1fdE$$~8?$kCa0laCK zL1hpJbD0aW?^XzAH2M4j^5lR*2d4_2Shdb*=%M#$=#g7E);BHpvA276LwlOCQ13Xf zI^-5^`&bwX`6Lv7rA3$&ze-tXFvr_$8~b(0G)UvR+Z*?a`c2i4eBYRt4TxO?uK#MB zzHEZWp1a9LSK*!62qCpL+Zb*tEm#{Mfu6y>27#m;z{40+0n0{I8&Dz9?MUbgtXMZKMv+AZB6!jhT@Xj)QQTUQKJJ+$(10d&j!&c z!Rj5wDoiwFDmjw^BMnrkOXT5x^66ylh>!G+wVbY@Z8QJb=hYwhg|}7xLK?$lQ0swp zuw*hl+oV}2*={9?0!%SYJr5w3V!D4WaaHf(1wNJzEj}@Hn_oEiEjS|9^n8?1nHEH7 zmmU~E!21e(p*Uqn#ac8HPM6?eoR|GyZ=*waL)sKR#=8-5vJ5_Dm--}LLv5Uhwp`61r?V+Z?RVGIrDj}$08+;kuv366Nwoq+i`B;E7l>X z^??3a;!jersT%{)fr7Ek=hAXtMNXTC2TEB?rXTJltyNlE4>6u(`-hWqVQHd^Eec5$ z{nAhEE8sl-ldPR(@iSrsp{oB9>osOpat6!Ku3KM4FO!A-C_o!M_J6EORQ5FSwcs-9 z8DuT=z#{VhDq{gs*j~rJ#SYL(Vk%LQQ>_KJ?o&`FlJXSqX?Hyc&z+_R5dl~2P@#Tb zSWX+}s8-Ts`*s+#*DTx2yI6Pwco(rsI5te+H1$udktZrOb~tovG-xvAg%CxubjIMA zs9eYE2;w0g%^(@P;cikk9`Q0AZS41!^}s|{*(e~cMd6QD_;o(wZOM^}O$Yzaoedaf zJO>VW`jKw{A)rK*D+pzXQE==_@qzElwSi6*Nt8=MTud7{-yB$W#5dV9PoL3!NC5(P zP4gq08Mi_Z2xZEee{^lo6Qf%|yimYT;)q+CJh^^)ynp}*&i@Dff1~W{_Bjy20k{y$ z%}4)CzH{8U_bxjM8sj0?*S(SF`KKu{-g%+mncAf(delXHmn-SV4n)WH(N80ZLpWtNrE^KbugaYX!<4%8DBS|-dcd47I<(%rPxvcEKK{A7r zdiwt*2_a&b+vbF+<)>ePBC_}>0?mr9rOZ!?7DoXKdvG9k(!9u28R+ zM}*Q>kiAjBs2+Ybii&YS4zoPlL8KVlsW&$^5#Xkmvct}+-CNqoaC%C-#w8maQp_Y~ zLm`VgBsXlo;Wul44AsK3K#7t{b}q|$0rZf_g0(9?@K@7a&yR-iqrso`dw9m|(&$*% z$`=7_jyiwJ-Om|ETh4W##a}mkysQ;%ityuNp=c!*?bzC0SVLbnX{b%t8m3L0=Dawy zCaz&n#dEBC%hb`LO;g&eUU}Q0Qb?r!$?)&6SC)@%uSWPefC^V(GT$*VH+S z?-Xcdu2E9|unW6#1uYw~pMoRx`gU8cfvphJ_op?!HAk3z7(alap1rJ?)AK=jqmFAa zHe9-LQ6D);{Fq@H>Dc52??L&oyZflXHJsKJs5R2G;93@_;gIe(< zq>H~Gn-LFE)CCth=x*#XG`jBatPSOSwRSTArCt^b%HVLME5zIlNg*MItl zc_g*Vs})g>QPJ<&&>mwJii0fGmEP^>@Kw`dgX$DOn-H(PRC4G;|3(l_{<)obV33V> z0000K9IDloL{W1)n^v_2h%Y&ePfq1F(^PxvU`>yLi*H%)zqlu2FWEqG89u#AjbPf_ z1wHC8-%bdz0t;52SD#=*R5u>neHz5SaE&t>P4$k!@2_DYK=q@3Lg?=@*BqYha?nE2 zutA+vRVl$z8R<;P*1{9nB>8EnVp^t08X7O5(wq8iPej3{YNXnCZ$CCTr5-FnAp<@kD|I{nEIb4yEat-b;i*KpdZ;fYoc`2(_$XF4r z|3&YhjLos4iNB1;QB=>n2H^aE(e7-@2GvL6E|XUYjB4lSr0k&t_+ka;zmAoo`&)I^ zZUr~Djps{|J%~^h7^XC9!@S@l|1VR-9TG#E;eZ-G!(dKfjk()#?>a3z@8wu>!n z(3?A4wvt`i#;gxW5~Swqh1@@t&!+{1=*?HR$f?jVsZTHT6UcZEN^hLR( ztUSpAh;RjE%YmK0l=O~?I}wY6U;Fiq)QjiTb?flE0?9DQE4{Rta{#GFNnit=S)~?k z$V%NEB;MA{w#M9%ZcU#_tesiQaReqU@Hu{~0jD}2i8HpQy+PS%YPvOHZr$;6X5dnv z@u8gOWPfCYoZDLgqbK6$ro3Q9mAo0pv^c_8Y*=UnJo($+MV#upvS;~9(h^MtAiEMR z=(Ba*&bDyAsq-O&(_k|zuD+0i zBg7oTnmh^%a=CfE#l9?iY1uV7;czjx^bPQI zFgUTl9UH~wp+nxa&T!SUsO21h+KwkjU2x{T?rQ*dsEzB0Y*?FY|Lr~B#XSfiXv#gn zeWv>d+$qGe59XVNe&#S6alHJX`>C`-m2+v#kBl(afH&tDeqO$i@7K?^LDz((pYaR*CYhlq!4etC!n`D#%xt+hqd`amQ^ zdBj-Tj8JmKBy|r+43^!ADxpahri<1mF%b>s*ky&uEzjS^xB_eWG;WGJ0PIe{V)bitHrw?n!Y8t-UZHzk~$Fm574aJ>uwemJugOTwnu zX-i+cES+AWbSRwZuHg{AtzE&uh0*bsNNmvC8TU`JzWh~ea+*VU&=<;-&Qj@HjeCKT zc#ZtE3R>=CX)VIY*+H6TWPV^zGMNDEDTIO2C*>p61&-4N#}Qg1ETHkxnIl?Tf;|W& zeh$)SK7N;Onoa$rT~yzjFG7(C`pVl#J?%y|#t4Bdh#|%568Tqm70&`jr9WfUxd2A7 ztWroI)v%nB)*j$()52^jfqXy{Yx>eNSvksINi$8?2xak&R!PP zgs620OvOBRP~;7={Y0NbaU26cA0?~U5mw@|4P+h)LXk;9MSD1r+8`(koUIGkHU8zYP^0>-+?v|N3XF4x2Tf@XsfyuY$_>V&85sc5 z|Hn@O+(L+&cgh};3p|ZXGI34ooJHN3QBCLZg22mlecu^s%W-8&V&N=topg)Ubqt=;-tl16sD#PtWgk$b;nwRM%QhD=Ie|xl|u#G7!HS73d_+N$SmVGIMJb zr{Ql~F`wW7^hG%V*i!< zs9I}@ATzAOW^SnzoE3m(<$lKPsLd?@o+hDdNU zWaaF_QQzr>T1>yf7K@fB`Qn*#PB3vy89F|Z9%Eu35xjv^tkuP{Okm@IWJ|bXrk+*jP+Jl5XBH_(wHhdeE++XL$6~|geunhSY2OXW*!nq zj7u$y_$r=afn+t3SZdfy_06&VRMjG?&ULFB5~J7)Rba$whrLTV{*wcQ3g0|1G)d*U z0)U7LnXg>B1gKx~vJbqBSXUjO-o+ENh`@Qj-v{J=8;7{;U5AH9S6^?2&jN$QS3poW zk-hVTh3!X`&$t5(qf;D#a!JoGRYBdR{Es5}5 zpls9Na%jyDMr~TD&uGWzE*3zqLuT7GtTZ89>lZ9{{Kd8G+(ZBl33Di#CgA>RyRbYR zgk9Ve4J|y{lKo&;(P@NA9P8hrMpmc$X5Zc81wEgqmO4b73xcs8DBlk4sL4X~rfsnq z;iYHL87Gt9SyVLsp1Hiy(5l|j$&clxwt4fGW0JV_P-<+5KiBDESA7K!=~C)g`8;{!p8^A8U@N9wa~mYZIC?18zEHwlV-Fo;ik3725`m0ZP0< z47T*?ym_;hS}80MQL+&5zFq^EYox!QI8zPno(a)To_sxs@DYO|G>LCQX%g6nPz_yA z;)>#}_00S(G5bn)+Kg-%9O04#G}sD1s?1KyV0)i?0Hcx#dQpn+dd~Yzpav>v4LAcH6gVL33%qUEWmU(45mU8h)-ngLTig+Jr z^YJ&>{`fO{2Oz^K9||$zkRLD$V?IovE;Z~f(b`n;8*S)O*1URWljmA&%rw_AZ?>dN zpP1Y#T495T?pMts$M3N0mG-n!?3gjuqYag16Pvm##Ol8mBC_6Gr^J(Oo+?})5euDC zjIW-|(Z8HNLEC-PmeFcck+2P((Mygeu|d+A7%X)4)!w0844*xZW{N?a&qty#$vzAM znE;UQ$PfSQ^z?nL?N)NXH<=vs0WJ?t-|+gJ;J}05jjueqG6#q+3kh#0NA`7ZwK2kA zB;WreBu(CY`DyXp?ql$_9&WVOjrK6?xMjc2VVY7|eL=0+4d;v9mGtzJiWvjHFPm^} zRV{a&2ZPb17uw(hGq7hv7dL}|h%zAqe`h+Ct1{`x;q3%^cQ_bfKqgAJz#-l=_rPL> zvg;D6f3^w<45h(1nWAwkZ)5k1=+EYB9l^u7!q~ z`-LK@J>dkmD5qB{4HL-563jb)aNm~t1#HMN{5+o9`{ie~>sVT$kiVUe;kUjZCb5fJdj zccKpsD9aRgpJ3MZS5?V_B@e+`YkU<2D=$khb7Ndw!7caDU%aBBCO#VX5iez;)ccch z$yUnc66nCd>GlTn8p5bnN`EmgvnZ_1UMUc~R`y*}S<$k{xz(TUhX9eqmjz)(Y)_D9HrR9}{2OA4ecmrIjf8pdLAh$P&@ooMP}4e&gOb_@r5WDdGY3&ukc>O8(oe`Yje4D$H6dugi&2HY% zrs}K`r_BDXbOrEtS1%`B6E%tL7SraLgj~sVy{MltUYzZ4fgR69+BodSyNz=25-*V>r#2Wk#ORoZ&G%4ZC1tV#^;eM7k=7=6o zM_rlP;jq@5&c?yMs2`^$QH}S)Kb4(74|Th) z6>lS;H`_?Uu{TnjxNkD=mwQHwo)lpT8Q%eIJ9;o=upi)IN5>1PsuPjBD5F_(hi6+C&ub>MI}P zKN#x$-a{ekJUK(OWAQUJta^zxkb~mnaul&?a`8?k z8IM06`5i7l!55NHyk{3qNtlNoAPpI^c(**1f>1Yq1bx=BW7kBM7vO3g7Eu?H1aLDZqB{ zxKwEoUqVkG3gld#ENJDcHSnC_^6*NSpsNg1*gr`qdo$yLycfCtrI6CkC%$aQ(jTi; zs=6alq@%dBbJq}N)fUnBpgk(> zvCo`2SL}|lWC%!vuvEm`I9KIXeAQX47;P{(`PGtPUn1*;1+L4ubkFNtlCf|Fkw;Pd z@s5~GR7;bZajBu&wK92i#{8Qmemgl3Lc24q$MEWsxTMqgJi;*mv8CrnI5O}WBYQ^Z(#!7s zm4>I7vyz8&RJPTtk^xKnh>{h3sV5C;lU(NtdCSFfYX0}wpblz68H*II?1N$e+Y$k533aK+jn%~E*QTgt5Cj8W@`^d@_pWan5WhezBG0ziHRs*%M z<=bgP`Q6I(hZY{pu5+kERHUxx&n;ib0km4(M|XW}=;xCi7lJxs!^4%3pl=#bwjVW0 z?+>k)C85oMT6|e5c?`iGx(1m`>A&fEfHqryAb`6W-lWHj;ST#BLG^e}C0iHV#YVbU zevZ1Ad#)_9aGJt3$amc&o4+6;*T@(&!SehdZLF!Ivo>($$K0SRA5~9Glbdkn;Bjrv zi{m^(qkT&xHF;(wNsF-}HbtkoekiBh;)s8<5_@k7W}jpKHXe@uBdw%YsfNf))YptU zEI}Wf^yBzh;d6;|pigMkDxylh2K8HH3=4~CF3Ut?B;#1g_;aQTIy6;R?fCrtmmzZ- z*hlTOFL!~<|Mtga3Q*e)m7pNts!l5R?ClRfU>W}rMRxyP?;HbH3BL?FMt;{ zeu@IgQQ$xO-Z{f^+0Q-9GKJ_72Ve0qlwQ#Ibfx|-q83@{78V^Eew+dBY3xFa=zsF{ zK+5ac+O>Y0?ALe!G|~`}U2djby`L0I8Nbx26_!!#!H@}R;hFN708)mb)b1yNQ)s*I zs$a!(WJJ=!3FO-r;xv1QX?~pX>KnxTkcG>2`oXhEF3fF(h93MowTp7^Bz9yV3?5^0|WEkdNfExk4Nl`O`(2Q9+vCg8XT4 zndED?^4{ydkElx@_>?e5^d~l6BEm=zg$UNJE|>TkX{drMt?I;g)~?(adMJ3W<4kiO zT%HDMZYcEvc|O+fZs+A|unvVbZw~pYb}A-Qmd>uwur1Ze^lQVycP}V;Jm<(>0WhXs zO01xV2&LwjDkVktNl?&j+q517?n;1TLCy@P{12wMG*j^xTI`I(DRWR3Yb7Gq^5*>1 zLAclz+@694wh{fiA`ll#qgJ_}MOdl2adTjb8A+negj(#1jyy6XO2eCm8zl1Zmeado#`zkn?S>H92v7e4pk57?apc)`KyYyyoj8rZx*NjEfORD8LfDdhWW>x=}C$Qnz={@OShvIhs_Nub+E%z_*p+) zKN$1D;B=maCs7pQ{1`>G=iM7t(RlziD1-BY&&D0_`w#X6byPNYQ$qANnVZ)Jn6Dg( zyKR@hV1j(xV4N;&jkho6rsae-DY*lq-KPpR;~mg-rZ}O=`%+abHXO%;Eb~yAGN68W zV=4WuZxXxbU0{X5I*@O!OvppAvj%Su9Mf{3`BclJ%aNqJ2f6fr@5O&VWK08r1iz&O zkE@WQXtjuU-kQ6v_xIURK2Di_(FaJ{FSQf1I7qwIr> zFm7rBiG#cI?8^80bGl-#M#n&sBs%c=)$cH8oa83f=Ze1oKh_M<>yA`g9z!7A(zfi< z)FVt&PS-V?j6F-T>X-it{u#p+h~qZ&o#jj09w3hZP}uOs!WrZPSDwdWG8aVya4_ZI zdlb;1ZLEPE$z|>M$cz`-{*0IO+MO;RrFYzkv6`%dvHDT z6$Zu&i?DqxgAd8gPX)=2f?xpPXIr_z$aI5DB}FE7*#uoK)#@N)O~Y868fH-m^;k%clX7#UyN9zT8?-;B7QG{T8RhjFf`9OjD7u(? z*za})?rga|y(acFueMqeglGooAtn1NG^hF)*7AR^p?d}I@$kJ9`Tj-3SggK$a6r|A z#9@*lR-25eV?r6|nreM2j!dp>sOHIgY7wj@+hJ;7bc~J$G`S-io=(!__tyr>g?Z^G9(fpk`^sWSFL=XHg=65>5B*Pi%c$NjC=WYrNfSIM$edZ`Sc^ z{uaE{W_w0#M&zIVdHo#J^`AC?`nt>p1QZNQp}l{V=1RPNVi{conQv3VN~UBEj0iB0>NlS?dNMH} zKbVqMjv!VumtjyLJs6|1ZoP0{ha6>KU)GjxZH_jD5FAw(h8xt}G0F_3FFs-`?$Pn4HNxHyYFvb% z1*~nG@$H*X#Uo3HQ5`F-+=L#7s61p>4R4VDlx{^Oh#UCi&$@c?Wm$I-tSW--lt@@efQf6;@9R3gWjQDHUXN+UNI2`5^f1;s$3XB?; zQEzLx(2Uno+p^jr4U4CVs_SRvKJ3ohWQ6ybeV_fN!rBPZPpNX{4ccMYlKjc-W^X(Lak`Cv*#APWZ4TjmRN4 zUk{%4JEH=Ag-4<<@)s?T1Hz*PL4cx@b!Hr3Fwk5a`E&BZi~YT>6Nn>Q(*XLusN;g6 zMmAQv3f%d@AtIN<4J-iCC@*^egwBeAaD zI+Pl)SF#Cj<9!T+kkTn7i}oI$(=DS7%9Tr?E`ZlO&B)h6fN_9-{8E?%Xy zcAGrMnA2+BlCZfRjDNvHf(eeh{g7V0LB4#t9Uy|iqKIg3c($Y;*!B(dAH%f)j;=uX zU>nP3>SsgwFDe57Rh#ll@I`ZVMuu7pwn#y%48kp0AtQHYpKW$?prj{JI zLGU{PpjN*>n^1tnVoJ+F|HCnR!4>{J=n5ItaKJo6fEEr1Z~FP_e~JK;5=UWLVFI2Q z1x-5kKL}_Mp#DgeA$mb#UMAian126bf_D+KVR8j9P{LJ@pZ&K#D2T6Alu4M%2M%Lb zkkoIdd%NG?L@UCRw7Ncj(I@wqK=i{LD1&;BayuX0iu*wg2(ei;{g74{QjxL4+^>PvaIK zD{k;;XsDnNDDRE@ziShSkn&OE%#Mmi^8OtM0RAH>*+x|SAPGvHwb*xrqCm(&0m`S69{k9jra;E9gzL-6|#4 zLPjJ#Y!+bY3`|ZQ2ffAjVe=;_u>x}|U7_rx$ZPSw)w^Up7 z_xV#h#-95eHT**+psSyZ1Q3>>Z}9+hZI*6!e$AR#>kx)xe(S{sjRPWZBPi=7Bh69p>vAg($S@5-2*to zpg>{*NC|=eY^V_>GJz^;JNnX!kyPmKa3~FZgFR2TviwC*9JV0syWhv9SS23aL1AmN zdF=@!{HrBHaJlk`-BGrL5!v1-t_%ZFsWeNy$iN`={tX z{{sL(C5kV+6SGDKeq)CSz+2J_b5OFnx0Xl*!=grWb?Km>bE3ZbL2gtJA2N*SJs*5G`NJUle0Fi=cVIzRNL z>OgV_?kd=dIvX6p2j3NFBl&4RSlxRqoBN>R%hm!v@~|K1n{a<&xFm#$#dck1Hqap` zpP3rS;)}`g4{2MTe!aXz+5({ z<#y#i(-(cvcS%-*Jat`A2q&-m`zD5HIrC(6_F)=Gc2fRA`3#Ul4TV4b9-1=sVIIaG zm~qr!Zl^B031$X!hj5gl_lCfx(meuvtp7 zRL8j_Ik_~aKXMT%c|6ua!76U>r{Ds^eoU3vCY?N;)pxzC)n)Q=zUgQKr!!XTk@x6> zSTNk5`5>RAttTSG4dhGxzfX>!{@QcsHd6?^j0UpS6TByi6Ca*JP|z_A-j&>(mC-`r z)7ETFr01Oa6{ z@AD|V$h}a+X^~%!-AOsd_u_u64aELzzxO;J2EA;?npesHu? zM7u)d|F%FM9}ZJH1RrO*uCe^A2SXE+R)w%1u9B>-6%(5MdJ80-sksnk^s_{2y*lQw z+HpTFNpDOs7B1jXJgr@cOn4hQz?cam|^@Ox<5Ud|?K z=t2!GYeE?tvE|9wxoRed^(WI_Y`~)pG|_|5ol|_IO5-SfY{pgy1$1mxU@znb%_jSC ztr05eWqeJW{{S4XGD-;49 zaY+w4Y{TJOnxAU(2O{L&9xXQ?&?dfwFcCz;Hh`_!$MQ;lmK4PJ9>hydaZ2$Mq@a(Y z4X)-ca4683E38#MX^BKKVFd*}PS8dw(#u1%)JZmAp}^DbW{RyK3Th9+*5T*`r{ta| z_~_T1@D)%s>NzHXU;{nw*Bi%gF1(Ix1*n^bWq0hiEZ9>0>`#adRUb zqOiD4Kbunz<)z+?35d}I)Gl{saS0(T0#P?Pl(=>?k4ls?DVatTC)U&zhcBtJ#B7R|frU&e4LEX`f6ONV5>ssP&IRZ+zrhgNzS0wS zI2*7qmx(|0GAE|*?r!eWU(%p4p+}ggs(i)O|Cgd9uqey$+7E!eqBsw)OpG}bvLbf? zq(KM}$Lr^({3iCXZ%SvhZ~OKBYvoS08pIx4i@N?5Sh~s!CW#HBSR?Z+UL& z`1gr@0&%e4^)YrX4cd%y11HbVCVF6L0UN;x;!0`n>J$TGU_FK;J11k7*1P-WI$N4S zf09`ku_f%nW^Zt^XTz_1B}@!=h+g8k+l%L{IgD0YV&+M>%d5jE+H7xGV4LJ)t(iL~ z)fD*dB)#Ue*nnkW0FeaCDJjczBBb^P{K3iJy`~E1;*x)?*G-|=uAWo1l2RAMT~#EBK$@`hnu&d( z;9ceI3(x(vt5sd&PsE5e>w8WypVS3RFt2IVG`WQA#Ub|(Ny==UZ;$j&qOHqDO^E-d zc37y$RBd574!BuDhaE2jCF$@>!CxPIGFaE~GEEFgHLiY^UDNF69SUhqpISXbLUK`5 z|GshldLpMH{I6#n!C_wf$bta(l{mw`qNPifs;M)4NGl5f0Cc?XE`AZ*fAJbX)o+XP z2#9dE|M;e%Uuy{;c%N=XsnB*NP-89BDZ!QhR|GDE{pJlr=pc1c$K^xzf$0g##~n=^ z07PQ8Px=G6(Ck@MK2fSYYpF7X_BOt7_Vs*&3D8@%RqGZSGLcO@52@6hq;Y&Ber z$HH;`F*k(W)S&3)GKUI=6^&*O&6Ti#7|$II*5 zP`@%Pt!vDQa;07uNf%Jk;-7u2;eQEC~Y z-+;5Hl$8dlmpKNC>Q6P?2Rql-~3zY3pSqA`+S`(V-E7WliRKqfDpQt$a&qn*G#e2brQ$V zSbBx;4-#~#4FBY~_|^_SV?>p(fcVXR8ZJL<6<@NElL&z0AbvI#;P42m(ksVLL>+a* zFg1&G3f&5Jeq_8gjRe7i?F!*tXL#uJqK|-@_{&wWK5H8R(2@UmHIfapJ=__G+IV6o ziRR^leKM$p?Zo?H3!xENY09Y{v|?XH7HZs3Q(e>M2Js?uM5}9Z-xBhrTN=<`>0VsT zp_^wyAu~4=EhfzaSsJmRrFfNsAIGC0S-{|T^ZK2H9`6{Lrq z08iqiTpVvi6SWv($-2_yuyE16yC&;(Vv;0S0_ue(=97pVm7OQ&B`!nd1papU!Ihjz z9>jb@i!jxRprYEB{MTo}VI6bDjC4Qo<=&v{fFhLNuPX9;a2vl?AL$n&%)V5kCym8VTGZLvmYChs&z#@C9{li-+Pp1m zWFh(8MYZ;AZw7YbU(;bu`8Ie;{16u{fpk;wU!{@t1Q)6G%Mp4^^0t>w!`L^|B}k0mkWaPf=J=<;@fN~UMgw9}^tMV!lX_cNY<%9`61PF*d1x_1l`mMYTEWn3)=bkk6B)w4->VI&|Xg~IKhwoUv*1V(}KB3u$Oh`1o5qUi8IK#u(aRDDWJ6CqdOf__T7`jZKdPfo2IeoXAjBW>{Hx9|h&%4; zhJ=6!ykzw>?gUNhHk0qQ=3cQUTzkK9ugHIs6Ui$GfU|@BCk*6T81)|pUpVq{`TCYn&Q4pK}{C_VZCIP1n_gB;M zB9JEM%gF<&{YU6B*q1k`bkE#Aa~RKpV+HI2ye>sb=j2%&%Mix^qSVToqGs;=E`s)^ zc8okk%cvZ+>dV^C)E|I^h*Q?_0=q0Kdhmz|jelr&0BAN;jrI|8Pi!&fJiylWtD8#2 zpa5>xCytaGklbrU-)zXo)Ze;4sW8VI2`q~DkT75%s7Xx3#+ zxo{GGknFyDi;#H!Kf%0dVPjyDk6DaG#6ex4a0u$Lr}+cEylxdQAxZDtoUNszevn1C z`8K_n-<`*7t@#-Q!e))%gUo=Ro@jrFx8jjnDfuZF%jd;dJA~Y_u;%j|dlh^m=gAVd z@8Jj@0q7I(>&1Lho)eS8`?>Q~v_GA@Im-`uzzf`f45};xuhoK+5A)?O!&wFk9}uU| z1`{t*+N8F{&r%lQBm#5;*O_W$wDbRs?)9c?f&eZc`7tCkLY};+&NMG_jD62NGddeT zHN-X~Bd5IBc*hd>+}e5QtH8WSP}_i=mc8bX!)UCqkNn zr>bMiQuo*@h^-%!SETQ=!KbIL3IyNPVP5dXbm@y$rOi?YV)_ygIhweC&meJ{z#&hk zmnLoOm02f!V$!tIc7A|JD768;J5wmcMo_y;UJ3xk2wILYpFa@7@nAd;U1Kk63sF~` zm8KjAuD)}@I66Jb;Esd)fDDln_v42MlqP6YDw#QQN69oRl9rH+oNUjh4E2*J zZ@{HFyGblmPt9rKMUS$Ba+B_^0ZiwEct-ew_iX@qzMyAah*?}nticEvz62y9HR3A5_wYALtO z86T!}xGrh8e}cC5f+26?nfdv8;xh+R&&REAc<=Fc zLUyqW&eX)7V0Mm~J6&$w0i$|#Lo~O%vhvv2+KBJ;*fZJZ-{E@4E-zm)JOKr|YOVWy zlkmlsOO3nY`U5#po)jD9w7yuSaJDoF;oRR}B_R2guq+Sr9%l#}9t)+SO`b}n0TSn9 z0e(-sx@w_t^EB6^^NJF2H^0D0?mD-ax5ZXg1BSz+NaeGe#jK1yh7`1;kfMLv`!T-2 zu{7SX0l~s!cT%Y?3+R-ZDWKhXypb_lLF`Wp_>fDS7b+E5@euoX`YLg*`1Pv!v!Rqy zM=a#y_6@5o9bR|kc=goXiEu<3|_ynhJlp4ia?0rxAWWG!Hu z+|#HdD8IZgZnZNb_## zYq^n9jvn*T1qq|EAMYd$H5n*4e^7_L#Tt=#Tu(Os3KtMNkc%Y&t9*;X$H#Nx+B?bil>rS$1JpO-SmT%oOK#6~0f1&|1L!}1rWnN^vZCxMv( zoy@}VV6kS-C|!=oR8O1RXiuQh;|}-yp2CgUETen##@xOLPymajwEwW44v1ZVJ=dW1 zDtU9 zhJ=&BxG~x$#@|QdN(L2ZEZg`C?Fu2LZj;E(A_>Jbvi%$}iho&h?25Mir%MZBE@TTW zJnA$C=W$lQO#7f@#Ip30jc~LXhvd5g85PA2JCOakvKvi1NF!sZfBQYaBrz!p6Ba(2 zB)OqwqTp4{lp)ICd(Lrv&nFTchnOY6J8YxemBr3VD4LbN4}7vq7KbniPOk}1VNZgY zi(+WK(@kwc_YcTf9OXeKqw;G*IW+1yVK2qx5n?Z$vOuOM zVQuBytk1$xbXFUq9O0E;8x)l47Qf=iGDvk990d4$U>%2uz|i#@5;{B$6A}`f zREQGLYY(Y1U6w&Xq-0+^)WO4ZM;L54gnec|SgP;1M3Sx{!yx6y^&J){@)5d!4`GaI zO#Pbj(}yc&FVPvH6qLiA>@Hz6# zbppb)0&swi!8bq0j?)JNx(AsRNpt;R>H6Tjm*d-$ZD~B_pqV}D022|KfI+j*1H4Ds zbw^e!5+Ot0UB#QU7Ji;EAHi~-Q?-4el*jr9Yo>;zD^mnPKCbR@t1EeuAMjpm8Jnt} zl+_)R^gJhf#32>eWte;6Jv+{SX0>}w+;!=Kd2z+$KIDe~Ra*0oHRO zd1XCbpydhVWvWl0E&jpZ-+;bkxlM@7y>No(TL}8tMl!-qxI4gvlj6}7w*K&-P?bt1tplp;WbUYz)HP};8e9~#ZJ2ng3Yb}PnUl!wWQMWM^KeLoV!P}c6inY!(y&N| z8j9K}5HoXMju*8etMW%-Tk2vZ=f(OTy=FjZX<3t63uQtv5E+ask#N(5l_&(9ZoF>c z=YU0jyr1$i*kf1|U%md(gjUb(BuU)l5)cVf{Zg7r+`yD{Amu`sw-`)TdB%*(J-YFf z*k;#Ul?nTbHSL~Th2VY?7Jy($BBP~A@^;zZN%{x)n!hKu6T#-7`HI9~i!q%~&kl;9 zJ(AVP3UPFMkUwUR{e<5&2hzYxrFUhkD(uteTA3cyvcQBr*l!vTH?_yFlMW%%WSJ|Q zukY;Q0A5yeRPr9;b5Qk$Vcc6`m%xtq)YO^**%z z{s27J1|_wY~={ZHRyD=9S92fz4Jx}P*I%x%GMAmJG>;j3f zPlR`AqBNufub^?EOLGdKMJQR!Q7o~Jfo5i)^`5?aOYZ39me2;RX> zm3Ox3R&f0Os8nNr`8YU zGC(;nHV5bs+*{M|x^FHt8zMlcqsV#zTADn}EXe@-d#?~U7gil<-H~@3D{OjHQS`d{ zmTs=Fif2l23;zF(m6c>18~4_;JtvAwEa#9{m_Jr9%p-gn{YP}DZ@UydLubemc<$hc z;Z0*#R$NR9T{(j<{*%?8rvczu1wIitY!4?9wQg3BfuSD=Don_aNHU*#@@r8Zoml$Q z+}u?6PnyJFCHH|BxbQ9o^SdgqxRh|2Mum3URCfzbe9_o>-B{*c61a@({$un~v!0^P zDK40Re|F<%*R_p@N$(9A?P zaz8TSc&0ZtJTUx7GO_qV4B?2oVq>S_>t!xX)$79Ih9%^1(S}fpJzqR3aMWtf`ianK z;^%k^)v`f08@VemC`qC%&h4>#L4|n_OaBcGi+Y@yj&(Q+mAzus8K;D#Rw5+0KD3?D z!Uqo}5ybFPcW6e)XZh2n`FbjfA_9_`oQSCIO~V!LBnS{VQaH^j;0(gMgE zLDynpaH!ez0OL6_8-OV+W0Gljo*J=BfYPdaLQ4UyUUx5z;y$mRDq_0Vb6ouQoAG8b zB!BgtG$e;V1H1KN|17rN`2`?Bv+izckvE5ckWfvhiS;~U^p^&Wok^C4h1!O$w0ruE zYs)vc_uy7hpy(XMKmR+TVsJXRxp{H-wRW3*Pte^x$Go( zjD|I!>z5;reVrN0dT2}QUUL@@ECKFBamVlK?09_*m1flZ?sy6xcdImqNI44Ro*7NC z$7}_a?-Dd9WUV|x!uEuj^ZQys-W1#^F8%RfxL}X|CKRqq6_%lNUj_eNOz0bqUBIX| zT6fjp1exg(^%%e|-Fco!S?0F#JhP>T;CMlFl}XQxuJ~94@k|{}sgo zI{gFoi4=sR6k$mRT?L1q&YV!NWT+IDwoG#WXSsA7 z!E9Gbqt+R=OWmW#^6X?Z!5;^?mQPOLo+$y%U+Q6Cp*6;}{-zcR6I^Rw=ogYi4d+EI z6i$BMJvf}4f~zSP@Fo9Qy2+u=D+lj@%UxiQ6AwB7R8A1@01FcZqU5+3q(lGMWJ$x} z1fs3oC|tcrQ2djgZd`6Rmx&}C^=;S&$!CN+hwZI z?aso&HWUZXq0eC7QL(QbJpKRkW#>|l5c%xB9HMnfF|s!I1IVXa9p-AD=Swpm@gXxR z>iw0sPw8oGPaTJX{F7aPbzeU1PgA|BQsJ+fRzDxF|1mn3_wV1Nq^$bk`+Tx895-V% z8RnAp@Vxb0>O#zhoq}Nq^L?=dpl;8JoeY0ckSg^Y@km0KxKUX~Nmb<>xIqJc;WeuZ zs`{xO{Zlw;!A`CJh;EI%DCOzpiVb*IbP+#y0KXg;y@0QKqJ14L?^F0P@z1=?;|rke z_&Ncr)pOT}8zyS9LmOP%K%pU#Oz{W!X_LFoJxwy1jq%d3gyvZU8$)|wbx3z)=0d}n zFrNku2{%}06vagZ73++8e?#_Dk1}G%gYKwv5U?5|Fdgkd3 mZLIopxhQzw-mqCrs|o+UjdC#kl#&gWSF*SvgVdYo0001xKusqA literal 26304 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 M00070Ju(0Q0CyGv_W%F@ diff --git a/screenshots/mobile.webp b/screenshots/mobile.webp new file mode 100644 index 0000000000000000000000000000000000000000..21b5811cd827498a5d815e38668ba5874d70e9be GIT binary patch literal 77414 zcma&Mb97|gzwR5`R>$dB9oz2Mw(X>2c5K_WZQC8&wv#&P_xd`;qt=>p zE`0GkpIHhLqM|x{ z+{y;)n7&n?B3|n@^F?ee0?Hpv&j}`c25y(`5T|`+eJlW|fPi-~0N|bPH{Z5T>*vQO z$tT~$)oJ#Y&k7*s8R&x*ApLRnq52_vo&9x|mouQ{^WaMLwfQ6aZL`NG7N7$N{Z##g z{M<^Rf5^V{>HoZZFZ!(h#Qk)A&b}icB$(>%^cno<1{~a_17JU&+5j(nuLN&iy*}wa z-hjpzz)d2c`{VbUEC3*xJV@jza0?>mC(}puGv5vGkPrH6_oM8&?ml21VDi!S9Q`)^JiX>~rCa|w_o@8$ z=Y`;Ut3h|u$AP!k2lrFpBl->VMfP5I9bol2(*FH{IRdSDuNlPcO1Jx`*9|KH&fWz~{Jo3ef742_SkK{Y(Y`wh?c-kNEa| z+I*4#Uk?lb`0Q@y8}X?JNWJ|zfqv?K*m?kryaW3%eYOKo-|1hnSE37Tce)P%;Q&iO z^#|tHlzbRIi~vM{>U;I8?aI~H4*)^FM1Uf|{^RWZ>a+UJ2LSl^*a3V3w6EhIuK-tV zeCJPq>IZ_0-!-iW7=`5I-TV^oC0f5>72@N!a!5aw=!AkwB}T7iP<*H`iTV}__MeUb zkb_sRu|`~;m4f^18u1wz=7QB&Ol}oMw@s=JzaV9gr`DnJABKyYIt;ZO9dgzU4+I9| za71EsVelp#CpRe)=23IDoXwuXv$t;g9@SsZmHiH$L$7R!f)(N1GnBj>M?h26E2eOF=Pk3G@sLhl&hM9=`WVtn$^~_MIM-}E zf#%TTn>foBTdn4a=`E^F4#E(;h6>Y@RgCE zkP3>%;!pS4u3S@!{>&%uChw^1IZNZ9>-ERF!O!{tCcn*fz@wFvk@fbCf01iNz@)1Z zipt10Hxn{ySJ6B;5;XA?Eg5piNG==q>^S~89kPfur5N|1ZkwD5oqB_lk3B4Q87$mO z;^p}j9ud=6UonAzLlhfV1Yh<(?P1~IaSxU~7Bph#Yw-~otmb07A9TbIXV>hnB;|;pa+w4$#WJVpOE|jLn8p8sb%2WVz%gzX>#q!LB5iIY57;R|aLwtq1 zCI`GrNf0td>k&-?K=+c{MYmoDmC?ZD;dhUs+f7D@?c9tT&H*-Jm1*~bg?Lvn{z=6x zG%jt~C{+^g3C5Fwo`Z0rDK13Vm{BA6td6$Kv}*tH!ie}zVH+!I?s`(AtQ<}P5)l!F zK_{FMOaEU=%3tFRtpyR+I-d)fM zdj+i1b1XtREB{4XQ4@qgGt(9dcn104St?gXR_AHe+f~}C^&Teg-3sQ=)cWp`V0+9d z<3PqI#*w-7<Dh~@2+hzLTpOg|aa&Ge!F&d1qQDQ~D=#SMGf$E46yUP~r z3qy7%j6UKG3S1z*6(E@Mf`y?F+4tv57tEU0DQLgLEf$et1dH*EoJk{@yv^|pQodo1 z%u31Gym1)Q8@)31q}(PG^POE`_66nS5MQ6T{{H4>9 zbap21_j4gB;ez%@{5As-R?|o8ZCEut{-~-SLSE|>k;n~ZUb4ZBTaoox_pGwu9og@YHS9NhIW( zHJSOCF?VJU*0kLfr|s(D5b<}z^2}}zyRot z#%J36&G1z>io}M)l1}J!Um2q4l$|)<)6Yr^!NurGH3_{Z?@&>*3Bq|vnn-RdPtX#j zSio&Mi{Thi+b(7c^BWjN{q}aC4{*kTb-u?dOh$=x&%zi2UnNE)S>Odxrsu)|Y;sn# zzkfaWEg=6TG!o@gp_`Yiz%>?%w9dkeCgt-kt~Oe0iq70%46cIY5oSJgjG5kOvB{LaImHu|%mn%U<5;@VYwt(M;g zKRGQ>6P{-l3;#ZQr0TN8V{9%7J32NZpZleBE>NfVMzJ_}@e1v|d*@W< z@)$`xKcqUoy-dgJi$FfHrzc`2$tK&mIV2F1c+2xpyA*tDaTgs>A$X3Ik2v6<1rKR; zpGnO|c-}fN-AB*>jm6YemyudDZuEA{F%2>%znkn&;|4#`^UE`(90mNUXda&mocMPv zy>duGh+QKk5BT5K`5+d*hwo>wCVXMSgAt?>#afRa_UHej-+IFr>^j*bV#F+rno8pq z0vogy6>Z)G)oO~3Q-X(End|bzFv}_>gf2dXAWwkwl ziZ%Uj4V@T=*q<_}lHJ^f4b^ow^62BPB_Hm_Lgh7x*MosFr;30GNt}fH(}@QP1@=Ia zp_+4>`Gp9EwZnpU1+v}ral{pB@JvK+Tz~iTik(sdq1rGh+!+^Y^Kt{MbFy;alieA* zCu>4DLiV*_qtjRF&v1-f9|FKgz;)y3hEe8!*AoGU9iYlfgov?|rOhej6u*OJ|)oE@o_R?pMypuUmmeC>2geRCVZAyxe18^@aBq3Y>zUC}!l{ zTsL=G0T@kGDHL{G^n6L1&#GqApIx)-23nz*5UxRX2(1qti^DL8 zij6#7p^)yQ$SGrAn*3{V;D7#59vq&)$@ z#e^6C_G<F|AK|Y_ug^xg$A;M6B<6S2N!Hbzg`7D8mq19};em4q!;`r5Dw+1Jc z$I@H0Z|g5yMjr{hb+vxwgfW+1p8YoDZ>H9Y7<+ypQ<`wZ6^l6+) zREZ!`{Nu#UH)9{GNyK0!zD$RQhCKWtX)C&C4Z5zFcj!Gu%lT}Ro&4v(gWa&KAdHFJbE*`V;mIxk9OS{;(tjt<)UWBHbH?q$h5tj?@N^8# zmk1lPW1;X@e56}hP>;paWr(ovLoWT`3}anCQ{Lf0Mx|(7J8)JNbS|Ibo4 z)}>>jjU`)N;$H>p-=+W2J@xuTzU5Nh|5xcW=ActfdwZA5#3f>Yc!$3P?DA$&w?+T| zsH*=j0p`LN8m)8W--BIjOV?U`^s>@oePPB2eNDVely?k~(uRmQmD8MJf z2KEG%ZGVN|C2{qNIx*dyUTaAaNsYRlS1Cq=yL3HV7*I|%cuFr)iHtNnBBkxv;X#@I z&_Q->Rctb%AAyAJtVdoq@A@yo~Blx)Lyx=8O`YDkj?|J8&G+k&mxU zdrt=l*=Cekf2Ra6g+?#!1#lEpro$q-AGb^5nlmP~p&8Uhq zj#S3~pWfx4R~JW^*Gx&+^$Fyhce%J$8>vjOUSdVE_M7-iUAfVUjNv*w8(pfA27I&M z&+W!<&iy~s*M2>M1Kn@lcxH>wn3pV(OLpPnCg%8N#>5xzed}vNS~FNH;tb;vW^$t; zoX8i@l$@z(9vPXwr-ZUWZ(L5K5hqxe{qia{xm3^Scr+)L>A}Tb4mUao#)>5kjIqv$ zY3!k_`xfz_W#}9}DJ1u}+C-6wBDn1Mownv!Pg2}d`dn#5(ZwZ!<}9JJ;S?={#`H96 zHU{XXdyD|;-gK*q7bW@X2V|WL$&DYPS}q=}Bv|u#n5QX5HqTM0FWiW~Dz-#Ob)q33 zDUUuOSJaBQt}|$*3v7KeogoK5@*|ZJ&hkoQX$a*|2$R`x{*ZG zUSrDS&sgZnQV}+rpQT4kLF<~}vi(XH8}g!L&>cJ0;qGS&keB<3!tvcRGBI3gYr*s< z*1u)_=f~6GDcfPoi86WVBTF3}bZEiZRNp-DJ=@y9CRLLnE%K}r`q67zG`%Dq261*@ zy&rurtF^eodE~3*q8IU)4q3x1SrP$e3?o2Da+G0jw;z2aE_~`QzAWwKinBf_v?Rt- zac6v5z)IoN(S5BKS(lr>zFTH?pc}BE5SPCYz5K{+qMlm*1t;?X{UDsJE=&p|&B#h9 zGukMHWBMPes`a3?@CEYG(i6NQdu z)Cgh3Do(|ET||sT%ezLNMz|sgZ?|Wq87^yGMVhF@Cb})k$epLo3n#jsXy+aI3W0^+%LJ- zInhcD2)E??&xn#R&4tWe%&4I94Il(@+Z0j4kX)Qgf37PB@7No$Yb4}kR}lSGGsn>S z`#L8RbwJOZX*|#5hs-idh9Z9nf@B{-B;kM9fk44T_Os$@Q2M0ie^t+~xG4DYhl1qU z(h+b5J$ZpT;v|Vo>CyU~c_c5>IqB-HuE>=^XnzgPD4tNf08{0cQ%!f91bj^mE-Dff z$a@gLedYttu?2%vhn8aR=+mCaxL7sLU)|2@ebFq20$NV-H+ZZBOB+U1~x|$ z-H-xYgHF$YtT;ycTs4sd*1NgP;;SOvObIg8o1)~2UMbX)O0NC{0P?WlYTeI1eR~a3 z#Z+BK6b~6&xJU2V77%p?;*iIQWe)^Tw43E)xQJSuz&e5wft#8$U9rm1-`R)+D^VNj zgemK+^&DuN;PoE=fig)if6pCc^n>~;ggF);dZ5$rN2M1^)W3h@@aZ*fL!*)-EqicE z+p%ikjxoJP4K+XrkShz&tsdqN6~4?1AO6dGxLA;Q8Ywy2BHsl5rifD=^=1aS+$R}l z%Wc^J2C&X#hc+jY4*2Aa7bLiU3`9!g$REecR_1Jqo%c0XFcrsXtxqM4w7jqM`>#37 zIP(Tgn>9cN-xCZs18=_tP16AjlNAeet-2j_7%M#R&sCp19Poc@c(KrL zJn`=}>3?;=eI32XR}G+2LplusS8Be9YgwK6MGI4j^_9u8XQ&>r|3g5aS7H8}gHT35 z{T)Wh!Sf0tyVn?;`w#H?+cb!LpnU?6LU;_@FF!e5?EzO|Z~eD;srmrJEz zogS6=8ghWX{ZFvc@S{Yqs#Cg7%}uR+Bt%I&AlXT7!ml62hfB6r*4}m@!kTqZ)LZ?@ zpqc`zFmDZkpD*}S!ev;6{=#kkB>Nm+DXV}7${GP96g=yay2?KJNbL1<;ypAoO+q34 z+Dinw_3B%aQysIQxzg> z?L!XdJ!X>)<vdWt*#( zuQ(AH5;8spotHv|SUbqxlp!hZ)IV(!>5wgMNOxIY9o`oCrzaP-lz%Cwxptd;LKh*& zsb&;b@5xiC?;cm_W75k@7c3-rmBI{g4>W9YE&$YIamN-Q-GAsLL$rL|7s-;7T|zol zaB$yB;%4D;MCD)&Uo`I0{60rp^Kv33i4t|dL9d*2FC1)n@E3PXF4(T{UlBM55F&7l zt{UIVhHav5BaP=E?{~mtD@~W)-eJsZs7VN`$=j^De+>|?`g=$Jp`b!Qs4BB*RDh`` zwu#Ax=Yq`gA;2lNY2XMSee;smTj?lwJ=8`X1+-01m5X*a9mpF~5El z{n3?z8pro__;00r5e&y={0|Qj*tp}q{LdT$@8f~6KFtwZw_mR;!%rprOOZlied$u; zD1Y<60QW1R*pq5ZDs-CvSt?L_Fhpo|G;-Yc;0qvSykejUA}hBv-`Ci>aj7^8u(|vT zo*+j)HV3T%7a#3diwcq5=A2^cf!>7bU_wa=;UG>9I}t(ni7b^OMcG7mO#^C+;2iW{ z;LpYmy=$Wc;@GBEGb;^bndzD5Mg_hJIZ?H}<#LWPpL+jj_r?Q1__Y1?nv%q?0WGi!>Wd~$nagCzc(2L zeOle6wd-*|GIzP<=0Xo_lgiF(o|=GrUSjo%ysSrER>!~_yHiHWgWvjQVJQQvfYi!zX)<|7BpoR;OEB_|CRa=d#m?HTw=De@V#G0DNKZ+ih0*L$!d;=uu zIA|TFINYNBxL)HKWjuIhW)VJw2L$WuLbAvF=Vht{t33^|f_xra@-O@x1vsr|b)N#W zISjuF&Vk_MPA8)uNCQ@VDs16sP;QKK+J3htVbzs^8aUMIIYDrHJFYp!x>a+%-?%i+ z!{zmMf6=z*T1wscrh?0}9q{PSz`OU%n?j&y$kUV^GC0a4h@J6g7up771P!?rv==7J zGZFj+Onghxws3!dVFV_LOGj*oC^M=;{wo6=Z{_j!;-=t8c>(|?5qL$Iz<@x%)SU|{ z(-DVO{fKad-7TD z;vq9|l!#?FRlPA9cV>cI_$Vj=yDWQcihv2PwnlgjI+dDOgFa8TNae3-B^|=9{*l9{ zf^hCHcp21}Z!TFiR@n-L!y6$ja=cz*u{VrFgyP+F%60+%B^$U$4FO+!4$!qY7NUZS zV+xO!XtP60V!77T|F}DP)xQEFeIm2Cn;(T~{)<{;6mg)}{jJtq&r8Bz)g!&%xm050 z2yG7JznUi}4CWS8QJ|ODHG$NwD?M>z4Td0JX!yRM3sZw@cF^YskTwWk#$87)t&zY? z;eEt&M>H8?!~!d5-B%1Ax55vg`=SU6X!?sa=@?yn!8}lJTqQ#e8Nt(gF4&mel%7DX z;9Z!n*ivsH^)Nn^nVn^N%p|{At$obYBrn*?YFmI^zfn(uMB`x?|YTOZLe)d=3dU1GGdwHrJc=2gZ%kGg`s((%*Sj?99!6PM~i|fmbf){ z6vnGQAtXcIU)3=X7Li=eCPjRw`SW>}k8J4OnV0+xEQR7%Kz{D7zA^k}%Py&{#&euP5I-2FZT1D(37z3!k`Syrhg2QNG14^nCR z&x2oL71J=Q!V#9Ohe>n?zcmlpcW2DjQ=n`pD1=G8Te#|7btqt!zcWR)EC+--8v;Qr; zWIe+~@mhqpgOAJVKQqB4cANTHjHI>yaS1RFDa>D!R|f|gc*kfW9;dukV*ie;h#<0$y5dYNg>TsjM6%1d^w~hgIiGqd4>+~5BWm)ch zgR8w^*G;9zom=VZLX~Sv?1kUqK#1|$cXrbV2x>VL8LO63ze%5f$SqHC(bMB^P>saS z87IZfuWoOjBCCn7lNJP>2gRKAC;YQ~iTBLW2!9v&Jes8L>C&N(D{Hlnb2z>X=C4on zxv7}|?rj*GfDl6=R9tV`)Ky*>?n&WA1>W>6g#=fjD5tndaM@qoIErt*cFA#A)XU!W z_LmG&gCzS@2$d*kl`+_B!}NQ&umn6qxyp&~(ME>(;n$v0@u>w$J4rx!_lh1@++gVN9TGzgm>itTZEF59q{=@Y`RTK#- zB&B8jBMn~u@?GRI#*AXJy;i5tds(Od+4rQjw#BN$Rum7q`^VgT;adGLYuE72D3iO* z61VWFIViEHp{FjU_?jXexkdUqTp?#ckx#uJs|Sh)z^`G3FGX^P+9vQJ7r%GG+r=k4V2waXJuY}Jq-NT&IpMJH z%&;vQUiG*@OO$`|C8Vp@*-(PjqM8Lr!gmHfQ40Jh+I_aY91AY|zPNT?6N(#Rtzh&M z%bNKjl`JdLDIEb-pep``219f%&-!H;sF4x~8+I!e&KP1(35RHRR7%5Rk`(cU&cTcG z;Ht@N2MIUde~`kx-JFd$m+ zT2C&$@Ybw`+eon4tD2+?_b43aTac2Q@wTu}mysssnd*lK4jn-(T1_jEpxs znt4X<`tSB0&=DYg1j4Mj+G5#3h83`sw{31jW8rkzny6kb9!+P?38Sh4*>{0&SlW1+ z%e0QQdH%dL>lUYmoBG-q*7(oUSQ04xG^3{TAD8x{&=@;#Bl^|<4V1`>R$#t-a513e zh(Uz=m#S^1P`zRXdD-iQCLcpVsjfA{Qi{9?^l_ZOtNz(m{lD#}(*OZ|eiq}MGK(MWQt$))`vJX9s=yj*gx4bm-56z1l#7tFYGs+F*IEirckI+i}oOd$EI`O4fEa^&CUdXiI zMLo27_D@_2NgY)0#>QWCI4-A|myYR~PJ@tPEJ@gOqkUr-$;?zPz)1twxCxoP$!t1$SFIz-K6JAoDcL6jBH$B5^&=bx>szy_{j>ZKwOTvEdNM4DrRQx zmkn*jFAu;=q_(^D4`YxsG4&GL>{p|NUZ&rK2WPqYBgimi4r?$LF0NL?>ztc{aD!gD zY1zqfqi8dpIAFkg8IkN7uJ!7EZnLP&?-g z?PbAgih%VFr4_zh;U@isP_Dd2SynAUitlXArdzcOIjxJfT=il;9GMfM!^y~*ZjoL; z{2-tVao|%k1`3lvlXDl$OJkde+Tei+-_xHhwa8#(kggmdc5ye^0gk2U$p*CYNaJnh zP3hw8UJWTqByMYYQ02~+!lAzyWK-aOv-(czh!`Q>F-SHi-vawQUE}8di`?I;(t<9( zU22dq)|+Yu(>#v3l8Ec~TIfX$PhN=G=d+XW_)$fnco)MgOdE4@cwvfRRjX<0!UJ}q zcNlNZtqNqV86hr0l#jVx>;`8HzxD)ybpkXiY@SH^fR5d+B4$0D3sfL#|B~YN^T;OVrFO%$i z{pj7@jqtNVttfxal% zQ9 zOoFbQ0Sm}h!>ZEuYO9sT(**OWtwjX0tldC>_uZpQYL#YTl`|Ul>k!pB)7BMo?Z(CfcG? zW6ZM2#04c1vsU0Pn*)Z_0d~daYq@w655%13sB^o#|BVOA0IpM|o8K(jYQkF{^B{q1 z)!tLSeMo_cO3R5r9S5vQ9@M%zE zrw2(%+*f*lzk@X)75h*?q_6$Vdxhj5d{**=84cxf0x*cj61#g0T6}0Sr1$2nsT0N+rQ5p zy}e$WtNUyE>M&{p3AVV4Eh|9RX}zV-n+)tWB&w<(p%=zSDf8+roIuU{!0ddh6cyK= z{;kWttoLfw!(v#sYFfA|AQHFK#48d<%qVyg=i1VY#9b-3>Bp&($n6HK`Qs_|t<74c zUwmBCeXdL!`rqUQ#+Y8&-%S3gR^jRo`Z=Ong`4{y7yzfPHZ z1-TZsfxC!d!lqH^CQ_&Y<_`<>7cUP-6nl7e8+)G@#5|;^NHRWHY z>|Cn{S`8`jQ~&Vo3x?O|ZKIL3emmB+9)zpW!CVGw#ab-v7*p6gCENqL$mRT}HbIra8Qbu1x(J6u3{(}ERxJgFHE~M69I7xuLJ8GP z!g{)dY7xB`n{Q6Fell$%eK1D{sf{X{xAfG#t1DFXNgV1Z=_W-{Xj2&yh;J0d%)s~( z*n(gGJ>w9hxg)eVEEdX%1!(7pDD3TfIg5zm9L?|9Kh|QKQ}dyP6sH1Q86SU-z81m4=KzR+Dj0HE zk*wcFJ}4DRi)vwFdX39JgnD;5^KY`*5S@AEELKN>swl`)`k)n{wA&^PnO4n z`YQijKMiBrRe%{XXgy}{rkiY`!Y6Pv`kmJ7DJ^XtxiG8UVX$QDhI0>L3qzs)^mwfM zoS1?L_@U&QUO$g=83*4Isz1R3>@D-e?k~ct(LpKBO$v};90q`L7>6HB8%=nQn5&*- z!l@c2Hg{@Qlnv12`L-d7V5H$Qaeshmy~xS#M`z6q9Ge)4BUv?KTebszHzjyLVeZ9s zukHg5daqdpd-=Z*4eg<2c+$~{}_IB~`JzEzX%6#wufaOne0_P}g6?Wbfp zHySt?c@kqNvXh!Ynwqa&nBK!){|C9B1B0i>+`=zPtMRS0!&(&c{iPEDG#c^~u(LnJ z3G^JS(8>dY7&;j_d8eL9AE(>wcJ#^dhhpqg{PBGNiZ$z}b8;|b{xx|q2F@xx(?>~^ z=$#n{H7_yH#K_oc2MB)H>*_^q%kQ28_ff6HqAU)Z-az}_NVz6c^H}h0A=Bw(wzdNx z4+uizw@hG0QaTG=&$DiSoEu9SK~KX)i~#%jm*O%&q5{tM>Y@$t%HMq8HCEVf%HYll zD}{>b>E|WY+3GZKV;?E|2kXm=5YF`hM9exHPGcz!e7gfp{NQ1QFFlpGkF-&n!rx!S ze7-4MPJmX^eT()Kg!4X^<&vo_p6xDDoRKsE=RXM8VgBg#af>F-cZ@?*l{WF1cYGq6 zV%iWfxC$V3%umz5(QbyonRy|VgR3vg4fm8tDZ1W1*Za<)I0xtm7Mb4#@*&-&9w!=aFdJ5u zfi%*&n2~RjWm^6-LKBiGsnKAY$be^zI}!-Va#i;G6Qh^&4q3x_&#+|T`*;QV>o8C_ zYIt6GEGbwjc8%v1O|~nRzdUVLFZ(EdaXd0<5l^D^wR$G?PYm>kpC7GRNTJtU$L>Zl zt$sqtR>))au5l;l%s1AueAcRoI6WF!BM$tDiagMRUBw{3txwk}u*eXh3P&yW{8pvP zLgp_lJ@T}zeU^o>3E)bGzbKkPm1tT?UCTsIsfVjUqfu{K}AZe8Lede<`p z@0pD{m=VsW_Hk}~{TGbXIYk$8iDP#KVUWRC4aH3M#kZ(DP*d}O_O&)Uk{QoC-dv)PP9gj zk1`z`_^j?Jq1s^{MSClY_S~Gs(hKIexkV3I`nNciXA%7`Y64eVzVksh+@ZWq1ri@Z z=-qa6y8M(9P6Fk1HDB{-CjO)lAq^MyZ9Dh&42hRV=SFeU%;v{8$0DK z%bUH7YywT3X$bX>roWG$j8K*L>%w+O? zRiBFfv~HiBeiFjQ95(-<*`N=LM#g*7&%e;3zhX4WvScTU#7Yag5IHg5HIYV$lX?AH{1JQ{U-(XQ(sBB~%Ggez+1a2~aR(H{!yt z;FQF7lJwn&EVwEOXxF~L!U2YxEI1PfGJAIj#?VbaXI)pM06B*^*;5FRFd!d&ni`PWNcr}Dxhbd$}9VEDh1g-2f;uY|?|b`~tcz!{Isy^nk7bW``Sv*TetE7g@ULJu*)9F%Gbh=mW^mnnsiYun~f&dGz;t{8gbUt>`rO``oSrFPvVJ$D-HKcYBK))L;*EKQY`t3QI}R@l`fKDy8Bl99@W z%cN6_-i0UW4o1pg^Z}!p(R3F13peX<5?XQ^h6k%j-xs505pSNpt{^mIdqy))dvUnV zir#wyu#t=Tt~F&x=0^@7z?-CTDFJk{WA z=KRq&$Mo#1ZEs1cmSA<8-ez31_f=9gYN@V0P|;ri{DS+q3u16_$r*m5Q%539Ixpmqf>1hfdy&>d~?51W(LEjSTlV2v^ zbmRr%iJoI~)V)?9So7hFEv7+W&}&iz{rIzl*vriVo^5kuv_;0C0tJd_wmlx%QV3Du zl)BM@TV6m;sHqZEF3Q_zi(ct_pnkKUK-48&fS^k;0g11OIg}F!+Fps_+rCP^5H^Rc z$}%tMA6?4t&N%z!FCM0ZPiW!Szvm)Sj<;lE^K3Wx=>VVZ46cQ+m%N9s>m&$62DJ&G z$h17C@T8gNrki^&p(GU|oldlyI4lR~_nXq9M851GgwoT0t%}?oy~9CubC5?ijGUzn zPd##q^0d#PIl*S+OxY%V2qG{#1)jKqIj9C**tZ`9n zGs3A+FEMJA-J6kc1YqZfE#jjH{G|+3*|w>*v|yIqFN`CMW$zVIlXOV`QY7%lR8iLM zF=yTS(^baRF4_VUk@d3}5=3Eay;Y=7Rsp3k2cJID%a@UnCc-v!%+~8w0?5MBzVi$h z#&}u=%m^v|d8bsQ-2-0arMOm9xVVgNaUCBMItNZ3F(jPLp%?G?c+34_@VyDUEx}Mwdk)OZyDOK@tfve~ZX79>b(CLW`;I0ik zk)vxVc7#vj_rGOxHz}&NRcIyZqapFcD>}KN46eV0NLL$cVobzmiMD}0&Y>xIOTD!W zr^VhD$V`E$d<36Z+(=T}vIHiP6kUP0P>z!H1t|bJoILDV^XsUU82)((zzXI5qWrg8 z^f?SU@j~WQCe2b)k_ukYTZnihuEOZvWsT0XU6LrG=UfFT6%&F-E8xF=sPs}wd|EM* zFuOa!Fjh`U{eUhytsIe3TWg9w&f&-^tv~ya#ueeDE zM|L5KzH8tPI_kxDz)RDWdn(i4mKlph*FRPIN=2YY`UAOLl_c0N{1~jH(B@(PSm?PF z9$W#^%jc8rkjqhTTv>a@azN~(dCMU5W-92B{OhHHOg96Kwm!@igt~(0v@!;d&as{s zcGVK!ci@Uvo5Nwk?bZt=A`aRdkX?Y596OV>-u8ZkDi%^>#%%yGo7QsW;mI4IC%432 zTTG2Op`pB25?r`9mxGJ7R2BzPFNc&CFt~iHX$n>HbCTUhFWCnI77rK^E~-#k;ZRJw zr_=D#;u20qvC-*5yPc?&oXvj{(7SeEn>>d+!XzOEh_(o0TkK7txv!H-r6;4DSDlkH zxw`t{dU~*yXdMYB$K=>M;QUk%o^0~_WjA!#g|Rh;)hKME}2``^1*F?{D7@3^vb+9`ATHdHK^D+_Wq%Qdc<~W`W;#< zj!UUb>Ep13(HvI^V6|6N96$R^%>oK9jYF9^)1CqryS$?NR4CtjC$Z}lz<-Xj1PX+m zL6_AmA{bK>n5$|I)Thts$2#D{eUG_5#|)M?mn+YVtc{9q&k!&(8z{td-#$|Z`Xi+s zWkWTanx!$%!VE=1!{`r?|I4?2j6Z5>d|X%S3`b(Xww0a28jMyb3nLj=O+eWP2q{6H z`&=>csUa_my^`5ne5;gj|+7uvL7clPhED5nL9 z9P=_~5t3I*GU4;?i-uI;G9`TJT?`i#z{Wp-xO-1U@gpM>TO|aEr0fh*L}ONv@gINc zCsHmlekVgXJPDaZVlyBuyZ_NtCZGNS@s=Y=wCOf~i4b|)(zTSk+e*Ch-7Wi(m~-Q| z%6tc|orhJxrk9l9jBkzs8g_%jJ$cRN@tZao)|ZRR^eZM`!Yygfxcxgv-Wt zAGzfymFk>!uSMdERnDy}%h!~)m5aG90?f}Vcg=}&JpjCN4xMo!0LcOS*H(0xil9JQ zZeq383s!Agcm5oTY5Q=f33Ysn4OpqtY-><@CxMS#lk9x%4y7Dp=+L4Iq!1O~FbKLG zy!ZSvo<|@SVe(Qy%Q>aekEd3ZINd|d%yjlVDTjpttpd_EY+P2&cJO=f!7CdctOYtG zD41AQt+s)>MdJiw@rTTj0`Q4x{_ZnYJX5vBd|CKouYO=783 zc(9IHv0ARCQn#^**6=66@ClTvzr+7f2I`zDQL%)|kqkCG#SS;-gwSegFTYL2EWzlX zwbDdlhIJaml0W`(;6aj9xQP(}ckY+5FJ|^`=!iro*UM=fI=TtE1xiQ$-c3ws^?VDW z3Bw<@_%YdwA%#A!HQxyU&t$E+u!*ydzZlV|DTLK*QF`SA#w)$yr2jGZF*nEOZ-v!_ z%Dh4tQ+0ys|Itbq)9bpE zfm#}L;#!EPK3Sczi%P2XgeUIV$T7&>+CB6K?cl~$3%-Wq`1EqDQn;L_AHoy3l-*E5 zYGF~fH%O^{er#hlzWGIIuItlQsjD6)hZDWsdyXX$bPLeKheyPQ#V*}Lf46cqLrqjK ze%vsUu30G3f)C;HS;8Dc0A4@PXvVzzcU~YNexrKVi^~E}0!e6^W6?n4_a9=GiZQ+`TZ?i`PWjo^#p$@#OY4y< zm>8*s1w6L8Ohe>y*CAGgM))=1coU0Bzc${QUF7Sgc%x3B2TOdij`aRnScRt`pm8xE zb9p0$>(pM`_Dz5gYd{j^^g1Q37#mAE781D(lh9g{dQ|C~>Qun&QP`t_pWG^T?$^zswRhScAFiQaaqoLRrn!40m{ zt7G&e`MP|_%yyCQ4gb#?={w82g~?z^O70%;H*l-XAA0NGx^~I?cE7W;4aK;mKsh8t zhg$w_sh>+;3|F|~Q{|M=A>rEpIJgPag&liYtW?q|(++Z63qBkr-BuzV7)Bp)*Mz(_mR`snnpYxPH zW_d4vefL(l)Fw2&oH9PaMG$~=Q>0+G-_xsTow7Z0c6Z5+$-1i1VltC8ZpmXunpDIF z^wy|Uo(fvSX2g)sn|qE>KC{QouF&YW`fp-zk{kXEY*NE&0d5?dJA<_)r3g!2h;ow* ze0D#=<-^}_(dYV*qp)yGIDsSmq((rTL?T0n5z(i&<2YmiIS*%x5OMO%nd$O`Q<_Ih zntS353pAV}7w;cWh20e8RZYQB?Ko%V$?w-zPuNm5H(IS6Lv~Oy%2W~(C{Z0WrKv6@ zD(kVa%Xlm8wgpuci3IZ=U92|-LsG%}G61M_g-4vkg2d>)BvVT+S&5(PN$cxM-1UbN z;qN`I_nITt=7&aFAOZ2t!YR^%*;nK_LpOobq)$g>SYD`Jg?-tC7)88Ab!Z_{{-{?O z6j4f^oK^a~S0xm8bfBlSOy+ICbC_?tn(o{%x@3Hl_`|~p2aph(lXgxMV)JZAG6t>(C zqZ=UT|Fo&$-g5idk%mutnH);H>A@L{=9^s=a&WM+8D0MPQFXsDQqYe&hdRvRyxHD> zCvve7zLbMoHh{2w-}8b0U4wD4C!zB6atLAsWjqdPM|QNE=+3d8HAZFj*{OpR#eTv$;SXu@x}ng;HrjBPTiXJqVyjBT zgc1vG&G^i}D4jv#j&d5nbnRWG5UugQ&m?1@N)5*6itK0fk;fzbF91Y9yT4JukUq3} zEq)o4meTer+y2{=EGD$ECFtk?qrqF~Qt}C(0G!%4kQGkqV*(R}dv_A~k<_NBuZiI) z>xQ2fzPm}DxdD3vcm3VpY#uUr^DmvI};ucKF z6>9WC($ryOA2(+TlLYRiSYcq^U=+#8w=kwQI^T7tDv(*Ez&r}3yJp2Q=x~fb6KUtq8E??!}))ozE;Y&Md%UmRM*-5;Qir)EDPqubr7jNd4I#=(!unIXk44g@B+&4)wTYzp55C-sb@WM0*d3g3g1fGj|Jx)*M+ z{0SgwPKg8m0m4hx36XOW_})|Hm(Ull6pdo*K~leHwSQI|F;tpS?W8CKg||yCxhlS| zsjp_}0YCf90)Z;So+q*SxNNkMOelUKFo2E)c+az&uDTL$BS>Y℞IP-rjmAH05<* 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

    s!`YTQ8DWsTtq4A8{z{P>dKi#&i< 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 YB>v|u00)F|?004!8pAP{19~pZNT>t<8 diff --git a/screenshots/trending.webp b/screenshots/trending.webp index 017815dc25f071d559c3f9434dfd6103f42e2b8e..0380c0c95561c25ac9ad195ba2dc14e7be0969a1 100644 GIT binary patch literal 59610 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%0Dwt1mR9!^^1RO%(ZP}0C>i><_v+VJ#ft2t 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≧e>*Ar6FW$2g1il7`{o5V@9!k%VYvID00000033%p zK#nLq{tnvW)sbXbbgD@(ap;ub6j%1th1~|lntR|YY1tValwq1+mW;;ikQgvN0t27` z=7p!RWWfm?+W7IgGyHN{b78#|a-OE{tBCV?Ue3c>)d^y+3kiYhkM6Q)0pC+IX!obS ziG>xEdZDVwzGHSrN`fP7U{2db!}IMYshPBU)8CXJO&%udKAy%xnGi{|FQ=O@vt?&M z&Jh*BlJm4=Rx~KAl5R~uZ%lt*3TSn}d*ALNLV|=DW50&}K(f^3BamD2r2V2q>6#6nOBmRhh4m&vsM{PIUcgYfkQg0WS{?YJzZk(y6xBFRb{IeX$_W}0S ze-qH1kJq0H9Q-mF-utn4;T`;C^>Oxz_=wo~-h2UfmA(SJ0H!~&{~>zsKk<`)=Kz9j zL;YEMntLYN2_W-#1Saptyw<<=4H!%d^#V_UqE{zRdqws2LQn7EK!LA!U_|3f$vERa z938)Ymh~m;y|-0$&D6-Rvbts_tg@`G>7M_0xQY`YSXJjem{tmIj?3tv__ARRzP_Q+ zElZR1e72?NrH3^Hs6<VCU8xMZqN{~^#}+I)_grj=+ucC+ob*<@m_#GU)G z()3wx+4Hl+Mo>~?>bbY*H|&p^zf7s}GF9pPJ68W&ga65w^(Ofr>aa@RNUPL2w_$khd`zi#$aTHt;w3Ed3?IT z|K<7q=2&+bPl|Z8OaTi~z<;ep-$;ccpRC&KU4OwVOls9PzBc{ZNBk6nOzVNS&7k!f zD?=^LV*Fymf3<8CT*z7XE-^&A^WU2ApL}cc9YGe#O{t)?E)UU?akN5ScU;`RwD9l2 zP5SIW{&PHxVCq#&>tyf?p;X3zHe?7KuAlVP0o2~gEkPP_)lTG`I`U#9_ssnP_oOdU z-vxxbJtENmYe360uEu@Op!XV_43&RV7k040`Z5aB!wTVD>PgzbW#*DE3Hw|E*r$YNWuCm*L( zR602-TCuT^iqz~D3Mst|4m?%YQKf|vW$r+%ANJ^vaZT>=l9knpVRAn8RzPho=j_(O zs09;PniHvVbDi3-g!l&rVbi9by=ocJH0$7Bu1W)8-4-T_RyNOw_{$62=B$YlH8(t? zq^^R(?%zCnw?@lzyhaiiwpfKVkW|YFMatxbY;xR7Vu}Q1(>i;;ZSi+V&=Ii>Ai7Ek zF0YXOzJV*D7TrvMr(sH-hnCu3Ji=&k|J_%16v->cZP>1A2SzOz2 zQ~7e-OW2d z6RBovDYv^iXN z8Pyz}?_-d6)<1}}+|d2zxS@<$RPu&bh}mLaRYu+q@5w#Z%?&1I8lZ7k%Ibfq z-i9iWDgTz?U+ORVf}z`6`M>7KzbCRDjunm^gkF3{zX3dXS2V* zEe@n@^??>jpst2eMpyx31)7egVYg@W16Us6~+do}YzRJ4W1E zfWIj5&3jFIaI&L~>@ckusF)S#d>8pUuC)Ep2Z#f843ZTz$ZpR>2ofjy1FY*>hTD#el!04c^Z08XdbOgDjr?mim-2E6Wo3nP%w_X% zcPBK%_!?(3>oHhepmYaMpqrfo=3p};946>6QO zhSSpVP>$d71(Sj>xlj)K(4%(3boiOP$n#F5Zq}HZ3fG9l8XAAfCfA+F+l=?|X2bme zb|FCO*&?gJLofUEG8el&>bWHPFzLi_R)yVkH(D>DbWbe)YO!#0q(F)jHg#%fqJ!U~ z@zpT6?UYTd;Go451ljzRBVAX+@z*{zOoX;}VDaE@=cYgoNiS4p;e0yKpT znw{pf)F;UBwVTZpZi~{O7NYq@&T82!Q(j}$3Hw?{Xc=3wFxYlnu~rR180nNBj!{yr zYqhdUbBJFk6mIo-+Oj9)!xdRqFA0^$m7xw~7)8j!Z*`{ z`A)pF{ay+byu2+v9U||K|jx!jY#R2>5#TmO)YeDGUI6 zexJs)K6OYAhSB~cYH&w@*jAoGaEHg3Qtl-Bk&&>GdNhJhwm3JdMV98oM;-GkV6Cl~ zNtA_vMrq~DR*|^_i+H7$LiMQhdS+ePQ2|L$m(#%#!Q&|$Y}x8Jp3H=bx~aS?@`-H5 z@VhvkhXIJSiW(a4iaFGM)bJ|ds%gL%Q?Lbmyc3z^c1Z1POMMV~Oyw8iMnmqNp4^pVsplzRJMl39O}O9+YhvOj7=HA;S~H z6zT;kJU5Th9o;tsp&p(buhTpt0e!<(u}-McZwDl)*b~>YC1BKyz8t4zSlwfLBgLSSP z*2Q4)4Ff@bI*`9v$e`Gc@$}aqyy`SiiZN6leimqnY!-9{1LJd{K2fG8e+PV!o}O&b zqtUccE$tfBJD9eVj0mk+0yPlXiWzo|?0GB z+BfS_AygUf598*~D+WEBX$gC~6FZGG?@kg`=e+rydSYc%m`-Dlnz?y65{icA z`CoSkqM`c!V;G6DK-$^m(op%jRyAmJv;^v|wqz#E@v|=(tHwShIL*O%v7+w2^Uk$2 zkz57BZlN>CX$Gnjp-Mjp7H;^oxF(#5ZnjLqq5A zjjtBAt3Rm4+D#^utyTF$z-gCNTRxky@aQ{-Hx!ge^VXgr)r4nSCl3p-d61w1X%2_H z7<(Bd5Q%&AZK%qp!&0ZQSW)11anF@FOQtF&{#+qkAH?!!r5zjr!@Q*;*!-9LtJe-X zPP`nkK8b3dek~BUclbN?&CC7PP6fKWYP66ztOI$S>*7*0b!8;)mMGs|QxnG#jd!G; zN#7hHy*V-yGo`e2Je0pw65+GJA~E3a2Rb`#r2mWEzq z=H5@~6`s@z_4cc7nr4}cJ?&Pw5|(;ymJKj2$sdw+!M3cINvs$MV4UB2`y>hu;?_Dr z#A?8ylx@&Y$V9V?kvr0Euu{iNj<7Uzk=NdgwB#Kw+4o)Illm2Z_JYRBa`p60{I}w7 zyQ+Y2e_kSG4a*H7g8TmBkr?%(nTs1@6}}iQN^h))xAHCXY!?sZmuMJG|xB9E|yfUe#306|or zPSf{kLZ{@l!$l&AG#Ez!=BMCyMQfKErH7kViP1m04xxqz2M=)vGxYA<#mS6qoeo0< zh|9Wd27ip+>uA1>oJvwbS%9AZB^8Vcu=a>Tjp;xssy;1PNMf4gtp*ce>%0t^;<;yb z)KZ>Fyn0Vs7*P3X-GrHYLh4?8(Y zWt$#Az;?PNx7}Xrr-^c_TgJZJtpwy8YcaI6qOXwD?jFs5>B}IkS`3Kh^JNT(%C})4=t78x&jnC%&&pYL+Wu|G|fYf`3 z`b5jKrxx3Nhl()jz-#yC?u~N((6Dah`)>-0$LPiMHVlW+cBk)?^^6bi^ z*hqLqC*p0>kG3mbc~fS^Oj|;0AtYh>5pwIQbZu+6JqVqJB0+;Qj>?>oY&*{a<}?l; zszh@zd&s?hM6O9r7;=~Sq2uOJ;JFy<>1%u?;*xFoLi?H!#5fmvG}ne4V|}&Wy&#x& zHt-HY(B`*Oz3Rid$ZU})#nN>b`rTj+tAi({fph4zSIL=_mONZ)ro@*~u7;wMl zQLy^-7+)f@TCDlG0c~cm@<~axe%DYyiu`T{6ah%=*{MJqZJDF;9GvRjETztp1n%X| z&vqr!fp5zBg%%N$A0WSu5`-)%1oAYD#)@oXyt?xf@Od#XlD9^gZH9oDN{4 z#VFPyXtx7Fn(T?n6*-q~?`VKa9ckGayr!nE1}ZjExmJttQD_BwI6HMRpY#J?a9c?u z`?Xc=2k*ZZRcu)%j6)(gEvxfIJ6Kk7AODb}oOy^oBP=KK1=dH5G^JweIOu79Lfhwm zMSFj)s?a9_!NwV@52D`D;7m%zKqOf1de0(JyeacHc2j*P_q>mbqYnW;%e4{CR&c?+ z0&}e0oYP6=p}JAuESGhnK<=qe*_93t)`Iy;=nv0hQCfI6nOdkoa^e+mnLy0MdmWs>))s@eAmw+9hCHvaD*O8T2)-iD zKmj@|KJ?7JTKVU@>onlCevcp)$U!diRs#T#9S9zsGQ{#wtPB8XYiL%`eI!GKq|1tB0RZlG z31^Gk(7%We?d9?r&1@dd-wu6qfbBM0RD>tKE>D&}Qy#HgfV%%fL9rn+@mKzJWqODn zoD6}XQUa707N?o`ZA7p~Dd-Rdc%Zu4&s$p3Y>{^-9^B|W*29I6vD_{Dw)e!?G3cf$ zy<;O%-b61ewiQJGlzK!SH3-rqzRA^SySA13$C$I8ZRPJW^;PaXuWb0wY|{P0lNDS` z00&se>FzTH*e0#@N|cY{A&lBw-V3ft6hu$@ndBuoKK(szHREr_>aC-#KA4*v0W3O2 zwX?>qvYNcD+d&~q>dNFD-3}l)_;{xy-{cpVB3-0lCvyR>KS_;NrX7*#>d0AB9&l-+ zTiMnp853^+-1qnmdVB3N z7^_2DHr(e*J=Xo|*jaZPW=> zJL;Y(tBO(_ab2urtaSSpMoyi%vM06%d{UGj0`^hG{6d<(y|`2}CE#J(DSD?YEf*7R`N`&ib@a9|#&RpGnKM8&+NRR^H0?;54 zv?g2G*5!;lvUDAR2l`{&z$3$M8uxZW622}U zo;AM(F>a$Wz~G)bGW@&R0LXIFgV)3Wuaf*Ae=e@HsdPkB2VdxQZSn_boE-=-n)Z@N zrFW2~TVAp?r2mE)T;4kkuJI;SU46ueSc2L#_J(|23wh%%Rn|3 zoszwZ26Q6$TI;7LYCDEztK^RnV{c6ejY)>8ARDokM81Y97m6iMGBi8yL;0Vu1I&^u z40lDUVa4_>TmH+tks$0K98!R0Qe^S8ovPSx3w&EeeKrznayRHq<4rTnnq-ejskOI^ z++3P$<5zmzPA&T2|^;AH*`H!J)b+bxQkY;Mj zm&$LsO38n-}Zr z^MO82$6>&4rjTmjKH%6w<2 zQ=hL$;o1vY@&a<(iIcpCtz`S~Xc6>lm@~IvX02mz$F{PErY7}7@&jQtau6_6(ksT{ z^Wm9AO464*Xd@NSR7qqdv~b)V{h_&~@opf!2ZZX17$5;9r#}ZD0pLok(7q@8>y*#5 zH`p%G5577R%!gLv9bA_ypmK&`KJpAR_F(8Y2!tUG4#SSR%P6q27(`aXL)P2g-yqc#u-8atolR6lQ?(r&{zn+-F~(JiNV_<4s1Z<9wso&%n-;>aA6_U7w2G zh>NQr2Yx6{al+a=kfy^2Jaq}8Ap!zpTQltWB(QQXcGuFEb~AUl`#DuAN$hn}A_cQ5 zNSLN&Q3AChg_Gx-wuSwKDz1s*sL+0@p$=>E)^3|p3%&F860art41m|F5T~>Y4vK1c z^&$3MAer@<;ay>gR|Nk zhF3+&Fyo9{5`T4&lb~;HOks48OuQM$OvlGp?jbKIFj>m~#xL{&c-M!!`~lN0*AZBr zPOym<3^12!-9}j?7t)P~M-4E8`lb&9@0)bU(C2FM(SOGPBbyc3nXo(*an-k$k_nwM zu-T5rbSjQk`?KuNZdFe%>S96TNG4fAM$8q5q77P(-(M7+j)(}yyMv&odsb4R}&)yAZ3 zx3##sGaB7~{ppQNYlayqZ6xDLwvYsY@Qg{p4eWg@GNd^<+Jp!K^Z4n}Kv2XO$G}#G z-v@kDn0T`sg6xUG=v=@=An9M}oc0?+b_`El1;=Nqr~%C|%kwj7j2!zQ=^QFL&)6)P zbruV9pf#+-O_a)G6z@&kuT6tD?SjL!?NAqK7sw0uB`I**!w85iADb*cWs!LX-|csj zBr5AYvz*zkkl!UMmG<|zpChk&`dC%$aHKI8kP+lb-a2bPdUXC>Y_%P#O5(zBeT#T# ze44UbKD|nhVyw325#`AwC<`J|I*9?a#UvfG1o?0@2(7FQ%&xA5_!zJ~>-7vGL~jzb z<$WVmQiO@c>*l7cg6tz@_%MiU+*Y2%3h*AQcQJ`1^h$(sltF4DIcCeRqt$XASJDFo z8ig1Kp)>T(=e6|t|B6n73Uo%M=)h%tTf#Kq&WgjJfXl}-1)nSqf0>Ugliz;~R!65F z9-y2_1!>tb*pDpRT4c#vXF%AP9sU*)J(GP9pgP_-)@xFw#b&CmujUg4m{_<~gE_5h z+NLa%z)da6JfL8bPJ?e6h65+I;}mrIDPX2#5JVz`Y7B342t9(q^g2yk0}^U9yu#_& zBLmBd*D-*ew$J6;zBV&XIeCSfvbVBINRD}`^#iLZ>;ep*{Euf9OG#4TcK_z#bAY`H zPmMSlS-G1n@NF&Q7L|MG=Y)usrsk~%3^9gU?xx$$Lqu7)d7;qlrXfV2)sf50^c;N*O zSIP*`^mUBB4;eyKC>vao&)@Z_j4Gu*H~xb!4Z6Gs9G+~{>bq}H?BrIGC4prB!~YY0Q!5vh%NtO{Fvi<~9|@9>Riw|O;qJhO8C z7aL}~z}C_9kC6(j3`27bi}nTJA#a=FW>poWW>HRgb zjROLY$v$*tLi)eH~o^=yiWO{eu zqb9IUI0b-AV%kT43?_~n=-%xQd@f4#G`vYSBg)b1IMaX!{8a=s|1wH{-myrqL?&8p zEpg}l@x~TKv2leTnk`CPOIi3h6)!&RjYx?1*N=`9^jGL|VAO?@0XA>`VDMzkN`bjl zfdUmEVs%BYSPbsH$Q-)s6)h9;8)mDG+!PS~1RH8LqNX58AUBUo%3)=0kWsu&EyH(W z#W`Ld!N~z|9walXbPQ9_KffSdk1KOAm%qD?!DycE0$2lW$(QU`g7(*TwcyH?XTG=R zqH~RjIX)0driEL2gc;QjFH6-A3z4yHLFZ|Ne!_k#r)Uv8n`?bZc}X7}%cRG*Njuk5 zB0uRf*mvse)4CxPK-s=q3!!H1o{zX_p*xsB6LE${l)`c&AXiI@X`~LhXYhttby4MF$sIGUlOLju2d*>G{?|`QmtQ=)D z!vi|?Wu-}l>dr36>JYq@<$Uiyi+$&+t-irfuvt(=yy0WkKcJOwcxZO|a#L$Bz?Yfb zqjc(^vkXvWH$>{|>yhyd=#a`w@SCQf+Oaqot_iTbD} zox)TU|K*hGq~LYk$?{eP@&wgBw71O$O>=eyJAgM|ne%8ra9(iEcs@VB9d+I4hBGqO z(TK`IPO5rP1)J*Yyqe?uBX}$#5`!eHfp9B?_*sx79js;wn^cWE&>zY{{+f5-tCL*t zJ79qR5jPxZK(_QGl#5Y%&~ypkcWLQe zcF&8kU=5f9%V94wC4Y{lha!Q=wLehRira+F3zk8iVID{2x>L=Ajw_5&J7qbG>kp?A z8TZNFJALVMjTqPM_RYyJ7DQbO-N{#ShD(>S09yAA+tlgxl68NLusC#4A%94p9ELqZ z-e0IZ(-%5cym27F-vf|_{R2i@(H9q++et|)<^;biH;nfmWGIu6%J>n@pFxz?#(Kf5yj%fC zUwJXEUPmO$&2BVk;#t&<12Xpk01%N8CO&8YK$hhoT)eTkTt^>bam?|H{7U*(`dEE# zrAjz%trrVxKD+IQC-g3g_;4!#bypHv5y=t@1WC(ez>I?7{Ff`nJnGM{Fm6+|`3r)! z8~|VqSx}5rf(eATr0wMZWo)}Kge#MoByS%u1pQs$`p+g+O=6-yjFuDtoEJB-y-Zbl zF4{w-jZQdbyIqvHoaYY@j@cH%8GQUV5I)?X3yz?W2M;I}DUl=_k@|7d$Pb2?cKr`} z0046?pg z^ZJcu-;H~3)JTR%WoKtN&vIHe8@NO+6%Sevi|3C54>J;a6s!jPF~E(I3R2TnH-wtu zZ6eVc9SUYMV{DFUC)wvhBhuan2Iw|`;kOvhs4`u^a&(e}&G$k-Ze{#Y_s4aE_c1JQ zX)gY~`no6s;(n5bZ>lC!kb+S{Vm)D<)KCUJ#lwtk(eeIRo2PNJ1N4=k@phYXYdPmP zjQ-)=e)6QkPciQ9;bOKKeANu*U-;psDZ6!P%#fJ4Qbl5Q(l=}ge|;_L9@#EWm|kt; ziAwF~LO$aOZ$S;9H6&iafYymK$LwGmUAp*GOiy4q_RhGH^J-FBdRM-vhc{gg?NNEp z7{a@Q8~g}=m;2%(=w5(i?Kytxs>47U5||z9e)`Sg^2q!A)I7-k0GyOP2oy|i95?3= zUVvI_4O=u;AnvLYivz4EkN*ktj1}Ies*&QL3}4sn6qdiIgb>mBJ&DUdP;NdyT!oD z&jmnCD7x1P%quNpe8cmfa*IS9h*q^vbSPwCG`>tdGl!!%Zk1*o$^xZGJDG@SDAl=- z2hef6;(k2CZiOFvkdW4$O|ZQFNrRQjOi&QYxvD9b+AEub@A1O<} z(y&`xPT$P#1S8JD3#3y8L_pMxcno(HJ1AM$r+Le<-oidvZzHbC&q{i^JLY@~O)G?` zEa_kOa2s{vu@?RuR0!)X1&NHlVpWf?T2mD!A})e3z$$MXQlPxcC}`kKl&2!+ zNR%`RQGinYw!GxLfnW=|g=|S%>LyGnE$c6lPBKVtYWb)WvTqJ|_$O)H(CU0`7XWd3 z*x9>I(!CL-T86wR&qFusRTD?(-<&2~HhZRo6;&JkI{-@yI4zvh?mv>s)-yXRW@}vD z!$CndRa1nRNoMb)eh3rt35K9I>htuF9x`>CE-pCs@mNBTZ%^*|k=CPu6RfWQgzL3b z?EQH^jf~uZTqv8zCDjZ|E8N#%Yl-dY*v3)}CKa;F!>11MSi6Y_)d~-?*pVDQ1Cc28 zG2~gpdx%8EEv#C|{H@OO6*=u2!B6#MI#73sa0ol*r*6thbvN_EKbA8eU>ur_t$#JL z@C^jO$#@-nz#o5UCbW*AHJ+s^4Ti-L$2TbUQE_kS*;BkIKqX;q>J=KIAmvkdW*GS~ z6D;^a2!o+!qViC>WZPMqopKKEL#bseEdq?J3zp~9&!Ugj)n-MrHzt%7H2O4m)Vv_G z1Vsaqt(!Tda7**1*Pkw)$-Z3@=m&a@ zdFIuF30pws@ah8o`PGF4iT&Y;5IsLKcNjV+iub!%l@MIvSQ3ES;~sG--mPIGmMMIE zQPR`sTfCVoE6#MvZdcIF_x%ua5>U*f72IuU zpHoxn69nN#oE5VVNz4Z=F1qBNXB+X(jLMrf>S59@GXwe_1b%2ANJp>gKS4`K9>!RGUoLU73X(cTkh8X9y!1M2!qgM$~nLNOf27j`22LKN$Xg;#XP zyvAKM5pu?mi)IN`rCl)BXevGbXFBF;?*%)qn$mVd@D#&u>Vu~I+2#~d5MP>w4+KhS z*VNbcq8uQeeKSz0G*aT>k}?vW6V2;UDylI2fP&k# zz}^lB&n1oglOCoT^5ozQhXHtWvV{{}HHM$gJ!P<&TPiZSu_)tC^`&dyG8H*b4CL!UtD7+BF4#3a4TcrUUWJ6UPn3-8s$@*NX;;Gt)JRvKrBtFcm|(Qu zYiL-ULQ~^Q<3k=ir}@CqPAQD`7uA4RX@e`~%K`@6LG31jY&s)&G^CG-q}yL1Z9l`> zv)rliYJM7fynO@{u*%|V2QjZ0sdQXWd>A-L>V<nu3{EuMxx= zlFKXvI%Q>nQg!f5jgmoy>hsrR9`N^m|o&!?^j+bgmx|Kq3XC7C6%r*8C0(}^u$ zLjZ?;YX&vxigC{rytrrQJ?uCkix`(9#|5W0VZ)H=&V)jdNg~eSL8@04ODEB&y${tC z<6U9*n;H*#pyUq;C9XI_ z0omXoh5d52yweZY{ZdgAsxK;Xvl&d6Hg^J)K~j0Tr<M%C?Z|=NX-@Y>+j@YrAH81HS`Do6e(;tr`n)|Z ztg1DBz0GM!n)l5#zG4+vpSJX{hHKEHc&#J~4NF8%z?#})(~f<@vhwwJQ8btXHb}tj*age^t_?05xO;vHBxYEr#?S&LKw0yC-3$3JV3o8ZpGlt2 zc5nl>3>C}BU2q)U0`Y#wysaIU+N@TQWD^UQTxUeGz}WBG-p#9}+eh|+Fzaz^OKQ^= ziAF~NVAf#W+LOtU-5yzR0&=~+zC8@MM*~&L!huA{lL@F}U?QGOvQGl~9~RUkj1a$V zu)*c4Fh!(x%z{8s=rqmVVsM8_d#ZPaU8TB%bZ^}A4*uHgsS%nk{<+ko;`&P@sNQ$S@H7=LEyxU3uUsSTl;M>HW)tY=5C=qf^&I)Z@ zO_tqz3|7VOx>zypoR5r$a<%kkcGLz1Au(H1?oCtp6C&8@t&xzkeD$mE*$VFDLn%}; z=}z<1Lo|rS3Y2iR{n4iT1)~bBLY86TnY&@Ef(ecioDTwY+N{*nFj9EAMq_*FxX{PHn8qB71= z$HLql6ZKB786b|@POmk#x+gLeM(+ZUt)f$P`ogdv9l~b)SwdS#fzKT)05_o*UQp5m z0>&}IGK{!n(Yd0KbO#vO>WV0`uT-vYm0M<@vzc))KukA}VvF{qB(&YDMjR0$=UrnwQ=~I%UEta#n$XMQ}2=)Vb_f(lc70 zsV!`GVh)Al?dXhD)!LV0;h%~SZoZpmLfLdt;>{KwYbY;E<-GL~$*o2~;F>hEv1Hpm zi=aCQgV}%j3D0+YR?+((WLs8`I%DfkOG@-X>c?E$A7e2mdr=&Q$oM{~iDV-zQujhO zhffS80_bR{)e2Nh&+>c)1q9%veV@AWLAYf#g&LVfSZ;q*3A=o_D|pvxDs9xYAg2B_GJ3euN(WIzIBuskkL?PiCEV!ArogJ+~jBCZCaXKhyN!ghg54{f&uK zO=y2O8mYto5#6?9^=a6|T+Lh4hfEnVDTA!L)3INHPNaZ@i7weW;(9h0fDIuUMmszR T{#O`zQW>z8ynp_^Vf23hgR-BP From 8167648ef2beb6074b88539c236466abf4f5b612 Mon Sep 17 00:00:00 2001 From: AddisonTech Date: Fri, 16 Oct 2026 17:42:47 +0000 Subject: [PATCH 10/10] Use hash routes and default to the live API URL Refreshing any page works on a static host without a rewrite rule, and a production build without VITE_API_URL points at the live API. --- README.md | 6 +++--- frontend/.env.example | 9 +++++---- frontend/src/App.jsx | 8 +++++--- frontend/src/services/endpoints.js | 16 +++++++++++++--- frontend/src/services/feed.test.js | 17 ++++++++++++++++- render.yaml | 12 +++--------- 6 files changed, 45 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index bfc12f0..c48e24b 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ Demo scenarios: - **Backend:** FastAPI. A single collector owns the scan loop, the latest readings, the alarm manager, and the set of WebSocket clients. On startup in simulation mode it generates 24 hours of history (with past events and simulated operator acknowledgements) in well under a second, so trends and the journal are never empty. - **WebSocket feed:** on connect the server sends a `snapshot` (meters, readings, alarms, summary, demo info). After that it pushes `readings` every scan and `alarms` whenever the alarm list changes or an operator acts. Clients can send `{"type": "ping"}` and get a `pong`. -- **Front end:** React and Vite. The live feed is a single WebSocket with automatic reconnection and a stale connection watchdog. Chart heavy pages are loaded on demand, so the first load is about 72 kB of gzipped JavaScript. +- **Front end:** React and Vite with hash based routes (`/#/alarms`), so any page can be refreshed or shared on a static host with no rewrite rules. The live feed is a single WebSocket with automatic reconnection and a stale connection watchdog. Chart heavy pages are loaded on demand, so the first load is about 72 kB of gzipped JavaScript. - **Cold starts:** the static front end never sleeps. While the API wakes up it shows a progress screen and pings `/api/health` (which is also what wakes the server), then switches to the live view as soon as the first snapshot arrives. If the connection drops later, the page keeps the last data, dims it, and shows "Reconnecting". ### Stack @@ -179,7 +179,7 @@ Backend settings are environment variables (see `backend/config.py`): | `CORS_ORIGINS` | `*` | Comma separated allowed origins | | `DB_PATH` | `power_dashboard.db` | SQLite file | -Front end: `VITE_API_URL` is the API base URL used at build time. Leave it empty when the front end and API share an origin or when using the dev proxy. +Front end: `VITE_API_URL` is the API base URL used at build time. It is optional. A production build without it points at the live demo API, `https://power-dashboard-api.onrender.com`, and the dev server without it proxies to the local backend. ### Real hardware (Modbus TCP) @@ -199,7 +199,7 @@ Each device entry maps a meter ID to a host, unit ID, and the register for each `render.yaml` is a Render Blueprint with two services that deploy from `main` on every merge: - **power-dashboard-api**: Python web service in `backend/`, started with `uvicorn main:app --host 0.0.0.0 --port $PORT`, health checked at `/api/health`, running the simulator. -- **power-dashboard**: static site built from `frontend/` with `npm ci && npm run build`, published from `dist`, with a rewrite to `index.html` so deep links such as `/alarms` work. Set `VITE_API_URL` to the API service's public URL. +- **power-dashboard**: static site built from `frontend/` with `npm ci && npm run build`, published from `dist`. No dashboard settings are required: hash routes mean refreshes never 404, and the build falls back to the live API URL when `VITE_API_URL` is not set. Build filters mean a change under `backend/` only redeploys the API, a change under `frontend/` only redeploys the site, and documentation changes redeploy nothing. GitHub Actions runs both test suites and the production build on every pull request and push to `main`. diff --git a/frontend/.env.example b/frontend/.env.example index 8116fa6..d42e601 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -1,5 +1,6 @@ -# Base URL of the backend API. Leave empty for local development: the Vite -# dev server proxies /api and /ws to http://localhost:8000. -# For a production build hosted separately from the API, set the API URL: -# VITE_API_URL=https://your-api.onrender.com +# Base URL of the backend API, read at build time. +# Optional: a production build without it uses the live demo API +# (https://power-dashboard-api.onrender.com). The dev server without it +# proxies /api and /ws to http://localhost:8000. +# VITE_API_URL=https://your-api.example.com VITE_API_URL= diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index c04060e..bddc2f7 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,5 +1,5 @@ import React, { Suspense, lazy, useCallback, useState } from 'react' -import { BrowserRouter, Routes, Route, NavLink, Navigate } from 'react-router-dom' +import { HashRouter, Routes, Route, NavLink, Navigate } from 'react-router-dom' import { LayoutDashboard, GitBranch, Gauge, Bell, TrendingUp, Settings, Zap, Info, FlaskConical } from 'lucide-react' import { LiveFeedProvider, useFeed } from './services/LiveFeed' import WakeScreen from './components/WakeScreen' @@ -119,12 +119,14 @@ function Shell() { ) } +// Hash based routing (/#/alarms) so any page can be refreshed or deep linked +// on a static host without a server side rewrite rule. export default function App() { return ( - + - + ) } diff --git a/frontend/src/services/endpoints.js b/frontend/src/services/endpoints.js index a973a53..320d090 100644 --- a/frontend/src/services/endpoints.js +++ b/frontend/src/services/endpoints.js @@ -1,6 +1,16 @@ -// Backend location. Leave VITE_API_URL empty to use the same origin -// (the Vite dev server proxies /api and /ws to the local backend). -export const API_URL = (import.meta.env.VITE_API_URL || '').trim().replace(/\/+$/, '') +// Backend location. +// VITE_API_URL set at build time use it +// production build without it use the live demo API +// dev server without it same origin (Vite proxies /api and /ws) +export const LIVE_API_URL = 'https://power-dashboard-api.onrender.com' + +export function resolveApiUrl(env = import.meta.env) { + const configured = (env.VITE_API_URL || '').trim().replace(/\/+$/, '') + if (configured) return configured + return env.PROD ? LIVE_API_URL : '' +} + +export const API_URL = resolveApiUrl() export function buildWsUrl(apiUrl = API_URL, loc = globalThis.location) { if (apiUrl) return apiUrl.replace(/^http/, 'ws') + '/ws/live' diff --git a/frontend/src/services/feed.test.js b/frontend/src/services/feed.test.js index a94af6d..0a37baf 100644 --- a/frontend/src/services/feed.test.js +++ b/frontend/src/services/feed.test.js @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' import { SPARK_POINTS, alarmsByMeter, initialFeed, reduceFeed } from './feed' -import { buildWsUrl } from './endpoints' +import { LIVE_API_URL, buildWsUrl, resolveApiUrl } from './endpoints' const meters = [{ id: 'UTIL-1', name: 'Utility' }, { id: 'UPS-A', name: 'UPS A' }] const reading = (id, kw, epoch = 1) => ({ meter_id: id, power_kw: kw, epoch }) @@ -73,6 +73,21 @@ describe('alarmsByMeter', () => { }) }) +describe('resolveApiUrl', () => { + it('uses VITE_API_URL when set', () => { + expect(resolveApiUrl({ VITE_API_URL: 'https://api.example.com/', PROD: true })).toBe('https://api.example.com') + }) + + it('falls back to the live API in a production build', () => { + expect(resolveApiUrl({ PROD: true })).toBe(LIVE_API_URL) + expect(resolveApiUrl({ VITE_API_URL: ' ', PROD: true })).toBe(LIVE_API_URL) + }) + + it('uses the same origin on the dev server', () => { + expect(resolveApiUrl({ PROD: false })).toBe('') + }) +}) + describe('buildWsUrl', () => { it('derives the socket URL from the API URL', () => { expect(buildWsUrl('https://api.example.com')).toBe('wss://api.example.com/ws/live') diff --git a/render.yaml b/render.yaml index 4f56161..414936a 100644 --- a/render.yaml +++ b/render.yaml @@ -46,11 +46,9 @@ services: - frontend/** ignoredPaths: - frontend/src/**/*.test.js - routes: - # Client side routing: deep links like /alarms load the app - - type: rewrite - source: /* - destination: /index.html + # No rewrite rule needed: the app uses hash routes (/#/alarms), so every + # page refresh requests index.html. VITE_API_URL is optional; without it + # the build points at https://power-dashboard-api.onrender.com. headers: - path: /assets/* name: Cache-Control @@ -58,7 +56,3 @@ services: - path: /index.html name: Cache-Control value: no-cache - envVars: - # Public URL of power-dashboard-api, for example https://power-dashboard-api.onrender.com - - key: VITE_API_URL - sync: false