From feb1319fb30da390cd5001c266c42fd087174e8c Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 19 Apr 2026 10:35:23 +0700 Subject: [PATCH] 690419:1035 feat: update CI/CD to use SSH key authentication --- .gitea/workflows/ci-deploy.yml | 15 ++ .../LCBP3 RAG Implementation Guide v1.1.0.md | 97 ++++++++ .../LCBP3 RAG Implementation Guide v1.1.1.md | 215 ++++++++++++++++++ .../LCBP3_RAG_Implementation_Guide.docx | Bin 0 -> 20347 bytes 4 files changed, 327 insertions(+) create mode 100644 specs/06-Decision-Records/ADR-022-/LCBP3 RAG Implementation Guide v1.1.0.md create mode 100644 specs/06-Decision-Records/ADR-022-/LCBP3 RAG Implementation Guide v1.1.1.md create mode 100644 specs/06-Decision-Records/ADR-022-/LCBP3_RAG_Implementation_Guide.docx diff --git a/.gitea/workflows/ci-deploy.yml b/.gitea/workflows/ci-deploy.yml index 46b9790..814ae44 100644 --- a/.gitea/workflows/ci-deploy.yml +++ b/.gitea/workflows/ci-deploy.yml @@ -79,6 +79,11 @@ jobs: chmod 600 ~/.ssh/id_rsa ssh-keyscan -p ${{ secrets.PORT }} ${{ secrets.HOST }} >> ~/.ssh/known_hosts + # Debug: Check SSH key + echo "SSH key file exists: $(test -f ~/.ssh/id_rsa && echo 'YES' || echo 'NO')" + echo "SSH key permissions: $(ls -la ~/.ssh/id_rsa)" + echo "SSH key first line: $(head -1 ~/.ssh/id_rsa)" + # Create remote deployment script REMOTE_SCRIPT=$(cat << 'SCRIPT_EOF' set -e @@ -131,6 +136,16 @@ jobs: while [ $attempt -le $max_attempts ]; do echo " Deployment attempt $attempt/$max_attempts..." + # Debug: Test SSH connection first + echo "Testing SSH connection..." + ssh -o StrictHostKeyChecking=no \ + -o ConnectTimeout=10 \ + -o BatchMode=yes \ + -o PasswordAuthentication=no \ + -o LogLevel=DEBUG3 \ + -i ~/.ssh/id_rsa \ + -p ${{ secrets.PORT }} ${{ secrets.USERNAME }}@${{ secrets.HOST }} 'echo "SSH auth successful"' + if echo "$REMOTE_SCRIPT" | ssh -o StrictHostKeyChecking=no \ -o ConnectTimeout=60 \ -o ServerAliveInterval=30 \ diff --git a/specs/06-Decision-Records/ADR-022-/LCBP3 RAG Implementation Guide v1.1.0.md b/specs/06-Decision-Records/ADR-022-/LCBP3 RAG Implementation Guide v1.1.0.md new file mode 100644 index 0000000..e07efd2 --- /dev/null +++ b/specs/06-Decision-Records/ADR-022-/LCBP3 RAG Implementation Guide v1.1.0.md @@ -0,0 +1,97 @@ +นี่คือร่างเนื้อหาฉบับปรับปรุงของ **LCBP3 RAG Implementation Guide (v1.1.0)** ในรูปแบบ Markdown โดยเน้นการยกระดับความปลอดภัย (Security), การรองรับหลายโครงการ (Multi-tenancy), และความถูกต้องของคำตอบ (Truthfulness) ตามมาตรฐานระบบ LCBP3 DMS + +--- + +# 📄 LCBP3 DMS: RAG Implementation Guide +**Retrieval-Augmented Generation for Document Management System** + +| Version | Date | Status | Updated By | +| :--- | :--- | :--- | :--- | +| 1.1.0 | 2026-04-19 | Proposed | Gemini (Senior Developer) | + +--- + +## 1. ภาพรวม Architecture (Multi-tenant Hybrid) +ระบบ RAG ออกแบบมาเพื่อทำงานร่วมกับโครงสร้างข้อมูลเดิมของ LCBP3 โดยมีการแยกส่วนการประมวลผลตามระดับความปลอดภัยของข้อมูล + +### 1.1 Ingestion Pipeline +1. **Trigger:** ไฟล์ถูก Commit เข้าสู่ Permanent Storage (ตาม ADR-016) +2. **OCR Service:** ใช้ EasyOCR/Tesseract ประมวลผล PDF/DWG (ในกรณีที่ไฟล์ไม่มี text layer) +3. **Data Enrichment:** ดึง Metadata จาก MariaDB (Project ID, Doc Type, Security Level) แนบไปกับข้อมูลดิบ +4. **Chunking:** แบ่งส่วนข้อความตามกลยุทธ์ที่กำหนด (ดูหัวข้อที่ 2) +5. **Local Embedding:** ส่ง Chunk ไปยัง **Ollama (nomic-embed-text)** ภายใน Intranet +6. **Vector Store:** บันทึก Vector + Metadata ลงใน **Qdrant** โดยแยก `collection` หรือใช้ `payload filter` ตาม Project ID + +### 1.2 Query & Generation +1. **Secure Filter:** ระบบ DMS API รับคำถามและตรวจสอบสิทธิ์ (RBAC) ของผู้ใช้ +2. **Similarity Search:** ค้นหาใน Qdrant โดยบังคับใส่ `project_public_id` ใน Filter เสมอ +3. **Context Selection:** เลือกเฉพาะ Top-K chunks ที่มีคะแนนความมั่นใจ (Confidence) > 0.6 +4. **Hybrid Generation:** + * *ข้อมูลปกติ:* ส่ง Context + Prompt ไปยัง **Typhoon API (Cloud)** เพื่อคุณภาพภาษาไทยสูงสุด + * *ข้อมูลลับ (Confidential):* ส่งประมวลผลผ่าน **Ollama (Local LLM)** ภายในเครื่อง Admin เท่านั้น (ตาม ADR-018) + +--- + +## 2. Chunking Strategy (Domain-Specific) +ห้ามใช้ Fixed-size chunking เพียงอย่างเดียว ให้ใช้กลยุทธ์ตามประเภทเอกสาร (Document Type): + +| ประเภทเอกสาร | กลยุทธ์การ Chunk | ข้อมูลที่ต้องแนบใน Metadata | +| :--- | :--- | :--- | +| **Correspondence (CORR)** | Recursive Character Splitter (1000 chars, 10% overlap) | Sender, Receiver, Ref No., Subject | +| **RFA / Transmittal** | Table-aware Chunking (เน้นดึงตารางรายการไฟล์แนบ) | RFA ID, Status, Due Date | +| **Drawing (Shop/As-built)** | Title Block Extraction + Metadata Enrichment | Drawing No., Revision, Discipline | + +--- + +## 3. มาตรฐานการพัฒนา (Technical Specification) + +### 3.1 Vector Payload Interface (NestJS) +```typescript +interface VectorMetadata { + public_id: string; // UUIDv7 ของเอกสาร + project_public_id: string; // ✅ บังคับ เพื่อความปลอดภัย + doc_type: string; // CORR, RFA, DRAWING + security_level: number; // 1: Public, 2: Internal, 3: Confidential + content_preview: string; // ข้อความสั้นๆ สำหรับแสดงผล +} +``` + +### 3.2 Ingestion Status (MariaDB Update) +เพิ่มฟิลด์ในตาราง `attachments` เพื่อติดตามสถานะ: +```sql +ALTER TABLE attachments +ADD COLUMN rag_status ENUM('PENDING', 'PROCESSING', 'INDEXED', 'FAILED') DEFAULT 'PENDING', +ADD COLUMN rag_last_error TEXT NULL; +``` + +--- + +## 4. ความปลอดภัยและการควบคุม (Security Audit Protocol) + +### 4.1 Data Isolation (Non-negotiable) +* **Tenant Separation:** ทุกการค้นหาต้องมีการทำ Payload filtering บน Qdrant ด้วย `project_public_id` เพื่อป้องกันพนักงานโครงการ A เห็นข้อมูลโครงการ B +* **RBAC Check:** DMS API ต้องเรียก `CaslGuard` ก่อนทำการค้นหา Vector เสมอ + +### 4.2 AI Truthfulness & Anti-Hallucination +* **Citation:** Prompt ต้องบังคับให้ AI อ้างอิงหมายเลขเอกสาร (`doc_number`) ทุกครั้งที่ตอบ +* **Fallback:** หาก Similarity Search ได้ผลลัพธ์ที่คะแนนต่ำกว่าเกณฑ์ ให้ตอบว่า *"ไม่พบข้อมูลที่ระบุในฐานข้อมูลเอกสารปัจจุบัน"* ห้ามให้ AI คาดเดาเอง + +--- + +## 5. ลำดับการ Rollout (Updated Phase) + +* **Phase 1: Infra (2 วัน):** Docker Qdrant + Redis + Ollama Setup +* **Phase 2: Core Services (3 วัน):** สร้าง `EmbeddingService` และ `QdrantService` (Strict Type) +* **Phase 3: Auto-Ingestion (3 วัน):** เชื่อม BullMQ เข้ากับไฟล์อัปโหลดเดิมของ DMS +* **Phase 4: RAG API (2 วัน):** สร้าง API ค้นหาพร้อมระบบ Citation +* **Phase 5: UI/UX (3 วัน):** หน้าจอ Search ผลลัพธ์แบบ AI พร้อมปุ่มเปิดไฟล์ต้นฉบับ + +--- + +## 6. รายการตรวจสอบ (Security Checklist ก่อน Go-live) +- [ ] ข้อมูล Confidential ไม่ถูกส่งไปยัง Typhoon API (Cloud) +- [ ] มีการบันทึก `audit_logs` ทุกการ Query ของ AI (ใครถาม, ถามอะไร, ระบบตอบอะไร) +- [ ] ฟังก์ชันการลบเอกสารใน DMS มีการสั่งลบ Vector ใน Qdrant ออกด้วย (Consistency) +- [ ] ทดสอบ Cross-project search แล้วต้องไม่พบข้อมูลข้ามโครงการ + +--- diff --git a/specs/06-Decision-Records/ADR-022-/LCBP3 RAG Implementation Guide v1.1.1.md b/specs/06-Decision-Records/ADR-022-/LCBP3 RAG Implementation Guide v1.1.1.md new file mode 100644 index 0000000..5192644 --- /dev/null +++ b/specs/06-Decision-Records/ADR-022-/LCBP3 RAG Implementation Guide v1.1.1.md @@ -0,0 +1,215 @@ +# 📋 Review: LCBP3 DMS RAG Implementation Guide (v1.1.0) + +--- + +## 🎯 จุดแข็งที่โดดเด่น + +| ด้าน | สิ่งที่ทำได้ดี | +|------|---------------| +| **Security-by-Design** | แยก Hybrid Generation ตาม Security Level + บังคับ `project_public_id` filter ในทุก Query | +| **Domain-Aware Chunking** | กลยุทธ์แยกตาม Document Type (CORR/RFA/Drawing) เหมาะสมกับงานก่อสร้าง | +| **Data Consistency** | เพิ่ม `rag_status` ใน MariaDB ติดตามสถานะ + มีแผนลบ Vector เมื่อลบเอกสาร | +| **Anti-Hallucination** | บังคับ Citation + Fallback message เมื่อคะแนนต่ำ ป้องกันการคาดเดา | + +--- + +## 🔧 ข้อเสนอแนะปรับปรุง (แบ่งตามหัวข้อ) + +### 1. Architecture & Retrieval Strategy + +#### ⚠️ ปัญหาที่อาจเกิด: +- การใช้ **Vector-only search** อาจพลาด Keyword ที่สำคัญ เช่น เลขที่เอกสาร `REF-2026-001` หรือรหัส Drawing `DWG-STR-001` + +#### ✅ ข้อเสนอแนะ: +```typescript +// เพิ่ม Hybrid Search: BM25 + Vector + Reranking +interface SearchConfig { + vector_weight: number; // 0.7 + keyword_weight: number; // 0.3 + use_rrf_fusion: boolean; // ✅ แนะนำให้เปิดใช้ Reciprocal Rank Fusion [[3]] + rerank_top_k: number; // 50 → rerank → 10 +} +``` + +**เหตุผล**: Hybrid retrieval ช่วยเพิ่มความแม่นยำทั้งเชิงความหมายและเชิงคำศัพท์ โดยเฉพาะกับเอกสารเทคนิคที่มีรหัสเฉพาะ [[1]][[4]] + +#### 🔄 ปรับ Ingestion Pipeline: +``` +เดิม: OCR → Chunk → Embed → Store +ใหม่: OCR → [Metadata Extraction] → Chunk → [Add Parent-Child Relationship] → Embed → Store +``` +- เพิ่ม **Parent-Child Chunking**: เก็บ Chunk เล็กสำหรับ Search แต่อ้างอิงกลับไปยัง Document Section เต็มสำหรับ Generation [[31]] +- ดึง Metadata เพิ่ม: `doc_number`, `revision`, `effective_date` สำหรับ Filtering แบบละเอียด + +--- + +### 2. Qdrant Multi-tenant Configuration + +#### ⚠️ ปัญหา: +การใช้ `payload filter` อย่างเดียวอาจมี **ประสิทธิภาพลดลง** เมื่อข้อมูลโตขึ้น [[12]] + +#### ✅ ข้อเสนอแนะ: +```typescript +// ใช้ Tiered Multitenancy + Payload Indexing (Qdrant v1.16+) [[10]][[13]] +await client.createCollection("lcbp3_vectors", { + vectors: { size: 768, distance: "Cosine" }, + sharding_method: "custom", // ✅ เปิดใช้ Custom Sharding + hnsw_config: { + payload_m: 16, // ✅ สร้าง Index แยกตาม Tenant + m: 0 // ปิด Global Index เพื่อลด Overhead + } +}); + +// สร้าง Payload Index สำหรับ project_public_id +await client.createPayloadIndex("lcbp3_vectors", { + field_name: "project_public_id", + field_schema: { type: "keyword", is_tenant: true } // ✅ is_tenant=true ช่วยจัดกลุ่มข้อมูล +}); +``` + +**ประโยชน์**: +- ลด Noisy Neighbor ระหว่างโครงการ +- Query เร็วขึ้น 3-5x เมื่อ Filter ด้วย `project_public_id` [[16]] + +--- + +### 3. Thai Language Optimization + +#### ⚠️ ปัญหา: +`nomic-embed-text` ทำงานดีกับภาษาอังกฤษ แต่อาจไม่เหมาะกับ **ภาษาไทยที่มีโครงสร้างพิเศษ** เช่น เอกสารกฎหมาย/ก่อสร้าง [[36]][[37]] + +#### ✅ ข้อเสนอแนะ: +```python +# 1. ใช้ Thai-specific Preprocessing ก่อน Embedding +def preprocess_thai_legal(text: str) -> str: + # ตัดคำไทยด้วย PyThaiNLP + รักษาโครงสร้างเลขมาตรา + # ลบ Noise เช่น "หน้า 1/3", "ลงชื่อ__________" + # แยก Section Header ออกจาก Content + return cleaned_text + +# 2. พิจารณา Fine-tune Embedding Model (ถ้ามีข้อมูลเพียงพอ) +# ใช้ WangchanX-Legal หรือสร้าง Dataset จากเอกสาร LCBP3 ที่ผ่านการทำ Label แล้ว [[37]] + +# 3. เพิ่ม Query Rewriting สำหรับภาษาไทย +def rewrite_thai_query(user_query: str) -> List[str]: + # ขยายคำย่อ: "รฟม." → ["การรถไฟฟ้าขนส่งมวลชนแห่งประเทศไทย", "รฟม."] + # แปลงเลขไทย: "มาตรา ๑๐" → ["มาตรา 10", "ม.10"] + # เพิ่ม Synonym: "แบบก่อสร้าง" → ["Shop Drawing", "As-built", "แบบขยาย"] + return [user_query, *expanded_queries] +``` + +--- + +### 4. Anti-Hallucination & Citation Enforcement + +#### ✅ เสริมจากที่มีอยู่: +```typescript +// 1. เพิ่ม Verification Layer ก่อนส่งคำตอบให้ผู้ใช้ +interface VerificationStep { + check_citation_exists: boolean; // ตรวจสอบว่า doc_number ที่อ้างถึงมีจริงในระบบ + check_security_level: boolean; // ตรวจสอบว่าผู้ใช้มีสิทธิ์เห็นเอกสารที่อ้างถึง + confidence_threshold: number; // ถ้าคะแนนรวม < 0.7 → ใช้ Fallback Message +} + +// 2. ใช้ Structured Output เพื่อบังคับรูปแบบคำตอบ +const rag_prompt = ` +คุณเป็นผู้ช่วยด้านเอกสารโครงการ ลCBP3 +กฎ: +1. ตอบเฉพาะจากข้อมูลที่ให้มาเท่านั้น +2. ทุกข้อเท็จจริงต้องอ้างถึง [doc_number: xxx] +3. ถ้าไม่แน่ใจ ให้ตอบว่า "ไม่พบข้อมูลที่ระบุ" +4. ห้ามคาดเดาหรือใช้ความรู้ภายนอก + +รูปแบบคำตอบ (JSON): +{ + "answer": "ข้อความตอบ...", + "citations": [{"doc_number": "...", "page": "...", "snippet": "..."}], + "confidence": 0.85, + "fallback_used": false +} +`; +``` + +**เหตุผล**: การบังคับ Structured Output + Verification Layer ลดความเสี่ยงการให้ข้อมูลผิดพลาดได้ถึง 80% [[39]][[44]] + +--- + +### 5. Operational & Monitoring + +#### ✅ เพิ่มสิ่งที่ขาด: +```yaml +# monitoring-config.yaml +rag_metrics: + - query_latency_p95: "<2s" + - retrieval_recall_at_5: ">0.85" + - citation_accuracy: ">0.95" + - fallback_rate: "<15%" + +alerting: + - condition: "fallback_rate > 30% ใน 1 ชั่วโมง" + action: "แจ้งทีม Dev + ลด Traffic ไป Cloud LLM ชั่วคราว" + + - condition: "Cross-project query detected" + action: "บล็อกทันที + บันทึก Security Audit Log" + +# Audit Log Schema +audit_log: { + timestamp, + user_id, + project_id, + query_hash, // ไม่เก็บข้อความคำถามตรงๆ เพื่อความเป็นส่วนตัว + retrieved_docs: ["doc_id_1", ...], + llm_provider: "typhoon-cloud" | "ollama-local", + response_hash, + security_level_accessed: 1|2|3 +} +``` + +--- + +### 6. Rollout Phase Adjustments + +| Phase | ข้อเสนอแนะเพิ่มเติม | +|-------|-------------------| +| **Phase 1** | เพิ่ม Load Test สำหรับ Qdrant ด้วยข้อมูลจำลอง 100K vectors [[1]] | +| **Phase 2** | สร้าง Unit Test สำหรับ `EmbeddingService` ด้วย Mock Thai text cases | +| **Phase 3** | เพิ่ม Dead Letter Queue ใน BullMQ สำหรับไฟล์ที่ Process Failed > 3 ครั้ง | +| **Phase 4** | ทำ A/B Testing: Vector-only vs Hybrid Search วัดความพึงพอใจผู้ใช้ | +| **Phase 5** | เพิ่มปุ่ม "ช่วยปรับปรุงคำตอบ" เพื่อเก็บ Feedback สำหรับ Fine-tuning | + +--- + +### 7. Security Checklist เพิ่มเติม + +```diff + [ ] ข้อมูล Confidential ไม่ถูกส่งไปยัง Typhoon API (Cloud) + [ ] มีการบันทึก audit_logs ทุกการ Query ของ AI + [ ] ฟังก์ชันการลบเอกสารใน DMS มีการสั่งลบ Vector ใน Qdrant ออกด้วย + [ ] ทดสอบ Cross-project search แล้วต้องไม่พบข้อมูลข้ามโครงการ ++ [ ] ทดสอบ Privilege Escalation: ผู้ใช้ Level 1 พยายาม Query ข้อมูล Level 3 ++ [ ] ทดสอบ Prompt Injection: ใส่คำสั่งในคำถามเพื่อพยายามให้ AI ข้ามกฎ Citation ++ [ ] ทดสอบ Rate Limiting: ป้องกันการ Query จำนวนมากเพื่อ Extract ข้อมูลทั้งระบบ ++ [ ] มีแผน Disaster Recovery: Backup Qdrant + Restore Procedure ทดสอบทุกไตรมาส +``` + +--- + +## 📊 สรุปคำแนะนำเร่งด่วน (Priority Order) + +```mermaid +graph LR + A[High Priority] --> B[Hybrid Search + RRF] + A --> C[Qdrant Tiered Multitenancy] + A --> D[Thai Query Preprocessing] + + E[Medium Priority] --> F[Parent-Child Chunking] + E --> G[Structured Output + Verification] + E --> H[Monitoring Dashboard] + + I[Low Priority] --> J[Fine-tune Thai Embedding] + I --> K[Feedback Loop for Continuous Learning] +``` + +--- + +> 💡 **ข้อคิดสุดท้าย**: ระบบ RAG ที่ดีไม่ใช่แค่ "ตอบได้" แต่ต้อง "ตอบถูกต้อง อ้างอิงได้ และปลอดภัย" [[5]][[7]] เอกสารฉบับนี้มีพื้นฐานดีมากแล้ว การเพิ่มชั้นของ Verification, Monitoring และ Thai-specific optimization จะทำให้ระบบพร้อมสำหรับ Production จริงในอุตสาหกรรมก่อสร้างที่มีความซับซ้อนสูง diff --git a/specs/06-Decision-Records/ADR-022-/LCBP3_RAG_Implementation_Guide.docx b/specs/06-Decision-Records/ADR-022-/LCBP3_RAG_Implementation_Guide.docx new file mode 100644 index 0000000000000000000000000000000000000000..5f5da2198e91c6bc7d6a1f173c4c05be5e2e1480 GIT binary patch literal 20347 zcmd43WppG<(j}N;W@g3`Gcz+YGqY4uiJ6&IVrHfiGcz+&iK)b}dfnga)7`VXXa3D( zobb$u^z`FtcHQi{yICkmgMdN<{(AYtCF=a+!~YauU+>@TolNKz{y(e0{9Q%g$<)UA zUlk$$(U!(IoIL^%06_HB5bl3gG_f~!wKcVKp>wyjq5JEnRY{X_{S1gf`ee6R98?O> z=E7{MDS{|M6YQ{HUQwUH zn~b-!9h+4nZVf)6@y4yYue~qCJhR#H__JLKr=kcEuX7qRyM?TBj<9pC3r;tq+_{nE zT1pt^ac2`o6j+Yjnu+9!{a+V62SEVZPlgFO=v~G$I)G7{X9pYwMR4szIAPQa zZv>(lMeubJN*)AVuP%UGx8z0rR}151j!XR~r+xQO$dz~)lH3xkV9iI{B*Nbk|ED1R zzSXU5Pyzr*)F1$)zXkd4BE0bSv|m?izWO{?KHrB2XBtBOb4zmSuB4fwEdL%+=^_^o zm1*mwZ6p*AE2*g%2%C|;L#~_|39}(tO!3=bs!&iN6C8-k(o^h%tCp}iqsr&)>K&W&)Drm)2)`5CHN}* z5?Un|mu9vlvggsQz0c+dRftXv(xxCQXN%q}9L$yV{i_&tBzBp{0)z4@mI%f2g-(A` zs(E>g@e%20N=0GFg@|l2Z9f})W{}MS>HdyDa`*xRji?lbvgF59BW(H#TW13B5<=aD ztU6BSBty7dHxEN4w%dt#1@U67YrEah?{jju1#ea5Eb=VwUpunKG}8;TyvK4#kMv=1 zqv0@4pY9};4Bg*CD%(!3^^<7wXRR4r+RHPt)-he#UQ8E%9$Xjx43NobAM+&scXuVA|mmw2Y2$J26g>;7M?EbAQ30LvsI8;2K7-nPP?Kio^qr8FI zRy2n?O@W=8new)6v+H{^KgRyE^28zXuh*sX@9k-u)NJ1HNmn61C%i9Lyfh`NjmC+- zb2}Hx@s4)5NNQncQu6kR+=I`T^_DS}WLpUusk1UDj+pw z^1;-5t;a&#^8RGQ&UAsB{gGPGog%yafWw7-s}w{{ZE zG)~h4V(ky?M(U-y~}?z-#quu{IWmKl-rcazIC@IS^((YuR7yInDkcFTp%hHUe8 zO3xFs)xnQW*t0=@Z^@gv*jHkQl&*wVKV7Z5K8bkj zfUksN(*;l468bxe)$RqJ58~-M=J4abpUVx2+TxPD0xyVhWv)G`i1+~)rY(59gx(3D zy93+_nWA&Fr1i&WvUinpq)1Ul_j5c(F+Oua{eX(~q0TjiXo?Ao5j#ancqP z@**A?gAKsu#Q_&8b+QWJEFcbpPfmj#Rw23&<1K>p0Ej3w2$2em=CF%5H;i{^+xT|5 zy%gDPMNHL>Hlb}@Rhr5i11kRjz=Qktxnnl8k+Ct#0tnBi@t-&G3j8tI1}jXiv8zgD z@7gNM)(}M*cB^t+iYD*;0lac{v(R$Lx{V#JQ@p z&CBf9q>OJ7XnRoK)rmHTUBkPP9@`HTC$cP7s11k2uR6zDcUXVR{D|Az(+IO5vTFHQ zvg@>M`B<~-v}x(GZqdu_AX8Tj9g*9_HjQW91lgW5agYUs{C2=}+VHVx$)5iVt5R*z z)^FCfU#k)y(Z3ac1H6Ccdfy9VuJOG*x}CYcp2S`(Enh6f-n+>>qU%QI~p) zlz7hBd5?ELr%VbC*P(olh|kROx5VOqHP)oPP?0Go<2b-HePp%)=&L*mi?dU z*u5#{kAae2F=M>HQnX}_r)Nm@=A*>mFDk1gE7pU3g_mU}d!U6r-}FB*@-Bp+1|wGN z=Gc|eS6m=dvNRvpnOKt*^R$-jnePYcjKm+I&$vRtE3F?@kfH^1lmsR1?Nhs=3?lx- zQFC838Z|F3a@A#QS~QTbwOIUc*i^MH520PO%-0>ObXt7>QB-XOy;c{M@!LJ<{5E2P zWP&okWtniv(mT(gtgcKi6@+Eq-FgVc`D%zo-d;g&2p6)6$=qw1x(#22j(XKYu*&D{xo?|8^u8Bgb$z3FF-OY?8Yns=F4L284#0 zmS#R2ylc0&m*fSX1MKTC^;6b!R=rKB5%lWi=d*3my5d$f(c&m+sE5yVzNCwK9EZ?o z7>zof0mX%@3wwg+Sy~O2#GPRC2>i*+#ZR`3?w>OxfRe?T+BzCxP!v6ZGuYGwwi9i6 z0B4uZYuVxhJ*5l)2Qog-XC4vGj=o=!l`tw3?)xm6`eb%6^YbOo@*NsX$4Y1f_`p6f z?oUb0GL6($sTmac<2Vay8ZXA#qri;b*VmQjBpHCo02i--nIhZM56N$Md+c5g?o7cw zG4}8zPVwyT4ZF-Wv1=L{IhcwalRKCetDyb4(g%3jnvesPm}#XCY)VZ(t^)`9$%4bq z4HHJfNJ}VMi62&a4-JN{uB?bCsZaVk7>SuvI2aYHyt~-mfZf@cd;mU8 zwVpwKQeO$5K=Mf%psj#bG8rWLuqq8&y$Lkgn8VvDyN%Yoc4{@DARG3S0X?L{K44*# zn6)ba^P9QAe-%<_aoSN4TyH*{)C>z^M=00k#mVv;q|CGAsrX8V-=~$kTD^eLR~v7k z=qX90Mmr9ge&j%)FM%zCV_ME(S?cKg?ATl|Rcow=*Ea7NOc#-hNa0sI&1m*OdxuUA z%g>IZ0;u7*vtuNQ8o#75E%rjcW`HGn4L)d^h z(b{h3b#-sYYav6fp?G4xvLP*B;@dm!y#ImCduxVqMR2{-&phyo{f@wWuzc%)0~h|g zJAZ%H|3@mNqxO3y;c7vvI_|N#-uXVa@6cAZX#T`*qQI^2g?DKu!c94Nk{2Gz*$L>T z#}Sx8D3y4a6i{~*celtmQMM>lH5&s2gShV*x><06u2md}C*bS2r(niMmhLB~$rm1R zo5M2Qem#8b2-91kOFo)8dLZZcR&a+zlNTG>$LV~zlE<%FSF0I)W&D%UASrr+q&9@F zisv@;*#wz$$ks`T6?zAuc94$JcLL!U-a*?>l{`>&Xwa6bs%koqc4Zw>Z(O8av2mhK z+9aiv%nKd0{Y6@bnSWwBz?F@u#_y4-s^c~k)}7uU0mv73m;mcq&rh{D_^Sm^P1-|W z_E5K)PESuY2YtWTV%bA?@6LVI00bg=*ba1qc%T|GI6as&qaK3c8wd{C9;*31s{Or2 z)aI74BCkB2(4`i>O+9+lUJtCSoF0#KrAg(XSM2b8aK1pFEsSL*km)aQ?jvYk>-6A* zd~n3@*YC6eDr8_Pq9V_f)~Es-n7APP8<>j5%+!@VrY}RvzlnjI*Trjsz9n0l#`Dwo zbpwlGUJpCI#Y6Yv@6-ZnWWZ~pBKwu-4qM!MO|h~; zw&||5{p7(Pn}Sxp!@dDEuYeuKPIzgw1iy3Ia=sRsu&d0aV+<|9b-tEe@)Vz!$%PoS zY)L(pxgd52KgZ+S!7v+iSQ|@6&r)lDkEf{&I~S#h3WLRE6cGWB;nWlXhXq3EGrc`e z8y)eU7RF0TqYHhMoN#ecFnXz?3325>75&_<9|BZL_E>MBKht?&1Bbg;)HMe~V9n z>GedYvU?OumJ*yc&q>-(2Eu z6a5ILUeZuU@R8iU7T?D*lGi6)f@itH(v-^axXYFa;A7DLk)@S=6M78idndpnYSC$C z74%5CBWs#{UGh75IsPbm`I)S>W&F4HtB5(M@b|QaMn4P??k*ZynvO)n4);?;mmG7a zANu5|L?FYNGGl&36sv<-^YnhYUiC*;=~tbR8$0C(zl#9U22@ESvYpm`lg9Nhm3x9Pa`{3e41 znST7dZ3Bdp)yLQ$m^Gwme$LdmQxhSt-vTqZ@g~qXR7{OXT1s;JW~0V|Cq){H^MEK0 z;aWapTFqB)sHeu9M?z|mp%HVFk*OZuohgDxHN zzyRXl3_@0L>Jn3;T24UAwZiAQ0Pr3kvD#PLnMW6$f+y?SuJmx2C!og@2X?seI>B6# zFa{yV`*Cj9{$~fG#LB2N-dAc*{AA786no2TRMZd0YE|`44QG>MyD+IGr3F9jX<{`X} zN1RV-a1kR&^`s}ppb-W8#iQ^ZC*)#2MXXscjv8cSXb^Yi-Ow5)V7S7~zY|s~E zVj9Fb(jb)5Gp(;n>W`g=cSD$3r1i5kj;Ttk8Z}zWnCJP99cTA1kf5+AMC62;TgIQXUqzG%#mmrLY_O9$EV^rtHPSJFO0*Q+mA)l5weYjJ0Fcl6E>Iry# zo{&F48U%iS6=^*q$4NB^CI;R+14OlafHRQZpVR8$k}km~^=qs6ouW3!ErP))UoNY?zghiZk#&t1|xLgpkVJ01@J1P$~Jg@I%7z zoIA1|l`ohrwv;Z3#d6(gy>d&g&XEEv!ClZHMF;AOaQ5a~DS}4V@@2O>-oz&+IyqlX zt0~8;ugvPsIm%+cV)Z=jJ`jS)XOF&bknAQBr)e{pG&amhEw|lFw*b{ zQlmc(euAKq8+f9@b4{wvJEFftSb@1sfElNPFuej{7SX*I5C>|lSDXf@VA-VLQwXEe zl;KdrBZxE9xb-|7!d2}uRQqQXea!Jj5YezGaaE+1cN24qD`afecgT|o`=xZ}*=q7b z3>CNhMe#Kb{!ye4UH?gl_h=)M;c){?9$QJMX7Nw%G1En~0RJ1(*(Cc^u zj=C`U3`Ae|6jAfdYgF<&q=v<7*zzX7q~(?<9*<-MlQ##A=$cvVhMAO#K?uxFm&L)i zv3fh-rZ2*I&>%-ZgfOwa5|TTC)n*-J4R{k|r2twpE#=3E8X8Rin(%Ulg{Lt|clvg_ z+M2-l2%Ir#m`~b?7tlgj1UAK6yVq(}F24c`XY!a?{T_E|2?3HNV7V0E!-m~e6O)C} zZ2lc*;3x2?3mr=?zSd-+7)l^+PYmk$YXiU`2(XQyID@c*ho$!iF!+&-FNxV=9;@-9O-#(vfeAV+2xC3fzmncT7$AA{^)%bspzknz(^>V zL|PlB+;R^O1~?z-=|Y$h1G#W8AgVyDhbF3ExQ85}#?A36qnf7H;oyUUsD}=9fHFbT zo2V43yMj@I77jRGj564~r1YWRJm)u=$3Tvg3OgmoJDVW-d7G${B@8_qh636Mx*A}7 zhAJ_)b0q1|L#XOtBzP%_cCH8{QI(FpTjf5}Ocw!Nbyf~y2{n6+5RpH{nMw%u0cB)y zoZ76pvb92qK6bXQZLz8wzj)xy+)#p94>#%`hs)vL`eW2zER`m9GJqx42`}jQ3Cd6o z3`(2mJmn-#8O1h2aC6RySMpI^UHZ9-X?lpC56J7w0}8akky6UAbr}8nIZlwj?iz`z zAwtcoihBv<|bDlLGAFqinD09-WQ2C1B} zElFg%0l{;bm>kL}73Z0a`fL7hFtgV;hpR*>Y@kcd>1&@{bqe|*n>C*Tj`*x71`E)+ z)}nyb>S0|QgpF50QAVqo>CLRbbRPNU#1Ja8u>dP0PldEvi>e0H%Z+s=Yc>=Jg;jQd z&qAo%=D+IRg&tv9de7!`^1@q4jbHHu8*sS|fI&*(AxF_;Fzg9Rr_|v^5jy}G2A@P9 zX5bebxA1{iw4pLd?e+7Re${NJ#Z0v^=*_GF+s~i@I3*EUTgjTLDwG0%3rR$^Bpxzf zF?7LikX$!9)LMQQbaqZRqmz~rmMj|#gT6I{W3w68owZ0NzKCg5B;qt&G7%J>ippXH zah$WBkEk}6_TGe&MUFUj^TPzE5$mA~eX$KRr`%H!ph}X#wmhyyUjD5!4Od`4VG(Pl z-QX~Ekw$W8b^3fVx8@oab+}(s53$wX7zcgN)JY-KkG)biKvfA1{$%sKc~&2LyyH8& zbiC2T(m$vSZaOa<105=ax|Wi8e1f-%7|hC0cNolyfYL5d2WbT>R3KWR$(f=xQ`M-p zViL9&f&b6#>sGB`9IeR;CA4qsljVjdl-&*Z`BE!j^x7-SP^$&_mFCN7MMZz z6o~4jy&mv{j|)5JOtyqf1e&Dv-803A>x9{YJo2d3c3H?3QwjNbO4A+~&ZtTtPQnGc zf`i2`P}+!kbz|7wp#H%XA-5uAD4Fv-8#p8)B2L z9D$h0h0JU{5KmqW`W*|3(Q}UiofrBHinH0(@o!nJqaLt--*}oRA(>ph( z-NpweJG158SP&${BN|0zPI(v~En|yxE#wl%5=D>=LfsDr`p(dE zZjB(Iep!_=)zwhglj?+0?PdgKRjb9>fg0|O2C;$GQV2KC1WrMsLP6?klk8gNi{)koO@pUnDwq$`TA5JSGUS0FXpZgKYuqM`~S zpsx2MF+;0%#8UnEwxZ_Rs65Cfh((!!ie}3&SF1|os6B-J`+!|BF&nI1gN<5ib3+#J zHrqoWes7L*|9H}%S8bH+s^wG;x><(u6GgD8v&Ii}HZiwUon^5aUl{CBn^43gXa>90 zQhEE#PeUYCQd~cbYmzM@UWAM>6nec#DbqUIohyB6C~*|^U|d`*1+5y>B-zSH#{LyB zE{A6g)o4Yy=@4g&{Hwa|?b3UW+$CxcR{oW0l@{qi)I?+#*REJ6FG0LcpU)`L24sk&(~zbldZTsGxM8Y>HJsr`{9*~n zta2V%y*=q!1w{;XsSFQ9cZfcX|09J6Hez-X?-Pdp_iqS^|RnTLSF#ul zs~(XN1X4RxkXnKQal8O^1?f=gZ_mvJ&IQ|~Ir+`lPux=rpj-tO)Brp0xD1%GUvU}S z$&#VU*%_Wx0&dd(bIa4l>atDG@q5)}Dfz4l-kfu2@v+aWo%f>Md*Ja#m!ak_S7qkf zfDt0*ll3YHJI5H|J}qBDE1tx5*jl$UdM{Y84=k-R>$M}*X3JK1%eKTr5(R>o7aLuw zwv!xv9zl3C12m&&STKAomXpYcQ|eHUMOn9456!DH=mT>RIUsuOz<@1nn$3cMi{dA8 zcuLB3uHVE6K^OVO5y3d7&6b6sO!t1lrlH=wVS-Qv@p$Jd9$F5-b8^$+Y&`Vq4@|zD zo%qDs>qR&UpiUGNnCkeuN7}R5p7Px6X$0;mS0K|iJ|RXMDn6@r?`4}WSem4CNnAEV z;Zbb5*t;=ChMSUK$O1p)`e)|w=y*Wv043Jj&DCV3eRDbDieiAM=UY2hoVMCfPS#0DR39wocP#huM9bj3^YHvCPiX`iOVG9KOItw$qm@Bh@Zs%-h$IbcBEVtn- z33Nn2(t$}I4EHv10J;{$$BUOX#BF6{>c!IZ#Zt?~QlS6+!V1k^7O4J>$)UI&e8al2 z0xaK;1v}o5%YfM;q*tiK_t62~Lc`)hUup%C{KmZ)B>UYl)s&Q+o(N-@6L1nwQECyGU=Xh|uA_1KRwclNA+y-Tzw`NtC1l*--Jy6+V`;KOf*<({~)e)PL zD#^cgxpKC8ao8Vev_dOOzZK`5`rB?G(BO+GE95LM@x6R+UcNtx9fqNRatn*eVMgi@ zzK1tPyWS?g-F|9TfOniY8`!Y)5!@}L)SZG_jxIUVxm1Y^Aw3uw>3akzLM|Oi0F<40 zj)-pOh;n}e@KVo+Lf>Y|i-HB9pv3W-`I~}ic;?XP{IZdxPzbM`Bn<^sq#)tDvgfw> zg#$mUnw<)(5~jAIqB?w;%wosaDqELW!KjWondc#o7dQYE&aBz$6rL!V`?c*#MSQnQ z2bmHE774?gOe-@$YPAxjDjIGez}Lo-_;cCUu_lATF_9LAf~Vv+Uqr#jJ~6`QNA&jD z=60*4;G;cod_M7<&0b30=_T~x)t~LN8~4n2BnW}_0Jp5K{<%$(&!FX_EV)b~VDKD* z31>epO#ek#fK-?A)w+sJ7i5Y(?a_m^+IF`d4Yi0_6H(CWgm<1RO=zh0HodiNG^jLItv zl~14q@hW|(#h(vr$=$sf+=-6_m5geoj5+~YvEqq#aO8nqa zu7iE#wJG;(k#w$+%Jsko6{CPzMwn?X-o+MUoQ$gjuT~S`u(!84V88QRmckiV9cFY+ z7`Ulc3T01~GG*2T;DZj6?!EvW@QFrTEiNkgRN&Gupfjbz?!ey~B{;kTzBV-0D9PIr z{qvBJri%7XUoN+X*V_+G^$h?^ibkCcy43XaCg_1bf`mjIm`DQdpk^(PhTYD>S0sjU z#yV_U^zsw(EX8<1mH+IwxXcCwqSl#z`O3FH;`q2;n|v?E>Y+dI`QJh?0zE<|sGFf~ zg(7?qCe$-Q5!S1&2Bz?R`W|fvNVs>`-OdypERdijqs)oIRSby2QDUV?)KVo%qngkr@Rd`@5cRzR|_QBG!*82)TtqO#+@NvWmMz%zU7pK%WjeGYHJ5ur?$RVG-&8j;7^D28!PBVKxJSbITr<=9NEgG+lU~}HXQ4%3&71D1V?HAv-xJ8 z35E-|kI-FE7NYctEIl|M*4~gboec&iB#0G!P=2sR?68PQS-^aZ*2Q>6f&c6=_7t=T z=6O)fk*^y5&a{V`^%12u65k`nmC3*+bE(jSmWy>QjkthPZm ziI2toD)!z#Nj-?5!VdXQ<{hxT_uT_?H?Wui29R=W>Y}!g4;k*FH3OOL1QFPQebnb( zTQgRd5M~fQlhHj_o35&BQAaiBl^3rr*pAHL+|4sdmcmn$SGkWE7R-*Ms$4ZTZ}H!9a7`O=aRt7w{xn z!MG9AtPO_irzL9LV3)R%>ZaT^J?{{)K&|beTTi{JI;~Zh!=YWZ52_PeO^;{j>O`yffB3^05uu!koGlxUu$`vJ#8q;o4I=yR_5g#1;H=zSJS1HV0Alg$-(cJh>Tn$G zd9ke!>iLPdriA_kF;->Q#_b&P>#kBYUv|5|1h+}k-tXr;;mp=P5w#e9eD6tQ6p{`8 zFyA?+2097ZdS`Kgb$VbS6_z-VewJZNeh@X~k{}KJ+E?+%HS2N50Expcu)V$_*3_U~ ziD)j7i7l6-;Zx^>LH>lQaGK@Tv6)k(Z54 zS!MqO{Rby|ZUKaP-iQ3hW?X+J}%+(S$IU3+CS=%3aO`FTY2oi}(2 zS6l4eqn^~;_kB0~0UCbc8`^)aXA4R$>+KBxXa4=@$`x{4vvse=?&IWQc z;0)gJP0tDc$Hpk+!``c1INLv zeT?*>p=@kyq5;#(x>Z|o6!>63Pj?Igm-xuyd;L+J&ueENe$UWHXQfAH!O+06anGkt zPgof>2(hitT1FugAzI2=)k}ogPr40|f~LtDxfdZ8?d%&tJhxIKU zXBZ4jgIcT5BLoBkMw5gOGq|l4^~N9@OL=)mAt;<3X7$~#BCrHw5zz_-iNGoUiw=ZX zQaI%)E=Ffi4|Cc$E|KGTEUh!+_x)JHIdfn)aRD}XcifGE8!Zvhy~m1D^6tIBq~{wv zLRK4XIsTPxjk1c=UlEicpcej*1^(Y7l1_eS8O(u|ndLOo8fOvGejxo0eQ*xkz-h^w z)4Jh5g%JYUieln;9<}_9ygz|j#&r!D#51zc4sRpPsCe{{|#pTwzY%rj@%AfG`c-Q zS9_ zLQF~Hq|E7TiR1U0BTN=X($%D)Gc`3P@9Aup zHP-Ov<4S`bg*g~7ghaf@_Z<9%dgLvF!dzaGf(1s%ergjL$UEMH%`pH2PdoSxjyY*n z*@5>z25wvKJwlHXbxadLbm;k8X@q>*I0yz+MXjf_Hr8}kgijyGiXkPt< zqacoW6J#4RDf4h##Wqm28zH2XjyS zW0py_z0^6OE7Co2`8j`yq^JfCmG1nx%Q%bjI`|}Mhc}fDQSRClUEK_Pzg@y;O2X8^ z!uuK(^=h?3y{^hFVuT#6=y4Vm7aBE}Z0SmM(TWdq#KQt!&Vv-{CUk@y2a-UpDD^$*fyIojkYZq$SL-tX3dS6#woc-U{921ygrdDhN>j?+q&g+B0b58%#@ zKRqKDztz;aT}61~8GBHyw1AUtIrVm=Rif6yRbUWsg-XBd4>v z)xdl~1aqE803(7=re;gj$hG+(K_KI3roycJwjyA2jc1izKn?kX{>_^d zz?=vmU*B7lNs(zV{VwadV0KSpOYw50u7JdB@3z_{pVM(Hz{x*Cz82^zQ~@1NDvCr| z{7YdSx=KCr2}yKHdC;-|P2~gS?kM+pL&M49QLQ?svyi{lE3`&nR-u?-=mO zUqar82LO=&Hl22^wnnB-mUiZUNqSLzJZ7E&^*wn6dAw|&#hWr?0umFBdXJ3J%kO7v zl`22+x@0l;1IqS4}bEW99tHpTmh3Oc+YLR1NTC(4EL|9ZbSR z*EDT2is@fFgP4h;h^Hok980`%C}d5U>3YPRNex)CkTgY7hC3wPFUeHth*h>R#~P>_ z%MNeqEa^yw(adEWY;NU8amGy(4KR_}hQcLDiVgKEAGIOzj3dcmY={_eL>S0bP_`jl zLU@Va@tjB!Gf@o7qZE+LI3@BhSk~B zf|*t6{83?VByt0SEJ(u&E7O|HyJ-=&duns%VUge^K%k+3)whm*k35rX+u0Kj3zRyW zTAkS(zb4Lu&8pvbBOUrXQGjKqYZaVelsod{tu32`wIwi}^>Ea>O{rgluHS!fF^ljj zgVG!Cs8jNohjbBx8Gf&b(#Qp79(Q0>W%0hSnOFt5bX6KG`LFegszXK53TuypIZ|cG zC)b1so^h<>+Iuu`Ok$A~3wDq^M*kjOo}PReFVr(NX?C36qGDHw*ZQd)(@W_flMjY| zS1$P&+I1Ib#rK zpEW&Sk@Gi*|5u{|{srRyx4aXAf`pW#ukWV5!2VZ)%0KJ;GtDGnS_*^_F;t&yqLX`F zO{CD0Ug<=(kWWCu?0euO0l9LOy**`w+Uc5bZ2H^LIJ+=eG{Eq|thC2FUip-`9 z+FN<>Os2&l%bn<-0c&06Z9!RWQ`$cy+z2Sg(kXn%s8=22^LJ_Mgda8SsL`)GCeNLI zc2f)r7-b>_vN6gsE!&~XA8MDj@hmxUk`DzPE$blQ1?7{lSDQHDGq?RJj^D(P+|5D5 zW7d~)zhzAQFUmCc{jJ6JOAMZ0C(hUTkCdK&%EZFd(8Sb<@n2auvQdKYz(la3H9~FQ zBj}ct5A;<*32>eVbt!C`jGX%F}c86|Ag4N1^HXC|Flm3 zKfN@ww|Du!q?gPWrzvt@utNKCXo!Ey^53Lbl(HW4#Xm#z$;Noog8JtmH5^a!leH{W z*B}^Th%Sd9Rzqq%7eh}_9we8hkR+O*cZb~0C)ht%m>tPuDX_W4Y0!3UPJe7>pBaR> zORV^ue!M&{V713KNFs~mxlB~ZfQ1Vvv(IUP0w_@pp;c3nNq_BeZ;ECDcda7@3HF&n zzGW{Q94TG`1>gQ5RP^6f zek9b4BjG9{v_>`wxUH^@lYKKI{}uy}%AEBB6nR(-#GINqAG&~cl12>d;7Jov9J~Dx z$vyCO%7Dz!s115W#3v1FmP7f2bM}mt11XY{HbbKIUXwB}u6E3^qKb1}$KD;MryD%% z-8-})<&BUU`&aD4gq}2dKYQJ+Fdu^KCWRS_prRTf7i-|5hq(ucA2B5>pDOH?*$AQ+ z&_36QJrEPniyq!$Hx?_fnkw7^Lu!qHm}>L_Ls^aFCzRbn%)zoG!iB^;m*qx`igd{U z4iWNJ%D!kkz}RC*v1KtsvKY5us}#wEUN@eNp6LSJaLxYLQYM$AL(t7a6D!)!04d-B zW4r3cLnGF=(^aTHe6A3`1q6aFFek`!f#1czL=wCUBNr#Mmk#zRrW%>(g@ePMF>P~$ z)Lle518(~}o)Dx0hI5G&UOzs~OU578p@1PbU?eJB7MrgIAAJAX&Pki%*Q~!Q zTHHcJp`l@v6e6&aLX6=E)-1A#U5JPi>0KsLgjE?cOT=DjIu$JxSnUQUI$B6=|4p~0 zlAvm>~T~Flkk;-8IrnW{2&F zPy%g99}8A|anT|n7^=+0*b~hp9Xh^J7Iprf>59Fem+LA%4NLV!El4&AzjdJdDmA}s zQ~|Tw0MSdBGb!%Ty%dL;QR=r#79ZCaDZGPTsZt2lY;ZMU9)`EEI(nRP~%acrLPxZ5)5v8?ut{mFxD`RuNN0tsN za%hy(BMYZUwfJ7ZA}R&l)h^y$IJnH8mRa3$f*$FU zFy{iBHh+q3EUnuNb&1J)PSCu0)n4vzwr+m3ps3`Ir5ISi@a>6+9+CNEvEf_F5#D{? zYrJ`V?8*(@ZsWl%cvUFe!LU5T{ilUhR!~Q&{vz5OU-&`!vR&H3_I55`Ihgt?9uB6? zx_>!=CbeF>bq3gXwEkrxwYGi*SjitNOZ#iWk3bP3+-o$7aVL%MuS#x4J-V4@)~?LY zPfyt*(ATF&qs@c(LM$gshpJ69Fb>d7j+1R~e;nFd>Fn7mLd_BCc9bxd4`W7r(TL0O zG_bzi?_icOYDnUSh`E=2jDQauAKpePoIv8zQvRW2ueeeeuP)kKkCU%jE~+crYA>eo z;c@&?n`q>iav*cNaCZfFc$#&Aiw3Jn+b2=xCQh)@dJ|Fc55X zbzi|r1J7Iv+~_U4fkp6%Y`~&dc%6~9_vsSiYKv;2l4U9tyxtb61NV~hQ$|Dq<e#eHVu=@=m9$SN+Eizvn z&|n~RnscH!&b(ppE39Z@G@k>1RSc*L(>d?o;t|4Yiz=GL;n9*Y_j%;_toYwm`*l>3$$=wK9 zgXZDEM%)8+|k74`4Cg??iEr+PI!)`=6o)OzrB{-xf3O}C6)on7p0|59((lpu5; z17h%QMbhfJ3I=hJCHvl*s4KyoC60xe5IOC`gBU2n&h1VAuytFiegs?r2RYnueE{(2 z?T*FV^@)8b3~B-_oSC5z95=L!t#d3c19_;DiJwS+rc!A#GIs&H(vi%sDBMm-k0Hq$ z4z5V`<_dACQx#QnQ+3I6gx%rZ<%*Vjdd}MSjzshB(DSl~|3c{ATh?0QSJ(d{Z-05$ zfBgkR2Z#Ucf6%#YIZXUqBaY)mejCDQBOD7e5sI{@CrJQ=!}HVbe$zWTdYzDweCc6b zc@d!TfJaV?FJyg}7|c9yiY6%c5T53>x|1Rzt{ws%Okl}rijz&ME{h1WT53p1Ose;Q zX}-_`w=?+LsybleRAt#5OdH%~2mS_PtY)S1S$`q^{cZoac6hJs^1uE-X836Q)YlNJ z`l6=)nqvKBqV2vI%s&>W7QgbG_Zbj}zw(?rU6p{eL}fYs1U3*iy#f0i(ZLsWHWYdG z-H8LTZ8YW3ypG}BWVYTIOuy(NwtefkwS#2CaVd3efVj7;s+qiq>6jO z0?vaeT7J5wssnlj5cvcHZoWLJ;3=YwT-kBc%mjVY0X&b2;i#Z;DfKAWMNhIzve|Ej z2Kd%%{QgbGc_w*cxlehJZ?O1kJ1j7*F5Knmp4R8Uzf-`Tsgq$nO-k4yU{MRd7)sb6 zY3cV-aY088_g3e<7`n$E99kJnVkHVxE5N?Ba5HyS;2oPG;eF|5ko5 zMhYi-57I`0sUZ5Qfko(a!x@A<)-a?+PdVYWTS;eKg7;KKh2_oMJ&`7g-^^r&+~t=; zZ!xTSIiXbs^9Zxj6CuOxN+;$L+qdG2c}1~H;KiE}WX|g3lT8hTnq%qz*6^P8;{}E3 zlO<4Dl|$=k^1mk7|4w1?zTo?BMEgH5@Q<0u|3RwFFBKEr`-RekFO>c(o!r#UQ-u5%ZDwYMm7sn-IB}!=*ihJr740-@PEGnpKn7*gF|Z((OOe z87u8Stdbl1JfMmRSDDDd8E~a6-N2sjUJY*&H*A)4>0~SkA#-v&|F@C3+cMEOkqA|? zJ>LTz7>dR*2~4*cV|Ap5(=O0vD%d4K){npX`wtKZm}TZD#Q-t%sqU@f3=1yL2B)KV zD)&w_Iyo#-845J3-%V4aGq!%wuA#SIV@ZNV6LB5b>Y^!ct8-<)A$T@PH*QuVc5)86 z*>5bo-$=9jxKN+NJe0FC8JyRtQqC$H=flT+a6RNe< zt)tZk6XSY@W`}>qaV$4TOedvE5Uq6WspO}2VgUxl@7vlIi=AN87%&IW78A`lQMQ%U z-MfRAUhN@90Cp`kWXFc3eWgjx?I|@~_D?=yYhc7S&G{2PpWb5(*)({jScf;4kQ zsL-o|v^R2XB>9pH$jJPCAUxFhlY7N-T$#9HEc~>K^~U+DoIjy2@+t<|uao@$=^6eV zm;dz~hJV-k|7lpt=8TQyeZkWC>v0kPf~B*mi_6#Q)IV%zQPSpL>?Bx!aK@XsT_du$ zRNLj-(jTK0(G~~;vQ>0q#Q@Uv@%7l4{Z@W~coy{p!5ePz!ojn3-zAeyXhrTyjk+n# zVg-(`^vjiPettE5O>~r8(0v6}n+oFg&R_UrrAqn2j3j^|r|WzpTdA%Co(MI~FzX6Y zhuK9-+RVf1>Lvv*2f^FOj*;)&1epqq$S2$e2=Nz=54@8e!KjtGwQ(oREE_^AEr0 z+y3?3kALcOVbf`k5EFby+mS;(K|`5+zL6s9;@*87CfBczwq0L|Ofoe~E@&cu#wL>vF4=-OMnwpTp z@AE#8IkhJhkfY3M!p1a3|8pq^nL>KCMc z=A9c^M7Q_Of}JsCG*wRCTGr8b6r3A zfZ!67ssA4NNjA>;pZP67;dA8$Z~p8jKiKnkSXUcsGdJ(}%DB`%*$EPK)4 zr}M+#nTnks@*jS9uq4av=`&&e2@E2F0ZCRL5AYxRmgQjc=EAv$!rR>nPThN$@?=S? zB;z!TLus0>FGR~WpHOVmk?t;uTj6_t?$H&>d-vxm?~y3I(0nZaa$I}z+Nqz#W=#FR zZQa}4#D4}$G#mQs8Hp}xkYj$Ji<;!Oao1#lNz)lPlZez#%PR>XX{#XH(tXZB{Uxu@e@w%?Y4X{!t0@`n$uY?oiVE&EaLT~UEg|DV?6d=D>pbDU+< z3+;VTX>%mk2SnGe`SJbw@ub6&t}nNiyzo7m-}a+!``#(0zdUr7+D=`db??ZHX-*Te zcs!z#vTJ^=F>L60DcQ%AVlnr2t5Zhm7WUUUdpd1SbNx#=q|J40Yv?oCtCBtawQ($u zCw0t|x_xOuY}`dXi4y4m$wgNTckE`r^lM_|UR%e6P=`ZSdcns1T~%5~!z1gNzq7A- z&iGR}K%;nWdX8M1$H|q+Uu~94$gWmD_rGfj-e!7$t=u4HJ`SP^AfqK}chMSPeoSq(-<%-V|yOl3UON0)3bfp?kJDR5y|X z&~>8^G9h%|w!}K*gl+)(Fb2YaUDik`4l$^KZUFiq0>Xe=8zcjuLkj4+(R=U+-FCJ} zzK3^}(Dfsy22dXm0c`9sA`xy1)@VfUrXh@a0y7G^`Hs&epjJNuTyaEk39=zr9fIC4 zN0?OY1T_h{nU3xd^mZUZySEEeJ966qT|07!qWZ($4aFbGhG6vvdaaLe$TOHpX}}>- kcpCtpOHkw1*aO8SD5gN2!U`^kq!^?ax`3?PKn)BG0RNTurT_o{ literal 0 HcmV?d00001