From 9aadf9cbdaaf80d8b6a2fabc54041039cbcff45e Mon Sep 17 00:00:00 2001 From: zmv Date: Wed, 23 Sep 2026 18:54:11 +0800 Subject: [PATCH] Integrate CAN-aware CMS risk pipeline and relocatable Orin runtime --- .gitattributes | 9 +- .gitignore | 45 +- BRANCHES.md | 9 + CMakeLists.txt | 31 +- Makefile | 11 + Makefile.baseline | 71 ++ PROVENANCE.json | 61 + README-risk-upstream.md | 330 +++++ README.md | 242 +++- TEST_REPORT.md | 56 + accelerator/.gitattributes | 5 + accelerator/.gitignore | 4 + accelerator/CMakeLists.txt | 23 + accelerator/README.md | 76 ++ {config => accelerator/config}/camera.json | 0 {config => accelerator/config}/door_mask.json | 0 .../include}/bounded_queue.hpp | 0 {include => accelerator/include}/camera.hpp | 0 .../include}/camera_pipeline.hpp | 0 {include => accelerator/include}/common.hpp | 0 {include => accelerator/include}/config.hpp | 0 {include => accelerator/include}/detector.hpp | 0 .../include}/door_risk.hpp | 0 .../include}/frame_result.hpp | 0 .../include}/gpu_preprocess.hpp | 0 {include => accelerator/include}/image.hpp | 0 .../include}/latest_result.hpp | 0 .../include}/pipeline_types.hpp | 0 .../include}/pose_engine.hpp | 0 {include => accelerator/include}/records.hpp | 0 .../include}/result_conversion.hpp | 0 .../include}/stop_signals.hpp | 0 .../include}/trt_engine.hpp | 0 .../include}/uyvy_converter.hpp | 0 .../include}/visualizer.hpp | 0 accelerator/run_camera.sh | 4 + accelerator/scripts/build.sh | 7 + accelerator/scripts/initialize_camera.sh | 4 + {src => accelerator/src}/camera.cpp | 0 {src => accelerator/src}/camera_pipeline.cpp | 0 {src => accelerator/src}/config.cpp | 0 {src => accelerator/src}/detector.cpp | 0 {src => accelerator/src}/door_risk.cpp | 0 {src => accelerator/src}/gpu_preprocess.cu | 0 {src => accelerator/src}/main.cpp | 0 {src => accelerator/src}/pose_engine.cu | 0 {src => accelerator/src}/trt_engine.cpp | 0 {src => accelerator/src}/uyvy_converter.cu | 0 {src => accelerator/src}/visualizer.cpp | 0 .../third_party}/nlohmann/LICENSE.MIT | 0 .../third_party}/nlohmann/json.hpp | 0 .../constant_door_mask.json | 0 annotations/door_zone_multifeature.json | 47 + build_and_run.sh | 101 ++ camera_reset.sh | 110 ++ can_comm.cpp | 338 +++++ can_comm.h | 54 + examples/read_latest.py | 36 + include/zcan.h | 443 +++++++ lib/libusb-1.0.so | Bin 0 -> 377192 bytes lib/libusb-1.0.so.0 | 1 + lib/libusbcanfd.so | Bin 0 -> 205816 bytes lib/libusbcanfd.so.1.0.12 | 1 + main.cpp | 344 +++++ native/native_api.cpp | 115 ++ orin/README.md | 43 +- orin/SHA256SUMS | 32 +- orin/annotations/constant_door_mask.json | 77 ++ orin/annotations/door_zone_multifeature.json | 47 + orin/build/camera_risk | Bin 695864 -> 0 bytes orin/build/libvision_native.so | Bin 0 -> 256776 bytes orin/config/camera.json | 22 - orin/examples/read_latest.py | 36 + orin/lib/libusb-1.0.so | Bin 0 -> 377192 bytes orin/lib/libusb-1.0.so.0 | 1 + orin/lib/libusbcanfd.so | Bin 0 -> 205816 bytes orin/lib/libusbcanfd.so.1.0.12 | 1 + orin/{ => models}/engines/rtmw_l_384.engine | Bin orin/{ => models}/engines/yolo11s.engine | Bin orin/pipeline/compare_rtmw_ml.py | 384 ++++++ orin/pipeline/door_mask_risk.py | 488 +++++++ orin/pipeline/door_zone_risk.py | 358 ++++++ orin/pipeline/fuse_rtmw_l_temporal.py | 855 +++++++++++++ orin/pipeline/latest_result.py | 64 + orin/pipeline/live_pose_engine.py | 248 ++++ orin/pipeline/native_backend.py | 75 ++ orin/pipeline/occlusion_aware_pose_v2.py | 1130 +++++++++++++++++ .../pipeline/predict_optimized_pose_videos.py | 683 ++++++++++ orin/pipeline/rtmw_l_person_mask_ablation.py | 166 +++ orin/pipeline/rtmw_risk_pipeline.py | 390 ++++++ orin/run.sh | 7 +- orin/run_camera.py | 299 +++++ orin/scripts/initialize_camera.sh | 22 +- orin/scripts/initialize_camera_impl.sh | 27 + pipeline/compare_rtmw_ml.py | 384 ++++++ pipeline/door_mask_risk.py | 488 +++++++ pipeline/door_zone_risk.py | 358 ++++++ pipeline/fuse_rtmw_l_temporal.py | 855 +++++++++++++ pipeline/latest_result.py | 64 + pipeline/live_pose_engine.py | 248 ++++ pipeline/native_backend.py | 75 ++ pipeline/occlusion_aware_pose_v2.py | 1130 +++++++++++++++++ pipeline/predict_optimized_pose_videos.py | 683 ++++++++++ pipeline/rtmw_l_person_mask_ablation.py | 166 +++ pipeline/rtmw_risk_pipeline.py | 390 ++++++ run_camera.py | 299 +++++ run_camera.sh | 5 +- run_risk.py | 5 + scripts/build.sh | 4 +- scripts/deploy.sh | 6 + scripts/initialize_camera.sh | 27 +- scripts/package_orin.sh | 34 + scripts/start.sh | 21 + scripts/stop.sh | 13 + send.hpp | 108 ++ tests/test_latest_result.py | 155 +++ tests/test_risk_integration.py | 70 + v4l2_capture.cpp | 380 ++++++ v4l2_capture.h | 91 ++ 119 files changed, 13940 insertions(+), 152 deletions(-) create mode 100644 BRANCHES.md create mode 100644 Makefile create mode 100644 Makefile.baseline create mode 100644 PROVENANCE.json create mode 100644 README-risk-upstream.md create mode 100644 TEST_REPORT.md create mode 100644 accelerator/.gitattributes create mode 100644 accelerator/.gitignore create mode 100644 accelerator/CMakeLists.txt create mode 100644 accelerator/README.md rename {config => accelerator/config}/camera.json (100%) rename {config => accelerator/config}/door_mask.json (100%) rename {include => accelerator/include}/bounded_queue.hpp (100%) rename {include => accelerator/include}/camera.hpp (100%) rename {include => accelerator/include}/camera_pipeline.hpp (100%) rename {include => accelerator/include}/common.hpp (100%) rename {include => accelerator/include}/config.hpp (100%) rename {include => accelerator/include}/detector.hpp (100%) rename {include => accelerator/include}/door_risk.hpp (100%) rename {include => accelerator/include}/frame_result.hpp (100%) rename {include => accelerator/include}/gpu_preprocess.hpp (100%) rename {include => accelerator/include}/image.hpp (100%) rename {include => accelerator/include}/latest_result.hpp (100%) rename {include => accelerator/include}/pipeline_types.hpp (100%) rename {include => accelerator/include}/pose_engine.hpp (100%) rename {include => accelerator/include}/records.hpp (100%) rename {include => accelerator/include}/result_conversion.hpp (100%) rename {include => accelerator/include}/stop_signals.hpp (100%) rename {include => accelerator/include}/trt_engine.hpp (100%) rename {include => accelerator/include}/uyvy_converter.hpp (100%) rename {include => accelerator/include}/visualizer.hpp (100%) create mode 100755 accelerator/run_camera.sh create mode 100755 accelerator/scripts/build.sh create mode 100755 accelerator/scripts/initialize_camera.sh rename {src => accelerator/src}/camera.cpp (100%) rename {src => accelerator/src}/camera_pipeline.cpp (100%) rename {src => accelerator/src}/config.cpp (100%) rename {src => accelerator/src}/detector.cpp (100%) rename {src => accelerator/src}/door_risk.cpp (100%) rename {src => accelerator/src}/gpu_preprocess.cu (100%) rename {src => accelerator/src}/main.cpp (100%) rename {src => accelerator/src}/pose_engine.cu (100%) rename {src => accelerator/src}/trt_engine.cpp (100%) rename {src => accelerator/src}/uyvy_converter.cu (100%) rename {src => accelerator/src}/visualizer.cpp (100%) rename {third_party => accelerator/third_party}/nlohmann/LICENSE.MIT (100%) rename {third_party => accelerator/third_party}/nlohmann/json.hpp (100%) rename orin/config/door_mask.json => annotations/constant_door_mask.json (100%) create mode 100644 annotations/door_zone_multifeature.json create mode 100644 build_and_run.sh create mode 100644 camera_reset.sh create mode 100644 can_comm.cpp create mode 100644 can_comm.h create mode 100644 examples/read_latest.py create mode 100644 include/zcan.h create mode 100644 lib/libusb-1.0.so create mode 120000 lib/libusb-1.0.so.0 create mode 100644 lib/libusbcanfd.so create mode 120000 lib/libusbcanfd.so.1.0.12 create mode 100644 main.cpp create mode 100644 native/native_api.cpp create mode 100644 orin/annotations/constant_door_mask.json create mode 100644 orin/annotations/door_zone_multifeature.json delete mode 100755 orin/build/camera_risk create mode 100755 orin/build/libvision_native.so delete mode 100644 orin/config/camera.json create mode 100644 orin/examples/read_latest.py create mode 100644 orin/lib/libusb-1.0.so create mode 120000 orin/lib/libusb-1.0.so.0 create mode 100644 orin/lib/libusbcanfd.so create mode 120000 orin/lib/libusbcanfd.so.1.0.12 rename orin/{ => models}/engines/rtmw_l_384.engine (100%) rename orin/{ => models}/engines/yolo11s.engine (100%) create mode 100644 orin/pipeline/compare_rtmw_ml.py create mode 100644 orin/pipeline/door_mask_risk.py create mode 100644 orin/pipeline/door_zone_risk.py create mode 100644 orin/pipeline/fuse_rtmw_l_temporal.py create mode 100644 orin/pipeline/latest_result.py create mode 100644 orin/pipeline/live_pose_engine.py create mode 100644 orin/pipeline/native_backend.py create mode 100644 orin/pipeline/occlusion_aware_pose_v2.py create mode 100644 orin/pipeline/predict_optimized_pose_videos.py create mode 100644 orin/pipeline/rtmw_l_person_mask_ablation.py create mode 100644 orin/pipeline/rtmw_risk_pipeline.py create mode 100644 orin/run_camera.py create mode 100755 orin/scripts/initialize_camera_impl.sh create mode 100644 pipeline/compare_rtmw_ml.py create mode 100644 pipeline/door_mask_risk.py create mode 100644 pipeline/door_zone_risk.py create mode 100644 pipeline/fuse_rtmw_l_temporal.py create mode 100644 pipeline/latest_result.py create mode 100644 pipeline/live_pose_engine.py create mode 100644 pipeline/native_backend.py create mode 100644 pipeline/occlusion_aware_pose_v2.py create mode 100644 pipeline/predict_optimized_pose_videos.py create mode 100644 pipeline/rtmw_l_person_mask_ablation.py create mode 100644 pipeline/rtmw_risk_pipeline.py create mode 100644 run_camera.py create mode 100644 run_risk.py create mode 100755 scripts/deploy.sh create mode 100755 scripts/package_orin.sh create mode 100755 scripts/start.sh create mode 100755 scripts/stop.sh create mode 100644 send.hpp create mode 100644 tests/test_latest_result.py create mode 100644 tests/test_risk_integration.py create mode 100644 v4l2_capture.cpp create mode 100644 v4l2_capture.h diff --git a/.gitattributes b/.gitattributes index 5f609e2..35acbc3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,4 @@ -*.sh text eol=lf -*.engine -text -*.ko -text -/orin/** -text -/config/door_mask.json -text +*.engine binary +*.onnx binary +*.so binary +*.ko binary diff --git a/.gitignore b/.gitignore index 4097644..85a87c1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,41 @@ -/build/ -/engines/ -/logs/ -*.tmp +# Python caches and local environments +__pycache__/ +*.py[cod] +.venv/ +venv/ + +# Build outputs (keep the supplied vendor libraries in lib/) +build/ +/build-*/ +*.o +*.a +/vision-anti-pinch + +# Models and test media +models/ +*.engine +*.onnx +*.pt +*.mp4 +*.avi + +# Runtime outputs +logs/ +outputs/ +out/ +frames/ +*.log +*.pid + +# Local credentials and legacy SSH authentication helper +.env +.env.* +!.env.example +ssh_expect.exp + +# The checked-in Orin deployment bundle intentionally includes its runtime assets. +!/orin/build/ +!/orin/build/libvision_native.so +!/orin/models/ +!/orin/models/engines/ +!/orin/models/engines/*.engine diff --git a/BRANCHES.md b/BRANCHES.md new file mode 100644 index 0000000..fa6ce16 --- /dev/null +++ b/BRANCHES.md @@ -0,0 +1,9 @@ +# 分支说明 + +| 分支 | 内容 | +|---|---| +| main | CMS v9.10 原始 YOLO + RTMW + risk 部署包,入口 run_risk.py,含 ONNX 模型 | +| use-can | 0923 V4L2/CAN + TensorRT + CMS 风险集成,提供最新结果变量、可选可视化及 orin/run.sh 可运行包 | +| inference-only | 原 main 的纯 C++ TensorRT 摄像头推理版本,保留原提交 26c5bfb88ddf9919ea46efcf5b12df6e09ebdfd9 | + +main 和 use-can 均在原 main 历史上追加提交;原 main 历史未改写。 diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a5dede..48ab824 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,23 +1,18 @@ cmake_minimum_required(VERSION 3.24) -if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) - set(CMAKE_CUDA_ARCHITECTURES native) -endif() -project(camera_risk LANGUAGES CXX CUDA) +project(vision_anti_pinch_0923 LANGUAGES CXX CUDA) set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CUDA_STANDARD 17) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_CUDA_ARCHITECTURES 87) find_package(CUDAToolkit REQUIRED) -find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs highgui) +find_package(OpenCV REQUIRED COMPONENTS core imgproc) find_package(Threads REQUIRED) -find_path(TENSORRT_INCLUDE_DIR NvInfer.h PATH_SUFFIXES aarch64-linux-gnu x86_64-linux-gnu REQUIRED) -find_library(TENSORRT_LIBRARY nvinfer REQUIRED) -add_library(camera_risk_core - src/trt_engine.cpp src/pose_engine.cu src/gpu_preprocess.cu src/uyvy_converter.cu - src/detector.cpp src/door_risk.cpp src/camera.cpp src/camera_pipeline.cpp src/config.cpp) -target_include_directories(camera_risk_core PUBLIC include third_party ${TENSORRT_INCLUDE_DIR} ${OpenCV_INCLUDE_DIRS}) -target_link_libraries(camera_risk_core PUBLIC ${TENSORRT_LIBRARY} ${OpenCV_LIBS} Threads::Threads CUDA::cudart CUDA::nppc CUDA::nppig CUDA::nppidei CUDA::nppicc) -target_compile_options(camera_risk_core PRIVATE $<$:-Wall;-Wextra;-Wpedantic>) -add_library(camera_risk_visualizer src/visualizer.cpp) -target_link_libraries(camera_risk_visualizer PUBLIC camera_risk_core) -add_executable(camera_risk src/main.cpp) -target_link_libraries(camera_risk PRIVATE camera_risk_visualizer) +find_path(TRT_INCLUDE NvInfer.h PATH_SUFFIXES aarch64-linux-gnu REQUIRED) +find_library(TRT_LIB nvinfer REQUIRED) +add_library(vision_native SHARED native/native_api.cpp v4l2_capture.cpp can_comm.cpp + accelerator/src/trt_engine.cpp accelerator/src/pose_engine.cu + accelerator/src/gpu_preprocess.cu accelerator/src/uyvy_converter.cu accelerator/src/detector.cpp) +target_include_directories(vision_native PRIVATE . include accelerator/include ${TRT_INCLUDE} ${OpenCV_INCLUDE_DIRS}) +target_link_libraries(vision_native PRIVATE ${TRT_LIB} ${OpenCV_LIBS} Threads::Threads CUDA::cudart CUDA::nppc CUDA::nppig CUDA::nppidei CUDA::nppicc + "${CMAKE_SOURCE_DIR}/lib/libusbcanfd.so" "${CMAKE_SOURCE_DIR}/lib/libusb-1.0.so") +set_target_properties(vision_native PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE INSTALL_RPATH "$ORIGIN/../lib;/usr/local/cuda/lib64") diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d665629 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +.PHONY: all run test baseline clean +all: + ./scripts/build.sh +run: all + ./run_camera.sh +test: + python3 -m unittest discover -s tests -v +baseline: + $(MAKE) -f Makefile.baseline +clean: + cmake --build build --target clean diff --git a/Makefile.baseline b/Makefile.baseline new file mode 100644 index 0000000..cb54c55 --- /dev/null +++ b/Makefile.baseline @@ -0,0 +1,71 @@ +# Makefile - V4L2 MMAP 取图 demo (OpenCV + CAN 收发) +# +# 用法: +# make # 编译 +# make clean # 清理 +# make run # 编译并运行 (取 100 帧) +# make capture # 编译并取 5 帧保存到 ./out +# make no-can # 同 capture, 但关闭 CAN 收发 +# +# 说明: 本 Makefile 在 Orin 上本地编译。 +# CAN 模块依赖 include/zcan.h + lib/libusbcanfd.so + lib/libusb-1.0.so +# CAN 收发默认开启, 程序运行时加 --no-can 关闭 + +# ---- 工具链 ---- +CXX ?= g++ +CXXFLAGS ?= -std=c++17 -O3 -Wall -Wextra -Wno-unused-parameter -Wno-unused-result +LDFLAGS ?= + +# ---- OpenCV 检测 (优先 opencv4, 回退 opencv) ---- +OPENCV_PC := $(shell pkg-config --exists opencv4 && echo opencv4 || echo opencv) +OPENCV_CFLAGS := $(shell pkg-config --cflags $(OPENCV_PC)) +OPENCV_LIBS := $(shell pkg-config --libs $(OPENCV_PC)) + +# ---- 本地头文件/库目录 (zcan.h, libusbcanfd.so, libusb-1.0.so) ---- +INC_DIR := include +LIB_DIR := lib +IDIRS := -I$(INC_DIR) $(OPENCV_CFLAGS) +LDIRS := -L$(LIB_DIR) +RPATH := -Wl,-rpath,$$(pwd)/$(LIB_DIR) + +CXXFLAGS += $(IDIRS) +LDLIBS += $(OPENCV_LIBS) -lm -lpthread -lusbcanfd -lusb-1.0 + +# ---- 目标与源文件 ---- +BIN := vision-anti-pinch +SOURCES := main.cpp v4l2_capture.cpp can_comm.cpp +HEADERS := v4l2_capture.h can_comm.h $(INC_DIR)/zcan.h +OBJECTS := $(SOURCES:.cpp=.o) + +# ---- 默认目标 ---- +.PHONY: all clean run capture + +all: $(BIN) + +$(BIN): $(OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $^ $(LDIRS) $(RPATH) $(LDLIBS) + +# ---- 依赖规则 (头文件改动则全部重编) ---- +$(OBJECTS): $(HEADERS) + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +# ---- 便捷目标 ---- +run: $(BIN) + ./$(BIN) -d /dev/video5 -n 100 -v + +capture: $(BIN) + mkdir -p out + ./$(BIN) -d /dev/video5 -n 100 -s 5 -t jpg -o ./out + +# CAN 收发默认开启, 与 capture 相同 +can: capture + +# 关闭 CAN 收发的取图 +no-can: $(BIN) + mkdir -p out + ./$(BIN) -d /dev/video5 -n 100 -s 5 -t jpg -o ./out --no-can -v + +clean: + rm -f $(OBJECTS) $(BIN) diff --git a/PROVENANCE.json b/PROVENANCE.json new file mode 100644 index 0000000..7a083b2 --- /dev/null +++ b/PROVENANCE.json @@ -0,0 +1,61 @@ +{ + "baseline": "orin@192.168.195.100:/home/orin/vision-anti-pinch", + "baseline_sha256": [ + "a6f884d241b3b345fbdc3bbb2d0119467f6a01d6828786a7d33d7f97ad101f6e main.cpp", + "ba7ce790ec4b43403fd6b9ccc4693148414b7314060c29d9f9f92dee931509cf can_comm.cpp", + "5aaeaba6f0f25a6202ff2cf61c626b61bda2350f5bd9b36e36c828b5b8fec994 can_comm.h", + "f5c6658eb3e8362569c18d528fd4c8a2e311e5f779d9687e8ff10b79a11dc5b6 v4l2_capture.cpp", + "dd7a6f92e4d3335368691dd587715cec3d24816e9a96d44ff11c91296f5082eb v4l2_capture.h", + "65b16fe3d4549ad218679f510afe4049ad0f197912832060daaca13acc0f5f4f Makefile" + ], + "risk_source": "/home/thor/文档/cms_v9_10_yolo_rtmw_risk_deploy_20260923", + "risk_pipeline": { + "occlusion_aware_pose_v2.py": { + "source_sha256": "81088b8bc072162bec13f57c65eb0d396e6d1e1074a83f92bcf29e393e27e11f", + "integrated_sha256": "81088b8bc072162bec13f57c65eb0d396e6d1e1074a83f92bcf29e393e27e11f" + }, + "fuse_rtmw_l_temporal.py": { + "source_sha256": "bc74a400ce5c5608c2fa49a69ccd8b41ec8633cd6a8239d9d594b8d9e5c3732a", + "integrated_sha256": "bc74a400ce5c5608c2fa49a69ccd8b41ec8633cd6a8239d9d594b8d9e5c3732a" + }, + "rtmw_l_person_mask_ablation.py": { + "source_sha256": "d983c9431237afcd7a786c6c4610be6d57a8b4d9ea8f2e9d1889fc0b0ca1d5df", + "integrated_sha256": "bf8bb754cd841a52b4410f958a651b005de36ac4d17cc0992fbe1c90ed30caca" + }, + "door_mask_risk.py": { + "source_sha256": "6d6d14a972bc4e5e9f8256514169e73ba0392a301cacd1221eaa26146aad00d2", + "integrated_sha256": "6d6d14a972bc4e5e9f8256514169e73ba0392a301cacd1221eaa26146aad00d2" + }, + "live_pose_engine.py": { + "source_sha256": "a15baaedf5a25b9896ff898fc1a095388483dc52b1b7000b56d5506ff73bf67e", + "integrated_sha256": "cc8ea36d543896cd90f7a00822f06fc67771a1811859a4087995ac372df30276" + }, + "predict_optimized_pose_videos.py": { + "source_sha256": "36d203f257444e57f890cdc3826dad0c7a46725b938e5f8507e357a70ae2cef9", + "integrated_sha256": "059e2a67c17ce63354986d3242a5d361103ee4241c5391f18140eeb19e47c939" + }, + "door_zone_risk.py": { + "source_sha256": "46d70e1e90a1f36d544b7492ef1fbf08821377a1c460a6683f42d4d7006055c7", + "integrated_sha256": "46d70e1e90a1f36d544b7492ef1fbf08821377a1c460a6683f42d4d7006055c7" + }, + "rtmw_risk_pipeline.py": { + "source_sha256": "1bb58d851ba5d684527b8d1e1940db6241d2b0b2862687fa3b151899a65320d2", + "integrated_sha256": "1bb58d851ba5d684527b8d1e1940db6241d2b0b2862687fa3b151899a65320d2" + }, + "compare_rtmw_ml.py": { + "source_sha256": "5de11436bb888f2f1c4c0e7ad0853e3864193fe2625cc65294b40683ebe8729a", + "integrated_sha256": "fd3ae92255abf95ef037a1060ee75897f9705b4040f9394c3130f6ab860667e1" + } + }, + "engines_sha256": { + "rtmw_l_384.engine": "ebcd09e8c2e35008adbb0c1d222e580b17e0df1c8093df3481ba3374cd9a8174", + "yolo11s.engine": "f6a65b926ac1144484f4aa93cd26d7997d32d62310ab93fe867f2bd4412222e9" + }, + "engine_origin": "orin@192.168.195.100:/home/orin/vision-anti-pinch-0920/orin/engines", + "can_mapping_user_confirmed": [ + "left_front", + "right_front", + "left_rear", + "right_rear" + ] +} \ No newline at end of file diff --git a/README-risk-upstream.md b/README-risk-upstream.md new file mode 100644 index 0000000..5af9397 --- /dev/null +++ b/README-risk-upstream.md @@ -0,0 +1,330 @@ +# CMS v9.10 YOLO + RTMW 门区风险部署包 + +该目录是 v9.10 的精简部署版本,只保留运行 `YOLO + RTMW + risk` 所需的代码、模型、标定文件和依赖清单。历史推理结果、研发测试、标注网页、参考图片、缓存与离线分析入口均未放入部署包。 + +## 1. 功能链路 + +```text +视频帧 + -> YOLO11s 人体检测与轨迹 ID + -> RTMW-L COCO-WholeBody 133 点关键点 + -> 手臂/手部时序融合 + -> 骨骼位置和尺度为主、人体框为辅的前后门归属 + -> CAN 活跃门过滤 + -> 手部区域(无有效手部时使用人体框兜底) + -> 与固定车门危险区 mask 计算二维风险 + -> causal_results.jsonl +``` + +本版本不包含深度估计和 EdgeTAM。输出是二维图像风险,不是物理距离,也不是安全认证结论。 + +## 2. 目录结构 + +```text +run_risk.py 主入口 +requirements-realtime-gpu.txt CUDA 推理依赖 +requirements-tensorrt-windows.txt Windows TensorRT 可选依赖 +models/ + yolo11s.onnx 人体检测模型 + rtmw-l-384.onnx WholeBody 关键点模型 +annotations/ + constant_door_mask.json 当前固定机位车门危险区 + door_zone_multifeature.json 当前前门/后门多特征标定 +pipeline/ 推理、融合、门区和风险计算代码 +``` + +`annotations` 中的两个 JSON 都与摄像头机位相关。当前参数来自研发临时机位;换成实车机位后必须重新标定和验证,不能直接将临时机位结论作为量产参数。 + +## 3. 环境安装 + +推荐 Python 3.10~3.12 和 NVIDIA CUDA GPU。先安装与目标机 CUDA 或 JetPack 匹配的 PyTorch,再安装其余依赖: + +```powershell +python -m venv .venv +.\.venv\Scripts\Activate.ps1 +python -m pip install --upgrade pip +pip install -r requirements-realtime-gpu.txt +``` + +不要同时安装 CPU 版 `onnxruntime` 和 `onnxruntime-gpu`。Jetson Orin 应优先使用 NVIDIA 针对对应 JetPack 发布的 PyTorch/torchvision,而不是强制使用桌面 wheel。 + +如需在 Windows 上使用 RTMW TensorRT Execution Provider,再执行: + +```powershell +pip install -r requirements-tensorrt-windows.txt +``` + +## 4. 运行 + +### 4.1 固定车门危险区 + +以后门 CAN=0、前门未进入电吸范围为例: + +```powershell +python run_risk.py ` + --video D:\data\segment_008.mp4 ` + --constant-door-mask annotations\constant_door_mask.json ` + --door-zone-config annotations\door_zone_multifeature.json ` + --active-door rear ` + --output outputs\seg_08_rear ` + --det-device 0 ` + --pose-device cuda ` + --write-video +``` + +`--active-door` 对应当前 CAN=0 的车门: + +- `front`:只有前门进入电吸范围; +- `rear`:只有后门进入电吸范围; +- `both`:前后门都进入电吸范围; +- `none`:两门都不进行风险判断。 + +当前命令行参数对整个视频保持不变,用于离线部署验证。实车 CAN 随帧变化时,集成层需要把每帧实际 CAN 状态传给门级风险选择逻辑。 + +不需要叠加视频时不要传 `--write-video`,可减少编码和磁盘 I/O。完整参数说明: + +```powershell +python run_risk.py --help +``` + +### 4.2 TensorRT RTMW + +```powershell +python run_risk.py ` + --video D:\data\test.mp4 ` + --constant-door-mask annotations\constant_door_mask.json ` + --active-door rear ` + --output outputs\test_trt ` + --pose-provider tensorrt ` + --pose-device cuda +``` + +首次运行会在 `models/rtmw_l_trt_cache` 生成 TensorRT 缓存,该缓存与目标 GPU、TensorRT 版本和运行环境相关,不随部署包预置。 + +## 5. 输出文件 + +输出目录包含: + +- `causal_results.jsonl`:逐帧因果结果,一行一个 JSON 对象,是 Demo 对接的主要接口; +- `summary.json`:模型、帧数、吞吐、延迟及风险统计; +- `rtmw_risk_overlay.mp4`:仅在传入 `--write-video` 时生成。 + +`causal_results.jsonl` 每行顶层字段: + +| 字段 | 含义 | +|---|---| +| `frame_index` | 从 0 开始的视频帧号 | +| `track_ids` | 当前帧人体轨迹 ID 数组 | +| `boxes` | 与 `track_ids` 同序的人体框,格式 `[x1,y1,x2,y2]` | +| `skeletons` | 与检测人体对齐的 133 点融合骨骼 | +| `active_door` | 本次运行指定的 CAN=0 门:`front/rear/both/none` | +| `door_assignments` | 每个轨迹的前门/后门归属及特征解释 | +| `door_risks` | `front` 和 `rear` 两扇门各自的最终风险 | +| `risk` | 经过 CAN 和门区过滤后供业务使用的当前风险 | +| `ungated_risk` | 未经过前后门/CAN 过滤的原始二维风险,仅用于诊断 | + +数组关联规则:`boxes[i]`、`track_ids[i]`、`skeletons[i].person_index == i`、`door_assignments[i].person_index == i` 表示同一个人。跨帧关联应使用 `track_id`,不要依赖数组下标。 + +## 6. `risk` 的含义 + +### 6.1 应读取哪个字段 + +单门 CAN=0 时,业务防夹建议读取: + +```text +risk.risk_type +risk.risk_level +risk.risk_score +risk.decision +``` + +需要同时展示前后门时分别读取: + +```text +door_risks.front +door_risks.rear +``` + +`ungated_risk` 只用于排查“图像上是否靠近危险区”,不能直接代替门级最终结论,否则会绕过前后门归属和 CAN 过滤。 + +### 6.2 风险标签 + +`risk_type` 是带门位置的最终风险标签: + +| `risk_type` | `risk_level` | 含义 | +|---|---|---| +| `FRONT_CLEAR` / `REAR_CLEAR` | `clear` | 对应活跃门没有风险 | +| `FRONT_WATCH` / `REAR_WATCH` | `watch` | 进入关注距离,但未达到 warning | +| `FRONT_WARNING` / `REAR_WARNING` | `warning` | 距离达到 warning 阈值 | +| `FRONT_DANGER` / `REAR_DANGER` | `danger` | 人体风险区域与车门危险区相交 | +| `FRONT_UNKNOWN` / `REAR_UNKNOWN` | `unknown` | 人物处于 `transition`,无法可靠确定前后门 | +| `FRONT_INACTIVE` / `REAR_INACTIVE` | `inactive` | 该门 CAN 不活跃,不计算防夹风险 | +| `NO_ACTIVE_DOOR` | `inactive` | 前后门均不活跃 | + +对应的 `decision`: + +| `decision` | 含义 | +|---|---| +| `DANGER_INTERSECTION` | 风险区域与车门 mask 有像素相交 | +| `WARNING_NEAR` | 相对距离小于等于 warning 阈值 | +| `WATCH` | 相对距离处于 warning 与 release 之间 | +| `CLEAR` | 相对距离大于 release 阈值 | +| `CLEAR_NO_PERSON_ASSIGNED_TO_ACTIVE_DOOR` | 没有人被分配给该活跃门 | +| `EVIDENCE_UNAVAILABLE_TRANSITION_ZONE` | 存在 `transition` 人员,门归属不确定 | +| `DOOR_CAN_NOT_ACTIVE` | 该门 CAN 不活跃 | +| `NO_DOOR_CAN_ACTIVE` | 没有活跃门 | + +默认阈值: + +```text +warning_distance_relative = 0.30 +release_distance_relative = 0.45 +``` + +对每个风险区域: + +```text +distance_relative = min_distance_px / sqrt(region_area_px) +risk_score = clip(1 - distance_relative / release_distance_relative, 0, 1) +``` + +只要 `door_overlap_px > 0`,就强制 `risk_score=1.0` 且等级为 `danger`。因此 `risk_score` 是归一化二维接近程度,不是概率,也不是厘米/毫米距离。 + +### 6.3 `regions` 与证据来源 + +每个门风险中的 `regions` 保存独立人体区域的解释信息,常用字段包括: + +- `track_id`、`side`:所属轨迹和左右手; +- `source`:`RTMW_HAND_KEYPOINTS` 或 `YOLO_BODY_BOX_FALLBACK`; +- `region_area_px`:风险区域面积; +- `door_overlap_px`、`region_overlap_ratio`:与车门 mask 的相交量; +- `min_distance_px`:区域到车门 mask 的最小像素距离; +- `region_scale_px`:`sqrt(region_area_px)`; +- `distance_relative`:尺度归一化距离; +- `risk_score`、`risk_level`、`decision`:该区域自己的风险结果。 + +存在可用手部时,每只手用 21 点凸包计算风险;一个人没有任何可用手部时,才使用整个人体框兜底。人体框兜底更保守,也更容易产生误报。 + +### 6.4 `transition` 的当前行为 + +`door_assignments[].door_zone` 的位置标签为: + +- `front`:归属前门; +- `rear`:归属后门; +- `transition`:前后门证据不足或位于过渡区; +- `unassigned`:人体尺度低于有效阈值,不参与门级风险。 + +当前 v9.10 中,`transition` 人员即使在 `ungated_risk` 中距离很近,也不会直接变成 `FRONT_WARNING/REAR_WARNING` 或 `DANGER`,而是让活跃门输出 `*_UNKNOWN`,其 `risk_score` 为 `null`。Demo 必须显式展示或处理 `unknown`,不能把它当成 `clear`。这是当前版本行为,不代表最终量产安全策略。 + +## 7. `skeletons` 的含义与可视化对接 + +### 7.1 数据结构 + +每个人的骨骼对象如下: + +```json +{ + "track_id": 1, + "person_index": 0, + "layout": "coco_wholebody_133", + "keypoints": [[x0, y0], [x1, y1]], + "metadata": { + "left": {}, + "right": {} + } +} +``` + +- `keypoints` 实际固定为 `133 x 2`,示例中省略了其余点; +- 坐标单位是原视频像素,原点在左上角,x 向右、y 向下; +- 坐标保留 3 位小数; +- 这里没有逐点置信度,`metadata` 提供的是手臂/手部融合后的状态; +- `keypoints` 使用的正是当前叠加视频 `draw_fused` 使用的融合结果。 + +### 7.2 COCO-WholeBody 133 点索引 + +| 索引 | 含义 | +|---|---| +| `0` | nose | +| `1/2` | left/right eye | +| `3/4` | left/right ear | +| `5/6` | left/right shoulder | +| `7/8` | left/right elbow | +| `9/10` | left/right wrist | +| `11/12` | left/right hip | +| `13/14` | left/right knee | +| `15/16` | left/right ankle | +| `17/18/19` | left big toe / small toe / heel | +| `20/21/22` | right big toe / small toe / heel | +| `23–90` | 68 个面部关键点 | +| `91–111` | 左手 21 点 | +| `112–132` | 右手 21 点 | + +每只手的局部 21 点顺序: + +```text +0 wrist +1-4 thumb +5-8 index finger +9-12 middle finger +13-16 ring finger +17-20 little finger +``` + +左手局部索引需要加 91,右手局部索引需要加 112,才能得到 `keypoints` 中的全局索引。 + +### 7.3 与当前叠加视频一致的绘制规则 + +当前风险叠加视频只绘制手臂和双手,不绘制面部、躯干和腿部。手臂连线: + +```text +(5,7), (7,9) 左肩-左肘-左腕 +(6,8), (8,10) 右肩-右肘-右腕 +``` + +每只手使用以下局部连线,分别作用到 `91–111` 和 `112–132`: + +```text +(0,1),(1,2),(2,3),(3,4) +(0,5),(5,6),(6,7),(7,8) +(0,9),(9,10),(10,11),(11,12) +(0,13),(13,14),(14,15),(15,16) +(0,17),(17,18),(18,19),(19,20) +``` + +为了与现有视频表现一致: + +- `metadata[side].limb_state == "consensus"`:手臂画实线,否则画虚线; +- `metadata[side].hand_state == "rejected"`:不画该手; +- 手未被拒绝且 `distance_eligible == true`:手部画实线; +- 手未被拒绝但 `distance_eligible == false`:手部画虚线; +- `alarm_eligible == true` 表示该手允许进入 risk 区域计算。 + +Demo 如果只需要复现当前可视化,读取上述 48 个点即可;如果后续需要完整人体展示,可以使用全部 133 点,但应自行补充完整 WholeBody 连线定义。 + +## 8. `door_assignments` 对接说明 + +常用字段: + +- `track_id`、`person_index`:与检测框和骨骼关联; +- `door_zone`:经过最多 5 帧因果中值后的 `front/rear/transition/unassigned`; +- `raw_door_zone`:当前帧未经时序中值稳定的标签; +- `front_probability`:当前帧前门概率; +- `smoothed_front_probability`:因果时序中值; +- `confidence`:相对 0.5 的归属置信度,不是人体检测置信度; +- `pose_feature_count`:本帧可用骨骼特征数量; +- `features`、`feature_frontness`:标定特征值和各特征前门贡献; +- `history_frames`:当前轨迹已用于中值的历史帧数。 + +当前标定阈值为:`smoothed_front_probability >= 0.72` 判为前门,`<= 0.28` 判为后门,中间为 `transition`。这些参数应随实车机位重新验证。 + +## 9. Demo 集成注意事项 + +1. 每帧先按 `track_id` 关联检测框、骨骼、门区和风险,避免多人时按数组顺序长期跟踪。 +2. 主界面风险展示使用 `risk`;需要前后门双状态时使用 `door_risks.front/rear`。 +3. `unknown`、`inactive` 和 `clear` 是三种不同状态,不能合并显示。 +4. `risk_score == null` 表示该状态没有可用数值风险,不应转换成 0。 +5. `ungated_risk` 只用于诊断叠加,不能作为最终防夹指令。 +6. 更换分辨率或裁剪策略后必须核对车门 mask、骨骼坐标与视频坐标是否仍一致。 +7. 当前系统可能把玻璃倒影或反光误检成人,部署 Demo 应保留原视频、检测框、`track_id` 和风险解释字段用于问题回溯。 + diff --git a/README.md b/README.md index d1a7025..3af6e70 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,205 @@ -# Vision Anti-Pinch +# vision-anti-pinch-0923 -C++ / TensorRT 实时摄像头风险推理,算法来自最新 run_risk.py。 -持续取图、推理并更新内存中的 FrameResult;可视化可选。 +以 Orin `~/vision-anti-pinch` 的 V4L2 MMAP 摄像头及 USBCANFD 模块为基线,接入 CMS v9.10 `run_risk.py` 的完整风险流程。模型及 GPU 推理代码来自远端 `~/vision-anti-pinch-0920`。 -## Orin 直接运行 +``` +基线 V4L2 MMAP → NPP UYVY 转 BGR → 最新帧槽位 + → YOLO11s TensorRT → RTMW-L TensorRT(含小人遮挡隔离推理) + → Python 原版轨迹 / 手臂手部融合 / 全局手关联 + → 骨骼主导的前后门归属 → 固定 mask 风险 → 逐帧 CAN 活跃门过滤 + → 内存中的最新只读结果(可选 JSONL / 浏览器预览) +``` -适用环境:Jetson AGX Orin、JetPack 5.1.2 / L4T R35.4.1、CUDA 11.4、TensorRT 8.5.2、OpenCV 4.5.4。 -仓库已包含该板端编译的程序和重新构建的 TensorRT 引擎。 +## 仓库分支与 Orin 直接运行包 + +- `main`:原 CMS v9.10 Python/ONNX 部署包。 +- `inference-only`:保留原 main 的纯 C++ TensorRT 推理版本。 +- `use-can`(本分支):0923 CAN 集成版本。 + +本分支已提供可单独复制的 `orin/` 运行包,包含预编译库和 TensorRT 模型: ```bash -git clone https://git.kendeji.fun/zmv/vision-anti-pinch.git +git clone --branch use-can https://git.kendeji.fun/zmv/vision-anti-pinch.git cd vision-anti-pinch/orin -./scripts/initialize_camera.sh # 开机后初始化 /dev/video5 摄像头链路 -./run.sh # 持续推理,结果只保存在内存 +./scripts/initialize_camera.sh # 开机后需要初始化摄像头时执行 +./run.sh # 默认无可视化,结果保存在内存 +./run.sh --visualize # 可选预览 ``` -可选板端本地可视化: - -```bash -./run.sh --visualize -``` - -Ctrl+C / SIGTERM 停止程序。 -关闭预览窗口或按 q/Esc 只关闭预览,推理继续。 - -摄像头为 /dev/video5,1920×1536 UYVY,30 FPS。 -当前 door mask 是指定的 constant_door_mask.json 副本,标定状态为 false;装车后应更换与实际画面匹配的门区并更新标定状态。 - -## 下游获取结果 - -main.cpp 注释中也包含以下示例。下游通过自己的调用位置或线程读取: - -```cpp -auto result = pipeline.latest(); -if (result) { - const auto& risk = result->risk; - const auto& people = result->persons; - // result->frame_index / track_ids / boxes - // result->image / door_mask_pixels / capture / timing - // people[i].selected / smoothed / temporal:各 133 个关键点 -} -``` - -latest() 返回 shared_ptr;首帧尚未完成时为空。 -公共定义位于 include/camera_pipeline.hpp 和 include/frame_result.hpp。 - -## 从源码构建 +`orin/run.sh` 通过相对目录定位运行库、模型与标定,使用系统 Python,无需现场编译。目标环境及下游调用说明见 `orin/README.md`。 +源码变更后,在目标 Orin 构建并执行 `scripts/package_orin.sh` 重新生成运行包;`ENGINE_DIR` 和 `DRIVER_DIR` 可指定模型/驱动目录。 + +## 两端目录和环境 + +- 本机:`/home/thor/文档/vision-anti-pinch-0923` +- Orin:`/home/orin/vision-anti-pinch-0923` +- 目标推理环境:Orin,JetPack R35.4.1、CUDA 11.4、系统 Python 3.8、原生 TensorRT。 +- 本机保存完整源码、测试报告、模型副本;本机是 Thor / R38,未发现 `/dev/video*`。Orin 的序列化 engine 不能直接作为 Thor 的本机模型使用,需在 Thor 上另行转换。本次实时采集/推理在 Orin,浏览器可在本机查看。 +- 远端 `models/engines` 软链接到 `../../vision-anti-pinch-0920/orin/engines`,避免重复占用有限磁盘。不要删除被引用的 0920 模型。 +- 原有远端 `vision-anti-pinch` / `vision-anti-pinch-0920` 源码均未修改。测试时已停止占用 `/dev/video5` 的旧 0920 演示进程,0923 可独立启动。 + +## 编译和运行(在 Orin) ```bash +cd ~/vision-anti-pinch-0923 ./scripts/build.sh +# 开机后如 /dev/video5 不存在,加载已部署的 0920 摄像头驱动: ./scripts/initialize_camera.sh -./run_camera.sh +# 编译也可使用 make +./run_camera.sh --active-door can --can-side left +# 等价入口:python3 run_risk.py --active-door can --can-side left ``` -源码构建要求 CMake 3.24+、CUDA/NPP、TensorRT 和 OpenCV 开发依赖。 -构建脚本会优先使用 Orin 上已有的 ~/miniconda3/envs/yolo/bin/cmake。 -源码配置直接使用 orin/engines/ 中的板端引擎。该引擎仅适用于上述 Orin 环境;仓库不包含 ONNX 或模型转换脚本。 -独立库目标为 camera_risk_core;可视化在 camera_risk_visualizer。 +默认只在内存中发布结果,不创建结果目录,不绘制或编码图像,不启动 HTTP 服务。 -## 目录 +后台启动、停止: -- src/、include/:采集、推理、结果变量及可选绘制。 -- config/:源码构建程序的配置和固定门区。 -- scripts/:构建和摄像头初始化脚本。 -- orin/:已编译程序、TensorRT 引擎、配置、当前 GMSL 驱动及启动脚本。 -- third_party/:nlohmann JSON 及其许可证。 +```bash +./scripts/start.sh # 无可视化 +./scripts/stop.sh +./scripts/start.sh --visualize # 可选浏览器预览 +``` -NPP 用于 UYVY 转换、YOLO 缩放填充、RTMW 仿射裁剪;CUDA 用于通道转换与归一化。 -风险几何计算仍包含 CPU/OpenCV 操作;算法内部的临时 JSON 对象只在内存中使用。 +默认从 `/dev/video5` 采集 UYVY 1920×1536,驱动当前为 30 FPS。驱动不支持 `VIDIOC_G_PARM`,程序会打印警告并继续采集,命令行 fps 不代表驱动一定支持修改。 -当前摄像头驱动启动时偶发首帧 ERROR,应用会丢弃并计数;持续错误、采集超时或推理错误会明确报错并退出。 -现有 GMSL 驱动停止采集时可产生 videobuf2 缓冲区告警,v4l2-ctl 同样复现;需在驱动侧完成量产修复和验证。 +- 开启 `--visualize` 后,预览:[http://192.168.195.100:8765](http://192.168.195.100:8765) +- 开启 `--visualize` 后,最新结果:[http://192.168.195.100:8765/result.json](http://192.168.195.100:8765/result.json) +- 开启 `--visualize` 后,最新图像:[http://192.168.195.100:8765/frame.jpg](http://192.168.195.100:8765/frame.jpg) +- 后台进程日志:`logs/live.log`,PID:`logs/camera.pid`;加保存开关后,后台结果写入 `outputs/live/`。 +- `--visualize` 开启预览;仅设置 `--preview-port` 不会开启预览。监听地址默认 `0.0.0.0:8765`,可用 `--preview-host 127.0.0.1` 限制为本机。可视化在独立观察线程中绘制和编码,只保留最新待绘制帧。端口占用或绘制失败不会终止推理;关闭浏览器也不会停止推理。 + +摄像头限定时长、模拟门状态: + +```bash +./run_camera.sh --no-can --active-door both --duration 30 --save-results --output outputs/demo +``` + +有人视频回放(同一 TensorRT/融合/风险链路): + +```bash +./run_camera.sh --video tests/person-test.mp4 --no-can --active-door both \ + --max-frames 150 --save-results --save-pose-records --output outputs/replay +``` + +`tests/person-test.mp4` 来自用户提供的 `segment_009.mp4` 第 10 秒起的 150 帧片段。 + +## 下游直接读取结果变量 + +参考 0920 的 `LatestResult` / `CameraPipeline.latest()`,0923 提供同进程 Python 接口: + +```python +from run_camera import CameraPipeline, parse_args + +args = parse_args([]) # 默认 CAN 模式;不打开可视化,不保存文件 +with CameraPipeline(args) as pipeline: + result = pipeline.wait_for_result(timeout=10) # 等待第一帧,可选 + # 在下游自己的循环/线程中读取当前完整快照: + result = pipeline.latest_result # 等价于 pipeline.latest() + if result is not None: + risk = result["risk"] + door_risks = result["door_risks"] + skeletons = result["skeletons"] + can = result["can"] + print(result["frame_index"], risk["risk_type"], risk["risk_score"]) +``` + +完整持续读取示例:`examples/read_latest.py`,在 Orin 执行。示例会自己启动推理并占用摄像头,运行前先停止已有后台进程: + +```bash +./scripts/stop.sh +python3 examples/read_latest.py +# 或开启可视化: +python3 examples/read_latest.py --visualize +``` + +- `latest_result` 是单个最新结果变量,首帧前为 `None`。每帧完成风险计算后发布,早于任何可选绘制或文件写入。 +- 快照深度只读:字典使用只读映射,数组使用 tuple;字段和索引含义与原 JSON 一致。旧快照不会随下一帧变化,多个读取线程互不消费或修改结果。 +- 只保留最新一帧,没有结果队列;下游处理慢可跳过中间帧。需要每帧历史时显式开启 `--save-results`。 +- `pipeline.wait_for_result(after_frame_index, timeout)` 是可选等待接口,返回更新的最新结果;超时或结束且无新帧时返回 `None`。 +- `pipeline.request_stop()` 请求停止,`pipeline.join()` 等待退出并向调用方传播推理异常;停止后可读取最后快照及 `pipeline.summary`。使用 `with` 自动停止并回收资源。 +- 停止后的快照只是最后结果;持续控制时应同时检查 `pipeline.running()` 及帧序号/时间戳,避免使用旧结果。 +- 需要修改副本或 JSON 序列化时使用 `from run_camera import result_to_dict`,再调用 `result_to_dict(result)`。 +- 变量属于创建 `CameraPipeline` 的 Python 进程。另一个进程或 C++ 程序不能直接 import 读取后台服务的变量,需要另行使用 IPC/HTTP 接口;当前没有新增 C++ 风险结果 ABI。 + +## 可选输出开关 + +| 参数 | 行为 | +|---|---| +| 无输出参数 | 只发布内存结果,不绘制、不保存结果文件 | +| `--visualize` | 开启独立可视化线程和 HTTP 预览 | +| `--save-results` | 保存逐帧 JSONL 及约每 10 秒的 latest.json | +| `--save-snapshots` | 约每 10 秒绘制并保存 latest.jpg,无 HTTP 服务 | +| `--save-pose-records` | 保存诊断姿态 JSONL | +| `--write-video` | 绘制并保存叠加 MP4,无需打开预览 | + +输出开关可组合。`--output` 仅指定保存目录,不会自动开启保存。未开启保存时,旧输出文件保留但不会更新。任一保存开关开启后,停止时额外保存 summary.json;默认内存模式的统计保存在 `pipeline.summary` 并打印到终端。 + +恢复此前的预览与文件输出行为: + +```bash +./run_camera.sh --visualize --save-results --save-snapshots --output outputs/demo +``` + +## CAN 约定 + +按用户确认的 `0x391` 数据布局: + +| 字节 | 车门 | +|---|---| +| data[0] | 左前 | +| data[1] | 右前 | +| data[2] | 左后 | +| data[3] | 右后 | + +- `--can-side left` 使用 data[0]/data[2];`right` 使用 data[1]/data[3]。默认 left,请按摄像头安装侧选择。 +- 值为 0 时对应门活跃,每帧读取最新 CAN 快照。有效报文至少需要 4 字节。 +- 未收到有效报文或超过 `--can-timeout-ms`(默认 1000 ms),整体输出 `CAN_UNKNOWN`,门级输出 `FRONT_UNKNOWN/REAR_UNKNOWN`,分数为 null。 +- 此时 `active_door=none` 仅为内部无有效活跃门输入,业务必须读取 `risk` 和 `can.valid`,不能将其解释为已确认两门关闭。 +- 显式 `--active-door front/rear/both/none` 是模拟模式,输出 `can.source=simulation`,预览显示 CAN SIMULATION。`--no-can` 要求显式选择模拟状态。 +- 本项目提供最终风险结果;基线未提供防夹执行器的 CAN 指令协议,因此没有自行添加执行器报文。 +- 本次 USB-CAN `VCI_OpenDevice` 返回失败,`lsusb` 中未见 USB-CAN 设备;真实 0x391 报文链路尚未验证。连接适配器后重新启动程序;字节映射及门状态组合通过软件测试。 + +## 风险行为与机位标定 + +风险算法、默认 warning=0.30 / release=0.45、133 点骨骼、track_id、前后门归属、transition→unknown、无有效手部时人体框兜底均沿用原版。详见 `README-risk-upstream.md`。 + +`annotations/constant_door_mask.json` 和 `door_zone_multifeature.json` 原样复制,属于原研发机位。当前室内摄像头位置与其不一致,默认输出 `calibration_verified=false`,预览显示 CALIBRATION UNVERIFIED。实车验证需更换标定文件;`--calibration-verified` 仅标记经人工验证的标定,不会自动标定。 + +当前实时场景没有人,约 29 FPS 是该场景的实测值,不能当作多人满负载帧率。 + +## 优化与输出 + +- 重用 0920 的常驻 TensorRT engine、CUDA/NPP 预处理、显存及锁页缓存、GPU UYVY 转换。 +- 独立取帧线程只保留最新帧,主动丢弃旧帧,避免积压;不像 0920 那样单独并行检测线程,完整 Python 融合阶段按结果顺序执行。 +- 风险 mask / 距离变换按原版缓存;开启预览时默认每 3 帧提交一次待绘制图像;开启快照保存时每 10 秒一次。 +- 长期运行清理过期轨迹,计时统计仅保留最近 3000 帧。 +- 开启 `--save-results` 后,`causal_results.jsonl` 默认每 32 MiB 轮换,保留 `.1` 和 `.2`;`--jsonl-max-mb 0` 可禁用轮换。读取全部历史时按 `.2 → .1 → 当前文件` 顺序处理。 +- `--save-pose-records` 额外保存同样轮换的诊断姿态记录;`--write-video` 录制叠加 MP4(视频不轮换,建议配合 `--duration`)。 +- 文件输出遵循上面的独立开关;关闭可视化仍可完整读取内存结果。 +- 新增 `capture`、`can`、`capture_to_result_ms`、`calibration_verified` 字段,原版核心 JSON 字段保留。 +- 驱动原始时间戳存在时钟偏移,保存在 `capture.driver_timestamp_ms` 供诊断。延迟采用主机单调时钟在 DQBUF 后取样,表示“主机取帧到风险结果”,不包含曝光到驱动交付的时间。 + +## 文件关系与测试 + +- `main.cpp`, `v4l2_capture.*`, `can_comm.*`, `include/zcan.h`, `lib/`:基线工程。新工程修正错误 V4L2 buffer 处理;旧 main 同步修正 CAN 字节解析。 +- `native/native_api.cpp`:采集线程、CAN 快照、TensorRT 的 ctypes C 接口。 +- `accelerator/`:远端 0920 源码快照,当前构建只选取 TensorRT/预处理/检测/姿态源文件。 +- `pipeline/`:原版 Python 算法,推理适配在 `native_backend.py`;ONNX/Ultralytics 的可选导入移到旧离线入口,原版风险公式不变。 +- `Makefile.baseline` 和 `make baseline`:旧基线演示程序的编译方式;默认 `make` 编译新的原生共享库。 +- `pipeline/latest_result.py`:线程安全的单结果发布槽位及不可变快照。 +- `examples/read_latest.py`:同进程下游读取示例。 +- `tests/test_latest_result.py`:结果所有权、线程生命周期、可选输出、独立可视化及异常传播测试。 +- `tests/test_risk_integration.py`:CAN 左右门组合、失效状态、手部/人体兜底、transition、轨迹回收、日志轮换测试。 +- `TEST_REPORT.md`:实测结果和限制。 + +```bash +python3 -m unittest discover -s tests -v +``` + +本机重新部署源码(会使用 SSH 交互认证,不保存密码): + +```bash +./scripts/deploy.sh orin@192.168.195.100 +``` + +重新编译共享库前应先停止 0923 运行进程,再启动新进程加载新库。 diff --git a/TEST_REPORT.md b/TEST_REPORT.md new file mode 100644 index 0000000..51b00e4 --- /dev/null +++ b/TEST_REPORT.md @@ -0,0 +1,56 @@ +# 2026-09-23 集成验证 + +执行设备:192.168.195.100 / Orin;摄像头 /dev/video5,UYVY 1920×1536。当前机位朝向室内设备,没有测试人员;用户确认暂不调整机位。 + +| 验证 | 结果 | +|---|---| +| 原生 C++/CUDA 共享库 | Orin Release 编译通过 | +| 摄像头 + CAN 模式,30 秒 | 882 帧,29.399 FPS,无运行异常 | +| 主机取帧到风险结果 | 均值 42.369 ms,P95 57.368 ms | +| latest-frame 策略 | 30 秒期间丢弃 16 个积压帧 | +| 真实 CAN | USB-CAN 打开失败,lsusb 未见该设备;882 帧均为 CAN_UNKNOWN,score=null | +| 有人视频 150 帧回放 | 32.898 FPS,31 帧有 1 人,119 帧无有效人体框 | +| RTMW 骨骼 | 31 个人体记录,每个 133 点 | +| 风险证据 | 22 个手部区域,9 个人体框兜底区域 | +| 视频门级风险 | clear 132,watch 5,warning 2,unknown 11 | +| 原始 run_risk.py 对照 | 同一姿态记录重放 150 帧,核心输出完全一致 | +| 行为测试 | 本机与 Orin 的 8 项测试均通过 | +| HTTP 实时预览 | 本机访问远端 /result.json 成功,连续返回新帧 | + +对照方式:将远端 `outputs/person-replay/pose_records.jsonl` 下载到本机,用用户原始工程的 `run_risk.py --pose-jsonl` 运行,逐帧比较原始 JSON 的所有顶层字段,包括 skeletons、door_assignments、door_risks、risk、ungated_risk。仅排除不同工程目录导致的绝对 mask 路径差异;150 帧无差异。**此项对照验证相同姿态输入下的风险集成,不是 TensorRT 与 ONNX 输出的数值误差测试。** + +证据: + +- `outputs/camera-can/summary.json` +- `outputs/person-replay/summary.json` 与 `causal_results.jsonl` +- `outputs/reference-replay/summary.json` 与 `causal_results.jsonl` +- `outputs/reference-parity.json` +- `logs/build.log`, `logs/camera-can.log`, `logs/person-replay.log` + +`outputs/camera-smoke/` 是初次调通记录,使用了不可靠的驱动时间戳,延迟统计无效。已修正计时来源,性能结论以 `camera-can` 为准。 + +未完成的硬件验证:有效 CAN 报文到达与门切换、真实摄像头下人员/手部靠近门区、实车机位 mask 与前后门参数标定。当前无法据此宣称已完成实车防夹效果验收。 + +本机没有摄像头设备节点;本机完成源码/模型归档、风险对照及行为测试,通过网络预览 Orin 的实时结果。 + + +## 最新结果变量与可选可视化改造 + +已对照重启后远端 0920 的 `include/latest_result.hpp` 和 `src/main.cpp`,采用默认关闭可视化、单个不可变最新快照、start/latest/request_stop/join 生命周期。 + +- 本机与 Orin:17 项测试通过,覆盖原有风险测试及只读快照、旧快照保持、跨线程等待/停止、错误传播、默认无绘制/HTTP/结果文件、JSON 与内存结果一致、预览端口失败不影响推理、独立可视化线程。 +- Orin 真实 TensorRT 视频回放:下游示例读取 90 帧,27.321 FPS;未开启可视化和文件保存。保留 watch/warning/unknown 等风险输出。 +- Orin 真实摄像头:下游示例读取 90 帧,28.858 FPS;主机取帧至结果均值 32.341 ms;关闭可视化,没有创建指定输出目录。 +- `--visualize` 实机运行 15 秒:成功通过 HTTP 读取逐帧结果及 JPEG 图像;未开启文件保存,没有创建指定输出目录。 +- 后台运行入口默认无可视化;开启预览需显式加 `--visualize`。 +- 重启后摄像头节点未自动生成。0920 初始化脚本因驱动缺少 vermagic 元数据而判定不匹配;0923 新增初始化脚本,存在 vermagic 时检查内核版本,缺失时交给正常 insmod 的内核检查,未使用强制加载参数。加载原有 0920 驱动后 /dev/video5 恢复。 + +日志:`logs/tests-optional-local.log`、`logs/tests-optional-orin.log`、`logs/result-api-video.log`、`logs/result-api-camera.log`、`logs/optional-preview.log`、`logs/optional-preview-probe.json`。 + +## use-can Orin 可运行包验证 + +- 独立运行包位于 `orin/`:包含预编译 ARM64 原生库、TensorRT 引擎、Python 风险代码、CAN USB 库、GMSL 驱动和 ./run.sh。 +- 在 Orin 新建的独立临时目录复制整个运行包,SHA256SUMS 全部通过。 +- 从临时目录执行 `./run.sh --max-frames 90`,实际摄像头 90 帧完成,29.080 FPS,主机取帧至风险结果平均 36.310 ms;无结果文件输出。 +- 原生库 RUNPATH 为 `$ORIGIN/../lib:/usr/local/cuda/lib64`,启动脚本按自身位置定位所有项目资产。 +- 系统依赖仍为目标 JetPack 的 CUDA / TensorRT / OpenCV 与 Python numpy/cv2,不包含操作系统或完整 Python 环境。 diff --git a/accelerator/.gitattributes b/accelerator/.gitattributes new file mode 100644 index 0000000..5f609e2 --- /dev/null +++ b/accelerator/.gitattributes @@ -0,0 +1,5 @@ +*.sh text eol=lf +*.engine -text +*.ko -text +/orin/** -text +/config/door_mask.json -text diff --git a/accelerator/.gitignore b/accelerator/.gitignore new file mode 100644 index 0000000..4097644 --- /dev/null +++ b/accelerator/.gitignore @@ -0,0 +1,4 @@ +/build/ +/engines/ +/logs/ +*.tmp diff --git a/accelerator/CMakeLists.txt b/accelerator/CMakeLists.txt new file mode 100644 index 0000000..1a5dede --- /dev/null +++ b/accelerator/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.24) +if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) + set(CMAKE_CUDA_ARCHITECTURES native) +endif() +project(camera_risk LANGUAGES CXX CUDA) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CUDA_STANDARD 17) +find_package(CUDAToolkit REQUIRED) +find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs highgui) +find_package(Threads REQUIRED) +find_path(TENSORRT_INCLUDE_DIR NvInfer.h PATH_SUFFIXES aarch64-linux-gnu x86_64-linux-gnu REQUIRED) +find_library(TENSORRT_LIBRARY nvinfer REQUIRED) +add_library(camera_risk_core + src/trt_engine.cpp src/pose_engine.cu src/gpu_preprocess.cu src/uyvy_converter.cu + src/detector.cpp src/door_risk.cpp src/camera.cpp src/camera_pipeline.cpp src/config.cpp) +target_include_directories(camera_risk_core PUBLIC include third_party ${TENSORRT_INCLUDE_DIR} ${OpenCV_INCLUDE_DIRS}) +target_link_libraries(camera_risk_core PUBLIC ${TENSORRT_LIBRARY} ${OpenCV_LIBS} Threads::Threads CUDA::cudart CUDA::nppc CUDA::nppig CUDA::nppidei CUDA::nppicc) +target_compile_options(camera_risk_core PRIVATE $<$:-Wall;-Wextra;-Wpedantic>) +add_library(camera_risk_visualizer src/visualizer.cpp) +target_link_libraries(camera_risk_visualizer PUBLIC camera_risk_core) +add_executable(camera_risk src/main.cpp) +target_link_libraries(camera_risk PRIVATE camera_risk_visualizer) diff --git a/accelerator/README.md b/accelerator/README.md new file mode 100644 index 0000000..1f815a6 --- /dev/null +++ b/accelerator/README.md @@ -0,0 +1,76 @@ +# Vision Anti-Pinch + +C++ / TensorRT 实时摄像头风险推理,算法来自最新 run_risk.py。 +持续取图、推理并更新内存中的 FrameResult;可视化可选。 + +## Orin 直接运行 + +适用环境:Jetson AGX Orin、JetPack 5.1.2 / L4T R35.4.1、CUDA 11.4、TensorRT 8.5.2、OpenCV 4.5.4。 +仓库已包含该板端编译的程序和重新构建的 TensorRT 引擎,无需先编译或转换。 + +```bash +git clone https://git.kendeji.fun/zmv/vision-anti-pinch.git +cd vision-anti-pinch/orin +./scripts/initialize_camera.sh # 开机后初始化 /dev/video5 摄像头链路 +./run.sh # 持续推理,结果只保存在内存 +``` + +可选板端本地可视化: + +```bash +./run.sh --visualize +``` + +Ctrl+C / SIGTERM 停止程序。没有有限帧选项;正常运行和退出不输出统计。 +关闭预览窗口或按 q/Esc 只关闭预览,推理继续。没有图像网络服务、端口转发、JSONL 或视频输出。 + +摄像头为 /dev/video5,1920×1536 UYVY,30 FPS。 +当前 door mask 是指定的 constant_door_mask.json 副本,标定状态为 false;装车后应更换与实际画面匹配的门区并更新标定状态。 +即使不开启可视化,风险计算仍需要门区。 + +## 下游获取结果 + +main.cpp 注释中也包含以下示例。下游通过自己的调用位置或线程读取: + +```cpp +auto result = pipeline.latest(); +if (result) { + const auto& risk = result->risk; + const auto& people = result->persons; + // result->frame_index / track_ids / boxes + // result->image / door_mask_pixels / capture / timing + // people[i].selected / smoothed / temporal:各 133 个关键点 +} +``` + +latest() 返回 shared_ptr;首帧尚未完成时为空。 +读取不删除结果,也不产生消费状态。推理不关心是否有下游读取。 +下游持有的结果保持有效,后续更新不会改变旧快照;历史保存由下游自行负责。 +公共定义位于 include/camera_pipeline.hpp 和 include/frame_result.hpp。 + +## 从源码构建 + +```bash +./scripts/build.sh +./scripts/initialize_camera.sh +./run_camera.sh +``` + +源码构建要求 CMake 3.24+、CUDA/NPP、TensorRT 和 OpenCV 开发依赖。 +构建脚本会优先使用 Orin 上已有的 ~/miniconda3/envs/yolo/bin/cmake。 +源码配置直接使用 orin/engines/ 中的板端引擎。该引擎仅适用于上述 Orin 环境;仓库不包含 ONNX 或模型转换脚本。 +独立库目标为 camera_risk_core;可视化在 camera_risk_visualizer。 + +## 目录 + +- src/、include/:采集、推理、结果变量及可选绘制。 +- config/:源码构建程序的配置和固定门区。 +- scripts/:构建和摄像头初始化脚本。 +- orin/:已编译程序、TensorRT 引擎、配置、当前 GMSL 驱动及启动脚本。 +- third_party/:nlohmann JSON 及其许可证。 + +NPP 用于 UYVY 转换、YOLO 缩放填充、RTMW 仿射裁剪;CUDA 用于通道转换与归一化。 +风险几何计算仍包含 CPU/OpenCV 操作;算法内部的临时 JSON 对象只在内存中使用。 + +当前摄像头驱动启动时偶发首帧 ERROR,应用会丢弃并计数;持续错误、采集超时或推理错误会明确报错并退出。 +现有 GMSL 驱动停止采集时可产生 videobuf2 缓冲区告警,v4l2-ctl 同样复现;需在驱动侧完成量产修复和验证。 diff --git a/config/camera.json b/accelerator/config/camera.json similarity index 100% rename from config/camera.json rename to accelerator/config/camera.json diff --git a/config/door_mask.json b/accelerator/config/door_mask.json similarity index 100% rename from config/door_mask.json rename to accelerator/config/door_mask.json diff --git a/include/bounded_queue.hpp b/accelerator/include/bounded_queue.hpp similarity index 100% rename from include/bounded_queue.hpp rename to accelerator/include/bounded_queue.hpp diff --git a/include/camera.hpp b/accelerator/include/camera.hpp similarity index 100% rename from include/camera.hpp rename to accelerator/include/camera.hpp diff --git a/include/camera_pipeline.hpp b/accelerator/include/camera_pipeline.hpp similarity index 100% rename from include/camera_pipeline.hpp rename to accelerator/include/camera_pipeline.hpp diff --git a/include/common.hpp b/accelerator/include/common.hpp similarity index 100% rename from include/common.hpp rename to accelerator/include/common.hpp diff --git a/include/config.hpp b/accelerator/include/config.hpp similarity index 100% rename from include/config.hpp rename to accelerator/include/config.hpp diff --git a/include/detector.hpp b/accelerator/include/detector.hpp similarity index 100% rename from include/detector.hpp rename to accelerator/include/detector.hpp diff --git a/include/door_risk.hpp b/accelerator/include/door_risk.hpp similarity index 100% rename from include/door_risk.hpp rename to accelerator/include/door_risk.hpp diff --git a/include/frame_result.hpp b/accelerator/include/frame_result.hpp similarity index 100% rename from include/frame_result.hpp rename to accelerator/include/frame_result.hpp diff --git a/include/gpu_preprocess.hpp b/accelerator/include/gpu_preprocess.hpp similarity index 100% rename from include/gpu_preprocess.hpp rename to accelerator/include/gpu_preprocess.hpp diff --git a/include/image.hpp b/accelerator/include/image.hpp similarity index 100% rename from include/image.hpp rename to accelerator/include/image.hpp diff --git a/include/latest_result.hpp b/accelerator/include/latest_result.hpp similarity index 100% rename from include/latest_result.hpp rename to accelerator/include/latest_result.hpp diff --git a/include/pipeline_types.hpp b/accelerator/include/pipeline_types.hpp similarity index 100% rename from include/pipeline_types.hpp rename to accelerator/include/pipeline_types.hpp diff --git a/include/pose_engine.hpp b/accelerator/include/pose_engine.hpp similarity index 100% rename from include/pose_engine.hpp rename to accelerator/include/pose_engine.hpp diff --git a/include/records.hpp b/accelerator/include/records.hpp similarity index 100% rename from include/records.hpp rename to accelerator/include/records.hpp diff --git a/include/result_conversion.hpp b/accelerator/include/result_conversion.hpp similarity index 100% rename from include/result_conversion.hpp rename to accelerator/include/result_conversion.hpp diff --git a/include/stop_signals.hpp b/accelerator/include/stop_signals.hpp similarity index 100% rename from include/stop_signals.hpp rename to accelerator/include/stop_signals.hpp diff --git a/include/trt_engine.hpp b/accelerator/include/trt_engine.hpp similarity index 100% rename from include/trt_engine.hpp rename to accelerator/include/trt_engine.hpp diff --git a/include/uyvy_converter.hpp b/accelerator/include/uyvy_converter.hpp similarity index 100% rename from include/uyvy_converter.hpp rename to accelerator/include/uyvy_converter.hpp diff --git a/include/visualizer.hpp b/accelerator/include/visualizer.hpp similarity index 100% rename from include/visualizer.hpp rename to accelerator/include/visualizer.hpp diff --git a/accelerator/run_camera.sh b/accelerator/run_camera.sh new file mode 100755 index 0000000..c153d56 --- /dev/null +++ b/accelerator/run_camera.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +exec "$root/build/camera_risk" --config "$root/config/camera.json" "$@" diff --git a/accelerator/scripts/build.sh b/accelerator/scripts/build.sh new file mode 100755 index 0000000..5b0fa8d --- /dev/null +++ b/accelerator/scripts/build.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +cmake_bin="${CMAKE_COMMAND:-cmake}" +if [[ -x "$HOME/miniconda3/envs/yolo/bin/cmake" ]]; then cmake_bin="${CMAKE_COMMAND:-$HOME/miniconda3/envs/yolo/bin/cmake}"; fi +"$cmake_bin" -S "$root" -B "$root/build" -DCMAKE_BUILD_TYPE=Release -DCMAKE_CUDA_COMPILER="${CUDACXX:-/usr/local/cuda/bin/nvcc}" "$@" +"$cmake_bin" --build "$root/build" -j4 diff --git a/accelerator/scripts/initialize_camera.sh b/accelerator/scripts/initialize_camera.sh new file mode 100755 index 0000000..8da09bd --- /dev/null +++ b/accelerator/scripts/initialize_camera.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +exec "$root/orin/scripts/initialize_camera.sh" "$@" diff --git a/src/camera.cpp b/accelerator/src/camera.cpp similarity index 100% rename from src/camera.cpp rename to accelerator/src/camera.cpp diff --git a/src/camera_pipeline.cpp b/accelerator/src/camera_pipeline.cpp similarity index 100% rename from src/camera_pipeline.cpp rename to accelerator/src/camera_pipeline.cpp diff --git a/src/config.cpp b/accelerator/src/config.cpp similarity index 100% rename from src/config.cpp rename to accelerator/src/config.cpp diff --git a/src/detector.cpp b/accelerator/src/detector.cpp similarity index 100% rename from src/detector.cpp rename to accelerator/src/detector.cpp diff --git a/src/door_risk.cpp b/accelerator/src/door_risk.cpp similarity index 100% rename from src/door_risk.cpp rename to accelerator/src/door_risk.cpp diff --git a/src/gpu_preprocess.cu b/accelerator/src/gpu_preprocess.cu similarity index 100% rename from src/gpu_preprocess.cu rename to accelerator/src/gpu_preprocess.cu diff --git a/src/main.cpp b/accelerator/src/main.cpp similarity index 100% rename from src/main.cpp rename to accelerator/src/main.cpp diff --git a/src/pose_engine.cu b/accelerator/src/pose_engine.cu similarity index 100% rename from src/pose_engine.cu rename to accelerator/src/pose_engine.cu diff --git a/src/trt_engine.cpp b/accelerator/src/trt_engine.cpp similarity index 100% rename from src/trt_engine.cpp rename to accelerator/src/trt_engine.cpp diff --git a/src/uyvy_converter.cu b/accelerator/src/uyvy_converter.cu similarity index 100% rename from src/uyvy_converter.cu rename to accelerator/src/uyvy_converter.cu diff --git a/src/visualizer.cpp b/accelerator/src/visualizer.cpp similarity index 100% rename from src/visualizer.cpp rename to accelerator/src/visualizer.cpp diff --git a/third_party/nlohmann/LICENSE.MIT b/accelerator/third_party/nlohmann/LICENSE.MIT similarity index 100% rename from third_party/nlohmann/LICENSE.MIT rename to accelerator/third_party/nlohmann/LICENSE.MIT diff --git a/third_party/nlohmann/json.hpp b/accelerator/third_party/nlohmann/json.hpp similarity index 100% rename from third_party/nlohmann/json.hpp rename to accelerator/third_party/nlohmann/json.hpp diff --git a/orin/config/door_mask.json b/annotations/constant_door_mask.json similarity index 100% rename from orin/config/door_mask.json rename to annotations/constant_door_mask.json diff --git a/annotations/door_zone_multifeature.json b/annotations/door_zone_multifeature.json new file mode 100644 index 0000000..3432c66 --- /dev/null +++ b/annotations/door_zone_multifeature.json @@ -0,0 +1,47 @@ +{ + "version": "v9.10-research-calibration-1", + "description": "Temporary-camera calibration from seg_01 and seg_08; recalibrate for the production camera.", + "front_probability_min": 0.72, + "rear_probability_max": 0.28, + "minimum_person_height": 0.4, + "minimum_pose_features": 4, + "history_frames": 5, + "stale_track_frames": 120, + "features": { + "shoulder_center_x": { + "rear": 0.53, + "front": 0.64, + "weight": 1.2 + }, + "shoulder_center_y": { + "rear": 0.54, + "front": 0.46, + "weight": 1.3 + }, + "shoulder_width": { + "rear": 0.14, + "front": 0.2, + "weight": 1.4 + }, + "torso_height": { + "rear": 0.35, + "front": 0.47, + "weight": 1.5 + }, + "hip_center_y": { + "rear": 0.89, + "front": 0.93, + "weight": 0.6 + }, + "box_center_x": { + "rear": 0.48, + "front": 0.58, + "weight": 0.35 + }, + "box_height": { + "rear": 0.7, + "front": 0.82, + "weight": 0.45 + } + } +} diff --git a/build_and_run.sh b/build_and_run.sh new file mode 100644 index 0000000..5ec936a --- /dev/null +++ b/build_and_run.sh @@ -0,0 +1,101 @@ +#!/bin/bash +# build_and_run.sh - 在 Orin 上构建并运行 V4L2 取图 demo +# +# 使用方法: +# ./build_and_run.sh [选项] +# +# 选项: +# --deploy 将源码复制到 Orin 并构建 +# --run 在 Orin 上运行已构建的程序 +# --both 部署并运行 (默认) +# +# 示例: +# ./build_and_run.sh --both +# ./build_and_run.sh --deploy +# ./build_and_run.sh --run --args "-n 100 -v" + +set -e + +# 配置 +ORIN_HOST="192.168.195.100" +ORIN_USER="orin" +ORIN_PASS="${ORIN_PASS:?Set ORIN_PASS locally, or use scripts/deploy.sh for interactive SSH}" +export SSHPASS="$ORIN_PASS" +LOCAL_DIR="$(cd "$(dirname "$0")" && pwd)" +BUILD_DIR="$LOCAL_DIR/build" +BIN_NAME="vision-anti-pinch" + +# 默认参数 +ACTION="both" +RUN_ARGS="-n 100" + +# 解析参数 +while [[ $# -gt 0 ]]; do + case $1 in + --deploy) ACTION="deploy"; shift ;; + --run) ACTION="run"; shift ;; + --both) ACTION="both"; shift ;; + --args) + RUN_ARGS="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac +done + +# 部署函数 +do_deploy() { + echo "=== 部署源码到 Orin ===" + + # 创建临时目录用于传输 + TEMP_DIR=$(mktemp -d) + cp -r "$LOCAL_DIR"/* "$TEMP_DIR/" + + # 使用 sshpass 复制 (如果没有 sshpass, 手动复制) + if command -v sshpass &> /dev/null; then + echo "复制源码到 Orin..." + sshpass -e scp -o StrictHostKeyChecking=no -r "$TEMP_DIR"/* "${ORIN_USER}@${ORIN_HOST}:~/vision-anti-pinch/" + else + echo "警告: 未安装 sshpass, 请手动复制源码到 Orin:" + echo " scp -r $LOCAL_DIR/* ${ORIN_USER}@${ORIN_HOST}:~/vision-anti-pinch/" + return 1 + fi + + rm -rf "$TEMP_DIR" + + echo "=== 在 Orin 上构建 ===" + sshpass -e ssh -o StrictHostKeyChecking=no "${ORIN_USER}@${ORIN_HOST}" << 'EOF' +cd ~/vision-anti-pinch +make clean +make -j$(nproc) +echo "构建完成" +EOF + + echo "部署完成" +} + +# 运行函数 +do_run() { + echo "=== 在 Orin 上运行 ===" + sshpass -e ssh -o StrictHostKeyChecking=no "${ORIN_USER}@${ORIN_HOST}" << EOF +cd ~/vision-anti-pinch +./${BIN_NAME} ${RUN_ARGS} +EOF +} + +# 主流程 +echo "V4L2 Capture Demo - Build & Run" +echo "================================" + +if [[ "$ACTION" == "deploy" ]] || [[ "$ACTION" == "both" ]]; then + do_deploy +fi + +if [[ "$ACTION" == "run" ]] || [[ "$ACTION" == "both" ]]; then + do_run +fi + +echo "完成" diff --git a/camera_reset.sh b/camera_reset.sh new file mode 100644 index 0000000..9ce7aaa --- /dev/null +++ b/camera_reset.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# camera_reset.sh - 修复 GMSL2 相机"第二次运行全绿"问题 +# +# 问题原因: +# quick_bring_up_64g.sh 第二次运行时,仅重新设置 sensor_mode/trig_pin, +# 但 sgx_yuv_gmsl2 链路状态未重新初始化,导致相机输出全绿。 +# +# 模块依赖关系 (modinfo 确认): +# sgx-yuv-gmsl2.ko depends: max9296, max9295 +# 必须按顺序加载: max9295.ko -> max9296.ko -> sgx-yuv-gmsl2.ko +# 否则 insmod sgx-yuv-gmsl2.ko 报 "Unknown symbol in module" +# +# 本脚本: 依赖模块仅在未加载时 insmod (不重载, 避免链路抖动), +# sgx_yuv_gmsl2 先 rmmod 再 insmod 完成链路复位。 +# 全绿图像多由 gmsl_mode 错误引起 (本工程固定 2,2,2,2); +# 若复位后仍异常, 请重启 Orin 后运行 quick_bring_up_64g.sh。 +# +# 使用方法: +# sudo ./camera_reset.sh [camera_type] [port] +# +# camera_type: 0-17 对应 quick_bring_up_64g.sh 中的相机类型 (默认 8) +# port: 0-7 对应 video 设备号 (默认 5) + +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +KO_DIR="/home/orin/SG8A_ORIN_GMSL2-F_V2_AGX_Orin_YUV_JP5.1.2_L4TR35.4.1/ko" +VIDEO_PORT="${2:-5}" +CAMERA_TYPE="${1:-5}" # 默认 camera_type=5 (SG3S-ISX031C-GMSL2F) + +echo "=========================================================" +echo "Camera Reset Script" +echo "=========================================================" +echo "Camera type: $CAMERA_TYPE" +echo "Video port: $VIDEO_PORT (/dev/video${VIDEO_PORT})" +echo "" + +# Step 1: 停止占用 video 设备的进程 +echo "[1/4] Stopping processes using video devices..." +pkill -9 gst-launch-1.0 2>/dev/null || true +pkill -9 vision-anti-pinch 2>/dev/null || true +sleep 1 + +# Step 2: 加载依赖模块 max9295/max9296 (未加载时), 再重载 sgx_yuv_gmsl2 +echo "[2/4] Loading modules (max9295 -> max9296 -> sgx_yuv_gmsl2)..." +if ! lsmod | grep -q '^max9295'; then + sudo insmod "$KO_DIR/max9295.ko" || { echo "ERROR: insmod max9295 failed"; exit 1; } + echo " loaded max9295.ko" +else + echo " max9295 already loaded (skip)" +fi +if ! lsmod | grep -q '^max9296'; then + sudo insmod "$KO_DIR/max9296.ko" || { echo "ERROR: insmod max9296 failed"; exit 1; } + echo " loaded max9296.ko" +else + echo " max9296 already loaded (skip)" +fi +if lsmod | grep -q '^sgx_yuv_gmsl2'; then + sudo rmmod sgx_yuv_gmsl2 + sleep 1 +fi +sudo insmod "$KO_DIR/sgx-yuv-gmsl2.ko" gmsl_mode=2,2,2,2 || { echo "ERROR: insmod sgx-yuv-gmsl2 failed"; exit 1; } +echo " loaded sgx-yuv-gmsl2.ko (gmsl_mode=2,2,2,2)" +sleep 2 + +# Step 3: 验证设备节点 +echo "[3/4] Verifying device nodes..." +if [ ! -c "/dev/video${VIDEO_PORT}" ]; then + echo "Error: /dev/video${VIDEO_PORT} not found!" + echo "Please reboot the system and run quick_bring_up_64g.sh again." + exit 1 +fi +echo " /dev/video${VIDEO_PORT} exists" + +# Step 4: 根据 camera_type 配置 sensor_mode 和 trig_pin +echo "[4/4] Configuring sensor..." +case "$CAMERA_TYPE" in + 0) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=0,trig_pin=0xffff0007 ;; + 1) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=0,trig_pin=0xffff0007 ;; + 2) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=0,trig_pin=0xffff0007 ;; + 3) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=1,trig_pin=0xffff0007 ;; + 4) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=0,trig_pin=0xffff0007 ;; + 5) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=1,trig_pin=0xffff0007 ;; + 6) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=1,trig_pin=0xffff0007 ;; + 7) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=2,trig_pin=0xffff0008,trig_mode=1 ;; + 8) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=3,trig_pin=0xffff0007 ;; + 9) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=3,trig_pin=0xffff0008 ;; + 10) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=3,trig_pin=0xffff0007 ;; + 11) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=3,trig_pin=0xffff0008 ;; + 12) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=5,trig_pin=0xffff0007,trig_mode=3 ;; + 13) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=4,trig_pin=0xffff0007,trig_mode=3 ;; + 14) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=6,trig_pin=0xffff0007 ;; + 15) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=8 ;; + 16) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=9 ;; + 17) v4l2-ctl -d /dev/video${VIDEO_PORT} -c sensor_mode=0 ;; + *) echo "Unknown camera_type: $CAMERA_TYPE"; exit 1 ;; +esac +sleep 1 + +echo "" +echo "=========================================================" +echo "Camera reset complete!" +echo "" +echo "Now run: ./vision-anti-pinch -d /dev/video5 -W 1920 -H 1536 -n 100 -s 5 -t jpg" +echo "" +echo "⚠️ If image is still all-green, the GMSL2 link is damaged." +echo " Please REBOOT the Orin system to recover:" +echo " sudo reboot" +echo " (then run quick_bring_up_64g.sh after reboot)" +echo "=========================================================" diff --git a/can_comm.cpp b/can_comm.cpp new file mode 100644 index 0000000..84b1760 --- /dev/null +++ b/can_comm.cpp @@ -0,0 +1,338 @@ +// can_comm.cpp - USBCANFD CAN/CANFD 收发封装实现 +// +// 代码迁移自 vision-anti-pinch_bak/main.cpp 的 CAN 模块部分。 + +#include "can_comm.h" + +#include +#include +#include +#include + +#include "zcan.h" + +/* ===================================================================== + * 类型/宏/全局变量 + * ===================================================================== */ + +typedef uint32_t UINT; +typedef uint32_t U32; +#define msleep(ms) usleep((ms) * 1000) + +#define USBCANFD 33 +#define MAX_CHANNELS 2 // 最大通道数量 +#define RX_WAIT_TIME 100 +#define RX_BUFF_SIZE 1000 + +// 接收线程上下文 +typedef struct +{ + int dev_type; // 设备类型 + int dev_idx; // 设备索引 + int chn_idx; // 通道号 + int total; // 接收总数 + int stop; // 线程结束标志 +} THREAD_CTX; + +/* CAN 运行标志, 由信号处理函数(Ctrl+C)或外部置位 */ +static volatile bool g_can_running = true; + +static int g_receive_count = 0; + +/* ===== 仅供 can_start/can_stop 共享的文件内静态变量 ===== */ +static int s_DevType = USBCANFD; +static int s_DevIdx = 0; +static THREAD_CTX s_rx_ctx[MAX_CHANNELS]; +static pthread_t s_rx_threads[MAX_CHANNELS]; +static bool s_can_opened = false; + +namespace CanComm { + +bool is_open() { return s_can_opened; } + +int receive_count() { return g_receive_count; } + +/* ===== 报文解析回调 (由 main.cpp 通过 set_msg_callback 注册) ===== */ +static MsgCallback s_msg_cb = nullptr; + +void set_msg_callback(MsgCallback cb) { s_msg_cb = cb; } + +} // namespace CanComm + +/* ===================================================================== + * 帧构建与收发 + * ===================================================================== */ + +namespace CanComm { + +// 构建 CAN 帧 +static void construct_can_frame(ZCAN_20_MSG *can_msg, UINT id, int chn_idx, int pad) +{ + memset(can_msg, 0, sizeof(ZCAN_20_MSG)); + can_msg->hdr.inf.txm = 0; // 0-正常发送 + can_msg->hdr.inf.fmt = 0; // 0-CAN + can_msg->hdr.inf.sdf = 0; // 0-数据帧, 1-远程帧 + can_msg->hdr.inf.sef = 0; // 0-标准帧, 1-扩展帧 + + can_msg->hdr.id = id; // ID + can_msg->hdr.chn = chn_idx; // 通道 + can_msg->hdr.len = 8; // 数据长度 + + if (pad > 0) + { + can_msg->hdr.pad = pad; // 发送后延迟 pad ms + can_msg->hdr.inf.qsend = 1; // 队列发送帧,仅判断首帧 + can_msg->hdr.inf.qsend_100us = 0; // 队列发送单位,0-ms,1-100us + } + + for (int i = 0; i < can_msg->hdr.len; i++) + can_msg->dat[i] = i; +} + +// 构建 CANFD 帧 +static void construct_canfd_frame(ZCAN_FD_MSG *canfd_msg, UINT id, int chn_idx, int pad) +{ + memset(canfd_msg, 0, sizeof(ZCAN_FD_MSG)); + canfd_msg->hdr.inf.txm = 0; // 0-正常发送 + canfd_msg->hdr.inf.fmt = 1; // 0-CAN, 1-CANFD + canfd_msg->hdr.inf.sdf = 0; // 0-数据帧 CANFD只有数据帧! + canfd_msg->hdr.inf.sef = 1; // 0-标准帧, 1-扩展帧 + canfd_msg->hdr.inf.brs = 1; // canfd 加速 + + canfd_msg->hdr.id = id; // ID + canfd_msg->hdr.chn = chn_idx; // 通道 + canfd_msg->hdr.len = 64; // 数据长度 + + if (pad > 0) + { + canfd_msg->hdr.pad = 100; // 发送后延迟100ms + canfd_msg->hdr.inf.qsend = 1; // 队列发送帧,仅判断首帧 + canfd_msg->hdr.inf.qsend_100us = 0; // 队列发送单位,0-ms,1-100us + } + + for (int i = 0; i < canfd_msg->hdr.len; i++) + canfd_msg->dat[i] = i; +} + +// 分发报文到 main.cpp 注册的解析回调 +static inline void dispatch_msg(uint32_t ts, uint32_t msg_id, const uint8_t *data, uint32_t len) +{ + if (s_msg_cb) + s_msg_cb(ts, msg_id, data, len); +} + +// 接收线程 +static void *rx_thread(void *data) +{ + THREAD_CTX *ctx = (THREAD_CTX *)data; + int DevType = ctx->dev_type; + int DevIdx = ctx->dev_idx; + int chn_idx = ctx->chn_idx; + + ZCAN_20_MSG can_data[RX_BUFF_SIZE]; + ZCAN_FD_MSG canfd_data[RX_BUFF_SIZE]; + + while (!ctx->stop) + { + memset(can_data, 0, sizeof(can_data)); + memset(canfd_data, 0, sizeof(canfd_data)); + + int rcount = VCI_Receive(DevType, DevIdx, chn_idx, can_data, RX_BUFF_SIZE, RX_WAIT_TIME); // CAN + for (int i = 0; i < rcount; ++i) + { + if (can_data[i].hdr.inf.sdf == 0) + { // 数据帧 + dispatch_msg(can_data->hdr.ts, can_data[i].hdr.id, can_data[i].dat, can_data[i].hdr.len); + } + } + ctx->total += rcount; + + rcount = VCI_ReceiveFD(DevType, DevIdx, chn_idx, canfd_data, RX_BUFF_SIZE, RX_WAIT_TIME); // CANFD + for (int i = 0; i < rcount; ++i) + { + dispatch_msg(canfd_data->hdr.ts, canfd_data[i].hdr.id, canfd_data[i].dat, canfd_data[i].hdr.len); + } + ctx->total += rcount; + msleep(10); + } + g_receive_count = ctx->total; + printf("chn: %d receive %d\n", chn_idx, ctx->total); + pthread_exit(0); +} + +// 合并接收线程 +static void *rx_merge_thread(void *data) +{ + THREAD_CTX *ctx = (THREAD_CTX *)data; + int DevType = ctx->dev_type; + int DevIdx = ctx->dev_idx; + + ZCANDataObj obj_data[RX_BUFF_SIZE]; + + while (!ctx->stop) + { + memset(obj_data, 0, sizeof(obj_data)); + int rcount = VCI_ReceiveData(DevType, DevIdx, 0, obj_data, RX_BUFF_SIZE, RX_WAIT_TIME); // 第三个参数固定为0就好 + for (int i = 0; i < rcount; ++i) + { + if (obj_data[i].dataType == ZCAN_DT_ZCAN_CAN_DATA) + { // CAN + ZCAN_20_MSG *can_data = &obj_data[i].data.zcanCANData; + if (can_data->hdr.inf.sdf == 0) + { // 数据帧 + dispatch_msg(can_data->hdr.ts, can_data->hdr.id, can_data->dat, can_data->hdr.len); + } + } + else if (obj_data[i].dataType == ZCAN_DT_ZCAN_CANFD_DATA) + { // CANFD + ZCAN_FD_MSG *canfd_data = &obj_data[i].data.zcanCANFDData; + dispatch_msg(canfd_data->hdr.ts, canfd_data->hdr.id, canfd_data->dat, canfd_data->hdr.len); + } + } + ctx->total += rcount; + msleep(10); + } + g_receive_count = ctx->total; + printf("merge receive %d\n", ctx->total); + pthread_exit(0); +} + +/* + * 初始化并启动 CAN 收发。 + * 返回 true 成功; false 失败(主流程可继续仅取图)。 + */ +bool can_start() +{ + g_can_running = true; + int IsMerge = 1; // 是否合并接收 + + // 打开设备 + if (!VCI_OpenDevice(s_DevType, s_DevIdx, 0)) + { + printf("Open device fail\n"); + return false; + } + s_can_opened = true; + printf("Open device success\n"); + + // 初始化,启动通道 + for (int i = 0; i < MAX_CHANNELS; i++) + { + ZCAN_INIT init; // 波特率结构体,数据根据zcanpro的波特率计算器得出 + init.clk = 60000000; // clock: 60M(V1.01) 80M(V1.03即以上) + init.mode = 0; // 0-正常 + + init.aset.tseg1 = 14; // 仲裁域 500kbps + init.aset.tseg2 = 3; + init.aset.sjw = 2; + init.aset.smp = 0; + init.aset.brp = 5; + + init.dset.tseg1 = 10; // 数据域 2000kbps + init.dset.tseg2 = 2; + init.dset.sjw = 2; + init.dset.smp = 0; + init.dset.brp = 1; + + if (!VCI_InitCAN(s_DevType, s_DevIdx, i, &init)) // 初始化通道 + { + printf("InitCAN(%d) fail\n", i); + return false; + } + printf("InitCAN(%d) success\n", i); + + U32 on = 1; + if (!VCI_SetReference(s_DevType, s_DevIdx, i, CMD_CAN_TRES, &on)) // 终端电阻 + { + printf("CMD_CAN_TRES fail\n"); + } + + if (i == 0) + { + if (!VCI_SetReference(s_DevType, s_DevIdx, i, ZCAN_CMD_SET_CHNL_RECV_MERGE, &IsMerge)) // 合并接收 + { + printf("ZCAN_CMD_SET_CHNL_RECV_MERGE fail\n"); + } + } + + if (!VCI_StartCAN(s_DevType, s_DevIdx, i)) // 启动通道 + { + printf("StartCAN(%d) fail\n", i); + return false; + } + printf("StartCAN(%d) success\n", i); + + s_rx_ctx[i].dev_type = s_DevType; + s_rx_ctx[i].dev_idx = s_DevIdx; + s_rx_ctx[i].chn_idx = i; + s_rx_ctx[i].total = 0; + s_rx_ctx[i].stop = 0; + + if (IsMerge && i == 0) + { + pthread_create(&s_rx_threads[i], NULL, rx_merge_thread, &s_rx_ctx[i]); // 合并接收线程 + } + else + { + pthread_create(&s_rx_threads[i], NULL, rx_thread, &s_rx_ctx[i]); // 创建接收线程 + } + } + return true; +} + +/* + * 停止 CAN 接收并关闭设备。 + */ +void can_stop() +{ + if (!s_can_opened) + return; + + g_can_running = false; + + for (int i = 0; i < MAX_CHANNELS; i++) + { + s_rx_ctx[i].stop = 1; + pthread_join(s_rx_threads[i], NULL); // 等待接收线程退出 + + if (!VCI_ResetCAN(s_DevType, s_DevIdx, i)) // 复位通道 + printf("ResetCAN(%d) fail\n", i); + else + printf("ResetCAN(%d) success!\n", i); + } + + if (!VCI_CloseDevice(s_DevType, s_DevIdx)) + printf("CloseDevice fail\n"); + else + printf("CloseDevice success\n"); + + s_can_opened = false; +} + +uint32_t can_send(int chn_idx, uint32_t id, const uint8_t data[8]) +{ + if (!s_can_opened) + return 0; + + ZCAN_20_MSG msg; + construct_can_frame(&msg, id, chn_idx, 0); + for (int i = 0; i < 8; ++i) + msg.dat[i] = data[i]; + + return VCI_Transmit(s_DevType, s_DevIdx, chn_idx, &msg, 1); +} + +uint32_t canfd_send(int chn_idx, uint32_t id, const uint8_t data[64]) +{ + if (!s_can_opened) + return 0; + + ZCAN_FD_MSG msg; + construct_canfd_frame(&msg, id, chn_idx, 0); + for (int i = 0; i < 64; ++i) + msg.dat[i] = data[i]; + + return VCI_TransmitFD(s_DevType, s_DevIdx, chn_idx, &msg, 1); +} + +} // namespace CanComm diff --git a/can_comm.h b/can_comm.h new file mode 100644 index 0000000..42415e3 --- /dev/null +++ b/can_comm.h @@ -0,0 +1,54 @@ +// can_comm.h - USBCANFD CAN/CANFD 收发封装 +// +// 整合自 vision-anti-pinch_bak/main.cpp 的 CAN 模块, 提供: +// can_start() - 打开设备, 初始化并启动双通道接收线程 +// can_stop() - 停止接收并关闭设备 +// can_send() - 发送一帧 CAN (8 字节) +// canfd_send() - 发送一帧 CANFD (64 字节) +// +// 依赖 zcan.h (include/) 和 libusbcanfd.so + libusb-1.0.so (lib/) + +#pragma once + +#include +#include + +namespace CanComm { + +// 初始化并启动 CAN 收发(双通道, 仲裁域 500kbps / 数据域 2000kbps)。 +// 返回 true 成功; false 失败(主流程可继续仅取图)。 +bool can_start(); + +// 停止 CAN 接收线程并关闭设备。 +void can_stop(); + +// 注册报文解析回调。收到每帧 CAN/CANFD 数据帧时调用。 +// time: 时间戳(us) +// msg_id: CAN-ID +// data: 数据指针(回调内有效, 不要保存) +// len: 数据长度 +// 传 nullptr 取消注册。 +using MsgCallback = void (*)(int64_t time, uint32_t msg_id, const uint8_t *data, uint32_t len); +void set_msg_callback(MsgCallback cb); + +// 发送一帧 CAN2.0 数据帧(8 字节)。 +// chn_idx: 通道号 0/1 +// id: CAN-ID +// data: 8 字节数据(不足补 0, 超出截断) +// 返回实际发送帧数(0 失败)。 +uint32_t can_send(int chn_idx, uint32_t id, const uint8_t data[8]); + +// 发送一帧 CANFD 数据帧(64 字节, 扩展帧+加速)。 +// chn_idx: 通道号 0/1 +// id: CAN-ID +// data: 64 字节数据(不足补 0, 超出截断) +// 返回实际发送帧数(0 失败)。 +uint32_t canfd_send(int chn_idx, uint32_t id, const uint8_t data[64]); + +// 是否已打开并运行 +bool is_open(); + +// 累计接收帧数(线程安全) +int receive_count(); + +} // namespace CanComm diff --git a/examples/read_latest.py b/examples/read_latest.py new file mode 100644 index 0000000..2a3f0bd --- /dev/null +++ b/examples/read_latest.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +"""Same-process downstream example. Run on Orin, which owns the camera/GPU.""" +import sys +from pathlib import Path +sys.path.insert(0, str(Path(__file__).resolve().parents[1])) +from run_camera import CameraPipeline, parse_args + + +def main(): + # No visualization or disk output by default. CLI flags can enable either. + pipeline = CameraPipeline(parse_args()) + last_frame = -1 + try: + pipeline.start() + while True: + # Reading the variable is enough for a consumer with its own clock: + # result = pipeline.latest_result # equivalent to pipeline.latest() + # This sample waits to avoid busy polling; still only the latest + # result is returned, without queuing/acknowledging individual frames. + result = pipeline.wait_for_result(last_frame, timeout=1.0) + if result is not None: + last_frame = result['frame_index'] + print(last_frame, result['risk']['risk_type'], + result['risk']['risk_score'], flush=True) + # Downstream code uses result['door_risks'], ['skeletons'], ['can']. + elif not pipeline.running(): + break + except KeyboardInterrupt: + pass + finally: + pipeline.request_stop() + pipeline.join() # Also propagates worker errors to the caller. + + +if __name__ == '__main__': + main() diff --git a/include/zcan.h b/include/zcan.h new file mode 100644 index 0000000..9f9d935 --- /dev/null +++ b/include/zcan.h @@ -0,0 +1,443 @@ +#pragma once + +#ifdef __cplusplus +#define EXTERN_C extern "C" +#else +#define EXTERN_C +#endif + +#define ZCAN_API +#define INVALID_HANDLE_VALUE ((HANDLE)(-1)) + +#define CMD_CAN_FILTER 0x14 // 滤波 +#define CMD_CAN_TTX 0x16 // 定时发送 +#define CMD_CAN_TTX_CTL 0x17 // 使能定时发送 +#define CMD_CAN_TRES 0x18 // CAN终端电阻 + +#define ZCAN_CMD_SET_CHNL_RECV_MERGE 0x32 // 设置合并接收 0:不合并接收;1:合并接收 +#define ZCAN_CMD_GET_CHNL_RECV_MERGE 0x33 // 获取是否开启合并接收 0:不合并接收;1:合并接收 + +#define CMD_SET_SN 0x42 // 获取SN号 +#define CMD_GET_SN 0x43 // 设置SN号 +#define CMD_CAN_TX_TIMEOUT 0x44 // 发送超时 + +#define ZCAN_CMD_GET_SEND_QUEUE_SIZE 0x100 // 获取队列大小,uint32_t +#define ZCAN_CMD_GET_SEND_QUEUE_SPACE 0x101 // 获取队列剩余空间, uint32_t +#define ZCAN_CMD_SET_SEND_QUEUE_CLR 0x102 // 清空发送队列,1:清空 +#define ZCAN_CMD_SET_SEND_QUEUE_EN 0x103 // 开启发送队列,1:使能 + +typedef unsigned char U8; +typedef unsigned short U16; +typedef unsigned int U32; +typedef unsigned long long U64; + +enum eZCANDataDEF +{ + //数据类型 + ZCAN_DT_ZCAN_CAN_DATA = 1, // CAN/CANFD数据 + ZCAN_DT_ZCAN_CANFD_DATA = 2, // CAN/CANFD数据 + ZCAN_DT_ZCAN_ERROR_DATA = 3, // CAN/CANFD错误数据 + ZCAN_DT_ZCAN_LIN_DATA = 4, // LIN数据 + ZCAN_DT_ZCAN_LIN_ERROR_DATA = 5, // LIN错误数据 +}; +#pragma pack(push, 1) + +typedef enum { + ZCAN_TX_NORM = 0, /**< normal transmission */ + ZCAN_TX_ONCE = 1, /**< single-shot transmission */ + ZCAN_SR_NORM = 2, /**< self reception */ + ZCAN_SR_ONCE = 3, /**< single-shot transmission & self reception */ +} ZCAN_TX_MODE; + +/** CAN filter configuration */ +typedef struct { + U8 type; /**< 0-std_frame, 1-ext_frame */ + U8 pad[3]; + U32 sid; /**< start-id */ + U32 eid; /**< end-id */ +} ZCAN_FILTER; + +typedef struct { + U32 size; + ZCAN_FILTER table[64]; +} ZCAN_FILTER_TABLE; + +/** controller initialization */ +typedef struct { + U32 clk; // 时钟频率 + U32 mode; /**< bit0-normal/listen_only, bit1-ISO/BOSCH */ + struct { + U8 tseg1; + U8 tseg2; + U8 sjw; + U8 smp; + U16 brp; + } aset; + struct { + U8 tseg1; + U8 tseg2; + U8 sjw; + U8 smp; + U16 brp; + } dset; +} ZCAN_INIT; + +/** CAN message info */ +typedef struct { + U32 txm : 4; /**< TX-mode, @see ZCAN_TX_MODE */ + U32 fmt : 4; /**< 0-CAN2.0, 1-CANFD */ + U32 sdf : 1; /**< 0-data_frame, 1-remote_frame */ + U32 sef : 1; /**< 0-std_frame, 1-ext_frame */ + U32 err : 1; /**< error flag */ + U32 brs : 1; /**< bit-rate switch */ + U32 est : 1; /**< error state */ + U32 tx : 1; /**< received valid, tx frame */ + U32 echo : 1; /**< tx valid, echo frame */ + U32 qsend_100us:1; /**< queue send delay unit, 1-100us, 0-ms */ + U32 qsend:1; /**< send valid, queue send frame */ + U32 pad : 15; +} ZCAN_MSG_INF; + +/** CAN message header */ +typedef struct { + U32 ts; /**< timestamp */ + U32 id; /**< CAN-ID */ + ZCAN_MSG_INF inf; /**< @see ZCAN_MSG_INF */ + U16 pad; /**< send queue delay */ + U8 chn; /**< channel */ + U8 len; /**< data length */ +} ZCAN_MSG_HDR; + +/** CAN2.0-frame */ +typedef struct { + ZCAN_MSG_HDR hdr; + U8 dat[8]; +} ZCAN_20_MSG; + +/** CANFD-frame */ +typedef struct { + ZCAN_MSG_HDR hdr; + U8 dat[64]; +} ZCAN_FD_MSG; + +// 错误帧 +typedef struct { + ZCAN_MSG_HDR hdr; + U8 dat[8]; +} ZCAN_ERR_MSG; + +// 定时发送结构体 +typedef struct { + U32 interval; // 定时发送周期,单位 100us + U16 repeat; // 发送次数,0等于循环发 + U8 index; // 定时发送列表的帧索引号,也就是第几条定时发送报文 + U8 flags; // 0-此帧禁用定时发送,1-此帧使能定时发送 + ZCAN_FD_MSG msg; // CANFD帧结构体 +} ZCAN_TTX; + +typedef struct { + U32 size; // 实际生效的数组的长度(用来控制实际生效多少条定时发送帧结构体) + ZCAN_TTX table[8]; // 最大设置8条 +} ZCAN_TTX_CFG; + +// 设备信息 +typedef struct { + U16 hwv; /**< hardware version */ + U16 fwv; /**< firmware version */ + U16 drv; /**< driver version */ + U16 api; /**< API version */ + U16 irq; /**< IRQ */ + U8 chn; /**< channels */ + U8 sn[20]; /**< serial number */ + U8 id[40]; /**< card id */ + U16 pad[4]; +} ZCAN_DEV_INF; + +/** controller status */ +typedef struct { + U8 IR; /**< not used(for backward compatibility) */ + U8 MOD; /**< not used */ + U8 SR; /**< not used */ + U8 ALC; /**< not used */ + U8 ECC; /**< not used */ + U8 EWL; /**< not used */ + U8 RXE; /**< RX errors */ + U8 TXE; /**< TX errors */ + U32 PAD; +} ZCAN_STAT; + +//lin begin +typedef struct _VCI_LIN_INIT_CONFIG +{ + U8 linMode; // 是否作为主机,0-从机,1-主机 + U8 chkSumMode; // 校验方式,1-经典校验 2-增强校验 3-自动(对应eZLINChkSumMode的模式) + U16 reserved; // 保留 + U32 linBaud; // 波特率,取值1000~20000 +}ZCAN_LIN_INIT_CONFIG, *PZCAN_LIN_INIT_CONFIG; + +typedef struct tagZCANLINData +{ + union{ + struct { + U8 ID : 6; // 帧ID + U8 Parity : 2; // 帧ID校验 + }unionVal; + U8 rawVal; // 受保护的ID原始值 + } PID; // 受保护的ID + struct + { + U64 timeStamp; // 时间戳,单位微秒(us) + U8 dataLen; // 数据长度 + U8 dir; // 传输方向,0-接收 1-发送 + U8 chkSum; // 数据校验, 部分设备不支持校验数据的获取 + U8 reserved[13]; // 保留 + U8 data[8]; // 数据 + }RxData; // 仅接收数据时有效 + U8 reserved[7]; // 保留 +}ZCANLINData; + +typedef struct tagZCANLINErrData +{ + U64 timeStamp; // 时间戳, 单位微秒(us) + union { + struct { + U8 ID : 6; // 帧ID + U8 Parity : 2; // 帧ID校验 + }unionVal; + U8 rawVal; // 受保护的ID原始值 + } PID; // 受保护的ID + U8 dataLen; + U8 data[8]; + union + { + struct + { + U16 errStage : 4; // 错误阶段 + U16 errReason : 4; // 错误原因 + U16 reserved : 8; // 保留 + }; + U16 unionErrData; + }errData; + U8 dir; // 传输方向 + U8 chkSum; // 数据校验, 部分设备不支持校验数据的获取 + U8 reserved[10]; // 保留 +}ZCANLINErrData; + +typedef struct _VCI_LIN_MSG{ + U8 chnl; // 数据通道 + U8 dataType; // 数据类型, 0-LIN数据 1-LIN错误数据 + union + { + ZCANLINData zcanLINData; // LIN数据 + ZCANLINErrData zcanLINErrData; // LIN错误数据 + U8 raw[46]; // RAW数据 + } data; // 实际数据, 联合体,有效成员根据 dataType 字段而定 +}ZCAN_LIN_MSG, *PZCAN_LIN_MSG; + +enum eZLINChkSumMode +{ + DEFAULT = 0, // 默认,启动时配置 + CLASSIC_CHKSUM, // 经典校验 + ENHANCE_CHKSUM, // 增强校验 + AUTOMATIC, // 自动,设备自动识别校验方式(仅ZCAN_SetLINSubscribe时有效) +}; +enum +{ + MAX_LIN_ID_COUNT = 63, + MIN_LIN_DLC = 1, + MAX_LIN_DLC = 8, + AUTO_LIN_DLC = 255, +}; +typedef struct _VCI_LIN_PUBLISH_CFG +{ + U8 ID; // 受保护的ID(ID取值范围为0-63) + U8 dataLen; // dataLen范围为1-8 + U8 data[8]; + U8 chkSumMode; // 校验方式,0-默认,启动时配置 1-经典校验 2-增强校验(对应eZLINChkSumMode的模式) + U8 reserved[5]; // 保留 +}ZCAN_LIN_PUBLISH_CFG, *PZCAN_LIN_PUBLISH_CFG; + +typedef struct _VCI_LIN_SUBSCIBE_CFG +{ + U8 ID; // 受保护的ID(ID取值范围为0-63) + U8 dataLen; // dataLen范围为1-8 当为255(0xff)则表示设备自动识别报文长度 + U8 chkSumMode; // 校验方式,0-默认,启动时配置 1-经典校验 2-增强校验 3-自动(对应eZLINChkSumMode的模式) + U8 reserved[5]; // 保留 +}ZCAN_LIN_SUBSCIBE_CFG, *PZCAN_LIN_SUBSCIBE_CFG; + +// 合并接收数据数据结构,支持CAN/CANFD/LIN/错误等不同类型数据 +typedef struct tagZCANDataObj +{ + U8 dataType; // 数据类型, 参考eZCANDataDEF中 数据类型 部分定义 + U8 chnl; // 数据通道 + union{ + struct{ + U16 reserved : 16; // 保留 + }unionVal; + U16 rawVal; + }flag; // 标志信息, 暂未使用 + U8 extraData[4]; // 额外数据, 暂未使用 + union + { + ZCAN_20_MSG zcanCANData; // CAN数据 + ZCAN_FD_MSG zcanCANFDData; // CANFD数据 + ZCAN_ERR_MSG zcanErrData; // 错误数据 + ZCANLINData zcanLINData; // LIN数据 + ZCANLINErrData zcanLINErrData; // LIN错误数据 + U8 raw[92]; // RAW数据 + } data; // 实际数据, 联合体,有效成员根据 dataType 字段而定 +}ZCANDataObj; + + +// UDS传输协议版本 +typedef U8 ZCAN_UDS_TRANS_VER; +#define ZCAN_UDS_TRANS_VER_0 0 // ISO15765-2(2004版本) +#define ZCAN_UDS_TRANS_VER_1 1 // ISO15765-2(2016版本) + +// 帧类型 +typedef U8 ZCAN_UDS_FRAME_TYPE; +#define ZCAN_UDS_FRAME_CAN 0 // CAN帧 +#define ZCAN_UDS_FRAME_CANFD 1 // CANFD帧 +#define ZCAN_UDS_FRAME_CANFD_BRS 2 // CANFD加速帧 + +// UDS填充模式 +#define FILL_MODE_SHORT 0 // 小于8字节填充至8字节,大于8字节时按DLC就近填充 +#define FILL_MODE_NONE 1 // 不填充 +#define FILL_MODE_MAX 2 // 填充至最大数据长度 (不建议) + +// CAN UDS请求数据 +typedef struct _ZCAN_UDS_REQUEST +{ + U32 req_id; // 请求事务ID,范围0~65535,本次请求的唯一标识 + U8 channel; // 设备通道索引 0~255 + ZCAN_UDS_FRAME_TYPE frame_type; // 帧类型 + U8 reserved0[2]; // 保留 + U32 src_addr; // 请求地址 + U32 dst_addr; // 响应地址 + U8 suppress_response; // 1:抑制响应 + U8 sid; // 请求服务id + U8 reserved1[6]; // 保留 + struct { + U32 timeout; // 响应超时时间(ms)。因PC定时器误差,建议设置不小于200ms + U32 enhanced_timeout; // 收到消极响应错误码为0x78后的超时时间(ms)。因PC定时器误差,建议设置不小于200ms + U8 check_any_negative_response:1; // 接收到非本次请求服务的消极响应时是否需要判定为响应错误 + U8 wait_if_suppress_response:1; // 抑制响应时是否需要等待消极响应,等待时长为响应超时时间 + U8 flag:6; // 保留 + U8 reserved0[7]; // 保留 + } session_param; // 会话层参数 + struct { + ZCAN_UDS_TRANS_VER version; // 传输协议版本, VERSION_0, VERSION_1 + U8 max_data_len; // 单帧最大数据长度, can:8, canfd:64 + U8 local_st_min; // 本程序发送流控时用,连续帧之间的最小间隔, 0x00-0x7F(0ms~127ms), 0xF1-0xF9(100us~900us) + U8 block_size; // 流控帧的块大小 + U8 fill_byte; // 无效字节的填充数据 + U8 ext_frame; // 0:标准帧 1:扩展帧 + U8 is_modify_ecu_st_min; // 是否忽略ECU返回流控的STmin,强制使用本程序设置的 remote_st_min + U8 remote_st_min; // 发送多帧时用, is_ignore_ecu_st_min = 1 时有效, 0x00-0x7F(0ms~127ms), 0xF1-0xF9(100us~900us) + U32 fc_timeout; // 接收流控超时时间(ms), 如发送首帧后需要等待回应流控帧 + U8 fill_mode; // 数据长度填充模式, FILL_MODE_SHORT, FILL_MODE_NONE, FILL_MODE_MAX + U8 reserved0[3]; // 保留 + } trans_param; // 传输层参数 + U8 *data; // 数据数组(不包含SID) + U32 data_len; // 数据数组的长度 + U32 reserved2; // 保留 +} ZCAN_UDS_REQUEST; + +// UDS错误码 +typedef U8 ZCAN_UDS_ERROR; +#define ZCAN_UDS_ERROR_OK 0 // 没错误 +#define ZCAN_UDS_ERROR_TIMEOUT 1 // 响应超时 +#define ZCAN_UDS_ERROR_TRANSPORT 2 // 发送数据失败 +#define ZCAN_UDS_ERROR_CANCEL 3 // 取消请求 +#define ZCAN_UDS_ERROR_SUPPRESS_RESPONSE 4 // 抑制响应 +#define ZCAN_UDS_ERROR_BUSY 5 // 忙碌中 +#define ZCAN_UDS_ERROR_REQ_PARAM 6 // 请求参数错误 +#define ZCAN_UDS_ERROR_OTHTER 100 + +typedef U8 ZCAN_UDS_RESPONSE_TYPE; +#define ZCAN_UDS_RT_NEGATIVE 0 // 消极响应 +#define ZCAN_UDS_RT_POSITIVE 1 // 积极响应 + +// UDS响应数据 +typedef struct _ZCAN_UDS_RESPONSE +{ + ZCAN_UDS_ERROR status; // 响应状态 + U8 reserved[6]; // 保留 + ZCAN_UDS_RESPONSE_TYPE type; // 响应类型 + union { + struct { + U8 sid; // 响应服务id + U32 data_len; // 数据长度(不包含SID), 数据存放在接口传入的dataBuf中 + } positive; + struct { + U8 neg_code; // 固定为0x7F + U8 sid; // 请求服务id + U8 error_code; // 错误码 + } negative; + U8 raw[8]; + }; +} ZCAN_UDS_RESPONSE; + +// UDS控制类型 +typedef U32 ZCAN_UDS_CTRL_CODE; +#define ZCAN_UDS_CTRL_STOP_REQ 0 // 停止UDS请求 + +// UDS控制请求 +typedef struct _ZCAN_UDS_CTRL_REQ +{ + U32 reqID; // 请求事务ID,指明要操作哪一条请求 + ZCAN_UDS_CTRL_CODE cmd; // 控制类型 + U8 reserved[8]; // 保留 +} ZCAN_UDS_CTRL_REQ; + +// UDS控制结果 +typedef U32 ZCAN_UDS_CTRL_RESULT; +#define ZCAN_UDS_CTRL_RESULT_OK 0 // 成功 +#define ZCAN_UDS_CTRL_RESULT_ERR 1 // 失败 + +// UDS控制响应数据 +typedef struct _ZCAN_UDS_CTRL_RESP +{ + ZCAN_UDS_CTRL_RESULT result; // 操作结果 + U8 reserved[8]; // 保留 +} ZCAN_UDS_CTRL_RESP; + +#pragma pack(pop) + +// +EXTERN_C U32 ZCAN_API VCI_OpenDevice(U32 Type, U32 Card, U32 Reserved); +EXTERN_C U32 ZCAN_API VCI_CloseDevice(U32 Type, U32 Card); +EXTERN_C U32 ZCAN_API VCI_InitCAN(U32 Type, U32 Card, U32 Port, ZCAN_INIT *pInit); +EXTERN_C U32 ZCAN_API VCI_ReadBoardInfo(U32 Type, U32 Card, ZCAN_DEV_INF *pInfo); +EXTERN_C U32 ZCAN_API VCI_ReadErrInfo(U32 Type, U32 Card, U32 Port, ZCAN_ERR_MSG *pErr); +EXTERN_C U32 ZCAN_API VCI_ReadCANStatus(U32 Type, U32 Card, U32 Port, ZCAN_STAT *pStat); +EXTERN_C U32 ZCAN_API VCI_GetReference(U32 Type, U32 Card, U32 Port, U32 Ref, void *pData); +EXTERN_C U32 ZCAN_API VCI_SetReference(U32 Type, U32 Card, U32 Port, U32 Ref, void *pData); +EXTERN_C U32 ZCAN_API VCI_GetReceiveNum(U32 Type, U32 Card, U32 Port); +EXTERN_C U32 ZCAN_API VCI_ClearBuffer(U32 Type, U32 Card, U32 Port); +EXTERN_C U32 ZCAN_API VCI_StartCAN(U32 Type, U32 Card, U32 Port); +EXTERN_C U32 ZCAN_API VCI_ResetCAN(U32 Type, U32 Card, U32 Port); +EXTERN_C U32 ZCAN_API VCI_Transmit(U32 Type, U32 Card, U32 Port, ZCAN_20_MSG *pData, U32 Count); +EXTERN_C U32 ZCAN_API VCI_TransmitFD(U32 Type, U32 Card, U32 Port, ZCAN_FD_MSG *pData, U32 Count); +EXTERN_C U32 ZCAN_API VCI_Receive(U32 Type, U32 Card, U32 Port, ZCAN_20_MSG *pData, U32 Count, U32 Time); +EXTERN_C U32 ZCAN_API VCI_ReceiveFD(U32 Type, U32 Card, U32 Port, ZCAN_FD_MSG *pData, U32 Count, U32 Time); +EXTERN_C U32 ZCAN_API VCI_Debug(U32 Debug); + +// LIN +EXTERN_C U32 VCI_InitLIN(U32 Type, U32 Card, U32 LinChn, PZCAN_LIN_INIT_CONFIG pLINInitConfig); +EXTERN_C U32 VCI_StartLIN(U32 Type, U32 Card, U32 LinChn); +EXTERN_C U32 VCI_ResetLIN(U32 Type, U32 Card, U32 LinChn); +EXTERN_C U32 VCI_TransmitLIN(U32 Type, U32 Card, U32 LinChn, PZCAN_LIN_MSG pSend, U32 Len); +EXTERN_C U32 VCI_GetLINReceiveNum(U32 Type, U32 Card, U32 LinChn); +EXTERN_C U32 VCI_ClearLINBuffer(U32 Type, U32 Card, U32 LinChn); +EXTERN_C U32 VCI_ReceiveLIN(U32 Type, U32 Card, U32 LinChn, PZCAN_LIN_MSG pReceive, U32 Len,int WaitTime); +EXTERN_C U32 VCI_SetLINSubscribe(U32 Type, U32 Card, U32 LinChn, PZCAN_LIN_SUBSCIBE_CFG pSend, U32 nSubscribeCount); +EXTERN_C U32 VCI_SetLINPublish(U32 Type, U32 Card, U32 LinChn, PZCAN_LIN_PUBLISH_CFG pSend, U32 nPublishCount); + +// 合并接收 +EXTERN_C U32 VCI_TransmitData(unsigned Type, unsigned Card, unsigned Port, ZCANDataObj *pData, unsigned Count); +EXTERN_C U32 VCI_ReceiveData(unsigned Type, unsigned Card, unsigned Port, ZCANDataObj *pData, unsigned Count, unsigned Time); + +// UDS +EXTERN_C U32 VCI_UDS_Request(unsigned Type, unsigned Card, const ZCAN_UDS_REQUEST *req, ZCAN_UDS_RESPONSE *resp, U8 *dataBuf, U32 dataBufSize); +EXTERN_C U32 VCI_UDS_Control(unsigned Type, unsigned Card, const ZCAN_UDS_CTRL_REQ *ctrl, ZCAN_UDS_CTRL_RESP *resp); diff --git a/lib/libusb-1.0.so b/lib/libusb-1.0.so new file mode 100644 index 0000000000000000000000000000000000000000..0824ee0f3a813b583209d571b1afc45ed82b2e9b GIT binary patch literal 377192 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

TlRW$zm7e62x;YmoTEFadRcCgH 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 literal 0 HcmV?d00001 diff --git a/lib/libusb-1.0.so.0 b/lib/libusb-1.0.so.0 new file mode 120000 index 0000000..4970d7f --- /dev/null +++ b/lib/libusb-1.0.so.0 @@ -0,0 +1 @@ +libusb-1.0.so \ No newline at end of file diff --git a/lib/libusbcanfd.so b/lib/libusbcanfd.so new file mode 100644 index 0000000000000000000000000000000000000000..72b9370fdcfe26d43b83dbd7a7e27cb112a36849 GIT binary patch literal 205816 zcmce<34D~*)jxh`319$$Bm@W)k^qWPksad35O!RE5G`)aB$EI!tV!6!%CK3~wq_Jp ztb|R;*lMgniM1NG*0**+TX(B>i;&lQ~7Ikzw*}#zjY1pCjQp9RadJWYxCB$->7!eexur1*K`FI*0r5( z?!=X!*V(xk*M15ttSjsCZ`$FCB7VQ*8ihFe>eK|nSJ_I4>1e0BpdsIX>8x+(YI^bH zvQVqRy6W!8zNG*MZ%@4b2659J54Bs`d$a9un=yH%pFMv0vqR=hAc_9?6yQU)&%>wl z>aMmO&Z_jB8xniAb&57#(b+4+-L6EZn6SRHbCM9=bZ-Z@uqAn?yVzpDHv0sT*{+@4 zHAp18CJ~nhAO02LQ;g4Sd`j@S9iO@QEW~FKK8x{LhRTGmgHI;h5c+({M^Al`{9|9uFSp)%<&z&hl{IzJrrobxaX8c_7`)(Z+wL=U z*AJOlnLOdTU4OaY+J@_gxSzQ0&@C0?AK2V9YW>CUoO)BdBv2szgqvr?`}!x zF~IrWr)@_}2o*J~tbJx^_pRFpb+|P-ujZ+ifx(-8|ChAouJk!k-HRwXpoiB7M}TC( zA-ai4FK7eNw|AhJbZ%9V*fBPI9}Fs1{WCC_Snzu>EMmbqtYg7n!k~x+-`^=V+#9F< zt~m7{I6pR?lsNoMNBztg@(BSJi_h2K3}V4g#eshqho6!-{dygAyTstQ$oHV&WD5ml(?)R>hIq0~mL)^!t}M{LhL*w8mOZ{)#wq=p6_CcpU!w#qq;0#gSY4ICy>< z$8MjEgMR?*A(p*;5ywv6iR0&s;?O-BM-DH=!Shv|`n%)URXYTivGi3PM?NRx;O`lS z|9`~6(>V@2H4Z=f3h%41ad@JSIUL1Wyg2fJuXZ}so_18b7 zDvncN@v-y|z%xt1E74E>^@BW#|Ghc||44zwHFBJ`7lT?9;7*M{MUK1nqVh=vccUKv zo|b;5y*N%sfxi>F{&D!L43R84>vcFt@+vUPgVa)&Cdmis{ZRwtBRNC`XP;H87CC{bp{{&dsEBpK$P4TY5W6T zQT2|Z%)ei1_^AD=Jiy{#!_#*uxKr~(zLLOy)z=FCb6x*=IS;lMqi#_A%!D7|-vV6O z-}PG*e3Is$_=x9dld5+K`oq6`EoY(SY^|>@k?@Y9=2F$s%T#r-OUq%}CWUx_#{VZR zx6?ZmV4tr4t+t;5KUMH);G2I3bbsCNtFmTatkUq#^$KpuXQNgBPYV8X-Qao+Kkyp` zp9Vho_cZL3a_Fq}sKqKi({ii4P4Tl(<5{HTGtH^_N11=Sv>Z-rISf-^@ujBg`d9&q zR5S6hhR@OcdRybUNaLURrK&#;_4wBd_^Fp=>lK1Q+HPCGC;6|hR&a~|eH#DigQ~r? zc%BJ4v;H!_s&CotRl0un9jbnq$@nGXhv&11s(CYjDOOcc zUQy> z1r$TY^86)(td_INii=wtYR(E5&n-O%SiZP$UP;9{U{Aq(PqER7g%xwkiVKSJ%ZumE zvWUznm|rxvIKOyF@%)N%$ZuZpg2feLUh%y0;tDalxWcovNX%NWuz0@Jpk#hYh4sC7 z8NSc*%w14kOp(q-Evded`B3e$!Gi}6DJ&>2@j%KD-t5U9sAI4P3L~c_73GsX<7X7$ zzwv_y$-;344uc<8H)?cJ!K_@VSxZPZE@k;5{xDCe#5vK`D4|%lUj&6(9=NIuu%+$1xumjqI@|>>0MwYgRC1c=h+o=U>#)(%3zW( zGWx4RIJx=xo`MR`91STemWXtz7=v5irK=jTq}WrjpltFSSo$1T`bb!MQSq#T#d9n2 z3l?Hr6^*BcP%~_Ns9P~?VL?gR@ z(UC#Z1WLnDk_*7zOd35H%#G4;I=(y?wzkEicK?_obA8$E9#|`6cka z1<;h9Sz{RXaJuk<`LpS&DOZK)`fSW_^B2qM03&Yxg0gu9bHmss&lsAIo{b+5dL#cs zdeLlOgL#B}BMkUnzGHhS0k#bc*x{(q!(qi#2c+mU>6(zHl(-&EU{?mCh8#;hR7E~0E&z<-G+^q~5 z267yldLS*HU$SU%asI*u<>R%z#xwr^6R$Rey*0?sL5PrV@BkgOx;g}Ov2=R> zzwkH&JQmNBfla=_;N&T}7_>tMFD$_fytD-IjbyNFu?JDyj3N1xr%c5#lwaWFrJEnw z>bJ~Z{JUO`TR1gOMKFjsty*a~V75tI!O~ zpYmc|LoY)H=U=xN7-UR2`C8L04#~e3{sqHkZi#34_#xxRL(X}V;nM%ZCO2M>P=JoM zps-}gV8%C?|H={5FJDNXJZphO%q7tXuAV##79*rC`cD}8Z`wt2#o(&EBnD&o*4m`B z7!FsuFkyi(G_b&fbc>c^)er{Hlk!|VpWZnNC_!)yayc`rs9<^2eYu9Q&?`I$MzG>* zttg2`)RPdanw%5peMlmVT~^^tT7WenW4iy;fe)s?02c59S1=h-r<&A8eb1zpUv3O$ zt5eY;lq^UKSzV4Ni|K|_9mv6z4&WC8rl=Ykp6 ziUo3&tO*S)UocQESg{K7TzoN$BXsz6>EMBb!nbF8unJ^pFzYD>g&vz01q2DWN<`r@L(}^ z=FBlUlk*1;92$8i+bpVdhp@|&1Wx?#(BBh80>1NO#|aFkLzrsgeWp@WeRW^Km>)^N zIRnaw=gg5UVp+LqWzfhi^jFc6=jc%H1q?``BAMPG{8Huj>Z9N_8vc3|yk5f(M8S7y z_2{VJ2I+j@q$v35!OFUKJV)z`gIIQ|s*~(|z(EK9c)9MmdKceC7G(UtdmmH}7to;YV#~OGn{Y1mN z8+g_lc+w5{G6O!!fR`BXWxBsM$N^g|;Xkhd?;3{U{FedmWx(B9PUO>sR~q#*jQWon z@V*9oj)BL7R~hy1H|p0I@TmrTrh&(V*BkYHM*Y_f_)P}#Y)bW10bngAV`AG~n1`2>-ba_>wSGh&cuvTN~lO zg$5j3z~R4T2K?SI6zALwxHWcpd%XcS_d_cUc(H-!Q3IZ2z^e>+vH{;=zYYG#|?OI1Af|o z_c7q&`BwW+H{k6Ixal`K8}Lk{es=?I`i*o0-p{B%z<~ER;DZeK1qOVS0l(0IyA1dM z13t-sXBqHm2K-_JKGT3-V!+)7{5}Id$AEhb_(B7IsR3VRzy}&|uK}NHz}Fjao(r}9 zDh>F23yABZ2K+JuUS+@s8Sotje6RtpG2lZC_$~uJ)PUC;aBI($w_i8l3yk^)3^?}= zt-tpS_;3q|YrueyFyKcG_(%hO+<=cV;HM3^4#m{n-?rNS2K)*G-r0a(X~4T1 z@Oun+x&gn+fDbU>R~zs_27ILfA7#Kt8*rBacNy?W27HVGpJu>w4ERg~KF)x<4fuEi zKF5GhFyIRf_(TJ~%z#fa;9dhh*?_M%-~|S}(tuAf;Ex*cYYcdm0l(IO?=awn2E4|A zUuVE~8Sv{3c)bBP#v;wztIBX+S!2r*noF8;4=+)x&go0fDbU>w;1q22K-h7KFWaKX24wr z+>8&;u6V8btV8(Tu!#+4SM1(V@5q0b&5i?JV-v@_d^a)JxpA~F-QMTjKIx8ktj__P zsO(~Q1##|2-jn4vC}$ewM3i%k^7$wi8s#LER~zM2l(!h=G?e!k<=!Ya8s$us?Y36> z7oePJl(SIIG0Fo`E;PzRP+o16N1(jLC|{299;19U%8f=j2W7jxmHq^jGmY{Tlyi*o z^(Yq_{t3#BM!67WyQ7u8+9;nwd5cj#gYq7u{2j`TM%g|F^xL)4Z-a8CQBFiT$0(nVa-mU9 zLV2}OPDOc(QBFg7k5TT8a-&hsMA?2`EBy;l&NRwdDCZdEfhZRm!%8f?3 z5M_J&R{FD0&NRxmqnu-u=c8O`l*>?FZIqXwyu~Qrf$|=sd>6`%MtL>L_71J|??yS( zDBp{6j#2(4%7sSx0hCu8<%dz;Vw4|8d5=+k66Hptyai=@M@j$eidU=aF(-*YN1x3l ze4Nu9ZsBX5VXJ-{@C}(AeT|M3|LAt2ZgdA*b+WMes&MSG@16E)k)Grm7YaQRa3tfj zp!eW)w}}l6_|E!Om;;+@WM+++GCV0!{ax>#|)oFmRgDdU!?3LfOs~#g`(Ny`HsR?y1h0gII^v% z9S!?wy3iFoBt#APs|h%|`PbqR!yMS-{zPwX2KXApexuHY9DzQk9D|(mRstq~<9S|D z=VJ81eYptMg9icHfhc;ZsQYk&sO@_Wy;ManAbbh!6}^-g^gNp0L%3E^)+1feQ>(1; zERvM<$y;)&TRdYi2L32z-WK#4!Fv<>2HDqOUGK|4-}a$zlzmr@C8KXu!BE~L(0Bv7 zI1Ra;(-wR>!6)0ciE8WmHk6l*wy@uBThE3bX#n2Ukl6|7Y&2}b4Y>s{t|(7;u1k)| zOZk0*`ksaF9M@|>Hvk@2LA@*yUrOxf6Iu zk2Y!9r=$rT9M&}N(KP#ru9DvSnqGU-(=vV=FiXa7vOZ*dG4OND24F|4FlMpab&URW zOhRlslDwY@?K}qgo|3$#`WFI6G2}wqqMdjk58Bu^@&>ukMt%xD-bFtsmp&r(SfC}8 zR|6h?4?J$&#|Rq(jtungkhZaTXs_CKJ?4dNZbsWbp>2Cy#VA)$u7R#pSDTnpO<$hg zdDG((zROj|YoA?0UeB)hef1HCJ*yEmX!+w8U=xQOj;tm}n=B{rgf0|y<&cX_9c4T^jk}vqBaR~qdn3lXdhv}<+b~A0(Rg2 zF3OMC!7F8F`mO1J(H_^}+S1b%q+TcKKGDZEcH5Lz*v6jS2)pPDesYB482t1>ygeZ7 zUo78p{Fbo(E2%^1zS098GQh(=@Id{ajpD%z`3%yu8=yz>@K1Ra!G|F$Yn*e8j)t$b zd`4g5f!+RtZBbv%YjxF->j6uylqd9gfIg!zhD^PXDP_<3gyW5}J?clz~CF3bOnM@LTlg|E%wnE&Iwox=@F5CBI6pUBhxEf0XOb z47rBJ+TYwtxvsEPpB*cF9@uR23_Jbjfs?l=|9J{yXf6766647Y+g(N5ov3U#067OQ z7C}5-1%KvgA-ma*A~yX>fpt$;8@gkr%tRcyn9l05#&i9w;kgcG07X) z!wNe4iEPIJk=-=W6k-al9NS$xh&o$}s7t-pUTyC#g1e!gvn$3_H_ynaK6%U7 zYRJS#UosTDyC0ua4WCy@-$$G0SOFgB%IW*W(KYK2LR@nQyi;daQD+9<)Y(FV-?wS| zn)f&5cPILRIPqKPOt(`y>lW6To3en;(zMP(YwT}sH}thVhQ6q$yCDnec%>aJpEy#p zsIw#BcN_SnzTTv44SuOFr@`mD(2>RSTk?AX_!q(1)R%6j^wlG*uM?C3^z|(8(083( z@lv(p?aG6FMb$U-U5rU~L4P=QaKQf0);O2r_XPA3EOl0g?oX)BfzFzs!y@SI5XKtq zHpd}G(4RdB+$S;4g7AGG$ho4c|K|3h_Gjoj#}?*_N{+K5&}G1p=3krM7P@Nd+y85& zr={c(^-Q1k2f*mlPUGs>w*KJ5m~Y60GJ z|9}TT1Mz>-mw>H$D$$ql%KC#%fN!uT+y|bM>|%W`p{#*sqy+%)y}v7H>zK4WAy7r z-LLhyTC#f{^z2dmDqe+e9ArdZJ4f;AM$9%AIO@>0`KHLe%C_KRANXKfTXfrRLV3f` z)`zxFLZ9?$vF4$RQHT0Ej4Q{;DSR0BpTMUXAI|q&qtXZ4yOUPtM%%6H4?;)x$rum! z?a3Pcb{u&6J+bT0jRW5m3AZ`#jcDKD{M83To=e_1yF#e-y^cS)&hR#N^l|)lg-i-y zQzG4!t=1at5iy zvV0Ba^R@Mf@H6eDkL}+_+3Kz25%st(;F`b%ANveoUf}x&t}UPuz}l$ZDMmbE(0Ify zYG<571M783L-_V<{NrNae^BG!PyARPZ-z~|Xv^Tk8n+(c;o4&#@K9dYqu(Zoy$pAv&&j%)Pw$tC&yy{oou(WP&s4Gw(}E1P zX<8>Vua*qlr$c!c0=65p`r}G@56AbnHI7Jqwf7yycPGnp7pnar?`q4h<8^FHC$I370oWcRFA>FV8=F(cnxynsdC5mBs z&2gaK(q)1eL0+si|5E6c_VP#vQM(a+G}j)^y&aUjq$_**1^A~;ZZ_=YBf#9iaX$DC z)95Hh5HIJ)7UUDw8F-14>zW)_N8f&pcd5o3G5>44r*WkY1bjgOzLQ1)`iuNi-DueS z9?Zu}K+Eb+Dsm?!nqI3fK%T1}eZlzZpP~A4a}1i*n&yZ43O`xd5cwT z)cVv~Pq7~LH&NS+vbzqj@s7TI=re8iM(P`~wECQm9NImg!M^TC+fmVNX|uZRMBO&5 zhZCW^JJ7ZY?Xq;cRyze<^t&JWO}e9^=+?vDOVM^8+LHEDxXQH~Y~;<;9=V27 zHru*>yAADVv)zC*+Gg2~Hp{#R;;!7bh}UG^L*>G1h>LUT;f+Gt?gZ3fPBt`EESGbY z&IL37`$zC`XsT;D=dEp=yOLb6A!k<6t4VdSa=*Kya=*-(?7>!b6Y|A50p#BCowCSq zo$ot=J_vmO61+YHI=0R(U&brBb)zeti{@Z%;62Xq*Pm%!_p>i;05|({IN2uWT=tdy z;CKv86m{&QntRolWNez@^yWSQT95(qK_V;6PyPAKF=qV@JUwVTJu;T9WwaG?j<)7z z%jT+VqDElt#aOOB;iw$roNJ{Ylw&c~{~mnzmLIDzz7H~>OpZ8`vk>!U$@wz9lP{;L zlW+UQia&Gy;XK&@o&&(exFQKW(q8@!x%~n-IhXAPKKA7>a59eY0AB|1Z3Di?X)CB> z`9|XV3-A$_W%K;L7x-v9LvW8a7t2?^Mm}J7%gF=kt9;Dw!*LK|AZcIJfoV&(F;DIg z!}?5eE}D$-=ElAn?dvddYt-r8pl|7q^D6Uk1IPz-0^aM!plv!nwmTDN&<3%VpT61# zJ966Edp=01%c$r*WAr6rQHFPQTEWLDF>P~|-SQPGM@Kw1FXnKEEvo=H7;hqvxabgQ z(q5?}$~32{vo9mPi_B}nvZT!(Mctz<$O+1Qnb!U{W8KCvdsq(rHCh^ zs*BGhJiT9>t@drW_L1=VF23ghD@<}_hhYI#_Zh-d4Y){>IJOg>h&7Rg!=>Px2tVI| zyA}K~!gCBfUIl-U@CgRIUcrB%>eosB0!bM2DSq<)Gr*^yUyKM`H1yh|Wgq3yfAyYC^uxkm9~Z}V-?w29@tGkS@n0=s~owY>+r`|d+MFMQ$~s3TBk ziQScr!~RL`-XiMA?q>yJ1Lum(;G^-fsJwJXGcWxIxgK`|$4azM|1LBX1xoHdafS6Ta9`f&3aiP`yl*+IUfX^M@KM!+T0|Nvq<(o z3?Ke5`rYS7%msa1L2E9cj@H(vB2Mb&+do{zNu8m~0P2*>m@iqb5%K}!ddY_?=SQy1 zI{;TB>REGu2Y51oXCLrTerez_8qamQeKp$maf(H&PKEMlTa;S{WYL%Ufet-rn+pBB z+gl_pG35oHkf!C}Mm^dWbzSg)*u^!{=2P(9ns?gAXptO_w+FIcphN%3IfOiNp10y_ z9XHo-UzhU{=F%G4A@MZ87F?KT&3Qe5I28NE2b!_|qKtPzKFd0b+CSV7Ip4~8*4;zJ z)kR9iFM&_aji!v-fUhdx7=u-M#CrS5c>LA(@D&#;{_c;#-^YNFKiY>E^C;ML z3txh^+zY?JXuA$F;`oxZAzP`aU5+sdJJBNIvj&-(LQ?pz&OZS^KxEbT%NvdO19l8x@2xkgl%JQRn8X? z=QZ>gwfUP7`_N~5+gQ0T6@M3?jQFb5g}r9eN4mSJbun|{jG1{xgZYl7SiioLCpP>H z?dT_G;YxeqI$7?|d3*YDT)ljUXDd71hyGHJRzAUnI5!#n!JeVwhZ`Zp$+>*9k5@tp|w&Ey?uvup9;ax zlfX~k-GV)KH{#Sj!chuZ5i;~5w`I|xzDa8XA762alHWwo zS_4|pt6a<6gYT2jz8HK`4wRuBH&TwheTTFRZh#D)Mcu1d7qrZ}M?g!;9dwF7hccUt z`dbv8q=mS$Z%0oc&#HC7*ef4rDKHmejcE5T249>jE^niG4$MmzI9+w`U{7ZJ-ig7$QtYSV48fjs(WMG;THwb5>rpTA z*50IFV@|@@tK%M10p_vv&SJR>KH8m-KB5jdPxQ58-c0e2g#1VL6}6{lVBVZ4W0M2W z@c}v3L^}L)x-Vg_lKZFVdjNIJGX|s3XYR}1j;kB={*JaO;Gt!8hOf^6G1!gV0R2Yc z?G>XMkcUc#TsO24zHfAWF+g;|Ijhokm{S{&7vuem`T@SraDOTAg}&>wsHB6)dtc@t zy83?tK3lRxmlM!e`p>S*c6SiNxi9q*_NBO{xC8fJ;~6mM0p|p>4mo;ed0-QssubU* z--$ZbVLZs|L-2zyyzHubtD6{R?aN@jDdodHRbjrQoC2e{FPh?i4!F5r2pc^>Sy4`F zDI;$ta^A^V`xhuVZHghMF99RYbo7g~{|wqI?cGXU$TN4>dtJ=4o4Of+`Y$5a?u*jR zC!j@pmGL9#yZie3FI2R>F=+oy)3#~a$-pOIBR9i_8h(s(AC6X^xH+@cC(?Iv@9W$0 z@t9ZNkny&qhkxaY4c%6Gb1gjtnnS}d<_<{xRb}|@0Idedo_$3Q=3pvlQeRcysCpS9 zQ?9KSYM$0Z9>2sGv+Obt^&25$jL`$c>p?#=AZO+}_Ce01Q^2;SJz^f+!2W|~g_dsy zV6?x$QrLcbfi*%e|6jm6uV3kFGU|GNhciAYT!ZxT7o$vjcn~mwF(b51SiEt}Adymg zag<)dW5(T2+Cy=f(n-%4I=Nlz=hyFc?e%}RI7i{g+#nR8SfN?Bb4fsiXH)T)TJ`8)4I)JV9gRN2i z(w+?Yrz8J93^Zl~2k|Zk9@ts#ES95iN?d_-pA)`?xHvvcT~_@gl$Qb6vF}3Nc4rm_ z8^Ocg3ku~Kw$V7Jl!0?!H#MvN*qto@v5hq-Q)@^vQ|pE{JETYY=^sB-wam(a$G`9_SQ zuS+gH`dy^2dk*(0r(R*5^pay{GI+feFy6!2&2IOjZ0beI5W3$6-BX6YB5wxYRfuU1 zfN#!~SgoAf7Iw<!dUGgGbdz5+IK~@4Pb5gJlgI=+n%^K zXuddSnrFRs;2!79LbU(BIrBL1Fn(d)_zQeEe>ziK@;o``N%+mm{_tm9Gp-faWIu)Z z@CfEZm`PBeTkUvYtFTtU%AG^yOsT%Tf1Uk`CH82$}|9KXV~5OW;o zs)|hEgPxOeFqfaeoc;=86nT$pyW2CDrGpO_=5Cz-h~VSObWwX=JU%eK`Y%&_ocZQl zJ|=5ER^aLeAMe7ZId{LS=WZ9~ZZ&VGhUaZ3^u)UH=Iwt07w2R6%=@_h;J7?-g$OR3 zuEyvCxN?3z9~V)GhlY)c3JW~c`5L4pBa87DS#ZZSDp6>>-!zl-I*$Ce{l}I zu8Lm$C34>Bzee@*r!i>$S=0OuSL=KW=XWR0;+W-Z#+QfWyQk>YKJBe~t0VJpWjnVZ->(`V?jMw-f5p7Vd;SZ3=Z-bWxJX zd!oJQ(&*@w#kCr3#Ig_8AEWK!Lgs-%j>ti2OfSxyKp3zBAyQ0Mfx}LEKgWZvc*a`(LZuo3QN zJIOXVrMujvC}^WDJ=DD%FfNxd3}SK_!<3dI_n=}J#^Z14x>h{S+ynZ4oU&r> z;SJo^^RPVY<@#gW5xrsCz?&QRL)#HO@%`7a48}FAQLBKLK;<3H2BQTTcE*bZm@QiI<2?#>b=k>>M!&)F7f8xj5^l2 z6UM+pP>xx@Dhu%w&d1??ycqr^+@ro0QEs3c?<`ex4A1Ad_>9qK_%J5m{`x2Q9Kq)> zKGri{jriVx57+Ubv3=jP&R~-NhjAY38GH6DzV;uAX#~O0FXK}wNKPOB}<&rSoNDuSw_6dsK7hi!M>Y4ez zD>c3OxKhpyv&Tg|o46Y}bK0eOo>k_N`r>)3v3-5qM+od4S4TekU=OkiW0<<2jPk)3 z_fiARx!DcLGqMqPX7%YM%3AQ867A}5xZenVEIXAs3Gkc&p0|N#(*1~XFnA7}3FUPH z>>ad!jqM>ntG$P9A>VzFFWdfwZ4LQ)kvkHA@!a<9kVS*Or`E8o&uFwzPUypBz|V2; z9NIK!9-`N~pUb+*{-;ofed2wdGo=0hSN4sy@8vP3bX}y4F8~kH#_x@9 z<7Z;nc!B2KwDI2B#vg+Istgq(tw=Jz1dBK z0mqw?es@3p@Z0E9>vNT21nJSnPomyKu<>!E1s$}GC#;c3%UUB%R`iAur(rLQqtc_)u9l*-!t$F%xSq zG7I;bp)dM>=5$Dp{y*f%eADvBmY-)%2M0{#Gwf@i5BhyRe8-XDFA^xvue!=<)X|GmJL{S4Z$Px7oY@X&Y9;W=lg80H0C>zp6+ zvh=0R`dr70u(fyb%tke2qR(|`-_3I!mnq*pMcLWoq@mA7AO|SVb$kjKeRogDLV!o=1CytAFR&qD?L(Fjn{Ib8C&-rX2pGCCngZcI=!OvDp-*1WK z>GfK<9Qo!QICizBXHpyRNf5WV6HTxAE?`f`(8n1 zBgD@&1+Tx7S4Z{pUqJ7mMZTivt*gm1Z0$6zQt$uEar#%#GRJ8#`1^O`bT`^WkJGz& zzWN7_)7P$zF-~2BrEU_gSGuVo4P#tzJ_rFu-3->c`QMDw8tg5ZoT&AtRK-`&;65#d#KB`_sJ%_4?&FZ{S7egO>qq&v>;7*Com}9mMqSz_ zbXYkS{A7TaL*RwucNhC%*rh0MC@bgnd2L8z^}di93J)f79)KL zGZc@v#NZJxagjWJ#Cx#Ofw-oE-i?}1jPpv$)5CENUoj42iSjIpl4p8DD3A8u7HucS zY&#rrba($g-99h6{h?6a&(OXP+K-IY9{q5lAEZrxYwFU4wdFFjJ%F|YVztFs=?7b3 z+YxBXwQcWM^oNFtZ8y>9_@q2x^IcJwbMb$hZ{d2g!-n1ca)YtuqKWDTauXEe%#YjvbQI$&3$)% zuNjWe&klMKqq&|=%tm|*pV!l$-WTt`8G7FGmeQo`Lkp6!Pi=D6?S;%~GgiFtJK*x- z9aVT0L$(X&URw%#3{kNUpMOvB_XCfN_!v0gY}t{3FGWviMKALf|BS+`$Jfp1m&QLVn!o2}NtGu4>+ zCHllYE7OPlgZ%`KPUyeD9wF_{jTCZoW~{tZwun}0>t(Iw2MVKUA?(m@eV6b=hbOk&-FuG|5VnR+*642 zk09n>EfU)Ej4J0S%O)7(A4ZJdwAYqBRPq_QzB|q{J}Rb<(3kXaeOqG~uI~m@Un-_= z)tCEnsjqc6DSc&<2I`plS_ByV@K#(YPZ>92y|dalgSt6teaCm?SZki>H6G3~J>tb0 zkL$Y*)T>$-C_f2)sModNhk8w;UJZU2H(m!m7&pH3nTqpc>2w_X0iAw_tBmv4#MY~y z-$1vAzOrSnfgjiko$f>Z=$L;MbeA4acb-<=EkPb=&*WHfjMClyo0aZfAPr-VX3TF# z|EarSxQ2B%HBxtDu)lVWpJ1MIO^h`<&Ne*HeJbd$;gNB5Hsos>Hjcx)>O>uLe~*Gs z9pCDCPw8_Xc%(j`qFxLh-N^sE55C_=+p)ODn=2@9>hoSppL-o|uEUsgcDoloPQCMI zd%b$+56^J(oj)#{|n!( zbD=KmTS;F&mb@kVi8Fxrvbb;_<09}ExPMYL);N+s$y-42cKB|^TN>$K6X_pHG;bSu zh1{y}tnG#iMVDse9(YFfBj7t>Pr2`jH5ooU4~RXiUh*7HU+8kBJ>^(|+P6|?F0pU* zBiabwNAi&DLl6H;BpX#4Vy0ACo zW|OYQ_wX4)>=lzPZIOLHiFLuVtUFruoi@q6O8B@s_PGILTFOBP$U#1n>)(E_;^T4h zf%-Q~+e}mWKfq{5J;@K_28_dorIGJ?+>CV|{2$h-t?#Fj?~vlVl*%VmhxR(;T6I16 zY6Sl9Jdg2_f$?z|e67X!pbvS7{WZpi_mfcG>)?U!PF=?K&}l?_*f854f(^6%I<_}# z*o`w7yU>0*+RusA9`?Y!CCLNqfjBCnaA1EW?`h!RnE;;A<=(!nisw>c7r;rIrxE2fXWv7y5gBV(VBAU{B1_D}Bs^SjUV4{@6ZdwDd9iwLJ|0 zPE&@QE0zLAJy!D`{K-zxviib&zv@q_{~f>^)=aDx%X0BPL7qiV_16Ga1RlGCKJAL~ zryiLPXbZcd>^#&ZY>MY_x51v+-%PDb%bvuSp}ZSFe?D*}P*%XP6?@v7<=J=I!f2_> zeOg{gx_#JJVl6Ws?HN-(cNFsp+7q|R1Ew9TN1lQ2^Slyu+Vj0l+76=ECc|)_d40;f zlyZQtJO&u+7h;{S@Y#%3@E~^H)ENh*T70|KC!x&R`%u}3yXjkvxJr#DJ3rTp#0^T{XrBL_^ zGF^2zms;vUJcct3{_;fl>QHFsyJ+(+?&ss(HD2i2l}`VZQu?WsM|b}a;E~UzL3a)2 zb7}H^vfp~-CUFwwjU4i`8x3C*N51Ed!%1*6=ZZ8 zzPf2aPOzn|2+w0jaNdyTYMTXa=>^d{25#~-6a;S zhkf)Z?_G8%(RGH;CD!Zw6`$)c`51;aZ{xX+p5TK#w9ccMj#JoGw5uAKcL@{bmU%WO4j)Oiq_YkoZCm2rd5V(6?DZUa*0G`ux|ygC`m1FS1tW z9(fSwFYK-R0^HA`KRJD|qjfLmGDr5|zlpk+(e6lZSM`xT9jgx|x$64$#IsST+W?$= zUm@4%<%qw%=L_Q*U9FeBYR$msI$pwAjGf@C=?XQ+D|z9)Q`8IASKId~Sv^Hrp^j+} zCjp~9TnJe)=DrwshQL>D#6=TJR z_ISoHXyMomJcnVc9^#R9+8r@hO4c^mDsgR$!j+D5{C@?m9|PB21~0@Talqc3us62- zc~n~$Z2C2{rJd2nXls0)!?JDH=U<&;+b7_Aia;l(Z40Mwown^8fOj%*(GD6R%Lw^! zj|;LUPqWFBA!|HCmG?N>K8>~!I!4`@ID;g$Lc?LTC4ki zEojxF-j_!(XK8&z&v7e2oBAD&x}2x@y#};sn}Yyr0I#v;x_M~FxsLZ~H(XDn(FU7Vw)!jOFYzwW zdc4C`zGD-<gZkWAUE9ad@}n`05tV1e~LvSpDr-=6w3eIDQ$Pe?EcrZv$c!_A|KE z;p+sxn!&5-C+`A12mIu=to6Bv-m)1vlw?2s%(WKI6Aq9*1}j{Wv;K zjYZ3cY=RwIwB60xhnRX#!TbLVee41Ku--9V`~OkV9tZrZfol@#Hp1S*J_I~kK6V@Q zMn6J-W7=dr-dDLE?KhzPD5HJYzY>SEYs4+k-8k49@z9=3JXN3K`G4TK26#+4uW9Ga z9mexECql!Iw(sscGf?=x=y^kSn{;pP=Y4L-K7E()wd-GAeWXzAYHB}aIo5zRhdNDJ z&b}T_p0YegwDmRF#qzeGd8mz8o`LJ(M6vt}ymRF9GUu{M7mDhmj_yA3`NUwmjJ#cw zl0_ZqB>rY$^%sb55-$_gpW%MH?Tf0XY|cG>2C2OR$!@!Z^T=Zl!&2JRZ$*W#{1ipr0nWmM1{w zpPlbo-jIk7c=-(HvC03Zpb1ec!C@#`57^AmhIPX6aha zVbl|R!8Wa*582lAJ)ej2&Iinmwy&}+_>Hg=%r*UB%hc_k+19Y-bgXeh;FEiX&&8rE zoW6drMYjDt+VZUGcGUX>{U(hgkeRe6$jk#i&ve4scF2f4I3Xj-jBP11%Ih=8>Ql(- zDCBe+^4$@|58u!FA^71tV8-Jby{>X&>@m(iNZCSuiQt9v(!Idbpk)$0pZ!tSU4=T< z8jNSjtoN~6YrW|Cst)ZqU-7&ybC{e9n{c(x?=m+T8tVwh_l)C_ORT}#CCetC)wARG z8SGh%`>`IcIfd9><{2F-&-gDnXLVCC{%o~|TaELEeD5*Wm$S!;4PI@xUd&q?5$m6n zcH7nOh7ECDRF61&3}t}z3izv|t)7aA`Fmxp^{V%lGIzEA4dqt`QYNUY)<^317JdpC z@ji!ZNXPpt%X*jXL%iRB=fo^tx(P>;3o*aRPdVDXh35=Vu_`y!fcCWattuaJz=QrO-`p*08~C98 ze@R-Vys=-AK^Sc4u|!c@j&~7tO~x7r@9({0Z#!QL^t{-mXeF zRCW6LD4su6>x^#x(STLmJN=?Q!d~jdnHA4nt_KqwSP#5D6m7ftx8dFW<)`j?3-9=O zVzQ)7)A+9}TP)mESl z?Nr;(@v!~C-)+}+S_~RD0$)ii{!nk5=5HzJ@|M63X8wS& zF#VO4Kj;P7^g{mNQuG(Gu*@G=@(Je-L`Pqa`+Su<_?sGIJ=r&7ZRdiIz8x?Dd{5wN zl;n>#Rh;QLaB!KZbget^@WFJmLphFv5aP;}2WolEyxP4_Nbqhn%|4u8Yw zMXZItfj$g6@FU0_kdBUt*Bw-}8e`BJtZ8|0jg>nn_<^~DZ#$~oft5G720V?%xH^qo z!f4Eut#NU8|1R)BeKCiy-M>2bFmed3`->_zZbANF9b)5Ro&`nz;2E@0aT{Z9l`EKo zxXm4vE0FThxq@zx4-%oZe#!^yxmG{R-;{!Um@9Zw$z~&EW2|4P|IYxU{(C_-)LlC8 z3`VZtVO+V+5Bo~svf|jakTu8qR<<$hiRqV zQF!W+C)fu(%(quW;gL9CTTa*(+pdmk%RcQyTQg5k3OrU^89<)Ev@dDL*q^-_bPW4~ zpTXKr$`5%0ZO7LD@Abenl{`U?5wc;P0CFZzw~;4P&X7wb+U`JGQ@>+T_j>F(r6W(! z@W$ljq?yr4EN6`Q>KL_7sfQoG0_}#xk^_9(S}g|`XueAPjqq(+C(-fM0`Nc@7ojfw z7{6}=9s1OMfW^xf6rkPr#9z{9A_ld57JcSgH{OA({pGs1)Oh(DWEl~^!?t>(uf#nK*Jyva z*~lTJ=-5lznqE)R)=t2Oyaqm)N3iHiTO)ng^mbm#{3c^BlMa36 z2<#O8{l@JuE5(Us3k^MB_O z8#et-EW$hg^EP#|ElOv+>Tpi)gJ-ZVl5t#`KZH6%;e!@~f3B~>;|#o8KFA5)<@g7G zrjDwxf3y?4^Sx%&J@?2xk$99ZA}+%ht%cl)Z+;ZM0QLnp1K&E}n;wP7LmbfAA>B4V zsx5ud188gdqKAOT@4zQ(?GUub2Qi-P(r-3dIOSARA%e3Qeu2r*M$;C`H|7$8s6v_Uso^$zbS`2K6$zoeWHy8?o%|l zU->_zfqq8VE9Ql@kOOJ_9W)~3fOoJb0>(UV1@Kwx+i1USLmg``a};RMU+)4e-a7gu z#^qH+Pw*QxQ>>2UI+8M{|A11rONmI7UvY> z`E57yyvj`)%+*|G_bt zhj@EB_-HcdOIs&>_<&+fJ0}KhpQcSa--GX#jfefVrbEB|Fy@Dmk#v;bCLQg!_aD{c zKL)KOn$`|nrQco|mH)jQ<3i?tE&8^&hwKa?!r2F(EKm^RZ_%kl9#{7ZJ z!0myatT}2Q^u%%hKH5jvV{<6417MG$J>^0hdpQ!%0ky9NT*e&bgpCp3{wRE2G43hD&J2# zgxGg(lPM2*C!PYE0Yk)1$SF$blB1~Hgu5n~fMf+%*>cBH#IMZqM z-*sH~-LR>*apvoK_C1bG?f+QW)M()6+GA6)ZIK)Ko=s2VT_||}?4~#H3@+X!xv9Nv zQPuglh8&CBh^IDnaxSXpwY_tZz`H^??q0cCYOfPT2p)_q?|5bvI?U4^~yOouC*I9u$S zH|9e>0sLk`;CxXx67?*-SvouUPs~FY`}7B^(5C8M{1)2_w&m0h^=SD7YhT^eQ(xFZ zQxo3P1stt0idr9U##zC1b8XysuC7iX*VzOa#?w{*fFA$AFDM`M%ZfW_ckGvYO;WZE z_ud4aShCv(eN%S-gq)s_(f^&m&3;OMI7Ri{>ND*#+BU0EpK-=)@`U^V@`a0z!hZPt zRRA*MS%R@%yk8Z5aSLdgV{0t-diY#M`gyH3oc_VNa@l|w^H<*^m+^;{Tz&~2UdDSy ztnpC)_j7$g1@>j`B`!5LM*0GGl5c#2!nK0^GUjF5JE6QCz-{tR-*6AkV!5#Z8-abqUx z2eIeKd|ou&Qqn!8=&nPX8{+7@UqI>G1KAG;o&@x3N}RgmAV=E9Ow`RnT^H-M&KC!y ze};_4K}M{1J?fbsS7MljuFzv{M`RDMfbNc=-M>hp}1PHM+$63 z$B$t;GFOT<8TD(>LA--pDd|}2{?8RHJcMyhACCaWK6VE!89)9w@*HqMClNP(gid{Y zugc@dJ+SX%us-9?D;{5E2`OVHMi)Yytb@!8L#w+?EXe-?@2Xi#R>f_O|-%NvwJAOYu&>h%$W!_3ZMuC++u{ z@a=&2iNynW-KKfC6g=>}56978{{bJN$3e7DxdnXD?{r0dt}|JmK0}T_edRinW%>YK zxmUs~eSln7{vY^(K6oDKhxmb>I9n6A@_YP%J0vHZX)#I5wlvCdmse&9@$9|&E6dB?EbrHPTYYx}vY&Q_^n_U}-aePj$!j~w_P zVK0l&pL2Wy`V+B6g8Vp+?gZba-slsaL!YRx4Z!u2NL)1@;?X{#ALK$DrO`NW=HW@; zcm?e(pCDrRgbM6?Pl%Mg@(GkZ*G5{$BZ2E@z;#6=F9#$qT(jxEOpf9s9X{bsv|Wj| z?2j8)bF5o(d=~J2v2b(Upm7fYZsx~0Cg1uf{#bW|9>;nb>i;)mJ$io>^ZfzL_XmE^ ze6P<{_eY$^an9f78KdX>Wr!KbJNMec^F5xAIRg8U^F8)Lug zH3r^B-_5-&j`P0gGsoKvxc<9wPCl&tSu0<(A3W$iB}t$1TT9x|?K(~O#TaxGG+o+9 z^f))^$oU?z%`=g7D&>4nI(nRM|3>w3V+>lK0meS|0xdbtqs~=t?)rV>T%D_cIF&izon8|Nv#A37WL z`3^hv{;)K8Ua%ixbnNSd*XPXnNSPRO@(J)Wi!xEM9%T=iXxU?}o1o?KW6C2c#(PT3 z<2~L(Up~5AY#5Kdh+N>)`=K?=^T>DvGB$lrKj@Tx<2K0Bw54>c-70~PHnad^ZFD5A zN)Pd9-?I(85y!RBIFK`12^@@PEZ^h)>MPZE$l1zMoCo5fpSuPgUp?}U#Y}r z$Q)-9^Ckly&y-19wB@>^p?pR*bu(J8`O4AG8Yd$qFCtj=A>}QC z@%BP50Zq!~2(Izso4&ZG)=WM8#B~$sFjjqEw=vg60le>sIrCK9x9|6ii zpS!T$tCtK|JU{s=@tJ;-eS^%`LgvKxXX1?g8KiLU%=qK;jZDRS!Kcmh6#!q(Wr`{KHc7?tA z>>A-~@g!7Z%pYLBsCkA%K6}Emy(e#RR-csTdD~Rqf&0uOeOulZ?-g^l=9BJEm(T6} z0{KGjNshrg0n!m)Rw18sC*nFU>|EeC9-2K)AD^}7TzftHI8mP^x!)B$iL<kO$J= zfcnG0(jC}KzH_{7RWA2n>@jFf*R2M>}k# zp^5h8*$=Kt!?Q_?8rDpzMr^%2=guBI8_~y%nui|W4mlp$>Z)_#EUg#sEoz*K=N>wX zE;hu@tMJYu880tzB1Y=zKh(!o*B|d@#BW0mvur7V=gy^$9S&(rQpdeT?PKUilgG3r ztz&mj-}aEQ-+Ljy0P2|b`#xZ_-}cl!@`as%$FeE!@wOx8!e?1_>&3lBju)JpJcTop zI!;vaH0&uuju&-4upjJ~zL4X?95VsDyX+Ov91gs5HNJ4XNgR5P7zdkV`{mK?alY`^ zXnz~p-x}E-@0}+Ph<`Qh+oRf6f%dP^b|~5=L!WQm^}dt87`Zz9rEfYQJ->BXQh(;FN_o$+_1;Z zcqi5>yc4U}dwF$FtlYfuiO{UKoUk?I`P$Q-{s-@Wp>6Gj9W}saH#r=ot8c8@xaPq% zX|#chu%}7C=lw1;!qSW7PacNeUc|GxXJGqhVAFiZL^sH!sl3$=)VditWR7=ln(y$p z$`;z9j{(#hGq&|TCpQ8{TUd|lQsgG-C$_U5`gRZcBOo`+4!s|JMLWcE(XBo$1<#$e zpq}<=mEpA;X=9E{IIU!{L>Ts-&)nh#YwCUTqS1?BTcDxg+ zbqws}`~N}v6O3W_(@Ks7MPH8t(F^ZB=#e#EC|~zS;Ex^)sk;A@*k|nvMCD^?)Kxa< z*8@N8ANE=)*GIHBu5r*W+Uj4?t_bx`K_922K2oI}G(yf+8yQov9dvOBx?sC{(nFoy zIMdE|7^Y)g)eQbN0oPX2L|?4-(#A2Sw_!}P?elDFjOhU0Wp@Z|JEH9dv^|1;uq|;| zJd=kE$YUI2K^#?4IG8_w3pic_j;nBOK%eO|qI1Z9!aX@>p?wSL@;+_lyAg~bQv7!T z&KzFp-SiN3z)d5E{>TulA|9mCeCi@qlZ3B2N44?CFec!{c(T2I| z&+y?o>^*$A4tp0L;$pj4{60xqTsNW)^Jd(u;P}oFwjm$B$MqYZGg2`LV-MuGYEI%g zBfh^|#U&2B&nTgKDd54VP-nVPh3cr4u(*}B(x}w7e(NM*vuP_85u)Jy-kA1Gb7W@3sN^F;510#1fa3)B$BQYTB5Af8OiRV{s?i?RW8`lu$RK)(y z_iLV8ad!7Z<1F@firCvxog%BK&Z@J|5OJogVo^?2VF-?tZhx3T)FI zCY9ZMbtUAK>W!`ljh>v^kZ<)0u%@s$OJs4DXnde=^)mF2)oslRKWB;-e)s%@#hIem z!s0`rGbX1f*DG{Jr_=+i_uMu&k(W=n_5)8hcd2B|V*YPtTqP$KK<6rGZ0q5^r8}Xq zWCVwAI`C7JxcFZ~_XPFtbm}w5+uCfqz{p2)R!OjoT`+)i1Hgkn1#eLnycl}@m%x)h z>N*cTMrIipf%rstOm%O|svG5;)05P_k-BO4OE$Oo*!sKiv9-@D@zq=GYg`0;m#;eT zF|zz+hmXetPv-@E?86mdJ3i<4j2-i(!`Pvxa*bV)#%|e#xyP>DcXaH!pOf%+D@!cw zelE{)p6BtL!1H{b6M2qLgqB=rkLi*VQty+O$Q@H3V_FBE{d3Wb{%mz>v}je3+(wyw!12aI2wpBd z6Qr#4jLItpSLb=9-;|TV)i+f;&^Hr0o@QK|r8{~?x%y~ZKE(pN-79jm`-Ic(J3Pa* zGl+hNSQ~rwOm=%q+3%a`Y0uU(PJ2er3@UxO&~EeW9Bn?}wE2R*LGx;8ZgM$YAL)?G zsicqe%%Gfmt|kZD1Y6IX3@%O_x-E<8w=IhYm2L$O$-mL?R|lFC^L@SAhrjN?4%XQE zO#DWlBtiJg`mqja_}Rs&O;2CU`qo#SCVnxWm=4irQ8(_4h4&lQM^cY5p+ElTdB&Bf0( ztYcpoU9@SPWpt775Dp7WoH}`5!B1nQae5g1_wc{^&l=O%t&;ynkBAP2_X^0P(64k2 z{3lxcGiyv@oYNo1JME8nc`eO;OZM2$C6Del+RMpn$j*BlUVHKF%pi z`4K56Tz;2@OB$W#{|{okN@&BJ zwfM1>x`cO4w@V%mF!K1T{J)a-`u~gk7Mx)`-Epr4_Eh?z^8%Wyl1I8jx51Htf8d*P zvK^wFYc9YtTjhlH!2%PpjzCl-2X{JDe_SenLIB}qp8217~wyGlkjnI5s%gi59a1<2ZwDra2Vj=Am8aUe!Dg?>yZw9A4@y^ zh`DX(*v@u)uby@sKkDqkc7NC9Xe+}z_4iA(WA>m})A`AxLSBGY(ZAB1pUWMSWAwu! zJ3dcw+!59u3yI_Q5%0X??#EYHR=+xAY)apXZy5WWo_bf@(@Oa|MZ)7bpVuV%I`4gv zNVw#-!M%MEE3EH&Kfbdy$G|}z=(}vfvY<6eW%OO;^nH9c8$M9P}b1pf^cnel_7OXUS;YYxd9KWa|F8d5F@X9Qw?loC;Bhc<4>Z)(z74_+M z;COj6N)Ci<-dsiwgi#%NW?wsR5;uI$K$~BN0sBhejmU);Nv_XFjzr=87_mM3haTOB`P-T3kI9a2<38KB zaRA?jJCAMO#>nISF}ESUUVmHoesUH08bW9;-+lev^(!u-95^O@@NWri z$Cxt%kue$MO$0xF)xb+rLGn&_#+P4X4XA!y=Q|vGHOlXaoF!2XW#x0cf_1%*F__3- zcl2WMUF7hcWr}Ubfka2ZmW;D{93TGJpJ`;eqqUwuvirI}aW|F}rz$}l9Fu9y8 zWXpHyzZ-9&SR0Ll=r14BZO}^Rnd=yX7HH|x-0)`_n#0yi@j%%m$5XF&tucy<{`W3wozn$CNaX9~Zl#xxhc~;3>iIH^0Ol+t00( z?8%)!kEAmGV09Vs0?Yh`T{p4^@&NO1CVOemvIipiYcDOs{z~R#|GWja)~`7Dy@dlL zCz|sMyB-|spLf+azi??ee~t8KHhX9j3%KtcySASB73QhF!(XAzqn0<}6!ErG-?B>0AQGP)5v*9P*jjDZuHMB3j(ERZBJH{IB zbzsWBF%KB3>&`vHkI*dW)V(jOZW`VGJasovcNov(`BHwtHxr)#P4}K*uQzT0mh9tC zsoUh}fowgvntGCDU#D!g->2UAL48TlQ|lJ3dE7HD^3f>1-CfV@<+uDe#@;?Q-hD|f zdz&@P66FcfzMW*a(U0s0`LXk=h=Ejmmyb2Cd@?%sBKur%96ERLDLKF;pI_jt-Y{rt zZ0&Q7@?(1(Y;Km}L zEypjTy+z^Uo`3m>y6e#sK5%LA;9>NH!66WT*=hg7-yhq4nbZDUo^BhGA+oW(?R-o- z{qW81VT?WPpdZ+~R6CA-$UD#O>mPEob&}K8*LdcPd)Ge4=fu5x&%Ts{iyvRU@3{vW zCI5EZG-SmN?wfe)UY*nMO`FJfw@<%;N1o&VW@ywd)4|)7=|S+;9C}$edd8@MoEL}a z%Ujfcs$+fh7w2XK!;G_S-_C;8g7ZukoGAIWcLPUbthn^$S+Hz4f%sOZzL_5$JVL}? z?V$c6)D?{XG*7GTJOh&$Bd2WkJbRt*;)O-vBYRVPe872XFV2ml)EvrjZY<~gfiKMb zVV)c_f0iQ0Wna4M)EImuyW5>V$~CF^^JnHy1vEHz{wO~;`DP=hw9lWs^KG6gS6@6d zk=-BXT?m+43?1xqW12r!*8FkT0-8T&9l%@`9$KTm#r*jaxOn*5whasptWllzhvaB~ zj??~Xp6>e8oj=}ov_@6ln8J?j*z-s2IP>S_@pfN3*;W=9)jN{>AxY`yLCD zx1Qc{{)~oicg(cs(5CN3Qk%YKrRGw`?bkMVWDoy4b7(tyXk8V!yK`tOxQq8c%EDcF zV@~GXo7De9$NJmN8c{Gjb0`SC1*bU+j^-vsrz|z$kszg_o=l`yMovxy zJrpd}T+*5id3ww~bqjXfu9a5mMdhS5F;WAQt4?E&h4pSdbaM9&Sj%ajdWmbpD3{$e z1FiLULMPcS$cB{cv^0Jp?NMXXY{#D2ZgPECUyPTBPBnW6TL0{d*nBu!eW$KhXRYU* z1?=5=qBGxpgEMWc*`zn+Cz9{mVsF&eUwx{lz?b#lij9N6!JH{*$FYy*A9*A$ad32T zGWtt6F`m21ocW&vm$-w=7M}f}h5V~&ew%y4`F|C@0PW$U&pOaX?cTxvEi(>*~gAye|-!c zHI~wCo7lg;7x>z{w$OLqzv`?NMfjhshqPZEs808^Dr(7jd6@n$cx`lDGf&YYzkT02 zxNRr!7I^oqD=tdyVBb23Ots9ub%1^Ae%0lyjjf(fn0 zZi6nJ-C!LGSypNEV%q*1ZC_)BWgq_n+#UPamTT~yE!X;$2H^q8qnEOHAj(;>f5Q6< zsIU2``r2PNbBwhvc7|ZtGEVT!{OZFxw_oW_=9ge5vS7w`WhykEN`d)cN1V1-2?q0F zC-XsdAI++3kx$~c)IFcN;+Y`zf9U+~!EfyacjEald@_Xkn|?jo><=G?FYG(emRd|M97|{r?Z1;tk~(>;@`tI+%=Wzye{0%V7c8TU)&cHbhjRO!a~bc{#(g}s7LVaayX$x8 zC2(0;!N~b)>k>1rUo^3e_grSTxgTMuqMhgAUAHfFz?AO{-P*?4JNW<{ znNmoe;nR>&;+g))ltHCI_(pO;^TXRG`K4Y3zRNHBetVQ(_7W!~f7KkP9S1&V)dXAq zuKuO9;4Qd!XTi1bS^WaI-=%(K$NKCaP#-!EgU+gZOIFnHfJu5tWWA#j%;tM*^;W33`jq5N1!dDE5)u1zN1d<#EoU-1g^t%JQIUco0b z`%-8ALx*hJ>oVS%`LA#IT_@a<0)sdyK0pWnvRr{k&z;}F9+ocDk_rwFT@8zQk0$Y6W zch%>+YfsA86XKnGI@^Ka(ZMzkL62F`Lv{a>Ro5a8wioYSqV9ZfR^3WRU(6s*H!53{ zyHPr;9<+)8UwW~D|BvUFI-px2w+4|C5^0nsDM^Q%~X+FshC4J=jrL@LYt`@Ba z{x9@Tikz~?(?8KH{d1@K{dxK)!oBT|{<-IJn-8uNEs#C#SV{kE;GOty4^LN~y!)G@ z^5m&3{WFsPUHzjx0n$IZn^O8Gk1(R4%d*ZKf^J!hj=4S*IaH2bA(pcA zZ1l`9^vg!>WDB8Rsv=hWBy>zk)QX>sjwvTkUX*&p?2(ROe{>f5Y$f_kYmw{FXPdEY z%h6>s23d0wCa$G0DY>zOK4^UYul3LX=zokJ61|a+Yp<|r-8BcTuX1SpAWv5hCHU>t zLsw(NxVl2JMSAG7Q`*~G$2?zR=D8VPTMy;Uu-p6xPin;yvwDBeguC16FoEt9Nhhs|4lt~H+cT5 zdMHD#xokaTc!l+(yT2$sG#6YQJtSUP*Ul@*-Cft%d@@UX;*r^s1JCeIa$uLfAzR-s zJys88w%5&|@d`P~CI0>PipYLS5;hKW;m|9=c9AL#rP_ zE9s%Zz&V~Cx>{w?Lwzapuj(PqC+Q)rn{=KbiY~4;6aVVx-bs!o!Oj_j5mSdge`S#GAG@;5%549UVmW{~dbiU5IzSTGk23 z_)2hno;#$^?qQ7%Ir|<1h)0d$yEQzu+V(MPE1ZZQlOh1*{hp zYt#{^b-L5?XuKCRutvvcUvJ|zCkI{)4qhMfTnLJiba>@=f?+tT(||YeGL~nu`Znx0bNq<+jzpyn-QKBJy;jP0hZhgNo*&^-v`+)`u z2J-K1o|1pZi<6R%M=}4l97`q2kxxegR=oUO`##+Y{+C=Ei~T2CenF1d)@Y!!iETB0 z`k}t~A+yKZH~9`RBR{6E*ZIrChM!M%WlItJQ{#{=&~Bq`j4)wa>h~P@m`3mVE#mH*Bh-)jg^-*5pD#oxLow5L()Wn+KhfazycIYINr|Lk9 zFK+KI_Dv2X9`s!30AHC{SVvxCYp}N%J1bru3Nv=LoP3!as2aag;Y!?|cl_q@E`*%@ zF;DFo-Els8b@7zMoqm6~4EnG1`&wUPf8%lH73!>R2KrWWEIO5PU8W}7GWR=W`j|5I zIgHyb=geXIzKGoq^<&M4bK_Zw{jA8DU(ShR{rd>!xE;%B+d#Bg(oQp5o^6G0;-f>f;ia4QT2A4e z=;YGOORofSQ+&YP*4v^({P86!>!H=_d>7y8`vZdQ(5RuU$Jl4#Il=r9&#fJCTv8<* zq021jBD@;2@M<8hK_2gvV@~^h-+*pr-_IFy@tgO)s!v2$cy~Q@Tp6VD@&(xPW_<^{ zsR2A4n&kKG$Nq%%Zma#|R> zjy9X%vmc-@uAX4U!$Z%GHxcI_q>fuQ#5z*z^tXWtT}stAi@8_O-5S$CjsxMY^XxCu z-edS$E5UnDVc9&{Ub_p*=4lU6{V0!|8{bI|o0o^$xL@MnUTh6CIInVWepBzMSA0eR zv7gw2C*G^Gr_~ESq9>f@@XCQ0Y zi?Z-NNj5c^e69uUXB1p}@5ub$7+bE1epyo%PNzTBW#~w^Z`jQ3ee=;b(WQj``RJe4 z^Xj52!0!MSEChm9XxD zUOI>Bz8l563H<*H4}8(p;78wg(f3&nO<&4tL-+Un6M9@nef7J*iuD$+DTZD1>~g+I z?g}ScwiG%(N$&p;9g!_R1g6TGJuJ#z#eB5O4rtxP8GOkdeb-!;?WNyZqbjye=Xn&v zb7cN6y>e)s?(kF|N68;_>pID#7H3TtJ~#5ca^`VV>pFC(1)pXzd5KIWKhew_k-g-e zDfvFU@f>GLZW3=W*N{m|W-@l7Wo_s@Ba`mA#-1Zrt3Q1iviZfS_Sdr89Mj)g-_z5kO=qV~_3PfkX*1d2MyBzt}NYa^2$hhCyxGr2!X&{1AIe*kUzV-xQ_=_o%u0bOle z``h%XCx^*Qn?5^UJ(eeiJGfrKQ)4oRr^ajJbRYIyB>KJK#IEha)S_GqR$V@z-1z zKY4jA#60Z5yX&dD(NlLV@GFh1p+0!+1TWS9O;-H|^hyR?h0nXdXsY6TB=h1<-icoo z*MhGddmDd7FY@YU(M9v*EY8K&d*~wGwb$V8Tp1r9eyvTHB{}Hw9`7_)dVyOLeAB#$ z7;SiN&k>tG(!G%!?cRZ}eHG3PoWsqT!+6wlbUk1KOyCv!vNDtYVWi~2p8iU)wBIPb8h z?gFionad^2s3Imp8z{rHf=s2VSm}qKo>Yc7Eh(KLigw*Mpo%Idt3|_z-{LX}4pWdGX&|TAQQYH=TCH9~zVT$Ge2B%kOWj z$Ito^Fz;j>N?tpb_x{M5@;{H;rXO3csPyF-c7LzS(e4JP-90>A-or;Vr>J1%Rm0)I z8NhaBH~h1tod@CRt?;yPy&0UnW0&TRrIo<@3OKJi^1)ceiI#0X7We-6{U#p|cPrn< z-5INKz&jH-QT&J5^DoSLWlR&+Xf|4Zuk_tckOYM)#1^hDZH{gblli!N7EU%V{ZboRh#uMeLLbM#ujtojk| zh`x~ecTg9d-uqWa@Y@XQFg|uati1Rz=q4Pp+85tx^p`Drq`%&!o|k{v&#&mgyW8Nu zc`u_skzF&}ZEk69z(qF_xx?=?+yNb$Di$IIJ!T>+HIZu zV~=Cc%dUT``9$(_2IMO%JvhM^k9hWL#S3L9r1Hz-|g)Uqx8wOt4aiPPW#Dm^q;jwkvrwv)f(tZ=rDw{uj+dtd^?GL@4CfmBc`Bn0e(z#X7d*8e9wB^cc#Ig z_`V6wp33ix&6~+|O4Ocf-I`&atNt|NXo(jPZF$#QzGKB^KTIADt-(HJ@2hf&FCHbv z;3M|D6fbvpf$C4|S&{{OO2D%hj1$Fg)i+wgL`3z_Qt<3#~~-E;Z)d?w(JU@X%U_{~~?aWsCH{jB}c zml6|x4(;&{*cG?=t+r+42H8)!*ybzGnmdFsqTIs9E6*YqVypam3;e`c;Fnp|Mtp9* ze*3G-`0a(Icwq6D*4VPmsb|@ zEt(%`lP@{SopqciX|(v0PpLcYOd6YR*TH7y{l*-egnpH zAbN5@X*qoVF*FiSA0+?c!Sk)&m4b``nvso>R;%0 zJ$XT6cend5 zT5RrK1}%Jv&E3m+`t3e996Q#VnZqq+tOKnP#@b?x(yRU9%#;4G84tY+@$Sd|un&4@ zZpcsj(sAgq+L@O}`9O3ymJi;_qJeL3hB@R*mh%31bKy1CW-I;7b>?UcUWvdvgDJlZ z-Bg3DQ4D~qOSDHWeINaOW_@4EJb<2WVr?wB(hUC6Nq-n%E!z(-zREXmJ<(fpRXRP$ zQ#8KF^SjRT``7%IoM}QQYyI5JeBb22{n)_ukvrLMd~q|j5PwJ6N}f^vG!JAWxO1SD zcWJ)gNPWqZ)!^;!A!L_Lt1RtZ>y-UIWrcUQdN==r)$ZTpyj&80^AhQ&1A#pD$AU>8 zzGvydgY1<_H#R(e0zSli&J*P&hB9YcYKF8K-nwLQ-86clzXQJ^@=%gGt${EoTu%2d*Wl2f;Ol%2Xyb9m=f=<3eH8sA(%9c*-jAZr#=9~QennNYfBxH@>q5WIc3r(TksND57L9_OH zlHb%5okjm4C)xCG^3XAWEzs0~j^v;nPK<;@_t(&ep+3a;be_!Kh~MaU-?>(sfj0tu z#&`eece>2AIeAU0Tp1hwnpZKe%@LP7wwfO2YHC+>xoLPDV z{g|m@jF`_QR^cg4BaCg**38)!&ebKSZDvjp2UUE-=(FaIw8o_8PD}i$cO+i+=ZaKQ zwUv4-U~MZ2S(j+6o3MeJR#>U!T{k^y5jXJShrSi)<Okr{<>-SNm*80`p)HHCK?R%>!m%n0(=6kJm0{hE-OUu(;;`rXC%|16aUH-SY z@S>c%Pl4R4Nb^oUgx*FD^h*u~<^cjltf5w~7dS_yHV>^1#L*Gcu`8!%0zF1{K}V#Y znGlBFW6~=kskzW(qraef8M-(`ne==s)qtIuuEE9+6jbl5j-;NPT04CbaqI!|H|%B{ zYJ0{8C|0bVc-!W4kiq0;D2Z?;h_zFB&&M9!v;Ty7yITvwyFMrg@5}^K$eYyuPI;+o zz;odOqpLW}QIxCz|7M=rFVuPPz$e6=5HoKnFFN!UO-0Z2kiFwH?kdw7LN3nd-2m<^ zq|99pf3NY~Kdt$2VB`mlgTB4#L*0+9Iq2)pc{k?MyThA5yn61FAEq@{HC8GOzGDg_ zZO?*hy|Fu3mu$ipa+)>@_PtvUP?QodRk*LtBE~Oyt9#~{gT*BsRf+FR*X}FY}nPTtB@lW_GJe;aYj?0LhMMf3~U-8$S zJYD$|b!hg!%EJTj;rjFWZty^#G}X-P5HElXl+9f#opfY=gnI4SjK9VBvnMgS z37Mt&Q3S8+eZg7!zaTjUnz!(jE;X^4$S}R1iAyvy!)1S@lNyQXFT5) zJ;&KP-JLUoR0p|gF?Z9*qE&y+REXB6L2L2yHvDW~pzU4ESL4&V-T2Z?ze<>^waiuZ zr&Rsnn>$xSEyVu;yAU|Bt|l+%B?~z7wF`JB0IwN51+P;37tly|+RUOKf>kJ3o_?g? z%2Z4R)>`oY1RH7>V^YOlm|#$UpQ+Dy1Q`$2??ips$RXl7TzOsp7c<67TshR&PyP>J zwSe<1V9eyNou<)l@wH_(P2YiE-lN@E52p`3up{WhJJfBauJCBbfqHAGCmeQzuVQm{ zQvW{wnjG5fXP%5lmepf#Xqa*W8KoiH~9+n zPQE}reM7mSA#8~XqbbcAXPfVoq%XxNB)M9s~2LNY2c0Ox`AY&+B z_b#*c3wrFZKs7dX#V&Ag?fduqdB$F^ckIjy`R?V9h7{2y1n9SAF_GnE70<1jHP5Q`>-2CyC!fG+=$a|06&4( z&Kz&`v)2*M_xF{%_dQ?y@D?AwXz~uR?z)q9cVd^f5br0ye)$B}6Zpq=5eN07LDn)n z4Q6`kc{uT7FHk>3rrcW*(+rI7Y>2zN3~ zz&@fsT6-MCxA)9O+M{n;9~Pf${c|sVMQn?IF2I(r9KxC(-fo)U4}Xl0lN^+1$(~-u zxg?cu7|#AJGNmNlJ3f$eiTEVfUk(12HE(blTUpQnCvdo|?jM!OOR-@IvNw`B|*Xa==*>J{AtAFxuB;PmQ%I zN`NyHKB^*qTz-)dIpIpMH6~bry5Gmsp$SW?=}B5@9PKJHmBP1S(EXR`nF}T+h4=~=H*F?wVo@}H1BU`Os^Pctsmj#Nygrm zX@#~-ix$M!#$$#zigNJA^$u_RfTtO|(~gdvyPjUeU0q%|r|}Q5_IKCQuYJ*~7>B+% z3;feB5#xkxfgb3sqU6tC!gh~XV+7mJx-=JGOrU-?{07#|F8mw#E!v2`eXQ99Ya#u1 zVYzs2LAH3|xboPAb0Oohi}A4OgKvlNkw2$}vC=r4?->WiATEA8NPiGGrY~FRi{^#+ z?^5{BU0-aFEruNX_>Yqz^QHf%+}T24_Aa#}wZw`B503^q@Un zKcT&Sz?N)&Ol`nFijVbUm!~wA$XD&*8DAOv*@Vm;MV*h?ANUF7GswV=dLk=@qpP2N zMnB_k`)~BKcMg@G&Ydd2cju4mcbmYzf!FW$p1-5t?e#3Z9C2i-bh7yO4*2)1Q?2!P zh!*gzE8E03HZ6L@hkw_m#f|hUTdqCFJIS@b@-#dFf4OsAW5(UP;%7% z|Mqu=r(LZvS#u(D2eHm$PmVpqOBiGCyb5K>LfJs0h?m)g4dv?RJ?K`=b@7(wtl_Ep zp7G(1jrZ2Cj^(ML4o_Xi)73R!17^0a4*e!mQAC*;%q!W55p=3(;Qc!~@z21K9jrO`K5MjF7=vBRGqYA?JhA=uRUt1+ z&~IzdZy|W*F2=(vBRG#x@pHy_s?(<{9h)lbJms$ut+lSb;&|{`6Rd$>1b-IrzXUE{ zrff5^+p)9P89b2N6Or30ca`wqyKDC~tjkn<2Rv%2d!Dx)%BUZ*-_s z=**PH@k8qAc?tNQ>Z!jQ{#Jcs^NSYn_Am$6a274n zUKbB&kAa!QH_g#+ql2XjkEks4ndw>Q#+-Hb*?be+>^T`hj*sG7XU#pQ9ee#dptTA6 zERF3r+rTeK?s8y=##%cM=YO+q&Z-wR^?b=M@LlyUqrUQT3GQK@T03i9u2>tbt@TZP z`z=q!+9+N|Wrgos{NBc&Yzmd3L1S0^4BBks{Z^;!4xWGEFB8b;Ub!yZb?cAszqD&& zv|`|?w~)2?fvdYESfg`Z;>1J=KDdb1>c&>)TJWBJ+gf8{4NnCmZ3Wlct4*=XL$2h07cI#&0-n zTKMH<1R{Je+^K+E9DEUR5%Cy?sw?-JkKaFZhxXn zytu+Qr-7J__FNhV4tAiE#;t(!Qm15%Tl<(b6vc->Y>(L>;4X!aLX?d{)7jAUI%ql* znqCjBn9tjLLQ`bO_8XyP6}0?0v@L;_v!TsaXn6y)*BrkInpQ*4o1y1_KyT4=A2j%kKcg@%j4WHdNUHgVl zan4A4C*>ilmqol`E%s&;-z(X3F0netOL|VbV|*x7UCCLev|@+e3CxL}&E8*i_r#sh zttD(TPyP%uKX+HFPtf~+D)>hkaWKZ$dz?@Kb{2Z?Z=G2p8 zv3Pr6PK3LG>&^t8>{8`mh?tZd@U1mX>ofEhpd2%ppbz8e)NRJ5dFjitnk20PYO+ya5`$$~fQ5Q@kPm z74I597ra}7yc&kQ3W3KwXyWA)3t#w8pw|v`(luH2#rGx5n_>EE}(f8t${rFl0$(752W zA$1lwDwm?w=kXQf!viO)&c!Eh3HW?8jXT?d(^e8Uw;5lM!N=f|*JT!cQ@@0dcwz!^ zT|@phEj4uSG`roubxjTZ8{-Hb1l=xxPSLK`=oWY^3Xe?$-d^$B zvNIAT@LnhQYohK5TlS@d_)NSwk-NfLpigkwnF;aTMD7d=E+3_M%j${T8x~wXIvj>bq|_Ike>`JE=EiSR|ZBKF`VLM#2-p{l@CbLl@9*t9R#dG2o}+apAbPDi}UtNzX%j?hA%@ z)p1|IL&0!<&)$dB$13{er(Zt$69s?HtWO&c?#-Ov5YG34bEU!A--UfO@=PhOsXg97 zXS{>Xcn6*F4l>@u3MVCkeex0|%oQJVrP7%zQRa#-of$ob{%&F1gYab~{MbJ3b6_{C%fHFPP@a@F8ro; z6~9smzm{g*b(^HA`gY)HeSaMG$ZJrlO{%YMrZ#V?7xZ`-TZSJ@Z**r^7S$~=P368 zejDXbZ^kYu=M10vvjW)ahiKcEw$zsco}iP>WX_wsZozAI_tU6TXv z-#K_&z&1G_*uV5cUpMDN3I6mW^Cz-Sn8Z5a0>)!9aqv?TjGI|2q``3``AO7Y>ZO#k zHAe3CnV%dqI169lDSVd`6E+K6uY)Fr?$i;!Hof~MH6HEsZYYjVa`3(+2j2A#-iYJjDXde9&DMr2v?D(=IX9y zUpF;A1pjtoJ#gq)+^^(Z`+DG(6&wCtH<`QognQE{$&G=fHXrv-mJN)s_C;=-g4~FG zA)fc7-Ipnak?`K3R%%KCPu62odhlc|HHEgdewxC4e0v#><@DJ*rV;!cJ9#Jh(vPuF zKQ#^?A-|V^&uso@jLq0;j1>oC^U2_NEp*hlK1Mw+%+P;jD&7F*9_c>%F`l*U%&rse zoI+l@bTHIm+;k_vx#V&C)^Yl7@^&ze>a+T;KCADd$vyvO-!IS6_q9&n|Db2#;>JGR z$ye-uVa4b`AM%R#Nxs()Sze6&e9_{@63eP9ht6SaM|~RtUCY2*zyC}*mv)MA(R-J6 z*E#d!dS_l}o|GViCOY%%%g|5j*wNIH{1Ux8&Z)wVa|#(T5g8%cpO;1Z=zE!pZ_<}G za1hTcX6oio?QyN)-9Xxiz+-A-GCZL%y?`;=rE?U}Rby-LgU%7?9fZbd_)2XV9useg z$HZIWG4Ymo4Bi@$g-eVx7GD7u~s$be_U;`t7ze1{@D?*T@V{JLUMyC9h38`oO!FZ3^z8+d$$h0brti#;!epJ`1}Beg2v{L zcc)eq-w=K-lj)Mk%&^)XBG-nWGMbMjUuBg0iEo(qT*Rsxyp?nG?lm&EvH^{-R> zuD-vR{hj-S&3E=;^nHEycZ)k{RlleG{U_PqL(cbZ_V+b>zZ1M7?2S(F#Ttp#A{LW% z7Vq+VM&{Kreh9r9MP6}lVE7<*`pW8Y zXC1_@{FHIfz5(Zp;sM$pVindc7K}g;8@ni}oS|3swU!-j3C7FYW5ow0U#HB+t-){= zzQ;9P9z@pljVqSClJ#cg6J5fR6|xI<&h^i0`5+iRINq0fkvftiGixGCC&bA4Hq?s0 zKtG95HGA>$Q7h*BHsaE$UmEIZjdtgQ?wc|5VUZnQr1`LeTq_&Et!1vUv)9>t>dXgX zD(^YX=FunAAIf;=;{o1jKAuebI{$hKa7>&pv?zh5uFtSlb-|fAynZjgHFq>`G>7Y1 z2b_U?T1MSw=DTzQd}yDQM=q4K--T3II+3|4U9eK^d1OPBy@p2M3f`yanFStLW!ke7 z9FxDFJ2jbeg7Muf80npvicP>64lZ*%^@WS6ue`}l`!!j0>(P5pt9{xQ4u9h5(%gFQ zgJWdS$HWGIjW%-1Anvx@HPWW}g}_woXnF$i7K{9{wHv=i+uCPJ!>^p(XmfeHaRd5; z_lKdq_8gm2*#nt=?(QOKH#UaUc0P zdGE%>v@j;Q_UGNWn30N$A&z7x^HOVi-O(f7-Nn57DmXX6`|09XZ_We5qx=sNBcG!!utj&iIYw-B{{M27iz7 zl6|?v`Cs#@37)q1C=1%{gF%9WjkklRp$UCgeC)-?>3>g^clv*#saueIRdpR)vf&2} z+&)R!5t28p4nE5LBRv1)Jl}D?%hpgH0PQQj$)C#n-g#=@@qfdvc$qw{|B794HM;y> z=x|)SA~G!Q+7+{l?KyRu=XW?25jFto0Xq+G)2d)Q)3UOgh=_YdA++_d9Jp&+~u7uBi9e6iq&cPkWws??wxonHdf5WzzD;OTzVnV^Ow#Czw`FCxL zwbaSBE!My%*|vqwWgN%0ShwF}Tl^B+;z!`-*cMCR)$PXC7Ox^J*ABP&^da@fBP%s0 z|H3=X$)4h2WL_WOam{Ez+Dx!Jgx+&(ZbG4s44u+HmBMXuhwV=IF7!5}W2{0#k7~UfZIK zwsYAQFFbRMZLvhQ#Ux;OZ42vv!M6Cnv@62k`+0W7oxOAO+1cu=!)N38{qNWnJsJ0R zf$QZ#GwzH>kns@DNS-XDT%*d_c7=G=<}c>T8s>`1rG)}^zC(?nF+ymKZg7l?5Q~SS^LaAbxmf!#rQXtI6e)|)8v!8hP^KC^D;h- z`|LfJUAJ4QowT)n8aP2NB0~J+x}M-K?9IZ0e1Fkhume zjek&MP-_j3mq)vE_PKxQt{L{cs}Sv|qkg&hXIAsh0_NL1$8&Gp>%`*393Mu*7xv0$ z+1|E%&GXQ?Q#@_ka~vPD+C!F1iaPo~M_czhZTXikZcK4@>ILEip5+~RTv#{vPj2qT zy@tJ^Id=Jts?WPEyjuo7G1hAGb$IdV13quD|1qp1KFE1u%Y~1zN&1!!zs|;~PY#@_ z9GsT(G1rAyUq|1Zz7Aur5hJ7ct^?$qJj@zg>ybtHwd{NteUmNnbF}!w zZ?Fd-x;AkRPX3`1^iy_!L|+1G*6*XwyWw~I3`;b|GkJ;@rcbex$wz1RC;jxX<9WK% zpGuyhvFhCnJPVq?Kn%pHYj0|s%etxodZrgysiu>y^$qaPA=dEj`lyBdH07)^d(q^V zsPPw>_;KGN<)5&sb^grCi!~m?w@^qsvX{32qX}K9z3IRrE37drzRwEp0Y}cWvBvTx zeb}k2qgvCf1#8G7Wd&CbsOQ|d&fv;dF@>`AH{H}`an82>rqZ@_pge2=LwzWt59ta1 z_-5MK0`7Z;V%HAVo}$&Zm-W74hh8bySzLQxVh_F*H^0l?OgGL%2g2Pyu+Mz2B1XyO zarq^@JZ1LOirN38J$HWD^w$}0c*+_PpIv3sKbC|3Z}3j@$p>AO2W74~OHq(~o%hCu zxW1!*VvArf){nt6#nzx!<;r}Ccjq8qz5x!+j6dr?vQehG7IB6Cdg*vMPHd*}1d zsT*jYUxB)jz;XN9(B;^^Ue=lWzde1m=d;^a<=?aWI!SnDwY7|Q>TCb6#2N?E=2rec zk@h0MdzEn#-ooFudj^&o{EOuF zhq+OIQhaTtjc@-P_}<{)`zTLeJB@sGI(t@-i`FJbo{eWo7M@Y;#0uaP<9BfT|2uFl zVSPUec$uCZ#%{amyRp^!mJUN6sqfvgU@Bkfcwovl`oL4a5;~gt^luIQQ{5w!^U^Iw z?yoa=_iNFgb6f6QO`p7SzzE)n_iR5$-{iH(BIQ2tv7hVmM*UwuICdV8pYgZgk#ioT zN5qHEvT6O&FYLQ+H&b@k6*j+W+}rU+W(`AT32)60FWzZlVf?%^=ev;sy1(c%;Q7E= zxz#93974gi8Ie%y>)69CzL8zW;(HmqvFf<^j*P$T;QKw`_XfUXp2lohE?P6sXED!( z^W#}KN18GfZv#W~yEAZ<6G^$vdh$;DDZkSbdi#(|It%XlB45*c=;O|Htu?mrZVYWi zz~k0jctGc2;4M5PZxkneL(Xy|<6E6_|4BLdNQ!{n#5l}E-^;(EoHXKF#ec8OflIyK zf&W$1|B(9H`%!(#7uN=I>n}HD`y{_g+2ghGpvpia`nmoAerL-+3xC=o-m6c-PkT?= zJNg@c?%vUMe!Dpwb#~j$^C;iYANfPMZ2sRjg>&7Di3;l2BW-Lfs#KHIz z>VwX7yD|C`h{@%E;N}k)+^Abo zK#bZC`~{TjpZrhCjkD^flZejXIEVH&-rXr-1?n3&mRoH@8IS!F0^oB&y#8#fZ58h_ zH76!AbFH?S9fwcxBMaw?T^zdDIQYQ<7j4J(Yq}>gH9h$2$zQKTF>+V=rfi(f zNz5cSo4?z+JQZ_$9#6&Gp3hS;x8u!S6${9x_ut|9U*Oq`_|eDwy})x&JD!JU*m$1g z;_1-popr+Ve~(VuL+weto5pClzh|As=>Rs?fvfHI^RwE2?*E|u9>gBU{5|T@Ne2iP|MI+j}6Q>aKcdyI*%u4CJ{I|sO z_|HRDx-oXu2zaSq@>k%z0Y2Qp+}#KtivPPzU);FB-=%IL@seFe@CN{K(S z#%isoec?3m>^du5PYln8;GP~8X`9GeuBBRW(bl@!hEmpXRy?oJj(2JKIWm=Rm1YfR z$Hkw?cnHoco_5Z>0ZDr=FgE?ZU71HZ-FAPY-pBl%>H@LY^vykDy%+F4|3UYCex1sf z^EaROd28JFd36Eey&k9hw|F0X(S0AJ{Qc7x^8Oay>rRCRKj#lT{rVVuKF+h&Ydq8! z^-29P{vh=Unf$WTr=K}}^4hUS^bQ!O(#K_! zbzXTXYqc2XH5PELaB(O20z0AxzFS2c)qeOqMl5xtv$f#>_Jm-ZDBfZHCEnabnFFjd zH~I&)mUQL!4E-M1TBhIZ(QWkiZ`B&;0CvkpKlhvPJAEnpVaS&>`A6S5k-TT;*l^$G z_eR!#mC*VCHcfh*>R7EM*pAZezva8u+uO{uAUO@XY=Q>MnVTEP=jAIxw?cyrH~Chm ztp;@d27lo9!ue+8{HK(aJ+c6r5fo6^&}h&^sZ zo~&?bt9xqEX{Mc?wDXDDasI~#xs05I?f>t~vz9&Xw5Po-8)m^a;o<9q?1Gl$KwII` zG$z~h(3Lx!i2ZT#Xrx`yRqe>8(z8RI>r|(ItF`ZF zos_4J;)hg6?FkRrf#Tzfd5YiMZ{OrwRWA6q3jUzh2zMH|ICihVC4i44bafQjdX}9HM%_DMgI`XeJbc&JZvx{tbehYJ7@!e_4x%Y>?#JhT6 z?c=Gr^*#1|=YmHR8Jl+6+Hcw@NIpxsLSiVZXiM_OZm+Ood&sS|PJ5RMrfJL0KfT&% z>usKrPhGydxUuWCwvJqi&RmY3jG-fc`_s%LmDqfmhjW>q-=chtzpv4Ql2M(?7B_Z2 zVR7RLMs{_gUT5l^PMn2Y z6n|u9FfQ9a#{a@m{P}GIx6sgJIX25&Gye;cw>#|_S~Xkoxu#B^(uMD zN^ovjS?<~$_=I)eBy*2@U-uBlB_Gu6r|miTU2sfOR(*8+;{U}v`L=q{k5A{4M;u>> z+ipYNzHwn_rZL?Anayv%r+k*5dWmonKJrtq=S;z!9dW`I!cQ%njGwxHY2J%AJ~!pS zC*|PN%G3C%pPbmiPrcv*^f7%pGQXU21rs<|Fp+ZwlUVB#Q!rt8Ts~_2ob5Ob0H*=a z>9USE?Q?0P+>Zvg`Y*;`cIY%Q2VP4ZyhM+!{Crai}^NdaVuC&zwC)Ti6@y_@;!MV=C zk9k>`f3%<5u`idHei|QN|I#31sXi8D^)bZR#|wb*5cNOq+D<3c=PbHS9|H%vZ*}P8 z&xXO=90LrU_0t|g5p&1oHO+zfeXaHH0o&pK?bzK%`9FG^aylk=IsJX(C&%`8u+!g* zc`A7=~vX*y@>OS!eO#m(`*-B z_FOzYK6|}Q_n+p#<1p_8>oo9CyXUj#r*oC{tmBjm$a-;ls(49o&I87$)i)`5I)Uh1DWbj{Ro%g=-1sLuJW>B82zf3pg0HhQSp<*h$oNGPnWml z2RCDkUqbB$ z@ZPS0myWE0_x22}7#Yjr!JY8sUr+a?-ro`ox4aq*@7>1P%r}DJ-EVRp^AExBOTg|x zCwO!|aqzJ&M|rg2?+%Z6c=VUtFZL_=>Ucal`#GCOe+K+37>lPV>*WQ-Tidem)OfAK z3mY{S9$vuatN4)m;$iXBKzIsYN*0_!HXP>kEatR$!j(5JZPWPl)4tdvqbwZKyD}BOr|zlLU7)(mH}PY;P9TP2BJ)x0KBT&y`DhWJvzfYssoOygP&P(P zjCCM0MlzVWRZ2T%zJ7LswXA;ejcrlv-Djw~5g(O3K1QdNo<aU-7Dc;7{cx z)2AAE1<9a;kL=9sHp?iZJh|$hVq2B>L2v|nhx62)&Tsh3Y#E9@ZQn(qH7WM=cI43Z z7Id=Ku72)g(wbHFwe~t>Pb();6n$96o=4N|!8Y_yV+h+}fNb$9<K0D+WZQqx;)XKUF}9nnAeWy&qm zd5@{KT_PJKiY|z8-a~x4bE$7$%jtn|IpuU0NHgy=_OeMb(u>`YDGnWFlc*nUTjcBL zpA;?MMfa7dFZk4s+9Zla67QhXU$SX=Ch*gg37eRQ{;iVX3wWoodPd)v!_R_y)RA#_ z@~(!tALE=AI=V4fKweCI1reV$x>)-Q!C@=VZSk3`-6Icjc4vu|iVawr;x3fd5zt#$pVj)V9mfb;%b64Mt!%RU zbvOaMthq4F>DRY;7BMf=w@+;I1r!5h-%al0Y`x^(adY`^85%e7Ma+r)Z`Y}1RrlGfb|b{o{FSATnY~S|%`jjb)?~O9jNgwkk->%L?=&Yu6lIm#hTs-m*{-l%izxYS< zsd zOh0Y-TO9aV{U!g3V9j)B>-P8gPUN(LUdPbKDSvrZ`Ja7G`KejuAOD>4=Vz6FxV`-I zi5Bj^tKz;pje&H$iA~sVJuSUopG<$)9^Y_^)%MGokwihD-?q7*O;|ej?!XG|A4Rzv zg>$w^-3N7!)oh-7Wd~0CcgdP_6%=ucchR^EZ z0p+S`MrVB4DO<%Eu>Z&0o4`d`egEV485VIj#oc5Emjt!U6)AHDP+{Bwt!!b2VH5;G zHpQhFT*{(Fw6e4kw-VYcL8Z;XY%$whvOPg9En3`CFpdBF{Vc-_BKqn3`To9tUa!M5 z&-2`S?z!ild(OG%E>Cz9%p>D_ffjtb3U-wKF4kJeYsYE?;*?_1m(0|{ri)qwA`i<{8bg_mRhApBmA-!*l#QF@XYGn7<0@gj z)ujb*yZS8Uh5N%Omv9YMv~OW765wGr=6M9pVhY5SbR?orEAb95d5>vt;BSZTYOcgL zAvJznTCiK@0p&RkG36et`kYgf7B?~iX&$op;~zfT|!;|6A2Ifjt=Ert~Qh&+@x3EzNl=@|51 zjej_AxrTbIx|aE&^D*x-95`aI7FW?{ioVqJx&$6m*XOylhdM6U!m~HE?^^IXeag51 z-^W84e*ri98EnU@5`3G2&Kcmt2B<-&Hlx#iBa*KosWRsi)pT zxs(&`n{|SxQ+wd-`I({BrMixLpTb%(oWXMHJIMaaXs4YzajFI6y%Y3ER;nnP2YGjw zbNM`XH+{qPp^EJK7ypEE_-) z^7s|knBZGX_+U|)ql2hvhqcS`fmlnA{$8uoC1dTMd~S{f>GhB=@|5qGhVR2U7J%Hd z@9Oz|WgWf^hUaLk*Z{9~RrKX5!RMpsvr0V0zjy=cw7!F}riY?eFhA*!aiLfKdX#VN zX58w|Pfh*{Q3my#MgC4ryW**+homPBQZjX)Y-52Z0?#Rzpa*rnT>oHhsYIj8!t*TU zdWdAM>1BL@<(vVn0XTQ39C20Bzfb1tn?=XqCnTtTg3|wC*Wo9S*Y*8``BRNW8+2Xv z+8}$jh2Cp&VbAqgLqd72mi+|0gFNPXd&%->gFF_g^4L*rBg&%#e!?8sRvpg4q&!OS zAGuzTa!EUy3)%d-o@{oZY{p-UY;s)7ecJxTx1r2B+3Zq$8f`?`JnAN!T+8P!n?XqP zttOkWgXEJYoAdFGb?%Jkw&jl1^A>hq!~H#64{-Fj?u`x4JR|#CG9QmiZwwk#aa!xs zN_<6&oz%Ny^0EbBZ`ENcTqps#9HWpmvIe+&3h_C6v^Lac9S*jn-1E1G3;n* zJIEvLsM5bRzT<3n&_;Zp!iQ7#p5iQ5$R8Y!RiT%7wsV)_$B~9>G}<+D>}RY>+@I;YY^0q_q0`OLo+m6tUpS$t&6TG9`@;T*p?!u017&p}P zD&%&4#*bl-v5Z)xV~uEyXfx%46>Y%&SqYpb(02G+QAFSA&_DRD zmL_vu>E9~89d+>$_?jl{R~U)%-eX??4e}X{D5nDNv~O?F{?SIzpS0i|%VxQp({k#j zTrfiaaXkusdiJCC;4SxJ9YG%66YoaQbR6J7KBg7kVjt}Y{gd-Lv6r+qL?_Q|IC7!3 zl;;u%{AQe&?RBN}}@U%V1@a6HWN7^mSm)11%YH@_djJAO}w`cir3Uz`h` zv5zzV61--FsNqu?jH={O+(<`Sv(z>R6np(qloHN7z45e+%kn#hy^6Q`Qz^&5PET zZQ+RBe6V@iCgr;a9P`n)%|RP1!FWrLau1`eHe*cBZ{;`xm#khQ#7i~c!4a$$e?#mSWG^7vBIL*jRt?L#yvx_R&b z5A6(n@vlJ($D#CnSZDea4)C6B*&cYd%I)Y~+*WNzj$su4x?^!mJaey?RIgs^A;ZeN zUzg$w8){ckuhZ6UM>>w_WqGg+Ef|Y?EpDdt6^y~5_hZn`XF;bxzgY(zZV&=vZ>fs9 zJkyW;rd{!7(1Emb^= zfyYb5vli`$H8`=vV-!A+Z*fXXw?5Gt60fF%eUj7Jgp?1Tz%~BS^nli{YQSU9vA9&+ z4*F&gzC+#%wz4Pmxea!4C+w6q&Y*3iy`*h%f6s9S?Ws5N1j1HvKE_)TLzvgHV(n^! zW9@3nrxy2Y2ir`$LR%(KSGG+Q_|1Gvb;jXdu#fEDCuRA;S_AOZJ-^oen!OjmM_FLq z>2p@Vc1}ed7@OfY+t4SIon&Ykmnp|yHbp09ej9K9<(p>kk+-JoAI6cv^o&ekx(wyH9^q;#>uDjg-+y2wE9-jYJ|H)iWJM!P@KkPGS z;HS|46c~dj^E6U%ThMMp-(eqOA7&r&=s#vLFE?0}Rj+Tn4@Ka8gMA2dJ=fBQD9=^E z;gV;!eE)xw*H1y`|AoB1hI0QK@_J7_JpV0u-TGgV*SA5AvL~1_+YUOFG8>P*92FZx zK{$M*qXEi3;BeIA3D_g1FU0zSJRSDvB3%H+xjeU`G63s|Alt69++n8_Tda&}EAzvO zydszFKPnZTHu!n1p)TLHPKo!s>@?=VNCVc-7Sv*HllZN`S=mv@>v9k`T~*N$d;IWB zTPIKf+0BE_R^}*`aY$i(yl!s;qf_zjfx@r`Kg2IGxw&*l7X( zU0^OxEG%CmE=C++TBftEd0>C}xi?RnzWDC6)pkNjC#Q*)(~v(>CxLMTzOw-N;XS_} z8rI3kaYJd)I;)v<9`-Yz1h3E8JUGfdt zqTUSvEwfSY+)(Vp)?qI#{UvoiKTxH^^&p$}0;DsS@aHqnzu;`aG0r z!CItj^wmJj)rRSZz>e~)9G$#Yc{9?=->OVQ7I)k60||r)_=(xL6Kx-i zK2>CbvULvp;5g<4{O}_5`yN$f0ne$|nU;NLB+^@up8fMXydy841U_wlpiC3W=3YQ`o^`p> zrieA34)@p_DE!2*to6p>gT1kK4)2`O$zh1|M$7Gnb&b$1E?cq=F&*$fSnC((<@k!{ zKCUFz|AxBy+bV9w8Gs`ScDGgPJ(u;y`%<~y?W+nA7cE8|=(Fd(Acpg-CCehr(IB2g z84Gh53Vy`8g2Ksh@PVx7jL$!Tl8VSPwVj4R+w>THVjrqU}|FDQ#c3=IU;wVcT~=e)lz3njFab3gu~SPq`R^ zZ_;p2n{<$mvF_nG#K(L<8?MYIgHOMy`%yM z>dJR4?@Q=qhwsT@x!`97=&h_LizdYETyiMK>=ik5{L{om=Lev(vUx<25j2iseA0=v zknr`x@w+GX$&+r(|G&;Q*(4l@d)y$8kv{{Cc;>Iw7vJJ_)t71I`a(8(s`cGfufE); z{}<|_@v!~5+98xR4IjqTE_^1?g1scc3QnAL*+JnU^_@Epoj9w$0yxQ!x7~0(dPQ8i z0&f-9>Uy{wSd;T9aIFWPVYpJh*j9>s`MY$>ZoH#>-H-h4^2Pac`T_3t_6+z!pVf-C zqMTLWUY0NDSIU=wzHJYkOuw!W?JIO*7pcf&f@+JG&l&ZWK`&-z0* zvQ5!8TWor7dEe+pRnOkVy1VIF3-rxna=nzYhp1&6FG6l)oc_fj4dJZ78Ez`h(JD?& zzAZRgVIFWYzIya|w>X{Zw`@Zhvb|INo7A-$|K2J>Jk7&S3D_y}Q05){0P@bL*&?)) z)y)>IgB?|D(fhLfJiCEB@h|ox{qWCKp1_uZCzMxpFKh?WkM|n=dgz-d(0?5CZw398 z>bv^#U_=_$;{vWq`z!m=J?ss953KjUqP?j=yT>CYx(jp6SyN3#&@qT#wJ-L^y%8}U z%1{Ml!3bHP{o>ks@&bM@mQgwOo3Ivza??=X*L3bjm!NZ38;e+f>M8ayo6!gM*Qel^ z%7ZUi7rfK#5OhSWAD)r6u)k|dIoHYk6B^E~SH$UC5Ya{Hv(9=r1?1uk`1u*|ux^~Q zCtjX`b|?9)map)+y}TZkHvMP3tBV z@q!gRtHhX*HdLVh#9%(+4BCeL&Am;W`UtXvv!PB2q%+|6I>d1$A#k1(;v&$eT=y%AFF!RK}GnF-Oq^G*`Yy+wIt&4O-dPD}f6!Id%U}`{F;J<8!49 z%3DX&RS#XkGjntBn{p-az0`2T^47x!*x&<4p#6FXulyx?zXHAw^f!it31Mb@GOU|% z#iE?}9HZW7<~|0F1LC@g^kZK7;D;b9WA$P(spzPSOrN?)`A@hx^2w#2o_n$3g3H;GK~(V@Cz(#9k!x2e_Y} zGku2>_nUCP3HSCK`;J1~V-Cu^1osI!2|JeHz8rEC<|o=70YAdP7uE;Y0@f!`=<-<~ z@RCx6aCU2OoHeBrU!r6h84c_a#!>SQ4_&5OkT!*xkSnFER z#8`uL^4fmH7EWPLU~xnzzKqfTzK zb=c3cq$02Y{jcniHcI??Nuem%jPIjFdW*6b@g0;gexhuB3!J;uLf{Av;csnW+Tj>w z+>!XKF(@9-N5fwkd-tRRQMX1OFfZ&B(+j-G6)meCh@2jh7nvOLP-IewBXVZQ2i^Q) z%JovP-X!oHGGP|N$BebaWkUFwE&jYVFbWO!Mo4+2HDo4md=!}&5;USs%!iSd5WPVPmZWB&UotnbG%;HpVL_Gn zJ;U2Ki1qSez5JU5SzCndaDcv0mabK~gcm5GC-(dDPAMhotjhNg6*WE%l7BXEH zC%lura5Wfl{uB5kjACC8W899O#(*7O;DtA2tA_*k4%~xYZ?tz0C+?lN2i+-E9tkY)gM96SPjno8{sYkI z16lbId*OHKOhHGzt}A9-LnrBE{Y(B>pa-FQKR)cG=)rK{D1uDcAiLvn{TSecd~Jq& z{RMeTLO=Qq&u+)FDm*)mYbyFzc4T(Q0lc3@y@cm8(XUJJ&Vqip3D0Lh4*Q_LPn2=Y z4GBY<&v2g^nHlo2p;>TBWJ<^@xKD=67RHO<)JS_sQ$y3>O@=1HiIG_$@sapaIBd+U z$h45;_~yYgA>)rA{V|N?9x(U?@3QKGKZHMj48BuOskwQBwOMcytru@~C+rwHSY>1f*}-6F>7jE;7TMblVLsdAv5y@1bal-PmiSQ29_Icq@eK_vvq1M zCL6(50iQGx{P)gXcwh{!OPr#hH?D^;pU%CYY>#8zjVq>rZ&~2+EL<1DrrE%&v*QNm zw;w+w|Id3T9q`UcsGcw~^1wIadgO0_T(=s3WB#AxZh}qpHjhKT_KDfmRkuYR@J`IC zHpfjma2Ig29N#~Gqt4s>+qi!D&Byo6|8-n&e*47K>ZsgKF|8BRs;31QSFlaa-`^?b zG1P5?uC>`aF{OIXxS)LhoQ2i9#s%iL&RJ0X)wp5#T@z`xyb&_@n$#M+Yi8aAxo?@6RQ-@>Z}v}&uU;ZGH8)F~TOE)0T@vS2 zeSN@61s}KHwAc+i~^~<(B->`)cxfoou(G!Pi98IeNV) z7!7_M$2W+KsM9Op%UIMs(wrEQgy*Bp(?iUVy)ot)A-|!HXweWq$d9kVH~6?{iN4ar z9BEDt`M@H~y`htg=A@8c!0R#QnQ}Vn@3G+dXmd)4FbL#nW}XRrw6T%ko3QwrqmV}r z9UlgIMg!M*v;p(e&K09y8UsXI($iZmvzeLg%5uk;<58}kIm|paq&IBCXwX)1D`fi? zQ6u!aVDdA}Yzui0?R)GNjtjiZZJ;NFMQ7H-hVVQC$<0@l+D299WeTtq~!?Rv|ic)bUzp0;&yXmK+IP;HVAIARb>!*!w z`l+yoh}{6))Cc7>?_&&VS{Yc-0zBxwu4lor+tJ%2)csFj$^_7H`A3R2NtpWMIjz<69ADHjE_Po+4c ztRL$`wx{N6r(SpFom$=yi%_4tr{ zUE=)egX0J1cZR;$I(|@oSLmU4$KRGeAN1`XKQKQ`bT+3W{as#NVaJUtxf3A zIdoX3M0<6Du8sL8oj-J2Tj;jd;BO~$u7ov=&~5CGd%-K}IN}{EHP3IR%DWTtj`0@c z-B*@(Kk%12-4Ffd0q~{>GHO9x(ouKHe~T#CO+5FFnjVshcTJ;`LdZK2Ws&XU1JE@= z(sj^pP0cN$(p>sYM9m6$1^LrZH`>vrQK=!RGM?EX4(PWa=;v|3N8hj|(o(-Y1iaL5 zHstd~dfMw$@FxuUNQXl$eyMa73Kf&KK2vV|aXmg?uCbWdl z2mSUd^qelr9zy%2>9^z1Gw%AW621_8;wp~c>g%@#b(_=R(rsa>j%dmwpYAm13v1_qKL7YLm~Y2ileR`zTN6hduK9B0t-$&xf8-^O60D2TdBb1Do`#AA z#y8;4R-M2&zy_S8&nl$+IJ6(v-oyvu8|q$S2-l_@nai}gs*mt|2=)ZTE34D6#+__Z5>qEheU|JK7*0! z_u?ou4{`qrooAKTiM21*YvqG)R@hjsFJv5IK6qroy%lT1n1*Mby5HyCFN%okD?C^1 z=-WjB@bP=XcV`TX{=5S*DmjjbI2PA6#)Bs@s5^c9x!}Wjl*#?KXfwG!IyBDHh=+VV zGb;q^PJ@#`1LqDZaF6pX3hcPwiFJe(kflt^9_bSR#W zzF@)p1oLHL?%O?|wl|=i%u~!m%j*#oJRA#FQilALwH)L{A?Ml`Vt?^M%q=d|0leUU zXycu__0dY*b@G~M%ykuyhAf4X58$s;c;&x`zIYI^p4??vPY3z<5OK;l(WL4K`Wp8^ z@oW}9(BuuiaL+`o@R8S`+Yr}F06&%r-@VN1MEcy>QabkuXEww74y4+iSsI1;kzQS^r;9 z7bo`Ka4&oq;wyc`lKscMnifw$te`*O&)hX_PuH$)`!aqv2Rsb$b5xwBUb;}bc7M&K zoo$<-PRG2O6ti6y`-_m{s2}kKVz2mO)Q|O%(9bP8|Gku}-%-aUzQ*BecSz}ln6vZ) zzt%33(jC|X9t8PW`?Qo^jw^8*K{NZ$!zy0N`{HF{vJJW}_k>7a2HtE4d~bEG@cUJQ zoiCUBLQ}af&~}v}{n{^34%Vx$Jt(DH5fcmW#~vi`5c^9DxZb?@ANY}wO(9x054hMm zy$EO+`e^hKMo%b!a){@Lr^48}OV7()N9>aS>1DrP?8+2kkbzcINO9wjJjQw6T}_d{rD}9P)+lG8B}9 zui*pKe&;RHv5p`%ZXxVAe8e~LZtY-Y9kH=h9o<|ny;hI?+vv+i)KjYu_w}JZSWhmB zIp^YV%fr11ndomvF?XmFjumYG4o|~Y@Hy%*AN=6_sz$TGdv}_xXiFX1gnC|ITU!zc zUWegKLDm!N^yXo2*l_TFUZ9^C&a#;P9OjPLh8E~Swq1KXt<;(SxC!5;@*v$m~r|2t%5ZJ=~82B{zn`&G$b`Wf$_KHx#{k;Rg{*4BV@ z24la1aPXe-$~?#uzAbP`7%biOXiwr|KH?)Do26d?alNGCshuv;i~7L!!3LeU$#{wV z3w};?DeA`jz?y|4zOM5a;n z!yJpTY%p*e+8Bq!?+wOuA^28_$YZIgEwQ36OF|5{>P$rj z;1dAo!J-aod)$unAppwLJX}}%AbtV6%@-Wc=ZSsd1u8rrQ|{de1^SBK-h5#QMBLVEBXa~y*qa|Qn1 z3Qx3tPJPV0CeSk!dGu#$OV%m%n8&(Xu-5|h*k@@aYF2^=hSRmOY*~?>_0h^c2)gC+ z+pJn$-C^zO9;B}${Lj`ZPk@JM$rmed?ZUaFCioDjw_Inwqpr+By|bE&QpyQwiidy4 z{T|FmI$Hv-z`3+?ouCW(4r@bB6{1~zkVZnDp1{le-q^dd0XCI+xsL`u@ILzUk7JNL_HMy)UNoSCo$H-c&`5VQM>0mZ5-;4x}R&H+_UHd+?OWXCY0X; zea?tEt`4H(K&OZtW`UeI&=#b{utlL`P8WO+5_QY!E>O1T9-!gi3;Px9J^M;=A@W+f z0AEgrw#I)Z4&xpm0llM*T{Qa056T4RwlT+c0qq@oNKH$d%lCTl$Q370*Ys3?E&={5 zu4`+o9~JmMkV#%gs(j}O=M14v%D0}piVULDK#m2m4!aEBx2w_CFtZ%c=88*bcAIwk zEbO*wzrUdUUJUz28@waFWx@JaO*LGXYk@7Vz}y&d)Ykg&9G76B=WpMl+S(>XMzkT@ zm}`b5JZC-6Jm_7-b1=@Qi89d~HmP-!q6(Z@?ZnurvIlK+hvJje+h~__Sf_FZ>tMHm zr%vp#T#xq8#8}}B)^=?N9q=a$jzEqB!6)X^%7Y!3_3attKY+ZYNK4t|*m)hsuX@lW ze`g)`ntjw2(}GXQbXr@nPiQuqb!I!e%7C4&d_1D)2x6M{2brhvu@Jj7SwDtrZ%fO9QD2X#>GiTyg%PmgB-!n*F0v>)*!FEu28$cdny)DaQ*(}rG58qHN zlWWe5cxO=GLze{SfmS&k*Q%)L*ake;ARt9bx1hZPenZR%K05u@fM;8uO62+%=o|X4 zY$N$S)|KO1OaV%O6i6E;1hf=js+PXpkIyv zkw3=qHSlk0NDpxsPzGrl30xdEti$|RVZ10fg?p4O`%fYGU5I|Ovn|%v!ZvDU#DGhpfGrrOF?NNr&cpuhMmole zD^AsxOvU*lv`-w9J5=84aV^IEi}0P6pdM>4V!a{Gw%^3xqJ32!&dE=}d&u)}oFxbQ zyrr!JZIOZBtZN?X>Oft$u^h-q4xYRC|3^Lkqn*lu+nxWXYwGF|h;gio|5;MHK+L5+ z|Jygh|HHtg@#+uwnGV=R^6DG6GLAs+y7S5aJErk!p2{o7iQ1BL&{gCWWibGJUeOyzJvR=qaSr1J5F@ z52$iPyuFc+GDqD=-9}wjx)SjQJk$B1p8^-xaIg>Dh-)SKeI@$5LGAM|QU9Q=q(125 zox~;TR|z^mdr!TB_t75jMNW67<+D0{yu+oB&tsh&b@DOzH(p0u%X0$s6P7|3{Dg0T z`rvm!tyGhXzCoXdeh&Q`(NvVsmsI>nT`>7tf%?oteZa2*+EdwvVJ)=-{us7 zTV(ZvuE$(kJG2Y!l?67e0`;wcZK2MqY${4C;WLbEBTk*59`=$7?v-Ug8Q0IE3}9~r z;$!$eIQ$RfSqwWJ!1){0-ygCRhVqX<@A6q8a99)LLqATn zxJO(8Wg+H@Yd!yWIelKXc>?Ni41O+co7VpHZ_9nEhtZ}(hPDh^Xk1wdA5oD9`OHGu z57Wa(;J&(Q_#*=T7Jc6{xjscwbF6c{t7Q=V-%9wuQxF&7*rKwBR4@SNZx>>YiG7BA zq7O-bwG#g7BI{{ z+9JK@W_5n7x$Ivqug&!;N+2(Cy^G|2f%O#Z7qzHI?I743$kI>X!6y2Hnw z3*C%GCt5cRS_hf`Il!l=5@{WjbF7U!5Bb+YzCcT~ybls4 z=V3go=9kApl#{=z8P~wL4Oh;u@fm&YKdZqj5rk(SgZoV*|Q7^Q|n69Ds?1%K>8>8nVH+qcMK#%t|&~plD{w+Nl z-RRL@13ie%UX?$eUWFd`^B(PGVSAzfa{mR^sRrk&G+EGQ@c+{(pKLRM?-;QCuGDsA z^=X67(P9)@+r8jUo7?-Vwc9i|J_*?OtI5$*^=WB9ju`j&x9v96ogVlsSEDE68t92@ zgdR=5pdZBs;>>3o`ggqGo@MAd{O*Bqa5(HG=T{h)gKmtaJ{XBu4f{9K>HI_uztJhs zhxm;Bh4yWom!jh=h<#AUX=R}w#tP)CuivN(C6xv%XyBL=*Ag$#&;vA>6g^pGp^j9` zXBrdA=lw-D8mJGcJFrh_6?I^D=oFhnYD^GaRyupY2Wh3KO^Z*nd4d4ii=S^|FCV3)M#v`ZV&ZV}*B9(ZH|j}`%F1F=s; zmKVm4ba+qMpsetU{gs$w(G|C?QRs;37i^JZvp7c^aaSw!9c`31WPo;+c8c+uchMfCO^feo zdXD~r+%D`RsAsOquL{bc>?bPiGE!|Xw#!S9L)KA3zvP+)rqlS$K1937xqqf{f8GPn zAusZC@*ic$`!E^PZ3TLfwG@j zdr%$*AF5uhJO7iu8ht#ij+NI~$DP+u$Cs~AN9xyl@>0zD#iM=>)IkbV+P7UB$P&gi zT3xP`FILOf2j2mO&Z;kCSIRe9%h&T7^0~D`h;i4nCM?y0acab?Xt`b8((3``fztnL8-AdJ*6K6ygXL z*gu}(?$9aeFo%zGhdWl4%WENU_OiBCQa)c{w;UtjGscNH&%<%7wjPrAe0~Xh z-mliN9sG^@ZCUw0Xv>EisiUIruf08oU!^^zM&uUttmc?{8R|(t;(tSKCpJ=7_qi>u zMUZtr`lYJ-<$fulezY-0oa^p@FC=n0wxykM1RKjNh~MJbCEQ=){1$aJz78bY9>fq! zIH$#DdC0d;7dezZ)R%}mJpn)b3D|M=Y3c&{542mDmyp*Nl%oF@qVHnP9&5mjHD@uu zr`a+0vA;LV0#1v%2AcYzom^jaj@4~^XMxW69rlj-nNGu}`Dko+J!r-_0PEE-{(+1# zrU^P?ITwYti5-cxdU{^_VEhX?9r?C;k2x$a#EBvR7W4;ZILE?v> zHeB}U@LV7*)))=p*vkj^JAq3emb!Cu9WLa9pJE(dj_-DHPXO~E4mP;b%O{w5Mk1{h zz9RD)aD{I+TwT@7KutPR6nTZ{umkH?D}kO(Xe9pZ+TEjaPZ^xXODWHC{iQ zUC>bdX{W$DkNpYg3(*e9v=&#UJ{klb2mro?Vb1I>G9PMpNak$b(2l#i- zsANBA0e>FzP;&eiHWhtKUX!TVP?n)RbGNPfHexbkOGmxD-@y2Ke-GWF(?-2>b%5~t zwGeW)li#7kn$3~mmjiQrEEn?@=}ydXjRcSLu%BZc^bd6q@#?W&lV`=9fovRxykIUN z-3ed6p|Xj)5OaQo&|3obB@b8l2PHQ@CdXgXiGw&l1sv;?OuxyXyec^_N?$(2~n97>~lxY$`Ybirhd9LDaD@9PoH7W3hkAE1>gJ& zx2E1P-JTH|s{ZH`q&)AH8LH3DjJH`+rzeE!Bf`dn>U(A0+AHCImA|CaEWL}ynC$pjNm(+9jo=9m4!#N=Ahg+2 zWIS`yk`mksuxDk@?&B&i+?tXSZ?z@&(`Tnq)ZmPTyZ7IG>x%bJyB)5}?zDZ)M{G;~U4d~9Nd-I~xR zJ}oT;DCO5zqo3`Nm6Sl5Q(W!fS>I97(RK2Wk`xa~iA%JmCZyQo>~rj?S($NaMOC3| zCNx>nr=-o$&$ebIhW5fzdLc6UD(!sZOnG=17^d#ap#I^?!bugoB(SL>;Y zg*Lh}0Z+faR&P9;B-eMV_BH$J=AJSwM-fUB2pN9tw*{c}=A zT2`7ZEoG`bBQq&2RpG;B{Zu~(y|dSV!8ywN411iUVa>9Rv#VrZu3z*i_Ee}Dg=!(9?deg7TZ+iJ zvGZozp?4CMoTD?Wv+T+vIcZFW&6JRkAtExf?~^C&Vfp4do=8Qs+&u&rlKEZcWOHnqD8P5K%D`Zyqvi=nxH&)+qHW zIxfv-O^L}GpQKhiEG5mB9D^>-!tpmcDJ3OrUY2$%M&&^H;x8(5d|E=%^m(If*>1VX zmsx39_PR%-!!^p~Y%)INbm8-8=P3y?Uu2r`FVo(~mX?a9%*@J2N}bWWpMF}nX+qqT zh?uzOQ8AMyPKX&5tg82V{iMD;%mx~}er9G`D*7t$>g^dBX&KGX0b`(NvNK6{=4`iS z6X0+-$;5S3MurfYUXy!hcuE>*yPDon`)7td#cs{C$DxbcGp1W@cG(nMyW$H6!>)lU37hO=Fly$#MyL_V=3#b;oE1~kfk#ch2xAZ|_ z{Sy;1f$0n!`8?#?mCp`lXzC6Of`ad-x7rj%@0s7jj>!4ZnE$F=EuYIUl1cb$ zq&#G)<7d70x^io&?c}nmw%M}&1i$pXd!w4k4VBw4pUB_;fL<4W6RcVPs$H0`etGnw z^tX=CqqD|Em}28%qNa_y3g2Aq^l#{3J2gZ{Bkcsgx6UGa>gmjQsOp%kwAp>8gt%0V z+yI{VJoq1urc%TcJ;ehbjIoT5s<=-!L?R>(t|EU78pvNR{|}l!Ce{=?C8oD34xV^M zCuPiRQA>vM)QS$eGXC(iS+i5@S(-!AApR+{ z!E()r*%GZ8E^}3{e?(0fUFUzo-?V4wvuDr9uqN1Pqxk2^SC8~?;WA(&QD^;hl>u6= z`uRNCLrVv9Ibe90Rr&q{u^8yA9bU6T?{PfWK92eQFsfvkdB%PclR3Cc> zd<>W3zIu9DU1jCe)0m$5Jmf;lP^Too7tiz_^s98y;`Tu~H{N(71hA3x)MsiQW%vUd zi@v6egWTIpKQ%lmj-xPmn|<70cs6bQJ6Q;#CPc-uks6_ce5b1^+vjj=MuPlfQd&k9 zho~4-&t}=G)8~oDgI`IhbF3*C?ZczRm;*Y41JFj&!;|D7D>W@k?sRrJWa3^ux!%zj zUWcWDs;JcIX^qxiu5ZMssd4BvF1hq9-=n=6t~V+>J+02ejl6xTE4VP)?RP|U-E-5V zC|8=O=*h0%;gJ*M-vhzJm z$ewl071rFO%khO{RGJZ%J)MIN_sZATYVPlV&HYy46P<_uL{TavU4{n(aD;gO1BH79 zJh2(p)J#TI-Aib!QmUv99MGWk_H4In&}Z)bioPW}797~LY}L?s;`5M$$=UX7yXwcO zp>5ajud)73^Y5~mp7=fJg|SQM(a{VIg@!2yxxGB@rNPER+C#7WRje3MomDn;7UxruJ9(@q+kw;?cze%!nhFXDj zj*5*7pEzN3)EJc5NO=w0iE%E|NzVibWydHjb$Zea&1N)6m(~xF6CM>dDlUAqCN$vB|Bz0X+@!iFsMFPypexWjDLXzTDKqiP)J~cb zHZCeA(vw)=Lwm{UfI;l=wA8GOv=k4e;HkFyVerWSxZIiLEV0q!5d5ADWmo@M%%p!Y z?r`aUPd<9sr3`y|9OA^ivV$;oK!^d>#+I0>#t0h8hs2qf?ZCK(fn~LSHIhC%0Wnp? zlsp_EE$)5?{1i^=&d$otu*=hbSCvzbdDDJs`JVWw%Q!t6VV}bhvs*07lTHsiN=h$soX&JYAzPt_5Ezj~j+Cxn| z!=4qVDz*eWJI`!jQh8T5!RLv`qaJgVIZ;f-L9x4js}kW(|3pk&_L*|?P;%T8-|f*8 z>f%-kF>Yf^_8-smSE&cOR0C6#L{krsM?Eg*hm0pP+h()d6YL1yyJkBZ#WNkI0Y)T6 zwgZjOt&O|U5$rjknAXNc9>TjLXe7T%uN*Z~0$*+vdgg1Wo^n37%7N`}hS)QIL;TL5 zqpeELW#V!TeD=uiqC-<8S1;d|VojP=Hyd_23D?-(_3?O;;z>tCe4L(Pw`(1U0;ANx zBaS;oj&ozGHyabmYOqfAuj)-qDz{TYs72_A$(`FZZRy_CT?U2mVD@z7uMv7@CnLIx z=>p6?qod*`HG38pyvPK5=JRN8g#0 zp7}iJ&9K|%C}nsMjkusK*{+JU=lnIivpL$TAhiKJ@q6fXjV{J#6+v{HoAk`*Nf(r( zJY9MX|3dXPd4SwcKPz*_T?6h3)n{eOHZ=ssNwrP#&(!Iz$6%|hcD1R_1S^83oSwag ze@d|UGP&`nH}F}Ng#vn4^2Yju+zxI|585x(H8JhcAD~z0&qSo9+Uqq#J^UX0q(9?Y z$JEc=1#xvgb#<0Y+UoaT4}A1v{+sw9_q||jWADJ6<~6r`!*;`iPGz1w)V;!W2HjKs zJlao|SIxk>IcyDb%M*`B`J6X!@kyiCrN-$falQcBO&-a34hb~%j&(fN_!O*q(FUB< zCHxDsW+!A|l2EzBdK)|RXog+HW@tH-Hy9(yi;v>1nMt-d#j=Ek#*N2-76XKgY#Yr& zN{Sram!}0(gqP8YKyC&{TvwpeeSD%BK6e~f8J}QiGG$auto!i9wN!@=wqhT_6;FP9 z*e!G+RaYxh8yppI{Z9k-&ZC{=AW0*5HKZKkt9DK`2H;gA`Ra7JT_K47v4%*Sw3Io0 zjrnDrl7=O4(^JxLB$T{fRWp&eYOCAoo^!dW`wREBkmZifITCPbocp`_?d1OMKk?(y zpX*IkDLtT(`pUxv8)lFgYgCw2-~aGvH>HNE59^87V?GvKgMJ@;hwNZ@rt^>=_$7KQ zbHi#nSLyZJ*8?vHr_*Q2Yls`A6J;m#hiy^*VL*wWSjnjVQx$_dpXK(E*NR=Wfn0jR zvtAy2qP~`$Z#~D<@@mui_3}ustlxlEa!;=eIAzU&g|sPH?FUyp)1INM>ccuWc|a<^ zPq0t7W~XGuS!YAUw1tmQ@|-}lA#)aj)pcW7eTp?>1{{PetXI?{z7|K9wN9Sh@FGAz zgUjLMQe(1izBz7uc9uOS4yw%_HEzQ2xVRaq*>SdS5-0ZZJB-^}E14m(n z4AKveiuKusrfRL2z8+#2HnvyLizC&5q92%>kY6m7w`<}oP)c?N z7Q$;SCi`h_e83VXvgTU)r;84`2vr|=((SBwa)PnQ2LyrmM?6Cn+N< z+nQ1*Gxw{NQoAIbAa#9xT^h!gAy=C0QLfz51=l51gw;KrC!HR8NcJE+Owc1a&NeH~3q9}1uH_w#ley`@i_EgUUPpNiJypXYsM zY$ckNf1J11*j(D&Iw z8;41MIfpm~o6d?`%P;0#GLDdHog*E$nf{S3I71z`nEn>S%WLwgjUl2>`H8$=j6qVB zv#%rA^sDrT^G3%_rawjh^564*Gxn2?IeR*KnSK&ClpoLg+1OhImLJJGYV09ZIt>oJ zsX{7rS{zo>I$KfM-f}K*%s0I$z3aT+k!#v1?kj&M?``8ksl=J($TpRV zx#ipQwi)M$jPf_~wi+{~*PZE(*`_UGQu*?{0^?+9r85R6oUM?aa!z&JZdxU#ls}pG zgfUin)_J$%9@BFou6%9Y^TvC{wDQ$?Ym9eE&p7XN++liJTIP&&M428EW6SgN9yXfA zg!0Go9yd;u9(9g)j59qVBFdNKEj5mk9(0azj5a+WEpmoA!cB{XsXQ;wVKh<>o*K|( zZa-_QKi-_&^qJ1PXEk~J?9ACiHramJ@MOaC1DAc*YU7UY=XL+(%Zg>+>|fP)+_t9g zEPVa`CjECDFSvf^@`N_quRpEdGBYy0?97j*cbD9E@Y^m`$9|YKx%A-K50@TTJoV|6 zcFxVo3G-{>Fa5U1{_w=RCI4?yd~LQ7tuOr5((loa^r^Sp+a_t;F_Y!XjPx1n_Z{=P zb<9EUv6q&%+@D<9Y}19!r9)Dlek1JAp0~a;*1Y}l(Uh+TX5W2y)aNY^eShbOeJ{N{ z;G5o|;>XF3$zOfc!TQC{(z7Lo9=o?redftGKX1M1ogL5b(Dm_K<`ehEH!VKs`AhTH zA6%Gr({!pf z`u8V&QxxUXSQu_JG$hSgePvBIjiO7X*1_H|Gd?)=W3g- zyx~>R?DglH+!wL3^~wDk{2oj^Ep`8Amv7QNx5uB~JHzfsADYtnxNmamoURA|spxy) zp=tBKZS#rwhZ$*y%W7)=eD|^Ncei)^^06(J6B`a4x_{-qb-Q_z2(jK`!s*&jTO^M`g+gYdiRU9 zU+ud2^Dj#CpZ})c^{@VT*OpxgYkHry{r2pJnc2-&&e9e6Hhp&F&{kDTXEe!Zcf0Ue zWZwCt|NI?CUhVt(f{?D;TC90&|B9CHe)-e(KfhmSIQ(7ngZmFW5O(C?sp_piB&II@ zHsI3^@8;dryX;)$+%0Ky$87KP^EAI@vuC!h{rDE&>327muB(0C{&>=>@zn=vldYpZ zPw9|zq*>t~`&)h$yV!feuB~49Zo-Tg&v&qVF@8)^)OT}JZ!^!__v-i44t+Dd`C;S9 zTfQC^^Xl70??3<6kGY?}G3J-r(gEF0zw^$+yWaeGz{;&LFKj63=`-|;H&^<8^=Z)U zKgRBy@lB5#=TG0d!))EH>za7a6MfTyhrQdpWZh#e-s^hUXWFBG>iWxe+%zgC4(o$5 z=FQI1miTH*Gv(E|Zi6KCUWwx}-`G)i(*9ZPnKyE&IZP~;nPaOPFUj_Knw@c#lVJZJ zl_LQm_B&(CCcYvCXamp#i~t9qD_|(Vws7u()5&S?50GZ`{pYKf=6t+p&wUr}9CPxO zgX>>=c4LNf`=yn=hmJh|$>2>tol5`u=Jwtn_IR(;Q$DNl^~fVtH@uPEbaB5fT~ntO zM&EL1YtYe~mc;B6zw0l)e%H*s?+!PQyW{gO{w)4GeEguLqiS@ylWtwRdGZG1<13yE z`Rna%-x}J~p4tCti*~=ot%~Tl`^Ec5B;3vw`@rDk%SQjP!~e&7n}1g^Ftk~e zZ_m4T9e6pu;K^h2j(;?4)}voeC`y@n_E-D-SN-11>2+hb7fL=j@k3U?*mv?Do_$;C z^hmFBt*k?CFMFW;`sXXFpS~{Xo5!A5)BV9;KAY0#@FVLUYPs|0utd`{{abH|eXGL< zHrpmb^}>Zq2!G6-`wZdSf(4HfYEPeTNjQ|8{0`yAw6xa=1@FHfORx+WFo~d(Brn2e zGiDSKruOZ7AK~~v|8yple)Uy6Vf;%k{Y?06&YabR$3Omf6d_>IqUQ(??b%}_T)6MP z2MK>(xX_;P#+`Ro5gr>eW)I=-lP8-KOs~B18)56ggEI(m>(^f*jC$?0UkN>)eRd}y zX5+^5gku>QPZ8EQop%wkw{PD?sJwKk8)3xCm9G-U_3k~BkTP`WG{XHON16zKojeZ!$R!y2TCG>3Db||5% z!?A{N_{fnFgiougdJ`txa6=Ly_l-9`CH$J5y_V3nY16KR>lZJ6o^VIMep!UUUAo*z z7}~XKf5P{vsc#TUrcL{Ua93gB--M0P(dP(rZnFN-w|+*54hmX8_~Gc$ z+X(mGbW=K^-I67%2rtCM{6#3+w=a=^E-C+&|NeVFf)N|d2}dtp3?R&V{q>Is+wQvS zcf!G$Gv6gVx_9qr!i;y{{f3Y+eE3+x6K3;|gr~=iJ4o1a#~mjKOF#eIOnB>yFOmuG z|M_PyVPbLdPlVt9{<{O=f$;G639HAC|B5hu(4Z-V>y|Ekg7EODQJ)ijsi|p0@Yd;k z3IF8g<`D`fO*%=)x%JivLa()J-z1FPy!j|${p87K2={E*@DBm5mXqM~_~Q=~My^=# z3c>K)b8i!7hlJn@x*?IL{`$+CV0-)R!-Topwv`iJ`}W&xLYTo|Bk0?-89=}p6tXW5rPk^ z74;pVg|BZjLS)aLDTEz&-+hd*cGs?Z2=5#?kV*)D`Q<+eyW`_uAPg@k*i5+j$tO1w z4jel+jBtA1ynMo!$Bz#r2Omr(>^*U!2Vvb0KP)7i$jW+_ za9cotf$-GWu|E*3@4WLpp=Eyl1BBKOKfIJsF?;rM!ou5b3nQeLmhL8eGJSe6VR>Za z*92cLFCW7BbLS*Nw^ps%5_Vaw8wfLp42dJWdi(7)gru^vF9;nUc%XprOnLbogwX4+ zzkzVW^Us$NzNxGXAyidYwN4sCiUr)L)diq@O*;TBab{zxO3gQ zYC_Y89&!-6v~1atVBfj(Tf$dA|9mrHNm$qigf9{kcMuktOz#nbo_S^qVOszGa|zvB zx4w?BV9S=hgw3(B7YVc8dg~COUxyB%gy^O-zZ@`hQ^-!^hUfFneD(Ljqr(@ixvBQS z!Hy=S`F5!X1 zr#l?nc=spw*te}nnH@Rl((h&8-rIik?Jqw1+>+&Aza$=c`#`hv$L{div2~R17yY_F z{_)7xy7JfF@sip-oE%zkooV8X?|)r&`t#3Dmi(Og)XQ0c$6pz;^hnLH6Wy{8r;a(* zCH?xK_a92z9^b0C)4N?SPQ7jH2m9ygSAXaHC+E{?X9IrNJZM>y4{v_GZJRr9aQqf$ znVehHxzyaU|4;MRuH5tNpM@2-jDI!wuPq-{y>;v2m}jgV`+DF1=G;TQE0g?fQw%Nc zn|$`gNrd}N_83B!jvL=2gx+xPQ-oVyO5RHdcy81w!pj%#c!@CfsMkt@e!zt(gjeRw zI!9Rc$(#bhU%GL<2orz$>LTI&;JsfFdJl3nZP6vN-MQksiLyV zy7&=yQPB^&SZPBVT3KZkSE_VHMJ3GleeRF>1(UXJ-S6iQpI2_qo%5V~?z!ild+xdC zd1m;RhrifNW#u1wHc|Og*n1pQYI7@!sXU%@HIdbp|w^RAbuaiQl-1$%c8bsw2-}%saDnHpC_AHguq)+}gm3M#Z*{@Jh zgN}WJ%Ih0Gc8JQS|9#VYs62OS@JTAa3;pi}D*G#c_B0jSD~ms*5)%A>UZV2jjKeol z8U5VKr>SJ56kee6%1$_GC9R0x%CRvYf2 z^8R;y`cG8aUk$m7%B$}W{vwrqzxd`ZDo+%B=AWp1aP*;IDq6^74V4nhdKZ;zoPXI& z<>hbws)Nd>vP|Ptj$Z0MNo8Qp_)RLIpL(=~$}g{ZFq6uuvEN*#^7QG5-BeB+V}3x(5pz^ab--w_x(sTQNQrUUajEPFzbsMjz5*;2DN#(yE{oV^y z?)X~YKU0an;qzlu?t9~!k5lE0d?bU)qo&(VQ2D>_{_ZrDuf4upL1k$6jWQ}1)24qw#aQ-n1C@0hH)T<2{%&j{ zm5=Y){9!6D{>xoURKED9^jIq2yY1=YRIcy7b1#+YucZEtO4KI`=Bb?g_RlA%yyvSM zs;GRv_MgvDiFM@unab{8mET0AZ@G1pO3%XG*HXFn!^u-rZralJTPmN-+y6Z(mok6+ zZ7QulcxHu)b24%pmCybDAO4-nvyZ%%MCFyQKXwb1yI=TLFO}r?UYMm~X?!w@$}#JB zCzYa)>^e;451(20uT(t5x0B`UYy z{q8g>-+k7RN@eRaM@FdF_YZHUviz|he2&UY+r$8sEzeD@r}Bp8+(RXM{*^yc`RETV z(Ns1*@rOI9oY?pBXQ-HdJFt(+`1AXUsLZx&Kc&+BRv zD3uEz_%Dr$u664}RQ~))dp(uEL}sT@`RdW@AE5H&`HQ8k zRJK2@e}u~YOYx6U`SrS;pQ7@k&)@nRDqk=C{#GjgvFSfwr}D_|FYlz%_2N(Or*iPW z>+hzL5dWi7RO-LC{aaKD|M6mwxvTRQ|bQ^!-#a zH)kYM`Pa{8S*dKe{@?1T4FBwAJ(Z-Ld5=`-yOQS3jg7v&)ey9WeWR8INfzY@1tas3-$8Xueh>qSCm=61mNO-bH$YmSOk~_ z*acV)*b9iiKch?nZU$`r?G;xA;OHAyT)lw(_@nbPfP;XGfWv@ccosGexCw9)kbdQ3 z8qf?_w21bA{lCBB8Uob*c*TXkrKt=qU2!!5mj4-i0K2YSab@b!KVUxKFklJbB%mE| z9Bjo;_3mMPhW9O18Vpqj)`&5!~0fTcEHVdp+CUI_pi8=b>N$` z;>rhf>{@X(12*qoaSahZf5l~phkgoIT;+hH_pP`F0Ot>_xWd+BT!&X&C4h@npa)#8 zU2&yu!2H@Ven9;rE3TazF^-Qy4}hbeTyZ5OV4eVX0%kn6;%Wih3D^Y~e`dus2YA}C z;>x-P{X17&t$_1SL4SbBpIvcT@CS13pToETwSLHfq-FD0AP3;)e})`@^WVhyuE%)3 z1wG!ND2M(P`oj+o&VCp2B|?rDK}YZ>D=sr^efSmhzZvwuSaB@^ZvF%A->fKAI{Xmi zEf`lg{z}fR7*B-DH33*2=W_KVVV0vMm?a^bH)DTe^N0LuXf=<^u1E0B{s=6mYWK zS0p1L#_7 zT&`Js9tT_koUes`QlZ}uqCH@S9rFO#+yFj+oACpP1ArQSv@kvmdIL-XTm;++n9&5i z0#^M4^Z;o780gZ`KVSx6@+V+dfW7!(#P}^34`34D{9`WH3}E@=&`Sp96R;d`QycUP z*b3MMxcCI@3sC=rN?a2fD4VB%J+&ok%;a2BuvaML-Liyjo%0pkIyI$f?Rz|(+D zfX#poz*fLMf?XK@cJRI6a-{+m0h$3FfW?4afK`CKfK7m-fIWcIfP;XufMbC3fYX4< z-7Z&HCi(|V2GpK{egGYS4#3Slpa&cVRCZv#o`(E@(|{F#8P8ze00#lv0LK9b0L`BT zf52hDu=hfbfJuP!fVqI>y)M@wz-7P|z~*NmAK*CP7~m}6G~EYW0NngJ*u(qKKVT}L z9nb<63xOnx5re;4!# zxEb&?pc$|nf4rd|Fux!3^L~u?1&kMP(-&cvfXQFNxbBAB1Ly~E9?$})|1#_YFd48B zFdwiLunMpTuoZ9+upe*?a2#+Na2{|0Q2!OklLa~O!?}Zit$<^I28Ca`M+y`Tf8yXe z{f!Kl0QBg8Vy_nWi4MzJnE@_K;1U6;uK&dqS1zEE9i4bV>kcxWQTM<0>QABx6^~Mm zk_sA)5aJ?!r%{&P3%R^-ZK%)t;d+6a@xmqI^AO4;a3qsgzq@6>i9k=IP`eU9Nn<{v zI&=k~nv7Nw39o~VV@!egYzE0@(DZ?3fatTMQ!j*c2b<4mj-W#koKbcp{>&f0bdOl_ znI=O!zw-f|avkXt=Fa+xhYqq-tcjyoDB01q7oxkPjAtX-!_8;(j!0uim@`z(1Ivq3 zFTG6ifh}u$2<;Q*uDIqP$Evm_PuqOIwxnbHMzb>dE5u-2JT|wBzzzA~!XQ^aaMXq_ zf}4Qr^P@`zuFDIT2s$%xZNN36?xmmmNINu&e4rE2=PYROqt%M`92}1rznR8wq%q`m zgxz-$b|c0fT}w#1+Yv^JvP4|Wj?BIYEh)v|R|`J#|0Vd@z4$R!?crx5OdVnOzWh@5 z#XVw)F zj)(`QE@of4@733&)NMK9PMCgeCYn6SD=A#xR6S_-A%+31xB^-Em zbPxK9>y9;@F*ssOXQSJray#_SNb~vda}lP_u;N!PWnaGc)z{oc0(zn(LZUktaX!2= zj2IL|5GlGPV5H{Roncw%vmbp{Ab!sX!uXzGeYWYSg_(6k+|0y|SgA)ai zwvmZNdk8VVw_W7}X914ZJY8f%CBPN=;q1T_`{7yyKkv3(z?JyX4FFdToSyXn830dX z97MN7KkyMfarfSN?$M_&PD^Md#y1?(1WzfxU(RA zPk^o;beo6{ml=ihI0T%7?71DmgIs$g|2`6{5KN@cVPmQV+H`N3lz8Io|T2y`=`8->1n=!|F8cAfeK*;guVXF}f7%kUkf+XN7)^pvpawY$gveUEX(b z$|Q7|3;wAX!!pjIS?F8vAJARc(7oPxCf>2mcs8y**3@Be#u(2boMyo8>(w+8Hl)L3?$aB%AuorarT&PyALcWKF_& zcW%Vlm*)F(j`FM!~OX6VB1JPTCm1rdZR3Hnsb4)p+JH)$tkC ze703>e^mXbmmh(>qb=o87O!7%Em7Ng*0v4fdQ$Cv0&Uw=$Kz=GnA-js^&YRb+0IAR zj#l+Fw-EL}X2r;{Z0|1yU&oC?ruV*enX({~18u|J1-piQXxH<$!Pyrq-3N>vdz^XZ zbGheto6qcb>^qy^zE{m!r4$QzOo7MrEyzL8e4POgV|34_bfycA*zPm2#&fN)=O4vR z^<=E$iCELww%GQ^V~rh;#X3I|YwG-T?1#Yevah0df@d=FLQ_e|JCLrdSJRad%29K{ z<)ZXXxoBU7_7%vlu=ej~?R%hWhuRHuIrF6Icmld^Q`<3X9gnHb�zzV3SSb^RXe~ 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 BGR 转换,避免手动转换公式问题 +// CAN 收发默认开启, --no-can 关闭 +// +// 用法: +// ./vision-anti-pinch -d /dev/video5 -n 10 -s 2 -t jpg -o ./out + +#include "v4l2_capture.h" +#include "can_comm.h" +#include "send.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +std::atomic g_Feedback_Of_The_Actual_Position_Of_The_Left_Front_Door_391_S; +std::atomic g_Feedback_Of_The_Actual_Position_Of_The_Right_Front_Door_391_S; +std::atomic g_Feedback_Of_The_Actual_Position_Of_The_Left_Rear_Door_391_S; +std::atomic g_Feedback_Of_The_Actual_Position_Of_The_Right_Rear_Door_391_S; + +// Sensing GMSL2 驱动自定义控制 ID +#define CID_SENSOR_MODE 0x009a2008 +#define CID_TRIG_PIN 0x009a2084 +#define CID_TRIG_MODE 0x009a2085 +#define CID_GAIN 0x009a2009 +#define CID_EXPOSURE 0x009a200a + +static volatile sig_atomic_t g_stop = 0; +static void onSignal(int) { g_stop = 1; } + +static void printUsage(const char *prog) { + printf( + "Usage: %s [options]\n" + "V4L2 MMAP capture demo for Sensing GMSL2 camera on Jetson Orin.\n" + "\n" + "Capture options:\n" + " -d V4L2 device node (default: /dev/video5)\n" + " -W frame width (default: 1920)\n" + " -H frame height (default: 1536)\n" + " -f target frame rate (default: 30)\n" + " -F pixel format: UYVY | YUYV (default: UYVY)\n" + " -m sensor_mode control value\n" + " -p trig_pin control value (hex/dec)\n" + " --gain sensor gain\n" + " --exposure sensor exposure\n" + "\n" + "Output options:\n" + " -n frames to capture, 0 = run forever\n" + " -s frames to save\n" + " -o

output directory (default: ./frames)\n" + " -t file type: jpg | png | bmp | raw (default: jpg)\n" + " --quality <1..100> JPEG quality (default: 95)\n" + " -v verbose output\n" + " -h print this help\n" + "\n" + "CAN options:\n" + " --no-can disable USBCANFD CAN/CANFD receive (enabled by default)\n" + "\n" + "Example:\n" + " %s -d /dev/video5 -n 100 -s 5 -t jpg -o ./out\n" + " %s -d /dev/video5 -n 0 -v\n", + prog, prog, prog); +} + +struct Args { + std::string device = "/dev/video5"; + uint32_t width = 1920; + uint32_t height = 1536; // SG3S-ISX031C-GMSL2F 默认分辨率 + uint32_t fps = 30; + std::string format = "UYVY"; + long sensor_mode = -1; + long trig_pin = -1; + long trig_mode = -1; + long gain = -1; + long exposure = -1; + long count = 0; + long save = 0; + std::string out_dir = "./frames"; + std::string save_type = "jpg"; + int quality = 95; + bool verbose = false; + bool can_enabled = true; // 默认启用 CAN 收发, --no-can 关闭 +}; + +// 手动解析参数 +static bool parseArgs(int argc, char **argv, Args &a) { + auto need_val = [&](int &i) -> std::string { + if (i + 1 >= argc) { + printf("missing value for %s\n", argv[i]); + std::exit(1); + } + return argv[++i]; + }; + + for (int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + if (arg == "-d") a.device = need_val(i); + else if (arg == "-W") a.width = (uint32_t)std::atoi(need_val(i).c_str()); + else if (arg == "-H") a.height = (uint32_t)std::atoi(need_val(i).c_str()); + else if (arg == "-f") a.fps = (uint32_t)std::atoi(need_val(i).c_str()); + else if (arg == "-F") a.format = need_val(i); + else if (arg == "-m") a.sensor_mode = std::strtol(need_val(i).c_str(), nullptr, 0); + else if (arg == "-p") a.trig_pin = std::strtol(need_val(i).c_str(), nullptr, 0); + else if (arg == "-M") a.trig_mode = std::strtol(need_val(i).c_str(), nullptr, 0); + else if (arg == "-n") a.count = std::strtol(need_val(i).c_str(), nullptr, 0); + else if (arg == "-s") a.save = std::strtol(need_val(i).c_str(), nullptr, 0); + else if (arg == "-o") a.out_dir = need_val(i); + else if (arg == "-t") a.save_type = need_val(i); + else if (arg == "-v") a.verbose = true; + else if (arg == "-h") { printUsage(argv[0]); std::exit(0); } + else if (arg == "--gain") a.gain = std::strtol(need_val(i).c_str(), nullptr, 0); + else if (arg == "--exposure") a.exposure = std::strtol(need_val(i).c_str(), nullptr, 0); + else if (arg == "--quality") a.quality = std::atoi(need_val(i).c_str()); + else if (arg == "--no-can") a.can_enabled = false; + else { + printf("unknown option: %s\n", arg.c_str()); + printUsage(argv[0]); + return false; + } + } + return true; +} + +// 使用 OpenCV 将 V4L2 帧 (UYVY/YUYV) 转为 BGR Mat +static cv::Mat frameToBgr(const V4l2Capture::Frame &frame) { + // OpenCV 原生支持 UYVY/YUYV -> BGR 转换 + // UYVY = COLOR_YUV2BGR_UYVY, YUYV = COLOR_YUV2BGR_YUYV + int code = (frame.pixelformat == V4L2_PIX_FMT_UYVY) + ? cv::COLOR_YUV2BGR_UYVY + : cv::COLOR_YUV2BGR_YUYV; + cv::Mat yuv((int)frame.height, (int)frame.width, CV_8UC2, (void *)frame.data); + cv::Mat bgr; + cv::cvtColor(yuv, bgr, code); + return bgr; +} + +/* ===================================================================== + * CAN 报文接收解析 (由 can_comm 接收线程回调) + * ===================================================================== */ + +// 512 位报文位域, deal_msg 中按 msg_id 拷贝后可按位解析信号 +static std::bitset<512> g_bitMsg; + +static uint64_t get_bit_value(int star_bit, int bit_len) +{ + uint64_t signal_value = 0; + for (int i = 0; i < bit_len; ++i) + { + signal_value |= g_bitMsg[star_bit + i] << i; + } + return signal_value; +} + +// 收到报文的回调点: 目前仅解析 0x391, 后续信号解析在此扩展 +static void deal_msg(int64_t time, uint32_t msg_id, const uint8_t *data, uint32_t len) +{ + if (msg_id == 0x391 && len >= 4 && len <= 64) + { + memcpy(&g_bitMsg, data, len); + g_Feedback_Of_The_Actual_Position_Of_The_Left_Front_Door_391_S = data[0]; + g_Feedback_Of_The_Actual_Position_Of_The_Right_Front_Door_391_S = data[1]; + g_Feedback_Of_The_Actual_Position_Of_The_Left_Rear_Door_391_S = data[2]; + g_Feedback_Of_The_Actual_Position_Of_The_Right_Rear_Door_391_S = data[3]; + // Rear_BCM_0x391,0x391,64,1.0-1.7,8,Feedback_Of_The_Actual_Position_Of_The_Left_Front_Door_391_S + // Rear_BCM_0x391,0x391,64,2.0-2.7,8,Feedback_Of_The_Actual_Position_Of_The_Right_Front_Door_391_S + // Rear_BCM_0x391,0x391,64,3.0-3.7,8,Feedback_Of_The_Actual_Position_Of_The_Left_Rear_Door_391_S + // Rear_BCM_0x391,0x391,64,4.0-4.7,8,Feedback_Of_The_Actual_Position_Of_The_Right_Rear_Door_391_S + } +} + +int main(int argc, char **argv) { + Args args; + if (!parseArgs(argc, argv, args)) { + return 1; + } + + std::signal(SIGINT, onSignal); + std::signal(SIGTERM, onSignal); + + uint32_t pixfmt = (args.format == "UYVY") ? V4L2_PIX_FMT_UYVY : V4L2_PIX_FMT_YUYV; + + // 启动 CAN 收发(失败不致命, 可继续仅取图) + if (args.can_enabled) { + CanComm::set_msg_callback(deal_msg); // 注册报文解析回调 + if (!CanComm::can_start()) { + printf("CAN start failed, continue with camera only.\n"); + args.can_enabled = false; + } + } + + V4l2Capture cap; + + if (!cap.open(args.device)) { + return 1; + } + + // 设置相机控制 + if (args.sensor_mode >= 0) cap.setControl(CID_SENSOR_MODE, (int32_t)args.sensor_mode); + if (args.trig_pin >= 0) cap.setControl(CID_TRIG_PIN, (int32_t)args.trig_pin); + if (args.trig_mode >= 0) cap.setControl(CID_TRIG_MODE, (int32_t)args.trig_mode); + if (args.gain >= 0) cap.setControl(CID_GAIN, (int32_t)args.gain); + if (args.exposure >= 0) cap.setControl(CID_EXPOSURE, (int32_t)args.exposure); + + if (!cap.setFormat(args.width, args.height, pixfmt)) { + return 1; + } + cap.setFps(args.fps); + + if (!cap.initMmap(4)) { + return 1; + } + if (!cap.startStreaming()) { + return 1; + } + + printf("=========================================================\n"); + printf("Capturing %s %ux%u @ %u fps from %s\n", + args.format.c_str(), cap.width(), cap.height(), args.fps, args.device.c_str()); + printf("Press Ctrl+C to stop.\n"); + printf("=========================================================\n"); + + // 创建输出目录 + if (args.save > 0) { + std::string mkcmd = "mkdir -p " + args.out_dir; + std::system(mkcmd.c_str()); + } + + using clock = std::chrono::steady_clock; + auto t_start = clock::now(); + auto t_last_report = t_start; + uint64_t frame_count = 0; + uint64_t save_count = 0; + uint32_t timeout_consecutive = 0; + + while (!g_stop) { + if (args.count > 0 && frame_count >= (uint64_t)args.count) { + break; + } + + V4l2Capture::Frame frame; + if (!cap.getFrame(frame, 2000)) { + timeout_consecutive++; + if (timeout_consecutive > 5) { + printf("getFrame: timeout/empty for %u consecutive tries, aborting\n", + timeout_consecutive); + break; + } + continue; + } + timeout_consecutive = 0; + frame_count++; + + // 保存帧 + if (save_count < (uint64_t)args.save) { + bool ok = false; + char fname[512]; + + // 使用 OpenCV 转换并保存 + cv::Mat bgr = frameToBgr(frame); + if (!bgr.empty()) + { + std::snprintf(fname, sizeof(fname), "%s/frame_%06lu.%s", + args.out_dir.c_str(), save_count, args.save_type.c_str()); + + std::vector params; + if (args.save_type == "jpg" || args.save_type == "jpeg") + { + params = {cv::IMWRITE_JPEG_QUALITY, args.quality}; + } + else if (args.save_type == "png") + { + params = {cv::IMWRITE_PNG_COMPRESSION, 3}; + } + ok = cv::imwrite(fname, bgr, params); + } + + if (ok) { + printf("[saved] %s\n", fname); + save_count++; + } else { + printf("[save failed] frame %lu\n", save_count); + } + } + + DebugInfo *pData = new DebugInfo(); + // pData->CameraId = (ctx->cam_no == 1 ? 0 : 1); + // pData->TimeStampMs = epochTimeStamp_ms; + memcpy(pData->Img, frame.data, frame.size); + bool res = send_debuginfo(pData); + //printf("send %ld %d %d\n", pData->TimeStampMs, pData->CameraId, res); + delete pData; + pData = nullptr; + + cap.releaseFrame(frame); + + // if (args.verbose) { + // printf("frame #%lu seq=%u size=%zu\n", + // frame_count, frame.sequence, frame.size); + // } + + auto now = clock::now(); + auto since_report = std::chrono::duration_cast(now - t_last_report); + if (since_report.count() >= 1000) { + double total_sec = std::chrono::duration_cast(now - t_start).count() / 1000.0; + double avg_fps = total_sec > 0 ? frame_count / total_sec : 0; + printf("[stats] frames=%lu avg_fps=%.2f door_position[%ld %ld %ld %ld]\n", frame_count, avg_fps, g_Feedback_Of_The_Actual_Position_Of_The_Left_Front_Door_391_S.load(), g_Feedback_Of_The_Actual_Position_Of_The_Right_Front_Door_391_S.load(), g_Feedback_Of_The_Actual_Position_Of_The_Left_Rear_Door_391_S.load(), g_Feedback_Of_The_Actual_Position_Of_The_Right_Rear_Door_391_S.load()); + t_last_report = now; + } + } + + auto t_end = clock::now(); + double total_sec = std::chrono::duration_cast(t_end - t_start).count() / 1000.0; + + printf("=========================================================\n"); + printf("Capture finished. frames=%lu duration=%.2fs avg_fps=%.2f\n", + frame_count, total_sec, total_sec > 0 ? frame_count / total_sec : 0); + if (args.save > 0) { + printf("Saved %lu frames to %s/\n", save_count, args.out_dir.c_str()); + } + if (args.can_enabled && CanComm::is_open()) { + printf("CAN received: %d frames\n", CanComm::receive_count()); + } + printf("=========================================================\n"); + + cap.stopStreaming(); + cap.close(); + + if (args.can_enabled) { + CanComm::can_stop(); + } + return 0; +} diff --git a/native/native_api.cpp b/native/native_api.cpp new file mode 100644 index 0000000..f256516 --- /dev/null +++ b/native/native_api.cpp @@ -0,0 +1,115 @@ +// Baseline V4L2/CAN + 0920 TensorRT/NPP, with a narrow ctypes ABI. +#include "v4l2_capture.h" +#include "can_comm.h" +#include "detector.hpp" +#include "uyvy_converter.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace { +using Clock=std::chrono::steady_clock; +double nowMs(){return std::chrono::duration(Clock::now().time_since_epoch()).count();} +thread_local std::string error; +std::mutex canMutex; +int positions[4]={-1,-1,-1,-1}; +double canTime=0; +void receiveCan(int64_t, uint32_t id, const uint8_t* data, uint32_t len){ + if(id!=0x391||len<4)return; + std::lock_guard lock(canMutex); + // Baseline comments specify bytes 1.0..4.7 (not overlapping bits 0,1,2,3). + for(int i=0;i<4;++i)positions[i]=data[i]; + canTime=nowMs(); +} +struct Engine { + fangjia::TrtLogger logger; + std::unique_ptr detector; + std::unique_ptr pose; + cudaStream_t stream{}; + int width,height,maxPeople; + Engine(const char* dir,int w,int h,int n,float confidence):width(w),height(h),maxPeople(n){ + detector=std::make_unique(std::filesystem::path(dir)/"yolo11s.engine",logger,confidence,n); + pose=std::make_unique(std::filesystem::path(dir)/"rtmw_l_384.engine",logger,w,h,n); + CUDA_CHECK(cudaStreamCreateWithFlags(&stream,cudaStreamNonBlocking)); + try {pose->warmup(stream);detector->infer(cv::Mat(h,w,CV_8UC3,cv::Scalar()),stream);}catch(...){cudaStreamDestroy(stream);throw;} + } + ~Engine(){if(stream)cudaStreamDestroy(stream);} +}; +struct Camera { + V4l2Capture capture; + std::unique_ptr converter; + std::thread worker; + std::mutex mutex; + std::condition_variable ready; + std::atomic stop{false}; + std::shared_ptr latest; + uint64_t generation=0, consumed=0, sequence=0; + double timestamp=0,driverTimestamp=0; + int width,height; + bool canEnabled=false; + std::string failure; + Camera(const char* device,int w,int h,int fps,bool can):width(w),height(h){ + if(!capture.open(device)||!capture.setFormat(w,h,V4L2_PIX_FMT_UYVY))throw std::runtime_error("Camera open/format failed"); + if(capture.width()!=uint32_t(w)||capture.height()!=uint32_t(h))throw std::runtime_error("Camera negotiated unexpected dimensions"); + capture.setFps(fps); + if(!capture.initMmap(4)||!capture.startStreaming())throw std::runtime_error("Camera streaming failed"); + converter=std::make_unique(w,h); + if(can){CanComm::set_msg_callback(receiveCan);canEnabled=CanComm::can_start();} + try {worker=std::thread([this]{loop();});}catch(...){if(canEnabled)CanComm::can_stop();throw;} + } + ~Camera(){stop=true;ready.notify_all();if(worker.joinable())worker.join();capture.close();if(canEnabled)CanComm::can_stop();} + void loop(){ + try { + int misses=0; + while(!stop){ + V4l2Capture::Frame frame; + if(!capture.getFrame(frame,1000)){if(++misses>=5)throw std::runtime_error("Camera timed out for 5 seconds");continue;} + double received=nowMs(); + misses=0; + auto stride=frame.bytes_per_line?frame.bytes_per_line:width*2; + if(frame.size image; + try {image=converter->convert(frame.data,stride);}catch(...){capture.releaseFrame(frame);throw;} + auto seq=frame.sequence;double driverTs=frame.timestamp_us/1000.0; + capture.releaseFrame(frame); + {std::lock_guard lock(mutex);latest=std::move(image);sequence=seq;timestamp=received;driverTimestamp=driverTs;++generation;} + ready.notify_one(); + } + }catch(std::exception const&e){std::lock_guard lock(mutex);failure=e.what();stop=true;ready.notify_all();} + } +}; +} +extern "C" { +const char* vap_error(){return error.c_str();} +void* vap_engine(const char* dir,int w,int h,int n,float confidence){try {return new Engine(dir,w,h,n,confidence);}catch(std::exception const&e){error=e.what();return nullptr;}} +void vap_engine_close(void* p){delete static_cast(p);} +int vap_detect(void* p,unsigned char* pixels,int w,int h,float* out){try { + auto& e=*static_cast(p);auto boxes=e.detector->infer(cv::Mat(h,w,CV_8UC3,pixels),e.stream); + for(size_t i=0;i(p); + if(count<0||count>e.maxPeople||w>e.width||h>e.height)throw std::runtime_error("Pose input exceeds configured capacity"); + std::vector input;for(int i=0;iinfer(cv::Mat(h,w,CV_8UC3,pixels),input,e.stream); + for(size_t i=0;i(p);} +int vap_read(void* p,unsigned char* out,double* meta){try { + auto& c=*static_cast(p);std::shared_ptr image; + {std::unique_lock lock(c.mutex); + if(!c.ready.wait_for(lock,std::chrono::seconds(6),[&]{return c.generation>c.consumed||c.stop;}))throw std::runtime_error("No camera frame"); + if(!c.failure.empty())throw std::runtime_error(c.failure); + if(c.stop)return 0; + image=c.latest;meta[0]=c.sequence;meta[1]=c.timestamp;meta[2]=c.generation-c.consumed-1;meta[3]=c.driverTimestamp;c.consumed=c.generation;} + std::memcpy(out,image->pixels.data(),image->pixels.size());return 1; +}catch(std::exception const&e){error=e.what();return -1;}} +void vap_can(double* out){std::lock_guard lock(canMutex);for(int i=0;i<4;++i)out[i]=positions[i];out[4]=canTime?nowMs()-canTime:-1;} +} diff --git a/orin/README.md b/orin/README.md index ca62f85..9bbe3f5 100644 --- a/orin/README.md +++ b/orin/README.md @@ -1,22 +1,39 @@ -# Orin 可直接运行目录 +# Orin 可直接运行包 — use-can -本目录包含实际在 Jetson AGX Orin 上编译的 aarch64 程序和 TensorRT FP16 引擎。 -目标环境:L4T R35.4.1 / JetPack 5.1.2,CUDA 11.4,TensorRT 8.5.2,OpenCV 4.5.4。 -使用系统安装的 CUDA、TensorRT、OpenCV 共享库;不适用于任意 JetPack 版本或 x86 主机。 +这个目录可以单独复制到 Orin 的任意目录,不依赖兄弟目录 0920/0923,不需要重新编译。 +包含板端编译的 TensorRT/CUDA 原生库、YOLO/RTMW engine、Python 风险代码、CAN USB 库、标定文件和原有 GMSL 驱动。 + +环境:Jetson AGX Orin,JetPack 5.1.2 / L4T R35.4.1,Linux 5.10.120-tegra,CUDA 11.4,TensorRT 8.5.x,系统 OpenCV 4.5.4 库;Python 3.8+,numpy、cv2。系统 CUDA/TensorRT/OpenCV 运行库由 JetPack 提供,未重复打包。 ```bash cd orin sha256sum -c SHA256SUMS -./scripts/initialize_camera.sh -./run.sh +./scripts/initialize_camera.sh # 开机后无 /dev/video5 时执行;需要 sudo 权限 +./run.sh # 默认 CAN 左侧、无可视化,结果保存在内存 +./run.sh --visualize # 可选浏览器预览,默认端口 8765 ``` -可视化可选:`./run.sh --visualize`,需要板端本地桌面 DISPLAY。 -默认持续推理直到 Ctrl+C / SIGTERM;正常退出没有统计输出。 -预览窗口关闭后推理继续。结果通过 C++ CameraPipeline::latest() 获取,不通过端口或结果文件传递。 +Ctrl+C / SIGTERM 退出。仅有一个进程可以占用同一个摄像头。 -程序为 build/camera_risk,配置为 config/camera.json,引擎为 engines/*.engine。 -./run.sh 从所在目录解析路径,也可以在其他工作目录通过绝对路径调用。 +```bash +./run.sh --no-can --active-door both --duration 10 +./run.sh --save-results --output ./outputs/session +./run.sh --visualize --save-results --save-snapshots --output ./outputs/session +``` -bin/drivers 中 GMSL 模块对应内核 5.10.120-tegra。初始化脚本检查内核版本;加载模块需要 root 或现有 sudo 权限。 -门区保留当前室内联调设置,door.calibration_verified=false。 +CAN 0x391 的 data[0..3] 顺序为左前、右前、左后、右后。`--can-side right` 切换右侧。未收到有效 CAN 或报文过期时输出 CAN_UNKNOWN,不发送执行器控制报文。 +标定文件仍为研发机位,默认 calibration_verified=false。 + +同进程下游接口: + +```python +from run_camera import CameraPipeline, parse_args +with CameraPipeline(parse_args([])) as pipeline: + result = pipeline.wait_for_result(timeout=10) + result = pipeline.latest_result # 等价于 pipeline.latest() + if result is not None: + print(result['risk'], result['door_risks']) +``` + +持续读取示例:`python3 examples/read_latest.py`(先停止其他采集进程)。`latest_result` 是单个只读快照;它不是跨进程共享变量。 +TensorRT engine 绑定目标 GPU/TRT 环境,不能直接用于 Thor、其他 JetPack 版本或桌面 GPU。 diff --git a/orin/SHA256SUMS b/orin/SHA256SUMS index 6034f9e..9588b90 100644 --- a/orin/SHA256SUMS +++ b/orin/SHA256SUMS @@ -1,11 +1,27 @@ -926a5165a4ebffe9568cf694018afb097cfb69b6e696a19939e5d364a9e3dfa5 README.md +4171567ecbea2f15b3c945b8d8363362d9f422b8c732d33ee1e15461b40014da README.md +9ba768d559fd3b64e833b50c62c70f2adfd6c169620aea5fba32cfb1b4c5b0e9 annotations/constant_door_mask.json +3544fb1c7b1b27b39db27d8f849d5e8652f5d09a950a59c5dd0c7703086b4f6b annotations/door_zone_multifeature.json 6d5e874fd27fcfd75d303d7e35d9672028af71041f52dcc82a1e83676faefa65 bin/drivers/max9295.ko 8a78d04ef8be44e9b62a5e4ee315d3d6d679e34aedff02a234bbf4d40e222933 bin/drivers/max9296.ko 3da628587477cc35d5e3f8aee86e718e2ddf16808e893e00ba6e164b2307e843 bin/drivers/sgx-yuv-gmsl2.ko -b5102fe0a529349bb8e9700ae1d8e8ddeaa7c4279cb28e7826c5cc32dce2bb1d build/camera_risk -f2334c43e6a48480260c770d46a3ab0edb855f6f52bc8b91d1559e69edfad043 config/camera.json -9ba768d559fd3b64e833b50c62c70f2adfd6c169620aea5fba32cfb1b4c5b0e9 config/door_mask.json -ebcd09e8c2e35008adbb0c1d222e580b17e0df1c8093df3481ba3374cd9a8174 engines/rtmw_l_384.engine -f6a65b926ac1144484f4aa93cd26d7997d32d62310ab93fe867f2bd4412222e9 engines/yolo11s.engine -7f42b0e7f9396e0d82313a892fc62c153261dab1206a206a466bce6376f58a36 run.sh -54e1d63e3aa72ad9b056a224d55968d4947ca6703a8d1c405570de5707a7e7ef scripts/initialize_camera.sh +cd75632beaaf81df2f59ce3e83fb335c21cc745068ef2b721c74cc3b2b03db26 build/libvision_native.so +49cc1067c1fa9f82a3d57dbfa77a55a54e5e5062ceae7ae84144b77745db79cf examples/read_latest.py +8dae8c557deadbe6bd7241c0dcd7025cb007077ee39a79b115e953a2b22cd9c1 lib/libusb-1.0.so +ab8b7f7249d5fb73d1d33d14fa7532a522088ffb6c25f37ba334daf4c6b4d313 lib/libusbcanfd.so +ebcd09e8c2e35008adbb0c1d222e580b17e0df1c8093df3481ba3374cd9a8174 models/engines/rtmw_l_384.engine +f6a65b926ac1144484f4aa93cd26d7997d32d62310ab93fe867f2bd4412222e9 models/engines/yolo11s.engine +fd3ae92255abf95ef037a1060ee75897f9705b4040f9394c3130f6ab860667e1 pipeline/compare_rtmw_ml.py +6d6d14a972bc4e5e9f8256514169e73ba0392a301cacd1221eaa26146aad00d2 pipeline/door_mask_risk.py +46d70e1e90a1f36d544b7492ef1fbf08821377a1c460a6683f42d4d7006055c7 pipeline/door_zone_risk.py +bc74a400ce5c5608c2fa49a69ccd8b41ec8633cd6a8239d9d594b8d9e5c3732a pipeline/fuse_rtmw_l_temporal.py +bcf2cc99dd27c8749801a5b743656767d9d64ef03d568d227cb654c573d70b00 pipeline/latest_result.py +cc8ea36d543896cd90f7a00822f06fc67771a1811859a4087995ac372df30276 pipeline/live_pose_engine.py +da299c11bd25127a09ffa738876f1de6e0d53d27add2840aeb6092ab0fe7016b pipeline/native_backend.py +81088b8bc072162bec13f57c65eb0d396e6d1e1074a83f92bcf29e393e27e11f pipeline/occlusion_aware_pose_v2.py +059e2a67c17ce63354986d3242a5d361103ee4241c5391f18140eeb19e47c939 pipeline/predict_optimized_pose_videos.py +bf8bb754cd841a52b4410f958a651b005de36ac4d17cc0992fbe1c90ed30caca pipeline/rtmw_l_person_mask_ablation.py +1bb58d851ba5d684527b8d1e1940db6241d2b0b2862687fa3b151899a65320d2 pipeline/rtmw_risk_pipeline.py +8a10e035334ed97b7480f558aff7b0464c255ac6138dd99f55a08ade68853e0e run.sh +4393f367b4ac7e5a00908043ffd21d5573cc12ed19b956fd101897ada22afd45 run_camera.py +11b5fbc3c17c0610ec0514a0a26cf5d92588d15c0e50e7086d9db5a5c0306e99 scripts/initialize_camera.sh +4cc40e244495e1de60a0429a8fc58cdf383ccda471955e53360a1c36a278c822 scripts/initialize_camera_impl.sh diff --git a/orin/annotations/constant_door_mask.json b/orin/annotations/constant_door_mask.json new file mode 100644 index 0000000..135b2a1 --- /dev/null +++ b/orin/annotations/constant_door_mask.json @@ -0,0 +1,77 @@ +{ + "version": "x-anylabeling", + "flags": {}, + "shapes": [ + { + "label": "door", + "points": [ + [ + 212.86, + 145.919 + ], + [ + 378.891, + 851.857 + ], + [ + 468.293, + 996.446 + ], + [ + 536.408, + 1294.131 + ], + [ + 553.437, + 1404.7 + ], + [ + 561.951, + 1532.279 + ], + [ + 51.086, + 1532.279 + ], + [ + 8.514, + 1515.268 + ], + [ + 0.0, + 1468.489 + ], + [ + 8.514, + 26.845 + ], + [ + 25.543, + 5.582 + ], + [ + 131.973, + -2.924 + ], + [ + 191.574, + 1.329 + ], + [ + 208.603, + 145.919 + ] + ], + "group_id": null, + "shape_type": "polygon", + "flags": {} + } + ], + "imagePath": "constant_door_mask_reference.jpg", + "imageData": null, + "imageHeight": 1536, + "imageWidth": 1920, + "sourceVideo": "D:\\huang.xuewei\\CMS\\video\\20260921104502\\segment_009.mp4", + "sourceFrameIndex": 244, + "constantDoorMask": true +} \ No newline at end of file diff --git a/orin/annotations/door_zone_multifeature.json b/orin/annotations/door_zone_multifeature.json new file mode 100644 index 0000000..3432c66 --- /dev/null +++ b/orin/annotations/door_zone_multifeature.json @@ -0,0 +1,47 @@ +{ + "version": "v9.10-research-calibration-1", + "description": "Temporary-camera calibration from seg_01 and seg_08; recalibrate for the production camera.", + "front_probability_min": 0.72, + "rear_probability_max": 0.28, + "minimum_person_height": 0.4, + "minimum_pose_features": 4, + "history_frames": 5, + "stale_track_frames": 120, + "features": { + "shoulder_center_x": { + "rear": 0.53, + "front": 0.64, + "weight": 1.2 + }, + "shoulder_center_y": { + "rear": 0.54, + "front": 0.46, + "weight": 1.3 + }, + "shoulder_width": { + "rear": 0.14, + "front": 0.2, + "weight": 1.4 + }, + "torso_height": { + "rear": 0.35, + "front": 0.47, + "weight": 1.5 + }, + "hip_center_y": { + "rear": 0.89, + "front": 0.93, + "weight": 0.6 + }, + "box_center_x": { + "rear": 0.48, + "front": 0.58, + "weight": 0.35 + }, + "box_height": { + "rear": 0.7, + "front": 0.82, + "weight": 0.45 + } + } +} diff --git a/orin/build/camera_risk b/orin/build/camera_risk deleted file mode 100755 index 276b22c3ef1a72eb39fccf579c34880499bef9d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 695864 zcmc${3w%`7wLiXRCO~)yf$)fcFbSxL50daoER@NF2>8G>iJH>ZnaN}zk-SU-1hFy% zA5_}PC{?Px5<;ycR*eE}Qg0;&>!otrreH0%?XS*EP*Y=V1d$Aa^Z%}W_DNQbbA0sP z&*wjWhB@nd_FjAKwbx#I?X}N|n{#fw&T6sPg!(#GE#$4Xe}zk0oIpdQKjWj_h3V4iBvOfT)@w1WDtJ`Qur zN{i-{6<=LeTCuL~YLBPdTe4u@H8qvjq-p&gk7_i=%U0eZs_y*R_Sa?>XZ)$DC+saO z|J&TxpSp(RCK-qym7x!n*Lp1kb#pRqQaRG;9{Xi8?%QU!U+o`1#Ibd$RqWa}^!Eu{ zk2n&<@CK_@mYss~m*8v1HyPi{@tuY5Y<#c6_ZocD@SThAJbdTlOP>tAg>X)%Eb*DCdAh7-O3R(g zzEyMIjZ>aJdrjos>u!m@{FmFNTo%6h)hqw>@u8CTsYibJO8UE4h$_uK^}7#VC4?G69g@G_9vK@yj=L#?N@~RZOJkS+>8#lJ zZIff;rB}wrZ#R)M^Xk~;Z-rQ~`qeW%Hh$Km{GUzAUt-d3l1cdpj5(G(X(r`=3}cT~ z{x9~}c*5-1_zF14n0!q1dDq0)<q+huvde~{wuS^sCLlgV2HW}Zan6&$ZiGR51 zirD(uYQkrl$^8ALiGJ)R^XM8A{YOmNecpu6^HXDwOS;K?|I}oide1~ZN1^{%_Op0G zY`oE=U$@VUE$1aze`E0N%6~{dj2Xc2AqEQ{Oj{-)ExdznS>?Q6~2AvWdNIH^Il6$a$TK9VVO1_g|anr_IFP ztS0f>l^4a<=YA9Z>rCutsEMA>nw0;W$$GTO#I9a4iGO}+GLApNJ}#EsE-;ZNY@(m@ ziLv?IZ(F>|JkENd?lQ``ulXY{INq={l%%hh~ z+8tx!w}(NZ9yS@5i%sU^9VYTDKq4iU z9!{Bz*LD+megb)7+0S!`A7agmJ51v0mrTYz$s|6!)?^-8P(D_>6()SrP3GxSCh{CG z@jthijLUzU*!ia;V(b5RCi82tNqqQ<$-KDUWW0{UPsY+uf{Fb1o2;h~n9QRECU}>L zKVM?v_nao>-!_S7_L$7aJtJf5`4BvIEc^el$vkzMtQS8pS;tFE@N*{oZHP}|jZ3-7 zxX(1E~|6XA%4r;oA)QoC3DVVvI;StLXvm zQGU9>pX}j?vIiai4--A#t>jF#Xbt{c@v%v}8Y8+XF^JC`g-=lB#d zPt!E4+wBj*b`RvNJE!r{?Q?LEDX*+>)zo^bYh5nkT2XM5tJqiVTT@z7>#HufDZ8w)!dKuaD)VXgV&3sq`#iP2 z6~r}fT}5qaxzDv?WkF8f%B&ly!OALMg?GKHq;yTmnsuer?!0T}3)iZZ>E88oZ}QYG zP0Lx&NKbyw&H1U2rN01>yc-mBgQ_&&OOjDVS5<8Z1Soc`^=))%qOiKz1I*{)X#gKM zt;~0&Ep)A@s9INh^SWC6n^j%y*_Z=(L2hMfMXhT^X--c5JeMrFFyHGb^HjT56zAlW zmX<2cX=xRna$oUnr4_}M8zjrxg)W!3t}ZPtExpK7Q|g6Et4k}^tnlX7rlomHz@fI< zQ(9ZI!kd%t!9U;zUaMB(cBU)8%2n=J>vPqhoUhnb>sd43mG7!8%~_u_-$f*f7UZMo z0xIgQgpyGV?f6#QxH1!CSg}qvp62*46szz7!LTM1Jjp^*(QHW%UYNe&w#B$NBSJIXO`KO)iX8Sy`pmRa#NwtFB#f zJ%*O<<*esDK@$~~)#aWtS1Ih!Lk;JmSpGtkTv~N=0hvd^3exTWAN^n!n>M%DhoP?A z_`k9R^oC}`g3|Jul7HKvG|NuYEL*c_;`?uyO9I!gyNj?!FsK#uJjJp zDs^*yjjy(#GL~ZV=jv<3!iq}G-1TL|cc)f?7~~YI$u+;Gs;sm&7N=N4q$(**!}I5^ zFCUCyy%-q8($6dwgA0R!S&6iC>CjhJR;=<>$Ly(M1z#r@E!kHLzs8WdSXWh@qY7n~ zmsZ^5slz%DtEaie&|0oxrNdN7SEH5&7dx=PRMl3mSX%MmCRLSVg=er zt8I-EBF1v7DV=vIr|2^(Vk>U?YAm+dl@+y>>#B9OgKBFG2T!!p(!qVzH92o}X;~SV zt@qXCLe#G$Wegz|+l7cF3Ve0CjhS@%t1q8}`%qd8dT>}$r1vYmxZ1P9pd=G9T!YLh z=dB*xfD_Bq4R2l&i#%# zvl=m@r((^QAAPg1dte*kt*rL3Wn!Si<>+v^X@_y=i#uHYnGVk__ta@4AlDK&$~?6Z z85DNAYAaoJD&jX^D$Vx-*bfxAa<41R#addPdjl<`wP;|y$5jSv$|=uxy6#d2wnn*^ zL2FxDny0wC@6N+hL{X^g3_tid^(yeF4Si`L*e( zu=)+2>f-*`U2S3hZ$b>HXTDmlGF*8@*jM>{E8wi4uocBVY(Hx^Vgr|7JFm=FQ$trC z+RtS`Tx=w;NaacgrYd5WQHY0{SR9d^Cw8rPcW+|2)$pGXAa_~As3n)y~yRI1f zXtK_ONG7{@4u<;=>8&)|YyHxz*UZSJ#&MH2JQBqRr&en_gE_61(l2 z}&p_W(H)XG{~Ut;vcC^p7quvWD3 zkWAz-kt}g!BUCa$gR3ZGRn=)u2R*K;ENffSXo$U4<-;hAXP7O4n!x zDCqh&Pj!{%uU#4IT-kH;T-mjC@=l)IZROutom*PxE8}++n_{2L)ug4#;`zSX7-hUN zVpm17i@up%Juf}IpfYcnQx;Cw8wAUm+G6jOSCVK8$m87b)m_d)Z)JHE5+pgfH+cU& zr!}u;gQqGd4~vXee*r1K%%`^V9wtEiMCq6SQxMA)X> zq;i%T0C%63x~`)1&UHSd11U-6!mg&4!cg3qr*AxqvA0H|Qm*p3*R5Z#jZ3NA!ys<2 z_FyF|%YlKE=E)2b))Zu)u%iMa+FKUf`oFdTWjLjk$OJ+(LuxPwX-%J}nuJbwt*ES_ zFZDvUO+C?uymYm>#ZjNM%ox@OB>3d8Xxhs_t1@C&X%{M%>8tbls-!cNalm|U?Zzq} z5|rts#ma2cGO*4Umr@x-B-N#q4W38IASenwP--U+1b*|SN79Ap=LP|a%hVPcQ(sLy zv_T_@mgLSozp|`G&n~5J`|dxys=>VFIpNQYvmBbrLgCBS&NIfL|hy zB$G2a`3wHd326-SZctGkg{P)b9#p1=caSrPjlMHGJa$E`B_lv5JBiagzKrm0b+8DQeq$x-xYTw-hE^KG<$N#Gs9u2Ant z#fEYyur^bDBHzT4c*Nh()HBVoC zjcb&)0;2?-hRF4~2osB8<)P(%i&RrP3r@Qy0*pvQ8yZbp>eam6_VLxvSkB@bH*S(nab~+F&*4;m%j+ z3K=stM|xO7@m$*6L8KZvw1knMgHKOU>H0Kex?J8e#LF&v=2a5ItOPV>8|+_rB0zs3%C_{ zk(AI4T#EtJ@toF=e)oeOsID#0HY95Ip`UMl^}U~b3PSEv3$UBfBdYnU;c{dkD3>2P ztf9EuS1sqJuHCe<$~AZbLB^H?UQSI}Eq+EoDD6XH8|bV>Twyc-ITuiWQco=wWsJe_Jm`L(`^8tkuhttcy+cL$zF(XlV`iZB86R6aN(BZ4on1WGNE#aC+k zNj;#AwKJu?p4sjKDcQL$3b~3s+7#!@5hmSDTBHc}*fi<`&zy~}U^!LO=27TFXSFUb zPQ7dN3VNY08^lXK)jqjOyFBaauu_-np=!E|f^N(a3J_o@`ieq6?K2q?X*9UOrxh@Y zhBI97CAFT?GI-|PYI^Xg+E?O1w4^{0r7*J;g?L z=qlcb*aKQt)yXXNfWRdGp*8Xah2}{+qM&hLk?437aDHdMhl>fl^OTjp7Q zgj76Vqve@~r=qqdO>NF8n&|fs16E@a)8(j!!11dZEbS<@Om9wJzn#QzkNxAEhJC8m zm45FnJM#I_6Z#@uzp6{h`dlxS0fTl`S60>zWI8@GCDnjcez`Djz_SjTQ*sTX8OpbU zmFsFGor%2O;dMETzz?8!qtEMFOVUXPEht^p>g?jgR4!AYw}_KbzYEE9u=y1vY2 zl=*F4Z7jgVz@iiKX&UZnSUjft+OMqi!MV5`TFPXHR^tGSMQ=E1Dc25JN;Xzi)(ZLW zYEg41g7K=#4WbNN%33<2TI0nts`8{rxNfP~Kw$`ugm5Gv4>Hv`4JFy}K&iK6E#j=w zG68khBDxazr*ea@TBC~NLz!8RgfDO-biE>{#{b(mIaJK6S z!9p*5bo{xxSgfz9s3IX(LtZq6x;WcbHE~i2&iy4wFi~3Rtt}Jf>nf;q?2lA!c~8oV zhbZXO4E?~v3-oj{$%xogS0K{+Wpo+}Im#>7<8J91DpgD=Zdnwx{D@^Yu5f0%(yvKd zD3)bsyXN9dQHRnqwadan!1Jz2n>U!u7)%Z>oGG#k3$vUnTxr+L#RJ)rrQ(yGK8VBt zAHSP6pVyqriNP(T53ZNKfE69YFGS45;~2l1IqI*u zX@A>|{?MCxww)e*x8X0c4Z$}~Sn;3sxAEvY4u83g-l2%cUj~c^jn^*lOV8L-+2QgF zLQ*4T%~A4SypDpq!|)Y&dw@6+MgPT#(YVIzlR$|k&eV?9+C@Nyf+l%};?0$d@GrGO z|IritV^NbZ;zKp4<#E7>vf;nsA`$mAe$>KnS({2}S3}hm^-wQ06f#g*sy!a}HCgH3 zM0~AMR%*{GCdg6~fX1N?^>Hl9jKnqZrTz@Zl?}AkB~L2buFKZI+4GjEKTBx@5F?LX=Z^^qi?Hj@(D>3_y2eWuph;3qZ!}Kyq578pv;PX@J0aS8laB=+#qeG%egTX= z)XJrJ$BN$9u;c4_;|iF}M2Ufv_v7&{lzu<=vW<8HWW0E#zrIz3@eUi^PsLZ`KSA;* z?0d4k1o7Mc@)ogzwU<0~%tbV%kpEzR7HCvJw{xqXrH7qEyBn2r;Ueg@OZ27r1IK*YyW-y?|Is^ z*Ly^&dQoV(`g@-`p0rOkCvpvVp~4Fd_%4OJ4fqL#ml*KnO&b3y1HMh+bq4&1!u{*1B@?_aeT@Prq%@~sBkuJCpPUa0U+1Kz9npD^GF z=QaL81KxL5!@CW5LZ62B8SwZbS~>8!UHjF?HyF|2cmtkrPQw!ncsKr}D1Gb(+^+b~ zGT;rLXnax)c&EZM47kpJxdG2m{BsR>u9CCRfcq8hHsCt{Dg&OY_}3ZmR3)e1fV&mG z&4BCtcNy>!#lOLTw<|gK8Sq|(w-|7pf4c$qEB;3ec)S|lP6M8#@Dm0+)d6RUPqzWz zrTF(6amA<4fbUbda1FM%D#bs+fVU|ANd`Pu@v$3lx58%`@O{cYGYt3<#ouATA}6kce+Qx)zu;L8~8t`s~pD^IP3hy@H30}>fdJXul z?`ZFx_8D=Ph70##J4||7!{ZHjgW{85z%vw|Bm-{m)!u`hWx#V&wEkuo@Zc$}{Bi@{ zqRJN<@K%MF81Qz5*BS653g2eHI~BgmfS*wKJ_8<9c&h>LR`?ME-mCBv2E1>YriX4L zuFCfra4|zGAFtL!eVy8MM$=n@0pF+aBm>^6aJvEbf279CfFDuiQw?~XD(^7hv((=; zUv9wny{+-jHQ+4@FErro3U?duR)v=s@J@x-8So?j(AwQ$z#Z>tc!L3VE4;;k=PJD2 zfa~v#cN%d0z3vkRyj9WN2E0VQ2i|AE{R$V#59#9`ROJ#3_%2m`mH|Ja@Kgh?$3G4O zF8Vb6EH~hK`9cGpp~|}rxL&@>fLE#Vbp~87zs-Q}Q{@{Bczi^Yv(*E!y7`&eDcv7lU^cwIJ z?`n4It{hyxP~q|F@9^vL>+~!Ge&P}(rvVQtJi~x@E8JngdlkOifcGgp*MJMPeia(< zc!j$Sc!I)940w{ls|@%oh1VJIRE7Huc!t8a8Sv!_-(kQD6~4=Wmngi!fLAGep8>B^ zc#8q|E4!V3*}p~Bq;yhPz82E0z;RR(;A!s`t9K85=Yc&oy<8Sokzb_1TF@FND?q3})vzFgra40x`>g9f}% z;oSz@t?*t0UZU_m174+YQ8U>7>l7Yuz;`G-!GJd?JjsB!D%@_sk0^YW0Y9PeR0G~} zT8pnT40yLH?=axK3SVx(^*lzd5m)O@p#kqxeB1_HsC|8j0pF#{R~hhlRld%ECn(%+ zz=LX^zRiFqsq#AvxLx7947gv-qXq*$OO@Ye!0rFi^xR^=Q&ss^1D>Jqb_1^Ge~uXN zs`oYiod(>Y_?$4{%M~6p;JFI#HsDohnt$ju;C+)cyw89aDn3H}y+J)bcPl*JfY&KJ z!GLd5c#;8cP`KTI?^AfH0dGv(_)-9U+ZUgSF(C{j?f2BW%_ae3^bT&vIeIH}Q zdrivg`&wgpyV@@s@eC6@*90#y!Tl!qE)%@P1V3Ve2Tkxk6FfofLyi5_^I=BZ&-D3A zP4)8M9gIK6_nF}BCiphSKM$Ps@!e&D?=!*md=<&h`RMs4BR-4iftSxP!Izuhg(i53 z30`M{Z!^Jnnc(|O@KzK2hzWke1n)M%`%Lh7m1i*OImrxX_HZq;s|2-=BR(8Iq4E+I zoOi1e0a>e?;gcDkK87bVT&O$-@kwKNJi~8dcml&$GCYal`3$!+{8om~Vt66LQyK1J zcm~7E8SY^CHij=}_=613Wq5$$g$(~O!%G;xpW#&uKgjSph973QpW#OtzK!8;FnkBY zPcVEJ!~cij4GjM)!}l@#U52+X{2vT&W%zpxZ)f=X3_rr~e=)q1;U6*l1jElTJjn1* z8Q#tCD8qXhJ_>U~|MW3@EW?x7Ji13Oj9)v$uVZ+|8ZAz?VqR!}@m9O(V7PkJMBZ4= za4quD%I7j%TfsHFkm2zfB>#0YT$4b%S;FuUtb7&2@xV|2r;g#H`cdSE8GaGNw=sM) z!*?)TJ*p({?qayUM$wH1hL2@@_Az`M!&?}RKdIdRX=V8MepHBdhSSq*`sWD4@u$Q4 zKb;K6pS14(oM3oTKPp6!;TJQ!o8eO!-plZ*4DVw&{^az)r)0pc@V~O?|HLyKe^R{v zlfZC$KPp5L!&4Y;XZQ?;&tmvYhNm+8Qif+R{4$0+7=Ag!mot18!*dya1;Yy&KAYig zhF{6>5{Bb3u>MaK!|^Cw|EG@O>Jc+}&(H8V{iTK2#_&{z?_hX3!*?-!F2frb-v76u zaep7f=dkRK@_!5Tq zG2Fp$Q95A%SqzV7xRc=t49{kG62q4=+|KYEhRU54*tIFCPD7`~a6Z)Lcj;q46H!tf&uuV;8C!?!a01jFxTc#z@uF}$1M_cOeg z;SVspkKx~AxL7-2|JxZJ&+zXvJb~dqV0aS4f5>nqWq2XOA7i+i;ky`K!tft6yo%wEGrW%BPcYoi@SiYz8^iyD;X4@q zB*S+xd^f`z7~a6}eGK2j@D_$QGQ5@Hdl}x&@SigL2*aOZcqhYu#_$sif12SzhVNr| zH^ZA4-plZ2hW9c28HS6p0sH?s!{ZtLEW;BR{v5-T82&uN?F?^W_$-FM!0=RtA7FR} z!w)jt!SG)&d^y8g8J^4VHij26{8tQjGyElnmoWT48D7QkUo*Up;V(1X&+tPG-^TEE zhVNkbD-7So@D7GIF#J`9?_>CH7~aD0*BIW)@c&|XJHwAK{0PH;%kWNyzs~Rz4F7M2 z2O0i5hIcdk_YCi4_#YVF$M8;ui}C^c|0BcW8Gel62@F5Z@Fa%+iQ#sJzsc}f4F5C3 zQyKmjhG#JRZwz-Z{Qoh0Im7?X@LYz!#qdIg2N~{Wc!=R83=cEBis4-huVeU0hWi=* zHp90u{2hkxV0bsfcQL$&;SCJ`C&TwK`~!x!Fua%HtqlK=;q44R#qc8xKh5w?hJVcP z6AVAg@F2tc7~akB2*Z0BevaXN4F81TLgnEpuXvu}@eIGf@C1en%fO8!hSS-A{;@OM z%J5kXw=q1G;c*PlVE7P*I~YEc;ma95jN!Qq*Z*H=Bx@nVhqLl-hL2!)3ByM+yo%u$ zF}#l9>Xj0yB0s~&u=3j&p1|-O3?IkvT?|iTcmu=7GkhPzCosH);S(9&%J4}HZ)bQC z!;dihVuoMXbg1cqO$5F@Ozga{>6Lx$HkWjZy}+yDMCaJYvm*%|Qv-JE^f#y5ZGY0g z^4^oU7uN1cx)HSX5?NN#KLee@=w{GPMn4C-h|w>Cu4nWwKsPe_SD-r>{W9n8zYf~T=--1bV)QZ4^^ATKbR(nx0=k3Ie+M0AbQrXC`at{dfKFlbd!U_+ z{s43lqfddZXY|LQ8yS5LbO)n91s!Izbt&4n541lNbPA(KfOax^H0UBmj{{xbPq&Pn z2)dEclR_&z7})`qrVP1 z%xEWQYsx_T*MUx9^!1>fj9v-4h|zhV>luA3=tf4b0^Pyr+d+pJT?E=XW1#)jpi>xq z2WTgwD?k@9x*Bvnqt}COWb|F2I~aWr=rE(}L0e}Iw0}S76h=P?+R5l2f-Yk8!=URK z{V3>0Mn4X^gV9fd4l}wDwDr<~_J0OCh0)ERos51CbP=Op1YOVQUx038^shj7F#2WC zVMcd=wq7>S{%fF982vhEC!>E4x`@%oK-V++P0)>u{tM_1M*kgjn9*U-*2@Rle+P65 zqu&GVWb_B1ix_iQ$Sm<7-;`8&?$_b4cf`*Yd{wbU+R5mZposg?*ScVbUkS6RRitc4?2a>4}x|w`iG#482vEl zdPYAAx{=Y3gYIDTlc2+lZUk+;dZ7KEflgs`GiWEHp95XQ=odlPGx`^x8yWp8&>f6^ z8FZM@9iXk(47C3m=oCi34%*4+--9k<^fA!&jD8bzBcuNUx`WYw2OVZ~7_@cHK>P22 zPGR(Wpq-5V0CW+fPl2vy^v9qZ8GR0P2ctg)9cHxkI<%iU(Ed=+DU2Qg+R5nApozV0&Sf;(Ee)B zDU7}Yw3E>lpop?d%`YzBNjJ^kSn9=p1t@8%jzaMl8qaOtAWb_X~7cu%_ z(DjUd6m%n_9|zsR=qEvk8QlolI)9-3pMg$cbTeotqn`s^#ON16*E9MTpc@(eE6^Q` zei?L_(H)?z3kKSM4Ri{lUkB}E^zT6zG5Q$jdPctqx{=X;0o}pqzk?1lIt<#naG?En zK&LSJJ_7e>p-V4`g+h#My~{2#OOTG^^Cq1bR(lzf$m`R?V!VqE&^@++CclO zL8oZ+g-tKZefH^mOVdX-(JY4ekL6#8K6V<{TSqwBisHl$r^pCwaf*O&h(M85M7$$J z+mq4gWA~18M7+4~ZU1@zxxG$LoM;K!5}TclDS_nR$bc7Ri^qw`yWkhAoy;%M&b?ou zo!=SSIc>8vqffJi&3|kf?u8&5^=l4zLhcsyt%YQ+9Vgnneaj+J_TFU?FZ!9>j$g>% zD(i`6x<~xJ|7r9wx_%8fX9RT!$B0B39u)M*2VVEo;+RudV5mnjuYHi3v^7O>vpY zUQ1u_A<<^vDgqPEQ`;9eZ-xw~_r?Y2x|`(snuuHm>|FK`V2QvcH@{ADdToJj^fw5) zdx?nrM#?_9d4HVPN#$OUzZW+@kKb&_w$$oB_VHdTcuZ~%*(NrVTqkc6k*;S%S+sXEs zfvC%xdDbR&o^)9QRv~uS@O1`L173StfXX>+mO!$5X5i#Y==aE^ruR{n>?hhKBELf) z!sz?Sxz<3J%^Dbjxtg>VnJxDM_wNtAqpBs^ey}d{izw@h#bEVJ=hMO zyRD+90rwsO-|4o*9_u5INWNRZHweBv6<=XXjLkP5eB=8T?zTte!ryj= z<~(eKd`@y*QQu{dWrmzr7dLy`X9nU>mi&bU-(jem1%BisXueorkI-LF))-N+bbMCR z$w?ENvf?!V;J8~fX*NHh+2s(Ki)h}$XRJc~>0)w^1M*BK3^Ha)>|%*c237<;kS@p$ zo!gd0l6NeN+(>0X*YrdW#G`K^j1kF9vX$drC?7OzoP2N?`VYa*-$fr!OWYB;33{=k zU!pxFu;rXKceb327Nh~!e2eB6R}nAxBJy9M-2=Sd0IxScjZS(U{!-^t2|lFLf8t&- z_`sIs`uY*(EZND;YJ6{^U&yqZ=IanqP=mfzp)Re<tBhC3*v`OQqwRdszT-nZq=68UHA92X}P50_CKSMTaGp#k% zBs16fC((jmgD=T<0`tIvaHdo&&o92tN(5Jz^cyhllCOa;N3U@U1*PF3u9fQ_=9xm!n_v$g3rO2+>W~ISRIn@706e`uvdvs*MP2ReaPBs z86;EiD9tU4oLd6=UJky$U_8hkS3q~qaSU_l2>cZ3QP&@py8`7R3|oS=AuAe{cH0p# z*scB2fOV+<*e;BbncZeWmKNOqGk#k!hxE3-$J(f8*R&r09rSdpGyU=9ND;xjX{ia1 zMI4jZ+(0&gUpMB`>5+~Id`8QKO&$B3cEqzkT^9Mu)yVO|N5kz`Z_pe=X2Qvi;(~*Qmei zosr+*m->qrU$p)PlVpF_#_DflVt;=peSysRkhy<++=J!qh7IcDBjxp96mZ}3Ir26v z42&Up?{P+cY?Rl%P|CX`mb~Esd3(_2=h^h-koOYU#58>0hEECE5G&6Rfp=^oK=VLU zVQ+(9Z_BbsF@Eo@TNZf^w(>oE<^7$@BJfuS{uGH$qL_i^mu{Q1UrL6J(t6$wpC)6G z+GP&$slJ%|q^^NxB z?)XL~?0CME@8`=Rew3GOAdYwfa$`-BYn{7eY$nZfn&Tvg?jHo=q-3mx79lbTcg2f4 z-B>qDAOqIDdBE{_gg=k&$v$DOa4Z@1iKaD#^x=vVcar?BQQ}SqemlTJug~l0yprM5 zIZo%>)E8RU>6}~a!rE@P2l`+W#K($X-LH|XREGA53L0%8~`+l8a;)pwRf1mfvzVE5tsHuj|CyUtD#h+jmT2W7Ai zSbII<#9Qt~9E){|^u7@LlAvu;^Chr*j}t!XfjF6~pgqZQ#PhT#*)vQOgyo*Z(j4Au z$^2*z?Mdckxa&n=8Tv+k?FHD$A!}k!yAAt{kvUCn@FF{IKpf>q{XHW@(_UcHvF^-oDkaM5`?ae@Yp(}9@<)~e> zk@+y%4xzk<>=tDvlT0X6Bil=qF|7|{{w8!pvHmNN34fit#{&H%BNptB>8FrwACb0A zd%idNRGd4*B7HZ-x%Y2lPC5wB zL0^ZG-cmA1w%1TD2pwR*6(L;_zgK{Twq|9*mNWG_6!T3ZpM?HVtg81hboR4-yb5hm z%(@=Gw7+PD9%v4bT_?L!0s=Jo1e!ObJ3X$ym1IYm_o;pS(ml$@%z|F&x(N5R`SMb~ z{b5hldj@6ndD9NvT3}D1%VFEf?lz!b_!Fv;`9o;WJE8er;x|Lcevo|~!CWKz%EB-D zn+ZK+dZ4S|49pSeipFb6i9I6-ee*H1z{UoT*>B{S**}dQ7*6{V+rW4&gY3vj(7cX> zz}EwPYhyM6{hZW%2s-IPziC~geaW|=*AB=@{msI&Fv;x;q;Dzj)7E7jlRg9S5a|}< z74ebHL01;&UH6gO&g${cOHGiuSNAgo&>hwDqks1AcP!?5JA=67%wZ82g?_k)!fv29 z(r0jtf3ZMZRYS7DXT>Gme3z6N^#$}tWraO1AkM!PKYgmGhAs+rlD$KBTe!W$CZ+BW zvs~Du=}p$f*i9RQy)$%CulldA6P5({8P!)0Y@7U37WBmPA%6I2z26T)SNb*i{0o~j zyU}fhY>j*v+0X>LHQ>2l^pXAS{!}z=zQ@wU^+7t_e2*2l4c|C?hu}LD-(gL=KaFoX zgz|@Q{}ApU!u>Nz1}7vx3Wsq$$YAhK+S0R|b1NMPm=!f({Ol?8#U+?PAHB z{s*P6KPdgqblit5MqA#Zj|XxJ`go9S(0o}A+a;N|fDh*70XyWIf-lMU3S=XjqPz$!{TQ;_ZDKy2kyd=C!fvNDKM39e@uc56A!eR%B>Z>K+P9GUPQI<*m$RJO zg-x$X9VEi%*~cIcjoc)BIQHv_&DTO-=Wj(naXls1DdV=?)(Jh2Km4P|{~vTp`E|(n zxqQ`}|J*WqyhY~*w1zk^w@BaTQV>%jM@TyVT9S3U4Rfjs@fPI?qd32D^}vtWEIq5D zmL@mit>9sciZ5YD@Owezo=HBxRU9}2JE?{5{snTbZ(*D|Fiwrorw2Z}0rwUvUAAMK z^jt2U&F|0U-hkN3KCEvc*$MTD)->d#9;3DS6|B36r9SK%wtKP*IoYI1yC>HTMJzqa zf9%6E(Z@Efa>!V3YCHM^pB_Z~^%KNeOKcOLu}^WFbBq)PA0q~P3ugw)(au}Quk0Br z3X*MQ zw&r)oH+R7ve?fi){TFeN0sN4E4{Wwh>2V-7Bb;(5QhxBEJ|vxs&Zqvahu#ht^yY@% zC}#Wzc#;iry}{r2>+Q-oQIK@^^nA*PQD5GS4CFNZkePf|2JDRDElZAdTr?>AV2r8%5hrl%qJW1=kxO<6)E`|GXD=L-J8hR`)|BC*__Uu$iBt zJn`rynNhv~b-Qs*{+8B~?~7EkAU&4*A1etbU3Xt5t&EM=W}c(KPSo+Vz? zcYR+(JY>!^ctzj^UT@YwJ*q=>W7ZS11A9@A{E}?%DpfC4Ywsjv?Qg?AJFrVDJ5QFK zr^;q%W&cO%)v`$84h^S#VAOW;AN4%YnQz&ef-i~4gz;Gs8o$%|)+QRm?#qXj%Q$4Z zO~$kD&5196f8p@*50;E5|I>MKpwa4Ra|vjs?bX2)4aVxP12 znGd1!(OFGH?@oSV$lZ=d+#>GiTi6qI_mUqQ5wKbPd1t+GO?}YwCpANx&O_(Hqasp) zvG0aWVxBZ_qCURlz**;zCNVWD(w-m=kZtXOox8BMY&jzeK)2cA9c`P1b?r#dmN-Y7 z5ADT?tR^qo#{X02=w`G#>m#(gbz}g3DlfP}L<-POpY0;-ZKmQ}GpX5)wn&#VVYBy& z_ER(L4S8be;l(EtEs>MiiGi*wt!-T!a8^R~=Wbb?V{fevX2%D1bbejZ4J|*s*oohF ze+fU1Uwv%W-0j#Of_}Pe!usOE0uw+ z!uv&}5`Amvumt{rF`@ZM@h#Sgn?pDo68n}#PTHmhQjWmq;x{^D)J7Y{wf?{&r$Yq% z{)ZP)e9`r^h;(_a5wHLDzVH*)h!rtZbeJvDc*l&s2CHp*_!-zJ+R^z#Z%sWI+d^vV z`^zGmzbl$j{&QKx=B7Lo)~4@TnjGNYw^!pETw{$iV9kndLS|{RH4;J_7RW2ME{inQ zTLKo$^U%m4Z31=nAa;=D(Wmfslz#}{t>ZI)gZ9rnggh8@1mAruSzL{IIiZ>2-M;M( z%q8ptZH~4_P%asJdKvfIQv)d|OYtuG11eK*$7(gqffP4*puY#LmhF2cJKFYQKaKTh zM6#HczGt#%`z>sU=01&6a1-*`*&;x5Gql$dk@k(TjXsUJmVHsC`+0HTWQ{Y@wZRG7 zit8Evw7?eDb`*2y7|n6gaR_n+A?KEf{=Dwz9TA&NbXs92@F$%o;d78r&lA1ZT_8FI z_AwMXvB72>xc0yva&X^SEXHEa=fSV7JqiCL62w?%!!csVQHgvi)0HufjzVsu|4PlZ`>DXH@F+| z$c(JEi^q$x6Q<&S%{LQg()&dl?XmWOcf;tol@^R!s0Q=lur)w>58_PTK0R)weTU;F zA^eNeuvhQe>WExUe!-UiEX|c{$T|dlq_c!#&|RAyk$0g}eO}C|>wz&%UFh?TXrKHe&A;wS2mWsd{=8)2C?~#Mn;a4NvT@1nYo_53AWf^s zJ(`bHUvJ}b=+=U7H`;yLe(b6jY^m)iH@>r`@(FDSzIoA{C+$UYmL zPqrY$#W%qIZgAgtcyYWannwD+0>8oI7!w+YKjU|J$uzrV#q^8XJ=5at?rHZvCkjMD z#k7`W_q11Wo;D(>d|E56uNZ#Ev=R8i#~0iP9#`6mrp04D851YQOh;Te`s(Yai?kKf zNpGYR(#OB1TQ1nq@AfSBGz99+3pYFVPX#R!il0r!^#drX_#7e40HiYx>Ho zv!;*7eJV?J7NC3r=!qyx`96vTX^cqU(l=sEXq?|V1)e*6)8fIeCAnnU&v7345Mqwt z19*0Y<_PqRIo_FUzdBHYIq08==QMx`JMsyzOR_~3Z*^L74==XUxWa~|y%xZ4!iLFa z^T89(P(*^e9g!42o~_sm9`IE&{L3P7%1@ny&vV0e$=?LGJEdQmj+m6@NHWRt1oo2T zbKu*^eLpiWd z?0Vo^O-qn##y+ZCpCjaV$R@)yPv%(Ll940RVvUQN*T##TdVRvljwp6GnLRAv!`e?V z4AB(t_*5)017iapm`AY=#W#8!aZ<$*@uWxe+mrp{W1fqiIu)A##;FOx!lo^M?mZ=J z6OM}WOCJ$;Tb_uH^!HfKJ0E!u`(k^%W&58yzSAl`x(BZ|TaNCZEVeg1Ou73>YwedH zKIq75+uIQrh+4&3{|3;foNasShfBJl4s^=Ww!O~L+Wosk!9i;xbTXkQbOGlTXj7Mk z+9r9VERX>?#Seo!kdGZDK6F2%b9G5=`px~~p|z32y?zYEu3jo4s8Ozenc35-#d zqc!@kk(rJv(TaDX$CE9`#bsrZ9YdaZGw;EE6FkV~-q&D_R(7xuBA z@m;{yqTbJ~n(rce8-qu6J-> zu2ZP9ALYZK6Q$o855JZ88NWrb=nEfy)^COOJK8e6n2XRg*4DLt%G+Rk|A9G6_vAPu zca)5CCp?eRcKHNH`OJ&6%JKXvaxm6rS`SIjMn6gI>1!eN?_soUZ0nWt*sIg{s&P*y z9|t=K?ah+11mVL-mUkfw$?@)ZNBPO5tn$0ib{Mumc0@iY9ya8-+x|pma999?wms7( zw(qfKm+LW(TyL>=&}~Kc<+QdIK~7pbXdUf_oV1pH0z3Gc)a8_BKlDnmx{T2=zkZ14 zD%$IB?`zDXy_x9Q6OI-%B4&TZdV62PN=M{X8n-ZV7l`Q{Z^I`-H~W#N3}Q|lMD7IV zXU{a?SeN zYqH>Pw7etv`KPfSg~oiRNv?(PVYG)KKjnsRiH`C2SkGraV*d{IjN;RW5qI_Ms}%)z z(0HH@$YiNTi%$^V0L#$9H$%bE+Zf_H*9@k9(27K|FM9 z>-ntX-uLf5ZZ8Qga^KOgNMP-t{pS|!WBh%aA1)SRfxXUs-hG$-yc52Aoz=P><8@5m zyIqg=Dc{y=O*|^xus^JeXFtInaLlfr=slu|p3Oj>Edm)LBAWdO*#gN=@!zaU*ag<* zOz?OYJc6U*SN4gd?R_XuelTeDFSf&u8^IfG|1leV@Ir3ucaS@V+_csR$WHUoeMe|f zuw>7oWXMmvNq#rvr@n~Z?;a1qo{*E=?ne7UI4;@cl3hcqF=l66v?rW2Xiw;0CJxNSJ;G^Ec=i)V zWP{uj;`|YKjl525o{j5Z5AyGzFQ@CjYS%My9fCh=4-X6M#G3mizDv-TS6;>b66@3i z_~^OE3!7*SZAVNsini*L)FpSdpt(g1kk;O5`z+ z!=P(FU60bPMK0uk{-w?dN3H{Qx;6`I^dZO|M0_=4q_c@~9JGewdCjBF^Er>W;{83P zx65gQ6*QNdp(V|`eTd2T~YIvf6r zVumKHdnYMRf*2)!EPNg8i}o|Lhnf6c$9}nYIil@d-orSqf`1^tL9qqxsZNfW{Orew zo&JH?>gisLhnMzI6MF=nc_kgb3|l2VhR)C$EjlS)-ZI9~hS=hmrR4Bp@}q9VezZRM z$6>F9F`;;g)~PPc!~Pf)_C|gy1YbaQtovBGufrak_SjFLecJcs<2*}HUK;!8aWrP2 zyKLhFMX%$;beUD|t)nxBZ=@K^3H=kl#1oDtxBthB-2TTGdEw_yW3L$gE9RihwteE- z8GYl?k1X(U;u{{8*z`{JMFDISJChNYzJ>gVz?qp7vE~dn-T}Zq`mMVyO~m`7z1T++ zFWPUugzq857~q=zI&^Mo`KD?%z*zvd6JvTp4@J0>pF_^f53O^=**AMH;OZ8 z{wMqA1R5dpaqtMkwjKVg%=WK~`Th4B<^+mx|0wSFW9@U`-~7j3Q+0?>);v4|oPqOa zV8NHNB5z~8*#j9;FeYzfk4mwmzTXPLk4NE~qwvxGrPwp?&x&;YG7DoJ*VBYpcVN#v zM8>qFua78(hkV`0=ZXeP;6HG_7s7f(`yP50^(1f_U+a+eQ@YKOz0p2-Jo-yz$>-}n z$^lo)~sWxeppo%9jYl_YUMs9LSZ>JS)Pu1`*r);gcUl zoWC1wgl+jvCt-7MZ%st559hNOPkNr4k0p)E)_Bo$2;+PRWoUoU4mpB*aW+=3jo%jR zH%}rDV#OYXWa~oygX)DbFZ4XfRPnvITjP ztt?Nn1$mOq=mW_@wvy~m4J-kVx1nAEk#5ccr#W&4&(xDIqIf52o$ySMVx4qRaAu?> zatLQk@t2B%L-c$$-c<=xtOGg1m`i6cr-bNxcuC3pjL?QGTw9J#FBBjCV-D(~EgGLN z@-@jKP3FwbDV-9o&7t7|Yb|mN@7i8WhF@<#|1SPa(3&S@KhV#jF`u1V;bG&RU1Xxu zJn#>qPdlNz=>q#r%(}Z3+KcOUk8=W9e=*g6 z0?+u6?ZZdX{GvHc`|%fHgR~c?IYaZ4<}mHcX@1Hw;Qf?p-wIzTWk6f~GQhWzKebWY zN3$Yc@a=;C)N=vTRNK@p`Dn=#_jjsx$=}L$!H3$NxK_0bo)1vnqmIZopew8)E%N+p zdiJ36FUt&y$)+~b^P{KpojBjh#`_aX@%}^(-k-Rxsr&L}D4!k)nWKy>~Y(pn- zcs%)mXn_;Y>rp%|>)ewSc}vxC+^^NS78GPyDs>-~&5Jge3fuxYu#sey=!BvDF^Llb3)e*{;Pw&rc;aZ$p2!LuT5u>w9$R zhp;z43HdC@B9pLp3p@s%!Y%?o!tWj-jwT~UTY_AJ8_xhP zp;%SlVe&0{g93*XF$)QU{4s?ioCbu zD#wLl=tx`tZ|}3%EZb9(9Bnh>1ii;I!in5>N|I-{F&-K60!qx^B?fwbID;@Vegq6K_!nFYGz2b%rS-tuaUmE#A|c{}lZa{m}Y z-buhqRG%!_mOvuesMKd%GwsufKedDBV&wk*AmUNNHY2~(0KZ1`TS^vs9*E1344Y~E z-hd3Fz}x=4=sc=(3}xYC+8%*Ex}MHz!}~4Rms{E%0!{n#2le@+_R3kiqD;1$6b zwcj6|N8|hGKeaVdh-(6Cas9APH>3upfZv-atF37%^1gmuf^r-1eGX;FMv}0H(e|`S zJ#O@k_ONe#0RIJ>kDyFG#)9tOjNdSHN7pot z_FBJ18GS$Y8m{SiAAL{OLG}NNSO(AQ9Ktp760%)-9!OvvyB-+%2WmfATos`HI^kOp zTer|Wpfh87c9YJ8>AfsEJANB=V#zG9KcapCFA7UQ#jr!GsawIGD^8?6E*A$b~Lk@awfoOWq zssmpAnUKzxqb$wiSmUDG-x8D=6ifUwT5v6} z62+h10ix$MC{IuNYQVVN3i;eB4j{Yw#pjIKZt%KI@uD*W>JL3<_n+!|2m2-d0(-2l z>-@3a6aR^82W*030cjIh`?rBNy@N(P@!t0&s!#U3L}91#I~{qH3!9$9JBf&A5rfn7 zCG-r{WY~AMEkk=Qs>>QELM%n^T@nw6ZJB(=&0FQ@)8E++KQgk3&JFCyJL8>g#DLhp zxNMm;rrA}Z59@SZ28|`we|nCc@-+_3@pm!)4z%M1mIc0VLxwo;?RpISXiWi6Yq39% zcv-%SGaT@GG6tVNfe*b)96|rr!;jnop66}Wz$D0#gfI1zZ1dN6Z;PJ4rFD&-M05UN@$M|y;dr{g1aV)Y zIFNiHdVuDLqYU$MtT-?OYpVOaYg=5L_(t*hA={op&IQj>-x;EO2y`R_VzKtI0WZ$F z<@!EJ6gW}0Xd<2g#hU6sT^s6VpO4%2Q&ku5G!>-ib%SFA*`u_&uS`W}yOP9@k37$cMjoKCe8H~Swnkb;L_&aoI$FpyAO=IQ6xKLi*O5=j@ z2|c8Z4UI_(#$%cqj~Y3yi9MDCoKHaC{qZK|2G&-bKWWcfSyI^Z;e(zjJSLwh+=D&f zD^?NNQ|;)BzGck}qs>>UMIXKI|MB+WO?^1$OR+cP(Yw_2JY#sPXgj?O`NtdZ?SYM< z+>hSJ@68UG$00kr34Q7twyY_-c~}$IhrlyXZIvN793b>)~%YNj@5+`MSVjvO0}`;2(eMt&@a=aq==!gGs%1x@zm z(Z+KJ*;+f^IXAPl2ApB2zRI$}k)Jd6m=84GE}D<0qF;LK$$!zD*2mu6i}yRBd*os# z*^wi(LiUtVqAi#DGFqd_*>1Bd=>hUUHI}8+ZqKU~X)|yWKQ5 ztauN_Y;L>)J6CgKhhTd4P+c}Ret9-}klyVGX=5VWNyZ$+Ub|-x{vH6e*E=;5uPjh`%Lc)wLlKzxCRWez6;t|k8E4l*JJNR4}M3|ljOWu zrLIY@C(x!7Hb?8wpKanG+3bt3x3A)_PQk{x&60n}A%B6j;353dd(>pl)W#A#j}E(( z@xmh9qj%s)&)WrJGhF}Id(p?<1O6ed^?G!+NA<{mP@k@myeG(YT`!~a*2`Qf%ZzW{ z4}Ndr`UUj!0(eq6@@F3MYw%~Au(nMXc=i^&lc)~-LHpV0fi;llwojr5DQ;*4kKf>4 z19<#S@!;|q+a9XgruVYxUJriBf4AGT=i4phyD{$iJC6L>`@~#Flm6^IolDR&a&Fk2 zA3loC>;DD0DR=IH4i5mY1x|XF&*aK?Tn_Jhrzbjz%2K&x_)9AHF=XInNEUhy7WTWt z>bA(|V3UzA(cgO!GqqUQgLOmCn{=XWDo^^OcLPBj9;}EFvfyK8z%S_QJoegm+Mz@3 zod@kb0}IxK6qJGgYoq(LucP(Ug1^6#3_t0F|H9t1CmHjz2E1#qc3Tlc#NwTWbI|^} z{eIHY^9tIexlQfTIA7RwcptsbYJty@ZNrCCoEw}ZaBhY7QYPUYMj9ho-qv59?B>Fz zUp3iq-bb+{JuCe&_)(lV;oJ20IV_0n>F)wrx845M{VixBj)OZ?R`Rjg8^rr ze*-Q?;Q9DC(R1!!-+fW^Z9e`F94W_tWg-n{f^*a1M&Y$pSB(Cn6@K^F%sJY`7!*|1o#w@ljUy{y#Gl zl8A^(Lc(InOt83hyDG}4m`UQ=`csS4wJnpxDzz&DZcy_i;L^sn45GB!D-&>=>9yrr z&{EqnfUVke5nQU>m`SKo(?u3FgJOQ~&v~9FnT$cbUVp!P|CrbF%z4iGJ>Tto&-Z-K zNzN53txuwG2iY~ViG9Qt_Cb@^HND|n7kNYc;MQP8$5!_C!nE;Pu&V1d+R0Kk_WQ)| zkr@H%Q@s&ye=3ihj>7kF@)Klq)z%>-7(+p6^>2U zfNP3pqBtg%=a|$4a7c9F`>XrsFig;_tw2wjK>L;a9${`K@P7?Y#rcrF>f4j#+tW#3 zy6iV}Y@V`nnk9?wm_Wbo<3Dg*V&eanIEwc7F8FB*8MniqPtJwm-xx@5;!K$4Q+wh~ z;A5`F*nJChs+s2j_gxd+vxJIiq_c#IX=KDpc<;o14E{zPXnohjSpL>h_dKE9H?J9b zo)DTII8V5D!J}43yp^+rWvq2`o7}maN?QklwI6~jejAcIKZ4iUv2m90 zjKBHkCcmFLg1z(b&%SDLR%2o_h;y0c>2EN`BmS{)=^24o{{C}Jz8u(!-}N_|&B>$i zb7~29b$-;D-ro}LU3rW%ebw>K^t(@Vrr%TNOux6$nSS5tq}@6ubL*E}3CJ+`#J<%q7jz(G6YkKB!nzGqQM;%;JE^^`bcvIjb2?!I+I>J@nZ zHt6G?<4wMn_0+1+=p*i7{P*8?D)i0U_a7EY-CI+Vy8phi)V(XpQ{Q5o z(&NP&S8fbH>ZMX7cTOx$H#wgWc~L3 z+{J;^*T430={cl z8!a*DnsIn_1Rf?`6Fzcq_>JJrE73Job{l=NXGEcgHu}cCiairu&-@I`jXjs>(uCFy zwhrWkcy%A}Rlf~=GPCy|ID4AqypbzU2hV+K&NPls(XU%+E6KP5l*=9F(scZ^`n=An z$4brG_{Zz>j-F?8-hroNn)(+<_8jkwOn~Fa`0Di2^gmo`rs~^qvHE;nERZLVJ>RO* z_sk6}(=z~%x)&I$Y}_j+{;vPaD0h4N$b{pS$&jApJezX`utfK>vd;VV0luxJ&)LIb z_Uy#~tO|I?5FDu;nJ8yoG?ol!i{cF<6D9i3m>m6Y9+@!we*!pO%<~>#+19W>{>1_4 z0(>D&&!_0SV5j$&=|f?k`fQ%c^d6or{oS_r#Gg>)W>{I zjROahwDb3P6Ymjc|3u`Ct&g__P0Ieyc>m#h_CN6l?f22(A$tKa&Uvn-EoY3`>&lg? z^k(|x(~e}l@IhsbX}K%n)b9+yA10rF zc22lbQ*WZ;p$@cMg^xbIi*o|dY#ZmovZP-KOzoTX7(z6a-|`dWeyBy-Y6n^q4$)XZ^^N00NX3!6DvJr5!cJ>YP?(Wt&I8AeNJO&biA$7DTMcpilz_i| zr%j!$;+=SX>^btD^Xd~U>ZmhrVHQYNSXhirN5Gwj$*1pc_+?GN+Wl=ku|VQ?etI~N z__hC@GzsCn@KreB;_ZJ9%==W%T)ax1tNeL~@3k{7*=;Xn{&g;(1m4%p{MQouOnOfY z-7d}(F8C{J@B@k!-@F4}4b^L&pyS!khfUmHWaOGDW8J1zaXGGc?)5R%N-=KrS8&en=)(fD4u%Fb@WNcxr<9KIf|s#x{;DiBI(8h@SA=q@M8C z6~Nl^;6vQ+F+ItT?RBmA=KO~GJOYinu)kg@8N#_6WXM?h7(baaf_%FhKg+9*tIuDB zy(`mQn$X$QJ%ji-z(7nzkq|%jwNk5=dL#_b?eBqvo}W_nRfKqhLVA~ zK9YQyD@ofJ8c6$~(wdcTFfB~lGvMQM;K^Ea2EVV_k!D$P4E@?@66&w|X0Rt#l3)E8 z!}GO+&DzY7)Ym?UKch(Bz!){Y4CDK;`o{P+c;gcuhLnf8ZJu_M_#t_8UfYkWsXTiu zJ|MeKakf0ncdbR{A3ZoP7vH1(CgvsVY*G37AF0pZhP^3yg}e9m66GJdjPnMJDMSB{ z)7&r*$NKfc!#gRLguXhvg99-76W^1kk=8tz_Iq1qZ2FjQdToBd*|L(x)r;`|fPeSwAAEpwZx3XMvk_+w9r}0G zL$Un)dt>=$YfWN(u&Q?><4@ig>sv>=T65ly{;s@h`5)JOQoneJ;1`G1XQ?ko^Pf5N zX+2F|@hh9BIgmJCd5Yp8bdpCt0EKY>9%-T>(dI>z5p7%j5WdkCl?~yWj~+ z_i=Qc-;n=M@Kk!vuXvxVcXXV`c(3*FcQN%}{m*`j)1MoD`!ACcb3-gK0;UVg<$K_fc1e3?utlr`R(Y;t7u)#$F8TN@qg-bz$Uf zm^EyK?@g4?B3HUAnN#>(oVrwR?xRE3DV;u#v+I*z+OftcAE&&*PbUW z7IJ^}G4x+D(ZX?YY})1z2yZIW;t#uf@LdG=wop#GLoVo@mp0MFFTf+ob@BBeeNQ6S zZ&qwmbn`-fd<^v<*Ox?qi*U=A>z^aNTY7whYge4bT*bj9#W$S7H{})o_yc|PWwrr! zWhaP1MJoQ{;!<5E_1d#qvu)hS)OBFbouf@-qR2tMzk=B|EfcFG*_1xJWsCu zbMbU=erC8NCZDY(k@z7NXS4K^^lXyg8Tgzmk>r*w6F-+{OJeavrr`|+LXwfC=WZyn#5 zchTO|qVfIt9ojp>%m36c?Y&A_R}b3v{EaVaZ^JvZcYv4w;bGeQ!$5n3_K0KPH@o2_ zE$~T$9iSQBAzfO$3c2%zk3-jU`6hnVR46OpyV4VVyPEj?anvQ=_YCoLBe7}LH&^^= zHhtQSOccFe%e#1?bVYsB{AbADh>v@2EB@EC+q2a~FCkrWN^6#++QpXzn`}oQ99tJL z=IF=xu6+l!`)l4^IIc_8(g%F!j}#sFeR_p8m%rB3x-#}OaUf`WBjb{sx*A?oFL}fI zAVB-wj6poIArnoM5u@#D)*0djT4yLmU3)2O>9gbq8tjn1(ZqlGu_8yiWRKd9HG(Sx zD$PDw?J+r#d41Z4)=i=B{YU<@B6pVp3R8Jo@m!*gfe0gc(1Rjdy-6wD=M zktYS~X7sYX3*2?H&P3?jq11^C-V)@ukb2^je-`-X(4plMmIY=8zpV#E$KHFIcgZjH zUoxVf@x`s|3Z$=AzM}qJsWjU9DNoI3y%USpI3^khnqzhDEEF?|kl{`M)`zWV zti_a8f}Czd{?sG4BgpbliOJ83QI_(OU8fL3yQDIZ(mtH{pXHOj4dqZ*&ds3RxwY)! zfvZ}NII=DA-c;+_*@D`WF4)rzdwPT~zgVls6;@;kE6MMJ28Hq8*|Wx9cWy&qb76mWkl*i*^xiBm z{yS+JOB;K9+DFmaDF>Wx2ez`!Rk0qEO>l7C`sn>z;dLsL!~f7PQ_s6>QyNzjXUsLO zU-7@NoU7*y#t0KU#WS=Y>+VkpD4+gCW8-gzO{_R_X)g}u2~E23RmjDTiYjZpHqE06#TukiWoxlHyh-P z545%gxVZCwU+PeF8{za~e62ja`bYe_^>B#N)^N3%IZ{I;|t)5%YP9=eVuH)R)3-G8`{1CFO zilNGx#Di|UV?F<8D~1>CZeuJt#<83GLE0(Py?oFHRgdjxTL|CaQT3_zTaHP+F?mEH z$b9J@jR5ndcs}U7t819E2sSp!xUbSr=JCiYda!q_8o}5MV^a*TL(-q;o7QKt9ekGW z*@p*xV4#zxYZTu;#PaPADQ)@C^}=CFyJ_gYey!55=M?h%4=C;Op?3p} zQ`!aaZ^o+gYHGJaX{QgpFJQFNjvs1&+>f+c>CyZ&20tF*iKL6iYwneP&PF#i`u`54~_vsrFvh;_P2} zF*H3ZG_E%bKZ_ma^6*>eQ;hwsV3>6-=PVl8b812s)_XpHt;o81U=S3)L5GrGK@3@^ zIg&rYaQQbdXUebk8jx?wuXdYAf34Q-Z#h1Xb)iFgohtT#i5n+-yXas0U$K#9?NRi1 z*f#M!Xrxaed=EN-zw-EP2!3j_CN!ZpLtFkB&-2C@W_&^PU|XL3uujG$dwR~wad;eK z3u|ny9G;Uy4sW21f$xk(-__3CmBbX{zLgC8KJLlMDD7NbOZ-3D$-4T&oE-XsVeb9> zYE$L61}l5R=#u`JlcUVqk7@6^xG(4u0pzQ2R$M>_5E-NW?% zZQxft7PaU1F9v@41RC8-9jENCr6mI2Qja07OsPLlb}OcxU_k2 z9r*6SRrsR1bSH&BkHjWeJ`cDaOCKB$u5G|ou#|88Kph?)JNp=WC$JsJThyMjYp}f= zy!IT%UHLZSw!GQfS16v7Ovv9a8oIA6UbTy}6a#t*dq9H!HNa_p!x4#VxxZI)?VwLT z1a3SGZphx+@7Y_k;KgU?pY%T;FD~N$T69jG---Z}cta!ndVW*c>Dw`f3js8!%`cw~Z@NsAUn}chTZG4~i?1i>(8T#fl zH%6I{W1Y{krfv>J+iC~*MxIw2XEW}VgL?r_EA0f*u)F(x{+-f}B&~gLt@JCUvBqf& z4yOHrG}$wjZ7fL)*xcdS>q!@^I^hxXe>vFKb)?7BT5q{)Ex~7v(rQn&eU9HAV?T04 zw5fY=-{(K{yvqQ(|1xE|L(!&{gX3Ib>-4^#uR8hOJvct$Tl_TYY#vNo zsmD56HklNw-a8W@n@g|i&xyu zQ#gm;_R>3hU3|Ng|AqAk*A46bQ%T>u;QK???P2(5(`Cf0Vc*uCPi+Y%c5ezLq!%p+ zvVO4k9PB#xxptiaJ_4=^|Fb8u7V_e%N6_=*>=Ej`{ztwTSeETMCF<;l-Jzy_U3}yI ziQpTv9w$ah2lDlC`E=)qgB0(6YdUAmStWXi!&?jqZ{}?D)ri(v3%VdM-yX1bT=_Add$=s8y7de@ziJpo{^*c zLgq5Qzd2UEy<^2kbe4p6Bh+6{*~^(1`S7bRYLk7wf%6-|B0GlcPgBdyvGMl(rAItY zJv@VtuarL#aLBycf2__h_xF@U*)LZh7pOYp!0RuHa75E1@8`r0$o{r3QF-k zeT=^RqQq>@U{7f_!LGaE>&BFI9rjpa%jJjMw{x)>K@1b}&H2;Lvd4DpG`!ysLN`6A z>`qf&c4v(l(c6sP-TYuIzp%X|(GU)7mM?>0eoR?Rcb}w6s<8uL$BN^75ts;Fj>Gm< z-9TC}l|!FzI>h9!4x7A#okeTre*oK87Bxht?qFQtO7`XcH9FfgpE2do&z0wJ=EUh~ zh%&>+D)0P%^iSoygK)>rXY8N-YqPE{Vb3AVrR>Atf$(lN@7>eBwWYo1$2)7kwP|Pf zwCql6WYnWy0D4u_&Vb=br=mP{auz#8#Tltfmzw-{ z8D|{4&S2-s)xmcdAATwMP4xX*_)2_sQ(uyA>-ev4NxmsQcFdTrDC@Uc`eEop%P2$p zq29mIew`WL8%HLpAM0sfZELNf^dxH=`S|zHH=}hM_z1mqtW`ex`DgMy$XNfA-x|_h z2T!s=<~w^r;w1W=0}rHAH2d(F8@ z*ZQBls_Wr5i7ijN{h@N=G`sh`dbTR;A)$nLdG@CAl<+Pm+s|R8UlLyzKR@D>Q};gd z+}ByB!%zENetze_|9GePVHQ67$FKi+r}+Dw&;4zu^pa`RA)TcE0%D)jem7&I&eaXc z6BCi-Nr_dQ(>og5zWix?84zHd8DQ-kM|NaeOum0IGLvzvrhI%V{&YV7C4CGtybNyQMU-vNU#t{HE@Pr^vPxqTg5J7x72tYy0U+BWC3V zz(n7u=bq>B@d#dim-6o3RFcR{8h3WK#+fes%+_S4cOQ5*{yP=?&f!wXd--c zB7C&GxAtJxp=0pn!G|M~6dy$w<*cMr>hjTCS8T6juXt&eaW1ZENHrz##d|oG7cX6m z9B+lc7-H;P3J==$2<^giy4Ul)yd>4ViT{W5|1q8)V(h@h03!p8nm%UsZXm9_?0v^E z=39V4jr0w8taAW%Sn3dc9LId`rrw#zX~8khnY=dEFJad5#WFe!KNap=bs+fmQvaI6 zC|iiTv6uR1`t#w#K1jQQ=g3LOYs zlpj%WW@9RX{3{Q~_9|Yq^ztk`+93DDH--1dsU7AsTQ)lNDm3Sm*7JT~$|>c3jIx7L z($%vaCV%^1k$u39*nF1m*h5`=7<@?cBi(T}_58IF9+z#1W_P07ofymO9GU1cdkO1H z&NYf&>vucYpuG$*`~SJn=PoQ&UP^3C^}d=Pojywc9E_kG&SG1Gji3& zolS>H9ZUAoYB*Xvtrve!ctRy?Pp|hU_+$A%&AqOwrY4U%d zzmnxyp28Kw7_z{=2ibjHfh_-tWI5j?%kN_xVPyHm$npmGn(<`$R%H2p*u}Q$u2xT$ z=R&3FF8U&Q{sQInO*U@n-1=55(=*CT|8y4eXN>)){Crt{CVejfzaJ*;C*+eHwzL5K zSMg1>|3y8K)1T#;gGVXP2FY^aKKaBiF624G=Hq?};_~}8cKHa~I>GzXXu||9yNhwG z`6ThCd^@)MJ(cILJjDlfF38`1wfEn$zb4sTg1>-UWx_?MtJ_xwdHe+BOW zQ{ADyZnAwDoBkYWE#S2F;ie&b`=bTp{!qcV zZ}7$~{{K$n{z$>NC%%hu*S?E!uPqq&gZmh_^_8tZMf6#|c&+p zbNeV)hyz=_G5EF!tv!oz;7a9@&I}HGg?AqZ3jG|Wd-dGJvlCy|fis=f_rTv%9(w;& zGxD!#qxKRj>>iTtp)%m7eEyE`>N||*8fa2+Jak5Pvi|SmuBoAInsjB17%$jsEX`#C zv{RLCL%uxMPh3XYZnJGy+O}^iXnUk>yE0wQb1iM}#xAI~OZ4BfZ8l*qiyw)6K<30) zqwIy}G{J+L$REdsl=>t3AiTJ#+x3lBp54l$F)L5INhFo0@J=u5XSC`5m;U72K)v&= zWrC;6OEi|T=oMN|XwTjtgLSrmYkZf^=S-n7p{`n<_?Y(229`SKr*%^R89$BoD@;X) z&Wri;?a#Gva~5Z^Cv!iN{0ZWDwD$ZEWvRL++pV+m=qHbNSMB7622`irT1#2l{R7 zM;nFpe;66!`s`GtPoRwUV!ub8ZOjw6x`b;D5|8rVrOO|uT8LrZLJV`?U#f@L;fsi4 zZtb}jqFZ6xu{vO6=u30+#785{3Bgx)=_H*ubnw;#+KGTI+!|iRAZlmPSH&I3a#0> zJ0%QWEGEsVb;~#N-Wm)<9q_gpJ7+s*LuyBz+Skg{Ig&n+&b;*|iDxLiuAMaWIoo!e z_ttjG28na?5x#vyWl!(ZSrX?2%95_K@sD|BNn=cIS>9WN!Kky6vL{paWRt&?Ga@bg zuf65WKF+@87cVvIoU=`S7V;_kVYlz?{CCc0Ox?jm>&jp>J|mXr29CUZr5w^)-rO&x zd#vJDl71z9xQgdhJWJ0(FJ?U&M9(Nam-mD4Z~i3DgL%&2$@+AxnRyX=z3&nW#Y@3*2hf#o<@-kBBSg4r$^khP8fEbA7ZK-Xi<7InU%5z8OfF9>K~) zzbLpIP5NB&m!6)|*&V}rAzpe$%CKIDm!8Q}@c4Ktc(vi%m{gqlvgksxfwwjXqJ?(w zUy4t8{SY79sQ=!W^#AAfzY7!n|B3y731fEs@gB1OFXaDt%PSw$|Bb=KIOrhCPx02Y zuOL4`#S;$0gMg3Dj{!TkTv+lg=irR%5J*u1U5@zXSaCDp-H zJm|LH#@ZuZx{!P&saxO;an8w@DV*KuFSR~M6X9FK(O_U(|4f|+Y9Ad)g;lQfdg>@m z-K6&$8&c+`k*O6nJw|$Y>YMicTHXUG8*5}^$>t__j)6D$cPGF)@i9o=#sv=(D-RV;8I!>Ox1y>f=QNjbvX3tz5wsS?b=1)HaHy# zeWvf&))Q0sA52qBjv)9hoHpQFI7AFWy@T7ei@Bb#X9CdY)2szEd|$u;C3B&ZE>3QOt_k|;J0u) z(o!E4E>FQP>?H0WtnI;1Vio1U^R?Kir_`LDDy=y%6(--5nlpGmC>6n08UWv?)SSux zgHsV;6#%!V)O?)(V^YHHa1HIZ1fr42gL^y&f{S7L<@+G*um6nE$JH|XU%2hw!yK~z zgdya0lr1BDTP_1 z<$zI`c;>>n>(EJLBk!XBvZv~suOs;T5fib?YaOV43F=|3;NCSo4thF`SSs-wKb~@K z9GN2a0O#kN0=fMJ_mk{?(OJ6N%I(VZh0kjpR@srgsWcT}9~ghajx4kwzo%wm zIBygDlCiUv;jfKs-n)qO_SsW^ES)y^?Y1orPvrF8c+#BpDaO;Z@@O}m=O_7Ja_FKh zBltPN65?Ep=unwYkZzpCTNV?SzllBKQudtNgQXqqzs5eu`{lv1j(&7bgPe|&Czx5h zCB*NBV6fw|V5p<*w`1~wr_mdp9m8GGvBc&4Z`m><-@0W?zAjl6oyb1+BHr7B6FXYi zmu~-)$sa=6?BF3CHGxoX5*Z%cM$GHKkmrRl`J1R?Ht#Ln)X_~H;p(XNz8CS{&OZ0# z)t|U_0{{1$eR^~@d*MB+_rJD1m#W%i88&*r%@W)dy0 zQs=AGnW>IG&i_Tcx3H()9;|T7eF#~DF0zRK?ISDlvw8Lh$MrUso|kVet>C=;xM(DH z*0t@to14#w=3=9+b#5+?h82H~xv5}WW9eH6xK)NKI>v`W9Tn(Xd(g=aF`Ad(yWD|PH zfhO<3TaIlFr0N!#Xxk=yB_E4L+aBZD#dmmXTbGH74_SQxo~g9(VbpUN?M`Oi;LXSM zhf>a}Kw>n026dAI(fZKn4hKFP{;0|Ydc*Kb`=2p_zxi5tU%00}+750;`bVVdR-vo) z1Z+Ez7we;KF9xD&FVf3GPS9iBJx{9tHe$4&gsxbWh2|N6n=rQwf#Y46KC%P*Y3y*3ASIH7|qerG=R z;k`*{CJRk0q5d5;i7YQ9qo-sDhH%O06K6y__aT{HVRzZ z9o)ZzAm|;tf}_B*>LGY0n1zAW6yVgx`%S#x;K5Ae%mA0efmaaNy#VaC^K(L_9g$FZ zN4JHWIja#^{0(@$WMQ@+FdJ!MHoXXDQT_{F-vh6;@0UeajadAy>1zYWYr%2hb_AT3 zd~OHdr7QTjZqQZ3;CCB%FC3pD{06r_2tL<>%ZGvU!t)5Yd=q#te7_NVmkx0Q_}&hl z3%BFa3&8I--hCVwZr6g#!t)YvTsU7JD(Mie&jPT!iO>i$Sj(O`7n0YZ0EefoGDd!i^qq zg|&6ZzHmhN5hxLEfGeJyaQ7a@rC)t+-!j$8Qo~w_a)A<_$k#&Is(#H1RSluP4a8X0 zIY{BSU^9T{9&TG3tcUYUh4UV*EaJTqIynCHSa-{}KKHxQ2es~QE6eU2&wbxocgqeYIsQ8OW->S)yYZ=>%*MAE zey+1yeBn2<&@)#Ua7bmd$Y*7_GXhPiDPHF z;>0&5-xBL90nV+glVil;)LJ*h|G+52TATIhndUH9YvM{|;rF_^GZI)=-N^>nsG%ktRQv z`)hQM&Dpl@ie8Irn;V=iHZKOXrT{ z49l2`j$KuXw}q{SKD`be?8d$&dx!2v*VxZi=vrH~1?yAIH<^_B#2OYK zG1if*T>rSE=*xmd<(%cN?A<_rlEm?vN`H(~zIiPD8B2edo2SOoAG2`mon||H5xvr& zN6xJ>9oJeta(p^UJ@Ns3{U~C1zfD}O_>J}Gi~+YVz{LSBf|uYX_>_6D5uDm~_s{$> zILw}u_)6ZPZ2Ts-Y~dL8fD7_T(>OZu8T}n)lEiqaIK_?sC0o@sq)p)e9G;7BXWwU8 zAm#AxEbQ1+rZ7pDCx`GtIAV0y5qve>ijF= zFM0Uec+Ocx*V=MJNF#;m;+-D7U8YzxF^!)7L*R%|wjdH9%yJpXfilx)nS zR`%cI-`Ym`!u>aAAHJ>fBlPpC4fQc>>Yi0w@=MQxkMbkc*@)Tr?*-uL^4HY3D2!7=9fW%)g2i5ubfb2np9-O5wk|KWVA-;e&QE%pDEvt#z`SEitEF=7k* zeXC^71@Hf<{uQpD{McLme2DL8E}R12=MBiGf$!d24e3ArTpHW5BA@2~KCCZ+oBAeO zIrQQBQ?qC5AjjvO_SSUhe&)O@-kL6+IPY6;O^>rDJ@3J{rpNFBo%ifp)1{-%-2+Yh zeW>3%anT0-<~+P#vb zW#v<4dOk8Dc{sjK_`=3WyE7hGrtfj@`{rl)&i`xhk#ft7OV6f^Im}FLIXg2wOgqgp zGSlVnsW>U~+Dj7Ges(7M7-zn*|Ku8j+z(aqKyJ~92X=$U3$8d%dew5pOA%hLVEwQW zde=A|{P({^ds~sY^50)@#n_a5NU!~DRqA2&bD&@2(%<*`)r3!yVmP^d3#9AG7sh`! z9xT_{@)^w=%cIwoa-Vt~vZowB6!hZ-RrUGmbL&&*Bb!>$DUU!GP~CmnLu|wj0MC~{ zfx|f|*@QO0+hr5iTKaqF>?_ch!|+-MeO@q&(H94KVcO$m0#>Tz=A4LDJq5sq9zuDjALD*F78Il07(B6&Drw#Ynp`XtQ9LRU% zs{dW}`aDYYNBGvyJZjyeeq@L<^aqZ9h*N)--P<+Iissj0~;DBQP%@^IDP8>4IiO*R7u&;op;NpOf zHZrh~SLMHOij6zFcfoJ1&&0sEJl<^H2JQoS3*hdL%K`2_94;?}!#luz7H1!m$eP{Y zyyYt%EYGJ72Ux29B;&lB7(ary^oIXrzVt3w{($!vpYC6NG`vLR{WwO}z6wmlgZ+4( z;;FU3rkgc+5dM4B5dK<~{($(DVl!S*pAWMKKLBHR&2{ug>(-m$hc-SFwgAZ>|Gai5 zHgX@%e*9kXd&Lw~Ji&YEV_zdajNoPyG0{Y){T(H#kI|;y&$rL&^h} z<%xGcQ2yS5@;@GsZf4p%Yf^VuVmj9Kr=m?ZS@3}e<>QS_kvoB6NxnT0>}Q3(Gw zXh`t)?fa6s4*FA@RzX(2D%XnDp zJ!vwviP6lFiw_T`Hj>s5JK4q;l8u6O+mm}j=Ey@|^v)Xh1keYN4d@+)`MA45u{xX? zIy)vhQH)ZHtJpdET7roU)E6-)Cp3Sn!2#|iJW_eLgQwpjPXDVt!Gzj;lzJLswb(6! z_(4=zALnheOrA41%XhWFAF*w9gNH5T%bthN9(LYb3$`NJni!+}g{DDQxsEffP3Uio zH`nnA`~HI7J>Q@n-WA*bS?cl6#GkFSb7J-mAnnN@+h?AsH1J}r&FAiIouYc6Rrup- zLkuRt`3|iy$n$@IVU};m$kmbLv_u=<6cb$bI@LFovQc1|{R;dP`Q+1j!20`m@$SJ# z(X05X&r=U%o^tRV=~eQfQ=LEA;IRMz#l#3ON9?sZah|M$^3o+_Kgw3Gn9!heLcp|YIE&WMlHvboZ2Edi)gp*xiGzro@fW9cRvjpYlbF#7~BgR;JHGHn6v4;|5t9+5~6D z3E*J1X7K#J=5qsOH}?0x%zP6cfjDl?M-mb2Zo5bqY?Su62e%;4oL64oWM@WawDa;q z^1o65N7W}d))v4~uoDb=fTds%1a`B4ne>J2{Ax?gvEtFjVZBJXZeS)@b7!7~S&Rj1*h}oXLb$4q zZPZZ=*Dp|ZIJo{h>BTVgar?7;6TH9Z!TVnR3(l`IMju!Ec$YkX*YE{51z*8A%Tutb zRs6wW;2Yt4Ax`>pp?MXo)d#`pkRmu`pyL7j^I-j>Vc>MfFmQ_O15W38V;4LQ_u$b? zS~2W={5z0ugZSt1|6kX=zx+R0XZiof7)K%hAI*Ij@5KKnQ|8_B{~v3d9{>NmeRui) zWqSAce+%!$eDJs8r$v1538fYB!AD8k7ytjwX7WRKmj62^yoLX-rR;m*|KAqxu>53@ z|DWKs<@5i$)K_@dcCUZU!|?yxlxNmZxwk}VMdR*JTG6;~R2uyMNuHuBpQZ-+KXL7d z?O9i8=J@{J$`@y?d_TO$#?a=yju_gV@Xi|J#y#@mY2oibN3>iAtw9g?IXPRRj1ifT zSA0(7gZ0H2$bX2L6GMj7g^5Q3?U@nImJb)^=l<#%;(@s|xzWlAe9DH@AsG;+jOb5( zq!DzFr-@-UuP7gV9a2u?60GYzmE=6n_vmIg{4snl#-G=Pn??BZDrx(ooBk)s@6!!2^xA-b zq2BZ&W#0?kNIn}3Cdw5gE zdold390q=08U}u|N!u6R%qhg1*jw@DBFerOyg6nVy!p%T7z6m><4uG53f|n}^=~-5 z5&tS4_pwSV!kdpOtq5<9R2uwt9?$=ec=M!>H>VZh&7p&MvwC0awCH~UZ+^?Te7tG3 z?=Idf)Vqf_*YaKrzipcHBKU1pS`qyIK$?d)ON!TNJ>Fa*ry}v z27jG)ZV}$BQD4EEH@*H1hd19>o+5s8uhNRf-Kn&qaeq%~;LQs>hr^oy>!Lc&CPcWO zBCPe7)?LV5!}?ve8lB(Mdu>UKeS~0Fonv;?vrdUAFZW<*O{RQ%7r62K?O6=gyYgvR ziM_^M|C@BZ!H$k?KH#qVqOu2Qt=Gg}*>ct?yMi&|-mv#U+Y@A8CvEOVcdeWx%|Fw# z1RMwxo5IoBhQ1-gt&LQ7g2da2`G>u7C2KX`KB@X7^ZnR6eth$jnVY`J0lV(g{Oe4I z+s3%`?}=Ua%Bq01L1fSc6fd?Rt9b9@h_e$+bnR4JZ_ZvbZ?dDrk9KC1NFT>0UuYYc zF4$v_(>=nz4PhE-tYw~*PN=gT4Ve#d_wIg)D@Zr!9~t`67L3_*cy)&oH=Dik$N5RG z$?B7_%d|L7r47T!amvH9aNjvL3moBj9;?6@ih z#$~2BGhP~ITxCPXP?7fIl}D9MTMcpd9uoVWaql6q?^))Db&vdL1t;NS9e%#TH`yb0 zh&GDg^>?KKr#;jyJU*7E%1O`EQwK_I-6oJwtPa0!>2HN~|H0N%k=}0WsZ7`MR35Dd zZTVOrp*>6c9u6erOKjhhCc)V%)`|ar@cTLX^?u;@jnIjY-$ya_Lj10I2mG!W2EWfj zcPz&58-|%LhqU4F`$5u$-{n02r|^5l4$N&~;Y;o;|_{C_X_eTA*3B7Kdmr!xH@|Nl4Q_iXz2e(>+A0{njDH$(CJhs5iA zJN#Z{@n9%^|LOI&;`dm=v`F3_MA~rp-9WnV`#bdIe+s`pIt+eq9ENVU(#OFu4C42} z8ry#Zzn`GqVt75OH1Kb)9e(%z>#h3tp~K+!X9UwC{JxO1LEISBzrR7c@H_kK|2h1=+Ky|eell_x z{61{R7zXkCBBk#ezgIWBgZ_Om<%{7pN@?Kt1P{Mw@_!ioUQH~tx7EM*09VmRxrg5k z)Kh@ps~ZOO@72V<^Yw3Hb`7h4FZqA9zU-r4?+1S0%Q$`f{sdz$#P7O6{9esEY<2Pa z@|a=p`-^*kU(x#V9>KH-zmuea->YTIuzIDpzT85(@cVF{?=$~i4bBa@=h9nW+Hn=G zFW3L`t@_D~Vd(ZNL&h+O-UD@i7^>?|z-8awnm*CPBi}rVn zu)Y_)TJK@qgFkVB!a)X>GL_+?LN+8|(W* zyM31a<*-*d*z)CrlKX^wy`35MJP3W*${O4E5xGXToihAMIQKF(r29jRwF@1AT}bI` ztzBqrZ_?U@s_nk|NRMvg*iMN1vE>!Y?&3VVVAFq7St`IDlIqo2I9oSQ`BiAmA16J4 zEh)!dy2^9|uYPRhvM(tHhWx<<+cw%$UX|0{v7Y!2RcCKHlk>ZQR2T2IUHnA*JIYdu zd89F|qHo@Q(CUVvcKs#)O+T8|k+5sm|I4egH4g3v=^h==uD@ho_Swyp+12vy{Aex% zpMCpmwS9N(vz2=H?6U{+UTmja*hN~Ao$_j>71=4TBu)0&YzRNYB0ri1zal^1u%*5{ zoPD;1vhT${JDqtcw$E;V!fng9>z}2*LI<~d{c9euTMhcrG%8P#efDIf6^%Qpw4!kz zt2F55dY+>5x9+39`*>O6kCHPEbbJ@@e!Q&LY#U?K-z80cF>eSy@~oY*1~vMJ2l6^;UvEM{zH;s;)n9D zkR4fNYOy2x{*?wEBpY-md`xs1$KS8m&qXxr?)kdDLGrm+&$tY-Q16%0uJ|;4itfwa zn#9M|x3}tDHrS;0uHgv||7CCO^zMCToNtwfJx2CcS02XjgWtqGGZRhz>-Z2U=CtpR zm;InK<5k(CYKGd8zfT_rWqRd+z4gyZe>d{bt55JNw29tkVP2VD<;|h$Qy$MIYIVBJ z@G#p3`q^*&cl0yyI-8Du_BikIqY0V*rJ67CJneUno9)JAl01`7q|PzchsJfa9@N$w zLry8Ckzxgfi6Qg|aS5`-bb?>^=6e^~bBs?QGjvbTiO{6*dOY!ZD`O_{I_DSH2gec1 zMrWN&G|ri4-5n~Q9NjIo8#}#XYzv2*N4MR-44PdLteIAGi|MxkW@_#n(8{RFAg^B;}(b%@$ zp)}^Or}2SdXlx689FE3HfcuZ251-C-mcYKFclP-2S^Q6V&+UWG9+6A|r=FlL;Z%rc zF`Yf>*9D#Z#(#&-w5Q?I*<-vH$8$5#9Q${@+kwwz%uzGGWeujZtL~uo-kS$_pBpnx zykE4aJ6Vqdzvh##)8cMby7}?`<(EM-nxj@z+Uw3|X*xq4!n;E&H{5>;xFKBW1otnq z<3bf(H6gQO zT>mMzo<$rCjZg79#RKz;0*Pspwg1N%e)jEj9;+NZR(o?mWI#v3?W!P=4hV zpVN5!Hgp%$9`ZTNhaD&9DlTrMZ`_MajGpDQIPcR$8TC(NyOlH6Hx!I7!Z{9=(;0uY z^&iG8(|p%+#&S6@-F3cr`q*AW-`x5u(%J|9iSltau8q21A>Vw9f85^&-fAwodHR0R zi=h*L+~VJo4H~b;G>$QaIqR5hlNebOEnMvU2lqC? zV;}R{@}%7) zMi$IjVc+BQ-R_6$ycw|${Qm2Via&2PUjOC0DO*7W@^=<@P=&#%;<{Cz>IYwX1s~Nd z7&!$vQCN35b^Co#nVfgdXbq6exd24EqMdK??qLi^JR-fwk??{oX zxe6E(JI=yixN-@2GM#?=b0}J`@8--8@Sn`w>-l-g96%nG3xM~2xsQ^j_YdLJXiX}e$*%2JHS3G(krM}{8;oV`qZBC-UaLJITYdbGmL%jf(=%uE#$uy z=L%Oj*9OcagXJ?W{w_RIxyLA{^PHlGHT3@#H{kZo;KeNT z=Q!t~XCZ?Fj3XRo-fCSxNzKLf$+5luIqg~StQcpcXTf*G7Ysg`k|$G3V)-qqyH=Ehh$#{{ZWu{+$x-D8UxvwWw&OCF=Xn#=AAl$4)6 zmKayJk*|%uDwaR;1-ne3Hv(*xM{Vn_5Wz7>-VF2Tw411WQFOnr;#IbdcKbU3<8j0j zC#FM~KE?U2u@uh(-}Wlql$gE6-;CBZ-kf}i{sv<1-SI1t{Q+aF9#?CE9pCvAHg>Nc z!?jU3x0g`QO6If=_~hVm^1p3@&((mVn(t-7V3+3C#_*FoCQtpR+}Pufqtj`gKTaLR z^IS=J+L^xQv;I6+TRl{K{~_j8FmI>d56NZ({ixqp(C@Z(;>7YhRXDH_9N^av4m3gc z*8sDz@REJuK$iY0hI=<-5xr`j{`CuYUT-D+W#0AwpZp4K10R3P)!jtbo3*FPm=dJD zMwzEn9z0#|*{RClC&DGkzmv$blRSY^e2c-I@*A?BEu-JNN&AIYPOmyZzB10GTh&l7%$S8`XEyOu+* z5iIw3Yq@Jl&vJL0)^dH`TJG}}55}b*w{V?cV?P_#b5Fz9p64F0=NcrBsx2?w##yf( z__O*EFWGRvQ-a#GVwerWvA1D7T&eL?l6Bn%$cn@p#N`@=ED6a1Lq%^ zBYVEI9bMSK&s`bAxpwKr-ue!E*^u>J?QZJx)^~HEo%oINt8>?P@>RRW$`N!L_=5P$ zuxCw?3zmKg)_0E_Df8`8t)6+-@3-TTl*#6dQ9{cgN81mkF4>QFqW4^zrNpE2k9q3vudv)ZW7)a zZ;9IV)_6;_clLH`yawt}o#%S<`3?RTtnrp;f6QCsEom5B<1Nu%m$$}SqP;Gy@mxGu zm)Zs&y%avH^}bJY*o)KSiSa0!6g~E#kBZ+)ZxPSUC`J-`rde1*Y)9haA&Ycx^Dg3R z$}UnJ8s8NoR*h)W5SLjo4fd0*|HTCl>OK3Y8<)8go9@C;b%z73#lLWTpYF>L{~bxJ zPv7n$y|IS)0*WIi{Vxm;dj*_V|F4Fgg)5RfSHr)>&s2U7u^cbOio4s&oyN!N4++Y$9Q-|b%>i8RV_%h&8>hNWN^nf<%s3VSpVo^Di_w~?A z*+(tbL!sB1PeYSiy_g%UV z?vI$eR&t7<>LMjRAa=oY7M-`aJcCZg&IQ zDYlNWwhqa6&5vY4VIAKbrj84}I)vL%%4v=(sOxF!l?*u6>!arC0Mf;yv#k02KAb^$ zdj^lZM|kDe)6U)nYX|w>Dq?vv=XU*Vd0-&j4XnE1gQ5eq6N3k4FF=0)?vh18<1B5n zunMHNQg1VHK;65x-Mf))$9IG=M)5bcezEL9&3p*l%(ny*;mPjWy1yk5-GcAqQ{Eah ziH^9Z=d@G_Yck=bU6+yu{);cHPhx`!DGj^q+i_dt_SbqpJ6p-u|X^ zRjt7kA5OgJIKh_j#QVoc4KD%e=Kdt_f_-} zfj*w1kJeuB?NhlUElBJXbfjar*9Dr@IG<;}!q^ii8!?cqlsdMPPc{i#uA3MJ{(CTx_^JQi5J;@^-)jR2&7IA^(j>%}WS>XpeW&x- z(HhntVff-~el^TZ8$2dn%U-WB>vZ;7`*6}fw9Wy)w&eIOKIz+mYglXAGT?~H?4oV< zn&;#g7j(1Nm}@2}UHnn{%%?rv(R+X~iw8A%9Cj*a@ZWn`2;Sq1^OHc}5^?eEYD*{owUoaW|0A3fK!+`G&oWt<#tr};N z@&?^D?D-OWkN>$4d(w?&-FfJl;!#=ZRV=sH*fW#g&(+{oR==Z6em86G72djQ3Vd4W zl69iRBsk}u>8MNxfvfy_;^3D219nrk*grt^%0Ix?E&l-YXzj_wNq;;40MVe})#l>3 zEoc1$C@RnqNfZ1)aFkwQ zphelfSHR1a_U}ApZ_+(6qPOqr|32@DS(6IJ+%t!gvGDLG3;j>Dw`6f1Y4J)tCSO4w0*w^;_V|J$T9vA%;9d}B7J7Qz7u`w%!fftaw@9oyGRthMKk zHft8rmxVu9AI7B?5XVXP2e)27K6MRuAhupVAyuof?4%9)V*6zKav*&<=z#$Cl5X0n zEc5!JeB29H*q1+eeQ6?=T1fYr(RTcLXZqwzO)7j#AayNqqjaZ2D>2r-H-$S5X-9ca zfquEmY;{Zg_(U`DkmeDaDC{gcN%~;RltBK{8Nqd7=Z2HQ&W-$T;&<~&t!D@Fv(Q6k zab|ng!eFWcIJG`F;#v#GEB24Z87p_MfMeAU)P&8Bo2MXKm><4>vgRZ+=jKEC&-|F+ z%S!{;Jc1c+@CY|edVI2(IW8QZ^mU$rgT6fJAkvQHUH81)uJIjWD#ZV!gV{Z!Sw(wB z$V9s?E{MtE-begvyAEjQZj5H`#%P4r+DCK8$mp`vWxOxG{gl+Dx0j^O;XTPboK9QU zLyMAi!l@dMULUsmgO%ymg%^^8HoY=^BKa9#J|#GSC;i~gm%Z{A^86R|8f+5(#`mU? zr=4(yfX2neOyOb~XZ&|1`{9vN=$B&_YHEGgC z26U^NPtQk|oNmV_S`coe8CU%5`g{idbpbGIgm$$*(Syv=Iz0YyVidy5;-}Rs*52BA z#4LQ8yed2KtiUooh3AI|b|<^>3>7DE-f{K$O8g9*?$X3}`Q|i_NG#`h`(3g8cUP7q zUOm99Z3EU#)aAen-pG)r9bVBec>nt8^xwIXG`H=FA@%w|_i#)P{`+F&Bdop?KcuzrA z^L^gYgRofKs=W?i5q7pbuW#HRyNtWYoGaXza+T`iW!yW7-BxRhIIzfIv;Hhk&1(R? zzDxar=GwSp$nRGv<($(Vayfvx7`Oe|njr2)0Ed4>{KVDcqUYc0CkMi5er~D@u=Ff~s+_;bYe_^z0Pa=N$s|#We_AP39aKVg*lx!*Mu|xc1>9RZ6M_$tn&s99| zPl>-8Gqp2V*~Px@k+QXa2py`9wLS4EXJ$;_af%rghKFvVoNQ>akt=4oA#D+S=T-Eq zFgDmf4AgrFFqoJ=nYz)(raHl~T{-$9n6uZ-o@JAL-=Fn+HrRK(^fd9_;pK|!TT>A> ziSU8QJoH@jD(Imi{ZHWe26hUyKk?iK>l?R%ee*k(-gd{I>7(>s`uMi>YEAr3dG;iEY^{x%F$+JP;hU}PMV1xV{F_W6w ziHE+(Bp$`@Shh#mA;ZAto$QZ)psa6yTua%t(1dI|{}ub=6V&0`AMd7)cVmA%1;4A| z?2l`h$71{A4@rA3_D6L4VeOBKk-RVa<2`&!%0CDD(Mry^H7xa(?0B_ZK7No`&7!ezTnQ(IT|-O>F#e; zr1$<@{lG@aysEy=;9G5!;zw#qPIR)OB#Lj4K zh}ivtwC%?{$U#em{ABL}*G^45-~3j1NEROVRD;%yRd#>%sh}CyUmfG&cBb7V{sGR) zSKefZj|ab&OmzLibieAjbRIb?T}(Q&1I!G%!V>12c>o@+4KT@m`*!*GVFRQN*RKy- zz!^%z2AGj8Q2u}D+_C{C`9GWY4W6AAI6R4MhTFyL_u}k$f2^q}7gilErWIhQ*$u*2DXgkTBlF8D=1cL^n4api;dAmYK;&$6rP zqpTaF#EqSlZ8UrF@0}|CP)~iYtqMfH_IGIK7<6;l*4VEI;&UwBegku+efDm2_OG&U zo$Fywfi~67HC`Lm&x<}wr;5UhbF>v>JYVIzQ;V%+#&{cpy&nEkxR)>3*?84O`zsN6 zkm?eDbl2|gzDf-^90o@WJZu(nKTHvPf%P*nEzE`BTsxFVG$(O{wL!a_>5DYXgVPIZCe$ltm zWOK0jvhF@cH~nj)f8zUv>$Zi0CF77>*PYBa!~dj1Yt7=>wk^+-4b|2M&(l7JeTUAq zk73`F{yxUT_@y{Az+Fo#7T>8$^DVlO9M-)1FqpFDIuw5PqoJ;?Mpc9T!@ZBVw4?ahd8_$Hc_Z2!}MY(FGjk6!dq<_z93Rd8R{EP9xj zUITs9gz$5NW;E6b;s?N7`Tf0^K#|-Z+^2rR+NUz~S$l`zo!vWZpkKT*#<8|t*@wmu z>nuaxy0K;TH<)NY{%Ml`+C$8sw@A)8oV&p0ZqEp0Ia{}Zv>xW(#aY)L^d!22{2gMz zGYmWpdyG%~6x?L4L}Tl*1>@tHf0Q)$9Ef6B^35>``Fkb#RwjEsxYGsRY46P9KmM$7 zcrj}O?)B?mD?i`%(I%zut?iShDGz?meKq8hyjnw_r!r@}=}Gi}7<1G0Gttc0^bvq?}PV&-?wQW)Wh$k_PruKgS@vr zGDu6m^6Jz+wNFbok=LiCAMjo4y1fhT9Zt_#lKZw<7xZ+T?Uxw$4Abx2wUqRfuRepG z!?<(oKUw?LrQDx-?)Zd>a~=%3c%w&We%v!Aq8HIuH@Zs>yLT3S37v}=@jTB{-0VU9 z=VI#3q9a(}r=AjcJoQ5tyP)me-;S+|OTP(K9x2`CoJY;FKrB9qe*7#)9ZJvjlvur| z|32DUW%iy%o@}Tws_(hR5z+o1Q6KB0><`V}oa{gM!M7UBny{x+CqLo(%kM_E_;Rhk zF%-RZqximPy&~QJ74EIx%R2QF?61JTn~pIv`$8oN(Yo}k9QhA@iE%7qjObXR>5G6_ zb`j&E?1oD49lh&XXz!J;kal$}|M1zdR26cnA3vf$Lc@mp->>uJ)N8b@^tgPqEqzb0 za!NL?tX+dnNH-yOZh*ImzIQEZ)ESF84tsX3`0a0)z&L4xGaa0zIS8JmyC~RyC^$p& zTj@09$=wvokHw$uS?px2O?NztAFb)(bINsgxuY=eJRU&_ucI)8Iu zs&=^ZH?+N({JBky1LtpEYsDV<}V+LwhWmS&8h`nAO%sY?18uiUz~@#g|ZCHVnM;SHMK zH+V{iK~C+^p002+3U0Rb_OErI=WN;NlyFk|gz~STzs0y&&;4gf%IQpY2Hc7>-mAgY zI6Qj+c-R`M{(gL7Y>zpWd#o2B4^K8b4xeOZvQM_7ll!Z|)o2sCjLrwt%szfv5}e+M zezTRdX7n2AH(SwjgvUwpSXlfGoT5Lqd-~Tj7M$&|xC~AUpLMRsKhrZoFebl`&+CCn zoO|8Yw!3F~d|Y17IM>sLa5%|0WPb$jdktgs@wu}ApN|9=RHx4Lv~sqk3E8N2;;;0t zkq+&jd&_WUK>H*~5ANdq%6~ZNqRAX*o(ktS!#%E+E(-8xqVR`)3x711-&7s^*L`UE z&w1tQEVwRuwc|tIC?222q%mqt8mGqR)2ol`h2z_azegb)e0tqOI~QCa`*t-xiJS*R zXHkEBe0*7ODZdzXyAe}^ho->l{z8?X+e#RGhR9FloPMYz0@zBoR5RQ z=TL{zL?37IelB@c7xx=fKf{<_g{O+g#}9CQuXi=Vcj3pmP$;?)Uu4U7FDK9CgKJ%U zM`v!U{y%nIt^DHY0r8>QRKnQkFlO&4H9oB29CbVdub;&lhBU3wl1G3`$jB2J z*QN&P?-Q-Ok*=Gio^Oy|PambbOU69E&ehco`ukRNtF7ouPm?wlon7a%rN3vO$!ADc z|9$=akKmQ`^8ZWQyT?aWU4Q>)Wo;);-%V_39*W| zYDJ`qUo%PY(#BSfVo|Y@5N|VTwF=eLTL87T_$Xq%^y--z6qIl4CEP|y=lA~Xb51g( z(8s=B&+m`(I{WOiFKe&8_S$Q&z4qFY(X|ibZ09~h#&f0iZ$0^`37TQtnX`BAq_V3D z;hpX}4PV*ti<8wS@NkWJ#sGTIGGHB-c=5N$1<>YB{uRLhu&|izO8eR*7uzG_ty8&M+)B5{a5;jzLM_JU*BiY4LMKkxxW7uFfxW8XN)gV zfA~5|weLOtInaW1ay8Fu+!xxC2du^O;isB!r-!r1CD~5+oziGs2oEV9%-NhL(UEZ< zsPmqxKe8z&tpnLk>X&r1g!9P>OPmc$0 zIXa$Q7Yb*au=5__>bxb3XgvIDGj+^oEHNIoGajDgtdC@iZunT{FK5O5b+O{K#(*B+ z^DYm1o3W_AO)<`s$e$N6*R*S0Ts0#cTj{O`|4APUcfMXEs=i&v+(-MgHv7QXlT8m> z=r7WQ4}uniEAjEkru{A+Ep&pS4F`Hof}AVPL(5%xgF?^6l7AK4P4Gr6B#NakwBO%gn5jX(BvcmGO!WgC1!^P%QI&3zgxPQjUR(S%bl99k+)__UEl zo)vv$AG3@sr8_T^(7{~h(h0X571v&^c#!B-`vjk&ue*ad$yycM!zujUZ19^i_K-Q| z@d&>bXMl}v4I8po&|M3^-P~bl;`A;2BC~B_FEKfG-}vom%=5+``t=Iv5L!&lr~QA) z9ebQ%Mz^-V@OvwA3%K%qzPt{MdmDQJ@SCe+bk8tbON^fJ^*#4s0?1BU!-_ZeF8cFB z(yhY}mgsJ+pIDG>4B{ZLM?lJe?u?kHn?CG6s`hbDidvD0!q;c$NRZ z^8WWwZ#VrCfqzvS7)ldg=e?2tK7O*yttM;*?0P?*KG!|-CLTQC3#KpqrGA+7pZH;P zr6>A%N#E$llP2niD*|@4n`Vj59i8jOo3lp85x+0o4fAlPvm)cbpXQwxNiQ6K?w3c| zGyL)>`wxD&-LfNom^3f?Vd9a?j6FxTZuA>3bGBo1RgvAh$TEAYFSGua4!8Ka$n7!w zK{&TtUF~{zT3y}9X3kAPbKXO`U8h1eLInwbt-obb{$)vI8Oc_UQ+&>0-5995KR`^>AE4zp9dsVXWr5u;g_W_9&MzqM&|X~kr{6fWTpbg zuFjzb4vpt*=g@F=IpvfEGY93uLHxzQ@f#10H7kqk@q(js037I6dX#@fATxRoIL3Hz zTnQXS@#s3$1suzP1d}v;Aae<5jZhZMBZ}hNuv{xL)6Nr-o&h@`}RgQ^KN;mlSR!-Aphy8(65f6` z`giJnPTy6hgxjh2w}d6zm#_ybT@-7nt=+60&V_dVM8EAY?bCi(Y2r!bmzAZlF43&y zg>*VEoI>W?iJgHDyY?L=J1PBxq;E%`C4GC8Jkn|1{er90LIyB8EyX88BV3&p^qedR z_OfZZRC+IDi~cl?UK(gESsd)W*-tYpC(Sx94Rnw!5B4^ZCT+@>y~SwLN9n4OVdv0b zulnkE`pVraDownc(}t_*zpH4++oliE&C-Wg@co|GhniOd(31N8hic;}w~aBcjSbYB zA}k!JeCEF}Jf-*1oH|ysk9eMN&$`8&$JToKcJzOjvzOT!>FRFQp62L1_D)X`ZBl0k z^;bqm+NV=DHi7iR^zf!m=2QB!#)@G2YK74uWTY#c&U!CRA4SwJ$io$jXU3BYE$YO6 ze~wizUa_+(&px+vq#cM3GCnyR_?dMDd$(FsLXWw;;}F3BUFF6dNL=A2>xgKbW#0u1 zJJfdOddc5|Yog=FGk;Y8m(~Wc@44%0S8l@=f^jp6apd+xS>pUY9F0vB3ubS;j8NDc zEBg`d2u2QDt-V|DR|#E-wnV!JAKWm$@Zjk9Zq^{8J)iD&Ki^MxirXQc!FX4`pxMi_3i-zvNRw_; z-6;4m_Nw%wQxMF|wX_B;w43Np^+^-<&$YK)8E+ZNatck$MHMHe6B-4yUwSLqK`D?S&i^_`a^Uw?UIR8?m@L~yF@Iu^54==Sr9_jk13UuA0ub z!kUw#;7jeeKN#zh{3!fv3JtYCs2dt?MNYT@8R0D27^MxSPUcge9&2;!g+>=sZ{y)V zn^k@WXJH;}s|vYyN7Wz$kdU1(<(_&ep=uYh8YL^{AG+v#%rj<(5tSAqIZgNV8U=+$3X0@|0lTo*f(iXlHg= zrZeBbSpltNJM+WYzW^um+grJ15nq-Ir!~r6Pk9xsZX35Zjf-bP1>x*wEAzYDe8deV zUz+x)Zw1HPp@iw<2KbED<;Msv=4#1TE?fu1Uj(iljRgiS(?5-r-2+@z!OUa1}Jyr7sI)76W6Hd0yo=Mry*@ z;epJi*1~YQlQPEzGA*hv?bTN&o;w&BkbhO=KOva8G`BwDf0bKbWQ0AJ`V1{8{Sj_` zNydfh3r(*HN7KlVlc=+9a5&vKIGjBukoke?>>TX25&r9}qs~tLoj@5ggPGHF>m;6w zg8J#VVw8O%b*AWV$sv*Y$aCA3Z<;&DRX=AfO~RiX{s{&rG$b6Y<81RxES^pYWM-&t z~=i$FmEAnb&j6hnJ7cEx&t|{gTROo{NGre?23lx9T zWB|>TXL4?2JF=tB)YKA|@4yr?pa~;Ou28w&JbI79A$N^)m%`q>`wNA=`So^%z4>*C z!mMFLqq5n#Mc=Gp%r~@pv%c4z9Cj{o|1Z{eqxa4Kn7%`NOSeS+>-63E%|2bzkM&*0 zH)B-)uhMt=B=?*ASLnNyZ{{`qzf|8<-Z%f}>3iMGu=w8(6mBF;AI?=cG&3xIJxAfr z8OFBly9(FM2uqeyo^$k_KGEbkQ{mPV!#gf_|9xBERqnsj6h{7$JfkssviZk1b2#$h=3#CC^Ik^JQAef4*GX5SNUM9Dp2a<>A*PZ%W*hK|f1|4m_DFLx0ni zp}n!BI`8?Ac0OFg`D-h&hBM2OS$_Z=(#>m~kt;(-uzl2bH@axa&)xaFk(t-BZy=dj zvb6SI4b6kMfpYVK+eF{v5>qKZS3d5+#=##4pAcRk8~|G#>13 zbWGUKzIh+zVf4a!)(ZcYG`VYJtyzV?tJQAK`1`t$m}rYWkt{l&GCPMv4%6OaN3iBF z(NiPyMJh?$B-`ykMVw?F8=w%lqg0obsGu_GiqeUlzVJ<-v=Ly-oX%=o@4^ zWFOnPX>i=gc9L~2=V>KwJ~DO_Vfa&34qd-S{o;MOala=n$vhW>-Yu=m(dSt5{lt7* zx$XKlCAT`rtlGoLvIY`O+)Y}|HRo0p+UWXpF6UFt6^x%*l55W`j@>QUR`Vxoo;EWN zGQT`Q8w@Q;k4?I5zjpDVF;H1C+X?S=L)2){iS-3YdiD!+^J z+Aoey*-823S~ns0s{FULc0&Hud@31v8FfWT?)*g`Lq#dM} z%zUSKH}j-vhc7F$Ze5%UH}NlfaI37!=y3a5%G20Uz8%QPWijgw$;$26W;%<&8N4rx zjGUc`ObC2e_^=Tt*q)%gm88|$N@do^S?TR#7;@ZfaU(8F!~!!FYr zASSw6h>TDFscfwWs){0Erxkw+jQw;cdl<;?*bDu;{QejA19Iz07lqHtt%vp15Y^M_ z)pM)rarZ7H!&eQb9?9%2)YHfw1v2|E>iIXBeRCl5`Ia2|M*gVIttU3Z{sbIJRyXZ= zQ1!Tb6O!Gl3aE#9KANJQD)e8-?%S|IjrwbY9`MOLkVO`8a_b>(LT)|I2>Wf-L%Ou^ zR*e3dxg}cbu5&61B4!>*GmkjlJo0Di@pY&v;Wrz|w2HRiADXLPK}Jb2hb&kbWStUW zU90_KY`8tWa0q!JM!!mb-vw-v=Y1J}HQz5_A7S<@8qp^ryDp$jj}e~?ok5#R5|5a$ zE5GAprcZuNeivOy-n~cP$nT=9yA+n}?#bqN=v%To}JfROU_kMrK!;iwO(&rcJ^rxNRb?fw0D}_8itc?(#B2yXY?# z&qd3bh2IQ7tQ14oWrTWX5dup0c773#U4?zYzN^ljr>PZ^H`fQ&!w1W zYGXk=#T+=+)IHtwTdC?(A8Zaj(Q(&Zp9Rg?z#u**Pc;61rISv-oUQKyQ}P|=aJEGL zzG|?4FnzFgu(1W`4p_%ZKOErfi-`{ovE^ex{=yo_W8zXn?4`t2fMe;lk7KXcO*`0@ z?$U&7huHX;cf&1%?VJ5@?O^)`Kb$JGTL_={q|WwAC+d!i^k#72t!o{H*SULte^c1Q z`=1r|#>+bjd*kJgCe3v00gws7vDSL8E3V32>%B@?a;f&Fey=d|;!ofys{aFEQC$j0 z85e8#FCSs5)5Osi&k`s50)0FBN4*Ni==0V5lkJ0ORO_Oh>L2>f-#2(v|2O;{<&1)M$&nGGf&^G;1K>61Lx=KyNdl-+R#8){ZmQ*sQqfgF9zV?9MZ^!yu!nQ z()`hDuk2Eie5(wdX3`c;pzHUsxUmg2cE8fqx20=*T3Nkql4*z@9AHWzR|(xU!lUD{$-HDp8h4Mu%~~? z;&ac}zwB1HZbrCAdU?v)rEl~vDr>vK=wEu6WAyJ+eWQQTzkd?mAAD)7=$wlgKhV(k zbMPjdZ6e+8y#JzUrCXPiewNZ}9@Csh`gch$n<1rBdPCyJ=p8d^Q`dZ>wGwyP2GZv^!54TqmmW^UA%$E_@;ng90 z36^=p-Q(47_-_smYvA7<1JZw&xFueC@nQA1_~AXG*Uo)9?`Zz*jc0$2c=2p!z00$e_d8x0x$sXQ zT`r#-&-X0SslW1Rm)_#hKYxsLjB|h8Ihu5Xy#N0A3FM@2QF_L{(Z@1=3Q2DbNWa^w zN9A9w^d5iceIFki-apZ(55r|jnt$e$H&imw@UUyZ=Bs?h7$(@YB7KQ|=U{hj&R{ z7N2>Z^dF&#Qk#`teVsd=e#8F_{8xY8#(%x@pb5Pt*G)9__xBTytClVH(n$|^h45|b;S85a7Pf65_WJOAYuc`fJZbtb#cvp-ed z^U=v|I>PmJYO!w9+NK*j60L2TS=&VMWn5udy?gVC93Y+ca&mnlcVHKzJl4An-&elR zs9Wn^`8{6usJl*R2u6(G;|P8vZk8_zY~r!WH}>zcVUbUXX{>J*p2pfYs&Cf45xxrv zW3OWTX0z_wfc|e!pE+s99B~8v9v`q_PoFv6oH_UhXH*9IJstx7SW|6S1Fj^O`sY!q ziTB!dz1sCG?NXaQfKLd9+9>Nx;!L>P^_gSBj_WfgS&n|Q*08rjo?!AltV9p09|9Ah)yh+^^oIHo?lAnf3f3Q?C41{hL4J zW4^pUMXo<&^7dp4y!(<1&3(znA2NDtNBeiY|IHur@opZSBgoFQGL~%Pc#8&v zuV$C#O+Kwrl;8M6R$b^kvTcQZ{*cdwUfh1_zwcISE6J3;FOOaL){&lDesqs}1l`e) zT5}gb2)fc7-8srKb~Fw6#%jPv->QFE@n|s8)gH9EUf_J^8tn0PPmFt3xQwY19zeW& zDqn?9OszfTPfz8Kr+m>{fU;Zg8>#XeC||xfrB6PII+`iFfwG&f55(W(Oxo4?{HNaj zdUO`1ECGLA7Nwr0)HAvlyG82B-RtdL&Q673C4GLi*_#azTfn|{WbpU-uDl9XIlrq!5CiR+uY~gt;_!Ok_qs=6uSH% zbS}JGm(I-iHuhS7Ue_|j-g1o98v~a*U%Z7fyT4;ij?O(LY(;rrfF14$(8BKb3N;QI zuxVAfmFW2z=3>V}c~LL#RPyd<#s4zrM_z;nFn-}J?2X2X?b@e{?GSl3&9^d>-gWJm zIt)Ha6GhN&!%yqt+gkJOR`Q8Yq~CP=UVe;!JU3u#PL*zW18H5GxY3Ej=+k-l1zs>= zuzijE1>>Kzux9S~PRg}vD#mlq!6BkA(TD6VUh1%xUW32Xg@*?+cR?Q&teqpk{yWM! z9-UYjK2sg~w3u&)ejlkfeG`DMUr(78tl2Bm{r*wA_+Np3qO!3+Zk5S1HZfurHZJTh z27u{u)6UU}l2t0NG*Qf3_z|9jqsngZlQ)`nmm2@R!qMN~adC8xhoiONRyZ1npS!`2 z@FM*DBnLMikZ?SJsS23>#m+5qQI@tX|4I9L1`-eU32o)_rK z7L>-5O=WQhICniGeJ%Drt(?iGF3~tXK9ASFlj1i^H%kBOPMuvr?#SUT%S_pd{pa8> zEnKi-|GUbqW5pZF$eYABrSLJ3_tXLt{dkCbhEI2A;A@J$a9)6iplfwrfR6(I9L~ct zhU&jAc=;!tk(0*OV6D!fxjuzOug;sq)%M37L>%+@|qJ_3I;;kvZS7H~u*&R>A zlx70siKmx#B#UOpTd6Zv%O1-YZkj=Ab1U$S3wG&zX-f+KY=u@li2v>e@EBXG{UvPM zIFobpzeIl;WB9GZ?r{xgfX#Oqdy&l3CLX&;6AxbS{hvvVW1pv7dz6KCvUo-~)mqb) zEFK(A@@>W5sZP}eyR7NluZCao#}h8yY8-0}FL@h#w&I%1oxm`eG2Fp8mCf!wubFcK znU1xV-NhId&e2iVZ=i3*gJ0v_#rT##QKeVDTlbQObw9Q)C5g34kN;ff3;L_2-^cT_ zqLrPTgM-JS=T`n(jl|XU$NiMJ64r5L>vHi}mNOyh7;( z+o9Co+K*E<0{N>lR#JA&*oUxOMGES``d_)Y1bX68vUG!;J;JV7?9bd6lYtLTy zO+5;plN*sOhsCKh9C1eQ1iP}m+U^X-W?k?yG|Jo+h41%XW-YZgS(k4L zh3vWc(+?JJ36aJLFE%`ul0sPR& z6mJ4Uq|BP!0FM(&rU$2hUYm;6iN<&~KH<&K1_Q zw~ash;nr&D(V{c3AyB!jORl9{zf6_4xcdaVugpfb%oF!jCcg5cLn)JWNc3c{%-L4v z2LsEDR`-|L>Xv!rzRHwu{=t+o_n5*WR8K?HW*%uebfIz{)L_! z)?&w*!)q598sNTM-XH<_TlQ8Z3FSL>FL_)ZQJlC?>BVc8Gf(93+6Lm2%UnJxxne){ z=}n|b_4C?ul%~~7(_-0qN;4nZ7eg!f;$==goiwKJ(FY`ts6iI)U%S=7NA_u}c?@;| zt%GgZX-1*7Q=qTQ;TaWmmR(PKG!94dUB&#Y^~D?1y@5x1oLm?x7}tjbgZyWRrbVOL z*R$EL(j0%Qd5=!4en{WNiA8UMU+zH=okk}NvFA{x?nf}+?3bRWZ~Du8&mCf)&G+9a zUu%a~c&m)>^G-sKf~A9UCeUV`q1IgwqD%F&@GCuxffpWpHvXRk&*oRN%l=BcM605I zc*o;PQ|XMd|4N>I{)*n5MdJ-i54GYJ2Qf2qyxT&py5nB&n&GhYW2Zv*FcFK-X;B>bWU8c>^N;-evNP2~H49>ZKnE0Q0Z3ub&Bzl(oBY9Nzj|1hoF7gcIORE$&fQ}y{ zuABChc>S&Rj3TUaK7vm=HNBVfmb@zdrE#Ns9;1Sfw&e1@<&>u~d_1;)>f-Tl#Q)SQ zE5loIm`iJc#74?deZrgkbzZ~sWAEGSXAZ=d{1<_*7-gRArSs`_4!F3QxRfUw`F#<^ z2a)<>K6$kFrFhNfqKCt&{}bZWPPOe?a4Vgm=^x%2!wT1YkX@y9#VFDrLA=qSn>-pb zfy9gKg&jk@!Ba&)o=Qo7h*#dByhQ`jg9?TY?>&Kc@1lNvgv#r|2d~z}r8VqJl2$sH z(*LpI|j0n&%IKBRfy@XF$Zp&#n#(1WVc;p`F;5d^!}HkugDQweNf5svlbMYtXl-&Bjh1S<%Jz;zo2p?U#tJ3(Ou{#}&;&a@+!VONSB(#95a zywa!4!4^jPlx)+GxNJhDQ<1NkIq1#Wv1z)Uw84;dtl{spV@J`+aowL?Yn86odh}G% zUd^2{x_4S->h5%vX<5Z>vYl}bjZIyHJyZ<(8OMERV<>M2Ytb^DD@S*!xkYz(A4mKN zJo;b8BfVxZWqv+CXzxY_FlExWf-A;b{^g?h{aRUU9s7$B%>U4#KFQEOVT*{*_y0l(bn~Nz!?H7#2w7Y_FBsevHV!L5ruQ6wXRd<>3XXn5x z)Tg>bT63EGraIJT))d5RzjNnW$qQv$JCK*#87mJ3t=`m4C&yRbX!Z41J9FfT(1Z5D zB7|!Rhv{?e>s5x3BWbJpTRvI)#-?|dr~JljL00Hp^qSH8&ZSLiyY^btX3?Y%*)910)ZT-8e*k=L|JbaHkXvNKG{08(E;h2)C*)rTmNcQvSF1QvSR9D1V5`2WIV4$wyiPFzH(|gKXIZ zi};7%-!D^++BU+=C;hhOvTngfI7u0Ey)qH+BF6`l?y%Sub;r06zZtG}a9LipG2%sQs54=?~41>JNP% zLcOZ9+1q1^v0wCx_K(}eYNe4j+Pqo8k(X-SLvKico} zYjW>Gxt7_w1=EM~G2I*ie?XN;(N%(gQd`|m5 zk-`Z6cC7W&Mzn0L*jREzEeE)T0D_khwV%lrfn{m+1dmix`2MR0B!3T@Rfy117GvPHO|HC-wL_Z3> znsE?gZ5(p%C&|9D=QyzNKX%(&(B$#VIl!rXP=74^3OM&R798T$u4(vbP@W|8bqsCg zEQjH}NAh31Q)eJVw`u6U;*T@Y#gxHIOY8vs_6EMLwgaQ?a#%^7;%!M}s8lvTUU`LO zUqW9tlUMPT?Ireml$mUs9@qDn+<#7q{VxB+)7|@&OA-}F$7a?1(QQ+1d#)v&Gl_PZ zHoA8#FCebJjhsv9{+eAG8Ek95F=LML{-{6x81D(f>bG&gpz-``KON)0(@)1(*1o>U z&shE?;UxGKET+$M_`;ccf$0pzG1q;cIzAxpr##Bn$1C6oH|LZ&kk>>^{$jH(_?Cf_ z^P0pdoz^A>E_jK2<+e=?OkL7tDwBE3e|DMt4tES?;mjD&p}U$PNB(MI^6(_{WRHc=Mbb1eVUY9WWvzo zzs*5jc>`(fx0I{7=M|4WRNfwR1>JtxImo4(r;XeoUho@e#=TD zB77_UBzWLX(yLEL)2@D5kNeh<^$OrG$mj4J?W2|%S?{0NnMiKgWBl)d>wa19LE^P; zsVs2U3^CRW+JA@EXB`V&TGj>k9>_DDr;%p{ZQ9BD&MLFw3xfIUBg-Q3yx{@-c@Hwa zvy5!XcnNW)Y!hRuDHz%sZD)RMUvcX60xQ$a95Od&y|J}3yG&(Tosm`~U z-5#tlgfHR9LGBhVqO6I8qe}Mnn%U!@NWO9_Z)-O`ZiSy$?-R{?_eMs)0k17fyztvS z@e@N9egOPD4PB{D)fHX2;#Ac&8~9Ye>Q=oC-2c%m+(3KH*c*ucV(3&Wi(FjEpRu{S zb{cxmobg&?WDMOYlcOu})+4=(UNP&CW|b46T-Mf-ftt5vIb-7X^WC(=>*oz>gZlYr z1KJ^({wms`b%nc*(K>wp#FO~07e0SQyymZ@M+fd0>A&;-Q|izhlQm`g%pXyz-DtA0=&|R2obH+jqw6D7Zpdlk~XgrkDe+|s@qP1*OUOa$Y z#~sn}EP9Pv)>*#nk;d0%%OKX;tfRGt+J>Ese4dzm$S}H3JV^Ojc(Y`hZOH5vdedwu zKb|~+vpwL8eNE1qVk49e*o?cNI;KOD|PxjWN1|TadG!MxWvgD?ANa3#Wp` zZE8b`dds0PwJ&>9VcaQ3hX9XPJJr5z*hQtV15(?ZCbwky!|j|sA}l_itsDLZ za`^^}d%6oMkt5j88{84>^TnB;4D`wCgBq|UWu7@78rZ}cP0c4IfkInjXh=iIF6ziL z_t|`oZZxkZ&)mlmY93?{t<1N}16EgI0DrU1OR6Q4Mp~PzBdsmfGqa)iOzd~&R0YCw zS_9$DRr&E5$e$k`S`hzVXp9S3GjotnPs|p^=QIYxbE-n&IkS1vq40G4@6V~rBQDT2 zr)p5R4xdwVS_g&a%nx*Rv@EM`Z@II24nCdcJk0+zAO}W@;A`w})Ua03f5Ep<@ZIjhcNJl) zAVORAkDrxBpI5*g7B1^4f?X(mB zWm?;OfWKN7@1=>;DN}NW^PuKLcdc+r>qqMk@zP&O)Ve0!=z*`ZCMSuDoQ*6Nv%)p#+NA%B(Qj2Mi*yy& zuxIYKrJ~Hv{vDjq#)?zH7rv`hkL)u|UHDg1T`ARttYGS@J2|}O3hUU&wbVsiD~;&>PJRMKDPsekaVp#HfYd|2GWAv#Plj!L23 zzd(mgJ{>Yo9?)K9=x}#F_i;goi_DlB=Zz`%UgZ%U9YQl^Okvls)%rWO)jl0Eo=&9Q z{&?CFD#Es5jO{!V?9%-70PS^Q9)rJxG4|2GxTUkmJ`4Ez;v-}1XBm6`_&kd8cCh|2 z^u;)Jib9lCnpnM(dQKt!nc6OkzFITE>Z&-OzQX3;xdI&W4_Vafum1bvpCVtfHeg5U z2HE!!PO0pox-MrSeiN@i7o4-F{fO#Nc^2h1)?~7r*H5OzYg`*K<#$f6$t0n7KW+ta z{rxh=euI87ZMogbOy7na2Thp&x1+1qcyPwp?JKR`-{qwHI_Vgrz5V5kwc8)CdanjA z0eB{4w$W)CDm}!HvPJvFBNw>yZ_RmDeE?op#axlTgfYJe+M91>DkKlJ4vVLn`0mWN zlT`)ymq!-Bj%hb`B)dBKh6Wsb-N}B>++_rB(tIfXb161Mvg4^S{y7gw{Fd+cp{)<- zyA*BDcH(m(1a5-pH5!Y;o4}#`GN*$v%%L!z=OK znBv?-$8{mY6GX!=61VQUATnX7D}~Yw>_@ zDchm1nhGep)2jakWxoZVQ5h9KhfhGb0eD{z@`dz_n!m+sR)Z_05sy=uf@eGJ(fl3b zzs|U74p$nd&8pwgDSJoSA{en%|O)_B^+oG$*DEgBiOCc0-1+9z1`6_TId9LbVrlzZl21>?fNI5zPBb|vP# z!7=Pntos%;jX#tiyaHccqV?nimv={zo6Tg06|J(Kd*!b1^`frWp|K#`&`Jb*E zX{YK~qc1)#ULP}eVQ%d{3|WZ2jRmcY!#fF2mY$`Z_-4hOU6YBiwsU6JWKxXnSiYN1 ze5)CrReQ^fxN|!E1z$1_-_845nHKJ*N?z!e6ID6HIhRw;1m2hM9?zS!&V}T=Bw*}L z#rvEV@*e_?FrNqp>rnFY?KF|+Xx@u>AI_U}4nASz_oZ2U5`O9MZvHxXZ}Q-$fAsC# zN}gKYZ8e!@cx39(x~|wa_$Iw`6EG8(ZKEuBZS!fsejD@Ha<6{+R&m@DoQa)9+0bd4 z^bUT4@&1uXrGj>hC++c9@#z>kBfe);sX30a}T2f%jxTjsk8kj)X6%x=4{G>rhGaQ{W$DTc&`sn#-lWSOs(EN|H~{S?CqWCy-RgH!r~c!AF1M`cjoJEH)Oi$jYHXXe3pDO< zR;fZf5!`CsvXTGld(Ge0VssXHq4+HNQfmOgca&(9b-1%TJ9)g)(tfq^P>*(FyRwsy zRXjLPuC(j}iN9Xo;)$%yvPH%57oZozBfal3m7nwfuYL4I{WlfG*XqCEfwm$y4MW8A zzfX#{-*`-1dzB%0f^?GqX&xLU7zfOQ`zh|Gnmy*hLd6Z32SbX3esbr*f89$Q^I-0N zPeyUj_8ZUYU7V;PpM}o1mG} z!F^%IHl@tnlaDfQ&E?6pP1!;}5YK&j*p$Vl*eUS)w{Dj|x%+~yUCOUCZ<02buSib# z12CfV-GI*bajiZ4^Uu2#@11kjzMu)iBegGM!j5a3V#4TXb#7mMaUyf3-e#S)Ig&X6 zT9qyXKmPTPQRW?_6K<;ah8uWZX~VxVYi>3 za>Yk{n6C5w-|fdauDycFDWsgGe!La1f8>XO;n#%s215g~lb*|9F1E2}rj=Qsbi`|aCV&oGJZ0XK z?)a77QTf%!#`eWwAG0E8f0w>=$Gh$VDoaGMSGi+7a1G#9uTl2i_`oZ~??LOH&C2J* z3$8PGuh|DLt6(2nG#cTpJt~b?hx?4pc=dRh!@bU;(S`%|O`~d?+9h75wplUuui$5! zU)Zy47WPHg>Kwv=wk;djhRDHorBi7CUh(_jWm?aQm#ZJ9p;PziYB72ChNtU^SD)Vk zy|mK51M{;cFm!np>3n}HeSHqSdHYuzWSgh`E7dD|9N~E9J+8h=>l4lQmFROm;yj>u zyx`YdEd11Zef}PJ5sZ>aWviqX(q^58m)c;V_1;K`-O z3V7l?@kQp37&4S-PqLJmZ=uHsJkrpp=u>(b)_Pl@$K>&S^!PY9emr+>_2}_&pB9ts zZ;2l32DDA|`1W4LS`RRSTb+?yBAW5%)&psS`u&IWd(@+WPmpg_e{B?Bsl=IZw`I## zQE9*Dy&L?0k$`4iKdeJ^;eAyoOhL-*DuXqo)o-FftEx45|vp2pT_2!mV@=0HcvE8x@ z!Gmz*%`K1DdieJ7{DzOivYJfanY)Lx^;c5HIUWwP%h_XKugI4Nqu}Hr9?@*1%EebV z??T0iW+%CE=)+u@2c6YHgd6@#94_m_q1J=g6M@4+_JPA0d*HC2W`9ilf5O!i{tx6Y z71-B7P6P_FJ`yLdLdx|{El2y?%;FW>HqckI#c%b#=cCb?*3i)G91<}l! z`!{L(TFUU-?$@#0hn;fw&k1V{XwpOi_UN3jbWnc$Eq*+>`AJT=Fem(ypPn|Tejo1t z@zW45-;Cw#=MO#YhKKI>%=r}E z>*6%#n{zBZ=p(i@7WSPRG-m}l>!v$;KRTk|vXu1BuNTL4PunVRBmV-xv;=vs&*#9& z=ng-jj87ZQKIr4th{MM>r0^lQ7T=Q7Pwbr_eGdC#p`aD7H8&mmNhZ$)176~b5`Piz_RjLLj;T;jwgUC@`^QCezApv zBn z_;y%iWo{^pb+zP04qjXs$@~^tc3KPUO4W?i-t+0h}E z{7G2Y_g3+52R!SJKgd5ld$`z3w-A0i7;O70Z3&$*)@}-xZmnc36P-2o4Z(?8XT1-n zwY&CB!6>+_ZIRnb>Pwcl2QR$$;2WIpzkfM*DRJ)ZgZVX?tIxdSvky00y(Qq_Woyv- zV&3a^*WKQDUFq`lApE?CM%o!@WAKO{j$Z|gE9WhEw)y9g!(!aE+c<^0R;N^s*S$Bo zE3L6GIzC!)(fG#iUNpWA9}G@tkbkH0to#v|j-LoEYn(T6Uwk|3@2D~HA*Z&0pu2is4vG9MjL691sQG`^{< zES_G+o)>mv)~T_Lci)*^_Bk*lL)H_(nTTO?Z#h%#O?A_|IOCa#<^^`8j;YPmj+Nxlc4Dd z*azXGN&B~v*qzmp*j?4u3TSv{ZKj6*kt4`Yc^{mjz0m98YvBLy*HI4kW}D8g&762B zHq5u?$0O5JZZNaP!5*eAm|4MC$X1OCTlZM?)A_e4l%H_skZ&e-%IDQ)Vx&u62)vy^ zyRMEhPN$x;gPB;A{m1iyhRYe z=!Bg0H_kp0 z9$OiEt-7YO0H0H@S3AVj4*gNQgT85}Z)%5+gRaKen?9!P?|`?VSH^3HA7J9%U(Okf z*xS{$L+2Csm3XSCE>qhBpJxwy!cdFzgzr=bWA9c6Vt=Z(Vt>Y0S0It3tO@LG2ZsjY z_u(I?GuB+aGS*Vvfsd>9*y3u3wx^J5l2zx1Ybv;(M>ZY8OI2yud8!tjNWZ<=IC!4^ zIpDT3(jQ+!yhA_q8pxkFW*nQ3O@#wifatFjVDhU{I7*SmPaRsA7K6{cP54#+K;x&V+V#WjPSO;8jg0e z*2X5{=F&)4=fzh)dxKTl)^cOyu*FueEp}VYVO#3*y0)O}-1710%$CLz+Oj>PGrO~+ zGvfW(PzgSPCX6q)M_r@)&&m%zFf1O<`SHw_;*!jkIlQZQH-4inTUL@uKU{;HRATPe zEUzrSru>^<4R5I$Y0ssuM(WMm&$=u)C~%o`e6Y8i`C`KXkw;$!zL%}{s*A5}81~tZ z8-|Uzw&AqRKW;ef4Z<(;zF|b<(Z!@`B@Op4Ju2NnMCl{eqmPqj)B%AXO8x~8x^b$-JMU{Z zP7NG+>TJ7X#NLj-2t_%BW?Z$a@<$gayaWcuu&P&U?h# z3FGsp%y{m8zUz2z=G}1WjOT>I=ovGfdzrWJdUY+n26-=B%e=??nike0-0dZQ37=e2 z*t_}i!rl+&7xupY;IQ6J4-e~2KQ^p4l^)%j+&sG1*~(iwyPJ?*EY7aNPb-+e$FZll zon)0ww zuNoeh^}yOfAkzm$3P9pdkdSgX#gDzsO%xb|BS z@Z&T^GOhG?(i`&@XT(Y;wr)&Ks_iX{E#Bxb*N<7f7+W^0D+WEZ*#rO@p%3SktJ^dcsT5$&Ld~H-_RQF?0b3*BvH9<# zGRcB7GtD26H*{vEh`g;S!tli*gx`l(4t;*{#`7zF5N-_)Z4>|C-pYjd#|!YJyl6rA zzKK5w=bg{{pdW+-pCA{&L-OVogpF_w{G?Ru0C9B*rVkfJAi;?|8oIR$TA;p=1@-|ksB`2Mk8AP~o`UT;9 z-p%>NnY@=4Z%o0zQjG_;bzp;28@V7Hj1`7cjbCl6wDQ_&Pr4u+T3i?o-dq^&$Ok9D z;sCEdx138KIN(X=7Bn}Vr9J|;4*j4s?ccEKzfD{UUhZ5-`N;OE^N`sXzX4=k%|E&y zNpnz&`C=uqev)~@vP#wmS(mJ2U1H()W`dFTgUcniRK3Rj);ji0eka;4+v=29vOisN zfbIxnKDdVPj?R%b1Ixa10(=EtCE0%riwMa8PE~EMwK%Z5BF{3iqV&xX;56Sy)MhG% z5`QS~LMs!T7TZ|S4(+l|$^HU6*#gEfelwy4R%ZU%LD(f0w`Cb$-RuR+E=%b(r){5v zjC82vvXS8h}{WHO~xl~;yz#!ygI8-o{d%oXO&31_)6>yuf%rm ziGbbuS-@^NI%wbUM9{u%UQhMn&w}<>c{hI+vPbfc9UZb~GjDu=jCBRytyhNZnY>$` z2-y>POZJ+@d~#lEp*@*&M-jfC_#0{m*`xW^T+_<;;w$s)An(}Gd3FQu)+dk^c^`ue z*78}N-NQU_bnNbG%}Ync?y26$_mQ!Ct2IAOLXP@1-;-m@t2GaO6?y6kzK@OlvU(=( z1CgsV2OSezQLQ=XXk@Oh5?>X&v0C%aQOI6{_&zdrL$&6g5cR5`Cd6*8ZXteB?566k z#(q-$Bf^!jpH?@|8e|WOwN-0=vtqXZ^B`O0uZ{hz`oVegpKT$(=AC@PYKvq_wMBB| z8I*A#@q%OXp`qSMe7_j`dG&pyeydo zmR3iLxNj_W2kVDln6hj(2=PK6D;6t+7TllGxo+N?|PR$e^^e?lkYw+a*y|Koe&6>QK^^$Zf zHDL=Mb)4nhJ?G}iJZofNckt$w*jOvC%34cVv$5YX>pA3GtGhP5bx}=kY{KAhraZ7T zxh#^oJw?0~SU<#Sy!T|*l|97c|7X3{WNi<8<+5n7@m~3pvPe9hB?ur8fnXgv>3;&0~8|DL_)`@okqw11gNA(;N z8)C=2e-lX;nZnr*m8&vhHNAmdk=_dSr>%n;##h7wy|n!m+71qauc+;2ElD|1uZ)G@ zUv@H0)RSB{Bg{FBjK&u`~`g5xQ-Uxp}*%&4*p6h=-}I8R}C zqrw5gJ;*xS+tl|ZTbU>8uWkvl7g~x>wD0d)S{ryH7oP3l+lR;SVD`d4Ax^L~1Ir8O zR(i-QJ;Qd&T|gbu;cO<2eCw&sO$vwH`jZMT!hXyA=bnuyHgM=!WY?^;e^UG<$R=~L zs}2IUyFbsCNgjCjh3x7n@U=V8`zpWoF{O71prbnIr`FOGv>)T%*vR6cah;J)BFC7% z56NHF_;~gUD|0ORDlV^Ewiz9P#!9M@bnx>bkDMC+=xY|bhOr6hwM0uFA|HJS&z9~> zdM}-)+*~j|o}?VvBz#<-AWFkD9_Dc68T}3n)Tz;cz_vplZdiS`v=rD0* zi8OFXza-s~^htMqfexH+za%QVLExE9 z8p(qC*V0nHt9;&sDU#)GP^f;Z*YXcLeV#;D^Hka<)_ls$$i z!2T!Ft-a;P@d>vC;v*?M&b%g+$7Tdm~;W|Sq~*1A>NGZP5oo3Ii0OP486bfogII7 z$9o>%$*R+_&$f{1-F~=Nah<1maW1a!S6rLuWNhMY#(G1lHXJx9d#uJn#V+*Zg{~ev zIWtQ?A>*Kro_5{f__XVW@D%Y3jZ6PMjWbo#@P9mwb5+=mP8P4X<`voH_|cVK@PDwG z=sCV7^Q0N?@MG2iA3@Vk;w#)aLTf2(c#lCI`{aM#Jc;;ZCwhx(&kF)BsnnyQi9_^^juKI`CmOdpMsm)F{d&k3B z8!8Tb2D;Hxl_9e+Z&<7kB{QOH$^>Ki_5^s3_7Fbi&Q4PmT@TozXWxZsuG5 ze~;&G5r4ioNA-L2#hD7j@0S6q@EFq>5%w=MU+nl5anRzQ<%1Pkj1IwH!T{QflkY## z-c*$j?cHwbEKc0OTd==R8!de0zC`{S4o7L4<2->{G!>v?E+s#^6k0yA&t9hpsOfrzZLBL`|)=!b@wf;h-Lqu+f>doeSScG z0UqTC#P^5OjX#h8btflT;vpO5KWka7WiNw=PiCJ*Jo^mr>r}ZglvksNL53-3t_tvO z$F3)a&Ov@SZfA{|z4(|Z&ZGf;R@gV{^T#nxu)kzrkNzvWYB01be?)4x#!(5lbN$6y z^apYo=ffm-Xg<+C$j`vhGI(DP|I*+{<4s^$HS5$N7*0Wdi`J}sp zcB8|&E#dh;>A^3=WsMcz>QY$%xNVDHPSj@*`QtiU(z zh)=U2E3+2+ru)|A+4r|{2XbC)lruaw>i%W<@g3NG-cS4QGy4v~L}zHk!4u%+4?W1) zH|Ep_R?NibZ0xp&CgsJSVjtsy@8E4q zCnFEh2fjS?F#XUmGa~zw4E&fr(mqsa;y~h~^v^2(segnIjj>7ejp$YVlU+CR4V~%L z+~e<~2bhE8Ph$uBMSWlU^hEw!n&Al@4L{w|$+>AtvXSN4cN zCdPL+ch=tnUd3;^!E5C`Gcywyvy~Qmx8zHbem8Ag!#}}hlUA~g(gp*uSw8?CwM}O) z0;aq`+scLVXCIsOcm5?8)pfNKMi+8%1N+GidqMi=9B*aVONGw{Ie(2EFE+UD~{-`zW?R3!@@$7o`ugcDhe;#7rzF-!6cBA5( zowbaS7 zmIpRprg@Nl@MZq{6n=;Flq23&3I13cw*@MYAFT3G*U=B@^^uIJhcZ>J>M}T7?!|-O z-1^lICOtUMjR!ZMSdl|@rgq6fXkcLwTM*Vy74z0jor@20)vxhkT@iUY@Hy?d(t7%; zwE^ykurkrP0lVpkR(L@$Xg3^fbv6Dg6mOak2uFv+rlwC|Pp@@wd^`N2W;#`h=AX6uRQ=bJyX*t@Uf&Km<;x)$AHY~x(cn>KK^6kh$K=nSj3 zq2(vlHLX_t_Qpu&9P*BBJ=9*s`9-a#*1*Hw4_TwznM;}0JF}>}UPdPtLh}`@ z%gvch<{{;&SY*}T*<#rS4r~J}+YhxnUv%&H*iQdtTL-!4+wnzHAwL(`X9X^`>MIM> zm)zg0@lbSTydAtrHz>Z*{e5f{hu~9~@qxGL7KSIgR<~VdjM=nP>h#+Ri*a zs_OjzXC`4$Tp=M4sF?|ML+iq#iP~loaI01;#@(-(Bv`51h2oAilR%4#t&CEss3pOr zWbC39RMg4@YOAHT3TmshbtXYY<1PpRaenX5x%X!7OcJX7et&<=YwkVwEYEq)vz_NW z=N#m28|BKd&r|nD>|6rcs@<2dkG0SieXhQXebKaa7JdD6^+EBgIkTpUI1cso`-SY! zYTC-=%X^CUz6&yR8YvLv!R$XfGzb9K2#rEcAu-)=6I*g0C70NMJ;XKS$?p^h5D^FU)l*S zdcdc~-D^*{h}>>!{dhP;`#xw-eXl>nSbT&d2ghfychJMbzFr<^Q?zc!=MGc56f zT;l&Q+S2(1$qM>3Y?`Hibo?~Yw)jGKy1cxnSty?r>soQyuRY@=>$$rK94v$X(~l!p zkZ<}vO7+774nH_^yhieXpOvAn;di^+$r~f@?#g>Bc2!MwK6tk3n}2e9Xo|~+`#@vI zvi@{5$O<(1e3?4!?IX)JuH z(<40}+)Vu!MQlFJldH&E2QJd&RUbr4Z<0rA3}ImKWcmd4VK(zNU)onli_UTRdy}c1 z1C2D8NIT;rU*89*)3IYiU$JNA+{>9cQTSJDu8I|l;CI#D)=qfIoJ;CrPG)wskyw`JXKC*Uv>rvadT?~Sn1#c(gTAzIL>)MACjCb^%Kif! zp%H;B9MImPPT)8%vO_RPwp+O}GGOsB8+=HffRE==^f8ch;CN<;1Bb^`#^S?~Ez&oi zi4MSp#y#o7gZL}5#V2EEzp)q{d>&(seo4X8YQK4#sr?jw_T-supLzq_Qztp|9C#3J zz4raG?KQV;$u^I#)raV)0J1GoDc-g+;~myesUw136|YGyMi?tgGalYG7pHGOWBj}5 zkG?lT16|~`=P|3_cFeI`!B0|c)8|g#_**&a)*Iz)Ch>;oUF9;31(hbo*(RcU=E{;;#Lay@#}th zqIMN0Ry8A3AwC`_enFP}1laXIhBhTrQk*d|kWBf*9$A@kD)~1e_asvmA`|@bq)>I| z$&*thH)e5f=svmfr01uk-)6Umbr`aB;Rt08T^D^Jdf^t?)&>Di0}`6Rn(qw*w;A$cWF z479RdaFNH`R~Lc)_E8@$LgxdQbf3~jlZMW~w}8$F9TIH2LAN-tVzP z;?Yygj^})NR=9aAA5L@m5WC~&&?t7tb3L7h#EW!Ro@-+jxq7WX8*3l>AYJRpAC)m} ztY5Ss@7T+bz6aW0ijINbQb!{9umMfT#DDNdI|q88g?+dI<||3)u4d!$J>#OzyrqkI zOHBlwHqn{C`~ln~u{ob)oSP|=#9j?Q!5u{8Nt5TBqN$sYZ`ZdlbEqKpv%aOMM{}Mv z7nj@llIB9y;E(y2vv2>%nj9Zu09w?1aUdTe^T4>~gtF~gfm!@q*)` zvpMIFxNE+P*Q?OS%BR?n6#IHTJ#6>-N)NM^Tkh#$?9U#}&*2y8VQk-cTyz4zi0iZ?)XpIP5a9RMy(X`2tK+EutE5YAr@*D^e_Q2z^$*IczZGZKHz`v)QRELv}ED0lP0=dVzoY!y#- zzod6$jpUMK%^MbHjMIC5|3cD1YWGqt(mFfze6FSEQY({}178j23P}FQ@8|8sd&BnCBoq&#Is0Wp@EP3E z|9t&p=uKlH-$@j|Nx+@^{}7z}aWoDbX>Pyflgx7YQ~Yy#yLa35GiV-Br}ZjyhHS|B zz~cEEuGjP5;VIe-V3*|k8=|z?wYGnMgZiR*?wTIj&+~a`pQYx}8nX;zsPPIgXP4}n zzYQFLbBp^_Ag+Df!nb^+8^N>uCBn7vtbJg|gR6WzpDVbb;}ytO8%IOm&LAxZ_wN3$ zd8Dfk!o%J4Q}z1&CR&sJEAZ;O_L~akb-*lKi+)9CQTFUD<0m>x>K~el;ujsNXXuQz zBbye3r$uKm)}njl3&`pr0?4MY0KhA)EyyS{YUUD z-+q!Y*iSO23ZDlwo0hL}3V!s9Lym6}UI?IzrGKrSM)x+@c19#7@vk=W$FkG%eM#a2 zzDs82z!3@9vkCJ1kRq-?KDYIheaC~7zVGHehXVFqiTrY5e9hw37X_1_rZ~?aNnQV- zeGhj%-ZQw+UNXU@a}3n(3i7_^wbg3uy%M$@@OG0|xO#-|qOYUKo5rsrz7W3u*fTIs zjDsc|*)yt_C(eJoFHQW6I&PBcTZLjhnFKOQoLIn-n?@hdie8XMO{BQ{HPzg*wew`1L&j$>Z_-dsvR6Y z;FA@0kELXV`W08d@V9w1`Xz@(ACP|Z_U(Fd`x*<2^kbGrA0l2NUv9rco%uBSCTY;9 z3m-bumD{6%PjGyX?*qwVk4BT|c@Mv_eRJ`fMW5o}i4)HpXL$H%7=(k(Um2Mx`?T~cYfc#Uqzky<2j2o=5q@idSg7@ zJGk#9J&k-_3j9{y;Ma-~%OctNExv`tkHAEKdeUo6k9W3Ge*Nc>cayuWIs+QH0^3-& zl;o?U-!(@n>RlI6Ug`Mz$!GD59+=0oXzL&JNq%gP#;3DJtvvnFc*k%0%HeG*`{HCG z@a4m-@#~MqqofOthk;`tIqcaRDde$7cDn3tSo>%)iZxPW?N16;CCc%(OVkj?IoO z1CPzQ^dsMHTv^!HZu|>%=8w&va{88)KRu+U?}q1qxgNVwzN<@bq&#!ah0w6pnatlZ zwU3bR3i|M>+plNc|L6Gk`nA#5N1YpB)3Fg=XMSm)u@PSL(s`cfJwvN6`<}nzJyUkQ z?|FZoh1;Vo4>@xZ@q=tT&KAU z4qK+`*Pbn-I09#GxK}?s^cDKi9}lU27QfNHdcxo5AF0pyF;kCaCLhH3sn5&kb3Hz0 zD^HoHgsM0Xh@a*uoW<+d8MVxj*=L}6O6UwHEuwekDUt7U9?(}=OPaaUKKId$k={O! z?VYEr??)DX0DS%Rxtu-={;T+&#?R=<-@={nc)e{?Hipxt=7x(O1t;!YrVLt-VDql0 z&U_yKYYrS)9ycx=XY$=Ie_N5Y8)g53N6qsz--}Jfcc3)z*m{DKW@R&YOz}R0xnReM zSv=xHwKm3<)#&TtvBlE4HWsL9RC{L1;K~D$ozD0Y8*mx-GyzMs)!n>D4vlXXZlE>s z%tt)8Ab(^tdo*@sKloml)6cA&{v+vvXG?=)2is@hl7Htn(9*U1X7jV@oyML;Cpod0 zH2vSjzs74f!F0Or=MpahC+k%l_+{xgS7$nKZu*s{Gc{(#c0T_VjhTO*#h87Idh^Gz zKBq6)F}sy?!SdD(xwM}%M|a080_}S`vz2E%j_66zeu{VL%=$C3Vgk-rtf`0`%uP@pU}Ka?P$`DWL$Q4$7neJ zwq9iVI>uGwrhB&Z{}p%q?gVGq@#8*7)|>Y4cl;cG%-o#ubNn&C$Hw%-BA)w%dh^Hh zL(;OmpB=w(z^(DSTCm`olh3?6!#pZG4q**DhDascC`H1XYmPMUnDR(^4w z*$F&%jNj=P_L14^?gw7l_V_6nBPNP-a+dZZPgdphBRh_^f9^Qyd@YOnq;tO3%f$TV z`x)xBb_WkUuCes_Le1Hk+WTnZN%k*jth{p*+enk%^TyQkQLUhE<$KiqPx(7)`V{{d&} z^DEcq_Bq6Q%nW{_JFU&Ae};2tpDyMZx{LCxw20oNH%Fl#ilDnuU#!nR=%>$v`ss7| z0DZ1?`n*80qtvmv7AQubglF~Z9{Q!V7*C&uSwBB?v&GW_ck^3O-x+&(f8F&;4{25#K{&Z3p(^ zcmceyAWuH~c-xWBqv=zp^&w~H?M40g>YvGhKTB8Jl`dR?W7mgjaV)<`7d-Qz%cl?X zZ}X+HzNNpq-=60`-<}OEbL{Z@ssC&49ASf3N2`g?bNN|5MsMCx&Dxvh9j8FgI%CYX zXSm0jJm~5LTY`c3+thWFR}U~Zc=?hhUgtey$LoA858iXUbm}_Od&Z7m;pHL!H@$RV z`>mIrGVyC&*st)~q};LOweZvg;(z43ZHIDIUOMZvNzxmC>(`@MmfN z7^M$D`yTCdGNxh1O#4lwhc>zYdy=O2;l44}eExO53nxF+_#Ex5-)ii_#MTVm$@pBT zz6?9g`k-X%KV|yP=l?;S`D3$QY3O!ud^~^RAo|vaC&xHE`A5pUv~^&5d$ON)R=Vx{ ziF*G=SxKn+IC|mY2@6c-y9j0`aJq&a=*av+3~F zxn4T_cp&L&Q|IpKe*yUR@;&O6q29|pm`or()=TI4Bo98?_>u2f{&5dJ?Q8R%tGqnG zakckMS*_!H?e@wS(kFU($p4uKH_x(3wNC{7@m$zc#CH^M9`P_|uSS6Lm%agBZCw8_ zXV1vyAMHGUwVS{DM^3rGAkLL`%kJ@GXJ1Kx__CnM+@k%)b$i9SW7uSYPp94*!av%E zkEg1Ty9ih#4R38)echgnTxZh&B$=v+k4P8F>1vxfUSP8i^Zre3{xmGNRX)>GemjIPE^zUJg7p zsVdvH_844^K5pc<|C`5iPH{o|R$|SM9U585c~|43+#O%YJoGr)-GUrV^PeW(QT}1= zRhUQIx82J?%;skHEo?sszcTf|ajN0`iPG_zTZ5Il8-CCjv$7^x84uu_-mqk7`?QbQ z!*e%hO0fqZeG+j|%wZJMAlSPyySB48Z+`e>6Mve%D>lKHt#%BwC+9@Y!VD|^k-Xtl zWjsioKTy8;ClEJ2BJn*vzyJ02sOkhh`Kwt!k89tP*{fx-VvP=9{WVF9euy(qHZez2 zx%62PV$LR2C_eOp{C0`w*o88^?M9B$eu8ziZEM|_Bs5g zZR{;)oN>o#Gx7PHV^Z0f*{xmibvIkszYgq0iHLnZ** zdub;H%(HA7`@f-^R;6Ljd23KgyMwee_Dxj#M&O&)py_#xeTA)*yGOLoH_KDtvW;(^ zuTo`iqHHB}k-8GPE6_Lux;6IAb`7*RyNAZTOM3f3;=R8u6TPL0Ulv}!On%lL?7G6G zf(4k_H&kNzqV=%&64Iofy?4PY+gmcf5cmX-V3hw=o)1ZxBJJHF9iZ~e#R)o<`UR+FanT;ZM%dVO?TJj0 zHfyzLZG;=guX71UB)$%P*myd=8`fi*pz$QKY6WdYTcAH^Vkt2q-k#SE@YK8iiLu); z`x!fCTd8L&``!)u_bza+d4cviDfaNdkBHBKu4~Zu5q_GBX?~zP0Tq++qh+3bc-;l*8S5zXzNOQRo==ILMm+~CXLRIpsb_hx*xb{z8N{VC1$v5#Wl%$xUz zc6H|q-kg(n&HKad-4B9a{qWBX)HknRHpZfW`N25Tv$yTn2>drrzYJ^7_bl(*ua2BP zWbcLkSm|mnO6)guVV{%Eyx%^j7$4CZv@AS1w8q)uE-l|r`Fwocr!;(h%SDHb|9iZv zoOhPK_R-q9jdL%wSGQ=cigRSVx)<7dMkJQndWsUS@~%AFz4DPj{4wtt-Ta96j6Pn@ z^N!iSZD;*(L1XgJ_=V87^qF+ZH9Yr#&->WxW_1d>wBI z-+u@W&|R__8^L4eY)_xCzuMI&8SavvNMEIM{5oY9&YlS8>6Cwgi}ZZ$O&pPUMb96f zkfT%XkWL}aS2{&;;~Vh8ChGFbFitmc zMnE;bJL|)SU#0ucuw{gY(!?}9TU}k6IF)COpI?tYrv9NzX4^iqUjg1;p)}~jua6#3 z8gjrN_jo^PY4FuRTvUzpH~3hOEMJPQeiS|a&>YI}9UcBaIQccJ!yg)Ma^egZQ-{_6 zI{#pv&T`7?g64sA`K)8n3(qfebh++d&ei2t3ohWFf*c4bCK6r#E7GK&z4v9jd(Zd! zo|pQbm-wFVG`<2kTk2i^YB%tyujMdzx20o?$`(Hv2bPTnaTssyjaZG zr;{3rX((E36aMQq8Ir2PfI~2f^7sWg4M29^<--IC-2kb5qyvH@7NiST06s)z0ZxVW`7uVn}0uX zIb+_5{8fC%=pS-scD1Q2dUXo%`rPM&f2{)fH)_pc_T27Iklm8IvNjlN* zbynQq)D@K*(D~(xC&xB;N+!%b>`aW51hS=lCL3jc0Ka0sem(B$X7h$mt5cU!>`Kihqxe zKjxeCl<@N_`dUvuJI281(btpWNoa5={dC6Xq4sg$w=p`&&bw6p3heRC=)b41(Nx!1 z#!TaNALI1KMb7y^OKDsBb5lWJy!M4_e7Azr>Esz3;9S{VOi$xCBU|U3Zng#onVz!C z+5axw59ZuxWPX^l0Xii=u@yR*S82XA3z%|b_9W!nBu{3Su(x$md^PQUiF|EVrj;a0 zRpw3PBXxE1O>?TrzB$z@?9HdSqt+B^PE}d4IcH8a8U6S5_Fbq$yt0KlyfYdv15fq9 z+bf@uwa*;t!J_%yBr9vTkuNYVva+fIKfCTizy{6XF?O>D>@I4uL#B#3n${MG%%!He5?m9;WTilgQtVkSHB)aXFNmwjvfR*k;ztP zya-G=`D6neY-*jDHpQuzB>tj2^j);@4A1Jn+V=F`B+@P$WhU!P3GsLbwB*gP0<2Z3 zoZn9Gxn!!P@g1|DwX|C`34DCn)b5V0Uv&)ran3iWim*S8vg-Sa)f3}upxvs2!Hd2f z#@vFu&bJBiC-jZ^Mk~Cfb&9a}tp%Lv+X1BESGV~aCdMBit!;lZ*}m6Ii2sUr`y4zx z-tIk@Pl(^=J+~ZgV`!Z`6XUI<7Y{kEeY@;5_GLsR+cHC$2L~%xaVB{Hdn%2L3WZJW zHjUMhJZlV-huQn#$N1#YhNH>r%A?n@108u(iag?6fm?Uodb{wAZa$CklpT>TkCw6T z%!yYUlW0(0e1I#EE%qEd@bM@zsjSJ&yaAb%e)EKO(Y16&-+8*k|QOG9f zK|IMBCH9`mB{l5Pr#=VniFUnx$ppuzzvKwML2ve3=Y;rL)v+t(go8ckulKFyaC;Y; za3P*heiNGzUsygdzL0p4->cjq}6A;-|R_dJScTR&qR_wsih9&aK4X82L@X|_#dlkPL|%I!+Irx<(heXy_2 z0^hUoJ@24TUVin@d)~scg`s6a{QDjZJlE5naI^&)bmrCBd-0y6jO+*RyxGTi7o8T; zo@iaX;glKEopj^Y6nimHeF>HK@sxa2_mU=m!fX5#`>K5fs#7-XEBs#O_YZ!K{qaP5 z9sBw=2p8mvw zhI56pXCaC9PO|Av8|v?=-ng=tY(tZ0Us=EQb9sL4=kRMk_kZZue(pc{weNhFIf*CV zk@tp3Ae^dC9ip__g1Ukp^G+=f!U;4f^-{ zwO=RA^=mK4_iMigUATVj1;S+;bmgCqzeL&pOTYHRf(4jezxD%~3%^C$J&t^_?}AtJ z1lgab0AIde`$4{I47RJTBm4JjFH@d8eBG_IJbe9vwEq0sKPP=>e(eQ$^&4c* zwe!wvLnfpY^GsfR&pl1}CHVC;mGX}-qVGDCGhfx*Mn2}N#+u=hOWIeH9yX*sy+`#{ z>lfsk*-P`QVB$^AM3n8-RWM|HD>gtBzgIajYEY3GzL9bby9MW)PmjB`CNgpD2J%SW zg?2OZ$0J*INB&3-ZYVI5<`$aMP7MEH@t{I8X;>iAb1(0Mfxjv+?CmMxrxt6@xyBT* zU&8d%z#sMCpcNU1eYp;sXy)mm^^1dM;*GO{CNXPx%i@RVZ{}0%aO~?hIkRydefDIX z=9=C-b7N(_ zPjI?qfcjg2QS-x8*EPSx-?>(E%7)zn^T9)R>z?c%hwe(znKhipTvr(E-q!WQ-_@{g z`7}Ne<*8W^TO9e+#KGbEQqI#C=ikcE;i1Aa^p8x05-3npnm*zBLq#oWHSP z#Q2H3asP<56NcJ-Ci{Ua$@b~sw?*&Dn4!zge?DPJCX zY4N`J4uFIG(d9RW81FJO=`4au+J(NX0% zdrtf`tr<+AUA39yS-28DgeT4GLb9illjDD){c-SD;i$;Uz))IA;rC8kuy>sX&k-tG95o5u{p?5jZZOW2x<-_y3iPubDtb_R0elz zUPk>r_zM}Q?E0^F&ZXpefHtoLzmi2OgC%Q2nW?u{?R9&168~Qazf@VF>E7CX?e7e- zXBX^D&3#w@kb9sRk5OjS{L+YtzZ@Jre-(bo80T)oJC&g!rk!~V_iRayjRek;gy^ef z4`+S6e9z`((x*#;Wff&NnXRqenMJGc4+c1&as@EF7%ZOu7~ii%M`;eLwRA;%$Gg-iTZx@)i$`&X z%Afhx=Umey=ie=@sf?_EroWEQp0i2jSeVdX@Nv{sy%gP#Gh|5nHT6Y@JI@I{!y7Tu zJzaY5b@+>iWzR=-_{};0RO4_Z>jCm>X*`A7lxyp2jOG9D+~4s9zXpEGZZ=!7`|;i?kOoF49Tj8*qES<_syuV-stnI*W4|@@PhkAD43;X9s!xxcBIY^Sj-1I0JTW@MrqpMZ3tXp7c2I#+Ye6 zR(JAA2GsDq5t`e?w=VF09K2`8g*n1Muf?8H|0NUX`&s1e06z8g-&)5d{THOEU)w0_ z;PJ8c8f2#COCE1r20n$$#-otk^lAE5?z=-D&5g`iEWQ24p^ne?LeAX>u5LW%w>0vb zi%rrvHTFtVp?UD0-3sT&=yM2KDnS3mD2JSVyO}iI|EDt&7E*WWQ074N$MXet$PYt5 zbw7cJuN|}h=+J1aZtGmvj!<1m^iRk{Dw`R@3}f?27rxFeLw^I6_0UihU0D+}lNHmn zlsxs&q2Ug{&ezCul3CfjyIDT{6wc_S9B0k5#yT>=w|IJ7ARdE0b@q~B-0QhJ2bs_< z{cC`M^(Dn8RZ8w8@qaWnL{?7MIcWt2;{)J|G9QK`vBk*w?i%nS{Di@cncDISGU35y zY?To5Kz3Fnlw2IPbP~9+k-N>n^J$F@#H_%N8Xpf=>8?m+vYdT(jN|VZJK-UXEj68U z+3Ly9+v7VEm;Ra~14H`~EyOxfzdqvBl<7$_V2clv5!#x^K zx-=Z|(Qxa3NyGA;VZ70?|sxe5dF$O^uM9soBeg?(JwLP zpNoDqzgWx9PrFwuW(YY~3GIq*3(RM|XIne-#Xw?IZKPdtSvH1Z4%>pG);8_d+?~S4 z5Pg4w9UOuVwvldJo1^FbA6lE^L}ZuFuDf@(6YDbCjGmta{xip!c@ZYu5g~k%^y@=O3SDmdmyt&7AE8{zI(8DvoqL-|X3b z3+5~y%{)zVW5?_Vd)I%jW-t9V;%&;^c+M^3km1-q5qLU9?53f;t=0zMK9M;(kG#aj z;Eceok$zL0%_qc>2(KTrM$<)n+S{}lrv0$_8fU9f4{4pmc;a7M@a3XNdts6G{u3j` zH=S3#0bh;cJ{3QzIM5}WdsR+(#q6x#`1yQfCo=vyzN&2O=K|4(=OgroOWFw*^A`M_mM?N%lDB5m=lQ(`iuSCOMP^GWF2ak*i+?wlIOrM$F_ak zZO88;+fQkEKA*7C!21@)+FM^8OPYL1$h8mhePsJWm-3NS^DW$3(Z@%&J7xbbePr*_ zp3g_NKt8e%ZTu4)SlZ@Y@QQzB>-^}NzCN;zf|;?O;Py*4zvhwt*w5FL=b~Jn;wwta z!`F+Xc|I}^XCZ8-zmdK(AK9Ps>X(mfHEDhynSWj-|M>{!Qx0zh5>3pjuw(E)L@Ha* zUHH^>?qj?mhz={qpU%7bn6>kqxrjHnT7;~U+`9@nW$fJQ=iL$H9(u>lt$N(K)ibV~ zy97MS{+FE7+$zaEgl*Wrwr%EE*j_!WFRrKvgiK`;8Rz(SocYz4i#nD~Eoxq-`=aq} z*3P2M_1qdZE99UUCm zVIECi7cyo?4drBCS3CBljc2Y${|n!q{4OhE4V`&2|1g*=)-aLZ&4>o;0^SUUs3%yJV zQ&0U-W~H5r?Vmdr3p0Kp+IHy0;ms&>KFvE+Ms-C?O^?>&>X$n4CX0WE?}oNo%Q+_( zJADK5)N=X-4HD|-&O5Mc?Yx6INyUTsR>>a)rfR_kT-c41)W0Zgh%Ut+tE= z=3OCZUH#F1Zo$+AOq>JR3)4rW2bn)q^9x1H^I=n05rO}KIX;FqRaWsL!sq3T?R0(~ z-xc835#LD;l|&u;OEOKeMe@iLl&qD_(8N9&+0&Y9_h5$=v0vsWQ?hnBcG!}^McoUx zHLZUO-q?hk5)Dnc+F7#?7ep!_50=hvyZESztH)_we{|x#Uur#}q+2%i2F9<;_4`B% zJC?-?C6@}UT)G;$v=X0@;wGDdqwM+DU6dD}2>uB9qvWqMqip^f?hC9e2+sFp*fe;0 zd9Y}{^|fNhz4$HD{z4x)=FGQiUHe@&SrIZ#bS~ez{IT$?m0uTA-x6S3c*~r{3*WnT zz3BXzt1^pL7_*|DeyVS)IH&DX@=4cC;J=5Tc&N*!jYwS0|Nl?>_jTZr9Q*%m|1P2( zzx}&~@%~Tt?_bF?ko`LXy!5qyv+GInc}0;Q-u$5SbVv8 zkO_)cYQmSM7?3hk!=y;GkT6T_MH6#6w{`= zpV1{T(Mkt< z9~7O-oJTst(d%A*?Ws|I-JiKddfoaWOA|i@|H7gCrp3dM4~iQm)+h+>ygei%>#+IJ zW1gMj`A+?76~%>Sg><~;w#D$ugZz(X4%J_O+K6r4f*l~=YI=?1_xlTQ$nTd5;`cim z84FM9OjXD4H#RX<-(?T+O?wk8|Kaod_m!DN$D)%~!GkN{!4>e}E#7zLP%V^m>`d+- zR;3`5?=RzTgSIOT|Sjfpt+jl*RF2bCe=mR8~JzS=1My+bN#Uk zI?-pMOYxm&526FOlg^2|=t1`PGzQ`!K7}ZMBz#rXHfrBxACI@~eU)tS>l*jQ&{iA7Ahc@+np%jb9Tu zDm$QI`G3VDiVwM!@|`yy+rD~_V0)Cl$mUglGZTp+0k6(ncqH;(V_lSZ0{y8n>IZ#) zUUS}Ccep-ce0ds&AaoW1?`h<>VC%57;@C-#!Fx$y{g`ixm3fl!GB&QTJbpUkta?Qc z!qGYI_>ZQp9kW;Tj^A0#leXT?o*;J&mEVxx(SZSHFV|VlI7-fNhfrk(o<5fP>gl&+ zK$^69v?qO85OHFFUOp39$f)Hm$Y-Vn~Nn`kG;|8<91**4s@e;R|m_7D4I5}o)1WCQ6Ai|OpMzwn4iPZ55= z2K=>J7fceTR;M*V;>fTK_KxC54au$!tzKLXt>T!Ur1iiMFw1_DU$T|C2lvRcwjq0G zOyUA$pX`^`aue5>*O2G@Le>TwgOxq^GOxQt>pG>~DP-NtjH_sRA#|X$2x&3WbZ)(9 z`ekT3#@LDPJNUndv2$p;rc(94%UN#RA780EL|R%{cVJBBw3x~{?3wNC3RG^G66u*c z68vx;cDf)qzH18eE6SwruCCPh{flSugyx57>hJZr0|))Kc3v+}^v2(=wS2LH`x15T zd4x4m;iDVcN`r6F;$6_3WLFGY)V+DlmL3&Lr!|YwiDJIbp}oy~n@_nAHdqwDbrbl$ zhxgd9NDn?J%X5(_T6>92TMb^|!5*#63l}=W@dnQ0NzFTvyCs9|3-L7w$C=X|UW^x2WSMTyPgJ9iAOb-y3u zewUr9eBzTWJp29ElAZY9ZxP?=`|a?L(YIeuF@i#i0)J-{zLjQ*1ku<}gB^dk!#Xlq6f`w7vTfE)wL5n z+tHgtIzB+juad->v?CknWUGfqCmyEnvVqXoAKt$`Q`^RG1T<5^Px8r;fASxWOw1?m z?f3$PlZkv^$G^otdh9vAIeO-a9RGfZxn1DwHD8VHn*3_Cf%D$5=g*K2Xm0ux-H#_e z?j+VvbQLuu7JU)%X!}w*Q@QD4EdoS9A zBcNf``*+G7ZRNb9r@i?nJobTTN^7N8wFKe?*guZGE=oi%IJUi>_Ih1&-*&$J#oHr|CWmeuyFm)rSmyxE}g1ngM^n>sQi;RlR*UvZ9$dr4TaeK;&W6 zH=do;?~SM6?Hx}SW|b42OTG_gJU!YKol6cWM*qvusqA&p>p$To;Y~0!6%=<19>L<^ z^2iFWeBcuYo^7e=%rcL-(SJ^ zQC&w^yF~GlVakiH1dB(rl9k(`Gp$1*bEbK6V&%nGJ?haLIz2}w#F(Sx)0=@_^68DU zDpr=UZ^Y^vXf%*Cr^!zye^@y5aw%sJ4O=nX#8=gDZzr*CcE1+mP|Y}ax)kdaNZ{&aV)7@&?-WlCh_tM>%#0=J3y>WR?<5n0rtqLFDQ0U#f zYECm2ZZk|YxwA3t(EhanWX|ZkF@>IoN9P7kE2Ew3k)8GD2ToJGehK;1ug7@aG5cXF z*Cl(-^o?~dOdFC(qLImYZFn@&D*C|2ta_nf=8P{fpFOw!ss>~Bs$LeJA2MYx#h^{al*@iv z4PHGxQa!QnymQCwKU-Rw_`?Pb$$^ruDkv}r%`r-k;g zX)!k~Y<9Qr*ZT7$huO3%{b{jXZQ2j~Y0+J5+IL7REIF37%3!=;B7A@ixEfyBP%^Z= z>m>Z*jH%*Vnm2Nn1N6iEBa7G2P+Q0O{l&-NyfjyzmXIc#7A~67UVy(m;k}pCv=@wt^xVfgGGu|7zUHgS zC%m_S_td!9SJ@k9ah`tF!Fi#VH@fDlo4x1r*L?LO_gUp@C~N+4+z!=~nqqb=aO>!J z#i`?C_UY)`QA+=LV5V%COOZ8Y-w(`;u~+L|IlnQT zsV#eg^&I|t`)V9qzN$RW1!hLjXJ5fyD0?9=GmWjO_C}#cJlw{ZyLV<54`;4CtnAZ0 zXP!v@RMQ>9k$Lug7wo}Rp9N-KL;JgJI&|`k6$n|#u zp!uHc3*xTF>-l#)%g;ufP)XUNfte|6=CY>)Gux0?>Q5W}X(!JueAj!J_j`H&sr%l{ zdmHaJy6@Gz-^Kfnc~?K)`4qf?t7`D3_l zya!@)r>ReYg{yv`K21KLc-RX1tiGvFORwAQ^tS7UpRRs{FC9B!!?4{CypFazzo&au zOB2<^^M|9OCtOWheTf-v^YMN;?;9?0@-*{4lXv0Z9AIW`$KvHu($3($QROmArZs}c zu1m~H=3bYm-ILMJ)icIeeAbhY<-K-p8EX7#*e+Ct_8fj?lEvS$1A){KRt z7$4Zx;7RZZmI`nsSdu3?u$1Wx0``Fy49i+me%W@s+CSi!a@a zlW!w6U{_s5KkKliQ{bv@gPHk`d~?X9Urpx!QSRg9T`-pwjOo6nrlwMR@?%r7V|&7W zrndBw%0A=TAI?(aa^W<{%U)Z~9anQ~UpVW5Q~ShQIYS_XtzU+%e*^7mY+gaGn9xCS z)+~Ew_;5b-P-pCgbJ3=U^U*HOV@EnTuL9>oIa9cpvDdg?-HY?e3fU+F(N72(^XO+6 z>vPebl~FnK$P;Hd^GJ`jG^Y9V-yfbL?`Cr8pSJqo>F~aI@{eZ}m^6N&k21A&@aj*{ zN0F;ahnE$hpU@LM&=Ne|vmjuK>WKj_7tPDAEi}(J;G@xZgI!yH9scuD(-SE+E28Cg z&i{NAJ70e1cYlD4HfCjAiJ2*%S?U1V97CH2vA3T3oPEEe66cXG%DuYQ2g({x8avyY zhjmm-{+IThhxzuST*LS&j#M;w4&#?(Y$aQ&@E@GOxunIHu%7E1w}IqJYdDwwT9IY> zcugJB7q7i@3FaP>dm-fCv*@kfc_;q#`fnZEE?TRCpT*Zv&S?;g@^Ng0ZYRUj`TQ&# zYy9_yZX+&Tiywzh;Qno2pBJk>o&7|8^4C6Hq&^>0aZPWZkE-zI*WSD-y0@7mdXT@Z z4n4{_Amc;et@*}CJ9DVvDa&uc?pF4~=g-enPBNh$A6S31p|SPThG34c4tEv&QuZtE zR%IP^>1ft&&VrRlUGjnoH(>PGKYW9fo|2er|oy$(U<%EH1~Uy`t?n9 z`29#HitZ`z>~VK|t^V)Td{^HqsbA&KxXkfk-wPhZrxDIqI2pO@;p70G>zQB6W)1Xb zYqOp*kgYwOx`m@GP92#!CJ#5n0QKV3qZO6&=%wvF*`bOL8l9L3oT^VWJgXN6V{>pY zls+nt@Th#6v!w7{os!pX4Y2#i@|)nK6aG+JqiH9_Ijw%*Z*M=M<1KBxMgDpp&r~A2 zpn+aFv5|Q2;!DCga^eums7|XxTpy3>H7N%-FX+3^&)BdjlLO<2Zh7d<`iIWv-NDV+ z#5+A%-0VlXCksWNCxMe@e50%%P7+>p#&y}kfZfv|-jiGqk4Zl3`~JuW4;L>{ugFaMv(e~sD)=g0EjAKiFkSWW*1qMsJp5FH36!6&$|DThlw zj04t2c*Ct4sR@_FAneIe!s^3UJA^jm)Dg~K2P^u zXLYMj5AiRaP#r%K9{3)uF+CT$`8K%!zu@1)$&bLveBM=F=LoB;pD*RZJeT%`7mse! z_zxw2ygDwU4&8~{A3g&Q42;LaTs#Vg!k;(BzoG8_>hi{>t!v;q$51EhIpZ}xg4d%R z`A+(iYvbsf6Cw3uY!yH?{JcT3#XE zqCXx<&dTzL^i=c*>}SHhk{#9v?=)g#v1VVSdK9y96|ih+3dDz!wyFhN_?j=V-}c07 z>Td&1cv5{*JMf@mw*`aktAn|HlAkm%$6e2%Pnt)C@ITAHZdivEK3Lc6(cEhl>uvHi z*MnmNj#O_wI`s|4E$Wkr{|0yqG7^0~?u+6-K>`E1|u@#fEoz@=SV zh+-?1EdvK%2ET(Hnkk@-3dW}%JtkZUC(*&s4sGPjSFta8?MfF9rk}PvJgY6{$uqx$ z{k$rH-Nk<&d+rD`$*a@rhwTINnEXC?^`@{Rg&*cmJ=}*{D|~6cr$-}#y&k%0=F9>= z{EDsg+7iChP6|5l+EHHhU%q_NiN5)1GR^!#ZCd=$p7MHaK~p*N=B3O5J-x3sB^#`N z+-PuW+t!t zZouBD^=s^gRqFyXlP7Q%ocw8vvCHshta>akvwr_vx=a50r_*9T`SlM{jnFE1HSW4< za%!$Eu6>^o`Yrj=Nk0QOi5?5OBlX(XmAm%s(PNM@ZCYcYzn%D2L*P_v;Hi1lm1QP) zNj3A4fp{Q!*5_+KRQF%BKi_R1KjlE}N6!9y?MKf4;_atzuC9#2lf({Ol4Q;s@chQ9 zLy04vg6xdgxSU-iH{T1)3}Ju8z~ib<0yCpLV=o}9oqTp32tB{rw+_^NX?7jRi&b0o zJLZ7M1)ce^>J2kfF&E;qOI7c~%zv0SX>L=z-PyMw7$o;ry{&T)Xdl{D44QaeXLzl; zk@LCiTH%PqSnLW9o>!HJHLpvETTD^TOIKO>j@$6*s=t-c|5fIObz$U^HxXO%rJAmIhzpZ@U zF5k_^+wQzmeCD+)-gfNel0;~W6Z4}vLfY;3#o$+RFNp8mlUvd+ez_$%CYc$2HY>X}ev(=AZR`}a z<(F5UJeK}8o<4atS4NiOKlIw_PexYLj)%v;(vF80)|~sb&%E#T9}g@Of9&E-_?J(A z)fLD+Xt0&LJNFkZq(@|{$UczWk8W)c{P>GlKS?woi-QGbMPr^#bEt6O!{buq#?JZ{ zekR*D-RtMUemwOw(uQ!E-^R!R`rUyqY#=)My4zo^1@4U2(pvvOKG-~YF+Y{mA^1cK z!kcK5#pX)kN;rx#H>y6-EDsA`%#Fm`viDkl&-pHSc+z~wkEe3vjTdVmTj(6VxB6s) z?rxFHxeXkZy%U@n3;SdtcW%`mg>Dq?fkif@H+Hfu`;MQnTla_%v+)5PIRDTQ2N$DrHw7Z_a>PlS)_Fx=`+b| zPX`vvb#!3tKvUa*Eb`meo-9%s#f;X?4b1F#&RI8;3<^sIh<{vtTTfg6shudgduQ!L z(5H0|1ZFnFTapR=wiEi#?L_w7c{>JMsqQbVgK?MpfbEnG+>U2EB+GZMJB8~yd<+rj zE%tP#_6X5}j}L?3quh;C*o3c8H1-eCpu^wR);N$d#z%9L^zPzDV;?)^r_)-0^Q%7g zPjs)(r~eK9n)02D{Z8$lWM)A7qjitZ*S>tLU$}kG{&`~H_RZ&PKZY;+i?%QOC*;{b zD_NUn%p_AT<1Qm_?ih6a3>T25@r>P+Szdq)^7uMRx@5;Z?&T}{G&r;R-D zSu#R-tjx=cfo%JyBM+6=e)q{ll?$7)2_JvgnZNzpr$ZGRbc67nM{~3D@|=jTJ3o)s z-u<*&jxNs6b3>!LOg6=cBx~g2jFF{4~FB{i?1KS*9eRcf4A2_`_I#>r82##UCI^O9A4#AN6Alp~jUistUwbKf$!pGU< z@o;k-aCy)B_|jW_&p+fjS`(>^%*;#nHDhq$NwS$t1*?8lC<##fKsf5(}u zWyxRiP3FVwNuh3gUQz1>*a6sHYmm)dbAtG*OA_1J%TvwwDd;?VE)eM(&f;9aLe9kC z+o?-g_o!np;YGl=Uh&ff-Jg~$DW(3IcNQ!ueRVf8dGS&cKN|dS_R{A%1F4=fkdmzN zM8`SjAF;>xZNP!M>$>&t%#Y_3+I69g;85#O zfnaP}lCql$2F2wo(*E@{<6Zz>TCqppe?7D4+WR6_PezxT%JUyJlf%Ti>W)9!kEieE z9HvXP_EwZI7xRBB_$D3P*n3nOFClFX^BrQHy|fFIHVeO+FW)&zW4t2lCpwd7-Hnxc zgfm;2FL>+S>H7?GwXx$jPK@m6e_!L@ZH#GMp^LMjoKuND5p8Aag4P#jz?q-6%r_j` zn&YFb%zvP*N86Z>YMjPG$E<_b5vP)dmK$iNntIq{MEtJljuIQ8wt~=U9k8_0mS`9J zRxbHDd$6Esy?4#2v9y~{&mJw`NqhCsQM8gLXQ_;VlNF7)z1tI3n0Rqh{1BI86$qG!?5`ZxN}(*w4yXrPy# zcI$_p>alST-U&UOmq$-e5U(NH*&CUp@z3YeW4bbvWY>h@6P@c-&a+@#kFQ7kCV!q} zOZC6-w@Zdhb7V*of0%!qlT(~=zS}p>|4D{?4ZOdPZ1v;iCj;SyvlBc%`{PS}`K%he zyg}K4_^db&FQ0C3@Uj-(Qu`WPjmvlXw%>=(@9U?1@%bNj(*EWRxqSX<%4z?8+Q0tX z$PN?y;1**p`bD54x=$z+-Dk#Bhp!~BTfdu&>rjOC7||(ozVR$W9B4^Gvbi2UXh2>! zus=yWFddrhgx5B-a)zOcXRn_VKSw_=?XRDV?@c@D=i_<(eBx!NpEK!aBlOeU8HhL0 zr{r-?p9+Av3EoXH7gaydr_(aPE*bGKaM$y0w0D%Wtur`}_r2qL&tl}9C-#t!arTh6 z5JO7re^ZtDa42(?CiajA@P)_NHyW8@D$ir>NcA^yU(Pn_7N1KlQ+1X_4;*ZjJgkZ>(=<1yn6F-ap|JZFU!77 z-CCEHtPF!YPgWZ20l%zFhO)A<_6yX1n#QCbS=od>3V{z#R^9mo7fZOK6V z31!$L=?3sd9o~3re{2mjtNWQW_S^97912Y5YoBaEX?F-azNN<5Cwu1__Q{eK!@iEO zF39?V-6z|reX{JK=_K~6`D>A$yU=l+?2C_S|2N~Tw#tEh&K%CI#MdR*7JIO9FHG}v zN0y8JHob+cw6&2XY@1?2w67xABG zGn@%rIX1&8?*AffD}8Ig9{3`5;Im6Ii>{-b@GBnexD8sR4!!>;z566(HMbAWji6sy zUl!d`_KVmGzow20)IPC$2Ays12_rTMo{!%N&1h^y4{7M4%8b1~G%B(!T5oDUMOG|9 zR$PzGumo9AkDd<0*VV|1^N|&zgEH>h>fH0|?KOJ_+dHY>?%}47l1(w_FoLYOm~kBo z?2B1nR{UFQrRa!z^a}73st(TMO-(U9bAU6-JMiF3kF9%(acTC+veb|v_~pk~_#)>a z%dkNt%a)zu$g*nS3<00cfe1xRWs3hXv@dxU0bcQfVNZRG=Th*I1Jh(;joh{+2hRmJ z#O?L$MLr{4Q5TGl;O>UqcrWEWGC$HTzKSrP2+TDVCo`rIw|=$d@xRXS5#QP$=jrTV z{KoKpjf;yE{!-z>;(>aOqMoQ*Pn3E-U~XjFyIJiObVrd%LGm5;IorD}ub&3{y|tfy zzC=5=pN+xz%kQv{iFd)Zc#A8WkV(xaI&%r>C&@|W|K|I^Yh^`g;$|-|vcf!)Ys*E^ zd3kdK*Ooi1m!EHcp|8!-jLou=vIE&H8#{CP{QM=3F8u|(?Z>n1&>HAUG=IVnvqQLL z&veP`r!&j7Uqk0%eC0j-E#OPf<9Yr$>DpVWGZD5y+b#54I0-Yao5C1LW?q{#&;O2m z3z6lHjaFoB*DnLJWSQiPTw&S*!rq!&S--aXb) z^I<#oVt~D3${Xf>tMY=_x+MBNJ?xw9O8dQ@PoI`^=i1M8Khqu5!=0mLid{Vl`m*;k zO{&>P_a@GY)Oau074@tcoev-sy(pDxUBo>Xkz-SDCI!*`xky>c>p z7FGl+;yVm*p zo#&uBLWdEz#Cb-tsg@Cgo|*!!aDJZhefwMNpCQj6#!G^uzY^fNVcc7*9W`)Akel=}=!kRjy62vw+l?3nmJ7D6|`wxQ$%tFt0* zpFOyH`%4~wf9ndyc86?Ur>|cAB`$sz7r1?-T#`O+KFxjj z(RiB=Gs`!W3~Ar0u_-y8t65nehTlH#{Oz*4GK=_WW1lFqjG?4%w zuS5HVqJ7374L(|-{Wj4)<1(}m{~@&R;6q~@%%S66e2{l4^gow+?lFa&5$w@}_$7M| zm!BTyisoHGpQUsHOA_xYtWzl>g7;YFF&-dAH58I)>C#My&O#E z>XJJf9KHM~^8dVtfE~K=<^ksczxu!Z^awGNk)B)B2XusV(+hm-VqEk+ZNFo84#h6Y z>&FQL^&^_?M{|Guz`kg6`=K_SvolL{M~(G8K8Jkq>%{ZVclz;T>0WfZ^sqnn_!!_# zqhH4%i~T;E&_M9{@O(~x@PX&6cY^0-`S6|Pz;^-g4dOhtLi+J1VDX*@fj94Y9_fYT z8AKlKCk{wA2RH+!^{{vi{a7*GedoNiTX=qu-vhq1pYZ%E-}?Zt=wH?z7HkQrdg`s~>t+U(Tm5&yw~}_q$@8 z^i6duo=eZ1Pf;m-avFJ8yJ>!SS~<@n2|SPUt-;6?&p2E`%ULUD34cWiTl3P{r{c&ud@l1?;-bpvHSmX{?X<3 z+b{Y5h5Ov@{x5L#BPZ|5{%atSenu2O8T8-ST_pjcsak zruGNmMQ0PJPRX|K^8PLF9ocX(?}BH?>__Z6lGctYuswBlli}PG=WLz;^DJlvTL_)M z?q`MEmBPAGn)`0*&-mF#A9IeL_S|;zp2D9|!yP!BWxUpyk!!F0Z0fCsGav743fy6? z4ct*}#_FD^?qvm>Q_6W*I-gkjF$z6KuQRNrV^h}8%sdsnGLiB}Mtb&yKRE~L!)D^Y!lHX@v3lycjDB>qz?0nPqB8_HzzZ+Y zclE!nU}Sd`e9f*g@fQZOr;|Ct%jo#3f+BmaU2-tEMEB{gm;;GbOiz@L1m6c^HI4C2 z!&_0x)U$@AyIs=EtNsG5M5$vF-^7!GW7GD`@~xr`VAolgt=KU5DD7BWe23)rh=kw? z6;^MR?1%+T?JLw%S1_WxgR$90ecm~jFOZ&|b6oq1;8;6e8aJIY6G9hj+|t040-n%b z#q(42UFTS+9>q7S9?218D)(%a$Ez6!(VMro`(DwzzQw*8e}i^5f!7nrvm`j8yBe5( zNT2J~H^!@peXddBQ&}fW{Fc1pr%krMMG2jYcMW*f`3D-?^C&00O{OmCSu;4cZpC18 zhwL5EY_sa2t-GjaI(Y+0*3h7fZ&Sw>w~nv7b)?86y7r$la|CkPyBAdLMd7Iwz9Pdo zmGfL@Ms&B0!dDQCRKkMmMsSDMChiPi9eQTj?tymEKpDQ_5bO8llpz+gr;PQh8Q5e> zKal_MZp=Tz+~vYLZG<=qeNVBz)f6<9_AYE}nhtQ|@kup#gcEN~&O7Txa^P(I6n4G% z?m+w~o(*$%GsyHr)|mL|_ydZEL^vm@c&+s_6Z5LGk2sW}i1@w_+wjMx>4)%HPurKb zlx?lAVebNa%cp~P)zz@a)b@rw0{CYF-A%zjWz&B6npk80m^o5?4RqJQee^Zv`L&Bh zt98)a2)i!%Rd9RdnKkXRf@NDX!Q%T<+?Ny+zr(9K+i@3YNHi{*77xV9uYF8W@&gMz zp!i$15|H?s@pM&tj}^9cG4F74TY#hmR5U3|C# z8TTx_U~$F%CXIVTu&$!<$4$f$l~qJ3C;T@JHummK%@wD&?6Wm}^I-fDqk$zjzVq%t zC71gyg5Ew1!%N~7wHL(q70_AI%&j^pe?57A4&Nx2_a75H>9&en(s0XSnKB1zE0uW z@;5Z}Yw?iF`!x;NI9=M49b0!Q`Nh)#_NQs@R@h98zw$T#x$PqpkgoI}^MULn(S8lF(c#$8_-mxA9r1rXw96ifgwEGW5fga;bXf&2 zMc}f&~M=>9F?DIWTFoG%=UFsd_8bEw)4oubLs=UrE~0cR&jK{*tFlXuCcRz ze@|t4`_0{6kptu5)X;bv=^les>sW6zZmQ?d_|Z1kGqIAm{viWVqx^19Y$R zAg920oK3S98Qpsam?3tgv&&Sb&g0ylJ-zc|Ig23Zo}b@^f8D(UEP`#IHMRoQ&FeX* zz7c*;v!^Xg9mF%QY?7@4FBhA-tuMlNtpU7_;!e0^knvrpEC`5pqM>=}{H zxn7Dn+CUu3bm|VPO=6DTr2pO-`yI#%`Q=;7Ib*+(JH47LHWK*Zx&JME%gC zY@1|hY+507EgqT$?RxsAjj~z3$;ylMq^pmb^GbjJ37D>f{=UOcvO{#f)TPl^$tyZm zy;iOukByasfy51blMHm|?f%|)F8Pc(XSGiZmw0FEnt+vSuP`Qahz$wQe)^Y=eJ(kd zfhIF|6T`)NQsyE4>sZfG92fiX-a(c%A-7WO>HLn?vn9J&1B!~)6o2+P?vztJRqG7L z4vDyT%Av>KHf}7<8khF(;eW%bKxG%_E{G>uh!Zoq6A!y7H3xcI=J0~}U<>mhdyeud z#v7UD@k0u`M{DKQ&iIM5)*SKOClx6$Jk6HidjqidUJRi%I zuVxm_ZmDtNyE+4vkN?W9)jrT0-*v0$`8TvBI=nv0{~Tz<(zO%c#p1S&>r!~aV znMliGY^d%q_a4^h{zKhWJ+;}6bCi3k4e_?+vA2_>@K_po zD_O2@QRHok{;J5OV% z<&6Kz#-+h{&bj5l+ICa_uwrwJ*PQd&H0yIJ?~Y43&*IxZF)j_|*d#-SwpVlClK3!6 z?3(7>A>!An3$fc7m;dqb2_BQ+G1VB-#VT{ok&UglBe+qEud)obupLx7=i}vGv zQ5|B4v!qY!{5mA{8vDY)QyXnHfTuM2Lo{tn!P+^*2nt`iXGAz#eMJ^$pG$xIPhb6! z{QiHZKXmQ^^qr$WrcCqck7!nZlrsL$K>yMS;uYzIZzI3$8iK1AuuVS5*9%Mk(!X9< zP1%9;!iTTq>V?^Vb9~#sL>KtmKk;+4-_l?EjLXuUwEuj5`)i%{=h1$%FCMWx8QmvB zJmOGv=oh7%=s|tyCiK@#?R4m-6Zphmck|x`?O2(O?8aBKqnFpFe=)jgJ+&|0nEL;Y zZc;WLD3@-=)nw@=a%PrpZX#agXz1pP;-?iGC7-WCPq9~PoO5r4WKaekx{Uhk!INR$ zD;|6J0>& zYjtC+@oO!|es$s=;i<-k&v(CZjx9%QR3BdCe85KZL1P2@^mylfW6z#Df_`hSsdLYd zV}o>|1I|XaaUSs(#&?WZ^?ZD{vM_BpC)yuhZ?C5q!j$B@kj|m&93p>Dn2b*G3{c!C)5L`Ci+kxxr{lHZXTo>;IuG{nA znthK0*Qvl2#$HgY`xC^y^dQ$2!}LD#(8gq9-^>1YDvFmF%TYpnAhGvtF4{C zz;EYosFO}EO8oSH_|LQRKZK`Kv$Fd*TH7+U?~pc(arEHD=h*wa$@gr}Rd)MyAL+6a zy0JNAr?oA`PQX6h=EfNPi}(s_Utm{+CuHr4LCmR@KXsR5SFHE)VOJ#C1MVNQdt6)z zcUfGCmb4!2;Obw0?n_I}jM)y#4ur#l^Kp2aGiIHd7vYQ4og$CJ`=@{t?_GB5gS;<9 zUpp`=CT&z=Hth&L;alT-CGVQMWv2LI)UIR>)3le3QTq;KqnI^+jM`ho)%DUr(uq+k zQNCfP*ci1UJ)cgzS`B_*&g+uReVby`=2H(bYOmpgzMgqa%8gO`WF9eU%oDp9`@S)1 zM^x;=9MnHo{O3=d7`1KCi~M7q2iX|41&UF-jW!MP|MH+ACTOIMQJV^$#<9Q5i&4WL z@?5w;F?QJ)wVR!?r$v7FE_elsrK_@3s(Lkw=c7=cgFI2b}UCE zMr_Y4IvZQt56d0{!Q!K<=cj!KI_xiQ;yuPM&6sN*lwamO%6M}lonhcTKlT5Zd;9n(i>v>Cb~jHv zqe)13=w>%T6qHIu3Q;N7ZV;?mZGqOiYGsq4P^ovTXhooA6HsW=2UoDP#@-}E)Lpf; z6+PP-V%$zyr z%$YN1&QPcGK83oR_gdbououR2XWMHOt@pHM3NSZIS8&!&6()UdFJsMAh2NLX$$!}L zb11)wc753LLCT*)A3tpQizu)2oenPK5Am#l=|xqSd^lVVqx=#1O@7Goy=!~d z7icU#Wchzk{-^&p+P|0b7ila%Wc|ORyhZ(){Od)2pK+~}Axp0N)fwgmWXau>{h)c_ zu|J+FOGe+4;@=yQzp_hftvv+2_uGtz^M3&UPvA@D{LkjU;xan_UHsRXUFUxfvRD4^ z$8YLge}EtRLG~TpQ{mlq{vXGd8&5y~#`CY~_doOe6TkoAC%sj2TKeQ_@FUyGU97<* ze=kqVaOq>mZcOD>zORwb@eg_r`Jnk~9Q_g;`I5NOXF>HpjLc79FWe0*tJPVQsi_wc|AoC!{yMR&(^{Se!MpB;l7ZZ*6HumHg^MZ1Hei5}hT-Oo=zoDsLTPri8Vp$6iC2^J$6d z+2v}-*BQf(juf0Gw>u&j+H)6P;@eX8`D5a-CsXf7^}ZqX{!iX*|BvIR`hT$3ciKI( zJ`=)Q4`K zrn8m&KT2CfGxV8z@h5i?fyLZ zk*6i5$R4kcYrGg!jk7bZA5&V!xP~|{e*tNq(U?*9$uX;Tl|LbTvB!PdnDI@1btlJc zvPo_NU!r^8{@yL)fz?Z!B*)Yqwb5zQS!Za|;C^iqt>r2Wc)V}U(mQhD8lHmb%xChs z6`d$eGGP^M_#m0kh)=_pSi6W$ZsqC7g14c2$s-T<{Pvee9l#fFj7jSh1N!L+4j;X2 zx34I6hw$GI-+vHaW#C(VdsS(3`}jy{JCz1K4f#v&`d`}h7RKHOhiaSp=jl4VeZL@| z!_zhn(lqg?-JZhOHMGZ>yX4O++$dl3@zZ%pbFsetA^mjbe#h_k_oVkM-)hfen!EDP zOZj(b|9&nuOU-k{XiJ6$n9YZ%cL{5!wY|Mto}FMN=dyQrr`saVY-%4hgujOJf7|YJ ze(ak(FLvQai+-Ry%B%fWm+cdfA6upGz-k;g)AorC{_|^lI@GsPd=c->jyAR7XO`Zd zy@$L_UW+sOW^-e^iJYT+L)o9*n5tX2{t9^-nJ0bJ>1KX%8GOVW^VvU@-y!wlujj(2 zeVoc7qfW^e?#q|JheP?sD4*7fneajx`RK3wOqBQCeC+}6cw*S+dy9mlCC7TV{7g9K zyYsEpGygS@qe8b`L7(aPWqAfsDwQ6l9Z2$euJLM~bDZedSH?`@}9g71;J}Qbg-tPO>?)JoUN1V9h((h8boeO_%^jz>SovsXA zbTAKSeh%kY(R#t)d+4T_(dP#K@!{e>7B!fqOS{6*P(FD>@D2Wyc3f7`$sXugX|B9K zKI{({HI(4XYiQ5WGM9~)tJ3gny9oFYUW~6i^7#y${OLdF+qtLWo2#`S-t zas4`VwbQOM;rc%H3tXq@?Y~dTAL0{&Ur!AAw7%dKW5-}{g-yBY>{;Gs>uf#Cx7qp8 zPu7?4%>`avSqA>we#&=r_4P^<-HQI5``D#_<9z(U323_Xr2oH(;g`id-Uj{&@77q4 zkp2NqY+s~iS42KXMa;Q^_ufkBAmC*)as;}^R=Ic}KI-a^%3#x*pnNvpKBxI^#%sr+ z6ZswDYrFZE!V&YUaE9)9_>jut=MmspiwC*Wpj# z>7#=H{z{p2(09LT>TYwjpF2dj?%fn5@KKgd>;|t3X@_(SojH(Sx%@jt+X-m+sApF6 z1!$sGex&%suegqR5WvI|6R^IX#PlzgVxUQgT2Qb z-Yr?fUG8(j@T%n0amgLd9my9`d|ASIiIM^46#m8Ue(^x~QDvAXPm?g(;@tn)^S#gMv709!+rS*QH3@IB>6#MxS8&lQZ-d(@NQOc;C0_LhBZ47hU*(mzux+e>}eUA^v|kzJvZ>7~e%7 zFut!ce*bEGulRuRZU1cV`cGzz@1*qjN*<-g_bFT7NSza8{!YtK=?8{;;BEZ?{uJLN zHi$RFyT!ZG6-2M%-(*Erq#Is7A)U4#k4bm<2EMk+dq%wh{?NP^FEX2d2F+>iJgGP6 z{FC^F=SjVRJ*%V06WK7NH`wz!G_87_b%gYhqxpdr`1|&^;mvqapvC$~*Hq54+#b^Z z(SerMG5jBxqMvvP-}Qee-{H}C8Q(|q|7^Z%K0BB1`agp2`p;f#>nQ$@;yXHH{6fC# zznAa&Kbh|%yQZf2voKcH!&w^IqJ9p+9;o(&3&~G=Mz65eawcnDJ8fz&=$d-N3SWcT z6~fQPZWn2WJZjtW8q?6I_S3#_emb2tDqVb_cDA0KPN%I(_bHwB8Yi7LE8Xsg+I?0! zKW(?+r`sPMo=UgVGr>jcgBLy$S`F7pig=g$NiFXQaa^vDkGG0ndN-zC<)(jQ)c7EZ|% zpC0KT&p`4BUYLC0fhMW*@pZ^cM;Cky*rK%$(gk;R;?o0-kA}8oPpL#Eo|O6E{LJ$H z_qOhB>wRxIdLJ<;(t6(;)G1w6vOZDKr}tHpev~tm^N_c~!y3^J?NwXld%B$Of5?!< z$LHZI27f(D+Ku%8=njvq8@kAMnr_IQ%fmcm|Lf`edo%NMx9<%fkpFAsPw5#2u{p>Y^*K`yoX&U6F{{)0qz5X$ zo@&=Gf!p+rK=fFJJMsehpxVb86kGX-*gkC7@?~38i*B+5do=CW87gC4VxKv9%x%^k zukb{+qi4%z>2JNnwt0SRQ|*QxrQN_idA7b@Xxlg6SJ|slXRCCk z&4S;OAAra6DX+E#uvN(Rt$S4xjB!>tbmT*V+pqo(rS+@-Z~f|zbGO9*koHh| z4E~XR>g<)qg;rG4n{3ly=PP7ajy#X6Ca-@c{qF4Cv zpXbb_3;%zujnLuBv741YOKh&%I@U>=BigZtbDm}`wD?oEE7FMVt+CYLhx1Wy9D4Fm zM=LVq5cI^oP`3Qpi~QR5apLw?nXP;A@4pOQ+dgg;G*}cH37<;uY@}UHZs?=WhW3m< z!-nR_po0Nn$H9wA-#DZ4>BaUcZtv7|MqY`ZT?~8~m6-;oWBgUwTV%C`C6lt4&vNmPtN8 zJf$Q5Ts$&2r31)Ta0TapHRp5oa$c={zP?!Y)$%*(i}YEYudjKZyM6EHjQjhZXicfB zd_Q$aMr;~K9LT(1KD;WN-OviYAHn8omM*aEQyy>~Iu9EV_9??T&uaefkbR0Y7iIjE z*?=8Y_Ng}JmV_re_UOksGgs$|uvfEt-*wOrZIunsAjjJ)koU+VgFe+ry^joRefW_* zrs0vJU)!U)-DXU^Ytf3XJ13ZA6E+b)^;No|InwftNw!kQaob*DxKlfY?=#_e5HTRc z!xnA*2mOR^UbT5;bxPlHY*#uPc;>llS8DEpH4<`}1?6 zw=j-w=(v(`j(c)q2ZrTF_t4+{`Lm)2hRu$KkM&L|@#Lh>f#$?sp)Hc(>cg*ie-*yh zeE9n#srgZ7x3zB3+Qg51NU(Phg03s+Ybu7pm{X-*on)Rr({gktuUolh8il zYtKNF+)m${!SPtesy1)O!~O?64f#v`U5!Ck1iU1*XAYmTXXlQnzHHS8&bU7#*)+nL zk4MC6s84qFqkQYazeakZ_;M8G?RV<@g!4|jv?t`WX*g}V8+=IieHt7ZcxN>5m_M-} z>&)+r$a?ZHf4=JCmuZV>A)m^tuO+M(Y4f}lqzQk^cm`;%;N|jOJJ5=DHG3ji=+}<# zw(z>|?$o>&tDy~L?Bh|dZD%kunD^L|HI6P&6#Eu+#TTYzbxC@UA*A~5K6M_xfwaE% zvVWeoEq{x2^>gzCE4ew>Y-yw2$l*DSrN}CH>c_y>``&wrA;Mgyc~gCwO*v;DLw==4 z=cMqRfcBg`pCFHP_Ap~=%M<9$$2drioR-Ge^iLDc?g2)7x_{1G6rz6VmgD%=zn^}k zA-69C&o(b5dpD0EP5sk3RKbw_Nl)n@>)Fexg`OPTon@CN?gTJ~@?OBcj`p#XzX^KM zykqCpeP_(Y+2qk#QjO_@;OZoegg+4(%Ktu`_vvJlC?j~H8`1A;Y51}ODE(2s@8bPl za4Hp-hairWcsE#sb_Qg*~GJF`P0$ymzl_ftzUW2vHKT7r{mvV@!*qb zd(Ba7H;1Sz%rdY@jGX@h9Bdze!@_58V(64{iJWg}vXNDl#bGvDO1q&{mr zZe=V}`cU6Kr0}dgC+!o-4w+=^_VE;a={p_hv!a99z|>qWeXol8+IhF^*e&?2Fb9<( z$JGvV$uk#mJN?G&+~9U~zN~qXcFX5idG`oc z$TPja%DbK?=cv)zyL-XLvn^vACq=5sQwa`5@4diF@w6-Uv2@wxJWtur{j|mYV+w~g z?t)H>`lY8Ysq2ez6C%w|ImMRoLxY=vKhIu=remh0@l!mvw@7(h#O_cY+c!;nK^gc< zjbq9lX4^$*r{-hfP`d2MxwHp6sOD$swbD7{8)EODxkv8wgnJ*XDF}C3oUzt@9-Ix2 z6?R{~)^A4c{KHVQd0S3l=av&Sdw#`S{_er$Kao97_RQ^{ksk)OJ=U0ip>6Mh|7GyV ziCg_$Hx5eaQHvN4tv@w>_MQu8S8dw~&oFvasKS(g6bnT4r{Q{2f$b9;6T(p z*cDZIyG)kqL6_oxCEveF-;cRR)W62K*yALd1T>1MT$cRmeDCzq)=~DJiF}@%*fxKn?XsgI_;;Wuj~8^QGXneW42+r}h(% zqI-o(vskOAWQq8rh%$Fk_ZDDle0nEm-(&Fq>%GdAG%w7y*LLl{#t!2te7g9M6%AUP z(_n4qS$R`e`(Be=c57Le;vN|OBj@UW2JYEocvUig`+v<&mWFf>wkx9hRTAVcq8{YE z-HxZoE8jfjZNq0N%s0tT&HpawI>Z>)vCk;ICds$Np93w8yrZYw>M9g{=EwdF{v@AE zj5+)^e55qVXZ5)lJZ(TWibppfe_toB#}w9wk;g0Td7&_-HIU$I4}Agc>41M%BBN!G zSKJE0`)|@kr%mJw+INt-iNk8OpikWD=S-S(N%i41`s+V5JK0vnJ8M|=*$=)F)$lxh zf0g$H#$jEq&5{XnbKH>1W)W zIdVI^ulcBFxfMMV|3E7d%`Yz6?Kj?wHc^-STA$>pxg(LT&u$C#OrajZ%jK!>>fa&W zHO^|^vRi%jxXT71{DX1>+cL(zB-VtR(jDF?dThBb7U8GrBaT zJO6nF{)iQh&4~R~ANYgcM!qjvQ7nVP*nbNyI&G%CDgtcTuoMr+vDti+G&f@-T&tX; zJ8L|p6RW)X#+|b#=dqeIz*(j=%CDjSzox$`qq#@V6Fl9t=N!I$J)I^WWc9b3^#85D z8~XaoT7mw?wN@Ar`z!Wnr@wV)=F_2Bl@i|??3o1^SstSPw@Zate-UZ zy>hMO5kBqYm5jKNzTMo0p2yk<`+w4n|Jg0jn{)@&GxI#H%iZ`mYYqH+*1!b~k1nh1 z+J`Q)inJ`|C41DP z@LA)svaSy1R%5lp^yZ3>?z%eqZEuiMIwWLY8aIs8-(UH3N0596!$n!i+g!#r2r zSj~MnRbKyJsyK&!vv(8E`K))F&=H!ZReHnILf+EPIOFtubUt$2S^F@LJo7I7a^m?l zVq2`F|A`V~&r8xl<`R?b=;)MfO18$A(OYC|H00CzqKWl|%b4;oeLp%H-$7)%_L6OX zmXdz^$>eurr=$0-WqpyW{oNhtIE?cj87Ivj31HRQbBO#$3S*zK(^GZGKl`)LBXj>V zvX#7fjWb`HUDt5u+_lDf@V7nJ)W0!^cqHf)GqS$j`SlfM@*9Ip%UiitOS{L~dMoLG^F)?pnI=`8+eQ-skgq z{lp%6Jj-esl5MqYbLB3sMW=W?kN*Qw|KEOm!>H9+S@mycn<)n~7W<+F)Jo#!$a z=Pp{8a(Toe$%$QfqIb(6#&9_8Q#<~~_)G#%Z(p}zl+J#fljW+<2Cx5sf5b<@ zJhMyvtjVhD3~+9w8r)Yi2352_NWEFcUGH90)kS-fb+mIM_3bB~qWmqz2R+ME{)?$~ zn|(H6XNmC~{uFniN#;oJl5M=oXEwh}Ji($4~zcQs$QLTH}#XTVKlOocgWRUDeQi z1>afAwuF}Xo}abOjDLrDKzU?SImTRH%ezg3@Mcwx)v}TwYY-bgaXSGr7^Wk?W8c;h#51;0J|8*Niy}`S5mJZLz3G(M)PX&I@ zx5sZH`@+}ZlPn*i_2lz`$L;8x!eI`$ckn12=79T5JXX?%$8*6wI$MZ#8ondbTd=im zy=8=Z{11Vr_Naf_=Sh~K+cEY>ppSR3ZQKD}oW0`ghQL6xYYKGWhex)cAKx{wu-*-A z`{Aoi^u674cB~m$C;e-mCwsz{i_ET-)F*tz(V@08@9ZY+7;wJ|OwsFS>EGp)1y9UN z!L=1UEy@H}jA#&y5Z{>pc3Xl0TnFAOz}t3_IXnk=Z{efk_+(0kI)1jIH9xleE5Ole zekI7GMrcFywK~gO95yL@gu$8cF|J_7c)wNhyzb?(@ymQ1rkor6GB+#^Y0sUq$ksEK z^-=Z)8<(YC)qzc`NPMsNt9kE_|4-|M~jxBNc_|E%Jv@sOR;hYaso{)?0L zpZrNFT~)GU2664W$lnOBtmoXiWXhp3)3XQ~3-i0{Pu6(jXCB~t7``Ymg|;jXGmhxS zi{r@uMq(YxmePofu5uUb6itVTVS2--*k}Bc8IK>-)+O*u3Gsph>9IXjX4&^js&75Z ze`)I{!>LF8Xzb~o5(>_Lz6x3pji~+rys7?h|0ukhYJ=oQ4Q=S44b6;U1>^5Qjt1dr zVr1;9D6m>Q1*XM9CJ2TPJwbJJP)9R7pJ&Y0!q?6C{{dHyzS8S)?aCQ$wPY1oQFq+z z+P7YN!T3J1*2&U7@p^l&vd4o>Aa^kOR6&q5Y(T~E3AzMz^$hn_daq^;H5Qy%aDN@VFFaFdm7BKI@buj0;`Uy^r~$=UfhYk>iS zv+56;?47Qq3%augqvtGL*e#r`qR$r~kC1E0^RvO3E4Q-)+|+`%)zHlOXF==8iwWRI zwWVpJzZ!I?^HXjitT&B}4CMgM_S2)@JYaB^~|Q9SJQ?o{Z`9F z`Y!lw)ENXP;B>wj+}R92ArtNXJW9J((I(+fINbzIY(oE2dxNCA z>F2C5R`mWcCOT_OfTxRRkf%FZLEBbR$3FDC$0=I}zs@%U7e9#}DS5D(|L21{(M3J? zSw~3gS-$zCoG)O_BU}GU)+pj#t>r?<$oPD82IgSNf7$wyz?Yrx(78Fcy?J5oZEsbW z9{;)K;xR+HS7QMCp2OIy930;LIp&8Vey>xu`$wkb<|-4p`F#^zR>eJ@?Af~~gm-JN zUh7-gKJESb_p_q=O9n*u&1Js^9y9yQmqYG6>=Gkm`%69cNmhN^M44ZcGq8(3NxkrUx%@douB`eWGfzD;(Arx0Mb-{k z*4E*de9Y^g_A&49QlEEK8T$dnlf0X9tgUYHvmdi_^~WX7PJ~xpQo(nfGGx zSZ|dpw?5<=U0?mhh0oVwL#+DZ^5<`(3b+U2P~I92y%XLT-U%ZY?0U4P=x>J6i|LCW?WNwTx~$vA^W0!Ow^rZpxh+1%%zHK~>zcB#D{`Ub zj(pV6t}FIleOsF=@*wHv9c$~Cg4lLBt9b73pS|XbL4CKbR$mvjc_IsgS&@U?7yair zzTMK66{+Og&B5%5`naGiJ5n9YiA)Hvj^{gPVe1p0w5}e+{}(Bvm_1`j-^BZN(pT|( zXKCe7KWQCHE3Z)>?z{-vBmE`PH{WMI)kb=C(DXdU|CRi2=KsPursqEX=dLoJs;V+Q zrKH!9e#;%ECx`dyI@8m^w=(kF{2=i7_Dkj6XnHpCtp17VS;@1q&Gc0A4DB{OzO0Ig ze)OW!0&A;>@pbSi9BW*SpSX8_4S7R67k?py9pa1L@n5Lqd8;=>o-6-a>9w+4-SB5; z<)5scz8Bw1#ywbaLKym%z0Y&vc9XO)i{md=ih2IU{ z78*dkgRHHk#Z}%HOQGdbtEc)rpO=VxJ+f`Yv29eJH_ofEuP$ETt^UTS+YZ7{gRz$^ z_(sKT)%VZ5Ej+E-8z66jbT{dN@-KQr<%_(ZqA zG#7j^+~@Z$K!&-1pEt77yJKL*#BgrK#6^Fj59AF^LvJE)p5;3Y#$PjF%mhZ>NS_y- z`k$gdlQpwvQM>7R0K7fPH_{(){c{%oE4{x$h9igOY$tE%Z&pvJG`HNJH?v3j(@yfn z4|;ymdg9;_7k42mjSV(CzhY&F#^sjl4(nRh7mnS!X<*7`|5imxw{+GJ&c4r~b7vvn zX5ZGc{1sc@T!FvRD)g6zA>rMt2Zncl9NBgp+4fvozP*gki27j$(8Y<2Uo6^7|&oVoX4{($J8t|I0bcI*Af;)D60 zj8*^ouTmJxjC+FN!Y3?=M1|q6zVz@mE2kRnTY^ zG+O2L`K!I-|61*}c(y4Izbn5`?F|}pTM*k?2s#zL`p*m5wA#cR_*wemt6={Sc`m*9 zr;M%Iq5Wg6CHm~1S?N7ww;j*@IC_wD0qKWYPjJseXZ!+m-p^TETlukGNNP>`DfU|S zVdH8lwaOdO7dN8!)s~v_+QEUYup7RlT{F;Y(52_q4s=EDtCI~ryVHzie$68(^SQGh^65dDq^`Hs*#B=7eUqD-sx7(G?ygebUp}3Y=A>l^|0e<;-pE*`8<|c^?$4 zQec&$3zh;4{jQ1kZC;*tD8DJMD+%uo^WGc`l&=iB${T~1cQ?=CeU_^{9L(-s$XGTr zm(}tM|B$t3_z#!)!Vg{6^iyE}lzFUsN^~1f3mfYS@@_#suH(1YUEJxy59_$QaA*9T z`*$}^-FgK7y2Hn~3!?Fj-yE^NeB#J!_nL;MFGg0=|L17`L;R+)Hg6g@J=$Dnc9jT6 ziro$UH@R=>+UWLnHJ*)sn>%%9MonEwm-cY`=RK^_zBKnEDJjotD*{g zHUR_MN76cr^5C=*oZ^3;tUMyzr|{5t2X`g6S>?_61%!eX-PJGhKFfd;SNA#etqL48 z@oW6Hm9)Zpz(eG+%Ey5HUG_1%Cr4`@OX1-X@-6`f#XGVi!Uulahw-kOS2?gI8gk#% z9jd!&T4UXqX^rkN-CA=ry1&p>iN4bg4#i7~BdUGmJmBbCRo(oqjddUCDuIX8=hVF; zr}kUr)o%wz<9UKn96NrcV9f8*w~fLVFtAS~wdb;rb;0&htGpE&ZR7iyXjJr`Nuyz6 zie%EL#k~Qo;B&i8qa$MSF%>>{^rO)@^1-3e7t%C}u5${F`tTQMg+{kSqkEyz?fqzU zN18@kq0t=~H2UB4amN{GbbAJk?oHF^9`e4%m|REyL(oJcG^O>o?rr&!(x8<_=tTZ$ zOX=6$q_xrBHfL;*zZ-!e-cx!V?G#R1`M*bb)A@X?FTbaJ;99t?6JC^$|3A&h7YD!J zPUqX0k*|?_4$q63awAIx}qtX{&){DIa5G=VQFyB41|O4$>YV-}bunUcwo0 zaF@Qj1F5}+GvG4J_oj^R{rmJg>TJq@-ye5BrhKty#7WtMkK*B?-agrL9NF`m;bz_* zWRK*I_MiL9o-lg~RT;9!!Y}26WzUGyWKSF#$do;ec^^*pU%)+pKY#wY(>*)yWEzwGg`R+Y`+bsNT+WltZUjfi~}x>78u{`{!*pvFyf zYj%7v-B!9&bmquP`4?8EX~U6y@iU}74-NG%n~En|5SvDR*%ND6i;o>{o#?L<$j?b@ zOX9)Bw7xunPLM<=@WId9(FLsQ`t*U@&<8rsAZshr`oIEPAIRzq`A?O#KH`;D!E25_ z5dYY}Cu@E9)AyIP=3}SI+E(rk{xGt(nlb%%W$jY(iVkOZMs-Rj$jblR2|qePIrru| zI>8LacWOVre4F@Bb62ML@_Ouer|~86txn;~{C~xlqfX~b`2G~W#BV#w&4envfM zy>WF?=>$QMViyf>Y%zn*a%`6m97{47U) zu5*v9|KH}sA=pSW=frc-$E(mw9DQ12e+uv5Z}wq$=QFhV-{qZK$lHHT6Ycyf-qBu9 z<~joV=BYA+`$GTKT;6|9)BS0h)5>UzGpF>|r`yxIpY#UJp~ZIIQ}uW0?((JXPg8r9 zc2f6D&52Ku=FES^_V^XoYp*p^chkDx*;}&UK}RpEfM+fiOr_a6T~_P`==lz4A~S6! zd|E`l%(BwomXj~w>C?~p)9Obk^RM)`#gzY7`roGoe`TM3*q_Fa@V);W{s*P?o9nlo zA#D?F>t9xT#68QOJ!v_AxpMmCd&E;($<&Hwl?LYn2?xlbJ>5=Dd z`|}a`mB`=V?soj}s@;*-fBN>3Fn$ME#CllY;dfAh-$AkMcVMu=yRdx=e$`M@kMDtP z<9`8r&s*@n_RA_uwRSh1Rm=f(;TyY$RX_ARPX} zbCg+J&t8Fxw6M9UD=;{fPx~m9(0l-Uc{qHNo$pP`%C13u(ObM$G?Zha_}WJw^P1?Q zaRL6j_#ccuG0qje^`k-lyQ6_(D;fK!I~qbKuY?X}VYAm>!j%```^A5&7C`Q6zuS-uSGYqw{(j)1v|XzUg~mDR|1mv*##$1dP=qe;UDk1$?gpu01AcxMk9Tfop;D$~4@1je*j@xAyV` z7hj}#P1I$9bH>xI|0>cpxZRyWp2GY6;60py_ch=>oPqamfcJ0)-Zh8R_QShyF5Czw z>!81%L(4(>qJ415g9P|W`Cp8P%|7XW0bMhP978_uBadueF7;D=x-#8X?lcnq>^@CM z(e+TO?VTXYTPsF)S+XCPDP^*{7gEnOv88RR5V(dhVRg6JjXgoOYxk* zDYO*N37$er3GkFjOYP9z0chnSAx+8~E5A zP`*CC@{r~tEt9VnAL^ZVKCrc~{|{uumyr?T{~sYI{$AmV{0`YLY{jsKBLmE?IqwJ7 ze(K2A_B`!6d*^LKhuFR+bC4IYiB|OKgxU4PrkT;$M@_WDGc@+t4=%TPvE4H)_UIHV z`Iy(uzWmv-N7WzZlV49X(U;G0MPK}gJNm*%ll)#+?|OVmw;Z7j*LRp*chHWX(1zXA zuknIcqSt!zcg`xYqRf}k_MVEhA@C~x58@kh#km2}U3T3IMx^9`>bdg5V031Yy~nkC zCVGkFf#BZ^&M(LBTkU!ABdNChdSa?AchQ#KggN{r?5na#YhKbk)wBFJwjKHc&Q(jU zIrLKTx88ZR#P7_cmnZ+q9l7lB3I7hgct{H<1xut~Skg6B51i#2ZJM z4^E#SQ*BWEFv;$ydqH zO$3|vPsU@HMc;^60VvG=!L5a}Q$-|xt)*nRQq zkUQw1&OSgbJetC9Dt=csx<>Dgyp!h}9ACOP{n5UseRf4>NUp^Xm$tVTrOr9{%8->> zqan{)OR?csa1OHqdYhaTS;0P+?GLeow5yOm!PGf-&5?2X9;!2uID4LlCYv7NbInwI z##WkLA=ba|aUNhz$%^svMfu*!o2G?5^ScglH`-Iwm#AQW{AZ@6tHWJhV#ahPsiG`dCSfaH=VJBz#=GAhJDb9bz6Zpms ztGxE8iG2Mf%eHCPqccBLlN|2HKdPQF3$MK_ z?imnqg&(yA~1-3d)@bg4^;qILCQ9c;2b@ApuY?_teq}Subt$(WPvN${>QO?nzh4} z`&d7XWBoMiB~xxyc)Gs`F07S*xhw!KtPS|osIMih(*rBN&^3SMN4f&w!CLvqWmb;a zd@p&Ax6xnvoX8Dq#qPa}_0+D>tiufPP9D)8NXIuA0TA(}WY@=2Gy{A2$Ku2q%s{9>Qj=n6ekEPvqCP zAZ2Bb^?}nC(kw3&E_6oMRs@BO!@i` zi1^9d&eMeda@qXu%c8y?X*?ggEHR8TF+T$y^xeqXWia@O=LYP(oB?{LZO++{Z2mj_ zRbMUSk0I@$ifrOg5G#Q7v-mQxx6iLpbHJg=Ru3}hRXa9KQQ*|rG}xq^^EW!PhWxU9 zwuCPW9KVMRej0o*L*oM;EO4l^3sa$K`6l{UKZL-cLmT&y=1;F#oN-ocYPGw+ypb&= zQ{Jpk%bQgh^5!^Wl#(}DosGz?OnGy^BX6L|RmhoD$Q?({Nal#QByZN?D=K*-JiWoV z9YE&n%aA$WVT>eiHpo7Y%vs0&SS>Oq!I(JmCc*xhWKk1)XpYQjVh>F+D8N3N+>A+xSP;OrX?&c@!CQXhi%H9vy}%p?zH)3i zQ_(#RT;(8V407gL`frdkE^uHnTUS+58316O+3^3qoDtP)C>0QW@LnWUZe;nDd$ZN*O zq0y!65htpJckVL9?qg9Gx&b`s?rdKSkIRmX9o)G)OiHekLsbt?RQ?`VD*e6>mv9md{H?+w!4M3)Qaa@IO`NVJ=~O2WB8-iJlANpHU!ygR-J*reo7FZ;|dC?|QU@1@Ln zGZ@ySx?NW2lW5CorAUS^tV_mcO zl4m}zkmKqbCDZQUOlHY2ZWJ!eoe&m)5{5tgW73jh5NvEah@_N#o z{>sT0{C`Xx_vrxEIrim<&(boN#-8KeeOUuHX|1u{rzHNb~Ym$mH)fQ(hB6G z^xqA2rH5a;*VCXo0B$q|^>4EWARCZi%Fj3DBgnZ}^jLd8ICx$}HoWsWs~6XKhH&X& z<{aou=a-6N-0QS{L-4%A6OpO!;!E>q{A%{PN8@KcI<^=&{PSb??pfj~te@u@U4Hs7GV%PkA#h!Ki+Dtxny`0#Kw2QkJ>@zqACezO2sTc|eCPPnY zABu!KXQ$&o;qRWg*1y6u)DVOEZG5n{ab8<+ns(Pd+(8@Pg?>vptE2cP0pr@)Hr!>y zpJl@x8Qbd~)j0_IxignG(jK)>ZM)&U8rnXpUTssmm$*mmR9o9p8uh^V99L{WNIjv{%1JJIBP__>QTK|6z)0W3dg}4@|Z1OT-H5zn)8-Z-2>NR|@BX z@!IZ&hvW324gWLc7rf7z5j(X;cMl&?uQjP~>-b424t8D=T7yP4J{m8LiG62{VkD5? zsVBxgOQH+c)z-wUEHi9efiPn_f%=QURZCVqO_IPXGymR`Kt@BK>YIbIk3 zWS_ZYvUk(flf9ote+*vj^M1v5k=G($)zueyjc+VImgjiQjrdLKou`kdU(ZtfobpP& zAG?Vs@56b<^)2sX-h+I1<>Z$5@l~7TyVxsVG*j&NwsIEHOv7Iae>dj0^!hd(r<*xP zv~FfHr!bGU2jKlHQ}28AeogBAFM9uK>iz3M-fvC4->>(ZQtvDEJ}31a=3V@didoy(?tA|)4-^yC{;11T)&$6CwHj%4bRno>;;f(d!@F;wQytncfOYi1=pwb(UPsT2zQek{o%M6PxA&j>(3R|U z^o7jDT1PXkJ><35(epoO9i8%*o6Nl4v;4;=V+5R_-Lp79p7JgBOxVHNxdT1ULwlVy z_B)=e2`M>}JwdYOt8amqWhHZ^&)qd=*!a8aOpA*%vo+T+AGP{ALv?E|D?^`r2izIr zy{ss8M@B%e;i2ESOy};6Uojv?#JViu+9V6ji25$_KEyYjuXSO6xR3ta^*NI)>8+0{ zZwX`kmh#_Zk_F^1;J=f18F|g3`{vwPg`Q^`?{Jy!2jlnp8Z`gCjPKYnU>7z%H0L3{ z?Y;L~(Rc5i(y*7hw2!BA+^-4lt%6%v|9iU)g?1Yj2yQ$w=g$8;9qt-@aBaBZ)pPzJ zxbJ`aBwTEBHr!Uh{p#s(uL16M&Vv4dUt^soa*VO{U)DBVX<5Uq@*UVAd{*1^#~6cb zW3`BfI~oRnhy2+7CrwN5&)nrN%ptzoGTDGJ20Ge%x|er zW$$>icYPam1RFh(m3-ePn#>;@Jp}yAsV6wedQNNS{d-d9x_ak(%Ihw2Jr@>C=FZv- zm@UAxVYPZ9T^%kPmZ!o*I@ab!tu!p%AsJ_FAV00%8SZkm!9Cga+?NDz26`j;oi=V# z8yh%RGno6)(cj`bQt#*+^WqzLCoc4M^u_o~sdx6W=f#_OFL2-P()-TTdz04HkMnK@ z+#b;T@AN+S_5|~xp}x)ZS+P74@Y*|dcD>acq_CM~zUq;MF*H1< z`9^$)&6+u(DmQz{jdvvO^*78R@5y{7FX9;%o}>GlDhFOWUNN%$D@q&u%)3`)=8NY= z%E3N9<@|C#5x-`VqAV>(t#^9*8jk-r8$uerq}2htz?{{wuf zJvrxn67O~yD>o7Z56=4x-cNu}=l`X`9sHm;5W?{c)(k%OIy63ceDkt?G{k0j2wtVn z59oY_A3y%H_}>m~Bt##KkrOLoGGzqEnLCb)$J2AiJ9zVMVIJQyN zU$?)--i#AJUhwP~K;H@4_FE?g(Du2qp;TaNpBa@5qD{69<=q>yISb=LzsDdpCn}#x9ewp?AveZ7$)pOv%d$BWc?r{cfdF3;#7gi349AAlz z2cCpK9$42lF!J8B%wye?qTSeQju9t&M)${^#Ol%i;PjG)-dqqKH;PBhLdBeZtReJkslMDhw z|1Qw8Z;7j=<8D_=`!z<*LP*=AYDw5-^5 zw6k|UzNz#D`A&a^M1tY$NX6OVIo|_Tg7uV@JF4C=pO-S`0b}Zei$c%)2U}Zb;hTQW z8f&6_+Bfl&e|y=qo4qrq-Qumz`=WOhzfj(-oKslfy%`y~viMeSnDY$5^KS9_&%4=M z1@Bb+W5u2YKF;)0cQ9`eI^iPk&G6SDaFsKBW{;h|sH{7%Xl!>Q&t{&1Mb+KGMGLw; ztF9<9Ypy7<+ig{OvkPYS1bNOZp4ro0ofC<#zBYPb{ixdlc{3(fk#6|y+iQB-n_XM! z$He&KuB{!PNb!s6IkZ~x>m1@^&ACUu#O(WNO@2=YI+puO;W-D``}7-6z3lm(vEkh> zvhU=X)Oy6^S>>#;nJ@BU2iPlqk$t-Z-XKqRw1_e4V4g5m*VK4fAUS|?i5Y=p9<*iH zw;e$Fjf~Z7#>fwTkyAY;E481SWmxNExd$y>VLf{fzj&^zCx>=WA8KfL_kP(>29bYJ zWp^Vq9v|lF2~)OsMd;a){4{52oa6bVQ)VA?#-VeG6^AZ$kTY|~@=Y>cc(#hJP!2~+9Xm3Asm_>UV?=_pT(0U=Ds1$sgVd56yMAh=$t1lXNN<`knq8^g7K8iIrzP zedYe%^^)OnPas)>3}@{!uNwY)M>c2jfP(mbN*-=j}(K?FQ@YhA3G@H51k!(jQrAX5{!@Z&qCh)S>`iS zZ!BtXp}QG$(8Mp$0V_P^8~OImXjihm#D#o7Ui|{PqHVoJ1Ip{%oKwb@!C8*-m*`6+ z>nyifvwI)7uD0oSM17sR@yHx#zE7T9;>z7+E%y01#kq*8s z5WGR3MX%209(h;GooO1f>kJh|%FvH)Adfw6=*;noz}61%v5a-2aN!15dETY~!H}p>o2Hib0Dptq%RDh#FnYgivZQPWN49}Ua zc4y$`ue8l>2l}?!p!%1gL#Pd@`icAS0riJeKXj2_AL3p&|vn^$~(Ao6qCQtY{yGu?%qubq8)Bmu8W--CX2ztYwmU`mG&&ppYQ z3V!vd@SIY3Q}5!tY{7^A*8e&@r;z!lXvNe9?R_kn&i%=hEiy%{2?e7#R`=`FJZh-d z{{K?yfAQRrk&^D(Cr(gi3--Sz&W^{KpIpPAIeQ_v`A6@X2c?(9kD8w}zIpsezIb`q zq1|Wk6fO@w5Quz{vHW|@>Ia8_pTUfg)t)?OCouHT?hAXj9l3~d zALW@d`~q(-^Y?GS;WznN*;dqKo9K_>zwAmA`KK9H-(iNVp*opY+Rd|ns!xX?c@q|9*c!n3x* zoAzE~=_`Co=dZz*Zjsloyyul-R~g4QAGVfB-t)#WUf5>7#U6*wWBbkUoy4(O>*p6V zrT^vU7bL%*pK}&1SbT@qUwpf_k~z29Oo~XKtsz#yltp)Szi7rr&RKMO_i*STi~p@4uIf*=y z4<9E@FgnnK?m(R{z3jm|@?VeS)CeBhop@JpvY%>~u*VUd~G zW8KIBt*v6f;EXu)UixkX<{;;81Q%Mn#qt|YdrA{!U|;6A3hn6o!i zPG^Udr<-RxZK{Mu^nX6_Znt&toYj^lqO4v%>UacoB`6jKEI2JN12nerb9hyD8X74@s*)EI<|Njnn` ze?WSI{z@NEe>2x~Hwg~7eL{I?S0ImZd@mKtB9X4Mf0@syOh(-X-nyDJ-L0;?vJ>dJ zk!ON=rVgDU1;c%EEolh`{B^&^6TVu-Q?Zeh?*vcb|0Vh@K9Ickn-P%;{`d8-FIM)= zz&emFD;h2bmSQWlQ+I8;ZjEsm+lR*3PyR%@jvr>$5&lSILaL4j;2E1A99~oZ)V3_v z^m?kE615$fK7?<-0iNV;&+^ng7mj_?_5lKx){~X)YbUz?`S|Wu?6`h(QUB}yn+!iU z^N7}J;yL3<$6Y964Oo*M?VZf?I)hFyVqyXvxb0Hz%6|Mx`+TrsCFF#N6_#`D_$S7q zYd5+~~xkv!mJ*A@0@FLyvpSgq{6Or;$f`)2Uz;I^B7I9%!_er$ZkJ>eYLIJJDosd5Ukxfzh-4 zhkf>EjT5-nSj??v{=|pN9uJRuf;9{uLGXUyJ0_|A$_D+}GR4?;rD9#o#W#z17mJvu zzs}E&doeZdw!dFxdVI_ul1Ue@vby|Ztd{L=*Htr?n%iGtP84479pB>rAI6rSmp%=# zeBL;5uRE}JRAcW58nZKi&!c~ZrvY2R?QdU#f5h}}%<28kz-aULzdy(I(&Klmj6QzH z1=K4&do(}Urv8)vh3xkXKu4HM`?s*a4yVKT4MuB-iE%1`#;JV@`>JCSw{@_UEn>$xSHY%yowFrW_^%1{ygtJtP6eYtqk{} zE4)HX3HFzy!y3+|D8|zx2h4cIMTNIq5(KTI;x1N{V7WH$tdxBjWlxUUMXs9Adn`v^5| z&*35Gn|aM{^lS1Rr7U|Rv5L2~*36G7CRGUkb@6S8cy%FSLRF#%DbIp+)_9+QT2wbO6YhiNeEH$WquSJ2L*bFJj1#N(^E*F+T) zwDw%tct^*!UV>cYIogb_54ltE&zJL^`FqZl@KNI0E2FyCUGY%N4ihPdmM+ag9xNOh z?X4Mxe`7&sZ|`u{Dz2@y^p8Mx1##*sq+g+&a7*K|&~wIZrrcGk^(1$`gUg?fGwbMI zxy2rm@+z&GybGWK;Y0amE-icR8S;%}k6Q7)RFC3a9K;5Yps$tm)#u7h+wffMshHa* zvJPySvWuTv zn^RCfa}e|ef5h1z&Sos8c)~4@4SeC@7k{7C@Mr8x=AK)+8i$z8^dYJ793WdQ?}jw} zuVCF!nfJoO{%>YA>}Bo<5PMH!o?t8)XYQEK-FXz)?eqg*nux}$ivBDZVG-|ZaMZuT z-B2}9@xKiIXa$Si$m9{ltZA_s4#B6+>7(t3zWT~&*ll)do-^prW`(Ok_z8SAaioO0 z8#$9`u;;T+(fQs#zV;JCjGzJVgU0?7j6HUf)Y!AfylBzI&&y6HKAUgM;X6qiv(Jow zigAs@OL1eibTFTkAS)C453MK5Q!wcNgm8wz56Vly@2OEK>cy<2{aAA~R8Y?0i9w|D=VHZ-7p|`43GeYpKIWU7}~&AF0K^ zWf^Te${J%2>s8@L^Oj^?7JYq|c_BXN8hd|Tyje{@PG(H-2K(iLj)wK-*OO~s+bC4=7zmX%j|LbF8zUyz>zDqhqhSx@CajN<(uSe`LobY$>P6vB7;6ahUvU{ z7~BeX-^U)2@_xQT3Y7_BMSByHfR#jWJ6Dw;ovP}C>vL%To zhy__BoQwCwbK=F6ymU9Xp%ZBF_6z>jJMVGINNz}f`XOcN8TUrkKgP<9yh2~ZW1=gE z&&&h05073kx?uw4$oGIDmVO)gY@H-M9uI0f7}LM-EP-#dH});w=P|x^KE@tiw#Qjx ztZ|h;#UbTQkF_(-HG;+1h^`F#HOu+$=&=_7FAgm2--uuCR9^7h2n|WMt%0{!6_eU!1J;9mEDN6vca*(#{8&dt`l_b6W?9 z75XAJ`vmiOFYOzGp7(^^quEIH#zw^_1n{a&A*ZF8RcGY&5o$7%Bj4{UX7d` z?Q!qiM>`&+4a+&_{3!L$q~7HGu8zbC&GZXW}8n(iHtP5WA0aoI97Mak4y(lVW_69GoPnuQ-hp z(ruhf!xzWq|9^oOR|a0jftS`aUappYO}YR10K8n{DLQ!u{Q8XZ-`8`G=g(>LLGbWM z`Wfdb{}w;6O&b0y$e7GNJ8?t%r;R+<6ezBbXI0&9#}{QXxInM!d>a`dowFNaKaMCx0*gJA&zj$FUn*4MHMlJ$|nrEM~4|PA+_#h z{Os{6+9|lH@hVgt#kI;Sn406%-c`Iiahw!K`x5%AbiLOf)q0>Mx`Fs;PW#29sWm`$ zItGC&R{QGx4~rjajH^?z?yiPEjzbs49%JKK{2@LVm4WLL4|8jsi7dxIRCwRQy%Vo6 zC(G|C6OXAgrYV1`%rmudXupnmp~;EO!~7B^jtXn5%3#pVeUn`dQ4Y@Sabm+H*L!m7<>RUG6E9z%md~W`l;7vFvq#zTxs?1q${ORYAIrLHMta`T9<+sgCVgiu z^H%(9Q}1%-EzT>cToLkFWmQh)RaWy>x4Vyy9?6gyk3c^^VQp1gm-1H@Z}+F)v!Kgb zxAXmU9+}E_$sR*o0-bAr-CbO-cwrXj`g*w=D1=?+YaAU;>WG{6d~fOEl9^vv3&Tv6IbnKWSbpV&Cl82Jo3Un@|kb-vF3z-61*#B zc`vd?hJ9X@_e8_M4hmK&uu73Bg2j2r1n<50T_-YP zR)yp@Pt2-n;;O}oS=BL%cjBtafBr1!qXU^G|9Sb$J8{(#KLs{^^NOq1%hN(;j3Y1S z9U_W>AUv5pDLlD2=cITJ??N+MpcmnE3$#+qczu>R?DzD43GG*Gqr#fPhQY|+ucJd& z5?_t@k-JLhW0*dQ&nuDPRmdA_%$fN-#5l`0$dTcd#8;~!o_rj6C>dS}j4EVPBk?*u zNQQ^*FcHb{>YyoiWOz04)k4Hq`_0r8pWFEOwv}|^t4W4e_LJf5(A#-zfa@yv4Sxow!wyx;(;p7 zd7L+JWO)CWKWC&>bkO2@n8 zWZbmBDsMVpD|7Lc$_LN4!QWNlO>o-E|5oy~XTWTQ_GYAED&2t@rw;kTIWXg#gP)Ry zDVgEGj04k9h{gdMVp~ zo}Q_+e)IW->3qm7;EjlVmpT-$L-|4(^S*2xnz!H4d8f7w4@+h$hTHGm1@&x@*4H2p z8adar7yF|1lhiqVosp_VZt4uCLH=ufpgncTP{nt-xXi3mx$Ve#@zGJ_$9IVn{wy+N zFLgbO40#Q`VJ*@BwHN93JXVxn^uNwyng^VDjCFgxvktf#nWlMc)CbICvpN6n z=tIt0M|Eq>x5(t~6mB}?hlD&pM`yo5_m~yg_&QXQ6Mgm^vrhZ$2d7%t2y`Au_xlx} zlE1@~8^d>O!ib*U^^ejgy*uz^Lrm>U6rFL6#`#F>8ZSMeHspXq;r5kMvu-bT#@1$g ze0F^c8qiwtx%4v&+HvMz$tTUf*z``$xsFWRNm`;VH4lrQMEi_YQ6e2zPrN9;xrnsw z8TrI_rAo`lC!WnG&8gR!_kTs3Yu%^L_0Osw&{RIUi_R=Ew;tAcMV(b#!a2nuKSM)w&Je zuL+Xh8tW9j7sasOtgm$!om|f^fk&jDIcxfZlsQ0|{gkP`Hw%A_!r0gqS@t?lYra#~ zRQ4XyFQ522{rv3_tsDF5`8EG#Ls9?PAG^@$zxr5kqZQrY=KMG3cGUNG-32?_*-Loz z{ff2n3t7eff$9pHtgB>ekzHXeHgD}GTzsxsx6SQ7{1kJA?i(n?Ze+1e*IgLWw-%vO zA%E;Rz?XBbNqY;8th1}ALpTU?hrou5d)KoM(z67Zf>DVKImA5|+qqvDUuN45?(Pok z@e$YFiCy%N+Z`#UJ!(s4JMP1`{PcDd*MBXe z9oy3Fke@;$wl>-E8~-oj-aS65>fHZdGn0e>;ZnmTTuf#XR8Xm?pc#d-XTn8A(J!Xj zYL%HJDuP&ByhF((!Al#pjG`#mGF-e&tgSzVYFar=z}BA9S^+O@ZI64Bfb_(kRxX;6 zjPree_GBPZd(Qd&e&6%@{xPq;_nNiWUh8?*de-xN*0Y|~IKRiYV!ji1C!aQ|eZv2| zc_!_BAe+wlA=O)Ghs%Im@os{1E{}h=j`oR<%BMWaEBst%lJwiw?P*}xmqhVLp}-=$xtcTvXC{N4qn4}#^Yp8qWWM)GS>s=l%!W>%F2?jk`0o zr|%>_%inY7T&`ff&|Ym)hI#59W2N?9Iv}NWQLQJc|ENz1H;_%TpS6jOmtC#NfhQh| zldtu{>HQabSuZ^Ja-h|9XkKfB={}b|rOtZchu{o`axLM)UD&bb-oM*@L;OH;?dshd z#=UVMQ2dhv9(HJ2R5<48KCgoBSjD6Qep{tcjen z!kUk}OFp}bEnPSvTsmPw$nhsC?7y&d0zc;GuGn5vtr(DFZgE9Nh4P~VFT1|fOme~>^O>wV$$ZU3{|I{ausle`r=(7$e#-1X%1YDypsgllPfb9Xp0alNG}qUyern3&d5jM-s@nwIe>I{E@ z86CAhXq?v7aYi&RG$uOpJMQ>(#9a5-W1@STO=>}VL3HmN7yHr9jP3=)-&<7~o%J0P zFR(^OKWG{f-TOPzJQJgtj)ASxFZQu^wQt9eXe{!*sq*VP=ot{rR7~<`Hcs-_@m?o= zw3ct+!@j%oC&c36*{;Puc@bmx4(NB#wC-EWy8k-%b3aErsK01w>=UExD-ce9mwkih zE__>4A>KW-mVG$~T`3vg`++Kj3}fjRPt(_P~b+BIvh#8<; z3(T_bJYs(zx>HB#rmpiM^Hfi(&@|shUHwCRYde_>4Cmw6k09SF3_kYQ$h6@IgYynl@3yw`Qhb3^IxoP>c?~7RP_xf=rB_Tf z)%xFky3RJJDQ&;nl^)caHe}L_bm;Y&oMjR&^{iY{dh<`LG&f=y1Ltptu3{$ z52W5et~%>VUqjB|gY(7&bOrJl{PMsyy6mr$PX9=dFVy|P0XO~Q10sw`w_ByAXoc6e6yinJJ+RE{h~GJn#mmTgEe|eaE>`5Bb#(G^YjFR}g}} z9n`V5=YsL=c_|D(r8ofL2GIqGD4Dx*jEUJ70h;2ry$@UF>9{RRGckYVyEt0?p| z@85%uDevdOJJrGQF~fJ_q#J9y3pf)-JXO7(!hdQb>t%-jwEtiAd}cvicfT9Qb#F2T zA9HteE&c#I3QeodWAxn^?%uc{)a|*^%TkzWj<6r*UjFw{PAB^bt|y;|b6XL0mmoLTjI^h)XE&!elnjSj4K zB-|G5E@>G^{HR-)*H3y0z0gA}5BiQ9yiYVq@ZPI@ZzsBV336o{_Iv=Es4m;6gF*L{ zpP&_)-y_@6)vF8tf-*F3!w*LvRiBhT8f5-w-cBoap~{gw8HVnzF&%N&{?Ju9BQ3q1 z?L9yA;wNyLsr{kmfbDmOdxouCwWfhQ11lGm?zsEb9?6A8{cB6-oNkr0%c6aVwy(5|rBc?)VZI0$8ElbH)=D}8$ ztof%j&#te^20934F~Xsj`=iBeob85x;TsOUN3&aB%U$@J@(t z4fdF{_NNMO$sK>R&oFlrsre@EHan5AH$HN;LTiHFuYzZL? z4kMS6$gUC0Io^TbA&mKRmYuU!bHH2F@0Eq2O6@(GjPFdz%CVJ?Pc~EJZ&DT;TUo>V z9mpu;{`vYPg18Q&YKyBPEZ>v#P-5Z z8~Gk!jA_n}tTI!MFUO0#)qLlDg?&wYqd#_z_B?gePH^O(=F2d#Eqq?@uJb9!i+r&c z4)C)V+VSg{CA|U}+un3$v;#Rij{o;UCl@l?eknUYN@k)zQih4H=Q`_2E57fC{`jmX z16kw};M;ch(H>pQZAU9Tu47bk&>wt^29mi~jZyd}Cw%(7*A?rVpKyOFv~+ zN;1|-zn5{i4q5FT6iuS5O;kD1=E;gd(ND?;MGg9cvtJCoDshULVg{o_p-XlnJgPl<2n*C z)sHa-B}3I0g=Zuf=c5>p>d&$V??J|P?qHv&$#?uFKXvdk_eT##P4x)Ix5o8EelIY# z?^z~UI?5T_<(^|>`^HK5xH7i=l>0t)3R5T9kXbp3yv43RDnr-&qn)0Uqmm6-IXc3T z56K|?K~;pZZsXy4xW-qg3Yn_bdDC3gejH#`telAeZXP0rkUjHj;Sc>2t+EKfDR zif(;*dWbgl^zw9_n?Cey&PMTMaVzc95>7QdQ}u}B19L*+k87Zz@GHsd``~4n2VUOC zJH7K`1bKZ)j-NLP9~$lOGf0_^yyE@CXJl4C$lQ1p{4C@A0r689+d5B47xJVR5BmK4 zsPng^GybRZqbEB*#y$(|d5E~qhx_m}!n1VK!OWAlIy@cLa&9kA6KgY@Cv*QN@ILpw zW^TY{pAaw>hN*TIv?i?_K%xyR^RQhM~weK+L-#3}fVb9gws=HkiNF_fo>GIxp z#OL-M=n5ZLX#epVPP1M(NxSZlYXtUD;~V#mnih1L>>Mg;ICTiE9q8t&*vM{yMNfiJ>QoU(i0b%FQf z>wVt!T{bE@1Kx!BNltkRvv`c;vCbD0&SJ*bmOceWDLh8yxP=$32$r$ix@-pg8$emd z+e%k37IL;y9sS2SgKSht_R>l-V@CQi&yK#r>xGO|CP325q2$)*V)Ic44jC7k!3nIrB&j*EW6^akin;XYuE# zhbE!7H_W~0?HA^n9^cIurBAte2xkNi;(WllcZCOEd{=nxmmgSn@#znkivx^_@Vb<9R-OO>EIwZ22u4NVmIYrec@zKX{AX!FOLMXl(?uu|JrZ zid^hLzxwsm%m?|Yz0_COPAJkmRpll#GgFOqyx)ae z3h--3cPXBgGTyPomo4qK!Ofh0KwW%%!_gt=Yh}>VNrw(T>Y7U*l}m@NK9f!Nf^ig! z_FYzLJ(!vcOl>__+Gy}NA6Q!ZyT}i8`}TK*6OHc0XkBZ?iygI$b?W4+yMOn`^}PS# z3kQ6+{o#OcT0@+z_37jR;k5=Ia`}EMu7r19W^>Pyv!X}XH#P-bWzWJ3o1$lLMNzmByo#YL#2 zo}ViJ*L-U)7{~dAj7N+3x{8^&x9Ti^=j^lm_UfXotEq=C;4L-$0<~bWedJEaJHE8= znu^j8>$2ug6{VJU0_Sa(bM=+_{#0J7ezu-5>Z_c<*c@LvRdrljwDnNawcy*P%exxc zQ1LB)q>=Vi%t}XCLvFwy#y*Yy$lNC^C4|ncbo*@5w8nh~SJu?KPb(k~80Q%U#0)vp zA7Sme~+OJ7#~|A7TC8h9AcIYEJ}QeFZ)) zxibT=qRo+->^XqR-_1(3@0pcqXe{kczB?=BUcnx(Pk5I)I#>_buXw+hch3Dg`V4yd zJLO~P$HTku>xhQgJKYVo{|W1UFSG9VGHZTUvfh_KCoE%K(XjqDa@okW6Q^gepUn$f zmd{Qdk&ch1WX~b`zV;{BC%88ccYHQWTAl#cK5L9&U2IfW;`gpkG}h>ZfvF>gEgTmOr-rL1KvCTaKM{yA5g!#ztCO1{!Q2B$;2u8gmsX~Lx(x> z{#4!{CuaAHs-BL$fNgQ(m*pFNW;9Y>5Z!?9f%aU29&@*U(h1S2e?K95{tLy?b8i_IRSaY=aR%%wO{yJ?^91&;L~fqxXANkI z?4T{dqUb96L9Q>9RE%}T>{VR-{GQ||*{JuIa{mc=?UnS~!881cbY}8VTL-?MN8LM- z=^L1j6|XZmxr})%KPr7QQ!(bQ%?9pE2{4|AVS?{Ca=i>~s8j@7c!rm0{j{ znmjA`ZQ5XV>79LGn#%V4&Am<+XhK=-i?)jE#FBQ~e#@bNF}Q z^R$1DzVzRref;apWArzN_U>yP+Uv|_(Ohd0qOscX-50aG5D(NA@jz`6-F-U4xt9;3 zz38iV)IQPppYg)QInDdXbKk<5|1}TXv;1w)^=a}uJb*^}M&}Zf>dS+D*yO603w~Ws z-v15{WRpL8r+-h@F#SH3>h> zVO`SeeAi{F=O4-H_rkkeU(Zzc=b6}Z=qQ7tHWy3ig4G?Z)STb>5X8 z>}(%6n)G^MSF-Vhr=704BWJ*(UdR&`<(+sGi~1pbR#;SGQFcBOHlJPNaqVo!-u4RP z$L1F1W@5}y;NM{|elM|ve4J0M^@r_W1GD06=gxMZWrdXfAVFE`F~i;GxRS@`zK`wvgRTC^#$^3og-)etmOGdcq@MB9iJ(U zKEZqD%UM|u58iZm5IcqkPJ;(Me5VAxv5~9%04lhuOwH}>8?mLpHw@_wi|nb^0(+`- zxiTyNBkyl&<_f0@(7r36L&f-;N@wz0!OzXlX5BRr2$i<+^9(bK-9ufA|AlcnAK|t<)ojcj#T!Bi4&iY+2gx+;^!%-?5p$Ok@5Sf5o%h zxK!+j2pFv!OraDR;P969Hu2W$JRdu={H5;9NcrEiwPvb+@CkYUU)mOB#@)5w5bv9@ zEd3~lpG|W3QR4V0#m>)EC%}CAu8Cy%aom~+>oIpghuoUTIxzf%{~zDQAG12w-_@`8 z{ulk-;Rl$O{G}4XO!XU1U5>36s4oAoUZB{|)FroGAWY1*{_$Pa<-a>l75`AS_Vya$ ziLSmpUT)mYk}*|Y6P1j~gFhM%NpM^XdBhrDkK|JO!cdPvE@=%C403W4X}-d`(#A!k za}6VlEaXeW0&h=bk+&x|j@sDgESX~8JiuSxXUw-SHm!d$=GAY6c{pSKTj;0ASgko6 zkLkzGGm~>NsVeUznl!+gS6MsBc zSolVFVw(Ki?EI3O!zH30(sj=HK)erqkJ?om*;v_yl3D(OtoQ~`yHlPdN z0nKO6!>1Z#nTy|t>LWX6rnSame=;*&YnO6f9cv!+U18Md^SckNUbp6vPwV%Dq{p)! zOm%j~IH%57qoZ1j`8WFQ@&A==F1qV7#^kN|w#XhI%XsabKmVSU-K9t8&o?BC;90UB zKT`054PXWAL)cjkUa$e2K)zuiFnsxj9rX$8^#uz(jcmlOa}UGU*|?tz@*KL+wOM+m z_O{BWXbbzy&9LD|{fmBlYSylkP4cMhfDZgWY4aoQ;^t$x(}yr%LU z_OT^i)c^Cl6Yd{Q-6jkJ|G@<5G5p>W_zJCOFGd^tD7Gx09=D-4dHf0Rix_rrJ^3yC z*PUnfoFu?AV)!b%YsW;_Z@2uh#vM}=U>h$jcj5mtCc3TB_}jJ{|9bWcw*8Xpuetu3 z>l7dLSmp^e1 zdCs9edWZcR&huAz=PRV2$Mrm}l)Le>g7~&}mtSRL<5y1>jdJbad6J%?g=|~VB8Fe? zX{0%}ELfXt-!1%>@Dq;TaOfBY*AAbse|HIolkbtRIAL($Z+jd};_qM*ge6B9wN!RaU)|IxqztM9{ zzs>5<7qgzwj(nAEB5Y5-lus06qkt(v&&@XDK8IOF7H6ve#PdRAl+8FZE9S;SD~8|` zTF~;G=B_^T#zVdH#`9b?ZwN>KqItu5`^R&`VCkl3;?1XF9kb zYs{{`ctR3fP?$nHxZp*eT;h z`f+a=t+_JX1^#oGtJ>vb^&CHNCyOzG$+6oRH~0m2Fcz#~rg;MTljiZIml^iOnpCLB zG>>Qf$Ic9l_h*u{!H$GAY0Ma65DUW+Ug?Y(_AP1cRJyXwde{KUQobZuObpCmbC8(g zV1!9XyVj$hEurkkjB(07hqAjFf10y3o=d8V80#au zZ2W@tZRxmy&k`<2);je!!P;U)s$PrW*plx<7@Tlz&GmCk$)(c@|%8>u2e4K3Nj&h!54{H35E6Uba^$CuzBW7}Ksj%BzoMaF0g~)&JNNe$vRr2c| z+hvHYTuW?a9w$@hlgN+%cA>X)6MI@O(-|I&o7cE^)*4raO0B|B z)-Mp*AHkPg_BXMMvg@h^R$4Z-{BSn?*m5w8mEKV49QLS$;4^(_a!B(DbDS_@^+V)h z^_mID#ntqoc_z9TpSKEqb4xJwrX<)Si})#%JT_7!x@mw9M7| zE&79@emd9Hpj>ZJN9_GArpHRHpabwd3(S5|#W^^3ho3>(H^ zL!bJ6J6AvC`Aq8Pp>C>|bZPX{d9_1L^Lu<>^pcMI)W_MFlWy)+C*oj?6yG1Q#f)nkJaanpDf`2thHpJ00qql_Z_ zS8djKq~k`27bQ9#NmJz2+ zJ_YKZpD-Rb6EAEs-}!*L*FE$dXYDt1@A8R*)i&l2o!?>#ee?s?etB;&{l(&2jvs9A z_gu8y#W&B6u`a+mMh&t>xGC$|i)Fh>-w@vA8(-t}Yp<7fvVTBz^l?25jxQ{@7CTUw zV>!5$=zbU(qW4&{O?!FQe#E2~(JwY3bCHX0Hu8%#BFDh^gJ9^#h67l=iG(9NoX%@kfr(_9n*O@oVWr3U4Zf zM=ON|9Y$8088g%3``@t-M_c((bMZI9^h|oXd^^}LbP$ZQuN;OxyV{Y}8Z+`0Z@)t_ z8DAONI7?|hjAS%2uyU-*E*278ppB)+wb7s;Y~$pZk^u^M)xK@ z$oY&($=mahyZTPlx_(ZTgD#rSykxqHDldi-Yi4`%)(0uU?2hhUC|T{>07ar}5nJF8&wv6Z;W(D<8}6 zTWM&J_Hus$Z5`_UrsETR6W_%zKdo_QQT}DfcJ({$MM*YWY1xc3*cW9t!LR$|w>`FN z5xx!H5^M?9MREL1Khcl5r`WVUKE$NfR+!fBZgekxvIGBA>V4>Ci?dsaqXB&$!9Qm& zXBA(^ImMm$bJbu2KE-*(zu>&$oF9<-)bVlf9=5gKHTa|FKP8rfdoX>SxGC8Gga61G zT%O{t1oc(_U(#-(|H{0tvNQYD*LbV-edAhm6VL6!-U^}VXPGS_ z@@mXRM0e*M)8!_QT^mS+D65hG#dnprjq-lQT#+kp9pzojbKmmRw!Y|=EUG|(n z>R;fmDZ<|A&TRQz@4fvg`@p!@ylpw{HH&uAe{$~zNI!fv?Pkr<;1jO6ovuh?YOKaY zV{Y?&%Jt_K>)-i<-JGveI z>NfKQ<0Ex$?I=g@t76<;6*1AP@m&Ze46(jAuL^nM#E>IhdoVlZvvP8Fers~0I~7Q< z#{P^O`+d0Ie#xD(EO(UiiBg#z!~K~i^6cdPcl?@0`0e+&zR%Ay(!YP5JH7vPce(Wgs7kneFe+@c)9!$|D2ash;+#xXM#mi4%{#yZ?#oyMf1Z z?~Z9nHu3HdxAU&ubg4gi-=%yrkZy0j)Sqy(M)>_p{cR_VtxO&Xq_&rjtxTN7uW@Y8 zboQeqh__(lzul1uq}m2gi*IjK91702^aN9hn5k|f4#jr%zei%&cWSo>dZ?a;eMtk! zgT1U+LKgMu7!pjqkKNo}9Hgx2aciC42Oo7akFDc<+LbKkebtrsZQd`_yNt8{bqaG8 z_4@=YRr}#I!2yPklnX8iSOtu@Y#khZL}fb zF0B-A#G`KHLE?nc$|U{5hEGi4mEwPrckF~?^e)7wL%a&C zLKeU)o#B-L19A2jfQ!tBUwkj>Dspuv2UIy2@bY(Pi}ZTxt-2cz=RH!lKQIo}rd)g0 zqr>%W&w9yq+NW4V?X>HPfo9dm=teslX)iLPO?oKbS1eKOVZRldZU}Zzl6REP3sz_% z?x>f&g1L7hjBm|9N%9MOd-r6{f5Go=M*-uQ`9GJga^K`X=~q7X>+Qg<_j$6ua1|p1 z6URZcFlXp_xW=5b?#fFyJ*>E`=tcOnoPsU89hq^@*iCa?;IIAiif+CRU)H~jeP-?l z*suNb#@;*uUpL9kma$LG?O+c?d5QIWFeKTC?*wD@qTk#wH+W*pT>T$h5FY&N-`qGi zcw=~O&12cV&Z%7NWzWed%!DvApP5*?GS=Uvr;)vLEgDf+-&|Lvl;~b|e2g={reBw&c=( zkV}7wbYxO4eRXeoN`AH*`Hyxx|23KFmHa2U=$ye$TzA>B<_dg7H8)`+Yd^R8k+3E& z_HhUEfnrKo*u@<$(YJT-gMR_|ce!wxwb{LDrgL6vj6K3h_6swA%yDrxneVc7qdV8q z$B?5(kiGH)d(@1NmJ~&HM}}U|`osY3zjY0a3@vPpBra@qac}c}L!y6cr1ON<1mi5x z&rD7*o+4Z`Zu6~3KlWJ`Ke1-TAodXS$F3O?*&Q4jS>qeJVvSX6q65)s3XHos-*}pJ zHjKp{w<`9y4O&q1YT<&~SJ`{@YJfiWK%TYrdHf6FT;*r*2G@(YKEN+T-I#S ztDZ05*^uvO9&|6Qn;y->^NpKL^*hL@EsX0c7qO-c4Q~U3&v;y|Pttx@;*_W`2A4Gf z`^Fp9TDVoko>bmP-WoudPM9eW48 zyaAoZ7b}fUqP;%&6ua6?5q@$7G_^f<`0evutyS#r;;hEj&^OE!E6>_RKL(Gy+n>Ph zu?#%oIvu~}P|3A-Kln6qggN!7PtGEf`szvay{bTK2jyotw}$=3UsC^5Txa6UwxYL6 zw`z4!rcI1uA3ibkk5i4#G|?W2Z<*>U4`)80t6Kx%8@v{6%IMGgvf=B%4JLU{D(%FcQ2q(z`CEVdilYNuExQMdY-?6n2 znstr|v^L?3=px3t%2pX`^D5S^caLdaCYqifXbqiaCjSNbj4$`r!#n>Z!>$mE%t&v z9*A!kiyw-?hsqFF5Pb5fVcg5-6J7QfCVwaXqr0A>9Ao4v_Wec&aht(uD*AjarWD89~_9|i$|S3J2x_?I`LE04xU}?KUe*HLmQhfri@PX%y-;@ zxb(U$3WjWvd5B~O)sCr_Avp)c&(m}P7?Ft!@ydvcZKOmjzkwZg?((N1stCl ztBn7c@16fnapA9)-4nK+wK(B~DsT7$R=1-^QvOegpQN(&4Ig=u=eknb51A~+ryo5n zsrEA`s{QTfyHeBToBFq28}4lOgb44hHR%d?++It6gBHqfKa!Z%PI{7hiEi>~wb!C2 zQ^w!_gZ{v~9^{hViKz^1z!Q4Qz_v~6jI9LeDx-t{2KN1ry7m1pug`yyrFv&(abTj} zYe0@_o_++G=VCvx;&khq`o<*uTgQcrGnYF199S2XFF_DL{91lKFeVG!L2H>0GUj|G zoO#y!pM7O5u-hpk?>?K9f&f>Od zoqLL+9b?+2b(}pY+FsE%?SVi|Y4WtTX@BEtpWQa?1N50+@_UNkC;i%{eLSRX+6wM# z`AOID@nbLZ;KL)^rX4D4n|AP&wrK~>Xq)!;bK9ovTNs}E3x53;h39VK+Qjc<^r0HA z$%BKU0j{%oHeA~u85GUu-oAWrbOqPWmj*{`xpou}i3XL2-zgrG_Ho@;?@I4&cBMO4 zyV4ySUFr6puqW*2uC)C+*Yj!H)r`riwrQ?$T+wG$$9>NsyRbn!9tozs#D@2wzp38s ztApvi)7z$%o08_v*=^HKUNH65sb*|*Ewo<0AUyXZI zd3pMRb6=Gn+CZH`{C@HyGcmb`dc04)_IS3ozw6mLVH{^T3G-iv?OAT3PoW$4L!Smm z!PW!g;<<-CDmHQ-ENZKv&dAkfL;YOT!%e*mb(;8!ndqV}g}vV|;@fBNJxA_%0X**< znQNrSb)#Plmo8zsqBc5-&Ac&cXk_xjN0-NblF zm%hT;Vm3Mo@kUx>#eAFoAm3kuE#cT*JJ1!d$)w*nYcVe|hdu|k0A@0rST*ah!GsfS z?1x?oza;bDqD{o5+j0o(ViDC9&C9F_As1g4eV;>~zwVr0 z+ww6O0eX$IhwM=><%5(>44+D{zg;#o3W0amy9@kbFr%Cf{!_}RXT72gdqR6AwRhMj zJBf1jjUV&>LGX@4_+BcX#hjb-3x9_Hj`s`Spfu_#%s=NBZjCe5Pm(Sl5|w?3@^X97 z9#i?3U+bKa(6{WBUr=`Q7nE%?58l(a?1RMe)?5O8>q$>yLufr&bWv<#$-0MkWT|Sp~i_$J4jdlK9+9IW$M;iVH&bl{tPiU;EzK-;)twQ@W$MQYVZa(QT z&ggbx%U^m?%8hQ4i!CqALNSrjORay1XRH{~y!>bfzS}!y&GaW&Bhi{>2R_{L zF}Lyket3899%af^|3}|`LHc$zGRM)kH-Qn89%e4`;S(vn`x5>uL!WlmF-NW&eY_rS zZ{!_xZ0U^Bv!!<|D~D#xJHx%!E*Cm_5*__7>=QY{7^m&&qxv}Z{}FVdTgdM_F^;XA zU2CtY$_GO`Gn%{-`vSitud@$0IoIG@Da=L~tMqi~{SnCr^!c($=35WSPYa!A+q~({ zSl@QVbSI`s{G#dUF;@PrXXj2QZp)aKH~C(Y`ia)J!XR9 z7_?J|a`HK}vdW_E*Z_slBurWoJ3)Q|u?jO~{YCZZ*xdTG-S3jP_O_Ox--Y_MIs2D| z8>#M2y?g8G@ELnXHinHI(#2Y__8-;Bzv<^z%0v`O+YV-=_?g1KzM}l#Zn^vk zpYo4xx!K8oO}GBr-Wvy1Z75fMbj-?|bUx9D7H2+Wte0`7fh$Q2KjuTpn}$ClZw^{c z+)PLQ{4pzkY|W2O{;^%juM#ItG@)&YApY63)8RjKk^fH{m|d1GqgyVbKHI6kXc^=k z;en#HaL_b<5W@G=e}r2)KIq6)2cx22M~lp=YQ8(4emDrZ0Z!d2zKYKo@tJ;;;NGUs z+yakI z3%+Jv4X!kU${Wlj>{P$RXPx-!bZmqqX>Ad6$@-PxP@JtJ49W%mr)p_Z`EX!pHspHu_AR_|vPKeit5SO{iVZj8W<2 z(piT`4F2z07Y6@Y;a+?tV?y(bbbjq)1&1CIpZ;IaJV);xkblAUX}UI9)~-h8qJoQgW*!J_%1oSJ7Ss#+Ny1 zqgp1iAHsD=q-q{ki089!M1A0USAp{E_4Zh{1)Pr3IC-Zwhs%IX+GCnzG2?*NKf(L5K~j<;oiZWfNS1vK`()*{@=OGK;-1?W>Cyhw%~W028>%mswqa zJ>SXL*~_~w+P9DQy#DJ-FXum{cW6Bv8-JxYR62ne!g;KHpTuvN=6!69Cg_#N`Hi*K zF~8==y_wZl{s(+y4)d=3MrG*hnaMtEE;BUi!_)OOCypWK_mYPHx7N-tAT3rfy!os2 z`*x4#)V2Ypng05%U*8>iH4g7i2j7#vBD{G$e0vU_33t}I{vy`(FPY%@r>qQ`no?I` zmXC$(XA(azp#27am7%^+Y2hVc62#>np3I)Jm+3I6ZS<|fH<;8t^wm1(F_Yh)7zY{V zKH_h+ZjnrW8QTWE;(T<{$@mS9WnRua2M+f#zt>Ib4EYk$k1zR1*D)X9+t#v7Vjn*brgigsWM@D58G&{rOnq`YG%C zu5%*uvH;S(kYY8qsrelw6 zDXd&jdJ$OEV`ZE{iG5&Be0Hv{nAn>hdxN;}0y@IRO|J#|n&M_mJ(aoFNpEIq0q)fG`4gapf zA6e=B*faF$$%;8FUE@8z_a6HclN*D6(W(vK%p~vp3jfVc#@+_%;-N0<`M#AWd>H=% z{0)4jVy*09)_wTaEWhDQLhlQ*DGU5Lf0z)mp@Z^OM!?~rd#A%Ycqm@xc=!T3;HL6O zt9;&|#XR|zHIbh)rFLfh-tvz6y`4>Y9a`_g?=14Rop2>KO(r#3>#V&ry*Ecw>aYV`fpt8`-!%bk zcf2TFm{{!Cn46!d>8hioR|rQ?}rBrPv^}(`~bcv&gZvn&m6eaR=iBKOV2~ zG@rJhqNjs4jmk5ryrHJGq{!gAfM^7xEZUx|An^Si4e*dF)`N!Mr>t!%SPKDX`As|I>Or#%~>*Y=+#p_O~B>GfH6 z!z&BfQO-J}>ny^@GmO0SiAcj9?m(>wVpmPqfOL(Vq$M9%inQv`A z=hC+`kL=x8(3(FKT)QbhdflFU|K2JvKjxI}tP4qI`4XOJX7yA5ppEpsNpES@~2i<>~A<+S%u>yee-7KNqq>7)R1` zm0y@k64~R>yWds*{j;mmvHr*$Fb4I-e}V2A!~1zYBDu%-a5XSakg*|f1j(ph&<~va zbE=N{*RhA;cf8xkI0-raUic(g{h}X}#`6o%D?0nc%je9ru}HJhZ!@2M@)>99e3;(y)xS7pzF;_iubuJ^bLQpS2eRKWF;Dc*qJ9rwpg;EgI_AG5K4>{i z?rzGL41JBO{PT5ojn@07<8K~7h9tpgC0D1qk+ER0%IoJohq)3_d-Wma0%5C);iov0 z>)B_M!%J)UUok5_C9aI-%>70fFR_!ks!sA9*8ae+kx%n|1T3#LyYF&AezoC8L z(Rz*|PlP$z2A7L~Nv~r*Xn+s7c6^EdSAkzYOF7A_1I{_rVF%N7wG7}t*_X%1G0e-Q z_l;vnJ3q_ytv-8*EYiDk>Bq$^I*?00E@sh(x%56Ui)?(!_mM8XUPoQuR(;w3BRb{k z`)_(r^(B6duaED`?{n$Invp%MwkPnZ-A($flyeC`m7}ufs@&t~@GJ6xX{KVIWH$eT z`=66XJdu5%{S@zLAL0P6H=DKf=!8Dz5bZlm;HzpP9) z4-F1oz+O44DqvK#Lo({kHSm* zte_Kf-mKO5e^xY6T{!n5cQ(YM=-)bT;qhNbcBd*#3LmK5m7M+9%Go>Xov~Naa%4MOzwI8?+>MV) zs=`XG#s+$vJ(Rin^gVaOnJ1W!oO2+k)49B>^D=X1j;Q}A9o-~%`UU$ zUH3@NGaBA}`xPdBN8h@R5ihf4XXC?+Xjx7<;-PxB8&RHqHbZ9J0J_+8Wb0krst_S2><+9xrbpXNTr zkkCF&=(19}$Tsqo(Lc?~#x*7I=NCO8SLp{in%9Wtw8w=nzhrBU&XP6S#}LMz z6~Eb^N55tt1LJD~?_AD0wCW_esMb zvsYU4O9%8(J&-lkp;N&e23W22;I*fb9-mzQH}Y&?=@n-Y0O*HhkXfCL}QhA z0qfK{6EI16Vakh99&%#QLY|AEjhnux_Qu3FNyx7Np1bX(us&hBT3O+h}x z9*Bd~F{5&6yXda-t<|RAa7{0LIo<)ryYY!94v6=TY!aWohF`{XqrFHgH8<*fE3IQ| zyd}wxjhNay+c@X-B-|r+>WrR-QN*0dkGetVXEijpKc~2??K*<4`lGhcai;jDPgJk#pM z$I{!+q*dP1vrJ0+6bu+#uFUbLXUoJxw7S9B<1nTryxrx$o4xvBH~!O<9SXX&*DLk2 zD=vu7_Y8M@@4d9=Fm2oR74y+}+O&=H>|Cdq>HuYggKqzAv%o+&Z>wyfG$G=i16hlZiHX40imrJ>lYOD;xT;C$oa?wd_0!`K&gAv+tEbEe^H>O-O8oYEc}LIaI1%Qi&=4zC zy94~7%t}Yfpvw+dG+ghB*Ebn|Qm07Xv-}bILBpjke~7sza)#Kg z=+P|^`s{7>1@ZbFF2C_y+g(!S+U21wip63vJ~)JWwV^#8Xr?s7n%7@R)Be2%WX+S5 zwUpnMMt5`xKgByr2}@)@#@a^ruGkY#>|W{_xij)a>w(A zX_xizQufy^9XO_W%&;-dAr=)ZyPS<}l*oBZngJE<~N~gP-@p z!+YT03V7ED&u)MZ*Td86;O9DGK-Y9!^`{N*}d@V9(eU#_}d6SSHP=v@bpG_yZ~OT zg9kUj*X!Zwb>gLX2QLlni@?J=J;TQp@G(^7jy6J_kC9$J<~e-K>xwYnFYUue@ld?Hil2B{ z?;Zgkiyc0O&`wzs!JDmBNF~@f# zH#=yTOJ|%7B%T5ob(I0rH*$x--@PtQ`&5l5Zg2m9K68Kkv7$_cPV=$hTso6|WoVj^D|BsNd{( zq+kE|Sx)+F()-8PJNGlW?-zgAxes!m7r)ENKa>3Z;-k5*8ySqRAl>DpTco?=A5mY) zy|CNm{}K1}N3gRo_@){E6Fi$?%#ZYk<=nqrV7By?YvDg+s*ga&b0|-1e|Nu=*<9@4 z&+aHX!S3s!b+U?n#QYF;=3(t0V?W6#{BM{yKIOj%<+3*Dk`@Eg8A==GH_6ES_yqp^FudDFMp#b&+X2;4?eC^c=+j(`9V^}$&lo3W(}mPe z@$?L~R0p=yLF|Y%*v*pD$J@bQA+PLU2M<8Ee`MaMU9!=asBXPB`jXFrdt{?8S#H)Y z`Ph1R$pCcZn$c^WIRSobM;_^%x!`4^cIm7+oiW$M_ps^r=$tvxO!lYFlnWlR9u5|H z*2)Gi$v#_g1%Sr(rFvf-@WHwBKS_ zUUQIr9y)6;0sqMpkGa`LQWV+A8rMgEfxgCy?0#(|ev;H7hMgTcnK_4XEql)g+4U^8gYbl}@*H$xhkf?& zSLs*V(8=#-UWyU7VH4lS=H97u8f*AISpA+b_JeH9kwqh$MVAQr3FpADw`F8Y9r;7p zAHSrZ-i=Lo7)-_H+4KXuVIDWs$1vyH3-9V??n^z24y?2Ye18qTU1>%-_UQ)brEjfv zzA>`vU-`y#_#AQYzL6~#@g0qArPTZ0+SmDp zWQ}b01bbkvpiWz$9p^+h&*z-^_uQO)weY;2AJMO%@kd3B(-P!Z&St*#W)r`wxButH zL=IEQ&Icvn7sFZx@*U@W$`NL=i1sP|q>b$;8(T3sY@V~SJ-fynB+u`AGMf*PF56o+ zm_r}r`F;H7=#(p)96Mb0d2YPq7iH-p`Q$5%wB}@*Xy+~5vBs?Mtle~Hs5^x|CO;$j zx&+Z3)`2-NH&?G?4tN~?$M6>^!A{N_7-?4BcyWPo&=4u!F(l8K>C)JPRwH4z4Uehe(ihh~Tkx z2p|7P&LVC5Cx-6`e-ES_ZweW~e+Nbp1-wjy}8lMJMxo>q9PQ&G+^nx>8QQ z_QBxe_-66nU9{VeXqEyUR&8_z%RE<8$_9PpgYQxsG^e zrjRSK=+-TF^Yie_i#O4xN0H6K!ya=ZFOZAGx!<(~`S9-G;mu3=KPLwhcTeeVxYiwy zxIOWPYxCl(&=Df;C#T*CFLK||{Go4Tzjf?8H&TwykPbCw&*)Iwx=Hi(vyd&36U67~ zk%4~kSo*K`gA-ac$EhD=@vhe$eOTC~;?=B@tQf#`p;ET(uWD(D2(JxaxPvWZYk9PX&@RmcQ zMd%AP{qtw>4$d3c$aw=t^&-w4s5*MixU0qW;>z76=tb(QDavcO=SK(B zmwk0@2ZYo32HMUU1=^pO!)m-`lE3bjpF>OUiCMY(>3es+Xz&5)FJEQ)-4WU-J!>@h z%vjbE#gh>7_mF!`b8WfhZ*0`w|3J6B@cf>pa^r7gT)8dI6lU)763fUGVz-kPK~I;S zRKtBeHbBJfiqkqLW7IDt5V10`CUP`C^PJ7sA z(;cDSONb5GK)q#S*Sn3sK{f+=iF6$=_OG6W-9>1JV)29zfE}yt)SW)tqqC7C!E769 zi4CcC<<72nj<$q*+oHO7BYW8EP~4?9grA1Cv?B)o-9|p0kG#!2#yJ~Vu@qw4^PMvy zj49cvGwO9l1pMC<_-3DTBG6C9a!$mP#B_VoV|MnOFcuwUL>KL>ehFIWT-Za{R^ze1 z)b1QFYt?q~kanv5;oi2-N2WLR@-l)xr*?~nYI|L8+to&=?a&}XTSbH1nH{1)sS~FBz9X_(3AjDkn@QnJ_z{4r1Nu zeivH54iO_#u?w{Zk;{8upY*8iJ;QhE+zn#V@A{`SJ?`v{CyUKdT>nbil+$m|U1H+r zp|9oi%BQ$U3ddmGkYFeHrj7R>@sA%_F&#meH>Zp*uYu`E^%G>LSZH%8$Jj)M8V@vlMTcehZS}S>xc zV|t{^S-X)wAH&wsy0z9uG%slF{v7#Ju|`x5&9#Oq-9mcNi#%Vq9a)BKt*5?j*6FSf zny805={qy96|~Powm?JSTWfqPhppXocetB<;hR^GmS?cBc=mGLpm<)$?J{g(3%%%E z>U!Heb9Dcq{1UW|Cp%j2h4|jncl)~YC}$HmLhSB}?hg7@O;2Xaf6!*#ySW$UqxxWHb_3M|H zS&wA(aMQA3A6V*u9cyM#pUzY81BC|WPoA|}EB2x12UyE5=f4^FM)qfp5=}NhFFoH& zIc?ZOzQ<(`xw?|F4NcynB=(Cn3Hy<-n?Hnrz9 z)~g!OnIp_Mjm%-p`Kf!*@9NO|>(4TNt^e)CW(y&6wXfgsUHnwhorbmC!J2A>ce@89 z){K1LtnCH|i12;w&vq@ivpWC}eY7D=nTBU@&r}272%Uv5IDNcE+E0y}U`2Ccl{fFa7u1 zl-sxey8j3J?|qd0Kh=MS(vHjt$NKN&UK*A5(r7c^{{J)1#~(*0^{4--aX#&TkWRmZ zMqB#O>EHR5#>HD))xQ=VrPJqq3xu!BUXYK07rzsq7d?>v+kmbn8zO?P=FZs;=#Hk4 z{>=Zf9YWF->HCfifqg06Q+7lRSJ@3-Y=|;!js$a)>;|P#?oqoTgxyfnYd1*e{35&I zP59B*ZulabL9!v||B%%e-EqY=3l+?8bjMEaEMbth#t^_7zmre7_cdX3l+D>cB(h51wxAe zbZ7#{oX)$Nb5@Xc?{<}y*CiU*%=53Q9BgqJ)p1`BZDePuJkdycd0jBz zubma}J2n?~N=`pt0ljLlO&a(`evCf`HkMa*2{xDPlKI$Lvbm5!o1Y-BOs}nc9aY9qhNe4w@)tXvj_5p-1i;@`VgFTG_PTvi|Du{g@w& z#=|f(Au7MKk&%-fABzZbK8Ac39`I-{9w1w*oq1VuC5GL9DfN?|op3khpTjda%Py_? z3wO)KBG7yWU8}43KXj^M797LfzM{0p0>nEwhOzmTc5fiHq(*7k7^O$&xn7^PNyWYX zh+r|F^rlHSklm2$&nFAxVxHE#{Z5~GTJyK&?gVqS=4|tO&)S&=e-V7n@|h1u9yedl zJZ`?$^D~r})cp12vHALalb@Zh84u2Ujo(_|`Pv8ed9)pUeA2qBT+xmSVqv1As^5k2 zpZ6JWv=iMp??`5~=5O&x^S9>l74Spzw*LRNa$L4M3;M~0ZrutZ)c{>b$|EsxM*t7J(uYU>tQPvH;K3Ts&{yqRt)rQ-- zO70eMRX@sj3U@WZkMvUGtjpB09xZ;Mdqy|V);jponaS!>o}==~;8$s-+vng%kL+?I zr^HX$6{DfO*64*JbyT?hc9lsdz-J_vl;6G_8FimuMllwlLy|ONNI5e4hF)yvc4UdFL+9tR^2^#pTE&*(e`? zs~&-;o%4|!8(nwVRfBrM&?C|K_Eg2Kim>Kse}b>U0Bgd!fyl`rf$sM|n-cd%)=sUh zLWe51{OD>Egpr5KjsF8Mz}N}kG}Jl7o;=BvFlA_MxrsJ?%D2|hhB9P;=ACwE-p-nQ zU`SQBba|}@$Jn!9M*NpXWRL+T+9y5_@WcZu2f3OUY&L67x|jQP$f(C?ugbG&-{Z7d z{$uweXC-s*L)NaQ%@OFZ0C{`EEElpjzo&zB-cx92^82&mrs?geA!M%PZIW-{*OMyC zOo?ZxZv>gwfp5Z8^2+xh2G83og8oL@njCmx+^(|H$U|@uV*K(h^J;ZH_Z^p09)2L# zQD@2KCfaWg#a9*{?}f)1_{rLlQ}5)}yywg_;C#d+-B;J-79&XRQSe+lWJ- zN6X;!Mu(j+B zrP7S0iF|lY*@3g;(le$}eKx5k`Wc{)$-kj{cs6!U+L0$_Dl`>9w%={K78Vfl#lvaFCw34SZ8m5kM9XSXmywipLD7E z(pHum|2}2f%7|Z~e&wlk>sNc1P|l+b(UoZ9Zl$^7EZ)~R%Wu}w$i64>jN87}&1RuX zmFCs0b;ihSbSZK}xX>C+OQ6~*=l1U{(r%Y*V~i9ZBz-iMXW3VhQSIQKbx-twFMg^q z);}kCcRA1U(S2}e+`Rex|5)oDjvu5rQADiQV)TXll=7EcjZag4 z5be9x9xBCO>>W5L+T8EA3kUzcV9{g5Yquj~<`Z{6h%?FeptHQTZ)N>;V-7LdlwIt$ ztvY6qm;0qG40jDQ>-u8f(B6jq{Nytfybe4iiK`WR=D@Q-YbE$tHwd0k@8We=_czhK z1B;`-?f3q|`Tsd+5&O-FksV^~G`seuc%;v>Hl3kc<$DkxNcZdlRwoXgIAQu*Lp$=V zmT~5JC2e?XdER{5S<7*JoCoVya;`6NTFvL~>-3p8Yj3-;zcjWQqZ5!%?fhR~XqL-Y zP-%SY*7!N^5kG7bFk~) zd{_(3&gwlju5~Aq&pZC^SpoPafXp9AdE}Jzh;*R*{+`T>%-}4SHN@0a!wdMoZ@?%1 z?eXwRweP@B2e@`M@+R^yvJIbiFcNe8{R?DQpAv8Q5i%8du$H{SyZq*l^WzSQ9fp{) znqCcY`NYFo(`X!eW+b5VuGt$C_)2>X>!hu&EQ#2-+5AL|di1Rpzy9pTW9%6{>a*4y zy7yb<)o-tk=21@UZN%0wwO!w4H-ax@O&EO1kJiBa=GVu|2KOh16N3|C3^gax*qudO zLJQ-o@w_rUZl1>UbjDF*s&UkKwjeW8lr3T$wch^$aWm6D51+z&2cQ*)-WC5lG|@z? zk%td>afj$oWemRYtJg*rdUSIDS!~;*9mzhmv%+5-RU4um4$8B9@9D?yL{slertUSs2yH-L9G{1h(eChd;Dt z)OarZQRO?ZrGLh}^ZVWSiy9B)(gtMVjtKI+3xCXpKm0C#a2|Yl27j1B z(RO~~ZR&~e&GLtPCe>m5;r6|<8-GYH$i92Y*5UGp{X*1R1CGwgUWwoWaYv z{X?`TufWO|aA$Fej_ZO$_Ea2EzJS9c;qS5k2L68R;4cPE+ch`QeT1?7d-!X@mdKoOQLB1bl8==_`!OIuk|f}-`~@bN`IZb+cmR8jva))5gq)P7|$BNm*({C zQKfnL=%4a^6_`5mxitH#(z@mQSr7TnBW)^jVLI!jL$D)C_@!t=vZC*YcHhZ+I+NvP z(k2j}bDjx3l6P=IbZpjlw&xwJoR?s%w;fw_C806~pQyO+J`1U-tG}k+WNge>x9e|Mk?< zfbBQuz_{p~1C{gsLiv91iErj`^jjAD6SESV&=aGeLEp^l56mWicAuTZe9mB9!OEg#J{6O}m1=;hpmslItny32@G;9p@iA0A- zrXDcBS9^EZ;^%exaWQ9ay#`)S)<5sqBh!QA)7hQYr%F7A^pEh_2VJCdegZ+xwjeg~ zDez;@6PYuW`og78g3AWv@=@f|9MJmD=u?>bpqYd7fl>PwZCmtRZR?KbI`Rf1Wj2rE z|Kw9?g|0=n#ET*u^KD1uN&`kOFX-D-)-z{a&qw;9prthrX9K447uMRUi zh&c!6jvq_>l&4zWG4lR9pal zRrYHV4}#umLMAkU<67np>T|?DIJ&P7YX~;hz{F?N8qNwwhLA5!nIQNi-d8ac5p{x*hFPeB=*bq}~&sEznu7Gu? z0+aGZroN&we-T|@V^*o%rTs#j4aR*!w7Z15e0hfRj2yfOCytNLvBkv)!i(lU{|GP5 z{~}(N{~f#-;l&?XHH)A6F~{QMx>wZqu#0o0dpH-abjOv()5DASK9tA2oPG*Nl@DEK zagqhiGf!RBq%i@1c09-<90@l%&rr0|9VeS;yQgxJPr{eh%Nkg77%?E!F@I4!)h=Y1 z_LL`G`_T*tt*T+HPv+e5cYqlg9iPp(sC{cs0E_5p4m7B`W-*4R;YVqPu4ET0)>QXM zUJw2@@jiz*;`!v)ccsfd5#L^+#4-_**X2Qqbsm4wlK#z8yZ*~DA}(4M6;l?&m)^&D_}nlXCS@77&kM<;)BHj z?ri2=wAc{HvGOO#xUJ@=al0N`8{w8KCm(XUOF8EAQ)W_5dLqaeJN|Utr<0Rt?yYlC zOV)9RZ1nNKplAqO8sd&v58wW4^o#cUWWp*w6TW5#6wl5bJ|(&FpHYW=C#@ypiSctrc5|0;Ed}lLvFpE#LXEu!dDyMH@?&47Yo??!E?9fpB z#-Roqx@7w>2;cKTxvHmNzCEg0H>{TpEu};N9LYjn4crb={GZANB4k z-wf_G9wqo=)UTzCiM@k@bKw=ME&F9Ne!deJd-3gNe0{iXz+r8#pTF{y|CvH_eqT>kd__45|C1t!F2(09*9_4grG z2N|P&cG|PQdPe)cG)DWuo5o2rEE?5#$p`6;*{sjFbAq;)B6A$y(yyKgt1NgtSpR>X zPtyl`=F=4E|IhF#dSf*|(ebVS2A_V=>)+?o*Qw)woKNXnIN#~tv;QKWE(WguDL(Ck z@ABW})BU0!TUmbs~FVW7~bLCsd z6KAJ01i0tS;48chy^5TdJ*{{}>AT(Nz&p@=+m6eb{_)x7;BV3MZ39E`IVP}fHoBzh zoe=Apds_a=La}_?7Y}L!*OzLaRnr4CB7qa(g$H&XpUx; z?m_v=v{FBQlH^){>_DAA){8rolj!;!^ksxL@XN&v?MP>>L3f0aak9m{Hj?n&u!lHv zox6swS9`P-=I+&FxtmGtyur`p-B@Zkv(H>RjXPs*C_NutHK+Nw($)P!D|4Bju>N~V z#GF|g<_|1iz&nm9tdk){iZaQ-RmSfjPimOzP^Bh<+x8*_^<+3SP&Uf%QIhavy z80FF?=a#1RRd?S?j6{gNS^Mt^JukWYpZxn?S~Esz$Az0FzkE;ldGpGeF<0|1`K!H8 z@|g;jZ0>O)zHZ>wMP_AtL$7#CWA?Mdp*P{k8yDfs!`Cu&i0Gh#v9@P&5khkC^uTKyH%?l!B!vmZJqJo|g+EdDuhzr*~o zUAK&n--)evHuws$R#O(?oO^6Ft*eAxdtZH-KO0*rtFm2lswVt@f1n@AQ;toz3p?PO z_}?{$-bnh(rRKE#!#NYc!cdZ!Lt8D3o&3QsgNt3;CotbEK4Ser{Qaw`M|o8LKFZ#0 z>n~2cO!_vfWBZufRab~Qv0v|Af(@;@+i2l>(Jq^nUrE$bY|g_j5X+4%&&XonNvas57xh9c}BD(8%krn2pdZ8m49>I zXSwgIw>z|^bLu!hZC$u35Ie7*nXh@?HkaONfLHY8(ei%AN^}HIg5R!mthD18caM%U z>8xDz0B?NBZMz(~sqdU2ROlD2f&cK$`0Am{!Q{OIybc1Vnv2(hzb5>aVT)7l-vy`d zii9M^ z@etpZ@DAVYm{SzuZeIC#Uh0sgyRrZG;79Q0v|;AKWqD?Y=2eofTBCJzyC2=2JxVh4 z9qhI7(A3=rs-sEt_>}z(k8DLZT%E3*7e=SgXB|!Jds{i5;MD#FQR#_o_%*k*H$3u& z$%`gU-numKyaP?$*e@p=GRm)VD)SJubq{m4O|*MGZ9UGu z@5dXm7AbyEVHo=ctH=#iy;vz|Dc8QJawQZRosJ%%@)S4_&v+U%XD~T2qrh zQ*-#9c<*5SThBZP4v*sufyePZtIzY?K0ogEc?Rc*?V>I9`4r|yN9ynW^jH2M^|#rz z@8!2u{@)&XT1PV=>3p?aXuK$Gwn#KFoRT9z7FV^iR=q5V}7SJ%92)M9-gq?>Fdk z1ix6VKPRd&uDSWfS2TzFwoB8Z=SvyqOg_;3u0DgN>lx$vZZ!RUWcPtCG(FU%=@LuR z#HvEmB^fk5^dHi+)__FQi(HzX;nH+{2ThlBq3I*>vDfb!`aRq2cf{>?mP^~}_mm#` z-4kuIreJCNY4=|`%hEQ!ouKR6x#8cSZS~{-Rr)@kz8(X8D?Vm1aTDGeg%fX+-LW@a z>qw5w&Pm+A{{DrEvA9*fdF1Zt*ceUdNymRIdn!Be+Z@jFWPL(<^CM!L4C5j^r2U+e zf^SbUc!}$$)_6Y2T0|E9MCJ9?4_4r_mJKDpS$8?j(FAwCzLPly3f{z2eUWt3m# zR7QI772?9W>qUIt1?9+cPj5X6j|(18Z>>OY?T01=&-?88KN37){H>x7!J{<|;pYV8 zrt+5@0iK%z`5k&o_JMTcG?R-6l^r??wOpAYI$pKl}HNAxNfj%EDh50)=B{Ab47 zICPox``2B?H~BbUcK;vcUvw7ad@ZZT{DamB?u$s*xgPA3UMGIdJ6P@RVPj7wx>CBa zhOw6&CEGObUf&`D&N+7>kjTq6v3ButAZwJ?((_Xdtf^Pdo8ixkYF%9MhMo?c4xe(4 z0)DC?qr9_8J$;%aeHQw32KrPqu$4R-XW2+wzz23tqVB$|Mbfh)I5)^yYwZ@BFkEKu6>2CVt$))Bl za_KrpE}_FR<F&ljkYp-)qh0qaxPH(_+}lm6^z2wAY?<{PYi^EvzlUYSSXr_6G)Z+enV z$0D18u51!al1+k1vPm#`vPm#WHc5VaZDiK(!6iDmKH$I=zQuuS1TxAiv#1BS{#6B3^X|y0XX07-d%Zb}Vmg>#ug@yFc%*#J!y;ck*fO|s=(qc~B)98|YD)idM&9&1?%dwS+HjTj5L{tW1=n-NqkNFBIzGs+;}6bz zr;dA<@C)-RZ@vkC@lB<}%}o5aGfVMtPh4aC6C<=$$I+#L36?uBgT zM3O9XbXmxEdngnv_2DzE&BlLtw`A+E(q7n_q2?ey{gI{5ATz@=?|j9_dyx0zc{hQq z-Zj4uzcQS(FlpaGCx=M8p0q|cZ5y`r9MbB3fBh>rkk&-L38eiX7%Wxn)lB~1MwWg% z(hC=Iud?gs^eU^#>Q%;?F+NrKEbvE6^sP!?)S!Q$-_x7nj#9+o&3?!C3 zF!+`eutAeoTpagozP+p?J2YYvE3schCpuqE`?OABPB{bpFF(o3UffagH0#^QT-gWV z%h@xu%q#1}EwdIdd7aj?$Tt$5mR`i!33V68!QDm4iIFji@ejU%Z!XL951le^a;h;a z7ToysHx!T6i?Pvpf`jKYzGve?u(x%dTo`|!VxgoLTj{Ih)%b#j(H9qmM)yAJxYFh` zKUaFoQNhwI^n&IYuj20upmzoQMrE`PFl~$c_blIj0 zMzH=fqO=ISnqQABT~Dmg>I=$CzaIQt>9PxkmzIo1r z%thF@f_~%N8|D{^%dz_xh>6i!@T=H`W%m$2AV0}>S=ab5v`X_5&i$RtnX!{+{rTx{ zMBaY-8@+yCeqHjT(5lbV_rCnJR@DdkJc@Me^Mcmu%2g&fqO|JFQKjaO{IhnHJlnUb zs%TniRj9V~O5nR5A3+2fth#nYY0KEkRhxT-R<&09R+XPQvh*qH(LJE$>c1X()f&EHth8Ph!k-c$rYcN4oNyLlY{Rq5 z+AqyAsSkM9-qvP#sabJXeo7&0agR7MZo$x>q-_^(3Nmy zaYUX>JZ)C|0^eUmr>Xw|p4ETbZx=^i-@gox`1mfLLUNJTW|{9|6U^=xiZ6vOHK!Hq zO~Af;fl1w~eDre=^4#;e-G!aM2fJGP4w$=)N+OTUJ)xCa&tu_gijTdkihKXg3^Qfz zH$~f;b33t&e}ZpY;i09(J&VUYnJxZ0hBasL*Cko}&vX3a7wWmud7j8~n7wNDKJiy| zP6V>fuqFy^Eit~s=HTAi+Q%o2pZ=FKCQMg94%YwP`tu~)W%J7)x|92NTdtTKuM+;O zUcuK!Uik+8!nYYYq13~COIKy@==*gu<%2_)MkRQGVe<;Jk-+9&gB5G`+18_nI>Z-lr_?ixOIw)tn&R?3;`iCI4G}hG6LREeICyoO_{BA@Ch+! zJ@Lu2zv&#et}qoPw!wpofNLmcGwa;%?^Bn7flH! zjfHsQuPMd~I33>5+29%v)iv0T)fT=-pfAy-U=>}8zKWr}PgXg&>&_eP(3Hm;lU_Lz zZxnX$#wO;{9&cO?{GGfZ9A_miQ`%v?QFH{}Q2!j>c+tXM)FW@a^Fk+%yUI&&?D9qq zJnr$vsld?58`2{=iIbFe7;h*JzB_M-Umf0fMELF^i@dw33oX7M0aVPH(@&?JPx)m>E>xSpf%B&ka zezL~NpF{p;WMYn6_lMBXN5C`0cw%4s`zve$=}h{WVbO4_|2Y!J%SK z28m~KOwKyN`3CU5LB2^p#-=-PZuBrXseenoqr;AeZnpLBhs?-J{8jVu4mcHWl$ZFk z()v3vS~)=<6pIuJ=#+X7Q5N5pe!U8K>uIl^e3O=Sj)SAiidS zO1wb3n>zZZn3Sx<|594vg^n%*W=EF|>Bg@`t}ZL?;MYRR=?wdxblE%q0qocgJ>h+u zi}z#2uNLn)iMiCJv2^Ie(PdGk9ftRwbeV&9>9WuEGFBGvvK>5}t3C(sAM;(~p|b)v zfq&^T>2KK;ZTfbLLr)s#p=Rhh@s!r=BhqDz$)xW)W8&$j!6Yunj;@X`0?b@kjjR#poO9vS-O7T_zlrSY1{$s@~OQTbK2V*IRv765WgpkS-bzJ~jiNgCo{c z;RWe5_Hf!hdpe{Qy>XPUWSyl|a4P-g=nzk*6^)XP+eW=V627Q&>s``sc|Gg5?{$u4 zS2%|zwuv8svyHkIF`ly3jsYHz&t=yQ;k}JEf`JlCD~e(8bevIvJr@yN zz}~6nqzjeDk*zcN9)|Y1>$#!ml4s{SI;=b2oRz^heIGs&-wa8JXEsBZBj6kH%qIG_ zjrKNm;9hbeD41Ed)eRKFmdLYa4j$;FQd?Oll^xSzC_TnD-=6lT9d*&PX4!GKe z_luuv@tl*`0$gjTYfA@Q@~`D2xL@0*i7(s0Vc6AgRz4y(gn!}Pi9r!RJGyQ-<+ecw z4$j3p#o%0Z4zV(;gzw@Nt$#VPOy8XGDBzpJSA$)?;x0LCCh=8YzWo_pr#V|W_dROf zwk_MtzvDvg@B&7yGiJ_NujP(tA3i$6UC&FHtBqytGx;Fvm+}FUU-Np+Z&gllJDTTK zGLOHIa^8G(=4a^zm+|hvG$?T*@88-_3=;l1%||ugmG5U*j+rn2oaVLi0fnZgS7?ot zZ8Y7#OecN5A)AY9(3|~vPXJf@@XM9?;`R^FHeGgH2*n# z&Q@UQ=iAtNoBQ{%_VIScWiw;s*rTH9?8FwOx${ZUixYEOkoZpE$n!|iv%#kBjtk9c zCf(=I^WpFmCnSGF)8nD%trn)-#2eHlTibz2c5QBAwbC+Ra^{eHW8T_z4(ZUcNzL))H)mDW8y z>&+QO>z`cV;NRm1&u{blOur30_pHlbqQS0s$(S>iIXrPJcnm9<^nln~I z7v5NT`n0DxV-5K`#)&cRK4-kjjz!ON#!28*NJz&iIzn z{)IW?C<}YfbH?f8I&u8Z%o(4iuFg55qf3`6?XWqc?iD!loH3g+htC;RpTidichgsN zt7D&P&e*9(_vqWh=OdpL6QXp7Up^(hFMfIXNPE&vhC6`d^Zz!nSdI=XNWAzdbxo8k zMHgSHad&i=bn+jm?|bCcnuhY;RLJbsVs7ZQ(u?-GZ{51&WmJN8gn|M(5aS?jC8 z7QK&tbL>L+#Pn&NBCGyiKByo?*YRxRe5>Pr z#`h%h$gl<&0-jBQJ^jTajR7_-dTs=L+hpf)S&35m(K)|#^xP1o zxpuN_WZ9pNT`}Z{dM*O&N78fCM|a}ek>^ES^&B>`r|0%jPv@L+XkriVvWYwOT+u(& zb6=s%;dZffnPV4U#`jI&SvIleIgXxm#^6G}H62OM$v?wgpyI3UJkVu639n2#zH7do z=9AM;{yX!@;r%=3lhC{Mj{;jyyz;F23y<_TpJaY;#Q7xk4pdq2yOlZkk>-=rIfKjN zm+tdPJC|hqyt(9q)Yr);C5iia*ZBQ+=8~W6%p5=GK1FOF#?P6%Z038@5$2M8p*5}3 zbk~2Gb4i`;C7W9^s;dtMdVv2mpVVB^^TAkp>EM5dM=qvchx=fPkKlvpoJ+o7VLyUB zIJ^_jj{b9fbm$&WE@>|5`Cv{0hE5-h*41+oqm*`-TpE;UI!ym{&Ld;OcNZUw=8>w; z;g|37U3}6xk95}XrI%*&Z4qyLod@X=g3DazpE1mCqCo-c;avz9XUAh4DXZeyiWX_pLmk@0`hxv*(ToWnKud^>Ec%9 zXHTi~J}B`g-kVc;mu?-L_)p#&tqzv0HaPJC??XFuva=qrfi(H>+ig86=cKQ5({Hf( zWfv7D-XQI4`>uS2i8Z`mpHcrWd5_t89D4pH@4v9{I{p;Rv2G(xbD?K#x^&*)#8%Sf zyP3u}ts9DGSz~nj#XdQ{)uEOcq=}AJTR4R` z=#BJAZhb$s_;>P8Anktp?#R<|ygzH-UHB zPA2Us`z~8*Na6(E-?i@!e!s^1*Dd}W`|M`ke`wz|e$KeuK$^yDnH^`91AojbrjoAp z&bw{8;AfqV^sC(bC)jkSo++gHJMtAJF6RC79rdxEO1X({xi#$?ht4(JFO#lz9<%9c zpZh;ad)2;o;%WCM&Un3H@#Ky(vh;7HZykPN{P7MvgD=`U$!%}0rGJe_VPX_%(>nN} zFmWvJ58HS3gL3Gsa+O2hjkM|FGiQ9?ciZ>dadBv2J!ztaLTJIUHH#DLNUP-ixI>2) zIPqc5oTs;2?+3PC7tgepO}cyn&)Rf{Zhk=>Yixhi{*c5Ayl?O5w`0@&FVbXZJ<`D+ z`H7#9_Og9fJq3xs^1i{+gZfvH_?Y*7yla2m)B6uCC})43_A-=*j*kuJojAL>HFkeq zzTMBDJ$i~&(>^`Lt5qF1#NRh1>5OwqW5N|KO<3>iFQ1Sqnd~^$kue*ayCN)_JI^mos3a$5QvB+;Lh3 zJX5s~fcD?#{-_zmPz(+Xjy^`bRetaM=npRJy!XX9bK|v+xDfH>1=KA*_$l@601rXk zQ5+c)`+#@FohiQE+l!(z!oB@o`H@gu@jwyU4eE?4Vts5Z5bf3wTeE~dYrMREdv~e` zkFCt%Yq4KnWdE!7vb5|pKcC53>yiX_l-YTW-`?GlBwi=PnQ3KNW_#*y_d0hLvDZa( zIvKbXhpRh_iisKfJw86+Q1Ly2gYyI8oDZCe5Q`)`Qv9L*XkXko_O~dmmUGwItC{OH zfbS~ap$Wx-ZNMMOokoT0LYJ-hEOgoXpAlQXF?5-GZ|`T^TSP3L&PCbSFF$%WeZ9-> zyDm(81)K@TFWhY6>O1jv9pmoov3uR(9-OTx=4>(iDDTNPs(qb9c>fjuJAqYt){X;r ziGEY#V7P~f@9b!`_YgJnUFUV_Oe39Rr18C80U4W;|WtJq&y*&AH5pHTaKlEjm> zfoJT@#5nhSA>nl#c)p(RW4W`w&c*X7bsnB+_eglw{m9^XCwLwk7-a8X zYeO~Vsu>^QnsebcRx?JLJJ|c7K6USh%Hn<~>_*)W^*%H+(~eb9;xnG@88)AH?uhzr z##lLg;+&C|G~5pb?sW&OeAuhOeF5*@{ZM+=xD?z|VDE?W#x2L?pBBz}mR#Ay7(5C7 zHCBFPi^oTjE#7|08Akhh@K-XfcjA}VI4K@paqv2;dNKSq3%~y~@T_>uR`!v|UJ_kT z9bi_LbLRNe0<%&$4@I6hrv`eS&lwtZeF~!7AJRdKnes>UGM4j&+Tau2L%m?wV+((W z3`zUh|NF?Cg?n=fqdMPGI_(bVK<%nc$s#|p?MUr56|>(8I*_a`V~<)0IdLTZ`w05> z_%FoxL>U{-#g6J6%@-LL^`U_M#4lysVU;P%EY6Wxamslz+>_nJ(ap8E2LCI-zs~xb zN-W@P?(V#7{i6%*UNhQ|3@yB8e5x<<<$2ECmb}m&9MM*;bPwaW2H7H7UyXcubhhFA z&itt8-VeTYCR`KaqW*d^Mt#!W+i{VycF7y%k&LNbV>ZlyhA)MFs}59eyc8O~6xyx2 zCx1~@2Hl!I{-|hWO+REA^)v&gCr>l)>fqkid3WqfuMmD0A2RX1(5PfagneUE`494c zp)u>UPf0REcT4|KXJ_hcyTzR4c`j#hjXEI| zKbG^j#?z0RPcZRg`9BWaozL^R{NKn==LbBL-6uM-Z=Yy$-?tX_dns?xU%|U#2l9OV z*7ads^{>F`!SfUL{k@ajFFK1dWxzDLZ{KLVuWy|P*Cv1D5f84Vz?1>khF4AAe+#as z^0L>B?3*2ZtM9KD=B@0r=$ZXGGrfNT+}Zm9q|0?aqyB{xohhWYhnei?Q{dq{BSP_M zBj_u*xZlOY{ovpM`aOa4Eb{3rQ{h4Qs00_XPrUj?*V<>;_1tu0Z6HUM`0Y8Cds%zZ zJ=o*85AAZsK0=(T<44I(T+)7s^Fs3N9?@ENA7+!^ziuMwFTi)1YYXR+rgJTOqBre1 zeTX*H-vD-$_RyVf3f48bZ8>we?8Ir*@v7UN^vF{DqM9$BMEVMRIcn3>&9Xs8lCJ-r z+EkkM_>TeRAqhGf=p=>>M-jPM$x9yz&=uR$ght#>#0mGl}WGc{OrK zHq;(tPWL6br-^ZD@tIS7;i?MyaZ5|#;$rYV%7ekXE3cd~J*5X}qZT^`x%H_D9vf@v z9hqE3o5&OQZuR^`$c+8K2RzRHlvm=CHJ;AK=Q~$>ch|b-+8{Ug)nK2tlySZ%^kb0A zmty1XL~iNahlVei9dE&R4V=krWXJNn#5*4tIChqVQnEKcpuVzcr<|EA>w4D(Hg`w- zu%`#+VI$|tC$JXXM4M6i6!GKRqOMuU9QnQF2gtVRP8(an{ZZ&RD|?%V#h%#P)n3#% zT+Ut^_05yT&A{YS-;Q(oCRx0o%ET7X)@j5^YwRCFh9`$3=jdzMIcCRqfEW93hmZdz z`WfMDaP>`nOy5lZj_caLO6bxXJ4Z%3HdmNF9%cO=&YgVf=Oy$%8+Oi@8ll>zDpIVR;-&4*0JkA<_a;(8;Y~Kx_;*AbFo(kCw{beym;)9 zXO7E?zc}0<`%zhT{F$fo;y+q^RQyNuxqx{0Fyj?wyq1sW937VyIa6mxCF8T2@u^{a zmeB8SGCpO~PCc`Ub<1IlIs27u{CYX#^J)Ma5}N8dP9Ip?_*BLz&yJJkk@?sdk@vPT z4ok)>{(`xMrAOzypc>M{jL&kuX?%na#rxM;JK&dbpQ*L`z_#_)*-+t9Gxz$^UGyW5 zbHegg-&AU}pR2dd*I8rRcEa zX1?{L5NA+@I7>9J9sIo)qenbCC3G)6l_cJHq<}o|ojBQ^#g;&Jy!B?sb`K!oFBlGxwqnh%DUQ z#(r^Vb{n*8f&*gW?^bB)^4G$$gGvjRRS+g7Nk4%#l1Eb|^hp_>lar z3XP1FC-Y+0D4n*d&})(d_L(+y7KwdMnpg|ZEpC0nq1^`rPNdWFDX;p<;XjSB>QkQm zUU}n-X-;J83i)Ec@t%Xe*gEgI$;95`S@WQOcDy9}k2GE;#JL4MjM;i%^v3Lt|BGYR ztA{aLeC*+4_6jieG-iKQ`oA$|;(v|VayxeU3Dx(nj+w(}FLsr6yN3T(4f`V3#iD9VWT=F^7b!!AfvGS;+rdkg%$2Ron!`$TmV zDlfD=gSyM`*My*xTKcbZU6n_$^i!TwLaF&S5BCX?=PL5pv%Zi|OOR9EIe9+o!x)@l zW4vwUParGAS+Ifad3;wt{k-2veS7H7SmdVxH{yBD^@{qj)nyN<5B0-1*9zPSM&YLA z6l5>^l8~2ETF{S4-doP*haMAt1aE6P5Kj;HRkWPJy;QrMv6X$OI*{S?)3-gmJ3Zxi z`oKB)g~v2vcvoBGG*Qzgs~q;Q#q)CN5eyn5rF&!aQ}vyq}>MppzZt6IYIn3*YZtkIWyKUwL5cJD*O{dnFMStHn4pQha{{!3pUXEVbmp(@bAIAM z^1id{5NA+uMj*1s5AUdqeA~^#Ol);d<(aRNS7-AneGB=euhVM_H=N73d-q1Z!T5LB z>(E`s4t7#+%U%5L46*ycmnuIVKQR4jsjmd)cFxvefA0vh{%PTo~%;iv^>$w@;jdrL!Q zD$IKgbN6k)I*0M!3><t1~Dbpx%EV4V(m(d4(pUIXlQZEUeZGq~;fp?5n@@9?^6=nT)ps16?PV{1q|xcmUe)t6evN%A z&KRyU0EQ;Qwa_|kr(gD^n$><=M*9TTc7G%WPlu zyveV+Uq$*|U#gV)!r(c{yJ#VtQ6D`1sh^+IAI9mS(Uu0*QlH(+v&MmYFZHB1`cg5$ zzN}v-?l_wvy^MA~p))lZu0-@en~ZPBPV zo|Qodzk06<6~-cG%;z!z`3%cKSa!`?O* zhGE>{(MJ2jX@8zS^U)v;TI-nOx%g6Dm3f@62+kg|IAgzRmEVqUJLS`-_){OFHypc?{nz5P z#s1W0(q=C8$7FXDvHqd;H_7m;Xixe{I=iL%k_y2!g|wEoiz|}!^%6ZdUR==*o(z0F zN$$!1Kh0YUExi9K{xby8KJ+Hl>LbCD%J=gIJd?R`GWTNC@2>r7V8f(XnfX|*Q zZyp^pvL_;e*ekNrrkc~rgH4lLs(mY4rlMnXCd4(!#i!xlADh&E%C-c|DC>uL*Q|_! z|913>>QK2>%9t=`X5>@;^S+hkA<`bE>^x|55&w&+i@Nu^^<9d5Z(EiXYp>3VwO*rm z8LgYJ?}TyG7-(P0{j?FJ?j+^3pUf-!dkafZ;#j_^Kgo4wf1`B?hc(mlFadilCC>Y;zqne7e5aT9?j*HX_%#A$i;@UD8cX4E5ikdx0j{D_Rt zJJHs6KJ_`Yke`s8Y)_ZOhrlnX;kg#pAhemPH|WOPiu88=(T!2B9n#d!I~nbOgHP4Q zFjpt)T{`k)+A*PbxVM$ND$2Hf<})`vk)#i5Gjvo+3m=6ZQyNRmS^i0Z>N`0 zZwcSfjpulElcu`w>jof>GY-E3jK zq61c^K7TYMSm8NOAEqdq{=6^sgm7DTRL5AS>!|k>zM&6~_Ua~0bzj;I)_sE2)q@sR z^x_M^>fv>t>N$hoTIw9@OC22P(mC&{Z!Gm?>O)%}cpYS6W&ftD5BE_vUF}QF0M`A( zds$e+;B|k4=(1NudLrM^hnv0nNmKpD^#m_EP<&+JMK?YOyj!Y!#T*^jtHQ=D-KDeq zjkOb-(Sy>7Q)qi%o6~kkW7G}Zkl>K06@vpjTkO#AaAvz>DLRi=So0NeZlU+Q~aS>9FlUBNY@Q$J_I^`wQX zAQ49IipTd;J{|R?{JmE^=)qK6Ki`nveJ&# z+CGfcVD>QtVlTU6wT!X)SaKE}YU{^t*SyWz^e_5TU-8;dI&Cb@Y@>Nd>}RyGsk(2h zZCzw#3w1a&(YHeIFOqFk8;CX12Ju#Qub^!M+uXLXmj12vr^b10D4jO$&uqgK#~!1N zw%%8bG;`O#*Zet04l*~tJ&azed~I=Y8?+f-6R4!QEjPgaFbVK z&p5L(@?GCS)?^oWdn;s%TbMosrg#0RG7l!#9%Am8FnP2ClWb?T zVc{8;<&2@~`-rxY&20f}T(GA6-45BHWr4Q@iOB+LvA`^dG!PZDV7|-dw}n zHoeoII-j)GW#cO9tFmKDSYudW=%!IZCpGOgGug7qa}lwDeH?a~r! zmp)HggJ+jwf9?mSFtXxV(q(^2_9gV}+MiGB*|k5P)HC+ye$9O-)1-IoPnG!(J!60F zho1E9hkD2U)VIgb9DkLxN*YmQ86_PoP zdaj;W5u%=mp4-l^2vN_ydTuv|5H zS7At>uIFVFti61*o~tKR>_Y#lt{e58oe{oB-lV9?4+p^F> z**S)?eqhI2wPKY+U)K=E4_ht1a;5icL?4Qt~}uMm1^d zbEp`H@1hMmcC=u9fPAlFkB1yzaR{6LKcMTDM$&)QHGKi;vgQBqDgU%pkVl`P$>yWX zX_e6TEND}6fc~;6m+>vfu)fRq-yh=sHewi9GZd^hh=)nnS`G1rsgQR@*4`@YZQ69# z7+d;kooSH0hvs0t;yAe%G2_lO@4PI0Up96liQYAH&gGs>Up!`GSiSof^AlHNdvNw{ zVK3GX!SDL==8>^v9kz6%NpZ&50@>`zC(|7^x@U(+!AH4l@6ZXca^hqSw!7Z(`8`*j zJRxSx=$P#F@}|f_>|Ab~4jt^Z$(*FLUQ5&5=la!B#(cfnG{I4^a>I|jT32I#+U;g9 z>%PeK_26_CxRl>i>xki@X38`Cw2l}$##u9LzQ9b$QyS}tde%B(g!>J(j@ZQe@jS1- zz*$EWooSAqxsIr`ZO9fA3~)|icB~b88kJA%GJ4NBPdGmjVGXg4yHk=ERdrb>DPrvX zhtlgS{pLBXF?(x>=aWvo&zYu^V`uZckl(AsCGWy!as7b>`q%s{mv7JwGV2dDcZsPery*%)F622F_HKgx!)777i)aChM`{3VIo$~YQKi~aVzPAMnvLuOY zQ9T!_tqgfGQSYuinUK-8%Kk!SkxRBL{Rr`0@x2!Q40&~y>Yxq5e+JKrQL%Yk`SwN9 zw2xnD@;N_Ay(#w{|BgFGLlRG@Jy$+{jxt&oRvE8fiZ5~MC{D~%URSObt9`dzp`P7# z3wZwEuy%?Qb5wS%BcFSdr=w49T8`>)>kjbzXSWW?_ayROcs$6uX=k5`6Sq;PHy(-+ z5uBZUD@oj>HeKEESITDUj*s>3>W-~E>yBuZzm9+SXnj@K#7_2}n@w!A`~4dCU-w$r zd`T12ndIHuo}ji}9rmu;a`Q-+%Fa@M-c~yLbT|6630?BK-qEK`jOiLZqfd9sj^x`f z^^QK(x0m(o>eH9>?CR4MJj4YoL(}G6KrdIEamC8)z`7yUGk3ZDryK1w|@%3F!9>uZ< zHpN5e|Dz803KOp>FEGf~6kg6JzejT(9zDDYk1r{|3+Gt!{-Iml%JVbjap6CmJi22j zv;ALZwEv{?(mzXkjQ1$=Vk7(7i(O*+tlv7=+dDghsG8fo0Ua@t4 z&Ii{0RVMKv^Mx6;@

%F^0{bAftNt*w<@AMkya_BFY!?2BDPN*B6k+FQF|3%4AR{r+CZ zF-y=@Y66r%V>>T?3cHc5a!9Z>+y8aK;bq zL8ssgnuy;*^!Eb%@NvT97w|hj!5Vx6HlcHnLDJBc(Sx3Se-wV47bhMpp2G8WiBBi^ zv5Lza9X>m9IMQQh@OJ%FwDvS#6Z$6bD7!v@KEvAkI`+lvw92!E_CV*ZfNcA%dv?BF zuFID%iE(>RylihRL!F?(<43S|cic_i0p@&?_@5Ezv~HB)K5Evl>K+w-tZK=H0P2aL zy|7&l$M+Go{0#O4|HgtT0(|f@UddmkBL7sbvtyIRLk*CB{mVr6e@eOg+VC&>VLioI zS&-j?{08miVmv`>?{z$ler~f#*|*ChTFX)2?cfC(a4p4rjBLy8&b7tl?o9B!Ue5=D z{Sv%Io)1($)!ur?(Uf7?&>$nyu8AY}I zDEgbv`*1CVo}=MhIMx%D|IrUp{zo6Yfb!%;{*B8+2M|Z8VI2*CPn4ohcR>$&5-|9^ zzi!kkAP4V2zXC6uEekzO!+9Qf4>|Nz=xMLA?+rP0H24e0iD`etJ!9}#ev7$$sWtdc zALR$24D&n8`Gp9+)kpq|$jACGyDCIIxa`_HqXQ}`V8_K`mAMHFx*EQ zUO_&#d4f4V*0X=;+Wk9vuQSQY9VB9ar#$bh{KJP!CA z=69l$&XOMfANbBx0qchjbr$PDcfFF4PN6-N+5Q>t)we-#J^}CnJx0HuYKN@lMp>TW zbsn^0oRwJ0w4u3iy3A&z^+qpWW!=EL6R@N7)q?NA_tExU$j>%cq0Jq@Wf$t@Gv^R! zSL!x))}MgWjZ8D)gfC#PUx2iYdLL4^Asp&9yspKSc>SBgOO2s@Nw8lcUSEWLV&95x zwvXjBy?mX1{{+2W z;?Z+#;A_Ttf0Pk##a!ijA$2q4rGCP1wx93lr{XKTmY~!nHd&;eLb>Tf(nS6M8Edfw z{B9i9lD1FYPGLMwF4j=@h!s=FU&`iyPr=7e`5_nl|3oKjf-hT|x=!QzmZfPg@CIE@ zh0kZf6Syb6Wk6qVfqZPhJ2D#M_jYbmV6<5Hf>qqTAz#c}m4~!n<~C)de8$_Ji&(Qg zkQMMV_!|B9JtdazoSinTk>kP#b|!}o>`cP1AAbEqotvyUm&MvD=ljqL3(LSGA|-i{ zVXQA_4BK^jH{&%Od962!F(aI*vlo_Qy>nu{>)f2z+S4;2l({qMk)9r$O^5Hd=SSFtI2pL0lBXk>+woFpTe4pGgMnC)8UM@@W*@eS|iX|xz3z|{@c@&5*m)S zpMp+mA1CHRhU&J#W_Eu6%1}P+X7*D%UMDU%}RYt#D$1IKRRO5hXs$=x3`Sg|IG;M>B9M`TW_+rZWQUO-bO$E z2Vx^jr`o&UN*1@I+ZXKJ3c0f#eL(rl1)f$8Su_*AKk&wGXO;6p*-fIg41MrG65>t4 zL)#%&u%Ee>S}^{u0BGWuD?>cL_XGG<*}jhtq0MO5xwmnKssr#{_SO$=w#6SomS}%j zw07KI6xuyRggWlO30DiQt8lf3+AA@KVH5qvFKi)v%Wtv#R_3PMxNo-~k#Qwy&4Cmd&|2$>p72J24ACXq6PMuv-v5(7d(p3b+{O>nHHW5 z8~wRsDM9ee_xPPWq4k5GJT3gxXCRB=nYzw8z=({^jkCva{zeAn#_>cAX)#`x9$g#P zA$=>x;UMOw(XZ@JC5w#?FGGKlew>gOM3NX@3OdT*_l0m)D%!n6yxXP^BJbr6?-lFzB(nL5n+I6V6We-9jDFk?2|A;?di(6H%J zUgZ5artAGo_&L~*ta!U6{O^FB*xxTQ4dZiMFFzPpmg8PWUMa&6cb{&j9mq2xfxi{` z*arm)-@~#GV1sUp!#5_|bRZvWT!&d^A@2F@mrl&rQ^#zj-tEroA3O!$ z#Pj1oJ9A;L%ufoQLSE3;tD+R|Fh@s%t|C0Q@J7+icN|yR<1!=tgKhZk2jR8n_Y0B_ zor0cEnC&^R@c{l4fE($*BJ{zret?@E{yymDe15WSkHp$8aQ-UNzY91n@UsiYl7r=# z&sNkyxIF(jFK}(pk`y?;2j_)81b83j13uDEfroS5KLD5?9qX^d92?HG6XuxkHvrQK zo*@9M6FkHUIE2YLHF212FXaZpb%8J51Gt=1oJX8faz88Js`)f7d=L6LaX#I`u}qjx ztC{vu{I^e5FzvM3=W2Y1D357xAqFF#vdAbYn=NJ9%klEbBBnhTZ)=^4GV5o7pBeEMXjW4w6&tT}%s(>dll;?u_>JvIl%MR~%_NS_M&>;SzVge*fE zG|MvA;C*6$q##Xxd+ww7KCv=yLZ4h@AHNmfCl{EO&?je@_FR0Q{1Iur^~ouw-*{=C zbTGY_KKU=E_tGbCAYFcgi+F=Z{u6o)+yA0IU+LTCynR`}(l*9t?or|OSNfHES@`^x zel=niXkTRdJGgSr-h}$1{4Z(Q9^SKl%FLXrq-7zJf@?XCaZld& z8p=eb#q;~eP%bvMF@C}JVK36ic0Ir1Woc1f_AuTP=3}z`sp0>|GxN|F_al_ELtYd9 zyzaKTPjq|xGojP?_9ghm_e{RI!;${B&`H?ZA#(*wVaM%yS_CI!P41j%$aBgz44ard z_cxMn37(#XvxldN?sqoh3SRZj7SVcgV^zkH>fp0lw1Dvq{;v4Zqbc$l=OXs=n`A06t6m!^IuXgorzFGvj{}c%K0N z)jICPy94-5wb;Ag-6XmPLY|bk+aTlZfvp+%_l0}W72^Ij@?8n;*8=yR{1LD98&)&^ z;tp%*;vV?FUHw9|cY;RtedOyO`WXBT?KxYMqb((!iuTy2%(1%6va9WiEA8|v%8Pb3v)N+px`Wir{-UA?iA{aOaMKs65ZzyB?o(&(_w!c3A>BvUIu!bgg&>S+#_uR zxi;eoaJs+Ic=W?*9q*%*S#plW89uOhx_^tH8s6>&aR9 zt(~XyS`W6M-mwL(9b0m{PgYu5BYSf%p4eh(?eth$JDwBWkr%|pAaEe8i3TijO;8Zl z9w|FweZMAXwIOB>_M|SzT;KkdFNFO*gDgYs-6t~!h6V_G)3?9n51q^y6zZ2^UyL)w zg1@s3XgV=y#Ny;{HNZD8B6u=maOgSIgYz<{YH6@l49cCd+*UUJCsxo9=7JOBYRB*7 z$XlkoC@TMjHtgJ;_NR}Ga*ppBH>$X0RO$EvJUe%mK79!J%5m*PJ&%nWTznMIE6_*D zz)_6M4ZV{pT3;NWR@^;QbQ8~)l9C4%WQ;5BvIUmj^&MZR>M?()=KBr&?$_~mXAKOU znmj1<`-Ou;slX3`J5$?IE-Vyd?Nd&mAMyOX?qfqQShc`$;*`2Gd2G8a7jvQQedvhC zOF!&Cyy6pEwy@tf<_6#(cBZ68K7voL+1~vpj8OplK>M?wT(;mT#Oj}b?%7ph3wA=j z>Nte`Uxy$sxsrls-UQD&a80QDe$oBmL`!S;eq85TT2JoBnecCm?v?o>-b)Z+^>NMN`pos@yLhG?%{ArB#N;64ufy7}R=@^2 z8ay0waNFV_<+*uddiF!N+DBS+MTQ0oV8^6yiDTUk810Y?+TWxfjo-)1MLefCjdM@% zZOW8j0eni69$FmAg}l}Nmgu&_2chC}t_?fjf4C0iBX7pbKNpzx(|CX88Km{LhFyno zVOu)EGqxiS+rl<=?xmkQ)+Td%#AVv^6kzn$o?Y-UUP*iYT=U8PSJ21ok6id=+A-d= zw{e|MY}4~>C)U?j&<4sE$+$8f*H?3S#x^qjJ^jjWAh+v%#&q&q4R#8ikrDz-##_+e zE7#|pdELLRG1liFgxrzby-cUC^^n!0ymK88kS{-aQ5Q$#o6$ z#|azdrEBufpOC&i%wNO5N}p;f{9#XHPj4w~zjmw#ThLdf@GbKG$Edp$`!RUm%KH)O z{yxAk@;@j08nG|^0>=$M>3H;uanCw0?&!ULP8<@!t_MZ13Tq$xMfSyH(K-O@|L@R0 z12_-ZHzUD=`{Wt+Z8q7z&YUKOAHEnNc8R!EvJldQmFf8aoo>KY!FPxjd8}T>5;fol%C>(8ga1Ziq zLLSD9o`D~e{$AzBe^JuHy=a3mj(-5Y#<(vtjr)zJaZfRg`%>ip4t|^`597-5Cm%Zi zn4EK@$DaJ*uW?RvB9;Pj9PBvi8zk&c=+pbC$I?DI3bvO~#|8#Rf)-Vur^r|m+96LQ z2Vl3ydOg_+nhqTAf*t3b-FEQjexZ9CGfL*7f4lc21@DE-L0RK<)L(}F-jgKP{KJ`% z;lXtD!G|c%$ads%@<2m>SM{?++2Vtjs9R7dcO?iQSYYXtA zjFF7;F&QI0JP>^X*&Z@Rdbk<)%*!$|KV*y#@$H6p&gZpeg1%37<|E(OaOcx`tsQG} zyWg1w`NETX@g&x*&V`UK4uG}~iHl9BmvAUwNH~x$P65t|)a9Yv9T_F>&RPc=|KY;EXAIYCuHRg<^KHKgta_BrTYaJl`O!{(<9zP#5Ru2PlhvJq%vDk2XH-iK9!~k}VgyklqX% zS{vpg=dKNPcZ{)5Ik0ngs2%(c(Qe&^kdMknh}M@L7E>mOQF|Xo9GHyTo17OHxA$&X?jyz5+kJMd_bF35cTkQTFcoLXcmHmX zr4_P!_o=a#)_+BNxW9q(6}re&uF(%5jq?!e^S*Pi9YNmM*NO8TDRa>NV#ph#M)mBs zVf?u^CdwN>0gNN)1ME?Wmp2frMOmY3+f_?(0IIt}|txSl_QGJgcT4Ctp^qji^IKFgdIR^iw0SYG?rO9PTG+o(1)#v2ZulYxZ??NcL2}#12?Rv^Zn>+ z;;iDnRBVwsj*KwZ3(Lzk@IJNvSi%Bwk3cNI0qjE>0J+uQ|H2OmW8GcK#(lP*c%~F< zKj44=b7UK+b*3;F%f4;Ep%}Wx`yaB)P5x{>~ zr0?Y!c1E0#QFb2AaQ2I|z4%7=X*=X2e=m8s50CMf=c}bY6J~vsuOi^lT=N*W{T|*i zPJnWiN=pmR0^VwmwJm%K?^#azlF_fi-aqKWdn4|bYXxw5@1e2<(vLMC_s>}82OqLt z`!a0)Q@OUB$5>xLJNE-t&(MeDcPt+IB>%xwjLD(xz6<2JKAcyg$Fxr^#rcZ|5Cfcv zcqF6U=J+Txy-;qZ43~#-hdh8dz!zk^-o+h9QY>8o}*e130rUF8ioIBs?TQ#>`e{90W@O^sIP@oQUw zX}Jz)R=wBbn&orXRLpWW0)T4REQR^ZyL_HHmC@8hnPAkfg8@EO?wWcbHq>pY^K7fr zJoWx+Pu&fg@qVM;K~5%X4Ry|~&gvRxSq=Im+C3U7XVZb$_!s!Ayl!WCcDAF$k700B*Vfk* z6_+>`Ig0AGdbYT|MJ4|E{)YM*chOC^7teLo`m(b*79|Q&{=C9<#U*nc+4B@mYjunhz|A+|Zabr?ci z{jMs&an-n;NEYQDP=gBtSmssj-0JpLS5&)=@x0`H@tXCTkw?oaBVEjBsGmaI_@@(L zmD2~(&?-omT6L|nlC;FXo1HZk9&fF?T=Ob&)nDr6YMq!5pK z=5W+$S=*|rS)Wh4ZhONNZP`-IUsdg!vCM~gm^CHgwX8)5R-whfi*-dMtB7IotX!Ex z;{*QG1kgJK&)QDS=e}Fxm2+jTL27gn%TdQpVPcL(Wm2-Mc*UB3Fq)KLRIVFE`f%Ev?nx~Aj0956v1>39kSIafS ztJPHd^nt%lpU9iZdS|*DU2e%pXUfX(k6x|F-%yY%nPG$1O>U?;{rFdi8~6|Y;_LPK z%Wt@$+c=3$->N;1|jM zY(#8vH))fRj`3iV{nc1HwRLV?uvkwj1fSN>E{E4$F#p-hkp_No^Feh++-S3A+TgqiqXp5ez`($s3DOxs8tc` zR<+Lu0>j#bUg0XGiwwQY3$?`bH8Id8{&}k_t2jk#+!b=BQmg_eXfOy%3NhX&IbeO0 zauCK@_NTEtWBfp=^&YMvGR^CDd9XZ33u5xPswfvZYCKr}1;jHoADxoCMC?7*H2dj!)*|EfwyBlQ@zZV4Hs4h3~FY`3Id5`|2$XHQb zPJz`Yyv}V7&|bX}70x6X;r7|mDf_B+d+ey2i<`QlP)s%y(27Ngr$2CzSLji`^jN|mHq1=N2qbuvmX7uks{d}Yk-~;gB{CyPSG65$d*^rD*^{O(394L*0#>f*%?M`c}u!`0ZBJ;$*c z>$L-HtJ>96IH#~s2;^VvD5*ymZgGRf0RM7_-&x7@1x$BgEVzv%_?*LbRGF>KijC@MLeWz~+Y(9W_Qa~FV#K}}p7 zm7W0V3i4+!NE9}%u-xpJaG;P@?fEqPvgeqE487!);F)a_R*VY&GW|9|m7P}vm3Y3S zj>4_+YVH3a__GbY`Tr37Yy*CYf6iPpUDo@(nCSI2PM5n#>H4$tq{wzNctT-`v#10` zKW!3VoIf3Iw#nFY6@W?nroXTL;hC26FCAVsSN^@O>ns1216!rw&-lw%`UWO@dAvxZ z%RjTq-CH5ym%BalWf7(4a^2rr&82W#b-84CRcVwNLn~YuzMUUG0TD zql=(A0%{!rYl2_{ah)Qs{G+N-@AkmBqMi-8%_MBd7f?|epyccFA^4omq78nVz-GZ8 z6`xH^HInriQX{ zzNR|Avr#o%!!t}VSoN8SXv03qMEud@3FVmdcmoxfhB|j+y%hK~{eAqi62_NsWR^** zkFtt5oDE8D)mgNzg5020*VN3=4OAP}FQ2hUD{GP>USd9)7QLPt4Z<}f0fNo;`CWu6fIs_X-QI^7SmsmoJz7 zdRcg;%nF`DETO7i;h?X}s>`7qn0nG#!TzL1>BC@4ap{u&>ZAW>Ygxq`R`)#svn3L} z^nV}lvbC&|H7omumwlD+<^bOMTl}YMSxe*H+qZ61@9;W z$ScHev6i*+GQ+W0!s9}4h4AvUtc{m}mv^Ob^0lnxm*I2L$8<-QW#zByyWa|A zJEiUW#B9q?cx{W z-^GjK1@R;C48km)6yFvH#YqH8?G^Wl-QshiQTRlis21hIA#N8N#9FaREEl76a(QcR zzA>un%x)}PuFY=D%i}-GwdxA35|&n3!l(ycF}k8qCP6WqJarZubxA(eVN~5F&zeke zW%AU?Mz^7ak>60wbth<2%@ zvZ<77*yx$oq)BVRjnJ?V>OfDeUu%M=LM0o{H((4K0sO6olhcQs?id~1RI;X+?S^Vb z{9-{G6|e=npk2~&XJBK>mtb^vDSHzAh5+PaT!rDHlpS$J_Db12WmGZjm8utGwkyMi z)q)o<;1{^e^?><(e>@}$F&>vBQ#x+r{s!YI1wZED-#+|4t)9g9_oGZ8p_~y801Jl- za4|-y3Wfyfl0^ah8F5hv9YOejCW<|9UDD)+U;$dzjI2JlUxCamFNdMtrw2S4uSK-J zav0+3=%`2V7aiczFI)p}sLHyb4y8RcTVZS{Z>n?FR=W@#C994W)ba8))WZ`;hfoYQ z{Akj3EJR@=2nc~x2AXio_&pxYSBsdHC{loQW$^=kuiv38ghuE9!vdCj-R>+9YVAx! zj=9TaY!cHEdxSWFtm|X1rqj`1JJX9u1{fHbQw3HO(F(Z^9tU)a-eacExS}A>Z4g_OlJF2T4bITUZo>#GGcJ^YvEvDm&k%_A?j_#VmwH0eu zRaIB(-6IUcq_4Wx<-#Fl>e?jMt-pDb-W089)*1~i9?)|_q!$@Z_T0HMqz6)~^^_al zH^h~(ygp7K;u??BKX;CVgvf|;usvl~zCyY&HFKt`fw-IKL%ZJP_0;o8}wRff_6;NrfOS?Xp`MUdw29{rL=nEajqo7_y-~TS}YE~7-}Wb87=W~OqmK?Rf0mvF;&NCErZD9 zpn=u9RO}~biF928-%p>1;1o3td}d~q3gsc*E8KpCY}WOznRWR{ zQIAEKaB=U~qTdm+R_#WVPyO^u@*3l$;(`EG1q7*OYdT@8H!@l8aM^F}T33D3oPt~! znO#{4y(a@1X2J;Xn>u&8iqD%#zrS(s^SkSf`}ka5&o&>-_hc-xf|VYhf4xUFja0+M z)EIVAymoEOxUJIxTCf^KRmdQrEEB$}6(vBn%Im4ah-SrrUHN!WfrL zRo3;=E9Z#f$7aO6hogaSW6e{&r_W)>%yKzBvL;B{nJ{I#7EjIEw7%z!icR30k%c!h zo(nx`dPtlD=5AIU+*e0O+p!LTFy3q5`o0_D>B#VK!UyP>hWy4Jf2O&Q_u64;E7h(gP|B5g)xzkU=FTtOy;!uB|quz(~dcK>pBkj8@ z+P8l{XViU8{QpGG{YTGb-En`1p8hNS`dH5Bq>V#neDA58DR(f(?{hvtuA}Ep>G0Zh zc)!r&Tz{IgR0h1htLJ|O$5tx5ZMX)|0L>6k^nNhnWR0t^SZzuDlKYPuJ!b5<&y3Gt zub^vkjH_M@a-{C{W1u%edbVk6ii>a6hg-{n=BW6|EJXlOJ{K)lQQZjPN|r9pU%5%; zrhICKs|stIv!^ebH@)~yR4)0UE=NK-hA``xuH=C%>FS;`Re8FN^)(955Lwjpq~s!- zA`yr>y<;5d)A>B(XAQ5nA^l#;uT=}o({y?QgHSmfQ=;kgc>1!U$*~o{;JlJI#Fivu zNK9Ak0F!@r>et)#s}PC~TVF7?f^5oNS6o!Q!ckn9yN*Q)a*J0Ku5%O>V|z+TVgC9e zsdWmmDR+JTO1#fstujXAtsE?caobo_P*|K_=-5!4yD_(Db#C5jsTx91ltH!d-@6*3 zQId>1#KI1Tf-aX+1~-Rw3b`#o3Qr2Yd{(lPOpx*`WKQfkkwU5wG>4d`rb+~=$@dOM z2dMH4UqIlI5w0Ly)n07D5JD>G$fBDWq#hRyfnx-&lutCF$MfmoTSjgr7duww78f{H z72dXX4f?G_R>*iZ-jsRDCF_xKcrvCiey0TAJGNuGFpg5s?|>7(M!H{xXmr*!$u>g7 zCOn8}jP`)A2(LHd|2WaWE3wQ%{bz6mO&=Vb8S>$hxD5uq!>|BlvdU9~jYhgiug%t$ zEY*?v~J~8Eu|DWAUBSgqT^c@R?awD?`R-`m5<~61?)p=l4|eS$1C$ z!vOgN`ZD;qLRP*eTuI7c>`~;x~{)fUg4cp z*EQ?awfGi!m77s;hwwVNM?-cuf|!l<#qXq-5b@vcZ44JdJT>HE5b+HC1#6#C0eM~K z!n{W;WHq+g%<#JX4cw5>>v4yRYT5f{(Z-`Hc8d*)}K{HBR&!bYxJ7*9eysjCU}n zD!bQ=s3ET$p$<-O>>2Zcp{vmZXDw$4qF-fg=vSzC2+*jn(mRxK)-zx?LYXSJuNpH~ z{mD4&US3G{pwA)ZtgmVCMJvNIrE4dyRZXY@mP6ED?Lp;6#KLyB*TZs{AG`=?dg=<& zX9^pCWr)*cq!lhp&bHcr3qPR-tgzH`U`x^af1mG)b!8qyZl2~vrjTN|V)zg(!E5vsF zS+*1A*qWxeX2$r35{aRq$NJ?T}TF&g|wA1-sbSV-NK<=5#VRtzf) z3{bM0&2TTJA00k;0sS0t7@69U09Z9$=OG6A;D+v+(g&LHBum0FuE)VbEYT=b)_H2#@6P#rR=7W zw&i9acq1UU0zb?tOjj8SDqqs*&q%)nnvfZ|5kQ0Cx+pLI)>|Fx3Re`~>L^*CyS~t| zy6EPj_4@XzX#W=@hMlYc_`?Q?H4i&eAR}QH96~9%^$>fSy~u4ER~h2U?oF(pKu!5{ zy6G)fY~PsNRMHnPz%%9#)^2Jc8suBr3ZnQM@9Bxa#O7ux?C_1zvGG2E7^CG)_?9DP z(!eBvw6*1s&eyIfDY{it0k_!Lr>XpE$2EOOjjH zbTc=#<8Xk>*0H*5cA@d(_L#pOPB!rVYvE)|oc=a&{#tw#F6^Vf4j%)~-vXb%MgI_n z`d!+tISx*rt0Eu?ByrrY8jjvMe-#{4=ls=h`oL$tBTtF;SKmc(^Ykx)(;NLjyiH89<-N1 za|a5_Fo<9rSyab=UEwWx8bGHe3<(UC5(FX;1L;) z0m)3B>QLvd^x$NPXq}QWbi7~$sgD`0@y38lnEW&Pb^W@++?!#`)ywJquIbyq^vz_* zufOMU2%fq+wXp|M1|(pFhZw;WF}MY6E=wEzYHBKEps3l;z=PSd`LM7E2<1R>mbfqB9L!K-&mm9C6u^D<)2Hszp zA0feakB|sj{bd}Da+gOP#b*D9{%X2(80bA2^A^PW+a1$oml%$A^&tK1>Q=hhd&wf5 z>@lEpJw#olg868WiG=E`DYc+3&Xa@=Kuo_c^#{+oBC}M zcCkp{%s(+0b%>e1Ds(u#0PG)iZK^e0v3tI*yiv@o+d30|MGrh82t=FtcaH}%>i@^o ztWFU4$JEWmg6^<6|Jdqh{{yNocb7F(IwTtxh^nkX5K4T4Gd=}0%3N?I!W8%y(DvV- zs{h|);^7&8pO8|rkbmH0ayUG$N=gAZOKsBMo6;u1{DdXX;j5i98>b&^byO^v=kUS1 z!UJR+TjxmrZgkE+V5&RdAaK@-`00H0GhQunz5F`|Y1UzbVsD13+e5h6gehImG0e*J z0kQo0-6Ke!fc&pgsm0&yWObckV}4rT4x?jdx!6DAiuF{$I^T7m!&`Qo_{ux zw3FANgLef2St6xpS0F1z-l~jzH#-I*?ygP8Gf67pEAdVNNs3U~7lLK&@=o3Jne_#B z2eJ~YO9`O*biNq|?A6}`Ohb?Gk7Y-xWFdnnaBuXJruS3QtQ1NeVhnys6H}sgfus?p z`{Aa0f_<7aUX7{YhZa_A%CLd6*b(e$Ui9lQ z{W?m&YWg)xzs}aLi{usH^{XlmSy6vhgBC^c_5xP9sj(_Cg2b7WIwNzPqF7G5}sw4;OWn{9b?$voSWO$G0JZEooy-( zaJ71FzpYI#_Wv&bKk0$NJ4Fv^q<-ytgT!x!iWOj)nw*#cn|ODq*obH`@&(!4Q$xju zW@FZ3-pOaHo?txN2o8V7bCS+$jOTtjGc}%*In7P^`|F&>c%Py(S>t(toDVVh19c{E zydR`9apQTgzBm}q*C<93#czmi^EBQM9b(1@?blZtq@umM8=>*33_^4b6_d7Fdbn)# zh_Ce*FAf!>n{@QAL#7Es@L?P@_YT|>Yvg~dF)4{mD98G>p`wHN_3p{U`$tpJaAeeVH1co1;sb8lTCH1Cq~=_|2*w<_A1k-*OaSFZ>Mf8$}OQ(*fzg z8qdSM10;l=FW(RNz`rqhfLQxUPcqAQ4NaP~-8w+riT0>xF}YDBFaBERBKeH+lNzno z06-b_jc&9__#z751|E&~#{nPh9o?8D-&@mA=p~jHw#X+vruu9)bA5QP%CmmtAKlnb zmbbAy;0^Oy<$G%+sKZz76MPT+hCz8IK_yMPN9Et1WW{!5(G&S|fBAkp-fqToSF>RI zcQpwN2>ynTA1odnB2t-l7DCq^UL?Z zZ<2pt4_`;08wU)K{lWGCziECeM&`YoA*6@FH0K{U znC~PJcVvhWK7G240{vcJET(K7f`kBa;1A`qyw)KS7N1kbi$RTI=v?1sn>hNujr}=o z`(UfE281MfS-(}*FQKN57ZV#(WcwtQf*w&mWy1#aVcvT-gI|;qHtPhxnB=#{^_Lan zxsM&pStR?*7VEDUhl&F9r(F&}o8&i>yjIC<26H~KKfN~je2qT8a*<#Cq5o0e=*Iq% zK9V{99Yco=^9@yfIczqJGDF05jVS{--z0rwyoYa3P7$|ae1-+&cnsg(KZU_z1JZyX z-rv_Gl8I{4=wXA!so{z~IG|Db7$EMrf3>2IGSbK39P2*|qAI|SmyoS{M7tQb9$1`w^98d7Sn-loKh{l0zioK@|{6q4a6pZJ44g=r9 zCVT)y@|%FpzemL8Bk~V!lvBxGUkd)l^4@`x|H$%KkNP(bLTlgSlA0ti-dW(^a;~z8 zgF#QeR3Qb5QFxw2{tZ5Y`8t9;LGstMVHinD9|)ElCPp+4L(c`8CB8q)!2C}e0S!lt z;QKO-_#kUwSqz^MCVVo0PihPw;5*HqF6$#Z6az^gBZf#=gva&Ao1T`ATh^iYLD~pD z%Rh9m-qxfKc_HVq#z+b5T95I6R$-k9D*uR5iUoipv3hjxNUn%*emHFj-ll?c$O89Dh zohg9tK$N%3^$P7v@eWFjI=QDJJ#N6&==QNRG%a|jP{$#10LveFvOq#&EEUK#Z{eo3@}i-o84u%dAIB~+hyDAmaS=< zu58OzVn~9Pw%J{}Ww&&j-I74Kzwh_C_s-lINTS`opWplLyYuC~SJYi9>yZ_;6#>ThWl4%cd~qP(H>djOSWH9%#>^oq2hQd+6V_ zkT2Ow%3}ovcv~KMl!piMamZu2*c)VleymbF4Y|vuyoq0nKe(bH%e-fQf`8~~@GK|$ z#>9V^{cERHzl_hz_>T6^B0lC5;$L_gvU4Q=F-#m#U&woTqJ3dMvvw}cNwx>?J)Xo` ziR53Norvz>9^<2@(f0t1{rhbo5 zzw<=D`x4KgFHbF1#8$F@(?8tl&~MlS;OCnC1NwvhaZN-4JJT;JKLS1K->aJNFC@v& zt2wR&KlG1ZHR);8H`KTARfqnV_9ib;pZ6=mzuEpK|L8At0L@<|_U*&onLqQn?O!QE ze--rCCG3j6L7%FgRkVp;vBh44JZ=#B`1U1!uV5HmrsOB=EvWuCxVMD!TLVg0^dXIc z&$=H^G=`aAw}zday1f{Fft3g?O8KSZpM$4qMM!>+HESNSu$hO$H2?Uc`tsL<2kA7K zK4Rfd@W$~=&wI7`tj>`|E(ffFwptJDYRJ&*$o$9V^#XidW~qvTt<&-&K4q1T|M%b@ z=?n0iEc`JOJ@MbJzYYHc_*T|L9$r*igL<)*%JNyZjpwn_zXX9$CX}!9*J9xpIT9D+ z{}N07>G%T{euG2ci{ak{`phCh14mg+wvpgygdh1wz6+apg~U z+Vy9d#Ix&ZWlMk=OF%Ys;-&MNKw9L&#tfk;k9-VEuECeDLO*5^He_7vfG&QTgA!Y6i~~>buyw z)_$a4hN(`K)ftN|d%py#z1X_hI!RBrzBu0{=@zop2MK7GR(KLKBc;i5a_C7ES^0R) z-+yI&%xCexV13L7#_%J3pIn*Oc6p1gk9}s5^)aTMVSUV&pVtxr*T={b=TKZ9v+X+9 zz7p41`$}9Rk8KZ`CvlBDiR;s>kI|;rs4KBPwlcBa^={Y0S|KJM3i^L(J&bY<pEn~iraJDrdWoACM)j8xZsOHJI<0} zZ-i%bu6VPe$vpSPpy)s1cw86llN;b8&Q(~SiESKBYi;~XWgh+FYuFAdakk6r5q4IZ z*2}PfdG+P>nHkKVxZjx}yGLa5&F4FpxNLjRI34aYIWLhkxmR3?d5ZO%>`0mw$M7+M z>r#kgXgeuA{OJE9j-WMUD;_5Ce!sQuB3Xtcf8ow05_fVjE`aCh>nyArlyjLlg z*5|PO9P(a*=~2^qp-K7FD@!Qv#Qn}}g(W)VEeplMg~&5oWGNnt+`H1Ao9mkL+>*Cf zh+Fc8eCsG6k?$&5*P0N0Gv%8u&s*x3nDS(v(PhdN&p~|X5B55hxo+WCoRM+$xE6g){4~M*F~Zc;cfx#=Tg!tim;FOYkbcZ*4%{k53wW7(e- z4F&?4#*3~4SZC$F5|o!%cR_gx`ak*)#){aqP%6}91o%p!BC=0?4zz2OS z3>#QCX_j?do1dMf|1R}qoW4f#H;H|-`7wrGPR)Nsl7GdKKX<1h3xP5|fgjv2W&6~< z9}zk5Q>Y=VjeFbvU*3X!3`)}@OcVWT&M}7AKBB*{M==IutmlxYCzg}rLyEK~+HX19 z7te=`LFzm8M^kFVID!9v;=YEZvT?=uiQWFWo|j19(ub_4^2~K7m{Z23FWtF}{5HvW z1pYCef`KMO^!cZZvopDi8F8MBm0LuckElhwgCK0{or%n+WrXjc_i)mB#N{3 zVMPPm8v-4Iyr`eh?>+?P1evlKe@1yc_z6_Cw=xRIn+RdHVMyjc3QT2 z1pN#5nU;RzsjSn0A6dt!yBqxp&o9_%nvWdXFWlSxP5S?SwqLHSqsl%Y(t|w|almBK ze$c-0K6eK4;=R2OiSl#k-x8~RSL}4kk_7V}^eL_;SJ>iL+8gV%T!*vxsXASL>v^%`xz^xfEaF9b z{9$=c{x01q`UDI}N%*s*XX$65_&bmX?Fs6Ob(-wrU$X)(vfaU(@tV6eKGvItc)K|LrA+-PPgtdVyRVnJR!>}INyRl0!*jLM^F>_ zO_(6@KRxf&=99Wa2J50)H!se%?qaa{)d2+iQS8>WW_5!7v8Vt5ZGe;-(=xi z*=_VhL3X^72S4YZhsuaA;cUEkm?m9iqf6gX;q9_hO3>^S8{LoQX+XBj%sDK26M@ z#nh;|i23IxV*citm*klkDRDY^=7lkSuf-qbEx-R}=Uu{fwE%4yT1o!{{u@c)f8zH4 zwYa_Z9E<^t5d93!+c0mC-xc`3Xx!d>?15$SP+-{zinQ0 zw*7TxYy9^A>3`CvP5=3kcO z{2>efZ1bkqfxplzQk0m*sK>!SlWh6f=~1LnCYHFY+*tp%@VTGE{w>D;>E=yM_T z2LakIyU8YI!Nj~NZT?|r>$fg!X!B3Ds1G)uc77XjW0o1WStZDTLqY`ikFoLto%5^7rWUvUR9Jnz+-?DfSw5U>fC_m?YIZrj$SIbrMpoCX{Pth?=mAsbq5M?J8yrD5#}qZP2`&J#uq^{!ff!WhCKf}xrd zMn4ug#%fO(bx5B8YzCYL90siYFz7HJU?HIQBPWb7py#m@MkCj0+!n*fyyz%O7S-~qrAK;?xK#x_6?U>#r>Fap>BI0!fhI1V@o$btLcQX7qA3y46p%k4zTJa$P4oGzH-9Ig}fR7y@26n)CVy3 z3A8)p7ycyL9kApxkO!dW3(((7pueq<8(>iz^a!vR@HpU14DGZEun*+}PJbEo2Aupo z@ax6>@8daO?QZBXpzjaRj(|;n2>O5}e|o}Lb1Cru0_6gZ45HqEC4U3`M>`I_cEYFv zjO~Yh0geG40L=dm>Tx;h4HyFK|LzH+9&q9S@Bxed4sr)DU zKLmeQfX!fX_g}$3;K;v0{{c&;!9U@@1CImHuOWZHzTZHefP;Yf*MP4X z-~mZ2e<<;e;)l3(5sv@#sNL9lSbic@RxDYs0FOaI%&iKv$9Vb#{gRa zbD{Ue=bSXA0Q*;-G^(Kg1LvPKVu0ZbPa30uo`RFc>Knk{s*^@P;Pj;@jcLG{!js0j zV(@#*Nn;4G|G-IO5U^o8@&ooib<)_1e$`ih(%1!f;A1C^VZf~C zP8tO_qn;l}`GAv+CyiFXtS0aU=zAIEuYr6&0lI)qEhmjVfU!L%jTu1C_fHzzZ^3iG zLBMLjs$0ST-<>p?0ViHZxwnHZ;DG?@F?-S&LB3kRPpR*2ujL&o9Jtz)8Rs zz`l!SjeUUC1+&I9U<;s5zAgrR!0Jn8jTm6xs##+cu`&S6=44@vqmdm@olrl zF~F+ZXN|%;p$BX69I)ihSt9~i#V_*{^{CTV}}p=RZy8(Rz;0v$@us#I%XR}5>;K-kYA3)`6 z;I|a|3s?kL0vHA?`a1XqjQ!=TF$_2WSX+kj|7zA40Id5a>R*m_`rBD!2+;TaS;LER z!hmZ4s{q4*)qvxGV}A#^p}gAH!7re9c-EK#-9A7s=(YTC)|det7@akCf!^3b@D)Zq z01E&o0gC~r0c!!3H_g8gqbE zKbtl3E6_eapEVi)2Y&^8z?KuU20oIl#0<~}tX1ZW-GJ3Ob4GC`>brE#hy&K<%^3rL z4S@RrrvdXff&XQ5#&*E5bLWiXcj3Me_;;iIubeYl?m_>&Vb18k7yaqRIb-#GklRgw z_k;iSphxIKIn|&aKt8~M-XS4$L{o$N32AI`9 zXB2Ef{Q!M{%Ad>`&495#pEHJ;zIV>ZtwMdiK4K`6Qxu|#bTXV)7pz`B6qv`?BpO`b60K-24-+0cGuAu=x>Iw;1mMiC=8T$$p})uHj1j;CfckqOm*1c~z<$8v zfYr0Oe+2x`fexUeoHAC|K+gcT1A4DMW$XgIl50*G#oN$du03Tm0ybQC%Gd`udHpFP z7xbrZIA!<%hi*J&^n>o$O{a_l+fl!pPZ|27kjt7=#u~utTTU7L&dv0#r;Nf6g1`5i zGDbdv{3Xcu81(b@Q^sCE&mE_X%8#P{fV&WDWl|R^v7?UG6tSQ{a!m|%zO^zyam4B2YCR70F}2-8P$M3z#V{1fK7lyfDu0b zG580}2iyl(4LAZ=2Y3u{0B{Cy8Zh_$Xx9nw1sDcg1K0u>2J8de1~>s&2k8CDDWe&% z1~3NL0=Nfo0B{I!3~&@s`ROTR5-0=2cM9CAK(tareB^ivOa`%`j1n_ZouOI zgq#8EPMk7|YC(4v3%^RbDSy#>*G3ZVB+IeGZ z9q0l!0L}pJ0c=@4Zw&MP`gx<^N$7Vm$^{&|dEVF$ICKl>?L@tAoi}y?hTk)93<9>6 z%p1o6XKtG});$IOZ=W}+0EgD0et<>m!8hQfZ{8?|zV?N{FZ6VveBKxX3~!h>JkQ`c zU_1UT^Nd1D`7&1bY8S?sllm}S6 z8}0B3$n`7GPeA1xs0U!xK9v7S$m6f)jb^}+Z=pQ^2fjUT6n+Zz`#$Oi=p8}1fF*CB zT)?42;Hw3AZ$aLGRX+vafJ2j@%k-b4yicQl{Q~j@EdDj>4>;Y`O%`jGe0p+eoIe-TMhX6f(!#EDu0$A0G@`Hx4?TaWc zgmM7;0Sk~GD>aN=fPH0#u@7*p+%PDt$=+G8b;QukQ-nDVBJH85dy^9Ym8Pv z-}}K|8|VVI0xBOcj6uLUz)3*wcEeZ`fnGmq7<&Od9|1k2=K~h-Ibbnh5nu?g1h5(~ z2Dk(HhaSW8c9gTjFt!7R0UH4M^O!(UpSxSp8!k~V%Eei8q~+tU{*n`k_unyXHU3(W z<^$xi+fn6wgqFulqI^5{&kex!#kri>un=7F#k zf5S*y2go1OcH?gbX+A*ym^O&N9hWC@y|^F7UoFzs0NT8S+O%>fFVlE51zLq>9#4Y3et{1a8Vh_WZ|UjD5@EJH&){Y&V`{=6o&$J4tk z(4O0ov#~8NvNW2lRf6!LgKt`V6$57&eAOZ*Hic{8NF4(0869q^NLf^8MUp5A>#d-S zLe$&YeyB?Yxn_j}mhecQGWQ|xD9X{V6~4?eD5oF`(n^7s;E6IOFUJZoUk22#5}bsN z*kzE97Vxq13e*|bcH4oE`|Uh7AI$4xJ&|`8uJuDNDM}!(xF@669ca@du0Xr?kkwo@ zcs>ET!^kV=b^UoYJ-NL(fwt_(l3;sQM`ko5<_>h~U9Ld47FX+0*wOLBM-GkIRk(LS zN;ox(1dO>KapKAo#w5zpH-eu;dquNjOM;zQU75k|jJSJaWNBMopd+U}SNquL8~!&B zZnTL((r98fEL)gZL?RBGz4VRIgKzqY>?g7kLcKyLYicRt7)wy5(Zn*R_0pcry_+RIqc|k|f(XY?9`dhO9Zm^nN`dT6K)ZCNo zzaF5KAZ;tsc+DU6qY`ODMTjLa!J>u!7g4FIrk-v}Tv<3xz$pNo1`{Wx9k(E})$bs7 zxl+8yx7XrltBE7}RO+xf%)@wd1axas^W0_Ei~PqdNK%>lCAg3Ld;xe;|bcS;MJ>OM( zzoQ1*zpZxst-7&ozZ!W>b%(#9x;Oll>aG}6-5dW>byt2}b#M9$)xCMI>fZ7-b!+Tf zYIH~q#J{O_?^DBFf30@@jp|yHkv(?Ef8?-#{Ag*$=8P>Fl^L5dDl#@^gflk0^|r0s zt~=C2V~39%9j~y6nAjGrrw<Q?hN$z z?Wy`Vh_r2KX~RgXN=utSS_o-iL4Krn9BCzKX?&aE>a?^1q#jl_6k6rPJehcc={evS*L z^+6s0g2M+X0geYeHK0!PU-a)alCQd+yxygu_UsNgVY!i1lQQ-oOEdBxK>mE@$B+HG z5Oo+v8rOaG?_rW^`*ZZQ#HkBM^(QHiBrTRb0$TdLSa%^IzvUOTYaMEk&e8i)$}VD_ zT-e82tY0|uGi#__dziT`|FRy>2f@<;ZojLEfL;ab5fM z{@AtA)&8!lJFoG_uj(%H=LDG=WNMhH)lAhM

nueSr7nN5{8y7sao-JA3>n2H^3d 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 }u5)2ENv@!o6fc<1${ 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 diff --git a/orin/build/libvision_native.so b/orin/build/libvision_native.so new file mode 100755 index 0000000000000000000000000000000000000000..db264045cc79c7dff747fd6c56f72b531b354192 GIT binary patch literal 256776 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�Mf$YFoQzEqBSmELh6u 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

TlRW$zm7e62x;YmoTEFadRcCgH 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 literal 0 HcmV?d00001 diff --git a/orin/lib/libusb-1.0.so.0 b/orin/lib/libusb-1.0.so.0 new file mode 120000 index 0000000..4970d7f --- /dev/null +++ b/orin/lib/libusb-1.0.so.0 @@ -0,0 +1 @@ +libusb-1.0.so \ No newline at end of file diff --git a/orin/lib/libusbcanfd.so b/orin/lib/libusbcanfd.so new file mode 100644 index 0000000000000000000000000000000000000000..72b9370fdcfe26d43b83dbd7a7e27cb112a36849 GIT binary patch literal 205816 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�zzV3SSb^RXe~ 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 argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--video", type=Path, required=True) + parser.add_argument("--boxes", type=Path, required=True) + parser.add_argument("--model-m", type=Path, required=True) + parser.add_argument("--model-l", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument("--max-people", type=int, default=2) + return parser.parse_args() + + +def load_boxes(path: Path, max_people: int) -> dict[int, list[list[float]]]: + frames: dict[int, list[list[float]]] = {} + with path.open("r", encoding="utf-8") as handle: + for line in handle: + item = json.loads(line) + boxes = [entry["xyxy"] for entry in item["boxes"]] + frames[int(item["frame_index"])] = sorted(boxes, key=lambda b: b[0])[:max_people] + return frames + + +def point(pt: np.ndarray) -> tuple[int, int]: + return int(round(float(pt[0]))), int(round(float(pt[1]))) + + +def draw_pose( + image: np.ndarray, + boxes: list[list[float]], + keypoints: np.ndarray, + title: str, +) -> np.ndarray: + canvas = image.copy() + for person_idx, (bbox, kpts) in enumerate(zip(boxes, keypoints), start=1): + x1, y1, x2, y2 = (int(round(value)) for value in bbox) + cv2.rectangle(canvas, (x1, y1), (x2, y2), (0, 220, 255), 2) + cv2.putText( + canvas, + f"P{person_idx}", + (x1 + 4, max(22, y1 + 24)), + cv2.FONT_HERSHEY_SIMPLEX, + 0.75, + (0, 220, 255), + 2, + cv2.LINE_AA, + ) + + for edge_idx, (a, b) in enumerate(BODY_EDGES): + color = (40, 40, 255) if edge_idx < 2 else (30, 230, 30) + cv2.line(canvas, point(kpts[a]), point(kpts[b]), color, 3, cv2.LINE_AA) + for idx in (5, 6, 7, 8, 9, 10): + color = (40, 40, 255) if idx in (5, 7, 9) else (30, 230, 30) + cv2.circle(canvas, point(kpts[idx]), 5, color, -1, cv2.LINE_AA) + + for side, (start, end) in HAND_SLICES.items(): + hand = kpts[start:end] + color = (255, 80, 220) if side == "left" else (255, 190, 40) + for a, b in HAND_EDGES_LOCAL: + cv2.line(canvas, point(hand[a]), point(hand[b]), color, 2, cv2.LINE_AA) + for hand_point in hand: + cv2.circle(canvas, point(hand_point), 2, color, -1, cv2.LINE_AA) + + cv2.rectangle(canvas, (0, 0), (610, 45), (0, 0, 0), -1) + cv2.putText( + canvas, + title, + (10, 31), + cv2.FONT_HERSHEY_SIMPLEX, + 0.8, + (255, 255, 255), + 2, + cv2.LINE_AA, + ) + return canvas + + +def normalized_keypoints(kpts: np.ndarray, bbox: list[float]) -> np.ndarray: + x1, y1, x2, y2 = bbox + width = max(x2 - x1, 1.0) + height = max(y2 - y1, 1.0) + result = kpts.copy().astype(np.float64) + result[:, 0] = (result[:, 0] - x1) / width + result[:, 1] = (result[:, 1] - y1) / height + return result + + +def hand_span(kpts: np.ndarray, bbox: list[float], side: str) -> float: + start, end = HAND_SLICES[side] + hand = kpts[start:end] + span = math.hypot( + float(np.ptp(hand[:, 0])), + float(np.ptp(hand[:, 1])), + ) + x1, y1, x2, y2 = bbox + return span / max(math.hypot(x2 - x1, y2 - y1), 1.0) + + +def summarize(values: list[float]) -> dict[str, float | int | None]: + if not values: + return {"count": 0, "median": None, "p95": None, "max": None} + array = np.asarray(values, dtype=np.float64) + return { + "count": int(array.size), + "median": round(float(np.median(array)), 5), + "p95": round(float(np.percentile(array, 95)), 5), + "max": round(float(np.max(array)), 5), + } + + +def temporal_metrics(records: list[dict]) -> dict: + by_model_person: dict[tuple[str, int], list[dict]] = defaultdict(list) + for record in records: + for model_name in ("M", "L"): + for person_idx in range(len(record[model_name]["keypoints"])): + by_model_person[(model_name, person_idx)].append( + { + "frame": record["frame_index"], + "bbox": record["boxes"][person_idx], + "kpts": np.asarray( + record[model_name]["keypoints"][person_idx], dtype=np.float64 + ), + } + ) + + result: dict[str, dict] = {"M": {}, "L": {}} + for (model_name, person_idx), sequence in by_model_person.items(): + upper_steps: list[float] = [] + wrist_steps = {"left": [], "right": []} + hand_steps = {"left": [], "right": []} + hand_spans = {"left": [], "right": []} + bone_lengths = {"left_upper": [], "left_forearm": [], + "right_upper": [], "right_forearm": []} + + previous: np.ndarray | None = None + for entry in sequence: + normalized = normalized_keypoints(entry["kpts"], entry["bbox"]) + if previous is not None: + steps = np.linalg.norm(normalized - previous, axis=1) + upper_steps.extend(float(steps[idx]) for idx in (5, 6, 7, 8, 9, 10)) + for side, idx in BODY_WRISTS.items(): + wrist_steps[side].append(float(steps[idx])) + for side, (start, end) in HAND_SLICES.items(): + hand_steps[side].extend(float(value) for value in steps[start:end]) + previous = normalized + + hand_spans["left"].append(hand_span(entry["kpts"], entry["bbox"], "left")) + hand_spans["right"].append(hand_span(entry["kpts"], entry["bbox"], "right")) + bone_lengths["left_upper"].append(float(np.linalg.norm(normalized[5] - normalized[7]))) + bone_lengths["left_forearm"].append(float(np.linalg.norm(normalized[7] - normalized[9]))) + bone_lengths["right_upper"].append(float(np.linalg.norm(normalized[6] - normalized[8]))) + bone_lengths["right_forearm"].append(float(np.linalg.norm(normalized[8] - normalized[10]))) + + span_summary = {} + for side, values in hand_spans.items(): + median = float(np.median(values)) + gross_limit = max(0.2, median * 2.5) + span_summary[side] = { + **summarize(values), + "gross_limit": round(gross_limit, 5), + "gross_outlier_frames": int(sum(value > gross_limit for value in values)), + } + + bone_summary = {} + for name, values in bone_lengths.items(): + array = np.asarray(values, dtype=np.float64) + mean = float(np.mean(array)) + bone_summary[name] = { + **summarize(values), + "coefficient_of_variation": round(float(np.std(array) / max(mean, 1e-9)), 5), + } + + result[model_name][f"P{person_idx + 1}"] = { + "upper_body_frame_step": summarize(upper_steps), + "wrist_frame_step": {side: summarize(values) for side, values in wrist_steps.items()}, + "hand_landmark_frame_step": { + side: summarize(values) for side, values in hand_steps.items() + }, + "hand_span_relative_to_person": span_summary, + "bone_length_relative_to_box": bone_summary, + } + return result + + +def model_disagreement(records: list[dict]) -> tuple[dict, list[int]]: + values: dict[str, list[float]] = defaultdict(list) + per_frame: list[tuple[float, int]] = [] + for record in records: + frame_max = 0.0 + for person_idx, bbox in enumerate(record["boxes"]): + m = normalized_keypoints( + np.asarray(record["M"]["keypoints"][person_idx]), bbox + ) + l = normalized_keypoints( + np.asarray(record["L"]["keypoints"][person_idx]), bbox + ) + distance = np.linalg.norm(m - l, axis=1) + values[f"P{person_idx + 1}_upper"].extend( + float(distance[idx]) for idx in (5, 6, 7, 8, 9, 10) + ) + for side, idx in BODY_WRISTS.items(): + values[f"P{person_idx + 1}_{side}_wrist"].append(float(distance[idx])) + frame_max = max(frame_max, float(np.max(distance[[5, 6, 7, 8, 9, 10]]))) + per_frame.append((frame_max, record["frame_index"])) + worst_frames = [frame for _, frame in sorted(per_frame, reverse=True)[:12]] + return {name: summarize(items) for name, items in values.items()}, worst_frames + + +def write_montage( + video_path: Path, + records: list[dict], + selected_frames: list[int], + output_path: Path, + titles: tuple[str, str] = ("RTMW-M 256x192", "RTMW-L 384x288"), +) -> None: + selected = set(selected_frames) + record_map = {record["frame_index"]: record for record in records} + cap = cv2.VideoCapture(str(video_path)) + rows: list[np.ndarray] = [] + frame_idx = 0 + while True: + ok, frame = cap.read() + if not ok: + break + if frame_idx in selected: + record = record_map[frame_idx] + m = draw_pose( + frame, + record["boxes"], + np.asarray(record["M"]["keypoints"]), + f"{titles[0]} | frame {frame_idx}", + ) + l = draw_pose( + frame, + record["boxes"], + np.asarray(record["L"]["keypoints"]), + f"{titles[1]} | frame {frame_idx}", + ) + m = cv2.resize(m, (640, 360), interpolation=cv2.INTER_AREA) + l = cv2.resize(l, (640, 360), interpolation=cv2.INTER_AREA) + rows.append(np.hstack([m, l])) + frame_idx += 1 + cap.release() + if rows: + cv2.imwrite(str(output_path), np.vstack(rows)) + + +def main() -> None: + from rtmlib import RTMPose + args = parse_args() + args.output.mkdir(parents=True, exist_ok=True) + cached_boxes = load_boxes(args.boxes, args.max_people) + + pose_m = RTMPose( + str(args.model_m), model_input_size=(192, 256), backend="onnxruntime", device="cpu" + ) + pose_l = RTMPose( + str(args.model_l), model_input_size=(288, 384), backend="onnxruntime", device="cpu" + ) + + cap = cv2.VideoCapture(str(args.video)) + fps = float(cap.get(cv2.CAP_PROP_FPS)) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + video_output = args.output / "reference_video_rtmw_m_vs_l.mp4" + writer = cv2.VideoWriter( + str(video_output), + cv2.VideoWriter_fourcc(*"mp4v"), + fps, + (width, height // 2), + ) + + records: list[dict] = [] + timings = {"M": [], "L": []} + frame_idx = 0 + while True: + ok, frame = cap.read() + if not ok: + break + boxes = cached_boxes[frame_idx] + + started = time.perf_counter() + kpts_m, scores_m = pose_m(frame, bboxes=boxes) + timings["M"].append((time.perf_counter() - started) * 1000.0) + + started = time.perf_counter() + kpts_l, scores_l = pose_l(frame, bboxes=boxes) + timings["L"].append((time.perf_counter() - started) * 1000.0) + + records.append( + { + "frame_index": frame_idx, + "boxes": boxes, + "M": { + "keypoints": np.round(kpts_m, 3).tolist(), + "raw_scores": np.round(scores_m, 4).tolist(), + }, + "L": { + "keypoints": np.round(kpts_l, 3).tolist(), + "raw_scores": np.round(scores_l, 4).tolist(), + }, + } + ) + + left = draw_pose(frame, boxes, kpts_m, f"RTMW-M 256x192 | frame {frame_idx}") + right = draw_pose(frame, boxes, kpts_l, f"RTMW-L 384x288 | frame {frame_idx}") + left = cv2.resize(left, (width // 2, height // 2), interpolation=cv2.INTER_AREA) + right = cv2.resize(right, (width // 2, height // 2), interpolation=cv2.INTER_AREA) + writer.write(np.hstack([left, right])) + + if frame_idx % 50 == 0: + print(f"processed frame {frame_idx}", flush=True) + frame_idx += 1 + + cap.release() + writer.release() + + jsonl_path = args.output / "reference_video_rtmw_m_vs_l.jsonl" + with jsonl_path.open("w", encoding="utf-8") as handle: + for record in records: + handle.write(json.dumps(record, ensure_ascii=False) + "\n") + + disagreement, worst_frames = model_disagreement(records) + fixed_frames = [0, 60, 120, 180, 240, 252, 300, 360, 411] + montage_frames = sorted(set(fixed_frames + worst_frames)) + write_montage( + args.video, + records, + montage_frames, + args.output / "rtmw_m_vs_l_full_montage.jpg", + ) + + summary = { + "frames": len(records), + "input_sizes_wh": {"M": [192, 256], "L": [288, 384]}, + "raw_score_note": ( + "M and L raw SimCC peak scores use different scales and must not be compared " + "or thresholded with the same numeric value." + ), + "timing_ms_two_people_cpu": { + name: summarize(values[5:] if len(values) > 5 else values) + for name, values in timings.items() + }, + "temporal_metrics_normalized_to_yolo_box": temporal_metrics(records), + "m_l_position_disagreement_normalized_to_yolo_box": disagreement, + "largest_upper_body_disagreement_frames": worst_frames, + "montage_frames": montage_frames, + } + with (args.output / "summary.json").open("w", encoding="utf-8") as handle: + json.dump(summary, handle, ensure_ascii=False, indent=2) + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/orin/pipeline/door_mask_risk.py b/orin/pipeline/door_mask_risk.py new file mode 100644 index 0000000..49eeec5 --- /dev/null +++ b/orin/pipeline/door_mask_risk.py @@ -0,0 +1,488 @@ +"""Per-frame door-mask loading and YOLO/RTMW-only 2-D risk scoring.""" + +from __future__ import annotations + +import json +import math +import re +import time +from collections import Counter +from dataclasses import dataclass +from pathlib import Path + +import cv2 +import numpy as np + + +RASTER_SUFFIXES = {".png", ".bmp", ".tif", ".tiff"} +DEFAULT_DOOR_LABELS = ("door", "车门") + + +@dataclass +class LoadedDoorMask: + status: str + annotation_index: int + path: Path | None + mask: np.ndarray | None + source_format: str | None + + def metadata(self) -> dict: + return { + "status": self.status, + "annotation_index": self.annotation_index, + "path": str(self.path.resolve()) if self.path is not None else None, + "format": self.source_format, + "area_px": int(np.count_nonzero(self.mask)) if self.mask is not None else 0, + } + + +def _frame_index_from_path(path: Path) -> int | None: + matches = re.findall(r"\d+", path.stem) + return int(matches[-1]) if matches else None + + +class DoorMaskSequence: + """Index a directory of X-AnyLabeling JSON polygons or raster masks.""" + + def __init__( + self, + directory: Path | None = None, + mask_format: str = "auto", + labels: tuple[str, ...] = DEFAULT_DOOR_LABELS, + frame_offset: int = 0, + require_every_frame: bool = False, + constant_mask: Path | None = None, + ): + if (directory is None) == (constant_mask is None): + raise ValueError("Provide exactly one of directory or constant_mask") + self.constant_path = ( + Path(constant_mask).expanduser().resolve() + if constant_mask is not None + else None + ) + self.directory = ( + self.constant_path.parent if self.constant_path is not None else Path(directory) + ) + if self.constant_path is not None and not self.constant_path.is_file(): + raise ValueError(f"Constant door mask does not exist: {self.constant_path}") + if self.constant_path is None and not self.directory.is_dir(): + raise ValueError(f"Door mask directory does not exist: {self.directory}") + self.labels = {label.casefold() for label in labels} + self.frame_offset = int(frame_offset) + self.require_every_frame = require_every_frame + + if self.constant_path is not None: + if mask_format == "auto": + selected_format = ( + "xanylabeling" + if self.constant_path.suffix.lower() == ".json" + else "raster" + ) + else: + selected_format = mask_format + self.source_format = selected_format + self.paths = {0: self.constant_path} + return + + json_paths = sorted(self.directory.rglob("*.json")) + raster_paths = sorted( + path + for path in self.directory.rglob("*") + if path.is_file() and path.suffix.lower() in RASTER_SUFFIXES + ) + if mask_format == "auto": + selected_format = "xanylabeling" if json_paths else "raster" + else: + selected_format = mask_format + candidates = json_paths if selected_format == "xanylabeling" else raster_paths + if not candidates: + expected = "JSON" if selected_format == "xanylabeling" else "PNG/BMP/TIFF" + raise ValueError(f"No {expected} door masks found in {self.directory}") + + self.source_format = selected_format + self.paths: dict[int, Path] = {} + for path in candidates: + index = _frame_index_from_path(path) + if index is None and selected_format == "xanylabeling": + data = json.loads(path.read_text(encoding="utf-8-sig")) + explicit = data.get("frame_index", data.get("frameIndex")) + index = int(explicit) if explicit is not None else None + if index is None: + continue + if index in self.paths: + raise ValueError( + f"Multiple door masks map to annotation frame {index}: " + f"{self.paths[index]} and {path}" + ) + self.paths[index] = path + if not self.paths: + raise ValueError( + "Door mask filenames need a frame number, for example 000000.json" + ) + + def load(self, video_frame_index: int, frame_shape: tuple[int, int]) -> LoadedDoorMask: + if self.constant_path is not None: + annotation_index = video_frame_index + path = self.constant_path + else: + annotation_index = video_frame_index + self.frame_offset + path = self.paths.get(annotation_index) + if path is None: + if self.require_every_frame: + raise RuntimeError( + f"No door mask for video frame {video_frame_index} " + f"(expected annotation index {annotation_index})" + ) + return LoadedDoorMask("missing", annotation_index, None, None, self.source_format) + + if self.source_format == "xanylabeling": + mask = self._load_xanylabeling(path, frame_shape) + else: + mask = self._load_raster(path, frame_shape) + status = "loaded" if np.any(mask) else "empty" + return LoadedDoorMask(status, annotation_index, path, mask, self.source_format) + + @staticmethod + def _load_raster(path: Path, frame_shape: tuple[int, int]) -> np.ndarray: + image = cv2.imread(str(path), cv2.IMREAD_UNCHANGED) + if image is None: + raise RuntimeError(f"Cannot read door mask: {path}") + if image.ndim == 3: + image = np.max(image[:, :, :3], axis=2) + height, width = frame_shape + if image.shape != (height, width): + image = cv2.resize(image, (width, height), interpolation=cv2.INTER_NEAREST) + return image > 0 + + def _load_xanylabeling( + self, path: Path, frame_shape: tuple[int, int] + ) -> np.ndarray: + data = json.loads(path.read_text(encoding="utf-8-sig")) + height, width = frame_shape + source_width = float(data.get("imageWidth") or width) + source_height = float(data.get("imageHeight") or height) + scale = np.asarray( + [width / max(source_width, 1.0), height / max(source_height, 1.0)], + dtype=np.float32, + ) + mask = np.zeros((height, width), dtype=np.uint8) + for shape in data.get("shapes", []): + if str(shape.get("label", "")).casefold() not in self.labels: + continue + points = np.asarray(shape.get("points", []), dtype=np.float32).reshape(-1, 2) + if len(points) < 2: + continue + points = np.rint(points * scale).astype(np.int32) + shape_type = str(shape.get("shape_type", "polygon")).lower() + if shape_type == "rectangle" and len(points) >= 2: + x1, y1 = points[0] + x2, y2 = points[1] + cv2.rectangle(mask, (x1, y1), (x2, y2), 1, -1) + elif shape_type == "circle" and len(points) >= 2: + radius = int(round(float(np.linalg.norm(points[1] - points[0])))) + cv2.circle(mask, tuple(points[0]), radius, 1, -1) + elif len(points) >= 3: + cv2.fillPoly(mask, [points], 1) + return mask > 0 + + +def _fit_mask(mask: np.ndarray, frame_shape: tuple[int, int]) -> np.ndarray: + height, width = frame_shape + result = np.asarray(mask) > 0 + if result.shape != (height, width): + result = cv2.resize( + result.astype(np.uint8), (width, height), interpolation=cv2.INTER_NEAREST + ) > 0 + return result + + +def _box_mask(box: list[float] | None, frame_shape: tuple[int, int]) -> np.ndarray | None: + if box is None or len(box) < 4: + return None + height, width = frame_shape + x1, y1, x2, y2 = [int(round(float(value))) for value in box[:4]] + x1, x2 = sorted((max(0, min(width - 1, x1)), max(0, min(width - 1, x2)))) + y1, y2 = sorted((max(0, min(height - 1, y1)), max(0, min(height - 1, y2)))) + if x2 <= x1 or y2 <= y1: + return None + mask = np.zeros((height, width), dtype=bool) + mask[y1 : y2 + 1, x1 : x2 + 1] = True + return mask + + +def _hand_mask(points: list, frame_shape: tuple[int, int]) -> np.ndarray | None: + hand = np.asarray(points, dtype=np.float32).reshape(-1, 2) + if len(hand) < 3 or not np.isfinite(hand).all(): + return None + hull = cv2.convexHull(np.rint(hand).astype(np.int32)) + mask = np.zeros(frame_shape, dtype=np.uint8) + cv2.fillConvexPoly(mask, hull, 1) + return mask > 0 if np.any(mask) else None + + +def _decision(distance_relative: float, overlap_px: int, warning: float, release: float) -> tuple[str, str]: + if overlap_px > 0: + return "danger", "DANGER_INTERSECTION" + if distance_relative <= warning: + return "warning", "WARNING_NEAR" + if distance_relative <= release: + return "watch", "WATCH" + return "clear", "CLEAR" + + +class DoorRiskEvaluator: + """Score RTMW hand regions, with one YOLO body-box fallback per person.""" + + def __init__( + self, + sequence: DoorMaskSequence, + warning_relative: float = 0.30, + release_relative: float = 0.45, + ): + if warning_relative < 0 or release_relative <= warning_relative: + raise ValueError("Risk thresholds require 0 <= warning < release") + self.sequence = sequence + self.warning_relative = float(warning_relative) + self.release_relative = float(release_relative) + self.mask_status_counts: Counter = Counter() + self.level_counts: Counter = Counter() + self.source_counts: Counter = Counter() + self.maximum_score = 0.0 + self.timing_seconds: Counter = Counter() + self.timing_counts: Counter = Counter() + self._constant_cache_shape: tuple[int, int] | None = None + self._constant_loaded: LoadedDoorMask | None = None + self._constant_distance_map: np.ndarray | None = None + self.distance_map_cache_builds = 0 + + def _record_timing(self, name: str, started: float) -> None: + self.timing_seconds[name] += time.perf_counter() - started + self.timing_counts[name] += 1 + + def _measure_region( + self, + region: np.ndarray, + door_mask: np.ndarray, + distance_map: np.ndarray, + source: str, + track_id: int, + side: str, + state: str | None, + ) -> dict: + area_px = int(np.count_nonzero(region)) + overlap_px = int(np.count_nonzero(region & door_mask)) + distances = distance_map[region] + distance_px = float(np.min(distances)) if len(distances) else math.inf + scale_px = max(math.sqrt(area_px), 1.0) + distance_relative = distance_px / scale_px + score = float(np.clip(1.0 - distance_relative / self.release_relative, 0.0, 1.0)) + if overlap_px: + score = 1.0 + level, decision = _decision( + distance_relative, + overlap_px, + self.warning_relative, + self.release_relative, + ) + result = { + "status": "calculated", + "risk_score": round(score, 5), + "risk_level": level, + "decision": decision, + "source": source, + "track_id": int(track_id), + "side": side, + "state": state, + "region_area_px": area_px, + "door_overlap_px": overlap_px, + "region_overlap_ratio": round(overlap_px / max(area_px, 1), 6), + "min_distance_px": round(distance_px, 3), + "region_scale_px": round(scale_px, 3), + "distance_relative": round(distance_relative, 6), + } + self.level_counts[level] += 1 + self.source_counts[source] += 1 + self.maximum_score = max(self.maximum_score, score) + return result + + @staticmethod + def _unavailable(source: str, track_id: int, side: str, status: str) -> dict: + return { + "status": status, + "risk_score": None, + "risk_level": "unavailable", + "decision": "EVIDENCE_UNAVAILABLE", + "source": source, + "track_id": int(track_id), + "side": side, + } + + def evaluate( + self, + frame_index: int, + record: dict, + frame_shape: tuple[int, int], + ) -> tuple[dict, np.ndarray | None]: + total_started = time.perf_counter() + stage_started = time.perf_counter() + use_constant_cache = self.sequence.constant_path is not None + if use_constant_cache and self._constant_cache_shape == frame_shape: + cached = self._constant_loaded + assert cached is not None + loaded = LoadedDoorMask( + cached.status, + frame_index, + cached.path, + cached.mask, + cached.source_format, + ) + else: + loaded = self.sequence.load(frame_index, frame_shape) + if use_constant_cache: + self._constant_cache_shape = frame_shape + self._constant_loaded = loaded + self._constant_distance_map = None + self._record_timing("door_mask_load", stage_started) + self.mask_status_counts[loaded.status] += 1 + mask_ready = loaded.status == "loaded" and loaded.mask is not None + door_mask = loaded.mask if mask_ready else None + distance_map = None + if door_mask is not None and use_constant_cache and self._constant_distance_map is not None: + distance_map = self._constant_distance_map + elif door_mask is not None: + stage_started = time.perf_counter() + distance_map = cv2.distanceTransform( + (~door_mask).astype(np.uint8), cv2.DIST_L2, cv2.DIST_MASK_PRECISE + ) + self._record_timing("distance_transform", stage_started) + if use_constant_cache: + self._constant_distance_map = distance_map + self.distance_map_cache_builds += 1 + + stage_started = time.perf_counter() + regions: list[tuple[dict, np.ndarray, str, int, str, str | None]] = [] + track_ids = [int(value) for value in record.get("track_ids", [])] + person_positions_with_hands: set[int] = set() + for hand in record.get("global_hands", []): + position = int(hand.get("person_id", 0)) - 1 + track_id = track_ids[position] if 0 <= position < len(track_ids) else position + 1 + side = str(hand.get("side", "unknown")) + region = _hand_mask(hand.get("keypoints", []), frame_shape) + if region is None: + continue + person_positions_with_hands.add(position) + regions.append( + ( + hand, + region, + "RTMW_HAND_KEYPOINTS", + track_id, + side, + str(hand.get("state", "unknown")), + ) + ) + + boxes = record.get("boxes", []) + body_fallbacks = [] + for position, box in enumerate(boxes): + if position in person_positions_with_hands: + continue + region = _box_mask(box, frame_shape) + if region is None: + continue + track_id = track_ids[position] if position < len(track_ids) else position + 1 + fallback = { + "track_id": track_id, + "side": "body", + "state": "rtmw_hand_unavailable", + "body_zone_box": box, + } + body_fallbacks.append(fallback) + regions.append( + ( + fallback, + region, + "YOLO_BODY_BOX_FALLBACK", + track_id, + "body", + "rtmw_hand_unavailable", + ) + ) + record["body_fallbacks"] = body_fallbacks + self._record_timing("region_build", stage_started) + + stage_started = time.perf_counter() + measurements = [] + unavailable_status = f"door_mask_{loaded.status}" + for owner, region, source, track_id, side, state in regions: + if door_mask is None or distance_map is None: + measurement = self._unavailable( + source, track_id, side, unavailable_status + ) + else: + measurement = self._measure_region( + region, door_mask, distance_map, source, track_id, side, state + ) + owner["risk"] = measurement + measurements.append(measurement) + self._record_timing("region_measure", stage_started) + + calculated = [item for item in measurements if item["risk_score"] is not None] + nearest = max(calculated, key=lambda item: item["risk_score"]) if calculated else None + if loaded.status != "loaded": + status = unavailable_status + elif not calculated: + status = "person_region_missing" + else: + status = "calculated" + frame_risk = { + "status": status, + "risk_score": nearest["risk_score"] if nearest else None, + "risk_level": nearest["risk_level"] if nearest else "unavailable", + "decision": nearest["decision"] if nearest else "EVIDENCE_UNAVAILABLE", + "source": nearest["source"] if nearest else None, + "track_id": nearest["track_id"] if nearest else None, + "side": nearest["side"] if nearest else None, + "door_mask": loaded.metadata(), + "warning_distance_relative": self.warning_relative, + "release_distance_relative": self.release_relative, + "regions": measurements, + } + self._record_timing("risk_total", total_started) + return frame_risk, loaded.mask + + def summary(self) -> dict: + return { + "mask_directory": str(self.sequence.directory.resolve()), + "constant_mask": ( + str(self.sequence.constant_path) + if self.sequence.constant_path is not None + else None + ), + "constant_for_all_frames": self.sequence.constant_path is not None, + "mask_format": self.sequence.source_format, + "door_labels": sorted(self.sequence.labels), + "frame_offset": self.sequence.frame_offset, + "warning_distance_relative": self.warning_relative, + "release_distance_relative": self.release_relative, + "mask_status_counts": dict(self.mask_status_counts), + "risk_level_counts": dict(self.level_counts), + "source_counts": dict(self.source_counts), + "maximum_risk_score": round(self.maximum_score, 5), + "constant_distance_map_cached": self.sequence.constant_path is not None, + "distance_map_cache_builds": self.distance_map_cache_builds, + "timing_ms": { + name: { + "count": int(self.timing_counts[name]), + "total": round(float(seconds) * 1000.0, 3), + "mean": round( + float(seconds) * 1000.0 + / max(int(self.timing_counts[name]), 1), + 3, + ), + } + for name, seconds in self.timing_seconds.items() + }, + "score_semantics": "2-D image overlap/proximity research score; not millimeters or safety certification", + "region_policy": "RTMW alarm-eligible hand hulls; YOLO body box only when a person has no usable RTMW hand region", + } diff --git a/orin/pipeline/door_zone_risk.py b/orin/pipeline/door_zone_risk.py new file mode 100644 index 0000000..972cfb7 --- /dev/null +++ b/orin/pipeline/door_zone_risk.py @@ -0,0 +1,358 @@ +"""Multi-feature person-to-door assignment and active-CAN risk gating.""" + +from __future__ import annotations + +import json +import math +from collections import Counter, defaultdict, deque +from dataclasses import dataclass +from pathlib import Path +from statistics import median + + +DOORS = ("front", "rear") +POSE_FEATURES = { + "shoulder_center_x", + "shoulder_center_y", + "shoulder_width", + "torso_height", + "hip_center_y", +} + + +@dataclass(frozen=True) +class FeatureCalibration: + rear: float + front: float + weight: float + + def frontness(self, value: float) -> float: + span = self.front - self.rear + if span == 0: + return 0.5 + return min(1.0, max(0.0, (value - self.rear) / span)) + + +@dataclass(frozen=True) +class DoorZoneConfig: + features: dict[str, FeatureCalibration] + front_probability_min: float + rear_probability_max: float + minimum_person_height: float + minimum_pose_features: int + history_frames: int + stale_track_frames: int + source_path: Path | None = None + + @classmethod + def load(cls, path: Path) -> "DoorZoneConfig": + source = Path(path).expanduser().resolve() + data = json.loads(source.read_text(encoding="utf-8-sig")) + features = { + name: FeatureCalibration( + rear=float(values["rear"]), + front=float(values["front"]), + weight=float(values["weight"]), + ) + for name, values in data["features"].items() + } + return cls( + features=features, + front_probability_min=float(data.get("front_probability_min", 0.72)), + rear_probability_max=float(data.get("rear_probability_max", 0.28)), + minimum_person_height=float(data.get("minimum_person_height", 0.40)), + minimum_pose_features=int(data.get("minimum_pose_features", 4)), + history_frames=int(data.get("history_frames", 5)), + stale_track_frames=int(data.get("stale_track_frames", 120)), + source_path=source, + ) + + def classify(self, probability: float) -> str: + if probability >= self.front_probability_min: + return "front" + if probability <= self.rear_probability_max: + return "rear" + return "transition" + + +def _point(keypoints: list, index: int) -> tuple[float, float] | None: + if index >= len(keypoints) or len(keypoints[index]) < 2: + return None + x, y = float(keypoints[index][0]), float(keypoints[index][1]) + return (x, y) if math.isfinite(x) and math.isfinite(y) else None + + +def extract_person_features( + record: dict, + position: int, + frame_shape: tuple[int, int], +) -> tuple[dict[str, float], int]: + """Extract fixed-camera pose features, with box geometry as low-weight fallback.""" + + height, width = frame_shape + box = record.get("boxes", [])[position] + x1, y1, x2, y2 = [float(value) for value in box[:4]] + features = { + "box_center_x": ((x1 + x2) * 0.5) / max(width, 1), + "box_height": (y2 - y1) / max(height, 1), + } + + all_keypoints = record.get("temporal_selected_keypoints", []) + if position >= len(all_keypoints): + return features, 0 + keypoints = all_keypoints[position] + left_shoulder = _point(keypoints, 5) + right_shoulder = _point(keypoints, 6) + left_hip = _point(keypoints, 11) + right_hip = _point(keypoints, 12) + if None in (left_shoulder, right_shoulder, left_hip, right_hip): + return features, 0 + + shoulder_x = (left_shoulder[0] + right_shoulder[0]) * 0.5 + shoulder_y = (left_shoulder[1] + right_shoulder[1]) * 0.5 + hip_y = (left_hip[1] + right_hip[1]) * 0.5 + features.update( + { + "shoulder_center_x": shoulder_x / max(width, 1), + "shoulder_center_y": shoulder_y / max(height, 1), + "shoulder_width": math.hypot( + left_shoulder[0] - right_shoulder[0], + left_shoulder[1] - right_shoulder[1], + ) + / max(width, 1), + "torso_height": abs(hip_y - shoulder_y) / max(height, 1), + "hip_center_y": hip_y / max(height, 1), + } + ) + return features, len(POSE_FEATURES) + + +class DoorZoneAssigner: + """Fuse pose-dominant evidence and smooth front probability per track.""" + + def __init__(self, config: DoorZoneConfig): + self.config = config + self.history: dict[int, deque[float]] = defaultdict( + lambda: deque(maxlen=self.config.history_frames) + ) + self.last_seen: dict[int, int] = {} + self.zone_counts: Counter = Counter() + + def _score(self, features: dict[str, float]) -> tuple[float, dict[str, float]]: + weighted_sum = 0.0 + total_weight = 0.0 + contributions = {} + for name, calibration in self.config.features.items(): + if name not in features: + continue + frontness = calibration.frontness(float(features[name])) + contributions[name] = round(frontness, 6) + weighted_sum += frontness * calibration.weight + total_weight += calibration.weight + probability = weighted_sum / total_weight if total_weight else 0.5 + return probability, contributions + + def update( + self, + frame_index: int, + record: dict, + frame_shape: tuple[int, int], + ) -> list[dict]: + track_ids = [int(value) for value in record.get("track_ids", [])] + assignments = [] + for position, _box in enumerate(record.get("boxes", [])): + track_id = track_ids[position] if position < len(track_ids) else position + 1 + features, pose_feature_count = extract_person_features( + record, position, frame_shape + ) + probability, contributions = self._score(features) + enough_pose = pose_feature_count >= self.config.minimum_pose_features + if features["box_height"] < self.config.minimum_person_height: + raw_zone = "unassigned" + door_zone = "unassigned" + elif not enough_pose: + raw_zone = "transition" + door_zone = "transition" + else: + raw_zone = self.config.classify(probability) + values = self.history[track_id] + values.append(probability) + door_zone = self.config.classify(float(median(values))) + + values = self.history.get(track_id, ()) + smoothed_probability = ( + float(median(values)) if values else float(probability) + ) + self.last_seen[track_id] = int(frame_index) + self.zone_counts[door_zone] += 1 + assignments.append( + { + "track_id": track_id, + "person_index": position, + "door_zone": door_zone, + "raw_door_zone": raw_zone, + "front_probability": round(float(probability), 6), + "smoothed_front_probability": round(smoothed_probability, 6), + "confidence": round(abs(smoothed_probability - 0.5) * 2.0, 6), + "evidence_source": "pose_primary_bbox_secondary", + "pose_feature_count": pose_feature_count, + "features": {name: round(value, 6) for name, value in features.items()}, + "feature_frontness": contributions, + "history_frames": len(values), + } + ) + + expired = [ + track_id + for track_id, seen_at in self.last_seen.items() + if frame_index - seen_at > self.config.stale_track_frames + ] + for track_id in expired: + self.history.pop(track_id, None) + self.last_seen.pop(track_id, None) + return assignments + + def summary(self) -> dict: + return { + "policy": "pose-primary weighted front probability with causal median", + "config": str(self.config.source_path) if self.config.source_path else None, + "history_frames": self.config.history_frames, + "front_probability_min": self.config.front_probability_min, + "rear_probability_max": self.config.rear_probability_max, + "minimum_person_height": self.config.minimum_person_height, + "minimum_pose_features": self.config.minimum_pose_features, + "features": { + name: { + "rear": calibration.rear, + "front": calibration.front, + "weight": calibration.weight, + } + for name, calibration in self.config.features.items() + }, + "zone_counts": dict(self.zone_counts), + } + + +def _inactive_risk(door: str) -> dict: + return { + "door_id": door, + "status": "inactive", + "risk_score": None, + "risk_level": "inactive", + "decision": "DOOR_CAN_NOT_ACTIVE", + "risk_type": f"{door.upper()}_INACTIVE", + "source": None, + "track_id": None, + "side": None, + "regions": [], + } + + +def _clear_risk(door: str) -> dict: + return { + "door_id": door, + "status": "calculated", + "risk_score": 0.0, + "risk_level": "clear", + "decision": "CLEAR_NO_PERSON_ASSIGNED_TO_ACTIVE_DOOR", + "risk_type": f"{door.upper()}_CLEAR", + "source": None, + "track_id": None, + "side": None, + "regions": [], + } + + +def _unknown_risk(door: str, transition_regions: list[dict]) -> dict: + return { + "door_id": door, + "status": "door_zone_ambiguous", + "risk_score": None, + "risk_level": "unknown", + "decision": "EVIDENCE_UNAVAILABLE_TRANSITION_ZONE", + "risk_type": f"{door.upper()}_UNKNOWN", + "source": None, + "track_id": None, + "side": None, + "regions": transition_regions, + } + + +def build_door_risks( + raw_risk: dict, + assignments: list[dict], + active_door: str, +) -> tuple[dict[str, dict], dict]: + """Build per-door risk and select the CAN-active door result.""" + + zone_by_track = { + int(assignment["track_id"]): str(assignment["door_zone"]) + for assignment in assignments + } + annotated_regions = [] + for original in raw_risk.get("regions", []): + region = dict(original) + region["door_zone"] = zone_by_track.get(int(region.get("track_id", -1)), "unknown") + annotated_regions.append(region) + + active_doors = set(DOORS) if active_door == "both" else {active_door} + if active_door == "none": + active_doors.clear() + + door_risks: dict[str, dict] = {} + for door in DOORS: + if door not in active_doors: + door_risks[door] = _inactive_risk(door) + continue + exact = [region for region in annotated_regions if region["door_zone"] == door] + transition = [ + region for region in annotated_regions if region["door_zone"] == "transition" + ] + calculated = [region for region in exact if region.get("risk_score") is not None] + if calculated: + nearest = max(calculated, key=lambda item: float(item["risk_score"])) + level = str(nearest["risk_level"]) + if transition and level in ("clear", "watch"): + door_risks[door] = _unknown_risk(door, transition) + else: + door_risks[door] = { + "door_id": door, + "status": "calculated", + "risk_score": nearest["risk_score"], + "risk_level": level, + "decision": nearest["decision"], + "risk_type": f"{door.upper()}_{level.upper()}", + "source": nearest["source"], + "track_id": nearest["track_id"], + "side": nearest["side"], + "regions": exact, + } + elif transition: + door_risks[door] = _unknown_risk(door, transition) + else: + door_risks[door] = _clear_risk(door) + + if len(active_doors) == 1: + selected = dict(door_risks[next(iter(active_doors))]) + elif not active_doors: + selected = { + "door_id": None, + "status": "inactive", + "risk_score": None, + "risk_level": "inactive", + "decision": "NO_DOOR_CAN_ACTIVE", + "risk_type": "NO_ACTIVE_DOOR", + "source": None, + "track_id": None, + "side": None, + "regions": [], + } + else: + severity = {"danger": 4, "warning": 3, "watch": 2, "unknown": 1, "clear": 0} + selected = dict( + max(door_risks.values(), key=lambda item: severity.get(item["risk_level"], -1)) + ) + selected["door_mask"] = raw_risk.get("door_mask") + selected["warning_distance_relative"] = raw_risk.get("warning_distance_relative") + selected["release_distance_relative"] = raw_risk.get("release_distance_relative") + return door_risks, selected diff --git a/orin/pipeline/fuse_rtmw_l_temporal.py b/orin/pipeline/fuse_rtmw_l_temporal.py new file mode 100644 index 0000000..f212589 --- /dev/null +++ b/orin/pipeline/fuse_rtmw_l_temporal.py @@ -0,0 +1,855 @@ +"""Fuse raw and person-isolated RTMW-L poses with temporal consistency. + +The fusion keeps the two inference views as hypotheses. It selects body limbs +and hands separately, rejects implausible hand geometry, adds source hysteresis +and constant-velocity consistency, then applies a motion-adaptive EMA in +person-box coordinates. Occluded/conflicting limbs remain labelled as such so +they are not accidentally consumed as precise anti-pinch distance evidence. +""" + +from __future__ import annotations + +import argparse +import json +import math +from collections import Counter, defaultdict +from dataclasses import dataclass, field +from pathlib import Path + +import cv2 +import numpy as np + +from compare_rtmw_ml import ( + BODY_EDGES, + BODY_WRISTS, + HAND_EDGES_LOCAL, + HAND_SLICES, + draw_pose, + normalized_keypoints, + summarize, + temporal_metrics, +) + + +BODY_SIDE_INDICES = {"left": (5, 7, 9), "right": (6, 8, 10)} +SIDE_COLORS = {"left": (40, 40, 255), "right": (30, 230, 30)} +HAND_COLORS = {"left": (255, 80, 220), "right": (255, 190, 40)} + + +@dataclass +class Candidate: + source: str + keypoints: np.ndarray + scores: np.ndarray + normalized: np.ndarray + limb_score: float + hand_score: float + upper_length: float + forearm_length: float + hand_span: float + wrist_link: float + limb_valid: bool + hand_valid: bool + + +@dataclass +class SideTrack: + limb_previous: np.ndarray | None = None + limb_velocity: np.ndarray | None = None + hand_previous: np.ndarray | None = None + hand_velocity: np.ndarray | None = None + limb_source: str | None = None + hand_source: str | None = None + previous_hand_eligible: bool = False + + +@dataclass +class PersonTrack: + sides: dict[str, SideTrack] = field( + default_factory=lambda: {"left": SideTrack(), "right": SideTrack()} + ) + smoothed: np.ndarray | None = None + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--video", type=Path, required=True) + parser.add_argument("--raw-jsonl", type=Path, required=True) + parser.add_argument("--isolated-jsonl", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + return parser.parse_args() + + +def bbox_diagonal(bbox: list[float]) -> float: + return max(math.hypot(bbox[2] - bbox[0], bbox[3] - bbox[1]), 1.0) + + +def build_candidate( + source: str, + keypoints: np.ndarray, + scores: np.ndarray, + bbox: list[float], + side: str, +) -> Candidate: + normalized = normalized_keypoints(keypoints, bbox) + shoulder, elbow, wrist = BODY_SIDE_INDICES[side] + hand_start, hand_end = HAND_SLICES[side] + hand = keypoints[hand_start:hand_end] + diagonal = bbox_diagonal(bbox) + upper_length = float(np.linalg.norm(normalized[shoulder] - normalized[elbow])) + forearm_length = float(np.linalg.norm(normalized[elbow] - normalized[wrist])) + hand_span = math.hypot(float(np.ptp(hand[:, 0])), float(np.ptp(hand[:, 1]))) / diagonal + wrist_link = float(np.linalg.norm(keypoints[wrist] - hand[0])) / diagonal + limb_score = float(np.mean(scores[[shoulder, elbow, wrist]])) + hand_score = float(np.mean(scores[hand_start:hand_end])) + limb_valid = 0.025 <= upper_length <= 0.8 and 0.025 <= forearm_length <= 0.8 + hand_valid = 0.008 <= hand_span <= 0.35 and wrist_link <= 0.12 + return Candidate( + source=source, + keypoints=keypoints, + scores=scores, + normalized=normalized, + limb_score=limb_score, + hand_score=hand_score, + upper_length=upper_length, + forearm_length=forearm_length, + hand_span=hand_span, + wrist_link=wrist_link, + limb_valid=limb_valid, + hand_valid=hand_valid, + ) + + +def predicted(previous: np.ndarray | None, velocity: np.ndarray | None) -> np.ndarray | None: + if previous is None: + return None + if velocity is None: + return previous + return previous + 0.65 * velocity + + +def robust_distance(points: np.ndarray, target: np.ndarray | None) -> float: + if target is None: + return 0.0 + distances = np.linalg.norm(points - target, axis=1) + return float(np.median(distances)) + + +def select_limb( + candidates: list[Candidate], + side: str, + track: SideTrack | None, +) -> tuple[Candidate, dict[str, float]]: + indices = np.asarray(BODY_SIDE_INDICES[side]) + target = predicted(track.limb_previous, track.limb_velocity) if track else None + scored: list[tuple[float, Candidate, float]] = [] + for candidate in candidates: + temporal_cost = robust_distance(candidate.normalized[indices], target) + geometry_bonus = 1.2 if candidate.limb_valid else -5.0 + switch_bonus = 0.35 if track and candidate.source == track.limb_source else 0.0 + score = candidate.limb_score + geometry_bonus + switch_bonus - 7.0 * temporal_cost + scored.append((score, candidate, temporal_cost)) + score, selected, temporal_cost = max(scored, key=lambda item: item[0]) + return selected, {"score": score, "temporal_cost": temporal_cost} + + +def hand_link_to_limb( + candidate: Candidate, + selected_limb: Candidate, + bbox: list[float], + side: str, +) -> float: + hand_start, _ = HAND_SLICES[side] + wrist_idx = BODY_WRISTS[side] + return float( + np.linalg.norm(candidate.keypoints[hand_start] - selected_limb.keypoints[wrist_idx]) + ) / bbox_diagonal(bbox) + + +def select_hand( + candidates: list[Candidate], + selected_limb: Candidate, + bbox: list[float], + side: str, + track: SideTrack | None, +) -> tuple[Candidate, bool, dict[str, float]]: + start, end = HAND_SLICES[side] + target = predicted(track.hand_previous, track.hand_velocity) if track else None + scored: list[tuple[float, Candidate, bool, float, float]] = [] + for candidate in candidates: + temporal_cost = robust_distance(candidate.normalized[start:end], target) + link = hand_link_to_limb(candidate, selected_limb, bbox, side) + valid = candidate.hand_valid + geometry_bonus = 3.0 if valid else -7.0 + switch_bonus = 0.45 if track and candidate.source == track.hand_source else 0.0 + limb_source_bonus = 0.15 if candidate.source == selected_limb.source else 0.0 + # A newly visible endpoint may disagree with the currently selected + # (occlusion-driven) limb. Keep this as a soft cost so strong image + # evidence can switch both the hand and its limb together. + link_penalty = 1.5 * min(max(link - 0.12, 0.0), 0.2) + score = ( + candidate.hand_score + + geometry_bonus + + switch_bonus + + limb_source_bonus + - link_penalty + - 8.0 * min(temporal_cost, 0.15) + ) + scored.append((score, candidate, valid, temporal_cost, link)) + score, selected, valid, temporal_cost, link = max(scored, key=lambda item: item[0]) + return selected, valid, { + "score": score, + "temporal_cost": temporal_cost, + "link_to_selected_limb": link, + } + + +def candidate_disagreement( + raw: Candidate, + isolated: Candidate, + side: str, +) -> tuple[float, float]: + shoulder, elbow, wrist = BODY_SIDE_INDICES[side] + start, end = HAND_SLICES[side] + limb = float( + np.median( + np.linalg.norm( + raw.normalized[[shoulder, elbow, wrist]] + - isolated.normalized[[shoulder, elbow, wrist]], + axis=1, + ) + ) + ) + hand_distances = np.linalg.norm( + raw.normalized[start:end] - isolated.normalized[start:end], axis=1 + ) + hand = float(np.percentile(hand_distances, 90)) + return limb, hand + + +def suppress_duplicate_hands( + fused: np.ndarray, + metadata: dict, + bbox: list[float], +) -> None: + left_start, left_end = HAND_SLICES["left"] + right_start, right_end = HAND_SLICES["right"] + left_center = np.mean(fused[left_start:left_end], axis=0) + right_center = np.mean(fused[right_start:right_end], axis=0) + separation = float(np.linalg.norm(left_center - right_center)) / bbox_diagonal(bbox) + if separation >= 0.08: + return + weaker = min( + ("left", "right"), + key=lambda side: metadata[side]["selected_hand_score"], + ) + metadata[weaker]["hand_state"] = "duplicate" + metadata[weaker]["distance_eligible"] = False + metadata[weaker]["alarm_eligible"] = False + metadata[weaker]["duplicate_hand_separation"] = round(separation, 5) + + +def fuse_person( + raw_keypoints: np.ndarray, + raw_scores: np.ndarray, + isolated_keypoints: np.ndarray, + isolated_scores: np.ndarray, + bbox: list[float], + track: PersonTrack | None, +) -> tuple[np.ndarray, dict]: + fused = raw_keypoints.copy() + metadata: dict[str, dict] = {} + + for side in ("left", "right"): + side_track = track.sides[side] if track else None + raw = build_candidate("raw", raw_keypoints, raw_scores, bbox, side) + isolated = build_candidate( + "isolated", isolated_keypoints, isolated_scores, bbox, side + ) + candidates = [raw, isolated] + limb, limb_detail = select_limb(candidates, side, side_track) + hand, hand_valid, hand_detail = select_hand( + candidates, limb, bbox, side, side_track + ) + + other_hand = isolated if hand.source == "raw" else raw + endpoint_advantage = hand.hand_score - other_hand.hand_score + if hand.source != limb.source and hand_valid and endpoint_advantage >= 0.6: + limb = hand + limb_detail["visible_endpoint_override"] = 1.0 + hand_detail["link_to_selected_limb"] = hand.wrist_link + + body_indices = np.asarray(BODY_SIDE_INDICES[side]) + hand_start, hand_end = HAND_SLICES[side] + fused[body_indices] = limb.keypoints[body_indices] + fused[hand_start:hand_end] = hand.keypoints[hand_start:hand_end] + + limb_disagreement, hand_disagreement = candidate_disagreement(raw, isolated, side) + if limb_disagreement <= 0.05: + limb_state = "consensus" + else: + limb_state = "inferred" + + score_advantage = raw.hand_score - isolated.hand_score + raw_temporally_stable = hand_detail["temporal_cost"] <= 0.08 + if not hand_valid: + hand_state = "rejected" + distance_eligible = False + elif hand_disagreement <= 0.06: + hand_state = "consensus" + distance_eligible = True + elif ( + hand.source == "raw" + and score_advantage >= 0.6 + and raw_temporally_stable + ): + hand_state = "visible_endpoint" + distance_eligible = True + elif hand.source == "isolated": + hand_state = "inferred" + distance_eligible = False + else: + hand_state = "conflict" + distance_eligible = False + fast_alarm_endpoint = ( + hand_valid and hand.source == "raw" and score_advantage >= 0.6 + ) + alarm_eligible = distance_eligible or fast_alarm_endpoint + + metadata[side] = { + "limb_source": limb.source, + "hand_source": hand.source, + "limb_state": limb_state, + "hand_state": hand_state, + "distance_eligible": distance_eligible, + "alarm_eligible": alarm_eligible, + "limb_disagreement": round(limb_disagreement, 5), + "hand_disagreement": round(hand_disagreement, 5), + "raw_hand_score": round(raw.hand_score, 4), + "isolated_hand_score": round(isolated.hand_score, 4), + "selected_hand_span": round(hand.hand_span, 5), + "selected_hand_score": round(hand.hand_score, 4), + "selected_hand_valid": hand_valid, + "limb_selection": {key: round(value, 5) for key, value in limb_detail.items()}, + "hand_selection": {key: round(value, 5) for key, value in hand_detail.items()}, + } + + if side_track is not None: + limb_now = limb.normalized[body_indices] + hand_now = hand.normalized[hand_start:hand_end] + if side_track.limb_previous is not None: + delta = limb_now - side_track.limb_previous + side_track.limb_velocity = ( + delta + if side_track.limb_velocity is None + else 0.65 * side_track.limb_velocity + 0.35 * delta + ) + if hand_valid: + if side_track.hand_previous is not None: + delta = hand_now - side_track.hand_previous + side_track.hand_velocity = ( + delta + if side_track.hand_velocity is None + else 0.65 * side_track.hand_velocity + 0.35 * delta + ) + side_track.hand_previous = hand_now + side_track.hand_source = hand.source + side_track.limb_previous = limb_now + side_track.limb_source = limb.source + side_track.previous_hand_eligible = distance_eligible + + suppress_duplicate_hands(fused, metadata, bbox) + return fused, metadata + + +def adaptive_smooth( + keypoints: np.ndarray, + bbox: list[float], + track: PersonTrack, +) -> np.ndarray: + normalized = normalized_keypoints(keypoints, bbox) + if track.smoothed is None: + track.smoothed = normalized + else: + displacement = np.linalg.norm(normalized - track.smoothed, axis=1) + alpha = 0.32 + 0.58 * np.clip(displacement / 0.08, 0.0, 1.0) + track.smoothed = alpha[:, None] * normalized + (1.0 - alpha[:, None]) * track.smoothed + + x1, y1, x2, y2 = bbox + result = track.smoothed.copy() + result[:, 0] = result[:, 0] * max(x2 - x1, 1.0) + x1 + result[:, 1] = result[:, 1] * max(y2 - y1, 1.0) + y1 + return result + + +def build_global_hands( + keypoints: list[np.ndarray], + metadata: list[dict], +) -> list[dict]: + candidates = [] + for person_idx, (person_keypoints, person_meta) in enumerate( + zip(keypoints, metadata), start=1 + ): + for side, (start, end) in HAND_SLICES.items(): + meta = person_meta[side] + if not meta["alarm_eligible"]: + continue + hand = person_keypoints[start:end] + span_px = math.hypot(float(np.ptp(hand[:, 0])), float(np.ptp(hand[:, 1]))) + candidates.append( + { + "person_id": person_idx, + "side": side, + "source": meta["hand_source"], + "state": meta["hand_state"], + "distance_eligible": meta["distance_eligible"], + "alarm_eligible": meta["alarm_eligible"], + "score": meta["selected_hand_score"], + "center": np.mean(hand, axis=0), + "span_px": span_px, + "keypoints": hand, + "aliases": [], + } + ) + + kept: list[dict] = [] + for candidate in sorted(candidates, key=lambda item: item["score"], reverse=True): + duplicate = None + for existing in kept: + threshold = float(np.clip(0.45 * max(candidate["span_px"], existing["span_px"]), 18, 70)) + if float(np.linalg.norm(candidate["center"] - existing["center"])) <= threshold: + duplicate = existing + break + if duplicate is None: + kept.append(candidate) + else: + duplicate["aliases"].append( + {"person_id": candidate["person_id"], "side": candidate["side"]} + ) + + return [ + { + "person_id": item["person_id"], + "side": item["side"], + "source": item["source"], + "state": item["state"], + "distance_eligible": item["distance_eligible"], + "alarm_eligible": item["alarm_eligible"], + "score": item["score"], + "center": np.round(item["center"], 3).tolist(), + "span_px": round(item["span_px"], 3), + "keypoints": np.round(item["keypoints"], 3).tolist(), + "aliases": item["aliases"], + } + for item in kept + ] + + +def draw_dashed_line( + image: np.ndarray, + start: np.ndarray, + end: np.ndarray, + color: tuple[int, int, int], + thickness: int = 2, +) -> None: + a = np.asarray(start, dtype=np.float64) + b = np.asarray(end, dtype=np.float64) + length = float(np.linalg.norm(b - a)) + if length < 1.0: + return + direction = (b - a) / length + for offset in np.arange(0.0, length, 14.0): + segment_start = a + direction * offset + segment_end = a + direction * min(offset + 8.0, length) + cv2.line( + image, + tuple(np.round(segment_start).astype(int)), + tuple(np.round(segment_end).astype(int)), + color, + thickness, + cv2.LINE_AA, + ) + + +def draw_fused( + image: np.ndarray, + boxes: list[list[float]], + keypoints: list[np.ndarray], + metadata: list[dict], + title: str, +) -> np.ndarray: + canvas = image.copy() + for person_idx, (bbox, kpts, person_meta) in enumerate( + zip(boxes, keypoints, metadata), start=1 + ): + x1, y1, x2, y2 = (int(round(value)) for value in bbox) + cv2.rectangle(canvas, (x1, y1), (x2, y2), (0, 220, 255), 2) + cv2.putText( + canvas, + f"P{person_idx}", + (x1 + 4, max(22, y1 + 24)), + cv2.FONT_HERSHEY_SIMPLEX, + 0.72, + (0, 220, 255), + 2, + cv2.LINE_AA, + ) + for side in ("left", "right"): + shoulder, elbow, wrist = BODY_SIDE_INDICES[side] + side_meta = person_meta[side] + color = SIDE_COLORS[side] + for a, b in ((shoulder, elbow), (elbow, wrist)): + if side_meta["limb_state"] == "consensus": + cv2.line( + canvas, + tuple(np.round(kpts[a]).astype(int)), + tuple(np.round(kpts[b]).astype(int)), + color, + 3, + cv2.LINE_AA, + ) + else: + draw_dashed_line(canvas, kpts[a], kpts[b], (0, 140, 255), 3) + + start, end = HAND_SLICES[side] + hand = kpts[start:end] + if side_meta["hand_state"] != "rejected": + hand_color = HAND_COLORS[side] + if not side_meta["distance_eligible"]: + hand_color = (0, 140, 255) + for a, b in HAND_EDGES_LOCAL: + if side_meta["distance_eligible"]: + cv2.line( + canvas, + tuple(np.round(hand[a]).astype(int)), + tuple(np.round(hand[b]).astype(int)), + hand_color, + 2, + cv2.LINE_AA, + ) + else: + draw_dashed_line(canvas, hand[a], hand[b], hand_color, 2) + label = ( + f"{side[0].upper()}:{side_meta['hand_state'][:4]}" + f"/{side_meta['hand_source'][0]}" + ) + label_y = max(45, y1 + (48 if side == "left" else 70)) + cv2.putText( + canvas, + label, + (x1 + 4, label_y), + cv2.FONT_HERSHEY_SIMPLEX, + 0.5, + HAND_COLORS[side] if side_meta["distance_eligible"] else (0, 140, 255), + 1, + cv2.LINE_AA, + ) + + cv2.rectangle(canvas, (0, 0), (650, 45), (0, 0, 0), -1) + cv2.putText( + canvas, + title, + (10, 31), + cv2.FONT_HERSHEY_SIMPLEX, + 0.8, + (255, 255, 255), + 2, + cv2.LINE_AA, + ) + return canvas + + +def make_montage( + video_path: Path, + records: list[dict], + selected_frames: list[int], + output_path: Path, +) -> None: + selected = set(selected_frames) + by_frame = {record["frame_index"]: record for record in records} + cap = cv2.VideoCapture(str(video_path)) + rows = [] + frame_idx = 0 + while True: + ok, frame = cap.read() + if not ok: + break + if frame_idx in selected: + record = by_frame[frame_idx] + boxes = record["boxes"] + raw = draw_pose( + frame, + boxes, + np.asarray(record["raw_keypoints"]), + f"RTMW-L raw | frame {frame_idx}", + ) + spatial = draw_fused( + frame, + boxes, + [np.asarray(points) for points in record["spatial_keypoints"]], + record["spatial_metadata"], + f"spatial fusion | frame {frame_idx}", + ) + temporal = draw_fused( + frame, + boxes, + [np.asarray(points) for points in record["temporal_keypoints"]], + record["temporal_metadata"], + f"temporal fusion | frame {frame_idx}", + ) + panels = [ + cv2.resize(panel, (480, 270), interpolation=cv2.INTER_AREA) + for panel in (raw, spatial, temporal) + ] + rows.append(np.hstack(panels)) + frame_idx += 1 + cap.release() + if rows: + cv2.imwrite(str(output_path), np.vstack(rows)) + + +def active_hand_temporal_metrics(records: list[dict], variant: str) -> dict: + values: dict[str, list[float]] = defaultdict(list) + previous: dict[tuple[int, str], tuple[int, np.ndarray]] = {} + for record in records: + for person_idx, bbox in enumerate(record["boxes"]): + kpts = normalized_keypoints( + np.asarray(record[f"{variant}_keypoints"][person_idx]), bbox + ) + meta = record[f"{variant}_metadata"][person_idx] + for side, (start, end) in HAND_SLICES.items(): + key = (person_idx, side) + if not meta[side]["distance_eligible"]: + previous.pop(key, None) + continue + prior = previous.get(key) + if prior is not None and prior[0] == record["frame_index"] - 1: + step = np.linalg.norm(kpts[start:end] - prior[1], axis=1) + values[f"P{person_idx + 1}_{side}"].extend(float(v) for v in step) + previous[key] = (record["frame_index"], kpts[start:end]) + return {name: summarize(items) for name, items in values.items()} + + +def metadata_summary(records: list[dict], variant: str) -> dict: + state_counts: Counter = Counter() + source_counts: Counter = Counter() + eligible_counts: Counter = Counter() + alarm_counts: Counter = Counter() + switches: Counter = Counter() + previous_source: dict[tuple[int, str, str], str] = {} + for record in records: + for person_idx, person_meta in enumerate(record[f"{variant}_metadata"]): + for side in ("left", "right"): + meta = person_meta[side] + key_prefix = f"P{person_idx + 1}_{side}" + state_counts[f"{key_prefix}_{meta['hand_state']}"] += 1 + source_counts[f"{key_prefix}_{meta['hand_source']}"] += 1 + if meta["distance_eligible"]: + eligible_counts[key_prefix] += 1 + if meta["alarm_eligible"]: + alarm_counts[key_prefix] += 1 + for kind in ("limb", "hand"): + source = meta[f"{kind}_source"] + key = (person_idx, side, kind) + if key in previous_source and previous_source[key] != source: + switches[f"{key_prefix}_{kind}"] += 1 + previous_source[key] = source + return { + "hand_state_counts": dict(sorted(state_counts.items())), + "source_counts": dict(sorted(source_counts.items())), + "distance_eligible_frames": dict(sorted(eligible_counts.items())), + "alarm_eligible_frames": dict(sorted(alarm_counts.items())), + "source_switches": dict(sorted(switches.items())), + } + + +def main() -> None: + args = parse_args() + args.output.mkdir(parents=True, exist_ok=True) + raw_records = [ + json.loads(line) for line in args.raw_jsonl.read_text(encoding="utf-8").splitlines() + ] + isolated_records = [ + json.loads(line) + for line in args.isolated_jsonl.read_text(encoding="utf-8").splitlines() + ] + + cap = cv2.VideoCapture(str(args.video)) + fps = float(cap.get(cv2.CAP_PROP_FPS)) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + writer = cv2.VideoWriter( + str(args.output / "rtmw_l_raw_spatial_temporal.mp4"), + cv2.VideoWriter_fourcc(*"mp4v"), + fps, + (1920, 360), + ) + + tracks = [PersonTrack(), PersonTrack()] + output_records: list[dict] = [] + frame_idx = 0 + while True: + ok, frame = cap.read() + if not ok: + break + raw_record = raw_records[frame_idx] + isolated_record = isolated_records[frame_idx] + boxes = raw_record["boxes"][:2] + raw_keypoints = np.asarray(raw_record["L"]["keypoints"][:2], dtype=np.float64) + raw_scores = np.asarray(raw_record["L"]["raw_scores"][:2], dtype=np.float64) + isolated_keypoints = np.asarray( + isolated_record["L"]["keypoints"][:2], dtype=np.float64 + ) + isolated_scores = np.asarray( + isolated_record["masked_raw_scores"][:2], dtype=np.float64 + ) + + spatial_keypoints: list[np.ndarray] = [] + spatial_metadata: list[dict] = [] + temporal_keypoints: list[np.ndarray] = [] + temporal_selected_keypoints: list[np.ndarray] = [] + temporal_metadata: list[dict] = [] + for person_idx in range(2): + spatial, spatial_meta = fuse_person( + raw_keypoints[person_idx], + raw_scores[person_idx], + isolated_keypoints[person_idx], + isolated_scores[person_idx], + boxes[person_idx], + track=None, + ) + temporal_unfiltered, temporal_meta = fuse_person( + raw_keypoints[person_idx], + raw_scores[person_idx], + isolated_keypoints[person_idx], + isolated_scores[person_idx], + boxes[person_idx], + track=tracks[person_idx], + ) + temporal = adaptive_smooth( + temporal_unfiltered, boxes[person_idx], tracks[person_idx] + ) + spatial_keypoints.append(spatial) + spatial_metadata.append(spatial_meta) + temporal_keypoints.append(temporal) + temporal_selected_keypoints.append(temporal_unfiltered) + temporal_metadata.append(temporal_meta) + + global_hands = build_global_hands( + temporal_selected_keypoints, temporal_metadata + ) + + output_record = { + "frame_index": frame_idx, + "boxes": boxes, + "raw_keypoints": np.round(raw_keypoints, 3).tolist(), + "spatial_keypoints": np.round(np.asarray(spatial_keypoints), 3).tolist(), + "spatial_metadata": spatial_metadata, + "temporal_keypoints": np.round(np.asarray(temporal_keypoints), 3).tolist(), + "temporal_selected_keypoints": np.round( + np.asarray(temporal_selected_keypoints), 3 + ).tolist(), + "temporal_metadata": temporal_metadata, + "global_hands": global_hands, + } + output_records.append(output_record) + + raw_panel = draw_pose(frame, boxes, raw_keypoints, f"RTMW-L raw | frame {frame_idx}") + spatial_panel = draw_fused( + frame, + boxes, + spatial_keypoints, + spatial_metadata, + f"spatial fusion | frame {frame_idx}", + ) + temporal_panel = draw_fused( + frame, + boxes, + temporal_keypoints, + temporal_metadata, + f"temporal fusion | frame {frame_idx}", + ) + panels = [ + cv2.resize(panel, (640, 360), interpolation=cv2.INTER_AREA) + for panel in (raw_panel, spatial_panel, temporal_panel) + ] + writer.write(np.hstack(panels)) + frame_idx += 1 + + cap.release() + writer.release() + + with (args.output / "fusion.jsonl").open("w", encoding="utf-8") as handle: + for record in output_records: + handle.write(json.dumps(record, ensure_ascii=False) + "\n") + + def comparison_records(variant: str) -> list[dict]: + return [ + { + "frame_index": record["frame_index"], + "boxes": record["boxes"], + "M": {"keypoints": record["raw_keypoints"]}, + "L": {"keypoints": record[f"{variant}_keypoints"]}, + } + for record in output_records + ] + + summary = { + "frames": len(output_records), + "fusion_policy": { + "candidates": ["RTMW-L raw", "RTMW-L smaller-person isolated"], + "selection": [ + "limb and hand selected separately", + "geometry validity", + "constant-velocity temporal consistency", + "source-switch hysteresis", + "motion-adaptive EMA in person-box coordinates", + ], + "distance_rule": ( + "Only consensus or temporally stable raw visible endpoints are eligible. " + "Inferred/conflict/rejected hands are excluded from precise distance." + ), + "alarm_rule": ( + "Alarm attack is asymmetric: a geometrically valid raw endpoint whose score " + "is clearly stronger than the isolated view is admitted immediately. Alarm " + "release should still require temporal confirmation and hysteresis." + ), + "risk_distance_note": ( + "Use global_hands and temporal_selected_keypoints (unfiltered) for alarm entry " + "to avoid smoothing delay. Use distance_eligible hands and temporal_keypoints " + "for stable reporting. When the door edge is available, a conservative " + "implementation can use the smaller of the unfiltered and smoothed distances." + ), + }, + "spatial": metadata_summary(output_records, "spatial"), + "temporal": metadata_summary(output_records, "temporal"), + "active_hand_frame_step": { + "spatial": active_hand_temporal_metrics(output_records, "spatial"), + "temporal": active_hand_temporal_metrics(output_records, "temporal"), + }, + "raw_vs_spatial_temporal_metrics": temporal_metrics(comparison_records("spatial")), + "raw_vs_temporal_temporal_metrics": temporal_metrics(comparison_records("temporal")), + "global_hand_count_frames": dict( + sorted(Counter(len(record["global_hands"]) for record in output_records).items()) + ), + "cross_person_hand_aliases_total": sum( + len(hand["aliases"]) + for record in output_records + for hand in record["global_hands"] + ), + } + with (args.output / "summary.json").open("w", encoding="utf-8") as handle: + json.dump(summary, handle, ensure_ascii=False, indent=2) + + key_frames = [0, 45, 50, 55, 120, 132, 136, 180, 240, 252, 295, 300, 304, 360, 411] + make_montage( + args.video, + output_records, + key_frames, + args.output / "rtmw_l_raw_spatial_temporal_montage.jpg", + ) + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/orin/pipeline/latest_result.py b/orin/pipeline/latest_result.py new file mode 100644 index 0000000..1ab68ae --- /dev/null +++ b/orin/pipeline/latest_result.py @@ -0,0 +1,64 @@ +"""One owned, immutable latest result, mirroring the 0920 LatestResult contract.""" +from __future__ import annotations + +from collections.abc import Mapping +import threading +from types import MappingProxyType + + +def freeze(value): + if isinstance(value, Mapping): + return MappingProxyType({key: freeze(item) for key, item in value.items()}) + if isinstance(value, (list, tuple)): + return tuple(freeze(item) for item in value) + return value + + +def result_to_dict(value): + """Return a mutable JSON-compatible copy when a consumer needs serialization.""" + if isinstance(value, Mapping): + return {key: result_to_dict(item) for key, item in value.items()} + if isinstance(value, tuple): + return [result_to_dict(item) for item in value] + return value + + +class LatestResult: + """Readers share a stable snapshot; reading never removes or acknowledges it. + + Only the latest result is retained here. Slow readers can skip frames, and + references they already hold remain valid after subsequent publications. + """ + + def __init__(self): + self._condition = threading.Condition() + self._value = None + self._closed = False + + def publish(self, result): + if result is None: + raise ValueError("Cannot publish a null result") + snapshot = freeze(result) + with self._condition: + if self._closed: + raise RuntimeError("Result publisher is closed") + self._value = snapshot + self._condition.notify_all() + + def load(self): + with self._condition: + return self._value + + def wait(self, after_frame_index=-1, timeout=None): + """Wait for a newer result; return None on timeout/end without a new frame.""" + with self._condition: + def has_new_frame(): + return self._value is not None and self._value['frame_index'] > after_frame_index + + self._condition.wait_for(lambda: has_new_frame() or self._closed, timeout) + return self._value if has_new_frame() else None + + def close(self): + with self._condition: + self._closed = True + self._condition.notify_all() diff --git a/orin/pipeline/live_pose_engine.py b/orin/pipeline/live_pose_engine.py new file mode 100644 index 0000000..b0140e5 --- /dev/null +++ b/orin/pipeline/live_pose_engine.py @@ -0,0 +1,248 @@ +"""Resident YOLO11s + RTMW-L pose stage extracted from the v9.9 pipeline.""" + +from __future__ import annotations + +import argparse +import os +import time +from collections import defaultdict +from pathlib import Path + +import numpy as np + + +SIDES = ("left", "right") + + +class LivePoseEngine: + """Run the v9.9 YOLO/RTMW pose and temporal-fusion path without EdgeTAM.""" + + def __init__(self, args: argparse.Namespace): + self._trt_dll_directory = None + if args.pose_provider == "tensorrt" and os.name == "nt": + try: + import tensorrt_libs + except ImportError as exc: + raise RuntimeError( + "--pose-provider tensorrt on Windows requires the " + "tensorrt-cu12-libs package in the active Python environment." + ) from exc + + trt_lib_dir = Path(tensorrt_libs.__file__).resolve().parent + self._trt_dll_directory = os.add_dll_directory(str(trt_lib_dir)) + os.environ["PATH"] = ( + str(trt_lib_dir) + os.pathsep + os.environ.get("PATH", "") + ) + + if args.pose_device.lower().startswith("cuda"): + import onnxruntime as ort + + if "CUDAExecutionProvider" not in ort.get_available_providers(): + raise RuntimeError( + "--pose-device cuda requires onnxruntime-gpu. Uninstall " + "onnxruntime and install onnxruntime-gpu==1.22.0." + ) + + from rtmlib import RTMPose + from ultralytics import YOLO + from predict_optimized_pose_videos import BoxTracker + + self.args = args + self.detector = YOLO(str(args.det_model)) + self.pose = RTMPose( + str(args.pose_model), + model_input_size=(288, 384), + backend="onnxruntime", + device=args.pose_device, + ) + if args.pose_provider == "tensorrt": + import onnxruntime as ort + + available = ort.get_available_providers() + if "TensorrtExecutionProvider" not in available: + raise RuntimeError( + "--pose-provider tensorrt requires ONNX Runtime with " + "TensorrtExecutionProvider. " + f"Available providers: {available}" + ) + cache_dir = args.pose_trt_cache.expanduser().resolve() + cache_dir.mkdir(parents=True, exist_ok=True) + device_id = ( + int(str(args.pose_device).split(":")[-1]) + if ":" in str(args.pose_device) + else 0 + ) + trt_options = { + "device_id": device_id, + "trt_fp16_enable": "True", + "trt_engine_cache_enable": "True", + "trt_engine_cache_path": str(cache_dir), + "trt_timing_cache_enable": "True", + "trt_timing_cache_path": str(cache_dir), + } + self.pose.session = ort.InferenceSession( + str(args.pose_model.resolve()), + providers=[ + ("TensorrtExecutionProvider", trt_options), + ("CUDAExecutionProvider", {"device_id": device_id}), + ], + ) + active_providers = self.pose.session.get_providers() + if not active_providers or active_providers[0] != "TensorrtExecutionProvider": + raise RuntimeError( + "RTMW TensorRT initialization failed instead of using the " + "requested provider. Active providers: " + f"{active_providers}" + ) + print(f"RTMW ONNX Runtime providers: {active_providers}") + + self.box_tracker = BoxTracker(max_age=30) + self.people = {} + self.timings = defaultdict(list) + self.isolated_inferences = 0 + + def infer(self, frame: np.ndarray, frame_idx: int) -> dict: + from compare_rtmw_ml import HAND_SLICES + from fuse_rtmw_l_temporal import adaptive_smooth, build_global_hands, fuse_person + from occlusion_aware_pose_v2 import Measurement, resolve_global_hand_assignments + from predict_optimized_pose_videos import ( + LivePersonState, + filter_person_boxes, + mask_other_people, + update_live_v2, + ) + + infer_started = time.perf_counter() + height, width = frame.shape[:2] + started = time.perf_counter() + detection_height = max( + 1, min(height, round(height * self.args.det_roi_y_max_ratio)) + ) + if hasattr(self, "native"): + boxes, confidences = self.native.detect(frame[:detection_height]) + self.timings["detector_ms"].append((time.perf_counter() - started) * 1000) + else: + detection = self.detector.predict( + frame[:detection_height], + imgsz=self.args.det_imgsz, + conf=self.args.det_conf, + iou=0.30, + classes=[0], + device=self.args.det_device, + verbose=False, + )[0] + self.timings["detector_ms"].append((time.perf_counter() - started) * 1000) + boxes, confidences, _ = filter_person_boxes( + detection, width, height, self.args.max_people + ) + track_ids = self.box_tracker.update(boxes, frame_idx, (height, width)) + + # Retire disappeared people in long-running camera sessions. + for stale_id in list(self.people): + if stale_id not in self.box_tracker.tracks: + del self.people[stale_id] + if boxes: + started = time.perf_counter() + raw_keypoints, raw_scores = self.pose(frame, bboxes=boxes) + self.timings["raw_pose_ms"].append((time.perf_counter() - started) * 1000) + isolated_keypoints = raw_keypoints.copy() + isolated_scores = raw_scores.copy() + started = time.perf_counter() + for person_idx, bbox in enumerate(boxes): + target_area = max((bbox[2] - bbox[0]) * (bbox[3] - bbox[1]), 1.0) + needs_isolation = any( + idx != person_idx + and max((other[2] - other[0]) * (other[3] - other[1]), 1.0) + < 0.5 * target_area + for idx, other in enumerate(boxes) + ) + if not needs_isolation: + continue + masked = mask_other_people(frame, boxes, person_idx) + keypoints, scores = self.pose(masked, bboxes=[bbox]) + isolated_keypoints[person_idx] = keypoints[0] + isolated_scores[person_idx] = scores[0] + self.isolated_inferences += 1 + self.timings["isolated_extra_ms"].append( + (time.perf_counter() - started) * 1000 + ) + else: + raw_keypoints = np.empty((0, 133, 2), dtype=np.float64) + raw_scores = np.empty((0, 133), dtype=np.float64) + isolated_keypoints = raw_keypoints.copy() + isolated_scores = raw_scores.copy() + + selected_list, smoothed_list, metadata_list, states = [], [], [], [] + for person_idx, (bbox, track_id) in enumerate(zip(boxes, track_ids)): + state = self.people.setdefault(track_id, LivePersonState()) + selected, metadata = fuse_person( + raw_keypoints[person_idx], + raw_scores[person_idx], + isolated_keypoints[person_idx], + isolated_scores[person_idx], + bbox, + state.fusion, + ) + selected_list.append(selected) + smoothed_list.append(adaptive_smooth(selected, bbox, state.fusion)) + metadata_list.append(metadata) + states.append(state) + + measurements, endpoint_tracks = {}, {} + for person_idx, (selected, metadata, state) in enumerate( + zip(selected_list, metadata_list, states) + ): + for side, (start, end) in HAND_SLICES.items(): + meta = metadata[side] + measurements[(person_idx, side)] = ( + Measurement( + keypoints=selected[start:end], + precise=bool(meta["distance_eligible"]), + provisional=not bool(meta["distance_eligible"]), + quality=float(meta.get("selected_hand_score", 0.0)), + ) + if meta["alarm_eligible"] + else None + ) + endpoint_tracks[(person_idx, side)] = state.endpoints[side] + measurements, assignments = resolve_global_hand_assignments( + measurements, endpoint_tracks, boxes, 30 + ) + + v2_list, v2_meta_list = [], [] + for person_idx, (bbox, selected, smoothed, metadata, state) in enumerate( + zip(boxes, selected_list, smoothed_list, metadata_list, states) + ): + v2, v2_meta = update_live_v2( + frame_idx, + bbox, + selected, + smoothed, + metadata, + state, + {side: measurements[(person_idx, side)] for side in SIDES}, + {side: assignments.get((person_idx, side)) for side in SIDES}, + 12, + 30, + ) + v2_list.append(v2) + v2_meta_list.append(v2_meta) + + self.timings["pose_pipeline_total_ms"].append( + (time.perf_counter() - infer_started) * 1000 + ) + return { + "frame_index": frame_idx, + "track_ids": track_ids, + "boxes": np.round(np.asarray(boxes), 3).tolist() if boxes else [], + "det_confidences": [round(value, 4) for value in confidences], + "raw_keypoints": np.round(raw_keypoints, 3).tolist(), + "temporal_selected_keypoints": np.round( + np.asarray(selected_list), 3 + ).tolist(), + "temporal_keypoints": np.round(np.asarray(smoothed_list), 3).tolist(), + "temporal_metadata": metadata_list, + "v2_keypoints": np.round(np.asarray(v2_list), 3).tolist(), + "v2_metadata": v2_meta_list, + "global_hands": build_global_hands(selected_list, metadata_list), + } diff --git a/orin/pipeline/native_backend.py b/orin/pipeline/native_backend.py new file mode 100644 index 0000000..91895f5 --- /dev/null +++ b/orin/pipeline/native_backend.py @@ -0,0 +1,75 @@ +"""Native Jetson TensorRT adapter; temporal/risk policy stays in upstream Python.""" +from __future__ import annotations +import ctypes as C +from collections import defaultdict, deque +from pathlib import Path +import numpy as np +from live_pose_engine import LivePoseEngine +from predict_optimized_pose_videos import BoxTracker + +ROOT = Path(__file__).resolve().parents[1] + +class NativeBackend: + def __init__(self, args): + self.lib = C.CDLL(str(ROOT / 'build/libvision_native.so')) + pointer = C.c_void_p + signatures = { + 'vap_error': ([], C.c_char_p), + 'vap_engine': ([C.c_char_p,C.c_int,C.c_int,C.c_int,C.c_float],pointer), + 'vap_engine_close': ([pointer],None), + 'vap_detect': ([pointer,pointer,C.c_int,C.c_int,pointer],C.c_int), + 'vap_pose': ([pointer,pointer,C.c_int,C.c_int,pointer,C.c_int,pointer],C.c_int), + 'vap_camera': ([C.c_char_p,C.c_int,C.c_int,C.c_int,C.c_int],pointer), + 'vap_camera_close': ([pointer],None), + 'vap_read': ([pointer,pointer,pointer],C.c_int), + 'vap_can': ([pointer],None), + } + for name,(inputs,output) in signatures.items(): + fn=getattr(self.lib,name);fn.argtypes=inputs;fn.restype=output + self.engine = self.lib.vap_engine(str(args.engines.resolve()).encode(),args.width,args.height,args.max_people,args.det_conf) + if not self.engine: self.fail() + self.camera=None + self.args=args + + def fail(self): + raise RuntimeError(self.lib.vap_error().decode()) + + def open_camera(self): + a=self.args + self.camera=self.lib.vap_camera(a.camera.encode(),a.width,a.height,a.fps,not a.no_can) + if not self.camera:self.fail() + + def read(self): + image=np.empty((self.args.height,self.args.width,3),np.uint8) + meta=np.zeros(4,np.float64) + result=self.lib.vap_read(self.camera,image.ctypes.data,meta.ctypes.data) + if result<0:self.fail() + if result==0:return None,None + return image,{'sequence':int(meta[0]),'capture_monotonic_ms':float(meta[1]),'dropped_before_inference':int(meta[2]),'driver_timestamp_ms':float(meta[3]),'latency_clock':'host_monotonic_at_dequeue'} + + def can_snapshot(self): + data=np.zeros(5,np.float64);self.lib.vap_can(data.ctypes.data) + return {'positions':[int(x) for x in data[:4]],'age_ms':float(data[4])} + + def detect(self, frame): + frame=np.ascontiguousarray(frame);out=np.empty((self.args.max_people,5),np.float32) + n=self.lib.vap_detect(self.engine,frame.ctypes.data,frame.shape[1],frame.shape[0],out.ctypes.data) + if n<0:self.fail() + return out[:n,:4].tolist(),out[:n,4].tolist() + + def pose(self,frame,bboxes): + frame=np.ascontiguousarray(frame);boxes=np.ascontiguousarray(bboxes,dtype=np.float32) + out=np.empty((len(boxes),133,3),np.float32) + n=self.lib.vap_pose(self.engine,frame.ctypes.data,frame.shape[1],frame.shape[0],boxes.ctypes.data,len(boxes),out.ctypes.data) + if n<0:self.fail() + return out[:n,:,:2].astype(np.float64),out[:n,:,2].astype(np.float64) + + def close(self): + if self.camera:self.lib.vap_camera_close(self.camera);self.camera=None + if self.engine:self.lib.vap_engine_close(self.engine);self.engine=None + +class NativePoseEngine(LivePoseEngine): + def __init__(self,args,native): + self.args=args;self.native=native;self.pose=native.pose + self.box_tracker=BoxTracker(max_age=30);self.people={} + self.timings=defaultdict(lambda:deque(maxlen=3000));self.isolated_inferences=0 diff --git a/orin/pipeline/occlusion_aware_pose_v2.py b/orin/pipeline/occlusion_aware_pose_v2.py new file mode 100644 index 0000000..5b7c73f --- /dev/null +++ b/orin/pipeline/occlusion_aware_pose_v2.py @@ -0,0 +1,1130 @@ +"""Occlusion-aware temporal pose reconstruction on top of RTMW-L fusion. + +Visible endpoints are filtered and optionally connected with a two-bone IK +solution. Short gaps are interpolated/predicted, medium gaps use a local motion +corridor, and long occlusions retain an undrawn shoulder sector for downstream +door-band intersection instead of emitting a fake precise wrist. +""" + +from __future__ import annotations + +import argparse +import json +import math +from collections import Counter, defaultdict +from dataclasses import dataclass +from pathlib import Path + +import cv2 +import numpy as np + +from compare_rtmw_ml import HAND_EDGES_LOCAL, HAND_SLICES, normalized_keypoints, summarize +from fuse_rtmw_l_temporal import BODY_SIDE_INDICES, draw_dashed_line, draw_fused + + +STATE_COLORS = { + "observed": (40, 220, 40), + "provisional": (255, 190, 40), + "recovered": (220, 180, 40), + "reassigned": (220, 120, 40), + "interpolated": (0, 220, 255), + "predicted_short": (0, 140, 255), + "reachable_medium": (0, 120, 255), + "reachable_long": (30, 80, 255), +} + + +@dataclass +class Measurement: + keypoints: np.ndarray + precise: bool + provisional: bool + source: str = "model" + quality: float = 0.0 + + +@dataclass +class EndpointTrack: + wrist: np.ndarray | None = None + velocity: np.ndarray | None = None + hand_shape: np.ndarray | None = None + last_observed_frame: int | None = None + missed_frames: int = 0 + last_elbow: np.ndarray | None = None + last_direction: np.ndarray | None = None + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--video", type=Path, required=True) + parser.add_argument("--fusion-jsonl", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument("--short-occlusion-frames", type=int, default=12) + parser.add_argument("--medium-occlusion-frames", type=int, default=30) + parser.add_argument("--lookahead-frames", type=int, default=3) + return parser.parse_args() + + +def bbox_diagonal(bbox: list[float]) -> float: + return max(math.hypot(bbox[2] - bbox[0], bbox[3] - bbox[1]), 1.0) + + +def point_distance_ratio(a: np.ndarray, b: np.ndarray, bbox: list[float]) -> float: + return float(np.linalg.norm(a - b)) / bbox_diagonal(bbox) + + +def collect_measurements( + records: list[dict], + person_idx: int, + side: str, + lookahead_frames: int, +) -> list[Measurement | None]: + start, end = HAND_SLICES[side] + measurements: list[Measurement | None] = [None] * len(records) + observed_frames = [] + for frame_idx, record in enumerate(records): + meta = record["temporal_metadata"][person_idx][side] + if not meta["alarm_eligible"]: + continue + keypoints = np.asarray( + record["temporal_selected_keypoints"][person_idx][start:end], + dtype=np.float64, + ) + measurements[frame_idx] = Measurement( + keypoints=keypoints, + precise=bool(meta["distance_eligible"]), + provisional=not bool(meta["distance_eligible"]), + quality=float(meta.get("selected_hand_score", 0.0)), + ) + observed_frames.append(frame_idx) + + # A small future window is allowed for stable reporting. The alarm fast + # path still uses the unmodified current-frame candidates from V1. + for left, right in zip(observed_frames, observed_frames[1:]): + gap = right - left - 1 + if gap <= 0 or gap > lookahead_frames: + continue + left_points = measurements[left].keypoints + right_points = measurements[right].keypoints + for offset in range(1, gap + 1): + ratio = offset / (gap + 1) + points = (1.0 - ratio) * left_points + ratio * right_points + measurements[left + offset] = Measurement( + keypoints=points, + precise=False, + provisional=False, + source="fixed_lag_interpolation", + quality=min(measurements[left].quality, measurements[right].quality), + ) + return measurements + + +def estimate_bone_ratios(records: list[dict]) -> dict[tuple[int, str], tuple[float, float]]: + values: dict[tuple[int, str], list[tuple[float, float]]] = defaultdict(list) + for record in records: + for person_idx, bbox in enumerate(record["boxes"]): + keypoints = np.asarray( + record["temporal_selected_keypoints"][person_idx], dtype=np.float64 + ) + diagonal = bbox_diagonal(bbox) + for side, (shoulder, elbow, wrist) in BODY_SIDE_INDICES.items(): + meta = record["temporal_metadata"][person_idx][side] + if meta["limb_state"] != "consensus": + continue + upper = float(np.linalg.norm(keypoints[shoulder] - keypoints[elbow])) / diagonal + forearm = float(np.linalg.norm(keypoints[elbow] - keypoints[wrist])) / diagonal + if 0.04 <= upper <= 0.65 and 0.04 <= forearm <= 0.65: + values[(person_idx, side)].append((upper, forearm)) + + estimates: dict[tuple[int, str], tuple[float, float]] = {} + person_count = len(records[0]["boxes"]) + for person_idx in range(person_count): + for side in ("left", "right"): + samples = values[(person_idx, side)] + if len(samples) < 20: + opposite = "right" if side == "left" else "left" + samples = values[(person_idx, opposite)] + if samples: + array = np.asarray(samples) + estimates[(person_idx, side)] = ( + float(np.median(array[:, 0])), + float(np.median(array[:, 1])), + ) + else: + estimates[(person_idx, side)] = (0.24, 0.22) + return estimates + + +def solve_two_bone_elbow( + shoulder: np.ndarray, + wrist: np.ndarray, + upper_length: float, + forearm_length: float, + reference_elbow: np.ndarray, +) -> np.ndarray: + direction = wrist - shoulder + distance = float(np.linalg.norm(direction)) + if distance < 1e-6: + return reference_elbow.copy() + unit = direction / distance + + if distance >= upper_length + forearm_length: + return shoulder + unit * upper_length + if distance <= abs(upper_length - forearm_length): + sign = 1.0 if upper_length >= forearm_length else -1.0 + return shoulder + unit * upper_length * sign + + along = ( + upper_length * upper_length + - forearm_length * forearm_length + + distance * distance + ) / (2.0 * distance) + height = math.sqrt(max(upper_length * upper_length - along * along, 0.0)) + base = shoulder + unit * along + perpendicular = np.asarray([-unit[1], unit[0]]) + candidates = (base + perpendicular * height, base - perpendicular * height) + return min(candidates, key=lambda candidate: float(np.linalg.norm(candidate - reference_elbow))) + + +def update_endpoint_track( + track: EndpointTrack, + measurement: Measurement | None, + frame_idx: int, + short_occlusion_frames: int, + medium_occlusion_frames: int, +) -> tuple[np.ndarray | None, np.ndarray | None, str]: + if measurement is not None: + measured_wrist = measurement.keypoints[0] + measured_shape = measurement.keypoints - measured_wrist + if track.wrist is None or track.missed_frames > short_occlusion_frames: + track.wrist = measured_wrist.copy() + track.velocity = np.zeros(2, dtype=np.float64) + track.hand_shape = measured_shape.copy() + else: + prediction = track.wrist + track.velocity + residual = measured_wrist - prediction + alpha = 0.78 if measurement.precise else 0.88 + beta = 0.18 if measurement.precise else 0.24 + track.wrist = prediction + alpha * residual + track.velocity = 0.82 * track.velocity + beta * residual + shape_alpha = 0.55 if measurement.precise else 0.7 + track.hand_shape = ( + shape_alpha * measured_shape + (1.0 - shape_alpha) * track.hand_shape + ) + track.last_observed_frame = frame_idx + track.missed_frames = 0 + if measurement.source == "global_reassignment": + state = "reassigned" + elif measurement.source == "temporal_recovery": + state = "recovered" + elif measurement.precise: + state = "observed" + elif measurement.provisional: + state = "provisional" + else: + state = "interpolated" + return track.wrist.copy(), track.wrist + track.hand_shape, state + + track.missed_frames += 1 + if track.wrist is None: + return None, None, "reachable_long" + if track.missed_frames <= short_occlusion_frames: + track.wrist = track.wrist + track.velocity + track.velocity *= 0.86 + return track.wrist.copy(), track.wrist + track.hand_shape, "predicted_short" + if track.missed_frames <= medium_occlusion_frames: + return None, None, "reachable_medium" + return None, None, "reachable_long" + + +def temporal_recovery_measurement( + keypoints: np.ndarray, + metadata: dict, + side: str, + bbox: list[float], + track: EndpointTrack, + medium_occlusion_frames: int, +) -> Measurement | None: + """Recover a weak current-frame hand only when history strongly supports it.""" + if track.wrist is None or track.missed_frames > medium_occlusion_frames: + return None + if metadata.get("hand_state") not in {"conflict", "inferred"}: + return None + if not metadata.get("selected_hand_valid", False): + return None + if float(metadata.get("selected_hand_score", 0.0)) < 2.0: + return None + link = float(metadata.get("hand_selection", {}).get("link_to_selected_limb", 1.0)) + if link > 0.08: + return None + + start, end = HAND_SLICES[side] + hand = np.asarray(keypoints[start:end], dtype=np.float64) + if hand.shape != (end - start, 2) or not np.isfinite(hand).all(): + return None + prediction = track.wrist + track.velocity + diagonal = bbox_diagonal(bbox) + gate = min(0.20, 0.05 + 0.008 * max(track.missed_frames, 1)) * diagonal + if float(np.linalg.norm(hand[0] - prediction)) > gate: + return None + return Measurement( + keypoints=hand, + precise=False, + provisional=True, + source="temporal_recovery", + quality=float(metadata.get("selected_hand_score", 0.0)), + ) + + +def hand_span_px(hand: np.ndarray) -> float: + return math.hypot(float(np.ptp(hand[:, 0])), float(np.ptp(hand[:, 1]))) + + +def bbox_area(bbox: list[float]) -> float: + return max((bbox[2] - bbox[0]) * (bbox[3] - bbox[1]), 1.0) + + +def reset_endpoint_track(track: EndpointTrack) -> None: + track.wrist = None + track.velocity = None + track.hand_shape = None + track.last_observed_frame = None + track.missed_frames = 0 + track.last_elbow = None + track.last_direction = None + + +def resolve_global_hand_assignments( + frame_measurements: dict[tuple[int, str], Measurement | None], + tracks: dict[tuple[int, str], EndpointTrack], + boxes: list[list[float]], + medium_occlusion_frames: int, +) -> tuple[dict[tuple[int, str], Measurement | None], dict[tuple[int, str], dict]]: + """Resolve overlapping-person hands before binding them to body sides. + + Large foreground top-down crops may include a smaller background person. + The same physical hand can therefore be emitted for both people, or only by + the smaller crop even though it belongs to the foreground person. Direct + duplicates are kept on the foreground track when their apparent scales + agree. A missing foreground side can then reclaim a nearby candidate using + its recent hand trajectory and historical hand scale. + """ + resolved = dict(frame_measurements) + events: dict[tuple[int, str], dict] = {} + keys = list(resolved) + + # First collapse direct cross-person duplicates. Keep this deliberately + # asymmetric: a substantially larger foreground crop must also carry the + # substantially larger historical hand shape. + for index, first_key in enumerate(keys): + first = resolved[first_key] + if first is None: + continue + for second_key in keys[index + 1 :]: + second = resolved[second_key] + if second is None or first_key[0] == second_key[0]: + continue + first_hand = first.keypoints + second_hand = second.keypoints + first_span = hand_span_px(first_hand) + second_span = hand_span_px(second_hand) + center_distance = float( + np.linalg.norm(np.mean(first_hand, axis=0) - np.mean(second_hand, axis=0)) + ) + if center_distance > max(70.0, 0.5 * max(first_span, second_span)): + continue + + first_area = bbox_area(boxes[first_key[0]]) + second_area = bbox_area(boxes[second_key[0]]) + if first_area >= 2.5 * second_area and ( + first_span >= 1.45 * second_span + or first.quality >= second.quality + 0.6 + ): + owner_key, released_key = first_key, second_key + elif second_area >= 2.5 * first_area and ( + second_span >= 1.45 * first_span + or second.quality >= first.quality + 0.6 + ): + owner_key, released_key = second_key, first_key + else: + continue + resolved[released_key] = None + reset_endpoint_track(tracks[released_key]) + events[owner_key] = { + "method": "foreground_duplicate_owner", + "released_person_id": released_key[0] + 1, + "released_side": released_key[1], + } + events[released_key] = { + "method": "reassigned_away", + "assigned_person_id": owner_key[0] + 1, + "assigned_side": owner_key[1], + } + + # Then recover missing foreground hands from another crop. The candidate + # must fall inside the target's recent motion gate and be much smaller than + # the target's historical foreground hand shape. + available_sources = [key for key, value in resolved.items() if value is not None] + target_candidates = [] + for target_key, target_measurement in resolved.items(): + if target_measurement is not None: + continue + target_track = tracks[target_key] + if ( + target_track.wrist is None + or target_track.hand_shape is None + or target_track.missed_frames > medium_occlusion_frames + ): + continue + target_area = bbox_area(boxes[target_key[0]]) + predicted_center = target_track.wrist + np.mean(target_track.hand_shape, axis=0) + target_span = hand_span_px(target_track.hand_shape) + gate = 0.20 * bbox_diagonal(boxes[target_key[0]]) + for source_key in available_sources: + if source_key[0] == target_key[0]: + continue + source = resolved[source_key] + if source is None or source.source != "model": + continue + source_area = bbox_area(boxes[source_key[0]]) + if target_area < 2.5 * source_area: + continue + source_center = np.mean(source.keypoints, axis=0) + source_span = hand_span_px(source.keypoints) + distance = float(np.linalg.norm(source_center - predicted_center)) + if distance > gate or target_span < 1.45 * max(source_span, 1.0): + continue + target_candidates.append( + (distance / gate, target_key, source_key, source_center) + ) + + used_targets = set() + used_sources = set() + for _, target_key, source_key, source_center in sorted(target_candidates): + if target_key in used_targets or source_key in used_sources: + continue + target_track = tracks[target_key] + shape_center = np.mean(target_track.hand_shape, axis=0) + reassigned_wrist = source_center - shape_center + reassigned_hand = reassigned_wrist + target_track.hand_shape + resolved[target_key] = Measurement( + keypoints=reassigned_hand, + precise=False, + provisional=True, + source="global_reassignment", + quality=resolved[source_key].quality, + ) + resolved[source_key] = None + reset_endpoint_track(tracks[source_key]) + events[target_key] = { + "method": "foreground_temporal_reassignment", + "source_person_id": source_key[0] + 1, + "source_side": source_key[1], + "observed_center": np.round(source_center, 3).tolist(), + } + events[source_key] = { + "method": "reassigned_away", + "assigned_person_id": target_key[0] + 1, + "assigned_side": target_key[1], + } + used_targets.add(target_key) + used_sources.add(source_key) + return resolved, events + + +def track_direction(track: EndpointTrack) -> np.ndarray: + if track.last_direction is not None: + return track.last_direction / max(float(np.linalg.norm(track.last_direction)), 1e-6) + if track.velocity is not None and float(np.linalg.norm(track.velocity)) > 1e-6: + return track.velocity / np.linalg.norm(track.velocity) + return np.asarray([1.0, 0.0], dtype=np.float64) + + +def ellipse_polygon( + center: np.ndarray, + major_axis: float, + minor_axis: float, + direction: np.ndarray, + point_count: int = 64, +) -> np.ndarray: + perpendicular = np.asarray([-direction[1], direction[0]], dtype=np.float64) + angles = np.linspace(0.0, 2.0 * math.pi, point_count, endpoint=False) + return ( + center + + np.cos(angles)[:, None] * major_axis * direction + + np.sin(angles)[:, None] * minor_axis * perpendicular + ) + + +def clip_polygon_from_anchor_to_circle( + points: np.ndarray, + anchor: np.ndarray, + circle_center: np.ndarray, + radius: float, +) -> np.ndarray: + """Clip radial polygon samples to a shoulder-centered anatomical limit.""" + clipped = [] + offset = anchor - circle_center + for point in points: + if float(np.linalg.norm(point - circle_center)) <= radius: + clipped.append(point) + continue + ray = point - anchor + a = float(np.dot(ray, ray)) + b = 2.0 * float(np.dot(offset, ray)) + c = float(np.dot(offset, offset) - radius * radius) + discriminant = max(b * b - 4.0 * a * c, 0.0) + roots = [ + value + for value in ( + (-b - math.sqrt(discriminant)) / max(2.0 * a, 1e-6), + (-b + math.sqrt(discriminant)) / max(2.0 * a, 1e-6), + ) + if 0.0 <= value <= 1.0 + ] + clipped.append(anchor + (max(roots) if roots else 0.0) * ray) + return np.asarray(clipped, dtype=np.float64) + + +def medium_motion_region( + shoulder: np.ndarray, + upper_length: float, + forearm_length: float, + bbox: list[float], + track: EndpointTrack, + short_occlusion_frames: int, +) -> dict: + diagonal = bbox_diagonal(bbox) + direction = track_direction(track) + hand_shape = ( + track.hand_shape + if track.hand_shape is not None + else np.zeros((21, 2), dtype=np.float64) + ) + shape_center = np.mean(hand_shape, axis=0) + centered_shape = hand_shape - shape_center + perpendicular = np.asarray([-direction[1], direction[0]], dtype=np.float64) + hand_major = float(np.max(np.abs(centered_shape @ direction))) + hand_minor = float(np.max(np.abs(centered_shape @ perpendicular))) + + extra_frames = max(track.missed_frames - short_occlusion_frames, 1) + motion_major = min(0.20, 0.04 + 0.007 * extra_frames) * diagonal + motion_minor = min(0.13, 0.03 + 0.0045 * extra_frames) * diagonal + major_axis = max(hand_major + motion_major, 0.08 * diagonal) + minor_axis = max(hand_minor + motion_minor, 0.06 * diagonal) + + center = track.wrist + shape_center + tracked_hand_extent = float(np.max(np.linalg.norm(centered_shape, axis=1))) + hand_reach = max(tracked_hand_extent, 0.10 * diagonal) + anatomical_reach = upper_length + forearm_length + hand_reach + 0.02 * diagonal + shoulder_to_center = center - shoulder + center_distance = float(np.linalg.norm(shoulder_to_center)) + if center_distance > 0.96 * anatomical_reach: + center = shoulder + shoulder_to_center / center_distance * 0.96 * anatomical_reach + + polygon = ellipse_polygon(center, major_axis, minor_axis, direction) + polygon = clip_polygon_from_anchor_to_circle( + polygon, + center, + shoulder, + anatomical_reach, + ) + direction_deg = math.degrees(math.atan2(float(direction[1]), float(direction[0]))) + return { + "geometry": "motion_corridor", + "center": np.round(center, 3).tolist(), + "predicted_wrist": np.round(track.wrist, 3).tolist(), + "major_axis_px": round(major_axis, 3), + "minor_axis_px": round(minor_axis, 3), + "outer_radius_px": round(major_axis, 3), + "direction_deg": round(direction_deg, 3), + "max_reach_from_shoulder_px": round(anatomical_reach, 3), + "polygon": np.round(polygon, 3).tolist(), + "requires_door_intersection": True, + "render_full_region": True, + "distance_lower_bound_rule": "minimum distance from motion-corridor polygon to door_edge", + } + + +def long_reachable_region( + shoulder: np.ndarray, + upper_length: float, + forearm_length: float, + bbox: list[float], + track: EndpointTrack, + medium_occlusion_frames: int, +) -> dict: + diagonal = bbox_diagonal(bbox) + height = max(bbox[3] - bbox[1], 1.0) + arm_reach = upper_length + forearm_length + hand_reach = min(0.13 * diagonal, 0.17 * height) + safety_margin = 0.025 * diagonal + outer_radius = arm_reach + hand_reach + safety_margin + inner_radius = max(abs(upper_length - forearm_length) - 0.04 * diagonal, 0.0) + if track.last_direction is None: + direction_deg = 0.0 + half_angle_deg = 180.0 + else: + direction = track_direction(track) + direction_deg = math.degrees(math.atan2(float(direction[1]), float(direction[0]))) + half_angle_deg = min( + 180.0, + 65.0 + 2.0 * max(track.missed_frames - medium_occlusion_frames, 0), + ) + return { + "geometry": "shoulder_sector", + "center": np.round(shoulder, 3).tolist(), + "inner_radius_px": round(inner_radius, 3), + "outer_radius_px": round(outer_radius, 3), + "arm_reach_px": round(arm_reach, 3), + "hand_reach_px": round(hand_reach, 3), + "safety_margin_px": round(safety_margin, 3), + "direction_deg": round(direction_deg, 3), + "half_angle_deg": round(half_angle_deg, 3), + "requires_door_intersection": True, + "render_full_region": False, + "distance_lower_bound_rule": "intersect shoulder sector with door danger band before alarming", + } + + +def reachable_region( + shoulder: np.ndarray, + upper_length: float, + forearm_length: float, + bbox: list[float], + track: EndpointTrack, + state: str = "reachable_long", + short_occlusion_frames: int = 12, + medium_occlusion_frames: int = 30, +) -> dict: + if state == "reachable_medium" and track.wrist is not None: + return medium_motion_region( + shoulder, + upper_length, + forearm_length, + bbox, + track, + short_occlusion_frames, + ) + return long_reachable_region( + shoulder, + upper_length, + forearm_length, + bbox, + track, + medium_occlusion_frames, + ) + + +def calibrated_bone_lengths( + upper_ratio: float, + forearm_ratio: float, + bbox: list[float], +) -> tuple[float, float]: + diagonal = bbox_diagonal(bbox) + height = max(bbox[3] - bbox[1], 1.0) + upper = upper_ratio * diagonal + forearm = forearm_ratio * diagonal + total = upper + forearm + # Keep only a loose sanity cap. The previous 0.55 * bbox-height cap was + # unsafe for close, clipped CMS views: a valid projected arm can occupy + # almost the full detection height. The ratios are already robust medians, + # so this cap only limits catastrophic calibration outliers. + maximum_total = 0.95 * diagonal + if total > maximum_total: + scale = maximum_total / total + upper *= scale + forearm *= scale + return upper, forearm + + +def process_sequence( + records: list[dict], + short_occlusion_frames: int, + medium_occlusion_frames: int, + lookahead_frames: int, +) -> list[dict]: + person_count = len(records[0]["boxes"]) + measurements = { + (person_idx, side): collect_measurements( + records, person_idx, side, lookahead_frames + ) + for person_idx in range(person_count) + for side in ("left", "right") + } + bone_ratios = estimate_bone_ratios(records) + tracks = { + (person_idx, side): EndpointTrack() + for person_idx in range(person_count) + for side in ("left", "right") + } + + output = [] + for frame_idx, record in enumerate(records): + boxes = record["boxes"] + base_keypoints = np.asarray(record["temporal_keypoints"], dtype=np.float64) + unfiltered_keypoints = np.asarray( + record["temporal_selected_keypoints"], dtype=np.float64 + ) + v2_keypoints = base_keypoints.copy() + frame_measurements = { + (person_idx, side): measurements[(person_idx, side)][frame_idx] + for person_idx in range(person_count) + for side in ("left", "right") + } + frame_measurements, assignment_events = resolve_global_hand_assignments( + frame_measurements, + tracks, + boxes, + medium_occlusion_frames, + ) + people_meta = [] + for person_idx, bbox in enumerate(boxes): + diagonal = bbox_diagonal(bbox) + person_meta = {} + for side, (shoulder_idx, elbow_idx, wrist_idx) in BODY_SIDE_INDICES.items(): + track = tracks[(person_idx, side)] + measurement = frame_measurements[(person_idx, side)] + if measurement is None: + measurement = temporal_recovery_measurement( + unfiltered_keypoints[person_idx], + record["temporal_metadata"][person_idx][side], + side, + bbox, + track, + medium_occlusion_frames, + ) + returning_after_long_occlusion = ( + measurement is not None + and track.missed_frames > short_occlusion_frames + ) + wrist, hand, state = update_endpoint_track( + track, + measurement, + frame_idx, + short_occlusion_frames, + medium_occlusion_frames, + ) + shoulder = base_keypoints[person_idx, shoulder_idx] + upper_ratio, forearm_ratio = bone_ratios[(person_idx, side)] + upper_length, forearm_length = calibrated_bone_lengths( + upper_ratio, forearm_ratio, bbox + ) + reachable = None + + if wrist is not None and hand is not None: + reference_elbow = ( + unfiltered_keypoints[person_idx, elbow_idx] + if returning_after_long_occlusion or track.last_elbow is None + else track.last_elbow + ) + use_ik = ( + record["temporal_metadata"][person_idx][side]["limb_state"] + != "consensus" + or state in ( + "provisional", + "recovered", + "reassigned", + "interpolated", + "predicted_short", + ) + ) + if use_ik: + elbow = solve_two_bone_elbow( + shoulder, + wrist, + upper_length, + forearm_length, + reference_elbow, + ) + else: + elbow = base_keypoints[person_idx, elbow_idx] + track.last_elbow = elbow.copy() + direction = wrist - shoulder + if float(np.linalg.norm(direction)) > 1e-6: + track.last_direction = direction / np.linalg.norm(direction) + + v2_keypoints[person_idx, shoulder_idx] = shoulder + v2_keypoints[person_idx, elbow_idx] = elbow + v2_keypoints[person_idx, wrist_idx] = wrist + start, end = HAND_SLICES[side] + v2_keypoints[person_idx, start:end] = hand + uncertainty_radius = ( + 0.025 * diagonal + if state == "observed" + else (0.04 + 0.015 * track.missed_frames) * diagonal + ) + precise_distance = state == "observed" + fast_alarm = state in ( + "observed", + "provisional", + "reassigned", + "interpolated", + "predicted_short", + ) + else: + reachable = reachable_region( + shoulder, + upper_length, + forearm_length, + bbox, + track, + state, + short_occlusion_frames, + medium_occlusion_frames, + ) + uncertainty_radius = reachable["outer_radius_px"] + precise_distance = False + fast_alarm = True + + person_meta[side] = { + "state": state, + "precise_distance": precise_distance, + "fast_alarm_candidate": fast_alarm, + "risk_mode": ( + "precise_hand" + if state == "observed" + else ( + "motion_corridor_intersection" + if state == "reachable_medium" + else ( + "door_intersection_only" + if state == "reachable_long" + else ( + "reassigned_hand" + if state == "reassigned" + else "temporal_hand" + ) + ) + ) + ), + "requires_door_intersection": state + in ("reachable_medium", "reachable_long"), + "missed_frames": track.missed_frames, + "uncertainty_radius_px": round(float(uncertainty_radius), 3), + "bone_lengths_px": { + "upper": round(upper_length, 3), + "forearm": round(forearm_length, 3), + }, + "identity_assignment": assignment_events.get( + (person_idx, side) + ), + "reachable_region": reachable, + } + people_meta.append(person_meta) + + output.append( + { + "frame_index": frame_idx, + "boxes": boxes, + "v1_keypoints": record["temporal_keypoints"], + "v1_metadata": record["temporal_metadata"], + "v2_keypoints": np.round(v2_keypoints, 3).tolist(), + "v2_metadata": people_meta, + } + ) + return output + + +def sector_points(region: dict) -> np.ndarray: + center = np.asarray(region["center"], dtype=np.float64) + direction = region["direction_deg"] + half_angle = region["half_angle_deg"] + angles = np.linspace(direction - half_angle, direction + half_angle, 48) + radius = region["outer_radius_px"] + arc = np.column_stack( + [ + center[0] + radius * np.cos(np.deg2rad(angles)), + center[1] + radius * np.sin(np.deg2rad(angles)), + ] + ) + if half_angle < 179.0: + return np.vstack([center, arc, center]).astype(np.int32) + return arc.astype(np.int32) + + +def draw_v2( + image: np.ndarray, + boxes: list[list[float]], + keypoints: np.ndarray, + metadata: list[dict], + title: str, + show_reachable: bool = True, +) -> np.ndarray: + canvas = image.copy() + overlay = canvas.copy() + for person_idx, (bbox, kpts, person_meta) in enumerate( + zip(boxes, keypoints, metadata), start=1 + ): + x1, y1, x2, y2 = (int(round(value)) for value in bbox) + cv2.rectangle(canvas, (x1, y1), (x2, y2), (0, 220, 255), 2) + cv2.putText( + canvas, + f"P{person_idx}", + (x1 + 4, max(22, y1 + 24)), + cv2.FONT_HERSHEY_SIMPLEX, + 0.72, + (0, 220, 255), + 2, + cv2.LINE_AA, + ) + for side, (shoulder, elbow, wrist) in BODY_SIDE_INDICES.items(): + meta = person_meta[side] + state = meta["state"] + color = STATE_COLORS[state] + if state in ("reachable_medium", "reachable_long"): + region = meta["reachable_region"] + if state == "reachable_medium": + if show_reachable: + polygon = np.round(region["polygon"]).astype(np.int32) + cv2.fillPoly(overlay, [polygon], color) + cv2.polylines(canvas, [polygon], True, color, 3, cv2.LINE_AA) + center = tuple(np.round(region["center"]).astype(int)) + wrist_point = tuple( + np.round(region["predicted_wrist"]).astype(int) + ) + cv2.line(canvas, center, wrist_point, color, 2, cv2.LINE_AA) + label = f"{side[0].upper()}:corridor" + else: + center = tuple(np.round(region["center"]).astype(int)) + cv2.circle(canvas, center, 8, color, 2, cv2.LINE_AA) + if region["half_angle_deg"] >= 179.0: + cv2.putText( + canvas, + "?", + (center[0] + 11, center[1] + 9), + cv2.FONT_HERSHEY_SIMPLEX, + 0.65, + color, + 2, + cv2.LINE_AA, + ) + else: + direction = math.radians(region["direction_deg"]) + direction_end = ( + int(round(center[0] + 55 * math.cos(direction))), + int(round(center[1] + 55 * math.sin(direction))), + ) + cv2.arrowedLine( + canvas, + center, + direction_end, + color, + 2, + cv2.LINE_AA, + tipLength=0.25, + ) + if show_reachable and region.get("render_full_region", False): + polygon = sector_points(region) + if region["half_angle_deg"] < 179.0: + cv2.fillPoly(overlay, [polygon], color) + cv2.polylines( + canvas, [polygon], True, color, 3, cv2.LINE_AA + ) + else: + radius = int(round(region["outer_radius_px"])) + cv2.circle(canvas, center, radius, color, 3, cv2.LINE_AA) + label = f"{side[0].upper()}:unknown" + else: + thickness = 3 + if state in ("reassigned", "recovered"): + draw_dashed_line( + canvas, + kpts[shoulder], + kpts[elbow], + color, + thickness, + ) + draw_dashed_line( + canvas, + kpts[elbow], + kpts[wrist], + color, + thickness, + ) + else: + cv2.line( + canvas, + tuple(np.round(kpts[shoulder]).astype(int)), + tuple(np.round(kpts[elbow]).astype(int)), + color, + thickness, + cv2.LINE_AA, + ) + cv2.line( + canvas, + tuple(np.round(kpts[elbow]).astype(int)), + tuple(np.round(kpts[wrist]).astype(int)), + color, + thickness, + cv2.LINE_AA, + ) + start, end = HAND_SLICES[side] + hand = kpts[start:end] + for a, b in HAND_EDGES_LOCAL: + cv2.line( + canvas, + tuple(np.round(hand[a]).astype(int)), + tuple(np.round(hand[b]).astype(int)), + color, + 2, + cv2.LINE_AA, + ) + label = f"{side[0].upper()}:{state[:5]}" + cv2.putText( + canvas, + label, + (x1 + 4, max(45, y1 + (48 if side == "left" else 70))), + cv2.FONT_HERSHEY_SIMPLEX, + 0.48, + color, + 1, + cv2.LINE_AA, + ) + canvas = cv2.addWeighted(overlay, 0.06, canvas, 0.94, 0.0) + cv2.rectangle(canvas, (0, 0), (670, 45), (0, 0, 0), -1) + cv2.putText( + canvas, + title, + (10, 31), + cv2.FONT_HERSHEY_SIMPLEX, + 0.8, + (255, 255, 255), + 2, + cv2.LINE_AA, + ) + return canvas + + +def endpoint_metrics(records: list[dict]) -> dict: + states: Counter = Counter() + assignments: Counter = Counter() + steps: dict[str, list[float]] = defaultdict(list) + previous: dict[tuple[int, str], tuple[int, np.ndarray]] = {} + for record in records: + for person_idx, bbox in enumerate(record["boxes"]): + kpts = np.asarray(record["v2_keypoints"][person_idx], dtype=np.float64) + for side, (_, _, wrist) in BODY_SIDE_INDICES.items(): + meta = record["v2_metadata"][person_idx][side] + key_name = f"P{person_idx + 1}_{side}" + states[f"{key_name}_{meta['state']}"] += 1 + identity_assignment = meta.get("identity_assignment") + if identity_assignment is not None: + assignments[identity_assignment["method"]] += 1 + if meta["state"] in ("reachable_medium", "reachable_long"): + previous.pop((person_idx, side), None) + continue + normalized = normalized_keypoints(kpts, bbox)[wrist] + prior = previous.get((person_idx, side)) + if prior is not None and prior[0] == record["frame_index"] - 1: + steps[key_name].append(float(np.linalg.norm(normalized - prior[1]))) + previous[(person_idx, side)] = (record["frame_index"], normalized) + return { + "state_counts": dict(sorted(states.items())), + "identity_assignment_counts": dict(sorted(assignments.items())), + "wrist_frame_step": {name: summarize(items) for name, items in steps.items()}, + } + + +def write_video_and_montage( + video_path: Path, + records: list[dict], + output_dir: Path, +) -> None: + cap = cv2.VideoCapture(str(video_path)) + fps = float(cap.get(cv2.CAP_PROP_FPS)) + writer = cv2.VideoWriter( + str(output_dir / "rtmw_l_temporal_v1_vs_occlusion_v4.mp4"), + cv2.VideoWriter_fourcc(*"mp4v"), + fps, + (1920, 540), + ) + key_frames = {0, 50, 120, 126, 132, 138, 180, 211, 220, 240, 252, + 292, 296, 300, 304, 320, 360, 411} + montage_rows = [] + frame_idx = 0 + while True: + ok, frame = cap.read() + if not ok: + break + record = records[frame_idx] + v1 = draw_fused( + frame, + record["boxes"], + [np.asarray(points) for points in record["v1_keypoints"]], + record["v1_metadata"], + f"temporal fusion V1 | frame {frame_idx}", + ) + v2 = draw_v2( + frame, + record["boxes"], + np.asarray(record["v2_keypoints"]), + record["v2_metadata"], + f"occlusion V4 global assignment | frame {frame_idx}", + ) + left = cv2.resize(v1, (960, 540), interpolation=cv2.INTER_AREA) + right = cv2.resize(v2, (960, 540), interpolation=cv2.INTER_AREA) + writer.write(np.hstack([left, right])) + if frame_idx in key_frames: + montage_rows.append( + np.hstack( + [ + cv2.resize(v1, (640, 360), interpolation=cv2.INTER_AREA), + cv2.resize(v2, (640, 360), interpolation=cv2.INTER_AREA), + ] + ) + ) + frame_idx += 1 + cap.release() + writer.release() + cv2.imwrite( + str(output_dir / "rtmw_l_temporal_v1_vs_occlusion_v4_montage.jpg"), + np.vstack(montage_rows), + ) + + +def main() -> None: + args = parse_args() + args.output.mkdir(parents=True, exist_ok=True) + records = [ + json.loads(line) + for line in args.fusion_jsonl.read_text(encoding="utf-8").splitlines() + ] + output = process_sequence( + records, + short_occlusion_frames=args.short_occlusion_frames, + medium_occlusion_frames=args.medium_occlusion_frames, + lookahead_frames=args.lookahead_frames, + ) + with (args.output / "occlusion_v4.jsonl").open("w", encoding="utf-8") as handle: + for record in output: + handle.write(json.dumps(record, ensure_ascii=False) + "\n") + + summary = { + "algorithm_version": "occlusion_v4_global_assignment", + "frames": len(output), + "short_occlusion_frames": args.short_occlusion_frames, + "medium_occlusion_frames": args.medium_occlusion_frames, + "lookahead_frames": args.lookahead_frames, + "policy": { + "observed": "filtered visible endpoint; precise distance allowed", + "provisional": "strong current-frame endpoint; fast alarm only", + "recovered": "weak current-frame endpoint accepted by temporal gating", + "reassigned": "global hand candidate transferred using foreground scale and trajectory", + "interpolated": "fixed-lag short-gap interpolation; fast alarm only", + "predicted_short": "damped-velocity prediction; uncertainty grows each frame", + "reachable_medium": "track-centered motion corridor; intersect with door band", + "reachable_long": "no exact wrist; keep shoulder sector data for door intersection only", + "ik": "two-bone shoulder/wrist reconstruction using robust visible bone lengths", + "ownership": "one-to-one global hand reassignment using foreground scale and trajectory", + }, + "metrics": endpoint_metrics(output), + } + with (args.output / "summary.json").open("w", encoding="utf-8") as handle: + json.dump(summary, handle, ensure_ascii=False, indent=2) + write_video_and_montage(args.video, output, args.output) + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/orin/pipeline/predict_optimized_pose_videos.py b/orin/pipeline/predict_optimized_pose_videos.py new file mode 100644 index 0000000..dd15617 --- /dev/null +++ b/orin/pipeline/predict_optimized_pose_videos.py @@ -0,0 +1,683 @@ +"""End-to-end optimized RTMW-L prediction for CMS videos. + +Pipeline: +YOLO11s person -> fixed-camera false-positive filters -> lightweight track IDs +-> RTMW-L raw/smaller-person-isolated views -> temporal fusion -> causal +occlusion-aware V4 global hand assignment. Reachable regions stay in JSON and are hidden in the main +comparison video. +""" + +from __future__ import annotations + +import argparse +import json +import math +import time +from collections import Counter, defaultdict, deque +from dataclasses import dataclass, field +from pathlib import Path + +import cv2 +import numpy as np + +from compare_rtmw_ml import HAND_SLICES, draw_pose, summarize +from fuse_rtmw_l_temporal import ( + BODY_SIDE_INDICES, + PersonTrack, + adaptive_smooth, + build_global_hands, + draw_fused, + fuse_person, +) +from occlusion_aware_pose_v2 import ( + EndpointTrack, + Measurement, + calibrated_bone_lengths, + draw_v2, + reachable_region, + resolve_global_hand_assignments, + solve_two_bone_elbow, + temporal_recovery_measurement, + update_endpoint_track, +) +from rtmw_l_person_mask_ablation import mask_other_people + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--videos", type=Path, nargs="+", required=True) + parser.add_argument("--det-model", type=Path, required=True) + parser.add_argument("--pose-model", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument( + "--det-device", + default="0", + help="Ultralytics YOLO device, for example 0, cuda:0, or cpu.", + ) + parser.add_argument( + "--pose-device", + default="cpu", + help="RTMW ONNX Runtime device: cpu or cuda.", + ) + parser.add_argument("--det-imgsz", type=int, default=960) + parser.add_argument("--det-conf", type=float, default=0.30) + parser.add_argument("--det-roi-y-max-ratio", type=float, default=1.0) + parser.add_argument("--short-occlusion-frames", type=int, default=12) + parser.add_argument("--medium-occlusion-frames", type=int, default=30) + parser.add_argument("--max-people", type=int, default=3) + return parser.parse_args() + + +def bbox_iou(a: np.ndarray, b: np.ndarray) -> float: + x1 = max(float(a[0]), float(b[0])) + y1 = max(float(a[1]), float(b[1])) + x2 = min(float(a[2]), float(b[2])) + y2 = min(float(a[3]), float(b[3])) + intersection = max(x2 - x1, 0.0) * max(y2 - y1, 0.0) + union = ( + max(float(a[2] - a[0]), 0.0) * max(float(a[3] - a[1]), 0.0) + + max(float(b[2] - b[0]), 0.0) * max(float(b[3] - b[1]), 0.0) + - intersection + ) + return intersection / max(union, 1.0) + + +class BoxTracker: + def __init__(self, max_age: int = 30): + self.max_age = max_age + self.next_id = 1 + self.tracks: dict[int, dict] = {} + + def update( + self, + boxes: list[list[float]], + frame_idx: int, + image_shape: tuple[int, int], + ) -> list[int]: + height, width = image_shape + image_diagonal = math.hypot(width, height) + active_ids = [ + track_id + for track_id, track in self.tracks.items() + if frame_idx - track["last_frame"] <= self.max_age + ] + self.tracks = {track_id: self.tracks[track_id] for track_id in active_ids} + pairs = [] + for detection_idx, box in enumerate(boxes): + box_array = np.asarray(box, dtype=np.float64) + center = (box_array[:2] + box_array[2:]) * 0.5 + for track_id in active_ids: + prior = np.asarray(self.tracks[track_id]["box"], dtype=np.float64) + prior_center = (prior[:2] + prior[2:]) * 0.5 + iou = bbox_iou(box_array, prior) + center_distance = float(np.linalg.norm(center - prior_center)) / image_diagonal + if iou >= 0.05 or center_distance <= 0.18: + score = 2.0 * iou + max(0.0, 1.0 - center_distance / 0.18) + pairs.append((score, detection_idx, track_id)) + + assigned_detections = set() + assigned_tracks = set() + result: list[int | None] = [None] * len(boxes) + for _, detection_idx, track_id in sorted(pairs, reverse=True): + if detection_idx in assigned_detections or track_id in assigned_tracks: + continue + assigned_detections.add(detection_idx) + assigned_tracks.add(track_id) + result[detection_idx] = track_id + + for detection_idx, box in enumerate(boxes): + track_id = result[detection_idx] + if track_id is None: + track_id = self.next_id + self.next_id += 1 + result[detection_idx] = track_id + self.tracks[track_id] = {"box": box, "last_frame": frame_idx} + return [int(track_id) for track_id in result] + + +@dataclass +class LivePersonState: + fusion: PersonTrack = field(default_factory=PersonTrack) + endpoints: dict[str, EndpointTrack] = field( + default_factory=lambda: {"left": EndpointTrack(), "right": EndpointTrack()} + ) + bone_samples: dict[str, deque] = field( + default_factory=lambda: { + "left": deque(maxlen=120), + "right": deque(maxlen=120), + } + ) + last_frame: int = -1 + + +def bbox_diagonal(bbox: list[float]) -> float: + return max(math.hypot(bbox[2] - bbox[0], bbox[3] - bbox[1]), 1.0) + + +def update_bone_samples( + state: LivePersonState, + keypoints: np.ndarray, + metadata: dict, + bbox: list[float], +) -> None: + diagonal = bbox_diagonal(bbox) + for side, (shoulder, elbow, wrist) in BODY_SIDE_INDICES.items(): + meta = metadata[side] + if meta["limb_state"] != "consensus" or not meta["distance_eligible"]: + continue + upper = float(np.linalg.norm(keypoints[shoulder] - keypoints[elbow])) / diagonal + forearm = float(np.linalg.norm(keypoints[elbow] - keypoints[wrist])) / diagonal + if 0.04 <= upper <= 0.65 and 0.04 <= forearm <= 0.65: + state.bone_samples[side].append((upper, forearm)) + + +def current_bone_ratios(state: LivePersonState, side: str) -> tuple[float, float]: + samples = state.bone_samples[side] + if len(samples) < 10: + opposite = "right" if side == "left" else "left" + if len(state.bone_samples[opposite]) >= 10: + samples = state.bone_samples[opposite] + if not samples: + return 0.24, 0.22 + values = np.asarray(samples, dtype=np.float64) + return float(np.median(values[:, 0])), float(np.median(values[:, 1])) + + +def update_live_v2( + frame_idx: int, + bbox: list[float], + selected_keypoints: np.ndarray, + smoothed_keypoints: np.ndarray, + fusion_metadata: dict, + state: LivePersonState, + assigned_measurements: dict[str, Measurement | None] | None, + identity_assignments: dict[str, dict] | None, + short_occlusion_frames: int, + medium_occlusion_frames: int, +) -> tuple[np.ndarray, dict]: + frame_gap = 0 if state.last_frame < 0 else max(frame_idx - state.last_frame - 1, 0) + for endpoint in state.endpoints.values(): + endpoint.missed_frames += frame_gap + state.last_frame = frame_idx + update_bone_samples(state, selected_keypoints, fusion_metadata, bbox) + + output = smoothed_keypoints.copy() + output_metadata = {} + diagonal = bbox_diagonal(bbox) + for side, (shoulder_idx, elbow_idx, wrist_idx) in BODY_SIDE_INDICES.items(): + endpoint = state.endpoints[side] + meta = fusion_metadata[side] + start, end = HAND_SLICES[side] + measurement = ( + assigned_measurements.get(side) + if assigned_measurements is not None + else None + ) + if assigned_measurements is None and meta["alarm_eligible"]: + measurement = Measurement( + keypoints=selected_keypoints[start:end], + precise=bool(meta["distance_eligible"]), + provisional=not bool(meta["distance_eligible"]), + quality=float(meta.get("selected_hand_score", 0.0)), + ) + if measurement is None: + measurement = temporal_recovery_measurement( + selected_keypoints, + meta, + side, + bbox, + endpoint, + medium_occlusion_frames, + ) + returning_after_long = ( + measurement is not None + and endpoint.missed_frames > short_occlusion_frames + ) + wrist, hand, endpoint_state = update_endpoint_track( + endpoint, + measurement, + frame_idx, + short_occlusion_frames, + medium_occlusion_frames, + ) + shoulder = smoothed_keypoints[shoulder_idx] + upper_ratio, forearm_ratio = current_bone_ratios(state, side) + upper_length, forearm_length = calibrated_bone_lengths( + upper_ratio, forearm_ratio, bbox + ) + region = None + if wrist is not None and hand is not None: + reference_elbow = ( + selected_keypoints[elbow_idx] + if returning_after_long or endpoint.last_elbow is None + else endpoint.last_elbow + ) + use_ik = ( + meta["limb_state"] != "consensus" + or endpoint_state + in ("provisional", "recovered", "reassigned", "predicted_short") + ) + elbow = ( + solve_two_bone_elbow( + shoulder, + wrist, + upper_length, + forearm_length, + reference_elbow, + ) + if use_ik + else smoothed_keypoints[elbow_idx] + ) + endpoint.last_elbow = elbow.copy() + direction = wrist - shoulder + if float(np.linalg.norm(direction)) > 1e-6: + endpoint.last_direction = direction / np.linalg.norm(direction) + output[shoulder_idx] = shoulder + output[elbow_idx] = elbow + output[wrist_idx] = wrist + output[start:end] = hand + uncertainty = ( + 0.025 * diagonal + if endpoint_state == "observed" + else (0.04 + 0.015 * endpoint.missed_frames) * diagonal + ) + precise = endpoint_state == "observed" + else: + region = reachable_region( + shoulder, + upper_length, + forearm_length, + bbox, + endpoint, + endpoint_state, + short_occlusion_frames, + medium_occlusion_frames, + ) + uncertainty = region["outer_radius_px"] + precise = False + output_metadata[side] = { + "state": endpoint_state, + "precise_distance": precise, + "fast_alarm_candidate": True, + "risk_mode": ( + "precise_hand" + if endpoint_state == "observed" + else ( + "motion_corridor_intersection" + if endpoint_state == "reachable_medium" + else ( + "door_intersection_only" + if endpoint_state == "reachable_long" + else ( + "reassigned_hand" + if endpoint_state == "reassigned" + else "temporal_hand" + ) + ) + ) + ), + "requires_door_intersection": endpoint_state + in ("reachable_medium", "reachable_long"), + "identity_assignment": ( + identity_assignments.get(side) + if identity_assignments is not None + else None + ), + "missed_frames": endpoint.missed_frames, + "uncertainty_radius_px": round(float(uncertainty), 3), + "bone_lengths_px": { + "upper": round(upper_length, 3), + "forearm": round(forearm_length, 3), + }, + "reachable_region": region, + } + return output, output_metadata + + +def filter_person_boxes( + result, + width: int, + height: int, + max_people: int, +) -> tuple[list[list[float]], list[float], Counter]: + boxes = result.boxes.xyxy.cpu().numpy() + scores = result.boxes.conf.cpu().numpy() + rejected = Counter() + kept = [] + for box, score in zip(boxes, scores): + center_x = float(box[0] + box[2]) * 0.5 + box_height = float(box[3] - box[1]) + if center_x > 0.80 * width: + rejected["right_reflection_roi"] += 1 + continue + if box_height < 0.20 * height: + rejected["too_short"] += 1 + continue + kept.append((box.tolist(), float(score))) + kept.sort(key=lambda item: item[1], reverse=True) + if len(kept) > max_people: + rejected["over_max_people"] += len(kept) - max_people + kept = kept[:max_people] + kept.sort(key=lambda item: item[0][0]) + return [item[0] for item in kept], [item[1] for item in kept], rejected + + +def process_video( + video_path: Path, + output_dir: Path, + detector: YOLO, + pose: RTMPose, + det_device: str, + det_imgsz: int, + det_conf: float, + det_roi_y_max_ratio: float, + short_occlusion_frames: int, + medium_occlusion_frames: int, + max_people: int, + video_label: str, +) -> dict: + output_dir.mkdir(parents=True, exist_ok=True) + cap = cv2.VideoCapture(str(video_path)) + fps = float(cap.get(cv2.CAP_PROP_FPS)) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + writer = cv2.VideoWriter( + str(output_dir / "raw_temporal_occlusion_v4.mp4"), + cv2.VideoWriter_fourcc(*"mp4v"), + fps, + (1920, 360), + ) + + box_tracker = BoxTracker(max_age=30) + people: dict[int, LivePersonState] = {} + records = [] + detection_counts = Counter() + rejection_counts = Counter() + state_counts = Counter() + timings = defaultdict(list) + isolated_inferences = 0 + frame_idx = 0 + + while True: + ok, frame = cap.read() + if not ok: + break + started = time.perf_counter() + detection_height = max(1, min(height, round(height * det_roi_y_max_ratio))) + detection = detector.predict( + frame[:detection_height], + imgsz=det_imgsz, + conf=det_conf, + iou=0.30, + classes=[0], + device=det_device, + verbose=False, + )[0] + timings["detector_ms"].append((time.perf_counter() - started) * 1000.0) + boxes, confidences, rejected = filter_person_boxes( + detection, width, height, max_people + ) + rejection_counts.update(rejected) + detection_counts[len(boxes)] += 1 + track_ids = box_tracker.update(boxes, frame_idx, (height, width)) + + if boxes: + started = time.perf_counter() + raw_keypoints, raw_scores = pose(frame, bboxes=boxes) + timings["raw_pose_ms"].append((time.perf_counter() - started) * 1000.0) + isolated_keypoints = raw_keypoints.copy() + isolated_scores = raw_scores.copy() + started = time.perf_counter() + for person_idx, bbox in enumerate(boxes): + target_area = max((bbox[2] - bbox[0]) * (bbox[3] - bbox[1]), 1.0) + needs_isolation = any( + idx != person_idx + and max((other[2] - other[0]) * (other[3] - other[1]), 1.0) + < 0.5 * target_area + for idx, other in enumerate(boxes) + ) + if not needs_isolation: + continue + masked = mask_other_people(frame, boxes, person_idx) + kpts, scores = pose(masked, bboxes=[bbox]) + isolated_keypoints[person_idx] = kpts[0] + isolated_scores[person_idx] = scores[0] + isolated_inferences += 1 + timings["isolated_extra_ms"].append((time.perf_counter() - started) * 1000.0) + else: + raw_keypoints = np.empty((0, 133, 2), dtype=np.float64) + raw_scores = np.empty((0, 133), dtype=np.float64) + isolated_keypoints = raw_keypoints.copy() + isolated_scores = raw_scores.copy() + + selected_list = [] + smoothed_list = [] + fusion_meta_list = [] + person_states = [] + for person_idx, (bbox, track_id) in enumerate(zip(boxes, track_ids)): + state = people.setdefault(track_id, LivePersonState()) + selected, fusion_meta = fuse_person( + raw_keypoints[person_idx], + raw_scores[person_idx], + isolated_keypoints[person_idx], + isolated_scores[person_idx], + bbox, + state.fusion, + ) + smoothed = adaptive_smooth(selected, bbox, state.fusion) + selected_list.append(selected) + smoothed_list.append(smoothed) + fusion_meta_list.append(fusion_meta) + person_states.append(state) + + frame_measurements = {} + endpoint_tracks = {} + for person_idx, (selected, fusion_meta, state) in enumerate( + zip(selected_list, fusion_meta_list, person_states) + ): + for side, (start, end) in HAND_SLICES.items(): + meta = fusion_meta[side] + frame_measurements[(person_idx, side)] = ( + Measurement( + keypoints=selected[start:end], + precise=bool(meta["distance_eligible"]), + provisional=not bool(meta["distance_eligible"]), + quality=float(meta.get("selected_hand_score", 0.0)), + ) + if meta["alarm_eligible"] + else None + ) + endpoint_tracks[(person_idx, side)] = state.endpoints[side] + frame_measurements, assignment_events = resolve_global_hand_assignments( + frame_measurements, + endpoint_tracks, + boxes, + medium_occlusion_frames, + ) + + v2_list = [] + v2_meta_list = [] + for person_idx, (bbox, selected, smoothed, fusion_meta, state) in enumerate( + zip( + boxes, + selected_list, + smoothed_list, + fusion_meta_list, + person_states, + ) + ): + v2, v2_meta = update_live_v2( + frame_idx, + bbox, + selected, + smoothed, + fusion_meta, + state, + { + side: frame_measurements[(person_idx, side)] + for side in ("left", "right") + }, + { + side: assignment_events.get((person_idx, side)) + for side in ("left", "right") + }, + short_occlusion_frames, + medium_occlusion_frames, + ) + v2_list.append(v2) + v2_meta_list.append(v2_meta) + for side in ("left", "right"): + state_counts[f"{v2_meta[side]['state']}"] += 1 + + global_hands = build_global_hands(selected_list, fusion_meta_list) + records.append( + { + "frame_index": frame_idx, + "timestamp_ms": round(frame_idx / fps * 1000.0, 3), + "track_ids": track_ids, + "boxes": np.round(np.asarray(boxes), 3).tolist() if boxes else [], + "det_confidences": [round(value, 4) for value in confidences], + "raw_keypoints": np.round(raw_keypoints, 3).tolist(), + "temporal_selected_keypoints": np.round(np.asarray(selected_list), 3).tolist(), + "temporal_keypoints": np.round(np.asarray(smoothed_list), 3).tolist(), + "temporal_metadata": fusion_meta_list, + "v2_keypoints": np.round(np.asarray(v2_list), 3).tolist(), + "v2_metadata": v2_meta_list, + "global_hands": global_hands, + } + ) + + raw_panel = draw_pose( + frame, + boxes, + raw_keypoints, + f"{video_label} RTMW-L raw | frame {frame_idx}", + ) + temporal_panel = draw_fused( + frame, + boxes, + smoothed_list, + fusion_meta_list, + f"{video_label} temporal fusion | frame {frame_idx}", + ) + v2_panel = draw_v2( + frame, + boxes, + np.asarray(v2_list), + v2_meta_list, + f"{video_label} occlusion V4 | frame {frame_idx}", + show_reachable=False, + ) + panels = [ + cv2.resize(panel, (640, 360), interpolation=cv2.INTER_AREA) + for panel in (raw_panel, temporal_panel, v2_panel) + ] + writer.write(np.hstack(panels)) + if frame_idx == 0 and video_path.suffix.lower() in { + ".jpg", + ".jpeg", + ".png", + ".bmp", + ".webp", + }: + cv2.imwrite(str(output_dir / "raw_pose.jpg"), raw_panel) + cv2.imwrite(str(output_dir / "spatial_fusion.jpg"), temporal_panel) + cv2.imwrite(str(output_dir / "occlusion_v2.jpg"), v2_panel) + panel_width = 960 + panel_height = round(height * panel_width / width) + image_panels = [ + cv2.resize( + panel, + (panel_width, panel_height), + interpolation=cv2.INTER_AREA, + ) + for panel in (raw_panel, temporal_panel, v2_panel) + ] + cv2.imwrite( + str(output_dir / "raw_spatial_occlusion_v2.jpg"), + np.hstack(image_panels), + ) + if frame_idx % 100 == 0: + print(f"{video_label}: processed frame {frame_idx}", flush=True) + frame_idx += 1 + + cap.release() + writer.release() + with (output_dir / "predictions.jsonl").open("w", encoding="utf-8") as handle: + for record in records: + handle.write(json.dumps(record, ensure_ascii=False) + "\n") + + summary = { + "occlusion_algorithm": "v4_global_assignment", + "video": str(video_path.resolve()), + "frames": len(records), + "fps": round(fps, 3), + "resolution": [width, height], + "person_filter": { + "center_x_max_ratio": 0.80, + "minimum_box_height_ratio": 0.20, + "max_people": max_people, + }, + "detector_settings": { + "imgsz": det_imgsz, + "confidence": det_conf, + "roi_y_max_ratio": det_roi_y_max_ratio, + }, + "filtered_person_count_frames": dict(sorted(detection_counts.items())), + "rejected_detection_counts": dict(sorted(rejection_counts.items())), + "track_ids_created": box_tracker.next_id - 1, + "isolated_pose_inferences": isolated_inferences, + "short_occlusion_frames": short_occlusion_frames, + "medium_occlusion_frames": medium_occlusion_frames, + "v2_state_counts": dict(sorted(state_counts.items())), + "timing_ms_cpu": { + name: summarize(values[5:] if len(values) > 5 else values) + for name, values in timings.items() + }, + "output_note": ( + "Main video hides reachable-region arcs. Reachable-region geometry remains in " + "predictions.jsonl for later door-distance lower-bound calculation." + ), + } + with (output_dir / "summary.json").open("w", encoding="utf-8") as handle: + json.dump(summary, handle, ensure_ascii=False, indent=2) + return summary + + +def main() -> None: + from rtmlib import RTMPose + from ultralytics import YOLO + args = parse_args() + detector = YOLO(str(args.det_model)) + pose = RTMPose( + str(args.pose_model), + model_input_size=(288, 384), + backend="onnxruntime", + device=args.pose_device, + ) + all_summaries = {} + for video_idx, video_path in enumerate(args.videos, start=1): + label = f"video{video_idx}" + output_dir = args.output / label + all_summaries[label] = process_video( + video_path, + output_dir, + detector, + pose, + args.det_device, + args.det_imgsz, + args.det_conf, + args.det_roi_y_max_ratio, + args.short_occlusion_frames, + args.medium_occlusion_frames, + args.max_people, + label, + ) + args.output.mkdir(parents=True, exist_ok=True) + with (args.output / "summary.json").open("w", encoding="utf-8") as handle: + json.dump(all_summaries, handle, ensure_ascii=False, indent=2) + print(json.dumps(all_summaries, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/orin/pipeline/rtmw_l_person_mask_ablation.py b/orin/pipeline/rtmw_l_person_mask_ablation.py new file mode 100644 index 0000000..6263500 --- /dev/null +++ b/orin/pipeline/rtmw_l_person_mask_ablation.py @@ -0,0 +1,166 @@ +"""Test whether other people inside a top-down crop cause RTMW-L mix-ups.""" + +from __future__ import annotations + +import argparse +import json +import time +from pathlib import Path + +import cv2 +import numpy as np + +from compare_rtmw_ml import ( + draw_pose, + model_disagreement, + summarize, + temporal_metrics, + write_montage, +) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--video", type=Path, required=True) + parser.add_argument("--baseline-jsonl", type=Path, required=True) + parser.add_argument("--model-l", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + return parser.parse_args() + + +def mask_other_people( + frame: np.ndarray, + boxes: list[list[float]], + target_idx: int, +) -> np.ndarray: + masked = frame.copy() + height, width = frame.shape[:2] + mask = np.zeros((height, width), dtype=bool) + target = boxes[target_idx] + target_area = max((target[2] - target[0]) * (target[3] - target[1]), 1.0) + for idx, bbox in enumerate(boxes): + if idx == target_idx: + continue + other_area = max((bbox[2] - bbox[0]) * (bbox[3] - bbox[1]), 1.0) + # The failure in this video is the small background person being + # absorbed by the much larger foreground person's 3:4 pose crop. + # Mask only markedly smaller people. Masking a larger occluder while + # estimating a small person removes genuine target pixels at overlap. + if other_area >= 0.5 * target_area: + continue + x1, y1, x2, y2 = (int(round(value)) for value in bbox) + x1, x2 = max(0, x1), min(width - 1, x2) + y1, y2 = max(0, y1), min(height - 1, y2) + mask[y1:y2 + 1, x1:x2 + 1] = True + + masked[mask] = (124, 116, 104) + return masked + + +def main() -> None: + from rtmlib import RTMPose + args = parse_args() + args.output.mkdir(parents=True, exist_ok=True) + baseline = [ + json.loads(line) + for line in args.baseline_jsonl.read_text(encoding="utf-8").splitlines() + ] + pose_l = RTMPose( + str(args.model_l), model_input_size=(288, 384), backend="onnxruntime", device="cpu" + ) + + cap = cv2.VideoCapture(str(args.video)) + fps = float(cap.get(cv2.CAP_PROP_FPS)) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + writer = cv2.VideoWriter( + str(args.output / "rtmw_l_raw_vs_person_masked.mp4"), + cv2.VideoWriter_fourcc(*"mp4v"), + fps, + (width, height // 2), + ) + + comparison: list[dict] = [] + timings: list[float] = [] + frame_idx = 0 + while True: + ok, frame = cap.read() + if not ok: + break + baseline_record = baseline[frame_idx] + boxes = baseline_record["boxes"][:2] + masked_keypoints = [] + masked_scores = [] + started = time.perf_counter() + for person_idx, bbox in enumerate(boxes): + masked_frame = mask_other_people(frame, boxes, person_idx) + keypoints, scores = pose_l(masked_frame, bboxes=[bbox]) + masked_keypoints.append(keypoints[0]) + masked_scores.append(scores[0]) + timings.append((time.perf_counter() - started) * 1000.0) + masked_keypoints_array = np.asarray(masked_keypoints) + + raw_keypoints = np.asarray(baseline_record["L"]["keypoints"][:2]) + comparison.append( + { + "frame_index": frame_idx, + "boxes": boxes, + "M": {"keypoints": raw_keypoints.tolist()}, + "L": {"keypoints": np.round(masked_keypoints_array, 3).tolist()}, + "masked_raw_scores": np.round(np.asarray(masked_scores), 4).tolist(), + } + ) + + left = draw_pose(frame, boxes, raw_keypoints, f"RTMW-L raw | frame {frame_idx}") + right = draw_pose( + frame, + boxes, + masked_keypoints_array, + f"RTMW-L mask other person | frame {frame_idx}", + ) + left = cv2.resize(left, (width // 2, height // 2), interpolation=cv2.INTER_AREA) + right = cv2.resize(right, (width // 2, height // 2), interpolation=cv2.INTER_AREA) + writer.write(np.hstack([left, right])) + if frame_idx % 50 == 0: + print(f"processed frame {frame_idx}", flush=True) + frame_idx += 1 + + cap.release() + writer.release() + + with (args.output / "rtmw_l_raw_vs_person_masked.jsonl").open( + "w", encoding="utf-8" + ) as handle: + for record in comparison: + handle.write(json.dumps(record, ensure_ascii=False) + "\n") + + disagreement, worst_frames = model_disagreement(comparison) + fixed_frames = [0, 60, 120, 132, 136, 180, 240, 252, 300, 360, 411] + montage_frames = sorted(set(fixed_frames + worst_frames[:8])) + write_montage( + args.video, + comparison, + montage_frames, + args.output / "rtmw_l_raw_vs_person_masked_montage.jpg", + titles=("RTMW-L raw", "RTMW-L smaller-person masked"), + ) + + summary = { + "frames": len(comparison), + "labels": { + "M": "RTMW-L raw crop", + "L": "RTMW-L with markedly smaller people masked", + }, + "timing_ms_two_people_cpu": summarize(timings[5:]), + "temporal_metrics_normalized_to_yolo_box": temporal_metrics(comparison), + "position_change_after_masking": disagreement, + "largest_change_frames": worst_frames, + "montage_frames": montage_frames, + } + with (args.output / "summary.json").open("w", encoding="utf-8") as handle: + json.dump(summary, handle, ensure_ascii=False, indent=2) + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/orin/pipeline/rtmw_risk_pipeline.py b/orin/pipeline/rtmw_risk_pipeline.py new file mode 100644 index 0000000..a61a490 --- /dev/null +++ b/orin/pipeline/rtmw_risk_pipeline.py @@ -0,0 +1,390 @@ +"""Lightweight causal door-risk inference using only YOLO11s and RTMW-L.""" + +from __future__ import annotations + +import argparse +import json +import sys +import time +from pathlib import Path + +import cv2 +import numpy as np + + +PACKAGE_DIR = Path(__file__).resolve().parents[1] +PIPELINE_DIR = Path(__file__).resolve().parent +for import_dir in (PIPELINE_DIR, PACKAGE_DIR): + if str(import_dir) not in sys.path: + sys.path.insert(0, str(import_dir)) + +from door_mask_risk import DoorMaskSequence, DoorRiskEvaluator # noqa: E402 +from door_zone_risk import ( # noqa: E402 + DoorZoneAssigner, + DoorZoneConfig, + build_door_risks, +) +from live_pose_engine import LivePoseEngine # noqa: E402 + + +def parse_image_size(value: str) -> int | tuple[int, int]: + parts = value.lower().replace(",", "x").split("x") + if len(parts) == 1: + return int(parts[0]) + if len(parts) == 2: + return int(parts[0]), int(parts[1]) + raise argparse.ArgumentTypeError( + "image size must be one integer or HEIGHTxWIDTH, for example 960 or 544x960" + ) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--video", type=Path, required=True) + door_source = parser.add_mutually_exclusive_group(required=True) + door_source.add_argument("--door-mask-dir", type=Path) + door_source.add_argument( + "--constant-door-mask", + type=Path, + help="One X-AnyLabeling JSON or raster mask reused for every video frame.", + ) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument( + "--det-model", type=Path, default=PACKAGE_DIR / "models" / "yolo11s.onnx" + ) + parser.add_argument( + "--pose-model", type=Path, default=PACKAGE_DIR / "models" / "rtmw-l-384.onnx" + ) + parser.add_argument( + "--pose-jsonl", + type=Path, + help="Diagnostic replay input; bypasses live YOLO/RTMW model execution.", + ) + parser.add_argument("--det-device", default="0") + parser.add_argument("--pose-device", default="cuda") + parser.add_argument( + "--pose-provider", + choices=("cuda", "tensorrt"), + default="cuda", + help="ONNX Runtime provider for RTMW.", + ) + parser.add_argument( + "--pose-trt-cache", + type=Path, + default=PACKAGE_DIR / "models" / "rtmw_l_trt_cache", + ) + parser.add_argument("--det-imgsz", type=parse_image_size, default=960) + parser.add_argument("--det-conf", type=float, default=0.30) + parser.add_argument("--det-roi-y-max-ratio", type=float, default=1.0) + parser.add_argument("--max-people", type=int, default=3) + parser.add_argument( + "--door-mask-format", + choices=("auto", "xanylabeling", "raster"), + default="auto", + ) + parser.add_argument("--door-label", action="append") + parser.add_argument("--door-frame-offset", type=int, default=0) + parser.add_argument("--require-door-mask", action="store_true") + parser.add_argument("--risk-warning-relative", type=float, default=0.30) + parser.add_argument("--risk-release-relative", type=float, default=0.45) + parser.add_argument( + "--active-door", + choices=("front", "rear", "both", "none"), + default="both", + help="Door(s) whose CAN state is 0. Use front/rear for deployment simulation.", + ) + parser.add_argument( + "--door-zone-config", + type=Path, + default=PACKAGE_DIR / "annotations" / "door_zone_multifeature.json", + help="Pose-primary fixed-camera front/rear calibration JSON.", + ) + parser.add_argument("--max-frames", type=int, default=0) + parser.add_argument("--write-video", action="store_true") + parser.add_argument("--progress-every", type=int, default=100) + return parser.parse_args() + + +def load_pose_records(path: Path) -> dict[int, dict]: + records = {} + with path.open("r", encoding="utf-8") as handle: + for line in handle: + if not line.strip(): + continue + record = json.loads(line) + records[int(record["frame_index"])] = record + return records + + +def percentile(values: list[float], p: float) -> float | None: + return round(float(np.percentile(values, p)), 3) if values else None + + +def timing_stats(values: list[float]) -> dict: + return { + "count": len(values), + "total": round(float(np.sum(values)), 3) if values else 0.0, + "mean": round(float(np.mean(values)), 3) if values else None, + "median": percentile(values, 50), + "p95": percentile(values, 95), + } + + +def visualization_skeletons(record: dict) -> list[dict]: + """Return the exact fused keypoints and metadata consumed by draw_fused.""" + + boxes = record.get("boxes", []) + track_ids = [int(value) for value in record.get("track_ids", [])] + keypoints = record.get("temporal_selected_keypoints", []) + metadata = record.get("temporal_metadata", []) + if not (len(boxes) == len(keypoints) == len(metadata)): + return [] + return [ + { + "track_id": track_ids[position] if position < len(track_ids) else position + 1, + "person_index": position, + "layout": "coco_wholebody_133", + "keypoints": person_keypoints, + "metadata": metadata[position], + } + for position, person_keypoints in enumerate(keypoints) + ] + + +def render_frame( + frame: np.ndarray, + record: dict, + frame_risk: dict, + door_mask: np.ndarray | None, + door_assignments: list[dict], +) -> np.ndarray: + canvas = frame.copy() + boxes = record.get("boxes", []) + keypoints = record.get("temporal_selected_keypoints", []) + metadata = record.get("temporal_metadata", []) + if len(boxes) == len(keypoints) == len(metadata) and boxes: + from fuse_rtmw_l_temporal import draw_fused + + canvas = draw_fused(canvas, boxes, keypoints, metadata, "YOLO + RTMW risk") + else: + for position, box in enumerate(boxes): + x1, y1, x2, y2 = [int(round(float(value))) for value in box[:4]] + cv2.rectangle(canvas, (x1, y1), (x2, y2), (0, 220, 255), 2) + cv2.putText( + canvas, + f"P{position + 1}", + (x1 + 4, max(22, y1 + 24)), + cv2.FONT_HERSHEY_SIMPLEX, + 0.7, + (0, 220, 255), + 2, + cv2.LINE_AA, + ) + zone_colors = { + "front": (0, 220, 255), + "rear": (255, 180, 0), + "transition": (0, 140, 255), + "unassigned": (150, 150, 150), + } + for assignment in door_assignments: + position = int(assignment["person_index"]) + if not 0 <= position < len(boxes): + continue + box = boxes[position] + x1, y1 = int(round(float(box[0]))), int(round(float(box[1]))) + zone = str(assignment["door_zone"]) + cv2.putText( + canvas, + f"T{assignment['track_id']} {zone.upper()}", + (max(0, x1 + 4), max(24, y1 - 8)), + cv2.FONT_HERSHEY_SIMPLEX, + 0.68, + zone_colors.get(zone, (160, 160, 160)), + 2, + cv2.LINE_AA, + ) + if door_mask is not None and np.any(door_mask): + overlay = np.zeros_like(canvas) + overlay[door_mask > 0] = (255, 180, 0) + canvas = cv2.addWeighted(canvas, 1.0, overlay, 0.22, 0) + + score = frame_risk.get("risk_score") + score_text = "N/A" if score is None else f"{float(score):.3f}" + level = str(frame_risk.get("risk_level", "unavailable")) + color = (0, 0, 255) if level == "danger" else (0, 180, 255) + if level in ("clear", "unavailable", "inactive", "unknown"): + color = (40, 210, 80) if level == "clear" else (160, 160, 160) + cv2.rectangle(canvas, (12, 55), (490, 95), (0, 0, 0), -1) + cv2.putText( + canvas, + f"{frame_risk.get('risk_type', 'DOOR_RISK')} score={score_text} level={level}", + (24, 83), + cv2.FONT_HERSHEY_SIMPLEX, + 0.68, + color, + 2, + cv2.LINE_AA, + ) + return canvas + + +def main() -> None: + args = parse_args() + args.output.mkdir(parents=True, exist_ok=True) + if args.pose_provider == "tensorrt" and not args.pose_device.lower().startswith("cuda"): + raise ValueError("--pose-provider tensorrt requires --pose-device cuda") + + capture = cv2.VideoCapture(str(args.video.resolve())) + if not capture.isOpened(): + raise RuntimeError(f"Cannot open video: {args.video}") + input_fps = float(capture.get(cv2.CAP_PROP_FPS)) or 30.0 + width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH)) + height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT)) + + risk_evaluator = DoorRiskEvaluator( + DoorMaskSequence( + args.door_mask_dir, + mask_format=args.door_mask_format, + labels=tuple(args.door_label or ("door", "车门")), + frame_offset=args.door_frame_offset, + require_every_frame=args.require_door_mask, + constant_mask=args.constant_door_mask, + ), + warning_relative=args.risk_warning_relative, + release_relative=args.risk_release_relative, + ) + zone_assigner = DoorZoneAssigner(DoorZoneConfig.load(args.door_zone_config)) + print( + f"Door masks: {risk_evaluator.sequence.source_format} " + + ( + f"(constant: {risk_evaluator.sequence.constant_path})" + if risk_evaluator.sequence.constant_path is not None + else f"({len(risk_evaluator.sequence.paths)} indexed frames)" + ) + ) + + pose_records = load_pose_records(args.pose_jsonl) if args.pose_jsonl else None + load_started = time.perf_counter() + pose_engine = None if pose_records is not None else LivePoseEngine(args) + model_load_seconds = time.perf_counter() - load_started + + writer = None + if args.write_video: + writer = cv2.VideoWriter( + str(args.output / "rtmw_risk_overlay.mp4"), + cv2.VideoWriter_fourcc(*"mp4v"), + input_fps, + (width, height), + ) + + frame_latencies = [] + pose_latencies = [] + risk_latencies = [] + render_latencies = [] + started_all = time.perf_counter() + frame_index = 0 + output_path = args.output / "causal_results.jsonl" + with output_path.open("w", encoding="utf-8") as output_handle: + while True: + if args.max_frames > 0 and frame_index >= args.max_frames: + break + ok, frame = capture.read() + if not ok: + break + frame_started = time.perf_counter() + pose_started = time.perf_counter() + if pose_records is None: + record = pose_engine.infer(frame, frame_index) + else: + record = pose_records.get(frame_index) + if record is None: + raise RuntimeError(f"Pose JSONL has no record for frame {frame_index}") + pose_latencies.append((time.perf_counter() - pose_started) * 1000) + + risk_started = time.perf_counter() + assignments = zone_assigner.update( + frame_index, record, (height, width) + ) + raw_risk, door_mask = risk_evaluator.evaluate( + frame_index, record, (height, width) + ) + door_risks, frame_risk = build_door_risks( + raw_risk, assignments, args.active_door + ) + risk_latencies.append((time.perf_counter() - risk_started) * 1000) + output_record = { + "frame_index": frame_index, + "track_ids": record.get("track_ids", []), + "boxes": record.get("boxes", []), + "skeletons": visualization_skeletons(record), + "active_door": args.active_door, + "door_assignments": assignments, + "door_risks": door_risks, + "risk": frame_risk, + "ungated_risk": raw_risk, + } + output_handle.write(json.dumps(output_record, ensure_ascii=False) + "\n") + + if writer is not None: + render_started = time.perf_counter() + writer.write( + render_frame(frame, record, frame_risk, door_mask, assignments) + ) + render_latencies.append((time.perf_counter() - render_started) * 1000) + + frame_latencies.append((time.perf_counter() - frame_started) * 1000) + if args.progress_every > 0 and frame_index % args.progress_every == 0: + recent = frame_latencies[-min(len(frame_latencies), args.progress_every) :] + print( + f"frame={frame_index} recent_ms={np.mean(recent):.1f} " + f"risk={frame_risk['risk_level']}", + flush=True, + ) + frame_index += 1 + + capture.release() + if writer is not None: + writer.release() + elapsed = time.perf_counter() - started_all + summary = { + "mode": "yolo_rtmw_door_risk_multifeature_v9_10", + "video": str(args.video.resolve()), + "pose_source": "jsonl_diagnostic" if pose_records is not None else "resident_yolo_rtmw", + "models_loaded": [] if pose_records is not None else ["YOLO11s", "RTMW-L"], + "edgetam_loaded": False, + "risk_region_policy": ( + "RTMW alarm-eligible hand hulls; YOLO body box only when a person " + "has no usable RTMW hand region" + ), + "frames": frame_index, + "input_fps": round(input_fps, 3), + "elapsed_seconds": round(elapsed, 3), + "throughput_fps": round(frame_index / elapsed, 3) if elapsed else None, + "model_load_seconds": round(model_load_seconds, 3), + "latency_ms": { + "total": timing_stats(frame_latencies), + "pose": timing_stats(pose_latencies), + "risk": timing_stats(risk_latencies), + "render": timing_stats(render_latencies), + }, + "write_video": args.write_video, + "active_door": args.active_door, + "door_zone": zone_assigner.summary(), + "door_risk": risk_evaluator.summary(), + } + if pose_engine is not None: + summary["pose"] = { + "provider": args.pose_provider, + "isolated_inferences": pose_engine.isolated_inferences, + "timing_ms": { + key: timing_stats(values) for key, values in pose_engine.timings.items() + }, + } + (args.output / "summary.json").write_text( + json.dumps(summary, ensure_ascii=False, indent=2), encoding="utf-8" + ) + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/orin/run.sh b/orin/run.sh index c153d56..7f8c795 100755 --- a/orin/run.sh +++ b/orin/run.sh @@ -1,4 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" -exec "$root/build/camera_risk" --config "$root/config/camera.json" "$@" +root="$(cd "$(dirname "$0")" && pwd)" +export OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=2 +export LD_LIBRARY_PATH="$root/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" +export PYTHONDONTWRITEBYTECODE=1 +exec "${PYTHON:-python3}" -u "$root/run_camera.py" "$@" diff --git a/orin/run_camera.py b/orin/run_camera.py new file mode 100644 index 0000000..576304c --- /dev/null +++ b/orin/run_camera.py @@ -0,0 +1,299 @@ +#!/usr/bin/env python3 +"""Live baseline V4L2/CAN capture + native TensorRT + CMS v9.10 risk.""" +from __future__ import annotations +import argparse +from collections import Counter, deque +from contextlib import ExitStack +import copy +import json +import signal +import sys +import threading +import time +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +from pathlib import Path +import cv2 +import numpy as np +ROOT=Path(__file__).resolve().parent +sys.path.insert(0,str(ROOT/'pipeline')) +from native_backend import NativeBackend, NativePoseEngine +from latest_result import LatestResult, result_to_dict +from door_mask_risk import DoorMaskSequence, DoorRiskEvaluator +from door_zone_risk import DoorZoneConfig, DoorZoneAssigner, build_door_risks +from rtmw_risk_pipeline import render_frame, visualization_skeletons, timing_stats + + +def select_active_door(mode, snapshot, side='left', timeout_ms=1000): + if mode!='can': return mode, True + p=snapshot['positions'];offset=0 if side=='left' else 1 + if snapshot['age_ms']<0 or snapshot['age_ms']>timeout_ms or min(p[offset],p[offset+2])<0: + return 'none',False + front,rear=p[offset]==0,p[offset+2]==0 + return ('both' if front and rear else 'front' if front else 'rear' if rear else 'none'),True + + +def gate_risks(raw, assignments, active, can_valid): + doors,risk=build_door_risks(raw,assignments,active) + if not can_valid: + for door,item in doors.items(): + item.update(risk_type=door.upper()+'_UNKNOWN',risk_level='unknown',risk_score=None,decision='CAN_UNAVAILABLE_OR_STALE') + risk=dict(risk,risk_type='CAN_UNKNOWN',risk_level='unknown',risk_score=None,decision='CAN_UNAVAILABLE_OR_STALE') + return doors,risk + + +class JsonlWriter: + """Bound the disk usage of continuous camera runs (current + two backups).""" + def __init__(self,path,max_bytes): + self.path=path;self.max_bytes=max_bytes;self.size=0 + self.handle=path.open('w',encoding='utf-8',buffering=1) + def __enter__(self):return self + def __exit__(self,*args):self.close() + def close(self):self.handle.close() + def write(self,text): + size=len(text.encode('utf-8')) + if self.max_bytes and self.size and self.size+size>self.max_bytes: + self.handle.close() + backup=self.path.with_suffix(self.path.suffix+'.1') + if backup.exists():backup.replace(self.path.with_suffix(self.path.suffix+'.2')) + self.path.replace(backup) + self.handle=self.path.open('w',encoding='utf-8',buffering=1);self.size=0 + self.handle.write(text);self.size+=size + + +def render_output(frame, record, risk, mask, assignments, status): + canvas = render_frame(frame, record, risk, mask, assignments) + cv2.putText(canvas,status,(24,frame.shape[0]-30),cv2.FONT_HERSHEY_SIMPLEX,.8,(0,180,255),2) + return canvas + + +class Preview: + def __init__(self,host,port,results): + self.jpeg=None;self.results=results;self.lock=threading.Lock() + self.pending=threading.Condition();self.packet=None;self.stopped=False + outer=self + class Handler(BaseHTTPRequestHandler): + def do_GET(self): + with outer.lock: + if self.path.split('?')[0]=='/frame.jpg': payload=outer.jpeg or b'';mime='image/jpeg' + elif self.path=='/result.json':payload=json.dumps(result_to_dict(outer.results.load()) or {},ensure_ascii=False,allow_nan=False).encode();mime='application/json' + else: + payload=b'''Vision anti-pinch 0923

Vision anti-pinch 0923 / Live camera

''';mime='text/html; charset=utf-8' + self.send_response(200 if payload else 503);self.send_header('Content-Type',mime);self.send_header('Cache-Control','no-store');self.send_header('Content-Length',str(len(payload)));self.end_headers() + try:self.wfile.write(payload) + except (BrokenPipeError,ConnectionResetError):pass + def log_message(self,*args):pass + self.server=ThreadingHTTPServer((host,port),Handler) + self.thread=threading.Thread(target=self.server.serve_forever,daemon=True);self.thread.start() + self.renderer=threading.Thread(target=self._render_loop,name='risk-preview',daemon=True) + self.renderer.start() + def submit(self, frame, record, risk, mask, assignments, status): + # All inputs belong to a finished frame; inference never modifies them + # after submission. Retain only one pending frame, replacing older work. + with self.pending: + if not self.stopped: + self.packet=(frame,record,risk,mask,assignments,status) + self.pending.notify() + + def _render_loop(self): + try: + while True: + with self.pending: + self.pending.wait_for(lambda:self.packet is not None or self.stopped) + if self.stopped:return + packet=self.packet;self.packet=None + self.update(render_output(*packet)) + except Exception as exc: + with self.pending:self.stopped=True;self.packet=None + with self.lock:self.jpeg=None + print('Visualization disabled; inference continues: '+str(exc),file=sys.stderr,flush=True) + + def update(self,image): + w=960;h=round(image.shape[0]*w/image.shape[1]);image=cv2.resize(image,(w,h)) + ok,jpeg=cv2.imencode('.jpg',image,[cv2.IMWRITE_JPEG_QUALITY,80]) + if ok: + with self.lock:self.jpeg=jpeg.tobytes() + def close(self): + with self.pending:self.stopped=True;self.packet=None;self.pending.notify_all() + self.renderer.join() + self.server.shutdown();self.server.server_close();self.thread.join() + + +def parse_args(argv=None): + p=argparse.ArgumentParser(description=__doc__) + p.add_argument('--video',type=Path,help='Diagnostic video replay through the same TensorRT/risk chain');p.add_argument('--camera',default='/dev/video5');p.add_argument('--width',type=int,default=1920);p.add_argument('--height',type=int,default=1536);p.add_argument('--fps',type=int,default=30) + p.add_argument('--engines',type=Path,default=ROOT/'models/engines') + p.add_argument('--constant-door-mask',type=Path,default=ROOT/'annotations/constant_door_mask.json') + p.add_argument('--door-zone-config',type=Path,default=ROOT/'annotations/door_zone_multifeature.json') + p.add_argument('--active-door',choices=['can','front','rear','both','none'],default='can') + p.add_argument('--can-side',choices=['left','right'],default='left');p.add_argument('--can-timeout-ms',type=float,default=1000);p.add_argument('--no-can',action='store_true') + p.add_argument('--max-people',type=int,default=3);p.add_argument('--det-conf',type=float,default=.30) + p.add_argument('--max-frames',type=int,default=0);p.add_argument('--duration',type=float,default=0) + p.add_argument('--jsonl-max-mb',type=float,default=32,help='Rotate each JSONL at this size; keep two backups; 0 disables rotation');p.add_argument('--output',type=Path,default=ROOT/'outputs'/time.strftime('%Y%m%d-%H%M%S')) + p.add_argument('--visualize',action='store_true',help='Enable optional HTTP visualization; disabled by default') + p.add_argument('--save-results',action='store_true',help='Save per-frame JSONL and periodic latest.json') + p.add_argument('--save-snapshots',action='store_true',help='Render and save latest.jpg every 10 seconds') + p.add_argument('--preview-port',type=int,default=8765);p.add_argument('--preview-host',default='0.0.0.0');p.add_argument('--preview-every',type=int,default=3) + p.add_argument('--write-video',action='store_true');p.add_argument('--save-pose-records',action='store_true');p.add_argument('--calibration-verified',action='store_true') + a=p.parse_args(argv) + if not 1<=a.max_people<=16 or not 0=a.max_frames) or (a.duration and time.monotonic()-run_started>=a.duration):break + if video: + ok,frame=video.read() + if not ok:break + capture={'sequence':count,'capture_monotonic_ms':time.monotonic()*1000,'dropped_before_inference':0,'latency_clock':'video_decode_complete'} + else:frame,capture=native.read() + if frame is None:break + tick=time.monotonic();record=pose.infer(frame,count);pose_ms.append((time.monotonic()-tick)*1000) + rt=time.monotonic();snapshot=native.can_snapshot();active,valid=select_active_door(a.active_door,snapshot,a.can_side,a.can_timeout_ms) + assignments=assigner.update(count,record,(a.height,a.width));raw,mask=evaluator.evaluate(count,record,(a.height,a.width)) + doors,risk=gate_risks(raw,assignments,active,valid);risk_ms.append((time.monotonic()-rt)*1000) + result={'frame_index':count,'track_ids':record['track_ids'],'boxes':record['boxes'],'skeletons':visualization_skeletons(record),'active_door':active,'door_assignments':assignments,'door_risks':doors,'risk':risk,'ungated_risk':raw,'capture':capture,'can':dict(snapshot,valid=valid,source='hardware' if a.active_door=='can' else 'simulation',side=a.can_side),'calibration_verified':a.calibration_verified} + result['capture_to_result_ms']=round(time.monotonic()*1000-capture['capture_monotonic_ms'],3) + results.publish(result) + if out:out.write(json.dumps(result,ensure_ascii=False,allow_nan=False)+'\n') + if pose_out:pose_out.write(json.dumps(record,ensure_ascii=False,allow_nan=False)+'\n') + now=time.monotonic() + snapshot_due=now-last_snapshot>=10 + if a.save_results and snapshot_due: + (a.output/'latest.json').write_text(json.dumps(result,ensure_ascii=False,indent=2)) + status=('CAN LIVE' if a.active_door=='can' else 'CAN SIMULATION: '+active)+' | '+('CALIBRATED' if a.calibration_verified else 'CALIBRATION UNVERIFIED') + if preview and count%a.preview_every==0: + preview.submit(frame,record,risk,mask,assignments,status) + if writer or (a.save_snapshots and snapshot_due): + canvas=render_output(frame,record,risk,mask,assignments,status) + if writer:writer.write(canvas) + if a.save_snapshots and snapshot_due: + cv2.imwrite(str(a.output/'latest.jpg'),canvas) + if snapshot_due:last_snapshot=now + count+=1;dropped+=capture['dropped_before_inference'];levels[risk['risk_level']]+=1;ages.append(result['capture_to_result_ms']);latencies.append((time.monotonic()-tick)*1000) + if now-last_report>=5: + print(json.dumps({'frames':count,'fps':round(count/(now-run_started),2),'people':len(record['boxes']),'risk':risk['risk_type'],'latency_ms':round(float(np.mean(latencies)),1),'capture_age_ms':round(float(np.mean(ages)),1),'can_valid':valid}),flush=True);last_report=now + finally: + if pose_out:pose_out.close() + except Exception as exc: + error=str(exc);raise + finally: + ended=time.monotonic() + if video:video.release() + if native:native.close() + if writer:writer.release() + if preview:preview.close() + elapsed=ended-(run_started or started) + summary={'mode':'baseline_v4l2_can_native_trt_cms_v9_10','camera':a.camera if not a.video else None,'video':str(a.video) if a.video else None,'frames':count,'elapsed_seconds':round(elapsed,3),'throughput_fps':round(count/max(elapsed,.001),3),'dropped_latest_frames':dropped,'risk_levels':dict(levels),'active_door_mode':a.active_door,'can_side':a.can_side,'calibration_verified':a.calibration_verified,'visualize_requested':a.visualize,'save_results':a.save_results,'save_snapshots':a.save_snapshots,'latency_window_frames':3000,'latency_ms':{'total':timing_stats(list(latencies)),'pose':timing_stats(list(pose_ms)),'risk':timing_stats(list(risk_ms)),'capture_to_result':timing_stats(list(ages))},'error':error} + if summary_sink is not None:summary_sink.update(summary) + if save_any:(a.output/'summary.json').write_text(json.dumps(summary,ensure_ascii=False,indent=2)) + print(json.dumps(summary,ensure_ascii=False),flush=True) + +class CameraPipeline: + """One lifecycle per instance, with the 0920 start/latest/stop/join pattern. + + The worker owns inference. Downstream threads read the latest immutable + snapshot directly, without JSON files, HTTP, callbacks or a result queue. + """ + def __init__(self, args=None): + self.args = copy.deepcopy(args if args is not None else parse_args([])) + self._results = LatestResult() + self._stop = threading.Event() + self._lifecycle_lock = threading.Lock() + self._thread = None + self._error = None + self.summary = {} + + @property + def latest_result(self): + """The latest complete result variable, or None before the first frame.""" + return self._results.load() + + def latest(self): + return self.latest_result + + def wait_for_result(self, after_frame_index=-1, timeout=None): + return self._results.wait(after_frame_index, timeout) + + def start(self): + with self._lifecycle_lock: + if self._thread is not None: + raise RuntimeError('CameraPipeline can only be started once') + self._thread = threading.Thread(target=self._run, name='vision-risk') + self._thread.start() + return self + + def _run(self): + try: + run_pipeline(self.args, self._results, self._stop, self.summary) + except BaseException as exc: + self._error = exc + finally: + self._results.close() + + def running(self): + return self._thread is not None and self._thread.is_alive() + + def request_stop(self): + self._stop.set() + + def join(self, timeout=None): + if self._thread is not None: + self._thread.join(timeout) + if not self._thread.is_alive() and self._error is not None: + raise self._error + + def __enter__(self): + return self.start() + + def __exit__(self, *args): + self.request_stop() + self.join() + + +def main(): + pipeline=CameraPipeline(parse_args()) + for sig in (signal.SIGINT,signal.SIGTERM): + signal.signal(sig,lambda *_:pipeline.request_stop()) + pipeline.start() + # Periodic joins allow Python to deliver stop signals on the main thread. + while pipeline.running(): + pipeline.join(.2) + pipeline.join() + + +if __name__=='__main__':main() diff --git a/orin/scripts/initialize_camera.sh b/orin/scripts/initialize_camera.sh index 5f70e1f..1383006 100755 --- a/orin/scripts/initialize_camera.sh +++ b/orin/scripts/initialize_camera.sh @@ -1,21 +1,5 @@ #!/usr/bin/env bash set -euo pipefail -root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" -device=/dev/video5 -loaded() { test -d "/sys/module/$1"; } -root_command() { if [[ $EUID -eq 0 ]]; then "$@"; else sudo -n "$@"; fi; } -if [[ -c "$device" ]] && loaded max9295 && loaded max9296 && loaded sgx_yuv_gmsl2; then - echo "Camera already initialized: $device" - exit 0 -fi -for driver in max9295 max9296 sgx-yuv-gmsl2; do - file="$root/bin/drivers/$driver.ko" - [[ -f "$file" ]] || { echo "Missing driver: $file" >&2; exit 1; } - [[ "$(modinfo -F vermagic "$file")" == "$(uname -r) "* ]] || { echo "Kernel mismatch: $file" >&2; exit 1; } -done -loaded max9295 || root_command insmod "$root/bin/drivers/max9295.ko" -loaded max9296 || root_command insmod "$root/bin/drivers/max9296.ko" -loaded sgx_yuv_gmsl2 || root_command insmod "$root/bin/drivers/sgx-yuv-gmsl2.ko" gmsl_mode=2,2,2,2 -for _ in {1..20}; do [[ -c "$device" ]] && break; sleep 0.25; done -[[ -c "$device" ]] || { echo "$device was not created; verify camera/DTB" >&2; exit 1; } -v4l2-ctl -d "$device" -c sensor_mode=1,trig_pin=0xffff0007 +root="$(cd "$(dirname "$0")/.." && pwd)" +export DRIVER_DIR="$root/bin/drivers" +exec "$root/scripts/initialize_camera_impl.sh" "$@" diff --git a/orin/scripts/initialize_camera_impl.sh b/orin/scripts/initialize_camera_impl.sh new file mode 100755 index 0000000..c840953 --- /dev/null +++ b/orin/scripts/initialize_camera_impl.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Use the previously deployed 0920 drivers; do not force module compatibility. +set -euo pipefail +root="$(cd "$(dirname "$0")/.." && pwd)" +driver_dir="${DRIVER_DIR:-$root/../vision-anti-pinch-0920/orin/bin/drivers}" +device="${1:-/dev/video5}" +kernel="$(uname -r)" +for driver in max9295 max9296 sgx-yuv-gmsl2; do + module="${driver//-/_}" + [[ -d "/sys/module/$module" ]] && continue + file="$driver_dir/$driver.ko" + [[ -f "$file" ]] || { echo "Missing driver: $file" >&2; exit 1; } + vermagic="$(modinfo -F vermagic "$file")" + if [[ -n "$vermagic" && "${vermagic%% *}" != "$kernel" ]]; then + echo "Kernel mismatch: $file ($vermagic), running $kernel" >&2; exit 1 + fi + if [[ -z "$vermagic" ]]; then + echo "No vermagic metadata: $file; using normal insmod kernel validation." + fi + options=() + [[ "$driver" == sgx-yuv-gmsl2 ]] && options=(gmsl_mode=2,2,2,2) + sudo -n insmod "$file" "${options[@]}" +done +for _ in {1..20}; do [[ -c "$device" ]] && break; sleep .25; done +[[ -c "$device" ]] || { echo "Camera not created: $device" >&2; exit 1; } +v4l2-ctl -d "$device" -c sensor_mode=1,trig_pin=0xffff0007 +echo "Camera ready: $device" diff --git a/pipeline/compare_rtmw_ml.py b/pipeline/compare_rtmw_ml.py new file mode 100644 index 0000000..7d92a4a --- /dev/null +++ b/pipeline/compare_rtmw_ml.py @@ -0,0 +1,384 @@ +"""Compare RTMW-M 256x192 and RTMW-L 384x288 on cached YOLO boxes. + +This is an experiment script. It intentionally keeps the candidate weights +outside the formal models/ directory and does not change deployment code. +""" + +from __future__ import annotations + +import argparse +import json +import math +import time +from collections import defaultdict +from pathlib import Path + +import cv2 +import numpy as np + + +BODY_EDGES = ((5, 7), (7, 9), (6, 8), (8, 10)) +HAND_EDGES_LOCAL = ( + (0, 1), (1, 2), (2, 3), (3, 4), + (0, 5), (5, 6), (6, 7), (7, 8), + (0, 9), (9, 10), (10, 11), (11, 12), + (0, 13), (13, 14), (14, 15), (15, 16), + (0, 17), (17, 18), (18, 19), (19, 20), +) +HAND_SLICES = {"left": (91, 112), "right": (112, 133)} +BODY_WRISTS = {"left": 9, "right": 10} + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--video", type=Path, required=True) + parser.add_argument("--boxes", type=Path, required=True) + parser.add_argument("--model-m", type=Path, required=True) + parser.add_argument("--model-l", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument("--max-people", type=int, default=2) + return parser.parse_args() + + +def load_boxes(path: Path, max_people: int) -> dict[int, list[list[float]]]: + frames: dict[int, list[list[float]]] = {} + with path.open("r", encoding="utf-8") as handle: + for line in handle: + item = json.loads(line) + boxes = [entry["xyxy"] for entry in item["boxes"]] + frames[int(item["frame_index"])] = sorted(boxes, key=lambda b: b[0])[:max_people] + return frames + + +def point(pt: np.ndarray) -> tuple[int, int]: + return int(round(float(pt[0]))), int(round(float(pt[1]))) + + +def draw_pose( + image: np.ndarray, + boxes: list[list[float]], + keypoints: np.ndarray, + title: str, +) -> np.ndarray: + canvas = image.copy() + for person_idx, (bbox, kpts) in enumerate(zip(boxes, keypoints), start=1): + x1, y1, x2, y2 = (int(round(value)) for value in bbox) + cv2.rectangle(canvas, (x1, y1), (x2, y2), (0, 220, 255), 2) + cv2.putText( + canvas, + f"P{person_idx}", + (x1 + 4, max(22, y1 + 24)), + cv2.FONT_HERSHEY_SIMPLEX, + 0.75, + (0, 220, 255), + 2, + cv2.LINE_AA, + ) + + for edge_idx, (a, b) in enumerate(BODY_EDGES): + color = (40, 40, 255) if edge_idx < 2 else (30, 230, 30) + cv2.line(canvas, point(kpts[a]), point(kpts[b]), color, 3, cv2.LINE_AA) + for idx in (5, 6, 7, 8, 9, 10): + color = (40, 40, 255) if idx in (5, 7, 9) else (30, 230, 30) + cv2.circle(canvas, point(kpts[idx]), 5, color, -1, cv2.LINE_AA) + + for side, (start, end) in HAND_SLICES.items(): + hand = kpts[start:end] + color = (255, 80, 220) if side == "left" else (255, 190, 40) + for a, b in HAND_EDGES_LOCAL: + cv2.line(canvas, point(hand[a]), point(hand[b]), color, 2, cv2.LINE_AA) + for hand_point in hand: + cv2.circle(canvas, point(hand_point), 2, color, -1, cv2.LINE_AA) + + cv2.rectangle(canvas, (0, 0), (610, 45), (0, 0, 0), -1) + cv2.putText( + canvas, + title, + (10, 31), + cv2.FONT_HERSHEY_SIMPLEX, + 0.8, + (255, 255, 255), + 2, + cv2.LINE_AA, + ) + return canvas + + +def normalized_keypoints(kpts: np.ndarray, bbox: list[float]) -> np.ndarray: + x1, y1, x2, y2 = bbox + width = max(x2 - x1, 1.0) + height = max(y2 - y1, 1.0) + result = kpts.copy().astype(np.float64) + result[:, 0] = (result[:, 0] - x1) / width + result[:, 1] = (result[:, 1] - y1) / height + return result + + +def hand_span(kpts: np.ndarray, bbox: list[float], side: str) -> float: + start, end = HAND_SLICES[side] + hand = kpts[start:end] + span = math.hypot( + float(np.ptp(hand[:, 0])), + float(np.ptp(hand[:, 1])), + ) + x1, y1, x2, y2 = bbox + return span / max(math.hypot(x2 - x1, y2 - y1), 1.0) + + +def summarize(values: list[float]) -> dict[str, float | int | None]: + if not values: + return {"count": 0, "median": None, "p95": None, "max": None} + array = np.asarray(values, dtype=np.float64) + return { + "count": int(array.size), + "median": round(float(np.median(array)), 5), + "p95": round(float(np.percentile(array, 95)), 5), + "max": round(float(np.max(array)), 5), + } + + +def temporal_metrics(records: list[dict]) -> dict: + by_model_person: dict[tuple[str, int], list[dict]] = defaultdict(list) + for record in records: + for model_name in ("M", "L"): + for person_idx in range(len(record[model_name]["keypoints"])): + by_model_person[(model_name, person_idx)].append( + { + "frame": record["frame_index"], + "bbox": record["boxes"][person_idx], + "kpts": np.asarray( + record[model_name]["keypoints"][person_idx], dtype=np.float64 + ), + } + ) + + result: dict[str, dict] = {"M": {}, "L": {}} + for (model_name, person_idx), sequence in by_model_person.items(): + upper_steps: list[float] = [] + wrist_steps = {"left": [], "right": []} + hand_steps = {"left": [], "right": []} + hand_spans = {"left": [], "right": []} + bone_lengths = {"left_upper": [], "left_forearm": [], + "right_upper": [], "right_forearm": []} + + previous: np.ndarray | None = None + for entry in sequence: + normalized = normalized_keypoints(entry["kpts"], entry["bbox"]) + if previous is not None: + steps = np.linalg.norm(normalized - previous, axis=1) + upper_steps.extend(float(steps[idx]) for idx in (5, 6, 7, 8, 9, 10)) + for side, idx in BODY_WRISTS.items(): + wrist_steps[side].append(float(steps[idx])) + for side, (start, end) in HAND_SLICES.items(): + hand_steps[side].extend(float(value) for value in steps[start:end]) + previous = normalized + + hand_spans["left"].append(hand_span(entry["kpts"], entry["bbox"], "left")) + hand_spans["right"].append(hand_span(entry["kpts"], entry["bbox"], "right")) + bone_lengths["left_upper"].append(float(np.linalg.norm(normalized[5] - normalized[7]))) + bone_lengths["left_forearm"].append(float(np.linalg.norm(normalized[7] - normalized[9]))) + bone_lengths["right_upper"].append(float(np.linalg.norm(normalized[6] - normalized[8]))) + bone_lengths["right_forearm"].append(float(np.linalg.norm(normalized[8] - normalized[10]))) + + span_summary = {} + for side, values in hand_spans.items(): + median = float(np.median(values)) + gross_limit = max(0.2, median * 2.5) + span_summary[side] = { + **summarize(values), + "gross_limit": round(gross_limit, 5), + "gross_outlier_frames": int(sum(value > gross_limit for value in values)), + } + + bone_summary = {} + for name, values in bone_lengths.items(): + array = np.asarray(values, dtype=np.float64) + mean = float(np.mean(array)) + bone_summary[name] = { + **summarize(values), + "coefficient_of_variation": round(float(np.std(array) / max(mean, 1e-9)), 5), + } + + result[model_name][f"P{person_idx + 1}"] = { + "upper_body_frame_step": summarize(upper_steps), + "wrist_frame_step": {side: summarize(values) for side, values in wrist_steps.items()}, + "hand_landmark_frame_step": { + side: summarize(values) for side, values in hand_steps.items() + }, + "hand_span_relative_to_person": span_summary, + "bone_length_relative_to_box": bone_summary, + } + return result + + +def model_disagreement(records: list[dict]) -> tuple[dict, list[int]]: + values: dict[str, list[float]] = defaultdict(list) + per_frame: list[tuple[float, int]] = [] + for record in records: + frame_max = 0.0 + for person_idx, bbox in enumerate(record["boxes"]): + m = normalized_keypoints( + np.asarray(record["M"]["keypoints"][person_idx]), bbox + ) + l = normalized_keypoints( + np.asarray(record["L"]["keypoints"][person_idx]), bbox + ) + distance = np.linalg.norm(m - l, axis=1) + values[f"P{person_idx + 1}_upper"].extend( + float(distance[idx]) for idx in (5, 6, 7, 8, 9, 10) + ) + for side, idx in BODY_WRISTS.items(): + values[f"P{person_idx + 1}_{side}_wrist"].append(float(distance[idx])) + frame_max = max(frame_max, float(np.max(distance[[5, 6, 7, 8, 9, 10]]))) + per_frame.append((frame_max, record["frame_index"])) + worst_frames = [frame for _, frame in sorted(per_frame, reverse=True)[:12]] + return {name: summarize(items) for name, items in values.items()}, worst_frames + + +def write_montage( + video_path: Path, + records: list[dict], + selected_frames: list[int], + output_path: Path, + titles: tuple[str, str] = ("RTMW-M 256x192", "RTMW-L 384x288"), +) -> None: + selected = set(selected_frames) + record_map = {record["frame_index"]: record for record in records} + cap = cv2.VideoCapture(str(video_path)) + rows: list[np.ndarray] = [] + frame_idx = 0 + while True: + ok, frame = cap.read() + if not ok: + break + if frame_idx in selected: + record = record_map[frame_idx] + m = draw_pose( + frame, + record["boxes"], + np.asarray(record["M"]["keypoints"]), + f"{titles[0]} | frame {frame_idx}", + ) + l = draw_pose( + frame, + record["boxes"], + np.asarray(record["L"]["keypoints"]), + f"{titles[1]} | frame {frame_idx}", + ) + m = cv2.resize(m, (640, 360), interpolation=cv2.INTER_AREA) + l = cv2.resize(l, (640, 360), interpolation=cv2.INTER_AREA) + rows.append(np.hstack([m, l])) + frame_idx += 1 + cap.release() + if rows: + cv2.imwrite(str(output_path), np.vstack(rows)) + + +def main() -> None: + from rtmlib import RTMPose + args = parse_args() + args.output.mkdir(parents=True, exist_ok=True) + cached_boxes = load_boxes(args.boxes, args.max_people) + + pose_m = RTMPose( + str(args.model_m), model_input_size=(192, 256), backend="onnxruntime", device="cpu" + ) + pose_l = RTMPose( + str(args.model_l), model_input_size=(288, 384), backend="onnxruntime", device="cpu" + ) + + cap = cv2.VideoCapture(str(args.video)) + fps = float(cap.get(cv2.CAP_PROP_FPS)) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + video_output = args.output / "reference_video_rtmw_m_vs_l.mp4" + writer = cv2.VideoWriter( + str(video_output), + cv2.VideoWriter_fourcc(*"mp4v"), + fps, + (width, height // 2), + ) + + records: list[dict] = [] + timings = {"M": [], "L": []} + frame_idx = 0 + while True: + ok, frame = cap.read() + if not ok: + break + boxes = cached_boxes[frame_idx] + + started = time.perf_counter() + kpts_m, scores_m = pose_m(frame, bboxes=boxes) + timings["M"].append((time.perf_counter() - started) * 1000.0) + + started = time.perf_counter() + kpts_l, scores_l = pose_l(frame, bboxes=boxes) + timings["L"].append((time.perf_counter() - started) * 1000.0) + + records.append( + { + "frame_index": frame_idx, + "boxes": boxes, + "M": { + "keypoints": np.round(kpts_m, 3).tolist(), + "raw_scores": np.round(scores_m, 4).tolist(), + }, + "L": { + "keypoints": np.round(kpts_l, 3).tolist(), + "raw_scores": np.round(scores_l, 4).tolist(), + }, + } + ) + + left = draw_pose(frame, boxes, kpts_m, f"RTMW-M 256x192 | frame {frame_idx}") + right = draw_pose(frame, boxes, kpts_l, f"RTMW-L 384x288 | frame {frame_idx}") + left = cv2.resize(left, (width // 2, height // 2), interpolation=cv2.INTER_AREA) + right = cv2.resize(right, (width // 2, height // 2), interpolation=cv2.INTER_AREA) + writer.write(np.hstack([left, right])) + + if frame_idx % 50 == 0: + print(f"processed frame {frame_idx}", flush=True) + frame_idx += 1 + + cap.release() + writer.release() + + jsonl_path = args.output / "reference_video_rtmw_m_vs_l.jsonl" + with jsonl_path.open("w", encoding="utf-8") as handle: + for record in records: + handle.write(json.dumps(record, ensure_ascii=False) + "\n") + + disagreement, worst_frames = model_disagreement(records) + fixed_frames = [0, 60, 120, 180, 240, 252, 300, 360, 411] + montage_frames = sorted(set(fixed_frames + worst_frames)) + write_montage( + args.video, + records, + montage_frames, + args.output / "rtmw_m_vs_l_full_montage.jpg", + ) + + summary = { + "frames": len(records), + "input_sizes_wh": {"M": [192, 256], "L": [288, 384]}, + "raw_score_note": ( + "M and L raw SimCC peak scores use different scales and must not be compared " + "or thresholded with the same numeric value." + ), + "timing_ms_two_people_cpu": { + name: summarize(values[5:] if len(values) > 5 else values) + for name, values in timings.items() + }, + "temporal_metrics_normalized_to_yolo_box": temporal_metrics(records), + "m_l_position_disagreement_normalized_to_yolo_box": disagreement, + "largest_upper_body_disagreement_frames": worst_frames, + "montage_frames": montage_frames, + } + with (args.output / "summary.json").open("w", encoding="utf-8") as handle: + json.dump(summary, handle, ensure_ascii=False, indent=2) + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/pipeline/door_mask_risk.py b/pipeline/door_mask_risk.py new file mode 100644 index 0000000..49eeec5 --- /dev/null +++ b/pipeline/door_mask_risk.py @@ -0,0 +1,488 @@ +"""Per-frame door-mask loading and YOLO/RTMW-only 2-D risk scoring.""" + +from __future__ import annotations + +import json +import math +import re +import time +from collections import Counter +from dataclasses import dataclass +from pathlib import Path + +import cv2 +import numpy as np + + +RASTER_SUFFIXES = {".png", ".bmp", ".tif", ".tiff"} +DEFAULT_DOOR_LABELS = ("door", "车门") + + +@dataclass +class LoadedDoorMask: + status: str + annotation_index: int + path: Path | None + mask: np.ndarray | None + source_format: str | None + + def metadata(self) -> dict: + return { + "status": self.status, + "annotation_index": self.annotation_index, + "path": str(self.path.resolve()) if self.path is not None else None, + "format": self.source_format, + "area_px": int(np.count_nonzero(self.mask)) if self.mask is not None else 0, + } + + +def _frame_index_from_path(path: Path) -> int | None: + matches = re.findall(r"\d+", path.stem) + return int(matches[-1]) if matches else None + + +class DoorMaskSequence: + """Index a directory of X-AnyLabeling JSON polygons or raster masks.""" + + def __init__( + self, + directory: Path | None = None, + mask_format: str = "auto", + labels: tuple[str, ...] = DEFAULT_DOOR_LABELS, + frame_offset: int = 0, + require_every_frame: bool = False, + constant_mask: Path | None = None, + ): + if (directory is None) == (constant_mask is None): + raise ValueError("Provide exactly one of directory or constant_mask") + self.constant_path = ( + Path(constant_mask).expanduser().resolve() + if constant_mask is not None + else None + ) + self.directory = ( + self.constant_path.parent if self.constant_path is not None else Path(directory) + ) + if self.constant_path is not None and not self.constant_path.is_file(): + raise ValueError(f"Constant door mask does not exist: {self.constant_path}") + if self.constant_path is None and not self.directory.is_dir(): + raise ValueError(f"Door mask directory does not exist: {self.directory}") + self.labels = {label.casefold() for label in labels} + self.frame_offset = int(frame_offset) + self.require_every_frame = require_every_frame + + if self.constant_path is not None: + if mask_format == "auto": + selected_format = ( + "xanylabeling" + if self.constant_path.suffix.lower() == ".json" + else "raster" + ) + else: + selected_format = mask_format + self.source_format = selected_format + self.paths = {0: self.constant_path} + return + + json_paths = sorted(self.directory.rglob("*.json")) + raster_paths = sorted( + path + for path in self.directory.rglob("*") + if path.is_file() and path.suffix.lower() in RASTER_SUFFIXES + ) + if mask_format == "auto": + selected_format = "xanylabeling" if json_paths else "raster" + else: + selected_format = mask_format + candidates = json_paths if selected_format == "xanylabeling" else raster_paths + if not candidates: + expected = "JSON" if selected_format == "xanylabeling" else "PNG/BMP/TIFF" + raise ValueError(f"No {expected} door masks found in {self.directory}") + + self.source_format = selected_format + self.paths: dict[int, Path] = {} + for path in candidates: + index = _frame_index_from_path(path) + if index is None and selected_format == "xanylabeling": + data = json.loads(path.read_text(encoding="utf-8-sig")) + explicit = data.get("frame_index", data.get("frameIndex")) + index = int(explicit) if explicit is not None else None + if index is None: + continue + if index in self.paths: + raise ValueError( + f"Multiple door masks map to annotation frame {index}: " + f"{self.paths[index]} and {path}" + ) + self.paths[index] = path + if not self.paths: + raise ValueError( + "Door mask filenames need a frame number, for example 000000.json" + ) + + def load(self, video_frame_index: int, frame_shape: tuple[int, int]) -> LoadedDoorMask: + if self.constant_path is not None: + annotation_index = video_frame_index + path = self.constant_path + else: + annotation_index = video_frame_index + self.frame_offset + path = self.paths.get(annotation_index) + if path is None: + if self.require_every_frame: + raise RuntimeError( + f"No door mask for video frame {video_frame_index} " + f"(expected annotation index {annotation_index})" + ) + return LoadedDoorMask("missing", annotation_index, None, None, self.source_format) + + if self.source_format == "xanylabeling": + mask = self._load_xanylabeling(path, frame_shape) + else: + mask = self._load_raster(path, frame_shape) + status = "loaded" if np.any(mask) else "empty" + return LoadedDoorMask(status, annotation_index, path, mask, self.source_format) + + @staticmethod + def _load_raster(path: Path, frame_shape: tuple[int, int]) -> np.ndarray: + image = cv2.imread(str(path), cv2.IMREAD_UNCHANGED) + if image is None: + raise RuntimeError(f"Cannot read door mask: {path}") + if image.ndim == 3: + image = np.max(image[:, :, :3], axis=2) + height, width = frame_shape + if image.shape != (height, width): + image = cv2.resize(image, (width, height), interpolation=cv2.INTER_NEAREST) + return image > 0 + + def _load_xanylabeling( + self, path: Path, frame_shape: tuple[int, int] + ) -> np.ndarray: + data = json.loads(path.read_text(encoding="utf-8-sig")) + height, width = frame_shape + source_width = float(data.get("imageWidth") or width) + source_height = float(data.get("imageHeight") or height) + scale = np.asarray( + [width / max(source_width, 1.0), height / max(source_height, 1.0)], + dtype=np.float32, + ) + mask = np.zeros((height, width), dtype=np.uint8) + for shape in data.get("shapes", []): + if str(shape.get("label", "")).casefold() not in self.labels: + continue + points = np.asarray(shape.get("points", []), dtype=np.float32).reshape(-1, 2) + if len(points) < 2: + continue + points = np.rint(points * scale).astype(np.int32) + shape_type = str(shape.get("shape_type", "polygon")).lower() + if shape_type == "rectangle" and len(points) >= 2: + x1, y1 = points[0] + x2, y2 = points[1] + cv2.rectangle(mask, (x1, y1), (x2, y2), 1, -1) + elif shape_type == "circle" and len(points) >= 2: + radius = int(round(float(np.linalg.norm(points[1] - points[0])))) + cv2.circle(mask, tuple(points[0]), radius, 1, -1) + elif len(points) >= 3: + cv2.fillPoly(mask, [points], 1) + return mask > 0 + + +def _fit_mask(mask: np.ndarray, frame_shape: tuple[int, int]) -> np.ndarray: + height, width = frame_shape + result = np.asarray(mask) > 0 + if result.shape != (height, width): + result = cv2.resize( + result.astype(np.uint8), (width, height), interpolation=cv2.INTER_NEAREST + ) > 0 + return result + + +def _box_mask(box: list[float] | None, frame_shape: tuple[int, int]) -> np.ndarray | None: + if box is None or len(box) < 4: + return None + height, width = frame_shape + x1, y1, x2, y2 = [int(round(float(value))) for value in box[:4]] + x1, x2 = sorted((max(0, min(width - 1, x1)), max(0, min(width - 1, x2)))) + y1, y2 = sorted((max(0, min(height - 1, y1)), max(0, min(height - 1, y2)))) + if x2 <= x1 or y2 <= y1: + return None + mask = np.zeros((height, width), dtype=bool) + mask[y1 : y2 + 1, x1 : x2 + 1] = True + return mask + + +def _hand_mask(points: list, frame_shape: tuple[int, int]) -> np.ndarray | None: + hand = np.asarray(points, dtype=np.float32).reshape(-1, 2) + if len(hand) < 3 or not np.isfinite(hand).all(): + return None + hull = cv2.convexHull(np.rint(hand).astype(np.int32)) + mask = np.zeros(frame_shape, dtype=np.uint8) + cv2.fillConvexPoly(mask, hull, 1) + return mask > 0 if np.any(mask) else None + + +def _decision(distance_relative: float, overlap_px: int, warning: float, release: float) -> tuple[str, str]: + if overlap_px > 0: + return "danger", "DANGER_INTERSECTION" + if distance_relative <= warning: + return "warning", "WARNING_NEAR" + if distance_relative <= release: + return "watch", "WATCH" + return "clear", "CLEAR" + + +class DoorRiskEvaluator: + """Score RTMW hand regions, with one YOLO body-box fallback per person.""" + + def __init__( + self, + sequence: DoorMaskSequence, + warning_relative: float = 0.30, + release_relative: float = 0.45, + ): + if warning_relative < 0 or release_relative <= warning_relative: + raise ValueError("Risk thresholds require 0 <= warning < release") + self.sequence = sequence + self.warning_relative = float(warning_relative) + self.release_relative = float(release_relative) + self.mask_status_counts: Counter = Counter() + self.level_counts: Counter = Counter() + self.source_counts: Counter = Counter() + self.maximum_score = 0.0 + self.timing_seconds: Counter = Counter() + self.timing_counts: Counter = Counter() + self._constant_cache_shape: tuple[int, int] | None = None + self._constant_loaded: LoadedDoorMask | None = None + self._constant_distance_map: np.ndarray | None = None + self.distance_map_cache_builds = 0 + + def _record_timing(self, name: str, started: float) -> None: + self.timing_seconds[name] += time.perf_counter() - started + self.timing_counts[name] += 1 + + def _measure_region( + self, + region: np.ndarray, + door_mask: np.ndarray, + distance_map: np.ndarray, + source: str, + track_id: int, + side: str, + state: str | None, + ) -> dict: + area_px = int(np.count_nonzero(region)) + overlap_px = int(np.count_nonzero(region & door_mask)) + distances = distance_map[region] + distance_px = float(np.min(distances)) if len(distances) else math.inf + scale_px = max(math.sqrt(area_px), 1.0) + distance_relative = distance_px / scale_px + score = float(np.clip(1.0 - distance_relative / self.release_relative, 0.0, 1.0)) + if overlap_px: + score = 1.0 + level, decision = _decision( + distance_relative, + overlap_px, + self.warning_relative, + self.release_relative, + ) + result = { + "status": "calculated", + "risk_score": round(score, 5), + "risk_level": level, + "decision": decision, + "source": source, + "track_id": int(track_id), + "side": side, + "state": state, + "region_area_px": area_px, + "door_overlap_px": overlap_px, + "region_overlap_ratio": round(overlap_px / max(area_px, 1), 6), + "min_distance_px": round(distance_px, 3), + "region_scale_px": round(scale_px, 3), + "distance_relative": round(distance_relative, 6), + } + self.level_counts[level] += 1 + self.source_counts[source] += 1 + self.maximum_score = max(self.maximum_score, score) + return result + + @staticmethod + def _unavailable(source: str, track_id: int, side: str, status: str) -> dict: + return { + "status": status, + "risk_score": None, + "risk_level": "unavailable", + "decision": "EVIDENCE_UNAVAILABLE", + "source": source, + "track_id": int(track_id), + "side": side, + } + + def evaluate( + self, + frame_index: int, + record: dict, + frame_shape: tuple[int, int], + ) -> tuple[dict, np.ndarray | None]: + total_started = time.perf_counter() + stage_started = time.perf_counter() + use_constant_cache = self.sequence.constant_path is not None + if use_constant_cache and self._constant_cache_shape == frame_shape: + cached = self._constant_loaded + assert cached is not None + loaded = LoadedDoorMask( + cached.status, + frame_index, + cached.path, + cached.mask, + cached.source_format, + ) + else: + loaded = self.sequence.load(frame_index, frame_shape) + if use_constant_cache: + self._constant_cache_shape = frame_shape + self._constant_loaded = loaded + self._constant_distance_map = None + self._record_timing("door_mask_load", stage_started) + self.mask_status_counts[loaded.status] += 1 + mask_ready = loaded.status == "loaded" and loaded.mask is not None + door_mask = loaded.mask if mask_ready else None + distance_map = None + if door_mask is not None and use_constant_cache and self._constant_distance_map is not None: + distance_map = self._constant_distance_map + elif door_mask is not None: + stage_started = time.perf_counter() + distance_map = cv2.distanceTransform( + (~door_mask).astype(np.uint8), cv2.DIST_L2, cv2.DIST_MASK_PRECISE + ) + self._record_timing("distance_transform", stage_started) + if use_constant_cache: + self._constant_distance_map = distance_map + self.distance_map_cache_builds += 1 + + stage_started = time.perf_counter() + regions: list[tuple[dict, np.ndarray, str, int, str, str | None]] = [] + track_ids = [int(value) for value in record.get("track_ids", [])] + person_positions_with_hands: set[int] = set() + for hand in record.get("global_hands", []): + position = int(hand.get("person_id", 0)) - 1 + track_id = track_ids[position] if 0 <= position < len(track_ids) else position + 1 + side = str(hand.get("side", "unknown")) + region = _hand_mask(hand.get("keypoints", []), frame_shape) + if region is None: + continue + person_positions_with_hands.add(position) + regions.append( + ( + hand, + region, + "RTMW_HAND_KEYPOINTS", + track_id, + side, + str(hand.get("state", "unknown")), + ) + ) + + boxes = record.get("boxes", []) + body_fallbacks = [] + for position, box in enumerate(boxes): + if position in person_positions_with_hands: + continue + region = _box_mask(box, frame_shape) + if region is None: + continue + track_id = track_ids[position] if position < len(track_ids) else position + 1 + fallback = { + "track_id": track_id, + "side": "body", + "state": "rtmw_hand_unavailable", + "body_zone_box": box, + } + body_fallbacks.append(fallback) + regions.append( + ( + fallback, + region, + "YOLO_BODY_BOX_FALLBACK", + track_id, + "body", + "rtmw_hand_unavailable", + ) + ) + record["body_fallbacks"] = body_fallbacks + self._record_timing("region_build", stage_started) + + stage_started = time.perf_counter() + measurements = [] + unavailable_status = f"door_mask_{loaded.status}" + for owner, region, source, track_id, side, state in regions: + if door_mask is None or distance_map is None: + measurement = self._unavailable( + source, track_id, side, unavailable_status + ) + else: + measurement = self._measure_region( + region, door_mask, distance_map, source, track_id, side, state + ) + owner["risk"] = measurement + measurements.append(measurement) + self._record_timing("region_measure", stage_started) + + calculated = [item for item in measurements if item["risk_score"] is not None] + nearest = max(calculated, key=lambda item: item["risk_score"]) if calculated else None + if loaded.status != "loaded": + status = unavailable_status + elif not calculated: + status = "person_region_missing" + else: + status = "calculated" + frame_risk = { + "status": status, + "risk_score": nearest["risk_score"] if nearest else None, + "risk_level": nearest["risk_level"] if nearest else "unavailable", + "decision": nearest["decision"] if nearest else "EVIDENCE_UNAVAILABLE", + "source": nearest["source"] if nearest else None, + "track_id": nearest["track_id"] if nearest else None, + "side": nearest["side"] if nearest else None, + "door_mask": loaded.metadata(), + "warning_distance_relative": self.warning_relative, + "release_distance_relative": self.release_relative, + "regions": measurements, + } + self._record_timing("risk_total", total_started) + return frame_risk, loaded.mask + + def summary(self) -> dict: + return { + "mask_directory": str(self.sequence.directory.resolve()), + "constant_mask": ( + str(self.sequence.constant_path) + if self.sequence.constant_path is not None + else None + ), + "constant_for_all_frames": self.sequence.constant_path is not None, + "mask_format": self.sequence.source_format, + "door_labels": sorted(self.sequence.labels), + "frame_offset": self.sequence.frame_offset, + "warning_distance_relative": self.warning_relative, + "release_distance_relative": self.release_relative, + "mask_status_counts": dict(self.mask_status_counts), + "risk_level_counts": dict(self.level_counts), + "source_counts": dict(self.source_counts), + "maximum_risk_score": round(self.maximum_score, 5), + "constant_distance_map_cached": self.sequence.constant_path is not None, + "distance_map_cache_builds": self.distance_map_cache_builds, + "timing_ms": { + name: { + "count": int(self.timing_counts[name]), + "total": round(float(seconds) * 1000.0, 3), + "mean": round( + float(seconds) * 1000.0 + / max(int(self.timing_counts[name]), 1), + 3, + ), + } + for name, seconds in self.timing_seconds.items() + }, + "score_semantics": "2-D image overlap/proximity research score; not millimeters or safety certification", + "region_policy": "RTMW alarm-eligible hand hulls; YOLO body box only when a person has no usable RTMW hand region", + } diff --git a/pipeline/door_zone_risk.py b/pipeline/door_zone_risk.py new file mode 100644 index 0000000..972cfb7 --- /dev/null +++ b/pipeline/door_zone_risk.py @@ -0,0 +1,358 @@ +"""Multi-feature person-to-door assignment and active-CAN risk gating.""" + +from __future__ import annotations + +import json +import math +from collections import Counter, defaultdict, deque +from dataclasses import dataclass +from pathlib import Path +from statistics import median + + +DOORS = ("front", "rear") +POSE_FEATURES = { + "shoulder_center_x", + "shoulder_center_y", + "shoulder_width", + "torso_height", + "hip_center_y", +} + + +@dataclass(frozen=True) +class FeatureCalibration: + rear: float + front: float + weight: float + + def frontness(self, value: float) -> float: + span = self.front - self.rear + if span == 0: + return 0.5 + return min(1.0, max(0.0, (value - self.rear) / span)) + + +@dataclass(frozen=True) +class DoorZoneConfig: + features: dict[str, FeatureCalibration] + front_probability_min: float + rear_probability_max: float + minimum_person_height: float + minimum_pose_features: int + history_frames: int + stale_track_frames: int + source_path: Path | None = None + + @classmethod + def load(cls, path: Path) -> "DoorZoneConfig": + source = Path(path).expanduser().resolve() + data = json.loads(source.read_text(encoding="utf-8-sig")) + features = { + name: FeatureCalibration( + rear=float(values["rear"]), + front=float(values["front"]), + weight=float(values["weight"]), + ) + for name, values in data["features"].items() + } + return cls( + features=features, + front_probability_min=float(data.get("front_probability_min", 0.72)), + rear_probability_max=float(data.get("rear_probability_max", 0.28)), + minimum_person_height=float(data.get("minimum_person_height", 0.40)), + minimum_pose_features=int(data.get("minimum_pose_features", 4)), + history_frames=int(data.get("history_frames", 5)), + stale_track_frames=int(data.get("stale_track_frames", 120)), + source_path=source, + ) + + def classify(self, probability: float) -> str: + if probability >= self.front_probability_min: + return "front" + if probability <= self.rear_probability_max: + return "rear" + return "transition" + + +def _point(keypoints: list, index: int) -> tuple[float, float] | None: + if index >= len(keypoints) or len(keypoints[index]) < 2: + return None + x, y = float(keypoints[index][0]), float(keypoints[index][1]) + return (x, y) if math.isfinite(x) and math.isfinite(y) else None + + +def extract_person_features( + record: dict, + position: int, + frame_shape: tuple[int, int], +) -> tuple[dict[str, float], int]: + """Extract fixed-camera pose features, with box geometry as low-weight fallback.""" + + height, width = frame_shape + box = record.get("boxes", [])[position] + x1, y1, x2, y2 = [float(value) for value in box[:4]] + features = { + "box_center_x": ((x1 + x2) * 0.5) / max(width, 1), + "box_height": (y2 - y1) / max(height, 1), + } + + all_keypoints = record.get("temporal_selected_keypoints", []) + if position >= len(all_keypoints): + return features, 0 + keypoints = all_keypoints[position] + left_shoulder = _point(keypoints, 5) + right_shoulder = _point(keypoints, 6) + left_hip = _point(keypoints, 11) + right_hip = _point(keypoints, 12) + if None in (left_shoulder, right_shoulder, left_hip, right_hip): + return features, 0 + + shoulder_x = (left_shoulder[0] + right_shoulder[0]) * 0.5 + shoulder_y = (left_shoulder[1] + right_shoulder[1]) * 0.5 + hip_y = (left_hip[1] + right_hip[1]) * 0.5 + features.update( + { + "shoulder_center_x": shoulder_x / max(width, 1), + "shoulder_center_y": shoulder_y / max(height, 1), + "shoulder_width": math.hypot( + left_shoulder[0] - right_shoulder[0], + left_shoulder[1] - right_shoulder[1], + ) + / max(width, 1), + "torso_height": abs(hip_y - shoulder_y) / max(height, 1), + "hip_center_y": hip_y / max(height, 1), + } + ) + return features, len(POSE_FEATURES) + + +class DoorZoneAssigner: + """Fuse pose-dominant evidence and smooth front probability per track.""" + + def __init__(self, config: DoorZoneConfig): + self.config = config + self.history: dict[int, deque[float]] = defaultdict( + lambda: deque(maxlen=self.config.history_frames) + ) + self.last_seen: dict[int, int] = {} + self.zone_counts: Counter = Counter() + + def _score(self, features: dict[str, float]) -> tuple[float, dict[str, float]]: + weighted_sum = 0.0 + total_weight = 0.0 + contributions = {} + for name, calibration in self.config.features.items(): + if name not in features: + continue + frontness = calibration.frontness(float(features[name])) + contributions[name] = round(frontness, 6) + weighted_sum += frontness * calibration.weight + total_weight += calibration.weight + probability = weighted_sum / total_weight if total_weight else 0.5 + return probability, contributions + + def update( + self, + frame_index: int, + record: dict, + frame_shape: tuple[int, int], + ) -> list[dict]: + track_ids = [int(value) for value in record.get("track_ids", [])] + assignments = [] + for position, _box in enumerate(record.get("boxes", [])): + track_id = track_ids[position] if position < len(track_ids) else position + 1 + features, pose_feature_count = extract_person_features( + record, position, frame_shape + ) + probability, contributions = self._score(features) + enough_pose = pose_feature_count >= self.config.minimum_pose_features + if features["box_height"] < self.config.minimum_person_height: + raw_zone = "unassigned" + door_zone = "unassigned" + elif not enough_pose: + raw_zone = "transition" + door_zone = "transition" + else: + raw_zone = self.config.classify(probability) + values = self.history[track_id] + values.append(probability) + door_zone = self.config.classify(float(median(values))) + + values = self.history.get(track_id, ()) + smoothed_probability = ( + float(median(values)) if values else float(probability) + ) + self.last_seen[track_id] = int(frame_index) + self.zone_counts[door_zone] += 1 + assignments.append( + { + "track_id": track_id, + "person_index": position, + "door_zone": door_zone, + "raw_door_zone": raw_zone, + "front_probability": round(float(probability), 6), + "smoothed_front_probability": round(smoothed_probability, 6), + "confidence": round(abs(smoothed_probability - 0.5) * 2.0, 6), + "evidence_source": "pose_primary_bbox_secondary", + "pose_feature_count": pose_feature_count, + "features": {name: round(value, 6) for name, value in features.items()}, + "feature_frontness": contributions, + "history_frames": len(values), + } + ) + + expired = [ + track_id + for track_id, seen_at in self.last_seen.items() + if frame_index - seen_at > self.config.stale_track_frames + ] + for track_id in expired: + self.history.pop(track_id, None) + self.last_seen.pop(track_id, None) + return assignments + + def summary(self) -> dict: + return { + "policy": "pose-primary weighted front probability with causal median", + "config": str(self.config.source_path) if self.config.source_path else None, + "history_frames": self.config.history_frames, + "front_probability_min": self.config.front_probability_min, + "rear_probability_max": self.config.rear_probability_max, + "minimum_person_height": self.config.minimum_person_height, + "minimum_pose_features": self.config.minimum_pose_features, + "features": { + name: { + "rear": calibration.rear, + "front": calibration.front, + "weight": calibration.weight, + } + for name, calibration in self.config.features.items() + }, + "zone_counts": dict(self.zone_counts), + } + + +def _inactive_risk(door: str) -> dict: + return { + "door_id": door, + "status": "inactive", + "risk_score": None, + "risk_level": "inactive", + "decision": "DOOR_CAN_NOT_ACTIVE", + "risk_type": f"{door.upper()}_INACTIVE", + "source": None, + "track_id": None, + "side": None, + "regions": [], + } + + +def _clear_risk(door: str) -> dict: + return { + "door_id": door, + "status": "calculated", + "risk_score": 0.0, + "risk_level": "clear", + "decision": "CLEAR_NO_PERSON_ASSIGNED_TO_ACTIVE_DOOR", + "risk_type": f"{door.upper()}_CLEAR", + "source": None, + "track_id": None, + "side": None, + "regions": [], + } + + +def _unknown_risk(door: str, transition_regions: list[dict]) -> dict: + return { + "door_id": door, + "status": "door_zone_ambiguous", + "risk_score": None, + "risk_level": "unknown", + "decision": "EVIDENCE_UNAVAILABLE_TRANSITION_ZONE", + "risk_type": f"{door.upper()}_UNKNOWN", + "source": None, + "track_id": None, + "side": None, + "regions": transition_regions, + } + + +def build_door_risks( + raw_risk: dict, + assignments: list[dict], + active_door: str, +) -> tuple[dict[str, dict], dict]: + """Build per-door risk and select the CAN-active door result.""" + + zone_by_track = { + int(assignment["track_id"]): str(assignment["door_zone"]) + for assignment in assignments + } + annotated_regions = [] + for original in raw_risk.get("regions", []): + region = dict(original) + region["door_zone"] = zone_by_track.get(int(region.get("track_id", -1)), "unknown") + annotated_regions.append(region) + + active_doors = set(DOORS) if active_door == "both" else {active_door} + if active_door == "none": + active_doors.clear() + + door_risks: dict[str, dict] = {} + for door in DOORS: + if door not in active_doors: + door_risks[door] = _inactive_risk(door) + continue + exact = [region for region in annotated_regions if region["door_zone"] == door] + transition = [ + region for region in annotated_regions if region["door_zone"] == "transition" + ] + calculated = [region for region in exact if region.get("risk_score") is not None] + if calculated: + nearest = max(calculated, key=lambda item: float(item["risk_score"])) + level = str(nearest["risk_level"]) + if transition and level in ("clear", "watch"): + door_risks[door] = _unknown_risk(door, transition) + else: + door_risks[door] = { + "door_id": door, + "status": "calculated", + "risk_score": nearest["risk_score"], + "risk_level": level, + "decision": nearest["decision"], + "risk_type": f"{door.upper()}_{level.upper()}", + "source": nearest["source"], + "track_id": nearest["track_id"], + "side": nearest["side"], + "regions": exact, + } + elif transition: + door_risks[door] = _unknown_risk(door, transition) + else: + door_risks[door] = _clear_risk(door) + + if len(active_doors) == 1: + selected = dict(door_risks[next(iter(active_doors))]) + elif not active_doors: + selected = { + "door_id": None, + "status": "inactive", + "risk_score": None, + "risk_level": "inactive", + "decision": "NO_DOOR_CAN_ACTIVE", + "risk_type": "NO_ACTIVE_DOOR", + "source": None, + "track_id": None, + "side": None, + "regions": [], + } + else: + severity = {"danger": 4, "warning": 3, "watch": 2, "unknown": 1, "clear": 0} + selected = dict( + max(door_risks.values(), key=lambda item: severity.get(item["risk_level"], -1)) + ) + selected["door_mask"] = raw_risk.get("door_mask") + selected["warning_distance_relative"] = raw_risk.get("warning_distance_relative") + selected["release_distance_relative"] = raw_risk.get("release_distance_relative") + return door_risks, selected diff --git a/pipeline/fuse_rtmw_l_temporal.py b/pipeline/fuse_rtmw_l_temporal.py new file mode 100644 index 0000000..f212589 --- /dev/null +++ b/pipeline/fuse_rtmw_l_temporal.py @@ -0,0 +1,855 @@ +"""Fuse raw and person-isolated RTMW-L poses with temporal consistency. + +The fusion keeps the two inference views as hypotheses. It selects body limbs +and hands separately, rejects implausible hand geometry, adds source hysteresis +and constant-velocity consistency, then applies a motion-adaptive EMA in +person-box coordinates. Occluded/conflicting limbs remain labelled as such so +they are not accidentally consumed as precise anti-pinch distance evidence. +""" + +from __future__ import annotations + +import argparse +import json +import math +from collections import Counter, defaultdict +from dataclasses import dataclass, field +from pathlib import Path + +import cv2 +import numpy as np + +from compare_rtmw_ml import ( + BODY_EDGES, + BODY_WRISTS, + HAND_EDGES_LOCAL, + HAND_SLICES, + draw_pose, + normalized_keypoints, + summarize, + temporal_metrics, +) + + +BODY_SIDE_INDICES = {"left": (5, 7, 9), "right": (6, 8, 10)} +SIDE_COLORS = {"left": (40, 40, 255), "right": (30, 230, 30)} +HAND_COLORS = {"left": (255, 80, 220), "right": (255, 190, 40)} + + +@dataclass +class Candidate: + source: str + keypoints: np.ndarray + scores: np.ndarray + normalized: np.ndarray + limb_score: float + hand_score: float + upper_length: float + forearm_length: float + hand_span: float + wrist_link: float + limb_valid: bool + hand_valid: bool + + +@dataclass +class SideTrack: + limb_previous: np.ndarray | None = None + limb_velocity: np.ndarray | None = None + hand_previous: np.ndarray | None = None + hand_velocity: np.ndarray | None = None + limb_source: str | None = None + hand_source: str | None = None + previous_hand_eligible: bool = False + + +@dataclass +class PersonTrack: + sides: dict[str, SideTrack] = field( + default_factory=lambda: {"left": SideTrack(), "right": SideTrack()} + ) + smoothed: np.ndarray | None = None + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--video", type=Path, required=True) + parser.add_argument("--raw-jsonl", type=Path, required=True) + parser.add_argument("--isolated-jsonl", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + return parser.parse_args() + + +def bbox_diagonal(bbox: list[float]) -> float: + return max(math.hypot(bbox[2] - bbox[0], bbox[3] - bbox[1]), 1.0) + + +def build_candidate( + source: str, + keypoints: np.ndarray, + scores: np.ndarray, + bbox: list[float], + side: str, +) -> Candidate: + normalized = normalized_keypoints(keypoints, bbox) + shoulder, elbow, wrist = BODY_SIDE_INDICES[side] + hand_start, hand_end = HAND_SLICES[side] + hand = keypoints[hand_start:hand_end] + diagonal = bbox_diagonal(bbox) + upper_length = float(np.linalg.norm(normalized[shoulder] - normalized[elbow])) + forearm_length = float(np.linalg.norm(normalized[elbow] - normalized[wrist])) + hand_span = math.hypot(float(np.ptp(hand[:, 0])), float(np.ptp(hand[:, 1]))) / diagonal + wrist_link = float(np.linalg.norm(keypoints[wrist] - hand[0])) / diagonal + limb_score = float(np.mean(scores[[shoulder, elbow, wrist]])) + hand_score = float(np.mean(scores[hand_start:hand_end])) + limb_valid = 0.025 <= upper_length <= 0.8 and 0.025 <= forearm_length <= 0.8 + hand_valid = 0.008 <= hand_span <= 0.35 and wrist_link <= 0.12 + return Candidate( + source=source, + keypoints=keypoints, + scores=scores, + normalized=normalized, + limb_score=limb_score, + hand_score=hand_score, + upper_length=upper_length, + forearm_length=forearm_length, + hand_span=hand_span, + wrist_link=wrist_link, + limb_valid=limb_valid, + hand_valid=hand_valid, + ) + + +def predicted(previous: np.ndarray | None, velocity: np.ndarray | None) -> np.ndarray | None: + if previous is None: + return None + if velocity is None: + return previous + return previous + 0.65 * velocity + + +def robust_distance(points: np.ndarray, target: np.ndarray | None) -> float: + if target is None: + return 0.0 + distances = np.linalg.norm(points - target, axis=1) + return float(np.median(distances)) + + +def select_limb( + candidates: list[Candidate], + side: str, + track: SideTrack | None, +) -> tuple[Candidate, dict[str, float]]: + indices = np.asarray(BODY_SIDE_INDICES[side]) + target = predicted(track.limb_previous, track.limb_velocity) if track else None + scored: list[tuple[float, Candidate, float]] = [] + for candidate in candidates: + temporal_cost = robust_distance(candidate.normalized[indices], target) + geometry_bonus = 1.2 if candidate.limb_valid else -5.0 + switch_bonus = 0.35 if track and candidate.source == track.limb_source else 0.0 + score = candidate.limb_score + geometry_bonus + switch_bonus - 7.0 * temporal_cost + scored.append((score, candidate, temporal_cost)) + score, selected, temporal_cost = max(scored, key=lambda item: item[0]) + return selected, {"score": score, "temporal_cost": temporal_cost} + + +def hand_link_to_limb( + candidate: Candidate, + selected_limb: Candidate, + bbox: list[float], + side: str, +) -> float: + hand_start, _ = HAND_SLICES[side] + wrist_idx = BODY_WRISTS[side] + return float( + np.linalg.norm(candidate.keypoints[hand_start] - selected_limb.keypoints[wrist_idx]) + ) / bbox_diagonal(bbox) + + +def select_hand( + candidates: list[Candidate], + selected_limb: Candidate, + bbox: list[float], + side: str, + track: SideTrack | None, +) -> tuple[Candidate, bool, dict[str, float]]: + start, end = HAND_SLICES[side] + target = predicted(track.hand_previous, track.hand_velocity) if track else None + scored: list[tuple[float, Candidate, bool, float, float]] = [] + for candidate in candidates: + temporal_cost = robust_distance(candidate.normalized[start:end], target) + link = hand_link_to_limb(candidate, selected_limb, bbox, side) + valid = candidate.hand_valid + geometry_bonus = 3.0 if valid else -7.0 + switch_bonus = 0.45 if track and candidate.source == track.hand_source else 0.0 + limb_source_bonus = 0.15 if candidate.source == selected_limb.source else 0.0 + # A newly visible endpoint may disagree with the currently selected + # (occlusion-driven) limb. Keep this as a soft cost so strong image + # evidence can switch both the hand and its limb together. + link_penalty = 1.5 * min(max(link - 0.12, 0.0), 0.2) + score = ( + candidate.hand_score + + geometry_bonus + + switch_bonus + + limb_source_bonus + - link_penalty + - 8.0 * min(temporal_cost, 0.15) + ) + scored.append((score, candidate, valid, temporal_cost, link)) + score, selected, valid, temporal_cost, link = max(scored, key=lambda item: item[0]) + return selected, valid, { + "score": score, + "temporal_cost": temporal_cost, + "link_to_selected_limb": link, + } + + +def candidate_disagreement( + raw: Candidate, + isolated: Candidate, + side: str, +) -> tuple[float, float]: + shoulder, elbow, wrist = BODY_SIDE_INDICES[side] + start, end = HAND_SLICES[side] + limb = float( + np.median( + np.linalg.norm( + raw.normalized[[shoulder, elbow, wrist]] + - isolated.normalized[[shoulder, elbow, wrist]], + axis=1, + ) + ) + ) + hand_distances = np.linalg.norm( + raw.normalized[start:end] - isolated.normalized[start:end], axis=1 + ) + hand = float(np.percentile(hand_distances, 90)) + return limb, hand + + +def suppress_duplicate_hands( + fused: np.ndarray, + metadata: dict, + bbox: list[float], +) -> None: + left_start, left_end = HAND_SLICES["left"] + right_start, right_end = HAND_SLICES["right"] + left_center = np.mean(fused[left_start:left_end], axis=0) + right_center = np.mean(fused[right_start:right_end], axis=0) + separation = float(np.linalg.norm(left_center - right_center)) / bbox_diagonal(bbox) + if separation >= 0.08: + return + weaker = min( + ("left", "right"), + key=lambda side: metadata[side]["selected_hand_score"], + ) + metadata[weaker]["hand_state"] = "duplicate" + metadata[weaker]["distance_eligible"] = False + metadata[weaker]["alarm_eligible"] = False + metadata[weaker]["duplicate_hand_separation"] = round(separation, 5) + + +def fuse_person( + raw_keypoints: np.ndarray, + raw_scores: np.ndarray, + isolated_keypoints: np.ndarray, + isolated_scores: np.ndarray, + bbox: list[float], + track: PersonTrack | None, +) -> tuple[np.ndarray, dict]: + fused = raw_keypoints.copy() + metadata: dict[str, dict] = {} + + for side in ("left", "right"): + side_track = track.sides[side] if track else None + raw = build_candidate("raw", raw_keypoints, raw_scores, bbox, side) + isolated = build_candidate( + "isolated", isolated_keypoints, isolated_scores, bbox, side + ) + candidates = [raw, isolated] + limb, limb_detail = select_limb(candidates, side, side_track) + hand, hand_valid, hand_detail = select_hand( + candidates, limb, bbox, side, side_track + ) + + other_hand = isolated if hand.source == "raw" else raw + endpoint_advantage = hand.hand_score - other_hand.hand_score + if hand.source != limb.source and hand_valid and endpoint_advantage >= 0.6: + limb = hand + limb_detail["visible_endpoint_override"] = 1.0 + hand_detail["link_to_selected_limb"] = hand.wrist_link + + body_indices = np.asarray(BODY_SIDE_INDICES[side]) + hand_start, hand_end = HAND_SLICES[side] + fused[body_indices] = limb.keypoints[body_indices] + fused[hand_start:hand_end] = hand.keypoints[hand_start:hand_end] + + limb_disagreement, hand_disagreement = candidate_disagreement(raw, isolated, side) + if limb_disagreement <= 0.05: + limb_state = "consensus" + else: + limb_state = "inferred" + + score_advantage = raw.hand_score - isolated.hand_score + raw_temporally_stable = hand_detail["temporal_cost"] <= 0.08 + if not hand_valid: + hand_state = "rejected" + distance_eligible = False + elif hand_disagreement <= 0.06: + hand_state = "consensus" + distance_eligible = True + elif ( + hand.source == "raw" + and score_advantage >= 0.6 + and raw_temporally_stable + ): + hand_state = "visible_endpoint" + distance_eligible = True + elif hand.source == "isolated": + hand_state = "inferred" + distance_eligible = False + else: + hand_state = "conflict" + distance_eligible = False + fast_alarm_endpoint = ( + hand_valid and hand.source == "raw" and score_advantage >= 0.6 + ) + alarm_eligible = distance_eligible or fast_alarm_endpoint + + metadata[side] = { + "limb_source": limb.source, + "hand_source": hand.source, + "limb_state": limb_state, + "hand_state": hand_state, + "distance_eligible": distance_eligible, + "alarm_eligible": alarm_eligible, + "limb_disagreement": round(limb_disagreement, 5), + "hand_disagreement": round(hand_disagreement, 5), + "raw_hand_score": round(raw.hand_score, 4), + "isolated_hand_score": round(isolated.hand_score, 4), + "selected_hand_span": round(hand.hand_span, 5), + "selected_hand_score": round(hand.hand_score, 4), + "selected_hand_valid": hand_valid, + "limb_selection": {key: round(value, 5) for key, value in limb_detail.items()}, + "hand_selection": {key: round(value, 5) for key, value in hand_detail.items()}, + } + + if side_track is not None: + limb_now = limb.normalized[body_indices] + hand_now = hand.normalized[hand_start:hand_end] + if side_track.limb_previous is not None: + delta = limb_now - side_track.limb_previous + side_track.limb_velocity = ( + delta + if side_track.limb_velocity is None + else 0.65 * side_track.limb_velocity + 0.35 * delta + ) + if hand_valid: + if side_track.hand_previous is not None: + delta = hand_now - side_track.hand_previous + side_track.hand_velocity = ( + delta + if side_track.hand_velocity is None + else 0.65 * side_track.hand_velocity + 0.35 * delta + ) + side_track.hand_previous = hand_now + side_track.hand_source = hand.source + side_track.limb_previous = limb_now + side_track.limb_source = limb.source + side_track.previous_hand_eligible = distance_eligible + + suppress_duplicate_hands(fused, metadata, bbox) + return fused, metadata + + +def adaptive_smooth( + keypoints: np.ndarray, + bbox: list[float], + track: PersonTrack, +) -> np.ndarray: + normalized = normalized_keypoints(keypoints, bbox) + if track.smoothed is None: + track.smoothed = normalized + else: + displacement = np.linalg.norm(normalized - track.smoothed, axis=1) + alpha = 0.32 + 0.58 * np.clip(displacement / 0.08, 0.0, 1.0) + track.smoothed = alpha[:, None] * normalized + (1.0 - alpha[:, None]) * track.smoothed + + x1, y1, x2, y2 = bbox + result = track.smoothed.copy() + result[:, 0] = result[:, 0] * max(x2 - x1, 1.0) + x1 + result[:, 1] = result[:, 1] * max(y2 - y1, 1.0) + y1 + return result + + +def build_global_hands( + keypoints: list[np.ndarray], + metadata: list[dict], +) -> list[dict]: + candidates = [] + for person_idx, (person_keypoints, person_meta) in enumerate( + zip(keypoints, metadata), start=1 + ): + for side, (start, end) in HAND_SLICES.items(): + meta = person_meta[side] + if not meta["alarm_eligible"]: + continue + hand = person_keypoints[start:end] + span_px = math.hypot(float(np.ptp(hand[:, 0])), float(np.ptp(hand[:, 1]))) + candidates.append( + { + "person_id": person_idx, + "side": side, + "source": meta["hand_source"], + "state": meta["hand_state"], + "distance_eligible": meta["distance_eligible"], + "alarm_eligible": meta["alarm_eligible"], + "score": meta["selected_hand_score"], + "center": np.mean(hand, axis=0), + "span_px": span_px, + "keypoints": hand, + "aliases": [], + } + ) + + kept: list[dict] = [] + for candidate in sorted(candidates, key=lambda item: item["score"], reverse=True): + duplicate = None + for existing in kept: + threshold = float(np.clip(0.45 * max(candidate["span_px"], existing["span_px"]), 18, 70)) + if float(np.linalg.norm(candidate["center"] - existing["center"])) <= threshold: + duplicate = existing + break + if duplicate is None: + kept.append(candidate) + else: + duplicate["aliases"].append( + {"person_id": candidate["person_id"], "side": candidate["side"]} + ) + + return [ + { + "person_id": item["person_id"], + "side": item["side"], + "source": item["source"], + "state": item["state"], + "distance_eligible": item["distance_eligible"], + "alarm_eligible": item["alarm_eligible"], + "score": item["score"], + "center": np.round(item["center"], 3).tolist(), + "span_px": round(item["span_px"], 3), + "keypoints": np.round(item["keypoints"], 3).tolist(), + "aliases": item["aliases"], + } + for item in kept + ] + + +def draw_dashed_line( + image: np.ndarray, + start: np.ndarray, + end: np.ndarray, + color: tuple[int, int, int], + thickness: int = 2, +) -> None: + a = np.asarray(start, dtype=np.float64) + b = np.asarray(end, dtype=np.float64) + length = float(np.linalg.norm(b - a)) + if length < 1.0: + return + direction = (b - a) / length + for offset in np.arange(0.0, length, 14.0): + segment_start = a + direction * offset + segment_end = a + direction * min(offset + 8.0, length) + cv2.line( + image, + tuple(np.round(segment_start).astype(int)), + tuple(np.round(segment_end).astype(int)), + color, + thickness, + cv2.LINE_AA, + ) + + +def draw_fused( + image: np.ndarray, + boxes: list[list[float]], + keypoints: list[np.ndarray], + metadata: list[dict], + title: str, +) -> np.ndarray: + canvas = image.copy() + for person_idx, (bbox, kpts, person_meta) in enumerate( + zip(boxes, keypoints, metadata), start=1 + ): + x1, y1, x2, y2 = (int(round(value)) for value in bbox) + cv2.rectangle(canvas, (x1, y1), (x2, y2), (0, 220, 255), 2) + cv2.putText( + canvas, + f"P{person_idx}", + (x1 + 4, max(22, y1 + 24)), + cv2.FONT_HERSHEY_SIMPLEX, + 0.72, + (0, 220, 255), + 2, + cv2.LINE_AA, + ) + for side in ("left", "right"): + shoulder, elbow, wrist = BODY_SIDE_INDICES[side] + side_meta = person_meta[side] + color = SIDE_COLORS[side] + for a, b in ((shoulder, elbow), (elbow, wrist)): + if side_meta["limb_state"] == "consensus": + cv2.line( + canvas, + tuple(np.round(kpts[a]).astype(int)), + tuple(np.round(kpts[b]).astype(int)), + color, + 3, + cv2.LINE_AA, + ) + else: + draw_dashed_line(canvas, kpts[a], kpts[b], (0, 140, 255), 3) + + start, end = HAND_SLICES[side] + hand = kpts[start:end] + if side_meta["hand_state"] != "rejected": + hand_color = HAND_COLORS[side] + if not side_meta["distance_eligible"]: + hand_color = (0, 140, 255) + for a, b in HAND_EDGES_LOCAL: + if side_meta["distance_eligible"]: + cv2.line( + canvas, + tuple(np.round(hand[a]).astype(int)), + tuple(np.round(hand[b]).astype(int)), + hand_color, + 2, + cv2.LINE_AA, + ) + else: + draw_dashed_line(canvas, hand[a], hand[b], hand_color, 2) + label = ( + f"{side[0].upper()}:{side_meta['hand_state'][:4]}" + f"/{side_meta['hand_source'][0]}" + ) + label_y = max(45, y1 + (48 if side == "left" else 70)) + cv2.putText( + canvas, + label, + (x1 + 4, label_y), + cv2.FONT_HERSHEY_SIMPLEX, + 0.5, + HAND_COLORS[side] if side_meta["distance_eligible"] else (0, 140, 255), + 1, + cv2.LINE_AA, + ) + + cv2.rectangle(canvas, (0, 0), (650, 45), (0, 0, 0), -1) + cv2.putText( + canvas, + title, + (10, 31), + cv2.FONT_HERSHEY_SIMPLEX, + 0.8, + (255, 255, 255), + 2, + cv2.LINE_AA, + ) + return canvas + + +def make_montage( + video_path: Path, + records: list[dict], + selected_frames: list[int], + output_path: Path, +) -> None: + selected = set(selected_frames) + by_frame = {record["frame_index"]: record for record in records} + cap = cv2.VideoCapture(str(video_path)) + rows = [] + frame_idx = 0 + while True: + ok, frame = cap.read() + if not ok: + break + if frame_idx in selected: + record = by_frame[frame_idx] + boxes = record["boxes"] + raw = draw_pose( + frame, + boxes, + np.asarray(record["raw_keypoints"]), + f"RTMW-L raw | frame {frame_idx}", + ) + spatial = draw_fused( + frame, + boxes, + [np.asarray(points) for points in record["spatial_keypoints"]], + record["spatial_metadata"], + f"spatial fusion | frame {frame_idx}", + ) + temporal = draw_fused( + frame, + boxes, + [np.asarray(points) for points in record["temporal_keypoints"]], + record["temporal_metadata"], + f"temporal fusion | frame {frame_idx}", + ) + panels = [ + cv2.resize(panel, (480, 270), interpolation=cv2.INTER_AREA) + for panel in (raw, spatial, temporal) + ] + rows.append(np.hstack(panels)) + frame_idx += 1 + cap.release() + if rows: + cv2.imwrite(str(output_path), np.vstack(rows)) + + +def active_hand_temporal_metrics(records: list[dict], variant: str) -> dict: + values: dict[str, list[float]] = defaultdict(list) + previous: dict[tuple[int, str], tuple[int, np.ndarray]] = {} + for record in records: + for person_idx, bbox in enumerate(record["boxes"]): + kpts = normalized_keypoints( + np.asarray(record[f"{variant}_keypoints"][person_idx]), bbox + ) + meta = record[f"{variant}_metadata"][person_idx] + for side, (start, end) in HAND_SLICES.items(): + key = (person_idx, side) + if not meta[side]["distance_eligible"]: + previous.pop(key, None) + continue + prior = previous.get(key) + if prior is not None and prior[0] == record["frame_index"] - 1: + step = np.linalg.norm(kpts[start:end] - prior[1], axis=1) + values[f"P{person_idx + 1}_{side}"].extend(float(v) for v in step) + previous[key] = (record["frame_index"], kpts[start:end]) + return {name: summarize(items) for name, items in values.items()} + + +def metadata_summary(records: list[dict], variant: str) -> dict: + state_counts: Counter = Counter() + source_counts: Counter = Counter() + eligible_counts: Counter = Counter() + alarm_counts: Counter = Counter() + switches: Counter = Counter() + previous_source: dict[tuple[int, str, str], str] = {} + for record in records: + for person_idx, person_meta in enumerate(record[f"{variant}_metadata"]): + for side in ("left", "right"): + meta = person_meta[side] + key_prefix = f"P{person_idx + 1}_{side}" + state_counts[f"{key_prefix}_{meta['hand_state']}"] += 1 + source_counts[f"{key_prefix}_{meta['hand_source']}"] += 1 + if meta["distance_eligible"]: + eligible_counts[key_prefix] += 1 + if meta["alarm_eligible"]: + alarm_counts[key_prefix] += 1 + for kind in ("limb", "hand"): + source = meta[f"{kind}_source"] + key = (person_idx, side, kind) + if key in previous_source and previous_source[key] != source: + switches[f"{key_prefix}_{kind}"] += 1 + previous_source[key] = source + return { + "hand_state_counts": dict(sorted(state_counts.items())), + "source_counts": dict(sorted(source_counts.items())), + "distance_eligible_frames": dict(sorted(eligible_counts.items())), + "alarm_eligible_frames": dict(sorted(alarm_counts.items())), + "source_switches": dict(sorted(switches.items())), + } + + +def main() -> None: + args = parse_args() + args.output.mkdir(parents=True, exist_ok=True) + raw_records = [ + json.loads(line) for line in args.raw_jsonl.read_text(encoding="utf-8").splitlines() + ] + isolated_records = [ + json.loads(line) + for line in args.isolated_jsonl.read_text(encoding="utf-8").splitlines() + ] + + cap = cv2.VideoCapture(str(args.video)) + fps = float(cap.get(cv2.CAP_PROP_FPS)) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + writer = cv2.VideoWriter( + str(args.output / "rtmw_l_raw_spatial_temporal.mp4"), + cv2.VideoWriter_fourcc(*"mp4v"), + fps, + (1920, 360), + ) + + tracks = [PersonTrack(), PersonTrack()] + output_records: list[dict] = [] + frame_idx = 0 + while True: + ok, frame = cap.read() + if not ok: + break + raw_record = raw_records[frame_idx] + isolated_record = isolated_records[frame_idx] + boxes = raw_record["boxes"][:2] + raw_keypoints = np.asarray(raw_record["L"]["keypoints"][:2], dtype=np.float64) + raw_scores = np.asarray(raw_record["L"]["raw_scores"][:2], dtype=np.float64) + isolated_keypoints = np.asarray( + isolated_record["L"]["keypoints"][:2], dtype=np.float64 + ) + isolated_scores = np.asarray( + isolated_record["masked_raw_scores"][:2], dtype=np.float64 + ) + + spatial_keypoints: list[np.ndarray] = [] + spatial_metadata: list[dict] = [] + temporal_keypoints: list[np.ndarray] = [] + temporal_selected_keypoints: list[np.ndarray] = [] + temporal_metadata: list[dict] = [] + for person_idx in range(2): + spatial, spatial_meta = fuse_person( + raw_keypoints[person_idx], + raw_scores[person_idx], + isolated_keypoints[person_idx], + isolated_scores[person_idx], + boxes[person_idx], + track=None, + ) + temporal_unfiltered, temporal_meta = fuse_person( + raw_keypoints[person_idx], + raw_scores[person_idx], + isolated_keypoints[person_idx], + isolated_scores[person_idx], + boxes[person_idx], + track=tracks[person_idx], + ) + temporal = adaptive_smooth( + temporal_unfiltered, boxes[person_idx], tracks[person_idx] + ) + spatial_keypoints.append(spatial) + spatial_metadata.append(spatial_meta) + temporal_keypoints.append(temporal) + temporal_selected_keypoints.append(temporal_unfiltered) + temporal_metadata.append(temporal_meta) + + global_hands = build_global_hands( + temporal_selected_keypoints, temporal_metadata + ) + + output_record = { + "frame_index": frame_idx, + "boxes": boxes, + "raw_keypoints": np.round(raw_keypoints, 3).tolist(), + "spatial_keypoints": np.round(np.asarray(spatial_keypoints), 3).tolist(), + "spatial_metadata": spatial_metadata, + "temporal_keypoints": np.round(np.asarray(temporal_keypoints), 3).tolist(), + "temporal_selected_keypoints": np.round( + np.asarray(temporal_selected_keypoints), 3 + ).tolist(), + "temporal_metadata": temporal_metadata, + "global_hands": global_hands, + } + output_records.append(output_record) + + raw_panel = draw_pose(frame, boxes, raw_keypoints, f"RTMW-L raw | frame {frame_idx}") + spatial_panel = draw_fused( + frame, + boxes, + spatial_keypoints, + spatial_metadata, + f"spatial fusion | frame {frame_idx}", + ) + temporal_panel = draw_fused( + frame, + boxes, + temporal_keypoints, + temporal_metadata, + f"temporal fusion | frame {frame_idx}", + ) + panels = [ + cv2.resize(panel, (640, 360), interpolation=cv2.INTER_AREA) + for panel in (raw_panel, spatial_panel, temporal_panel) + ] + writer.write(np.hstack(panels)) + frame_idx += 1 + + cap.release() + writer.release() + + with (args.output / "fusion.jsonl").open("w", encoding="utf-8") as handle: + for record in output_records: + handle.write(json.dumps(record, ensure_ascii=False) + "\n") + + def comparison_records(variant: str) -> list[dict]: + return [ + { + "frame_index": record["frame_index"], + "boxes": record["boxes"], + "M": {"keypoints": record["raw_keypoints"]}, + "L": {"keypoints": record[f"{variant}_keypoints"]}, + } + for record in output_records + ] + + summary = { + "frames": len(output_records), + "fusion_policy": { + "candidates": ["RTMW-L raw", "RTMW-L smaller-person isolated"], + "selection": [ + "limb and hand selected separately", + "geometry validity", + "constant-velocity temporal consistency", + "source-switch hysteresis", + "motion-adaptive EMA in person-box coordinates", + ], + "distance_rule": ( + "Only consensus or temporally stable raw visible endpoints are eligible. " + "Inferred/conflict/rejected hands are excluded from precise distance." + ), + "alarm_rule": ( + "Alarm attack is asymmetric: a geometrically valid raw endpoint whose score " + "is clearly stronger than the isolated view is admitted immediately. Alarm " + "release should still require temporal confirmation and hysteresis." + ), + "risk_distance_note": ( + "Use global_hands and temporal_selected_keypoints (unfiltered) for alarm entry " + "to avoid smoothing delay. Use distance_eligible hands and temporal_keypoints " + "for stable reporting. When the door edge is available, a conservative " + "implementation can use the smaller of the unfiltered and smoothed distances." + ), + }, + "spatial": metadata_summary(output_records, "spatial"), + "temporal": metadata_summary(output_records, "temporal"), + "active_hand_frame_step": { + "spatial": active_hand_temporal_metrics(output_records, "spatial"), + "temporal": active_hand_temporal_metrics(output_records, "temporal"), + }, + "raw_vs_spatial_temporal_metrics": temporal_metrics(comparison_records("spatial")), + "raw_vs_temporal_temporal_metrics": temporal_metrics(comparison_records("temporal")), + "global_hand_count_frames": dict( + sorted(Counter(len(record["global_hands"]) for record in output_records).items()) + ), + "cross_person_hand_aliases_total": sum( + len(hand["aliases"]) + for record in output_records + for hand in record["global_hands"] + ), + } + with (args.output / "summary.json").open("w", encoding="utf-8") as handle: + json.dump(summary, handle, ensure_ascii=False, indent=2) + + key_frames = [0, 45, 50, 55, 120, 132, 136, 180, 240, 252, 295, 300, 304, 360, 411] + make_montage( + args.video, + output_records, + key_frames, + args.output / "rtmw_l_raw_spatial_temporal_montage.jpg", + ) + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/pipeline/latest_result.py b/pipeline/latest_result.py new file mode 100644 index 0000000..1ab68ae --- /dev/null +++ b/pipeline/latest_result.py @@ -0,0 +1,64 @@ +"""One owned, immutable latest result, mirroring the 0920 LatestResult contract.""" +from __future__ import annotations + +from collections.abc import Mapping +import threading +from types import MappingProxyType + + +def freeze(value): + if isinstance(value, Mapping): + return MappingProxyType({key: freeze(item) for key, item in value.items()}) + if isinstance(value, (list, tuple)): + return tuple(freeze(item) for item in value) + return value + + +def result_to_dict(value): + """Return a mutable JSON-compatible copy when a consumer needs serialization.""" + if isinstance(value, Mapping): + return {key: result_to_dict(item) for key, item in value.items()} + if isinstance(value, tuple): + return [result_to_dict(item) for item in value] + return value + + +class LatestResult: + """Readers share a stable snapshot; reading never removes or acknowledges it. + + Only the latest result is retained here. Slow readers can skip frames, and + references they already hold remain valid after subsequent publications. + """ + + def __init__(self): + self._condition = threading.Condition() + self._value = None + self._closed = False + + def publish(self, result): + if result is None: + raise ValueError("Cannot publish a null result") + snapshot = freeze(result) + with self._condition: + if self._closed: + raise RuntimeError("Result publisher is closed") + self._value = snapshot + self._condition.notify_all() + + def load(self): + with self._condition: + return self._value + + def wait(self, after_frame_index=-1, timeout=None): + """Wait for a newer result; return None on timeout/end without a new frame.""" + with self._condition: + def has_new_frame(): + return self._value is not None and self._value['frame_index'] > after_frame_index + + self._condition.wait_for(lambda: has_new_frame() or self._closed, timeout) + return self._value if has_new_frame() else None + + def close(self): + with self._condition: + self._closed = True + self._condition.notify_all() diff --git a/pipeline/live_pose_engine.py b/pipeline/live_pose_engine.py new file mode 100644 index 0000000..b0140e5 --- /dev/null +++ b/pipeline/live_pose_engine.py @@ -0,0 +1,248 @@ +"""Resident YOLO11s + RTMW-L pose stage extracted from the v9.9 pipeline.""" + +from __future__ import annotations + +import argparse +import os +import time +from collections import defaultdict +from pathlib import Path + +import numpy as np + + +SIDES = ("left", "right") + + +class LivePoseEngine: + """Run the v9.9 YOLO/RTMW pose and temporal-fusion path without EdgeTAM.""" + + def __init__(self, args: argparse.Namespace): + self._trt_dll_directory = None + if args.pose_provider == "tensorrt" and os.name == "nt": + try: + import tensorrt_libs + except ImportError as exc: + raise RuntimeError( + "--pose-provider tensorrt on Windows requires the " + "tensorrt-cu12-libs package in the active Python environment." + ) from exc + + trt_lib_dir = Path(tensorrt_libs.__file__).resolve().parent + self._trt_dll_directory = os.add_dll_directory(str(trt_lib_dir)) + os.environ["PATH"] = ( + str(trt_lib_dir) + os.pathsep + os.environ.get("PATH", "") + ) + + if args.pose_device.lower().startswith("cuda"): + import onnxruntime as ort + + if "CUDAExecutionProvider" not in ort.get_available_providers(): + raise RuntimeError( + "--pose-device cuda requires onnxruntime-gpu. Uninstall " + "onnxruntime and install onnxruntime-gpu==1.22.0." + ) + + from rtmlib import RTMPose + from ultralytics import YOLO + from predict_optimized_pose_videos import BoxTracker + + self.args = args + self.detector = YOLO(str(args.det_model)) + self.pose = RTMPose( + str(args.pose_model), + model_input_size=(288, 384), + backend="onnxruntime", + device=args.pose_device, + ) + if args.pose_provider == "tensorrt": + import onnxruntime as ort + + available = ort.get_available_providers() + if "TensorrtExecutionProvider" not in available: + raise RuntimeError( + "--pose-provider tensorrt requires ONNX Runtime with " + "TensorrtExecutionProvider. " + f"Available providers: {available}" + ) + cache_dir = args.pose_trt_cache.expanduser().resolve() + cache_dir.mkdir(parents=True, exist_ok=True) + device_id = ( + int(str(args.pose_device).split(":")[-1]) + if ":" in str(args.pose_device) + else 0 + ) + trt_options = { + "device_id": device_id, + "trt_fp16_enable": "True", + "trt_engine_cache_enable": "True", + "trt_engine_cache_path": str(cache_dir), + "trt_timing_cache_enable": "True", + "trt_timing_cache_path": str(cache_dir), + } + self.pose.session = ort.InferenceSession( + str(args.pose_model.resolve()), + providers=[ + ("TensorrtExecutionProvider", trt_options), + ("CUDAExecutionProvider", {"device_id": device_id}), + ], + ) + active_providers = self.pose.session.get_providers() + if not active_providers or active_providers[0] != "TensorrtExecutionProvider": + raise RuntimeError( + "RTMW TensorRT initialization failed instead of using the " + "requested provider. Active providers: " + f"{active_providers}" + ) + print(f"RTMW ONNX Runtime providers: {active_providers}") + + self.box_tracker = BoxTracker(max_age=30) + self.people = {} + self.timings = defaultdict(list) + self.isolated_inferences = 0 + + def infer(self, frame: np.ndarray, frame_idx: int) -> dict: + from compare_rtmw_ml import HAND_SLICES + from fuse_rtmw_l_temporal import adaptive_smooth, build_global_hands, fuse_person + from occlusion_aware_pose_v2 import Measurement, resolve_global_hand_assignments + from predict_optimized_pose_videos import ( + LivePersonState, + filter_person_boxes, + mask_other_people, + update_live_v2, + ) + + infer_started = time.perf_counter() + height, width = frame.shape[:2] + started = time.perf_counter() + detection_height = max( + 1, min(height, round(height * self.args.det_roi_y_max_ratio)) + ) + if hasattr(self, "native"): + boxes, confidences = self.native.detect(frame[:detection_height]) + self.timings["detector_ms"].append((time.perf_counter() - started) * 1000) + else: + detection = self.detector.predict( + frame[:detection_height], + imgsz=self.args.det_imgsz, + conf=self.args.det_conf, + iou=0.30, + classes=[0], + device=self.args.det_device, + verbose=False, + )[0] + self.timings["detector_ms"].append((time.perf_counter() - started) * 1000) + boxes, confidences, _ = filter_person_boxes( + detection, width, height, self.args.max_people + ) + track_ids = self.box_tracker.update(boxes, frame_idx, (height, width)) + + # Retire disappeared people in long-running camera sessions. + for stale_id in list(self.people): + if stale_id not in self.box_tracker.tracks: + del self.people[stale_id] + if boxes: + started = time.perf_counter() + raw_keypoints, raw_scores = self.pose(frame, bboxes=boxes) + self.timings["raw_pose_ms"].append((time.perf_counter() - started) * 1000) + isolated_keypoints = raw_keypoints.copy() + isolated_scores = raw_scores.copy() + started = time.perf_counter() + for person_idx, bbox in enumerate(boxes): + target_area = max((bbox[2] - bbox[0]) * (bbox[3] - bbox[1]), 1.0) + needs_isolation = any( + idx != person_idx + and max((other[2] - other[0]) * (other[3] - other[1]), 1.0) + < 0.5 * target_area + for idx, other in enumerate(boxes) + ) + if not needs_isolation: + continue + masked = mask_other_people(frame, boxes, person_idx) + keypoints, scores = self.pose(masked, bboxes=[bbox]) + isolated_keypoints[person_idx] = keypoints[0] + isolated_scores[person_idx] = scores[0] + self.isolated_inferences += 1 + self.timings["isolated_extra_ms"].append( + (time.perf_counter() - started) * 1000 + ) + else: + raw_keypoints = np.empty((0, 133, 2), dtype=np.float64) + raw_scores = np.empty((0, 133), dtype=np.float64) + isolated_keypoints = raw_keypoints.copy() + isolated_scores = raw_scores.copy() + + selected_list, smoothed_list, metadata_list, states = [], [], [], [] + for person_idx, (bbox, track_id) in enumerate(zip(boxes, track_ids)): + state = self.people.setdefault(track_id, LivePersonState()) + selected, metadata = fuse_person( + raw_keypoints[person_idx], + raw_scores[person_idx], + isolated_keypoints[person_idx], + isolated_scores[person_idx], + bbox, + state.fusion, + ) + selected_list.append(selected) + smoothed_list.append(adaptive_smooth(selected, bbox, state.fusion)) + metadata_list.append(metadata) + states.append(state) + + measurements, endpoint_tracks = {}, {} + for person_idx, (selected, metadata, state) in enumerate( + zip(selected_list, metadata_list, states) + ): + for side, (start, end) in HAND_SLICES.items(): + meta = metadata[side] + measurements[(person_idx, side)] = ( + Measurement( + keypoints=selected[start:end], + precise=bool(meta["distance_eligible"]), + provisional=not bool(meta["distance_eligible"]), + quality=float(meta.get("selected_hand_score", 0.0)), + ) + if meta["alarm_eligible"] + else None + ) + endpoint_tracks[(person_idx, side)] = state.endpoints[side] + measurements, assignments = resolve_global_hand_assignments( + measurements, endpoint_tracks, boxes, 30 + ) + + v2_list, v2_meta_list = [], [] + for person_idx, (bbox, selected, smoothed, metadata, state) in enumerate( + zip(boxes, selected_list, smoothed_list, metadata_list, states) + ): + v2, v2_meta = update_live_v2( + frame_idx, + bbox, + selected, + smoothed, + metadata, + state, + {side: measurements[(person_idx, side)] for side in SIDES}, + {side: assignments.get((person_idx, side)) for side in SIDES}, + 12, + 30, + ) + v2_list.append(v2) + v2_meta_list.append(v2_meta) + + self.timings["pose_pipeline_total_ms"].append( + (time.perf_counter() - infer_started) * 1000 + ) + return { + "frame_index": frame_idx, + "track_ids": track_ids, + "boxes": np.round(np.asarray(boxes), 3).tolist() if boxes else [], + "det_confidences": [round(value, 4) for value in confidences], + "raw_keypoints": np.round(raw_keypoints, 3).tolist(), + "temporal_selected_keypoints": np.round( + np.asarray(selected_list), 3 + ).tolist(), + "temporal_keypoints": np.round(np.asarray(smoothed_list), 3).tolist(), + "temporal_metadata": metadata_list, + "v2_keypoints": np.round(np.asarray(v2_list), 3).tolist(), + "v2_metadata": v2_meta_list, + "global_hands": build_global_hands(selected_list, metadata_list), + } diff --git a/pipeline/native_backend.py b/pipeline/native_backend.py new file mode 100644 index 0000000..91895f5 --- /dev/null +++ b/pipeline/native_backend.py @@ -0,0 +1,75 @@ +"""Native Jetson TensorRT adapter; temporal/risk policy stays in upstream Python.""" +from __future__ import annotations +import ctypes as C +from collections import defaultdict, deque +from pathlib import Path +import numpy as np +from live_pose_engine import LivePoseEngine +from predict_optimized_pose_videos import BoxTracker + +ROOT = Path(__file__).resolve().parents[1] + +class NativeBackend: + def __init__(self, args): + self.lib = C.CDLL(str(ROOT / 'build/libvision_native.so')) + pointer = C.c_void_p + signatures = { + 'vap_error': ([], C.c_char_p), + 'vap_engine': ([C.c_char_p,C.c_int,C.c_int,C.c_int,C.c_float],pointer), + 'vap_engine_close': ([pointer],None), + 'vap_detect': ([pointer,pointer,C.c_int,C.c_int,pointer],C.c_int), + 'vap_pose': ([pointer,pointer,C.c_int,C.c_int,pointer,C.c_int,pointer],C.c_int), + 'vap_camera': ([C.c_char_p,C.c_int,C.c_int,C.c_int,C.c_int],pointer), + 'vap_camera_close': ([pointer],None), + 'vap_read': ([pointer,pointer,pointer],C.c_int), + 'vap_can': ([pointer],None), + } + for name,(inputs,output) in signatures.items(): + fn=getattr(self.lib,name);fn.argtypes=inputs;fn.restype=output + self.engine = self.lib.vap_engine(str(args.engines.resolve()).encode(),args.width,args.height,args.max_people,args.det_conf) + if not self.engine: self.fail() + self.camera=None + self.args=args + + def fail(self): + raise RuntimeError(self.lib.vap_error().decode()) + + def open_camera(self): + a=self.args + self.camera=self.lib.vap_camera(a.camera.encode(),a.width,a.height,a.fps,not a.no_can) + if not self.camera:self.fail() + + def read(self): + image=np.empty((self.args.height,self.args.width,3),np.uint8) + meta=np.zeros(4,np.float64) + result=self.lib.vap_read(self.camera,image.ctypes.data,meta.ctypes.data) + if result<0:self.fail() + if result==0:return None,None + return image,{'sequence':int(meta[0]),'capture_monotonic_ms':float(meta[1]),'dropped_before_inference':int(meta[2]),'driver_timestamp_ms':float(meta[3]),'latency_clock':'host_monotonic_at_dequeue'} + + def can_snapshot(self): + data=np.zeros(5,np.float64);self.lib.vap_can(data.ctypes.data) + return {'positions':[int(x) for x in data[:4]],'age_ms':float(data[4])} + + def detect(self, frame): + frame=np.ascontiguousarray(frame);out=np.empty((self.args.max_people,5),np.float32) + n=self.lib.vap_detect(self.engine,frame.ctypes.data,frame.shape[1],frame.shape[0],out.ctypes.data) + if n<0:self.fail() + return out[:n,:4].tolist(),out[:n,4].tolist() + + def pose(self,frame,bboxes): + frame=np.ascontiguousarray(frame);boxes=np.ascontiguousarray(bboxes,dtype=np.float32) + out=np.empty((len(boxes),133,3),np.float32) + n=self.lib.vap_pose(self.engine,frame.ctypes.data,frame.shape[1],frame.shape[0],boxes.ctypes.data,len(boxes),out.ctypes.data) + if n<0:self.fail() + return out[:n,:,:2].astype(np.float64),out[:n,:,2].astype(np.float64) + + def close(self): + if self.camera:self.lib.vap_camera_close(self.camera);self.camera=None + if self.engine:self.lib.vap_engine_close(self.engine);self.engine=None + +class NativePoseEngine(LivePoseEngine): + def __init__(self,args,native): + self.args=args;self.native=native;self.pose=native.pose + self.box_tracker=BoxTracker(max_age=30);self.people={} + self.timings=defaultdict(lambda:deque(maxlen=3000));self.isolated_inferences=0 diff --git a/pipeline/occlusion_aware_pose_v2.py b/pipeline/occlusion_aware_pose_v2.py new file mode 100644 index 0000000..5b7c73f --- /dev/null +++ b/pipeline/occlusion_aware_pose_v2.py @@ -0,0 +1,1130 @@ +"""Occlusion-aware temporal pose reconstruction on top of RTMW-L fusion. + +Visible endpoints are filtered and optionally connected with a two-bone IK +solution. Short gaps are interpolated/predicted, medium gaps use a local motion +corridor, and long occlusions retain an undrawn shoulder sector for downstream +door-band intersection instead of emitting a fake precise wrist. +""" + +from __future__ import annotations + +import argparse +import json +import math +from collections import Counter, defaultdict +from dataclasses import dataclass +from pathlib import Path + +import cv2 +import numpy as np + +from compare_rtmw_ml import HAND_EDGES_LOCAL, HAND_SLICES, normalized_keypoints, summarize +from fuse_rtmw_l_temporal import BODY_SIDE_INDICES, draw_dashed_line, draw_fused + + +STATE_COLORS = { + "observed": (40, 220, 40), + "provisional": (255, 190, 40), + "recovered": (220, 180, 40), + "reassigned": (220, 120, 40), + "interpolated": (0, 220, 255), + "predicted_short": (0, 140, 255), + "reachable_medium": (0, 120, 255), + "reachable_long": (30, 80, 255), +} + + +@dataclass +class Measurement: + keypoints: np.ndarray + precise: bool + provisional: bool + source: str = "model" + quality: float = 0.0 + + +@dataclass +class EndpointTrack: + wrist: np.ndarray | None = None + velocity: np.ndarray | None = None + hand_shape: np.ndarray | None = None + last_observed_frame: int | None = None + missed_frames: int = 0 + last_elbow: np.ndarray | None = None + last_direction: np.ndarray | None = None + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--video", type=Path, required=True) + parser.add_argument("--fusion-jsonl", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument("--short-occlusion-frames", type=int, default=12) + parser.add_argument("--medium-occlusion-frames", type=int, default=30) + parser.add_argument("--lookahead-frames", type=int, default=3) + return parser.parse_args() + + +def bbox_diagonal(bbox: list[float]) -> float: + return max(math.hypot(bbox[2] - bbox[0], bbox[3] - bbox[1]), 1.0) + + +def point_distance_ratio(a: np.ndarray, b: np.ndarray, bbox: list[float]) -> float: + return float(np.linalg.norm(a - b)) / bbox_diagonal(bbox) + + +def collect_measurements( + records: list[dict], + person_idx: int, + side: str, + lookahead_frames: int, +) -> list[Measurement | None]: + start, end = HAND_SLICES[side] + measurements: list[Measurement | None] = [None] * len(records) + observed_frames = [] + for frame_idx, record in enumerate(records): + meta = record["temporal_metadata"][person_idx][side] + if not meta["alarm_eligible"]: + continue + keypoints = np.asarray( + record["temporal_selected_keypoints"][person_idx][start:end], + dtype=np.float64, + ) + measurements[frame_idx] = Measurement( + keypoints=keypoints, + precise=bool(meta["distance_eligible"]), + provisional=not bool(meta["distance_eligible"]), + quality=float(meta.get("selected_hand_score", 0.0)), + ) + observed_frames.append(frame_idx) + + # A small future window is allowed for stable reporting. The alarm fast + # path still uses the unmodified current-frame candidates from V1. + for left, right in zip(observed_frames, observed_frames[1:]): + gap = right - left - 1 + if gap <= 0 or gap > lookahead_frames: + continue + left_points = measurements[left].keypoints + right_points = measurements[right].keypoints + for offset in range(1, gap + 1): + ratio = offset / (gap + 1) + points = (1.0 - ratio) * left_points + ratio * right_points + measurements[left + offset] = Measurement( + keypoints=points, + precise=False, + provisional=False, + source="fixed_lag_interpolation", + quality=min(measurements[left].quality, measurements[right].quality), + ) + return measurements + + +def estimate_bone_ratios(records: list[dict]) -> dict[tuple[int, str], tuple[float, float]]: + values: dict[tuple[int, str], list[tuple[float, float]]] = defaultdict(list) + for record in records: + for person_idx, bbox in enumerate(record["boxes"]): + keypoints = np.asarray( + record["temporal_selected_keypoints"][person_idx], dtype=np.float64 + ) + diagonal = bbox_diagonal(bbox) + for side, (shoulder, elbow, wrist) in BODY_SIDE_INDICES.items(): + meta = record["temporal_metadata"][person_idx][side] + if meta["limb_state"] != "consensus": + continue + upper = float(np.linalg.norm(keypoints[shoulder] - keypoints[elbow])) / diagonal + forearm = float(np.linalg.norm(keypoints[elbow] - keypoints[wrist])) / diagonal + if 0.04 <= upper <= 0.65 and 0.04 <= forearm <= 0.65: + values[(person_idx, side)].append((upper, forearm)) + + estimates: dict[tuple[int, str], tuple[float, float]] = {} + person_count = len(records[0]["boxes"]) + for person_idx in range(person_count): + for side in ("left", "right"): + samples = values[(person_idx, side)] + if len(samples) < 20: + opposite = "right" if side == "left" else "left" + samples = values[(person_idx, opposite)] + if samples: + array = np.asarray(samples) + estimates[(person_idx, side)] = ( + float(np.median(array[:, 0])), + float(np.median(array[:, 1])), + ) + else: + estimates[(person_idx, side)] = (0.24, 0.22) + return estimates + + +def solve_two_bone_elbow( + shoulder: np.ndarray, + wrist: np.ndarray, + upper_length: float, + forearm_length: float, + reference_elbow: np.ndarray, +) -> np.ndarray: + direction = wrist - shoulder + distance = float(np.linalg.norm(direction)) + if distance < 1e-6: + return reference_elbow.copy() + unit = direction / distance + + if distance >= upper_length + forearm_length: + return shoulder + unit * upper_length + if distance <= abs(upper_length - forearm_length): + sign = 1.0 if upper_length >= forearm_length else -1.0 + return shoulder + unit * upper_length * sign + + along = ( + upper_length * upper_length + - forearm_length * forearm_length + + distance * distance + ) / (2.0 * distance) + height = math.sqrt(max(upper_length * upper_length - along * along, 0.0)) + base = shoulder + unit * along + perpendicular = np.asarray([-unit[1], unit[0]]) + candidates = (base + perpendicular * height, base - perpendicular * height) + return min(candidates, key=lambda candidate: float(np.linalg.norm(candidate - reference_elbow))) + + +def update_endpoint_track( + track: EndpointTrack, + measurement: Measurement | None, + frame_idx: int, + short_occlusion_frames: int, + medium_occlusion_frames: int, +) -> tuple[np.ndarray | None, np.ndarray | None, str]: + if measurement is not None: + measured_wrist = measurement.keypoints[0] + measured_shape = measurement.keypoints - measured_wrist + if track.wrist is None or track.missed_frames > short_occlusion_frames: + track.wrist = measured_wrist.copy() + track.velocity = np.zeros(2, dtype=np.float64) + track.hand_shape = measured_shape.copy() + else: + prediction = track.wrist + track.velocity + residual = measured_wrist - prediction + alpha = 0.78 if measurement.precise else 0.88 + beta = 0.18 if measurement.precise else 0.24 + track.wrist = prediction + alpha * residual + track.velocity = 0.82 * track.velocity + beta * residual + shape_alpha = 0.55 if measurement.precise else 0.7 + track.hand_shape = ( + shape_alpha * measured_shape + (1.0 - shape_alpha) * track.hand_shape + ) + track.last_observed_frame = frame_idx + track.missed_frames = 0 + if measurement.source == "global_reassignment": + state = "reassigned" + elif measurement.source == "temporal_recovery": + state = "recovered" + elif measurement.precise: + state = "observed" + elif measurement.provisional: + state = "provisional" + else: + state = "interpolated" + return track.wrist.copy(), track.wrist + track.hand_shape, state + + track.missed_frames += 1 + if track.wrist is None: + return None, None, "reachable_long" + if track.missed_frames <= short_occlusion_frames: + track.wrist = track.wrist + track.velocity + track.velocity *= 0.86 + return track.wrist.copy(), track.wrist + track.hand_shape, "predicted_short" + if track.missed_frames <= medium_occlusion_frames: + return None, None, "reachable_medium" + return None, None, "reachable_long" + + +def temporal_recovery_measurement( + keypoints: np.ndarray, + metadata: dict, + side: str, + bbox: list[float], + track: EndpointTrack, + medium_occlusion_frames: int, +) -> Measurement | None: + """Recover a weak current-frame hand only when history strongly supports it.""" + if track.wrist is None or track.missed_frames > medium_occlusion_frames: + return None + if metadata.get("hand_state") not in {"conflict", "inferred"}: + return None + if not metadata.get("selected_hand_valid", False): + return None + if float(metadata.get("selected_hand_score", 0.0)) < 2.0: + return None + link = float(metadata.get("hand_selection", {}).get("link_to_selected_limb", 1.0)) + if link > 0.08: + return None + + start, end = HAND_SLICES[side] + hand = np.asarray(keypoints[start:end], dtype=np.float64) + if hand.shape != (end - start, 2) or not np.isfinite(hand).all(): + return None + prediction = track.wrist + track.velocity + diagonal = bbox_diagonal(bbox) + gate = min(0.20, 0.05 + 0.008 * max(track.missed_frames, 1)) * diagonal + if float(np.linalg.norm(hand[0] - prediction)) > gate: + return None + return Measurement( + keypoints=hand, + precise=False, + provisional=True, + source="temporal_recovery", + quality=float(metadata.get("selected_hand_score", 0.0)), + ) + + +def hand_span_px(hand: np.ndarray) -> float: + return math.hypot(float(np.ptp(hand[:, 0])), float(np.ptp(hand[:, 1]))) + + +def bbox_area(bbox: list[float]) -> float: + return max((bbox[2] - bbox[0]) * (bbox[3] - bbox[1]), 1.0) + + +def reset_endpoint_track(track: EndpointTrack) -> None: + track.wrist = None + track.velocity = None + track.hand_shape = None + track.last_observed_frame = None + track.missed_frames = 0 + track.last_elbow = None + track.last_direction = None + + +def resolve_global_hand_assignments( + frame_measurements: dict[tuple[int, str], Measurement | None], + tracks: dict[tuple[int, str], EndpointTrack], + boxes: list[list[float]], + medium_occlusion_frames: int, +) -> tuple[dict[tuple[int, str], Measurement | None], dict[tuple[int, str], dict]]: + """Resolve overlapping-person hands before binding them to body sides. + + Large foreground top-down crops may include a smaller background person. + The same physical hand can therefore be emitted for both people, or only by + the smaller crop even though it belongs to the foreground person. Direct + duplicates are kept on the foreground track when their apparent scales + agree. A missing foreground side can then reclaim a nearby candidate using + its recent hand trajectory and historical hand scale. + """ + resolved = dict(frame_measurements) + events: dict[tuple[int, str], dict] = {} + keys = list(resolved) + + # First collapse direct cross-person duplicates. Keep this deliberately + # asymmetric: a substantially larger foreground crop must also carry the + # substantially larger historical hand shape. + for index, first_key in enumerate(keys): + first = resolved[first_key] + if first is None: + continue + for second_key in keys[index + 1 :]: + second = resolved[second_key] + if second is None or first_key[0] == second_key[0]: + continue + first_hand = first.keypoints + second_hand = second.keypoints + first_span = hand_span_px(first_hand) + second_span = hand_span_px(second_hand) + center_distance = float( + np.linalg.norm(np.mean(first_hand, axis=0) - np.mean(second_hand, axis=0)) + ) + if center_distance > max(70.0, 0.5 * max(first_span, second_span)): + continue + + first_area = bbox_area(boxes[first_key[0]]) + second_area = bbox_area(boxes[second_key[0]]) + if first_area >= 2.5 * second_area and ( + first_span >= 1.45 * second_span + or first.quality >= second.quality + 0.6 + ): + owner_key, released_key = first_key, second_key + elif second_area >= 2.5 * first_area and ( + second_span >= 1.45 * first_span + or second.quality >= first.quality + 0.6 + ): + owner_key, released_key = second_key, first_key + else: + continue + resolved[released_key] = None + reset_endpoint_track(tracks[released_key]) + events[owner_key] = { + "method": "foreground_duplicate_owner", + "released_person_id": released_key[0] + 1, + "released_side": released_key[1], + } + events[released_key] = { + "method": "reassigned_away", + "assigned_person_id": owner_key[0] + 1, + "assigned_side": owner_key[1], + } + + # Then recover missing foreground hands from another crop. The candidate + # must fall inside the target's recent motion gate and be much smaller than + # the target's historical foreground hand shape. + available_sources = [key for key, value in resolved.items() if value is not None] + target_candidates = [] + for target_key, target_measurement in resolved.items(): + if target_measurement is not None: + continue + target_track = tracks[target_key] + if ( + target_track.wrist is None + or target_track.hand_shape is None + or target_track.missed_frames > medium_occlusion_frames + ): + continue + target_area = bbox_area(boxes[target_key[0]]) + predicted_center = target_track.wrist + np.mean(target_track.hand_shape, axis=0) + target_span = hand_span_px(target_track.hand_shape) + gate = 0.20 * bbox_diagonal(boxes[target_key[0]]) + for source_key in available_sources: + if source_key[0] == target_key[0]: + continue + source = resolved[source_key] + if source is None or source.source != "model": + continue + source_area = bbox_area(boxes[source_key[0]]) + if target_area < 2.5 * source_area: + continue + source_center = np.mean(source.keypoints, axis=0) + source_span = hand_span_px(source.keypoints) + distance = float(np.linalg.norm(source_center - predicted_center)) + if distance > gate or target_span < 1.45 * max(source_span, 1.0): + continue + target_candidates.append( + (distance / gate, target_key, source_key, source_center) + ) + + used_targets = set() + used_sources = set() + for _, target_key, source_key, source_center in sorted(target_candidates): + if target_key in used_targets or source_key in used_sources: + continue + target_track = tracks[target_key] + shape_center = np.mean(target_track.hand_shape, axis=0) + reassigned_wrist = source_center - shape_center + reassigned_hand = reassigned_wrist + target_track.hand_shape + resolved[target_key] = Measurement( + keypoints=reassigned_hand, + precise=False, + provisional=True, + source="global_reassignment", + quality=resolved[source_key].quality, + ) + resolved[source_key] = None + reset_endpoint_track(tracks[source_key]) + events[target_key] = { + "method": "foreground_temporal_reassignment", + "source_person_id": source_key[0] + 1, + "source_side": source_key[1], + "observed_center": np.round(source_center, 3).tolist(), + } + events[source_key] = { + "method": "reassigned_away", + "assigned_person_id": target_key[0] + 1, + "assigned_side": target_key[1], + } + used_targets.add(target_key) + used_sources.add(source_key) + return resolved, events + + +def track_direction(track: EndpointTrack) -> np.ndarray: + if track.last_direction is not None: + return track.last_direction / max(float(np.linalg.norm(track.last_direction)), 1e-6) + if track.velocity is not None and float(np.linalg.norm(track.velocity)) > 1e-6: + return track.velocity / np.linalg.norm(track.velocity) + return np.asarray([1.0, 0.0], dtype=np.float64) + + +def ellipse_polygon( + center: np.ndarray, + major_axis: float, + minor_axis: float, + direction: np.ndarray, + point_count: int = 64, +) -> np.ndarray: + perpendicular = np.asarray([-direction[1], direction[0]], dtype=np.float64) + angles = np.linspace(0.0, 2.0 * math.pi, point_count, endpoint=False) + return ( + center + + np.cos(angles)[:, None] * major_axis * direction + + np.sin(angles)[:, None] * minor_axis * perpendicular + ) + + +def clip_polygon_from_anchor_to_circle( + points: np.ndarray, + anchor: np.ndarray, + circle_center: np.ndarray, + radius: float, +) -> np.ndarray: + """Clip radial polygon samples to a shoulder-centered anatomical limit.""" + clipped = [] + offset = anchor - circle_center + for point in points: + if float(np.linalg.norm(point - circle_center)) <= radius: + clipped.append(point) + continue + ray = point - anchor + a = float(np.dot(ray, ray)) + b = 2.0 * float(np.dot(offset, ray)) + c = float(np.dot(offset, offset) - radius * radius) + discriminant = max(b * b - 4.0 * a * c, 0.0) + roots = [ + value + for value in ( + (-b - math.sqrt(discriminant)) / max(2.0 * a, 1e-6), + (-b + math.sqrt(discriminant)) / max(2.0 * a, 1e-6), + ) + if 0.0 <= value <= 1.0 + ] + clipped.append(anchor + (max(roots) if roots else 0.0) * ray) + return np.asarray(clipped, dtype=np.float64) + + +def medium_motion_region( + shoulder: np.ndarray, + upper_length: float, + forearm_length: float, + bbox: list[float], + track: EndpointTrack, + short_occlusion_frames: int, +) -> dict: + diagonal = bbox_diagonal(bbox) + direction = track_direction(track) + hand_shape = ( + track.hand_shape + if track.hand_shape is not None + else np.zeros((21, 2), dtype=np.float64) + ) + shape_center = np.mean(hand_shape, axis=0) + centered_shape = hand_shape - shape_center + perpendicular = np.asarray([-direction[1], direction[0]], dtype=np.float64) + hand_major = float(np.max(np.abs(centered_shape @ direction))) + hand_minor = float(np.max(np.abs(centered_shape @ perpendicular))) + + extra_frames = max(track.missed_frames - short_occlusion_frames, 1) + motion_major = min(0.20, 0.04 + 0.007 * extra_frames) * diagonal + motion_minor = min(0.13, 0.03 + 0.0045 * extra_frames) * diagonal + major_axis = max(hand_major + motion_major, 0.08 * diagonal) + minor_axis = max(hand_minor + motion_minor, 0.06 * diagonal) + + center = track.wrist + shape_center + tracked_hand_extent = float(np.max(np.linalg.norm(centered_shape, axis=1))) + hand_reach = max(tracked_hand_extent, 0.10 * diagonal) + anatomical_reach = upper_length + forearm_length + hand_reach + 0.02 * diagonal + shoulder_to_center = center - shoulder + center_distance = float(np.linalg.norm(shoulder_to_center)) + if center_distance > 0.96 * anatomical_reach: + center = shoulder + shoulder_to_center / center_distance * 0.96 * anatomical_reach + + polygon = ellipse_polygon(center, major_axis, minor_axis, direction) + polygon = clip_polygon_from_anchor_to_circle( + polygon, + center, + shoulder, + anatomical_reach, + ) + direction_deg = math.degrees(math.atan2(float(direction[1]), float(direction[0]))) + return { + "geometry": "motion_corridor", + "center": np.round(center, 3).tolist(), + "predicted_wrist": np.round(track.wrist, 3).tolist(), + "major_axis_px": round(major_axis, 3), + "minor_axis_px": round(minor_axis, 3), + "outer_radius_px": round(major_axis, 3), + "direction_deg": round(direction_deg, 3), + "max_reach_from_shoulder_px": round(anatomical_reach, 3), + "polygon": np.round(polygon, 3).tolist(), + "requires_door_intersection": True, + "render_full_region": True, + "distance_lower_bound_rule": "minimum distance from motion-corridor polygon to door_edge", + } + + +def long_reachable_region( + shoulder: np.ndarray, + upper_length: float, + forearm_length: float, + bbox: list[float], + track: EndpointTrack, + medium_occlusion_frames: int, +) -> dict: + diagonal = bbox_diagonal(bbox) + height = max(bbox[3] - bbox[1], 1.0) + arm_reach = upper_length + forearm_length + hand_reach = min(0.13 * diagonal, 0.17 * height) + safety_margin = 0.025 * diagonal + outer_radius = arm_reach + hand_reach + safety_margin + inner_radius = max(abs(upper_length - forearm_length) - 0.04 * diagonal, 0.0) + if track.last_direction is None: + direction_deg = 0.0 + half_angle_deg = 180.0 + else: + direction = track_direction(track) + direction_deg = math.degrees(math.atan2(float(direction[1]), float(direction[0]))) + half_angle_deg = min( + 180.0, + 65.0 + 2.0 * max(track.missed_frames - medium_occlusion_frames, 0), + ) + return { + "geometry": "shoulder_sector", + "center": np.round(shoulder, 3).tolist(), + "inner_radius_px": round(inner_radius, 3), + "outer_radius_px": round(outer_radius, 3), + "arm_reach_px": round(arm_reach, 3), + "hand_reach_px": round(hand_reach, 3), + "safety_margin_px": round(safety_margin, 3), + "direction_deg": round(direction_deg, 3), + "half_angle_deg": round(half_angle_deg, 3), + "requires_door_intersection": True, + "render_full_region": False, + "distance_lower_bound_rule": "intersect shoulder sector with door danger band before alarming", + } + + +def reachable_region( + shoulder: np.ndarray, + upper_length: float, + forearm_length: float, + bbox: list[float], + track: EndpointTrack, + state: str = "reachable_long", + short_occlusion_frames: int = 12, + medium_occlusion_frames: int = 30, +) -> dict: + if state == "reachable_medium" and track.wrist is not None: + return medium_motion_region( + shoulder, + upper_length, + forearm_length, + bbox, + track, + short_occlusion_frames, + ) + return long_reachable_region( + shoulder, + upper_length, + forearm_length, + bbox, + track, + medium_occlusion_frames, + ) + + +def calibrated_bone_lengths( + upper_ratio: float, + forearm_ratio: float, + bbox: list[float], +) -> tuple[float, float]: + diagonal = bbox_diagonal(bbox) + height = max(bbox[3] - bbox[1], 1.0) + upper = upper_ratio * diagonal + forearm = forearm_ratio * diagonal + total = upper + forearm + # Keep only a loose sanity cap. The previous 0.55 * bbox-height cap was + # unsafe for close, clipped CMS views: a valid projected arm can occupy + # almost the full detection height. The ratios are already robust medians, + # so this cap only limits catastrophic calibration outliers. + maximum_total = 0.95 * diagonal + if total > maximum_total: + scale = maximum_total / total + upper *= scale + forearm *= scale + return upper, forearm + + +def process_sequence( + records: list[dict], + short_occlusion_frames: int, + medium_occlusion_frames: int, + lookahead_frames: int, +) -> list[dict]: + person_count = len(records[0]["boxes"]) + measurements = { + (person_idx, side): collect_measurements( + records, person_idx, side, lookahead_frames + ) + for person_idx in range(person_count) + for side in ("left", "right") + } + bone_ratios = estimate_bone_ratios(records) + tracks = { + (person_idx, side): EndpointTrack() + for person_idx in range(person_count) + for side in ("left", "right") + } + + output = [] + for frame_idx, record in enumerate(records): + boxes = record["boxes"] + base_keypoints = np.asarray(record["temporal_keypoints"], dtype=np.float64) + unfiltered_keypoints = np.asarray( + record["temporal_selected_keypoints"], dtype=np.float64 + ) + v2_keypoints = base_keypoints.copy() + frame_measurements = { + (person_idx, side): measurements[(person_idx, side)][frame_idx] + for person_idx in range(person_count) + for side in ("left", "right") + } + frame_measurements, assignment_events = resolve_global_hand_assignments( + frame_measurements, + tracks, + boxes, + medium_occlusion_frames, + ) + people_meta = [] + for person_idx, bbox in enumerate(boxes): + diagonal = bbox_diagonal(bbox) + person_meta = {} + for side, (shoulder_idx, elbow_idx, wrist_idx) in BODY_SIDE_INDICES.items(): + track = tracks[(person_idx, side)] + measurement = frame_measurements[(person_idx, side)] + if measurement is None: + measurement = temporal_recovery_measurement( + unfiltered_keypoints[person_idx], + record["temporal_metadata"][person_idx][side], + side, + bbox, + track, + medium_occlusion_frames, + ) + returning_after_long_occlusion = ( + measurement is not None + and track.missed_frames > short_occlusion_frames + ) + wrist, hand, state = update_endpoint_track( + track, + measurement, + frame_idx, + short_occlusion_frames, + medium_occlusion_frames, + ) + shoulder = base_keypoints[person_idx, shoulder_idx] + upper_ratio, forearm_ratio = bone_ratios[(person_idx, side)] + upper_length, forearm_length = calibrated_bone_lengths( + upper_ratio, forearm_ratio, bbox + ) + reachable = None + + if wrist is not None and hand is not None: + reference_elbow = ( + unfiltered_keypoints[person_idx, elbow_idx] + if returning_after_long_occlusion or track.last_elbow is None + else track.last_elbow + ) + use_ik = ( + record["temporal_metadata"][person_idx][side]["limb_state"] + != "consensus" + or state in ( + "provisional", + "recovered", + "reassigned", + "interpolated", + "predicted_short", + ) + ) + if use_ik: + elbow = solve_two_bone_elbow( + shoulder, + wrist, + upper_length, + forearm_length, + reference_elbow, + ) + else: + elbow = base_keypoints[person_idx, elbow_idx] + track.last_elbow = elbow.copy() + direction = wrist - shoulder + if float(np.linalg.norm(direction)) > 1e-6: + track.last_direction = direction / np.linalg.norm(direction) + + v2_keypoints[person_idx, shoulder_idx] = shoulder + v2_keypoints[person_idx, elbow_idx] = elbow + v2_keypoints[person_idx, wrist_idx] = wrist + start, end = HAND_SLICES[side] + v2_keypoints[person_idx, start:end] = hand + uncertainty_radius = ( + 0.025 * diagonal + if state == "observed" + else (0.04 + 0.015 * track.missed_frames) * diagonal + ) + precise_distance = state == "observed" + fast_alarm = state in ( + "observed", + "provisional", + "reassigned", + "interpolated", + "predicted_short", + ) + else: + reachable = reachable_region( + shoulder, + upper_length, + forearm_length, + bbox, + track, + state, + short_occlusion_frames, + medium_occlusion_frames, + ) + uncertainty_radius = reachable["outer_radius_px"] + precise_distance = False + fast_alarm = True + + person_meta[side] = { + "state": state, + "precise_distance": precise_distance, + "fast_alarm_candidate": fast_alarm, + "risk_mode": ( + "precise_hand" + if state == "observed" + else ( + "motion_corridor_intersection" + if state == "reachable_medium" + else ( + "door_intersection_only" + if state == "reachable_long" + else ( + "reassigned_hand" + if state == "reassigned" + else "temporal_hand" + ) + ) + ) + ), + "requires_door_intersection": state + in ("reachable_medium", "reachable_long"), + "missed_frames": track.missed_frames, + "uncertainty_radius_px": round(float(uncertainty_radius), 3), + "bone_lengths_px": { + "upper": round(upper_length, 3), + "forearm": round(forearm_length, 3), + }, + "identity_assignment": assignment_events.get( + (person_idx, side) + ), + "reachable_region": reachable, + } + people_meta.append(person_meta) + + output.append( + { + "frame_index": frame_idx, + "boxes": boxes, + "v1_keypoints": record["temporal_keypoints"], + "v1_metadata": record["temporal_metadata"], + "v2_keypoints": np.round(v2_keypoints, 3).tolist(), + "v2_metadata": people_meta, + } + ) + return output + + +def sector_points(region: dict) -> np.ndarray: + center = np.asarray(region["center"], dtype=np.float64) + direction = region["direction_deg"] + half_angle = region["half_angle_deg"] + angles = np.linspace(direction - half_angle, direction + half_angle, 48) + radius = region["outer_radius_px"] + arc = np.column_stack( + [ + center[0] + radius * np.cos(np.deg2rad(angles)), + center[1] + radius * np.sin(np.deg2rad(angles)), + ] + ) + if half_angle < 179.0: + return np.vstack([center, arc, center]).astype(np.int32) + return arc.astype(np.int32) + + +def draw_v2( + image: np.ndarray, + boxes: list[list[float]], + keypoints: np.ndarray, + metadata: list[dict], + title: str, + show_reachable: bool = True, +) -> np.ndarray: + canvas = image.copy() + overlay = canvas.copy() + for person_idx, (bbox, kpts, person_meta) in enumerate( + zip(boxes, keypoints, metadata), start=1 + ): + x1, y1, x2, y2 = (int(round(value)) for value in bbox) + cv2.rectangle(canvas, (x1, y1), (x2, y2), (0, 220, 255), 2) + cv2.putText( + canvas, + f"P{person_idx}", + (x1 + 4, max(22, y1 + 24)), + cv2.FONT_HERSHEY_SIMPLEX, + 0.72, + (0, 220, 255), + 2, + cv2.LINE_AA, + ) + for side, (shoulder, elbow, wrist) in BODY_SIDE_INDICES.items(): + meta = person_meta[side] + state = meta["state"] + color = STATE_COLORS[state] + if state in ("reachable_medium", "reachable_long"): + region = meta["reachable_region"] + if state == "reachable_medium": + if show_reachable: + polygon = np.round(region["polygon"]).astype(np.int32) + cv2.fillPoly(overlay, [polygon], color) + cv2.polylines(canvas, [polygon], True, color, 3, cv2.LINE_AA) + center = tuple(np.round(region["center"]).astype(int)) + wrist_point = tuple( + np.round(region["predicted_wrist"]).astype(int) + ) + cv2.line(canvas, center, wrist_point, color, 2, cv2.LINE_AA) + label = f"{side[0].upper()}:corridor" + else: + center = tuple(np.round(region["center"]).astype(int)) + cv2.circle(canvas, center, 8, color, 2, cv2.LINE_AA) + if region["half_angle_deg"] >= 179.0: + cv2.putText( + canvas, + "?", + (center[0] + 11, center[1] + 9), + cv2.FONT_HERSHEY_SIMPLEX, + 0.65, + color, + 2, + cv2.LINE_AA, + ) + else: + direction = math.radians(region["direction_deg"]) + direction_end = ( + int(round(center[0] + 55 * math.cos(direction))), + int(round(center[1] + 55 * math.sin(direction))), + ) + cv2.arrowedLine( + canvas, + center, + direction_end, + color, + 2, + cv2.LINE_AA, + tipLength=0.25, + ) + if show_reachable and region.get("render_full_region", False): + polygon = sector_points(region) + if region["half_angle_deg"] < 179.0: + cv2.fillPoly(overlay, [polygon], color) + cv2.polylines( + canvas, [polygon], True, color, 3, cv2.LINE_AA + ) + else: + radius = int(round(region["outer_radius_px"])) + cv2.circle(canvas, center, radius, color, 3, cv2.LINE_AA) + label = f"{side[0].upper()}:unknown" + else: + thickness = 3 + if state in ("reassigned", "recovered"): + draw_dashed_line( + canvas, + kpts[shoulder], + kpts[elbow], + color, + thickness, + ) + draw_dashed_line( + canvas, + kpts[elbow], + kpts[wrist], + color, + thickness, + ) + else: + cv2.line( + canvas, + tuple(np.round(kpts[shoulder]).astype(int)), + tuple(np.round(kpts[elbow]).astype(int)), + color, + thickness, + cv2.LINE_AA, + ) + cv2.line( + canvas, + tuple(np.round(kpts[elbow]).astype(int)), + tuple(np.round(kpts[wrist]).astype(int)), + color, + thickness, + cv2.LINE_AA, + ) + start, end = HAND_SLICES[side] + hand = kpts[start:end] + for a, b in HAND_EDGES_LOCAL: + cv2.line( + canvas, + tuple(np.round(hand[a]).astype(int)), + tuple(np.round(hand[b]).astype(int)), + color, + 2, + cv2.LINE_AA, + ) + label = f"{side[0].upper()}:{state[:5]}" + cv2.putText( + canvas, + label, + (x1 + 4, max(45, y1 + (48 if side == "left" else 70))), + cv2.FONT_HERSHEY_SIMPLEX, + 0.48, + color, + 1, + cv2.LINE_AA, + ) + canvas = cv2.addWeighted(overlay, 0.06, canvas, 0.94, 0.0) + cv2.rectangle(canvas, (0, 0), (670, 45), (0, 0, 0), -1) + cv2.putText( + canvas, + title, + (10, 31), + cv2.FONT_HERSHEY_SIMPLEX, + 0.8, + (255, 255, 255), + 2, + cv2.LINE_AA, + ) + return canvas + + +def endpoint_metrics(records: list[dict]) -> dict: + states: Counter = Counter() + assignments: Counter = Counter() + steps: dict[str, list[float]] = defaultdict(list) + previous: dict[tuple[int, str], tuple[int, np.ndarray]] = {} + for record in records: + for person_idx, bbox in enumerate(record["boxes"]): + kpts = np.asarray(record["v2_keypoints"][person_idx], dtype=np.float64) + for side, (_, _, wrist) in BODY_SIDE_INDICES.items(): + meta = record["v2_metadata"][person_idx][side] + key_name = f"P{person_idx + 1}_{side}" + states[f"{key_name}_{meta['state']}"] += 1 + identity_assignment = meta.get("identity_assignment") + if identity_assignment is not None: + assignments[identity_assignment["method"]] += 1 + if meta["state"] in ("reachable_medium", "reachable_long"): + previous.pop((person_idx, side), None) + continue + normalized = normalized_keypoints(kpts, bbox)[wrist] + prior = previous.get((person_idx, side)) + if prior is not None and prior[0] == record["frame_index"] - 1: + steps[key_name].append(float(np.linalg.norm(normalized - prior[1]))) + previous[(person_idx, side)] = (record["frame_index"], normalized) + return { + "state_counts": dict(sorted(states.items())), + "identity_assignment_counts": dict(sorted(assignments.items())), + "wrist_frame_step": {name: summarize(items) for name, items in steps.items()}, + } + + +def write_video_and_montage( + video_path: Path, + records: list[dict], + output_dir: Path, +) -> None: + cap = cv2.VideoCapture(str(video_path)) + fps = float(cap.get(cv2.CAP_PROP_FPS)) + writer = cv2.VideoWriter( + str(output_dir / "rtmw_l_temporal_v1_vs_occlusion_v4.mp4"), + cv2.VideoWriter_fourcc(*"mp4v"), + fps, + (1920, 540), + ) + key_frames = {0, 50, 120, 126, 132, 138, 180, 211, 220, 240, 252, + 292, 296, 300, 304, 320, 360, 411} + montage_rows = [] + frame_idx = 0 + while True: + ok, frame = cap.read() + if not ok: + break + record = records[frame_idx] + v1 = draw_fused( + frame, + record["boxes"], + [np.asarray(points) for points in record["v1_keypoints"]], + record["v1_metadata"], + f"temporal fusion V1 | frame {frame_idx}", + ) + v2 = draw_v2( + frame, + record["boxes"], + np.asarray(record["v2_keypoints"]), + record["v2_metadata"], + f"occlusion V4 global assignment | frame {frame_idx}", + ) + left = cv2.resize(v1, (960, 540), interpolation=cv2.INTER_AREA) + right = cv2.resize(v2, (960, 540), interpolation=cv2.INTER_AREA) + writer.write(np.hstack([left, right])) + if frame_idx in key_frames: + montage_rows.append( + np.hstack( + [ + cv2.resize(v1, (640, 360), interpolation=cv2.INTER_AREA), + cv2.resize(v2, (640, 360), interpolation=cv2.INTER_AREA), + ] + ) + ) + frame_idx += 1 + cap.release() + writer.release() + cv2.imwrite( + str(output_dir / "rtmw_l_temporal_v1_vs_occlusion_v4_montage.jpg"), + np.vstack(montage_rows), + ) + + +def main() -> None: + args = parse_args() + args.output.mkdir(parents=True, exist_ok=True) + records = [ + json.loads(line) + for line in args.fusion_jsonl.read_text(encoding="utf-8").splitlines() + ] + output = process_sequence( + records, + short_occlusion_frames=args.short_occlusion_frames, + medium_occlusion_frames=args.medium_occlusion_frames, + lookahead_frames=args.lookahead_frames, + ) + with (args.output / "occlusion_v4.jsonl").open("w", encoding="utf-8") as handle: + for record in output: + handle.write(json.dumps(record, ensure_ascii=False) + "\n") + + summary = { + "algorithm_version": "occlusion_v4_global_assignment", + "frames": len(output), + "short_occlusion_frames": args.short_occlusion_frames, + "medium_occlusion_frames": args.medium_occlusion_frames, + "lookahead_frames": args.lookahead_frames, + "policy": { + "observed": "filtered visible endpoint; precise distance allowed", + "provisional": "strong current-frame endpoint; fast alarm only", + "recovered": "weak current-frame endpoint accepted by temporal gating", + "reassigned": "global hand candidate transferred using foreground scale and trajectory", + "interpolated": "fixed-lag short-gap interpolation; fast alarm only", + "predicted_short": "damped-velocity prediction; uncertainty grows each frame", + "reachable_medium": "track-centered motion corridor; intersect with door band", + "reachable_long": "no exact wrist; keep shoulder sector data for door intersection only", + "ik": "two-bone shoulder/wrist reconstruction using robust visible bone lengths", + "ownership": "one-to-one global hand reassignment using foreground scale and trajectory", + }, + "metrics": endpoint_metrics(output), + } + with (args.output / "summary.json").open("w", encoding="utf-8") as handle: + json.dump(summary, handle, ensure_ascii=False, indent=2) + write_video_and_montage(args.video, output, args.output) + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/pipeline/predict_optimized_pose_videos.py b/pipeline/predict_optimized_pose_videos.py new file mode 100644 index 0000000..dd15617 --- /dev/null +++ b/pipeline/predict_optimized_pose_videos.py @@ -0,0 +1,683 @@ +"""End-to-end optimized RTMW-L prediction for CMS videos. + +Pipeline: +YOLO11s person -> fixed-camera false-positive filters -> lightweight track IDs +-> RTMW-L raw/smaller-person-isolated views -> temporal fusion -> causal +occlusion-aware V4 global hand assignment. Reachable regions stay in JSON and are hidden in the main +comparison video. +""" + +from __future__ import annotations + +import argparse +import json +import math +import time +from collections import Counter, defaultdict, deque +from dataclasses import dataclass, field +from pathlib import Path + +import cv2 +import numpy as np + +from compare_rtmw_ml import HAND_SLICES, draw_pose, summarize +from fuse_rtmw_l_temporal import ( + BODY_SIDE_INDICES, + PersonTrack, + adaptive_smooth, + build_global_hands, + draw_fused, + fuse_person, +) +from occlusion_aware_pose_v2 import ( + EndpointTrack, + Measurement, + calibrated_bone_lengths, + draw_v2, + reachable_region, + resolve_global_hand_assignments, + solve_two_bone_elbow, + temporal_recovery_measurement, + update_endpoint_track, +) +from rtmw_l_person_mask_ablation import mask_other_people + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--videos", type=Path, nargs="+", required=True) + parser.add_argument("--det-model", type=Path, required=True) + parser.add_argument("--pose-model", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument( + "--det-device", + default="0", + help="Ultralytics YOLO device, for example 0, cuda:0, or cpu.", + ) + parser.add_argument( + "--pose-device", + default="cpu", + help="RTMW ONNX Runtime device: cpu or cuda.", + ) + parser.add_argument("--det-imgsz", type=int, default=960) + parser.add_argument("--det-conf", type=float, default=0.30) + parser.add_argument("--det-roi-y-max-ratio", type=float, default=1.0) + parser.add_argument("--short-occlusion-frames", type=int, default=12) + parser.add_argument("--medium-occlusion-frames", type=int, default=30) + parser.add_argument("--max-people", type=int, default=3) + return parser.parse_args() + + +def bbox_iou(a: np.ndarray, b: np.ndarray) -> float: + x1 = max(float(a[0]), float(b[0])) + y1 = max(float(a[1]), float(b[1])) + x2 = min(float(a[2]), float(b[2])) + y2 = min(float(a[3]), float(b[3])) + intersection = max(x2 - x1, 0.0) * max(y2 - y1, 0.0) + union = ( + max(float(a[2] - a[0]), 0.0) * max(float(a[3] - a[1]), 0.0) + + max(float(b[2] - b[0]), 0.0) * max(float(b[3] - b[1]), 0.0) + - intersection + ) + return intersection / max(union, 1.0) + + +class BoxTracker: + def __init__(self, max_age: int = 30): + self.max_age = max_age + self.next_id = 1 + self.tracks: dict[int, dict] = {} + + def update( + self, + boxes: list[list[float]], + frame_idx: int, + image_shape: tuple[int, int], + ) -> list[int]: + height, width = image_shape + image_diagonal = math.hypot(width, height) + active_ids = [ + track_id + for track_id, track in self.tracks.items() + if frame_idx - track["last_frame"] <= self.max_age + ] + self.tracks = {track_id: self.tracks[track_id] for track_id in active_ids} + pairs = [] + for detection_idx, box in enumerate(boxes): + box_array = np.asarray(box, dtype=np.float64) + center = (box_array[:2] + box_array[2:]) * 0.5 + for track_id in active_ids: + prior = np.asarray(self.tracks[track_id]["box"], dtype=np.float64) + prior_center = (prior[:2] + prior[2:]) * 0.5 + iou = bbox_iou(box_array, prior) + center_distance = float(np.linalg.norm(center - prior_center)) / image_diagonal + if iou >= 0.05 or center_distance <= 0.18: + score = 2.0 * iou + max(0.0, 1.0 - center_distance / 0.18) + pairs.append((score, detection_idx, track_id)) + + assigned_detections = set() + assigned_tracks = set() + result: list[int | None] = [None] * len(boxes) + for _, detection_idx, track_id in sorted(pairs, reverse=True): + if detection_idx in assigned_detections or track_id in assigned_tracks: + continue + assigned_detections.add(detection_idx) + assigned_tracks.add(track_id) + result[detection_idx] = track_id + + for detection_idx, box in enumerate(boxes): + track_id = result[detection_idx] + if track_id is None: + track_id = self.next_id + self.next_id += 1 + result[detection_idx] = track_id + self.tracks[track_id] = {"box": box, "last_frame": frame_idx} + return [int(track_id) for track_id in result] + + +@dataclass +class LivePersonState: + fusion: PersonTrack = field(default_factory=PersonTrack) + endpoints: dict[str, EndpointTrack] = field( + default_factory=lambda: {"left": EndpointTrack(), "right": EndpointTrack()} + ) + bone_samples: dict[str, deque] = field( + default_factory=lambda: { + "left": deque(maxlen=120), + "right": deque(maxlen=120), + } + ) + last_frame: int = -1 + + +def bbox_diagonal(bbox: list[float]) -> float: + return max(math.hypot(bbox[2] - bbox[0], bbox[3] - bbox[1]), 1.0) + + +def update_bone_samples( + state: LivePersonState, + keypoints: np.ndarray, + metadata: dict, + bbox: list[float], +) -> None: + diagonal = bbox_diagonal(bbox) + for side, (shoulder, elbow, wrist) in BODY_SIDE_INDICES.items(): + meta = metadata[side] + if meta["limb_state"] != "consensus" or not meta["distance_eligible"]: + continue + upper = float(np.linalg.norm(keypoints[shoulder] - keypoints[elbow])) / diagonal + forearm = float(np.linalg.norm(keypoints[elbow] - keypoints[wrist])) / diagonal + if 0.04 <= upper <= 0.65 and 0.04 <= forearm <= 0.65: + state.bone_samples[side].append((upper, forearm)) + + +def current_bone_ratios(state: LivePersonState, side: str) -> tuple[float, float]: + samples = state.bone_samples[side] + if len(samples) < 10: + opposite = "right" if side == "left" else "left" + if len(state.bone_samples[opposite]) >= 10: + samples = state.bone_samples[opposite] + if not samples: + return 0.24, 0.22 + values = np.asarray(samples, dtype=np.float64) + return float(np.median(values[:, 0])), float(np.median(values[:, 1])) + + +def update_live_v2( + frame_idx: int, + bbox: list[float], + selected_keypoints: np.ndarray, + smoothed_keypoints: np.ndarray, + fusion_metadata: dict, + state: LivePersonState, + assigned_measurements: dict[str, Measurement | None] | None, + identity_assignments: dict[str, dict] | None, + short_occlusion_frames: int, + medium_occlusion_frames: int, +) -> tuple[np.ndarray, dict]: + frame_gap = 0 if state.last_frame < 0 else max(frame_idx - state.last_frame - 1, 0) + for endpoint in state.endpoints.values(): + endpoint.missed_frames += frame_gap + state.last_frame = frame_idx + update_bone_samples(state, selected_keypoints, fusion_metadata, bbox) + + output = smoothed_keypoints.copy() + output_metadata = {} + diagonal = bbox_diagonal(bbox) + for side, (shoulder_idx, elbow_idx, wrist_idx) in BODY_SIDE_INDICES.items(): + endpoint = state.endpoints[side] + meta = fusion_metadata[side] + start, end = HAND_SLICES[side] + measurement = ( + assigned_measurements.get(side) + if assigned_measurements is not None + else None + ) + if assigned_measurements is None and meta["alarm_eligible"]: + measurement = Measurement( + keypoints=selected_keypoints[start:end], + precise=bool(meta["distance_eligible"]), + provisional=not bool(meta["distance_eligible"]), + quality=float(meta.get("selected_hand_score", 0.0)), + ) + if measurement is None: + measurement = temporal_recovery_measurement( + selected_keypoints, + meta, + side, + bbox, + endpoint, + medium_occlusion_frames, + ) + returning_after_long = ( + measurement is not None + and endpoint.missed_frames > short_occlusion_frames + ) + wrist, hand, endpoint_state = update_endpoint_track( + endpoint, + measurement, + frame_idx, + short_occlusion_frames, + medium_occlusion_frames, + ) + shoulder = smoothed_keypoints[shoulder_idx] + upper_ratio, forearm_ratio = current_bone_ratios(state, side) + upper_length, forearm_length = calibrated_bone_lengths( + upper_ratio, forearm_ratio, bbox + ) + region = None + if wrist is not None and hand is not None: + reference_elbow = ( + selected_keypoints[elbow_idx] + if returning_after_long or endpoint.last_elbow is None + else endpoint.last_elbow + ) + use_ik = ( + meta["limb_state"] != "consensus" + or endpoint_state + in ("provisional", "recovered", "reassigned", "predicted_short") + ) + elbow = ( + solve_two_bone_elbow( + shoulder, + wrist, + upper_length, + forearm_length, + reference_elbow, + ) + if use_ik + else smoothed_keypoints[elbow_idx] + ) + endpoint.last_elbow = elbow.copy() + direction = wrist - shoulder + if float(np.linalg.norm(direction)) > 1e-6: + endpoint.last_direction = direction / np.linalg.norm(direction) + output[shoulder_idx] = shoulder + output[elbow_idx] = elbow + output[wrist_idx] = wrist + output[start:end] = hand + uncertainty = ( + 0.025 * diagonal + if endpoint_state == "observed" + else (0.04 + 0.015 * endpoint.missed_frames) * diagonal + ) + precise = endpoint_state == "observed" + else: + region = reachable_region( + shoulder, + upper_length, + forearm_length, + bbox, + endpoint, + endpoint_state, + short_occlusion_frames, + medium_occlusion_frames, + ) + uncertainty = region["outer_radius_px"] + precise = False + output_metadata[side] = { + "state": endpoint_state, + "precise_distance": precise, + "fast_alarm_candidate": True, + "risk_mode": ( + "precise_hand" + if endpoint_state == "observed" + else ( + "motion_corridor_intersection" + if endpoint_state == "reachable_medium" + else ( + "door_intersection_only" + if endpoint_state == "reachable_long" + else ( + "reassigned_hand" + if endpoint_state == "reassigned" + else "temporal_hand" + ) + ) + ) + ), + "requires_door_intersection": endpoint_state + in ("reachable_medium", "reachable_long"), + "identity_assignment": ( + identity_assignments.get(side) + if identity_assignments is not None + else None + ), + "missed_frames": endpoint.missed_frames, + "uncertainty_radius_px": round(float(uncertainty), 3), + "bone_lengths_px": { + "upper": round(upper_length, 3), + "forearm": round(forearm_length, 3), + }, + "reachable_region": region, + } + return output, output_metadata + + +def filter_person_boxes( + result, + width: int, + height: int, + max_people: int, +) -> tuple[list[list[float]], list[float], Counter]: + boxes = result.boxes.xyxy.cpu().numpy() + scores = result.boxes.conf.cpu().numpy() + rejected = Counter() + kept = [] + for box, score in zip(boxes, scores): + center_x = float(box[0] + box[2]) * 0.5 + box_height = float(box[3] - box[1]) + if center_x > 0.80 * width: + rejected["right_reflection_roi"] += 1 + continue + if box_height < 0.20 * height: + rejected["too_short"] += 1 + continue + kept.append((box.tolist(), float(score))) + kept.sort(key=lambda item: item[1], reverse=True) + if len(kept) > max_people: + rejected["over_max_people"] += len(kept) - max_people + kept = kept[:max_people] + kept.sort(key=lambda item: item[0][0]) + return [item[0] for item in kept], [item[1] for item in kept], rejected + + +def process_video( + video_path: Path, + output_dir: Path, + detector: YOLO, + pose: RTMPose, + det_device: str, + det_imgsz: int, + det_conf: float, + det_roi_y_max_ratio: float, + short_occlusion_frames: int, + medium_occlusion_frames: int, + max_people: int, + video_label: str, +) -> dict: + output_dir.mkdir(parents=True, exist_ok=True) + cap = cv2.VideoCapture(str(video_path)) + fps = float(cap.get(cv2.CAP_PROP_FPS)) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + writer = cv2.VideoWriter( + str(output_dir / "raw_temporal_occlusion_v4.mp4"), + cv2.VideoWriter_fourcc(*"mp4v"), + fps, + (1920, 360), + ) + + box_tracker = BoxTracker(max_age=30) + people: dict[int, LivePersonState] = {} + records = [] + detection_counts = Counter() + rejection_counts = Counter() + state_counts = Counter() + timings = defaultdict(list) + isolated_inferences = 0 + frame_idx = 0 + + while True: + ok, frame = cap.read() + if not ok: + break + started = time.perf_counter() + detection_height = max(1, min(height, round(height * det_roi_y_max_ratio))) + detection = detector.predict( + frame[:detection_height], + imgsz=det_imgsz, + conf=det_conf, + iou=0.30, + classes=[0], + device=det_device, + verbose=False, + )[0] + timings["detector_ms"].append((time.perf_counter() - started) * 1000.0) + boxes, confidences, rejected = filter_person_boxes( + detection, width, height, max_people + ) + rejection_counts.update(rejected) + detection_counts[len(boxes)] += 1 + track_ids = box_tracker.update(boxes, frame_idx, (height, width)) + + if boxes: + started = time.perf_counter() + raw_keypoints, raw_scores = pose(frame, bboxes=boxes) + timings["raw_pose_ms"].append((time.perf_counter() - started) * 1000.0) + isolated_keypoints = raw_keypoints.copy() + isolated_scores = raw_scores.copy() + started = time.perf_counter() + for person_idx, bbox in enumerate(boxes): + target_area = max((bbox[2] - bbox[0]) * (bbox[3] - bbox[1]), 1.0) + needs_isolation = any( + idx != person_idx + and max((other[2] - other[0]) * (other[3] - other[1]), 1.0) + < 0.5 * target_area + for idx, other in enumerate(boxes) + ) + if not needs_isolation: + continue + masked = mask_other_people(frame, boxes, person_idx) + kpts, scores = pose(masked, bboxes=[bbox]) + isolated_keypoints[person_idx] = kpts[0] + isolated_scores[person_idx] = scores[0] + isolated_inferences += 1 + timings["isolated_extra_ms"].append((time.perf_counter() - started) * 1000.0) + else: + raw_keypoints = np.empty((0, 133, 2), dtype=np.float64) + raw_scores = np.empty((0, 133), dtype=np.float64) + isolated_keypoints = raw_keypoints.copy() + isolated_scores = raw_scores.copy() + + selected_list = [] + smoothed_list = [] + fusion_meta_list = [] + person_states = [] + for person_idx, (bbox, track_id) in enumerate(zip(boxes, track_ids)): + state = people.setdefault(track_id, LivePersonState()) + selected, fusion_meta = fuse_person( + raw_keypoints[person_idx], + raw_scores[person_idx], + isolated_keypoints[person_idx], + isolated_scores[person_idx], + bbox, + state.fusion, + ) + smoothed = adaptive_smooth(selected, bbox, state.fusion) + selected_list.append(selected) + smoothed_list.append(smoothed) + fusion_meta_list.append(fusion_meta) + person_states.append(state) + + frame_measurements = {} + endpoint_tracks = {} + for person_idx, (selected, fusion_meta, state) in enumerate( + zip(selected_list, fusion_meta_list, person_states) + ): + for side, (start, end) in HAND_SLICES.items(): + meta = fusion_meta[side] + frame_measurements[(person_idx, side)] = ( + Measurement( + keypoints=selected[start:end], + precise=bool(meta["distance_eligible"]), + provisional=not bool(meta["distance_eligible"]), + quality=float(meta.get("selected_hand_score", 0.0)), + ) + if meta["alarm_eligible"] + else None + ) + endpoint_tracks[(person_idx, side)] = state.endpoints[side] + frame_measurements, assignment_events = resolve_global_hand_assignments( + frame_measurements, + endpoint_tracks, + boxes, + medium_occlusion_frames, + ) + + v2_list = [] + v2_meta_list = [] + for person_idx, (bbox, selected, smoothed, fusion_meta, state) in enumerate( + zip( + boxes, + selected_list, + smoothed_list, + fusion_meta_list, + person_states, + ) + ): + v2, v2_meta = update_live_v2( + frame_idx, + bbox, + selected, + smoothed, + fusion_meta, + state, + { + side: frame_measurements[(person_idx, side)] + for side in ("left", "right") + }, + { + side: assignment_events.get((person_idx, side)) + for side in ("left", "right") + }, + short_occlusion_frames, + medium_occlusion_frames, + ) + v2_list.append(v2) + v2_meta_list.append(v2_meta) + for side in ("left", "right"): + state_counts[f"{v2_meta[side]['state']}"] += 1 + + global_hands = build_global_hands(selected_list, fusion_meta_list) + records.append( + { + "frame_index": frame_idx, + "timestamp_ms": round(frame_idx / fps * 1000.0, 3), + "track_ids": track_ids, + "boxes": np.round(np.asarray(boxes), 3).tolist() if boxes else [], + "det_confidences": [round(value, 4) for value in confidences], + "raw_keypoints": np.round(raw_keypoints, 3).tolist(), + "temporal_selected_keypoints": np.round(np.asarray(selected_list), 3).tolist(), + "temporal_keypoints": np.round(np.asarray(smoothed_list), 3).tolist(), + "temporal_metadata": fusion_meta_list, + "v2_keypoints": np.round(np.asarray(v2_list), 3).tolist(), + "v2_metadata": v2_meta_list, + "global_hands": global_hands, + } + ) + + raw_panel = draw_pose( + frame, + boxes, + raw_keypoints, + f"{video_label} RTMW-L raw | frame {frame_idx}", + ) + temporal_panel = draw_fused( + frame, + boxes, + smoothed_list, + fusion_meta_list, + f"{video_label} temporal fusion | frame {frame_idx}", + ) + v2_panel = draw_v2( + frame, + boxes, + np.asarray(v2_list), + v2_meta_list, + f"{video_label} occlusion V4 | frame {frame_idx}", + show_reachable=False, + ) + panels = [ + cv2.resize(panel, (640, 360), interpolation=cv2.INTER_AREA) + for panel in (raw_panel, temporal_panel, v2_panel) + ] + writer.write(np.hstack(panels)) + if frame_idx == 0 and video_path.suffix.lower() in { + ".jpg", + ".jpeg", + ".png", + ".bmp", + ".webp", + }: + cv2.imwrite(str(output_dir / "raw_pose.jpg"), raw_panel) + cv2.imwrite(str(output_dir / "spatial_fusion.jpg"), temporal_panel) + cv2.imwrite(str(output_dir / "occlusion_v2.jpg"), v2_panel) + panel_width = 960 + panel_height = round(height * panel_width / width) + image_panels = [ + cv2.resize( + panel, + (panel_width, panel_height), + interpolation=cv2.INTER_AREA, + ) + for panel in (raw_panel, temporal_panel, v2_panel) + ] + cv2.imwrite( + str(output_dir / "raw_spatial_occlusion_v2.jpg"), + np.hstack(image_panels), + ) + if frame_idx % 100 == 0: + print(f"{video_label}: processed frame {frame_idx}", flush=True) + frame_idx += 1 + + cap.release() + writer.release() + with (output_dir / "predictions.jsonl").open("w", encoding="utf-8") as handle: + for record in records: + handle.write(json.dumps(record, ensure_ascii=False) + "\n") + + summary = { + "occlusion_algorithm": "v4_global_assignment", + "video": str(video_path.resolve()), + "frames": len(records), + "fps": round(fps, 3), + "resolution": [width, height], + "person_filter": { + "center_x_max_ratio": 0.80, + "minimum_box_height_ratio": 0.20, + "max_people": max_people, + }, + "detector_settings": { + "imgsz": det_imgsz, + "confidence": det_conf, + "roi_y_max_ratio": det_roi_y_max_ratio, + }, + "filtered_person_count_frames": dict(sorted(detection_counts.items())), + "rejected_detection_counts": dict(sorted(rejection_counts.items())), + "track_ids_created": box_tracker.next_id - 1, + "isolated_pose_inferences": isolated_inferences, + "short_occlusion_frames": short_occlusion_frames, + "medium_occlusion_frames": medium_occlusion_frames, + "v2_state_counts": dict(sorted(state_counts.items())), + "timing_ms_cpu": { + name: summarize(values[5:] if len(values) > 5 else values) + for name, values in timings.items() + }, + "output_note": ( + "Main video hides reachable-region arcs. Reachable-region geometry remains in " + "predictions.jsonl for later door-distance lower-bound calculation." + ), + } + with (output_dir / "summary.json").open("w", encoding="utf-8") as handle: + json.dump(summary, handle, ensure_ascii=False, indent=2) + return summary + + +def main() -> None: + from rtmlib import RTMPose + from ultralytics import YOLO + args = parse_args() + detector = YOLO(str(args.det_model)) + pose = RTMPose( + str(args.pose_model), + model_input_size=(288, 384), + backend="onnxruntime", + device=args.pose_device, + ) + all_summaries = {} + for video_idx, video_path in enumerate(args.videos, start=1): + label = f"video{video_idx}" + output_dir = args.output / label + all_summaries[label] = process_video( + video_path, + output_dir, + detector, + pose, + args.det_device, + args.det_imgsz, + args.det_conf, + args.det_roi_y_max_ratio, + args.short_occlusion_frames, + args.medium_occlusion_frames, + args.max_people, + label, + ) + args.output.mkdir(parents=True, exist_ok=True) + with (args.output / "summary.json").open("w", encoding="utf-8") as handle: + json.dump(all_summaries, handle, ensure_ascii=False, indent=2) + print(json.dumps(all_summaries, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/pipeline/rtmw_l_person_mask_ablation.py b/pipeline/rtmw_l_person_mask_ablation.py new file mode 100644 index 0000000..6263500 --- /dev/null +++ b/pipeline/rtmw_l_person_mask_ablation.py @@ -0,0 +1,166 @@ +"""Test whether other people inside a top-down crop cause RTMW-L mix-ups.""" + +from __future__ import annotations + +import argparse +import json +import time +from pathlib import Path + +import cv2 +import numpy as np + +from compare_rtmw_ml import ( + draw_pose, + model_disagreement, + summarize, + temporal_metrics, + write_montage, +) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser() + parser.add_argument("--video", type=Path, required=True) + parser.add_argument("--baseline-jsonl", type=Path, required=True) + parser.add_argument("--model-l", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + return parser.parse_args() + + +def mask_other_people( + frame: np.ndarray, + boxes: list[list[float]], + target_idx: int, +) -> np.ndarray: + masked = frame.copy() + height, width = frame.shape[:2] + mask = np.zeros((height, width), dtype=bool) + target = boxes[target_idx] + target_area = max((target[2] - target[0]) * (target[3] - target[1]), 1.0) + for idx, bbox in enumerate(boxes): + if idx == target_idx: + continue + other_area = max((bbox[2] - bbox[0]) * (bbox[3] - bbox[1]), 1.0) + # The failure in this video is the small background person being + # absorbed by the much larger foreground person's 3:4 pose crop. + # Mask only markedly smaller people. Masking a larger occluder while + # estimating a small person removes genuine target pixels at overlap. + if other_area >= 0.5 * target_area: + continue + x1, y1, x2, y2 = (int(round(value)) for value in bbox) + x1, x2 = max(0, x1), min(width - 1, x2) + y1, y2 = max(0, y1), min(height - 1, y2) + mask[y1:y2 + 1, x1:x2 + 1] = True + + masked[mask] = (124, 116, 104) + return masked + + +def main() -> None: + from rtmlib import RTMPose + args = parse_args() + args.output.mkdir(parents=True, exist_ok=True) + baseline = [ + json.loads(line) + for line in args.baseline_jsonl.read_text(encoding="utf-8").splitlines() + ] + pose_l = RTMPose( + str(args.model_l), model_input_size=(288, 384), backend="onnxruntime", device="cpu" + ) + + cap = cv2.VideoCapture(str(args.video)) + fps = float(cap.get(cv2.CAP_PROP_FPS)) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + writer = cv2.VideoWriter( + str(args.output / "rtmw_l_raw_vs_person_masked.mp4"), + cv2.VideoWriter_fourcc(*"mp4v"), + fps, + (width, height // 2), + ) + + comparison: list[dict] = [] + timings: list[float] = [] + frame_idx = 0 + while True: + ok, frame = cap.read() + if not ok: + break + baseline_record = baseline[frame_idx] + boxes = baseline_record["boxes"][:2] + masked_keypoints = [] + masked_scores = [] + started = time.perf_counter() + for person_idx, bbox in enumerate(boxes): + masked_frame = mask_other_people(frame, boxes, person_idx) + keypoints, scores = pose_l(masked_frame, bboxes=[bbox]) + masked_keypoints.append(keypoints[0]) + masked_scores.append(scores[0]) + timings.append((time.perf_counter() - started) * 1000.0) + masked_keypoints_array = np.asarray(masked_keypoints) + + raw_keypoints = np.asarray(baseline_record["L"]["keypoints"][:2]) + comparison.append( + { + "frame_index": frame_idx, + "boxes": boxes, + "M": {"keypoints": raw_keypoints.tolist()}, + "L": {"keypoints": np.round(masked_keypoints_array, 3).tolist()}, + "masked_raw_scores": np.round(np.asarray(masked_scores), 4).tolist(), + } + ) + + left = draw_pose(frame, boxes, raw_keypoints, f"RTMW-L raw | frame {frame_idx}") + right = draw_pose( + frame, + boxes, + masked_keypoints_array, + f"RTMW-L mask other person | frame {frame_idx}", + ) + left = cv2.resize(left, (width // 2, height // 2), interpolation=cv2.INTER_AREA) + right = cv2.resize(right, (width // 2, height // 2), interpolation=cv2.INTER_AREA) + writer.write(np.hstack([left, right])) + if frame_idx % 50 == 0: + print(f"processed frame {frame_idx}", flush=True) + frame_idx += 1 + + cap.release() + writer.release() + + with (args.output / "rtmw_l_raw_vs_person_masked.jsonl").open( + "w", encoding="utf-8" + ) as handle: + for record in comparison: + handle.write(json.dumps(record, ensure_ascii=False) + "\n") + + disagreement, worst_frames = model_disagreement(comparison) + fixed_frames = [0, 60, 120, 132, 136, 180, 240, 252, 300, 360, 411] + montage_frames = sorted(set(fixed_frames + worst_frames[:8])) + write_montage( + args.video, + comparison, + montage_frames, + args.output / "rtmw_l_raw_vs_person_masked_montage.jpg", + titles=("RTMW-L raw", "RTMW-L smaller-person masked"), + ) + + summary = { + "frames": len(comparison), + "labels": { + "M": "RTMW-L raw crop", + "L": "RTMW-L with markedly smaller people masked", + }, + "timing_ms_two_people_cpu": summarize(timings[5:]), + "temporal_metrics_normalized_to_yolo_box": temporal_metrics(comparison), + "position_change_after_masking": disagreement, + "largest_change_frames": worst_frames, + "montage_frames": montage_frames, + } + with (args.output / "summary.json").open("w", encoding="utf-8") as handle: + json.dump(summary, handle, ensure_ascii=False, indent=2) + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/pipeline/rtmw_risk_pipeline.py b/pipeline/rtmw_risk_pipeline.py new file mode 100644 index 0000000..a61a490 --- /dev/null +++ b/pipeline/rtmw_risk_pipeline.py @@ -0,0 +1,390 @@ +"""Lightweight causal door-risk inference using only YOLO11s and RTMW-L.""" + +from __future__ import annotations + +import argparse +import json +import sys +import time +from pathlib import Path + +import cv2 +import numpy as np + + +PACKAGE_DIR = Path(__file__).resolve().parents[1] +PIPELINE_DIR = Path(__file__).resolve().parent +for import_dir in (PIPELINE_DIR, PACKAGE_DIR): + if str(import_dir) not in sys.path: + sys.path.insert(0, str(import_dir)) + +from door_mask_risk import DoorMaskSequence, DoorRiskEvaluator # noqa: E402 +from door_zone_risk import ( # noqa: E402 + DoorZoneAssigner, + DoorZoneConfig, + build_door_risks, +) +from live_pose_engine import LivePoseEngine # noqa: E402 + + +def parse_image_size(value: str) -> int | tuple[int, int]: + parts = value.lower().replace(",", "x").split("x") + if len(parts) == 1: + return int(parts[0]) + if len(parts) == 2: + return int(parts[0]), int(parts[1]) + raise argparse.ArgumentTypeError( + "image size must be one integer or HEIGHTxWIDTH, for example 960 or 544x960" + ) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--video", type=Path, required=True) + door_source = parser.add_mutually_exclusive_group(required=True) + door_source.add_argument("--door-mask-dir", type=Path) + door_source.add_argument( + "--constant-door-mask", + type=Path, + help="One X-AnyLabeling JSON or raster mask reused for every video frame.", + ) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument( + "--det-model", type=Path, default=PACKAGE_DIR / "models" / "yolo11s.onnx" + ) + parser.add_argument( + "--pose-model", type=Path, default=PACKAGE_DIR / "models" / "rtmw-l-384.onnx" + ) + parser.add_argument( + "--pose-jsonl", + type=Path, + help="Diagnostic replay input; bypasses live YOLO/RTMW model execution.", + ) + parser.add_argument("--det-device", default="0") + parser.add_argument("--pose-device", default="cuda") + parser.add_argument( + "--pose-provider", + choices=("cuda", "tensorrt"), + default="cuda", + help="ONNX Runtime provider for RTMW.", + ) + parser.add_argument( + "--pose-trt-cache", + type=Path, + default=PACKAGE_DIR / "models" / "rtmw_l_trt_cache", + ) + parser.add_argument("--det-imgsz", type=parse_image_size, default=960) + parser.add_argument("--det-conf", type=float, default=0.30) + parser.add_argument("--det-roi-y-max-ratio", type=float, default=1.0) + parser.add_argument("--max-people", type=int, default=3) + parser.add_argument( + "--door-mask-format", + choices=("auto", "xanylabeling", "raster"), + default="auto", + ) + parser.add_argument("--door-label", action="append") + parser.add_argument("--door-frame-offset", type=int, default=0) + parser.add_argument("--require-door-mask", action="store_true") + parser.add_argument("--risk-warning-relative", type=float, default=0.30) + parser.add_argument("--risk-release-relative", type=float, default=0.45) + parser.add_argument( + "--active-door", + choices=("front", "rear", "both", "none"), + default="both", + help="Door(s) whose CAN state is 0. Use front/rear for deployment simulation.", + ) + parser.add_argument( + "--door-zone-config", + type=Path, + default=PACKAGE_DIR / "annotations" / "door_zone_multifeature.json", + help="Pose-primary fixed-camera front/rear calibration JSON.", + ) + parser.add_argument("--max-frames", type=int, default=0) + parser.add_argument("--write-video", action="store_true") + parser.add_argument("--progress-every", type=int, default=100) + return parser.parse_args() + + +def load_pose_records(path: Path) -> dict[int, dict]: + records = {} + with path.open("r", encoding="utf-8") as handle: + for line in handle: + if not line.strip(): + continue + record = json.loads(line) + records[int(record["frame_index"])] = record + return records + + +def percentile(values: list[float], p: float) -> float | None: + return round(float(np.percentile(values, p)), 3) if values else None + + +def timing_stats(values: list[float]) -> dict: + return { + "count": len(values), + "total": round(float(np.sum(values)), 3) if values else 0.0, + "mean": round(float(np.mean(values)), 3) if values else None, + "median": percentile(values, 50), + "p95": percentile(values, 95), + } + + +def visualization_skeletons(record: dict) -> list[dict]: + """Return the exact fused keypoints and metadata consumed by draw_fused.""" + + boxes = record.get("boxes", []) + track_ids = [int(value) for value in record.get("track_ids", [])] + keypoints = record.get("temporal_selected_keypoints", []) + metadata = record.get("temporal_metadata", []) + if not (len(boxes) == len(keypoints) == len(metadata)): + return [] + return [ + { + "track_id": track_ids[position] if position < len(track_ids) else position + 1, + "person_index": position, + "layout": "coco_wholebody_133", + "keypoints": person_keypoints, + "metadata": metadata[position], + } + for position, person_keypoints in enumerate(keypoints) + ] + + +def render_frame( + frame: np.ndarray, + record: dict, + frame_risk: dict, + door_mask: np.ndarray | None, + door_assignments: list[dict], +) -> np.ndarray: + canvas = frame.copy() + boxes = record.get("boxes", []) + keypoints = record.get("temporal_selected_keypoints", []) + metadata = record.get("temporal_metadata", []) + if len(boxes) == len(keypoints) == len(metadata) and boxes: + from fuse_rtmw_l_temporal import draw_fused + + canvas = draw_fused(canvas, boxes, keypoints, metadata, "YOLO + RTMW risk") + else: + for position, box in enumerate(boxes): + x1, y1, x2, y2 = [int(round(float(value))) for value in box[:4]] + cv2.rectangle(canvas, (x1, y1), (x2, y2), (0, 220, 255), 2) + cv2.putText( + canvas, + f"P{position + 1}", + (x1 + 4, max(22, y1 + 24)), + cv2.FONT_HERSHEY_SIMPLEX, + 0.7, + (0, 220, 255), + 2, + cv2.LINE_AA, + ) + zone_colors = { + "front": (0, 220, 255), + "rear": (255, 180, 0), + "transition": (0, 140, 255), + "unassigned": (150, 150, 150), + } + for assignment in door_assignments: + position = int(assignment["person_index"]) + if not 0 <= position < len(boxes): + continue + box = boxes[position] + x1, y1 = int(round(float(box[0]))), int(round(float(box[1]))) + zone = str(assignment["door_zone"]) + cv2.putText( + canvas, + f"T{assignment['track_id']} {zone.upper()}", + (max(0, x1 + 4), max(24, y1 - 8)), + cv2.FONT_HERSHEY_SIMPLEX, + 0.68, + zone_colors.get(zone, (160, 160, 160)), + 2, + cv2.LINE_AA, + ) + if door_mask is not None and np.any(door_mask): + overlay = np.zeros_like(canvas) + overlay[door_mask > 0] = (255, 180, 0) + canvas = cv2.addWeighted(canvas, 1.0, overlay, 0.22, 0) + + score = frame_risk.get("risk_score") + score_text = "N/A" if score is None else f"{float(score):.3f}" + level = str(frame_risk.get("risk_level", "unavailable")) + color = (0, 0, 255) if level == "danger" else (0, 180, 255) + if level in ("clear", "unavailable", "inactive", "unknown"): + color = (40, 210, 80) if level == "clear" else (160, 160, 160) + cv2.rectangle(canvas, (12, 55), (490, 95), (0, 0, 0), -1) + cv2.putText( + canvas, + f"{frame_risk.get('risk_type', 'DOOR_RISK')} score={score_text} level={level}", + (24, 83), + cv2.FONT_HERSHEY_SIMPLEX, + 0.68, + color, + 2, + cv2.LINE_AA, + ) + return canvas + + +def main() -> None: + args = parse_args() + args.output.mkdir(parents=True, exist_ok=True) + if args.pose_provider == "tensorrt" and not args.pose_device.lower().startswith("cuda"): + raise ValueError("--pose-provider tensorrt requires --pose-device cuda") + + capture = cv2.VideoCapture(str(args.video.resolve())) + if not capture.isOpened(): + raise RuntimeError(f"Cannot open video: {args.video}") + input_fps = float(capture.get(cv2.CAP_PROP_FPS)) or 30.0 + width = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH)) + height = int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT)) + + risk_evaluator = DoorRiskEvaluator( + DoorMaskSequence( + args.door_mask_dir, + mask_format=args.door_mask_format, + labels=tuple(args.door_label or ("door", "车门")), + frame_offset=args.door_frame_offset, + require_every_frame=args.require_door_mask, + constant_mask=args.constant_door_mask, + ), + warning_relative=args.risk_warning_relative, + release_relative=args.risk_release_relative, + ) + zone_assigner = DoorZoneAssigner(DoorZoneConfig.load(args.door_zone_config)) + print( + f"Door masks: {risk_evaluator.sequence.source_format} " + + ( + f"(constant: {risk_evaluator.sequence.constant_path})" + if risk_evaluator.sequence.constant_path is not None + else f"({len(risk_evaluator.sequence.paths)} indexed frames)" + ) + ) + + pose_records = load_pose_records(args.pose_jsonl) if args.pose_jsonl else None + load_started = time.perf_counter() + pose_engine = None if pose_records is not None else LivePoseEngine(args) + model_load_seconds = time.perf_counter() - load_started + + writer = None + if args.write_video: + writer = cv2.VideoWriter( + str(args.output / "rtmw_risk_overlay.mp4"), + cv2.VideoWriter_fourcc(*"mp4v"), + input_fps, + (width, height), + ) + + frame_latencies = [] + pose_latencies = [] + risk_latencies = [] + render_latencies = [] + started_all = time.perf_counter() + frame_index = 0 + output_path = args.output / "causal_results.jsonl" + with output_path.open("w", encoding="utf-8") as output_handle: + while True: + if args.max_frames > 0 and frame_index >= args.max_frames: + break + ok, frame = capture.read() + if not ok: + break + frame_started = time.perf_counter() + pose_started = time.perf_counter() + if pose_records is None: + record = pose_engine.infer(frame, frame_index) + else: + record = pose_records.get(frame_index) + if record is None: + raise RuntimeError(f"Pose JSONL has no record for frame {frame_index}") + pose_latencies.append((time.perf_counter() - pose_started) * 1000) + + risk_started = time.perf_counter() + assignments = zone_assigner.update( + frame_index, record, (height, width) + ) + raw_risk, door_mask = risk_evaluator.evaluate( + frame_index, record, (height, width) + ) + door_risks, frame_risk = build_door_risks( + raw_risk, assignments, args.active_door + ) + risk_latencies.append((time.perf_counter() - risk_started) * 1000) + output_record = { + "frame_index": frame_index, + "track_ids": record.get("track_ids", []), + "boxes": record.get("boxes", []), + "skeletons": visualization_skeletons(record), + "active_door": args.active_door, + "door_assignments": assignments, + "door_risks": door_risks, + "risk": frame_risk, + "ungated_risk": raw_risk, + } + output_handle.write(json.dumps(output_record, ensure_ascii=False) + "\n") + + if writer is not None: + render_started = time.perf_counter() + writer.write( + render_frame(frame, record, frame_risk, door_mask, assignments) + ) + render_latencies.append((time.perf_counter() - render_started) * 1000) + + frame_latencies.append((time.perf_counter() - frame_started) * 1000) + if args.progress_every > 0 and frame_index % args.progress_every == 0: + recent = frame_latencies[-min(len(frame_latencies), args.progress_every) :] + print( + f"frame={frame_index} recent_ms={np.mean(recent):.1f} " + f"risk={frame_risk['risk_level']}", + flush=True, + ) + frame_index += 1 + + capture.release() + if writer is not None: + writer.release() + elapsed = time.perf_counter() - started_all + summary = { + "mode": "yolo_rtmw_door_risk_multifeature_v9_10", + "video": str(args.video.resolve()), + "pose_source": "jsonl_diagnostic" if pose_records is not None else "resident_yolo_rtmw", + "models_loaded": [] if pose_records is not None else ["YOLO11s", "RTMW-L"], + "edgetam_loaded": False, + "risk_region_policy": ( + "RTMW alarm-eligible hand hulls; YOLO body box only when a person " + "has no usable RTMW hand region" + ), + "frames": frame_index, + "input_fps": round(input_fps, 3), + "elapsed_seconds": round(elapsed, 3), + "throughput_fps": round(frame_index / elapsed, 3) if elapsed else None, + "model_load_seconds": round(model_load_seconds, 3), + "latency_ms": { + "total": timing_stats(frame_latencies), + "pose": timing_stats(pose_latencies), + "risk": timing_stats(risk_latencies), + "render": timing_stats(render_latencies), + }, + "write_video": args.write_video, + "active_door": args.active_door, + "door_zone": zone_assigner.summary(), + "door_risk": risk_evaluator.summary(), + } + if pose_engine is not None: + summary["pose"] = { + "provider": args.pose_provider, + "isolated_inferences": pose_engine.isolated_inferences, + "timing_ms": { + key: timing_stats(values) for key, values in pose_engine.timings.items() + }, + } + (args.output / "summary.json").write_text( + json.dumps(summary, ensure_ascii=False, indent=2), encoding="utf-8" + ) + print(json.dumps(summary, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/run_camera.py b/run_camera.py new file mode 100644 index 0000000..576304c --- /dev/null +++ b/run_camera.py @@ -0,0 +1,299 @@ +#!/usr/bin/env python3 +"""Live baseline V4L2/CAN capture + native TensorRT + CMS v9.10 risk.""" +from __future__ import annotations +import argparse +from collections import Counter, deque +from contextlib import ExitStack +import copy +import json +import signal +import sys +import threading +import time +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +from pathlib import Path +import cv2 +import numpy as np +ROOT=Path(__file__).resolve().parent +sys.path.insert(0,str(ROOT/'pipeline')) +from native_backend import NativeBackend, NativePoseEngine +from latest_result import LatestResult, result_to_dict +from door_mask_risk import DoorMaskSequence, DoorRiskEvaluator +from door_zone_risk import DoorZoneConfig, DoorZoneAssigner, build_door_risks +from rtmw_risk_pipeline import render_frame, visualization_skeletons, timing_stats + + +def select_active_door(mode, snapshot, side='left', timeout_ms=1000): + if mode!='can': return mode, True + p=snapshot['positions'];offset=0 if side=='left' else 1 + if snapshot['age_ms']<0 or snapshot['age_ms']>timeout_ms or min(p[offset],p[offset+2])<0: + return 'none',False + front,rear=p[offset]==0,p[offset+2]==0 + return ('both' if front and rear else 'front' if front else 'rear' if rear else 'none'),True + + +def gate_risks(raw, assignments, active, can_valid): + doors,risk=build_door_risks(raw,assignments,active) + if not can_valid: + for door,item in doors.items(): + item.update(risk_type=door.upper()+'_UNKNOWN',risk_level='unknown',risk_score=None,decision='CAN_UNAVAILABLE_OR_STALE') + risk=dict(risk,risk_type='CAN_UNKNOWN',risk_level='unknown',risk_score=None,decision='CAN_UNAVAILABLE_OR_STALE') + return doors,risk + + +class JsonlWriter: + """Bound the disk usage of continuous camera runs (current + two backups).""" + def __init__(self,path,max_bytes): + self.path=path;self.max_bytes=max_bytes;self.size=0 + self.handle=path.open('w',encoding='utf-8',buffering=1) + def __enter__(self):return self + def __exit__(self,*args):self.close() + def close(self):self.handle.close() + def write(self,text): + size=len(text.encode('utf-8')) + if self.max_bytes and self.size and self.size+size>self.max_bytes: + self.handle.close() + backup=self.path.with_suffix(self.path.suffix+'.1') + if backup.exists():backup.replace(self.path.with_suffix(self.path.suffix+'.2')) + self.path.replace(backup) + self.handle=self.path.open('w',encoding='utf-8',buffering=1);self.size=0 + self.handle.write(text);self.size+=size + + +def render_output(frame, record, risk, mask, assignments, status): + canvas = render_frame(frame, record, risk, mask, assignments) + cv2.putText(canvas,status,(24,frame.shape[0]-30),cv2.FONT_HERSHEY_SIMPLEX,.8,(0,180,255),2) + return canvas + + +class Preview: + def __init__(self,host,port,results): + self.jpeg=None;self.results=results;self.lock=threading.Lock() + self.pending=threading.Condition();self.packet=None;self.stopped=False + outer=self + class Handler(BaseHTTPRequestHandler): + def do_GET(self): + with outer.lock: + if self.path.split('?')[0]=='/frame.jpg': payload=outer.jpeg or b'';mime='image/jpeg' + elif self.path=='/result.json':payload=json.dumps(result_to_dict(outer.results.load()) or {},ensure_ascii=False,allow_nan=False).encode();mime='application/json' + else: + payload=b'''Vision anti-pinch 0923

Vision anti-pinch 0923 / Live camera

''';mime='text/html; charset=utf-8' + self.send_response(200 if payload else 503);self.send_header('Content-Type',mime);self.send_header('Cache-Control','no-store');self.send_header('Content-Length',str(len(payload)));self.end_headers() + try:self.wfile.write(payload) + except (BrokenPipeError,ConnectionResetError):pass + def log_message(self,*args):pass + self.server=ThreadingHTTPServer((host,port),Handler) + self.thread=threading.Thread(target=self.server.serve_forever,daemon=True);self.thread.start() + self.renderer=threading.Thread(target=self._render_loop,name='risk-preview',daemon=True) + self.renderer.start() + def submit(self, frame, record, risk, mask, assignments, status): + # All inputs belong to a finished frame; inference never modifies them + # after submission. Retain only one pending frame, replacing older work. + with self.pending: + if not self.stopped: + self.packet=(frame,record,risk,mask,assignments,status) + self.pending.notify() + + def _render_loop(self): + try: + while True: + with self.pending: + self.pending.wait_for(lambda:self.packet is not None or self.stopped) + if self.stopped:return + packet=self.packet;self.packet=None + self.update(render_output(*packet)) + except Exception as exc: + with self.pending:self.stopped=True;self.packet=None + with self.lock:self.jpeg=None + print('Visualization disabled; inference continues: '+str(exc),file=sys.stderr,flush=True) + + def update(self,image): + w=960;h=round(image.shape[0]*w/image.shape[1]);image=cv2.resize(image,(w,h)) + ok,jpeg=cv2.imencode('.jpg',image,[cv2.IMWRITE_JPEG_QUALITY,80]) + if ok: + with self.lock:self.jpeg=jpeg.tobytes() + def close(self): + with self.pending:self.stopped=True;self.packet=None;self.pending.notify_all() + self.renderer.join() + self.server.shutdown();self.server.server_close();self.thread.join() + + +def parse_args(argv=None): + p=argparse.ArgumentParser(description=__doc__) + p.add_argument('--video',type=Path,help='Diagnostic video replay through the same TensorRT/risk chain');p.add_argument('--camera',default='/dev/video5');p.add_argument('--width',type=int,default=1920);p.add_argument('--height',type=int,default=1536);p.add_argument('--fps',type=int,default=30) + p.add_argument('--engines',type=Path,default=ROOT/'models/engines') + p.add_argument('--constant-door-mask',type=Path,default=ROOT/'annotations/constant_door_mask.json') + p.add_argument('--door-zone-config',type=Path,default=ROOT/'annotations/door_zone_multifeature.json') + p.add_argument('--active-door',choices=['can','front','rear','both','none'],default='can') + p.add_argument('--can-side',choices=['left','right'],default='left');p.add_argument('--can-timeout-ms',type=float,default=1000);p.add_argument('--no-can',action='store_true') + p.add_argument('--max-people',type=int,default=3);p.add_argument('--det-conf',type=float,default=.30) + p.add_argument('--max-frames',type=int,default=0);p.add_argument('--duration',type=float,default=0) + p.add_argument('--jsonl-max-mb',type=float,default=32,help='Rotate each JSONL at this size; keep two backups; 0 disables rotation');p.add_argument('--output',type=Path,default=ROOT/'outputs'/time.strftime('%Y%m%d-%H%M%S')) + p.add_argument('--visualize',action='store_true',help='Enable optional HTTP visualization; disabled by default') + p.add_argument('--save-results',action='store_true',help='Save per-frame JSONL and periodic latest.json') + p.add_argument('--save-snapshots',action='store_true',help='Render and save latest.jpg every 10 seconds') + p.add_argument('--preview-port',type=int,default=8765);p.add_argument('--preview-host',default='0.0.0.0');p.add_argument('--preview-every',type=int,default=3) + p.add_argument('--write-video',action='store_true');p.add_argument('--save-pose-records',action='store_true');p.add_argument('--calibration-verified',action='store_true') + a=p.parse_args(argv) + if not 1<=a.max_people<=16 or not 0=a.max_frames) or (a.duration and time.monotonic()-run_started>=a.duration):break + if video: + ok,frame=video.read() + if not ok:break + capture={'sequence':count,'capture_monotonic_ms':time.monotonic()*1000,'dropped_before_inference':0,'latency_clock':'video_decode_complete'} + else:frame,capture=native.read() + if frame is None:break + tick=time.monotonic();record=pose.infer(frame,count);pose_ms.append((time.monotonic()-tick)*1000) + rt=time.monotonic();snapshot=native.can_snapshot();active,valid=select_active_door(a.active_door,snapshot,a.can_side,a.can_timeout_ms) + assignments=assigner.update(count,record,(a.height,a.width));raw,mask=evaluator.evaluate(count,record,(a.height,a.width)) + doors,risk=gate_risks(raw,assignments,active,valid);risk_ms.append((time.monotonic()-rt)*1000) + result={'frame_index':count,'track_ids':record['track_ids'],'boxes':record['boxes'],'skeletons':visualization_skeletons(record),'active_door':active,'door_assignments':assignments,'door_risks':doors,'risk':risk,'ungated_risk':raw,'capture':capture,'can':dict(snapshot,valid=valid,source='hardware' if a.active_door=='can' else 'simulation',side=a.can_side),'calibration_verified':a.calibration_verified} + result['capture_to_result_ms']=round(time.monotonic()*1000-capture['capture_monotonic_ms'],3) + results.publish(result) + if out:out.write(json.dumps(result,ensure_ascii=False,allow_nan=False)+'\n') + if pose_out:pose_out.write(json.dumps(record,ensure_ascii=False,allow_nan=False)+'\n') + now=time.monotonic() + snapshot_due=now-last_snapshot>=10 + if a.save_results and snapshot_due: + (a.output/'latest.json').write_text(json.dumps(result,ensure_ascii=False,indent=2)) + status=('CAN LIVE' if a.active_door=='can' else 'CAN SIMULATION: '+active)+' | '+('CALIBRATED' if a.calibration_verified else 'CALIBRATION UNVERIFIED') + if preview and count%a.preview_every==0: + preview.submit(frame,record,risk,mask,assignments,status) + if writer or (a.save_snapshots and snapshot_due): + canvas=render_output(frame,record,risk,mask,assignments,status) + if writer:writer.write(canvas) + if a.save_snapshots and snapshot_due: + cv2.imwrite(str(a.output/'latest.jpg'),canvas) + if snapshot_due:last_snapshot=now + count+=1;dropped+=capture['dropped_before_inference'];levels[risk['risk_level']]+=1;ages.append(result['capture_to_result_ms']);latencies.append((time.monotonic()-tick)*1000) + if now-last_report>=5: + print(json.dumps({'frames':count,'fps':round(count/(now-run_started),2),'people':len(record['boxes']),'risk':risk['risk_type'],'latency_ms':round(float(np.mean(latencies)),1),'capture_age_ms':round(float(np.mean(ages)),1),'can_valid':valid}),flush=True);last_report=now + finally: + if pose_out:pose_out.close() + except Exception as exc: + error=str(exc);raise + finally: + ended=time.monotonic() + if video:video.release() + if native:native.close() + if writer:writer.release() + if preview:preview.close() + elapsed=ended-(run_started or started) + summary={'mode':'baseline_v4l2_can_native_trt_cms_v9_10','camera':a.camera if not a.video else None,'video':str(a.video) if a.video else None,'frames':count,'elapsed_seconds':round(elapsed,3),'throughput_fps':round(count/max(elapsed,.001),3),'dropped_latest_frames':dropped,'risk_levels':dict(levels),'active_door_mode':a.active_door,'can_side':a.can_side,'calibration_verified':a.calibration_verified,'visualize_requested':a.visualize,'save_results':a.save_results,'save_snapshots':a.save_snapshots,'latency_window_frames':3000,'latency_ms':{'total':timing_stats(list(latencies)),'pose':timing_stats(list(pose_ms)),'risk':timing_stats(list(risk_ms)),'capture_to_result':timing_stats(list(ages))},'error':error} + if summary_sink is not None:summary_sink.update(summary) + if save_any:(a.output/'summary.json').write_text(json.dumps(summary,ensure_ascii=False,indent=2)) + print(json.dumps(summary,ensure_ascii=False),flush=True) + +class CameraPipeline: + """One lifecycle per instance, with the 0920 start/latest/stop/join pattern. + + The worker owns inference. Downstream threads read the latest immutable + snapshot directly, without JSON files, HTTP, callbacks or a result queue. + """ + def __init__(self, args=None): + self.args = copy.deepcopy(args if args is not None else parse_args([])) + self._results = LatestResult() + self._stop = threading.Event() + self._lifecycle_lock = threading.Lock() + self._thread = None + self._error = None + self.summary = {} + + @property + def latest_result(self): + """The latest complete result variable, or None before the first frame.""" + return self._results.load() + + def latest(self): + return self.latest_result + + def wait_for_result(self, after_frame_index=-1, timeout=None): + return self._results.wait(after_frame_index, timeout) + + def start(self): + with self._lifecycle_lock: + if self._thread is not None: + raise RuntimeError('CameraPipeline can only be started once') + self._thread = threading.Thread(target=self._run, name='vision-risk') + self._thread.start() + return self + + def _run(self): + try: + run_pipeline(self.args, self._results, self._stop, self.summary) + except BaseException as exc: + self._error = exc + finally: + self._results.close() + + def running(self): + return self._thread is not None and self._thread.is_alive() + + def request_stop(self): + self._stop.set() + + def join(self, timeout=None): + if self._thread is not None: + self._thread.join(timeout) + if not self._thread.is_alive() and self._error is not None: + raise self._error + + def __enter__(self): + return self.start() + + def __exit__(self, *args): + self.request_stop() + self.join() + + +def main(): + pipeline=CameraPipeline(parse_args()) + for sig in (signal.SIGINT,signal.SIGTERM): + signal.signal(sig,lambda *_:pipeline.request_stop()) + pipeline.start() + # Periodic joins allow Python to deliver stop signals on the main thread. + while pipeline.running(): + pipeline.join(.2) + pipeline.join() + + +if __name__=='__main__':main() diff --git a/run_camera.sh b/run_camera.sh index c153d56..c19253a 100755 --- a/run_camera.sh +++ b/run_camera.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash set -euo pipefail -root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" -exec "$root/build/camera_risk" --config "$root/config/camera.json" "$@" +root="$(cd "$(dirname "$0")" && pwd)" +export OPENBLAS_NUM_THREADS=1 OMP_NUM_THREADS=2 +exec "${PYTHON:-python3}" -u "$root/run_camera.py" "$@" diff --git a/run_risk.py b/run_risk.py new file mode 100644 index 0000000..9cdf2b3 --- /dev/null +++ b/run_risk.py @@ -0,0 +1,5 @@ +"""0923 entry point: native TensorRT camera/video inference and CMS v9.10 risk.""" +from run_camera import main + +if __name__ == '__main__': + main() diff --git a/scripts/build.sh b/scripts/build.sh index 5b0fa8d..ea63c29 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +root="$(cd "$(dirname "$0")/.." && pwd)" cmake_bin="${CMAKE_COMMAND:-cmake}" if [[ -x "$HOME/miniconda3/envs/yolo/bin/cmake" ]]; then cmake_bin="${CMAKE_COMMAND:-$HOME/miniconda3/envs/yolo/bin/cmake}"; fi -"$cmake_bin" -S "$root" -B "$root/build" -DCMAKE_BUILD_TYPE=Release -DCMAKE_CUDA_COMPILER="${CUDACXX:-/usr/local/cuda/bin/nvcc}" "$@" +"$cmake_bin" -S "$root" -B "$root/build" -DCMAKE_BUILD_TYPE=Release -DCMAKE_CUDA_COMPILER="${CUDACXX:-/usr/local/cuda/bin/nvcc}" "$cmake_bin" --build "$root/build" -j4 diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100755 index 0000000..7d4455f --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "$0")/.." && pwd)" +remote="${1:-orin@192.168.195.100}" +rsync -a --exclude .git --exclude build --exclude __pycache__ --exclude outputs --exclude logs --exclude models --exclude 'tests/*.mp4' "$root/" "$remote:vision-anti-pinch-0923/" +ssh "$remote" 'cd ~/vision-anti-pinch-0923 && mkdir -p models && if [ ! -e models/engines ]; then ln -s ../../vision-anti-pinch-0920/orin/engines models/engines; fi && ./scripts/build.sh' diff --git a/scripts/initialize_camera.sh b/scripts/initialize_camera.sh index 8da09bd..c840953 100755 --- a/scripts/initialize_camera.sh +++ b/scripts/initialize_camera.sh @@ -1,4 +1,27 @@ #!/usr/bin/env bash +# Use the previously deployed 0920 drivers; do not force module compatibility. set -euo pipefail -root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" -exec "$root/orin/scripts/initialize_camera.sh" "$@" +root="$(cd "$(dirname "$0")/.." && pwd)" +driver_dir="${DRIVER_DIR:-$root/../vision-anti-pinch-0920/orin/bin/drivers}" +device="${1:-/dev/video5}" +kernel="$(uname -r)" +for driver in max9295 max9296 sgx-yuv-gmsl2; do + module="${driver//-/_}" + [[ -d "/sys/module/$module" ]] && continue + file="$driver_dir/$driver.ko" + [[ -f "$file" ]] || { echo "Missing driver: $file" >&2; exit 1; } + vermagic="$(modinfo -F vermagic "$file")" + if [[ -n "$vermagic" && "${vermagic%% *}" != "$kernel" ]]; then + echo "Kernel mismatch: $file ($vermagic), running $kernel" >&2; exit 1 + fi + if [[ -z "$vermagic" ]]; then + echo "No vermagic metadata: $file; using normal insmod kernel validation." + fi + options=() + [[ "$driver" == sgx-yuv-gmsl2 ]] && options=(gmsl_mode=2,2,2,2) + sudo -n insmod "$file" "${options[@]}" +done +for _ in {1..20}; do [[ -c "$device" ]] && break; sleep .25; done +[[ -c "$device" ]] || { echo "Camera not created: $device" >&2; exit 1; } +v4l2-ctl -d "$device" -c sensor_mode=1,trig_pin=0xffff0007 +echo "Camera ready: $device" diff --git a/scripts/package_orin.sh b/scripts/package_orin.sh new file mode 100755 index 0000000..767a105 --- /dev/null +++ b/scripts/package_orin.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# Run after building on the target Orin; outputs a relocatable ./orin/run.sh package. +set -euo pipefail +root="$(cd "$(dirname "$0")/.." && pwd)" +package="$root/orin" +engine_dir="${ENGINE_DIR:-$root/models/engines}" +driver_dir="${DRIVER_DIR:-$root/../vision-anti-pinch-0920/orin/bin/drivers}" +[[ -f "$root/build/libvision_native.so" ]] || { echo 'Build the Orin native library first.' >&2; exit 1; } +mkdir -p "$package/build" "$package/lib" "$package/pipeline" "$package/annotations" "$package/models/engines" "$package/bin/drivers" "$package/scripts" "$package/examples" +cp -p "$root/build/libvision_native.so" "$package/build/" +cp -p "$root/run_camera.py" "$package/" +cp -p "$root/pipeline/"*.py "$package/pipeline/" +cp -p "$root/annotations/"*.json "$package/annotations/" +cp -p "$root/lib/libusbcanfd.so" "$root/lib/libusb-1.0.so" "$package/lib/" +ln -sfn libusbcanfd.so "$package/lib/libusbcanfd.so.1.0.12" +ln -sfn libusb-1.0.so "$package/lib/libusb-1.0.so.0" +for model in yolo11s.engine rtmw_l_384.engine; do + [[ -f "$engine_dir/$model" ]] || { echo "Missing engine: $engine_dir/$model" >&2; exit 1; } + cp -p "$engine_dir/$model" "$package/models/engines/" +done +for driver in max9295 max9296 sgx-yuv-gmsl2; do + if [[ -f "$driver_dir/$driver.ko" ]]; then cp -p "$driver_dir/$driver.ko" "$package/bin/drivers/"; fi + [[ -f "$package/bin/drivers/$driver.ko" ]] || { echo "Missing driver: $driver.ko" >&2; exit 1; } +done +cp -p "$root/scripts/initialize_camera.sh" "$package/scripts/initialize_camera_impl.sh" +cp -p "$root/examples/read_latest.py" "$package/examples/" +python3 - "$package" <<'PY' +import hashlib,sys +from pathlib import Path +root=Path(sys.argv[1]);ignored={'__pycache__','outputs','logs'} +files=sorted(p for p in root.rglob('*') if p.is_file() and not p.is_symlink() and p.name!='SHA256SUMS' and not ignored.intersection(p.relative_to(root).parts)) +(root/'SHA256SUMS').write_text(''.join(hashlib.sha256(p.read_bytes()).hexdigest()+' '+p.relative_to(root).as_posix()+'\n' for p in files)) +PY +echo "Package ready: $package/run.sh" diff --git a/scripts/start.sh b/scripts/start.sh new file mode 100755 index 0000000..d471295 --- /dev/null +++ b/scripts/start.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "$0")/.." && pwd)" +mkdir -p "$root/logs" +pidfile="$root/logs/camera.pid" +if [[ -f "$pidfile" ]]; then + pid=$(cat "$pidfile") + if [[ "$pid" =~ ^[0-9]+$ ]] && kill -0 "$pid" 2>/dev/null && grep -zFq "$root/run_camera.py" "/proc/$pid/cmdline"; then + echo "Already running: PID $pid"; exit 0 + fi +fi +nohup "$root/run_camera.sh" --output "$root/outputs/live" "$@" > "$root/logs/live.log" 2>&1 < /dev/null & +pid=$!; echo "$pid" > "$pidfile" +sleep 2 +if ! kill -0 "$pid" 2>/dev/null; then tail -30 "$root/logs/live.log"; exit 1; fi +echo "Started PID $pid; log: $root/logs/live.log" +for option in "$@"; do + if [[ "$option" == --visualize ]]; then + echo "Visualization requested; see log for startup status (default port 8765)." + fi +done diff --git a/scripts/stop.sh b/scripts/stop.sh new file mode 100755 index 0000000..c372287 --- /dev/null +++ b/scripts/stop.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "$0")/.." && pwd)" +pidfile="$root/logs/camera.pid" +[[ -f "$pidfile" ]] || { echo 'Not running'; exit 0; } +pid=$(cat "$pidfile") +if [[ "$pid" =~ ^[0-9]+$ ]] && kill -0 "$pid" 2>/dev/null; then + grep -zFq "$root/run_camera.py" "/proc/$pid/cmdline" || { echo 'PID belongs to another process; refusing to stop'; exit 1; } + kill -TERM "$pid" + for _ in {1..30}; do kill -0 "$pid" 2>/dev/null || break; sleep .2; done +fi +rm -f "$pidfile" +echo 'Stop requested' diff --git a/send.hpp b/send.hpp new file mode 100644 index 0000000..54c0cc1 --- /dev/null +++ b/send.hpp @@ -0,0 +1,108 @@ + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct DebugInfo +{ + int64_t TimeStampMs; + uint8_t Img[1920 * 1536 * 2]; +}; + +/*******************线程发送检测图片与结果 ***********************************/ +pthread_mutex_t g_send_mutex; +std::map g_map_debuginfo; +/*******************线程发送检测图片与结果***********************************/ + +int g_sockfd = -1; +std::string g_server_ip = "192.168.195.110"; +int g_server_port = 8002; + +void disconnect_server() +{ + if (g_sockfd >= 0) + { + close(g_sockfd); + g_sockfd = -1; + } +} + +bool reconnect_server() +{ + + disconnect_server(); + + struct sockaddr_in s_addr; + + /*建立socket*/ + g_sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (g_sockfd < 0) + { + g_sockfd = -1; + return false; + } + + /*设置服务器ip*/ + bzero(&s_addr, sizeof(s_addr)); + s_addr.sin_family = AF_INET; + s_addr.sin_port = htons(g_server_port); + + if (inet_aton(g_server_ip.c_str(), (struct in_addr *)&s_addr.sin_addr.s_addr) <= 0) + { + close(g_sockfd); + g_sockfd = -1; + return false; + } + + /*开始连接服务器*/ + if (connect(g_sockfd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr)) < 0) + { + close(g_sockfd); + g_sockfd = -1; + return false; + } + + return true; +} + +bool send_debuginfo(DebugInfo *pData) +{ + bool res = false; + if (g_sockfd >= 0) + { + // tcp 发送数据 + int len = 0; + if (pData) + { + len = send(g_sockfd, pData, sizeof(DebugInfo), MSG_NOSIGNAL); + } + + if (len < 0) + { + reconnect_server(); + sleep(1); + } + else + { + res = true; + } + } + else + { + reconnect_server(); + sleep(1); + } + return res; +} diff --git a/tests/test_latest_result.py b/tests/test_latest_result.py new file mode 100644 index 0000000..e3be130 --- /dev/null +++ b/tests/test_latest_result.py @@ -0,0 +1,155 @@ +"""Latest-result ownership, optional output, and asynchronous consumer contract.""" +import copy +import json +from pathlib import Path +import sys +import tempfile +import threading +import time +import unittest +from unittest.mock import patch +from urllib.request import urlopen +import numpy as np + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT)) +import run_camera as app +from latest_result import LatestResult, result_to_dict + + +class ResultTests(unittest.TestCase): + def test_read_only_owned_snapshot_and_old_reference(self): + channel=LatestResult() + self.assertIsNone(channel.load()) + source={'frame_index':0,'risk':{'risk_score':None},'boxes':[[1,2,3,4]]} + channel.publish(source);old=channel.load() + source['boxes'][0][0]=99 + self.assertEqual(old['boxes'][0][0],1) + with self.assertRaises(TypeError):old['risk']['risk_score']=0 + with self.assertRaises(TypeError):old['boxes'][0][0]=0 + channel.publish({'frame_index':1,'risk':{'risk_score':1}}) + self.assertEqual(old['frame_index'],0) + self.assertIs(channel.load(),channel.load()) + self.assertEqual(channel.load()['frame_index'],1) + self.assertEqual(result_to_dict(old)['boxes'],[[1,2,3,4]]) + + def test_wait_replaces_old_frames_and_close_wakes_reader(self): + channel=LatestResult() + for i in range(20):channel.publish({'frame_index':i}) + self.assertEqual(channel.wait(0,.1)['frame_index'],19) + self.assertIsNone(channel.wait(19,.01)) + answer=[];worker=threading.Thread(target=lambda:answer.append(channel.wait(19,1))) + worker.start();channel.close();worker.join(1) + self.assertFalse(worker.is_alive());self.assertEqual(answer,[None]) + self.assertEqual(channel.load()['frame_index'],19) + + +class FakeNative: + instances=[] + def __init__(self,args): + self.args=args;self.index=0;self.closed=False;self.opened=False + self.frame=np.zeros((args.height,args.width,3),np.uint8) + self.__class__.instances.append(self) + def open_camera(self):self.opened=True + def read(self): + time.sleep(.005) + self.index+=1 + return self.frame,{'sequence':self.index,'capture_monotonic_ms':time.monotonic()*1000,'dropped_before_inference':0} + def can_snapshot(self):return {'positions':[-1]*4,'age_ms':-1} + def close(self):self.closed=True + + +class FakePose: + def __init__(self,*args):pass + def infer(self,frame,index): + return {'track_ids':[7],'boxes':[[0,0,frame.shape[1],frame.shape[0]]], + 'temporal_selected_keypoints':[[[20.,20.]]*133], + 'temporal_metadata':[{'left':{},'right':{}}],'global_hands':[]} + + +class PipelineTests(unittest.TestCase): + def run_fake(self,output,*extra): + args=app.parse_args(['--output',str(output),'--max-frames','3',*extra]) + pipeline=app.CameraPipeline(args) + with patch.object(app,'NativeBackend',FakeNative),patch.object(app,'NativePoseEngine',FakePose): + pipeline.start();pipeline.join(10) + self.assertFalse(pipeline.running()) + self.assertTrue(FakeNative.instances[-1].closed) + return pipeline + + def test_default_has_no_renderer_http_encoding_or_disk_output(self): + with tempfile.TemporaryDirectory() as tmp: + out=Path(tmp)/'must-not-exist' + with patch.object(app,'Preview') as preview,patch.object(app,'render_frame') as render,patch.object(app.cv2,'imencode') as encode: + pipeline=self.run_fake(out) + preview.assert_not_called();render.assert_not_called();encode.assert_not_called() + self.assertFalse(out.exists()) + result=pipeline.latest_result + self.assertEqual(result['frame_index'],2) + self.assertIs(result,pipeline.latest()) + self.assertEqual(result['risk']['risk_type'],'CAN_UNKNOWN') + self.assertIsNone(result['risk']['risk_score']) + self.assertEqual(len(result['skeletons'][0]['keypoints']),133) + self.assertEqual(pipeline.summary['frames'],3) + with self.assertRaises(RuntimeError):pipeline.start() + + def test_json_output_matches_in_memory_result_without_rendering(self): + with tempfile.TemporaryDirectory() as tmp,patch.object(app,'render_frame') as render: + out=Path(tmp)/'json' + pipeline=self.run_fake(out,'--save-results') + disk=[json.loads(line) for line in (out/'causal_results.jsonl').read_text().splitlines()] + self.assertEqual(disk[-1],result_to_dict(pipeline.latest_result)) + self.assertTrue((out/'latest.json').exists());self.assertTrue((out/'summary.json').exists()) + self.assertFalse((out/'latest.jpg').exists());render.assert_not_called() + + def test_preview_start_failure_does_not_stop_inference(self): + with tempfile.TemporaryDirectory() as tmp,patch.object(app,'Preview',side_effect=OSError('port busy')): + pipeline=self.run_fake(Path(tmp)/'none','--visualize') + self.assertEqual(pipeline.latest_result['frame_index'],2) + + def test_worker_error_reaches_downstream_and_releases_resources(self): + with tempfile.TemporaryDirectory() as tmp,patch.object(FakePose,'infer',side_effect=RuntimeError('pose failed')): + with self.assertRaisesRegex(RuntimeError,'pose failed'):self.run_fake(Path(tmp)/'none') + self.assertTrue(FakeNative.instances[-1].closed) + + def test_consumer_reads_while_running_and_can_request_stop(self): + args=app.parse_args([]);pipeline=app.CameraPipeline(args) + with patch.object(app,'NativeBackend',FakeNative),patch.object(app,'NativePoseEngine',FakePose): + pipeline.start() + try: + first=pipeline.wait_for_result(timeout=5) + self.assertIsNotNone(first) + second=pipeline.wait_for_result(first['frame_index'],5) + self.assertGreater(second['frame_index'],first['frame_index']) + self.assertTrue(pipeline.running()) + finally: + pipeline.request_stop();pipeline.join(5) + self.assertFalse(pipeline.running()) + + +class PreviewTests(unittest.TestCase): + def test_http_results_follow_memory_without_waiting_for_new_image(self): + results=LatestResult();results.publish({'frame_index':1,'risk':{'risk_score':None}}) + preview=app.Preview('127.0.0.1',0,results) + try: + url='http://127.0.0.1:%d/result.json'%preview.server.server_port + self.assertEqual(json.load(urlopen(url,timeout=2))['frame_index'],1) + results.publish({'frame_index':2,'risk':{'risk_score':None}}) + self.assertEqual(json.load(urlopen(url,timeout=2))['frame_index'],2) + finally:preview.close() + + def test_preview_renders_on_observer_thread(self): + results=LatestResult();rendered=threading.Event();worker_threads=[] + def render(*args): + worker_threads.append(threading.current_thread().name) + return np.zeros((48,64,3),np.uint8) + preview=app.Preview('127.0.0.1',0,results) + try: + with patch.object(app,'render_output',side_effect=render),patch.object(preview,'update',side_effect=lambda image:rendered.set()): + preview.submit(None,None,None,None,None,None) + self.assertTrue(rendered.wait(2)) + self.assertEqual(worker_threads,['risk-preview']) + finally:preview.close() + + +if __name__=='__main__':unittest.main() diff --git a/tests/test_risk_integration.py b/tests/test_risk_integration.py new file mode 100644 index 0000000..26e5ad1 --- /dev/null +++ b/tests/test_risk_integration.py @@ -0,0 +1,70 @@ +"""Behavior tests for CAN validity and upstream per-door evidence gating.""" +import sys +import unittest +import tempfile +from pathlib import Path +import numpy as np +ROOT=Path(__file__).resolve().parents[1] +sys.path.insert(0,str(ROOT)) +from run_camera import select_active_door,gate_risks,JsonlWriter +from door_mask_risk import DoorMaskSequence,DoorRiskEvaluator +from door_zone_risk import DoorZoneConfig,DoorZoneAssigner +from predict_optimized_pose_videos import BoxTracker + +class CanTests(unittest.TestCase): + def test_four_bytes_and_side(self): + for front in [0,20]: + for rear in [0,30]: + for side in ['left','right']: + pos=[40]*4;i=0 if side=='left' else 1;pos[i]=front;pos[i+2]=rear + expected='both' if front==rear==0 else 'front' if front==0 else 'rear' if rear==0 else 'none' + self.assertEqual(select_active_door('can',{'positions':pos,'age_ms':10},side),(expected,True)) + def test_invalid_never_becomes_clear(self): + for age in [-1,1001]: + active,valid=select_active_door('can',{'positions':[0]*4,'age_ms':age}) + self.assertFalse(valid) + doors,risk=gate_risks({'regions':[]},[],active,valid) + self.assertEqual(risk['risk_level'],'unknown');self.assertIsNone(risk['risk_score']) + self.assertTrue(all(r['risk_level']=='unknown' for r in doors.values())) + def test_real_none_is_inactive(self): + active,valid=select_active_door('can',{'positions':[10]*4,'age_ms':0}) + _,risk=gate_risks({'regions':[]},[],active,valid) + self.assertEqual(risk['risk_level'],'inactive') + +class RiskTests(unittest.TestCase): + def setUp(self): + self.evaluator=DoorRiskEvaluator(DoorMaskSequence(constant_mask=ROOT/'annotations/constant_door_mask.json')) + def test_body_fallback_intersection_and_can_filter(self): + record={'boxes':[[0,0,1920,1536]],'track_ids':[42],'global_hands':[]} + raw,_=self.evaluator.evaluate(0,record,(1536,1920)) + self.assertEqual(raw['risk_level'],'danger') + self.assertEqual(raw['regions'][0]['source'],'YOLO_BODY_BOX_FALLBACK') + assignments=[{'person_index':0,'track_id':42,'door_zone':'rear'}] + _,rear=gate_risks(raw,assignments,'rear',True) + _,front=gate_risks(raw,assignments,'front',True) + self.assertEqual(rear['risk_type'],'REAR_DANGER') + self.assertEqual(front['risk_type'],'FRONT_CLEAR') + def test_transition_keeps_unknown(self): + raw,_=self.evaluator.evaluate(0,{'boxes':[[0,0,1920,1536]],'track_ids':[42]},(1536,1920)) + _,risk=gate_risks(raw,[{'person_index':0,'track_id':42,'door_zone':'transition'}],'front',True) + self.assertEqual(risk['risk_level'],'unknown');self.assertIsNone(risk['risk_score']) + def test_hand_overrides_whole_body_fallback(self): + hand={'person_id':1,'side':'left','keypoints':[[1,1],[50,1],[50,50],[1,50]]} + raw,_=self.evaluator.evaluate(0,{'boxes':[[0,0,1920,1536]],'track_ids':[42],'global_hands':[hand]},(1536,1920)) + self.assertEqual(len(raw['regions']),1) + self.assertEqual(raw['regions'][0]['source'],'RTMW_HAND_KEYPOINTS') + def test_expired_tracker_state_pruned(self): + t=BoxTracker(max_age=30);t.update([[1,1,100,100]],0,(1536,1920));t.update([],31,(1536,1920)) + self.assertEqual(t.tracks,{}) + +class OutputTests(unittest.TestCase): + def test_rotation_keeps_complete_utf8_records(self): + with tempfile.TemporaryDirectory() as tmp: + path=Path(tmp)/'risk.jsonl' + with JsonlWriter(path,19) as writer: + for i in range(6):writer.write('{"门":%d}\n'%i) + self.assertEqual(path.read_text(),'{"门":5}\n') + self.assertEqual(Path(str(path)+'.1').read_text(),'{"门":4}\n') + self.assertEqual(Path(str(path)+'.2').read_text(),'{"门":3}\n') + +if __name__=='__main__':unittest.main() diff --git a/v4l2_capture.cpp b/v4l2_capture.cpp new file mode 100644 index 0000000..2f20786 --- /dev/null +++ b/v4l2_capture.cpp @@ -0,0 +1,380 @@ +#include "v4l2_capture.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 四字符码构造宏 (使用 v4l2_fourcc 避免重复定义) +// 注意: 这里使用videodev2.h已有的v4l2_fourcc宏 + +namespace { + +// 将 v4l2_capability 的 driver[16] / card[32] 转成 C 字符串 (v4l2_capability 使用 __u8) +inline std::string to_cstr(const __u8 *arr, size_t len) { + std::string s; + s.reserve(len); + for (size_t i = 0; i < len && arr[i] != '\0'; ++i) { + char c = static_cast(arr[i]); + if (c >= 32 && c < 127) s += c; // 只保留可打印 ASCII + } + // 去除末尾空格 + while (!s.empty() && s.back() == ' ') s.pop_back(); + return s; +} + +// 打印 v4l2 格式调试信息 +void dumpFormat(struct v4l2_format &fmt, const char *msg) { + printf("%s: width=%u height=%u pixfmt=0x%08x '%c%c%c%c' bpl=%u size=%u\n", + msg, + fmt.fmt.pix.width, + fmt.fmt.pix.height, + fmt.fmt.pix.pixelformat, + (fmt.fmt.pix.pixelformat) & 0xFF, + (fmt.fmt.pix.pixelformat >> 8) & 0xFF, + (fmt.fmt.pix.pixelformat >> 16) & 0xFF, + (fmt.fmt.pix.pixelformat >> 24) & 0xFF, + fmt.fmt.pix.bytesperline, + fmt.fmt.pix.sizeimage); +} + +} // namespace + +V4l2Capture::~V4l2Capture() { + close(); +} + +bool V4l2Capture::open(const std::string &device) { + if (fd_ >= 0) { + return false; + } + fd_ = ::open(device.c_str(), O_RDWR | O_NONBLOCK, 0); + if (fd_ < 0) { + printf("V4l2Capture: open %s failed: %s\n", device.c_str(), strerror(errno)); + return false; + } + + // 检查设备能力 + struct v4l2_capability cap; + if (ioctl(fd_, VIDIOC_QUERYCAP, &cap) < 0) { + printf("V4l2Capture: VIDIOC_QUERYCAP failed: %s\n", strerror(errno)); + ::close(fd_); + fd_ = -1; + return false; + } + printf("V4l2Capture: opened %s, driver='%s' card='%s', caps=0x%x\n", + device.c_str(), + to_cstr(cap.driver, sizeof(cap.driver)).c_str(), + to_cstr(cap.card, sizeof(cap.card)).c_str(), + cap.capabilities); + + // 必须支持 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING + if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + printf("V4l2Capture: not a video capture device\n"); + ::close(fd_); + fd_ = -1; + return false; + } + if (!(cap.capabilities & V4L2_CAP_STREAMING)) { + printf("V4l2Capture: does not support streaming I/O\n"); + ::close(fd_); + fd_ = -1; + return false; + } + + return true; +} + +void V4l2Capture::close() { + if (streaming_) { + stopStreaming(); + } + buffers_.clear(); + if (fd_ >= 0) { + ::close(fd_); + fd_ = -1; + } +} + +bool V4l2Capture::setFormat(uint32_t width, uint32_t height, uint32_t pixelformat) { + if (fd_ < 0) return false; + + struct v4l2_format fmt; + std::memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = width; + fmt.fmt.pix.height = height; + fmt.fmt.pix.pixelformat = pixelformat; + fmt.fmt.pix.field = V4L2_FIELD_NONE; // 逐行扫描 + + if (ioctl(fd_, VIDIOC_S_FMT, &fmt) < 0) { + printf("V4l2Capture: VIDIOC_S_FMT failed: %s\n", strerror(errno)); + return false; + } + + dumpFormat(fmt, "V4l2Capture: setFormat"); + + width_ = fmt.fmt.pix.width; + height_ = fmt.fmt.pix.height; + pixelformat_ = fmt.fmt.pix.pixelformat; + bytes_per_line_ = fmt.fmt.pix.bytesperline; + + // 如果驱动不按请求设置, 给出警告 + if (width_ != width || height_ != height) { + printf("V4l2Capture: warning: requested %ux%u but got %ux%u\n", + width, height, width_, height_); + } + if (pixelformat_ != pixelformat) { + char req[5] = {0}, got[5] = {0}; + req[0] = pixelformat & 0xFF; req[1] = (pixelformat>>8)&0xFF; + req[2] = (pixelformat>>16)&0xFF; req[3] = (pixelformat>>24)&0xFF; + got[0] = pixelformat_ & 0xFF; got[1] = (pixelformat_>>8)&0xFF; + got[2] = (pixelformat_>>16)&0xFF; got[3] = (pixelformat_>>24)&0xFF; + printf("V4l2Capture: warning: requested '%s' but got '%s'\n", req, got); + } + + return true; +} + +bool V4l2Capture::setFps(uint32_t fps) { + if (fd_ < 0) return false; + + struct v4l2_streamparm parm; + std::memset(&parm, 0, sizeof(parm)); + parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (ioctl(fd_, VIDIOC_G_PARM, &parm) < 0) { + printf("V4l2Capture: VIDIOC_G_PARM failed: %s\n", strerror(errno)); + return false; + } + + // 尝试设置 FPS. 需要 V4L2_CAP_TIMEPERFRAME 支持 + if (parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) { + parm.parm.capture.timeperframe.numerator = 1; + parm.parm.capture.timeperframe.denominator = fps; + if (ioctl(fd_, VIDIOC_S_PARM, &parm) < 0) { + printf("V4l2Capture: VIDIOC_S_PARM fps=%u failed: %s\n", fps, strerror(errno)); + return false; + } + printf("V4l2Capture: set fps=%u (actual %u/%u)\n", + fps, + parm.parm.capture.timeperframe.denominator, + parm.parm.capture.timeperframe.numerator); + } else { + printf("V4l2Capture: device does not support V4L2_CAP_TIMEPERFRAME\n"); + } + return true; +} + +bool V4l2Capture::setControl(uint32_t id, int32_t value) { + if (fd_ < 0) return false; + + struct v4l2_control ctrl; + std::memset(&ctrl, 0, sizeof(ctrl)); + ctrl.id = id; + ctrl.value = value; + + if (ioctl(fd_, VIDIOC_S_CTRL, &ctrl) < 0) { + // 有些控制可能是只读的或不存在, 打印警告但不失败 + // 继续尝试 VIDIOC_TRY_CTRL 看是否可用 + struct v4l2_ext_controls ext_ctrls = {}; + struct v4l2_ext_control ext_ctrl = {}; + ext_ctrl.id = id; + ext_ctrl.value = value; + ext_ctrls.count = 1; + ext_ctrls.controls = &ext_ctrl; + + if (ioctl(fd_, VIDIOC_TRY_EXT_CTRLS, &ext_ctrls) < 0) { + printf("V4l2Capture: VIDIOC_S_CTRL id=0x%08x value=%d failed: %s (ignored)\n", + id, value, strerror(errno)); + return false; + } else { + printf("V4l2Capture: VIDIOC_S_CTRL id=0x%08x value=%d not supported (ignored)\n", id, value); + return false; + } + } + printf("V4l2Capture: set control id=0x%08x value=%d\n", id, value); + return true; +} + +bool V4l2Capture::initMmap(uint32_t buffer_count) { + if (fd_ < 0) return false; + + // 请求 MMAP 缓冲区 + struct v4l2_requestbuffers req; + std::memset(&req, 0, sizeof(req)); + req.count = buffer_count; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; + + if (ioctl(fd_, VIDIOC_REQBUFS, &req) < 0) { + printf("V4l2Capture: VIDIOC_REQBUFS failed: %s\n", strerror(errno)); + return false; + } + if (req.count < buffer_count) { + printf("V4l2Capture: only %u buffers available (requested %u)\n", req.count, buffer_count); + buffer_count = req.count; + } + printf("V4l2Capture: allocated %u MMAP buffers\n", (unsigned)req.count); + + buffers_.resize(buffer_count); + for (uint32_t i = 0; i < buffer_count; ++i) { + struct v4l2_buffer buf; + std::memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + + if (ioctl(fd_, VIDIOC_QUERYBUF, &buf) < 0) { + printf("V4l2Capture: VIDIOC_QUERYBUF %u failed: %s\n", i, strerror(errno)); + return false; + } + + buffers_[i].length = buf.length; + buffers_[i].start = mmap(nullptr, buf.length, + PROT_READ | PROT_WRITE, MAP_SHARED, + fd_, buf.m.offset); + if (buffers_[i].start == MAP_FAILED) { + printf("V4l2Capture: mmap buffer %u failed: %s\n", i, strerror(errno)); + return false; + } + buffers_[i].queued = false; + printf("V4l2Capture: buffer %u: addr=%p len=%zu\n", + i, buffers_[i].start, buffers_[i].length); + } + return true; +} + +bool V4l2Capture::startStreaming() { + if (fd_ < 0 || streaming_) return false; + + // 把所有缓冲区入队 + for (uint32_t i = 0; i < buffers_.size(); ++i) { + struct v4l2_buffer buf; + std::memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + buf.bytesused = 0; // 驱动会填充 + + if (ioctl(fd_, VIDIOC_QBUF, &buf) < 0) { + printf("V4l2Capture: VIDIOC_QBUF %u failed: %s\n", i, strerror(errno)); + return false; + } + buffers_[i].queued = true; + } + + // 启动流 + int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl(fd_, VIDIOC_STREAMON, &type) < 0) { + printf("V4l2Capture: VIDIOC_STREAMON failed: %s\n", strerror(errno)); + return false; + } + streaming_ = true; + printf("V4l2Capture: streaming started\n"); + return true; +} + +bool V4l2Capture::stopStreaming() { + if (fd_ < 0 || !streaming_) return false; + + int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (ioctl(fd_, VIDIOC_STREAMOFF, &type) < 0) { + printf("V4l2Capture: VIDIOC_STREAMOFF failed: %s\n", strerror(errno)); + return false; + } + streaming_ = false; + last_dequeued_ = -1; + printf("V4l2Capture: streaming stopped\n"); + return true; +} + +bool V4l2Capture::getFrame(Frame &frame, int timeout_ms) { + if (fd_ < 0 || !streaming_) return false; + + fd_set fds; + FD_ZERO(&fds); + FD_SET(fd_, &fds); + + struct timeval tv; + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms % 1000) * 1000; + + int r = select(fd_ + 1, &fds, nullptr, nullptr, &tv); + if (r < 0) { + if (errno == EINTR) return getFrame(frame, timeout_ms); // 重试 + printf("V4l2Capture: select failed: %s\n", strerror(errno)); + return false; + } + if (r == 0) { + // 超时 + return false; + } + + struct v4l2_buffer buf; + std::memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + if (ioctl(fd_, VIDIOC_DQBUF, &buf) < 0) { + if (errno == EAGAIN || errno == EIO) { + return false; // 再试 + } + printf("V4l2Capture: VIDIOC_DQBUF failed: %s\n", strerror(errno)); + return false; + } + + // 如果之前有未归还的缓冲区, 先归还 + if (last_dequeued_ >= 0) { + releaseFrameByIndex(last_dequeued_); + } + + uint32_t idx = buf.index; + if (idx >= buffers_.size()) { + printf("V4l2Capture: invalid buffer index %u\n", idx); + return false; + } + + last_dequeued_ = idx; + if ((buf.flags & V4L2_BUF_FLAG_ERROR) || buf.bytesused > buffers_[idx].length) { + releaseFrameByIndex(idx); + last_dequeued_ = -1; + return false; + } + + frame.data = buffers_[idx].start; + frame.size = buf.bytesused; + frame.width = width_; + frame.height = height_; + frame.pixelformat = pixelformat_; + frame.bytes_per_line = bytes_per_line_; + frame.sequence = buf.sequence; + frame.timestamp_us = (uint64_t)buf.timestamp.tv_sec * 1000000ULL + buf.timestamp.tv_usec; + frame.index = idx; + + return true; +} + +void V4l2Capture::releaseFrame(const Frame &frame) { + if (frame.index >= 0) { + releaseFrameByIndex(frame.index); + last_dequeued_ = -1; + } +} + +void V4l2Capture::releaseFrameByIndex(int idx) { + if (idx < 0 || (uint32_t)idx >= buffers_.size()) return; + struct v4l2_buffer buf; + std::memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = idx; + if (ioctl(fd_, VIDIOC_QBUF, &buf) < 0) { + printf("V4l2Capture: VIDIOC_QBUF %d failed: %s\n", idx, strerror(errno)); + } + buffers_[idx].queued = true; +} diff --git a/v4l2_capture.h b/v4l2_capture.h new file mode 100644 index 0000000..5dfc2b6 --- /dev/null +++ b/v4l2_capture.h @@ -0,0 +1,91 @@ +#ifndef V4L2_CAPTURE_H +#define V4L2_CAPTURE_H + +#include +#include +#include +#include + +// V4L2 流式(MMAP)取图封装 +// 参考 quick_bring_up_64g.sh 中 v4l2src 的行为: +// - 打开 /dev/videoN +// - 协商 UYVY 像素格式与分辨率 +// - 设置相机控制(sensor_mode / trig_pin 等, 等价于 v4l2-ctl -c ...) +// - MMAP 方式申请内核缓冲区并流式采集 +class V4l2Capture { +public: + // 单帧采集结果 + struct Frame { + void *data = nullptr; // 指向 MMAP 缓冲区, 释放前有效 + size_t size = 0; // 实际帧字节数(bytesused) + uint32_t width = 0; + uint32_t height = 0; + uint32_t pixelformat = 0; // V4L2_PIX_FMT_* (如 V4L2_PIX_FMT_UYVY) + uint32_t bytes_per_line = 0; + uint32_t sequence = 0; // 驱动序号 + uint64_t timestamp_us = 0; // 单调时钟时间戳(us) + int index = -1; // 内部缓冲区索引 + }; + + V4l2Capture() = default; + ~V4l2Capture(); + + V4l2Capture(const V4l2Capture &) = delete; + V4l2Capture &operator=(const V4l2Capture &) = delete; + + // 打开设备节点, 例如 /dev/video5 + bool open(const std::string &device); + + // 关闭设备并释放所有资源 + void close(); + + bool isOpen() const { return fd_ >= 0; } + + // 协商像素格式与分辨率. pixelformat 使用 V4L2_PIX_FMT_* 四字符码 + bool setFormat(uint32_t width, uint32_t height, uint32_t pixelformat); + + // 设置帧率(通过 VIDIOC_S_PARM). fps 分子/分母均为 fps/1 + bool setFps(uint32_t fps); + + // 设置 V4L2 控制, 等价 v4l2-ctl -c =. id 为 V4L2_CID_* 之四字符码 + // 例如 sensor_mode=0x009a2008, trig_pin=0x009a2084 + bool setControl(uint32_t id, int32_t value); + + // 申请 MMAP 缓冲区, 默认 4 个 + bool initMmap(uint32_t buffer_count = 4); + + // 开始 / 停止采集 + bool startStreaming(); + bool stopStreaming(); + + // 阻塞取一帧, 超时 timeout_ms 毫秒. 成功返回 true, 需配对调用 releaseFrame() + bool getFrame(Frame &frame, int timeout_ms = 1000); + + // 归还缓冲区给驱动队列, 必须在下次 getFrame 前调用 + void releaseFrame(const Frame &frame); + + uint32_t width() const { return width_; } + uint32_t height() const { return height_; } + uint32_t pixelformat() const { return pixelformat_; } + +private: + struct MmapBuffer { + void *start = nullptr; + size_t length = 0; + bool queued = false; // 是否在驱动队列中 + }; + + // 归还指定索引的缓冲区 (内部使用) + void releaseFrameByIndex(int idx); + + int fd_ = -1; + uint32_t width_ = 0; + uint32_t height_ = 0; + uint32_t pixelformat_ = 0; + uint32_t bytes_per_line_ = 0; + bool streaming_ = false; + std::vector buffers_; + int last_dequeued_ = -1; // 当前已出队但未归还的缓冲区索引 +}; + +#endif // V4L2_CAPTURE_H

}1>N`pdFyk{4*8UrcPyTGB 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 z zNS2(}dSB!6bjFEUt??z-pU2NfG9TJq^)mQtx@K7)>5ALs`zV{tq->|=Z3td|fx3sz z?QTd6~J z2lFYPkc8@c$b)n1%SCLotOqHBUSjcP7W%o`5lwBuUZ}k&z5mJou00C%`9%H&%N#I} zToep@(7~`dZB$HB=}tjB(i@+L4_G)7Z`zz~;kb3V;3zpiDSM+2#{kzwSMMEWY_mxl z4vxZ4+vg!P^iI`58((A`o24`Q^yK*s6O-D9WA!j?O(9KZSJc0^14sF>tDJmyHGcW4 z26P-dRJ3&b)X$DQu-k{rTE^6RPhI9%`1QV__!alya=V3#hhNcQ@JsSxD1QBowBg_q zWenYnIpO0@BmCAIGiLyYspk($^Ks`dlojsijxE7TAUJA&%T%K-o6RmVOuhMstJ9L|M})&jG(b zf46+(gh6fo!{y^|UOr;n+Ui+maaq*|Zc{8|joXgvAA-x^HdOwY_5NLW4X*1S9&hBt z|4n$kd3jSNe-O78ea7zj4#10X36F#aA?@jw;0gI}<^9&dxHPyO6ZyyMtr_cbj?!cX z)teh!ukh1pTt4@BeW5_~7z_6>F`X2E3m>?ZRDkku7UY&PkbN&Fp=ezXUip zY(7J*>HmlG1@pJ*XGeVhyr&2J^U9eM^?Md$xEdZ3;u(LV8G-*xODJM-Kt583mv4Pc zbsb(leEIkP56X)l2JO!srhEmy0P&DpIMe?YW33zX4c<6I-)55Mo&NWACEwXQozM{~ zU$k<9Yw5mp45HuCag_FB(wp>S+~4WP$p2wK;K@7ca_>w9ev{Hw)F-X?BG`+z$k!-7 z&FcL*(I4}rSbdF;;Y-H*Y~+QDp1u@$rFBN>Se+A+JNIorQh9j!Qv>s^y5&T?e59#z46!k9T<`6;#+?#32;ck=Av#iRkeXboLnt2X2_Cj8!aT^;zb&Ekj3 zJnNTnkS(S2rM6l_<+V}ZBz;KzP};Z1uXWW`q#vW78`J9t^>d^8xxA#Gj}6z)t@Gcs zpAQ|YpS0Dwbwcd{z7O=1w7Ym$KTjXh&vNA8lBV+1zH);P75f=SEG#z~$DEyP^I#?a zCJU=_w-CTebpi8@7gKN75p2}FceIt){)YEAE9c?w(fPFP*Bqn$y1(E4J4@TIE3fTT z`)^WiX#19au0}TorxG9cY{f3;2C%WD64!EneG@SUfJ-_wsa@xFL-^4(fnV#um0Yp- ziouVLn7A{hNAL?_9i3qRq6uANGx^v5sjRjce~$#^Tfy-NdUoPn?%XY5GYh?J(K_sc z9rrkk^Uz8hKc;Hrf#}ABlk?;Ena+4kI8}yEpKx?KG}E+D`ibJ*i>GaS?B<^ysf>W9 z%Bye6e?2l#-<4nGlwWxlkymX+*thN&?JPFzt0r%oGNF3Bvp9}VXR<6gAsI5Gt1odD z=kVR{xR-QnYaQLr;xv7@iMqv)4CgEoz$AHc%PzGU#jh!{Aim6uz4~mmMU2`RT1Tk; zOPPyA=!4d`F~+z~Wc(4}8V9b*Be`-h^shX!L3F_n;?!M3x}jdPtZ7;DNaLKOKgOAq z?}ATiylO||Jr-=y(y-rU1{v&(G8beZ?2y4ShAo#m^4L#~HVif-#O~jJrb>i=wP=y zdSK824C2@XTY*u8eEP1j3J*0_^-*wD*9bVkFPkw+Ur!-5%}r5*i*hv-_rOm={dvm6FXzXJ)X!c90Jl+Z%-jH=XDfmQq&o=Rws)e^l3(cor<3^5o9Tf5LhbxbFh4 zDwlwcR8F=St+fq#<}fbxDY$pyO3KK0G??LA0m%2 zH$Gy_4Uafwo{#_K*NQkolxu3@}bt6roqu841 z@ao=<<)=4(m24sH`O#`;@~f#$T=w+>%lZ1=UTb*7g1C56qvQ+s_a#G6~ga~ix&f*(&{lZB5I zz6%Vi!{z^Orn;|paqg-QpAPLEW`LWwk5ggy0>2E5<+rIat)qjzK=$iNR~t#{Q5${a zQM+nO?XDx%K_9TlG4E@D!Cw6STkcqqSranbTd1cvat-#R*y=R?{f_CkaCn(BOPb?X z{u7vUo}$83w7cVy=PgycQ|j^49nqVFzs0yaciSlQT+|ru&kb##w@iEIp=|u_OJ4uP zq1djA*-IogFuHhh=cAmTSn1!N>n_NjYZk0KS9Z=0;NA*uJ^IS$?t8|R^{(v4Z`qW! zAIC2Of4ykI^~-8TnbgPyr!3oz&Xfdx?62KgGv1^gEi<<&EeD>SGK#b+(nfh{uF}Sm zhTZ7Vv0hplx;kY%X~gV#bi9{_{BAgx$~U>4 z^7V6joRnhGB}bUUv1Zfhrrk^O_`k;Hu^itfb+0^0u<=_T-A(^ZoyqmAkOYWPL@Mfk<0dUlY6qQl$Xs#|2_WyILf-?;LF&xuBMD^T8Eb(o4<>%#o>2D`Fpp|-`!*IcjweM z=kHex!{2AopMbxg$@5#`?{6pHaQr>0x_thAGS8O3S0s1-4p_b^e<#mS{{BbGNY07B z&x60u^Z9%EKbcKs5syxOr8yE#gKGhQpGm&x5dOYyfWJ>3#NTV)0)M~T=kHI_)=>T) zd5io#|G&ZC4fin~i@(1O7!SwaJHY3^&)=~X{~i9$d6EJC{toS>!{3()=01Oq{15p1 zzy2S`-+|*>5e10MP%JO;c;}P%458?CA{K%ujx06qNewy;b=e0lfR{6Z*mJH?d z`@~Q1g%F>=hc+_&9^>~leqZGm9m3}w%g3i>pSy{etUjMV1gstSi}o!#DI-2#PriW9 zuOzLM&wrP1L-~BK=Ibr+`THpw@%g;?m&fOiuE*781%A4l@GX{2U>}zpr19}h^WIv6 z4n2%ta2z?m58FVT@8Y3aZ`S|hNM+LZ1wpUtl>abu($EU;6^%wmA!}HZZKm#DsqSO= z5693K2g>;V!)ohA<|66)KD6Qsp}mU3%b(2j;2XXH-*Bx-v<|WQ_eG_ont0%zop!4Dvqe^J@9(Vt_*zPz~4Ui zxO@y6nUj8Cm0(Y?B0RPI;X0F=w&cP~DI zeayA=lH^&|Hhde!Y1v{osQ;9}Z96o_w(Lwd8}p zdF|n1{jTJL`PUw9F%Lc5=ic`)XZ{`@Gp&8vxM}SVQ%+~Ka;y!0N56GmYcKkW^dq&$ zx&Zr_vE#_eMxZh9E}dTeQ(rZn<(%iycr+F}4#pB6GKQCbICu;$`tnSF4A1yuNH7L$ zGTS)^uoJ!SxmL!|${6ss+11Jz?3rrLGaK}DY#r?nk2CEU`8SEiBGgqGu51^sYK?vM z5|g7^Qtnlxe7jUC-@~8%I8@yL{DlMI_?DLt>PnMjL*qz^YaHV zPwvI<6Bw1w_d53XgZ%RCsXQ*Z^Pl-Y1b#fqe_DJcer8Jj6>d6wKX6}i?SVU-hZ^~Q z2XOi~$7~kPUC!R!qh=w`$Hn7*Z$LA^1{p1&%4eV`>6J&Vq18XZtqjhjZksn{Pkvp(wu=bmMoho+&GH z3m2M6?XBdA@ZH#NrdKgLc8AQXAA)aq_|tV>GyYKVI=8kiZc=WtdhU`Y{XcT9)&-iQ zJ1x!x_TeAcxj8V^6e^jU>F^JHB_B_7cD{x6!~*Kqp61QKrww>$4_AI8n!5;XUO&mr zoWePIwb9JE^68@tXZEoL(6-uZvUn28ehE1J2|L~c;4wb4*a+(~2jJ)G%O8N{JbbDX zA*a1`9N^ol&Hgy*hm1q<);pOy-vDcjr(N5v-O{N6P8iGU_8 zEl!uM=~+A1X>2VW(143P5WXK^tWHGzbQXObT2#Lh*o4FfHLe$)g@@2ib=dQ5n(os; z)czAwleUl5R??22J;bkdOp%X`+7|t_vYy%t9%)?LNf)g2E+43eXisA~p89w2OVGCZ zR9!-cA;0ZlU;T0WUY>nF|DprY-%;9=3>szUdQ!~0(_8pH>2t(Mh?&}d0gl4!B>4SF zo*h%!uJ)g`bxzFQNLn-eR<;l6H&GMbE?dx#u^$9}oS!D|8p;cv*O5O#{;;3F**N46 z_sZ8>=lE53li%L~xIqhtmwU8mc@;5S_c1TQ^J_dOe10VVo;dK6?@1Tws&DlFVBBYx zjQias;`WZQt-UUHJxcF52pU|yk#9(Xs zSI))DZjeWho&|0S7j+I{ikZ@09+4b!+MB}A`oidUCD&VdcFIhrfp&M*nCFu3GpQxi zYs|#$%}45YwY+@CYo_YsuV;|$@ahz{^__8SVT!MjUf6wZa^d=O>s;v^A#3+a^tasC zjN?!Gw#1?2ZP7zZ>P%{NsND0Fri}y0?gO-wqi%R+>V@MtOG$mIH|pEdx~Mnq*V_p0 z%AV#>ukbkf%I9|dhB1i$3a=tz_i)6R!_-N?E8B0fd|+bsZNOUmRCc6_%S>hpa$fiw z$oj*}e`NWK37O61_}S_{G3`%&7n+{JyL`z#{3mwVO7~D?r8$J`>Rm@)!~?|B^88n0 z?=q`auAM@^6re$Y1^|$DpiMc4ecMOyp7pdl4p>gf^b#+JH@N_v(y`>-Xv`V`!JuP z&fqz~6Zu|+xtlJB{HVcp=^!)YOI3Y>lj#B;+Osk6^(gRkPA~+=M&+La4+R$@a z4gBquBM;ny?v{JI)>p(WlI(jA>r~Pb=yO`L+)STxr;#>7b#RWUSe7X^JGH-{kHWcH z#-j3T$ZKP(1HbXigY-b*lKy|jf9|deGI8|&UYlkLf1{jy#DVvYz(;(G^@TVwwT!w& zKblM7s7sv(p{vq%l(t`K(3MMjT0^N!g1s;Gvx7Q>JKnrJNvsy`Nk@)&^MNlm@fMmm zkAls;(DNRHT*v2vdEdgkH-XPRz@dz9&G4-AH)dj4A`;|G5m+EHz_a6@8OY6MY#B79khVAl8uO942{TO{*&mGHo zU?RK-;_&@e>9kcB_hQ4@XWCS3IQyLAYzWVJzdq5PboMwfk=}BjosWuan)wiJs6ORU z91L5YvnJ9P?X&BoejYqWoRnmRO;4NDk9qdy?b}x06YuV)ui=*hdNSGTnU6h}8J(lt zX`o^8dD&2;=O@OShFh4!zT$E0vvU3bS}#I-dD8MT!Q*qZr-Sau-l6WPm(M%6*KiGc zc{%cI-YQ&XEkasw?q&sJg7?dBrgk57sI5KV2x}7?Ln_AHiVv3F4c-ze>vhmGR7Ux` zpxkK1&4iD)=s@H`L`mIT1iv9k1f>S3LSRAD|W*t zs(^=L5IES$g8ktH{m`5SJmTm&;U`v(i>HYP3EzJWoOPB}?Mp9FOpDw>?ty4#KHv=< zv|-m!z;`umDjrx~@owmc+86=e%RbfutW;L>DYysse)jPE3~5_W^v=rd;CT;tA^2&3 z=C9%t>|GgXXEpRHx>*Na%YGCk#%T9Xh%pL`y%?yK_U`FV{SDlj2fwp@uC%;iFJ%Ye zvmayhRPaxA-_Cc@qv}^&%u-Wg68n*8c(Zydw6p=0o4jP6tVF=$fz#DarIhn(g0>2M=uG(S&U zdMwXMo&@>P4q!zL(R@9yI?WXBc~NKGxE~JQC3{2{F~hGL23C>}N9UWf7Cx-9N!6#Te4}L;MHztPGyvX+JG_z9V>szx}Y}S^K57 zEWEC(Lyb5F&{H{>XFOXa42(^-3UC1u^kkr6S#EVQ4 zdky78L(|ERp4lt9&m-qcWmp^@v!C{w&@xn!Uf5*Z)^o0m@ADx${hy6t3&@; ze4q&&lKheG-$m@-#TOPII0^o#GX21;w2p^|siSw8I^xtJSrzCKE^~31vPb6{UD>DY z_b@+_L&~eUoW~w-Fn6y|MtZ>!JBQ`jx%?}S&gXlx<$r^13Jaizz@~5weUS}H^6^TZ<5#+w=b<<0 zIh!~S+r`|-Hr#cgB9Lf&fqt+jVD zRJFaOBH7!8Z=cp}1>iUF&;_gCYpS+y9%D8=Gh$-zX7&fP=HBEupI39A)qyWGz*d9SwfP3}=AB>pFgM(@31l z>i#(AOx@(k{VgHleF8IL9%W-Lc6{;%vNR^&va*=HD@o;TnKA<(4EL%o^u~r;8OLuz zliO=o$c_y@F&Ev~$`o%#`p9tgvX|CyebUXu#uLkmdf<)tIab&@Td9*Z{r1{$dHXWE z-mc1C3|xN|nrLn7T66Ee!DRLYwo~7}9@y45v*w<}Jc>`n(eYjSTRMggzwa?(#Ru*D ziM$h`-LLUq0B+K~?VMvLzmm3}q0Hv{R;=Cpm*u-2;oIge&gvPnIgSp|;oAZu#q z_}@SAzlWb_=I1u8JbOL=L-jM^1+d>C9vawX6syXC@8r?b9LAyjo!okp;=b$N96DP6 zHYb&9^L6rW-$xES5Kc{H4sz&hIp{kleGB;CR%f2`&d^R_Z)HmMC!(JT{d3}>#{T{2 zbllb68=+p|wRF6Ey(t`G?rvf)rwKduk~`)>cT=<{Rge!<$6eFr>fW#X2Tfrlbxi}m zR`y62D(me+k6MW@Uu%0P(+ZziS#1jF4V#keowl;>?7;7UHC$~gYo8?R*ADnzl66*s zc}`AuQZ2x>RWK!={8rHCYX1t{*e7~!4gJ~7Pj~8Rzv16#+l2ei?g&@(8rIFN&_uG* z<=iQDC+4=BIvcT@OV*0c{|(w{8%ew5X+!U?UQjbPNn5{TK9hc*lk`_~c0c{qna%u| zi=b20$=wjFG1zyqapz>i?5TGPUHCV^mkKL@OL8JMVjq4*;A6+h`bzO_lI%wnftMX8 zb9VvbRNMyT(^xdlO^j1uPd@gxBeV5oU@btUs|4mKUq1Fo*CiccS!yNE5(S-15 z3b-TPHpaLD-Bvz!N9|IcKHFN)`kgidczmC+BKwGIFe=l^a{#*>dxtuwdNFMa4&CTZ zZSYmWPJNTCF2$p+A$X*-gAL)z?Ze^GGj}=zcytqE?_lpH$3E*C_I=nxd~MAg=Ao~{ zC(Z!B>MeeSdky$?!585h4}>x?@T;Er>MApvv^O6Ezg))M=;K%n9CN|3MsUpaam)qB z{`8EE_ipnEuLb)nXdmC&SJUt=_pXoiE7oPqt|vmhQEWwZ;LX+mpIBcU2RxMKf=hKi zE@_QdzkLY4&_R4 zNb8SHjAJMcO&@|o|4yC(93qy_0dVRw^hx+CJ|+6Ug7=t@55btUuFQw)ERGB}?~3;w z;D`ZcHh#VE)yI+U5**R`Ccv%RdDb|CwtrO8PEb~7bfvRNR*I)R&X}s-KW zRr-cxjzNCWMj?r9Ot!G6=u3y}Veo}b^l2&S1M55AZnmk*vzsYj6q%!Z(&sEq`FT9M z8TuscNS<4}sAD#6@NHCkx0zI1ok`hsHR~3wt7TKD0e56ujzd4;QP2%(J=3vcA&(ql zt(CL4?2LB{)vl?n9*>_W_>w=(6rKRDrhxC)cYFL4-q~h;8&bm6D* z5HTKsqxS2?XA-AkYXVPNwC{bY$7kZ~$DPLfCm5IVNe6;=JSTjAkaoPY#}(O|;U^aW z<6Nkp*v0I}0LSU{U;AA1;B)KXr2+0EryDK=w#uXLO;bEx5T_08T}mfbU*q&swv7b+ zlrk+^l@GaKoUF0?3{1#|ni5+KoZ_jkMkVD_wLiufsD-BKOfLR`x6@iV$xJ7hu z8a!8Y0Ib9(yV|&y_-V$1PN#gDV~sDN@sU?~lH~a_d2-~D-Ya{X3qPI3I5x{y96f)X z`ow%m-a7On;H!a7p+2eq>XT?XQRnf`01i)+78)DNbdM{`+{JSMFX83u%z?(-4Zqr| z`4aD>FFz4n!ZAx@!FTD``{{eN#rLD<%A`k_jg05pF0dfZ9`!nL^IYf)cVt2*n2ce+ z*BlQ_9>=z8?QGuJw8YccLHSlQ_Tx5Rv>*H<-#+>j=bIBT$u+mwA8eIqwAWs)OP zaq3AtIk>JZ%!zdW;10?_zm@LFS@*{s_Ma_%sITDsqwJe6Wxo%9;O$?6ryKT_p1&jX z5cgF+)M_Se*IN4h@D4+)scv*n;hx6b=$hIna@#e@^XlUGe?Y@aMwGWVk1cQC0Q`>5 zjkiZA8kLSc4?SiZ^rBd5x72)T?F;PJ6tN{8xNqg!10yQi54`rdU9yqf2`+eTvc{*c z4*uF|cOLE5(Qbrxqkg;ihi1Hc=h$<_k2?a~PbrCqKONZBk1~bb%!&FMrLW-DrY{5E zCG7FbALKjWj{09duDt!bmm2oqJUg^xa;_j_W0>H=Tu)DPCPEv#pyTQ@-~MQA5V+6wI1Jw2utdgQ#kQyU|#9vZ1H zLk^L?2iiNo%;QgmebNn~6Sar@Yy)otJNi26^>EAEJ9jDnm3r>WhGs4P@ow~U&2zFL zH&OO~(uZHG50sUSY$mjDc)4fKELq3b%3g_byixcj8{u?pdcpzAhkg5|gU#(G_>}CK z{U!Fyb)*IM%mdgn;rqTlv%=alFNFW5$+Kpw$19i{y|RdRCgNcVL_&&&%)x zXVidQZO3}8<>RIM0@en((e4YB*dQN2P-=r@zXTiP=l}bSV^}|Q48C3Mm!!*1rtyk~ zwJwQ+OOlKC^G)O3z&ItB|G>NQ_%{C?;w8TY&g!f7FC;@1yH0s@Hpr&uOt3GoLwB3_ z`vN=au%Y?;0z2xkn`vLb=1&uMhUfo3(bICq|9=8K{S4d==;;Xj>mQ}30&ocE>5-@2 zNKgO$gE!LCvOm8O7mJh~j-Jj0zeG=W@%{fRdivx3H`3F${_Bln`1#N=`1EAngr2rg zM)dRxOIP?y{l7|2o4GeV)GmF z!RMmnjZ#k^e7R3HAo$8*pXb6iv5j)~FtTHL4RQ^AM|O+E3Fz6#hmU}>vsusP>WKmT zSvONjA3DP2y|2Uj4ZizV@~sTHxCEJ~^tkrt_@@1Dt+D7EYZCg+no_ohkActWBgNVI zo>=XgCiG_P8QtuuR%5G)$sYrLZ*3J<4YpNaUm4K71Dl0x8;6%~xBGA|V~j9H6ULwB z``|iyWgZ_=tpjxrk}<{mbSKa=?7KCx)_4ZpYZNl!D&5zkwKei?1m$Eym45i`kSRz% z6Kr%2+d;pRJzjG$7MLud?{>|gG4m|}%+T>RGj{nKTVKzXwv*>7PfMt}pR?3K)$i^nyLY#bBV{84U`4Oz-Kl#+Q;sa^m+0C9`vCh;MPc#Js-)}lGlu1+9 ze^5`7HnEY^cJQ9NYh-2(X+6{@TZOllo0xqLS-ydE*+0eid!U1~bW3++>J(^1@Z??$)CU4*YVebcz9v*9JdR*Eu4?zzGETM*`khzyK(FW--Fd(+8`$x=GbB3$dN{zj zP~EpKd*~1C*u8U~KV<$}m)G`d?I-+U-D~YU!hsuj*4kX_+hF~!b*|R93Fe}!&7|H7 zeBjvwYj~}1GmNK$*oA*Vw^_^n$AhCQ+OIpAajz$cSt&3a`~lvr)JWr0E*nSZBOc^`HuD8T@(!{Ko z%$eBQ;x+9pBOmN_sbBWcz1#3528Q`_Sd&^i9Q*q0Cx^xWf6}_^;g8VK62|Iat1+CD zTXN*`_Ud}^(W-1UwxK1=NB2Bq?bIIwUOMmlF8E&^^K*W^aFes7=!xf3XY2BF`gP_x zPrqeHgyuFSm(T6r!x-STc7AeNQ!y_w+HN!^m$xq;GnM(M$UZQxiaDCf993rbP$rH&yBM0%8-a(YPSJOA z`SO0*VY-2Lj2MRla{*uL0XOtr-_(C=)25uxlLuqUF(#KWX&+_$GQW+tg2g zdtLZY8X3aaGxZiWo_*V;jTrE$r@X-jaHwrku#kOQ@CfYNg312^CP!_Po=xTucoW#S zli>AA@@V~I`Kxb}`32)aHmsWD+p)KRSAktdF)#+Lc{s=K$p&xTldtn^G66ik&o~1+ zO@OZrq=m-GPBSVaJ7@q)!`N5Rw%{NecK}QEPdc;4Z|y(e-WJ}MLu<=9$Fh`pT!UR< zb-02U?#$a?n72hs`e9T4PSVV~U^{?!$bu$|YqTYN!w)dIXjXq>7=ADm-_91k z(T4bj=vTa0IQJ;^82Ud&$deasRzGg$GHK1{-<%KFamj5#@UVOjOo;AvCN2RPNs#iol;Sk zDXU;F3mC~xyN5dwUks1TD$gkuPGA=591NPb8`N~_a=3TRVMD%yfg;! z>EXWL=6{!cO#TU7{{L_IS3hLG*%HKPNuFe5cE0!~_@?+o^4XAGIgb8)laF_|%xBKQ zC94;Md(gn_4d5Pn)GKx1o;R*ZGny^_g?jUXpC6+r4gN`{tx#W~PXi2d_-4v3TU`8R>T;4Sz&0iFZ*Nx-WV_Ury0?Adp%PU0g8j1(g(fd6#HmORmH>iDd) zIKupNtoQsVJHE;~5}NJ!w6nO2J*tksI*VQA-o|cP>ez2L(=YAc9v~)C*Vb9>;y=lg z%xuYIaPAewsG4r)o_h$XV<~h0{MI?`zhv&?A-6WkdUYIpCw;FwHx1um?PB>(dW74l zc^JjFIQWnZN9I(Ume;m0KWTo(v`*3Yp)eIK#YcE?pLC|RiLwrOgucH}^cezXv9$R} z<9|7eqtI9cJ|dsG0In5$7p)|~l^UKK4{`SpYtbg~KLYH9GqRKFEKCI6SN$@w4VYB# z#h+OJE4iPPbFVr27$sguX`CnVYvI_*j7d0}B%V~_9(XF_kY3z$=cSqHhhnSap>TVG z^DBvk&HXhCn)+YC=V$0RO{n^L%|$L<6rRV(s#-UR{u&`0LL=ofCb|S;3(cF9+sv| zG&do&8CkD)SMSi%xBPee-AqV*gZJU&speL5nq*F!!Dr#ZC#v8r^r4I~u0Z~5SkSzz zK793@j*ZX;df6wyt1x)=j0rC^%zMXYoWTMnP1Brdz3KYjZei{;U*eUTzsgQ{8S^5YJdT`MhRl;rApJ%7EjcC`93_TX zEOhnRiRUlLgcws3;}Or$-B$94GvIx0G&UUe*mTzJZ27|t$i`W713J=q5#fybSh^qO z`NdTZl1sn;t|ynQZ{3i()L(~vV$~%(bq=|d=f4A3<-wt}4=2rYDLmHUcbe0j#w+YN z1skn*mENWFBr*ILztU%s?&)#(*Oi=a)3*cYnpK=3)*9We%TF`x>Ed6<**57M(y!#7 z7-0|cbfbxxEWMcja`}U-;K;4pnad5`48WY+n5x zerR6@rq6`Tt7Dm?D*VkfZozNqr%mQoba;)?p7}ma^1wUu;Mr-seWWvK$CjratyfdP zR{n-L&RtIi4|G;6$9v$@EBabMo?jD3N9V041K(fr4}IFR+~43^wZT7T)rz%~u`|kl zEjSw%z8ko(#t;lzpoIu+M!=OgYlb-byl8^8YN7PJkIt6lSueJ_?C+6B-wZaAK!5e- z;pq8c)vbA`iiA^hpnvVpO^%0C=6X-3Rjj*e+G{%TgLcm{4V@|W6*~Cb4pX@(0{?CX zmqnLX(zh03K?{%L%$-Bq^6UID{l3}9;{^KAJp4LUUnApQ2Obyy!d-^cBixBtJ~1)% zHRPY*8wQ^6r=7xU>00kR1}+EnrKzv9e^GE-eRJs>df}q$;Ri`%hYJr7A9N)zkehk( zY3>7j@b=}r{Zi>_k_GCY@%z_8|AKjP#(vPwlh%w8_)87*61v)(w^L}hW0U8D-|cdb+%x-}C%2ubKHS_i|m=eeL&kBL_o#i-!rmTFc^Dl0V{MyP@gq zb|Vg-%f4PtAF5MUOB>={0s8$Cc3$>#<{P1wu<=g{udNJ*4zrIWgO6lCE4W4k*XE+= zhk$F(|3qQ*gZ%g9&9w4(G}kb+4%^WO3ciUUI@Bvwkr^zkRVPzMuWdnrrLIO!wVfuREF(yM}9z^84?c zhj|g--#jTY>q6!~BsVhag8xpvb#<<3xti-&m9dVgRigf{tTe#~_+C_Fg1O=1=(VSC zJy{&RW|@8cYhyXfthqS))wPD0YEJwsA2lss-eiJTpJiIU)Xw)OX!AVNvY^ZpoWC}w zYhKxar>1_$ESWdov|QyK7^D5}x)V?SPNwm&q`ts*OF&cdl6?_6EF_X;y$z$ z-ZukZ=aASO`XJzYB)n$5f>TIrQ>cKdqnRo+!iG~vjEN}?Ow-=-w0eHBZdING>^kNBE+ zsrX$OT9glEFzZTfRPk-oAN#wV{BrT!;;=3EBqtTuko+^`Tq?fQM1Hw+W##B-Z+AC5 zy?`9^fGKW!k=RdDZb9cNa?A&zAMLYp%&|xDf&b42doN)MAMMZB3qAIv5H)W`$HVdy z&JT1c<}xQ8i7Do?)a16Q24y%+jt{XHL#`d?q&>EV{2%F)dD5AQ|2#ySYDYD+INQ5n zJA5v(JTm1Ayqg3!DQHRi1Tyn$#*o)CJmc0J%j0>azskot#VDV1{}cLik1N@Rdj4Z}=vx{l$V~IFguR<+PhCx*`Vu zUL-PQMFf6MpOHwZl^3sA&JtvQOHY1#NvC0~Iy+nEeW{%g?I;&ML_6TDJH-3pp}>Ro z=Ae(M54BTil+*5QxB+`u`raz=z1~~UAiY6;%$LY%f6>t$BtPsrrS?AZ0`!7H*2wpu zl>%Zh_wwD%T$H<923(uSb6Q27(<<`Q@8lZuvGjrm>0>bWHyE=ag1ACP;Iqca_V-xvjU@F1YPe6Gk!TnnseB(HyfE$ z-44-x<1*SnH%X#vbln7MXRb~YM|4tym#A)p;#Kawdr->`=r-_?}=WSLw5q2N%Ae)_$m0b z^N)(5-2(b7il>jJ8+C6z_XLaAz@5Hd=KK4M-Ns+c+6OAWunnB;C)df9RflmuBYA4#+~gUNbG1(D%e+yGzC&eEFK3dbIooS*=g?SptuNTV-L#~a z`-188iLrG0BtFApsr1RQ^g8@e>HJvwLE;n-qi+Bs=(4*N8LKrRdpEKcdi;W?rEB?s z;N#Qb*Tgk+ZrD2RYb-U)NBmfGl3p&~T!3pAeUANCcS84!OZ<-Zs=mjXOD?z9+kN_d zHEr4bkdJvq7e3(zk6-l^N{3$y&N{x}o=2yeCQxtKOXQ99YYtOQ|>ag}(LXUZLJxNqYLqk~-h&QuYb?$$gYfth!E;{S(cI zwx@<-^A0TOEFpIF8Zx=dlJ_O?O^+XKe4FuveT7y`Qu~KCbf>8$z&U!}5uFM2rG3b| z0r<8QkJ-Q{O*{tPS`{HDp_x302=&RDsZ$Wit>oJqi%`p>l=w+Ka&IFs)8)g-DF+@u zgXb%*t2w)CJ2E(NZf3j9-li!P*k5)(MdW30eiSq}n*No4qGuJeR{!vSD-R<~e>LPz zsLwEC&>5o<#-aXe>AQ(BsQ*U#uD1Fw?&&{F|C#MZoc^c!ia2wE8kh7fekvN%bCtkG zImY$my)1z~wvyb)mL|T1 zGY`K@Rz~hCsq?Is?Gdr^6h9t)g0?&0p`sZdz6OnBFEA+pZ`!-yVcmZUdR~s5-1nJL z@gY2;7_{ue5YO2Az>0h5&GOYa^BT&$>{wx6n$$DO`xwppd!Y&Or~QxF?FNw9OD!0T ziia8JsajV~dtF_e%f-9y|9$*-_mK{Ap6j3;9 zpkde6dXarjdPX_XS`XCpZ>f;%y4;ps@}(yRT{6k4(?yK`HSCQVa(w5Yj|i93c(zG4 zHnwx6U$G>wmBZwRm)G(^rrdo)J9;2?(SdSelO4*N))|oKjx$Y5d;Wl!#+#JR0Y5bO zj^tO^t@)xe1QN&*WcNaJBsW*yym;4^@#uek)BM)LqtjO|BoDq0-`wrsMeRPK_UPkb zzLk3&CU+opdEfl&dSKnd+egW-WamWT&qXJYJSvXwK`*E-0~Ww>2QXX%4TYIgz&|oN z7rjpZ{n(HJGb$Q({@eFQM8D|%*Zpuw^t1dIoHf2%obfHUzVqWBxA4+i-&6Eq#^CEA z4a80BhdxnktO9 zsU2jTKda`=FCITyEV`E8N6*VAX2B*S=9?L3&K}!*~}QW4u>7zh#iFgl(Da7 z47mx!E4p{U<8qK49~{P6LpOQIv7ojP>;5nBrCq0^W8XO-wsU1}to_b`v8Tyj5BK3w zMe&VXt9E!)H9Tr1JSvG^5k}YWIy|bZhesKBl(#d_;!#EM6}&4Rvy5-;n{s*7TIkl@ zBXWEmB_5g|e->Xzy~Cq^3LnYjN$0?`Y@UO^+v)Er>zi|dz=dts^zMt&x|V)psAu1V zeRk)Mk2YRaR2j=9XQMTpe)LMtUl>s0iv^P7qsRdEQ5gBLFTS!JeHu7;bF`0+?>y5z z_r&S3oS`|fxi!)yxHgnM^W#FYa~`SrsJ=aqguUKJe5YaSCOuK_hmB(4&*y|qOJ%Yk zI`=GcWG9&JX3i0acxjI_1eT!_{ot${G-2)O=p*+iPBZCmu!5e1`Hk&Bu9D|^3V z5}ujOuOhsYy)ME$cO%!E;FVez>w!U4KYJmsd5m*>q$j{n^~}M3`AR=qhyNw>J@;Ma+wyMn&1)Lk0lQtKh>%-yQak^^hS7T*Mrcx)(JK;b)s3riuE`;NAr)57Q4R{D^Py% z)9`octt-d}vw1vwV)3b@zDi9)`g3bM$Pd$n9FVQ2Iv^vbndoHtI+PwrKHP}Tbh$U^ zC$=S?A$$Cf@V4(x8ykI_n38m0@x^-VVbP)ZMYX1{H#&O4* zPmG*q+ZHP66XPyt4BE3LJ3RT-P)h>Xz-O0~=9F9;W{mlf$SmcXFQf+j^Lz{T!p9(F zlit&Ogd@e_^}PH=BWY7(o6EN?zn-%Eayj@;^*%blqr$)9rWNcXc>vj}TBXam{{v`b z7rq(gC%V47>+v0t8}-!G5_63oJN^-1qncA8>V*6an?^aAVfKYg{TTTw=(dKsl~4N3 zglhELGT>CR#Y3I|w$NB|+OVD0e9%9snl;9?J^o>#L!x!bznZh~@s&ZNjQyn7Y?&{d ztpTsD&nfkx44VX7_sG&`Enk!N;)TiARt@W^?8j^7tR^qx@Q^1dACmNT&(}gN)kjX6 z^gr13ioGRyMzOe7=&7}aT!)cng8UcYY1}4c262+c@Ro{Tf?8|s*r2*DxQ0Atm2%&v zj<#z#X>Z^fuVUBC!$z>j+K*PM!^T*3xc1Y@rKc*iCxV)n=^b`kV)9~j|MgeqXl{B z55Ekucf^CQqac0+yQ~8`P5DMLX8CY^<7&Tn$=3WQ(~ZiPsRrJ*y^8-3oT**CZ?%nY zQf-#dX2~?QR}$wOqMr8DmaeJ2^b_euw0PHK;Td>v?FC({p$~Fj z*iT?xYcS+DR2b7x9ts6(JJS;u^Q`8yh<-jlFU%gCg3e$L@PzgP_+$i|fEn4Q{Y&bn z34RuV#)ZRrc#(YJ)xg_N?r%VNGiG=@{JA;LOe*t@Y*U@4IXvq*08O1>HmH5&1ubH1 zE)9x42QzNLWii($YRoGt@Hu!oD|V%;ywG}J7;$xS)mnGb4$tdd(Zx8P)jHh7{3<+t zYA_U!JIHm>dU!{AqWi39UH1JcJg;Zo;J5DS`XZjywK~@JZs*-qUNdeH|A#xz!{=97 z>nD|-sG3$a_{ju=4)*-k@|@xnCT1_|j{CNjLtU_i7kt<)Jgq()_pazncGnSMC2gZ{3cc zjEp}i9?bq1t7aoO7LO18#ipS-&ynVEx2iN1)mkj)Q$zFB?1lW zUdMt^i>{F;GtS4F(>*<}`?^;L57F5TI`1On8{NPjKTE%soFuMotwX``M#dx>*7g77 zdZ@j0lD~cGSvqS>bggHqdB(PjM#a7S7S5js=B3De<-NgM;>vk+ePpwdAKH^xFvgZK zk~Q~GC;JKH)(U>hzHFSouxr^cZ^OOFxSXNH1c)IfWmoV!GJkxRUw9v^Ir-w1tczLT zsgdhXaLv+tl=Ecyq3k*g+u4(NA?s-yXH@DLz4J-lX{Jxs-DlL+Tg>ms(#QJvw+z3tFbGCy)|5+18~v*4z9^IYufK$x@Gh~3W3GnS01<-hy^mBgEgA#SOp z&kEwr6~vn>i8ogeZ`NMJO5)9x@D;(^4D~i#^{vWSl6dG&>}u*QM0LJJx-J*{J$?7p z;JF64r0WL8Zh%JrGAb{2KKSS$?h^7tOS4V4F?ns~@O0~33+++T*?8&n;8+njP0v9l z50cNhDE{Ijthw3ZS49m;`~vOV6ForR-6n)y6)Am6Yg#<6W18^0;v; z;F}z8|4!+5x&8ak{FV=swM7k9csA?b0}iV#9j?&Q;iNCxwDVg_U)VWhdTa;qnhUH9 z&yI!mD$RhlbGtdC=_QW6J zn(6}`S^DUEr{6l8ex=`u7DdPJM!)A6S3$F) zW1DVmI+m^?8eU9(&5T#3#dcv6Bxe|ljzz=UyaU^|;pg6V^MKXc;Vb78j}i^P{Dw`# z_iEoUzNB*IsJO5j@6ve_(`irioPwUWd2^h0h-+og^;CzhMV~2XHx2Ek7Z5L}J^0Wb z)zy0%8NX>T`vak+IXULXn|{!A-)iosSPP}T-nBp+X>f|QP%`Y>)>=6D@(Ho7PSbMt zwzT#MkCVPqf&3CZi|!wzjlGv&X#0-EFOk9WXE*zZuR$a716H%<_OpIm-|z_0m9uV& z^xIiC`TFgwn_>L6)=gdCb(6BzO;PWC2pZ^_C-?ZN1)yMocV_%%cD zK$4-V%1m=Y;yD0)aeiOf@>?Xr{dj$Jdc2j~q5we@mWw7^&C&Ih@==@E{ zHh4&ttLLVqqn}yH9t|@wz!<8}^rC-Jqgi~-iTQ=gZ2y4j&2QX^eIlC(J^VM0O%#Eq zT)kiP9Ois*;U%*T$yv8vy=){S{R|sPc(L>DGxnZ1{p$H86g84PB)v=ako zuLIx0O%?Fb9$M{RtYwWqj$O14d#D*b_Hn*5$Dut%)ys6gy`AS>&ARua&+>nMJ+_wG z8G?QtL66nA)R#F?`GLgcrOyK^IL1UhSNjR<1qYXjx6%`I9+7f<^=u4%!Bg97gRMD8 zJ}vi;H`i?k?6FBt()gOS4-Wn$+%=Qe=Gtgeu+dbP6dNo)3K_g~nytg$`?hOKjmD0m zPJv^a{qXU0<0#P`uu*$zJL1@8o1ih}4;yxx09~p&z^*Ab(7_ldaYT{$9d1 zdkKCdd+npZy$d|bUUO-Z{cPx0m9hEn0@KUErSS0q+7Qn4`#NwaJk&w!#STu@?gs3P z>$s+NrN_^vZRK4iUOQ=$-o3^7Pt1E(q|4Upv4gC*pMUSvNk8Pi=qa`1jI$~-p7kFr zofPH2+7K*6H`nU^fznB#15?kEzOME1@6vy2S@S7+c);%Ve*-6cMD zHuQn-uDcaIY6H1+<>u2+I}@ptIJIXDYrXeAFYebUtByKelklXC`?$(=SXesGwjrU zi2S^jmMv`iHr7IacM4Wq6Ma~@O8AXh8MmtoX6E#XW?a8fwtcxB8KX71|KYy&Wh*kn zFrI40qjiqouu6T2PIT^q=Bd1lbC5r!S@vG|?eqk}=mnme>a%O2$lg#CyX#q`00%UM%`?^tBcm8`3s=;#B$|J&GyV~aVT z6nMI|%oSTa2+#fn`6I4D%1Sh3tfOSU31L#;AIm=J~*Rb|BC8x!dv+C!}Eaj}0_`FU|muGdj@RGA+ zL#n=wXj8iP{)_Ws-J=G@4xn$}UTW*tBmQpd*ROC^wCI0koIFt9O_Gs2*=|HnbxoOh1y+e9+ZSR9k z_a*3Cy0+}j?hLzAy0&e1j)))n`w6jw=-N+iO*fXHXV>FXO?HM_nmr$zWXy;&liVA~ zy7a)SG@lf8Z+^(L(#ZqBIXUorOGoo)jE;W(EBZZn^@TCzt{L!svGPnt#6Qk;S2z8remna4>HOY2JQS-pzP4{upHF#1$a51BWUzlsqSJA1jn^)E)I@{HhfY;f1iY?^L8rHU%JO4*q0?lBKO>VK=Q#AZ8Cn!w z?SQ^AY0IUn9nhG38XXxvjX$@$K8+EUPviUKyLI8yc#3`L$*u5?Hz(ONhY#dL;4j}w zr9*e^4FhB8t4+6jBfrjS=Nq(>q@6H(wA+2>f3_iyHWf;8p?L9tCcqCGDBj znPGGJ7R~B+`1SM#=}oe;KFGK7&Aj}6hTq~x*TC~5*f{cGJO+Kczkj4P2CYg)q%2zY z#Bb(W4&%4w#)!CgC*y;cKh1UfnlJi@d>)Q1b}iRM?@4U2ukzcf`9yodOWO|n-3`vW zw*R9y?@R3&a3Q-Wz`PUqYCWurde%w-^lhMf#aC5xH;g>3{#Gb<9cyv!$WV(N2PurN zV4cq$Xg5s&@3~h!rRfe83VV=J$M7wG)$yy0P-?gWRuiAEy z&WKL<=4`8G%}?bS$)8%}gWIQ@x4j}~)R~LvPqD)YF->fxYpb!NH9kF~@wwyriZiZi z?Qdl~b%Wp8U%>BqfpIoy?rYF5vgclbA6R=e#9!0P^VmmeEZHPE^a`@cQ0LRKUpITA z(}*EjxjrX(tXv=I0f&8F>zAmCo34j_Do^j>6=%Tno=aAG#~O z)wcwBcyW5K={A4VnF5h5n|_5~Zuv=%6z>SdD&g@5XR=0?UD4Hko9SLMzq~80ynOzL z$?adnnv~omK6%$4_^6(A{n{D$T86~d{(MGvIXo|5JW=KLtF89B!T7gqKTL}DRxzF{ zm(S>)yO#V(YM?*BGvONhe6^j(taJyp7;Z4cBso9!CFuAD@;1ni3KJ`mo-6v_!82uy zqnc})+r|7&l0W@enEEsHHEc?0d2hJ&A zB^Yi4t{UGG_C{^vzTkL(ck}7rI&bQviazH}wXznd%Qf!EQtjQ!*e{AMEFBOUiHeR@ zTd8tTWVna?_iFZG`LVB!@p7cc$TR&VrbYbW*w1{xdggz4hVv(fZ{~XrV^+>ot217~ zF#ukKuiXx8OVQgj=P&6$vC1d-W}Uzfly~fj&$q7U#~aOYEw2u*pfZo__G-L~P*5CVzw8nL};YXVFV@(8JYkIqzz{ zl{02P<8X28@~8gBVVrSX=8S{$1Kv3fbZ%=L?E7@b@mKg$_BbqmO{I@LRyh`rxQ==5 z7X0CDpP+r_J5IWQ><{t@XKl6M+Iz0gdiD!hynTYrzb7)Udi3Tp__=D;Yi-{3(9uT4 zXvlpY=jNLvx0@jF!ViPa3qJhDSbNM3ax{#7V(A^Fef^sOp0nTsZ*^-Yh}PK46HR^0 z&KdtPW6!Mb@Lt9@@82-K7H524XMCRbaUSbEj175zjPqD~?YjNwapbXB{9dx63wk%~ z6X<5oTh)WsnW^0)%8j-Dv|r&K@KJb^mvcOnD^wKUMht$Vx2W@V_)XDC$avto9h=<% z^C^tMgX~uQq)!uLlFgQ~^fCA*xggR-r&7<-U(hrX-_!(m&m%sd_y;uKVzp=6h5_*F zDK?gG$+FqXh09-9viQr$U;}QgT9EXkF|@EQ+`b2+)5^!z%DD!jIjtA@vUS#~e~_8D zksQ=7;TzL`^>-fQws=t{-^}RGFs^2FA@%9@@nObLjK11P-G_EyqCV8_VBnBKKUhO- zN&97VUH5fwCi=4Be~PiG=9$LEnx5stByuo4@p=coI@9|pp2??=h0MdvwGnK`(TDg* zn0^whX|+>EJ9b8lkqW=E2Uw$56{0**ae~airz7E0kN#3*jVy?Wayn4;) zacDbpPJ)}})65>IcbkvKv+_`SgM4`%j8}cz^*cwzRX^zn=g<#u>UoI9OOQv>ZweB2 zE|v6O#e;M4uS!SqmY@?3tg!rCx1s03l-rE<0-J$tcJuIczMlklnVSmLz!!90G|Qo(-24>1k9 z*lY5lkvmMR9{WE$(pY{9m(H)Jp23`)qR!jVU$Fu9T+aW>f~NZ}C#IFg_PZVZB#E#6 zD*8L%Eozh9Tth$Gj#g}y{#;34MMI0&H%ra~a+I3hZIUHpc|OeeZU;9vUSVP{vlltR ze>0GpFDIefF(!N--HG{2x+08Sem7laV2^DZevNCEGcW37Ze0N^76PkfymS4D zMGaerue@&|`*5eS9zLa54R)@v;$r#nKR95 zJkEJy&9pa=F{^#6FJP}e>Vdu6M=kw|$7;{7d>_I?jfDs7C;EvnzOl^x+n1SGjkmZV z%zx1h@uY5(92kuZC#Sv$+L(VsmuMz}ZDL(7Gu_L^y7cn2#TPY)q+pM17M!JXKTIF5 z1LsHh&eU_H7ipcjYhl@m)4DwVQ1`v?4EY+Qd)2cR(EF?IFABw`lg|(eQ;U%`IxWwp zRZEWo7KZ1u^%2q9PJB)VJ~?Rib>Y-(i7L(FL{`==AosMeQqu8M%S zXrgSWiOG*w##nU*N#s@&yVqG`3CW5AMRzrke}jIvqw#`R9(y#NSZ33)@^Y1zvb7z1 zX`MH^qj7+}SDM@u4}H6Pv(xF^*lSBo%Wh)fyPDX?+%PD%t7&korjz)WvkyZtKl!Hr zgKIV5t1?0DCg9OZywZ(A?efi`{)%J;b z7d3CnVUL<8dH}s3xqQWxYk)_`Bxmn%ZQs4a{pDuVLpLr>h;EN8wevEh_qWrZWW(pt z8#k5V`vk_HMh1%>F+>XL;R$}}#q23-bFOQQUHCgR#shpGYbGv zPwm+sQ<)fG?T@kXG}FcdHl*+n*@Qka$#mZf-h{thP3OfdoJnsg_eKwPc!81XFHvi^ zF_*pJ17oi>fG_NkT}^|)*I@89B&P9Z<7*Gs-Y>p(XW(mt1B=JiHu#DNU(>+X>B847 zQw9iM#7Nemx5##_fv(-X=GGZS*ja15A^5tTOY=^A{m$YknfQ9+&0c(^;90_#@;S0` zc0~rx8k}){o$q6fM>zX9I8z>%v#zWhcdaWMU#IorEAoj9d|l9I-B|cKBNJcbk86zy zUmYH6t@Yw-0Ql;Eecd6LX05MVxb}YWmASq?<-lQv+II2f>s?>p!R9&^Oopn%fQ!l4!*K+wb#WXG)%2wYki%<_p!zzTs;HdwdHgVzIynejjs>&;tQX$_Mf?Y z&?EcK;dB2id}+Md_!_~re*|BDl0Q>13cmZp*GK*Z_$tc4*PvtI>$VJht#`)w7~jXk z*XR4<>rv#^qkZI7Vw@|tp05m#`vG}ipDedR8TcCS;44FJ_2BGL_a40PPs%;h z`se#t;}Oo5gEL2N^@FdE^x~^|at6NsHFE2Zj5QlyFLUkv;ww{bt#;t>9kuP^D?@H| z9zHfr|8M2ii*NLe$mVS7I{Pt?>uK@O!_Q5AI>@V$u_Z!nzhW%yd;VbvpYuR7K)Ghm~ zmG{MOHuBwrw+y~`vhem#=8K2OpKW#QufMT2w9bau_E!&2Tmaq#SK)2%srWmcao)rC zvBo35crLg*vecGiwaJfJcynJa(mWdzXKrw{xfFl=|`C4!IgGbVy z)}L3pzb}8B@Z-jJy1}P#i{1CA@LHSvIQr*#)|#wrJ}W9(5smcPZO68=M+^QAZkrvy zNHN#`5#0V^m%T1u<-0%Jp8h^@yC%yo(rv{V-f3&+JNSJO-$<^5L&tXOS(_^|aQkCt zoIm3Gc(}bBTxebXGw^!3!k#2ZDVTUe|E#AHnOD4!mmBc0X%&!=Yot zu|NOGd&TSb{%WsV;q@+fWPiHNi5Yl3#~Ejk@8jV$1uo>@mCsdvR##3IAdlp8_2pGk zL)wme$j2)mY(4U7lh@mpL;OQN+Dc@R{Io0Z6;|YV8|0r|q3if%<)dAOPuBIzCW-HO zbI3J7W~hy_q08FX6Jy6f@Xb~<6HCNzoavkOI=$#Emfy8J!#}&MPYlG4uX`PT z?Azo-$senDLRfpRh#9P4&bA*y_1h0yHE_hAtQ!I=aX-86O*6jN zpK)C^$JB0SovtU;-f`+dg@{)?;=C*TXVxQokn0hzJ+Axtt$4JD8aUNWHeQ7f;kT9V zjl@+0#CP<*>e^ZVow{9r;=klBJ7%^_0$!T8^1ODBH%G3ZEybXc7g1l1bL~pO;X<$J zTbQk2pR}g}xYPp|@h$S(f{PeqDQ6l`cQCr1m?ZTxx_?HFK$EZF;Rvt@v#)s{ zuxJ7n&yq8tHd4^J+MsS-a1n9G4PNr4Xk#JYR(%%ok`g>~Bk)}hd~XC+KLajqn|{XN zw)vmrH>TKYp}E1ww_NDJH_SWL7JOB6V|4r(Xdz4+`+%$Rh8FHguV2GAd=Wl0EULBd z;s2^ZX2Y?@#QvzNB(T~C|4l-Z*j3%h-*Wcb(G@Y(ld|Y>h+to7!yb7ddc57qAGrtE zi~dFX7JU=*Qp|QG@9w;NdTgU&tMCdBw6D7E;?q9(yn#=9;qw8$%i+~c#MR0iKEJ{Y zXsZ{EuSi|dPMxY0b-s4pHYTbvD1ry-c-N1U(&g zovF#p-%#sIakP!>;TL`<03+pL2)<$HQ1IOc97VsvGqp~jUmLz(5q!bB;M>4Es)=s# zaOP6(%zFse1vmC-z;8V4IkfkSh<{v#90*G$B+8<1f3Np2Tw8QIPg5R&Gzq|-`yxsOW`2Y7f&%Ul_saw#@KG^a6ZsWSGm;9e0?@nY) z$CG!t-0x4`8Lsyy?+$^>cawK}ct-DL%ezjlN5BdATEE+(30vMh04^lw{u%OaEp5G< zy!(!DueJGal6U__fB&b+JHfv{c~`^re}}xAoB@;n8|B?y4t%ra-C(YVk0tMtCq@4q z^6u5|+VubbXL&c-g>RO;dknfdmb|;#nfLMJT^zoLtgz(WRGxQ#Ps#Wl;<1UC=A<9@KqDj!5>5=eh3EAM*G?;3yjysfgm zm1|smqMd`WA2=vakNN?7^3dr$)EYF%)HUd-6B%1GdZBbm@$OaR*R3M2u6Src!`>6~ z$#=}}tVBk4mz(Zxe3_E3CKTCnD)0Gk!(wM|-tE{{@~5>H{nu8rbWzvBGV?+$>udnI zi_Kn7jJ;+J4_x7mUCIA7C;DQKkG1pXq*pyqX4}nf?xmmne2q){Xn(uf-s5*Z`h$iPc21f64t|48{7dvd^g9n9?ZcC9X8AN^-=Q~ZA9wm;>g)^|5^L9fnYt5V zN#DRnlD@o0R+9&mpuJQB?VwjCmlLD#n-`?}`p+;`t-#x}!gM8z|iUTX;n0vmcg@R~-K`&$fSo`_w(JXa4Qf zsMYx!f`7>JUHCd@V)N)sw#qzmbIF~L@SNro0ndJ(spIzr(A>`PtXXo>cA#r7^ZBD4 zwVW%$dfJJv;zRqaJzw!;c}2_k0_+s_3zMUGP0sBzIAa$7#cFI%YQ?nDmudoPZ;kp0 zW23e=+V_ldr5S62F)n8e%9EZ0etw93r+v1D@r9l7X-pbl*m}lTx!@LVGx3Uz?R9Xf z`D%~Ghk%FhEBvefz+0>p-^|!O^tTm!m15UHlT{0`B~$Zio+@J=jQg4~&OA0T25TPJ zOMey}^SohBUUGA<#^zP6s!H&^%Xk}}&cPmJ&I#=6?@+HVMGW8;`YC73P57EF#2>N~ zz7U|zYUZ_(wlt?T)_qUs1I_o`w}y6GvEk&`s2mD@-b!!yHopzO&B62r?Li9gn>r*` zjsM;}wUP1Z`21JG2Nv^8>P~2p8eDXhGQ=J2+YKJ~*fm5~Mgl|ANwD=3pbVExOd#MpH%&gzc`c@1^Ye2dCbAZ21_kHO~ zG?7X7cd&PN=Q+f3So8a#cboooUXXoGjn;wa|3CLqYmfd)7zYJg)+eBG^`&`~S@STR z3-INM2HbgwzqvW-WsFI&&^w^L%)Yi&8qWQ;`%_<9ZwKh_)AVQInw*~G0&q*ev%@A< z0SqF*Z$G%*TNmoyKp(O{HfgQEuYUt?mcLAOcJ{GPr$Nmy}ffu`V$piR@GxJ+jQ$V);k)^L%d6PkG$5;2HH>?ED>2>UX$Nu)c znqH4zCfdxW5}#$5x_)8K3K73d&W@a$z_!Q}uk-BJ9Ql;XnzwWm;9Z&&3<~2P z&^Pb4k*AXaPJ+)L-?HKJ46x}~2b|$eI+JD%{ncdTm%6o=-0#0?e4MrG=Jamsk%Ra5 z)Keg5`YyGnylD9?mva7!l`FU%o{HQH-xq3G>Ki@0^b%?ivHnV{kQvZu>G}L;kAEpO zmXMLN5@Sr2@{v>9v(CDhXXDGp(H|`wNsivYo;JxA=_=Q=w@v#Nt^+=juODNag2k;J z#P-+1gC7&EQs3muIy)vZYqe^|F|MhMAu^XeM^8AseI_-K$;b7OTR!5iH^)lgF|GJx zZd^w0JnwmlXG*5dM&9i&&$aqjKOLME)&A9@*x}6sg0F4wjd}Uc*ZL`p@6a{Yv%wc1 zMmL#V8tOR@#DkpHo`*nBt$i=@ki7~ul81%y81G6hKFGIZV#&ag20!mB_SNpoiyngK zwU)7thm|yhB6m&E9)JYC%Y5XlHRln?tCKE?dC9A1UeR`Vo0m1GdHI=>{O{7Ev<{lV z_q)MX_J_uGMiy+F8SjWJ*fvk>g>7gWJoFnk#{}Q@lZI(577y1rlJM-sz<4_Ex1*c* zfO9@D7OXSjyaPCQ3@M6r1Lr$4;M_dbhVva+aL#`ZaGv)?8_pLyaQ-ykDb|}{odi|^ z>ZX_+)1a8Wf0$`#1-6xpU4F{Fj9dILObs!?SbG=z4ve*bA;H`pd=D^P;lT9w)Dy_0 zSMynFBrGs3OHZR#w?m_eDZMm0YWK~t5e|*s0Q@S5xwDq;PBn0LSvz}~+t7`nQ{(Dm zXWMWJF-LE^k|L&UU zuIySn&^vf48E9VUSWpye2UlZwC*q7D1Wjm7lya?}F(~h*o-u?OgS+qHSa~<6ecDuw zwDN9PbAL`Z1_x3fg0+$4cNkoUPRhHemUi~CCPoa?y}YRKWmp%&-(>m`PK7_=O?VB1 z(-Lsm1uj#2kTLKPYI8+bbH2@F2X~7tUQ=S7jkm<&H6!9T!fV8P3N74?j4uFp;kD>B z@EXZv{{_e|cueU$YP6lFIm^F2B0k7@evY2cz09gv5}uT~HcsffHWr%hY}_8sz^x0{ z$OId%&jE`}xF+8NTz7vGzUaX9o4kLJdKnR52`z1*4nntTA{EPqS>7`>KAY9nVe$zEu^HLeug#xah{VN_)*7>XmFc0U07V?nbBoF19Un##w#vcWRF$ zYsqbK)~jrs5V%FJw{V`UHQg1A<&R^`#3VXM;@qw$#d9*(Offu1YX&>f!b=jHM6|jH zm?RzkorHgTptWvntR>h~#jF?NYi*Nya>PcEBUapbT99~~V2X_=emRLY_H4&J5p71C zbsT}VQ{Y--NzLHfsvGNBEqz&X;IuQ@_v+xdK=T34!}(634;;Llc2~0&{kDCX#C|E3 z9kLo5^|lLQf^oa_HsGssOnYElXT#VBj8nk(1m4>{jpxA6MCPOO1w-)kj-{+^_;&l| zilAs&b@!6+2*E|PEFLjRb8&b?z^cjbo@F&U{t49{DGOP97+twt|FU9K+K*Hep8(wi z=tu3P;Fq^!GfCz@j?N^y6CFw4SVOIGtwX<_<(kI%L5Jp+^3Ij4cel+_t_Phq7dh>H zn)Xr`Yks5Rm$C;+d*)?lq=1VTx|8j^1O8Gm%+sK`3#Qm(-R;1pRQnX6-S#H-raj1> zI^a+W4_e225#n;P!}W~XsOEh?XUPiwCS<9cuRVoEMF;^n@^6~gAKz$cR&k{?TrDu`+B&C4QFn&5vPaHw1v+rE?Skstpx zIzyq+A$^Z zZ*yIA`LV2i&zW~cEJ&Z zar`U?|Mzj-lHZ%X(T5MD8_&1!Xv^Kx?>pK!#ahoJ;}LA69@*Sx^91pNGM*7%T&(-Z zFY*`G8+b5y*dm!Xx{u7Oom@+;gN{3MW8dW*%@fF_j%@ZfC@(9&cg1O5=f_Z98n&fO7qaZ}5!9_ZQx)&e(hT zCFWtJ5<}?C-GnWMD1Jsg-WAmX1()K z=YK-uX+9-7j{ojFF1O|}GJYxFKcOA*OXW2!XJ4uOxwV<+^58GXK99%EM|02Qv1>8q z#Xr;7dp3`9)2#D(;O7zc8S6|Q6B--UUR3pWkCz+|a>sOLr{N49KQ%3qUhEw|vI4rP zgKxG{uVW$h>3*JjT<7roVMfn6Jk)IMIfv(bWbOEQXZ3pyPb+yXKhB%|o!R5Da`Hw~yX2kqjoiF1coyv!E8oQO zujErR;OF2;^9P6H6o*kRKqd?ZQA^7{kF)RDJrfv9it#z5Hj+!in*Zjh2;2 zk3mPb^bF0bI3B{MqduSJ9c#|yTQyBHLDf|%V4bNw%~$l4d8W??1q)=`SNT4&)IQHg z>$4G9bm1#a;nPr@U^X^Y8FbZ-KFA!cvziX*yzO$uMNE7nW2{5RJstcj-V(83mLLDq zJ**enm)@d$2<5iy=Gk=?4hxY*x>pdd#m^+al=#>b?(eVlSoI6mRia<$w&%=X^d}fM*z=lIquaf!Y5+gDIy!8@7c#`5wQ`=(mmEf^#A7 z=($Ds_zu&Sy^ee973rSV>O^DORJ+qUC!+M8PStez6?XcDqcc`k;pZ+KUD$8}>!P*@ z-?rD+N$j?&7TrU?L#*H0v+Unt;$55-AC(VMIH^UZ)+whG-u@ym2?GP=>$LK{mbpZZ zu$~xa4;)4b26mkXJ+J5Ve0VrD8+bl^I6YB$K=1l|S*ZICtyj)G;{3sPfBwu+_su-- zKcx2ie?Cd9&K&;a%2Mh{YW}6vlk}sbmXZ$)j=*PeT=}LiGUqTKqvzG$LgwcM)|u_7eO*_Li&Y2uws#5bCHJQ%=)Ppds{MWMpRfD- z?ECUjHj}HUIxT)8Te(JsJ%pcLl+t7;V zaK*~+Qjf(m+^nApf9O6~_t+ro43QD>w^y;Icz*;nDaq-JhRG#vqMlOo{3(mWtl8#I zm?$}CFBod9P|u{TbTKfzVxi9wlQZZFTK7KA3#ldEBDzh?Z=cdUf9;gY5cOj4 z@7Duc-<$tMew(kemR#mdUSC5qA3yZ?^!(bz_{yXA&o5uxgntm8Ts18xw4{RkHD8Wl zEa>&XdRiXWO1PG1UkmBlP_Fs8Hq^d`4N*017}rkY+A#Z?(X|4ueT-`b_BG+Cq9nA$ zQ(~4ZB=4EpDGg2Dk)27_!E|3i+loB%Let00p2*>ft(xC!$QI2{^VA$8%rBfZKd&`E zZ)YX*YxH^>s`+Ssq8;y;(Bd*)LB8(Na2-!kT>YnosCV6Khi8uQaN&9D7L zu9b0(`RSVGNA0F1$#Gm`e!8alwHI;iOs+9MUDN!?^IYO*e#`~=m(#%6Nb99T{s_J+ zpL5~GCPsZ>cz9pgb!4fXpB>>G?%B*2-=|e4?ndbFbNpV&w_+~sv{k`=no8OaQFp$U zZ{>wIkyjpm)6Oebd_Z|z8~GOQmD4=}_|)(}guY|Q>3)*&==^KxDx&RskuN^#-8~I2 zmb?)S*Gq4~mX~iqG+#%2R{n7DMCH*ZI3rHysMUoye*hnR-E?yedV5vf6wW)q7yn`M z`UnR5e(IalKcQysa_!h^%W`@dx$pwsyC@K2&2qbJX*c_!5T zLFOBQe@;ivswUpb#aDt?Z^O^gbG@8R=9^-!#UIm>^p%Y>oUyggTQb}jYKxt2CO)2H zCPwb4(4Mg+)WR7Txx*8zHJ)+HH<=|9X}?vn=W=@w6ZbnsYtS+DlX0Gmv$iZRZzO7YWx+j{tUGS2LU_vK~2F~R{+0XJNFBn`yT6l zVSInNH+mWOs|SB3wi`MUJO#tqM}Rp#ozPh7m!T8wWz3=-wOPsBH1-wrEx%7YbDjz> zH}Ek0{}ZJ{xpKXk+Fu9YX%9R7Yi#YvSmAZDgI6;Qywd-{b=19~|J|%njp0nj(0&ea z8b2{&^j3}4zF%nF|2g;NgIZgOKaKnHwYD=J10PH^LmI+to#$W6Y~+&`BM8S2XQ`e`-7)!@KmSF)mn*J%$W25uU~V)i@4X z{ZbzdKhTr3^QDZruXEp__?q`gJoPQD~-j>YsPqOS;)_XNM9qv0{ah`wLol~yqq5I|m&_DG3VfxY- zN}!!G+Dk#RU0lE39dpK-c;gQ?O)ur1ZQsieQ4oLTg>>UXT-yZiB-daM{Ge(o@D^JPDmlxhM7V zR{)1_cX~p0o11AIb1eWS){&A%-BzP2(5JqBGEh_}0V$#d{>1$fc8 z=d3r^XkV)OSqEN39~~Keg^^vz#UT79T25bHc#it{AI%4NZPI$9{nuqH@L%gs_cv%9 z%uDMiTem*AQhX>sUICt}wJ!@81(N>ge=s)vkLZ8%nCR!6|HiVz%cGa_Uu#Tj$!@c_ zvz~kr)!FZ9C+v^T?DJkAIwSMH855nx|5u%N0?E?oRQ_kmw|m&PD*1N*`;c#}*(&M$ zl5Y|Cf+gQLdsOnxlyFWXwPiSC^V$IPj;}YHR(3D0|(KEWKSYPwxI`!&a5#& z*FkirsAx?xP%^B@kx`$uU{e$?U`&qyAI>1|BjYY{V7Cvs@BsI18CDP%yu_QeuUaxJ zQcm6paz!*MxqS3)w~lOnPaWBIY=2uWvqz70@tfcGm2F{U$}&f`t%4?Hb6`7EO@+P% z%MF?%eRMJRT|MoW^t7L(%~q#QZ8L58S!W5!4fNRrazi{RQ+|(d=Jr*WF6i5pk(!?? zBiTb^%g7P7j1(;F`vsPa+|Pa4?b3U57^}uE9;ESy&`VF^+O`_T;K;cMx^;hY?#JID zPtcKb8gHhY)7h#=n6vySnRD1J-b~-0aOM!wSjgcu-)v) zI?=CWT>|?39DTWT_69j9qBG6wJ6!Kirv1ViOG$hbW7!AIuVQV4k!fb2|19xt^&{Rr zjrY|~K6Fwuz?M_e&z5KOx5er2ySj$XYuBqQil6el?elZT^{n%p_AF>Uh-W@GGTrzg z{_D5;{2cL}vDW?k_*FbF85Dp=yL`i-BTEKVphs)1COH4gZ;v(T%GM%{!&!3=(}u>Y zIb6ndS6;Wmvs}5b%z?!#(74*fmoUM7e>LyRR?e1B&tiK5_jkyrX5?kIeA?&8r#B@R z6oW&rxYFtKr}XK{qSN4yYV-ZbqCYsYNO8?OkQq8j1WbB;`Ul;?W>BU^r$`9BrYds(r<6btUzk31VyV zGw946|KamiUdnY-Xzx+(?zqv~qx>8)NwD8_mtA95`NEs<_sX|WKpp)M`fOtU#IA5o z1u;QiXEV=R{|8(8vT8BJYrUqsuF?cU34GVA|7q~)F+;Jc;Q^sxm0m_aVLlqmvf;$*@N3C;5<>pg^FKV2XGhv?X)j_mb>HiY?0t~%tE!ix@IJ1y z&$Cl|76bUMtALrVy~vqnb9|$$`mUAuUUxvV9q_G?nbTDbjKI0&$JJV_05{N6cXb|d ze#H)f%X!SZ@}{Y=TlkH?H@KbpztzAg3@j4Nxq|b&ugdYp*f$>y1Dhr@suMXJ#ommj z7{`sATfE9Uvf&2HCr})ZGgisdqS?py31rTv86R^tJl7zf*moU^@x1!a7Dz)Pym_DN{HY$nH9d8q-$vJN_vU%G>whOg3Y1UY@^ z51)#CgLSdD!)w*Vtmc{29MgS}_P4X&bso96+u840&6=pR_RMzk)4|5B}Z8cY-rM>F}-% zoTqE}%w5>DI%D_a-xiNeGM?1crn`gu_XPK3U)O8`*69JUB>%NO)9bJ?7*qRKvAZS1 z;Ipdln7n~^c}8)pWo4{g-s_mgJ!+(S;Cmg!X=TqRS>I)>LG;D$8lLX}uGmYR33vr^ zr@Q@XbUoH$doACrIX%;!9ug~KEvCWOLfS>Yq<_U?@;jTcv#kF&@H}gg8Wr?~zRg+? z-AfNu%;6yID8ELydj=c`4$3)J&1YR}<(hTQMjieD;OoXGJhY#!8~2`PXJuKzLj2I$ZyqUm0a?I{~^FU#oBjaE5Dv(=q>bjz`D*nSSOk99OYi$cU0?$_%hcI zI`7C|n7r-$Sn{?LRXc~@=ka@Jj6z7o?RQ>8PN6TRocZ=UFXXo;_Cx(a_5a1S$9Sg}*(#k#^Ren|@XTW6Y5`Lhp4aOAEO>rd*Ldei zz9oaTR(fa=fAy7I@1p$_{R+pnoQ4jRuL3OpL+^1PUj3+RLq4ssWIZ2tbb-&Pzl=U2 z><__yhC2mEFGLq(^qtr&J}MdR3tNqnKN5jW4a z6+@1#*!rPfU+AJT6D_dxmxB2GS8TlvdGwxa#T&_a>ai7P%OBd;Ry3z_rr7(m6_do2 z{f-_gebcfPfoB#X35x>P<;^`wg&uFLvTip3Afoe=9!4Iw@d0 z<-kUJLNe`;XRP}L@qO^bQQXhA6HCa!Ou~DToM9&$PJB#u;-Wi`VJBMa6}~^s6P)%k z_7(3U11ukCkDW*xuAOLD9~)>(`u-D|BYntD{9;f08FnIV9?wpEAZu=SI&<5}IFgLP z@7jsA9>)%}eW}|IqIbim+e@$$S$l#-rk%I|7`S%gjf~5(6Pbf+C*H!fe(gls^uUMJ zrflw0@6ECkx$g2(`9l}dPPUzRg)@is&K&x)6QBE2|8`>FR`CGjX@Ii8(3op#03j%O!+&FL@OPF(ftzINhO&T~C>BJ?%2INdmoKAuJxyn zu64(VKDv=H{yX&1|8&OJqXQtf=js}``+r>@Epyq{`ApS?jKJdZQ;Jlmt1|+Fa9>Cum0-tw@1_;>(Qlm>7x&Et$%&APki3e zN8f9FK7kGjzwS3SFMafrU!fKGCFQSH96&LEU%zO}Na>rIv3Y+# zvH3qZ?`OvLf5!XLH-5^!OntP>f}0(izX8}u@74W6za6_D>A-bAzWlFp-_}=&%>zs6 zSYO%?yl0XFUwZ7={P*ZPGd8b1@?}o^!lkhU{-KkgG1+>V{U3tnh1W}5yk^Gd8G{>p zxPWn3@p<%S`2#dwjZt|78s|3d|EuEjsc*cu`26yf$B)ndj&{D}%wM?)KV|M=X!~Sm z?#ayfyaWHSqF>@}+41=``R_kIKi;7c`9iWdZ7v3eZi3n8m8vl(Rsm;Z|vkbo}A7T$T8UE%ZW=i4&>SnYUR!G4CrJHR=wsM z68|vg6{?*k{H6~a{$#@gW$n~>LrV^7 zPs`y@!&v3!L93NHiO(D6a^?K+1m~)-USr7xh8lUg*9NO|Nz>chv-ToTSEJyx$4S6H9Gne;Qk=w5rmHO~u z_o&Zyp1X?Y%E=SdGm698G0lSbx5?f0VH1%n)TsG>nKd_wyvEr zZmk^2yfif-3^w!u_9(OuBu+g%@q6u+sWfJ$;Gk#L1H;Oj>Q>&wc(zxXJ-$SoXK;H zXTe(DQ9B)s-IHU29`LH`#GtEcj0pk*_Nf+Gx#8i$F6KZR z3C5P9CQvOjsrn!R+UO$Y(Ov6{jwIG~7N56ky-|E;TN+O>!`FCC8)s0rsDJ$Td%jG& zWzeY)d7d+`2Kp*qP!lj!)VXL2(`En~)N`B(49yjGHbaZXgsdDj^y>xB5l4{^0eZ5| z5Z8(M6S0X1YwhsMpNic| z3}8EB-*neK_q7v)izt@F9+Vxcb7Q}RU+!3aUd(vNr7?wVsimRE6w`rERi&0!TfY}* z{TXx3H^Aks?2p*!&Fx%!_pMf2_0%uXeipU0KBKK>Z*EUpzvg|nt(ou>wRM7GCCpJV z!&34=Q`GUTCLbb<4w53L^`=dsB^NRu54o?)*c078l|A_2KQOOmag)z8Uw)tz@3$Ir zmM4k)KG{t0ge!x{gaskwa`@H?&g{*N-9&pDUy!zBC;6d+6nS)?`?~gnz|Z(t_7i!J zmlv4HK48wBYN^TksNJt!K?W;qX;GA7Q_C z=Ciw*Pd&Ufg522d^(;UxQ%k*SgfNztbnRciXhDHR3f5b8olLr}bxCo5Qtl zF`ucxH1SfpO1Y97$+1r$7n96&C+~X2gW-Yjr{F|*r1-G-qMO61_I1uS@;kZ_7_MQA z;auf?7k2u$QvaQtherBv$IU*l1z%^Lnd7EbhBfZbGVTRDtJ?CeT#$^Y{!O}S3D?z+ z+FQ6zQld$T}PI#)1Ks6in&R* zT9r}zM{*p!oINhAg}>N)+$7UwBZr@{_XNoH)R_gU8?k~t0qMHD*b4voThn!esC_q> z&k#O#9lZ2r&ysY5FPL0@Vr)l;FQ{4x>AI6+kKm`4jprf9GFjX-veX3TSChBc(J(Ej z{&#GySR%ToX5hFK?^l?daVgqLq2q(si`TN3D>+c{*5R~E?zHH-iCWRXcIP_iem4Kh zBj+Am$A0X~`F(2S+z#G({nVMUm5?QSZH?b^uw&31j89n@tBQ7gKg7uV|BzvH`OS};tV==SBg!Pquz z6W*6>K7g$&+R}NhVfM;*m6I1TH18sv>-skNc^&YWb;w2g`66r~d+%iOr|?m(A7xGK zefiRu>S-m#L*dz(@!|vA&#oVgU0wAi*R|ix%C-7YsQWrA|D`bgy4t(E%4$zM*?M=G ziMq9%BjhNioOh+q>|fXW?jN|GY_!Mqihh$HpfSE=wK>yj)3BDrKeEU9Yo5s-ryp7K z4A*x|sLP#X*f-) z@_wc~IkNOmmK@PoWVh_6y}z}PDsb=LnB_1*RZQ|-I3{^RQroD_e&5&kQj zYRzKbY)~G{3-S#>&%d+2^Wzr0xZln5*?5=TS;2lGtpmkW4D|3CZK^$sheH2Hmagg1 z!56WINcTL6(2-PaPH-7{#VKm$1gNF1^*oKW+;PxoU(XiSb&J+>y4Dj+U(LtoU6LM> z6AVyWhq~(2tjy&zkk6n;ye0m#_Ae)YrxqOveA;qEG)*4CA?y|W1=Y|;vbG`!ekPFgVXSi$l)99G2Vc@g7^di=9?jyUFvWB1JU37-zRA&wU)HrLnm^EAy z+r=8)xz$<24?Ao4HrDPRSi22;Z|A#qy1j;d1A|YoZrwFJz+J=e4QmafU)XE-)+vLv zhT%W`uHiPD22ZeP`SRngj~t%KULRV=M{nz`1HOM_FO7F`eedO$9dmtX9sk{V*IFNs z_rCiY*HsHd>tmOG!^`x$!)o)>#~tVIc_w?DTE{PPU2DPOH}F(Y{kZ}(lt+xxC#+Uv898C#!q3{3m1W8kE9EZYAZ zxgDbOByv|dyXd>KQmh?=?vZ5u$d~2j5_2X}mELjp*F})G`Y(UyOTVKw1bNWO$IX({ zc}F?5S_|JhDcyJu|G&($q9Lv0nRfd1uAP3hom_eE?Pm{cJ9c{WJM8qL_=}F6em60r zjo9fQ!LEEM%T7;tZ9Dx#AC#S5)ENkvs#hF+a$}F3j!ytythuhqu+!Ve*mC4pcKQa( zPA|0W^v|o-Q_(T)bi>$s?R3Tg-|AlHMHYLblhCg`d}O1muE#yt>Bxq*eVqL+I8N=? zPRHJ1k5>P7dXZJjQ#68YumEQW`sXyO7S$T)=p*QL#B!|sy%6gLJC40Tq2NZZZ^7EK z${SB(Y-P|{?WVpqRvmsRbPe0angUOyUCYLr(raVsS{PVpAGKv$W!$TvUD1G5+W~$m z9nZC`s)@N|uAyGr>NnO}l0V_Q*uhJ&i*LkEJ`Dd`ajR`RDesxuVTfDjdPzu&d?p4l@b2yJhB|Nqa84twvl z*ZQsBTI;ud>-Sn~)3yRUV>j117zllMWZ1}(dTH=^7}fJq&Y_JYo4duv{mv$5T0 zZ^d}t)ed?%_@2@)Gj;uv{bj-VwckpGZetsFIv2X774!gm*hs=FwE>o{S2{rR0jX1t zjp~T}HWBs0b-2z#{-a8_d{yejCf(AGwy-Y@-ST1NH*~_l34G@WeXQp1wOgt|SDe4p z2me!_zszgziqB`(2icB9eUNF?2RA@2i0OmrQXh=mYt{!<+FM9F3mqzl?d(wc;M;Nf zV0xTBxS&^kFg^T1uliv6>B!qX>$gIGyNEgreUQ4}ZnU#6eUSbI?g=;e5B0&!-}J11 z8|kcv@P3DT>VRygSsy%#^!LHX+d-4P>2)@Y7stdRuc_fxxRQ5&#Idmrc#V1+Wv7cf zM3lE1@*mG`C4c__XHZG~EyIF29>DqGN`E7Nrw(V<-?$IrI`AK<#~p(#xVPV8>T+E; zkE#nYWCSu5&oQSw7_kj}DiGMeBoO$gB}*a4ChBho;ot7uTL>F^67;vcCbmQAZ~b)r z&DyjX@vg-GXb0B6{%c_)8x!hsLH64VxeapIiTfe@K@Mww5YPF6r5E-j2dQsFRs@#X zIxW!ON^I=4lTTtkbfPTe@yI61emE-%x-0q2yOTc?I+Za#bn+v- z?-AV%yY1awHmlO#eh8Vbzoon5SfP^n@>3T7_BeF4p({iD?&XQpq7c7*c{1bX&~qI) zlNM|Fd7SOl4m%5F`jZ(c&}9dNes@T;o`P)KF?3MqMCxFiRd!A2wx8pyC;c2eo|8*{ zv>s_?{jrw;vD0P!MfX9R^JkouDRBNEc=^j3&L7PDxZuIeowi4??wsaXUN^!9%=$*5 zJZ(JbgpG3@DTmT;cn-Wcvgf`fRghI;awzu&jfv@!=ame#1-vtITHROS{>+=3`;^Nx z$W;#Hp-d;`$G2m0*=>aLx`MNj_qr@u!uv;5`dZwddGnS&;kUppw*q;h@GhduV~$?j!E-_4&vfA44$PHc8~jp)olD&fxW9%u#OEW3{opy( zj62{OqkJ)A!|B*x_UHuVCmvwPTA<+@urHcAkL)kxr%pc~Y1G}Ir@cygH}te-y&P?G ze5Y}5lNcLpiozQi{x4d!LrVys8q8uUCZ5L^=3lZ5jsq3=O= z${V3AIGYbWZ=#{+@w-(@&)a}CF{6>b-qrNd3Q4GGtl`y zI7V9ybUx^&Cw-Xfu+5y><44piN_dnJ3ya#nXuNiY4`d^1l z*YEZuFYdq?8v5N=aW8E&`MQ1wzNqxO&o6o4w-~4VKJ>d66pelz>r~`vb^ieF&%93i z3f4!gn~C<7HpqNmLY@QqygG}yPru*y{L@SB~9Hj zxMzPgU}PdM$Aq-*()Fdan7_?47+tM zqlk0*~qXH_;tYF^PClMNdH(%HvrEMG1k1Ffb|7*F_r6Oz74tte2UZ?Y{0t!&z*a? zr(+Cx;?&*Pi%5ByZR*@(Z|#uv+qT&Eur#^w@AGWFbut|Kgve+wtSpnyj$1XFc%4L<7M==FCs7a4D`0q;r5B}1x!|c zOvbp;mwDj}gF<-){07aanC^!4z&M+53F@Y7a09L}-EFk=Y2J;PQ`XP;cCJI)O}g7m zu^fvaF zp|_Dn&3YT*m4cRHdK+lF54~*xXy6F)KMI}L(vN46e!MP>p%rtNc8>}8U5k0oInsi;ZbLpR zVlp_+^sRv(VE?m4`tY{n8@PfXlt&FWs@{>ay3SUntpYgS@7O zKSSI>$CvSMy-M0L^rmcGR*U(!9*xs`=-V>p#-sYYpnoeLbEET5G2d3A&eJ|IX|Y+? zY2R}{bf1)`CZxu69?o|~AF1Kjun)|v@4zlSFVYN~B=nt?=ts^)$^m(h5hw?=?}c8Y z>p`V`=s{J69wg@p@_)gk2SNXldJuG)s2qGBh4jKAT zA#4SPK192&p$}a%pl5$2o_~wHiTaTDKh&J8m)F$rBKDI$CylEb?^w)%(ud;XJE1Ea zHtR!M%X*LRJP#c_!>0U3*Wzr}j;P;glqtS5<~K?@r~F3OOpEs$?T3umh9Bb_2h7p^ zMl;3wH+8%73!tNR$W9rQ->~L$%{BZ+SdV2)=;ibw+HF~u`p`D`O5V1@H-LI*2V#7u zSsxO>Ev66Yexpt+zUyHNE`k2DfjW>&*NI?O?rq2KbGp4@1U(e(Vt4UqhY5;rv^x zLQghhAK5C=O(Y zkHzbNzwJ%JMBYCD@AJT!_df#Nws*qbgz@PBEQ9y*o_#6bp)B9$>G~PEx4+@XgluDVcZzUc{|n@rt_N#8t|l^`5}2mFYimyKYaf_-g8dVznFoTQGxmN z2c(@u8N#AWo`H4BtbbCrh9B`T-y42J#-DL67`mt7NBmpHflh;LlITagk~q*e|34B3 zdH{B8L#Fn>+_&!81Ud23bkCg_!^_2i`td$7E{pMFbx3~!vMOj-#w<4IKDH{t`;<6P zhhA3t{|?3cbGISg&|f$5Ue{ksB+Sdlf!>5XiFj(z0Sb^F#S=QPf#)*9{FFG*`N$KE zAH$kql%0iiLl2&g`@d%#=mpHBGG?{ItBLhGl>0b23pD*W*ABo8v$$!ACep z6ZK^C{H3l;d7W{foU?z8p8P0dKq1S~H)xLkeDE@Q@;%_~py*3T&U99 ziHnTy2E4eqP~i5zur~6&jPFLD#>IuApMHS%oDZ)fCi8N7{aoZT^m+^9LQ%%>b8`LW zGyR-veiGB`uSXfB*IyeR*-yoVzJt7pdOhO?C>uU1uc_fY_M^^2jB6q|nZyBBvHl{O9oXFqU#g}fBDvI)SMaj>O0-`6TWGonq1 zg_L0?;7p{~&!atfNB+dL4(#h2jQCKdale-t-m^NqA%JJWdyYlXS(TUjRDK5gGRyrJ z?v=dqU9(Map9T2S7HHT7r7iG&Wea3nle3?gSB-I!=f9zCay*9Nd)0_*<+m^xmy56!sJMufxDrCeq{zrw5c%g!ODc z^GW~l3dBVP@I6?52gCuH{Rzkt{3agt*}*^4dEg$(sGgJ0MF$4iDukq>UiI)_eaZEv9NUfC`ogKb;Ace`@fDd zjBn%F)QqL!Hy7Au+C~~dyPuITMumNV!FJ~&E=TYi%cn)_*$%8hJ4E*fhiuXBQD|cr zw~-!xrw!lXO@=;*n5|uq|0AZDt-ii*oRT5dr^%SD^zf4?e;#(B0KW6hwlhxa+ZOSV zq(u$qiOINRb%yg<@-+B9Zvu|YdkXz|<~j5&^k5n51)F;wzuSm!i*|x{@%yA!4QFfO zOik+CdH619C*&r^)57L)+75c|7`j}3&zf=w_Q!QkD20D*l;~!^8Q%+E{waO;3mvaX zz{`)m3#5b3qEFzb3+~1lz`F-R*Th(}&QiogYxw3Y`>LY^-||F1BWCe|N6^RTJ0VA) zkLCU<^ljI3@U;#a9QqpiC>kq=b645#UqYI*zv_2qfArrK^m`R_^|5-t-;DC4%~gbr zSUL9RS=cWkd%n12xw-#wR-|#R#6x;J-#v!8iN0r<2hsnO9}!#iKnHZ{iD*whi~-w_ zmt@7asiE(oPaYj+-Ag-uTBisWVmz$Cy~`!KyD%PIu)lSpt@-#iY-c6kiSAo~SHL(E zUY-e;9$w8f^s4}^VLxSeS_X74e4n@s-zVnxywgOQ{GRtipAxt`Y5%==G$?^v9v6c4{`kp_zk~Nk%W29Z}t8L*Z+yDimhWDSz0*f zCCE$@@Qqc#V!x99N+It(j(o=RZ~ok~|4>4?Y?Kod?cF>(H3n~NcpB1o0Umt$BN+pE z5PWo%%wrAy3+`9qzC(^-TDaO~^|==m z9kt49YPfPoeAzvE*%q`Xv-G-PGoHEs!YKcwUhX!OySU?raqAb)^fcD43DmP!fHuH~ z`K`NIHt`VU3yurF8S3BN5B!HVJZ@}8|4Oo0*y88@ZwIKeqV`zco zAsXnS1NnF!a2sIA^>Ib~`gjoaMD1l``OUn4mun+&8iw_pZQ2DJ&sNNtC=cE&T7N|z zOg^d42>}`Pyo=vN8X3M1eQ4&vZCAhxvQS>};E~~*Q2v97iU&(R3g0jHUVaO*!7njZ z#BJ%@3bz*6A^E&mf2Mrgf;_v1#J+Q^zIU6XzITg0dU$*M_l`MtcMZYZiS!Td!a3{4 z_l^m-xhH;HoQO#wY<@p^;VYjF?J>cUFp#bh&TbLP4D=6j>>iM`%)T*VSJT3kkfDxX zOj~7pXa}?e{|oEuemrm7Y0xv`56~CH;~CUro&&ET&&3^2Mdd@-g7%SycY#JFZSGgJ zxd!;lwQDuxCg>JY?%p3ScRO)*zLFtdS8@^7;s|J)@-Fq#t)OMOR)c=KJ8eOJ%WoX` z+eZ^^QWq@68omT^&~p6-e~KIfFQzPk^OdIoPuhfcVNSPUPq#ta*1%^kbRf3LDjXL` z=RB`rB>FBFbBXQ6I7ahp_&$itkM$s$A8Y0)JwIc_?cfcMf+lm}Pl$XZS_SxjWRJjk z?rJ{SWlT5xE}KO6e?JeN3*OIn5p?`1dp5+0Wb~9${Qi3gk`7 zC6A#T&u%)OJaTV4cs9S!EHDS*pL%Tqu8a*4!|)FFL&_|9_*OGwWze3{;S0d6^JUSx z0ndy{L3~?x2kq_f@%#vIg&uoO{=sGvfn-#GN`8bR~zQd5q;hq(dUgF4)F~G^Dgp`?%KC6xG({{d4k6h(xC6``m%t&F)I8BV3lFMmaYpd z&9hsAUQh!) z8g;jTccq}cT(=Dwgx^0QZ?=^-hu9}v$NPb=?nIvekG+$?bJ?bcAVahM-57_?-JiK| z0&4)rSNYM}6myir{{E z`Pl;bS)8WMz`Al#mTk#_5f^^Ib8I9Y znA`AqOFW2QA}$fw4LWqbO?xtRv_;Uj+9ue$Z;MMG7oLN34f5&Xxb(E}bfoV``WKOI z$W9X@pAB__Ugv`5xTcVw80$&^w2&x|aa}1zd4)rI*a5kS_BX@sFkJGIap6knQ;>N^ z_QP`~&ScPZo#FF%J_{az^^f~-zrO)>ZXAiVdjij^Nk5$e8JF*d0w3-t<=%0`97rGb zK%|x42YCT@)!T4pRq0*$*28Wae08bvy%q1NGp)w;{;i+ve+gICby!dTGSUe90{9U5 znFBQTZ+f1`apn1PZTHzPyodKZtDj|QPvez)p41w2ZMaQZ3nt!b3!RK)0 znTtkx6P|y9XLBDEpbuzQG^gbt&AgvtJ?M({QI6#LM4O|OCn2X$*WntMaVx%KOWXGy z;2pHhl|r_pZEhTBmwF=j2FrKA7CjN`T^{sR*c6UuPEvAa%qOp6-iq!VNiV-IzY`<8qTF{v8rH)N)tp&$FgyH3aZMIG;h zm%|&fH}PKl7vNouco*|nzJhxD!l_8d=>Txzw{Xfp-?a147DAn^0I@wsfoI1K(RwX- z=7DD|ce6h_aMn*J*0_#*>*8U+G1}kY!^C?~0^S0=^V9k}3wAD}zkf-44eI|7T+Mxc z0b@YBqSQa6jW8W@EWVMH2i*kuNhfJ~o9;rJoM?~K8_vTsN4d^mEWGo5$ zXJ~_Y9XSu$Guwl>c4tyg!g_Wd_8`PEoUX#WVLyKrWu53dE7mcNNrXBDY*bws6OL0V z#)RW$$GQ=<$6>5GD^o%rVr)VvU#icA0DL%X>tlqe&jlyu!j+6o73OoQJ{PJ`o_$?G z*wP*f83XfyW5Y8rC{r;8ihSs4$ffOA6DB33Kc%OyPDpd5kH-{$I#Hf#l_CP6GeH z0@#9Xu(!4(U04uUhO6zuf(Mt`yI+@a5vk$tq=<)zlLflN+kg|8qt@zi68E&QaZVQ2 z@AV^*#(OU9x&od`6Zofpj zOuIp}5;yxtJqsBNM0_V=ES*Qce7xgz_#(s;?{_W~tuLVeU}~8b8mFl} zF&a1~Wx(g7^{R98$yYaF{HTL=p*(GzXQ8WdToD&I^&G}M!109bgyWeE8TRX-mn6uj zq@M%u(d9xOP;vQ`5!0uBo^XA{;K6Fx^slcqi3#(DJrgfizQT7sm{rGQUa zMxG4-{?cKy1ivN3LmwQ%xA?G6o8Otsj3~Y1IKCqQT53H5J!>+?l=ONE^gzD)GQTk( z@9`a6yo;=eeW#1`@F41;P3H~J9%I{>_BEzKK72-|shG?!AuTpP@XdF9emsYCHLugc z`y_3phJTK<4%FjBdA@T%HZKKS+C8=rc0zq#rkUz%fqY+!w9}vwmS7L(Dor$oM^nm{5*kvpc zfBqt6W_+jJf@_Nv=cni4>|(%q5NmVKU2_+a29B8KNv??xotL)xpU8eI{iNsn126|^ zGiF~bQPW$8E*f?FZ~Lc-M(O6a21Z+k{{V`uInBdrzQ! zoI4kHsJMe9(88nmO$6PLFWo1sd(WV6n@P{GQ(8bnZ{z+T`r&uz$H(p5U)NurNBg*Z z*Z=gF(AJxP8{v{>OVLNAz|k(hu?jy1-t$>QJ%9s zuyw9a87+-}|=JcKVG6_I&e= zKkj^;d~H6)jc12nka(r;HR{PU)zgx02cO^>5v0gI<$-Nk8j` z`s3}GH~H_x{AT5#m9A|T`e%)h6LBBL~MbZLkgY=*cE|`)GIat8H zISD)|6Z{D}`z@0}HyqOwJ$u$wqEE|^#_`Rt^xINCN3`bcE8Jc&9(F^lxy^Y=7nq<_SD3b!YM14;Cn78pO*p{Kej=a#a@N|2gW!W;rAC}Y6SNO z1at|UaT@t4_FUrHa)X#}5xb}#tg~2JyqhsDrH~Iwmt0s_iusm{cTE2Y(|GVF zTE;y4zT;y{$W^*5*x^bEwx?PyMn+mLzVNXv^uotU`1Qjt8NdGcrQkOJzk&D-!f!Bs z*Mz#pT3i2o5%T`Dyw;Yfd)Kv1ebNhC$(Brv8DrtvQ*)*5rOR