LiamKhoaLe commited on
Commit
412cffc
·
1 Parent(s): 53f192f

Upd README

Browse files
Files changed (3) hide show
  1. .DS_Store +0 -0
  2. README.md +45 -230
  3. report.pdf +187 -0
.DS_Store CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
 
README.md CHANGED
@@ -12,22 +12,22 @@ short_description: Ed-Assistant summary your learning journey with Agentic RAG
12
 
13
  ### StudyBuddy (EdSummariser)
14
  [Live demo](https://binkhoale1812-edsummariser.hf.space)
15
- StudyBuddy is an end-to-end Retrieval-Augmented Generation (RAG) app for learning from your own documents. Upload PDF/DOCX files; the app extracts text and images, captions images, chunks content into semantic “cards,” embeds them in MongoDB, and serves a chat endpoint that answers strictly from your uploaded materials. It includes a lightweight chat-memory feature, cost-aware model routing, NVIDIA/Gemini integration, and robust key rotation/retries.
16
 
17
- ## Features
18
 
19
- - **Document ingestion**: PDF/DOCX parsing (PyMuPDF, python-docx), image extraction, BLIP-based captions
20
- - **Semantic chunking**: heuristic headings/size-based chunkerstudy cards with topic, summary, content
21
- - **Embeddings**: Sentence-Transformers (`all-MiniLM-L6-v2`) with defensive fallbacks
22
- - **Vector search**: MongoDB Atlas Vector Search (optional) or local cosine fallback
23
- - **RAG chat**: cost-aware routing between NVIDIA and Gemini endpoints
24
- - **Filename-aware questions**: detects filenames in questions (e.g., `JADE.pdf`) and prioritizes them
25
- - **Classifier + fallbacks**: NVIDIA classifies file relevance; if retrieval is empty, the app retries (mentions-only, then all files) and finally falls back to file-level summaries
26
- - **Chat memory**: per-user LRU of QA summaries; history relevance + semantic retrieval
27
- - **Logging**: tagged logs per module, e.g., [APP], [RAG], [EMBED], [ROUTER]
28
- - **Simple UI**: static frontend under `static/`
29
 
30
- ## Architecture
 
 
 
 
 
 
 
 
31
 
32
  High level flow:
33
  1) Upload PDF/DOCX → parse pages → extract images → BLIP captions → merge → chunk into cards → embed → store.
@@ -39,30 +39,20 @@ High level flow:
39
  ## Project Structure
40
 
41
  ```text
42
- app.py # FastAPI app, routes, background ingestion, chat
43
- utils/logger.py # Centralized tagged logger
44
- utils/parser.py # PDF/DOCX parsing and image extraction
45
- utils/caption.py # BLIP image captioning (transformers)
46
- utils/chunker.py # Heuristic chunk builder
47
- utils/embeddings.py # Embedding client (Sentence-Transformers)
48
- utils/rag.py # Mongo-backed store and vector search
49
- utils/rotator.py # API key rotator + robust HTTP POST helper
50
- utils/router.py # Model selection + LLM invocation helpers
51
- utils/summarizer.py # sumy-based extractive summarizer
52
- utils/common.py # small helpers
53
- memo/memory.py # per-user LRU memory store
54
- memo/history.py # history relevance + semantic helpers
55
- static/ # minimal frontend (index.html, script.js, styles.css)
56
- Dockerfile # container image
57
- requirements.txt # Python dependencies
58
  ```
59
 
60
- ## Prerequisites
61
- - Python 3.10+
62
- - MongoDB (local or Atlas). Collections are created automatically
63
- - Optional: NVIDIA and/or Gemini API keys
64
-
65
- ## Setup (local)
66
 
67
  ```bash
68
  python -m venv .venv && source .venv/bin/activate
@@ -71,211 +61,36 @@ export MONGO_URI="mongodb://localhost:27017"
71
  uvicorn app:app --reload --host 0.0.0.0 --port 8000
72
  ```
73
 
74
- Open the UI at `http://localhost:8000/static/`
75
-
76
- Health check: `http://localhost:8000/healthz`
77
-
78
- ## Configuration
79
-
80
- Environment variables:
81
-
82
- - **MONGO_URI**: MongoDB connection string (required)
83
- - **MONGO_DB**: MongoDB database name (default: studybuddy)
84
- - **ATLAS_VECTOR**: set to "1" to enable Atlas Vector Search, else local cosine (default: 0)
85
- - **MONGO_VECTOR_INDEX**: Atlas Search index name for vectors (default: vector_index)
86
- - **EMBED_MODEL**: sentence-transformers model name (default: sentence-transformers/all-MiniLM-L6-v2)
87
- - **GEMINI_API_1..5**: Gemini API keys for rotation
88
- - **NVIDIA_API_1..5**: NVIDIA API keys for rotation
89
- - **GEMINI_SMALL, GEMINI_MED, GEMINI_PRO**: override default Gemini models
90
- - **NVIDIA_SMALL**: override default NVIDIA small model
91
- - Optional logging controls: use process env like `PYTHONWARNINGS=ignore` and manage verbosity per logger if needed
92
-
93
- Logs are emitted at INFO level to stdout with module tags. See `utils/logger.py`.
94
-
95
- ## Running (Local)
96
-
97
- ```bash
98
- export MONGO_URI="mongodb://localhost:27017" # or Atlas URI
99
- uvicorn app:app --reload --workers 1 --host 0.0.0.0 --port 8000
100
- ```
101
-
102
- Open the UI: `http://localhost:8000/static/`
103
-
104
- Health check: `http://localhost:8000/healthz`
105
-
106
- ## Running (Docker)
107
-
108
- Build and run:
109
-
110
- ```bash
111
- docker build -t studybuddy-rag .
112
- docker run --rm -p 8000:8000 \
113
- -e MONGO_URI="<your-mongo-uri>" \
114
- -e MONGO_DB="studybuddy" \
115
- -e NVIDIA_API_1="<nvidia-key>" \
116
- -e GEMINI_API_1="<gemini-key>" \
117
- studybuddy-rag
118
- ```
119
-
120
- For production, consider `--restart unless-stopped` and setting `--env ATLAS_VECTOR=1` if using Atlas Vector Search.
121
-
122
- ## Usage
123
- UI:
124
- - Open `http://localhost:8000/static/`
125
- - Upload PDF/DOCX
126
- - Ask questions. You can reference filenames, e.g., “Give me a summary on `JADE.pdf` …
127
- API:
128
- - `GET /` → serves `static/index.html`
129
- - `POST /upload` (multipart form-data)
130
- - fields: `user_id` (str), `project_id` (str), `files` (one or more PDF/DOCX)
131
- - response: `{ job_id, status: "processing", total_files }`; background ingestion continues
132
- - `GET /upload/status?job_id=...` → progress
133
- - `GET /files?user_id=&project_id=` → filenames + summaries
134
- - `GET /file-summary?user_id=&project_id=&filename=` → `{ filename, summary }`
135
- - `POST /chat` (form)
136
- - fields: `user_id`, `project_id`, `question`, `k` (default 6)
137
- - behavior:
138
- - If the question directly asks for a summary/about of a single mentioned file, returns that file’s stored summary.
139
- - Otherwise: NVIDIA relevance classification → vector search (restricted) → retries → summary fallback when needed.
140
- - returns `{ answer, sources, relevant_files }`
141
-
142
- Example chat cURL:
143
-
144
- ```bash
145
- curl -X POST http://localhost:8000/chat \
146
- -H 'Content-Type: application/x-www-form-urlencoded' \
147
- -d 'user_id=user1' \
148
- -d 'project_id=demo' \
149
- --data-urlencode 'question=Give me a summary on JADE.pdf and setup steps'
150
- ```
151
-
152
- Upload example:
153
-
154
- ```bash
155
- curl -X POST http://localhost:8000/upload \
156
- -H 'Content-Type: multipart/form-data' \
157
- -F 'user_id=user1' \
158
- -F 'project_id=demo' \
159
- -F 'files=@/path/to/file1.pdf' \
160
- -F 'files=@/path/to/file2.docx'
161
- ```
162
-
163
- ## Data Model
164
-
165
- - Collection `chunks` (per card):
166
- - `user_id`, `project_id`, `filename`, `topic_name`, `summary`, `content`, `page_span`, `card_id`, `embedding[384]`
167
- - Collection `files` (per file):
168
- - `user_id`, `project_id`, `filename`, `summary`
169
-
170
- ### Atlas Vector Index (optional)
171
-
172
- If using Atlas Vector Search, create an index similar to:
173
-
174
- ```json
175
- {
176
- "mappings": {
177
- "dynamic": false,
178
- "fields": {
179
- "embedding": {
180
- "type": "knnVector",
181
- "dimensions": 384,
182
- "similarity": "cosine"
183
- }
184
- }
185
- }
186
- }
187
- ```
188
-
189
- Set `ATLAS_VECTOR=1` and configure `MONGO_VECTOR_INDEX`.
190
 
191
- ### Schema overview:
192
 
193
- - Collection `chunks` (per card):
194
- - `user_id` (str), `filename` (str), `topic_name` (str), `summary` (str), `content` (str)
195
- - `page_span` ([int, int])
196
- - `card_id` (slug + sequence)
197
- - `embedding` (float[384])
198
- - Collection `files` (per file):
199
- - `user_id` (str), `filename` (str), `summary` (str)
200
 
201
- ## Notes on Models and Keys
202
 
203
- - NVIDIA and Gemini calls use a simple key rotator. Provide one or more keys via `NVIDIA_API_1..5`, `GEMINI_API_1..5`.
204
- - The app is defensive: if embeddings or summarization models are unavailable, it falls back to naive strategies to keep the app responsive (with reduced quality).
 
 
205
 
206
- ### Logging and Observability
207
 
208
- - Logs are tagged by module via `utils/logger.py`:
209
- - [APP] app lifecycle, ingestion, chat flow
210
- - [RAG] storage, vector search
211
- - [EMBED] embedding model loads and fallbacks
212
- - [CAPTION] BLIP model loads and captioning
213
- - [ROUTER]/[ROTATOR] model routing and retry/rotation events
214
- - [CHUNKER]/[SUM]/[COMMON]/[PARSER] module-specific messages
215
- - Change verbosity by setting the root logger level in code if needed
216
 
217
- ### Performance and Cost Tips
218
 
219
- - Disable image captioning if CPU-bound by short-circuiting in `utils/caption.py` (return "")
220
- - Use smaller `k` in `/chat` for fewer chunks
221
- - Prefer NVIDIA_SMALL for simple questions (already default via router)
222
- - If Atlas Vector is unavailable, local cosine search samples up to 2000 docs; tune in `utils/rag.py`
223
- - Run with `--workers` and consider a process manager for production
224
 
225
- #$# Retriver Functionalities
226
 
227
- - Filename detection: regex captures tokens ending with `.pdf|.docx|.doc` in the user question; preceding prose is not captured.
228
- - Relevance: NVIDIA classifies files by relevance to the question; any explicitly mentioned filenames are force-included.
229
- - Retrieval: vector search is run over relevant files; on empty hits, it retries with mentions-only, then with all files.
230
- - Fallback: if retrieval yields no chunks but file summaries exist, the app returns a composed summary response.
231
- - Guardrails: responses are instructed to answer only from provided context and to admit when unknown.
232
- - “I don’t know…” often means no chunks were retrieved:
233
- - Verify ingestion finished: `GET /upload/status`
234
- - Confirm files exist: `GET /files`
235
- - Try `GET /file-summary` to ensure summaries exist
236
- - Check logs around `[APP] [CHAT]` for relevance, retries, and fallbacks
237
- - NVIDIA/Gemini API: ensure keys are set (`NVIDIA_API_1..`, `GEMINI_API_1..`). See `[ROUTER]`/`[ROTATOR]` logs.
238
- - Atlas Vector: set `ATLAS_VECTOR=1` and ensure the index exists; otherwise local cosine fallback is used.
239
- - Performance: disable BLIP captions in `utils/caption.py` if CPU-bound; reduce `k` in `/chat`.
240
-
241
- ## Security Notes
242
-
243
- - CORS is currently open (`allow_origins=["*"]`) for simplicity. Restrict in production
244
- - Validate and limit upload sizes at the reverse proxy (e.g., nginx) or add checks in `/upload`
245
- - Secrets are passed via environment; avoid committing them
246
-
247
-
248
- ## Troubleshooting
249
-
250
- - Missing Python packages: install via `pip install -r requirements.txt`.
251
- - Ingestion stalls: check `[APP]` logs; large files and image captioning (BLIP) can be slow on CPU.
252
- - No vector hits:
253
- - Ensure documents were embedded and stored (see `[RAG] Inserted ... cards` logs)
254
- - Verify `MONGO_URI` and collection contents
255
- - If Atlas Vector is on, confirm index exists and `ATLAS_VECTOR=1`
256
- - NVIDIA/Gemini errors: see `[ROUTER]`/`[ROTATOR]` logs; key rotation retries transient errors.
257
- - PIL/transformers/torch issues on ARM Macs: ensure correct torch build or disable captioning
258
- - PyMuPDF font warnings: generally safe to ignore; upgrade PyMuPDF if needed
259
-
260
- ## Development
261
-
262
- - Code style: straightforward, explicit names, tagged logging
263
- - Frontend: simple static site in `static/`
264
- - Extend chunking/embeddings or swap providers by editing modules in `utils/`
265
- - Optional Makefile targets you can add:
266
-
267
- ```Makefile
268
- run:
269
- uvicorn app:app --reload
270
-
271
- docker-build:
272
- docker build -t studybuddy-rag .
273
-
274
- docker-run:
275
- docker run --rm -p 8000:8000 -e MONGO_URI="mongodb://host.docker.internal:27017" studybuddy-rag
276
- ```
277
 
278
- ## License
279
 
280
- **Apache-2.0**
281
 
 
 
12
 
13
  ### StudyBuddy (EdSummariser)
14
  [Live demo](https://binkhoale1812-edsummariser.hf.space)
 
15
 
16
+ StudyBuddy is an end-to-end Retrieval-Augmented Generation (RAG) app for learning from your own documents.
17
 
18
+ - Ingestion: PDF/DOCX parse optional image captions chunk to cards → embed → store.
19
+ - Retrieval: filename detection → per-file relevance classification (NVIDIA) vector search (Mongo Atlas or local cosine) with retries and summary fallbacks.
20
+ - Reasoning: context-only answering; per-user recent-memory mixing (classification + semantic); key rotation and robust HTTP for LLMs.
 
 
 
 
 
 
 
21
 
22
+ ### Key Endpoints (FastAPI)
23
+
24
+ - Auth: `POST /auth/signup`, `POST /auth/login`
25
+ - Projects: `POST /projects/create`, `GET /projects`, `GET /projects/{id}`, `DELETE /projects/{id}`
26
+ - Upload: `POST /upload`, `GET /upload/status`
27
+ - Data: `GET /files`, `GET /file-summary`, `GET /cards`
28
+ - Chat: `POST /chat` → `{ answer, sources, relevant_files }`
29
+ - Report: `POST /report` (Gemini CoT filter + write), `POST /report/pdf`
30
+ - Health: `GET /healthz`, `GET /rag-status`, `GET /test-db`
31
 
32
  High level flow:
33
  1) Upload PDF/DOCX → parse pages → extract images → BLIP captions → merge → chunk into cards → embed → store.
 
39
  ## Project Structure
40
 
41
  ```text
42
+ app.py # FastAPI app, routes, chat/report flows, ingestion orchestration
43
+ static/ # Minimal UI (index.html, styles, scripts)
44
+ memo/ # Memory system (LRU + helpers)
45
+ utils/
46
+ api/ # Model router, key rotator
47
+ ingestion/ # Parsing, captioning, chunking
48
+ rag/ # Embeddings + RAG store (Mongo + vector search)
49
+ service/ # Summarizer, PDF generation (dark IDE-like code blocks)
50
+ logger.py # Tagged logging
51
+ Dockerfile
52
+ requirements.txt
 
 
 
 
 
53
  ```
54
 
55
+ ### Quick Start
 
 
 
 
 
56
 
57
  ```bash
58
  python -m venv .venv && source .venv/bin/activate
 
61
  uvicorn app:app --reload --host 0.0.0.0 --port 8000
62
  ```
63
 
64
+ Open: `http://localhost:8000/static/` • Health: `GET /healthz`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
+ ### Configuration
67
 
68
+ - MONGO_URI (required), MONGO_DB (default: studybuddy)
69
+ - ATLAS_VECTOR=1 to enable Atlas Vector Search, MONGO_VECTOR_INDEX (default: vector_index)
70
+ - EMBED_MODEL (default: sentence-transformers/all-MiniLM-L6-v2)
71
+ - NVIDIA_API_1..5, GEMINI_API_1..5 (key rotation); model overrides via GEMINI_SMALL|MED|PRO, NVIDIA_SMALL
 
 
 
72
 
73
+ ### Retrieval Strategy (concise)
74
 
75
+ 1) Detect mentioned filenames (e.g., `JADE.pdf`).
76
+ 2) Classify file relevance (NVIDIA) and restrict search.
77
+ 3) Vector search → on empty hits, retry with mentions-only → all files → fallback to file-level summaries.
78
+ 4) Answer from context only; store compact memory summaries.
79
 
80
+ ### Notes
81
 
82
+ - PDF export renders code blocks with a dark IDE-like theme and lightweight syntax highlighting; control characters are stripped to avoid square artifacts.
83
+ - CORS is open for the demo UI; restrict for production.
 
 
 
 
 
 
84
 
85
+ ### Samples
86
 
87
+ [Report Generation](https://huggingface.co/spaces/BinKhoaLe1812/EdSummariser/blob/main/report.pdf)
 
 
 
 
88
 
89
+ [Memo Dir](https://huggingface.co/spaces/BinKhoaLe1812/EdSummariser/blob/main/memo/README.md)
90
 
91
+ [Utils Dir](https://huggingface.co/spaces/BinKhoaLe1812/EdSummariser/blob/main/utils/README.md)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
 
93
 
94
+ ### License
95
 
96
+ Apache-2.0
report.pdf ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ %PDF-1.4
2
+ %���� ReportLab Generated PDF document http://www.reportlab.com
3
+ 1 0 obj
4
+ <<
5
+ /F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R /F5 7 0 R
6
+ >>
7
+ endobj
8
+ 2 0 obj
9
+ <<
10
+ /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
11
+ >>
12
+ endobj
13
+ 3 0 obj
14
+ <<
15
+ /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
16
+ >>
17
+ endobj
18
+ 4 0 obj
19
+ <<
20
+ /BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
21
+ >>
22
+ endobj
23
+ 5 0 obj
24
+ <<
25
+ /BaseFont /Helvetica-BoldOblique /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font
26
+ >>
27
+ endobj
28
+ 6 0 obj
29
+ <<
30
+ /Contents 16 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
31
+ /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
32
+ >> /Rotate 0 /Trans <<
33
+
34
+ >>
35
+ /Type /Page
36
+ >>
37
+ endobj
38
+ 7 0 obj
39
+ <<
40
+ /BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font
41
+ >>
42
+ endobj
43
+ 8 0 obj
44
+ <<
45
+ /Contents 17 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
46
+ /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
47
+ >> /Rotate 0 /Trans <<
48
+
49
+ >>
50
+ /Type /Page
51
+ >>
52
+ endobj
53
+ 9 0 obj
54
+ <<
55
+ /Contents 18 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
56
+ /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
57
+ >> /Rotate 0 /Trans <<
58
+
59
+ >>
60
+ /Type /Page
61
+ >>
62
+ endobj
63
+ 10 0 obj
64
+ <<
65
+ /Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
66
+ /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
67
+ >> /Rotate 0 /Trans <<
68
+
69
+ >>
70
+ /Type /Page
71
+ >>
72
+ endobj
73
+ 11 0 obj
74
+ <<
75
+ /Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
76
+ /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
77
+ >> /Rotate 0 /Trans <<
78
+
79
+ >>
80
+ /Type /Page
81
+ >>
82
+ endobj
83
+ 12 0 obj
84
+ <<
85
+ /Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
86
+ /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
87
+ >> /Rotate 0 /Trans <<
88
+
89
+ >>
90
+ /Type /Page
91
+ >>
92
+ endobj
93
+ 13 0 obj
94
+ <<
95
+ /PageMode /UseNone /Pages 15 0 R /Type /Catalog
96
+ >>
97
+ endobj
98
+ 14 0 obj
99
+ <<
100
+ /Author (\(anonymous\)) /CreationDate (D:20250915071444+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20250915071444+00'00') /Producer (ReportLab PDF Library - www.reportlab.com)
101
+ /Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
102
+ >>
103
+ endobj
104
+ 15 0 obj
105
+ <<
106
+ /Count 6 /Kids [ 6 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R ] /Type /Pages
107
+ >>
108
+ endobj
109
+ 16 0 obj
110
+ <<
111
+ /Filter [ /ASCII85Decode /FlateDecode ] /Length 1822
112
+ >>
113
+ stream
114
+ Gatm;9lo&K%)(h*@!Ysga3e(r("p-ol,U/pcF10B^+^1:F%_?>8_J69r;r'3.3E`FSXiG0N[Or>&&88e_?bWXrgW$MYF"b1]+DgbQ>6aR_$$(un90*Im36B'9W!nF_I,Eq:%8E/"OUmFM]rGdg%>VHK5!H=7MD0(a#j0V!j9BPs%_QV&1-j(9Hp\R()L?AG*k\fA-P=V)2I5T!r<kT?oJmX-#DOG+efs]7=_6I)`gAtK8$M7"3b=jXM9GM5Ht'Li-o+h4il6]U^)1`#>\WaCCan\_`E,;n6QmY$841h"Y=3KAc<f(K^fVJ&HW[g7`c+RI/E.ZJ>D5ll-ZGjm8jUNY)e6hdiKYi'fYW]dU)#^',kaIZLB>tKj";d5j!!%\lE(6^9[<cH*B1B6iloVX#j19#;'@u7AbqO/.N/B4r7HdSXg*?*lU>i5&$Ap+#C[e.Yi^EnN^g5:1_k)J@.s!LZq?(-6Io)LcPXcKnL&-S[:I)pHV$@VJtBmWM`id)fORG1^$)Q?'2B#HkWpJVup.>A`('%/^ZW9E8^9MDJN-k[4iL@P.T:om8g1:YURtlqB<L,`K9P;]RBAe8hE0^b8Df4!JBec?*7Prpfb:NW="#1PrZO(081t`mV4Gj?X7-FH"dUH@<7i%V`P3$9Pt?%+a@ir\m'qj>*TJBk`l1S$V3B\4#%/H:h;)h@tW)O<dCY^aUtR@(D^:gYdPmV$a&Y?LDf0/`@@QeE3?,dZgk#hRQM@Y?gX4XgG.;bAlC=g0Rs[f[jIj_0u]'Qe*e,#@Xd3he[3HO:nm_a.-#%>)kg)`:ad"Ve94M&?nd'h`ICg!MW$b%4g)E*gtG#bPhl8/he>`=Mi#d*VJU]akf2$:k9:n[W!0@TV7A/]3)cP*?rgBo7HI7hT,opD$HKVJ=]PsTAYk+B7`'V=>,t/EpY.c[>NhlVAdAc0PZYUCh0)-G8Y$n4i++9m1A$MWT1W<IEai5<)1aA;5G[GcX+GjXcD)Ac%nBW%)atR>+iW[*\iIrZR%3.U#B#Uo(T=JCmKc%S"U;"]8V#W;cg^1lhu1gQn`Bh^YWH=,QH%E^E;do]=_q&g'S#WId8cKH_uV?pDPM)p46A>_WH*7<TuP2^'+BF=_V/[7kb:Z%[R9QufiFh?O3c4DbiB\UAV^[>FUbe-KWW=%OD$QU=(-7a\Q/&JBZ*RT1K6-qe6:BtN^ZBgkA"F#7B&Ba8rKLUI'uV@./@5V_B$<.Hk\Y>CDOR.gBp*VZQb`_A&#0!T;AVjcP!0UXa6qESbdE,b6\NoZ!`E$NVrG7=uN/n@ki3&5NfTkQH%6SRm!U$-X"`rFT[H>#*,L_R'fV4dIYp\;>l;U@>^3D"!,SR19EM<9h1bt5T#9S1(_c\,6MT!nh\is1N998=]QW/<rRX/6Q9.6#&#bi7qoMu>sAjjhAoamXTu)b,fp\`S/(_FZWDV!]Jm4?@]-:V#V"mDWtjOV$!&[m;p/XAd4Zs`G*(E#b?b-NZW;Nt):T>^%r</:q]\X6ML-*KG+_%[AO(P-O94]JI'a@LKN8u'&j19PPp2KslCD@u<G@H%V1NNZ>D)c+XHeE.!NH?F6rM-=OK@;.9=p9d!]Q[VKeP^$]8!*<REa-;>=K;h>8?,">7k66MKmpdh]*s2*:S:;:9IsXO-8qp57UlN$.l%(Z<GGU8LY8E9Z9D8Zb^@SQ)#R)Vj/ck<1N&Lq9&<UXn,1SMF4%8OB/ucn:AQr><V[7:0sonQC::Ma^E.)/.e=U2l6-!)Z7%lIQn^O#'Z!OX32YZnt'X/NI]4tjCT8Wfk.X,l3'V_AcXnF*TOY*4C%dlfCsY-~>endstream
115
+ endobj
116
+ 17 0 obj
117
+ <<
118
+ /Filter [ /ASCII85Decode /FlateDecode ] /Length 1662
119
+ >>
120
+ stream
121
+ Gb!;cCQI1/'`C51ii5m&VO`%m,_T^??"s/&G.N+h%]WPZr=BSDmNsi7%$[pkhtPhrJ1r7tN]PT@8-G)khq,F%(^^beWVoM2JB(#:4f:PN(f#VX`/!;%GW%\\HpfL.5mRQW,%2=B\,m``3cOtF"N9srl4&92:U^jLHA&oX*='J%2tq=HEc\R0cR"gk42hp2]\itFXFOEKGXm3lM2"[#(\;,RIY-NA'?;3iDT:]/2mM^6EX"U63qgC=:ioN'KdkKAW.kr)Cs'^'XQ;dbbBOm,'2,L(aI1D:0+*[SO@V+bdtM6[XLOk<bGW*BGi*-&3aOQBhL,HD7De=(HJ9/^O=1l["u-ClWpJnKhHZ;:0:k@[;6Rd=$2Xmtb[_p>4Ir!!9/\gX>r;t`ef"]8]s^De_%N%'5%Sd^;C7QLB)k6I)M#RA^k(@,m^DQL(nl/>VP%S'XNH/gR4XhYN/pu?et?SW^q-3!2:aV+(+C%u]4rOr9WlUCFH]'tp,\Pho0,R^Bl>VFng2WKK5E/&R.-%H(s[AW!6?odj[s&=:+ZT(0)i;n"A;ioR'>lFbdsO\Bl8:BW8!iW^`QD*^]+$Kf<"JHr=/X*m'6U5*e]&R9ADft!#P)ZG^Rj6,D"lDXpYAlSN`'X&G_QFHg!_hW8Q'Yd%Z.rFF<lLorF-Zl1Nlr<cX#/SK+)L#,0!L/b)e_Q@t!q]IR%cY[;5K]a[.b/'9rgfo)D6^fPf&hg0^tp58fJai40%h)4Ul2'n)JF^\/'=E&Ro7Jle`dX2ZTHI"tUmY;Uc42;:40#atJ$#()5+`&:^gN*.D3n<iqRZjlp_J>Li=WE7_E4\k,qK9bf%fgInG,"He<3OEC#FYRF>T#FM1j3JQgu[1L#&TTU_t4TggEfDg'.s]?%TR=*onaB:<\YE%<:KXeipf"/.b5AT^HLQ\62Zfu$ti%tOTsmbdP&r0))JiECW$@=r6jN;5iStf0LiXr!sJe%c:^<-ek)6nFu?p-Q,!dWi=f<JaCWLL'_Ak7)T@D'Lf%TDdV$8Z6n5-'Um;d979&9@@(KP_I+hmda1J=HgC,\;f0%@R<uZEd&7.cZK(&j1VVO>sWmE-G,t,D]8F-XsY@]]@.s7%c,PB]J),Fk@*b26-2TiD$fhC%4U@$*`m.Y6G'^J)l]X&2V^V'iCs.>YBQY5d53d'/QiN4@kh4RcHWC)/3WH#dpl<pBVV6H*I@aXace(nnO4@_"4nA!S(K.:mb1m6^-SR"<aN&.%jP2T*P]:'Voc8ErD=$3YbZghLhWNn,b;'iH24G=ae3pL!cKm<Ob&RmW:e,J2Zo/]$g0'/n\$h&9.R3ff=N:$Hj3MPTG8*(g/o6o-#;[L::SXE3PG=KU`)k260r;+uu3uWf;;acC`6JVu@_k:k8;)3&\X0iS7Ag.`7[BrO.V_s:M1cBd2DH_J+^*#;12MABP>NEX]'&]p5TlB]U)7%t^`1g4(jC0B5V;enf61SPb[cPac_iB%iN*Qq65%Pt''q6^STK(Oi4D3;/AF1i#'i79F/4NgP;4YKjaW-h_GV[utViGi-PH1\3g>1*s2?q"tS#aH]8HK^9;7.MD+B'L\iCOWN]eKCSAMsYr3R]dP&jdMtM7.=<q&!fYYu[UHXKWhHTt4fLTg>367ZTU@Y^\5@2E8@L1`ZH%hLa;0~>endstream
122
+ endobj
123
+ 18 0 obj
124
+ <<
125
+ /Filter [ /ASCII85Decode /FlateDecode ] /Length 1952
126
+ >>
127
+ stream
128
+ Gb!#\D,8nW&H9tY(a2nH2AiW)@Y\8cU'3#A=(icBI3<oVm5<Rtm7k9;+?J>.^Y-#Y(m?r)V'd9OE>#HfkN/+EAsRsus$XO*$,HE]*+'7"-4D+A[Vj"PG;p]4rR`@F9%O0s13Ch]Gk_Eud#$Md>lr::bt!0D&T=`=d(Es$HR[TdjFM.[h/o2OfE92C]RRWh"i[2_o.<fY',=)h&?3tFK`_FVTC,k#Eig/0liFKR@lU4q9.BWbpfZb*J4IE'S3G:.VLHP_D_Vt<nI0dgBF]J2o>&Zi:PF6'_`qT)>)>96KCRq%<,e!t6.9((5,L$-=b'lW#?lJg'Ui'C8",U<HXtJ^4OEt[2)%`if1J2clK3CcNnPO%`b#7H_kfM_C&ZZ/md<a(:7!<F4%OTeA"BS6Vp]'"D?!Qfg[@G.5):9HAkW$mh2HV@2[3^d77!a[9i?bDTl)"$C1&g4P#+3RYS<TQasF!nOX>=(_*!8Z@ifT;&k5$ojTu*V9JSf.M%'7EY\j.6^g$0^]]IgP'dM$>qgd)91EYWYT=N$GqTu6oCT^[RhQ-cu=6_IZ1BI8s*)k'X$%15N6rb?[A/>"9.npWL!=a2H"7lROKj^T7-4<n9.?*45+7h(T/RUU3@hs[SEM;qN.I_&&^_G0iDme/"D_:Kof"UctC"^q_\N^W3`-"_C*ab;b?#@Z(5DEad^bRGge_7PZ%>JPq-kaW]a9jTrV)4;5-r;1@r`-"Yc84O_Lt7]^)m3b@puQL"ZYl0*hJ11J#D$kajt!P>OOmH:=^L/ESdH#'UM[Z,p*ru$=W[+#E>`nfMB\g:!tD6)(:#C6"H-CHO*:+8UYYi"/\\&INqD*F4q9;?(e3]qEK&WG+K"sc5Y01bJQ6OJa,":Db5@BgrXh]q<.E8AOOIUM^pd.0NXho_;D&+XP_RQB'RFOHT/\1n:MMSXBN]s(r/?OCB7STb9o.D/%4og?F#i/-dSOLY]DM!flfiheIDg2UWY)\7pVF04CYK-<,hr&*#Sgn+6F%V!DXum.c,VrrogSN8c,.lU&U_=,*F<'#KFc[9\&4]abH'U(r4TYJ[1[AYKDGt=C!t0`UuWmfaQ(t!7JG=6aCUE_gQ&XQ#LS2&GPaV"_!A:NN9Z\BMp'<S/lQT\a\T0IPL]SA-+f08Bq<l0p9ZokXqmC9)^ZNBOX<^^_o?K$T'@oM:lD\fb0.G#_]*ON+Qr[1fG<t[N$,R8q05=>n(9eCnX6m]61*T`<AE&'hBog7LZhd_IU8018NfG*8+(PA1cETmfKmsJjLno"M1Zt;M+[AlATK<V+_)hi\5k9:G3sLi@^A>cNPo-2M]Fs9R!OB=g.H/d2f9#R%R0`uoOE(FkU2\%"S'"o^kqD8r$f\K2p^-@@6]R[Z\hO][%&>Fq&\!Elno?+9o9"/+t[W2A*W*`2FX2(-k#1>^L)"j^lq>`T5)'QhGEG<F-+P4=Xi20MNG];Rpg57)j+"WDO?%A)eo7UNqR5lJK9aM+)s,qOMK<0pgAPd3sr0]Z6:g2A4:E\/N.2'k2=_p;JOQ^:!TAYM,`"HV/Ut34(D-@j(k)*JB2@XX^N($oeA*@`gAtW8;nqf;k+TA)hhWgn4<)'#r,l)GM*m(),DAc,021X78\W4ipoc6_/aGU73#@'&/%$W`?^be%t/oV,Z@48Y9f'H1K(.A1X5Hhpt9%,7rOZ\)3*n1Drfs$;[rC3.0BenMLu`Qb\%TZimCa`amDS=V!n6*K,.Ui]C5,hlc(,X]$D`2e$3n10l74@d,hn(]MR*+'t'<a$UmeGdc#eSlC?m\P-Y9SF^(D6LfO]$=p<*+a6dep#U@B;19b`qOsBUA)UR2p$=Y>3@Vk^)Fm'_:@)`T)c5*-Z-[:TTQ4l82#a*COB.iICVEAp.FCAH8YKQ`.<^ggjC-cST?!V5[B6//8Cj*Y[UTh<#iJ(gP7't!O.bJWE"k`\W!DhEl~>endstream
129
+ endobj
130
+ 19 0 obj
131
+ <<
132
+ /Filter [ /ASCII85Decode /FlateDecode ] /Length 2017
133
+ >>
134
+ stream
135
+ Gau0D9lo#Z&A@sBFF:r0TJ2N_OAl_.Z*U6rfJ.49Yj=YH"&'nQfU3>QCFfF5]13rjfTNSDXJl7?BkFq`^\><N#$lU2q]7'aDl<*qM?.d,\cCkS5"r0=EdI<.#qPH1&"rCaSAASm^_M(pQ`t3@eq[sk$Yc$bLs\[tqbg(#9ii=[@/:Tkp0^GC=ppH^',bFPaE6"%SJ@L7[4OqZ=igrX,*"t\5_U^j8-K$1![WGDbTY>:/CT9M#0\PN\:PY/!T(#cQtlrH$OH+5dpJcU$"=L_=t6k?Z&j("$j/O3KZ:.#1hu&7%g">8Hk;s@J*!BG!t8aU!eEENV`YOLqi%^G#[OWcnG#oUHk0M<p!<S#KB(:ipUFgnQgN[Lr2Gu0.JV7-JF>55mJ"oB`G[cLrPbAkS9MZ?l[jaJGC)^T*;YU'B\cuXOTllWP;!hU7PH<.l]2RO0;Cb$o'>uFs%<t5A)5=;i%_G(_=?]@/=>UeGmsH<Gkht)Y[/Nu7(NN&>!f(/q;sY:!A/*VhG0sNPFLkkj%o,PqWfH_hVGiX^ALOZ+5Aoff7kZ5b`&l/+uM+GqK-279BVQ#X^`NGHoa?9?1G>`*U*'\2iu+:a3Khe]XZpXFQ4>Kl1I>=@KEf9[DRn]OCiJp4+i$_Er^\2&%u4j7G<!+&7"%cng)8sM8:j3'[cosn%`GXJ)pB#EgO=:B.e4a@-NC'\^42tg*eMEd>-q6DksAA:Xdah%P=eZJ60fTpU1iKR&Q1^Jr>m&V6c0tD4k?7KulI.8tn0hKqHndn+Q$_^`P`\>4/g\.k5"tY0b4*=9qR*Q73\](o389/^-6EABps+PGK1.,a'kle<2%,Qe"J8Dlu!/X*_!p\jI=O'bA'!FUH4NdiF/640m4(]JSfmF5/"R#@&!`nlG`K%l;+u7VhW$opGC(TrY[d+2,kj8bV)h]A%[_P+.)W/oY\o)H`(`#<n+'?,F\FHlE<XKM&=*Dc!C&Ej_.$[Ep-b^,B+*2cnK&C*WJ-hU=l&O&`O8Fh01E$o%B,[!l?glurWJ2M-gR"GUD.N&=!9.r;4$'V\+MHmm<!Cq8Xm=="X<!t$Uq.FuN&19muF7nGfIpRm_OD].n\RGnB`>FEHPEf,g\pV^OW_u#OA1$TETQXm'DR]9W>/UQkd$(:%JCc^0'd8UFCmmV=A($XK^RLo2tX;:>4mhoBpjsBLKpm%L7LH4jaduZkH9oB!'F`_,@IXQV3%pRAB]LS'><$VK=6RH"R`=Q`#B2O[3at]2d$8De]<F^uhQF6.Rs4fnY`qoYo!U=0f^2``s0S)[\G`I(RG?gnIBgFNq&Q`Ud*@`eQSgok@ZlUFH!#D(p)R[\XV:.mgLlgrrNap]p'!ALQ&KTKV4;N7.4#>TP84i),3H88[OK"D'KdBoV'qWdn5hE-/L&E&Y7/@oJf6l#sJ&?%g(;uR62/(AgI6&`G4tSTl8d<;4_@HGfk*TYUAFeA\qa=_[6YdN?%\rE'GLmDLV$LqWP2I:q]FrCf-fu?h6c;?c&SZ)TO_LDjZL+WT:G5`$G26oaME&m;BQ(^lDE&CEPJH*9+_!T.EPpP^3+<Irf<S*t#`V!J,Xqcg>+;LOW4E]R9MKY@6hW=8Iq^tdL/q6ra[*<EF/^Zo,<[R_OR)1.;AB\o`jo7U+]XF[O%@N\`26:i5.Vb5(asnG0hu7/YbegG!=R5?.cO&Z,M4*hq$QG55LGs+VeG'+#Ao6j*E/7aNfB`Yoq=/7bV@<K^YAFL<DD=#W282P]'GFt2Boq6lTPbZ8uC)UdCD)b]VajqXA<HcYK"&HcKO7+\\5%gV96^2YCgqbi>,4NHt_!sT0N#`b'',C_uE4JoUi@UU5uErR#qt-6M$&r=N$tO`h0DOmQNi*?NLV(0$UAc_pQDBQE,7;oFPm/lfQThs3h!^'Pn^D'IrB*jMF)KUjQrp]3PK5,ka3nOD0?ikW]KE]U*;Lc#f9r4WEZkXqnh230:bqcbEa\VKE_Z$[NY=Z\RWp6H^PmPS?0fFg2/m!@RmK7c+a(~>endstream
136
+ endobj
137
+ 20 0 obj
138
+ <<
139
+ /Filter [ /ASCII85Decode /FlateDecode ] /Length 1969
140
+ >>
141
+ stream
142
+ Gatm<gJ[&k&:L1S;"6;L$TrFsll/#O'jJlkfJd+N>DY5YP#mg1aaX2[QL-YBP&Qhg:g=W9l9;-CS/*jFiY@7;8^>sqp[#dtbi0\UT<WVP%G:Ug]=`Xfn%6)93M*HpIi(m,B+mCY&+E-&hBa5Lqja4#UH%\%H['jn?"f;'CJ;?`_op>.k91mVGp_/u]Dmm+6Ztp,3gW'!;L3'Lq-7T?J(Qm?@7sP!Pke#:m0BgZ?[]K`o[<pAk9KE-j^-/4]2.?`;u5u#IO6D^cWU#V:Sf6d^]+C-+M3YIJn5H5&^@)7m@ujoq0[=u,:[34='hG)hu%PB\\7Rm3,4HV'Ar;*b!rSLAn1/%dFfjD%IgtHqf()hO/qL04ETuuOiWqa=CP1ES<cSe]ONb9rV--,-0#+KPBiiiNo,)sJEmp8o=WR.WSat4C#bZk3dec?i_q.je,e%8RY=F(b&T1F-!)^F3'NSrBX0k]_:_;p;*=7U#A5UQ%Jk'obTco?)u]t+Y<no&i__sK&eGmJlrHZ:I$9X7]+Nh5WTWVOUNA&j8cNIG+pq[toh=$:rF'nWc;XY*-Yf:.)oB6AR\Jk8RAC;4\s;k2BAP=2Ta,VR([qY(TTZ=Cno8e.ZlG@fJ.5>ReEUH3%F=_p2&qV5^dY`TEY.eGB/te-Lsc_!)G9L.V0S*\C`8_4VnAscn6ioHrUKTQ;76?h<g03#*"c3AA;*BJZ_d:s?0ACgTI@mUo3dO3[+a7Kp"!'h&lfW<U3/_@:$/&QZ]Fim5FB)Dq]OpA#/)@94)c@Oe+tkrQ'Bi4NB+J/_P;3q.Z$*._GUZT!r:'AaTH3*pUjL^l&+>612O5n'R%('g>.)3.!&g.,$61_2g0>\]LXg+.0V.m8["(A%)sIu2DsV/i=nJ&7XbT[ppU<KSuc`&$$,4pG"n[R%Vr"6Ugs1'AcaIZ0f+YpL#OW'3(p=]%EtnNU8fR^[\a9PaGd='aRWp(ChsI5j#FhG$b-RSrQH[(80Q-oQT2orgt*obgp%#a&fcc#0LkU-[pjG0Q=u1^(caV.a>lYV$gnRHV1jW-OH#btX3&SrY0goKoW+]!]Z-4KZ?7`IN\\nRP.p4NLL[\M')rIZ5t`dPF,a=KR8`.'i\2JoK"ptUIm!^!0ApS_5^o$&li,XQj'=&!ldmeG^JY]9IP76&?6J3@QCo`nGd8M^RILI/Y$c9c,Qb>Q$e944>_3#gEfN1KHfq5W&Ar$pi5m!mU-I?B`=k[hWIka!4"[6E<JC>,Z!1/O*uAB5K;Fd@<8DOqE%2IC=p:\.iUUNCJB8hU-B@h3e(Y^D?:jKDHP@urA:RnJH&.uTIoSuKm&;%%Qc=VV<%b&KgbC)s`EG)pi'O1Zkk@@$L6-Sq-jNjhY/AKGpe3O)*))*&+#OC(aYAWG@@$,X;PD\RSX(l=jp]Qt9R:Wi+/ZlD@CcY3</]sY-+pEZX]cpm%7t/jUSLp0dRNh+26*657qIi,@Hri+1oOm5Y]Pr.;O0qj,*mhGXq=p3T2HP`E**[i7VNmn;Ph&,/J/PU`ki8_FK`G$T'i*,=^SYhJDbTLPb*],hE=kJ+]M8>rT$:d,^"\?6cS2S9`-:I$0r1G$"oja\S.7knG6MrbX,ATWl-\')NW0m0dZ'BU6]5leW/9Tl$Yp6Dl2D\&k$G7lA?U>5-79bZ4)9jg2ag"JRlCC4&o9>PioOgWP^ahp.beip]Z\ej&UR&at!)$4P!h?"mLsiD^$@FGZ3F1$eSD)pnmn?'MOM4esSSkJt'l.X"]-',@r]eDBOSk+Jpm!!E8=*qa(t4>=^TJ_N=lJKlOF&hm\D";rF+3_g$A!j7slYANd)1j?=<#[BBY5)`GK_V2capU&)1sS2cnS,h2X7[-Io5[i`<;oarnE^`#tmWS<i='g=H>HNch;.KbBs=Wq21obE1eUEK@B9;^jl;*4Wud)Y-&S3XE+@hP'j2+)XpFDZ`ETLf>`n6k_a#JUBf$3~>endstream
143
+ endobj
144
+ 21 0 obj
145
+ <<
146
+ /Filter [ /ASCII85Decode /FlateDecode ] /Length 900
147
+ >>
148
+ stream
149
+ Gas1]968f@&AI`dp..7&`]O;_[V9dGjO1ue>S_UEe]<n(a\_tb=)1J98NY.@Qs&hEpQBR,k$K`JeGstKi:B;Gq$`,fnjU!;iXtU:dB?Dr4LnY5C;.pCle=:@E8at-IQQQGr%p$56.,2'3TPHM.npqsN1X<P]$^qM.g^gXD+cTKjZI2qC$RKg]7mlN.0k2?CI!+gD>A^VL2;N56>t>@b%!eck?kEcp^+ne(o&I_/ctH;)r):iR1O.cf"7J*WItI#H&X.]03:L[oD?A=[iB&P'??$Zc2.-mI[70LbJc&DZc,&!Y96Kqg%([VZX/\1j>WgR>4bp/E9F;X?-pmr&'rMcT6QZ[eJXsf0'(3_[MN;0'f-';?sM2BJ>^uo#d0(T>7)pkGFL5'#rJ30\oB#7^b'?J[\6d1Nhg.)=sqqK_UIPPFaN\\DtI/;2^_,4+[g'#.*bOXeo*5RPghZ3\0pk$hBu:8L%ji/2<$RX_-(`Be<TWIR]ZEmNm4psb5`h0au-<-koYi+.?WX7]PnrcZDPsnm)U8aK.c0jlt`_<&5`Li#s*crBqCWR%@p:9d?oJ:o2%J.aP(nP"@aU\OSlPg$WX9E$,/20HHW:I*KN0Rh?!QRjkK_;0\Li<Y8=4g9O2SJaA^'H^UHL6iS.7o.%B]8*SRM!&]8BTJsI8D9MAsK<@0GOhN9C"6X'Wj-InqZ"qTF:N;;KQH7:L#XiRDj8R/:@SCY0:Utdj0^-#M63,8U+^_5Bc#a8TDrcne1G6:"iFWVUlfJ-u.!pE>oZ(cIS:1B$h#Wjl32&,<e>#^a7apBbHO@Wm)as3fNH'4gEoVpud(ca+E"aj60K75!tR5$budVGecQ03sC\X&8Y,UWFQ-!1fj/,AFkPE"mEM-b7*/fk05r;i1&`K^~>endstream
150
+ endobj
151
+ xref
152
+ 0 22
153
+ 0000000000 65535 f
154
+ 0000000073 00000 n
155
+ 0000000144 00000 n
156
+ 0000000251 00000 n
157
+ 0000000363 00000 n
158
+ 0000000478 00000 n
159
+ 0000000597 00000 n
160
+ 0000000802 00000 n
161
+ 0000000907 00000 n
162
+ 0000001112 00000 n
163
+ 0000001317 00000 n
164
+ 0000001523 00000 n
165
+ 0000001729 00000 n
166
+ 0000001935 00000 n
167
+ 0000002005 00000 n
168
+ 0000002289 00000 n
169
+ 0000002382 00000 n
170
+ 0000004296 00000 n
171
+ 0000006050 00000 n
172
+ 0000008094 00000 n
173
+ 0000010203 00000 n
174
+ 0000012264 00000 n
175
+ trailer
176
+ <<
177
+ /ID
178
+ [<6161c847c487331f71cdbc5a1598b1d8><6161c847c487331f71cdbc5a1598b1d8>]
179
+ % ReportLab generated PDF document -- digest (http://www.reportlab.com)
180
+
181
+ /Info 14 0 R
182
+ /Root 13 0 R
183
+ /Size 22
184
+ >>
185
+ startxref
186
+ 13255
187
+ %%EOF