From 075360f9f4bb874fc9a1c769f95ad853f9d17fe2 Mon Sep 17 00:00:00 2001 From: MajestyHenius <3051797499@qq.com> Date: Wed, 2 Sep 2026 10:25:40 +0800 Subject: [PATCH 1/3] feat: harness + CV funnel (from feature/esp32-ocr) --- extensions/assistive_harness/.gitignore | 4 + .../OPENGLASS_MIGRATION_MAP.md | 25 + extensions/assistive_harness/README.md | 60 + extensions/assistive_harness/__init__.py | 14 + extensions/assistive_harness/asr/__init__.py | 6 + extensions/assistive_harness/asr/base.py | 30 + .../assistive_harness/asr/energy_vad.py | 92 + .../assistive_harness/asr/funasr_engine.py | 84 + .../config/skills.example.yaml | 128 + extensions/assistive_harness/cv/README.md | 171 ++ extensions/assistive_harness/cv/__init__.py | 14 + extensions/assistive_harness/cv/base.py | 44 + extensions/assistive_harness/cv/noop.py | 60 + extensions/assistive_harness/cv/pipeline.py | 159 ++ extensions/assistive_harness/cv/registry.py | 89 + .../assistive_harness/cv/requirements-cv.txt | 2 + extensions/assistive_harness/cv/yolo_onnx.py | 220 ++ extensions/assistive_harness/echo_guard.py | 75 + extensions/assistive_harness/model_log.py | 72 + .../assistive_harness/package_phase_a.ps1 | 69 + .../assistive_harness/phase_b/README.md | 114 + .../assistive_harness/phase_b/__init__.py | 5 + .../assistive_harness/phase_b/bridge_ui.py | 337 +++ .../phase_b/cam_pipeline_v2.py | 2283 +++++++++++++++++ .../phase_b/esp32_runtime.py | 1851 +++++++++++++ .../assistive_harness/phase_b/funnel_gate.py | 218 ++ .../phase_b/realtime_session.py | 306 +++ .../phase_b/recorder_live.py | 860 +++++++ .../phase_b/requirements-phase-b.txt | 4 + .../assistive_harness/phase_b/rerun_source.py | 368 +++ .../phase_b/rokid_runtime.py | 1703 ++++++++++++ .../phase_b/session_recorder.py | 90 + .../phase_b/templates/live.html | 620 +++++ .../phase_b/templates/replay.html | 566 ++++ .../phase_b/templates/replay_index.html | 321 +++ .../assistive_harness/phase_b/timing_probe.py | 163 ++ .../assistive_harness/prompts/README.md | 43 + .../prompts/describe_scene_zh.txt | 8 + .../prompts/find_object_zh.txt | 9 + .../prompts/idle_chat_zh.txt | 8 + .../prompts/obstacle_avoidance_zh.txt | 9 + .../prompts/read_text_zh.txt | 7 + extensions/assistive_harness/registry.py | 117 + extensions/assistive_harness/router.py | 262 ++ extensions/assistive_harness/schemas.py | 67 + extensions/assistive_harness/server.py | 604 +++++ extensions/assistive_harness/state_machine.py | 115 + .../assistive_harness/summarize_reset_run.py | 97 + extensions/assistive_harness/telemetry.py | 67 + .../assistive_harness/tests/__init__.py | 0 .../assistive_harness/tests/test_core.py | 402 +++ .../assistive_harness/tests/test_cv_yolo.py | 41 + .../tests/test_phase_b_rokid.py | 352 +++ 53 files changed, 13435 insertions(+) create mode 100644 extensions/assistive_harness/.gitignore create mode 100644 extensions/assistive_harness/OPENGLASS_MIGRATION_MAP.md create mode 100644 extensions/assistive_harness/README.md create mode 100644 extensions/assistive_harness/__init__.py create mode 100644 extensions/assistive_harness/asr/__init__.py create mode 100644 extensions/assistive_harness/asr/base.py create mode 100644 extensions/assistive_harness/asr/energy_vad.py create mode 100644 extensions/assistive_harness/asr/funasr_engine.py create mode 100644 extensions/assistive_harness/config/skills.example.yaml create mode 100644 extensions/assistive_harness/cv/README.md create mode 100644 extensions/assistive_harness/cv/__init__.py create mode 100644 extensions/assistive_harness/cv/base.py create mode 100644 extensions/assistive_harness/cv/noop.py create mode 100644 extensions/assistive_harness/cv/pipeline.py create mode 100644 extensions/assistive_harness/cv/registry.py create mode 100644 extensions/assistive_harness/cv/requirements-cv.txt create mode 100644 extensions/assistive_harness/cv/yolo_onnx.py create mode 100644 extensions/assistive_harness/echo_guard.py create mode 100644 extensions/assistive_harness/model_log.py create mode 100644 extensions/assistive_harness/package_phase_a.ps1 create mode 100644 extensions/assistive_harness/phase_b/README.md create mode 100644 extensions/assistive_harness/phase_b/__init__.py create mode 100644 extensions/assistive_harness/phase_b/bridge_ui.py create mode 100644 extensions/assistive_harness/phase_b/cam_pipeline_v2.py create mode 100644 extensions/assistive_harness/phase_b/esp32_runtime.py create mode 100644 extensions/assistive_harness/phase_b/funnel_gate.py create mode 100644 extensions/assistive_harness/phase_b/realtime_session.py create mode 100644 extensions/assistive_harness/phase_b/recorder_live.py create mode 100644 extensions/assistive_harness/phase_b/requirements-phase-b.txt create mode 100644 extensions/assistive_harness/phase_b/rerun_source.py create mode 100644 extensions/assistive_harness/phase_b/rokid_runtime.py create mode 100644 extensions/assistive_harness/phase_b/session_recorder.py create mode 100644 extensions/assistive_harness/phase_b/templates/live.html create mode 100644 extensions/assistive_harness/phase_b/templates/replay.html create mode 100644 extensions/assistive_harness/phase_b/templates/replay_index.html create mode 100644 extensions/assistive_harness/phase_b/timing_probe.py create mode 100644 extensions/assistive_harness/prompts/README.md create mode 100644 extensions/assistive_harness/prompts/describe_scene_zh.txt create mode 100644 extensions/assistive_harness/prompts/find_object_zh.txt create mode 100644 extensions/assistive_harness/prompts/idle_chat_zh.txt create mode 100644 extensions/assistive_harness/prompts/obstacle_avoidance_zh.txt create mode 100644 extensions/assistive_harness/prompts/read_text_zh.txt create mode 100644 extensions/assistive_harness/registry.py create mode 100644 extensions/assistive_harness/router.py create mode 100644 extensions/assistive_harness/schemas.py create mode 100644 extensions/assistive_harness/server.py create mode 100644 extensions/assistive_harness/state_machine.py create mode 100644 extensions/assistive_harness/summarize_reset_run.py create mode 100644 extensions/assistive_harness/telemetry.py create mode 100644 extensions/assistive_harness/tests/__init__.py create mode 100644 extensions/assistive_harness/tests/test_core.py create mode 100644 extensions/assistive_harness/tests/test_cv_yolo.py create mode 100644 extensions/assistive_harness/tests/test_phase_b_rokid.py diff --git a/extensions/assistive_harness/.gitignore b/extensions/assistive_harness/.gitignore new file mode 100644 index 0000000..e607f1c --- /dev/null +++ b/extensions/assistive_harness/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +*.pyc +runs/ +test_artifacts/ diff --git a/extensions/assistive_harness/OPENGLASS_MIGRATION_MAP.md b/extensions/assistive_harness/OPENGLASS_MIGRATION_MAP.md new file mode 100644 index 0000000..1110736 --- /dev/null +++ b/extensions/assistive_harness/OPENGLASS_MIGRATION_MAP.md @@ -0,0 +1,25 @@ +# OpenGlass Migration Map + +Phase A deliberately separates portable policy from browser-specific transport. + +| Phase A component | OpenGlass-side destination | +|---|---| +| `schemas.py` | shared structured control-event schema | +| `router.py` | local deterministic voice-command router | +| `registry.py` + prompts | configurable Skill registry/prompt bundle | +| `echo_guard.py` | output/playback-aware ASR echo filter | +| `state_machine.py` | device-independent control priority and dedupe | +| `asr/` | phone/host local ASR service behind the same interface | +| `cv/base.py` | future advisory perception provider interface | +| `server.py` WS messages | replaceable host/phone transport adapter | +| `browser-session-adapter.js` | reference semantics for an OpenGlass session adapter | + +OpenGlass migration should keep `ControlEvent`, `SkillRegistry`, prompt SHA, +generation fence and STOP priority stable. Replace only AudioMirror capture, +session lifecycle calls, and the control transport. No dependency on ESP32, Rokid, +DOM layout or the MiniCPM private wire format exists in the Python core. + +The first Rokid implementation of this boundary now lives in +[`phase_b/`](phase_b/README.md). It consumes the existing APK JPEG/PCM endpoints, +reuses this Core and the existing Gateway, and implements the browser adapter's +STOP/RESUME/RESET/Skill generation contract in Python. diff --git a/extensions/assistive_harness/README.md b/extensions/assistive_harness/README.md new file mode 100644 index 0000000..8be88a5 --- /dev/null +++ b/extensions/assistive_harness/README.md @@ -0,0 +1,60 @@ +# Assistive Voice Skill Harness (Phase A) + +This directory is an optional, local sidecar for the MiniCPM-o browser Demo. It is +disabled by default and does not replace the native microphone/video path. + +Start the sidecar explicitly: + +```powershell +python -m extensions.assistive_harness.server --enabled ` + --model-path "C:\path\to\a\local\FunASR\model" +``` + +Then opt the browser tab in with `?assistive_harness=1`. Test-only transcript +injection additionally requires `--allow-test-injection`; it is never enabled by +the normal command above. + +The browser hook is deliberately thin. Control, ASR, prompt registry, echo guard, +state machine, metrics, and CV shadow interfaces live under this directory so the +module can later be moved behind another transport (for example OpenGlass). + +The first Rokid/OpenGlass transport is implemented in +[`phase_b/`](phase_b/README.md). It preserves this Core and the existing 8040 +Gateway while replacing browser microphone, camera, playback, and Session calls +with a Python device adapter. + +## User-editable Skills + +System prompts live in `extensions/assistive_harness/prompts/`. Existing prompt +files are read on every activation, so users can replace a prompt and activate +the Skill again without restarting the sidecar. Skill IDs, enable flags and +voice phrases are configured in `config/skills.example.yaml`; changing that YAML +does require restarting the sidecar. + +Enabled by default: + +- `帮我找<物体>` -> `find_object` -> hot Session restart with `{{target}}` +- `读一下` / `帮我识字` -> `read_text` -> hot Session restart +- `描述一下` / `看看周围` -> `describe_scene` -> hot Session restart +- `帮我避障` / `前面有障碍吗` -> `obstacle_avoidance` -> hot Session restart +- `回到聊天` / `恢复普通聊天` -> `idle_chat` -> hot Session restart + +`obstacle_avoidance` contains the frozen AAAI_SI prompt and is enabled only for +stationary, supervised validation. Its mobility safety has not been accepted; +never treat this Demo as a navigation or safety device. + +With the sidecar running, `GET http://127.0.0.1:8021/skills` reports the active +configuration and absolute prompt path for every registered Skill. + +## CV V1 shadow pipeline + +Browser JPEG mirrors enter a capacity-one latest-frame queue and are analyzed +on a dedicated single-thread worker. `cv_mode: disabled` drops frames before +inference; `cv_mode: shadow` writes `CVObservation` records without changing a +Skill or taking ownership of MiniCPM output. Slow, timed-out, or failed plugins +remain outside the audio/control receive path. + +`find_object` uses the local `yolo_onnx` reference provider. Other Skills keep +the `noop` provider until a task-specific plugin is registered. Provider setup, +the observation schema, and an OCR implementation template are documented in +[`cv/README.md`](cv/README.md). diff --git a/extensions/assistive_harness/__init__.py b/extensions/assistive_harness/__init__.py new file mode 100644 index 0000000..339e7b9 --- /dev/null +++ b/extensions/assistive_harness/__init__.py @@ -0,0 +1,14 @@ +"""Portable voice-controlled Skill Harness core for Phase A.""" + +from .router import RuleIntentRouter +from .registry import SkillRegistry +from .schemas import ASREvent, ControlEvent, ControlIntent + +__all__ = [ + "ASREvent", + "ControlEvent", + "ControlIntent", + "RuleIntentRouter", + "SkillRegistry", +] + diff --git a/extensions/assistive_harness/asr/__init__.py b/extensions/assistive_harness/asr/__init__.py new file mode 100644 index 0000000..6d88083 --- /dev/null +++ b/extensions/assistive_harness/asr/__init__.py @@ -0,0 +1,6 @@ +from .base import ASREngine, ASRResult +from .energy_vad import EnergyVAD, UtteranceAudio +from .funasr_engine import FunASREngine + +__all__ = ["ASREngine", "ASRResult", "EnergyVAD", "FunASREngine", "UtteranceAudio"] + diff --git a/extensions/assistive_harness/asr/base.py b/extensions/assistive_harness/asr/base.py new file mode 100644 index 0000000..a6fc73d --- /dev/null +++ b/extensions/assistive_harness/asr/base.py @@ -0,0 +1,30 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Protocol + +import numpy as np + + +@dataclass(frozen=True, slots=True) +class ASRResult: + text: str + confidence: float + model: str + device: str + + +class ASREngine(Protocol): + def transcribe(self, audio: np.ndarray, sample_rate: int) -> ASRResult: + ... + + +class ScriptedASREngine: + def __init__(self, transcripts: list[str]): + self.transcripts = list(transcripts) + + def transcribe(self, audio: np.ndarray, sample_rate: int) -> ASRResult: + del audio, sample_rate + text = self.transcripts.pop(0) if self.transcripts else "" + return ASRResult(text=text, confidence=1.0, model="scripted", device="cpu") + diff --git a/extensions/assistive_harness/asr/energy_vad.py b/extensions/assistive_harness/asr/energy_vad.py new file mode 100644 index 0000000..58cec2e --- /dev/null +++ b/extensions/assistive_harness/asr/energy_vad.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +from collections import deque +from dataclasses import dataclass + +import numpy as np + + +@dataclass(frozen=True, slots=True) +class UtteranceAudio: + audio: np.ndarray + started_at_ms: float + ended_at_ms: float + + +class EnergyVAD: + """Small streaming endpoint detector; it does not perform recognition.""" + + def __init__( + self, + sample_rate: int = 16_000, + rms_threshold: float = 0.012, + min_speech_ms: int = 180, + end_silence_ms: int = 450, + max_utterance_ms: int = 8_000, + preroll_ms: int = 200, + ): + self.sample_rate = sample_rate + self.rms_threshold = rms_threshold + self.min_speech_ms = min_speech_ms + self.end_silence_ms = end_silence_ms + self.max_utterance_ms = max_utterance_ms + self.preroll_ms = preroll_ms + self._preroll: deque[tuple[np.ndarray, float]] = deque() + self._active: list[np.ndarray] = [] + self._started_at_ms: float | None = None + self._last_voice_ms: float | None = None + + def _duration_ms(self, audio: np.ndarray) -> float: + return float(audio.size) * 1000.0 / self.sample_rate + + def feed(self, audio: np.ndarray, frame_started_at_ms: float) -> UtteranceAudio | None: + frame = np.asarray(audio, dtype=np.float32).reshape(-1).copy() + if frame.size == 0: + return None + duration_ms = self._duration_ms(frame) + frame_end_ms = frame_started_at_ms + duration_ms + rms = float(np.sqrt(np.mean(np.square(frame, dtype=np.float64)))) + voiced = rms >= self.rms_threshold + + if self._started_at_ms is None: + self._preroll.append((frame, frame_started_at_ms)) + while self._preroll and frame_end_ms - self._preroll[0][1] > self.preroll_ms: + self._preroll.popleft() + if not voiced: + return None + self._started_at_ms = self._preroll[0][1] if self._preroll else frame_started_at_ms + self._active = [item[0] for item in self._preroll] + self._preroll.clear() + self._last_voice_ms = frame_end_ms + else: + self._active.append(frame) + if voiced: + self._last_voice_ms = frame_end_ms + + active_ms = frame_end_ms - float(self._started_at_ms) + silence_ms = frame_end_ms - float(self._last_voice_ms or frame_end_ms) + if active_ms >= self.max_utterance_ms or silence_ms >= self.end_silence_ms: + return self._finish(frame_end_ms) + return None + + def _finish(self, ended_at_ms: float) -> UtteranceAudio | None: + if self._started_at_ms is None or not self._active: + self.reset() + return None + audio = np.concatenate(self._active).astype(np.float32, copy=False) + started = self._started_at_ms + voiced_duration = max(0.0, float(self._last_voice_ms or ended_at_ms) - started) + self.reset() + if voiced_duration < self.min_speech_ms: + return None + return UtteranceAudio(audio=audio, started_at_ms=started, ended_at_ms=ended_at_ms) + + def flush(self, ended_at_ms: float) -> UtteranceAudio | None: + return self._finish(ended_at_ms) + + def reset(self) -> None: + self._preroll.clear() + self._active = [] + self._started_at_ms = None + self._last_voice_ms = None + diff --git a/extensions/assistive_harness/asr/funasr_engine.py b/extensions/assistive_harness/asr/funasr_engine.py new file mode 100644 index 0000000..c7a126d --- /dev/null +++ b/extensions/assistive_harness/asr/funasr_engine.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +import threading +from pathlib import Path +from typing import Any + +import numpy as np + +from .base import ASRResult + + +class FunASREngine: + """Lazy local FunASR adapter. It never downloads a model implicitly.""" + + def __init__(self, model_path: str, device: str = "cpu", model_kwargs: dict[str, Any] | None = None): + path = Path(model_path).expanduser().resolve() + if not path.is_dir(): + raise FileNotFoundError(f"FunASR model path does not exist: {path}") + self.model_path = str(path) + self.device = device + self.model_kwargs = dict(model_kwargs or {}) + self._model: Any = None + self._load_lock = threading.Lock() + self._infer_lock = threading.Lock() + + @property + def loaded(self) -> bool: + return self._model is not None + + def ensure_loaded(self) -> None: + if self._model is not None: + return + with self._load_lock: + if self._model is not None: + return + from funasr import AutoModel + + self._model = AutoModel( + model=self.model_path, + device=self.device, + disable_update=True, + **self.model_kwargs, + ) + + def warm_up(self) -> None: + """Load the model and run one short silent inference before serving clients.""" + self.ensure_loaded() + silence = np.zeros(8_000, dtype=np.float32) + with self._infer_lock: + self._model.generate( + input=silence, + cache={}, + is_final=True, + batch_size_s=0, + ) + + def transcribe(self, audio: np.ndarray, sample_rate: int) -> ASRResult: + if sample_rate != 16_000: + raise ValueError(f"FunASR Phase A requires 16 kHz audio, got {sample_rate}") + self.ensure_loaded() + waveform = np.asarray(audio, dtype=np.float32).reshape(-1) + with self._infer_lock: + results = self._model.generate( + input=waveform, + cache={}, + is_final=True, + batch_size_s=0, + ) + text = "" + confidence = 1.0 + if isinstance(results, list) and results: + first = results[0] + if isinstance(first, dict): + text = str(first.get("text") or "").strip() + if isinstance(first.get("confidence"), (int, float)): + confidence = float(first["confidence"]) + else: + text = str(first).strip() + return ASRResult( + text=text, + confidence=confidence, + model=self.model_path, + device=self.device, + ) diff --git a/extensions/assistive_harness/config/skills.example.yaml b/extensions/assistive_harness/config/skills.example.yaml new file mode 100644 index 0000000..4e589ff --- /dev/null +++ b/extensions/assistive_harness/config/skills.example.yaml @@ -0,0 +1,128 @@ +version: 2 +default_skill: idle_chat + +harness: + enabled: false + host: 127.0.0.1 + port: 8021 + allow_test_injection: false + +asr: + engine: funasr + model_path: "" + device: cpu + rms_threshold: 0.012 + min_speech_ms: 180 + end_silence_ms: 450 + max_utterance_ms: 8000 + preroll_ms: 200 + +echo_guard: + window_ms: 20000 + similarity_threshold: 0.86 + +cv: + mode: shadow + max_fps: 1 + queue_size: 1 + inference_timeout_ms: 2000 + providers: + noop: + type: noop + yolo_onnx: + type: yolo_onnx + # Resolved relative to this YAML. Keep weights outside the Core so the + # same plugin can be reused by the later OpenGlass Adapter. + model_path: ../../../../OmniHarness/mini_omni_harness/models/yolo26n.onnx + device: cpu + confidence: 0.25 + image_size: 640 + +control: + cooldown_ms: 1200 + stop_speech: + # `同一下` / `等一(一)下` are bounded aliases observed from the local + # FunASR model when the user clearly says the short command `停一下`. + # They are command-only aliases, not arbitrary substring anchors. + phrases: [停一下, 同一下, 等一下, 等一一下, 别说了, 闭嘴, 停止播报, 安静] + # Literal substring protocol: any transcript containing this anchor stops. + embedded_phrases: [停一下] + resume_speech: + # Literal substring protocol: any transcript containing this anchor resumes. + embedded_phrases: [恢复对话] + reset_session: + phrases: [重新开始] + # Literal substring protocol for real voice RESET. Product deployments can + # later prepend a wake name (for example "乐奇重新开始") without changing + # the deterministic router. + embedded_phrases: [重新开始] + return_to_chat: + phrases: [回到聊天, 回到普通聊天, 退出技能, 普通聊天, 恢复普通聊天] + cancel_skill: + phrases: [取消任务, 不找了, 不读了] + +skills: + idle_chat: + enabled: true + prompt_file: ../prompts/idle_chat_zh.txt + requires_session_restart: true + cooldown_ms: 1200 + cv_mode: disabled + cv_provider: noop + activation_phrases: [普通聊天, 回到聊天] + + find_object: + enabled: true + description: 使用第一视角画面寻找语音中指定的物体 + prompt_source: AAAI_SI/C1_OBJECT_FINDING + prompt_file: ../prompts/find_object_zh.txt + requires_session_restart: true + cooldown_ms: 1500 + cv_mode: shadow + cv_provider: yolo_onnx + task_trigger: '请立即根据当前画面寻找“{{target}}”,只回答它的位置;如果没看到就说没看到。' + slot_schema: + target: {type: string, required: true} + activation_patterns: + - "帮我找(?:一下)?(?:我的)?(?P.+)" + - "帮我找(?P.+)" + - "(?P.+)在哪" + - "(?P.+)在哪里" + - "看到(?P.+)了吗" + - "有没有(?P.+)" + + read_text: + enabled: true + description: 读取当前画面中清晰可见的文字 + prompt_source: AAAI_SI/C1_TEXT_READING + prompt_file: ../prompts/read_text_zh.txt + requires_session_restart: true + cooldown_ms: 1500 + cv_mode: shadow + cv_provider: noop + task_trigger: 请立即读取当前画面中最明显的文字,只读看到的内容。 + activation_phrases: [读一下, 念一下, 帮我读一下, 帮我识字, 帮我读字, 上面写了什么, 这是什么字, 读文字] + + describe_scene: + enabled: true + prompt_file: ../prompts/describe_scene_zh.txt + requires_session_restart: true + cooldown_ms: 1500 + cv_mode: shadow + cv_provider: noop + task_trigger: 请立即用一两句话简短描述当前画面。 + activation_phrases: [描述一下, 帮我描述一下, 帮我描述场景, 前面有什么, 看看周围, 画面里有什么] + + obstacle_avoidance: + # Experimental: enabled only for stationary, supervised browser validation. + # It is not a mobility-safety guarantee and must not be used for navigation. + enabled: true + description: 识别前方可见障碍并给出保守提示(实验) + prompt_source: AAAI_SI/C1_OBSTACLE_AVOID_DIRECT_V1 + prompt_file: ../prompts/obstacle_avoidance_zh.txt + requires_session_restart: true + cooldown_ms: 1500 + cv_mode: shadow + cv_provider: noop + task_trigger: 请立即判断当前画面前方是否有明显障碍,并给出简短、保守的安全提示。 + activation_phrases: [帮我避障, 前面有障碍吗, 前面有没有障碍, 看一下前方障碍, 前面安全吗] diff --git a/extensions/assistive_harness/cv/README.md b/extensions/assistive_harness/cv/README.md new file mode 100644 index 0000000..6c986c2 --- /dev/null +++ b/extensions/assistive_harness/cv/README.md @@ -0,0 +1,171 @@ +# Lightweight CV provider framework (V1) + +This directory is the transport-neutral CV shadow path used by the Assistive +Harness. Browser and future OpenGlass Adapters only provide JPEG frames. They do +not call YOLO, OCR, depth estimation, or control rules directly. + +## V1 data flow + +```text +Browser / ESP32 Adapter + | + | FrameEnvelope(JPEG, timestamp, skill_id, slots) + v +CVPipeline.submit() # returns immediately + | + | capacity-one latest-frame queue (old queued frame is dropped) + v +single background worker + | + | provider.analyze() in a dedicated CPU thread + v +CVObservation -> cv_events.jsonl # shadow only; no control decision +``` + +The Router, state machine, Session Adapter, and MiniCPM audio/video path do not +depend on a concrete CV model. + +## Guarantees and deliberate limits + +- `submit()` never waits for inference. +- The queue is bounded and latest-frame wins; overload cannot grow memory + without limit. +- Only one inference call runs at a time per client pipeline. +- Provider errors become `CVObservation.error` and never escape to the control + socket. +- A timeout is recorded without blocking STOP/RESET. Python cannot kill an + already-running native ONNX call safely, so that one worker lane remains + occupied until the native call returns; new queued frames continue to + collapse to the latest frame. +- V1 accepts only `disabled` and `shadow`. Shadow observations never switch a + Skill, suppress MiniCPM, or speak to the user. +- Temporal voting, result fusion, navigation decisions, and accuracy tuning are + intentionally outside V1. + +## Configuration + +Providers are declared once under `cv.providers`. Each Skill selects one with +`cv_provider`: + +```yaml +cv: + max_fps: 1 + queue_size: 1 + inference_timeout_ms: 2000 + providers: + noop: + type: noop + yolo_onnx: + type: yolo_onnx + model_path: path/to/yolo.onnx + device: cpu + confidence: 0.25 + image_size: 640 + +skills: + find_object: + cv_mode: shadow + cv_provider: yolo_onnx +``` + +Relative model paths are resolved against the YAML directory. Weights are not +owned by the Core. The current local sample points to the previously validated +`OmniHarness/mini_omni_harness/models/yolo26n.onnx` file. + +## Provider contract + +A provider is synchronous. `CVPipeline` is responsible for running it outside +the asyncio/control loop: + +Provider instances are shared so model weights load only once. If a backend is +not safe for concurrent calls from multiple connected clients, the provider +must protect that backend with its own lock, as `YoloOnnxProvider` does. + +```python +from typing import Any +from extensions.assistive_harness.cv.base import CVObservation + + +class OcrOnnxProvider: + def __init__(self, model_path): + self.model_path = model_path + self._session = None # lazy-load on first frame + + def analyze( + self, + frame: bytes | None, + frame_id: str, + timestamp_ms: float, + skill_id: str, + slots: dict[str, Any], + ) -> CVObservation: + if not frame: + raise ValueError("OCR requires a JPEG frame") + # 1. Decode JPEG. + # 2. Lazy-load and run the local model. + # 3. Return JSON-serializable values only. + return CVObservation( + frame_id=frame_id, + timestamp_ms=timestamp_ms, + skill_id=skill_id, + provider="ocr_onnx", + values={ + "status": "ok", + "text": "recognized text", + "regions": [], + "latency_ms": 12.3, + "model": self.model_path.name, + "device": "cpu", + }, + ) +``` + +To add OCR: + +1. Put the implementation in `cv/ocr_onnx.py` and keep model-specific imports + inside that plugin. +2. Add one `ocr_onnx` factory branch in `build_provider_registry()` in + `cv/registry.py`. +3. Add its config under `cv.providers`. +4. Set `read_text.cv_provider: ocr_onnx`; leave `cv_mode: shadow` during tests. +5. Add a blank/synthetic inference smoke plus one recorded real-frame test. + +No changes are required in `router.py`, `state_machine.py`, the browser Adapter, +or the future ESP32 Frame Adapter. + +## Observation schema + +Every plugin produces the same envelope: + +```json +{ + "frame_id": "browser_123", + "timestamp_ms": 123.0, + "skill_id": "find_object", + "provider": "shadow:yolo_onnx", + "values": { + "status": "ok", + "found": true, + "detections": [], + "latency_ms": 31.1, + "pipeline_latency_ms": 42.0 + }, + "error": null +} +``` + +Plugin-specific data belongs under `values`; the outer keys stay stable for +logging, replay, and later OpenGlass migration. + +## Validation + +```powershell +python -m unittest ` + extensions.assistive_harness.tests.test_core ` + extensions.assistive_harness.tests.test_cv_yolo +``` + +The tests cover failure isolation, latest-frame dropping, timeout reporting, +non-blocking submission, and a real ONNX Runtime YOLO inference. A browser +acceptance run should additionally verify that `find_object` produces +`provider=shadow:yolo_onnx` records while STOP/RESET remain responsive. diff --git a/extensions/assistive_harness/cv/__init__.py b/extensions/assistive_harness/cv/__init__.py new file mode 100644 index 0000000..dec2042 --- /dev/null +++ b/extensions/assistive_harness/cv/__init__.py @@ -0,0 +1,14 @@ +from .base import CVObservation, FrameEnvelope, PerceptionProvider +from .noop import NoOpCVProvider, ShadowCVProvider +from .pipeline import CVPipeline +from .registry import CVProviderRegistry + +__all__ = [ + "CVObservation", + "CVPipeline", + "CVProviderRegistry", + "FrameEnvelope", + "NoOpCVProvider", + "PerceptionProvider", + "ShadowCVProvider", +] diff --git a/extensions/assistive_harness/cv/base.py b/extensions/assistive_harness/cv/base.py new file mode 100644 index 0000000..5c1e153 --- /dev/null +++ b/extensions/assistive_harness/cv/base.py @@ -0,0 +1,44 @@ +from __future__ import annotations + +from dataclasses import asdict, dataclass, field +from typing import Any, Protocol + + +@dataclass(slots=True) +class FrameEnvelope: + """Transport-neutral frame handed from an Adapter to the CV worker.""" + + frame: bytes | None + frame_id: str + timestamp_ms: float + skill_id: str + slots: dict[str, Any] = field(default_factory=dict) + mode: str = "shadow" + provider_id: str = "noop" + + +@dataclass(slots=True) +class CVObservation: + frame_id: str + timestamp_ms: float + skill_id: str + provider: str + values: dict[str, Any] = field(default_factory=dict) + error: str | None = None + + def to_dict(self) -> dict[str, Any]: + return asdict(self) + + +class PerceptionProvider(Protocol): + """Synchronous plugin contract; CVPipeline always calls it off-loop.""" + + def analyze( + self, + frame: bytes | None, + frame_id: str, + timestamp_ms: float, + skill_id: str, + slots: dict[str, Any], + ) -> CVObservation: + ... diff --git a/extensions/assistive_harness/cv/noop.py b/extensions/assistive_harness/cv/noop.py new file mode 100644 index 0000000..1770c62 --- /dev/null +++ b/extensions/assistive_harness/cv/noop.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +from typing import Any + +from .base import CVObservation, PerceptionProvider + + +class NoOpCVProvider: + def analyze( + self, + frame: bytes | None, + frame_id: str, + timestamp_ms: float, + skill_id: str, + slots: dict[str, Any], + ) -> CVObservation: + del frame, slots + return CVObservation( + frame_id=frame_id, + timestamp_ms=timestamp_ms, + skill_id=skill_id, + provider="noop", + values={}, + ) + + +class ShadowCVProvider: + """Failure-isolated observer. Its result is never a control decision.""" + + def __init__( + self, + provider: PerceptionProvider | None = None, + provider_id: str | None = None, + ): + self.provider = provider or NoOpCVProvider() + self.provider_id = provider_id or type(self.provider).__name__ + + def analyze( + self, + frame: bytes | None, + frame_id: str, + timestamp_ms: float, + skill_id: str, + slots: dict[str, Any], + ) -> CVObservation: + try: + result = self.provider.analyze( + frame, frame_id, timestamp_ms, skill_id, slots + ) + result.provider = f"shadow:{result.provider}" + return result + except Exception as exc: # shadow failures must not escape + return CVObservation( + frame_id=frame_id, + timestamp_ms=timestamp_ms, + skill_id=skill_id, + provider=f"shadow:{self.provider_id}", + values={}, + error=f"{type(exc).__name__}: {exc}", + ) diff --git a/extensions/assistive_harness/cv/pipeline.py b/extensions/assistive_harness/cv/pipeline.py new file mode 100644 index 0000000..f17f9cf --- /dev/null +++ b/extensions/assistive_harness/cv/pipeline.py @@ -0,0 +1,159 @@ +from __future__ import annotations + +import asyncio +import time +from concurrent.futures import ThreadPoolExecutor +from typing import Callable + +from .base import CVObservation, FrameEnvelope +from .registry import CVProviderRegistry + + +ObservationCallback = Callable[[CVObservation], None] +MetricCallback = Callable[[str, float], None] + + +class CVPipeline: + """Latest-frame-only worker that keeps CV inference off the control loop.""" + + def __init__( + self, + providers: CVProviderRegistry, + *, + on_observation: ObservationCallback, + on_metric: MetricCallback | None = None, + queue_size: int = 1, + inference_timeout_ms: float = 2000.0, + worker_name: str = "assistive-cv", + ) -> None: + if int(queue_size) != 1: + raise ValueError("CV V1 requires queue_size=1 (latest-frame-only)") + self.providers = providers + self.on_observation = on_observation + self.on_metric = on_metric + self.queue: asyncio.Queue[FrameEnvelope] = asyncio.Queue(maxsize=1) + self.inference_timeout_ms = max(1.0, float(inference_timeout_ms)) + self.executor = ThreadPoolExecutor(max_workers=1, thread_name_prefix=worker_name) + self.worker_task: asyncio.Task[None] | None = None + self.closed = False + self.submitted_frames = 0 + self.processed_frames = 0 + self.dropped_frames = 0 + self.timeout_count = 0 + + def submit(self, envelope: FrameEnvelope) -> bool: + """Enqueue without awaiting inference; replace the oldest queued frame.""" + if self.closed or envelope.mode == "disabled": + return False + self._ensure_worker() + if self.queue.full(): + try: + self.queue.get_nowait() + self.queue.task_done() + self.dropped_frames += 1 + self._metric("cv_frames_dropped", 1.0) + except asyncio.QueueEmpty: + pass + self.queue.put_nowait(envelope) + self.submitted_frames += 1 + return True + + def snapshot(self) -> dict[str, int | bool]: + return { + "closed": self.closed, + "queued_frames": self.queue.qsize(), + "submitted_frames": self.submitted_frames, + "processed_frames": self.processed_frames, + "dropped_frames": self.dropped_frames, + "timeout_count": self.timeout_count, + } + + async def close(self) -> None: + if self.closed: + return + self.closed = True + if self.worker_task is not None: + self.worker_task.cancel() + await asyncio.gather(self.worker_task, return_exceptions=True) + self.executor.shutdown(wait=False, cancel_futures=True) + + def _ensure_worker(self) -> None: + if self.worker_task is None or self.worker_task.done(): + self.worker_task = asyncio.create_task(self._run()) + + async def _run(self) -> None: + loop = asyncio.get_running_loop() + while True: + envelope = await self.queue.get() + started = time.perf_counter() + future = loop.run_in_executor(self.executor, self.providers.analyze, envelope) + try: + observation = await asyncio.wait_for( + asyncio.shield(future), self.inference_timeout_ms / 1000.0 + ) + except asyncio.TimeoutError: + self.timeout_count += 1 + self._metric("cv_inference_timeout", 1.0) + self._emit( + CVObservation( + frame_id=envelope.frame_id, + timestamp_ms=envelope.timestamp_ms, + skill_id=envelope.skill_id, + provider=f"{envelope.mode}:{envelope.provider_id}", + values={ + "status": "timeout", + "timeout_ms": self.inference_timeout_ms, + }, + error=( + "TimeoutError: CV inference exceeded " + f"{self.inference_timeout_ms:.0f} ms" + ), + ) + ) + # Python cannot safely kill an in-flight native inference call. + # Keep this one-worker lane occupied until it exits so timeouts + # never create concurrent calls or an unbounded executor queue. + try: + await future + except Exception: + pass + except asyncio.CancelledError: + raise + except Exception as exc: + self._emit( + CVObservation( + frame_id=envelope.frame_id, + timestamp_ms=envelope.timestamp_ms, + skill_id=envelope.skill_id, + provider=f"{envelope.mode}:{envelope.provider_id}", + values={"status": "error"}, + error=f"{type(exc).__name__}: {exc}", + ) + ) + else: + observation.values.setdefault( + "pipeline_latency_ms", round((time.perf_counter() - started) * 1000, 1) + ) + self.processed_frames += 1 + self._metric( + "cv_pipeline_latency_ms", + float(observation.values["pipeline_latency_ms"]), + ) + self._emit(observation) + finally: + self.queue.task_done() + + def _emit(self, observation: CVObservation) -> None: + try: + self.on_observation(observation) + except Exception: + # Telemetry/consumer failures are also outside the control path. + pass + + def _metric(self, name: str, value: float) -> None: + if self.on_metric is None: + return + try: + self.on_metric(name, value) + except Exception: + pass diff --git a/extensions/assistive_harness/cv/registry.py b/extensions/assistive_harness/cv/registry.py new file mode 100644 index 0000000..dbe3b4e --- /dev/null +++ b/extensions/assistive_harness/cv/registry.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +from pathlib import Path +from typing import Any + +from .base import CVObservation, FrameEnvelope, PerceptionProvider +from .noop import NoOpCVProvider, ShadowCVProvider + + +class CVProviderRegistry: + """Small explicit registry shared by browser and future device Adapters.""" + + def __init__(self, providers: dict[str, PerceptionProvider] | None = None): + self.providers: dict[str, PerceptionProvider] = { + "noop": NoOpCVProvider(), + **(providers or {}), + } + self._shadow = { + provider_id: ShadowCVProvider(provider, provider_id) + for provider_id, provider in self.providers.items() + } + + def register(self, provider_id: str, provider: PerceptionProvider) -> None: + normalized = provider_id.strip() + if not normalized: + raise ValueError("provider_id cannot be empty") + self.providers[normalized] = provider + self._shadow[normalized] = ShadowCVProvider(provider, normalized) + + def analyze(self, envelope: FrameEnvelope) -> CVObservation: + if envelope.mode != "shadow": + return CVObservation( + frame_id=envelope.frame_id, + timestamp_ms=envelope.timestamp_ms, + skill_id=envelope.skill_id, + provider=f"{envelope.mode}:{envelope.provider_id}", + values={"status": "skipped", "reason": "unsupported_cv_mode"}, + error=f"Unsupported cv_mode: {envelope.mode}", + ) + provider = self._shadow.get(envelope.provider_id) + if provider is None: + return CVObservation( + frame_id=envelope.frame_id, + timestamp_ms=envelope.timestamp_ms, + skill_id=envelope.skill_id, + provider=f"shadow:{envelope.provider_id}", + values={"status": "skipped", "reason": "unknown_provider"}, + error=f"Unknown CV provider: {envelope.provider_id}", + ) + return provider.analyze( + envelope.frame, + envelope.frame_id, + envelope.timestamp_ms, + envelope.skill_id, + envelope.slots, + ) + + +def build_provider_registry( + config: dict[str, Any], *, config_dir: Path +) -> CVProviderRegistry: + registry = CVProviderRegistry() + providers = dict((config.get("cv") or {}).get("providers") or {}) + for provider_id, raw_spec in providers.items(): + spec = dict(raw_spec or {}) + provider_type = str(spec.get("type") or provider_id) + if provider_type == "noop": + registry.register(str(provider_id), NoOpCVProvider()) + continue + if provider_type == "yolo_onnx": + from .yolo_onnx import YoloOnnxProvider + + raw_path = Path(str(spec.get("model_path") or "")) + model_path = raw_path if raw_path.is_absolute() else config_dir / raw_path + registry.register( + str(provider_id), + YoloOnnxProvider( + model_path.resolve(), + device=str(spec.get("device") or "cpu"), + confidence=float(spec.get("confidence", 0.25)), + image_size=int(spec.get("image_size", 640)), + target_aliases=dict(spec.get("target_aliases") or {}), + ), + ) + continue + raise ValueError( + f"Unsupported CV provider type {provider_type!r} for {provider_id!r}" + ) + return registry diff --git a/extensions/assistive_harness/cv/requirements-cv.txt b/extensions/assistive_harness/cv/requirements-cv.txt new file mode 100644 index 0000000..72c2319 --- /dev/null +++ b/extensions/assistive_harness/cv/requirements-cv.txt @@ -0,0 +1,2 @@ +opencv-python-headless +onnxruntime==1.21.0 diff --git a/extensions/assistive_harness/cv/yolo_onnx.py b/extensions/assistive_harness/cv/yolo_onnx.py new file mode 100644 index 0000000..01ca1c8 --- /dev/null +++ b/extensions/assistive_harness/cv/yolo_onnx.py @@ -0,0 +1,220 @@ +from __future__ import annotations + +import threading +import time +from pathlib import Path +from typing import Any + +import numpy as np + +from .base import CVObservation + + +COCO_NAMES = ( + "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", + "truck", "boat", "traffic light", "fire hydrant", "stop sign", + "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", + "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", + "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", + "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", + "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", + "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", + "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", + "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", + "mouse", "remote", "keyboard", "cell phone", "microwave", "oven", + "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", + "teddy bear", "hair drier", "toothbrush", +) + +DEFAULT_TARGET_ALIASES = { + "手机": "cell phone", "电话": "cell phone", "智能手机": "cell phone", + "phone": "cell phone", "cellphone": "cell phone", "cell phone": "cell phone", + "书": "book", "书本": "book", "图书": "book", "book": "book", + "杯子": "cup", "水杯": "cup", "茶杯": "cup", "cup": "cup", + "瓶子": "bottle", "水瓶": "bottle", "bottle": "bottle", + "椅子": "chair", "chair": "chair", "人": "person", "行人": "person", + "person": "person", "电脑": "laptop", "笔记本电脑": "laptop", + "laptop": "laptop", "遥控器": "remote", "remote": "remote", + "键盘": "keyboard", "keyboard": "keyboard", "鼠标": "mouse", + "mouse": "mouse", "背包": "backpack", "书包": "backpack", + "backpack": "backpack", +} + + +class YoloOnnxProvider: + """CPU-first YOLO ONNX reference plugin with no control-side effects.""" + + def __init__( + self, + model_path: Path, + *, + device: str = "cpu", + confidence: float = 0.25, + image_size: int = 640, + target_aliases: dict[str, str] | None = None, + ) -> None: + if device.lower() != "cpu": + raise ValueError("CV V1 only accepts device=cpu") + self.model_path = Path(model_path).resolve() + self.device = "cpu" + self.confidence = float(confidence) + self.image_size = int(image_size) + self.target_aliases = { + **DEFAULT_TARGET_ALIASES, + **{str(k).lower(): str(v) for k, v in (target_aliases or {}).items()}, + } + self._session: Any = None + self._input_name: str | None = None + self._cv2: Any = None + self._lock = threading.Lock() + + def analyze( + self, + frame: bytes | None, + frame_id: str, + timestamp_ms: float, + skill_id: str, + slots: dict[str, Any], + ) -> CVObservation: + if not frame: + raise ValueError("YOLO requires a non-empty JPEG frame") + self._load() + target = str(slots.get("target") or "").strip() + target_label = self._resolve_target(target) if target else None + if target and target_label is None: + return CVObservation( + frame_id=frame_id, + timestamp_ms=timestamp_ms, + skill_id=skill_id, + provider="yolo_onnx", + values={ + "status": "skipped", + "reason": "unsupported_target", + "target": target, + }, + ) + + encoded = np.frombuffer(frame, dtype=np.uint8) + image = self._cv2.imdecode(encoded, self._cv2.IMREAD_COLOR) + if image is None: + raise ValueError("YOLO could not decode the JPEG frame") + height, width = image.shape[:2] + started = time.perf_counter() + tensor, scale, pad_x, pad_y = self._prepare_input(image) + with self._lock: + output = self._session.run(None, {self._input_name: tensor})[0] + latency_ms = (time.perf_counter() - started) * 1000.0 + if output.ndim != 3 or output.shape[0] != 1 or output.shape[2] != 6: + raise ValueError(f"Unexpected YOLO output shape: {output.shape}") + + target_id = COCO_NAMES.index(target_label) if target_label else None + detections: list[dict[str, Any]] = [] + for row in output[0]: + x1, y1, x2, y2, confidence, raw_class = row + class_id = round(float(raw_class)) + if float(confidence) < self.confidence or not 0 <= class_id < len(COCO_NAMES): + continue + if target_id is not None and class_id != target_id: + continue + left = max(0.0, min(width, (float(x1) - pad_x) / scale)) + top = max(0.0, min(height, (float(y1) - pad_y) / scale)) + right = max(0.0, min(width, (float(x2) - pad_x) / scale)) + bottom = max(0.0, min(height, (float(y2) - pad_y) / scale)) + if right <= left or bottom <= top: + continue + center_x = ((left + right) / 2.0) / width + center_y = ((top + bottom) / 2.0) / height + detections.append( + { + "label": COCO_NAMES[class_id], + "confidence": round(float(confidence), 4), + "bbox_xyxy": [round(left), round(top), round(right), round(bottom)], + "bbox_normalized": [ + round(left / width, 4), round(top / height, 4), + round(right / width, 4), round(bottom / height, 4), + ], + "center_normalized": [round(center_x, 4), round(center_y, 4)], + "position": self._position(center_x, center_y), + } + ) + detections.sort(key=lambda item: float(item["confidence"]), reverse=True) + return CVObservation( + frame_id=frame_id, + timestamp_ms=timestamp_ms, + skill_id=skill_id, + provider="yolo_onnx", + values={ + "status": "ok", + "found": bool(detections), + "target": target or None, + "canonical_label": target_label, + "best_detection": detections[0] if detections else None, + "detections": detections, + "image": {"width": width, "height": height}, + "latency_ms": round(latency_ms, 1), + "frame_age_ms": round(max(0.0, time.time() * 1000.0 - timestamp_ms), 1), + "model": self.model_path.name, + "device": self.device, + }, + ) + + def _load(self) -> None: + if self._session is not None: + return + if not self.model_path.is_file(): + raise FileNotFoundError(f"YOLO weights not found: {self.model_path}") + import cv2 + import onnxruntime as ort + + session = ort.InferenceSession( + str(self.model_path), providers=["CPUExecutionProvider"] + ) + model_input = session.get_inputs()[0] + if model_input.shape[-2:] != [self.image_size, self.image_size]: + raise ValueError( + f"YOLO input is {model_input.shape[-2:]}, expected " + f"[{self.image_size}, {self.image_size}]" + ) + self._cv2 = cv2 + self._session = session + self._input_name = model_input.name + + def _prepare_input( + self, image: np.ndarray + ) -> tuple[np.ndarray, float, float, float]: + height, width = image.shape[:2] + scale = min(self.image_size / width, self.image_size / height) + resized_width, resized_height = round(width * scale), round(height * scale) + resized = self._cv2.resize(image, (resized_width, resized_height)) + pad_x = (self.image_size - resized_width) / 2.0 + pad_y = (self.image_size - resized_height) / 2.0 + left, top = round(pad_x - 0.1), round(pad_y - 0.1) + right = self.image_size - resized_width - left + bottom = self.image_size - resized_height - top + padded = self._cv2.copyMakeBorder( + resized, top, bottom, left, right, + self._cv2.BORDER_CONSTANT, value=(114, 114, 114), + ) + rgb = self._cv2.cvtColor(padded, self._cv2.COLOR_BGR2RGB) + tensor = np.ascontiguousarray(rgb.transpose(2, 0, 1), dtype=np.float32) + return np.expand_dims(tensor / 255.0, axis=0), scale, float(left), float(top) + + def _resolve_target(self, target: str) -> str | None: + normalized = target.lower().replace(" ", "") + for alias in sorted(self.target_aliases, key=len, reverse=True): + if alias.lower().replace(" ", "") in normalized: + label = self.target_aliases[alias] + return label if label in COCO_NAMES else None + return None + + @staticmethod + def _position(center_x: float, center_y: float) -> str: + horizontal = "左" if center_x < 1 / 3 else "右" if center_x > 2 / 3 else "中" + vertical = "上" if center_y < 1 / 3 else "下" if center_y > 2 / 3 else "中" + return { + ("左", "上"): "左上方", ("中", "上"): "正上方", + ("右", "上"): "右上方", ("左", "中"): "左侧", + ("中", "中"): "中央", ("右", "中"): "右侧", + ("左", "下"): "左下方", ("中", "下"): "正下方", + ("右", "下"): "右下方", + }[(horizontal, vertical)] diff --git a/extensions/assistive_harness/echo_guard.py b/extensions/assistive_harness/echo_guard.py new file mode 100644 index 0000000..fc3d25e --- /dev/null +++ b/extensions/assistive_harness/echo_guard.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +import time +from collections import deque +from dataclasses import dataclass +from difflib import SequenceMatcher + +from .router import normalize_text +from .schemas import ControlIntent + + +@dataclass(frozen=True, slots=True) +class EchoDecision: + allow: bool + reason: str + similarity: float = 0.0 + + +class EchoGuard: + def __init__(self, window_ms: int = 20_000, similarity_threshold: float = 0.86): + self.window_ms = int(window_ms) + self.similarity_threshold = float(similarity_threshold) + self._model_text: deque[tuple[float, str]] = deque() + self.ai_speaking = False + + def note_model_text(self, text: str, at_ms: float | None = None) -> None: + normalized = normalize_text(text) + if not normalized: + return + now = at_ms if at_ms is not None else time.time() * 1000 + self._model_text.append((now, normalized)) + self._prune(now) + + def set_ai_speaking(self, active: bool) -> None: + self.ai_speaking = bool(active) + + def _prune(self, now_ms: float) -> None: + cutoff = now_ms - self.window_ms + while self._model_text and self._model_text[0][0] < cutoff: + self._model_text.popleft() + + def evaluate( + self, + utterance: str, + intent: ControlIntent, + at_ms: float | None = None, + ) -> EchoDecision: + now = at_ms if at_ms is not None else time.time() * 1000 + self._prune(now) + normalized = normalize_text(utterance) + if len(normalized) < 2: + return EchoDecision(False, "too_short") + + best = 0.0 + for _, model_text in self._model_text: + if normalized in model_text or model_text in normalized: + best = 1.0 + break + best = max(best, SequenceMatcher(None, normalized, model_text).ratio()) + if best >= self.similarity_threshold: + return EchoDecision(False, "matches_recent_model_echo", best) + + if self.ai_speaking and intent not in { + ControlIntent.STOP_SPEECH, + ControlIntent.RESUME_SPEECH, + ControlIntent.RESET_SESSION, + ControlIntent.CANCEL_SKILL, + ControlIntent.RETURN_TO_CHAT, + # A positively routed Skill command is also a control-plane + # interruption. Recent-model-text similarity is checked above, + # so model echo is still rejected before this exception applies. + ControlIntent.ACTIVATE_SKILL, + }: + return EchoDecision(False, "ordinary_skill_suppressed_while_ai_speaking", best) + return EchoDecision(True, "allowed", best) diff --git a/extensions/assistive_harness/model_log.py b/extensions/assistive_harness/model_log.py new file mode 100644 index 0000000..43045e4 --- /dev/null +++ b/extensions/assistive_harness/model_log.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Any + + +@dataclass(slots=True) +class ModelTurnAccumulator: + """Aggregate streamed Gateway fragments into auditable model turns.""" + + turn_index: int = 0 + _key: tuple[Any, ...] | None = None + _text: list[str] = field(default_factory=list) + _audio_ms: float = 0.0 + _metadata: dict[str, Any] = field(default_factory=dict) + + def _flush(self) -> dict[str, Any] | None: + if self._key is None: + return None + self.turn_index += 1 + record = { + "type": "model.turn", + "turn_index": self.turn_index, + **self._metadata, + "text": "".join(self._text), + "audio_ms": round(self._audio_ms, 1), + } + self._key = None + self._text.clear() + self._audio_ms = 0.0 + self._metadata = {} + return record + + def feed(self, message: dict[str, Any]) -> list[dict[str, Any]]: + state = str(message.get("state") or "unknown") + key = ( + message.get("session_id"), + int(message.get("generation") or 0), + str(message.get("skill_id") or ""), + state, + ) + completed: list[dict[str, Any]] = [] + if self._key is not None and key != self._key: + record = self._flush() + if record is not None: + completed.append(record) + + text = str(message.get("text") or "") + audio_ms = float(message.get("audio_ms") or 0.0) + end_of_turn = bool(message.get("end_of_turn")) + if self._key is None and (text or audio_ms > 0): + self._key = key + self._metadata = { + "role": "assistant" if state == "speak" else "listen", + "state": state, + "session_id": message.get("session_id"), + "generation": int(message.get("generation") or 0), + "skill_id": str(message.get("skill_id") or ""), + "slots": dict(message.get("slots") or {}), + } + if self._key is not None: + if text: + self._text.append(text) + self._audio_ms += max(0.0, audio_ms) + if end_of_turn: + record = self._flush() + if record is not None: + completed.append(record) + return completed + + def flush(self) -> dict[str, Any] | None: + return self._flush() diff --git a/extensions/assistive_harness/package_phase_a.ps1 b/extensions/assistive_harness/package_phase_a.ps1 new file mode 100644 index 0000000..8264580 --- /dev/null +++ b/extensions/assistive_harness/package_phase_a.ps1 @@ -0,0 +1,69 @@ +param( + [string]$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path, + [string]$Date = '2026-08-11' +) + +$ErrorActionPreference = 'Stop' +$deliverables = Join-Path $RepoRoot 'deliverables' +$packageName = "VOICE_SKILL_HARNESS_PHASE_A_CODEX_RETURN_$Date" +$stage = Join-Path $deliverables $packageName +$zipPath = Join-Path $deliverables "$packageName.zip" + +$resolvedRepo = (Resolve-Path $RepoRoot).Path.TrimEnd('\') +New-Item -ItemType Directory -Force -Path $deliverables | Out-Null +$resolvedDeliverables = (Resolve-Path $deliverables).Path +if (-not $resolvedDeliverables.StartsWith($resolvedRepo, [StringComparison]::OrdinalIgnoreCase)) { + throw "Unsafe delivery target: $resolvedDeliverables" +} +if (Test-Path $stage) { Remove-Item -LiteralPath $stage -Recurse -Force } +if (Test-Path $zipPath) { Remove-Item -LiteralPath $zipPath -Force } +New-Item -ItemType Directory -Force -Path $stage | Out-Null + +function Copy-TreeFiltered([string]$Source, [string]$Destination) { + Get-ChildItem -LiteralPath $Source -Recurse -File | Where-Object { + $_.FullName -notmatch '[\\/]runs[\\/]' -and + $_.FullName -notmatch '[\\/]__pycache__[\\/]' -and + $_.FullName -notmatch '[\\/]test_artifacts[\\/]' -and + $_.Extension -ne '.pyc' + } | ForEach-Object { + $relative = $_.FullName.Substring($Source.TrimEnd('\').Length).TrimStart('\') + $target = Join-Path $Destination $relative + New-Item -ItemType Directory -Force -Path (Split-Path $target) | Out-Null + Copy-Item -LiteralPath $_.FullName -Destination $target + } +} + +Copy-TreeFiltered (Join-Path $RepoRoot 'extensions\assistive_harness') (Join-Path $stage 'extensions\assistive_harness') +Copy-TreeFiltered (Join-Path $RepoRoot 'static\assistive_harness') (Join-Path $stage 'static\assistive_harness') +New-Item -ItemType Directory -Force -Path (Join-Path $stage 'static\omni') | Out-Null +Copy-Item -LiteralPath (Join-Path $RepoRoot 'static\omni\omni-app.js') -Destination (Join-Path $stage 'static\omni\omni-app.js') + +$docNames = @( + 'VOICE_SKILL_HARNESS_AUDIT.md', + 'VOICE_SKILL_HARNESS_DESIGN.md', + 'VOICE_SKILL_HARNESS_EXECUTION_REPORT.md', + 'VOICE_SKILL_HARNESS_GO_NO_GO.md', + 'VOICE_SKILL_HARNESS_RERUN_COMMANDS.md', + 'VOICE_SKILL_HARNESS_CHANGED_FILES.md' +) +$docTarget = Join-Path $stage '_codex_context' +New-Item -ItemType Directory -Force -Path $docTarget | Out-Null +foreach ($name in $docNames) { + $text = Get-Content -Raw -Encoding UTF8 (Join-Path $RepoRoot "_codex_context\$name") + $text = $text.Replace($env:USERPROFILE, '%USERPROFILE%') + Set-Content -Encoding UTF8 -NoNewline -Path (Join-Path $docTarget $name) -Value $text +} + +$manifest = [ordered]@{ + project = 'Voice-Controlled Skill Harness' + phase = 'A_MINICPMO_BROWSER' + date = $Date + ready_for_phase_b = $false + feature_default = 'off' + excluded = @('model weights', 'raw audio/video', 'runs', 'credentials', 'absolute user paths') +} +$manifest | ConvertTo-Json -Depth 5 | Set-Content -Encoding UTF8 (Join-Path $stage 'MANIFEST.json') + +Compress-Archive -Path (Join-Path $stage '*') -DestinationPath $zipPath -CompressionLevel Optimal +$hash = (Get-FileHash -Algorithm SHA256 -LiteralPath $zipPath).Hash +[pscustomobject]@{Zip=$zipPath; SHA256=$hash} diff --git a/extensions/assistive_harness/phase_b/README.md b/extensions/assistive_harness/phase_b/README.md new file mode 100644 index 0000000..b7ffe10 --- /dev/null +++ b/extensions/assistive_harness/phase_b/README.md @@ -0,0 +1,114 @@ +# Rokid Phase B Adapter + +This adapter replaces the Phase A browser transport while preserving the +frozen Harness policy and the existing MiniCPM backend: + +```text +Rokid APK --JPEG/PCM over Wi-Fi--> Phase B Adapter :18080 + |-- audio.mirror/frame.shadow --> Harness :8021 + |-- audio_chunk + JPEG --------> Gateway :8040 + `-- MiniCPM audio -------------> PC speaker +``` + +The backend remains `llama.cpp-omni -> Worker -> Gateway :8040 -> MiniCPM-o +4.5`. The old ESP32 and Rokid bridge scripts remain reference implementations; +`demo_rokid_phase_b_harness.py` is the Phase B entry point. + +## Frozen control contract + +- `STOP`: block and flush PC playback immediately. Device PCM continues to + reach Harness ASR and Gateway with `force_listen=true`. +- `RESUME`: release the playback gate without replacing the Session. +- `RESET`: stop the old Gateway Session with light cleanup, increment the + generation, create a new Session using the idle prompt, and reject stale + output. After `restart_complete`, the PC plays a short two-note ready cue; + initial startup stays silent. Use `--no-session-ready-chime` to disable it, + or `--session-ready-chime-volume` (default `0.32`) to tune it. +- Skill activation, cancellation, and return-to-chat use the same replacement + flow with the prompt and slots supplied by Harness. +- After a Skill Session reaches `restart_complete`, Harness injects the + original one-shot task into that new Session. This makes read-text and + experimental obstacle activation answer once instead of only changing the + system prompt. +- Rokid PCM is repacketized into 100 ms float32 `audio.mirror` frames, matching + Phase A. A bounded drop-oldest queue prevents device capture from being + blocked by Gateway latency. +- PC speaker queue depth plus `--playback-echo-tail-s` (default `0.80`) keeps + EchoGuard active through buffered playback and its short acoustic tail. + +## Prerequisites + +Run the existing Worker/Gateway on port 8040 and the Assistive Harness on port +8021. Install optional adapter dependencies from `requirements-phase-b.txt` in +the same Python environment. + +The current Rokid APK must target the host computer on port 18080 and provide: + +- `POST /rokid/image` with raw JPEG bytes; +- `WS /rokid/audio` with 16 kHz mono signed PCM16 little-endian packets. + +## Start + +From the repository root: + +```powershell +python .\demo_rokid_phase_b_harness.py ` + --gateway localhost:8040 ` + --harness-url ws://127.0.0.1:8021/ws/control ` + --input-gain 12 ` + --image-rotate-cw 270 ` + --session-ready-chime-volume 0.32 ` + --playback-echo-tail-s 0.80 +``` + +The local Gateway currently uses plain `ws://`. Use `--gateway-tls` only when +the deployed Gateway endpoint actually serves `wss://`. First-round model audio +plays on the computer; `--no-play` disables playback for diagnostics. + +The Rokid SDK PCM observed on the current device is materially quieter than the +browser microphone signal. `--input-gain 12` is the initial device calibration; +gain is applied before both Harness and Gateway and saturates instead of wrapping +PCM16. Recalibrate from real-device RMS logs rather than lowering the shared +Phase A VAD threshold. + +The ready cue briefly suppresses Rokid PCM forwarding for the cue plus a short +guard interval so the laptop speaker notification is not immediately recycled +into Harness or MiniCPM-o. + +Streaming model text is aggregated by Session, generation and end-of-turn. It +is printed as `[AssistiveHarness][MODEL]` and written under the current run: + +- `model_events.jsonl` for structured records; +- `model_transcript.txt` for quick human review. + +This is generated model text, not ASR over the final TTS waveform. Keep a +session recording when exact spoken audio must be audited. + +Health and the normalized latest frame are available at: + +- `GET http://127.0.0.1:18080/health` +- `GET http://127.0.0.1:18080/capture` + +Healthy input is approximately 25 audio packets/s and 1 JPEG/s, with one audio +client, zero sustained queue drops, `harness_connected=true`, and +`gateway_status=running`. `device_input_ready=true` confirms that at least one +PCM packet or JPEG has reached this process. If `[ROKID][NO_INPUT]` appears, +restart Sensor Mode on the glasses (`STOP -> RUN`) after the PC listener is up; +an APK WebSocket disconnected by a PC restart may not reconnect by itself. + +Stop the adapter with `Ctrl+C` (or `Ctrl+Break` on Windows). The HTTP listener, +Rokid WebSocket handler, Gateway Session, Harness connection, and PC speaker are +closed with bounded waits. A 10-second process watchdog is the final fallback, +so a native audio cleanup stall cannot leave port 18080 occupied indefinitely. + +## First device acceptance order + +1. Ordinary speech produces a MiniCPM response on the PC speaker. +2. While it speaks, say `停一下`; playback must stop and Harness must ACK + `stop_speech`. +3. Say `恢复对话`; the same Session resumes. +4. Say `重新开始`; the Session ID and generation must change. +5. Activate `找物`, `识字`, `场景描述`, and supervised experimental `避障`; + each switch must complete with a new Session and no old-generation output. + +Experimental obstacle output is not a navigation or safety guarantee. diff --git a/extensions/assistive_harness/phase_b/__init__.py b/extensions/assistive_harness/phase_b/__init__.py new file mode 100644 index 0000000..80d861b --- /dev/null +++ b/extensions/assistive_harness/phase_b/__init__.py @@ -0,0 +1,5 @@ +"""Device adapters for the Phase B glasses runtime.""" + +from .rokid_runtime import PhaseBRokidRuntime, RokidRuntimeConfig + +__all__ = ["PhaseBRokidRuntime", "RokidRuntimeConfig"] diff --git a/extensions/assistive_harness/phase_b/bridge_ui.py b/extensions/assistive_harness/phase_b/bridge_ui.py new file mode 100644 index 0000000..c3940f8 --- /dev/null +++ b/extensions/assistive_harness/phase_b/bridge_ui.py @@ -0,0 +1,337 @@ +"""bridge_ui.py — ESP32 duplex bridge 的 Web 观测/回放服务 + +URL: + / 实时观测(摄像头 + 字幕 + 状态) + /replay session 列表 + /replay/ session 回放(直接播 live_session.mp4,字幕跟随) + +依赖 recorder_live.py v5+ 写到 session_dir 的成品: + live_session.mp4 ← 播放主体(ffmpeg 已对齐) + live_session.m4a ← 没有视频帧时的纯音频回退 + live_user.wav ← 诊断下载 + live_ai.wav ← 诊断下载 + events.jsonl ← 字幕/事件源 + meta.json ← 会话元信息 +""" + +from __future__ import annotations +from typing import Optional, Set, Callable +import json +import logging +from pathlib import Path +from typing import Optional, Set + +from aiohttp import web + +LOGGER = logging.getLogger("bridge_ui") + +# 模板目录(和 bridge_ui.py 同级的 templates/) +TEMPLATES_DIR = Path(__file__).parent / "templates" + +# 开发期想"改完刷新浏览器就生效"就设 True;生产环境设 False 只读一次 +HOT_RELOAD_TEMPLATES = True + +_template_cache: dict[str, str] = {} + +def _load_template(name: str) -> str: + """读取 templates/。HOT_RELOAD_TEMPLATES=True 时每次都重读。""" + if not HOT_RELOAD_TEMPLATES and name in _template_cache: + return _template_cache[name] + path = TEMPLATES_DIR / name + try: + text = path.read_text(encoding="utf-8") + except FileNotFoundError: + LOGGER.error("[UI] template not found: %s", path) + return f"

Template not found: {name}

" + _template_cache[name] = text + return text + + +# ============================================================ +# Server +# ============================================================ + +class WebUIServer: + def __init__(self, port: int = 8080, host: str = "0.0.0.0", + sessions_root: Path = Path("./sessions"), + stop_callback: Optional[Callable[[], None]] = None, + mode_info: Optional[dict] = None): + self.port = port + self.host = host + self.sessions_root = Path(sessions_root) + self.live_clients: Set[web.WebSocketResponse] = set() + self._runner: Optional[web.AppRunner] = None + self._stop_callback = stop_callback # ← 新增 + self._stop_fired = False # ← 新增,防重入 + self.mode_info = mode_info or {"mode": "live"} + + async def start(self) -> None: + app = web.Application() + app.router.add_get('/', self._h_live) + app.router.add_get('/replay', self._h_replay_index) + app.router.add_get('/replay/{sid}', self._h_replay) + app.router.add_get('/live_ws', self._h_live_ws) + app.router.add_get('/api/sessions', self._h_list) + app.router.add_get('/api/session/{sid}/events', self._h_events) + app.router.add_get('/api/session/{sid}/meta', self._h_meta) + # —— v2: 直接吐成品文件,FileResponse 自带 HTTP Range 支持 —— + app.router.add_get('/api/session/{sid}/video', self._h_video) + app.router.add_get('/api/session/{sid}/audio', self._h_audio_only) + app.router.add_get('/api/session/{sid}/user_audio.wav', self._h_user_wav) + app.router.add_get('/api/session/{sid}/ai_audio.wav', self._h_ai_wav) + # 兼容老路由(可能旧版 events.jsonl 引用 images/xxx.jpg) + app.router.add_get('/api/session/{sid}/{path:images/.+}', self._h_image_legacy) + app.router.add_get('/api/session/{sid}/{path:live_images/.+}', self._h_image_live) + app.router.add_post('/api/stop', self._h_stop) + self._runner = web.AppRunner(app) + await self._runner.setup() + site = web.TCPSite(self._runner, self.host, self.port) + await site.start() + LOGGER.info("[UI] http://%s:%d (live + replay)", self.host, self.port) + + async def stop(self) -> None: + for ws in list(self.live_clients): + try: await ws.close() + except Exception: pass + if self._runner: + await self._runner.cleanup() + + async def emit(self, evt: dict) -> None: + if not self.live_clients: + return + msg = json.dumps(evt, ensure_ascii=False) + dead = [] + for ws in list(self.live_clients): + try: await ws.send_str(msg) + except Exception: dead.append(ws) + for ws in dead: + self.live_clients.discard(ws) + + # ---- handlers ---- + async def _h_live(self, request): + return web.Response(text=_load_template("live.html"), content_type='text/html') + + async def _h_stop(self, request): + if self._stop_fired: + return web.json_response({"ok": True, "already": True}) + self._stop_fired = True + LOGGER.info("[UI] /api/stop triggered by browser") + # 通知所有 live 客户端"要关了",前端可以把按钮改成"Saving..." + try: + await self.emit({"type": "stopping"}) + except Exception: + pass + if self._stop_callback is not None: + try: + self._stop_callback() + except Exception as e: + LOGGER.warning("[UI] stop_callback err: %s", e) + return web.json_response({"ok": True}) + + async def _h_replay_index(self, request): + return web.Response(text=_load_template("replay_index.html"), content_type='text/html') + + async def _h_replay(self, request): + return web.Response(text=_load_template("replay.html"), content_type='text/html') + + async def _h_live_ws(self, request): + ws = web.WebSocketResponse(heartbeat=30) + await ws.prepare(request) + self.live_clients.add(ws) + + LOGGER.info("[UI] live client +1 (total=%d)", len(self.live_clients)) + try: + await ws.send_str(json.dumps( + {"type": "mode", **self.mode_info}, ensure_ascii=False)) + except Exception: + pass + + try: + async for _ in ws: pass + finally: + self.live_clients.discard(ws) + LOGGER.info("[UI] live client -1 (total=%d)", len(self.live_clients)) + return ws + + async def _h_list(self, request): + sessions = [] + if self.sessions_root.exists(): + for d in sorted(self.sessions_root.iterdir(), reverse=True): + if not d.is_dir(): + continue + meta_p = d / "meta.json" + meta = {} + if meta_p.exists(): + try: + meta = json.loads(meta_p.read_text(encoding='utf-8')) + except Exception: + pass + if (d / "live_session.mp4").exists(): + media = "mp4" + elif (d / "live_session.m4a").exists(): + media = "m4a" + else: + media = None + sessions.append({ + "id": d.name, + "tag": meta.get("session_tag", d.name), + "start_time": meta.get("start_time"), + "end_time": meta.get("end_time"), + "stats": meta.get("stats", {}), + "media": media, + }) + return web.json_response({"sessions": sessions}) + + def _safe(self, sid: str) -> Optional[Path]: + if "/" in sid or ".." in sid: + return None + p = (self.sessions_root / sid).resolve() + try: + p.relative_to(self.sessions_root.resolve()) + except ValueError: + return None + if not p.is_dir(): + return None + return p + + async def _h_meta(self, request): + p = self._safe(request.match_info['sid']) + if not p: + return web.json_response({"error": "not found"}, status=404) + meta = p / "meta.json" + if not meta.exists(): + return web.json_response({"error": "no meta"}, status=404) + return web.json_response(json.loads(meta.read_text(encoding='utf-8'))) + + async def _h_events(self, request): + p = self._safe(request.match_info['sid']) + if not p: + return web.json_response({"error": "not found"}, status=404) + ev = p / "events.jsonl" + if not ev.exists(): + return web.json_response({"events": []}) + out = [] + for line in ev.read_text(encoding='utf-8').splitlines(): + line = line.strip() + if not line: + continue + try: + out.append(json.loads(line)) + except Exception: + pass + return web.json_response({"events": out}) + + # ---- 媒体:直接 FileResponse(支持 Range,可拖动进度条)---- + + async def _h_video(self, request): + p = self._safe(request.match_info['sid']) + if not p: + return web.Response(status=404) + mp4 = p / "live_session.mp4" + if not mp4.exists(): + return web.Response(status=404, text="no live_session.mp4") + return web.FileResponse(mp4, headers={"Content-Type": "video/mp4"}) + + async def _h_audio_only(self, request): + p = self._safe(request.match_info['sid']) + if not p: + return web.Response(status=404) + m4a = p / "live_session.m4a" + if not m4a.exists(): + return web.Response(status=404, text="no live_session.m4a") + return web.FileResponse(m4a, headers={"Content-Type": "audio/mp4"}) + + async def _h_user_wav(self, request): + p = self._safe(request.match_info['sid']) + if not p: + return web.Response(status=404) + w = p / "live_user.wav" + if not w.exists(): + return web.Response(status=404) + return web.FileResponse(w, headers={"Content-Type": "audio/wav"}) + + async def _h_ai_wav(self, request): + p = self._safe(request.match_info['sid']) + if not p: + return web.Response(status=404) + w = p / "live_ai.wav" + if not w.exists(): + return web.Response(status=404) + return web.FileResponse(w, headers={"Content-Type": "audio/wav"}) + + async def _h_image_live(self, request): + return await self._serve_image(request, subdir="live_images") + + async def _h_image_legacy(self, request): + return await self._serve_image(request, subdir="images") + + async def _serve_image(self, request, subdir: str): + p = self._safe(request.match_info['sid']) + if not p: + return web.Response(status=404) + rel = request.match_info['path'] + # rel 形如 "live_images/img_00001.jpg" 或 "images/xxx.jpg" + # 这里只取末尾文件名,防穿越 + name = Path(rel).name + if "/" in name or ".." in name or not name: + return web.Response(status=400) + img = p / subdir / name + if not img.exists(): + return web.Response(status=404) + return web.FileResponse(img, headers={"Content-Type": "image/jpeg"}) + + +# ============================================================ +# Standalone entry +# ============================================================ + +def _main() -> None: + import argparse + import asyncio + + parser = argparse.ArgumentParser( + description="Bridge UI — standalone replay server (no ESP32 / no model)" + ) + parser.add_argument("--port", type=int, default=8080) + parser.add_argument("--host", default="0.0.0.0") + parser.add_argument("--sessions", default="./sessions", + help="sessions 根目录(默认 ./sessions)") + args = parser.parse_args() + + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", + ) + + sessions_root = Path(args.sessions).resolve() + if not sessions_root.exists(): + LOGGER.warning("[UI] sessions dir 不存在: %s(之后录到这里就能看见)", + sessions_root) + + server = WebUIServer( + port=args.port, + host=args.host, + sessions_root=sessions_root + ) + + async def _run(): + await server.start() + LOGGER.info("[UI] standalone mode — replay only") + LOGGER.info("[UI] sessions root: %s", sessions_root) + LOGGER.info("[UI] open http://localhost:%d/replay", args.port) + try: + while True: + await asyncio.sleep(3600) + except (KeyboardInterrupt, asyncio.CancelledError): + pass + finally: + await server.stop() + + try: + asyncio.run(_run()) + except KeyboardInterrupt: + print("\n[UI] bye.") + + +if __name__ == "__main__": + _main() \ No newline at end of file diff --git a/extensions/assistive_harness/phase_b/cam_pipeline_v2.py b/extensions/assistive_harness/phase_b/cam_pipeline_v2.py new file mode 100644 index 0000000..fdd2b8c --- /dev/null +++ b/extensions/assistive_harness/phase_b/cam_pipeline_v2.py @@ -0,0 +1,2283 @@ +# -*- coding: utf-8 -*- +"""cam_tuner.py — ESP32 相机调参台 (形态1: 纯调参, 不接模型) + +目的: 一边看 TCP live 画面, 一边热调分辨率/对焦/quality, 实时看每帧的 + 拉普拉斯清晰度分 + 亮度 —— 为三级漏斗一级标定阈值。 + +用法: + python cam_tuner.py --ip 10.100.7.68 + 浏览器开 http://localhost:8080 + +注意 (硬约束): + 固件 TCP 5000 是单客户端串行。本工具独占 TCP —— 调参时不要同时跑主程序 + (pc_vlm / demo_esp32), 否则抢同一条 TCP 连接会错位。 + +依赖: aiohttp, opencv-python(cv2), numpy, requests +""" + +from __future__ import annotations + +import argparse +import asyncio +import socket +import struct +import threading +import time +from pathlib import Path +from typing import Optional + +import cv2 +import numpy as np +import requests +from aiohttp import web + + +# ============================================================ +# TCP 5000 抓帧 (复用已验证协议; 单连接 + 锁, 后台线程持有) +# ============================================================ +class TCPImageClient: + def __init__(self, ip: str, port: int = 5000, timeout: float = 2.0): + self.ip, self.port, self.timeout = ip, port, timeout + self._sock = None + self._lock = threading.Lock() + + def _connect_locked(self) -> bool: + try: + self._sock = socket.create_connection((self.ip, self.port), timeout=self.timeout) + self._sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + self._sock.settimeout(self.timeout) + return True + except Exception: + self._sock = None + return False + + def _recv_exactly(self, n: int) -> Optional[bytes]: + buf = b"" + while len(buf) < n: + chunk = self._sock.recv(n - len(buf)) + if not chunk: + return None + buf += chunk + return buf + + def capture(self) -> Optional[bytes]: + with self._lock: + for attempt in (1, 2): + if self._sock is None and not self._connect_locked(): + return None + try: + self._sock.sendall(b"\x01") + hdr = self._recv_exactly(20) + if not hdr: + raise ConnectionError("no header") + magic = struct.unpack_from(" bool: + try: + r = self.sess.get(f"{self.base}/control", + params={"var": var, "val": val}, timeout=self.timeout) + return r.status_code == 200 + except Exception: + return False + + def set_resolution(self, name: str) -> bool: + v = FRAMESIZE.get(name.upper()) + return self.control("framesize", v) if v is not None else False + + def set_quality(self, q: int) -> bool: + return self.control("quality", max(0, min(63, int(q)))) + + def trigger_af(self) -> bool: + # 单次对焦: 直接写 OV5640 寄存器 0x3022=0x03 (single auto focus)。 + # 固件用标准 esp32-camera web server, 没有实现 /control?var=af (af 非标准变量), + # 之前先试 control("af") 会"假成功"(固件忽略)而不真对焦 —— 故直接走 /reg。 + # 固件端应设 g_auto_af=false, 关掉每秒定时硬对焦, 对焦完全由此按需触发。 + try: + r = self.sess.get(f"{self.base}/reg", + params={"reg": 0x3022, "mask": 0xff, "val": 0x03}, + timeout=self.timeout) + return r.status_code == 200 + except Exception: + return False + + +def rotate_jpeg(jpg: bytes, deg: int) -> bytes: + """后端真旋转 (顺时针 deg∈{0,90,180,270})。返回旋转后的 JPEG bytes。 + 真转而非只转显示: 因为最终自动旋转策略判断后会真喂给模型, 数据路径要一致; + 且清晰度分基于转后图算, 可验证'旋转不改变清晰度'(锐利度与朝向正交)。""" + d = deg % 360 + if d == 0: + return jpg + arr = np.frombuffer(jpg, dtype=np.uint8) + img = cv2.imdecode(arr, cv2.IMREAD_COLOR) + if img is None: + return jpg + if d == 90: + img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE) + elif d == 180: + img = cv2.rotate(img, cv2.ROTATE_180) + elif d == 270: + img = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE) + else: + return jpg + ok, enc = cv2.imencode(".jpg", img, [cv2.IMWRITE_JPEG_QUALITY, 90]) + return enc.tobytes() if ok else jpg + + +def _decode_gray(jpg: bytes): + arr = np.frombuffer(jpg, dtype=np.uint8) + return cv2.imdecode(arr, cv2.IMREAD_GRAYSCALE) + + +def frame_motion(jpg_a: bytes, jpg_b: bytes) -> float: + """两帧灰度平均绝对差 (0-255)。大 = 画面在动 (快速移动/转头)。 + **先高斯模糊再算差**: 抹掉密集文字的高频细节, 只保留宏观位移 —— + 否则密集文字面(成分面)手持轻微移动时每个小字边缘都产生大量像素差, motion 虚高, + 把可读的图误判成"在动"(真机+OCR校准证实成分面可读却被全拒)。 + 漏斗二级用: 一批帧相邻 diff 都大 -> 画面不稳 -> 拒绝(念字必错, 让用户停稳)。""" + a, b = _decode_gray(jpg_a), _decode_gray(jpg_b) + if a is None or b is None: + return 0.0 + if a.shape != b.shape: + b = cv2.resize(b, (a.shape[1], a.shape[0])) + a = cv2.GaussianBlur(a, (7, 7), 0) + b = cv2.GaussianBlur(b, (7, 7), 0) + return float(np.abs(a.astype(np.int16) - b.astype(np.int16)).mean()) + + +def optical_flow_motion(jpg_a: bytes, jpg_b: bytes, downscale: float = 0.35) -> float: + """两帧稠密光流(Farneback)的平均位移幅度(像素)。物理含义明确、可解释: + 画面整体移动了多少像素。用于【严重晃动一刀切】—— 相机大幅位移时光流幅度大。 + 比 frame_motion(逐像素差)更鲁棒: 光流看运动矢量场, 不被密集文字的高频细节干扰 + (密集字轻微移动 -> 光流一致小位移; 逐像素差却虚高)。降采样提速(判"严重"够用)。""" + a, b = _decode_gray(jpg_a), _decode_gray(jpg_b) + if a is None or b is None: + return 0.0 + if a.shape != b.shape: + b = cv2.resize(b, (a.shape[1], a.shape[0])) + if downscale != 1.0: + a = cv2.resize(a, None, fx=downscale, fy=downscale, interpolation=cv2.INTER_AREA) + b = cv2.resize(b, None, fx=downscale, fy=downscale, interpolation=cv2.INTER_AREA) + flow = cv2.calcOpticalFlowFarneback(a, b, None, + pyr_scale=0.5, levels=3, winsize=15, + iterations=3, poly_n=5, poly_sigma=1.2, flags=0) + mag = np.sqrt(flow[..., 0] ** 2 + flow[..., 1] ** 2) + # 位移幅度按降采样比例还原到原图尺度, 便于用原图像素单位设阈值 + return float(mag.mean() / max(downscale, 1e-6)) + + +def bg_signals(jpg_bytes): + """候选'背景干扰'信号(都可解释, 检测画面有额外背景 -> 提示拿近/对准)。 + 干净白纸标签: 大片均匀白 + 中间少量黑字; 有背景(灯管/工位/天花板)时信号异常。 + 也含清晰度类(local_sharp/worst_block/sharp_ratio)供评分。返回 dict。""" + arr = np.frombuffer(jpg_bytes, np.uint8) + g = cv2.imdecode(arr, cv2.IMREAD_GRAYSCALE) + if g is None: + return {} + h, w = g.shape + # 信号1: 亮度直方图熵 —— 干净标签(白底+黑字)分布集中熵低; 背景杂->熵高 + hist = cv2.calcHist([g], [0], None, [32], [0, 256]).flatten() + p = hist / (hist.sum() + 1e-9) + entropy = float(-np.sum(p * np.log2(p + 1e-12))) + # 信号2: 最大均匀(低方差)区占比 —— 白纸有大片均匀白; 占比低=画面杂乱 + blur = cv2.GaussianBlur(g, (5, 5), 0) + localvar = cv2.blur((g.astype(np.float32) - blur.astype(np.float32)) ** 2, (15, 15)) + lowvar = (localvar < 30).astype(np.uint8) + n, labels, stats, _ = cv2.connectedComponentsWithStats(lowvar) + max_uniform = float(stats[1:, cv2.CC_STAT_AREA].max() / g.size) if n > 1 else 0.0 + # 信号3: 边缘空间分布 —— 干净标签边缘集中中间(文字); 背景使边缘散布/落外围 + edges = cv2.Canny(g, 50, 150) + ys, xs = np.where(edges > 0) + if len(xs) > 10: + cx, cy = w / 2, h / 2 + d = np.sqrt(((xs - cx) / w) ** 2 + ((ys - cy) / h) ** 2) + edge_spread = float(d.mean()) + edge_periph = float((d > 0.35).mean()) # 边缘落外围(远离中心)比例 + else: + edge_spread = 0.0; edge_periph = 0.0 + # 信号4: local_sharp / worst_block —— 有高对比背景(灯管)时 local虚高而整体糊 + lap = cv2.Laplacian(g, cv2.CV_64F) + local_sharp = float(lap.var()) + grid = 6 + vals = [] + for i in range(grid): + for j in range(grid): + blk = g[i*h//grid:(i+1)*h//grid, j*w//grid:(j+1)*w//grid] + if blk.size == 0: + continue + e = cv2.Canny(blk, 50, 150) + if (e > 0).mean() < 0.006: + continue + vals.append(float(cv2.Laplacian(blk, cv2.CV_64F).var())) + worst = min(vals) if vals else 0.0 + sharp_ratio = float(local_sharp / (worst + 1e-6)) if worst > 0 else 0.0 + return { + "bright_entropy": round(entropy, 2), + "max_uniform": round(max_uniform, 3), + "edge_spread": round(edge_spread, 3), + "edge_periph": round(edge_periph, 3), + "sharp_ratio": round(sharp_ratio, 1), + "local_sharp": round(local_sharp, 1), + "worst_block": round(worst, 1), + } + + +# ============================================================ +# 三级漏斗 (形态2核心) +# 输入: 一批 N 帧 (bytes list) +# 一级 单帧质量筛: 太糊/太暗/空白 的帧标记不合格 +# 二级 稳定性判定: 相邻帧 motion 都过大 -> 整批拒绝 (画面不稳) +# 三级 选优: 合格帧里选 sharpness 最高的 = best +# 全不合格 / 不稳 -> 返回拒绝 (安全闸, 不喂模型) +# +# 阈值说明: 分辨率固定 HD 后针对 HD 标定。这里给的是初始默认值, +# 你戴眼镜实测后按 CSV 数据调 (尤其 SHARP_MIN / MOTION_MAX)。 +# sharp 低 + edge 低 = 空白(拒绝, 说"没看到文字"); 用 EDGE_MIN 兜。 +# ============================================================ +import math + + +def _g_sat(x: float, x0: float) -> float: + """Michaelis-Menten 饱和: x/(x+x0) -> [0,1)。x0=半饱和点。""" + x = max(0.0, x) + return x / (x + x0) if (x + x0) > 0 else 0.0 + + +def _g_light(b: float, lo: float, hi: float, soft: float) -> float: + """亮度响应: 太暗/过曝降分, 中间平台=1。两 sigmoid 相夹。""" + def sig(z): + try: + return 1.0 / (1.0 + math.exp(-z)) + except OverflowError: + return 0.0 if z < 0 else 1.0 + return sig((b - lo) / soft) * (1 - sig((b - hi) / soft)) + + +def frame_score(metrics: dict, rel_change: float, cfg: "FunnelConfig") -> dict: + """对一帧算 quality + focus_gain + 各分量 (供解释/记录)。 + rel_change: 该帧相对上一帧的 sharp 相对变化 (稳定性输入); 首帧传 0。""" + # 清晰度用 worst_block(最糊的有内容块) 而非全局 sharpness —— + # 全局拉普拉斯被大面积白底稀释(白底无边缘, 拉普拉斯低), 把"清晰的白盒子标签"误判成糊, + # 触发假的 need_focus。worst_block 只看有内容的最糊块, 不被白底拉低。 + # 真机+OCR校准: 不可读帧 worst_block<4.6, 可读>5.5 -> 分界~5, 故 x0 用 worst_x0(~5量级)。 + worst = metrics.get("worst_block", None) + if worst is None: + worst = metrics.get("sharpness", 0.0) # 兜底: 无 worst_block 时退回全局 + g_sharp = _g_sat(worst, cfg.worst_x0) + g_stable = max(0.0, 1.0 - min(1.0, rel_change)) # rel_change 已归一化到[0,1] + g_content = _g_sat(metrics.get("edge_density", 0.0), cfg.edge_x0) + g_light = _g_light(metrics.get("brightness", 0.0), cfg.light_lo, cfg.light_hi, cfg.light_soft) + + wsum = cfg.w_sharp + cfg.w_stable + cfg.w_content + cfg.w_light + base = (cfg.w_sharp * g_sharp + cfg.w_stable * g_stable + + cfg.w_content * g_content + cfg.w_light * g_light) / wsum + sharp_gate = g_sharp ** cfg.sharp_gate_gamma # 念字硬要求: 糊则压分 + quality = base * sharp_gate + # focus_gain: 稳 + 糊 时该对焦。对 content 用"温和依赖"(sqrt)而非硬乘 —— + # 重度失焦会把边缘也糊没(g_content 低), 但它恰恰最该对焦, 不能因此归零; + # sqrt 让低内容时 focus_gain 降低但保留触发机会。真空白由 g_content 极低 + + # g_stable 高的组合另行识别(见 run_funnel 拒绝归因)。 + focus_gain = g_stable * (1 - g_sharp) * math.sqrt(max(0.0, g_content)) + return { + "quality": round(quality, 3), + "focus_gain": round(focus_gain, 3), + "g_sharp": round(g_sharp, 3), + "g_stable": round(g_stable, 3), + "g_content": round(g_content, 3), + "g_light": round(g_light, 3), + } + + +class FunnelConfig: + """评分函数 f 的参数 (替代硬阈值 if)。每帧算一个连续 quality 分 + focus_gain, + 决策基于分数而非离散阈值 —— 可解释、可 ablation、可用数据校准。 + + quality = [Σ wi·gi] · g_sharp^gamma (sharp 作乘性门, 念字硬要求) + g_sharp = sharp/(sharp+sharp_x0) 清晰度饱和响应 + g_stable = 1 - min(1, rel_change/change_ref) 帧间相对变化越小越稳 + g_content = edge/(edge+edge_x0) 有无内容(区分糊/空) + g_light = 亮度双sigmoid(暗/过曝都降) + focus_gain = g_stable·(1-g_sharp)·g_content 稳+糊+有内容 -> 该对焦 + 决策: max(quality) >= ACCEPT_Q -> 选该帧; 否则看 max(focus_gain) >= FOCUS_G + -> 触发对焦再采; 都低 -> 拒绝。 + 参数是物理动机初值, 戴眼镜采数据后可校准/拟合 (方法 vs 调参的区别)。 + """ + # g 响应形状 (半饱和点/参考值) + sharp_x0 = 120.0 # (记录用) 全局清晰度半饱和点; g_sharp 现改用 worst_block + worst_x0 = 6.5 # worst_block 半饱和点。调严(原5.0)要求更清晰。真机+OCR: 不可读<4.6/可读>5.5。 + # g_sharp = worst/(worst+worst_x0): worst=5时g_sharp=0.5, 白盒清晰标签 + # worst 正常(不被白底稀释)故不误判need_focus。阈值待白标签标准数据精校。 + change_ref = 0.5 # (旧, 已弃用: 稳定性改用帧间像素差) + motion_ref = 15.0 # 帧间模糊后平均像素差达此视为"完全在动"。校准依据: OCR证实可读的 + # 成分面(密集字)模糊后 motion 达~8.4 仍可读, 须能过; 故 ref 上调到15, + # 使可读帧 stable>=0.44 通过, 同时剧烈晃动(>15)仍被拒。下界待补采晃动样本精校。 + edge_x0 = 0.01 # 边缘密度半饱和 (区分有内容/空白) + light_lo = 40.0 # 亮度下沿 + light_hi = 220.0 # 亮度上沿(过曝) + light_soft = 25.0 # 亮度软边宽度 + # 权重 (语义清晰, 可做 ablation) + w_sharp = 1.0 + w_stable = 1.0 + w_content = 0.6 + w_light = 0.4 + sharp_gate_gamma = 0.5 # sharp 乘性门强度 (0=不否决, 大=糊帧强烈压分) + # 决策阈值 (作用在归一化综合分上, 只此两个, 远少于原来一堆硬阈值) + ACCEPT_Q = 0.55 # 可用性门: 调严(原0.40太松, 放过模糊图)。0.55 要求更清晰才放行。 + # 宁拒绝不念错: 送下游的必须够清晰, 模糊的宁可让用户重拍。 + # 放宽的理由(数据得出): 全局quality分不开'能OCR'与'轻微糊', + # 那是任务层的精判(局部/文字区清晰度), 通用层不越俎代庖。 + FOCUS_G = 0.35 # (保留) focus_gain 参考 + # 稳定性优先三出口的门限 (段级中位数上判定; 待真机 rerun 校准) + STABLE_MIN = 0.35 # 出口A: g_stable 低于此 = 持续在动 -> "请拿稳" (第一闸)。 + # 从0.45降到0.35: 配合 motion_ref=15, 让OCR证实可读的密集字面通过, 修复误拒。 + SEVERE_FLOW = 8.0 # 出口A0: 段级光流位移(像素)>=此 = 严重晃动一刀切拒绝。初值8, + # 待 shake 样本校准("多大位移算严重"); 光流位移物理可解释。 + LIGHT_MIN = 0.35 # 出口D(留): g_light 低于此且为最差 -> 太暗 + CONTENT_MIN = 0.30 # 出口E(留): g_content 低于此 + SHARP_OK_FOR_E = 0.45 # 出口E(留): 判"没对准"要求 sharp 够高(清晰却没字才算对错) + MIN_QUALIFIED = 1 + + +# ============================================================ +# 场景配置 (核心: 机制一套, 参数按场景标定 —— "权重由场景物理特征+安全等级决定") +# 药盒(medicine): 小字/高危/白底 -> 偏拒绝、要求清晰、零容忍。= 默认 FunnelConfig。 +# 文具(stationery): 中大字/低危/彩色包装 -> 可放松、允许更多放行。 +# 固有机制(对焦/多帧筛选/倒置/光流晃动)完全一致, 只有下面这些判定参数不同。 +# ============================================================ +def make_scene_config(scene: str = "medicine") -> "FunnelConfig": + """按场景返回标定好的 FunnelConfig。机制代码不变, 只改参数。""" + cfg = FunnelConfig() + if scene in ("medicine", "药盒", "drug"): + return cfg # 药盒 = 现有默认(小字/高危/严) + if scene in ("stationery", "文具", "supplies", "生活用品"): + # 生活用品/文具: 安全等级低(念错关系不大) -> 放行阈值放松, 少拒绝、少打扰。 + # 参数依据: 网络摄像头 clip_windows csv (routing 分析) + 安全等级。 + cfg.worst_x0 = 5.0 # 松(药盒6.5): 拦截判据, 药盒严文具松(安全等级低)。 + # 手动定: csv里 worst_block 对ok/blur区分很弱(图都较清晰, + # AUC~0.52), 算不出可靠值, 按"文具比药盒松"手动定松一档。 + cfg.ACCEPT_Q = 0.48 # 略放松(药盒0.55): 安全低, 容错高一点。 + cfg.SEVERE_FLOW = 8.0 # 沿用药盒: csv 里 seg_flow 是最强判据(AUC~0.71), >8 后 + # ok率骤降, 与药盒一致。晃动是通用物理约束, 不随场景放松。 + return cfg + # 未知场景 -> 退回药盒默认, 并提示 + print(f"[scene] 未知场景 '{scene}', 用药盒默认配置") + return cfg + + +class FunnelResult: + def __init__(self): + self.accepted = False + self.need_focus = False # 稳但糊: 上层应触发AF再采一批 + self.reject_reason = "" + self.best_index = -1 + self.best_jpg = None + self.per_frame = [] + self.motions = [] # 这里存 rel_change 序列 + self.components = {} # 段级各 gi 分量 (归因用) + self.timings = {} + + def to_dict(self): + def _fmt(v): + if isinstance(v, (int, float)): + return round(v, 1) + return v # list 之类原样 (如 grab_per_frame_ms) + return { + "accepted": self.accepted, + "need_focus": self.need_focus, + "reject_reason": self.reject_reason, + "best_index": self.best_index, + "per_frame": self.per_frame, + "rel_changes": [round(m, 3) for m in self.motions], + "components": self.components, + "timings": {k: _fmt(v) for k, v in self.timings.items()}, + } + + +def run_funnel(frames: list[bytes], cfg: FunnelConfig = FunnelConfig()) -> FunnelResult: + """评分函数版漏斗: + 1) 每帧算 metrics(sharp/亮度/edge) + 2) 帧间相对变化 -> 每帧 quality + focus_gain (连续分, 非硬阈值) + 3) 决策: max(quality)>=ACCEPT_Q -> 选该帧(选优); + 否则 max(focus_gain)>=FOCUS_G -> 建议对焦(need_focus); + 都低 -> 拒绝。 + 返回里带 need_focus 标志, 供上层决定"稳但糊->触发AF->再采"。""" + r = FunnelResult() + if not frames: + r.reject_reason = "no_frames" + return r + + # 1) 单帧 metrics + t0 = time.monotonic() + metrics_list = [frame_metrics(j) for j in frames] + r.timings["level1_metrics_ms"] = (time.monotonic() - t0) * 1000 + + # 2) 帧间"运动"(稳定性输入) + 每帧评分 + # 稳定性用真正的帧间像素差分(frame_motion)衡量 —— 位移/转动会改变画面内容, + # 但不一定改变清晰度, 故不能用 sharp 变化代替。归一化到 [0,1] 的 rel。 + t1 = time.monotonic() + per = [] + prev_jpg = None + flow_mags = [] # 相邻帧光流位移幅度(严重晃动一刀切用) + for i, m in enumerate(metrics_list): + if prev_jpg is None: + motion = 0.0 + else: + motion = frame_motion(prev_jpg, frames[i]) # 平均绝对像素差 0-255 + flow_mags.append(optical_flow_motion(prev_jpg, frames[i])) # 光流位移(像素) + prev_jpg = frames[i] + rel = min(1.0, motion / cfg.motion_ref) # 归一: motion>=motion_ref 视为完全在动 + sc = frame_score(m, rel, cfg) + per.append({**m, "rel_change": round(rel, 3), "motion": round(motion, 2), **sc}) + r.motions.append(rel) + r.per_frame = per + # 段级光流: 用中位数抗单帧噪声。大 = 整段相机在大幅移动 = 严重晃动。 + seg_flow = float(sorted(flow_mags)[len(flow_mags) // 2]) if flow_mags else 0.0 + r.timings["level2_score_ms"] = (time.monotonic() - t1) * 1000 + + # 3) 决策: 稳定性优先的三出口 (A/B/C), argmin(gi) 归因, D/E 留接口 + t2 = time.monotonic() + qualities = [p["quality"] for p in per] + # 段级聚合各分量 (用中位数抗单帧噪声) + def med(key): + vals = sorted(p[key] for p in per) + n = len(vals) + return vals[n // 2] if n % 2 else (vals[n // 2 - 1] + vals[n // 2]) / 2 + seg_stable = med("g_stable") + seg_sharp = med("g_sharp") + seg_content = med("g_content") + seg_light = med("g_light") + # best 帧选择: 只按【清晰度】选最能读的一帧, 不用综合 quality。 + # 原因: quality 含 stable 分量, 会让"晃动某瞬间恰好帧间motion低(转折点)但画面糊"的帧 + # quality 虚高, 压过"稍动但清晰可读"的帧 -> best 选成糊的(真机验证: f0糊被选/f2清晰没选)。 + # 念字能不能读只取决于清晰度, 与该帧瞬时稳不稳无关; 稳定性只用于整段是否拒绝(出口A)。 + # 用 worst_block(最糊有内容块)选: 选"最糊处也最清晰"的那帧 = 最可读。 + def _clarity(i): + return per[i].get("worst_block", per[i].get("sharpness", 0.0)) + best_q = max(range(len(per)), key=_clarity) + # quality 仍保留供出口B的接受阈值判断(下面 qualities[best_q]>=ACCEPT_Q) + r.timings["level3_decide_ms"] = (time.monotonic() - t2) * 1000 + + # 归因分量表 (供 argmin 路由 + 记录) + r.components = {"stable": round(seg_stable, 3), "sharp": round(seg_sharp, 3), + "content": round(seg_content, 3), "light": round(seg_light, 3), + "flow": round(seg_flow, 2)} # 段级光流位移(像素) + + # ---- 出口 A0: 严重晃动一刀切 —— 光流位移过大 = 相机大幅移动, 不看别的直接拒 ---- + # 可解释: 画面整段平均移动 >SEVERE_FLOW 像素 = 明显在晃, 念字必糊, 让用户停稳。 + # 光流比逐像素差鲁棒(不被密集字伪运动骗); 阈值待 shake 样本校准。 + if seg_flow >= cfg.SEVERE_FLOW: + r.reject_reason = "severe_shake" # 出口 A0: "晃得厉害, 请拿稳" + r.need_focus = False + r.best_index = best_q + return r + + # ---- 出口 A: 稳定性优先 —— 持续在动, 不看清晰度, 直接请拿稳 ---- + # (动的时候对焦也没用, 且用户没老实, 不该浪费时间去挑图) + if seg_stable < cfg.STABLE_MIN: + r.reject_reason = "unstable" # 出口 A: "请拿稳/对准" + r.need_focus = False + r.best_index = best_q # 仅供参考, 不喂模型 + return r + + # ---- 稳定。看有没有帧够清晰 ---- + if qualities[best_q] >= cfg.ACCEPT_Q: + # ---- 出口 B: 稳 + 有清晰帧 -> 给最清晰的 ---- + r.accepted = True + r.best_index = best_q + r.best_jpg = frames[best_q] + r.need_focus = False + return r + + # ---- 稳但没有够清晰的帧: 归因 argmin, 决定是 C(对焦) 还是 D/E ---- + # 在"稳定"前提下, 看哪个分量最拖累: sharp低=失焦(C); light低=暗(D); + # content低但sharp高=清晰却没内容=没对准(E)。argmin 连续路由, 非硬堆阈值。 + cand = {"sharp": seg_sharp, "light": seg_light, "content": seg_content} + worst = min(cand, key=cand.get) + + if worst == "light" and seg_light < cfg.LIGHT_MIN: + # 出口 D (留接口, 未激活干预): 太暗 -> 未来 CLAHE 数字增强 / 提示到亮处 + r.reject_reason = "too_dark" # TODO: 接 CLAHE 后改为可救 + r.need_focus = False + r.best_index = best_q + return r + + # 出口 E(aimed_wrong)已弃用:原设计(-v/OCR)用"清晰但无内容结构"判"没对准", + # 目的是排除背景干扰。但 -o 不受背景影响、完全没字时会老实说"没看到字", + # 不需要漏斗拦。故这种帧直接放行,交给模型自己判断,避免误判打断。 + # (真正危险的"像字又不是字"是另一个问题,待 720p 数据用别的信号重做。) + if worst == "content" and seg_sharp >= cfg.SHARP_OK_FOR_E and seg_content < cfg.CONTENT_MIN: + r.accepted = True + r.best_index = best_q + r.best_jpg = frames[best_q] + r.need_focus = False + return r + + # ---- 出口 C: 稳但糊 (sharp 主导拖累) -> 触发AF重采 ---- + r.accepted = False + r.need_focus = True + r.reject_reason = "need_focus" # 上层触发AF+重采, 仍不行才最终拒绝 + r.best_index = best_q + return r + + +# ============================================================ +# 方向处理 & 推理 —— 留桩, 下一步填 +# ============================================================ +def _center_crop(gray, frac=0.6): + """取画面中心区, 排掉四周背景(手/桌面/墙)。用户会把目标大致对准中心, + 故中心区更可能是文字主体; 在其上算判据可显著减轻背景污染。""" + h, w = gray.shape[:2] + y0, y1 = int(h * (1 - frac) / 2), int(h * (1 + frac) / 2) + x0, x1 = int(w * (1 - frac) / 2), int(w * (1 + frac) / 2) + return gray[y0:y1, x0:x1] + + +def _binv_fg(gray): + _, b = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) + return (b > 0).astype(np.float64) + + +def _detect_sideways(gray): + """90°/270°侧向: 水平投影方差 vs 垂直投影方差。多档中心区(0.5/0.6/0.7)投票, + 比单一比例更稳(文字不在正中心时不易被单档背景污染带偏)。 + 返回 (verdict, ratio): 'upright'/'sideways'/'ambiguous'。ratio 取中位数。""" + ratios = [] + for frac in (0.5, 0.6, 0.7): + b = _binv_fg(_center_crop(gray, frac)) + hvar = float(np.var(b.sum(axis=1))) + vvar = float(np.var(b.sum(axis=0))) + ratios.append(hvar / (vvar + 1e-6)) + ratios.sort() + med = ratios[1] # 中位数, 抗单档异常 + votes = ["sideways" if r < 0.67 else ("upright" if r > 1.5 else "ambiguous") + for r in ratios] + # 多数票: 3档里≥2档一致才定, 否则 ambiguous + for v in ("sideways", "upright"): + if votes.count(v) >= 2: + return v, round(med, 2) + return "ambiguous", round(med, 2) + + +def _detect_upside_down(gray): + """180°正倒: '注水容量'判据(资料方法, 真图验证对中文有效)。 + 对每列: 最高文字点上方空白(top_cap) vs 最低文字点下方空白(bot_cap)。 + 正立版面文字整体下方留白多 -> (bot-top)>0; 倒置翻转 -> <0。 + **看版面级上下留白, 不依赖单字对称性, 绕开中文字对称死结。** + 真图验证: 正立+0.66/倒置-0.48, 抗±8°倾斜、抗裁剪比例(0.5~0.9)。必须裁剪(整图会被背景淹)。 + 返回 (verdict, score): 'upright'/'flipped'/'ambiguous'。""" + b = _binv_fg(_center_crop(gray, 0.7)) + h, w = b.shape + tc = bc = cnt = 0 + for x in range(0, w, 3): + col = np.where(b[:, x] > 0)[0] + if len(col) < 2: + continue + tc += col[0] + bc += (h - 1 - col[-1]) + cnt += 1 + if cnt < 10: + return "ambiguous", 0.0 + score = (bc - tc) / (bc + tc + 1e-9) + if score > 0.15: + return "upright", round(score, 3) + if score < -0.15: + return "flipped", round(score, 3) + return "ambiguous", round(score, 3) + + +def _detect_truncation(gray, margin=10): + # 先确认中心区有文字主体; 否则不判截断(避免背景边缘误报) + cb = _binv_fg(_center_crop(gray, 0.6)) + if cb.mean() < 0.01: + return {}, {} # 中心没内容, 不谈截断 + b = _binv_fg(gray) + edges = {"top": b[:margin, :].mean(), "bottom": b[-margin:, :].mean(), + "left": b[:, :margin].mean(), "right": b[:, -margin:].mean()} + overall = b.mean() + if overall < 1e-4: + return {}, {} + # 贴边判据收紧: 边缘密度需 >= 整图的一定比例, 且 >= 中心密度的一定比例 + # (排掉"背景纹理贴边但中心才是文字"的误报) + center_d = cb.mean() + touched = {k: (v >= overall * 0.6 and v >= center_d * 0.4 and v > 0.02) + for k, v in edges.items()} + return {k: round(v, 4) for k, v in edges.items()}, {k: t for k, t in touched.items() if t} + + +_PAN_HINT = {"top": "请向上看一点", "bottom": "请向下看一点", + "left": "请向左看一点", "right": "请向右看一点"} + + +_ORI_CLS = None # 方向分类器单例(全局只加载一次) +_ORI_CLS_TRIED = False # 是否已尝试加载(避免反复重试失败) + +def _get_orient_classifier(): + """懒加载 PaddleOCR 文档方向分类器(PP-LCNet, 6.75MB, 0/90/180/270)。 + 单例: 只在首次调用时加载一次(几秒), 之后每次推理仅几ms。 + 降级: 未安装/加载失败 -> 返回 None, process_orientation 回退到轻量CV判据, 不崩。""" + global _ORI_CLS, _ORI_CLS_TRIED + if _ORI_CLS is not None: + return _ORI_CLS + if _ORI_CLS_TRIED: + return None # 之前试过且失败, 不再重试 + _ORI_CLS_TRIED = True + # 加载方向分类器。优先用最简单的写法(实测 SmartGlasses 环境可用, 与 torch 不冲突 —— + # 当初冲突的是完整 PaddleOCR-GPU 识别, 不是这个轻量方向分类器)。 + # 若想显式指定设备, 后面的参数变体作为备选依次尝试。 + from paddleocr import DocImgOrientationClassification + last_err = None + for kw in (dict(model_name="PP-LCNet_x1_0_doc_ori"), # 最简单(原来能用的) + dict(model_name="PP-LCNet_x1_0_doc_ori", device="cpu"), # 显式CPU(可选) + dict()): # 全默认兜底 + try: + _ORI_CLS = DocImgOrientationClassification(**kw) + print(f"[orient] PaddleOCR 方向分类器已加载 (PP-LCNet, 参数={list(kw) or 'default'})") + return _ORI_CLS + except Exception as e: + last_err = e + continue # 这个参数组合不行, 换下一个 + print(f"[orient] 方向分类器加载失败, 回退到轻量CV判据: {last_err}") + _ORI_CLS = None + return None + + +# 文档方向标签(图像被顺时针旋转的角度) -> (状态, 给用户的转向提示) +# 注意: "图像旋转角"与"用户转药盒方向"相反。文案先按标准定义, 实机核对后固定。 +# 90°: 画面顺时针转了90° = 药盒被逆时针放了 -> 用户应顺时针转回? 需实机核对, 故保留 raw 标签调试。 +_ORIENT_MAP = { + "0": ("upright", None), + "90": ("sideways", "请把药盒顺时针转90°"), + "270": ("sideways", "请把药盒逆时针转90°"), + "180": ("flipped", "药盒拿反了,请上下翻转"), +} + + +def _classify_orientation(img_bgr): + """用分类器判方向。返回 (raw_label, conf) 或 (None, 0) 若不可用/低置信。""" + cls = _get_orient_classifier() + if cls is None: + return None, 0.0 + try: + res = cls.predict(img_bgr) # 传 ndarray, 免落盘 + r = res[0] + labels = r.get("label_names") or [str(x) for x in r.get("class_ids", [])] + scores = r.get("scores", [0.0]) + raw = str(labels[0]).replace("_degree", "").strip() + conf = float(max(scores)) if scores else 0.0 + return raw, conf + except Exception as e: + print(f"[orient] 推理失败: {e}") + return None, 0.0 + + +def process_orientation(best_jpg: bytes): + """第2级(方向) + 第3级(取景完整) —— 只对清晰的 best 帧做一次。 + 方向: 优先用 PaddleOCR 轻量方向分类器(PP-LCNet, 真图验证0/90/180/270全准, 置信~0.92); + 未装/低置信 -> 回退轻量CV判据。180°走多帧一致性('请确认正反'在handler触发)。 + 返回 (jpg, diag)。diag 含方向反馈 + 截断反馈 + incomplete 标志(传下游prompt)。 + [留桩] 圆柱曲面矫正 = 独立课题, 不在此处。""" + arr = np.frombuffer(best_jpg, np.uint8) + img = cv2.imdecode(arr, cv2.IMREAD_COLOR) + if img is None: + return best_jpg, {"ok": False} + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + + orient_hint = None + orient_state = "upright" + ud_score = 0.0 + side_ratio = "" + orient_raw = "" + orient_conf = 0.0 + CONF_MIN = 0.60 # 置信门控: 低于此不硬判, 走uncertain/兜底 + + raw, conf = _classify_orientation(img) + orient_raw, orient_conf = (raw or ""), conf + if raw is not None and conf >= CONF_MIN and raw in _ORIENT_MAP: + # 分类器可用且置信足够 -> 直接按映射给状态+提示 + # (实测180 conf~0.93很确定, 不会与0混淆, 故即时提示; 若需滤噪声在簇内多帧投票层做) + orient_state, orient_hint = _ORIENT_MAP[raw] + elif raw is not None: + # 分类器给了结果但低置信 -> 不硬判 + orient_state = "uncertain" + else: + # 分类器不可用 -> 回退轻量CV判据(整块投影/注水容量) + side, side_ratio = _detect_sideways(gray) + if side == "sideways": + orient_state, orient_hint = "sideways", "请把药盒转90°" + else: + ud, ud_score = _detect_upside_down(gray) + orient_state = {"flipped": "flipped", "upright": "upright"}.get(ud, "uncertain") + + # 取景完整性(截断) —— 显示层暂关, 接口保留 + edges, truncated = _detect_truncation(gray) + pan_hint = None + if truncated: + worst = max(truncated, key=lambda k: edges.get(k, 0)) + pan_hint = _PAN_HINT.get(worst) + + diag = { + "ok": True, + "orient_state": orient_state, # upright/sideways/flipped/uncertain + "orient_hint": orient_hint, # 侧向即时提示; 180的"请确认"由多帧一致性在handler加 + "orient_raw": orient_raw, # 分类器原始标签(0/90/180/270), 实机核对转向用 + "orient_conf": round(orient_conf, 3), + "sideways_ratio": side_ratio, + "flipped_frame": orient_state == "flipped", # 供多帧一致性累积 + "ud_score": ud_score, + "truncated_edges": list(truncated.keys()), + "pan_hint": pan_hint, + "incomplete": bool(truncated), # 传下游prompt: 只念可见部分 + } + return best_jpg, diag # 第一版不自动转正, 只诊断+提示(方向由用户调) + + +def infer(frame_jpg: bytes) -> Optional[str]: + """[留桩] 未来: 把 best 帧喂给 -v (或 Qwen-VL) 做念字/识别。 + 现在返回 None。接推理时把这里换成真的模型调用。""" + return None + + +# ============================================================ +# CV 指标: 拉普拉斯方差(清晰度) + 平均亮度 +# 这两个就是三级漏斗一级的判据; 在这里实时显示以标定阈值。 +# ============================================================ +def frame_metrics(jpg: bytes) -> dict: + """返回一帧的 CV 指标字典。记录器会动态把所有 key 当作 CSV 列 —— + 以后 CV 那步加新指标(如帧间差分测晃动、方向检测分), 只需在这里往 + dict 里加 key, CSV 自动多列, 记录代码不用改。""" + arr = np.frombuffer(jpg, dtype=np.uint8) + img = cv2.imdecode(arr, cv2.IMREAD_GRAYSCALE) + if img is None: + return {"sharpness": 0.0, "brightness": 0.0, "kb": round(len(jpg) / 1024, 1)} + lap_var = cv2.Laplacian(img, cv2.CV_64F).var() + edges = cv2.Canny(img, 80, 160) + edge_density = float((edges > 0).mean()) + + # --- 附加指标: 先记录不判定, 采数据后用 ok/blur 标注看哪个最能对齐可读性 --- + # local_sharp: N×N 分块取最清晰块。抓"局部有清晰区"; 但会被高频背景(木纹)骗高。 + ls = _local_sharp(img, grid=4) + # text_sharp / text_ratio: MSER 类文字候选区的清晰度 + 面积占比。 + # text_ratio 说"有没有像字的区域"(高频背景 ratio≈0, 骗不过它); + # 但糊到一定程度 MSER 找不到字 -> ratio→0 (自我矛盾, 已离线证实)。 + # 与 local_sharp 组合: local高+ratio低=清晰但非字; 两者皆低=糊。 + ts, tr = _text_sharp(img) + # worst_block / block_var: 匹配"一处糊即不可用(OCR 标准)"的悲观判据。 + # worst_block = 有内容的块里最糊的清晰度 (看最差, 非最好); + # block_std = 块间清晰度标准差 (大 = 部分清晰部分糊 = 局部糊)。 + # 对 OCR: 决定成败的是最糊的文字区, 不是最清晰的 —— 故看 worst 而非 best。 + wb, bstd = _block_sharp_stats(img, grid=4) + # contrast / dark_ratio: 区分"糊"与"暗/低对比"。暗+低对比时全局sharp假性偏低, + # 但 contrast 低会揭示真因 -> 对应"数字增强(CLAHE)"而非"对焦"这条干预路径。 + contrast = float(img.std()) + dark_ratio = float((img < 50).mean()) + + # [CLAHE 接口预留] 未来暗环境念字: 若 contrast 低 / dark_ratio 高, 可在此对 img + # 做 CLAHE/gamma 增强后重算指标, 作为"数字层干预"(区别于对焦的"物理层干预")。 + # 现在不实现 —— 待有暗环境测试条件再填。示意: + # if contrast < TH: img_enh = cv2.createCLAHE(...).apply(img); 重算 lap_var ... + + return { + "sharpness": round(float(lap_var), 1), # 全局拉普拉斯方差 + "brightness": round(float(img.mean()), 1), + "edge_density": round(edge_density, 4), + "local_sharp": round(float(ls), 1), # 最清晰块 (乐观, 记录) + "worst_block": round(float(wb), 1), # 最糊的有内容块 (悲观, 匹配OCR标准) + "block_std": round(float(bstd), 1), # 块间清晰度std (大=局部糊) + "text_sharp": round(float(ts), 1), # 文字区清晰度 (记录) + "text_ratio": round(float(tr), 4), # 文字区面积占比 (记录) + "contrast": round(contrast, 1), # 对比度(std) (记录) + "dark_ratio": round(dark_ratio, 4), # 暗像素占比 (记录) + "kb": round(len(jpg) / 1024, 1), + } + + +def _block_sharp_stats(gray, grid: int = 4): + """分块清晰度的 (最糊有内容块, 块间std)。 + 只统计"有内容"的块(edge 非极低), 避免纯背景块干扰; + worst = 有内容块里最低清晰度 (对应'一处糊即失败'); + std = 块间清晰度离散度 (局部糊 -> 大)。""" + h, w = gray.shape[:2] + vals = [] + for i in range(grid): + for j in range(grid): + blk = gray[i * h // grid:(i + 1) * h // grid, j * w // grid:(j + 1) * w // grid] + if blk.size == 0: + continue + # 只算"有文字/边缘结构"的块。关键: 用【边缘密度】而非 std 判有内容 —— + # std 只反映明暗起伏, 白纸的折痕/阴影/渐变 std 也 >8, 会被误当"内容块", + # 而白纸拉普拉斯极低(~1) -> 把 worst_block 拉到假性极低 -> 清晰标签被误判糊。 + # 文字块有大量边缘, 白纸光影块几乎无边缘 -> 用 Canny 边缘占比区分。 + edges = cv2.Canny(blk, 50, 150) + edge_frac = float((edges > 0).mean()) + if edge_frac < 0.006: # 边缘太少 = 无文字结构(白纸/背景) -> 跳过 + continue + vals.append(float(cv2.Laplacian(blk, cv2.CV_64F).var())) + if not vals: + return 0.0, 0.0 + worst = min(vals) + std = float(np.std(vals)) if len(vals) > 1 else 0.0 + return worst, std + + +def _local_sharp(gray, grid: int = 4) -> float: + """N×N 分块, 取最清晰块的拉普拉斯方差。""" + h, w = gray.shape[:2] + best = 0.0 + for i in range(grid): + for j in range(grid): + blk = gray[i * h // grid:(i + 1) * h // grid, j * w // grid:(j + 1) * w // grid] + if blk.size: + best = max(best, float(cv2.Laplacian(blk, cv2.CV_64F).var())) + return best + + +def _text_sharp(gray): + """MSER 找类文字候选区, 在候选区上算清晰度。返回 (清晰度, 面积占比)。 + 找不到 -> (0,0)。占比=0 提示'没找到字'(可能糊/无字), 与 local_sharp 组合判读。""" + try: + mser = cv2.MSER_create(delta=5, min_area=60, max_area=14400) + regions, _ = mser.detectRegions(gray) + except Exception: + return 0.0, 0.0 + if not regions: + return 0.0, 0.0 + mask = np.zeros(gray.shape[:2], np.uint8) + for pts in regions: + x, y, bw, bh = cv2.boundingRect(pts.reshape(-1, 1, 2)) + ar = bw / max(bh, 1) + if 0.1 < ar < 10 and bw < gray.shape[1] * 0.9: + cv2.fillPoly(mask, [cv2.convexHull(pts.reshape(-1, 1, 2))], 255) + area_ratio = float((mask > 0).mean()) + if area_ratio < 0.001: + return 0.0, area_ratio + lap = cv2.Laplacian(gray, cv2.CV_64F) + return float(lap[mask > 0].var()), area_ratio + + +# ============================================================ +# 后台抓帧线程: 独占 TCP, 持续抓最新帧 (供 /frame 取用) +# 前端按自己的刷新率来取, 后端只维护"最新一帧+指标"。 +# ============================================================ +class Recorder: + """记录一段一段的指标序列。每段带一个 label(触发来源, 如 af / res:UXGA / manual), + 每帧一行, 动态列(跟随 frame_metrics 的 key)。存磁盘 + 供前端下载。 + + 两种触发: (a) 点控制按钮自动录 duration 秒; (b) 手动开始/停止。 + 记录挂在后端抓帧线程上(每抓一帧记一行), 与前端显示刷新率解耦, 密度=真实抓帧率。""" + + def __init__(self, out_dir: Path): + self.out_dir = Path(out_dir) + self.out_dir.mkdir(parents=True, exist_ok=True) + self._lock = threading.Lock() + self._rows: list[dict] = [] # 所有已记录的行 (跨段, 全量) + self._active = False + self._seg_label = "" + self._seg_start_mono = 0.0 + self._seg_deadline = 0.0 # >0 表示定时录; 0 表示手动录(无限直到 stop) + self._seg_index = 0 + self._columns: list[str] = [] # 动态列, 首次记录时按 metrics key 确定 + + def start_segment(self, label: str, duration_s: float = 0.0): + """duration_s>0: 定时录; =0: 手动录(直到 stop_segment)。""" + with self._lock: + self._active = True + self._seg_index += 1 + self._seg_label = label + self._seg_start_mono = time.monotonic() + self._seg_deadline = (self._seg_start_mono + duration_s) if duration_s > 0 else 0.0 + + def stop_segment(self): + with self._lock: + self._active = False + + def feed(self, metrics: dict, grab_ms: float, res: str, rotate: int): + """抓帧线程每帧调一次。仅在 active 且未超时时记录。""" + with self._lock: + if not self._active: + return + now = time.monotonic() + if self._seg_deadline > 0 and now >= self._seg_deadline: + self._active = False + return + if not self._columns: + # 首次: 固定前缀列 + metrics 的动态列 + self._columns = (["seg", "label", "t_ms", "grab_ms", "res", "rotate"] + + list(metrics.keys())) + row = { + "seg": self._seg_index, + "label": self._seg_label, + "t_ms": round((now - self._seg_start_mono) * 1000, 1), + "grab_ms": round(grab_ms, 1), + "res": res, + "rotate": rotate, + } + row.update(metrics) + self._rows.append(row) + + def status(self) -> dict: + with self._lock: + remain = 0.0 + if self._active and self._seg_deadline > 0: + remain = max(0.0, self._seg_deadline - time.monotonic()) + return { + "active": self._active, + "label": self._seg_label, + "remain_s": round(remain, 1), + "n_rows": len(self._rows), + "n_segments": self._seg_index, + } + + def to_csv(self) -> str: + import csv, io + with self._lock: + rows = list(self._rows) + cols = list(self._columns) if self._columns else ["seg"] + # 动态列可能因未来指标增删而不齐: 用所有行 key 的并集补齐 + allcols = list(cols) + for r in rows: + for k in r: + if k not in allcols: + allcols.append(k) + buf = io.StringIO() + w = csv.DictWriter(buf, fieldnames=allcols, extrasaction="ignore") + w.writeheader() + for r in rows: + w.writerow(r) + return buf.getvalue() + + def save_disk(self) -> Optional[Path]: + csv_text = self.to_csv() + stamp = time.strftime("%Y%m%d_%H%M%S") + path = self.out_dir / f"tuning_{stamp}.csv" + try: + path.write_text(csv_text, encoding="utf-8-sig") # BOM 便于 Excel 直接开 + return path + except Exception as e: + print(f"[REC] 存盘失败: {e}") + return None + + def clear(self): + with self._lock: + self._rows.clear() + self._seg_index = 0 + self._columns = [] + self._active = False + + +class FrameGrabber: + def __init__(self, tcp: TCPImageClient, recorder: "Recorder", ctl_state: dict): + self.tcp = tcp + self.recorder = recorder + self.ctl_state = ctl_state # {"res":..., "rotate":...} 供记录标注当前状态 + self._latest_jpg: Optional[bytes] = None + self._latest_metrics: dict = {} + self._latest_grab_ms: float = 0.0 + self._rotate_deg = 0 + self._lock = threading.Lock() + self._stop = threading.Event() + self._thread = threading.Thread(target=self._run, daemon=True) + + def set_rotation(self, deg: int): + with self._lock: + self._rotate_deg = deg % 360 + + def start(self): + self._thread.start() + + def _run(self): + while not self._stop.is_set(): + t0 = time.monotonic() + jpg = self.tcp.capture() + dt = (time.monotonic() - t0) * 1000 + if jpg: + with self._lock: + deg = self._rotate_deg + if deg: + jpg = rotate_jpeg(jpg, deg) # 真转, 指标基于转后图 + mtr = frame_metrics(jpg) + with self._lock: + self._latest_jpg = jpg + self._latest_metrics = mtr + self._latest_grab_ms = dt + # 喂记录器 (仅在 active 时真记); 带当前分辨率/旋转状态 + self.recorder.feed(mtr, dt, + res=self.ctl_state.get("res", "?"), + rotate=deg) + else: + time.sleep(0.05) + + def latest(self): + with self._lock: + return self._latest_jpg, dict(self._latest_metrics), self._latest_grab_ms + + def grab_batch(self, n: int, rotate_apply: bool = True): + """连抓 n 帧 (复用 TCP 连接, 串行)。返回 (frames_list, grab_ms_list)。 + 对应真实链路 ASR 后'抓 N 张'那一步。""" + frames, lats = [], [] + with self._lock: + deg = self._rotate_deg + for _ in range(n): + t0 = time.monotonic() + jpg = self.tcp.capture() + dt = (time.monotonic() - t0) * 1000 + if jpg: + if rotate_apply and deg: + jpg = rotate_jpeg(jpg, deg) + frames.append(jpg) + lats.append(dt) + return frames, lats + + def stop(self): + self._stop.set() + self._thread.join(timeout=2.0) + self.tcp.close() + + +# ============================================================ +# Web 服务 +# ============================================================ +PAGE = r""" + + + + +相机调参台 + + + +
+
+ +
+
Laplacian variance · 清晰度
+
+
+
+
+ +
等待画面…
+
+
+
+
漏斗选出的 BEST 帧 (喂给模型的那张)
+ +
+
+ + + + + + +""" + + +class PipelineStats: + """漏斗运行统计: 接受/拒绝计数(按原因)+ best帧存盘 + 最近 best 缓存。 + 拒绝率是安全指标的雏形: 该拒的拒了多少、各什么原因。""" + + def __init__(self, out_dir: Path): + self.out_dir = Path(out_dir) + self.out_dir.mkdir(parents=True, exist_ok=True) + self._lock = threading.Lock() + self.n_total = 0 + self.n_accepted = 0 + self.reasons: dict = {} # reason -> count + self.last_best: Optional[bytes] = None + self._batch_i = 0 + self._runs: list[dict] = [] # 每次抓拍一行汇总 (供标定用) + + def add_run_row(self, scene: str, res, focused: bool, best_path: str = "", geom: dict = None): + """每次抓拍追加一行汇总, 带用户标注的场景标签 + best帧路径。 + best_path: 供你事后人工看这张 best 清不清楚, 在 manual_label 列标真值 —— + 用人工判断(而非抓拍前意图标签)当 ground truth 校准阈值, 绕开标签错位。""" + per = res.per_frame or [] + max_q = max((p.get("quality", 0) for p in per), default=0) + max_fg = max((p.get("focus_gain", 0) for p in per), default=0) + # best 帧的完整 CV 指标 (供标定: 一张汇总表就能对比各指标 vs ok/blur) + bm = {} + if 0 <= res.best_index < len(per): + bm = per[res.best_index] + best_sharp = bm.get("sharpness", 0) + t = res.timings or {} + import os as _os + row = { + "time": time.strftime("%H:%M:%S"), + "scene": scene, + "manual_label": "", # ← 你看完 best 帧后手填: ok / blur (真值) + "n_frames": len(per), + "accepted": int(res.accepted), + "need_focus": int(res.need_focus), + "focused": int(focused), + "reject_reason": res.reject_reason, + "best_index": res.best_index, + "best_sharp": round(best_sharp, 1), + "best_local": bm.get("local_sharp", ""), + "best_worst_block": bm.get("worst_block", ""), + "best_block_std": bm.get("block_std", ""), + "best_text_sharp": bm.get("text_sharp", ""), + "best_text_ratio": bm.get("text_ratio", ""), + "best_contrast": bm.get("contrast", ""), + "best_dark_ratio": bm.get("dark_ratio", ""), + "seg_stable": (res.components or {}).get("stable", ""), + "seg_sharp": (res.components or {}).get("sharp", ""), + "seg_content": (res.components or {}).get("content", ""), + "seg_light": (res.components or {}).get("light", ""), + "max_quality": round(max_q, 3), + "max_focus_gain": round(max_fg, 3), + "grab_batch_ms": round(t.get("grab_batch_ms", 0), 1), + "funnel_ms": round(t.get("level1_metrics_ms", 0) + + t.get("level2_score_ms", 0) + + t.get("level3_decide_ms", 0), 1), + "total_ms": round(t.get("total_ms", 0), 1), + "best_file": _os.path.basename(best_path) if best_path else "", + "best_path": best_path, + # 方向分类器原始输出(定位方向不准: raw标签 vs 你实际摆放) + "orient_raw": (geom or {}).get("orient_raw", ""), + "orient_conf": (geom or {}).get("orient_conf", ""), + "orient_state": (geom or {}).get("orient_state", ""), + "orient_hint": (geom or {}).get("orient_hint", "") or "", + } + with self._lock: + self._runs.append(row) + + def runs_csv(self) -> str: + import csv, io + with self._lock: + runs = list(self._runs) + cols = ["time", "scene", "manual_label", "n_frames", "accepted", "need_focus", + "focused", "reject_reason", "best_index", "best_sharp", + "best_local", "best_worst_block", "best_block_std", + "best_text_sharp", "best_text_ratio", "best_contrast", "best_dark_ratio", + "seg_stable", "seg_sharp", "seg_content", "seg_light", + "max_quality", "max_focus_gain", "grab_batch_ms", "funnel_ms", "total_ms", + "orient_raw", "orient_conf", "orient_state", "orient_hint", + "best_file", "best_path"] + # 未来新字段自动并入 + for r in runs: + for k in r: + if k not in cols: + cols.append(k) + buf = io.StringIO() + w = csv.DictWriter(buf, fieldnames=cols, extrasaction="ignore") + w.writeheader() + for r in runs: + w.writerow(r) + return buf.getvalue() + + def save_runs_csv(self) -> Optional[Path]: + stamp = time.strftime("%Y%m%d_%H%M%S") + path = self.out_dir / f"pipeline_runs_{stamp}.csv" + try: + path.write_text(self.runs_csv(), encoding="utf-8-sig") + return path + except Exception as e: + print(f"[PSTATS] runs csv 存盘失败: {e}") + return None + + def record(self, accepted: bool, reason: str): + with self._lock: + self.n_total += 1 + if accepted: + self.n_accepted += 1 + else: + self.reasons[reason] = self.reasons.get(reason, 0) + 1 + + def set_last_best(self, jpg: bytes): + with self._lock: + self.last_best = jpg + + def save_batch(self, frames: list[bytes], best_index: int, res): + """存整批 N 帧 + 标出 best, 供人工核对。返回 (目录, best帧路径)。""" + with self._lock: + self._batch_i += 1 + bi = self._batch_i + d = self.out_dir / f"batch_{time.strftime('%H%M%S')}_{bi:03d}" + best_path = "" + try: + d.mkdir(parents=True, exist_ok=True) + for i, jpg in enumerate(frames): + tag = "_BEST" if i == best_index else "" + sharp = res.per_frame[i]["sharpness"] if i < len(res.per_frame) else 0 + fp = d / f"f{i}_sharp{sharp:.0f}{tag}.jpg" + fp.write_bytes(jpg) + if i == best_index: + best_path = str(fp) + import json + (d / "funnel.json").write_text( + json.dumps(res.to_dict(), ensure_ascii=False, indent=2), encoding="utf-8") + return str(d), best_path + except Exception as e: + print(f"[PSTATS] save_batch 失败: {e}") + return "", "" + + def summary(self) -> dict: + with self._lock: + rej = self.n_total - self.n_accepted + return { + "total": self.n_total, + "accepted": self.n_accepted, + "rejected": rej, + "accept_rate": round(self.n_accepted / self.n_total, 3) if self.n_total else 0, + "reject_reasons": dict(self.reasons), + } + + +def make_app(grabber: FrameGrabber, ctl: CamControl, + recorder: Recorder, ctl_state: dict, default_dur: float, + funnel_cfg: "FunnelConfig", pstats: "PipelineStats") -> web.Application: + app = web.Application() + + async def h_index(request): + return web.Response(text=PAGE, content_type="text/html") + + async def h_frame(request): + jpg, m, grab_ms = grabber.latest() + if not jpg: + return web.Response(status=503, text="no frame") + headers = { + "X-Sharpness": str(m.get("sharpness", 0)), + "X-Brightness": str(m.get("brightness", 0)), + "X-Kb": str(m.get("kb", 0)), + "X-Grab-Ms": str(round(grab_ms, 0)), + "Cache-Control": "no-store", + } + return web.Response(body=jpg, content_type="image/jpeg", headers=headers) + + async def h_ctl(request): + op = request.query.get("op", "") + val = request.query.get("val", "") + dur = float(request.query.get("dur", default_dur) or default_dur) + loop = asyncio.get_event_loop() + label = None + if op == "res": + ok = await loop.run_in_executor(None, ctl.set_resolution, val) + ctl_state["res"] = val + label = f"res:{val}" + elif op == "af": + ok = await loop.run_in_executor(None, ctl.trigger_af) + label = "af" + elif op == "quality": + ok = await loop.run_in_executor(None, ctl.set_quality, int(val or 10)) + label = f"quality:{val}" + elif op == "rotate": + grabber.set_rotation(int(val or 0)) + ctl_state["rotate"] = int(val or 0) + ok = True + label = f"rotate:{val}" + else: + return web.json_response({"ok": False, "err": "unknown op"}, status=400) + # 控制操作自动开一段定时记录 (看该操作的效果曲线) + if label and dur > 0: + recorder.start_segment(label, dur) + return web.json_response({"ok": bool(ok), "recording": label, "dur": dur}) + + # ---- 记录控制 ---- + async def h_rec_start(request): + label = request.query.get("label", "manual") + dur = float(request.query.get("dur", 0) or 0) # 0=手动(直到 stop) + recorder.start_segment(label, dur) + return web.json_response({"ok": True, **recorder.status()}) + + async def h_rec_stop(request): + recorder.stop_segment() + return web.json_response({"ok": True, **recorder.status()}) + + async def h_rec_status(request): + return web.json_response(recorder.status()) + + async def h_rec_save(request): + path = recorder.save_disk() + return web.json_response({"ok": path is not None, + "path": str(path) if path else None, + **recorder.status()}) + + async def h_rec_download(request): + csv_text = recorder.to_csv() + recorder.save_disk() # 下载同时也存盘一份, 双保险 + return web.Response( + body=csv_text.encode("utf-8-sig"), + headers={"Content-Type": "text/csv; charset=utf-8", + "Content-Disposition": "attachment; filename=tuning.csv"}) + + async def h_rec_clear(request): + recorder.clear() + return web.json_response({"ok": True, **recorder.status()}) + + # ---- 形态2: 抓批 -> 评分漏斗 -> (稳但糊则对焦再采) -> best/拒绝 ---- + async def h_pipeline_run(request): + n = int(request.query.get("n", 5) or 5) + focus_n = int(request.query.get("focus_n", 3) or 3) # 对焦后补采几帧 + af_settle_ms = int(request.query.get("af_settle_ms", 120) or 120) # 对焦生效等待(ms) + # OV5640 单次对焦(0x3022=0x03)锁定通常在~100ms量级(目标近焦时更快), 非几百ms。 + # 默认120ms为初值, 实测用 ?af_settle_ms=N 扫描找最短有效等待。 + scene = request.query.get("scene", "") # 用户标注场景 + loop = asyncio.get_event_loop() + + def _work(): + t0 = time.monotonic() + frames, grab_lats = grabber.grab_batch(n) + grab_ms = (time.monotonic() - t0) * 1000 + if not frames: + return {"ok": False, "err": "no_frames"}, None, None + + res = run_funnel(frames, funnel_cfg) + focused = False + af_on = ctl_state.get("af_enabled", True) + # "自动对焦"开关 af_enabled 的语义(用户设计): + # ON(默认): 自主判断+按需触发对焦(路线A, 正常使用)。 + # OFF: 不自动触发对焦, 只保留 res.need_focus 的判断结果 —— + # 用于录制实验时验证"判据说该对焦"这个判断本身对不对, 不让对焦动作干扰。 + # (手动"触发单次AF"按钮走 /op?op=af, 不受此开关限制, 任何时候可手动触发。) + # 固件侧须 g_auto_af=false, 否则固件每秒硬对焦会架空此开关。 + if res.need_focus and af_on: + tf = time.monotonic() + ctl.trigger_af() # 写 /reg 0x3022=0x03 单次对焦 + # 等对焦生效再抓 —— trigger_af 后马达物理对焦需时间(OV5640单次对焦~100ms量级), + # 立刻 grab_batch 会抓到"对焦过程中"的糊帧。af_settle_ms 可调, 实测最短有效等待。 + if af_settle_ms > 0: + time.sleep(af_settle_ms / 1000.0) # _work 在 executor 线程, sleep 不阻塞事件循环 + extra, extra_lats = grabber.grab_batch(focus_n) + res.timings["focus_af_regrab_ms"] = (time.monotonic() - tf) * 1000 + if extra: + frames = frames + extra + grab_lats = grab_lats + extra_lats + res = run_funnel(frames, funnel_cfg) + focused = True + + res.timings["grab_batch_ms"] = grab_ms + res.timings["grab_per_frame_ms"] = [round(x, 1) for x in grab_lats] + res.timings["focused"] = 1 if focused else 0 + + infer_text = None + # 可读性多帧一致性: 本窗口 accepted 只是"候选送下游"; 复用方向那套跨窗口累积, + # 连续窗口多数都候选送, 才真正送下游 —— 滤掉"单窗口偶然可读"(晃动中偶抓清晰帧)。 + # 严重晃动(severe_shake)已在 run_funnel 单窗口即拒, 不进这里, 不受一致性影响。 + # 纯CV判定累积(不喂下游), 与方向一致性同机制。N=3 多数。 + rhist = ctl_state.setdefault("readable_hist", []) + rhist.append(1 if res.accepted else 0) + del rhist[:-3] # 只留最近3窗口 + readable_consistent = (len(rhist) >= 3 and sum(rhist) > 3 / 2) # 3窗口多数 + res_dict_extra = {"readable_hist": list(rhist), + "readable_consistent": readable_consistent} + if res.accepted and res.best_jpg is not None and readable_consistent: + to = time.monotonic() + oriented, geom_diag = process_orientation(res.best_jpg) + res.timings["orientation_ms"] = (time.monotonic() - to) * 1000 + # 多帧一致性(方向): 累积最近若干次抓拍的"疑似倒置"标志, 连续/多数才弹"请确认正反"。 + # 纯CV判据的多帧累积(不喂VLM/OCR), 滤单帧噪声, 避免正常图偶发误报。 + if geom_diag and geom_diag.get("ok"): + hist = ctl_state.setdefault("flip_hist", []) + hist.append(1 if geom_diag.get("flipped_frame") else 0) + del hist[:-5] # 只留最近5次 + # 5次里≥3次疑似倒置, 且本次也疑似 -> 才弹确认(多数一致) + if len(hist) >= 3 and sum(hist) >= 3 and geom_diag.get("flipped_frame"): + if not geom_diag.get("orient_hint"): + geom_diag["orient_hint"] = "请确认药盒正反" + geom_diag["flip_consistent"] = True + geom_diag["flip_hist"] = list(hist) + ti = time.monotonic() + infer_text = infer(oriented) + res.timings["infer_ms"] = (time.monotonic() - ti) * 1000 + pstats.record(accepted=True, reason="") + saved_dir, best_path = pstats.save_batch(frames, res.best_index, res) + res.timings["total_ms"] = (time.monotonic() - t0) * 1000 + rd = res.to_dict(); rd.update(res_dict_extra) + return ({"ok": True, "result": rd, "focused": focused, + "infer": infer_text, "geom": geom_diag, "saved_dir": saved_dir}, + res.best_jpg, (res, focused, best_path)) + elif res.accepted and not readable_consistent: + # 本窗口看着可读, 但连续一致性未达(可能偶然/刚开始) -> 暂不送下游, 等确认 + pstats.record(accepted=False, reason="await_consistency") + res.timings["total_ms"] = (time.monotonic() - t0) * 1000 + rd = res.to_dict(); rd.update(res_dict_extra) + rd["reject_reason"] = "await_consistency" + return ({"ok": True, "result": rd, "focused": focused, + "infer": None, "await_consistency": True}, + res.best_jpg, (res, focused, None)) + else: + # 若对焦后仍 need_focus, 归为最终拒绝(对焦也没救回来) + reason = res.reject_reason if res.reject_reason != "need_focus" else "all_blurry" + pstats.record(accepted=False, reason=reason) + res.reject_reason = reason + res.timings["total_ms"] = (time.monotonic() - t0) * 1000 + # 拒绝时也存证 + 显示本次批次里最清晰的一帧(而非留旧图), + # 让你能看到"系统这次面对的到底是什么画面", 复盘判定冤不冤。 + rej_best = res.best_index if 0 <= res.best_index < len(frames) else 0 + saved_dir, best_path = pstats.save_batch(frames, rej_best, res) + show_jpg = frames[rej_best] if frames else None + return ({"ok": True, "result": res.to_dict(), "focused": focused, + "infer": None, "geom": None, "rejected_shown": True, + "saved_dir": saved_dir}, show_jpg, (res, focused, best_path)) + + result = await loop.run_in_executor(None, _work) + if len(result) == 3: + payload, best_jpg, run_info = result + else: + payload, best_jpg, run_info = result[0], result[1], None + if best_jpg is not None: + pstats.set_last_best(best_jpg) + if run_info is not None: + res_obj, focused, best_path = run_info + pstats.add_run_row(scene, res_obj, focused, best_path, payload.get("geom")) + return web.json_response({**payload, "stats": pstats.summary()}) + + async def h_pipeline_best(request): + jpg = pstats.last_best + if not jpg: + return web.Response(status=404) + return web.Response(body=jpg, content_type="image/jpeg", + headers={"Cache-Control": "no-store"}) + + async def h_pipeline_stats(request): + return web.json_response(pstats.summary()) + + async def h_pipeline_download(request): + csv_text = pstats.runs_csv() + pstats.save_runs_csv() # 同时存盘 + return web.Response( + body=csv_text.encode("utf-8-sig"), + headers={"Content-Type": "text/csv; charset=utf-8", + "Content-Disposition": "attachment; filename=pipeline_runs.csv"}) + + # ---- 录制一段纯原始帧流(按秒, 不掺对焦), 供 rerun 看过程判定(问题1) ---- + async def h_record(request): + name = request.query.get("name", "").strip() or time.strftime("clip_%H%M%S") + dur = float(request.query.get("dur", 8) or 8) + dur = max(2.0, min(30.0, dur)) + safe = "".join(ch for ch in name if ch.isalnum() or ch in "_-") + clip_dir = pstats.out_dir.parent / "clips" / safe + loop = asyncio.get_event_loop() + try: + rec = await loop.run_in_executor( + None, record_stream, grabber, clip_dir, dur) + except Exception as e: + return web.json_response({"ok": False, "err": str(e)}, status=500) + return web.json_response({ + "ok": True, "dir": str(rec.dir), "name": safe, + "n_frames": len(rec.frames), "duration_s": dur, + }) + + app.router.add_get("/", h_index) + app.router.add_get("/frame", h_frame) + app.router.add_get("/ctl", h_ctl) + app.router.add_get("/rec/start", h_rec_start) + app.router.add_get("/rec/stop", h_rec_stop) + app.router.add_get("/rec/status", h_rec_status) + app.router.add_get("/rec/save", h_rec_save) + app.router.add_get("/rec/download", h_rec_download) + app.router.add_get("/rec/clear", h_rec_clear) + app.router.add_get("/pipeline/run", h_pipeline_run) + app.router.add_get("/pipeline/best", h_pipeline_best) + app.router.add_get("/pipeline/stats", h_pipeline_stats) + async def h_af_toggle(request): + val = request.query.get("on", "") + if val in ("1", "true", "on"): + ctl_state["af_enabled"] = True + elif val in ("0", "false", "off"): + ctl_state["af_enabled"] = False + return web.json_response({"ok": True, "af_enabled": ctl_state.get("af_enabled", True)}) + + app.router.add_get("/pipeline/download", h_pipeline_download) + app.router.add_get("/record", h_record) + app.router.add_get("/af_toggle", h_af_toggle) + return app + + +# ============================================================ +# 录制 + rerun (受控对比基础) +# 录制: 采一段(未对焦) -> 触发真AF -> 再采一段(对焦后), 两段都存, 标对焦点。 +# rerun: 从录制回放帧喂 run_funnel, 同一段反复扫参数, 输入固定=受控对比。 +# 解法一: 对焦效果也录进去(对焦后的帧真实存在), 故 C 出口的对焦可受控复现。 +# ============================================================ +class Recording: + """一段录制: 原始帧序列 + 每帧时间戳 + 对焦触发点标记。""" + + def __init__(self, clip_dir: Path): + self.dir = Path(clip_dir) + self.frames: list[bytes] = [] + self.timestamps: list[float] = [] + self.af_index = -1 # 对焦触发点: 此索引及之后的帧是"对焦后" + self.meta = {} + + def save(self): + self.dir.mkdir(parents=True, exist_ok=True) + for i, jpg in enumerate(self.frames): + (self.dir / f"frame_{i:04d}.jpg").write_bytes(jpg) + import json + meta = { + "n_frames": len(self.frames), + "timestamps": self.timestamps, + "af_index": self.af_index, # -1=无对焦点 + **self.meta, + } + (self.dir / "meta.json").write_text( + json.dumps(meta, ensure_ascii=False, indent=2), encoding="utf-8") + return self.dir + + @classmethod + def load(cls, clip_dir): + import json + d = Path(clip_dir) + rec = cls(d) + meta = json.loads((d / "meta.json").read_text(encoding="utf-8")) + rec.af_index = meta.get("af_index", -1) + rec.timestamps = meta.get("timestamps", []) + rec.meta = meta + n = meta.get("n_frames", 0) + for i in range(n): + fp = d / f"frame_{i:04d}.jpg" + if fp.exists(): + rec.frames.append(fp.read_bytes()) + return rec + + def pre_af_frames(self): + """对焦前的帧 (rerun 时先用这些跑漏斗)。""" + if self.af_index < 0: + return self.frames + return self.frames[:self.af_index] + + def post_af_frames(self): + """对焦后的帧 (rerun 时 C 出口触发对焦后回放这些)。""" + if self.af_index < 0: + return [] + return self.frames[self.af_index:] + + +def record_stream(grabber: "FrameGrabber", clip_dir: Path, + duration_s: float = 8.0, gap_s: float = 0.05) -> Recording: + """按秒录一段纯原始帧流 (不掺对焦)。专为问题1: rerun 回放看整个过程的 + 判定序列, 验证 CV 判的'该对焦'对不对。af_index=-1 表示无对焦点。""" + rec = Recording(clip_dir) + rec.af_index = -1 + t0 = time.monotonic() + while (time.monotonic() - t0) < duration_s: + jpg = grabber.tcp.capture() + if jpg: + rec.frames.append(jpg) + rec.timestamps.append(time.monotonic() - t0) + time.sleep(gap_s) + rec.meta["duration_s"] = duration_s + rec.meta["kind"] = "stream" # 区别于对焦对比的 clip + rec.save() + return rec + + +def rerun_stream(clip_dir, cfg: "FunnelConfig" = None, n: int = 5, stride: int = 3): + """对一段连续录制, 滑动窗口跑判定, 输出'整个过程的判定序列'。 + 每 stride 帧滑一次, 窗口大小 n。看物品进->停->出时判定(A/B/C)怎么变。 + 对焦命令天然关闭(回放死图), 即问题1: 验证'该对焦'的判断对不对。 + + 产出(供人工核对): 每窗口存 best 帧(文件名带判定) + 一个 CSV(每窗口一行, + 带判定/各分量/best帧路径)。你筛 reason=need_focus 的行, 点开原图看是否真需调焦。""" + import csv, json + cfg = cfg or FunnelConfig() + rec = Recording.load(clip_dir) + frames = rec.frames + out_dir = Path(clip_dir) / "rerun" + out_dir.mkdir(parents=True, exist_ok=True) + print(f"\n=== 过程判定序列 {Path(clip_dir).name} " + f"({len(frames)}帧, ~{rec.meta.get('duration_s','?')}s, 窗口N={n} 步长={stride}) ===") + print(f"{'win':<5}{'t(s)':<7}{'判定':<10}{'reason':<14}{'stable':<8}{'sharp':<8}{'content':<8}{'best图'}") + print("-" * 78) + rows = [] + i = 0 + win = 0 + flip_hist = [] # 跨窗口多帧一致性: 累积"疑似倒置"标志 + while i + n <= len(frames): + window = frames[i:i + n] + res = run_funnel(window, cfg) + t = rec.timestamps[i] if i < len(rec.timestamps) else i * 0.05 + comp = res.components or {} + if res.accepted: + verdict = "B_usable" + elif res.reject_reason == "need_focus": + verdict = "C_needfocus" + elif res.reject_reason == "unstable": + verdict = "A_moving" + else: + verdict = res.reject_reason + # 存 best 帧 (窗口内 best_index; 拒绝时也存参考帧) + bidx = res.best_index if 0 <= res.best_index < len(window) else 0 + best_name = f"w{win:03d}_t{t:.1f}_{verdict}.jpg" + (out_dir / best_name).write_bytes(window[bidx]) + # best 帧的完整指标 + bm = res.per_frame[bidx] if 0 <= bidx < len(res.per_frame) else {} + # === 方向判据 (只对被接受的 best 帧跑; 拒绝的帧朝向无意义) === + orient_state = ""; ud_score = ""; side_ratio = ""; orient_hint = ""; flip_consistent = "" + if res.accepted: + _, gd = process_orientation(window[bidx]) + if gd.get("ok"): + orient_state = gd.get("orient_state", "") + ud_score = gd.get("ud_score", "") + side_ratio = gd.get("sideways_ratio", "") + orient_hint = gd.get("orient_hint") or "" + # 多帧一致性(按窗口顺序累积, 与 live 同逻辑): 5窗内≥3窗疑倒置且本窗也疑 -> 触发 + flip_hist.append(1 if gd.get("flipped_frame") else 0) + del flip_hist[:-5] + if len(flip_hist) >= 3 and sum(flip_hist) >= 3 and gd.get("flipped_frame"): + flip_consistent = 1 + if not orient_hint: + orient_hint = "请确认药盒正反" + else: + flip_consistent = 0 + print(f"{win:<5}{t:<7.1f}{verdict:<10}{res.reject_reason:<14}" + f"{comp.get('stable',0):<8.2f}{comp.get('sharp',0):<8.2f}{comp.get('content',0):<8.2f}{best_name}") + rows.append({ + "win": win, "t_s": round(t, 2), "verdict": verdict, + "reject_reason": res.reject_reason, "accepted": int(res.accepted), + "need_focus": int(res.need_focus), + "g_stable": comp.get("stable", ""), "g_sharp": comp.get("sharp", ""), + "g_content": comp.get("content", ""), "g_light": comp.get("light", ""), + "seg_flow": comp.get("flow", ""), + "best_sharp": bm.get("sharpness", ""), "best_local": bm.get("local_sharp", ""), + "best_worst_block": bm.get("worst_block", ""), "best_text_ratio": bm.get("text_ratio", ""), + "best_frame": best_name, + # 方向判据输出 (供核对方向准确性) + "orient_state": orient_state, "ud_score": ud_score, + "sideways_ratio": side_ratio, "flip_consistent": flip_consistent, + "orient_hint": orient_hint, + "manual_check": "", # ← 你看完 best 图后填: 该对焦的真该吗? ok/wrong + "manual_orient": "", # ← 你填这窗 best 的真实朝向: upright/sideways/flipped + }) + i += stride + win += 1 + # 存 CSV + cols = ["win", "t_s", "verdict", "reject_reason", "accepted", "need_focus", + "g_stable", "g_sharp", "g_content", "g_light", "seg_flow", + "best_sharp", "best_local", "best_worst_block", "best_text_ratio", + "best_frame", + "orient_state", "ud_score", "sideways_ratio", "flip_consistent", "orient_hint", + "manual_check", "manual_orient"] + csv_path = out_dir / "sequence.csv" + with open(csv_path, "w", encoding="utf-8-sig", newline="") as f: + w = csv.DictWriter(f, fieldnames=cols) + w.writeheader() + w.writerows(rows) + from collections import Counter + cnt = Counter(r["verdict"] for r in rows) + print(f"\n判定分布: {dict(cnt)}") + print(f"CSV: {csv_path}") + print(f"best图: {out_dir}/ (筛 need_focus 的窗口, 看对应 best图是否真需调焦)") + return rows + + +def record_clip(grabber: "FrameGrabber", ctl: "CamControl", clip_dir: Path, + pre_n: int = 8, post_n: int = 8, gap_s: float = 0.05) -> Recording: + """录一段: 抓 pre_n 帧(未对焦) -> 触发真AF -> 抓 post_n 帧(对焦后)。 + 含对焦点标记, 供 rerun 复现 C 出口对焦效果 (解法一)。""" + rec = Recording(clip_dir) + t0 = time.monotonic() + # 未对焦段 + for _ in range(pre_n): + jpg = grabber.tcp.capture() + if jpg: + rec.frames.append(jpg) + rec.timestamps.append(time.monotonic() - t0) + time.sleep(gap_s) + # 触发真 AF + rec.af_index = len(rec.frames) + ctl.trigger_af() + time.sleep(0.2) # 给对焦一点生效时间 + # 对焦后段 + for _ in range(post_n): + jpg = grabber.tcp.capture() + if jpg: + rec.frames.append(jpg) + rec.timestamps.append(time.monotonic() - t0) + time.sleep(gap_s) + rec.meta["pre_n"] = pre_n + rec.meta["post_n"] = post_n + rec.save() + return rec + + +def rerun_clip(rec: "Recording", cfg: "FunnelConfig", n: int, focus_n: int = 3) -> dict: + """对一段录制跑漏斗: 用前 n 帧(对焦前); 若判 need_focus, 用对焦后帧重评。 + 输入固定, 只变 cfg/n/focus_n -> 受控对比。返回判定 + 是否用了对焦。""" + pre = rec.pre_af_frames() + if len(pre) < n: + n = len(pre) + batch = pre[:n] + res = run_funnel(batch, cfg) + focused = False + if res.need_focus: + post = rec.post_af_frames() + if post: + extra = post[:focus_n] + res = run_funnel(batch + extra, cfg) # 合并重评, best 应来自对焦后帧 + focused = True + return { + "accepted": res.accepted, + "reject_reason": res.reject_reason, + "need_focus": res.need_focus, + "focused": focused, + "best_index": res.best_index, + "components": res.components, + "n": n, "focus_n": focus_n, + } + + +def rerun_sweep(clip_dir, cfg: "FunnelConfig" = None, + n_values=(3, 5, 7), focus_values=(0, 3)): + """对一段录制扫参数, 打印结果表 (找 N 拐点 / 对焦是否值得)。 + 受控对比: 同一段帧, 只变 N 和 focus_n。""" + cfg = cfg or FunnelConfig() + rec = Recording.load(clip_dir) + print(f"\n=== rerun 扫参 {Path(clip_dir).name} " + f"({len(rec.frames)}帧, 对焦点@{rec.af_index}) ===") + print(f"{'N':<5}{'focus_n':<9}{'判定':<12}{'用对焦':<8}{'best':<6}{'原因'}") + print("-" * 50) + for n in n_values: + for fn in focus_values: + r = rerun_clip(rec, cfg, n, fn) + verdict = "接受" if r["accepted"] else "拒绝" + print(f"{n:<5}{fn:<9}{verdict:<12}{'是' if r['focused'] else '否':<8}" + f"{r['best_index']:<6}{r['reject_reason']}") + return rec + + +def main(): + ap = argparse.ArgumentParser(description="ESP32 相机流水线台 (形态2: 漏斗+录制+rerun)") + ap.add_argument("--ip", help="眼镜 IP (live/record 模式必需)") + ap.add_argument("--tcp-port", type=int, default=5000) + ap.add_argument("--port", type=int, default=8080, help="网页端口") + ap.add_argument("--record-dir", default="./tuning_logs", help="CSV/批次 存盘目录") + ap.add_argument("--duration", type=float, default=5.0, help="点控制按钮后自动记录秒数") + ap.add_argument("--quality", type=int, default=4, help="启动默认 JPEG 质量(小=清晰, 默认4最高)") + # 录制 / rerun 模式 + ap.add_argument("--record", metavar="CLIP_DIR", help="录一段(含对焦点)到指定目录, 然后退出") + ap.add_argument("--pre-n", type=int, default=8, help="录制: 对焦前帧数") + ap.add_argument("--post-n", type=int, default=8, help="录制: 对焦后帧数") + ap.add_argument("--rerun", metavar="CLIP_DIR", help="对一段录制扫参数(N/focus_n), 然后退出") + args = ap.parse_args() + + # ---- rerun 模式: 纯离线, 不连眼镜 ---- + if args.rerun: + rec = Recording.load(args.rerun) + if rec.meta.get("kind") == "stream" or rec.af_index < 0: + rerun_stream(args.rerun) # 连续过程 -> 过程判定序列(问题1) + else: + rerun_sweep(args.rerun) # 对焦对比 clip -> 扫参数 + return + + # ---- record 模式: 连眼镜录一段 ---- + if args.record: + if not args.ip: + print("record 模式需要 --ip"); return + tcp = TCPImageClient(args.ip, args.tcp_port) + grabber = FrameGrabber(tcp, Recorder(Path(args.record_dir)), {"res": "HD", "rotate": 0}) + grabber.start(); time.sleep(0.3) + ctl = CamControl(args.ip) + print(f"[REC] 录制中: {args.pre_n}帧(未对焦) -> AF -> {args.post_n}帧(对焦后)...") + rec = record_clip(grabber, ctl, Path(args.record), args.pre_n, args.post_n) + print(f"[REC] 已存 {rec.dir} ({len(rec.frames)}帧, 对焦点@{rec.af_index})") + print(f"[REC] rerun: python cam_pipeline.py --rerun {rec.dir}") + grabber.stop() + return + + # ---- live 模式: 网页 ---- + if not args.ip: + print("live 模式需要 --ip"); return + recorder = Recorder(Path(args.record_dir)) + ctl_state = {"res": "HD", "rotate": 0, "af_enabled": True} + funnel_cfg = FunnelConfig() + pstats = PipelineStats(Path(args.record_dir) / "batches") + + tcp = TCPImageClient(args.ip, args.tcp_port) + grabber = FrameGrabber(tcp, recorder, ctl_state) + grabber.start() + ctl = CamControl(args.ip) + # 启动默认: HD + 最高画质(quality=4), 省得每次进网页手调 + ctl.set_resolution("HD"); ctl_state["res"] = "HD" + ctl.set_quality(args.quality) + time.sleep(0.15); ctl.trigger_af() # 切完补一次对焦 + print(f"[PIPE] 启动默认: HD + quality={args.quality} + 对焦") + + app = make_app(grabber, ctl, recorder, ctl_state, args.duration, funnel_cfg, pstats) + print(f"[PIPE] http://localhost:{args.port} (TCP {args.ip}:{args.tcp_port})") + print(f"[PIPE] 录制受控对比: python cam_pipeline.py --ip {args.ip} --record clips/case1") + print("[PIPE] 独占 TCP: 调参时不要同时跑主程序") + try: + web.run_app(app, host="0.0.0.0", port=args.port, print=None) + finally: + grabber.stop() + + +if __name__ == "__main__": + main() diff --git a/extensions/assistive_harness/phase_b/esp32_runtime.py b/extensions/assistive_harness/phase_b/esp32_runtime.py new file mode 100644 index 0000000..1a7d4cc --- /dev/null +++ b/extensions/assistive_harness/phase_b/esp32_runtime.py @@ -0,0 +1,1851 @@ +"""ESP32 Phase B Harness runtime. + +复用 rokid_runtime 的全部 harness 骨架(HarnessClient / GatewaySessionManager / +GatewayDuplexSession / PCSpeaker / OutputGate / 控制逻辑),只把设备 I/O 从 +"PC 起 web server 等 Rokid 推" 换成 "PC 主动连 ESP32 拉音视频"。 + +数据方向对比: + Rokid : 眼镜(APK) --push--> PC 的 aiohttp server + ESP32 : PC --pull--> ESP32(CameraWebServer, /ws_audio_v2 + TCP:5000) + +汇聚点完全一致: + 音频 -> audio_queue(给 gateway session) + harness.send_audio(镜像给 8021 ASR) + 图像 -> latest_frame.set() + harness.send_frame(镜像给 8021) + AI 音频输出 -> PCSpeaker +""" +from __future__ import annotations + +import argparse +import asyncio +import json +import logging +import signal +import ssl +import struct +import base64 +import os +import time +from pathlib import Path +from typing import Any, Optional + +import aiohttp +import numpy as np + +from .timing_probe import TimingProbe +from .funnel_gate import FunnelGate +from .session_recorder import SessionRecorder +from .recorder_live import LiveRecorder +try: + from .bridge_ui import WebUIServer +except Exception: + WebUIServer = None + +# ── 复用 rokid_runtime 的 harness 骨架(一个字不改)────────────────────── +from .rokid_runtime import ( + RokidRuntimeConfig, + GatewaySessionManager, + GatewayDuplexSession, + HarnessClient, + PCSpeaker, + NullSpeaker, + OutputGate, + DropOldestAudioQueue, + AudioMirrorChunker, + LatestFrame, + RuntimeStats, + CtrlCExitWatchdog, + SkillRegistry, + default_skills_config, + pcm16le_to_float32, + apply_pcm16_gain, + now_ms, + SAMPLE_RATE_IN, +) + +LOG = logging.getLogger("assistive_harness.phase_b.esp32") + +# ESP32 音频包头: = seq(4) ts_ms(4) n_samples(2) reserved(2) +# 注意:第4字段是 reserved(pad),固件真丢包计数 g_ring_drops 未发到 wire, +# PC 端用 seq 跳变推断真丢包。 +ESP32_PKT_HDR = 12 +# TCP 图像帧头 magic +_TCP_IMG_MAGIC = 0x55AA55AA + +# 句子边界标点(作为"保护单位"的边界) +def _install_asr_tap(harness, live_rec) -> None: + """把 8021 的 asr.transcript 截下来落盘(评分取提问时刻 t0 用)。 + + 为什么不是另开一条连接:8021 每个 client_id 有独立的 runtime 和 outbound 队列, + asr.transcript 只投递给"送音频进来的那个 client"(即 esp32-phase-b), + 另开的 esp32-asr-tap 虽然能连上,但永远收不到任何消息。 + 所以只能挂在同一条 HarnessClient 上——rokid_runtime 里加了个可选的 on_message + 旁路(默认 None,不影响原行为),这里赋值即可。 + + 8021 推的字段(server.py 148-154): + {"type":"asr.transcript", "asr_event_id":..., "utterance":"这上面写的是什么", + "confidence":..., "final_at_ms":..., + "suppressed": true/false, "reason": "..."} ← 被回声抑制时带这两个 + 注意:**被 echo drop 的也照样推**(抑制发生在 route/echo 之后),所以这里全都记, + 由评分侧按问句筛,不在这里过滤。 + """ + if live_rec is None or harness is None: + return + + def _on_message(payload): + if not isinstance(payload, dict): + return + if payload.get("type") != "asr.transcript": + return + utt = str(payload.get("utterance") or "").strip() + if not utt: + return + try: + live_rec.log_asr(utt, payload.get("final_at_ms"), + payload.get("confidence")) + LOG.info("[ASR] %s%s", utt, + " (suppressed)" if payload.get("suppressed") else "") + except Exception as e: + LOG.warning("[ASR] 落盘失败: %s", e) + + harness.on_message = _on_message + LOG.info("[ASR] transcript 旁路已挂在 HarnessClient 上") + + +class TurnPrinter: + """把逐 chunk 的 text 碎片聚合成整段 turn(移植自 demo_esp32_duplex_0703)。 + + -o 每个 chunk 只吐几个字,评分要的是"这次回答说了什么"。规则: + text 非空 且(不在 turn 内 或 listen/speak 发生切换)→ 开新 turn,turn_idx +1 + end_of_turn → 返回 (turn_idx, 整段文本, is_listen) 并结束本 turn + is_listen=True 的 turn 是 8021 ASR 识别出的用户说话(用于取提问结束时刻 t0)。 + """ + + def __init__(self) -> None: + self.turn_idx = 0 + self._in_turn = False + self._turn_is_listen = None + self._turn_text: list[str] = [] + + def _reset(self) -> None: + self._in_turn = False + self._turn_text.clear() + + def feed(self, is_listen: bool, end_of_turn: bool, text: str): + """返回 (turn_idx, 完整文本或"", is_listen)。 + + 除 end_of_turn 外,**listen/speak 切换时也会把上一段吐出来** —— + 原实现在切换时直接 _reset() 丢掉,模型一路流式说、end_of_turn 迟迟不来时 + 整段就没了(bare 组实测 transcript 全空)。 + """ + flushed = None + if text: + if (not self._in_turn) or (self._turn_is_listen != is_listen): + if self._in_turn and self._turn_text: + flushed = (self.turn_idx, "".join(self._turn_text), + bool(self._turn_is_listen)) + self._reset() + self.turn_idx += 1 + self._in_turn = True + self._turn_is_listen = is_listen + self._turn_text.append(text) + if flushed is not None and not end_of_turn: + return flushed + if end_of_turn: + full_text = "".join(self._turn_text) + cur_idx = self.turn_idx + cur_listen = bool(self._turn_is_listen) + self._reset() + return cur_idx, full_text, cur_listen + return self.turn_idx, "", is_listen + + +_SENT_PUNCT = ",。!?,.!?" + + +def _emit_chunk_img(web_ui, jpeg: bytes, idx: int, img_sent: bool, age_ms: int = 0): + """把一帧图推给 bridge_ui 第一视角(type=chunk, img_b64)。无客户端时零负担。""" + if web_ui is None or not getattr(web_ui, "live_clients", None): + return + try: + b64 = base64.b64encode(jpeg).decode("ascii") if jpeg else None + import asyncio as _a + _a.create_task(web_ui.emit({ + "type": "chunk", + "idx": int(idx), + "img_b64": b64, + "img_sent": bool(img_sent), + "img_age_ms": int(age_ms), + })) + except Exception: + pass + + +class SentenceTracker: + """跟踪模型输出的句子边界,供漏斗"标点保护"策略用。 + + handle_result 每个 chunk 调 update():检测句末标点,累计标点序号。 + image_loop:reject 挂起时 snapshot() 记当前标点序号;之后 + boundary_reached(snap, speaker) 判断"自挂起后是否出现了新句末标点, + 且该段语音已经播完(speaker 队列基本清空)"。 + + 关键:模型文字生成远快于语音播放,文字标点会早于语音到达。所以"语音播到 + 标点"不能靠文字标点时刻或墙钟估算,而要看 speaker.pending_ms —— 队列里还 + 没播的语音降到很低时,才说明当前这段(含标点前的字)真的播完了。这样打断点 + 落在句末标点、语音播完那一刻,不会把句子从中间截断。 + """ + def __init__(self): + self._speaking = False + self._punct_seq = 0 # 句末标点计数(每出现一个 +1) + + def update(self, text: str, audio_ms: float, is_listen: bool): + self._speaking = not is_listen + if text and any(p in text for p in _SENT_PUNCT): + self._punct_seq += 1 + + @property + def speaking(self) -> bool: + return self._speaking + + def snapshot(self): + return {"punct_seq": self._punct_seq} + + def boundary_reached(self, snap, speaker=None): + """自 snap 之后:出现了新句末标点,且该段语音已播完(speaker 队列近空)。""" + if self._punct_seq <= snap["punct_seq"]: + return False # 还没出现新的句末标点 → 仍在保护当前句 + # 出现了新标点:等语音真的播到这里(speaker 队列基本清空) + if speaker is not None: + try: + if speaker.pending_ms() > 150.0: # 还有 >150ms 没播完 → 语音还没到标点 + return False + except Exception: + pass + return True + +# ── 强制措施:播放离线预生成的 reject 提示 wav(模型音色,运行时不碰 chat/KV)── +_REJECT_WAV_CACHE = {} # reason -> float32 ndarray(进程内缓存,只读一次盘) + + +def _load_reject_wav(wav_dir, reason): + """读预生成的 {reason}.wav(24kHz 16-bit mono)→ float32 ndarray,带缓存。 + 找不到返回 None(跳过播报,不阻断主流程)。""" + import wave as _wave + if reason in _REJECT_WAV_CACHE: + return _REJECT_WAV_CACHE[reason] + path = os.path.join(wav_dir, str(reason) + ".wav") + if not os.path.isfile(path): + _REJECT_WAV_CACHE[reason] = None + return None + try: + with _wave.open(path, "rb") as wf: + n = wf.getnframes() + raw = wf.readframes(n) + pcm16 = np.frombuffer(raw, dtype=np.int16) + pcm = (pcm16.astype(np.float32) / 32768.0) + _REJECT_WAV_CACHE[reason] = pcm + return pcm + except Exception: + _REJECT_WAV_CACHE[reason] = None + return None + +# ── 强制措施(防幻觉):reject 时用模型音色念提示 ───────────────────────── +# 复用 test_tts_speak 验证过的链路:走 gateway 的 /ws/chat(wss),zero-shot TTS, +# 模型音色念任意文本,返回 float32 24kHz 音频 → PCSpeaker 播。 +# 停/恢复走 8021(funnel.stop/funnel.resume),和真人「停一下」同一条 controller。 +_TTS_SYS_PROMPT = ( + "模仿音频样本的音色并生成新的内容。请用这种声音风格来为用户提供帮助。" + "直接作答,不要有冗余内容。" +) + + +async def _speak_hint_via_chat( + gateway_host: str, + gateway_port: int, + hint_text: str, + speaker, + ssl_ctx, +) -> bool: + """用 chat zero-shot TTS 让模型用自己音色念 hint_text,播到 PCSpeaker。 + + 返回 True=念出并已入队播放;False=失败(不阻断主流程)。 + """ + url = f"wss://{gateway_host}:{gateway_port}/ws/chat" + req = { + "messages": [ + {"role": "system", "content": _TTS_SYS_PROMPT}, + {"role": "user", "content": "请朗读以下内容:" + hint_text}, + ], + "streaming": False, + "generation": {"max_new_tokens": 128, "length_penalty": 1.1}, + "tts": {"enabled": True}, + "use_tts_template": True, + "omni_mode": False, + } + try: + async with aiohttp.ClientSession() as sess: + async with sess.ws_connect(url, ssl=ssl_ctx, max_msg_size=128 * 1024 * 1024) as ws: + await ws.send_json(req) + audio_b64 = None + sr = 24000 + # 加超时:念提示走 /ws/chat,若 duplex 占着 worker 会排队。 + # 超时返回,避免永久阻塞 image_loop(否则后续抓图全停)。 + deadline = time.monotonic() + 8.0 + while True: + remaining = deadline - time.monotonic() + if remaining <= 0: + LOG.warning("[强制措施] 念提示超时(可能 /ws/chat 排队,duplex 占用 worker)") + return False + try: + msg = await asyncio.wait_for(ws.receive(), timeout=remaining) + except asyncio.TimeoutError: + LOG.warning("[强制措施] 念提示超时(等 chat 响应)") + return False + if msg.type != aiohttp.WSMsgType.TEXT: + if msg.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + return False + continue + data = json.loads(msg.data) + if data.get("type") == "done": + audio_b64 = data.get("audio_data") + sr = data.get("audio_sample_rate") or 24000 + break + if data.get("type") == "error": + LOG.warning("[强制措施] chat TTS error: %s", data.get("error")) + return False + if not audio_b64: + LOG.warning("[强制措施] chat TTS 无音频返回") + return False + # audio_data 是 float32 base64(24kHz mono)→ PCSpeaker(也是 24kHz float32) + import base64 as _b64 + pcm = np.frombuffer(_b64.b64decode(audio_b64), dtype=np.float32) + # block_and_flush 之后 PCSpeaker.blocked=True,enqueue 会被丢;先 resume 解除 + await speaker.resume() + await speaker.enqueue(pcm, generation=0) + LOG.info("[强制措施] 念提示: %r (%d samples, %.2fs)", + hint_text, pcm.size, pcm.size / float(sr)) + return True + except Exception as e: + LOG.warning("[强制措施] 念提示失败: %s", e) + return False + + +# ============================================================ +# ESP32 音频输入:PC 主动连 ESP32 的 /ws_audio_v2,收 int16 PCM +# (摘自 demo_esp32_duplex_0703 的 esp32_audio_reader,去掉 ring/live_rec, +# 直接把每包音频喂给 harness 骨架的 audio_queue + harness.send_audio) +# ============================================================ +async def esp32_audio_reader( + host: str, + port: int, + manager: GatewaySessionManager, + harness: HarnessClient, + audio_queue: DropOldestAudioQueue, + audio_mirror: AudioMirrorChunker, + stats: RuntimeStats, + input_gain: float, + stop_evt: asyncio.Event, + probe=None, + live_rec=None, +) -> None: + url = f"ws://{host}:{port}/ws_audio_v2" + LOG.info("[ESP32] audio WS: %s", url) + backoff = 1.0 + last_log = time.monotonic() + + while not stop_evt.is_set(): + try: + async with aiohttp.ClientSession() as session: + async with session.ws_connect(url, heartbeat=30, max_msg_size=0) as ws: + LOG.info("[ESP32] audio WS connected") + backoff = 1.0 + stats.audio_clients = 1 + async for msg in ws: + if stop_evt.is_set(): + break + if msg.type != aiohttp.WSMsgType.BINARY: + if msg.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + break + continue + data = msg.data + if len(data) < ESP32_PKT_HDR: + continue + # 固件包头: seq(4) ts_ms(4) n_samples(2) reserved(2) + # 注意: 第4字段是 reserved(pad),不是丢包数;真丢包用 seq 跳变推断 + seq, ts_ms, n_samples, reserved = struct.unpack(" 0.0: + stats.non_silent_audio_packets += 1 + amplified = apply_pcm16_gain(raw, input_gain) + audio_queue.put_nowait(amplified) # -> gateway session + for frame in audio_mirror.feed(amplified): + await harness.send_audio(frame) # -> 8021 ASR 镜像 + # -o record:录 user 音(原始 samples,未放大) + if live_rec is not None: + try: + live_rec.feed_user_raw(samples) + except Exception: + pass + + if probe is not None: + probe.mark_audio(seq, n_samples, packet_rms) + + now = time.monotonic() + if now - last_log >= 5.0: + LOG.info( + "[ESP32] rx=%d pkts seq=%d ts=%d rsv=%d rms=%.4f", + stats.audio_packets, seq, ts_ms, reserved, stats.audio_rms, + ) + last_log = now + except asyncio.CancelledError: + raise + except (aiohttp.ClientError, asyncio.TimeoutError, OSError) as e: + LOG.warning("[ESP32] audio WS error: %s, retry in %.1fs", e, backoff) + finally: + stats.audio_clients = 0 + if not stop_evt.is_set(): + try: + await asyncio.wait_for(stop_evt.wait(), timeout=backoff) + except asyncio.TimeoutError: + pass + backoff = min(backoff * 2, 10.0) + + LOG.info("[ESP32] audio reader stopped") + + +# ============================================================ +# rerun 音频 reader:读 live_user.wav,按 40ms 包喂 audio_queue + harness +# (移植自 rerun_source.local_pcm_reader,下游从 ring 改为 esp32 的 +# audio_queue + harness,其余节奏/回放逻辑一致) +# ============================================================ +async def rerun_audio_reader( + session_dir: str, + manager: GatewaySessionManager, + harness: HarnessClient, + audio_queue: DropOldestAudioQueue, + audio_mirror: AudioMirrorChunker, + stats: RuntimeStats, + input_gain: float, + stop_evt: asyncio.Event, + speed: float = 1.0, + live_rec=None, + ready_evt: Optional[asyncio.Event] = None, + replay_t0=None, + hard_stop: Optional[asyncio.Event] = None, + done_evt: Optional[asyncio.Event] = None, +) -> None: + if hard_stop is None: + hard_stop = stop_evt + # 等 duplex session 就绪再推,否则排队期间的音频全丢(见 _wait_gateway_ready) + if ready_evt is not None: + await ready_evt.wait() + import wave as _wave + wav_path = os.path.join(session_dir, "live_user.wav") + if not os.path.isfile(wav_path): + LOG.error("[RERUN] live_user.wav 不存在: %s", wav_path) + stop_evt.set() + return + with _wave.open(wav_path, "rb") as w: + sr_in = w.getframerate() + pcm_i16 = np.frombuffer(w.readframes(w.getnframes()), dtype=np.int16) + _SR = 16000 + _PKT = 640 # 40ms @16k + total = pcm_i16.size + LOG.info("[RERUN] audio: %s samples=%d dur=%.2fs sr=%d", + wav_path, total, total / _SR, sr_in) + + packet_interval = (_PKT / _SR) / max(speed, 0.01) + ts_ms = 0 + cursor = 0 + pkt = 0 + # next_tick 必须是"本函数真正开始推包的那一刻"。 + # 曾经这里写成 replay_t0()(就绪门放行的时刻),但那之后还要经过任务调度、 + # 读 wav、打日志,等跑到循环里时 next_tick 已经是过去时刻 → + # sleep_for 恒为负 → 每轮都不 sleep → 564 个包在几十毫秒内全灌进 audio_queue + # → 队列容量 96、DropOldest 把开头的提问全丢了,模型只听到最后 3.8 秒的尾音。 + # (stats 里的 audio=25.0pps 统计的是"推进队列"的数量,正好掩盖了这个问题。) + # 图那边按 frames.jsonl 的 t 等待、以 replay_t0 为零点,两边起点差几十毫秒, + # 对 1s 粒度的 chunk 没有影响。 + next_tick = time.monotonic() + # 只受 hard_stop 控制,不再被 stop_evt 掐断。 + # 原来是 `while cursor < total and not stop_evt.is_set()`: + # 图那条路径放完图会 set stop_evt,而素材的图轮数常少于音频秒数 + # (drugbox 16 轮图 vs 22.5s 音频)→ 图先放完就把音频推送掐了, + # 后半段提问根本没进模型。两条流应各自跑完自己的。 + while cursor < total and not hard_stop.is_set(): + end = min(cursor + _PKT, total) + chunk_i16 = pcm_i16[cursor:end] + cursor = end + pkt += 1 + raw = chunk_i16.astype(" 0: + # 这里等的是 hard_stop,不是 stop_evt。 + # 之前 while 条件改成了 hard_stop,但循环体里仍 await stop_evt 并 break, + # 等于没改——图放完 set stop_evt 照样把音频推送掐断。 + try: + await asyncio.wait_for(hard_stop.wait(), timeout=sleep_for) + break + except asyncio.TimeoutError: + pass + + if done_evt is not None: + done_evt.set() + LOG.info("[RERUN] audio 推完 %d 包 (%.2fs),等模型说完…", pkt, ts_ms / 1000.0) + # 音频推完不立即 stop。注意:这里**不能** await stop_evt 就 break —— + # 图那条路径放完图也会 set stop_evt,两条互相踩,结果谁先到谁把另一条掐了 + # (图少的素材尤其明显:图很快放完 → 直接收工 → 模型话没说完)。 + # 这里独立按时间等,让模型有机会把最后一句说完;真正的结束由 image_loop + # 的静默判据 + 尾巴决定,或走这里的兜底。 + waited = 0.0 + while waited < 120.0: + if stop_evt.is_set(): + # 另一条已判定结束,再宽限一小段让 TTS 播完 + await asyncio.sleep(2.0) + break + await asyncio.sleep(0.5) + waited += 0.5 + if not stop_evt.is_set(): + stop_evt.set() + LOG.info("[RERUN] audio reader stopped") + + +# ============================================================ +# rerun 图像 loop:用 LocalImageSource 按 chunk 顺序读 best 图,直接喂模型 +# (-o rerun 不重跑 funnel——best 已是筛过的,直接 send_frame) +# ============================================================ +async def rerun_image_loop( + session_dir: str, + latest_frame, + harness: HarnessClient, + stats: RuntimeStats, + interval_s: float, + stop_evt: asyncio.Event, + web_ui=None, + live_rec=None, + ready_evt: Optional[asyncio.Event] = None, + replay_t0=None, + done_evt: Optional[asyncio.Event] = None, + peer_done: Optional[asyncio.Event] = None, + speaker=None, + sent_tracker=None, + tail_wait_s: float = 30.0, +) -> None: + if ready_evt is not None: + await ready_evt.wait() + try: + from .rerun_source import LocalImageSource + except Exception as e: + LOG.error("[RERUN] 无法导入 LocalImageSource: %s", e) + stop_evt.set() + return + from pathlib import Path as _Path + try: + src = LocalImageSource(_Path(session_dir)) + except Exception as e: + LOG.error("[RERUN] LocalImageSource 初始化失败: %s", e) + stop_evt.set() + return + # 按 chunk_idx 升序回放 + idxs = sorted(src._map.keys()) + LOG.info("[RERUN] image loop: %d 帧待回放", len(idxs)) + for cidx in idxs: + if stop_evt.is_set(): + break + jpeg = await src.capture(cidx) + if jpeg: + ts = now_ms() + latest_frame.set(jpeg, ts) + stats.image_count += 1 + await harness.send_frame(jpeg, latest_frame.sequence, ts) + LOG.info("[RERUN] send frame idx=%d (%d bytes)", cidx, len(jpeg)) + _emit_chunk_img(web_ui, jpeg, latest_frame.sequence, True) + if live_rec is not None: + try: + live_rec.on_frame(jpeg, latest_frame.sequence) + except Exception: + pass + try: + await asyncio.wait_for(stop_evt.wait(), timeout=interval_s) + break + except asyncio.TimeoutError: + pass + LOG.info("[RERUN] image loop 回放完毕") + if done_evt is not None: + done_evt.set() + # -o rerun 的收尾。之前这条路径图放完就什么都不做,结束全靠 + # rerun_audio_reader 里 `while waited < 120.0` 的兜底干等两分钟 + #(日志表现:音频推完后一串 audio=0.0pps 的 STATS,两分钟才退), + # 而且 --rerun-tail-wait-s 对它无效。 + # 判定与 esp32_image_loop 保持一致:先等音频也推完,再看模型说完没有 + #(队列空 且 不在 speak,连续保持 2s 才算),最后加 2s 尾巴。 + if peer_done is not None and not peer_done.is_set(): + LOG.info("[RERUN] 图放完,等音频推完…") + try: + await asyncio.wait_for(peer_done.wait(), timeout=180.0) + except asyncio.TimeoutError: + LOG.warning("[RERUN] 等音频超时") + _QUIET_HOLD_S, _TAIL_S = 2.0, 2.0 + _quiet_since = None + _deadline = time.monotonic() + tail_wait_s + while time.monotonic() < _deadline and not stop_evt.is_set(): + try: + pending = speaker.pending_ms() if speaker is not None else 0.0 + except Exception: + pending = 0.0 + speaking = bool(getattr(sent_tracker, "speaking", False)) if sent_tracker else False + if pending <= 50 and not speaking: + if _quiet_since is None: + _quiet_since = time.monotonic() + elif time.monotonic() - _quiet_since >= _QUIET_HOLD_S: + break + else: + _quiet_since = None + await asyncio.sleep(0.25) + try: + await asyncio.wait_for(stop_evt.wait(), timeout=_TAIL_S) + except asyncio.TimeoutError: + pass + LOG.info("[RERUN] 结束(静默保持%.1fs + 尾巴%.1fs)", _QUIET_HOLD_S, _TAIL_S) + stop_evt.set() + + +# ============================================================ +# ESP32 图像输入:TCP 5000 持久连接,请求-响应取裸 JPEG +# (摘自 demo_esp32_duplex_0703 的 TcpImageClient,接口不变) +# 帧头(20B 小端): magic(4) frame_id(4) w(2) h(2) fmt(1) reserved(3) len(4) +# ============================================================ +_ROTATE_MAP = None + + +def _rotate_jpeg(jpeg: bytes, deg: int) -> bytes: + """把相机原始帧按顺时针 deg 转正。deg ∈ {0,90,180,270},0 直接原样返回。 + + 为什么要在这里转:眼镜的摄像头是**物理侧装/倒装**的(devices.json 的 rotate), + 出来的帧本身就是歪的。不转正的话,漏斗的方向分类器会把"相机侧装" + 误判成"用户把盒子拿反了"并提示用户翻转 —— 用户翻了反而更歪。 + 取景截断的上下左右语义、_PAN_HINT 的"向上看/向下看"也全都会反。 + 所以必须在**进漏斗之前**转,转法照搬 demo_esp32_duplex_0703。 + + 注意 PIL 按逆时针算:顺时针 90° 要用 ROTATE_270。 + """ + if not deg or not jpeg: + return jpeg + global _ROTATE_MAP + try: + from PIL import Image + import io + except Exception: + return jpeg + if _ROTATE_MAP is None: + _ROTATE_MAP = { + 90: Image.Transpose.ROTATE_270, # 顺时针 90° = PIL 的 ROTATE_270 + 180: Image.Transpose.ROTATE_180, + 270: Image.Transpose.ROTATE_90, + } + op = _ROTATE_MAP.get(int(deg) % 360) + if op is None: + return jpeg + try: + im = Image.open(io.BytesIO(jpeg)) + im = im.transpose(op) + buf = io.BytesIO() + im.save(buf, format="JPEG", quality=92) + return buf.getvalue() + except Exception as e: + LOG.warning("[ROTATE] 转正失败(%d°),用原图: %r", deg, e) + return jpeg + + +class TcpImageClient: + def __init__(self, host: str, port: int = 5000, rotate: int = 0): + self.host = host + self.port = port + self.rotate = int(rotate) % 360 + self._reader: Optional[asyncio.StreamReader] = None + self._writer: Optional[asyncio.StreamWriter] = None + self._lock = asyncio.Lock() + + async def _ensure_conn(self, timeout_s: float) -> bool: + if self._reader is not None and self._writer is not None and not self._writer.is_closing(): + return True + try: + self._reader, self._writer = await asyncio.wait_for( + asyncio.open_connection(self.host, self.port), timeout=timeout_s) + sock = self._writer.get_extra_info("socket") + if sock is not None: + import socket as _s + sock.setsockopt(_s.IPPROTO_TCP, _s.TCP_NODELAY, 1) + LOG.info("[TCP-IMG] connected to %s:%d", self.host, self.port) + return True + except Exception as e: + LOG.debug("[TCP-IMG] connect failed: %s", e) + await self._close() + return False + + async def _close(self) -> None: + if self._writer is not None: + try: + self._writer.close() + except Exception: + pass + self._reader = None + self._writer = None + + async def capture(self, timeout_s: float = 1.0) -> Optional[bytes]: + async with self._lock: + if not await self._ensure_conn(timeout_s): + return None + try: + self._writer.write(b"C") + await self._writer.drain() + hdr = await asyncio.wait_for(self._reader.readexactly(20), timeout=timeout_s) + magic, frame_id, w, h = struct.unpack_from(" 4 * 1024 * 1024: + LOG.warning("[TCP-IMG] insane len=%d, reconnect", length) + await self._close() + return None + data = await asyncio.wait_for(self._reader.readexactly(length), timeout=timeout_s) + # 转正后再交给上层:latest_frame / 漏斗 / 录制拿到的都是正图, + # rerun 时不必再转(否则会转两次)。 + return _rotate_jpeg(bytes(data), self.rotate) + except asyncio.CancelledError: + raise + except Exception as e: + LOG.warning("[TCP-IMG] capture failed: %r, reconnect", e) + await self._close() + return None + + +# ============================================================ +# funnel rerun:把录制的整簇多帧当图源,复用 esp32_image_loop 重跑漏斗+播报 +# RecordedImageClient.capture() 按 frames.jsonl 每轮整簇顺序吐帧, +# funnel.run_once 调 N 次凑一簇 → 重判 send/reject → 播报/标点保护,逻辑全复用。 +# ============================================================ +class RecordedImageClient: + def __init__(self, session_dir: str, n_frames: int, no_funnel: bool = False): + import json as _json + self.dir = session_dir + self.images_dir = os.path.join(session_dir, "images") + self.n_frames = max(1, int(n_frames)) + self._rounds = [] # 每轮: [jpg_bytes, ...] + fr_path = os.path.join(session_dir, "frames.jsonl") + self._round_names = [] # 每轮的帧文件名(供 record 复用) + self._round_t = [] # 每轮录制时刻 t(秒),用于按原始时间轴回放 + with open(fr_path, encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line: + continue + try: + rec = _json.loads(line) + except Exception: + continue + names = rec.get("frames") or [] + jpgs = [] + keep_names = [] + for nm in names: + p = os.path.join(self.images_dir, nm) + if os.path.isfile(p): + with open(p, "rb") as fp: + jpgs.append(fp.read()) + keep_names.append(nm) + if jpgs: + self._rounds.append(jpgs) + self._round_names.append(keep_names) + self._round_t.append(float(rec.get("t", len(self._rounds) - 1))) + LOG.info("[RERUN-IMG] 载入 %d 轮,每轮≤%d帧%s", + len(self._rounds), self.n_frames, + "(无漏斗:每轮取中间张代表帧)" if no_funnel else "(funnel:整簇逐帧)") + self._round_i = 0 + self._frame_i = 0 + self._no_funnel = no_funnel + self.exhausted = False + self._t0 = None # 回放起点(优先用外部注入的统一零点) + self.replay_t0 = None # 由 runtime 注入,与音频共用 + # 整份 record 一张图都没有(图像链路当时丢了 / 手动删空 images): + # 这是有效素材(对照:无漏斗→模型 0 图编场景;有漏斗→全程 reject no_frames)。 + # 此时不能置 exhausted,否则会被当成"图放完了"秒退;让音频推完来结束整场。 + self._no_images = (len(self._rounds) == 0) + if self._no_images: + LOG.info("[RERUN-IMG] 这份 record 没有可用图像 → 全程无图回放" + "(由音频长度决定结束)") + + def current_round_cluster(self): + """返回当前轮的整簇 (jpg_list, name_list),供无漏斗 rerun 存 record 用。""" + i = self._round_i + if 0 <= i < len(self._rounds): + return self._rounds[i], self._round_names[i] + return [], [] + + async def _wait_round_time(self): + """按录制时刻回放:等到墙钟走到本轮的 t 再吐这一轮的帧。 + + 录制时每轮耗时并不均匀(对焦轮 ~1.9s、reject 播报轮 2.3~4s),若 rerun 按 + image_loop 的固定 interval_s 匀速吃图,就会以数倍速把图吃光(实测 33s 的录制 + 11s 就放完)。音频是按真实时长回放的,用 frames.jsonl 的 t 对齐,两边同一条 + 时间轴。 + """ + if self._t0 is None: + # 优先用统一回放零点(与音频同源);没有才退回"第一次 capture 那一刻" + self._t0 = self.replay_t0 if self.replay_t0 is not None else time.monotonic() + i = self._round_i + if 0 <= i < len(self._round_t): + target = self._round_t[i] + delay = target - (time.monotonic() - self._t0) + if delay > 0: + await asyncio.sleep(min(delay, 10.0)) + + async def capture(self, timeout_s: float = 1.0): + if self._no_images: + # 全程无图:一直返回 None,但不置 exhausted(不提前结束)。 + # 有漏斗 → run_once 拿到 0 帧 → reject(no_frames) → 播"没有拿到画面"; + # 无漏斗 → 不 send → 模型 0 图 → 暴露编场景。 + await asyncio.sleep(0.05) + return None + if self._round_i >= len(self._rounds): + self.exhausted = True + return None + # 只在一轮的第一帧上等待,同一轮内的多帧连续吐(模拟原始高频抓帧) + if self._frame_i == 0: + await self._wait_round_time() + rnd = self._rounds[self._round_i] + if self._no_funnel: + # 无漏斗(对照组):每轮取一张代表帧(中间张,模拟"随手抓一张就发"), + # 每次 capture 直接进入下一轮。含模糊图会照发 → 暴露幻觉。 + jpg = rnd[len(rnd) // 2] + self._round_i += 1 + return jpg + # funnel:一帧帧吐整簇,供 run_once 调 N 次凑一簇 + jpg = rnd[self._frame_i % len(rnd)] + self._frame_i += 1 + if self._frame_i >= self.n_frames: + self._frame_i = 0 + self._round_i += 1 + return jpg + + async def _close(self): + pass + + +# ============================================================ +# ESP32 图像轮询循环:定时用 TCP 取图 -> latest_frame + harness.send_frame +# ============================================================ +async def esp32_image_loop( + client: TcpImageClient, + latest_frame: LatestFrame, + harness: HarnessClient, + stats: RuntimeStats, + interval_s: float, + timeout_s: float, + stop_evt: asyncio.Event, + probe=None, + funnel=None, + recorder=None, + speaker=None, + gateway_host: str = "127.0.0.1", + gateway_port: int = 8040, + ssl_ctx=None, + force_measure: bool = False, + manager=None, + reject_wav_dir: str = "assets/reject_wav", + sent_tracker=None, + live_rec=None, + web_ui=None, + ready_evt: Optional[asyncio.Event] = None, + tail_wait_s: float = 30.0, + no_reject: bool = False, + peer_done: Optional[asyncio.Event] = None, + done_evt: Optional[asyncio.Event] = None, +) -> None: + if ready_evt is not None: + await ready_evt.wait() + LOG.info("[ESP32] image loop start (interval=%.2fs, funnel=%s)", + interval_s, "on" if funnel else "off") + _last_grab_mono = None + + # ── 强制措施状态 ── + _funnel_stopped = False # 是否已发过 funnel.stop(在停住态,等好图 resume) + _last_hint_mono = 0.0 # 上次念提示的时刻(节流用) + _HINT_THROTTLE_S = 5.0 # 同类连续 reject 的念提示节流间隔 + _pending_reject = None # 标点保护:挂起中的 reject(等标点/超时再复查) + # ── 「持续坏」检测:3s 窗口内 reject≥2 → 判定输出基于坏图=幻觉,直接打断+压制 ── + # 覆盖"错错错对"场景(前半也错,标点保护不适用)。窗口单位=判定/chunk(每≈1s)。 + # 依据:模型拿图→输出约 1-1.5s;2s 都坏则幻觉必已在输出,必须闭嘴。 + _judge_history = [] # 最近判定时刻+是否reject: [(mono, is_reject), ...] + _WINDOW_S = 3.0 # 窗口长度 + _BAD_THRESH = 2 # 窗口内 reject≥此 → 持续坏,直接打断(跳过标点保护) + # _funnel_active:念提示临界区标志(预留给兜底:念提示那几秒真人喊话的处理) + # TODO(兜底,下次实现): 念提示期间若收到真人 STOP/RESUME/RESET, + # 先掐掉提示音(speaker.block_and_flush)+清此标志,再执行真人指令,避免撞车。 + # 当前只占位,不实现逻辑。 + _funnel_active = False # noqa: F841 (预留) + + async def _capture_one(): + return await client.capture(timeout_s=timeout_s) + + while not stop_evt.is_set(): + t0 = time.monotonic() + # funnel rerun:录制的整簇多帧放完了 → 优雅结束(不报 no_frames) + if getattr(client, "exhausted", False): + LOG.info("[FUNNEL-RERUN] 录制图已放完") + # 图轮数常少于音频秒数(drugbox 16 轮 vs 22.5s),不能图一放完就收工, + # 否则后半段音频(可能正含提问)根本没推给模型。先等音频也推完。 + if peer_done is not None and not peer_done.is_set(): + LOG.info("[FUNNEL-RERUN] 等音频推完…") + try: + await asyncio.wait_for(peer_done.wait(), timeout=180.0) + except asyncio.TimeoutError: + LOG.warning("[FUNNEL-RERUN] 等音频超时") + LOG.info("[FUNNEL-RERUN] 两条流都完事,等模型说完后结束") + # 等模型把话说完再 stop。判据不能只看"队列空"——模型是流式产出的, + # 某一瞬间队列排空只是"下一段还没到",不代表这轮结束(图少的素材尤其明显: + # 图很快放完,恰好撞上队列空,就把还没说完的话掐了)。 + # 改为:队列必须连续 _QUIET_HOLD_S 保持空,且 sent_tracker 不在 speak 中, + # 再加一段固定尾巴,给最后一句 TTS 留出播放时间。 + _QUIET_HOLD_S = 2.0 + _TAIL_S = 2.0 + _quiet_since = None + _deadline = time.monotonic() + tail_wait_s + while time.monotonic() < _deadline and not stop_evt.is_set(): + try: + pending = speaker.pending_ms() if speaker is not None else 0.0 + except Exception: + pending = 0.0 + speaking = False + if sent_tracker is not None: + speaking = bool(getattr(sent_tracker, "speaking", False)) + if pending <= 50 and not speaking: + if _quiet_since is None: + _quiet_since = time.monotonic() + elif time.monotonic() - _quiet_since >= _QUIET_HOLD_S: + break + else: + _quiet_since = None + await asyncio.sleep(0.25) + # 尾巴:让最后一句 TTS 播完,也给模型一点补充的机会 + try: + await asyncio.wait_for(stop_evt.wait(), timeout=_TAIL_S) + except asyncio.TimeoutError: + pass + LOG.info("[FUNNEL-RERUN] 结束(静默保持%.1fs + 尾巴%.1fs)", + _QUIET_HOLD_S, _TAIL_S) + stop_evt.set() + break + try: + if funnel is None: + # ── 无漏斗:取 1 帧直发(含模糊图,暴露幻觉)── + # record 仍存整簇(mp4 用全部采集帧,和有漏斗一致,只是无 reject 标注) + cluster_jpgs, cluster_names = ([], []) + if hasattr(client, "current_round_cluster"): + cluster_jpgs, cluster_names = client.current_round_cluster() + jpeg = await client.capture(timeout_s=timeout_s) + grab_ms = (time.monotonic() - t0) * 1000.0 + if jpeg: + ts = now_ms() + latest_frame.set(jpeg, ts) + stats.image_count += 1 + await harness.send_frame(jpeg, latest_frame.sequence, ts) + _emit_chunk_img(web_ui, jpeg, latest_frame.sequence, True) + if probe is not None: + since_last = (t0 - _last_grab_mono) * 1000.0 if _last_grab_mono else 0.0 + probe.mark_grab(latest_frame.sequence, grab_ms, len(jpeg), since_last) + _last_grab_mono = t0 + # 存 record(无漏斗:send=True 无 reason)。 + # rerun 时图源是 RecordedImageClient,有 current_round_cluster(), + # 能拿到整簇;**实机时图源是 TcpImageClient,没有这个方法**, + # cluster_jpgs 恒为空 —— 原来写 `and cluster_jpgs` 就把实机的 + # 录制整个跳过了(实测 frames.jsonl 0 rounds、images/ 空)。 + # 实机 no_funnel 本来就是每轮一张图,拿不到整簇就用这一帧当一轮。 + if live_rec is not None: + _frames = cluster_jpgs if cluster_jpgs else [jpeg] + _dec = type("D", (), {"frames": _frames, + "best_index": len(_frames) // 2, + "send": True, "reason": ""})() + try: + await asyncio.to_thread( + live_rec.on_funnel_round, _dec, latest_frame.sequence) + # best 图也存一份(events.jsonl + img_*.jpg,供 -o rerun) + await asyncio.to_thread( + live_rec.on_frame, jpeg, latest_frame.sequence) + except Exception as e: + LOG.warning("[LIVE] on_funnel_round(no-funnel) err: %s", e) + else: + # ── 有漏斗:一轮判定,合格才 send_frame ── + decision = await funnel.run_once(_capture_one) + # 统一 record:每轮整簇多帧 + 判定 → live_rec(供三种 rerun)。 + # 必须放在所有分支之前:持续坏分支末尾有 continue,放在最后会把 + # 触发压制的那些轮整簇漏录(实测 42s 只落下 8 轮)。录制是原始素材, + # 不该因为走了哪条处理路径而缺失。 + if live_rec is not None: + try: + await asyncio.to_thread( + live_rec.on_funnel_round, decision, latest_frame.sequence) + except Exception as e: + LOG.warning("[LIVE] on_funnel_round err: %s", e) + grab_ms = decision.timings.get("grab_ms", 0.0) + async def _do_reject_interrupt(reason): + """真正执行打断:停 duplex → 播 wav → 恢复。""" + wav_pcm = _load_reject_wav(reject_wav_dir, reason) + if wav_pcm is None: + LOG.warning("[强制措施] 无 %s.wav,跳过播报", reason) + return + try: + await harness.send({"type": "funnel.stop", "reason": reason}) + LOG.info("[强制措施] funnel.stop 已发 (%s)", reason) + except Exception as e: + LOG.warning("[强制措施] funnel.stop 失败: %s", e) + await asyncio.sleep(0.35) # 等 STOP 经 8021→rokid→block_and_flush + try: + await speaker.resume() + await speaker.enqueue(wav_pcm, generation=0) + dur = len(wav_pcm) / 24000.0 + LOG.info("[强制措施] 播 reject wav: %s (%.2fs)", reason, dur) + if live_rec is not None: + live_rec.log_event("HINT", f"{reason} ({dur:.2f}s)") + await asyncio.sleep(dur + 0.2) + except Exception as e: + LOG.warning("[强制措施] 播 wav 失败: %s", e) + try: + await harness.send({"type": "funnel.resume", "reason": "hint_done"}) + LOG.info("[强制措施] funnel.resume 已发(提示播完)") + except Exception as e: + LOG.warning("[强制措施] funnel.resume 失败: %s", e) + + # ── 消融用:选 best 但永远放行(关闭工作③的拒绝/播报)── + # 用途:把"多帧选 best"(工作②)的收益从"拒绝坏图"(工作③)里剥出来。 + # 对照 bare(每轮取中间帧直发),本 arm 每轮取 best 直发, + # 下游模型侧完全一致,差异只来自选图。 + if no_reject: + _b = decision.best + if _b: + ts = now_ms() + latest_frame.set(_b, ts) + stats.image_count += 1 + await harness.send_frame(_b, latest_frame.sequence, ts) + _emit_chunk_img(web_ui, _b, latest_frame.sequence, True) + if live_rec is not None: + try: + await asyncio.to_thread( + live_rec.on_frame, _b, latest_frame.sequence) + except Exception as e: + LOG.warning("[LIVE] on_frame err: %s", e) + LOG.info("[漏斗-放行] best (原判定=%s)", decision.reason) + # 消融 arm 不执行拒绝,但**判别结果要留痕**: + # 这一轮漏斗本来会不会拦、拦的理由是什么,是分析判别倾向的依据。 + if live_rec is not None and not decision.send: + live_rec.log_event( + "WOULD-REJECT", + f"{decision.reason} {decision.hint or ''}") + else: + LOG.info("[漏斗-放行] 本轮无 best(%s),跳过", decision.reason) + elapsed = time.monotonic() - t0 + try: + await asyncio.wait_for(stop_evt.wait(), + timeout=max(0.0, interval_s - elapsed)) + except asyncio.TimeoutError: + pass + continue + + # ── 「持续坏」检测(优先于标点保护)── + # 3s 窗口内"真坏"reject≥2 → 输出基于坏图=幻觉。此时不走标点保护 + # (前半也错,不值得保护),直接触发"停→播提示→恢复"。 + # need_focus 不算坏:它是系统正在对焦(run_once 已发 /reg 重抓), + # 属于内部自愈,不是用户造成的持续坏,算进去会误判、干扰对焦流程。 + # "真坏" = reject 且 reason 不是 need_focus(severe_shake/unstable/ + # too_dark/orient 等,要用户动手的)。 + _now = time.monotonic() + _is_real_bad = (not decision.send) and (decision.reason != "need_focus") + _judge_history.append((_now, _is_real_bad)) + _judge_history[:] = [(t, r) for (t, r) in _judge_history + if _now - t <= _WINDOW_S] + _bad_in_window = sum(1 for (_t, r) in _judge_history if r) + + if _bad_in_window >= _BAD_THRESH and _is_real_bad: + _pending_reject = None # 持续坏优先,取消标点保护挂起 + # 到这里必是"真坏"(severe_shake/unstable/too_dark/orient)。 + # 直接触发完整"停→播提示→恢复"(复用 _do_reject_interrupt, + # 停模型输出不杀死、播完恢复)。耗时≈播报时长,天然间隔。 + LOG.info("[持续坏] 3s内%d次真坏reject,打断+播提示(停→播→恢复)", + _bad_in_window) + if live_rec is not None: + live_rec.log_event( + "PERSIST-BAD", + f"3s内{_bad_in_window}次真坏 → 打断 ({decision.reason})") + await _do_reject_interrupt(decision.reason) + elapsed = time.monotonic() - t0 + try: + await asyncio.wait_for(stop_evt.wait(), + timeout=max(0.0, interval_s - elapsed)) + except asyncio.TimeoutError: + pass + continue + + # ── 「标点保护」核心:突发 reject 不立即打断,保护当前段语音播放到 + # 下一个句末标点,到标点那一刻复查当时判定;仍 reject 才打断,否则无事。 + # 挂起期间的 send/reject 都不算数,只看"到标点那一刻"的判定。 + # (snapshot 记标点序号,boundary_reached 判断新标点+其语音已播完) + if force_measure and speaker is not None and _pending_reject is not None: + # 正在保护中:只判断"是否到标点(语音播完)或超时",到了才用当时判定复查 + now_mono = time.monotonic() + reached = (sent_tracker is not None + and sent_tracker.boundary_reached( + _pending_reject["snap"], speaker)) + timed_out = (now_mono - _pending_reject["since"]) >= 1.5 + if reached or timed_out: + # 到标点/超时 → 复查此刻判定 + if decision.send: + LOG.info("[标点保护] %s,此刻已恢复(send),无事发生", + "到标点" if reached else "超时1.5s") + _pending_reject = None + elif decision.reason == "need_focus": + _pending_reject = None # 复查是对焦,静默 + else: + # 仍 reject → 打断(受节流约束) + LOG.info("[标点保护] %s,仍 reject(%s),打断", + "到标点" if reached else "超时1.5s", decision.reason) + if now_mono - _last_hint_mono >= _HINT_THROTTLE_S: + _last_hint_mono = now_mono + _pending_reject = None + await _do_reject_interrupt(decision.reason) + else: + _pending_reject = None # 被节流 + + if decision.send and decision.best: + ts = now_ms() + latest_frame.set(decision.best, ts) + stats.image_count += 1 + await harness.send_frame(decision.best, latest_frame.sequence, ts) + LOG.info("[漏斗] send (%s)", decision.reason) + _emit_chunk_img(web_ui, decision.best, latest_frame.sequence, True) + # -o record:只录真发送给模型的 best 图(chunk_idx = sequence) + if live_rec is not None: + try: + await asyncio.to_thread( + live_rec.on_frame, decision.best, latest_frame.sequence) + except Exception as e: + LOG.warning("[LIVE] on_frame err: %s", e) + # 注意:send 不清 _pending_reject,保护期只看到标点那一刻 + else: + LOG.info("[漏斗] reject(%s) -> hint: %s", + decision.reason, decision.hint) + if live_rec is not None: + live_rec.log_event("REJECT", f"{decision.reason} {decision.hint or ''}") + if force_measure and speaker is not None and decision.reason != "need_focus": + now_mono = time.monotonic() + if _pending_reject is not None: + pass # 已在保护中,上面已处理,不重复挂起 + elif sent_tracker is not None and sent_tracker.speaking: + # 模型正念字:挂起,保护到下一个标点再复查 + _pending_reject = { + "since": now_mono, + "reason": decision.reason, + "snap": sent_tracker.snapshot(), + } + LOG.info("[标点保护] speak中,reject(%s)挂起,等语音播到标点或超时1.5s", + decision.reason) + else: + # 模型没念字(listen/静默)→ 无需保护,直接打断(受节流) + if now_mono - _last_hint_mono >= _HINT_THROTTLE_S: + _last_hint_mono = now_mono + await _do_reject_interrupt(decision.reason) + if probe is not None: + since_last = (t0 - _last_grab_mono) * 1000.0 if _last_grab_mono else 0.0 + jb = len(decision.best) if decision.best else 0 + tm = decision.timings + probe.mark_grab( + latest_frame.sequence, grab_ms, jb, since_last, + reason=decision.reason, + judge_ms=tm.get("judge_ms"), + af_ms=tm.get("af_ms"), + n_frames=tm.get("n_frames"), + ) + _last_grab_mono = t0 + except Exception as e: + LOG.warning("[ESP32] image loop error: %s", e, exc_info=True) + # 控制取图节奏 + elapsed = time.monotonic() - t0 + try: + await asyncio.wait_for(stop_evt.wait(), timeout=max(0.0, interval_s - elapsed)) + except asyncio.TimeoutError: + pass + LOG.info("[ESP32] image loop stopped") + + +# ============================================================ +# ESP32 Runtime:继承 rokid 的 PhaseBRokidRuntime,复用全部 harness 骨架, +# 只覆盖 start():不起 web server,改起两个 ESP32 主动拉取 task。 +# ============================================================ +from .rokid_runtime import PhaseBRokidRuntime + + +def _insecure_ssl_for_wss(url: str) -> Optional[ssl.SSLContext]: + """wss:// 且自签名证书时,返回一个不校验证书的 ssl context;ws:// 返回 None。 + + 与 rokid GatewayDuplexSession._ssl_context 同款做法(check_hostname=False, + verify_mode=CERT_NONE),用于连本地自签名的 8021。""" + if not url.lower().startswith("wss://"): + return None + ctx = ssl.create_default_context() + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + return ctx + + +class TlsHarnessClient(HarnessClient): + """与 HarnessClient 完全一致,仅在 ws_connect 时对 wss:// 传入自签名 ssl。 + + 覆盖 run():逐行照抄父类,唯一区别是 ws_connect 多了 ssl= 参数。""" + + async def run(self) -> None: + ssl_ctx = _insecure_ssl_for_wss(self.url) + while not self._stop.is_set(): + try: + async with aiohttp.ClientSession() as client: + async with client.ws_connect( + self.url, heartbeat=30, max_msg_size=0, ssl=ssl_ctx + ) as ws: + self.ws = ws + self.connected = True + LOG.info("Harness connected: %s", self.url) + async for message in ws: + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in ( + aiohttp.WSMsgType.CLOSED, + aiohttp.WSMsgType.ERROR, + ): + break + continue + payload = json.loads(message.data) + message_type = payload.get("type") + if message_type == "harness.ready": + await self.manager.emit_recovery_sync() + elif message_type == "control.intent": + task = asyncio.create_task( + self.manager.handle_control(payload) + ) + self._control_tasks.add(task) + task.add_done_callback(self._control_tasks.discard) + except asyncio.CancelledError: + raise + except Exception as exc: + if not self._stop.is_set(): + LOG.warning("Harness connection failed: %s", exc) + finally: + self.connected = False + self.ws = None + if not self._stop.is_set(): + await asyncio.sleep(self.reconnect_s) + + +class PhaseBEsp32Runtime(PhaseBRokidRuntime): + """ESP32 版 runtime:I/O 从 'PC 起 server 被动收' 换成 'PC 主动拉 ESP32'。 + + __init__ / close / health / _initial_session_loop / _stats_loop 全部继承。 + 仅覆盖 start():把 Rokid 的 web server 换成 esp32_audio_reader + esp32_image_loop。 + """ + + def __init__(self, config, esp32_host, esp32_port, image_tcp_port, + image_interval_s, image_timeout_s, probe=None, + funnel=None, recorder=None, force_measure=False, + gateway_host="127.0.0.1", gateway_port=8040, + reject_wav_dir="assets/reject_wav", + live_record_dir=None, rerun_from=None, + funnel_rerun_from=None, web_ui_port=None, + record_no_media: bool = False, + rerun_tail_wait_s: float = 30.0, + no_reject: bool = False, + rotate: int = 0, **kwargs): + super().__init__(config, **kwargs) + # 用支持自签名 wss 的 harness client 替换父类建好的普通 HarnessClient, + # 并同步更新 manager.harness 引用(发遥测/镜像走同一个)。 + self.harness = TlsHarnessClient( + config.harness_url, + config.harness_client_id, + self.manager, + config.reconnect_s, + ) + self.manager.harness = self.harness + self._esp32_host = esp32_host + self._esp32_port = esp32_port + self._image_tcp_port = image_tcp_port + self._image_interval_s = image_interval_s + self._image_timeout_s = image_timeout_s + self._tcp_img = TcpImageClient(esp32_host, image_tcp_port, + rotate=int(rotate) % 360) + self._stop_evt = asyncio.Event() + self._probe = probe + self._funnel = funnel + self._recorder = recorder + self._force_measure = force_measure + self._reject_wav_dir = reject_wav_dir + self._gateway_host = gateway_host + self._gateway_port = gateway_port + # 念提示走 gateway wss /ws/chat,自签名证书 → 复用同款 insecure ssl + self._chat_ssl = _insecure_ssl_for_wss(f"wss://{gateway_host}:{gateway_port}/ws/chat") + + self._rerun_from = rerun_from + self._funnel_rerun_from = funnel_rerun_from + self._rerun_tail_wait_s = rerun_tail_wait_s + self._no_reject = no_reject + self._rotate = int(rotate) % 360 + self._replay_t0 = None # rerun 统一回放零点(就绪时设) + self._rec_client = None + # 回放两条流各自的完成标志:图轮数常少于音频秒数,谁先完都不能掐死对方 + self._audio_done = asyncio.Event() + self._image_done = asyncio.Event() + # bridge_ui 第一视角(8080)。live/rerun/funnel-rerun 都可推 img_b64。 + self._web_ui = None + if web_ui_port and WebUIServer is not None: + try: + self._web_ui = WebUIServer( + port=web_ui_port, + sessions_root=Path(live_record_dir).parent if live_record_dir + else Path("live_sessions"), + mode_info={"mode": "rerun" if (rerun_from or funnel_rerun_from) + else "live"}, + ) + except Exception as e: + LOG.warning("[UI] WebUIServer 创建失败: %s", e) + self._web_ui = None + # -o record(音+图,只存真发送的 best):和漏斗 record 并存。 + self.live_rec = (LiveRecorder(live_record_dir, no_media=record_no_media) + if live_record_dir else None) + if self.live_rec is not None: + try: + self.live_rec.attach_to_player(self.speaker) # 录 AI 音 + except Exception as e: + LOG.warning("[LIVE] attach_to_player 失败: %s", e) + + # 句子边界追踪器:包装 manager.handle_result,每个模型 chunk 更新句子/语音进度, + # 供 image_loop 的"标点保护"策略读取(reject 时保护当前段到下一个标点再复查)。 + self.sent_tracker = SentenceTracker() + self._turn_printer = TurnPrinter() + self._turn_start_ms = None # 当前 turn 的起点(session 内相对 ms) + _orig_handle_result = self.manager.handle_result + + async def _wrapped_handle_result(session, result): + try: + is_listen = bool(result.get("is_listen")) + text = str(result.get("text") or "") + end_of_turn = bool(result.get("end_of_turn")) + ab64 = str(result.get("audio_data") or "") + audio_ms = 0.0 + if ab64 and not is_listen: + n = len(base64.b64decode(ab64)) // 4 # float32 + audio_ms = n * 1000.0 / 24000.0 + self.sent_tracker.update(text, audio_ms, is_listen) + + # ── 评分用:把 chunk 碎片聚合成整段 turn,落 transcript/subtitles ── + if self.live_rec is not None: + # 先记原始逐 chunk(不依赖 end_of_turn,保证一定有东西可评分) + self.live_rec.log_model_chunk(text, is_listen, end_of_turn, audio_ms) + prev_idx = self._turn_printer.turn_idx + turn_idx_cur, full_text, turn_listen = self._turn_printer.feed( + is_listen, end_of_turn, text) + if text and self._turn_printer.turn_idx > prev_idx: + self._turn_start_ms = self.live_rec.session_ms() + # 只要拿到完整段就落盘(end_of_turn 或 listen/speak 切换冲出的) + if full_text: + end_ms = self.live_rec.session_ms() + 800 # 多挂 0.8s + start_ms = (self._turn_start_ms + if self._turn_start_ms is not None + else max(end_ms - 3000, 0)) + self.live_rec.log_turn_text(turn_idx_cur, full_text, turn_listen) + self.live_rec.log_subtitle( + start_ms=start_ms, end_ms=end_ms, text=full_text, + is_listen=turn_listen, turn_idx=turn_idx_cur) + self._turn_start_ms = None + + # 推模型文字到 bridge_ui 第一视角(type=result) + if self._web_ui is not None and getattr(self._web_ui, "live_clients", None): + asyncio.create_task(self._web_ui.emit({ + "type": "result", + "is_listen": is_listen, + "end_of_turn": end_of_turn, + "text": text, + })) + except Exception: + pass + return await _orig_handle_result(session, result) + + self.manager.handle_result = _wrapped_handle_result + + async def _gate_open_when_ready(self, ready_evt: asyncio.Event) -> None: + """等 gateway 就绪后放行回放任务。""" + try: + await self._wait_gateway_ready() + finally: + # 录制的 t0 必须和回放起点一致,否则 frames.jsonl/subtitles 的时间轴 + # 会把排队那几十秒也算进去,两个 arm 无法对齐。 + if self.live_rec is not None: + self.live_rec.start() + LOG.info("[LIVE] rerun 录制已开(就绪后启动,结束自动出 mp4)") + # 统一回放零点:音频按 40ms 绝对时钟推、图按 frames.jsonl 的 t 等待, + # 两者必须用同一个 t0,否则各自以"自己被调度到的那一刻"为零点, + # 起跑差多少全看事件循环,音图就对不齐。 + self._replay_t0 = time.monotonic() + _rc = getattr(self, "_rec_client", None) + if _rc is not None: + _rc.replay_t0 = self._replay_t0 + ready_evt.set() + + async def _wait_gateway_ready(self, timeout_s: float = 180.0) -> bool: + """等 duplex session 真正 prepared 之后再开始回放。 + + 实测:连着跑两次 rerun 时,后一次会在 gateway 排队([GW] queue position=1) + 长达 17 秒才 prepared。而回放任务从第 0 秒就推音频和图 —— 这 17 秒的输入 + 全部推给一个还不存在的 session,直接丢掉,提问就在里面,模型自然没反应。 + 更要命的是两个 arm 被吞掉的长度不一样,配对设计直接失效,而且事后从结果上 + 看不出来(长得就像"模型没回答")。所以回放前必须等就绪。 + """ + t0 = time.monotonic() + warned = False + while time.monotonic() - t0 < timeout_s: + if self._stop_evt.is_set(): + return False + try: + status = str(self.manager.health().get("gateway_status") or "") + except Exception: + status = "" + if status == "running": + waited = time.monotonic() - t0 + if waited > 1.0: + LOG.info("[RERUN] gateway 就绪(等了 %.1fs),开始回放", waited) + return True + if not warned and time.monotonic() - t0 > 3.0: + warned = True + LOG.info("[RERUN] 等 gateway session 就绪…(status=%s)", status or "?") + await asyncio.sleep(0.25) + LOG.warning("[RERUN] 等 gateway 就绪超时 %.0fs,仍开始回放(本次结果可能不可用)", + timeout_s) + return False + + async def start(self) -> None: + await self.speaker.start() + _install_asr_tap(self.harness, self.live_rec) + if self._web_ui is not None: + try: + await self._web_ui.start() + LOG.info("[UI] bridge_ui 第一视角已启动: http://localhost:%d", + self._web_ui.port) + except Exception as e: + LOG.warning("[UI] bridge_ui 启动失败: %s", e) + self._web_ui = None + # 方向分类器预热(原设计,-o 迁移时漏了):首次 process_orientation 含模型加载+ + # oneDNN 编译(~2s,甚至 5s+)。不预热的话它会推迟到第一次 accept 才现场加载, + # 卡住那一轮,且在此之前链路出不了 send(模型长时间拿不到图)。 + if self._funnel is not None: + try: + ms = await asyncio.to_thread(self._funnel.warmup_orient) + LOG.info("[预热] 方向分类器就绪 (首次 %.0fms,运行时应降到 ~10ms)", ms) + except Exception as e: + LOG.warning("[预热] 方向分类器预热跳过: %s", e) + # ── rerun 模式:用录制的 session 回放(音频+best图)重跑 -o,不接实时设备 ── + if self._rerun_from: + LOG.info("[RERUN] 模式启动,回放 session: %s", self._rerun_from) + _ready = asyncio.Event() + asyncio.create_task(self._gate_open_when_ready(_ready)) + self._tasks = [ + asyncio.create_task(self.harness.run()), + asyncio.create_task(self._initial_session_loop()), + asyncio.create_task(self._stats_loop()), + asyncio.create_task(rerun_audio_reader( + self._rerun_from, + self.manager, self.harness, + self.audio_queue, self.audio_mirror, self.stats, + self.config.input_gain, self._stop_evt, + live_rec=self.live_rec, ready_evt=_ready, + replay_t0=lambda: self._replay_t0, + done_evt=self._audio_done, + )), + asyncio.create_task(rerun_image_loop( + self._rerun_from, self.latest_frame, self.harness, + self.stats, self._image_interval_s, self._stop_evt, + web_ui=self._web_ui, + live_rec=self.live_rec, ready_evt=_ready, + replay_t0=lambda: self._replay_t0, + done_evt=self._image_done, + peer_done=self._audio_done, + speaker=self.speaker, sent_tracker=self.sent_tracker, + tail_wait_s=self._rerun_tail_wait_s, + )), + ] + return + # ── funnel rerun:录制的整簇多帧重跑漏斗;不加 --funnel 则为无漏斗对照组 ── + if self._funnel_rerun_from: + no_funnel = (self._funnel is None) + _ready = asyncio.Event() + asyncio.create_task(self._gate_open_when_ready(_ready)) + LOG.info("[RERUN] %s 模式启动: %s", + "无漏斗对照组" if no_funnel else "funnel 重跑漏斗+播报", + self._funnel_rerun_from) + n_frames = getattr(self._funnel, "n_frames", 3) if self._funnel else 3 + rec_client = RecordedImageClient(self._funnel_rerun_from, n_frames, + no_funnel=no_funnel) + self._rec_client = rec_client # 就绪时注入统一零点 + self._tasks = [ + asyncio.create_task(self.harness.run()), + asyncio.create_task(self._initial_session_loop()), + asyncio.create_task(self._stats_loop()), + asyncio.create_task(rerun_audio_reader( + self._funnel_rerun_from, + self.manager, self.harness, + self.audio_queue, self.audio_mirror, self.stats, + self.config.input_gain, self._stop_evt, + live_rec=self.live_rec, ready_evt=_ready, + replay_t0=lambda: self._replay_t0, + done_evt=self._audio_done, + )), + # 复用完整 esp32_image_loop(run_once 重判 + reject 停播恢复 + 标点保护), + # 只把图源从 TCP 换成 RecordedImageClient(读录制整簇多帧)。 + asyncio.create_task(esp32_image_loop( + rec_client, self.latest_frame, self.harness, self.stats, + self._image_interval_s, self._image_timeout_s, self._stop_evt, + probe=self._probe, funnel=self._funnel, recorder=None, + speaker=self.speaker, + gateway_host=self._gateway_host, gateway_port=self._gateway_port, + ssl_ctx=self._chat_ssl, force_measure=self._force_measure, + manager=self.manager, + reject_wav_dir=self._reject_wav_dir, + sent_tracker=self.sent_tracker, + live_rec=self.live_rec, # 开 --record-live 则录 rerun 输出→自动出 mp4 + web_ui=self._web_ui, ready_evt=_ready, + tail_wait_s=self._rerun_tail_wait_s, + no_reject=self._no_reject, + peer_done=self._audio_done, done_evt=self._image_done, + )), + ] + return + # 设 ESP32 分辨率为 HD(1280×720)。固件默认 SVGA(800×600),但漏斗阈值是按 HD + # 标定的(cam_pipeline_v2 注释:分辨率固定 HD 后针对 HD 标定)。-o 迁移时漏了这步, + # 导致一直跑 SVGA、画质与阈值不匹配。这里启动时补上。 + if self._funnel is not None: + ok = await asyncio.to_thread(self._funnel.set_resolution_hd) + LOG.info("[ESP32] 设分辨率 1280×720(UXGA档): %s", + "成功" if ok else "失败(检查ESP32 /control)") + await asyncio.sleep(0.3) # 切分辨率后固件重配,稍等 + if self.live_rec is not None: + self.live_rec.start() + LOG.info("[LIVE] -o record started") + self._tasks = [ + # ── 继承自 rokid 的三个骨架 task ── + asyncio.create_task(self.harness.run()), + asyncio.create_task(self._initial_session_loop()), + asyncio.create_task(self._stats_loop()), + # ── ESP32 特有:主动拉取音视频 ── + asyncio.create_task(esp32_audio_reader( + self._esp32_host, self._esp32_port, + self.manager, self.harness, + self.audio_queue, self.audio_mirror, self.stats, + self.config.input_gain, self._stop_evt, + probe=self._probe, + live_rec=self.live_rec, + )), + asyncio.create_task(esp32_image_loop( + self._tcp_img, self.latest_frame, self.harness, self.stats, + self._image_interval_s, self._image_timeout_s, self._stop_evt, + probe=self._probe, funnel=self._funnel, recorder=self._recorder, + speaker=self.speaker, + gateway_host=self._gateway_host, gateway_port=self._gateway_port, + ssl_ctx=self._chat_ssl, force_measure=self._force_measure, + manager=self.manager, + reject_wav_dir=self._reject_wav_dir, + sent_tracker=self.sent_tracker, + live_rec=self.live_rec, + web_ui=self._web_ui, + no_reject=self._no_reject, + )), + ] + + async def close(self) -> None: + self._stop_evt.set() + if self._web_ui is not None: + try: + await self._web_ui.stop() + except Exception: + pass + if self.live_rec is not None: + try: + # 冲掉还没等到 end_of_turn 的那段(bare 组常见:模型一路流式说, + # 没有 stop/resume 打断,end_of_turn 迟迟不来 → 整段丢失) + tp = getattr(self, "_turn_printer", None) + if tp is not None and getattr(tp, "_in_turn", False): + pending = "".join(getattr(tp, "_turn_text", [])) + if pending: + end_ms = self.live_rec.session_ms() + start_ms = (self._turn_start_ms + if self._turn_start_ms is not None + else max(end_ms - 3000, 0)) + self.live_rec.log_turn_text(tp.turn_idx, pending, + bool(tp._turn_is_listen)) + self.live_rec.log_subtitle( + start_ms=start_ms, end_ms=end_ms, text=pending, + is_listen=bool(tp._turn_is_listen), turn_idx=tp.turn_idx) + LOG.info("[LIVE] 冲出未收尾的 turn #%d (%d字)", + tp.turn_idx, len(pending)) + except Exception as e: + LOG.warning("[LIVE] flush pending turn err: %s", e) + try: + self.live_rec.stop() + LOG.info("[LIVE] -o record stopped") + except Exception as e: + LOG.warning("[LIVE] stop err: %s", e) + await self._tcp_img._close() + if self._probe is not None: + self._probe.close() + if self._recorder is not None: + self._recorder.close() + await super().close() + + +def parse_args() -> argparse.Namespace: + p = argparse.ArgumentParser(description="ESP32 Phase B Harness runtime") + # ── ESP32 设备 ── + p.add_argument("--esp32-host", required=True, help="ESP32 IP address") + p.add_argument("--rotate", type=int, default=0, choices=(0, 90, 180, 270), + help="摄像头顺时针旋转角度,按眼镜侧装方向填" + "(取自 devices.json 的 rotate)。在进漏斗前转正," + "否则方向检测会把相机侧装误判成用户拿反了。") + p.add_argument("--esp32-port", type=int, default=80, help="ESP32 HTTP/WS port") + p.add_argument("--image-tcp-port", type=int, default=5000, help="ESP32 TCP image port") + p.add_argument("--image-interval-s", type=float, default=1.0, help="取图间隔(秒)") + p.add_argument("--image-timeout-s", type=float, default=1.0, help="单次取图超时(秒)") + # ── gateway / harness(与 rokid 一致)── + p.add_argument("--gateway", default="localhost:8040") + p.add_argument("--gateway-proto", default="auto", + choices=("auto", "duplex", "realtime"), + help="gateway 协议。duplex=/ws/duplex(V1);" + "realtime=/v1/realtime(V2,V2 gateway 只有这个端点," + "连 /ws/duplex 会被 403 拒绝);" + "auto=按端口猜(8006→realtime,其余→duplex)") + p.add_argument("--gateway-tls", action="store_true", default=True) + p.add_argument("--no-tls", dest="gateway_tls", action="store_false") + p.add_argument("--harness-url", default="ws://127.0.0.1:8021/ws/control") + p.add_argument("--client-id", default="esp32-phase-b") + p.add_argument("--skills-config", default=default_skills_config()) + p.add_argument("--cleanup-mode", choices=("light", "full"), default="light") + p.add_argument("--chunk-ms", type=int, default=1_000) + p.add_argument("--force-listen-count", type=int, default=3) + p.add_argument("--audio-queue-packets", type=int, default=96) + p.add_argument("--input-gain", type=float, default=12.0) + p.add_argument("--prompt", default=None, help="system prompt(可选)") + p.add_argument("--no-play", action="store_true") + p.add_argument("--log-level", default="INFO") + # ── 时序探针(纯旁路)── + p.add_argument("--timing-probe", action="store_true", help="开启时序探针,写 CSV") + p.add_argument("--timing-csv", default=None, help="探针 CSV 路径(默认自动带时间戳)") + # ── CV 漏斗 ── + p.add_argument("--funnel", action="store_true", help="开启 CV 漏斗(抓N帧判定,合格才送模型)") + p.add_argument("--scene", default="medicine", choices=("medicine", "stationery"), + help="漏斗场景参数") + p.add_argument("--funnel-frames", type=int, default=3, help="每轮抓帧数(3选2)") + p.add_argument("--no-focus", dest="funnel_focus", action="store_false", default=True, + help="关闭漏斗内的自动对焦触发") + # ── session 录制(对齐 -v 格式)── + p.add_argument("--record", action="store_true", help="录 session(整簇帧+判定到 sessions/)") + p.add_argument("--sessions-root", default="sessions", help="session 根目录") + p.add_argument("--no-reject", action="store_true", + help="消融:漏斗只选 best、永远放行,不拒绝不播报" + "(用于把工作②选图的收益与工作③拒绝分开)") + p.add_argument("--rerun-tail-wait-s", type=float, default=30.0, + help="rerun 图放完后,最多再等模型说完的秒数(默认30)") + p.add_argument("--record-no-media", action="store_true", + help="批量评分用:只写 wav+jsonl+transcript,跳过 jpg 落盘和 mp4 拼接") + p.add_argument("--record-live", action="store_true", + help="-o record:录音+图(只存真发送的best)到 live_sessions/,供 -o rerun") + p.add_argument("--rerun-from", default=None, + help="-o rerun:从 live_sessions/ 回放(音+best图)重跑 -o 模型") + p.add_argument("--funnel-rerun-from", default=None, + help="funnel rerun:从 live_sessions/ 回放(音+整簇多帧)重跑漏斗+播报+-o") + p.add_argument("--web-ui-port", type=int, default=None, + help="开 bridge_ui 第一视角(如 8080),live/rerun/funnel-rerun 都可看") + # ── 强制措施(防幻觉):reject 时用模型音色念提示 + 停/恢复走 8021 ── + p.add_argument("--force-measure", action="store_true", + help="开启强制措施:reject→停duplex→播预生成wav→恢复duplex") + p.add_argument("--reject-wav-dir", default="assets/reject_wav", + help="预生成的 reject 提示 wav 目录(gen_reject_wavs.py 生成)") + return p.parse_args() + + +def main() -> None: + args = parse_args() + logging.basicConfig( + level=getattr(logging, args.log_level.upper(), logging.INFO), + format="%(asctime)s %(levelname)s %(name)s: %(message)s", + force=True, + ) + config = RokidRuntimeConfig( + gateway=args.gateway, + gateway_tls=args.gateway_tls, + harness_url=args.harness_url, + harness_client_id=args.client_id, + skills_config=args.skills_config, + cleanup_mode=args.cleanup_mode, + chunk_ms=args.chunk_ms, + force_listen_count=args.force_listen_count, + audio_queue_packets=args.audio_queue_packets, + input_gain=args.input_gain, + play_audio=not args.no_play, + ) + probe = TimingProbe( + enabled=args.timing_probe, + path=args.timing_csv, + chunk_ms=args.chunk_ms, + ) + funnel = None + if args.funnel: + # rerun 时强制关对焦:rerun 没有真实相机,trigger_af 对录制的图无意义, + # 且对焦重抓会让 run_once 多抓一簇 → RecordedImageClient 多消耗一个 round + # → 图提前用光(有漏斗比无漏斗先用光的根因)。 + _is_rerun = bool(args.rerun_from or args.funnel_rerun_from) + _focus = args.funnel_focus and not _is_rerun + funnel = FunnelGate( + args.esp32_host, + scene=args.scene, + n_frames=args.funnel_frames, + enable_focus=_focus, + ) + LOG.info("CV 漏斗已开启: scene=%s frames=%d focus=%s%s", + args.scene, args.funnel_frames, _focus, + "(rerun 强制关对焦)" if (_is_rerun and args.funnel_focus) else "") + recorder = None # 旧 SessionRecorder 已废弃,统一走 LiveRecorder + # 统一 record(音+整簇多帧+best标记):--record 或 --record-live 都触发。 + live_record_dir = None + if args.record or args.record_live or args.record_no_media: + import time as _t + live_record_dir = os.path.join("live_sessions", _t.strftime("%Y%m%d_%H%M%S")) + # 日志同时落进 session 目录:评分时要按时间轴对齐 reject/播报/模型输出, + # 控制台日志是滚动的、和 session 分离,跑多组 rerun 极易对错。 + try: + os.makedirs(live_record_dir, exist_ok=True) + _fh = logging.FileHandler( + os.path.join(live_record_dir, "run.log"), encoding="utf-8") + _fh.setFormatter(logging.Formatter( + "%(asctime)s %(levelname)s %(name)s: %(message)s")) + logging.getLogger().addHandler(_fh) + LOG.info("[LIVE] 日志同时写入 %s", os.path.join(live_record_dir, "run.log")) + except Exception as e: + LOG.warning("[LIVE] run.log 创建失败: %s", e) + os.makedirs(live_record_dir, exist_ok=True) + LOG.info("统一 record 已开启: %s(音+整簇多帧+best标记,供三种 rerun)", live_record_dir) + # 解析 gateway "host:port"(念提示的 chat TTS 走同一个 gateway 的 wss) + _gw = args.gateway.split("://")[-1] + _gw_host, _, _gw_port = _gw.partition(":") + _gw_host = _gw_host or "127.0.0.1" + _gw_port = int(_gw_port or "8040") + # 选 gateway 协议。V2 gateway 只有 /v1/realtime(连 /ws/duplex 会 403), + # V1 只有 /ws/duplex。auto 按端口猜:8006 是 V2 的默认端口。 + _proto = args.gateway_proto + if _proto == "auto": + _proto = "realtime" if _gw_port == 8006 else "duplex" + _factory = None + if _proto == "realtime": + from .realtime_session import RealtimeDuplexSession as _factory + LOG.info("[GW] 协议: /v1/realtime (V2)") + else: + LOG.info("[GW] 协议: /ws/duplex (V1)") + + runtime = PhaseBEsp32Runtime( + config, + **({"session_factory": _factory} if _factory else {}), + esp32_host=args.esp32_host, + esp32_port=args.esp32_port, + image_tcp_port=args.image_tcp_port, + image_interval_s=args.image_interval_s, + image_timeout_s=args.image_timeout_s, + probe=probe, + funnel=funnel, + recorder=recorder, + force_measure=args.force_measure, + reject_wav_dir=args.reject_wav_dir, + gateway_host=_gw_host, + gateway_port=_gw_port, + live_record_dir=live_record_dir, + rerun_from=args.rerun_from, + funnel_rerun_from=args.funnel_rerun_from, + web_ui_port=args.web_ui_port, + record_no_media=args.record_no_media, + rerun_tail_wait_s=args.rerun_tail_wait_s, + no_reject=args.no_reject, + rotate=args.rotate, + ) + if args.force_measure: + LOG.info("强制措施已开启: reject→funnel.stop+念提示, good→funnel.resume " + "(节流5s, chat TTS via wss://%s:%d)", _gw_host, _gw_port) + + LOG.info("ESP32 Phase B input: ws://%s:%d/ws_audio_v2 + TCP:%d", + args.esp32_host, args.esp32_port, args.image_tcp_port) + LOG.info("Harness: %s", config.harness_url) + LOG.info("Gateway: %s://%s", "wss" if config.gateway_tls else "ws", config.gateway) + if args.rotate: + LOG.info("[ROTATE] 摄像头顺时针 %d° 转正(进漏斗前)", args.rotate) + + async def _run() -> None: + await runtime.start() + stop = asyncio.Event() + + def _sig(*_a): + stop.set() + try: + loop = asyncio.get_running_loop() + for s in (signal.SIGINT, getattr(signal, "SIGBREAK", signal.SIGINT)): + try: + loop.add_signal_handler(s, stop.set) + except (NotImplementedError, ValueError): + signal.signal(s, _sig) + except Exception: + signal.signal(signal.SIGINT, _sig) + # 等"信号(Ctrl+C)"或"runtime 内部 stop_evt(rerun 图放完自动结束)"任一触发 + _internal = getattr(runtime, "_stop_evt", None) + waiters = [asyncio.create_task(stop.wait())] + if _internal is not None: + waiters.append(asyncio.create_task(_internal.wait())) + await asyncio.wait(waiters, return_when=asyncio.FIRST_COMPLETED) + for w in waiters: + w.cancel() + await runtime.close() + + try: + asyncio.run(_run()) + except KeyboardInterrupt: + LOG.info("Interrupted; shutting down") + + +if __name__ == "__main__": + main() diff --git a/extensions/assistive_harness/phase_b/funnel_gate.py b/extensions/assistive_harness/phase_b/funnel_gate.py new file mode 100644 index 0000000..fe683a7 --- /dev/null +++ b/extensions/assistive_harness/phase_b/funnel_gate.py @@ -0,0 +1,218 @@ +"""漏斗闸门(接入 -o 链路)。 + +把 cam_pipeline_v2 的 run_funnel / process_orientation / CamControl 封装成 +"一轮漏斗判定",供 esp32_runtime 在图像循环里调用: + + gate = FunnelGate(esp32_host, scene="medicine", n_frames=3) + result = await gate.run_once(capture_fn) # capture_fn: async ()->Optional[bytes] + +返回 FunnelDecision: + send : bool 是否放行给模型 + best : bytes|None 放行的最佳帧(已做倒置纠正) + reason : str 决策原因(accepted/severe_shake/unstable/need_focus/orient...) + hint : str|None 拒绝时给用户的提示文本(先输出 text,TTS 通道待定) + timings: dict grab_ms / judge_ms / orient_ms / af_ms / n_frames + +设计依据(防漂移文档 + cam_pipeline_v2): + - 判定唯一 = run_funnel 的 frame_score 三出口 + argmin 归因 + - need_focus → 触发单次 AF(0x3022) → 等 AF_SETTLE_MS → 重抓一簇 → 重判 + - 倒置 = process_orientation,flipped 时纠正或提示 + - 拒绝 reason → HINTS 文本 +本模块只做"输入端把关+引导",不碰模型输出侧(那是 harness 的事)。 +""" +from __future__ import annotations + +import asyncio +import time +from typing import Awaitable, Callable, Optional + +from . import cam_pipeline_v2 as cp + +AF_SETTLE_MS = 120 # OV5640 单次对焦 settle(与 v5 一致) + +# reject_reason -> 用户提示(先输出 text;TTS 通道确定后接同一份文本) +HINTS = { + "no_frames": "没有拿到画面,请稍等", + "severe_shake": "画面晃得厉害,请先保持不动", + "unstable": "画面还在晃动,请保持不动一会儿", + "too_dark": "光线太暗,请到亮一点的地方", + "aimed_wrong": "好像没对准,请对准目标", + "need_focus": "对焦中,请拿稳一下", + "orient": "画面好像反了,请倒过来", +} + + +class FunnelDecision: + __slots__ = ("send", "best", "reason", "hint", "timings", + "frames", "best_index", "af_triggered", "af_ok") + + def __init__(self, send, best, reason, hint, timings, + frames=None, best_index=-1, af_triggered=False, af_ok=None): + self.send = send + self.best = best + self.reason = reason + self.hint = hint + self.timings = timings + self.frames = frames or [] # 整簇帧(存 session 用) + self.best_index = best_index # best 在簇里的下标 + self.af_triggered = af_triggered # 本轮有没有触发 AF + self.af_ok = af_ok # AF /reg 请求是否返回成功(None=没触发) + + +class FunnelGate: + def __init__(self, esp32_host: str, scene: str = "medicine", + n_frames: int = 3, frame_gap_s: float = 0.0, + enable_focus: bool = True): + self.scene = scene + self.n_frames = n_frames + self.frame_gap_s = frame_gap_s + self.enable_focus = enable_focus + self._cfg = (cp.make_scene_config(scene) + if hasattr(cp, "make_scene_config") else cp.FunnelConfig()) + # 相机 HTTP 控制走 /control、/reg 到 ESP32(同 esp32_host)。 + # camctl 总是构造:分辨率(set_resolution)独立于对焦,即使不对焦也要设 HD。 + # 对焦(trigger_af)另受 enable_focus 控制。 + self._camctl = cp.CamControl(esp32_host) + self._last_af_mono = 0.0 # 上次真正触发对焦的时刻(冷却用) + self._af_cooldown_s = 2.0 # 对焦冷却:2s 内最多触发 1 次(避免每秒对焦) + + def warmup_orient(self) -> float: + """方向分类器预热(同步,调用方放线程里)。 + + 原设计(-v pc_vlm_v5_funnel):首次 process_orientation 含模型加载 + oneDNN + 编译开销(实测 ~2s,本次日志里甚至 5.76s),启动时先跑一张假图,把这笔一次性 + 开销挪到启动阶段,运行时 orient_ms 就是纯推理(md 记录:2143ms → 9ms)。 + -o 迁移时漏了这步 → orient 直到第一次 accept 才现场加载,卡住那一轮, + 且在此之前链路出不了 send。返回首次耗时(ms)。 + """ + import numpy as _np + import cv2 as _cv2 + _warm = _np.full((480, 640, 3), 255, dtype=_np.uint8) + ok, buf = _cv2.imencode(".jpg", _warm) + if not ok: + return -1.0 + t0 = time.monotonic() + cp.process_orientation(buf.tobytes()) + return (time.monotonic() - t0) * 1000.0 + + def set_resolution_hd(self, retries: int = 5, gap_s: float = 0.6) -> bool: + """设 1280×720(UXGA档,这块 OV5640 枚举非标准,HD(11)无效、UXGA(13)才 720p)。 + live 启动时 ESP32 可能刚就绪,/control 偶发失败 → 重试几次,避免要手动进网页设。 + 失败时打详细原因(status/异常),不再静默。""" + import logging as _lg + _log = _lg.getLogger("funnel_gate") + for i in range(max(1, retries)): + try: + ok = self._camctl.set_resolution("UXGA") + if ok: + if i > 0: + _log.info("[funnel_gate] set_resolution(UXGA) 第%d次重试成功", i + 1) + return True + _log.warning("[funnel_gate] set_resolution(UXGA) 返回非200 (第%d/%d次)", + i + 1, retries) + except Exception as e: + _log.warning("[funnel_gate] set_resolution(UXGA) 异常 (第%d/%d次): %r", + i + 1, retries, e) + time.sleep(gap_s) + return False + + async def _grab_burst( + self, capture_fn: Callable[[], Awaitable[Optional[bytes]]], n: int + ) -> list[bytes]: + frames: list[bytes] = [] + for i in range(n): + jpeg = await capture_fn() + if jpeg: + frames.append(jpeg) + if self.frame_gap_s > 0 and i < n - 1: + await asyncio.sleep(self.frame_gap_s) + return frames + + async def run_once( + self, capture_fn: Callable[[], Awaitable[Optional[bytes]]] + ) -> FunnelDecision: + """跑一轮漏斗:抓 N 帧 -> run_funnel -> (need_focus 则对焦重抓) -> 倒置 -> 决策。""" + timings: dict = {} + + # 1) 抓一簇 + t0 = time.monotonic() + frames = await self._grab_burst(capture_fn, self.n_frames) + timings["grab_ms"] = round((time.monotonic() - t0) * 1000, 1) + timings["n_frames"] = len(frames) + if not frames: + return FunnelDecision(False, None, "no_frames", HINTS["no_frames"], timings) + + # 2) run_funnel 判定(run_funnel 是同步的,放线程池避免阻塞事件循环) + tj = time.monotonic() + res = await asyncio.to_thread(cp.run_funnel, frames, self._cfg) + timings["judge_ms"] = round((time.monotonic() - tj) * 1000, 1) + timings["af_ms"] = 0.0 + af_triggered = False + af_ok = None + + # 3) need_focus -> 触发单次 AF -> 等 settle -> 重抓 -> 重判 + # 对焦冷却:need_focus 但距上次对焦 < _af_cooldown_s(2s) 时不重复触发, + # 给对焦时间生效(每秒对焦太快,马达反复动反而对不好)。冷却内仍 need_focus + # 就用当前帧判定(该 reject 就 reject,不重抓)。 + if res.need_focus and self.enable_focus and self._camctl is not None: + _now = time.monotonic() + if _now - self._last_af_mono >= self._af_cooldown_s: + self._last_af_mono = _now + taf = _now + af_triggered = True + af_ok = await asyncio.to_thread(self._camctl.trigger_af) # True/False + await asyncio.sleep(AF_SETTLE_MS / 1000.0) + frames2 = await self._grab_burst(capture_fn, self.n_frames) + if frames2: + res = await asyncio.to_thread(cp.run_funnel, frames2, self._cfg) + frames = frames2 + timings["af_ms"] = round((time.monotonic() - taf) * 1000, 1) + timings["n_frames"] = len(frames) + else: + # 冷却期内:不重复对焦,用当前判定结果 + timings["af_cooldown"] = round(self._af_cooldown_s - (_now - self._last_af_mono), 2) + timings["af_ok"] = af_ok + + def _mk(send, best, reason, hint): + bi = frames.index(best) if (best in frames) else -1 + return FunnelDecision(send, best, reason, hint, timings, + frames=frames, best_index=bi, + af_triggered=af_triggered, af_ok=af_ok) + + # 4) 拒绝出口 + if not res.accepted: + reason = res.reject_reason or "reject" + # cam_pipeline 的拒绝出口只设 best_index(注释:仅供参考, 不喂模型), + # 不设 best_jpg —— 这是原设计意图:拒绝就不送图。 + # 但消融 arm(--no-reject:只选 best、永远放行)需要拿到这一帧, + # 所以这里按 best_index 把帧补出来。**send 仍然是 False**, + # 正常链路完全不受影响:只有显式开了 --no-reject 才会去用它。 + _bj = res.best_jpg + if _bj is None: + bi = getattr(res, "best_index", -1) + if isinstance(bi, int) and 0 <= bi < len(frames): + _bj = frames[bi] + return _mk(False, _bj, reason, + HINTS.get(reason, "看不清楚,请调整一下")) + + # 5) 接受帧的方向检测(OCR 方向分类器优先,见 cam_pipeline.process_orientation) + # 原则「宁拒绝不念错」:方向不正 -> 拒绝 + 提示用户转正,绝不自动纠正、绝不送倒图。 + # process_orientation 只诊断方向、返回的 jpg 未旋转,故不能拿它当"纠正后"送模型。 + best = res.best_jpg + to_ = time.monotonic() + try: + _jpg, geom = await asyncio.to_thread(cp.process_orientation, best) + except Exception: + geom = {"ok": False} + timings["orient_ms"] = round((time.monotonic() - to_) * 1000, 1) + + orient_state = geom.get("orient_state") if isinstance(geom, dict) else None + orient_hint = geom.get("orient_hint") if isinstance(geom, dict) else None + + # upright 才放行;flipped/sideways 拒绝并提示;uncertain 也放行(不硬拦,避免误拒) + if orient_state in ("flipped", "sideways"): + hint = orient_hint or HINTS["orient"] + return _mk(False, best, "orient_" + orient_state, hint) + + # upright / uncertain / 检测不可用 -> 放行原图(不做任何旋转) + return _mk(True, best, "send", None) diff --git a/extensions/assistive_harness/phase_b/realtime_session.py b/extensions/assistive_harness/phase_b/realtime_session.py new file mode 100644 index 0000000..c0e4435 --- /dev/null +++ b/extensions/assistive_harness/phase_b/realtime_session.py @@ -0,0 +1,306 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +realtime_session.py —— 把 duplex 会话接到 V2 gateway 的 /v1/realtime 协议。 + +为什么需要它 +------------ +V1 gateway 有 `/ws/duplex/{session_id}`;**V2 gateway 只有 `/v1/realtime`** +(实测:V2 gateway.py 里唯一的 @app.websocket 是 /v1/realtime, + 连 /ws/duplex/... 会被 FastAPI 直接 403 拒绝握手)。 +所以 rokid_runtime / esp32_runtime 里那套 GatewayDuplexSession 在 V2 下连不上, +demo_esp32_duplex_0703 同样连不上(它连的也是 /ws/duplex)。 + +做法 +---- +`GatewaySessionManager` 有现成的替换点 `session_factory`, +所以这里**继承 GatewayDuplexSession,只覆盖协议相关的方法**, +其余(音频攒块、状态管理、start/_run 骨架、stop 的收尾)全部复用。 +rokid_runtime.py 和 esp32_runtime.py 都不用改,只在构造 manager 时传入本类。 + +协议对照(V1 内部 → V2 对外) +------------------------------ + 连接 URL 带 session_id → 连上后 session.init,服务端回 session.created + 排队 queued / queue_done → session.queued / session.queue_done + 上行 audio_chunk → input.append + audio_base64 → input.audio + frame_base64_list → input.video_frames + force_listen → input.force_listen + 下行 {is_listen,text,audio_data}→ response.output.delta 的 kind: listen/text/audio + 结束 stop → session.close + +注意 +---- +· V2 的 session_id 由服务端在 session.created 里给,客户端不能自己指定。 + 但 manager/日志里到处用 self.session_id,所以保留本地生成的那个作为占位, + 拿到服务端的之后覆盖掉。 +· full-duplex 下没有 response.done(文档说它只用于 mode=chat), + turn 边界靠 delta 里的 turn_id 变化判断。 +· kind=audio 的 PCM 是 24kHz mono float32 base64,和 V1 的 audio_data 同格式, + 所以 on_result 那一侧不用改。 +""" +from __future__ import annotations + +import asyncio +import base64 +import json +import time +from typing import Any + +import aiohttp +import numpy as np + +from .rokid_runtime import ( + LOG, + GatewayDuplexSession, + SAMPLE_RATE_IN, + float32_to_base64, + now_ms, +) + + +class RealtimeDuplexSession(GatewayDuplexSession): + """V2 /v1/realtime 协议版的 duplex 会话。构造签名与父类完全一致。""" + + # ------------------------------------------------------------ 连接 + async def _run(self) -> None: + scheme = "wss" if self.config.gateway_tls else "ws" + # mode=video:连续音频 + 可带视频帧,300s 上限。 + # mode=audio 是纯音频(600s),我们要送图所以用 video。 + url = f"{scheme}://{self.config.gateway}/v1/realtime?mode=video" + self.status = "connecting" + LOG.info("[GW] connecting generation=%d %s (realtime)", + self.spec.generation, url) + try: + async with aiohttp.ClientSession() as client: + async with client.ws_connect( + url, + heartbeat=30, + ssl=self._ssl_context(), + max_msg_size=0, + ) as ws: + self.ws = ws + await self._prepare(ws) + self.status = "running" + if self._ready is not None and not self._ready.done(): + self._ready.set_result(None) + await asyncio.gather( + self._send_loop(ws), + self._receive_loop(ws), + ) + except asyncio.CancelledError: + raise + except Exception as exc: # noqa: BLE001 + self.status = "failed" + self.last_error = str(exc) + LOG.warning("[GW] session %s failed: %s", self.session_id, exc) + if self._ready is not None and not self._ready.done(): + self._ready.set_exception(exc) + finally: + self._stopped.set() + if self.status not in ("failed",): + self.status = "closed" + + # ------------------------------------------------------------ 握手 + async def _prepare(self, ws: aiohttp.ClientWebSocketResponse) -> None: + """等 session.queue_done → 发 session.init → 等 session.created。 + + 文档明确要求:**必须等 queue_done 再发 session.init**。 + 没有排队时服务端会立刻下发 queue_done。 + """ + self.status = "queued" + while True: + message = await ws.receive() + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + raise RuntimeError("gateway closed while queued") + continue + payload = json.loads(message.data) + mtype = payload.get("type") + if mtype == "session.queue_done": + break + if mtype == "error": + raise RuntimeError( + (payload.get("error") or {}).get("message") + if isinstance(payload.get("error"), dict) + else payload.get("error") or "gateway queue error" + ) + if mtype in ("session.queued", "session.queue_update"): + LOG.info("[GW] queue position=%s eta=%s", + payload.get("position"), + payload.get("estimated_wait_s")) + + self.status = "preparing" + init_payload: dict[str, Any] = { + "system_prompt": self.spec.system_prompt, + "config": { + "force_listen_count": self.config.force_listen_count, + "chunk_ms": self.config.chunk_ms, + "generate_audio": True, + "max_new_speak_tokens_per_chunk": ( + self.config.max_new_speak_tokens_per_chunk + ), + "length_penalty": self.config.length_penalty, + }, + } + await self._send_json({"type": "session.init", "payload": init_payload}) + + while True: + message = await ws.receive() + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + raise RuntimeError("gateway closed while preparing") + continue + payload = json.loads(message.data) + mtype = payload.get("type") + if mtype == "session.created": + # session_id 由服务端给,覆盖本地占位的那个 + sid = payload.get("session_id") + if sid: + self.session_id = sid + LOG.info("[GW] prepared session=%s generation=%d skill=%s mode=%s", + self.session_id, self.spec.generation, + self.spec.skill_id, payload.get("mode")) + return + if mtype == "error": + raise RuntimeError( + (payload.get("error") or {}).get("message") + if isinstance(payload.get("error"), dict) + else payload.get("error") or "gateway prepare error" + ) + + # ------------------------------------------------------------ 上行 + async def _send_loop(self, ws: aiohttp.ClientWebSocketResponse) -> None: + """攒 1s 音频 + 带上最新帧,发 input.append。 + + 攒块、取帧、force_listen 的判断逻辑与父类完全一致,只换消息外壳。 + """ + carry = bytearray() + last_frame_sequence = -1 + last_frame_sent = 0.0 + sent = 0 + while not self._closing: + audio = await self._next_audio_chunk(carry) + if audio is None: + continue + inp: dict[str, Any] = { + "audio": float32_to_base64(audio), + "max_slice_nums": self.config.max_slice_nums, + } + if self.gate.speech_hold_active: + inp["force_listen"] = True + frame = self.latest_frame + frame_age_ms = now_ms() - frame.timestamp_ms + frame_due = time.monotonic() - last_frame_sent >= self.config.image_resend_s + if ( + frame.jpeg + and frame_age_ms <= self.config.image_max_age_s * 1000 + and (frame.sequence != last_frame_sequence or frame_due) + ): + inp["video_frames"] = [base64.b64encode(frame.jpeg).decode("ascii")] + last_frame_sequence = frame.sequence + last_frame_sent = time.monotonic() + sent += 1 + LOG.debug("[GW-SEND] #%d audio=%.2fs lvl=%.4f frame=%s hold=%s", + sent, len(audio) / SAMPLE_RATE_IN, + float(np.abs(audio).mean()), + "video_frames" in inp, self.gate.speech_hold_active) + await self._send_json({"type": "input.append", "input": inp}) + + # ------------------------------------------------------------ 下行 + async def _receive_loop(self, ws: aiohttp.ClientWebSocketResponse) -> None: + """把 response.output.delta 翻译回 {is_listen, text, audio_data}。 + + 父类的 on_result 拿到的是 V1 那套字段,这里保持不变, + 所以 handle_result / TurnPrinter / speaker 那一侧一行都不用改。 + """ + cur_turn = None + async for message in ws: + if self._closing: + break + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + break + continue + payload = json.loads(message.data) + mtype = payload.get("type") + + if mtype == "response.output.delta": + kind = payload.get("kind") + turn = payload.get("turn_id") + # full-duplex 没有 response.done,用 turn_id 变化当边界 + end_of_turn = (cur_turn is not None and turn is not None + and turn != cur_turn) + if turn is not None: + cur_turn = turn + result: dict[str, Any] = { + "type": "result", + "is_listen": kind == "listen", + "text": payload.get("text") or "", + "audio_data": payload.get("audio") or "", + "end_of_turn": end_of_turn, + "turn_id": turn, + } + await self.on_result(self, result) + continue + + if mtype == "response.done": + # 实测:full-duplex 下**也会**发 response.done(文档说只用于 chat, + # 与实际不符),而且它的 text 是这一段的**完整文本** —— + # 前面 delta 已经把这些字逐块传下去了,这里再传一次就是重复 + # (实测每段都被记两遍,只差 1~2ms)。 + # 所以这里只标记 turn 结束,**不再传 text**。 + await self.on_result(self, { + "type": "result", "is_listen": False, + "text": "", "audio_data": "", + "end_of_turn": True, "turn_id": cur_turn, + }) + continue + + if mtype == "session.closed": + LOG.info("[GW] session.closed reason=%s", payload.get("reason")) + break + + if mtype == "error": + err = payload.get("error") + msg = err.get("message") if isinstance(err, dict) else str(err) + LOG.warning("[GW] error: %s", msg) + self.last_error = msg or "gateway error" + continue + + if mtype == "debug": + # V2 自带的阶段追踪(llm.chunk / tts.chunk / t2w.chunk,带 ts)。 + # 平时不打,需要时 --log-level DEBUG 打开看服务端各阶段耗时。 + LOG.debug("[GW-DEBUG] %s", json.dumps(payload, ensure_ascii=False)[:200]) + continue + + # ------------------------------------------------------------ 结束 + async def stop(self, cleanup_mode: str) -> None: + self._closing = True + if self.ws is not None and not self.ws.closed: + try: + await self._send_json({"type": "session.close", + "reason": cleanup_mode or "user_stop"}) + except Exception: + pass + try: + await asyncio.wait_for(self._stopped.wait(), + timeout=self.config.close_timeout_s) + except asyncio.TimeoutError: + pass + if self.ws is not None and not self.ws.closed: + await self.ws.close() + if self._task and not self._task.done(): + self._task.cancel() + await asyncio.gather(self._task, return_exceptions=True) + + # ------------------------------------------------------------ 文本注入 + async def inject_task(self, text: str) -> bool: + """V2 的 input.append 没有 inject_text 字段,暂不支持。 + + 父类靠它实现"技能切换时把指令文本塞给模型"。V2 协议里没有对应字段, + 硬塞会被服务端忽略或报错,所以明确返回 False 让调用方走别的路径, + 而不是假装成功。 + """ + LOG.info("[GW] inject_task 在 /v1/realtime 协议下暂不支持,跳过: %s", text[:30]) + return False diff --git a/extensions/assistive_harness/phase_b/recorder_live.py b/extensions/assistive_harness/phase_b/recorder_live.py new file mode 100644 index 0000000..3e17528 --- /dev/null +++ b/extensions/assistive_harness/phase_b/recorder_live.py @@ -0,0 +1,860 @@ +"""recorder_live.py — 录屏式实时录制器 v5.0 +================================================= + +v5.0 改动:user 轨从"ring buffer 切片拼接"改成"WS 原始包直录"。 +和蓝牙耳机录通话语义一致:丢包 = 该段缺失,不再补零去对齐墙钟。 +和 AI 轨完全对称——AI 轨录的是 PortAudio DAC 实际写出的样本。 + +调用顺序: + live_rec = LiveRecorder(session_dir) + live_rec.attach_to_player(speaker) # 必须在 speaker.start() 之前 + speaker.start() + live_rec.start() # 此后 user/ai/frame 才会被记录 + + # ESP32 reader 每收一包就调: + live_rec.feed_user_raw(pcm_f32) # 16kHz 原始,丢包就丢 + + # 每发一个 chunk 配的图: + live_rec.on_frame(jpeg, chunk_idx) + + live_rec.stop() + live_rec.finalize_mp4() +""" + +from __future__ import annotations + +import json +import logging +import shutil +import subprocess +import threading +import time +import wave +from pathlib import Path +from typing import Optional + +import numpy as np + +LOGGER = logging.getLogger("recorder_live") + + +class LiveRecorder: + def __init__( + self, + session_dir: Optional[Path], + user_sr: int = 16000, + ai_sr: int = 24000, + no_media: bool = False, + ): + self.enabled = session_dir is not None + self.dir: Optional[Path] = Path(session_dir) if session_dir else None + self.user_sr = user_sr + self.ai_sr = ai_sr + # no_media:批量 rerun 评分只需要 wav + jsonl + transcript, + # 跳过 jpg 落盘和 mp4 拼接(150 次 rerun 会重复复制整簇图、跑 450 次 ffmpeg)。 + self.no_media = bool(no_media) + + self._t0: Optional[float] = None + + # User 轨:ESP32 WS 来的原始 PCM,丢包 = 缺失,不补零 + self._user_t_start: Optional[float] = None + # self._user_chunks: list[np.ndarray] = [] + self._user_chunks: list[tuple[float, np.ndarray]] = [] + # AI 轨:PortAudio DAC 实际输出(含 underrun 时填的零) + self._ai_t_start: Optional[float] = None + #self._ai_chunks: list[np.ndarray] = [] + self._ai_chunks: list[tuple[float, np.ndarray]] = [] + # Frames + self._frames: list[tuple[float, str, int]] = [] + self._funnel_rounds: list[dict] = [] # 每轮整簇多帧+判定(统一record) + self._round_counter: int = -1 # on_funnel_round 轮次计数(qid,每轮+1) + self._transcript = None # transcript.txt 句柄 + self._subtitles = None # subtitles.jsonl 句柄 + self._chunks_f = None # model_chunks.jsonl 句柄 + + self._lock = threading.Lock() + self._started = threading.Event() + self._stopping = threading.Event() + + self._user_calls = 0 + self._ai_calls = 0 + + # ------------------------------------------------------------ + # Lifecycle + # ------------------------------------------------------------ + + def attach_to_player(self, player) -> None: + if not self.enabled: + return + orig_enqueue = player.enqueue + rec = self + + # PCSpeaker.enqueue 是 async,签名 (pcm, generation)。包装必须同签名 + async, + # 否则模型音频 enqueue 报 "takes 1 positional argument but 2 were given", + # 导致 AI 音播不出、也录不进(live 听不到声音)。 + async def wrapped_enqueue(pcm_f32, generation=0): + await orig_enqueue(pcm_f32, generation) + if (not rec._started.is_set() or rec._stopping.is_set() + or rec._t0 is None or pcm_f32 is None or pcm_f32.size == 0): + return + try: + pcm = pcm_f32 if pcm_f32.dtype == np.float32 else pcm_f32.astype(np.float32) + pcm = pcm.copy() + t = max(0.0, time.monotonic() - rec._t0) + with rec._lock: + if rec._ai_t_start is None: + rec._ai_t_start = t + rec._ai_chunks.append((t, pcm)) + rec._ai_calls += 1 + except Exception as e: + LOGGER.warning("[LIVE] enqueue hook err: %r", e) + + player.enqueue = wrapped_enqueue + player._orig_enqueue = orig_enqueue # 暴露原始方法,绕过 hook 的场景使用 + LOGGER.info("[LIVE] attached to SPK enqueue (async, pcm+generation)") + + def start(self) -> None: + if not self.enabled or self._started.is_set(): + return + assert self.dir is not None + self.dir.mkdir(parents=True, exist_ok=True) + #(self.dir / "live_images").mkdir(exist_ok=True) + self._t0 = time.monotonic() + self._started.set() + # 评分用:模型/用户的成段文本 + 时间轴(移植自 demo_esp32_duplex_0703 的 + # SessionRecorder.log_turn_text / log_subtitle)。 + # transcript.txt —— 人读,[AI #n] / [LISTEN #n] 整段 + # subtitles.jsonl —— 机读,{start_ms,end_ms,text,is_listen,turn_idx} + # is_listen=True 的 turn 就是 8021 ASR 识别出的用户说话 → 提问结束时刻 t0 从这拿 + try: + self._transcript = (self.dir / "transcript.txt").open("w", encoding="utf-8") + self._transcript.write(f"# session {self.dir.name}\n") + self._transcript.flush() + self._subtitles = (self.dir / "subtitles.jsonl").open("w", encoding="utf-8") + self._chunks_f = (self.dir / "model_chunks.jsonl").open("w", encoding="utf-8") + except Exception as e: + LOGGER.warning("[LIVE] transcript/subtitles 打开失败: %s", e) + self._transcript = None + self._subtitles = None + self._chunks_f = None + LOGGER.info( + "[LIVE] recording started: %s (user=%dHz ai=%dHz)", + self.dir, self.user_sr, self.ai_sr, + ) + + def session_ms(self) -> int: + """session 内相对毫秒(与 frames.jsonl 的 t 同一条时间轴)。""" + if self._t0 is None: + return 0 + return int((time.monotonic() - self._t0) * 1000.0) + + def log_model_chunk(self, text: str, is_listen: bool, end_of_turn: bool, + audio_ms: float = 0.0) -> None: + """逐 chunk 原始记录 —— **一条都不过滤**。 + + 这是诊断用的原始流水:-o 是 1Hz 决策,listen 期间大量 chunk 是 + text="" 且 end_of_turn=False。之前这里写了 + if not text and not end_of_turn: return + 把它们全扔了,结果 24 秒的会话只剩 5 条,看上去像"模型 5.7 秒才出一个 + chunk / 输入分块坏了"——那是记录函数造出来的假象,不是事实。 + 要判断模型节奏是否正常,必须看到每一个 chunk。 + """ + if not self.enabled or not self._started.is_set() or self.dir is None: + return + if self._chunks_f is None: + return + try: + self._chunks_f.write(json.dumps({ + "session_ms": self.session_ms(), + "text": text, + "is_listen": bool(is_listen), + "end_of_turn": bool(end_of_turn), + "audio_ms": round(float(audio_ms), 1), + }, ensure_ascii=False) + "\n") + self._chunks_f.flush() + except Exception: + pass + + def log_event(self, tag: str, text: str) -> None: + """把漏斗侧事件写进 transcript,和 USER/AI 同一条时间轴。 + + 评分时要判"这次拦截对应哪次回答",三者必须在同一条人读时间轴上: + [USER @12480ms] 这上面写的是什么 + [REJECT @13520ms] severe_shake 画面晃得厉害,请先保持不动 + [HINT @13900ms] severe_shake (2.52s) + [AI #3 @16100ms] 上面写着阿莫西林胶囊... + 机读的一份仍在 frames.jsonl(每轮 send/reason)。 + """ + if not self.enabled or not self._started.is_set() or self._transcript is None: + return + try: + self._transcript.write(f"[{tag} @{self.session_ms()}ms] {text}\n") + self._transcript.flush() + except Exception: + pass + + def log_asr(self, utterance: str, final_at_ms=None, confidence=None) -> None: + """8021 ASR 识别出的用户说话。评分取 t0 用。 + + 写两处:transcript.txt 的 [USER] 行(人读)、subtitles.jsonl 的 + is_listen=true 记录(机读,与模型 turn 同一条时间轴、同一个 session_ms 基准)。 + final_at_ms 是 8021 侧的时钟,和本 session 的 _t0 不同源,只作参考存进 + asr_events.jsonl;对齐一律用本地 session_ms()。 + """ + if not self.enabled or not self._started.is_set(): + return + t_ms = self.session_ms() + try: + if self._transcript is not None: + self._transcript.write(f"[USER @{t_ms}ms] {utterance}\n") + self._transcript.flush() + except Exception: + pass + # 复用 subtitles 的 turn 序列(负数 turn_idx 标识 ASR,避免和模型 turn 撞号) + self._asr_seq = getattr(self, "_asr_seq", 0) + 1 + self.log_subtitle(start_ms=t_ms, end_ms=t_ms, text=utterance, + is_listen=True, turn_idx=-self._asr_seq) + try: + if self.dir is not None: + with (self.dir / "asr_events.jsonl").open("a", encoding="utf-8") as f: + f.write(json.dumps({ + "session_ms": t_ms, + "utterance": utterance, + "harness_final_at_ms": final_at_ms, + "confidence": confidence, + }, ensure_ascii=False) + "\n") + except Exception: + pass + + def log_turn_text(self, turn_idx: int, text: str, is_listen: bool) -> None: + if not self.enabled or self._transcript is None: + return + tag = "LISTEN" if is_listen else "AI" + try: + self._transcript.write(f"[{tag} #{turn_idx} @{self.session_ms()}ms] {text}\n") + self._transcript.flush() + except Exception: + pass + + def log_subtitle(self, start_ms: int, end_ms: int, text: str, + is_listen: bool, turn_idx: int) -> None: + if not self.enabled or self._subtitles is None: + return + try: + self._subtitles.write(json.dumps({ + "start_ms": int(start_ms), + "end_ms": int(end_ms), + "text": text, + "is_listen": bool(is_listen), + "turn_idx": int(turn_idx), + }, ensure_ascii=False) + "\n") + self._subtitles.flush() + except Exception: + pass + + def stop(self) -> None: + if not self.enabled or not self._started.is_set() or self._stopping.is_set(): + return + self._stopping.set() + assert self._t0 is not None and self.dir is not None + total = time.monotonic() - self._t0 + + with self._lock: + user_chunks = list(self._user_chunks) + user_t_start = self._user_t_start + ai_chunks = list(self._ai_chunks) + ai_t_start = self._ai_t_start + n_frames = len(self._frames) + + u_path = self.dir / "live_user.wav" + a_path = self.dir / "live_ai.wav" + u_dur = self._write_track_wav(u_path, user_t_start, user_chunks, + self.user_sr, total) + a_dur = self._write_track_wav(a_path, ai_t_start, ai_chunks, + self.ai_sr, total) + + u_size = u_path.stat().st_size if u_path.exists() else 0 + a_size = a_path.stat().st_size if a_path.exists() else 0 + + # 写 events.jsonl(供 rerun 的 LocalImageSource 读:chunk_idx → img 映射) + try: + import json as _json + with self._lock: + frames_snap = list(self._frames) + ev_path = self.dir / "events.jsonl" + with ev_path.open("w", encoding="utf-8") as ef: + for (ft, frel, fidx) in frames_snap: + ef.write(_json.dumps( + {"kind": "chunk_sent", "idx": int(fidx), + "img": Path(frel).name, "t": round(ft, 3)}, + ensure_ascii=False) + "\n") + LOGGER.info("[LIVE] events.jsonl written: %d frames", len(frames_snap)) + except Exception as e: + LOGGER.warning("[LIVE] write events.jsonl err: %r", e) + + # 写 frames.jsonl(整簇多帧 + 判定,供 funnel rerun 重判 / 无漏斗 rerun 取代表帧) + try: + import json as _json2 + with self._lock: + rounds_snap = list(self._funnel_rounds) + fr_path = self.dir / "frames.jsonl" + with fr_path.open("w", encoding="utf-8") as ff: + for rec in rounds_snap: + ff.write(_json2.dumps(rec, ensure_ascii=False) + "\n") + LOGGER.info("[LIVE] frames.jsonl written: %d rounds", len(rounds_snap)) + except Exception as e: + LOGGER.warning("[LIVE] write frames.jsonl err: %r", e) + + u_nz = self._nonzero_ratio(user_chunks) + a_nz = self._nonzero_ratio(ai_chunks) + + LOGGER.info( + "[LIVE] stopped: wall=%.2fs " + "user(calls=%d audio=%.2fs t_start=%.2fs nonzero=%.1f%%) " + "ai(calls=%d audio=%.2fs t_start=%.2fs nonzero=%.1f%%) " + "frames=%d user_wav=%dB ai_wav=%dB", + total, + self._user_calls, u_dur, + user_t_start if user_t_start is not None else -1, u_nz * 100, + self._ai_calls, a_dur, + ai_t_start if ai_t_start is not None else -1, a_nz * 100, + n_frames, u_size, a_size, + ) + + if self._user_calls == 0: + LOGGER.warning( + "[LIVE] feed_user_raw() was NEVER called — " + "esp32_audio_reader 没把 live_rec 接进来。" + ) + if self._ai_calls == 0: + LOGGER.warning( + "[LIVE] AI callback NEVER fired — attach_to_player 没装上、" + "speaker 未启动、或开了 --no-play。" + ) + + # 关闭评分用文本落盘 + for _fh in (self._transcript, self._subtitles, self._chunks_f): + try: + if _fh is not None: + _fh.close() + except Exception: + pass + self._transcript = None + self._subtitles = None + self._chunks_f = None + + # 结束自动落盘 mp4(不用手动): + # ① 整簇多帧 + 角落 reject 标注(演示主用,流畅 + 可视化漏斗决策) + # ② best 1fps 版(兼容旧用途) + try: + self.finalize_multiframe_mp4() + except Exception as e: + LOGGER.warning("[LIVE] multiframe mp4 finalize failed: %s", e) + try: + self.finalize_mp4() + except Exception as e: + LOGGER.warning("[LIVE] mp4 finalize failed: %s", e) + + # ------------------------------------------------------------ + # Inputs + # ------------------------------------------------------------ + + def feed_user_raw(self, pcm_f32: np.ndarray,t_override: Optional[float] = None) -> None: + if (not self.enabled or not self._started.is_set() + or self._stopping.is_set() or self._t0 is None): + return + if pcm_f32 is None or pcm_f32.size == 0: + return + if pcm_f32.dtype != np.float32: + pcm_f32 = pcm_f32.astype(np.float32) + # 新增:允许调用者提供精确的音频时间轴 t 戳(rerun 场景); + # 否则按 wall clock 来(ESP32 场景) + if t_override is not None: + t = max(0.0, t_override) + else: + t = max(0.0, time.monotonic() - self._t0) + #t = max(0.0, time.monotonic() - self._t0) + with self._lock: + if self._user_t_start is None: + self._user_t_start = t + rms = float(np.sqrt(np.mean(pcm_f32 ** 2))) + LOGGER.info("[LIVE] first feed_user_raw(): %d samples rms=%.4f t=%.2fs", + pcm_f32.size, rms, t) + self._user_chunks.append((t, pcm_f32.copy())) + self._user_calls += 1 + + def on_frame(self, jpeg_bytes: Optional[bytes], chunk_idx: int) -> None: + if (not self.enabled or not self._started.is_set() + or self._stopping.is_set() or not jpeg_bytes + or self._t0 is None or self.dir is None): + return + t = time.monotonic() - self._t0 + rel = f"images/img_{chunk_idx:05d}.jpg" + # 实际写 jpg 落盘(供 rerun 的 LocalImageSource 读)。 + try: + img_dir = self.dir / "images" + img_dir.mkdir(parents=True, exist_ok=True) + if not self.no_media: + (self.dir / rel).write_bytes(jpeg_bytes) + except Exception as e: + LOGGER.warning("[LIVE] write frame jpg err: %r", e) + return + with self._lock: + self._frames.append((t, rel, int(chunk_idx))) + + def on_funnel_round(self, decision, chunk_idx: int, text: str = "") -> None: + """存漏斗一轮:整簇多帧(筛前原始)落盘 q{NNN}_f{MM}.jpg + frames.jsonl 记一条。 + 统一 record 的核心:一份 record 供三种 rerun—— + 无漏斗 rerun(每轮取代表帧)/ funnel rerun(整簇重判)/ -o rerun(取当时best)。 + """ + if (not self.enabled or not self._started.is_set() + or self._stopping.is_set() or self._t0 is None or self.dir is None): + return + t = time.monotonic() - self._t0 + frames = getattr(decision, "frames", None) + if not frames: + b = getattr(decision, "best", None) or getattr(decision, "best_jpg", None) + frames = [b] if b else [] + # qid 用独立轮次计数(每轮 +1),不能用 latest_frame.sequence—— + # 那个只在 send 时递增,一直 reject(晃动/糊)时不变 → qid 不变 → 整簇 jpg + # 反复用同名 q{同值}_fNN 覆盖旧图,record 存不下、rerun 没图。 + self._round_counter = getattr(self, "_round_counter", -1) + 1 + qid = self._round_counter + frame_names = [] + try: + img_dir = self.dir / "images" + img_dir.mkdir(parents=True, exist_ok=True) + for i, jpg in enumerate(frames): + if not jpg: + continue + name = f"q{qid:05d}_f{i:02d}.jpg" + if not self.no_media: + (img_dir / name).write_bytes(jpg) + frame_names.append(name) + except Exception as e: + LOGGER.warning("[LIVE] on_funnel_round write err: %r", e) + return + rec = { + "qid": qid, + "t": round(t, 3), + "chunk_idx": int(chunk_idx), + "frames": frame_names, + "best_index": getattr(decision, "best_index", None), + "send": bool(getattr(decision, "send", False)), + "reason": getattr(decision, "reason", ""), + "text": text, + } + with self._lock: + self._funnel_rounds.append(rec) + + # ------------------------------------------------------------ + # WAV writing + # ------------------------------------------------------------ + + @staticmethod + def _nonzero_ratio(chunks: list[tuple[float, np.ndarray]]) -> float: + if not chunks: + return 0.0 + total, nz = 0, 0 + for _, pcm in chunks: + total += pcm.size + nz += int(np.sum(np.abs(pcm) > 1e-4)) + return (nz / total) if total > 0 else 0.0 + + @staticmethod + def _write_track_wav( + path: Path, + t_start: Optional[float], # 仅用于日志兼容,不再决定起点 + chunks: list[tuple[float, np.ndarray]], + sr: int, + wall_dur: float, + ) -> float: + """录屏式写盘:每个 chunk 落在它真实的 arrival 时间上,空隙留 0。""" + if not chunks: + n_total = max(int(wall_dur * sr), 1) + track = np.zeros(n_total, dtype=np.float32) + audio_dur = 0.0 + else: + # 计算总长 = max(最后一段尾巴, wall_dur) + end_time = max(t + pcm.size / sr for t, pcm in chunks) + n_total = max(int(max(end_time, wall_dur) * sr), 1) + track = np.zeros(n_total, dtype=np.float32) + audio_dur = 0.0 # 这里改为"有效样本"的累计,不再是 concat 长度 + prev_end_samp = 0 + for t, pcm in chunks: + i = max(0, int(t * sr)) + # 防止下一段的 arrival time 小于上一段结束——重叠时按上一段尾巴顺延 + i = max(i, prev_end_samp) + j = min(i + pcm.size, n_total) + if j > i: + track[i:j] = pcm[: j - i] + prev_end_samp = j + audio_dur += (j - i) / sr + + i16 = np.clip(track * 32768.0, -32768, 32767).astype(np.int16) + with wave.open(str(path), "wb") as w: + w.setnchannels(1); + w.setsampwidth(2); + w.setframerate(sr) + w.writeframes(i16.tobytes()) + return audio_dur + + # ------------------------------------------------------------ + # MP4 finalize + # ------------------------------------------------------------ + + def finalize_mp4(self) -> Optional[Path]: + if self.no_media: + return None + if not self.enabled or self.dir is None: + return None + if shutil.which("ffmpeg") is None: + LOGGER.warning("[LIVE] ffmpeg not found. WAV/帧已保存在 %s。", self.dir) + return None + main_out = None + + + try: + main_out = self._do_finalize_mp4() + except Exception as e: + LOGGER.warning("[LIVE] mp4 finalize failed: %s", e) + # 额外合成一份 user-only,用于 gateway 8006 视频输入测试 + try: + self._do_finalize_useronly_mp4() + except Exception as e: + LOGGER.warning("[LIVE] useronly mp4 finalize failed: %s", e) + return main_out + + def _do_finalize_useronly_mp4(self) -> Optional[Path]: + """额外合成一份只含 user 音轨的 mp4,用于给 gateway 的 8006 视频输入端做 fixture 测试。""" + d = self.dir + assert d is not None + user_wav = d / "live_user.wav" + if not user_wav.exists(): + LOGGER.info("[LIVE] no user wav, skip useronly mp4") + return None + + with wave.open(str(user_wav), "rb") as w: + u_dur = w.getnframes() / w.getframerate() + if u_dur <= 0.5: + LOGGER.info("[LIVE] user too short (%.2fs), skip useronly mp4", u_dur) + return None + + with self._lock: + frames = list(self._frames) + + concat_txt = d / "_useronly_frames.txt" + if frames: + with concat_txt.open("w", encoding="utf-8") as f: + f.write("ffconcat version 1.0\n") + first_t = frames[0][0] + if first_t > 0.05: + f.write(f"file '{frames[0][1]}'\n") + f.write(f"duration {first_t:.3f}\n") + for i, (rt, p, _idx) in enumerate(frames): + f.write(f"file '{p}'\n") + if i + 1 < len(frames): + dur = max(0.04, frames[i + 1][0] - rt) + else: + dur = max(0.5, u_dur - rt) + f.write(f"duration {dur:.3f}\n") + f.write(f"file '{frames[-1][1]}'\n") + + if not frames: + out = d / "live_useronly.m4a" + cmd = [ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "warning", + "-i", str(user_wav), + "-c:a", "aac", "-b:a", "192k", + "-ac", "1", + "-t", f"{u_dur:.3f}", + str(out), + ] + else: + out = d / "live_useronly.mp4" + cmd = [ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "warning", + "-f", "concat", "-safe", "0", "-i", str(concat_txt), + "-i", str(user_wav), + "-map", "0:v", "-map", "1:a", + "-c:v", "libx264", "-preset", "medium", "-crf", "18", "-pix_fmt", "yuv420p", + "-vsync", "vfr", + "-c:a", "aac", "-b:a", "192k", + "-ac", "1", + "-t", f"{u_dur:.3f}", + str(out), + ] + + LOGGER.info( + "[LIVE] assembling useronly: frames=%d u_dur=%.1fs → %s", + len(frames), u_dur, out.name, + ) + try: + r = subprocess.run(cmd, capture_output=True, text=True, timeout=600) + if r.returncode != 0: + LOGGER.warning("[LIVE] useronly ffmpeg rc=%d stderr tail:\n%s", + r.returncode, r.stderr[-1200:]) + return None + if out.exists(): + LOGGER.info("[LIVE] ✅ saved %s (%.1f MB, %.1fs)", + out, out.stat().st_size / 1e6, u_dur) + return out + except subprocess.TimeoutExpired: + LOGGER.warning("[LIVE] useronly ffmpeg timeout (>10min)") + return None + finally: + try: + if concat_txt.exists(): + concat_txt.unlink() + except Exception: + pass + def _do_finalize_mp4(self) -> Optional[Path]: + d = self.dir + assert d is not None + user_wav = d / "live_user.wav" + ai_wav = d / "live_ai.wav" + if not (user_wav.exists() and ai_wav.exists()): + LOGGER.info("[LIVE] no wav files, skip mp4") + return None + + with self._lock: + frames = list(self._frames) + + with wave.open(str(user_wav), "rb") as w: + u_dur = w.getnframes() / w.getframerate() + with wave.open(str(ai_wav), "rb") as w: + a_dur = w.getnframes() / w.getframerate() + total_dur = max(u_dur, a_dur) + if total_dur <= 0.5: + LOGGER.info("[LIVE] session too short (%.2fs), skip mp4", total_dur) + return None + + concat_txt = d / "_live_frames.txt" + if frames: + with concat_txt.open("w", encoding="utf-8") as f: + f.write("ffconcat version 1.0\n") + first_t = frames[0][0] + if first_t > 0.05: + f.write(f"file '{frames[0][1]}'\n") + f.write(f"duration {first_t:.3f}\n") + for i, (rt, p, _idx) in enumerate(frames): + f.write(f"file '{p}'\n") + if i + 1 < len(frames): + dur = max(0.04, frames[i + 1][0] - rt) + else: + dur = max(0.5, total_dur - rt) + f.write(f"duration {dur:.3f}\n") + f.write(f"file '{frames[-1][1]}'\n") + + # apad + -t 让短的一轨自动补尾静音对齐到 mp4 总时长 + if not frames: + out = d / "live_session.m4a" + cmd = [ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "warning", + "-i", str(user_wav), "-i", str(ai_wav), + "-filter_complex", + "[0:a]aresample=24000,aformat=channel_layouts=mono,apad[u];" + "[1:a]aformat=channel_layouts=mono,apad[a];" + "[u][a]amerge=inputs=2[aout]", + "-map", "[aout]", + "-c:a", "aac", "-b:a", "192k", + "-t", f"{total_dur:.3f}", + str(out), + ] + else: + out = d / "live_session.mp4" + cmd = [ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "warning", + "-f", "concat", "-safe", "0", "-i", str(concat_txt), + "-i", str(user_wav), "-i", str(ai_wav), + "-filter_complex", + "[1:a]aresample=24000,aformat=channel_layouts=mono,apad[u];" + "[2:a]aformat=channel_layouts=mono,apad[a];" + "[u][a]amerge=inputs=2[aout]", + "-map", "0:v", "-map", "[aout]", + #"-c:v", "libx264", "-preset", "veryfast", "-pix_fmt", "yuv420p", + "-c:v", "libx264", "-preset", "medium", "-crf", "18", "-pix_fmt", "yuv420p", + "-vsync", "vfr", + "-c:a", "aac", "-b:a", "192k", + "-t", f"{total_dur:.3f}", + str(out), + ] + + LOGGER.info( + "[LIVE] assembling: frames=%d total=%.1fs (u=%.1fs a=%.1fs) → %s", + len(frames), total_dur, u_dur, a_dur, out.name, + ) + try: + r = subprocess.run(cmd, capture_output=True, text=True, timeout=600) + if r.returncode != 0: + LOGGER.warning( + "[LIVE] ffmpeg rc=%d stderr tail:\n%s", + r.returncode, r.stderr[-1200:], + ) + return None + if out.exists(): + LOGGER.info( + "[LIVE] ✅ saved %s (%.1f MB, %.1fs)", + out, out.stat().st_size / 1e6, total_dur, + ) + return out + except subprocess.TimeoutExpired: + LOGGER.warning("[LIVE] ffmpeg timeout (>10min)") + return None + finally: + try: + if concat_txt.exists(): + concat_txt.unlink() + except Exception: + pass + + + # ------------------------------------------------------------ + # 整簇多帧 mp4(演示用):用每轮整簇多帧拼,比 1fps best 流畅; + # 角落用 ass 字幕标注每轮 send/reject + reason,直接可视化漏斗决策。 + # 对比无漏斗/有漏斗两份 mp4,即可证明"模糊图被拒、不进模型"的正确性。 + # ------------------------------------------------------------ + def _ass_escape(self, s: str) -> str: + return (s or "").replace("\\", "\\\\").replace("{", "(").replace("}", ")") + + def _gen_reject_ass(self, rounds, total_dur: float) -> Optional[Path]: + """生成角落标注字幕:每轮时间段显示 SEND / REJECT:reason。""" + d = self.dir + if d is None or not rounds: + return None + def _fmt(t): + t = max(0.0, t) + h = int(t // 3600); m = int((t % 3600) // 60) + s = t % 60 + return f"{h:d}:{m:02d}:{s:05.2f}" + ass = d / "_reject_notes.ass" + header = ( + "[Script Info]\nScriptType: v4.00+\nPlayResX: 1280\nPlayResY: 720\n\n" + "[V4+ Styles]\n" + "Format: Name, Fontname, Fontsize, PrimaryColour, Bold, Alignment, " + "MarginL, MarginR, MarginV, BorderStyle, Outline, Shadow\n" + # Alignment 9 = 右上角;红=&H000000FF 绿=&H0000FF00 (ASS 是 &HAABBGGRR) + "Style: REJ,Arial,36,&H000000FF,1,9,20,20,20,1,2,0\n" + "Style: SND,Arial,36,&H0000FF00,1,9,20,20,20,1,2,0\n\n" + "[Events]\nFormat: Layer, Start, End, Style, Text\n" + ) + lines = [] + for i, rec in enumerate(rounds): + t0 = float(rec.get("t", i)) + t1 = float(rounds[i + 1].get("t", t0 + 1.0)) if i + 1 < len(rounds) else total_dur + if t1 <= t0: + t1 = t0 + 0.3 + send = bool(rec.get("send")) + reason = self._ass_escape(rec.get("reason", "")) + if send: + style, txt = "SND", "SEND ✓" + else: + style, txt = "REJ", f"REJECT ✗ {reason}" + lines.append(f"Dialogue: 0,{_fmt(t0)},{_fmt(t1)},{style},,{txt}") + try: + ass.write_text(header + "\n".join(lines) + "\n", encoding="utf-8") + return ass + except Exception as e: + LOGGER.warning("[LIVE] write reject ass err: %r", e) + return None + + def finalize_multiframe_mp4(self) -> Optional[Path]: + if self.no_media: + return None + """整簇多帧 mp4 + 角落 reject 标注。演示用,比 best 1fps 流畅。""" + if not self.enabled or self.dir is None: + return None + if shutil.which("ffmpeg") is None: + LOGGER.warning("[LIVE] ⚠ ffmpeg 未安装,无法生成 mp4!" + "装法: conda install -c conda-forge ffmpeg。" + "帧和 wav 已存在 %s,可手动拼。", self.dir) + return None + d = self.dir + user_wav = d / "live_user.wav" + ai_wav = d / "live_ai.wav" + if not (user_wav.exists() and ai_wav.exists()): + return None + with self._lock: + rounds = list(self._funnel_rounds) + if not rounds: + LOGGER.info("[LIVE] no funnel rounds, skip multiframe mp4") + return None + + with wave.open(str(user_wav), "rb") as w: + u_dur = w.getnframes() / w.getframerate() + with wave.open(str(ai_wav), "rb") as w: + a_dur = w.getnframes() / w.getframerate() + total_dur = max(u_dur, a_dur) + if total_dur <= 0.5: + return None + + # 整簇多帧 concat:每轮的 t 到下一轮的 t 之间,均分给该轮的 N 帧(高 fps) + concat_txt = d / "_multiframe.txt" + with concat_txt.open("w", encoding="utf-8") as f: + f.write("ffconcat version 1.0\n") + first_t = float(rounds[0].get("t", 0.0)) + if first_t > 0.05 and rounds[0].get("frames"): + f.write(f"file 'images/{Path(rounds[0]['frames'][0]).name}'\n") + f.write(f"duration {first_t:.3f}\n") + for i, rec in enumerate(rounds): + names = rec.get("frames") or [] + if not names: + continue + t0 = float(rec.get("t", i)) + t1 = float(rounds[i + 1].get("t", t0 + 1.0)) if i + 1 < len(rounds) else total_dur + round_dur = max(0.12, t1 - t0) + per = round_dur / len(names) # 整簇内多帧均分 → 高 fps + for nm in names: + f.write(f"file 'images/{Path(nm).name}'\n") + f.write(f"duration {max(0.03, per):.3f}\n") + # 末帧兜底 + last_names = rounds[-1].get("frames") or [] + if last_names: + f.write(f"file 'images/{Path(last_names[-1]).name}'\n") + + ass = self._gen_reject_ass(rounds, total_dur) + vf = "format=yuv420p" + if ass is not None: + safe = str(ass.name) # 相对 cwd 需在 dir 下运行;用绝对更稳 + abs_ass = str(ass.resolve()).replace("\\", "/").replace(":", "\\:") + vf = f"ass='{abs_ass}',format=yuv420p" + + out = d / "live_multiframe.mp4" + cmd = [ + "ffmpeg", "-y", "-hide_banner", "-loglevel", "warning", + "-f", "concat", "-safe", "0", "-i", str(concat_txt), + "-i", str(user_wav), "-i", str(ai_wav), + "-filter_complex", + "[1:a]aresample=24000,aformat=channel_layouts=mono,apad[u];" + "[2:a]aformat=channel_layouts=mono,apad[a];" + "[u][a]amerge=inputs=2[aout]", + "-map", "0:v", "-map", "[aout]", + "-vf", vf, + "-c:v", "libx264", "-preset", "medium", "-crf", "20", "-pix_fmt", "yuv420p", + "-vsync", "vfr", + "-c:a", "aac", "-b:a", "192k", + "-t", f"{total_dur:.3f}", + str(out), + ] + LOGGER.info("[LIVE] assembling multiframe mp4: rounds=%d total=%.1fs → %s", + len(rounds), total_dur, out.name) + try: + r = subprocess.run(cmd, capture_output=True, text=True, timeout=600) + if r.returncode != 0: + LOGGER.warning("[LIVE] multiframe ffmpeg rc=%d stderr:\n%s", + r.returncode, r.stderr[-1200:]) + return None + if out.exists(): + LOGGER.info("[LIVE] ✅ multiframe mp4 saved %s (%.1f MB)", + out, out.stat().st_size / 1e6) + return out + except subprocess.TimeoutExpired: + LOGGER.warning("[LIVE] multiframe ffmpeg timeout") + return None + finally: + for p in (concat_txt, ass): + try: + if p is not None and p.exists(): + p.unlink() + except Exception: + pass diff --git a/extensions/assistive_harness/phase_b/requirements-phase-b.txt b/extensions/assistive_harness/phase_b/requirements-phase-b.txt new file mode 100644 index 0000000..a247f64 --- /dev/null +++ b/extensions/assistive_harness/phase_b/requirements-phase-b.txt @@ -0,0 +1,4 @@ +aiohttp>=3.13 +Pillow>=10 +sounddevice>=0.5 + diff --git a/extensions/assistive_harness/phase_b/rerun_source.py b/extensions/assistive_harness/phase_b/rerun_source.py new file mode 100644 index 0000000..448862d --- /dev/null +++ b/extensions/assistive_harness/phase_b/rerun_source.py @@ -0,0 +1,368 @@ +"""rerun_source.py — 用已录制 session 当输入重跑模型 + +替换主脚本里的两个网络输入函数: + - esp32_audio_reader → local_pcm_reader + - esp32_capture_image → LocalImageSource.capture +""" + +from __future__ import annotations + +import asyncio +import json +import logging +import time +from pathlib import Path +from typing import Optional + +import numpy as np +import sounddevice as sd +import threading + + +LOGGER = logging.getLogger("rerun_source") + +_PACKET_MS = 40 +_PACKET_SAMPLES = 640 +_SAMPLE_RATE = 16000 + + +class _UserMonitor: + """独立 PortAudio OutputStream,用于 rerun 时播放 user 监听音频。 + + 为什么不复用主 SpeakerPlayer:主 speaker 是单 FIFO ring, + AI 和 user 两路 enqueue 共享同一个 ring 时,DAC 按入队顺序消费会 + 导致 AI 音频被 user 音频"插队"——听感是 AI 输出卡顿。 + + 独立 OutputStream 由 OS 端混音(同一声卡时钟驱动),物理上不互相挤压。 + """ + + def __init__(self, sample_rate: int = 24000, ring_capacity_s: float = 2.0): + self.sr = int(sample_rate) + self.ring_cap = int(ring_capacity_s * self.sr) + self._buf = np.zeros(self.ring_cap, dtype=np.float32) + self._r = 0 + self._w = 0 + self._size = 0 + self._lock = threading.Lock() + self._dropped = 0 + try: + self._stream = sd.OutputStream( + samplerate=self.sr, channels=1, dtype="float32", + blocksize=0, callback=self._cb, + ) + self._stream.start() + LOGGER.info("[RERUN-MON] user monitor stream started: sr=%d ring=%.1fs", + self.sr, ring_capacity_s) + except Exception as e: + LOGGER.warning("[RERUN-MON] failed to open OutputStream: %r", e) + self._stream = None + + def _cb(self, outdata, frames, time_info, status): + with self._lock: + avail = min(frames, self._size) + if avail > 0: + first = min(avail, self.ring_cap - self._r) + outdata[:first, 0] = self._buf[self._r:self._r + first] + if avail > first: + outdata[first:avail, 0] = self._buf[:avail - first] + self._r = (self._r + avail) % self.ring_cap + self._size -= avail + if avail < frames: + outdata[avail:, 0] = 0.0 + + def enqueue(self, pcm_f32: np.ndarray) -> None: + if self._stream is None or pcm_f32 is None or pcm_f32.size == 0: + return + if pcm_f32.dtype != np.float32: + pcm_f32 = pcm_f32.astype(np.float32) + n = pcm_f32.size + if n > self.ring_cap: + pcm_f32 = pcm_f32[-self.ring_cap:] + n = pcm_f32.size + with self._lock: + if self._size + n > self.ring_cap: + drop = (self._size + n) - self.ring_cap + self._r = (self._r + drop) % self.ring_cap + self._size -= drop + self._dropped += drop + first = min(n, self.ring_cap - self._w) + self._buf[self._w:self._w + first] = pcm_f32[:first] + if n > first: + self._buf[:n - first] = pcm_f32[first:n] + self._w = (self._w + n) % self.ring_cap + self._size += n + + def stop(self) -> None: + if self._stream is None: + return + try: + self._stream.stop() + self._stream.close() + except Exception as e: + LOGGER.warning("[RERUN-MON] stop err: %r", e) + finally: + self._stream = None + LOGGER.info("[RERUN-MON] user monitor stopped (dropped=%d samples)", + self._dropped) + + + +async def local_pcm_reader( + pcm_path: Path, + ring, + stop_evt: asyncio.Event, + stats, + live_rec=None, + speaker=None, # ← 新增 + speaker_sr: int = 24000, # ← 新增:speaker 期望的采样率 + speed: float = 1.0, + drain_s: float = 5.0, + prefill_s: float = 0.0, +) -> None: + pcm_path = Path(pcm_path) + if not pcm_path.exists(): + LOGGER.error("[RERUN] pcm not found: %s", pcm_path) + stop_evt.set() + return + + # 优先用 live_user.wav (LiveRecorder 直接写的,干净); + # 回退用 user_raw.pcm (主循环 ring.slice 落盘的,带 40% 零填充) + import wave + wav_path = pcm_path.parent / "live_user.wav" + pcm_i16 = None + src_label = "" + if wav_path.exists(): + try: + with wave.open(str(wav_path), "rb") as w: + sr_in = w.getframerate() + nch = w.getnchannels() + sw = w.getsampwidth() + if sr_in == _SAMPLE_RATE and nch == 1 and sw == 2: + pcm_i16 = np.frombuffer(w.readframes(w.getnframes()), dtype=np.int16) + src_label = f"live_user.wav (clean, {sr_in}Hz mono int16)" + else: + LOGGER.warning( + "[RERUN] live_user.wav format unexpected (sr=%d ch=%d sw=%d), " + "fallback to user_raw.pcm", sr_in, nch, sw, + ) + except Exception as e: + LOGGER.warning("[RERUN] failed to read live_user.wav: %r, fallback to user_raw.pcm", e) + pcm_i16 = None + + if pcm_i16 is None: + raw = pcm_path.read_bytes() + pcm_i16 = np.frombuffer(raw, dtype=np.int16) + src_label = "user_raw.pcm (may contain ring.slice zero-padding)" + + total_samples = pcm_i16.size + total_dur = total_samples / _SAMPLE_RATE + LOGGER.info("[RERUN] audio source: %s", src_label) + # rerun 用户监听:独立 OutputStream,避免和 AI 共用 ring 导致互相卡顿 + user_mon = None + if speaker is not None: + try: + user_mon = _UserMonitor(sample_rate=speaker_sr) + except Exception as e: + LOGGER.warning("[RERUN] failed to create user monitor: %r", e) + user_mon = None + + + LOGGER.info( + "[RERUN] pcm loaded: %s samples=%d dur=%.2fs speed=%.2fx prefill=%.1fs", + pcm_path, total_samples, total_dur, speed, prefill_s, + ) + + packet_interval = (_PACKET_MS / 1000.0) / max(speed, 0.01) + ts_ms = 0 + cursor = 0 + pkt_count = 0 + prefill_packets = int(prefill_s * 1000 / _PACKET_MS) + next_tick = time.monotonic() # ← 改:不再 + prefill_s + audio_t_start = None + while cursor < total_samples and not stop_evt.is_set(): + end = min(cursor + _PACKET_SAMPLES, total_samples) + chunk_i16 = pcm_i16[cursor:end] + cursor = end + pkt_count += 1 + + try: + stats["rx_pkts"] = pkt_count + stats["esp_drops"] = 0 + except Exception: + pass + + try: + await ring.write(ts_ms, chunk_i16) + except Exception as e: + LOGGER.warning("[RERUN] ring.write err: %r", e) + + if live_rec is not None: + try: + # ↓ 关键改动:用"累计音频时长"作为 t 戳,而不是 wall clock + # 这样 LiveRecorder 写盘时 t * sr 算出来的 i 与 pcm.size 完美对齐 + if audio_t_start is None: + audio_t_start = time.monotonic() - live_rec._t0 if live_rec._t0 else 0.0 + audio_t = audio_t_start + ts_ms / 1000.0 + live_rec.feed_user_raw( + chunk_i16.astype(np.float32) / 32768.0, + t_override=audio_t, + ) + # rerun 模式:把 user 音频也推给扬声器,这样能听到原录制的用户在说什么 + # (live 模式不这么做,因为用户本人就在那说话,会和扬声器叠加。 + # rerun 是事后回放,没回声风险,等同 8006 浏览器播 mp4 的体验) + if user_mon is not None: + try: + chunk_f32 = chunk_i16.astype(np.float32) / 32768.0 + if speaker_sr != _SAMPLE_RATE: + ratio = speaker_sr / _SAMPLE_RATE + new_len = int(chunk_f32.size * ratio) + x_old = np.linspace(0, 1, chunk_f32.size, endpoint=False) + x_new = np.linspace(0, 1, new_len, endpoint=False) + chunk_resampled = np.interp(x_new, x_old, chunk_f32).astype(np.float32) + else: + chunk_resampled = chunk_f32 + # 关键:走原始 enqueue,不走 LiveRecorder hook + # (hook 会把这条用户音频错误地累积进 _ai_chunks, + # 导致 mp4 的 ai 轨里也有用户声音,听起来像"用户被录了两次") + user_mon.enqueue(chunk_resampled) + except Exception as e: + LOGGER.warning("[RERUN] speaker.enqueue err: %r", e) + + #live_rec.feed_user_raw(chunk_i16.astype(np.float32) / 32768.0) + except Exception as e: + LOGGER.warning("[RERUN] live_rec.feed_user_raw err: %r", e) + + ts_ms += _PACKET_MS + + # prefill 阶段:让出事件循环但不真睡 + if pkt_count <= prefill_packets: + await asyncio.sleep(0) + continue + + # prefill → realtime 切换那一刻,重置基线 + if pkt_count == prefill_packets + 1: + LOGGER.info( + "[RERUN] prefill done (%d packets, %.2fs audio in ring), " + "switching to realtime pacing", + prefill_packets, prefill_packets * _PACKET_MS / 1000.0, + ) + next_tick = time.monotonic() # ← 关键:基线重置到此刻 + + next_tick += packet_interval + sleep_for = next_tick - time.monotonic() + if sleep_for > 0: + try: + await asyncio.wait_for(stop_evt.wait(), timeout=sleep_for) + break # 被外部 stop:跳出推流循环,仍走下面的 drain(等模型说完) + except asyncio.TimeoutError: + pass + + try: + stats["audio_done"] = True + stats["audio_done_ts"] = time.monotonic() + except Exception: + pass + + LOGGER.info( + "[RERUN] pcm exhausted: pushed=%d packets (%.2fs audio). draining...", + pkt_count, ts_ms / 1000.0, + ) + + # 音频已推完并标记 audio_done。结束的裁决权交给主 send loop: + # 它会在 audio_done 后等模型说完(轮询 last_speak_ts)再 set stop_evt。 + # reader 这里只需等待那个信号;带兜底上限防止异常卡死。 + max_wait_s = 120.0 + waited = 0.0 + while waited < max_wait_s and not stop_evt.is_set(): + try: + await asyncio.wait_for(stop_evt.wait(), timeout=0.2) + break + except asyncio.TimeoutError: + waited += 0.2 + if waited >= max_wait_s: + LOGGER.warning("[RERUN] drain 达到上限 %.0fs,强制结束", max_wait_s) + + if user_mon is not None: + user_mon.stop() + + if not stop_evt.is_set(): + LOGGER.info("[RERUN] drain done, signaling stop") + stop_evt.set() + + +class LocalImageSource: + def __init__(self, session_dir: Path): + self.session_dir = Path(session_dir) + self.images_dir = self.session_dir / "images" + self.events_path = self.session_dir / "events.jsonl" + + if not self.images_dir.exists(): + raise FileNotFoundError(f"images/ not found: {self.images_dir}") + if not self.events_path.exists(): + raise FileNotFoundError(f"events.jsonl not found: {self.events_path}") + + self._map: dict[int, Optional[str]] = {} + self._build_map() + + n_total = len(self._map) + n_with_img = sum(1 for v in self._map.values() if v) + LOGGER.info( + "[RERUN] image map: total_chunks=%d with_image=%d (missing=%d) from %s", + n_total, n_with_img, n_total - n_with_img, self.events_path.name, + ) + if n_total == 0: + # ← 新增:诊断空 events.jsonl + n_files = len(list(self.images_dir.glob("img_*.jpg"))) + LOGGER.warning( + "[RERUN] events.jsonl has NO chunk_sent entries! " + "but images/ has %d files. Falling back to filename-order matching.", + n_files, + ) + self._fallback_filename_order(n_files) + + def _build_map(self) -> None: + with self.events_path.open("r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line: + continue + try: + evt = json.loads(line) + except Exception: + continue + # ← 改 1:看实际 events.jsonl 用什么 kind 字段 + kind = evt.get("kind") or evt.get("type") or "" + if kind != "chunk_sent": + continue + # ← 改 2:chunk_idx 字段名兼容 + idx = evt.get("idx", evt.get("chunk_idx")) + img = evt.get("img") + if idx is None: + continue + self._map[int(idx)] = img if img else None + + def _fallback_filename_order(self, n_files: int) -> None: + """events.jsonl 是空的时候的兜底:按 img_NNNNN.jpg 文件名映射 chunk_idx。""" + for p in sorted(self.images_dir.glob("img_*.jpg")): + try: + # 文件名形如 img_00007.jpg → 7 + idx = int(p.stem.split("_")[-1]) + self._map[idx] = p.name + except Exception: + pass + LOGGER.info("[RERUN] fallback map built: %d chunks (filename-order)", + len(self._map)) + + async def capture(self, chunk_idx: int) -> Optional[bytes]: + rel = self._map.get(int(chunk_idx)) + if not rel: + return None + name = Path(rel).name + path = self.images_dir / name + if not path.exists(): + return None + try: + return path.read_bytes() + except Exception as e: + LOGGER.warning("[RERUN] image read err: %r", e) + return None \ No newline at end of file diff --git a/extensions/assistive_harness/phase_b/rokid_runtime.py b/extensions/assistive_harness/phase_b/rokid_runtime.py new file mode 100644 index 0000000..af9f8cc --- /dev/null +++ b/extensions/assistive_harness/phase_b/rokid_runtime.py @@ -0,0 +1,1703 @@ +from __future__ import annotations + +import argparse +import asyncio +import base64 +import io +import json +import logging +import os +import signal +import ssl +import threading +import time +import uuid +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any, Awaitable, Callable, Protocol + +import aiohttp +from aiohttp import web +import numpy as np + +from ..registry import SkillRegistry + +try: + from PIL import Image +except Exception: # pragma: no cover - optional at import time + Image = None + + +LOG = logging.getLogger("assistive_harness.phase_b.rokid") +SAMPLE_RATE_IN = 16_000 +SAMPLE_RATE_OUT = 24_000 +PCM16_WIDTH = 2 +CTRL_C_HARD_EXIT_S = 10.0 + + +def now_ms() -> float: + return time.time() * 1000.0 + + +class CtrlCExitWatchdog: + """Guarantee that a Windows Ctrl+C cannot leave the Rokid port behind.""" + + def __init__(self, hard_exit_s: float = CTRL_C_HARD_EXIT_S): + self.hard_exit_s = max(1.0, float(hard_exit_s)) + self._armed = False + self._lock = threading.Lock() + + @property + def armed(self) -> bool: + return self._armed + + def arm(self) -> None: + with self._lock: + if self._armed: + return + self._armed = True + LOG.info( + "Console interrupt received; closing Rokid listener and runtime " + "(hard cutoff %.1fs)", + self.hard_exit_s, + ) + threading.Thread( + target=self._force_exit_after_deadline, + name="rokid-ctrl-c-watchdog", + daemon=True, + ).start() + + def _force_exit_after_deadline(self) -> None: + time.sleep(self.hard_exit_s) + LOG.error( + "Rokid shutdown exceeded %.1fs; forcing process exit so port 18080 " + "cannot remain occupied", + self.hard_exit_s, + ) + logging.shutdown() + os._exit(130) + + +def pcm16le_to_float32(raw: bytes) -> np.ndarray: + if len(raw) % PCM16_WIDTH: + raw = raw[:-1] + if not raw: + return np.zeros(0, dtype=np.float32) + return ( + np.frombuffer(raw, dtype=" bytes: + """Apply device-specific gain with saturation while preserving PCM16 LE.""" + if gain <= 0: + raise ValueError("input gain must be greater than zero") + if gain == 1.0 or not raw: + return raw + samples = np.frombuffer(raw, dtype=" np.ndarray: + """Return a short, non-speech two-note cue for restart_complete.""" + + amplitude = min(1.0, max(0.0, float(amplitude))) + + def tone(frequency_hz: float, duration_s: float) -> np.ndarray: + count = max(2, int(sample_rate * duration_s)) + phase = np.arange(count, dtype=np.float32) / float(sample_rate) + envelope = np.sin(np.linspace(0.0, np.pi, count, dtype=np.float32)) ** 2 + return ( + amplitude + * envelope + * np.sin(2.0 * np.pi * frequency_hz * phase) + ).astype(np.float32) + + gap = np.zeros(max(1, int(sample_rate * 0.030)), dtype=np.float32) + return np.concatenate((tone(880.0, 0.080), gap, tone(1174.66, 0.105))) + + +def float32_to_base64(samples: np.ndarray) -> str: + return base64.b64encode( + samples.astype(np.float32, copy=False).tobytes() + ).decode("ascii") + + +def same_slots(left: dict[str, Any], right: dict[str, Any]) -> bool: + return {str(key): str(value) for key, value in left.items()} == { + str(key): str(value) for key, value in right.items() + } + + +def rotate_jpeg_clockwise(jpeg: bytes, degrees: int, quality: int = 95) -> bytes: + degrees %= 360 + if degrees == 0 or Image is None: + return jpeg + methods = { + 90: Image.Transpose.ROTATE_270, + 180: Image.Transpose.ROTATE_180, + 270: Image.Transpose.ROTATE_90, + } + method = methods.get(degrees) + if method is None: + raise ValueError("image rotation must be 0, 90, 180, or 270") + with Image.open(io.BytesIO(jpeg)) as image: + output = io.BytesIO() + image.convert("RGB").transpose(method).save( + output, format="JPEG", quality=quality + ) + return output.getvalue() + + +class DropOldestAudioQueue: + """Bounded device-audio queue that always preserves the newest packets.""" + + def __init__(self, max_packets: int): + self._queue: asyncio.Queue[bytes] = asyncio.Queue(maxsize=max(1, max_packets)) + self.dropped_packets = 0 + + @property + def size(self) -> int: + return self._queue.qsize() + + def put_nowait(self, raw: bytes) -> None: + if self._queue.full(): + try: + self._queue.get_nowait() + self.dropped_packets += 1 + except asyncio.QueueEmpty: + pass + self._queue.put_nowait(raw) + + async def get(self, timeout_s: float) -> bytes | None: + try: + return await asyncio.wait_for(self._queue.get(), timeout=timeout_s) + except asyncio.TimeoutError: + return None + + def clear(self) -> int: + cleared = 0 + while True: + try: + self._queue.get_nowait() + cleared += 1 + except asyncio.QueueEmpty: + return cleared + + +class AudioMirrorChunker: + """Repacketize Rokid PCM into the same 100 ms frames used in Phase A.""" + + def __init__(self, samples_per_frame: int = 1_600): + self.target_bytes = max(1, samples_per_frame) * PCM16_WIDTH + self._carry = bytearray() + + def feed(self, raw: bytes) -> list[np.ndarray]: + if len(raw) % PCM16_WIDTH: + raw = raw[:-1] + self._carry.extend(raw) + frames: list[np.ndarray] = [] + while len(self._carry) >= self.target_bytes: + frame = bytes(self._carry[: self.target_bytes]) + del self._carry[: self.target_bytes] + frames.append(pcm16le_to_float32(frame)) + return frames + + def clear(self) -> None: + self._carry.clear() + + +@dataclass(slots=True) +class LatestFrame: + jpeg: bytes | None = None + timestamp_ms: float = 0.0 + sequence: int = 0 + + def set(self, jpeg: bytes, timestamp_ms: float) -> None: + self.jpeg = jpeg + self.timestamp_ms = timestamp_ms + self.sequence += 1 + + +@dataclass(slots=True) +class OutputGate: + generation: int = 0 + current_skill: str = "idle_chat" + current_slots: dict[str, Any] | None = None + speech_hold_active: bool = False + drop_output_until_listen: bool = False + restart_in_progress: bool = False + dropped_old_text: int = 0 + dropped_old_audio: int = 0 + stop_count: int = 0 + local_cue_mute_until_mono: float = 0.0 + + def __post_init__(self) -> None: + if self.current_slots is None: + self.current_slots = {} + + def stop(self) -> None: + self.stop_count += 1 + self.speech_hold_active = True + self.drop_output_until_listen = True + + def resume(self) -> None: + self.speech_hold_active = False + self.drop_output_until_listen = False + + def replacement_ready(self) -> None: + self.speech_hold_active = False + self.drop_output_until_listen = False + self.restart_in_progress = False + + +class SpeakerSink(Protocol): + async def start(self) -> None: ... + + async def enqueue(self, pcm: np.ndarray, generation: int) -> None: ... + + async def block_and_flush(self) -> None: ... + + async def resume(self) -> None: ... + + async def close(self) -> None: ... + + def pending_ms(self) -> float: ... + + +class NullSpeaker: + async def start(self) -> None: + return None + + async def enqueue(self, pcm: np.ndarray, generation: int) -> None: + return None + + async def block_and_flush(self) -> None: + return None + + async def resume(self) -> None: + return None + + async def close(self) -> None: + return None + + def pending_ms(self) -> float: + return 0.0 + + +class PCSpeaker: + """Interruptible 24 kHz PC playback with a short write quantum.""" + + def __init__(self, block_ms: int = 50): + self.block_samples = max(240, int(SAMPLE_RATE_OUT * block_ms / 1000)) + self.queue: asyncio.Queue[tuple[int, int, np.ndarray]] = asyncio.Queue(maxsize=32) + self.blocked = False + self.epoch = 0 + self._stream: Any = None + self._worker: asyncio.Task[None] | None = None + self._io_lock = asyncio.Lock() + self._pending_samples = 0 + + def _open_stream(self) -> None: + import sounddevice as sd # type: ignore + + stream = sd.OutputStream( + samplerate=SAMPLE_RATE_OUT, + channels=1, + dtype="float32", + blocksize=self.block_samples, + latency="low", + ) + stream.start() + self._stream = stream + + def _close_stream(self) -> None: + stream = self._stream + self._stream = None + if stream is None: + return + try: + stream.abort() + finally: + stream.close() + + async def start(self) -> None: + try: + await asyncio.to_thread(self._open_stream) + self._worker = asyncio.create_task(self._play_loop()) + LOG.info("PC speaker output ready") + except Exception as exc: # pragma: no cover - hardware dependent + self._stream = None + LOG.warning("PC speaker disabled: %s", exc) + + async def enqueue(self, pcm: np.ndarray, generation: int) -> None: + if self._stream is None or self.blocked or pcm.size == 0: + return + if self.queue.full(): + try: + _epoch, _generation, dropped = self.queue.get_nowait() + self._pending_samples = max( + 0, self._pending_samples - int(dropped.size) + ) + except asyncio.QueueEmpty: + pass + copied = pcm.astype(np.float32, copy=True) + self._pending_samples += int(copied.size) + self.queue.put_nowait((self.epoch, generation, copied)) + + async def _play_loop(self) -> None: + while True: + epoch, _generation, pcm = await self.queue.get() + try: + for offset in range(0, pcm.size, self.block_samples): + if self.blocked or epoch != self.epoch or self._stream is None: + break + chunk = pcm[offset : offset + self.block_samples].reshape(-1, 1) + stream = self._stream + try: + async with self._io_lock: + if self.blocked or epoch != self.epoch or self._stream is not stream: + break + await asyncio.to_thread(stream.write, chunk) + except asyncio.CancelledError: + raise + except Exception as exc: # pragma: no cover - hardware dependent + LOG.warning("speaker write failed: %s", exc) + break + finally: + self._pending_samples = max( + 0, self._pending_samples - int(pcm.size) + ) + + async def block_and_flush(self) -> None: + self.blocked = True + self.epoch += 1 + self._pending_samples = 0 + while True: + try: + self.queue.get_nowait() + except asyncio.QueueEmpty: + break + if self._stream is not None: + try: + # Windows MME may reject start() immediately after abort() while + # the previous buffer is still retiring. Close the device here + # and create a fresh stream only when output is resumed. + async with self._io_lock: + await asyncio.to_thread(self._close_stream) + except Exception as exc: # pragma: no cover - hardware dependent + LOG.warning("speaker flush failed: %s", exc) + + async def resume(self) -> None: + if self._stream is None: + try: + async with self._io_lock: + if self._stream is None: + await asyncio.to_thread(self._open_stream) + except Exception as exc: # pragma: no cover - hardware dependent + LOG.warning("speaker resume failed: %s", exc) + self.blocked = False + + async def close(self) -> None: + self.blocked = True + self._pending_samples = 0 + if self._worker: + self._worker.cancel() + await asyncio.gather(self._worker, return_exceptions=True) + if self._stream is not None: + try: + async with self._io_lock: + await asyncio.to_thread(self._close_stream) + except Exception: + pass + + def pending_ms(self) -> float: + return self._pending_samples * 1000.0 / SAMPLE_RATE_OUT + + +@dataclass(slots=True) +class RokidRuntimeConfig: + host: str = "0.0.0.0" + port: int = 18_080 + gateway: str = "localhost:8040" + gateway_tls: bool = False + harness_url: str = "ws://127.0.0.1:8021/ws/control" + harness_client_id: str = "rokid-phase-b" + skills_config: str = "" + cleanup_mode: str = "light" + chunk_ms: int = 1_000 + force_listen_count: int = 3 + max_new_speak_tokens_per_chunk: int = 20 + length_penalty: float = 1.1 + max_slice_nums: int = 1 + audio_queue_packets: int = 96 + input_gain: float = 12.0 + image_rotate_cw: int = 270 + image_jpeg_quality: int = 95 + image_resend_s: float = 0.5 + image_max_age_s: float = 30.0 + prepare_timeout_s: float = 120.0 + close_timeout_s: float = 2.0 + reconnect_s: float = 1.5 + play_audio: bool = True + session_ready_chime: bool = True + session_ready_chime_volume: float = 0.32 + session_ready_chime_feedback_guard_s: float = 0.65 + playback_echo_tail_s: float = 0.80 + + +@dataclass(slots=True) +class SessionSpec: + generation: int + skill_id: str + slots: dict[str, Any] + system_prompt: str + + +class SessionTelemetry(Protocol): + connected: bool + + async def send(self, payload: dict[str, Any]) -> None: ... + + +class GatewayDuplexSession: + """One generation-fenced connection to the existing MiniCPM Gateway.""" + + def __init__( + self, + config: RokidRuntimeConfig, + spec: SessionSpec, + audio_queue: DropOldestAudioQueue, + latest_frame: LatestFrame, + gate: OutputGate, + on_result: Callable[["GatewayDuplexSession", dict[str, Any]], Awaitable[None]], + ): + self.config = config + self.spec = spec + self.audio_queue = audio_queue + self.latest_frame = latest_frame + self.gate = gate + self.on_result = on_result + self.session_id = ( + f"omni_rokid_pb_g{spec.generation}_{int(time.time())}_{uuid.uuid4().hex[:6]}" + ) + self.status = "created" + self.last_error = "" + self.ws: aiohttp.ClientWebSocketResponse | None = None + self._task: asyncio.Task[None] | None = None + self._ready: asyncio.Future[None] | None = None + self._stopped = asyncio.Event() + self._closing = False + self._send_lock = asyncio.Lock() + + async def _send_json(self, payload: dict[str, Any]) -> None: + ws = self.ws + if ws is None or ws.closed: + raise RuntimeError("gateway session is not connected") + async with self._send_lock: + await ws.send_json(payload) + + def _ssl_context(self) -> ssl.SSLContext | None: + if not self.config.gateway_tls: + return None + context = ssl.create_default_context() + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + return context + + async def start(self) -> None: + loop = asyncio.get_running_loop() + self._ready = loop.create_future() + self._ready.add_done_callback( + lambda future: None if future.cancelled() else future.exception() + ) + self._task = asyncio.create_task(self._run()) + await asyncio.wait_for( + asyncio.shield(self._ready), timeout=self.config.prepare_timeout_s + ) + + async def _run(self) -> None: + scheme = "wss" if self.config.gateway_tls else "ws" + url = f"{scheme}://{self.config.gateway}/ws/duplex/{self.session_id}" + self.status = "connecting" + LOG.info("[GW] connecting generation=%d %s", self.spec.generation, url) + try: + async with aiohttp.ClientSession() as client: + async with client.ws_connect( + url, + heartbeat=30, + max_msg_size=0, + ssl=self._ssl_context(), + ) as ws: + self.ws = ws + await self._prepare(ws) + self.status = "running" + if self._ready and not self._ready.done(): + self._ready.set_result(None) + send_task = asyncio.create_task(self._send_loop(ws)) + receive_task = asyncio.create_task(self._receive_loop(ws)) + done, pending = await asyncio.wait( + (send_task, receive_task), + return_when=asyncio.FIRST_COMPLETED, + ) + for task in pending: + task.cancel() + await asyncio.gather(*done, *pending, return_exceptions=True) + except asyncio.CancelledError: + raise + except Exception as exc: + self.status = "error" + self.last_error = str(exc) + if self._ready and not self._ready.done(): + self._ready.set_exception(exc) + if not self._closing: + LOG.warning("[GW] session %s failed: %s", self.session_id, exc) + finally: + self.ws = None + self._stopped.set() + if self.status != "error": + self.status = "stopped" + + async def _prepare(self, ws: aiohttp.ClientWebSocketResponse) -> None: + self.status = "queued" + while True: + message = await ws.receive() + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + raise RuntimeError("gateway closed while queued") + continue + payload = json.loads(message.data) + message_type = payload.get("type") + if message_type == "queue_done": + break + if message_type == "error": + raise RuntimeError(payload.get("error") or "gateway queue error") + if message_type in {"queued", "queue_update"}: + LOG.info( + "[GW] queue position=%s eta=%s", + payload.get("position"), + payload.get("estimated_wait_s"), + ) + + self.status = "preparing" + await self._send_json( + { + "type": "prepare", + "system_prompt": self.spec.system_prompt, + "config": { + "force_listen_count": self.config.force_listen_count, + "chunk_ms": self.config.chunk_ms, + "generate_audio": True, + "max_new_speak_tokens_per_chunk": ( + self.config.max_new_speak_tokens_per_chunk + ), + "length_penalty": self.config.length_penalty, + }, + "max_slice_nums": self.config.max_slice_nums, + "deferred_finalize": True, + } + ) + while True: + message = await ws.receive() + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + raise RuntimeError("gateway closed while preparing") + continue + payload = json.loads(message.data) + if payload.get("type") == "prepared": + LOG.info( + "[GW] prepared session=%s generation=%d skill=%s", + self.session_id, + self.spec.generation, + self.spec.skill_id, + ) + return + if payload.get("type") == "error": + raise RuntimeError(payload.get("error") or "gateway prepare error") + + async def _next_audio_chunk(self, carry: bytearray) -> np.ndarray | None: + samples = int(SAMPLE_RATE_IN * self.config.chunk_ms / 1000) + target_bytes = samples * PCM16_WIDTH + output = bytearray() + if carry: + take = min(target_bytes, len(carry)) + output.extend(carry[:take]) + del carry[:take] + deadline = time.monotonic() + max(0.1, self.config.chunk_ms / 1000 * 1.5) + while len(output) < target_bytes: + remaining = deadline - time.monotonic() + if remaining <= 0: + break + raw = await self.audio_queue.get(remaining) + if raw is None: + break + needed = target_bytes - len(output) + output.extend(raw[:needed]) + if len(raw) > needed: + carry.extend(raw[needed:]) + if not output: + return None + if len(output) < target_bytes: + output.extend(b"\x00" * (target_bytes - len(output))) + return pcm16le_to_float32(bytes(output)) + + async def _send_loop(self, ws: aiohttp.ClientWebSocketResponse) -> None: + carry = bytearray() + last_frame_sequence = -1 + last_frame_sent = 0.0 + while not self._closing: + audio = await self._next_audio_chunk(carry) + if audio is None: + continue + payload: dict[str, Any] = { + "type": "audio_chunk", + "audio_base64": float32_to_base64(audio), + } + if self.gate.speech_hold_active: + payload["force_listen"] = True + frame = self.latest_frame + frame_age_ms = now_ms() - frame.timestamp_ms + frame_due = time.monotonic() - last_frame_sent >= self.config.image_resend_s + if ( + frame.jpeg + and frame_age_ms <= self.config.image_max_age_s * 1000 + and (frame.sequence != last_frame_sequence or frame_due) + ): + payload["frame_base64_list"] = [ + base64.b64encode(frame.jpeg).decode("ascii") + ] + last_frame_sequence = frame.sequence + last_frame_sent = time.monotonic() + # 诊断:真正送进 gateway 的每个 chunk。audio=xxpps 那个统计的是 + # "推进 audio_queue 的包数",看不出这里有没有按 1Hz 正常发出去。 + self._sent_chunks = getattr(self, "_sent_chunks", 0) + 1 + _lvl = float(np.abs(audio).mean()) if audio is not None else 0.0 + LOG.debug("[GW-SEND] #%d audio=%.2fs lvl=%.4f frame=%s hold=%s", + self._sent_chunks, + (len(audio) / SAMPLE_RATE_IN) if audio is not None else 0.0, + _lvl, + "frame_base64_list" in payload, + self.gate.speech_hold_active) + await self._send_json(payload) + + async def inject_task(self, text: str) -> bool: + """Send one text+latest-frame task to a newly prepared Skill Session.""" + text = text.strip() + if not text: + return False + payload: dict[str, Any] = { + "type": "audio_chunk", + "inject_text": text, + "max_slice_nums": self.config.max_slice_nums, + } + frame = self.latest_frame + frame_age_ms = now_ms() - frame.timestamp_ms + has_frame = bool( + frame.jpeg + and frame_age_ms <= self.config.image_max_age_s * 1000 + ) + if has_frame and frame.jpeg is not None: + payload["frame_base64_list"] = [ + base64.b64encode(frame.jpeg).decode("ascii") + ] + await self._send_json(payload) + LOG.info( + "[TASK] injected generation=%d skill=%s frame=%s text=%r", + self.spec.generation, + self.spec.skill_id, + has_frame, + text, + ) + return has_frame + + async def _receive_loop(self, ws: aiohttp.ClientWebSocketResponse) -> None: + async for message in ws: + if message.type == aiohttp.WSMsgType.TEXT: + payload = json.loads(message.data) + message_type = payload.get("type") + if message_type in {"result", "audio_only"}: + await self.on_result(self, payload) + elif message_type == "hint_audio": + # 强制措施念提示:独立播放,不进 on_result 状态机 + # (不记 model_turn / 不发 model.state / 不触发 EchoGuard), + # 避免和 duplex 主对话抢话、纠缠。 + hint_b64 = str(payload.get("audio_data") or "") + if hint_b64: + try: + pcm = np.frombuffer(base64.b64decode(hint_b64), dtype=np.float32) + # 念提示前先解除可能的 block(stop 时 block_and_flush 过), + # 否则 enqueue 会被丢。 + await self.speaker.resume() + await self.speaker.enqueue(pcm, self.spec.generation) + LOG.info("[HINT] 念提示播放: %r (%d samples)", + payload.get("text"), int(pcm.size)) + except Exception as exc: + LOG.warning("[HINT] 念提示播放失败: %s", exc) + elif message_type == "stopped": + return + elif message_type in {"timeout", "error"}: + raise RuntimeError( + payload.get("error") or payload.get("reason") or message_type + ) + elif message.type in (aiohttp.WSMsgType.CLOSED, aiohttp.WSMsgType.ERROR): + return + + async def stop(self, cleanup_mode: str) -> None: + self._closing = True + if self.ws is not None and not self.ws.closed: + try: + await self._send_json({"type": "stop", "cleanup_mode": cleanup_mode}) + except Exception: + pass + try: + await asyncio.wait_for(self._stopped.wait(), timeout=self.config.close_timeout_s) + except asyncio.TimeoutError: + pass + if self.ws is not None and not self.ws.closed: + await self.ws.close() + if self._task and not self._task.done(): + self._task.cancel() + await asyncio.gather(self._task, return_exceptions=True) + + +SessionFactory = Callable[ + [ + RokidRuntimeConfig, + SessionSpec, + DropOldestAudioQueue, + LatestFrame, + OutputGate, + Callable[[GatewayDuplexSession, dict[str, Any]], Awaitable[None]], + ], + GatewayDuplexSession, +] + + +class GatewaySessionManager: + """Python counterpart of the frozen BrowserSessionAdapter contract.""" + + def __init__( + self, + config: RokidRuntimeConfig, + registry: SkillRegistry, + audio_queue: DropOldestAudioQueue, + latest_frame: LatestFrame, + speaker: SpeakerSink, + session_factory: SessionFactory = GatewayDuplexSession, + ): + self.config = config + self.registry = registry + self.audio_queue = audio_queue + self.latest_frame = latest_frame + self.speaker = speaker + self.session_factory = session_factory + self.gate = OutputGate(current_skill=registry.default_skill) + self.harness: SessionTelemetry | None = None + self.active: GatewayDuplexSession | None = None + self._restart_lock = asyncio.Lock() + self._playback_epoch = 0 + self._playback_release_task: asyncio.Task[None] | None = None + + async def send_telemetry(self, payload: dict[str, Any]) -> None: + if self.harness is not None: + await self.harness.send(payload) + + async def _set_playback_active(self, active: bool, source: str) -> None: + await self.send_telemetry( + { + "type": "playback.state", + "active": active, + "source": source, + "generation": self.gate.generation, + "pending_ms": round(self.speaker.pending_ms(), 1), + } + ) + + async def _mark_playback_started(self, source: str) -> None: + self._playback_epoch += 1 + epoch = self._playback_epoch + if self._playback_release_task is not None: + self._playback_release_task.cancel() + await self._set_playback_active(True, source) + + async def release_after_drain() -> None: + try: + while self.speaker.pending_ms() > 0: + await asyncio.sleep( + max(0.02, min(0.25, self.speaker.pending_ms() / 1000.0)) + ) + await asyncio.sleep(max(0.0, self.config.playback_echo_tail_s)) + if epoch == self._playback_epoch: + await self._set_playback_active(False, source) + except asyncio.CancelledError: + raise + + self._playback_release_task = asyncio.create_task(release_after_drain()) + + async def _clear_playback_state(self, source: str) -> None: + self._playback_epoch += 1 + if self._playback_release_task is not None: + self._playback_release_task.cancel() + await asyncio.gather(self._playback_release_task, return_exceptions=True) + self._playback_release_task = None + await self._set_playback_active(False, source) + + def _make_spec( + self, + skill_id: str, + slots: dict[str, Any], + system_prompt: str | None = None, + ) -> SessionSpec: + rendered = self.registry.render(skill_id, slots) + return SessionSpec( + generation=self.gate.generation, + skill_id=skill_id, + slots=dict(slots), + system_prompt=system_prompt or rendered.text, + ) + + async def start_initial(self) -> None: + async with self._restart_lock: + if self.active is not None: + return + spec = self._make_spec(self.registry.default_skill, {}) + session = self.session_factory( + self.config, + spec, + self.audio_queue, + self.latest_frame, + self.gate, + self.handle_result, + ) + self.active = session + try: + await session.start() + except Exception: + self.active = None + raise + await self._emit_bound() + + async def _emit_bound(self) -> None: + await self.send_telemetry( + { + "type": "session.state", + "phase": "bound", + "generation": self.gate.generation, + "skill_id": self.gate.current_skill, + "slots": dict(self.gate.current_slots or {}), + "session_id": self.active.session_id if self.active else None, + } + ) + + async def emit_recovery_sync(self) -> None: + if self.active is None: + return + await self.send_telemetry( + { + "type": "session.state", + "phase": "restart_complete", + "generation": self.gate.generation, + "skill_id": self.gate.current_skill, + "slots": dict(self.gate.current_slots or {}), + "new_session_id": self.active.session_id, + "cleanup_mode": "reconnect_sync", + } + ) + await self._emit_bound() + + async def handle_control(self, event: dict[str, Any]) -> dict[str, Any]: + if not event.get("accepted"): + return {"ok": False, "ignored": True} + intent = str(event.get("intent") or "") + if intent == "stop_speech": + return await self.stop_speech(event) + if intent == "resume_speech": + return await self.resume_speech(event) + if intent in { + "reset_session", + "activate_skill", + "cancel_skill", + "return_to_chat", + }: + return await self.restart(event) + return {"ok": False, "ignored": True} + + def _ack_base(self, event: dict[str, Any]) -> dict[str, Any]: + return { + "type": "control.ack", + "event_id": event.get("event_id"), + "intent": event.get("intent"), + "generation": self.gate.generation, + "dropped_old_text": self.gate.dropped_old_text, + "dropped_old_audio": self.gate.dropped_old_audio, + } + + async def stop_speech( + self, event: dict[str, Any], *, emit_ack: bool = True + ) -> dict[str, Any]: + self.gate.stop() + await self.speaker.block_and_flush() + await self._clear_playback_state("stop") + ack = {**self._ack_base(event), "ok": True} + if emit_ack: + await self.send_telemetry(ack) + LOG.info("[CONTROL] STOP event=%s", event.get("event_id")) + return ack + + async def resume_speech(self, event: dict[str, Any]) -> dict[str, Any]: + self.gate.resume() + await self.speaker.resume() + ack = {**self._ack_base(event), "ok": True} + await self.send_telemetry(ack) + LOG.info("[CONTROL] RESUME event=%s", event.get("event_id")) + return ack + + async def restart(self, event: dict[str, Any]) -> dict[str, Any]: + async with self._restart_lock: + requested_skill = str(event.get("skill_id") or self.registry.default_skill) + requested_slots = dict(event.get("slots") or {}) + if ( + str(event.get("intent")) != "reset_session" + and requested_skill == self.gate.current_skill + and same_slots(requested_slots, dict(self.gate.current_slots or {})) + ): + ack = {**self._ack_base(event), "ok": True, "no_restart": True} + await self.send_telemetry(ack) + return ack + + started = time.monotonic() + await self.stop_speech(event, emit_ack=False) + self.gate.restart_in_progress = True + old_session = self.active + old_session_id = old_session.session_id if old_session else None + self.gate.generation += 1 + await self.send_telemetry( + { + "type": "session.state", + "phase": "restart_started", + "generation": self.gate.generation, + "event_id": event.get("event_id"), + "old_session_id": old_session_id, + } + ) + self.active = None + try: + if old_session: + await old_session.stop(self.config.cleanup_mode) + self.audio_queue.clear() + spec = self._make_spec( + requested_skill, + requested_slots, + str(event.get("system_prompt") or "") or None, + ) + session = self.session_factory( + self.config, + spec, + self.audio_queue, + self.latest_frame, + self.gate, + self.handle_result, + ) + self.active = session + await session.start() + self.gate.current_skill = requested_skill + self.gate.current_slots = requested_slots + self.gate.replacement_ready() + await self.speaker.resume() + await self._emit_bound() + latency_ms = (time.monotonic() - started) * 1000.0 + state = { + "type": "session.state", + "phase": "restart_complete", + "generation": self.gate.generation, + "skill_id": requested_skill, + "slots": requested_slots, + "old_session_id": old_session_id, + "new_session_id": session.session_id, + "cleanup_mode": self.config.cleanup_mode, + } + await self.send_telemetry(state) + if self.config.play_audio and self.config.session_ready_chime: + cue = make_session_ready_chime( + amplitude=self.config.session_ready_chime_volume + ) + self.gate.local_cue_mute_until_mono = max( + self.gate.local_cue_mute_until_mono, + time.monotonic() + + cue.size / SAMPLE_RATE_OUT + + self.config.session_ready_chime_feedback_guard_s, + ) + await self.speaker.enqueue(cue, self.gate.generation) + await self._mark_playback_started("session_ready_chime") + LOG.info( + "[CUE] session ready generation=%d skill=%s", + self.gate.generation, + requested_skill, + ) + trigger = self.registry.task_trigger(requested_skill, requested_slots) + trigger_frame = False + trigger_error = "" + if trigger: + try: + trigger_frame = await session.inject_task(trigger) + await self.send_telemetry( + { + "type": "session.state", + "phase": "task_trigger_sent", + "generation": self.gate.generation, + "skill_id": requested_skill, + "slots": requested_slots, + "session_id": session.session_id, + "has_frame": trigger_frame, + } + ) + except Exception as exc: + trigger_error = str(exc) + LOG.warning( + "[TASK] one-shot trigger failed skill=%s: %s", + requested_skill, + exc, + ) + ack = { + **self._ack_base(event), + "ok": True, + "restart_latency_ms": latency_ms, + "skill_id": requested_skill, + "slots": requested_slots, + "old_session_id": old_session_id, + "new_session_id": session.session_id, + "cleanup_mode": self.config.cleanup_mode, + "task_trigger_sent": bool(trigger and not trigger_error), + "task_trigger_has_frame": trigger_frame, + "task_trigger_error": trigger_error, + } + await self.send_telemetry(ack) + LOG.info( + "[CONTROL] %s ready generation=%d session=%s latency_ms=%.1f", + requested_skill, + self.gate.generation, + session.session_id, + latency_ms, + ) + return ack + except Exception as exc: + if self.active: + await self.active.stop(self.config.cleanup_mode) + self.active = None + self.gate.restart_in_progress = False + ack = {**self._ack_base(event), "ok": False, "error": str(exc)} + await self.send_telemetry(ack) + LOG.exception("[CONTROL] restart failed") + return ack + + async def handle_result( + self, session: GatewayDuplexSession, result: dict[str, Any] + ) -> None: + is_listen = bool(result.get("is_listen")) + text = str(result.get("text") or "") + audio_b64 = str(result.get("audio_data") or "") + stale = ( + session is not self.active + or session.spec.generation != self.gate.generation + ) + if stale or (self.gate.drop_output_until_listen and not is_listen): + if text: + self.gate.dropped_old_text += 1 + if audio_b64: + self.gate.dropped_old_audio += 1 + # 诊断:这条路径原本静默 return,模型的输出被整个丢掉却不留痕迹 + #(表现就是 ai(calls=0) + [MODEL] 只有孤零零一条)。打出丢弃原因。 + self._drop_n = getattr(self, "_drop_n", 0) + 1 + if self._drop_n <= 3 or self._drop_n % 100 == 0: + LOG.warning( + "[GW-DROP] #%d stale=%s (active=%s gen_sess=%s gen_gate=%s) " + "drop_until_listen=%s is_listen=%s text=%r audio=%dB", + self._drop_n, stale, + session is self.active, + session.spec.generation, self.gate.generation, + self.gate.drop_output_until_listen, is_listen, + text[:20], len(audio_b64)) + return + if is_listen and self.gate.drop_output_until_listen: + if not self.gate.speech_hold_active: + self.gate.drop_output_until_listen = False + await self.speaker.resume() + audio_samples = 0 + if audio_b64 and not is_listen: + try: + pcm = np.frombuffer(base64.b64decode(audio_b64), dtype=np.float32) + audio_samples = int(pcm.size) + await self.speaker.enqueue(pcm, session.spec.generation) + if self.config.play_audio: + await self._mark_playback_started("model") + except Exception as exc: + LOG.warning("model audio decode failed: %s", exc) + await self.send_telemetry( + { + "type": "model.state", + "state": "listen" if is_listen else "speak", + "text": text, + "generation": session.spec.generation, + "session_id": session.session_id, + "skill_id": session.spec.skill_id, + "slots": dict(session.spec.slots), + # llama.cpp-omni marks each decode slice as end_of_turn. The + # actual duplex turn boundary is the later __IS_LISTEN__ + # result, so keep the raw marker for diagnostics but aggregate + # model text until listening resumes. + "decode_end": bool(result.get("end_of_turn")), + "end_of_turn": is_listen, + "message_type": str(result.get("type") or "result"), + "audio_samples": audio_samples, + "audio_ms": round( + audio_samples * 1000.0 / SAMPLE_RATE_OUT, 1 + ), + } + ) + if text: + LOG.info("[MODEL] listen=%s text=%s", is_listen, text) + + async def close(self) -> None: + await self._clear_playback_state("close") + if self.active: + await self.active.stop(self.config.cleanup_mode) + self.active = None + + def health(self) -> dict[str, Any]: + return { + "generation": self.gate.generation, + "current_skill": self.gate.current_skill, + "current_slots": dict(self.gate.current_slots or {}), + "speech_hold_active": self.gate.speech_hold_active, + "restart_in_progress": self.gate.restart_in_progress, + "dropped_old_text": self.gate.dropped_old_text, + "dropped_old_audio": self.gate.dropped_old_audio, + "session_id": self.active.session_id if self.active else None, + "gateway_status": self.active.status if self.active else "disconnected", + "gateway_error": self.active.last_error if self.active else "", + } + + +class HarnessClient: + def __init__( + self, + url: str, + client_id: str, + manager: GatewaySessionManager, + reconnect_s: float, + ): + separator = "&" if "?" in url else "?" + self.url = f"{url}{separator}client_id={client_id}" + self.manager = manager + self.reconnect_s = reconnect_s + self.connected = False + self.ws: aiohttp.ClientWebSocketResponse | None = None + self._stop = asyncio.Event() + self._send_lock = asyncio.Lock() + self._control_tasks: set[asyncio.Task[Any]] = set() + + # 外部可挂的只读观察者:收到未被上面分支处理的消息时调用(同步、异常吞掉)。 + # 不改构造签名,赋值即可:client.on_message = fn + on_message = None + + async def run(self) -> None: + while not self._stop.is_set(): + try: + async with aiohttp.ClientSession() as client: + async with client.ws_connect( + self.url, heartbeat=30, max_msg_size=0 + ) as ws: + self.ws = ws + self.connected = True + LOG.info("Harness connected: %s", self.url) + async for message in ws: + if message.type != aiohttp.WSMsgType.TEXT: + if message.type in ( + aiohttp.WSMsgType.CLOSED, + aiohttp.WSMsgType.ERROR, + ): + break + continue + payload = json.loads(message.data) + message_type = payload.get("type") + if message_type == "harness.ready": + await self.manager.emit_recovery_sync() + elif message_type == "control.intent": + task = asyncio.create_task( + self.manager.handle_control(payload) + ) + self._control_tasks.add(task) + task.add_done_callback(self._control_tasks.discard) + # 可选旁路:把其余消息(如 asr.transcript)交给外部观察者。 + # 默认 None,行为与原来完全一致。8021 的 asr.transcript 只投递给 + # "送音频进来的那个 client" 的 outbound 队列(每个 client_id 有 + # 独立 runtime),另开一条连接是收不到的,只能在这里截。 + elif self.on_message is not None: + try: + self.on_message(payload) + except Exception: + pass + except asyncio.CancelledError: + raise + except Exception as exc: + if not self._stop.is_set(): + LOG.warning("Harness connection failed: %s", exc) + finally: + self.connected = False + self.ws = None + if not self._stop.is_set(): + await asyncio.sleep(self.reconnect_s) + + async def send(self, payload: dict[str, Any]) -> None: + async with self._send_lock: + if self.ws is not None and not self.ws.closed: + await self.ws.send_json(payload) + + async def send_audio(self, samples: np.ndarray) -> None: + if samples.size == 0: + return + await self.send( + { + "type": "audio.mirror", + "started_at_ms": now_ms() - samples.size * 1000.0 / SAMPLE_RATE_IN, + "sample_rate": SAMPLE_RATE_IN, + "audio_b64": float32_to_base64(samples), + } + ) + + async def send_frame(self, jpeg: bytes, sequence: int, timestamp_ms: float) -> None: + await self.send( + { + "type": "frame.shadow", + "frame_id": f"rokid_{sequence}_{int(timestamp_ms)}", + "timestamp_ms": timestamp_ms, + "jpeg_b64": base64.b64encode(jpeg).decode("ascii"), + } + ) + + async def close(self) -> None: + self._stop.set() + if self.ws is not None and not self.ws.closed: + await self.ws.close() + for task in tuple(self._control_tasks): + task.cancel() + await asyncio.gather(*self._control_tasks, return_exceptions=True) + + +@dataclass(slots=True) +class RuntimeStats: + started_mono: float = field(default_factory=time.monotonic) + audio_packets: int = 0 + audio_bytes: int = 0 + audio_clients: int = 0 + image_count: int = 0 + image_bytes: int = 0 + last_audio_ms: float = 0.0 + audio_rms: float = 0.0 + audio_peak: float = 0.0 + non_silent_audio_packets: int = 0 + + +class PhaseBRokidRuntime: + """Rokid sensor ingress + frozen Harness control + Gateway session adapter.""" + + def __init__( + self, + config: RokidRuntimeConfig, + *, + speaker: SpeakerSink | None = None, + session_factory: SessionFactory = GatewayDuplexSession, + ): + self.config = config + self.registry = SkillRegistry(config.skills_config) + self.audio_queue = DropOldestAudioQueue(config.audio_queue_packets) + self.audio_mirror = AudioMirrorChunker() + self.latest_frame = LatestFrame() + self.stats = RuntimeStats(started_mono=time.monotonic()) + self.speaker = speaker or (PCSpeaker() if config.play_audio else NullSpeaker()) + self.manager = GatewaySessionManager( + config, + self.registry, + self.audio_queue, + self.latest_frame, + self.speaker, + session_factory=session_factory, + ) + self.harness = HarnessClient( + config.harness_url, + config.harness_client_id, + self.manager, + config.reconnect_s, + ) + self.manager.harness = self.harness + self._tasks: list[asyncio.Task[Any]] = [] + self._close_lock = asyncio.Lock() + self._closed = False + self._no_input_warning_emitted = False + + def health(self) -> dict[str, Any]: + return { + "ok": True, + "phase": "B", + "device": "rokid", + "uptime_s": round(time.monotonic() - self.stats.started_mono, 3), + "harness_connected": self.harness.connected, + "audio_packets_in": self.stats.audio_packets, + "audio_bytes_in": self.stats.audio_bytes, + "audio_clients": self.stats.audio_clients, + "latest_audio_age_ms": ( + round(now_ms() - self.stats.last_audio_ms, 1) + if self.stats.last_audio_ms + else None + ), + "audio_queue_size": self.audio_queue.size, + "dropped_audio_packets": self.audio_queue.dropped_packets, + "audio_rms": round(self.stats.audio_rms, 6), + "audio_peak": round(self.stats.audio_peak, 6), + "input_gain": self.config.input_gain, + "effective_audio_rms": round( + min(1.0, self.stats.audio_rms * self.config.input_gain), 6 + ), + "non_silent_audio_packets": self.stats.non_silent_audio_packets, + "image_count": self.stats.image_count, + "device_input_ready": bool( + self.stats.audio_packets or self.stats.image_count + ), + "latest_image_age_ms": ( + round(now_ms() - self.latest_frame.timestamp_ms, 1) + if self.latest_frame.timestamp_ms + else None + ), + **self.manager.health(), + } + + async def _initial_session_loop(self) -> None: + while True: + try: + await self.manager.start_initial() + return + except asyncio.CancelledError: + raise + except Exception as exc: + LOG.warning("initial Gateway session failed: %s", exc) + await asyncio.sleep(self.config.reconnect_s) + + async def _stats_loop(self) -> None: + previous_audio = 0 + previous_image = 0 + while True: + await asyncio.sleep(5.0) + if ( + not self._no_input_warning_emitted + and time.monotonic() - self.stats.started_mono >= 10.0 + and self.stats.audio_packets == 0 + and self.stats.image_count == 0 + ): + self._no_input_warning_emitted = True + LOG.warning( + "[ROKID][NO_INPUT] no PCM/JPEG has reached this process. " + "After the PC runtime is listening, restart OpenGlass " + "Sensor Mode on the glasses (STOP -> RUN) and verify that " + "the APK targets the PC WLAN address on port %d", + self.config.port, + ) + LOG.info( + "[STATS] audio=%.1fpps images=%d(+%d) audio_clients=%d " + "queue=%d drops=%d rms=%.4f peak=%.4f harness=%s gateway=%s " + "skill=%s generation=%d", + (self.stats.audio_packets - previous_audio) / 5.0, + self.stats.image_count, + self.stats.image_count - previous_image, + self.stats.audio_clients, + self.audio_queue.size, + self.audio_queue.dropped_packets, + self.stats.audio_rms, + self.stats.audio_peak, + self.harness.connected, + self.manager.health()["gateway_status"], + self.manager.gate.current_skill, + self.manager.gate.generation, + ) + previous_audio = self.stats.audio_packets + previous_image = self.stats.image_count + + async def start(self) -> None: + await self.speaker.start() + self._tasks = [ + asyncio.create_task(self.harness.run()), + asyncio.create_task(self._initial_session_loop()), + asyncio.create_task(self._stats_loop()), + ] + + async def close(self) -> None: + async with self._close_lock: + if self._closed: + return + LOG.info("Rokid runtime shutdown started") + + async def bounded(label: str, awaitable: Awaitable[None]) -> None: + try: + await asyncio.wait_for( + awaitable, + timeout=max(0.5, self.config.close_timeout_s), + ) + except asyncio.TimeoutError: + LOG.warning( + "Rokid shutdown step timed out: %s (continuing)", label + ) + except Exception as exc: + LOG.warning( + "Rokid shutdown step failed: %s: %s", label, exc + ) + + await bounded("harness", self.harness.close()) + for task in self._tasks: + task.cancel() + if self._tasks: + await bounded( + "background_tasks", + asyncio.gather(*self._tasks, return_exceptions=True), + ) + self._tasks.clear() + await bounded("gateway_session", self.manager.close()) + await bounded("pc_speaker", self.speaker.close()) + self.audio_queue.clear() + self.audio_mirror.clear() + self._closed = True + LOG.info("Rokid runtime shutdown complete; port may be reused") + + def create_app(self) -> web.Application: + app = web.Application(client_max_size=8 * 1024 * 1024) + app["runtime"] = self + + async def health(_request: web.Request) -> web.Response: + return web.json_response(self.health()) + + async def capture(_request: web.Request) -> web.Response: + if not self.latest_frame.jpeg: + return web.Response(status=404, text="no image") + return web.Response(body=self.latest_frame.jpeg, content_type="image/jpeg") + + async def rokid_image(request: web.Request) -> web.Response: + raw = await request.read() + if not (raw.startswith(b"\xff\xd8") and raw.endswith(b"\xff\xd9")): + return web.Response(status=400, text="expected JPEG bytes") + try: + jpeg = await asyncio.to_thread( + rotate_jpeg_clockwise, + raw, + self.config.image_rotate_cw, + self.config.image_jpeg_quality, + ) + except Exception as exc: + return web.Response(status=400, text=str(exc)) + timestamp = now_ms() + self.latest_frame.set(jpeg, timestamp) + self.stats.image_count += 1 + self.stats.image_bytes += len(raw) + if self.stats.image_count == 1: + LOG.info("[ROKID] first JPEG received from %s", request.remote) + asyncio.create_task( + self.harness.send_frame( + jpeg, self.latest_frame.sequence, timestamp + ) + ) + return web.json_response( + {"ok": True, "image_count": self.stats.image_count, "bytes": len(raw)} + ) + + async def rokid_audio(request: web.Request) -> web.WebSocketResponse: + ws = web.WebSocketResponse(heartbeat=30, max_msg_size=0) + await ws.prepare(request) + self.stats.audio_clients += 1 + LOG.info("[ROKID] audio connected from %s", request.remote) + try: + async for message in ws: + if message.type == aiohttp.WSMsgType.BINARY: + raw = bytes(message.data) + if len(raw) < PCM16_WIDTH: + continue + if len(raw) % PCM16_WIDTH: + raw = raw[:-1] + self.stats.audio_packets += 1 + self.stats.audio_bytes += len(raw) + self.stats.last_audio_ms = now_ms() + if self.stats.audio_packets == 1: + LOG.info("[ROKID] first PCM packet received") + samples = pcm16le_to_float32(raw) + packet_rms = float(np.sqrt(np.mean(np.square(samples)))) + packet_peak = float(np.max(np.abs(samples))) + self.stats.audio_rms = ( + 0.8 * self.stats.audio_rms + 0.2 * packet_rms + ) + self.stats.audio_peak = packet_peak + if packet_rms >= 0.01: + self.stats.non_silent_audio_packets += 1 + if time.monotonic() >= self.manager.gate.local_cue_mute_until_mono: + amplified = apply_pcm16_gain(raw, self.config.input_gain) + self.audio_queue.put_nowait(amplified) + for frame in self.audio_mirror.feed(amplified): + await self.harness.send_audio(frame) + elif message.type == aiohttp.WSMsgType.ERROR: + break + finally: + self.stats.audio_clients = max(0, self.stats.audio_clients - 1) + LOG.info("[ROKID] audio disconnected from %s", request.remote) + return ws + + async def on_startup(_app: web.Application) -> None: + await self.start() + + async def on_cleanup(_app: web.Application) -> None: + await self.close() + + app.router.add_get("/", health) + app.router.add_get("/health", health) + app.router.add_get("/capture", capture) + app.router.add_post("/rokid/image", rokid_image) + app.router.add_get("/rokid/audio", rokid_audio) + app.on_startup.append(on_startup) + app.on_cleanup.append(on_cleanup) + return app + + +def default_skills_config() -> str: + return str( + Path(__file__).resolve().parents[1] / "config" / "skills.example.yaml" + ) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Rokid Phase B adapter: sensors + Harness + MiniCPM Gateway" + ) + parser.add_argument("--host", default="0.0.0.0") + parser.add_argument("--port", type=int, default=18_080) + parser.add_argument("--gateway", default="localhost:8040") + parser.add_argument("--gateway-tls", action="store_true", default=False) + parser.add_argument( + "--no-gateway-tls", dest="gateway_tls", action="store_false" + ) + parser.add_argument( + "--harness-url", default="ws://127.0.0.1:8021/ws/control" + ) + parser.add_argument("--client-id", default="rokid-phase-b") + parser.add_argument("--skills-config", default=default_skills_config()) + parser.add_argument("--cleanup-mode", choices=("light", "full"), default="light") + parser.add_argument("--image-rotate-cw", type=int, default=270) + parser.add_argument("--image-jpeg-quality", type=int, default=95) + parser.add_argument("--audio-queue-packets", type=int, default=96) + parser.add_argument( + "--input-gain", + type=float, + default=12.0, + help="Rokid PCM gain before Harness/Gateway; clipped to PCM16", + ) + parser.add_argument("--chunk-ms", type=int, default=1_000) + parser.add_argument("--force-listen-count", type=int, default=3) + parser.add_argument("--no-play", action="store_true") + parser.add_argument( + "--no-session-ready-chime", + action="store_true", + help="disable the local restart_complete notification cue", + ) + parser.add_argument( + "--session-ready-chime-volume", + type=float, + default=0.32, + help="restart cue amplitude in [0, 1] (default: 0.32)", + ) + parser.add_argument( + "--playback-echo-tail-s", + type=float, + default=0.80, + help="keep EchoGuard active after the PC speaker queue drains", + ) + parser.add_argument("--log-level", default="INFO") + return parser.parse_args() + + +def main() -> None: + args = parse_args() + if not 0.0 <= args.session_ready_chime_volume <= 1.0: + raise SystemExit("--session-ready-chime-volume must be between 0 and 1") + if args.playback_echo_tail_s < 0.0: + raise SystemExit("--playback-echo-tail-s must be non-negative") + logging.basicConfig( + level=getattr(logging, args.log_level.upper(), logging.INFO), + format="%(asctime)s %(levelname)s %(name)s: %(message)s", + force=True, + ) + config = RokidRuntimeConfig( + host=args.host, + port=args.port, + gateway=args.gateway, + gateway_tls=args.gateway_tls, + harness_url=args.harness_url, + harness_client_id=args.client_id, + skills_config=args.skills_config, + cleanup_mode=args.cleanup_mode, + chunk_ms=args.chunk_ms, + force_listen_count=args.force_listen_count, + audio_queue_packets=args.audio_queue_packets, + input_gain=args.input_gain, + image_rotate_cw=args.image_rotate_cw, + image_jpeg_quality=args.image_jpeg_quality, + play_audio=not args.no_play, + session_ready_chime=not args.no_session_ready_chime, + session_ready_chime_volume=args.session_ready_chime_volume, + playback_echo_tail_s=args.playback_echo_tail_s, + ) + runtime = PhaseBRokidRuntime(config) + watchdog = CtrlCExitWatchdog() + shutdown_signals = [signal.SIGINT] + if hasattr(signal, "SIGBREAK"): + shutdown_signals.append(signal.SIGBREAK) + previous_handlers = { + signum: signal.getsignal(signum) for signum in shutdown_signals + } + + def handle_console_shutdown(signum: int, frame: Any) -> None: + watchdog.arm() + previous_handler = previous_handlers[signum] + if callable(previous_handler): + previous_handler(signum, frame) + else: + raise KeyboardInterrupt + + for signum in shutdown_signals: + signal.signal(signum, handle_console_shutdown) + LOG.info("Rokid Phase B input: http://%s:%d", config.host, config.port) + LOG.info("Harness: %s", config.harness_url) + LOG.info("Gateway: %s://%s", "wss" if config.gateway_tls else "ws", config.gateway) + try: + web.run_app( + runtime.create_app(), + host=config.host, + port=config.port, + access_log=None, + shutdown_timeout=max(0.5, config.close_timeout_s), + handler_cancellation=True, + ) + except OSError as exc: + if getattr(exc, "winerror", None) == 10048: + LOG.error( + "Port %d is already occupied by another process. A runtime " + "started with this patched version exits within %.0fs after " + "Ctrl+C.", + config.port, + CTRL_C_HARD_EXIT_S, + ) + raise SystemExit(2) from None + raise + finally: + for signum, previous_handler in previous_handlers.items(): + signal.signal(signum, previous_handler) + if watchdog.armed: + LOG.info("Graceful shutdown returned; exiting Rokid process") + + +if __name__ == "__main__": + main() diff --git a/extensions/assistive_harness/phase_b/session_recorder.py b/extensions/assistive_harness/phase_b/session_recorder.py new file mode 100644 index 0000000..ce6bcda --- /dev/null +++ b/extensions/assistive_harness/phase_b/session_recorder.py @@ -0,0 +1,90 @@ +"""Session 录制器(对齐 -v 的 SessionRecorder 格式)。 + +沿用 pc_vlm_v5_funnel.SessionRecorder 的落盘结构,让 -o 链路录出的 session +和 -v 完全一致,可用 -v 的分析 / rerun 工具链直接读。 + + sessions// + images/q{NNN}_f{MM}.jpg 每轮一簇帧(整簇存) + queries.jsonl 每行一条,-v 原字段 + 漏斗判定字段 + meta.json + +启动标志:-v 是「ASR 出 query」,-o 里换成「链路启动」——从 start 起持续录, +每轮漏斗决策 append 一条。qid 单调递增(一轮 = 一个 qid)。 + +queries.jsonl 每行(保留 -v 原字段 qid/text/frames/ts,兼容;追加漏斗字段): + { + "qid": 3, "ts": 1699..., # -v 原字段 + "text": "", # -v 原字段(-o 无 ASR query 文本,留空/可后填) + "frames": ["q003_f00.jpg", ...], # -v 原字段(整簇帧文件名) + "reason": "severe_shake", # 漏斗判定 + "send": false, + "hint": "晃得厉害,请拿稳一下", + "best_index": 1, + "af_triggered": true, "af_ok": true, + "timings": {...} + } +""" +from __future__ import annotations + +import json +import time +from pathlib import Path +from typing import Optional + + +class SessionRecorder: + def __init__(self, sessions_root: str = "sessions", sid: Optional[str] = None): + sid = sid or time.strftime("%Y%m%d_%H%M%S") + self.dir = Path(sessions_root) / sid + self.images = self.dir / "images" + self.images.mkdir(parents=True, exist_ok=True) + self.jsonl = self.dir / "queries.jsonl" + (self.dir / "meta.json").write_text( + json.dumps({"sid": sid, "source": "esp32_runtime", "created": time.time()}, + ensure_ascii=False, indent=2), + encoding="utf-8") + self._qid = 0 + print(f"[SESSION] recording to {self.dir}") + + def record(self, decision, text: str = "") -> None: + """存一轮漏斗决策:整簇帧落盘 + queries.jsonl append 一条。 + + decision: FunnelDecision(含 frames / best / reason / hint / + best_index / af_triggered / af_ok / timings) + text: 可选,-o 无 ASR query 文本,留空;如上层有 ASR 结果可传入。 + """ + self._qid += 1 + qid = self._qid + frame_names = [] + frames = decision.frames or ([] if decision.best is None else [decision.best]) + for i, jpg in enumerate(frames): + name = f"q{qid:03d}_f{i:02d}.jpg" + try: + (self.images / name).write_bytes(jpg) + frame_names.append(name) + except Exception: + pass + + rec = { + # -v 原字段(兼容 -v 工具链) + "qid": qid, + "ts": time.time(), + "text": text, + "frames": frame_names, + # 漏斗判定字段 + "send": bool(decision.send), + "reason": decision.reason, + "hint": decision.hint, + "best_index": decision.best_index, + "af_triggered": decision.af_triggered, + "af_ok": decision.af_ok, + "timings": decision.timings, + } + try: + with self.jsonl.open("a", encoding="utf-8") as f: + f.write(json.dumps(rec, ensure_ascii=False) + "\n") + except Exception: + pass + + def close(self) -> None: + print(f"[SESSION] recorded {self._qid} queries -> {self.dir}") diff --git a/extensions/assistive_harness/phase_b/templates/live.html b/extensions/assistive_harness/phase_b/templates/live.html new file mode 100644 index 0000000..96099f9 --- /dev/null +++ b/extensions/assistive_harness/phase_b/templates/live.html @@ -0,0 +1,620 @@ + + + + + +AI 眼镜 · 实时演示 + + + + +
+
+
+ 🕶 +
+
AI 眼镜 · 实时演示
+
Real-time multimodal assistant for the visually impaired
+
+
+
+ + 连接中… + + + 待连接 + + + 输入异常 + + 📁 历史 + +
+
+ +
+
+ +
+
📷
+
等待眼镜画面…
+
+
+ LIVE · 眼镜第一视角 +
+
+ 📡 前方 -- m + 🧭 朝向 --° +
+
+ 🎤 +
+ -- dB +
+
+
+
+ +
+
+ 💬 对话 + 0 轮 +
+
+
开始说话以与 AI 眼镜互动…
+
+
+
+ +
+
+ AI 静默中 +
+
+
+ + +
+
+
+ +
⚡ 用户打断了 AI
+ + + + + +
+
+

停止并保存?

+

将立即结束本次会话,并把视频 / 音频 / 字幕打包写盘。确认后无法恢复。

+
+ + +
+
+
+ + + + \ No newline at end of file diff --git a/extensions/assistive_harness/phase_b/templates/replay.html b/extensions/assistive_harness/phase_b/templates/replay.html new file mode 100644 index 0000000..458d238 --- /dev/null +++ b/extensions/assistive_harness/phase_b/templates/replay.html @@ -0,0 +1,566 @@ + + + + + + AI 眼镜 · 回放 + + + + +
+
+
+ 🎬 +
+
AI 眼镜 · 会话回放
+
+
+
+
+ ·探测中… + 0 轮 + ⬅ 所有会话 + 🔴 实时 +
+
+ +
+
+
+
+
加载中…
+
+
+ +
+
+ 💬 字幕时间线 + 点击跳转 +
+
+
暂无字幕
+
+
+
+ +
+ +
+
+
+ + + + \ No newline at end of file diff --git a/extensions/assistive_harness/phase_b/templates/replay_index.html b/extensions/assistive_harness/phase_b/templates/replay_index.html new file mode 100644 index 0000000..efcc60a --- /dev/null +++ b/extensions/assistive_harness/phase_b/templates/replay_index.html @@ -0,0 +1,321 @@ + + + + + + AI 眼镜 · 回访 + + + + +
+
+
+ 🕶 +
+
AI 眼镜 · 会话回访
+
Session replay & offline inspection
+
+
+
+ — 条会话 + ⬅ 返回实时 +
+
+ +
+
+
+ 点击行进入回放 · 所有会话按时间倒序 +
+
+
Loading…
+
+
+
+
+ + + + \ No newline at end of file diff --git a/extensions/assistive_harness/phase_b/timing_probe.py b/extensions/assistive_harness/phase_b/timing_probe.py new file mode 100644 index 0000000..6d921c4 --- /dev/null +++ b/extensions/assistive_harness/phase_b/timing_probe.py @@ -0,0 +1,163 @@ +"""时序探针(纯旁路,不改链路行为)。 + +只做一件事:把 ESP32 -o 链路里"取图 / 音频 / 相位"的时间点写进一个 CSV, +供事后分析漏斗该插在哪、跨几个 chunk、音图怎么抢。 + +不接对焦、不接漏斗判定 —— 这是纯时序探针。 + +列名尽量沿用 -v 的 latency CSV 风格(grab_ms / n_frames 等), +额外加 -o 特有的 chunk / 音频相位列,方便和 -v 数据对比、也让分析工具链复用。 + +用法(在 esp32_runtime 里): + from .timing_probe import TimingProbe + probe = TimingProbe(enabled=args.timing_probe, path=args.timing_csv, chunk_ms=1000) + # 取图: + probe.mark_grab(seq, grab_ms, jpeg_bytes, since_last_ms) + # 音频(每包调,内部按秒聚合): + probe.mark_audio(seq, n_samples, drops, rms) + # 关闭:probe.close() +""" +from __future__ import annotations + +import csv +import time +from pathlib import Path +from typing import Optional + + +class TimingProbe: + def __init__(self, enabled: bool = True, path: Optional[str] = None, + chunk_ms: int = 1000): + self.enabled = enabled + self.chunk_ms = chunk_ms + self._t0 = time.monotonic() # 进程起点,用于算 rel_ms / chunk_id + self._f = None + self._w = None + + # ── 音频活动/静默相位判定(用于给每帧图标 phase)── + # 简单能量门限:rms > 阈值算"活动",否则"静默"。阈值可调。 + self._voice_rms_gate = 0.01 + self._last_audio_active_rel_ms = -1e9 # 最近一次音频活动的相对时刻 + self._audio_active = False + + # ── 音频按秒聚合缓存 ── + self._agg_bucket = -1 # 当前聚合到第几秒 + self._agg_pkts = 0 + self._agg_seqgap = 0 # 本秒内 seq 跳变累计(= 真丢包数) + self._agg_rms_sum = 0.0 + self._agg_active_pkts = 0 + self._last_seq = None # 上一包 seq,用于算 gap + + if self.enabled: + p = Path(path or f"timing_{time.strftime('%Y%m%d_%H%M%S')}.csv") + self._f = open(p, "w", newline="", encoding="utf-8") + self._w = csv.writer(self._f) + # 统一表头:kind 区分 grab / audio 两类行 + self._w.writerow([ + "kind", # "grab" 或 "audio" + "rel_ms", # 相对进程启动的毫秒(对齐两类事件的时间轴) + "chunk_id", # rel_ms // chunk_ms,看事件落在第几个 chunk + "seq", + # grab 专用 + "grab_ms", # 本次取图/一轮漏斗耗时 + "jpeg_bytes", + "since_last_grab_ms", + "audio_phase", # 取这帧图时音频是 active / silent(相位) + "ms_since_voice",# 距最近一次音频活动多久(找静默缝) + # grab 专用 —— 漏斗字段 + "reason", # 漏斗决策:send/severe_shake/unstable/need_focus/orient... + "judge_ms", # run_funnel 判定耗时 + "af_ms", # 对焦触发+settle+重抓耗时(0=没触发对焦) + "n_frames", # 本轮抓帧数 + # audio 专用(按秒聚合) + "audio_pps", # 这一秒的包数 + "audio_seqgap", # 这一秒 seq 跳变累计 = 真丢包数(不是固件 reserved) + "audio_rms", # 这一秒平均 rms + "audio_active_pps", # 这一秒里"活动"包数 + ]) + print(f"[TimingProbe] writing {p}") + + def _rel_ms(self) -> float: + return (time.monotonic() - self._t0) * 1000.0 + + # ── 取图事件 ── + def mark_grab(self, seq: int, grab_ms: float, jpeg_bytes: int, + since_last_ms: float, reason: str = "", judge_ms=None, + af_ms=None, n_frames=None) -> None: + if not self.enabled: + return + rel = self._rel_ms() + phase = "active" if self._audio_active else "silent" + ms_since_voice = rel - self._last_audio_active_rel_ms + if ms_since_voice > 1e8: + ms_since_voice = -1 # 还没出现过音频活动 + self._w.writerow([ + "grab", round(rel, 1), int(rel // self.chunk_ms), seq, + round(grab_ms, 1), jpeg_bytes, round(since_last_ms, 1), + phase, round(ms_since_voice, 1), + reason, judge_ms if judge_ms is not None else "", + af_ms if af_ms is not None else "", + n_frames if n_frames is not None else "", + "", "", "", "", # audio 专用列留空 + ]) + self._f.flush() + + # ── 音频事件(每包调,内部按秒聚合写一行)── + # 注意:固件包头第4字段是 reserved(pad),不是丢包数;真丢包用 seq 跳变推断。 + def mark_audio(self, seq: int, n_samples: int, rms: float) -> None: + if not self.enabled: + return + rel = self._rel_ms() + + # 更新相位状态(供 mark_grab 读) + self._audio_active = rms > self._voice_rms_gate + if self._audio_active: + self._last_audio_active_rel_ms = rel + + # seq 跳变 = 真丢包(PC 视角:应收 seq 连续,缺号即丢) + gap = 0 + if self._last_seq is not None: + d = seq - self._last_seq - 1 + if 0 < d < 10000: # 合理范围,排除重连/回绕 + gap = d + self._last_seq = seq + + # 按秒聚合 + bucket = int(rel // 1000) + if self._agg_bucket == -1: + self._agg_bucket = bucket + if bucket != self._agg_bucket: + self._flush_audio_bucket() + self._agg_bucket = bucket + self._agg_pkts += 1 + self._agg_seqgap += gap + self._agg_rms_sum += rms + if rms > self._voice_rms_gate: + self._agg_active_pkts += 1 + + def _flush_audio_bucket(self) -> None: + if self._agg_pkts == 0: + return + rel = self._agg_bucket * 1000.0 + avg_rms = self._agg_rms_sum / self._agg_pkts + self._w.writerow([ + "audio", round(rel, 1), int(rel // self.chunk_ms), "", + "", "", "", "", "", # grab 基础列留空 + "", "", "", "", # grab 漏斗列留空 + self._agg_pkts, self._agg_seqgap, round(avg_rms, 4), self._agg_active_pkts, + ]) + self._f.flush() + self._agg_pkts = 0 + self._agg_seqgap = 0 + self._agg_rms_sum = 0.0 + self._agg_active_pkts = 0 + + def close(self) -> None: + if not self.enabled: + return + try: + self._flush_audio_bucket() + if self._f: + self._f.close() + except Exception: + pass diff --git a/extensions/assistive_harness/prompts/README.md b/extensions/assistive_harness/prompts/README.md new file mode 100644 index 0000000..38fb5ac --- /dev/null +++ b/extensions/assistive_harness/prompts/README.md @@ -0,0 +1,43 @@ +# User-editable Skill prompts + +These files are the system prompts used when the Voice Skill Harness creates a +new MiniCPM-o Duplex Session. Prompt text is read again on every activation, so +editing an existing `.txt` file takes effect on the next Skill switch without +restarting the Harness service. + +## Shipped prompts + +| Skill ID | Prompt file | Default | +|---|---|---| +| `idle_chat` | `idle_chat_zh.txt` | enabled | +| `find_object` | `find_object_zh.txt` | enabled | +| `read_text` | `read_text_zh.txt` | enabled | +| `describe_scene` | `describe_scene_zh.txt` | enabled | +| `obstacle_avoidance` | `obstacle_avoidance_zh.txt` | enabled / experimental | + +The find/read/obstacle task bodies were copied from the frozen AAAI_SI C1 +prompts. `find_object_zh.txt` additionally contains `{{target}}`, because the +new Session must receive the target extracted from the command that closed the +old Session. + +Source directory: + +`C:\Users\Lenovo\AI_Glasses_0618\AAAI_SI\submission_release\AAAI27_AISI_Anonymous_Code_Data\prompts` + +## Editing an existing prompt + +1. Back up the target `.txt` file. +2. Replace its contents with a UTF-8 system prompt. +3. Keep every declared template variable, such as `{{target}}`. +4. Switch to chat/another Skill and activate this Skill again. (The same + Skill/same slots command is intentionally deduplicated.) The new hot Session + will read the new text and record its rendered SHA-256 in telemetry. + +## Adding a Skill + +Create another `.txt` file and add a matching entry under `skills:` in +`../config/skills.example.yaml`. Configuration changes require restarting the +8021 Harness service; prompt-only changes do not. + +Obstacle avoidance has not passed a safety evaluation. Use it only for +stationary, supervised tests; never treat the Demo as a mobility safety device. diff --git a/extensions/assistive_harness/prompts/describe_scene_zh.txt b/extensions/assistive_harness/prompts/describe_scene_zh.txt new file mode 100644 index 0000000..b19376b --- /dev/null +++ b/extensions/assistive_harness/prompts/describe_scene_zh.txt @@ -0,0 +1,8 @@ +当前技能:场景描述。 + +规则: +1. 用一到三句话概括当前画面的主要物体、位置关系和明显状态。 +2. 优先描述门口、桌面、道路、人物、显著文字和可能影响用户行动的大物体。 +3. 只描述当前可见证据;看不清时直接说画面不清楚。 +4. 不给出未经验证的距离、路线或安全保证。 +5. 避免反复描述没有变化的内容。 diff --git a/extensions/assistive_harness/prompts/find_object_zh.txt b/extensions/assistive_harness/prompts/find_object_zh.txt new file mode 100644 index 0000000..affe3a2 --- /dev/null +++ b/extensions/assistive_harness/prompts/find_object_zh.txt @@ -0,0 +1,9 @@ +你是智能眼镜找物助手。你能看到用户当前第一视角画面,并听到用户要找的目标。 + +当前寻找目标:{{target}} + +上述目标已经由外部 Harness 从用户语音中识别。新会话启动后,直接寻找该目标,不要再次询问目标是什么。 +用户问完后,必须直接根据当前画面回答,不要先说“好的”“我来找”“稍等”。 +如果目标在画面里可见,用一句话说清它的位置、方向和附近锚点,例如“复印机在左前方,靠近窗户”。 +如果目标不可见,就说“没看到”,并给一个具体下一步建议,例如转向、靠近、抬头或调整角度。 +只描述画面中确实可见的内容,不要凭常识猜测。回答尽量短。 diff --git a/extensions/assistive_harness/prompts/idle_chat_zh.txt b/extensions/assistive_harness/prompts/idle_chat_zh.txt new file mode 100644 index 0000000..a558053 --- /dev/null +++ b/extensions/assistive_harness/prompts/idle_chat_zh.txt @@ -0,0 +1,8 @@ +你是一副面向视障用户的本地 AI 眼镜助手。 + +规则: +1. 只根据当前音频、视频和明确上下文回答,不要编造看不清或没听清的内容。 +2. 回答简洁、自然,优先一到三句话。 +3. 不要主动给出未经验证的距离、安全或行动指令。 +4. 用户的“停一下、重新开始、找物、识字”等控制命令由外部 Harness 处理;不要争夺控制权,也不要重复解释系统机制。 +5. 没有足够证据时,直接说明不确定,并建议用户停稳或调整视角。 diff --git a/extensions/assistive_harness/prompts/obstacle_avoidance_zh.txt b/extensions/assistive_harness/prompts/obstacle_avoidance_zh.txt new file mode 100644 index 0000000..82cb340 --- /dev/null +++ b/extensions/assistive_harness/prompts/obstacle_avoidance_zh.txt @@ -0,0 +1,9 @@ +你是智能眼镜避障助手。你能看到用户当前第一视角画面,并听到用户询问前方障碍。 + +用户问完后,必须直接根据当前画面回答,不要只说“好的”“我会留意”。 +如果能确认障碍,用一句短话说明障碍是什么、位于左前方/正前方/右前方或地面哪里,并给出立即可执行的安全建议,例如停下、向左绕行或向右绕行。 +只根据画面中确实可见的障碍和可通行空间判断,不要猜测,不要把普通物体误报为障碍。 +如果摄像头没有朝向行进方向、地面不可见、画面被遮挡或证据不足,明确回答“当前画面不足以判断前方是否安全”,建议用户先停下并把镜头转向前方或地面。 +在无法确认通行空间时,不得声称“前方安全”或直接给出通行方向。 +如果障碍随后进入画面或画面质量改善,应立即根据新画面更新判断。 +回答尽量简短。 diff --git a/extensions/assistive_harness/prompts/read_text_zh.txt b/extensions/assistive_harness/prompts/read_text_zh.txt new file mode 100644 index 0000000..5d104b6 --- /dev/null +++ b/extensions/assistive_harness/prompts/read_text_zh.txt @@ -0,0 +1,7 @@ +你是智能眼镜读字助手。你能看到用户当前第一视角画面,并听到用户要求读字。 + +用户一开口要求读字,你必须回答,不能保持沉默。 +用户问完后,直接读出画面里清晰可见的文字,不要先说“好的”“我来”。 +只输出你看清的文字、数字或符号;看不清的字不要猜,不要根据物品常识补全。 +如果只能看清部分文字,可以只读出看清的部分。 +如果整体看不清,也必须回答“看不清”,并建议靠近、正对文字或重新对焦。 diff --git a/extensions/assistive_harness/registry.py b/extensions/assistive_harness/registry.py new file mode 100644 index 0000000..35b2fc1 --- /dev/null +++ b/extensions/assistive_harness/registry.py @@ -0,0 +1,117 @@ +from __future__ import annotations + +import hashlib +import re +from dataclasses import dataclass +from pathlib import Path +from typing import Any + +import yaml + + +class RegistryError(ValueError): + pass + + +@dataclass(frozen=True, slots=True) +class RenderedPrompt: + skill_id: str + text: str + path: str + sha256: str + slots: dict[str, Any] + + +class SkillRegistry: + def __init__(self, config_path: str | Path): + self.config_path = Path(config_path).resolve() + raw = yaml.safe_load(self.config_path.read_text(encoding="utf-8")) or {} + self.version = int(raw.get("version", 1)) + self.default_skill = str(raw.get("default_skill", "idle_chat")) + self.control = dict(raw.get("control") or {}) + self.skills: dict[str, dict[str, Any]] = dict(raw.get("skills") or {}) + if self.default_skill not in self.skills: + raise RegistryError(f"default skill is missing: {self.default_skill}") + self._validate_prompt_files() + + def _prompt_path(self, skill_id: str) -> Path: + spec = self.get(skill_id) + path = Path(str(spec.get("prompt_file") or "")) + if not path.is_absolute(): + path = self.config_path.parent / path + return path.resolve() + + def prompt_path(self, skill_id: str) -> Path: + """Return the user-editable prompt path exposed by the registry.""" + return self._prompt_path(skill_id) + + def _validate_prompt_files(self) -> None: + for skill_id, spec in self.skills.items(): + if not isinstance(spec, dict): + raise RegistryError(f"invalid skill spec: {skill_id}") + path = self._prompt_path(skill_id) + if not path.is_file(): + raise RegistryError(f"prompt file is missing for {skill_id}: {path}") + + def get(self, skill_id: str) -> dict[str, Any]: + spec = self.skills.get(skill_id) + if spec is None: + raise RegistryError(f"unknown skill: {skill_id}") + if not isinstance(spec, dict): + raise RegistryError(f"invalid skill spec: {skill_id}") + return spec + + def is_enabled(self, skill_id: str) -> bool: + return bool(self.get(skill_id).get("enabled", False)) + + def cooldown_ms(self, skill_id: str) -> int: + return int(self.get(skill_id).get("cooldown_ms", 0)) + + def task_trigger( + self, skill_id: str, slots: dict[str, Any] | None = None + ) -> str: + """Render the optional one-shot command sent to a fresh Skill Session.""" + text = str(self.get(skill_id).get("task_trigger") or "").strip() + slots = dict(slots or {}) + variables = set(re.findall(r"\{\{\s*([a-zA-Z_][\w]*)\s*\}\}", text)) + missing = sorted(name for name in variables if not str(slots.get(name, "")).strip()) + if missing: + raise RegistryError(f"missing task trigger variables for {skill_id}: {missing}") + for name in variables: + text = re.sub( + r"\{\{\s*" + re.escape(name) + r"\s*\}\}", + str(slots[name]), + text, + ) + return text + + def render(self, skill_id: str, slots: dict[str, Any] | None = None) -> RenderedPrompt: + if not self.is_enabled(skill_id): + raise RegistryError(f"skill is disabled: {skill_id}") + slots = dict(slots or {}) + spec = self.get(skill_id) + schema = dict(spec.get("slot_schema") or {}) + for name, slot_spec in schema.items(): + if bool((slot_spec or {}).get("required")) and not str(slots.get(name, "")).strip(): + raise RegistryError(f"missing required slot '{name}' for {skill_id}") + + path = self._prompt_path(skill_id) + text = path.read_text(encoding="utf-8") + variables = set(re.findall(r"\{\{\s*([a-zA-Z_][\w]*)\s*\}\}", text)) + missing = sorted(name for name in variables if name not in slots) + if missing: + raise RegistryError(f"missing prompt variables for {skill_id}: {missing}") + for name in variables: + text = re.sub( + r"\{\{\s*" + re.escape(name) + r"\s*\}\}", + str(slots[name]), + text, + ) + digest = hashlib.sha256(text.encode("utf-8")).hexdigest() + return RenderedPrompt( + skill_id=skill_id, + text=text, + path=str(path), + sha256=digest, + slots=slots, + ) diff --git a/extensions/assistive_harness/router.py b/extensions/assistive_harness/router.py new file mode 100644 index 0000000..43038f5 --- /dev/null +++ b/extensions/assistive_harness/router.py @@ -0,0 +1,262 @@ +from __future__ import annotations + +import re +import time +from dataclasses import dataclass + +from .registry import SkillRegistry +from .schemas import ControlEvent, ControlIntent + + +_PUNCTUATION = ",,。!?!?;;::、\"'“”‘’" +_SPEECH_PARTICLES = ("嗯", "啊", "呀", "吧", "呢", "啦", "哦") + + +def normalize_text(text: str) -> str: + compact = re.sub(r"\s+", "", text or "").lower() + return compact.strip(_PUNCTUATION) + + +def _strip_speech_particles(text: str) -> str: + cleaned = text + while cleaned and any(cleaned.endswith(item) for item in _SPEECH_PARTICLES): + cleaned = cleaned[:-1] + return cleaned + + +def _collapse_repeated_tail(text: str, max_width: int = 4) -> str: + """Collapse a short duplicated ASR tail such as ``手机手机`` or ``母母母``.""" + + cleaned = text + while cleaned: + collapsed = False + for width in range(min(max_width, len(cleaned) // 2), 0, -1): + if cleaned[-width:] == cleaned[-2 * width : -width]: + cleaned = cleaned[:-width] + collapsed = True + break + if not collapsed: + return cleaned + return cleaned + + +def _clean_slot_value(value: str) -> str: + cleaned = _strip_speech_particles(value.strip(_PUNCTUATION)) + cleaned = _collapse_repeated_tail(cleaned) + return _strip_speech_particles(cleaned) + + +@dataclass(slots=True) +class RouteResult: + intent: ControlIntent + skill_id: str | None = None + slots: dict[str, str] | None = None + reason: str = "" + confidence: float = 1.0 + + +class RuleIntentRouter: + """Small deterministic Chinese intent router with exact control commands.""" + + def __init__(self, registry: SkillRegistry): + self.registry = registry + control = registry.control + self.stop_phrases = { + normalize_text(item) + for item in (control.get("stop_speech") or {}).get("phrases", []) + } + self.stop_embedded_phrases = { + normalize_text(item) + for item in (control.get("stop_speech") or {}).get("embedded_phrases", []) + } + self.resume_embedded_phrases = { + normalize_text(item) + for item in (control.get("resume_speech") or {}).get("embedded_phrases", []) + } + self.reset_phrases = { + normalize_text(item) + for item in (control.get("reset_session") or {}).get("phrases", []) + } + self.reset_embedded_phrases = { + normalize_text(item) + for item in (control.get("reset_session") or {}).get("embedded_phrases", []) + } + self.return_phrases = { + normalize_text(item) + for item in (control.get("return_to_chat") or {}).get("phrases", []) + } + self.cancel_phrases = { + normalize_text(item) + for item in (control.get("cancel_skill") or {}).get("phrases", []) + } + + @staticmethod + def _is_explicit_command(compact: str, phrases: set[str]) -> bool: + polite_prefixes = ("麻烦你先", "请", "麻烦", "你先", "请你", "可以", "能不能") + polite_suffixes = ("一下", "好吗", "可以吗", "啊", "呀", "吧", "呢", "啦", "哦") + + # FunASR commonly appends a sentence particle ("停一下啊") or repeats + # the final syllable ("停一下下"). Build a small, bounded closure of + # command-only variants instead of doing substring matching, so a + # sentence such as "我刚才没有说停一下" still cannot trigger STOP. + candidates: set[str] = set() + pending = [compact] + while pending: + candidate = pending.pop() + if not candidate or candidate in candidates: + continue + candidates.add(candidate) + + for prefix in polite_prefixes: + if candidate.startswith(prefix) and len(candidate) > len(prefix): + pending.append(candidate[len(prefix) :]) + for suffix in polite_suffixes: + if candidate.endswith(suffix) and len(candidate) > len(suffix): + pending.append(candidate[: -len(suffix)]) + if len(candidate) >= 2 and candidate[-1] == candidate[-2]: + pending.append(candidate[:-1]) + + return any(candidate in phrases for candidate in candidates) + + @staticmethod + def _contains_command(compact: str, phrases: set[str]) -> bool: + """Use a literal command-anchor protocol; do not infer sentence meaning.""" + return any(phrase and phrase in compact for phrase in phrases) + + @staticmethod + def _skill_variants(compact: str) -> list[str]: + """Build bounded FunASR variants while retaining an explicit Skill verb.""" + + candidates: set[str] = set() + pending = [compact] + while pending: + candidate = pending.pop() + if not candidate or candidate in candidates: + continue + candidates.add(candidate) + + without_particles = _strip_speech_particles(candidate) + if without_particles and without_particles != candidate: + pending.append(without_particles) + + # Observed FunASR variants include ``一下下`` and omission of the + # pronoun in ``帮我找/读``. Restore only that pronoun; never invent + # a missing Skill verb such as ``找`` or ``读``. + collapsed_action = re.sub(r"一下下+", "一下", candidate) + if collapsed_action != candidate: + pending.append(collapsed_action) + if candidate.startswith("帮") and not candidate.startswith("帮我"): + pending.append("帮我" + candidate[1:]) + + for prefix in ("请你", "麻烦你", "麻烦", "请", "能不能"): + if candidate.startswith(prefix) and len(candidate) > len(prefix): + pending.append(candidate[len(prefix) :]) + polite_prefixes = ("请你", "麻烦你", "麻烦", "请", "能不能") + + def noise_rank(candidate: str) -> tuple[int, int, int, int, int, str]: + return ( + int(bool(re.search(r"一下下+", candidate))), + int(_strip_speech_particles(candidate) != candidate), + int(candidate.startswith("帮") and not candidate.startswith("帮我")), + int(candidate.startswith(polite_prefixes)), + len(candidate), + candidate, + ) + + # Regexes can match both the raw and corrected ASR text. Prefer the + # bounded, lower-noise candidate so slot extraction is deterministic. + return sorted(candidates, key=noise_rank) + + def route(self, utterance: str) -> RouteResult: + compact = normalize_text(utterance) + if not compact: + return RouteResult(ControlIntent.NONE, reason="empty") + + variants = self._skill_variants(compact) + + if self._is_explicit_command(compact, self.stop_phrases): + return RouteResult(ControlIntent.STOP_SPEECH, reason="explicit stop command") + # STOP wins if a transcript contains both anchors. + if self._contains_command(compact, self.stop_embedded_phrases): + return RouteResult(ControlIntent.STOP_SPEECH, reason="stop anchor contained") + # RESET wins over RESUME and all skills. The protocol is deliberately + # literal: callers can add a product wake name to the same sentence. + if ( + self._contains_command(compact, self.reset_embedded_phrases) + or self._is_explicit_command(compact, self.reset_phrases) + ): + return RouteResult( + ControlIntent.RESET_SESSION, + skill_id=self.registry.default_skill, + slots={}, + reason=( + "reset anchor contained" + if self._contains_command(compact, self.reset_embedded_phrases) + else "explicit reset command" + ), + ) + if self._contains_command(compact, self.resume_embedded_phrases): + return RouteResult(ControlIntent.RESUME_SPEECH, reason="resume anchor contained") + if self._is_explicit_command(compact, self.cancel_phrases): + return RouteResult(ControlIntent.CANCEL_SKILL, reason="explicit cancel command") + if self._is_explicit_command(compact, self.return_phrases): + return RouteResult( + ControlIntent.RETURN_TO_CHAT, + skill_id=self.registry.default_skill, + slots={}, + reason="explicit return-to-chat command", + ) + + for skill_id, spec in self.registry.skills.items(): + if not bool(spec.get("enabled", False)) or skill_id == self.registry.default_skill: + continue + for pattern in spec.get("activation_patterns") or []: + for candidate in variants: + match = re.fullmatch(str(pattern), candidate) + if match: + slots = { + key: _clean_slot_value(value) + for key, value in match.groupdict().items() + if value + } + return RouteResult( + ControlIntent.ACTIVATE_SKILL, + skill_id=skill_id, + slots=slots, + reason=f"matched {skill_id} pattern", + ) + phrases = [normalize_text(item) for item in spec.get("activation_phrases") or []] + if any( + candidate == phrase or candidate.startswith(phrase) + for candidate in variants + for phrase in phrases + ): + return RouteResult( + ControlIntent.ACTIVATE_SKILL, + skill_id=skill_id, + slots={}, + reason=f"matched {skill_id} phrase", + ) + + return RouteResult(ControlIntent.NONE, reason="ordinary chat") + + def make_event( + self, + route: RouteResult, + *, + event_id: int, + asr_event_id: int, + utterance: str, + created_at_ms: float | None = None, + ) -> ControlEvent: + return ControlEvent( + event_id=event_id, + intent=route.intent, + skill_id=route.skill_id, + slots=dict(route.slots or {}), + utterance=utterance, + confidence=route.confidence, + asr_event_id=asr_event_id, + created_at_ms=created_at_ms if created_at_ms is not None else time.time() * 1000, + reason=route.reason, + ) diff --git a/extensions/assistive_harness/schemas.py b/extensions/assistive_harness/schemas.py new file mode 100644 index 0000000..edad067 --- /dev/null +++ b/extensions/assistive_harness/schemas.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from dataclasses import asdict, dataclass, field +from enum import Enum +from typing import Any + + +class ControlIntent(str, Enum): + STOP_SPEECH = "stop_speech" + RESUME_SPEECH = "resume_speech" + RESET_SESSION = "reset_session" + CANCEL_SKILL = "cancel_skill" + RETURN_TO_CHAT = "return_to_chat" + ACTIVATE_SKILL = "activate_skill" + NONE = "none" + + +@dataclass(slots=True) +class ASREvent: + event_id: int + utterance: str + started_at_ms: float + ended_at_ms: float + final_at_ms: float + model: str + device: str + + def to_dict(self) -> dict[str, Any]: + return asdict(self) + + +@dataclass(slots=True) +class ControlEvent: + event_id: int + intent: ControlIntent + utterance: str + confidence: float + asr_event_id: int + created_at_ms: float + skill_id: str | None = None + slots: dict[str, Any] = field(default_factory=dict) + reason: str = "" + system_prompt: str | None = None + prompt_path: str | None = None + prompt_sha256: str | None = None + + def to_dict(self) -> dict[str, Any]: + payload = asdict(self) + payload["type"] = "control.intent" + payload["intent"] = self.intent.value + return payload + + +@dataclass(slots=True) +class HarnessState: + current_skill: str = "idle_chat" + current_slots: dict[str, Any] = field(default_factory=dict) + session_generation: int = 0 + control_event_id: int = 0 + asr_event_id: int = 0 + restart_in_progress: bool = False + drop_output_until_listen: bool = False + speech_hold_active: bool = False + pending_skill: dict[str, Any] | None = None + + def to_dict(self) -> dict[str, Any]: + return asdict(self) diff --git a/extensions/assistive_harness/server.py b/extensions/assistive_harness/server.py new file mode 100644 index 0000000..3d3343d --- /dev/null +++ b/extensions/assistive_harness/server.py @@ -0,0 +1,604 @@ +from __future__ import annotations + +import argparse +import asyncio +import base64 +import json +import time +import uuid +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any + +import numpy as np +import uvicorn +import yaml +from fastapi import FastAPI, WebSocket, WebSocketDisconnect +from fastapi.responses import JSONResponse + +from .asr.base import ASREngine +from .asr.energy_vad import EnergyVAD, UtteranceAudio +from .asr.funasr_engine import FunASREngine +from .cv.base import CVObservation, FrameEnvelope +from .cv.pipeline import CVPipeline +from .cv.registry import CVProviderRegistry, build_provider_registry +from .echo_guard import EchoGuard +from .model_log import ModelTurnAccumulator +from .registry import SkillRegistry +from .router import RuleIntentRouter +from .schemas import ASREvent, ControlEvent, ControlIntent +from .state_machine import HarnessController +from .telemetry import TelemetryWriter + + +def now_ms() -> float: + return time.time() * 1000.0 + + +def _decode_float32(value: str) -> np.ndarray: + raw = base64.b64decode(value, validate=True) + if len(raw) % 4: + raise ValueError("float32 payload length is not divisible by four") + return np.frombuffer(raw, dtype=" int: + self.event_counter += 1 + return self.event_counter + + def refresh_echo_speaking(self) -> None: + self.echo.set_ai_speaking(self.model_speaking or self.playback_active) + + def record_model_turn(self, turn: dict[str, Any]) -> None: + self.telemetry.write("model", turn) + self.telemetry.append_model_transcript(turn) + print( + "[AssistiveHarness][MODEL] " + f"turn={turn.get('turn_index')} role={turn.get('role')} " + f"generation={turn.get('generation')} skill={turn.get('skill_id')} " + f"audio_ms={turn.get('audio_ms')} text={turn.get('text')!r}", + flush=True, + ) + + async def recognize( + self, utterance: UtteranceAudio + ) -> dict[str, Any] | list[dict[str, Any]]: + async with self.asr_lock: + started = now_ms() + result = await asyncio.to_thread( + self.engine.transcribe, utterance.audio, self.vad.sample_rate + ) + return await self.route_transcript( + result.text, + confidence=result.confidence, + model=result.model, + device=result.device, + started_at_ms=utterance.started_at_ms, + ended_at_ms=utterance.ended_at_ms, + final_at_ms=now_ms(), + inference_started_at_ms=started, + ) + + def recognize_in_background(self, utterance: UtteranceAudio) -> None: + """Keep receiving microphone frames while a completed utterance is decoded.""" + + async def run() -> None: + try: + await self.outbound.put(await self.recognize(utterance)) + except asyncio.CancelledError: + raise + except Exception as exc: + await self.outbound.put( + { + "type": "error", + "code": "asr_failed", + "message": str(exc), + } + ) + + task = asyncio.create_task(run()) + self.background_tasks.add(task) + task.add_done_callback(self.background_tasks.discard) + + async def route_transcript( + self, + text: str, + *, + confidence: float, + model: str, + device: str, + started_at_ms: float | None = None, + ended_at_ms: float | None = None, + final_at_ms: float | None = None, + inference_started_at_ms: float | None = None, + ) -> dict[str, Any] | list[dict[str, Any]]: + finished = final_at_ms if final_at_ms is not None else now_ms() + asr_id = self.next_event_id() + asr_event = ASREvent( + event_id=asr_id, + utterance=text.strip(), + started_at_ms=started_at_ms if started_at_ms is not None else finished, + ended_at_ms=ended_at_ms if ended_at_ms is not None else finished, + final_at_ms=finished, + model=model, + device=device, + ) + self.telemetry.write("asr", asr_event.to_dict()) + transcript_payload: dict[str, Any] = { + "type": "asr.transcript", + "asr_event_id": asr_id, + "utterance": asr_event.utterance, + "confidence": confidence, + "final_at_ms": finished, + } + if inference_started_at_ms is not None: + self.telemetry.metric("asr_inference_ms", finished - inference_started_at_ms, asr_id) + + route = self.router.route(asr_event.utterance) + echo = self.echo.evaluate(asr_event.utterance, route.intent, at_ms=finished) + print( + "[AssistiveHarness][ASR] " + f"text={asr_event.utterance!r} intent={route.intent.value} " + f"echo={'allow' if echo.allow else 'drop'} reason={echo.reason}", + flush=True, + ) + self.telemetry.write( + "echo", + { + "asr_event_id": asr_id, + "allow": echo.allow, + "reason": echo.reason, + "similarity": echo.similarity, + }, + ) + if not echo.allow or route.intent is ControlIntent.NONE: + transcript_payload["suppressed"] = not echo.allow + transcript_payload["reason"] = echo.reason if not echo.allow else route.reason + return transcript_payload + + control_id = self.next_event_id() + event = self.router.make_event( + route, + event_id=control_id, + asr_event_id=asr_id, + utterance=asr_event.utterance, + created_at_ms=finished, + ) + decision = self.controller.process(event, now_ms=finished) + print( + "[AssistiveHarness][CONTROL] " + f"intent={route.intent.value} accepted={decision.accepted} " + f"action={decision.action} event={control_id}", + flush=True, + ) + payload = { + **decision.payload, + "accepted": decision.accepted, + "action": decision.action, + "decision_reason": decision.reason, + "client_id": self.client_id, + } + self.telemetry.write("control", payload) + if route.intent in { + ControlIntent.RESET_SESSION, + ControlIntent.CANCEL_SKILL, + ControlIntent.RETURN_TO_CHAT, + ControlIntent.ACTIVATE_SKILL, + }: + self.telemetry.write( + "skill", + { + "control_event_id": control_id, + "intent": route.intent.value, + "skill_id": event.skill_id, + "slots": event.slots, + "prompt_path": event.prompt_path, + "prompt_sha256": event.prompt_sha256, + "accepted": decision.accepted, + "action": decision.action, + }, + ) + if decision.accepted: + return [transcript_payload, payload] + transcript_payload["suppressed"] = True + transcript_payload["reason"] = decision.reason + return transcript_payload + + +class AssistiveHarnessService: + def __init__( + self, + config_path: str | Path, + *, + enabled: bool, + model_path: str | None = None, + allow_test_injection: bool = False, + engine: ASREngine | None = None, + cv_providers: CVProviderRegistry | None = None, + ): + self.config_path = Path(config_path).resolve() + self.config = yaml.safe_load(self.config_path.read_text(encoding="utf-8")) or {} + self.registry = SkillRegistry(self.config_path) + self.cv_config = dict(self.config.get("cv") or {}) + self.cv_providers = cv_providers or build_provider_registry( + self.config, config_dir=self.config_path.parent + ) + self.enabled = bool(enabled) + self.allow_test_injection = bool(allow_test_injection) + asr_cfg = dict(self.config.get("asr") or {}) + resolved_model_path = model_path or str(asr_cfg.get("model_path") or "") + if engine is not None: + self.engine = engine + elif self.enabled: + if not resolved_model_path: + raise ValueError("--model-path is required when the Harness is enabled") + self.engine = FunASREngine( + resolved_model_path, + device=str(asr_cfg.get("device") or "cpu"), + ) + else: + self.engine = None + run_id = time.strftime("%Y%m%d_%H%M%S") + "_" + uuid.uuid4().hex[:8] + telemetry_root = Path(__file__).resolve().parent / "runs" + self.telemetry = TelemetryWriter(telemetry_root, run_id, self.config) + self.clients: dict[str, ClientRuntime] = {} + self.started_at_ms = now_ms() + + def make_runtime(self, client_id: str) -> ClientRuntime: + if self.engine is None: + raise RuntimeError("Harness is disabled") + asr_cfg = dict(self.config.get("asr") or {}) + echo_cfg = dict(self.config.get("echo_guard") or {}) + return ClientRuntime( + client_id=client_id, + registry=self.registry, + router=RuleIntentRouter(self.registry), + engine=self.engine, + telemetry=self.telemetry, + vad=EnergyVAD( + rms_threshold=float(asr_cfg.get("rms_threshold", 0.012)), + min_speech_ms=int(asr_cfg.get("min_speech_ms", 180)), + end_silence_ms=int(asr_cfg.get("end_silence_ms", 450)), + max_utterance_ms=int(asr_cfg.get("max_utterance_ms", 8000)), + preroll_ms=int(asr_cfg.get("preroll_ms", 200)), + ), + echo=EchoGuard( + window_ms=int(echo_cfg.get("window_ms", 20000)), + similarity_threshold=float(echo_cfg.get("similarity_threshold", 0.86)), + ), + controller=HarnessController(self.registry), + allow_test_injection=self.allow_test_injection, + cv=CVPipeline( + self.cv_providers, + on_observation=lambda observation: self.telemetry.write( + "cv", observation.to_dict() + ), + on_metric=lambda name, value: self.telemetry.metric(name, value), + queue_size=int(self.cv_config.get("queue_size", 1)), + inference_timeout_ms=float( + self.cv_config.get("inference_timeout_ms", 2000) + ), + worker_name=f"assistive-cv-{client_id[:8]}", + ), + ) + + def create_app(self) -> FastAPI: + app = FastAPI(title="Assistive Voice Skill Harness", version="0.1.0") + + @app.get("/health") + async def health() -> JSONResponse: + return JSONResponse( + { + "ok": True, + "enabled": self.enabled, + "clients": len(self.clients), + "uptime_ms": now_ms() - self.started_at_ms, + "asr_loaded": bool(getattr(self.engine, "loaded", self.engine is not None)), + "config": self.config_path.name, + "cv_providers": sorted(self.cv_providers.providers), + } + ) + + @app.get("/skills") + async def skills() -> JSONResponse: + return JSONResponse( + { + "ok": True, + "default_skill": self.registry.default_skill, + "config_path": str(self.config_path), + "skills": { + skill_id: { + "enabled": self.registry.is_enabled(skill_id), + "description": str(spec.get("description") or ""), + "prompt_path": str(self.registry.prompt_path(skill_id)), + "requires_session_restart": bool( + spec.get("requires_session_restart", True) + ), + "cv_mode": str(spec.get("cv_mode") or "disabled"), + "cv_provider": str(spec.get("cv_provider") or "noop"), + } + for skill_id, spec in self.registry.skills.items() + }, + } + ) + + @app.on_event("shutdown") + async def write_shutdown_summary() -> None: + self.telemetry.write_summary( + { + "enabled": self.enabled, + "uptime_ms": now_ms() - self.started_at_ms, + "connected_clients_at_shutdown": len(self.clients), + "asr_loaded": bool(getattr(self.engine, "loaded", self.engine is not None)), + } + ) + + @app.websocket("/ws/control") + async def control_socket(websocket: WebSocket) -> None: + if not self.enabled: + await websocket.close(code=1013, reason="Harness disabled") + return + await websocket.accept() + client_id = websocket.query_params.get("client_id") or uuid.uuid4().hex + runtime = self.make_runtime(client_id) + self.clients[client_id] = runtime + + async def send_outbound() -> None: + while True: + response = await runtime.outbound.get() + if isinstance(response, list): + for item in response: + await websocket.send_json(item) + elif response is not None: + await websocket.send_json(response) + + sender = asyncio.create_task(send_outbound()) + await runtime.outbound.put( + { + "type": "harness.ready", + "client_id": client_id, + "state": runtime.controller.state.to_dict(), + } + ) + try: + while True: + message = await websocket.receive_json() + response = await self._handle_message(runtime, message) + if response is not None: + await runtime.outbound.put(response) + except WebSocketDisconnect: + runtime.controller.mark_disconnected() + finally: + pending_turn = runtime.model_turns.flush() + if pending_turn is not None: + runtime.record_model_turn(pending_turn) + sender.cancel() + for task in tuple(runtime.background_tasks): + task.cancel() + await runtime.cv.close() + await asyncio.gather(sender, *runtime.background_tasks, return_exceptions=True) + self.clients.pop(client_id, None) + + return app + + async def _handle_message( + self, runtime: ClientRuntime, message: dict[str, Any] + ) -> dict[str, Any] | list[dict[str, Any]] | None: + message_type = str(message.get("type") or "") + if message_type == "ping": + return {"type": "pong", "at_ms": now_ms()} + if message_type == "audio.mirror": + audio = _decode_float32(str(message.get("audio_b64") or "")) + utterance = runtime.vad.feed(audio, float(message.get("started_at_ms") or now_ms())) + if utterance is None: + return None + runtime.recognize_in_background(utterance) + return None + if message_type == "asr.inject": + if not runtime.allow_test_injection: + return {"type": "error", "code": "test_injection_disabled"} + return await runtime.route_transcript( + str(message.get("text") or ""), + confidence=1.0, + model="injected-test-only", + device="none", + ) + if message_type in ("funnel.stop", "funnel.resume"): + # 漏斗 reject/恢复:程序直接触发,不经 ASR/router 文字匹配。 + # 复用 controller.process + STOP_SPEECH/RESUME_SPEECH,和真人「停一下/恢复对话」 + # 走完全相同的下游(设备端收到 control.intent 执行 stop_speech/resume_speech)。 + # 归口 8021:telemetry 统一记录,标 source=funnel 以区分真人还是漏斗触发。 + is_stop = message_type == "funnel.stop" + intent = ControlIntent.STOP_SPEECH if is_stop else ControlIntent.RESUME_SPEECH + event = ControlEvent( + event_id=runtime.next_event_id(), + intent=intent, + utterance="[%s]" % message_type, + confidence=1.0, + asr_event_id=runtime.next_event_id(), + created_at_ms=now_ms(), + reason=str(message.get("reason") or "funnel"), + ) + decision = runtime.controller.process(event, now_ms=event.created_at_ms) + payload = { + **decision.payload, + "accepted": decision.accepted, + "action": decision.action, + "decision_reason": decision.reason, + "source": "funnel", + "client_id": runtime.client_id, + } + runtime.telemetry.write("control", payload) + print( + "[AssistiveHarness][FUNNEL] " + "type=%s accepted=%s action=%s reason=%s" + % (message_type, decision.accepted, decision.action, event.reason), + flush=True, + ) + return payload if decision.accepted else None + if message_type == "model.state": + event = dict(message) + runtime.telemetry.write("model", event) + speaking = str(message.get("state") or "") == "speak" + runtime.model_speaking = speaking + runtime.refresh_echo_speaking() + text = str(message.get("text") or "") + if speaking and text: + runtime.echo.note_model_text(text) + for turn in runtime.model_turns.feed(event): + runtime.record_model_turn(turn) + return None + if message_type == "playback.state": + event = dict(message) + runtime.telemetry.write("model", event) + runtime.playback_active = bool(message.get("active")) + runtime.refresh_echo_speaking() + return None + if message_type == "session.state": + event = dict(message) + runtime.telemetry.write("session", event) + phase = str(message.get("phase") or "") + if phase == "listen": + runtime.controller.mark_listen_fence() + elif phase == "restart_complete": + runtime.controller.mark_restart_complete( + str(message.get("skill_id") or runtime.registry.default_skill), + dict(message.get("slots") or {}), + int(message.get("generation") or 0), + ) + return None + if message_type == "control.ack": + if bool(message.get("ok")) and str(message.get("intent") or "") == "stop_speech": + # Browser STOP has already flushed/blocked playback. Do not + # leave EchoGuard in a stale speaking state while the user + # immediately issues the next explicit command. + runtime.model_speaking = False + runtime.playback_active = False + runtime.refresh_echo_speaking() + runtime.telemetry.write("session", dict(message)) + print( + "[AssistiveHarness][ACK] " + f"intent={message.get('intent')} ok={message.get('ok')} " + f"generation={message.get('generation')} " + f"session={message.get('old_session_id') or '-'}" + f"->{message.get('new_session_id') or '-'} " + f"cleanup={message.get('cleanup_mode') or '-'} " + f"restart_ms={message.get('restart_latency_ms') or '-'} " + f"stale_text={message.get('dropped_old_text') or 0} " + f"stale_audio={message.get('dropped_old_audio') or 0}", + flush=True, + ) + metric = message.get("restart_latency_ms") + if isinstance(metric, (int, float)): + runtime.telemetry.metric( + "restart_latency_ms", float(metric), int(message.get("event_id") or 0) + ) + return None + if message_type == "frame.shadow": + at_ms = float(message.get("timestamp_ms") or now_ms()) + max_fps = max(0.0, float(self.cv_config.get("max_fps", 1))) + if max_fps <= 0: + return None + if at_ms - runtime.last_frame_ms < 1000.0 / max_fps: + return None + skill_id = runtime.controller.state.current_skill + skill_spec = runtime.registry.get(skill_id) + mode = str(skill_spec.get("cv_mode") or self.cv_config.get("mode") or "disabled") + if mode == "disabled": + return None + provider_id = str(skill_spec.get("cv_provider") or "noop") + frame_b64 = str(message.get("jpeg_b64") or "") + frame_id = str(message.get("frame_id") or uuid.uuid4().hex) + try: + frame = base64.b64decode(frame_b64, validate=True) if frame_b64 else None + except Exception as exc: + runtime.telemetry.write( + "cv", + CVObservation( + frame_id=frame_id, + timestamp_ms=at_ms, + skill_id=skill_id, + provider=f"{mode}:{provider_id}", + values={"status": "error"}, + error=f"InvalidFramePayload: {exc}", + ).to_dict(), + ) + return None + runtime.last_frame_ms = at_ms + runtime.cv.submit( + FrameEnvelope( + frame=frame, + frame_id=frame_id, + timestamp_ms=at_ms, + skill_id=skill_id, + slots=dict(runtime.controller.state.current_slots), + mode=mode, + provider_id=provider_id, + ) + ) + return None + return {"type": "error", "code": "unknown_message", "message_type": message_type} + + +def build_parser() -> argparse.ArgumentParser: + default_config = Path(__file__).resolve().parent / "config" / "skills.example.yaml" + parser = argparse.ArgumentParser(description="Optional local assistive voice-skill Harness") + parser.add_argument("--config", default=str(default_config)) + parser.add_argument("--enabled", action="store_true", help="explicit opt-in; default is off") + parser.add_argument("--host", default="127.0.0.1") + parser.add_argument("--port", type=int, default=8021) + parser.add_argument("--model-path", default=None) + parser.add_argument("--allow-test-injection", action="store_true") + parser.add_argument("--certfile", default=None) + parser.add_argument("--keyfile", default=None) + return parser + + +def main() -> None: + args = build_parser().parse_args() + service = AssistiveHarnessService( + args.config, + enabled=args.enabled, + model_path=args.model_path, + allow_test_injection=args.allow_test_injection, + ) + if isinstance(service.engine, FunASREngine): + warmup_started = time.perf_counter() + print("[AssistiveHarness] loading and warming FunASR before accepting clients...") + service.engine.warm_up() + print( + "[AssistiveHarness] FunASR ready " + f"({time.perf_counter() - warmup_started:.2f}s)" + ) + uvicorn.run( + service.create_app(), + host=args.host, + port=args.port, + ssl_certfile=args.certfile, + ssl_keyfile=args.keyfile, + ) + + +if __name__ == "__main__": + main() diff --git a/extensions/assistive_harness/state_machine.py b/extensions/assistive_harness/state_machine.py new file mode 100644 index 0000000..e0cd9ce --- /dev/null +++ b/extensions/assistive_harness/state_machine.py @@ -0,0 +1,115 @@ +from __future__ import annotations + +import time +from dataclasses import dataclass +from typing import Any + +from .registry import RegistryError, SkillRegistry +from .schemas import ControlEvent, ControlIntent, HarnessState + + +@dataclass(slots=True) +class ControlDecision: + accepted: bool + action: str + reason: str + payload: dict[str, Any] + + +class HarnessController: + def __init__(self, registry: SkillRegistry): + self.registry = registry + self.state = HarnessState(current_skill=registry.default_skill) + self._seen_asr_ids: set[int] = set() + self._last_skill_activation_ms: dict[tuple[str, tuple[tuple[str, str], ...]], float] = {} + + @staticmethod + def _skill_key(skill_id: str, slots: dict[str, Any]) -> tuple[str, tuple[tuple[str, str], ...]]: + return skill_id, tuple(sorted((str(key), str(value)) for key, value in slots.items())) + + def process(self, event: ControlEvent, now_ms: float | None = None) -> ControlDecision: + now = now_ms if now_ms is not None else time.time() * 1000 + if event.asr_event_id in self._seen_asr_ids: + return ControlDecision(False, "ignore", "duplicate_asr_event", {}) + self._seen_asr_ids.add(event.asr_event_id) + self.state.asr_event_id = max(self.state.asr_event_id, event.asr_event_id) + self.state.control_event_id = max(self.state.control_event_id, event.event_id) + + if event.intent is ControlIntent.STOP_SPEECH: + self.state.speech_hold_active = True + self.state.drop_output_until_listen = True + return ControlDecision(True, "stop_speech", "highest_priority", event.to_dict()) + + if event.intent is ControlIntent.RESUME_SPEECH: + self.state.speech_hold_active = False + self.state.drop_output_until_listen = False + return ControlDecision(True, "resume_speech", "explicit_resume", event.to_dict()) + + if event.intent is ControlIntent.RESET_SESSION: + rendered = self.registry.render(self.registry.default_skill, {}) + event.skill_id = self.registry.default_skill + event.slots = {} + event.system_prompt = rendered.text + event.prompt_path = rendered.path + event.prompt_sha256 = rendered.sha256 + self.state.restart_in_progress = True + self.state.pending_skill = None + return ControlDecision(True, "restart_session", "explicit_reset", event.to_dict()) + + if event.intent in {ControlIntent.CANCEL_SKILL, ControlIntent.RETURN_TO_CHAT}: + event.skill_id = self.registry.default_skill + event.slots = {} + + if event.intent in { + ControlIntent.CANCEL_SKILL, + ControlIntent.RETURN_TO_CHAT, + ControlIntent.ACTIVATE_SKILL, + }: + skill_id = event.skill_id or self.registry.default_skill + slots = dict(event.slots or {}) + try: + rendered = self.registry.render(skill_id, slots) + except RegistryError as exc: + return ControlDecision(False, "clarify", str(exc), event.to_dict()) + + if self.state.restart_in_progress: + self.state.pending_skill = {"skill_id": skill_id, "slots": slots} + return ControlDecision(True, "queue_skill", "restart_in_progress_last_write_wins", event.to_dict()) + + key = self._skill_key(skill_id, slots) + last = self._last_skill_activation_ms.get(key) + cooldown = self.registry.cooldown_ms(skill_id) + if skill_id == self.state.current_skill and slots == self.state.current_slots: + return ControlDecision(False, "ignore", "same_skill_same_slots", event.to_dict()) + if last is not None and now - last < cooldown: + return ControlDecision(False, "ignore", "skill_cooldown", event.to_dict()) + + self._last_skill_activation_ms[key] = now + event.system_prompt = rendered.text + event.prompt_path = rendered.path + event.prompt_sha256 = rendered.sha256 + self.state.restart_in_progress = True + return ControlDecision(True, "activate_skill", "skill_switch", event.to_dict()) + + return ControlDecision(False, "pass_chat", "ordinary_chat", event.to_dict()) + + def mark_restart_complete(self, skill_id: str, slots: dict[str, Any], generation: int) -> dict[str, Any] | None: + self.state.current_skill = skill_id + self.state.current_slots = dict(slots) + self.state.session_generation = int(generation) + self.state.restart_in_progress = False + self.state.speech_hold_active = False + self.state.drop_output_until_listen = False + pending = self.state.pending_skill + self.state.pending_skill = None + return pending + + def mark_listen_fence(self) -> None: + if not self.state.speech_hold_active: + self.state.drop_output_until_listen = False + + def mark_disconnected(self) -> None: + self.state.restart_in_progress = False + self.state.pending_skill = None + self.state.speech_hold_active = False + self.state.drop_output_until_listen = False diff --git a/extensions/assistive_harness/summarize_reset_run.py b/extensions/assistive_harness/summarize_reset_run.py new file mode 100644 index 0000000..1e8ce19 --- /dev/null +++ b/extensions/assistive_harness/summarize_reset_run.py @@ -0,0 +1,97 @@ +from __future__ import annotations + +import argparse +import json +import math +from pathlib import Path +from typing import Any + + +def nearest_rank(values: list[float], quantile: float) -> float | None: + if not values: + return None + ordered = sorted(values) + index = max(0, math.ceil(len(ordered) * quantile) - 1) + return ordered[index] + + +def load_events(path: Path) -> list[dict[str, Any]]: + if not path.exists(): + return [] + events: list[dict[str, Any]] = [] + for line in path.read_text(encoding="utf-8").splitlines(): + if not line.strip(): + continue + try: + events.append(json.loads(line)) + except json.JSONDecodeError: + continue + return events + + +def resolve_run(value: str | None) -> Path: + runs_root = Path(__file__).resolve().parent / "runs" + if value: + candidate = Path(value).expanduser().resolve() + if not candidate.is_dir(): + raise SystemExit(f"Run directory does not exist: {candidate}") + return candidate + candidates = [path for path in runs_root.iterdir() if path.is_dir()] + if not candidates: + raise SystemExit(f"No run directories found under {runs_root}") + return max(candidates, key=lambda path: path.stat().st_mtime) + + +def main() -> None: + parser = argparse.ArgumentParser(description="Summarize real browser RESET telemetry") + parser.add_argument("--run", help="specific run directory; defaults to the newest run") + args = parser.parse_args() + + run_dir = resolve_run(args.run) + events = load_events(run_dir / "session_events.jsonl") + resets = [ + event + for event in events + if event.get("type") == "control.ack" + and event.get("intent") == "reset_session" + ] + successes = [event for event in resets if event.get("ok") is True] + latencies = [ + float(event["restart_latency_ms"]) + for event in successes + if isinstance(event.get("restart_latency_ms"), (int, float)) + ] + changed_ids = [ + event + for event in successes + if event.get("old_session_id") + and event.get("new_session_id") + and event.get("old_session_id") != event.get("new_session_id") + ] + + print(f"Run: {run_dir}") + print(f"RESET success: {len(successes)}/{len(resets)}") + print(f"Session ID changed: {len(changed_ids)}/{len(successes)}") + if latencies: + print(f"Restart P50: {nearest_rank(latencies, 0.50):.1f} ms") + print(f"Restart P90: {nearest_rank(latencies, 0.90):.1f} ms") + print(f"Restart max: {max(latencies):.1f} ms") + else: + print("Restart P50/P90: no RESET latency samples") + print( + "Dropped stale callbacks (cumulative): " + f"text={max((int(event.get('dropped_old_text') or 0) for event in successes), default=0)}, " + f"audio={max((int(event.get('dropped_old_audio') or 0) for event in successes), default=0)}" + ) + print("Audible old-output pollution: manual observation required") + for index, event in enumerate(successes, start=1): + print( + f"{index:02d}. generation={event.get('generation')} " + f"session={event.get('old_session_id') or '-'}->{event.get('new_session_id') or '-'} " + f"cleanup={event.get('cleanup_mode') or '-'} " + f"latency={float(event.get('restart_latency_ms') or 0):.1f} ms" + ) + + +if __name__ == "__main__": + main() diff --git a/extensions/assistive_harness/telemetry.py b/extensions/assistive_harness/telemetry.py new file mode 100644 index 0000000..2e3aa18 --- /dev/null +++ b/extensions/assistive_harness/telemetry.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +import csv +import json +import threading +import time +from pathlib import Path +from typing import Any + +import yaml + + +class TelemetryWriter: + FILES = { + "asr": "asr_events.jsonl", + "control": "control_events.jsonl", + "session": "session_events.jsonl", + "skill": "skill_events.jsonl", + "cv": "cv_events.jsonl", + "echo": "echo_events.jsonl", + "model": "model_events.jsonl", + } + + def __init__(self, root: str | Path, run_id: str, config: dict[str, Any]): + self.run_id = run_id + self.run_dir = Path(root) / run_id + self.run_dir.mkdir(parents=True, exist_ok=True) + self._lock = threading.Lock() + (self.run_dir / "config_snapshot.yaml").write_text( + yaml.safe_dump(config, allow_unicode=True, sort_keys=True), + encoding="utf-8", + ) + self._metrics_path = self.run_dir / "metrics.csv" + with self._metrics_path.open("w", newline="", encoding="utf-8") as handle: + csv.writer(handle).writerow(["timestamp_ms", "metric", "value", "event_id"]) + + def write(self, stream: str, payload: dict[str, Any]) -> None: + filename = self.FILES[stream] + record = {"logged_at_ms": time.time() * 1000, **payload} + line = json.dumps(record, ensure_ascii=False, sort_keys=True) + with self._lock: + with (self.run_dir / filename).open("a", encoding="utf-8") as handle: + handle.write(line + "\n") + + def metric(self, name: str, value: float, event_id: int | None = None) -> None: + with self._lock: + with self._metrics_path.open("a", newline="", encoding="utf-8") as handle: + csv.writer(handle).writerow([time.time() * 1000, name, value, event_id or ""]) + + def write_summary(self, summary: dict[str, Any]) -> None: + (self.run_dir / "summary.json").write_text( + json.dumps(summary, ensure_ascii=False, indent=2, sort_keys=True), + encoding="utf-8", + ) + + def append_model_transcript(self, turn: dict[str, Any]) -> None: + text = str(turn.get("text") or "").replace("\r", " ").replace("\n", " ") + line = ( + f"turn={turn.get('turn_index')} role={turn.get('role')} " + f"generation={turn.get('generation')} skill={turn.get('skill_id')} " + f"audio_ms={turn.get('audio_ms')} text={text}\n" + ) + with self._lock: + with (self.run_dir / "model_transcript.txt").open( + "a", encoding="utf-8" + ) as handle: + handle.write(line) diff --git a/extensions/assistive_harness/tests/__init__.py b/extensions/assistive_harness/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/extensions/assistive_harness/tests/test_core.py b/extensions/assistive_harness/tests/test_core.py new file mode 100644 index 0000000..83066c9 --- /dev/null +++ b/extensions/assistive_harness/tests/test_core.py @@ -0,0 +1,402 @@ +from __future__ import annotations + +import asyncio +import tempfile +import time +import unittest +from pathlib import Path + +import numpy as np + +from extensions.assistive_harness.asr.energy_vad import EnergyVAD +from extensions.assistive_harness.cv.noop import ShadowCVProvider +from extensions.assistive_harness.cv.base import CVObservation, FrameEnvelope +from extensions.assistive_harness.cv.pipeline import CVPipeline +from extensions.assistive_harness.cv.registry import CVProviderRegistry +from extensions.assistive_harness.echo_guard import EchoGuard +from extensions.assistive_harness.model_log import ModelTurnAccumulator +from extensions.assistive_harness.registry import RegistryError, SkillRegistry +from extensions.assistive_harness.router import RuleIntentRouter +from extensions.assistive_harness.schemas import ControlIntent +from extensions.assistive_harness.state_machine import HarnessController + + +CONFIG = Path(__file__).resolve().parents[1] / "config" / "skills.example.yaml" + + +class RouterCorpusTests(unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.registry = SkillRegistry(CONFIG) + cls.router = RuleIntentRouter(cls.registry) + + def test_control_and_skill_corpus_over_fifty_utterances(self) -> None: + corpus = [ + ("停一下", ControlIntent.STOP_SPEECH, None), + ("停一下啊", ControlIntent.STOP_SPEECH, None), + ("停一下下", ControlIntent.STOP_SPEECH, None), + ("同一下", ControlIntent.STOP_SPEECH, None), + ("同一下下", ControlIntent.STOP_SPEECH, None), + ("等一下", ControlIntent.STOP_SPEECH, None), + ("等一一下", ControlIntent.STOP_SPEECH, None), + ("请停一下啊", ControlIntent.STOP_SPEECH, None), + ("请停一下", ControlIntent.STOP_SPEECH, None), + ("麻烦你先停一下", ControlIntent.STOP_SPEECH, None), + ("别说了", ControlIntent.STOP_SPEECH, None), + ("请你别说了好吗", ControlIntent.STOP_SPEECH, None), + ("闭嘴", ControlIntent.STOP_SPEECH, None), + ("停止播报", ControlIntent.STOP_SPEECH, None), + ("安静", ControlIntent.STOP_SPEECH, None), + ("你先停一下,我有个问题", ControlIntent.STOP_SPEECH, None), + ("说得有点长了麻烦停一下吧", ControlIntent.STOP_SPEECH, None), + ("现在可以先停一下然后听我说吗", ControlIntent.STOP_SPEECH, None), + ("不停停一下继续介绍", ControlIntent.STOP_SPEECH, None), + ("我刚才没有说停一下", ControlIntent.STOP_SPEECH, None), + ("请不要停一下,继续介绍", ControlIntent.STOP_SPEECH, None), + ("停一下是什么意思", ControlIntent.STOP_SPEECH, None), + ("恢复对话", ControlIntent.RESUME_SPEECH, None), + ("好了现在恢复对话吧", ControlIntent.RESUME_SPEECH, None), + ("乐奇恢复对话", ControlIntent.RESUME_SPEECH, None), + ("停一下然后恢复对话", ControlIntent.STOP_SPEECH, None), + ("重新开始", ControlIntent.RESET_SESSION, "idle_chat"), + ("请重新开始", ControlIntent.RESET_SESSION, "idle_chat"), + ("重置会话", ControlIntent.NONE, None), + ("乐奇请重新开始", ControlIntent.RESET_SESSION, "idle_chat"), + ("你有点卡了请重新开始会话", ControlIntent.RESET_SESSION, "idle_chat"), + ("请现在重置会话然后听我说", ControlIntent.NONE, None), + ("停一下然后重新开始", ControlIntent.STOP_SPEECH, None), + ("恢复对话然后重新开始", ControlIntent.RESET_SESSION, "idle_chat"), + ("新建会话", ControlIntent.NONE, None), + ("清空上下文", ControlIntent.NONE, None), + ("回到聊天", ControlIntent.RETURN_TO_CHAT, "idle_chat"), + ("请回到聊天", ControlIntent.RETURN_TO_CHAT, "idle_chat"), + ("回到普通聊天", ControlIntent.RETURN_TO_CHAT, "idle_chat"), + ("回到普通聊天天", ControlIntent.RETURN_TO_CHAT, "idle_chat"), + ("退出技能", ControlIntent.RETURN_TO_CHAT, "idle_chat"), + ("普通聊天", ControlIntent.RETURN_TO_CHAT, "idle_chat"), + ("取消任务", ControlIntent.CANCEL_SKILL, None), + ("不找了", ControlIntent.CANCEL_SKILL, None), + ("不读了", ControlIntent.CANCEL_SKILL, None), + ("帮我找手机", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("帮我找一下我的手机", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("帮我找一下手机", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("帮我找一下下我的手机嗯", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("帮找一下手机手机", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("请帮我找钥匙", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("水杯在哪", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("书在哪里", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("看到门卡了吗", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("有没有雨伞", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("麻烦帮我找眼镜", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("请问钱包在哪", ControlIntent.ACTIVATE_SKILL, "find_object"), + ("读一下", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("读一下这行字", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("请读一下", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("帮我读一下这个杯子上的字母母母", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("帮读一下这个水杯上面的字字个", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("帮我识字", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("上面写了什么", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("这是什么字", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("读文字", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("请你读文字", ControlIntent.ACTIVATE_SKILL, "read_text"), + ("描述一下", ControlIntent.ACTIVATE_SKILL, "describe_scene"), + ("帮我描述一下", ControlIntent.ACTIVATE_SKILL, "describe_scene"), + ("看看周围", ControlIntent.ACTIVATE_SKILL, "describe_scene"), + ("帮我避障", ControlIntent.ACTIVATE_SKILL, "obstacle_avoidance"), + ("前面有障碍吗", ControlIntent.ACTIVATE_SKILL, "obstacle_avoidance"), + ("今天天气怎么样", ControlIntent.NONE, None), + ("停止是一个动词", ControlIntent.NONE, None), + ("他说让我闭嘴但我没同意", ControlIntent.NONE, None), + ("重新开始这个词怎么翻译", ControlIntent.RESET_SESSION, "idle_chat"), + ("我在读一本书", ControlIntent.NONE, None), + ("你觉得这杯水怎么样", ControlIntent.NONE, None), + ("普通聊天机器人是什么", ControlIntent.NONE, None), + ("请介绍一下上海", ControlIntent.NONE, None), + ("我不想清空上下文因为还有用", ControlIntent.NONE, None), + ("帮我分析这段话", ControlIntent.NONE, None), + ("帮我一下手机手机", ControlIntent.NONE, None), + ("能听见我吗", ControlIntent.NONE, None), + ("今天周几", ControlIntent.NONE, None), + ("为什么会这样", ControlIntent.NONE, None), + ("继续说", ControlIntent.NONE, None), + ("接着说", ControlIntent.NONE, None), + ("你继续说话吧", ControlIntent.NONE, None), + ("谢谢", ControlIntent.NONE, None), + ("你好", ControlIntent.NONE, None), + ("左边有什么", ControlIntent.NONE, None), + ("给我讲个笑话", ControlIntent.NONE, None), + ("", ControlIntent.NONE, None), + ("。", ControlIntent.NONE, None), + ("安静是一种状态", ControlIntent.NONE, None), + ("取消任务是不是一个按钮", ControlIntent.NONE, None), + ("有人说不读了然后离开", ControlIntent.NONE, None), + ] + self.assertGreaterEqual(len(corpus), 50) + for utterance, expected_intent, expected_skill in corpus: + with self.subTest(utterance=utterance): + result = self.router.route(utterance) + self.assertEqual(result.intent, expected_intent) + self.assertEqual(result.skill_id, expected_skill) + + def test_find_target_slot(self) -> None: + result = self.router.route("请帮我找深绿色的书") + self.assertEqual(result.slots, {"target": "深绿色的书"}) + + natural = self.router.route("帮我找一下我的手机") + self.assertEqual(natural.slots, {"target": "手机"}) + + repeated = self.router.route("帮我找一下下我的手机嗯") + self.assertEqual(repeated.slots, {"target": "手机"}) + + missing_pronoun = self.router.route("帮找一下手机手机") + self.assertEqual(missing_pronoun.slots, {"target": "手机"}) + + +class RegistryAndStateTests(unittest.TestCase): + def setUp(self) -> None: + self.registry = SkillRegistry(CONFIG) + self.router = RuleIntentRouter(self.registry) + self.controller = HarnessController(self.registry) + + def event(self, text: str, event_id: int, asr_id: int): + return self.router.make_event( + self.router.route(text), event_id=event_id, asr_event_id=asr_id, + utterance=text, created_at_ms=float(event_id * 1000), + ) + + def test_prompt_render_and_hash(self) -> None: + prompt = self.registry.render("find_object", {"target": "手机"}) + self.assertIn("当前寻找目标:手机", prompt.text) + self.assertIn("智能眼镜找物助手", prompt.text) + self.assertEqual(len(prompt.sha256), 64) + self.assertIn("手机", self.registry.task_trigger("find_object", {"target": "手机"})) + + def test_aaai_skill_prompt_files_are_user_editable_and_registered(self) -> None: + find_prompt = self.registry.render("find_object", {"target": "水杯"}) + read_prompt = self.registry.render("read_text", {}) + self.assertTrue(Path(find_prompt.path).is_file()) + self.assertTrue(Path(read_prompt.path).is_file()) + self.assertIn("当前寻找目标:水杯", find_prompt.text) + self.assertIn("智能眼镜读字助手", read_prompt.text) + self.assertTrue(self.registry.is_enabled("describe_scene")) + self.assertTrue(self.registry.is_enabled("obstacle_avoidance")) + self.assertTrue( + Path(self.registry.get("obstacle_avoidance")["prompt_file"]).name + == "obstacle_avoidance_zh.txt" + ) + + def test_required_slot_validation(self) -> None: + with self.assertRaises(RegistryError): + self.registry.render("find_object", {}) + + def test_unknown_skill_is_rejected(self) -> None: + with self.assertRaises(RegistryError): + self.registry.render("not_registered", {}) + + def test_stop_hold_requires_explicit_resume(self) -> None: + decision = self.controller.process(self.event("停一下", 1, 1)) + self.assertEqual(decision.action, "stop_speech") + self.assertTrue(self.controller.state.speech_hold_active) + self.assertTrue(self.controller.state.drop_output_until_listen) + self.controller.mark_listen_fence() + self.assertTrue(self.controller.state.speech_hold_active) + self.assertTrue(self.controller.state.drop_output_until_listen) + resumed = self.controller.process(self.event("恢复对话", 2, 2)) + self.assertEqual(resumed.action, "resume_speech") + self.assertFalse(self.controller.state.speech_hold_active) + self.assertFalse(self.controller.state.drop_output_until_listen) + + def test_reset_always_supplies_idle_prompt(self) -> None: + decision = self.controller.process(self.event("重新开始", 1, 1)) + self.assertEqual(decision.action, "restart_session") + self.assertIn("AI 眼镜助手", decision.payload["system_prompt"]) + self.assertTrue(decision.payload["prompt_path"].endswith("idle_chat_zh.txt")) + + def test_skill_activation_supplies_rendered_prompt_path_and_hash(self) -> None: + decision = self.controller.process(self.event("帮我找手机", 1, 1)) + self.assertEqual(decision.action, "activate_skill") + self.assertIn("当前寻找目标:手机", decision.payload["system_prompt"]) + self.assertTrue(decision.payload["prompt_path"].endswith("find_object_zh.txt")) + self.assertEqual(len(decision.payload["prompt_sha256"]), 64) + + def test_duplicate_asr_event_is_ignored(self) -> None: + first = self.controller.process(self.event("停一下", 1, 9)) + second = self.controller.process(self.event("停一下", 2, 9)) + self.assertTrue(first.accepted) + self.assertEqual(second.reason, "duplicate_asr_event") + + def test_same_skill_same_slots_does_not_restart(self) -> None: + first = self.controller.process(self.event("帮我找手机", 1, 1)) + self.assertTrue(first.accepted) + self.controller.mark_restart_complete("find_object", {"target": "手机"}, 1) + second = self.controller.process(self.event("帮我找手机", 2, 2), now_ms=9000) + self.assertFalse(second.accepted) + self.assertEqual(second.reason, "same_skill_same_slots") + + def test_restart_pending_is_last_write_wins(self) -> None: + self.controller.process(self.event("帮我找手机", 1, 1)) + queued_one = self.controller.process(self.event("帮我找钥匙", 2, 2)) + queued_two = self.controller.process(self.event("读一下", 3, 3)) + self.assertEqual(queued_one.action, "queue_skill") + self.assertEqual(queued_two.action, "queue_skill") + pending = self.controller.mark_restart_complete("find_object", {"target": "手机"}, 1) + self.assertEqual(pending, {"skill_id": "read_text", "slots": {}}) + + def test_disconnect_clears_restart_and_pending(self) -> None: + self.controller.process(self.event("帮我找手机", 1, 1)) + self.controller.process(self.event("读一下", 2, 2)) + self.controller.mark_disconnected() + self.assertFalse(self.controller.state.restart_in_progress) + self.assertIsNone(self.controller.state.pending_skill) + + +class EchoAndVADTests(unittest.TestCase): + def test_recent_model_echo_is_blocked_but_stop_is_allowed(self) -> None: + guard = EchoGuard(window_ms=20_000, similarity_threshold=0.8) + guard.note_model_text("请告诉我还需要什么帮助", at_ms=1000) + blocked = guard.evaluate("请告诉我还需要什么帮助", ControlIntent.NONE, at_ms=1100) + self.assertFalse(blocked.allow) + guard.set_ai_speaking(True) + allowed = guard.evaluate("停一下", ControlIntent.STOP_SPEECH, at_ms=1200) + self.assertTrue(allowed.allow) + resumed = guard.evaluate("恢复对话", ControlIntent.RESUME_SPEECH, at_ms=1300) + self.assertTrue(resumed.allow) + + skill = guard.evaluate("帮我找一下我的手机", ControlIntent.ACTIVATE_SKILL, at_ms=1400) + self.assertTrue(skill.allow) + returned = guard.evaluate("回到普通聊天", ControlIntent.RETURN_TO_CHAT, at_ms=1450) + self.assertTrue(returned.allow) + cancelled = guard.evaluate("取消任务", ControlIntent.CANCEL_SKILL, at_ms=1475) + self.assertTrue(cancelled.allow) + ordinary = guard.evaluate("今天天气怎么样", ControlIntent.NONE, at_ms=1500) + self.assertFalse(ordinary.allow) + self.assertEqual(ordinary.reason, "ordinary_skill_suppressed_while_ai_speaking") + + def test_vad_emits_one_utterance(self) -> None: + vad = EnergyVAD(rms_threshold=0.01, min_speech_ms=100, end_silence_ms=200) + frames = [np.zeros(1600, np.float32)] + frames += [np.full(1600, 0.1, np.float32) for _ in range(3)] + frames += [np.zeros(1600, np.float32) for _ in range(3)] + utterances = [] + for index, frame in enumerate(frames): + result = vad.feed(frame, index * 100.0) + if result is not None: + utterances.append(result) + self.assertEqual(len(utterances), 1) + self.assertGreater(utterances[0].audio.size, 0) + + +class ModelTurnLogTests(unittest.TestCase): + def test_streamed_fragments_are_aggregated_with_audio_duration(self) -> None: + turns = ModelTurnAccumulator() + first = turns.feed( + { + "state": "speak", + "session_id": "s1", + "generation": 2, + "skill_id": "read_text", + "text": "上海", + "audio_ms": 120, + } + ) + self.assertEqual(first, []) + second = turns.feed( + { + "state": "speak", + "session_id": "s1", + "generation": 2, + "skill_id": "read_text", + "text": "电力", + "audio_ms": 180, + "decode_end": True, + } + ) + self.assertEqual(second, []) + completed = turns.feed( + { + "state": "listen", + "session_id": "s1", + "generation": 2, + "skill_id": "read_text", + "end_of_turn": True, + } + ) + self.assertEqual(completed[0]["text"], "上海电力") + self.assertEqual(completed[0]["audio_ms"], 300.0) + + +class CVIsolationTests(unittest.IsolatedAsyncioTestCase): + async def test_shadow_provider_contains_failures(self) -> None: + class Broken: + def analyze(self, *args, **kwargs): + raise RuntimeError("synthetic CV failure") + + result = ShadowCVProvider(Broken(), "broken").analyze( + None, "f1", 1.0, "find_object", {} + ) + self.assertEqual(result.provider, "shadow:broken") + self.assertIn("synthetic CV failure", result.error or "") + + async def test_pipeline_is_non_blocking_and_latest_frame_wins(self) -> None: + observations: list[CVObservation] = [] + + class Slow: + def analyze(self, frame, frame_id, timestamp_ms, skill_id, slots): + time.sleep(0.08) + return CVObservation( + frame_id=frame_id, + timestamp_ms=timestamp_ms, + skill_id=skill_id, + provider="slow", + ) + + pipeline = CVPipeline( + CVProviderRegistry({"slow": Slow()}), + on_observation=observations.append, + inference_timeout_ms=500, + ) + pipeline.submit(FrameEnvelope(b"1", "f1", 1.0, "find_object", {}, "shadow", "slow")) + # submit() must return before the synchronous provider completes. A + # wall-clock threshold is flaky on a loaded Windows workstation. + self.assertEqual(observations, []) + self.assertIsNotNone(pipeline.worker_task) + await asyncio.sleep(0.01) + pipeline.submit(FrameEnvelope(b"2", "f2", 2.0, "find_object", {}, "shadow", "slow")) + pipeline.submit(FrameEnvelope(b"3", "f3", 3.0, "find_object", {}, "shadow", "slow")) + for _ in range(100): + if len(observations) >= 2: + break + await asyncio.sleep(0.01) + snapshot = pipeline.snapshot() + await pipeline.close() + self.assertEqual([item.frame_id for item in observations], ["f1", "f3"]) + self.assertEqual(snapshot["dropped_frames"], 1) + + async def test_pipeline_timeout_is_observed_without_escaping(self) -> None: + observations: list[CVObservation] = [] + + class TooSlow: + def analyze(self, frame, frame_id, timestamp_ms, skill_id, slots): + time.sleep(0.08) + return CVObservation(frame_id, timestamp_ms, skill_id, "too_slow") + + pipeline = CVPipeline( + CVProviderRegistry({"too_slow": TooSlow()}), + on_observation=observations.append, + inference_timeout_ms=10, + ) + pipeline.submit( + FrameEnvelope(b"x", "timeout", 1.0, "find_object", {}, "shadow", "too_slow") + ) + for _ in range(50): + if observations: + break + await asyncio.sleep(0.005) + snapshot = pipeline.snapshot() + await pipeline.close() + self.assertIn("TimeoutError", observations[0].error or "") + self.assertEqual(snapshot["timeout_count"], 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/extensions/assistive_harness/tests/test_cv_yolo.py b/extensions/assistive_harness/tests/test_cv_yolo.py new file mode 100644 index 0000000..59476f8 --- /dev/null +++ b/extensions/assistive_harness/tests/test_cv_yolo.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +import unittest +from pathlib import Path + +import cv2 +import numpy as np + +from extensions.assistive_harness.cv.yolo_onnx import YoloOnnxProvider + + +MODEL = ( + Path(__file__).resolve().parents[4] + / "OmniHarness" + / "mini_omni_harness" + / "models" + / "yolo26n.onnx" +) + + +@unittest.skipUnless(MODEL.is_file(), "local YOLO reference weights are unavailable") +class YoloOnnxSmokeTests(unittest.TestCase): + def test_blank_jpeg_runs_real_onnx_inference(self) -> None: + ok, encoded = cv2.imencode(".jpg", np.zeros((480, 640, 3), dtype=np.uint8)) + self.assertTrue(ok) + observation = YoloOnnxProvider(MODEL).analyze( + encoded.tobytes(), + "blank", + 1.0, + "find_object", + {"target": "手机"}, + ) + self.assertEqual(observation.provider, "yolo_onnx") + self.assertEqual(observation.values["status"], "ok") + self.assertEqual(observation.values["canonical_label"], "cell phone") + self.assertEqual(observation.values["model"], "yolo26n.onnx") + self.assertIsInstance(observation.values["detections"], list) + + +if __name__ == "__main__": + unittest.main() diff --git a/extensions/assistive_harness/tests/test_phase_b_rokid.py b/extensions/assistive_harness/tests/test_phase_b_rokid.py new file mode 100644 index 0000000..1787b69 --- /dev/null +++ b/extensions/assistive_harness/tests/test_phase_b_rokid.py @@ -0,0 +1,352 @@ +from __future__ import annotations + +import asyncio +import base64 +import unittest +from pathlib import Path +from typing import Any + +import numpy as np + +from extensions.assistive_harness.phase_b.rokid_runtime import ( + AudioMirrorChunker, + DropOldestAudioQueue, + GatewaySessionManager, + LatestFrame, + PCSpeaker, + PhaseBRokidRuntime, + RokidRuntimeConfig, + SessionSpec, + apply_pcm16_gain, + make_session_ready_chime, + pcm16le_to_float32, +) +from extensions.assistive_harness.registry import SkillRegistry + + +CONFIG = Path(__file__).resolve().parents[1] / "config" / "skills.example.yaml" + + +class FakeSpeaker: + def __init__(self) -> None: + self.blocked = False + self.flush_count = 0 + self.resume_count = 0 + self.enqueued: list[tuple[np.ndarray, int]] = [] + + async def start(self) -> None: + pass + + async def enqueue(self, samples: np.ndarray, generation: int) -> None: + if not self.blocked: + self.enqueued.append((samples.copy(), generation)) + + async def block_and_flush(self) -> None: + self.blocked = True + self.flush_count += 1 + + async def resume(self) -> None: + self.blocked = False + self.resume_count += 1 + + async def close(self) -> None: + pass + + def pending_ms(self) -> float: + return 0.0 + + +class FakeTelemetry: + connected = True + + def __init__(self) -> None: + self.messages: list[dict[str, Any]] = [] + + async def send(self, payload: dict[str, Any]) -> None: + self.messages.append(dict(payload)) + + +class FakeSession: + next_id = 0 + + def __init__( + self, + _config: RokidRuntimeConfig, + spec: SessionSpec, + _audio_queue: DropOldestAudioQueue, + _latest_frame: LatestFrame, + _gate: object, + on_result: object, + ) -> None: + type(self).next_id += 1 + self.spec = spec + self.on_result = on_result + self.session_id = f"fake-{type(self).next_id}" + self.status = "created" + self.last_error = "" + self.started = False + self.stopped_with: str | None = None + self.injected_tasks: list[str] = [] + + async def start(self) -> None: + self.started = True + self.status = "running" + + async def stop(self, cleanup_mode: str) -> None: + self.stopped_with = cleanup_mode + self.status = "stopped" + + async def inject_task(self, text: str) -> bool: + self.injected_tasks.append(text) + return True + + +class RokidAudioBoundaryTests(unittest.IsolatedAsyncioTestCase): + def test_health_marks_device_input_not_ready_before_first_packet(self) -> None: + runtime = PhaseBRokidRuntime( + RokidRuntimeConfig(skills_config=str(CONFIG), play_audio=False), + speaker=FakeSpeaker(), + session_factory=FakeSession, + ) + self.assertFalse(runtime.health()["device_input_ready"]) + runtime.stats.audio_packets = 1 + self.assertTrue(runtime.health()["device_input_ready"]) + + def test_pcm16_conversion_and_mirror_chunking(self) -> None: + raw = np.array([-32768, 0, 32767], dtype=" None: + raw = np.array([-4_000, 1_000, 4_000], dtype=" None: + chime = make_session_ready_chime() + self.assertEqual(chime.dtype, np.float32) + self.assertGreater(chime.size, 24_000 * 0.15) + self.assertLess(chime.size, 24_000 * 0.25) + self.assertLessEqual(float(np.max(np.abs(chime))), 0.321) + self.assertGreater(float(np.max(np.abs(chime))), 0.30) + + async def test_drop_oldest_queue_preserves_newest_packets(self) -> None: + queue = DropOldestAudioQueue(max_packets=2) + queue.put_nowait(b"old") + queue.put_nowait(b"middle") + queue.put_nowait(b"new") + self.assertEqual(queue.dropped_packets, 1) + self.assertEqual(await queue.get(0.01), b"middle") + self.assertEqual(await queue.get(0.01), b"new") + + async def test_pc_speaker_stop_closes_and_resume_reopens_stream(self) -> None: + class FakeOutputStream: + def __init__(self) -> None: + self.abort_count = 0 + self.close_count = 0 + + def abort(self) -> None: + self.abort_count += 1 + + def close(self) -> None: + self.close_count += 1 + + speaker = PCSpeaker() + old_stream = FakeOutputStream() + new_stream = FakeOutputStream() + speaker._stream = old_stream + + await speaker.block_and_flush() + self.assertTrue(speaker.blocked) + self.assertIsNone(speaker._stream) + self.assertEqual(old_stream.abort_count, 1) + self.assertEqual(old_stream.close_count, 1) + + speaker._open_stream = lambda: setattr(speaker, "_stream", new_stream) + await speaker.resume() + self.assertFalse(speaker.blocked) + self.assertIs(speaker._stream, new_stream) + + +class PhaseBControlContractTests(unittest.IsolatedAsyncioTestCase): + def setUp(self) -> None: + FakeSession.next_id = 0 + self.registry = SkillRegistry(CONFIG) + self.speaker = FakeSpeaker() + self.telemetry = FakeTelemetry() + self.sessions: list[FakeSession] = [] + + def factory(*args: Any) -> FakeSession: + session = FakeSession(*args) + self.sessions.append(session) + return session + + self.manager = GatewaySessionManager( + RokidRuntimeConfig( + skills_config=str(CONFIG), + play_audio=False, + playback_echo_tail_s=0.0, + ), + self.registry, + DropOldestAudioQueue(max_packets=4), + LatestFrame(), + self.speaker, + session_factory=factory, + ) + self.manager.harness = self.telemetry + + async def test_stop_and_resume_flush_pc_output_and_ack(self) -> None: + await self.manager.start_initial() + stop_ack = await self.manager.handle_control( + { + "type": "control.intent", + "event_id": 1, + "intent": "stop_speech", + "accepted": True, + } + ) + self.assertTrue(stop_ack["ok"]) + self.assertTrue(self.manager.gate.speech_hold_active) + self.assertTrue(self.speaker.blocked) + self.assertEqual(self.speaker.flush_count, 1) + + resume_ack = await self.manager.handle_control( + { + "type": "control.intent", + "event_id": 2, + "intent": "resume_speech", + "accepted": True, + } + ) + self.assertTrue(resume_ack["ok"]) + self.assertFalse(self.manager.gate.speech_hold_active) + self.assertFalse(self.speaker.blocked) + self.assertEqual( + [message["intent"] for message in self.telemetry.messages if message.get("type") == "control.ack"], + ["stop_speech", "resume_speech"], + ) + + async def test_skill_switch_replaces_session_and_fences_old_output(self) -> None: + await self.manager.start_initial() + old_session = self.sessions[0] + ack = await self.manager.handle_control( + { + "type": "control.intent", + "event_id": 3, + "intent": "activate_skill", + "accepted": True, + "skill_id": "read_text", + "slots": {}, + } + ) + new_session = self.sessions[1] + self.assertTrue(ack["ok"]) + self.assertEqual(old_session.stopped_with, "light") + self.assertTrue(new_session.started) + self.assertNotEqual(old_session.session_id, new_session.session_id) + self.assertEqual(self.manager.gate.generation, 1) + self.assertEqual(self.manager.gate.current_skill, "read_text") + self.assertEqual( + new_session.injected_tasks, + ["请立即读取当前画面中最明显的文字,只读看到的内容。"], + ) + self.assertTrue(ack["task_trigger_sent"]) + self.assertFalse(self.speaker.blocked) + self.assertTrue( + any( + message.get("type") == "session.state" + and message.get("phase") == "restart_complete" + for message in self.telemetry.messages + ) + ) + + audio = base64.b64encode(np.ones(10, dtype=np.float32).tobytes()).decode() + await self.manager.handle_result( + old_session, + {"type": "result", "text": "stale", "audio_data": audio}, + ) + self.assertEqual(self.manager.gate.dropped_old_text, 1) + self.assertEqual(self.manager.gate.dropped_old_audio, 1) + self.assertEqual(self.speaker.enqueued, []) + + await self.manager.handle_result( + new_session, + {"type": "result", "text": "current", "audio_data": audio}, + ) + self.assertEqual(len(self.speaker.enqueued), 1) + self.assertEqual(self.speaker.enqueued[0][1], 1) + + async def test_restart_complete_plays_one_local_ready_chime(self) -> None: + self.manager.config.play_audio = True + await self.manager.start_initial() + self.assertEqual(self.speaker.enqueued, []) + + ack = await self.manager.handle_control( + { + "type": "control.intent", + "event_id": 4, + "intent": "reset_session", + "accepted": True, + "skill_id": "idle_chat", + "slots": {}, + } + ) + + self.assertTrue(ack["ok"]) + self.assertEqual(len(self.speaker.enqueued), 1) + cue, generation = self.speaker.enqueued[0] + self.assertEqual(generation, 1) + self.assertGreater(cue.size, 0) + self.assertGreater(self.manager.gate.local_cue_mute_until_mono, 0.0) + + async def test_obstacle_switch_injects_one_shot_visual_task(self) -> None: + await self.manager.start_initial() + ack = await self.manager.handle_control( + { + "type": "control.intent", + "event_id": 5, + "intent": "activate_skill", + "accepted": True, + "skill_id": "obstacle_avoidance", + "slots": {}, + } + ) + self.assertTrue(ack["task_trigger_sent"]) + self.assertIn("判断当前画面", self.sessions[1].injected_tasks[0]) + + async def test_model_log_turn_ends_on_listen_not_decode_slice(self) -> None: + await self.manager.start_initial() + session = self.sessions[0] + await self.manager.handle_result( + session, + {"type": "result", "text": "上海", "end_of_turn": True}, + ) + await self.manager.handle_result( + session, + {"type": "result", "text": "电力", "end_of_turn": True}, + ) + await self.manager.handle_result( + session, + {"type": "result", "is_listen": True}, + ) + states = [ + item for item in self.telemetry.messages + if item.get("type") == "model.state" + ] + self.assertEqual([item["end_of_turn"] for item in states], [False, False, True]) + self.assertEqual([item["decode_end"] for item in states], [True, True, False]) + + +if __name__ == "__main__": + unittest.main() From a4580500c45e1f6a5258faeafa6a340457cdbd20 Mon Sep 17 00:00:00 2001 From: MajestyHenius <3051797499@qq.com> Date: Wed, 2 Sep 2026 16:47:40 +0800 Subject: [PATCH 2/3] feat: harness + CV funnel chains in the control panel - panel: four cumulative ESP32 chains (basic chat / voice control / frame selection / full anti-hallucination) plus a criteria selector; machine paths move to runtime.local.json; TLS certs are self-signed on first launch - esp32_runtime: --rotate, /v1/realtime protocol adapter, reject prompts no longer block the capture loop, every captured frame reaches the first-person view - cam_pipeline_v2: report orientation-classifier load failure instead of silently falling back to the early heuristic - docs: dependency list and setup steps in both READMEs --- .gitignore | 7 + README.md | 67 ++- README_zh.md | 69 ++- .../phase_b/assets/reject_wav/aimed_wrong.wav | Bin 0 -> 142124 bytes .../phase_b/assets/reject_wav/manifest.json | 92 ++++ .../phase_b/assets/reject_wav/need_focus.wav | Bin 0 -> 113324 bytes .../phase_b/assets/reject_wav/no_frames.wav | Bin 0 -> 105644 bytes .../phase_b/assets/reject_wav/orient.wav | Bin 0 -> 163244 bytes .../assets/reject_wav/orient_flipped.wav | Bin 0 -> 163244 bytes .../assets/reject_wav/orient_sideways.wav | Bin 0 -> 117164 bytes .../assets/reject_wav/severe_shake.wav | Bin 0 -> 142124 bytes .../phase_b/assets/reject_wav/too_dark.wav | Bin 0 -> 132524 bytes .../phase_b/assets/reject_wav/unstable.wav | Bin 0 -> 145964 bytes .../phase_b/cam_pipeline_v2.py | 15 + .../phase_b/esp32_runtime.py | 168 +++++-- .../phase_b/requirements-phase-b.txt | 36 +- .../phase_b/templates/live.html | 7 +- runtime/openglass_omni/devices.example.json | 7 + runtime/openglass_omni/panel.html | 27 +- runtime/openglass_omni/panel.py | 467 +++++++++++++++++- runtime/openglass_omni/runtime.example.json | 55 +-- 21 files changed, 897 insertions(+), 120 deletions(-) create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/aimed_wrong.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/manifest.json create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/need_focus.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/no_frames.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/orient.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/orient_flipped.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/orient_sideways.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/severe_shake.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/too_dark.wav create mode 100644 extensions/assistive_harness/phase_b/assets/reject_wav/unstable.wav create mode 100644 runtime/openglass_omni/devices.example.json diff --git a/.gitignore b/.gitignore index 0cbd177..1ecff26 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,10 @@ tmp/ *.tmp.mov *.tmp.avi *.scratch.* + +runtime.local.json +devices.json +certs/ + +# ©ʾʱԴַֿ +!extensions/assistive_harness/phase_b/assets/reject_wav/*.wav diff --git a/README.md b/README.md index df9ce6e..24f2bde 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Solid arrows represent code or artifacts present in the public repository. Dashe The control panel is intended to make **repeated runs** one-click after a one-time setup. It does not download model weights, clone upstream repositories, compile `llama.cpp-omni`, or flash the ESP32 for you. -> **Current clean-clone status:** The panel UI starts from the repository root, but the current launcher still reads machine-specific paths from `runtime/openglass_omni/panel.py`. The included `runtime.local.json` loader is not yet connected to that panel. Follow the effective configuration locations below; a code update is still required before this can be called a portable one-click installation. +> **Current clean-clone status:** The panel itself starts directly from the repository root, but the full chain still needs four out-of-repo assets prepared by hand: the `llama.cpp-omni` build, MiniCPM-o GGUF weights, the FunASR model, and the Wi-Fi credentials inside the ESP32 firmware. None of these live in this repository, and none can be fetched automatically. ### 1. Prerequisites @@ -128,6 +128,9 @@ cd .. git clone https://github.com/OpenSQZ/OpenGlass.git cd OpenGlass python -m pip install -r runtime/openglass_omni/requirements.txt + +python -m pip install -r extensions/requirements-phase-b.txt # voice control + CV funnel (harness chains only; skip if you just run basic chat) + ``` Because upstream `master` branches can change, record the exact commit SHAs used for every validated OpenSQZ Glass runtime release. Upstream changes may alter ports, arguments, protocols, TTS behavior, or process ownership. @@ -177,17 +180,32 @@ Edit `runtime/openglass_omni/devices.json`: ### 5. Configure the current launcher -At present, these are the **effective** settings: +Copy [`runtime.example.json`](runtime/openglass_omni/runtime.example.json) to +`runtime.local.json` in the same directory and fill in your machine paths. The panel reads +it at startup and uses those values instead of the defaults in `panel.py`: + +```json +{ + "conda_env": null, + "minicpm_demo_root": "D:\\path\\to\\MiniCPM-o-Demo", + "llama_server": "D:\\path\\to\\llama.cpp-omni\\build\\bin\\Release\\llama-omni-server.exe", + "llama_model": "D:\\path\\to\\MiniCPM-o-gguf\\MiniCPM-o-4_5-Q4_K_M.gguf", + "asr_model": "D:\\path\\to\\LocalASRmodel\\speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", + "glasses": { "ssid": "YOUR_WIFI", "psk": "YOUR_WIFI_PASSWORD" } +} +``` -| What to configure | Effective location now | Value | +| What to configure | Location | Value | | --- | --- | --- | -| MiniCPM-o-Demo checkout | [`panel.py` `CONFIG["minicpm_demo_dir"]`](runtime/openglass_omni/panel.py) | Absolute path containing upstream `worker.py` and `gateway.py` | -| `llama-omni-server` binary | [`panel.py` `CONFIG["procs"]["llama"]`](runtime/openglass_omni/panel.py) | Compiled executable under `llama.cpp-omni/build` | -| Main GGUF model | Same `llama` command after `-m` | Absolute path to the main MiniCPM-o 4.5 GGUF | +| MiniCPM-o-Demo checkout | `minicpm_demo_root` | Absolute path containing upstream `worker.py` / `gateway.py` | +| `llama-omni-server` binary | `llama_server` | Compiled executable under `llama.cpp-omni/build` | +| Main GGUF model | `llama_model` | Absolute path to the main MiniCPM-o 4.5 GGUF | +| ASR model | `asr_model` | FunASR streaming model directory, used by voice control in chains 2-4 | +| Glasses Wi-Fi | `glasses.ssid` / `glasses.psk` | Passed to the Rokid APK at launch; leave empty and only that chain loses glasses connectivity | | Glasses name/IP/rotation | `runtime/openglass_omni/devices.json` | One entry per ESP32 glasses prototype | -| Prompt presets | [`panel.py` `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | Interaction prompts shown by the current panel | +| Prompt presets | [`panel.py` `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | Interaction prompts shown by the panel | -[`runtime.example.json`](runtime/openglass_omni/runtime.example.json) and [`prompts.json`](runtime/openglass_omni/prompts.json) document the intended local configuration boundary, but the current panel does not consume either file. Copying the runtime example to `runtime.local.json` does **not yet replace** the hardcoded panel paths or prompt presets. This is a known integration issue, not a user configuration mistake. +The panel self-signs a TLS certificate and key pair under `/certs/` on first launch, used by the `wss` connections to the gateway (8006) and the voice-control harness (8021). An existing pair is left untouched. ### 6. Configure and flash Wi-Fi firmware @@ -203,16 +221,39 @@ Activate the same Python environment used for MiniCPM-o-Demo, then run from the python glasses_panel.py ``` -Select **ESP32 Glasses**, choose the device name, and click **Start**. The current panel attempts to start: +Pick a **chain**, a **device** (and a **criteria** preset for chains 3-4) at the top, +then click **Start**. + +Five chains are available. The four ESP32 ones are cumulative — each adds exactly one +thing to the previous: + +| Chain | Function | Processes started | +| --- | --- | --- | +| 1 Basic chat | Full-duplex omni-modal conversation with the local model through the glasses | llama -> worker -> gateway -> esp32_bridge | +| 2 Voice control | Understands "stop", "start over", "find X" | llama -> worker -> gateway -> harness -> esp32_bridge | +| 3 Frame selection | Picks the sharpest of several frames per second | same as 2 | +| 4 Full anti-hallucination | Rejects bad frames with a spoken hint, so the model never sees them | same as 2 | +| Rokid | Reverse link: the PC listens on 18080 for the APK | llama -> worker -> gateway -> rokid | + +Chains 1-4 are **mutually exclusive**: each needs exclusive access to the glasses' audio +channel and image port, so only one can run at a time. ```text llama-omni-server :22500 -> worker :22400 -> gateway :8006 - -> ESP32 bridge / local view :8080 + -> harness :8021 (chains 2-4 only) + -> glasses client / first-person view :8080 ``` -The chain is ready only when all four process indicators are green and the first-person view is updating. A successful UI launch alone does not prove the model, audio, image, and response path is complete. +The **criteria** selector (chains 3-4 only) picks which calibration the funnel uses: + +- **Strict** — safety-relevant scenes, such as reading a medicine box or a street sign. This preset rejects low-quality frames aggressively to keep the model from hallucinating. +- **Everyday** — ordinary day-to-day scenes. + +The chain is ready only when all process indicators are green and the first-person view is +updating. A successful UI launch alone does not prove the model, audio, image, and +response path is complete. ### Panel lifecycle @@ -258,8 +299,8 @@ Upstream model projects and model weights remain external dependencies and are n ## Known Limitations -- A clean-machine end-to-end Omni run has not yet been verified from the current public tree. -- The current panel still contains machine-specific runtime paths instead of consuming `runtime.local.json`. +- Task injection on skill switch has no effect over the current `/v1/realtime` protocol (there is no equivalent field); the model relies on the system prompt instead. +- Basic chat and the harness chains each carry their own first-person-view frontend and recorder, so the tree contains two same-named copies. They do not interfere, but the duplication is easy to misread. - Prompt presets are still embedded in `panel.py`; the standalone `prompts.json` file is not yet connected. - ESP32 Wi-Fi credentials still require editing the tracked `.ino`; the local header template is not wired in yet. - Normal panel close performs cleanup, but abnormal termination can leave child or externally started processes running. diff --git a/README_zh.md b/README_zh.md index 6f5f855..71d658b 100644 --- a/README_zh.md +++ b/README_zh.md @@ -92,7 +92,7 @@ flowchart LR 控制面板的目标是:完成一次性环境准备后,后续实验可以一键重复启动。它不会替用户下载模型权重、clone 上游仓库、编译 `llama.cpp-omni` 或烧录 ESP32。 -> **当前全新 clone 状态:** 可以从仓库根目录启动面板 UI,但当前启动器仍从 `runtime/openglass_omni/panel.py` 读取机器专属路径。仓库已有的 `runtime.local.json` 加载器尚未接入该面板。请按照下面列出的实际生效位置配置;在完成下一轮代码修改前,还不能把它称为可移植的一键安装。 +> **当前全新 clone 状态:** 面板本身可以从仓库根目录直接启动,但整套链路仍需手动准备四样仓库外的资源:`llama.cpp-omni` 编译结果、MiniCPM-o GGUF 权重、FunASR 模型、以及 ESP32 固件里的 Wi-Fi 凭据。这几项都不在本仓库内,需按以下说明安装。 ### 1. 前置条件 @@ -107,11 +107,11 @@ flowchart LR 本仓库不分发模型权重。 -### 2. Clone V2 上游项目的 master 分支 +### 2. Clone 上游项目的 master 分支 三个仓库必须保持相互独立,不要把 OpenSQZ Glass 的文件复制进 MiniCPM-o-Demo。 -当前公开启动器采用 V2 四进程链路:`llama-omni-server` -> `worker` -> `gateway` -> `demo`,对应两个上游项目仍在维护的 `master` 分支。WAIC 演示使用的 V1 三进程链路由 `worker` 自行启动 `llama-server`,属于历史运行方案,不再作为本 README 的默认安装路径。 +当前公开启动器采用与面壁同步的四进程链路:`llama-omni-server` -> `worker` -> `gateway` -> `demo`,对应两个上游项目仍在维护的 `master` 分支。 ```powershell git clone --branch master https://github.com/tc-mb/llama.cpp-omni.git @@ -128,8 +128,13 @@ cd .. git clone https://github.com/OpenSQZ/OpenGlass.git cd OpenGlass python -m pip install -r runtime/openglass_omni/requirements.txt + +python -m pip install -r extensions/requirements-phase-b.txt # 语音控制 + CV 漏斗(harness链路需要,只跑基础对话无需安装) + ``` + + 由于上游 `master` 分支会持续变化,每次完成 OpenSQZ Glass 运行时验证和正式发布时,都应记录实际测试过的 Commit SHA。上游更新可能改变端口、启动参数、通信协议、TTS 行为或进程所有权。 ### 3. 准备模型文件 @@ -177,17 +182,32 @@ Copy-Item examples/configs/devices.example.json runtime/openglass_omni/devices.j ### 5. 配置当前启动器 -当前版本真正生效的是以下配置: +把 [`runtime.example.json`](runtime/openglass_omni/runtime.example.json) 复制为 +同目录下的 `runtime.local.json`,填写本机路径。面板启动时读取它, +用其中的值覆盖 `panel.py` 里的默认路径: -| 配置内容 | 当前实际生效位置 | 应填写的值 | +```json +{ + "conda_env": null, + "minicpm_demo_root": "D:\\path\\to\\MiniCPM-o-Demo", + "llama_server": "D:\\path\\to\\llama.cpp-omni\\build\\bin\\Release\\llama-omni-server.exe", + "llama_model": "D:\\path\\to\\MiniCPM-o-gguf\\MiniCPM-o-4_5-Q4_K_M.gguf", + "asr_model": "D:\\path\\to\\LocalASRmodel\\speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", + "glasses": { "ssid": "你的WiFi", "psk": "你的WiFi密码" } +} +``` + +| 配置内容 | 位置 | 说明 | | --- | --- | --- | -| MiniCPM-o-Demo 目录 | [`panel.py` 的 `CONFIG["minicpm_demo_dir"]`](runtime/openglass_omni/panel.py) | 包含上游 `worker.py` 和 `gateway.py` 的绝对路径 | -| `llama-omni-server` | [`panel.py` 的 `CONFIG["procs"]["llama"]`](runtime/openglass_omni/panel.py) | `llama.cpp-omni/build` 下的编译结果 | -| 主 GGUF 模型 | 同一条 `llama` 命令中 `-m` 后的位置 | MiniCPM-o 4.5 主 GGUF 的绝对路径 | +| MiniCPM-o-Demo 目录 | `runtime.local.json` 的 `minicpm_demo_root` | 包含上游 `worker.py` / `gateway.py` 的绝对路径 | +| `llama-omni-server` | `llama_server` | `llama.cpp-omni/build` 下的编译结果 | +| 主 GGUF 模型 | `llama_model` | MiniCPM-o 4.5 主 GGUF 的绝对路径 | +| ASR 模型 | `asr_model` | FunASR 流式模型目录,②③④ 链路的语音控制用 | +| 眼镜 Wi-Fi | `glasses.ssid` / `glasses.psk` | Rokid 链路启动 APK 时传入;留空则该链路连不上眼镜,其余链路不受影响 | | 眼镜名称/IP/旋转角 | `runtime/openglass_omni/devices.json` | 每副 ESP32 眼镜一条记录 | -| Prompt 预设 | [`panel.py` 的 `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | 当前面板中显示的交互 Prompt | +| Prompt 预设 | [`panel.py` 的 `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | 面板中显示的交互 Prompt | -[`runtime.example.json`](runtime/openglass_omni/runtime.example.json) 和 [`prompts.json`](runtime/openglass_omni/prompts.json) 描述了我们准备采用的本地配置边界,但当前面板还没有读取这两个文件。把 runtime 示例复制为 `runtime.local.json` **还不能替代** `panel.py` 中写死的路径和 Prompt。这是已知的集成问题,不是用户配置错误。 +> 面板首次启动时会在 `/certs/` 下自签一对 TLS 证书,供 gateway(8006)和语音控制 harness(8021)的 `wss` 连接使用。 ### 6. 配置并烧录 Wi-Fi 固件 @@ -203,16 +223,35 @@ Copy-Item examples/configs/devices.example.json runtime/openglass_omni/devices.j python glasses_panel.py ``` -选择 **ESP32 眼镜**,再选择设备名称并点击 **一键启动**。当前面板会尝试依次启动: +在顶部选择**链路**、**眼镜**(③④ 还要选**判据**),点击 **一键启动**。 + +面板提供五条链路,其中 ESP32 的四档是递进的,每一档只比上一档多一件事: + +| 链路 | 功能 | 启动的进程 | +| --- | --- | --- | +| ① 基础对话 | 通过眼镜与本地模型全模态双工对话 | llama → worker → gateway → esp32_bridge | +| ② 语音控制 | 能听懂「停一下 / 重新开始 / 找东西」 | llama → worker → gateway → harness→esp32_bridge | +| ③ 质量筛选 | 每秒多帧里挑最清晰的一张送模型 | 同 ② | +| ④ 完整防幻觉 | 坏图直接拦下并语音提示,不让模型看见 | 同 ② | +| Rokid | 反向链路,PC 开 18080 等 APK 连入 | llama → worker → gateway → rokid | + +①~④ 是**互斥**的:它们都要独占眼镜的音频通道和图像端口,同一时间只能跑一条。 ```text llama-omni-server :22500 -> worker :22400 -> gateway :8006 - -> ESP32 bridge / 本地画面 :8080 + -> (②③④ 才有)harness :8021 + -> 眼镜客户端 / 第一视角 :8080 ``` -只有四个进程指示灯全部变绿,并且第一视角持续更新,才能说明链路就绪。只看到面板 UI 打开,不能证明模型、声音、图像和响应链路已经跑通。 +**判据档位**(只有 ③④ 需要选)决定漏斗用哪套标定参数: + +- **严格判据** —— 有安全风险的场景,例如需要念字的药盒、路上指示牌等。该判据严格拒绝质量不佳的图像防止模型输出幻觉。 +- **日常判据** —— 日常场景。 + +只有进程指示灯全部变绿、并且第一视角持续更新,才能说明链路就绪。 +只看到面板 UI 打开,不能证明模型、声音、图像和响应链路已经跑通。 ### 面板进程生命周期 @@ -258,8 +297,8 @@ OpenGlass/ ## 已知限制 -- 当前公开仓库尚未完成全新机器上的 Omni 端到端验证。 -- 当前面板仍包含机器专属运行路径,没有真正使用 `runtime.local.json`。 +- 语音技能切换时的指令注入在当前 `/v1/realtime` 协议下不生效(协议没有对应字段),模型只能依赖 system prompt 完成任务。 +- 「基础对话」与 harness 链路各自带一套第一视角前端和录制模块,仓库中存在两份同名文件,互不影响但容易混淆。 - Prompt 仍写在 `panel.py` 中,独立的 `prompts.json` 尚未接入。 - ESP32 Wi-Fi 仍需修改 tracked `.ino`,本地 Wi-Fi 头文件模板尚未接入。 - 正常关窗会执行清理,但异常退出可能留下子进程或外部启动的进程。 diff --git a/extensions/assistive_harness/phase_b/assets/reject_wav/aimed_wrong.wav b/extensions/assistive_harness/phase_b/assets/reject_wav/aimed_wrong.wav new file mode 100644 index 0000000000000000000000000000000000000000..4fff8e2e9ba7ac93117f248688e1de137ad6422f GIT binary patch literal 142124 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¨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 literal 0 HcmV?d00001 diff --git a/extensions/assistive_harness/phase_b/assets/reject_wav/orient_flipped.wav b/extensions/assistive_harness/phase_b/assets/reject_wav/orient_flipped.wav new file mode 100644 index 0000000000000000000000000000000000000000..2b61d877f97b30b84a2673a76df41f4998eb7099 GIT binary patch literal 163244 zcmeFa2b5Jsvnagx$vL0Nff<+~XUT}|!~lo{5yeCh5lmzhkf0zr zXBcuG7$(o0oYUT~>XiFCfO_x!-hKCf|9Z>mH9K@yS65eeS66pe?bE+k_wGNwD`Ez9 z8rbc{v2WBcFbu;&*z+{QO#Pi1rvglC=0T<#)0=sWd4d@T;c=!vJojTB zVR}M*SEe)5foTs=4?t+iv;pWYOfRMn^C*NzAiW*al&QnyFj-6uxaKnr;k`NhH)WbI zjUY5&>ch1uOGf9kp#fY2YH`vDZz zttX^*1(;4uM}X}F_3Q$n8`C462VuHHN;{yTB?RPBM}Y4MshG1fq&xt1s|$6n9S?P( z=8d7|$Rnh*bv)+-KyO2)7L&=OKz)i~aiGP&?y z3(7%GV;i-IQ%Q8TfS87Wvlf(}4pd^x7@?QwAs8SSAtr@Mg&HJ5i<#r8Mz~ubCLO5G ziQ~_OdkqLwR(_nuI`EbW@JdDkJy66b;5i-QkopEdS32NUF)~P3F&YRuMhj0;=&>Q* z4Jycpt>pp;s1`ZD0zz^EBHa2~|MGP<+pdDK^6|N?r zNc=}RUdYAsB7jf}*ZE@J4rM|DC~9taMAFXM}#ybF8* zf094Jp90J`AkGPOLLM;jx?}0lc>NKZ2T~pJfH(tu4B%u?TWozj)D?NcLA)KPzX^4? z33Qf19>gbu+Uw#$1^kZymU5`k?Kng=(2Tf5(Ebd=1H4e09conqbQZ=rbB;d?{J8?p zHz1~vzZEZ`1j;Cfdb{I&Aq06{5OWpkb&Nj>b-M^qWsvRwh-#qhRy_BeKlrNz+OhBP z@P3m&!|&(!@ca1VkiQ!0jeJ14$iuUnuYx#xoK{i1uW~>&atGT|3_V5KsNM22~e(v z*28wxK^n$$0EweO7aze!pgRm$u)kad3huyjlvlur&jD$HvMU+#W6iKWa^PrMTt=7y zuLyEF|DezZcrg{_gAuq90WMSlon=688Bkmi=WYP{nGNVI{TKaJagJb*!x85Nd`^JD z))B``r8e*b*Iba(0WjE`aEwcVo)|!4pRhxU59p>*Yyyf!Krhxc2LCM3iao&y0Y@y# z93=!XKuP2L(LpMvq=B5Q3o0(HSLjUySk!9n{)ptg44-gW5b zm!N%a10RtCVMsyzwm5z-aLo<59PoyvQ~`g>p?4Gk=aK7fNJqKggPcCd%LD)DkA=FS z%*4M)yiR4%{x_i{?3LG{yb{3Zj?1D*obM82&<*Il zIC3i>w=0gf3MeXpR1Da2?*Mf;!mmKzM+tQTM&$_@1sCIeurMw=a0K8}alHQ^WjMMo z$7LEqp94AzAr>Vg;zT)e2?ENHBH)4x>Wxw~477Uw;HwvS5CGnx%%{GHBkd;Oy$+%9 zE}l67E6S5=P|j&6?Ic_aKz<{IDE+XOmv)z;fkZF5HKKLN`XqOE6V>f zAdOMdU4oimz_@b|dj{~Iff6o29M%ByW7=7WKMCPXJOw$667vS&y9K-{ikDCd9IA-7 zdI?a3IFSoT1yYIuYlf6i8{LjmdT-s*n$X)yhT}zW85AekvM|<@fq3oM_! z{SJE`^}aC3su+YQga`zb$tbTV4*MoSBfi*OBbK0W3?e2Ugdmg_f-BwyY=|2rpD=?F z43>-~QCWzIi(|%86LBJ#59A>6aL&-e96=hO8Kk-yWE|>*y0|nX-G*REcT<7nQ~xUs zH82^-7nCp(c#?p$MGXLF5iz`B3hHQd#hesHnT*td$Atlni*n=Zrr>7HF3EpA*-R^I*=yPzPp#x^T|}>0A@i z(*O(350>~Wg5}^7^28LsqA_VxMu$VT$_UKkF!f7xHpQg z6mYfBI393)h5^?O&EbmA2wflQjI>aw4cKv2k_oj*i3j9j2D~F}7>Ariz946CJ(v7P zpcvGc6Lr9v377=_XT@72Cte2P%#PztgV^kNt6-k=e}xQyBW}?O2y0&pYM&3Why!)A z8gZB$$c=4{YZ2rdUJ(Z4F(m`|i?mwf0c(}|M@_I*u&%-?2emxvf$I2^@P<87SYu!c z>JQlGu+4FN5H$5f^B?74o6{J=K0$i5E`F!AmMIR0D=dV=bxl&de+ilkLg9$O9*?6C zOT}@3V+Yq6ILdHTp(ctW7z5HNj2?u6; zN{oc8Ks|!AdV>4AD@q)aG$`RP7h%CGN-7~1^J5vPwNjwk&}t6rgmt9)A@x{KTJfQ5 z!N0qyK}@JSM&c4SA#G7M)9MNJA=I2uuA_X$AV^)5z_|7zoe5<)2Gr$9o1?WB>UD$# zB{4pshD9qg)IL!9V~%PFsGZ@R^fX*)p{9#h)Q~VA>9+)hkT|#C8)|c?Njc-19qN4e zkNPLV;98Gnb<{Ixj;DDOwQgJ|kgkn0A3k9$YGRn@Hq3T~5J-nXZQ>5Z-hp_W2kDBl zDX#Yt>oS}taYn{?S_vXF;z1pVv?+QQG%L!FIt^jL)Z0)F##6q+cnQ}aH);~7T?u(` zMkhT6bD#!8`VYpF7D4HFrTPDATw_6P0d*|YRuB&Lm8%eUHXhE$VNl1t0T85*q2`0@ z@5_(_bE5u$Iu2?zs8Nt+f;GPhaYQ51jc=rjA!kqzLfs7Y7vv`CT+|}SbBZB8;}zjB z4xg}oq)%ZSuAfmeq8QZKFa~uLY8fmQTL)=DZjnYxe4}T)B3H0ZS0G&d*Ar=&SO?@d z>O`nNVt+$zKMiDO0D2paF5Dx~f?PnoKn$xI)OT!+dXj@T&3WcK|PCNXf%<&PWlv%Fw&$@e$11W>?^cNQm_g#dQxgbwSCX$R1^cGoM8e-htK?Zz4$%9v1p;EwICtOXER3h0* zG7RGdX@+>H49ZV$#7Tz(373L&G93Sp8;HusL(w;OToMBM5T7u&(F~V> zM0^-_D)4KHCd>o7kVJH&IW+84_nl>ZSOE^CSKV zcY4DsjvZk<;o1UcOj<|NY6Qm_&8xW5!7(Syvcmd@)-RzrmV0y4&Lz&WIOEaS7G_$E z!#Pu!MQII$akRq1eKVXZan7ch7_T^!;%uClnJE@!4$3o{MRCTYITN37O^2&KoMmyp z1fOx&1m{PbGjYcXSA@6%6?Q9764Sl~#^Mu6cVR~ZV^HdmG)H-lc~Sb4)W@ALlKr?A z##tBxm5Y0iiGSPy#N9!<;uFed;f@sJJMHrb@q`U$cA}1E6QYvJM{0;7x+0yJjm=;q5f@SNBWFF(ir5-49(y+K4CDSJ>NJ6P8{vu=cV0*f z!g$O@ZHQVD=|__#X=BP$wFVI`2%|{ z{?n=**U!}BaVPxoUJ zYLTD@p9D+^iV|>tPQ#e{|Na~!U=Sex43Q}9&rd?G|Ec@^)Cjdqly^TwBIQ4Sx*Hqe z5o&mMUX1(q{_fB5clqxw|KBU&erPN~C`Gv65Az?r-%BykML30cm3>@7h4ckXyP z^>=|Z#FzPY(|GmFImd<~= zp%#RC&7TA5Il>inq(mSMNzjc*W5O%yU5OyP3-?6Iy-%dG;o9S`g0M4ydK~F^!d=kp zgcORu`zq*)i96|%xMN6xw9Uj7V^RAQt^_5(6CR8cVuYte30OXz&)iLk@GR62bLuLP@}cChxt{aW1rMJp9N+r>XRCBl;Zdp=v8Ur+2;#%_CY=q@zB8^+>GTKJnYe$9yF|Dzi}pS^w*TWlgu&B%g2P=DED^8w z=R_?Udtah2(W;Z)QR9yOt5@EuHB%WxM?%`rz73T`&$!!#>ty_=JsYZlAen?c9+F^0 zDe)&EFR&D$yuXtS_ftpv-xy2(bP9;IrF8-T4BZDjdlny zKRr=Trtyt7TEZzN?jRrp_G((2QMnj{WuOfP?l0h-Mh2z`qm0HU;uCi8@dTDeDVBk7 z_l`gsqe!oiia2oBkxp-MwTfc{*Rr(NfN!{B#T^OUf51_MI}f@1-3SJcTHS7?c*c4}g0PxRYX!$K&2Y8SGBr zo(i2e;2sF=R?w~o?zNz`0%9qS-*M-IEI81T11;U~JRW!Z1-k*X{Gfem+)W{C1KKMu z257V_z(6_aim|iV*vJ28p<7qkYzcfx^Cv@e4D_*fF|p3oi$owLxM3hv31 ztr_mc(`g1;px~Z7<`+%^3SlP&&m7RY<1pBtodMoPfu|n8j;9aR@v(%v>SYjv);8ET z{P129-_J)2667AH;+Y8AOH=}k1IoeE60}l4D=?&=P7H|KWSN6pwgF$rHbkg3?ZDFs z1zJ}i%~%6ETeum2r}GSq!xXd~L4IQW1iK6@4{_iw7;y&cjQm30B9{;o=0v)%{V*rB z2JM_-FTg<1_=Y_Ydjg(l;2D7p0;VDb)XOU14O<5B;{F)XfN#{V3gf3YWMS!q+{M5# zJoUHw%)5kYutOSD_Uk%A=<7qE>G7wrVnjwbH((P;_htOjW8cgRH? zZ@7nv{T#;(TG8RTAo2uHR!A1n{wM8#;t3?mCd7ntfX;A8*5Dha(kTs=gw|8oOG#$n z*$m1Oe8WF6&Z&2*OGy7G^jbLF*N?BgL}^I-8*L20ULteUB^-=xmI%K0KGldLa+c>Xa;F@tw+0 zLma|je#(uOvuLwGT)?Zq2jU8ySqK^y@{}xxkWZ+qk&cFM1cTO$_=b86>LZwgG$?Fy z><9Rc+5_qis6&ut74{F*JIE3t6z_SYiBK=2^L!jpXg!T57&!Bhj)C(d_CnHIuvegN zL)s{5B-m%^qyz8tgxZH-U67d3Nw2^;T+lH{7so4VCa4qPxI*n5pU47$BnHVHlrA(& z(KfD$XQB$I**X3Ql(!eCxBz8; zz&GH3=UQ?zxbK*B@w<|y(kG=YC6h(_K`K4Rr}II1xz${Z8_NFClDqBY#kWwQK&cB^_~Gs(OvvX{ww}l zelzGZ=V3-dyL)Pf+t4}^7~N=5ehYZA17P>@2O;c(vR3l*`H%S7{HOfa{5Sj({&V2N z+x(mSTl_43DYRMvi9a~8w{9x0EWh3 z@s<$^7m9-z>U0DGVUPN~TnO#?Av z$Xf$y+5$X%+CxpT#`*Bx5HOKX6-sSAP>9xT7N8NmT!?P6_{S4(vLZtd8uSgonxkg` zN@A47I6GjC(LVrJ_j+gvv{I}A7}0-#WG#*mv=}EX0&T>}VqXQh4FHFdUK>AWN6#3X zX_V08&<+p%i_oSJEe31Esjmk$r~@{N=xK%ai0I`+HhtLuYXr*NFwQQ4?tBWaCD6yv zBZCG0ki{FeNG4E-wu{+-6)hQPK1AOe^bSBN=ZaH^9!PYmu7+GWkfR=05M~0U#yBU4 zb4l=wmM^&G1QhWsQuv`%g29&pnV6L`*E&8c*-N}At3FjDPX`nIOmckNpKiP`UBntS`&K{l%IHj z&xDO+2gTx*;AspIUZjb5hj{Uy-YAbiBT+`VF^Wi^Hn#h&F zO&AFeUh$8x5HzOaAI8xW;iOcGy%&<8{(Dzi1N`@J{B>>|U;mXq9D}H5)0m{|U*|eT#aifFJJy#Jwe9EaIi~Kf~NzGCkkhUP5l73EzaLzq{XC3xX1AfmHnGe*&!p z`Jd$x=txi|l<=SB6yW}&yMO~r`RDJy!-2$HM^AYDui?8JQpkIE&cDO+_wj^Lz?FEr zTSuT02!?clyUYA{pZ|`Qe;3dHd3d5ML0^I^|NCVLTuWg1b4()b|ISmQ#{c#5u@?73 z|2gJytnMcoAC5sFAE_tmyi>AefP8QMsWn4xDs^Y{oW_q`%YlQ zREi@wA?4m&_rD<&{s|P^jp1(CM10~YQ4V29)C^Pp?(beI3G%N>y1$%6X@7_N&+&hb zL9GA${lCru(wXo|`?UY@_21)$fGd&fugbam{G86*@4X6G?!5~zbn;GVe^mzo?yv52 zqE9JzKi>G ziF>d2;!NZbO1PKj^hT8a85ZM-ivlkN7^-7}0wJC#zqjUzwEI&9tO7hi3b^mhN1RB+ z-CgTMEItX?=zeb*Lb`BIa9MZ~%E9+U9KzpSBH7N|8$)qq<$@___afxN{6e_9euP0t zp*zOm6Qw1rX6}BXw0j}Yq6jUK@Jdf)>qGW830Sn+O27&BKV%z3DP++^RzGN=gmzH( z2C{$>EQ5r*;Nx^}4zh7d*l8tfqbQ$XGnA+kSq%wPCTygzR>%c`U(`N$6>2Bs5hxPw z0!I=&BuKncoNy;@Ax11k=tK9fL#bCG6wyjJFb~PTgbXH0naH1bO32Xv-6uN1$1{4g znn0Tcw7)>xOCbo~eIl!Ov|vvJvUd=yEbx1NXemhF7eYHm`u-n%0Z70@9s`J-;0ccG zJjpH+ufjKp@EL7JF(kg(MBi;f3qcHtT*5QO3vYyrzDq>kEu!xo(bo;pBSHA~6MfT3 z_zn}kVZcd>6hkh2Nh-t6co@6n@{6g78M)qoQ<7!FLLjgRc0^szjh~ zUI|zFK4~HqanM&S1x!>f+8ztvD#eoM+n4k$&%5#8O{G8&ed|-G5!IIJNOh)m6)2*& z#5M8#Ey_u)E_{1Sz$1Loi{9~y_Pl6Sj4gV1uSM?`A>7>~65q|DuY3#R4DUF`=o?uy zW)K3sQ4)d14ZaKcaIDg(B&#LC-X>w2biW-G!TpsUk81?7Z4xY*5LSRhNtT#ZNP;G$ z8(Cta6eH_alKONNtXTyaiZYdCGTN__Z7s=Bl80ntiqI7Bi7aes4k7PX#DGu2cb3rm zMDPPc?-TSkLH`W$TSE^S^ctmaTcQUC+P;&mFZr2~^)7xD3Vm46uLSLk(c6oBUkDm; zphp^FL(J&YM*f-fEiHUT-#YYCA#XYKNkN|y3g}fw-_9ccJo0}d>WCupr$sLk`bsC# zfiz$|`r}{@{7SvxLyCSLpH_UDd0CMU9(gj6mjqITWg&Hl(-qfdusqa-s6XNxc~fIf@}Z*M zMBas%OYn-q?~|c_GJ0Ql0G8m;-W+|WoN?N*uHN`~!r2|?XZ&7*3g#C41qJlR!|%#s znTP|aqrQp#82E>x6Fn8stHcUE7U*Y# zzw(2=7FpmykpkGTO!5#w|GH4Tej30g2C1C_|D^q(Ckp;51om}oKM%CE2Vz7(s|ZS0 z10Qmrgofae(J1cGL%%G9-)}Sl)gd1JIj~-6n~%SrA_0t8s~CLu0>7-B3>?XUU%jaf zl+^_fp$>4(2agi;#b^jm=u0629-&7Qax(70`;;VYK;REINP^6_kvBSiTjwlotO@pC*9eDfrzU^fG!Be!-_X z__Wjk%J7TU@{_uL*Tdhc9xc0lf_%#Q?N)0&0{{ zn{?ns6_j5HzHc6={}u2+!{6md0s0%k_dhy=m)9sL|4n8R_;5{OHZt?UAM73QhZ+y* z*+5}38ufmUJQ+6mgJ2&l{fSe9`>9D2m0L!ZNMCSr@Z`Py*J0Dq;? z;8*tsl(Pcp^D-Xb`5Vmdz$^TQtB(1NZ^bX*7x54CseDiVeem0x2;ABL-c0quzpgj@ zuV;=kh0GmB%qk%SnG(o7op}!MbcKG%(F0|)$@Z$T1mjcd9;Ker* zycP@jBxXD0U%}4>E~k+$sP{*D(iy z{=Uq2%-hggjLc;iB?q7{EdW2rE#MKkg8va(^cR?uEWq)z{3fV@8v0Bf=usg)AKGUN zc(PptpdT0PTO1@5GPi+w<4B72Fzb9`_FC;m&gVxjS4B@FH9S zb$F0@1vsC~KFAJZzhTF)ud|P`t=QYl56}y*1HVS`&+uhjB{zic1y5f9HEY2uu_p9p zlphnAHO%MCGr;XN%q*Z{KGfI-BkKroXfS`2`TlCc4IU5)BkRB>IgV$tJOz07Esj#4c_J_Z4U2T5x*qSnQ|Rv)op$H~45~^G}1f z;|cy1=#f*H9neAz*lBD>)(n1~FT-8V@=Snv7e?OzkWgd!;ovbjif_vI1Fy*#^zTja zUV09Ax*L2ylXwx|oaeZ85NzBW{zK?nY8YV~nM2HHzy}H2o?XYbVYe~cp|+2}h~EvZ z+6H=~ntz2~%Jvjeie(F$V(Q*Fei}08Ts#ewTxorOYX& zk~zWr47^&%ya%IW8;ragT$sBEJetEj&TZ!ypz3@0U8ajLPEIgG*k0@%#>`FxFVt?urWW53vtf_1(&!(To?Wzw-!q2#q0_PCD-2%VQHVMXcSH6nd18uf|+sAQS z6(7cs`rCjcNjVQD{yBGNVP7^80I3h@fX0iCQvskjQEzk z1aLItzvooYf_C7}IDRox0djFS$h0lc(u-gO?Eo1(ksks7CcZCk=Pd9`RYfqnT;zX> ze>Fr6V_^XE68P)J_({;7V?l~(p`K%)ZKm+G`HfJ|>D-IllicB$ggeKzf-%#I&t~R< zG-?9l=@Q672aKu(AO#K3?|Vb<*MbMI3tFm@ugC8OE}8gh?lAWTjIM3mQ_u%Kf}Z*S zNR2e;m)k(H)r_~~Q0SSbVRYc{o{ium+(R&)&VpQ629jeknmS z43J)FOeu4P%@>J9UiJggXCgm4l>LM$fmZ6w|HLhe$zu=4Dr2L-gZU6=gx>uybCcN# z(pV2N*9W}3!)@VCaL2hUei+ERCD8VZL2fLEx;+e-Qdk?a8GL?IK$6;l;~e)QNX7+x zBR-2)f%NDJGtMROL2l0!Gf_stb^(b#6Goqu9SHJeEx!?Z(vy5$7!51AAkc7>o5IZk z9yEqJ+F>-0x40Z`cx-0$$>>wj(@|xt7MB9jeH}BGy&`&0{JChf=#pr?C|5L| z{eqG6gMoXexlC?r>;iCeF!wm{X*oZV>BRoRo&mhgfcsb2Eo>J13e4AE0#}D|TCO5i z5qkmZT@yxs8^+1J#ExUXV7swuq=4xSl6N7O&eh}O+(!`d_#I51=ta>`(Pq(Tu}HjF z^pWT=`x{>lGN>+>6Dy1kk4=qjjlBtw8~EwWAa*f~s0j3)?_h+ifR@+|^GZYL{X3xF zw}#Pj9rUX4{7r5NaBw-aax3UBZkU0#GyPa6`?RP`^rNVneU*IzB9q zb07_h06qmg(Vu|X?K!C959|P#Kbo;o#?S19@%ak$fQMmj_whr)*GApnUP3X5gr!W7+M<+ zN4|@NInYno=A!8$v#5%Bj8EaNMn^_wh5~_0{-yrQ{<(obU}11u=())7*mT~{JTLlE zd{lB&I!*Smtc%PiT`qk^+D3XpGEcHs@}jhh?7XZ*enP>j9#U&GW=)ocQ-7}Bu9~Dg zA=@D7BVNX~now$*q3 z>^T=W8etfN^exps-8^G|^DgsVlf$qlmt?GOIFl&?4vuW?8y_(Y6JYCaKc7VAQZsY6je5m@v zinA5Nt8<)9d>taE*lvpchUF>GXS1~)uKit|j5-(cBDqgz)k-NhoL9~j%ed*GH~n9D z=Xhp#s=S>8(?Uza*`Y?hD~|3}P0P%8>J;W*d;Rj{EA0!vDWB^e5Y3jg(Kk#!lBv&a znEQL?b4eSuCF0yrQ^(_FeT%*+oLcyC(Ff%(I%kCji)GrcEKjBl%f4JQB|j_wg*;cy zuWNjfQJiwhGDN>nIa%6QG=U!)vqdI^GhzGX!SJtPOL%$kMgLQ-ZIyjWY8F{;Id0s( ze&oiHTbD}@I%b5lqH7ALzCqIGsp7PbDT~aU`YrJ%kz4K&l?RJoEc*1ewy1GQq_Vfi z8#|~-Gp$Q~xrR8uU%kABriO3VJydgA=H%pG4c{r-ikESZN2-E{1JR%_vVsqZ6tdBZ zhRS)0Hu47IZNWKhm|aQ} z)617u+4=T&*Q{5Qu7?Wy6i=Jnfd-SC3~MTDQ^Sb6;LvSF+19SG?DBBx`TJ zr+(YU1Dg06U8$E;YfQ#DOPThLytcSCQZO6p@D+)~I4(5opeeM3u+qRk2YIBpi`O}l1l4iMg-)whk z{Qf8RK6$9&=>u2tO7h%(=5^!g8qx;I&3ZKdqDkEbzvij4MJdgU162*gpK*O+MX?>s zcuA6Cy=t%KB|{qY+G*)!X(=f$n?kCQ%y8H28#%|5b_IT0xOMbzjdrd%a`4Jv=l6>F zneR3@(W0o0tMzkD`_b-C(09^32KwPpX?r}Wq6m!`f_cjI&iT>1JjV=pSx=xM+^_HRU30WAoCK))~Vx>tyUq>0-{+ydVzx z+m<|W=Ik#0*0N2@x908`ap;rtkuohaI91VbaqHRbHSKyfx8!G8tJ$XZme-Ug()THL zkJ;br)VJ3sR<#c95x=eXqy=-0`QPU?tvNsY$&5j1M^koL?-<+aMyg*^7RcAgevm#O zZ6nK9%vO&u?6lTS+nlj9qeDtP!;`WTk%NxvTXj$Af0wQA|MMeT9@#tM%!S+2yzeSk zXXiJo-~P!5Uv0(Le>h`}(j2&1I{M1Dr^*fwJ9P0_!TIGyyPb8SH^p;QzZjEK^Rvd( zxL)J;8qd_Yk*&y{mf0n(uGOMvmF41YjFQh{f}(}8j_PVdX;SNSN#^YI8A&~L4W(a1 zjyr$4V>~x$&$*2SKd;@=cW>m>vBLM=ugW6n-I`2puXyN_HmQw9W=55gz_n86mAPk{ z97{hk_IRiBb#9ebKOdaIKBRb7x6Lvy?W3#*at7ASsHLd6tcELdWm?OmF@`FoOWcv) zAMMF0#itZ4w3iI)ER9lLPivKaA*Ge+D>)a*a2+o#ytejKVAsZtAFY3LTi~eW#zNO& zX>#(#{LB^=?W^0SHhm{2sBIIfSJv$6&Vuxl;bTXS>kDpOJ6CZea7iRmy`W7o?6+)A ztD8M7=W_1F++8(VXVysTm)y_1UAsj-S|s6L;%c*BNn^@awNDue%`21h(uSvvOR&6Avn;bTMQyENNKXoETQY}azMlGlv7c;0=zR67w=I{(9`CmE%?*>*7w`D8 zU~K8I$a9ACH7+!Kzg5k4IW2b8{ygc1_%&z$TapWFPOUhx=j7`J`pct=itP;|E=fS0 zWC)o&Nf$B>=hUlJqt?*evDu%dE0SHtE}Ac7F7`=&0rw8ST69~Us(au3O!A`CfoYbs z#VJo%MA{u9N#LofeYa&-2b^ts_`96AhmIe=a5m$HxoUi*w(4EWkEylNUWbu917xBjw^h!!nRzKq&Exb_ z)Kg>=*=?~yk>8`AvX3b`>hD<2rJPQGHFJ1oEN!aw6>XlRD)gfxskH0O{0j|^Oxw2Q zmzTD^b@cMJeYP5+50kpqnb`83hraEwq4}Yla_!Mz?_$w;|IvbjD-R_f|KconJyv-+ zJX>+pFxz5EUXi*YqjR<;Cs4zY)g~h+^^oN~y+jp|q%t$3=OR<5T9P zNivRSe4E}OxrsrkNar8)ZK%q=bK+|G>2doW+5GW(-L@Z3uPU3tG3JxCW;Of%!I_>1UI~}!*>1!`&ilP^kwx=wrKUB@1eu3H|1~B7X~`scAp-9$bR76BQKvC za$)d|#^pMG9hLP`PB3S4_D>lfq*Rzw^uMbrr7y8B#?D7tM8D7#|$=;Mb7ux9;{c}=tB-2%|{Fy@e#bL)c?@HO!ef`oM?_K0w#fkx$ zM;mF{e$;VYr|E6<`IQ>h>%7_O)Q$sd_q}{*!-?{9w(Di(F8?0!80}c|mr18nG#N*- zFX#GmeKk5}RwbV_ex~N6Ynern{ek`dZlTGXL8{eWx3o*&4wB-#+(6FItlv`V8XCzi zgjYF#D9yO}#D#_@J^L%R58C|Tj+ApfoiX`|jGPA9EvK}Nwy$nEJ&#j&^(?#j?3quG zh!1Z#Hm^W?rTo^o%ErE7d}BpZ-MdDO`Kt9uYU`}AIX!ZZWv8T1u^iTx$qekoNWh=( zdo(aJc2as+_ek>P%tvx(=hd&R&)=NWI_<3fXK`9EVrx{=;s$%^$up*-M|Quu?a7^v zGqA6muG}U+)qhfT}$~E=9|cOfw%qM;M3e}X-DlO%aXL$vtO@yJ};2> zT+KmQ4U&&(2a3!AfAz^bovv!moCdrtdUMv`1~0XEx6Q2?ybCsW?IFyrEoQ;iR6ckkL3+_9-(Ky{E68;qH) z>baVFnh$MUmGheRtx$2L?Dl}mi_f+^+w8)tmnU8Q_U7r5u8#LZ?~7RF72Ug5QP!b7fA|GQ(3T18elj`zmiv?%SCUr<^xVQXP=U zm=m%0V+y89vR9=xMN@WXUd&e37+RxVwln=;(k1=d@)=z1z&p;IiXPAw?-ZmQ?)v+v zEi-rSK3`D%6w}&pt;UcB1DlzfwW{ACqm}BLkgD2uYw?v&FFta4&(+Yivg;FXJzCn; z_O>@CIzarJy3%qg^I$Dioy0K z89!&_Wn`zloYdKYqzBC$=0MybE$5$YN=Ghz7nnN zx7$ie*4$Wke#entcCXm8;neH5X4oH!d?;^g4x|mw3Fp*HTclNpPlVfhhua5NeNi!| zd{WsPr5#Flly)yaR{5cAzpFSnSF~Ky%9@)|ojnU=&w^Z8jRonel3JVex`pbx>SWC( z?K)kl{)*vU<8I@R##@FudY5Lps-N60I?eS6|K>a7oL{xRc;40DPbVL_e5~{NH*Wn{ z*~#CJ%~f%RL&>93N1NYQEfiUz&HVe^yIlp&w;h@Gh1FfFKdAQGQXR{jb36lsGXAWr zhwcZLtYl zX&O5`_G756ucjlX;y@95eb3qcCpw*+b!p?B?`?AfaJC?SUL!GmX{j)bfK^Rb?nroI zpoi~KPnx^L>2zGRzh>WWzv+;>S9@Inf8;q>2d>ju%v-G^Qre|;NFScQHa#=_tJL?B zpH7-?{lN0LX}IAV-2u%cRYcK2(MT~;eoH!EJd@cU`!0Mq(9^rfIijk5@$_qp&wqTr z=*p1WpOhW9@AWIW^^$AqJNhBow-s)&g547PHu6ejZMaM5c);!Zz?VD1rxqGX} z@BKM2Iyzr8U)f5ZWiGXjOumt_B(*B_)zk^eZ(6%pbe8Ux-_7++TlH5oqg1adDrB3b zYb9pM6tP(3;Kf{vXe`*(+uPo}e8BCYS5IGf?qc!v@x@cCw|gTXS?Vb!Xo|HDsRzr4 zOPY$FV`5yFm^ykPYzXUvi+uIGqdk*7$2_OJ-}-Yx!Dt&%j(oT3N3F*2wCTLLo%M=! zrnRSahqaHjzGb0lv+*&*P~BL~eAP;v}{iw=_}|dNepB_+8*)pjY5v;Pqg7 zs8MKRP#tOvZV~S5y(>3KwMYK$tm-k4s?pl=gu(eMem9(iry4S z*|#`HbazA+c{rpF7WmcvOa2l5Q@#Vf8~(k4KyY^05n-Z}VtsfS8)mzSFGx;E7sz(V za~01h_9`-ztCh2q66GWXC;w6YjC{4cmtwTydxcS1S2;v6Sw2QqOWI4koE^p-hVzr1 z%s{rQXtnq!NwPFW+F3eDdPg!!{5fmq8*?Mmk0%d`+v1+7hkLpX+Y~?HRi;^26J9CPg zAN?h~Em-Mq@4M)Ux?XnnhJBn*Y!jhZZQMfLb^fmuKHK)Bz;rk8dFzumFYLrQPT<2V3X8z#CX^kGfpynZ8Dl% zhF|ojb>nsIb*r^ejZeKr^^3wQoiAF=Z;FkIo(o$-&VbW@!&l&4>6zhr!Ew`8!xpWo zth7{qU-3yrN@d^5{K~eKfy((+^6HJ%pV)-4`4`*``&0UG->XuZmOUh2_=dH7eRxq*XjsF}YG% zJ;HXtUgkXEkpxDDH^#;@4$(ZRUH*o$y(&rFLi3Jxy>7dHkKrfdQqza#8J28oS8JZN zzBSo;(lXj&Gha3xHVo0t({xb(to%v-t#qUKYxWcVix|vM5mV%o@V3yGFe%LPHTKST zH*{{aHLHHFYHOvka!N(5iqwij6~92c6j$kNSM58TBiu!vZ+*)G(a_ZBDsBujL8Owt zChw$Nr*f+sYUk;^`bxtpt*W zoupgES)xhI$6PR)6x|*<5gr-R2Cw09fzX$1b&fcz3?yo%!eUAmILr+9M z=T0+Pai-KETcPkP1F9s=WNn#FWJohMGNnV`NU^+TdEfG& zBIN^$8L}Ia9^w;hjDLh{7rPK07X2vlYj{;?Q1Fhwk?*Fvk8`R0f~|?|Q8JtY&P5XFj_uvzUunfUE5pj(*{R{pN|@0za>e;N?wvKlwFfgP>xpj(f*<<*Y`7S zH|;l%vTU?0wluY@G@mi;GA=Q^r+-$Lr>(2WQCn2I6vQ8G6X01mwVrH&vQ<690C)nj<(;bXI3At?q{2ATWYImS39DPi_R0SbMAWHB>ywP z*TZSig|Uu&dv>(=MQIDUU-7M~spd0nu`b6j!8p|vGG&`{zZh7a@$ zbp5osnxKke%hP*?x!#CO%75$YIWW5ry5cAq#P%~do~{i1egy6eX3 z^@h(3PaB(p6k*J@%zATysgG%)alPR&{ZZ`f!@o;o77V8;b02pVIg1=V`*M3% zdprA7`$79Hdjm(%@vC#P>oIpDPj_$F_ek*haPw#=24DYWZ;H*bgYx>yw^SwS_S$~B zwt9ztm*FjA6gbk(RL3MUoi}zdHZXjyOVgS(L)1N0Un%y<6w)Q)I->K;TK))UkCjC$ zBEGOHEDogyPx!UI*F8hrKe~Q%Dx8xY^&L7#$X;mw(SFL_*P(TWoE0w4-O#(!H!JXD zs6(V4jM_@(hG>VRvuvq6L%B*-OY^nXt;;afHY%Y{>@b}(-7sx8J!d*`M2fu=UH~)9M~=phoAwR% z>Gp5zJM3AG{f=JFLgzx)XYS3O6koCbP;gdwShPR)Fq0t?Np4Ad%4aD8%AM-&+V6E? zeM@7WX_sk$d7*igd5l?So@ZKP9BcSp_qg^6%{cXgsxgX>W!ohpadUPY--s)XegXPc zZg_HNSa4e4BY#WZZqJ+U4lbi}nj_tD*#4@0ru}F8F?)B%9mhOpwexe=OYY8|KHiJI z8-dNCwuZua!dorWqlJXsO zwWg2m2Ysm_U_5Vn$9&10Z0TUhxBO)O-89B%)9=t7)o#;_RDY_RD_>xlTIe&i5Q* z$9wi+_D}7H?M}M_=<4g3;V?K)InTK~?iaj!eEkA@gWbY~k)^32t4Pv`{wz!d%Jo}?n37o7$YV2&+Rh%QQKsDL(srKmgi_em5 zeZlg!*<%_4?Q>OsSevizt+2{U#MhXav7f?wg9`%h_=ox?dAhiFyL)(gc;>suy8W(6 zu0gIRT_>CeogLlXJ!?GuJ(D~d?_TeCUkl%(-X7kjzD9vDAxm^O*F)35L|2@n#VV6r<$TupEE6=Il*E)6QLHFonl9?A;B-URoJ=BLL>B71`0_y)V*vX7{0Rn^Ou?Ql3UoIkowxxRHj z=UL)?+h_5g2rLR8jJAu-k2=D$fbKs2HU9R&tnm6spXkYG*QhTtC;D3KCoaf4*?!WW z6lJO|nmSsS_FdiU`WuFkrX{94%VtY~g#+2K%JhWMVt81`X~wF*gq2-}ypv=K+n4Vh zyA*yZp!AM)q}mRYUoI;sd%b$0qqSq4{k%=)Z0WLjZur&&o(kqhZbeUXqocouzX;w6 zJQZjYa0LfP_Qu5AtI;LlN#UCj4R?rXF7`_L%X=yNX};Ce(yr9p)DAMp%=y-k)tEdj z=}qg?Aj7gvQ=n(eG~UtupuVY`p?F$8U2I_7(eV*3v>{mLz3F_Xa$-rnBJrJ1t7vQO}=)oKGWPf>7$hQQ#vQlwR+5T%qEi_W?r9hu;H9`tGcGD zhpfG*I@T=OGd3_fC+zg)xsFv96xX<&R=l)wrQ>&JpXw=9Y1Jzo63+#%*QfF?2#kqZ znYsLgNT0y(z5?GOfBVp+=;PdxSbk)EsCW3ANO5cXD?$=3~a1=JVz?mU7Dj7OQcuCQEfyaYz;uw_<1UUvV2_`O$ZS4)>z! z$>oJ57mE*;oT`*~hIuyGx|e=lHrw9Q^P+!hV0PFRPL4Pukq8^)+-E)ZU{$0bQa5@q z_CQn;Z0)}s{3JGzHA#CZ`YQX#&&rxBXRD=}@!EsN)TFw}DJch&omQz?Ysv>TWs&D2M}jAP;{(5jGb0V5hddo^9PJyd6WknmhuJCGC^Cuj z#cIiH#TwXo8LZ9Htk-MIx2?XUGfDfbyDVcYZLK|%ZzV0ThK)af3~8WwL|vlXp|~xr zDf*uO8LUM*MMQ!3JsTW#ZQhD6%BGeqEE#J1(p6*mmB%+qWXnBh)pR>z^2S zHM}zPnSYVr82%{IHhd%WW@Kjgr2hxsi{W8RZ}EGgd{Ha$vl5%^an*LMM6c58%*9Dd zllvw;Y3Xf+{h6dkQYw=lPd;p!Wqeg9)#|lL>O7TSxkk}k+MMmgD`JyFZT&^w49|MU z!piz(ZHk{S9$)^O^8@Fqa^IbcWjUU@{s)4~0+V57aUl?n9E^1jcMMvB<3gRoi^9tz zvGAziT3^)fifmxh#N$OtqIbm2q(c=))cy1w^}p-grWHw_q&$$+);ixh(t6CYB`K6L zF6AS0bAwGgS}jo?RIXF+Q4N*v7qLusw0@{Vpo{N0kJqu(-mSW6d3y2J#dWJ@Ia3|W z%eXR4^)tRJ&|_BmT7oXNHC!D{4nGQdiz#FdSwe%nKNt2VeB}-B(k{-8iG|e|$(e72hqJB&@L7A-R zA=}J89$gnI4L%%v#XH>}z?tIjlnZGWnFp>J{6!h}TK+1_9g`=aPwNks0^O*D))T8$cuE-7lAleEXGwI(NRNclFk zMe=d;bYn+DH*E)XmiiafT;(O{EOBRc0=FsBJLK_i@!C9HT!S2=$_q-57C&D8v7>?a zJ7=$oNhMWP2OQJ=ABKO7yb!$N-S58^Vx#**jYDkckx2VU&FIU~+aZZ>iFZ`+7j6Li zkodT0GkcRcD4s7Lt}QXRjUsbPbGG%ob$rse#1hJJ?n8O2t` zcvZP-h2k5DjQu1wDLf%K5o{qk`&jn|`_RhblK#cVDx@yAd#det$>g#O__2Z$-rxP# z0&fSd1r9;awFE~7&WB!za?t@%arEJEeqgZgF~1?Qo9`>CWDDWfJW82uk`(1Hs*$>O zrjT{7HP1B5SjVhL;Zk!_cO_3uZkSwZK5iJUb7*&J`e~M{2dECo3ndrW$GDr}L80@( z*`bW!M$a}|qw@0Nvv-uG`)rxsL$2+Wn~O8cAGQr~pY=})i6WneehaP)?GEMzJ`P+9 ze+afsTVrFR$ASUhdhdyVGa~h_lH*+Oa8hs}xCKZ#-x6keAF_*bky*? z?v7@Z<{3?i$|cW}y(n2B>dIXTb`R7ITEgYN?;Uf>CzR?-G2bek>Q~ygG~6XP->_hjORUIX_^GqA1fmlg2Vhj2d+mNvWvtAL_0;Pvqs{UhrqhL!rOI=jZLmTFV9^OT>-ypoBG zE1VNp6?_*)haq^&xuNpo;-cHP?u;rIyE^z*+4q+PZfBQ?93Jm4pC z8v;#3b0XEqsqsfCTmBuy3S>`!bW9ldA!_vH0?%Be@#!-CyHg#S!^F}e&|QAPiq!>B2?g=U^`W2C|*^x?vA56+ke#iK=rVq z<|S7vS@(_5sK{gC%)rY5MWkD3cCcBvG`f!)6k7t8iH)Pn0{@Gnvw*JR`nvesJMvtT z_aY<&_W;G+8oao>yHg~%yGwC*EAH;D#T^0!i0A3}z4M*_w^(ggyI%7qGjr|iy?E?2@R~z?X8{jBC%GTU$w!!VW;qX>YZclq}223aL-9bar-H?bK%9AO2jNb16I~5Kb@tqvWrC z8H4?Or5|c}sFUVZUMme{EH_Y}=@eYNi3~QX>J#OSV!U#c`0-qRDz^fUXCl#hwx4;u z!|(nla*d~*XF=o!SRC?=VC`~n-x5EEiGrb)67Paq5dZq zk(~KTki|^eRnzcQ|AZ!b$cFL0W)P2aklYMTQ5h*ioU9T49u_vr&P1DvctfE?u&TfYGR*Y@mt1Q^O+a&)wuciq<&GZF6~uTiYYrQV;)DbJzRZ`F^GE_+2jJM)rWvD`|vwO)IDs*5Xu79j5xV@sxp-LMdhk*{VL3 zW++qij*t)N$n-@2;wY4ciU}u&_(uQQs z_I;9)i50vL80H*C^XQMYbIb`Ng*goAlr!YDk|xKf^YzNiD(uE3(GjCHs=<{qhi&=b zSoTJ>O1lMKjpwW=(NMiGuK3E4ijyQ`(l=B?&eDGZH{uR~J8|iHft9mE6 zQ|;XS9ThC6g=a!XQjC-#W)jwS)3V@-A8zb`eoteK{CX>Gk$OjMLf#o~P;1-}{X`tj z$2YL#wQqJNx#PSOyiU*A$g18f?^N#y@3*MYQDrq zF8afB#Qq}ak%7axdooJ=YY<-1Zx|C@}3dfiu4QAp#Ku|x4~?y_a5!y7T%b0KO*)H4r?{M)m~ z)6_e}do`-H_qaROaot+Oyp)@YUEBz$upeTs=>y~w;fJC9;$+De3i$G5<^GEKnfhyz zuV1jOziHN;^cPuIa*KyMz$lK>){+-Ag$DEvWEsshbmkx+hT1UkbcDWFeXeEbar6k& z0x~FX83k?UPnmRcnmxzWDbf{jDI(}KMNf=kJ+HmPKmqCQX&A}7huTH+SkqI!KUW#% z@e8OS4Jlq}SU5_29ljUb={uQSGri7_AwPzsrv*<1-}~-n)yz1ZS;E&w*#e!)nm{t3 z41GcB=#8LS*c#=>Ga(I>MuuqD)kVryb&X!t2w*R}508b6iORjT5a-SaCE|WW=ZN9n zCQ<)*G*8QD6jRDuKJrs!syoG=Yi?$W6WVk0x%d1n)*wIRs*+i{9X=Hv99j~1o&7zn zP3q_$RWpYLcw7K#_ zc#m~0q@Ob$;dnd%wL)XLfMBz(aUS+;jEaB}HOu=P_Q(0XgS>py0`E)@jVSDVY8fsx z;RXH|JDt77ZbB7_AX}wk(hJcQE)f{+dz1O~*R|AkX%}*92Q0qNIqNg0WL3*qAL^jS z6Z8M)EvwTA`kb18aQ-{4RLc zZ_PfKekFDJ?_#;1{9XNJGIKIJWPi;$7H+M4){7DgjmFoQT`->7GPTiHGK#E&)XpfX z{_pH5T@iESp85ki8@%!_QCU9Qe8f7yw%?(+mwGBkB}bo*=^K3$G_xen?Z|&4oRQbu zl^g{uSNLh%8GIPu#5d47qn5r~8>+6A+esZmKLU+%AEkHy^)a)K1%Gq79JvmOAkjFDEu&D8=E`u!+ACOmJPR6h8gm>qLN?|zEw7t2uRKJo94eOkDkGSh=V#B1yM9w> zng4Cpx9ry0$vJfcvy|%W1^f#=rXI{9NW+qYq=#NcbLeZxe|lc^x_B(u$$!%Sw=|Jz zxGId3hJ1fvzGaQm9J$3a(mN-rXiO;PWbE!3!?W7G%vr|O({%uL72B;3g!}9zyc4fQ z*)Yq$f;;|MTd8eV=Slti^)q+H0yXwaGd?Q$92M_D|W`^m?m zQ{Y*huT@g+OY61cdJFx!>XZwHGyVPjuYxxDFs;BAF*(gk%>heY`wrLE$bH_LF(|fd z?B$p>(V?h85yPCh_G^x8&~EBmikSZ4?%*W648K7WnITMonQR;&e`phw!=Y+9wbJIM zMyJ2cZWmbML%Hj6+vIG_P4ssZAE{IIPsRz{p4-AYaW<1izRQfN%;T)H6IL z7#sLEG*WUZRdj}JYaVDzxAD%?u535*?C|c6cE?nU86RCSYLBNt#0TeZ`(#@e>nC$d z(;-VFfr2o})v0wm3FCQ!F9Bmaa-N%%Q!5Nx^-g^H76JCvCac=6~&*T}>kw zcy@TG$M4zWy%=>nIw`uOHxMz&Rov0ncE|F}w41NTb>X7;9(*INE&DI4F-|&7A46{$ zpY{LbTY;rnwbN|BKcq9+Svl_PP*GUmqYFnUy71+^^+ z>VS6x?%<4YAMpF#7k^2^V6GZ_2v?*RRVu|xg~i{&tAXM{Dbzs95VON;#NJAn)WWes ztmV7CbmW1kgE04XhJB#LQzCLz74E$7%`{8c#&5-| zA-#12GM62QBs)Tx*;ms0XS~e5n)NxOaaJAQhtP;{j(kU{s%5JuHJ%n?GH@yG4l_;H zmDNf?(L*;Cz#05>@kxyn<<^VRjz(aTxP zwb(h_anRA<(Z;saT;4QM@Cpa{H2%1-h@Z^=&0S(!q3T8<`d0m0D(x?w6_eRM^G0^h ztfo01effjIP`k1HZOc94=CG?^9qbw&o!c#2%dVBpWq-()e2s(E#rf(eZK7IJ9j-qi&0tj9 zA^)h;0$O)ah|bDC#iURt|Dl}4xebF`!~4Z$;#cV}eFjPto|_Jst63`8ki+U6={(~q z?QZCr=iKdF;e79ibY?pHI!oJcTMO6}YdOn)^DXlW(|_D0{D4houd>JS2XxC2)cWD6 z{`!G~fuey|zK*^E!2uEj`KlCUC|u2Hy{^Jn1Niy=2=E~d9$w1rCSIMl1Qg2ZUzY|L-lGaM= zr)u&JrMuEwIjL3A`m0g$J~3I$65C6ILKpmH1NlNJq3U8II5X$Sic*Vy!28%y>}76; zu*5XaoMD-2m8~&0)qdC6&0Qv@ua8;!Iz-Xf_+) zVM}qV@DNJXu5zsC4o?pE1$AmcI7SZXMQ9V4nHs61lwy)iKA=5XNtBIu~xI?*viR4d+3^f~pLGkXO|L9dY{a&}nq~Q6?Pl9;U1l9)D`9J7du%&r+iqQ9iLrDso#n!~ z3*HVMGCz*vo^gXY%(2`iEEzw@IK3`pwKl3-p}I6fPExOFZ?%u=I%T352pta>kne(X zWs=lIDWH^)E6B;pJ6MUEfCKylJlp1S9pxav#6(D?GQb)r#v^~n=hMN0Y2y! zyjh#9E3NM>qb!-0g4Xud!BEA0!z*wK`J2(0u6PFXGirdTmlJ*0?P zQa9;eC7%8RspNjRsqn;Xwu~}|%}M24LR-*E zv1 zKS_$x2K-X7T5Y2XUWhv&li@MWL#FnNv4EBa>cTAJKibxqVHAbL`Bq4XD@G5zj=#WP zNhxCmbm8ufKd~LzLF_)hgOHCM%M^q(a${zz;l*89C$clmaebU@ zR3snuot!@Q-j zWC%%SIzv|YGQLcI6V1qEZGLSF6fk*wa=2txGYb}{vH(oF`P)nAY&Re<*nRpgF z;rfv11uvmKR!=d)>>G9-eBTJ5wM3DnT4i`o&OnB@9o>XJ;vei6HU^Jl8p1tZNk2f1 zttL2;8fg}NA1wrTd>OY$*uqc7J5YCaKT0B_@8aSV&7!bUKWcNK| zjxiLfjthWb5J~gsz2W;Ck)HGeq>^Et#^<;Nku_wZIfVt27wcoKUA#@{wLUwx#5 zNeKeuoxCIij4{kv6w7X558~bEf5eV7be$;z??-FBjQ&fnLLTUXK3ChM|7qMuEw~HZ zTedwoaIOgVSlMU@Z|x_&mA;oI8()Y|Uq%lwYk`nag*ggLkN3bKqDU> zgX_SVzbq>%-wN&iA`k_)f`-2*a#fX3iL=n7ObUc(u^rqLJp8f_p|-hw%Vtjrup zlrLtk8|#gEkXauHIq|D#KDh53ObXpdwrXFssrnk-NjssoxFz!&rE^vIb@&@|4dr1@ zklnD0X{B!^b&{Ae7D!?ox z8_7{1LEP6LlHW{s^cNjOrqEd6b(DaleM4iYA)&5pS@afY1?hAKWZ(Y+l1FQNk?n&D z0g<3Kv)33%zv-%aNG+zv18ZeA{bkHy-}1G1H~R(p!=FOWjU;kT6UYI26?Vma*aqBB zv@o7=1`X;{mFI;+d(a1^$MfARS$UZ)yn) zj1Tk$oMvz94X8-_GSBg7j_1#_&0&3-WK1Uc;a%HJX3*8lOyp*+(P73~Agd%WdC@t1 z0Uu{q@V&TIaMm7SywEe%gK)>%s2#PAP@hO;i|`}(WBf60Ka%JxeYI9ptF8~HcZ~TaN#EM+Bk&1AUpibTEMkw zj!NUw%pN_DK8Xw`Gj&Yv0VAY7tq#?snWz*VjNPaRu$o4r-FO@#bUTF(>EOIy3HPTp z${2hn{&1c?haN+lU~VuoPf#7$b2sCLvCHrg zlm$w$k3J*$^y^v~Jx=$KSIlZ|IhP+io+phRv^cOPP5>W-1AfX*G=~kd({KSa31*91 zdQ-hPjNWr3AMFb)oSL``RON4Q4`B8jZVWLF8ms6z>NolVk>~+!0dtWX=C7{s$#D!u zYw=rd2wMy|IJfaLP!+zAUO?km#>@ep(pzIEjJ}R^E-6eru==m3w}4IZ!bkujj1_Ny zn(t&FqG&*KT4Nw%3)E&y(YeMvAgi1}<>AdgXmn?e!@DvA&YQR4zQ2HbJdnu*CQ$`= z8ynMEFtf$MPU8?Zvjbt(sL3Yd#%LsctD(aNu?1HDE8SucN(SR1{!F;UVBZZDfizdBO2BLFg|8xCcxn@T2FD z&a@ivMw%Fnm?*Xjw}#`n_1qcG$vy*i&>A2b?WD6v2YseeS`tM?o~!g%6&=Wiz&n}^ z`e1@FPrm_svcd9JvABFpxvK0`$LWVjir#`G8+)0J#%WkdchibMsoKL#2maC#P=M#+ zb@)4GVSoD%XX66!){W;+3*AgZO|mdsxFQ@g3D%OfkmaZ_gB4K|v7@dLSuxIem%&+~)LD{LE_CRZPOtaYfhs->gQ4d16DG#mI6x`vO3UWHnR zn~B||UvfZGfdBG_6a;e3Rj3GjRRpXo;JOo4^DiP=vx*Jtg?tq|-ZXOW_88h4w` z!v(qT>`UXO9#-0jM+1F***TqZKl$nfnQ&9-x3Wu%B~If6a|)PFQ(yR(uGd^?9qRgq84YQBuwhsIwwIR)si;ESW2m!tb zpMqhvAgrDvj|o2xjthPdqz4LuI#)ALGFV#ds%+5?kw(T9CLUMhw(`ZfrAP$-^irjh z*djbjEG*|&lZeEG*sMPR7oWQ`=YDRPfFoR4^1wB8hV}Cfx(M??K3Hd#8p|PrZjUMaMO=*dR?ELQyiu2pRFS-Bh3X&8%;UZ zWVbJBU+nzoxe;@$dAZ@FPxxw9<=?e`&Pd&#Iydcy?}*q_`^A_{$IKVa18jXvFc4Eee9esI=hw9PD(H8*EjAiwmtc7P5A1)u`Eoc)fkGR2@`aZ$M;|CWm? z_vE8;l=4`uK&Bee2*X)*Id_-OWBLI)fM zsin9s^g8$J)onlft6SWX5Snjy!{PzfvsFoQ$foL>p}Y! z_pc}=Pno>)^UjIimFH~imbiOy7oyzuOhyhX8J6#lK3P6&d0+NZ>2K9Cc7(g&FV3TR zoCO*b2q#>L|2KMrYo+-Xb692qMROZxx6Hhm5s@`M>rU3V>^#1tATP}Y57SwckL%0- z7W$dW^1IPqI2#w1<^+pF{ccF`a;UOYL(SDo8UH&WbYl0gx7k)~YdDkjMi-gWz>+%y zr?vGsl20}Dwnl>Ys$6uBxSWKz0$uW#&X*_QRb00i64BJMo6Zk9)AM{?{jT1-7VqDG z>YJM8>qqXHK1FuUJF>v=f<+2k%y&2TmHV;f25zCf4W7jNKO6GA+^}Ah3WTl z#Nb|KnX!O7VybLeVKJHObK98Op!AQDHiR|@<>1heJzNzk^k3z}N?C0sXiZ3^<7b@Va7*mS_yO$Mo6u!F@Z*o2PW%%zR4fRTVo%d7zBl*td`Q=^f{$Oh_G&hRMB?A?* z@2455@!var`<1fs`+yhf9YghYU_9YgcKgvAN-^y)(@U$YdKln6o zANkTu6-UgHX`4w zf_)1o75<)oPW+qLQ!(eglN@RIqr5k#-%oQ&v#)Kx?MZc{&GmhkW0~jX?Gc@0U&rsw zb0D@~lr19UbXa6;(k&rhR?lDMzW4st?#s$AT~nt0*#CQ6&UxuRlb^p~3R;TTqO3bj z8+Z@fn@(4$+(h0YCWOWWhX#2_B9--z4kn7P<&pXmqYUoGRS=4p#)7`P5IAS2fVMXi z@8HUrzM0$G!p>gaopHPK&n@_0!Ttq?>jNS)8VH)GHdp&^Uaa{e!O~+=3JSPqrF(@MXQ4+F7a&weImgA>0((sa3(d|lq7?uGifKsL~k=sg?ePnmbx&O3P5P4K-J0awl8_&NCx6}X&# zXF`+sWieTiN8L+ZEuB8=Ilc-55u4Cy{~}-EoXD)W?2$e`xG8*ENhPI$Gg+3=&{LQ* zNAvfEqQZ4{E3?9=NN z|1W=oI|4fTPP$I3sN|8aOAn<~sj>W8j#Cn0=Tl$FRLW`niI-{3z7jOcQu_mE@rYvH z?a{Mh*T&yZxRfw7@5a36^2WsNiQXB#EIQM3z%{{og8iws4c`rZ^6v#daqpbzx$eOC zP#4&pypx{*w~N!4(!)$|HZNC%3jt{_5^7^r)pYq+xNPW7pitnw-|b)GYwtUjyEb=M zZYlrJ;Jxq~`JQ@R|3PMqlLWS%}7>N}@NKT-%hJf-yf+D@&Mept(f999~hdxdj zF6EK#hLeLm{A+x3AT4vnS2pl67!0?Su`)~ED{oVFfZF9D>GUg{xPm~Z?a!=+lX!KS zm-eC>y~cFM1KGRmUalZNo6i;=nlD-V+Z#B`yXQo3o>|^qQEQ^UdL>T=P~)hlk9V2( zh3BFBtSwP^iQ*uu`%#UNON;U0BB7dr;(=v>9>IpeI-!5U<;6F^G`XYT6d;1 zN`%vDP%Et+gB^GUZHjtIx+l&T--btqi-aeIP6SJYs)gH$4W$-JEw!q;6l%O96ap*s zSU5#pBRlCvAbReH+SqQWFAoP*G>0#05+Uz>&OF>w#d_3w#d_T4c9d|AaUO7Obhn6@ z5m7BN1(JdXBkDwKcHeRSWuI*=Y3{`hhRVSUx<^Zwzso6d5ve06q3gm!f)4{3!41Kd z!4qLcZlF!q9%zHKDar)7w(JDwT!gw$`$zi=++!;=Mtv#Ik()zGI#%i_{UcWaA9h2@ zDw(7+;(t;fH52|U)SM(g@KaYC!-3b@0X2iYcmb%nr1IN^9zqczMZo6f<|gL4mIBuO z)_%52c87C@^NG`NR(ExDCq!tj4bGa*$&NQRVy$4aS;p`)*zW9A<|t)>!-RR)q@T6w$6kDg6|?>=TR1Q4+7b)0)#mL{oKe1#M6&$X_6%vP51b zCn}@icdMmLS2lw?d7ivfsiZR6L8wrMpbn(co zz7}em+M6p{9M*tUwf%w&Z!za^=PKtU=Nxc#eztwGjkg!KKeC>(-nDK4uRX^%VjG}D zI+;G9rO5|I{+C&!2Pg%5>(h9ZDp*jzd#_7tUXUdVp^B|eghC==A)YOGouGOZr9 zv%;#6wAtD^tpuFZ6184R2_>MkSH3CZ)M45os5cD*_ech*3w7(cbOe0|cRd4`nnR&t zS_`gyHPA`pxP{y+&d<*=U$)kZua6wSr3rQQL>T-Um zrF2cYBF%*Rc|bd=kJG1V#kBt*FTF$=t|e;|wS}6SUZVBrE;uhgBxA@NU{+oLpIvQW zx88x8;wEDq@WM+oiO7kM<3?VgJ6)P)Syana@IRimFR&+BA6j#) zQ*5QId9B&jN9LpEOmmdEn6Qys%!_O!@IGy*gpmjITveCVjq-E(o6=Q@kvmJ9z$LL? z{3tFG{}A_!nNlt&%+r-B@cT7an?VL;pt@Y!s&CQ{>#yKFo=9fsmGy;s68yapT}!8s zqA&+_2a@R=`VhzpzK3a( z$!lI|&TF1y9&R20s^~8BD05@eUC8{lGgaVqwh$NK4&q%v>%9n-wcbGV4Ukp(9?han z)(Yu=>;J&)OVyvs79|=KnQGc=eJ;76rK;n#idwd^OD?E-$x?Du@1}p$+G=5CgxXl| zM8f1PvC`e-ivF2ArWJu|yT+&hjQzz-ebgUF-Q9qoI@{>X)Io{BHa&&j0KK^gYXjG= zjl05)#3}eVUzIP&DjedYVg6aqK4yz^8+nae!rkK^vE$GJypj8avyA-sDtiZ5+Izq+ z*n~+in$u~#xaeAi-ADKdV-~3MisS^j@Hv zJOOw9I#Nh~M7kLl!GHLfd;!kle;U;#$IcHJty<7G!4QszMnwgSuHk_zSd|-?$_j(0|hF>_R41Pcr)P zNvJN(fO_A2ltTMMm8dmMF~%AzXbn=A-OJ`^OXyFg8PJpS7>n7KD4wjsz0oH9h1Skk zh$fSAT0P(suY)HxP9F)Lvc2>=+5=UO;>?BX z>g-Xv&RB^%qwa=}+(H8}_`#WWP=j-*`zX)H8y}VGxHDIr6sC>X8SGZQBk{3=@qF5V z?%+D|HTCDP53Wsi1IK(TBwxnU15kHtq(3uW;`j6>+Q;~z-rtg2BmCC(0G0j*J3xP= zv|z_^707n|K3a_1E02E&5?JSePOIriDz&`b(*$X|UO>Uz6u@rA*Vc%SuDE zkvofa=ozFsp3ZJ24@hlvjVVqm>I;Ms_?9%tSj!*ARi$FYY1+v~sqKsjaIe#~_2f2> zP_Fm{9}#xaI`S~~fXSh~S5)Q*zh3{P?BH55|7chBR$Kv8L-~wnnHrE7trOlNYy$^L zbGD$lVE7foInw0za$Cy)oGd2l9qeUjpHLE)YkjOX2_~8+Tc!dJgmFwaqu`&~QRe|; zmADp_vUUPzz(=l*S(NT*KGRb4TWerMus30rk?A|;EmZsK7=`h5y#oHp)Kv}R0bZz2 zGIl`nrW4IV4UFmfPJEu3X(Z4c#vyJ#>8LtcAO0XVW3KS+^%#^!uNkSJ-M!)OtKC2` z>uq>xF5~5M^v&`O%R=sw)Qh>qUnU3DMaavQ)4OXQ`Lei+woYwm+QA+b`y0q!m)w`$ z2;GGd>Ja6!`98nYKL_1$lrbuYhT(;#(`c?%Q2Eo`)+UHg<*+Tr)HK*!e{46SDgMtW z6ycP+=Z?2Guow0(7n?bznm-42%GCA{?+7N5eD*C`Dd_{Z8x__!(}IGDTogC+cZ8nu zXwuM>gmk5?kDDTTyLc%ro^Ss(Oa=m^bQUr2dxY z!cwV~+R8SIeHh%!B-AyTYGxqP9_p;*UWFk>|?rucR^B8tZg4Ks;f5wM5gg z;$PegVG_BgEJN9*+WI4@5Z6R_59{GM@PS^_ziR3DA)BF2qJ{ZVz@M&-eu4_V8@~Yh z_)l=0?qaB(iDS`9EnvLC)zNt}LA?Mukk?9YW-psaF4Cr`ALr9O>Mih$dDIzXsL9T@ zRX#91OyBgAdI7FKs5RxGT00G>-N}#x=%Ws2T5+9eK{Y?R#ceUd+I0FIXxN2~a{3+A z9%t&Wadi&B6j~Zrgs-mLCMm)ZrlZ`1+RQ05Ry_t4T232kECq-AGd-J5$7_sD`U0aQ zDuU{RqIe%~plkH{XeLTv>#MEkeW5%)q%0zzg=9mM11tee!l$fbcA9GHjn#(yRb1BC zN>`z~_ywszY~VRB2+qxaIR}c-qm4Vb0lo>J?vIXvKJ&xq#T*BccmZ&U{?s*?rQRDi zpqIpGSc$)(IZP4o>!v`3nbng)t!n~Q?Y~hY;~cqyT}*Gi6Y?7^nc2`g;9v9x{{aew z#H|E&@?J*5)r^&76rPXw&{T3AjRVDb9z7`7=xTUVZVMj0k$j#Ng$v+bSOV)vAMKXD ziZkQaY9guvX@(uDl{V&YGON{@#x3E8@sHer-OT?1tf5p;*=1!fX4(0q7X1cfnJij_ ze#YIHuu_tbW5;Sw)#iLUQ%75CJjRs0A}>Z=`4(giSxck1DE60TL54n)en78{Gt3_1 zBkkBFMmIgjh(Mb$2TsS9#&xzQqiS)m^LU`9Fhfm;NUS`P5m*t3)<4lJRE+5e^zEm3 z8?iIbP=9LY%j&7bW9p7IX)-Bk-j2t}eiF&AL!y!dMEHH6XXP+E*)2pNacp%a691x) zjFI>$GeFzPa2Pt#Xig@XZ>pD6d!YrU$s|TeACWOoI(DOt8; zes8!CDQX!)%ScW5;=*3>551iID03r_#7?su(u*iN_*X)tbeSYst{Mx)3G7r`b*aB{ z97v3c`qfy*DMpTbiW|$0(0FaQsXLko?ZK{a7uc7|d*d&DBz>S>;0E9v!h=HwU}Y!`r&J8e%gV3it4IsaR%N*hC^MdA>*e* zjXby|;~`U+CFmthqzl12@(kUi4{09gC9xgNWrE}@Y0jn_hG9lsjB4~MjMqKrAqhcN zrxtWrI0~xSe`p6?PO3A@*i@9RCot9V70`}mk)qg5ZqpO|9tMFnSq81bgXwUlf{_fm zLPtm_)I@ukt|T4z;os`JJ2nj5+BM`IXCKqFvJ-kJQS zo59oYoz$koP(^MZ^a?79_86CFE$D%ugMPQ!n8JKOlc}t6s2Dq4_Za0+C)inTWI8hs zfwZ4(OlL&h1G?{VyuheIr=e%)59TIa1e#nYV;XY~G$su=_J`0#qZ`=;UKR_pS1$k> zU>#;BIY?LF_RMIKgeP#fASF_QDT4DekLYeVo6QIJ{!V5n{zxS)AIeX^=%t|Fzy*T` zjqW$9tRL6MGUZVP<0SML`bcgDwcIjXq3wwlF@(?4tXLiS$B!xHQ8? zROUY%$JpskqdqPUpB@Yv{uJ~J`b%_T>VgCPGxS;ckBou4`hoF+x>y7B=qYFn^h=m) zv}7-X$~6+Iz5VGb(wFIny3#s^le4lbK=V6egm5$+pl$`{)jQB^=YtcZljb&B;9Q`e z-DZ}v)s0{JS?EJyK)qrO`UniJT1+KQHwuuRpohEz>VJaqnJEn^i9SpzqZRli`l06iq2J2`+Kt(T&QU9LwYbU5qJJ6%(QacjO=7k~PndU<&<4hA$Ss zXTqTC<}` z7)^EhzwS9d=t<)u^!n%xC&pHk0T0MjV!Z$$Y5pa&o zMPtx0=yJ0M)ZI+bMq1$SOncBHuW=o@!OLr0*N*IAq`?iCM7t$~tNT)GMWoFrFL@~d?aSz_$x107`toA~#jS-Ea z?#1Y_Z)09Z_l%wu^D?#{BoYg`(j7Wn(@d@&rp#&Z<@b}0%g-RExiUN|tOb?_-$>om zhl;L>kam$sA7eF;s>;!wWD@LfDv^z_i@c&%l|PGm_*SS|aA&|3j0!yPp9!oF6%N-D zPk_g8j9gDCuBGW?{{JmK#NFU0KrP<_1jb6{($-J*Kiq8~^X7;?8*;5;u3CothtxTI zJ5)VzE_XrB+??^bwfw7td&12n;PjAE%n9fx)Rg%NKDlDXTktcE#aW<>`C*T>hb_pJ zV0YjnTt7=s$02uKZ|~Um30D&i#?_4aD{_!4#q455ATgAbJmF~Rv1AcJaS!K&s)Qbe zFUT|1#@b@S!j5w=FPR*sUEC7z8!ceQ5~Tlzk+xX=Ppm2;F){ok*x!E=6qsNB89@?u zD09@uutx1gpVbUfLY+b{f?I>V!vm!wN<;7rrV{8p$QoQb;Wf7w z*F;|C9?%2ZY8LeY_|uUxUkSbVnF*bZYWD~RHwdxp+qo0`5>@=P=l{S|)hfHZg zI==wUQPc1~REB9zH|Rxm7r8+j8I57Jm~R?o`|fxVaT91Chdj4k6CH0Y*<3Z|t=>U- z7Pf`Xgjd-{;&nylQC=ZQ7pNxleO4#kBp zh#lk;%4}^R*-YcXO?d`-QRRaBd5eBXE2aGj6}kQDQ|++Mz`j2gR*e63E^NotHQK@4 zzaOWtJy<(u=Zlz&Lk6RSI~~Z0XY8NMYs}^O=FB1Ovh+P92T#hcbqC4NOVW4vu5j9v z7y5{-;`?#Mz&(GB?TnpxF}lUn0Iy#X*{qZd&jr?1u5Y`)N$^zoos^)~Bu$~pw7}>G z1fnCrr|GIRR4S_}>RU}F`Jo5X873ciTmqm`6okKKL(i=ooWk`IUW4NQ!!iJ}S9jcR zJgHF|qdrGGbX2nDH`PXdbx$ZUusg6fI9nVjFH)=O$k>OEa{b_n{$_`R7xfUDhALqK zdG+q#mP}!4(RYy9ofP<;yCo->H7NUU-^kD+327g}JK3Cp9-77p@b{im+9|h`scJoK z2^kBjc?lMAAE7lb=E?(q?G$u+8pPh_QiRjyY|AWLA!lWvk@WU{jh-0O!n4#71wAny zvnTYL@;aatzX>LZZWwu@xJi3!9EF~1JHQ857*%J2upS?R&SNbQV#l*HQ7m1kos}nr zulj?)Ec=>0I%l&#F}zf2sCL$?L$!1WbdGzj7to4B=_i94Ci|Be8D>Yy1sJ21sVlB#NPh1q5MD-tD-&E z??e8(Jre?VS_X9A8Vr3J4>J!@FSY~!R!~jv&G{|EEGHrHv(>WS^33wXQr?`s6%Q9(KITAFVq~1_ zvE5_tj*F30xm);Fa9F5u_;jdxI3RV<-h#(w0rXdlHJXCobB^9XTcwVH#Ls;-O8c!A z1P;vs359nDD+TujD)@&0olfBdW+#OvYjp{UT4 z;Kg7E@Ge{l=7buHSH$g7ZP4}V>jTJAx(zzH%|q4LF`UHJ;(1|<;5F4Z?KJV`e&%;@ zjo+=3Ez(}ao^G%1JmD%7F+K8;r-!$Or+&l@S3gIlnc=E4EA<8PT2ToHLZ^dqp`GG; z*{pTZ^MOt}gbt;r$s=$Z4gp1Rv9d?`Urux%B)1EQ!$Ei46*>?EB6>gw?hkGY-3p%& z7f7v?RazWmen-$}h82Myj-AUr2On`3e_qf9y9t5Y>Lg^|PFcEwdNkX1&R)%V&GpJX zBcckhA2)b&Bfh&jItto)n{KkiIH2EGEJ`nV9&n6%i8bU`N)4^Kc2qk6uGH4rZuO3` zT}e>B5Z)bX0d&d}!TjM!&}iJ!d8xSa2ps#TVLq7!?257I z1&-%5ZaqI;h&J^$4KW=z-7@`Ss&4LR8EYMDt!(?#E<3I`+qrv1SUj@#GMhRRmhN%jGi zbFnl5l)BpD2yrqnx{|_2!~Mc8@hb3JPs>k$@sU?A0(wzTV+->V?Z*e$=Ae3>=Z^?Y z;JO}|Mwkm&oYocAXVy>F8IY+|92cCj^Q)_tdxd)#I1i@6TG_{J5e~7<(0ghI#rURL zUD+%bRQ^?dDh1X5)c5Kc^)WaN%R`m89@KmG%M0bra%X4-oguvh?%z4!s5KJLgu8?X zg=d9dg;$Clq&OLLP$f&9t+fOlOd_x8dr)NTxF5Tco5e2@2Ags~lj>-`Z{{ssEx#>G zfUY#wHp!ms$m<;JeCKQn6mRToVt;NeZMh=!Ml6r0C`#s zs2Qq7I|C`or^-d8F;G0t%g5yc@*cRq4WwP-VsVxD0QNj}#Uo<2m;{=kCQXwYgW{b} z8=)1~f9ec$wfvJA2Fai%>=14kPvF^p5DX#FwA)k+nCDB(1ue%cXRH@(qTS_8b#8ZU zbB%O$a>m~0+#gxR4R60Sz7f6wzSX`hzKOmY zScw&tlS;V%g1?j+uVz3)uPyjEH_)H9>3fW&U`pMBSKuVzhsV+HX@;o`*T3d$DjUa5 z;A;wD;yKYIjg_`buVAYCQtBrK#SY>fA%#!iHnY2!Z*&6n9KMF1;U>Mr7-B>l%aK{w za04F#%=Og34fTdU#P3lSE5)&Ee*stX)|cp`m2{~4r}-Kx7crip{(4X?84I=0*3iW1 zp(SfagBA28x(HTL8+85tLK$KUY6Rn{i%{+OLceAPvyWI{V!2;<#=HDkek*2rgs?`~ z3TEUk#OiW_4e@6NcaC*4QA|1dF4YC>77IKfH{#^32p!_@&;pvTWd#PKBG6d1`#JTh zzq`LD)W1@2BNz-s#UQN4i`c7k{J+8P>#9CMcYkl7zIF%w(5b-_!7lKAtqX_iKE!Dv zh&o0-YCYUH8`C#1ihsc=ti?2DIx%;c-fS7p!i~hPzRI8BPvA5;#rNf#@`dB>$sQYKZhxQwClJ#1B?P;JIcJ_UBtJ+tctyaK{TTv${q5g-w z@{^xZ$EdOD5=5dxz=Wg(8fmM*LfD7ro2w^);qe?9$}r@_Wl37Z4$tti&noR5k|`MjkL{upa)<%jlkTHLwq>Km+0$IRn1G z^WcRV5C7mVdTUffCxAO8ffqFx+VGaobzSA%t>p$@f-3?SEjK$+=Ibbop}-3ou| z&_OCMy^p?$l~5mFn@=~TpM(9ioEnBPL~)4PPacE6XjPyM>~L_Mjl8ocx+}|!e{R+> zh64_?1N8j53>L$t;Ck$+v%$yEsQna74c>xUiwx|B8YJ{QdbC~@_s>RH&okf+yi1=4 zM$$RB*WSausI##WPP7%_n7fU52AAc0@L66D-_{@C6IP@e;fClSU0~pR0@6M|b(K6q zE+$Wd1=xmsM5=HCEl7^X*IJW9!4>jD_vxP#bw}{&BEXeA1Ux_sD6`1m<^9&7W@gYv z9q>K`bUXerB71}DB*OQ$9T=0hkWpFTK71cou$!3g|4%vCiswcy*m0$$NBjA#k`_ci=PDtybm`1!YZqfhwctN6Wn@jdzQGZpZB0`U!AvmwwJ zy8v!nE6hg+tig_O!|nl>;WrqIbhygzHD<#fI2Ai}1bpBBIUhg5p3Q)l^KUSXoN%${ zur3t%)t7-=a5&~*4E}b-ycS0f;tT4Z*WvbFgm{b3%fxS?@&9!EY!Do*k9a00-r0ju za$ppGq0(K4cx`mWsoWJDH7C~aM_}2~@x2=6@&#u0BxaPre_c0X;3J#^2#d9NzT?13 zv;YrpIp+Tkp79m@+(R)#|8~J4e8Ocg8=Dm&?Afu4`=#Z zL;~I}4P#OYPQ4;}BJZFJwhA8OrLYc55cAMqz6`ZQGgyH^BbFfXB(pFJ4~!ugMFJhx z2+VLU+|WxCKk#I_Q60z|2kQ5)@zjs7${g_UmQW)*jlC9!*+Wedz1X7gU4Mg02ZQ}0 zgF)5?YqdQw0KJTg7{!K|pFY5mR6s8`0<#b>>f`-$;%%;CX03Q46Y+00S76uZ7;mf5 zj`)MoxCFP!Ow7%{wYV3f;>2D#4qxsyc)}PUb{b&)6~YK~f=_h=yh~YPDOUYOthRUf zoOf8acCd7_4L_b>5x#pJ>i5^Ni|eA&_ZgTX0+G~?HM0!t%VJm;v3TcbJR=7_YI)qp zi(=%;Ap^>R)%pf&#)`PXqPoxH*;}KA@ffT96PT-af$({Wk?Muf3B&HLkC~YS&Qdds zX%~D#VT@jT%tu~~TT9GLE<9Upd^$~-Fq0oJLd&pQt`qt3{Vg$qJu#klv3F99sc^Xd z7gaK_`f}qpd@vM@Q$xIy2J}u6_SDG=PTVZ4rQ!eoP2GuK81*ff^=;rK z7RN}HA;#f(#t^F0)ASQhhIfEbLZ(-|v)M@+6rY{ff-5U;SW<1jYO@ZN*4OKKpRe?WY^hqdt* zUfXx^T!rvN7qPOQU_TAQN-hU(acQjLO8C4Yn5Vp$qn~)QkJwpRMh#Sw3gDT)Sd$y`W5a6YF*m2Ny9Z)7uE%f8i*dGKRnvIKB+NrG%*0=#AL4rq zo^K3R)?hqiCya6m)@^=#?JMTypT^cAtWpcSxS#$%TDdUt_wcq$5$zbfqm1?Q5Tm;X zYc(FxsuTXb6MlLq@aArKxQAkv6hs=hz~kAf;JL3O>maZftK$tG;e@J=wK*57y&Lw{ z2mIFeh^2e64@)B|UBb@$jurI`tC_}_K13a87gk9M#^)5?s1Wu@DB_bD@6rje^cEt; z5X^0L?BKG9vNQ2yH4#NuVsy3=qv3JSBT6;Etlz`jwZfiqVQ=k1#5e`6>UE6rAH?pP znEAtqHaCDhS%mw_d%WR#;~G}bK73jf_SAVJ8FTXpCqxPCfF!Ke?l}7zAV=$m`Fx45 zw#FMpVSFxOXWqj|ea5N11I$Yo&eH_^jrxD|If0QFi_`4}*3M|mvyAunh|l^17xXC@ zwX=xU7r{3DY)nON(ExiV-dF+_?l*kb4PYTFVQ22c+DXLkxQNJ6o+t~%%tP=*C*m|s z#H!ecJaRcAV=Jtg#zbH2>-fE&oFDq>kzRIVg2_o{Q7F_fL%EKJ{otyEZd1pBMN6*U!%eQbBc#J4;AD@ z7maWD9xEcoO}y(stmio3IwOd1%uzgkb~v8>Umx{5qHaHY?m;}?2fT@bXP=F@Rv1rR zn5Yb8j(mt)t+2NUxMFlgLO_iVW9ib1}XUWMb4zL?N7m ze~>f9<2T;Gt~rbu+Ks&ImeCLE!!Qox)V`0%+6!EwcNjGp>`Vp`@Gv4eux8jV7Oa93 z_??xp$NFIfOX#&`5N2aLK4Tq05!-=Dx{P_U8?iXK2O)bKLafBTK8!Uo;9n;n^F)B@ zPvAR$8Xa+J^uU_jh1I$V`W^%^0CR8&r}H3#LO*+lQ3i889CJkzx^d1}h3|fW=T88N zAvbct26!J}H1XU`5Vr_COAx2pJEI4(pCs((@AwT{FvgV-1L_fva3&{WzXUMLG`{QK zsGPzx+*pB zR5wsp?@tWD9uI>aMmg*>3+|AkFvkUmVo=KHkM)v>Q#~K%b1(M8ag0JKeBwfk$tmO& z8CX{Y&b{hH8lL+-X7D@m1P)Ogj(hl*W4P-)!b~*A8SF+3ZAVDhulW%{qVNebhy>)_ zxACMR{;LwkY5-PrF`N^Hu{Zx>m;FRk%)}^VVvlx5R4ant{O=Z75OL-_a{Sgfvx*~c zdxpSZDLnJS2l3&4ne{{PvUf)!Z^ zZ!qNl=hJ4)>0#`=e+nUe@O_O4H}Mhq&>HA;eTMdsMhpV#;2XH(-_VUY0hNhNoLk{o zQNs{F7D3%22@xbe<~SB_xDB%@ z4q@>14%iD$TxHtWnT!_qD(aY-7f>nZbG_U&Ie;pN~HvS-L2b5ApIjRuo{Nz;EsvgwgeCpUh z67UIowEfyOt#>dQ=!M6)e~toD;gGgK%MPf4ML;j?3Ob;rI)GS2y<%Q+RmEd+FZ0t7 zA?$ki0r=%5hF=MDgw74E7?Q(0%amyPZF*x~A6hX~G{2KhiTk)n@`qN)f6L9-#q14P zo{Y@&7MY1zRkKsAmmHHk$9<3eZMFVJD#LYN|)B({Vz)SQr*u;bwsBc?>Gjcl3YUC!{_x$_msyEJ-U#Nd#pd;#O0Coy|K zYR;q{zpDL8`Smv`{_lm19+n)AYd|^=XL1N{OzXnBM|Q}Wk+W)!(cv3R1$l+AszFZ? zd&R6(se_Yi{&}7}Ev1>zGXQSYi& z^tVzDc^A8@xTk`#9IlXoYDNdT5Bo@XW^Nw&A?KA`d_Fzj@H|Chp5=_qF(AB9NL)z8 z@c8hiVav=x;WAZ2tK}O2b>d&igZ}))=ax$i&)Vv!>74WieV-OUwh_R2WD`oOp2bw{)tW*o;oGtYxYjpbY)RsAefcEgb4YbX>~}g zkn-|zVI-GLJ=a$S%KO)Nsyhogm%BE&ce~GdPeM2QEL1gr3-`?1!e2+FKxuSk%$8i% zT*IOtMw-I*$us%Y^iirlbqUDZRopH<5}t4!nG|Ag@Q|W7DVxV~C7ZI@?ZaFzJyn!p z>N;(*v53mW7T{+Jcf{8cY4V$jn?{PS7?QZF4)JWWf42lO7NpDR*=aY^RSW6f?2ihp z4)!H0vb&VcD-C(;4ZRNsd zF+?%@%{Fs=b0brJ`GHW1tHLZ`#`-JtclqzzTx7@ zsK9f##s1b>!5VF29G#sH+^u}Y{o!hYR+ucoj^?YPXH*hhtSM45pP#Oww^Gk}UpY(J z)3b+Lre_tj*sL=gb6j!Izl#DRBLVp7uhe+@INb_-iPmICVxci2xK1_sNBNzKU&&Tq z1V8Dkp#RdB7)#ct*3$pcX;dKPz zi{?Sl9Ie3@XLC{CgO&Ui*B@)ktZV7R(r%_T&nTI>Kl4v^758+tukoHt28PzeCG(Sk z?>Wrv0>bBvF+hI;zt$wUA71yi0PE+WGFNq|w*v~WzvqZhsw>@wX~jN=`%?>!M4fb- za91n?2TIjEIjna?MAYmkdt`q&*!Bqx4b?-2g|-M?4=3Ld{0Z`LV5PUC?Ogi40|@O$visu|kHbWnWE&7?{PUEY%RyXjq%d;hNbtHv+S z@9wGJEu&rI)mcV0>LqobJpoP6xh6%-mKI5a`B26|*4M`=i`#yI9@s!NDHvV7YH-(a5RM#bPGq z2!x%KE3^6a@&3i$BaZc12T~(be*Jlwl=`Ra-!18@EQaHmvYr?z)DK-ASuW~O#J-St zVKw8)uGmX+Oxs?6qu>5?w9T^z7zf-noe|NlX*oLDP9+M2vPiB#zwx? zb?vt{OveqCveWgrgF?JqHY7gmXhhGbZaIrZw~y|c^8=K6Plc9{SMr0IQuH!I&@4(l z?_hU~)8uUHI^;U$Ij+18z9(PN9!?Z#nUT&4o%ruGZG2LH`*L`*ou!;h9Gu;0^;-#t z$8phl-5u{8qEuBcXcogoTt-dw9kf5b81HmP@I1I+8*nxi0kdsbfYmO6OZY6X3Y;n) z9wjruv^Zz1CqqzY4QC!OpMcm7BRNz9x}xSd56HiH)C#5_A1akF6$U$VGZc{LL@kS& z7j-0RL6kM3V_0jG#+@Z^K*{M7*nUT}_d&wgKzOKzY-^@I`9ur#$M~vy|H4^U@}>BP zY1{NHVlud}c`2y21qtXg-bAb(0DbMl?slF&o<#T|4)8iXqIauzwbCNcUr!}uazAp5 zAatmTPnEDa6xMjxE&~{oe%nnFZ5=%5}(PvW$I8B$(7)A zn_1Hrbm*EC10;gSc_>yoD5u4CM$iELEfI= z=nZonaPD_5c9n3G?vdyYulKtGpZ<*va?66y{JBVH(@AhySY`AMs)4+LBxM4e2^v82 zvz9MLJ*_eN6(fVJ14WsBh`+7ra4L%2Og=;3p$iyMD`^4xfTe+yyh!h5EkZwYo$&lo z1#{+%nU$+!Ozs>xu}^Y_Y&La~4sk4f-&h*_8f>U5dL5v_exuGZ9)B`};OF>0du%}b z753dwcA^{jB+%VB2Tpub<~tQ68U+Wc6Tzpi>8|Er?LBO)&0|Y}j^Mt`+`WMj4zr)A(J&JRy}n zqVG_;x^CKPX8SGEvd3EII+nZgdb)d;DyF~_bW;Zfng!aK3T5N& zP#Epv->JM&RR3Hs+}8u?_|W$Z3P0VH)#^}a?Cu6fEljVc-++GpxS&aM2i|LMgI~~_ z-Var_weZNufD+`F8wTt_XJ#OyY%1TOb_YF{jbN?!`BT?$BA} z&(7PEvnL+We_feSMqx)w?+ZRBp!O0gvruwF14`37n&gY{ylEhH0p$S86c z*_DXacdK`NtKF)-sqL*b+DoJ$pM_G zqfEC=H=yD>PJGYz<8*cvw^|q}rAh~+^3r!;Zf5W_v&DF!*7LVguK*o7*n7ZL&(XlP z0G_XhZ8`13?WZ zDeYPCp7DhoL04gGaaXwrj%9Ds^T}?;f}jmp9O$Wn$@41sK`%u#04t*=^usfNG5kc< zroN*Cv`wXUNASz+A$$|3$>U6iOf{fDenhG%iO}yEAo>NDkV~8e z|LP`Es(4?d&*(oB9J`kzg%{#0>7cyTRLZ;`?%JEgT!Mp}!Ij{{g)|{a{3fN#!%dp}NqQ{w z0=BFRe~15wTVNzxh3QBugiTL|>g#`MnxFAs2SdDtcadkBJJy-Qamya*_zXwXwZOra z3V5L1l2bneb-5YZ6J(czfIRB%g_j02kgaeUk=;2wvEFgMVt$)CODm1_*%O`E?etIj z1-$`C!#2<|t50U(ZfZu~Vg|Z>&Gpcrp-m5(^aJ`n-0-&(JxPN8NY9}&sTf*hx*%gp zXOD2>jPHhrT4s-@fG%FxJuc3XFtx`lX)}quw|CLyXS!N zTRUiw)L!Zrd<2dLgZ{eSH|{vsZnyxPfab$hS0#5I?;77pB{a}ae@$MZC2lOA#sB2? zFq^2~MsGa~YH0(tHCk-&2as0}^v~$0Z`N5LtmBAmaw+X)hO_Hf8`Rw!f(1~HtchCh z3L=~u$Xwvo3unZ4(iyp(sfVeisWLDVXQ0wN!}Qs-!Bo+-N=}euX|ni2EGuo2RLps{ z$z?id+9q>SB7cjqlXJnpeIHorf8a~U+~oD<_SAKy+Fo1ATGB0DvaeW{W!r3|bD*2> z)eO|c8Ce7>iZz2Su)YyRJ;$8;9J3s&92UnfS4pqk*HPUV{MYyDOxWS7K!dxz0v+g= z=LA3l2*xUOpncFL(@V}g|>wk`Ug`dxrOvmY$Mha-C|z3l_>@O_9k;@lPK>M zD++%&n(Mwu{b- zuJ+y*YL{R;C^}64r*o>d^$+v4_4IL{bv<;S^&V6f_#XhPeHm4Xyij1hf(qM9qA3_n zf2ht>9I8C4P?hT2x0OxPx9RTm8S+)VTQ?{eFx3(*`k+w3{3)wmGzN#fI zJKmP&wEJ2^*DOk32mOE{!8d{0{?*=o?q#mq?pvP2-X6Z{il*%L+tqmOUhts4#b^%w zsP}YNrXll{t_VHm;fSL?R1*pGe;T6B9)dT#k4n}i;8n7TUgQ(=#nM1&khDaididaK%5rxVIBw=u4+Po-s~b^d z8E^s`Q>~z7nvNBEhnz_6z)$h!vz1X)d(Vdzi+W)|xJxR+(e1J*FyE43C?(vQxHqko7(#kU0 z(m7kpCU8QUt@*9C?EcnHHpSk^{lt4)`3#rNErI-jm;SDb>do@B_Kfsso+#g7rIk8T zYosqhKP&<3co3?_F+>_Ng%~OoJo+m1WGa?A32o;xsDM@@dy#9%RB|CIEGwuzP!2pn zJ*IeiAu1Ptm`%{aprII74Y;HCf-LqIQ^X-s5BU>L(oZIz>4~YIX|idqDbmzT{ve%| zu0dgCfK(RlmXbJ7c*|Gkmvbg=5!;I$h1#RY?POapSD{u~oM;MtWG_(njaAWK(O1KB z*}1^J)f$t%$a2h*Gn>x7V5w{QW+{>VIs0$+H|suoEcE(b`!2$Lc@ePx8&qJb;0(!u zBU2HsN8!+&*amN%Yrw&D#vZMKvt@^oMG&Za#vxOVr&FlP)K;QN>-1oxwI^$FtSguFNDl4Y#?OMiuPF0opOB zHLvr_%5Tq6R}05TTP^Fj?AqCirFixcOT5Lf{K_6?t8Q=Z=;AEv&gb3XYoh#whRl5b zOdv!H_~DYExRvVu9Pnv~)^;P_62KYw(AO&mz2Ad`3awEdDl8e)eY{;9HHvCOmB6j3 z6IGBZ0JV@o)Jm!kzB+>H4V}pUpb}Xa!m}BfBt{UdLhF})AiyfpLKu~YSUGcJ9 zQ~rt_oGd;P7m0DeS$_Zme683~tSBB6!i0%@Y5q0`Wp}O{H;-$;y=D8c$B|<$p?0B; zJki*zpTpU3T-y_vq&`x9d*8XAI9EEV+soPFtj(<>tR1YOz)CqI19`cQSLI^ZyxDS@J?f2buJ5Q|-@F_`OI^lN${6VC1j^0Ohglq40|lG}wf&J?WvuX9>}aU& zPhfH|=jl>(H)3|6Hm`NG z?U^mY-p(HFIP8?&t311*je1KN1Z>_ne`R&18Vbex*T{Ic2jA%H(61Z|MA3HiN+N+Z zm{uGUwQYsuR41<8r$pJ z_uE2kTdeME-s;URWIcot$YI~;XzjY^=DfeXUwuoI+e$5Kplt{Em0` zk^jDKV4W8LDs&~4jS-5YpVGroHW+{baDY&H=S>487DzKw%Crs-p8A1h(M?ZpOK&Q0hJ2b^{qtt|DJx z&ZDX3)O6|~{%oRRs4RT_Fj(KYs0q{~DwfviCn?=M)v_>~aRJeci`(qOEB!N|udOJ(rxuf=#o^=NUpa0-0D>0Ej4CcBR<3#{yM zW)0@ug{XRmYE6A5OT#sw7AmGSjU#$_y&1Ho?Z6mMR`U25?|HYwCAeBT=Qvi|vrs=< zXf2BOPq0q2HL>?{TmT0x&OO4@+}p)>(050f3x3LkKx3^EP^u51?R^obgEZhO+5!_a zgeZVFdX4p67;jz)ZXHj_gXDI&pPWa|vJ&3O?UAQGM34Cp`m-DVkEQ+sgz9+8PBo3D{grKz?YM2Mt$_Wd{i0*Ov#G0sdl_oJxxBfs?)yRywV^r#y;CuGJGdQ) z>#0EBlmJrn2=N=3=2OU5bKvBjMa_h=?|0mbjI14dOM1Lt6C*6FpvshgG z4;o?L`6+xT|AyQI9_kuX=u313X76fu)h`~cW{#`Jr)zpdy zYN%h8INuoW6weWNx+}sJ@7(A}u>ZAPv>mbSw(Ybvu-9_TbCw5Z=%jmxX9VuuuY5}t z3zVQ7fyMA!IEiXvB2XkFfdF^`Ex9tN=O2ZVUo~n5^vw!T8t}(w!K<&2d)H!gw<`l{ z9E%$FA7B6;qRx{)*nyZghrULahcb86ys#>H#>%PF)NrsOcuK0uW*Kp#QfL8 z>aPdZLO$Rjcfir&JX{dItBL*<%4pw8Z+A~UcR|-7=P^XQe{)~m*2p&1cFcCzzQA$P zIo? pcIG-0=?c#VTFk9J~U2iZ-aI`1KP&%M<`!;5XjBC{!MNqMwelBGqvC$HHC}d zzwteVDBQIUh|k5I;zDs6Zd{6(3T3;-(nQIQ5h#gl{TVOtHn?K#=i<5kTsiItyPD0z zo`K&}f4U%jfjUdIqfFFd@*^+{*MJeJs1FPF(t3gKHOhZeS?*f_AHH4g`>s9C*N(6D za`u_FrM6UCQ~M!A`x4H#U{?)tGoHVmliowVmC6>sgbu@dZ4y}I1%U3b0ZZ}>GuaSp zn*{57J3Oae!7Jhhb&q1O?iP~!Fe-g8?-g-#IR)fG$qeL@OB_TCXU(=h3b$cYn#GQxeV{rtR} zOM^mfPn>w?*iNXG)&&RTBC2fT=_q&2|z!fm@%0V%%6;uiQK}tE~@i)F)%d zk08)_K?dVNRx0zcWrLSQN>K;arY2A) zpNR56dGw}&R9{+!rb1psuFAN%t>I$@3hO&fw4e^r1<@{t6om>yK>UqZZxyd%ExdpV zw~gP3yV^T$D%T2_kN{L^I^v{n2cOh(^bcx2Rf9T$O3!JG_bXtlYT~57t0f1_fl9c& z(aKBcNfz=HcK35ta&AM#unU~!YTC=%X?v1=qNAqsEc8`#yA#|m;5*pEw_i#1KgVfz zODhLe)PG2rP4FlgMb1I|GEv(y7>@gE1p42_nG~iDqTU8>G4JB%3!jD2;&(9u@7xkhp9Rt`X_6Et zwa3msBx=GhVZSg7{(X(nIdgDZP;1_SHUA%~jvDq*SDK?YQ9L*oP2tj!gJ^-f3YvHbRW0cWx)f)mbFAa9UAAAg&9_aqy|l^p@AfH=LOWy=^*jZvO`2ZPP9_j#2tv0y5)Q3jwaC#5@7rG%8;SI48`#lfN zx!mMj)Rsr!PdT9GQjrlgLi7tooXkaCplZ^$vFFbr%X`Oe<(lv&;kHl#TwSj?5?O4l zR2yepRjCHfy~?i{pH zBal%&joZ2_SSMIjs}U#+ozMhv!26@dEVk%;J7*!N^F*6uAqu}`aoIVd#@On^P z??~Myub}!`4*t(eu--cXE9FB4ZaFY>Z-IeZh~7m7oRB@Bf>saOox>3851?96g)c0` z3(?{Rk&xy|$E8Qof6_kbvt&b_dmPFbwWJJjGVbb|1S{W)f5O$^zTk`xWp^;Sm>2X& z+E2|!7Ci)dPpfgxoi=J4ufdZ!0ES;9tr8Rh6vggycprHJ?qrwCna^3#amZfDe%IF0 zmJAK%ceauCk@mihI?mxP*1g^x4Q}69h4%MUcLh?whqUN_fezk|2zQWrNY#N;+I`f< z-@xayB<_v};L!3Mu|Anx4tCEqbTK-hE|h@V{ZrsOI|7Bf9=G0R_>)fTBIi*zp=;3| z-bb6*2Ixdx;BO1%Fyp!Krv2r$@??3m+yRv+ANXxku;LwHT$=ITWrgj$i|fsuWxKK& z%v3mP#G=-|2K9kGWHIOj6$E;|J9hbXy*etxM6i!`Ij~Dz;Gdz)^DXvH@T_xx0h4!$ ztRc4Xw&wORc0Zg*VW;gX?cVMg?hREEz`-3IIIH!7cS{v8bbjKQZ$nkB z9OgMUGlkKBe<;rWfga8vpds?o)u~Hl4e;sbqvIWddh1oJx-cj~f7XA3D-@0Y9t+le z2wckG^Tl*yZ{T!OxljB-p*nPGCZo>!OeRg?rnaV{Cen0No-Lc@SJH6w12*HlKP40q z`tX;yG~_i;m^{oeIvt$0TDULOAx{94J>7T!#m{rW?ohPbr`3ZFDii3U7V`%&-w!+= z-5$7vra68>4JF1t%4W5CtxatwZFTMO_6?3X&H=6o?sx8j-u1qCCDXr4T?q%Mw!p4N z0DG5@UW{ncjCsPmMoxAMPd=Vqgsl1+Gl>!5fO`%uJBy*{Fc)|F+d%Y9#EmBld@R3S z+Gq|`!eb!&qjA&gOLe64L65m2_lVoWj}*out~HdtO3UH6n-5i~>85zoMpJInZuzF% z9(P$4XC94{of5k7C%By4T67$IP#;-}x_tq15YXoRFuLva+tAl$f~zsl*=j*`t^crc z*>}Tx(!+a7x`(+6I14$B+j)C$+h(iTR@dgUb+B9P#hi^?kKBIu3D0}z<5%%-@ppwj za4zV*4j=}gu5_5*0yg(bsKPvBWVQfX9BeywKVPC|RRG+O%ivEf z0ZQ|yo&-OsCb<8M2l{g#?t3H^j_TcAu!p0O#cziOK_$^Cj+J!jyZlRzLQiX`X}_rn z-hQdPSk5EQmLB7r_amFVfPCgSSCCu4?qlB3`REzc4cyqg=)v68OF~z-Ec8h8Y4roM z)YIUE|M6Axp7lI-$GDF=CpjV=W$kNhx2-j;lJ$c1v$Z;6`ceBB=S^oeyoLLFfA|#T zsCp+bEBITFB3hG0Q8_%r)MN#=C(hla+yKrDWMwGUn$9jkzrGnzSwY-i?vT%rwLJm8 zwlF*md%+EG57faoLy_#JUIRS1rl_+&g(mArcoLe}>ufByfUhh>h$El?ZIj~U5~fO~ zg{BVBBkpE0(DP~|3-Sbs!;Q6z_yy~GFtYcq+&K6Mf}@Gb@_XEn;(!T`Hu{5|UpF{I zn+MgQfPb%lk8<2M*SpIT;|JKA5UV_h!1X9I9|H_+*@1U&RA> zUz4c?>gr!iMa=cgis`(mg6WBzUp|2yJyHB11c4ZP#C7Htv$vV|7~hH1QL-f2204lY z`Wjz?^`K__Bp^dYe2~AIvc^{q>ghS%qN}v?vwf58nsrh3BTIy3N7f+p#`?ga*I}J$ z&vg88K5(7zZ1*kz{-J6hLF=nmAmjb{|3UtQK@G%(@z^tyk3N>khp)urM2m1bDe9^jBsfyN{dB z&jA~LwOC8KD=m=ya({I5WOFOC6@2OLrn07Z`8sarD^YFjFI?p#_yh3RYzP0e`Seft zIF%=BgEfVk0Thl|D8}qT7uW3%^WXKo@=o;d?z_&Zj(F4{QnKG#R%dZpgEPNo8OHj zO5 za!dHy=(mr-4a6oMl|(oOACya(;!J6#tENV#jj|IFt&X@Cm8YTnVQw^PtAE%&KvUkP zHL5l>9Qwk)a5go80^5(^l;AS$V?a^stEtLD-+fOx_Z+9k{=qiT%4Ao{I+0l>^Kgcg z5uPzM^F^j5YaP6@pV#0O19<|k{HK(%zLAK`lbov^pKPRcr)5WG-OQF5b%1Ck z((h*kGe2a#wEhOZIUg#Ey_FsQLt2b}06d!^w1=^@0CQ@tZ7t~_1#W$!loJAetppaiMP*L+T7R2R7 zxZQ|k6`&@nLO=I0Jk+iQhiN?n)l`cT^!9-V)kB=O!?SN>-O0F-J}GV2UoQ2=-|}e- zGrDBn%6@HY<8Gi_RO?)=-TbVu2Tt+8D2fv;Mvi~75 z4cT}q{29kGVVK(+LT)h;_=-fSt~?kySCUN2v!t2m8`P6nu>r=oH5|&@v(K1&@VV)Q zUc?h9EN#N+YryNwjB{uW(0rTJjf&2M8|ml z&_4%P1g{5&26F{tgInRE5rDU7f||>p-`l}8+rG+H%DOu%HNAdnv%kGk_NMgzdo*oy zrWJ2G(A`W0Lz0O_74j7SMLaA&6PL3espg~`$fhZQt7>cH8_)bNl`YCxe+4*QwAMIi zDi>njac{(l@;XzbnGYFi-YBmUFYpVw*-SXCK@*8bW;w;k05AU+o{0<|My2&Lv4axX zGJHuv7klBRG!uKYzf?txN4@Z)uuf=!NR@!TN0?|4A_R#a0AH~hY#Fv5a+&s6_pwX~ zdIvBNK19B{K}O366xA+jx3!CbALs!%z3ttx4vRHk)|a$HDHHz4Ni%;9`+e)r+0;3i zvTckfG0=>9%{>=C$SqBMO|9jY(mZ|xofj^aGqpviEaX;#o__A-pN4s4^#66 zKS2q$i+sb>!h9ukT!bmIa(KRwR#H2D7RG)!HOE*NjD{9LGiYEqgTtX!;SN?dnvip8 zC!@2w_-Eo|`G@I(ISY>CJ|RVDEEW}jm*noU*eTowcm|Ms2jniFaU0BHKe3nDns6)W zh2Gvuwmnmv{zS$QiHN-iH3fOoQ{@M;{PRAiXT9@`{h{rw)nqA|mM7&!(t+Qzex3T$ zDs@lRcWb1(sMeiaBP2TmC50x2(&i^pL%s={iyjG%*=OKX*`N~GpiS2j;eGejNF`d4 zJL&D*dEvTflOD>6@&M#WqP$ZqC+tBs7=n7X36@v0zDm{-;>FLb9#s89UJN(EU z=jL*m+<0ybJBQ)v>117FG1Qh?1RnTbC_dj--%`&h*9OOW`$gNI?1x#&=`+*h)XbDC z$tRN=r54I;lpS=azMn=RcD4{>js!1YnbbiHa5_;YcuTG3U+-z`iUIQSj^`fE+hfWs zI9F^9O5|Q(rVmINA;rV%M~sN96sd((44Ea*5l%5L$i7Cm;72G>jn+QH+j4NQ1~_RX zkbDZxmPBc1$I=Q&__2vj4 z(6@?0WpfZapXoqXp!SkuP|-bNG}X^&X9HIClz*X8%e%p~*0J2y#M;A>l^K_DB6VGg z^UwA_ZBuHela{SE%{ka#hA7HcHEE{LauO=amBkzEG-8W3(_h)w!d=LH0$8weu1I$~ z?`CD7+ADaCuu?%X?kILE>96p3weajSfx$bLX1L{rki5_))8WbbYZNR zE|x?-%!_ue0eb{KE;{OGJHUpj4Tknk;Cgx()q_0)9L|RRAB~MR?Ow(6^VPBDl(b;$d6zDX##Af17 ze2pxDsGFPUOZupKOmnWZP)dwMReq}c#Iz0BeRXM(@B+2i_vk<+vxnFyZWh;yZz~KG zC*fW6+{5bKeki-|}%W?`6MHc}^a&54lmLo7wedf0-$;wV8RLSdo^`%lL^nsw7bg+_ZtZtQA%}pbquUx5j(j+r^X9nPqEi zO|sO^D3V$yC3jM>#QeXv{{5BJ#9Ga@EwGgKOTR+PM)VI$m-~ndxqjrzfXy@6;kHKE z{&Nfkj_9xNhu=`k2hSQ#^v_mNdl?VMNDlMr@QdNC!sxK4VP!)Sg#YNj@cfv7p8go< z<+arV1j9(c1K;DH3jG9@UxIr3f4C)Nb54G+_({x(id!z}u5bX=)t+pCPN2I$sXUea z29?yuaPPSwpOgNg)0l_DS@I9hjb6qu)U{fo(-J~nFjVc8I>TSym(!KY*3&x2>dC%j z>6#UqSv2j@--~~#)L*IhGFa;xM~G)vpcV5)u!;{v4{BV+_?GlyW1@e!+wW-Pyp3Dj zA$PjBmH&639$Z1bP^GBR^d)vMKSby$tuW0u7cy51kwd?js*4-B)2y9B7Jy9YX)qF* zKm_VcxuErPjyum?g-hm8IJ49N`dQ_>OD*K)au-u~^JDW)(@k*Zbk>R+|7Ksm|YyNarM1SGVFW z>1(S#hmZ0Q_>4TIo3q8?Q=cNYGOskZHrChAMRu~# zU+e=kS9vLsTMhn}g(j%h@F=f`TI@h>pmfOe7`27rsH&WiUQ5s9-O^_`7i|&GNqxlq zd<$+P!_iCWeauz5IvI`1-F0-KC!-HtfHg1ZT5oUdPbZG@LHLL+Lx(ztu!c#~3FV<{x#NxVr%Q##>O7xE5#iID zMA)DQFqS+??FZ|lx7gpj9*oI6=Gvh}LaIt;ZVT-;)@r)~Gqi|cL45}CgVxyde1EB( zd`z@)BXE})Mn6Jl=?gO1k8~M+g1AshlXIICsXGu{cjQp%Bl6%iP{=!i1}lDF<}+=oy--i>#ye<>ni4Gc>a-GnKN3d(-282>@&D0h@kqQhHF^oXHiVSyCt;|7012tre95ocjefN`>& zY6qlaUv!!RV1v(tzLHGjFzni1zZG}OOy_w=hV4{#-mIk=`!gz}pGwV>_Bef1W@6?D z>s9v&^&)&PelQD}8Q=*7*)%d!UE>{%-oOKQ1@{&ATIlsAs-N@;KV+71^SK{f zcj1SiK`*NS?$nD>N%6Dy=t9uKuLZ>667==I&?5Vmt-${V-uVi;v7Z>3PKMt67iu-_ zglFwlZj-nO6~N6vKRe|e@@cHhbHZ@`Dc?zWh^#yTIr(8G4(_VQ=o#cND95fr*VKeQ zS}l0*I^bmRK+CJ-fOhXvcLm2j%eIVM=_}JV{B50bAo+VrNb0lnaBCg+Pj$bM%$(pj zo)VgfpSjM4TiNL?=Ben6bG(Er@ox7$WpVHYageME?d(NNe&~{QVDGcVkTqUF2W~cW z>Y57;xZTVgIu35$PSgmek!IRP$FNtqE5b@3UMCBa*!px;sxTbUq2yt7CYLbP;RU?1WG5CGtAziWk9@ z-eb+N<;(nagawy#<34DKk5pJ2CJ7Qhc-MKsieVMADqpk$3_CB~K+sT1cIeH1R6^Jh@dqgnHFQIAIM!3NG zQPGS7!|OGw9*f8!bbYoiG>kQ{kh`JJ@`=rhdv!1B7j%HuAf`0H?YooMUS4kcYfcEs zYu+Lq2mUHfqQ%+#Jgzl6g&E6uamy}Bs=$Iwg5t$8;yk&Vil%=9iQ1MbWGsP8&j;^t z_gVWf%eaimsiqVoS^ArvnwGjhy|~rl^!wxWhg1wQ*;P1yFEAa+a$0X6>q>-f=>zm^ zemQq}pQyZ{QDIOP>ND;H6bHMokKp21liG?};uex- zpMWj>Q1HV8d8D|FZ^I2@mXobfsrX4$$35c|CyS-PMR;JYADSI<0^VtF(Upi0JM(T} zrkVhiUm6uNKiwGKx*N%s1ZOz)2G9Z9Z3Kzwq^3X7{%A7;3zRReK8{Y-cNw`;ho+25 zY5liu>V%Bzmc@=TK8LoQ+(GG7A@s?PQ3s8RffK$ocYgOi*9dnx&oXb4GCfdGZ$cEN zmLU?P0v|Vp{)JH(4pqNv%ucQt_P&d|#*PI`cOLqTHsIR9ZX$vNeYV3h>fs$%{M3W=VWLphuZOexA4}UAB3TegC<;<* z+;FL$bUf7rYK8mB3EF4hD|ednuVbZi6ndz&ys!KZg2f0P@3o08j2KXdw$Oio_1MO& zW*>0(`5Sycem2(J9UhD=IvJUhgj8TndW4`Sr{c>L{wX9{M_C z=1%jO!f|l`x+nAHslY-lMpde>Xcv-%4#HDDi7$v-MPv3GFfc)Iz?wsY(<~ijS2kmO>&pBpUW<1nU-<4-V9q8@Y|Vx&w-SMKlRM zweMX!9L=qRGW({*q%BNenf^9oy5*aFuIISA622A1flKTRynJOiohDBaoe7WBUUN`1vod{v&| zr*J)3foTi9@@cdLb?^45eUyeaUoRp~kI`PM{h_HC3V&w8^WNFS`Ja7m_M}WDqjhGL z%+r}|v-3OGdvs-WU=4f|%fUC|kTEbY)E5Dt(LL@??rZLTs4HIfH`YmXB2}UdP#1Zr z^HgzWJ-rCHv+GPOw;lb+AFLgi(7Lpb9!9l;lKNfp9GrC1`Mu&q(ZG`rlOBi@__AO> zB>-X3g1OCJXzybbPbOg3~BE4&%0$d(Qyi02LU`05E_>5jeY3dXZ@m=7P*cje}ui4)~RLGo< z89@IBlu=_!CW``_mq5ib`H<~5M@J$NXoJVV7d7Yava6Xb%z8E&XC@ED+fk^V?U2Le zD9I3-2(S2DLJy&+aEt%N_Z3urJ#XThaCI4)T8%SoDRRc@!6w=JK8a#{I}yo}r)rKf2xn%&H=0{66KDZS2x}?;yP>O#}szqKF_Ohz(Rgq$nT)qM#s% zpoof66;J^Y6%hp$DbjmWdhf8k+;+a6e=q0{*tat~ylzMXPw)UBSkKE3(!&BxQL=H3WB6zv>qW8cKb zKF29*H;+DEke}Nl&!0b;?DXoPtjOlrW;;VWY3$Q~!U|0#!hWIFS}#V9(hlPgo~}Uf zqriuO4uNLq(i*<)#6=f2&Y2VaPX+b`Zzp6C=luk8%oTwi{toy{-tdj{eH3WH`Ngax z4@_Q#UZ2jcrJ492dgI&NjL)Q=-y}9<7yj0z<^=NCnrr>tB~&tV6C6m#;HxzU>=N%vDmatBA}>2gd<$AQH)yzIOAZPOm5ii&EPmFnH3Gz{YWgWjkpn<;#(I@NRn^8W~f63Po*v|yh5)Lt+ z))OYM()TRusdcHJ@HP=Hb%|TgOt_giH0i6Pqr~z)kl2w}mi>79caksF+dNBr#c{Gi zpGTv#Adc20R`Y%9VRp=Ug}mWn5iMLe^iIL^`SWrc=KP)g1kvd`GB0E;$QhTnFaO`r zu5jzfPxzu9u@}TPMkYrhkztW;;k{J%tsNd685VoZZsH7g-ggV@b&UIrvt*OJL0o-l z^OiZrH^rAu{f{5$fqB?f+leGUpgf`o3M!NfeA!fPVyh}oy80C zEMC@yfvn)FgjR_w6I-#%?ApZoi9-{52Q&Pqd{6p5CI0MLR*&x@kL0TJ1|IBG`%UW; zDmuSl6|s`7ZLzAc`=Sp<+J>g*HOp<9Q$D+F=GBZrS~oMt+VAveuEix7993?X`x~I$Nx@*SqVBh`+2tbjo7i14PZw^Is(U z`B>nI!2SMRXt0~U^+bsN=6edSz+Cd&o=BL_DCtdp-d_U{ z9q%449y*l&YhGUNq?}pVYqL-1bYQRUjDmLIUn1-r!k)C_iNX9K)}36UQIVF^v|hwY zW=pF*apZ^HEau7Ui3$D<4Yk*(XFiQ>n?%ixe|&3*O}L*p*S7x7{(k<){O@A_z86@E zFQ-j#OmIrDOR#ouSKuY$CjRwrVJ#`O;9!1F>h%xE>y|em?^E`a zs2)1T_@B*Q%#~v;W9QlZcyBb1+Uw1zZ@xM@GB(8O#9a3#nTeZ-4@f0mt>^c-j#-7;pmZg7*fae7h0YM|5X3?4%HO zeQhd_ydPK+_?NopHv*FaB?5!}%aJRmiE?$Q&$!QR$y)jWe0j~BEc*$2wDlW&HjW&- z7?q^Ug(t9o&&vgu^7~MsK9yL4arsjVR)oq^?L05soSMz8V>!{2RK9+eTFD>9wv(^6 zKlYdPyS>bQle~`h#C%L8?{%AgFR`xAny5(;uL?NrgKGNwX>)>-jG%4Vu3v3g1-09@V`LR$xh#EzKHpO zshJ&&zWPXN+NBsdXJgOB?v6EyRgZ0qcEMZPm&)fg!@Wb@i0yiXOu7~MX2FDl z3k83L+;Gw8%VeW`A8kUd=MFK0Y9d>xKR*?({3i77TlUlBD@-LSO{$!2CaTRLbM&?` zo>4Lz4`+h^vhTX@qHhIRGS3i4KgTy1?i=La$qcq{;1eo+cMZH47!t_!kCXWc8Q~jP zc_|qv6S$wTG>Ckv#{OMA`y*?z<&7cwX`){TP>b;m@=fk>b#@F+aVD~>+MVMek$~@E@&BA7djUz!fv*=!m}bbBO$7O7iO2RBhi}dknjvOL?&5f z?AKZQE5x2rFFD((%KRd0fN4}9c}cHgT*e+Xd~JzeYQ{J*fMz?k>o?3f=K7W)?Ixg? zlA!&#z|}Ic^oz)~@YL{v@MNmeCx%;u2ZjfS+l9x3M~1%-$HGsu zYr=bx?8v-mbt=ZMh#Axxi&;adVEz&7jwPvt{VO|id_t_`+gcC3K(9u|o6H#3GsErd z8|3SPA7Qp{o9`$P-bJQfbM((B{}{4vn_v@+_PqMW74vIbyZ4hk|4Msze2GI|R40fXvVx`$puqIfvaHcsIoo9%WtxVm! zHP{8yi4(3sl;RR&1#^Zz=1gJ;tHM`DeI;Ad^ zkC58eeDlHKM`rp}%oug&N0D6-rA}N`{bwrqO>{N)WA+=LW4B|Z+!LvWJUbP+57{<0`g!!9Xzf_nSR>>^i`b~xFEK0Dor-XdHJx~$ zX~gg~Be$a%vC6yIb@4MI^_vrOc*IB|0-z<;R7RU0n=8r4`-k~LHR`{Nq2k8pM9YPJ zL8`U4q6$Z2eBvJ9|xc0zAY}=F<&8H5g)4r*uxclcN6KEYi>1vHJ6#A$hOWR-uXj%pbHWHzu`0Ps3+-b znE&2jwW_BZa%Qsg>;Zc`F^M5-J-atFwu-XH#1ZxlnI4<$?UOJN>H1`BNNj5CgV@B_ zTa1G(v0br$VgaiwbDfLU-8S{QygoS0ju#!MD49Xr@mwum>rU17RNDRun`UKd+__}+LkFuKl zjW$#?Or{Padni&hbFurJTh848Q) zlXZ+vWUfykns^_zF-)^0e9_jt&unOxHiPT}ca+)Or)0*?q?-P8X#NHHVl%+L8^Sf|_44aDWsy>uK=rr1)}Ciiq{`t_ zb`SeuyD!+iZcninlFM__j^TOl%zm+-QBnUo(NL9<*8Rvz{+wE!X*1KWve@tG}5vmH5WX-Y@-rufds!~6L>UWKedPaRRn46NxTh1topRq7e$|uPF z`hz_7xAZ5-n2C`C^$XF3gPD~#rlzDrM$KRDS5&lmk~*>hymRY_%o^;pCE_rdJjHxF z)3)qlPJQ4U;!GwA@f&skSmUgsTFwfpaV&9GBFl~u#g*(fAR_o}GV-=jk29aDsg=n_ zyqB5~uTU9b1v>8^=98LUmT0ur)cx;GMBiBUwSS+e)`@&3>!b8%^hb&2Zm&OpwbzZf z^5^x@!2LRZA0*!;Mil>-vg8rIF?cP_2%pMEo zUy_Tkh1~|WvfIFq>~k=d%B%Mh&#F_6ID<;9*+gzfsDPVKcFQ>`luEVMx4~qXI~e`? z3VsW!ksNrcwOh}vOP*_c^4JHHQ@R40AA{;=$cQ|EPkRIPTV+>*?VKq< zL)V3mq>}&he0oqVyCr>J3;$d-@T*6a)7C(AANO=1TeuUSN2nFrAFK!P#8XJJ)?WQl z4NZKG5qln8c^m2^knKTddUw8u zvtT4N5-MduS>Z&X>?v^D2KR5EAOC_E4+H6WsF2C^8$fUz%(rr7BmMX%f2DW#LJ>K3 z^L-cC?cmH2?mR=k<-#QzaAJmY2)t2xhjeD32-AByJ(0}e=ZZ^jg}73{UkyA8Q&*%c z{8f>jP3C$&?>kN_(*9QHe;jzydBWyy2g+mu{~5SuA8>Eu*zrG{C%tqCYV7r{Yz9B! z!j054-preJf%6fbJHgZEd8Zr~;ED5hdgv0AyG~1)^hyrUMW`XIL1iEGE((N|7)7<1 zaW_CFHQ;DS=FMH4sg7hS2genr{(l1fqkh;EkzNv~X;npxomfGL{a}qsQps6MT;G{V?bDf#E^E9r3OyY|im!IWBm-oIzWPwnc!e z6wnFm)u^Og19)p8OX~u8eGiAm{JzUOBfAQSq?J3Wb7ysLtQCg~15iPO+d|$U{hCX^ z=0K_2Kz<3hPje{FmT{56l`N09Zvf9(pcnX$dz^n2Y=s*IYvKD7;H5B$%bOfHMz~2s z+B^JJJfFl^C<&KTqZV{kek%wCC)pXK37LOwJ*oCESu)+p2YU#;cOUYvDZSMY3`K(o z-m1UK^R6QFt8i2d`4IKwvfw3HWdPqTAe7Gy@3;o6(o=Fs6@PWdZI4@oUlgYoK%X%0 ziUGfRt9-LPKGLCLGB^}RI#qyUs(Q4Reo#Fj7_u&8)c+dd2m=jpne?SDS$h2=%0)`d>*~S z<&;8TeEOibP+s7V@Y_Wa1>x+%jDcc&(%=UK_lR|k5l4Hz{6qZ&k?RsfgMP^*Y{q}~}x zN%WZ<2^{h_=t&#HgIPF6cm-D|he*j}56(0X_M*UE*gMiZsTx09j5bQrQW-{x=(s9y zRvmC^M1P33Y=^d#<35hI-v18(ZCBv$Nxoq}^z1We&OZFtowLGot-!o7JSQ@uK3caf zM?DVd={n$6nRd$2W?|q9dK6dkUH4>-?D3EYy%m)U@l9bXvLpprqW%-S<&b+5_)RG^ z?~rfmyWpM%&VpMx+EgP&MzxF|89j2yh?ntGA9xi9wgF4QRpHy39&N@IIT}L~IT~=k z>{L+-3=%zgr^b+QI&LnwrofX9S&S6X>Ngopa)@S^9ROrZ$i0|n-YA!T`|n5h`cQgN zcu}aKFp}O(f$Ivx57K8PIEr%!SIU2arAWD&(6}D>h;$R`%TXJAt8lFvzpH?K73fik z@lpmHO7Oly;2~OzFdq*P8{W_JMu@;IV_qb*`YVz^*(&l)zF$ReT;?N3T)N%%MpqW^ z5Unc~jp!8hO|-CR7wZoG25l>Dj_V86r*cm8M;z-o_XW;^ACquByvSG>TXZtZ^zQyg$6pr zRk3Bx@tY3jfJgPW^l1`3sSd#-k$#SkVUbe;I~z;V2id@% z=^fG!*F8K0hqHI|=zcWi4s3wGIktMgx1;;TLfOgr?VJ-U;4kmk%za|>?dRCXv4^|1 zd(X(TTd|6_OkdL3vC0(Uw5Dr8(Z#D7MNIJ zV$JU4++OfH<9jtHNp@#H|8UyFRQ1raw8-YMRVnvJ1ve$!H;UzsKR+~Vq`a=3c4x#)$ z?@0x3oNA}M_sYAEd53UroO`98PJq`rI8jL(>65q(BD=4NJ@J2KjbI}>T4rN17UOzS zWRl`Nkzq;(i1n-_fMBW)HP+*te}Nu83k0V;+KQDghy0Z>CL>H>m7YHfltOi(m^`hl zPqE$}OI4I|&n^G#{xx=8fK=potHsSdKdB3H%Y zDdWu^#HOmmGiA_t#h`%b$|Ud2#nBDrxgzfqi=q(p&^?}3ye*cxXk4)iWX_lXoC2X} z1CdJVUhjeb^ULsPr>uOjheX>JqjiC&Jcq!p+Esc+#b zYU)`Jf@4ijV^sw+p@upXeS{_z?;K+Hm8M;p^U8ctX$OHvIHEW(iQOi!#r3Al3FIio z9fdskt2ji_OW~k;LA|*o_sZ^Bvcpz&w5dQ|kKSlVUkKcH-?9GMV8OM*hP%hJ|C(|w zezg_0pxB44?pQ|+JnTd(%f2XaN{Llm^$upDodv77Wv2L{tOs=wa1%^ZfnMxTnc>9W zA+!Hd9yJ7Nd0O5tv&+h~R)ycn5|WvmqJDD^;=6&l8Ha*e!QIk>S75*A&Uu+j2+ntN zMxJQS_lBN@A@d5^6HRzfpb;oadmjaZf}#S@$dzJP9Rj_;U)bvx=_kQf?iTn3dikyX zihUy%su~Rn6R~8(rm24CkeQMCh+QYMxZ2*K<~_;+6-!k9m#cEU4j-An3OB`JmNrZ9 z5$j4gN2o1aB8SKn`6$^TV??ah|L>1@Dbzh;qx-nWE>&$6 z=4{IUaIjEDFpu|O++q_>{?FTB1MJc%=wr#+Z zJ7Ukt5vQw?k&0T1QgMn1{bi(zpvS-&Ix6NLTc74T0k%tdoAo81$T7D|GqABN%_cK;)_%5 z$Xk?uN-Phtrp1z0hqCfcdltnp&)adtvti=4sn`Kxw<@2MSQyH(JK$LlhqqVAIW#ABrFXr=Q-zl*Ibo<5=K89t)- z{{dRDeU$YjP>6Rb?w?W?sSA}E2YzL*2+nbPRInAB^gQ>7ZT){O7iDYxXV-~ECv;a>DeEo{ zp}@H3PG88pK`c6#IqHLRC-bR@et?4-z9dR^p-#`^j6lCqODl1%6byZTew|p zaPi$LpOWGy#h=3a%5D>nP5cngP5hAAi98v%#H44%GE=iVvGs%-RbR(vI5LV<4~sue z`d!&}%B~jsPT6=uW#JQb2*u-XkQt+zH;9K!?5emGCDxppK`Vch*jO@FWba=YTVi9$ z+(^wYB*vyXdd#O{)rt#Fa{JMzEpSCUiNYszz=U=Yh!*|@4jX;ZtOGoSl@j{5+{ZHr1y~=`=`$R8` z?Gm?!#R8D~;~HA*2;~7$I#D#BXw&~7P*!6(PeTd>%EE|SM9N-KoDl#MTkI zNIT`ZBW}SdyIS5O{iXUsQD510a$fvR%CjuCy0X*beI9RBo+(W$Vs$I{R7-MR?v=NR z%_Tfml5+y5n)@ibM_QJnviE*v1F8O1wykPMEMvtLa!oK-P^%e{_{tOnWqG@@v&F|M ze5-6c;T*+FGAmH_nOITko0?lH9#gXku?uC~%IFmMRvsP-T$u3-O3{_^b+{QJFV6lWpzvWO5)y7)wVnl zw|&JPRx4Qr$X!{F6HTM^f~?Zz-I4WTl?tRXqt55fbo9m*G|5@dHWB?I9s*f0&E~pD zW@%ITUu9iU^qjm+`QAitD1V1|1mzG9k9bDnUfVp*h@Q-%Jvl2Dv8+|!pe6BI$cm-- zQbgZ~k2jOn)e4&IESkj?p`OdrH-S>wn6g?b>$hSji#JbN5Z{LAMtMrsAVgEAbM~V5 zjA;6^T#c``2+m?@UH00LHA7j4%0_oz^=KiQ_KF9!=q}OdN`p%c$$YR7OI&(A$}?AK zLA;%^3V4dQsx@4}S#0L(yyrg;>2dVC?C~I&iI zLgAz<{El0MCwb;1|4A^cez98jf%ipPjX?1Ty?GWZ@K@IT z*I~b&04@zVA=)Q}Dr1+yOL_YaL(l7QhK$!dAP~I7`zb56XTUVVb24`fgNKX{;dPm7 z$$UpvvBg$B&$ke3RLP9OBu25U4_^l-v1g@!WduZBS$|fm(gmEmNJ}TUp3VD3&x_AT zXWjWc6xzai@eUxozLw@D`c(#O>GXwBtkWiswvb`?AU=xCMB!Dw@73a0%U&JTbtfFmEag zMmpzh_UujJdujAdIq#fE5akb4veM*v+5fj5{+9cIybgDk;4K<49`Th(8Oce|PFB@w za<6z&l7aLxxSRzip{$`K!Ez$-J>5wvX~C$qHFD z@YL8zK99JS%Fy;+vgEq3X4?Sz{ex$pNOT}7&Qo`JezAJIPbe?iL;Sg=u$k^9hV%he z6kDUsh1#k7Ek{cwz`iziOagT{kJ5vsSwHQ|ifUI@S|5XcrM+F4chMWwxgsmAU3o_t z-XNaYT>2>rhtvh00j$Y(f!=k&Ck$ttfQv#zWl9y5&p{+y;RRqFj@LL6XGXR%}7s3M1+IaVBaZaL~vccTX zowaFCW+P&k6yd2MR2W`Ht>uRqH6`eUY(~{T^k)(7P4XhAuJNP^o|S;&VdCar(_SSK z@=1E53B7z7+DYupenw@?t;6}Dtclm>O?hy$%-8ejQ-Qt<>&yM2Qc3o_K2FcE13Hw< zhWdXa0c4hc5eS+cZ{7HP`R3f~x*c-eHxYYD~pB0dX=egSi-@-s6YcB zIG*Uji?lDZibB9y0M#Yxbv`|p%Ky~MA$D>-b;)}J+XHZHA{y)jv3+mSL)Y0$_-FP$ ze+LRL0=v0HH@-%V+Ru?uVyg*XU-9HYglBd^+bnpu8uG0l{d1e$7M}s?AGk9WNH+rA z7-AzQvRmjDsQolO-xr#sYMb1l?l@L;uhG-8E5aMZO@6~0C1&g#cFi$*Xdn@jjc7f? zZAtv@M0RQ)0jF-|zAfCj7d$5uOSzfeKL_-GL4|to?Rg-6!F`H0SFq}O(XF9P1*4a= z{p3uygQj!Yd803QU-Y8Nz9as1E8KeyZcu*6UxD>S_NUn7wuNV2LW|{r=eI=p)?+`6 z&W!c3@M=-=9#;_OISv@Bfb%A|5Tp7YPv=!b7VUD`eUs?V6}-6^T-1Y+*93~JrXJo6 zVp^YrlHHL&v$;~AD+YT*wjjoJ2ApvPN@u|D55l!o$jD>MP`4D}45o$iiF# zkv{ts-i{DqI~2+Jk#?9m+z-GzCi-ob`#8`(NG}Q{`g{5?NcPY)xa=!h7fCjVh}pMk zE9OyXGL=^j!&!Y8Pu19=Y8f%U8yIn7)fnit(Vh&Eh@48=3HtqGIP4p)oucUV?SlN>OI-A1C_DiDLEgKznen_Be*F{PO+%vWV*FIp z+Odnq7tS(bm{+*dwD!cJ|3NhRa5#SvQtwrF1km-Q4)<{SXEmHM&#lO_nM4Tpgaba- zj+56Lfy>VzeMQeXw0+Czg`|6zIRBq`vN}~WGvV(BaLOcFJx#7`2lj1w)XgQ9dYIdc zeEQ1ljrALx5Fo3y6g~P1^-m_!V{3_PE>2ckfB2#pyHdQbuh4qCKDa=*>lAtKt+?X{ z;-IT*?*r{3>=2PY8k%J=y1o(mum(993mND2;gu;w1^)^4ceyW+&oUb6egrM3qxWm0 znd*{zeVT9GiG==%arzkAw-s1D24t!xE^DN=X;5>AE~|Rwk5WF6+Pbp`n&~oJAl;%W&mP+FM|); zY6plJ{{URRbZ;}M-{am3=2aQH{o(44P-G*|YmD>Cn#?YDB5Ag|_Y*=f ze?dKFiHCXx^w|>RNg?cs1N2uT@&sg`)NeGCDj4r*v!MQOP<%X< zcfV#&r3baYf$<-w4Dh{y^>~V1wof7F`jaQT+_CH(&Qt71@PM92gntKWmTaLv!elB` z=c&Gox?iYYe@M?JH@S`bw$qME$Od+77PG~1&~O@-S7A7>8oDLGconbR{b=z9oPQ7) zyD-WMqpSLB$DphZ{WrPo;H$o9wa1aNx!QyJWoXgGt>kv%>N%=QKj*&44xWZS0lq$r zHT4#nq92lZvUZn#0U5iW??c^7>^{^4`s87`hy_#)IJQB_z2G#P^9zuA4Z(XgJy?l4 zxKFqToGDIWIO{QN+GXTN48s0QM8>vp)5sY)iXC(xeSHBfv=$w^9UJjFlz9UkAlMGl zE}~n0M60~*)`mY)w0yFBno{egp*{_n^)^q;LL04R_a{F)pOn?-YrnfSsHFENc{zQZ zlTK%?DZ4nX#R?xtdt=<{NVEr$gZClDU3Ve5HN&(yaLsbG% zLqDiZcaM`NGmzcmvz>R`;Z%$Mnhd>3`U~tWo#_l>NBY?gHNTGAhe!5xt`k(r!D`$zMuf+!s*S;Rs{r55`D6D$mYv zK1F*x#!hj~^e$LAvftE9+Ngqt*bCjhamzEZThLnz7-3@VH^)AB7s#eDE@v`dIVn9u zPtS9IM@F4yME1tse9Zlv9ks>YYQ>Hnlgap*r0qeT*K{k=Kg)r48#*C|g>f%d;GfKh z#OE`R{hKbp-(oqI$4+>M(K^k2n#$G>xg*hc+34ZB;iUD*wHLLYpmu-8R~DSu38+pX z0VXmYv#}{I(vM^C!t{aqRj}jMush;sWc3V08tz2`e?|t5#)xvEZXw3)6IyAiu5{5# z!yOB-N-EITt9g0^bC9OU&5LN|Li*2)tv|5$2O|w9vJ=M_(EB(oG^W+R>CI#AKCL!1 z=*3uH%zZPEo;TtDvPkJ}$iohBl8z1aGPgMSwCa@>}Gb5%Lp7r|9^oTd={Cx3QpG0 zqr0?{=&af3tXk|E-9qc@)`o)1+(gDiTVzFTa-t8zQ&Zre;rI>8Vhvr^67(r(;NQsu z-UbA9(JgJUrgWgbj1@2ie%t}HPiv2}FVpAjMfD~7{vB}&VQsYl`djWZz&nt)xt?y? z!$>c|41NZ0{stJ2qJb7L_AfE+dSYkgx_@i6&_T;??JNXJ1?-0cs??+68gCvGHMeNC6oSdLEq-m!)wq%o1y9_z<3*-a?7d1w+iT~ z%2>Fw!K4x6>pYg}YIgwk%>b~gh5Y*no%1H2-8}USTJam~g^tLi_E5f|cG{aCu0;y2 zM9**1lJvpaVkC4QW|niALkva>G)3FA!3J9CzE9@ZQE0mWPMd+W8pEiXiv5Enra#AB zPk{SaC^d|hYUvyCGaNvouf;MQ1&a+Or+(AN+VhN}MO5}5tG%l4WezY4+4egem&2%@<62G^bk%ystOh<^koXnY z@9cAL#EGx(Z}L-Xc{cMe@cH-5+NiO@*gD8Obq@W$o&HJ#njlh9!;V^sWU2)08l!$Y z{V)WJeh)o5oV?R*Ze8U2ZgzbA4Vv~v#^_Xzf7N-5d;Zcov0qlQUPOC^O2Q+Z4QR0( zcRrTEP&HY z`{Bj!*qOex{wjNfog#m-Dc0N@4=otcP9s0FeKQ{csRVaV40wp$9r)L$s&;e(>sg;Oc>-naq6l zK4kO)<{MKOVFMXE>}JAjwYi&xHhBrTvkuy{LZkhm6_d(VT6MPoiBW_8Z%qxGw%D^S zJ7d?QzS~4HkLMyMcQezNjOO?QD{+XsoowEk%)c6e+slm9U%}xj(p6(F)eD;~4P7a* zc8_Aw_G2`igcIHYnkn47MD|jL(u24<3v1&c&aB4c(3ZFNWz4=r8{^RdAEMdwobvF- zlk}RblDXhC3Qt6PIOZBwX&of*o6sW*J{k?ByCb0<0j8h9CYdqxDHQk^e(T1avMSpY zIoKTj*$)RSK&w3lhcAW4&oM6BF$c1c>6$i)ryGLLOr+|4JhcgFmhY}%EcL|pu8j4v z#rX-z)I+PLx6rTQ@5sSdaRGgl4vnTUujqnh`vv){57O_qq0=xdR14}Bz`q5|EsKKb zmvG2tB*9hY4@>FI>&&A}S}TbxS%rV5w%%0V0KcYCUu7uyzkk68>ltq|7;iP*vsB%? zj;?$K%k3L9cX2GY^T;5bx!OF&+SlN^0B!GMEd7F=JQUt9uKxy>|G@c0v84B-r+$Lc z&!NE&0RNA`Pznq`K*C+byRrtGSvcZq@>e;#8oHdKy`jvz8zC1nfoBCh=|fjZ z%!sUKG-6DA3TJJKl%VaHZG-MVMJLQ%BaPV2v-Q6>8VPZyn&BGxYif@VMrF!fxpY(IDyA z@eP^HPD0L=#x~xH)apeh{y%PKdbK|mzT`e9z{i7;$hq#DNV$1K0$gN;0t{q`)j%E~m29CY)8`J{MqddKlkvap(J`zrgG8&%3ZokUBqZ*dpecBcD z#Iy9;3$zi!(*75o90mnt1@t1l))pK`p#|1M*M9WDVdy*_S(oFEV(-AMj5b-l*$pQS zL9YIZ-Bycv$tia9Sb~4zE&@iMf=Ake@ocP%1pR9y(|hoLf3$2%&TZltgM507kv$DN zqYph*5sA?gymFAmlX$Bio|^$@e+uoI(b@)PU~Rcl2b<+4J9CbU5BfI3C$kq-W-cBt2q|I zGxSbnu>KH^Eyt{KDb#%gTLD=D?>&L-aS+?&Iru#Vn!SaU`!H>2NRWltRvPbk46d_~ zZ?bMLtF_7C^#o%qigvuf*{aaDBb-&65!D0foWV$wsJa_zRA00;5B#zOkaV6S7MD;fG@TnCu*>gGy=Tuf(9XYd4p#^KZsqL&)jM` zcfG)T{YTE}3uQ0O+8tpU#@FiU`{w~;sRL8CQ{q+9eRrVily$NzQx# zg(X7sJUB*x?=9vi!+~c6yWB|Lh@5YYM5xJ|GCl4Z2R@q^tJN5Jb@8Iiz`7dB9OPr5sfu0EhfyO^ zZ6tF#sSsHY2~(FgMDxlFc0U}PgcbG>GT=ILX(aD@4}1cQ%2IraL)l&Q zzzpu+;n`3RqfJD5EQf*;%Pf&3M?H?I3vF8gX)UBr0^?5NR}yGVc5;21YbD^avy86= zP#~9CMMp+!B4d3E5>$FP$8C;|or1J0O$#E6mU0|J-`0Rf8*uIr-0=-`oeBRNymJy` zq#11;#a39$o#{wOgFY$-r-t}Xa@miA&2Iim+(tgXD?`a-q<#jHDi!>ak$nb2La(i6Os#;+9s0ZsS})8qvhF7FxvDCHffXw=hlaQI(JfC zoby#_LwMWdZx!0E2gK#+NvZJgFK;ddpQYea*an;urE`%MR5c8Vy_MLE!thFMJ|;M2 z^F$)_kr>7DSR*$W0kT>v5g+AgFTfKnxCll8+Io=LVhj3FLx)N%(^cqG9qzabI#l*> z5`Rn{bGKIXM+bVTHaKL`pI3QHF(mL~aMazry*TG3vP|eG(Lc4}B*~fX4$Z22wtSE) zF|?1YLiC~+AD{(^iIJ!y3mZjzn9ZzpOU7aPws-S07q*1NZLWUX*^9sG9OX+nN^dhR3S| zMG4+4@r&hoP9kI_PNWv?hf60TAJg_#vA(1W}X{9yq zZOnDaG-~9Hb>Sn4&yn1{inP!K$nWEtRF+Zks`A!aT&W1mk{KlJ$tY=#S&*MnQ~RQU*wNOCrgB}MCGa+brp|V7L4TH>fDt~Ul#(Ssyul&a7rzOySY-5 z79|r=MvI)k9}HwIPvmQHIHWqb2zBc6c8QNxk<7JdTVis{0j1<(sT}k8@9K9TDaRWm zYFT1{g^DWrwW!zcL0XlVT@}$Pv80JWp)$TCr%6>nkc>vjX-wse#FTCBvMJD<|SH5V3%_$l2+cLGOpD7ihI4Psw{|Hk|-VFI;kch`TZ(KOENTzdUO{| zRSdRdZV4=k69uFH;&dh3DR8H4$-|NeJBh?k01kmFh3_J(@Et7`<{%GUi35NffNa;>GiRB`Q&l|6Q3Qj8>7{ z3YF6!84U7fiN932!4i2Z5tov!q~d5Ll2&qBB_3C0Wyn>@|B|RG$v#mzQxd_XvP>k( zR^s9$swrMGL{$(Gi7W4wDhW~{L85Wv*|u^{qVy!jSLKoX-zO)!p&j6^VqDCsd^8C1iCxJ4NN{tJq`7zEV%9$W_T~mpp2LQ~V?nSsSm0AT3Ho z0m;`=(Vzl}9O^CSX-i@w<2hy$rztZ%$&FFJ&)$JX;xq+A`77t-qcW}pYV|#yQ6uk^ z@9Hh`c9qF4enrcDe{(m#DRrISsE;U{R2X(i~h!S|^DFwO8 z{gLQViHTKJZ6y0#BEVE8kYszyA<<4!Jwc9mU4^6GUH{!7xnuIQk=a@ zSyz%*BoWbqso<&ZI|C);P?QqLSgXBJYz-IF;okZ7M_b|YbhR7<0W26L&cQKcvP9`DpN`QC*R|7>S8-cZj>7Tl7A?-f60xqT>Bu>`Q)NO* zhJu1EepT{MywM0G2oJ`4a(Gg1P6uG0(L_3L|P#Ibx=f%bm9VGHzavoInmz@1C zt3>76izbq%RbGk8T2fg&qRr)y|Kx8xQ%B_`OOCx{%!qE6%oe#Po=+m@#afXw@|@(w zs63gtEuks}h)p3@jH-ww8a;l9^`LU9MW3szeW^hhKPMSWqWdeOBPCBq;D}op0*}h& z5&8&T@r*2$-J>#nltm$SfE+4cTr42bykZZEZ71I(-dA$6q`sK48-x~Ohe@`OV5V}= z6r}`bd0RYxOkfhLB%TK)?-8gggGm+dyI@k;`z|?0lIJB5sBEx!rjp8&lK-TYIAzse z$>&j7M{#=pXC*3VRKEyZ0%<9zA=MbvQxcCV|Ha=cwvP0sqM5u~XeKs^JQdG_mwuM> zD#J)+A&G4zmb>~-{))|^a*tF-xWulD?V;-C2tP~Z1K~g6Y_`20Ld$q5g`08XH{;uv@N_Ze^vIP{4dqw)Sc>CRhJ`) zQ7Ge3G8Pj&dq>8lWZFwcf&3MVNainczqBEioU-o(>oi~%%TVk=v1e7K1c5kS5kuwQ ztE@_ulO!<5GcHx0m1J?MD1VhTr7B^FWYPae?x?&Wm4Pa|m zK)E983X;DidNH5B@*b&lDOp;g5A(ghqMamGMDnZIU;(L&+q70ym@ZOtV+u{ik3-B_K*P?$VcS8=LZU+BJE0WoC zi&h0w$sd!fC0QjDPl{v^NcP$_sG5f@qO!#Q!4^#CzI4v!@|5tDXj$n`$*dAfR3Lj0%K8fg9W{ zZqL#fTd&v6oAWBV36E>$lSbZ{E6zkIUdP;gmRm~77C;cGRO=bS6A=ia}Tn~C5eIrsc$a%4>Qqa

!B=$m8PurL0nE>a@Ao&ZSuL^mPh?WqD1S63#LP?PT!V{7axSx;M{Qt0OwwYC; zU-1=7hQT_#t)uYBx57g@l*qeD#vJWy-O%c~TeXtzkD5)5>O8zi^R-I`duvJbv~LB` zBySQ0z0EEDcV%`Ej&aO^phB`XIYh4?L0%2!+oq8Z^nyx zFaGH%_d6drp!u+9HftZ_|x(whJ|M&t5PHWBn1kIJh6zj+X#<6fEN7}>WBw?HBm#2 zq3JZDy1&)t^Scc_`YC;NkTsGK?i~EC!{~#H?$_v8fpH9)IJNb6y47u=LdZ<>zo~+)t7n?r@nT-KH3>TOwDy? zgSOgvOTWoF=n>*Dis`eQGI;j}X-i@3OWHPPgZsU{*ST!Jq3<$2u}ZnG8B>W~G2MYi zdu?-Um)T1@X0LaL=?nEM))=>u`8zwtkJQ)bi>c`StsBwnYXx=-J(HE~OVHBqMm5WM zhpOC--M!kq&T{Zr;RN)3Zd2mpK609{2ULzdpZzxmxxYEr@ONt3F{g%JLYwX!)4RDz zjPedTD;UmIXx@`&b>h~Vy01DX_3K(!=Wctd`7#ma4eet_7j2bOKzv&#B9^PM>ad*s z-7mV1_JcFpeTTKhqKvHt#9F@SHqdXm6P%9j0rPvSG%G5(#7u=_ea)xXH@6{u{edx@ z=-WcXH;+S)il4hA5DYe-b-uA**SEMm^xDoE@)asN=p14>US-9pn2~KyAgXk)Q^Pps z94CVBFMAKGpGo>kJLFE$4?)Av>;*=IIIeyAqrf}DDQ}dupVr13`Sx@tL%*UmvCmVL z{Q>7;#>hWJAF#C_@oLx+`c11l(C%?=+V!*<#yaP$^Okl(JM9$H_qgleyB^LmtjiR= zjAmQY*~_H5o$qAoZ)x}1_v;1k#XleCyq z-)*JW(LQ%hJ9CMIU+E-5Fl2B_JgVvDtImh+8NHEq)_TS)Wwf_H)LU!C=!sKSNnhCc%${bf)9-VJSx@XjF9qqNoYx*JkE9*&i4-ZC{>S5y^J78Bg8|o$OU)^u?$BnVE z8}4G?yUv%f;l7o|5o?bX3M6ZfMAEey!H2D%V~zZ~^}JYpyG-Deb}6z>cg-7Gzi1C_ zZLnwTYrCZ0UbFR&El2a2A368Lwi=7H$L&#usZ}!)?Nv@l|CP9)Dsa*TdpJ>%n%2&) zueUd+IF7YXU!flankK&8W-0a(o14_sZ511@kMKPhTj6f-SJS_XF1G(lyl$Ti`PuRE zkX^}YXq1KfUZYn&)V5kn^knTBeWUw<^@HBY7>{IlNnc`D*CNJa?ys@GwW+?IPO8<+ z*yh_DIbfd)6miO0gZ&${Q`SOvJN-J%`2ud~?n|`(aCQf_I}NR5ZGrE1w|CSuE1H9K zJ#;DXpfND~qVK9P!XD#P(C;=6Mv58j^$z-L?px8_3Co-xLks-_%z?3=+{2m?ToB%F z&+?n*v{(ykf8Zr!dVV<2)qg#-%dN(4vQI=BTD=nbn|1Sh>LY?D?AJrf{1=Sg)^4Ot zwpLbuF7~G{X!N((=S4Tn?_wkL>*n89De_rNqmlEjb)RYYx8`@z-%lzLJ>ar+weP{` znOIVCG403DyZXSyH$$ITN&aT$z`XIk&yt@kC>guqZ>|4gy>I;$7_FTvXd9gG?-HpJ zekS4TgzdSHM2{3%>U7I1>Z_5k%laz&SW3;5BR3QE!D&PF;hAOa9%%usUEUTqC$X<@ zQ0~9h{z6aNALM@I`y}~5Y*$_t|DLqUIS&_%Nt>SVbHNKYX|H-?i%`O!D<9SgNn`9k3fk zGW;uz8L^4(Wz*I+gdfo(?8sR$^0L-Dp{Vs&q_OW0vwI{bvLeJ( zIN!;XKKboJ!x94iFYN5dPi}*h0kIO%60sqEGgv#k4_Wnb!pQs+cCQp8wm7`fd@Zqy zGc#*kplHg6`E~Mpr5*{qo6{$nP^^qLA$_&)>EaFZ>Sg?0^yP$}`K1c#CuRq$~RxI{J zbaeLgV6&8~p^f?73Y|~xlYXJ#Sn*E2)SSB`S*bm>=kha6GiVpIihi8XE1_Gcb|fY7 z%f#*B=c8NPUsArX59O^lTlyA9YniTpf7HqA>7Si4y5K^7_2fQg_59`5!n870a!$jf zPD$_OHY-@3QY(3N*8P#MQy=`>V5(u9+#`x{n+R(CKy@aPjH$tmZ zM(YK654%tJsbzksSG2o0m7RGB^USU6Terf0ul}*K#4Y8#7A_xboR(&9%vcq^ zocvnys^~9Hw%OjWqU|GN{0E)&b`i59yEc88J;wi8FHrp1g zip~f=m-wqTCvQV!AbT@@1< zIb>WRj;W|l%%a)b*E?#tL(SLC0Zv!@Yxa8S7a3)rH`*nx3a<^%ao!1hV6=~nwwnhx z1($>d*nNXn1C64+@(Y`fCrxrn*>#Ayi&~FZnL2rqRv~{wBV;&{tM*0hno-8L)>-X* zqE`(5>zf&VJJP@?X*Aa@`)gyY+tI$Ny%u}iJ{@T4Pqh0*=4z#kS;ijyynQ{gz?~m_ zAyhe1Dfwpd`uuzIW7@O9<-UsHL2lG;=N>Wc@|CcLMZY$C`5t%v%zen+p0GV|CQ{a3 z=49zV*k-Vnf2&(1znL{Dc+GgxdeqsbKk7D&Rrj4pm}l(_Uw04boul)uO$q%IzYnbo zp9?(YUbla-@74EMn)ZCcPl54~t~rm{-y~h~x3wx+6C$gP?BuVsn)&H@XU$Nd;(B|# zi`~~a6dN5aWB+OVu9tIPPI<=nV%Esa87Z$NF3fvbn_Vavs8#S~gIFF@W$Zgfj5Y~=gy({9E-wmx?9-LrZ&bY0~P z@vpJ>IsWKEzEv`xa@Jdi+>XxQ?mqhqKiN>mJNj$({mykG#q1YLk3FvU3N|onL$$9>z!h`S#MtF7_eK zE0`B)WCjv%YBfVwj7RM*k@mjINo};}^EWy(6VHV|$vtT#CUN#ebiF1Sl?jIr?XemPGf1TnA5~`eHqbY{iOdjdu)DJ>te8#w!x_s ze9-@WxJ6!_;G5?5{KBzuX_bTD790;PFggbh+B0H#{v(XxX-0kRb$h5Y)M(>-J-ptU zs~=6e$6qHr0;}#PUH5@xp#J4G|yN1a9NVD*rD(jFhHU}Jfk`Tj{-RqOl69_zip z5q(K`kG9TiALz;sm{rZ?+EVPS!OkZA5o4WE#rE5UT|YZv4fk*M6_4JIEj3H%N306g zcflfB58E~NI2){^_9^!+|89F-^eDSaH8&<(!(y4*qt?I167#VBr1M*Nsj<*}Cve=F z7~X2w?%Tfk*4Ee_W3qYMcs3$+GpYr;>Fc1+4ySU$3NlIR*z@#1w8hRO{S)grJI*h$ z8izKPt9!<%PHtg0^AV?R^jrI(Kxh4N>uLKQ_by*!{Ue)wVvNs&C)_Tf z8rIjo_Y-fLkJ-;?Lu1pOy@8v^(A0tw&H*Clrf5wJOIx7VVm9%9w2<|J`LXY^`buWI z%0*fkubJbBlI!OC3_WXE*+eLvu?OkZ{fXKvE2IrG_C;@mE$v9)J#&=ao4L&TSW!Em zon!w$vUkj_T4}p~q>b4(p@@Dy`g-(~Uc(&eRMV?!WzC)L@@Sh_753ZfWNg&-MvvMv ztijrs{-Ju%8WCM(J!Y2o$(|pLo!&8jtgT)$X`gvE(kjAi*1yCUWHvQMYDeu6(c$`H z^MtRcu~~b?I__k;)%2(JN#xz_wqJ2Ko5^~}J%Hz=BYuMh#&O>R`sLWPXbJmyeWdY~ z&(zOYy{$i;1x{Eir8oBl^;1r&yPv&0I~$|?e`trT8rp1sz}OLMjW6XM`#XECx!c#$ zo$jO=yPV^(Cv0XOzUpLvS9B*kqpZ13JKt^n6}OP{yL*Jpg;aZjv%}bEu66#fix?fu zU+hU%3H?`XuJZ@`E#J^yVlUy6#&qJHN0Aeii_QL#J;{Dft6*F*#xVPR&0b6XVUE2o zGQ-XD{o-3_HrI~E=0vYKZ|E(JgYI=xH)}X$Vy6ADe}NIu8?j^DQ1>2lxNnrR%>G^f z-u%;^VAs~(GrG8MTi4w2My@-?C~wx%qOnKq-`FSqYqzYv!g!co{yJ9G3Ok0m(QwI| znvVzL7k!)lKKmSgqpi{3XU*>&{ha>0QwiU}XuFOnw_0=yJBix|X zUteh+)Y{se-4@snuua}|1NSsj_8J5Sqd4l@or50basz+R{M{ofj`?S|G& zCs*6ASJ2})cEA8>xNa;+=QV)Cjt5LMAo>p;duTkgE>bkHC6J>dI?3JcBjAN7BXslIW@ z?l2yRmjjO{J{0)Ych#&EC=o0ZJRflUD+9fK3w^uUm;Og~G;U<>*KMPTZ?6A@F@Xr; zS>z3mBAd)|9=G;H|BO|#qLI#_dqVxg&xY5q!|#HETe59fba;15jp{gtoRsii|MVc1RE_S5ok-{6&4y6r9TUn?} zYMnxTQc{!uPWmWuQE&%4_rA+c%D=Ne`6IV241Vj-Leio zfk=_)fY?>*yGS7a+1$Z-ujVhz>y+!u9+0^rvrqQ1j9It#-0G5Hr|Y*;Z|}Q3E&a;v z#p%T}LK&O0f6T3%_a%Fjw~6R6Cw7m!S^t=^2@fYOPfSQC7ih+Q>0gZ+JEEv^`EcRx%T4q z{x>?_c>PB5jUJReeDU@Jndh>)=Z?#*oc~y8UGxUy^)CH$<6r-@K+lA%#Q#UqRe;BB zG|>}F$7E*5alnql%*@a*Gc#kuObs(*!`xuQ9EZU%^D#3@_s{jOzKd)7eA4dD&hE~< zc~2*3Dhi0!NMfZAB&m`Z=^N=JX;bkq(M5q(7!*^Y&vZMyHTe!y>?aYcKy|l2tbKm; zAl?!n84SZXx(H9;RNVY~xD(Yki3}S^Gpi zS>w`f)^F1v)}JsuFvOe2n7vkkqqlRGTk1u9SNxU1lc8C#;w{G?65U7v)rM}*)Pe}c zQ@)p<$~QAF>D6>8y_Q-)J)|tu8bS%aT8}g%t`O(&`n+*~rk;V$CXV3^$YI1I@(Q(w z+RXG5R0=IZyJ({1w2Y8VlGsHTC55tG@`tijl2-yPO@LD^flwe_ShIhrf0b{K zm+=H(!Cz_5*JMtm1fJ~$k=@qn;KaIbN`9$5LYSVe3)xMSbL_H+zU@20}g30k+ zSW`3sk)SoP!`OT5I(`%W@+#Gosbr$~+xYE8Ns_~|#WGYz%WTqo*;+-nh%X9-tgZx; z9+2!5sRRp|DReQJhqu8y@IvflU!Hrm=d;V{YG|uxTCL+WQ*;}2mvyZ*jH*rrUin$& zR+nhXG_2OHU1T_5d}r=p#q4XHTGv9~8UNSd@gT>oMb2U;2q!U^ssMHQMN~89te}Np z1EVK})JA$1bA)E7p=2b{9G{L=qU*3Pm=^7ad=BkE&Z1pF*Z2V%jVBQmW?a)YMZ*I=8k%KWygvW6&+NA)r@wvey%auM(i{hfS*<)THHhwC)wb1maw&D_dC<;yFL zDz7F^ds-EzYFm+^uB{!Z*O^4-7nY@#c-vZAfn%BbwQnY94EN^xv4eq8qYkTgbZN1H$V{MVvNQ=axGt=g1!!XU1%66(G4Nt#Gze2Z7+goGS6l-@I zCYtYAm)O2qYub+5208Y)CU|SZd3;Rpa8Sk`WP!(v_X>N5x4>&)ZLpu%H+(g*lN?S} zr#6sfcsAY{e@QGR_mPJoLf8uLf}O{zVs3mQDJKhXCBB<@NzS5EnDxv+ejZ;ZoFM>yEKRPqM0eZN#S&vbZC_?z zXTR+5yNWzd{1bvEb^}|7n*{t0hj^cm+gLVUhp^!U9>f~pBZyqG2lbtNK)xmF6OXYV z_K28E?j*Aa7Ut??>?XDk-$;HVUy)A2L==-a&C(a?0JDT&DXbzY6V(>i5H}P*67Q0! z~*lxl@5M(h?jGx0h6J~NM-GEM^lF8q&&K)7Xk#@42xP))O z#^Js3{rCs`FHl0Ck8Q$_5EM0tszWKMsZ;~zil9)`P~1|qPIN$gQMydFNIqTuhoXg| zT-HP8lW3&BC7&ga#RrAc1WlN6^g416eg}PyTnmk4clu9z8~WP0XE`d&GmS3{Z4Gk$ zJYA9|TeZ4^Een*Ns4UW?YmezZY1-(P>CPL3mWj4@&LhqqE}g5n=f3xs|61@h;3Mzh-!F6SM9{F8I!{Q5P52b-BsvZB&VNINWpl{pKLe%jAM6guZJq=~ z!6!Ix_CN>P1c@l4)V zo(oo4L(*C3;E!RJ(j6!h_6*KZMz&LMx%ZW)s(Yo=W{6#nw8m}5>o7R|y*diUX-3vWQz8K#@Z>s+@SmH2_14PPRIF$~An*AHd zEMzl8@(gG@h#IX24fKZSX~-trM~)*4foJI&)HeqK50L}WiRHi$wiHHcHqsKSjW;4T z5cy;)dL2`pe_F6axJ8sAekF;P$>qc4F^a~DCW_sPtBOQreXz$)3bp)~tVGgP@=!cf zyh5ZA4iNlcM7x+lg1SP#C{lbt{1e7+kaUaeyv#0-R&ZdQC*`N*U*wJD6J=kes5D8s zQgT{+OH^IBnLmPQ4f|3#^_1v}ZQ=b1Z5$ui;@jYHyJk6W+D(@ArYOS?-9jy@ou$Dw z9`$kcTa~(UqDrheuM--k8TT2j#&f3Q=Ihp}w%d+IPNyr&UE$vBP4r#&lYvXY18gaG zB=njW2dh*rau{ulb;UR0)xbtu5KD<1d@=lA2CUOdh`~fJ*n@iTPq21H!B+_}kGM`$ z1$!Pso+pn}#k2f`vL7-F25oFDcd1?1?#|Vd3Tvo z+D=?9iV<}Zeh~cPKVi;Nmx#gm7jy^Ylcn6Zz+2yGPjmMt=T3XR^@MqpDFCONQ`%Kp zi>8)lp85lf;sq$TxTig(Qy9)0SOac;VotN3us*i6cceLwxKwVw_k;JeuSUQY7{}5a z4prLK>Q-66UzyPkP;K{LAU|igr#6pusc{P zoYC&#$;2HZitI`DqT=a+%y<4T!A4;%QKq;^{97_ux=?mq9-&yMsHzyF=&xWDcjV3F zM%g;q64_^IqO`ZTt_Ty#1S0-TT0)N_@8hFTC(pzkWHSPkKif0P-NN?mU0ZFUc8MlIb4mSBO=#|DiZwg5@wycKWPK~c9HYSW+?-;DC;SWijX2taYNA&TCI?0$qq=jOa2j`6$yn0`T2AiHJ?l(YGNLqjYHX# zfXds#Q^j@DA-4UpEHQmGm~~IJ3pBmei&Z^Ul{D_~x zP9m2=YuMj`X8y%qiD#7Sr$cMYu>NCiX1Z=@qfgKc(;n9Z)T`9})t^<@pv@jtKebe| zT~kdPp)1y*2BV>cX`5MXsb|}6S2#Dgk~|jx)Yv_6G1!n>7kUcuy!ihn>u`zon=qdHRaM6*&`Ti0IS+%VO6)f689(e8^#-ln?9O_)}=P7qrWrCJ;+nT zH`f0>(1Sg|fhr|31)YwK!g~-j?6CV%*5QEJg}+HK6e0$Y(AFjJ zZ;Gr~x=zYSH%UH=GsTTXJ%l|3o%t=8FVr5gGlApJ(B6P#TM9WWA~4s-c=rRWdYb1mz6 zTZSXYIn^EMJ>hE>cpGdD84VI5o7b^t_$y*Rxt@xl-_!M(4a`gC47^q{6PX0&E4_;* z>8DgTh!S5Q7m;0I_BMr>>tJ#{=^#5$kEssycX}t&nokJc36=_5iGGS!iTMx{tuH+y zt(3;fCO}IM!mG2)BwZp+madg}#0|uwMWcjm1vLK$#FU1S@x*?t4SEJ**B7B^evQA# zyUBCf)ya9zKHT=h(#GsC&NhtFchl|A7HFzzo~S#imFirTO4UMrM%`ZXMzdSH0#>9Q zhP6hexs&C+wUzz0W3uaxdy@CAZ+75aa1eJbBt%-HBe5CyP@+2-Pkp2M(|2ew(}8Kh z^k*6})tR?2XGhTS^gC)boIG5xzT6=%kx$5rY znAmNq6MY$cO)}Gw8N&2s8ZogjYcGP&YDlNhpQu;VU({l1Bej%zO1+_k^Z@z{oyhEC zB>dz2G{Id#E8%0|Akha=FYz(4NHS2eSMp5qTT&=_55B6eBnW5C4&u+EcA|B{yMiZt zBjcb$l#fK=oc9D>qJV(+_Qb%GJpA%0I7m3D; zE(?=|Lk0IB_UwoKl88zoeQjc+ttP?c6_z%wT`rO zGY>Z%H@Xd@4WHp`=F)xDz1DrydB6wX)mJk-H7qoaG}ScMv{bS7wk@^abs(;O?oFPj zUV(o?;AXIbRRA`*HPRl9!6NY-d=Kp3cawfNgKmc?VLt5Si@{&LrJhqas3YK~mQ&NH z`P6P`wGN_I6X-p(haS#UFoPieF;MVIFhux4I7D4wVs!6&@+DLj!8c1R! zh2j(9&f+{#579lLNH|t-71|o2MRYV(1@hccxC`3)5AetK=VYuZaKpdE*T`Gw-tOw^ zOmtB8B5RSQ!i<`0nx+}E4MPof{XhD@Al7qQe_x+wm}Zb0cNwR_s76`htRh>My{TiK zbEoU0oA$Qz&GhdKdbXaRgLYp5`DBXcROFQV%%r9mD|1H0X;HsdO@UYM-94@*6YiyRdD~#d@@c?lv zaaFNbbWgNWq!e8fCI}A;M1sluA50`Of!;;EAb${MoR3Fg$!Ic?#$zDM@i=%oFvH)< zC-LUEZ@5-E$2bPq``N}@*IPcDrRI&MAe>2u7*mWABWkQ=Tx={ib~ELfR-4;fXsZ?M zH_x8uFgSVcM9)y~Qr}tsy}h8|5_hDb&RoGCWJN&hr*2C&l`xJB&H zU{?s2ZG!cgrL*OSd6l`ASqWoIo3qT*%wNnImdBPZR=@SS zZH|4AqlGiwMYz3?W6*dtzW4rLfk(kh>Q3 ziSEQ?*e~oR&JzE^XtQvx`-5Bt5eXBSMopnkQdU3@E`oJR!i)m{R0wNqd;U`XDgI}E zG2aIfe;41*FXF%BpX9HA7W$dn3}gwJ2lOD?M9rgYeX~&2YE$P~JT68Q)}oBgnqJ4Q^-u03OKWp}N4b*&TTW=kl|FE*gtn z$J`L(`xC#6m*6OzT*ngoh;IZ()Q5523~NpqS%n%x9R%;>p;G9M;G>VzuV^(bgltd~ z*li7ChBJfUYg?u^6V0&nFR=A#5LXMpET2L}Q1{7RB%B$*awp??STo3ftB^*J^SB-= z=6GB>v~*$Ms=pLsB|W|CJ>T5bptXo=t25Sl&oSLm*THiX+w<*}cAq`TG1PI<;e$QW z181h|q$|z+*gYKLM~A)5d^x_k{;0sSz_cKrJpqx-$6O1jj7bH)Hx!wQKwcAFjeZ3$ zH59VmKe1?hIDP{Efn!8tVj^*dC?u4yk61wdO@0UO6%R9a0=1bsL;XWNfgDE;c(GFI z7xjU94JU~6)Lu9j^rMm}5BZ)vLQW!Uk!IpJ(VHNMn|OcRh^++7#B$Vx3`br=mGfHQ zr>@0qW($H@!3}{te;xmBAL(1_HF*|!aL;*nd$-^9#I?h<$Ti9}+BMO&#&y+I?230! zbl-Q&0cED~4DtT*_V#`Db@PAp_YV{VMg{YN{n__yGhlEhfLrWsC<*um@9})#iB}_U z5ESi*&Owi%zfc9%4_kvh$7~Q|=?CYyN4Os16e9p#bqTVLWkiq=lPP2avI{u`uD)a| zvLTsFGNgsbCEgIH;8fIx;1gf*U2wWjf(+|1tT%>XSJ8fe%{Yv-12oS%K+3-a4l5J4 zmaD?OVh6J3;O=0*gEao9tWSJL-Gl zQ~M(Po&4+k5B&yzt-$2KU5Gt24$cYQ3I>Di*sXw(Na4nEcOcK-8CcMNLT%9~s8h1? z8bCbkI#PkeqJ7Xc=ykLhP-j`#9}rL411H-TSOMn2BzOXzj#t5}<2CS_@chxZ7{_oc z_6@rMk*JwiUx?W!V*xY=Jq=mo#(?N8Larbyk-kVOqK7Em9N_5*0x#Mg;HPUHqJd5J z2Dh5)!=-`U7PAl7BkUq}B-?_m%F?VM_&InlcsY0^xHGsexHPytxGK03UaNz9gC_t7 z^)6T*WP=fGEw&5%&1&{M`-??@UArf+-yQ-~Cm$k%vw_7c59$rVI#SDk)4l*W{?h@s zKL*g78;}#oKS&WoDG=}zQD_yk8rlNwg$_k$q6=ZP$3SMi7upl;fObNgpy`0fBv2#r z6Y7d?A}4`scOx<#=>uG+)e#}E#eN4a#^b;RI}75A4WL5H4?Gi3fp2UBJj1Y1Q((+> zgEGY@?jCTNZ|CN7Be`DOA6##)E7yXn$5rKIoP>+vl3>KE!j;0+=9+MAxqhHxumBk8 z&v0+J9IleHL95cC=f(oR*%82OTnB!ze5h;+Gc~n_JI@5v)N$atF9e(ojYL4N*M!_v z6VR6Egmeb$>I}T#b%1w18m=hdSf+ppv;;V{AHdjLhKjKZz!QBNu4lmWSqe2zMqn_{ z;k|>Ia2V!8PpD**{8!~$4%~rH0snLBzt>*ic-#fdWgGuv&szbUkL%(8m%$ikgm}Ox zjsWX=e5f&SV-Eua#1LR$tqzRw^`KWe0%!D4z!UX@R}ZlHS@1~*fCKLlRQ81#Z^HG~ zLa0CsYo^5k&r(~cpBn;|Y)e1|V;xkBt%mlVf~e@QKxeQF4 z7lF%iCvaXKg}SGcz$1DFIAFu=JP!P!Yk(DWJn(kGZVT9?ngTOYO<-Hk-F zx_}id2$hpzj+(F{V=+{+mV$@-2kImr0Ha+FJlX#%egCgIXo9Lk!GC=agu1~ngGpEm zEC#AE!}aW8O}KD1vJb|EfO{oDt)2{O48v8TVV1NopKyQR5vvDWQ|*8)Z6a?pprxk6 zH5HJClYwonA6x@~YpfT1zYWG`1$-A)Yik5dW7XjkIjCtg!97@bZUU^W5~^^+6~aHD zNB_^=QV6XGYj%g#0<}>27-lyKSFVQn62i<(VTDx&zQ^DvVa9?mZ&{f0Aj~`$R;CT} zHvC^nH_UkWe-^Va-&UBZt`R&-D_&UHtus7NYv2NF13v{WbofnJ!L1WKcUUnl%=O(K ze%Bg)Rv)aV8B|&}gxpDc7}a+Fy{{wuwiCQB%$nL8e%cn^7uFXG_gD-(6$+J);fm+~ z*OrItzze{R-owbe1G~8ob*$ImIt5mB8s_?O_<9zYL~p}&2Y!AD_z17S2!^?89|1e! zD;UY=z)<)R#xwUn-kxx6Y?uittdtX0i4Aj1{9ofQ4O$)6APl$s|4Mvm&@*907SJHCUj&*0wo;0kkR-+-sO0+pkufcf$uuvi{| zYX|TsZi9c<1B!k&a4n7kX2zaSFIxlD4y3?k$_Et@6ITM>?Fy(o?Bj-W^`RQBh;6{O z3jXcWx|X<_1|cLD`~vN`3$>&MmIt`aM^JZ~i9A4#ph|QmV&(lpR$`qYx|~jp08G

)*Dwd^c@QV8PqfC@V{5TU*!7mc3VR%|v}WkbLT(!OH@g#%LGe&Y{2FFLPf!A= z3e~n3pa&Cy^*9l7VG9AHy9l2A9`yN&&`WL{_mmqDdI+mkGwuRcgUe@S++NV<06iz* zwk46LD1v{7=;#gN7P*F;K+UJGLDpp%^BDGSRjC9DVH&|+wg93Gr|1LJI(i_zfjj{F z;f6#2!4QB{@#48p!Pde1{(9ce?mSm7`%2qu+d}(i>sL#_%Gzr>dpbus&pPWkw>eKa z3D-{dRqsCkm_Q&ni?eeNKox}nO@}{$fT9t)0<|MUQ7gI}JBL>#B@mzO!_Iu3E8pVl|#i1n00tbsN6rw{l=Nl>Gu9QtqSA=-EP zg{EBdGe>prGG9`_%dS95q0ZwrJh3<=;J&l*fh@1mbKBL&ao8d-Wf~3}iu4M7kztQ{ zvu&v@#%Xu=@FlZ<^BO|NK7rUkwg3#G0`eVM(E3PfF8{l*LYyeuDHlczjjD+2mrxep zF^OMAn|3d0OjNR@Hu;)&!PnCD(@t20*2C~zoefot2IFgegf2&)VsSfEzBQpj%!iMn z(wKJi1nMZ9c*f%$K+j<)FQ5JDx4VZrj+k=|GW`jiL|3NkWq4uAv`XwZ9YUAP{nS&{ z_c1Vwjplh#B_V>G^&D~!oXH*$Zy?Hf53fm) zUgc=AE=nq1fWKhtdr#Q9nD~Z!y78Jy%|IPvpbgy(e;fOoTRPhMwOl8tO8F|%L-w$h zWQe%0U^Y>K)D6|=_WJ{#nT`z0SmROc1oh!cL_JCKLNiX^z}(oe&9mRH3cg`CLv40P zbT4`UZ3UGmONbQ^Yd%B1Bv%m@$fkFqEP^!YAZ7ok(wN5a!xH{V;*#%Gai zqD(AiVvud_J*G-cCsq5he&ugeJcy?KV`ygW?AYNx=R3qUL=gN7xrQGtDV0B$7fBBY z8&C@Y)ou6GcYLu7G_BGP(YArOoKIa}Q?6~RuVQR#-Qt|@8weH6<+z&sOrg{)au7tn zs^I^kbzr|FMOVVEb{zT^PhmWwpsZ7*Hm+9kq0}2yhNi1BZe(7sJ~-j4ygrj1dhgz6 zo}kGsmlVg8ILr2`UTDu5-&&vA^Xy69r`$HI8M&T529!51#D2*$QA@!w@&sUbE4^A5 zWB+cxW2gc7ey*}#zX%w(`#cXi9`d_h;sg4a>!K&qghgNxu9wOm%@Uw zNQkPB((Ko-vn+L$2Gh`6q(M+1EdZ6Gv5Gna7 zttSh}h=?&U#-z#Bj%Nky4yheeBQxnvgoD20o2g%4tpEM*cis1ixjjp6R!-BE*}C`` zwgZw$x&$8KBgq@ZyQl-v{HR%qQegm<`={9YX@jLN3eOexE81Lgr=qWBnjykswB}ljLqAmSOpcWC5n&JfERffY$dG~|u{X>02eGY#rHy2+nNS57DsFd3y55))* z4kjH)`&fNNttlBN(;p-%A{eHBpsjg&xjtvX*J)p|oX>?VD-IcYIBouqTz7mU^F^E` zc`G%`8Y+4!9>_~%eMDybK;W?Lh3>Iw33-G~{=n4q*dAF9H_M3|KNT}3r3cb>g$%*-dCZy#7RLLS!Be*$oA12BVWrG zioJXbHJ7*1`_gh*Yb%>w@Ne#^+aOZylsY$reB^%qOmU@Rd(?=Cq4EyWmm)V4A_M4BcE2mq(oOfi za&+mm!m5S+iZ7M!sUUUHw$Yw@!2)DHai5yPSOn{Z3j|O3-S~5vENTVbA3X%SknOO8 z53{n*!lyIaM0=&Ua#GaInBurkN%zwuGCdhcT9?=XlC9VkZ;r*KT9qgLGV1e{AA$Vc z<-?5<&-PG%a*L>j@_yvZ$mx-?$epr}f+$*x_YZyX^s-IUf2;5m|5LcLz?gp>dg-!S zWvu2D2b-eX$%A~Qs3G8uuL>dsNz6OaKvX5>U{bUKxr}HbKGX}JPn!f1$u8M`WmMFp z*tEpdv@SL7*Z7?}Jnph`fanx@)qPvHw8--F_P40-+Mgo|vsIk6ci;mNDG5ftj-Q^m zExu{=RS8a|AB-(2#dYr0A!-~?ELN1z z8kTX~RXxnD{}ub1`RjLndD&`xJLg_@JZTa8BKF0EVmrpvj65V$h&IvN(LI5N&V{D) z+KUyDCC>^5=1cPX=L)dJb~DY>~dS&d~-dv$E2@#14=iz!tdY>$3`SKE8j`@x%IW z_3}mP1^|Q&6}YrNyH+UO3P&20cQ}wPqs;o-Mk)oHy6Ut^(M(T~Wg@In!3jTO$u6!cY z2b__F1Y@X5v>8_|(8jL-ya=D|g(%5~TsJgT~)8lythW7My;BaJ`o zJ$zZ*XnY9&ka&sor)-ws+JM2ldI^xY#pno zRQ;{=75l91>;0cpzlT=Vbd4w4$l_y5Qi`f=sx~=U5p`DRNA`Lj+Y(GNjkRoLskRKS zXjk68QlkB!CrpvH)*c}{2363D1*O7B@ny+eX-)As!E!1etsYv%cHvYUaJeJx@x$~X zagT^9ag&nvrV>?)YD}rqzuv_fTwG^~fcV#2sUKPNT)H%)Z()k+mQ* z$Z>pHJY4ojeo>Y!jugD2M7R=xd{K~L*M-_(x5?px!HUbVbyF-=qcYFe%dNjDYhl&r zu}{QjL(Lsk)E9pv*$ZA*zTKT2^*yENiXQha#?DKI#hy*xP-SH5%Y=T)O8Ok{qVKYO zyuMvUc8RFCxa4>FeARnRzV1(RvAxtC5qQp(qI-xN^diV&t`@Bp4Hh~0KJssD7_jUl zu_FTG0vCewkxkSSac<;@#Mtz@wZ1g`-tuFMC3TOb%vElpcX=W-bAC_x;CzZbe*ZH2 z;#F10WWK1CUL8x`7S)|34m{W!C#a>(&?>eWrN6&Ef1dVW<->_DPGvXyb)jO4 z>m8XHp-=f%vvHO+<6!!MghTQNWL)rXTY)COcyJz>>&{~esp3XuN$M`f>-Gxo1D4|{ z@LX!M;Ik-7QVHmUWBR8sAbu<9B`ufq5nmNn!RAH4F|}@Ncgb?Rwr{`raAo`A&-vCoI=^rJ`+{L5 z-zvZ9H&`Rx4Fh{axp-IpL5WKitLUf5mG6}a#Pj$)NhflLTOXVml(P=5Gun-OEIJys zIb~gq?)4NcZnvu5sAJ6oDbnaD`lMq~S-&qS&#jLpKRxp5%p)3xs!{S%F715?SiK-#}JsXi)^m4 zbL17cd`eP2LA;x(L+s(b3U2jp@&5=$gs!8Fm?QEr@nh3o)|%FMV+%`TS(Z0_VZv3h zE-+I6Ft5Y=E6>WFRlFSgX2-|&1^GrIsA0U315*N3^U{;j&!-%XnIvgM#<1~@#rnFH z4@xVG+7#^0Z&7fu=xEstb+n!O~&x z^b@G#W)LTt?m#*}Eon>oq1v&H1~urD`A=Gp#8--exXOuC?*6g-UH>;#-i>@G|2Qot zs&btjMHWknV)RLS)0S6_OPwC)RDKekL|FG@GplJ`-le#8QO!cS@MuxzvXkmOeWK;9 zo%FWhT422)PM{YVrA_2s`F44t3=<>#$<#1n1@;Fro3{+vhp%8xN&kxenN+*Fp-xdF zWBp~Bx~j*M4l6u}+7ewV_`d$#x7YpOJb07!VRVjJv&b_R>n+j5)=r(5HneJLm6EuJ zvKh<=B*7~*Z`61zww69BdR4e}{UUBrRN zY-N%3pr|_RQX1k*(4Po_GWfrAq=Xl-F1}yd`dVx1F?EM#Y)z|{&_*@~jdV`0Z1Ahz zhl6i_z1#SX_;lcRZ#C-Z&dU~`in)^bKILVV+>}3JOXP`*aWUE`LmV`{WJ#cI=1eUoRHlF~16) zWsXMNNg9y0wCdxu*-7^zuL;ND-2#iOoMv%FTG{vFqC%#4Q0cgerAKr3kCJG99&4 z)vhJokM1o^Lyy>dspkK_{$btgr|eH8s(dpGxW#1qylbBznN#-DuHA+ zlQZ&M*eT*9^_*ELd?yM*wS`ZdE$%GpEz}DqiTa413TudL;!iShJ z&dHzSXNyUcVcHImLwgE_bZK} zN2G)8QC;?fh}@ zMBl|$$zo}gbdmIy?1KD+th;Qs;%j7S^wHR-33F5WrnXPwV&fuD%fAZZ(CY5hhDYUt z3j)70a##E|=A6sVR_(Hxd~MM>g30pT%I}diVh%*Tkp9ga#(%Sj>$v%(VTLxok}Q8+ z{;D!o0|!08-X~bA+ZVZ}d!PCT22k*-uh9lXAJR(a2~Ghvm5}a|ak3oQCHY;&8AWHs zBjuyWInf(pcE?_gI~K1`xD(eWGEuT#P>s@aGn_#~E%oz~hK0_eGbOPlqe|V{MCT5F zLZ~h=Pq0{|6&WReNE-{X2p2Mgb9=u!y4W9DVvXB%UTsTVb)8n%Sl>}U$xzo+VYy^? zx;l98_sRFWb~@& zaWPM#6!Pw(W&E~eT{g{;VKk_=my$(-Vr9wRqBSM&HI;Ui_hhgSevH3K^i@<(_Eh#x z(2TU8Uqa`--|g|%5ynyCPS432bOv?9VuP!ji=6i9ciaD^ta7m`J=uV5N0{Cb_&xNwuQd1=9*A6;lfeAzu6h9N~6Ka{;cnN3sAM!M{XPM^eU+Y?H%QSY~Y2$G7UzTfjtE;^? z!T&9g4QzMIVO6Y(#$hGc6MPiurua||`epzSXzo}3uJ}jwMBCR;%`(+F+q=b|0Gxwn ztOX!00vLu$xb$EjzsK!y6x-fe|2BUx^|IWyHnnk3?|92y!^`vNMo%VUq zXPkxXM{h%%+(_E#WC0<{7B7}wlJ`(PjyM*1GD;HNC3Ph0ycOQdRRmd|O6NZ%4`QjXU!Cvo z;d*ZGYWG>jnGPEChH^u5;|cR#+eiCsN36ThH!{#Un8(%xzNqu;L%1#n1%Zn`y*JI9 z=&9|Q>e=g2c)EBRdmnrK-a)=5{^R}y{v1C)IE`(@9SW85=Ad2hyQGIMVG8&af(+4d zac{|fNpndK@B-`v|L`|dSxf^Qw?tMU=_H;kY9Ktp^r24TuaJIRARq`_@X*c~w(0f} z_I=hC)?>DS{f=XWi}CjGb@cxg7!KS}F@OhH1{_dZ*xtduf#?3l{$yX!bJ6_`P&t3O z9&?Jh z#~&id6sm;1L^+~kB2F|-bPM8x@0pu`2>Y8T#~jF)P&}Yit%28ockA!9dHQ+ox{aQn z-Yed7zLtU3fVODFw%`b^2U{9k18AE8{*J!0p8f6|*9TW0SBz_)Ylyp#r-fJQKOeXf z)U#_t^^q_u!D&p1Td-2VL4C#)*fFTb+J!KP53=-6L5VdJvPUkI#UA7NL{Dls-Gph( zj~BcL9O_L$mf$kfbdyjOjgo8dVc2W*4$_L(9gqXN0ZkDNc|#rd0&rK=LYKLX?DOF5 z;I81sz&pRxf88hX9rn)mqTY3$Zk{Jlk@6a_KIgp$eQo{kV0Io3rn1GXmAe2agQKB1 zP_O(Ga?hRNGDFVP1dO~o$Z0-+d|)fUL5Kji5{o`UA7FRzGsIA+qROSl&~Ip*8Orow zD(P)>H2s?DK>Y>C|3SnNoWef>)-4~fG)RLbCLvFn3xA(A%Hx6=E? z)7-Pxo#mFgJGe&zS-0O)=)L5-?^gu7vhkdj`v&700EN~#Kmz>*Ib$beA2&co^a1;U zJ;{y%{7y9Y54R8$wE4&mz{I}6Uf}|$vA9W$1Kd;!iI4=ji>Lz_tl3am%HrveDVj(q zi4g9azCL1tY7Id&W9&`tx?#(L0R+ymL`Oo%mq=bD*753f)qiHeHrA0%OIOto6BKe z0?XJ>Hj!%wR|X(@R&af}AbXEp$~I(uK~?Ze@GC@9Ccu-m0VGp3(5wT!c|drSf*yHo zBpqoE%HUF9VM#->5IK?wir~XxG!Foh%Lgo)&C$ug6t@?$mqqAn!0c@RcBxqO7Vw5L z$Qnp`Zwxhnaof!G2Ns#OfWXBbKtq@z%l;>1jgJ6U=O~-R9t)-i^?{tg z&j1$3H+xl z;MP~5PINdn7dV&(f_E=M*P%)1R^$U9Qmz6@rUIT}3OAnH$^8J0<;7sFselzZ2Yvk# zGW#w=1F9e@r;yPyiR5Z)VuT!5KU2F%)hKr=fz z6bCq-$*`taL#;t|{v2>21$av6Z6Q(#Se2E4MiPT2>Rdo!Ik>;Mc`%B}9K!{GZ^y`5 zSRBTA0N|ibaPI)uqyS{V0YDFg6&q!M9qA3|p5uVxDFChTBpA)Hz}qti@M)a^=g31I z0dk}^;6#pv#sh|^R;UV~i8_WRfKK8|(4TArn3Lsj|1d&mHlSh(VXlX@>7Cpy?lx#t zKjJ=sEJHm&Bisd4gA#BXqrrA2fr?~Pz|ZhN6aE(Xhn4XA>7g0$^*Eq0+@TEk)ZM&X zUQMvpF~}6?!4^mW7;WnTYfh8UQ*IcCaL?Fd>?@W8TfGW4`8m`DaG~{)t;lWUDc~h< zAu|AxbqlZ|Utu1_hOTf!xR!u?s}8Ta++^-N=LDVcjo^U-p-#}kV}Q9j3@k${L5aO5 z+@}VhGvG)Gns1!|M{^7iXFT9DYK(LNc8&%Jj@*X#B|?w)1fGj%{uacN{e2^FcFS z2|V6YVBX&VWK&obkb%GH1b%ZOAnMKlQmhiV(-V>U&>yXl3>bYCAeWXxD|x&dU>~hu zrnn&rYvEA1!!W>td;y)vuJDeFFguLEk>rF=cnSEd#ek8)K$G-BXeMa9hrk!U2TaIr z@Ce(v{eTmE0sPAWE&5)z;{&@o{0b!bt_<*asl!470_eACI^@&H()m!0#;}aZ!>s?$1p3O zg8uX+Kz&UEtWgH^yB1JEm%-QVho_hUBenqU*a`ZhC8)U80XDP5P#TQYc);ClgirOt z3fB~Ddj-s-o1l??0jw#EPaFbs#|vno+khQf3i`&?;mO-Vk0(J7jRlm;K6tJgfZ4hL zTK9F43CM2nT&I!wF!NYYp&kcMe;Mqz%YS#Q59qx$FcuEL%eI6WKNWP8yTUBeg1s#Q zL|-h7qYf^Ps|i}tTL3%6hu?32(b5BRT6Or$>IeyZ6c%XjM##Xi(A&#lMr#2lxsn?Q z$k4gmL71;Kp~ZUOlgb7Te&87e9M2x`2ThPtn3HY66Fi3&F95{hF2Dxq;pu0?)0Y6# zKZ?)@3aiUSK>F2y)#@Rk14i!uh`9x@ z3-}XkJiIq~0Y0)BV7$+98(~%I$IS#}=o=1)S@sC-F(1bHJx{}90M(fb{&*>jbRB3x zSX0Xg=&c~An>GSVoB%U-4%osIm~~HJ*4V&rTX^L#Yu&ngp3eaG z=?Q$N1lybf*3=$GsV#oDc4D>VS+5C!d*vxq7r;PtFcg^5g8vci&^xsnf-}MaIHv&Atc-Xmw@vG+n-56FAMWO$z!+pXSxDaR#w}c*< z1amSMTGbo*0~rNt;W1=CtVp#HHT2pf09|7*|Eqjig&kkq*g44hW;C1;Jy2!bKPkBH&;sj_6tVLb|??pbm?jVcd{b#^OeSvoufyLM4 z0CdJahs(_lfTt?ps)Fw=4-EzT`oWVRz(NkaIvRGnwPAm73r4L0SZY|)IRJ_RIIOA5 zU``wZzwwplg%t}h2rxh7z~Fxl6xt&~GFWr`oRNzF73#6@Oz*%G60p`~fbZ@Mp1Bu{ zM*^%0UKp**ureHj)%XxR!B*gXcns@NHu$O>@MR{LjbRO73$Ww010-WZSbrwL-}i%g z)CN$FF|co80T1~WKIJ6fD7V7CB#cO04!$((e~Uq_cRK7J3t;Xyfc{$wYjqp&O+n!M z9}4zY2>8E)uoqYaXvVL=C)EVz!Vy?WRp4dbfu|S*yQh4xBrA8F+rTXZ3y9@tKydHl zo&oAR1rX6cK_^8BEgKALcRTQqMnK~}g=bk7Y6Ek+9eDF;@cH*)eQn1Z0sVLiK3xm5 zxd710SHK7KgF9HDckY8-ABBE+3;ipDH6aS-$T;||3^2Yy=!^568n zv}^`o6Ym4Y`x89t9l+f7guf~R548e(pc4E^3GBcMxjay*kbqww99j*1Tnbvzt-x|t z0YY~Rtj=4&Z#04XeTBc<3^O?aEU+19r}Tn*9R|Fq9Q;@;%+}su=^decVXuS3nEd=t zFZ>W=1lr4scHIN{TsE8@x`tjg5OZxIR1f=w14D~K&oO(uh*p>- zdkmi~-(X&U8XEcEK?=tc_c0sj1rC&aLY~1``6K3Gd61mwq9lpw1EEv5v? z!lLCgtO&|OCM`p|CqeFJddRp`E(} z+Vzh@r|@mm8Wsa8tRSch?FSNY6%#TAe}Y|vKd>dxE8zC8^nc(N{TdwA{geC;{LKQ_ zu;LO5?trb<6Ik`1k$nJ}aThxmb;+U7F?>rVQLU)a)P1T3Fr=OWX`?@Lk%?uS0{N{! zP;o}Hoq!@!99BBU_I>qQAd?wtu_-u>TJ~9q0}V zkmC3r+=H+7?Xqpe74kLpjNZW1V{fo3PR`}AcVRErh7m5?cfjG6#i@Z zQsFa2A2Ck(1UMi+s_v<>RohifRZ7)ex?ZG*D|h2T>rSzai?QO z>h7o;DJKd_)+3whpXGXOZC`LQcWdUdv<0bOrVL4`nR@MAvy1`R4-8cc)>^7LJZ{=w z7dWmvp%*-XQet07&dfv^AG5nTU|#Yy<)`H@32G3LB(h$cprEKFm|ku5`$eXE`0EFoFJNrX<8C-AHzh$nJr_EWPk@~JwYC_7$SVSnwOecnrG?*Dyx{Fu=4j=1MMQivN54|{zKjYZr)kP*4)y-K6EtDh_PDPHrXxvoqrDkz(cul8Y~@_~g{WmVl)nV>nSSMC?D z11(__-wNoeSLsChQz}f(CNIJh(f(jTV6Fc%kLVm_{lqjW&zP&pp|fXYWn}Hj$ufRx zink|vZU)zrE!ofIFGZ8Oj&`4>w|cd*o#Gl0WwWVQvZuiu|4!de-U*)mZqfaN>$J0m zV~~BVZG%;9v6|ckl?o~p#F+}rE3KRDv94|2&x4(aFX`qSFANilsluw?)SqZR)C^FM zR{f?_DoNmXc2@)xU%?)?g;*6BZFj+`^Hm3xe~5<_&tP%97JX|XB<5VE1oH@p5>@G? z#H{eGV4{DYD`@??;HH7kUY3!Q9!Niw(JE`E;kD_OeZOaLs1<#H|3mmfe5CwAbwRmN z(L=tKHBmnh4P}kOCxhDq^#WZ2iGiX1eZG_4v7T8jhkdnmqdBvnSN^!XZ}Kd8oeL<- z1$#&LOAi1BhgZYZWc!gatQ8`4tPLra! zrD>!|Q9Tf!Djo}^2q@079`j|_jC$Pr1f%(kN}*F#mbIihWt8LfpL?`_=1wj>V#`zw$w6|8*C7e z`)7J5xjQ?qT4GGjyo*LFtmpR|+vd+TU$uAhTn!w9XPzruOCen`N0f_~gn{x?oQC}t z_S-wj2Gmx%BijZzjw2Kcm1Q*sZB1=6&1dRosvNO{;;g(YzmYx5e8_I$fZQVAB@7j7 zs8*?VLYA~qRuwX7d3bOEh-?Z5&UnLJqU6Q^h>tn+Z(@gk{aKfjEo4E$m zj~B4WJ;0l}%dqo2$;_sQQgdM&xrI7K1j8Le9|S1xA?G{Wbj#iXI&YR?xM7iTW&SGj zYuikh6DDn!i3&`2?lY_(cj15KQh){f20QgzskanGr@+$S1%FHNt9Vu9l~+}M;B*aE z9ul7k@ffLQ^H0%ELtr=3QNA4r#gD}wfL&Ey94uZ?JQUvXZMfR>l~7f$!BN3>ub_&d zXXb&lJE@alHdT=EHfMI;ujV_B-M)-)CAtJZQqdCVW$ndY;yAInf|hH!7{)_Z0ap>> zv_Q7Empjf`+z!M^bCM}JKQUjPzo1~dd9!V>bFOEn-xNAWl%bcf8h!|WiQB~O<+^aY z+0WTwSPQSf-eChk7hb^m*kfEd`5wM5*OGH^-=g#>{Al4<;gE1jku0W)vthIUPW)J0 zDzNf<{7%%bs(cvio`>^|xSGsB+4De4kKCavXp|k3{$=uSZ!%t=N={6pGRGTgTX%c= z%i1tmf}lR8>7{w6X4H4ZzR)q=Oiv^^;2)I^pM=eKJ^xm336I=$9_Y$*O?~ozG5&1a zoo6k$Xi++9d1is1=Fn3)w_K%|rPw0$1-9TS?lgOi8G$jpBwLqV&dukW${BfG{&P-X zP4rxNsrmt^&PhOUOyWHJ9pO8%tm=;HxQbORQ2NEXRw0LUX%_;1eXv^7E^UFMfRa)!QEFHFBGp4m(SSo}eCMRc=iwok7z~B`QwvXW5UK zE7WUZAHJKdnCsRFP4MTqA2`0W_A_0`t705xxL|0PCz=@BR@W3i?BS@ATt)dW!dk_5 zip|0T`2qeQTI3jT5}t9j_%wbVAH$iLhs+e(Ow0+pVUd{?GKQwh#!)6l#h-*Wz&OaN zKC0EKNvd07d*O-PDBlbF^XBsMf?4RKC@y9w`o{d2W$`)ifr`%4bM-XUF=ZX)5HVI1m5o%T zRNsg{E5<1j6i4Ns@QvB()Y;(oZl|Sfe&gKH8DFK`dt-RL`gKh5(v0r;y{ty($-s2F zgZ!jeQ(augYA!3kRZJ6Bat_){3gj>0Nx`JRJpW){YtM71%{CP{hT{u{6x=B|Z?ajw zv)A=J3jh_K?I3?FhyYv89mB+as|umhSO zY#Zc4t!357{d8q$g?udzQU%oKG%GcJwN+IX=s_pM7otz>sO%}>lPFU}n{b0a&90)0 z6T51l3aR-=rG?^>j&li8F3?=EEO@<`h$_kiFmvL`oJu>{!KXE850swg4v z#gg=GVm{FB-GTakjjslfrG^2Q@fX`8OHZ@eL|F8;xsK}YuY99IEy&A^Qr=&|i|Z9_ zge19*E6FWn&2%EQ9%$h*>_0VN4Xl;f4(|=^@HO)>P^-BRhh67I1kEhq%|b2F4m_yF zs#~hx)mPNpRBmyYm?Jh(u2yYRZ&DvqE>LWfx8+vQOUUZ7m4R!X?yjB=k7Z=R?}lqR zcQS41ebR}HR+*~oJBAu&(XrIKJ=BjX#x0T8R#a2;hx6z8+*n3Q-IJY!cTPG~EO;x> zA@GZDxYz40>HZeTb|vlg?Xiw8otNFM{5?WLh?i7fb~N8fzF%G!(q|>thB1)6$hy=> z`aX4#Iz-*0*8pj-DRY_nh%{gYDhpqBOJxU%Z^;GpA8eXjDSoGXt7@kn0z8!wK#oZS zlGQk|v3OH_Dkh3+pzC^;|DDaG5{a(ikAeyQdO#?s?Y`xRv28M4%p070Cwo}du8f)K z+Kd`m`*Ww8b~v_rZv|t?>TCtx!}k|5bYiZvpPi zP4{3|$l24i&fVWT*v|%^htg%UsPl}KCAbOf8Kwhs59q!?8UeQZSa>k$%q(X5!iUOL zx;lM@$|gq;()#pZf+hQ6kCSBk^Ie1*VhiOvpv$fSR?KA8eQ;P;@r5ErY$NU!Ux`&P zZ+#01>1F?*=MaIw6yE~RM=s7`w+=MV$g^Vp^(3=&X4j0_>BTc*vo_?8&);bUjG6zF z;6#~`oCK`)(?CYsN^hpl!!9vEHU)M>C8`R!i|CEDv+oZ3}yqY_!Al@c(+kHzyuVo*?_HHszRR5$d zkeh*#{(|gCXVc$dmb8G4VOKD>=*pB|b|n;q4@Hx&f`1(L2{#6|2Fu|K--O+Y+xX%y z4XdHsL1(ZRFg`cJvqdxVJBk73+zs{uE3yZGmm=-(FUS7#QEmxj^&*8vnWQ?ZdW@O! zJ)juP!_K}Qv#M1JhpS)?7aS ztl{IF%UP8(JsGnyPh`!@aTq=-s9?R|SnvMT+tz<4P$#qytE0!m!)14fmt;LUmTknB z2Oi5VAkbXp2eMk`2z8zKK0Fk-1<$c3tqRSB9j^i7%AC+)@Mx<*f7oi2@E!J@^4|+| z4W)*)gr3}u{rM~f6DBCOiqn;u%1?prI0Ih*3RPd_CDEn$Sg{wa zQ$}v)Tk;#YN5B}CGY6;xWH$Vod>n>{#egyp^u6{j^oZ_>`2Lt-KWrOoDQ4=PzsCp_ z*qk#t+kh|C*tjb1V8M1vlB278v$ukOOJHJXYIuz7ccLuip$^brF_~-^{yX`f^2_qs z@~OO*+s!-$uJlnt34gim!`WDEpNBP;2B9Ir1%YS&(a_CE^iB8H^RDxz`W^;4hAxJ? z6T_)6ozEn2rT8mA;d;ccmd^$P-fH+ZU{(86Klo%CJw@}4hUpF68Kc-u}hQLx)s+3-Q` zyqw87Lv#Ix6M3r(b^&=h-7((1+dI%-A+RvGDZC$6$Oot`%w*vBeJEE7OB5x=8H#d( zMn0L>aDA8uSV=xbV8;yWN9RLLL!Siu1_t~0`_jD6pq((p{fm3LC*PChz3vYM--I_2 zB`H7s1!kS8+#<}ICkovZKZ+zU(Uxe2Yu#F{Zk_g1O+EEKc*2NRm@!upfm!GW%CL*k zG6HQSmts7q2Lzt^!P|jhfeFweX%(mn|4bEp0nc#HX!kxR=eT8SZ>?r7R`6l|_`I3W zt{P*QW0-1eg7t>#mWQ@duH&9K|BHYIIK&Ic8gwJ3H#?Tw%r_Up!ed2Gag3-DD=I`` zI)8?}Kwl+~$clyOP#Jg%?F_~KjlN`WKd-@a&r{7)!}G?Y_qBxXkv>!r-bsDbEG8A` z+VA*pt1G8 z$Z4HB-B3FJzNxEKblBX*1I2-udX&)8mDmp4E_j!iBCJsqC^E&cs8h}ZW@|h7cy0yr z8MT9;B(KTASy&hA7Z3tZp}W!8-_>^%+Ey-aecvEo9sj%l6~gWw@rY``gn|CyylLUf@NMy{gJ(leWc$b}^h2gKcbVTO&lSE< zG{YB@8Mdo?ph5aZvtRSMroG0hF0a0a+J%H|@&ax(JDXVs+|Zv$l01N2p^k(DtGwyh zH(n;o#{NTtFgy)~<^}!!!@joOY^ zuZ>oi_r)u}5le}FMZRLaVuYfHu#WGCFP75m1g03%i7Cafm?v*yCbRW{m$sPw9rKq2 zW;f7!R=|(yRHB@W3KziN&{p3Wcd}!cO|*0~eVFeyer;%++a~8s*2b(VS;e!PWs5n! z+&THLEE;FnGbPxE2-EHOoKkd!aFWcr286 zk<;?FKuIXZH-ML*d&1Yk0L-8I@GrP-oQ%86rm`oY;l}cUd>)V-`|%@ygS7(q0b#l| zd>nP6E@I_+G%;KDER-Ku=bPejy2?BAZO1IfOqUC;<-g49k+;Iw+b}(6N>=&I(;2rj zC*=HW)SDLACc8TLzYhngCcH~%rD&swRpfvxr;0yfc6vtfMre=kSBASqA16A6I{7bq zhP%^TN$!j8-JX`-dcLXt*8w`Dgs#Xg>~pMU4w*d@$0 zx;|ZrIswn%`N2DW#<#;W)U9=Ga5S=)uywLNwmdgCGk@IPQ&i zt+DYyF??$N$vWS`yVrYn1eS&mk)yF@F-LBY(?VZ?Rdg3eVWukrH}ImOvT%x@$W><^ zkpbD6&~2>B9rUjWoDNP1??F`L+Rcmpd zd=U4Fo=J)HVl}Te4>u1okFnUzf+@{t z&rQk6&;B#(O7=ZNZ_`-E3crI`#tjv(Xm0C{V%2AYs=o4yuoxpzAI3x-BNVb~L7i`r z`;p_FwY9mtX`Q*V&EOd0c@$Vk>|}ayKKV{XqVhxKSjcakz$mr(uSl7Q9!xnJjB=*#vdd!D)1LeH|bI}RvoUwa>UjovfRmAwtGCKc>c z%*zYr7_aAko1L05IK6M$-Sjb8M~ruEChuukEmo!IqW)Z8KJIAjM*R$|#tho*Mp5p_*h{`WkEJIfYI9QgukZQj@MZrmd+PuG^!1rhcoO zrFh6sV85Y9P|t`P*k!#S+d3YGB-3V zp!GHMeBes88?1dzH;k8Z%4BbWkB~dL7jrx2_~4NyHlr-8hYnj;1}?K5H5qZ+i;XS0 ztfafxpt$eVP56d{(YMT1%we~kvwP+;jHC-9ePREl;2gJ*LIKjDQ27g zqIN#|*$%~3ei}OtXeN!}y#lBhL`!Jrl_AcO=jh&?C$znX{T=NXUZiaFmK^34NWokM=s zugZ>jnZT83SE_pP?6|ucm*AxzhHK#4;+p@0r?2yY?Tn?pdAX&feYEqe_Yc`q{-*kY z{z%-m_^z=NwH1{;<)hfzKteo6^`Jz0Hd7tgGTB&Xq3Ox=5%#v+qgaC(&tsKV`9MhH zS?*K%BJn8PAXF~+1!kiS0v^ntvVk6GboFv=b}8H)+{N8CXIuL>=KcBC47!}k=~*ei zzulL7BDHb$VS5|0rmAFo>EiE7)+^B|VWR$5^>RNm zlr9)(Tkf?Ix8X8ff^g^p*8Yc79}? zlYb(2ccwlqF6I84=dbI%KKs^{k!M{>)zA(vR#2*RnGq#D2~13RjZCOa@%{#md*&(m z=iy_eq4Ag85;-q(^7GEwrupSeD`lA&cl_$a;Ys0yr*YrvHj7W#KV*);Fn>AU9`8QS z6xV#m16v=v$(iX{8u(RKnK>xbRxj3mq(7zoTK!6~i0wylKppH%b*28G1o*sp%Z}ju zTtlFqvceX{Y}lwS(sa_qsuYS%+<5vOA(PF8wp)2RYOSn53}7Yt0KFV7G>@=2>Df z`8};>w{m^4K4?_D5@#!URhp7lek^i|tMbwO4t57Uj+`Rv5xy1b4$TESymq^=LSh7N z;0K|mK{JpX4ZvEi=XJX3J5HIu%)6PhIqQ$~8SgHqOiBGT+4VY{%o-MWC-Wb~{!(&k zneL@a7QYrhRzE__pw9>6UA(1F-XY__ypN1a4Xxo>=0W~V8|5EEj~9#UXU6e~GZPyo zJd7QtJ0$L6WwJefr>B*>EaX6Y$6-4KKAqzZ__l}rbV;F|%B2~sYoW_je<@a!A7kE; z3DA76OZ*8vE*G(hn$EOS7vi;p zVl(5vP4LDSj~k#bu1=K;v@X2Qx7j_=ML0LxN80XLH`~1SfU9$099dT0K-EM$T7OkX zX}%Os@+wwC?ZN8P6rvk-iW$l6;n%b4pewP8=_D^LD%GR36?Hc?VO34+)J>6>$39mx z$^wnCisWUoF}%Ij1u8*8U;%JBKMAA+Pls+pSEOh7i%@faL-$YCetFBY)tNKWtE3)y zd*Zd})!J7tk_YD933OKMkN21CS2nS9sig6-)3uDE58W}KaCSE9@;KvWgERLA@U+hv zc9^o9CqoyxmUAH{%5DOM%E_OXl>)9<)x>UHWm*it%-l98z(%GE%hF>4#*p6 z$S`y_R>^&kCC}cFTTt-W^?(?nsGzG9=Set`I4t3#xHx@hRS!N)^ax(^&T&t7^>Px9 zIks=Cw{4T0>%AL82dNTr9zHcl%~cwzoMuS%{x>ty=kim5n;Di;^m77>WR<=&D$FY+& zd-$cqGvAMnKTP9|lMPpMH)Vg8^&soB+*Jj&oSC8hyiPMOc7B2)ad-T-n0wkB_WlYSd-2 z76FY@QVTCddpVDMj6x;GD&y3%vBSGs^HyzFY7`Cm-teJTpLz^U^7~l%QbXIVyzB|I zq7t!2NrdM^uW~o^X4?isUc$Z6KFEA0FC(XA2Ay){1^r~wgD#KFsnzXG_@so+WqVX? zS8hV_EAc0EoJ!#KhKG97ZS@Mu8hhq;%g##w_}z)Ld)Z0mLtc(Ks;UutF#c>pQbO;z zJ^GFswb+%LO4>r#;i)Xsxyg3W{7XTHg16?c9gBTNSps)S?4WUKCTr%anv3V;`Rq-s z)g2;#AP+&GvLp3`>PhdXhS86PC-iw(J8{Yl?VNB|I z#{zj){DrdV<+IBgOT0_$9OqGg%*~KZ^=NFS{71l}JDS<#-Px4#@0Mk`3I=$G(zC@+ zw6a)TeBJnpaUaKA(khida+|0HvaDb+|9ZE^@y0wSzeoOlQ=Gkpr&3T&>G`8#SM?!y z6`iXJDn{}vX*H0Qzhc%g$7q5|m-P(~k`00;MQgz)npGbIyJ4rMigt;{ry3{5$t{eA zenB;(i_-_FYUDuKS**`~9oiEvLp&fiVuqxm?Bo&hxXc(h>M3nsYR<^-p7$cBV!Hk1 zj}J3%)xG!8YrT0CQCT}Z=}F06C1R5XB{omkq@OCjpm&E%o(J}(*7*fXbJgj?l5fAA z@veF9XZFdVwwyt1pc$h(sc#xnF=l{nwYs`EhJQ|L$@V~|spjr!D{X3+S1~UUHtWB6 zSB4icZhSR015)`gp*>$5c2#lmqkK1x;$AZosm`)C;SY%;R8OWccSh)=OaPAiIdyrB zRi#u`5^F0Qd?_xMO=n*+?PwoWjcPzVg3jd^;Tq7CZ%lqk#nRuCrODmI#qfl{N$)LJ zg1x7CWBy1(zs%p?{Q0=`9nT%ji)IG+ZdXrC{HA2r5+joe;#!vARak*rhz{lq*6*D|$nZBg1mD;5En*WndB(?^uuHUWm z^XC~Z8ahMwXS-{5pcx52o}8V}!n#RU1+ZgK*RbLaY~km#0csCH$g036W@|c!=>)s@ z^7!_jBpy|E#`nh?gbeDjS!@Si8FhDXX?K#1EUYY{F3jmyfg<@gYK`3yOnoI!5F zw^6e|UvHfIuDze>&z$Y4#h(Ul4!%+0(ZjSkjA#xSMH6?(q8J>r(G(8G1Nw1Y0xrgbMHq_6YN`ke<*V(Dv0VR<4v+VQR?w z`#RY(^LrY0<&4j*mR|!_#5Y5ms6pI4cvhGIKO#Hjb%f;#m$*mltcaC&W8M&(L!F@^ z*9t3vBh*E_fYEMr^j!quFb!QBq*)@OB|t@w*}{oEIi3)(dO+ z<#at+<&YR!6#kgR_lHnZY$Prcr;9a2TKq#SulzwArRbnAD6H5yR|zxuBz74!6+4Ur zNjdQFTQgmmf%rzzF;kcVss*t+_}p99)z|i* z^ZJ(K*-z-UR6lAVl?vSKtz>`LL{_9qP(fm2m=CoImJe+64sc8|El7`fT=)8{>&2fa zG8;Rl)6bQ~v?aA^nyUH~eJOpCzP&cAY%gT9cga`2uGalIl~Omo`u)|cR57=LWr2HA zunp0O3NgGeO?5{5O8+c&YTWGDa(chY%==|B&jd@=y!wV?hL$ijyJLUmQhDEbyZ9Of z=7a@$H6JVHt1{Im)jQP-#kKqcswI4Lr-Wrh8OlfZU@5G9>)>TBz-DbCZAeE~kd?0-vdSsxPZmsJ{ZH+W_4Z-C)>PuNKBIUx$l(juf=W+>yNY^@ne6 zze_R9vv=|R5qgESQUh~BK2w#X|2lSV+~&BAF@zs>CYbBm zwXVCKalYyPcELNcM8?T8$`7^u^wYH2;!b`#eV_OeIv;PLTTllra+Kkf5JfTd4=N?)qK+kVK-;(n)1<+17=&A5O*Olo>pTHj6UU;M0 z=$r5CYAT*J_Rkr&DqJuBApYG3+bU|0=BJqMx(Vt@>d`ujZYIzPn(3A+llVnc$>3;P zo!klU#=fcgnopUTUB`UWIol_On#(>QUCazcOHFtEs@N9so#Q^&A5jk$+EJ@~vuy|R zlMLP9>9S%0XNj@3b?98z-Ccdz!P(S#KB)LjwHUYvcYnZ5FEN*(5Dqg2NQfn(@) zuw1=OeFjWpLiRS45?JHg=)WIa0857XL|JAje?w@Y+NN!&pQIZCkFc{fCRGYBz-Ecx z3y-kE-iDhC4Za;rW%@gE7A!<)@*(yGe1WjLk9mB0qbKC8szW!V0N{rhgqL5ttq-~54jrunF)ykoKVm(T{X30qCb z5sxXiD61-4C}@5^bC&*yc2Y`sPIrZF`aJH2?rmE~}*P2lk>WpjxU(rVp~0RgGf52G)R6=T?6wugV;j^>@$Ai%swNcI4Yqsh6@3 znKwJyI)^$cJ3eup^v|Jb)x?-p@j@b>FeY}HwwrPie~|diXK< zy$mmnm(49*)q^#uFgscPnc}>-P5DMyTRC6R7wBJ=+4FP(`8<5qU%|7;Io7ewk>_mS zx$K)8Tp?RX?PssbHOg4c5M5HtxY&G*bU*87Xe+4qDtAM#=ucsgJd5kjwu3*{#^;0zWSZ#@rm26hn+Jw`Uph{@P9w;cS16=L@w8kiW78CR1T$= z-%C9VbaOo_pwfl6gWmp<+9bOyw9}?|YrFS2pSf!X(#W!k2Kp-rccIVSEdH>58)R)m z^0~i+tG2zVy@dUU?F;K}lbClt=S9x7ykfSRz7B+s%@yv61JI&(;icve#Tk?}f!_vy z)QyRkfkvJYj^egM)={>Dj>|VmaCb+zhLjvcV9doWh@acD_QjVq_$gQ8RGACL`TOJmiFUYW|10(2= z_<79O1O_X1RpZyjoL0L99aoV$5snQG^f&e-*?Sc1$Q84$XI#o^nRmoG%Dp83i+}ne zw^ul%{78LEJx+5*Q&lrtHCmCz?IM>2G;X8qfMvS5f_b`ShwYHFws&6OYIr-D&(M%d zO*QNFwpe>yT3qwEV9ZSYJ?#MXYtbpplVkOiorZPWFqK8tAl8PLhDyRJw>Gf<&xF$h zf`_&wW<7s3;pwdBeKY2GRtrb8BUL52`0#%p)NcB{^SW`j#4%$0|d2eW--H`iB z`t-CfaxYpRx!mrp(4O`cj4ilgyW($6U6Lxw-aGe*lPF3^i*d?*&HO7ZWtl!@UZ`i3`F-aUZlwuL>L4pJc!IUb;>> zez*T*Z|kV*TmT=^?c85^hWq9QmV}4X%jI7w9l(z{0}szJ+ABc*ey#IsJ!(#AkuTsr zW%g2?h&>?%c24>QKgL(~YG}sTiKkRk?5T!c||)-s1}}OZ)_ZuxjVyPyyEQP-RRZ1 zWwx#PCyhy#VO}x3kS->qE7z$r@NN7;bx-~y{K3|v7t_O-L2M1WN+=QL2-Qt5^7`a| zWfttGo%=kW2I62t+5o%A3FK&cDqlxw(p=Xq*R|H1RGeZh&_-w&J|FB9$n+__vF^#v z5svlfFOwW?-8KA4;Y#F}bRydv-s%>^zjtRvf;dlX3Js+x@=M&u>}a|MSxKf3{|4Lt z>7nxB=izp+-rh^>1MWj_<_+7N-zYDq_(L=+<*L2PtKtELPI$!?W1bW5g8jTt?KKJ< znZdVH-z-nxZL$Na)a}jm&hg~9e+w*Nj))UfX_|w&Yr3FDtEw)Hr7r{vyp_E}y}x_w zdV{WGwj~A0#@~!L^Ddhn*{Zs;eO*I5NiqxJsc9IjM%K#LE8ZwO!F%;IQIso~MnuC< z<-n)DN1kc!(XM^Yiq3%Jx#NW6L#NS|17T?;hdSx$nAex(>Q1cdloIzgq|zm&{=KP?1*e*S6B@Vw%T<^(U|< zr_;u(mxzPp0{bT!44(?7_M>O{05H*S0;?WGVcu=r!~-lT|pm(Ce(6blk73OnQ{pnwmHZtu)FxCHeE+Wpp2KQbPAg?Y!d{?fj1MJ*a)K{{nZfF? z`Y#CefNgGL_>gIVHIn+|RI&?cA%1|R=R5Z(DuOWo_p*+p)VYX4th?H<=tbO~!O7by$CXFVq!g9bA zu0zn&V!9!-hOP^5Ob6jpcM=Jlg1~FV^k$!?T+-7vx_2A_tFfv)~np5m_Y-dTiK z-T_~!8^i~y=c-=Hb#jIo6e{lf**`aY8CVLPLZ5nnu=O=D(AclbOsBJhRpbMJl6Nq0lnMaKZg8Rr{M zR$!{^OW=%<(7y;n>-1B0DZf>|P`;I)2YZlsrXSUv=osDw?WjkZ-P;g&!=8r!hwz$agGJ0)a6E;Xhei^xQ3W2)notKIdt?QF z3w|3M7n~V91fLkILOd*dYr%500<1F~go-o~FNilt=?&0OrV=@@sy+d)Ke5uj4Jw(VlgRC=bj$?t}paP1)e5`z`fGu(a*06nmP;d!0;LA{-0q~FIB@?I? z)Ckb@7;FOiQWn@vwk9))nZy~`TYnNh5po7K!5#i;-sjG1_P)+x-Y3Bv89_8AVDpca zoHerRz|QQ!CUC9!TKrC~A^SPKmS`8=8Cnv?zC3Ua;$&NcLEjW_MeiLi<3Ap#9qI)u z;?GcuN3f~y2rK?O#2%_N{ApLGTahJYZJ_fuB)|tc!n(6rux2m>zhPJWf}aKkj3xLg zJdIdRdPpmIm;44OMFPo@P2lBf1mr<`f|JbxGVoN`63q+T4U`Cu53UQ|3pNIQOTaq5 zi7bf_$PD-r`5ivzTT<`H1LSUU6$xxZ*q1wjK=EU!SZHgoaxeq2y@3wF4e&GO4weO8 zLMU`Lyj)fZs40Wd@@L?`K7p)FRw3=6lnxqL&*8Ny9lRiirs@muKw9W3_-AHlEo{|G z!FKj{AUcGw2mdu}trLI~P?8V`6Lw%O0vlr{EN;E9$leLFW}raagRH-qJMFIXn`f|c<;phNtCc5eVoff{Jn0fj!L`a^di9_#z1fwUlb*m(@! zJZ|vFFF-XI1az78Seq(9;T(jPEcmZsSLtIQt}MYmN^SHpEhsq?t#J%}a2Jp+dZDI4 zV743t-Ty!xGEg%e>X?Cb!OAF$WREU+@!EhKC&OBN5Re+m0jD7sNFFo7Er3eW2sLSo zx{SvCMj#4g!Iu3g4rjO#YCaw@KE?S{@I!ytb^C#4AOj-G5Tra8R0$z`3j6_WgLU`` zQ0FKt$dAF2{3c3L8>k(xWHj(K3@F2AkV*AXJ3Y`OD&ee^QP6!k9iECYatwSnWrpKH zt&YGlC;@4=5WO}T(&;HMHWmSEU?|!!5fbeLZ0)~6oPKEWX4w4%em^A85d1eSlud`B zpU7bE_k!$Opqg|63cz!qmQ;e=d>qOEs*Wd=gT2$=UrU4R~S9~dZlc!+buCVV20 z6!Ou#o@0LN05|=Ly`XLwF%n??-vn0gyAfNBx+kILlDDq9pvf8FiAeD|;x*7EMxp&< zU~Nw#XB#+q8}^h2BaQB8ozQ#;AtZ)^$)|6e?=k6+i8p@A;|eA z==)vKOBbS47l9k_0{A+s5QCT9Mjz`7#IMRozYV0u1gx-+1SRL92V4S5NpH~60i?2FOp zOI^{Y%7I(L2qk$!9D}xq1Aa+yl%O{70_xzu73i}OJ<|vZl|kElS?KlcTVQ@Q1BOrt zI2YMym7_o;`UK%)AS)8Wb;0u+!KGzUtI_BiGtiz}(67#e0}g_FdV_Z|As0ReEt{jJ zy@9~-DP(46&~hAT^#?ei8p=Bp=m$TdN3K8$gFv;qzym2JGpd3lDm!i%i3frSQ_JBL1hbKWw-v*_|K+crJeqt@ixk=#T)#zoL zL9-{2t4+|GzeenZ;Dxs6PXu&wpFm!m0uQW459y8m(FmoT4xJAP%|S$}WgxQ~LgMrV zWkvuuqdR&{Meu+R@*o))5-*U#ZKNT2M|%d0h5-7y(Js|aY&#<%=cwLvyw_d zpuA<#s-+8`#}rE8V(7;;f$-4=600L<(g?MRM{E^JAVvGU zum%h&NUe~Cmbwp`KLmyH3+X9QltXP25T-d|^u+kp9BD|kERLs1s7E;*rBPzZYn=@x zliDYtP%=k6+m%C!s-vwMqt!bi{zo`E;;sThN%fS0zmrkQqu|GN;PJhXb{A30Y}Bzd zxT-5^HVORsgX}1J)H$HCEJ2-{Bj+$`C3%57fHCVND03UJUW3ml|>)#h4EJEira=z?jk+u^ZuNjF#+*k+vU>k3r+MXr;#BjPl4kh|%~l z#><14H|@axZuG$4&_mL}ja87xM9h)aVuW1>)E5b*>J#MJ0$5U|AT8a9`x>LER7VNx zL_ljcL{8F}ItqQhALdhC5xN>Uj)p9LikjU+JyXz!GQhWXjQ^!jmj0l{63k)`;u~QX zC^H@M=|i+nEwoa6p=`VXy8MRO-!rs<7x|P!9i=vyg)%LMocIB8kKxz}>U@Hl>A-D9 z(A0oj-k>%|Fg|QTJ6=W3Zt%S1O_D1U8N?a>}mYZy>7sb_n^I|1}8 zFA&+J-a;bA2cTvx1jyPQNg|x{4bxcU#14$)Gp%fe$ zh!rlBrKQ0e(kw;>oS|&gLh9XGltTq%AtP#%i6;bPjTSwTM^EL@D5NP2S_m!rL!Q7F#50-^bjD;orU})rAmWRUeNzOO1B5S?jWSg6L3i$N|=dqrs7Hl zUT9p{Q!9W59<-IjNm*MYN8RpH+#b3&MmIl?lNI?e4AoXpia*U`;*j?HgK#ok6|G?W=*A#B2zfGlX%<> z=`YED>5y86MgA(Jr$bpw6^7*zR+?i-HI}|@2v9sSca-FlG*hGtXHAiwCiOUJhE^Oo zN}iHKXj5q(Dnlxg2VjYBrJN|xHxZ+Md6X#;`H46*;NVD1J!l~HTgij8)VCN&C@pHO zMJ%ZY3%H6eoDWFzAZb=4%|InND#<+tS0X|uAVe{wn24~6s7pzNl>gF}ZhO7lsn zcSOR*pcF|+Nr`)+Fjo$xR)St?{7NAu$qB${{6a~g@L2@EO`?|^VWm1sqdK4>3e)8Z zYaopb(#RymlX8-1DTS2!H-)pb?hu1RjptH&($mQNK!JBspOoYg^*>4}jd^OsmpCrT7uQ)2hOp`NDEzB{(r&5oQ^2bl%SxPY)^554m5>~2bw60RBA=E`0^`%*sl%AAI zBpsuU9;sAP3rOXOj4+Xq5~oR2lKhZ+a7gk^jF zMV?E~r2EJd>77)bNW92%>0U}H5+fQ;8g(4_m&zlB1AKeoRV037T#;f)JyZ%6eJ`D* zF)I?fD2{X$NjnlYl5%7|6sbq#xs}2d2#utai%J=(nG`D;^IuCDp@$psB567b&yw%;_j8nLB!!8Txv2b79O;l^ z6>q{ ziMF;BuBfb$(no3_l_64&NNkCdq*zkRNAi>2{xx>JfP>T}SH{O)HXaq@2-bku;(uFUq+nm7@y@^~)ztQ*7 zS(15?zi8~DIMJ(Ui2pNZY2=6=lGOhD5qTEdtVO@l)%(Z$VT(%m*QZ5ykrGAbI+1!u z=~UEyktdOme-9shR}`x#t;m%`KPlGV)BD%^NVq5!qB%ulM{|m_MA4meA1#~o^!@9i zP|{VTB_%$JUPs;+{YFCk>wPqibpAUx{x!9tJc{_WD3-+kMZF;UJn}Sh_kItFUPod? z-$&2Ua{M(^^seY!BrBrNie!ZJBq9@}-{`kk4?k|irz-&7DZ2ruA*~_5M~_zRk+CeXozU6Xii1< zMJY$Fq!^J{k*lKnXvlw;Z&8eB>}YC{(C_E>pVE!Sh}P`=IMLetyL|p$o=7|?wW1XM z-BqNde|;0JiPW=zMn?X^P;Q&S(?$36oq>~ZuD*BS)@MEkkN3_Fh$R! zZ;GBsSAP!|eH%Id`#66M^UvKs6!?b%|N9h>W*L!GqO*+XyyNfp(K*O}dM>5%_jg5U z6oc|i;zjycdeBY1#e#wizKHd-U-?{$ZPvP&m{a0m=sf2q$iQ|-oJW3eDrzr{GZ=NLj0fnjh6KPWSak^ h^$!L9p};>B_=f`jP~aa5{6m3%DDV#j{{KgT{}15`1Bn0t literal 0 HcmV?d00001 diff --git a/extensions/assistive_harness/phase_b/assets/reject_wav/orient_sideways.wav b/extensions/assistive_harness/phase_b/assets/reject_wav/orient_sideways.wav new file mode 100644 index 0000000000000000000000000000000000000000..4d4f0b04a08a22996c7686c9ecfe316e2d04f9a8 GIT binary patch literal 117164 zcmeFab+{GP_b@&)r#o(6y1PS=6hT@-kPxJlQbK7FL_tE377&mUX{DvRJEa>gH&0HS zoSENRXEUF3@uT18`#kUOkN0^W&VFWQ$J%Sx+N<`y(6Qxv@2x#YQ(fNquvz~hBa7N8 zilQML?MYFS4p0EXLnyUKT?TMqP_QX+g!=D5pyJR2RN&&Rz7F@#DXjJX!cUed3Lo-QQc8{t zKP*?i2u0!~rljLg1opqv3dVR11@hm&@s{(qiWpx1{X2&LE|LC|CCUFD5C|d3^Y3u~ zULyVj_J7LzcMSi3lwgbbTP5-QIse?s-{C~Sl0OgQI6MCo6zrr<{x^YE$}y#s=Ep*K__StocXqdaZv?<;SOt=>PnS`+#7H$MWwz zC0E%$`FA0fDZhWqSIXaf-^{?98TjAKz`tt+ik|WJucDifnnbUNzw<-?z5Rc0>+g{H z)34Wxr~WCHzutexN#9=2k7FUa7?zT}*P#`-*K^}_^4BAAr3R+{{)?9>ZT%hM@9B6A zrR2YJl#(~!H#6{m=M4Ox$?gAbZPYN7@xQKZDB1_fMJOeP-~3v~>-h>cgm}G9emDh( z0)e$iUjA4-hhSCG@jky^OR1~CDQV@KKR@0w<`Rtg@hUBny054H4Vpk9W+nD|Jf8a| z_GSj&%)px&crycUX5h^XyqSSFGw@~x-ps(88F(`TZ)V`l47{0vH#6{0Gobish*w4N z!o=J+e|!D?gpr&l{`VOkIlIgMMi_DmsGMMma`aVDVi8D_Cj#Fv1pLNhBnRJ0O;S$Y zSeKL_4os16SPnrVb{3o38 zamLSUqkw_55rh^6nU}d&5C5O95bKQ)>xnW(oN;B%@J@+=N}H+VRQmSa8AH3uysXLQ9#TUK-T0QD(RqqXpbpn}RP5j~1}$C?f;| zrH67-Mp4qMnMKUPt8w_D-x25~-mcNcYMEj+^-$LcX$|CR0SjU?L2Kq%o0!5@D^kVepO&{t%CHJ0+I!4=+4NiPs>b$9kl#{1x)A zLH_*waqKO&NPh7%8XQ^thdTmO2#s+vQbM_5$dh8TO7?&N6ho*V=Q;wggodK8;KH#v zk^m|SWeP@RmyukgQ$oE+$>iZ>7AP(N4+a6~0n;(o7_iI}gUf?AdEAhbC+Ea+U2<+L7t3-W zo-1d^a&ls+Jiv)LB$W-ZY&k1df_Yi;OL#J4@B}Isax-7SV+lfF$bbh^necrsKZEB* z?EPGR3b9N`KZ(VjK?=iDNI#Ju$8w*@k6xu7Le5hN2!&V>Peu%P2ILT|SQ~qVVPhw$8w zg$MEjNa2Hd_{JO@H`aOt;Q>5PU$uZ~#Eb1bg*bu0@#9EID~};Y<|_mGo)udgGS9e9 zq~{1ta4NOP%wi8o+obmhjjMtymGP=o95GobY)6?j%p>!MZ=5v@NJTi0nK0W(BS=LU z%Zml1E<#xtL#jfmbpI!gX+nuuM(SV;ak>D7+APF5$A|t#B~pa`}HTh6G#8O ze2%~pUP$CS)*)CC6Zz#&lQ`kjg!ALQPUTJ|eo=a9VtJ~V?9s(!5K1Q^I}idT8s0ob zNK9iKIX{6yIff-DoiIl5sUb~p>0&vUk2vEuSTT-eCrC**FUn^OmRIr?)Am@v zJd}vmSTM&RFpW7*%JH9oQrZFmB`eBL2b3#th|3zQiTTc0Jtyb~Bu>5rQzDfN`a=qp z6oX0t4ImjpQcQdFuC{+aB1tAoIZ{gS*Qw3f@V16M;VOjq8ZI5TOjD6V#UQO*Af&Qs|9nP=s1Zo)I7s1}PKsQCq`@ zP$1GR!GyV}g<&8y2!2H$BN`aOBLucj=$+6!xig)g!pROnswa99xsyyZuKc{g|Vu}+-B5IhR^!q!liQt-xG7oh}O!5pP+ zgd!Xd@ez)PT$k`)Oe3emfZP~=gagWuBDq+P)KKyW=Ol3W#yZG9u^jP|o|9e>oFs?z zD*w1KpFG$a=>gH?iMEKaSdL$1y!kb0TuZXrgwNs|1L48s-a5h~ZD1fdY~q0T;meVqesGP^&`C7$1bkH)=VE8}%n*6CpK|_Q`%Fx(@aX zV`$$aEb3Tj{VP^$5O83xh^4{;X4JD#<3`OY6ZA#Ylu_S(Am0P6_+IRNA5!<_yYemh zhJ0PVCSR5>%ID>?@)`LwgtHJXK+a|PihLEGYY_f|a7(@e@9VMLYx2!l-e2&&Dc_C- zjNORk--LP>0NXM7h`dkUBkz{C%A4gi@^X2FyjuQU{!=~(B?qDW9MsH%{ff4w2ej@> zkXxD>LI1)WV^Wx^^hZ=}Y8|zhuENkv8@eu4N1iTyD(#ob$nVI4)Jr-bekj%vyNe6O z46&{Br<5SKkw1|~%5woz1L`3)i`Fuwn5Xm*SnS)BOtq&M($neE^i;|ve=WC{d&-mL zRq_(~bGeqRlSQeJ+(X_3D^rGQPIaO_fTuh41+|zuPCcgXQ@g2&)Vn~ZM1P{FXYyY8 z2f44@Qf>tOX#?0km%o%p$>ZejH(AQ`9-Ws?;s(g0j42WEAT{F}T? zUMT-4e^<#mATPnfMsFuQkP-7wsXt;SVYr?c`2 z`KWvdW^O<9XTN+HAWy=~UWFC92Xp!YXo3f>h};T$V2kYyl;Q^9V>0N^9-tJotR4eZ z+=6~x0%|x9?`yC+4{^+E593h zbOfmCN~|}C?IrAi0ANvcRKjg>SE6L#WB9UT)T>w^XnFXcjwIt>Ug=}I-2q&NXlBSc zP?xdCMuc*o@aVWsuYnrK5m8G-&8`qtoGL|?i}{~Qg7>LNEEIy06o9fo3j_ypThcqi ze^Fme0GM=G(L$gN7Nbf~C8^SYt0cq_Pk~rpkPj-llo@6m`JELoBR@tiih5`P&>u(^I%tXLJuOhkGRcx)4AgIF9mCnPvy@Q4A|2zCBq@Gc5-TOt;U$JQCkv8QBKtUzJ7w~#_` zhRAG_Sx$qQC<67#d=Q+)0UNO-6l($3n5-;P5t)Co+PIEHp2f$8ZKJ(_QZW_kAw3|~ zp!I<%g}RGF3hAd{tpB7BxDv!tAyy2=k)APy_6^w$NJH3b95qrmNt1Rk2dOkpfk?w8 zUgZ!R1Q($KoJGV`4Bl9`EbP5Qqgt7WEcLo9d7z zSSwMLp}Y*##IfTTaEzok%4{e*5vc@2oFkNg6q!pLxzakWkwQz@1MCx-VX}uw&y-wc zP7xEK9)&{Uv_x=YAIWHOWpHiCYA7p(7%(WDPFZinL+n|kGTiG(3rH`xcNIGpV_1rm zgfRjUFIRXIv6{&)SL|O*5j&b-AegZQg{Kh>RN47N=TrC=@&x1oxQB695u29ivP8GT zJr?I_7*of%#aDI8et#OP6S}sC_GzF6I(# z6z$Ud7AS#1EfsB20!3<)H__gaa}fDLBn7cviFJ&15vyWTpj<*&Vkw{{f>Iq}(PqFj zO00NLP9lh|OUESlzrFsc6fyl%{=eZM`JimP`VkwBSZ5?lu?A6xB|0zKgybQ9Gt_OB zlPo;Xil@-eh@L&-byU7YCno1m7$-h{JQ=_gDaA7Z^eZYlG||0D9)ZJnJfJ>}UQE>E z(Wi)|n1?y2y`#4ueU%7>Fc`?`0;W(OM_dT4XyzoXv_MWI5Q3Z=U>&T9xD`u**a^hq zAW)wFK%u9U^h2pd>XV+39w2U|ZzPALurAsxXtfZ_1??7cZb3?j<VHtCg^cOwJ#4}C&;MkH9!`9H-Of*Om!?)54#7V|ZdWLVrOGZgXMts!dECz8a+9>8@ zO6eEr4ZaChGJX5C!TlgAL%b@x1_(yj3cgi99N2X$nj)~(4?}?`1Qu9 zB2GVOd6GIxEkXwhJz=A+wDXhPgPm z7{d`D?c=#I*>~i88c(swsa|~7;$9`NiZ@^36vX#~o+#yf0M7w1kTXIO!!lAH=NpKV zK$6x7Kfyj=S~*!z&djl00vE?fd5Yf|7>s7QV)Xp%VZiTuN$tN+Q11h=X zY(UYlh?a-7u!e$#=yL=cYG_2yQ*Z?V%<~ps^HnIy{v?-B5ub{Un%3 zAO8D|^_1}`xUoJ4oF6geZuaMoP*tVky=mbrcNBm*grZQABem9$=!slQTwgu841PMnyDuoda?VkiiP7tj=e=fF6@FE5*`S+8re`@1Djr}L`_j4Gf zASTLQy->d4Px)dTWgq^Cv{c?`E5uKqFc)*ksZ%^f@`&U|Z9(y=D_96-(LV@OydJ4bv;k~c(F}-gfHqD3K+3T#^y*_!;NtZZ7%WpTl2W3(C>jiE zEsAbKbQsiU^5>xjgF&%^NL+y-ryL3v0z)hle4`Dcq=;38+9$acg)yQf5(|f(_KqL@r z2+Qymka9x^znCIvEK>rW?ZgB6>GKB#ir`mp$6HeH5&UszY)xsA#FRStRca~su}HsO z$4+jak$J$mQck1Dypj1*=3cSNhy{cxVoj1cB~}-)+Yo|SM!1&5##Ag={F0zpBZQg= z{SXRNs1j3(HBY{z1g#RqKcMUz<%=a~vyd-B)ht>kx5oBMJJxgveksVKX%j+D5 za1!Jy$ORQnmH(@7&iEJkvvMz#@ap{BT9FFm?1D%VB8P}XA(Dj17DdvaSBdzcFore) zzLkI}lv(kBB`EKR+{CvMBeIi}6BtrPJYeWuBXStuq#m&~;ur`fB3X zY(Orr@M>k35RVs0#knxbN_Z~bFpBePlCM})#EL>2i~L0drZGis{}9Uy z&ryhthW48hLmv{J!6;|4J7 zY!p8UIg!H@Lf~m6Ii189IhDk7NxV})PAHXJ{3>xJhA00RFdy+^EI%BodCl#&=Z z6D8+`q-MMn&nwA;<=9u{OU4!VT;W-x5{Rb@=K}p+7|{C@pBscj7%aty1SLgsl-f!y z;*}yRK)fvI*-<<&WZiHb@mw%+@HoA47e8&ifBi;8;N#CGzp@$Df^rLAJ_r0l?itt zvR%T=m*5(jyLGBlvtFgEg%f$#4S|hY^WzFId}sI@6RI-3xUkI z1NVJ?lNZ2Ur2%q1IYq7tHJJ)p9vOe&dv0(~3>_q|HO=+4W7L&G(K9P1v zHzbQ(OkOIh;VxM>>K3%sgzijFr3cYp(Y@)xbSe4@brD)^LcNfu$&KZpv=jRHq0~@% z2i`rUVbTIgC0pb^aI0(+*is2pHMpzLfEqw`q*_rQ!tIB)KuD;JODj+|c(R=tZbm+=6-E1Z%TPo+E!FkA<6WGvpEQodx&ReuEX+12rDVcq=m< zZbrOKb%mbwp?bmSzMw`^L#TJC&d_crxGRwid*~(5*e!X7yi%SZ&z6V5eYF8_7j7iX z);x&Mg`0IppzYHDa|3h)l*iAYPnn?KWkU}y!kw|J(5H*B+kzKhMb1NPAKVn&A#aC! zaU)^OE#+#mLw+n}NGGJ5(sKv}xil&p zcEU55+pVwKVekbtlG;lhg?;0ryp(}HLEWI1P+!A}NU)j{a-_;|53zt;QyvX_aHIT-d>rUM0q6y9qqL*?!u`djaL1(q)r@){b_WkDz{3ih zgtcD;yEkNG<0CzZlpm=HrrKWSKyVO>| z)(v))A4Xb1t|;G>7D@x8fl_bSdA+4w5-mriA#i84AlwI?NN*fMq~yNCRHqnraU--VSK86Wl2325~LOcop>k z=I~44o8#m`aC3A4(DOa{6RIWLH+@N^f&fSY4k5t|{Q`YXrOv{>odM9_%9DV`qH+b8 zv*Ex|IO-{E^j6RWzKuhgl#A{&Xex=UA9olT_FNy}P zCsH1me+PY&`Uxm|9&nUIxB+|(=B+2(%T19DzzGimCtM=^0c-4*u7Q}F0;{P5DjP(t zpse&Kv>jHWEM16B0N%X~Rs+uw!$6t8z*vW9zjXDG)chIBh z?(}?m8eo40a;yo>!OA`WXH_ejThcOVJz!x)wbW8-Bz+-eO982Z z{FPh_=6C}1aV602_aK3Hz^ruwDp(4%b_8ZV38>Xde*;|m0KJ>$Ko+=wf1js6rw;;L z0Orpv4S{`rU(6MKA}y(E2aZ-2KBRgT=4Fqj34ema!qH5EV>67#=7^?_l-w)cxQ{b>3;JX7smQImw z!%g{3u-a}(4?O%s&=?$`M|1^lSPn+?IcQ|17?wT+I3~hg_kz@zAJc?ZNgo3**$Ayk z(q!oEr$8U?&@<_c^cgyxW`L@`1)X*ZXacD+E2RLhZzQ*XwLSsVdL4NAHaT6+mUxim zZKV)U#ADc7RpiHV7I3@ybW0|eDXbcys-t?$bYvp*NP04G$b#}$QWGgd>?;lyr-<*1 zgT%5R=M!L$kEhx~4=v0f=6hxpV`i?=TYxLK1g&%%w93dF@Qo3m_f&+r?FPG%q5VKD zli{fZv=s%J^#O#!pj(}n4omZazvMyB3V~e7fSD=^a;FS6j=Bmo{}XkVDheEnp|8P+ zMQRzWQ!404F5uSh!`}ZA`0XX&mwn|dX}MG!TAc!GUKn)8D!_#(Y79vDpJC_k0ljxT zTaV zfj=$=EiDsdNgbe^g4FK-^9$_$ru2vOIpC$gQ3rvOG1No&`-+y(`)VK?w@Iy}DnNOs zKqkr3T=4mTWX{|V6Oz57Y-2CGs>zAinHz6bu+gxUnu9|Zn>5oGTRkb+KF z*}>9fakw~L945Agzx~)K^??z0phnUanGpSg9>p|gM$q?x8d>>-R8y)hIi;uK2Jvke zTZZ&LtnL_?v1ULOHGx`Yf<&DUG+P1mo^^66?9h*>EiiMts0fUM0&aF5AVleoR2JG! z2hDb!JW(DZTftf=OnK!_prLJpF%N)U`3FF3mwHGK#Li+taiX|I6vR?6;ydzS*zHO5 zd-MRh2VI*kPd@^FasmFjq9}D(t{k&81_7720~+UCkPUZ$YIXwmn+@7k58yVPK}Jo5 z9?yYxevubRXF;l87Was=p^b%N57@~sr1kPU04d3 zNmf-=6;MrPIx+Lu&pc+%tF-D7ss~I5RbBNO)jj4i^Qr2F%Ax*BJyLB{_f^-?4A6X_?xotmSeWBr z6`hwY(pO+n`J$tvQ=>1U2cm1DwZv88WO1fALi}F5A6*nljP#D|i4=$w3YQM|4*wA@ z9(fj-5&b$kGrA?3E`A_VVD;Ogw;~TB^`ouDb7BLKHqYr=>aLpO+SB?UjK@r^%@xfW z^Gs7I6KxuA9A~(rTc#VNZ)ezKXk_@pFx$}E(AjWH-#|Y_dtH4|Rg-B7} zgWCcd1Y@8_ph>W9sCHzBG>}=XZET!pxoe-1P$zkIN@~hS$$un|VL2-Gls}3tL0OBIToH z#m>@~;{8aCa7JJ?-;~?Q3clXn*`Dt`oLh8lcRg`Eca3u&^L*|r${yprp*!LYs;x@Y zRL~DI4lob0T(^|9Hn7gHuC-0Kf8%KB9Fw>@v1Rgz^vpsp3V&T>TCuG~&Zk>a<|fZ` zOfsa=#>hmzs<&X?>D-aIALp#it>RrL+z*Y2d`itzwNsq|t%0IuNB0NY3;p~Z++*@8 zxJtQ>q0!NnavwU638+8P{jTq5oM6%zdl?f< zVbfXDV^h#_*_v$oAYo$4i?j`C9~3-N>~<+{$#KQP1=G`?B$szgHx_5^1($gny2`sA z=1$JsnR&$Z6Z?lSFWitSrirTiXo_ertNxOXM{b7x;77XK=JwAE=N-!ZCU;=o%G_GH zOY&~JySvZiW#zftJ-j9TF0OS*C2p0EGG%r5jeX1k^M{sk=9R{|hN*@shO&CCA7>4$-$zor+%JZo3`sHJ%;ruC8oP4%afM zk9;O4sY|QxFkh(VsSnd1i)^@6xT?^=cMA?hzHq&lJ2mIioQ~N^SwpiuxlUJI*Kqe3 zUrX*&;Yo-W2U7#+3aWJNTHOcwLwbuoLpwopUvpENuK(Ro*>v7i-}0@kal*yq?P==^ zepIAL@wO#?FZOYv%4y-m#n!!=QW77i>hF?wId_%oH`lbhfV-3MLo`PopyIU`^@H^H z^d3E{p{V*%UHF->+PBNKCU~?HS71S< z(iT;ox~gWEYCcnynL#&TmZ(zI2UY9UBlR=QpW7xm)JYRle^0+#uu0L9CEJ(GDORUY zcB(hwiKVC3CAow_om&mxJ!9A`Va9lgViJ5r84v)<}lqFwAX>md-N!3 zAy|x$spE7Z^&L%LZJw^K=|`*4p6O_mv^7B~&tM6%6YQ9t5r3%Yy#r2W$;iuv4;st7f z>U(Xf@h8hZ`}4#rDf+ap(l(@bD|n+|#lo$N%_?50NbeM{W0m==W=3>0f5Ua*MaReH z=cTg`=O%l)1=}#E_1&$BN$pb$ChfA9wsg^_Qr`sn`F7qk-rf^U1*WWV?P+H-x**B-rZH(yT9 z(^2LU_ALq16Pr4YSVkDvGd;ouxQf2ct}0of7Ykk-deQJ@qs*MF?5z3OUGn;Rn);6T zZG4yDhmmijtJI&gPL-)msf#IoE7y(zmWc-im2D=c9=@oRyo%vpGrHNUOIhZ zx|o)jrcaw*s8!J`1?whQOewkml^R;?J(2VB*|dj?o}A2{;7b>}O7#rA?Z*=@rFJjK zr=>X?o31gHBj@}@+@b7A88e>-9>082wW)p5Hm34v zLkeyxs7>5!tfwie$_PL4^vGnN3rKlyIr0cRW2Th!>l9^bRPaanUR zdS&!|IW%M0%j6u7dw_diUKzL3+uO6vQI+#mI-4d}NUfK?xqzIuESXQ*l>B3I>tuUc$3o>&jh2zBRa7)mkL7c= zzj*i2h5KipkMlkXm6GPGFImncCZ&!{>z~><(QF(?FAnWxTe{X{mCo#zG4T1wXXcFE z@Mj_Q^Va3vcWrZphRS z5ur8VE|DwJOXh@nfo8BaS#zF#TOKTl;`(T6^b^TT-&If2AGF+c&P=+NTqCV_S|H_S z%CXcjscn;cr10s33ouFTjP02|(NTiV(=#jUh34sx&nDzLg+tK<>bkapHOo;X@xw%q z{hZ;UYKmMbEV2u{<2;*OeRJk!cF3%n*(Gzv%L^|rW!}r$<{HAEiqr?KcPu?dJxY68 zo2Ff;nk26lzY@DhTfsI)YVWM6u2UH&SyP=y62r-5QzoQvDgDzHq(4Zjn{qyhNgkgx z$dXNW4_^u-vcKl^01lj*d)xJhyCDu&57O$4^=(U>Yiut}Lk$9f+-CV!M%GPQK#1H*nP94sz$_j0a* zIX`9X%6yWSBea+HF!gj5jenWinaf!hShGwTeQ)Mo^sKOob$OkxJ=y0ou0DJD%>80Q z76p?3yl1fQJ9b>4xTvRBz+e1VRW(6Va-F`7PBLv zR_g4uU(??!Af!D^>65Y`eNmx=LbcK=IJX%)s}6~O1wFwTI!DdOPKh%op0Q4)$&Tb#EDW&%CZVMRU?~j%4#$M>F?k2l7hz3J7z; z26+*EPL-%_u6>~H##E;p$+^*bkzJ7rQa`GQs-gC*zOreh^*8t<-k;L8r@fzUfMZO3 z>dw?j>0Q#tq>f4$ZZ57lDy|Q{&jwsgv)X11%~|0)9O^3PsPF4<8YAZ3)^zhh?HSrD zmW_-FEZ|qLH+;W%`nzYl8s`nj*_mB8yJYt7S+{eVxR?6o@#90O;wotcRasR>y@9zz zT>~rrA;^%&a&x*B^F;N5_ILdeV;jpX$Dc_{Qa(wMQxeiHr>#z1nRdCrlL8;4p0hVG z%~sEnoS~-N7;l5zRoVAE6NF3R0r?U$K(kBttMQN_O;=7;g8p8*6WtybLRAB6`4n!o z-|C*7QzC15Cig=9;@1~tvMamC_zwuV!NSp2QZFW3eNVNS+A0O59bmUK0xv|En$CQs zzM`$E-(-Adk(_6etE7xbzL3&4eNh2p`nL4P=>yU#Bz|q}W6V))j8+Vc=j!;sb6@eC z6%wP(z}I$7byIsq*HO1m`@QB}#sz-EequCKLwL!p<$C-3d)#?-a^K3Xo8`>>B6E0V z$(&lQZ0}w!H*h{uN7_o&2Vdzp8vlib8nQzQimm0v%oKG+tzNf6f8SKkekrj=%Jh`u z$wN~FkQdnn+ZJ4szAd?i{X640?FyO;d-%QnN>BS8`Tzo0Kn7cBdw#e_Nnox(GVOMN>0f z9vz5&8S?PW{Cj;iep;lJv{RO-8cZFg8Q7Y|R7d5BV)N+l(bJLYVROhBtSVIEZumEP zJG<$;(tEBEpy_f1r9iQ};BV>x`K2rTDrA4*{iwIM>U-`c1Q|rODuPy%}Il)Rz6hqOBNUO+eC-Rf zg@liT*F%LOZ%40-Ya|<3vRmca;48XMUtprDcAAfM)r>VQ*KB7UXPm~wbBTwN+9sP* z_NM4k)+Vm83+4|D?`T^yY4VB4ro)qe%a#R{Be1qZ^{dqP?S?qdTHo zA{pTs;Zc#b;lxmC;4HtITgGPkQ~kTWDc)pXTYq=99=DHwJCG54JN#+nNaT}fIkBWP zO%kPL@;z!Hlc;X5acYa`&g!d}Mp@2Vv#qmji|kpBj?T5tPR^>1nl{>U*Qn9g*W|*f z^?3Pvsik;d>?4hU(}I<7f>=^0I)z=~wS}76X>wFIn4iI$uBOcLOYvoNP2@JR zoE^s+!S3$JFXdP8<%Ni_4X$Ag3wndUhW3Yp5gSwzP|j8K(Gv1m!Lu{1}1OciB*S54E@*45Li3@Z#vj7Lnz&A(gPSW|5KZAI;M z?B(qPZMUr5tshu3EP}a-`KIZ8Q#WIA!x`OVtwys=Re_mC1*8t57;%NygenD}2rqay zH;!%S@8TQm-R#kNGTa)E-ZR0|#@oVI%74%AWj)*szMAk%m>4J&6oQq*g(8tiINDNL zD;J=L%@%`r)u*$#C(cu6dTFp>>P3sBNRImc57FVsBxaW36g!Y5mo*-29;_ z+t|@K+wieIqMfWMqi&$uPiM&o#P_1*B5#KS!TEtSp$K1!dxy38wZ7Wkb)K(0i#@-2 zhImBJEw9->&;KX8pWDc{64C>|1rmY>g4;q@!Z#yA^uCxTkE2XXL)A8Qf_A2EoW6nK zm|?f^rYX<7)6&TL*gDwevlWB>d}YhF_O|l$q>*j)ppT*rZ%V+ z(eveycqY0(@=17Kuymlbpyq>YmVcLTjdzD<5QL_lww}|TY2Hb`ihcuoh^@nMT$C4t z1%YTFC+G57PR;M+_XxiQRs^4iR1rPgZU{+3sKazs)jjn`+GV=Q`bma$ z#!IHn=FyfGR^GbK_Ky9u{e*qJeT==Yy}tdlEy?zoHDu{$nPMJoYG8hMWFJRiJAHfV2&(@Wn_IagLNF zkD^mmYt$NTS)D`A>z&3O{bFrrJ!yGn zeq!2hTx|GEUq-i3b4HcQ%%YOyWnv`qZg@lRvp^%^J~xW}#J||L&uj6{^r$_<-1XcY z-Cw!0+|xXzy!*Wiee?XySTz^nstFweUkCpT-3gb9t`^(K9%?BwR9#zpPsbQ?3=fT! z&8sbYtix?B?P|wd#~lajxa6qna5((-)%N4IDDa~tmiy*v=K7`#;ElC)t2O&nZn_NB zRXPJY=*dv6peXF&dvb-@EZ%TD1^ z`QpOBz?|Un(C%=v=v@*1?J9bys;Op!me+MPTsPJ*e_`ortzyfz?YB2~ta2Q8+;9jE zom21p%rVLSo9&sku{FW+!1RmpV?!UkPIpk_R1b#rS}0ePdPFCMeZeWP=V!w|r?B7m zyZ5}u=9%J7ci(rNcj?_F-9y}u-G@Cpz3qL8e!*XttHw7HW(AG~pM+fDzEQ6T+@AWG zS*`A?y{z-=YZ^zJ&YRs9yDif;*WSgk&r!iCJDxc*@9J3ZIN{jonCg z2{e>`!ODT3`Bq$(-{gZ};W_x7SS<6`7Giyzg4Q2EjwH8fD)ew5K>=Wli?}mGXZU)u}{rNB}_;>q$@_z1F z<*w-7;2Pj+>l*Gl;cDtG;xTyz??c}K|5A1d$W=N}CD=H$Ap9)SMtmrJLe*k&RL3<{ zbd~j;4E>BZOgGKPEn}=LZ0+nN9J?Hn!{|Kj_}MYpQPWYy{+?}+b*W{Nxx1;h@s|Dv zT`lcybuCqI`iLxn21-S`gq{Vy7JBd%xo7_KzKz~pp1ba`?)PAJuDG&Y)!pOWwLK-h zdESG*-~9*KP26QZJunI6dx^-1=uxqzIVM-VPB1PzvWJI4|gATm+%~gT{RH+P9Zjti*f;85?Tjmh63T{(cNM) z$Wnn`q-vr0P5W4PNgp&6Ff}(fu_Rh)+n=^i?I-OCj(Uy+$7TC8dsX`c+eGVGi_fe! zUob8*G|`8(n>C%)$Cw5%Hx;Cv(Mpl4q2|GW@E3oD+rj<>l9cx*dV6?IxxaMRaQAm} z?$13w&u`udzK{G>*@|2WALa`OIs~V}O1UF_#A{M1YCcV?7N}`$Pte4^Hyk%UHzirj z)`!+5w(|BZFgpbuYR5`@e|tgu0^3&WBTEfS1GClimtm>CiSE8;nYxZ@2`z!`Qd8Ux zr#(l5V*?$97JN0X9NWyl+UM|f@$U9i@Z`B&?ljLZ&q9yYd(eBpx5obsJDi)s9~OK8 zb;uO15}6gX!ijNNdI_Ud&(*x6+pFJWSYSM4dThRK`Ptgq=C=*EKecNe+4f!b0d}9Q zo9zed3d=xqA5&jreZwVPGp$K;U9}EQ{<7sRQo5KK*%Gb-dptw9!{6h0wlMT(gRi>p zgtv#cp0|>>m-kmM?Q84X;Ct6kvDew%++O~HP%bz>B!=5Z*NFkCKJ_Dglc}Yita+hL z1UhbK{04T_QP|@rZ71x%IGQ;7ImQi)S znTyVj*dyRE3ps;Ng`KdcW^;$xx&8+JbH4GuLEgchi=bUR@eS}l@F%h**lX<1Tr2)# z;KQRsKSzp+b*1+5cB&~eRkcCgPt#F*Mz`It!gSR<%Cg>4!TKqzk;C!SvBx~1?04)({`Y)Oy$gILSc#j<4-tL`&8tH&BiJH`aJxDL=jyH z!*FA^=?@ESTWPCmt7GeBI|Q6>gR^dtkSIY0wfsfUrwZrxEjGvh{napOv(%II~zRkAY_LKcn$2Okbgfnh@Z}{ zXIJ^HtO?HMHiyoImV^$4mPS61CQ*x-?WzLm1kE;0wr+`GzG~Gl{ z+wVEjovWPFoXryK&Q`Y4=1rzPmciz!rfJ%js@~ME@|SR@@3OQtGCQ~|&?RtLI40B* z)WS`!3fmRN{}EeTW{pI{uS*_p*d>6PK{3LuXQYW%I zI$mB(KVb^0Cc>WH17~1|jPIE`n=YE>S^GJfC){-$ur;$Tw)V33a-K>UnONF6!J27E z)-NzzH!Lz<(_L0Sq}EBd#Aeb$&}e+YErDi1bKnml!Ufo0*mCS)b_>YDx_k|8Gp>yP z0y~7?%}wGqv)TT`K-aT4N;nv}71|T36B-`c5N;~Xphv1Ysx|5`cv*Yuzcp?#jWd_G zjIvI)?*%Ppq;;rez3rOwO5*IKu?f2zYRds*FT)_yHp?2bV3+{^i0Ol9l9&LuAd5u5 z2@ehS2|N_CI5X$+CvnGtpQZEHI2~6VI89ZbgS*Rr8dxHj*dM(&+>QJuK^3YWEF)Cs zv-v{7yP+%5(~^;H$Rw%Gs8*>;YrfUJXFP6NYi??(VU1Xe+FRQn+kUkDW?SJHmQW_~ zE2rJw$acaq$o$awrE#mNuCcG~6V({-o}Z0U;!4RDZ5|2=1Nd8j z8_aZ+3&ZLEj_AthmasQiU&w%y_u-&he$6cdo>Pl`$G^_+W><1%Udx%d`fMTYAp5{? zXIHZZ*k8RlFT0-mR%j4j8~P(OI&?g`i7BL>0utsF`9b_t;cB2;=yq^! za6{-pL<>8;ue!Eopt`zdlWvh=qG_GEgmo2IoSp5d_Eumg6oTFLMS?#uF{xR?7JI72 zYn*JXYD_e>HVrfM*4&lSBTGX)frp)sB!-6u)LdO|h`$%>^40Ut_YdJV2myWJ0Xj2$Isyc{?fi*eVM*Y|7!jyKSr3s?O|JUP5pJji!xI<9DFBW;aB=^ z_y)4zMhi3#e;XPVs1z6wJQz9?Su695TKyb-^P1(lPYoN58_XW7XuD}^YP$>G3(CII zQ9ognvxH-*ZI$Duv#&E~D{Wb8EUaIs?WQYhaO%ADtnhU3!d(m04~`1$3oK-t!zKCR z{)4_m-xW5>l@wTio_{D;Q|QM#xrtzrU*S9PX@PWMGuMo*%2x=K4!jjO99SA$9J(Fe zCf1?~Fq4@8$ctX;QTo-Oi<&GgEH^FNEi#l05+N4>csz|U-n zKNYy+Kz@$!Szutm#j|WRc0Bi)P&RZF^mT7&c{nrjd9;IEoL;H=S<_ydqrIxDYusou zTE4U#vv#+s?C;v=fmEMu|IyLkG1yt(QN+>RG0aiR-q70KT+`^$O;lfE?la#oL#VkS zHD8C#<8BB|gdsu~?uPFJS8@2m*F{3n;JrX!E&(*u2L5K;K%r15DWDfV;dKFl+r}-B{2D3mQzON0wXmtF>TbG%`W?Fcx)X*U%>}L3t!-_M?YHb#919$k90TlsIb6=6iQV821-}NG zO0{_{KUo@^HtWArZ=zc>XK4>*ilhij*u(xg+&n&yZ_l;!wfBAqI`J;Ho4*Wu+IO2> zDa;M{0?YY=!d?F{U%s(R2IyE75rE(M;H_6F5F@- za7%)z!OcQnzN2uR-@jUGPRfiGD7wkQ=H}wEc7$x{>;_#$o1Vma*18*0*h= z!GG|+qnfjA!mxz72`Xo8dpFS7R@(Pkk6E6ZZ_g#cAT`jPKgf*{o(d@e3M~4GLWoW0zXf@6L->>J z#rG5{2Fr)O2w#kjg!`D?byOR8nFWvgY9IK}c>>>XMTI}TTbAF5Ofp?m}1G|e`;7j&z z_kQ8O#t-1f2D*dC=>S;ifl#UN){v1O#?R;Ovz53?LbG58;TZdjT`D{YJ_s?9X3_Q0 zUD1$KTlKznr>?TDq~4`3ZT!}>#GGaM(elW$+`1jKwcd`E&Sd9#`#M{F+dH& z@65Wmp@Ej6?mp)kynYNAnlr8K(?Wg!V@XxfA3*8GI3|0zV2#Jxx@_JQRW74jG ze|}(^Zl8X-p{MaHQ?jL?^$Xi1`}g*?;Hlebdu|(LPjUdY>66Hjiuwy&c*VUJQ0e7QfH8+jGtH)W3~C!?)rKvEx9loEHWM_XJJBliYRg zORfv}po@alwu!yQ4dNPcRfHXZa)AJUJQxyt%R{Ahl8sJbcqU2HP_H-C(*L60Vz>)E z>uFvA-uibeFD*N4PwlH6g`F?#X4^AMHA`K~5_46Ut0OSG9vH`2?Q!O*G&*`Oax%Oy zTr*T7__;8S@6X=yZSm=W%1X1DTuQ(ko)OFnSc8_(HK93IklVoj#2@2-6$T2=S=zVN z*N>kZsvhnWo*#BZN<_Lwdr8Bo7t|yAITKM2*QpE>4Qut?^h5O@8rB+rH5tvV&BsjV z%z#)C`X|~|>JQap)N|FpP_^Z`(Tm|H!B(N7(J!NU zq1D1Q|1Dn&xSuu^cxM6O5w~2Z5;z#h1}UivWb;?Kk?cXXm2fYxFHl`r&y4`teIg`8 zhlv%V%OZ86i=|%FRNBN0WE!Z7tCO{V>QeP%bYbmT-6MT(W0HA{Suhoa+l?QacUekV zlPu-TO-)^l`wRhnlCGlGt*!xo>&U8FtNW@XMxgVgdE$_$748e$#L>Z7d}G1SHwvr| zRSo+B6NR*3YIswyXy6H)4gG%{opoFl>D$Jq=gdh2K@kDFySsDk?q0h)R%LD1TDx1< z?(QyJb!|lvOhlSflh4e1{oX&^^n-KGJaNZ$eedRhv8cPYRo5%W<) z(JE?l^lbgCF`T?464b|)sH^k~wl~*}&0>16x0r)$Ht&IAEkRsq`)r#iwXkoqD^erL zgD3Ke8*R_UngYj1^2uBdcU|0Wn=MY{?{JK;o?FS3u)08hI?=dBs=)nq)hY-zc4ecl zHcXii92g7@R#*CIP4!u7MzCwJbueFm4>rMnG1W+If?ks3G5*#(npf?KJMxM#0}AFe zV<0JN=}`2hP?e#{sBe{H25}`}qV2){!MtM{;I?sdx7hov#C_r}@;8N*!Z|*L`^LW! z@`?wA^L!fruP|6FBTckT!4p1aL}n4ZR@c#c9!#~TCHk{f4b%Jbn7hngBx8$&u z2<@E(H-(ew!^~t7;cO{OZ-Faz8nuh=!3`1y*lJ5HrFGIIakJ3W_M5Got&BLGtHxg8 z_6RSq3c|R(%nUf}?yx7>E!26lk=YC`kO=As-GW)cEM!_S+o&JrGEzi8tmFo}1+NDm zDS7qnMtx(X)>ECNPc}c975&{kCoVC$=v`(OuA${GG1D?G|Y1qN9oPxqX<_T)H5>=DM>3xxQRe zwm4@KR&Z~uQ{)v?;MK?p-EJ0zqoWX%Mo;*o_&h=OZ}u`(&l*ZtBTFl#oz^;NN7WOhFQ8a{@NAQv$s|eIFw&v_Cy?d0G&w)DFX*V ze{(!pXEkLX3X5%PYnr zNT|=}!)}^kwKQI7leDGUD#J#3m_bZ$=KI`- z3AdUz4WBWB9?FHY8=yjWnV+=>>R$Z`DTm(qUHAr*pfLYo)x|m9gdRf0(22|`HkqBt z`sfZ&A3TQ#_B$M7si0iiWCrD8T}&%8T_35fRZHu?$Yt|y zvd0Xir?So2{r_JT+Dl5nuhiZ+ixc6a;e#S`6;~ZmNhcv*JS|q|hEd6S5!@QBwe4gs z94TArc3cl3k7x+%xOI$+-UYAhDAJtFCgIp4TS$mimwH5hWi!|`oE0PZSzHe$#=514 zLnZiFz7(vXelliSu}rk^LL3AQiASu(YxrdKj7KDjJTv0VX*k1VG93<)d{!DXSmAIy zPN!4Ymi%Mh-~)U;-em4tM~yS;C%J%9SsO;aQf|19zrZ+e<4^FdgiX9gH!~L)2h4_W z)vPAnl(gVf<*Px{GE;#4gWgJQHJg!WBg>d(^6)uypvKV`*leMX_>`?@tuq>uf5=@D z14VnhTF-pKC5Y#RrhI_g$*rSb!f)5zc%#NEwRGAnLFvp6t`-+y4zX?cSoVVToT%hD zTvdMaBK*b-eSqD=ySXCtW@-hrq=n52nq9dmS5oR~56A**FO|d&u|+!mwnvL)*|OF$ zO%LqwjSo1K=jwDL)6&=uLSNf%X^hx{o^9OL|JIM_5k}BhO7dCBbOK!ckC;1bG}nOL z2fxHKvo5?RMd&5e7SbR4*-iC<$JIgKgEMO^oq^jr2ks!tSIRn}V*YwG0lstTI4&%9>sfvYgl>TSBs#+H*Q!nv7F@QAF1m$4;17d@Mza6c>~+escW zoMe)`)(xs0Q;MC%ZRNAMwoF57j`0k-o?FHNeYdtuyJ6(Do>8~xeRL{(AYa(#{C55j zcZazGkKYaJCh_Q-)w9Za<&7GOjHfI;m#M>55dIX0i+lOH?0dR5g)X(uqLUw?R@0Z6 z|8rz*g%j&CoQ2)!C}t8oF^#Co@b47Fztx1U|B6`yen*A;g};s7pK(;u23a;4))@C!wc#NIVU&&S*8S~8;x)e8^zYX2U6(L0E!4{!jkfYjk zWx4#jTwI-D?6XQUPq`GKsF)#?7oxfA*5CRE)Ynp#R$46d0-DvCN#dJ`tNAeYI-O$% z^*Q=Wqo^@fziqs*F2jNN8~mEfn5#^EW*l@1ovhu6m4;AfaHp;#E6s7(y$h+fc-E^p z<9os3Rmz+~7N9FG>w5_1(4Z3SXWsJ)bSi(c^{s}anpvD=YA2K->JNR4S(i!0t=fj2 z0tfs>Yl~T#82I*fYb=>SpWyolmADl833c5XXa-PKOjS>*hxG-P#7^c*ido`I{u#Z& zY(;t)AN7Lpws3?pcTf%3Gh9KwJUu{!nA^pnZPUs}AnTkB?2 zN9RnZ|D~71qtleW4GO^{x;t}}nZ*u3TtA&!Y<@HP8GVd4Mt2g8KgmbeV{|5oRoG+r zX`yTzdaJd~Jb>Q#cXhFLUF)uQG^&|{sh7+IzP)(YHpq5eIK$6l^IL|dAZ{!Yyd*pH zmE@LnkS@qtY$hAR-Qjj|y)mk%yE)J73B}bE_@#@$&6Q#fB#X3AsCc%K_SS1^HG{Sk zqS~F}C@z}HB2k71o|ZA{3w0n=BkN7oy2GULi-bC;4g6s0&=s&^)2K$)1ky~euBGX# zO#?o=D)8BTG$&Y@aN>TXR#W}xNM;$6#N4BYQ%&Gmx@rZ?>e%VajE1@$?voVyJ9CsB z#m9=n#AIk>gUm!zG&<=Ew8QERwVqCs$<{SyB9uj|1V0yKZOjQP+T07@(LkuH8jww9 zMXEUy&vxhQbN|7Azm=M4wKLz7d*%(&i8O~&dlQr{1z0=%%d8DA^H8{N%Nu9(QG{5> z=tm%tETZR7o#`{opL7wc1bm0{$QyFodI1kz8LJxfyW33{y!dxb)~rQLvWYrHUxV)9 z06UuXuyZi+su|s!8gI=oQ^^+)C@xr4G5P8#9L$MK7(0#WP5%Iw!vj})ly!hC)?cAZ zHx~Qh86_}d*}B3g$!%|7^F#B#j7BzKw9rlR^m{>$f6X@;K6ss+~zP+r5=3P>Tj4<{Y|Bycs zx!K4)Xxv^So}U9pct6kw9#eJbet7HexMl2aTDI=NRhNhexH>s+`1FNFH*(#qgLhnr z8P1ImJ_$>OkHQY|7r&D|&U9jI)DSa)d?N3Wd-$!n)LrU4eF5LgcJ2#zlwaTFY)b=6g)!K5SV839^K(aqR zcpY_)(pr5o&iqVznls_I9AvhHXYd?ZWfq0wdd2@7(8!q*;Lxm(Nac&wpT5ZT7*q*3eS`aGzBR;HrWgSRs=#xyEO(T91gi#T2lt>p zdOz?iAfr>^40ct%YMP#;w^o0X32Jf)fv7;hzr)|te><>LsjltTbp0*4PA=)Ap^UG9 zGdQws_dBLT;%HH z?&VH&7x4^szjyXQH~Em5%!lwzxRvZ#<{LAODaGVrR)g)}rZefo%pNw8+l?wgZ;pe1 zb1c)Go@A{g53tYQYKmG`Evoo}`=HB^-FiZoXFD@nnYqwRz2zM2 zReYLQ$_7_)0s18y$?q0Iq;z{b2k&4V3(;Y)1h3#0KMGC6<+csdc4?6`(cV^?C>9q^ z@@u(1Y%%T;A12t5xwjN6317IiTv`0o+RPL5QuncC;8#1&Z{~Gw8W+Mw(#_3fdM7on zS^-+#*2s|D^T4AlMwnZDSdK5*iW=zz(>NSm$;5S{dwlSkPkvq@!7Yd3;adzhCH}SRE2Xq`$ zh1mrH#GmvlxZXF?Icy7_=Bx70gq>nvv83n||FAu?&6FnF2RLTiXGz31#x_TM%g68x zzniQVXSbJ^Ri7@H{-J=8jn!>dL5h@bfSwf zA1KWQIqsY-S%XR+xcX*nYqta5{8g0&m*8C5|s;$in zMs@9*EC(Mb50(1LFlC6|3#Z*G(v7agP66TK1oI31jICTW^11DtkGsV`;A*o&m_GDp zoJq$~aXDsvHFC_&xo3BhF!52wZBG9?VG)kBid2R9&W!a`K3Rlc(IaL zLP+Op2<3zm!f0_2s%oQb8KNToZ7V5ll?F)X#bRP6|0jQrn~OX%(t3>8WR$Ww@Yc84 z`&Ul$EH!;<`ku5CX|FSKGq+@Uvto14`fJMl)Rx9Z@JhNY<&hu`!JadNB02Z zhN4PYm*IM6z(6=})q_5|CZf7L&~D4ZZq$wHi(kZEwzgQs|2Z-o4V{MLw7su{9A0{A zn_xR^YaxZ&H`s?e+M=?Ef`#L_W4NQP{W#9aPssEuisezai)L3*@uZFZNG+<~#p(Ci zS3mb$&c*D(S>BAI>3!3=jQ*LuvR7v}&F$k~6zq+j&^gVnAJBRj(+CT_(@WCN{DE7z z7wKqB(jv5OS|{~};?@V~rO;3BYRn*B;~;qnj>&klgS7#alD#ZpXi;G$9~ja#~$HW z<5=vR;cV)Na>O_`JH9(gI0rg5IGQ?RT$Nn0&bp5M_6N2o+b-b*AIe+o6*i1{Y}F?X z^&RR+nG3A-h5N$1^Kw^aU&|VjxiYBT6EX1lLP{mg!4@pDR*ZNxr!4W8l z+FCnsF;b{GI1A5$-lEW6hG7S@F0M7aN^_96>=ZwUn`{GYWu))YEBhkHP{((>Y0u}V z=ZJNTb+mI_w-2%Rw3oMElkz&^oL!wa9Utv~I(p(W%JyV?FKCK_wu81&Vr#+4|I4nW zLA5iVkoCq6ElHUtzYhq3SU>A4np-{F%oH=XW?awM1n2hW%z{~2S<|4Q`R1MPo8{}~ zYv`XGET;UYglYl(mT_J04X+zmVsI;M$8DDdE%R>bDdV;;$F^3`cHppvu z^)3*XnFR($3D6f7faP%o1d()V8hx9&h%BxrNAtJ&uEKL+hB()D$hN^2Eu~9a?1p{0 zW1e$>bC}a`hPqm#3SJ*B`YZN1_P&m#_N7vNDZi8`y^{_|v!r>p+O|vLpTd0fv}!0C0p7Rt+u3^~+u!;+3U&v0#NyxpD zn~}TLTg>;$x7PnOP(-e&lu{dNA$l|YiXH(v&}EWBKEnGm3j`GwJcA%AXEPAT{X{Id z6(k4;GN+!%2M)mv{06gCV>oY1dgY z0nQ$Zb-+U#!lcvPP$@mg48@ICh|S0T&So>?(XV_%cL9T;4c>1%&R`324Yw+19q`-1H8g+v1%5|lxvR_G4SnZ^CK_hwtQjW|a%`mCABzP=ktis5M zD$*)7p1#5qX6k@THH7(qc>g0Svz58l{2MMAe-GvQvLo40z8Bw%tIVB2_W6wc#ZBc- zur;~<+8NBQ<__2UN;iZ>F7h6871gd)N;fCvrzl5uBWIKjsC`KLE3c&+F`w88ToQ;y9}&xZLeJqDm&7H|GToHh%T-{LDHa{u z+teX?B3GRC(ktj=+$J`HN@N7~Upj_uMUO%Mdw{SHoS;mmH$TyeGxM`m`81}cQHhJ^ ziql?j>+Z7K=snhL#D)3InN}`WjGC@}G)Lk__yB%ROKXE!%S-}I>9Da2q{;>6Mk7lt z3${_JafEyzv1Wd75j#+dK2)cuH)eOuO}Q*P_hSdNxuQAjj?x!V^Blm0_!2SwXOrXCwG8&C$_hAU<* zH+OLs9nO@eMw*kEQe0!ImHC}|!g{Iqq#3h{O+>f&9$kRBK&mp4Y$uxFd%ePyq9+?! z^q<^z>#_ch{=|>M8f(J{bQ5G#x2c-+T63e-)jDUshx))xx^SAYz+i-tOj)_3b;EX* z^iZxd$Hh@_zbz4Zv!j)c#3NldI|O5CA|BRm$sM^dTmyBT-daedy}`rgD)F>cUu{G2 zT$pu4Uroc4txq&9rYAF7x2R&`J~CJ@&2D9$SR>3MEX(F<)wulZXmXI$LshJ;affu_ zS5h0zAK<x!* zL-qVR)6cqNJZ7HbjVEd?MTx3T7BCs+KC*(z$1b3nXglenLNPK^SI~F4Y3?M~=tGta zg3c1E7hTHCq*9Dk+)w(AdYZ{$8q<489_xSPG&kLf?8Hf)M7JYRW&!?{^-d!eBkV;j z`6=(Avf;^`%WR{s>M3S5<_Eo7TZ5h4$aI?7luCaiCx`=#&-%y!%8Q#wy2fJ9G||gZ zP1&N<7Of7ufq6~ZoBOEsY!_pg@qkaEm#KMZi>*L?Rh-NbF58ULG_12mW=tgja@L5DhMSL+mFx*_u;EdL2q{82-xq6+ z9aO|XTk0m54&~(IW^dbiws>$J$?KS4#RX2%rEP=EUBP*5j(wZLD2;7Rgh&2=4Ue>l zi}xoR9(x2;G00f$>^lrie!^DZrWnPI8$!C(P`<&KwlwXN`b3afqBbK_g|SS1Z5{Ow zDyMyn@rbQPQ#bIAe^HVV&$I)XD+9IXf^2DHvz0@KP`Ty~eV#auZW^q@^s!AdE~~$o zetadfsrr^XI~`JAs|MG*(}ov%cGS4#=o*tY5&-7O8F{l4n#bt$0y zAs-c9@ITNKZp8g7G*NxVPkJ-G47DhcD}xGP4Aq?bXgai8^Z{i3k15q0;e4!O z*9J?a8N2d?J}ZEC{tfXd%J~L7sN;~-q`2L=Dj991|8xZ-UPP zhn;8mM#19hH2Xh%Lxs`5^NDPAHAX)yJta%XR@26$q7vF!uS|vTlNqP}r`d`9PDdLp zt-1Ur>#@?Gjo_P``Sc~$IO#B%BbTGci3_Y<+9Il-Fx9*)FA`F@@ybARtAu?P7-Us- zd8`)!mQA%4C%=?9z6Bqxx{OIuEK^hN$TSc_O-=j2IhfJ!r-=G~G&T zMa6TOR$pT0x=^dN-P8>9W^%M}4a^5dDJ5<6Q1< zv^PcM(GkWKkTD<7CH0DA9KXnF!QL~TSO=+|_&vYC(QruTnU4Bw-OV>+bImxq8>nXe zSc+|79J8*oBj^z8sd>_@&CG(^ek3Z=KS?z6l&Ne!K^H5Wea564)95{POKP4a>ob`; z)+f@G9RvOzM@~_{xHINxtpI$atE_*`6=pW{R0phA&@!HA~nsB!dpOo$f}`(ecX0dDfHJVSP1@qfZx4 znveo)CB6f>Zfs$zFpZ34>pK6$;RdXu!94y^y^l^Fsd4e;hJv-A%Cta9h)(8?!pRksg@zhUd2%Q84 zNIKhuiY0FIH4}+!;f@&%4&^U%9o}#QvobY}`GZcS*Pzo}h`E7EbuH>7mu~*6KeHZi z=O_++jpAG~QQH(Fdd?M@IB@b- zQ&aI=Q%QgGF1Wa|QOv4F2dpC`4aDSeR<^l=B$!t%FJ)1+!0Gm&2iyTP)^JpeU(&r% z(RmD3XJNWAb=*8^iQt(&p~q7jEW0@c8iYnvC%PH^#%f0YLFF;8lN9T3D$cx%Z&QJO zDIJ;AF_4l!BERfx5o#vmq+XKz@JiIDRckT0&Te`q2-TgCcdY=!?-E^$?gEPWbt;OM z!2R@F`S5d(Tg_<(Kj*l00$jqp*l{J%*(y&Z;(6YH<5vWHzHp{E-5(UiN7iVI263?m zwF|jxA?g?-QdP)V>nv3g&-=}agTJjBRh}+O4FeZ42aLO~Ry(luM$&0u7$&0g*u*-I z4)q=CA-JmZkp(7#P&Wc3KppJPT;#=@LB3mtPF-;`9r;rZx={;oBb(R(U8yfrNoWk7 zf+krXOzCb|SG^F?EH~$&`&*9+0e`V2wbIOif^8yLnd_m-!KrSYg6^r3^%v@A4&<8~ zz{2|lLLw-QCQmX*MJkfMfWFgw5JA6K&#V^IUF!g-p^5m@u7k^26!n#pWF9F48h93{ zdSj8H{%?Z(R#0he)K+|3U#W|95~|JJ(My;D8Y2e|aW8$88v=yaR{SF{G`-D9a+Sm#CX+-txc=w`OU zs%Z!QZUKDHl|eUMNh+dVaF4{1^H3&@vz8$zsb(G~+l`h+gn13bg^FN4K7@Yd2dXZt z@yRfad*n8mZB7Jvv9q}Z9K|ch7M8%-SRV}Y*62XJwDy5I=z!0@GkA%!p%r?@bYLej zt(iD>9`xo5xlMdu{x|+_z7*I2<%Kw*8K1)ixkY?=WNb0$mG0tp@HhBVTrwzv?KzsO z$JOL2a(lS;{1sHJuYo&gXP?l8p~LDADoCpNm@L$%LTSGb`kSl%&hUP(_C@*xe?`CQ z?dt8|~>Q z=6t+|yYSVw#44LeC4$%Tfn5pZTPgk#H;QY;{}AGZ#X<$!PTMe>UmRzPlg`@0rIvOl z>OnbrI1<%)E-!xwzUv_Rsc$F{1b2i&I%zxPb!@nUgGe8B~$`A27lY_gJ zib{X^V{oTBTMbdBD`BX2PgDO;?81dxEXOKNZ@D&%|T4-qH|hrBn&kz1fatj-X?K^Ov(T_zLl^1yKK9bEY`g zyCPg$pvyh$9OI;&Tb#cfbsha2?d_GNH{yJ8x!~bbK!+Smdrgu2&?I$JaE|`~Dt#?- zC*{uf?t|WS0vt)TK!9NV_x%0++XEYdX0TK6zu;sgRPoD2R71^@zXjpeR#wQ-vP~(e zGHQ9XG~82B+AK}g`sgxT;`fXNWCh+>b2Hm40Fro3>Y=rjDoyju8fYs9uzk6W{4Alo zSW#Rnjz^`rxKvMK@s9p=bazg1@^GoVas7u+74G`aSr|;APwpx1zV2-IHg|FNPv<6Q zs^hsM##zhppS0TMuyqp|{uJ|_+DF2)&T_0gFHqJ$$(xxoE+>$4&T9kHVwJauFVp*< ze{kSn;CtXypqktj`p=T^az0VM$b01|C0&k3cj!YfInX7rJLpo*DVOD1+BdL7R^n4J zMl*e@mILP1H{&*jbsWcpgeMj#;kc8Ffy~nf_sJ}pW9FjsTc3N#4dhqw<;8opR`zuJ zamO-eDc5b+E0+$R0&%JCVEA0!~NcM#QB%=rfa-w3jFA+oc}mOoFyHb zL4cSlZWEHZf=sx%O^;K1$PWWM{iXdWxh1{XzAk~k@T7&{7TxW?8`u;$1-)p!z{bGc zK$N^pZY7KIJvkB1v*pm2--dIcsDBDP;SJ>_%4qcj9JNHhsu$7sK$~AeJELuaIwI7_ zH0GGPSs0Yq@>Vl+t@o4CeBZr+{G-P!%d zeGs4L1l}0!dFl@LwDj2F=_(Pj&(qsI!d2M0$kEDv2tN7Vd{g!S^|v|6*r3Y669H$y z?<3xNzLtK~Up9c&ggi{Cri@o()f~A57z|&6`vPwQX98Y-nLtEvdvHcDF%T=K2GfFU zuoPBuAh-cN%Ik8bd{&89T4;=Z7+s*{#wMJK4#We~$wX+B`xy1eO;C8EjTX=dtw+4F z-#P|WhmTeGGlCszuMkJNV+JaztzE-i!(8`Wb6iJUURRX6jeDbey62fEHe_r_9k^9I zAyFYa@t$bcZpQ^En9E4zZB5b78_afOc3OXuQ`$tOZm{vxFVQ_Z7B_v!tc= zB>O!_H;_4kPAJ#i39ieo3|Bk%boXX=y1S;QjHk6{5121+JySf}+=bnfTsNHc;00e| zZzNq63km@+&}LXk#%?WK?Ikw|-1DXQ-2N-Rx9}z13%m=KQ67ND(*vjX9yl`hD|zKD z!2yAxa4YJ*OK`OIM?c__zaczTz2q(OEBOO{|6}!sYSSb1!um_CpYAYf8_l8e-Dx~G z3?q_MCSMH62*YgbZ^z;1V?&jX*p5d9}ndUy@8sO5Lmz;f^#~u0Yrua;_!0%;`Q3cFAMnkQf zau9X?B>xD1IltGxGte`r%h^y5|E}ulJZ+RV6fWjCd1LT!V7|Yf@0xdE?)KanaD|oj zulBbO?vihTzj#k|>N)x^yn*~6{7%zf!ZlM>|5r=YR_m?x@#wjp*PrWi3}Vb8&&W_y zK(+s;^(WL`LHY#qnsxBygf3vZ^tTUkjB_TqZn!IXB0Up5f5Bf|%roEZbZ5HKTo3Wy zez+7@va5!BpL>lv%w5+V;-2KR(9P1to16kI)&~-TIp34i<_r1uKmql}H3MP=mo{zKr-V z3i;e!qbX^P-6fN6P!5kq3@EYVxG#Jkv8l8Pj3mi5-rdb}2mGJ6o>b2*&sGm{uXlHK zw{kCbr?~IChq&|L_I&^zRwws0*M8>*$1!`ZZM(3HJIVY(Ei!2mr*BltA=?2pOO8`A^f4r}g@42_5Z;I~+{G+-4Du_1n zDcx|2AJj_dN)n%M{b=k z)K=2o#Bs!V%C*rQ2D(zFXQyYgXPl?F=dOD{PVas0x9$x5{gb;k-db;u>b~JF@9yf# z@0A(jyp(9Uraa%B*rx zE-pU`RtqkNkE)9QI(*Fe;q#vE8xO})t3XUJ6I6s)^`Uw}%heN&tt1P~qo>gFHnARH z4o)R#ky-N{;{8h?pby2}n-`O}x-s)v0X~Qvv6ZyUo{k>a8`mdyXM7eZq;klZkbNOv zL#~E&2jgNq_z87zYH#;c@f-xts-rW@AYUnJld#_lzeb(my(OY3q3v<7d#Q18f+At5bTZ{bzxvX zBBD@42=V^y{-JOzFZ0j${|y3F*T7Y*$>G79!3j`$zft1UdfErXtP$AvF{CBd8f%s? zdz$AleJ30G{{zTHlQ6j=n_kWQ&UWPL@FssBOdr#x;>{FroIv!`)}^_cxJO}cwDs)3 znw#h8>*;_sch>#f6_3vC9>-YwAJPol1aY|VCqJ0eP^0i-7SRXj?fx@(qmn*X%U0{F zd!h2kl4r;YTzG7-Q{a_3*Y5|lqjp0Z03G!-<6omW`0<0l9Uh4_^&iyQG_W;km*?Y(P4Bgg9oXfj? zq5j4Gr}zYMh`Qqt;|#zJT2r~KR8W_yuhqudDlHj)qHyCb?#+Gh9x~wl?}yf^78JR) z&~q${iu!hOsco&a*xtuc-x=*nbnSOf1`X?BNR>PjL07t#r&FGlA?G}WJcvPEJ)IpK zZSC`=N48z!G+`nCoI3-G#dJ_m%UO|T3sN1t`7YXD>MPXUtIA`7SD*@O@89Js>$`;S zJu~+V`r;pRi+cOR_5Q;<$tU?2`4#_|Kw_W`qP1agjw$l*V6EjmeK_OPC4lTJ9dd4yy3q(B-dWFOPR{+}R#9__ywPp1dI=Lw1EE zhh&Ca3L%~`aKYAak9I9~K69klBkXmgrnX42r7#UEX&&2&sffBvDXX@r8ILgZG)gO> z)>InFe+HKZ&cL5L2UL)X-eB%mJpDhpS$O_U-ca8{WZyIVbYN=WXP`^)c~Foy%JFgy zWgb+0PPH@q`fjbAc0e<lLhU>EG&q@}h;qF*R04B^*tGoV82 zK$oB*tweGK?xE${aTVPY`E)Q7REoLqeOB=u^S1Uj@EW;Exs9{vRX z^Z*I`75oT(VzS&>*`T~rib83*5B^KPT0|S5ZO~q6W%QMZV1~e%@i*yWR>Lf_5@4n; zWUq4PLBl#I?gLM4n7y$h%`w$k(e={R!o3|-wa&O5Hee@5dd}nazT&D5n%W&lQO73x zFNsG?JWsqX+~*1BM>c&4+Wmu8H>lQ&8euw%Xfjr*F4qSi=Bi)CU2w-c!dtRkO_%9|+(0``lCZE^`z5%z1D+l_KGWLw9M>YI9|Tyc6_- zzJU||82?j5PYrz$*az1;x>n6r zo5An&QEQKU;6J?%rb@KN4L%olUckCVZKKC9)u3Ri$d?clAwhg>J1C8`7ePip)@gUG za&hiD$Qi4L5nrB z;pU6cYvXSCOSvO!!7jmvfzG()c4Mti#4Rwze-!sx`@l*tJ7R*9gWrO!vF@+RywXd# zpahfxYCEuOlGJdxQm<=HM7MYJ7{rF(jd5@VY%#k)i?xZWjUMPbXdgy!m3f!&SvVsO zv_(mmqybQ?9ENl45I#dmS0PuLbDOgtR{bl`B_G%u+n+;0_s!Pc_CRbS#tYHHaMaSy zviC3tDFZ6mc=H2tgYSAk6Sd;%VCA$NBg3N_d>UAUn$mbM2>uK_fwHv%6u2jYZbXDH z<^0gieN>v@yt%J3T3v03wjFnw1M@d0>bJ3OnuCfO1=k3LnUo&Xh?{`TKZSNP*O>mO z*6rt7@EQCLp|$v3Tx%;UotMhkPvI?01AFJZ)U_N%pl+mwlF|NFHf}jk8U` zP~v{V52LZs*Y;8cYtZ z3|9&#LFy{B@j9IJFvW-G7Y?_PmyqoH=*- z=rbo;4M4apL*Im=?+jBKwY(b8{*(vFCra2Mgo(4o2vzVHDA-Fe^HKFIk81K;vyOS5lp^a42l6sOpO1C3Q*8yM z%S~mQ@+Yc|?eQswDGPCKm~F#W=K^A zUpfum$PZL2IC=^(x0s6THkRYoL!&hePc8G6g+GK;Xn+Tc3*h8S6N%`uv9@%qpzlzZ zjuV~YMWK!Go*%`(<+^c?*-q?jrU1OUI%c5#!o;dHa{wy3oe=d5G*a|s@O_`wdTC$P zy=p&jE2=>eEdEccqgGM7s#DbY@bV<9EwLLnY1cGfZ?7-b({P$>GE`$M;^^N{6RwLn zL-{b{FC0BC7c+-Z;IHwsgSiJ>3_l5ad4q2wtQD@|oGB}g6#o)8;koyVo5khuoKzM+ z2wQ~4LLxtr*Pu+Mp-|G9flLZLlg@<_GZ{0y63l^c=S_#2bFa}Jx%&n@g{c3hE!Vng zbu?Q00;kF&D9o;?ukfsrRzaJn?auZrYmqbSP$S8!U_zS6l*`IFAgQVci zO+}V`7dO#i=!2%QFWE})uAk&oOz2q*m6yR+6~;ivdJDdbUr-%G2q~rs7r-N{j?Vg6 z{wFt_%Yn-57oPV!-5+xv2Vi>cQ1tW{m=We_(hz=%I3pHx_gQ)c{goE4E!4{4i4E0M zzpGhlrb@#h+e#aQy6txDtriP))L+OS!;J}0M3sgb>LclcxmCrG(X*Jo6i-#BH_$nB z57312LgjUa&A|;c4o__7o5SyVjn9PgHVO`*#@J`&@GDG6=Fj5))Z)F|39c8X!e>#9 zeZusHR&D|9#GO-!I*)$HLv*bY$yDM*t*$1Vc9WouP1Fu)leMNeOT6k!IGy*XJ3z$R ziMZsU%HwnNM|PN{3Gjzx=`D=`M!-0MT1tQ9AY;*oihwsUFS@7qpuI~#wRtGJj=cxh zZUwFnH=bJsU0M?N6Tj}GdocyffSOz(sEbcxtxt!7J1;Bag#4SC1m<=aqtQB@Mkmlu zF{kVr{W~U!`Z3STBAu|BPs7KNhtwhsjehz&ZL5mL9PYoJ>ODk#b@dtgD*dd^;SKz& zKh__hzR(}t%bAGBQ!xLmIyz1BF()>Onndr#EWKhlk$-SOeyUi;mS3{lYvaE79Vb{F z=@)iYQz4F@$sJ}6K_gb)d}yrK&uHD$8VaR6k$1=yRI> z&3#XckXzvMz4EMf)wYL;lezZvZ)BM|IQY<;ll>tpCu>^v&YUM+F<_GysOt^P;-gB@ z|IxSTh4e3|rK0F+)G*|plZ={}z_ME|7ntt5k(-iTK07RDS5EKT$KC~jLQ0(0f*iGK zVV+=VrX^dKt&D!Fz#OM9VLDw+W&_?pBFOS5_+vtb?UEzGmF&3@%I6za;7UOyW?kWZ zMV7{X&L5d)fqfr)T>tJJl|KLbnOdH}uLSIjKokv-d0InS<$^a3BEOUCvs`d`V}r4ovl zDHIv`$Ri2w$)Z4yjMiV*e#}mI{vkDS=AQ4#7oxiwI@dT? zIH%g1h?Usito7QmU{PNnt5RC0l(yf#e;xb1+|Lo|!?H;3N`Hz{!YsnXz_V>WHeITf%#zj=xW4xgXn-4t(646!?7UOXrlRtR8_LYO0yc_je9+^P%qWP7%($ z?ZftjozFAXv7BE*&CvS##%DJ9HUIm~&sUOzpDTTx^}W!qD%rcdqXJXa)h3*&ObF`G zMfi(wi1{#otUtps7w9mnk>N)zd%Io`9P)#DENMWU=TF%`JKuWhhc_)aDfVcgdPTk$ z?^CLE$%{oMMHLP^CT*sS;NHx;-`6EQ{WvG_Vp4~%y?;8g=gA2q$h5FsbWP85DO3uN z4_}ZsF0=p$LaiLP`PX>DR=$oI(^8&&y_>u~$xN#K<;9P0>8rhl9Htv2iz*2RQU=Gu zfBu=ykGtwIrg|n>jjhIn(c5W~F%DW$pVr?vVSb_RaS75Q*Q5|FtXls1QQxB97kXOc zT+uznP82Uv=&$g2`&V{~{x$QDZ`q%YCfMIDexK*d+n-f4mIf8(ft1JDG32*=`6Ks6 z@Dar$vs_K4+VDh>5#?MK zBoGCrLG3#or{zPP)hiqG$PiP~Re6hqWw?8Tbv8|SXPI&hZ_$h;KT0HD`I!GB_32tN{e4cxqQG?H6SZDg<*4lt zkyoq}1~Lo5(m!k_>opOFC&?{?Pl6xdnj4_>S7?2v*_dYd6ikKtYTxE)?+Uoaxb}wh z$~zWQz5XebUGksOvr7z*{t&uAT%oVcc70#{Vc?rNud?2q`g|vSO(5CoB2^Db4ec17 zk-tX)IbZj%%#dyFf1L!GWs=a)tQ~BYz2;}mmnup3J_(=x{?z&ViHx~{D7^%8U#wxD zZrdh=^H-R$Rs&ETx2QR1)n6B1K@p3RO9rc%r8L%}kw z=INS$T>jkfHF;O%t(s?t;~XZLEoI8+kNol3bAKscw|_nI?L7AKw)Ab@eu`nnvxh;G zI>~(FOeP<73x0uf+F&TNm#T4co4^GyJiqws2VZL|EFTom-Poyo5xy)U$y0nb*ynxd zwQNbQpV-8?C-iPa=>h`_o`|yN&lgtPwU4i7Ob-0WNy_{qjZHtEc|ZG*cenbD=_Gx3 zz7DGt=_$}9JT+`{m=e;(F+{w{Y%;b6;=Jo~j%IF2d;F_*TCud$bWd&}Wgl_S`?)E? zTW%*)75Up1dV={>uc8e0hj=-!43;mGyARa6>w$V&ed-zK6}sA%fy=X6c)~)VhT7c* z5(8gTPgA1Kax*0n+{~Y@itcmZdmXkluh%bXGxbTN0^LyvcXrC-4J)6w zXP6ZBD|CJ68+RQEj0z)K&i1C}Jj?o?aXWKq)`6@#xpf2k42k|7j+kh~d3kJ;#5g{O z+D^`Dixn!^!Ph;fN#>n2->*?=Z!)TRHw87L^s`y}xL6JiyF8uRUHAi-fO3V);lstsQY}}BkosZuBc|rx zn9mt;AfiRSQF#^$Sy~tW&+Nx(4O2g+3{4sOV|tq8@1}3GzH+4-;>Av#3s{y$uzRb zh*InMYv*3d?v!0Aw`A~Ny)o|c9?Wc>x1~u{oi101y`V6ZPXz7zob=fl=UE=oDD-^< zDe$GBS+GX*sp#Jd><+78Yp(apZkIa$`;^aPKaKd5_~p~Db-q_dKW?I=yNiVW9@Zsn zXqXcAUubi8P3bbIpNjEo1aIdtjnwwXr)_LU3Lav2y-c1aA&j; zvxGguJa)ekFBcDN@YTqfl({csY37}rjlr?Ta%vu{3+YlH`*eGv^hO#a?ZQ6m;jHc1 z9d;^Tc%+!WY~;0qV`I{yw?(&%SsxkV-fOn^Hcs94qd>WHkxJt2(#TOTmV*5rN4z0(;W&im#J8@isBVonIxrq_U z3w})%~P> z*D~7$PZ%?pd%|xvzy|DH?a4v|=76~r6JL&Kz2u2rE^Bi7lk}9Vpl^n9RfnpY&SHP? z8R&*imu`z`Q0v?j>p8lGoDFXknWw<~sIIYT#d1qkD!sSlo8r?7O%E+=-p{!3?cB$s zZ=zrR`zraZD=8vlzBZmIX#2v%vnG z1(}^Q=jSB)%c||jdMbk{!?zPJ*v8sM37z3n9mtO0H`)Vv((*?~KZ$u(XjYLqMU#uo zD7mhTR>B^&+SVz!D0OwxqWAP0=c{Y4hP^BEB|Ae>&eEy&7kMUyFV1(i;JLy-icTqV zBD#0PBIgA5tlq)9=4bY&-1o!Z{qe5rhoYZblcE}yw$T$XYI~;>8%`Wsf{5`ttZqOrZ%^eA1QFcW?mKyskCcVp6>a&6g(Xh zjNM!0w-Pa>=#sCCH7dG4>XH;0Sd}s%>DSwiZ<@Y8k#OjP@5`v{-?h0^rZCU-Do@wE zY59^14lA^>=U*@E)tDj6!tD-@K!Rk2>?T!Sk9 zqjl7W#V__f)4k4rGvVDYS<9>={Vn2cxZc|8Njb@5Qpc3Ko*^qYvi$SXT}>+4hq%*M z+FmvPI3AlAj*~fI0 z?;ly~U*zfN4g1yx#qc*+YkCOBKU5oFW)1|h(E@oL#R%0(oyBxD`QMaIX}^~8l{ufe zzP!DHzS5QQi&JY$MZeDSCTsee(r;q#&wkY8?k+y)?izX#byG%pM6=#lI`wYG-tyPW zwaWN5<+i3BGbg;&z1A`}clF1aA1;0TJ^PpZ0mX9r(~=u*b>P>?8F8I-w3^nfRx1=U zrB9iDkmCB_Apab11K(eP=_u)H@g?A44r3qZLT0S=wET@?w925#(YDkV8%HPgOzxci zzI1-Z&txh0C@STE8*n{617tWKLz z>P8tZV^Wz)WwvIXs!+4SmubBe+auE*GxPmf)3R1&Z~9m($6C1GKHk$Pyo)l(jw`S0 z81uRGS!Mss)MuPX9@NF)8_8`0K7Eeztv22C zmANQ+XKJ9-!;FLFhE|$Y{YceOrR7SnR=FcZ$MTu{mAP-Tc4hAe`DIiU+E?tJc_sCU_H*f7>U8vbe=ld)+P|n@{vSCvv)P=}IS=xFEUxEV5Zo=C z;>2sGuUy`T|hHjC|@9N zrua=AG%QS-pRzsuM(HzUs%O+ICoA8-?9r5!it6!Np4yJ8Hm#*&@%{WEc`x$Smj6md z`ld!Uiw?;Y#b(_B^Xhb=6jSQBd4zVq%tj54jS6OXE0*jnZc*?wZ(M%Mf)hoYt(D`f zv#$4j*e&c~HgQd51>8I)of^$7qpu4K!L{~W{2}g+{e{u@zWfFLZ{SL$Fm>1`vc8G| z*n53TwOrrTG&*U1a_O{vY3ZfrWOS|YzQWHLZljOA6zS$!YnNCviz*b<&YN05StmN~ zxI=zbbcb+X(nFbJkfdBsf02GIrIB%(x`u2ybtBp)xYb=~t5kfxXj|ce{1thcf|C|^ zNgdyi(5`qdx;plt&fx^G?o_1~VrTAdFwLu|S;An9dvA^p6&?t`qh(nE4%S)V7lOXH#?`6Kdg6fP~=Q>?b% zarX=Ek72wO2vw`3?=Vt(lH1PI1Qx{tVP(8jYzr_(O9AVq2s>luiJR&3tVGdS?Ev0$ zs-7|ROd4%|X?~fkOYtTjNnKv%Xt`?{&kaMkqUhKDRn7%=m(^aBU*Io%WUW$C-@U+J zJKQpw%74ykwCl_pQ%|P~=6m}4%IBPn*}y*uU-#c}mv_7=+E=i)pjUysz)^V5Hp2ZO z*d+dwxR{z0Y3wP9RFX@76mRk`W96gofKu@WSa?3_XUPlhpnRoDugTOt z&{Z@%GFCPJ1Kz=ArBlj$n-R~9W-dxKt2}hCXn}7^$rtvm#c%TtW@x8q!+3Y$2<>LC$?ho&RHrm%{Z3Pz z6i4dX^ed$*m04A`u)J7tbJ^O)I_#K84PQT}&T-M++!8F@mG>ccP~M&*m$Qd&Lg>rb zR4!F#O0J#ODlMKgN~ctwl$p6v%zE)rg!8R%ytVeS)GUnVt;`*kXDj^OaVxMT_82qA zzl!6i)AU&2lHQS~NWW)!*2^_zZS;3S-MAq-HF__8Qy5Qc+4a(T@_h=0W`zC+lgeB* z`OlP1X^YEDEB|w)FDo@Jw>hPX(h{#6*zX$TsBM{6w5;%8p{{@`m|Jky^4{LoGc(+h zIjeeRuq8WFzfRp~%G4fGlyD=NlT>rQU3k2AO39dFbMCtAaIU$aZ&451Ot&GhI7+NAf;kX}l0?3+*xbb0Izv$RZ)S6Sr5MsqCz7r|*H{H0vAisQ>~ORb^`iFczdeBhI_6o(iTxV7+`(nXr%d(QSUTv^fbTL?v zb0i*V8~JvbUiP1?ojgtcR{E0t2|E~D0)40+-wmu~R{9c{6tBvrsW#~|Ooz?QQX8k& zL&|gOi<$tRvGq!4K3fuj|J*7+HHf!OP>{}n6WWC5;mzR|vvK(|S^Cm^Bb4&GG zlb@&BQb#2>G)eVq)FnVjb_g%SyL=(%R?C6>AvrIz4ty-kE?2n2&UmYaCPqi|L#WRs zJGsa5v#P}^rIJ%NRe2Ogzt5=(RTC=jQ z3WqC|s@kvW@8z;gUFDakbs?X#lhsvxyU>)EmAyM_<;P_oE!pA1503KzUi?zgL2onm zPQI2hCwYhIjjpR^u_DNBrbfhfgmRsa3by2w&+eUlD=ROTFZ#~*!dZ-7QrmceaGTk{ zU6ZX)W~+zms_43Dj;LxVilq{EK69StsA|}al!9H&ZplNmYcZX=9R#x<4%Sm2JMpI)WQTKnAHFL`MFt~&dEyMHoWxdQ=k@Gw+sc?)f$^DbRbGT3Zr7)S6 zvZ73*9-zBmI140nxo)`Tq)JeXkZoeyGijJBnE}kY!`P;oqmZaZYDO48rsZVJD&Mrq ztST4E&M@;Dsd6o2;+uwT?x6L@!U+Xz-s-I5ABSa~&T5xG(EdxHalAZjkS$U5*Zpa@ zYG`DTfko;I^;`L9ZlyRYoZ>m)=vVxG{+!%;d5iMf7Wpmn9V*u>Z>M0rXf5F`)tg-@ zAEnOKcF^C`@6z4Yl&Jqwk5RW(wNrFPZ}T5%8QD$XD*P$CEc;H?!O%Z>RocajIu+KH zkEh>B`o&mIw_3VAwm1|AQ_We&HA~%sNKW6JQ`tgR^IWsV?yTx>7#U1&lXX|$*H+OF z(^u4A(QncXP@j{xW&aUEp}n5u5|j0I(dUKQf}I78ike#kHmBnW5W0JX>cy^!581Dk z{j^E?x`uVepN+2#o4~9%Tx-z0!-`#te1M_?*wwDfs>vM~8~#t*&-ftuL77RJUCUHV zDQ~>5eJZQMY~|laCI!m57nQuT9W8!R@H{so_j2~eyv4<1oN8ao$QPnPI!f`odOP|P zX3Z>3iuR&%s%)ENpExkOIQD6Cn~Id5nFuHtL9bSL8tglznL#>urr{w^u6Dvhdv zN|oX$#)d?3Zv1+v5hvFU~JvEhvVgZ{q$o^HH$mgXULi%iokHC{6fO>UR6+*C8Hfr9kG(nJ!^bNfV6mxuSu<83OI*ijhe-( zGpUg=9W=E|s*tn=yycUOFAV+l68%M8f8e_}G3_$nPB~^iX|Ss&s@f=CvoYabq)ss4 z`{>;R2566?f^BkfZc%RWZtG;*0LL?DZQqX2_4rf4L0w}aU{{Z@o#2l>k=9|C(vPVA z)UUvJYZbj3)cI$4lRYclhg?ftubdB@*)F-SB(NZKI9xAwRd`Ih*dkdyl}pn@&x2Wa zvnkKiDrs<1@1$*}-NvOxyYZ=sH(f+)bSb&H*{w^~Sd@1a96MON7|RJi@-OjD^{j9Y zE|J<)ma9bzE&o}qwoSGr4zs%^`r7%?K73!XGCfo>lKUO=)ODn#xzB<7wF$_%ooS`$ ziCv1+3DcqBfplL_&qr4cx7|%+^ADfq@e#GB`;<@jK2 zWI0pZ4{YaMEyFEc?01~Mc+dIOp>>hL@!i5UYCThf-Oo0~yg3j2xg|jJItc8A-PpmJ zA6LX)V!dD6pg!=z_uM-UtK(ArZ~V6dJ3}*~Me(xY3fd}ZDE&%4UAarG0iVEc`eJaN z^iMjGG$^TaQeILtsh@eZd1dm1luJq14R%d0%}AwQ`Z>KlJ_}3&hkRzQ%h{ylr0tmH zcJYVeW|p_n@HSVS>&T9lyrrK} z{|GgC4tRCVLu0{Obpt4NuLEU+HA7jU>5*?@<-iy?mwL~{*_AT0vY)!L_H$he{UO6H zqsrto+D$dh+2;1izofKHQ>9HzJ`To+x!QWFLDE$EX#7HWMDUcqt5@o(;W%sUUOcy` zxadvM>cZiLYl@TXX&4JV;6D`Fj@{xV!Zx})P@*bh^^K4FN2UcbS~*#LX+v%b`<>(z z#`hP;`$qo_-wj_4mxTPm4#Doh1|fC$6;|eZqI2S@!We3=q>r>Z*13F8yizsOexd(Y z|3Y7+Z(;mB=~eRElr5>V(%PkYl6#oC8XxJ)Y8E4fIw3b24*wJ!@2ls&R&v8$WUXpZ zTJ{tL3Z4}_E;?&_RI<^n^wkdhhO*iY=56fBrKZ!ZBoZ)@2j$CU8L|$td$OBA86N^B z?+HRHepmcN>|k_m4V^zWO$n8id@*tWLGsNHUOT|X?7ffCDA1)^46!(=;Rl2&8CJSk- zZrq$yA0FxT)CVawlK)Nmn6%bl(hQg1`M5V|B2_i>t%_?aogJ0QoVRw z@k?vA{hyL9u5Io<-lx8U!J|OH{|h@(8h~+Yu;c;P8FKtmwggNmUF4T!UTz9_Tz{i> z00AFscVc;wRgov)40{TsK_6IkcSerJj`NMMKk5RWR&x&NGPy$W5iQ(h^>A%heGg-? zQEB=!scuR%C2qDDr-5U$toE_;C)sB}!!e1?fjW9C+$%8HJIqCweC60+XKjC2&RIU% zOpbRYf4LTUSYKy0jYNc_crA31pP)wd|#=NY)zTlE<-jcRAytz61B; zfq1L9H~Im*J$9hrtp_h@CUBTO#0r6quA zy`<39)6>W|HZUS|JW>OrcxS}VsK4l^>|QXt$mDe~eo_mox=u=)a7}=on-8p?wS3!n zVRU7rF7W!MhuUF{Iu+7|k4DDD+VW=Xac3nr*|T_Bg|#b3RZTU0v~9rhcvHX4pfRN< zy-b>6erz6GpZHla@5g0E^02 z;&|bdgKLNlj1E<0hBFeY09G*Ik>O;((eACff%`|46o#pXlDeer1Qcx++x zdbn(8O2Fbb2b+cVh9-n+hA&6Fu@tcxeFFH($G9|%RMrJUd6wF(sfK+n5nW}&8{;a| z0Mpf^U(Du|B}sb>QEgkTMKxcxMsi7f5syS#g&PJd`MY`2U1rC2`&fI1U1z;otgu$M zFLRo~`6%&^4K0bz<$D6>bRTm^as#WQC(5qL*2){od&yE|N?C2`6`)f5D0;y8panC9 zELhdw!FLRtjkW!%z{bD{uz*#;==pi^DLqT_FIPdnQQ1;GLVI3!2b@1!4bP0NjTy!n z#zUq%rmc|a7v_rQdSKWqP>ojpBAYBZD;$e`8}1H1pFez$JR#RFC8Ok3;}=W177Z>E2Fs4(JRkW$d4{3fv0k z!wmz|yw_c2o#v9(j-K}Qj(Ki_|7hTPa7#qRpQc7gc5o|Y*@|5Cx4IHTSJT9#VA8^* z)ut9krQt{PWtOVWEAJ}ns#+>DfIc?`>qgD;&DcG@RX&xyOSKZ)1D#OAtD~zztAp)> z9RuI^Zn+uPDWrC=y_aKHNgHQR&rja_!3^NF{0(n%6m0r@c~9k^3Z-l*=aIgVGVBMs z8%6?ahEMoE^YG5jj#S%vOR803Z&cF6b0Kgv@@Kp;HIE%8udPbg6li|ceyd+<+-uYu zY`QnP_PVy35vo^;UD&svl5GSU+ymJuxko+|tB#*x?Pv@6aamhgy1Xio9^1(Gvu{~5 zw~8JT>k%yS`COqAk1gGrRLog6+OFF!IR0~20*8z)+&+GUUL+~a{VJ`eIImivKCa19 z&sLt7^#EE>KmJBI&sWts-(Jdg##+~^w0vvXVAHs^`1x>QEFUNF;R&Q;nBb;6_T?VU+eTv!7{=wLX`m6%~DyhZL9=Q`o>d@&!f~hoD9bQ?}5C z3=P17I9oYFR+;;f>Ks;hct@H=TU4iTZ?Vzx!QyjFaa!DE{Ar<`(Z7Ia)RGw_U8s1V zYNq?#@JRQiZiIH0vN~rFl#xNcj?NX1gBD5AvVtl_N34f!ot-J3d4W2SG~U3}keStb z-DZQ|^q09w@|&cHp@N1|bdXM!Ob2RSsc4z#oR}xR1>6U{xOD9Q9jr=K-&S{5w^n5< zJ18~*x4*n1sLId|)jc%)W=b^`9lv@Xx+&0Kq>M?Fj1LpN8~T(?`jPH~^zE_4Ww_1v<3Rdg@EV}7@MWx;nv$EaQEqlKxBTZa$o}#`vecy>_p{B$?0aqpd@={Bt}ePXq6fz^cei zel62mdR1XkPuFt#J-SWWy_)6fY}Mb&TZ(In(#l(^>6&J`iTZSXTkTNAJo;R0P`HKv zU&q6umPJb~6RhhU8Qyk*w;@O5D{&s(g+45)!F?~qS|0f_>{!34TBtP353^UOby00# zq4ThHc+uhf;{4)*?Ut*K`JSxMCVngPjvK1jrJkzofSqZ_v0r78VYXqF?tp5$YykUA zXc@8kRyc>)C)sM2*j*ny{Q~~TGAfH(p?I(UQ5VqVYs>1=z=pn2m#NiYhh$sLAkFtG zo$NL%us?7`YnLtFp_pfqKj;zQW#wFO-ATKWjH>R|BcwHukVRR=!lo6ay5iYo*ZCOLUGiLV5PQ0oqTf{_=`LBsF!UuV8|XJ(fLLBP zniBj2jDmk*WmDV0Ise{JjQ>h|;S3wTT!*xe#ZY|;$bZ>&dBNumFW6PM&+2qhp|Zj(ZkS@SvbA=M;jr-!-4@Mab&9MtBd2bOQ({B> z%RMPBt$k?mnxdOU8w-quFRgmlQ{RioWae|lKFvns*%U+iKdC>P>l<0k3Cy@XihdsW z#pSW9Y|X6itOM+iOJ=)g_=3TL=rO*Hu!lM)A8LMEdPkXanNKQ&D@Dp_%9c)Fr+d!s z5|+otgkJdjgi6PLihn0cW#4FL>d)&c>uj1b%0k&=`M=WLR248F9EhFr547i7rA5#3 zk7wuQEw^khxfNJIIg~R@n^R9@j4%5`>5<7jbq8eA;=Fg8t$)#g{Iz-VJgUH7{Gp_j z=PPK%4bNwEx9+mi?e?t+r|! z>K_4LptNS7yexYbxXv^9^3hG9cxYm57O*sSP&1hwXv?2PQ-fyDX_wz)^j-08^FN7I zXI+Y$>LI$(x>f3bxy97*_}gHK(`mhBIc61XYWI?0A@)fhjKu`2@N4V=_JpYGoQ$o7n&42;k;hNy-sD|$gt^qUONgPIBl}rNu z!xQ;cWc< zL|Hj@7yVqg9eL}IyBj+{vyZn9utgk3&yK*<*dh8G`Cjcs>Z2iFBIgjxiLgxm1{(Z5MLN|m}^$&qBU`7@&( ztFX=s)q}s<2Iu6xuk)_y+pKpvxyx+VJXCZEQ(l>+*{x4Ey)#ZkFF#)yl79KyR2X2(O3rNN(ljJLn%tf$a>&EElx&ujSM^cwbxtdgRe;+@PReJpDT20O3xdoG>p zA{FJVvXY{YJSyude+}&1(TWaoPIgaHwTFzBJD=%GV?&)M+NZi>AigOXp8WB zU`CYp-}dK#DYBiXH&_xMVAcGp@Qe6msy#PbF;=_XcpV(f*Y&B|E6UT-4w4Guxo9-h zFszT>jm_g%0}E6S-17tML}^v|7xKCaL3vSgR=?6%&9v26-Ox&3MSDm|OMj*x^WR5@ zgd2lpI5*TId>j}z$3oA-bX-CmW`fvtT#@BuW8}Bku2iqMi61XiCVNW|x%}86i19O1cEA6kkFYh9&1x$vO^kVEt{8I2lZ-&Ll zud$8M>QR0CPOL%X3J_+FVfSfS^x3NOa&ZUkl>Vlgqj`*-eCt#b6m?}E;8A=Q?-U&x znG?Aj4aR=QPK4c5Rms2XN~uKtnc{}xkz$zYu4WRD2zZ?feTdI=_fdZ56lt(g|qbNhG1)qBP=c1Xm3?wb*8$Sd4))f z`BHX6^#&vO9kHV!S2l@u1%7f?u`Mkej#V2*+dyXr@6B*^Dw8WCZ=n22`L`?wELiQB z4ZuVV35UVa^9DGg`)L!_l~#^657i3P_G|og1NKlj+Dcp{86lsi+NUb5daL+W_L`Y1 zoQZFZUJeh8Fnm7sn`Db@xO%qkm3}Umw;SrsnhC1^fS}V0sO7shi&c= znTMD)nW?>@s;w%oKA@Pz-IstPnQ2Fr7Iw$_hidzN^Ze)@>9RVL+~4>rgt+)5#vrSu zyssLfxu|WaF{wVtKa*1Ie@s5c(BE+vr6<6KxlUz;%{0jVVk67}dN5suIf}d6|3oZ{eh@J_>Jl7pZ9eURa=LP2w zm)-TH`?#lF@LeoNe8$|C_E*$U<*6I%%IT}98na1aQ6%6~m8`HVDjc6XEcBHhc1$iQjXTHLoX$&U8VM@o?zBSiv6y=#a6Lk?#{1t+{?On|vqs z-=0>L)11;a)z?A!78sm{>V~m8UcFPfQr<)Q6}-#kz_3dN0^JPZpV;w8Z(w2Mg&ct{ zz7)5_J=T9Av?x3~C_&x18_)x236H*rEIYcy#&k zZ^NtnhrL_etZSKTz1I_X6saWs&TUps);M%(LymTfYLC3PbPxR~-aNJzdq_)TO!YqV zk{u@XV2r*m%C(*1p}eg$pIyhzMo%i{A3-cV5ZkA@hx`N6pGjRPFlXwNJ zaueutk^;sFhD1i9qI&byVj}~^&bju7)^9D}6jmuNZQth*OUn41v2GZdIVyjutf3vD z-=lYFcF9X5*Z3~sD?YdDyscwVu#mNEv<$I#@SF^An(SK|FkaX7k(B#$6)&^C6 znGK_O>lih7DP{qst&8lPVwG~3;uq;2urZAmisAzzt$mJ?`u1;2-Z)D+A3Jt9o|M#g zu5mVUx4^hhw*V8%qqehWWCu0xjb{xVG+Bxb(sx3=;3Ib>N8KV$Bh* z-bDW@sV%#%=&x9d-Am=9bAiVD6?Qr9k(eYECG{i*x|c99elv1ExD7ZYoxx!{GuRtS506X)RfMt7|LGpxdxW=J)>*QIOssh6WiTuM1kaZvsqEBiMnYpb>>XDgCramhpK3g0av56Ha( zJRWzwk~NOGC2w5sJy*QCz&QUt?+?DQ!T&-}LW`oSgbapb)Ld_12J}=EbB!dO1U~5U zu6F54CRh&_53xS6_i$hK{}v=>>L}WHyrn*1a+GDEc#c1(;O7 z2SVA!Sl`GHjOIVb?&1#N_E9R{RS>A{lKbGWNtZFQMbakHJ{-%fW=Bb$p+|5)vP@D& zG7qa$_hY}=j~MU&z*UkBl~+~NQg%~+2IQzW+Mwowx{E49*;;WxHc|S8bR2k6kASuC zzVfD`P&Sl1$2_HKfbXm&Z;Dh1O$L|n*P$+fGl5QiD-Z#fxQ4<1vp83{j=0l(zlDE{ z=TZiCxpXL4I(jM!r9Ay-{8DHrMvzS<0q%x1SYss@^Q-VR8HkO;3tNq8nj2}n8|bnaRI+NRwH^gJO;arZv~tCIqx9P1kWM2 z+Wo8Rlxwy7zE=@a$0`zz1ZE^x8T|8mxe_47-{(Jz&JXtqcJh|bO zWC9Zy#calE<0H`MpV$KQfO+KqHTG-Hqx0$MOfTrVn^l0%Ml1hH-W%MvBjhunQAvsm z7~#7quLvZ&8DN&kmamYPlm8}LAUiI5FYllji*>oL*_v!Wup=4S5cM@*E$)vGida8Kc!EPAqKOgx6yF%AvCL*1_2A+(4R0>M^JofY+WyUcZX_~U}zw?a* zOMG-p3JjD!{9Rs2y`0d~c-mYWnK6-5f4Vwj=_kR(ScZp&}UD+5vCqI{WrzT7Uo!u18? z+z76v1iOj(va#uyf65Ks^oM=h{67VZ!Ii-y!4bh`-~etFs27-mIY?`$R`_D{HE*Db zfm+m+eu0^SiSbF1?*q5IKY4q5zIV^^ei@WTo|nM5^#?RiVpfF#}sC&4ZEx3B|yW#5Q=1SCf}3wMYMatEbjrK>rtu;!Mt zPf(jDW6$;g<~XAV6URGAgxxNEB{L{`E2pSd0}bOO5EtiaLTaxnNi|*hgQArDcd3=# zjB%E)n4`eP|C0I_D1ZuT1tkSP<8;b|{m5^48NVi$AHmpLs(!wT?=&xZ;Et^P3IQ~-Nj>IrWzBk5u1(iu{)u5!L^uA8y%K|GrK)d|F*@> z@qhAH!6*BIe=IOKMvGEPLiNS|W)J-eJg3XBM?E5Vg&G*+dLh=JTGHPDg|-H}ki7^z z87E6|7lB3lP;w9Hj)K8*3iibxWak5S;689RYRX5;>nkQI9>_mpUUv^zZZ@z#vOU>a zc)ko*%zX>y-}bU1smNVrU0@YyBss|Vf$kiq2Qf*^82TdR5f2F)cm_MR$46^M8ilt8 z&-+E+8~*|SHlUk~_D>1i3C<4pMSti*)E#>QmcAe#i_7AZqmi%}z7ST0w})neNB2VX z8iy1J(z2qDmx21{H3%Tx0GEav4Bm+3U0YN;N>cX z`NRL@eG~=qfwJk`1gs}tz}%vb0ZrH;6bK7}8Qp_AL|vr{fZb^qYKkf_^7{Bc<1v(R zgNQeLJLC&=_D}NF_I>7$1!{$kht`H_M!Lu6gVkoGuz&HLt{b%5&n-* zDX;{#j%|+F;`zKUJ`C)*4X81|oPJ7=lSG)Oi~+nZ91HFNNVhiX&PgzG4ZNG^a`4T7eM%6_lV8FnRY4OHC7l&i3|uo2J+O9 z0Pk-OWSV!u8KFbK13eq*78}QVg!1BKVK@IFrinZa-G-liBWMfs3>^#i1YhGbp@}H+ zG5!_sg}(sma2{3~zZI*}ZYNSnif!oLKlxQR`(5kfuW6nNyBA3tku#Yg6+X&XD zCn)0>eTqH}#DWmDfO;cl2@!r0zari@b|(5&tY*A>d?nCymjH+UJHBdsNOWy@X^09{ z3jXW=&z~D?6G@F$09wMu*ra$~>~VBUq#pLQo{an&-3vSu@EOD}0}o|i`C-ZVB1JQi~z3xJ}q z4Rb#&qK0@y;K8Kx?c#f)X_0TkFG3#^7=xZ*mGDB$LGR)F!J4)M4{3M03Oxr1;48p! z+eWw~ECpgxKJfWZ(Oc-=^a1)ZQ(bZg<**niA#K@m;9y$GeFcn)#$YU+k2T$Qfp4*& z;h8a#I&6Ke9q^Tg0Aps5%p$FXd@W?V0z2j_tm0n=OmHnYr#dliARhchH>6dxj6Og; zhmD*GT!)@ugSLxl)KB8S!YEh~3z#JKpe8MiejRNCjEnWr7m-cTH9!cF0L$U`=z{1U z(GHm5C5&IfuCstIAoSELzr)vM(E`pq<><5L@NMKm+i=n=Q^Q8zXoR2bha`Z277_SKgl?%XA z?iPCre5jqVR`I`MtzsJBa9#tNqX`V61NfyFnc54k?|VXLF&E=Gzl+F}c)r!}Te-od_?-Y6p<=_eY5$_wX7T*f=z0$CyL-~G! zQCNyxUBXI`X8cfKiXH|ZppSKO-U}3l8VY zR69DGZUtPNFr$-vL|)V=lYw+OAU5@d?^GEqYw40Mk_^cMroZdzKNS&ct0*`+uP{_?f9JrfSAp>lYxj?O)EOrzh0x?D*lm+L(Rxy=| zfX(-mct#w7wsQ|ypS$CkFNA{v2VR4(#bx4J?3X!!HYiE#0w3acplZ!S?Yl2x{)_4b z-|;+pFh{A=)CsISx&|2E=U6vT6CTGZU}=}f_~8{`WR4N*f+^r0y^E;=3p5vA-M>H^ zst+c!QSd;EsSfl2`Y1TVcYp=$NY7*;wIUAWq!-Y@PVl_H16M^3c;$=1 zrcePmI?cf3V5TytU(i0QMWeU|zNd#DB&MN98H)#BL>Kn*7j<6TRHQ=vt#+l%52$lfOwfDyzDYXmkBy#FcE z_Xb!+f1^*(2Ry&^MK5wQRNRSv8I2eRq7E%aNl74|DbScRh{Zq+#yd6CHpJagoC#e% zjW%MBSctyXQmQ?4axWMt&8T%n*rA$^xXOYnVgo+CFa}!yPTT`{qYLrt!RNOacYZ?3 zn@}P!+k7Y!2V~V2?^sOTM0u?Q%ZQm0phv5qC9fb23z+&^AoL;V?+)a17S0OsWEONe z6S{a5we||^>}YWxSVThbC7*#i#EpDj1t0ntFmjBAmEDS~9JIc7LVEqtKk`Bs_aeR@ z#bL-p=Tu;7?hDeSH(C z(eQ^RLGN}!bDF>(sRK*!9y;|DZ#a#VTJi2WRC6%ODN%E(K`u#DWoiKWXd6(6z2bJ% zvQE&)=RnJE2EF-!`ZgCfbv*Swu+b_|Hsm-5DLIJTF_aUfavJH}i;(Lflb^(iC=W06 z#fQ?)pc+u=sN?q`r%mEz$UO^vL%g5paaOU=+#vs?TQ5S1LQ){Cx*pSK!xVi#0 zbPaM)jyevX343ZpE$ZBUXk#mIc^(FnOBXyrp|;&dDZE9TTGZ#V(3TVM>DD1X1EHaR zAT0`{uP*9rI`sl2H5Q)(;zwLHKqK|g{VTXK1n-y(#uq6hKZ%+LP3i}kiIDpxaW~2| z2P`%LJW~zj-->FCvTBC3rcp+)Nz_AK+6yat0tXn>!Cq4X_Te4UBtV`bY*`U3PzuFT z7a{HQVmiue8Z7o6Sf1IiNb^xMiOvyC_Q1yYA)#Z)={ac5A*Ajh^pJwykH&i`=o66; zIbK7{T+n=S&5KgwsM1JX52^!dR1es|c0g>4K^xbiwOI?zK80Syd)UhQD2Zy2bw%h< zeQGjfJR0&}gmf=K%IZ;3l*}!}{uDOh8cMYi)iIIcdDKK`(pRXlXTfsy3a#d^c#jdf zcMDpv7Pg&&b~c0LI-%6msDmb?pgPqWR-rpJ5_z6MO^1c;k1#B($yxCTa=8^{bVJMr zR%Z~oe~ub^5pt-GFrAQxVbJg{Xs5!kH=7}k%gDncNR-HxL2J_-C7VPgquev8@{ms( zTxkF=q9eGElt`HcC727D0^kwy1w<>p7@eh%tLm_^!*FdIo|*vmqUMwW>`p;oXV=ElwITg})DYyiCc=`p zQm8paNQD=crUj&%ftbod8&t5=NswL&WL6#}Aw?{2P@-Ar9h5~04nQ2uafhPbA=eM^ zh7_c%A7uCq(q)8odI&pm3YwgbcaEgSptlo1SJ9TFIW*4 z_wTD6wLcV<*(Ee$ZYm?Bp4=klWCP{fB&(h75?Nn-IPThYONZ zKz}lj_F9ll8CarJq{WDwB_mhq_*KIbks>upq>pHGBgESfVaq}qCR_&|m zgz^g{BpMS%$Tf~qa6=cP2_25(o5fR7l#dru_?W0yx%e)ETr6mT?a1{rr1lwf_&M}1 zA7%Us8kdiDrwI20uxk$FmZZM`Vab^VXCLqcX<4#yr4Ts-C^j_0i=zbL!;rTGX-q?^ z4M=4i_reGv!cvz(ZE6Zh)QbE#9q#MN(KD^zAdsh4s%Mn04C43X!#Cce~3poCT&AWxCoc?^n2ziVwe6BRD&Y)ZfCLmv{q- z=N+EUM!w%d0V0}z7;tpT1E7owEUzF0!{`cPxQx+ zYoun8G9@j3KAt0aAiv}wZy-`CL|o)Q;^C2c^ndZ^C9db<8Yyw2X&)2Mlk^qiIdT-@ zyzqZ_nQJC<_}tBnL%EDG6)CFDWrnF8R1(!+*9!9!L&IPJB2>K1hB%c$$jhlavsPL97a~VR0Nh>KCbD!~!xnh!rIN5v?LE6_2o(KEN}d!X+-_3q#I$ ziu{qV3_iqyGI$yw+t5uctx4P?AxNwwZenG~T^Z~!vBjFiuL699B=jdMMcOZ7yST*n zC#y_iBTvfllnftD!m1fz%T0+k#|T@mhm}u(y-!M5ee?f*Q}COF)*v1JX=$_&V!KFPR3+S@YtkPxQCVZ^rqv6~Vf4eT&ENX|HR53L{Z;Tyud@|O~|M;pfsn^C)6Tifh`3%pHqX|6S29QS`9JP?EDtKQxlv){-I~nsx$1h18DajOk6IrK0 z=0xhB^n#>11D{kJ)Bk@!i=O5{}) zDJ7DvjkGmNe1A%PHQXVx|8&$$NP0(NENXr0G`Kx#99y=L2L~1 z=+p>D><1=jVT*`;BXw4SYs4avKQUns`GiFyc8%CW0pG-$k&qI^K>o-Xop?_A|1B4J ziwghg@g4>8P2@x*Kx~B(sU>MA5+HdY@=d`#5?-4~8A&U#bxM4QbV&{ji4DszhT&SY{A1pS`gCekamLDeKNX0{mcBkg$(KJOCVW)`l#N5~xbUnJ~DwC33ePd>ymApSRLu`P+blUCS;_LxYd7}tqh z$Ti|=kQSTdpQMANtt4^9j;o(qbCO5WmfI8gAu%{`M&cuqCY}M2F-a})L30z{M*-4A zMl?wph#zakhrE+`by!N6_>iYaY~;qoveflMG|KwW`UxuW+1ouC^ncO4Z)hAzs46zKSj!dNFpEq5x5o(AaWxTawML& z;ffvC$p0koL^?K<0P)Glw;RuX>VuKez#Mu)R>b2Y+CtJm-a+I=;{23OA`xIPn~hJD+^JPqv1&(C~-%LGvW)9c2SNP8C;2Cl(!t(fOK3XajOxJ5uYlFvvlOG4r0`x zy^x^AV9>^s)K^9r5_?*rRned~oP;h;Y}D2e`(0PEz+pKbtyc!EX;8B!BY+3eN={w?qmEsgprp@ znD^>~xg0X%<;PtjD>5P!LynVhUJh{(iAM1*1wxbg5(@0+O|ciPHSW2^I{0pg{KpdI z+!~>*7~kxOc#|PL;yb;;78bEE6gws$H>uI)HHv3aNu zhatN!@cTE_93xZ@FxI^RBleA;11G={{{e4VjggnW_EUAHl?EY8^)}w zW6pdseOmk=a8wC>8{9wr>0Q(bVX=4h?|7-RBgIM_)C~h@1Pn9Y1E&z zAdG{2w_$ETjggEvB?=xf8?&xof+4;HbFBwa(m~-C%IBgm0OfxXVRwm{qM5EpO%Zle z1L>c@sMUm)Qd;ClN>`&!3I*aNj1P~)%x^PlAxe8TaxwwWZotU@M*J3udxT%8Ve~HX zF#iSJjGiDo6&3UhaWl&E2EUiCLiHAkPGN72u?j~U@1ur>RU zvVWoZe~5pgHh|S047^r8jh;-i;3??>+>k83j5vjEL+ud4;u`96SoRz-jh10%`)7J2 zO7@ko45Q_3sqw-{ahfEV_wfrPFEC@@19Q#Kg`dSYm=jO|NiZ&K6)aenbC#dO(`*GG zRXr4ku`Prxdd0>5yT&_!PyHo054_@Zri>`WjdU5T2Ga5# zzN>T*e>HlZeaLQI(ee(rxL_CqpPZNE2tHEe>2FGGyCXknBA1kY-fC9H#6ha zV$^*0yzw8%n8T=6<|88;yPp#E?PfV<0?0JkkaMrE-!cE=wv$boz${=J8#9giY!S01 zymE3u8~H<%Np3#ToUKiw&oHmG=U} zL%kCc^*q{eelGJvVa&sPCn~qvhRPuz=P&Ot_eqlBljE88>>%oqs?!s=GDchVB|J)s zXdRd!-HGb17sT0AqAIa7jlyIqTtZusN=8NV3Ri|6sm4=l*}>*_H81s!-%ICIYO3cQ zkInPpd|XYwvV7c}C@mvuI7;uZme$LKd+>Rs573FZ;V%@AyXa@@;*s2lOUAftLzmar zfV(<^8f#XE%hhd=LSj|BagFnHo@fKZZaGS?iqb}9>t3^Y^fB92OjD|(+1#8A^ zI)xl$_QJ>P67QidD=Vn4;%hS{l)(Sso16csEEy$gW?E#ZU}00Wyv8-A4F6WGsx1H! z^H1dq@o-tp{mKLGD&5i0Nh_)r4UaW_4S$JVsN^*_3(e?~@?6HnPttpk%chGvMINf% zSdmx5+nHp`NTmleiXKeu0yUwSv!!l}9%a9XO_k2ddT|Ep3FhPO**43+qYRhG-!zt~ zv$-{FX>}(xp8wCh7U{vwvRsjOs|Tg-Y<<}Yzmu2barBc|O}yZJ!klqtHx&O{vd|_n zTO-f3-_}AxrC>9?ugz{Q4liUEO1t%a(S7V#d++d|$VE_`x(8e8i8dmtfd`Qk`$oQM zaDbj3dy$+CwPlX5$>wcszLbN06>P*bvKQ4JMN9L``6eoFjOWtXy&6rj(35ieyrDVCT-HbWP``=F6(N0;!Que6wz5O-Z7EMJ3~ym|>&s|dG!Z@$!}ON& z3wE%ruyQ;4kSQY;)f;Qc;%vIVaYST4vuCsuDhy{CS=0v1 zAn|~hVN+9D}P{cT(_uG4j)sHsi8qjOQe;XAXHoaA^?S1rmk=FU?ewM9mK zX@GH2ea2RyE&4mMk1H>Zmeb{Cc80kJiZ5+B!^J5bm@ zpxiZ6rSO#xFE$s3o`o{4leYUXPzHB+G}Ciq>`TG7=*{ z`OB7x#uhm<-B&!PHdlvZ!z{UPuaeBN_B>+Wf&dLjHWY@gL+e; zHKol*ui*5Z%%OOB=K=0gbv2>NS^`Q|Q`ctu~LVM878v z^(tMJ8ARn|x>Lz)qM8RvyyoDjv1&6qRWitBd05oTRA7Yvb^v{y+|rzS2~>I(pq{~(tpNKo zRErdMY@${Ns*qHvn2=Y?qt|9$8q1C4-1Lmx65WuSZyr&DB#hm}4(=lRnoQRWsB6BF zJK7_r3;Wz$!`386l;fnO)Qx!?T}YX{z%c0QR7HeeGqnc1?j)&K74z!IXo7GXYVG3Ey+GOgfH+LTIT8c?Opdd4bdulds`No6*s!RwYW4bXdr=iHQ zk6XjN)eLn2c7{utj^;Wx1$w9$W-Ka*=ArIsKN+Swv9lUN8_X}Whq7MJ!hhE0YLhJ` z#WLzYN~~Fcoj_+bU{ObWdM2|1pKhMjCeSbFab|Jlp4px+&D}C&G9HfC@#Z1nE1o~w zBh`$<{3m9Oah?3e?(C4ZnQG1dpmORLjGX2Y?HTz)xXZUtmus)sE9O07pnk>Bw~%%G z6~3=AO37o?<|@-mh@HBkH=^$d&#*rKl)KY=MQ}f$ulV(V-IzR9MgXp8|dMrxZZ`{CA7q9Q(38OjAPC+*zp@z0 zc#K`-2UNtVMq53N#ImXMa%i+#(vQgp>`1rMW%#?$+0D~xP{WuyU zx%r&lPSUmYMBu)dL$u!1NIs4~2W>_#bE9@y?_(hQYFQ|5r5c5ck_B`@w@XJvNCfGMdnRg*I$QQXMXeSE0tv zVy07m5<_QEY0Rey7~Ok}%4Qdw=*Q3vp)YCx)$vzS2Gv1}P%UxO{77|x?sEzMC-Wy| zP}ATad&5YgS8(6Sa_oRhG6hkSzYDvCB8FxTW5P@;>XY`J9Hw6~oAs)C6sptA^jvM8 zhDtQJI$zW0k+!5EdmKBdkEnav#O|d=(3cQv3Xv}KdFFxMkh;rkrgNiK`YxOyd+Vvx zP_{OmNv%Sjb9LzR;0zw*eligwqHi_3Fcx@;s?=Oi6*rsz;q$y^I#-!r#~h@HzEeLz z?dG1+Pch>An{o7iW-VlZSD?Bl(U=D>tZYnWzAb$eW8ezn{>_b==1V3*=fnE_3D1U% z(EIssj2TDGH=bxy z4T^q;*iQ=8li7xA@acld(2Kw(-455%TQtXvpevys_6~mP9%=wXGiMOh=?^tWR?L&T zR1dl-#%%#=J$Z?ENN&vT3Dj)56tk5o$GAcMsc39BdoU_f6?c9IC7FZBM6eW&GPUUA zXsw2-oqx@Th*rHLnW(qWULP|0q8}PSv77`Qds#985vmUG?R3J?bS`;~Xo%I!ODY(R zp;vu{HchAIn7vS+@YtMy-9Qb*c=AHkyqMmKDvO2GdTKfD`l3gwzRU#iy zp_X5+s!Ww}-cU|xjWhu}@V|^G*=%N^3o{nxD1*}nyieDQ7HPZG9WM2mZ7Xec?0+~s zj)ve<)^q-LCOR89zdGJHhC4bt1m_vYcl$1zE=`d#No%ECQcufW;VqZQ>8L#$00u+> zMA&K>4Yh6RB-D`ag+F)m(BVKKf5cxTST69<_n)VzyM()xE3f;QTlBv0EcFa_?{)Y0 zZ1DW>6$xYt)kmdddbnD2ncP*qs%geL%-R|CeE?)~zf~TzKmwUEr zgR6wAMtYw#A4rEoTnE!*-7Zf7|5pEzV9jv$NY7{<<*s(t$VtUA7uZK!alvNUFIBLe zx3_To?YQI^p*L9>nJHfDsAZ}Zsdyyxy72oTsq0< zV&IDJqWf3+>GadC&aUa{1%7}2mGW!d?_+6;e@D{(cKzYWAxAg8*V1gQS+hp z@(bL_Cc#T92_9iNteNfO?Drg9o#UN9oTHriowW0UBd>$A@3x+ma!WLvYLCD(d0Q!yq>V^3(gvpWNk5z3BK?hv0jre@ zg#6=zOn5}}qnuZJj~G;Iuz9w?8=$(dTx6wA)?wCTpaHwB&8%~++wj#KYkjGv zKwA%MB`_7vg6kqtAu<@`_ROeR9~mwX924OD&Ag4=?cnP-JpD$xBRy|=Anj4wR99Zt zI+yM~?!Do^8aNqBiAeG><(+y^&jdE}NM;6D>$}93mTi_Z(oO3_Yc=Z>YYtnYtv2{( z$1N!q4|tnj__thZb|~`~)0)|j=jCG5#?56uGdb9!peFAVs#vN^Wv#EQb!_$Ql^mBH z9~?Iw^PQ;}|FShIWtCEep4@+Qf9f6SZ+y}|E4!l;!l#3^1LJ*pyb*T~cQ;pY*MI5t z(yye?1QoR)u3&I~hF{l>v7Q%n^*N?%aId&hR( z*3Z_?w$%Dr+KAEE#IjG!3Yza)RHA0%MzeRA%1kF_D^n8{NLSevTra+*&|2(iStb2r z&1+-q$L(SJL3@6CReL+T&A!tbwhR~J`4r}xS)1fFYzwnq=Jy)?xru@kEkfZCuY?nyah3kY}gI@ZR_34YUeU;pdSZ@;$Y`KA)@weaQw_q&GrC z%StI|b=n`sHdfF1D*t$vD%%2Aw~ z>%tR$yRc9!YZ+@9U}W6>w0)L!sfPDtkSLS7-zTQ+@td3VU%GaV- zz!W$fdLA4VVEtKr`@LtpgS}y_%eg#zJRdz{z016+U z(5|PpWP2rhb9<`Y?uc_#bj)(WbZcqrztU;TezB2olv~06%RHq=QOTy? z*rhK7wcM#}jJA$64tEG?fjRy}U##~p&wY2$)!LQds_z=?YUHZx+U;uQF6JrfZQ~p0 zpB>PG8^S}P`4ml^u6H92?C*BqDMF*tG?!?zXqK%R#8vA6tfNkQC;JBbbNe0pEPDfc zHG3m_Q~Ol=PWyYvTB!-IH9|UCFMVu4S%MuKw=ao&;|u zUrqm*z@1?4aJDF`_|z?WMRE|_iFb@0zEyrcyU19MfNr8oE3F=D58H9uCEHcoJKIOw zG~D6*7{?c_H?8??)ocyX%Mn{1^zSfxioKQnvMmP)8qcj=tbIYm+b!-EIztW=%jRP$ zAZOIV6iJHyH=M*;Vpp7->mli*r4+nqouCVjU`I3OXa*yo zoarP)PtreQepQfjf(H2`G&yJqXujsY$KFm}!?VfL-?QJNdF);Zvum`ktA9{nXmDoe zZn$Xly*yEE0@6cf#9`8C8PB#6TyegTz=|)$MwSPb!O~~x4?HbWtY@rG(b|yJYrTvo z$WN=)mSFQ+lhIBFY~iYQ**4qO(PptN0w?;WC5xpFb{7*7$sEWWroTbA7h}ew0(rD< z*XDs5TRmDUQYp-a4hH7=W#3TWJ8xgC1Dm`Dy!XBLykEU}eY8L7{~Wj!)I)W^P~((M z;PG`Z-jIr@39pT((lb1T$ACefB9s;%i}ft8EnVOkdsE7d)w7DVq_vDS#+qpT1FLUG z>jCUDTVj4~wvER)_}g~Wme;n>>XmB1HTS;oFF%%>!JcDSMx+V$d-dEgz#Xlj?HP|{dBYZQ`P`;ql)h_CF z5KH?=y#%*)Cp(0*@zeQAf<>H!6=1aGu7v?}?67oF+955IPD_iWh0=0qDSkgKmA4ME z?zi5u9g(lcpJwWd;E4n{VE z)igGEEKoHt)c?x2-*?=X=KJQm?>pj)^>6Wa4*Uun4lWHH3g?b4mhUNX$OY9RGm#}- zgjP;sn{y#8scbf4NnuS0I-8aI~D z3=&a!@toMva?bL`5(Bs8Ez%IFs#FTCi^rd%q;XOk>6lavt*egv-_N?nI@DUsdLGv> z+HzWaD=gr*a!=T7Yzd|(-3Kv+Zit~Q)Jtocl20Mgr;&5vli;|g1$qQ7`5XGJ{v7`2 zzEq#)i@^vu>~9pf8|WA84|-5agqNEs(^V1G^0&xM^Bct>2J@CZiTwxR-wNYI6Fbs( z7KfBy>Vj7pcq0{)vP+T_hm%ZUsU1eECdH%wvRLz54a~F=l5Xi|`63FUAjI+2xsxC} z0E|T2sLEztGQ`NKyVQ@$C;3D4aOB_c)KECsICv`n{*wQpf1Cf1f3<&#f06&Ee{#SQ z+>16g3-^hvkDix3N-1r+?lKBOA(53%WHPf6_6)axuOI}4jUcTL19kn0<%=Z_n0>{RWO~q}abliF zZW=rFnOaYEhB8m?8SNIC6h0R!89Ehg9{e2G7uXb-9hefB7}yd>4g3}S5gZqa52uCS zM{Y!UMN%tkeRX7|;oWe7It#AF0=5ws$A9Fv2@*c-O7U7&wMqG|nQ-G751V7=IV9*^EkBGa)9pXvxnfM!5 z@J0L#zl?L@HgP`oNiV>+GWjw53$7fuoXy9s#jL4KuYlqu(d=@)D7+J#2IE<|ZA-PAlm9ON(KKOKB%t$_Bg8mk^shAJhLU-C(L zg*;0hAkUC@%Gc#LGOhGiZYViGFp;z^$TXeR|1_Q&UBDw62n}gn@B#|ai|JH4A2Sm% zh!Wt74n~A!5xa>!j=k}BxJ0M3e#BWMaDmEzaWR;i0oUjQ++pqoC(@tW{%_e0@s&Noe#ezmizoYNbr|P}+dU`FrHh3vH zLAk4nul~e)JN5f|x^6Kl7)^}{MvC#mph*=nge)ePi3%psAE-Y+f%u{b9n&ljpza`( zRFNKmF_H#uOJim-@*W<>&Xz*naxz+d6g~eEB%(Cd2MUgh{lY#%=3*hP$%;4u@~BKs z<{Q`|<3Je6OuvG*t0gpT-%u?(9F(9q^DQ!xvq@``3rvl4=wec!C>a0_S_~rHpU~F3 z84)o3iT+l1fjXq?R!~oh81;;i#!BM|T5lQ^$w+br&e4@o1^*P9o?&S9H;n35^it?m zEKD7=`3(9wJKKaEjq$Px?YqEU#Op4517B}ur=$OyvBe=zynugOgJGB#pk@rCYavpb z4zV)EaBzw8n)CkL~2*gS|Vp2A!!g;il4Jqnx!4zbqD7;%%J zW}{GV6bqA(QY)R7~PE$Adz|T3h63%aUuP?{u%vi>JFnQzMBFL ziy!?ujvOJcAXSr7#=t`%I8mIxsasPV<7`vWy-8PDvDmrFn?b7Kirm4!8p&%$jDbnM%%* zg`^j$P7;V45#4wYWf9a0ccaE*yzK>L4Nc|yNL?(!CRCI;QYGPIHzypI*=+49JlekRw*elUHevt1`icu!q62M#dN^YQk)}w_(NheTfYGIwIK*}N4RhKj--N-P^y$w(qUIGi{4f#a~ zi3J^_rr8~BT#jn@$H-9Gph<0nTI~rS9&CZ0@gi2VRLV;ctZE5pWfnR+e&xVd3>YSF zsr#S}>_v;_K>OJiBPKUAvnulH_dqaM4m!gSkU45W=U50Tfn;!J;;`>ez^9f5qv8*I zc2lqsdV`%Z3);?u&=|ae20euO-omK0?}^zx2I|7e;ApHwpY29_&QX`Bo75}3UZC>- zE#mXn(Z*xAYqRh#`(u^NP|aqjVk1!h-Nx#+3S+G!TEIeQxgT_%(&P(PlfuRc?@SI?8Wo36Wbq8u2tX?9${;O<(3t>n$B!@ zyjuD%#~vpiO-S0xoR%P{U~JqM@nLEQqA~;_2sv=2pNJ|+G4G~mR)1C z$Lbx`qPO=J!o>VQhRIRE0OmA+KF-l`5O(c^+*lIwo;K^SRT!~+(oy|wJ zrvGG?F%nw029c%qLS?WZcUuP7-Z|1@{PB~La^xtQtA6fzxji{6W&b<5VB+}Lua>uT zcReoJFmS+KE^XP*Qr{nc`wV{cfN#ydkNb5wy|t&izgM`1>O$6bCJ0(q{vB6=^U^EH z6SZmdYp|-nzju^-K>FRZ?XFAizuYZ7x?hMij5d;atq)jTHggdTRwY-SGx+}E6JfOA z6OT&Y5y=Znm24#u4LRvt5JzX~n)oB>OY+;K0ZG-e_RX<5cS62kzLvQwC3lLgAcl;4 zfsH>Ke6YSa`RMAyYmaw4Kk|n8{Kt>OX+Ezt@>Flh{wY;=zKlPSm?P`jY}>N#$il@J zvsGrts$$?|+TtHszu)@S?(4TNS-%zdzU${dX}UWu@CRHM&a*S6hmPm5ZxTLcdKTX% zW~p6~J_-Zac~lU&kcLXKTql}0vOL@&@-{k4iD>i8>>RNabyiELn`La)hS`T?|COy* zwu9N8W?!3gMXqnzb0(^e2s>9T=U?*c>Zii5sTU_-9DaTFLxI$s=~sM5LaXE^`VhLG zc-v7Vp>SfJEN8P!Oxl^0Cv$ygx^T*@E}!##PS2XQ;&+E%Wq-=w>;CZme3x$bj|@km z>$P+`V(I2+7)#>WOwZyDI@(BkxIN}_wQXcWAd~lg`iHa!@Co1V-4$%FO~yTp%^?=3G*?L5b(%mOCdoHaNYp^Wuj%+w%wIi|$iD(moIPu;(57 z;oYbDsbABW;4o#NIe;0$p6C3+d~12mf02l0t9SELm7kTG3hA|L#5p5m@} z*JxKocOUQAKoT+;ql|o9Ra-EwMUpMY`JC-?re`mlZCKL5Ol(|V$82dmZ!qypDpQRA zAgzs=7T+@VretRpDB}W4J%W2j`t-Dg>8wZbb`PY555n22hk2Nu$T=-V?Oa^f%-OOu z$=oCUuNaGs;(w6Oa)H44^h!U4?+a7^_&)OIgtX4?|GXUo-pDz9K4TZN*~&U=#O{kN z9DC9^)Yes)O07^2gjRcpxO${dOV8nY4KJsw{$`PXwB6KMevP$C%*2E(i5rsoC$CQG zmzX`FS4?qRn$Vm5NwqY$lP!i<@2a;lvYH?0GGdFE37PLDZc6Yt$4M?GFBze_B7X*B z{f&Ho`1=IjyF4YyG`|S*#8#8*@FW~Zxi;9t)Sy*4}JB1b10ZwEtxy)MxKZ_ zt^YWR#!ifHndx)p{#pJ?T9_2b(jbvdI2Y5*@t3Wg)s#L6H%PxwLD#1ruCF(~H2vD? z+xqVbY2$otqVJ6++*YZdBNDSZE=R)LOj9%ENzh}GZBw}G`i<~I@2s@(Kl-PhN?q`y z%H-=EQ^>c9z{G_wp6{J^Y*TsrjcnpT>UKl6w5tR(HqXGNpidfh}P9#~z63 z9e*@IOE?#|#NJo{Cdv$W$Y(QAxmT0qUFP1V-u3FMghh@Q_+uoj4^n{YAlb<&%p0a>KXE#iGKg0rdp zrnDb)`2gFFoCzIHoA%|%+Z(UveC+@GeRvjGEVQ;?i^&yNBED^=9hq-u>YvGoA0De% z%W}1hyP@6bO;R6y`uZ``=Ow9Me;4pn@;3~ZP_q*3mzd&0L+c*+o*i~Fj`DCU9zyae zt3sUu^ZjW)pZA)V`16GG%hT1J`XW+;ddch*4#71do2`?ztYr$v(Nn-NX4H0aZrQ4w zRO=i6Qkl7A(P16u7#-IvbMK@~S*K-vpIkU;YvxP|O=FANRsIOo!|15Cj}{463_lCE z2nU15{eC$6UiC~5-O`RQeJualHD_AP@t9IEhaHz}D=c@pBJ_QOQtLz>1{!+Lryu!U z^!LKwjnhM(S-~OEh?<4GK$VA^%Es_G+vY@;C@+7TZABL_vm17eSIWwbjv9f|QBR)Gs~^Z||;BUf~A&geJyhc^l~7hvAi3QO=>cv?a==NK9lrylMv+ z9CZN7mIgw0v8ZK&WtuRW9YrTm<%p`ag)46;Qa!ZDFMAT)*PwE#%lU37f!@CEzQzqTkYsS()D{uC#2E?A9gLleX!O;c%Zy zjveg0XDcTa5X;`qA&_%Cx4Q>w$^UYI;#>6uVTIEj6|ebUutp zik<9SVjC_lU@99MU9lS0M9iz9cU^A)?Xf_})qM*nxR1+4k37U=-y zKub6X;bVaoll()oPRju;EPuyZdihvusW`q zBSp+h|EK?| zDULfJCRwvub6HyOX>=W&EqgF2Y)7sb z--Ca|?cf^l35b^E6&H$aEK%vSEzRz>-?Y`TwzZT&<~*C_y=AoJjgXsf4W*Sx$3oXN zp8R9<*V}8c*ry*df06Inbh%UHOXzwaS71lzlCs~ZNwtRtjbU2g#Fd>nLdB7&{zC7q z)`%Vr9}M3JPWB)6z4cpz$>BG$qA!7R@G|`e6f{5_1S&5L@Y;$(x~ zQmdd|mQO~!p{1en;osq!5fV8oPXWDu5M7G9%3l%|iT_CB?2nzvv2S7)I4|2*BU3ie z)=8Sgx1e7cJGIPO0ezH_4X3masRu>>2i6dZS~uIrJEl1<+FRRBNQ$ME6p`YrytG=} z#chH6$u2EPQ(P(L`hGS4QrK(y&$0N>MOo|xm z_1SthZMf1o+B?!Yyf55do~JKB#a$IM7x@d3tiogp-J2^VTmkQYGP{5t2R7(LQs0=M z*ViO9o06ooQcgiJa|-^tCd4G1iMt)s)X~%0 zLA3K4DyH76Tf@(N4Lsl7#Ix6bAlM>QHt^BSr*BAW?W*G)5NH#vucPvZxxwUN$AXug z4K(cCd;|6(su4?*(b})*7dX$~^ELAa0&7E?A`T@%TLb5^wqWSjq0`~hR#H6A-(x#6 z&FOVu0rWB}kyH9~Z4GJ=Myf7#vGz_ItdBS5K;@Z*PXJY%6Wbx4T-vhB@8Zj~Nd_uCIU^TjTW^~BbWs}nmL9#ntF?2ozb zcwoINIGGf9JDtKlrM@yZoGYMsM!FuSA9iK&baOKX#b z3qp)=72fB^Ej^^p$O8T=UFIiH`A~r{FcJx7g#xRd?+`qBO8HBN+C<;MJ>a?88#OOK zSikTdeic82UtAFU|1-=-FvgqE@u&vstWod+aj6 zTFKtb(Z``6gFD7n(#lFTEgi&)LNZ^58^->_T!$X60{FtCpv6eA+>;V*mFx=~Gn|f? z-EiIN72|i*w;!_hwv6P5GTlu^?=Qa%bq?5kemCWk(~71g{J!_=U7Evn8d{pu-oFE# zgAaqZqD4pww?%v>O_vTrC-WaPB}7c&4p3i>P1+a58+{o%?ceTc>pq0@BZ-t(IAwEm zRFqa2sD*~G6L}NV=5Ab3WbWGHeA@u$?72*1C~!xC{o0uXplggrZ21(brrUs1+kx55 zDqISGLO3VZld@PhS_{}dTO-&x?Y6{PP6!S7XY4Fwgo+{xG!(IqQFIq5`$llL;0U}( z%52MR&+K^ZcntO2YkL`cCR=amhN$v0Se8CQ-s;EI_Ht_EMEFdod$38MtAC?!rLVMq zL!fHtLU>(dRdl)BT`rD{CoJsbyvj25nD$cdZ1gdHYZui%+HPY6c|hJ!Z|KqVJ91x( zQ>V!bl`GyVU`TC>Mis!V#!qR)OzorLR#k^$oQy)e%j6$5ch!p*9=B{jSd} zLrmc=^v}Z(>pF(WU0J3YB6ORXZiwvmfkv?iUmHaBCR~(_L-hGL6f;HHElgqd6I+X0 zk8C>2@5kQaoKOIs!PBL4(o1PLGE;S>6;eM*kWN}kTK*7!f$Tnmd&kDGWtowvQB5_2 zh>h8eE80kPq%vP#ipXG4ppm_GnpBb7qROEMEs7Ty4#A#+)HXFB2A|e3qJsw*Fr=;3xMXD6HMma zhzeiB`qm9KruPsZQmNlmbGjZq0dqBuxy^8FS-5)EXA+THDT#P+9G3$O`YGU-@8Hs) zcY6!hllJhYdW>gKec>Ro$@jr=UoM;%{uS~G7mx=jhp(bSCvm;FLQD}KBI~GG8pBs2 zQL1BUE*2I35G1)k_ zHe5Y+^W}x-$eZ2~6QmR=BrTEtkv730@sZ_>I79fGU(es-U-GwbEq_Dhya*ZBF>p_B z%9dv`(Wj~LbYYf3CN54G##cbbXd^#HNW?RHikMA&E_4xG{4B8I$065tg1JSnq0)(= z+qA84*!&o*9607{>a}|#o*kYZ?h@&%f2aPO^y?ygmxubpfd#?w!KJ~iAtUlsZBJ6@ z&S0}|LCx(qCOdQ;Az_`k4xh4EtRb0JoH0VKwwB^gTE$ zu)x>d%Xz1IH~1F&`vqPE>ILTq-v*n6(n4b+1?4j8WUUNx3k8icaP}#KYWmD{F3jYb z>?q`5?z4;8{M-iYpB5oc_XJtHwTMJk;Wh3aa$(CczRPe&*mNcz^M*$CBRJs;X*d8= ztIbx3PG`_(JYWWlMZEPC^_0qoO0yRrjSK7xrVnFfTEOo{W4ws%v&>k!3cUz+T7bC(OYZ{zpMj*q~nRBAgcf;i(6+iDhmj~V?A9zXl3P+cj z@Xi{}_k>?bLu6J>cq)|OmcVVRGIJEUmF>uzzDM>$N6ezVwncrZIFT(M6FnVCj!X>O z!|UNCEeDxUrO-d2wW0N)L7_3B3!z@&ERh?LA<>u7mhvNcw31JKrasb+=*x^2$n0%H z75+174R+TdXig+}06gOC7!Q;A@yOz?;=k}=-YR_OZz7}H9LnU++)qw}1|TO|cOE*) zBvjD8V!t9oS(eMny}+rkIQ+zJGnbjyOcXKe{D@@#X6`X>5W&vP)@3_lhtUMb|C zEp`EAx-7_xqj{p2BI6^YBMT!BB66f`v~hGKd}ngX$K@)@Rz+0Xsyo$}Y6ESLmV^k< zWj)Clhh1l30vty7OZj7vDCiWLHuQQnPOe&cDYq4Xh47Z)@ATCruO~y9VCy4CRbmaSz zp$;*P2(rKr|L6JTrZpgvZ=4v&|~#uJ>Vdf@I~BNX@(8FfkZz;jrQe3_3bg+0J!xCmr}>&hTz z2lD{=Ry(}>im+YTmB__k!=2m4uElDE=VICeu-ud?bTr?;)k*&;jfnUf%mZ=ZOl=s2jONM^n7FNhD$l}#PhA$O9630>Nx)SZFMY7>8r(s^cga$=3 zM7a8Rj8Dd6jU{tJaDIbj$HZ=XhSq2!A&cQckh!Y zuo?8M)eVxY9$^1yE>qfMhcdZCru2t_3T5KC}#DkrnNXyl7kS zvPVNLFc^I4R$v(BMUHy_{_hwN@mqsNl)=5MhgIq{*3DF~<1gXB5RMdt+ zsdEfG`>Rk6JVM6%9`55=aDi_lXRV^A^WqB2W2NqjwPQJY^a57VcgQq9hrh^qjI2u- zQ|H0hpNc-r2L;({thE{ZV;0PzFrGTEpc#0EpPRw|eTH$F!Hjd^z5lQxZN`QLGGndKx~1$Io-%CuVTOykO~ML%(IPJu{pR zGU%-i{GJV;n?c6PAaikeuQ0|(JLKSd;LJ4)Jv$YBI|omdDfn9tyx$G8e=uI%aF=T1 z)e!foELxtyy3XJ!XApqzVI?|-J9`;C;tcnc+vtaDxONW|M^4n)72 zy>KF!f>m)2GzbUr_ea3A0NPvwyKKl0fBv+aI?J&?gZ%OH!V;%aZ;Do>(6 z9)PX*0rxS3QTH5QrD7)4t%^3vQ>=->2(4q`({0OWD^)a_IIIJ10*%G*_cyPip zW`KzKlR?MKpppMSjZ;M1WB*59%b>c2@bfQ0OEL`e;1r%4JJ4fE@S60RO|Tv$)0yZ~ z=+|%94+r6UF#w;|3_YAd1IzI0Nc-Q_?SkfG4%7>Su`=&PUFT@9ypG`6Z~)i*1b2TI z-aQIU#(mt+x46brxU&!O)o*BcWW1Y#mEbt8GQ)`mCmgiO4QAjc5bZMNF9l836ZBz* z*V0j}9K*2cb~EizCS|Nnb+Bp-1Vb$|*7L#iIsEUIW(<12I5Z;?v?|xI3TBL*D`?L} z{QqLJXGC97Eu>()t7#^S&ayNElNj(J%XE9L71ur+=NvC705!~HjFLO>Epfsf z#lW-roY?@{l};GxN5H+>iCM#=XRqQ6a~w0Y9>(ZPJkNijA~lM4&tYu5h7xKIc?tH( zLGZH1;OXPXUMe$~Vf~m1^kgcVSpz5ED&}NFvCm}ePG}Hqbia|A>PfH1$!{~2$!u!W zHw2s#c=)}2qT9i{^bpBx^abhSo_P@K$UOQfor^kP9M*2>zepi!H+=(Vzn;_@^2)fD z@r*O)gF{!2N@nW7OKSmD20oHK;ey@8=xKh2*6WPfAF874=4q0VdD%x7K=oH!^8#50 z^2AH}D0P7xFjtaAh(NEyT^(xng!*a^J%w70=i)Rtf!;AH(d9WO?J*{iXQVEwfEOTN zecNb(@ju%9L?;WMnUHov*{L@IlOQX9lK(;PHsXwhq%l0j=7JUS5Bmujhd8*yZzU>y zn`ukS=>LK6gZhR(4jOOtq9mCSxrOvEj5b~Wpw-q(VGMkv>cG``h1pB#tv3g4ZG+yA z`YkqK!)7zgg@V{;2I+s1AKCy%uyWKooO^Rn7xY==v2N9pjmAPVsTVtjdT8{L_l7Ge zs6<56_JGjbxDb949b}He9o<3?vHZbBmGaSjT3v1}96by0E>l5H;i25XSk3gXSjF}1 zeQF5mB06gV>BVGYr}MvrQS33jW#mjWH+jO`#O+kQ5#0m2;)5UCT z{9#D&cAgBC<2rgB*4y{yRj7cjnHw=rP8)4VVUX*FGAuU&T!+>2Eb>d3&fnlvuA5Oa zGFJ{7P3f}CcH3B6qCPmBTRE-C#w+H8H9sH0vv-UBOYNz2F;_Ens1;mU!N;ZeL$N z9I;2vhI<)zELH4PrA16xbxNeOyoOoKzo$!K4>yg})%%hTs0w*yTJ#ohe@fWE8k4{UOe2oGd(*k7PtY!^3La|U|{4$0M-1V=*5LV87X zo6;Wpvz}boI$ap6(Baj}HLa0x%o-Da&5~m5kK760SKi25D2uIe%mVR^nkLr^kN0=d z+;%1In8it*Gm3^JS3tfZp0WP6T$C{M49UMKa8(X#E7<-HhvNi&Qg6#PGLJ@D`Bo_V zXunttRj$`8=h#wex_?`siNY`?t@9iUr8su8@lGiec16E1U4;W}+29(iY|fck-E?CFm0LN#Wd z@jluma!LM5P(>v!uwLQMn-TS~cAj{&F={@r@;30VxrxFewgMH>t|>O9f|^Vn<}!1K zm@lA*ye19RTKZog!;QySs}7CJJS{;ziChp%4~GNqaVk+y)AMPiR438-(qdzJmN|oJ zjM|z`#ylpGjhb^o6Jg+G>Y{$o8Z(W$q3h}%ZHSqb9U?vxK9ccTH|34?-6Zr}_ADHj z7c!HnjmB<$FR4Jk#Cf$F>oIn!?Tz`Uj?Hc=bWQ%D*$zIDgQy@in_0}&gZ%0u4GItQ09}Efz+Yopn3do-8V?eWo36w@pyr$1ajuS` zhnvTctDIqk$X{$cVo@`>kED#=37Xv8WHMa}9*pIgUEq?ohf~`I^R}@X@$5a+QkI~; zbBb94o7;`BUe+u`cc+({Nyam+ z38_QBp^M?Xvl&lO}-cg^-C_+n%AYNsYDW{QL+oIPtbF*I5w9F88FlWe3EkWz>f9-vDoD{{@_T)UX zIl}G&yOM*5N|1~M0RfQ=!UdF|qE|p!kRS*sSwKNhk_adQ!W9IRAaW5<2`j-BST@1t zo!vg>Zx;}Z6O7+W3+0&>NWHp zy#x1wL$~{S`Q6e~STFRTj}T$w^IQLU?4-&O{oY@FulX`BQZ-WDLsO)#QqR3^kvr=C z*16sBx}z`l9Nno-sP183TCt+Md->(^=@sKEIs4RVg`=ax;V5>lbfvkMd(QI5A(bBm z@;g&%iG5v(%5AEJ>h?gyJG4*hkLq57!O9c*RD;I!4E83!YCdBA+1$)L)^x)BgmtNP zh;4hsp2$BU8$`xM{ykz&)V5fA?2FOSwy(^u8K%S1@h@0y=mZ@meU+R1&j=o@nPfW8 zI#XR;oT}#F;_=PPazzf(Bx{ZTR~ z?kT;hnOFrIiW#|l%^+>A?x?CxoiEw78@}j;!0FjY(kPfVPou~h)j#lyxDlzlxS{ddfG5pGedF5*H+l< z`MYbp^O&QaV|&$R`@Ql{$_-^JO1~*F6fY_Mt=L+&ta41X!SxC(M-OtxxS#MG!z%PV z=t3H(eqT3R*BGk}tFgYM)aUE===&LanOYft(Vx?G(f&=n4SRIzV0@K>QJF%KsQgZO z1f#LWSk0QEzJc{*xA7%QWJGCHgV+;sZzfeH9ZJ?Ebc{U`9gK{RTx&f6#7@3$uV%gC z2dS$!mP>a2X8)q{Z22!`J4$29Dod`FTqu6AxL@(K;$9`AOP%F2t5!NLJD+v?xH2K# z>+}VJ<5gZ|dsU%2*JwAbG+i~cFg|Z~Vg0Lv!Gj%7b2W=$Lwu4tM%6Cp_7A{{`7tpd zru%aJ0lyw!_{*UK^n3Lf-E_l5%aw?4Vk+WG6Z7hxPwQLn-ITS7lM+V9j)*F)Nl|rzHrZ_HWuG8? z#y`bHd$zhi@*LuB@cV?Ou>Bk#Xb3zgTmz>#K}&AUhgc^DG}))>>8pw=v$BYT&hd zG`&=PgN>ya?=gOXyQOQCqr7T|eY(BUKGELSZmil}z0^2wQ^x5>{29|S=A{pxrJc|bTrNL_Yk*udbpfb%__&2Z!B9>*1YsmNz2kr zrAx|wD{EF+w`#Rxth=vp#@8U=RQ#@PZ|GtE#5ODHkC?^ruO+^l+$E(V&D~&WMrB5J z#>w;^=^fH->7D9Vq;yO^6DyeCQ>Ovd_lmPgd3uSt=*xoMd7tHvC}>@9Jojk+?tF(Yc-3`nrm>-A2z0m%h*%7~h7#Iv-Z#H(8mxaz^R*)19}v}i8+Q{& znLVarN?BG(UdhVRvnB4*mSyjk536ikRo7J?80CH5dD5?nc=Z|WlZGU7rDX}!kG~!# zB;+Jj))`dyLdu=gzV-UmKUVKh+B>Pf)U|2j(uSvqb)HUK9aXB|hzV!Ab8ls@;Db|bT zR;G4_LhTT>M%gLwt2dT^7jh)7azoj{l6oblN~%h&<$7qVNI~!Mab-QXi|4p(VZ3jZ z!mfJYZuik_8h=|1Ctsie_JQJjw-bdU+V`o`Qwr)lQsVCEyP>qbo6qNdt=dvd%TF)SXbLDB`6|?@aMJ|E_19>$Kxc)tZV;WdloBmRv6G z4V^Y?%VH}EtE0L8;uylnes+V*t$x!EoI<1o`5`Kzv#(ZqvtC-52t8Q)YUwk8f!rei4Jvqnk zzE-%j*k1fY@&3|;%EtCLs)u_bfce~`d`_ET5hCwKkBE(r85}j+TGzBsKUFgosGBoF z8Q076y1Udh&1H3LwfBIgppMWE^G5lk@((Je*z+7yJza!0-Yt9fJ4tDZg<(_c8?)VO?s2d!eoO$p~u3Bl|X#dfE#Qv;ZUp2=u z)U!({@-2fd$&u;?n)#%a0xSDDKmhdAMHxn#Jiw;5jocEoDcTfkh+PmfCptSSIyyPJ zVRXZovez~d%CpT-qS zp>1GPe$UV+&))#*Va2(i{%X_pA6JRfQ$J zOIF|SeNR`CT^?!At1PLW!!6*~@Ym5=PWm75uMON(PS(uV9Wiu-&Wr2V0e?|{Nb^BZ z<1-3t-5&wvv8DQz>Z8?}&T7}oz;g#Y+qviYFZl1d-?tVmn* zxu`x-TOzY;Zi8N(8O-)&bBn7D6$i^kmMY5IRd%UrSpBiX>**^#i`CSlzHEOQ=0zss ztLziiCUs-&tGb2wGVH7y2K~C-q@mt+LY1e=Wp@7R=;|Ee%5it+O1WrZpLh&wZRbTj z)+7h|EdE?+7uFRwC=!snnOHHLiM6vVtm5v$8p(ANgrWeimmIzxt zo8QV=SJ*~JoQ-G^al-nwrNHv3wFr2!Z;e^{yXt$vDyfCPLionr+m-3O=-BOS>QV4L zu!}iY9F6^~GyHX=KO}|JPg)#!96Mpz^jjSy;fAaBaA5+(_Yjp+7&5|59}NX89KRj`(ANY?uy>qM3mzAQY}h zhov;^JiCV7#-evQ)-pd9Z{wNU!sq-jek-3O{vrM*CVBByj_+6wa0Y@(0DS`AQ(j#nNi&sX(z*>A&sYV69* zN8FzA{AwZEtM>1O#@aEM>0ht-1}h6YFw;H;^UV_#QA#CN<0IAWH9u>1K*RJ&%>?ay ztgT3G$-28NsJi+}UA4Xjag1^y@#njtzWABRSR zZGldKLhMkt1-mNdDJQ5}sn0{xm>xUfhhU$%0&{s^Y7P20!%*X=rhM~J%S7wntye8O z%%7ST82cMi^#gQP=piW7mFvq5lTAa+36@!w73P)3qZ+$nOrVP|6UJN`It!eSLW|Tw zzQF7DZT0_58iSQpSQ*WcZh9XTEy7X$J8mc!E7TXKi64n0#G&Ffz7>Div%y{NguWT4 z%GKX(#p(zEsAR7kOOLeiQxII z<*H?&WtTbEIKXg2(_hiTzgIjf)bX5mlvG!CL*?z%*!d{+kclwY^V^ zSE09H6ZbSwEF~zdx#B5N<-I626WUq63;XdoVYB?9`oNr z#RmL7&tOjkbV4L^_qgZ9X295dCcS{UnZd!~SeefA&+(=Ur+KRo@I2*i=1%jx!A#vuPN%pDX2R$&e3rJ#gexswAor3|T!ROat0 zb%wTSgCb42RfQQ2SS`rW4u+P9CAuedS=v(Q;Tfcxp!ZBH$jPBH_%2}jL6d&OPi262LSq4!gp}E1{S=xcOXz0 zd6>0*)~Cdd{kO3oi@Vui1$Cs~b{VzX4kC_CgIvNr2T&R_vF2N;&|o+DD&PekSKdeY^j0oXJ`W_ANp)VeRy|oWSld*03wu{@8Kyu# z(rV)kBaas3fX>Ac&^5IXt^I(d%F@F6i1i;9zgchYZfb1I*Jtb0y5`ylO;2b9oTlsn z9pIUPE|SxC%DY&63iDGVJ^S1j+>d!?cs!mczFK(C+Yx>8Vc+Y%+undUSe(z-MXg)t ze!@N7wZawa>BXJl_lR8)W2!$7I*-Q%3xPN|3_TYkfVF5HxF!8WxfTo?MpL#H~eBBJb1fE*@uX@*uqOe66 zAzb6Lc@IBY(24JeKZ#y(hBw>0-s=~ai0h!$B$EGyGjj2s?w-cn5zfzj${WNivD6#y z*GlKm``Dxj(k*{K?Dgvh+}H(ZyuK_|VuW%fxJA(c^T#<#3$Q8!pm$@SsveGY!1`>4 zzL3e93z|%Aly14sql?nF2D<-oeSdv>{XqRJ=!*GWpJeE6$S}k}qn!uWo1kUpRsAda z`TDQ*JM{DPi-2uxuK!$T(Y4UpG}Wr_mE#m>!{`MoflulRJv?Xmv3ytF$2qtG{4qY4 zR|xM38gYWyQA`p~3Vno1emVan|2`+dwC)h@H_pv%AH8=SXdV11UxO zw_xQm6)Rm|V13+#GCHXkiWRwZl~EO^GD916Q|9+-QfMsiTI=I2ITThS}J!UZ`7(-l)I!7_gzcpy6Yw zDoa@jJizea(!dUBhyPoj()YHP7c-%4=CZIHyUBw5Mt%@)<1KtPq~TC*E!T>l$S>vp z!KZ=K(?S!m9rPteic`cmFDw>#2SbO-%f0}5G11>y`U$A^JJ5>I2J6E+F`qXVs1m=T zHIO&$RBx%ysM3J08U?K2BS77?gZ|Eynsb^nn%h{JvTC2!F4F#tJ@=fpJ+x9O^ph~V z<=0O(oP#!^e;Q6=pF;{pH`Dc1x?#|XI9FSt8KbFEuLs_5rs|@yIZ#>Ez@!`i`e+&C z>^1)r{*^G8cEmf$dtFQxR|=g3jc||unxDas0Cu^J?iJk{U5V~7{eVz?8?HC$FY69LS5Ss7 zPn)ehioH<*=-X+jS)+CWr}we402qh+SWEsHdL3>9J=R6C0~J=+e+uI>mv@x+6y)9? z!fYWOJe}lE@xSvL;aTB;&`LZcHuTQ*Uh*bl-^bg~C-AXvm+vdzk3Nqt*8iyg4QRIM zFYT5hq1C1g{o6($4H`j890roUHMCLeSE_*;T&=pSGGqVXG^|&A3w=j-)IN19=!;#Y z*$j%&mq|uGgZ34=?M0ZzrS@$`#9AyLldI7r(4yz67_pvg)K{*s!Ey{pZ znt`?XMv5!o$sF7Tt_r1jk_LL2hWQ)&y}qly-M&oUFkgRPOCRq&?p=*9n^s2WN+ByzkFH&#dO8$Y>_avY^-hwWP z0$A0W16*7Rb^}~cHBrw}{{WpfO*IoRtNSwQ-$>01&`R(OMyMk+eGxiG^A7Nj{egT; z*5s=90PFgcIu6*lYE`AmrQ(1nMOk= zeT?si3)t^?ANpEUffOL(<^eTU5NHX6z&TiOn+mNW70`4322knyvG1`2x`$GLY8?&q z=W1w=xv6r5FtBaagVe*Inc@ZYOVBOzcj(EPuAU71-(c(-sSBL%UVM%AQ6)eF-fp1f zo>E4k#vK6i=Q)&75GbvWu#Vmd66*KB?!X+BRzkpyeEw2eAYN#NX5~Cv4}M_Fax?@wgdNg3w>)WbdB@{ z{$VZ7=)O6JJll@+ z76Jv;0BdeP0Bbi67}PY3Gt1DolmKIx3lyRQ=#wB0FLGYM!9#{AuzJ`6BY}}X@y)=x z{W@T=wxBdN0m-)y?knJRE&#c7A9x(HTS+(~vf`@+s)(#~lf_-a&k-)KF|c60(W)n) zR=y1s)lNu}6QGmub7vGsfTr9D+{;Gfz%KZ|1l7mkj^bN!53Gm156gCM1J^bMh^yhi zTlN7Kras=|0tW17Ab<`+ml9EQ5LlvvKoxC)eZ7Ui0}Vr4YZ5{x#V8<9ngMk@ z7%StipgdNBqjkV!eSrTDQHwXCANm$(oI5~X=|UK|WQ>N)z&T*85~w4xMn`xn5BlI# z@bffUz;Kk~NKn)rn5)KEog%x+WG6WT2%-Lp@u;(lff!o{9yXy|KZJh`b`q?_@gca~ z0Jj1yX%;wp9@sRp#CRL%!|lLJErMGZd^flpw0#Q7J_k~4GyLm;np^@D(OleJhU?8( z8{P(N)mK0ZZH0d$IQbCRp^dn+9bsRf)_sNJbHv(=dmkXhWk};ATod~0d&r6_D8;+r zFc%nAA)ebZmSwAL=y%jjfuI>F09+0g57UGR}k*BxNE-nHebqu5HUEpCgYTII<{$``z zy@BIRAhPDbEkO7h)W4l5>*GLH{Q~^gbsz(;hj5lzNac5=m5nru@E#5|lB_?+p*+%1 zU+Q4BkSu_bRcd^m14|VHikkqv)ecz29&lYzuUet(>OfAL5QFSelQro?JWcW1zi z8d+>_j{gkc>C%9>i$=TvT0sG5IScIAmuMkdQ44pVT)qaB~W)GL}@nuFNKh9 z*Z!o{9>N_ek#}T|l`I(-p%!KV3r8H?!IdLOc4HMGx`W`1tlr*5I+sy)*HL;!sFey( z5e<48fwI;>rIA%~a%6G7AwtO#JJ};o0mWo@JPNsE!ZT#&l`P1T{b90doC~BT;Wf$f zFIo2`yU=9ink<`YLNwA}0MC$hS+aCXwr{E3YeM;Dgij4QKvr)h)Fwh3(q26)-bnVh zqfiDmAeYslv?Rz5Khh@axAaeeWCPb9@~aSwS>q-v@ANd;aV46`qAl5WCM(Kr#MdIt zgb?>FFvrsj+%`bzB%_S!ZDa|Ztkx>A)?XdU-#p~(HI!Et@Ta+`ixAP;gf&LqCIC-Kws5%+UCaVC+5L7Qm%QMT z?DrDFlG z4Y*sVb>(;`S;dV3c)WAI^eibDCLHDV^bWIDVX|~gcI2aRClP5T z<4A!c9*Md*a7wo3$znXK&1C19>@Sn$c0N?vRN~Y-Qi?<|NhIQp@TJre%yC(pY+G$E?H5g7ENuCLp`lR?J7f?FMxz5JK@y+$+|XKtrtUemblR1pdZhZ~jJK1Tk4Ef1N z&y2gAP$U#KWaJDGqLtd^_SW)U9-N5)qd*3=wNw3QbNuvqL=c6oEv#b zy&Ls!EFIP+$(lS%hsg@M_TnwnGte99p!cy>L()T*9Axi31`;d*PVW7qLVc78?TT6w zwJ_SfK&{Li>bW8yLCHnHSrJCNgy^6a$RsU|Q{=p0eF-*hB8>bjXM&)GY(Emc?4PxM zR$quq#wl^ZWC7blK~kJjVrj9yicx0_QDFs5j5Zr+vqB0o%1oiVv>$^;DinkGCeEn` zB<`svBbS7}ArWD*xEqaFj8B#trAT8P+0hmCO(ZXC^2c(G`Wuo=`cSUWKha2eMO3l8 zw1oWhPhmCFCo0((AsTeVfF7cV`n3lg(H{?*i38SqQlCZrb7F`ycAxe7?5mMdq_ipB za0ugtZ+5&5#au_{Pv)>E%dNqBa zP91;rO~Aej*gu5_wQVQ*8M@y9&!0k~gxWo|+sRq0o19*s(BKGRwUMyJk;? z|HE;~C#ONZm^=oO!&pofPJJRtclI?O9xqWZK)n$L$x|VsB zW6QKs?y^#mOI9vhib1@vcgbn8=fk|q>B;vWrnF|ZV&OGMTVYv7F=%xE;4d8GKl9O-0XyWc1tx__ z63eogNoBfb;~W|-$v$?LnKF|JRIDGbZ(-;aF@`KqHo#j*S$kKc#U)?K`!fsC`$CDUS$foKf4c zknsK5K6<`ph@2if*QPpr6~4h{)IM%bBj^I{NTAT!U+lHy(~x zJ4AjeJW63B9*QO3lb;B;74ot1j_j-5s_3eAI}Eo-HvXx3&HU_{hr|C>h&)5U?z1tK z9422qe5Tk;UOae@q{&~qe|?AEC%;o3*RinLcWTB8^YhnlqtI|#;dIDXlX{lszfPm} zo$y<0(h@GU2jyb;4m}yZl6`-bUYJ5gf6X}LuT9ZkUHxZ0!T(QBu|Dv@zV5;6n*Hd* ze%9~O?7+Wr)H}0-&AQe8XFa(5&&Kntx0l1@GaC!YqX7BL<|o2e@<^S|@+kg)a%Lla zIcDvz19_}cJM_Q1V&fe7pTaU<#Cfda;p72T|J!Y!*Rk~$-bIr^2^sU=QQ#P z`^i^xL?-9zU!7UJ|L$M@c9To1_L-G>xCXFtXR};1@5Ef#Cx^)A+Vzi(3F%(#@CUCR zthwy^;d(BQ8s(KQImUyn<=pAU!s-}u8 nn6;myvaTIc^GdEIHN(hH&(wU5`NL_k=l=Kqe{lAV^TjIcL}~vpbt7b=U8lIo8{Y;r)K!z0Y(1xKqz`S62=vS9SHH4|MICQCDVt zJM`)D{K&CYos2OF+^(k?dvhCOGIO#agT@YGkmhkdhJV0U@ZWg}uf*)|8drXJp%sr ztN}}f6pV2w`xd{%uYo(qFYv4UI={(tc|I@VQLbY)D6J-|3+^6Pn^<<$Npu zl^@|}ptf9Iz>9f=%go2>vyQ9}8_Hg1bJ;g+BlK}S^l=m0z?QO)*lhL=o5Ws$_{Ui% z))G=zg4QK49rPjsy(s3TJPfWBS{{Oyn_yI9T;VG8BLe-o!2f`e+{@SSg?t|Wh|hx7 z%;TR!+m=AsI=-H7DRtD+w<9RGF>KQPT9bgt80@szbVU3^!JM_Dh=kP21Jj~w>euwA9 zM=}C^W-$L!9J1g7KRq)u3v&Z(dBM41Y$DL21AHxv!6@DfX0jQt!)x+dyaDvE3-8Sb z^5M|G+0d8ed=vEU1f(y7kyJQ`(y@KH5ONwubT{;SBaGl`7>AW`-vIsniEoFIKEf|T zyZpQiawIYr)a-#4*r6p7wEPalo`G@?K^ecn+#KPj;2B}?3Y3j`%rL|C*}VW2-C>Nd z=WSseszDhBXn!CMx2O4WeiHJX1a}rj;v$U2h5xv-{3t&N@VXaT`6KjWL)@){wyuSi zu7&wp2W?&f|CRhZn8~kU_Lj!~OW}D9zEG_d*+z;^n&HknV)BbH?W+5oQEO zJ0U((MtDkyk3E)!b(cX6rE%Df!Q99Y?|^c!v1R%5l^fft7gG11hEAcrx2-tQI;QTni<_&<{9OzRtK1&D*2u%n% z`aj!)GjbJjUWM_i$%cdfc{Uih!lTfOZji1uP@hIn@;%T4>_s!^O&bVr z57f33;9v*9K6I@iv<+(oqk!o%p$!#atnAQwiKzg4NVjre7ViMO_~THIa90YD6a|O$ zxdi%N2-gt6mkbc?hWr&^Cer~zGN4yA;94y{vuW{=^!QT-^u7}Guws11an{oyM-70r z+Q9Yd{n_Hy(83NdJJjM1@i}PiN>-H#9@D1K%d${UpqqHj^Jwp zVf7$S2Grw&*)hbijseyf;&^HU*m8j*sH+I2Vf(T52pIC=ufn!iRj%^L& z^VcYjbM+yl9&qhC@JC3g9{*PZcus{pRpSnGWO_2@_9840P4Yr{i4e;Gj$<%WNR#}~=G%a=*MZjF0BpPi zJ@G?-5PFeXKw{{J5qgR=6=_Q%I7_@`ScfYcWC1_=>_{`w^)QZnc6=*{W zI1jYb4CNqojsebup&pc9h(?9r8AC8kf%?O7h{C5B{4oqU6t+qHR0zX7Dul|=QiM4i zJsdZraXuIYY$NhAsx=&^wmHyO>hTTee-6+fl+qCXjnF=8eC)6%h=+)Yh_C1n{t=JU zA*?d=HRaD5>`M#Tz$q|fNEUhFOQRRNg5@y?CI2+E&%@JGsleU8LOLP#HiW0K^I zJuTm77=Uskz+qHE(Dp)@vqEqvQxPvjj6_!o4zaT2&om|R`jAV?Fr&nCE%7^Fyh-2E$oRfix&JBgCRZAJTnvN#F>JP!jS$IQAc5 zzzL&(4sjo$AM3?=CoID@Bb?HVBmRn>U<|b%Ap|8vghUF_a2UrHOGJ3YIuMg=a3$D7 zN`sV|t|)U8{$VRH7tIREl?2b&a*{j|pHZ&D{*xmN$59a+4tX5%6v0t(-bwbN9uux( zt%xhw3W68J62uoQ3#mmq+|g-a)q#Fz0#&RJG`ulT@h0G!#U1*QA2bB2-XPA^kWV2; zL+YIZvxqZ+?Vy=N_{7;nsH9koOa6}&sc`NQLlK%WJ#k1H1sntPQ5~2cxg5?hUa2-L zk*GTM4kcief$@&L!rrCFUG;ctQI?^;Q~xvKGD9usb6w~&_PPP^V8OdHVKh)4!hX_7 zAxu&Wu@;m|#Vk=>_=MC5Ye(3{Q4ugn@F=jDU>M`E^*93PXf(u?#uW1l*eB>m3@3*) z9sdM_ct?jJ zJ<@rka6}h~6A)(*+<~YLQXZr@ctwgKXqDhTh;f96lnQepMI|RF4u*-+HTq8V3w$Cz zMcjvQkg!s42GLq9huWm!zi0!|0=y#i)Z`qZLE@@$2c$$q^+XQp1yL8wPbrWp5j`bp zOSy^y;2s}k)ezJPw@FrwEqx=772 zhu}cyqrMB?jOjFu8M!9%O==yr7W;rLtrZ^^l*^HSqiin54mk@t(y)=oh&d%bL)-;h zhx3PXhK{%?K{0VugdprS&NQW=CmILjt2j0kL%c?$C!Q+w5XZ^ku! z^rOaq{Xb8b6D^b3@JENbnb6Msaa|0#C~9J8t3)1)PS{E`Y@r-8rx?o{9g@#O>fG;H%=S#a9syK^*G4*#1-T zm4&0Q27viQ?N~C#Vvo?B`LjKg2cOYV4E7F38vBZ?3N+&A7h_*OoYJBd{R;eXMeQ1B z+XzMYM|ji1a6T``E$%q4m*WmKc5=9iLDqOogR@P~A`g~|Wr{n&EgINVE;*d!%mUgdbC2h)64Fs-U8R%2GV#MVk!%$&rLFuK!La zDMsWHbeyDHaaH5R{7+?2{69&}|8vgrvN!oP+OGNj=W_mUQeb(aOmWA2<^7@@5vK8) zzxptR7AEp(cZ$R7UmfaW_wAb=! z$&WE29p3-Vp@u|`a!^g$RcOd4F_6RZHN9JeVmd5GJZot&y{1KJevyLmmCuW%l+U5{ zP8&-qRivVk!?I~qwH(4nEyg-U2&Vpbr^VvzQoY)Y(X*(PO2j9TOWd`5m`1dY@)6Xa zpCCu2!QfvZOgvNGzo+?YS^wWY|D94${Tj_8pP)_ng!GB-By}QXqIjZyf(8o8 zMR!46QFA97iU<+(R!~}TCweQWtdLqsZY3H_Rt|9$)L%T~y?mJ93F1y%MOa(V)*@CF zgr7q2DmauT4zwpsB%D=)1Kgq)=NuVr&PbhVuBRK=FBxh*Sv*x4n=^15fl-4ol-HuA5 zE0s!VFg@j>t9T}V7Tgs zDnH-;*D!Ilk}Skz z-$gwa^NPX8Vh$LB&)P=TQvM18G zU>v4InufE4E19%fOLwhSToDpw;JlSD1)p(bBXLQUY_Ld$$^aq=CIrQyP`nach_y0Y zUn6N1S4FV|p}XTgAC!JE7FU%qFNT!D9oL>wt3|!G7@m-hm8Vp=o{yGc(q_@7Ou8)U zkKxK|3tr~t52s|$C1VSdumNQ1u&Wnl|(Wu534>1o&#vNc?TaH1@z6JigLD&ZO^ z?H((DI&mB@H&TOKNQ1g1{xR$pltkJdQcHZoaA9!_V~#7(a->J7*J58V52nF5OnCwB=rnzm#tv;1r1hVUmyUTT?ZrRyp=|+2 zhT4WL!FH2=i(zEvz#g0hO`fb5WIe!LgV;LMl+S~oY#XTYABCN9e}Fp->8W1q2ktpU z8v$8M(8_=*(WY<~dP6!hK^8(8>eSbuY^)cp2G|1Z9o9xYrJj(UPCF09Xo)m9Zsfll z_hCLROB7R2EAq9bTQiw}+%)s1D~Y@Vfc)-B9`F35v)zfJxEV57UKzD z$wG(piD(pIJ4t9l4#PYcj}jR2ZlrgZ8tWsTE^HMfBjm@^i5(b4kVDW&+*gP+x#-Ul zH9AVNouHyr8&W;o=|OGAUQm75X0&NgEZG;aB#Or?%5T&r(N}y%ijCA0<(NSHiDXTr z>bTnl=~fu1Anv|FsxSBj**-|_4MR#C1L6nRYFZ@}G7W~K*+Fm*;6=`Nvnahs!w}Iutyjwp0IVa(n;%ww0DI1PFET~TJfi{sf|=0l`U3ID3!L7 zB3dC*QERpQ_>8?1`NjSf8fO}RTC2fUi&3HUVkT%VG`SGxndT73n$~u(U9{FCO2%Bc zQ$T3i2uI>aE7~Y)5(H5@5E5v88s}Q<6cu^2J4&&%S5U0^(CQJb*I?^tPZY_R8Ww0J zAVkydDS{$`E!yi(sYG6sW(0PSrd(deEMHQSJG(k8B<`{h{<%<+9y`tsqTNeme&fX94tvoSw5aZ{~jVzliZFoNk7zNB$zeY zA%biCxL!uu29_f92i&`b^MiZl3xTHM8qy7rD}I4DN0!4IAH(@WycVwp?}@w)VTa(2 zf{E}ZMNs`n9jU&rUQ|2qZP4P{@Se^a>|HjGO@?<}+QQ!Kx7Zi3BfA6C^bU`x!_?ZU zRW+-1z}-|HP-ew8MwdssDIfAjq^IOfvPqY!`(3UpZ;|#%OQlBA+c4rEK?^#v+srC$ zhn?PxZRD@^F9b?PU{T#UJ0u(7|p6#ty^V9qqZE=c+}jk*D&y zyaRufKgC~$H*|gmdFU3mz<#TTVXyc+cmro0Tg*O&Ha`jbzw5$^wHNRPcl$bER1hC{ zoR{EkdfL^Ekia>PAI=ln!bppQfV*Z6pa1{;6Oj1VyRZV1l@PI-bXBqAgs2x%VdPmv z#V8Fyur_L{X=ikxogWLW4w&2Dv_2709wcxkxLdcu@+b zBS#z>`8d)E{A>EG;Of+JvNM#|_ywI2RymX{(2=}C8ZOmDx^sC7fMsHSqI-8+LP$=a z7GXLZ9fU|6Z;i@hI|Y@ZR9f4RYSAeDl?qa=*i+K6F(JUXq=ciY$>KJ zUmxb9P^3-Br|2D>7?gl=B1(Yh&|d~M5MH58gyxyrNV7<3QF23lU5qD=14?QVz?2gt z2;5uY1x{%EvxF$rggc~B^2C*E(vZsq1A~j7PKFa-nPJ= zV%gYV8dEHjd|09eIS314o@pG(ZjUx2fj?9mUH>VpeEfg+lNF0rJ8+ho! z^6rM2^6`ZAVtqltIjw)tI*3?#K^jwj{RP9tN(tsi+#pAIBCLQSKjy_8bVsR5>`D=~ zH=4Pm*5C%dnaxTfTIXmqi_-BrP|UhgXuRMG9;u?b{<+pROb$ z3z--tVv?3g))rDW=>wz_i2Z_eM=b$&1=3DLeA7eh9i-ib;!1n0#C|T?V@Uf9%kMWV zzjylX9JtF5UHKBU{f)FsTBM*IkhBL<+kJ@pv}j+LwgVY=5NbOUY4;cI>cT%dZEqL( zC>-u1D_}b@n7VHXa_<2iSUtaoI=aTV2Zz|BFhe0 zZ)j~!yQ0OXe2lR1PzqXQLc1^7v(WBCJ`B_LD|d`A?4OLR%tP5%IaajZr+|$``c^t&im$ra(vQgJd;Cdm;M7S{d2D z%Ui+8qDU)?BCjZip2@n2rBZvun9yB}QTbMvPfPvK+DUB}Z51_Aj`B|!Laj%ih}X&y zV%w$LY@1q>pzqF=x( zK@2^Ma1G|shj322zexHNR|-S?BC9OGu$lbyOfiJXETc433vO-OMd@b|368wNRfp! zjMSQTvLN*q6r4it4i{1*rXfGcjVR}pmk{Y$$crR@lB_6XOHCI1C$6GNfr3j3ens4h zt`vusJdy;(l|sZ7c_GD=m)!)1MD8j4|9=1XG*tK9@j?O=QlF?pgx}4(@k!&|nomfG zTF5{9NJXed?J^2|9kk~Q<1D9q)*H%{NgPY?HS)?L8(*=`8OZEQ}g#L zN=|n>AxnwS@+ri-IU??Ve;1|wPbHyrO)@stQQl9_T8NOtsbtFc*LI28XmrG={ojlm z<s8PU(jYZTqG^A3uR|~7EdDIU!O(zU+-c) ziSA?-ygQ7Z1l82&DCyaxYm-$`=>7CW)R?Y9mlt8eB0zQl%@!c2Jn;l^C7S_V(W*fX zW3?v{ig)5P_xtndE zky08V3y@_?JfU4obHWBmIuXhmByXU#i=I#xA$ui-mA|6gBCNHfCy6UcM|Vp>nyr^& zM7$xqZNFyn?RF5#eM-HwPK39ou*q+8jK}LR$Mjx2t!CqDt{F^n@C3`iYHA%#t*^B*!C#C0Z=(x=7`PoKAN^|A{kb zJcMjL$XhT>*l5X0OST@ti-^Z*T&+CEB)*Fw8b?Mxtv!|BX@If=$rPIWfzK$Dh^vUl zXDt;;u_V!Geoe0Vt28R4DU^zY|L@Xhd6`MXlC&mdG<*^zP&pJ&@*Txd8cOxgsVOJc zaJP@j(!$F3Le%_Mxl?-+@g)r&A zW22A^?v@KQjh({Ls!4ysaI$R@RS;A|*bI=H3s;_p3%*Tp;z`&#HL8UiTs#RMadpA9 z1zps*uke-Uz`~EzR`~I*@n6l3N%S81?O&-lac!daf(K}PLgPfl&jcqTjzw2tdm@Vz z@;u~sg6E-)s(cExeWBeA?RdgIMiw@*5Yo5JSNRoic*Q-fB3#sl_wu`4%ZF3{v^-Rr zC_%f6vZ)>_joO4et+k#~JiTp;J95cK@841@ao;SaqCL8z1{!%$BDDfj2`Ap)r8lJU ziTX;rm~pqRutxtCE-?mS1pibUy~|5E2#yIh(boG{D>s&gmU6@bVYmLPEn3Tk`)g@` zGlr3+n{3pWhwun75b=|)gx5mSC458-BRnOmE$vuESq`xuB|hA7i#ZAFiGFBTq94L~ zD`a@eiFt@hU>nd+G9*zJEKg7)A;S@+BN+`TD4vOjw2^ihAgvU8Q&4vynU2oV6K_qR zeu8f~kaUL<8}3Iy3XMA|XwQJg14zQcXOyn~{r686RxP#QG9;O4@)@qxljW6G?P-Sq zawDuy`=MWs^Et62RgwQZ{lT4>ByV9kBp;DPBdlCPzQH<45+V6Y)J(Z(J(*TTv27^5 z&>vHyOe5BnY26f8UTJNWBqEe>C=JEaX?1i439d2Y3bI(c)z))qWtdiy%U>xRuNaD_ zoY09SRpMv2;HfE9|Kl(QpXj77JRwG$v4ZEW;At;(-WlHUlodL21>lQIAN?o{FE^~ zOAYhjX}xsEv&YC`*%%`nro|J==ma(_^&aqJ*%;agb_?POqIiBR-Z2Ev^29US8pp46 z8Zfp8Q(!q*E0&HYkcx9iDKExiNmvG^#`Kh*PN&5Zo51;SO(7I(X%>IN)8a%tm4kWE zhhCxZ)YGc@b`9nX_Go)QMxYK@pq-E$M9hK-NmWDKzPMAeMO8FQ^Kcu*%DPxF; z#r@YL`Qy30_!Il_a0e@;!gBuYM|4`m;_fuePjWwn5>LUsY53-y;6wP11@a%-nThAM z;vYE?=8pg$LT*Ny1o9@_Cr7)eu|_?N8q#z;-P*_mEG_z)kSy%>n0z__OPE=fK8P)N$aG&(q(C( z)LrT&>7@H%m+^8qHUGMrtDaYns+ZI%yg!^X|318nbsA&@#tPv4|Fv)m`$#xU7vCJy+cg`;p!JO-MDC9b!*OKS&vJQ(b4hUf*B;j{aUlf?>CQpnjn)DnBWI zDZR>8@UPXNlB#?W>kvB?y%fD3O^D5l<;3Od&mCuB|&kwT+>ijM)w^F^4^EqoB{Y)@ckcyGY!MKIfp z{ls5__FRYW1E7`WN%j<+lKwWFINmq@1qU~@2j5mZ0_XHR59K_;dvL$1nlstD|{ilEgh39>OA_PdXxSq-8tP@-OI8= z=28@TuW}!Io!0~R7VO?10^f@G0scS2yMJ4tM;-Wd2(7~#!j}OWK%eWup86p`(IT+_ zza@W0tqiTsS5_)BmHA3rb)K5Wzu+|ihFVEFxd%YrKzXA4mfTO?DlL%4Nk`&z?hSyz z_39Y)A@!P4puC_eidWsB{s7<9=mzy31SsjuzK59}$f9f!yg8669c7=fF|eb53-FN2 z00E1jonHYQwc=rQsd^7TqfX)#;F}I_K)4lP{2N}2-GTQVAAsH+g;{wKzN1kQINA#6 zuM_5M2=v$wurmW@^d%bz`%Qe|A*mQ7Gt3Izr&jauW%iI7@%Sr z;BN~^vmD+d_yR`fG5CIh5qQTHn9&JwDjfxA`yAd+I1OLgc#GEuXt@ld`5k;eppZ9X zPXIOzW3RIJfm5yFcJ={aQziZgVAEK@!%6UUky~mD&_qJ;KEnZi7+|Ia+Xj%zAoX-; z-!S;H$fNMKg@M%rc>Wk#e}p#$SUU+VI|J?62vn*sxUb>cBg0{Q1^~QwOl2bb*Q>neH!{a7QPN~lg|M7 zO=qj%#P$yCSvW)A%H{!<{K)U9)p=$92E4)1LTwB0aJT`AUFu8fRkaa744#HQ3f`n> zEH#zBWp$+8KwpNjxj;!G>hCc7FR3r9hm<+WM6B1%=UJe0sN}U zMVEp2(wd-C-Qx2 z0$;3VDbE65Sf_4M7sAyCWq%DLlh5CU@89fTZ%Y%TYEoP2H)*Y8kj6lp2Cz*)H;<@O z)fDxxQU$2{Nu^ks5A%sw9pQBWdve%ORza!@-0Ej|`(`4155WrZ3BEsEpZfr+n)6HQ zN|^PUs!koF+*Fn;T>&qz$BLDw)Dra_`0~q3AnnwV9)LPa*o#s{xtWwG>8081EO5qg zY$#u=7Q?tb4A>Hdw|{H^lU}xqE9yb@C7>xU@^ipx+HeoI!S_avz&A)P^Hezdp&7^* zyFn(}3~vw};)B@*7~4ZIhU0*4&IgEjh7Do{c+aOd@c5OyDM()V@C^k#)9iO%1NiP{ zZs(t<)TrLCP6R&EiNC}8NDoQ(NvnYd^^tSr{Xmrhl3h-f-O?#| zOXwqj=p6nIU}28>jhe)NQmd)Qlo9F#H3+ycL*1`-hWCp@z*%OpS*(k+TG}CfF7=Zt z$WP1n%VR<03bPAVI-dg%v}aN@Lp-4td|pHtL~yaT&@o= z__oxAP3E=PIR2gDQTHl+pw=GBT)?5j>cbo*zMp`naMo2CByC_-q-5zDbHT{p0UUS} zu%M0fEYQU+@P(lJ;JXR^VPt*-8Z#XzvZ8JQDELObrhdjt)Hl>0_$0O;DBV}=G{DIY zfP!^Eg}Q=N90qFOVryZfLu@sCi^nDnkt#^PODm*F(s?L#Iecg75`5bzpuP?G{1Go! z8v;B(3||6T$`1e?O#!;`5y)ac^Cm!5&VxiZ8l;yCP(um)2T5;Ao8kLKUxIrMXlXX^ zmvQPS^|<=3T2(y@^nZ_fQf&=Xmq8nD@L$*o;FkT_E$E*FbKin>;H7Fy;J$rfBxkCd z)fJF;Do`^wta=?{he1{<1ul^X?sMrmX(7N+U#W?-mA3^NlLHdQHgysI5~PcZ0M!dY z;+n*}0?qEma)DyM%G}ao&;jNHJxKy8I2ZDC<}Yv?@QWvaJFSJ0ysTD)dG7(z+E|bn zo@N_(B8=N$wjU&&$JsA{H;dr@BaF$%Ko2SbO<`;TK;tUF#yadK(8u#&S+hdQCx9PZ z0Gd=2X0-*3#|n^*6d3p8AmzKEJ^3&OKSSwp`BX3*#{#-bnkH z&j#u`A86Jy>SkrEvR-MRey6Sk8Ra$LawDZ{(ne{H)IvTb-77yXmq=yoJJu2)d;-*@ z0553>9J>PWO_Zz-a|e8FBBp)~yzUNs_vsjkRdd+q(Bn<;PTgUUIX%F`sscA22V8SE^rr#y16*BT)qze` zk{$*)UJugT!Z;7P0C@W&dySa@MslQ&rCrjma&>v4)KmISS^~0WGmz8HsjsRR)M)_8 zW7Ib4qaYpjRKHh$QZu*=9M}w0couU?U8FtIN$G7lL$^Ses5>wJC*p!VigECIBgOpONy7(bAo6llRq#l4>eWXet54|Gm{pPdGte4S4MYLf_jzli)1^{?h(hj=zJj)`X3s+(o&`$dlJ)~$Y-A5f zOIb1CmJ9gSM7~*F2oQZrZOS%Dr(wo^VY2*;{IGmX9w4`rVk{d%K4#7N7~uI1wNRO> z3;^o6USRw=oNB)sL%U@Avt8alE z`Lyz*GEFh74&XGapx#n`i(Q3!r%R7Y7Xe280Lbnyza!mZOQbtM(c4HW%LBRUF&K%L zfp^Z}jd>>I?9AQ*ZEX-}AIn(;-rxKY;II(n(IDX4S0D#^rT3);AYtr;xmCcr8U;J469 z>dG#vMQShpI%@>5*q85BlUZ}nHd3V3+z3?GB`=aQr98;zXPqRg+)Ww>n#$Yot+QO< zkvoO|0UP0(JIKPj0(+TRU)@uECc9xazi8vqKM0rz{4CGnF=rm{jkqYh9jsPCwq z)b8qQdIC4!)uWw7E6Em%S$a%G$$M z`L=*8em`i&i(s6F0bOqk5OfdQ4jkqK)d(`Rk^4Y$ejV`V2*^M)_=l>K-v+658jM4x zoF!cWiTiQs277_e0bW#(yHp!UC=QT+oNSboB!4D_rCaiKd8X7Fc=KTXl)7B$0XqJI z*gLV2N_VwAoZ9jVyCbE`&&#y{vQEiUfKLyV>aZ%HpPW}`Djk%3<(TqT?0hT}TJgQI zSA8AEJ*@O?Lgw5ADa-nu2crTlg;h{{=G-~MOVcz0H}vm_cidO@1%5gpV~p`99t8; z7_F(4#qLDEirrEUsR#HqkP;_C4U?p7d6&FhY7H`GeW2Hy0qU}$>}u+7U?Ul+HUM5d z1mLiNoGqv5TI)vXs^}`n3s?{|ug=QH(Z-SDupyEaehB3DwV*q!QYWy%(lKeQ++Lak zcpBiifYoY6Y@PD7@{YQb=dk|r`?~YGrNBAQNhR_?Ml*#IL$c!58BrWz};OS$3M=p00TTA8|Q$YGEKc#DU7WLt?R66;^}-m zKDWtyIe`v1|aoOxeXXlp974nqmES^u?In>*seUR4ws(M9h9fZPw0aNuc1u$ zhHeO?v#Y-V6h|YUhkp)_j|_^Kqhn$^H5DvWeRx%%w(m-vq~|3aJEVM}+y^VCManv$ zT%lM;bv7F;BgMSK8tE468iJihFD>CyK&n^|(DM_Iu}boMoua>L2pVo1dK;6CCHewg z8##^TD3bC~tZCF5IUoKh+%i%<+FOaiIP?aa#V=sVTCds^e`IT@Y1!1WZlPwO>Sdpl zg~Kgl2b2b&3A6xRVxcroeouZqu9HraTFZUqeR3mR4c&Cz`}&230S1R*tKnzk?1WaP zQ|1+k6B2t`T3O$)-mpAk>6?%Q}Vtjc&6~1f>tHw; ze#IBLUiMx|?V{fcIuwiuRtT;Q8Vma7&+tE)Yxeidy_)^Xom02Q+&p{xCI7m-x%p{@ z?}U#st8tyBsk4S_i~F>9c~S$#1*JfFNmG4#@(J7@(3J>RhnfG4c&A|A)N`XGv`rBP@ z7vA1>@%A5|tO+^jE27MLV*RJ!P%E`woj7S-r^r7cIM^WMr#v)xK zS;zOssw+qMK`BQz7#f;KS?Ai@xb&WgXN|8Yxn9Ng6=o+Jl3($ibpK{wkT}!OkPnE| zFEtms^0w#xk~=Q<+nmWciMh?Q7TxsR=z8P3tAj2sJ=gg{_)@*=Sy@j7hlMJzXUuCn zT`QkWJ6*MH)#+*aily#SOGo`fv4bVQ6(r`b$nzF$3k_7>k+Tx6+Mo1Rs(3!NbCsH@ z7b{Omy(q9=&s>t&_!I{y{fUeJnDvbavrqc}x8zxo_v(&dJMZl>Pcm<2BFq zX4eK>`uNPgQ%|4Gx%l19SMpq?H)3JKlb-vk1k!C8nbj9nomp{}`*F*7-NTUw3tQ#Q z^mp(-mbbRZ6v^PLb#)R8U0Z-0{AA$M;6w$K!5PQngHX2pVP3o^FX z%&9%O&YQKCR_{}_u%gG4Ww~gy$?IZYgwB?pD1M-J305BqG@U?^S91>l6R+0 ztnRPXwQgD6WwpoExK_Gptd-gZvf zB~^;PQd+b4rIMkc52Dx97IJ&zc=J5V<;3TV8`STMM`c|&XWP#=A6b|FL*ll6yIn^{ zUSAMSbrsfpq z-kp^qRa<8?&%9W7N1fklEz9_%>VOK>+$P&238Psk(y{FMl5b1o@H5I;R-mh9s$osF z@37@2t}(cjYDJ&lo_6-PJsUPWvugRq_qXrZxBOJkoUZJ}r0w+@wyxT)L95eEH`VKt z*2MmW+9){tMz3=VPS-xW_rlFw}~FrJz;+%`IFRxRrAt4HI~%uk?E;bB}1yR zF3IYwm6)Z!hp!1|l)hA)QEG|w=Ti*V5`B&$=R>YZu2&sjCf1Y^OBUUF^yEjoK3ace zwQp1N?OlKEb@KJ>Ql6dMv_XwF+uAx?e%j=hI<+fbHE#@e%)N2hcjlv0Pn_L)Y4okV zdFf?}@}%Jj`|C+c#WR%`Rk^R)`s(f)XEJK0Kb-nYQdd`h>kZ?1b|N|}^my5ap|!CC z@EPAn6ZhKgb6#C|fgV%e-Bq|Co8{p~6K89aE>> zGqP=2n@KHRXz*NmlKUI>Rl)1GnqP>XTye7Ph0yg?{uw3PV^idvCZBUU(72x}Ose!_ zm0!{qW{l1lQ>|y}sie;w8_mz_K33X?o0eslIU^79xrRN7bsR(7x4l7MJ@4y|BMAr8 zWyQ<0E?tlgdAE;W)pNzJ&DZyhIsM|DO|h1)Y8m^RpXuOjXK1{v`tIZ`)7i2i*(0u` zoQ)hWJN5LHNLJh6+_HXL)qh}a<(!=~q~g&^CsMzvb|k}Avt`EpRclq+>cc&;8#1nU(Gxf8Wg(4eLIe7V@kz%q_{gQ*f#Mncq%zyWqU}qJL!Jw9p0R54n~3 z6K6`&zLYAJP#YRvwBB-k@8ij) z3VoALxO-Tu=|7BopMTHI%4hZ-2yR}#V$8~l+YbJ*`Qp&LA7sVXv{tX?Z?*lY#Rs(y zR|?xNvb=(Gw?4h(Ia_wxda?ekXYwwURE>fDtY2wf=&YRlPQ`hZ&1qkzzh2|L8lBQd zr9PN^&2i1tTNhT-qaDK6!UpAa=~LrvOS)^2@BQRR(lyU!yV=}T?i_U%4b2LjpZ{Cx z*6yo2t*gF!!I4kSFVA{U`OMR@#-he8TiEXDUSmc@lkrLi8m zw8W#%grpNG4^+67yxwbc+)mibJB7LjFW#PXapjTAJ45SUT(^6B?(gn%p{zy9HT&mP zd852mFSb}z=Y`Y+S4-XTl9@T-Yb(#+f2R2S*VohhYl@mhTJR~leA5?>2EMN=45_pw zwPDqQ^syPi^n26H6>7O2Gq03qt97Dzp*dlHbQ@b`e8cvRr+RYj3Y$}A`5tt(HRs7^ zqf?7xIS*b{jvIbivcbMSeS5#(%_pziC@Hy^cr0~6gU$Co&}>_s>1n6DmlD1W)$;#( zBYN?pb1Tk2b8S<0S;5(GH(pKmaYAF;cOFM_H09xnyDPt6ZDn<5_0+T#6&`eVPi(0l z!!Jbdi42I8#x6)NnNB;_`o^WyuP{6%HEDozx_Pi}pfa%Jo7~G+pFXv0&m)^|t-EKt z>9@=ib+3&rx@y{3sbal%n%~=WN9{vZl6^0jyGBk2M%;SfN{tKsFYdm6Cuc%|BeXlV zh>g{MotWjCmOQ7zph}-rxi`a9^SkP^s@PJJoaO|Z^t$?aY(eyc*dBJ!xXUuw<@Mc{ z+$^b)cbRjXwNt_wxt}t%?DKrf9n(e6A7i%dTtEKD&U*`vDwn$kf6?toYMNQ8S!(mF z`ZcPVeLc;~q7Cu~-`;ukrAxyu-njN$_U3|`q1CY}QdH+QEwSzJY)sylGPlyPs>iF( zP5-va6BS!|-PVf6R`R1B#v$C%^>5-(TJlXd1=3n$ZnG_jcaOcjU zi&=-;?wG!D^tRgj(~f_1p{u`C-Qk#)eov$K8+WX2s8Z&eZ`r60DLkLO_~ztm(v87) zM)-dyFqNJU&5hiQWy&`a8rYAzdnLIm{ZMUDtvQ*Ij91cnrOb0SOl)OHmcEbKqaP`I zr8S13=ArhMAisv(>8{W1Us~oS)RB!!ztXh4IyXKzv14b&ALjk|=C8F6Pd~pP`}4>} zOYbVL*E2OJsWGtfH}1>k#w@oaJ#S#v@3-7HKfd#E;9B9srN={0MjnoR%6-O**4Nz| zeA`maSJ|KOR?QLB=T@1Xyum)f%}qU(@jm^IJ*lzEwP znf#3MeW-fDuAAw{>+fl@^Oav}{5t*6L+6)eHwhJ3^l6@2>uVHNeX+9DyUx^DeW)y> z;HTWJcW&I#=PdHK3cgXawj>o;{LI(^Inn&PP3Jz9+$gnL`iP998Oy3ZTVauBnWMcm z-4r%-Hx%k0(swXUFwe4%wgs$%EUV3PO*2h<63*yDl2Pei((Pv76N3*}_jTIW=)nA= zhc7P3N)J^sFHLD)`AkYuQXB7O=VH?%Qf9y_D@Q>i-g5klmg3@5?f`bJ+iqD0o zs5j(yK^}c1=}zU}(%z_cE$!z@qmz$$=ejG}_auI2e#0Cz7n;qMI+j|NY8IWP)NC~0 zf`fJTnmQ)*HDs}SLf>RL6 z>Wpeq=tj}Z!d*q#{ zq%VAZJg+*o*i!5pY;&xmtk2m}?elHZJJc$Ld+-%yyi2GD8v`hYd7a^&++G~6gQKQyQ; zTs9?qB2--3B~%#d8qSEeRJlCZkZgX|deTwFHOaZi+0^y6yNf&5ZT4((_i|^u6FuWx zDUJ>H0rqU$2FnYHRn4k#y?&(hf;uB&2Zgz&a*qLE6gp7svKZD`SMswcvZ<4 zMSTjR!T$NJ1IhjixrLxNy_+*2cT3*Ef_sWP7JpQ7qpW>oc(jRPh4sN(>R_q6KHcCn z95k#kHZX40#bCAKVfHEPGw1{>yGgL#K18=!zre7{Xf_=+y=ZQiIN5TaRkeI;Ew)Ci zA6aW#dYMle=Yj=or_Q8z>n=*;rFU5}zY`l9O$!ezompaOuRGQ_syRm4xh2Q+zVQ+L zVCh#_?HLfO9=#pz5iSY69GX#fuJrZN&ZP%Rl#;WhE6Wy^9WCn;`YJRp^jhfE(Ed=p zus?h);)rzy%gaabltc5y@u1q-lmXwjwNUvVPEG^om1UD zZx>&w@8P5xNgkicGt9ZoR+gA)x&!pB7xyUbqPN1|g?f}tE!kgmU*Y-SqWlSY-vpis zj0`LfB<3aOS@Mnr-U?$)v>cr}+4>6-$Uw6O$9jLX6X|?%5 z%PH$nd!eI-i@Sby-|zXrbJluk5#i`!d&*dncz>Zj0PDxf^mf`n`F7DBB<9*26#k<7Q2dK>$$9mhRmVM@E!V|{v z`iMMKD&alUW3jiQFGs!%j}EmgD=txsFBNSm{IsA`@Q=K=1Bd-?f3w_zoPN2D{Ac{H z28?+*d6wYNf+>aLi#{m6x3pd8(}+!Zg}*IL)p5i9CUc_0GReBnmg%VNOm-b}t#vQ+ zboQR|cJ#gL8{+f%9`GJ_TU`SjyKGl1{SsT4U8YvXy87O74qMJ!so%yxUJP#zjVh~B z`fG9TqRxf=3aSNn0z?c7U__UXM4-~ zmgPX=V)Itu0M+zc~?r_w3#wbg}ujeAN@q*Xj9|Fh~=bhwqvVv zjcdHS&^^wR?A`3$>3z@J!n?cE9U+#LK_g)3VHx%`Uh6} zb^czt3Aw-KWaQ@MZuQp=Obpb>y9^`pUGSHJq@uFoI%N&Rm7|X;oX?Q+^yY+PrY90l zTb{MOZ|~=*>h!oexL@>)^4fh5`1<;6zOTGjJSW|=T@9U&ImX$m+qzh0np>Jq7<(BO z>aN2Y%OrJK?AOQzpn;W3N{c2HUJ4G#e=%=SV2Qt`|J&S_xkq3;s^&hHyCT=-zv;gj zFz5FTN`;xlZGa=Tjnrx39LE8FPq;65KJ?b|we>ai zUG{eO{^YTHI=eGnk2;@l?6>W+l$aNr`XuZ&{Hog~DZH)vbZkRJ3b!unQu19<&BC{X z59asIn;z&6qp>UJxtx?716;S{B%ObrU;VYukTxaA&gH>B;si@Vb1heQkU$-|v9C-+K1Bx4TX_Yd9M@KC~^g>@in2 z%`pC;-y&aPz4)ujg6Q>d#ZbM{e#I4vW))n@pPDy0Fw;LWcYTf}XH)jJ?8Y!6Q*+z+ zn+M*?JCbiGc)Czmyrra9StPVCvNv{HZ7zMN+iN(Uu+6;0GTs)jXE}B|b6j@M4bLQR zmN()(=KT?9*$q#o=S#Q6UC(vSQN!NX`g3A;^ZJCfh97iSC5a`gDX}4uH$vA-hnM6R zJy!Tba9qAC@1p-~ZnfMQIi8%PoE|V16?4zzF7ZzYi~w5pc)`uWrN!@;P6>^G(b%un zkOt{qHZ)1FnU5z)Q-3b9C~2>^|c9##v_f z+9p`^iNj1U8oTSK$~)N(b!#jTX&&xUw!EZw@v*}D3rg}Y=6x0z;2)p6Kc`<#o1F1E zU*&AisRJ(vM*LDu8`i3OHNZL{n_$Lp?L z?iHR_y!ZOf`BIY7laBf_d;`2wJb$OYmwF*9$VjE$}h z=ar2qy$EwMvcMf&oA*$lsecU6^JY16PC<6_oCP_3b06^64RpyHoPRXfyHF~=RI;PY zA5M!suD-^m%J1mA8^Z}}%!4eY)`#s|92H%?08d`_cJ{6GW%Udc0jd_qyA= z>N$V3N3BCG+&seciE*j^plpj5(Ec&~UDdu`rUAWs*#dbkES(;c7LN-Pg1zGND2d`>@4&SO(~n)*d7 z5_vsbE3~TgO0m7@wSu$xPv$iVyyCx-+atGrZqMA$a?j|XMyLCXNTt-&oGb9^SQgb z`?4$DmFbMw-v(^;BsMj5Ha@A}CfAcj^MJBAHY!>%vMyAwY@R{O#`zn{50#B-L0 zwh{I>9K)QITnAj;+`qW(o_jr=JgJ_IZrR<>^_6qE;|cpN>tmJ+=AovIMvI}lZVT)u z_*s1bAmc=MT4-chyVA1a%|*isGYc-~f0K75aNEDczu8|uuogJKKX5XyX7Dkf7tM?9 zB`ZpQ4t0rq9X%WSQk~2e$)D=G8RsVKHeawE!~510{cKc8I_{7!c(C3+r?j&%qlJ{yi{-jBZ{R6tZ zDS zmpD4RvRps8{LYz<*X(s|%dKW>Kg;Yyzv=Y^$*9whlB=+g@>=wKC{lX1SShMktS??v zgobk2ljH@f_<*d zWVdd5gg6X|CBWzoUcQVB2EtVtdN=h%LeT zn0dZ|OAo>tdmrTvaIh<(V#X3a=vwLQ;yi4xU~6od zny5GZs#m31u)}f=9~T=M-cfq6=&j)1Kt|rcywvZYNQrz9$-F8`gad&rL+`YKFEN;c!S)@e@EiKgBxI9h%!~gYzWg#+e z=FXja@0@e4AznY!P{&wcOfiL9Hd|^~LzY}ihJ~_JG*>c)^i6biIfo{T-A4Z;hN^l6 zFUZS;dH#G)oO?22t9$l&jt+&Xxy^Ft=Y z=3>{ZQYE?R$1zsykE*xmTSc*>Mv`DFbB@9@CV z%ks&*(?lC~>2`8&xMXcBb`e!x-7mx`C2?P&_D%LgyS;XyFtcz_;qm-gxo`8Y7Y=vC zJBPcLxt6=K+}nN61N8&N`PxDiQ6>E$N%AB`13pWCVC-+J9ugcW6Z5DRY&M(AzG7c% zR&ic^H&d=@n`w)QvK+Q}EZr^PmM}}9xvZs?d7rV5elK@l)0tUCZ6`aEr&Z$=KVREF z+gr*V>G0)y3P0HE*~=8H!Cl|XyjlfX*C@{rcZB<{cej7E|E+&K#!+7wE;7ozU>T*m z+#~oFY>4XWXGC#|A&-z0Jx-Gh%Q&So7+M;vhU3O2mWH;9)-IN5@Sd^OftGXTkETfD zbNv}zFWo_{i7}94)f3fILS5x)fo|T-?#a#$_Kf^YSYH;y}`A8PDw z$+Nw+zBCC2%Dl&xjPrxF6`EyZhJLF4AALPt8%;Jno7}G68)~n#mhyc4Jef|yQO3SH zZ zqf^LUWIN&}z4=gk3SOG&VD>HtCI%FdI)9 zmh=ICb6IVY`|(vhZQX;NihZ_ynSGeUR2ax(a+w0Tprd1oK)oiXtIw04>1)h%M#Bv<)YezhmN9&^?6+wx)2y{^ zEi4h{?N(#N^03C13#R6#^9G|H_cq)rrX^8Ioezvhp45&X=Y8l%wl8qBafBC2g)IwP z6(r`Ua+ekEEG&&$L<9E)&qvoIFXdPHeg1JgAwQF{L^^0tEe*X=ZUo-}C((x}&dy`U zAy&Cd7ihw`8+yT*WU6MqV>)H-Z%wk!wf40zwx>4McHEq3N--uF8td2S%4na_7u9+o zfsLv;vW7qJ8RW_+TvsrsAk)6d6>iVYE0^6q_YlCk&E0QZ8=SXXZtpJC7Owf~`=17u zNFU_>z~jDA7Aby2oN9uhx>9e*HyFblb{?#Bnf3_x)v&>wXic*mwdi1>UW?Q6-c})e zlkKs2zNwmNo}rvBo*StNqss#?_Cob{P%EtPiLNycUt!0>OLm{*FS{zgdv-zgwfu(m za}JHOxx1V@(>=n|&)>$+`vSf+p^uWHxRo?;&@L;H(*Dppsw7*7i6D>D7a5Kzsu`@S zVY+L0t@~&?Z24h*ZnRj`^N3WQ?;e3m+1Z9(L0jVRjm0 zO!4MnCbe-jyhl6cw7L@zvBg6nab{q?SLIq@f0KU$x#@#~i}^Kj7i7K5u@qiGO@(rF z^qlex^px_(3orPMfro+V%G}UM+gSr^w z8FNKzeaj_NJ?mB5tg!aB%eJZ3CZ@rt-nKEHH!je5HJ|A5>ej(F!4)Av%JW;jA!mwx zdEThs`ElX!e0OfoykPFEf_{a+?5CZqtBp6yd&RdP;P+qRAMiV+%@Q3<3|$6p(+192 z0x^a%XreUNn43%tMsifQUEkPnN?*ZP&eYP>$a2iO!+ORNvX%HU|26%G$FE9v7}Ih_oyD&GQm+w&rXqs8HAhwF8@Du{*)L z!teD?_ZIPg6x`xeAzx~wN+KSsKZ9jejaW_01Z~vMG-1y(lIDT-lr~QLw{C>7tZBSy zy1BJ&x-G?GH&3;6uuZaUvX!+?GnX@d)6dtf(Eea6(3gnms*0fjN{Xls4Dwudgxil6 z=nIDyCKcW;Sep~fu9rs@n(dDKe;mC%J3NX<^3)Sr^Fm-Oua#ZOfKVPWk94bJLnqW( zR1NA0nN5XQr{)J+oBNmZYrC@xHH2}8`JMHQwJl=3L}PRFcgqJ`TU(4}5=0k$h6cLX z+B%vFXg+iXn8stFXYwP|E^9kq7GBIRU-+{Smv8n{c~5gD<-E;%SJ0#2gMEW*xTl#n z=vl+B<=sLd|4lF|-9tyghwDrBR+m+sC!Uk#=-u=oDwATE3tEppjeDlqt{KABGgwWt ztY>UV)(@65md-d^&f&k~%;Su!^cQrObwjjkm`dajRZeiYGFE9TZ3?tO+)>LhuaGP_ zU9h>ZR$kwn!t5mlW9_R8EvOunbH8*Kc-93TikHL-QY&e<(lvNI)PP(F1p8T)mAt|< zq-GPN)q0xJTx1t(S8M;&cF@e!^7`YZ2vih$T8CPnnPbiCAPwL)w={k-^f5ft9oP2L z>e+SFGxcwF;Y?+Q94D^x6}o4^qpr5Q3b#6z=GV$K=e{g>?a({M6|#=W&X=yI-U0kE zpg3*?5`h^M!Q~nqa;Sf(U0{#C0R#0a?5!8^mI`NQYX)j3XliKmoIyXwkYPA%ENy12 z_pBvspRD_VJm>;Zgl`5#Ut3p+JFlt4_M)8XF5q$Wk?szWQ47qI{W_o&$-3^TQ}jJJNYY(p(U zZZ68dIHt*$oTrRaT3C`d4}Gy0^Qhy1qDdj-!Qj^5+zY_SVj4 zg&zu=IA*(VyNzB4UqWmx&fq@?gXC4R8hp-D;DB@veOF}?yH#EwnV+K`_=9Lh*J6gS zahf{X`nm+&GJ_cr*#%=w6K2HP-@4Y)-Mkm~Qk(Sm^`ALf`xo<>dP{av+e2}ohsqGq z7kKEK;;ZEz;&j``J5M-P6&@>e*pImSIJY~WJH|VoxJr3%`O5~j1g;2wOMa=n91~m# zA75FC2`&UXga@Wx1zwe&IE;$xlWHUw3A2D==g6gGfBF(#llqq# zrk%w-*H+NYH&!(-!l|>w>bE{H4>hJDj;Hm7+Gy^K_BfkM1*jF&HuXTDuNMXLrA7P; z{|4U&?EME_?03;uxcMmi>)!am-hTn@fe zl7clu3Ba@t2XelLy7TY#A#af3bddf-vy+pw2|7u?(6rI?7}b}h=K5xhDZ_Zkn5qBH zmE~$^ud~l+HJwV1LG8K@aGS5>Hqrp0JYUA|_lTZo&tmr}=Ue*&=VND6x5u6AQd~pb zQ+)FSgZ=OPRRT3dt9%Lg)HiZ@S?nx4E~a@0OSHCHQ{$>q5k=te7h9l4SXuayQrwjGN!= zaWxRk-POAZFVU7-!<5&Y(+HZGoLe_Ww@d$7U&pXpe^j4{k<8Wi(+|^k)0N=XYqK<7 zb|_PU-bF?c;oud{4fR!;qjFnPoWy_exAR}{z4X2GzVi(6j_?ijC3|0bU-%aJGJJde zVSzUOA^sBlYknkuhA$!(N+0Eyz;t_pnV}b|b?WQtA>iEnAj(q&-Gw$VRoHe~NjsGr zpc|oA^k?-J!v*~aeOFzWE`>X%{h_homiY~Hmaa-4q_&W6)%U=T`vJDv5jiN06Ke>| zc%1!wufPNUSbwr_xIe{z#n;N$!uQ2@&1dru4KxYF29EJV#WP}a@s>1KDWfb`BxOCg zue(Bzz}b5WmR1rulKMf7W8N~OHJdb5wbg-bn8+RAR&sgTQru#08uwB=Nh@o5Ba)cJ zZe~tV3&}GCO$49^PzM|bQ;-NQQzpqLr9Y*uVutXY|G-b=R|aPLPx!9|1iwD8IWUhe z!B^)6Ay(`oTo68pKBiBwy9DLsj)!LDX+ zu~v;oLu=P-I%%3|QrK1OUu+N7%`|8FF!6}NKT<6y4{0Met2crt*as|$Jh`E=QobjB zlq$+QrBu-<&5(@JEHPS46K)8@g&2Vre(@J@V;L{l#7MD%cucG(B}=??LawdMRT>5T zV6Th?(=1J$Lp&gJ$||2u z5S2`BBPp_}`Vu(qGjOwQ1S{LEOi-!=3;zyGk10w`xu0Z~Zi(N8cz$nSQy>`F%BS&v z34?^1;t;8=9FTv?kL6;DM_B^qS2x^HPsDxrf2vgV2%M2fV#(H24!M^c3jKk@P_!sY z_kX zz~TA`X1^vhCs?SIl|DUITxVRW$%Rdm&im{gAhj zKyNG$h6g#Nqby2ZsD#v#s!5w9N`4@>QNAm~f{{?WXbC-&f4~U-4$MFfbT$40-{df= zfKzdE-x=yA6N&SLK$IqnP!lODb%C5gz5t(Wj5-m#!>r)zV3Qyn91QJ-+u$~EU_rf8 zy-;^062Z^P29vk|iX9K2X;3G~1;;2iWM0mei-Xm~Vva6>YuyA4Wjh$w7oj&GD;!qT z9IOtOWjZ*30vP;-s>#qXVexrYiKfKA>MH6w;JxoxZ3LHU1oUr;fzzA=4#)^K1%Ad5 zVlHuxI7wUr|Ew7?7PC1?I2|lNe`3 zV2@S+`>_Yud`949WN=w}g*vIqfU~$89Ez%BQ(zpf6EhLLR#l&XqQIkI-{2XXhxc$I zE|7Q0)s>)98cdzVp@~o#FslCs!*92`A3i$?@m&V03Sr>B%$DcLzhu9hptQwn+kprF z9!fD&zyUj?{sj)z5OuEV3b?Ajm2tek`D+-%6;(Rsr-OPw)N1yt?O>P<#b;gx+iMtD z-AkeWvIkltsnAV$t&|0)wJkJ0;-R>(6@1BXa7nj;J*>hxyB_Syqu{0kF9Xe*r9mk; z4D7m=s(Y&9>Kf3$xvgG-nr$>V>c5%SC%_$C9oz@&Y!sY<9dRUB3ry%YuRnx`;&X;PqP78K`Vnv7_U_tt|_Qw72JYKuAf3(VWvV00~p>QW&-FBZJW)4=Jp3JwF4 zd_Uf`2uvUethM*xIak4++YEm44E1((3vk$eb7%*E7qk_h+$B^KiX7qKn5BRnS{b(7 z2i!gvGz-F^A+i|!^S4l_xq&!h3K-HH?CmI6sL^2Ie}eYH@9%mC>yCr=!LLw1c#yH! zQ$BSC*v}fG8xe^*Pk;3f=!vA1*5@As|MABsGv_N4(8!+{_09RRXOM;xUioqswb%j;<;)9(GmowZ6WyX z1+e7Kp~fLPfWHbg{L|RFS!D`3(c`UPOM%5cwBG6 zMYjLHFZ*@qFf0!J4Ibq0HK~D>Bf)6)VMpun=kl=s1n|s1gAXK2op#L%jiYRGN`xyvdy$L!Y8)3DB;s0pZ%sMdJo55y^hpK}!-W%#L zuc1lOS#=0&TpFHoEq3&B^%i*D3gDU@fV~OOdDszZ2ozIkyr&^BOjBS7AF@q zU{ku`Z3luup99R;TrlMNVFsFkqqPT2&5V!@Y`^AMhrv*HSPCzf1ciZp__>S`UsR<6 z-L(Kp4KY}YyI|qA#eR`+Z}K~yet|RL9sK4FD3DZ!w#Qwl<}8N~N(7I64t`p~XEz0J zaeb&7R9miKtV=NBEQn#X0i#?G2JUp#GiWI^QP&6Gx|O;)cD6?SQ8gJ#0R`9zlVSY< z*i1O)Wf*vUW-xp2g1y`Znbs8e0c z{?CrHW;)jE4n~lz3c$iH;PtUMYZf41$_VZPDsMe>U>0I-;$T^cp>7!Meq=wjVTqaG z(R*QM(=o@DpstgTJ#iUcYd*Ac_TVJFgPC0eC7=b!`NsjxRv*tk3H6lqu%0~JPYuP5 zj9zV0kHcPmhWhz!^;7u2>NxEV!22G-dW!IQLy$q%587Z6r=e=~A=n9;LJ8p0Gg!T7 zsJ%4(zaG(V9l26i(Z9gqUI|-SfO$9y3+@a%Xo74Y3yLyVLbKp=wqdvI1H$hycA)~+ za&gqD+hQ&|BCZ_^c6mp5^`X$uXa(+g51fp#`1ce%*$K@2aQM4PP#LO+{V)a|^Uu(3 z%;ag}v%S2o_;pf}svjzE}-qk9?fUCg}NC z5EUJUotB4k#Y60YR-r1;*JuN7c?|5i8I*adVb!L?`(6VZ-+_3r7rglhtnMOs%Y%4t zKSX8y@Z9NmqW91?8UrPZCE$(r#96uwoW+^&rCHFH@W7+B#=E=Xlt>7;8RcI z*{0$ftKz%cp!4(=?6?EaIjW6kkH)yFVJ7Neb`_|L2wTb`N=Y%C3M%Y`Lg-?bVoF`l%0$O6reVz7%6n4=M} zkSFje6`%lP#Jh&W1O4uF-5$D()9{29V8LFDfQDkxXLy&p_^t=o=^>2u2YjANm5bBP z3=M;PyzUd8HXXB(k2Oxhw`GH)s>3Lo<7rwT7F`41J_2XWzt|%aFe?nsp>&LYDbA^S z7*jo1dt=Pt2`J>Wghlkhnq9}wGw|1Ez|Q_ejHbegdj;o2IyA0g@R|m&oyV}cSvW(F z<5fMN8c`Lq_Ir%K)uFDy7N)`yM!*hR!0Z3^Slh81_G8A6!lE^p<&N-GQ!%ahiks-UzJq zyV!j@{y)1*uzPP}t$yoXj#Pbt=F2<8Y+1i z(f?vb?_&&O@VQg4V?EHyh=ZT}h)*=)Y<-W_S3@U(hbGGJ*L20FoX5LsVWje34@rc+;d?0XWMa&_F&pg=N$$ZutO*Sg z1^QKH?CR>!`XuW@BYx@~?yBxE62vLm}(Z+1VfES?Q2u5bGGTxIGs*Y#w1GT<%s0=lMn$9$+FTKDM zTcG?l8J~4TRSEd!A*syY36tIw=?kiovZoz3hmxotWFj@WfAn zjaYyYtbu3!8BUg!i3%LG_fRIwCns!KPdOVOR^opfuuAtjI$RS!BAf8hIvs7Ao{qoDh9U#STT`V%>`4}W?G zy$DWjAe|C!^JP#yOZ0v6HuOF6J@M7_TLYK)RAG!XT*(MB$cCSzR`;GNMsJ`K=<77W zOlGX8Xl$n+&?A`tn91x7meu5G&TG4KtGQS%jN7WMpyk;tW-G0s#uF~wqT7P2t8@PHn8K>RR-m%?oc7!|Yx>(Otuk33Z@Cey*F;r%nsULc5U~!mIJC+ zWI4vjjWiT9{xGEJi|BVk7qle3a*tlh{~VAjyR=@#Tz)qPY2UkYD*?_EU-ujDNJ^*nujT4BnzFOR>(eQTdq zH{*PkJ749N`E{X3bR%x7A2INzFVUHh@5y2_My2-o zHsQ<-2eF1iI*-^f`Hg&&W;ACnq8H+D!&yP{>IH%Dx+nazXsr!}pa5>&FPm)x6A z@(pvZuqWgW&lG-){5~_~)R#V=!jjK@8lCbXt^BX-T*lchP%}7>uA_4qlPza$rtsNe z*DdFav$zWkNj?r8RZdG~B)3#MD5`bLWp1Epr_B{Pyy)z>$Hg`mI}(==)3Zok1_~nQak&nY`TaCs<&2X}2sEag&Z{e@zmjZ*tjNm$I99PynD*SViA94Sd z7#lw`o-0|cSk0Ke(Ko}FTb3Bkayje^x;YT|x0D0I5>|V5`9@2 z9BA#HY3B>>7lxeMyqUsK^?B_MOY5joaji<$ER|HcRGH$X9u)hl$e4(-Hm7N{{*edh9?z!ywiz2gC%&8Y+W+eI%T+I)ywZQ{kajH3=*tQ2VRxF| zMMlT9DZV78dek9no}OaX1Rwfk`;fdrxh?Zz3gcZF{#wdLx`JtNBp(x9;!1o}>1n0j zm#kP^UG!AA(NfHmt8b&*%k9-&(?=RZ=Dy}7dVp-meECn$)NK9t4B=6@(ad{aJG>tF`1HM}_o(|>_k+)VeJt{GuPZimm%A8tAZB!_T4k1$nj9AvQQq*4 zxGfHKuE`#jUNi0CkCs0_=AL(L5NlCmj7y?w7V96MQf5Ng@X|yHIi?`0h_#L3iT02t zUeiPyYp8449+nVA$Bc@b8TFrexTY+z&{r~h^5?CuxCcvbnQm>peezDk!YdH9SwtXbw49I7B5nENO`GjR0&JuA^i+uFK;PK`5Bd( z|8-nShqS8Mha5^^Kk?LHjoMMHQK^5+ZZF%XbVP|tF`CE{=2slc&Za-miR^sc-)3KU zhZw$?Ccb5S*WxF_cWMWPUVC0Mz0SpfkUGKk|kDT>IPDpUDNfzz}t$zGXxpu3hPva*fJOE8V|D znV8iPi_HIWJl&5fq^`0Hbc4({!z;(EEm^Bf-!i`VFR`_)m&iSV`22(~_n#g}tbOI% zdELdPH<~^;_wvNoX^u2vqGe=EztVFm%&B;_{N4EbQ9RdOnc%kNwoQ*r>GJvTm%XWR z*%tQ{Wk0*hoF4tHgr|(9T$M5<;#Ze!Un|}0nf24Or2*rppeJZ@FaK7xw z;!nf3YbcR*RLr`brcb&0IpgcfAI@B}uVZMtwwLvIkv~h^EH$jmuu_|gD@Bh*T(OQe z9^w`ONji};8h2X9M3yb8D)vXoI;B!ej*nd*(OlnNeo)}}5uZHe>89)LE(b2Iy1ME1 z#ph3x9qFY#x7nD;Y9&UMK3G1r{Fc%UioLcyW`_#j3fpAuPCK7c`ODpuPw5SF8+)Te z{j@VIbX1#Sz2f_o-d-xL_zQS|XJI`pCS##)8268EiSeAZazuWVqv)}?VDYHp)nlR} z=NWc}Zabu3cT?8ADt;&D%7!b0t`54@mAbv zpax>hgRKFZ6p?uJ4Oe$@DM3`W9UG4GZ;UPa7j5 ziWj{Y*QfZX;^m6{Q#2_uJbbflx#gy@f?<}im6^4!3HviLD!OcuIYn0$og4jE_%Xv# zwaarm@A=PTpWeLaeShJdI(NH0toJ%SY0`IH?gpVd_akguk=SBoirb2{F8Ve6r2e_; zrthTvOfHpKAzh!I^m9v2S;x%4@=!cu(T}kT5j~3-Vzw7;P~=WzW<>djFE+;d+`Po{ z6AY>@;SVF4MD>mS9Nnr&rRcrkd6v(dMxE=un%5w!;9JXgb)R}3oqhV|x$EtLPc2gG z=PdS3rcW40*?vSeD0->rp{SX*t@`0a6CvCkD9Fez^=r>hPv-vIZ}uks=E?_Z5@#?c z+MY&Kiw=)|5IHA&5x5qDwYGJ)rGs^$?Qz)di1f&6TAm^cA&LuuTigkN6(d zB)Uv=YSgdDW#L*|2}>EYKbWiDB+hh=%N>&aEo14|mGA1lyZf7~BZdiT%!_>W~jol3cqF(r4tW1H}UUZlTZG6Qit(lSBcPLr%YCTiTX3vT3H&5g;e zlGoc#c{d87P!7{mU*9wq=&1o<9hJAdGqyCAH?B6`HjTHuv#zlP!Y4of#09y#_hmtTPDIw8v<*q+KJH5T^m)?PP+G;DqJ?LCS5%X^TE>S) z+Oo`Y-f&RUmAE9$_Dn3y%G;aEoeA?_Z(O@L!aH(95 zZoHub*p&}#>EXMhmPU_{J{?sqa$9(sZK`>WVLtao6UAIrbrSo!@OX!+^WDHF)Wl!&S2|n`eZ@|EwLDXu7%eUL4fLF_XJ$7`JDl=4Wx}^V zzpK*^XHLtj>0T>R#1^U(6VmvgIIxEN6&xZq_t*8h-1lAY++BRd_}bDAWs~|V*^pXH z)gZqR^>C+?jY`-(bx*39X0^V)IX0|%WcO&g=(eH{iX4qR7BwT&-8?viujaj*G7jbjQ;u;G??VISw|sN|9p5b<>%Zz>65xb-Vnb=JTvjO`T#wsv)I3zP zi8_>u)p1w!^MF$BZkr#rIZP9_+E&&UZ5<2*nbTa{($R9+THX4=OqsZNZfD{#}bSD0G_ud;-83BCNhr-euFv3tt+ z*C2yV7SvFhOjq7Ov$hY~6IX@y`$Hm?%%YoUpXeGI1Ez7-RkoA1zrhIG5S|>iJFHb0 z5%!PmzIBgffoZP(qh>RGSJhQ2<^8L$cFu=i3BPV+#HF{&NYAe4NOBMIo1}B0WyDgd z72TEW7uqR*0s^6G!uC@A{3q$*30(QvKz=?L9f&8K^DJ_zDbx=k7TRR$lKU?rtm?5 zrJ!P7V(zyBtLvDjijU^)Qgx*wZX&9LDk){8QDTy?DzMw%&40}Q#J@d|%uf^+3hRa9 zVp*}FXcK+Hc&trjWlwMjvC4VGBbT*Ct} zP7Z1+vqAbU$r9C7-GWsl$v@3|+x?H*=(_3HZ}&PcdOG@|{J;EfgamP-JW5eyTJ9&7 zmo|tlzBPDjLjte;D+4@q35|h4f!Bc%P`wx|)D_=~v*lG_hB?(&Nr_&k>Bm*qZ!x4B zXPLU0p92m1)!fMZ))X>23?dqMC2bcK{rv@%jX9)fmguw)%FWMmA{sMgnuuTuC5Cg z#1v_*k{O()ItIn+VbmMC7dsL@>nc~M%hO*pyfiL1y)o^AT^d$rIv7VVTfP8ZHl&>&knj(b6}ehmgd#2|V)0 z`@8#R`8xT+f#b6HfB6pkC4VI#l$!7_fClO-UXr?CeOjsp5#y<|Oc_l>u0Yq#Fx1%5 zRNCCqJlw1`_c6^d`k`d_K)0N`sC8?Ov6q<(^f+oA*&j^KHlY*B8+j%4R#`biY$e`+ z+QkQHACPGc6@Oa2!70sh_MLu4~VY z*9KUYeNXS9eB>!23wNX;)baWQ)$%y_-~W4{T!zj@q>?Y4l}?M#g%rMPUkZAmuLQDy_ynS1Km0O z9m8p3W0Tv|-Rv_>Fl{wnHhk8P*7f6DnhKg#tjuIEHJA{cM~?vO>nT}_IG`eMcT+ml zQE4Q1mbXiXM6Hk=DDY4Auk>B_p70#^7{ID3?@n}A_lyGnU>y*4&3syaW54Wg5*Wi@ z5Wb67B_l8=D%BMA8TjNT^fcx*dsK5&+k&gAyQ(XtzlsJ>6%014(_i`wT}Rzk?yI)A z_OvF0?Zw&|6SI{5N-d(kl5L?xI$rI@EoTzYN7I$j@@L5&46cX&7{$n=~MJ{nx^Md zndBejX`&9{N0qe`?t<&$hNMR5o3dG6F5M8<3m4F6dQjk@zbEQ8g72B{qc6vo=F9W- z_x}qfPqjc&U=QC%=q6T`!sT@NUu7Zc*@tnHeL}?mIgknU@Eb%K@-g`*rJ-NYOPDBj z7aOnHtoe!@JVEf_8^q zLKAkcyh(CFnf0zvz&GQM2WZ&U17AzuSMMh84DVp?Q15*2BX1esY+t@_w|`(j4s7Qe z3zBdG{-P_Y!OenypySIy^*th)d`_j(UzoLQDa}=l5%V@fdsX`m3PdfqS*Wuf;O=qB zTo#whUF61c6%jww06Ngl#;~QBI9eg^5YN>%=qAU6VuP!dr?OvqD}E9Lz9v5{aNMu> z#`*HSC%r?weZ396-MsC+-M!N=#&mCG-zlHj|J465aF|~rEEVrdzhn{U#A>)Fd8z)7 zI7^P8n$t0$aqVSSYkF(d+-A<88>w5X+oxNktFFuCHgP4m{n`#%8!W9k@RFz5@@xWA zmib1*LSb#y$uJ@pH>m4EYlCZ)(?D@{l#YlGg;#tL{$RiqXb&6fgc+OZZR3sc(%yPt znp{R>-9mYw()GghApsX|lWl`rkm1s6=%*DUf%lKGPXWu(YO* zW`X9I<{l8QJ+%9^pS2K+g$MbneXiZ7ZG{!xswt_t&empEGAE(Q`jNa(tX2<%2m2e5 z!(sV`q>{D(&uIYAOrj}+6`xO|*Kj@Xz0CE{IP~BZ+4%G@y1TXtNEUmIQPT0pk z3Ec8){k?pd-aowQo&%nVo>iV1o(E_$Ji?pn?csC##`+rv^!y`!KUVZKBBM!4Z*-R_ zf_wMp>ZwFAG7%`s9BL39#hhen0bNRI=4ftd7;Sm&T z^Ly8LJ9#^MM|c-|)8IcI``Y-k{3iqLc^7|9SSt<(UR8l+GH#!6i@pVYR-EX>P>y^` zj;BoYd3qqwombdV8keS=wi_5MN3@r<2es>g&TXfS)IQeC2b1I%yMwLA`k1whju}kf zpctwnxf*!L0^EZogH0Ebd&pNLgS1YJ6~72`h2p|xsEz&zEDJORx9Wy}w!g052!9gc zZ{}a@|Ihyiu&HPGUQqSfDYlmw`Mo?(sRUK)X+YL&hqnC#bzkB+(Syt*XHsseC!I#O z2L7}JyMVpQzGYLvX}!#@g~w~pip(S6K}R!<7z2}p8+Eu+x^&A+x zUBOS#9Iquml)6b@#hv1Ov88AcvxN6TqHs?5M;Ijx5&8%%g(~>f1IXjm!V4iroFXQP zC8PyXI>verNdBE@D6$E6sq=uP_3;Oz z_`NSQ;mXl*bU0AIIn*2K1uR&kqUl(=Jl%_KMVAIMa4$6DPLgHGbwmIt#eKMW4hs!| ziZ-QGlRHZf#dhL<7+;w1lApr&en&$G#F z7JgFMk8C2llC8tuW(GpJ>MUJ}K1J20Zb6m%8Sw}40cgRyz%tzf`XnjXJovBDM7blE zmX}JuFxmq`10jcBiL=GVrv)wr5(9aNY-zp;zXRCm`ocw_99FAz(l+ z!v@adK7J!mZ~bsr8Hc`oHwg;t-h-q>w!qvzq%4@zJ#-G;lv%;tViM{>-31KSN!(KN%6gz&|C2Y%RpncVH){cP zzDb-Qjuv}>YxIZMQ|u*<1qbVdcpF@-kXTCUCnW&EoG&$$_X6u(7btiY?k8_yyjy{- z84XNdIo#rZ!-)ST4nvu~9N6A7$dmu?_YqC~P3@yn;1im_4*JsF=z6fweCiAAU@tY8 zDoNS#%FbjEy7#l7vhD}UcAolA+{NdkTg(L9r#W$-+#7vgK7!3M6qu@X#Dw#e`e54L zme4y220?I9Z--fL<8` z$$7uk-0^JNF!BxfS%^+0ZOIboE%^aloQ*_3qBKychrp7rgpMg^fM+TVy!~<9?66bp6%`t%LZFzvAh_kq-^05rr3AX?r4#iR%JxGnOSDd;qE4r6(b z&P*<~S1qYSurG=Tssri*tWuKtIV|oJaIULh?c?x{9zbJM1VSW;?pZHU3)%t1#6X~- zXdt|<0_8LkXqa#ycYQ!qz65^$-{5ATv1_4o4iiiQa(JXtOj#$VN=~r|^noghbg+zE zE4VQ<4G3*s^#-W;wM0d-E_sm{OFkfrkhO{Z#A_mkSPy?Y5uIlS0c(F2b5}xr5txl8 zKr`0`hNK~W{Xj>dUO+ou!>N>}4#N(O06$_X`k&Pz@_`>20YrxjPd^9PMlJeTEdnO5 zFVIRFAX!=fv-Bxg2<*ltAWqw2v?YPr$irOTQywTwfOhVQxmGL3ia?k!uD z_OeY{AU;MI7{jOd&HkOf9=`kDIo?s;2yd*ni}$g&kME6dyg$ufKhTxG%A17tLPz1P zFimJDTo?WZ6K20uS$4=xz#HhJtW}ySDrL5EEO-ux!_Mkn=tMXaJFzGE3m&o+taviD zfS$(sG~>Wxy~yQoTe+KDZCw*xd!0p}qHkc>VmJ%V_YmDEU2Etb&DA7n-f0#xbEsd~ ztvb~MWr8%0KkEC#H{AEl9qroV>f$aB_T~x4N5^dYX!`_bXP4k!1P=QAfRFDaAB9z? zDgUC{7p96OQphNB2`U)zbYrq5F@`)soC4?34s7BrB|&bj1m&Mnfpi{`>m2bv@rpDa zECn*u6A0ul(1&?Tzhh>wb2U@6-E|g2rlGm9wyC3eqIrS2zonCCowp=^Md8`PJB6}im}j={K_CNK z%E|KMpdL21g`7okY(t#DtJ$-f+M2%1QDo&W$#X!>zX{R7&+;*ukZJK1{})g36Mf4O zv99(>{&9h8{Bj{#Dgp$}sNf^jO2SVLphaeYb`7^hUlMwxE6w{XL#$h^O~9r8Y7JU; znMsSu^1@UL+|(2L*_xeH52CFqAjR+pyl>nN$6iNq$J)Z_`To3$1?K!~c|<{kV<(i? zSWmCOX0e~#JXjmtm&e2l>Ljz2-3A+6sIAWx(YDcaVSg~gX*GEg+=rX0>Y;1$TDd5& zCJu49;NnjP4x+B|1y!a5|9*a$_#S!OF~y8tc~?+PnS?G!9(10VpsA(3!4djn`V;!y z`nraphM9)0h6IC8FY0b`9l4Smqn*wkfD*_H^)7Iyy2zh|Up|++itB~*oTIAayZwc| zz<$<#&Dq+`c&555dZ+s@3xh?soEF-o-b2)+QW&SEoMt4O2KBme+O^soZ9Q!iI%@nt z@0?duE7E}OOfpyuCLr&21G_l@i1)+jL-!r5lx}hcEPuYdD>w^SARESR0A~6II?COJ zKb#7`=OhQxo9TDdWU3<-MVF@TQd__UTZb668#R-1!KP!0TdD}P6ZNPisD2(4?gyIt zdi(l%H@a`QZn-OXYPl7c=o#kodJ}yc_;2C~X`!qRbw!l4h8Rb6p{=xqUc{VZ$Dl*V z7!9EvuGz;HG836y^drRid#PSjU8+0%4V9FR)CO`6l>v;@0%`*_nqI*yMy;nWy0`Qs zGtuJ=#8C+KkcB3KVT?Fss3e#g0% z2@Kdp#V5~_6QmtNGT)J36;KBT`YZcw{?EQu{#~ee*MtITQ$EBm5|hA+^(rGn>u|<8 zz;T~XbU=5bnuw13(*gQ#__1P)i>}HnVM?<_5sk)bs%jE7x!QePJMKK!T7Oozj=QB< z2YcSAJE`;Ox^b`J;U;P;YMj(<@}p`|s7LU%+*sC0YovK%Wub3if`0}yCoB0M`YH!@ z1uF4gDy!OqB_w3AQrt(H(>fR$Cx+lI_(DT zBeWf!LfdMVzO*6LAi_hOGJG`-G>?S(iABE{DpS{W*L7E*^tJ*!upKI<%T!~7yfjpF zqZSf_Y|rX{?Jec$<(}ZCy!qZyzN5aspuf@--uMtQswb#ex=yEbBjP%7fLLDih|i@i;B}r-GQk&|5NwQi_BT>}F&GIE>SJK) zoWq$p4RKNt>LO}nAF(pwtef>{G^hgf)jib}=+g8T48={2O*c&CE!C}GEH2YkLurG@ zP}g+SNSm4%BaIWe_iQX(pB$u0mOqNEgsM1Sp8J>ik9fDar@JP)Zo0O+w4RNgB(Kib z7AmzCp%`+5R-#T=!9U?6#5dwvX^K=<>LA_{%t9K!ns39O4y+4Qh9y-J7l~2Q1#zU< z7Ww28sT&w&J;5Ft6)XjO@q8e0oj^r?RBcdqAbdn?vOC!uS&yAshg@oH~B-A z862tn5Cy(+z#J&)Kkqx@t>UTSKI>}d9_mhjj)KSYr?0C2B}OU*{80MR3P*UE{{v^{ zYODw;#)z3%pW*yWo)Pv6`;j+q7K~zjXh0MNKliRQN$MbNk;=#xbcq_N{E2SS8NvNP zH2>x+)x^`yQ?DYrBL2IG^M5onkqhYc%ywoa6U&BaYHF)<&2?{ef9mse7j%tv|LE2k zvW!mi6U%eU1`BK6Z}J#F8p<2`>Tl~h=`y)LxM$kK>;r0~x@u6TT#+_HFJ(60hgb2} z0#gE_Kf|{KjPiQk*1kbL+4sxeJ&=zYQc3HH*NJ2Jg;@+i3;d`UnaCO4DUp!3!6;6UJe+X0yz26X%MuUy?w>NrtclF@FM?4C=VWeio6}Q z+Tl165`fE}4*cy)V8R;!aef*sDitvQRe}8O7Rn9A2g@n@;6Haj>+KV=p(|hrH3dTW zBKqQuRIfz8#WiF@I-R-A_J#hrQ~M6jWQ58{1>*oCY5HvPntxduTFY98SrW`1(+FsO z^oHukVxyw3pc|&0$yTGMkx$gCfMKm03|IC`=fo$%C4Oqa?d$KoVr$y-wrNlX)b#8DE06lx3*cTEMa00e)$Jxjo|8B1)Fh4v}smI*>I%FR$H1 zG*uIP=Qy^chC;k2b2@z`Lpft3(-`vxOGoQ|Yl@Y$eY5^+U1FUKl$qnhU}vC) zRLMTn{>DBF8i1!=O+7EY8NL(n{}JFxUlJODIj%tIhm4M0L zfQ+Pyx<6RXcY`AGo_sk&zK%?8Dl*h)SuHzJUnwC^L-yJYxllOj&3)A?(JQkW#X*DQ zJ=;ushSTe517X~19BK+Tm$S^U2CdC(m25+8@wTPbQc%D;Z)u5JJHb@LI6(jEe^h-1 zbQD<|Wx2FQ@C3IZxV!7%1lPe`2N_(0yW8Ldch{hUy9c*;(rNE5-`n~3>^V!Fgb=!_ zUcGwyeOFAk#HPY0E}E@FN05eIUAwC+l^05}!R`K8-UV3O=7I9;2FI(cQ&7}A1x?Z9 z%zRlDvN~lQ$!g_@$e!VB=icpk?sfRK1gz3nIbQLo`GME}X>1^tlmAe)=xx~Rc7vDa zL?F)Jlh?qxJOiHAA^j^{>pQ?5_KT8=hz%vTmEXywFz(a=WBabM2Q&W}{e=Pc3~7cg z<514Y|0R|)1)%MF+mdFDvOfoY<0V|cZbiO|JQ7(Wm!8W7MeO#Gmm`KoER5hI)`e}f zeKwC1%kc?pb?EubBu49J)XK^WDJtmqP4S4XvDtBs+>YB>WwRDR&1y!*+>C1(k23zn zk(A-doZ;x}%shgl=&;fDfZcs5;2R*E4wj^R- zUd(H`O&iV4t-EYT?ft@*g)fMRi5vmV@#M&0U*s?`q_1&1pH9DVsE;ioPmhIMdX!^p|jbWXIXsKjkccl8}^xDO~a3){~e9sBR@n$Mm&Ye>zHs`_@S^l_FGU8s)%)ULm`Zx z%66u^k}r&7&~~Yb1;anL{&IK=0|l%(TpLSdy(W|aMrtXN!QSQ| z=Ise+q0#y)INR^SK5{TtqAA!n9M%d!(d9I_uRjoTZ-;r}9%X`}!kW6@;3 z0z7O}Yf;;1dt}(-u@&34!;pTFg!Zk6?P@;Y*-%Xq=(rKSt>z$y0q|)JHWo6 zqp8(I1EV6;W`-$^B*TB-JIwRS-N3!r^_R0%b`vPrAIWlMRdhVaYMT`U?fMyxo!Mnw zUESr8U5WFy@p*lv0oT$J0%OuG3EN z3>O^BW1*XqMxSQpu$8%VZYp0@cqP;oePXn^ zkEN^iskO5$&i24o#J(f$ldQ@L#8ttYXz*#*wSVFBxFj$yCSb*KcQ zyrF5w)HcdlDKfaqU&2?=Th24az038{$v9hPyBwDt_Z@c~=IqMZ^Rs#lo_ zr=6Gf={^U?GH3p0lPNKPP3#xAWL zb}7YWCuaDszJ=Z?a3rbh-sF1kZ0~%VeLVYg_T%ht*}tJ}I?-uyEq0A?=l6I$+r3?o zD@yeH0)b$p{6pTN)K_`LgpVMb>og`{1yc`fuzb`IY86;Qd#IDt3(BCX($#2=zDsSx zZx15Q_#d?!Ub6M6D%2dPn{0&w%uo6iB9jvl<(`9_QdjN)*OLFuPZ30MvltWwJb^53 zHH|mx=G+$6;x!*PH#X;oZ)OGT-p!`f;!WWyAJ1JteqjfF3M~KW1dE+;AGH?N{BhEX zU_(6P5w8z>gx*-A#km#Nc2`qZtZTK)aCLI;1SerJbPpeT=Kv`Z57dDvm=gRXy#YR? zpZY@WqP^B8gPjkrdN5fJ6Oo8^{~$Taf@mpEm4y%ZYCP$AY9%!pb7VYqje3r3`(;G5 zJyZjFDt$KR31zw=bCii?*Rr2j7yFgvxh`B&UWTWQTlg--Av$wYm?nBelj(riK+F{K zArE;4xzXlAcm4#|fg`wC?5j}poB}Hyxrn>^Q_WC0Rg?3`!=)kUQI3Y83wRy}$G zG-Zo1Q<;~@n@@$_k)7MjZA6dkhn!$KZx{Lr!-T=YJbWK06c%Lu4u1*RYZZE@A~y{= z>4wY_+CxQA^~f1u(&dGs!#eE(6iSnTs2U-q1zSU;vs$39zqc=s*W=#f%5vUtK5`ZE zjSqZ=p4M4!QJ)FgP;tT2N|xFST*7yVwRh6@!C!nOv6wtaErwr95BfRY+F10nZJ0Hd zQE^m7L@?_SOAR~L+qE&CZbD4GBciVLu(Q|zj-!)!hZsp7dLW|bdzjg< zP2Wws&EqV!tQpqH(1m?yzhb{>pJpfQL*SFM)>_3{$kNOFOYAIk=1wy0=!N8cBNHs6 z*Rlc>PPFfs=L341AF-u+jwM;Gvus(FGW{9dGp}T}&dSc}luf#hyLP&ldKB+m|MkFD z$*zPU$Cak@&=?p%ouj)Wi+u^LXg&9t>&aK;!}unMHnnFlRalyZXFM89L+vadLUFNi2ZWpk3bs>QHmS&!SS zP&KOa6ZjyrhblwZjP=@D)sTkjq_<`iO=PL3ZVdwg7vhXfRDFDhwI*ChR&qTNkmdsjK-93$*jBH*MMWy5Wby#fa+R zSHt#)6%5Y{2ZbMD7qKI6H2;#gZD9x;pt=a=(x~*ThWY4A_zi_7DBl z|FDafl}d;-9apz%UOhilL5gE-zKVIyW^>hn`RHPvZQXD4+aK72_F!18h{VXgxr#ze zdIg^FukbQZ-gMfRS*w{i;SFnHN6-bxM*2SabYKkj<+t2!XLm=D%spw@DVtNaq;yZ& zl-w_=bkg|WbCPZ+ds5XjDSc_in#>iBlW;OS<+~h+1%hF{8jk4a3Mdv1;9~gYf+E~B ztv9!YvRR@z%EFn?n%A41rX;a3R)7!LWTri{mM%|SAsQNu!4S1-X~>`^C^MDm$|q$N z@{8}Zv*4iKB*1NjN?8#oA)goiG{stqTCXA=q}u54MG@a32jps+YgA-JM9c6Jk$WTU zxe~(<*iM?uiTC)%{Bdq1bDzpotI0F{`Tb`9HP2l4knAs+tI|H=U42WvoJypAPac|l z{I@B&bxJhceNSW@%RHNv?pWdc+e7$Q2Fglsbx|Md{fYI|K&BpR;^O#=D8&#{A#)Y; zE0e=i$#mX))nu6LVj@3{%Rv5n6f&`QDS@nDOvK9B1#PJP`e(J2x)0iY-L#9khWy+k z@QPc)wP6@Lo}Vs6iUWiWqG%dnxoqDQ79O!J{BYQ>umfS1NIq8ryb2zN_YVJQkFmam z``dO?EWetYO#dWH>276)d?VoSxA&fNZ*Uq}QbynO;^{}y>ZBb@ZJlCIIg>=Eh^c+k zPo__R3(lU*Zt#22-7S32;FeHIdMUqDqm8;`2YM${iyZ{bu0@FSHZavR=P?uJa8o;z z9jw;PP(d9p+~U0KY9Nu!nPz-ztsUh-Jo<(+M^24~Dox2NAt`y*{;>ampZ$-d-|DZ8QiUN7Sw+n9Vo!O0snXnxZaDPtS}8TMk*rRCZHb$p)c6D z56tn_7uF)snjC3gk9~kSVtn`;s6IBfC)xYh)8UE}Z>kKf;~&fndLXrc_@Z5qhXii< z>Uq0+@KZ$T%Om6l0;r=&#Q4$P^Z={e1E$?#b*z3Ofwg!J3`-?u5!l!r z$kJpnJX<6o7@v^&o{k993u7Qy?Yp3+bAl{IcV_-(t8ne01KV26Ybt1NZpmvcX`6$2 zENIUPiw?hory6bFjXmCA`$lV1%XHIAK9fDgJfef-F5_?Qn*1hE-nZHN#FOGG=xpL> zpLsg{aO&N(U~2KSN2#8aCn?8LE~S1>JD+ha^L3Vxy(RmDtGUPTs~fx`EmU@?9rYnZ zUaA#ZO%c8c|A%l%NEf>!+gR2z$(&`{j3|9C=zP`^7Yfn*cc|=b0AekSt_{tw9l*AX zMGmDsa-$WE-$2qdF^&@Z$w^pmm82hI_GrP~;3Rt-Y1~5BqHU z0eir{9SWWAp-mlY37AR<-`V19G(DC&XH3+qsQZIYec@ix6XUsnD3_W!EWKNrk+M9k zQrd7R|Bg?2lyWF#W!i!C8ku$BE*0h+?Y!;2?7i!sCCyTbXl6aZcu#hOZt8ySv+zx* z4kTGGQ>3MkCCXaFGRT~W=h|+%ET)N9gp+(F?f_GQ8BKSkmr!%bOHc)P44r}3XoDhh zz#omnP-2*gwbwOjHQIG)_z_JPbfJrA1=nP(rG)LF?UQX1;>iMbY-j9=_6WOTEpIt$ z9%C9Urtm9}&4Lz?5v{dSUrJ>HFTCa5(XM0JOC6*m9h$vmQdgw>m(nY>Q)=O~CaFfs z;?!Gd^D>TR>W&y!UiV4&KF>-2{NQlqq&m{jiD6WA`ViBVYb;C^i(!Ru-24$bxnIq9 z%)Kl(%#>xX>8kiQ+F^Zg(u;F189&{SnngarPBbreaCe|hwi3CXa71alAk*D~)X6K< zZJKBOECGz*P2rn(&Xfd)xR=O=Ua@wxxomM^eZvNY-G%mTJ4!SW8Hx1f+V_dFm%2Ca+J@Y{3pBc%iWmEPifnStTIW;EjbLz&l?rEjd<1)r& zO?O({oxG90)BfZ@mNZ}82S=eh)Lx*8{p@!Bop9LXG)=*Nu(ic+{%#&*>4fjcOoL4O zM2j$sr@0>N0Olu9Ik8k75)oSCv)%+66~&Fx#(tfY#?zK(xu=Y6^7M( zBHlJ{PBz)Wp|4=q?Vk}dC+%;oC+#n6XKiPYr`c=TB$gDNoKBA?d+0s1G+>F+fXxi$uVEVqSHy8(XcZRpFpAN2( zENVeRB+pWN=?~0eE|uRbb})4_Z#4I?bb{XLK})zLh|=UUFEcF$X0;#YuNG_(<_6YM zGvGdGCCtVdoq^g~3uvRw07|1RqLW1tJ(`Ufxi*l)1-SwIHDRCF%oJsQWgcMZX_c(& zZEq1_=Irb7rqaM5IBzLys)jceCyd4rHi>MkzflA7O6gr-rr+V2?jjwBGB;-Q$n2Fd zIK5)pqLiB{Ws>7lR;AWV&q_a>J}aYHW`yHIcEGjC+Y-@⪻t@SM`NHldMf|XEtFS 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�ynDU7 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 hint: %s", + decision.reason, decision.hint) + if live_rec is not None: + live_rec.log_event("REJECT", f"{decision.reason} {decision.hint or ''}") + if force_measure and speaker is not None and decision.reason != "need_focus": + now_mono = time.monotonic() + if _pending_reject is not None: + pass # 已在保护中,上面已处理,不重复挂起 + elif sent_tracker is not None and sent_tracker.speaking: + # 模型正念字:挂起,保护到下一个标点再复查 + _pending_reject = { + "since": now_mono, + "reason": decision.reason, + "snap": sent_tracker.snapshot(), + } + LOG.info("[标点保护] speak中,reject(%s)挂起,等语音播到标点或超时1.5s", + decision.reason) + else: + # 模型没念字(listen/静默)→ 无需保护,直接打断(受节流) + if (not _hint_playing + and now_mono - _last_hint_mono >= _HINT_THROTTLE_S): + _last_hint_mono = now_mono + asyncio.create_task(_do_reject_interrupt(decision.reason)) # ── 「持续坏」检测(优先于标点保护)── # 3s 窗口内"真坏"reject≥2 → 输出基于坏图=幻觉。此时不走标点保护 # (前半也错,不值得保护),直接触发"停→播提示→恢复"。 @@ -1099,15 +1178,33 @@ async def _do_reject_interrupt(reason): if _bad_in_window >= _BAD_THRESH and _is_real_bad: _pending_reject = None # 持续坏优先,取消标点保护挂起 # 到这里必是"真坏"(severe_shake/unstable/too_dark/orient)。 - # 直接触发完整"停→播提示→恢复"(复用 _do_reject_interrupt, - # 停模型输出不杀死、播完恢复)。耗时≈播报时长,天然间隔。 + # **必须和标点保护那条一样受 _HINT_THROTTLE_S 约束**: + # 原注释说"耗时≈播报时长,天然间隔",但那不成立 —— + # STOP/RESUME 是在播报**之前**就发出去的,不受播报时长限制。 + # 实测画面持续不合格时(晃动/倒置),3s 窗口每轮都能凑够 2 次真坏, + # 于是每轮一次 STOP/RESUME;17 秒内 17 个 control event 之后 + # gateway 会话直接换代重连(generation 0→1),期间 + # gateway=preparing、音频队列堵死 queue=96 drops 暴涨、图也送不出去。 + # 表现就是"灯变红、画面卡住、取图 TimeoutError"。 + if _hint_playing or _now - _last_hint_mono < _HINT_THROTTLE_S: + LOG.debug("[持续坏] %d次真坏,但距上次提示 %.1fs < %.1fs,跳过打断", + _bad_in_window, _now - _last_hint_mono, + _HINT_THROTTLE_S) + elapsed = time.monotonic() - t0 + try: + await asyncio.wait_for(stop_evt.wait(), + timeout=max(0.0, interval_s - elapsed)) + except asyncio.TimeoutError: + pass + continue + _last_hint_mono = _now LOG.info("[持续坏] 3s内%d次真坏reject,打断+播提示(停→播→恢复)", _bad_in_window) if live_rec is not None: live_rec.log_event( "PERSIST-BAD", f"3s内{_bad_in_window}次真坏 → 打断 ({decision.reason})") - await _do_reject_interrupt(decision.reason) + asyncio.create_task(_do_reject_interrupt(decision.reason)) elapsed = time.monotonic() - t0 try: await asyncio.wait_for(stop_evt.wait(), @@ -1139,51 +1236,14 @@ async def _do_reject_interrupt(reason): # 仍 reject → 打断(受节流约束) LOG.info("[标点保护] %s,仍 reject(%s),打断", "到标点" if reached else "超时1.5s", decision.reason) - if now_mono - _last_hint_mono >= _HINT_THROTTLE_S: + if (not _hint_playing + and now_mono - _last_hint_mono >= _HINT_THROTTLE_S): _last_hint_mono = now_mono _pending_reject = None - await _do_reject_interrupt(decision.reason) + asyncio.create_task(_do_reject_interrupt(decision.reason)) else: _pending_reject = None # 被节流 - if decision.send and decision.best: - ts = now_ms() - latest_frame.set(decision.best, ts) - stats.image_count += 1 - await harness.send_frame(decision.best, latest_frame.sequence, ts) - LOG.info("[漏斗] send (%s)", decision.reason) - _emit_chunk_img(web_ui, decision.best, latest_frame.sequence, True) - # -o record:只录真发送给模型的 best 图(chunk_idx = sequence) - if live_rec is not None: - try: - await asyncio.to_thread( - live_rec.on_frame, decision.best, latest_frame.sequence) - except Exception as e: - LOG.warning("[LIVE] on_frame err: %s", e) - # 注意:send 不清 _pending_reject,保护期只看到标点那一刻 - else: - LOG.info("[漏斗] reject(%s) -> hint: %s", - decision.reason, decision.hint) - if live_rec is not None: - live_rec.log_event("REJECT", f"{decision.reason} {decision.hint or ''}") - if force_measure and speaker is not None and decision.reason != "need_focus": - now_mono = time.monotonic() - if _pending_reject is not None: - pass # 已在保护中,上面已处理,不重复挂起 - elif sent_tracker is not None and sent_tracker.speaking: - # 模型正念字:挂起,保护到下一个标点再复查 - _pending_reject = { - "since": now_mono, - "reason": decision.reason, - "snap": sent_tracker.snapshot(), - } - LOG.info("[标点保护] speak中,reject(%s)挂起,等语音播到标点或超时1.5s", - decision.reason) - else: - # 模型没念字(listen/静默)→ 无需保护,直接打断(受节流) - if now_mono - _last_hint_mono >= _HINT_THROTTLE_S: - _last_hint_mono = now_mono - await _do_reject_interrupt(decision.reason) if probe is not None: since_last = (t0 - _last_grab_mono) * 1000.0 if _last_grab_mono else 0.0 jb = len(decision.best) if decision.best else 0 @@ -1473,7 +1533,21 @@ async def start(self) -> None: if self._funnel is not None: try: ms = await asyncio.to_thread(self._funnel.warmup_orient) - LOG.info("[预热] 方向分类器就绪 (首次 %.0fms,运行时应降到 ~10ms)", ms) + # 必须查真实状态:这行原来无条件打"就绪",而加载失败时 + # process_orientation 会静默回退到轻量 CV 判据、照样返回, + # 于是"预热就绪"根本不能证明分类器可用(实测 panel 环境下 + # paddle 循环导入失败 → 轻量判据 → 第一轮就误判 orient_flipped)。 + try: + from .cam_pipeline_v2 import orient_classifier_status + _ok, _err = orient_classifier_status() + except Exception: + _ok, _err = True, "" + if _ok: + LOG.info("[预热] 方向分类器就绪 (首次 %.0fms,运行时应降到 ~10ms)", ms) + else: + LOG.warning( + "[预热] !! PaddleOCR 方向分类器加载失败,已回退到轻量 CV 判据 —— " + "orient 判定会明显变差(实测第一轮就误报 flipped)。原因: %s", _err) except Exception as e: LOG.warning("[预热] 方向分类器预热跳过: %s", e) # ── rerun 模式:用录制的 session 回放(音频+best图)重跑 -o,不接实时设备 ── diff --git a/extensions/assistive_harness/phase_b/requirements-phase-b.txt b/extensions/assistive_harness/phase_b/requirements-phase-b.txt index a247f64..4cd81f4 100644 --- a/extensions/assistive_harness/phase_b/requirements-phase-b.txt +++ b/extensions/assistive_harness/phase_b/requirements-phase-b.txt @@ -1,4 +1,34 @@ -aiohttp>=3.13 -Pillow>=10 -sounddevice>=0.5 +# OpenGlass — extensions/assistive_harness 依赖(②③④ 链路:语音控制 + CV 漏斗) +# +# 装在**和 MiniCPM-o-Demo 同一个 conda 环境**里:panel 起子进程时继承启动它的环境, +# 而 worker/gateway 也在那个环境跑。不要另建环境。 +# +# conda activate <你跑 MiniCPM-o-Demo 的环境> +# pip install -r requirements-phase-b.txt +# ── 基础 ── +aiohttp>=3.13 # gateway/harness 的 WebSocket 客户端 + bridge_ui 服务 +numpy>=1.24 # 音频/图像数组 +Pillow>=10 # --rotate 转正(PIL) +sounddevice>=0.5 # PC 扬声器播放(AI 语音、reject 提示音) +requests>=2.31 # ESP32 HTTP 控制(分辨率/对焦) +PyYAML>=6.0 # harness 的 skills 配置 + +# ── 8021 harness(语音控制腿,②③④ 需要)── +fastapi>=0.110 +uvicorn>=0.27 +funasr>=1.3 # 流式 ASR。模型另外下载,路径写进 runtime.local.json +cryptography>=42 # panel 首次启动自签证书(没有它会退回调 openssl) + +# ── CV 漏斗(③④ 需要)── +opencv-python>=4.8 # 清晰度/光流/亮度判据 +# +# ★ 方向分类器(orient_flipped / orient_sideways 判据)—— +# 装不上或版本不对时会**静默回退到早期的简易判据**,表现是画面明明是正的 +# 却一直报"画面好像反了"。启动日志里会有: +# [预热] !! PaddleOCR 方向分类器加载失败,已回退到轻量 CV 判据 ... +# 看到这行就说明下面两个没装好,别忽略。 +# +# 实测可用组合(CPU 版即可,模型只有 6.75MB): +paddlepaddle>=3.0 # GPU 机器可换 paddlepaddle-gpu,但 CPU 版足够 +paddleocr>=3.0 # 只用其中的 DocImgOrientationClassification diff --git a/extensions/assistive_harness/phase_b/templates/live.html b/extensions/assistive_harness/phase_b/templates/live.html index 96099f9..5ab0032 100644 --- a/extensions/assistive_harness/phase_b/templates/live.html +++ b/extensions/assistive_harness/phase_b/templates/live.html @@ -399,7 +399,12 @@

停止并保存?

const sent = $('hSent'); sent.classList.remove('good','warn','bad'); if (e.img_sent) { sent.classList.add('good'); $('hSentText').textContent = '送图 ✓'; } - else { sent.classList.add('bad'); $('hSentText').textContent = '送图 ✗'; } + else { + // 没送模型:可能是被漏斗拦下(带 reject_reason),也可能只是同一轮里 + // 非 best 的那几帧。画面照样刷新,这样第一视角才连续、也看得见被拦的图。 + sent.classList.add('bad'); + $('hSentText').textContent = e.reject_reason ? ('拦下 ' + e.reject_reason) : '送图 ✗'; + } // 3) 音频静音 const aud = $('hAud'); diff --git a/runtime/openglass_omni/devices.example.json b/runtime/openglass_omni/devices.example.json new file mode 100644 index 0000000..5cecb6c --- /dev/null +++ b/runtime/openglass_omni/devices.example.json @@ -0,0 +1,7 @@ +{ + "_说明": "多副眼镜配置。烧录后从串口看到 IP,改这里对应那副的 esp32_host。rotate 是该眼镜摄像头顺时针旋转角度(0/90/180/270),按设备侧装方向填。两台笔记本各自维护自己这份文件。gateway 走本机默认,不放这里。", + "devices": [ + { "name": "1号镜", "esp32_host": "esp32_ip", "esp32_port": 80, "rotate": 0 }, + { "name": "2号镜", "esp32_host": "esp32_ip2", "esp32_port": 80, "rotate": 90 } + ] +} \ No newline at end of file diff --git a/runtime/openglass_omni/panel.html b/runtime/openglass_omni/panel.html index 99e4173..c024489 100644 --- a/runtime/openglass_omni/panel.html +++ b/runtime/openglass_omni/panel.html @@ -107,6 +107,10 @@ + + @@ -184,11 +188,20 @@

第一视角

(CFG.devices||[]).forEach(d=>{ const o=document.createElement("option"); o.value=d; o.textContent=d; sel.appendChild(o); }); - applyChain(); // 按链路刷新灯/日志页签/FPV/眼镜下拉可见性 + // 填充判据下拉(只有开了漏斗的链路用得上,applyChain 里控制显隐) + const ssel = document.getElementById("sceneSel"); + (CFG.scenes||[]).forEach(x=>{ + const o=document.createElement("option"); o.value=x; o.textContent=x; ssel.appendChild(o); + }); + if(CFG.default_scene) ssel.value = CFG.default_scene; + applyChain(); // 按链路刷新灯/日志页签/FPV/眼镜+判据下拉可见性 fpvOn=false; toggleFpv(); // 默认开启第一视角画面 setInterval(poll, 1000); } +// 进程内部名 -> 界面显示名(拿不到就退回内部名) +function PLABEL(n){ return (CFG.proc_labels && CFG.proc_labels[n]) || n; } + // 切链路:重画状态灯、日志页签、FPV 地址;Rokid 分支隐藏眼镜下拉 function applyChain(){ const c = CFG.chains[curChain]; @@ -197,7 +210,7 @@

第一视角

lights.innerHTML = ""; c.procs.forEach(n=>{ const d=document.createElement("div"); d.className="light"; - d.innerHTML = `${n}`; + d.innerHTML = `${PLABEL(n)}`; lights.appendChild(d); }); // 日志页签(保留 autoscroll 勾选框) @@ -206,7 +219,7 @@

第一视角

tabs.innerHTML = ""; c.procs.forEach((n,i)=>{ const t=document.createElement("div"); - t.className="tab"+(i===0?" active":""); t.dataset.t=n; t.textContent=n; + t.className="tab"+(i===0?" active":""); t.dataset.t=n; t.textContent=PLABEL(n); t.onclick=()=>switchTab(n); tabs.appendChild(t); }); tabs.appendChild(auto); @@ -215,6 +228,10 @@

第一视角

const show = c.need_device; document.getElementById("deviceSel").style.display = show ? "" : "none"; document.getElementById("devLabel").style.display = show ? "" : "none"; + // 判据下拉:只有开了漏斗的链路(③④)才显示;①②没有漏斗,选了也不起作用 + const showScene = !!c.need_scene; + document.getElementById("sceneSel").style.display = showScene ? "" : "none"; + document.getElementById("sceneLabel").style.display = showScene ? "" : "none"; // FPV 地址随链路变(ESP32=demo bridge_ui:8080;Rokid=bridge:18080 自带页) document.getElementById("fpvUrl").textContent = c.fpv_url; if(fpvOn){ fpvOn=false; toggleFpv(); } // 重挂 iframe 到新地址 @@ -226,6 +243,8 @@

第一视角

} function curDevice(){ return document.getElementById("deviceSel").value; } function onDeviceChange(){ window.pywebview.api.set_device(curDevice()); } +function curScene(){ const e=document.getElementById("sceneSel"); return e ? e.value : ""; } +function onSceneChange(){ window.pywebview.api.set_scene(curScene()); } function selectPreset(name,el){ document.querySelectorAll(".preset").forEach(p=>p.classList.remove("active")); el.classList.add("active"); @@ -234,7 +253,7 @@

第一视角

} function startAll(){ const p = document.getElementById("prompt").value.trim(); - window.pywebview.api.start_all(p, curDevice(), curChain); + window.pywebview.api.start_all(p, curDevice(), curChain, curScene()); } function stopDemo(){ window.pywebview.api.stop_demo(); } // 停止:只停 demo,无需确认(现场要快) function restartDemo(){ diff --git a/runtime/openglass_omni/panel.py b/runtime/openglass_omni/panel.py index ed262e3..d3bce4d 100644 --- a/runtime/openglass_omni/panel.py +++ b/runtime/openglass_omni/panel.py @@ -169,7 +169,44 @@ "--connect-retry", ], - # ⑤ rokid bridge —— 与 demo 平行、二选一的“第四个进程”。 + # ⑤ 8021 harness —— 语音控制腿(停一下/重新开始/找物),也是 ASR 来源。 + # 只有 ②③④ 带 harness 的链路才起它。 + # ★ 开源用户必改:--model-path 指向你机器上的 FunASR 流式模型目录 ★ + # 证书:自签即可,只为过 wss 握手,不绑机器;客户端全是 CERT_NONE 不校验。 + # ★ 它在 extensions/ 下,用 -m 启动,因此 cwd 必须是 MiniCPM-o-Demo 目录 + # (见 _spawn 里的 name in (...) 白名单)。 + "harness": [ + "python", "-m", "extensions.assistive_harness.server", "--enabled", + #"--model-path", r"\LocalASRmodel\speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", + # e.g. + "--model-path", (r"D:\OpenGlass\OmniDeployment\OpenGlass\LocalASRmodel" + r"\speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online"), + "--port", "8021", + # 绝对路径:harness 的 cwd 是 OpenGlass 仓库根,而证书由 _ensure_certs + # 生成在 minicpm_demo_dir/certs 下(gateway 也用同一对)。 + "--certfile", "{certfile}", + "--keyfile", "{keyfile}", + ], + + # ⑥ demo_funnel —— esp32_runtime(harness + CV 漏斗)。与 ④ demo 互斥: + # 两者都要独占 ESP32 的音频 WS 和图像 TCP,不能同时跑。 + # 这里只放各档位共用的参数;--esp32-host/--esp32-port/--rotate 由 + # devices.json 填(_device_args),漏斗档位参数由 _funnel_extra_args 追加。 + # ★ 同样在 extensions/ 下,cwd 必须是 MiniCPM-o-Demo 目录。 + # ★ 8006 是 TLS(https:// 能取到 openapi.json,http:// 是 Empty reply), + # 走默认 wss,**不要**加 --no-tls;而 harness 8021 是自签 wss,两者都是 wss + # 但证书来源不同。 + "demo_funnel": [ + "python", "-m", "extensions.assistive_harness.phase_b.esp32_runtime", + "--gateway", "localhost:8006", + "--harness-url", "wss://127.0.0.1:8021/ws/control", + "--image-tcp-port", "5000", + "--web-ui-port", "8080", + "--record-live", + "--prompt", "{prompt}", + ], + + # ⑦ rokid bridge —— 与 demo 平行、二选一的“第四个进程”。 # 注意:它不是客户端去连眼镜,而是在 PC 上开 18080 端口等 APK 连进来。 # ★ 用 v8(API V2)。v7 是旧协议(/ws/duplex),连不上新 gateway:8006。 # ★ run_rokid.ps1 / run_rokid_wifi.cmd 已不再需要——它们做的事 @@ -191,8 +228,12 @@ # live.html 观测页(与 ESP32 demo 同一套 bridge_ui 前端/模板) "--ui-port", "8080", "--prompt", "{prompt}", - "--glasses-ssid", "SQZ", - "--glasses-psk", "sqz.ac.cn", + # ★ 眼镜连的 WiFi。**不要把真实密码提交进仓库** —— + # 在 panel.py 同目录放一个 panel.local.json(已在 .gitignore): + # { "glasses_ssid": "你的WiFi", "glasses_psk": "你的密码" } + # 没有该文件时用下面的占位值,Rokid 链路会连不上 WiFi 但其余功能正常。 + "--glasses-ssid", "{glasses_ssid}", + "--glasses-psk", "{glasses_psk}", ], }, @@ -202,13 +243,48 @@ # rokid → rokid_minicpm_v7.py (PC 开端口等 APK 连进来,无 device) "chains": { "esp32": { - "label": "ESP32 眼镜", + "label": "① 基础对话", "tail": "demo", # 第四级进程名 "start_order": ["llama", "worker", "gateway", "demo"], "stop_order": ["demo", "gateway", "worker", "llama"], "need_device": True, # 显示眼镜下拉 "fpv_key": "fpv_url", # 第一视角地址 }, + # ── 以下三条走 esp32_runtime(harness + 漏斗),四档递进演示 ── + # ① 基础对话 = 上面的 "esp32"(esp32_bridge.py,无 harness 无漏斗) + # ② 语音控制 = harness 开、漏斗关 + # ③ 质量筛选 = ② + 每秒多帧里挑最清晰的一张 + # ④ 完整防幻觉 = ③ + 坏图直接拦下并语音提示 + # 每档只比上一档多一件事:看到什么说什么 → 能听懂指令 → 图会挑 → 坏图会拦 + # (没有"只对焦"这一档:对焦后要等 settle 再重抓,1s chunk 时序固定, + # 对焦后那张未必赶得上这一轮,等于花了时间没用上。) + "esp32_voice": { + "label": "② 语音控制", + "tail": "demo_funnel", + "funnel": 0, # 漏斗档位:0 关 / 2 选图 / 3 选图+拒绝 + "start_order": ["llama", "worker", "gateway", "harness", "demo_funnel"], + "stop_order": ["demo_funnel", "harness", "gateway", "worker", "llama"], + "need_device": True, + "fpv_key": "fpv_url", + }, + "esp32_select": { + "label": "③ 质量筛选", + "tail": "demo_funnel", + "funnel": 2, + "start_order": ["llama", "worker", "gateway", "harness", "demo_funnel"], + "stop_order": ["demo_funnel", "harness", "gateway", "worker", "llama"], + "need_device": True, + "fpv_key": "fpv_url", + }, + "esp32_full": { + "label": "④ 完整防幻觉", + "tail": "demo_funnel", + "funnel": 3, + "start_order": ["llama", "worker", "gateway", "harness", "demo_funnel"], + "stop_order": ["demo_funnel", "harness", "gateway", "worker", "llama"], + "need_device": True, + "fpv_key": "fpv_url", + }, "rokid": { "label": "Rokid 眼镜", "tail": "rokid", @@ -220,6 +296,30 @@ }, "default_chain": "esp32", + # 判据档位:漏斗的两套标定参数。对外用场景名,不暴露内部值。 + # 严格 = medicine (药盒小字高危,worst_x0=6.5 ACCEPT_Q=0.55) + # 日常 = stationery(生活用品,worst_x0=5.0 ACCEPT_Q=0.48) + "scenes": {"严格判据": "medicine", "日常判据": "stationery"}, + "default_scene": "严格判据", + + # 档位④的提示音目录。**跟着 extensions 包走**(和 bridge_ui 的 templates/ 同思路), + # 不落在上游 MiniCPM-o-Demo 里,保持三仓库独立。这里是相对 OpenGlass 仓库根, + # panel 会拼成绝对路径传给 esp32_runtime(它的 cwd 是上游,相对路径会指错地方)。 + # 启动前检查,缺了就报错 —— 而不是跑起来才发现没声音,那时 duplex 已在跑, + # 没法当场用 gen_reject_wavs.py 生成。 + "reject_wav_dir": "extensions/assistive_harness/phase_b/assets/reject_wav", + + # 进程的界面显示名(灯泡/日志页签用)。内部名不变,只影响 UI。 + "proc_labels": { + "llama": "推理后端", + "worker": "worker", + "gateway": "gateway", + "harness": "语音控制(8021)", + "demo": "眼镜", + "demo_funnel": "眼镜+漏斗", + "rokid": "Rokid", + }, + # 可选眼镜(对应 devices.json 里的 name)。面板顶部下拉选择。仅 ESP32 分支用。 "devices": ["左镜", "右镜", "备用镜"], @@ -278,6 +378,191 @@ def _load_devices_from_json(path="devices.json"): # ============================================================================ +def _load_device_map(path="devices.json"): + """读整份设备表:name -> {host, port, rotate}。 + + 原来只取 name(下拉用)。但 esp32_bridge 自己读 json(--device-config), + 而 esp32_runtime 不读,它只认 --esp32-host/--esp32-port/--rotate, + 所以由 panel 把这几项取出来填。rotate 尤其不能漏:摄像头物理侧装, + 不转正的话漏斗的方向检测会把"相机侧装"误判成"用户把盒子拿反了"。 + utf-8-sig:记事本/VSCode 存的 json 可能带 BOM,用 utf-8 读会炸在第一个字符。 + """ + out = {} + try: + with open(path, "r", encoding="utf-8-sig") as f: + data = json.load(f) + for d in data.get("devices", []): + n = d.get("name") + if not n: + continue + out[n] = { + "host": d.get("esp32_host", ""), + "port": int(d.get("esp32_port", 80)), + "rotate": int(d.get("rotate", 0)) % 360, + } + except FileNotFoundError: + print(f"[panel] 未找到 {path},带漏斗的链路(②③④)将无法自动填 IP") + except Exception as e: + print(f"[panel] 读取 {path} 失败({e})") + return out + + +CONFIG["device_map"] = _load_device_map(_dev_path) +if CONFIG["device_map"]: + print("[panel] 设备详情: " + ", ".join( + f"{k}({v['host']} rot={v['rotate']})" for k, v in CONFIG["device_map"].items())) + + +def _load_runtime_local(): + """读 runtime.local.json —— 本机路径与私密配置,**不进仓库**。 + + 为什么要它:panel.py 里原本写死了五处本机绝对路径 + (conda 环境、MiniCPM-o-Demo 目录、llama-omni-server.exe、主 gguf、FunASR 模型), + 还有眼镜 WiFi 的明文密码。开源后每个人都要改源码才能跑,密码也会进 git 历史。 + 改成从这个文件读,clone 下来只需 `cp runtime.example.json runtime.local.json` 再填。 + + 键名沿用仓库里已有的 runtime.example.json 风格。 + 找不到文件时保留 CONFIG 里的默认值(也就是原来的写死值),行为不变。 + """ + here = os.path.dirname(os.path.abspath(__file__)) + f = os.path.join(here, "runtime.local.json") + if not os.path.isfile(f): + print(f"[panel] 未找到 {f}") + print("[panel] 请复制 runtime.example.json 为 runtime.local.json 并填写本机路径;") + print("[panel] 否则将沿用 panel.py 里的默认值(多半不是你的路径)。") + return {} + try: + with open(f, "r", encoding="utf-8-sig") as fh: + cfg = json.load(fh) + except Exception as e: + print(f"[panel] 读取 runtime.local.json 失败({e}),沿用默认值") + return {} + + def _expand(v): + return os.path.expandvars(os.path.expanduser(v)) if isinstance(v, str) else v + + n = 0 + # ① 简单键 -> CONFIG 顶层 + for src_key, dst_key in (("conda_env", "conda_env"), + ("minicpm_demo_root", "minicpm_demo_dir")): + v = _expand(cfg.get(src_key)) + if v: + CONFIG[dst_key] = v + n += 1 + # ② 需要替换到命令行数组里的 + def _sub(proc, old_pred, new_val): + """把 procs[proc] 里满足 old_pred 的那一项换成 new_val。""" + arr = CONFIG["procs"].get(proc) + if not arr or not new_val: + return 0 + for i, x in enumerate(arr): + if isinstance(x, str) and old_pred(x): + arr[i] = new_val + return 1 + return 0 + + n += _sub("llama", lambda x: x.lower().endswith("llama-omni-server.exe") + or x.lower().endswith("llama-omni-server"), + _expand(cfg.get("llama_server"))) + n += _sub("llama", lambda x: x.lower().endswith(".gguf"), + _expand(cfg.get("llama_model"))) + n += _sub("harness", lambda x: "speech_paraformer" in x or "LocalASRmodel" in x, + _expand(cfg.get("asr_model"))) + print(f"[panel] 已读入 runtime.local.json(生效 {n} 项)") + return cfg + + +def _load_local_secrets(rt): + """眼镜 WiFi(Rokid 链路传给 APK)。同样来自 runtime.local.json, + 写死在 panel.py 里就等于明文密码进公开仓库。""" + out = {"glasses_ssid": "", "glasses_psk": ""} + g = (rt or {}).get("glasses") or {} + for k in ("glasses_ssid", "glasses_psk"): + v = g.get(k.replace("glasses_", "")) or (rt or {}).get(k) + if v: + out[k] = v + return out + + +_RTLOCAL = _load_runtime_local() +CONFIG["local"] = _load_local_secrets(_RTLOCAL) + + +def _ensure_certs(base_dir): + """确保 certs/cert.pem + key.pem 存在,没有就自签一对。 + + gateway(8006) 和 harness(8021) 都用这一对(gateway.py 的默认值就是 + certs/cert.pem,缺了会直接报错退出),所以四条链路都需要它。 + 自签证书**不绑机器**,里面没有硬件信息;客户端全是 CERT_NONE 不校验, + 只是为了让 wss 握手能过。所以本地生成一份即可,不必也不该提交进仓库。 + + 优先用 cryptography 库;没装就退回调 openssl;都不行就打出手动命令。 + """ + if not base_dir or not os.path.isdir(base_dir): + return False + d = os.path.join(base_dir, "certs") + cert = os.path.join(d, "cert.pem") + key = os.path.join(d, "key.pem") + if os.path.isfile(cert) and os.path.isfile(key): + return True + os.makedirs(d, exist_ok=True) + print(f"[panel] 未找到证书,正在生成自签证书 -> {d}") + + try: + from cryptography import x509 + from cryptography.x509.oid import NameOID + from cryptography.hazmat.primitives import hashes, serialization + from cryptography.hazmat.primitives.asymmetric import rsa + import datetime as _dt + + k = rsa.generate_private_key(public_exponent=65537, key_size=2048) + name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "localhost")]) + now = _dt.datetime.now(_dt.timezone.utc) + crt = (x509.CertificateBuilder() + .subject_name(name).issuer_name(name) + .public_key(k.public_key()) + .serial_number(x509.random_serial_number()) + .not_valid_before(now - _dt.timedelta(days=1)) + .not_valid_after(now + _dt.timedelta(days=3650)) + .add_extension(x509.SubjectAlternativeName([ + x509.DNSName("localhost"), + x509.IPAddress(__import__("ipaddress").IPv4Address("127.0.0.1")), + ]), critical=False) + .sign(k, hashes.SHA256())) + with open(key, "wb") as f: + f.write(k.private_bytes( + serialization.Encoding.PEM, + serialization.PrivateFormat.TraditionalOpenSSL, + serialization.NoEncryption())) + with open(cert, "wb") as f: + f.write(crt.public_bytes(serialization.Encoding.PEM)) + print("[panel] 证书已生成(cryptography,有效期 10 年)") + return True + except ImportError: + pass + except Exception as e: + print(f"[panel] cryptography 生成失败({e}),改试 openssl") + + try: + subprocess.run( + ["openssl", "req", "-x509", "-newkey", "rsa:2048", + "-keyout", key, "-out", cert, "-days", "3650", + "-nodes", "-subj", "/CN=localhost"], + check=True, capture_output=True, timeout=60) + print("[panel] 证书已生成(openssl,有效期 10 年)") + return True + except Exception as e: + print(f"[panel] !! 自动生成证书失败: {e}") + print(f"[panel] 请手动执行(在 {base_dir} 下):") + print("[panel] openssl req -x509 -newkey rsa:2048 " + "-keyout certs/key.pem -out certs/cert.pem " + "-days 3650 -nodes -subj \"/CN=localhost\"") + return False + + +_ensure_certs(CONFIG.get("minicpm_demo_dir") or CONFIG.get("cwd")) + + class ProcManager: """管理三个子进程:起停、状态轮询、日志收集、端口/就绪探测。""" @@ -294,6 +579,7 @@ def __init__(self, cfg): self.status = {n: "stopped" for n in cfg["procs"]} # stopped/starting/running/crashed self.current_prompt = next(iter(cfg["presets"].values())) self.current_device = (cfg.get("devices") or ["默认"])[0] + self.current_scene = cfg.get("default_scene", "严格判据") # —— 当前链路:esp32 / rokid,决定第四级起哪个进程 —— self.current_chain = cfg.get("default_chain", "esp32") self._lock = threading.Lock() @@ -341,9 +627,29 @@ def _build_cmd(self, name): if name == "demo": subst = {"{prompt}": self.current_prompt, "{device}": self.current_device} cmd = [subst.get(x, x) for x in cmd] - elif name == "rokid": + elif name == "harness": + # 证书用绝对路径:harness 的 cwd 是 OpenGlass 仓库根, + # 而证书由 _ensure_certs 生成在 minicpm_demo_dir/certs 下(gateway 共用)。 + _base = self.cfg.get("minicpm_demo_dir") or "." + subst = { + "{certfile}": os.path.join(_base, "certs", "cert.pem"), + "{keyfile}": os.path.join(_base, "certs", "key.pem"), + } + cmd = [subst.get(x, x) for x in cmd] + elif name == "demo_funnel": + # esp32_runtime:prompt + 设备参数(IP/端口/旋转) + 漏斗档位 subst = {"{prompt}": self.current_prompt} cmd = [subst.get(x, x) for x in cmd] + cmd += self._device_args() + cmd += self._funnel_extra_args() + elif name == "rokid": + _loc = self.cfg.get("local", {}) + subst = { + "{prompt}": self.current_prompt, + "{glasses_ssid}": _loc.get("glasses_ssid", ""), + "{glasses_psk}": _loc.get("glasses_psk", ""), + } + cmd = [subst.get(x, x) for x in cmd] cmd += self._rokid_extra_args() # 内联 ps1 的 --enable-funasr 分支 return self._wrap_conda(cmd) @@ -436,6 +742,110 @@ def _rokid_env(self): self._log("rokid", f"日志: {env['ROKID_V7_LOG_FILE']}") return env + def _device_args(self): + """从 devices.json 取当前眼镜的 IP / 端口 / 旋转角,填给 esp32_runtime。""" + d = (self.cfg.get("device_map") or {}).get(self.current_device) + if not d or not d.get("host"): + self._log("demo_funnel", + f"!! devices.json 里找不到「{self.current_device}」的 esp32_host") + return [] + args = ["--esp32-host", d["host"], "--esp32-port", str(d.get("port", 80))] + if d.get("rotate"): + args += ["--rotate", str(d["rotate"])] + return args + + def _funnel_extra_args(self): + """按链路的档位追加漏斗参数。 + + 0 语音控制 不加 → 走 no_funnel 分支,每轮取一帧直发 + 2 质量筛选 --funnel --no-reject → 选 best 但永远放行 + 3 完整防幻觉 --funnel --force-measure → 选 best + 拒绝 + 语音提示 + """ + lv = int(self.chain().get("funnel", 0)) + if lv <= 0: + return [] + scene = self.cfg["scenes"].get(self.current_scene, "medicine") + args = ["--funnel", "--scene", scene] + if lv == 2: + args += ["--no-reject"] + else: + args += ["--force-measure", "--reject-wav-dir", self._reject_wav_dir()] + return args + + def _check_deps(self): + """②③④ 启动前检查关键依赖,缺了就说清楚缺什么、怎么装。 + + 为什么值得单独查:paddleocr 装不上时,方向分类器会**静默回退**到 + 早期的简易判据,表现是画面明明是正的却一直报"画面好像反了"、 + 接着播报把帧间隔拉长又误报"晃动" —— 全程不报错,极难定位。 + 实测踩过:panel 在没装好 paddle 的环境里启动,一上来就全是 orient_flipped。 + """ + lv = int(self.chain().get("funnel", 0)) + need = [("aiohttp", "aiohttp"), ("numpy", "numpy"), + ("PIL", "Pillow"), ("sounddevice", "sounddevice")] + if self.chain().get("tail") == "demo_funnel": + need += [("fastapi", "fastapi"), ("uvicorn", "uvicorn"), + ("yaml", "PyYAML"), ("funasr", "funasr")] + if lv >= 2: + need += [("cv2", "opencv-python")] + if lv >= 3 or lv == 2: + need += [("paddle", "paddlepaddle"), ("paddleocr", "paddleocr")] + import importlib.util as _iu + missing = [pip for mod, pip in need if _iu.find_spec(mod) is None] + if missing: + tail = self.chain().get("tail") or "demo" + self._log(tail, "!! 缺少依赖: " + ", ".join(missing)) + self._log(tail, " 请在**启动 panel 的那个 conda 环境**里安装:") + self._log(tail, " pip install " + " ".join(missing)) + self._log(tail, " (完整清单见 extensions/requirements-phase-b.txt)") + return False + return True + + def _check_extensions(self): + """②③④ 需要 OpenGlass 仓库内的 extensions/ 包完整。 + + 不需要复制到别处 —— _spawn 把 cwd 设成 OpenGlass 仓库根。 + 缺文件时子进程会起来立刻死、日志里一行 No module named extensions, + 面板上只看到灯变红,所以提前拦住并说清楚。 + """ + if self.chain().get("tail") != "demo_funnel": + return True + f = os.path.join(self._repo_root(), "extensions", "assistive_harness", + "phase_b", "esp32_runtime.py") + if not os.path.isfile(f): + self._log("demo_funnel", + f"!! 未找到 {f}\n" + f" ②③④ 需要仓库内的 extensions/ 包,请确认它没有被删除或移动。") + return False + return True + + def _repo_root(self): + """OpenGlass 仓库根(panel.py 在 runtime/openglass_omni/ 下,往上三级)。""" + return os.path.dirname(os.path.dirname( + os.path.dirname(os.path.abspath(__file__)))) + + def _reject_wav_dir(self): + d = self.cfg.get("reject_wav_dir", + "extensions/assistive_harness/phase_b/assets/reject_wav") + return d if os.path.isabs(d) else os.path.join(self._repo_root(), d) + + def _check_reject_wav(self): + """档位④要播提示音,wav 必须事先用 gen_reject_wavs.py 生成好 + (且要在 duplex 没跑的时候生成)。这里只检查,不在面板里现场生成。""" + if int(self.chain().get("funnel", 0)) < 3: + return True + full = self._reject_wav_dir() + try: + n = len([x for x in os.listdir(full) if x.lower().endswith(".wav")]) + except Exception: + n = 0 + if n == 0: + self._log("demo_funnel", + f"!! {full} 里没有 wav。档位④要播提示音," + f"请先在 duplex 未运行时跑 gen_reject_wavs.py 生成。") + return False + return True + def _rokid_extra_args(self): """按配置追加参数(对应 ps1 里的 $bridgeArgs += ...)。""" extra = [] @@ -524,7 +934,18 @@ def _spawn(self, name): creationflags = subprocess.CREATE_NEW_PROCESS_GROUP # worker / gateway 是上游 MiniCPM-o-Demo 的文件(worker.py / gateway.py), # 必须在那个目录下启动才能找到。llama / demo / rokid 用的是绝对路径,不依赖 cwd。 - if name in ("worker", "gateway"): + # harness / demo_funnel 用 `python -m extensions...` 启动, + # **cwd 必须是 OpenGlass 仓库根** —— extensions/ 就在它下面。 + # ★ 不要用 PYTHONPATH 代替:`-m` 时 sys.path[0] 是 cwd,cwd 优先于 + # PYTHONPATH。如果 cwd 设成 MiniCPM-o-Demo 而那边**也有**一份 + # extensions/,OpenGlass 这份会被完全遮蔽(改了不生效); + # 更糟的是 PYTHONPATH 把 OpenGlass 根塞进 sys.path,实测导致 + # paddle 导入失败(partially initialized module 'paddle' ... + # circular import)→ 方向分类器加载失败 → 回退到错误的早期 CV 判据 + # → 第一轮就误报 orient_flipped,然后播报拉长帧间隔又误报 severe_shake。 + if name in ("harness", "demo_funnel"): + _cwd = self._repo_root() + elif name in ("worker", "gateway"): _cwd = self.cfg.get("minicpm_demo_dir") or self.cfg.get("cwd") or None if not _cwd: self._log(name, "!! 未配置 minicpm_demo_dir(MiniCPM-o-Demo 目录)," @@ -676,6 +1097,21 @@ def _wait_ready_or_die(self, name, timeout): self._log(name, "就绪(关键字命中),放行") return True elapsed = time.time() - t_start + if name == "harness": + # 8021 是自签 wss,不能用 HTTP health,只能探 TCP 端口。 + # 而且端口开了之后 /ws/control 还要一小会儿才绑好, + # 不等的话 esp32_runtime 连过去会失败。 + if self._port_open(8021): + self._log("harness", "8021 端口已开,再等 2s 让 /ws/control 绑好") + time.sleep(2.0) + self._log("harness", "harness 就绪,放行") + return True + _now = time.time() + if _now - last_log > 5: + last_log = _now + self._log("harness", f"等待 8021 (FunASR 模型加载中) {elapsed:.0f}s") + time.sleep(1.0) + continue if name == "llama": # llama-omni-server:轮询 /health 返回 200 才放行(= 你手动的 curl .../health) if self._http_ok(llama_url): @@ -775,6 +1211,11 @@ def _other_tails(self): return [c["tail"] for k, c in self.cfg["chains"].items() if c["tail"] != cur] def _do_start_all(self): + # ②③④ 的两个前置检查:extensions 复制了没、档位④的 wav 有没有。 + # 提前拦住比跑起来才发现好 —— 后者时 duplex 已在跑,没法当场补。 + if (not self._check_extensions() or not self._check_deps() + or not self._check_reject_wav()): + return """按序补齐:只起没在跑的,已在跑的跳过;被急停立即停下。""" # 切链后若另一条链的尾巴还活着,先杀掉——两个客户端同时占一个 gateway # 会互相抢 session,必须互斥。 @@ -940,24 +1381,34 @@ def get_config(self): "need_device": c["need_device"], "fpv_url": self.cfg.get(c["fpv_key"], ""), "procs": c["start_order"], + # 只有开了漏斗的链路(③④)才需要选判据档位;①②选了也不起作用 + "need_scene": int(c.get("funnel", 0)) > 0, } return { "presets": self.cfg["presets"], "fpv_url": self.cfg["fpv_url"], "devices": self.cfg.get("devices", []), "chains": chains, + "scenes": list(self.cfg.get("scenes", {}).keys()), + "default_scene": self.cfg.get("default_scene", ""), + "proc_labels": self.cfg.get("proc_labels", {}), "default_chain": self.cfg.get("default_chain", "esp32"), } def set_chain(self, chain): return self.mgr.set_chain(chain) + def set_scene(self, scene): + if scene: + self.mgr.current_scene = scene + return "ok" + def set_device(self, device): if device: self.mgr.current_device = device return "ok" - def start_all(self, prompt=None, device=None, chain=None): + def start_all(self, prompt=None, device=None, chain=None, scene=None): # prompt 来自前端文本框(用户选的 preset 或编辑后的内容)。在起进程前更新 # current_prompt,否则一键启动只会用初始的第一个 preset。 if prompt: @@ -966,6 +1417,8 @@ def start_all(self, prompt=None, device=None, chain=None): self.mgr.set_chain(chain) if device: self.mgr.current_device = device + if scene: + self.mgr.current_scene = scene self.mgr.start_all(); return "ok" def stop_all(self): diff --git a/runtime/openglass_omni/runtime.example.json b/runtime/openglass_omni/runtime.example.json index f3c77a1..c69bde1 100644 --- a/runtime/openglass_omni/runtime.example.json +++ b/runtime/openglass_omni/runtime.example.json @@ -1,33 +1,28 @@ { - "_comment": "Copy to runtime.local.json. Paths are resolved relative to this file and may use environment variables.", - "python": "", - "minicpm_demo_root": "${MINICPM_O_DEMO_ROOT}", - "llama_cpp_omni_root": "${LLAMA_CPP_OMNI_ROOT}", - "devices_file": "devices.local.json", - "prompts_file": "prompts.json", - "state_dir": "state", - "worker": { - "host": "127.0.0.1", - "port": 22440, - "ready_timeout_s": 180 + "_comment": "复制为 runtime.local.json 后填写。该文件不进仓库(加进 .gitignore)。路径支持 ${ENV_VAR} 和 ~。", + + "_conda": "留空表示已在外部 conda activate;填环境名则由 panel 用 conda run 启动子进程", + "conda_env": null, + + "_paths": "三个仓库相互独立,各自填自己的绝对路径", + "minicpm_demo_root": "D:\\path\\to\\MiniCPM-o-Demo", + "llama_server": "D:\\path\\to\\llama.cpp-omni\\build\\bin\\Release\\llama-omni-server.exe", + "llama_model": "D:\\path\\to\\MiniCPM-o-gguf\\MiniCPM-o-4_5-Q4_K_M.gguf", + + "_asr": "②③④ 链路的语音控制(8021 harness)用的 FunASR 流式模型目录", + "asr_model": "D:\\path\\to\\LocalASRmodel\\speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", + + "_glasses": "Rokid 链路要把 WiFi 传给 APK。不要把真实密码提交进仓库", + "glasses": { + "ssid": "YOUR_WIFI_SSID", + "psk": "YOUR_WIFI_PASSWORD" }, - "gateway": { - "host": "127.0.0.1", - "bind_host": "0.0.0.0", - "port": 8040, - "tls": true, - "certfile": "certs/cert.pem", - "keyfile": "certs/key.pem", - "ready_timeout_s": 45 - }, - "demo": { - "ui_host": "127.0.0.1", - "ui_port": 8080, - "audio_endpoint": "/ws_audio", - "image_min_interval_s": 0.8, - "player_hostapi": "wasapi", - "player_prebuffer_ms": 200, - "connect_wait_s": 120, - "ready_timeout_s": 20 - } + + "_ports": "以下为当前 V2 链路的实际端口,仅供参考;panel.py 里已按此配置,改动需同步改 panel", + "worker": { "host": "127.0.0.1", "port": 22400 }, + "gateway": { "host": "127.0.0.1", "port": 8006, "tls": true, + "certfile": "certs/cert.pem", "keyfile": "certs/key.pem" }, + "llama": { "host": "127.0.0.1", "port": 22500 }, + "harness": { "host": "127.0.0.1", "port": 8021 }, + "demo": { "ui_port": 8080 } } From 5a6b59df29fdb7ed18736b03db011fb8895feeb8 Mon Sep 17 00:00:00 2001 From: MajestyHenius <3051797499@qq.com> Date: Fri, 4 Sep 2026 11:11:09 +0800 Subject: [PATCH 3/3] fix: address PR review - README: correct requirements-phase-b.txt path (both languages) and the MiniCPM-o-Demo clone branch (master -> main); llama.cpp-omni stays on master - panel: restart the tail process when the chain configuration changes. Chains 2/3/4 share the demo_funnel process name, so neither the cross-chain kill nor the alive check would restart it and the previous funnel arguments stayed in effect. Now keyed on a (chain, funnel level, criteria, device, prompt) fingerprint, which also covers device/criteria changes within a chain. - bridge_ui: default to loopback instead of 0.0.0.0. Binds both 127.0.0.1 and ::1 so the panel's embedded http://localhost:8080 view keeps working on hosts that resolve localhost to IPv6. Non-loopback binds now log what they expose. - esp32_runtime: pass stop_callback to WebUIServer so POST /api/stop actually stops the runtime and finalizes the session; add --web-ui-host - esp32_runtime: the reject hint records gate.stop_count before pausing and only resumes if it still owns the pause, so a user STOP during the hint is no longer overridden --- README.md | 68 ++++--------------- README_zh.md | 9 +-- .../assistive_harness/phase_b/bridge_ui.py | 35 ++++++++-- .../phase_b/esp32_runtime.py | 48 ++++++++++++- runtime/openglass_omni/panel.py | 44 +++++++++++- 5 files changed, 138 insertions(+), 66 deletions(-) diff --git a/README.md b/README.md index 24f2bde..2bf698a 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Solid arrows represent code or artifacts present in the public repository. Dashe The control panel is intended to make **repeated runs** one-click after a one-time setup. It does not download model weights, clone upstream repositories, compile `llama.cpp-omni`, or flash the ESP32 for you. -> **Current clean-clone status:** The panel itself starts directly from the repository root, but the full chain still needs four out-of-repo assets prepared by hand: the `llama.cpp-omni` build, MiniCPM-o GGUF weights, the FunASR model, and the Wi-Fi credentials inside the ESP32 firmware. None of these live in this repository, and none can be fetched automatically. +> **Current clean-clone status:** The panel UI starts from the repository root, but the current launcher still reads machine-specific paths from `runtime/openglass_omni/panel.py`. The included `runtime.local.json` loader is not yet connected to that panel. Follow the effective configuration locations below; a code update is still required before this can be called a portable one-click installation. ### 1. Prerequisites @@ -120,7 +120,7 @@ cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON -DLLAMA_CURL=OFF cmake --build build --config Release --target llama-omni-server -j cd .. -git clone --branch master https://github.com/OpenBMB/MiniCPM-o-Demo.git +git clone --branch main https://github.com/OpenBMB/MiniCPM-o-Demo.git cd MiniCPM-o-Demo python -m pip install -r requirements.txt cd .. @@ -129,7 +129,7 @@ git clone https://github.com/OpenSQZ/OpenGlass.git cd OpenGlass python -m pip install -r runtime/openglass_omni/requirements.txt -python -m pip install -r extensions/requirements-phase-b.txt # voice control + CV funnel (harness chains only; skip if you just run basic chat) +python -m pip install -r extensions/assistive_harness/phase_b/requirements-phase-b.txt # voice control + CV funnel (harness chains only; skip if you just run basic chat) ``` @@ -180,32 +180,17 @@ Edit `runtime/openglass_omni/devices.json`: ### 5. Configure the current launcher -Copy [`runtime.example.json`](runtime/openglass_omni/runtime.example.json) to -`runtime.local.json` in the same directory and fill in your machine paths. The panel reads -it at startup and uses those values instead of the defaults in `panel.py`: +At present, these are the **effective** settings: -```json -{ - "conda_env": null, - "minicpm_demo_root": "D:\\path\\to\\MiniCPM-o-Demo", - "llama_server": "D:\\path\\to\\llama.cpp-omni\\build\\bin\\Release\\llama-omni-server.exe", - "llama_model": "D:\\path\\to\\MiniCPM-o-gguf\\MiniCPM-o-4_5-Q4_K_M.gguf", - "asr_model": "D:\\path\\to\\LocalASRmodel\\speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online", - "glasses": { "ssid": "YOUR_WIFI", "psk": "YOUR_WIFI_PASSWORD" } -} -``` - -| What to configure | Location | Value | +| What to configure | Effective location now | Value | | --- | --- | --- | -| MiniCPM-o-Demo checkout | `minicpm_demo_root` | Absolute path containing upstream `worker.py` / `gateway.py` | -| `llama-omni-server` binary | `llama_server` | Compiled executable under `llama.cpp-omni/build` | -| Main GGUF model | `llama_model` | Absolute path to the main MiniCPM-o 4.5 GGUF | -| ASR model | `asr_model` | FunASR streaming model directory, used by voice control in chains 2-4 | -| Glasses Wi-Fi | `glasses.ssid` / `glasses.psk` | Passed to the Rokid APK at launch; leave empty and only that chain loses glasses connectivity | +| MiniCPM-o-Demo checkout | [`panel.py` `CONFIG["minicpm_demo_dir"]`](runtime/openglass_omni/panel.py) | Absolute path containing upstream `worker.py` and `gateway.py` | +| `llama-omni-server` binary | [`panel.py` `CONFIG["procs"]["llama"]`](runtime/openglass_omni/panel.py) | Compiled executable under `llama.cpp-omni/build` | +| Main GGUF model | Same `llama` command after `-m` | Absolute path to the main MiniCPM-o 4.5 GGUF | | Glasses name/IP/rotation | `runtime/openglass_omni/devices.json` | One entry per ESP32 glasses prototype | -| Prompt presets | [`panel.py` `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | Interaction prompts shown by the panel | +| Prompt presets | [`panel.py` `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | Interaction prompts shown by the current panel | -The panel self-signs a TLS certificate and key pair under `/certs/` on first launch, used by the `wss` connections to the gateway (8006) and the voice-control harness (8021). An existing pair is left untouched. +[`runtime.example.json`](runtime/openglass_omni/runtime.example.json) and [`prompts.json`](runtime/openglass_omni/prompts.json) document the intended local configuration boundary, but the current panel does not consume either file. Copying the runtime example to `runtime.local.json` does **not yet replace** the hardcoded panel paths or prompt presets. This is a known integration issue, not a user configuration mistake. ### 6. Configure and flash Wi-Fi firmware @@ -221,39 +206,16 @@ Activate the same Python environment used for MiniCPM-o-Demo, then run from the python glasses_panel.py ``` -Pick a **chain**, a **device** (and a **criteria** preset for chains 3-4) at the top, -then click **Start**. - -Five chains are available. The four ESP32 ones are cumulative — each adds exactly one -thing to the previous: - -| Chain | Function | Processes started | -| --- | --- | --- | -| 1 Basic chat | Full-duplex omni-modal conversation with the local model through the glasses | llama -> worker -> gateway -> esp32_bridge | -| 2 Voice control | Understands "stop", "start over", "find X" | llama -> worker -> gateway -> harness -> esp32_bridge | -| 3 Frame selection | Picks the sharpest of several frames per second | same as 2 | -| 4 Full anti-hallucination | Rejects bad frames with a spoken hint, so the model never sees them | same as 2 | -| Rokid | Reverse link: the PC listens on 18080 for the APK | llama -> worker -> gateway -> rokid | - -Chains 1-4 are **mutually exclusive**: each needs exclusive access to the glasses' audio -channel and image port, so only one can run at a time. +Select **ESP32 Glasses**, choose the device name, and click **Start**. The current panel attempts to start: ```text llama-omni-server :22500 -> worker :22400 -> gateway :8006 - -> harness :8021 (chains 2-4 only) - -> glasses client / first-person view :8080 + -> ESP32 bridge / local view :8080 ``` -The **criteria** selector (chains 3-4 only) picks which calibration the funnel uses: - -- **Strict** — safety-relevant scenes, such as reading a medicine box or a street sign. This preset rejects low-quality frames aggressively to keep the model from hallucinating. -- **Everyday** — ordinary day-to-day scenes. - -The chain is ready only when all process indicators are green and the first-person view is -updating. A successful UI launch alone does not prove the model, audio, image, and -response path is complete. +The chain is ready only when all four process indicators are green and the first-person view is updating. A successful UI launch alone does not prove the model, audio, image, and response path is complete. ### Panel lifecycle @@ -299,8 +261,8 @@ Upstream model projects and model weights remain external dependencies and are n ## Known Limitations -- Task injection on skill switch has no effect over the current `/v1/realtime` protocol (there is no equivalent field); the model relies on the system prompt instead. -- Basic chat and the harness chains each carry their own first-person-view frontend and recorder, so the tree contains two same-named copies. They do not interfere, but the duplication is easy to misread. +- A clean-machine end-to-end Omni run has not yet been verified from the current public tree. +- The current panel still contains machine-specific runtime paths instead of consuming `runtime.local.json`. - Prompt presets are still embedded in `panel.py`; the standalone `prompts.json` file is not yet connected. - ESP32 Wi-Fi credentials still require editing the tracked `.ino`; the local header template is not wired in yet. - Normal panel close performs cleanup, but abnormal termination can leave child or externally started processes running. diff --git a/README_zh.md b/README_zh.md index 71d658b..ba13d70 100644 --- a/README_zh.md +++ b/README_zh.md @@ -92,7 +92,7 @@ flowchart LR 控制面板的目标是:完成一次性环境准备后,后续实验可以一键重复启动。它不会替用户下载模型权重、clone 上游仓库、编译 `llama.cpp-omni` 或烧录 ESP32。 -> **当前全新 clone 状态:** 面板本身可以从仓库根目录直接启动,但整套链路仍需手动准备四样仓库外的资源:`llama.cpp-omni` 编译结果、MiniCPM-o GGUF 权重、FunASR 模型、以及 ESP32 固件里的 Wi-Fi 凭据。这几项都不在本仓库内,需按以下说明安装。 +> **当前全新 clone 状态:** 从仓库根目录启动面板 UI,本机路径写在 `runtime.local.json`(复制 `runtime.example.json` 得到),面板启动时读取。眼镜列表和旋转角在 `devices.json`。TLS 证书首次启动自动生成。仍需手动准备的是仓库外的资源:`llama.cpp-omni` 编译结果、MiniCPM-o GGUF 权重、FunASR 模型,以及 ESP32 固件里的 Wi-Fi 凭据。 ### 1. 前置条件 @@ -120,7 +120,7 @@ cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON -DLLAMA_CURL=OFF cmake --build build --config Release --target llama-omni-server -j cd .. -git clone --branch master https://github.com/OpenBMB/MiniCPM-o-Demo.git +git clone --branch main https://github.com/OpenBMB/MiniCPM-o-Demo.git cd MiniCPM-o-Demo python -m pip install -r requirements.txt cd .. @@ -129,7 +129,7 @@ git clone https://github.com/OpenSQZ/OpenGlass.git cd OpenGlass python -m pip install -r runtime/openglass_omni/requirements.txt -python -m pip install -r extensions/requirements-phase-b.txt # 语音控制 + CV 漏斗(harness链路需要,只跑基础对话无需安装) +python -m pip install -r extensions/assistive_harness/phase_b/requirements-phase-b.txt # 语音控制 + CV 漏斗(harness链路需要,只跑基础对话无需安装) ``` @@ -207,7 +207,8 @@ Copy-Item examples/configs/devices.example.json runtime/openglass_omni/devices.j | 眼镜名称/IP/旋转角 | `runtime/openglass_omni/devices.json` | 每副 ESP32 眼镜一条记录 | | Prompt 预设 | [`panel.py` 的 `CONFIG["presets"]`](runtime/openglass_omni/panel.py) | 面板中显示的交互 Prompt | -> 面板首次启动时会在 `/certs/` 下自签一对 TLS 证书,供 gateway(8006)和语音控制 harness(8021)的 `wss` 连接使用。 +**TLS 证书不用手动准备。** 面板首次启动时会在 `/certs/` 下自签一对 +(gateway 8006 和 harness 8021 共用),已存在则不覆盖。 ### 6. 配置并烧录 Wi-Fi 固件 diff --git a/extensions/assistive_harness/phase_b/bridge_ui.py b/extensions/assistive_harness/phase_b/bridge_ui.py index c3940f8..a65ed15 100644 --- a/extensions/assistive_harness/phase_b/bridge_ui.py +++ b/extensions/assistive_harness/phase_b/bridge_ui.py @@ -52,7 +52,10 @@ def _load_template(name: str) -> str: # ============================================================ class WebUIServer: - def __init__(self, port: int = 8080, host: str = "0.0.0.0", + # 默认只绑回环:这个服务把第一视角画面、session 元数据、原始 user/AI wav + # 全部无认证地暴露出去。绑 0.0.0.0 等于把它们放给整个局域网, + # 要那样必须由调用方显式指定 host。 + def __init__(self, port: int = 8080, host: str = "127.0.0.1", sessions_root: Path = Path("./sessions"), stop_callback: Optional[Callable[[], None]] = None, mode_info: Optional[dict] = None): @@ -85,9 +88,28 @@ async def start(self) -> None: app.router.add_post('/api/stop', self._h_stop) self._runner = web.AppRunner(app) await self._runner.setup() - site = web.TCPSite(self._runner, self.host, self.port) - await site.start() - LOGGER.info("[UI] http://%s:%d (live + replay)", self.host, self.port) + # 回环默认同时绑 IPv4 和 IPv6。 + # 只绑 "127.0.0.1" 的话是**纯 IPv4**,而 Windows 上浏览器把 + # `localhost` 优先解析成 ::1 的情况很常见 —— 那时 panel 内嵌的 + # http://localhost:8080 会连不上(表现就是第一视角一片空白)。 + # 绑成 ["127.0.0.1", "::1"] 两边都覆盖,又不暴露到局域网。 + _hosts = self.host + if self.host in ("127.0.0.1", "localhost", "::1"): + _hosts = ["127.0.0.1", "::1"] + try: + site = web.TCPSite(self._runner, _hosts, self.port) + await site.start() + except OSError as e: + # 系统没开 IPv6 之类:退回单地址,别让整个第一视角起不来 + LOGGER.warning("[UI] 绑定 %s 失败(%s),退回 %s", _hosts, e, self.host) + site = web.TCPSite(self._runner, self.host, self.port) + await site.start() + LOGGER.info("[UI] http://localhost:%d (live + replay) bind=%s", + self.port, _hosts) + if self.host not in ("127.0.0.1", "localhost", "::1"): + LOGGER.warning( + "[UI] !! 绑定在 %s —— 第一视角画面、session 元数据、" + "原始 user/AI 录音将无认证地暴露给局域网内任何人。", self.host) async def stop(self) -> None: for ws in list(self.live_clients): @@ -293,7 +315,10 @@ def _main() -> None: description="Bridge UI — standalone replay server (no ESP32 / no model)" ) parser.add_argument("--port", type=int, default=8080) - parser.add_argument("--host", default="0.0.0.0") + parser.add_argument("--host", default="127.0.0.1", + help="绑定地址。默认只绑回环 —— 本服务无认证地提供" + "第一视角画面、session 元数据和原始 user/AI wav," + "填 0.0.0.0 会把这些暴露给整个局域网") parser.add_argument("--sessions", default="./sessions", help="sessions 根目录(默认 ./sessions)") args = parser.parse_args() diff --git a/extensions/assistive_harness/phase_b/esp32_runtime.py b/extensions/assistive_harness/phase_b/esp32_runtime.py index d343a9c..285eec2 100644 --- a/extensions/assistive_harness/phase_b/esp32_runtime.py +++ b/extensions/assistive_harness/phase_b/esp32_runtime.py @@ -1049,6 +1049,15 @@ async def _do_reject_interrupt_inner(reason): if wav_pcm is None: LOG.warning("[强制措施] 无 %s.wav,跳过播报", reason) return + # 记下发 stop 时的 stop_count,作为"这次暂停归我"的凭据。 + # 漏斗的 stop 意思是"先别说,我要插播提示", + # 用户的 stop 意思是"闭嘴,我不想听" —— 两者走同一条 8021 + # 控制腿,无从区分。播报期间用户若说"停一下", + # gate.stop() 会让 stop_count 再 +1;此时若还无条件 resume, + # 就把用户的停止状态覆盖掉了。 + # (播报改成后台任务之后,这个并发窗口更大了。) + _gate = getattr(manager, "gate", None) + _owned = getattr(_gate, "stop_count", None) if _gate else None try: await harness.send({"type": "funnel.stop", "reason": reason}) LOG.info("[强制措施] funnel.stop 已发 (%s)", reason) @@ -1065,6 +1074,14 @@ async def _do_reject_interrupt_inner(reason): await asyncio.sleep(dur + 0.2) except Exception as e: LOG.warning("[强制措施] 播 wav 失败: %s", e) + # 只有"这次暂停仍归我"才 resume。stop_count 变了说明期间 + # 有新的 stop 进来(用户按的),此时保持停止状态不动。 + _now_cnt = getattr(_gate, "stop_count", None) if _gate else None + if _owned is not None and _now_cnt is not None and _now_cnt != _owned: + LOG.info("[强制措施] 播报期间收到新的 STOP" + "(stop_count %s→%s),保留用户的停止状态,不 resume", + _owned, _now_cnt) + return try: await harness.send({"type": "funnel.resume", "reason": "hint_done"}) LOG.info("[强制措施] funnel.resume 已发(提示播完)") @@ -1346,7 +1363,7 @@ def __init__(self, config, esp32_host, esp32_port, image_tcp_port, gateway_host="127.0.0.1", gateway_port=8040, reject_wav_dir="assets/reject_wav", live_record_dir=None, rerun_from=None, - funnel_rerun_from=None, web_ui_port=None, + funnel_rerun_from=None, web_ui_port=None, web_ui_host="127.0.0.1", record_no_media: bool = False, rerun_tail_wait_s: float = 30.0, no_reject: bool = False, @@ -1395,8 +1412,12 @@ def __init__(self, config, esp32_host, esp32_port, image_tcp_port, try: self._web_ui = WebUIServer( port=web_ui_port, + host=web_ui_host, sessions_root=Path(live_record_dir).parent if live_record_dir else Path("live_sessions"), + # 接上运行时的停止事件:不接的话 POST /api/stop 会返回成功、 + # 前端按钮也变灰,但运行时根本没停,session 也不会收尾落盘。 + stop_callback=self._stop_evt.set, mode_info={"mode": "rerun" if (rerun_from or funnel_rerun_from) else "live"}, ) @@ -1531,6 +1552,26 @@ async def start(self) -> None: # oneDNN 编译(~2s,甚至 5s+)。不预热的话它会推迟到第一次 accept 才现场加载, # 卡住那一轮,且在此之前链路出不了 send(模型长时间拿不到图)。 if self._funnel is not None: + # ★ 先在**主线程**里把 paddle/paddleocr 导进来。 + # cam_pipeline_v2 的 `from paddleocr import ...` 是懒加载、写在函数体里, + # 而 warmup_orient 走 asyncio.to_thread(工作线程)—— paddle 这类 + # 带大量 C 扩展和内部循环依赖的包,在非主线程首次导入时会撞上 + # "partially initialized module 'paddle' has no attribute 'tensor' + # (most likely due to a circular import)", + # 然后 _ORI_CLS_TRIED 永久置位、整个进程退回错误的早期 CV 判据, + # 表现就是第一轮就误报 orient_flipped(实测 panel 启动必现)。 + # 在主线程预导一次,后面线程里再 import 就是拿缓存,不会再触发。 + try: + # ★ 只导这一个符号,**不要 `import paddleocr` 或 `import paddle`**。 + # `import paddleocr` 会走 paddlex.inference.utils.official_models + # → import modelscope → modelscope.utils.logger → import torch, + # 而这个环境里 torch 的 shm.dll 加载失败(WinError 127), + # 于是整条链断掉、方向分类器退回错误的早期 CV 判据。 + # 窄导入不经过那一支,实测可用(cam_pipeline_v2 里也是这么写的)。 + from paddleocr import DocImgOrientationClassification # noqa: F401 + LOG.info("[预热] paddleocr 方向分类器已在主线程预导入") + except Exception as e: + LOG.warning("[预热] 方向分类器预导入失败(可能退回轻量判据): %s", e) try: ms = await asyncio.to_thread(self._funnel.warmup_orient) # 必须查真实状态:这行原来无条件打"就绪",而加载失败时 @@ -1770,6 +1811,10 @@ def parse_args() -> argparse.Namespace: p.add_argument("--web-ui-port", type=int, default=None, help="开 bridge_ui 第一视角(如 8080),live/rerun/funnel-rerun 都可看") # ── 强制措施(防幻觉):reject 时用模型音色念提示 + 停/恢复走 8021 ── + p.add_argument("--web-ui-host", default="127.0.0.1", + help="第一视角服务的绑定地址。默认只绑回环 —— 该服务无认证地提供" + "画面、session 元数据和原始 user/AI 录音;" + "要给局域网内别的设备看才填 0.0.0.0,风险自负") p.add_argument("--force-measure", action="store_true", help="开启强制措施:reject→停duplex→播预生成wav→恢复duplex") p.add_argument("--reject-wav-dir", default="assets/reject_wav", @@ -1874,6 +1919,7 @@ def main() -> None: rerun_from=args.rerun_from, funnel_rerun_from=args.funnel_rerun_from, web_ui_port=args.web_ui_port, + web_ui_host=args.web_ui_host, record_no_media=args.record_no_media, rerun_tail_wait_s=args.rerun_tail_wait_s, no_reject=args.no_reject, diff --git a/runtime/openglass_omni/panel.py b/runtime/openglass_omni/panel.py index d3bce4d..e16bcb6 100644 --- a/runtime/openglass_omni/panel.py +++ b/runtime/openglass_omni/panel.py @@ -580,6 +580,10 @@ def __init__(self, cfg): self.current_prompt = next(iter(cfg["presets"].values())) self.current_device = (cfg.get("devices") or ["默认"])[0] self.current_scene = cfg.get("default_scene", "严格判据") + # 尾进程是"为哪套配置"起的。②③④ 共用 demo_funnel 这一个进程名, + # 只看进程活着就跳过启动的话,切链路后新的漏斗参数永远不会生效 —— + # UI 显示④,实际还在跑②。所以记指纹,变了就重启。 + self._tail_started_for = {} # tail 进程名 -> 指纹 # —— 当前链路:esp32 / rokid,决定第四级起哪个进程 —— self.current_chain = cfg.get("default_chain", "esp32") self._lock = threading.Lock() @@ -980,6 +984,7 @@ def _spawn(self, name): return proc def _kill(self, name, graceful=False, grace_timeout=20): + self._forget_tail_fp(name) # 进程要没了,指纹一并作废 proc = self.procs.get(name) if not proc or proc.poll() is not None: self.status[name] = "stopped" @@ -1183,6 +1188,9 @@ def _start_one(self, name): self._spawn(name) if self._wait_ready_or_die(name, ready_timeout): self.status[name] = "running" + if name == self.tail(): + # 记下这次是按哪套配置起的,下次切链路时用来判断要不要重启 + self._tail_started_for[name] = self._tail_fingerprint() return True # 未就绪/退出/被急停:先把这次 spawn 的进程杀干净,绝不留残余 p = self.procs.get(name) @@ -1205,11 +1213,28 @@ def _start_one(self, name): return False return False + def _forget_tail_fp(self, name): + """进程不在了就清掉指纹,否则下次会误判成"配置没变、跳过启动"。""" + self._tail_started_for.pop(name, None) + def _other_tails(self): """除当前链路外,其它链路的第四级进程名。""" cur = self.tail() return [c["tail"] for k, c in self.cfg["chains"].items() if c["tail"] != cur] + def _tail_fingerprint(self): + """当前链路下,尾进程真正依赖的那几个量。 + + 任何一项变了,已在跑的尾进程就是按旧配置起的,必须重启: + chain 决定漏斗档位(--funnel / --no-reject / --force-measure) + scene 决定 --scene(严格/日常判据) + device 决定 --esp32-host / --esp32-port / --rotate + prompt 决定 --prompt + """ + c = self.chain() + return (self.current_chain, c.get("funnel", 0), self.current_scene, + self.current_device, self.current_prompt) + def _do_start_all(self): # ②③④ 的两个前置检查:extensions 复制了没、档位④的 wav 有没有。 # 提前拦住比跑起来才发现好 —— 后者时 duplex 已在跑,没法当场补。 @@ -1228,9 +1253,22 @@ def _do_start_all(self): if self._cancel.is_set(): return if self._alive(name): - self.status[name] = "running" - self._log(name, "已在运行,跳过启动") - continue + # 尾进程还要比配置指纹:同一个 demo_funnel 进程, + # ②③④ 传的参数完全不同,光看"活着"会漏掉重启。 + if name == self.tail(): + want = self._tail_fingerprint() + got = self._tail_started_for.get(name) + if got is not None and got != want: + self._log(name, "配置已变(链路/判据/眼镜/Prompt),重启该进程") + self._kill(name, graceful=True, grace_timeout=120) + else: + self.status[name] = "running" + self._log(name, "已在运行,跳过启动") + continue + else: + self.status[name] = "running" + self._log(name, "已在运行,跳过启动") + continue if not self._start_one(name): if self._cancel.is_set(): self._log(name, "!! 启动被急停中止")

=XkKoj7ze3z_4akQScvSj9jWj@1 zw+m^Z?ozwxb<9lkHXEAg$__o ztQC#I9_|yH!hU5dvNc1egPVd`!R{gSx==>&aBw)HTFnAu{NsFIy?eYHynVfLZ*}h_ z?_Hk_MBso>cXm3rpWiJsMGX2E+?R%+Wb5Gb*$6~IJH$}dz#fdh#b(?_wi?@=-O65J zhp`_*y+faa?SlUV&ie28ILzU%yv5#+UblCmZ;}6fpjK!iJBwS!uM?JFbZiGvavCMu zgP%IW0b(WGrFMX9VnKb4gu~-0Vj|fNL|Pf94YYC=d!OekP z{!hqGx5zik7v+=V`wIW_fHqW*ZNYWm#|tyWhKSz(myh;82i%`HdC-Gn8wF3=X<#Q- zgT5+<->-!myoY>7J)}d-6nTaMIXBc}k*jmJ;e_$0v8FLcUkZwN1kt^?*pEN z=iroNV=HrY`KCg1ur@Qn6P*X=at{2-Jn$Ifu$l}CEL@l}gnW>n$Hm5=T1LY0_5~?X z1DW$OJ=8{a^<&LU-DCZ7!*YXD|4i3fdqdq;6{XCVcarU=hf{mWoy0(RaV6n|xd8ca z9|%_A5b9EnHG&BDV2+!?$+)3dy-x*8Sua2Y3jKNh+x{>9<$)!^W1%bXogUBE5)3#S zEGJb5$r6UT3y9g`W|2YPnJpXwGx;yPiI1bCGsH+~Ek^WtM66s?eBu5po6Ng4+XQ16>2N1J?pd>@cZN1pJ#Hax?f!LMqN4j=@3rt$0toE*?Y; zM&Nz63q6E(_?jsEAq+((-7|t26m30Z(RL9!cz$Ox)8#HjWz`h8dR^BJ(QVK*)os{`s+?ZNuy2QmVcgL8u)f>EKJpw3rvO?Uw-W(sTE$sk@1<2~w$r1&0;RA#$X*H=Lk)vZ11W)r z0adUCN}7i!_hFY0PqY1Lb+udG#61cI_lxvVNFe)MaZ^kS`=xX;h4tjb{$gjj)#}OCmok zPVhbAOtCJ;U<&T_EZW~IED??hCxkx2cI-th=$Vg06+**;w*u1w7Xto3m0<7SlVG1v zZ*~=)dNqVALU)W_ADmU6icQ6{xJNhU2?M_bV^7O9LB#nqX3+cm5<&7Gp_=JWrY*%H;`dB z!1Emu!^MEm58bc8b4k6cTBBi|mR zxdHRyIq*i+;hr3TTi`5so9lRPIBbRITzK#V`2kFP4R2Z}AWFJM$YH(>2T))bPKQ8fC9baPDgO_+?xDDPXrh^Hs3?}axQ4VK< zVIUprgQs1C$j(Y~B(8PjVsOZ%$jkT~65QEiaf0wSUz_j3FXJ!px3QP<@M*$*%uJ^- zS8as1&p(K@T*8bMDK){mqq=lf;F=3#Bh&qL?BmKxy~IX!s(ygeG{pUBsUM5HfHlflWLN&h9B* zTL_|}1=e0=2rbClrdWgR!us_)JY}E3={}3<_#ex|R6$;WzvR#4iHZ%1d{M8+aL>RYcs^LgM9_EJ!40-WYo7x3+#XD`o$7(BE!gt9R1{SNm*+o`AH4`X z-oKzx+k+8mhF8A;W!E1y8ISec0QwDGmYKn%Fy&-xWIts_d1ZJwtd-vYJAVlJlg4sV zzE2j1Y!|n{%x8dX{UO~H|A9-tgS{2{66_bOgAC)}0?Pw`2F?c5!OCFZV}m1tpMpI@ zpK^*J}f0GX(GIt+iM-Nta9eQMQqJ&sMzQ?Y{L)M_SP`RMT&r^dC*VIxu z;N;yzCqxWagLO2(i6vS5g#3aT0xzgBzMG0$#c=qB>#=^mOjJic_kqaNuA-~a13}4u zMy7=f`Z4y*Pv{?X9{nE7{6^4^XX(r6-7`Q=m7$gNM`{&S6MW8kknINY8fFm@T zt1{`0xL2Hmr^o=YkJuk<(BI-l^xCK57cmb^D*_VmBK2ZM%)t8TDV}DJ!OlBHIatyp zP@lD=hFG6AK#xuaTWY~dkO2c-h<44!_hL|-|NZ0w8EeBU8cIDuYG1-CHVSPt7esXl zQ3)e!Gj=j=?5X;Ku7`$_N&-`Vi2j9q1udDW%wFahlaE{+j7%YuL(BG^xr``XJaY^g z4%Sd5;HF1l_q|=biutw!e~$Z&vvJ+IGvNMz;(HO-7r8d}Vouw_ALgI)*|>ILoWA5M z;u$;znby__55e8f5VwIze2iGoEX=M>5WCfgDPYrcaXlcm{g2TsP2^!s*&QsC9yP~; ziqFKFvMgBNrQk8&!J)ksc=xBcD;;?JVPNjhAd~%7@)`*Id-!ud+Ik+jg4~T*(`B$i zZ?S(Ac;RakpaAdx4Ak;1Fv#by&cA~8dVx>P zl|1-FHJs`bP_`<#*M^w$THzfUqP%5^D9nK>___Y~AA_Hea158}f3Hu(zljG=UJ9Qb zhWO8aukwLP&cRwd9s8U@yf=qD1!mCeHBg>DPyx&Vx4j0Mg`JpHw}ZxB4Hd*xkj{Nj z;@YU02)w)azbp$Muoq569)>s4d#v~iz*>93gokkFu&Kp6=VCRTh1!FwIGE;F|JxZ9 zqgDcV1&z;){y(PP0?w-Hdmlb|yYHPDI;6W1q(cD#1?dt51Q8IBknTphq@+QlLs5|K zkPf9|U}kQ2oP3`>_v`!r&H3CrH_kn0?X}n5d+oi~dLBqu2HLI&EmTH~b|$XOW8{&b z^;fv|O~kX`!T(2yH_n0HS(Je2z2g6L&=eY|10B@Fugii3Ars&8D4~dZMDpuNixDCd zrLT&!8bD{A;a`4(*zb|B`%(Bm1bcm-Q%&)01w??eh{Jq?I(`IMNsRhA)W;1xt|4aq z0c_wY;`9IS@f@WlTFiqsNF7;Fq6)C07U=i7APyY95V9<~A%40wqU1}V#0>864A(q~ zcC{UCZat1Im^YokO#LY|m_+n;26R#fbK`jlHU*mzaRCr5C8vwg{1P+AJ{@B!$JT<0mQ=n3Y?uh0Vh_>GFTNBBoF&=(Oc7R945 zu8@Jx%>PF|5v56>bwwdx9IsN)tNuWQCl9or4T)aCDxO2am(Zsh--G`HvSmPDKt1a6Yf*(nWEIwntAWB8cX^BBHLmy+*7E??a}ByW1G_&43*3iHmp!n{gOKzD zB2urS-X7!J_mC%saw-3_7Yg;8M47|+C439%{>6F!P$&VPen5J`!h(D~K{!X>mZ zVpRfuN9ylAn+)0A$30x(ZU)yPk@1kBw?{gh;-#~A07kwAe z-rN7_kFeSJad`0lCBC_jbFRX-JBRh7Gbqtnl=dog{utl7p&4SwR#-)G*k4&_uN?jt z$9vLRNGl*?MF`r<#r3lBAV)5KNop#Fl0@>45cJ?diC#ey|KOf?ptqa(65hnC+xX-k zXod9Z0H}#Dbrp269nTq|Qm{7_?tf-!v)c|NhcF z4$_wLzt_M*O^`nmt*Ri70_dYM@!kNvlV2uL9zU-67TS4+w)s!~@ffe3q3&Mg+gL6% zN)9*5NowddBqV1N%YFc<9^mz}e0$8nS;U4Duqx8$F|bE+XmN1=lahD_Nt{8(C{nlS zHck4SWd1klXVTh<-Gd}G|IVaM5uNAYIR|pM@l6m{AU#34p6PsTkZi>Nv_W(r;2?d4 z2#KV8dm!2(T4VEN0wp$Hkuf9vN3=%Tos6@|b;)}a<$upIt_ZRXT#v|0&nT7?#Uv;nQag1*v;-iGv^|BWfd(NhC((&Z%O z`%gYnMkG?VpiBqej?pHD_3VkM;iBI6{2SMzlPN>=dsl zzqGBB*ED`bv|_`33jJ@~D-WNf5~Qtw)?6OF50R5-mfV}P1u{|*?WJ1?Y5%2hUL}+b z`3jgVkRHEAemO}=%cG=a@~=Q@hKyC|c9kv*d6$`gIH7~|C{J1-;1Kc;9?yEnZ^s=A zKn9}8^0+GTz{&VtACEd1;;@uEFGBRQp!?^|XyuKD`Xkbr@~w}&v*ef1g6~KPt#~FSCa;NArfri*NPIhDv1x7C@VyfU z(T^j)4zr+*^n4X&2;Ox_uD)CAC2w>2pY%$;_9SSZ?|n=^9Au_P^J}riqM1 z%S3J>5$R(9@D0gGJ0sSZ?iK!@meYLz=>Ce+TNo$4N{l7LqMm$o#>F57w$^ClJ<9rBYUVl+A|ShiD>zS43vwjij}c{!iYM@{u!$ z)LuM@M@P<&;&lXfB-bIDAf5=3j94YHj{obKr)w+ieQ97_WaJ^1MS3bS=8`d**e2<> zSo}BOk@hsw{<)H0$HW>)X^4i2brBEOn}6iydpX4Oa^uL!x3f3-{>6JdyYYDro{2T4 zOF+CKat-nzUK6Q(AHF4X8*&YDrM!IqiTEnyw_ZH*^0h#IK{QKhkH`~;Y^3FrcBkUM zkZ-xT?R_&ooaye1Fg zJ-@{>k&wtidI=&IvAwj$0{DdZ%%mS7noHMpy1vr)^WmKwhQWD`_RfBGdOFEreJU z`6PW$(%y(Iq&@5ZdNQ)QNP1~;I#H^uc1!8fde_n%`2WG{F$6|j~L zQ{hReKPjh`U$BxmOL?I*#=gfs?1OB>jzL4LV!a1`!~(SX`}kh~7%(@{Cux8cQ5P$i zuMpd~A8U+d=`GlUT#o&blEC@NM)}IqgW-2fQx8yG>A#eV)EXdnTmr|QPi;jflsT#g zdzC}LE;oqIqn<0hFyn3rl#Y+ECbJjbO;FhmGzo`VkgT37HhR0V1^Q~Ed<&0rI@S%E zQSFewb^tp%Gk|X~jJ}U+fmN89p}bQ+WP->TYlMh{*XlsTXFgY4N>{cN<(G}L8T@cF zRgEIRXy$+oH3zFyYp6J|A-Y2^9l=CLL6dn{p*^H-p#GGN7OipW`1LN`Jp_UYfTrB zD5ZfWA;-lzba%Fu;*=M%Th$}t45m5V3>l-HnZrsgWw<(>{sVgp6_QEDZ23cpZ(7Gu0TXlL39%fj==%7@?t<;mTV`Uz4q=ZpS*p2CA0w5^TzCsVicLw(+Iq zL9z$CYNw?oN*P|EEaG5kg`ux9OlZLUOMjCZOdr*qP=+K!be?9L{3iJ`TTDYk|KHKa zVe!ZaLcYL0xifoRnL)8^2k=&&VMMf-RfzuaFhl9J@@Zu%P$`;8&8ae6U6qz1%5BY4 z>}UVY=TWS(4GGd)#?uBJ69Qfd|Zn(HRskjik6xUZ#)sVjO>+9dp> znM!-afbyLCK&>S-;$P4LGDbe3KIP9NKI><$FEa?bS->x3-o$zK1FoIg1W_*|xc2nX z1g)9HpGsbrD{EG;*OCvU-MX)smWg+2QoC1?;tTj+fw>TuAE@WSKwC|n$9zd$mIY-V z+mPBMF5*@)%|wQ3%e1BE%JZab?hkfx%*50&c!mA)cxEPhU1%!#jB%w;Y9{kgBc%=t zR^0)*QmlmLsqXh=cIqGgN2V|$;?MGH=t;?L%mB?@sdwTSH&drcej<)D6lbOndzZOw>Fw zO^?)xZ?Fu~77CV@E1B!_tHXVSTIR8I=SWFvi{+*ih<(6q;C_*-h?{h+nF*1_^bPah z!nin)qq)D5pU8bRWw=Yp&U6+#Q9Ub^2FhGxc@emcfg&R|qCaJI)MrwEI*)ZoHc&vXd5lSGGf3m740Svr?32X6Rf}4dDj+Mt?zI zqE`)Fwc7YN;d@gyb0zeavRW@Bzls{PKkI5s?UO$;3k`3QJ%sO=S^N^|M`5vM1baaC zBzkctbYo*yskLD;`#Ao4s+#Eu(?4`rscJP+&hSl|v5XYx=&!mpraKk^VtSN-WcrHY~jQ!6aj*k3|*B*|J@SrblbJ~lLt+2SeV zdt;5zfw*j`!haK}BcHa6VlIboQS&Vmlh;Chjb9pPr!vF)^&^Z$lU3qpG(B|vW7U)0 zEnTTh;hvZY{tT_~v-p;S1HuIdDow%p&=8Mx;#UIob+%9FH^bOsHogz+? zJ8~m6r<1!8Nl=Q;caST7=pBLw1ii zU#ZO~e6M&Rb)lvxy+n?s`fGaYCnvfHmFXDs8l$X>U8l54ZD$uST6vZ-i5kGqq5l#J zOZ~YfbY1x|xNS$sL1v$(nfy;;r@WhO$`gP1xVnxB%2Sdf2o584R=!JZ*ELLZPQEwo z<4wVUxXqH(REhnbY^=Y}%!-+rRooeMj{Jff!JdyDk~V9AiU|Ma0dltzU@|I8caiqe zUuihRWm%aFx{t7zUc&#QW=LnKFh3Z`M(ePq(oFuIUaDT?7BNO)tWcPhfz5W5Jxphd zC#A~VTIM$)puAu@sEetU5)HQFP1K*_b?Fc0A=Ofz%DA)><)0!)sCCBi@`6M~Zl!*n z@HX}n>(bf~Us*(7jp-EYr`|BvkatI2Y=6xxs+cgCvv4KF4J2=%# zzNUG=e53p>w5IEEo#}^^S^5}tUI*h*9=w&Jd{N3RoIu2to7u?7LMhtI^h7@M4)GL! zgsz}e0qcD^pi<3e7DpIt2Ol*emi>ZH(-8ph94?a6{_QOz;VoZKmnV{PDlen90k7Ygdo>>^{_DL~mW@wg?B4 z6Lf?1SL4HzU0Dq;Q4ItR2$RQ@Or;dxhAJhrWm<3;2@`A7AzCfq^G+yrv2Wi|`ieit z%~5-UL9PWii#{T+QlHYr6uZ2FZp8PY?g-PAVf00*uIy%8YHNx{p)hZySIU>=iA*g- zF3#lUar31SsgP7ao1nLd7pSoG3AIu)h?$Y9nHbJa&|g#A%gfcDxa~rQ@Jyw-Ka@6N zKYdy4^~k%>0z(0vCE7xDn6r6TY@V>)_*h8Artwjo33c)f-;bV{Y@V`lziFS*i{!yn z2lXYG?4nc!^_sW}*j@|OR?>Lv@?Vh0BU0cmDTCUf=_B8eYD)9LYHwlMU<5s)yp%ry z6Z95D1Ri3y(pBUg$`rO4HA(thDa>49f1;ktla$|qd^UyZOIN2#X}rh*c%59WuF@V? zD@Yoe<}B*VVnk}K57x?aro z)G(!l)*)ua0`xVVqLz|>Vt%A~v59<}D@orHUaAGP-MLQke04aJ6nls@l+yHFZ7%Pm zi$ssfrMOMV@62W^>2*x8M01H}2CH?Iy6il*r%*e|a<{l`;v8`^-H%(ZlmoYPU8W54 zvpiq<39a=BJpf283*~Y`9qflsQr6NYzCXW%x`w=&{ZbW9<`*e{QBRo#^m-{zsLH&T zKUP;E-fXY9O8J4WNtqHA#kPD?T2aerI`daj^WY8_6NRC1 z=98_|{>aC=E_aenP(Lsk$|&gvzAaM&Q{R%xQy|ywq^59%)t*w0T7TFX};NF_n$hN+II(AGtC$j2*)qR2oo!&;zB%!l&v<)X5Ec zHM4>)D3z5yRLUafY%D#7EyvVW)(X9-Ye45)r&L#3(8H)MN=v3MJ%H+?+`+8wA|m`& zFpZe^$nmWvy;MKo7Bioy*JZCbSIwq7(Wj||QVwzHZIyxS1ZJOl3W&MmFze1>TCjte z;%Z^BsKU{wn6B(yrlz_~8K68>|Dn3kIapqKAs+)L!(@5~FjOZ|-^<&9L)nvgfd2Xr zBJzu=7WN%<+h3V3kCz6k4E>P3MRQa^^=oN}cva2hE-)q4qG}_i1rT>;QyrB<>_d9rJ2Ww9r{T5MH--NWKyssr&C+)~)>eYqrJ$K1%^8iNQj7hOu>)GyVtz})N%52zy628XC-Wr?&= zF+snLxe4?o;9<8`CL;3;*mUfCro38IuBVJ=Zcz?;5^y2kDX-Pm^jT^k1q^W@X?~4p z(@k_qH6@Kv%Fq+h4hAq1Wd+0iTC8tep)wFRxsvXvX2=@kKm9>pz$jjw+9@xm`Y=yu zv)WYoLoGt@1lDkQEC{W^EIt!;_!(?%6eDBq^a3%EbAiuNfextyW$?u_S@c`wyfP4Z zXp@y|@){rs{(xA=DojW=DNT{T+lU#4HH*IxEmv1Ppwz)Ud<5MPGr9A?;xr=4`HZ?j zUakbd?cRr8Nk38llHSQF^&U#m4-&?JEvh2+F#+GT2WEm;A606BtMD}KRXZyZwG}uR zVaz@i%0RyYx~Q4nr%t1*(Y0X7#hESiM(T;$gZ2ZRb0FoXEzD5lKu!aK`x9k^T9Y|Q z4?x^X8S1WlQW*=hl2z1MM8De98`3t#NqWHn4Q&3u0WQIJ<&1|inm2hO7r--*oJtI#FfO%wA3jsNPFq{oQddwvN8eU|L%&S_vGIc8fMKz*rD2mHLqA=ASAS1G z)i6^3J-8&a;6=yz+OFC&kkri;;7{;NfHH1m@1ovcPz%vU_90JWxAYE~TO9=^RX=$+ zaW*kIJ~R40(k^yC(l>l3d@|A|A_s?sehIG*g+j*2#OTRLv^w27?P2XG-E>_G;C${d)Hlr0x7U}{&(r^*FJY); z7y z*O;^$`8n)WT1(egrzq=WjWjlOJdvFkhK$$G!=BKd;G#f(f5cb8AM|eaQeLO`qGyD+ zqQ7Y1ERfXd1sjIyMp{J@(Y}e>;y2Rz)KnmEo>qUP4zS08-nfgKz}@CuT1mG<-`4P_ zzKQ;TZU~Tt42B%N9!z}&bklUhbXmH++6Fk@Vg|ilH(qyA_d*xbRn@OBv^1464>R>N zt}`Z##mprw>nt5CpPK(dCJW(AwCE3LY3(%rFLoYHs{`a8#oKgJGskxmV2sry*_JTQt)(OPq1y|TKp)`G0vtWp__C?I-~5Q zx3H_hj&O}jvTL|sH9Mj6=h~HEPH3n7O;cM_MAKI@T2n$(hhNXF<+dQ>V-44kAH=ho zVVYb`6=V?91m0LB(?FBK?6NeoT(%aljkCYAAGgc);r1Ncep_k#G1~wzMy)jJ^gA@G zc_4+b6{rW&=v3jv(`fPN&9F7J-hals&NC=)P42(BHus>s4!P@ds^#)|f94$lByvA0RzpR&Rw`^A&+njOd*Dig= z(+qFMLDxfPF))W!ar|i4*xs4{HK^L#{25@|v-A<=P%0QdAAJ*U8!j4L6X@ox?Dps0 z${m*XIJazGi`g#6wr$$`jyT9*{W?udl_N%f(x zS&4iriOJxP@LzMsm{N3MWDV2=K2?l8NarFx6|21Taq2rnl&?gr`OoOGIqJvJ7+rgIHuT-SnrxcMoHgJ z^F7A{$G#fo&X)`9DJJcw89X$%jHvh1l`DWlcXsbP@ix`fWDq1>#uVpB*N9#C`W;D(m zn|V8t)k({S3|D+$ZoHwBR$|CoYNii&O}gj!X^z z5fTHucYwQgt}#z?pYid{yr$RWRTq$Lv2lesI)sxWG&Fvu(3&pZ&G{sBMbnq;Z$w8-u|VHrY%@ z{XK33a|u}TUtq6oh_X+toiIdeM!ey-k+b0g;ah?CKH9g)+tK%_uaf^SUn^hS^WJmG zyU`c+KL`3^rNH>W#^9px?g)eYX+CC76i9GjCOIlBmtTNUp|1Q|*`=PNj?yx75_w)< zv9-XUa*NgRO@U3elskirr^;M8z5+jsTg2)3&Bz6M#y8h=()zTgb?5X>g9mJb4}eeC z!rar+$6DXk+_uZQ!#c+H(Dt?chP{!!roE7DqqVoCwB@*UhpmI{hOrz_LSOMC`8!;k z(=i2*XlWWQrYlyyCOk!{K~<;|Ls=&vW}R_VUg4>9yJ{%M+R9%s2?`Nd*I zYx>yU(oxH~$}!AQ$1%py&N1IU)6O_sBD;N^)ouO(Jhz|f=jcXi@AFH*&9+xKnTW?7 z@sHvyqB)^E{@b3>o_6l5Ksv4MZs{(b+bx&MJ(8QsU6OafJ<7AxyUzF4|5Lya%nG#) zzl_|CeUu!O$`Br>a)hJOZ*n&9u8tv_urKo|Gmh!ajppuS1Ubab=eDr}*xGC{ph8?h zj?^AzHu8ZQ;j_|gW7fqj=f?4S_}1Doy4yhEZ4MOPHOAje6;P&j)=#X9te@G6+g*-3 zj-^h!6G{Be;m+31QI4~YCyq^yIrd`UyNnv289M6kYNm4M=w?)V`Ht`^@lU*5Y)hni zXnNpxUu*Av<}n_rG~Xa|`AT$UT(XDYsbOr|y_L|XW)7}>r>y(HMWtiUX0 z;y`Gq%`N3tfc^Ggt`r~V3uv2Q#4n?N04}9g#xbVj=8l&3mYC&F%X;g4TSNP0N5C=M zS#gda!FL>t7* zB)(2%3oE3~@+zgA+5?%?3VnrH2)w0_;q{H-K0y{%HQ>l(!vmaxJWrbYoW05v1-@QQ z;OKqFTDg-z>~y1)h5725fJV_y*WJ=>)qiDpZ#-rSp?yUxZ>(S2Qug7FMotHMziX~j zu9g`!Gj6#CyCTm1&OaSV`z_lfOTySqKU*7wcRZMyt4tS%B~QdQMA)!5;PvZ$zkB{g zn@Z*_%DtGgDyMbMS2+g>=3d^lyi#t~UB>gRhxQHfZwUSkB$Dfq^U;>^CW$l2Il?~a ztsKUDNTNp5Ht^uV6fll-{pJZ6+Fv4 z&)oampSUCLOwR#NY43FOk>h+j{3Qci@KW%7sC;B_^vBpsQV94Qr_)vis^|7d)k0LH_s{pq5QTmb!{v>UPL>t3|({w=gAO zw*!C@vr4l;yHM9lKhRLg=r#Umssuj1d6wEhLjBp+)_&UVwwoPsJL8}oT8GAwV;^Nd zXUn#}w|r>%$~@Op9w-kE-6D;HAIa8cE>J*-kf#HOy0B0KcsqmR!(!v2TO;qo1;P_T z-GhGw?)c05zxQ?UwF4uW&gb$q@qGbA>ifRMD5*biD!4W@JlqWUv2@H8SK{{)za|H! zx*>F6iP%tjCN-4r$>lH`<1r_j0UU#_*bh4l%#q8OYl@i7PC)By%IsvyvwyM;xUJ}S zy6~CE0Ij6`TRTqIPG8-y-B8we90;W?%m>U}Epf{k>quJ+zQr&0!j1`!V~z`sgyWrK zyQ6{QsXfbn$2Q9LyLFAFyxC$J2CnFS+86vlZUb`4yQs_Lr{XB#O7cQHGd48xX?R|+ zaX|6~y$3xL+z;}~<6OvoWP!9 z8*(eTiu^IYi^i{6qOF8k$2fgEnC4Mq4^suR#d6y6jkSo)XWMS?;9#6bo$XyaT=!iy zGCt4fopHjo*VWQh*7c=xrK6YqAh`0%n5G&oBX_BQF9n#h?D z1>~t#zN+5k?zMSca~J1i~HKpIodlp*JD=? zw8Rq`4>Nwx7?Pp5X1FG~e#2-{-@YH?p25`C&{^l!nD`#7iglrE>@1Z})lF22)rhnR zoeOmEQ@*PhAFk%D&yDBw$?1|)A*XRpd$9Yp$i15TH1D!I;ko10VMN~g0OrEa%*0uV!mu*>4gJt@Q`B3Es%Xus#x#i%S~ei)86| z;plf^DY!P!)nCGw<$dganAbZmlKUWcLGHfXzjIxA1M(`lMOf$q?AeovruXjk}F zgo@RQcSsyaZb=;#)`%S?ue1dygLg1uY{W{|YecMZ$o?FPY&;TipFn&}0-P!j9xT z;PAJ@s4+I!H&EUm#XP>V=e>IZ`qTh|{_^s=!JnDyY2@{L|G+4}IIuc+Ds(&Sk3^%E zxH$n_q*QTXr%*)vL#zwLFc&hs%V5`XG}bBmE3=i~ksIwncCHpII1a38^*}Zb4c41I zXrq6E@!<~UK5lkDH-xXIDW;8SAL=&iXB$2?RyWlKV`d@iBkM1=$@cD!V$KK7Nv;wZ zyE62dbuu$E;~9@o)-D;3Ty_M?ueaN6UxJmiobgw1=atjc5Z3< zjRwNn?%=Y(*Z%pw!`_sqv*)sVjJv737#@e+Z9Q&yF++S!{RUu%Jqtb$MZ=FGkD|U< ztwclgGka4Vg_}YNae|l-cT44v(f^}-TYiLG^p|pud#*W`#?2W)0Dfpw9gwgv}~ z3)#xGvCiC)F|g0rbKDuQ6-)ysKofldU_EoDqUQRRdSIXa&|c7S+p*Hw-&F~1uYIOF zvt!n{tae#7vZ9%nGdp4?x6D=AdBKjA0?Y5Fn#LLW#oF!s1ok`ndv&w?r?@h;B=I;_ zHTqMyR!9lt`S1F2yk_rrsKfQ{{#e!M?cV0D=sD*Z=`G?rxoW|WLZ64fi}Z?i ziB*Yni64q+A5Je067PvMq(Ra`X%lcxu3=@(A(xZu$RC1@t)biv=ohc$u3$l{ zjNH3c7(d#0VZY^ip%wPj4h7@EctdAneK3=^u?)6;X&VNX!zS=!uDcdyRL$I< zSvPBW)`6_;S#z@1XEn<@o*B*vx}G}+Im)Zlaf>cH&ay3pnD z#mFDg>#;xM%Mza@^{Gq1p_wZ@5xx=6h%TUcY?Jcw5 z24v8g-(_mE#%Fo6XyCEk&H65@ZPtp+oQ&hHQz+q5+iuG$;K6*LAE%wkZ(=voKY@F+ zk61U=D$zZ*E+U7{2bTu6`&arld5?HP?m2EL&zI-PE9;&IZ1LZ*wpPREMjKom_#)Ug z)GItavN<{}wmUv1F*#W<^?RzFuv&O1B!mH2CrpSHq#wYcG8%gcg@M(004PGs#nWPC z;7t4uOv8_0vu5}X?A> z;kIijxSkJYPRw#=buREpfo}_RFJLRMBP*F%BC|xsN+;{^TANzdn{F7Y>j!H8LJcmb zSF59eu~#oOIK|IGl>6MMgPT^xX%2inxSZglTgMf#+{~D=DOBTY~Ahk z92VzsXFFF6Wo()0&0L*jFVLkx-2&dM4OxY=#%2DHG1b-HxyOFPddb|(blgx--$Q$X zXSjFtChS4o5K9RkCYQ&Ju}hJM;iEvljs#qRZvJ0%193Cng_J{9Bev2N7t&f*ZEJ=hC-GKM@Hkq0FIJG{NlWH#XMGVBZLQ|lGJWD-H zT?F3W6`+QAfMqvOcrJ8+#m2?GQY#?27!dEcfL_M@%r4~?^V2o^wQqI*=%0aExro_; zv>D0z7fPwvS38W(&CXUB>pNsTK!4K>D|>PHHRUsgxYjziJNDU2fe+@XskhN!n5fIp z4&yzr(+p~)a!S&Oy%4lJJ6?XraIG zjnG1H2nN9}G(fq%LOand_K;3Uocsw;g%&A0fnztGUeCN>W85kJndZE9i|%86L&FEg zhNe1LG0wAWwDz?HfyVaQ-pX;(!8*q|bDf`Hjcl81v8%l6iF3O1jia*TBl}QWN$W;% z-hO1z=$~u%10$<3yB27H3Hh0*5tbys0)FcJ=&HzzaM^JC(5T=xj2u1vVc#|1dEYBv zNB;(_;_nXh3$mdVA$xcd(AWn@ssLB+S?n-4r81Jsl3A&tsi&zb!WY6C;UA$GMvi0R zHPIu+#B<^_u@$f{9imt83ye5Uye(D-k{K&6l%2{YWtiH9YEO^GocTBI4Sz#(L;EW{ zw@kxT!vbS>Q%UnX^CSyvoo*Ga!)#Y=4*OjDb9)QNNXMU!%FY?ilg>@fZ?PWpz%kbG z+U~U_t$$dCVP(dyf2r95K7vWqD2)4CgvQvbC=$OC?Gb4jt{AEx>=oGMAL(!BpXnd( zSNtmjuL50yUj?TG6TvT0!p32J)Ej*j9Rz&Lv*=MvCL0Q`fZZJt3(DPrCG{I33CjTq z<~&$RuS+x-j#c2Pyg?mzN&cM}m-r;{EpQjBCT*$fDVtbAQoz-4SGl5Aq>Hmj&WO~z zJ%(e()us~W6X(q7nJ1$BDP*~ir^qh-eK3?JtDam*fT z+9zATF?Td>(r?y`X1c~-O$+$qU34Go4r(WAPh#I`ivEV7t*N#7khz=rH|Go{`!rUUdv&%-blnrAeu~@jlVqaOLn6tY|EY?Mk#ueIY!<`4OSHSXNptH$fD4 zHnW^Hv#06j>NdH)*eT@)c9ERul&q0F37g)SI-dL~c{TYl`r(;kDfyZ5uUd-UPmjiK z=?nFy(m^>PS3`{aJlwT6n0Mp!JTOk&U|#{FE*E%ZXY@h+@A@b>l{RRL>DC))^G!dt*0lU(s&06!>C9@VCejzlg3%J89$=ehBW&zV zqPA#4WbY*Gg*T#)Qlr!cU{`J<)ez?jpQf58AH{pboKYrnFx&e^y%ap6i4devuWt~)1 ziUA#Hv2*~KVh5$-(hDJyYAsBYeo)$B-!%$0`zM-pngW`i`S1B8*oki-f{*7LVPETG zU2%Oy!{^4ojFn6+Od;cXk-X%@=I0 zQbCvyof8Oni}q$R->X3e`(3=39gR3uaH|V*fO+=-GkpzaDT$~p(lz`lv?RPH zYE2wW4VQYTO@JNshW?OtAf0TvbQS(hA8}UK@&EHy1*FjqijAM)VS=w(6Jkhy~GOUE_mUdLnm2J2|E zXdG+EG;Gqn)*jIO%jT#fg$J>*p%VU$zG1=ru}0!D>J0axE}^TWYtENv)*?oGXgnuU zG%_#pJ(#@pvDLBhu|2Wl@v`vGrwg~G%gSEr4n3aPfn}v7N(1Ri>VxE8K<6HUbz~VV zw%G*O07)X2FC7__|e3Plv_L^_e1J z;5tau$JqTlkG+lhK>F$r6tNNDv%16f=IViWtAg&OUNj^PN&RYVdre1;Pn%`xXdPy! z9Uhy*7O|YST(!=zow4n-Rx%Ga?$=+?9nqHKhfx!Sr;*8ltKMv1op3ZUS6)mfn11Lh zwrOT-HgGaERyvq4#mYn(}gy?XQ=(h>2xJ<4HjEQ^5S80P-#FohFxGnV- z9wg@`4+6PwbgCNqfEj4nAA_fEuiQ_LNKK_*MOM6p$gFm$^~p)eBFU49(O?`;rXGr$ zfieCeW@BCHL(~p%sh^V00avf2G+q8%ZOhEyuxG3N7dyE-H6eZ=f0G-*b?07ld-w*L zN189S_q5%0pXrUpo~Cyghih1lSRdJEIWJ&`>KDg&+g@`gLpkjh?g2Z5Rlv37RKF7s z#%qV^U`B97xM#wsTw!}^Iekq-7o;}UqX$bZ6Mu$}fJx33dK#_{j>*Yrk?)eHQf0vp zdP?pFp6QxE*!T+^#aeZ(+z+Wy(-MsmD-*vZzYq?IJEi@YyMX5iXscDk7QmQpEY=W< zi^G7YI0P$e*AfR4$$Q#m2r6;|TEx{K6d(Ip% zaqZ)4@GH0%Ko`?+efiUxU$Nufgq zQ|*2B1lHIFFkP^wzl`pod>}lIT@L34`-Xmx{*v0MuxumkW5W$&X~PE1J;YNVkF@u@ zyiYvKd>O$(5iyoR`qM+PEO6aU$p?V{xe6$%pCN8=AJ&)}Ne5E*6L;hK#EfJqp}P1z zQn`MSddj=xp%|eSA~Goxa{yHwBsGwJ6kCF&V-j?fnVf)qytRmx8-lE$4RkMNBoGWc z0i}8em{yOoYq|H_PhcS&h8pnIwrv=3YZzu5 zUK?9l2H39IuRGd0XFK-UoEER)0dg=VBTCW=4ujHcUphlBowyPz=>OPvCU7uXSa_-A zFdu1W7{(Z_hDW?f^~NUzSkKM8Tka>mF`c!gn`{7^sE1K#nK}koX-^ULQd+qpH4zH}d#_h&ak4;iRH9%)g8e*& zzfu74fL^y1Yr-3D1)j`yN>I81{`zsi zJzk#5OZt)vQ|E*W;z8gBM`fQ<3(-rL*qQuBjR5SzEPe)ioUTf>0o(K_YAJJ@U!l_) zw&@>hJ8SmyAETC?x~jS(y4r@hroL9ceVB8K^M&KNy)n?Chg(XUPa5rpDJaE6elFjg zugx7{bn4?|D742{&G#ZeN1rEO$-C(W++@uIU4Ok_6QvtUk7J(%EBmHl{h>jiU1(UO zH<0mZ;jJ_fvC~7T8)^vIKrfYo>RTX^4w9A%Wm7YgLy}LD!&8aWSYbREakAz2%22G1 z-BzBuS{6~7pxXkpAag|}1p3$!Z8tLcy#|E9bot1W^obR2VI>NR(R)={t zb~MA-BGnJ{W@;6{=pi+aAa6}TNpqHA0Maoh(s_&`a=wi$}<~|$ZmS9)9 zIo}!cn9@u?dJ^I!7SXe?bFmD)`bcI0_GIqy2Hgt70@FkDYfC39V?Av70Wm=@fk$4$ zFj_wiKrsg6a^o;#5o2eAsH>&bX(HSi=A;Y;#!$>#)icqn1S=+vNtfu>n%M@Exjnez zI%yiIljG0)f8>3co6Ic)#wsy5G14?%Ak|-*g!x(zb%Ig^v2G337`2(H&YBR_&Pg3o zkW4Aq2w zLSJTnU?*@*G}+n}x{q|_wR8ENtbtw&%b5!V%C4$|HnGk5O6743^fe>^=oyo#i=lq=~Bw(~T0m-2N8@$r75 zjvl6o8_ei6Hb{#%`)WB?g@oI09r#hunpFpjaN z9BVU*W__Jm$n}j~!Af>Z<3)WzU6eo0Ze*u&Hu#_gbRX$&Xg;DAC-;W8`9Jin@RbM@ z4mXca7faBWH6I(Rm^}J!n$y$+;c6@pej4%y%LbPQ`-Fds=Eb|F28p}Gg~Gkm{!}xd z&8MV;%4#56g;gMEBENGVaBLNEtxyg;d^?4{Vtb6geSjrh1lYo5;XyZ*r%8E0XCDEa z&8L_%jS+HEKM02ups{vovP(11D z=jKkfxd2BO&1HY5&!fa612z25`)E+Gvc^ira7e%6ikv_?eUXxohkvz={6>QSLK@ zIjK5;FNh{7p^$h=+Nw0C+A-bu4-hFbK>vllgno%GsZD9V;!}wF9>LsWCxJ<#zb>NJ z8dn<60V%(gC2Bfn_*L&S6tr$}l_=D^=$^uQ=OS$vDLed`=ixiko8+tJZ=1Sn$41ic zOnHuZu2rsk_Qs}3{Bd=^AV#(Z2Kf5=Uizzs?na9zuE%p?C1XFwCd5;T>4F_7^dr?v z%xZoiaM?$3Yv|7Mz!bR7V?Cp>=tuEz;u3P*^pqQHcc5URe8{sdu86=>zAsgmzQU|d zmS$tmV!OOSZiy8`7n8;Nwc8CVOl2%ru^+h7Qq5Fbm(4yw>~aP8CSAck=wRDw&Kvqz ze{<;ymo5HX(XClsY%W7{<~OlV{Fh)Guh!Ge?}+6HkJMxAHO*dKG2Kq>KFtiaGPObK zm@*{Z$F9bsi4DoyiI3u=F_$?KYZKp^c$ahu9x)_$rh=%YC^L*6spd-iQ*V<)z*#Xn zSv6H2^Ric9+j=KY0G@eU>5g> z_YmDz$doj`GgQ#;!7k86uyonker#RtiDsptmnF+_E5ll#dgfm1c1>KKl&BxA9{xOd zE;uxDDY=uHrCVU$X4zowX`HIP%yysz>44B7xi?-rJ~VM5^{KP~3}K70#!xJFC|WBv zGF~f@laNxaWIKH68r%>zi?$(;vb*?RxR9KeEDXMjxS)}~0CV9>N>aX)s-<+;*)NRP zEGd35aV1q;x+*)c6ZllE4Wz0LR0FyKEb5Mi*Clm+J!SmT)W~$qFh$p1>(qAEjzdJO zqU&uOYFTHWl<{w&0>#G{m0a(%y!?6ec);hi{53jN#4^H&}H_#_q@FrYy=}HlS^YUGV1mA=(;z z4=Nz$VBNlaWPGSwq*Gj%$`)P9dex*_F&6DtI?4xy4^jnFQ&Q7}7Sb8`al55n(r&C} zjt0i_QYs5kml>KzI>uNPY~cSID;ezi<=_JTzU&48Sqp(bi$V?k#SJJR;dQ_e${E!r|tbBq*`oB;>+a1L}hSJwNpZL6aFQ1wN<-H^O*aa$yK+=WkqXZb+m5mK;l{QyTop+ zM4Q1O_=8wXZY+nSY^6Q+c$P7}Sqt|Ivy`fZ4DL4IYOjjekPcwVC_@+KHuKMUMpI53 z)%7t+w$hmo3;j@hNvX3Rmo{WG(D!D8Xp%w8xz96gvNvlf|06Qa-vk6I>~&Cb%oOU zV%i#94Md%mRBDTdQhic`QZDdi?Gn342~iP~;y~##@WaQ7>!eJ?tSmrwJ&mZoui5SZ z-uM?RObs}e8xNH0&KMy}^HnrJ%s1V)t+BVV&Nr7a6x9j5jcuh)6gQ_T2q&a0H4_m9 zBXF*f&*pk^l~_GJ35@h*fmhyBvdKA8H>oxv5qip}#8WAA@^t*ym^IcR_FJq({0LZ} z<4XF{1L;sGXE$@<5pfuWn=c0vHmSfwkofP*<|lI5-rVz}vr$ST`+@7b-Jk8!Ht+`GG=nN|Bs`yfRf_cx^TI)j?dr@ zK@!~E9fG^NyK8WFcMt9mJOp>Q1b2p+_O9yk`uF?StgK|c#T&Xy?!D)ny}#YVS&?f( zbWpoTT4!wh^6|^ApA|w&fLZ!Uwi8l3r4!qyh^fO8_j@NemveRCOX_Hr(JLxktY)k* z?nQO2Cgy?V=jtP}>=At-s0QbX|HE)t-D{r<#?u#!3jV7gywdWTf;| zE`zhzI;$FShrCNaW-dWP*Ne%)tfz}W*SVan$2MYjunaed6Zkwrnn*iyc&aCKP3e-h zC*@IMZtoN45N?Z=5c3CS{yg;U)7N}Iw4aJ^d8D^?n>@v>aC+iSB^*gu6F(#Fqo<~G z9RGptOROa=d_E5F-eP(%k1yP%-PAAf}q5TQj zeULS}9<}-+wViqw8PdO^e=88ZaK?X+B;@7zbN#6vWG8f54-@a8s+-50cYTuIj-*fptpba^_R;^~XXC#Xa2 zCVA9E->6Y|3+mF{(KVZ8xeP<~D2?PuG%b2Bq9S4O7M|eA$~ibJY9LqawE>5-*%0Z` zr$FW`Ni={;VJ^H`9!7zp<|DJ8{hhN>iIhdB@-2OzT2Ea^;;c%A*;Qf<*Jk&7=rYc@ z+BjK9dA<)_*zRPk)e_Vxn0sAUJ}NWSy!t?-P5cU8d_n6^WWwgOCxYQjfRlX>v!A)t zDC#I#2Wskn%z(~l!<2@x^>Rb`z5FR=C=Ij~`dsXWcQD!gTi>H?QfXAp{h({RW&C0v zCg(7-_?_Z6M<-`N=K#lRVH$s#UB&zd#Zx)vEW1k>?7Zh%>K^V{;aTn8CIbzAI=d|TcE#Y#kdt-mpL!9%{vnr}srNpr;Pis^qI(`W2MUT{5Y4^m%do7cdO z--?xC59Z5J!)3LF;-d{Z55J{xEv$P4)BWD1S%7&le=rv^3wC!?1g=hk5{1 z31rLuLD_U+E{mXw-JC%r|HTq|CjOaV#rKO_>G|dw=;*<%p<2MF-PTGn=4w~f?dn5R z%)_OeJwyq0YGX^qzV>D$1wH}yhBS;N%t=$3XtJF5};buEYXALfb;kTQ4*=ZVMq zXr%C#1AWG0R|5w=Kgcov>wNx?u9r$Yu;HL0Du8PfL(ar1q%%*WE>hc(naa?mm;!8l zE>2kMnCWJ`C($9Ame498Uwm_KV^@8l3)=vnvWfXpYoQ)f%BhXiH)>PuU(^aG@lPMk zrH(>nTR_Q+dVWvrtWrRouh!SXT6bO5OB&mC6;s_$$YR@w+3rs5hSo=K3q{)lvnjMQ zo$UokB>9L>iHQUB=;#5FHW{FP(D#^y>_M(1AL52`<+;Y3%I4uH{!yd#c~$EhRqFYHjRIsc6J3H^{V^vyZTdDEHGH4}+0dt8NFEHp`X#qMHN zVI^0Ut;H;*X!4vr*SchE(i*Fc&^I_GRg~&uugM}klUAW8HaV76IiS2nzcjmA9ocXn zFsr$*X2%ryq&84zpzL^!nk=W8Xf{Cd(GBw%dTVpQ06Jm+Laavjq&ImE_qGGF!k<&k z=&H;Z_Auua0%C%5q4S6{udARAB^9}vY(u6my^&l7 zT|+HnuXamW7?b3Va!h(7O_Gnwo8@OvD_q9U@mL}f;}Vqm$~&byp4(rc9y*0*^pJ7b zY-nw^@`8;d!QD8M_>74YD36z`%FX3` zax;0Fyc732H?o=1F^j*f6jyhuwY7KJ9Q_yLfzchhmq}JtoUEG?`;pZ!nEV(0(fd>? z-GW{KXWUhInPvg%^_5%4EBs?V%yU9nK@d*x75M#J6RtiN&n;oIv7eX(_B_*&abZH# zlpas*BTcB>irIs$fo3OT5YERvv_I7#Qh46Q2F2dXQ{+POVX2|iPI@6#lDA>{IuY;4 z0dp9k9J>-{#ct4ckLP#sl>|dLCjKK%7O#n4#C0MoP8E`cAlHDa!fj+jOkt)JBQQ;X z@47~fq%PwbKz;%;*e97A(Fa_tT~TwXAC(!3fRvT@=#K?sH)3;dr!!5^6CRH|n^k;$A-C8>^g5E!EsA$e za&&cMb5s`F3M2SWY);GpwleqWC-78Fq6Q;X`xuf$x}k@e7oO7b<~FRbg)t{9qCHaE zs6Q|lhGHUC7f)GV*^+drfSf89kY}T>bsp1jpYmB9q!rPVF)^Qn+?ED*Ydq&qFayfL zgcvAjxHag;4i=Kdt70Me77t+MI^sI*D&{)xeB&JF+~>F~4i-*uYgwA@02lH&coD}C zpOBn21gTt|OsCn+*on!=e7(@1_*3-L~{%irRCqF>Q5b}%5#YT=f4&Hg%dCWD^ zecpZ2y}>=%UC=$!)!tcF9M0dwlxPEe4-B<+$S#ttiB>i1s@Vr=&=d9V+9CCsav3Y^ zRkG2U6}drzFM;nQRr-Ku@#=QOS0~7rYV~YJV6z^i$d`wU2s4*&Dlo zzLSZSeW0`g*`y?cG0)h~Tz%o0a7Fy-sP8=FJm6wI8J;hmL2+3V!tq(-8^;Zab9+Czx;UNUQPxd| z$TV`GmCu-^&%u*Z0Bcb%B*KkWr>O(f5z67%gjlQCG5NLB6nUh-%e$pn(tK&KL`adS zOIi`FAKe`N6B)15<%XECy-`yzFGmKn6X;RLV!zr^;7A1{NOpm`C_p9f&I2L3anYeB>G&;Z+d<}bR{n!pftzi2&alRO`vq&q(04xDJdDBD#ZrclL{ z*GgNQssE8WN*|*yBA1}tdl9WAwU8ggnyZbpfPToljr+Erm_vQ1-!UiH>HHhx*dDo{v^7*BSSGYM zyeYgWd?eZ*eVG~3RXH!xriR4|DVCb11+*kXFgqJgy`ElH>#i)5rbM=f>xSwEtw7Dt zx-cExBjr#kgRYbfeWZZZ6El^DltkxaZ*UVFQ#{Y&wkC8-nw2~?c|gjX)PkucQ{JTh zmvvOuDXB}7HYSGSdb>^GJT=_NkcLDK1^fBF|NQoIZsuv9MUgc@X{`cdtm=QaK| z>S98lX4@;pYV@2-nEYJ zM7C9zM)m}~{`=|d_r2*OGROH!2f9VCq0^R48;ta^1Lh8BJ;P>m>*fESZC&JgJHKgZ z4V1)a-{4_iu8be)-G2Hq{Jv_T?a@xL(&|6@QtO4?95r$S>I0p|KIfK-#auT$RpW{z zI1(!-K2CU^&=5}9#fiTqpU!e3d;RS7(uSo-Nr~}e9M_o>1}(Ms2Ytgboj;Cz-;+C-mTpVSTmN>ts>kd#|6NqPI5bnGva^QbqeZ)Bz zoCw((;zjNb+m5{puFO&WyfRy^5Ki@<&Di3r?TgDu&FJLI8QdAz6WS4}jdjYegspeb zC8B@pXy(f6n&Y13&Fxw3TIbsDDuSP|yMp)Exa^64rQXTp>pWr^<6dNH`jt7;F>V;XmW+9Xt)U@4e6! z>6$WKyQ$x^8Tbk3(L9x%n`UBcM1*+{Tr$q*y{fhObmSvqy@i)OURX#_v$pAFjv?w;8A}< zY(aM8bL)`#uijMU6h0P{hDhHdW5Q#?lOy5q^I)A&v#1aHteQ$LJ!)E(365kL__5k? zrNzOH0gm5YD?NgDxc6aPw}j;hM-#IqUrs8Ul$4S^OM|q=DU(ymCFh9CBQ6xK3;F3` zdTHrg_;Ao0>=e!uI-j{H!|R_D%8Q@+(nw@PQ%aIi0UfQ{#7fj^-Qmf24@$~wB^Dhf zWdS8&K=?cM-~Qp*p`#H--X^8UJ!6lR^XdYBg^dr&^GNSt7I^6M1Vg^l zf!%@JnM*SJ`>Tc?2TMfzs;l+E)+alHdh!yIYJ1r^tmoPVr3|v8`y#({n5HPTFj?Ig zO^`Q`>l&I`@cIS=GLz-_fSZNzoh8(bAPr59qgpnOQP&|6Jf7 z5GfKJAI+g$&?g#?G{e|nUP6}PBXgzo%E;6!p{6OO9f%!}$=DJpGtwg36Q`Fs;jPgp zu{w&RwAU82s8CND@4j2%J6St&fO>3Iw z&C)(gvn-Azhvy5tBJ+gW^db9S^KU&<-irQZ&gd0?d}jN=I=?%!j{kJ%aP)qtaO6a6 zin?13s>#MsO-K#4JyG{eD2R?qmXy;ZKM!!he@ zNBl-rVd79tHQ|!PzZ_-7YVc4Mc5QVgxW{^b#_4hX_z{UkllCL1A{Fl8=}9M3&ZK=z zs^aY)93c9d+<;f~% z+(Q><5V{-N{x{n(Uufgx1<9EX2To-!i8p*3uN~R1?tnNwW2hcI< zA@$Rgp$}>&4Gp&Nweqj`SNNIoqip70pXpoaKOLr|#*tx?tX$WQL+g57OE9wQpV48z zu5X0G?g{7sd2l9HlyB+_R1bBvpgzLrWpuE7b_vQPA5poOx#(VgW@w!I_6QZx&uAug z65EJAQF3f`Mx9UHMdBvF^O}^DoU}0^d&1nr^U1rCeWHyeYLV$OT7&+^iI99QB>!( z$4XIU4etADJZtE^ffRMpYC~vb93xK43@#2-$G#$Sm48h6XxNVr8!vMh9%|I)m%R?*{;I-!>S z3mJVfvu3vXdF02u%=!MOerF&@c%b~JG(8%L3Fy2%(B6P9Se7V@^v;5|(_CfDFt6D! z&4Ag_UQ2uf3wyG)%1*|*Jr%Q6lKjPb3GVc4Vu-y99IGI4mwd(s`3KO@9frp54JKTy zYm4W$XTRsH*A*Y1&@sMXTmx^=Q!Z|A+~>Hw-W=|qj;#DLvW6CwpGX%_KX;Pl;7#Au z%v(Rd{LIXdeT969zRQ8{(FA$9G%z+-*$Q{aQ7uSPL_1_LZzuk?h8tB)jyz-kFvo+| z9kU*rU|A!LybttLwd@|mXwbR_APsu4G2I$T{2-2jgXp9S!XbKz+Ruz;TeFGKmwXb> zJI}brxn1rh?zi52@!>cl?w|N^a4YBVmU3MK1!z0Jf;-CAWtvgjtbp=5Itx2hv*@dE z6+}cd4)h4*_s9JCf_&(3IA`=ADx#^%4)iwtYA3x8?y?8Uz&E&J1W^ikZJn(S;5F?5 zcf6K0M}MUKj?S&BRWe3c`>fVDEuTX-#bMI8>d82B9zZ(sBI*jckeWpA;_Er5I$t6Q z`k2$_O7P4^J*DB)H#Y8TT!FYtp6wo&=aI9R5atH6IhX~Yj-}hbn?=k=`U81jXp1i# zOp;zjeuS0>=LbgwYWjbMyULmJ?^2CeGjujxMpv6AlgJy!S^IaWtT#YS{5$c^+=9g3 zF>osH(%a~HwfUM)%deNz?y2kHb8wi`&#XI-=^E<2;_-MEc)EG!y6?D_xlefBxEDA-pszqUTJwHJp-iGW5`D|Tk6B$WqXuH% zq6E@g4aBe3XlFAGki;1?CZbimV3CTT9|NnHzkz z=0qZ9lwHyBNze;GuY1bqE`N{~#vUjEwXRm&IHl~6uf|qt)76aFEM=i`R=$QwY*Y0T z6zsj_!b+>ys#tB%xXNl(^so3ntF1~K z2=j)1N=KLswl|jr6q)`+C+i)YjlICV6T$v%uC!3&v~;zO5{czdT}mIhf!s;Xz!Nkj zT0~loZh1R-j5H)#8@<&3VviIV&&50Ky?(_y3GVzVA`A5Zn$m~hn7xFSb{G@I{4EcA zm1%@2kw(3S+chhF2+aH^P$yO*y;L`3+`ml29Dn1cp+X~Bh==wEM;k4$%4O+muXHNl1pb7fxh3re<;XR^O zFm2fiTwDIB5E0Ib%bj0cG?b*eHz)W#0G-C2j#~=Hj^Fbiw1oRGq4M%)*zL>+dMS0( zE^QouV*jW-G+HKdCG;*>KQP|M_)29C$h_dY17F!o|BgVf;JZ-UNKvUzj7ER)mGTMf zlyCY-^8}_!>#UJh8B9o)lEa`ra9}4XM~t_Vn32#K)*v6k%{hV?NZlkIWO1mvUR&G1 z@$Z3zY!T{i_Ryb;qYBOi7rPP%@!(e3tl>_=9mn zyp*S@JKojZae!aTey5v(qMKn|G$-kE)bH{i=oYPtB!#<&?)eF@(IkKCU>EFY*-r0m*7K zd5b;`c4i%u1P^gA?$HU*C`W1?J-h z@VUsIaO+@=z|+7_beG0Nrbndk-|+RNN{^*O=y$!sTr3mxp~mVQtuGW9(~XcZ&FBxM z+%e=++&~`3Wat7qlYY!=inBBE6qRPKGeNckPYD;Ht6d1Eak8VKGvw5q`P?DNjFUF?cc;sq4_~ z`Ru*c2Ap#K=jTn-TS5oET&{@D+X(cTS*ccJRJcxfDW0!dk)`2Q;TNG(p+lh@;rfxA zkq?p9(dp5{QCg~xS|S&mPwSNGny&7{+@qN`U4H{YTnS7c{)O*Zw@;B%m_3|_8^}&X z-*+@yo{tk33p0gUd{@2%|ABJ|g~Ua|A-D_k^Ex+_f6ZqT?(+@6v)Lm|5hOmqzZF)B zagLgftD+@T7CH+Qy6QbaBkac)=K5goNo7U!hl|j&sZBUZ9kfqb?ePw`vIdzipmDd9 zADDMcQ;x<8%A=y~qo*U+!~cYehueg&hH8X51#^VThS>1GAu-%B@-VtZ@--QO2}k)+ z{8hfVPypXQ!u`U1VoJc`uY>keiE4uEk)A{|)Uow2E58HnXmO*Beo39DjDkw6q}p3a zkCljZkgLlVK&;#>_dz$eKDy22F%65#lssSBDP4dIdIywq=VQBL4=`^TtmMG#F1OZ2 zOV^Y1wR%BJy-Q=Vevjw^x@bIH$z92H%w=vaUk20R4eTU%Ec=Ly#Y^H#yiX^EvEW~| z5D$w-L)sO8d2o4;6# zaYipq1jt>Oj1*!2#yxt##MsS&21O6pn zS-1<;OqB1-f8@4<bl#6;sMJVg_HA9Pb?SvD%EqbooE$R#zU^ zGUr0a5pk|KL;NgO5^3QKH-J6C+`>CLo~neC{A19+Ya3;BxAu!V4fCX1^4aKSoHE9S z9FfQ2w&B}>e|!&pr+jS!BIE< z`g8rRncuo%-yqM@QTh^777mT-+%9gO@P}i$qrBssfTRfVIjE)^#T?>peEXhwKes?L zCNsG}*;+=wrq+?j`5{;0Ih{uLGSC5z@WX*b|ME;aBbxr~=f{kEzWKg?Gr7#^zTCdG{w_gZXkWBwRF2Z} z61k&tUb}=8fb!fY?yShZy>J6 zTKPrT#`Rg zQf%lPy6pe=tnGG7?$Mrc?h~$0&b-bo4pnR}78m~Frm~$FCtZm25?8ED)V{^_ z3{_NqlMh6l(vj$<$k_0p;O~JwpiMOhWcaK2Wv~?2XLJHVrK|6_uZoZMm-HVGdc#Y? zb0Uu;hosiZNo|5I7=@rGSb$Y%C3>>!;e24&U${T8c8(M`fWJ@#`}sgeZO4C@ioX{7 zJCYrlLQDQ3=JZ|Io9tRPHAGo`muLTpUzh6474UdNcEKhTrR)Am;C3*NkY?b%3A8%nHzLSqw{N zU-XFkg>pg`ffUxDk{Zb^W)H&^HXTmrmdJ*BOzg3fkR@5{?~<^@=T%2Z3DHPMR3~5;+jLA08B0 z5dJ0dJroxz6lxG!7pW6&961+uMsr9Fqi%VP{7^Zl9)_>@gTBtBkSVZ*97ElrZ_#U@ z$~=U+HkY6a#l$sYP0*U>hy_8LE+t+U`w0=;$zxFXgy6sRBg3NuRQN@#d5`qt-5N(62TlC8S=wA})H2@b6ZOV=FRh~5 zNg0f5;DE>UMeK;2N9q(!iX4T@>0-29v}Sm3*dO{ev?;tbyaWFfiwbyqdW3sN#!Cz2 z1zMUmM!ljuR$N9Ovn;V3?#un;d7=zmkvYVj=a&id1WL#!wiP!ynmEQglAI$QMVwKw zka$A4#{VJY;tft=)0t$Z2OOQ9$sWjFL%zH920p_6@HI3?H@S+5z7I}(<8r4><}jS_aBKqY&jWo~K}x3@fvf(JdCb-aC#|QLC|(g<;!p9N;}X0p z4;*PK*7)lIJ503&Jv~u*k>{WKf z`YHRBRcd3n1x`Rak&SEv-rEZ*3oG!?xf}deR1a5$=c0_>^kFf-^ReTuSYJFUP7xal z=lSZmTUXdi%vq)sJ(21MCEq?|?u`U>YXSC$diZx^>l0G$${@Y^sV(Cg=Y^Af6TOeA z!Q5qPf^6G||C?_r{D3y=q~I0Xi4DXeq8Dd?)uJiv#WQe|tIIt`1v-oy&HA88UWY5) z3%Zfr!~lD>nZta7YkeDRj8@tcg;18oYXm)5wut~6LplIN}KQ3@C&=H)HA@JPI3uF%s3$KcH0QIP3tc|=49khU! z&AenjgK{(z3h0`63M|$u%n(~aE$0#QJF+_yU3=WDJCD1Si^3@>yR$Ruqu4v_0In`S61&7rVX{y|D1nn;J9OQe30L`Ad=ORO9rhOLxqV0~ctE`;m!YmP z%{FExhy$DSKH4JXQ|v4zGd`(Z^dQa&k1-4OVhUU)Fw(!=pT*zGKiYrMUlDqPV}WG> zDIkUxhMz}TM%PF)LrYL+rqw-jE)M@Be@!#T(*z@n5kDh#EyP$8YUE zy3YQ5IE~&c?LId9f9Dg7b0h_;#o!(!^?Fd(jWZ{%l-<%fcohUZ}?p z;?A)G_R0@*4*Cgcff$-%XP6(2&w466lO|kSvto_qc!`$6(e2T1k!j)Ep(3G~!OY;f z;Gp2gfHN>LurUxHObR97r$?|N=q8^cNGFm~<-u~dSY36awi@{W<*gmoQhOOOgDS}U zNsH`$R6Of(Du_WFxKFI&3_9*P|8ahBK6Z9;3_{(q*^$pt2lJLE{0-D(W4Ph)#Fb@k z(4WY4D^GXr9$b^2EC@D+*z&< ze+zY9PT>)Mj-QTtem$rUSNS&}o@`?eFu$Q|JcCZ4OH&KToJhjR2`%e9L)DM!Z?!FI zN#%5`yL?Mp0$RsusdltSWNo-|=v=5+cuQCaHwzsPz6-7nmI$>9Zw!A9UjxzmPGnAW znUqaVm%qmbDi^@JYNl_5Rv?Fc9DNE6&d@?&NmvZW$#8^?8$TCz3s5eW&jeDD@59dl9C~<3$ z)5r+96wbTP^f`J(#y5cHu#s}?&+E8t&K0#K(t=L@of+R_V7cmA+nNj^cv80 zuF_wbX{^aCLq#`@8;_n0f!bvY*OH&gU+21T9-O8xu@1IBbfN+?jmgV=qYdf=^_XJt zzK*AsK<_Pq0^1*Fn-x?Q=$VIt4xWh9s7;RmDWMI!jJ?FZVzY9$xFC0dI}Ig0k28@2 zi4Go2mGZE;*+;mtz35J;g4>ZB$wBaFIP5akPk1917=6Iv_!qR@i|R!Z zux*&ZI02_K`IyzrN#-1VpPq&simUW@dOFhyj-~|s*9m$O?O^g_BAh_iphZltt1%Z* zMfmCQOdV!9FryQh+n}iDL2vddYHTmv7?gq9w1fT+U7jY`3CDn`ae(*(dAua?(AsJK zi-}ofb0$b;PIH0Y78=_>;eQmg0qP8`o2n~Upwi2xUQk}d7}bhBh7xxNG=ueHzSwTH zyIMk70rm1rWu4jvOy9bC9#Bp;;I#DvsbVRpObgn#z~pxzin%UGu*=AqNa?CX1wgzT zNEg7jS%tTA2VDuL!>6=LH$`ppiOx;y&|_Bs+x{AzhTN=FItO)&+=z-SnZ6F9e_l9k zHj_oD2_RPgM&G2KK=Evm4?zgthQ305rZtltEcRJ+9i}6`btyRGzLEEd1^C+zV;0*R zPtiI|3b&H^$muwTZp9TTVqUN+5-ZHZ##1CweKboziw&L-l>fgPpS1h>9OI34QlEvK zf%P~I@6~@dwi#E{YkF9(q;dKo^tfi~8QOkB*KcTNbdPn?7zKj*dF)_A%tv@Dc9}h` z0+yxQF})Zw}_e`ri=wgW(WC=+>6wu-Q-O4I1eG;X*=17Dhi@WB5@znrY$&i zq+llc4El>!#3<}NRgoc4jhqV-<#0GV&KfhV$4EkZXU((|$-eMJ_O=g^>DZ?$AT=Y= z9&ctYWr6($?>G71M>cK+3@!c^ z)-=g3bq> zL1#Q64REys%vz$f@z%ZspV3XTr|qCqiQUE+nxxJepdC|7h#y8BVmIA~P>qiEB4&hs z%gV_~)>0!2ISU!fG2M?^qnnuo-J6GcYoyq5$j9W(5%w}>95F|oLVc$+Ynu57JWw@| zhy93dfRxNJ_H6nbkyD>#?_gfqyuO|2L`Tdv_+7sd?~G0MWz4jeBmH78HQ%0KKC;Wv zudVXt1*8j>vx?xp)}spAF7q)}l|HC#AjfgN%^voAyg_%2eRg|3VCA>≶Q6aK83u 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 KqBMG^zyAm8*UJe2 literal 0 HcmV?d00001 diff --git a/extensions/assistive_harness/phase_b/assets/reject_wav/no_frames.wav b/extensions/assistive_harness/phase_b/assets/reject_wav/no_frames.wav new file mode 100644 index 0000000000000000000000000000000000000000..86806fc569cd001b848dc79086d808d4b9b74c54 GIT binary patch literal 105644 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Π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 literal 0 HcmV?d00001 diff --git a/extensions/assistive_harness/phase_b/assets/reject_wav/orient.wav b/extensions/assistive_harness/phase_b/assets/reject_wav/orient.wav new file mode 100644 index 0000000000000000000000000000000000000000..2b61d877f97b30b84a2673a76df41f4998eb7099 GIT binary patch literal 163244 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