From 8009cdce86d92732bcb559a1d79d0ffcdd312bda Mon Sep 17 00:00:00 2001 From: Shuangrui CHEN <37070607+Phinease@users.noreply.github.com> Date: Thu, 13 Nov 2025 14:30:07 +0800 Subject: [PATCH 01/13] =?UTF-8?q?Revert=20"=E2=9C=A8[Request]=20Abstract?= =?UTF-8?q?=20Storage=20SDK"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/database/attachment_db.py | 4 +- backend/database/client.py | 136 ++++-- backend/utils/document_vector_utils.py | 8 +- doc/docs/zh/opensource-memorial-wall.md | 36 -- .../[locale]/chat/components/chatHeader.tsx | 4 +- .../[locale]/chat/internal/chatInterface.tsx | 49 +-- .../internal/memory/memoryManageModal.tsx | 4 +- .../chat/streaming/chatStreamFinalMessage.tsx | 8 - .../chat/streaming/chatStreamMain.tsx | 10 +- frontend/app/[locale]/page.tsx | 8 +- .../components/AgentSetupOrchestrator.tsx | 256 +---------- .../agents/components/McpConfigModal.tsx | 78 ++-- .../setup/agents/components/tool/ToolPool.tsx | 33 +- frontend/app/[locale]/setup/agents/config.tsx | 11 +- frontend/app/[locale]/setup/agents/page.tsx | 5 - .../components/document/DocumentList.tsx | 10 +- .../app/[locale]/setup/knowledges/page.tsx | 6 +- .../components/model/ModelDeleteDialog.tsx | 8 - frontend/app/[locale]/setup/models/page.tsx | 14 +- frontend/app/[locale]/setup/page.tsx | 22 +- frontend/components/ui/markdownRenderer.tsx | 12 +- frontend/public/locales/en/common.json | 1 - frontend/public/locales/zh/common.json | 1 - frontend/services/knowledgeBaseService.ts | 18 - frontend/types/agentConfig.ts | 4 +- frontend/types/chat.ts | 2 - sdk/nexent/__init__.py | 3 +- sdk/nexent/storage/__init__.py | 19 - sdk/nexent/storage/minio.py | 398 ------------------ sdk/nexent/storage/minio_config.py | 90 ---- sdk/nexent/storage/storage_client_base.py | 219 ---------- sdk/nexent/storage/storage_client_factory.py | 57 --- 32 files changed, 186 insertions(+), 1348 deletions(-) delete mode 100644 sdk/nexent/storage/__init__.py delete mode 100644 sdk/nexent/storage/minio.py delete mode 100644 sdk/nexent/storage/minio_config.py delete mode 100644 sdk/nexent/storage/storage_client_base.py delete mode 100644 sdk/nexent/storage/storage_client_factory.py diff --git a/backend/database/attachment_db.py b/backend/database/attachment_db.py index d7764b3a2..224ee0d8c 100644 --- a/backend/database/attachment_db.py +++ b/backend/database/attachment_db.py @@ -165,7 +165,7 @@ def get_file_size_from_minio(object_name: str, bucket: Optional[str] = None) -> """ Get file size by object name """ - bucket = bucket or minio_client.storage_config.default_bucket + bucket = bucket or minio_client.default_bucket return minio_client.get_file_size(object_name, bucket) @@ -207,7 +207,7 @@ def delete_file(object_name: str, bucket: Optional[str] = None) -> Dict[str, Any Dict[str, Any]: Delete result, containing success flag and error message (if any) """ if not bucket: - bucket = minio_client.storage_config.default_bucket + bucket = minio_client.default_bucket success, result = minio_client.delete_file(object_name, bucket) response = {"success": success, "object_name": object_name} diff --git a/backend/database/client.py b/backend/database/client.py index 27e2a1bdb..2880fde4d 100644 --- a/backend/database/client.py +++ b/backend/database/client.py @@ -1,8 +1,12 @@ import logging +import os from contextlib import contextmanager from typing import Any, BinaryIO, Dict, List, Optional, Tuple +import boto3 import psycopg2 +from botocore.client import Config +from botocore.exceptions import ClientError from sqlalchemy import create_engine from sqlalchemy.orm import class_mapper, sessionmaker @@ -19,8 +23,6 @@ POSTGRES_USER, ) from database.db_models import TableBase -from nexent.storage import create_storage_client_from_config, MinIOStorageConfig - logger = logging.getLogger("database.client") @@ -71,12 +73,6 @@ def clean_string_values(data: Dict[str, Any]) -> Dict[str, Any]: class MinioClient: - """ - MinIO client wrapper using storage SDK - - This class maintains backward compatibility with the existing MinioClient interface - while using the new storage SDK under the hood. - """ _instance: Optional['MinioClient'] = None def __new__(cls): @@ -85,18 +81,39 @@ def __new__(cls): return cls._instance def __init__(self): - # Determine if endpoint uses HTTPS - secure = MINIO_ENDPOINT.startswith('https://') if MINIO_ENDPOINT else True - # Initialize storage client using SDK factory - self.storage_config = MinIOStorageConfig( - endpoint=MINIO_ENDPOINT, - access_key=MINIO_ACCESS_KEY, - secret_key=MINIO_SECRET_KEY, - region=MINIO_REGION, - default_bucket=MINIO_DEFAULT_BUCKET, - secure=secure + self.endpoint = MINIO_ENDPOINT + self.access_key = MINIO_ACCESS_KEY + self.secret_key = MINIO_SECRET_KEY + self.region = MINIO_REGION + self.default_bucket = MINIO_DEFAULT_BUCKET + + # Initialize S3 client with proxy settings + self.client = boto3.client( + 's3', + endpoint_url=self.endpoint, + aws_access_key_id=self.access_key, + aws_secret_access_key=self.secret_key, + region_name=self.region, + config=Config( + signature_version='s3v4', + proxies={ + 'http': None, + 'https': None + } + ) ) - self._storage_client = create_storage_client_from_config(self.storage_config) + + # Ensure default bucket exists + self._ensure_bucket_exists(self.default_bucket) + + def _ensure_bucket_exists(self, bucket_name: str) -> None: + """Ensure bucket exists, create if it doesn't""" + try: + self.client.head_bucket(Bucket=bucket_name) + except ClientError: + # Bucket doesn't exist, create it + self.client.create_bucket(Bucket=bucket_name) + logger.info(f"Created bucket: {bucket_name}") def upload_file( self, @@ -115,7 +132,16 @@ def upload_file( Returns: Tuple[bool, str]: (Success status, File URL or error message) """ - return self._storage_client.upload_file(file_path, object_name, bucket) + bucket = bucket or self.default_bucket + if object_name is None: + object_name = os.path.basename(file_path) + + try: + self.client.upload_file(file_path, bucket, object_name) + file_url = f"/{bucket}/{object_name}" + return True, file_url + except Exception as e: + return False, str(e) def upload_fileobj(self, file_obj: BinaryIO, object_name: str, bucket: Optional[str] = None) -> Tuple[bool, str]: """ @@ -129,7 +155,13 @@ def upload_fileobj(self, file_obj: BinaryIO, object_name: str, bucket: Optional[ Returns: Tuple[bool, str]: (Success status, File URL or error message) """ - return self._storage_client.upload_fileobj(file_obj, object_name, bucket) + bucket = bucket or self.default_bucket + try: + self.client.upload_fileobj(file_obj, bucket, object_name) + file_url = f"/{bucket}/{object_name}" + return True, file_url + except Exception as e: + return False, str(e) def download_file(self, object_name: str, file_path: str, bucket: Optional[str] = None) -> Tuple[bool, str]: """ @@ -143,7 +175,12 @@ def download_file(self, object_name: str, file_path: str, bucket: Optional[str] Returns: Tuple[bool, str]: (Success status, Success message or error message) """ - return self._storage_client.download_file(object_name, file_path, bucket) + bucket = bucket or self.default_bucket + try: + self.client.download_file(bucket, object_name, file_path) + return True, f"File downloaded successfully to {file_path}" + except Exception as e: + return False, str(e) def get_file_url(self, object_name: str, bucket: Optional[str] = None, expires: int = 3600) -> Tuple[bool, str]: """ @@ -157,20 +194,23 @@ def get_file_url(self, object_name: str, bucket: Optional[str] = None, expires: Returns: Tuple[bool, str]: (Success status, Presigned URL or error message) """ - return self._storage_client.get_file_url(object_name, bucket, expires) + bucket = bucket or self.default_bucket + try: + url = self.client.generate_presigned_url('get_object', Params={'Bucket': bucket, 'Key': object_name}, + ExpiresIn=expires) + return True, url + except Exception as e: + return False, str(e) def get_file_size(self, object_name: str, bucket: Optional[str] = None) -> int: - """ - Get file size in bytes - - Args: - object_name: Object name - bucket: Bucket name, if not specified use default bucket - - Returns: - int: File size in bytes, 0 if file not found or error - """ - return self._storage_client.get_file_size(object_name, bucket) + bucket = bucket or self.default_bucket + try: + response = self.client.head_object(Bucket=bucket, Key=object_name) + return int(response['ContentLength']) + except ClientError as e: + logger.error( + f"Get file size by objectname({object_name}) failed: {e}") + return 0 def list_files(self, prefix: str = "", bucket: Optional[str] = None) -> List[dict]: """ @@ -183,7 +223,19 @@ def list_files(self, prefix: str = "", bucket: Optional[str] = None) -> List[dic Returns: List[dict]: List of file information """ - return self._storage_client.list_files(prefix, bucket) + bucket = bucket or self.default_bucket + try: + response = self.client.list_objects_v2( + Bucket=bucket, Prefix=prefix) + files = [] + if 'Contents' in response: + for obj in response['Contents']: + files.append( + {'key': obj['Key'], 'size': obj['Size'], 'last_modified': obj['LastModified']}) + return files + except Exception as e: + logger.error(f"Error listing files: {str(e)}") + return [] def delete_file(self, object_name: str, bucket: Optional[str] = None) -> Tuple[bool, str]: """ @@ -196,7 +248,12 @@ def delete_file(self, object_name: str, bucket: Optional[str] = None) -> Tuple[b Returns: Tuple[bool, str]: (Success status, Success message or error message) """ - return self._storage_client.delete_file(object_name, bucket) + bucket = bucket or self.default_bucket + try: + self.client.delete_object(Bucket=bucket, Key=object_name) + return True, f"File {object_name} deleted successfully" + except Exception as e: + return False, str(e) def get_file_stream(self, object_name: str, bucket: Optional[str] = None) -> Tuple[bool, Any]: """ @@ -209,7 +266,12 @@ def get_file_stream(self, object_name: str, bucket: Optional[str] = None) -> Tup Returns: Tuple[bool, Any]: (Success status, File stream object or error message) """ - return self._storage_client.get_file_stream(object_name, bucket) + bucket = bucket or self.default_bucket + try: + response = self.client.get_object(Bucket=bucket, Key=object_name) + return True, response['Body'] + except Exception as e: + return False, str(e) # Create global database and MinIO client instances diff --git a/backend/utils/document_vector_utils.py b/backend/utils/document_vector_utils.py index d470071a5..c37e17474 100644 --- a/backend/utils/document_vector_utils.py +++ b/backend/utils/document_vector_utils.py @@ -595,10 +595,8 @@ def summarize_document(document_content: str, filename: str, language: str = LAN {"role": MESSAGE_ROLE["USER"], "content": user_prompt} ] - # Call LLM, allow more tokens for generation - response = llm(messages, max_tokens=max_words * 2) - if not response or not response.content: - return "" + # Call LLM + response = llm(messages, max_tokens=max_words * 2) # Allow more tokens for generation return response.content.strip() else: # Fallback to placeholder if no model configuration @@ -677,8 +675,6 @@ def summarize_cluster(document_summaries: List[str], language: str = LANGUAGE["Z # Call LLM response = llm(messages, max_tokens=max_words * 2) # Allow more tokens for generation - if not response or not response.content: - return "" return response.content.strip() else: # Fallback to placeholder if no model configuration diff --git a/doc/docs/zh/opensource-memorial-wall.md b/doc/docs/zh/opensource-memorial-wall.md index 4ee74f603..c7cb65c00 100644 --- a/doc/docs/zh/opensource-memorial-wall.md +++ b/doc/docs/zh/opensource-memorial-wall.md @@ -16,10 +16,6 @@ 请保持消息的礼貌和尊重,符合我们的行为准则。 --> -::: info lzysleep - 2025-11-7 -非常不错的项目,很适合快速上手搭建自己的Agent,赞赞赞! -::: - ::: info fishcat - 2025-10-31 很好的项目,希望蒸蒸日上 ::: @@ -304,44 +300,12 @@ Nexent功能如此之强大,给我很多帮助,感谢开发者!厉害 ::: info niceman - 2025-10-29 感谢 Nexent 让我踏上了开源之旅!希望能参加ict大赛长长见识。项目不错,给个star~ -::: :::info XxHosxX - 2025-11-5 希望参与ICT大赛以及Nexent平台提升自己的能力:) -::: ::: tip Zwer1 - 2025-11-04 感谢 Nexent 让我踏上了开源之旅!平台开发智能体的能力十分强大,希望能够学习到更多东西! ::: -::: tip Zwer1 - 2025-11-04 -想参加ICT创新赛 -::: - -::: tip Jackie - 2025-11-07 -期待能使用Nexent成为智能体开发大佬 -::: - -::: info xiaochenIpter - 2025-11-08 -希望能参加ict大赛可以学习到更多知识,感谢 Nexent 让我踏上了开源之旅!平台开发智能体的能力十分强大,希望能够学习到更多东西! -::: - -::: info user - 2025-11-08 "🎉 很高兴加入Nexent社区!作为新贡献者,我期待在代码优化、文档完善或测试反馈中尽一份力。#NexentCommunity 让我们一起构建更棒的项目!🚀" -::: - -::: pxqn-xing - 2025-11-08 -感谢Nexent让我参与ICT大赛以提升自己的能力 -::: - -::: QIYAN - 2025-11-09 -体验华为AI技术的一天 -::: - -::: tip qiyan111 - 2025-11-10 -想试下华为的智能体 -::: - -:::info XxHosxX - 2025-11-10 -自动创建agent的功能挺创新的,试过其他很多平台基本上都是只能通过一句描述语言优化提示词,很少有可以通过一句描述语言直接生成agent的功能,赞! -::: diff --git a/frontend/app/[locale]/chat/components/chatHeader.tsx b/frontend/app/[locale]/chat/components/chatHeader.tsx index 549a5f548..ea64c958c 100644 --- a/frontend/app/[locale]/chat/components/chatHeader.tsx +++ b/frontend/app/[locale]/chat/components/chatHeader.tsx @@ -50,8 +50,8 @@ export function ChatHeader({ title, onRename }: ChatHeaderProps) { const inputRef = useRef(null); const { t } = useTranslation("common"); const { currentLanguage, handleLanguageChange } = useLanguageSwitch(); - const { user, isSpeedMode } = useAuth(); - const isAdmin = isSpeedMode || user?.role === USER_ROLES.ADMIN; + const { user } = useAuth(); + const isAdmin = user?.role === USER_ROLES.ADMIN; const goToModelSetup = () => { router.push(`/${currentLanguage}/setup/models`); diff --git a/frontend/app/[locale]/chat/internal/chatInterface.tsx b/frontend/app/[locale]/chat/internal/chatInterface.tsx index db65739e8..ff60ec4bb 100644 --- a/frontend/app/[locale]/chat/internal/chatInterface.tsx +++ b/frontend/app/[locale]/chat/internal/chatInterface.tsx @@ -2,7 +2,7 @@ import type React from "react"; -import { useState, useRef, useEffect, useCallback } from "react"; +import { useState, useRef, useEffect } from "react"; import { useRouter } from "next/navigation"; import { v4 as uuidv4 } from "uuid"; import { useTranslation } from "react-i18next"; @@ -61,7 +61,7 @@ const getI18nKeyByType = (type: string): string => { export function ChatInterface() { const router = useRouter(); - const { user, isSpeedMode } = useAuth(); // Get user information + const { user } = useAuth(); // Get user information const [input, setInput] = useState(""); // Replace the original messages state const [sessionMessages, setSessionMessages] = useState<{ @@ -208,45 +208,6 @@ export function ChatInterface() { setShowRightPanel(false); }, [conversationManagement.conversationId]); - // Helper function to clear completed conversation indicator - const clearCompletedIndicator = useCallback(() => { - if ( - conversationManagement.conversationId && - conversationManagement.conversationId !== -1 - ) { - setCompletedConversations((prev) => { - // Use functional update to avoid dependency on completedConversations - if (prev.has(conversationManagement.conversationId)) { - const newSet = new Set(prev); - newSet.delete(conversationManagement.conversationId); - return newSet; - } - return prev; - }); - } - }, [conversationManagement.conversationId]); - - // Add useEffect to clear completed conversation indicator when user is viewing the current conversation - useEffect(() => { - // If current conversation is in completedConversations, clear it when user is viewing it - clearCompletedIndicator(); - }, [conversationManagement.conversationId, clearCompletedIndicator]); - - // Add click event listener to clear completed conversation indicator when user clicks anywhere on the page - useEffect(() => { - const handlePageClick = (e: MouseEvent) => { - // Clear completed indicator when user clicks anywhere on the page - clearCompletedIndicator(); - }; - - // Add click event listener to the document - document.addEventListener('click', handlePageClick, true); - - return () => { - document.removeEventListener('click', handlePageClick, true); - }; - }, [clearCompletedIndicator]); - // Clear all timers and requests when component unmounts useEffect(() => { @@ -1578,8 +1539,8 @@ export function ChatInterface() { // Both admin and regular users now use dropdown menus }; - // Settings menu items based on user role (speed mode is treated as admin) - const settingsMenuItems = (isSpeedMode || user?.role === "admin") ? [ + // Settings menu items based on user role + const settingsMenuItems = user?.role === "admin" ? [ // Admin has three options { key: "models", @@ -1674,8 +1635,6 @@ export function ChatInterface() { shouldScrollToBottom={shouldScrollToBottom} selectedAgentId={selectedAgentId} onAgentSelect={setSelectedAgentId} - onCitationHover={clearCompletedIndicator} - onScroll={clearCompletedIndicator} /> diff --git a/frontend/app/[locale]/chat/internal/memory/memoryManageModal.tsx b/frontend/app/[locale]/chat/internal/memory/memoryManageModal.tsx index e0639ed28..23beb6fa9 100644 --- a/frontend/app/[locale]/chat/internal/memory/memoryManageModal.tsx +++ b/frontend/app/[locale]/chat/internal/memory/memoryManageModal.tsx @@ -45,10 +45,10 @@ const MemoryManageModal: React.FC = ({ userRole, }) => { // Get user role from authentication context - const { user, isSpeedMode } = useAuth(); + const { user } = useAuth(); const { message } = App.useApp(); const role: (typeof USER_ROLES)[keyof typeof USER_ROLES] = (userRole ?? - (isSpeedMode || user?.role === USER_ROLES.ADMIN ? USER_ROLES.ADMIN : USER_ROLES.USER)) as (typeof USER_ROLES)[keyof typeof USER_ROLES]; + (user?.role === USER_ROLES.ADMIN ? USER_ROLES.ADMIN : USER_ROLES.USER)) as (typeof USER_ROLES)[keyof typeof USER_ROLES]; // Get user role from other hooks / context const currentUserId = "user1"; diff --git a/frontend/app/[locale]/chat/streaming/chatStreamFinalMessage.tsx b/frontend/app/[locale]/chat/streaming/chatStreamFinalMessage.tsx index fe5bad3be..34c32ed37 100644 --- a/frontend/app/[locale]/chat/streaming/chatStreamFinalMessage.tsx +++ b/frontend/app/[locale]/chat/streaming/chatStreamFinalMessage.tsx @@ -32,7 +32,6 @@ interface FinalMessageProps { hideButtons?: boolean; index?: number; currentConversationId?: number; - onCitationHover?: () => void; } // TTS playback status @@ -49,7 +48,6 @@ export function ChatStreamFinalMessage({ hideButtons = false, index, currentConversationId, - onCitationHover, }: FinalMessageProps) { const { t } = useTranslation("common"); @@ -271,7 +269,6 @@ export function ChatStreamFinalMessage({ {/* Button group - only show when hideButtons is false and message is complete */} @@ -290,11 +287,6 @@ export function ChatStreamFinalMessage({ isSelected ? "bg-gray-100" : "" }`} onClick={handleMessageSelect} - onMouseEnter={() => { - if (onCitationHover) { - onCitationHover(); - } - }} > {searchResultsCount > 0 && diff --git a/frontend/app/[locale]/chat/streaming/chatStreamMain.tsx b/frontend/app/[locale]/chat/streaming/chatStreamMain.tsx index 6709d734b..dde39fed4 100644 --- a/frontend/app/[locale]/chat/streaming/chatStreamMain.tsx +++ b/frontend/app/[locale]/chat/streaming/chatStreamMain.tsx @@ -37,8 +37,6 @@ export function ChatStreamMain({ shouldScrollToBottom, selectedAgentId, onAgentSelect, - onCitationHover, - onScroll, }: ChatStreamMainProps) { const { t } = useTranslation(); // Animation variants for ChatInput @@ -327,11 +325,6 @@ export function ChatStreamMain({ setAutoScroll(false); } } - - // Clear completed conversation indicator when scrolling - if (onScroll) { - onScroll(); - } }; // Add scroll event listener @@ -343,7 +336,7 @@ export function ChatStreamMain({ return () => { scrollAreaElement.removeEventListener("scroll", handleScroll); }; - }, [shouldScrollToBottom, onScroll]); + }, [shouldScrollToBottom]); // Scroll to bottom function const scrollToBottom = (smooth = false) => { @@ -551,7 +544,6 @@ export function ChatStreamMain({ onOpinionChange={onOpinionChange} index={index} currentConversationId={currentConversationId} - onCitationHover={onCitationHover} /> {message.role === "user" && processedMessages.conversationGroups.has(message.id!) && ( diff --git a/frontend/app/[locale]/page.tsx b/frontend/app/[locale]/page.tsx index 81922cfe8..93d6e11cb 100644 --- a/frontend/app/[locale]/page.tsx +++ b/frontend/app/[locale]/page.tsx @@ -77,7 +77,7 @@ export default function Home() { // Handle operations that require login const handleAuthRequired = (e: React.MouseEvent) => { - if (!isSpeedMode && !user) { + if (!user) { e.preventDefault(); setLoginPromptOpen(true); } @@ -102,7 +102,7 @@ export default function Home() { // Handle operations that require admin privileges const handleAdminRequired = (e: React.MouseEvent) => { - if (!isSpeedMode && user?.role !== "admin") { + if (user?.role !== "admin") { e.preventDefault(); setAdminRequiredPromptOpen(true); } @@ -244,7 +244,7 @@ export default function Home() { transition={{ duration: 0.8, delay: 0.4 }} className="flex flex-col sm:flex-row gap-4" > - + + ); + })} + + + + {/* Tab Description */} +
+ {tabConfig[activeTab].icon} {tabConfig[activeTab].description} +
+ + {/* Content */} +
+ {activeTab === "dashboard" && } + {activeTab === "knowledge-graph" && } + {activeTab === "diagnosis-flow" && } +
+ + {/* Footer */} +
+ 数据来源: 病理学知识库 + 最后更新: {new Date().toLocaleDateString()} +
+ + ); +}; + +export default MedicalVisualizationPanel; diff --git a/pathology-ai/code-changes/frontend/PathologyImageGallery.tsx b/pathology-ai/code-changes/frontend/PathologyImageGallery.tsx new file mode 100644 index 000000000..766ad28e8 --- /dev/null +++ b/pathology-ai/code-changes/frontend/PathologyImageGallery.tsx @@ -0,0 +1,326 @@ +"use client"; + +import React, { useState, useCallback } from "react"; +import { ChevronLeft, ChevronRight, X, ZoomIn, ZoomOut, Download, ExternalLink } from "lucide-react"; + +// 病理图片类型 +export interface PathologyImage { + id: string; + url: string; + title: string; + category: string; + description?: string; + magnification?: string; + staining?: string; +} + +// 组件属性 +interface PathologyImageGalleryProps { + images: PathologyImage[]; + className?: string; + columns?: 2 | 3 | 4; + showDetails?: boolean; + onImageClick?: (image: PathologyImage) => void; +} + +// 分类颜色映射 +const categoryColors: Record = { + "Immunopathology": "bg-purple-100 text-purple-800", + "Pulmonary": "bg-blue-100 text-blue-800", + "Cardiovascular": "bg-red-100 text-red-800", + "Neoplasia": "bg-orange-100 text-orange-800", + "Neuropathology": "bg-indigo-100 text-indigo-800", + "Gastrointestinal": "bg-green-100 text-green-800", + "Hematopathology": "bg-pink-100 text-pink-800", + "Inflammation": "bg-yellow-100 text-yellow-800", + "Histology": "bg-teal-100 text-teal-800", + "ElectronMicroscopy": "bg-gray-100 text-gray-800", + "default": "bg-slate-100 text-slate-800", +}; + +// 获取分类颜色 +const getCategoryColor = (category: string): string => { + return categoryColors[category] || categoryColors["default"]; +}; + +// 分类中文名映射 +const categoryNames: Record = { + "Immunopathology": "免疫病理", + "Pulmonary": "肺部病理", + "Cardiovascular": "心血管病理", + "Neoplasia": "肿瘤病理", + "Neuropathology": "神经病理", + "Gastrointestinal": "消化系统", + "Hematopathology": "血液病理", + "Inflammation": "炎症病理", + "Histology": "组织学", + "ElectronMicroscopy": "电子显微镜", +}; + +// 获取分类中文名 +const getCategoryName = (category: string): string => { + return categoryNames[category] || category; +}; + +export const PathologyImageGallery: React.FC = ({ + images, + className = "", + columns = 3, + showDetails = true, + onImageClick, +}) => { + const [selectedIndex, setSelectedIndex] = useState(null); + const [zoom, setZoom] = useState(1); + + // 打开大图预览 + const openPreview = useCallback((index: number) => { + setSelectedIndex(index); + setZoom(1); + }, []); + + // 关闭预览 + const closePreview = useCallback(() => { + setSelectedIndex(null); + setZoom(1); + }, []); + + // 上一张 + const prevImage = useCallback(() => { + if (selectedIndex !== null && selectedIndex > 0) { + setSelectedIndex(selectedIndex - 1); + setZoom(1); + } + }, [selectedIndex]); + + // 下一张 + const nextImage = useCallback(() => { + if (selectedIndex !== null && selectedIndex < images.length - 1) { + setSelectedIndex(selectedIndex + 1); + setZoom(1); + } + }, [selectedIndex, images.length]); + + // 缩放 + const handleZoom = useCallback((delta: number) => { + setZoom((prev) => Math.max(0.5, Math.min(3, prev + delta))); + }, []); + + // 键盘事件 + React.useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (selectedIndex === null) return; + switch (e.key) { + case "Escape": + closePreview(); + break; + case "ArrowLeft": + prevImage(); + break; + case "ArrowRight": + nextImage(); + break; + case "+": + case "=": + handleZoom(0.25); + break; + case "-": + handleZoom(-0.25); + break; + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [selectedIndex, closePreview, prevImage, nextImage, handleZoom]); + + // 网格列数样式 + const gridCols = { + 2: "grid-cols-2", + 3: "grid-cols-2 md:grid-cols-3", + 4: "grid-cols-2 md:grid-cols-3 lg:grid-cols-4", + }; + + if (images.length === 0) { + return ( +
+
+ 🔬 +

暂无病理图片

+
+
+ ); + } + + return ( +
+ {/* 图片网格 */} +
+ {images.map((image, index) => ( +
{ + openPreview(index); + onImageClick?.(image); + }} + > + {/* 图片 */} +
+ {image.title} { + (e.target as HTMLImageElement).src = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Crect fill='%23f3f4f6' width='200' height='200'/%3E%3Ctext fill='%239ca3af' x='50%25' y='50%25' text-anchor='middle' dy='.3em'%3E🔬%3C/text%3E%3C/svg%3E"; + }} + /> +
+ + {/* 分类标签 */} +
+ + {getCategoryName(image.category)} + +
+ + {/* 放大图标 */} +
+
+ +
+
+ + {/* 详情 */} + {showDetails && ( +
+

{image.title}

+ {image.description && ( +

{image.description}

+ )} +
+ {image.magnification && ( + + {image.magnification} + + )} + {image.staining && ( + + {image.staining} + + )} +
+
+ )} +
+ ))} +
+ + {/* 大图预览模态框 */} + {selectedIndex !== null && ( +
+ {/* 工具栏 */} +
+ + + e.stopPropagation()} + > + + + +
+ + {/* 图片计数 */} +
+ {selectedIndex + 1} / {images.length} +
+ + {/* 左箭头 */} + {selectedIndex > 0 && ( + + )} + + {/* 图片 */} +
e.stopPropagation()} + > + {images[selectedIndex].title} +
+ + {/* 右箭头 */} + {selectedIndex < images.length - 1 && ( + + )} + + {/* 底部信息 */} +
+

{images[selectedIndex].title}

+

+ {getCategoryName(images[selectedIndex].category)} + {images[selectedIndex].magnification && ` · ${images[selectedIndex].magnification}`} + {images[selectedIndex].staining && ` · ${images[selectedIndex].staining}`} +

+ {images[selectedIndex].description && ( +

+ {images[selectedIndex].description} +

+ )} +
+
+ )} +
+ ); +}; + +export default PathologyImageGallery; diff --git a/pathology-ai/code-changes/frontend/SourceTag.tsx b/pathology-ai/code-changes/frontend/SourceTag.tsx new file mode 100644 index 000000000..e88f4b891 --- /dev/null +++ b/pathology-ai/code-changes/frontend/SourceTag.tsx @@ -0,0 +1,178 @@ +"use client"; + +import React from "react"; +import { Database, Globe, BookOpen, FileText, Sparkles } from "lucide-react"; + +// 来源类型 +export type SourceType = "internal" | "external" | "knowledge" | "reference" | "ai"; + +// 组件属性 +interface SourceTagProps { + type: SourceType; + weight?: number; + className?: string; + size?: "sm" | "md" | "lg"; + showIcon?: boolean; + showWeight?: boolean; +} + +// 来源配置 +const sourceConfig: Record = { + internal: { + label: "内部", + labelEn: "Internal", + color: "text-blue-700", + bgColor: "bg-blue-50", + borderColor: "border-blue-200", + icon: , + description: "来自本地知识库", + }, + external: { + label: "外部", + labelEn: "External", + color: "text-purple-700", + bgColor: "bg-purple-50", + borderColor: "border-purple-200", + icon: , + description: "来自网络搜索", + }, + knowledge: { + label: "知识库", + labelEn: "Knowledge", + color: "text-green-700", + bgColor: "bg-green-50", + borderColor: "border-green-200", + icon: , + description: "来自专业知识库", + }, + reference: { + label: "参考", + labelEn: "Reference", + color: "text-orange-700", + bgColor: "bg-orange-50", + borderColor: "border-orange-200", + icon: , + description: "参考文献来源", + }, + ai: { + label: "AI分析", + labelEn: "AI", + color: "text-indigo-700", + bgColor: "bg-indigo-50", + borderColor: "border-indigo-200", + icon: , + description: "AI生成内容", + }, +}; + +// 尺寸配置 +const sizeConfig = { + sm: { + padding: "px-1.5 py-0.5", + text: "text-xs", + iconSize: "w-3 h-3", + gap: "gap-1", + }, + md: { + padding: "px-2 py-1", + text: "text-sm", + iconSize: "w-3.5 h-3.5", + gap: "gap-1.5", + }, + lg: { + padding: "px-3 py-1.5", + text: "text-base", + iconSize: "w-4 h-4", + gap: "gap-2", + }, +}; + +export const SourceTag: React.FC = ({ + type, + weight, + className = "", + size = "sm", + showIcon = true, + showWeight = false, +}) => { + const config = sourceConfig[type]; + const sizeStyle = sizeConfig[size]; + + return ( + + {showIcon && config.icon} + {config.label} + {showWeight && weight !== undefined && ( + ({weight}%) + )} + + ); +}; + +// 内部标签快捷组件 +export const InternalTag: React.FC> = (props) => ( + +); + +// 外部标签快捷组件 +export const ExternalTag: React.FC> = (props) => ( + +); + +// 综合结论标签 +export const ConclusionTag: React.FC<{ className?: string }> = ({ className = "" }) => ( + + + 综合结论 + +); + +// 解析消息中的来源标签 +export const parseSourceTags = (text: string): React.ReactNode[] => { + const parts: React.ReactNode[] = []; + const regex = /\[内部\]|\[外部\]|\[内部知识库\]|\[外部最新信息\]|\[外部最新\]|\*\*\[内部\]\*\*|\*\*\[外部\]\*\*|\*\*\[内部知识库\]\*\*|\*\*\[外部最新信息\]\*\*|\*\*综合结论\*\*/g; + + let lastIndex = 0; + let match; + + while ((match = regex.exec(text)) !== null) { + // 添加匹配前的文本 + if (match.index > lastIndex) { + parts.push(text.slice(lastIndex, match.index)); + } + + // 添加标签组件 + const matchText = match[0].replace(/\*\*/g, ""); + if (matchText.includes("内部")) { + parts.push(); + } else if (matchText.includes("外部")) { + parts.push(); + } else if (matchText.includes("综合结论")) { + parts.push(); + } + + lastIndex = regex.lastIndex; + } + + // 添加剩余文本 + if (lastIndex < text.length) { + parts.push(text.slice(lastIndex)); + } + + return parts.length > 0 ? parts : [text]; +}; + +export default SourceTag; diff --git a/pathology-ai/code-changes/frontend/chatLeftSidebar.tsx b/pathology-ai/code-changes/frontend/chatLeftSidebar.tsx new file mode 100644 index 000000000..907e18d1e --- /dev/null +++ b/pathology-ai/code-changes/frontend/chatLeftSidebar.tsx @@ -0,0 +1,544 @@ +import { useState, useRef, useEffect } from "react"; +import { + Clock, + Plus, + Pencil, + Trash2, + MoreHorizontal, + ChevronLeft, + ChevronRight, + Trash, +} from "lucide-react"; +import { useRouter } from "next/navigation"; + +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdownMenu"; +import { Input } from "@/components/ui/input"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { StaticScrollArea } from "@/components/ui/scrollArea"; +import { USER_ROLES } from "@/const/modelConfig"; +import { useTranslation } from "react-i18next"; +import { ConversationListItem, ChatSidebarProps } from "@/types/chat"; + +// conversation status indicator component +const ConversationStatusIndicator = ({ + isStreaming, + isCompleted, +}: { + isStreaming: boolean; + isCompleted: boolean; +}) => { + const { t } = useTranslation(); + + if (isStreaming) { + return ( +
+ ); + } + + if (isCompleted) { + return ( +
+ ); + } + + return null; +}; + + +// Helper function - dialog classification +const categorizeDialogs = (dialogs: ConversationListItem[]) => { + const now = new Date(); + const today = new Date( + now.getFullYear(), + now.getMonth(), + now.getDate() + ).getTime(); + const weekAgo = today - 7 * 24 * 60 * 60 * 1000; + + const todayDialogs: ConversationListItem[] = []; + const weekDialogs: ConversationListItem[] = []; + const olderDialogs: ConversationListItem[] = []; + + dialogs.forEach((dialog) => { + const dialogTime = dialog.create_time; + + if (dialogTime >= today) { + todayDialogs.push(dialog); + } else if (dialogTime >= weekAgo) { + weekDialogs.push(dialog); + } else { + olderDialogs.push(dialog); + } + }); + + return { + today: todayDialogs, + week: weekDialogs, + older: olderDialogs, + }; +}; + +export function ChatSidebar({ + conversationList, + selectedConversationId, + openDropdownId, + streamingConversations, + completedConversations, + onNewConversation, + onDialogClick, + onRename, + onDelete, + onSettingsClick, + settingsMenuItems, + onDropdownOpenChange, + onToggleSidebar, + expanded, + userEmail, + userAvatarUrl, + userRole = USER_ROLES.USER, +}: ChatSidebarProps) { + const { t } = useTranslation(); + const router = useRouter(); + const { today, week, older } = categorizeDialogs(conversationList); + const [editingId, setEditingId] = useState(null); + const [editingTitle, setEditingTitle] = useState(""); + const inputRef = useRef(null); + + // Add delete dialog status + const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); + const [dialogToDelete, setDialogToDelete] = useState(null); + + // Add delete all dialog status + const [isDeleteAllDialogOpen, setIsDeleteAllDialogOpen] = useState(false); + const [isDeleting, setIsDeleting] = useState(false); + + const [animationComplete, setAnimationComplete] = useState(false); + + useEffect(() => { + // Reset animation state when expanded changes + setAnimationComplete(false); + + // Set animation complete after the transition duration (200ms) + const timer = setTimeout(() => { + setAnimationComplete(true); + }, 200); + + return () => clearTimeout(timer); + }, [expanded]); + + // Handle edit start + const handleStartEdit = (dialogId: number, title: string) => { + setEditingId(dialogId); + setEditingTitle(title); + // Close any open dropdown menus + onDropdownOpenChange(false, null); + + // Use setTimeout to ensure that the input box is focused after the DOM is updated + setTimeout(() => { + if (inputRef.current) { + inputRef.current.focus(); + inputRef.current.select(); + } + }, 10); + }; + + // Handle edit submission + const handleSubmitEdit = () => { + if (editingId !== null && editingTitle.trim()) { + onRename(editingId, editingTitle.trim()); + setEditingId(null); + } + }; + + // Handle edit cancellation + const handleCancelEdit = () => { + setEditingId(null); + }; + + // Handle key events + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + handleSubmitEdit(); + } else if (e.key === "Escape") { + handleCancelEdit(); + } + }; + + // Handle delete click + const handleDeleteClick = (dialogId: number) => { + setDialogToDelete(dialogId); + setIsDeleteDialogOpen(true); + // Close dropdown menus + onDropdownOpenChange(false, null); + }; + + // Confirm delete + const confirmDelete = () => { + if (dialogToDelete !== null) { + onDelete(dialogToDelete); + setIsDeleteDialogOpen(false); + setDialogToDelete(null); + } + }; + + // Handle delete all click + const handleDeleteAllClick = () => { + if (conversationList.length > 0) { + setIsDeleteAllDialogOpen(true); + } + }; + + // Confirm delete all + const confirmDeleteAll = async () => { + setIsDeleting(true); + try { + for (const conv of conversationList) { + await onDelete(conv.conversation_id); + } + } finally { + setIsDeleting(false); + setIsDeleteAllDialogOpen(false); + } + }; + + // Render dialog list items + const renderDialogList = (dialogs: ConversationListItem[], title: string) => { + if (dialogs.length === 0) return null; + + return ( +
+

+ {title} +

+ {dialogs.map((dialog) => ( +
+ {editingId === dialog.conversation_id ? ( + // Edit mode +
+ setEditingTitle(e.target.value)} + onKeyDown={handleKeyDown} + onBlur={handleSubmitEdit} + className="h-8 text-base" + autoFocus + /> +
+ ) : ( + // Display mode + <> + + + + + + +

{dialog.conversation_title}

+
+
+
+ + + onDropdownOpenChange( + open, + dialog.conversation_id.toString() + ) + } + > + + + + + + handleStartEdit( + dialog.conversation_id, + dialog.conversation_title + ) + } + > + + {t("chatLeftSidebar.rename")} + + handleDeleteClick(dialog.conversation_id)} + > + + {t("chatLeftSidebar.delete")} + + + + + )} +
+ ))} +
+ ); + }; + + // Render collapsed state sidebar + const renderCollapsedSidebar = () => { + return ( + <> + {/* Expand/Collapse button */} +
+ + + + + + + {t("chatLeftSidebar.expandSidebar")} + + + +
+ + {/* New conversation button */} +
+ + + + + + + {t("chatLeftSidebar.newConversation")} + + + +
+ + {/* Spacer */} +
+ + ); + }; + + return ( + <> +
+ {expanded || !animationComplete ? ( +
+
+
+ + + + + + + +

{t("chatLeftSidebar.collapseSidebar")}

+
+
+
+
+
+ + +
+ {conversationList.length > 0 ? ( + <> + {renderDialogList(today, t("chatLeftSidebar.today"))} + {renderDialogList(week, t("chatLeftSidebar.last7Days"))} + {renderDialogList(older, t("chatLeftSidebar.older"))} + + ) : ( +
+

+ {t("chatLeftSidebar.recentConversations")} +

+ +
+ )} +
+
+ + {/* Delete all button */} + {conversationList.length > 0 && ( +
+ +
+ )} +
+ ) : ( + renderCollapsedSidebar() + )} +
+ + {/* Delete confirmation dialog */} + + + + + {t("chatLeftSidebar.confirmDeletionTitle")} + + + {t("chatLeftSidebar.confirmDeletionDescription")} + + + + + + + + + + {/* Delete all confirmation dialog */} + + + + + {t("chatLeftSidebar.confirmDeleteAllTitle", { defaultValue: "确认清空所有对话" })} + + + {t("chatLeftSidebar.confirmDeleteAllDescription", { + defaultValue: `确定要删除全部 ${conversationList.length} 个对话吗?此操作不可恢复。`, + count: conversationList.length + })} + + + + + + + + + + ); +} diff --git a/pathology-ai/code-changes/frontend/conversationService.ts b/pathology-ai/code-changes/frontend/conversationService.ts new file mode 100644 index 000000000..9d27ccc1e --- /dev/null +++ b/pathology-ai/code-changes/frontend/conversationService.ts @@ -0,0 +1,853 @@ +import { API_ENDPOINTS, ApiError } from './api'; + +import { chatConfig } from '@/const/chatConfig'; +import type { + ConversationListResponse, + ConversationListItem, + ApiConversationResponse +} from '@/types/conversation'; +import { getAuthHeaders, fetchWithAuth } from '@/lib/auth'; +import log from "@/lib/logger"; + +// @ts-ignore +const fetch = fetchWithAuth; + +// This helper function now ALWAYS connects through the current host and port. +// This relies on our custom `server.js` to handle the proxying in all environments. +const getWebSocketUrl = (endpoint: string): string => { + const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; + const wsUrl = `${protocol}//${window.location.host}${endpoint}`; + log.log(`[WebSocket] Connecting via server proxy: ${wsUrl}`); + return wsUrl; +}; + +export const conversationService = { + // Get conversation list + async getList(): Promise { + const response = await fetch(API_ENDPOINTS.conversation.list); + + const data = await response.json() as ConversationListResponse; + + if (data.code === 0) { + return data.data || []; + } + + throw new ApiError(data.code, data.message); + }, + + // Create new conversation + async create(title?: string) { + const response = await fetch(API_ENDPOINTS.conversation.create, { + method: 'PUT', + headers: getAuthHeaders(), + body: JSON.stringify({ + title: title || "new conversation" + }), + }); + + const data = await response.json(); + + if (data.code === 0) { + return data.data; + } + + throw new ApiError(data.code, data.message); + }, + + // Rename conversation + async rename(conversationId: number, name: string) { + const response = await fetch(API_ENDPOINTS.conversation.rename, { + method: 'POST', + headers: getAuthHeaders(), + body: JSON.stringify({ + conversation_id: conversationId, + name, + }), + }); + + const data = await response.json(); + + if (data.code === 0) { + return data.data; + } + + throw new ApiError(data.code, data.message); + }, + + // Get conversation details + async getDetail(conversationId: number, signal?: AbortSignal): Promise { + try { + const response = await fetch(API_ENDPOINTS.conversation.detail(conversationId), { + method: 'GET', + headers: getAuthHeaders(), + signal, + }); + + // If the signal is aborted before the request returns, return early + if (signal?.aborted) { + return { code: -1, message: "请求已取消", data: [] }; + } + + const data = await response.json(); + + if (data.code === 0) { + return data; + } + + throw new ApiError(data.code, data.message); + } catch (error: any) { + // If the error is caused by canceling the request, return a specific response instead of throwing an error + if (error instanceof Error && error.name === 'AbortError' || signal?.aborted) { + return { code: -1, message: "请求已取消", data: [] }; + } + throw error; + } + }, + + // Delete conversation + async delete(conversationId: number) { + const response = await fetch(API_ENDPOINTS.conversation.delete(conversationId), { + method: 'DELETE', + headers: getAuthHeaders(), + }); + + const data = await response.json(); + + if (data.code === 0) { + return true; + } + + throw new ApiError(data.code, data.message); + }, + + // Delete all conversations + async deleteAll(conversationIds: number[]) { + const results = await Promise.allSettled( + conversationIds.map(id => this.delete(id)) + ); + const successCount = results.filter(r => r.status === 'fulfilled').length; + return { successCount, totalCount: conversationIds.length }; + }, + + // Stop conversation agent + async stop(conversationId: number) { + const response = await fetch(API_ENDPOINTS.agent.stop(conversationId), { + method: 'GET', + headers: getAuthHeaders(), + }); + + const data = await response.json(); + + if (data.status === 'success') { + return true; + } + + throw new ApiError(data.code || -1, data.message || data.detail || '停止失败'); + }, + + // STT related functionality + stt: { + // Create WebSocket connection + createWebSocket(): WebSocket { + return new WebSocket(getWebSocketUrl(API_ENDPOINTS.stt.ws)); + }, + + // Process audio data + processAudioData(inputData: Float32Array): Int16Array { + const pcmData = new Int16Array(inputData.length); + for (let i = 0; i < inputData.length; i++) { + const s = Math.max(-1, Math.min(1, inputData[i])); + pcmData[i] = s < 0 ? s * 0x8000 : s * 0x7FFF; + } + return pcmData; + }, + + // Get audio configuration + getAudioConstraints() { + return { + audio: { + sampleRate: 16000, + channelCount: 1, + echoCancellation: true, + noiseSuppression: true, + autoGainControl: true, + } + }; + }, + + // Get audio context configuration + getAudioContextOptions() { + return { + sampleRate: 16000, + }; + } + }, + + // Add TTS related functionality + tts: { + // Create WebSocket connection + // TODO: explain why we need to create a WebSocket connection for TTS + createWebSocket(): WebSocket { + return new WebSocket(getWebSocketUrl(API_ENDPOINTS.tts.ws)); + }, + + // TTS playback status management + createTTSService() { + const audioRef = { current: null as HTMLAudioElement | null }; + const wsRef = { current: null as WebSocket | null }; + const audioChunksRef = { current: [] as Uint8Array[] }; + const mediaSourceRef = { current: null as MediaSource | null }; + const sourceBufferRef = { current: null as SourceBuffer | null }; + const isStreamingPlaybackRef = { current: false }; + const pendingChunksRef = { current: [] as Uint8Array[] }; + + // Play audio (main entry) + const playAudio = async (text: string, onStatusChange?: (status: typeof chatConfig.ttsStatus[keyof typeof chatConfig.ttsStatus]) => void): Promise => { + if (!text) return; + + try { + onStatusChange?.(chatConfig.ttsStatus.GENERATING); + audioChunksRef.current = []; + pendingChunksRef.current = []; + + if (!window.MediaSource) { + await playAudioTraditional(text, onStatusChange); + return; + } + + await initStreamingPlayback(onStatusChange); + + const wsUrl = getWebSocketUrl(API_ENDPOINTS.tts.ws); + const ws = new WebSocket(wsUrl); + wsRef.current = ws; + + ws.onopen = () => { + if (ws.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify({ text })); + } + }; + + ws.onmessage = async (event) => { + try { + if (event.data instanceof Blob) { + const arrayBuffer = await event.data.arrayBuffer(); + const uint8Array = new Uint8Array(arrayBuffer); + if (uint8Array.length > 0) { + if (isStreamingPlaybackRef.current) { + await handleStreamingAudioChunk(uint8Array, onStatusChange); + } else { + audioChunksRef.current.push(uint8Array); + } + } + } else if (event.data instanceof ArrayBuffer) { + const uint8Array = new Uint8Array(event.data); + if (uint8Array.length > 0) { + if (isStreamingPlaybackRef.current) { + await handleStreamingAudioChunk(uint8Array, onStatusChange); + } else { + audioChunksRef.current.push(uint8Array); + } + } + } else if (typeof event.data === 'string') { + try { + const data = JSON.parse(event.data); + if (data.status === 'completed') { + if (isStreamingPlaybackRef.current) { + await finalizeStreamingPlayback(); + } else { + if (audioChunksRef.current.length > 0) { + playAudioChunks(onStatusChange); + } else { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + } + } + + setTimeout(() => { + if (wsRef.current) { + wsRef.current.close(); + wsRef.current = null; + } + }, 100); + } else if (data.error) { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + cleanupStreamingPlayback(); + if (wsRef.current) { + wsRef.current.close(); + wsRef.current = null; + } + } + } catch (e) { + // JSON parse error + } + } + } catch (error) { + // Message handling error + } + }; + + ws.onerror = () => { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + cleanupStreamingPlayback(); + }; + + ws.onclose = (event) => { + wsRef.current = null; + if (event.code !== 1000) { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + cleanupStreamingPlayback(); + } + }; + + } catch (error) { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + cleanupStreamingPlayback(); + } + }; + + // Initialize streaming playback + const initStreamingPlayback = async (onStatusChange?: (status: typeof chatConfig.ttsStatus[keyof typeof chatConfig.ttsStatus]) => void): Promise => { + return new Promise((resolve, reject) => { + try { + const mediaSource = new MediaSource(); + mediaSourceRef.current = mediaSource; + + if (audioRef.current) { + audioRef.current.pause(); + audioRef.current = null; + } + + const audio = new Audio(); + audio.src = URL.createObjectURL(mediaSource); + audioRef.current = audio; + + audio.oncanplay = () => { + onStatusChange?.('playing'); + }; + + audio.onended = () => { + onStatusChange?.('idle'); + cleanupStreamingPlayback(); + }; + + audio.onerror = () => { + onStatusChange?.('error'); + setTimeout(() => onStatusChange?.('idle'), 2000); + cleanupStreamingPlayback(); + }; + + mediaSource.addEventListener('sourceopen', () => { + try { + const sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg'); + sourceBufferRef.current = sourceBuffer; + + sourceBuffer.addEventListener('updateend', () => { + processPendingChunks(); + }); + + sourceBuffer.addEventListener('error', () => { + onStatusChange?.('error'); + setTimeout(() => onStatusChange?.('idle'), 2000); + }); + + isStreamingPlaybackRef.current = true; + resolve(); + + } catch (error) { + reject(error); + } + }); + + mediaSource.addEventListener('sourceclose', () => { + isStreamingPlaybackRef.current = false; + }); + + mediaSource.addEventListener('error', (e) => { + reject(e); + }); + + } catch (error) { + reject(error); + } + }); + }; + + // Process streaming audio chunks + const handleStreamingAudioChunk = async (chunk: Uint8Array, onStatusChange?: (status: typeof chatConfig.ttsStatus[keyof typeof chatConfig.ttsStatus]) => void) => { + if (!isStreamingPlaybackRef.current || !sourceBufferRef.current) { + pendingChunksRef.current.push(chunk); + return; + } + + try { + if (sourceBufferRef.current.updating) { + pendingChunksRef.current.push(chunk); + } else { + sourceBufferRef.current.appendBuffer(chunk.buffer.slice(0) as ArrayBuffer); + + if (audioRef.current && audioRef.current.paused && audioRef.current.readyState >= 2) { + try { + await audioRef.current.play(); + onStatusChange?.('playing'); + } catch (playError) { + // Auto-play failed + } + } + } + } catch (error) { + cleanupStreamingPlayback(); + audioChunksRef.current.push(chunk); + audioChunksRef.current.push(...pendingChunksRef.current); + pendingChunksRef.current = []; + isStreamingPlaybackRef.current = false; + } + }; + + // Process pending audio chunks + const processPendingChunks = () => { + if (!sourceBufferRef.current || sourceBufferRef.current.updating || pendingChunksRef.current.length === 0) { + return; + } + + try { + const chunk = pendingChunksRef.current.shift(); + if (chunk) { + sourceBufferRef.current.appendBuffer(chunk.buffer.slice(0) as ArrayBuffer); + } + } catch (error) { + // Processing error + } + }; + + // Complete streaming playback + const finalizeStreamingPlayback = async () => { + if (pendingChunksRef.current.length > 0 && sourceBufferRef.current) { + const waitForPending = () => { + return new Promise((resolve) => { + const checkPending = () => { + if (pendingChunksRef.current.length === 0 || !sourceBufferRef.current?.updating) { + resolve(); + } else { + setTimeout(checkPending, 100); + } + }; + checkPending(); + }); + }; + + await waitForPending(); + } + + if (mediaSourceRef.current && mediaSourceRef.current.readyState === 'open') { + try { + mediaSourceRef.current.endOfStream(); + } catch (error) { + // End stream error + } + } + }; + + // Clean up streaming playback resources + const cleanupStreamingPlayback = () => { + isStreamingPlaybackRef.current = false; + pendingChunksRef.current = []; + + if (sourceBufferRef.current) { + sourceBufferRef.current = null; + } + + if (mediaSourceRef.current) { + try { + if (mediaSourceRef.current.readyState === 'open') { + mediaSourceRef.current.endOfStream(); + } + } catch (error) { + // Already closed + } + mediaSourceRef.current = null; + } + + if (audioRef.current && audioRef.current.src.startsWith('blob:')) { + URL.revokeObjectURL(audioRef.current.src); + } + }; + + // Traditional playback method + const playAudioTraditional = async (text: string, onStatusChange?: (status: typeof chatConfig.ttsStatus[keyof typeof chatConfig.ttsStatus]) => void) => { + audioChunksRef.current = []; + const wsUrl = getWebSocketUrl(API_ENDPOINTS.tts.ws); + const ws = new WebSocket(wsUrl); + wsRef.current = ws; + + ws.onopen = () => { + if (ws.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify({ text })); + } + }; + + ws.onmessage = async (event) => { + try { + if (event.data instanceof Blob) { + const arrayBuffer = await event.data.arrayBuffer(); + const uint8Array = new Uint8Array(arrayBuffer); + if (uint8Array.length > 0) { + audioChunksRef.current.push(uint8Array); + } + } else if (event.data instanceof ArrayBuffer) { + const uint8Array = new Uint8Array(event.data); + if (uint8Array.length > 0) { + audioChunksRef.current.push(uint8Array); + } + } else if (typeof event.data === 'string') { + try { + const data = JSON.parse(event.data); + if (data.status === 'completed') { + setTimeout(() => { + if (wsRef.current) { + wsRef.current.close(); + wsRef.current = null; + } + }, 100); + + if (audioChunksRef.current.length > 0) { + playAudioChunks(onStatusChange); + } else { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + } + } else if (data.error) { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + if (wsRef.current) { + wsRef.current.close(); + wsRef.current = null; + } + } + } catch (e) { + // Parse error + } + } + } catch (error) { + // Message error + } + }; + + ws.onerror = () => { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + }; + + ws.onclose = () => { + wsRef.current = null; + }; + }; + + // Play audio chunks (traditional mode) + const playAudioChunks = (onStatusChange?: (status: typeof chatConfig.ttsStatus[keyof typeof chatConfig.ttsStatus]) => void) => { + if (audioChunksRef.current.length === 0) { + onStatusChange?.('idle'); + return; + } + + try { + const validChunks = audioChunksRef.current.filter(chunk => chunk && chunk.length > 0); + + if (validChunks.length === 0) { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + return; + } + + const chunkHashes = new Set(); + const uniqueChunks = []; + + for (let i = 0; i < validChunks.length; i++) { + const chunk = validChunks[i]; + const hashData = chunk.length > 32 ? + Array.from(chunk.slice(0, 16)).concat(Array.from(chunk.slice(-16))) : + Array.from(chunk); + const hash = hashData.join(','); + + if (!chunkHashes.has(hash)) { + chunkHashes.add(hash); + uniqueChunks.push(chunk); + } + } + + const totalLength = uniqueChunks.reduce((sum, chunk) => sum + chunk.length, 0); + const combinedArray = new Uint8Array(totalLength); + let offset = 0; + + for (let i = 0; i < uniqueChunks.length; i++) { + const chunk = uniqueChunks[i]; + + if (offset + chunk.length > totalLength) { + continue; + } + + combinedArray.set(chunk, offset); + offset += chunk.length; + } + + const finalArray = offset === totalLength ? combinedArray : combinedArray.slice(0, offset); + + if (finalArray.length < 100) { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + return; + } + + const hasValidMP3Header = finalArray.length >= 3 && ( + (finalArray[0] === 0xFF && (finalArray[1] & 0xE0) === 0xE0) || + (finalArray[0] === 0x49 && finalArray[1] === 0x44 && finalArray[2] === 0x33) + ); + + if (!hasValidMP3Header) { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + return; + } + + const audioBlob = new Blob([finalArray], { type: 'audio/mpeg' }); + const audioUrl = URL.createObjectURL(audioBlob); + + if (audioRef.current) { + audioRef.current.pause(); + audioRef.current = null; + } + + const audio = new Audio(audioUrl); + audioRef.current = audio; + + audio.oncanplay = () => { + onStatusChange?.('playing'); + }; + + audio.onended = () => { + onStatusChange?.(chatConfig.ttsStatus.IDLE); + URL.revokeObjectURL(audioUrl); + audioRef.current = null; + audioChunksRef.current = []; + }; + + audio.onerror = () => { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + URL.revokeObjectURL(audioUrl); + audioRef.current = null; + audioChunksRef.current = []; + }; + + audio.play().then(() => { + onStatusChange?.('playing'); + }).catch(() => { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + URL.revokeObjectURL(audioUrl); + audioChunksRef.current = []; + }); + + } catch (error) { + onStatusChange?.(chatConfig.ttsStatus.ERROR); + setTimeout(() => onStatusChange?.(chatConfig.ttsStatus.IDLE), 2000); + audioChunksRef.current = []; + } + }; + + // stop audio + const stopAudio = () => { + if (wsRef.current) { + wsRef.current.close(); + wsRef.current = null; + } + + if (audioRef.current) { + audioRef.current.pause(); + audioRef.current = null; + } + + cleanupStreamingPlayback(); + audioChunksRef.current = []; + }; + + // clean up resources + const cleanup = () => { + stopAudio(); + cleanupStreamingPlayback(); + }; + + return { + playAudio, + stopAudio, + cleanup + }; + } + }, + + // Add file preprocess method + async preprocessFiles(query: string, files: File[], conversationId?: number, signal?: AbortSignal): Promise> { + try { + // Use FormData to handle file upload + const formData = new FormData(); + formData.append('query', query); + + // Add files + if (files && files.length > 0) { + files.forEach(file => { + formData.append('files', file); + }); + } + + // Build URL with conversation_id as query parameter + let url = API_ENDPOINTS.storage.preprocess; + if (conversationId !== undefined && conversationId !== null) { + url += `?conversation_id=${conversationId}`; + } + + const response = await fetch(url, { + method: 'POST', + body: formData, + signal, + }); + + // Check if the response is successful + if (!response.ok) { + // Handle specific HTTP status codes with error codes for internationalization + if (response.status === 413) { + throw new Error('REQUEST_ENTITY_TOO_LARGE'); + } else { + throw new Error('FILE_PARSING_FAILED'); + + } + } + + if (!response.body) { + throw new Error("Response body is null"); + } + + return response.body.getReader(); + } catch (error) { + // If the error is caused by canceling the request, return a specific response instead of throwing an error + if (error instanceof Error && error.name === 'AbortError') { + throw new Error('Request has been aborted'); + } + // Other errors are thrown normally + throw error; + } + }, + + // Add run agent method + async runAgent(params: { + query: string; + conversation_id: number; + is_set: boolean; + history: Array<{ role: string; content: string; }>; + files?: File[]; // Add optional files parameter + minio_files?: Array<{ + object_name: string; + name: string; + type: string; + size: number; + url?: string; + description?: string; // Add file description field + }>; // Update to complete attachment information object array + agent_id?: number; // Add agent_id parameter + is_debug?: boolean; // Add debug mode parameter + }, signal?: AbortSignal) { + try { + // Construct request parameters + const requestParams: any = { + query: params.query, + conversation_id: params.conversation_id, + is_set: params.is_set, + history: params.history, + minio_files: params.minio_files || null, + is_debug: params.is_debug || false, + }; + + // Only include agent_id if it has a value + if (params.agent_id !== undefined && params.agent_id !== null) { + requestParams.agent_id = params.agent_id; + } + + const response = await fetch(API_ENDPOINTS.agent.run, { + method: 'POST', + headers: getAuthHeaders(), + body: JSON.stringify(requestParams), + signal, + }); + + if (!response.body) { + throw new Error("Response body is null"); + } + + return response.body.getReader(); + } catch (error: any) { + // If the error is caused by canceling the request, return a specific response instead of throwing an error + if (error instanceof Error && error.name === 'AbortError') { + log.log('Agent请求已被取消'); + throw new Error('请求已被取消'); + } + // Other errors are thrown normally + throw error; + } + }, + + // Generate conversation title + async generateTitle(params: { + conversation_id: number; + history: Array<{ role: 'user' | 'assistant'; content: string; }>; + }) { + const response = await fetch(API_ENDPOINTS.conversation.generateTitle, { + method: 'POST', + headers: getAuthHeaders(), + body: JSON.stringify(params), + }); + + const data = await response.json(); + + if (data.code === 0) { + return data.data; + } + + throw new ApiError(data.code, data.message); + }, + + // Like/dislike message + async updateOpinion(params: { message_id: number; opinion: 'Y' | 'N' | null }) { + const response = await fetch(API_ENDPOINTS.conversation.opinion, { + method: 'POST', + headers: getAuthHeaders(), + body: JSON.stringify(params), + }); + const data = await response.json(); + if (data.code === 0) { + return true; + } + throw new ApiError(data.code, data.message); + }, + + // Get message_id by conversationId and messageIndex + async getMessageId(conversationId: number, messageIndex: number) { + const response = await fetch(API_ENDPOINTS.conversation.messageId, { + method: 'POST', + headers: getAuthHeaders(), + body: JSON.stringify({ + conversation_id: conversationId, + message_index: messageIndex + }) + }); + + const data = await response.json(); + + if (data.code === 0) { + return data.data; + } + + throw new ApiError(data.code, data.message); + }, +}; \ No newline at end of file diff --git a/pathology-ai/code-changes/frontend/index.ts b/pathology-ai/code-changes/frontend/index.ts new file mode 100644 index 000000000..0deaddfd2 --- /dev/null +++ b/pathology-ai/code-changes/frontend/index.ts @@ -0,0 +1,17 @@ +// Medical Visualization Components +// 医学可视化组件导出 + +export { MedicalKnowledgeGraph } from './MedicalKnowledgeGraph'; +export { DiagnosisFlowChart } from './DiagnosisFlowChart'; +export { MedicalDashboard } from './MedicalDashboard'; +export { MedicalVisualizationPanel } from './MedicalVisualizationPanel'; + +// 新增组件 +export { PathologyImageGallery } from './PathologyImageGallery'; +export type { PathologyImage } from './PathologyImageGallery'; + +export { DiagnosisConfidenceCard } from './DiagnosisConfidenceCard'; +export type { ConfidenceLevel, RiskLevel, EvaluationDimension, DiagnosisConfidenceCardProps } from './DiagnosisConfidenceCard'; + +export { SourceTag, InternalTag, ExternalTag, ConclusionTag, parseSourceTags } from './SourceTag'; +export type { SourceType } from './SourceTag'; diff --git a/pathology-ai/code-changes/frontend/markdownRenderer.tsx b/pathology-ai/code-changes/frontend/markdownRenderer.tsx new file mode 100644 index 000000000..057a908c8 --- /dev/null +++ b/pathology-ai/code-changes/frontend/markdownRenderer.tsx @@ -0,0 +1,1285 @@ +"use client"; + +import React from "react"; +import { useTranslation } from "react-i18next"; +import ReactMarkdown from "react-markdown"; +import remarkGfm from "remark-gfm"; +import remarkMath from "remark-math"; +import rehypeRaw from "rehype-raw"; +import rehypeKatex from "rehype-katex"; +// @ts-ignore +import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; +// @ts-ignore +import { oneLight } from "react-syntax-highlighter/dist/esm/styles/prism"; +import * as TooltipPrimitive from "@radix-ui/react-tooltip"; +import { visit } from "unist-util-visit"; + +import { SearchResult } from "@/types/chat"; +import { resolveS3UrlToDataUrl } from "@/services/storageService"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { CopyButton } from "@/components/ui/copyButton"; +import { Diagram } from "@/components/ui/Diagram"; + +interface MarkdownRendererProps { + content: string; + className?: string; + searchResults?: SearchResult[]; + showDiagramToggle?: boolean; + onCitationHover?: () => void; + enableMultimodal?: boolean; + /** + * When true, resolve s3:// media URLs in markdown into data URLs (base64) + * so that images can still be displayed after page refresh or when + * the original S3 URL is not directly accessible by the browser. + */ + resolveS3Media?: boolean; +} + +// Simple in-memory cache to avoid refetching the same S3 object multiple times +const s3MediaCache = new Map(); +const mediaObjectUrlCache = new Map(); +const mediaObjectUrlPromiseCache = new Map>(); +const S3_MEDIA_SESSION_PREFIX = "s3-media-cache:"; + +const isBrowserEnvironment = typeof window !== "undefined"; + +const getSessionCachedValue = (key: string): string | null => { + if (!isBrowserEnvironment) { + return null; + } + try { + return window.sessionStorage.getItem(key); + } catch { + return null; + } +}; + +const getCachedMediaSrc = (src: string): string | null => { + const cached = s3MediaCache.get(src); + if (cached) { + return cached; + } + const sessionValue = getSessionCachedValue(src); + if (sessionValue) { + s3MediaCache.set(src, sessionValue); + return sessionValue; + } + return null; +}; + +const setCachedMediaSrc = (src: string, value: string) => { + s3MediaCache.set(src, value); + if (!isBrowserEnvironment) { + return; + } + try { + window.sessionStorage.setItem(`${S3_MEDIA_SESSION_PREFIX}${src}`, value); + } catch { + // Ignore storage quota errors silently. + } +}; + +const setCachedObjectUrl = (src: string, objectUrl: string | null) => { + if (!objectUrl) { + return; + } + const existing = mediaObjectUrlCache.get(src); + if (existing && existing !== objectUrl) { + URL.revokeObjectURL(existing); + } + mediaObjectUrlCache.set(src, objectUrl); +}; + +const resolveMediaToObjectUrl = async ( + src: string, + { resolveS3 }: { resolveS3: boolean } +): Promise => { + try { + if (src.startsWith("blob:")) { + return src; + } + + if (src.startsWith("s3://")) { + if (!resolveS3) { + return null; + } + const dataUrl = await resolveS3UrlToDataUrl(src); + if (!dataUrl) { + return null; + } + const response = await fetch(dataUrl); + if (!response.ok) { + return null; + } + const blob = await response.blob(); + return URL.createObjectURL(blob); + } + + if ( + src.startsWith("http://") || + src.startsWith("https://") || + src.startsWith("/api/") || + src.startsWith("/nexent/") || + src.startsWith("/attachments/") || + src.startsWith("/") + ) { + const response = await fetch(src); + if (!response.ok) { + return null; + } + const blob = await response.blob(); + return URL.createObjectURL(blob); + } + + if (src.startsWith("data:")) { + const response = await fetch(src); + if (!response.ok) { + return null; + } + const blob = await response.blob(); + return URL.createObjectURL(blob); + } + + return null; + } catch { + return null; + } +}; + +const usePrefetchedMediaSource = ( + src?: string, + options?: { enable?: boolean; resolveS3?: boolean } +) => { + const shouldPrefetch = + Boolean( + options?.enable && + src && + typeof src === "string" && + !src.startsWith("blob:") && + (src.startsWith("s3://") || + src.startsWith("http://") || + src.startsWith("https://") || + src.startsWith("/")) + ) || false; + + const [resolvedSrc, setResolvedSrc] = React.useState(() => { + if (!src || typeof src !== "string") { + return null; + } + if (!shouldPrefetch) { + return src; + } + return mediaObjectUrlCache.get(src) ?? null; + }); + + React.useEffect(() => { + if (!src || typeof src !== "string") { + setResolvedSrc(null); + return; + } + + if (!shouldPrefetch) { + setResolvedSrc(src); + return; + } + + const cached = mediaObjectUrlCache.get(src); + if (cached) { + setResolvedSrc(cached); + return; + } + + let cancelled = false; + + const promise = + mediaObjectUrlPromiseCache.get(src) ?? + resolveMediaToObjectUrl(src, { + resolveS3: options?.resolveS3 ?? true, + }); + + mediaObjectUrlPromiseCache.set(src, promise); + + promise + .then((objectUrl) => { + if (cancelled) { + return; + } + if (!objectUrl) { + setResolvedSrc(null); + return; + } + setCachedObjectUrl(src, objectUrl); + setResolvedSrc(objectUrl); + }) + .catch(() => { + if (!cancelled) { + setResolvedSrc(null); + } + }) + .finally(() => { + mediaObjectUrlPromiseCache.delete(src); + }); + + return () => { + cancelled = true; + }; + }, [options?.resolveS3, shouldPrefetch, src]); + + return resolvedSrc; +}; + +const useResolvedS3Media = (src?: string, shouldResolve?: boolean) => { + const cachedInitial = + typeof src === "string" && src.startsWith("s3://") + ? getCachedMediaSrc(src) + : null; + const initialValue = + typeof src === "string" + ? !shouldResolve || !src.startsWith("s3://") + ? src + : cachedInitial + : null; + const [resolvedSrc, setResolvedSrc] = React.useState( + initialValue + ); + + React.useEffect(() => { + if (!src || typeof src !== "string") { + setResolvedSrc(null); + return; + } + + if (!shouldResolve || !src.startsWith("s3://")) { + setResolvedSrc(src); + return; + } + + const cached = getCachedMediaSrc(src); + if (cached) { + setResolvedSrc(cached); + return; + } + + let cancelled = false; + + resolveS3UrlToDataUrl(src) + .then((dataUrl) => { + if (cancelled) { + return; + } + if (dataUrl) { + setCachedMediaSrc(src, dataUrl); + setResolvedSrc(dataUrl); + } else { + setResolvedSrc(null); + } + }) + .catch(() => { + if (!cancelled) { + setResolvedSrc(null); + } + }); + + return () => { + cancelled = true; + }; + }, [src, shouldResolve]); + + return resolvedSrc; +}; + +const VIDEO_EXTENSIONS = [".mp4", ".webm", ".ogg", ".mov", ".m4v"]; + +const extractExtension = (value: string): string => { + const normalized = value.split("?")[0].split("#")[0]; + const match = normalized.toLowerCase().match(/\.[a-z0-9]+$/); + return match?.[0] ?? ""; +}; + +const isVideoUrl = (url?: string): boolean => { + if (!url) { + return false; + } + + const trimmed = url.trim(); + if (!trimmed.startsWith("http://") && !trimmed.startsWith("https://")) { + return false; + } + + const extension = extractExtension(trimmed); + return VIDEO_EXTENSIONS.includes(extension); +}; + +// extract block level elements from

+const rehypeUnwrapMedia = () => { + return (tree: any) => { + visit(tree, "element", (node, index, parent) => { + // find

tags containing video or figure + if (node.tagName === "p" && node.children) { + const mediaChildIndex = node.children.findIndex( + (child: any) => + child.tagName === "video" || child.tagName === "figure" + ); + + if (mediaChildIndex !== -1) { + // extract media elements (video/figure) + const mediaChild = node.children.splice(mediaChildIndex, 1)[0]; + + // if

has other content after extraction, keep

; otherwise remove empty

+ if (node.children.length === 0) { + // replace original

node with media element + if (parent && index !== null) { + parent.children[index as number] = { + tagName: "div", + properties: { className: "markdown-media-container" }, + children: [mediaChild], + }; + } + } else { + // if

has other content after extraction, keep

; otherwise remove empty

+ if (parent && index !== null) { + parent.children.splice((index as number) + 1, 0, { + tagName: "div", + properties: { className: "markdown-media-container" }, + children: [mediaChild], + }); + } + } + } + } + }); + }; +}; + +// Get background color for different tool signs +const getBackgroundColor = (toolSign: string) => { + switch (toolSign) { + case "a": + return "#E3F2FD"; // Light blue + case "b": + return "#E8F5E9"; // Light green + case "c": + return "#FFF3E0"; // Light orange + case "d": + return "#F3E5F5"; // Light purple + case "e": + return "#FFEBEE"; // Light red + default: + return "#E5E5E5"; // Default light gray + } +}; + +// ============== 可点击选项组件 (平台特性开发) ============== +// 格式: [btn:选项文字] 会渲染为可点击按钮,点击后自动填入并发送 +const ClickableOption = ({ + text, + onOptionClick, +}: { + text: string; + onOptionClick?: (text: string) => void; +}) => { + const handleClick = () => { + // 触发自定义事件,让输入框监听并自动发送 + const event = new CustomEvent('nexent-option-select', { + detail: { text, autoSend: true }, + bubbles: true, + }); + document.dispatchEvent(event); + + if (onOptionClick) { + onOptionClick(text); + } + }; + + return ( + + ); +}; + +// Replace the original LinkIcon component +const CitationBadge = ({ + toolSign, + citeIndex, +}: { + toolSign: string; + citeIndex: number; +}) => ( + + {citeIndex} + +); + +// Modified HoverableText component +const HoverableText = ({ + text, + searchResults, + onCitationHover, +}: { + text: string; + searchResults?: SearchResult[]; + onCitationHover?: () => void; +}) => { + const [isOpen, setIsOpen] = React.useState(false); + const containerRef = React.useRef(null); + const tooltipRef = React.useRef(null); + const mousePositionRef = React.useRef({ x: 0, y: 0 }); + + // Function to handle multiple consecutive line breaks + const handleConsecutiveNewlines = (text: string) => { + if (!text) return text; + return ( + text + // First, standardize all types of line breaks to \n + .replace(/\r\n/g, "\n") // Windows line breaks + .replace(/\r/g, "\n") // Old Mac line breaks + // Handle consecutive line breaks and whitespace + .replace(/[\n\s]*\n[\n\s]*/g, "\n") // Process whitespace around line breaks + .replace(/^\s+|\s+$/g, "") + ); // Remove leading and trailing whitespace + }; + + // Find corresponding search result + const toolSign = text.charAt(0); + const citeIndex = parseInt(text.slice(1)); + const matchedResult = searchResults?.find( + (result) => result.tool_sign === toolSign && result.cite_index === citeIndex + ); + + // Handle mouse events + React.useEffect(() => { + const container = containerRef.current; + if (!container) return; + + let timeoutId: NodeJS.Timeout | null = null; + let closeTimeoutId: NodeJS.Timeout | null = null; + + // Function to update mouse position + const updateMousePosition = (e: MouseEvent) => { + mousePositionRef.current = { x: e.clientX, y: e.clientY }; + }; + + const handleMouseEnter = () => { + // Clear any existing close timer + if (closeTimeoutId) { + clearTimeout(closeTimeoutId); + closeTimeoutId = null; + } + + if (timeoutId) { + clearTimeout(timeoutId); + } + + // Clear completed conversation indicator when hovering over citation + if (onCitationHover) { + onCitationHover(); + } + + // Delay before showing tooltip to avoid quick hover triggers + timeoutId = setTimeout(() => { + setIsOpen(true); + }, 50); + }; + + const handleMouseLeave = () => { + // Clear open timer + if (timeoutId) { + clearTimeout(timeoutId); + timeoutId = null; + } + + // Delay closing tooltip so user can move to tooltip content + closeTimeoutId = setTimeout(() => { + checkShouldClose(); + }, 100); + }; + + // Function to check if tooltip should be closed + const checkShouldClose = () => { + const tooltipContent = document.querySelector(".z-\\[9999\\]"); + const linkElement = containerRef.current; + + if (!tooltipContent || !linkElement) { + setIsOpen(false); + return; + } + + const tooltipRect = tooltipContent.getBoundingClientRect(); + const linkRect = linkElement.getBoundingClientRect(); + const { x: mouseX, y: mouseY } = mousePositionRef.current; + + // Check if mouse is over tooltip or link icon + const isMouseOverTooltip = + mouseX >= tooltipRect.left && + mouseX <= tooltipRect.right && + mouseY >= tooltipRect.top && + mouseY <= tooltipRect.bottom; + + const isMouseOverLink = + mouseX >= linkRect.left && + mouseX <= linkRect.right && + mouseY >= linkRect.top && + mouseY <= linkRect.bottom; + + // Close tooltip if mouse is neither over tooltip nor link icon + if (!isMouseOverTooltip && !isMouseOverLink) { + setIsOpen(false); + } + }; + + // Add global mouse move event listener to handle movement anywhere + const handleGlobalMouseMove = (e: MouseEvent) => { + // Update mouse position + updateMousePosition(e); + + if (!isOpen) return; + + // Use debounce logic to avoid frequent calculations + if (closeTimeoutId) { + clearTimeout(closeTimeoutId); + } + + closeTimeoutId = setTimeout(() => { + checkShouldClose(); + }, 100); + }; + + // Add event listeners + document.addEventListener("mousemove", handleGlobalMouseMove); + container.addEventListener("mouseenter", handleMouseEnter); + container.addEventListener("mouseleave", handleMouseLeave); + + return () => { + if (timeoutId) { + clearTimeout(timeoutId); + } + if (closeTimeoutId) { + clearTimeout(closeTimeoutId); + } + document.removeEventListener("mousemove", handleGlobalMouseMove); + container.removeEventListener("mouseenter", handleMouseEnter); + container.removeEventListener("mouseleave", handleMouseLeave); + }; + }, [isOpen, onCitationHover]); + + return ( + + + + + + + + + {/* Force Portal to body */} + + +

+ + {matchedResult ? ( + <> + {matchedResult.url && + matchedResult.source_type !== "file" && + !matchedResult.filename ? ( + + {handleConsecutiveNewlines(matchedResult.title)} + + ) : ( +

+ {handleConsecutiveNewlines(matchedResult.title)} +

+ )} +

+ {handleConsecutiveNewlines(matchedResult.text)} +

+ + ) : null} +
+ + + + + + ); +}; + +/** + * Convert LaTeX delimiters to markdown math delimiters + * + * Converts: + * - \( ... \) to $ ... $ + * - \[ ... \] to $$ ... $$ + */ +const convertLatexDelimiters = (content: string): string => { + // Quick check: only process if LaTeX delimiters are present + if (!content.includes('\\(') && !content.includes('\\[')) { + return content; + } + + return ( + content + // Convert \( ... \) to $ ... $ (inline math) + .replace(/\\\(([\s\S]*?)\\\)/g, (_match, inner) => `$${inner}$`) + // Convert \[ ... \] to $$ ... $$ (display math) + .replace(/\\\[([\s\S]*?)\\\]/g, (_match, inner) => `$$${inner}$$\n`) + ); +}; + +// Video component with error handling - defined outside to prevent re-creation on each render +interface VideoWithErrorHandlingProps { + src: string; + alt?: string | null; + props?: React.VideoHTMLAttributes; +} + +const VideoWithErrorHandling: React.FC = React.memo(({ src, alt, props = {} }) => { + const { t } = useTranslation("common"); + const [hasError, setHasError] = React.useState(false); + + if (hasError) { + return ( +
+
+ {t("chatStreamMessage.videoLinkUnavailable", { + defaultValue: "This video link is unavailable", + })} +
+ {alt && ( +
{alt}
+ )} +
+ ); + } + + return ( +
+ + {alt ? ( +
{alt}
+ ) : null} +
+ ); +}, (prevProps, nextProps) => { + // Custom comparison function to prevent unnecessary re-renders + // Only compare src and alt, props object reference may change but content is the same + return prevProps.src === nextProps.src && + prevProps.alt === nextProps.alt; +}); + +VideoWithErrorHandling.displayName = "VideoWithErrorHandling"; + +// Image component with error handling - defined outside to prevent re-creation on each render +interface ImageWithErrorHandlingProps { + src: string; + alt?: string | null; +} + +const ImageWithErrorHandling: React.FC = React.memo(({ src, alt }) => { + const { t } = useTranslation("common"); + const [hasError, setHasError] = React.useState(false); + + if (hasError) { + return ( +
+
+ {t("chatStreamMessage.imageLinkUnavailable", { + defaultValue: "This image link is unavailable", + })} +
+ {alt && ( +
{alt}
+ )} +
+ ); + } + + return ( + {alt setHasError(true)} + /> + ); +}, (prevProps, nextProps) => { + // Custom comparison function to prevent unnecessary re-renders + return prevProps.src === nextProps.src && + prevProps.alt === nextProps.alt; +}); + +ImageWithErrorHandling.displayName = "ImageWithErrorHandling"; + +/** + * Render a code block with syntax highlighting, language label, and copy button + * This is exported for use in other components that need to render code blocks directly + */ +export const CodeBlock: React.FC<{ + codeContent: string; + language?: string; +}> = ({ codeContent, language = "python" }) => { + const { t } = useTranslation("common"); + + const customStyle = { + ...oneLight, + 'pre[class*="language-"]': { + ...oneLight['pre[class*="language-"]'], + background: "#f8f8f8", + borderRadius: "0", + padding: "12px 16px", + margin: "0", + fontSize: "0.875rem", + lineHeight: "1.5", + whiteSpace: "pre-wrap", + wordWrap: "break-word", + wordBreak: "break-word", + overflowWrap: "break-word", + overflow: "auto", + width: "100%", + boxSizing: "border-box", + display: "block", + borderTop: "none", + }, + 'code[class*="language-"]': { + ...oneLight['code[class*="language-"]'], + background: "#f8f8f8", + color: "#333333", + fontSize: "0.875rem", + lineHeight: "1.5", + whiteSpace: "pre-wrap", + wordWrap: "break-word", + wordBreak: "break-word", + overflowWrap: "break-word", + width: "100%", + padding: "0", + display: "block", + }, + }; + + const cleanedContent = codeContent.replace(/^\n+|\n+$/g, ""); + + return ( +
+
+ + {language} + + +
+
+ + {cleanedContent} + +
+
+ ); +}; + +export const MarkdownRenderer: React.FC = ({ + content, + className, + searchResults = [], + showDiagramToggle = true, + onCitationHover, + enableMultimodal = true, + resolveS3Media = false, +}) => { + const { t } = useTranslation("common"); + + // Convert LaTeX delimiters to markdown math delimiters + const processedContent = convertLatexDelimiters(content); + + const renderCodeFallback = (text: string, key?: React.Key) => ( + + {text} + + ); + + const buildMediaFallbackText = (src?: string | null, alt?: string | null) => { + if (alt) { + return `${t("chatStreamMessage.imageTextFallbackTitle", { + defaultValue: "Media (text view)", + })}: ${alt}${src ? ` - ${src}` : ""}`; + } + return ( + src ?? + t("chatStreamMessage.imageTextFallbackTitle", { + defaultValue: "Media (text view)", + }) + ); + }; + + const renderMediaFallback = (src?: string | null, alt?: string | null) => + renderCodeFallback(buildMediaFallbackText(src, alt)); + + const renderVideoElement = ({ + src, + alt, + props = {}, + }: { + src?: string | null; + alt?: string | null; + props?: React.VideoHTMLAttributes; + }) => { + if (!src) { + return null; + } + + if (!enableMultimodal) { + return renderMediaFallback(src, alt); + } + + return ; + }; + + const ImageResolver: React.FC<{ src?: string; alt?: string | null }> = ({ + src, + alt, + }) => { + const resolvedSrc = useResolvedS3Media( + typeof src === "string" ? src : undefined, + resolveS3Media + ); + + if (!enableMultimodal) { + return renderMediaFallback(src, alt); + } + + if (!resolvedSrc) { + return renderMediaFallback(src, alt); + } + + if (isVideoUrl(resolvedSrc)) { + return renderVideoElement({ src: resolvedSrc, alt }); + } + + return ; + }; + + // Modified processText function logic + // 支持格式: [[引用]], :mermaid[图表], [btn:可点击选项] + const processText = (text: string) => { + if (typeof text !== "string") return text; + + // 添加 [btn:选项] 格式的匹配 + const parts = text.split(/(\[\[[^\]]+\]\]|:mermaid\[[^\]]+\]|\[btn:[^\]]+\])/g); + return ( + <> + {parts.map((part, index) => { + // 匹配 [btn:选项] 格式 - 可点击选项 + const optionMatch = part.match(/^\[btn:([^\]]+)\]$/); + if (optionMatch) { + const optionText = optionMatch[1]; + return ( + + ); + } + + const match = part.match(/^\[\[([^\]]+)\]\]$/); + if (match) { + const innerText = match[1]; + + const toolSign = innerText.charAt(0); + const citeIndex = parseInt(innerText.slice(1)); + const hasMatch = searchResults?.some( + (result) => + result.tool_sign === toolSign && result.cite_index === citeIndex + ); + + // Only show citation icon when matching search result is found + if (hasMatch) { + return ( + + ); + } else { + // Return empty string if no matching result found (display nothing) + return ""; + } + } + // Inline Mermaid using :mermaid[graph LR; A-->B] - removed inline support + const mmd = part.match(/^:mermaid\[([^\]]+)\]$/); + if (mmd) { + const code = mmd[1]; + if (!enableMultimodal) { + return renderCodeFallback(code, `mmd-placeholder-${index}`); + } + return ; + } + // Handle line breaks in text content + if (part.includes('\n')) { + return part.split('\n').map((line, lineIndex) => ( + + {line} + {lineIndex < part.split('\n').length - 1 &&
} +
+ )); + } + return part; + })} + + ); + }; + + // Create wrapper component to handle different types of child elements + const TextWrapper = ({ children }: { children: any }) => { + if (typeof children === "string") { + return processText(children); + } + if (Array.isArray(children)) { + return ( + <> + {children.map((child, index) => { + if (typeof child === "string") { + return ( + + {processText(child)} + + ); + } + return child; + })} + + ); + } + return children; + }; + + class MarkdownErrorBoundary extends React.Component< + { children: React.ReactNode; rawContent: string }, + { hasError: boolean } + > { + constructor(props: { children: React.ReactNode; rawContent: string }) { + super(props); + this.state = { hasError: false }; + } + static getDerivedStateFromError() { + return { hasError: true }; + } + componentDidCatch(error: unknown) {} + render() { + if (this.state.hasError) { + return ( +
+
+              {this.props.rawContent}
+            
+
+ ); + } + return this.props.children as React.ReactElement; + } + } + + return ( + <> +
+ + ( +

+ {children} +

+ ), + h2: ({ children }: any) => ( +

+ {children} +

+ ), + h3: ({ children }: any) => ( +

+ {children} +

+ ), + h4: ({ children }: any) => ( +

+ {children} +

+ ), + h5: ({ children }: any) => ( +
+ {children} +
+ ), + h6: ({ children }: any) => ( +
+ {children} +
+ ), + // Paragraph + p: ({ children }: any) => ( +

+ {children} +

+ ), + // Horizontal rule + hr: () => ( +
+ ), + // Ordered list + ol: ({ children }: any) => ( +
    + {children} +
+ ), + // Unordered list + ul: ({ children }: any) => ( +
    + {children} +
+ ), + // List item + li: ({ children }: any) => ( +
  • + {children} +
  • + ), + // Blockquote + blockquote: ({ children }: any) => ( +
    + {children} +
    + ), + // Table components + td: ({ children }: any) => ( + + {children} + + ), + th: ({ children }: any) => ( + + {children} + + ), + // Emphasis components + strong: ({ children }: any) => ( + + {children} + + ), + em: ({ children }: any) => ( + + {children} + + ), + // Strikethrough + del: ({ children }: any) => ( + + {children} + + ), + // Link + a: ({ href, children, ...props }: any) => { + return ( + + {children} + + ); + }, + pre: ({ children }: any) => <>{children}, + // Code blocks and inline code + code({ node, inline, className, children, ...props }: any) { + try { + const match = /language-(\w+)/.exec(className || ""); + const raw = Array.isArray(children) + ? children.join("") + : children ?? ""; + const codeContent = String(raw).replace(/^\n+|\n+$/g, ""); + if (match && match[1]) { + // Check if it's a Mermaid diagram + if (match[1] === "mermaid") { + if (!enableMultimodal) { + return renderCodeFallback(codeContent); + } + return ; + } + if (!inline) { + return ; + } + } + } catch (error) { + // Handle error silently + } + return ( + + {children} + + ); + }, + // Image + img: ({ src, alt }: any) => ( + + ), + // Video + video: ({ children, ...props }: any) => { + const directSrc = props?.src; + const childSource = React.Children.toArray(children) + .map((child) => + React.isValidElement(child) ? child.props?.src : undefined + ) + .find(Boolean); + const videoSrc = directSrc ?? childSource; + const caption = + props?.["aria-label"] ?? + props?.title ?? + props?.["data-caption"] ?? + undefined; + + const element = renderVideoElement({ + src: videoSrc, + alt: caption, + props, + }); + + return element ?? renderMediaFallback(undefined, caption); + }, + }} + > + {processedContent} +
    +
    +
    + + ); +}; \ No newline at end of file diff --git a/pathology-ai/code-changes/medical_extension/__init__.py b/pathology-ai/code-changes/medical_extension/__init__.py new file mode 100644 index 000000000..661fbafeb --- /dev/null +++ b/pathology-ai/code-changes/medical_extension/__init__.py @@ -0,0 +1,52 @@ +""" +Nexent 医疗领域扩展模块 +Medical Domain Extension for Nexent Platform + +本模块提供医疗领域的智能体模板、诊断推理链框架和专业工具集。 + +Features: +- 医疗智能体模板系统 +- Chain-of-Diagnosis (CoD) 诊断推理链框架 +- 置信度评估系统 +- 医疗提示词库 + +Author: Pathology AI Team +Version: 1.0.0 +License: MIT +""" + +from .agent_templates import MedicalAgentTemplates, AgentTemplate, MedicalDomain +from .chain_of_diagnosis import ( + ChainOfDiagnosis, + DiagnosisResult, + DiagnosisStep, + ConfidenceLevel, +) +from .confidence_evaluator import ( + ConfidenceEvaluator, + ConfidenceReport, + RiskLevel, +) +from .medical_prompts import MedicalPromptLibrary, PromptCategory + +__all__ = [ + # 智能体模板 + 'MedicalAgentTemplates', + 'AgentTemplate', + 'MedicalDomain', + # 诊断推理链 + 'ChainOfDiagnosis', + 'DiagnosisResult', + 'DiagnosisStep', + 'ConfidenceLevel', + # 置信度评估 + 'ConfidenceEvaluator', + 'ConfidenceReport', + 'RiskLevel', + # 提示词库 + 'MedicalPromptLibrary', + 'PromptCategory', +] + +__version__ = '1.0.0' +__author__ = 'Pathology AI Team' diff --git a/pathology-ai/code-changes/medical_extension/agent_templates.py b/pathology-ai/code-changes/medical_extension/agent_templates.py new file mode 100644 index 000000000..1ccb3f8e2 --- /dev/null +++ b/pathology-ai/code-changes/medical_extension/agent_templates.py @@ -0,0 +1,433 @@ +""" +医疗智能体模板系统 +Medical Agent Templates for Nexent Platform + +提供预置的医疗领域智能体模板,支持一键创建专业医疗智能体。 + +Templates: +- 病理诊断助手 +- 影像分析助手 +- 临床决策支持 +- 药物咨询助手 + +Author: Pathology AI Team +""" + +from dataclasses import dataclass, field +from typing import List, Dict, Optional, Any +from enum import Enum +import json + + +class MedicalDomain(Enum): + """医疗领域分类""" + PATHOLOGY = "pathology" # 病理学 + RADIOLOGY = "radiology" # 放射学/影像 + CLINICAL = "clinical" # 临床医学 + PHARMACY = "pharmacy" # 药学 + LABORATORY = "laboratory" # 检验医学 + GENERAL = "general" # 通用医学 + + +@dataclass +class AgentTemplate: + """智能体模板""" + template_id: str # 模板ID + name: str # 模板名称 + description: str # 描述 + domain: MedicalDomain # 医疗领域 + system_prompt: str # 系统提示词 + suggested_tools: List[str] # 建议的MCP工具 + knowledge_bases: List[str] # 建议的知识库 + model_requirements: Dict[str, Any] = field(default_factory=dict) # 模型要求 + metadata: Dict[str, Any] = field(default_factory=dict) + + def to_dict(self) -> Dict: + """转换为字典""" + return { + "template_id": self.template_id, + "name": self.name, + "description": self.description, + "domain": self.domain.value, + "system_prompt": self.system_prompt, + "suggested_tools": self.suggested_tools, + "knowledge_bases": self.knowledge_bases, + "model_requirements": self.model_requirements, + "metadata": self.metadata, + } + + def to_json(self) -> str: + """转换为JSON""" + return json.dumps(self.to_dict(), ensure_ascii=False, indent=2) + + +class MedicalAgentTemplates: + """ + 医疗智能体模板管理器 + + 提供预置的医疗领域智能体模板,支持: + 1. 获取模板列表 + 2. 按领域筛选 + 3. 创建自定义模板 + 4. 导出/导入模板 + + Usage: + templates = MedicalAgentTemplates() + pathology_template = templates.get_template("pathology_diagnosis") + all_templates = templates.list_templates() + """ + + def __init__(self): + """初始化模板管理器""" + self._templates: Dict[str, AgentTemplate] = {} + self._load_builtin_templates() + + def _load_builtin_templates(self): + """加载内置模板""" + + # 1. 病理诊断助手模板 + self._templates["pathology_diagnosis"] = AgentTemplate( + template_id="pathology_diagnosis", + name="病理诊断助手", + description="专业的病理学诊断辅助智能体,支持组织病理分析、细胞学诊断和分子病理解读", + domain=MedicalDomain.PATHOLOGY, + system_prompt=self._get_pathology_prompt(), + suggested_tools=[ + "pathology_diagnosis_assistant", + "pathology_image_analyzer", + "differential_diagnosis_generator", + "knowledge_graph_query", + ], + knowledge_bases=["病理学知识库", "肿瘤病理数据库"], + model_requirements={ + "min_context_length": 4096, + "recommended_models": ["glm-4.5", "gpt-4o", "claude-4-sonnet"], + "supports_vision": True, + }, + metadata={ + "version": "1.0.0", + "author": "Pathology AI Team", + "tags": ["病理", "诊断", "HIV/AIDS", "肿瘤"], + } + ) + + # 2. 影像分析助手模板 + self._templates["radiology_assistant"] = AgentTemplate( + template_id="radiology_assistant", + name="医学影像分析助手", + description="专业的医学影像分析智能体,支持X光、CT、MRI等影像的智能解读", + domain=MedicalDomain.RADIOLOGY, + system_prompt=self._get_radiology_prompt(), + suggested_tools=[ + "pathology_image_analyzer", + "differential_diagnosis_generator", + ], + knowledge_bases=["影像学知识库"], + model_requirements={ + "min_context_length": 4096, + "recommended_models": ["gpt-4o", "gemini-3-pro"], + "supports_vision": True, # 必须支持视觉 + }, + metadata={ + "version": "1.0.0", + "tags": ["影像", "CT", "MRI", "X光"], + } + ) + + # 3. 临床决策支持模板 + self._templates["clinical_decision"] = AgentTemplate( + template_id="clinical_decision", + name="临床决策支持助手", + description="临床决策支持智能体,提供诊断建议、治疗方案和用药指导", + domain=MedicalDomain.CLINICAL, + system_prompt=self._get_clinical_prompt(), + suggested_tools=[ + "pathology_diagnosis_assistant", + "differential_diagnosis_generator", + "knowledge_graph_query", + ], + knowledge_bases=["临床指南库", "药物数据库"], + model_requirements={ + "min_context_length": 8192, + "recommended_models": ["glm-4.5", "gpt-4o", "claude-4-opus"], + }, + metadata={ + "version": "1.0.0", + "tags": ["临床", "决策", "治疗", "用药"], + } + ) + + # 4. HIV/AIDS专科助手模板 + self._templates["hiv_specialist"] = AgentTemplate( + template_id="hiv_specialist", + name="HIV/AIDS专科助手", + description="HIV/AIDS专科诊疗智能体,专注于HIV感染的诊断、治疗和机会性感染管理", + domain=MedicalDomain.CLINICAL, + system_prompt=self._get_hiv_specialist_prompt(), + suggested_tools=[ + "pathology_diagnosis_assistant", + "differential_diagnosis_generator", + "knowledge_graph_query", + ], + knowledge_bases=["HIV/AIDS知识库", "机会性感染数据库"], + model_requirements={ + "min_context_length": 4096, + "recommended_models": ["glm-4.5", "gpt-4o"], + }, + metadata={ + "version": "1.0.0", + "tags": ["HIV", "AIDS", "感染", "免疫"], + } + ) + + def _get_pathology_prompt(self) -> str: + """获取病理诊断助手提示词""" + return """你是一位专业的病理学诊断助手,具备以下能力: + +## 专业背景 +- 精通组织病理学、细胞病理学和分子病理学 +- 熟悉WHO肿瘤分类标准 +- 了解HIV/AIDS相关病理改变 + +## 诊断方法 +请使用诊断推理链(Chain-of-Diagnosis, CoD)方法: + +【步骤1 - 症状分析】分析临床表现和病理所见 +【步骤2 - 病史关联】结合既往病史进行分析 +【步骤3 - 鉴别诊断】列出可能的病理诊断 +【步骤4 - 检查建议】建议进一步的病理检查 +【步骤5 - 诊断结论】给出最终诊断和置信度 + +## 置信度标注 +- HIGH (>85%): 诊断依据充分 +- MEDIUM (60-85%): 需要进一步确认 +- LOW (<60%): 信息不足,仅供参考 + +## 重要提醒 +- 病理诊断需结合临床信息综合判断 +- AI诊断仅供参考,最终诊断以病理医师报告为准 +- 遇到疑难病例建议多学科会诊(MDT) +""" + + def _get_radiology_prompt(self) -> str: + """获取影像分析助手提示词""" + return """你是一位专业的医学影像分析助手,具备以下能力: + +## 专业背景 +- 精通X光、CT、MRI、超声等影像解读 +- 熟悉各系统疾病的影像学表现 +- 了解影像学检查的适应症和禁忌症 + +## 分析方法 +1. 系统性观察:按解剖结构逐一分析 +2. 病变描述:位置、大小、形态、密度/信号、边界、强化特点 +3. 鉴别诊断:列出可能的诊断及依据 +4. 建议:进一步检查或临床处理建议 + +## 报告格式 +【影像所见】客观描述影像表现 +【诊断意见】给出诊断及置信度 +【建议】进一步检查或随访建议 + +## 重要提醒 +- 影像诊断需结合临床信息 +- AI分析仅供参考,最终诊断以影像科医师报告为准 +""" + + def _get_clinical_prompt(self) -> str: + """获取临床决策支持提示词""" + return """你是一位临床决策支持助手,为医生提供诊疗建议。 + +## 专业能力 +- 疾病诊断与鉴别诊断 +- 治疗方案制定 +- 用药指导与药物相互作用 +- 临床指南解读 + +## 决策支持流程 +1. 病史采集:了解主诉、现病史、既往史 +2. 体格检查:分析体征 +3. 辅助检查:解读检验和影像结果 +4. 诊断分析:使用CoD方法进行诊断推理 +5. 治疗建议:基于循证医学提供方案 + +## 置信度评估 +- HIGH: 诊断明确,治疗方案标准化 +- MEDIUM: 诊断基本明确,方案需个体化 +- LOW: 诊断不确定,建议进一步检查 + +## 重要提醒 +- 所有建议仅供临床参考 +- 最终决策由主治医师做出 +- 注意患者个体差异和禁忌症 +""" + + def _get_hiv_specialist_prompt(self) -> str: + """获取HIV/AIDS专科助手提示词""" + return """你是一位HIV/AIDS专科诊疗助手,专注于HIV感染的全程管理。 + +## 专业领域 +- HIV感染的诊断与分期 +- 抗逆转录病毒治疗(ART) +- 机会性感染的预防与治疗 +- HIV相关肿瘤 +- 免疫重建炎症综合征(IRIS) + +## 诊断推理(CoD) +【步骤1】分析症状和体征 +【步骤2】评估免疫状态(CD4计数、病毒载量) +【步骤3】鉴别诊断(机会性感染vs其他) +【步骤4】建议检查(病原学、影像学) +【步骤5】诊断结论与置信度 + +## CD4计数与机会性感染风险 +- CD4 < 200: PCP、弓形虫、隐球菌高风险 +- CD4 < 100: CMV、MAC高风险 +- CD4 < 50: 播散性真菌感染高风险 + +## 常见机会性感染 +- 肺孢子虫肺炎(PCP): 干咳、呼吸困难、发热 +- 隐球菌脑膜炎: 头痛、发热、意识改变 +- 结核病: 咳嗽、盗汗、体重下降 +- CMV视网膜炎: 视力下降、飞蚊症 + +## 重要提醒 +- HIV诊疗需要专科医师指导 +- 注意药物相互作用 +- 关注患者心理健康 +- AI建议仅供参考 +""" + + def get_template(self, template_id: str) -> Optional[AgentTemplate]: + """ + 获取指定模板 + + Args: + template_id: 模板ID + + Returns: + AgentTemplate or None + """ + return self._templates.get(template_id) + + def list_templates( + self, + domain: Optional[MedicalDomain] = None + ) -> List[AgentTemplate]: + """ + 列出所有模板 + + Args: + domain: 可选,按领域筛选 + + Returns: + 模板列表 + """ + templates = list(self._templates.values()) + if domain: + templates = [t for t in templates if t.domain == domain] + return templates + + def list_template_ids(self) -> List[str]: + """获取所有模板ID""" + return list(self._templates.keys()) + + def add_template(self, template: AgentTemplate) -> bool: + """ + 添加自定义模板 + + Args: + template: 模板对象 + + Returns: + 是否添加成功 + """ + if template.template_id in self._templates: + return False + self._templates[template.template_id] = template + return True + + def remove_template(self, template_id: str) -> bool: + """ + 移除模板 + + Args: + template_id: 模板ID + + Returns: + 是否移除成功 + """ + if template_id in self._templates: + del self._templates[template_id] + return True + return False + + def export_templates(self, filepath: str) -> bool: + """ + 导出模板到文件 + + Args: + filepath: 文件路径 + + Returns: + 是否导出成功 + """ + try: + data = { + "version": "1.0.0", + "templates": [t.to_dict() for t in self._templates.values()] + } + with open(filepath, 'w', encoding='utf-8') as f: + json.dump(data, f, ensure_ascii=False, indent=2) + return True + except Exception: + return False + + def import_templates(self, filepath: str) -> int: + """ + 从文件导入模板 + + Args: + filepath: 文件路径 + + Returns: + 导入的模板数量 + """ + try: + with open(filepath, 'r', encoding='utf-8') as f: + data = json.load(f) + + count = 0 + for t_data in data.get("templates", []): + template = AgentTemplate( + template_id=t_data["template_id"], + name=t_data["name"], + description=t_data["description"], + domain=MedicalDomain(t_data["domain"]), + system_prompt=t_data["system_prompt"], + suggested_tools=t_data["suggested_tools"], + knowledge_bases=t_data["knowledge_bases"], + model_requirements=t_data.get("model_requirements", {}), + metadata=t_data.get("metadata", {}), + ) + if self.add_template(template): + count += 1 + return count + except Exception: + return 0 + + def get_template_summary(self) -> str: + """获取模板摘要""" + lines = ["=" * 50, "医疗智能体模板库", "=" * 50, ""] + + for domain in MedicalDomain: + templates = self.list_templates(domain) + if templates: + lines.append(f"【{domain.value.upper()}】") + for t in templates: + lines.append(f" - {t.name} ({t.template_id})") + lines.append(f" {t.description[:50]}...") + lines.append("") + + lines.append(f"共 {len(self._templates)} 个模板") + return "\n".join(lines) diff --git a/pathology-ai/code-changes/medical_extension/api.py b/pathology-ai/code-changes/medical_extension/api.py new file mode 100644 index 000000000..043e9c593 --- /dev/null +++ b/pathology-ai/code-changes/medical_extension/api.py @@ -0,0 +1,332 @@ +""" +医疗模块 API 接口 +Medical Module API for Nexent Platform + +提供RESTful API接口,支持: +1. 智能体模板管理 +2. 诊断推理链调用 +3. 置信度评估 +4. 提示词管理 + +Author: Pathology AI Team +""" + +from fastapi import APIRouter, HTTPException, Query +from pydantic import BaseModel, Field +from typing import List, Dict, Optional, Any + +from .agent_templates import MedicalAgentTemplates, MedicalDomain +from .chain_of_diagnosis import ChainOfDiagnosis, DiagnosisResult +from .confidence_evaluator import ConfidenceEvaluator +from .medical_prompts import MedicalPromptLibrary, PromptCategory + + +# 创建路由 +router = APIRouter(prefix="/medical", tags=["Medical"]) + +# 初始化组件 +templates_manager = MedicalAgentTemplates() +cod_engine = ChainOfDiagnosis() +confidence_evaluator = ConfidenceEvaluator() +prompt_library = MedicalPromptLibrary() + + +# ==================== 请求/响应模型 ==================== + +class DiagnosisRequest(BaseModel): + """诊断请求""" + symptoms: str = Field(..., description="症状描述") + lab_results: Optional[str] = Field(None, description="实验室检查结果") + medical_history: Optional[str] = Field(None, description="既往病史") + imaging_findings: Optional[str] = Field(None, description="影像学发现") + + +class DiagnosisResponse(BaseModel): + """诊断响应""" + success: bool + data: Dict[str, Any] + formatted_report: str + + +class ConfidenceRequest(BaseModel): + """置信度评估请求""" + diagnosis: str = Field(..., description="诊断结果") + symptoms: Optional[List[str]] = Field(None, description="症状列表") + lab_results: Optional[Dict] = Field(None, description="实验室结果") + evidence: Optional[List[str]] = Field(None, description="支持证据") + + +class ConfidenceResponse(BaseModel): + """置信度评估响应""" + success: bool + data: Dict[str, Any] + formatted_report: str + + +class TemplateResponse(BaseModel): + """模板响应""" + success: bool + data: Dict[str, Any] + + +class PromptsResponse(BaseModel): + """提示词响应""" + success: bool + data: List[Dict[str, Any]] + + +# ==================== 智能体模板 API ==================== + +@router.get("/templates", response_model=TemplateResponse) +async def list_templates( + domain: Optional[str] = Query(None, description="按领域筛选") +): + """ + 获取医疗智能体模板列表 + + Args: + domain: 可选,按领域筛选 (pathology/radiology/clinical/pharmacy/laboratory/general) + + Returns: + 模板列表 + """ + try: + domain_enum = MedicalDomain(domain) if domain else None + templates = templates_manager.list_templates(domain_enum) + return TemplateResponse( + success=True, + data={ + "templates": [t.to_dict() for t in templates], + "count": len(templates), + } + ) + except ValueError: + raise HTTPException(status_code=400, detail=f"Invalid domain: {domain}") + + +@router.get("/templates/{template_id}", response_model=TemplateResponse) +async def get_template(template_id: str): + """ + 获取指定模板详情 + + Args: + template_id: 模板ID + + Returns: + 模板详情 + """ + template = templates_manager.get_template(template_id) + if not template: + raise HTTPException(status_code=404, detail=f"Template not found: {template_id}") + + return TemplateResponse( + success=True, + data=template.to_dict() + ) + + +@router.get("/templates/ids/list") +async def list_template_ids(): + """获取所有模板ID列表""" + return { + "success": True, + "template_ids": templates_manager.list_template_ids() + } + + +# ==================== 诊断推理链 API ==================== + +@router.post("/diagnosis/analyze", response_model=DiagnosisResponse) +async def analyze_diagnosis(request: DiagnosisRequest): + """ + 使用诊断推理链(CoD)进行诊断分析 + + Args: + request: 诊断请求,包含症状、检查结果等 + + Returns: + 诊断结果,包含推理链和置信度 + """ + try: + result = cod_engine.analyze( + symptoms=request.symptoms, + lab_results=request.lab_results, + medical_history=request.medical_history, + imaging_findings=request.imaging_findings, + ) + + return DiagnosisResponse( + success=True, + data=result.to_dict(), + formatted_report=result.to_formatted_string() + ) + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + + +@router.get("/diagnosis/cod-prompt") +async def get_cod_prompt(): + """ + 获取CoD诊断推理链提示词模板 + + Returns: + CoD提示词,可用于配置LLM + """ + return { + "success": True, + "prompt": cod_engine.generate_cod_prompt(), + "description": "诊断推理链(Chain-of-Diagnosis)提示词模板" + } + + +# ==================== 置信度评估 API ==================== + +@router.post("/confidence/evaluate", response_model=ConfidenceResponse) +async def evaluate_confidence(request: ConfidenceRequest): + """ + 评估诊断置信度 + + Args: + request: 评估请求,包含诊断和相关信息 + + Returns: + 置信度评估报告 + """ + try: + report = confidence_evaluator.evaluate( + diagnosis=request.diagnosis, + symptoms=request.symptoms, + lab_results=request.lab_results, + evidence=request.evidence, + ) + + return ConfidenceResponse( + success=True, + data=report.to_dict(), + formatted_report=confidence_evaluator.format_report(report) + ) + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + + +# ==================== 提示词库 API ==================== + +@router.get("/prompts", response_model=PromptsResponse) +async def list_prompts( + category: Optional[str] = Query(None, description="按分类筛选") +): + """ + 获取医疗提示词列表 + + Args: + category: 可选,按分类筛选 (diagnosis/treatment/safety/specialty/general) + + Returns: + 提示词列表 + """ + try: + category_enum = PromptCategory(category) if category else None + prompts = prompt_library.list_prompts(category_enum) + + # 简化输出,不包含完整prompt文本 + simplified = [ + { + "id": p["id"], + "name": p["name"], + "category": p["category"].value, + "description": p["description"], + "tags": p["tags"], + } + for p in prompts + ] + + return PromptsResponse( + success=True, + data=simplified + ) + except ValueError: + raise HTTPException(status_code=400, detail=f"Invalid category: {category}") + + +@router.get("/prompts/{prompt_id}") +async def get_prompt(prompt_id: str): + """ + 获取指定提示词详情 + + Args: + prompt_id: 提示词ID + + Returns: + 提示词详情,包含完整文本 + """ + prompt = prompt_library.get_prompt(prompt_id) + if not prompt: + raise HTTPException(status_code=404, detail=f"Prompt not found: {prompt_id}") + + return { + "success": True, + "data": { + "id": prompt["id"], + "name": prompt["name"], + "category": prompt["category"].value, + "description": prompt["description"], + "prompt": prompt["prompt"], + "variables": prompt["variables"], + "tags": prompt["tags"], + } + } + + +@router.get("/prompts/recommended/full") +async def get_recommended_prompt(): + """ + 获取推荐的完整医疗助手提示词 + + Returns: + 推荐提示词,包含CoD、不确定性感知和安全提醒 + """ + return { + "success": True, + "prompt": prompt_library.get_recommended_prompt(), + "description": "推荐的完整医疗助手提示词,包含诊断推理链、置信度标注和安全提醒" + } + + +@router.post("/prompts/combine") +async def combine_prompts(prompt_ids: List[str]): + """ + 组合多个提示词 + + Args: + prompt_ids: 要组合的提示词ID列表 + + Returns: + 组合后的提示词文本 + """ + combined = prompt_library.combine_prompts(prompt_ids) + if not combined: + raise HTTPException(status_code=400, detail="No valid prompts found") + + return { + "success": True, + "combined_prompt": combined, + "source_prompts": prompt_ids + } + + +# ==================== 健康检查 ==================== + +@router.get("/health") +async def health_check(): + """医疗模块健康检查""" + return { + "status": "healthy", + "module": "medical", + "version": "1.0.0", + "components": { + "templates": len(templates_manager.list_template_ids()), + "prompts": len(prompt_library.list_prompt_ids()), + "cod_engine": "ready", + "confidence_evaluator": "ready", + } + } diff --git a/pathology-ai/code-changes/medical_extension/chain_of_diagnosis.py b/pathology-ai/code-changes/medical_extension/chain_of_diagnosis.py new file mode 100644 index 000000000..f1fda65c8 --- /dev/null +++ b/pathology-ai/code-changes/medical_extension/chain_of_diagnosis.py @@ -0,0 +1,542 @@ +""" +Chain-of-Diagnosis (CoD) 诊断推理链框架 +Medical Diagnosis Reasoning Chain Framework + +创新点: +1. 结构化诊断推理流程 +2. 多步骤逻辑推导 +3. 置信度量化评估 +4. 可解释性诊断输出 + +Author: Pathology AI Team +""" + +from dataclasses import dataclass, field +from typing import List, Dict, Optional, Any +from enum import Enum +import json +import re + + +class ConfidenceLevel(Enum): + """置信度等级""" + HIGH = "HIGH" # >85% 高置信度 + MEDIUM = "MEDIUM" # 60-85% 中等置信度 + LOW = "LOW" # <60% 低置信度 + UNCERTAIN = "UNCERTAIN" # 不确定 + + +@dataclass +class DiagnosisStep: + """诊断推理步骤""" + step_name: str # 步骤名称 + content: str # 步骤内容 + evidence: List[str] = field(default_factory=list) # 支持证据 + confidence: float = 0.0 # 步骤置信度 + + +@dataclass +class DiagnosisResult: + """诊断结果""" + primary_diagnosis: str # 主要诊断 + differential_diagnoses: List[str] # 鉴别诊断列表 + confidence_level: ConfidenceLevel # 置信度等级 + confidence_score: float # 置信度分数 (0-1) + reasoning_chain: List[DiagnosisStep] # 推理链 + recommendations: List[str] # 建议 + warnings: List[str] = field(default_factory=list) # 警告信息 + metadata: Dict[str, Any] = field(default_factory=dict) # 元数据 + + def to_dict(self) -> Dict: + """转换为字典""" + return { + "primary_diagnosis": self.primary_diagnosis, + "differential_diagnoses": self.differential_diagnoses, + "confidence_level": self.confidence_level.value, + "confidence_score": self.confidence_score, + "reasoning_chain": [ + { + "step": s.step_name, + "content": s.content, + "evidence": s.evidence, + "confidence": s.confidence + } for s in self.reasoning_chain + ], + "recommendations": self.recommendations, + "warnings": self.warnings, + "metadata": self.metadata + } + + def to_formatted_string(self) -> str: + """生成格式化的诊断报告""" + lines = [] + lines.append("=" * 50) + lines.append("【诊断推理报告】") + lines.append("=" * 50) + + # 推理链 + lines.append("\n📋 诊断推理链:") + for i, step in enumerate(self.reasoning_chain, 1): + lines.append(f"\n[步骤{i}] {step.step_name}") + lines.append(f" {step.content}") + if step.evidence: + lines.append(f" 证据: {', '.join(step.evidence)}") + + # 诊断结论 + lines.append(f"\n🎯 主要诊断: {self.primary_diagnosis}") + + if self.differential_diagnoses: + lines.append(f"\n🔍 鉴别诊断:") + for dd in self.differential_diagnoses: + lines.append(f" - {dd}") + + # 置信度 + confidence_emoji = {"HIGH": "🟢", "MEDIUM": "🟡", "LOW": "🔴", "UNCERTAIN": "⚪"} + lines.append(f"\n📊 置信度: {confidence_emoji.get(self.confidence_level.value, '⚪')} " + f"{self.confidence_level.value} ({self.confidence_score*100:.1f}%)") + + # 建议 + if self.recommendations: + lines.append(f"\n💡 建议:") + for rec in self.recommendations: + lines.append(f" • {rec}") + + # 警告 + if self.warnings: + lines.append(f"\n⚠️ 注意:") + for warn in self.warnings: + lines.append(f" • {warn}") + + lines.append("\n" + "=" * 50) + return "\n".join(lines) + + +class ChainOfDiagnosis: + """ + 诊断推理链 (Chain-of-Diagnosis) 框架 + + 核心创新: + 1. 症状分析 → 2. 病史关联 → 3. 鉴别诊断 → 4. 检查建议 → 5. 诊断结论 + + Usage: + cod = ChainOfDiagnosis() + result = cod.analyze(symptoms, lab_results, history) + print(result.to_formatted_string()) + """ + + # CoD 推理步骤定义 + COD_STEPS = [ + "症状分析", # Step 1: 分析主诉和症状 + "病史关联", # Step 2: 关联既往病史 + "鉴别诊断", # Step 3: 列出可能的诊断 + "检查建议", # Step 4: 建议进一步检查 + "诊断结论", # Step 5: 给出最终诊断 + ] + + # 置信度阈值 + CONFIDENCE_THRESHOLDS = { + "high": 0.85, + "medium": 0.60, + } + + def __init__(self, knowledge_base: Optional[Dict] = None): + """ + 初始化诊断推理链 + + Args: + knowledge_base: 可选的知识库字典 + """ + self.knowledge_base = knowledge_base or {} + self._load_default_knowledge() + + def _load_default_knowledge(self): + """加载默认医学知识库""" + # HIV/AIDS 相关知识 + self.knowledge_base.update({ + "hiv_opportunistic_infections": [ + "肺孢子虫肺炎 (PCP)", + "巨细胞病毒感染 (CMV)", + "隐球菌脑膜炎", + "卡波西肉瘤", + "结核病", + "弓形虫脑病", + ], + "cd4_thresholds": { + "severe_immunodeficiency": 200, + "moderate_immunodeficiency": 350, + "mild_immunodeficiency": 500, + }, + "pcp_symptoms": ["干咳", "呼吸困难", "发热", "低氧血症"], + "pcp_treatment": ["复方磺胺甲噁唑 (TMP-SMX)", "喷他脒", "阿托伐醌"], + }) + + def analyze( + self, + symptoms: str, + lab_results: Optional[str] = None, + medical_history: Optional[str] = None, + imaging_findings: Optional[str] = None, + ) -> DiagnosisResult: + """ + 执行诊断推理链分析 + + Args: + symptoms: 症状描述 + lab_results: 实验室检查结果 + medical_history: 既往病史 + imaging_findings: 影像学发现 + + Returns: + DiagnosisResult: 诊断结果对象 + """ + reasoning_chain = [] + evidence_collected = [] + + # Step 1: 症状分析 + step1 = self._analyze_symptoms(symptoms) + reasoning_chain.append(step1) + evidence_collected.extend(step1.evidence) + + # Step 2: 病史关联 + step2 = self._correlate_history(medical_history, symptoms) + reasoning_chain.append(step2) + evidence_collected.extend(step2.evidence) + + # Step 3: 鉴别诊断 + step3 = self._differential_diagnosis( + symptoms, lab_results, medical_history, imaging_findings + ) + reasoning_chain.append(step3) + + # Step 4: 检查建议 + step4 = self._suggest_examinations(step3.content, lab_results) + reasoning_chain.append(step4) + + # Step 5: 诊断结论 + step5, primary_diagnosis, differentials = self._conclude_diagnosis( + reasoning_chain, lab_results + ) + reasoning_chain.append(step5) + + # 计算置信度 + confidence_score = self._calculate_confidence( + reasoning_chain, evidence_collected, lab_results + ) + confidence_level = self._get_confidence_level(confidence_score) + + # 生成建议 + recommendations = self._generate_recommendations( + primary_diagnosis, confidence_level, lab_results + ) + + # 生成警告 + warnings = self._generate_warnings(confidence_level, primary_diagnosis) + + return DiagnosisResult( + primary_diagnosis=primary_diagnosis, + differential_diagnoses=differentials, + confidence_level=confidence_level, + confidence_score=confidence_score, + reasoning_chain=reasoning_chain, + recommendations=recommendations, + warnings=warnings, + metadata={ + "input_symptoms": symptoms, + "has_lab_results": lab_results is not None, + "has_history": medical_history is not None, + } + ) + + def _analyze_symptoms(self, symptoms: str) -> DiagnosisStep: + """分析症状""" + evidence = [] + analysis = [] + + # 检测关键症状 + symptom_patterns = { + "呼吸系统": ["咳嗽", "干咳", "呼吸困难", "气短", "胸痛"], + "发热相关": ["发热", "发烧", "高热", "低热"], + "神经系统": ["头痛", "意识改变", "抽搐", "视力改变"], + "消化系统": ["腹泻", "恶心", "呕吐", "腹痛"], + "皮肤表现": ["皮疹", "紫色斑块", "溃疡"], + } + + for system, patterns in symptom_patterns.items(): + found = [p for p in patterns if p in symptoms] + if found: + evidence.extend(found) + analysis.append(f"{system}症状: {', '.join(found)}") + + content = "; ".join(analysis) if analysis else "症状信息不足,需要进一步询问" + + return DiagnosisStep( + step_name="症状分析", + content=content, + evidence=evidence, + confidence=0.8 if evidence else 0.3 + ) + + def _correlate_history( + self, history: Optional[str], symptoms: str + ) -> DiagnosisStep: + """关联病史""" + evidence = [] + content = "" + + if history: + # 检测HIV/AIDS相关 + if any(kw in history.lower() for kw in ["hiv", "aids", "艾滋", "免疫缺陷"]): + evidence.append("HIV/AIDS病史") + content = "患者有HIV/AIDS病史,需考虑机会性感染" + + # 检测免疫抑制 + if any(kw in history for kw in ["免疫抑制", "化疗", "器官移植", "激素"]): + evidence.append("免疫抑制状态") + content += ";存在免疫抑制因素" + + if not content: + content = "无特殊病史或病史信息不完整" + + return DiagnosisStep( + step_name="病史关联", + content=content, + evidence=evidence, + confidence=0.7 if evidence else 0.4 + ) + + def _differential_diagnosis( + self, + symptoms: str, + lab_results: Optional[str], + history: Optional[str], + imaging: Optional[str], + ) -> DiagnosisStep: + """生成鉴别诊断""" + differentials = [] + evidence = [] + + # HIV相关机会性感染判断 + is_hiv_related = history and any( + kw in history.lower() for kw in ["hiv", "aids", "艾滋"] + ) + + # 检测CD4计数 + cd4_count = None + if lab_results: + cd4_match = re.search(r'cd4[^\d]*(\d+)', lab_results.lower()) + if cd4_match: + cd4_count = int(cd4_match.group(1)) + evidence.append(f"CD4计数: {cd4_count}") + + # 基于症状和病史生成鉴别诊断 + if is_hiv_related: + if cd4_count and cd4_count < 200: + # 严重免疫缺陷 + if any(s in symptoms for s in ["干咳", "呼吸困难", "发热"]): + differentials.append("肺孢子虫肺炎 (PCP) - 高度怀疑") + differentials.append("细菌性肺炎") + differentials.append("肺结核") + elif any(s in symptoms for s in ["头痛", "意识"]): + differentials.append("隐球菌脑膜炎") + differentials.append("弓形虫脑病") + else: + differentials.append("需要更多信息进行鉴别") + else: + # 非HIV患者 + if any(s in symptoms for s in ["咳嗽", "发热"]): + differentials.append("社区获得性肺炎") + differentials.append("病毒性上呼吸道感染") + differentials.append("支气管炎") + + content = "鉴别诊断: " + ", ".join(differentials) if differentials else "需要更多信息" + + return DiagnosisStep( + step_name="鉴别诊断", + content=content, + evidence=evidence, + confidence=0.75 if differentials else 0.3 + ) + + def _suggest_examinations( + self, differential: str, existing_labs: Optional[str] + ) -> DiagnosisStep: + """建议进一步检查""" + suggestions = [] + + if "PCP" in differential or "肺孢子虫" in differential: + suggestions.extend([ + "诱导痰检查(银染色/免疫荧光)", + "血气分析", + "乳酸脱氢酶 (LDH)", + "胸部CT", + "支气管肺泡灌洗 (BAL)", + ]) + elif "脑膜炎" in differential: + suggestions.extend([ + "腰椎穿刺", + "脑脊液墨汁染色", + "隐球菌抗原检测", + "头颅MRI", + ]) + else: + suggestions.extend([ + "血常规", + "C反应蛋白", + "胸部X线", + ]) + + # 排除已有检查 + if existing_labs: + suggestions = [s for s in suggestions if s.split("(")[0] not in existing_labs] + + content = "建议检查: " + ", ".join(suggestions[:5]) # 最多5项 + + return DiagnosisStep( + step_name="检查建议", + content=content, + evidence=[], + confidence=0.8 + ) + + def _conclude_diagnosis( + self, + reasoning_chain: List[DiagnosisStep], + lab_results: Optional[str], + ) -> tuple: + """得出诊断结论""" + # 从鉴别诊断步骤提取 + differential_step = reasoning_chain[2] # Step 3 + + # 解析鉴别诊断 + differentials = [] + primary = "诊断待定" + + if "高度怀疑" in differential_step.content: + # 提取高度怀疑的诊断作为主诊断 + match = re.search(r'([^,]+)\s*-\s*高度怀疑', differential_step.content) + if match: + primary = match.group(1).strip() + + # 提取所有鉴别诊断 + diff_match = re.search(r'鉴别诊断:\s*(.+)', differential_step.content) + if diff_match: + diff_list = diff_match.group(1).split(", ") + differentials = [d.split(" - ")[0].strip() for d in diff_list if d != primary] + + content = f"综合分析,最可能的诊断为: {primary}" + + step = DiagnosisStep( + step_name="诊断结论", + content=content, + evidence=[s.step_name for s in reasoning_chain if s.confidence > 0.6], + confidence=0.85 if "高度怀疑" in differential_step.content else 0.5 + ) + + return step, primary, differentials + + def _calculate_confidence( + self, + reasoning_chain: List[DiagnosisStep], + evidence: List[str], + lab_results: Optional[str], + ) -> float: + """计算总体置信度""" + # 基础置信度:各步骤置信度加权平均 + weights = [0.15, 0.15, 0.25, 0.15, 0.30] # 诊断结论权重最高 + base_confidence = sum( + step.confidence * weight + for step, weight in zip(reasoning_chain, weights) + ) + + # 证据加成 + evidence_bonus = min(len(evidence) * 0.02, 0.1) + + # 实验室结果加成 + lab_bonus = 0.05 if lab_results else 0 + + total = base_confidence + evidence_bonus + lab_bonus + return min(max(total, 0.0), 1.0) # 限制在0-1之间 + + def _get_confidence_level(self, score: float) -> ConfidenceLevel: + """根据分数获取置信度等级""" + if score >= self.CONFIDENCE_THRESHOLDS["high"]: + return ConfidenceLevel.HIGH + elif score >= self.CONFIDENCE_THRESHOLDS["medium"]: + return ConfidenceLevel.MEDIUM + elif score > 0.3: + return ConfidenceLevel.LOW + else: + return ConfidenceLevel.UNCERTAIN + + def _generate_recommendations( + self, + diagnosis: str, + confidence: ConfidenceLevel, + lab_results: Optional[str], + ) -> List[str]: + """生成治疗建议""" + recommendations = [] + + if "PCP" in diagnosis or "肺孢子虫" in diagnosis: + recommendations.extend([ + "首选治疗: 复方磺胺甲噁唑 (TMP-SMX)", + "替代方案: 喷他脒或阿托伐醌", + "严重病例考虑糖皮质激素辅助治疗", + "监测血氧饱和度", + ]) + + if confidence in [ConfidenceLevel.LOW, ConfidenceLevel.UNCERTAIN]: + recommendations.append("建议进一步检查以明确诊断") + recommendations.append("必要时请专科会诊") + + if not recommendations: + recommendations.append("根据具体情况制定治疗方案") + + return recommendations + + def _generate_warnings( + self, + confidence: ConfidenceLevel, + diagnosis: str, + ) -> List[str]: + """生成警告信息""" + warnings = [] + + if confidence == ConfidenceLevel.LOW: + warnings.append("置信度较低,诊断结果仅供参考") + elif confidence == ConfidenceLevel.UNCERTAIN: + warnings.append("信息不足,无法做出可靠诊断") + + warnings.append("本诊断由AI辅助生成,最终诊断请以临床医生判断为准") + + return warnings + + def generate_cod_prompt(self) -> str: + """ + 生成CoD提示词模板 + 可用于配置LLM的系统提示词 + """ + return """你是一位专业的医学诊断助手,请使用诊断推理链(Chain-of-Diagnosis, CoD)方法进行分析。 + +请按以下步骤进行诊断推理: + +【步骤1 - 症状分析】 +分析患者的主诉和症状,识别关键临床表现。 + +【步骤2 - 病史关联】 +结合既往病史,分析与当前症状的关联性。 + +【步骤3 - 鉴别诊断】 +列出可能的诊断,并说明支持和反对的证据。 + +【步骤4 - 检查建议】 +建议进一步的检查以明确诊断。 + +【步骤5 - 诊断结论】 +给出最可能的诊断,并标注置信度: +- HIGH (高置信度 >85%): 证据充分,诊断明确 +- MEDIUM (中等置信度 60-85%): 有一定依据,但需进一步确认 +- LOW (低置信度 <60%): 信息不足,仅供参考 + +请始终提醒:AI诊断仅供参考,最终诊断请以临床医生判断为准。 +""" diff --git a/pathology-ai/code-changes/medical_extension/confidence_evaluator.py b/pathology-ai/code-changes/medical_extension/confidence_evaluator.py new file mode 100644 index 000000000..5a1f57d6b --- /dev/null +++ b/pathology-ai/code-changes/medical_extension/confidence_evaluator.py @@ -0,0 +1,434 @@ +""" +置信度评估系统 +Confidence Evaluation System for Medical AI + +提供医疗AI回答的置信度评估功能,支持: +1. 基于证据的置信度计算 +2. 不确定性量化 +3. 风险等级评估 + +Author: Pathology AI Team +""" + +from dataclasses import dataclass +from typing import List, Dict, Optional, Tuple +from enum import Enum +import re + + +class RiskLevel(Enum): + """风险等级""" + CRITICAL = "critical" # 危急 + HIGH = "high" # 高风险 + MEDIUM = "medium" # 中等风险 + LOW = "low" # 低风险 + + +@dataclass +class ConfidenceReport: + """置信度评估报告""" + overall_score: float # 总体置信度 (0-1) + confidence_level: str # 置信度等级 (HIGH/MEDIUM/LOW) + evidence_score: float # 证据充分度 + consistency_score: float # 一致性得分 + completeness_score: float # 完整性得分 + risk_level: RiskLevel # 风险等级 + factors: Dict[str, float] # 各因素得分 + recommendations: List[str] # 建议 + warnings: List[str] # 警告 + + def to_dict(self) -> Dict: + return { + "overall_score": self.overall_score, + "confidence_level": self.confidence_level, + "evidence_score": self.evidence_score, + "consistency_score": self.consistency_score, + "completeness_score": self.completeness_score, + "risk_level": self.risk_level.value, + "factors": self.factors, + "recommendations": self.recommendations, + "warnings": self.warnings, + } + + +class ConfidenceEvaluator: + """ + 置信度评估器 + + 评估维度: + 1. 证据充分度:支持诊断的证据数量和质量 + 2. 一致性:症状、检查结果与诊断的一致性 + 3. 完整性:信息的完整程度 + 4. 确定性:诊断的确定程度 + + Usage: + evaluator = ConfidenceEvaluator() + report = evaluator.evaluate( + diagnosis="肺孢子虫肺炎", + symptoms=["干咳", "呼吸困难", "发热"], + lab_results={"CD4": 150, "LDH": "升高"}, + evidence=["HIV阳性", "CD4<200"] + ) + print(f"置信度: {report.confidence_level} ({report.overall_score:.2f})") + """ + + # 置信度阈值 + THRESHOLDS = { + "high": 0.85, + "medium": 0.60, + "low": 0.30, + } + + # 关键证据权重 + EVIDENCE_WEIGHTS = { + "病理确诊": 1.0, + "实验室确诊": 0.9, + "影像学典型表现": 0.8, + "临床症状典型": 0.7, + "病史支持": 0.6, + "经验性诊断": 0.4, + } + + # 高风险诊断关键词 + HIGH_RISK_KEYWORDS = [ + "恶性", "癌", "肿瘤", "转移", "急性", "重症", + "休克", "衰竭", "危重", "紧急", + ] + + def __init__(self): + """初始化评估器""" + self._custom_rules = [] + + def evaluate( + self, + diagnosis: str, + symptoms: Optional[List[str]] = None, + lab_results: Optional[Dict] = None, + imaging_findings: Optional[List[str]] = None, + evidence: Optional[List[str]] = None, + medical_history: Optional[str] = None, + ) -> ConfidenceReport: + """ + 评估诊断置信度 + + Args: + diagnosis: 诊断结果 + symptoms: 症状列表 + lab_results: 实验室结果 + imaging_findings: 影像学发现 + evidence: 支持证据 + medical_history: 病史 + + Returns: + ConfidenceReport: 置信度评估报告 + """ + factors = {} + + # 1. 评估证据充分度 + evidence_score = self._evaluate_evidence(evidence or []) + factors["evidence"] = evidence_score + + # 2. 评估一致性 + consistency_score = self._evaluate_consistency( + diagnosis, symptoms or [], lab_results or {} + ) + factors["consistency"] = consistency_score + + # 3. 评估完整性 + completeness_score = self._evaluate_completeness( + symptoms, lab_results, imaging_findings, medical_history + ) + factors["completeness"] = completeness_score + + # 4. 评估确定性 + certainty_score = self._evaluate_certainty(diagnosis) + factors["certainty"] = certainty_score + + # 计算总体置信度 + overall_score = self._calculate_overall_score(factors) + + # 确定置信度等级 + confidence_level = self._get_confidence_level(overall_score) + + # 评估风险等级 + risk_level = self._evaluate_risk(diagnosis, overall_score) + + # 生成建议 + recommendations = self._generate_recommendations( + confidence_level, factors, diagnosis + ) + + # 生成警告 + warnings = self._generate_warnings( + confidence_level, risk_level, diagnosis + ) + + return ConfidenceReport( + overall_score=overall_score, + confidence_level=confidence_level, + evidence_score=evidence_score, + consistency_score=consistency_score, + completeness_score=completeness_score, + risk_level=risk_level, + factors=factors, + recommendations=recommendations, + warnings=warnings, + ) + + def _evaluate_evidence(self, evidence: List[str]) -> float: + """评估证据充分度""" + if not evidence: + return 0.3 + + score = 0.0 + max_weight = 0.0 + + for e in evidence: + for key, weight in self.EVIDENCE_WEIGHTS.items(): + if key in e or any(k in e for k in key.split()): + score += weight + max_weight = max(max_weight, weight) + break + else: + # 未匹配到预定义证据类型,给基础分 + score += 0.3 + + # 归一化 + normalized = min(score / max(len(evidence), 1) * 0.5 + max_weight * 0.5, 1.0) + return normalized + + def _evaluate_consistency( + self, + diagnosis: str, + symptoms: List[str], + lab_results: Dict, + ) -> float: + """评估一致性""" + score = 0.5 # 基础分 + + # 定义诊断-症状关联 + diagnosis_symptom_map = { + "肺孢子虫肺炎": ["干咳", "呼吸困难", "发热", "低氧"], + "PCP": ["干咳", "呼吸困难", "发热", "低氧"], + "隐球菌脑膜炎": ["头痛", "发热", "意识改变", "颈强直"], + "结核": ["咳嗽", "盗汗", "体重下降", "发热"], + "肺炎": ["咳嗽", "发热", "胸痛", "呼吸困难"], + } + + # 检查症状一致性 + for diag_key, expected_symptoms in diagnosis_symptom_map.items(): + if diag_key in diagnosis: + matched = sum(1 for s in symptoms if any(es in s for es in expected_symptoms)) + if matched > 0: + score += min(matched / len(expected_symptoms) * 0.3, 0.3) + break + + # 检查实验室结果一致性 + if lab_results: + # CD4计数与HIV相关诊断 + cd4 = lab_results.get("CD4") or lab_results.get("cd4") + if cd4 and isinstance(cd4, (int, float)): + if "PCP" in diagnosis or "肺孢子虫" in diagnosis: + if cd4 < 200: + score += 0.2 + elif cd4 < 350: + score += 0.1 + + return min(score, 1.0) + + def _evaluate_completeness( + self, + symptoms: Optional[List[str]], + lab_results: Optional[Dict], + imaging: Optional[List[str]], + history: Optional[str], + ) -> float: + """评估信息完整性""" + score = 0.0 + + # 各项信息的权重 + if symptoms and len(symptoms) > 0: + score += 0.3 + if lab_results and len(lab_results) > 0: + score += 0.3 + if imaging and len(imaging) > 0: + score += 0.2 + if history and len(history) > 10: + score += 0.2 + + return score + + def _evaluate_certainty(self, diagnosis: str) -> float: + """评估诊断确定性""" + # 不确定性关键词 + uncertain_keywords = [ + "可能", "疑似", "待排除", "不除外", "考虑", + "建议进一步", "需要确认", "待定", + ] + + # 确定性关键词 + certain_keywords = [ + "确诊", "明确", "典型", "符合", "诊断明确", + ] + + score = 0.5 # 基础分 + + for kw in uncertain_keywords: + if kw in diagnosis: + score -= 0.1 + + for kw in certain_keywords: + if kw in diagnosis: + score += 0.15 + + return max(min(score, 1.0), 0.1) + + def _calculate_overall_score(self, factors: Dict[str, float]) -> float: + """计算总体置信度""" + weights = { + "evidence": 0.35, + "consistency": 0.25, + "completeness": 0.20, + "certainty": 0.20, + } + + score = sum( + factors.get(k, 0) * w + for k, w in weights.items() + ) + + return round(score, 3) + + def _get_confidence_level(self, score: float) -> str: + """获取置信度等级""" + if score >= self.THRESHOLDS["high"]: + return "HIGH" + elif score >= self.THRESHOLDS["medium"]: + return "MEDIUM" + elif score >= self.THRESHOLDS["low"]: + return "LOW" + else: + return "UNCERTAIN" + + def _evaluate_risk(self, diagnosis: str, confidence: float) -> RiskLevel: + """评估风险等级""" + # 检查高风险关键词 + has_high_risk = any(kw in diagnosis for kw in self.HIGH_RISK_KEYWORDS) + + if has_high_risk and confidence < 0.6: + return RiskLevel.CRITICAL + elif has_high_risk: + return RiskLevel.HIGH + elif confidence < 0.5: + return RiskLevel.MEDIUM + else: + return RiskLevel.LOW + + def _generate_recommendations( + self, + confidence_level: str, + factors: Dict[str, float], + diagnosis: str, + ) -> List[str]: + """生成建议""" + recommendations = [] + + if factors.get("evidence", 0) < 0.5: + recommendations.append("建议补充更多诊断依据") + + if factors.get("completeness", 0) < 0.5: + recommendations.append("建议完善病史和检查资料") + + if confidence_level in ["LOW", "UNCERTAIN"]: + recommendations.append("建议进一步检查以明确诊断") + recommendations.append("必要时请专科会诊") + + if not recommendations: + recommendations.append("诊断依据充分,可按诊断进行治疗") + + return recommendations + + def _generate_warnings( + self, + confidence_level: str, + risk_level: RiskLevel, + diagnosis: str, + ) -> List[str]: + """生成警告""" + warnings = [] + + if risk_level == RiskLevel.CRITICAL: + warnings.append("⚠️ 危急情况:诊断不确定但可能为严重疾病,请立即处理") + + if confidence_level == "UNCERTAIN": + warnings.append("⚠️ 置信度极低,诊断结果仅供参考") + elif confidence_level == "LOW": + warnings.append("⚠️ 置信度较低,建议谨慎采纳") + + warnings.append("本评估由AI生成,最终诊断请以临床医生判断为准") + + return warnings + + def add_custom_rule( + self, + condition: callable, + score_modifier: float, + description: str, + ): + """ + 添加自定义评估规则 + + Args: + condition: 条件函数,接收诊断信息,返回bool + score_modifier: 分数修正值 (-1 到 1) + description: 规则描述 + """ + self._custom_rules.append({ + "condition": condition, + "modifier": score_modifier, + "description": description, + }) + + def format_report(self, report: ConfidenceReport) -> str: + """格式化置信度报告""" + lines = [] + lines.append("=" * 40) + lines.append("【置信度评估报告】") + lines.append("=" * 40) + + # 置信度等级 + level_emoji = { + "HIGH": "🟢", "MEDIUM": "🟡", + "LOW": "🔴", "UNCERTAIN": "⚪" + } + lines.append(f"\n总体置信度: {level_emoji.get(report.confidence_level, '⚪')} " + f"{report.confidence_level} ({report.overall_score*100:.1f}%)") + + # 各维度得分 + lines.append(f"\n📊 评估维度:") + lines.append(f" • 证据充分度: {report.evidence_score*100:.0f}%") + lines.append(f" • 一致性: {report.consistency_score*100:.0f}%") + lines.append(f" • 完整性: {report.completeness_score*100:.0f}%") + + # 风险等级 + risk_emoji = { + "critical": "🔴", "high": "🟠", + "medium": "🟡", "low": "🟢" + } + lines.append(f"\n⚠️ 风险等级: {risk_emoji.get(report.risk_level.value, '⚪')} " + f"{report.risk_level.value.upper()}") + + # 建议 + if report.recommendations: + lines.append(f"\n💡 建议:") + for rec in report.recommendations: + lines.append(f" • {rec}") + + # 警告 + if report.warnings: + lines.append(f"\n⚠️ 警告:") + for warn in report.warnings: + lines.append(f" • {warn}") + + lines.append("\n" + "=" * 40) + return "\n".join(lines) diff --git a/pathology-ai/code-changes/medical_extension/medical_prompts.py b/pathology-ai/code-changes/medical_extension/medical_prompts.py new file mode 100644 index 000000000..6bd81cc5a --- /dev/null +++ b/pathology-ai/code-changes/medical_extension/medical_prompts.py @@ -0,0 +1,514 @@ +""" +医疗提示词库 +Medical Prompt Library for Nexent Platform + +提供预置的医疗领域提示词模板,支持: +1. CoD诊断推理链提示词 +2. 不确定性感知提示词 +3. 专科领域提示词 +4. 安全性提示词 + +Author: Pathology AI Team +""" + +from typing import Dict, List, Optional +from enum import Enum + + +class PromptCategory(Enum): + """提示词分类""" + DIAGNOSIS = "diagnosis" # 诊断类 + TREATMENT = "treatment" # 治疗类 + SAFETY = "safety" # 安全类 + SPECIALTY = "specialty" # 专科类 + GENERAL = "general" # 通用类 + + +class MedicalPromptLibrary: + """ + 医疗提示词库 + + 提供标准化的医疗AI提示词模板,确保: + 1. 诊断推理的结构化 + 2. 不确定性的明确表达 + 3. 安全性提醒 + 4. 专业性保证 + + Usage: + library = MedicalPromptLibrary() + cod_prompt = library.get_prompt("chain_of_diagnosis") + all_prompts = library.list_prompts() + """ + + def __init__(self): + """初始化提示词库""" + self._prompts: Dict[str, Dict] = {} + self._load_builtin_prompts() + + def _load_builtin_prompts(self): + """加载内置提示词""" + + # 1. 诊断推理链 (CoD) 核心提示词 + self._prompts["chain_of_diagnosis"] = { + "id": "chain_of_diagnosis", + "name": "诊断推理链 (CoD)", + "category": PromptCategory.DIAGNOSIS, + "description": "结构化的诊断推理方法,分步骤进行临床分析", + "prompt": self._get_cod_prompt(), + "variables": ["patient_info"], + "tags": ["核心", "诊断", "推理"], + } + + # 2. 不确定性感知提示词 + self._prompts["uncertainty_aware"] = { + "id": "uncertainty_aware", + "name": "不确定性感知", + "category": PromptCategory.SAFETY, + "description": "在回答中明确标注置信度和不确定性", + "prompt": self._get_uncertainty_prompt(), + "variables": [], + "tags": ["安全", "置信度", "不确定性"], + } + + # 3. 安全性基础提示词 + self._prompts["safety_base"] = { + "id": "safety_base", + "name": "医疗安全基础", + "category": PromptCategory.SAFETY, + "description": "医疗AI的基础安全提醒", + "prompt": self._get_safety_prompt(), + "variables": [], + "tags": ["安全", "免责", "基础"], + } + + # 4. HIV/AIDS专科提示词 + self._prompts["hiv_specialist"] = { + "id": "hiv_specialist", + "name": "HIV/AIDS专科", + "category": PromptCategory.SPECIALTY, + "description": "HIV/AIDS诊疗专业提示词", + "prompt": self._get_hiv_prompt(), + "variables": ["cd4_count", "viral_load"], + "tags": ["HIV", "AIDS", "感染", "专科"], + } + + # 5. 病理诊断提示词 + self._prompts["pathology_diagnosis"] = { + "id": "pathology_diagnosis", + "name": "病理诊断", + "category": PromptCategory.SPECIALTY, + "description": "病理学诊断专业提示词", + "prompt": self._get_pathology_prompt(), + "variables": ["specimen_type", "staining_method"], + "tags": ["病理", "诊断", "专科"], + } + + # 6. 鉴别诊断提示词 + self._prompts["differential_diagnosis"] = { + "id": "differential_diagnosis", + "name": "鉴别诊断", + "category": PromptCategory.DIAGNOSIS, + "description": "系统性鉴别诊断方法", + "prompt": self._get_differential_prompt(), + "variables": ["chief_complaint"], + "tags": ["诊断", "鉴别", "系统"], + } + + # 7. 治疗建议提示词 + self._prompts["treatment_suggestion"] = { + "id": "treatment_suggestion", + "name": "治疗建议", + "category": PromptCategory.TREATMENT, + "description": "基于循证医学的治疗建议", + "prompt": self._get_treatment_prompt(), + "variables": ["diagnosis", "patient_condition"], + "tags": ["治疗", "用药", "建议"], + } + + # 8. 完整医疗助手提示词(组合版) + self._prompts["medical_assistant_full"] = { + "id": "medical_assistant_full", + "name": "完整医疗助手", + "category": PromptCategory.GENERAL, + "description": "包含CoD、不确定性感知和安全提醒的完整提示词", + "prompt": self._get_full_assistant_prompt(), + "variables": [], + "tags": ["完整", "推荐", "综合"], + } + + def _get_cod_prompt(self) -> str: + """诊断推理链提示词""" + return """## 诊断推理链 (Chain-of-Diagnosis, CoD) + +请按以下步骤进行诊断推理: + +### 【步骤1 - 症状分析】 +- 识别主诉和主要症状 +- 分析症状的特点(部位、性质、程度、时间) +- 注意伴随症状 + +### 【步骤2 - 病史关联】 +- 既往病史与当前症状的关系 +- 用药史和过敏史 +- 家族史和社会史 + +### 【步骤3 - 鉴别诊断】 +- 列出可能的诊断(按可能性排序) +- 分析支持和反对每个诊断的证据 +- 考虑常见病和危重病 + +### 【步骤4 - 检查建议】 +- 建议必要的实验室检查 +- 建议必要的影像学检查 +- 说明检查目的 + +### 【步骤5 - 诊断结论】 +- 给出最可能的诊断 +- 标注置信度等级 +- 说明诊断依据 +""" + + def _get_uncertainty_prompt(self) -> str: + """不确定性感知提示词""" + return """## 不确定性标注规范 + +在给出诊断或建议时,请标注置信度: + +### 置信度等级 +- **HIGH (高置信度 >85%)** + - 证据充分,诊断明确 + - 符合典型临床表现 + - 有确诊性检查结果支持 + +- **MEDIUM (中等置信度 60-85%)** + - 有一定依据,但需进一步确认 + - 部分符合典型表现 + - 需要排除其他诊断 + +- **LOW (低置信度 <60%)** + - 信息不足,仅供参考 + - 表现不典型 + - 需要更多检查 + +- **UNCERTAIN (不确定)** + - 无法做出可靠判断 + - 信息严重不足 + - 建议进一步检查 + +### 标注格式 +在诊断结论后标注:[置信度: HIGH/MEDIUM/LOW/UNCERTAIN] +""" + + def _get_safety_prompt(self) -> str: + """安全性提示词""" + return """## 医疗安全提醒 + +### 重要声明 +1. 本AI仅提供辅助参考,不能替代专业医生的诊断 +2. 最终诊断和治疗决策应由执业医师做出 +3. 紧急情况请立即就医或拨打急救电话 + +### 使用限制 +- 不提供处方药物的具体剂量 +- 不对危急重症做出延误治疗的建议 +- 不替代必要的医学检查 + +### 免责说明 +AI诊断建议仅供参考,使用者应自行承担相应风险。 +如有疑问,请咨询专业医疗人员。 +""" + + def _get_hiv_prompt(self) -> str: + """HIV/AIDS专科提示词""" + return """## HIV/AIDS诊疗专家 + +### 专业领域 +- HIV感染的诊断与分期 +- 抗逆转录病毒治疗(ART)方案 +- 机会性感染的预防与治疗 +- HIV相关肿瘤 +- 免疫重建炎症综合征(IRIS) + +### CD4计数与感染风险 +| CD4计数 | 风险等级 | 常见机会性感染 | +|---------|----------|----------------| +| <200 | 高风险 | PCP、弓形虫、隐球菌 | +| <100 | 极高风险 | CMV、MAC | +| <50 | 危重 | 播散性真菌感染 | + +### 常见机会性感染诊断要点 +1. **肺孢子虫肺炎(PCP)** + - 症状:干咳、进行性呼吸困难、发热 + - 检查:诱导痰、BAL、LDH升高 + - 治疗:TMP-SMX + +2. **隐球菌脑膜炎** + - 症状:头痛、发热、意识改变 + - 检查:腰穿、墨汁染色、隐球菌抗原 + - 治疗:两性霉素B + 氟康唑 + +3. **结核病** + - 症状:咳嗽、盗汗、体重下降 + - 检查:痰涂片、培养、GeneXpert + - 注意:与ART的药物相互作用 +""" + + def _get_pathology_prompt(self) -> str: + """病理诊断提示词""" + return """## 病理诊断专家 + +### 专业能力 +- 组织病理学诊断 +- 细胞病理学诊断 +- 分子病理学解读 +- 免疫组化分析 + +### 诊断流程 +1. **标本信息**:部位、类型、固定方式 +2. **大体描述**:大小、颜色、质地、切面 +3. **镜下所见**:细胞形态、组织结构、特殊发现 +4. **特殊染色/免疫组化**:结果及意义 +5. **病理诊断**:诊断名称、分级分期 +6. **备注**:建议进一步检查或会诊 + +### HIV相关病理改变 +- 淋巴结:滤泡增生→耗竭 +- 肺:PCP间质性肺炎 +- 皮肤:卡波西肉瘤 +- 脑:弓形虫脑病、PML + +### 报告规范 +- 使用标准化术语 +- 明确诊断依据 +- 标注置信度 +- 必要时建议会诊 +""" + + def _get_differential_prompt(self) -> str: + """鉴别诊断提示词""" + return """## 鉴别诊断方法 + +### 系统性鉴别诊断步骤 + +1. **确定主要问题** + - 明确主诉 + - 识别关键症状 + +2. **生成诊断假设** + - 常见病优先 + - 不遗漏危重病 + - 考虑年龄、性别、基础疾病 + +3. **收集鉴别信息** + - 针对性病史询问 + - 针对性体格检查 + - 必要的辅助检查 + +4. **评估每个诊断** + - 支持证据 + - 反对证据 + - 可能性评估 + +5. **得出结论** + - 最可能诊断 + - 需排除诊断 + - 进一步检查建议 + +### 鉴别诊断表格格式 +| 诊断 | 支持证据 | 反对证据 | 可能性 | +|------|----------|----------|--------| +| ... | ... | ... | 高/中/低 | +""" + + def _get_treatment_prompt(self) -> str: + """治疗建议提示词""" + return """## 治疗建议规范 + +### 治疗建议原则 +1. 基于循证医学证据 +2. 考虑患者个体情况 +3. 权衡利弊风险 +4. 尊重患者意愿 + +### 建议格式 +1. **一般治疗** + - 休息、饮食、护理 + +2. **药物治疗** + - 药物名称(通用名) + - 用法用量范围 + - 疗程建议 + - 注意事项 + +3. **其他治疗** + - 手术/介入指征 + - 康复治疗 + - 中医治疗 + +4. **随访建议** + - 复查时间 + - 复查项目 + - 注意事项 + +### 安全提醒 +- 具体剂量请遵医嘱 +- 注意药物相互作用 +- 关注不良反应 +- 特殊人群调整 +""" + + def _get_full_assistant_prompt(self) -> str: + """完整医疗助手提示词""" + return """# 医疗诊断助手 + +你是一位专业的医疗诊断助手,具备以下能力和规范: + +## 一、诊断方法:诊断推理链 (CoD) + +请按以下步骤进行诊断推理: + +【步骤1 - 症状分析】 +分析患者的主诉和症状,识别关键临床表现。 + +【步骤2 - 病史关联】 +结合既往病史,分析与当前症状的关联性。 + +【步骤3 - 鉴别诊断】 +列出可能的诊断,并说明支持和反对的证据。 + +【步骤4 - 检查建议】 +建议进一步的检查以明确诊断。 + +【步骤5 - 诊断结论】 +给出最可能的诊断,并标注置信度。 + +## 二、置信度标注 + +在诊断结论中标注置信度: +- **HIGH** (>85%): 证据充分,诊断明确 +- **MEDIUM** (60-85%): 有一定依据,需进一步确认 +- **LOW** (<60%): 信息不足,仅供参考 +- **UNCERTAIN**: 无法做出可靠判断 + +格式:[置信度: HIGH/MEDIUM/LOW/UNCERTAIN] + +## 三、安全提醒 + +⚠️ 重要声明: +1. 本AI仅提供辅助参考,不能替代专业医生的诊断 +2. 最终诊断和治疗决策应由执业医师做出 +3. 紧急情况请立即就医或拨打急救电话 +4. AI诊断建议仅供参考,使用者应自行承担相应风险 + +## 四、回答规范 + +1. 使用专业但易懂的语言 +2. 结构清晰,逻辑严谨 +3. 明确标注不确定性 +4. 必要时建议就医或会诊 +""" + + def get_prompt(self, prompt_id: str) -> Optional[Dict]: + """ + 获取指定提示词 + + Args: + prompt_id: 提示词ID + + Returns: + 提示词字典或None + """ + return self._prompts.get(prompt_id) + + def get_prompt_text(self, prompt_id: str) -> Optional[str]: + """ + 获取提示词文本 + + Args: + prompt_id: 提示词ID + + Returns: + 提示词文本或None + """ + prompt = self._prompts.get(prompt_id) + return prompt["prompt"] if prompt else None + + def list_prompts( + self, + category: Optional[PromptCategory] = None + ) -> List[Dict]: + """ + 列出所有提示词 + + Args: + category: 可选,按分类筛选 + + Returns: + 提示词列表 + """ + prompts = list(self._prompts.values()) + if category: + prompts = [p for p in prompts if p["category"] == category] + return prompts + + def list_prompt_ids(self) -> List[str]: + """获取所有提示词ID""" + return list(self._prompts.keys()) + + def combine_prompts(self, prompt_ids: List[str]) -> str: + """ + 组合多个提示词 + + Args: + prompt_ids: 提示词ID列表 + + Returns: + 组合后的提示词文本 + """ + parts = [] + for pid in prompt_ids: + prompt = self.get_prompt_text(pid) + if prompt: + parts.append(prompt) + return "\n\n---\n\n".join(parts) + + def add_custom_prompt( + self, + prompt_id: str, + name: str, + prompt_text: str, + category: PromptCategory = PromptCategory.GENERAL, + description: str = "", + tags: Optional[List[str]] = None, + ) -> bool: + """ + 添加自定义提示词 + + Args: + prompt_id: 提示词ID + name: 名称 + prompt_text: 提示词文本 + category: 分类 + description: 描述 + tags: 标签 + + Returns: + 是否添加成功 + """ + if prompt_id in self._prompts: + return False + + self._prompts[prompt_id] = { + "id": prompt_id, + "name": name, + "category": category, + "description": description, + "prompt": prompt_text, + "variables": [], + "tags": tags or [], + } + return True + + def get_recommended_prompt(self) -> str: + """获取推荐的完整提示词""" + return self.get_prompt_text("medical_assistant_full") diff --git a/pathology-ai/code-changes/medical_extension/test_medical.py b/pathology-ai/code-changes/medical_extension/test_medical.py new file mode 100644 index 000000000..85e5c770a --- /dev/null +++ b/pathology-ai/code-changes/medical_extension/test_medical.py @@ -0,0 +1,150 @@ +""" +医疗模块测试脚本 +Test script for Medical Module +""" + +import sys +import os + +# 添加路径 +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from medical import ( + ChainOfDiagnosis, + MedicalAgentTemplates, + ConfidenceEvaluator, + MedicalPromptLibrary, +) + + +def test_chain_of_diagnosis(): + """测试诊断推理链""" + print("=" * 50) + print("测试: Chain-of-Diagnosis (CoD)") + print("=" * 50) + + cod = ChainOfDiagnosis() + + # 测试案例: HIV患者肺部感染 + result = cod.analyze( + symptoms="干咳、呼吸困难、发热", + lab_results="CD4计数: 150, LDH升高", + medical_history="HIV阳性5年,未规律服药", + ) + + print(f"\n主要诊断: {result.primary_diagnosis}") + print(f"置信度: {result.confidence_level.value} ({result.confidence_score*100:.1f}%)") + print(f"鉴别诊断: {', '.join(result.differential_diagnoses)}") + print(f"推理步骤数: {len(result.reasoning_chain)}") + + print("\n[OK] CoD测试通过") + return True + + +def test_agent_templates(): + """测试智能体模板""" + print("\n" + "=" * 50) + print("测试: Medical Agent Templates") + print("=" * 50) + + templates = MedicalAgentTemplates() + + # 列出所有模板 + all_templates = templates.list_templates() + print(f"\n可用模板数量: {len(all_templates)}") + + for t in all_templates: + print(f" - {t.name} ({t.template_id})") + + # 获取病理模板 + pathology = templates.get_template("pathology_diagnosis") + if pathology: + print(f"\n病理模板工具: {', '.join(pathology.suggested_tools)}") + + print("\n[OK] 模板测试通过") + return True + + +def test_confidence_evaluator(): + """测试置信度评估""" + print("\n" + "=" * 50) + print("测试: Confidence Evaluator") + print("=" * 50) + + evaluator = ConfidenceEvaluator() + + report = evaluator.evaluate( + diagnosis="肺孢子虫肺炎 (PCP)", + symptoms=["干咳", "呼吸困难", "发热"], + lab_results={"CD4": 150, "LDH": "升高"}, + evidence=["HIV阳性", "CD4<200", "典型症状"], + ) + + print(f"\n总体置信度: {report.confidence_level} ({report.overall_score*100:.1f}%)") + print(f"证据充分度: {report.evidence_score*100:.0f}%") + print(f"一致性: {report.consistency_score*100:.0f}%") + print(f"风险等级: {report.risk_level.value}") + + print("\n[OK] 置信度评估测试通过") + return True + + +def test_prompt_library(): + """测试提示词库""" + print("\n" + "=" * 50) + print("测试: Medical Prompt Library") + print("=" * 50) + + library = MedicalPromptLibrary() + + # 列出所有提示词 + all_prompts = library.list_prompts() + print(f"\n可用提示词数量: {len(all_prompts)}") + + for p in all_prompts: + print(f" - {p['name']} ({p['id']})") + + # 获取推荐提示词 + recommended = library.get_recommended_prompt() + print(f"\n推荐提示词长度: {len(recommended)} 字符") + + print("\n[OK] 提示词库测试通过") + return True + + +def main(): + """运行所有测试""" + print("\n" + "#" * 60) + print("# Nexent 医疗模块测试") + print("#" * 60) + + tests = [ + test_chain_of_diagnosis, + test_agent_templates, + test_confidence_evaluator, + test_prompt_library, + ] + + passed = 0 + failed = 0 + + for test in tests: + try: + if test(): + passed += 1 + else: + failed += 1 + except Exception as e: + print(f"\n[FAIL] {test.__name__}: {e}") + failed += 1 + + print("\n" + "#" * 60) + print(f"# 测试结果: {passed} 通过, {failed} 失败") + print("#" * 60) + + return failed == 0 + + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) diff --git a/pathology-ai/custom-tools.md b/pathology-ai/custom-tools.md new file mode 100644 index 000000000..a6cf27613 --- /dev/null +++ b/pathology-ai/custom-tools.md @@ -0,0 +1,368 @@ +# 🔧 自定义工具说明 + +本文档详细介绍病理学AI助手中新增的自定义MCP工具。 + +## 工具列表(共15个) + +### 医疗诊断工具 + +| 工具名称 | 功能简述 | +|----------|----------| +| chain_of_diagnosis | 5步结构化诊断推理(CoD) | +| evaluate_diagnosis_confidence | 置信度与风险评估 | +| search_pathology_images | 搜索本地病理图片 | +| generate_medical_guide | 生成就医指南 | + +### 诊断模拟游戏 + +| 工具名称 | 功能简述 | +|----------|----------| +| start_diagnosis_game | 启动诊断模拟游戏 | +| diagnosis_action | 执行诊断游戏动作(问诊/体检/检查/诊断) | + +### 医学可视化工具 + +| 工具名称 | 功能简述 | +|----------|----------| +| generate_knowledge_graph | 生成医学知识图谱(Mermaid) | +| generate_diagnosis_flow | 生成诊断流程图 | +| generate_medical_chart | 生成统计图表(柱状图/折线图/饼图) | +| generate_radar_chart | 生成雷达图(多维度健康指标对比) | +| generate_timeline | 生成时间线图(疾病发展/治疗计划) | +| generate_gantt_chart | 生成甘特图(治疗疗程安排) | +| generate_quadrant_chart | 生成象限图(风险评估/优先级分析) | +| generate_state_diagram | 生成状态转换图(疾病状态变化) | +| generate_sankey_diagram | 生成桑基图(流量和转换关系) | + +--- + +## 1. chain_of_diagnosis + +### 功能 +实现 Chain-of-Diagnosis (CoD) 诊断推理链,将复杂的诊断过程分解为5个结构化步骤。 + +### 参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| symptoms | str | 是 | 患者症状描述 | +| medical_history | str | 否 | 既往病史 | +| lab_results | str | 否 | 实验室检查结果 | +| imaging_findings | str | 否 | 影像学发现 | + +### 输出格式 + +```markdown +## 🔬 Chain-of-Diagnosis 诊断推理 + +### Step 1: 症状分析 +- 主要症状识别 +- 症状特征分析 + +### Step 2: 病史关联 +- 相关病史 +- 风险因素 + +### Step 3: 鉴别诊断 +- 可能诊断列表 +- 排除诊断 + +### Step 4: 检查建议 +- 推荐检查项目 +- 优先级排序 + +### Step 5: 初步结论 +- 最可能诊断 +- 置信度评估 +``` + +### 示例调用 + +```python +result = chain_of_diagnosis( + symptoms="持续发热2周,体重下降,淋巴结肿大", + medical_history="无特殊病史", + lab_results="白细胞减少" +) +``` + +--- + +## 2. evaluate_diagnosis_confidence + +### 功能 +评估医疗诊断或回答的置信度,包括证据充分度、一致性、完整性等维度。 + +### 参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| diagnosis | str | 是 | 诊断结果 | +| symptoms | str | 否 | 症状列表,用逗号分隔 | +| evidence | str | 否 | 支持证据,用逗号分隔 | +| lab_results | str | 否 | 实验室结果 | + +### 输出格式 + +```markdown +## 📊 置信度评估报告 + +### 总体置信度: HIGH/MEDIUM/LOW/UNCERTAIN + +### 评估维度 +| 维度 | 得分 | 说明 | +|------|------|------| +| 证据充分度 | 85% | ... | +| 一致性 | 90% | ... | +| 完整性 | 80% | ... | +| 确定性 | 75% | ... | + +### 风险等级: LOW/MEDIUM/HIGH/CRITICAL + +### 建议 +- ... +``` + +### 置信度级别 + +| 级别 | 分数范围 | 说明 | +|------|----------|------| +| HIGH | ≥80% | 证据充分,可信度高 | +| MEDIUM | 60-79% | 有一定依据,需进一步确认 | +| LOW | 40-59% | 证据不足,建议谨慎 | +| UNCERTAIN | <40% | 高度不确定,强烈建议就医 | + +--- + +## 3. start_diagnosis_game + +### 功能 +启动交互式诊断模拟游戏,用户扮演医生进行问诊练习。 + +### 参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| difficulty | int | 否 | 难度等级 (1=初级, 2=中级, 3=高级) | +| case_type | str | 否 | 病例类型 (hiv_basic, hiv_opportunistic, random) | + +### 输出格式 + +```markdown +## 🏥 诊断模拟器 - 病例开始 + +### 👤 患者信息 +**男性,32岁,程序员** + +### 💬 主诉 +> "医生,我最近一个月反复发热..." + +### 📋 当前阶段:问诊 (第1步/共4步) + +**请选择您要询问的内容:** + +[btn:询问发热详情] [btn:询问其他症状] [btn:询问既往病史] +[btn:询问接触史] [btn:询问用药情况] [btn:进入体格检查] +``` + +### 游戏流程 + +``` +问诊 → 体格检查 → 辅助检查 → 给出诊断 +``` + +--- + +## 4. diagnosis_action + +### 功能 +在诊断模拟游戏中执行具体动作。 + +### 参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| case_id | str | 是 | 病例ID | +| action_type | str | 是 | 动作类型 (ask/exam/test/diagnose) | +| action_detail | str | 是 | 具体动作内容 | + +### 动作类型 + +| 类型 | 说明 | 示例 | +|------|------|------| +| ask | 问诊 | 询问发热情况 | +| exam | 体格检查 | 检查淋巴结 | +| test | 辅助检查 | HIV抗体初筛 | +| diagnose | 给出诊断 | 给出诊断结论 | + +--- + +## 5. search_pathology_images + +### 功能 +搜索本地病理图片服务器中的图片。 + +### 参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| keyword | str | 是 | 搜索关键词 | +| count | int | 否 | 返回数量(默认6,最大9) | + +### 支持的关键词类别 + +- HIV/AIDS/免疫 - 免疫病理学图片 +- 感染 - 感染性疾病图片 +- 心血管 - 心血管病理图片 +- 肺/呼吸 - 肺部病理图片 +- 肿瘤/癌 - 肿瘤病理图片 +- 神经/脑 - 神经系统病理图片 +- 胃肠/消化 - 消化系统病理图片 + +### 输出格式 + +```markdown +## 🔍 病理图片搜索结果 + +找到 5 张相关图片: + +| 序号 | 分类 | 文件名 | URL | +|------|------|--------|-----| +| 1 | Immunopathology | hiv_lymph_node.jpg | http://... | +``` + +--- + +## 6. generate_medical_guide + +### 功能 +生成结构化的就医指南,包括科室推荐、检查项目、注意事项等。 + +### 参数 + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| condition | str | 是 | 病情描述 | +| urgency | str | 否 | 紧急程度 (emergency/urgent/routine),默认urgent | +| patient_info | str | 否 | 患者关键信息 | + +### 输出格式 + +```markdown +## 🏥 就医指南 + +### 推荐科室 +| 优先级 | 科室 | 说明 | +|--------|------|------| +| 1 | 感染科 | ... | + +### 建议检查 +| 检查项目 | 目的 | 费用参考 | +|----------|------|----------| +| HIV抗体 | 初筛 | ¥50-100 | + +### 就诊流程 +[Mermaid流程图] + +### 注意事项 +- ... +``` + +--- + +--- + +## 7-15. 医学可视化工具 + +以下工具均输出 **Mermaid 格式**,可在前端直接渲染。 + +### 7. generate_knowledge_graph +生成医学知识图谱,展示疾病、症状、治疗的关系。 + +| 参数 | 说明 | +|------|------| +| topic | 主题(如"HIV感染") | +| nodes | 节点列表,用\|分隔 | +| relations | 关系列表,用\|分隔 | + +### 8. generate_diagnosis_flow +生成诊断流程图,展示诊断步骤和决策点。 + +| 参数 | 说明 | +|------|------| +| disease | 疾病名称 | +| steps | 步骤列表,用\|分隔 | +| decisions | 决策点列表 | + +### 9. generate_medical_chart +生成统计图表(柱状图/折线图/饼图)。 + +| 参数 | 说明 | +|------|------| +| chart_type | 图表类型 (bar/line/pie) | +| title | 标题 | +| data | 数据,格式"标签:值\|标签:值" | + +### 10. generate_radar_chart +生成雷达图,用于多维度健康指标对比。 + +| 参数 | 说明 | +|------|------| +| title | 标题 | +| metrics | 指标列表 | +| values | 数值列表 | + +### 11. generate_timeline +生成时间线图,展示疾病发展或治疗计划。 + +| 参数 | 说明 | +|------|------| +| title | 标题 | +| events | 事件列表,格式"时间:描述\|时间:描述" | + +### 12. generate_gantt_chart +生成甘特图,用于治疗疗程安排。 + +| 参数 | 说明 | +|------|------| +| title | 标题 | +| tasks | 任务列表 | + +### 13. generate_quadrant_chart +生成象限图,用于风险评估和优先级分析。 + +| 参数 | 说明 | +|------|------| +| title | 标题 | +| x_axis | X轴标签 | +| y_axis | Y轴标签 | +| items | 项目列表 | + +### 14. generate_state_diagram +生成状态转换图,展示疾病状态变化。 + +| 参数 | 说明 | +|------|------| +| title | 标题 | +| states | 状态列表 | +| transitions | 转换列表 | + +### 15. generate_sankey_diagram +生成桑基图,展示流量和转换关系。 + +| 参数 | 说明 | +|------|------| +| title | 标题 | +| flows | 流量列表 | + +--- + +## 工具文件位置 + +所有自定义工具定义在: + +``` +backend/tool_collection/mcp/local_mcp_service.py +``` + +使用 FastMCP 框架注册,通过 `@local_mcp_service.tool()` 装饰器定义。 diff --git a/pathology-ai/diagrams/cod_process.png b/pathology-ai/diagrams/cod_process.png new file mode 100644 index 0000000000000000000000000000000000000000..7da167fb4fb5b5fba7711d7fa464e0a83d10f872 GIT binary patch literal 68300 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µgnmG`joW>`tNILB`i3+xJkcD|v?yrCC_?IS&4u-(MEG#|$Y9tH> zQRI)2p(to&?Lp=?eFtU>qt{#Fzdz={YDWnzy`T)L8szjPc?0H}4c4U8xSOwnvJkvU zOE^Hfz&O~6VYUz2Za_;D5+Vln$m{oI57Ykq_kU8J73}dr)cn6+O1ytxyTAX>KaT#t zFT_7t2LF0S{;@>;>q`9Zd>a4cSNwIQ{x92O{$IW9@3(FZgrdXix82?HMcf_=hjw37 z{;z+GqqConuSQnN5zi&!qySqMy U4Zig)2;F?_6-~uF1&e$C3#yo8Pyhe` literal 0 HcmV?d00001 diff --git a/pathology-ai/diagrams/dataflow.png b/pathology-ai/diagrams/dataflow.png new file mode 100644 index 0000000000000000000000000000000000000000..1d825e14118e0c3a977f30925205f41c34600be8 GIT binary patch literal 63220 zcmeFZXHb;e)-~E@4=Rd^AaN^-3X&ve6QD$qoRc7_8_7AC6=*OKl%(X0q$Wua1(YZ` zG|)=UNNO_Nx!Qfsd(W*~_s4hZt9rkB4^`VONOwQav(}n(%rVBC&u=Nq9in2O!eB6m zZr-?l8-t-DVlcbf_V0zCRKGeN2>%mvlF@cjv$Jq=HE}Sy z*FRyX_7ivh>$}T4O!WTs4d(n`wg>*}yFHKo^I`vajQ^WA$iM9|6ZQXJd$_j8_~D`3 zui2Gq`=i}QPHG)OdpVrz-}d|c5gBpxV?UiQcVoOmLv^iFJXl#Z6h9KetEvwAKx~ENI>*ST1Am-N57+)!+MrV@ua>6u$h1%R_`~_zFVvQn+JG4-Rp55jcPshlT_XE(+J4Qb&zv{*1r*nxW($l;5sD^XGy2rCf5K zA95mM3x5Vp6n6YAwNjusT6CPBuYBdQ)I&mLy%eHj!pE@b$T~W>6nI+LnO;o@k+dw?P3m zx6P%_Ru<2xmlj%K`VKdBo!d1gy*D`0(k~ehDeupldz7;9e%;!zdM$eyZEsET!Obg; zMtkDcI?K00d{%xvtsG=miH_V_sgX`REVc4igD}af^+UeE^)POO+siY31_J0({ftt^ zvm_}&lGjGhsad9V51sxC&R*{Fjrn{Qaj%u%PCZshn-+g=%x_%jPiRaI)6mp8yAP*j z=sv6)Tr!cG*3y-2W}t!I5@Yd?2F4P~TUOMYm935_c(0R{3`$&-;^cz4J?jhY2V0_C z``?m@cI6&1uHRmq8qX-`uazGB)bLJFVWCOd*BVwx_imK)?Fb=kOW>WMZ!e2VjlAY$ zaI-w+8?R1i8{g0Sb~+$FzeAUki_m3?@B4bP;~5QG3#?JJug^k*@OV;;Pi-f6{~)cF zKHt-#2mz~>u7=&{+LHec*#bAv#w2Z#3!E04<>*)zeq1};&Ol%mv{o;Mr`Qq~EcMRN zYp!a;6I<*w{)$?9<9FWrOi7aHNO;^7Uz5awV$Z!VhbEU8qP@x8IrkesKioIksl|QS z3vG<2tUe-=+Zzkxa6y?%8+AP8USdNpuFVTtcITMC>yvr5)}p}E(E0n}VX5S$uKj)F ziFVG-aTQ;Ao2*iojGD~sYKC!Gu8So+J4vOU%iLa5@D`E9&Xbxhq)EMc<8fx5f&i8{~Dg>gl4KWQ>Ir%^56_fc>=9+mfCkK&UE_9 zKIS(pZa?pfJtUmk8L~c=t1{7F>bW+R+tgw=9&Q%&J;Zvs*Rjc|hS|04WZofGpA{3a ziR3tk8*V?|U$Jso`f^x0{tLDEMXvm|+vD)6Onyto*xSFS3rNwN40griiK5ARchWKl z*1t){H+Po?eEMB^ph(vqd!^3-cDUIUN(v3%^N&A?_0S1giMTb(m-~N&9=I7q&v)9u zwamBHZFsgccPk_y^i zVMadg??mhe)T82z%6(ECM;pgsC*baN330HiV7tgAvt^v=;f%0nLvn}({T`FLF~`s| z3m5(SQq<0-x^;}e7L4K665=4rYV^LXDj@kpxOAI`35c)4#oTU+mTZOhSx;-C{XBss zbh95~68TtNM%jySpXRJ|Cf&*DdQOcFqiIub??zwPSZ5Tn)y7XNy%V7Mb82kYm)PG{t$>gKguJnq%RNQB*1L_S|-B7}p~&g>{LXZe7OIo|}_`;$#es!r&= z$*|Se(JxtHwC?}pzBXUS(+cl$AUKNGb<96&%yFqxbNm#anBWHWKWHp6XW( zeK(hEraU+1YFdZBzqY{|ZEtP1Hp{UZn61Nh)F-b9cIxwU6_3T{NB=*bVgl^C{F&{o z^;w%f)?Z)yTuGAHyk=QZ0b;sNF30-5gY+-R@I$7L>A2cA7seaKXBE%IcsW!N8l%KV z{qB5!f8}9I%+_L3P7?}}Nder&$<^eZok=t|@MK)hclOmenw*S_mF4?b+>AZus_5#Z zwjh{nD}5ozG1*@)4aR@8j*;?C{Jvlap>rIzC3kOmEk{~BEUdIv8Q$3Wro;&B92JO5 zTJmU%VrBrXhZZ4~xMX?R#+==#} zCrl;e9-C1z9R0M8!PC4>`oRixhP7T^rbNU3R= z?^wKkf6nVP^h}7r6{k!M@|3L%IQ81sBtVWVFxC6S{}PgWn-)7@cpdg zkL=9%*zZRbF1{>woi%hZTDmv1IA6<|1tEd!`4KDC$E{6L>ld};qe5f^yBw|z9-%db zlsb}gg;;AcRmWYDE+0!5 zV*21wM=Q9sR{14ki#I8-mQ(ee5Zm#54w z=XMp8HZaqJCZiLrNoz)xOpcO%xv~r*2KG&t>TkW$1~@fJxv8%G?n(DZ)r@xfvkU3Djbh^f zEO<(IGTnS8FvEAm zEt~7kM3VfY2PLkv(LM@nazT+3zn#qkxCq+6${c1t-&WuX*_98W5Qq2XDP6qX^#w(dl&x^`)PUCKI-~kq}Y$xG|dbLZ925$!kq=NQ>Z4zVEAK_ zxfx6vPczznywW`l0Lckqo>th^!fLy*aSyNnSz2IWmyMY7qL{CT=ik_^J83ghG|Jt( z46sosx!6{nz~w&h{9FqFgxluZ5D%k$(b1Y3j9YWK2~Una!uHh&VAe`91w8Ug|EUc9 z_KL$w*gQJHNrX?cvGoM-;P}`4`fNE*x)%fO^)NkLQQL=WPyLDC&&5Q}6b=TFHVjYz zb$sEl^81(ha)BL5Dx+kkI7KZ9!qOsV3L`J($*&lN(15R);3^R+t#n$e{ z>g8L9WWx2e!6LQ+Fy5%N7RMOY4L!ya z^7>qe34m}v)spwiWqq2jUG-5giB4EDuXz7ZaS}3+591)HLa9CAX#32sEW=gec9cAOY>@Hra>JpxV#8pdHQd! zhkFmn1NP<8YbV6_l1$XQy#YSgJ;BE1*kgB?QLd=tZ_w9Pr)O6h(xG!VN|*D^){JYp zg7?~@)h)Li&*hoN>#~9L&F^1Wn9G=S-O4n@nrD@gbxqzE63APNtt#V?_>^+f9BAQ1GFvva}X=iul)_4 z`8V9!RON=>Piq-@Yq<43IKUl_D;f^XIn^m5_Y$4|DKbQfB!Gt^n-IU%mZ%#fmwO+t z?>)?-A6Gk`g|!nQcbVOttR*nw3QerrQ#HE1A-ddvZR@)>9A-qt%DPT1Huk=9+3PW_ z=8Y(ES8gvabpjTWKYkh=SO$@M#vxcP-MkyHXY50;fYo$$Ek8WAme>L;)nu|TL4X|b zcQKz!{U;KKdm&%* zA}Sc`G+9^xzf1X=+v`tuWTe>!IBFgK`2+x*IG#naxRwB6O^gya{}446%z{ZPf07M8 znT4_ahA)1q06bjOSb>`g zzJ+_aKUKDZ3=bgnXkHXl3l2wItp%_>0$TDJO6obxupg*aGTHmZsn1w6s=f;qSbg*HKyfYC9m7M!}%g_M;!QFUvP~3K zu#V?+z8XU1d^Jq`O8swlQH%VA2#E}+M)Fw-x=aHSLb>!hk^}WR%?9&(;Vc$W*?B)K z$_q_vlVZ~7 z+40&~T>`4+0={oQ`qr3y)JS1#)^}SWt9;9Y0no%d33mr-3zx|bE<^{lPPpo*#yA8mWkg^|Z*MqK2LY!fC>^xs3AOZs zr!=IbMSyT4HvN#G+AeD{9;$5Wh;K*`TOas2e{h08laH03Ix&+)il`=e0pSa*1!3`Ki5>B{BNqxe-oMVKiLTLAC35bRsFua5X+3I z4;OQp3P)5I2eGHXE~X5~Tv;2$6)SRbW)_;Rf#hW^nRxRxdx}PyrWMpv4VyzyNpmfM z9m=$Tj)%E1+z>}||-3Fd7j>QEh0(4BgMlE`WP|gnT$)5v8f_PBnhKVmuU26&8 zDGSd8nj;UPX8uMIwxyZAlI#csbom1TxyCE-lnO*aMS#jUF3);E;&1JM)=~rlSc$ra z#e1&&II054}X33MvueyQ}uGdcCO08+1WMA8;9;vLkl$>VYC) zOgJ9(5k6hS_4-~Q#@UtLy(!?y{(2POhXlIBmQEwzsI|rM*J%rpKn-NF!4Gpw=?@^{ zrv+GiMklW7Am)gzxnSRTkX^+jSAITBQ3&J4dvNgpH!ne83~~2e8&CR#1wKPQw-^9D z=hGNAeF?YUKmDf@=CBwaarCG{O-0`TmsXaI9(aY*5e*#N;i^-`j(vq?@R9Wd9FVMe zB%gJSM`}scKwN}CzSfI-5|Z%~A)qglB*|TI)nrh@gqh)ykAp&%l5Mv*);tcJog%E(rd^vn z+(I~?7d!_f6muTz$t<2o9sl|8u(G5lSrJj1h&O3Li^}4=F$X#*-SB$*Ch&3NhkaMB zc|gJ4`e~tYo$(VDCOli`a0My|XwxdnHTaIg>Nz~1( z*GO-@+?7j1FaV0@Hn8iCZZ5+iT8+U_jV<4v?JqrW?GrF@b51x(I53b1EL4Si?_INQ ziNA>_g5IoWU(XgS@yZ2g{=E82b@7mFIJpXcK1czHq3F`Bdc}05BFCEgnpZ%{@G`@5 zb3ge~WL9FK{>OcofYNSm?YCM`<8#%$t0HBo$g&sxGQ!&TYG`5F*(G4@rNJ2`zEq zJ3$*w?NS#YIcS#;i~RJH@YCKT!@m!0Hv9IX{gzY59ia=1Vh2ccx-rW@<1}ryK?y1H z)Ely8gq^+bYbBxYn|1V`A{kWO&#yJYM>`>H5vR78L5FnPuSXSzuzVP?dp|40n%c{K zw-=M7H!nCt!RHJ#Neo-rzOnW+EwRBs{uT;9>4MJq(lk+++3ClX)%AxWBp^j&(*DW- zg2M_{rD@b_JR!_lvT2#*8-w`SJm3~bUGjmJMS`~#P*N%e#ZEVgxDu=wM50z;05xU_ zu*ZMA`>vx*Wjoe6xaP50I&B=Ce8hI~il$8SCKMutB_lK|P z^zU8CJfY4C@~f5@(63bcMr4CoqU>mf@V9Ihf7Q7|5N=hKV-C6YdHCu#`+yob)~#o3 zLEl2~?}WHA8-8RNl`n>sZ=BWQ<5-rw)_b~e0|bWzkTB9}D{Rc?3@$%<^Yk#Qp_!4o zfxn*OPyFl|(_5&r=e9*TLC^qhOZ2*K9}>E@R-1e~CSS?W3s(n-J5RiUsHh${ORm^; zI37;BSz_4+n{40>pg*)cAX22-ZqL=Qw!(V9zE(HqePwa_u=vzRS(|eherl+qE%?FA zppbb)P0~`&;NXOe`FoMFQ_7;lZ=CA+YTEYqXfDG!ALS5hMj*}4i0wi2a2}w^#u}i( z-uGW2?oY&JSDko#h3F9Nvo?;{&fdeBN{exaB^Q54h!O}?B1<&wwroRs-0=R2pYXIe z(-#696QRdwePbu=ir!eWwdCEC8x5XWjI{ zP`&NO%A9+8vBwWWvGyS{TvSuL*A6hF84DfTr3Yf0ZD|mmLsV5Ysm%0ac3JMJFA(s1 z-Vef6zmJUdnW5rLzm;_}ZppriRxAFsvRKOJ*S8gDU67RDdzkyEh64vrm}owv*{D3& zJ9K+r1bmI}1)8b6nhX-h2vw2HmEJY~S$bvZ%|#<;YFHC%y0plHCojcUllOO5pQ(M) zgDaV?#RY39Sy=FmlMxMD8Y~U#k@0Eg<<#vrv|#;+0khr~1Sy-5&jld*4f_kreCUDG z$2ASXV@b^Q;>n|?-QT4*ejP4yP;u%t{a%y&;28hzw15O*(-Y>%@Uhqdo(Cr&VMo{F zWbw64dIsv7ToVG27kCHV$38rzN+a9mHV8ROl?m)G8t~^#jB@F@fI{LpWYOf?210v( z28quU<^&r7qum034S!gA?3{9aO+TavtI9|J&@)u!gV)5TIgQeCi@n&XLP06?PHjA$1@vMCUY5hj#Eym4FP(wPy-!ozZ zJJlT^^^M9)wddP*Uoy%<=9uNpxR_0NL_EGVM}7@V3@n8ln5tghVIO^)*8?K#DuWaX z$XWZ~F;{`iUz$VI(!=HpfVD(mrKKv|LDUHJcPC#)G3N<&J^~{deutqZ9j@65a&B5q z2B=ET(d!X*W#6UgK#ie9dc?-!nZ<>C%Wq{`+bu4uNUaX_%58Cdbv=?juVm#gwd=6N zt-)~Zgv5CpP@BztUlVrJH=?9-4Y@#yVc8tc3o$`V90zRH7-F3YN34^A%y0u9XD=y&bte0*Qv?puj%7Z@-#8Y zu+(GN&$j4@?LjY@?Yy#wuFWdkR6W&~b&G!7m6%D4z@^gUaV?day|NKiT_WTp-{J=Y z7eh@3;97Uy41FWXdLUS>AQWZgOv6&Tc5_@uK_A~qr{Tc))LH?>H;!_-_8y0Ux#6!1 zU**My30icc(EvQ_qR(+~SEY)=!nPSL(JIQf&`ZJ@bD0A*6c;Ii^4i*LenlT z_hvsruw3!LbWgrQu*Ce0(lj!}b{5gEdhx#7TSf11&du8y*dN(&HmyQ5G*hxSks5UA zFCCnF?U8nzjg3}O**cWxb%b0{8O>SMGQHcIz)EHF#@lwc3ELwHU>Q8}vwGc49cEFU zL@K986zD&GJt2$%hX7}Wrz&U>2Tg6=ENDr4zAo>RsZ~0Cs5*a#g&iQ|+_&2DaW~ZW za*Tq+m)com_E&cDfD*FgbdU19GeLgCLo}}?05lKl(-O*%TWfL)qDS%+d8tD$tI^SQ zyd|NUfcya(cjWs4GBDI!H;=*#^_&;{3h7>tP&&3Anqtj4FUAR_^f zp20Gbogk}SLn0FrcU!6Y*aMF>a;1c1Fcu03)!^jtUS`Jvlig7 zTrRp#vF?EM=s4b?XQzbX-b3!&&0kwzfsrw!uM9-z4)+;QCOSk#v}QKIi+RUHu;&TE z(OTW`mj&qajS4p0P|7^sMF0ny6*VhFkMgE=TtH?gr2Xg<`u9HPth3$m1Vt8Xnd&9@ zAE@Lxq}HZ|_fH3)WcH9}6fALY48dE$uU0PTjJFA6Y^DC^k|^?nsp@TNf~>Wk3xW{H z8Mv6`yU9sH@O}}A@sOggAqS8$%1iwO2yn{nkNtVAu(cWi8Fs900JELBCq)6|F|6C@ z2_}9+I5IJ0BFi1N*v+i6HS0AZX-kv-FKT3AXve|E{Fbv0HQALyffDP?fX1u zijt^Ka;A-m_hmB=SZUw1-FIR$2DXTs%r55bN@dL}KCbr!c=BQ8(NVp1MXG;HN(y4;8 zVfs10-D5dsLFo*`75;i60ClU=L`qU<#yh9)XT#b=F`ockB#6&`;`g5aer`NDE{Mak z7v4;N)CO|v&ut=P{W`-S?d&r<3zld&^TDqug?zVyWTa80+--{HU+Tgc4EBHq%Tv-< zC{!^8CRaZz_R!gj!Y{NP0AGjom4R8XJ&mCW^toHwe9PcIvb&`hA;h&^UIEZaXiNfj zUwu#P1DvREpOacfh#T4zIU)BtV54w&x2%*#0uq=#lq!-3?wBxxM!3=##a0D%!sbHE zc4Uy$+E@ZRA`yS+}bYSDxU)m>%iIUN$JWAQd;9f2E(6uxS$ zfa`Pd+70pN?=hrB3)pm|chKrx4P>O#cu@)(|LtobY464J%}Rv9acL6c`SlsiIM`yi z*EibJ_6j@ci?h#A1G2k<70f)uI|%%{@jL&slI7sn$f3oeLW+SHx7GmG5nXd4IDIr+ z{_#EBWCg^&l4^2tEa1mkf#fLFD@l=0Sv=0;S*6RajH12Y(GJfeN8z3ixN65gexc@M zEX4a~J!NvZ(Y=5QpxRludb4hd<<84i)z}#+>VOQ>RwVa|33uOl%}|5nSX7au+9oF=LRAwHGCxMNbwyIV`&zDk0=6P!bfP|Jpu z-Y%KSQNSl~v-y>D=-MOz`pB-HLspK=+E!F+%mv(=g5clx)79kuo)h0f9Fg0NfuFV$ zd@K@!{9>`el4Nag<;1uGS#2zILc_xBRz@)xm(CuZ!U9%AF{820ruyd)crFcu)ET_H zp=2+tB?xwCvta>AkHfJ|x8Hy`|9ZUwFsO!MY7P)`MI>Z&8ZEmACDYG>Gkd89i_*kF z&us<6*$bgQr`9}B+D8_y#{d!3T*S({Ih(xqc+Dn+_^kOZ`nL?no7uYc@1Cla;C(6@IYoYU<0koP>p_oEAJLdSK!Zk2lGPHOc_aBaHxLp zQY!afkB-$oF;F{iX(w%5jOCdC9uC#k+N-GY(G< zvqrD4!$Gv0fZ{wl-UG0TaA7L;eCloecl3-|(ho}c2+W%vm_$}kYZHrBZm~v%7heSI zHV!tP^CfmolFJvxwdrWFP%06;(k@!iRR3jk?JH&!C=(5{bx8CPK~Tc(jRK;`Pe<#~ zwYW<*2fu32Y4}YL_i-2KDinfQdcn`6$XY^mmHld|eOevZj-!J_2A+K?RxENc^j>PW zvX$3-DnLAkm)O>$*Fdt_GJ#E={QJ~H<7m*Kh5_+Q1i63RORn7HU6O~$F%NoV~rH(Znuu(r8WNhyoQqvF@ejL-P)jICwgRx*!#acjI zPVdYH&}>u;Y>dsteAOJp%3P^jd!}>0S;saR96!ZV^$Kvc$unT{QUHiUQa1=6D$v@+- zP?et8_HagSe*=_Z&I1FqDG z;5rRlGhC(f;gAUus?30msdj1<9Ub!V@Rl(u)0Zxl2{^GNCAZkHJs(yc55zHVIk`4< z+b|+|{@AV;@M42fRs_)8q0zw219-%inUYz<*;|&{CXZ=b5VS&$=1PA;h>STgxl%U* zeAP+d!{tCk`5~W@SRNlR94faL-g8EXlKMwShZdd}r&x@io9(%Zs$m?M_#>>RrRBO- z!Grp4qFo~{m^H+Eho!!nwDTSe)!uz(DR|DTPnUqrHW-I8vn$O3jQw>U;}3AV?JtSmcHIx6N+@DsbS=M${)`+lBO*_YbLS6+ExsohTZORshiY zUBL{J%O@)^#3?{^TeJ*O&5sH(z-wPvw_YILc;EiGVwH=BM4>lF;wRmXPWl&t6Pfn< z>QgCMZWMeI1jo8J$!Fy4-4>_-UxkH5irAY{cM_0U6KbIptt`XUjeL!b=ROOl6Q$|c z<|NeeNyvbR_|+_tV>^i28tfcv*ArqLyqEUV+W~7#p_37FhHFAS0f?w49^2ep;r@$b z(-sc<<6ViaByU&bkMsag=cosEy~yj#I4Yp$T$OgY@9(e$pAb|juF&SD?j&Y%=R4lgN0c((2;)3IE#*?BBckqV~0Y{hId63QT z2}ePCwZ~*eSlVw){WCAkclM;Gfbi`)|nXc63a-y@yakLr-r=%?vWU0&}=-2Aw18?ra@QPdhvmFin z5aV|;q?V9dc;(^V1h4`NxbQ=};Ip&h>e}Iahv<1L{uvQ`ny7B_vzxVGFxxfZi4+@0tE~WPsu>sr@{G8~m^R1g>A9D&kyu^M8#GSyKO+D{~Tp&&U^UGNF z?Eer`&3{Kb$$uiyf6EBuC))}s4RwZiL7QTilY0;}cBT)A0{@abKF@@yFNV#O_!9aI zJ`6l`zh*brrPBcD?6oo|3vECuq2?G$A2?F^ohRBZOhb3XIO@&<+=H94_&amfJ0U`Z z!>o~l^rJ?BILdU02A<63T>+>@dngUV0-3D78+?*bk%=BG0sOf&v2ci0N`e_#D-egJ zmZ+GLGYjmiyjgYNO^TDA-gTx|baT>ZTOJy@8?$^2{~UI|?slZ&HUir%0MwY^m_2H) za{}*4y*%Z9fJje3vUoKaw3AbaZ&}>}x^UD>-x-=~tm8f%M%`n&pngyc3pdY2Ev9`T z(8TtE^28C^YY8nEJ-|q{0w1!T2L&4iIs*C=?gO@B9JQySwiM(EM{ex}`@dt5Krf;f zaR~2!rIBk}=L5Fb+~fD>eFiv8@;+c>t>U34aaFT#Wo|I-ku_VOSlly$%nuh`dPxtb z9=Ab!D_B+LXQ8$?F9tJ2E7B+iyIPgSxeNf^745{Scc6X&)DzhXorr=;J%2xc-jZjP za@jkr(m8rwe8e(sLjxzJso@Zdgj+Fz24mr(gj%-i8OWfA_`jc~7N2^7I)tH_?+3WF zouFL>^&DQW@Le9lNOwDgnGm8PEzfKapr5CopYX&9)tZpHgz6D&E8>NXE-j=}_AaxpjOeqj% zlS|=<--AB;(`GZtFRWH?InW-~Q#|=_Zlv;~lbm`jBCwj1_Mo-h>9Mb2c5LrMP@E?v z2h_Mk#F+l(OPGW<1;=3$JlxGZ!0w6AWY23?4jr-!WVft=<&lPnq?c@R9X&zi8^b)b z*q{Zd573t)9?3qa&6pINT?Z!m_SJA$JBjTL)C!>q^`34pK13coE@X+u9;jagkRb+4 z|B1l#Uto6awYLIt2AY!18WZ@M;kRt~~UwM71C2$B$ZtCtxhK>=xlV6c#N>j%?gsIXC*uVLGEBmV{-2&hcs9i_=3Pqx zY7v{jFj<-u2s2XfPM+@dVppS~`c28j)6{Ra#%#Tjg7yrFL|r5B2FdjJtWP^0$+v1v z6s<1?Dq2Hy1Qg6~gP9NvJy=|WF54bY^v_;~{*U*jRqe%#;Fm$Y`9&GPM(MMt1Wg_@ zo1yuQoD+^Ti6VC9ApuuuX$h20K44S7x(}{tO5a_|o~0)S&5c{ag2-ta|E#z_{^A<- zcbO7QI2nSb1*Um!Wpmay1|t7!CT;xTifmgsr=z9>U3Fvpkuk(iqmFU^8bmUT1IyR2 zJb2BgerGxwUXb2JfGDNmMIYSlf)w>)Xp7+p!oRS!c@L=>`NijveM)a5-FnJ?UL^bnbM(#aGMI zKq3@5(#=2zO{F88k_FnRhGLFCJ)eM1&7lW6^ZfiVvk&=?brd**s@)uqpH0n}u-PqY zM%zJO(+|{z!*E-2G-HT8FiA^Z^=Rlx5NJNSM7kYB!lmt5QMjoV2by4=K<$Na$Ij+(!XF)ULBB<9xb3c=-!G>pcuuKS1M?RTu4XRg! zdg#pR?W51z<~PeS4iCoW*y_)oPu9o*p=9)y1J;CiF4`@&R>V`kU;?o@8~mBB$M18T zOI@zkb`6{hGt|2CkJyG^(0`}m!-Y}QYe2qjaUmfVUu{ivV%%L}Or@ z(lGVqi^nbr4iqWKf9|uoAVv?3LJDQ9owGpQrR8iRp9-y=8NtlyB2tf%AiTGUsO*k5 zBUm^+Fcl4&7~pG8@!xE|&j74|p>llj?Z*Sjmq1h!SNWoa##F&qeP*mYHqcvEH8J@I z!{_D+L~%>_=rSbXKwpg-#lM(_{jRP0DESNvt4!qS8;m=8MV5hZ)h09X88QwwXFssa zwP=`F@;JSl$!r*MZ*94pM(=q|jXpRzTG>>#$0Pl1Zgr!<7pPTL|9Hxc-L`BW8PeWV zi{SFWdl0P=Bnn4-!TH(TkXxBsf9+^s=Q8k6L#OrTSkze@gBGNg+SFEk9{HL@N~RL4 zMQa~p*(~+)tfzrX58suK7``e(vJ)e%J9I?)j*w8q%mb>2uFMd_plq(^CyTgljYoF} zANmfz$KJH%qE-S&tvO|&dpxNa=QG4=$R zY%~nT|2*M}Hh*L5<8D-{_X&~bhZcbo9r{tJgNAL90{RPKWE`EKd#9DC7DWtqC0z*2o&d2#N8IKGqUBX~M ztX$BD(b4V$o2C)X`%(Zk)>FYBAzj8TY)W~r3H%KC^W-qcBf$T_S&d&`nhfJi*E}&; zlW+ug{G_hw^Ro;Bp?Zy|@!wur(~;{aXHjNOEyt42dh8nRk)guiFQf)`6C{Aurd_Vn zDCK%Spf0nc=SYbAwMQWeI|fdx{vyn;*xd|fk>se%MDS@oyv07kHs_`kx5VaRtNTW| z!-q_iBS=|Tjhh4!mo>~>4l^>OU8kOOD! zpoHpM!K=}8_eCw1s-7-|)4IWUruOa~Yl0kFxy<|)^)M!7e$YRZb~V3KcnWsk<4#vd zpDAPC-jtM`<;=*tozVoo5VMmZEw)t?qy9QEr^GTr8EDS(!2bPYLQt>d>fJ!^YHfRS z#mFHH?VhKQr`q;I;*+3U%@ZG5A*!7t1&_J` z{#_8U6-}tkajfT)n*h~0V-%SI>u_26A;MQb^SS6p0L@%5umuU&Afd%BouHeUgMAcp zO}z?lKS2K_IC}^=3utR3plYF=27Qh8K#VUy2JT)h_bTGtU`^+m7{-zwK!vO(ajNWe zcDkH1YPA#_ext?_nzmn##r;lZmzbo6A@`ZoZ_4;uehz>_a{_FJq$AAH(7K%7SQBP( zR2IbV^_et>{+9aMQaH}VPu~B*X@1=*>cIw({T4QXuPu|ukU`R{lcr1$fR;~>D4x_` zs6$!w>q(Q2{R@V0u*ZKrWmQI#bzoqPX=!8Y3;UnRjf`e#H1F}FDH+CU>1( zc!&<0En`g^yT2Q43X^=$GPR%8==Rp|zW2@7|H@tbB`qetlnuk1Li@@f*lVtqLhDWI z`^U}&XG2?_QD3cR2yE1??}~Ugk=tDK{OyC*!L=t)-xL@sygu&S5zDVNAr(ADlIdm^`^5&)uhmhz34`%7e#l8@&wL#c(_uPvZ`zeDrR1WK=up0bdw4y?5N zf;3X7`wBdyr9#`!bK#qz{XhT)^k{aoM!gNUUxp$?xbP@;c#<(TciAS>{@N5Ohr7&z z8<>;FzE)3FBPZl65*uc`cGe#pAY}teJnuZ-a&{UL;?i0UB_D?K9b^zV4+^W2d*B@~ z7OH@L06g4|^82X$IIC+FU{Mk>`#;4F-hHGL$6+04-XW)M#UK$2XnFn)imYgulaehuk7*^*t6$IET)^yBlEmVtR`a|_4mh!6lZ?E>RXd3#*bAupdU9}00>Aa7Q z>U!t6IKFi_dvj|2*yOtYRFGpy*1Qk=dcq)xxQ;_N_4oA&qWd08Tae@(z?_Yr51d1a zMbnvJoS&-ADJ}E1`ajnt=nKQ^Q@l*aBg$28~tA zj~3?m9(wGttR}=6|Lm8=)g_$4;?P{t1CuB2Fic^ z081!HrM`pL47?VWcW6vGDC2=9n6e|kqEcmc8yT}v)ZID>v){5Q!?%j!Wt^lEHJwfj zT=R89Iv+d;ovfNoNXW{_rCr9lBNK>?glfLIDwUMMW6XF5Q(2dn$)S2wQ`OLsc4$RU z8)6M-=<>5pH|S&^R@Q+IgjPt`D-n4+es=nw>4b zhGKxHQr0!Y3r=_k)owqzZvSDzRA0njT8W2GQ=f_ek3HB5x|mXE!u#MZ9qtJtv;R0m z%Pjk7G&wLhrE>&4_c!1us+4WRsK0#KE3aOm-XyKQLwwZ8&EF|v@#T4p z*$;_{N@>-39^|RFzNiDs3JN>g8rX;6%e1`X*dVASBSQ>-Nf&irTk5n$U)9q^?MAi- zx!D^s^+K6tPOcX_Y50Ft!n&xu?sHt_z>&PCq4>Qma>xW6Y8@Qis= z3F<6z5*t{O(dYuzS5zwie=?kAcbYzPVPv6fg0iyHPSgj0ERGV#E*aWI3X54IX_PVn zF7IemX(0>E3>R1SZK^F4R}U0u4L*T-OV&tu1aK zpzWGtni2q6XLOXSLFnQ+u`|P=9p`mGE_Re5THbwj&$d?{kx3NSJx`!NvI&o;Bt_RU zhll5{K;K=0@5UgjV2};iC1)&^IBCuVQER8Dowz?RY)j#eVK9os`T6V)(Zsv>k)nyRy@fM-#K5IZ#r%5)_<@+?o>PV`jJb64f(znqP2Y zTt6&2^g_Sc9-Q3H7fenZx!;7k0XJdhi4s(#O2`B7kY&4sw8>4U<)1wTje`l$M|hgV z5$ssAHIbI9Yy;)G3-@K(&+YV+_{-RIKZXw-M@)!lIHUa_aII(Q9{TIu1X{~+g`nR~ ztUVpi7#tj{qIy%yE2hh;|J4R-75YvX3X}~wLE`@F1~5#i=;6`jxGx&1Zp2%_mv|XIIU^=a z)94=q20~{BehbAdQ)H{DuX}x6qnn0JHXgb0(a^yrpTJHXWv3uhql@b_b$7qgS+9(N-Wz!o)8p9IV5I8j5`y^N+4>xUQoWt_0$o@g-tjhDw)>+@rV0vvfX0fY~Wie19IC5imoKY zECv&&0K;&ftKS)WSvK(4EU;>{Y4JkWAKApcS39olKi5GY5%k~&U*jhTxubJG$GIv~ zp`F2oWf^Mpf`xGVY4R1vBWgIn%(=e#vaF zc^CK}_WWy@v@ttux65%>9qBrmYdz3pg~sI!6Oo^SGKvc2(8bw$puwV^9AXTet!cSf z5om>ABa}#_<(#)fN0r2jL1pj;z`I`VpAW#BwAZJ`PbONtXGFH@XB&n8LrY{ zEDu6UWPO3ocQlI^k)~e0;Gb%`B4u1H0MB;l#Wsi&h&cbz)$sNdWh4~vY~x^mRzi)r zzwCi$cgwu(14UpWjHla3#8N(#d^~Lwi4>GxGt!)DKU`c?ISG(X4HZu_8i7?#6o+wW zsLgWn_D;;@vjEb0@j$(?jRVw`M|SXH==Ny=GfQLv6lYZ_?vC4ak53xFNV$1@>S=vO zqs(%UVjhQCJU<(H10|S=)}-JU6rBQZirnbJsi>`_)d)Zc;^mGTz5@+_Ql2yKdT{VEKmYP!XX5U2-Y452Kr{kiHqQ#i9aON^_R-&^K#$*049BOK2e7w zBDcCXuM)t3=S#VAXd&Z9-9U(8MgV^k;X9&jE`IVrecsyAq?V8+=N&KsLVt1Dj$M1- z9O|L!hTHxEqev?Rj@EHj9WvIW(ZF&Z%RvL+{NC08fQmpP?0{gA9wt4u-GMQlpv*0O zY*Y;$TdgT}q%t(~6j@Z2VYb)3eDvnV>^~q>P-gHT0f!3`$9S;sh8Y^qXC@4vZy^tt zi@E#(jS(cFSNOecLXJZ_Fra6(E^0}!pdbGEvd}@l`_Hdi|F3h>m*&xUSX8K>iCN>& zi0064e4;bQyv_^pD2yc+(CdHvJ@X(u0jW9-kZ))|WW$Y>UI`8!R0x)YLO#iT9T}tj z7kE&6H?+oC$vQ)zNCIB;G@enI8=PD2$a)5q5g&6e6ic+euk9y$iyYsA3f1o0GsiIl!`abz7zpIzmpMv{7AWZsK$e~)$D;~Kr*XZ zd-f$Ipf&(h`O=olY5#_aS2y`nA$zs&zpAVNLfCc-e0&IH$ZYN^EN?5=*CRcaCPFL( z0ZOS-e^SPy+`YXwsTw4mmmS(>_&kWbNk|DQovUWFLNk3eA!zRrG6CDt7e-Mp&^4~Tkkj2Yw8=z^uAA#xPwH$iN5~9AaQOjPj0%3 zG9WbOH&H7bh&(>#tR$$>J)|i!Cx3{5kOB7^Ze9vkIu5mY-7+$rGsPar9@+>zLg3nS ze-s8FqaM#iScoJzm_zchG>s9>c_2~kJDT+LWJ1sHsh+LVXi6{Y@NQL8kqkjK@7_J> zY#2SN2=2e<#4Sh;PoNI+rk0lNw&QcLrenXk_OQ3n#{xCy4s=wd#JDW_M(YZM$RlcI*c?P!G zRV~PPxCJSfZZGx=;P@D7Xqw4`hnV=p-@k<>6hD!77G-2cFG?gZ?toqoc!m`hFN8iX z2hMtdBIp7oA-(zQuZKz?;OkdkJvdq~=gt|y1sHBkLQ>`^|d)c`UYBAmH!wjux z@VYL+R%gz&`^Aej_?=MSM%1(o^UG2fRvJnNlk9dVf?N|SX7?X$;w{5*6 z+YQ&-`_G1IpVp$60(1WS)|!9$c5(~j_7*aM$47$Y(82afuoOc!dxR76U*I+x_O z4W(}#qJQHus8MxHM-S2LMXgkvl@&A|8A^{VgMqa`E`&s|q^ft*{a@_8c|6s7*EgwcgXZMJu4E1VW_whf}X=>H*7gM%!78p(SdL^C5;% zSog0G275(%#{u2Jhg+RB*eu#ReCGd%d7X*RB_R19IIrW0FlJDz;MOp$s}@@84YOYz zZ*NhBOAqw**10#{c(0kC1p*X2ZAP(87m1Af>GZjjE40*urq__D(xyp<9EYOeq}^4N zdGpX|&bL$0geUaq_s>y*R4*NJQq?Qf z1CR4LP8nx%u;-l(+w1eeSHr*hg#GPm!N3Ln6`sJFE&z;-!$yf~r0sw~@Y*Ik_r1v? zwSGIkCPz2@d0nK5XT;0mVu30wOtt8TZo2O9I(=Y`yLw)GhNTUM-+p5TZ%`fYN2Z5x z7RO6JTV#O5?UhPq? ztoZqJ+YjL%KUwz}GJ3W{9C}DOmVK{X#K5yJm!s^cujF!69%| zXP;l51;bR@%cUeAPu0s%fNN>aeaAUUGgADE(0^LLC-xJQkzcz!yo#Q6HE(9hWAEzC z`fq!sA|k#vqtc#F;P23bITXHZecPAWV5%IjrV=Vvaj0aMF6o@;42bdYI1%seECjwo z&y{FaT6ny|6viY7epAWo{AHxXbfRnl0>erA&_hhwmlVCQzffT>IXi~E@|YGR9azDe zP(KFNFbmJXdb%dEvGsT6y@;Alo{&JXj^D+=MZ$2WPj_I1ZSZj zXuhSdaB`uR-8EgQ|vV}f}N8tpYUy}!_s$9%WZ3J+a3XlmkWhr zl%@R^CC7e>t8zaJh@sfN{N+_4n!YlT>Gg(wRCdIP8r-1AH^=N#HqB%TR%SZ7){@4j zUI-yW{X;2KPHh=g=aeI<^1gcc3#Xb=()D>bg?I55!u96Y0%$-V{NOBSK$UW?a1YI~ zPshj8W*tRw%aIenMN5sm)YdJ}*p{dhI2?&fSIYTr|ATsuZk?HY6Fq`8$z<((?w_zK%-bS_%yEyl8L#Mj1WCZMRM0lj*FI19`XnkgV2QxIS zZkFy!I$>MU2a5xvz#K?b#t5_BL=7p0VP1jr)pOZ8jgq#QZ4KC7W*3G*_(cpt+L9(_ zZbYNa*@>lV;Z&zc?ctXRE6a9aaaRIblP}iNXPx`^f49={ zkLdkZFt5M~)Eg>(X!&?@Wc=K+7j1;72a6M$#aq-bYT^!d>yH&(!1G6v!RNRuy1Xa@-O*R zQF>;R4tq4DTu(Wt-z516FJU7DG+liQAsfS1xeRq6y1E6|wS3x7{N#3NsTg0yH}8JW zQQkzgEpLt6f!naIe~HThQWL+TkP_4koV+8fVZ=azG*nFD(Bd0$B}laDG#un+bqyCN zRUB8;!N_Njs4&K9lYSrdA}VcWPaUeBlj?&~vj~S@qa*aJzd+Gl_Ma;-Y^RWVc)F49 zz%F;NCI&zc5_+`+8zfkj?9vy80SPgD4C276oCM6VGQ3~VDkM z516!~OF(HO!17=-P@lRo@WM<^Gha{_Rni{vWnMEr4jo)#I0jc}Q?*D2QP!!?9kb<9 zYoPVca*KvWCR1EV_BHdO*dy)7nXEL6w9>4Js3QPi?sD7XlhSRJ7JteUla=Z$C6s+W zZpOHO8Dw#C=;^a6%D-pPATe{MMI5=bRA;JFm@n2U?b3Lp1L7UEFVg{nne0|@gh49N zbM+oTRV2#&2%56M?m1q~W~vba7>VvPf<#)&eJAy50cSVa*b6A2f%LchMup9Z(0^Zx zC`%x|cZTyT^G6_#htfN^StOAT`S<|5{{K1yTG_vR4Bo53aR(oNP(^fdD+npnDbwnG z)n$efw#u8>_KC!mmGj4^grgdCa0o~SxebTYl(lIf8cf(}7;Jj&g7(-Q0!Mq$)x`&A zg&(ICMMJE$ReDa98hjYb9r8#CsIu|NL<5P^eOLLCx zt{n4(-p2O)_#QmpJ09fxr}88!<<;>;aF$nS0YRbRZsbD&XsG9F5kKF@8z2bK{y8_) za-fHES1gT5R7dxfkkZ{+w2C3KkE+}ExAF`2wp3Xm;dXGt zZkmV%`!8U>1bN)Q$I{tG7}8BL<34eVuHwOfkUh8I67=Ml=ybol7?BzJb{}W}TcDkK z;#&#LZbZH+;m2Wxhr|qLUyjSC@uc*^gzs0Mw6*;P=D)^5?86YAvh#*Maq;Iz;B+)e z7PE>4=TJGNnC}DkqF5Of8|{^PL|#r@gLi_YP$+8RR3VQ`Fs7#A&3|^MPv}s{x=MT5 z5<%iu$<(n~=&jyY-}@RX)3uw2F_N#fcpScL`@fbF+NEC0^qou~h0QiBJg%?;;b3kh zkVurOt{P^97nwZrdzxgoRC;4Weho(-ov1k~d*dv8@Wn_Y=@&(Ob{W|e|A0*5dr5gk zpFRAID1aUqj==$aTd4}Io^QuR{~9Wqz_txzsQwVF2GYQ=0%&HRIePzu5wl?g-w7!j zqds`AuRP;!FGh6#1x!}`)1W*1CQzL7Aw~W*5H8zjRR0Dl)Q)7Fk9q)`nrV^jw0($B zyUg3Szl6mlY>$ftSQir>W$v5R@S*U3(35N!-`Vp75Ujz`~TBV)Tm*2)ri)~M7mXi&q zaoc1TUWWY(y7H|M^03ZrwQ@|ZWET!pnb%*z>$RQs0>@d?OQOAJ#qe6bxw<3lq6z%| zvU2bLe)x^S)FK}qw^y1mF4t3yy|x(iJem;{NRm7lA_ z6w;~TuE996xkW?DC{Rc+b@TR&V>*@cAnoRAL4A}CFq})*m+IryTwPeK@mC}V{$AH+ z`Urm2%@_xYLcHK#&xSDZgK?4;r&t0%_=5r zu~-X4Hnhe)Ap4ke?V<_IfwBPnf5~bGCqb>ChRQQekI(QAqk!%T6o)!DAP~meDouT# zjf;jRWj?@oJp_PF!`tr|O(NdKrY%~ll=qMvO#I z(P|$ZW+3;$Gp>$lLH%A^EP9yf=}SxoTatHcbNKn83L?uw5BlCG%(+`pIc2$kaEFMG zeh&o1k{$~Syp^nk9X_(8EF1N~`luH5qjjXB9}ZO<$(qLsKY*M7N-E5e*7Zl>>30U^ zG=cCOCc3a8_*Y`V!*>G-3&AZs7=cv%V=^<*_M4lH# z0%Nd#AQB~eky(gp3AUh$%5ni`<5TZ}GtRx3WfOpSERHr3&jPKf4uZGyl;0KZU^x~q zVE+pWQZwd4IZ4xKSK;fYW$l+^C_d{kc21m61Il;UP)hId)WFn47;VxREfjs8>l(Sx zVvR2^*#Q9eOQusal@Erb&s$6EfLzAnka=OIAS1%em!lcpgRo>Ee8#$nUjPTll(y%7 zhGuqI^m!!1xkC1L>y6mKVqXp~^S@YZBV(t5sFKq46)qbA#`8+N_SKQ&AoFun?$eKA zKnaFgWp}J}IKESF-VLl4eZVg2B$p1)1BzyZge}CR6t4XS;`%3lrK9jA(lY#_zU^l| z4}BkXe)SH}W9=`MTjeDX-@f{JAe%=EH;L4gb-&>;RJjM<&bFjAwI z>jVb+TY;awHnuip8|T=rw>@x5od`Y%J+->ms`)GIfTh{FJE!59I}HE@g)yt#tpETefdPqb zC7|3tAOurGc>!H`8RPPMKy6G?-q(VtUkVs-P6nEOM{WL?DwD+8OXd7b+_6-qO_HiU znt_%|rV?ejfMq)L&oeckc4%J5#K#_!WDw5fjSduuoOm4AV3YxG_Yh1d^}MaIgxEKH z?0P-m;0Q0jo2R5*uZM)I1a4h%`#fR*SE2<3Ku>_K`FBjUvIj10#-sXo=`KdJHzOv7Fyv!U%Qj{uwg+t(7{sNze7i0p^$0BDplo!jZD0xdN zyeD{N%ozAL+W9ds%O=qenvkH0xA{&$=Rsq{RV-cEh2uq4LmC{}V@zd~X2nMR9 z64JL|GaCtB5?=vvJ%53JDkpul8O?Bzjor4^FU5{Sv5u`4rvDLvP!vefc> zo6?DLQVLJtq<(*DyuD|_Gk8-CLg6_4I?a4Tt6HA+#PNF~4ju#Ot*L`d80k0MrD2DX zpNi@F2CKCa_q~dZp_oB1?7OMmKrOo&RE^0}4VE%{ukE2_#)~5#@~<~el3`A|7;lj{dfC* zH=@7)CdTJ~8si`RU(xzI|1bVd;eT$=Q2Q^rCVZQd|NF!KUtLD;uclCo-{pher%*e8 z3=)k5MjV0lrVbbVzF!O{otB`;Tfu3ezDr%?R0kY{e(rrRJ2{0>5f;uJ)?~jp$;coc znl03rMDkM|>DdpHoG*gb zy9L^*r}a=3F?u!WekGjvkFd$eg>_Cz(18hQz_einAF%$@UC5i-mjScg5R7THBil}P z9|m;-VPL>88NRFa*bn{lpxAds@xV)6yFfRujoTABevc8#Qnn7JSM& z4&lDOwF^P113-l4;$B7=yHC)QiXNQVZ#Al|2JM19Zst7?aEX)fSMW_}!0F+-09`~2 z99~f`H)HTN9A8fKe5d5jqF?IJk!WLWHMpV8pkLRXG1tmaei^nVsbO*1!XpaJ9diB% zK_x@U6P(+-2-9LSaJk*)Pl|v#9|9Jw?m&YmsS+sb4)a?2dLHORDZkL|g|wV2^f>!V z2e7fy*0(Bx7V-dcy8JXRY>!(&`K9M(3!GHLtuKgBx&YNfSFZv|T061~phq%Q*pVG~ zZ3(-&!q+7OXH<}%^UOkG=mRH%}b!>Ax?EZpIRX~dC2Srg7v(u+)45x?)d@T?wWjYF`DoZge1M?8jax-Pb3?cM zuwJ}$KXMAJwiCG2tgh!@>fy5Tato4~H}&#|R^v6^;jC{vASXS+@q{mZHiLWU9iENJ z&85I+UxrTIFLF8(F-pYl-HM=%byebmeC7?>x2b1^@<j`_F6lu+v!OKwo zFk47O4X1tqeEvMrGU=2LeCPNOR53w#yPg{|2zJdjFv%26!!;im0s_ghAajopx@=8k z;3=PS_PJsYLc)(Z7OGD;O~qk>bkKv#&}Y_614wHyScp9P9J?Wims$WDe2A&@TDLKH z8n^ro4yJj6*T9PYIv#D1eK~o3%P3LSc-bqjLb(MVu4f=t3>SxKHu3%bCx=UKPCMJw zoMVQG@M4K+;0(GcaqrUPKg`fvTr(~WzY2p}0tPtV497><{vp0TFm!1mFK*K;W(*TL zE|303+4bzGZ@IsjIAUo_OMtmbRLr89MW8b$hgZkkBm@%Y-MaPK!p|3n!jGw5YKO!6 zUrdjqiwqGTg%wr_kht@regxNNf@${El3U*maX8YFAq+dU$#W7STYu{ppq*-16qCR3 zx&cK((H@iURobLVv~XQ&By`kMUICU$%7Xy996Ny&n~uDe;>aYb{NSKIPzTGTp2IFC ztGIjnYfA4REd|GQ$vp!)am2u&a->O^eKh7P0GpbK5XWa7>WGXtvIjPeGI;|D+d>}E zj$QE@VjZTKXzL7mgYc5eXfvYRZK84mVU&>z07lZ8{g3}Xv3sN|yyJ|8oH6hTMAhn~7J22R}$i%>Z_a^y=x?zQu0ISf;eJC_V<8V5GYgYM-cB&p$=t${WK ze#ZI$=y&z^)St~fCKp-!dJ_l4|=CiCx?nw3WFL`G36Kq)-wB0GO#Y@}I~r9mWj(9V4jL6xebAiyF_l+U zUgq_k zb>X#}b6j*Hv1HD4Ys^3$!D>D@1pV?c`_OQ)T({dWlSukqw&=D-&d%;=NGBY(j<4($ z<33B@ZojX=u9H)bz>D2t)+$es0i#2F23Jf52%%NZ;0iM^)ho$sp6k0LSLW~Vl~BAs z-meXJ6==PPZ=)foBX|Sh{dtL|8}QovtZ9LIrn4>7w?NN-P+?j)ZJ)3RpZWr{c;8}% z;RZfAVs0)yAx}^b-hEqC{q*wHF^C*^grg&_#q>DQDv?@peuhnC`@QwXb&+MmG&4$9`_q9pMwzY@CD9N|t9zX@@IP z6UFTO3=ks>{rQNViEJyZ{q$JF$!3N^8RKOAUIjj-yFE}`<+pApybDn)Lp0@QFvp^# zFv;S$lKneW(adcLqVTX4tb*CM1%-L?FsXaoVlDTpkPi&3EQm-SgIZB{6TB2(ySPN% z4^+*4fg!1OjL<^VxQ;#$IpH+4?axc(oKP@yuB<%m;n&xDz`Y#nAu80idQ}x14BY(U zdKP={-z9e{uN`gWUpts{1SL;BFAsgCqpJ)I>`{k-DsoF`B%1{FDib5ffQP3_+cTfr z)U?7j`jK#&qRx0Ia5#b3B%u%lMTzpNNuG;l8Lvmojl!arSbI+(o}eNJ#8opK(EoN; zB|mknk)&yM{G*qj63IC_$eWs?a@q|*)rQgGrdf_>{2gh2I=Q24{KF~+uDN&eeaznP zQaUYln>yiU!9hGD+0otSg3=4)%eik=|B<9#d;CsW>7ev%Cu+z7T~MJsUx;G-d<|8* zFAzmq6AHwuu@!9LOnF`MPQ7AIpd-d&rClDXH^tbP@onEL0%WegHT9;dw6n7BLm_b3 zkom6=5x_f=fJqSAplYEPVBMr>hlr(J z(y9c=xMcFWp?8I{8Y4$v!V)5Kh>1nDseI34>ZrOm0uEU5iiIj=&Gb&}16|?GlQld& zonVv7E*1}8amL;7o3;sqN`aKH4Bs)X12lp{$gXe0W*WVhZX&KjB7}6`#-PUj`R}LL z4>UV`)s~c1^>OM`I#E%n30Sw!i9K+})m#bnl$Mo+;^lT63x3#~|4ExIw|24x@d~&0 z#tF&Wcx>N<@famBA)cITMzM$G!tEf*Zl;s0Yu;NE3l61L zsl?=^e<2!>4^U3$9%Vb#Nq!h|?uv_ughDOxx?o3@Un`)@7atn~8F&6HN4V@MkE(<2 zER+e0(B;)$6T<6Y3O8j**)=XUo5JiA&xPdl<#(NLtS($wDtC0KrXUL>W=n`tM!Ci>W%9Xe+yp@*!BJU{dQ8*OEKZs3e&xUT+Ing*H{%@KHd!d z{)yfEbO0#dikvwJoOUV0cHs1+OaRcdeZs?#{Vv!PlW^DS*L}CE2_l(C-ji-#u^~Uk1{)6YFH2WtKO|CtF_wO2|9r>W%b$b`gBwc-#U-b1Em#hj* zQki2tysMMf{TohOiEL8XHyK~{Nk}`gyEkqc&#IOgzb9m?tusk!KNIylPhHF?I&ZtY ztS{vI?mEJ8|M1g#-U5=_wzR^+_KuKl_v1KmmLpEgA?GQ3N8*pN*DE%0%~QZ^H+}!J zMoy&Y9+98_9M`(odYIGIDnDHX(e;4q+iWl?h+DZe`Re)KzZlqbk!uoqK#BItpTj%P zJn0xPD($fIoJp&eRGoQO2$QU*^&!P42U1umg`$pj-`1HQSGnP}vF zs!5h_S#nPOU8V>fLHB=^-{iDrZ_m@r?fWLJneZg_dMJ~jP4yeNxO7Fy5~eqn$5gUH~`tNcs+b~JQ$SA|(wPL;>WjRhU8 ze|OX3TRnL*B_NjLR$jW?k=su-tTsb$e}-!k9w8Fsq;PhfGjOrs3p_{P$Y(RSu?#9$ zWd4=hjO`j+SIr`=lFkV6mRteS-C&!aYNu;Z1Xn)O6u!iTDLOM(){+B#D7Pd>K+=0= z1NYUF4+ldxMS(cB=76*EF=x;lzh^rk>Z8!ryOxZy(2P-d_HCORx8LP^)bYsFZW(No zl8I$jGqRP7q`4TI!wmYaL~S9>Y%o=`t#4Y)gxm-hSl$i-MPy{G(=ak=DJqb%r&B~Y z1^Xip2aFOL95W>`WoBj@9;D7>+YbKP%8cI8T)4cFR>j(RbcGOuwc6{ncp;dh_(3|tiB zzUzL4>F5lsNr*Y+wy6Bd{W}o5nR~hTds#cD02$PU-3=zCP*+uYUgq#hfFvyA z^$#G)g~zg(I!mxwWPHukN1frl)Vo$pSdUL#7N{G^>l20G&5{d^R^g;pV0WmlDQC~E{HCxh>!qger*TLY<6Nc$uMFS!P09YJ2Ihfhl zh;>+lC|A4DhPG=V8+0WSi*jW!nQ%Up(yVv}6S*vp+@?T^RFl#!ZTB;{7iR11`Xw-7 z;HI>mFN;dFR&-}*sb*32jEOW!VPo9w^-)K;fyQ*sPebxk!oa$3Fr*vH99B1c!*Z&l zV29P|AA$P4ah6GsFW0n86my1mKly#pPNp&+?f@t4e41uIo#V2K&2gQpQgUf6!}4Qo);jz{k+eROC6|Ze#rBCOdSLr> ztlzuh`)+d=6p@S~V}^17mf0ylp0Lf^Z)p$(56HF&kEdHufU{LN-rYZ#sc_qoruek0 zxQy(WJ?Z;0n3E=_0rG44Hm3*RjbICO>S}k`{%Yz=Pq8&vl|#+ml9anuH|V(&YXRRn z8p-_gu)B+j*6Z)I>wuh+QVCKn+pZ44hz!feY z50l3PFP+&o4XMu`6I}j0Oq^60!;>LjvVREs?)>VzXso{YBoolBuz(EQUjawOvySPc zJ+1ImDY<-#+lmrREdUd3>gKV08d_b~E2mbHbFj>9>!Qv|3Ux*!(_?32f2jPyLw^Nh z+Npkcr?VGbZTg6X;eNpcA~YH~vx{;6XfvwE7Z-Uw0f1yR>P}-h z=VTDk1j#M&frwSMJT#>{b^d_)*JvT~`WPIw>6f|O&)T*i?}VE!T%rTtICxwcwjVTW zdi1mc3_JgpX63yG#x`sSQi^li-PZ(>SF=Xeyg4W=P>4zDZZg7}y*|RXqnf6`@Q|qn zKlvthRV`o*F(?Yc_jlzD$Oa`vvvdBIVLBB7zQlfP*T~*osnkf&1OrQBw?>GROCKe-OYAutG1C)h4LAX0i?=$=#kEF zjz)C6K%~Bh?=>j;jwC0B>kDijBCzcjb*_4RCHgVcfJpB3M^c&EN=;>8ABxjK*;zM_ zXBH+HlwNqiYzyzM#iJ$1F*4)l^2M`;A5_OarHFGY<|s9^!^3mfzOOyMX|tGcjYVhm zicLy@@b5}8zN&QGP}K2?!%ebMrxUWE-r_20Pk~TtM(<`ItMZLr^o__4lXC|pllNXQ zusuNefEeCp7UjiR(B3=<+*(Nuu*6*vZVBy7i7HRXx!1M_B0Q1*ta?E;LPB7B^~ycT zDfZ{$0zE2kB;~82L_fo&lU@4_cqAzsn{+(j`VY=_vEOs0Ta)U_*wqN zRw3=rk{t{DjJrFJmGlrIf)6X&jvQ=dIW+|*#!){Hi-a!njcAZ1Hlw<;G(Km$g6*?m zqSu-ZPBR13T*4_DQ)ksi%2Vg6GuQII3rXQ_E_Nzf+Rryc%i(UnXw+S(ZGVM>w{khv z49x6mbfgT7R#Q9p9d>f&FC;~~4|}ZLGtzD7aC;GW=Yd@v^d+3WsHNo{cmm+t)Lm7^ z<2Ltp4PO^_&+&wI8NGZi(V>B*pz!2{p}}2o%TeN4!|xT@Tm*rw!P+(yL38qh6n*aU zN3uY<%sHKr3TlN!K#%w4^Qb7d zlKF$mWM`ClqnQ*!hDQ^&-rH**#QF-_mO&A+k71t5|rkoOJb}Y@RUA5hf}ZB$iQ;{@Q&=O66s+>oD{>+R^|af91rX&EckNI z+g!H$k)@K}HM-q{#w4b4B;zY>(K_}ns~S>Ah~c2lV`|++(62j&wS1poi+%rn4Lggw zUn_LbPmiqSd&9wE9WQn9b@ks5)gSmt+}kztoud%Q<}hLYvI4?Md6-)!i=2Vud3Lq> z?j=V1c=w-Mj(+$D$+4PBGevWr0D-ccbiRbn)=K$63W1I0AWC49A$;t{T!*YWXbFm& z#!L+TRl@oT*n_*H!DH7@%p9+4JMACjsb@R*g2L0&`Q3qo%@lExpEQnSQqGf^l7IU*Ilhf+@z5fEG3RK*$F7QR#4Hl8BcL5Z)Sq~FZBX-?{3>QlM?3)S3E z;p}i*+xfEr4Xk&w`53sySVk8o^hjaB-W0}AgAUvaiLv`j#X)m{uHPZ;DYkhxPoeia zR;8+#cjuKt_I51uCvX+|ruc4d3=f{L|7dpQ(Kt*;{SO~l6GP+`+!!)OflqkP=0zk* z2)pv-8eSg%^0sh;1!-?L=rfve&{Js3%P?@EX}4fSJo3%_#$T(|h0X6??TJ$@anix( zmvixE;z4$zhQW9L!ByDj_*5`B6J&R$KK{`G%HuELFyC5#b zvAU5jqJEFeFf>;I7$BlBJ<^sX#uG;2O7*7iry9a!lI`~tTB2Z9MG2j~^YQ-*m)78i z^+zJQ=jGrD6wtP@xqAh7Lw+p1x$030GXi=}6KexwM$v7RjAzV^i@CC9|mThG?}MWQMrQf*XIpIj6g^ z0i9)-)~|TD4|;^NKqy(b!z72-?Vmk?{kRT;e`zY{1D)#yIb9<5|7Zuc!X7d7CKO@J zaicG{u*6IcDGjmre`gf@hihaIvBoVy5hyI0whN&P7=ZB zzs%IFa{Af_Q5MrI*3LfYN;PqcDWUDWH82JFi4>sk%CmL<>uTQyu|jzQ;5S3yAk;#Q zEhpqyp?4Lt#H`^L9tOb&I;>Gnipf9c;gz)(w&<`*)&NFE4Yb`Ckyv#6n0Us+eIL-BtnB!hli*GI(2?tZl2M;Q#6OY=-pE8cB$h(z04yLGKAG_4COJP{IGDo#A>q29uYDmh6O55wr|` zi!y5(oh_s+j2Tju*3qB@>)xhf?7F-tPCYG9+oP#4EQ-R_;L@w`YX7432->YPqyQTgGL>so>9f_aeo>_1xbihn;e$N zpR@R_mxudn`VEL^wti|~ijG06ofkBMgKIT;1wN_dq#|as!DR!i@`!7vCE|Wj@SFVc% zb#@a&kTsvF!F4#f^<9iqEP)$x-A6_*ViL^iFT}|PsN)eRX8Ch~k~?9hFPR2qwT_Ah zB?R0DN6?28w%9SZhU^b-#pWjv7jprG?}D@|R&GcuqYNbaC%hxW5SJJU(~m9Po&cRs z(>vhd|6O$je>!-rJ?gwrfNcD@wPgEA$ZTEXTQ0&vclAX>%iw!mJ~bxoE5u+)AovygZ+}DW8JpBD&0}UILM6X?UF0t~MZv%#eU%G$ zZi=I?@GDr*HOb8-3(#A&;MkAK8F4^12Y3I2ieOZ|(1pC1UA@2b%3+vwTT@@#t4rn5 z!#m)2zpt1f*^SdyeyqwX8)iF9`SDGOSpZd7B6O*8Z0rH9==+zT8>0Xuv(7e}KuI?Y z{8pG*Dtw+fD+;K%7HF^@pjTR@Z4N09(4J^S!sm738UzO6ey0!eqjU{W*oj)07#hDg zqF*l;u!aP{TZHq4(5PhvJ*oyE$Yu-BYMwP=qm+m`{y@B8e33{I>Nu1s>cg@~; z8MkXXLu<2DTf0+XMlzFDVv^fXoxw|+LTPnawMA#8MN_z8yLDQ|aBk;K5J5eM@cOVt zh+T1t9z$9FQIiiB&gNQHi}l@T#29%L=VNQhA)p2iCxi(<*aAjzBm%Z+@I~?0d|eN$OS%dc|!CQ-gn^ z**n6S_NbV}Sp!6M4HJ)>LAe)!+5?;wc3(O2AyESrUws29NHtpuFr0XpAdsZ>6Q#GX)c{gGi z|Et0wu#AYoSFp*qWyhM&OtU&0E+{gK1sE{i;@aG(QXn00LOI(BAXzoVK9HHDs^{m; zE;DVy7*2RV>^OT1p`$+1W4>7J8Z=hXZXw0J>jwByoY;3F;T|NTtZda2 zX|)?w>&_A1Qp0&%+j-||x}dg9y?1(QSgmaI)W;8q_W`;}rt@3F9=6L4W-NRa7`&L& zx|59~$CJ=02*eQyk}4m9QZq656}aMu%^-z|=)4}k<9v{szED|U6RR`? z>Lfxnm&pHIWdm^Th%@*i`_+=0GEpzvmVTO3+ajKF4Ao`2%833rz8Z&U-N$#Rgy^76 z&x0X#m6>}04vZzQoZWCJdKrh3wL;3&bC!lrl1aJ2l%3k7_|#!E86fY|rNUDg!gq8+|JkXO?;VCYUZNdVda!n(86BX$)pK9q{I6rV97usD>;}ds$BJn&7Y1yq zBz~1j2T`u{H_p)&LY1%*mm_b9BEiEG&~yP7=XlQ(9gTg3?PEF5;!l#6g2&WzimmUB zUGWKy*EkX2RCz;nhm1lIs)5lWG`SKyZtL>vc=rj%H91S{{gN-%hz?UQ9^QKWtu-A2 z5Rx0qT)eTb_aH)xg)gk0CZOrn?fSjzcJTA;CPujq@o>n_VvCM8{L}HoM7SU>5N0d3*fGwRtw&oGu-VBm^fopA773r!4%nmDd#Pf zgiayf|4ft}(d03R!sru#*>)}rN0q*a8FR&UGksIxjUVn+ZHhKxb`0>g&fTmU)}_EG7ynu8cJkIdCzW?% z0v)~wPt$vnaeLlP7bq}X7qYit$c*A^;=6-Ni66~Bp?=DbeX9$c@C~;<`zkHY!b$xk znJdkkEABLjQL7xZf=}|bm^A}jN0~B=0nP{h09q3PvsQ)NxiClTM1Mz&+FC{)kC%0C025n541C!>LI+#3F-$`!@)Xu+GJ=cdb zHJV8?-MQE0Z6bUTO69Ef3YklDg(EbvXdDbWBe@ZUY4gC{wwAqoDXmv`fFTAElM>c|_pYH$tvcIfPW1?-^s z@T3L9{5|CT*S3_d&`k-%#^e=pG{HY;QzEZI2$3UCKliN4X{uKv^?GQEnn8-mC&`W* z@z!?!l0QM!VTOGjG)S6vo*gmf;;oIC1MOYfuH3B-s~|?t?8@5qk`>Z?q31SsnnzgV z&e)#2*#TdMk)7b&wHQb43EgqkM+pLeY5K@EsDQUb9Xs4Ec_Ze500PM-`1Ela=>m=8 zUY`5SkB%V4YTel3+b&GIHL)BfSjgRqV9&Qaw~CCmmah4Obln5RLLqB2O+kEjZxZ-C0dawJ24YHHZ{%w zefYUc6IrC)ldG=n6ZWtu)F@>CQ}R@di5JBKIB2>&cEQxPVS!j0bj~G9Qfo8v1U{$~ z7!1t5Lijt=PB&9nhxt^S z`K6Ym1^6~-XnJBuqw*5ue}c#)a~9W~CsOI|J<`x;opwfs@u{x3tk7`=EXnpbSJ=!&a0^VtUj(QMZ);fnE%qJLKaSA0QhoS?a{<;83jc_dgM zgXoFTK$;-K){UC&O6k`3|6=!H51%*3$oc)7*3me(<}uZ?#@2xd{_p&)|9%cwtBt2+ z)Lwf+SuxZMN6|Q3ubgFap~9xusnYfECS{2M;Jwpx$Ey9~@dUvACXN8Z&OL*7!V01p z&Qeafv!Njxt;6H{|a1$&o0jazLoyM)%mi}4I1{xumS37BZ$AdT8?x<<_!O` zWJt98UGrkD^Pl50(v$ng#elFO`SRZD_RElXq}p`DSr0_bZ&($pyWrr+;N1NO&Fk<5 z;F6C5BD`#GJ?ySchD1U-EHtxo+^!EdaT%&pH^Cbw3mJU4@)`u^>w zDm%iqOxAe660qD40TFi^Tm?>EhvggSW`Zb})@ew6dlYhVfiAIP;@F;+^796iUfrKI zJ@zH&9LRT3b?N6@TEZBPYBqSF)p!NHshaJqrpNq;)1b?6iw^mEpvHZ585&`Y;ZIVp zf$qN)HUwgH37MOsA5{;^5Bl#c9$LlVXr zo##hA{_I;hnFk=}K^~Yy+}tr4bF_(g(HS(;8h|{wM)fMsfO#cHY#9zT@gg&5`4=NY zuR*&i24>(3$>?NiqA!Ji={|QBkxZqSCP zw3j@F=U=b|wp5XwSB~)tVZZhtR zGs83+pY<94sSJJ4<7Nb{xIvRo3SiX6U*)up=)1ha&l^o#BiZ#lgCnm6f)1s+ z0Lzinb7-z0G0O5PeWJ%%r-irL#&A}K2r-hDIM99wacYu0Nx6u0rItK2NX3p*7 zFT>={)v9&hL7Xq5UW*%^^x?A%Z%Lj27$f(c`yYHFK4e(oBvB(b9PT%DdIpu|`;NK8 z1Q}M3!5NQy9YA!{fxyn-5F9Mh*v~&tR7&hD19V1ru#lV_qM%MBTmw@QIcF|Na6i*a?_O!rueH)AE3hE8*PP7r3TY@H1dbZ@LwR)QIijdRNtRC|UE^(qyWe4k-AmnK}s z6g}UF1Ma6)_O-%0(Z7gY*99APaLG?n1%>zGQEEt-h4=cfr-mU@Rb?;Etb8NcP;Rx| zJ+WoM#0{a*iFuetr3%u){c`lCule-{SmD7#XD9R``gg1HCM90R^akADtrJTa!-?Ak zo7+@x*qdSCD&S&ocT9DG1Q9VjtE+OodCI)cF%=Q{TsUiY41>A-++Yq;&s({VWe+Uj zL}FP4(Q7Wzg7R&c%g8Bim&p{*`baDh&fMTok@hbr0V6(Yeu;G@ zE3fe+sCz@ny`Xx-#eW$y$r1s(E50mpJX%no{wFXO&l7QpN@DC6-`Ra94W?I%G#DBW zJD78^aoj!jJY?^cr|K$i#12E5ck}nL#@x*Voyd#gRM33>tWemUFsS(^3mDu2H82`U zTRVpKr>nzj+o*OJ$lM0NLc&3ZSS&2e+6MxO$%||EJ~=r>|T>4 zsF@PaX25udU!0R>jwze6V+d%VM{5td>IKV9Y{8{cxEAu4Os%IM1esnneA5MJPGQYY z3_A-4L5|0Z-Q~d*CD*}CG^uRqd(_?Nsa zU@=1|?!ZvPs8~`>Sqou3sLn?`0MF^~{{iK#{B`Dk?lEu2eST)nyARMI*(J;o@2GO? z8QCO6vKAX`&Ae7?%wIr>$kY_^zAL=gS}5Do2P2%*-H+sJ!IJgYW!FBnjE}3biK84} z8-{BEBSDYg^v^XIX5Njk@ivmRLg(&Pr=l{@P0oC}0XO612Ugus9iM?3Q#YmbH4!yk znkVxPUeadNcye5ZLSPD+{d_QvCCs|-rOGSMV-SPn$NouzdbZ2_GavsBN*zHw8d1r- zR&rbLIh#M~1mlI39J#)uNca|JlX9=98Z3bgGqU_0NIET}W|#F`Z6A_DLmIdiP(nSOBJEb2KL&Gjzz%o4-@F1!4EPo#__3l;>keOrkuZWZd7_7+TPbDa-|m)}nH4 z>h#6<0Kc>G);3R1R%httTSKp6_S13>zF^>u6$~M_OK8Py!UbP$cf|_{oASMJ2N<}` zqbH^71{9~{R#vuKSZhln?wQ(5N2Ygg%c~f)IpnbBI=~i@o+N+X z)8?Q1dZmQF_nHd}A2vApk#3X+j!%~Fn;T?3Y6r|J#pEza_<{~qHh)TzwB=w~G@&Dy z!G`hN2nY(lOoQ0x-Q7?HpDQDQd>05Gg5TIO9*3e=+iYDhQ%?N~O`s-XJS8+KFzC}&a_4U5Hi)~&jpC6Fs*5*rGgSS>1txWl2vQY&LM#l#nW@1I zxqy~`qcA@!HYxQ=jPHkQQ8EN~vtdmqCZieLKYCDUT(To6K1C<@vFb4?c|}jccrbN& zIG{>MXl)PThwuTgiu38`IqqVh1oLy8+IcYXvdUAKD z+-OIN4CXzU3Gjk5K+uvyauAKx?=g`Bbiklx#YPvylnSvlmIED4Q%Bq%RBl`aaP~=g zDy^4~p6gw_5Z7h^8u=+lpcR%pc5)y1(o`$re!8_N#yVqDevZ%{5Xc(xUWYYP?-hM3 z7AoCU^(4yDa8u&$xWB0v&jxJ%z$B`g_l4(yOtZ{V6 z4j0mg43;myMY9YlS}4!7J7A2k%;KfoA(aBmVyqoaY66=N3QspEVgMpWKy-QWm^G4Z zATu5`60tD{8=2#TUWFe@ir_;Ltn?)id<437=ozPL1tnlmxNgUZw6tE8y~jGLF(d>2 z^Jn}5?^NDCPua_LH*^#6*LOH=>sy*GfBtB$y7ivqG+8&)<(})e7crCw1e^hQ{73ME z%HkC06(4rq!6kgJc`O(^lKlUfhEh&O-=__ME_!7|17P`={BdhWnceO^j&yYt(Y9TZ9>bv8*+W+ z8H>suXvDR)QB)cwQro&w$4M0?(p=%vXIp#!m$QOL~bhciSIS{K{sZrI$ZPmyCVwf!SWg-@g6 z38SF_<}=XYb7bXsqgTP}d>)j!IFL>)qd@{au&wlbaagr@7)`?%8f}#~!@%(0;Rx(o zm*Ch%FySkV)A|`j^I)7 zhD>+u-^36cIvi*qgoO z&tW+P1HfrK$4eUCjR81&2CDE4eJD81Fh>51v?F}Xlpz?rG*PCzZ4$gn)zqCXPvN(* zLYWG-B^@vjH(z?Fae1@o`5RElnjvfC0q(HH7zXO>@VRpE?LNaq6Wn;43*y#q+tl#> z2Xnk^lEx3!q{C>lI6d?bJ$uuTR>agn6(zDvgV*6KE~@=%z|H}PG$SCbE$b+USa^T@ z3aPlZujHu63k=(Is{9DXL{g*c-?*eKnXW5@Z6%n^Y&S~7`KW^-48zgA*WaNM9bSmQ z1y9EIb^8boeS@i{zO%dCD#kwoM`A%=qX6>hM~Z)AK)si+K>l5!{H_;aZ99k8Q%peo z=y4No4KfJZ{N^Ac0z)M*R!g#t{2fR-E%fKQ!)2ngbx108x$P|xoQNs}(vMVNnE>T2 z@gukb1$siA5|C$~N&=Y}GCAco-4 zXC%TOarT*5oCp!?Ju$H#o*kJ`Pk^tHF3+H9GBEIO9#rG^(_j1w&BxXHP5jSMbAWow zutoItBG0Dp5=D;wW&aF1d#UZ^#@C_cYk`FjmoGFAqpzIXbra;woWZ@W^q{F5dF&gD zLFj}b*JluVEh(*+8A*UE@j6d;^YGG*S8vvC{x)Wf#tcl{bV^>M(tYkGW2`+q3m&DA zV}r5uXOT3v$>MB$w<=gCQohAycMGdb@BB^BxDBesr~QeQ^}gQ%cgWbXs&oFr+65*Xs*-2Lyb;oFOP&~so*g}<BfBhaG1b#cDy{dXG1QDM^;6yaev^XZT0w9AIwJPJ&yb%R=e&2Rifs zJoa8;i}m;6+j|2DkAtZqu7Y&Bo0SdrkbaT1ls3$8K&hMTG71CWKX{d=d#|Yr9<}q2 zh1Wi6j2IrP0gS@-j%YJaOBJ`%hg`VUxwFHKTQC_b5{5fLo>P1u5a&7x^OS$%%3X;Pr1qCpIwD7g~T^SfZRl&1?GDS z1Ya;$N2KgO2AtEUz2ef$QV@5zWnzpuHwlbhyc_K9I3-bUhJ0(s>+uL|Uho&+aiCCi zld8GwW#KcQE8defcO=)h_xLe^-6q0?-yVopv0HrW1WiXvN7~VvLnTM?EVaqnbgBMv zN6GNbKyFON_l9^(_{$p+E|AylGjs)+{-b)fupX>7HLoFdO)+W^lhkXRX!$q;>mD_P z{igIN7r%MR8H6B*VYU1)BrfR}071;qt;fZ;HNK^f;^0Uxe& zd4da+4Tmy$f&O&T$F=Jylc|CZQ5>2M`tG1*_zfXF4(e1x=Ow^wty-@HwVgD;+=Chi zQ#d8;omb%NMT0RXV+Bg*i>7(BA9#4&oA1j%o{9sZz%v_24h4(|aDYS{CQ#-we~h*I z&0SXggL@j#5z^dNIf1ypI+DVXrnfgvVs_10YzX4V3O}Ad+dmW7XX$h-Tr@RGiU(4+ zGKyv5<*Kn^iaAte*K7#?he2p>nIUq=(b#l01Mu3E(54(CsE`GLTzVzS2PMLfVz=M2 zpwwsw^+^+++r=H)!{+~|y)TcaI)B@j%yio1RJI(1X{v+5$R345yN-?}w4PD6V;4%2 zWZ!0rk)vqEVhywF~h* z9$KxS*s*lGjPro*@ZoUp1VCV_H}7ofjKr{a+)v(f$h*5QVyNT-+$Y|1fb8r;YlC<| z$PNx)0a+4x8Ojp0Bgh!PVQ}p$C#3?9`O8qfct~6U1aI;k+;>md_d!m z**k!@8;TKJ83h-etl8TW@g37>2l)0BJ`ye(3x6u;A`%-j#y}vn3><|}ta)I#0<@xJ zsdjW!#38d$SQPasU9hIMW&=K>p4{22v}t|Jc^NC=sty5;ttu2ru=Rf$9L6##2Tt{t zXvgv;gc>pp4Jh4UiK)15H_jIgA9dhs#9=a$X_#HgZ)hn}fjR+*Sr|XYg4j!ZG|+hJvF?#8ufs%l<^; z@C2BHtX^eH6JW=|&5*f&vMyga@)$K;Gx8XajC2e59$Jyq*W9H)vjh*^2%FY2*bZam z(|}!P@iE!~?kZ2b<2$!K2~-}l9{30+2Z+pUp|5#_4rqjK;k76~{fY}w1`2cQ*wZCp zW4{vjttH-sOQFlvqb*Q>uxqZS61dE6TaW=9#EXT$ryJ15Zwmb*uxE~g;y;;$I|HT?jy)chaDNxk~k86iI-?U>I5Il>o;lt^a4f%lNgQHP_~c z12U_O*hJ|?#zGz=i|#W-5jy?@cP?(~R*HP+=1Tz@Xy|BleV1;Mb-$`$zo%fu0~`-P zxGa5={izxoo>)jORA$i%87#H;l;#WQWsJrsNdren_5Es7aDLoHW*8lmY=Ljj*1}SI zxB}%eWng7HR_=%xCr;75S0=LS?WpfmG>$&bzeHQ9#ud1wJ^K3=q+0ToqP>dMgaYpg zGz#TEyEdXJN%J0bv6-$*;6}BHHK=d%7RazhE@IpWqu}Ir)3E3cP!-1A!xmR#Z`avH zW}7+fL4-4-kdSj7(Z`r%#zYw*`+91pqm=(2)U~Qbr)UvbzT)9yrWUs88ZmbD7-cpJ zYNp0kSXfT!u8izTpWv}bmJACUC$1J&q`LJ@8J?-Ma6cd-ZX1Rst|)~B|3(muS0xl#=fEd|ZFaiQCAn{UUs^9HG6 zSi?U6lBm!VCgW4SfU=uAH~4({3<*EdsjJj2XAE zqF#znxH$3kE35?Bl;%0hlNQ*2jQgV&KteAZDW^+9`fBJlpYotG zR8dR3bc}NSbu}18ynNeU0S|o?Ht^F{09D;K!Ev21H3!B!JC`Cpq7KbWqX)3v-TJ$_ znxW;IN23(+{$12vs`@6+bR8-X*gm|ALsL)wJ}m(qpXBo@dA;WV_+s+4)mIl0pPxdG-JkuMUigFW5nUL+FbAtXTWPm)E(|oZ%W_EcZJ(8D6{b^| zZ^fkN*Gs=P?t$7neo3gRnoum5QUJ8%_QPs@0gWe5i3sZ3uu?uc(2mPXM3D>83~dwa zFR`pZu^5Z6JvLw7{~6@92DF_mm>li9erkW>j_Ax6AD zbilzy?kflhTt{~DdZIK_+jsfl4IH%OS$Ms-7y82bWnbWTO?fEGVtP6e<(5kD_Zk zLR+&U;<-qaw7?Ocun2i$b6kT6`ESL&jSH}{rrfE_+5+ZHA;DMimV1k02~Jk9`eP21 zQYqP`sIi+@CD%}<3J5`un}_nVm_sV4)&gXE>pI0#r+jWpJE*`*sm^F)FK%5{rt}&; zrB^BLPj88Ve(?7V(80rpM21X@B)+dMuWHo&0yTA{)U$H+(QrNf2qFl?f%iSZEw zKdYgj8bn|*#kM3PPtdx31}uJ%z6i{1;_xeAz1*gr!s67Bhig-B;rJPMHz+xO2XhvA zE^!S1t>Mc+oFKaM7XY`E&ZUpwP%n+QcXtS-n%2nZgPc?Sr&gMu?jcR%rf9w(tj!#Y?y# z5@qWQqGibj274}`h-=z4HU4<{j%pj~7Wrx?>Pn?*5u!oF=Gx|MWNMvr9gz^05-0P~ zB6w9eF*wYU@9kNeXkhtee~K#MgiliIC^S^*UJd?`ZlVpwl>KlyZzz9RwB1h zYD)-fvC7e#I(~*m1ZQi=dTz6bvBS)%`C^Tq#iXVP`E?(rQ9hw{lCQYm+_=F^r&5p| zM~H3&iBl=BBeiyyeu=#A4We||fkMU0pxA7)`rx(0_c=Bt65ZtjdPO)yU)s7SxROB% z3pAiPh7VY*>G6dgM|pG?Fce!xnOw-m};*CcYg%Sj=rIf0aJta9XmvyK^t+T`8q7n@lh>NH}# z;la1ynR-t~PE61>Q&Z=$x-sb#BJZTs2)Z}1BP!Y@|E(H-ow{Wq4)J+%jlylVfAfTu zCkI+_o#NbSu8FV-gY49)M8)bKz;@a$XM}ra^fCfEQ^#I4^Xo0*m|X?+Is-JN&rGD! zl<2gxVWAGxs%-NMw7@VwLyzbZ0TXAj77%5|=O#c~N|B>CIr zSv8GH^>W|dNX|-`jY6px?G|`U0-ALBEFq&N`W|%E*Ma{a^2onj2NCFO!mqV1n=b8nnB}5fWD?x->dvc`PXyQ?C$ABO+OgR$Cc!<&Nh?4ocn0Xd zgD42N?Td&kbUzx8U3Tf-FN_qMka&@jERb}AMcG!wj1*_zMpK}s6F43Az0N7>3zeY= zy3>N&!xBkB$JHEm7j%*)zr%#~M0~wuJQ4Ci!E}P@pc$H(1D@jw8g3`~6#Df~OS3Ws z`&c47{s1ah{{CA+m%(=hBF5^hxZ1p@jV5bmC2E?CV2q{otffcu&tNcr2qEd5CNb&P z55a$Du#ydA(aBr6`6(fp%Vnl&WQfLLb{>iapWq@%kTq_C`+L?Y__Pb(Y3Uza0U#M> zr(U!KahO|rFCk8!(@SX4_t<~N%3uXIUco^mwTwYK46FYuV+%oOa$_o)5%BzM@C2dD z)NHp8ly#Fms3H#TF7kG!CbpPZwl zH+%%O#UQJAqI7_C8OS;#v_5_Ry4iTiw33+$Y~!vdc@8_2DfbXio0mQd=+Snq$R#m& zGMG7bYRTO6cPL0>Mo0XPa&>I(8$*vAuKWO@81Q(s)od$(=JVvQKQg9djA893sw?#?1eV+Oxc z7xMDQLZ&Fm1_$XAs)SV}ol{H}*-qV3-t@oo&AoWkIbgOku zSpPb-UB6eg`s>sbgqBpb8wlhGoZ$?CHCTWZz|PfNOn|O;tnhQboUS*gs=R*^^w7Lz z)O^h%Ytlh_!a4~pwH1T`5lQxarj0jDP`z2$m_+molzmX=q}Y^+4i?JLeZ>S0Wy-pl znf;#A^UL?&#+6OWQ7CW|uC0x(z_{U7WQNjH z`fo73*RhBDbzEsemGfD%t#q=kgsfb}iZCXM=Vo(rb@%9Jpx&~>~;xFMLzvOGqq z?Ivt8+^5dk9mw1ye6@htDZ2LtA)iw6Gb8~&`LLnpMGeytbZD%A0T~C&ZR8r1k=Ozq z&zy{x_7RIYkLeUz3n01~^mCY+yiRBo>dPHs>S$e(A|F-#fm|gND)lO%AJb=Ovv4Q5 zO%~Zk5?$oF0NiXv^bdG|;@6^^i)IbP7&m`IF~(p80^>RF#rwj6c~*W0l~>~&Nr4qM zU~wz8#T|5ZP-+gmT*+zkggRnqj}u7~Tf&zBc=KSEWDPSBt#q4z{WdIRVMUWG2i(QgOU6G9J&{3HQrZH> zEou$*ky3073_-7-H)D2SJbA1WO5lX~Ip!y!y}y_r@gSr>8tV&@@e@89JOKUkaHT!1 zld*4Vaw;fe=Z2WURB2~gNEqv3A84x%f*k7!ybmXj(=x)QN&rf5r95PQFDf`PW)>Sj z%`amF{6ts#Ot{tvXKT!vCkV<&u|!SHa`67f0xa>0krX+*&YmSG^;)2B8XoI|{o^K? zEXFbAbUTO3)TbIO)j;SlbUZhgfHg}{+z05_GRh67CILCS_&!hIj!v~_&49Vk2jQ9q zPY75Rhm_UXd_ryQqcEvHD01eXMNbgJ!v?zH(z=lu!k#lV>;5h6#-s;!gn4B>?c=* zVW5yCkRx<8j!8z(h{3#&Joz-e4i*1f6fYItH0o3-f!!v2=K0J5MWL7(D0YUU0L}KB z=8MO-bP_x$YM$oGrdx_H#!ai8Q>le+l(sU1!g(j6^oJC6_x+2v)!Ov)RC$YuceAxk z3m@mpRo|yJsw4t<9z!mx&6k@#w%~U%pfB}?!Mr7r^DJ%s4uyG0_=3Js$q17oXG_d0 zTs@{HGP0B|5XYRJ;DI?gF*fiHCIWW9WOt3I3Cc)fH2f%1RRD#!FKQuvr9B)@Kd>;l z6;`ibiWJ42QV^=SBA4v=WL13!h6g;w)vu4=WM)}7W5?Q8ocLrmVeY8 zoyTFcoPtdi86v-G#Y$f7PT`oJ_miFx6M}prW$9X%QP^lt*=4xdgZ|v45le}y*nV{p z3aa1HY|5zza>JAN!^yjkG>oGnrF7A79xAbXWDUf+u2@4XSZi&Po3_f4_9}|C1aID< zYwV{pfBq)EBD3bJi}tRpv*OYXlErFKhy}T^Spd4rnKgZvJZN*{dmfv`*$rvmpXs9R zo4@D2U`N8^pfk0_JfIEPfzLoC4Uy?CSIif$Wr(OeVm@gjK_}q|;pj%Uwc#*p1+Cyw zw@2s`X{?xik`VL%wGSc zwRg#TuYKwP^dzh5iysxVE{CG8xN#4MS2Ig_3NRsM%G%p5obsHoVA!j}>K9t}02=d0 zL-X(>IPgQ2_!wi!vmw|{?~g|=By~_W*_&2I`pu(2^q$N}5h%k{ZEv~ElOxZp4Po^Y zK@!;x85lbwt%*hQk=BK=v(S6ph2cmgqg=q(BOaZn%}3JhXgTs^0o6fsp_q$d3ORJq zHCLdFqga<^9Y#NS`OB9{xsG4~=95?ssO14edGwSTa}Q;z06ssoY5^czM>PEsTeF~Q z=Kd)Z#0>-LJn{zq5$q5+#sLaVJE%xX7J5PpPokpVX{5O zyQYm7Kpi)@%4Omtr>a{4Y~}|mh({y6SchIndv>uG_a4HpO;$x$i3^^TOrQs2rcbv}`X$lf; zHG+f>GTql@s__di8^qXjAm~e*CXrh`nJc~RA==h$@12I;{0-e=fz?-={}xyWQvb{q zpiu@Z83BvWSP{$R?`fR2BnfBM5_pK!J3#^8Mf-gq@t$e&64Y*7n&{d%F?TIeRTh8- zO){4k!sMrH%m8(2_H_8sqxHaCnBT$yglpsQsCk-c-x{Bq6SND+Ashq5$4#)ESyTeo zW;&Gn_df4ZboVB@MhKYljZ2rj0P_u!&01=qgAMr&IPhd(C(#tMgF26A1Bd%NxSjpgV4Dgro!TgWQt}JvY51;kOM@O9jYF#7`}RQqAD)|BfiOwh zgJ+IeX4F|U8gHnPVwa;d0UGga*Wg^=%_0U?J9vrQK8XMTA%i5|4w0QlYjmVz(p;|s@$1B z3`WLLoQ{&NEw4BAwP4Y0s~^Vm3EgjG+vE@*0(&+j=?_n>=u6SLI;1k9JeE*v# z&a-WP2cRkK!HvBEm*_TMI?m@`HUboH-bs)4{7=~LpR^_xt!rK^m%l`c2<;-yNAXi} z2s7ugWX!6x4KD!QjMx0pBcL zU7ww)bN^&N&=14lL@ z2lDrgN|X*%iju0A=_U5PBIq{2MWgO+QV)CGsw|6OQ=9h@h?S|M+4bP8bxW@h6%Zyb zQ>z)TSsq}m6-2SS?wxj@!S}O_zQI~Ed3^-YQi4H6zNskYFQNS?h- zc%(nFMOR*t=C&puU44c^<0i_0l~7$VblROLXgpB7{%W&8Op*+tE1GbY(ovKLGC#=q z;u}jl%b0JHc`4S{QNq!P-Du)wua5Rwd$b`MaZRQZ`bt+7-S7SIQD|8Qp+y2tdUXe3 zcFG+44#q2dRyz^gZZPaGz;019XcvxovJdMlqX;H3g{vCp(ar+5q+)Q``1 z!?n8Pvjl}xLov=W-Hy8E5-xizv6TYhlfR8YM10cld0>Gs!R*bRE3p4ByUa(rWfK|< z_NhdUTXUSpgBW^=M(FrDYubb7v`#CGEOhj8WlT0K#RM(9iYpaD$+jG+Q06(27=Z+7 ze+#OVyg%B&P7BnmR5jy!nA&1Nvq*$YE!U|BUQtM`uFH_nW2-7BdIwxZ9L6eJiIqX= zb!27yegM5TYjzqk<^1i|hWI(sBEz5EqKX$EqV@UUWqf)ItF!Lo6i_?5&Pbl-6s=4P zWBOQ}c&bwUL0t2K!{;w2v-81Jx*COA+zAo5M>m_5M)r7-wqo!D$ry26Ox$~Ux&x=0 zyhU9Og*1IfWJUBigJJrs{wXw2wmXa%8ld3A*O=vEceZLf1)NPg@CC##-6Kl<<{LR| z#AYz`KDJ4?ivbDVwrFJD^$940!#F0?t?lwUyjNV|EIRzF-z{rUs(&+iXXda$iHgRm z-Ee6|T;L53ouek{Xy`zHCLl=d`-WXsL7HZ>8o7`>lIGpyl)m@k70dH zcb41Pb{=|%#-uIi3n9houXAz7o`s#I=KFX!c&rR_A}@l1!*!5L;>Rl0RZw|B6mXg^ z*x7u66``nXqs-)$`Avj(9?Gr8R$@`;s`CX5B1w+C%<1++~A|M2F6b+Gd=s47}IGnHFrfbww-N@i}9;Mn8)uB^n>E|)sJ=Q7`i&(yYTEU-OUL2 z7g*0hdH&$K!7^AUPS#}ry=0f|I7*@;qK#ur9h;T+`Za4=s;Fb};=<+ebJ`A8G zB5chtP{74YMQ%rN_igOjTW=maV*3?eW7juPr5&F z`Q;w4DbvbOEf!6a72_>o%gMH)Dg*Q~48ti;YZxW7<9J-PU>Csn{nn`uJw0`{dMLEa z%nE{-m@Posd4bLdUaxZBH>spZHT3HVreN)&wE$$pJ%G_#P3_Va;qUGZifr2ZT(~E* z%e0U3#rLaiK-^W?xp$9P;PjF|w_oeKXSlrqIp#Mv=^PJ3P|_K)14<(fxl2UxT{V1IaqNws2m# zW{x!C?%PnkzD6hFo4POc;i;N%-1EQ!@xz`_>5ENU-^_5ek`2h->~QJX*O8$KfN z74=!k4I)c+TY!Nxh(@v8Veq%`kU*0hV{rU!TI>Vj65ta?Xpc5cny0x0oQ?5<1~N|`*1D#I-)xwY5>rE=dG9l8PkOL z{n@*WP(F+D%}H-=@}h>v*iG1w?VXwGopbPmPui@7gXn^`PUz%awWf`n`(OoJR{(`> z;j|rZL@@m=*l56H4b;&sOS15m$Z!+T6sieb)l6bZI%9o7x;&p_ij;p*L1Cr5jLu$5 z8%x~aer?LL}UC1c-HW$Gw-W6)C z>_03D{L!FxpaYKjB$UX4syOGt3dRvqg#@aCpoe%P)wBX+$MA*kw4Ka;Vd^fDV3Qj1 z$@>L@Aeu516U$@<^%Z<$Hiz*ntR#SQ9d4TD#fp}1PjRHVxzz2v*hV-m-`9~A{~D@= z|HH$>fD|Y0U%0>hn=JPqsKfp@4e&otJOA%{_P_HzQ@rqM1Dv!n)u7X&>!Hl1cPSdR zma%vYH?shG+731=!^=^L_mRb3TDMc7QYq3@P!sDF1(L}e+fL(F_X6A>g1subK-P7UsEIA9C<`*iSj4pQC%)|Gxn2 Cx=4or literal 0 HcmV?d00001 diff --git a/pathology-ai/diagrams/game_flow.png b/pathology-ai/diagrams/game_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..e47c55b6afc43485f3338afd63a8a8a2188ee76d GIT binary patch literal 54797 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

    SOA+b2gh*s^yP^83cWG4FE%7KoiRGkAzn) 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 literal 0 HcmV?d00001 diff --git a/pathology-ai/diagrams/system_architecture.png b/pathology-ai/diagrams/system_architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..37d822ebd08cb0f558102bde609727d9d05c4d25 GIT binary patch literal 85698 zcmeFZc{J4j{|D;R>O(3O718!l8HRkagiu1+!;EEYm2AV1J$suHp~X@A$#ZaA7Vso!wEZENprYkl*WtGT0- zwY}XrA(68}5`xF9oSknwNeK&+{`(z5_KudqYS|}o@F{=azG~pa#Kc>He*b0n#YL9s zFD52sg-f_QQImb!Lywr#p`k~tA2+uCZ}f!DZRol6zy8HUxc~0JfBoYbYXzM4pI;Y+m{tG#dkT*UZvU?@eE;8X_}{Dazf0r) zx&81=K=Z<^!gyP%PHj!F^v|xzo|$^#^0!05(n8pRulKF%_>HVwrv~_QRL-$brfRCziv8%d{x)^@EJxwpdd$GH< z*QqJmBHBe)n#<~3XJ)&uA+~g;g0($sePeZcEW3uco_8eL&19u#V55W5!wjGMMeA>L z+rMOb&3xE77GaaA?AGU^=dn7K-?}_IBoJX=eb`d1UNBdUU|+h>^7X@m+<~|R$<4Jn z0hVr~+aI=DXO%7zpOfO3H?j_gQl_3=-mM&IU*;ZRo%DKA7C!&(sU)_e@b{GbwuBB7 z&#AU7({ks*C#RFXeSEBUB$OrLN{Gf%pPMP&bGkJ59fz|*r->&?vDMgjeW9TY8@jkW z6cXMiqjlWA>)j347OJ&i(9xpLIonP8h;)p9cALJK{z_4xYC$30^c zS><+94R8LYWRlZ#ajm&cvXQbI%Vw)3Wapo~h000%Rg!)0rVow4$1r^lWK>F$E-skv zJ`&yf_vxr-8*6h-9sNUB2Sq5AL`-6pFc6Ys!d z=<|EH6;3)#*N{Z>2>%w9X%xlXT*m=NbBxh>zMP8o`c-SdUFNtlKlXC_-5q;)qmo`* zM8vl$=#M`+9rFo;W8;w$ReyCh?seWFg61~6y6Dr1_i zAB0H{c+Dkx{wzGrYIf-gyV(kSqJZR&lluB~DOw3FW+5_R9R!;Ui(Ywjd{)x``J5*m z?h6LQ)I_e*wXvkg%;q_HPvVFCMY>Hghn`XPKMj${Nc6GuD77E zpTprtjOWibt@YWOqXs?iVb4nk@kon%Z>}#H6jQAv&(D26XBq3=tawlz)dErjEW4K` zUb9v6!{MeDH91Zrjj4KBCa@bVRO+$$M&r#1R{}}(-1a5UP2gVHO2@C?oGfOhV{<;8 z;Aq$!3Xw}XXmaOx=~BO^!9r4MQUs>q{LoYD*XCi$>njVY8KlpzM8-bsJSzBmLy4Od z3Z0gOja8`NI@F%R2(Q(lsHfRHov~kv-KN{}?FXn8ECO$9Psd(x z!DYB;Y|gi8wvX5!ndl0xJryaaF0;^P9cEym3|B$Zm1nZ0O3oo{fBS*hJA+T=;V9q2 z>c-k=a(6x&OO7owHtB?Ias34z{=CTT1UnaB<(m`cdF1x{zh0KaWR2hGLjzS2!F-36kh9pxAU~F8qAZwP+r0oHq`eC2i%~bYIQO<%?G|3 zur%@h-qw1%k(#5vMlvM9rKjf_Q^s49HEYKXLW!k7JuUpc@@UUd6B-nByt?FYC||e; ztVFyq)N1_xQ)($hEZY6GQxkA|+mHILJy&;w8XMNemgtCT&-xH zSYFr7Kxf#jNwCLh@#8w1>(joiA~i=|Dg_^TO;Gjv;m1ihGX?Fy8k&juk{+(c19n;K zUptRH!}~p*PE-p+D$niig9DAuL%P-j{JzerLuh+4j3fEUD=X(5-#`$j#si?|C z+7R@o?c8l1p14PD?OptDXi-Cxy=QRuh)+{a<^3$0NP?;_l=e$E z)3Is$L8E7QYJf;rKdoAlha9;3!p!^h6J2tfznkWvzu=rrs?cQ*GqkgA^N^+t_-@J+ z?>NG^&cvop7gUUh417zK6v!%ZENxYIZw`%H1x~`6v)U?MX0a<_aZ=Z#Mr}XG0v9CTdA|8dvfSoc?x1gC6~)v+W5coeFQ75j`N^Ye%vExw5YTR5KW)zh~Gxy(s4+pO}+cL zdn{B(fxuWXs@(#J=A?xaO=iwNb@iD|Y*qHQ5^8?XF+ z(i1w)C)-137d$3?v(jIgAiR0{em-hM#pRj6^Da8E|3N`glkYxaV#EoFRYBjZHgj7w zq!aV|J<NlHZ@DCtf$J@_AZk62yKZiaB3Rg)fwOrvg4I zY~O@HrfHPb4hv~1Xg2v#EB!6F>H7Ig^y)5_fO|oQ28v@Y4j4c+b1TQ zqX{879U4`X1qHr1{T~QjrjPUd8RAUQ|Q4gS-?o3O2)0jMZy>x}_Sl|#Nm%=;>!f9ttoj;mL5S=K8niNjOBh)46Q z1KwTRc9?rSKp^uBcUKDkeJ)kOY=sDy4uf1XPSUxdS0TJIQtAOIyYZd_Sn3z~Zn44N zBeAhoCFFgbaVnW|q)RqYt)|`!cslGm0Xz3@Xq%H#hceWLE(E#&4(eHm33orxUL;lF z!UNYg;y;MDL-C+-=yqc+!s`=uF;~P=?kHIOL$O5{fiHQwuh@+ar&yPFJdmO_T%pZw za#-5c_5oq0y)#CzLJGB&2=g$5fU=`EUia9Sms%Ak-uU=P{eZkbt#HrhPq^{}d?@Szsr0d=7j_L9L!Y04T0Y3D)x>-V6m%eA}9{Rs5VnQu`|uJ*r; z^J;{GFYWSk&9{nbc9fLg=gOfM6F^bZGjTUZY-hm+fl+ZK+4cF>7juedN89yG8-fj; z1P-2xu!yi8$B78|&mE_;h3)%R$-G_pef+EURe-@_` z)x8J3Hb&$&U(@OWn+y$)WC0vG#;U0iz&xsO@m3XwUb+vq+Q&#|@WPqoMaxJW&s3D` zp#RAnhij&X>_TJ~KT!^Gu+CPkv8zbK{yOEces}BcSECWqj^95~>o94dMw$=lg9Jmv zsk=6wT64XDGZwhJ0cISen?qcSU1lM)$O$R9FQS1M_|xiRbuf>i*!A~!&+xR2Ug^v< zPHTiFlrwQy%Gs*hTrl_Zzvd$YZUf$`jm2%+svOalz@CJQ8^cXJQscenp{D7=9k(}6 z1_WYOmpM@@i5v&&F(vPAJLz75ORAeT=@M( zKy@8_kI@2j>VwABz)_9b3!O%C=3-%g;TxvHO?^@$d{)L(?LPj9v^R0=hZ~YOxhVYZ z{T2@U8iZh)Wv5yaRoj6V;l+H`mZj3MWws%g0oUpPBiqzv%wi|H#I zX^(JZ79C9)m+q-xS5LD4`oC2Nbl!&DhDt~F62=HC^2Mx#rp^4S+^;E0ERG-Vgtnx! zcxZmIJ9qM5DX7NybAd$hDnYo$)(v8vg2hi)=ooRoLpDRzK{nS|%kEnl93)>?afkbv z8}>kb3|d<)X1y(a5q}o#C~7%WmR~vb1dG?^IVv}rU*zly#OCQYtEiCu$F&kEMSkUg zce-Ek^HDC6i!G=e84em(sVe8szeDfDv)o^G z0^!C=C8n9}H}!#4*OdX28A$H1{m@CX>7@31Opv3?jb2f{1Z1Tu6xb$5yHc#^h%$IX z+29)p8S)%U47Z5QE>wJf3r_!xbi)y+&sx)xMnY|2BTi^x2^E(x%Vxf-VByG!EQ^x{k<{sI zz-?hh)u{CQz?to^?{Tch>P?FdV=#VyZQapU{Pg#a$gIg#VB0-z_Yb9(UHb-9Lr2Fyz>e(kCj4JeK#aa zfuoq`PrTo{$M*Z_6Sj;pX=+pd2l5I1fqc?ickWi(b7AHpQgw2P*M_%fR2^|?)3ToI z%2rHsumw=hH-bQPZe$tT->PKd2R*Axd2@}@;e8z`_c=&4gG$cSZGl9cCb>;7BHK}~ znM;A`$z9p0nuV^`+ZX)&En>YFJ;K?i(#F$TTB7U#wdBMVu27WxfF6l+dkz!+4oef& zNwq50GwrE}81xddoT7DVV9h~VO1COnslKe^*C^E@x!&(NP3{wB6?}J5mljxU^Qo{U z?0>Ax{K2FZgfJ0Orh-&riJiu_(B?=^IzZwU&{AGVW!#ZG z=O}5)#`>z8|DTF}@CHAsHl-<;191t=SOhgW8l0v}m%`Es9LLjD3}?w{7+QmPPaAiV z|5;_+tmN|72LijT9wLOoT3xxQq@T{0va6*C@M-k?uX^G9PenJ4HsQrf>eCn*PjRc2 zoA@4L#EnOXPg#3fagR`kde^ude-!`gR7K+PMUjG4VQ=dr*`5aHtsNd#0n5HZ6}*4ii*3QDLyr6H??i| z4sjeGxrj^q_e656PsH1)I8sz=u+tpeuMxD*F7p0S6yqv`maQ5NV&9M3{4HwNTM$33 z*hK`HQ*g!P^W68Bnifr0g1E>gKmg)fv9vaA>*tD`*0;L^=#$=1dyp`u0#wyRF=KoA z%6J;Jiqr6IN2ac0CHs|Ie^Hga=f_%;yX90p_pc5^`L=I%$(vvCSo&$axV}Qz*&^FG z7VHxxU>&pq9Wg17fqd>>*vG)kAD_Hwg?gkn?Tj>_=1$M~(dXhI61|w~gUj6Alv1KY zk-{h969dLNG7LGp0(9>IQ!_`x#sr(M3=pER)Z`eI40j!w3Nz7=(=m7At1kbuM`r#S z*EtKdzzigrrn?>eve7iQ5( zI*~-+BWtWIO`9&R%U5CPZm5$;xP#b3?ONe9^_tC@9&l=s+2YRgHR>l&p9sLB^>#}@ z@?r?umoYNxfaS~wHU~C0^rrtcaUUkP=@$H-mJd}D*sC)G@`4W0J!)P8?a+K6?ezVCtqfcL~ra)b$wf@H{Eyv?Gpzj z_8KopHP}2ElCh^ua>B0xSR(}22p}txNM|AuO*zz{u$m9}LbI4KR#J`8TW~Pm35s6G zpVsygM3flNi(bz!m2Z}QXurh^6xl;yR^bpuc9^1C)$lXcXT|yjVTK`U0tY{cG9TI77s{}C_9KX5LA^|{zh+bsqyD9R zr7fmu45>{0;x1?dRArnlho&(PcPPJk6;r(o$jr34=m!Y0Iny<6nuTxlyyW_vTh&vs ze@@o^&&lS-zxWLFCI&GYYQ0eL+vArXy>%F>CP!@q3YUGd`?7~iG^Ia}p#hXmfKoQ4 z186g_%&i@-$KmY_y+;GFMT+QNaiHte_gh%s?$NmRIRGNy2Az;WvoARv-2zhL|ajNa0VK1E2Q9C zANUvPEb13d#d`gk+~L+M8d7(R-1{(iru|f;t@gC@xzA@W(?RbDe1w+;i9CMJ7AWJw zBTZu9RPeK_7Y37jHaFIFfE2ZgwyM4CyAwh=-TdNR8Bq%Agh%ZXr?GRhNB&97q7jfx zgD=PB*_-Qb1CY?Hfu*WY|KzTEVTVz61L9LsYcn5nkLeGTdF$lc_2mp5ihFEzLqF5} z*yad)R-OE%;WoX*=6|WD)GL%9F2`da3p)DONNP z0m4cT_k(F9c%ZAeQg6A3x`JRB##XC%=j?r)6x(oVMg7g;`QmEdup9so#3&i2q)r3tR&7cYyTz zO-#e0!LNH}kL$5p1&v=ro=)j1hOm{>X3wEZy&xiq)A%wGc>exG+zb6x2Q@<1A+qFM zi;93bhcbqp!;aJ7*7LTOct2h0_NPSbu)G-5JGPeCEKj=+T#vWsd2CB)A0>-tmT6l^`Qj}wz;292V?f6`X@7hV5bL|J>hX=rB z6s^6)qv8o=rUljv-4?q{eDpHR*tHu}Bd90~dG~Bpv<$}KerW<8v=7Y4l_5@#I2)D6 zH{9}`T8@yX?m<@};+8@4zIWLf{0ZyVb)xbcKK!}0e~h{Y1F#7r)8%z=`?_Ic9k`lIEjt~nI0$^ za?15j-qqaO$=mf$Pup``%SLvp{J}`u9OdpM=pyy$<^I`@cu1F@E z89PJ`-N`B%rx>)St{{TQx~qCoiJYObMOBM$YCJ8gQND1v(yb8`Y^^`NR|bG1(pLFC zX0dk#PCsUjt9oU-#|Y`KqoY!I_(fY(g3WQ!8&RTpFmv959&yGStPki`$R*oD^dvo7ZrQo*r{l-eFr)XXrVVfwv8xw)Mxny=fBG!7qtS)kM#ldG2Q$6 zwqwYKN^jBVtqdj_sDA?m^^@J#E5-TtWxr4L)M!P6P-Rhje;a$Xwc0}3@)7uN3ocNz z7X260&NYa3kGz5o)+*164PAd&eMr*r7U%chu+~~%iJ0X$aE~Y(ZAC3~l56jXDzD31 zrxlPul+ks}o$x*~QgBM?E~bOKCLiR2?u6r)==8zW?|uhOu0oA!3_Hs4`NT7+rVDeo z?)9uxSc+BoJYkwRXzKMG*)O(+W(+mH>PA=IXU2{RRzM7uX`KDTU1t6uE-}jJ>ba&1 zP6&jb8cULaFM&>~$&GyVlp1hPRCXlFQ)BjpA|sp0YL#I(-u2jZ=TJIyHxxxJ=pQL3fv~}9rrVQ$BTa>c1Q4DXm9=W{G{s7 z1aQAkWfTksEFMSix+wi6ktTs&5e&D*Bde1-nNyzxVlCDi?#0;iE4<1`qeeJJrBUL} z%=Jr%00HM#Fh?&OvovF6tt; zD`5I?bf_Kuey2W6z{+S@H01q$s#D?l_#@#r+ddrp9{>jN=zI^eJ1PylDetvx^?dxJ&Sc zFW(R{T=>~nOp|z^{LfFutwq=6|2~Z7Y(2&H#vMUW+QC2W=->6{>#(X^=rjNIbD91(`1ZePzyDXI{dg)sa*skJcZ9J>xBp*{ zt|1djr=q|H?pN2Hp&*{)gm%!o44rLdS4I!}9xsdrr&8x`#cvggWJaw}QSEhnN2TvSyLIXX zBTDoIWAW<7BWIw79nyVKPL16sdKj5gXD`M9Urc)i;zBF%W~*t&|6`M!>N8MBWBhuv z@F#paRkvUB!gI#iI<#qBF`tGiJ;DGbNctOxh|*%eO;)L{qx;D#!D_%Lb?I=*t$-cF zLCb%h^y+2+aHn&LAhaa|J{Rjl_A)g66t|vCz%B7TK%K(znoa;Vk^vV9B9PNlra!B{L@0XrrU(7&tZ!ESafDMR^vGQ|n`n-uZg3+kw&s zvUv*vX<#U%*_NvV+(-pR+MS1V-!Vucs7^Hl%?;fE>EJE0`>_yv=yrGoeray(Y&U#- z{`{wtAqS!*s)xYmH<~|Gc?W9=8Jtwra3Pl;(%+w5CXhFtddcg~NylAJ9Q{sDh7X3|a@K zIK68#djO@9;#Wn3-6!+mu*GNxQ8UGlOlJoJ3?hK?=**=;51*+#;IDHwEY+{Sp0}Jwv2m>!MNj+rt zRj5i*xv$M$VsP^bUkik?w6v;H_O=JQcHMZ4q>}?|5pDS-BoCC59pTDtCaQ~fzx`03 zg~RO(!01-p7p5utPk^SW0g8rV^m`q^woSekH{LkT0S?o&ZdI4S8gh&SEc|p|zUscV zm^Yl2!TC{Gh-y=pa33)op_m`Q+v*lCKm14xsMFE9mztMivIyE`n2|}gLjgE_=J;rW zS&70`)oW-&S@HkbagT3m!796hj$(K*C|F!x!(;>i~c2U&g^DC*j8d3J$hyv%DKRqOJq7OEj z;#PfRdvS?cT_XVV5uoRxJy+zRnJyQ$iBh4v6cy`f8F_Td$`aVeGOV0_R`rXpN!nhI zplUk01h>3o#T|DT$uYS^4H_0aO6!@gA5dbfc8eseUUg0!g`bdy0#MdSv|Y-r_F+X9 zf5$01kQAB-g^E3;=YP=pz{D8?T_UBmXbQ*^#(fWNuqQcF`WWunK_} zI%X*GcE6J02dEh0Sa5o~Jrc0yB?uRNX=5PBySnTg4^F7*G{Rjrb+4cfe{ z#)t;GBq8bj^ok6fl~Z9kO<$klYW_xrVmDPd5`!|Q(Pu&(QN_MTPI-@?0c$TwRjBYE z&#ZmTgJ%f^4QD^@YR^*KYk?f|*2S~cm#9adzPt7TR&k77!M8{8^|B~T1TK$EvyCtK z(5(>p>$bzFDxT*L_Vo&;XH2u4xT?Rp=0CJ|NE&0uQ8~xV7X*l7s7W_s1JX%=pU<1;6-+OR01fd=5&G1?&(5T`tEN!hWb< zbh-=6>xpeWF|6Q{c(eWGA_ROzYmPXzz4mEK(Q=_|ss(^{P|#?@ejE1hhEB4F=C&HN zl{;RSwdh($OS#lh*xG?OL4HSylwHNCIFica7*I#h>PyLEHfrCk;wS69@)m@0N!mg1 z0B?))s%%eW`Iav^5|!IH0Ujw`p}b~RfHO3ZXaPK9MIoz7Ht5>*Y!_O`9e!N=A0|f# z_|t5UEA-??aJUfz-(1C+Q?L~(VgeEztZHP+U5@sb7V zhMLY$O^7gE8!PLUeI>hzo1BS^ea_$MA0O|@I;W018*ofla+nf86Jzi9gotkoXtCiz zA3#D$hA6EN79xMvkgHVQ$>V$t(d6;ZdbYc2WQ92uiXnS9PWq4!2;i-daS@e%=SdTH zEJ|L#Nn9H!e+Vy_sBf4XpB|CSsSP`r@v{z*{=hO>sG=Rklgv2>&Ov2@Lk{3iI`i9v zA&r})Q?8kXuJi`Y!oq3iwzUpuBBXn?FjAk3WJ5Q@eHk;05WbU|+9{w#G@68Xi8a{a z`%4$Wva>w?;e6-KGWxgFo7iQ7M@gGoKjQ78Vq|2y-`#zKlA45B^~okm#+6aD{V*5V z{@$eWA#vm-Hmyz8mWVv#g!|VLgLMoYe-DQzvx#@TvATw#&!JL*3fmauPRC`6K)wa~#G!Oxk_sA|EOB+XagapDrW9hk#DkwdAr5x7xy8QHi{$RRy2DL@S#l#mnZ!2hm299MYB?+-byo<>+1Xc*} zN=J2~w{Tf*u8xBP7~P4`TAMBwk{d22k!Nqnb7C;VIrT!Sklauubwd|7 z8ljtV89BgGc#mLO`yK`fl=6lSR)*tz{< z!208CjW}$C4{^lCzvuuX_a)vVAV3?Y09=sDmyn0xS3}tTns;wphpAn`H}9p~Ulcci zQ)J?jXYid*K~~XjQ23JWZQYrKtls#g_##c5B?cdtngs5~S=K=6Be4$sgwY9h&LZ$X z(|ofI{|L~vXP1>4dU|gB^AgfDQD}_D$6g@`jI0%Q$5MRkxeBe>6l{eK_HcyM6txu- zVF#R~sX|*zB&}uD zGie$Ax@!dPrFjbk)SoATSGl8!`>!yN2+vJHNEdJp$E~Xbp_X$5MgQm4U=kVq{F$oO zw-E^IX+joO37N#Lkia6#g7qcpI@u)(`Lguwbg26=x(4QCQL8U+()|dA&7l3v16)Z2 z=q|{pQK->Cz{|LUKtjGI48%Co!J}5md)NbwEcbRZ_+t$99qCBOtrz^<3Oc^vOwRWg zs!4!ig<1O)ZYPOVjy&nOUp$p($hnu1I!DlkCl+oA9}-Co$ZzwUZO8Yw$D=54I(Y~r zTE@@`5~@W(zBG@8Fv_Ab6pXchvQ977qdGLd@W@JY2vy}b`=Vi{lQKyO{sz!W<6PtU zA%!f!KT@kZ(SRw_uOX=KR{<0^DrC8gweYbanFi3gnxuPs045Y^BY4P?ym*|0MlKrW`#6xUAF}Zf}RXH;gA-1>3VLL^_B*_757kxQfH$ z$uY1vCbb%2pov03672iUKN2?6=$jq84n0FN2Y-~hyW*Gs=%-R|teV{reTM-Q3QdA> zaT-SdGdIN~Y6N~~%Oh^PS0(_g=i%PIMWws}L;)msC__-uQWuX{(%mP2l-i5ZZP4SK zJB{6Fix%+zOjLpYl>`6(GW?4)W3(0)zXRh@0}M_;vo&<+k%pd5uv`|HIU{BQase-;eo#Ii3RKq(@oUssV2b9XneepzM240zGH zv$5YTDFUV5!psgBV#ZuQ64{E}rejdn0rk-~&I66lA=;gc&riVqj8x_@JGMxIx;Rm? z1Q;>d{m1Lm4gb~)q8Tf-sahn&AUjYL^1vuVg{Be{WkLcM-*3RCxLd^7)btcau1&b? zJj1DgsJkkfIfy_a((NkbYoQ4iX9O7`%90#R5s3>+3EMX(2z*#Q@AD7lmz8D^k+5;T zdP<(#Z}-G#ZJhv41B9m^!%c`XuqcJ z1PV_QgpouW0P=PZ{5vb5zDC+#j#$zd4A@?KnhYuUNaib(l!Lwhf#_IKPy^;O?nmi=?~nr9@?CsHuFw` z(`?{>6C!A}b}#bvP=knY>vzu`fjII_q^StRNHn(JN67NyRHOS=^A$V?9|8@aE#?rTyK^{OGGdPCX2zyd)J!l`fybgpy6~6tBt~DZE5r*Lw zrl{I-a0Admd40-*vs&(F>^>u=X$?V*t7te_H~Jey22?@#vUfEr!j3}-jB|$T{O#*> z$Y&Bfo#<5NP&AWe;1{G44fr#))IV})c9c0jqDT33bf`=@2$L}3 zw|$qQ%Uf@qCt!JJHqf}eP-a=>2Kzh;o##-lRw;CycQfRL%$JrfYHxhyK2QNEfK2{)t7NKUf=u<<_shQr=2`v2+`mclzvzbnuGOc@z)Hb zz7wIZ$+8;4314*DkM^L|$@nTAs+H$lgGBDYNh@dg0E>3X07(%4T9ISk=Vfc76vWj| zkNomOksMO+{78uO&w`VzgSZo0m{Dt7^a6#(F85wxuvJ<{9`Uw5ae3yO!QMA}g`R}z zP%|d%4AUDsc@^&F>r1x+_7LvLLXwmessnYG0MNS^!RW0(S!45tA~O+T)cdVB!1VvL zVfRG0aF~7}24-Wi1!TBG-^q-82uT5V9kVTQ@X;>_GHL&N2ESM0XafDfR1*ZIVj;a4 zEmQvWJ}V|>8l@i*-;1~zz^@I_fJg_{R4jcM3jnWsF6HhoNMuM9Z9nRK3)D}N)UQt` zb1_c<<{Il_tse8ZUIl>RXk*WXJr?X{G|h4;6-nAQE(StpI0n~YXEcex)qB&;XpYps z&|tbt%84y!+5N4r8j90nHKL{P`L{eF=-L9*%ea|sRQ??i0Do&{3YntH5v+&{r%<<> zqSTSu4tJZs^im!!!5i_tMK2by8!_&nYUPeJtDMKERJrlO$x}HPVkPNf98K>$fJ$ws zcagT;h~c5VlM_bD?tN_;BbjD|Pq~S&17YIXZn?FYNeefae94*7#mNV}ui3ii!Zphk z7_k*EKFk%8;&lKG6^(ZevbWCoE&_HLA8B^XmPMkAtC9SXRx|=Q*x{W$4dh}ry-pS9 z{e(sN@e#+XirD>t!Magm;ub0Y=B@^*iS+J62GygKg~- z0VE`6@dbz^DhLF3)Cmxz+BuKsB57n*aJKMf45ZKm(yr?$FWYKYXvdYkYlCl#L5OPd zH_C;Llw{r-sFXawK^SzZ8i|CwZVrnclr8%O{WGq+!+JW!k^@-`)EzeTPAux(C}n5P zFxE=?L5uG-140z}J$o-!)64)(;V;;TG!ipU%cpM_5n{~>pMw}@QbLHVRFA!gPr?=> zBd1Pqx+jkSb{c>I5#XJ=StrBx-zxzLSjxtnv*uW157Mp-8^M^+_GIVSd-AN#d5zf= zXQKlO9QmNjim*X?peIX&*DSWuk@ZHp#N;J9Zkso(f z77g%BE?M;*>e>J82MijYk`@N{X)681Ex!1=7Bm-WTbPX%u`ug)FwUATE{yB+Q(3gf z-K9frC3o($tmcK4#i_^)GZ0Er7S+1P zhS*z06>gN3uMG=xG@S$4*?bNSO+f37Kn8>D2GCA%;>N42A8TkhbI}tv76r-jIdhrN z{ko|@n$sdcc4&vH5V0-`#!6V!2%L6m1k@K*-k19JPhV>9hQ33Aoy!sJ28vZm5p44` z6k~X?dJEQjYK&~Pr3eB)cnA#E2S+0tCf;4V`_{{xR!x{+!=s&(`}AI77y%P0*Vu!` zaK1ZVIpUzOP{a%J$BwB;IObd;RC?jn!w^=jcrkK4)!W#!2(DzNa^og_sJQD@2~ef9 zk#YzT2FB!*FCf)dnU~dXD&6@rv`&xqtZ;aGK=`c*O#bKdZUEZXb2`KBc!AW8f3S0p zP+=4b+*7hucpg-H)!;C}25{9NX~Pi`cpHiv-US|CFzEw^hp}p=^x`n6NJftRikt>- z$3f@97PE(ya}Gs(!uswMpfJe8L9JCWDH7*X=T#(`H8^4_ZwvYt^{iDCKBx^%@V zQ5sZc`pu;Wl!!W*1HQKCR3kP4Atxaz`-Y((rJD9cnmhrP)|wnF$vZCOXE0NjTkBd6k(yTc$QXS3 zd8pVrHg0KpbM8m36bfq-;8 zEm%hl$HI8d#E6#nKf&Fb^)jJZwg)&!gZhBg=B?2(AKBH-gWBU&6n9qc2TI8xv^24ymdLP3(7r}4OJ0cN^txDlzZcemz@ zG#CAg`K30l??2Ik98bJ^HzXBvI^#VEMl~#4zq%V?J*R8y`@5j28H4TVDLWRR=3BOh zn1CyZ1_YB~Us?>wVqC}!)5A<4j~{bR(L4s~wy-fgrltG$LAitojS@fzd|CG+IEpbM zUduC+tN&28R?UV`

    q5bi=_uCCGk6ldfg>i(6UbVs;aF)l*W>oo8LjqXE-Wjvho zjt&v-z+?lCighrl{C(7H3`Vr-G5(6%;|n;Is^ZRzi^RYbQYijF8h>W7Lq;G*<2dG0 zRl(DM%h}O>HjYm_3l^0Y(hu!ya5wg++;cDvu`!^s1Q8!=l?s-?@pk`iy(X4sqe#n0 z`ZX9RY$0bBTjLN6pz==T%FXhsxn;YjHt!*wqwjn;+kR*|KIPXza&SBsAeR%>F9`q(bl2T0wsakr)WMkK--|j$4Z4-Q)p#$qCS%^uLXpDJ%!4 z&al>$zRQA5VYNLYx+8wv72FB;m3A=-Gk!RB(`&2&e+Iy7sScF>UtG7ax; zd>j`XfqYsz%2VcyE7GdOIe!GH?5PS(6K&h;o+5}Q6ZIOv`0BPnjiL5;JeO+Ri7s#y z4DC5$Q!eJfqYBKYYi2iqnT@N#=))3jIwVC`yA}Loe0!p5_+)8U8Gzv|t9D9POaxw% zOIwCt))PnPFY$%Pv~a9XiadhJ6tQL-ZrgX4+My(C+xx|&c(u2geFa{Xk(q}l9;wXZ z=*XQeTjh*S>MeT>?I@QqMiQM%t19D$2w^TREFyHSJe!=Tg6733Xz0K;#-!8(50ZtR zOVaDm>>0Qby13t&M&_yKCE^KcC7mE!Q9!n&HHu~nLnLi;+}sv;hIzgiFY+p*t%D(> zFupY8B%x%33uEycS9FjeekwQ*{UC>^EW$|)95?lIhtZ)Ssp-w3qnjx{zLBIn{-URc zrp1;#3+uFJU%}vJ8hVh#h(|H(DV*m1_HJSiFyXWTG$WGhPV@w8I1TN&aTR5)L@Vtq z*5Soz2uABNLeIB=2 zfm;x>eqrqGOBl*sTb|vIe_ISVdLsRFna*G-8mAZ)<2Mly^o4mayGkU<5+YFj6lEJi z%Z3WP7AH3iDYBP8Yg6*TUOcBZPe37Q%0r!$I_*|8-hekvF?PTxB>F*)%(5v#d&|pH zl*foX0Z!ia3vhMk>r)g81kpLV=Ma7K*bLu~x9$fYY0@2MfgU1?RT6u#Jc%aC8!7&6t`IE7$%UA8TuV?2s`C*7uH7wZXxsZ41nN{tYU11`T${|y zGfqGP4`du_jWCOQSI*MjE(D=p^h6an>P2(hB@8YN1oX%jXlVwHuc1jcF1nC5muuv5 zF!p|wi&M&gkjK47@F!&F02IA0a!xfoCP!IRprzcbk)SYhP|h~MZRwu7S?@ojM_fDL z1iQ}y9|su&8#G?AFii_-0Qf>MK5h?<`7?%Eb%BPSM`cizu$TOTr73cv=$gLC(jUL@8O-^Qk5uJlAERKZJOX7l7P5TXUvB_3siQnpA9qLoU1xVDUe|!n^C9$t zlhS2clIck)KXp@h^=xGvq5(`irj*MC2BqG?Vj}%g{1>3>hxO^g-H!-iuzLXk>QUC_ zyu{Q>wpG9*lu^%SmXxpH%%;rw^d1o8vzt+petS*uANh}p`jp%I<>>QmDD$6`ZB_%V zNnM-I4#FyvmQFi}_q_&(1S-#eS({?z8^ z0Q0{}fhF%inhrIx7xabwmUYKa#dt1W(fXSd@3)kQpP-PB&sbAK1vx`8{<;tRu3c{k zb8T=iJ|if6Kc|WwEw0ocVjvjRp+8)GY1=Hz@y3ch@K%I=si*`8!`lupom;@#E{hbB+>v3si11t(gn0{G@N8OeE@Y1_ z$ocUeD!5P9{2A^WH905W?Zuniv^~&xFHfBF!~q>a7SOGY(ysZ2weCW8BFs1ig3*v3f`H%Xnf304$2HFOt{d9`h2Wf1PaO9nsuC2*dxp5E7ux zZh=X%FmKZKm1|!!$z0FZ`6j&t($6RPAhwJOxQ7?(8Pkkb=3@3oI!m(UQdu%00{DCH zV0$Ywv3By+Y~4sGitn(+V(nzF=*KUr&p5KQOVcmkeUnr$#uFE5Rd{e}KbW~+Cl{>h z^$NyJt?{YVy3J3xXO7z~9{db=Z=q2yQ$>Z}!L0apZlT3Otcv2ZV|MBJ&h3f!fmraf z)?9$fKZc&#wMD_NL*pg=zOVw*33(etwscd60o~NcTp?#MpA$_Y;1lT;zkLzJ$$$P- z{Mj(wo%TaN#XSbUPe1iAE@(!Rf4G8EOkgi(u}{7t`$K+Po9wWd;Y#e=uPfI`iq2bWZ+1%_pnpCFb4wd!wYjgI=^v-JK z-;HRC4F6F_a#D_I&9v!gCc+3>2|j-WIZ5a-7Oq30c9Xl0oIkrNV|V+CYW^KtcsSG; z_<**HBs4bKL8KU^yvdVacmcqW{(!k(LF_fNm%{n)kRPgB^o@(xcsQ;?J1%ev!|Mmr zB7*3FHx#QF@J^|XY`qZ@k5#SJ-XvMzgCFG)i$Fd^+b1+b0!C0Xi|us(PCP3+q(xa# z)yW?We21HyfZ0A=zP!s0$f&WV)8j3yL;nQ(@{u=Gf?ob85K?f-g*Tjw2EZ|f z9)&}>q)2{yN2c*3bE@LPM-@e842*}vI!U_KQ~bz(!ZxaB*1*iS@=$;SjTUz8O2{0nN2{zZmPCJN_ci4;#O+SHRe zHug~e$Q(5Cj-q3#{ReFA93F^QXgBK$U;^3>3ZWs71-4&Sr#t%<;Hf;k9PQ^%812O_ zv3!Vx*{8&Q?hP?T{q$?ci7;1U{l&G-RtINQsH<`${88T5v_49z#r9V#3S#6Gj|1Nx zSzY0jSg?r|#)`@AgooMjWEI>yivMszkc0F!UcK!tj!f}BCxaj|yj&JI zh3PVV{K-+;)PGe9iMGR(*VM(|N3rQh4M_i2^T>ewXnaPnUj#=MONKyws$>Uuk4H}F z6Em2jI(VyTh>I6{MZg7km+sEQ6QA~H3=#$K#%VuX1k0|};WvnNoCU+x%Cw4aAxP({q3Du|9;?yYC{|(Xui*bn0chbg_ftN%;7%|(pmYL))J5brUkKSg!3?(TdJK=p zJIEKl07EKy-E(pknt)}M7uNueYoKYZR>2mmfv z^u4jO#C-i-T9;DvuTgqMkQ9{`TO*bfwUX)dl44PCn(i95zq1vM8+!7#zo?@zr++W{ zvbUKdf`4_f=M*yRzU){7WdEt+!}@&~IoKd2|Q51Uc{XM+LIm9zJ{h;`k`&?ZM7y?!PHvMGq%L z^sf*Ra`8%txc<;R0BnCeCAP*#m}C6uMNOPFQA4b}KAvV=co#X-2F3!O%Psp2H z?rm<#Iz~|wt3;1Y8`r(-@cAf2A(iY^`9|C)a~<2~3Gz^F4$v9v+Vwx;xYl0@7R3;l zaRt<>n;$B`u{+?6%KyRMn}<`~es9AK8Z@VpS!GD3A`}&+$dr(64kclmlA+8hnvjG| zhD@0@l6eY^l%3f&hDs=7XdA=3)^^{=@Av-k{Ep-O=XsCgdA|O*Z?x^<^SQ2Tt#z*R zJXf(5+l2!u8Xxw(WzK)MdV8_}p(`<2-p@aEt=NHEX#mZoioE#VcCXFekGQ|#c53{0#T)UqCSQs~cRhPRzMxsNUr>X(ld2%EE%4x> zuHOb($%_D&=~I#`AJUlZQqP+HhGaod=3-vH5Q7u3TR4dQN4~2#X;CI>VeVd5(W&Z`kqq348Tz57>JIR_lvSs7S_D2G%ln`Rd zwRQ<;Pu1I5C9vwkX3e9O**(O2e-dJ@_zqq++P%Y8tyhy}BUTtOR+m{dSH5VYWgeh= zSKZLw>*Mx%<+`1l)jr&~s;w;KF@^Qx6DTy#ta+!^)1aA2HiejeZgcj>eg0QOR-NXE zUGJ};l+m0m*!n2H-<2z@l6a7(ocnv}^Lz!vmbX2e4htf*E*8SegmahqsNz^S$}UY; z)WJ9Pr{`g1&U`y;KdzVSn(47?zOHXc3>O)dS-qV*df=@s2k!+qpe z;${QiR3w@VN1S~uWU%=|5!TjCQ02s|S&@+030A(|D&C1JBi4V`Ku~TC%+kma+1$`eO!Rox`z@L_Hq<~jr96rK{V?7DG zOovl0i&PN(b*#241#FOU*lYsGT<*3yguw~^{^lPXgnYBXyeeW%N=Ip%g@f_knc9a# z@&Qp$(aNx&*8C>$8H!(hzqHCc#lXks0y>LiGr))wr6$!c*t5?kt}^rBuADxXHmHSF ze?bLL#Lm`tEV>QVBJ$T81VvsrY`+%Z_zU1*^_pJ^{-V|8rDoAp#bEhjRyKZ-IX)9& zrg_ioxIRxF3xOYAbWXWkw0SoPI~#PMH|G3!*S3KR(TDwrhTH!L=KZj~zkaqd=lhrY z2(OSJ8ZP%W+SUbX zw%zFKuYin$TsR3`^sF2D*;%U6kUyp)G0df+2FeTqbm$afT%qIljtuna&}e%|rPGlg zC?%@mnGBg-irXB^jSoP4l5W=%EeynlCGF3VFV{{Jpi|_pUI;x?9hA$?O&>KrcVaEE z6xtB`JMJP!IbpVXBxT2{u4`-z)z9$ zztAzwYXMqE=|A0cZ#HvSgvcXY6Z2zQ>Crt>4nDXhnDUTd%th0cy!MIBJ=pDx6JvLnw^oP{%dxp}Roz4s>cf0`h` zJtn-q|8Rrm#eIV3&V)UgIU#uXjA|5s2omWwO`*)-TKfksYv(v7x~$d(s(5cm>qtJ~;$Or=(Dx1CNPpVw9) zT9(EY2#|#o@}n$Mv@P$o>H*R9vdfpt(hZ|xj}(q4FrAGjs%mc*Y~d0TEP^}1{tE>D zpU8{~yFys}9XQPXD$t%q+J0seB6EL;2->h;O#Slb_v3-K=x~rbbrD=fQ=iFpTvZ^D zQXy*lC3Jm7soA5W-|uH!SJO@+Dra*_*1c1m7tomwV2v2~Q>MwB6E6>z7?(AA}Rz`p>I#V$2DV+S-2}4C#F4 zt`a8?zn5;?*3d5^Xs5uQpSn%AXi7mLk7bAE2@7C-z-n^eO;|+c(8&DE7JnB9hnhz! z$0R#bCAE!)%)TgemK1q?xEav;y<{8pdBVfwDi<7yQ`eE-cR4q76=f$>%jTIF|mH)upOE}8?WNuK z@S#D&ps4JPXkAS!A+XYMPS0!uGzmfXFv8_%pq1o~)wFdNF+*Kxpzr=R^*(DWlJO1B zrzolAf1k6G$0oqk*0qwrcyxQRs0sW%p9dcT2Q6E79)NdIa1@Rl2%-#h$_hrpxy?oLrcnwqMpfMlM^RuXwDAtxq%o&lx~sW6Q(s z@RvW^mPwI5TL!>d=^Q%ne46foro99h-bh?}>pMIRNYl$Tg(!}+6uD?%TLa&K1fTb| z7V>rsppa;SgQXEVkna#J&> zzH1UA(Q!2fuyT=CXwrMqnoc}}ktETW)S(w~7wC9?0ptA~9+EoBWc0HE(uz8Ix*-u2 z**w`Y-5T*E~bSmd@rE>`%B~e;iQ-RxV#f&#bYMIjSz~Lx#$KP0PUv_e+--iU^JZLF1 zdyWB7QyKb+zL-g^IGL+O-?KhC>4Jo~61s7O$f@O1#vq@peQS_DQb(dtw5FVHTX1~{ zz_Ih7P`rYJ2nJ)O&|?Mp^C&B60v>+rzE0eNC(BdmyxWtxHz65mg47bslJ9NdjKqNn z{5|~m_9ikN!B7FeIFZKI^wSkGh;IHaX8hIqWofvCKRQ@7Ok%s}T!{$&%eK64cunH; z|3dE?1&F_(X_V%b2}G^lG zJ{bGEUdDFZze*u6r-dXxy)%K(lARo~$Zq2d_ zh|kq&X#J)@&+Q1JeF{CXkPtQ@TMV?O8_v=f#MP$aS!SgBu2?$n8}|s1$|t2f-8<+G zDRISV%dg>22uBG7b|_>UhCqewj{OC{B>Xc=mw(qr!u4h#;TjFl;EYzHi*9|G zD?|(~l0oYI3wq8JuQ3p;vmLREUfv5L^8c)oypm?<7sR0Z)9^R|$je46^_Q1L$M{m< z{;~X6{Qm!Ji;(}%XY&7kPZ4l;M8W@m_Y`@=83hz#>HqQ+N!QK#kEh78v;)`de~eWA z*G@J6zh5P%6*xKplU-!5HsX8?Y}F@0OFl9G2%gq)=YIVwsZonW!w_32NvYpb0mnG7 zQT0O|q@Zs`0drn4v$TA0N~oZBAyOZYOSPHa0c{Uq{5tw!I7tJWx{Rl3CGa?m6@qSz zRDrQpC@8I-(fy$SU64gWTDx9+5j3iHX6|!_{z9iYE+NU~3w3S~VuCt)iI;WMdIBtk za(g8-Fq?x2Z|Jdr_7ihJo@;~<5IYL=jz1vKK5Q*g2uNG9W};%!aTc(9m;+b;D0P`% z&+~w@PKqf|4gbF8$9@oiU+qAPb)P9^x_MUICr*Gd&~-uu{(rBm^U)@5+2hFR`UNom zv($%8;H~_$;~}Q;biY>s2$Z3kxiNU33yeL69k;-YB2Va9v|H0+RH52-rH{z~t%6L$ z5a_(l<=P3s%bj#jq{oZ;A4rOD0@SlDcjPk);6$OJCe<@)_v2$QGVUxjN~@-R04#kT zC2r|=w88)zT$7{Yfj}kN@uI{y?2*i1suQ$`B!>!6fRcA)Ia1Yp2PYU+xPP`CcBLc3 zmj<1`I8-Ge)krsI4%l>b#T+=RKTT*l>t2FGc`)=&jV{>(BCG_qwT~At<W9xORPqHeA2)pzRW?|ml;=T9F05Jc|1F#1GTIP zO|s+fcThzb#-MpYH!lYJ0gK*jFk{p2%K%cDxO+uJBt@{r?NFubh;yaOZZN(``04Ut zN@vbB3+Uv7R+ojxAUA2(dsux9DW|CVEdc|}M!@bgEuJL`3A8lK`~FZU z8Qfd=(TXi?FI~y*&n|w_XT={RygNsW`xm?qHITBS<#|+2ofx?0CP7-71e@+4(u$o) zyIODEG=h}<7bL?XZeGnhDGwd@tkOqY#oVpE<8T079q{n|i`-GEQf}BcJ_XC*L)<4d zAXDpqOm!T1u=MF0$RTQ0oj%8RTLT!z4h1h@{KVyi?~OP}2mKl!7-QCm;^Bw2j^I{A zO}jq{*;zXM4cIshg5uK%wCLmKF4ID$sQEZqx=r zQo~RKNrZfcz|>F1Q~sm8P8gl*c{V95Xdgq%von$zKwT-S9RiC$%551?ET18BRtoij z?AS6S^G8C7e$oIzyNV6)N|bE~Mtb2;GQeQKSzP;iCxCZNz;m>p$YBV{N-MMIIF=CN=_>YGP(?913maKJ-|E-j5eeebHsZ=zrx zLweWXD1bZa=%uc+G9@{+Wv57GLYJX-?n4!w{1G^FoCP^P!864BNQOVJFOde{p35Ert)m}KD zJ@i28VLr~+YQMe_18Q^hzIx_U5daZOS-b10<(US&);82Ux+Og$M+Hv^or@#TB&@Ey zB<8?@q|?Ek#3Z9PP)1)I`0`+ZyDDB<$Qqz>!TDk!l~@p-B{XVl2a-LxcHyYM`F6-~ zh3_9lsq%mxM`1_&`)!v#T@GtX@cRMhpy2@R=-JC^Rc(t)ZSy;>84k>O|Ml*T5D$9F z_;lb3|C#k+0`X5iwq3E5ze0Tc>-2r4eyyjc`(2gpKG`eICthd%dC{b9e!gPbJ|@4l zqpAI!w8aUo*8Hs8x(@52))SdE3&-np-#%)Wi&{<4uV9QdkHHh_&pmovI`l)lTl8BH zgDBfsVp14%SzT5}l=FUef(HMeqJ`DmGbeE`RIY#dAhF)&vRj`prX^DcXE2|6(vrBMyryP?ZBtV(LFmw{iB?D&K80r__K zPRn0e2y>2b$sRvfDbSxzYDr|cWgscYSKpHAUBZx}xR++mO1`)TC)Q9onuTR{+o#_xVPM?xo^0O5@7s2K z>R?sga_Baxquffue5ho%H$oLY*Yx>LLf37Hcx6Y;mJ#6mFNl{bw+XE*yK1GS za`UDB)VuK-h*>&*tn5j9g>GfJF!92lQ%4M}Qi!DA&8R_Yv6Xg-VsFEFC4)uQ@Z4a< zS`FL3t=ARU3N0&xN)ZW?3140rHcUFz>oav~PO=h?XkZ=`)X8+s09u8eYacW&HtVLJ z=iKn=eg$YKY%)5Vd~?BKg0|iYXL^|jO1AtQKhC;?6nv>hJUJrybWV^3_o`48A4)1s`)dsRlH{XpsRl4aKrj>j6 zLt9nSVjG&51$82cRU9J3mY=T3)*=-i1e+HE7W@%9RqV03Y8;RLI645vqJxqoh)@^ZzAOSot;7f#N`%Cw zlk$g8e*?(OYCboBBMQJ2H_yMwWDMNEo@s6)0UXG@1^r3O@=6EG-l)}Ej>c_BGk@Q` zYNK#{?|@a9O0PzG%Zu?hrUmb2uEHj>o6ps$vPvJn9mq2|_r#?bYK4@5AN04eJfk|G z<7hc_h0D%1so6s`58SK&40m$bU3s^S<$3I!Qq7dMw)a#<`Vxisqs_yHO~f2XW2cJh zDxmPmfedb|{_DF9lG;@&CRGyf2~YCStq)AwaExT1h1|S;kV_=w$2mCUZo%u>tw){g z0oVXQzFS%M!0w6}g<^=mXKh)JUGl~b2nB}EG~`?w1Z#Aw`L=)ncFPFG8KTos^yRVqoC&=>+O{pg!zLrsLI)to^QmE`fR_iYj+TS=hM|6z%rhGB27qTv`yEHJ`%`2JijLY#*# zm%~*Jhbf7vXV*WMJC!DLjXDh5P5}DB&5r{Z<_C2vI(R}Sf`dGsZ%~v}&20vmTYc{o ztb=0n(gx^KT&%oNQ)7}334ckzU0(`TiCl#i?4H1GJP2wDyP#M;kEUwKJUS+(hTXkq z-f>sYlyl#iZ~OPpj%ErQaP%%2LbfkhtU{wBlYuU!Aa z)tTffOd$xG1iPeh|NXkoY~e3V;5^tf*HY*fu!-VX2xiRLc9fsx61sfC1+_9mp<6w^ zt|qMi3B*-lFrrqQh528`=*lA~a2@Qt!eMI{1mp={5Ym6fpxYQ3RRO>H2DYfh)?D!kCba7^@GUm0j@^X$PGieqIkJgAtyR;UWcSm zTdo55UKHS}T@2)jeryXB1!2z%>EVciERG>4q=4Q;0jNNm^K|>x9mK!jf@$RU<@#rP zuvSYf_=^|L_blBKgv9{^_$;LJdR#!-f(y8`IJQ&`GibH_0@zSlCbIjYlO|1ao9i>3 z-suD}jPInhH#KlVE<_N z3EzE-Ky#p_HR9Qpn}S_Q~iAvhByqiI;Om_er}L6XAL1Ty(3iSLzUd(IPrO(X_X@$=$m|(R%0R@ zVBoLW5xKTEB=+wWN%>5%&&}b!F`!Dx&9*}Vk)hPgmCs)=Y;zUvR|?I(R)a!oK_{vu zumv*Nf`AE@B@SLIf83>abpNuiw>ZiHkO(2SVTM0(fJLCG}w}s^C5h(N0H%-bPw|X%kKjKSb`G z5rsI5*9!;})kr#)+{kw{EZZ76Dy~qhSM!FbY59dA$t4GFvu=DuUh8w|G?Jzxwnr)B z?$CjDrqnCSAGO*`+%+-x;h>jhpf}|@6|8KS7XQWt46N(S(S)3}QilbVJDs#@q0!k+lG>d45eS6lty;0T)k7-Oo zGCFfTAbXmw1`ma1&rY~g7c$2{L7mTb?M*>A;9~=RJp#xJ*9W3b zdM^iDIMY4+zXk^f+3I;%?E6eKP@84eH3hRD66a!l;NR(Af9gQNVZsdJjchx2=%`R2 zExWo){cB~Nx6Hr&;uVM9FZX%yFMJ*?hhzF*J2Cv1!Fe3df5SUD{~Ox>^Phed{>90& z%jG2fuVwz51$F)Q|GdQioWV zHNa(h=rNGeOk$at()psv6Wefyh8qaq7UL*=A#NM!DZI&Xi+;UeCwm4 zbw;-0Y)5OkPE2AsI46Wduhl)G8)-Y6D#UnxBZ1|R4bBNBZ%!<~xd6P;P&fi#Y>57` z>NiGkG9SB`|L$N753yEp|Lpd7Ko&yA79Go{USyWXza$&(^{WgmO#g$J*EB)FCq42Mb07 z1uFD(tN@VH2?$Kt93YM~hctqXWd3RK$>TQ2Y>m-sapeiAAsYa5MF3;=(uaXA6pSZp zk{g+wLD8Yp(*xm$U`dwt33Fb6{I1+B3n#l$)vfqYl9YHoq^b+pR2Wz7&kOx(RAvPIoB8xf1#jNR;fJ)@zDJG# zeoVD2A0A+QA`2Uoa59IU9t}gNCOjU*9FTlBE#Nl*MLvvy^i*3dlqmo%ZW(wSl=dvx zX@}n%KmT?U7E(0NN-aKKjly;2uXIulZhgniq9z<<%;lHV?a zwMm!Z$IK2kYpW1saOGH=L8x`=!P{xi#GRUVe8qhnAEjcQ(Gu9Rb}hdOpCy}a&c zpo$8(Q_|}FXQkzjZNd55vc0&{_5k`NjOa;+PK7bFYJ%{Z=8(@bv5i+%$*_*H` zn7}_#GBJCi%nvd?F33#@r?ok2*#yzzae6w_AR7{%rm_n3B%%r^!CQ)`rw8pr4Jz{r zBj5_dHe_M-;iJMxz!5{RL9Yf^MPtY_p5@@IJ5;~Txh5h3mMttS%jEC(-CcziMh2eq zpzi7#n!tpQ(Dd=1?4NjXa6Qr9oisUD{Ix5b;VNAg4#l@FB`RCh)f;@43}AtIlKa>< zu$F}e`?(&3Zj42~dgEo3cIMfzTJ=FHcfe#}P?rMM8yCvz@?t$k9b<*?K%!0JVFFxf zGxajA!`0*??Ib*coqL3bOsOI#tn~GXX-U;+`+^OhY%i%NcQ3nQ!9YCIDwv+31$e-V zL2Ez;grHzPP1T@QV<|Y1pXHfJjQ%vGQu-N&aO-uoaEQNx!=$9JDah+jBB^c~PZ#KL zq!KHu7ehQHJ7wnW6f3D%TV^ zoyR$F!apLP55hBq7DKGZPs)8T2M#U0_Da zt9#|m^Cv4`@Ck>tewNh=@^J^b!aS`6S~M=w-+XtFuadF2qdGjJP2&;w7qa%u0?krd z553xxn{TfpH#kY}?sLuAitsd5phSnQF0t6;O0%Kjwtk~XPriBY0@d^Z94V1r^#Wp2 zSK-2s{c^0<$F3L#C4&)gyvKBD&xqaD^yxx_%Dz5F{;^3=_Hh56wBRm-i%IT1@Fppq zw8Dh5x>~G3rFMX3VK9YriX!SaEqH6fwtRhaU%XETY_iUU1&m;bkp5Y(@MF=+{!=T& zbCbXVqQ{q_A_$r3;|estpE5R&U7kWj&WVPygRmkYOd`Yslv@YkuzamoSOF`E;B&x) z@fs%_m3?rIHO8HN&9}Z$u!sgmw*(W2{aNIOyV(5e96;X}3fQ{TcRkjws0(rhM_(oui93u*Q4^5!#PU1_hag`lo-F&SqNL0 z6*8Gs$>(H0fdNx@D)+qCM2PtzCSL^#%Fc2s|IuRdDQ{o`*g&K-jW zxi=IaqdDA0z)v*?KbcWS*Xyz$XNLhj9@*YP(UsS+lC8F;@n4ER=<#hMv`~y$g>1t2 z=y&Uq_Qz8g&lRYyGG**C2B}(7dV2c22Pw`#*6cfaa?~!Z)+~Im`Q9+MbkKV&zOn2g zO#_U*yDvI)S~tiSfLR|#x=G)P9hsHaG|k*=py(m2NkY3?!GIi?i${omocHXCO(P~6 zWM}?UPhedXxv52348D8|#gg{Lk3kHpCUPUdTf{)L3L>8InpKS*6J=wbS;QfwjcU*K zXNBxJW1!Pm-^fv`@|yS3L(ClJ+}TX8@0C6Eh+$JBbLe(kMmNvNs2*YTtfJ~5EMPRO z{&8=k5yW*vLX9r^$ri(6O8x7*~Z?Naly(wrHy7^A5oPIGCYDbQZV={f$n`_Em?eLu{oqzO z0!Oc=Ro+dUJ6_K%Jvww!|50$c5omJ=_fuV$l;ZfR)N4iB<=i%^_Q^{3fLb`ClOvIp zHGEQ2ah6ZGy;U}LasVL)GC`no->F(ONS0Zbsbnr{WZN=vWT z$f|gr1M>>9^GqEw(Bme1?md;tVB#LKAT{t{QGy3xjn^}Da-h!x9kaH*@wY2CHnUEK z-hCcmOALLiAv(H0BG^Zx@$6%>Cjc27RWFN-xtKBuqtr4@f({ zkzVNo!wjxu_%8;(KE)Y22OHBQKTP7FJzIR^*C)&&5^{V-)W79!A*M>4p(;0jq{uB; zJ+;aCRO0acQ$ob;mv2n_`&#`9ds$RPc6@F%UEWm8!t1klBGy1X_>v*pO4_NZO z36%Nqq^fX(Dj$m@kYH{E-L6*3xurr;U3HaqGrw{=c*V(8M;ViOL&F;E?zjd98$Zh^ zEa4mkZ=Tdj56Nn;;MZD-3<3K(WxiGT5{OoX)i&rCVi=P4B?|9IunNug3Zy(f zsaQU^a7?^9Q?}MXSwo=rdyYCAUqFPJn5`Zw-_zbSu1jr#yrfoi<0~dZ1F>et zZHK`5^ND%+)Kh8E7ECHcj$YEFQtgA{vLo$}^pCiXWDEt=rT4iy8eJ{pbqb%f=qNY% zSnTmE`HnYDn(teSfg9c7lWky8TK_k zZWh!C^-yp>cGm2&M(hyGpmv0*AlD49=NyD;NRF zOStbP@d-gDH_I(5RGgtej8TYuseXL?eYV##A9dqnOe-v*V}-y;f!WNybHc^vpHl_) zCR}ASZjO&blbKDG2q*;_rAI}v@!i)BdZ0RaZk63TTLDsv9jD4mdz{MT8Y{6r-%X7z znC*^M{&C$&+0LlB*@TNidXwUt&TvIJgw>o%QwkxRxGg?!aiTvXjN^vYLn4<2>9J;4 zN9cg1EZ03PPJ?Q9;wIsI>*VyPH{y!fVgk*t>Yj6w!+hHYuNkqmBV&k^6~$lHUD?g| z7!YV(=h!BExi30FRi9JeFr4rFVHMFzF@53Jd2hiT36(F6&GsA`S_0o$a^)MT zpbs3jR;&oke#!Ez*kahHr@Vs&uDO~L9khvvOH$_Vy)zMZ@|2<#pI+!xh_5Xi!+UR4 zuFxg$XLn|D_iort&9SHbUQ90sd$t*UFTF< zrAumwRm!X+@}map^86)^Y>-sBbKX8v*Lek*>q9GfSE{jnW~Am^qL@Y_2XrtUTSPs? zLm|l<)VMG;TN&(Cmc|{jU?(7dDew*Xo1Xn?=Pw9Kcg;KGRzB9{G-cnySWbQOw4C>7 zME^6F`LmHp;%;J09yYtgKd0s~T-sMb(JOJ9Rv_%`Zp1dwk#<^JpH!lduHTW+ zC@dA(dFiO+qi7pRHzx^mZ{-UY%fc#h~t$LpMeWu+j*6#S*i5gvs~AmJwVVgkn9XlP1j~~5uXx5gCi2p&fFKd z0qt9vUQ>SNcXu}xv5@gMzJ{^6@}>r=Ww@eCN~{S^LEpuOw|2;3?_| zbQq%G%%wm#io42beKw*CoPAt8E2{{RHaXl^VkusF+=b|aSMjJ5mSGKeM|SlbdGv*y z=)BQT{;X%(JA3IC13ytmFQtML@X7uvRXU!8f==}X4zW__H2e> zm4zdRq8rupqM&<4nYjWTj4`p2Lzmhm&h&kWta~rPcvaX^J||ORw3N1pW6^eOSgwBA z7Qe4nSuVC%<^`A{h5nq+BGhIog=oM(Uxq*KV(+!Ws3k&cB$4s=_z6U&+QRi|bN z8$Mr?WE>l4wrkx!+lw^6g^YP$H-o2uU8R3jzRkucz_(t4<1W#a=^-7EhSD~O=pGGy zPpa-JJ;qa4JSEpnF}+eggyV+Dj~+;TzT#xAc!y7d%8~q2bt+aug;)kfKL$uQ_R8)o8386s%gb->evi&l3Z5%NsvGae3B2@~1Aa z%ITz^R#;%vk*rYUGL$Qq%W9aB39LEj=_i*!jd-cZNaYm{i~9&JLoFxBFS*`?`%f=e z{jf@MIMW5~DPM=(Adq{<@JyAy}B4YHhoNI*9Km@UP^s-R!^ zk?&||uap@yq0q^iT2xRO?AMzsF)zX8J@R*|umVKzeG8n|KkoIEorbyh8h)dVN2%oe z7g?_j?5iwlV}l=Gxoy1=e78b9L_@#pcOgvf3cOLHRi+R45?QL$V@q;yhTS$Bopo2t zjN~6<>|&!|!k+?GooRQpKm|gW1+=LpQJHV|gQ|7V@>i9-D!jXUN5oGd2^!SoI^J7; zy!9~VnfMEs%NM;G&CKS_l8h?me@xKVp-avifWLW<8l=*;#-cEl>bQS6WF+jRcBMR@ z(}jC!Yk7wD_x@Tt2vxEWLUk2Yj{^HAu5@z40H{9qo_S;Hdu%X;!8*#=a0u>&3(h(j z+WwHzme2F(Xu<|A{s1SK0!5&Z9Q>`wGJrs?%kyB&LG~n-<+X%`IV%X%o=spmcIpGe zSGGIH7ser5N;@VHcCrm>|E|QR0z+5iH4AHKl9ykIskNF|F_->nRIMVKSj#FxEi`(H zGuHW<=&7f-q=KBE^`GFiY!%!@EgIX>8i67l7Eu@jn1&ZJxCj#C z(uy892Mr!Y@KV=J8=@1Li+*?wEU2f(#$$kXxL@pC-1 zwnDcqzLR3W$szPuNV{7nEB_vX)ig$PZd4~6VKCom@+`|PtU4kU;L_Ypif>OlAFf4k z&M(_-9$K&Egsvk&%J1ql*lYWgS$;vV^Z<~-uo}8GMqQ-GT4f6cpIp8G6itEbz(7(` zp=I9mY&V}qc$|^}dGNJTfv3D)@AWVI>syGvhLPd?JDuxAMy$#L9nw1=FnJ7GFDWHz zi-=sRxm9Fv+p(+|^wb@T!aTc%CeOXK|AP|(wa?knWW>7V(g1nBrkZ~K&z;D(zLFBXJ)Jti3w`dkdruHHy z+Pz|D-tV7#wFGpEcCH{!6`t(ljJqVI9Fok*2c<=2A;-9}RF-wk&}3o}Vco)ucNaO% z(;PYt9SsaV-tE-joM&~`$?9~eI^8R^*qkCu9dP77qjzMLd4RduM_b5XMiymx*g81} z4wn7V$~yH58jIE$Q_ma3wFbW4s-8W#_k-KhEiymjP6ch^6k+7-k2V}TGE!R@Smj{G zg0vfc209Ms6e?pG?DH1*K8?Kt#YH&2VtS4vaBn)woHm6A6qBQ35f#4<{Ia}PCZaaz zx%Z;n1n7+OyIxt@JZ!g23?z?XfjH4M=2d9^cwg@dBoExkdUw$CmnyX7H=4}IPfw%O z0mY{VYHWQZR(pxG!Wc>oJQ@e*;Woa)CyW52K@3+uP(@QS}lb6&u$J&3SYY|!l2 zb#i)=mI{?C5H!ByHWIA&EFjhTh^z?DZv)BK;FW%WdNjYBYZ9uJ3X`z|my%o(e>Xm9 zCbI6k^u+D6Zi{mILYCN`uzKU%SK-4Z?`%^aEui(<+~N30iS3fA?s}0`gWKIOouBil z4fvJ8-p&-AvHET{xJLp;>nSCGYC3e5au4JPYqazG=L*HkIn7bt|oio5{ zNUa^gl!Z2(<j+&OFPXJ-LYA1%A2H|R{lEHzn#%R7#hI@%e{pb zSM)@0PP+tGa9J}01iQ5wAp!&<1YhLJ}-0bZ@xa5ISp9Hss= zk~AfXKf;#>jggW4P{<+D7R3-DE_*Oj)3prb25B4kJio5yPJJuEN+BJpMW>U&;`3li z&6W66c5yuDMpj|osia%{yE}G_DzEPav@o^BeieK1Hj{N5+;S1-94oe)Q+XX{_k%UH zlJqPN~K?URP0i#+bcdLw+n5pkkb+tJ<=atp_jJ5Ws7y%k2E z@_adSr(PhPn7{`sp13FXH{M;_c$Is5>)bIxdjNG_7*yqCGUY7eP5Wys#DG;4M2%o> zPnnowWsT5@f|I+zAQ`FN!g=-b=73ARc+@Fu&uQra9*|`IB;V^y&#Gk`TOE$=%vnm# z6qtHkJqb8M)Kui)m2!#Y?!WKqgHLz+DG)?T{MqSU-};KT>aOOfzg zP#4ylpH0|?D~tD^{V$Qln-_9ONp#zhBb+z@(j54@!;((Hj}=9?4eaw26>eRb22#Tt zO7FB_e448EsmB2>Dl>a_rw;iy2V%O1BrK;Rnw!t8;%1GRF0S)@aUArlgrC-s|Bg6R zyc~ zzHfMrQ6}3xrs|L466;1TLuQb1``FuW&-UNS5w@>Y2&}QW!}_L`rC&urw8mU|3r;~J2WN1l zkz7g`{ByQs!C5(&E*4#kpxHpQj4*YOrKY5IeyR3G`2}c%#0U;I3H}b*rsI9bF#N4Xh+xB5GfR|In`HrEytu*r_Re1iC zd=TUH{E)gb-;sTnP>&i>&+-nK2`A4g>+$Zs-;^3+su`)(m>RO@O_moeoz$CVaN=yF zG*hioy}+&8d1Q$r{hPw_MuC>a*$1It6e|iUn*?Mmx{05zYsylfKe|-Bp>UJVTM4UB zl^LGRB33J^tj(pF>Sg?6bJ$YeWSI**`P^YAbesE<*<+V?yo2w>p3>x7YZ*NPE$(7j8 zll`-xzNsgTC@>O|7KA$YcS?62tBd`8T3(Cs^&gAlrXrn3=ar|z=ZZec2FEplIKyNl zksG?LhO$zdbr^sC$hOi{Q8nmRy)BoI{h1Bt`($Tbr!pnN`^pB|I9skoTV!le?*7AY%zTswGigu(9WH+gvu9c ziHe@p(bWclIkEluIo|t+!yS8|;oM@aA=p?McG95MzCBz~>rqM`$-LCO^GEK%TQz^5 z(g2M)rZey``knj6T>ec@Uz$F8^KI@6_VvC=D7Pvt?cl$Ajyy3bXTX-Ecw#98>57%> zSj{DYFhIB!z>vkp?i866Lxkivi|uves}LQI2)!#6>L>Y5rTHE?%OE<|ZUxGYcC-4vlw-I3Z)L5&BDyx|!REG3#YgrM}tM(u` z>AS34W)WkZ)E%;YZo-y|HZOzod8+1W`_yb)V3&x41b~EbhN@KDFa-nm@`)i2vAAKg zUzd+WSPq~#Ql}xezaXhYkB!Tn#Mei0?g>TnEGM;#jVkyzRMU*U-KRmel!V+*+t@LP z(t_adX-Zo-Qa--f@cx5FSlJf>#iFh}QLctjjXJ=Y%)aEFiAJt}pzT=gNJJ%R?YEo?{MkjF$JkYDO8nR>IicdhWQzo3>taZXm3W#fu zXwwWSOdL-^ae3ECKYjSK1)xwmVc%AA7<8y{}U-}xae4n!Q|#P0f906+GBs~W%GM`=m2t!C@lX94&3qE zbRq@)=l_ATw@fe`@iVnVzEdAWnU^yEE~~q3!nvQd_+zvWHu$P9&-BBm`?>zVnS}hW z*?^S+Q@B=F)a#d&l+cOAo)sW`Bq{Shy^^<^?h>+PFWt%kc-1f|s+tZCRUktQQut4F zpA6G8YK>vu)pQyo&sS9Q0Yhm}uMp>l0v%r`dlBC&i%ZCsB~^T_*GrCYw*1lCwT|m% z92MdY9RBtHyap1ntD$VGpRj-f*+L(fySDf)R@@D{dI0~gm`NZfUqrVNpWtQPgpa0e z7}+WuKZa>hAnTMaJ}l0x%WWvL4}lj5zgDr+T_C=xhCzmUD7ni4W_r-a34B}i`pY}? zkT6PYaz;yrwhU$?g#{wG^Ieap_+&qALLMz&rb7-m>3Z!#8*tEXDupBGXT|bhQ=d!O z0Euj!%LX0sm&c-Xiw@uAo4d&$&ZpAPz$fbi9OP%YEokWaKw`l;yq+%BIu8;N@XSvpQ68`yHWq#){Kip_&ma3>+(adunvw}lo~LT=y$cv zYWe?Xo=X#v{X`ca>=nSP|6ePoKo$M;`rwQwFUnH2FCfE8Vfh1Wk6(6}*=`$-s@`gp zfOuYnOyV}(S|)&no`K*;hIDs%CDMQR5A7C|U;nQVg~!DqCj>|)Km@9nM88b%pVKx_ zT^|ThCx=_g1HQ6dS%U~9XYP>?|2`n%=W)nf%z;G6KJvko<3Z`a$JhUG{<9qJ*!cQ) z3Glb7VPFYS5;q5a{b|CCgQRzvamacfudrmWss?fSiI@K!js{H&I;Wlf^M5GM7!By9 zIQ@G34{_!{-0=U67fS6KmIUITctifo%)Qy_b*RH1^((J$s{QvUPQP!jeMDfWiHM=+ zU=~nnY&EQD*gVLpi)!TzKtc|7OGI!S20e)fp_Cp@G8Mo2IbyI5iQE|g3nDv76xF4! zP))lZufi(cI6QMP5`axqBj_Mdngd8W2@Bl6K#F2(zP`1ewr=jj?;=p57`_;T-f^oS zhItkRGsVddu!VgdG(ou2LfW5TXtT-1ix>NVzsJ$ock@rfSqe&RK!=rwICsITI*dJ@ z3jo3j(+SVOs;hqi&JI&7)SgvCuqQZ3I&>CiU$y+MPnC+EwJt)bc1vysJE1! ztE^RBme2_!MSJCuaUcuqI6cvU^WbsrRP{c8VJ$Ck2QJvGLSz2IrlS808>{BPGJUa1 z8@IsgpUdiqO8=M5=#RylH4nLeI7~#%!wPWq7Uj)_&>MMyz8V;^Sw+!(vmn?sFbv7n=2(F*7tANUpe3w3ywyF+QP%G~xVZ0wqkMRbB zbdh&jRyhVxSg!kHfY}YU1HAJvTnB`&L!cuT>Lns(kK_I*v0X^- zhHRK+0EP*|*V=zD04CNQt;4YJ4qNEtKJ+@Q7yN zm+PwV61FIAY8(JqDIW#s@h^cfCvb0sk?MyjVKoSAHP+NL{*eS4uI{ZO zV5OyFU46%Glwp8Q>PNkRFgz>Dk%j5SCCs3#25&%Z#76~Fr+_jKeGduGh3~s71kl_P ze9IKbt+i6<9#jq7M}67ZPv=QM9w(((=a zKNIOD3*=Wobg-TN#Idf%#I?NqN|dCW9gyg4+?U|ZR}4cEO7#k{jp_UBRyzscZ;t@_ zQpaXJ^?W%ii8BsIdl#W8Von{Eg7KHya`XL1D%uC=dbXIFWdXGkujP{l7w`mruUDAT zaG>{RhcrZW3S7zx5JE24gK%nPz6ws|we=>Mvu|c(<>QzDLk!xCes9~G@i)*#y?~qr z;?7G#u3KlTU8JE1r+_E6w%^0K!&k+aG-P0wui@HwreRmO%M_g4N|!t!5Y1*g(-gay zw_)YxFzk&Q+{N_O{N+It&mGws zLm+ncvjzFFx;J|wbPgty^DR@^o?%xg2Tp{7O)BTsqqbF$r5W6CRpkBQ6tSCygY|gJ z2%RogkbD*W5wUr>)+r$A01;H9fV9BgkEM=BtRq*T(o>k@m-`p=y4IZ}N9ZyIIvc*-y}%l-OA&a1x|_bb@~Ql+um&g4iiV>jRn-WZ zEKCbzH;`UdyL8&>`bDl4j86_|hKBHD$K4O*zx@v8buD@-8@3^l5!1&|hu}Wdn<-5= z$+FMiTF$=oXL&){z&UJ4m~Stj%0b zR@S~-UYZ}#?wD{|b8>xI!1sCR0(|LR1Z}iiP^Uru1zJB^J5UPZKs!=G4~BWX9--MT znK<&%9L`$d#1RMtFXRO?*?hzoMa^mF$*cQJ1l52MI{^%vV(Aw|nG66&w!i&gan0@rV;TH47V5sW9y(VuG6GmESXs`OkW@8Qd>>VeUkK%k#W7lIs!&R}d00xUTjp zbGejOId1yy7t+ypUHR0Ckr*QU~K zA#d0l0+h81gA~~8#uVq>2vNW(BHPqE1;}k_l`STS6=%mK?~w=B7KxcHR(RiY1)&pd zz4kds()vIi#wjGQ%hky2=8<&i74iwtu-X6T-tvdh z`{%=S!YSqc1v2M_%+hcCJRM$;2nEq5gFJrln8P09`fV*)*wQS%#ol8>$#eZ7G_9cQ zskgLj^*|y7ZMH4I&6;oJ^X_NfKb3s{FR=ae{SQgthjNLf=ATZrxR9YL@jS9JVyej6EB8w5HW z!``>tK{ytzLlXl z*2kd5)xIuv+=X#^Q~xY`ta}{OeHrk{=q#Ut_ewwkrq13>3G2XquO@Y9)9p;=8v+8I zAZA?De!5r#u8^1w-=#E$HnuYG^62}2*n9IpsQ348So=|_PMyk@7Lx2lMWHxRD6(c( zw#FJlcI|btB)eqlSYmA1cPd4hkYxzrh-nIAipIoP?(3S)_j!KLKleY+U-$3+`RAM% zGvhO#_xpWaukC`$=Bv+28*flUHUk9pNd6D=(nqDv1ulow(QEiv=HCxShbzta=U33c z}Sz;}|}e9XMg2I@caG!}i}2P9Et4r#;u$Mu^imr>3J}>itdTv}Z%D z&A~Cfe-JZ!yn_Ra*}l^Jz5sWt7?{{X@wPqOO^4RtR1#EztC`B&9_gM>;{cE>LrIEc z!~T)y9VIaZ=n!#$Tb2W#UV%Bfo_=|VngpxPz~MAm{5y#-f58i$9dWS?{;Pgy zT18b%E>wXl0u~`*0ahL%F8~g7GMokdX%(ZFJan3tv>#&r6Q8ocwcCmc-{*ZPMh zFaAOstd>LzRv?}Mk8b4Qwj8gfbJz)B>aV{aCeWa1DCoN_>PrxHR&1SsT{fHlai2eq z(QJI;$la)TaDA!E;W_wI2gkh>89RejhANWbM9!ht;-2uc7uSYnKU~cAk+PNTXvB$M zRsacRgCe744I7R?eilN~rk0*3qI?T{o1AB!I)cC1ZtFQrS>h%Bvi3JP!WNEzFg)nV zXOpbY?Dbt3%Y?UGnOZ#pV%RvNgWC&igYjBI{^>QaTNqc2LNk=Ld_NAip{OHa8@H`ix9<)p{D{QWv!Za_k zL-Wsajg2ZLO?3ZM$xd4gEv3S`bUCv88x*M*l|p2NziC?J(C;tI0$MxiY3U$v6ntPS zLLy+#uG7*mPR>Br6%dxd?-@qay6zp>_mKKQ`@US-^1v9D7hr@NuTIWpXb zkk@q(OIMU2Cl@S!fXuRHeVtv|a?Pd4@B$Uq-K+EPFG&?(>u1Lop#e?0j6~ z6KJm;&uM*A?8kx?dr@pk)*rqYL*3C_mcxDg+HpL+(APTWv$XOf2DM&@7q^Mdj?zO#FL@g{h}xxJ2fw-ZXB<5h_~+$4@tY zaY+AU+i;tEJAzX}-{d|{2n_wyES168@(Uq!*AWE+TngbUe^r;~%i+qHj12N;L}b+u zr@S}^7DF<8JSHIkyCh%}21&Jw(6!F$Ad^n|-4QyiGf6PvBIj`?1epdAt$`rT%W3!FCX4)tjZZ@cC}^&eD2?O3>xoCMmSQN^ z1Z==mkW2VrkRchjIJeu7yOM|b29#;k_>x|la-cdO%MaNz=xA2re>PQxql^4OK!(D9 z^Hukzl=;>q{q7CyyC)zar%BOXBQfF1?|eBR0vvJHwZ!l;9lL(eqgip9U06<0-f4z? zX&Vmz6Bd6w*Oz{YK9d2pL;?COsqi={oJo%>$x6yw-Hf}1nn*69T_I2FL3KJ(G69#9 zYeDgpDSXv4TCSjOdi=YZH*iqB%NE)s@yE)BnxdIMVs<6Mi%7?k_hc*X3u}5~JT8T%9ht z{Q$d;6+!G@M4uOa!s~C#HB9Bg{{YxaKrjxcoZ=qP3=7!`U9g-crD6zkwm!olbk>aX z^uru&1k5Uctx#w`ZdnB^jtd(M$44%Z@d%MM`1g%hWt<*^ty%&?K;udgHr2iSt6>g9 zdR5;Ypv@w{Oe}=)UHtir>Elv`z5VkEd?Wap%V2HybEf+^3ZP)z`0begbtxboPKy%GYe?7d!fFK!T&Q5`a4d$Pj z$-pnK=lhpsmXu_Im)3M>osQh@n;Ezpj0K+0{w^Wu1Is54vWB zfLAfH0r1H?iFZfPw-*i|P?B)TD>VU`lc^?z&nR~@ej-#Zfib_FU>PusnPJ7|1qtG& zYDXZ0r5U`S=i))OIr*&D7WGFICA+Juw(-8)yXKbRzMw&1B*Q&$S%rP?01cm^)yXqC z$3iD9Z0yJA<3I^a-j^DJlJl%$7E%c)y%O&{bHoji+h%~=Ev+WbtW%G_*B<@&Sm?~% z&oaxd&vcY^I6s2$347#9CD0~2+mTRb#IXwym*$_^^nb-;*dOp5G8!N8G~eC7sC#sr zg?(~8^kp3Qjc$jrH;APBw6;{Tpa;3aRE5ObS$Wk!I4znHblspddVdP`&e{MQZar$T z2*w_Z%l<@R+&q+RK;Jt2hD4A!PM0i=!h_jZ_A(q81?rx?39$1{kFoB2j2iBwP>eY^ zKQbtY`xxtc0_7Nm_iC;^hefsuEIy20l@ z*M^{;ZOs%QD#a*3UQu-}<=%T?PI`^HFr3Mj{!k(Z%+CXGMym6A!Nzbv&I$B$&-TyQ z^NQO(Ly^bKC)wyLPzsXnHOz9DWIUC3G|Xab3F+P|`UKpI#wYDDrUF3J$ve`1`x4*x zcr4$*$rA$zzHh{ddsGEdDJebhTIOg`{T`s(!@+QXsxlh#z*YqQ(rk4bL_mG|djJ_7 zQ^oFn7JyxqW*u_H6-aQ&i4K8Ck0A2Umd$^WOZw4xaMA>yq(fhl7B15vUJT(%rsD@kQblK;87)7O*B#o}Z~uydnI!{Hd!dU{QP(+q z{s;~lJbNM9H(c<#(k)C?C%qQit`9&1W9;zBf3R6|n>`AOA6w?@Z;ARn9y8e}Qs!iV zvfOa6q0i!JL!DM8cfRQ5OK`msfDo(=XE100(73S@YXHuw&{h8W!GVD|7W4HDI-rNS zGo7fSoD1wrpXz-md&)eb!;8a~Aem(xM#JLBM?gbnIK%ZGKpdrWY#_MI6}za@YV}Px zn85g=_|*=e!Je*7*kGc%qSGj@t^VZ5g^)w@ADUE6f)}ZN_kyI+G)wtDB+jM$z^aKf-*~Jv=(d`YzofvZ1Ojduwt- zNw7s>$q!g;USq+8!eaQwn(>f-Zl2D3xsO&fO!KO9FNY0f#ccXuCrk2={YE7 zT)x)+)!NI+2onJ0yqA;6=ohx@>YMQK>vbab`fD-}iWa}vBQ0iZ0W#7m#L^;;Q@DdC zw&i8Km2FY?(HGyH4VjshJ&%nB6fpJkjq{GxsL1!buR7ENLF~wKhk)SLXvoQR5Gv_| zSv{w!4R*x#!J$J2=&>E%M?aLXie~Vagv;aEW80PC=?Kvi;%G`Dg$@useXn!tFn!K? zJwx_c{QXwG><6A#Tec5`E$Kx@0nN}faPS>6z1Tg}Ka_WeXlG6+|rUle< zXC&@^x9+`-qk^!qz>@9RX&h=C2iN-DGinqqfAIYdADs_a`@t}qeQAHR!2vVI zhCQfiZNP>fe&=AD)a2xK%aS@;V;eKEG;@Gmm%qz61(yFgln%suID$(HJ+r0WCHb{^LNUGl z@}ufk7K(4w@40#hp?nOF8@G;kC5Mkqw9ROb=r$_s6-jRQBpiAxmX(`RH^Wr;gIbXr zm2p&+ZJ#Pbd;dAONNxNOoAwk67J*v`!O^f2tF zzmy)Zk>{`;6rS&G#UzigZZaJI);lzq>^Ht`v%B3+nmOeKebuo6>)3?AY>@76@@$Wp zrf?-IoQm%IY%yi$mW#bWpXW4jXaLZZ)ioP# zHKRyC{LdX`YXE8*h1G7`7RvM`HMKZ)S!%XBEPOtiXxj$ozM-O1chN>#;v2?RW?dXJ zSuP>iACJBvt115^;GN&d(+-rV(Hft0|4dez3@nB%%_J0e*MX78>~SEFzAmcv*IJ3W z$fBZT?Bj!Jt<*z2W`z8)an>!|=+{0%h>+r$^vy)o39V3GfFG6xTL#yWh8mz%1!jIq zu(EdXT`mh01>+V2QC7g&o2T~hhY~p{y7VpFFF(6rAqK|*GiygVETh?|W1^dJRK?=G zklccguzhU-&rxM2+piDk`;0a=2zg&pg7HY%I9v1)-!8eRT~i>U(;L0m18q#?BgR8e zNf1TEn)XZb<&IN<^NTj2!L%boU+Wl{l|K_gkEenvgpN}EfZ%tq(e(I0DOP5==vq7% z0y22t9w@z-@ojQY4f&}xp%FJ9gt+O{1ru{ZMm|!qE@G0EqYo(Fjj2bEx zAxnULUv`7CyjFDxwzWP*eWubrHu)Hwab5#WudxWq_he#u>H=lr7pBS?h-0(j;F3*I z<1a_nfEH)n=qY+y7F{*cN$OP;& zeTqhn)Oph(C&-7&ni&DmqK@i~16?R{%?xFLeVqDx@Zjr{b_zKN*nPQGYt0M*9kuPhpVJa|ICj>ZmkKD{`?^2px0^Zh;dGS;(mc8pBg71nV>l-2Rjk2%+1cIri z1^?BK!A%6pNrAVhm&M$AFX-`&c+Nz0%t1-$!EsSkFFTKfD@eOSSiw_AOG^wgtah~+ zM4SADgt)W9$%kDy&$)D64M@l+bTc(VDPdnhD5SX=M~Hw%jX+6>`J7#HvKI76#&(Su z(p>r>{rjHNs|cFf-rW!&cDDA6W<|y_VVS*sltUf98_qXLOHcvYRs{*@fe6L|U zfPl_6ZBwd?KS!t>lj->*!b+O*Y}5=54s;cRBk>2juy-c9@!`ZhLg!o6*n{cey3KRs zfYV#_%%k}iAdxJ$TZi9$Dx~vG^ugqkXBj)hq%;ZDV~n4zM@5^g`y##0oU%BTY_$Of z?M%T|kbuq+Dr~oov+(wZMhekQL~%8e(McZc$d7M~#AJMB_s;z2veXi5>S5h2CQ_%> z2tQ9A(Y5b)dNqtO-ip%>wcU9;7viRm#Y=P)#g_do7)ZGDHh_`W>r~M?!sIP3i5g8g zAl+eJ0-&8~zbNPiOG(30w4|D*le zHcuaw*k$aN@~V3?O|5w2{}nh~XNprnPhDMx(j;Z#0MM7l zE6#h^y`4JB7n8_}S&(bF2aLr|5>+>KPiSVGn3_wx?@P?~W7pbO+t;@(rZ5v}1ozX; za`zom6r@f>-VRz#P4NTK1&5h(-qL)yCS_m8g#!j&b$QgIM>$K6lb(!0;iTSgE;ej) zpE|O#u7=gj0;YbN7w}z8VLR^B(a~3B6zdHD%Sag?<$cTG&5OJ@uNvJ}S|ac{grNM+ z$!I}|HI`Fg(l5?qthA`9-k0c=-%@u4-~@=Ft!e6mr0Fh(!#jqY&-Fh2#gIh1UBurB zU-~dk(ff>QPZY%ckle(_m8JgfWjs_PPg{HCjtVBXrOYP{-NktbV+UkTU+C>7ym{we z|ER`&ru5?>xARJBU9{1vN8+?9z`C>NR3q-@LEVr!vBgYpb^>17Do3=ks?u3DZ6hFO zx87ZRTFR?z5W&TD`9g6Q?6>`8(OHG7z5*b~*HttDd)7c(43(emm<<6fPpec~mJyN( z@we_MELUJdP1#RV4u(yk%A%?x{t{59r8PFGIqrs-zDjB;b@}qf)I5zJ?!P6095=Dk z`%w@WCCZ5dWUFG%c8~s-9G?u&A#&BlQfVMt==nhOUC8zQ+Yyog6RJY%;5SU!gkpqa zov)C}X>k6&XEnnju*TCyTWs1W{qTSy@?AF}jirZFI$2`689 z({wG+W!If^gj|cefXVt$o4dj-nt;ab$&fmY4NB?M;Eq;|UcVfA#@>R5Ipd)k-=CK- zn4EzoynIY+oa+U6w;!kLv91Kgr>PQ4jx=Q~%To1oQgc?7p)v^m*~GM2AO5JypwhYU zlhfxHrUmO;iq4F;O+a&;`w|+x|6DktH$5vxyP8WIjQ7EO-H;(S zN`7}mR48aqT&wfFgFdHp=hu>EP;u8b6ooTuCfOw}+g%o|0M=_fB+m<0w%gLa@DJIk zse;i?k?6(@g`D(RF}K}5hG)|siM6bSaR6__i1qG!?}C^rBfLz(smo0tlX0VnPaSNb zW!>53jdNuOPM;*?YD?%z5Z0Y4)=qE#yIk|3LOdcfFhyte14am|dLUGfp8opy>}nP0#SJG3!2j4XcQ?0vFW zqZp4?=XZZ89Pb+1Xs>oh;asUpH`tEh7UMjoox9!r0xCCmCP!&EkbmAFF-4m~bmWfr4T|l~$cuHgEw--A?L9 z2nSu5e9?||6Gxc77vq_aB=u$}f={7yawXH+W((uJLsf-8VZB2kbxOKDAbibXF&fLB z4##iHH1{~|Gi%m*D6ekn$UFTh;dcJ@b|Kkc) zB>Ly6${Yd;XR<7h6VhL{b3Z{ghsujbp=GctZ6S02S5CZ5K&)o2dG)RQ=*0!u2up&w z%U~#!VC9qb<;p#yhfhfu=d_gy7AT#W>vJlK=s4ItS?suLtSw(sFL`lpx*8ze=O;P% z3Z!}+kG0j)bajx_lm6xkG0l_{h1d|VUm8ena+=q&%gRubzm?v7)Y(nJKK4xTGLq+? z|L9*_uY#0M?VukJdtVpp%I|d`NSJf!Y;hcv)VZ75K#cY^KC10!LIB$#mU2n^+@7@e zd+hFPzU;h@Y#G&|{Zq`Y)0ul>@2l;6_bB3G#$yN;b1h%> zHtyY}Yu8dXuXkA=qEIjtAn3SUYj(mF<;D{m@(-r=Bvb5GJ=_}`!)2{vE+^dJ%*SUI z)lR-rhhp^~TI#9Hih=NZu1~+G4D=UmgdD_k3>}U0&uI0U+~4hQ*hoYW8|YW;Nta z&+$5U^V&KO3PGnZYn8qz`PGehcd+%qinI0BAzIlQqfmg3tm7anf5)x6KwzHIIC~T- zuK_pV1>+@&c|=Od7jtCBs4oqrSAKr^9UGP1{*zUNUE9x(o8Vqiaj)mY6<%_PaU&j5tzGFc7 zB_`(MeqhMjsQ>Qsco_Ea9Q8HaMj}QB>rN%+9{iB`HwvZ$h)}=lZGBFDJqq_wwZpC) zIk9NR;>O4A6(#0fQcm>cqIuGfokE*Kw)ScU-+bLiH{@3AdUErI2sjSEdOZ+ul>@D%&3_Hkz2vdV=z|>eB21 z-xk#&?Z~^zuPOm8DRVpA+ylhmK$;vuth)&?_O6BCYb^^tu#h6QZX=X`oR!RGmQ85n z6)wwikA~1VE3`badVoEYlcd!zrVjD<-;XzU&R!O}x~G3{L~Jcxk9%)Kqi;5g31@hL zB!q6*4Ww@J>&xu;WEwiD<^8bp;(W*lcZ)ymRycXoZ`sTB@NU0OgtU4~UtGw{*p>``iKuEIkTlB1#-E++9QH1Mha9 z_rmgvF1t`fZnQnpd-&k?paY_EX(ECNyUc1A5J0;9xXNz<`EvdDYSlhds;QmaN#z8zcMtSd)O}^7TGP%;OKV#W?6T=&G2z zi11J=%T!k%5HD6ct;UptgttS9bhSS=zs$PM6MXYrU_X)V{D6>A-v0Eu*-q4ElO5CR z)-z%K1&BZui(s6^&6M$i8$!27<`2DZ`)5$~b|8Db&``OK6fuI2%7);nSOg{3`e$TM zfgO(Y(zdd8gPNi{xqWWoS@|*hk(rA=`KO*qvrS%J=8MC|qJC{3T5uN@Q%-&%GJ|K@wS&V0kmA^0m3!!^;U-zkdPKX|M!bB{&Xe{!)xo>em++C zJ-n>stbI^F;t^we&S`Qv#G2G~bVsik`0 z4b^NIqh(ttu4W$%K2`k&&k1o^KMXV5?$Vh$gLanrp``^I4*3tmI*m0gRQhDcOWgg( zqp*ZT#|&jv_sRnpXyB}HR#TN?L!X&eKKb6g>s;FK`eB~SMCYy=ne^Qf+h>cdFk+Xq zTjcyr1@(;M3>c)4FCED;T`om<+6PTQ&Oco!cNhdOj&m(-COo(Kx17a^294b#n~G~U zuW!D&aO2(TK=-7?R)>h;2aS(k9b?fNXHvpNC)x@>SnP6^6plml9ZAv@pHak>v$3Cc|=Lt6~;SxE{<9C95zI;s?7X)osoYe2_mOthE{-aGs; zD4seqKl#8jQrN!+R#;bK{n9#M`(tg}1k2|w<0l4W6`zpV1x%+M zUGx(zwp9TgMYC0)Y%o3?Xb!{G)4yPtZ5vinDV1dRkN3heKdW-^wg6{_*v zOxZVPl6CclzcBqIcM;XE>;{DhHCLIPtkz5D0?bxrc-84lk2a~!6biBU@)kswH3eDk zfOsJa<0;?9M9qSUemJZ|DX5dSck0qv&QplV9(Ru~EDB$Z zs2km5ljpf({iy%uQ7lz0gNfbu7b9=D#NP|Aluhm-pO`rrCMqSFw)g5o%bGmu9zy5< zEP#P0QRw}Xk~v0udHD#_Gu6|J8PcbH?NkKq_LF#7ivib!ONJ_E+#a)ys@F03S`r*1 z=W4s8u3V4y9)McY>?VCoGapoQnc?XxRRmZGH#AqLsjlv{kNrKa_N}J@(YvY1+pN)) zvg}fduXB9_xRjgl7YKqh&51KaU*D^*^VtkuC28N#c5O!^jZNBnqZoV3T+1U06CeN#0%RMQ8+}iKw>raUtj35wRn8S>-Di#ar zK%)c@=X}vc0rB%crI!AxtNX`hjrQs>kiCWY9XOR7IOcieI=65a@FU6btW#T>0ozf{ zTK!Og+=aneg&~874fYO)nV|e}tj#i94W_Zo1z(jDUbb&FAue0yij%op=Lk=%=Wv*So*>YL;)uTB9|cx13cn38eVXx7zQ2E3dsI>3jO9MuuvBhi%+h{{^Ld`PJE;YGW-RJnje%;s1+X z3v0qJDuMs&g3~>zvM(EKMM^3`O1hrJoncM$1g!!qV8}J5s>LNpB_R)to&&r4OV*Tm zg8{RA!EE^ZK z&{)lb*Bo)igVur{gy%di<_H$Il$1O!StmqYJ_r*TKMZ_~IlD9BYR01Wn>6?JZ%*`C z>bD)PI~sa~@8$!xf{j@I!|OP+Z3;wcIZacaKb_@Y-iPBC`WBB0S2*(xbh-peXe8cu5lA1qTD2}Gch4>?!dCAD-R`?pB=q63KhXn@DsK3RhlSi zQ(Ru)zD0Z5H0QZd<5Id}dR>LmeNQKxTZbB7^Tpi4{RFs2#uimuc5?4{2X4pf{GA_c zdh4f@nTs(Cs%-i(1?!2^&(h4y#W4D?EXt$iw}*7Y+hxf_&~wj-HPAsX5x{!=!}6R* zPgab+(~eiV(~a;voeRYPcV@GXc2A%JkF`jts11zKcdQ;^LwX)VNQW{+6A)KYbFB2* ztx`l3{n^#OYVpRA;z9l%y*{pS-|X;d7uD@O9T$s$kM+APgz5`<)#gQg@|zZuabemG zYgHtUu82X7JL8o46rk zao&0seTr`PNdpXV=mdnROYD8S5R-naAVyX9(liL3iXloOP2gwu9HkmU0Ct+^m+yy3j=N6fg`UE8Z#t{ zBa@Ir(|#j%{4YuGYljGq70^C3Bgl?k>giC z7pj;wuG|DHQ-pZ<{dIV8w(qK%PYi#I&xF9`9tc94byiW-VZX)CY)st^g1qOZ zYSu}W=$G=~XwotNqPEfHPThfJ4x!Y_EpPhJhycDa8vtP;4b1EJ+6|%(fjAd=AnNVK zEJ-a9kuK*-wgmgij*^paWZ2%z5B7QpG}-SBdT=j;xr(`H4!nQPy?R2h_HQDL1MGQ3 zACMUJ0xymU{Vd)5!{*r8X45)@9fsV}pJ(MiN%5#~n~6M&)qFD1pmea$YINsXFiQAg zT&~HgbzYuFg&)XI?jQbZWlzU8^gida6ZNW3P2Xg%9Pvse+hIIa0x-GH%o!0aVuZm{ zcM8;s3hdeYE=9YQK>V!f)vGD>Mb=|s$GeA5T7ce`6n66EU)*M+mdQR3SdT;>0z$nx z@oXA*>u5~^wbh>hHrCu!VYRkOi6*yh|JEJ^21_?m&%J%k&SeO0Q6f6kH~V`&vy;7T z5y^CAL;ehjKdltmN-nsJAJl{x&IQS6r8|$q8X-o$0uS4 zuO-Zxp?Jpi-_p1y((9;nd(<+ztzJ-oaDc2N!Jb2jSE+=9KflGCSBfL?j#G%QU;1Gr;P|3pWYYH;nK(W)dIt{FjwQz)xQ82q%I%4?3L7Us$Uh*l68T>Wy)$@Y7fCi#$HG* z2Wd%sLC<^&y$(YR@?iquv!McTD5M=GOW(!4+=wDrl!LsI3tQUE{47K zs5(VAD(PT&$;yn^q(=%)=`CL&hbl|+RfdDG+g8FKZv#)q=vVv3DjZAC+atA>Fxoto z*`tDs3znQgdNvkPP(8zeZk4K1Lr_I)z zc~YW)#)#~`ilWJYV$gP*j^uV2#GSPz96i;kS?1TLFTY$&II!sSYH=R9UU$fllmfKtH)QF`PPjl~clMWD#VxJCO$9o6DjliwyzyDO;C9wfNFR3X-(KYe%v z^Z!Z*I$R%gN2lbJL32x@W>YG~-J}S|n*H}R*(GZfg&bHePD^%WxUv_UmETmIBI~!F zCmek{?X+~JK`UPIv}D?TT6@VC4B9j9G>UAfVWf<7_9fhUP(v$;vtLNxkz>~F(rp?^ zQ_yi(e~#a(D6iA;L3d5Kb6%53WSdubM#TO+ZKcR@-|C4KN}?Tu9X)ct6AX3I&bI0h zI-6(Olv`$n*(V~074|rUf4p?+o^|9^*BC*fS*n7FV|AvY6#KG@{Ij$1Qp9PcTT`=1 z5HWv{8vOK$INQ}cWVM&%`rDEktu_RsW(GIkiey%T_Xj{0Egn5A4t=^qyuQJ{b|Z7v zLnK2*g4Q+h5N2{{b$#YNz0Q2luGK?0I3=S}hUlXdn(m-LPwZuRy&L_|<`kq7a7AoX zsWU8L=KcI+>=1LRHzio1$+WeAk5vhN6eIezSu0yHYGrW&rGASOk?ds2U*8d+DA;s@ zzog@1a&$HvHkFDzk);Y&pH&Gp&5UZLo>5gL8=BvAQ1@sthacUk| zMG9)rWeQu2G-@F*55aQ41Juegm;=CfpmAvr`Vqp;{Ij$Y-YnOaM<8`9;e-#sHV6h4 zbT5#>yI|FQ&MxA28&Dv_<+=RJlDFj%%289mTtfvuQyP7pI1!mNlZD(CC+-6#&Pl?a zYvm8p;X{4*U?%|);bV?LLUU>rpDG$8m<1OEQ~*{+ad&awf9w(VvdV+$JL*Ar^y}+? zX8&Rk+kX!)$gdEy04Q_vF8t^7^X&{yOO|+NeVaq2)<-rfiN~+{%d-`UD3-NGd1Via4G%%lb!azduGRy z?fCex)(+6~1N=}l#s-JMGhK+NN~^^wmRy&A`{l>b?BaLHJv=w*EV?BV5~Hk`kFk+@>R;m1v+!{Exy z6T)ZEyzy@$;43tmA@?1xRt+=-8CpFL9ejjr?!S?Z&Uprk^j{HvD}P1!g*)dMovy~r z0swj{_X;k~kHQd8_=smg+|q%>Bo5`?SEgXddr!^ zPu8Ac`Vi6M+>Jl8{qSpxl$}707@Eow!14$QF*GO)aWqLBm?B^P`%qowAUz)ZttCBm zedO2rDbYl3ZG1uw;FM>F7f}l%>T=D_lv83 zJsE!g@z(#cBbfY`ee%EeFNo?gcx)$Xz`N=&HTw1zXO+X%unj+*a=7rFYIW702acT2 zHamIE0C3U|KL*$1wSuoOvsN6$h0XrgTE6fH6#~D$4`%bV|7Dky_;nj|ewHVDKEQ)( zWE={0u`T<~D7^d6Z)hm^PmNB+m)E?$(sJ!ahNCC9HpcFB1|Im&BW$ZWIRR*#fB(;? z_J8NC`hU>+Jpb~?Al|ECUvcD*6o|ow9!Di%5*<{$6~mkQTb1BAfA&3W8N71#5S|^ z3FzUefV*Dwr@Po3(Qq9{I1XzL6!gcV?J>Xu{rg<+HvPJmnqOf?lnmGp?3EzykqmxO zN)b5r&LqgeN##NYW#L(A05YZkMAAz@4TVI$ z6+@dxGbqHZkb6pv0vfv^TnZod?%1!RfcHdB9dz2YNR?6{*OUJn8&7Ob<|i6jd+POE z>Pvo9!wF7Cw9E^-pZK>i`&cTh^iwg-{ev@QoMZm(mVLg#kvP=b$tUNt??F!P188k` zeyc!w2%%3-UN+hoK=2YsVq^UN7!&O!oDfD<9jlfTYIvZiJ(7-6?FhrChiZm-sGtTH z{87q+7RhV=dlRc#X2b_`;UJ9U%JY$8D@dz4GYdflW;h6x^x96S9z&13oiODDgoSR< zcnvNMjlc!7#*l?&EGKJeco&qzI1xLq@e{UmFs9l|kyBT?33EOy*|msDJd^r&CrgX#qo+pQcJ#|xb^HcMQDsf z<4l--+M$A+ENE`5SoD&vd}QbB)k_Ee|DyUwp5+70B~%@9a( zSeiWsBa6<@LcB|#q8OzG=T@RA!V9FS34AT*BHT!N%)Y1GaZFAMh)YJnMi`R5;-x}Ah(>c zlf~EE?fP>b^w^%yM*G`|E42@?TosWB_J0eu6GeI92m!iZgb?tlb>Uz^~$-N ztjwgE#>aYjLnJKCo{fAcm&y@6ANcYSU_q_>atLX>SP;J?kHbZM!>%Q zm|n5*N7#Qm6(yNZHU?iL^%HyMAlc0jmUg)hk8dz0c3`T;*3_|&seDqBiY9gfu$Sue z0-DYqNbtRhcl4U@aoF1jN*|mnUS+d50~_VeZ;9`spwxbx3y!;m$t8@R{fD{bFP*)) z?u@*LE1#jFRUV>N*MI#EZ=b7J-VJl_xEi0^zKCo6OIN_H@WzfinxG_c&Lg=D}S@^J~Sfd1BJVDd&!$J%G!6JUe z!V^PQ9YA6#)XfeAs{i(n3hY_gwv5{EZvQ5DtmyaZQyfm3^)_MO_KfS1vH`u zzy?n~cXCzklXGCxZ5n05>v1`5{dcd}WgK30>V4*c(FgG^*}h!_ShxiHJMZlGuU>Ee`O$5!bV9HL45eje|1B=8K9MOJhrZ^uX>P~AEJiy zv{t-4%FPIZazg@i*JiNJ{O2Z@7)y%`Pad6&%^es`06TVx`w__8C8HqC`uks|KL$c! zziE9BVH1M=D~X)M1fZK{23RP_Ls6SUNBXH1jSk>e7r8aI=`+< zTCU@dq_&{UaR#KRJSswi-oiWp;%O;BXsi(O0~$6S7!lj&3)~~&##{e({F2SbJGOqi z6fjOyjCx!r`RsXxTiX?0Mxhk|q+|?OZ3SLu86`sq!Yx8}lRm&Fnd5Bo2vfY5u^e)t zMIAivhOh>g@B#L3OPq8%rcmho_bE8W3+CaZ+abG+(Bk|4_!?$41H>7)p?wT%%7?wc zstNO11-p5Huw#Xe`Gd%$dTRgC&=rWItoU~A0KT_*wZ3nNKV1HfUPBc41gkx5 z=^K3;Lq3gLgMSN>893N#CMWsEb+~6aeP4 zcEZPE%*;W}^;&hRCmO@6-Sw>1`s)F5F*VLa7LyZ#vYSNs3JDkEhZe8tj9^0=^(mwIh1oIgyVe?yK)MyUIRT9@A-l3TAMDqCrrG!Q47d9xH^-E8` z3x->IN%a#Q*Tco?-b~#jd4~Xxm3FMCJF~Y-GUs>Rtz9g{`Fua?4OV>t>`5SIm=pVj z@(tXU{T3ELHEl3izqGhprDwB_Rc3@YLPf1Ws@K~j*(R52XMy3L%}|w+zF8i^4C~UJtJ$nX zqc43J2SwvYc~%aL?i99?FwE#Pdy0w~#MT=^uqe7%4FMW8IB#oVlDuS82K&I7a<>bv z|5nqh@$B@1y)XeWDkpt$V5o_^Z~H?;!n5;k8tO+0(+7>X+b5s~)d-k?LfYK;VRCc? z?L)UUlVpk^GG#QzAuzmVFGjg=+dTsQGi}3N4l)(=?=prE{&lgiu&SM7;pL?k9KHyC1M;eKw08rcx>OYt8M zNCpj_aM~qcj$aCvs89{(Xjim>JczUL;tWXR7X&<(V4MH&to(p+1oFdPfHlTr6=$qd z0rW_f^Tq_aHRR5ddh%O<8#li41=flLZqSrl(ot>GSgBIVIGS8GkuMxBTG5aVtEwjs zjW|OK+_pSVi+beAl7>i1%-hDu3Y;GaHVRfg%NVZ$6F3s;yl66;>D3Gyf(gss3s z3Czk7JK+(}b=5gFKNs&+xC>%2suJ(@M%=?~MgNT*YbbfM=N`^S&|<6LvnGWf41)i1 zy?>2*CU@|nctO5;9DHzPu=^gR!c_|1dVdbXOkkSj@e$;hWMlsGR-ole7{hNp&(-+# z+W1`mm%@wx2Vpku#Q^c4%V%ExoCJv?P)zUy*KACYX*sg;5(%*D$CNLGXua-xi6 z*W)Ozp_iUCdTBwh8)pE6lj?Mm7m%&IJp@U+RNLd~a@iFMo}XS7fl)gaCoy2V72%r7)(a+Cf`T7Is#6IXt6O$8cDZMNJRng4 z9Xc5g>?!CQ(249G;IX0e>~w|eAZPH!;UP$!ZiYA|Ls)Mn?7MvO&$~sHHUKBQgj>CF zlT-dU>;_ko6bJ^ruq<<2nDEcTwTEC_Kv>d!&VscYg~KV&9a2V!WK2H9`6daBAlea( za7jMjcm)t{DioUe%TM6WmbCRK^v6_iV_s&~DXT2aPgCLCEpSItYpeY@6~c0*FjG_s zj&CyTqjL+=_X@fDIMY~RAIKH|A_#pm4j|!AV7>Z=a0L}(#IWzIUJQZ#G%xb)?VTYN z=(@a>u*~Znjkir|S;Wryf7W1sAcod?1O+p{2Hh+pE3$Cnwi3LhHI`9Ju*bxq7q7|+ zK2PeUPCU)?-vAriDUL4A90s(Zp`5r{ONe3PbVtadH>3E8w7ebB42^J4 zbybc@?`EUxNbaWi0BCYZyWSx_xR9c4&?|#kQO3(gF^l!uMs9<>Vx2nb`gqP&f}=Qx zh^!OI`GmRyA`)A#RYTpFv-SkH@+fm~w$(2ljn{~zIXISrWFP@6P?b<3OEnE9I;fgT zWoZ?Bdkg1STA#p*baj34Q&L2_Q zmX_~T0or`yxC|7lafZX#%zxT${Q4MN30`jO62pGi{_tf7;|iQ$2tA3%eotl9JjKjy zPK}R~8=5T!r{ekkCK+8bD1Lw%dl|7(xB=tw>LK(d_^kr9`_%fy@%k!Nt>wlTM&%C$ zKn@Y}!^B0R|1o}gL-Y(x(VohX3C>>Y>=5eo!WZaF$pdK_-~oFsnA$6n{+n?0wnvXZ z;P>Lj9>Y9Q8rf*gN2obT-Klmjf^NQ`dK*G05;UASk68c$tNr7dJvT$PSuCo7Bprox z{Al|p8kXR8=2{(N+qE>Sw)B)igTt&XEFuOTUq6=|)`baa`Ny+Q3gj6@jv0T=*q{v+ zmM`U{Yx!fNnonB`#E4)CBRw~=IxBg;V&&5?GmX|2+$SkbSIj>z>zt_)(h~Ii6Ox>Y zl|Mn2scb|UusLC7cX5|_e)yzIMIT&}BX&p6EW&pB1Tq zBIGSUYZxPL0#QPNISeFPNz^^E`P?;Tzxqh4Q>nBb&UYV7~+g_)4X)7!Ha-bP5>Kd0f2_8REP-~3;c*s z@<4}jKHthLMqA#)l5#d8HkiUtgdhecy->lV6$+4gh~a{2L0o;yjGr>7+~!h`81F$+ znY7h9)dlW;X|Q!^qQ`YbU@j#7ge zSY!ZQtr4#Mavl#5R&m(KPGRNad*dm zamI6rt(7zk=}$^(8=h5?QX69C`^6zVjlFrE5K;UPHhpAHu*3I;M+LRZMU-fxf^&Ev z1Pqj{6>Kiu6UQjBQpz{6^nC4HhiPS;;Hp-#QfQ=!`L|o&ZcmhZJ z3m7?H$F#jWt*QbLc+<9MdP|#6HAQgWqmeizlPJ681=lO#)?f<-Vx3;t@v#X>3?G}w zr5n!P(&Td(9)n4?J2rg)kWtONc4#7DVhFR~4F~oKtE^F=8CpBxQavIOWD0{Y-b^Z_=2Qiz{UI*nj*R%#> z9*_;WbADiYM{9y7PO2`2k9y;Qy98==7W_9n8mBr14`Bzf5W<3Fqjr)4=kJs+!SCm9doXQY zDk-@LlO^GsR2ecP`q9s;*lfFmFU6W)fJ3^IRBQEe>uFA0h{el81gFGR)XW^0 zjz|jC!M-Cn<%`)>lpZwW78rEtJA@ajm<8$C4nqT$qrSy$27!3eLJFZA&APtPDRSt_1dtbxde-QZ?b4f;Qea;G=)7XS@clp9*X(R5(7IjG$UA{5h|WjrBj0@h-MqCXoPb|ejHjJP3`*UrUtTDh zS^YJI{}bw)k@J?p;dRUE-_^kw!A36yUQmYGZq?-PK(bRmRsckZ_0V&UF07D27OFUs z$^V_N(uyO&u(Fak`aaENlZnGVJBB^Lq}g;cEvUiP_wt3p(28^SkH&ozJ^3kF(Nvsi z!uShx`)hZN00S|*JNc6CNo()CV0MXW!RR@JSuuda85bjI9a4OxBWI9r^3a&(lV(&5 z=C^#IpKaGjU+s7e5eGbf4WHCy60;J{-ojj%KJePkv3H`g`G(W-EVeWRtGZMfN!XQV z<)G}bceJ3ZiBIKQ#J-3&$w;ZM@8rAo5VyFM)~sseBM#-|h2~Q$%h^l&?ze?4T{Z{= zZhBZ3XM zPghLu>oCUBF#MgNriL%nKO`8?kk+HW(msh%)+n1vXr0kt-2M+}G?elhP;Ha}CV>Y% zkw>uJqMcSA7zzdpkoZz6|u)H?VQMLv@UeQh=|MxU+=lmSXp|@eBLyo zr)J@2dJb0K7~$j5DBagD@*y?-awphqFElI}duC!3Iwv|-6c}Woo_3;ct7*w0s{N4c z!fnmtdlcN>WXf2p(g!c~@T6sEjCf_7bP+l;35rJ= zXQgRtqY3*|exxrzqPV9Q5%?6jB)w1`)*aTJ*|E{9R0V7|Fg&dFiIe|9BxHqsYsXs3 zE_6cZT{8eWn@i}n+WNcD@}-ZH*)H?MxXtx)L~j1NTU>tZCaes2T3tPWz4!gFI3FD^ zmF&p7Yz@#RiMq)>qqe*Pc5cIK;g$C1klsU}Wj)odf2nfa7+L-kSjUD||DMf1h)OA7 zSQ9SP3Zgx)Y4bduf8r(VwePyGO;P(rUlq9*Qs4WEck2IAD0Y>MDYScPdN3ztvE%QH z!XGNa4X%N{8BQQ7(ChN%=?m#zGd#Z))IoUPaPA9^IO^6o}#zg}|% z{X_O~6>8>~3Y!d)O0M*)Z>YumAe9;2x26ixlGQ9Wlh*xGUG{CcX=8 zDTlSwd@TpV*wz&B4NR z);H&$=EgDC#C*z=`G1~j_++;E#e$qEX3BBm^`o92q*pr#Z|ys4njjssNt*Rine9)` zIVZeftyff+g=qJX&?P9ua1i~wsvmU6;stxfx_+9s6)7vGE1kDJ4nm*9#ZyGVWe1$K zl3VP&64}o%j?5=3^u{>&#KLR)8i|oqzI;3?-`{l}YaK`D%fmtQ;JbF0(B<93 z0GBVsjPbf>R%c=P@)cg~(P<6cQ`4rrg)66fuaVZ$Ypzy1Zm(SAj1@HxCA-VqBw_F! zq3D?c>*mxIqHg@*6LktQsMOiolx=qN=jRQP0dwkYKTY1%5;sj!HQ(pF=*7sRw-pi< z#JV+(v^vI(XVzB469oNsgt6c8-8dN^Dn3qP+fP1F7`gw#nQhyqp+JyeRG-ZLrXjfz z`Bdl^yd$k2;^sYh&C?75GX|*q>n-?=Z=5->xuL*uZzO8kbJxDGZl$a!X9}G|q^2xf z`STC=6^{4Q>`G8hd@R|D^amxjqOaYqVmb9ixrBa^mPMXdy#uD zf@+yaY9{vH+xqI%cKwUI9^K`}FOR$@qaFm+MAKF23fFgp-lf^iy>FMvMk!}thT0^r zl{(OPcAw)7PJ2GtqP(HTb2FqUUGIrkAIdGM=js`!$>ThY4SGvVP-EXU`r zDAT{^XTV)dI?ROQSxjL*FoY(AO*t54)G{cL8?KNVMqA{B9GSaJhOCqdQdWH%h93W= zd0bU^wqJI!QnOZhquNfkw4_YsXnSzs12bCv*;PZ@9@XtG)DA{*g)>cu!Sl3=!n)k6 zZZs}<98L*vw{XlJGz%Qc|qc9tI1p0*-|*-!nM^0LKJItPo}X_`}{d>m^!qrjHH zhx_d4my}4TpYtn`?*=dEMvmaOpri+OE1YK{<~}qzqUSVYWNtYDc?Yo^s>uf495p0_{upScu<8N69dBBpH15{Q2qoGp#t%Ov4R(@iOC> zEU)UPCOvGzKa7^3QU_YGim|m zo((>Hkj$JChYUgzXKS@mdY-S`(EUG0rFqdh4Rq!7kot(eJQRMyn-Y(4eEo0 z4uoB@+1yRcU$#KX2?9+jQ!}^OG}w+gW`3@*%{Zc0scC(pfz~T^{wth&uj?!(-4*J1 zy8U-Ri@XEt$74n8!vQqX?H-@)H;T|tW33E`%s@gcJpM|fGcq{#EPE*gI}K(gxN!<* z$Rt?aEg2NMbXr_uDYaxc?0jXq32(4Z6S>3GE@}#%MipNHqXS%vHEnii;Lpoo9cxpf zlnrrR16OQlsw+Edh9u(Jf_JG#C%-iCzC$z4D5?tY;7GVDGw2|)~hUeqLKRQR)%#_uLS2s67v#5xxflDg$n?oKz;sW zhvG+8cjp^kp_zJ)pZt|J&iRS!JY5t|imq>Ev3rdj5MafwO6!0akoyt60zSTPk!yux zdcs~>2TGazb*LROMT)B3{N-ME65$CQyFZ>Ur6M7Hk0tVtyhKysrE|!~Phc+fdW3Hb zOUc%=sK8mChfQIk9bS_X-nj~)H~=-l$)6eCuUQdHxx)ZVLoVybFVGxRINI-+`lr9G zzfA%^R~oz1FwbcKaOJp0pyGZ6PL(fwpW|xBnDbzaM{kZ?p1J*p4dZOZ$IR011cq&= zAEVW?*3#+(!f>uZ`UQzY7B+!k4CC%1IJcDE3US{n`Z03}VR;Obc*YJn1T2E5X~=o0 zcV7Xrz5A2KZ+?Rs1Iw4tp7pPW$oBOQ`@bhD8X(_D{Yc31ycIgxGl*b*2I_LG)<6~B zltqu8hw%%v^b6kOZ~8@1RbxfLgBmF-j)%~u!=G98fA?RdxiLyfeHKotzKSavwH(oI z;mq8IFOaUs9(wL&oDWbOXZJE%fV*4SPTiH&8-BZS^xOUY{yGo8i+u%$=eUr}b9h0z zE-uz+-geCWSl8%8B*J*%-J#OOLmkUWHBk-r%M3=BRbZ9KeNk4g?os~+&?xKkLYjiv zRBYeP-~P0fPyYiusUs~gXyCH}?iGTBrUVtDbJ);S7!GD1+es+oKOcZF%kR)5yb3&? z9#aGyb4M_Tb%!j^l+K)0R%gRqj`q9ieq*<}>>v0yZLUJmCg!7@ zOf#hJN!s}bXVY@(MlD*;&elA%T&?q0S7wpJWly~b&~&BKhV$yp0=QN+$n%qVCvo~l zKJDafGvGCK;QwI`f`w_C#`9scnAqxiylGr5wc3`I>}tkq1@oSP!>~0C?U%L>c1me4 zook-g-FNEcz?MIZ?KTK`c)BJC41sMJc>HJS%OqDDeFvZS$;;g%_0mJeug~X-#HX1d z&n<$U*=x;n$G%(QjL=7dpf!2pFySZY^`C%oVx8Y@T&~=$|AWQqw$!(92bZkF#QoZ& ziE6!=146K{1E*g^?XtaRi;ola8E1&R0;hu&)rjNSyF(rl*!2w{-(y8!rao=H zof)Hrqdl3CtZfY2E7L=_vPpi9Iu;XPCcxn0myAv7&?udM+BWi+NJkJj|MqdUa4%I7 zhphwo6RP6U>^~NkJR{wi3y`<3P=C~+#?@^ba?g0!XHqdM)aC@mk*g}>S=xY#wGRJj z>@dOrgT7Z0Sf`4QTEi8onZExCeEY;JraYFl?dPaCYSAK_7yfF#HbG2=6X9+ z*0k{ki6?h7e+9i1tsG60W-IGTc=WEVVs%LV;I`+#wZe%9KMylp!-nZD*Xl`2{O~1+Jkpew_CGIp!!ilW67736C8@A$=C&Hv4r8P+;m8Dx=&e$ z)1dEZFHcxVxmY5}Oc?3H6EDK*u*$8Q%4=|{#9N;j1v>pFC5oy;BgO}%*ivjy-^bLD zFQ;7G)km^k7}@g+9^*;llOv#{j5A#?fTCN3AQpE+pmAAcjBut!b7ZmKaXMpUkem6&acFuc-;RCL^TqT)I;ASF_14 zRUA?38QeVt3mx8&XVp7o|0qB3B68)dxQ)r%dRwr!otv=78!3(vUV_G?b{^ZJMcsYU zjE0+YJg~*q-Lfut6#bTY#G75O(@=9_Ka)vx#3|7ozDgT2h}xMp*^#jDH-m{huA-v= z8(VL*h$-QF5@Mp&5OOmV44cFU*xv7pOUx6{CI}T()dMV0w`72sRPB2D11adn(mR5_ z}TE*$)WqaW1zAl^)%6~*t`la=WXb674_MKCu)95W8 zubv4ms(LmShKyYG2TKlCuGsi(oOw4>3K{x>v$_|Be`2 zedrPP8~s-j(>YglcveY{x~6w4e{zf=tunN0cM#}aXijXVvahesy24b2)o|S*mKj@B zlKi0{sHf<*dH0C1G<1{%mcGSoAo@z7^pezQ1{V%T5*xuQ`uvaza zp$}nL?ipE0<73Y4^@s>yX0I`$L~X{__Gy7RNhg4+rj*|#7|uhleJ)4nkZLCICd~hN z$gMq5`4pq&2U@;^1TLE?M3#7)e;Pb$eo?Nm&__@&&3>&S7BKZEGb zNl}9koLD0??`W7eQU2OLF^{1@FMit6ppG(QCWN17VEDxBfV>##?GJMVzY0C;;Si|F zcQeBit{QkV(le9RK(fzC(0tO%cCTUwJ{{Ppyx1h^My;>6DvVaa3&vnPM9n>^(Pk{B z6(YXC-|G~$EC}X3O*a83oU7mMW%WRj00neyczUmap^1$I<#Ah}8div)0F>&Btbto! zoR&gxX=x8v#S+*SU}_zp_he!X_%>YYTl@h~i{Vn*#Zq4z&QHZeTFj^gfH78cuy44a z@&l`^k(K4CMrWp4BPZ-puSq$RMqi}|XryrOnuA$4w+@McD?EElBDYEo&3GD3fmj_T zX3R&N4c2YU``giq70)tuO2MTQ`!-KjkA_0S)F%aq(b8NoywZ@8b}>HMJ1R0ml{;=Y zmLXk5y2C4-fj8*?3Dc^ZzC!OboYpJx|bz7iY7C1e@Oy11o zWG?rJIYKWN!w;XQ`Q9-Nm*M1M`!6;2I@sJx8@E1t>pIA5E~K_cbo3gKW@ULEf8KgA z1+^FA2BRksDqhnvPs?Fv8v6%~K&PJ>1h}}%!+wBt(TRzDxVX2PN9<}p&~ICF^E+WK zSNB3!`Oi%VlWm4O>k2GV1(Ozh?;3wQjW{#^3v(g_Xu)w)Y|0u&{(T83`e;^IWb5@q z)9*#wgRAuBgY6%`1>~h|H~aH!G{;IqmY_2m1hO1f!{W+QOASaw66;)#90D(WCXtwi z_V;l~vBdQds25W$Va}--r)~Fno<_{%kooGM9%^#8bR3Q zp)jQP;eFdeZuGn$fTfTLwLq7TWh=AQN22-I%p5nQCgc5_Pjz_1hp#Z~vU_*ZGG~&F6M44d8b-#0}V)w*@Y^(byUrqGQ z?TWgK2ca$oV6~%5jXyJ+Oz4#;_0>eB_9qdg{@s$kw_K?O&%gQUJ&Nl4{=2E?t8icc*H)Xy1s1H67JDZ;cmr$iOv3C_PjL1AROw3c)y~=< z%Ct1nmri>$>AVISkTl_bf+I}QWNbn=wS?C)rJ<87+8s9PvbTcg&4zI$4338?eYMZ8 zaX#4eE9k;*99Zd5n|p@7Q^6N66w4gelygh++W&-48;^onQ%`@D5T>Pnq^?ppn)XM< zg)qgMKU`koH3{o*Dyf!&l4%f?e?VL5t9=u$oC)YBJC=5l%n*T=qc6KCtcUczQI(lLve5Eb-iwu3(i>Ug?32#$X~w^rEAR* z*Z;sdg`XHt^QXSPlLd7jzFL~w=Vlw=TO#Ys)fP4RA1BYTe644fIe=b`>gRH5sVzcJ zjH{zi=7svr5N)*)Sn}Cd1*AT>{d+5(O^zCsrXaU-#-r1$Hf04UR6Y_?2XQJ7Z+yb1 zH5t7NQSG6p855gDcKcRu_jv<2i1p#pWU(??GNo`4vaiHQp#bJS$h^+J2rA+a$vxz^~a`I+8CeQc`N-vsfqMCaeNAvSo z*6mGuI~INTTZD1|u`xEX=7f7PdXHU##qUoSg?6IVj|&W>Wh35sTs!5Sq>)5B#0fuz z(D%5eMZN-tde25~KE|Y(tRy+_e<5_FO-BRr=YUCazN0@7fr=S^O?vyWtD)=F=dG$; zU5&l$!e%q4JNYRuO{Xl7Ci(g}TEhoh<6tSW8Kn8R{BC$LpVXixk|4vDCu1ZT`9jCq zl`@GL50uR6u2Az+XwF*W>AqJ)a%25z^jJ@FGMJ7Arl9*k@7_@yv61h0>tfWxPrec%U(;u* z>?_ZNu6Ah1=uKioJ9WAuddrjgoL2pHVx;&c<;pZDtvc=0QL0E%&Y^A2Qq1c7-uxbSDS5dXj<9ZopJJOJ! z497^jhieq|rnuzaFGwgc^vRF4fFzBUW9Lx11fI3(Hka=U=hCu30`dr`7iPHuSz{4P z;6P2+*DD8yloY5Etv>n;Mh2eRW&}%id4QJ?8CF#eeJYF%tM(OA&l4H~D-IU21j%sL z3ylsvNru9*Fx;vWTF`zXU~EF#Y!pC% zpOfQg7etyc6ZWtl=;zE%r}>Tm+{Fn(NRWcY#bca?K(1U!-D9!+O6jgu}(mf7zm6Z43AnTeU4W*K2vf)e`3j5~3`%wYr z2G;@UYzMg9)-&2eKt)7Do$gdTV5uo5q+PoQ5(>sO7{16$Tb7nGK9{XdxKh zOTYsJjlG6k-186;{gw6qD^Hk(7zaA;6qL(hKjFbwxsSW^|4Vm6%>*;@i`)EaB+C)} zfB!tX{{C+vcmKb(fJjwrI2E<5O8n+w@IS^4N3Pr~8!B1?s@u-*Q;^B$K2jzA5qxkz zsk-$KcML!If889q)PVL}b};nl!9!e6mD9wE_y6-82i<|G1FEvOM4`WnJEGz~*S1Ui z*G~QO(Z3Mf)3< literal 0 HcmV?d00001 diff --git a/pathology-ai/diagrams/tools_architecture.png b/pathology-ai/diagrams/tools_architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..54570127313ad06809912d81e8181e24c174a328 GIT binary patch literal 194657 zcmeFac|6r^*EX)Y=(-GPFhxj(Y$AnZt}ZfUw#~C-&X6G)BMoH8kTTE1HWSL&U?@VF zhY*s?^E|!l+*|kaKF=S&Ki@x|Up}AvzR0%s{+{3STF>){^k~ea+v$l1#wlF^FZ0c~w z!uIw>Zr=0Um$*)vJ389k5#r&o`OhP`Z5_;bZWNqWgJ=22PFm{@5fRgS^uK+#zc`5z z?IR+R`S*(2-I%HVgW=eYb@7?VQ)gS%ru@%ZD!oh4JS;4b|L;`4=F#MWnlsPy*p!cz zf2B&6nIb0B%&+yQrgr=Akn}MHndH4^D>|E7w2Se_&1NbOn2~;7%yx=g{pQh7mENRR zC_ZL$!E0x09bW7|UlQC=Ka1%9^CNt7)QIB$`qBHuKd=h__4Pwq^T2=oM0E1{`~UXG zmydS-U%w^#_$(i--tRAopa=ZFzeoRdIFtQ8|f=&W^ZLZ|Y?iH4A-Bk_`CuCGpx+F>sBhozaIrysY~xt6u*`FpdLxa9h3T?K>f;lwU3XSZV+P-_jDIo`|dmc@pN!a zzsn%w_Qvv^n}k;w-iw*6mnSlkho9@*=5V!5z4FFmbEV02mdW+Uv#-@&yP;$8;$EKI zeTyp#+ot>%P-Juh5G`|tWmzgrEU2I9+U+xmD=hDx=0#E;|Ge@Ub@vZpAuVkzC z^rf3y@Uz)ai1T!>bp&6SdGQGE2l@tHCOd6Zd{4+D~Mr*WH`UiR=?dWKk=TSq)eD=D9ijo__h)OS3o*ZC8`- ze50?)*Mo&7kKtFb{ZZO-Ar^gW_#_giobu&;(!IHN2Tdm0GnHvo&W}tLwFFUI`gT6I zdS}Cr)UrMO$uai2>fPW*d<$VJ=`+ud5+n8BwiiDXtnQfl|7%D?;l{y`d7(b9fropwJ(vGp_e zR;G^A8o1kU&3&LO5RATj=T?m8#<=~DXV-5<2pZbEOy-n67qKO^OnFPPoU9lxM%<^N zV^hqfq>gi>bX#n?G~z?X{TS^bSYJT|9G?cta8_YX4BF$y_8zSDd; zy{h~#bnRcv`SWHEq3?*~a{FwnMGsy65#p!s`R%p+{MtzHbsM+Q2o2-aewW~Xj6-??KAu&c$EJ!F62*UU~td`V~!ZSYR6!TN|WyG1ykHq#Q)=<%`7M z1Xxh~^9g(0V_3?1QqJsrrN%)xF}!BYF&XlCRU4L5ui6xPyysZI4(_a!3JyO$ZMk&D z&0Ly{uUZ=pFmFqfx31n^nNJtr z<`C$)8J09DI2x{s&QoUC4)@GM^5aKg>za7D;1P*8=J#8=wKCPC^?mrkF$K+x(YCgE zPOH`wnH5>ZV+Lx;Qi1-WtKW*G4!mm%8*+oYX_Z|72fqTFrOs>7nv#vFcbl!G{qTsg zrOJirkkGG$*FQq#8q(VCu`9&9uo;1^`sDtBgLQBm$Z}6lr;Be5QOJmk(*!EIemd&6;<2jSJ-uqZ7chcr32CKb_ZDNI-{9%vp{#vA3kR8*YUsCLs z8+t0oQ^`j-cM>Lhn~$q7h*7w1EZ$4sv~Rj}uu91&kSax5(JU`pr}Va#;BZlkSb*d+ zA4(2#UgxRq(4UHmez5bsm@C~@gG?j!N_y9CHAO{;cI?iS&o=vD0+O62J9`Y58UzO2 z7qhkNBx&`+w=db`g$jNnMSqq9}Iy za!Dh1c@5lKjp@qkdk8RtM}E?#5$%SzM@<6Gm1LCIKC~$?8^{UL`3Bf9UgbI(1BLQ%5chy5FG@ygZ%~mQ<2m*npY; z?n^1PI@3?qe92|z+ue=vbgLX@B^{OTNo5$JXzN0mY&i2B+?x<+>e%DmhrgpY0U-S< z;hkyTWU$V^^2(;Kq@iSeaZH1u;;evlIR*|QmJ7#IwRVcTa;Y_G(WYX)ZoYvt?_bz@ zv_d!RA#_UGXhZNU{4T@GQ@!PovvR=l+V0MFmQ5dAd9p^HKA96U0kCG+G+B9&p%;C7 zG!Np5*5l#%dgi=BQ9u4>vCXN_uGKmQ+nTwd4_VfI&V4o}%6iT{rm&h%eHI<3x_Pst z3f_}){(G%-v02!RT0BiYT76n%&|_7P>ysGd6gpnxf1fgoi@Bv*o*M6V`t^lH$Yth) zUb%B1WWV;_71iZOE(5OY@Ipm}Vky(9)9Id$kVz;-C~RE!h3Ed1!X{=ISY zu3SB5iWJYh;!f@5*3$MomqCxx-W5oX!kt=XvDVDN43~0y^Xpv4VriX>etdj3zqQy> z4~L)eoc61a@Ab>43grU3!f^N9x9016Tx7?T%QRAz)P>l_HB;_fCVscDveIW;A8lLp zvY#{Rk}VTw?rUS3nm+5Irb4%^P|MFRczaxS;UPsDxS;Udo(^@Lb0~)9=#=J0Oe@3) z7Fc_wkHn-!YFlPb=~qGOs4tt$Wnj4ddgy57>|)4D|HT%OWAUCF7S7Bw?U}01w$iHw z4?Xt+q8OoGI7tiJK35=n9*}_9fjqB`w)p3-awp;*#*-LvPk68Lo!kcGz%8gqZ|(t+ zl85F>;2DZJdEZVl3hTVv=QoEjSZmi`iI0Xmb!-D!u06b&=zF!b0A;6<7bZbZL|3{` zM~Z!hOgU4r*i0vAXIL@!o(x3`pT+e1)hGm=@Y+VIQ}jexHoA!ySY3`3rp+~v6xDvhzlwjeXi4K-q#|wY3-biTU?Ca zt(X$KVA-A_2q$9r>viUw^NOSzDf`w^?+!m@wkPZI=O;?FJa zG|~Qg0+%%$=Qi_c|FLmTl?W>B9{0tj5sm5%>Rm=i3_+y>_c+OD zsX|w_VQFZ`V(utp7u3=Bn2m4tL#Si5z1XDFu{G}bA_zNLUCu7YWj|7An`(}8p4L#CSNqJY?U*^;p z7w0)!xk^J}$#r*QBjJj#af|5cQ+a`&lwL#S%-lCWqozKsLNvN50*PGGmtKbcL42;S z8Y3Hprss5VR}!~;yqGA%w|JbXuH8FgR$~6prIhvdSqNJK6S8HLDgGiIG6%ZlDp$Y3 z;a1jZZCh)rOma|4RvZ5&bKspzpG~PXbL7!>&BNZC)3#m=0mE=RK4VVBIy7()AN-~G z;yepC?4hYB&gB@3kFBmTx&3@!#Ig1mDhX+$=aKsNILM?^CfTqGT6FPVJFYa&vRF^< zH$OtH%WHk;$yPi_Pm2J2B`fY{#gbl`&i`;os~f#~VjMmZN{sB4)jv*Qox1^YW!WfF z|1Il^S#47kXEgBIc8ah8XlBlZL(ss`?VjbzakH2s0nx^abG8r*xn^!P$GjBn7x8m$ zHC&cFZa7$KJ2+*roJ#&8w<2Cu`V6-IEZ^J87itt|uwBwviixYF`%*$a!tQISJ@q<_ zB;5B62frzQcfz#H^qqxdoD%~-W*DVQy@B_jhp+D zrIAN(BOE)+aWj1XUjfOlT2!&Yj+8R{QljVqr6U}nbvKDkC4`;0Mx`UT{UA+0oQqgL zE}BSSQsB$Hfh@i@P7`~CHLAUiY3bly+` zDgrMK3vV}EhB6mb(Rq|3U&H-NDoOEfgzbAGARtpUohI8`wF+0aAAd0Y-qNH7lc`d( z5}T>;2LUYRooMXPFkt-fkV5CzsBQUlNw!Mk@EI(x3^p29G*#GmYYa=O5DR#`px?Pq zGK@_g7jwz4T;;s|(yyFlcH^arX&=j@6NMkQIZYF`1^TRy1%xey?}%@YD-w^%_$s-e z;z&0&y^WT>!l3H?dlWjd@~Z9$oZVS$5f4V;?PqhWj@=uym3wwL9H&(I@2l*m%+W4x z*vN0dWZm2s{Ot7gIzWgTj&E1sR?_y}F1N{1lXx><#}Lq5)TwP{8X>1r-L|sN%L-jm64Axa z7g?LiKVNA4H<(G(81Q}2&!%Xz2t5_2aG5Z++9VQr8fo9JZ33N898L*RG79ktulS`b zo+cJ(794r1dEy%+^ZCKu9mw+lw%Dx#qCLj0@HAL_=e4?zQ9!v`kEs!^r@fwVGeY)I_8VEn=v?mX zXC(W?7e1cu2^+OqSlVp5G$_JwqavgA`?j$<;4Mwvlzk~2HK8OcG{S6<^Mh)Y>0fw$ zVvVGVVW+q$KABxK3@5vhWGeC!;Fj0leaMF4aAZ5LQ>CnpFz?c#lo&D1VW(^@al5w~ z;IQY`ghq7(Nsoq@LZ+9+TRSHe({L*KPv!5W=rs|{(C8b0WqduJ7G2oDiWQaggi@fV z?N^(Kg?N|W&i1B8-}CoefFM5wiz)8QN0mVDgeXVGv;E@ZZa)(pluRm@I|CS9zVSXc z@LXSmCmcbAY_QnIuj^yVxFnSu0H;PEv^4qHMsQN6VlMJj%w2UBOIK=4>ITd+j2MbQ zf!>U%BC7MU5yU&|EnYObD-cs!__OC>Z>zsh=yFJ$jm%Ar6Ls79wRnh8XzSOOe3!n{ zA;It72wOyqc?z|tq^7@$$C2vvL-g+9*XbC1s;Y3AwJ)-E=6GiBHBzUP5H(W+_jyV6 z*yM#uPQR{Z;n|A9ajH|CRJU#nrMXG-y9&V6u5Vx7O}La)kgQrP6S0oRe}TM{)e0HK@*W z&;Q~RbrPlci&^BZ9gRQ7isLSozVwv`wH>hGR(%vV6peiOGB!~JjF=wRy>XzW&2S@3 zQS43cvdHSUJG?hPhIHR9pZ08jew8j$<$B_kE-0&STE7{6-l3i&&EmtCuLzQdV=qvhSBcu3*8kgqBbI;)4~+r z4Cb`GwwFTR3iD}f8GZIdWI`YfirYl}z? zk-ArSk0o>Ax)c108>(?1-y+qFVaOOkBE^;+IKxdK%y90;?pTZlc_syi(lgw3t{a-C ziECBvCJAvUh2ivnu=YnYK?1`7yaI}f^P3wfu}r8VQ@Si^2QfdU4=|*OQL4AhXo8fh zS)A*wuS)WXhn23`Z!dSjDJAKK8(#HGs01>FWgiY#r)nPk2~cJv#T<_#PsRyBPN#vo z;g~zkpJvjrdYl$s5qbG)%wzafdb@uwE6xOoEPS-=1305K`hAs3EaSF>gFfuf*JUs8 zY{@W>*Sg$H#9tGwK#U!SqCc;s67q@U!H7tg299(pYsC&(jNAHXq)9_KM+bLNt1M?N zM12j1ka6H%^6Z&uB+H$r3o(CnxB?U?+E$UBOXpsi9jrD?y-%f%pOQYeAfY`jXB+6$+Sw4@p;v}dKT>9Y(su^M{RdS#BE;?#C)X$}7Ma0T*f z7*1hci3gOj=jd;Bd+lxqsLy%k)bLHiR^XR?ru|6XUHZ%Q#F%kiFtb7ONX2wX-z_5{8h!cPhz-I2d2w*;^lhkp zfugAeSl5s?3&|TZHrbZ0$W{8y;mtA!#lJj1d(7ekYrjH0Lc2QPW{bEq;;bkx1%J^3 z_u>xqta%~W(gIcOYDf({UoT5NtJFhSejsi z?FkJO1~Y6dzVF7m3}`K#;92<#G0*i7eJv}?q)Ko1Tk`F~6KnC+sA|aO{H1ES?DG)E zjbTCrDaDE)&y!YBYdF!iU;f8F&C$Hm#BTyXJELS9m2*474nIE930P}JES_-q$ns_- z)2b`C$9v`~ljqtHiRjt|3aQ!d0u#vGY=~{G1Ej*h?6qZ&l1c%Ph*Cwjnv7+Xxn6~= zNXk>Y;kE$=(CacUek-tuPoYVGR3zvJ^t!CG1iN1o4hSU%CjGZ!~k{zQGm-2pz-1+(WNu4`^-U(;l zBjTgbjsvnw)n*fL4b`=WNXALMvk{mjrneN-5p>2`sGmT(r>~ds_m(HH`P%>-gI-=VdtOn6NM7PTxYT<3)gcHA+^(CcONqdpC^MJz zT4ue5=vMSaYV@tFYm3O@jT=A%cG;|=?V^o)ya1r1y=SG&WmZ3b8>p_F#kUQ^+2IND zaEeJw#Ni+*chz6Uu4GPPF7W@uS`2T{a1(Z!f9?q2`lk<*#G3K^jQ7G`sjXcMsiGd2 zm8)&qw>CeLwdKCMy~?xkU{-RzUVNt@WgSTW>RQP2krerQbO-RmaHTmjtn~Nw0bST%TuAe5Brt7+?wVnZekJePtNx;D8|;NUen$I=x}T3 z!PNtm2&;W;(=hO$u3m4lH3pvbjp&nVHpK}ZQ$rWhRyDJn;?4%#lq0BRb$P~P%?Bt& z4g-h{EX(h?6Xp3DOrOy9%K8tN|dQYU3s}i%uPT8ozc2vF-fuu7vznt@-5-kFQp3&ao#nh2 z7ffY~r!NiMH7Tilm{hg5gNT3cAQy<`AehmAiNPIjFX790B_A!o+9V7({52>*MY5C@ zhwtJ_?BD;xUcePsO**IodWLOp+%uIl**Avo0(j2Iplr^}Q0aFelKMBheYtYb^gy&# zA5giBrGuVs0ts$2-`=qDL}Jc{t4Q8=Pcf9h>CU%!?G*L8f=EHd9_y%rq|pM1NcEVk z>`-FLR{MJZhzeKzQbMG(ON1<9Iru^_ylU*&Txsf?D(BBMRRg{@9eM^7%PrsB0GR`Y zKzem&oU=$+fkHj3vURy5RW35yvUZ`7C!XRPld!Y3dg4vMv&3C(#a3NY<)bW&(Ujs_ z`QJrqaa2^HGnX?l3PL0uGOOOFg9J}aTotO)(6yIT*Gkmvc)TP#W(o>Z^0h~Y=08x1 z-^8i_@0LUAI}@p9G3U-Q9;Farr&1fb+^NG;1((2eGV-dDhX>z`#p&2pQE{!;@^~IWX92I$BL##k zE!FD$cFv7$jAVTfV=^Ey;w-aoaA;6@oZav*sa@*g*=>p&iO&}9thx{bQa9$_uEs4`) zs2ukvk^>0COU9p!Cpptqqat@MLNrmFBA@$=sIsW&6VLVxW#Tcp1CjB-($Oy`g65=k z_{=PhzC&i{DOKoMn(&MUQ~{Y``BiGYC36bH-fJRLLGd&y;}M$D!p8J=!U^HxDuTtU z2V@`69KW9r=?8UZ{YYDPa5xot*SzYTdn-5vQnr4_Hu)a0JlukUtA!3nez<(Y!Z6XEKfmdpw8hAi94?!*{a&zM$`$gqHEllqrX*-C)V$H zYg_YTcyql~?i)5#biylte|wEmG@Rn!=C%usT*nR^JoLGF`yuyqx*G9GN(-eWJR*Lw z2AoXl1AbB&mYjVDNdDE6QCw5(5K%dNeKqL}my#|6O!wbvHuZv!i-zs-*9Bf#6^Kpt!&KIP`>=352RO zh+Y2rkpWO`miR*vSNvTBZ*WMB-<~qlk_?Ve*UnTZEr0z6Xlqm@yumul4kf7PXiMtJ zyvtQPk^yP8xGKkyvImIJJ6c`vbo$Ag#_OasnJOJXfH6@hd&CfM&t6d)d+53KW23;E z{Z3thwEA~hW+3PyLksuh4d1Jabau_VyRWv{f8^-~nNk(mLcY=>-M zq4~Az;odyYIW21B4vBp}*lR1fbEA(gHNO@KHK-OvnTa7L<~?Ptb^bdNdmt-n9x;2; zp~$S>VXRD|U;rMSc_;~MLG_>$bz6A~6f&(Y8^uS(cTZt8Ii&*WsR2DKpQ0Gx#zGLn z^PI@d(8I4TYx>lY(Ym0PriW+|@!b%}7?2vAqZr1n7<7=?9U?4nrd`M8Af-UP(C*|E zcr%c{^D)Y1$Uafe=%V{+>?Zx$9l(LS$PJ;{nmQ?r6%|4hi2j(x?)DFMaSp*25Xocu z`{E&_3jRv)mCd~!Ix}fux04(!7Pak>A;TZzI2{j`rXEpFJ=JkfzD6Eh&rUkYan@ zd;`_v7XV6-_)QbD8bF@={Nf1mC%6O8Fb{-Feaz)Mg&su^*3HJI9)fnRG%4Tp0n7(Q zn_E5}ak-C{WcP(2R{F=jZT^3_D&c`W+ou>O9e1Vo`Kx`p)x_WRIroEO1#QWM>_&Pu z)eX509hz)$KfTuNv&4tnwll&l8Oc(<4}q_)XeZ50r%XI$8OUyd9uE_HjXmh_MQ~3S zz{g!MaGDP>eIf(_!oNsF5JKGE@Besz(L(%jJi{XVaXh1~@W=5Ci}1h3@tpkAHJ2RS zR!xzncyaLoAVFS33PK)NUi;yi7r+{V3puZ4c!A5vYX`$~fW^avs;@Yg`4 z8y{GV&?DfhJ(+E>t@=GaSp~L2XdgjJBO<4yf=*}+_U|LoJmom^?efZ?*Df;mB*{f` zFZbgO&k0O~$SiSs84AqnVDK;j5VhP-P2|nm3V4M9Z!Lguj{XV05`y@1CMoc*v~2q^ zgvAFMJc_yej5n9Y!~AZd>d?DR(i9J?%^zF|1O!mo;7^a7jUaYhLPj-o9jVW?arzs7 z6Xm~tA?oIgm~wcd$9+jCkpEFb%V^};b*3jkdgr1C!B@K|p@uQPDFAfhT>utP3cqJS zN*&-Grmrb7VfQ8(h~5rcLjwzx#}!(NE|<@s_#?;(Nh6 z5(c%kY=de~Uc2va&4Ey=TqYwjlv#j+uLgN-0Vcc+_6$H^B(u~LU-&wuTQJ_nlf4;c zz|Oe%jRQi)Djgs?X~yxF8<2IiP|T{#mC~V?%m4BF<<3yhbJ+s>rJ;O)DB<~jhVfGM z#6e^9n75&F1Xm*c6DWFw1^^$C#xsI0w%o}KcR+7+P#fs$+u*vog#HD-5@vqiFy7nW zUX!-TNAW!Y&jxN_;{Z{9%4A2D#@9i-(fnt+{J{2&viy3qjNV)6rV+CB~bEj zls0FP3q1;noQg7aY!$M8ShSHmkZKc!J;O@482uOLn zE;G8D_`FG!LEAKGRzz6A)J@3G!|%y>o+8gEFb9t?V=slAET7WzV;&x2qz8|u1v0VQ zgBVs1rq&QYe6k=Sn(%KRG*n9XIztjP!(PlSo4_#>^P^r3)T_V+46r!qO+*pf11Vbz zR=DG;X*V)Q^a<5g;LE+1%P)p{(A=c;-56YjrtwbWt*pq6bPLOecrauhLM1F%BaSPI zE~~|Wv-oSFX=C9!Gqfimg}ZQqz)TT2UD@;dn}-0U!fY1r;S8m-c=T;R5vUW0*Sb3& z^<@|XEw!T@5eUG=j9O3(1mItgspf4)6H`SkLgpY7|bgvFs}CgggegmYMCs2R?}OS=f)E8XRRrEIv7NPg@lNe{e4ZwvIlR|tN*}Yk zS-l%D-j*IIzY8A5CkGA*CP+=9I|ectV*!xL5gseRp`5OJdOXa^fbi#-J?DUT?ORlD z;|?QTCj0fUKa!m^!8BzIc20laLqcc4tyJY#7r~hRu=`Gns0rvR{;84r zLdYog3(#8(RO9og)j_WwdFdf(bGW5Cu_1qD$p9jKH!FZkBU{!3Z$$rH*bt3rZcD$O zVcRw7EDZDQjAVyu+(Fm=MVE#_c z(;#3ShgOY`Rbz+|V)j^4{_1qXsa@H$PtP<0+aLxsUwtxgggvVYHqb`aA{Gxi%q!sZ ztzROKp6oJgPj$fomwqRWPmOr2_n+1iB8qMx(L?;smN||e1-8xz?{)_yf(LS7T}B-W z)^l6nxHu9lvLOA=Np!yE7?RNHcs%C=xX9?iZHCEh?Fc0aj%H20Rc1!@-4I%#?zENvGj8j*euz7qYdpO>ni zq{rREpdNuKx?tG5WRhFZ=G5eKF|$y5-9yPgfTv0jIcSmc=^PZ^1zi=S5i%-g&7iA+ zHRlrXeH!V+P|xj+jtm3*KKw$rhh`)W@Y@blWUEM$Du0d@E}dEgaKt9$Jf)f3Kz*s- zQFRK4K_o3c_jryGLVDrXT)pzb78Qx_2!w-1k^EkOY#j^_NU!RF<5fG6l^2Jd($rKG z-*)WTL=A<=F&}VhI&Z0;b`AcjFhovI7@E#T;ID!qzC8En#9_0hG}CajWT?{s3DPM3 z$m+Y0dLkvUXH(6ImC<);a6v^ny#knKDm`1FgAFZ_SFc2L;qfZb){DK9&!>c%3&@#7 zUR&Rb)N_6UJRg6WVmwp4$BLHv5fh*kwO%KI!+`h$rA5My&m8I?9Dz9U1d&x8{6K5b zq1H6e*h=4j-&M;@q{h}b`$+HISq_lbe$p8$N zoWmA8N6L|{yh6|+(2#Zs8n?1rKmGU=R%G%rs1}U2%sRKhPTq*D|91b9KPPbGcQo^jg(}<*>RNpfl&^ zBG_ehAU`eMg%(a@5I#1(3c&`TK~`?{)YIcobyVzZOllSTt7)0spXo0*n?yQhj~P-g zZo~=|n~STS9RZQngN7U(|H2kX4@ZTkU#SLG-@$D?!#IXh^8YXblWg{RJuz>kKGdNm z2phjKO*JCeu|j3-)|JDlAeo~!kQxXO8bfs8BKFG77srL}zks;-lHJ|8N8&YzBKC;u ztb~RmpaMh-QZp`uV64JRPi_@t zfbZlDY1>F$U_jYISM?5mmP3J|L8?E^sPBc*)RsI5fraB>jIRk{x#oY{1nR=9!+&Qs zL%DVwxf^=$vd44MYOiN$4N>Y zD2DJJQMn8889C`6BTLqgQRpq~y9)`ZF%24WG+G_3a*EY^Hj#q(YYR2fRjB1M6`tQ0 zfm73O0nL%wX$Y$GkC^cGA9N{SB-fSX2kO7$@82#M+-`bgH-PIvePsu*L~fx2;Y=#= z@1?p7vkvUPXulwbF=sRrc-_>Ojlp&kgme!S0qrUyd>MtO@~@TT80R69-TEbj&?@uY za)`sO<3PT?lVu>wT3AKfGl@H#vXLu8SEYd$nWl<8@~okI*B_a0euyoPx3PC>ngkY( zL!8($kAwJfYfN(;$A#Zi661SBtl<%y_-C*oC$04Ia6s2U3#UN=4NmzQ7e{lU|b# z&wHyB`?G0rbL`=Amw|XzZo$bPbHf2Vx32g^Jvf3}0O1e&VgM3+61SQdN#=ej`RYcb zyln1>L+l-fUfqu?(||mfKqU?YU7;*{8}u|zw>%tSszrOu-kxv&0{g>YWe2tSko@R! ze7lA0u{mtY5zzO?>Xu51Z?j!NT>*`qU|n;o1=^k&Dakz-kTc2833Y(qTl#f`LW}gm z(oDZ_)=Egqm%5Q)aVD^>Y5j6)2JFEE>sUC>tyfk9{vqAbk}NVUwRBC>h=%&_&~_0> zt**&3p#vD!I6c}~voD;* zlBsPF_f?%|!t-#*$EW@`I{~1j5?BZ#Z~6(as`-thmQtz4bW&Ol-2#a`{Yp!Ba@bnO zB6S^PP@fyM4-p(D{hlSzKj=VZI~T35B$=4l2Xsp^sCd*H9C!jX9?0HE$WH9%IquVv7z=N4%DWe zP1N>jUJWXF(Uo-yJ#dT+LvCo?DSs=&9!rJnQh}WpVKf1f#*C-B3ryp;hbX;1?q|Tt z3_T}qErC3(X}7%#x5a-2oV$lWu+s^bH*o5}YMDknOaK$BJ;2OJdCC)l=fNryfx1cs zVw>l|8e72RhG*S~0(gGMr$nk#f?(-sOoI(X51!uu+v@F-?+(ZY19F@Y0)2%oo?tvt z|C=>D5_19qb^3RqLC9I8ZJ?Ro@*9U1h19F!tI(vL#PZ-KlIFf|Z{U6V(C2|!@&NKI z5W;Xy%IG6XW+r%;2l?>}DN{vo|1YA0Y#GVH93?}2vH9{?jOCd8W?H*HW;FN;&NFoX z(TiryTxH*&6u?(2?P&`U_|t&;^BdBFFaLaD*&$zeDipZ4>j&R)=cv$Ab~1#H0tP?0jHoRovE zO^jNzbYcwnNW(qQ5C~J2p!Pht2(jK$TZ1JxWRxuc7!fW%2vnt(7qm!*FxD@Cv>So7 zl&N0;i{$oK-Ub~ZGgX67;he*a&`*ls*VZPl8dU?6DlVW`E>KBeP5<+-~#XqE@f z=K|`Gp}@tWZRUzPr}oof-v9;~fhLeA0Jbhi?|{K$7#skN`W7A*l^jYJpfAo`I!eGM z%I`Xo#Rb8M*tlXu8k3??Xegfk<=W`?5BuTBDypa6d};ce<8|e$+yL&fjH?~tS-EAH zJ}(f%9h|dOmczjyZEAy3f%@@O&D78((bg4Yl`QylDtD7Bs4|dS zt7zZas4qPS9cr?zLygL)`}y6n#v$62`&$;V5x(@9{xt~kir!nwa1hPZu0aO%`V)6< z&>T9;v&@rI1RX~RkDxk}-Ul_R%|mf;%L8Zq&NG)gqu?YRqPoLh<%B5+aWo4}W|Oi+ zIc}*u9s*ZSvkyIoCK?-I#uB2E`u!T|3pDhET1;_Lu0yERXoHu)Nk=xg zLQ9&|yWp)ugAL{Z{M16aK<-0c;GL}vJxKknOL}ghKz@tmAtD+mJipm}pqMWo+~!7w zH0pgQBxT5qKc`dj6!~=o;Mcz(z@LDw7R1-{Wh|bWu0}T3dAyg(1mXztpl3(P;H(Q0 z-q%Sn*ifMY;v1BfsNObfOv9bRAGaE08T6vMk--IRsaKxvZjFf}KNVNXvlUx#IGCXL zV*uf@09<~ZYr-ibaT^hsn3RzX*pGEkBSkEWGsd^a`CNiXE$>W@tp3oX@HwnGQH_I5 z3&Ls^c^%=Hq*`65cIbCPKNvmjR^MIushjc2RQ&2p>Vm6a-mN>tmjW^;s~i5nn+w0&2k0sWYgD-^Jdw zaeF8wzor*DXhx8k2!dPHRFRtF7A&zA=+}toef_^62Qs{WeU<4YM7R`@HSrn3lLx*9 z9^=GxZ*c%3VNlq(3&UX=dl7x~3mA{e6-xXApP$()p@;%MLSo0<*ac5=APOHyB|%?u zN&mSzB1;3bQBot+{XtN3Wj4al4x-{b3r1_gli{C{ zDB3cWE44(>NjWuCfNVh ztbypJp-waV{6g8*V;_+@7bJXrqcSKPmOE+jkNl4gT>z$YjTdpqv;h3*|F^shtaQeC zQ5Z9ch`5Oyad_o2s7`3M z!Hg}PESPqL9I@>>_=3y3>@)$m1bzhhUejm;k(S`gOoX?j6t>xg+N>&JXwymIL*{d> zw%JQMSzl~<(X|+U>bMEU0a%J-=tqfuIx+XV$T~?aHVHH!Ih07itPPzfqG%20P(`j+ zUZ8}n%Ye{BgI>&mw(@YHNa#(FBE1Esfdk?j=T^evw`%aBi?@`-o*&|0#F@imv*vnG zfsa6I1!TRU9&U+ie2@(b6Qn{1T3+xb>u>%A{r@_c?KD}V?uILYKrCs3$pF6Sj}S0t z!n5PR5h3cC7rG&si(ys^2dV)y&0?L5!Fw98=de&3fYdocTfHXf*Md4^%==1m7>V1< zQGeI!pcgZmcy+~>r1sa>WG}uJyx&7?!`vFM*m5hLWlWeM(BKlMm-hT2S>)DmMwzb= zJRUJooi6z17w@vjxQUp!nHUnv{X|N_+NHM{0lU5+BAdi3X`CQV0^30j{F@hxX*Br{whW9SMXDIiSmyiT>#A%dk;R0tBudkefaq7 z^fl0AE^rHj29pm|*TXk=#vX#x=MnH#j{u4HUnZ!4nAqQztq3#D*@x%3!KRhn zs1H-jK3!1O9fMZ=+*yDDm1TtxO{-LOTD=EZ{R1cy$AMXu9Kt*HG5>-~{k`&aMrsA2@f17guY3p&>C21omrBie43^;I zLtni;ZTkU~v>|u2MoJcFMv@)4W5}R%B9geAr9U7H-+1T55|$QQi^gO9NIf<0qK+Q0 zuB?Uru0eS#*~MLF2m~rEYyIVkjt@}pF`$n7FJQ)lX7K~IeCRD3hIug;L;u%#7>7Ft ziogSC%X_#y*+r`}0~QXaqu(;rbD}OHc7K#mPBnZ5$HleTfyw|szFZjBa~=%v`OwvR zc^4i-6b^%{e?CBCs&rurOYK#Lc^8e!d&>?haAOlrsPO~`qMf=snVBAk*%BY_$a;hv z7Rc;}ngQVN%hw7+*2*)$0K&80uO?Gnjvn7iD9%T3!u&rYXdLiML$_@Sn%6;6qWpbVyiGKKrKtXX&pUH zf=bPxeC?oe#F8)<{CJWPkHM7`Xt*?$e%%3oLoA-X#$dk=DpPMWBCGp4U6yxe#0XCf#2vn{6B%;(J7D{k3Rx~)NOUM6@VqpcTXH3A(sxK}zCYv_Vuf84gxC!LAq{~=f)ey&dq%_4 z$asIW+5p+6af5?$+;38@=6(W+PkY#29;O*tbD$6IxOyc}gi}5HZzS<@rV@-FN=$qF z2xcv3A%K?W5LiaYktJwtc6Vpi4s>Vm-3y&z{0emM>^%t@H2v$z*e%FY(fx09%AIY{ zn0YzfpJ3%9*YOA5*EDt&tQP9#I_TaIC5Y@1Dr)^!)RG)=yo=+f$QkNj7W{Z$5*tAF^SRVdB z-kO`;^fuG=c+FBtfA30gAt=p5Q#~8CAf^|ZyzwqL1@Y~rd>C5u5DhhX$|zj&zHgst zChkaWLK~RlUTMX?)y3UHqwR*kzeTR&!z6m|Ow046iLN|m&-F$FbxmQKbK2o*d@#pm z@hUXYUxf+xs9F3&r?Hi|C%RT|f2E?UD=4E8Q7arQaYRS_`Rk^wTBZM zzQT}wX5?=npKn@&u7`hM1Rf=_XqyA{>s&^jQPN880(l>LH7vUK4#70V;7_KFrpY?M zrThB4^&wCU-kix-R%(jkzxeP%oa@h*XXc7o&7m*zH4L*tE}hW1UNWAF!(~pB>PDNv zoBdI~r2q9s2qc@gY(|OwS4mnw*aocaSsFYe7r+$rHyCRiY)(Fy1H?lmOgUeE2l_Lp zqpLtfPBH%Q^PVmqvp@k+Fb-0{KgeQDT#SdDMBQq8RA593G@J~fv6e!+FnKoP%Zdb+ z>H{qrI97+F2P@#G*Uezey^4)I=Z;(!51F@rU5}o&Cm{0Ote?BPcU3r zWrO2m;2y}Uae^Dih(0l34utaueq^){g`6fHfCY_>B?KUi-$X}N=jOdCAlT=?c;N@* z#vXzd)K9>s_W{^sdH6sM`P`>lbW0w6mP+9?F&WK+(Z)#ju>??&&;YVeVwm2I<;f4} z@t*X^8=WE#EvOXGOQR5U2YfY@U@Ee*99sZUKyIZJOiO3R96*C0(}~i&&o(e9$p~#H zGWn=rftciZmd_SU`=3@#AgEAcJJ6v4b7JKD>tUDI@UGxd6n;M|VT|!mknoIj)ud?w zba(!E$qORMO_3RKPmSR(Fe>N^*z{vc(YVs{Fwi!IRH>pxBUkt3Zhs$CPhlo!^URc@ z>YqJ?v+f6$R@T*T!?gj|pr8mNl?60R3ZMUT!@~;=8GIpVZ(LaYI`3}9{3dffeyuZv zeuo=n86%(W@zRW;504(9Qe_L=*N4C@W7Fwma(xK7HnzZ`cPJ1#e+0asKfwqFRrHx} zqA_#q*RI$P0<`w}*a523dkAy%`Y^54IJU*AJ>v+BoTEdE&KK}4#FSnJ6U-b8Ydr^_ zF2EooaXNZsy6+MA%rC{jM?s7ZJiF|yi~P)Ci(%uvqfg%XBhS{>LS!|UlaeXy?ji8T z-&y++rs&@kFtz~39rFvo$tZO?&owzVQ`o#4D$d- zD>?GRNPhr(in6sf`32<=(GQ2w9I~s}i1F9Pb17cCJD==p zC+I<&GfG^aukv4&sAx_-63@U(MZ@WutyeBE>A-svKP?drENUtH3?kMCuunf1dF21_ zCaM3bv%7-G(wA#coA4^3&&@ENw4UlI2; z(IAQtcO`D)I;{w$X~_k^`prT-RjFc%>+xXF#NWuH}kW5aX50ObJa+CpDpvrX@rsc_E0xRH7 zC5qG-)}VoJ$QF}wz!M%|4j-vB1Op#Q!IgE6=E6rd=Nrs?=1PK)fiIHqFEo!Lzv>UM zC$`@PU#to2!2Fu?BNcRie^gseOz2h?4ZG{nN@`hi=eY13Z7~?R9>SSnAK`uV>=Qm@ zP#>Ty5W1?&d-td>y#=EN`Oli~^6s~5W({TbJ*pr*!s{N=gv^Pkg$6l|;Ze$4VrX2Y zjNL8ORF4zUr_{e7s}>r<7CO6G7pKG9?g+Ej9-@)1nGaOe(Fbq5hcT6*yctJo&5YcC z)*DKunVmyhmBe*=IWcueu$`HUEh5ZK@$YfK_O^NK74$TvMBO#ZxvCqkAsljDLGDoRFwaXNH8RpZozs zyUD4iVJ6o<5Gl`L53a1yY*N|b2kq1Mrb_)O#?aj?e%36U(o$Tee?nHpnCRSgJEaaw2eo7 z0{!Ue`OHJqw0mN3RyRqlYTn9_$Nhj|mwKW8=U-yp)Et)MZg~zSN>RVg9b2czXnvU5 zL%!hTLO2C(Lm;tpb_f;F*8?`v$2r}Gn4?mHPh#E+N=3RQ=;Jeq-b&Rfl=lb?%>pP& z1TO0M7<|0aIbc$l5@B{!BIvO&%K7;@GN9K;DMgo*G@+@bzzOCM$JxO|e@I2UtBhh0 zw=wORVpSYsx05qa8ba+nQ8dE!W2bE0<~5DKBtg)YaSA~)v&mxJ}IcTj;kk;J~STJwtMP zcs&Zn72Ji9&qdr`Fj(>t+S^Dh_e(>gauHpk)%OKV(Kp5Cg=!W0d1DR_evi+BkBDRI z5JmP{<3%(maSk=sjNF5Fxt1!DWm!YYa$4%?SpiWJI^&Q;^Sh@@N;6O|+Zz{LsAj=U zVCrhq>fg%1C6LJnbnv53BQtKSn>>-#8GeSzt>k1kz@B(_o@i)Tb*D9XZ3ZJtj~@_J zc2_XX`WvADwg?5|U+n5vo^+ifd13taRG`0@1>^O1V|wKAfO_(~FM!*U9C;)YEqdZU zxDLhxBg8oc%Z=u{eJZ*j=2aiaK#L~rp3ziohfftK{%WP6q%S8;naP>AMD7!?Z(i z4iBMTs!oMnpf)L>ci^1*KP=80GeD&-ya8Zo1jk~1@gNwO3ryUnepPWW&hbDCoE`L( z{`3-qwwVvm%1H~(>iB|1mnlPCwW)3|Ti_>wK>WEUFP$K+o}QqffUv`sEFL+CZqG?3IFKS8}f!3BWvzN)4qLzKBMJkFT}*q#e$km4sL^2^1N>^0+jdyz}0vX^+ndE)i(d&6%4(# z{Dgu*fGV2l0J$V1%mOotwkeT$FG%bGJIM&_u?Qh0Vl+C=YM(o!NPdN?l0AuTB=1hDfB4k|-JwO@!=oU6=d${f@o&+y8#CkLP~zJar#;xvuZ`^I7X$=Q`K9PJsdMb(&@0QBPYUK0H>0j^_x$?JGLP5i1(@r!5{)}`4GPkS zFpRM8qTs97dO*>EwJGuuwVhc6HhZY@mChin|pO!q3eJ2x#z^kkKlN zu(_9>E~Iq&L{uunNUE`z?-Xf&A6CBz!~l(L;wz}178%84VzOypqF`oC+4AzMfh%R+ zt8SK9o6vb%Dey|}nq#SkiE04=QpL?bgfyy+mtI*!dQ{G-D+iftmSlI^axyhlY(}pC zDcL|Kuj))_uvt8W?Pjs}T)sYz(DLKp@6FYhOnjRnVv{NpGsR6Dl5hdiwGG$SkX3wd+cS!HIc(ALkFaFz2zd<`1z{fk#hFG} zN1ruzAm|m9A%O(_#{RyID2k*w1q=SWjkk6`{6-_?n4eQmTUy(>>Gj};no_cTBbECi zfBw>4IjK5auX@4fcVIZAdR6p}Z66XMOBS@qEWKfxv#{Hn`RI(+I>t60W>yqW6w-Lq zMaj2MGEg)X(>Ka(7&Flg>PLYU^JmnhIXgx37UhWBb(wJTHFUOsiE+aMHS->88)Wp^ zWM?p7@auw%SeGMa>4mRVR?jL3eoVTmxaO-ga%Z7(c-k%aIG%oe0IsRhVMD+Ek`*9x z@z3Ekl(&}K*C&rA*JGe!o6{Jr9C?v-p)N`6{aUgEJ@cI$IhVuIcus`GcK$HafK=f8 z6vgtHf5?rl!b`!E|J1H4{1IOOt)Hm&V?bsGMhdvFJ;lC4W_8X&9WllXi5-#!h?`oN z;8Jvv4Rn2fyPN!cE4nvv8J91(Be|pY^lv?`XHH+&)@tJz#+t6|yyZK#-xJ^4mA^d!U8Jo(&YjSLy!Q)5WO~E02+W`kc*OxM!Q;SjA zcEI78i&Jn}TgJ^-sP$_2rd3_J?RHgWUO}}$?CFlP7PcANjD9!|wcu$RbEv+7FR9uoAdkO^@i2q20tNz3xaapKI)P<^YA#$orpTsTeIR_Q7Rv3P?o~6 zbzfWeLbm{B=T-Hv4ousn_4J2U35+H`eTGM9Sk=!qK0YmNniiZ>CvA@rLKK~ckISpcw_;>Pc^CgxCB}#IdF2NU zvSu8@Qk9_UZSyKuLMxe;s{QQJniX{slX7TSlf4l$-fKEws;MvYBbsl+5N07tX}}}x z^Omgxe}nlqGh#yT6$8uJy?KeL$r9ZBNdE&2Rp;$#-ePwArJDsU4zADX-<#Ewi>f*R z^K<@q_N%;RR(2p_&7`t(+iS>7@lQhB=a@IlU$JdI4Co-hDOQ#-2V{YsjEe;dYa&+I zDUbAkw#!J2k~N1qGI!oHOkyb){)JjHDW5|pYYw7sMoL%1RXiG7%bR-=a!u-=?C?lU zCQc-mrju3#YBA~;>@e^|1PZNP2j6?mU5xybG&>U=gav~B)rwHEF8Z;}tP-uD%x~m^ zNsET7^3S|lwPUEt7HFq~9Ha|xpzv7qrSb!8_C?9)gD8tLHFfaUut1oF;m1Y~wTvpyv{Fu%F^iV2QNMlMjv3h02*IGtN0x~Qr+ z>%<8QyUaeLa||}gC=0cR4}mU(uidqOzHtBa?}ILl#N5QnnQe1AdR*NXtwT0TR7Qf%WdD!yp)r0dcHSl~x;2x%8Xa4eiz z?-Y_3A@K~1+3mU!4A`#NG3WH8a6F;C7K?ZMZoU}pKFa*c(GvqM8vFw4GZ0t`n}0aX z9k#jFOAF6lj8wg-Qu_ncqiOdAOIRyDVfg!Z2BmFCNsatNgic{QEjH*&AoXR^>MT2%D-ZqT(V(^aU~D zjPK-VvCUa_TG%oyO`sWCz63!nnS?p>^}efe1g=qB^69=hJmbzZ-d+>BGs~3c5@=T= z{+JI#%(NjrVVveCBX@YHwhJZDl3xNpnwR{6)R&X^m+QY9fx@y5^zH_Em#$AHvlV;F zQJIO-Kv|l^v8yxR(mYQoiEmvKKwmh_ZEw{~3Pa&BrXrtsxz?VqGQwDWw4)^Fnurm(GT; zQtAAC4dE(aErFj7JUP9S3tGzFy#Q;bSSMRp+_34p>Yy#h;VzTiW~e1Ayaw(keks_U z?`SgUeF;mN(?hBcO`H|07GHI0l(T6R&}P;ZhT>QrF$CX#ztbGTR`lWKL#AS!eqTo6v6cOQk2@0+wke z+00+~R@CA2NR6?!)U8sVn~dzmf%E&23K`$Y;+!M|BrY)8N+Vxq8g1rFOZ4A7(ogKNU)4q_ES=b~>>*AHo9RG7ot zs>suo)nmbgwLevsgxV-5Ic(>0DDwuI+Agf6IiTKxn`^YgVP0j$r6Wkf`j=)YJZ%EF z?Yb}a%&TZTcTMOx{9GhEvXWrWU!?|&!;J~*gD*4YnXESpXQn*AhJUG)5>kGNjR0Cxi36*TgA^g& z_=$shPSjuI=IsuR;#e*~i;9D=jzS=7v0ua%w+;>LS|FT)`=FNfwXRvK+TDGQ~0C zVff7t6jE%#oURt8fA#WyR<>&VDl=ujq{q(gxpki(q*iJgt-{Oh`i|M9LNI`mH)+0-$M_i{G-tCGSNs^>Fn3H!T4!*~30QBLeeNGY ztT^|5FlSdCE%o?+i)(%8q0L0(d8ZQ>n%GD-+-XNQIFxVZ%9*plL2DAf19rRWt33q% z@4I4k7h0gIg#OOg1C4puZ{d#*uR$jSPY6u2JnrLuLjp0Vn?gtGiCsb2Lw% z$Z-07Fe^LPsUg)_|7QxhcvryOve*Bpp%k+bW_kgOKaR5EM9}!^|yOHAPAI;i{j$CElpkvP!?K zs6KQD-W%*rWk#FfkD-O;Lhdrr?s7ZEHS%sDfK*`7`T{jB*Hk)3X70f{+ zHJ&0omf%~QSJ-n9OEm(BU;Xm^+Pks2w?NChi8;Qdaj5Q!m)O+udTp+#vgO9g1NXs) z-`2FgCX`KHLW(}mItK?k#9;5X(!zcWSRd=qoT6jF=IPPx6y0<>d|7Sx{9FcX@Vq1>6m@cb`lz^c% zp)m}`47=_9{UNI1sqe?ck|YMszdwx8CUKho&W7WN-3?>Dq%eiEipWaY&;Tqt&KoDc zf5tUM0us$d8YN@NoKnv$_ia{;Z=K|Z<9fmLgG5w=@%5o3fF}mp9y{b`zi2*Q<|ve-s4b>! zlI8Lo-4)yBixHR8(ZpJ;Y$aCg9ncH5J zm2Sf@KL7|Cxd|^OG?F(?OpG`iTch~mhB?s_hZcnLKyoNyH|J|YCO-(Th>v-R=x+t# zT3v1aVd`uL_PWM_MPji13!K@~ONcJ0hwbb^Ji7qcok&s2C}(=G4H2hPCj0^!Um|_$e00`Y6gP z2yqeP7%3xW*918F4b`?RIUP3LVfB=qswRreWRCqPX0E^bgpU0-c8Neakls5!deb&# znsKv+!a?S{GV4d&(P`O#iS;95`p~YMaqZ%v&16&rVs=&uI*X;4jV}cX(FDs+yK*!U zS4;6g=luEAD@yOV{@RwLi+A48d&Ba=K=?HTfyf9V4MImaOp5|B!M?WTKyCcrXx5K3 z+Vz)ZkIZIbfwj4j3!HJ6IjM2}`88|8tGU(W)>oF$mGwv1oOCC?+r;nxKT+VYe%5~_ zPxKuA`@r!K{yTAihw%Tqi32*`_~-x332)Y?B_gA+vfu_CwZ%?_72%}U*GBGT>bBSt zTnO|`AEAJmL4j^T{3ea8S2jR68eNTTY5*HV@h|&x&UR)G5q0O6# zr7>KncQf<$-(i%85X~jm zNz?sFsciO-Mkq}Mvlfs^ZyVUE zs)8Pf1p|_zNNNM#k&k1)9I`Jy$ztZ?$Jf`j3-uizY1cIe$Hs@@?`=1oLl&G9Y7km; z)O}8twC8xV4%fvE_}p$V#nhsG(}#|udu*sFCcE>d{vBFV8AuzaXk(~FI1|sZ-BF%M z=tkj$qnAS&XBZ+Nw<;mJ~QOs`7ynjC7`i5+*1fruPn7(-z25 z+WYeh)a#-B+p|7`tvb-<8@?a}E6{_86*GQKTeM5a_2)1S2ID*9N;rItR{{r1upgu~ zn6zkp^OZ5?A1oS&7D`n(?+L1I<)E_I|f?{Hn ztrC@WDQx?zy~j}naDrVtdJi~(w1j%ae_?SJ4VefP*M!-}-Le+44sP1NQu*pC9KKSF ztw#+2B?qCd?%HW%N&>W%j?r!pFQkJrq4o@kRL>m`kC7%VNLTwHo^w#z(T!Q}U7-_M zJR&~}2f9X_xS)csEJ$)kXQk|Y7P`s40yZn6B!pi!asU*G`t^o-YVBYDR zLMId{BTi%IR0xpFFt?a^(CgCYYOz=_W>i#b3NE6r;##zoZI3bEV6Lrh!yW28N<^&A zHT4LBt5pC>!mMUui{98i;eGWGgs_$gZAJ8lkXNdEKbqd)mb=$($tvV|Rte7jyuTZ0 zhu!|fXdPV#$j{EtFJ0Y;f{>$yHTv$v{V%S&Shif}5-Q)t4;dxkr{dgyBq=-ZqB0&{ z0=+tS^U)C5UKhvwa{0B*VTZlY!Q*mN_?BPCmx`|6Yrkj1R$(*h+TNy&|15=TsH?0=A>5d)dhy*3~@c zWCc7G&O5Ehfc}J3OLGQ;o7Aqt+m5M$#Kqum-J+ahNt@5;Pz`#a2sOw!RA!`;B{Tru zXOW2tqxl^uU3NiB_pPU2AL|GZj7-+yN+B7Gu67s|gzSnWWy>uuX2ke(fg zC%3*zF%RY=f&W~C#~4J53gMla>DYCeM#bWvMw|$wE;IWc+wYh+`!Iba{``b zo|=sP#r}9KE6|v{Uv{{B&todBr{J1FPlymjS~JZWTEoiJnSsMMkdZ$ls&dmvBPAIF zMT;vN9{P?ia^Ln%b>^zBvx{tV4}GZ4M*L5EUxtyWn5X2(p^D%WIbiC&P(F*NRLZL{ zGXs`WOev|!ruQq)Oo|iQaJuktuLudZF5X3lJqTCper|#&8G@0x#ddYzL0Fz98SgmV zWSI(qvOftKQ5IZ_G-nkx=HdV8pJ{-L#D1wr8q)M?uL`v!GzAaTR;ra ziaOQHrtfS?jE(mD!N1*9Yb@1%yjesqR&I&0ZYP8!vtUGSsJU_=-sBEB{E_ae>Kmw< zMNJkAqsx#ucTf}aURR{vpzI}PoMijADef0-faNDd9aMS3VO5j-IF|Be%6FaSUz~f| zWbxoA$aBM!^I9<8B}pRavOC3KU#lJ>7t7_GEJr^%R$K|yzWnC4kI=@>%h>sBba4<| zrzLzxVWP-w9)bo*cLe$#YEI#d5788YnH0H<^Ta2qvf4hE`Ag}jlO3US(>oQ(dz7R) zC8**`$l_FBnS~HM_;xuJ;0W1rt&KMRu+aS8!X2NUWd1|jSD1a@yZNYh7p?a<9kYSp zAO%56IPMGH+e>F`5s~o)|MS6GF9+XbbU@$wVumg1YduH`l>KqMC1XrTUA$<961>FI z1}h9y-b5Qup&f#<_gN~6Z0!jlfgc|POLFL}N(tY>c_SbBiVxI#_m`*X0;-nZA`~8c zv2`QAxeJ2da3@)Qnv@6W$M6l3O*_4z1v?e&&n?N?3KK$Vv}AqZx7deVV68X%)=sX~ zT@L7hH;a|+=fAa)tG;Z(v=xj!WP+_5{t1zOi_C3OJm)5`j$^_^lZ9>5bI4*M9fhAG zW0c@8J#@1IKZ2)J+-q*H%_E!bPMhsQ0lDlh&U<3kANRDwZM2+-FUsX1Dz7C(0LwUXlKnat;wfMBvY4l)TZ$93HRuJYAG? zoh_#c-;F|^Oc@KT>b7(I^0E(fa%Nwuvif=mIw3}fnAs@_2s7`9Eh9KLfD!3f- z(mNOp;Y91=i9;efnjd$*k`{T1zW;hs;VG^~dmtOM&Cp}nJ-CS>+cXkyQm?^|FD~6VtNq!!54Q@KS~wM zmKMIzV0S-EAcw8P(E5!LdTELgjPtNXeL3uEj&QX}t;-kui8U5I2B>}BIn^s>Lq@7; zOBcGPGco$HX>H|lL)ey=e#F0cP$PZ-OyQL~EEIf)FX4!#3-iFIFJu_Khw$^+co8VD z4|!IIpUfP022*=7*dJY3KMF7K?g+}L!|PAzzaItRw=Z!w!bv^oTHE7*E*)Ur+w4bn z+_IWmZC)Ec{@dlcq+YClhO|`zkx8H!PZ=KN8(>dgFbW6w$^%h@?#5^EaJg{aH<%EHaS z=j>JVjyi}&$0)!vQ{gUTSnhSOC#MP4tqZK`8Bfb{yf}i!U9fqJC@s?+iwy^J219*qA3~`{#POE8#?k#)$wvrrquYSZuXr0e-I-zs)r4NvlFdb{1=Ewv$%_r+sVv81e&Y3(F=14mV`ql;VGfW~^ z4~UgLdIAI3QnU#tH>vWfxq@Qz}AYmL81H z9=aq-LRt0;KthMwy8?9I{~$4=DEA2SX|NUi>riaKr^TJqdF&GMe5~UbaJ4e6;$mlX zO74syHdtZvpnZumv_bbr=yG*~<_=AF=kQj8mg*Om&f_@ZR;x$VGZ zJXu^zsD0(hSvep>j5_}`w!lfVw?0jwLL$LUD;fMD1kyfT6wj3Es@lOX5vWS*r)`rI ze(?Oh56qZ0N6TWdiyPr8&4pA|@^@ep2p7_U{y&RyK5MN`!m@7znE>NFPb-@%r*R|} zcQ3f~8%I?#B{J+2vf3dl+DE>~k2mwGaV)7Fe|&C|#mJNL^`beqT)A9;G1XVy#W2;D zzC=%_mXm9kUr(dO__fi6TkZ&deoLDlotRuoGK2A9YKW6WT_)dv?NRIj=o~u`8n#rR zbThtgjboj0X=vm+yhX1VHRYpon78dU>9@^O$B#)ehicfeTS6f+0y}zj+iO;E&CZ`N z?eSYGolf>;wng~-6F`+M=HE&GjC-hKUED7KVFi)&XZ$-*C~wBj-}_ic$*=m|EhXkJ zjmj|{;@kms^-Sn-YE^xKs;OBy19`x3?W^nC7h_3E@=0@c)>pk0KWxMLRSch&2)cLd zwEcoPzvpl*Q4=K@)ix!_K_z9UdB0~KD037+E5(qOq1mahnD0HAk`u?lqzy~oqeew1 z3wKsVYzfo{Hi(_Fk|v=ZFJ(&E*^=i^B$M>_xkm>P?S`fEtAzn6&C|^qlT?|1#xJ90;;oR{0Qll0JwqTx zHGK$mF1!Lpq`sMCN*It;5D2;esDe!nN3s6u!3o2MC9T#6-xPYlNkL;8s4y;|1bt26 zoTEBo6%pd%R2&W*FSjFM(MR96h=^L~`9^)yvGS9crUp$~Cu}$Pw*EL`ta%F`%xEnW zdnR90LY-UR4RogZicO=rHPendX6!b6Tzf&-*+reaq3~h=yT2D}T@qR8=#P0|K8}NB zzDJs^r_Y@;$?rxhM4_DCC{J9kW6O->Mut=v^?Zkf67CRtGILPpEQe-kR72-& z_Q8%4MQ8aP)xk|ljCY-oCUGKCFLNCh`b$eb6;}i82KeaIa31X9CZTgW^a&SQr?O=i zTtMIW|K?YbhI%|;ZKcYZN)^GQ<_p-eB~N#pZtl2cpMQp$*B9<8AiZ+{J8$;U3E@|U z)%13IA7WFmqmq9nc883H2$8$EC#JGWunvAUG)CL)hp}dJ*;jlrChj~bLN*pk>jJgG zZ=K`vdVjc6O*`}8S77msgUEK#2U3%bz(Hbb?qm#Wh0s=f=!o7-1J3jF_1JhyAI8RB9w-MB4O?4ZM0*<=+JwO2O`i;f}B(88N_y zrw-n1ei0FF|v4Q#UR&(MC-Qg1fSPwDst5*y4N$65hEfHGcb`R>w5~#kSDPdH!u{(p<&ZsXUY7t|dt7+%ka7x(8mp3g%L5%I{SzTt0BekmcJ}MGj{_vCC z3w`J=TnL}aHorG%I2>JsZ#Y8&BX633suIcRMw-=pHVTJubdH*P&unzD&Fznpe-dai zQ2>{FM5vybJ8cqM1K+7RUe^96`6aQy{9NN7G#6@SNpww}^S&GWk(2uyA%7uQo^I2% zfw51($6nCgx|=RTVs1Cn!Is0h2&^`ijJeD}UFwtKHL<se?qIvf|XuA+!`J#VuBF zui1m+UWU#D^f{-R4VK9H{GH4u^S=8bseq_bsS4Fn9P^R+>vZ)Wa({`Q#Y8jG`)GO_ z3Zp&eAt$RC#?fFW;mY6Tmv&6oX4~^cK>gzlivmSbyo|T2md(~$M&d@&_;qzh7x{MP zHT=z*^INd}{U`us5ZDUA_?_T->S@Mg$~LQYlgq~{jmnF>z7rVZsLcc$Lb|JM!>MwW z`5?s@-KvH)+HJd6-_m}T!#17mY~axC&BsqXfx%N`(ssoba6pj<_s1=>yy#BPd@(C3 zO``qtMN8Gp_b_Q~8BG+eU?@=)C*mTrNpEaQw50#{9atJb!{*JPOcI%Ov5fZUn`ovn zkueu@v_APH5xEqrI^g-k0WYlU--&hAD43>X2)Pu>fW`heH>(=)FOAl-qU{`mq_t~k z0D@`EWLfwkAAUznQzeAasHEwGfkc)=Yas=O)aCM*otOc10wZJ%E}4r;xWDyyB(_%C zRQhjQ^A(qZ8{P`CO1IGL(7pDEh{Fu0_hqMb&mP7x47f^CWic#t=zwMyqq{G&vX8yT zQ0^>f2lV;^ijFP(TO`!&td9$+iOMx{B>9~;F;^T8>)4Dulv0Mib3WGXb;3m6fLDbKU@Ngq~|6LU5(8bO27j?O} zfSs4m9co>F>fikM@=D&xkV#5GcOHmYaKZR_>MB+cf^=lvuA{OnBl^zL-4BZD$9Ve_ zhx+kqah1Uw2J|JWeuWN%Myfx&Jxm{st$Ejk*@VVs#?MoxQ&aW?{ZXatdd*QdM^Q6t z1CM&6AlJS!m4!Qv^Us6@7!GQR(1sMHesqNNG)1W1Y`$2GuAHuYXUtBkB}!{{WRQxy z6wlaFQgf!m+x=7f?`9mj#Z1bNJ{nHg6IJgi58)?$w%yIcbb2*UoKby?gf7D~D6*zcJ4<^IkAAo|U zfucYvn62?%0zT4+ovvgU%>pcKL5rx=!&sKnB;H*{0-tEZEBE+mV#~;TO7al&SBRM5+5?pGE zf@SrIndQuvkDtCAJ5Lzv)2NAX?WZVusb77VNDHNR!Ce+voAEDicSkK}VFe{G52J{= zFH!l&8!u=+kMcMOC6+*j((E7@didA2P@#u%elBwib?z^W-SjL-mLOSz0P{%dTv@wnv=1j{rGnS!!IgM&C9WT zq}WI@+%(`a;K08ZB%N!b#2$|*9%s9qDfhc_OrC z<`~DzGA3$_NyZzr<)j7poPv|ZRxiHr0}R+t-!)%Gl7@R%9*b)@b~)@#G?)}JSTQGZ@k&9R@KW8yQx5MISyQ}ON; zZQle|^2wUt4}KTRb2=1tNy?7qX>@}T z*Vl4;aV^?J(yG+qi@XzYP|sR0Jmd--NIcfE0#W+XiRY}e3+L$O#UGXm9qO?#4~fn5 z)(^jR{)Z(`UGO+&Ti4`o;Ax-@_qWehfX_PgEYZC|*KCu-FP@-f57vP;`uqb&@Z(GJ zVxzURpAZxs6;i@JYwmdNarxW6Rhl~nyv;&j?D0XZy{r>g+Fbt$lY95Os?7>cemZn{ z3k-!7QtlTOt#)pIP@L8aG3^rz{=es+t~u28^cQ z8gg%dE6s$iE>9asndL3b=}@-e$Y;YT;S2Ky;3L0Cur+x3dTsmC-!4Df?>`T??6@=0 zbax2oWx;^Ew6?bOjPDyQ z(6^2jx3BG>)nv6q=%DpBQrFNDo4_1O{Mip%uLQ(fJUEXs$>kpp{dB7w zhPLkO-=J?*ywqZQhUyF4_Vw4T4^$$*0C&s@q#>G`+&q8^@XwQtYa;`c@Gzn&3g3PecfI}^t=X#b7xX1GAB3$MVeZ27(L(tvx``OSy=k0?m&4ifD1TVE& zpy^AT{O(H$v*+sRYqS?1I}-MKqx~NA)wE-JgSdoK%`2=)zw!tBWG|3kP}`KB&Fv&l z6le$@GwdX<5rjyzV!Jg(A%W4SsI7*M#x@uzh`OIK7(3DgcoXWgv)o6%t$k$sjvcX6 zl`{_i5?;Q?uib?Cg8nu5^mD`^T>}@x{PbO8Xa?!E+JF$No2vM}U17KY`RAAC($jl% z{FP{CH1%vn<=S64?&bVD)9@jh+rye6G-<@LzyzOfr^LH7r#yH5$hmt+^ABdRlg1KS zb5IAg_2-AQJLB~%aTpF-3SQf_O>)wml>ap#{D&Hhgh}- zMI+8AKs9vkJgw9bJQbdE1uXqWf#&o-BZq)nB%RwKt+DWwn70_f7(->o-8RhAk=!u> zr<58u51_juoxvyGG}2iRp9c-S0dzkq&xf!Ot-3_y#Y4c#G!nwRfvkWgUJ7nXk#eOF z18I#AnsnT7(4n$hxK;XVAK3u7!<^#^=dybm_Lom=FunZk$bLCu_t z-TxfO;SyhK!3yhsdvzvW%IVidUT*PN%zSh3m|Q@j;7nU|;k0>!Fe;ir7rxu3`w_ZM zi7r_8;11Ai+wW$*sk2jj+_Ml%m>Q5SdMoxip^z}M@5DX~X%6R$03T-dwD_4@O=lY* z!p?ZG49mm>BS0oEb@;uZJG!L(@qoHlLz?b&{Hw$A^sY2`CkWvB4RrMq?pb;$9yER@ zuMI44yXql7?}<)@LOZ7Xf!jpV`h69F`N?e@R6KO+!ML*v3 z`{4ctSB(!$n4C&O(ub<3#oZv!KEjb%BG7$^@O*k_nSg}n* zg3nTcDhPoE7yFhD` zl`x<@ZLS3OeoULiq=fZ+G)h5e#IMkvQSK31l|AD%u|mH`)|7~a3M`dzc%`ke_~hY$ zhn+U3`&d9wY2HNI~rtJ%IYC5FN|8~Dezxg%?TiQQ`Iu|{eD9L4RrO2b|=2zv@4 zuxbSMO2k>;Rqy}_0OxteJBcz3I}>*7#69W$iulZ}|VkES3Rv~mFoiyBR@ z0N+{f#{rvV9Y%WYY!|8zt?YUF9F8Yy;_CE@*vcou>}S`7E=`+1!~1NB*TOzR3{vms z0S!yNSGFbuqA5axz^$7)Vbb6(&_D(Csqk|ZOA8e?*mq)6>fx>Soo-1Z7KH%Z+tI{D zNE5S4J^*i>g5|sAsQhvm37@MjF!c|Er-vEg(~nI&jC?1AKnI-ug46jqWoe(ckzzsR z`khpBx|c;eYs)YL->C9nAj}Gf(1;p22{tU}60&yl zw8EL!ueenoRl@?#5&ppORL)93QoU9m=;aC?D)4+HC7q0{Z07eI=BLTyoA@+A*5D6f zcuj637joWLF9x`4BKF!XX{m_p5dAe_H zRDcrXFfWpA(j3g8xB9h)v{fH`W|jYL#suYsWd&W4O0dkuIr6Xp0Cm7@h_-JOzB_3F zcXs~b5lDb1*z@)@L|xAs<{O$hF@vDNez>pg0#O{9jCm0X!w>k#TPuSxFN$$FbXsjY zMvrgboZkND<=qfX5vls^JKNp(Q@9@|$1W{&<~!VxZknpTamm8A?Lu#Z?NIh!N0^_u z9e!8!Cn5)+{*JDU$Vx>@{K)MhzfIiB=t(^m#Ad#WjT{})w@G@(p@M88aj>thm~%V%R{QZBTCj77>C&bjIcs*HG2ksgo0N-0wF%R$X&G5cLpk@ z%IYC{0rzbNMU|sl`yvzmar;uj5VEdG=M7xn;w@td3jzl?GQN!waKW`OQ_cByfH8Uu zC;@*lXr#9GGE>mQN#04!x;0OUbrv*2)8{|HVYIk*=KOIr;JG{`IFY*t@WG(Svbecj zM}Nayv~pd9yNIf=#3cA9_4Z-IWobNeiE)U?Jhy)5H9TpK)t3 z-gy-=Avx~3YA-}L^c}EwXV3Vf;to(IImW#d2lLl~9T9~YoRI?g;$Ko*-iVFs!P0QTVQG=t6VTKBLpvH^;PbIJ$aUgUJX=vpEC3A*1c zuo$tgS7>nWZ7Wy-PO4aXPXQQuJay#Wz5|}421&T9FN>KQZ>iD9h!Ix6v>iazlVVfwyzK^T-_%LN;Ha3btBO{7;T7t~0xR{tLWW2}eEQXkTSTUc0OW`osRaNkC_``<}X7?^jJ$JCd^gn)| zvmt#G3lStMOcdB68}$DPXO9msxzjlw5Or!6wpT9DHo1d>EYajdP^&WLz1%@BU4?>I zx)Rq zS~h$MR#iscInZv^@as9x)#dMmBXVy3Px?=`n|L{nwMdSkQrjxV@dbA^`~vwdAHPXB z%Fkxo@)y^jq%;XsT6oYn1y9CIL*k^!zyW*Rl&}Ln-xF{|(U*$(()s)Q#&v(5lRw?w zH(|+ZwS$*wdYDX3A^7JoLN`uy#?KLEEtk&C`qGaU7=)jx`WnD1VUya0sVTinV!}}i zWTkZC#dK|$bwL`{1xRLOcuK&}&T?h4WY8e9s6nG+@A%ExZ`frtMNvaI)GKIOd*V5N zFe<&wKWSUXR!S1@_Dmqr>3N6?PA6@wn?B=Gq#-xO<#mUvz7IwWGi6xne+{T$paTIQ zjBl}ZS=w_TTe&n>Voe-0PW0Ra!+j(TQU%E`g=8;)czw^+1_zE%{1kcEgD^OCZ^ayomz>6pPOUc%pvOn99XH*4|*^rN}XJtKQO5XhhCiur)$)I9CWNfb7 zW@U8=S=6laj>4oPxGvhfywJU$TQl8Y{qctzH+7N?ARY=hiR!a~$vn}^r0&ob=TGEq zrKV^S{E(9dx^LH4__OnV-4?Ge7!JQuzNw}-qlqI4IaJ8%(T1_9rkz9r;G)xGNp@x3 zL%+RpC4z|9&kU5#*g?{W|w^ca`HGA?-u#dU#SnIfK+%yM>?(DM05^!aP< zxpwBV>e>3y8B7~`jTN(_>LmQOs=6+hnq!EU(fhXeenl_n^hBE8{SwW?%g!unr`3{0 zRO71$zw%i`%f^`Rq4Ez@z5CpfcpLn7<)OzVm*)z8=%c16s1H|2CtJFeLT$3q?)wn_ zm_gmhmnoN}fHn*u{*YIj_ND#dL!0IFTzl>qd3G9=6c;bmj+NmH77+6UTi^77AsJFmR>T=QHq`Eyxu`hzx99Ki2NQp5uO!8}Dg88Cl*N$=Ym z>U{mA;ivojm6A`4zeVlfjnIX|R?z)+DzBFpyn6?Tk%HPrOt#GpBLuv0&lng4998txy@6X8>=#Z|>i%=p`oJ;6bLy(_oiL z^^s(miC5i%qc0tj>mjD@!-+vZ^|f=J z{qumUjzRelXkSHb({#@n=&X^5rZ-ItVP&WD%b0bO(UytF5sspCmB9tYEB29ZK>H;UbJuCj6 z*ss6)?_gYG4gMD|MoF3H1x;Kp`yr~=l$10^g8F6OL~GFJ*#`1%BEZ!*uujV(>yU6E z>dnS0sUUe~Md=ujZ-hZ)rkd+bSW&(eZH@rGSj*`^o&W_uN#+evrr94VCPAa@8DGzv zgK^p)y$5{N-(Zoo1F~j8H?_p@Y@RAqD&aKcAm*9Gul72$Y>@@Ut*^~nJMREHZ6=?S zt(!biiI@d38QpjF6CZ1R@J%6p-VPZwb;o;Bw}znC`%&s~xgr#g#yc=n>o;dL$~e3! z82&oDjKRKDMoWap@1J-V`%b(VmqLhm8$mb?Vkn(?evd#@8DhL;w@py&SF%47XrRUEhrV=n_gBl_(kHE`BW^ant^H7a1*Y($ z1C%p%jQW00XulYsY=tUY1qV~I`Tmgu7%#Vao^#m!qqH`}&kaxkx>dI3u*e+d$N8zt z`Z!X~kk~k&uF-Dt!A%0{Lfs{s@k{iLVru9#Be))SuiLjE%u~+2jAvsSHr+2wgejb+ zh(=%kIK&WRa(N2i%-b$`H72~p$9elLP^H<%D1xxMM@M>VxeL&Vr1Lr`%`J@7=7Hn- z($AdsH;83b2nH3XY7aFX>vV;_r^UZEo<<77gjZa({|AI^X>PaQpSwiZpRJ&H(B?+B z>!ohzW%03e-S|g7&UuqZJSpc6=CsREVdm!$W372%6G_A!NCWrxLCU>+$}Qw8G&?{8g-W^8BnK+) z>v)kbcZ2gyHoq!t>xQ<}Cix1h4H8>g-D$)Z)!XylwN^P+m~Rq|6_H%xpUR z#%&&z{2G=lRyq0QVmo=OBGsMTcT*SkAqD7V1dA>>lfj#T9awubC6ykxPsd>p&((cS zJ0jekX@B@4@BK;dla~0OvuCFn?MoFIhkavbR-=x4pNu<3y7ne2hp+qVSt(RMB|-rT zbt}FpN$6(i&i#Wux0Wp_x3YOF5r#*Z!w$(WSpntX6KYHlx6PZzFk@o5jck`cPq}{n z(HlsU`#F>b*rUmtHrG%D=*Ob3fY!?6tqeV$#o@sAQ>1n1(-z-&fVNw9Q3agEgE6HIJc@Es=niW1w(UZ<845ko)y1RLn}a; z48QR(rWkS-zvsX8M9sMfhgz`JZ!fi&w7V5S<csr%*9WB zlUZfk{C$Y;4iN8XH`&{GFPS!Lo`rGPVVo%9uzo2ib)K!D5-lsLg8cv5+~E6AEwzq* zE!e;&5{BN$RhrH+yC)ZZjH4K~l+Sz)B;sRBF|<~|?uOZAOI>z?S*MJk__#uDqDT68 zE7t&&++f|AdL`DY$$O_80<2zZ5*JpQK;V z;*k{Nk$?&L&F;V!_Q$gaWwn=pasu*tUjdmlaXJ?PjPSMk3D{B}vi_(X&*xU)VNltq z^$Xq|mCG^QN6V)DVp;Dcc`7xUp8H=ufA$`P9$-9RfPvqFmAHnA2sF@%3gL#K5Awbj z0+g_Sth~)_;Qm4>m51GH`W2S&*l$Y-Bkr`NKYvEHz|oc(tJr{NZ^!zMa5`&n=7S$m z0{Tr&9-&IL^#M`bmZ}`55OR)8gpc}ztnd+k4t*?R!-W~=HTY_vJHdU$>x_vCX2K6B zTY+Ln@xmD6EEOphi80Nj;N57RD>2DW$)`%YT4_R^sf zEz&1z1m9GqHdX*9_@rp;JuPlWvEllM?&MgDq=KyhgOh^H7#VL)Bq{!O7vWC;`S z`03c<4i$XPWHoKk1QfaJOt%Wn{O40HK{%A4F+w~S1$8V>iU133w7AKA+1}aTv0+HX5MQmN4d%anz;dp|5YHCmk9OR&zf&)(QRFgf0t@ z!Ka`!ac>~rEzn&t(4Su4h9*`&j}ZV7B{EC$g}z znZE`-pMq|bLU94gYezd~aXPbk>;-@`+n87Ko^7BXjYNP9h&DqDl`FjL!L$@J>;E7Y zHhVW)>cdhv52y%B#h&jG<4xM%fQREWXw}57041#A0+DnKNNB`_cO9 zfiiR`AC?{%P-lNPKYSKRsp%zQ<4v0zj-3H%an+Ebx0{(=@aA~&de#1pVaJOP=Y3tZ z-+IBM?ksu`(^*>^k^^O~fWCzGB1ddrCh?Kx%G`JI8aBE3 z@04)7Efh|9lBcuoYe1f2=|>7M=z9VBnRP=nY*>*q|L%a9T2loG3C6TToBx z8lK)qsW>Ke&0@6tO4%J~g^JlG8?=Z)D~x_r!Er?x`+0b|#+pAUs3QZE$)L6E5B5xf zae$=T0Pp4p+SV~rTP|HxuUsZCzlGiuvz2YPK0l*;7OBQPdgyT2yD;;M-(G9L))xPB zB^gNr;}|fE%cFwzP?R=^bOeTWi?#SZxuviMA; zB?x-D%(Opn=8EHop|MXBIpJpHKK*|_K{WvAl)Ow!gbGN32C{AIE4cgM=M9wFD{py) zsjwyU;DYP}5d^Kw1@m?2CA-7I{~CtGweV;fpp`Z^GfsIg<^!1HfWrt1Ju!$w-Lj&S zY$)LGv7IG4m>`ukE|YDi3X zJ)!f*`k1w}$V4se7e9u6KWb}2vxmL}VY@5Yj!^}^I{!fX+nZD34JHM`+?$VoPkJlA zi!Wpk(foU)zn&4EDnz4|tWTqA%Dhn;r(Q!4L%v-usXF>?G){@bhFQggi(5T%b#TSL z-~@B?Hw@Jsd4Luv@+1@m;69H1X^49eZS^x_r(Vi#z;n3S<+4`K_jFEv_YGF6Zl6%f>^cf`i|4~797!60 zAIJ@gaEgC?b6R{c;Y#FXeoL+3ImsTCNMef@?N$epu=7#cANkD>$@W8H|cf z@K3;1IAaAF=W|GW3ue4YeOlg=vlZ0ArsisD`{n-Q-Rg+=G&qB%6wm=Bc9q6qTjn6K-RwK=o}H>>Ub zBPkhvzaevn1Ly?pm}NnLTWhA*N8(Q{MZRg@%xta`Y55G$slQrNMBaC}2BZ+%i(>Mq z!3zWLCm-)*0sTyK&gHxR*gr?$h@;J?#>*La6)kQn9l!xleBHYE8MxafX1mw#BP$C@ zw}32c0CV8RE6yVW zYbV>U|J&{RcQL0kEv9;UgF1k?^w=pNn>Wd*9Fs=daS-}MbViS1T3)g@6CGzk{y3Wa z73iaglYW{B=8P6)80t*@4N-=|g#{-?NSWvwfqSM#6|u^N1+j2r>4}|WRBD_1uR2qj zqolasyT1kx#j8s1tCpX@S4eZ8YKlIDHZw$1G|u9Xu0ZSTz-g-ARz{#-Eok|jSjJWm zC}H<+W@X87I`LWc2Y(SCIA$7TgpZPZmibZg4x%Bug{mWy3uo*=^dmx1SHeiAyc4~L zZJ=BzDb$vO5Ng0-jiSDL9t6!Gobgg_pVb)+pX$efQEcA^xcwy(ZJsLg4IOeFaD&8V%IPiSCvLDDF-L5RR+P=l_;Z9`F75ujXfZ+RYV)w4?pLk~r% zM`%)fC{ZzFJHuaQ$~tfm-3%VpEB_gXd`EOX`o=)let%fzQU<2_CA$#RT^Jg2gh>qQ zTa%F0ub}MilA2D*(adzRUn@zL!6P9M9$FAK%ex0TQbNjM(xVh`G9XjQ()m#L6s9oL z%F~)D48^_Z-Q%Y=+d6E0n zyt57hQ@6xzovtwaYAGNSu6k8wm98gUvtoSA2kmaZKo+9Yv_htcW4SbbV*La#y& zhhGJ4m->{@KDxIMvvj$>f`LkqYDQck5|kLq^_4R;YLrn=fKY=!=yJhU9Epv8N(3LA zU5l%|Z+u$vKrox9c1}dd{>{$=Y|uRc6UrzHPGyKczd)rDD-YSTyf%|#Z@^aQ{s}A7 zsR}O12VUQ~k=DC0T+Ga?v*^9lA5tMsQ`3-0TFpNxY=+~8onagb!`Bz4DWG{kcZ!el zdm)T|8VME4Sy(N|xV4dFo7{dCvOY(iC912uy0J1A88If$8#L_glKBCzl2ey&`cHqj zejD@cJX+8Sw6G)QPIiX%>Sb0%_tJXr!{N-hX}L?}5uCka|J3{ca}=qWgqxZoL`p+L z8l~0(f?9yUX0ri7e*H88`t?sEvnPwxPQ=C4y%rqIgB7ucX0%l&3QAarn;Kd zo2YMNoeg%9K4xwcVuAxyTeXYZZ|t(;^~ikNGf#oB!4ZIJY*zgSoY%HPdjBKAsGM?@ z6d0EO7kh6SkYgJD4c}SDHnyQ6C2NQ>QM5=6vP;pv4v7|(v}uo-P^pl$h4y`s_T8B3 z9?_yzJ0t-y2SmN7{&Qi9#7-y#q{dWBnlYy_9^~q!H)k^n=Cq; z{URr;y?(g8wDG3bstO=($FKoJo7Z>T6d?sp#I1A@X(V~X`uxBsPWZE&W{%KM-HZE9 zy8?O%C)l$SQ3$Uk1vq3amU6yJ_>W|B%^1YrKA3y8kF$!yH>e{ykzjM<^R$;rT2^i- zxdSLc!Lm3OuDof|+~7ESvojdMb>4CPIa+0&7HSrpPylZukN(}mw!+8Pa#9uH)f368#MmOX_gp}TPVavoQ>kE*;+7$(D7Mg zg8O(xwnWhwTo7zvZ;Z=CX2?3a3wG~rxU_!^`HI@h*#~1e2{upU&kk(U_K49~)AnmZ z0VmgCb0O^aE}z(Ffr|jO15sddY}SiEfQ%TMtCCZk-Fop%{m4&q%AV8IpT;Y#o}CC8 z+A`nJ0ZA0{?BWmwG=286+pzH{t*m>8W2J4ZW6x+tsiQD?C8BV%p}Au4RHIx=5>9iS zt$bEJ$Ic4(0P-)JVqxl>!>8GIoP~kA*cy|vj;%ul=K`ZS$4K9S#je>pf>M#led4J% z3M{4vqLcdrgC`HAT7;QH>#9z;Vv1*6U|JE&gSO zXwfh?8oH|)W$Ez)a^ktqR+$13-Q4poS>}5S-F0)-8M~TMIum23pNuF0<|rIaSyou% zc4HTW%2KN!C*2VL?z>nXNruveX}MBfvs2l*0yUDKtydWspwF8}F?0yneRdTayrmjlV07<4R z0m`==?8Xs_;|}t!48Q0BalE%g`v%N>e>>W_88kE9=~CsXK6I}t6XOW(QJGl9Sd?U3 zMVWS1aU>3pH?F#{ckpqnaTRhFd-WKL>aeMlBQO1O%}PCWSk}*O_i0gCF=zg#?KxDp@ets()m?+)^UeS;Z)d67wPHk^6#4n22Myv}}RC5!Xob8ww`)DT)gt1my?pUG9Qbm44wQJWO#uSp7unkv zZ!+vm?a?*LmamBj1B!yuN%arm2jD-$@S0xP&4^S6NOu&jWydjUMIlZEp}W9P3qs9( zJPd^!DzR#J$meE>VD9#kmG#h3uB=-DyoQBOmjam&o%~vgkJYHVDIYN}QG={o)w z7E6QxhNCgEUC#)75(`T(xq8?ou4d}RSHSiL+)jqF)uM2#k8{Wda0hMad8w%Qd-!Lw zimUm}(a~}SNHB|=OA#nlY}RBA_Ez796Gd|`+}6VqLr~;((v0YRJXr4oUJTip>X0CC)zJuRi)DJ)hcs8#-8991s>?p*N&@_{ zgn1yfTh1qG`Pcl);Ca0v*+)9^&16wz#B`$EkN(?*Mk>A^xfhQVg& zC=z}&Bnq9ooTeaE%;wfw6UxEx{0n=11&v8Wl$jSPjkFBd;ZF#}wB^B3{hQZPmj@=_ zxuF`xzquhxJ}YoTwat>a7aBjXui-qUXUTDXKxOYct^Xn&1;ke+%D;K|xhsAUeKOOf zaE)NV!NaY{Xnf-;y6(Uga$rz(A$FQ!@KJj;HYQgeU6d2$;O(Ed?g}5Etc^;h_bt(iyCfkaQsNaJ5>Zlj0_N*n;1 z^&*Iz;_M=e$aiQcPG=BQ(23+r2X@_uB3QqDhU~ILv>%qx28JW5Puip*J@K+5yve|q zI90XQCUXEE0yRXm$X4HFuOWJbRtDLsa&i`Iu$WXv2AS-w)Ax2{Nh)Nm!G2ClD>ugq zV;Y2DO-ryy53;>8flHOtNVcECSv`MK$m+;hQ~bzhbQ?Qr5&(ZAGuGTv{#;1K01OjKG!TA7j^wG%R!?>zT#J?<&!7 zC_Jg>4BQpJbh~D1Y-Gq6wz(;i_e^1zq~PM!d)|qi#TER(h8h*T|8_Nbm}bfql%2we z5gAnxA$+3{GTr_%B2S8}-3W;wFnM&D)S*$|$abD#JZq`XrQdP))`Znyl{-N2d`SEQ|BI!W9c6@IfbS zrI#L&)Pq0)LiCQW*;0UfMEAOiL$Al?US!A~Tk3OkUFZPNOmQqtRL+nLgVUv@8949` zxL77OuL`PG2^7RB55QAiRohBgWfliR!+ow1_KJ|mm_aryw|D+}r5t%_0?6S`X9MK2 z7VI)zA^2~&uPyq1K`Tyour_!gwZ(BS-StWK!n9|Aw7SZiYxr#_LZ%o5QhzHIcNm7X zZS6wFdlv{dVJafwCRFd#La7_9FDc*%4AVf(75|sQHgn58o5aRO0*ZWe8Lk>4rK54T30(dtsIT(-QRxfZuz8vh|z@L_TV zLvP3kG$hI{6Eq6mNvuDMQpfi*`48&?0)B2`!wAHY-Tk~}zH3cU>$G9X#uLM;Y~uDj zU^|vpWv#-Vb%*vW7cQ%isAs1SHe7PI?hk7+aIfy8>gPJ!NOy1<NNjXd-SW^ zSqvkgWOI0l!l^jL(_jI^1B|(GyRBQ!LdG1$&yk<&?4o9Sw`e)T(3WA`ow)f5AhG0G zRA$H~nS9Vuo9I^1Nat3Wa`!ue+egf}ti>R1csNmYos`;YI^n`G6Rp|>nQ?V2fWQ(! z^{80ieC z{Z|=Sr14BOXYKO1IudzpZ=K`vsf%c3NkaVlr?yc`%T`HL&Zg}n z@CeyYeD^xqDaH&(FWWY<2@BUGX*FB##Za&(dig?tsMAEZZhQ4&9?{KY&*?n~8A6!XdGAy+#PHx=+QTuY=8e)nu0oX zWZ{G9W}p0FY!H>_&EI>kd$b|)UY>{c;ub#6nzwAq%Wo%Am!j$BO_ic?2X*Cy-}%Y< z6_~Da%uav6_6gx+tk-79hAcF3U}ZI*pz>7%l{hFSXvDB^?@&jvUcUl*yr&B^+#bKo1&6{=DT^G+XB9kM@RJbpM8_Tt?Q!^tk#P{6l6vHw@a35_$uWq%S#3#~iRYQa~Of0r`)DPR`_kIG81 zg7dXHUgGRI*S>K4=wox3;6$ZR;2xzAw9I)+yN`)n`TRb3*Za3TTKXoaWm`^tfGVSX zTj0or!3X1>JgqDhc!Adu+FjCaJ{5yWb{HtF_SR9 zb!x6GjsF;#;*y{3wB1vfiJA(+GLG-Sa`9iN=Pep>;Qi9D`5jiu-;HkP7E`YLS;f;5 zFbZCi~4hMiYyk`V?l2W0wD<(mniaco+TiNj^70_ID z443mp1YV2Co|!Y4zB>tM9r_h01XX^HdFErg{7n~dXm-Ik?cyyvuzm7SRpHC76Ny;& zfuX$!v$?0;V>7_d&@i2TS9aMV(`WQhUj~YX@R;~a!2m=S&+vm51ZX>GYwRDy$d~4P z5=(d`X+o;aeXAH{Gdzry8(zCjA<_XnH)qWZ;9_jBfhPkm+^1*}!>!8W;%srB z_N2kq6ui?;Zj%>43pNkrvY$-@c}C7?MdGQuhW>W-=b=EYt$Q_W&*VN+wuZ}1BNb&& zpG_X9z<(u~V1ZER0a;+AtoT=x8Ac-DC-!Yybst-aOCduZ^q31wG=-uFv<`l$%|875 z|8_KOl#F3$kLiw`0$b<9yB}TY83Pi774KU`G@~@jT{U|h+RK{lcuSRnp5C75<;^)+C70 z6mccuf#CZ;W?oWiuqRgMh`lK_vIRtaJ;bJap%mA_N9U}IhVPOL(s)^g{72&jRSPP7 zIg@CjOa-JFmlT*AyrIZd$@n@gxnpvP%=_%vZ~qk4hwRMjyND|7xne@*%65!H>xiu= zBvWtAZw!~;GFQX05*+;U3{tV)cu5)?)TdvN2RKEud<2iD*mZY{$UZ(gGUIW& zy3ulZ&+u9O5a}_MNA0Ku$4f2Nmj+`~td(We(F4$6TZZs4B2$hyL{vFp=jadum4cuc3)88${i7ssQ}!hSCc+#<@Oku!NZ&g$1iHH=qOT*nqKKNcbAVfZ^BPVU^Q z`}L?KOggSuhQ6OuVo2?Pl8U`HY;e?}`lJ&Kdy#Aoam9U38ru}VUBpcnGhG#+gX1$G z>nYc3I0>{MS`I9rl?b`Y_XLj92e(c0E)ZmJDs#A3mn?k;!9oA+Le#XrG@ZIWYt3Kj&1HhmcwN`lK+?C^dj`!YNN3rQ`(YFhUu5pgNlnNiX7 zO=@midKB93X%%;uAL$5+&wgq7_I1!haGXxQtVC^+bX|yhv>;|IU+x1c*lJQ@i~!e^ z?j$Veu$CI7w=f*p7tqBbx|T6@9mY zgYgnV#^>_STv^?atyiGlHEQ_fAFtAdaSRWg8!>}X7D}ybS?EOoR$um+6%;g$I$OTo zTmY)VLwM-mf=^hP)OEl3<9AW^83XWroVN&Q6aXBdUi#Z4(Ic_ry zqE;;*fiB>UaJ7m_NCUP#_LY3#ok>APoxaBLN7%;)3%!&iB#^^#W}GNL4gLsXSEb$0 zMljs@(-Ytxujk_mp!Ld zG#yvQnIh-4;5of6hT{fTwcY_SHMrjZOrNeq)^K)^8i`x%(qp12%a-Kfu7lhslmmCZf6Zxy<@8 zfX9?s?5)T?0ctS6w`{`n_Kynn@9ZLJuaiNYTzvXI1c9OR5CTC1E>Y``G_@A- ze=JPYU01q+;##hp3*O@-7?bUYExDyQ{L(O46neK5n;#hlTx&h~QO>dJTRNMhS=V=G zuf+oy@HB&@ni2T1tPo6XfK}ZnJcqvarr`XsIM{w3H+1jMz>Crh4lVQaE4LurV!P0( zladg=|=HqJ+L-FJkVbSF9>=oL{NFtN=BgiYALzH>m?1} zfc-{cxf8q}5UWVGrzyzuN~{KN+jmXoDYO#3zhZBw{d;fdd!qjzu~wgYAvjqzraXhe zyMrFYQ5uid;98tsCIN!-V)+@*IZu%L132-cq<+3@3GQapiiHeOd-H6R`-_py5!|I4 zv>T@^x)Z7{sUvjx)DE@QF|Imrx~>HO!(NE$-1o{{M)J)?l+>^}lPLj6^*_*c$Lb5; zp=(hSdM3+jL6ful`Krfrjqe3xyO2}95Pbg?IFeW*!KyU z*&c(ttg%~%-4z9XMO!=hz;zeo-ZE{~gl!R%-kDq>|5{+}3`X(>tojqs0^k4O={_Db z-Mm7kMSYq$s=3N(%PVyEH?XhCF5s#<3uVWHn03p%msY-Gr*T1iBVatCIlS*9h%2kt zNcuju*pNMK`tW)|7N;E`4qqrk2YqX(@n9I(l4Kde3Ydvtodr`go%}#c)u@vtPlu*b znd$dK(^Quo$TfdKUBQk^?`2u?01rvDcvE1emqRGZy73#az=dbOH}BGrPI1dNBsJVH%l!=d!1x2aEvu(3%QN zZ1&Mcq4!q07MnAnhc)R$K9ob*=HB;e(aIh9((33Sh`tV-N1$K4=D`Bj7a-@b?aTs~ zZ|+u|O`tFP?mUdPTUvfoo~9zbl4g0?WUq&zO84mB&Qrv~`T#N%MrDcxv@30|zqlfbAchR#TyZ76&d1c%39G^!DMhqnY_DePZ<#*@OR=6{BXO>BWpWhi0?NL86J!(l+&Ve}G_l{^x(Y7U+A%u#9aY{$Kee z02)yPg=ugP*#Qwafa~6(7$w~$MJvh89*?&E-1zjnyGixg_RLE(me77CYE2Txh~EC* z2c^95obH3H6XT3lHB8%@u-wlcZpG{!Tn~vvq*+f`*_*KI_ULbCqYAPnG|3EI908yW zW00AI9}~{l;5d@>l(P;M&rFI;1ZQc!I0IUS?h#FQjG^0MGbR3#cl{x+`i?UzZ1MVFz)}p1IZihg7^^bRL!c zM30C!7%eZC_9!WRiK;(Re<-FlnmadmW86p*gRyWGJ1Mh*xO|e@+xLa~$R8!D!@2>r zppdfG98dXGGUK(Sm%GO?LJhPsE2DIt37-9>tADUN;1&LG_2MQVauqJ;sK^(;eiv^Q zd(yr;Pe>njclF9s)+Czm&4Qltqwu)`J*@^BpXs<5Yl$rS|9ebk(d~l`w*jF~K8<|G z8^E>&CX?y55#FI@knh}KNhOk7vv$pA$hJO1CmcKa>j&w6wU#=AE!UyF&T8j-josxG zP((r<0;A}WY+h331KO#;HJb7RP`On){0c#8^-rnb2DBpGs}nQz@!1e>VG{kLAruS( zHWyjbA(_Yh#S&Fn)H}4&$l9x?026>`=r8Gh|%@~EF zn&>sgA|2j(A&un7$Tck}Et3|($B7Ngx;N$7nzP#=;`wZi4uo9TWfyUg>tmW!QslbX zhNr!zTq-#~FK^r-IZf*VikB-$gCqjr1xQVpc{ai=r;ownf!36hu_IYg+%^GqM<-

    }OkaLO4Pw?V3y9{;#nW{dmQ=ki8qs2gt{eZ919 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 SW{1K5bzMVGy;#*I +``` + +### DiagnosisConfidenceCard + +```tsx +import { DiagnosisConfidenceCard } from '@/components/medical-visualization'; + + +``` + +### SourceTag + +```tsx +import { SourceTag } from '@/components/medical-visualization'; + + // 显示 [内部] + // 显示 [外部] +``` + +### 可点击按钮 (Markdown中) + +在AI回复中使用 `[btn:选项文字]` 格式,会自动渲染为可点击按钮: + +```markdown +请选择下一步操作: + +[btn:询问发热情况] [btn:询问其他症状] [btn:进入体格检查] +``` + +--- + +## 样式说明 + +所有新增组件使用: +- **TailwindCSS** 进行样式定义 +- **Lucide React** 图标库 +- **shadcn/ui** 基础组件 + +遵循 Nexent 现有设计规范,保持视觉一致性。 From fc23afe019757c491a2263768c635de690c40f39 Mon Sep 17 00:00:00 2001 From: Shuangrui CHEN Date: Mon, 5 Jan 2026 20:41:21 +0800 Subject: [PATCH 07/13] =?UTF-8?q?=E2=9C=A8=20Add=20SDK=20publish=20workflo?= =?UTF-8?q?w=20for=20PyPI=20with=20OIDC=20authentication?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .github/workflows/sdk_publish.yml | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/sdk_publish.yml diff --git a/.github/workflows/sdk_publish.yml b/.github/workflows/sdk_publish.yml new file mode 100644 index 000000000..1e5759277 --- /dev/null +++ b/.github/workflows/sdk_publish.yml @@ -0,0 +1,44 @@ +name: Publish SDK to PyPI + +on: + workflow_dispatch: + inputs: + version: + description: 'Version to publish (leave empty to use pyproject.toml version)' + required: false + type: string + +jobs: + build-and-publish: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install build dependencies + run: | + python -m pip install --upgrade pip + pip install build + + - name: Update version if specified + if: ${{ inputs.version != '' }} + working-directory: sdk + run: | + sed -i "s/^version = .*/version = \"${{ inputs.version }}\"/" pyproject.toml + + - name: Build package + working-directory: sdk + run: python -m build + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + packages-dir: sdk/dist/ From a0efbce155543242536f19d3207d6bbec11f765c Mon Sep 17 00:00:00 2001 From: xuyaqi Date: Thu, 8 Jan 2026 16:52:06 +0800 Subject: [PATCH 08/13] bugfix sync modle engine model icon --- frontend/app/[locale]/models/components/modelConfig.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app/[locale]/models/components/modelConfig.tsx b/frontend/app/[locale]/models/components/modelConfig.tsx index e07aa502e..f64009e24 100644 --- a/frontend/app/[locale]/models/components/modelConfig.tsx +++ b/frontend/app/[locale]/models/components/modelConfig.tsx @@ -848,9 +848,9 @@ export const ModelConfigSection = forwardRef< size="middle" onClick={handleSyncModels} style={{ width: "100%" }} + icon={} block > - {t("modelConfig.button.syncModelEngine")} From 137291b8271b41e1a08676ded072a11ba78feea8 Mon Sep 17 00:00:00 2001 From: xuyaqi Date: Thu, 8 Jan 2026 16:54:53 +0800 Subject: [PATCH 09/13] Revert "bugfix sync modle engine model icon" This reverts commit a0efbce155543242536f19d3207d6bbec11f765c. --- frontend/app/[locale]/models/components/modelConfig.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app/[locale]/models/components/modelConfig.tsx b/frontend/app/[locale]/models/components/modelConfig.tsx index f64009e24..e07aa502e 100644 --- a/frontend/app/[locale]/models/components/modelConfig.tsx +++ b/frontend/app/[locale]/models/components/modelConfig.tsx @@ -848,9 +848,9 @@ export const ModelConfigSection = forwardRef< size="middle" onClick={handleSyncModels} style={{ width: "100%" }} - icon={} block > + {t("modelConfig.button.syncModelEngine")} From c7f4a15f864af42ba0ccd953d18b4e61e1398440 Mon Sep 17 00:00:00 2001 From: WMC001 <46217886+WMC001@users.noreply.github.com> Date: Mon, 26 Jan 2026 11:53:26 +0800 Subject: [PATCH 10/13] Add CodeQL analysis workflow configuration --- .github/workflows/codeql_main.yml | 103 ++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 .github/workflows/codeql_main.yml diff --git a/.github/workflows/codeql_main.yml b/.github/workflows/codeql_main.yml new file mode 100644 index 000000000..85905eb55 --- /dev/null +++ b/.github/workflows/codeql_main.yml @@ -0,0 +1,103 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: '40 13 * * 6' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + - language: javascript-typescript + build-mode: none + - language: python + build-mode: none + # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Add any setup steps before running the `github/codeql-action/init` action. + # This includes steps like installing compilers or runtimes (`actions/setup-node` + # or others). This is typically only required for manual builds. + # - name: Setup runtime (example) + # uses: actions/setup-example@v1 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - name: Run manual build steps + if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{matrix.language}}" From 7d63bbfdb4467551fee6105aebf77f5658d0e2d0 Mon Sep 17 00:00:00 2001 From: zhizhi <928570418@qq.com> Date: Fri, 6 Feb 2026 09:28:47 +0800 Subject: [PATCH 11/13] =?UTF-8?q?=F0=9F=90=9B=20Fixed=20the=20data=20proce?= =?UTF-8?q?ssing=20image=20that=20lacked=20tiktoken=20word=20segmentation?= =?UTF-8?q?=20files.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/pyproject.toml | 3 ++- make/data_process/Dockerfile | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/pyproject.toml b/backend/pyproject.toml index af0d10ef4..65e27107a 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -25,7 +25,8 @@ data-process = [ "celery>=5.3.6", "flower>=2.0.1", "nest_asyncio>=1.5.6", - "unstructured[csv,docx,pdf,pptx,xlsx,md]==0.18.14" + "unstructured[csv,docx,pdf,pptx,xlsx,md]==0.18.14", + "huggingface_hub>=0.19.0,<0.21.0" ] test = [ "pytest", diff --git a/make/data_process/Dockerfile b/make/data_process/Dockerfile index e7550fe2d..35d7a6c48 100644 --- a/make/data_process/Dockerfile +++ b/make/data_process/Dockerfile @@ -42,6 +42,9 @@ RUN uv sync --no-cache-dir --extra data-process $(test -n "$MIRROR" && echo "-i COPY sdk /opt/sdk RUN uv pip install --no-cache-dir /opt/sdk $(test -n "$MIRROR" && echo "-i $MIRROR") && \ uv cache clean + +# Pre-download tiktoken cl100k_base model to avoid network issues during runtime +RUN uv run python -c "import tiktoken; enc = tiktoken.get_encoding('cl100k_base')" # Layer 3: copy backend code COPY backend /opt/backend From 00c83a580c2552ff8673e0bbb1c479deb928f9ac Mon Sep 17 00:00:00 2001 From: wadecrack <2138269670@qq.com> Date: Sun, 8 Feb 2026 16:20:25 +0800 Subject: [PATCH 12/13] New Requirement: Support for provider Zhipu AI Models (LLM and Embedding) --- backend/consts/provider.py | 32 ++++++ backend/services/model_management_service.py | 4 +- backend/services/model_provider_service.py | 84 +++++++++++++- docker/init.sql | 2 +- .../components/model/ModelAddDialog.tsx | 22 +++- .../models/components/model/ModelListCard.tsx | 65 +++++++++-- frontend/const/modelConfig.ts | 3 + frontend/hooks/model/UseZhipuModelList.ts | 108 ++++++++++++++++++ frontend/package.json | 1 + frontend/public/locales/en/common.json | 3 + frontend/public/locales/zh/common.json | 3 + frontend/public/zhipu.png | Bin 0 -> 1598 bytes frontend/types/modelConfig.ts | 3 +- 13 files changed, 315 insertions(+), 15 deletions(-) create mode 100644 frontend/hooks/model/UseZhipuModelList.ts create mode 100644 frontend/public/zhipu.png diff --git a/backend/consts/provider.py b/backend/consts/provider.py index 7fd783015..3f2224358 100644 --- a/backend/consts/provider.py +++ b/backend/consts/provider.py @@ -6,11 +6,43 @@ class ProviderEnum(str, Enum): SILICON = "silicon" OPENAI = "openai" MODELENGINE = "modelengine" + ANTHROPIC = "anthropic" + ZHIPU = "zhipu" # Silicon Flow SILICON_BASE_URL = "https://api.siliconflow.cn/v1/" SILICON_GET_URL = "https://api.siliconflow.cn/v1/models" +# Zhipu AI +ZHIPU_BASE_URL = "https://open.bigmodel.cn/api/paas/v4/" +ZHIPU_GET_URL = "https://open.bigmodel.cn/api/paas/v4/models" +# Hardcoded Zhipu models (injected due to incomplete API response) +HARDCODED_ZHIPU_MODELS = { + "llm": [ + {"id": "glm-4-flash", "object": "model", "owned_by": "zhipu"}, + {"id": "glm-4-air", "object": "model", "owned_by": "zhipu"}, + {"id": "glm-4-long", "object": "model", "owned_by": "zhipu"}, + ], + "vlm": [ + {"id": "glm-4.6v", "object": "model", "owned_by": "zhipu"}, + {"id": "glm-4.6v-flash", "object": "model", "owned_by": "zhipu"}, + {"id": "glm-4v-plus", "object": "model", "owned_by": "zhipu"}, + ], + "embedding": [ + {"id": "embedding-3", "object": "model", "owned_by": "zhipu"}, + {"id": "embedding-2", "object": "model", "owned_by": "zhipu"}, + ], + "reranker": [ + {"id": "reranker-3", "object": "model", "owned_by": "zhipu"}, + {"id": "reranker-2", "object": "model", "owned_by": "zhipu"}, + ], + "tts": [ + {"id": "cogspeech-1", "object": "model", "owned_by": "zhipu"}, + ], + "stt": [ + {"id": "sensevoice-v1", "object": "model", "owned_by": "zhipu"}, + ], +} # ModelEngine # Base URL and API key are loaded from environment variables at runtime diff --git a/backend/services/model_management_service.py b/backend/services/model_management_service.py index 4b8265028..7ae3dec92 100644 --- a/backend/services/model_management_service.py +++ b/backend/services/model_management_service.py @@ -3,7 +3,7 @@ from consts.const import LOCALHOST_IP, LOCALHOST_NAME, DOCKER_INTERNAL_HOST from consts.model import ModelConnectStatusEnum -from consts.provider import ProviderEnum, SILICON_BASE_URL +from consts.provider import ProviderEnum, SILICON_BASE_URL, ZHIPU_BASE_URL from database.model_management_db import ( create_model_record, @@ -142,6 +142,8 @@ async def batch_create_models_for_tenant(user_id: str, tenant_id: str, batch_pay elif provider == ProviderEnum.MODELENGINE.value: # ModelEngine models carry their own base_url in each model dict model_url = "" + elif provider == ProviderEnum.ZHIPU.value: + model_url = ZHIPU_BASE_URL else: model_url = "" diff --git a/backend/services/model_provider_service.py b/backend/services/model_provider_service.py index 3e67a804f..547df2e39 100644 --- a/backend/services/model_provider_service.py +++ b/backend/services/model_provider_service.py @@ -11,7 +11,7 @@ DEFAULT_MAXIMUM_CHUNK_SIZE, ) from consts.model import ModelConnectStatusEnum, ModelRequest -from consts.provider import SILICON_GET_URL, ProviderEnum +from consts.provider import SILICON_GET_URL, ProviderEnum, ZHIPU_GET_URL,ZHIPU_BASE_URL,HARDCODED_ZHIPU_MODELS from database.model_management_db import get_models_by_tenant_factory_type from services.model_health_service import embedding_dimension_check from utils.model_name_utils import split_repo_name, add_repo_to_name @@ -68,6 +68,85 @@ async def get_models(self, provider_config: Dict) -> List[Dict]: logger.error(f"Error getting models from silicon: {e}") return [] +class ZhipuModelProvider(AbstractModelProvider): + """Concrete implementation for Zhipu AI provider.""" + + async def get_models(self, provider_config: Dict) -> List[Dict]: + try: + model_type: str = provider_config["model_type"] + model_api_key: str = provider_config["api_key"] + + headers = {"Authorization": f"Bearer {model_api_key}"} + if model_type in ("llm", "vlm"): + zhipu_url = f"{ZHIPU_GET_URL}?sub_type=chat" + elif model_type in ("embedding", "multi_embedding"): + zhipu_url = f"{ZHIPU_GET_URL}?sub_type=embedding" + else: + zhipu_url = ZHIPU_GET_URL + + async with httpx.AsyncClient(verify=False) as client: + response = await client.get(zhipu_url, headers=headers) + response.raise_for_status() + all_models: List[Dict] = response.json().get("data", []) + + logger.debug(f"Zhipu API returned {len(all_models)} models for type '{model_type}'") + # Filter models by type - Zhipu API may not filter by sub_type + # Zhipu API returns models with "object" field indicating type: "chat" or "embedding" + # Zhipu api_models only return chat models + seen_ids = set() + final_list = [] + api_models=[] + if(model_type=='llm'): + api_models=all_models + # Normalize API models and add in API order + for item in api_models: + mid = item.get("id") + if not mid: + continue + # ensure canonical fields to match hardcoded shape + # object/owned_by exist in hardcoded items + item.setdefault("object", item.get("object", "model")) + item.setdefault("owned_by", item.get("owned_by", "zhipu")) + item.setdefault("model_tag", "chat") + item.setdefault("model_type", model_type) + item.setdefault("max_tokens", DEFAULT_LLM_MAX_TOKENS) + final_list.append(item) + seen_ids.add(mid) + + # Append all hardcoded models of the same type (if any), but avoid duplicates + hardcoded = HARDCODED_ZHIPU_MODELS.get(model_type, []) + for model in hardcoded: + hid = model.get("id") + if not hid or hid in seen_ids: + continue + model_with_tag = model.copy() + # normalize hardcoded entries to include same canonical keys + model_with_tag.setdefault("object", model_with_tag.get("object", "model")) + model_with_tag.setdefault("owned_by", model_with_tag.get("owned_by", "zhipu")) + if model_type in ("llm", "vlm"): + model_with_tag.setdefault("model_tag", "chat") + model_with_tag.setdefault("model_type", model_type) + model_with_tag.setdefault("max_tokens", DEFAULT_LLM_MAX_TOKENS) + elif model_type in ("embedding", "multi_embedding"): + model_with_tag.setdefault("model_tag", "embedding") + model_with_tag.setdefault("model_type", model_type) + final_list.append(model_with_tag) + seen_ids.add(hid) + + # Log warning if filtered list is empty but we got API response + if not final_list and all_models: + logger.warning( + f"Zhipu API returned {len(all_models)} models but none matched " + f"filter for type '{model_type}'. Check API response format." + ) + # Return normalized list (API models first, then hardcoded additions) + return final_list + + except Exception as e: + logger.error(f"Error getting models from Zhipu: {e}") + return [] + + class ModelEngineProvider(AbstractModelProvider): """Concrete implementation for ModelEngine provider.""" @@ -288,6 +367,9 @@ async def get_provider_models(model_data: dict) -> List[dict]: elif model_data["provider"] == ProviderEnum.MODELENGINE.value: provider = ModelEngineProvider() model_list = await provider.get_models(model_data) + elif model_data["provider"] == ProviderEnum.ZHIPU.value: + provider = ZhipuModelProvider() + model_list = await provider.get_models(model_data) return model_list diff --git a/docker/init.sql b/docker/init.sql index c547bd07b..7d31c8a93 100644 --- a/docker/init.sql +++ b/docker/init.sql @@ -807,7 +807,7 @@ COMMENT ON COLUMN nexent.role_permission_t.permission_type IS 'Permission type'; COMMENT ON COLUMN nexent.role_permission_t.permission_subtype IS 'Permission subtype'; -- Add primary key constraint for role_permission_t table -ALTER TABLE nexent.role_permission_t ADD CONSTRAINT role_permission_t_pkey PRIMARY KEY (role_permission_id); +-- ALTER TABLE nexent.role_permission_t ADD CONSTRAINT role_permission_t_pkey PRIMARY KEY (role_permission_id); -- Insert role permission data with conflict handling diff --git a/frontend/app/[locale]/models/components/model/ModelAddDialog.tsx b/frontend/app/[locale]/models/components/model/ModelAddDialog.tsx index 4a2c3bf97..ae3f79acb 100644 --- a/frontend/app/[locale]/models/components/model/ModelAddDialog.tsx +++ b/frontend/app/[locale]/models/components/model/ModelAddDialog.tsx @@ -17,6 +17,7 @@ import { modelService } from "@/services/modelService"; import { ModelType, SingleModelConfig } from "@/types/modelConfig"; import { MODEL_TYPES, PROVIDER_LINKS } from "@/const/modelConfig"; import { useSiliconModelList } from "@/hooks/model/useSiliconModelList"; +import { useZhipuModelList } from "@/hooks/model/UseZhipuModelList"; import log from "@/lib/logger"; import { ModelChunkSizeSlider, @@ -217,13 +218,25 @@ export const ModelAddDialog = ({ const [modelMaxTokens, setModelMaxTokens] = useState("4096"); // Use the silicon model list hook - const { getModelList, getProviderSelectedModalList } = useSiliconModelList({ + const siliconHook = useSiliconModelList({ form, setModelList, setSelectedModelIds, setShowModelList, setLoadingModelList, }); + const zhipuHook = useZhipuModelList({ + form, + setModelList, + setSelectedModelIds, + setShowModelList, + setLoadingModelList, + }); + + // Choose the appropriate hook API based on selected provider + const getModelList = form.provider === "zhipu" ? zhipuHook.getModelList : siliconHook.getModelList; + const getProviderSelectedModalList = form.provider === "zhipu" ? zhipuHook.getProviderSelectedModalList : siliconHook.getProviderSelectedModalList; + // When dialog opens, apply default provider and optional default batch mode useEffect(() => { @@ -688,6 +701,7 @@ export const ModelAddDialog = ({ > + {/* ModelEngine URL input (only when provider is ModelEngine) */} {form.provider === "modelengine" && ( @@ -723,13 +737,13 @@ export const ModelAddDialog = ({ {t("model.type.embedding")} - - - diff --git a/frontend/app/[locale]/models/components/model/ModelListCard.tsx b/frontend/app/[locale]/models/components/model/ModelListCard.tsx index ae966ae35..64d2ae045 100644 --- a/frontend/app/[locale]/models/components/model/ModelListCard.tsx +++ b/frontend/app/[locale]/models/components/model/ModelListCard.tsx @@ -33,12 +33,12 @@ const PULSE_ANIMATION = ` transform: scale(0.95); box-shadow: 0 0 0 0 rgba(41, 128, 185, 0.7); } - + 70% { transform: scale(1); box-shadow: 0 0 0 5px rgba(41, 128, 185, 0); } - + 100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(41, 128, 185, 0); @@ -162,27 +162,30 @@ export const ModelListCard = ({ const model = modelsData.find( (m) => m.type === type && m.displayName === displayName ); - + if (!model) return t("model.source.unknown"); - + // Return source label based on model.source if (model.source === "modelengine") { return t("model.source.modelEngine"); } else if (model.source === "silicon") { return t("model.source.silicon"); + } else if (model.source === "zhipu") { + return t("model.source.zhipu"); } else if (model.source === "OpenAI-API-Compatible") { return t("model.source.custom"); } - + return t("model.source.unknown"); }; const filteredModels = getFilteredModels(); - + // Group models by source for display const groupedModels = { modelengine: filteredModels.filter((m) => m.source === "modelengine"), silicon: filteredModels.filter((m) => m.source === "silicon"), + zhipu: filteredModels.filter((m) => m.source === "zhipu"), custom: filteredModels.filter((m) => m.source === "OpenAI-API-Compatible"), }; @@ -343,6 +346,54 @@ export const ModelListCard = ({ ))} )} + {groupedModels.zhipu.length > 0 && ( + + {groupedModels.zhipu.map((model) => ( +

    +
    + provider + {model.displayName} +
    +
    + + handleStatusClick(e, model.displayName)} + onMouseDown={(e: React.MouseEvent) => { + e.stopPropagation(); + e.preventDefault(); + }} + style={getStatusStyle(model.connect_status)} + className="status-indicator" + /> + +
    +
    + + ))} + + )} {groupedModels.custom.length > 0 && ( {groupedModels.custom.map((model) => ( @@ -394,4 +445,4 @@ export const ModelListCard = ({

    ); -}; \ No newline at end of file +}; diff --git a/frontend/const/modelConfig.ts b/frontend/const/modelConfig.ts index 490cf2d87..eff19e53c 100644 --- a/frontend/const/modelConfig.ts +++ b/frontend/const/modelConfig.ts @@ -46,6 +46,7 @@ export const MODEL_PROVIDER_KEYS = [ "jina", "deepseek", "aliyuncs", + "zhipu", ] as const; export type ModelProviderKey = (typeof MODEL_PROVIDER_KEYS)[number]; @@ -58,6 +59,7 @@ export const PROVIDER_HINTS: Record = { jina: "jina", deepseek: "deepseek", aliyuncs: "aliyuncs", + zhipu: "bigmodel", }; // Icon filenames for providers @@ -68,6 +70,7 @@ export const PROVIDER_ICON_MAP: Record = { jina: "/jina.png", deepseek: "/deepseek.png", aliyuncs: "/aliyuncs.png", + zhipu: "/zhipu.png", }; export const OFFICIAL_PROVIDER_ICON = "/modelengine-logo.png"; diff --git a/frontend/hooks/model/UseZhipuModelList.ts b/frontend/hooks/model/UseZhipuModelList.ts new file mode 100644 index 000000000..855b6f7b0 --- /dev/null +++ b/frontend/hooks/model/UseZhipuModelList.ts @@ -0,0 +1,108 @@ +import { useEffect } from 'react' +import { message } from 'antd' +import { useTranslation } from 'react-i18next' +import { modelService } from '@/services/modelService' +import { ModelType } from '@/types/modelConfig' +import log from "@/lib/logger"; + +interface UseZhipuModelListProps { + form: { + type: ModelType + isBatchImport: boolean + apiKey: string + provider: string + maxTokens: string + isMultimodal: boolean + } + setModelList: (models: any[]) => void + setSelectedModelIds: (ids: Set) => void + setShowModelList: (show: boolean) => void + setLoadingModelList: (loading: boolean) => void +} + +export const useZhipuModelList = ({ + form, + setModelList, + setSelectedModelIds, + setShowModelList, + setLoadingModelList +}: UseZhipuModelListProps) => { + const { t } = useTranslation() + + const getModelList = async () => { + setShowModelList(true) + setLoadingModelList(true) + const modelType = form.type === "embedding" && form.isMultimodal ? + "multi_embedding" as ModelType : + form.type + try { + const result = await modelService.addProviderModel({ + provider: form.provider, + type: modelType, + apiKey: form.apiKey.trim() === "" ? "sk-no-api-key" : form.apiKey, + baseUrl: + form.provider === "modelengine" && form.apiKey.trim() !== "" + ? (form as any).modelEngineUrl || "" + : undefined, + }) + // Ensure each model has a default max_tokens value + const modelsWithDefaults = result.map((model: any) => ({ + ...model, + max_tokens: model.max_tokens || parseInt(form.maxTokens) || 4096 + })) + setModelList(modelsWithDefaults) + if (!result || result.length === 0) { + message.error(t('model.dialog.error.noModelsFetched')) + } + const selectedModels = await getProviderSelectedModalList() || [] + // Key logic + if (!selectedModels.length) { + // Select none + setSelectedModelIds(new Set()) + } else { + // Only select selectedModels + setSelectedModelIds(new Set(selectedModels.map((m: any) => m.id))) + } + } catch (error) { + message.error(t('model.dialog.error.addFailed', { error })) + log.error(t('model.dialog.error.addFailedLog'), error) + } finally { + setLoadingModelList(false) + } + } + + const getProviderSelectedModalList = async () => { + const modelType = form.type === "embedding" && form.isMultimodal ? + "multi_embedding" as ModelType : + form.type + const result = await modelService.getProviderSelectedModalList({ + provider: form.provider, + type: modelType, + api_key: form.apiKey.trim() === "" ? "sk-no-api-key" : form.apiKey, + baseUrl: + form.provider === "modelengine" && form.apiKey.trim() !== "" + ? (form as any).modelEngineUrl || "" + : undefined, + }) + return result + } + + // Auto-fetch model list when batch import is enabled and API key is provided + useEffect(() => { + const requiresUrl = + form.provider === "modelengine" + ? ((form as any).modelEngineUrl || "").toString().trim() !== "" + : true; + + if (form.isBatchImport && form.apiKey.trim() !== "" && requiresUrl) { + getModelList() + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [form.type, form.isBatchImport]) + + return { + getModelList, + getProviderSelectedModalList + } +} + diff --git a/frontend/package.json b/frontend/package.json index 0a706bdf6..a6f7fd14a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,6 +25,7 @@ "bootstrap-icons": "^1.11.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "cross-env": "^10.1.0", "dicebear": "^9.2.2", "dotenv": "^16.4.7", "framer-motion": "^12.23.6", diff --git a/frontend/public/locales/en/common.json b/frontend/public/locales/en/common.json index 0023ab66f..a99092db1 100644 --- a/frontend/public/locales/en/common.json +++ b/frontend/public/locales/en/common.json @@ -656,6 +656,7 @@ "model.dialog.hint.batchImportEnabled": "Batch add enabled. Multiple models will be added at once.", "model.dialog.hint.batchImportDisabled": "Batch add disabled. Only a single model will be added.", "model.provider.silicon": "SiliconFlow", + "model.provider.zhipu": "Zhipu AI", "model.provider.modelengine": "ModelEngine", "model.dialog.modelList.title": "Show Models", "model.dialog.modelList.searchPlaceholder": "Search models by name", @@ -715,6 +716,7 @@ "model.error.deleteError": "Error deleting model:", "model.source.custom": "Custom", "model.source.modelEngine": "ModelEngine", + "model.source.zhipu": "Zhipu AI", "model.source.openai": "OpenAI", "model.source.silicon": "Silicon Flow", "model.source.unknown": "Unknown Source", @@ -723,6 +725,7 @@ "model.select.placeholder": "Select Model", "model.group.modelEngine": "ModelEngine Models", "model.group.silicon": "Silicon Flow Models", + "model.group.zhipu": "Zhipu AI Models", "model.group.custom": "Custom Models", "model.status.tooltip": "Click to verify connectivity", "model.dialog.embeddingConfig.title": "Edit Embedding Model: {{modelName}}", diff --git a/frontend/public/locales/zh/common.json b/frontend/public/locales/zh/common.json index c861c5fc4..e145e698c 100644 --- a/frontend/public/locales/zh/common.json +++ b/frontend/public/locales/zh/common.json @@ -659,6 +659,7 @@ "model.dialog.hint.batchImportDisabled": "批量添加模式已关闭,仅添加单个模型", "model.provider.silicon": "硅基流动", "model.provider.modelengine": "ModelEngine", + "model.provider.zhipu": "智谱清言", "model.dialog.modelList.title": "显示模型", "model.dialog.modelList.searchPlaceholder": "按名称搜索模型", "model.dialog.modelList.noResults": "没有匹配的模型", @@ -717,6 +718,7 @@ "model.source.modelEngine": "ModelEngine", "model.source.unknown": "未知来源", "model.source.openai": "OpenAI", + "model.source.zhipu": "智谱清言", "model.source.silicon": "硅基流动", "model.warning.updateNotFound": "未找到要更新的模型: {{displayName}}, 类型: {{type}}", "model.type.main": "大语言模型", @@ -724,6 +726,7 @@ "model.group.modelEngine": "ModelEngine模型", "model.group.silicon": "硅基流动模型", "model.group.custom": "自定义模型", + "model.group.zhipu": "智谱清言模型", "model.status.tooltip": "点击可验证连通性", "model.dialog.success.updateSuccess": "更新成功", "model.dialog.embeddingConfig.title": "修改向量模型: {{modelName}}", diff --git a/frontend/public/zhipu.png b/frontend/public/zhipu.png new file mode 100644 index 0000000000000000000000000000000000000000..4e37324561ae627280228be891f66aab7c2d18d1 GIT binary patch literal 1598 zcmXw(dpr{g8^`C8jEl(!<6IvUYjbL23W3F8cfLp7C7h~%=yiZ+SL z=ak%bL~}{G_hPgzR$Iej!!o3Dd0yUg&L7Y7{GQ+Qeg1j=c(U*wE@~>F!UNhDjD5fi59`{_ zcOv+s1(L5p-%B`=1xuenEQQ(*nEwPdPvAr*v^|ICuR%BkITaw0LTMeOGhkK*Lp*RK zf!}FpZ*VSMzp3siFAr~o2LBuil_%x5VjSWKjH?4oLK>btSp6{c$@5zXgkmA?prem} z2b-P}JZh_P3Hk4&Z*vDZ&iOUYCB-~bMYDSRo7&Ntw`}S1%9;To*3F|d@+ZGj_DY4p~jist|Y(7@SEkRAWFD&+SNUDf+v2W_n z-5j}$8g{;>ZD#2sLGnm@*{)u}qCOp)pci$!{|V2>GbLk}*1n!l9$K|C;DVXtXD3d` zha%K+435-uBm5p_KI-m{m*FYay+LyHyig^SH1C=so}b)(*{QflBB~k`{lQZ~PF1A_ zQ2b@(95zcG&5pkQ_}Wvu{r9Prp=rM{jd4zI6E9%{w|0abEXavYLW}6UJzYsO>~mk|D@q;P7A8oQ0cRA)s+L}Xsz7qGn$p3 z*?7ELj1P4%ae+(o|U0O zzK@s}QyWKquTmc#OSGmRgS2o5q@d=~+4sJNba=dVhjb^El}UNJ_%Jho<0~WM51U7_ z^zE68#tRf`J#wVLRv^SsG%4jbiWe}hO}bpTBg906Y-(mJ%5XbfQ}u7PYG+qxGPf+) z-aT?gx$n)^X0fGVratm}r&u8C{KVJM(Y4P>)J~9WbCKL?4SBW{SeeKuv?$9W1gO># zjs~jiohBXFx$Owo9ogu#Vt4yr$(On;MckIlCF;Y>_NG*4GZNwT#LQQ;*QqT>7pb7c z<(3hT`A6*K^{egZSZF6up4)$+qkqYm_Le(Nbe+*nAIds!afUH6PWxu}Srak&Qcc!Cly_v-=<+O0{GN0!QTdwFc zGl~fgn{}I?{b}_8J4aKKmz16NyFI5S&vL#qdj)B}qi}NEN?~Sz%@0=Q^)>|Syz^ZZ z#qzx6!>wQ6kqE}O?Vnmhj!~9ItF1N-yF{t8_FUf;8%*6?L0(Hqrcl-%EQ_>b(%&a( z>Y!1H8h-C5$g>z`xu~DZF@85oO-XTr*)7$Z8`X Date: Mon, 9 Feb 2026 18:41:14 +0800 Subject: [PATCH 13/13] New Requirement: Support for provider Zhipu AI Models (LLM and Embedding) --- backend/consts/provider.py | 1 - docker/init.sql | 2 +- .../app/[locale]/models/components/model/ModelAddDialog.tsx | 6 +++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/backend/consts/provider.py b/backend/consts/provider.py index 3f2224358..ea0ff6345 100644 --- a/backend/consts/provider.py +++ b/backend/consts/provider.py @@ -6,7 +6,6 @@ class ProviderEnum(str, Enum): SILICON = "silicon" OPENAI = "openai" MODELENGINE = "modelengine" - ANTHROPIC = "anthropic" ZHIPU = "zhipu" diff --git a/docker/init.sql b/docker/init.sql index 7d31c8a93..c547bd07b 100644 --- a/docker/init.sql +++ b/docker/init.sql @@ -807,7 +807,7 @@ COMMENT ON COLUMN nexent.role_permission_t.permission_type IS 'Permission type'; COMMENT ON COLUMN nexent.role_permission_t.permission_subtype IS 'Permission subtype'; -- Add primary key constraint for role_permission_t table --- ALTER TABLE nexent.role_permission_t ADD CONSTRAINT role_permission_t_pkey PRIMARY KEY (role_permission_id); +ALTER TABLE nexent.role_permission_t ADD CONSTRAINT role_permission_t_pkey PRIMARY KEY (role_permission_id); -- Insert role permission data with conflict handling diff --git a/frontend/app/[locale]/models/components/model/ModelAddDialog.tsx b/frontend/app/[locale]/models/components/model/ModelAddDialog.tsx index ae3f79acb..e70197d6d 100644 --- a/frontend/app/[locale]/models/components/model/ModelAddDialog.tsx +++ b/frontend/app/[locale]/models/components/model/ModelAddDialog.tsx @@ -737,13 +737,13 @@ export const ModelAddDialog = ({ {t("model.type.embedding")} - - -