commit 299332dd4ef5f28197d30f087bc9d70a296d2f0e Author: Cyber MacGeddon Date: Wed Jul 10 17:04:24 2024 +0100 Trustgraph, first drop of code diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..fdd19e0a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*~ +__pycache__/ +env/ +*.egg_info/ diff --git a/Containerfile b/Containerfile new file mode 100644 index 00000000..e01bd7a2 --- /dev/null +++ b/Containerfile @@ -0,0 +1,54 @@ + +# ---------------------------------------------------------------------------- +# Build an AI container. This does the torch install which is huge, and I +# like to avoid re-doing this. +# ---------------------------------------------------------------------------- + +FROM docker.io/fedora:40 AS ai + +ENV PIP_BREAK_SYSTEM_PACKAGES=1 + +RUN dnf install -y python3 python3-pip python3-wheel python3-aiohttp \ + python3-rdflib + +RUN pip3 install torch --index-url https://download.pytorch.org/whl/cpu + +RUN pip3 install anthropic google-cloud-aiplatform langchain langchain-core \ + langchain-huggingface langchain-text-splitters langchain-community \ + pymilvus sentence-transformers transformers huggingface-hub \ + pulsar-client && \ + pip3 cache purge + +# ---------------------------------------------------------------------------- +# Build a container which contains the built Python package. The build +# creates a bunch of left-over cruft, a separate phase means this is only +# needed to support package build +# ---------------------------------------------------------------------------- + +FROM ai AS build + +env PACKAGE_VERSION=0.0.0 + +COPY setup.py /root/build/ +COPY README.md /root/build/ +COPY scripts/ /root/build/scripts/ +COPY trustgraph/ root/build/trustgraph/ + +RUN (cd /root/build && pip3 wheel -w /root/wheels --no-deps .) + +# ---------------------------------------------------------------------------- +# Finally, the target container. Start with base and add the package. +# ---------------------------------------------------------------------------- + +FROM ai + +COPY --from=build /root/wheels /root/wheels + +RUN pip3 install /root/wheels/trustgraph-* && \ + pip3 cache purge && \ + rm -rf /root/wheels + +WORKDIR / + +CMD sleep 1000000 + diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..f7fbdc72 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ + +# VERSION=$(shell git describe | sed 's/^v//') +VERSION=0.1.16 + +all: container + +CONTAINER=docker.io/trustgraph/trustgraph-flow + +container: + podman build -f Containerfile -t ${CONTAINER}:${VERSION} \ + --format docker + +push: + podman push ${CONTAINER}:${VERSION} + +start: + podman run -i -t --name ${NAME} \ + -i -t \ + -p 8081:8081 \ + -v $$(pwd)/keys:/keys \ + -v $$(pwd)/configs:/configs \ + ${CONTAINER}:${VERSION} + +stop: + podman rm -f ${NAME} + +clean: + rm -rf wheels/ + +# sed -i 's/0.1.15/0.1.16/' docker-compose*.yaml diff --git a/README.md b/README.md new file mode 100644 index 00000000..a6c28209 --- /dev/null +++ b/README.md @@ -0,0 +1,151 @@ + +# For AMD... +# pip3 install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/rocm6.1/ + +---------------------------------------------------------------------------- + +docker network create trustgraph --driver bridge + +docker volume create cassandra +docker volume create pulsar-conf +docker volume create pulsar-data +docker volume create etcd +docker volume create minio-data +docker volume create milvus + +---------------------------------------------------------------------------- + +Cassandra: +docker run -i -t \ + --name cassandra \ + --network trustgraph \ + -p 9042:9042 \ + -v cassandra:/var/lib/cassandra \ + docker.io/cassandra:4.1.5 + +---------------------------------------------------------------------------- + +Pulsar: + +docker run -it \ + --name pulsar \ + --network trustgraph \ + -p 6650:6650 \ + -p 8080:8080 \ + -v pulsar-conf:/pulsar/conf \ + -v pulsar-data:/pulsar/data \ + docker.io/apachepulsar/pulsar:3.3.0 \ + bin/pulsar standalone + +---------------------------------------------------------------------------- + +Milvus: + +docker run -i -t \ + --name etcd \ + --network trustgraph \ + -p 2379:2379 \ + -e ETCD_AUTO_COMPACTION_MODE=revision \ + -e ETCD_AUTO_COMPACTION_RETENTION=1000 \ + -e ETCD_QUOTA_BACKEND_BYTES=4294967296 \ + -e ETCD_SNAPSHOT_COUNT=50000 \ + -v etcd:/etcd \ + quay.io/coreos/etcd:v3.5.5 \ + etcd -advertise-client-urls=http://127.0.0.1:2379 \ + -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd + +docker run -i -t \ + --name minio \ + --network trustgraph \ + -p 9000:9000 -p 9001:9001 \ + -e MINIO_ACCESS_KEY=minioadmin \ + -e MINIO_SECRET_KEY=minioadmin \ + -v minio-data:/minio_data \ + docker.io/minio/minio:RELEASE.2024-07-04T14-25-45Z \ + minio server /minio_data --console-address :9001 + +docker run -i -t \ + --name milvus \ + --network trustgraph \ + -p 19530:19530 -p 9091:9091 \ + -e ETCD_ENDPOINTS=etcd:2379 \ + -e MINIO_ADDRESS=minio:9000 \ + -v milvus:/var/lib/milvus \ + docker.io/milvusdb/milvus:v2.4.5 \ + milvus run standalone + +---------------------------------------------------------------------------- + +. env/bin/activate + +scripts/pdf-decoder -p pulsar://localhost:6650/ +scripts/chunker -p pulsar://localhost:6650/ +scripts/vectorize-minilm -p pulsar://localhost:6650/ +scripts/kg-extract-definitions -p pulsar://localhost:6650/ +scripts/kg-extract-relationships -p pulsar://localhost:6650/ +scripts/vector-write-milvus -p pulsar://localhost:6650/ +scripts/graph-write-cassandra -p pulsar://localhost:6650/ +scripts/llm-ollama-text -p pulsar://localhost:6650/ -r http://monster:11434/ + +---------------------------------------------------------------------------- + +The pub/sub infra means individual processors can be switched out for other +processors which do the same thing e.g. + +- graph-write writes to Cassandra but could be switched out for something else + which uses a different store +- vector-store writes to Milvus but could be switched out for something which + writes to a different store +- llm-ollama invokes Ollama, could be switched out for a different LLM with a + different API + +The vectorizer is a bit hard to switch out ATM, different embedding algorithms +have different vector dimensions, but can probably make that work. + +kg-extractor turns chunks into edges, so maybe that could be switched out for +different algorithms & different schemas. Potentially a good place for 'value +add' processing to be added. + +It would also be possible to have more than one processor running where +kg-extractor sits to have different kinds of semantic extraction: other +proceessors could take as input the output of vectorizer, and drop edges and +edge associations into graph-write and vector-store + +Actually, as it stands, kg-extractor does 2 different kinds of processing +itself: + +- Creates edges for relationships, and +- Creates edges for definitions + +Each of those uses its own LLM invocation and mashes the output into RDF. It +would be useful to split kg-extractor into 2 pieces to demonstrate this bit of +the architecture. + +---------------------------------------------------------------------------- + +- pdf-extractor turns a PDF doc into plain text. For each PDF page, a + separate blob of text is emitted currently. +- chunker applies chunking to turn 1 PDF page into several chunks +- vectorizer invokes a sentence embedding model to create vectors. Doesn't + store anything. Output of vectorizer is chunk plus embedding. +- kg-extract turns chunks into edges using LLM prompting. There are 2 outputs: + - RDF triples + - An association between the vector embedding and RDF entities. For every + triple, there's an association between the S, P and O entiites and the + embedding. +- graph-write loads the triples into a store +- vector-store store the association between the vector and the RDF URI in a + vector store + +---------------------------------------------------------------------------- + +The demo query algorithm is... + +- Take the question, extract embeddings using a sentence model +- Use the vector store to lookup RDF URIs +- Use the RDF URIs to find relevant RDF triples in Cassandra +- Also use Cassandra to turn RDF URIs into plain-text labels if they are known +- Construct the prompt, turn RDF triples into a knowledge graph format (used + Cypher, seems to work but not sure that's the best choice) +- LLM prompt and show the answer + diff --git a/architecture.png b/architecture.png new file mode 100644 index 00000000..deb30c7c Binary files /dev/null and b/architecture.png differ diff --git a/architecture.svg b/architecture.svg new file mode 100644 index 00000000..86a0cad5 --- /dev/null +++ b/architecture.svg @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + loader + + + + + pdfdecoder + + + + chunker + + + + vectorizer + + + + kgextractor + + + + llmollama + + + + graphwrite + + + + vectorstore + + + + Pulsar + + + + Ollama + + + + GPUhardware + + + + Milvus + + + + Cassandra + + + + + + + + + + + + + + + + + + Embeds + + + + + RDFedges + + + + + diff --git a/collate-graph b/collate-graph new file mode 100755 index 00000000..c43bca90 --- /dev/null +++ b/collate-graph @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +import os +import rdflib + +dir="graph" +g = rdflib.Graph() + +files = os.listdir(dir) + +for file in files: + + try: + cg = rdflib.Graph() + file = dir + "/" + file + cg.parse(file, format="turtle") + + for t in cg: + g.add(t) + except Exception as e: + print(f"{file}: {str(e)}") + +g.serialize(destination="graph.ttl") + diff --git a/do-query b/do-query new file mode 100644 index 00000000..af2841ce --- /dev/null +++ b/do-query @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 + +from trustgraph.graph_rag import GraphRag + +gr = GraphRag() + +query="""This knowledge graph describes the Space Shuttle disaster. +Present 20 facts which are present in the knowledge graph.""" + +# embed = gr.get_vector(query) +# print(embed) + +#entities = gr.get_entities(query) +#for ent in entities: +# print(ent) + +# nodes = gr.get_nodes(query) +# for node in nodes: +# print(node) + +#sg = gr.get_subgraph(query) +#for edge in sg: +# print(edge) + +#lg = gr.get_labelgraph(query) +#for edge in lg: +# print(edge) + +# oc = gr.get_cypher(query) +# print(oc) + +# pr = gr.get_graph_prompt(query) +# print(pr) + +resp = gr.query(query) + +print(resp) + diff --git a/docker-compose-azure.yaml b/docker-compose-azure.yaml new file mode 100644 index 00000000..1a86ed9e --- /dev/null +++ b/docker-compose-azure.yaml @@ -0,0 +1,172 @@ + +volumes: + cassandra: + pulsar-conf: + pulsar-data: + etcd: + minio-data: + milvus: + +services: + + cassandra: + image: docker.io/cassandra:4.1.5 + ports: + - "9042:9042" + volumes: + - "cassandra:/var/lib/cassandra" + restart: on-failure:100 + + pulsar: + image: docker.io/apachepulsar/pulsar:3.3.0 + command: bin/pulsar standalone + ports: + - "6650:6650" + - "8080:8080" + volumes: + - "pulsar-conf:/pulsar/conf" + - "pulsar-data:/pulsar/data" + restart: on-failure:100 + + pulsar-manager: + image: docker.io/apachepulsar/pulsar-manager:v0.3.0 + ports: + - "9527:9527" + - "7750:7750" + environment: + SPRING_CONFIGURATION_FILE: /pulsar-manager/pulsar-manager/application.properties + restart: on-failure:100 + + etcd: + image: quay.io/coreos/etcd:v3.5.5 + command: + - "etcd" + - "-advertise-client-urls=http://127.0.0.1:2379" + - "-listen-client-urls" + - "http://0.0.0.0:2379" + - "--data-dir" + - "/etcd" + environment: + ETCD_AUTO_COMPACTION_MODE: revision + ETCD_AUTO_COMPACTION_RETENTION: "1000" + ETCD_QUOTA_BACKEND_BYTES: "4294967296" + ETCD_SNAPSHOT_COUNT: "50000" + ports: + - "2379:2379" + volumes: + - "etcd:/etcd" + restart: on-failure:100 + + minio: + image: docker.io/minio/minio:RELEASE.2024-07-04T14-25-45Z + command: + - "minio" + - "server" + - "/minio_data" + - "--console-address" + - ":9001" + environment: + MINIO_ROOT_USER: minioadmin + MINIO_ROOT_PASSWORD: minioadmin + ports: + - "9001:9001" + volumes: + - "minio-data:/minio_data" + restart: on-failure:100 + + milvus: + image: docker.io/milvusdb/milvus:v2.4.5 + command: + - "milvus" + - "run" + - "standalone" + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + ports: + - "9091:9091" + - "19530:19530" + volumes: + - "milvus:/var/lib/milvus" + restart: on-failure:100 + + pdf-decoder: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "pdf-decoder" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + chunker: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "chunker-recursive" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + vectorize: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "embeddings-vectorize" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + embeddings: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "embeddings-hf" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + kg-extract-definitions: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "kg-extract-definitions" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + kg-extract-relationships: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "kg-extract-relationships" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + vector-write: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "vector-write-milvus" + - "-p" + - "pulsar://pulsar:6650" + - "-t" + - "http://milvus:19530" + restart: on-failure:100 + + graph-write: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "graph-write-cassandra" + - "-p" + - "pulsar://pulsar:6650" + - "-g" + - "cassandra" + restart: on-failure:100 + + llm: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "llm-azure-text" + - "-p" + - "pulsar://pulsar:6650" + - "-k" + - ${AZURE_TOKEN} + - "-e" + - ${AZURE_ENDPOINT} + restart: on-failure:100 + diff --git a/docker-compose-claude.yaml b/docker-compose-claude.yaml new file mode 100644 index 00000000..5999725e --- /dev/null +++ b/docker-compose-claude.yaml @@ -0,0 +1,170 @@ + +volumes: + cassandra: + pulsar-conf: + pulsar-data: + etcd: + minio-data: + milvus: + +services: + + cassandra: + image: docker.io/cassandra:4.1.5 + ports: + - "9042:9042" + volumes: + - "cassandra:/var/lib/cassandra" + restart: on-failure:100 + + pulsar: + image: docker.io/apachepulsar/pulsar:3.3.0 + command: bin/pulsar standalone + ports: + - "6650:6650" + - "8080:8080" + volumes: + - "pulsar-conf:/pulsar/conf" + - "pulsar-data:/pulsar/data" + restart: on-failure:100 + + pulsar-manager: + image: docker.io/apachepulsar/pulsar-manager:v0.3.0 + ports: + - "9527:9527" + - "7750:7750" + environment: + SPRING_CONFIGURATION_FILE: /pulsar-manager/pulsar-manager/application.properties + restart: on-failure:100 + + etcd: + image: quay.io/coreos/etcd:v3.5.5 + command: + - "etcd" + - "-advertise-client-urls=http://127.0.0.1:2379" + - "-listen-client-urls" + - "http://0.0.0.0:2379" + - "--data-dir" + - "/etcd" + environment: + ETCD_AUTO_COMPACTION_MODE: revision + ETCD_AUTO_COMPACTION_RETENTION: "1000" + ETCD_QUOTA_BACKEND_BYTES: "4294967296" + ETCD_SNAPSHOT_COUNT: "50000" + ports: + - "2379:2379" + volumes: + - "etcd:/etcd" + restart: on-failure:100 + + minio: + image: docker.io/minio/minio:RELEASE.2024-07-04T14-25-45Z + command: + - "minio" + - "server" + - "/minio_data" + - "--console-address" + - ":9001" + environment: + MINIO_ROOT_USER: minioadmin + MINIO_ROOT_PASSWORD: minioadmin + ports: + - "9001:9001" + volumes: + - "minio-data:/minio_data" + restart: on-failure:100 + + milvus: + image: docker.io/milvusdb/milvus:v2.4.5 + command: + - "milvus" + - "run" + - "standalone" + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + ports: + - "9091:9091" + - "19530:19530" + volumes: + - "milvus:/var/lib/milvus" + restart: on-failure:100 + + pdf-decoder: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "pdf-decoder" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + chunker: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "chunker-recursive" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + vectorize: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "embeddings-vectorize" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + embeddings: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "embeddings-hf" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + kg-extract-definitions: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "kg-extract-definitions" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + kg-extract-relationships: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "kg-extract-relationships" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + vector-write: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "vector-write-milvus" + - "-p" + - "pulsar://pulsar:6650" + - "-t" + - "http://milvus:19530" + restart: on-failure:100 + + graph-write: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "graph-write-cassandra" + - "-p" + - "pulsar://pulsar:6650" + - "-g" + - "cassandra" + restart: on-failure:100 + + llm: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "llm-claude-text" + - "-p" + - "pulsar://pulsar:6650" + - "-k" + - ${CLAUDE_KEY} + restart: on-failure:100 + diff --git a/docker-compose-ollama.yaml b/docker-compose-ollama.yaml new file mode 100644 index 00000000..d7d0f36f --- /dev/null +++ b/docker-compose-ollama.yaml @@ -0,0 +1,178 @@ + +volumes: + cassandra: + pulsar-conf: + pulsar-data: + etcd: + minio-data: + milvus: + +services: + + cassandra: + image: docker.io/cassandra:4.1.5 + ports: + - "9042:9042" + volumes: + - "cassandra:/var/lib/cassandra" + restart: on-failure:100 + + pulsar: + image: docker.io/apachepulsar/pulsar:3.3.0 + command: bin/pulsar standalone + ports: + - "6650:6650" + - "8080:8080" + volumes: + - "pulsar-conf:/pulsar/conf" + - "pulsar-data:/pulsar/data" + restart: on-failure:100 + + pulsar-manager: + image: docker.io/apachepulsar/pulsar-manager:v0.3.0 + ports: + - "9527:9527" + - "7750:7750" + environment: + SPRING_CONFIGURATION_FILE: /pulsar-manager/pulsar-manager/application.properties + restart: on-failure:100 + + etcd: + image: quay.io/coreos/etcd:v3.5.5 + command: + - "etcd" + - "-advertise-client-urls=http://127.0.0.1:2379" + - "-listen-client-urls" + - "http://0.0.0.0:2379" + - "--data-dir" + - "/etcd" + environment: + ETCD_AUTO_COMPACTION_MODE: revision + ETCD_AUTO_COMPACTION_RETENTION: "1000" + ETCD_QUOTA_BACKEND_BYTES: "4294967296" + ETCD_SNAPSHOT_COUNT: "50000" + ports: + - "2379:2379" + volumes: + - "etcd:/etcd" + restart: on-failure:100 + + minio: + image: docker.io/minio/minio:RELEASE.2024-07-04T14-25-45Z + command: + - "minio" + - "server" + - "/minio_data" + - "--console-address" + - ":9001" + environment: + MINIO_ROOT_USER: minioadmin + MINIO_ROOT_PASSWORD: minioadmin + ports: + - "9001:9001" + volumes: + - "minio-data:/minio_data" + restart: on-failure:100 + + milvus: + image: docker.io/milvusdb/milvus:v2.4.5 + command: + - "milvus" + - "run" + - "standalone" + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + ports: + - "9091:9091" + - "19530:19530" + volumes: + - "milvus:/var/lib/milvus" + restart: on-failure:100 + + pdf-decoder: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "pdf-decoder" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + chunker: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "chunker-recursive" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + vectorize: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "embeddings-vectorize" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + embeddings: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "embeddings-hf" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + kg-extract-definitions: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "kg-extract-definitions" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + kg-extract-relationships: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "kg-extract-relationships" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + vector-write: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "vector-write-milvus" + - "-p" + - "pulsar://pulsar:6650" + - "-t" + - "http://milvus:19530" + restart: on-failure:100 + + graph-write: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "graph-write-cassandra" + - "-p" + - "pulsar://pulsar:6650" + - "-g" + - "cassandra" + restart: on-failure:100 + + llm: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "llm-ollama-text" + - "-p" + - "pulsar://pulsar:6650" + - "-r" + - "http://${OLLAMA_HOST}:11434/" + restart: on-failure:100 + + graph-rag: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "graph-rag" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + diff --git a/docker-compose-vertexai.yaml b/docker-compose-vertexai.yaml new file mode 100644 index 00000000..e7e14be2 --- /dev/null +++ b/docker-compose-vertexai.yaml @@ -0,0 +1,174 @@ + +volumes: + cassandra: + pulsar-conf: + pulsar-data: + etcd: + minio-data: + milvus: + +services: + + cassandra: + image: docker.io/cassandra:4.1.5 + ports: + - "9042:9042" + volumes: + - "cassandra:/var/lib/cassandra" + restart: on-failure:100 + + pulsar: + image: docker.io/apachepulsar/pulsar:3.3.0 + command: bin/pulsar standalone + ports: + - "6650:6650" + - "8080:8080" + volumes: + - "pulsar-conf:/pulsar/conf" + - "pulsar-data:/pulsar/data" + restart: on-failure:100 + + pulsar-manager: + image: docker.io/apachepulsar/pulsar-manager:v0.3.0 + ports: + - "9527:9527" + - "7750:7750" + environment: + SPRING_CONFIGURATION_FILE: /pulsar-manager/pulsar-manager/application.properties + restart: on-failure:100 + + etcd: + image: quay.io/coreos/etcd:v3.5.5 + command: + - "etcd" + - "-advertise-client-urls=http://127.0.0.1:2379" + - "-listen-client-urls" + - "http://0.0.0.0:2379" + - "--data-dir" + - "/etcd" + environment: + ETCD_AUTO_COMPACTION_MODE: revision + ETCD_AUTO_COMPACTION_RETENTION: "1000" + ETCD_QUOTA_BACKEND_BYTES: "4294967296" + ETCD_SNAPSHOT_COUNT: "50000" + ports: + - "2379:2379" + volumes: + - "etcd:/etcd" + restart: on-failure:100 + + minio: + image: docker.io/minio/minio:RELEASE.2024-07-04T14-25-45Z + command: + - "minio" + - "server" + - "/minio_data" + - "--console-address" + - ":9001" + environment: + MINIO_ROOT_USER: minioadmin + MINIO_ROOT_PASSWORD: minioadmin + ports: + - "9001:9001" + volumes: + - "minio-data:/minio_data" + restart: on-failure:100 + + milvus: + image: docker.io/milvusdb/milvus:v2.4.5 + command: + - "milvus" + - "run" + - "standalone" + environment: + ETCD_ENDPOINTS: etcd:2379 + MINIO_ADDRESS: minio:9000 + ports: + - "9091:9091" + - "19530:19530" + volumes: + - "milvus:/var/lib/milvus" + restart: on-failure:100 + + pdf-decoder: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "pdf-decoder" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + chunker: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "chunker-recursive" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + vectorize: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "embeddings-vectorize" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + embeddings: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "embeddings-hf" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + kg-extract-definitions: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "kg-extract-definitions" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + kg-extract-relationships: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "kg-extract-relationships" + - "-p" + - "pulsar://pulsar:6650" + restart: on-failure:100 + + vector-write: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "vector-write-milvus" + - "-p" + - "pulsar://pulsar:6650" + - "-t" + - "http://milvus:19530" + restart: on-failure:100 + + graph-write: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "graph-write-cassandra" + - "-p" + - "pulsar://pulsar:6650" + - "-g" + - "cassandra" + restart: on-failure:100 + + llm: + image: docker.io/trustgraph/trustgraph-flow:0.1.16 + command: + - "llm-vertexai-text" + - "-p" + - "pulsar://pulsar:6650" + - "-k" + - "/vertexai/private.json" + - "-r" + - "us-west1" + volumes: + - "./vertexai:/vertexai" + restart: on-failure:100 + diff --git a/etl b/etl new file mode 100755 index 00000000..0191d766 --- /dev/null +++ b/etl @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 + +import pulsar +from pulsar.schema import JsonSchema, Bytes +from schema import Chunk, Triple, Value +from langchain_huggingface import HuggingFaceEmbeddings +from langchain_community.llms import Ollama +from trustgraphETL import scholar, callmixtral, build_graph_robust +import sys +import rdflib + +g = rdflib.Graph() +g.parse("out2.ttl") + +client = pulsar.Client("pulsar://localhost:6650") + +consumer = client.subscribe( + 'chunk-load', 'etl', + schema=JsonSchema(Chunk), +) + +producer = client.create_producer( + topic='graph-load', + schema=JsonSchema(Triple), +) + +while True: + + msg = consumer.receive() + + try: + + v = msg.value() + print("Indexing {} {}...".format(v.path, v.num)) + + chunk = v.chunk.decode("utf-8") + + s = scholar(chunk) + resp = callmixtral(s) + + try: + g = build_graph_robust([resp]) + + for s, p, o in g: + + sv = Value(value=str(s), is_uri=True) + pv = Value(value=str(p), is_uri=True) + + if isinstance(o, rdflib.term.URIRef): + ov = Value(value=str(o), is_uri=True) + else: + ov = Value(value=str(o), is_uri=False) + + t = Triple(s=sv, p=pv, o=ov) + + producer.send(t) + + except Exception as e: + print("Exception: ", e) + + print("Done.") + + # Acknowledge successful processing of the message + consumer.acknowledge(msg) + + except Exception as e: + + print(e) + + # Message failed to be processed + consumer.negative_acknowledge(msg) + +client.close() + diff --git a/etl2 b/etl2 new file mode 100755 index 00000000..43adefb6 --- /dev/null +++ b/etl2 @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 + +import pulsar +from pulsar.schema import JsonSchema, Bytes +from schema import Chunk, Triple, Value +from langchain_huggingface import HuggingFaceEmbeddings +from langchain_community.llms import Ollama +from trustgraphETL2 import scholar, callmixtral, build_graph_robust +import sys +import rdflib + +g = rdflib.Graph() +g.parse("out2.ttl") + +client = pulsar.Client("pulsar://localhost:6650") + +consumer = client.subscribe( + 'chunk-load', 'etl', + schema=JsonSchema(Chunk), +) + +producer = client.create_producer( + topic='graph-load', + schema=JsonSchema(Triple), +) + +while True: + + msg = consumer.receive() + + try: + + v = msg.value() + print("Indexing {} {}...".format(v.path, v.num)) + + chunk = v.chunk.decode("utf-8") + + s = scholar(chunk) + resp = callmixtral(s) + + try: + g = build_graph_robust([resp]) + + for s, p, o in g: + + sv = Value(value=str(s), is_uri=True) + pv = Value(value=str(p), is_uri=True) + + if isinstance(o, rdflib.term.URIRef): + ov = Value(value=str(o), is_uri=True) + else: + ov = Value(value=str(o), is_uri=False) + + t = Triple(s=sv, p=pv, o=ov) + + producer.send(t) + + except Exception as e: + print("Exception: ", e) + + print("Done.") + + # Acknowledge successful processing of the message + consumer.acknowledge(msg) + + except Exception as e: + + print(e) + + # Message failed to be processed + consumer.negative_acknowledge(msg) + +client.close() + diff --git a/graph-clear b/graph-clear new file mode 100755 index 00000000..9633a08f --- /dev/null +++ b/graph-clear @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 + +from trustgraph import TrustGraph + +t = TrustGraph() + +t.clear() + diff --git a/graph-dump b/graph-dump new file mode 100755 index 00000000..e31a1c3b --- /dev/null +++ b/graph-dump @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +import pulsar +from pulsar.schema import JsonSchema, Bytes +from schema import Chunk, Triple +from langchain_huggingface import HuggingFaceEmbeddings +from langchain_community.llms import Ollama +from trustgraphETL import scholar, callmixtral, build_graph_robust +import sys +import rdflib +import uuid + +g = rdflib.Graph() + +client = pulsar.Client("pulsar://localhost:6650") + +consumer = client.subscribe( + 'graph-load', 'graph-dump', + schema=JsonSchema(Triple), +) + +g = rdflib.Graph() +count = 0 +limit = 100 + +while True: + + msg = consumer.receive() + + try: + + v = msg.value() + + if v.o.is_uri: + g.add(( + rdflib.term.URIRef(v.s.value), + rdflib.term.URIRef(v.p.value), + rdflib.term.URIRef(v.o.value), + )) + else: + g.add(( + rdflib.term.URIRef(v.s.value), + rdflib.term.URIRef(v.p.value), + rdflib.term.Literal(v.o.value), + )) + + count += 1 + + if count > limit: + + id = str(uuid.uuid4()) + path = f"graph/{id}.ttl" + g.serialize(destination=path) + g = rdflib.Graph() + print(f"Written {path}") + + count = 0 + + # Acknowledge successful processing of the message + consumer.acknowledge(msg) + + except Exception as e: + + print(e) + + # Message failed to be processed + consumer.negative_acknowledge(msg) + +client.close() + diff --git a/graph-out b/graph-out new file mode 100755 index 00000000..4c305d92 --- /dev/null +++ b/graph-out @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +import pulsar +from pulsar.schema import JsonSchema, Bytes +from schema import Chunk, Triple +from langchain_huggingface import HuggingFaceEmbeddings +from langchain_community.llms import Ollama +from trustgraphETL import scholar, callmixtral, build_graph_robust +import sys +import rdflib + +g = rdflib.Graph() +g.parse("out2.ttl") + +client = pulsar.Client("pulsar://localhost:6650") + +consumer = client.subscribe( + 'graph-load', 'graph-dump', + schema=JsonSchema(Triple), +) + +while True: + + msg = consumer.receive() + + try: + + v = msg.value() + + print( + v.s.value, + v.p.value, + v.o.value, + ) + + # Acknowledge successful processing of the message + consumer.acknowledge(msg) + + except Exception as e: + + print(e) + + # Message failed to be processed + consumer.negative_acknowledge(msg) + +client.close() + diff --git a/query b/query new file mode 100755 index 00000000..7a6a3599 --- /dev/null +++ b/query @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 + +from langchain_huggingface import HuggingFaceEmbeddings +from edge_map import VectorStore +from trustgraph import TrustGraph +from llm_ollama import Llm + +LABEL="http://www.w3.org/2000/01/rdf-schema#label" +DEFINITION="http://www.w3.org/2004/02/skos/core#definition" + +embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") + +client = VectorStore() + +tg = TrustGraph() + +entity_limit=50 +query_limit=30 +max_sg_size=3000 + +query = """Explain how CISA contributes to incident management in the +US government economy""" + +# query = """Explain in a step-by-step form how CISA helps new legislation to emerge for national security""" + +query = """An insider threat has been discovered inside CISA. +The employee has been discovered to be stealing data using admin credentials. +Provide 3 theories as to the cause of the failure in hiring this individual, +referencing oversight information in the knowledge graph provided. +""" + +query = """An insider threat has been discovered inside CISA. +Their job title is Protective Security Advisor. What threats are posed +to to CISA by the compromise of somoene in this role? +Provide 3 hypothetical compromise scenarios which could be cause by +someone in such a role being compromised as an inside threat. +""" + +query = """Provide three hypothetical causes for the space shuttle +disaster. For each hypothesis, provided a set of step-by-step events +which lead to the disaster. +""" + +qembeds = embeddings.embed_documents([query])[0] + +res = client.search( + qembeds, + limit=entity_limit +) + +entities = set([ + item["entity"]["entity"] + for item in res +]) + +subgraph = set() + +for e in entities: + + res = tg.get_s(e, limit=query_limit) + for p, o in res: + subgraph.add((e, p, o)) + + res = tg.get_p(e, limit=query_limit) + for s, o in res: + subgraph.add((s, e, o)) + + res = tg.get_o(e, limit=query_limit) + for s, p in res: + subgraph.add((s, p, e)) + +subgraph = list(subgraph) + +subgraph = subgraph[0:max_sg_size] + +cache = {} + +def maybe_label(e): + + if e in cache: + return cache[e] + + res = tg.get_sp(e, LABEL) + res = list(res) + + if len(res) == 0: + cache[e] = e + return e + + cache[e] = res[0][0] + return cache[e] + +sg2 = [] + +for edge in subgraph: + + if edge[1] == LABEL: + continue + + s = maybe_label(edge[0]) + p = maybe_label(edge[1]) + o = maybe_label(edge[2]) + + sg2.append(f"({s})-[{p}]->({o})") + +prompt=f"""Study the knowledge graph provided, and use +the information to answer the question. The question should be answered +in plain English only. + + +{"\n".join(sg2)} + + +{query} + +""" + +print(prompt) + +print(len(prompt)) + +# llm = Llm("deepseek-v2") +# llm = Llm("gemma2") +llm = Llm("phi3:14b") +resp = llm(prompt) + +print(resp) + diff --git a/receive b/receive new file mode 100755 index 00000000..c32a3492 --- /dev/null +++ b/receive @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +import pulsar + +client = pulsar.Client("pulsar://localhost:6650") + +consumer = client.subscribe('my-topic', 'my-subscription') + +while True: + msg = consumer.receive() + try: + print("Received message '{}' id='{}'".format( + msg.data(), msg.message_id() + )) + # Acknowledge successful processing of the message + consumer.acknowledge(msg) + except Exception: + # Message failed to be processed + consumer.negative_acknowledge(msg) + +client.close() + diff --git a/receive2 b/receive2 new file mode 100755 index 00000000..82c013fe --- /dev/null +++ b/receive2 @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import pulsar +from pulsar.schema import JsonSchema +from schema import Triple, Value + +client = pulsar.Client("pulsar://localhost:6650") + +consumer = client.subscribe( + 'my-topic2', 'my-subscription', + schema=JsonSchema(Triple), +) + +while True: + msg = consumer.receive() + try: + +# print("Received message '{}' id='{}'".format( +# msg.data(), msg.message_id() +# )) + + v = msg.value() + + print( + "{} -- {} --> {}".format( + v.s.value, + v.p.value, + v.o.value, + ) + ) + + # Acknowledge successful processing of the message + consumer.acknowledge(msg) + except Exception: + # Message failed to be processed + consumer.negative_acknowledge(msg) + +client.close() + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..7bfcf3ba --- /dev/null +++ b/requirements.txt @@ -0,0 +1,16 @@ +torch +urllib3 +transformers +sentence-transformers +rdflib +pymilvus +langchain +langchain-core +langchain-huggingface +langchain-text-splitters +langchain-community +huggingface-hub +cassandra-driver +pulsar-client +anthropic +google-cloud-aiplatform diff --git a/scripts/chunker-recursive b/scripts/chunker-recursive new file mode 100755 index 00000000..2356903d --- /dev/null +++ b/scripts/chunker-recursive @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.chunker.recursive import run + +run() + diff --git a/scripts/embeddings-hf b/scripts/embeddings-hf new file mode 100755 index 00000000..a7d84d04 --- /dev/null +++ b/scripts/embeddings-hf @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.embeddings.hf import run + +run() + diff --git a/scripts/embeddings-vectorize b/scripts/embeddings-vectorize new file mode 100755 index 00000000..3de1e3a9 --- /dev/null +++ b/scripts/embeddings-vectorize @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.embeddings.vectorize import run + +run() + diff --git a/scripts/graph-rag b/scripts/graph-rag new file mode 100755 index 00000000..a6dab1f3 --- /dev/null +++ b/scripts/graph-rag @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.rag.graph import run + +run() + diff --git a/scripts/graph-show b/scripts/graph-show new file mode 100755 index 00000000..26e6cbff --- /dev/null +++ b/scripts/graph-show @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 + +from trustgraph.trustgraph import TrustGraph + +t = TrustGraph() + +rows = t.get_all(limit=100_000_000) +for s, p, o in rows: + print(s, p, o) + diff --git a/scripts/graph-to-turtle b/scripts/graph-to-turtle new file mode 100755 index 00000000..1bd48802 --- /dev/null +++ b/scripts/graph-to-turtle @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +from trustgraph.trustgraph import TrustGraph +import rdflib +import sys +import io + +t = TrustGraph() + +g = rdflib.Graph() + +rows = t.get_all(limit=100_000_000) +for s, p, o in rows: + +# print(s, p, o) + sv = rdflib.term.URIRef(s) + pv = rdflib.term.URIRef(p) + + if o.startswith("https://") or o.startswith("http://"): + + # Skip malformed URLs with spaces in + if " " in o: + continue + + ov = rdflib.term.URIRef(o) + else: + ov = rdflib.term.Literal(o) + + g.add((sv, pv, ov)) + +g.serialize(destination="output.ttl", format="turtle") + +buf = io.BytesIO() + +g.serialize(destination=buf, format="turtle") + +sys.stdout.write(buf.getvalue().decode("utf-8")) diff --git a/scripts/graph-write-cassandra b/scripts/graph-write-cassandra new file mode 100755 index 00000000..7fc3d0c8 --- /dev/null +++ b/scripts/graph-write-cassandra @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.graph.cassandra_write import run + +run() + diff --git a/scripts/init-pulsar-manager b/scripts/init-pulsar-manager new file mode 100755 index 00000000..6e855ffb --- /dev/null +++ b/scripts/init-pulsar-manager @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +CSRF_TOKEN=$(curl http://localhost:7750/pulsar-manager/csrf-token) + +curl \ + -H "X-XSRF-TOKEN: $CSRF_TOKEN" \ + -H "Cookie: XSRF-TOKEN=$CSRF_TOKEN;" \ + -H 'Content-Type: application/json' \ + -X PUT \ + http://localhost:7750/pulsar-manager/users/superuser \ + -d '{"name": "admin", "password": "apachepulsar", "description": "test", "email": "username@test.org"}' diff --git a/scripts/kg-extract-definitions b/scripts/kg-extract-definitions new file mode 100755 index 00000000..327ec06f --- /dev/null +++ b/scripts/kg-extract-definitions @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.kg.extract_definitions import run + +run() + diff --git a/scripts/kg-extract-relationships b/scripts/kg-extract-relationships new file mode 100755 index 00000000..91040589 --- /dev/null +++ b/scripts/kg-extract-relationships @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.kg.extract_relationships import run + +run() + diff --git a/scripts/llm-azure-text b/scripts/llm-azure-text new file mode 100755 index 00000000..cdaea4b8 --- /dev/null +++ b/scripts/llm-azure-text @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.llm.azure_text import run + +run() + diff --git a/scripts/llm-claude-text b/scripts/llm-claude-text new file mode 100755 index 00000000..496d1440 --- /dev/null +++ b/scripts/llm-claude-text @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.llm.claude_text import run + +run() + diff --git a/scripts/llm-ollama-text b/scripts/llm-ollama-text new file mode 100755 index 00000000..cb7a4ebc --- /dev/null +++ b/scripts/llm-ollama-text @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.llm.ollama_text import run + +run() + diff --git a/scripts/llm-vertexai-text b/scripts/llm-vertexai-text new file mode 100755 index 00000000..4634015f --- /dev/null +++ b/scripts/llm-vertexai-text @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.llm.vertexai_text import run + +run() + diff --git a/scripts/loader b/scripts/loader new file mode 100755 index 00000000..a6dc4450 --- /dev/null +++ b/scripts/loader @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +import pulsar +from pulsar.schema import JsonSchema, Bytes, String +from trustgraph.schema import Document, Source +import base64 +import hashlib + +# client = pulsar.Client("pulsar://localhost:6650") +host="10.89.1.246" +host="localhost" +client = pulsar.Client(f"pulsar://{host}:6650") + +producer = client.create_producer( + topic='document-load', + schema=JsonSchema(Document), + chunking_enabled=True, +) + +files=[ + "Challenger-Report-Vol1.pdf", +# "columbia-accident-investigation-board-report-volume-1.pdf", +# "Proposed_CIRCIA_Rules.pdf", +] + +for file in files: + + path = "sources/" + file + data = open(path, "rb").read() + + id = hashlib.sha256(path.encode("utf-8")).hexdigest()[0:8] + + r = Document( + source=Source( + source=path, + title=path, + id=id, + ), + data=base64.b64encode(data), + ) + + resp = producer.send(r) + + print(resp) + +client.close() + diff --git a/scripts/pdf-decoder b/scripts/pdf-decoder new file mode 100755 index 00000000..82b89298 --- /dev/null +++ b/scripts/pdf-decoder @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.decoder.pdf import run + +run() + diff --git a/scripts/query b/scripts/query new file mode 100755 index 00000000..5cb5c0c6 --- /dev/null +++ b/scripts/query @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 + +from trustgraph.graph_rag import GraphRag +import sys + +query = " ".join(sys.argv[1:]) + +gr = GraphRag(verbose=True) + +if query == "": + query="""This knowledge graph describes the Space Shuttle disaster. +Present 20 facts which are present in the knowledge graph.""" + +resp = gr.query(query) +print(resp) + diff --git a/scripts/vector-write-milvus b/scripts/vector-write-milvus new file mode 100755 index 00000000..952e22cf --- /dev/null +++ b/scripts/vector-write-milvus @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from trustgraph.vector.milvus_write import run + +run() + diff --git a/send b/send new file mode 100755 index 00000000..7f5c454a --- /dev/null +++ b/send @@ -0,0 +1,12 @@ +#!/usr/bin/env python3 + +import pulsar + +client = pulsar.Client("pulsar://localhost:6650") + +producer = client.create_producer('my-topic') + +for i in range(10): + producer.send(('Hello-%d' % i).encode('utf-8')) + +client.close() diff --git a/send2 b/send2 new file mode 100755 index 00000000..762a50cc --- /dev/null +++ b/send2 @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +import pulsar +from pulsar.schema import JsonSchema +from schema import Triple, Value + +client = pulsar.Client("pulsar://localhost:6650") + +producer = client.create_producer( + topic='my-topic2', + schema=JsonSchema(Triple), +) + +for i in range(10): + + r = Triple( + s = Value(is_uri=True, value="https://example.org"), + p = Value(is_uri=True, value="https://example.org"), + o = Value(is_uri=True, value="https://example.org"), + ) + + producer.send(r) + +client.close() + diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..2ad4db47 --- /dev/null +++ b/setup.py @@ -0,0 +1,65 @@ +import setuptools +import os + +with open("README.md", "r") as fh: + long_description = fh.read() + +version = "0.0.0" + +setuptools.setup( + name="trustgraph", + version=version, + author="trustgraph.ai", + author_email="security@trustgraph.ai", + description="trustgraph.ai", + long_description=long_description, + long_description_content_type="text/markdown", + url="https://github.com/trustgraph.ai/FIXME.git", + packages=setuptools.find_packages(), + classifiers=[ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", + "Operating System :: OS Independent", + ], + python_requires='>=3.8', + download_url = "https://github.com/trustgraph.ai/FIXME.git/archive/refs/tags/v" + version + ".tar.gz", + install_requires=[ + "torch", + "urllib3", + "transformers", + "sentence-transformers", + "rdflib", + "pymilvus", + "langchain", + "langchain-core", + "langchain-huggingface", + "langchain-text-splitters", + "langchain-community", + "huggingface-hub", + "requests", + "cassandra-driver", + "pulsar-client", + "pypdf", + "anthropic", + "google-cloud-aiplatform", + ], + scripts=[ + "scripts/chunker-recursive", + "scripts/graph-show", + "scripts/graph-to-turtle", + "scripts/graph-write-cassandra", + "scripts/kg-extract-definitions", + "scripts/kg-extract-relationships", + "scripts/llm-ollama-text", + "scripts/llm-vertexai-text", + "scripts/llm-claude-text", + "scripts/llm-azure-text", + "scripts/loader", + "scripts/pdf-decoder", + "scripts/query", + "scripts/embeddings-vectorize", + "scripts/embeddings-hf", + "scripts/vector-write-milvus", + "scripts/graph-rag", + ] +) diff --git a/sources/Challenger-Report-Vol1.pdf b/sources/Challenger-Report-Vol1.pdf new file mode 100644 index 00000000..58dc559e Binary files /dev/null and b/sources/Challenger-Report-Vol1.pdf differ diff --git a/sources/Columbia-Aeromedical.pdf b/sources/Columbia-Aeromedical.pdf new file mode 100644 index 00000000..eb408700 Binary files /dev/null and b/sources/Columbia-Aeromedical.pdf differ diff --git a/sources/Columbia-Ars-Technica.pdf b/sources/Columbia-Ars-Technica.pdf new file mode 100644 index 00000000..ae543f4e Binary files /dev/null and b/sources/Columbia-Ars-Technica.pdf differ diff --git a/sources/Columbia-Crew-Survivability.pdf b/sources/Columbia-Crew-Survivability.pdf new file mode 100644 index 00000000..c2e73bd5 Binary files /dev/null and b/sources/Columbia-Crew-Survivability.pdf differ diff --git a/sources/Columbia-Disaster-Wiki.pdf b/sources/Columbia-Disaster-Wiki.pdf new file mode 100644 index 00000000..40964223 Binary files /dev/null and b/sources/Columbia-Disaster-Wiki.pdf differ diff --git a/sources/Columbia-NASA-Decisions.pdf b/sources/Columbia-NASA-Decisions.pdf new file mode 100644 index 00000000..5535781d Binary files /dev/null and b/sources/Columbia-NASA-Decisions.pdf differ diff --git a/sources/Columbia-Options-Assessment.pdf b/sources/Columbia-Options-Assessment.pdf new file mode 100644 index 00000000..1bf4341c Binary files /dev/null and b/sources/Columbia-Options-Assessment.pdf differ diff --git a/sources/Columbia-Report-Full.pdf b/sources/Columbia-Report-Full.pdf new file mode 100644 index 00000000..f74d9f81 Binary files /dev/null and b/sources/Columbia-Report-Full.pdf differ diff --git a/sources/Proposed_CIRCIA_Rules.pdf b/sources/Proposed_CIRCIA_Rules.pdf new file mode 100644 index 00000000..f0d7e0e0 Binary files /dev/null and b/sources/Proposed_CIRCIA_Rules.pdf differ diff --git a/sources/columbia-accident-investigation-board-report-volume-1.pdf b/sources/columbia-accident-investigation-board-report-volume-1.pdf new file mode 100644 index 00000000..e91ec94b Binary files /dev/null and b/sources/columbia-accident-investigation-board-report-volume-1.pdf differ diff --git a/sources/nasa-gb-871913.pdf b/sources/nasa-gb-871913.pdf new file mode 100644 index 00000000..8730387a Binary files /dev/null and b/sources/nasa-gb-871913.pdf differ diff --git a/sources/prospect-theory.pdf b/sources/prospect-theory.pdf new file mode 100644 index 00000000..dd172792 --- /dev/null +++ b/sources/prospect-theory.pdf @@ -0,0 +1,4698 @@ +%PDF-1.4 +% +4 0 obj <>stream +Gau0Cfl#h.'ReS7nAT&B`3f4a7F>_8)0EG89f*$2RKukUMn0c&;cp(oAk(@$((b2hH$G9oVo4amRY=)qh/65^bKpnLaOI/id'"S4m/1RL**K;RRer92+rHY'#.`K(hO7-1pjYoc&f?jO=@)fYI2-H)XFNu!PosEXW77G$8CcV_^&uHW@@G[<7%!*`a2IkjRG@hDKTM$IEXBn5P@5=r]eq>7p$.";_(QUhR[kDrS&Lsh=EYVI&"j3Q^IS_`ue]ECoG]kk"GB%F'hV_p1(*7\*?1lAYm1)%rM_RFP0ndp"%e1Pbi7'*maqE%_0GtX]SO^AngHgfL6#*qd(8tT>"q3gS[#.S@b1?AXYiSKnb1H3]E&R>`dPR0okR=4*'nT?QcuMXm[.m-r22FEUWan+ff]9N:a_p&3od"M:5,\K0bW=+P)[C5Yri0gWVclkpI===58AA9lIh_nkA@A/WQPL\k`CFaR&QDZuA:"M_MCk6J:A3*g+hGXMQUF+=ghR2Ja8:nG6PTBbn\U/fVpuqL3T,'bN8]8Gf,Rf!9uD\]W>E6J#"aF&D2;o))ds@njs(T+4-P__b*i35H0C\-R#_oN\_[3!]@".!$k^jiVie-^[%EVe^k$aX!$+J)kp>M!H6.VLhfTTr_nUU,Xag~> + +endstream +endobj +6 0 obj <>stream +Gb"/id;fCLN^NdF5FoH`;SLu:!D#hq0&^Ya#rmIja_]6"o?Yt;e^`4#e^`4#e^`4#e^`4#e^`4#e^`2MR=;2-QnB:o)Pb?!WH@kmnKmoLN%bF*7?FUcQ3,OS]UsgPo?&dG"%i"9_q6-slqY!_Cg\J%Uo(r'0Q[LaheQ%Io=+#/`mCHZpe^_.pgV3g2+8j%AlKT;ls1C:>MnU<]_hqMs-O'O_2h$\!+FM(a='$aQs1C:>MnU<]_hqMs-Y7Z/@g2[TL:k)Y-MZc;nQYVhi>Yg&%+Ug!U&MOTV^$8"#^lf*a2SJ'pC3L@S>2h1(o/;gQ")rIP[eVIK^Y;2O>b1[,$tQQ0b#,CaG""@i*-B\V#e15;%kb0C=]#>4ke1Ii`o6']LYp3*kpI=*Mh$jo>-H"AW/Na$I8G^FTOjRo0o-=aM1U2`=77iaCm`@]0uNJV;;@6SO]7@+0-[^P1H,gQRLO/?s*g2>=uR8ni+6rM+KJ!Wq(lg[5qEoHSLerO(=:o4ILm>YB;@P91&%q;PbV7p5J,o(BPQgKGSf='pl#m@s[8YA8@;?mI.>48Bl`&jbZb=_L(=q-A?dNDK!flcFto&D6?\S[nP#UH&6SFq=?\K,F>JMqn.3?TU'dnC.V;2TA.B-buf7JEs1H]AW5rC#c$4F@3KJ=WCo]RJ3rVp.R&B"@UtH2K[4HBY=%EPD*qTdGKD7n/n@`GOi=OFe=^N-nFj*UY,"apV*d8F9i@]F[#d2Z6k,"9TVbBrjPR0kQe)L(F9(&L8]>\'SEUJ&,t[$sP)&6:K_Hf>(CfK4]M85J4W.<4<(L+GJ>iqf]Me;3h1G,8p4S3b=b23<J#s):,R"L$l-@?VhH1$8&XYIik7O=4BFQjp)/M=7lLlsI`_f/Mrh?M#B'#kB'B&gg6&hjA8i]Tboj.kn..lY`/2;_R9IcO.O]?*Yr?pt0J0.IS$$[]Q:X;p_jNDq-W3(PGk&>[EPYXGVX2)8hDtGDd0f<[!T09;p1e,I(L]4X)54N&71oI\Y5,uX:!u5cRSNQ&u+#4%o_,4?T/Uo/,:f1"l[W`oId-q\<:o5$"@j?)a:etE^o^o1;YY!6kE\\E-]F4BXCT938c]FR)_\@Qd(Jd?:dU''h/N#WuE[p'WsiU\B_sUYMl`d[BiTW>=Jr^N(-#`#d8-U]Mc-M9\BN3LFgb$`8K5LT;IN9&3ML;IngP]h/IY9A0i)?b"rIQm^Z#E(feI3>r7/k@I4(*$,W_^0!F?FP5M@IRoG(UGKe9/[BOk[,D[>jej$'q)--;+@ZkdZBTK1Gij/8ASL%Wau_FpBf>L5(a'B%,4'k_tb,D*OQl,G#^1[LAj"HfXRtO9G<**X=?5@jRr3>3EX+8Lh>@eD[C\_Mcu,lkY8@p*&6l6Y"Q'eZ#iP5n`h`gQLQa;RLCs-b60lIo;A8g.,GAb(nFmYBSL'bJk-4^WiNo'rD[#_n0=Lo7HJs6jFOL;tUml?7\!N)M':Y<)*h)08Gu=#]HedA;!'CGH]T.@RD@jJ:p;[3-u4%jO6,A4[BY9)f"sYH'1=MqM'k:]u7DOI&j8j"OD_R$/?]FDf<$rO=H2m'-kIF+$*KbI\$tLq?ekPE`F\I5nH49=8+8"kns_T^2KOo0Jh#;RD?X68X>VEXf?&="lYZ'p$Ldn4p#9!eLQf.ArVt*cqOisDlO/U,rt]*_WOEn.Nh^LQU-[h2Pb=co&kl>8\mn*k`uabCDnCO*o;?3rfZ)R8`[=^7oGi<53&\\B!K[?JQjJbd=c_fB-i\#$c5t>Vb4qRR!Us'=k4N][QKfP.Yol==c*nE0p`^]$GmU^-V7cBRX7.dQK0^@bN3m'ik/!O+pCW`-&-u&n73)O9l[k\#`m-LP5HVO\\-GH8T0fhRVY45+i%2[%1N[KcU*`['=o7WenalTAU:@a!5Y[(7^8hs*PSodnV4b#ZRgD/7GP#ma3H4-!!0#cRFV&1n]"QB/'HogK;)*E1%]tT69,d/4AARbj\;@7O.kt>5_q5b]$h^#`7ftUc]9mB+o-#H(Y#V'b'A%YsD.E!+H=D"WW^UHcpih4]$GuC#eD(Jn&[`5i9?%eOP'>$0fK)tHhu,iO:dI8_!+j>$?6_L!;i9<.;(f?WmT\0bF`+9CL;hG,\cGXUF'--OLHj>Ug+BDcq]mS=n.Di$G>dE67\*Q)&.jD7Y5jOBL69tQZPG?a=f,]\A8X5`Q,U!Q"7MO+,4Bh3Z'-0i/.ZA1bTqZZ]"qDJTqN9A:?&=X.!QCm$+?K)JUMIOq:S!?5c*e0AKus+M;]%3JG%K*!%uG-;Y^c92@Fmj%3]B`[t$i%#N?pfKD[4+?XAY8#o)?&PE?r[;k:A)*CKF+Amh!N_(HH*B$U=.`bBm9"S)CEq?,[XhrH/7#u=;9G1`i,f(=ZSr&dk7hD9!;l@f+Ea-DH;,t!4:QX*]@gS;T$g7.U]W=,Fn>)V[?A;9sK5;Ej7'#?!ZQp09hk2`:iT]3).:SqmI-lGpS.ZKrbuR$!2hF=8,Is0Ek!bA.mk4@,.EJ.:0`J2PP+(K)VG!aV&BDk1-*`^tMS8W-rHIdY_5/(m3EBBTC0E-1B6YFH2CpHF<9OgtY=g;H"lXaCNks\YI>N6^b[%C(0[n"Q($!u.P$.S-7*V/I#gYSENY0)O;V?*DdEtkn`J2JMRCe/K:ut7g&l5c4OC,#u4C`1KYA1C$ac:g##Se:j.fAN1lK"$EcOq`WEM+G%Alp,>NN$7Vd[*0IaUMtt`J1V`YD^g\;C>sV.#=+8OZe7_U6kE[qKa6:P&YqB]6@+;A8u_!;S&"7."'#bJVbK&qLHT8U.JZ6e3,ss$]K/p?!fnZL9Yb8(HQu(:-)ib11o^;#'.JXig*8.3X.iAr_S]plG6k?a(goWE;Q;AjQ4t:30F"MI+u#?s#7A=$2sCug10#:KDJ,&qoF(/kQP7%5&0?1A&,"2/'?5/SZ[K(u-9diQ4=^[j/K'V2GKB9d)(tZ/r&NiCB3,feEl,>HK^IU$8`":D@i<,iK)EWUD`d##b)qu%O2'["*1jLU^lO5?E7mc.YJ"M/`5h4N6NlA]4Wd284-UsA,J4J>[544NFSto9)nHOpco5"sBU)Klp$Li!d5^Y+]B7_8=4mCu:am2MJFdY>l^BiLP&#]*#GqI+Zg@Y0-?"Aa6^HLiA'ZoZ40PQr!Rm!g@#[]kQ(SQmKq*$r\pXW"9L?Si[HG7,5F<^pHQh*=tu'<5D(KLL.XVrn[mD)=ruhH2Y,_S5fkdkd8FjE>`#XRKrfdDEN'(C;Sc>b4g_VCAj(]dbrL0(t8)O*,QJ/b5Zd`A'a%H#aq"6I4a2'lTNr4%SAYr)Ui>dc'cV[9\6_Y;hT*O5kGNL/hk5$h>ZHI2o'J]t19JZ3l2sW@-"jV_LHj*:U&"nUY,LJS<%&TMI$$RDn9ri[Xnk*V]O^@$l:Y972Bd?H0V[-gKQ=MhK()Lb\?5Tan3#;IO4;HG;&(#cOr2_oB`KRTq#ts+M<"#VSJnT8`R<-Q,(1e4R;CDae6[*>CFdNPdAUKK[9"HS1&Hm*`>i"rqP5Y$;^D"gHIjEIm$(1Rt`C/jG+c7JC6XH/^BI*>?m>HcN:^Cr\g2(OmqAqh-W@RM&WnG$c5OW$TCrO#16FK+d;'^>b?aN.=%qGHb3#fg624A9Gn>A8N',1E#\1#5_lAr[]]H!SeFW3qm0bq+n9gVH)kC[l,Gnir97kKdcVB@/+ck8o#)'/*KHY5#9iRM(GWKLP'Q#P;$WXBXhG#k2!Ns[Q>gon5uDr-f,k)7$5ED#VQ0iH%+RCaL1W_I9&$Gp`If]:@#e96Hlir`%8*#FZDmuqsoP$R?(G$^8[:WN8MW]McXe5hU_hVK/Cb#KJQb1&Gj>U9[5h/WFK9n]Wd5G__,9NYb%=Bo=fM:s*Ymu?qr>m#W$\7b!UpT=+I+o*?$02gnqYAC"Y6ZrjSgKOhCj;i];e1AHBRj)V'IX8`f2pNlpYA#>p*,i/+It">lRp)LqPItrep7pe+d2"Cs=\1K7TnR;Q"Q>OpGn.*QD-h6;UV;Q$ZM#3EDRCp3M1o>-"QAsIjlI6AcHT-jQk^Q@&$u&oC)m*GX*e%hhWm-k&3dX,Q+S_DEQNnr&nAhRg)62o)5Yp=D&Nf(2VjRVNeY[e^gR,#h8:dUa&3'e,4hJ+Js6>Anlj>S?aC8[qJ#*7GN]fc"#-)F/nG/5>RnD6u0C5U`DEif"'GV%`IN?A3=Cu_7IrVnYpj:]?\3(FP:=G]Z[;G1$X"X(K_-)ehlahDLa"8g[f"*-sWd1-lO=!s0,Af89s`_-8LfLi/8Gl5%C`sB4ZPFiAGnbS>8!Zib"_fD_Z?F>Bi`$pYW[;=$.kYTo/3mXkCFD+F$7L?s'E=?iei!O1b*D7KMW>D@nI`kC;"kCQd,[%o@O&Mn^_XhaUEN7q(/@\A&=msV;Ya8Nor@O7EZ31Z?5XSk2>_04'(Z^@pGiD]='r,81MW@UgCC-4#/WmCE!=j"40YC[jZ)7oF_dtr%@.=uLb/6#I/.%In1;ELJWB0tCU1=Y&D5#;f^bi23gMD+*T4k_#F!f5*fMVXS3?cBrZJPGbT1oXR^-h2U+o-B6fr<,#&cLChW+MmjEZ6\`$6Df6D,#h]Y`OPk6n(j!ihQD\:euH52HJ^m!PmVXeN02N;c(AXpH]GY7?kI2d4[;q0sHPL+0JnnW?6>s96mD9FSYn?r-MXf#pOg<&[#Z*>bro+[uGcW7`BO%:nP0qG$!DPUu%f/PZhq).k&N<,[\ccg\'8og5Xh1>oQ;DM5K``DmNSF*!?C[>jU@k=If):=k.r#iCgWK;PR4NKTeMmm'h20P:F0pY_nN9Er'IZ<'lCqNg?3.d>2a2TUD#&e7Gr;TIW+@X5(J+TpHXo*Et/"b\=[S0Jc5Pe"]`j)e#nAuK'Y7iF8SXW8+*kZf*;R0RM(h%sX-%?kA_\B5)nB#Y=#6FFoe\;TV'H\WI^%R)C2kZ*#\atpZYa2bDJQ-\&VN)X`Z$OAHcB-MDHqV8E@I:#GtNI9"#a90)4lf9LBta92<,.4Z9=P`<'kBP5OpI:cg']l)^ukdKM$nqq@GrA[H;Ks,0q%q8VPYYSq@DIU8)m_H)gO2Y;%Q#f96(W-8XB(tp`MKh.?MH(JnpI[\2n@4RBT(j``6"Q@m6N9bc&KbdHb+fPaX,1Vo1WoJST63k,.hTuNK--1!Uj#M?f-C4%!ThH&.LVPKoqW@B`bPAhXGu$MJL`j@8%*qP'`"ahgQ<0kr&@+k_/lP&naEuXg6NlA]EHn!*R$F3k-bDh+-L)Lm:fRlP.-[.VSfe;Wmj!N%VAN:o8eq^CX+R>Y'M\m'n0Z;ROR&=o3sGF9'<0B)rsVn*<@pu9In&&$H0PZeGE_^o#f%;XmocjFX_BUR*?It9YX]8]R==T12W6REo'[I#cmke##'/@s^L*)[>^sp88[`MZo1KaB!#$CT12mkN?HPDW#VV7QCQ1GYPE*H!k2/&S0*N;@Fl4kBNlM=^q)Ec5%W%/&;Wg9RSa_?'Varr#NX8G0a#tUPDf8W;c>eAn$K4YST&m4W[4SrGnorG'aD\.*8]BGJhDan8c(qXF1,Z`!op8N*#d7"qmA_2uT]QoZ&tHr<9@td$hlu*?]C$%2K&a4fJJEe+%4bajSWrXZN"tFB)=m(XR,FV2`c'6@KPsu_lKY2'TD-?Dd2.IS=Rk\AUu7m>`c'6@KPsu_lKY1(Y@+HGSc@t)0DMf5eQ9Xq?'XW&`E--uY58r@?%'?!r@80Q.\0),@+U"e`j9$lL[hQ=/0p7"%>76dacl]Sc1m::60MYlb;KcmJeF@bo*5%^U=3#hAeK;I3GCcA2A9LDtEpr-8Z#[R<6[*nO@k3?V6rObt3YgWN:Mr_l[9i1ZX6GmX1Rc#bINu^&]0.bY^mZN.Z,nM#41N&$?s@%$UO9_t@E!2(=,b5^C0"[gO38&pec]%&WnS\?I1Agf#UoKW"ND_$fF8&pec]%&Wn*PEV_@+<%-RZDcrBkjZ9\*[5R+@c!X:kDQi;eUX@Z%@g%WNU$m\Q,Q37r?fQL[jMVga\pX9s$;Ek'];04DLh_[juPa[9G?4*-KlWq`!aFnA(;mOU@XTmIpOW4\-N\Q:-u'#joEUpA\Q#=d9PuTej*SCe77$Nh?k%VtJRID,9O7r`r=I[^&n!D?cj,G(T&$3qIe7,JnjXE7=\i/'eI^ZLsoRU#q*aEOS[ld!TMKe-I5lRUuj'X1ABBNIs+ck"'iZ78TaM3sa*3@*PlrN&Jpq2X=mfW(Kr_h`qYe9AVTtoRS#Yc/0PsK!Y98U^*164V0W1_!I%2kiYK7j-!`8b7poni5na"-drc41da#h<9S4:VRfI]5HOnHuCeZc4ndR--+K*X>n53`M^3/:Y,uD)).S0-qYEj3I]'E8!p&4JO`MPN*qc'DK6C"D`$AaC?WC[5j[6bAiL>M+:l\$$OmFc;;?Xc-cMnQHPe0pj8\UeQM(qIi_7A;;/Pegug6(h[;T'P]7bMeJlLVD;Kq>F>/#.qQu#kKuof+TBcqoPd[^1-TW*X+ar'3[)1nKci3/5l(bUo$?`1td2UM(]gXkLM>u8>K(jl^F'_=Pdj_)FK?SV!DN$(FJWE7LmD!]I[Df-#D>sj7!>H1phbEZ^%1;n(X+j$Os^_+gn![1^`J4nThU#W4%BYk!s\!jk2NT1G/9-T,BhM^cJ=m01N[,C95OHggGrH-pmB@1HsY.Sc*XNW.HtI-mKX"7>"QFkCZf0s"$NMK(uh2X-OZ6-,d$XbRfQuW-CE&CRsH)^/BD,r4E+=go<$21P#hDBblCD"Eh<5Xqb$6Y/.VLb%:GJdN."6C^0SiE2G?^=IYK.B+k;^\XWt=#78c>0i3/I08SC]QUfARpVt*.MOHODbRs%;Gbf0NFKA`r_o,OF'TQf#-YZ3kX/!WVL]]03HWi\D`s/3d8b9%A+nsY;M3J4H2:%mMY!DA3/\(DI\N8s&?mdc.OXh:2Ce,ccSGUHf1F\%iDCjg/L19MnYtPMGl0d+\".HN/a2K">Po_'s6PB1E4>Vbe^`3FUlQr('hc+3/&&Su9)XS(YLN1GUd:GN#8&MC.X8g]JE@&BWX/i91]&2u,e^`4#e^`4#e^`4#e^`4#e^`4#e^`4#"T8^E.F;)~> +endstream +endobj +7 0 obj<> +endobj +8 0 obj<> +endobj +9 0 obj<> +endobj +5 0 obj<>/Font<>>> +endobj +11 0 obj<>>> +endobj +12 0 obj<>>> +endobj +13 0 obj<>>> +endobj +10 0 obj[11 0 R 12 0 R 13 0 R] +endobj +3 0 obj<> +endobj +16 0 obj <>stream +HtU]o0}ϯ#H8!mmlmx@P!MJn_nl/[_{ތ/Zooߎ㧽OSq !#wﮦ BDA)aQbt;E9]&d>5q  8'ěAJqj"GP0(C~0I0$GĻlY\|r #_ǿY<%K;HF'&pB*nl&R(T^f71卻Cۊ1Fwwxj!Krp}K +s:Ẁ!_n;'5 br^Ѝ60@R#&daĀ!oDrVW>ӸHPh*ݹ%0TB{#ik砎GLFG)41Ŧ C"^Z!N(rDt4`*(,QL#r7(yZU-}#ٳ]VY(3#j#(aXhS]"B⌹K~W;|ZcV~_ "_a(-)>ػFkV+IV2O:҄]a.N(ML)*W쬉( mSU cg+nKc^ekƜ{nvp)+idgrW:IROm6mW*IN0yZ䕮j3~:>stream +HU͒ S8[P*$@JH ڽ|ݾoaݱQݱ{o'U›JPՐXF#s#c[Ku,wj/;zh~Y:=>GB݁ \WWW7)D];'#T*ÖPKwdeu:7jJ5~W\>QNyۤ@PA&y +c ."a2x\#]2;Q"wry/$ H2@jQ*%SgXx$l^J$UR0& 5Z{&F_fÂbx{탳P({UABA2j +) &$׮kx8؏b2O Z4(bXK-x9#7z,NPf[R2Yw # d0Eit(O{ \J&xY% 3>stream +H|Un0+tLz#o !9Vz+hUȒ!)N%z':&InqS[wB $@r&DK Mp=F8ѷ4W٤x(#WU%DҖ|7/ Z{(C&"?Vm,S=@SUYb +($qJOJtGʄGNWh'N'imp|t+pT&5Øa=]w̜+yR;aiս AW^Ge_`AR:a e_:*ͫM,J}-a/< <\ +3v?v23cgA95׹.8]eb;Zd0D_-'CB1ˆkP_t]p ÁTϰ<8E}k37a>]E`,sT:.M8 +\3ѧz|0e 1R{ +##3a)a>n}e~&^:ݨ.[P=n 0ƳܺH)=VQ}MH{f2ݾsĜF{1t =Pu]*sfFj<ɨۢ>{EWެۻ=v#^p|g͌WxyZ۟'wwOu!^ +P5)o3E0@!#ILAC  p.|Ǘ!ҫWaP5}4 t` 0f E~ݬّcRh&'H- +endstream +endobj +19 0 obj <>stream +HU]o0}:/%0IL 4,5kXWI +sNt/Q}k~*^?W'(/Z OaI"cF AIl(oVgO_b*J2LHzHRE<, |:۸jnB ñʤ66MGh"Üc ZeWMcCj1fvc9#!9cXW88ӡ!i"Æ0Id;kۤ,TmkXaeiw3< Æ&8S*3E_b~q,d8i֑(|ZQRH\/,d[WcՋ|;V2x9*IF +LQGP~$A;Ƃ$G+y"QLbmzb!¢!CV) ~ߜ Q0-@uT˝-z]mlnWf |d%Yg},xQ~h}TR$L-6[b{՜@ `T_(9L4afZOq;T.1ۮa}c +/~j&_sDo\zMv2+Eʧgk;|uy.>ׯ/]Gy=6Ot` += 4fF3_H7 +endstream +endobj +20 0 obj <>stream +HVn0+tL$C.깠%&f#K$;ߗd ,o޼q +RIQ&@ʒ4)EA6cJAJ<03l=D'{kGxf̕^m`] B YAe/cO7Ʋ`{NиOAp0rתRbq-Z}_!EG58;Uk b(YC (>^6eCq0QŨJQקwԚ(QkZ śj]R{7liE7Bl(+YaTOtmmA}zf4֘0lKkִDQkKC( L 0J-d~||?+1X D% %gvGU ]z?-S߷M} +R8?jFk[mTXjDt]du֨5F ,7 #nM@KJ9,vD'Zuf=Fu/۷A/K /mN/wG7IZO(D3Q)6#>NMeYܖޫebx~tǻ}B{m*/hUxZLD pA r_]eǝAu`p%)6~>rOsX ߋm]@NLYe913^9:d(=QE`|5[mVEB9xnVR6&!cԯ0,w+Dspo&+m$C +endstream +endobj +21 0 obj <>stream +HUMo0 Wآ'R>PcMŃmIt $J]&dNWy|m+$AY#%Xc!Y[ C}8CdLe[NH_}97)ܒh8I.X&O=urTj&J +G}UFJYh߻]{j^z^yG|Z#rdiuSwS3u\ǡT.AwAvm33A:{:ynie(2 &qeY>2t׵ -iWHMB--3'wV 4MhOZkeZeЫZMR#?]) ;0\sXҼl]i{EMsQ-╧}Nj~y-6vYʂ8c(D]c1cox +m>stream +H=o0w +m&͐Cu7,35SU$dRw8FG1pEb8V$u.fn`tk aߊRDVac8e)졋Y}ic(EirP$v$Gy)|,zAn]R:%uՍ.FQD4sӘ{c-\t[̷7>28q0f4#Lh7#&'3!fԔ,7+OѧJ2G'B6-vi +(z٦[ktsz.]~/}E77zv?p<x)01G$u`IH*7YjǣUM&%y &'v*^϶m0qw.C '.eK˽پ4R?/ZH&I'06mM)1N1wtc)~&emLk6d[V VgbR cm̍$ gYn,Wd%]NƱ3:r݌^umz:2D%Ҹ' ʼ?ܖn o +A]cᕄ ͕/ϩ:kk8.2|(41+c +N|K$7wD=S| q{|U-Zu/;7h>\, D.ˇ?. +endstream +endobj +23 0 obj <>stream +HVMO0WX]@ +hR%)+:UՋg<3͛qy|vvz;ň痳i]i2"4% $,f pd,8lI.$}0tMVvA0 a۪nboHRY8T{E\CBb۬n(۟?F1GָusYW{Ӯ L+_fsP )6$c΁J ܭV\/jW.ʠVqcrqhB^B lj# 3j`m?)=|Ѝ|mϡ+f^W/:=WDGE3@RރHj9ֆT̗:ӝv6l `A'L/uلI  gð,ڪ ci'G&u-!(7T#}\={ jĀ+EKf4k;@;iUud z L t)Oir0pvMFZЍѸz:[L|k88E<PD p +"^kyјnLOnUp;7e:͵ҫFEԕ:ummЮn!DomӐ5ը= +9oٜs}j&܉_'aWϲ hn\Տn1ASq}rh|/:{/]P"0 Q m۽;Jvde@Unmݷ*n}aw Tw^h  +endstream +endobj +24 0 obj <>stream +.llr;wO!bvx1 4Es-\xeMKEl0,7, 3M|J74\\w^th..rUJp%ḏڂR ƻ/E+jX6 15nS/^s >a +v$v,o=^(C*(>D\Zbb Klw6=gHG8r'q +$Ї _5s]ry$hW״ȂϺUĺtj8l?Bߞ{t |#}tLH.#d _ -$a# |n=p$Y{\^){4]q[7hrNؖ\`1A:PAqFMBo7 |(aU"BU:r0M_Fпk #)vlF`JdQ1֛ZD>(E U!@ȏCt\\нw}W-hl&#~w.4Gr5-AW=Պ@t ! +CXWJ5cEķQ1ʸUkTKF-'MdV;T/C$ hte}8;!wR({չ~poj$OcBۮT{-hzKHN .;}VtGRX avsOdSS +[)6f԰( +*&蕩a^1* SJQ&( a%kn_`R +,-Y ++5q{/j;B&q!r\ +¸a仛V.%4c^5R"}pwb}_\â^vkC!!߭%fQ&*b 0'o-!JJEgfOݿ B-f>)$ "_$|<5i8R*]EOkE nm9QYt3ĽFӯ,SEN xS>m?tFs!M`c_fk/d;zȓIxaqAbyXYN٫MrSFW nNL!B& Tdcӳ퟉+ZR%M hYҕ'.K + +Ԉ0S")&.Acدiq5^ofbh5|BdH(ORMb؈dh~ij{E]C |g5[9>& }+5 !0(—:LuE(8​ ?kT1x?^XtP Y|}ɵl( [U vwPX|6̡,ymb _o] ~ +T)oJRwN9*eEמk&'2ZamQj{f5 7|M6?{;wP6Up +?IX#tZ`RM?@DɓW `E +` ZtIan [c׏kPS0OS1Gdg{qcMc"eػ¯?Xh|Vek-7@W V?H5k=|ѓf\eFmu)*p]ݷIZ6mMmքmR  Eˢju7 a~+VkT%~v\H޿D v4ҕ>؍h"d+HGr#CF G^@{WWOR &8yh>UB +74\rbS;6uVcciΜ̂n$ՊIBwR[oTi0jb݊qUz>0B ʮE]ŐJ{=,!6o/*zTB Բ +&Rz3RHt]t +gQʹ(mEZR1ԂSAMvW&nc&}rIF=ō. +a"p[W ^ǯD mR&B|FtWsbmhVrdE"b. +o| B௓oX5i+e"YQᘘٕ)"3NQ5;S|@DeZ<W; o֬Hga:捍i +p6HkC_k6h`_Q-bU]iYO2nZ@/ffيOWN ~# rW\ʎ7s*32nfyj%RslPOtW3{ xK@YRtJ!AՓ|_~I3@d #w,G~ 2(8pae[=V'!JM?=U>%Q^G,nGp_;a2DG.1x:AqtE=|XiBBj[6hg]b%ka"8" s' S#=>SWˊfSDTsЋE;j}سfGiܲZO}^pz:k{÷^OTMH\&=֭~g{{_EogoR GsY)SȬՉ"o .3noK(E 5)?:δ}e7sV7 5&RCܥ :$\zdcѻVRP+?*p&-CUuu3M~ _]_aTGE슒bt2ymlY*72Kvv l}rV$~:U*GUz|ї.JV~MI8ƌDù3m+EjOfn؍0L?ŝ dd"G7s] 9TbvjǻA)S 5n(cK*<_'[1W4ơxd=V%5FhB7 Z)((iXLz5^8W$P<^$_M}XsK+ة {G{p|egMYAVX4:Cvig?2O`8},nUS?sxKa&yoء@fDj Q썋Oz֛!zG\|LoR=|)G +GpKX/,j V E5CyMƣJM!$vy -֯9{@#OWF\ڻC9E?,HX=Ou9Pc-:[TP*cJWsq)w)C-Qi>:1?NnrR[E6fEXWr܃b)!1>,.͠?#*G䰸FjOǥ̃/^g=t,r|6`R3X>vq'1G ZQ[滿pcQ~F`R Z ԊdzFAmաV'Er}bPxq7;;(T־ޗJ4WE +KPU b'j̕^Q? MBb,rgWu9`/H?Ҹo`d&ތK3/ pguv|r`)`4eh[dke{<-+."cQO+Vn;X)X ]鿬E e@"T +԰ 기kLJ0 ހAmI ~ՀzNtvv owHDQUʆ%,G5^;#Oc)z;U 7$+,ZiQ5{[]N%HHo4:=Aҧ: b3@ti= +_NbGPI!\6%B Q 4`:u+;20%@l+{]CizPN2O+)HFym2eH^'W1,b0{rP>ʩ1_ZFٟ}|lA08քaP;M(ٔlE뒓>GgIF:輱rR8rLXc#řxR1@vL0`}R}7b-pKUm/$5MLO |\veYorҪNsV3].!yyIozuR}[OGZS. f"S8y݀O-ScOıȕjZhڑ̵)pSYyg+" ӈq] *U.4hc&֚7bV!&~cji]X܀a2)>?؉(vuR"Jk%o:r >e:R~QtSh6$@x}r pKO.(]cT='AsZOA[SY7[jAE("&l*֥Č+tIf&S +˺ZT41 r1rA&WK(6':I%gU@4O C)d 8I;NBSs|'?5dD:{d9Gw4vy2^Y%Kn-u7oi cmHc]&ua-p 8pPQNp>ƑRV(IV$>pl!/֋u'A|9RB?`{LC. /@ +Iˠ sHǀu`/RBgS%&}x :uc};z}ޝ=t}_ރ?RzQk+¹8@qUMXXlo |`↎Qբ~3CܧM[!@ yc)ნ6n jC(-ouѳQmhcY<n?-8;_{ 񎘜IU2l}+q-y'vGIf~3 =6y;ҥBG,i矴zJH{ʌ`8/[Q4lQ2-Iԋrɓy䀥 +4|T$͜rHяtW`:R&EZ&9·0G,,k#ff*NECKp/^.+03#T8Q\B=9mԂ27~$PǗP!%m{ӮڴKSb^+ j򣧨&෈&?4ԫ*.O=PxP/_OiY+1Lwd\ +v*6Xcd9<0#=ƅ)|SXQ\ =cK&9aۉX )l5,}-V$bstK *9=&Q̰#Z@bjQ7_LsukWjiB&09T2?402bp.##5U{5\d~G=`Oe{v0ɈUm*hl6H 8|Nc<dx9\`OÓĜeMčLxc0 Le􍕓v3?Ce`<?twd ZΥsz?NR"wA01y_rt ŧ)5/ԝW}(Yy +h޾DJRϐ + \FYJ~gc]`/{]V'5C\ĘG#]3qQag ΋<rצn2؍^]斆5!Q" 2p8:ӔwꀖCnY5R~['fRdJK~:c0p`u~l-"KޗA*&p}v|Kٽ08/5{$ DgB^Or^dTY~-Gcf}F):(h1$kDH8JHthjC|02|@!f@dpՉ,WfB9B'}/]* esBO^ɀN_W 8&+ PS4=ʁ@8?Odu{\יtJvBX"YNѧM]&1L@B" xГ3-P>]c)XI0(B@X!0YUx3xKr^9֖;7&28 ŁzYzRϓzSu|P)djB.b90|{>nu?y҃C?tآj)he{ a^кdݢO.cش'BR +$}0UtX_s#ͺ^ԏ + UK~T;)ر]'~dʔ__IKa/YPŀ)Rpm6}%M2d+;?cçVDҞ/Y(qJwĦˁЙ#Kc'()"6d}jJzO ̣TnZbb +L.OsP覂,s0'?T$5scϤ_Yg3;Ju᪦?*'cPx6VGZ֞?ttt尿Nxov bewY Dx T{z?Mr\rE6hUMb[0acC6 8+p>֐l +T G@eEy({8R#Bs'6C,3BaP卝ד.-5,X +-VuAqS)&xj !kEG 8h:jF8Fyy2B%ң>QB4faRTH_rO`e#ּaqA*YcgDsJNL^[<8F f`(*<E}ieh3iWO qCtܝXfmAoN(?a嗧X;0,ʲ'hxWjxI_^m'! ?VEӳoUս7κk%[/koI]- %e 1hb]"EGw) ,A,@Y._&(qE„*= r]Rnqgଥpavݤf jozܓGG;?;Sm?^aPNfV5?|+ހLn,`b;I)pzC9K)$`:WD&P4NL~ᔐ؈<;UyT8[^N|Th-ٌK<7KI7*dcBIAg t彬g,~縹gfY~p(f5ۑu^Hۨi~Ԍ,`y|ڂ}$_r\ Af[ } ]#pI2 GV}g5e;]M6s/sѢ}as'Pi&#!{_vZJ:Gț^fX#u=sTZKdH\pp]Ž&$m`tAIsvmiQq&%#ΥFD<>Bvr(xx])Up&iI + r򶝐TX[s3;\6x=܆k|'X-[U.ە6>*G6؞^Xjj jfFZvSS|5iVh떒ԡVan51+dT|4/> !Je_l^I}H~XoOM&p>{qH}W)S\E.vgÒl+-x(5Z,*H__'P\8Bf${AP5(Uk}C.|x; V ni)3ɉ>iϠR0sf1 *ItL`_9/_-W%,x'QPFA-nΉZB[Z(3NCP*Hdi,wz b.۫JMKO5cC`xToY>[~ntp&=t ?cMT<8;aHr.i<|T8U3ItleY^k_ݥ=\+.zs>z=2a"zk]_rLb&_0m6]2_\%\+aos8Ÿ5L28a0z Bگr#3ӏ2Ɛ*p훜t!'./)qMnV8،U q_Wop*,E#WUm_ܒ:) ɓ7TgCoCUB^93g-I+iCSvNY)gd/'QĪvƙv~IH obQCxG^cݑ=l$zh]ǴϓYpY|EvKx؋$oI7ytciz/M*hD=)Cs< ReP +k!57n` G5Іy>K! BǼsC:bj@}tYgvs1w-4drL}gX]buz.aPc`B${oHDMH }.H|B<^:2~cyغO.Љhn S>oy.^LOBxՌi !e8[֭lqB 8WS.2 +} +di@M9>?G44B 3$qC[x=c ʪ`넄&d'.@C DyPל_3yȁZ٫32z#5n+硧 w@rʄPLЀ\ xwL`Л:석ڠyQ}#Or_yaP +Iqلmk2,P=pTafÒfMc*d~1 na>GQ@µ>"X fá#'mf(wsul x_4tm10!4 "7eߕXrxcI -3*mz#O6Oԏg!t6y5HzʘoSmdy+d•@|q<07̂hߥp^yHx@bQMҗy1om {T)c`*%6vӄ/RQd-K.U[HB>RSr5 +X LI1vQWۃA>7^%ր @ө(t$v'XAL8,8uB&PZf8=guhcB~2A"D1y $; ȓژg"JT0Aܧ*Kf鑉"^Oeڠfjs{9̇iC2CDwlCj797.[baƳj=qwHv`Aiݞ0#f~Q{B!mIP9:rJX4HZ(#7ۥqz8W#JծVoxv;Rϱ>'ll +]Z>n?xM]Ο\0Nt?!\H5bOYdV:~r-3nz +Ȭ +\hzAoG2Lr雭cͶ+" {rНp;]Z8shaVik/C"!lk%ўFJ/8fW%pӺ3aV>C(?n4 n|ԺtQ$.pQ/k’4m}Z"Х.S5}I)jEɗG${qċwμ&[va eD-(8A>uB}79ެ2jߴzl1,R 2$i\!B|K*Wi cZH$~C\{J@} r}itIfsoTr2V$[֔ < v4lE: , harvۖX `R {a@h˩\"%^ +t |Y%EzSeFW:<DDZQѧTSp} +0S ',Hattw +5xĊҔ33HD >@P5C#\塌WpyˆBduS뇫,dŐb1Ha(/bC. 8:A40E1]9AdsۛOXM L +79k@=eZL}G'JI F64ަ@aPrMK#,n4oU3'[z潥K 0Z%ąTyJX +u^ O-֨۾qՎ??-.o\onHf/^WBY[?P#uJ œxIIUՓ|ECG2nJUٴBSH1݌F֤oL_K\S12?۔KgUKXIppdQOuW-{K;*tE<$E2N+0c,E5ҭoۧd!R{5~J4Q]iBD!>7:C0 pap986RbK)XT!Ȏy;d7E @6q@M(œ\Y +7'~SHz΃6ؕa(?`MH + ʁL>vxM +ͣ8_*Vײ~c^Qo阽xM1f \̔%HF>kQ^_nt4#=h){MW3:L!O _>39m;4.%WH,jƻi\dֶ. 9) xbtI\+w: @/WYXתpK6oŻ@7`' +lHRsh6w%oNw&Nb]1n^R'qmalC{u#|{n\rĝ DPm`t4mP#q:1̘5|A!P P~НPaaHOF|Z9|Ѭ'iDf+'Z Egw#r*9eaym3>ìxSBr20'essYr)!ځ3*=!\0_˹>"F#ADgz2$dJT9b +IV(Ȓ&U蕾ދ̤11kC ǝ +E'q@׻˭qeJ1HƯHwƹj 32!HwO j9f&Pp{؜j '![TJs9; \?,gTT>O ·1e/ Er@hKM\},xˉςl0/VEzqiEk;z|I^r3=^m E]b @/zs&%Wj1"`@j?.l:?Uktiae./`n"~T9{TzqG:`99|<2(,I8 TvC.!Ǒ$e2 +lby!uE؜p~*92J +eЛb7!P`G! ej|DݍD'.ۂ%r3vePnP`C?%dL+3u>P_BݽΣ9aCV6(:xm5G\D5DŽ12R3 ^iRCMV3.yMQ[# _dN-u? +endstream +endobj +26 0 obj <>stream +Hln@E,I{( ("#Kcg^~)K9JrRg/u^ ղJO߹Q˅uQ8=&+ST׭:\2e +0kjH +endstream +endobj +25 0 obj<> +endobj +28 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +27 0 obj<> +endobj +30 0 obj <>stream +H\͎0y/gTU1%Ģ3J}p (J ӫYp>ۑeߵ}84mW1.3udTCÇ/v?u_×x6T>}4ulXDZN~Y6 xdn^xZ ߪK4ɺ1/:^*ıN1Z3ۦe߭j>slDSpNJ''k6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh9\pֹJp +%qAYΦ '@Y^vPD (K"cC@Ye1ޣ  gWn$,6F"t#a{Ѝl.aQG楪[/mKK9 +\#%^~.Wp_ʁR={*/hݳDz>98\8ߦTcb2,evqJ]|C?I,OPg +endstream +endobj +29 0 obj<> +endobj +32 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'x6Nlx"xR`KU`GS" j@@P>@P>@P>@P>@P>@P>@P>@P>@P>@P>@P>@P>@P>@P>UTb_qQY2C&PceI8 jʒ𲃲$D@Y;ʪ5HXdH8t#a@7y' ܃n$Wgs >j6U}*~m[_Qg/UGX/)K(GKa9^~-k9JrRg/u^:JgNp{P>Myɐ)mS&_c +endstream +endobj +34 0 obj[1/space] +endobj +33 0 obj<> +endobj +31 0 obj<> +endobj +36 0 obj <>stream +Hd͎0 +gtEt'DH BUQ|wLC8ٴ]L6ܧ)>3M/p,O9^};m^_5>}.a/]h?&Y}j4+</M e, CocTUMն,?n9zx=6@S`CQI-VNP$(^VDpR FHh ڿTTTTTTTTTTTTTTTTQE!lUJ8\%'$eI<&(Kt(KeIH@Y;*%HXdn$HXЍDt#a{Ѝl.aQG楪[ܯmKk9 +\!%^~)pX_ˁZ={*˯hݳDzwnr.|S>Mi”-mS&}i. +endstream +endobj +35 0 obj<> +endobj +38 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +37 0 obj<> +endobj +15 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.479004 0.0 426.479 630.0]/Rotate 0/MediaBox[0.479004 0.0 426.479 630.0]>> +endobj +41 0 obj <>stream +HWmo6_!KԖQ%494%ȵ{Ad-׫v_CRv+Ķ$Ùgn7e5D/_^2[!DIĩK/^~}t<$aBH}!hyBy )D.޴xV^ CYm:tjp ޗCM$EiFi(ƒww$׫Ohw +^hG$Q?X8K_9!y]NHS޾0Ki1JJHY!+o>12V hRy3^fq΅)6]O??╩wP-uSOMZQm9G\JB<͈/Mq_،Vb8ަA錓XVEJdL?H4T3=(‚ǂ-.$S@". N^1rcl奅 .u'AƃYa(o! XX3Q18'f9$NR\f3Gj,W}g,) P;f!xȋ)$*zjCJ+>tH@HA܇df:軇o.9qs#LrXL '! bFrnktȇ<3:WB;Aq]o<@11 el ΋O t7]ӥCm.{wpugO}=lhHڽ.#:<1C%r|Av";NٸeUi'bN;FVi=!dȺ˥`9uKnweb.j;43bsWNmHß#{%8ۺzo%91P<鬢AA1:iٴ(f& Zn+mbBsX /[k;o-AE|hYS9U)F-TY:x̡Nc|26b-P 6hbb̽Igy v܏V jSj +:6Xn/VgV솺:6e0K H`3#az3}/;}%-WHE1]ۇ&fphj4AD)|ƲE޶ݔ.6ZR[)} ׯdOpfsHX.w5C#S<\5R;Ea +bynvpvWW`Hq@v'>!v}d<[hu} [i_r1q[GJ1 zyn6pr m~BM?e4 *H2qu3q1/q 9vzBtHr'ssjfQE`0YrJ]K BV;K0Õ]o׆*ݧ +h}F XME)hV0(.CX{d1”-Je(4!M|0.$T> +D}-64fVBIyD ˦!!gyz[&`i2 ۥQvq5Oycg h {ĕЃn4cQ7[_&Z@ ?7'R0$3QA +yLO%5AN U,(ؓ%srH9<^ } +MK͵ݷ>SS;]Կ螡,'Ȼ[kpD Wm*tF߻u;Se +D$JihO!F)9x )PK /3L[C`u ,AJZ5_Tc82M2G?`AVbCs$#q6INn84Zf &?y\r|\eֲ "fN>\GIsFԡ`pv #KPǔtv^#ȴgr\Lnp'ƾ\z[qu);He?`&Pm)hkݖ%{w*t$"AJwݒKWt=T:m $l-$a+s}~s<rg2vȝ_{`I2ryzu[SĆ$r|Bd|@mJ6Ta]EyMcAt<$TC4x"_قyٝ2wV+ϓCbnTD'K4K߾ڍ TNHSx]tP{^MW TX[Ӯ}3r̀1?=h[#X΍o}(zݢnfbFϺGh\qXa=z1u>bc' /g +4 +qfX/z+e!l88e$ ᨯcYS/>-nLe\> l2//zfc>yK;˚DNr0Td¸ufcՠFS`A-c_MdJ_Y$Y>nWXRbޗ4e\7SĞ[A{s)aOM.iT^QSS7P[<橚A>a)Scٗ"6^p+S2EuԮW=y57L3#t\7y($^xݘSI.L;yzŵVEl @ߓ X ؆Pg3Gc&"#VE]w^lZc~"S#~ЌϮ,FqMП\[> +Ŋ- 0rgN1-A d{!8q&rW6)\?HMZEpDe2:hP4`Ił1u8YĨm_ZVOk1l_P0*Vl*/$+F4ONZ|r*7g^>zę7Sm7䕛glMpl" ؙ&P5bBV,ݶ=}NCy,y7t pDe+C `0'#:vw~]F>~z' ;Fk*_+2t;4O;WQYɺ#/(#.BO\u7mYL`~g|}|ջC٭>~ۗPO=ߢy5Zh&dq +T_"M$l0 +l-"*Yzَ\G|=ȕS* +D^~COў/r5h 9Jo||תhFaRP7P12F%(d[6ĀAS`Q:`ba﵍K<_[4-ȃP*Ph;81XҍZOEНb`{]lGO.!ˢ F=4է?EfB+\őΆ3mNoΠu"LfPm3K_dT9p]ߞ/&DF?O0 +endstream +endobj +42 0 obj <>stream +@ssOZ;?8L\HntswD"zgG/ )Th9nz(+?{4 (ŞN$n5_@9`Ԕb3_9Gf>C/m:@V r\%),j-#,,>tn+3-) [uC +tqJ]:iNbE4eGNG92ǤJ;&}iD+94.Bm#EMvnH12\飔1qn=ԙoi@@*f4 +|D= +wπ=_q'ޝmۧ:"9ž_cܾ S{ʶ?9t GIH=8._<Ϗ82C=߆{4)>/MM⢿𭤴ʈz b +Х%#ՆD<ɣF4\d!Q )4 jC$bV2@j~r|ڛqLYxcM =G*%捓% Mv]@9eoXеåc)$KJyX"FCЦ,= +>䜯G_K*w  Mȉ),9|)H,Rz~ ί#Qf }IN s@/=*鏴3ȳ2^ ˪30]۠a;onXܥqa+{kqMPWQRмKf]ઽc pЋj`x疺<` qiMαp \wnHd 6UḙVCA0bp*]G5Y=\[b):GRwH鵪UwTGev</Y_|B]Ha9Z6/,)K)K{n;(!P;o +Ԯuً1]OQ 94Y5KYlsW6/Jvs # GC5&`tjJG{g(:(uxoCcuD#2e¡2}bO$͟~/ + 4oLqYlߘ%3!vUtW#ZXcA/ģf~VTjH>W:x_7ϝOz`;N@]Y9Rx_H!ZdRV:Wf=t 87eC"p Ӗy4eI{ 0Rȯ.;yo*n 6w?7izdǨ_\܀Cc:ېO}V=Ֆh궈e++dgm4J;BڒTA[ Js :gOgdvEU7bQH#[$YC!FI\OKP J>R S0 YQ?wDGzPz,0k,V=:^:WX59WNħе&F[gA,[Ja"P)mI +qWMYGV|"S?8$d ֲZQܯ=*u\LH8Z'+S5Ӕc7m0\8dnJ?6/ +||T/bNP4X O" +*7.))ӧBsb"X9d$]S[G8p5LoTM-"IC7MV#1m8V.Q +Ќm{kW\ʱ#IyiQi<#vpC I|HV.UeXW;. =^Eω74Pڗ]c' kJ rAZ(iJ +6ҳ3F8 >.t RF+ϪY0i"nٍo~*LGm^DGUW mRɗTcE7Ji +$Ve,AOdX Ȃ*lxA#6{7b]v̇`Y[Wg"'XOS1G93z"Rb +(yl_TzP ?&Zr ̓*1`KGWD4k6^.ȋ>0)Y)bu>1ӫJeRVŻ'}ltB,(N<sWkK7u7c8㥋"tPY8vm9Tk&&zDzm +TꩨQ!Py.bpנ)Bo*0zmм-;$<逡> +?x"CN\ծF $b#.II]. -?E}!L!ܷ|M]|4"4s #]+g배>yS +膿#Qj-pgBR#~gXx .{ sg0~#ΏǕ²|cGп3o)Ax}qP)KT {TmΏL+M3}\#zhc|Ӳ}NӽW)^}qlmQB.vo#4T +pJGuI,E}*v$e7MAR8ql΂(eKKj +%ǹ45wqf+gcxKk7i·EjTBҞ^R=ϰNcVD*i9H +{U;7l(V25`p?岴O $ OS1Xaі Իi<52 [ʇfO +LVR /TsکypC'WH3`H胸ha^+qW/m4NtT׊@:o!tDVWB} dҴ~6S]/n0Њ=$/ĸAo8 3'vÍL 4'XJz{#]){,޼b0`LnhY+fG 9,{hZ'U:wK[C|d`~[. Ab8>? %ߴG}L@6BJYگk҄PapGFY?T) 1Jƙ$TtsкEbԄbx2ۧp|u}Xq~j5q]-FYUNxa +3@{ȷ^%"gi\dO桾c@'4"n{Џ@NTrw"n%@ 'H.7zDcs2ȾHbVA +3Qb>8#@%U1)1ܕߏ@)VkPG=0̿؃ga +ՎMI +P<{{'hӤ!Kಋ)ctAgq c|De=rE qvP)gTAĪo )ۤJd4Hamr }i eALS<$/oޕv75=#& +VXbPA'ՓYc;Rt1ۯ]9d• [N(Z+)5FKadZ8tu[2?/CpX8a|;-gPs~0L-U{l$_$ v/WTOe-9SetsUMFx o'%V "Ki,) |HY;IԶ9.BcӌKrĮ0[cϪ6>)t<65[^h +'M +kXpdZkRtmx\+1\5J}uYl%#~ɪ[Af`,":${+! Y;cA A +YZK\7GL?Ny #cU[YPO.Bbxyͅ%0y(_듐QoB^Z(|0fԪ&}L3+oqH} dKTnuw~YausVf]O&e=Uh,:60@ )Z&Z BXi}si+-CrxtU{84)dz.?+,R^&S/7^.LߝRDKPr8zxmSU< {(=zېӊJVb: x͇҉CYz}R#'cfc}Kb(&ϹAsuې Y|@ӓB륏~{&s* b̵`Xra>bL006) hc4Y!2, +"HJ؋[S xίIIobíoSHԒ$g/fǪsfP*)2s$mnX8'X3HH k(Er@(lGNR8wI|b:8p75} +r D "Y.B Y*093A{gkٕ~i=K#v8+FC#ddBjH>RƬncRMrVл'Ypp,A@ %AZr@ogyIK0DNmAy;(k F$9ZJAueje] UIp[ +endstream +endobj +44 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +43 0 obj<> +endobj +46 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +45 0 obj<> +endobj +48 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +47 0 obj<> +endobj +50 0 obj <>stream +H\͎0y/gTU1%Ģ3J}p (J ӫYp>ۑeߵ}84mW1.3udTCÇ/v?u_×x6T>}4ulXDZN~Y6 xdn^xZ ߪK4ɺ1/:^*ıN1Z3ۦe߭j>slDSpNJ''k6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh9\pֹJp +%qAYΦ '@Y^vPD (K"cC@Ye1ޣ  gWn$,6F"t#a{Ѝl.aQG楪[/mKK9 +\#%^~.Wp_ʁR={*/hݳDz>98\8ߦTcb2,evqJ]|C?I,OPg +endstream +endobj +49 0 obj<> +endobj +40 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.479004 0.0 426.479 630.0]/Rotate 0/MediaBox[0.479004 0.0 426.479 630.0]>> +endobj +53 0 obj <>stream +HWk6_] EI Й̢4lbQ-Ӷ[r{i)KD>=m_x߯׳Vk3Q,(`} (򍌲("0ϐ$(O) +>6->ɕ}}˃9X}>x}:8HȂQ '$zZ?<[p + ]@"8X/ K-aEi믋Lcd$'ADȒ/Ll*x.QIRsf*=)QY>=&2O!R*T$ +,J4#aEvϿ"ڮ꯷pN2G` v[{ox\ e EGBQ80EDDh|<%Ή['f>h-DTG;<3ߢ&Fz* .ש~MZd`F"zatlu2DFHa7~Ntsm9J h<Ҽ +w0Iѥ'h^BIA'i0བྷK9NR}fe47tp歲z8sHT%.t'X̮(rC$ƞ`!\>Nj /yNK6UO)\@kYc]TE۞^RxM *DҼa\BU{83j;=> Çb&ȴ>_~&,dخe!b}Z\jbǡ*o71Ns$R\m{24$|^@ȨMP|.g\c4bRle!i/nC5#OrD0bplxpË +)ˋ(5ձ$m}O3ejyGitȄS/|K:͌ʭ SJ9i"1aRbLC W̏\;Y6jÔ m񜗜x^-=n@䖋'!-дE ٫ +kK$GHjiO vW$ga~WXf31DafAgֆ6bqg6CjKAJ]VrR7=~k"3*hC} ĸئdgd[m}$e5v},А{J_BDp44T _aӪVU)sȼ%i.3b{3$g0 D{c,$^?98?J7J< E *"TPO]2?5l5J~ >zxs.2k777 9O<)ff1!'|HJmR?l +K75]w}b[eWb:^rpVkj] +fȭL %Q^%Rq6cN&Z6d~%yiO־~A 8m.W$s*9GO6`< m` +wc)U{DZ^"ۖJ72$X<3||ͦ*0=M(0,Ka}'yK~*̷j+o%Uɽ횦*;v_n Dڿypd~f ]?AJFrM^ӆ#yN'uG4Edev;|cbU(YT[+jV!HW&&)Dfc<׶; CW[dT%ԄUU5 w.@EEXWBëRRpȴ5uҘXRbAs0^ip4pfc0V7rkyH0d?DL#SצǮ=?/8&d7Ab;H]nΜ[PiܮVU +9% +D/?|3UlK+#rHjMT~Z[HTo6HgwY3+7рȇɓ$hAzTϿSnfhw.?7[~(7<K\.XG}G*d?YixME%U}ԴƔB +aiϕ=Ifu[SsK=۴l-pAFD3 -!BJ.fZB,'!=ȿ_Czw$/;}CfJY.嫱ӻKIj ϒւ +endstream +endobj +54 0 obj <>stream +}uuR;#^4 O-r/X_(V).!%;WG.E` XTzgq_wy<(9ca^ےϡQCI!< x.:$fVE_kxW~.wgĺOi!(),Nh*udb-HLG^8y)}?xhl{P8=[^GjU  y 9&Ujy-dA"*~A|vBQozԬ B#HJT&EDz"њD.nnDzɶ)hj($_J'QW +>h__t^^@%>B%btrpɊ&zO0|Ka!õ\[0<ڴXZ3C:kQ|x+jE@r[+Lس N>c)rM-01 #ޚ(x Huϼ2.I\Vg@,ĽnThf=i%z%:dB_@7Qi&J!O4Ѹ tZC.Jjc(H4 F +9`wuT~(S5bwV|**$ch(f}e[k >Ik4 +ᇸRhC?hru2鲃ZRp{ۛ4-dEYd59eR 2+MSyRLRL"Yf8O^=C72){uSC;[svOK'D0L9vQFX.K=PIp `%#}2Gjf sF^E؁rj;H`A}:aUlk(B8Zt?xG,{q/ko| +E}0>J30D/୼82j5`_x@"aA&lybqɅ.`n82hVaͿZil_uZ `)bDs'.A# H\2 ElUE+#XFj{U=p$iȘLEMM1?Ni +ĎVQ4&gI)Frx~;vuFWO˺&n;3іy}89-O7bs#\Z<#/C<4y!6pxXo!e=TlbsMe8$j2@1M>\1P:_q mkdsdMp)nQ(;3լ4F#,]LշX-) IX-c%*3}Aem>,$XVTȂ H<{1D,S2)oS_ZF oiiON/nHͶA/|Ɓt`^Mp[#Yu<:xY=9HBV>D\9R};Iv(:k&qsawzRE<*&_}:R+*wTPTpG56VctTpWkNovQAde L<|3fɋn~T} +مp0.wbX)C0}8!@iA,vIŔB֌D=c8#lcmhj2^Fќ]@&]1*:vD#(v3xckQwdJijY?21A!æ7 1uH厣*Ufi3j.@,C]waT{[^xJ +@y>?`6GaUH]ob ?XxMBCw7%S[\kBE/##lK`LҮR2<9_qH> |=8AoR|5 ?G +Vco3*Dw2QQV!L;lzU畿L K3= Qe9Rc]5%VO(HQ*PltTX(S#S;|P\p#Z*ζMBŔcEpN|)IzKkQ5)HDudF9N,#V],`O;FhAMN&I6{ً7'Vݗ4`TYMhrevZ~׬QezJR:Ds#{q0[T/JDy]>? QH"dk?Pd"#A@:vHCǡ}Jx\*Q5~N*@kYޏ|p)hzA,xPh GS Fa|H tcsR m CT}{[/ԥvjvLhf+򽯐9 +1/{UNH]AyEFy;JÉL7z9TOoǾ9H9??ÕD:GxV"Z,gPpEZE^IұWlS~麞747 3U멅\t+*19oTz RY4H} y9m1MY6RA!aIzq2p_ [|#pdl! ړj۱84yt8L +h̕2>mYvp/懾cg+-9奵)7;S栩)dc[8F /N}G!\Cja:/*|ĜqeC o;iJqh!ҔUs~eofN5Ag.4+eڜK@&Q0 @   +C #_!dQ ش e j ~J1T*R -0NP[B-0>[eO_tS CCҖ[[ņMG<,@+o5q KzeE_TM9|TWF9ѰλB{RJn +ʌU_ :@vwa3F"'t9.k>aBrKuʠ:d8$;>XmQ=$^ahXu(V2 TKfrSG ^|h\ T m2=2z0s]H ť]e  G^8_R?"^jP#9B,_1 /jF^eXZ=C=٤ti0+gubUTKQ&甦O#P,i%o1/AO-G=  |:et-\sigrn|@ʓ%Vņ;TroP!+a'KZf1>gؤ䵏8Sp'S7-?RsFCUx=2[p\G0ĵ\4S~[7e@4p +s@Qު}ڪ)(ݲ$p^jޜh|las` @Pyϳh[2NjNp=}ή]#{9/)v`hMV+9" +1g0jǰ ;Q lni.բ:$ 1Km-+2 rNO;}se\ Z0nPL&FbAe#v-$CH C:MRN/4kLѱH8;reDjl mtf^e :KUo-u&[aSu4nBVNTg8XcLn7לsY'(fIէkҩ(8Zex%,>R3<-Ј^Fjа늈?JGİj~":kr5Z38 $M:QLn,Eߒ/~@s8;= FdڙhͿv pj4wj?5O]Mt4oJ 8I6|nέxmcEaq-0NzgaQu rvVt숫?cF@ߋ%U"oZQ̪hR\Mp2*i'tH#Ee +8hȌ|y 'F⥗p~$pSS +TR(jbYW-ї4vfk$F16UW+cVҪF-gi1Gb a5g)!O5␛[\^%:a#YҒyY$19Gћi$y.Uz4$ xk^eC[9=9Tߴ4j3du;x`vXFDR2}:0bɢBX3| ϝa+Bq{٭ԶXym4nWi{ 1ZyReb"Qc,,2RRC~iks!)MFo'`*甗&oڴ\Nɲ2 PIA[YNx4s*OV.;FwlK$T܍۝.Z!+4as]V3h}r:ps˞f0`džc,k:'U:>=&VK+ Qp$r>B mR23oV|\2,;^բ΃.B2G%h]}[OE֍tB^RD9p$Eqwrb|gNwm aC7,ox;P l"8`>騽|p3+n"nq{O0(os`&h_FtFoe_0vk,ŭd3Z[|[R<'(a@8=\*X";aҡϝ }}k}Q"GhAZ/O (V?יzV +jT)|2r6k h[;]dWXN,+?LvDk6?UD L/Id@e:ZVCڟ֔޸]BPM%dDT 9(#ޗޕR-zzCGr)E;T&@*tY-i@F%N8{ +W32rGIE+ +e")$ +c 6݈޼!N$pg8^lEH/PI +3V[N2C '/TN~ 8J̶bq컕Tzip_| "KqUo%HphՀp-bIYꋛu7L_e~W9)lTBnš7;C &:<%fH=6q3e1lK +92A1 ; ̦VtWHǯD_H":Arc{XNm䖈бʐB+6PB{r`{b(2.eyC.3#WU'rHHKۭ~y(n,~{<*t`86Z CЎKnI=̙M)zWVQOӬVh*RtPvGyÄ[Ȯ/[Њq t$yu;zq}4~&撟 +ol܏bJѱgT]=~ В?6h@WYͻDCq0s%R|vepΪ&]Om!JZ)Sfdc/37s"N*TBi井vj} \-j>(MaTS~F)XO! C \^;d#W)δ uz+T8#Ow-gfi@l +ޤ/2rE-@YΛskpu򋗛MՈg~]PFeubsdwCCΕAWS)N'3EFR> +prb|=IGh^E5qy8C'%l8bo­xDZ˜菮νI:L}CqPPAG.zb>RO+e…l޿xdՕ(B! +endstream +endobj +56 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +55 0 obj<> +endobj +58 0 obj <>stream +H\͎0y/gTU1%Ģ3J}p (J ӫYp>ۑeߵ}84mW1.3udTCÇ/v?u_×x6T>}4ulXDZN~Y6 xdn^xZ ߪK4ɺ1/:^*ıN1Z3ۦe߭j>slDSpNJ''k6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh9\pֹJp +%qAYΦ '@Y^vPD (K"cC@Ye1ޣ  gWn$,6F"t#a{Ѝl.aQG楪[/mKK9 +\#%^~.Wp_ʁR={*/hݳDz>98\8ߦTcb2,evqJ]|C?I,OPg +endstream +endobj +57 0 obj<> +endobj +60 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +59 0 obj<> +endobj +52 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +63 0 obj <>stream +HWے6}]%q/Us{H%xVmٮ-JŒ Ix! ;qd@N>}y C\>= u5DIi,>{w}{]y'IҔFDJ8 ט"$/.'m{ϋ{y "Y^ڧϑv#9/HTE׫Ohpʹh#ZIh_b*/xgEjoW_sPqoe_9i~r<pX8ÿ\ݿzWx>Za~QpݫWok|ec18]AX4㽻.Oe +x-[#(GD$fEiy"=o׿ݛ4Gx3p Ƅgͮm{iJsN^l΄AO(%.Qv^(>u\Wu5zq +?S1c 9|Lș|eNӘ$ t5}oi40|>'r +u +ɘSiLӿ.t3TSüۆu5&TwZ+/&Bsj'=$ 0bwK$:|.9o40L91ɑ])1%f|x 3F7n,Cd@RliJ<g2|kKP LNU)06O-N n"%:¯lU偉|Oq .h9KD,-4hƯ䅘9 7z9!#h6/߁(Fu 2bgcDDcN|l6C"w *6Ǧz6e3x-A }멥9 ߈W.(g-e CPlAnѨN5F>#0MńGMm'g-9^mz+`24&d)S9@ 5VdivƘ-)4Q1+)p̀ f(if2/gsnl'PX^0 r}ӛ_ϜOou> Z$$Ur:}%E>KP9XOPS͐)uui!:L֏ M1V/.\D&bӕrfGY6bޙRIIZKC QDDX$⤫+U'VZPVZ^î刷.BnIt)mK=zCcw2@RDIDȸdnZUl/bO.v' C=IX~{|+ ş~z&#%YZ@ˮCcW]rjx'?OfK$R9kii"j0cT=Hv1oP3fv(d#v=6hB}Dre.x9PC=DQZ#'8@ D'Ge]큪S ILQ7qzY?#L^q 1%r:ʓ$| <pp)L& ^ > S$'+8 n4܁Q.|?^@V Ӡħ-hPGs#:n-1'(" 8W_d]xI^LdӉ+Y@3G`h*%y?̻*ЙAI+koyn}v6)Lݮ][|d(7`"9\5pȐW5̑;0X5&:g̺vvAfufsߵ/TQvshnI@j]]!PfY@i4"f0It3!0}QZ883[#ĈӦ[)Z PV(];/PlGVAJJ|^3M-4qyͣh"QJBPeאǿi1B +ic&.܇4Lg҆MRMU[MOfumI%*0C8ML}!l$Kǟu6e%0SqRl*$ia T%)W+lg*D! +NLa"cP};s 9vݶa(+2kX"i3Y2zS9Q8p=K):!ZW"PQgl^w)T+#-$f N$/qp!3"=|,%u\Dx"V"X>j_]"d/%|^jBt<>7QKm Jil2%dUBBTL*U#k"dGH@/<r׶> HAi+A{^$Uk +@3iݰ(CּȌ[% \߽VXu +-W!Ư9kUHӓF*A)=b%, AW1MDىkxXpV{9qL7S=2vۍ[ؗZg&Iٲc cՆ9#}7C# Ēw$_ +F fI4?/{| Ӓ3&n8G=|Iq7Q I 9o[R2EU-_!ׇC~_(wm@5<6h:4'L +N4ұHc|\}+ +endstream +endobj +64 0 obj <>stream + eeRf=ЫV9x &de p㝷\I +I^{)CG撕J[pen`I 4H rCB5jg6L;YBdv5!F1OūF )%rI)膻b/.0D/y3D Ͷ*NvuER{e8A꛵" d.g/ jl:Νr@)1 $.CԄȖ"[L-kqq3Lqބ&H 6Z(z_W3a'nyZY;;g-$zy>4gq۲߃h/ +D> yh=Pd7yoUq$M34ByJ"uDXҊ'g+Ǖ9wM~rg~˓1ET3YuT FBkE{s1 JtTe\ Qsh0zz!TvmGàȠj޷#iy+- xniS  +JS"Sha  XIw D@uV%<"YZE?iSfad"V!ϙ5)6LR| TdT7:e Iʜ5"fǒTq1#b0FƻN$d{=ےێ4V?"_;Q7U nrC'+P;Wnʀ&SLd^sXI#f8DŽlBAfXݰG1eTvb9G2lς62:Qte\P"D1%~Ȳf +FTxoqIwu]=ofE` +ZpBX&z#1"9rH}F8T%5h.KXsF>ӏ'Ido[=0s)ې698I*u66k(OBH*Fi|[6jT;An;=D݉"`7n}/p5} Xzr@Dbî" Dgt@ZV:"*ӉIWNm +mXaE7Nq:H`vy _wra}9d| +yίTJRJ[WWKWXzszdY3vi$<;xTU43w11/j>.`\&P\bsjdwʺNUDzvQ:^իmvF3յ[`SUYm|&%KZ0 %eHQWp [Ю+oKpR@+A0v-o3Ul3cNj4Ru ͍iNsS7euY60Ѓ[{NkD %Пaum|#mr5Gx(9V<0Ӵ zU5iQaVWӷCOFCe~:gX=-]:*j%${+5rP0uQ(wz B벖  {.C̛֜fv?`Oz?p7nm(Z4rJf`_;3gD$I{DޢXHB8~XҟUYh5^Dġ^R,esU(1ů^Щq?E6K$C7>]ڐB=opz1[g* 0$l,clbI:Y>0kNsf)zSa"Y'h;7bv0Uz)8$2<@b78m!jO]XW +4kGXN4,s aN?mH]=gtV+ f +S/cSp]~u0o,\nHQ + +!>ovD f@>W{4$?@4oh?ggDj?KlUB a#>Yqn,}@셎w`P'}bg88k3ץ~K LO0\jrL: [4)㿨IGnCmTҬ/ShmxQCZ{{S|C9! 0ez/Kz1h>aWElV܆&nzWo%"Cfs]N[KoHun>(24($#`/ ;Mdo  Z%$cx_~Q&Y$ kZ0(LjElJW f+ p P'9Ai#oW +_?O/,8_OI㤳`چzi9A^Vu g4 )pV^C[hˎ&\&ѕKYު8k2[ja2iϧC\H 8?:di eU!ğU g^1cNTF?jڅf^Òջ9j h**eYU2J[H:I%(Vq{-3.aCഥ^Z_5{m.YT0F˴,{\BLbwe$,4#^׮#1PAҽ!*ף-^6VğpE8N`yBtw(| ot($RO7eL_sjeohG4H&=thߓ8/`0V(W?A! +5 €[cBQ']X}ټŬ*#tk퀉ӹ$?c,&AI  ![>foia8 71=%j&#sԖSbTgk +Ái%Ef ˥?RnIW>7²5~GM|M&U,XgL7;kxW#2y>A&1oU!'~x+)͊<}uz%4<~m${}.di6w8l:b͹vI +rGw 2??a9;)@n4E)Ji142[D.ݼCzl6LɰK’ $W& o|7 +KΓ#~H,4!@`_ǡNuHl'%I?0 @   +t}PMEe^vI-$uxUfze"7WϞY\@A!?䳛;–ᦶݾd-V}u uC `C'>]ӻ)W|;GHXu#3NڼbַL 9n`*m^%mR0S ~M G<ਆsRNrY)Qj.|oP--!(HFQ#Ɉ5y9;- LJ'yhn@r.OۍƆƉX=e2GQkouLyγtET܉<6Ka{^q%JĈSGq9pseZofBhꙄ{| ꗬ*\])6Iui|:j +6U9xC(zpAV_*%F3@{ + YU7Wb6a(]Ril"x˳ ui )m58C6saXga kS~B['`92`&' )0k.UL@fnjJ=_ o|#š[+dաkF{GuneqOWjTS~TO ^~fHiDcK"|{(9bYO,l2 MF?qvh5D0Oj`"'1Nqٻk)Y:ٛ -_<`ȫ4eP!1=#ع + 12<9BuD +Hv{AMX6Wwg>7B g ]>Vw.?Җ` 8 i$~PT=ilP7K|78H^C90n48 Ǿ*}`fm:{+Bމ'~!Eyz.x=Aţ5$Q\}8l.Ih9YlD+wY 8Cˢk*&ټ.pPQdWg3~JzI(f8 kb;:1@DI0(;@qܖtB *rhnFKNp/fr +N4`ty('4RR`_>>񪒼* +G=2p@"ZIF2Sl0Z%[g`~DwTHxra,er7!%+lXF/itA +Vit>%KBa_P9*BN8 3G% 浔p=?|`vTXOOYuQza:eP9kתnE7rDbŖeOs޼ 7Y?0i!Lo= ;k.TSC`Q$Ǯ" +2 4 4؟(6{Pd +"iᦅO3A!T(M 219??4xM j/'9kP<p$`=/jǂa" 9;[Kdn1U;X#73K0E)Qvk}S;7ol|3z|ћ 5y=HA W;R51ףm]fnNQb0|}h#@G^2+貴)J'5W>AQ8lm]'0 vxShLkPX5鉧G .ȨnUf NK\DE'k,OxZ*1FDtYT_Esh| U7czv*o :VU"p"À')Gi sA֒;Jh}q"u$gkG"Y_:k5AY^7ԟJ/*wkl1͑ʐYg zlbjJ X +endstream +endobj +66 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +65 0 obj<> +endobj +68 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +67 0 obj<> +endobj +70 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +69 0 obj<> +endobj +72 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +71 0 obj<> +endobj +62 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +75 0 obj <>stream +HWے۸}W%Uvj*Ru%q8ĬDקA ̋-@wׯۮ/]Pf׿ͩˮ߼i~d_p3NL2}7fo D$*g9_Zae(c{kZWCXo˻9dןͶ˾8>.],LLoW}p@g-^~yDw41BC''HkI_}(w5]1juM-(PI]$;x"obȞ$DBVN(\+fkzPܞ9UP(mS"E76rLvӱkxq"(ml [mWTux>c>30mQ?T6^C2o8U7reWQQ}yDc<~񀤳}U^ `#qM{Ox%¢2/ \Fc($fcmQ>!]-#p^O + ʁ#-P`c.egqo< +TͱUo9JPZ>#G̠N]sj-5u-+fᣇ 9@ki `n+>R>Tڇb4D@'3`$Sπf#ͮf负$1|:N[繚`OtFxi\q5tr'cwxD=m›4  +،O 䂟'iK<)1xRciff3Sɳyf%|Jy.QVbq"{( +sh|AMA<.E<)ǖQ!a[gVY1x4e>G܃- W{@<}#Sx3L1U>?.W|2HEI" ' Uq}~r ҩO1-]xBIJrq !8u^7]UI,# Ͱuu8:mN IU;﨑0Z-!Uɻa[=2dAhg,Ͻ^z)-8j +R0+QBPGm/4Pþ^@&_ń7j^:e'\ ᪱J 6Z%?4cճc؀cV@-L1ۦ8Q\]mNmT X|8m"`sO t"އ1^L0d%`_էdi̖ Sh cݒim. +QF6y =vi zDMRgc9N\z@M2VeFV; 3 y5tp@(LеII;>Lx5IKM8Ddkob"/ǣw-*drt /+T6{/+ }Y о,F [(Wp?.AbPucf[|NɷeY[8FM +koV3!e9ρ,ojoF }@^ A]-s-B (P?Ly.gYGNLPlԚ+oN^к }M"pvf+cHj<ݰ1V?2:XȚx z[멖B$7 +}]SJUН)t ;` մòU0Q &7w'B +F}9jvTfSc + RJhȑ9tv̓(;PIa~vanʺl]0o ÁfJX >pba[cgVv~cF[]&h8-qA#?fG Ya0߫fp&]i G\4Z9H[μyx׏4{oiu0Qg +۩^:f P_]O 2aD93KIeˀ2*yeUB(S06}7W@;fJpy ÷y@K x:$g[7WA J*~T61b1;w0L'5t>uR`: f>a2_#C<yxPR}JK>E%YB%f*:(Aęq@VX=s}bRX]|CmS.:CEpGJ|Yuk­;I9{kUJl@V? Z +endstream +endobj +76 0 obj <>stream +Q“)U\VZgY:&9#x)TPK6q +˺y>o]kKk!gC?j +N@$"+x) Q{sImfÇpş",DanR˺]FS>]P%6&z$.h%WÏ[ัNou9=Ѯԕ6VlE+Hڐ,&?2!{w~`SH>~bI:iYlʀ&U a:{OMF 6˹u+õaxlJF.m4*_xæPʅ .tpT.A ly!zEkrQ.8ƿZfؔ"ۋyWyVH?{_mX< _kT8f-h<7;`3.ʐHC!\l I7 sU:~2),!M55uL(ȒY(lٟSek8]!"@4 'kyLfK<>u=a .Ŗx*"HڜEc+.SS2xkh)SE; +A!瘎Sb~FoyrFߛƶL l.zUcBقq /AH)Q5BeU]/;by~w"ڊ0W&̶U *#ݩ&~ޜeY +RY\ Ȯa sKQ"̀@L>>h9x2M3zk3qR-lz8Mº3c }Ӻ g.r $ħ3ByJC\]bVO0(T~07(Hh)<" |Pay=Ms&:ؕjx+jBԦ"5Q'肢'Z|Qs9ck`Fz#jtYjڦx^E0NKZtx BߴI!m!}?1= X*=RXP;8OYi39KzsLHk1H\NhKԤ :`̛*,^}r#/̡m|̄iBZBr %>J =mՃgUʀXA^:֏}R-mT~o cbxd,Ԕ*n.媱 rM.' _b Dh֋{ iwl +D=z9sâ|Xϳ0^%@ߚdN +s 0>\O06նaI=~ ư}A9qn_Jɜ]`LLʔ~o r~GopFHv܊?E +ђ[9<. f="&x"_]Iv2 I 97xJ/E>փ RV`{ Z ^*1no95黯IkU!ETIf d+W +2_5((f_^ +j˫kt`-F>ioLUFԚԏQ!kh\!g^v)|1ZC +u)1#z;Ճ SܚP85z|Wi9<ˑՁ|u>8sG͚Ht9h.:jhGegg2T. *3ʹ5X`Y.Dk2'jwMeܘZQ/ & )2 ]#hMY?K[sټפ,/2t)jg 8S-D?`%$"C>k `v{- jx /Zwag3)7FBP!yPHL<2w,p\q h-PI.r}ݎ媓m4֬zyS<^< m=Rg\7GNP'Qa} h|쵄wݚo2g2;_^${YSp[~|YA-)Ɗ%"G,/jc)8ѿ^"0A֯7W) !\s.YZEd)i?ڎUTtO+ݥbv5_R!%M5I!h?zvq쇖^?'9n8 dX'Q7 +ԆSOp Y#3笿 lA;[JLa=ct^t 4#hX;]8vtz bZ2QIsޫ|XU0U4]/5Zc\2KYEͿFU0zӪ~X]WrWv w%CIq}iV4x|A{Yw0la,-g <biFkR哟dsUNqbYy3H! ` 9K`SDAPr +uj@Ƭthhi֌Kd=@̢!V$7;=pZ%ѓ8P 0t\$0>H^X:ڠw2Q``5Rt w2;" 9/m%8c guBpP˄=b UD?7Π8;ްAkQڽH-@ *oS@W1 +:ɿtwiuV,Gw֍!X*An +8j [k$/XvڰTA!Bl2s ds\siO-Wnu.SI$`+xoKUjLHE!ha5Ḕp;ۓr/ (6"q(75_Hp#Zr`+V`{ ywzjhߟCԶnɺOo@{Q4z'S*x$ZOW 6_Qpf|w6T=*~?Rg\1L7>90HiqR| jbZ> `^sF3J`ԫ^QF0;jU=Ittϰ7 VMkoquc~SJAUͤO,HϪlg㏇E¦g'䭚(c zA0ho: K>9Nqs[ +Ngb͢CgZA7̳GDHz[0m`7ŝVȆ bؐ`AGuҧ{0³5Q!`5 ?9w_s`?QB>XUE~5"֘o4:qS[5~ JV$5{tOy`ĵF@0Dڼ9}k}C eIS-V^wzTjpVyԭ{CcWj +22"@W@;#` Yv ]aWр<|۽IpkRq߀`ILGsP~)IJAtޟ[9Xj!:]*MnrA7qB"CٰdT+ߘ%֏pTmy] c&&C\uI\bm  X`f7"t+IK@>-d)L|+Y<2 Mnǣ84B#ޓWmEZxEB߹=ַ#e&tT$c&Z:˜=hm;3Eٛ05f%&+g1-n"RHbФW{l巜i@k9>U]!E'~ܷe'ܐIT&{zڡxm#2TKS6#4>!;~WUլc?PQ7e?yF~*fc^#P&RTz'2$<w?JÓA_('@JJtPNzfWȔt &=B]0o)^}ײ{$YWs_bhq 5L6H}ԠCâX[Vyo/4|*Dp=SkTBi'3U yHYV[G^3B;*Kwےf^vFg`>bQ :MjyA{L/nlI@MŮʨ}MJfQgુl98U]ge/SzD_;d)|{9-p -EHzG[>(%,@U_Mca([ayHБ[u Z&9'Ñ?˦> + 8EU& +(pb]QInGiWzE\l$(a &y;四6Ӱ[$4fM`%Tϰ yw j*Sw(u-"Il~ +.sfaRx^)idy88pw_?}e=Y'X #]^ن|(B6ȀiOF@£'  I!XkC}.1a9@t X .H"964u(X%'h>-tU\G7]_ 5ςI`rce 6)&LSz߳40lٮ7x!|]#3zM` ^WѤi-5Ru39]|VNL}-K,hМk2SZ~>stream +H\͎0 +_gL7YG{6R1b޾>2"G䳍|D|>>~UyOax}TxSAFޯ7N?(᜺Q5MQe_O/GA9ĹOJ?rqiUIn _ Q:~ qKX4Z麶)N̵]h3 -;88*jZ `pN+UA + +>*H რ +>*H რ +>*H რ +>*H0PQ6"dPc@cdq/dqh8Y'Ȫ 5phyp}pán8kt{ hΡkQߢ(jrd[GV.0A/#{9HerRE/u^n%3&cr``(> +endobj +80 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +79 0 obj<> +endobj +82 0 obj <>stream +H\0E @zmfӸq&)CI.;7Iؘ<*/MuNGu~,Ȩ-􃛋2[c7)iqݖWg?ys/?--ӯ^8nJ3i}!ߗR_O!qq-֭j-[S~DCk `lĎA''GN'*JX +px@ D:/ რ +>*H რ +>*H რ +>*H რ +> TTM碩a1 aYF 'Y,,#@Gz jG 7x7Fxph:1n84p:shFZԷhnhnsEm.AQA9KA/C ٢eE9^6u^ .190\0f/Ka<(yraJc|4JxGe_ +endstream +endobj +81 0 obj<> +endobj +74 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 428.16 631.44]/Rotate 0/MediaBox[0.0 0.0 428.16 631.44]>> +endobj +85 0 obj <>stream +HWnH}Wme™x$AvF` Z,$QCQq[;lRr2@.N]U}Ꜻ\^MʗM._c]zU}nq3Ne&>|3)ifOHj֘rc1Jl]lqkvn^]5M\ڃbd|r7e p M71f$+٫rA3-V3 "-pbdCF5QZ 2H Q-gT¿}5x$Yi\iuN^3>I k7"R衏_ջ֓Ƹ2ޅ(!3@zuPr:##1Mp6RC.q5l_?C@G4h7m}*{Y% 1τЈkLu#.Wp=XmeK@HeqąW+8s*RDR0NA_ HGg3m u񹬎%ȡ !Ƶx_T8V*b,]<.qϐa,ܮeS~NH]b .Q.sF0'XH"BkYΛd>$}6]\k.eݦ<|T%AB{ +\ 8إiTqLG] 4X>ʗQwqJOFС>e-D֔:oơ.=hE>ғi=egKӁڙhɗ!"Lp|u =cd>4iR$K:acp܎c0÷K3njdUM +eX:g otI2SBsbh14Ձ#k{u}އToGA +=qEB_`5GOWm\Y}Pu닉(}$[n?>Guƣz{ipQ*;ۏۇ{XITD־Q#M + vHЇǐ@qeP"k/*OPzbom{=o5hD& u\ J~ff tL%5VHltI_c˵A lfrlJ<ԇdmPoÄvu +o MoyZ0?tO8 t(' 8ildWzAF̱cF'ޗ1e;?z) '4v)ed}^Z>HO +/=싡 e"7CC]s,(q+49eF8kyBkchi/a +A2gxۖ0/ o3dOJ i='0v5v-S8O5 5RC;Ǩ5@C$8*CO?$n&RG{Y%|761OkM-7Ŗ2†Fh7=.Rɿ{riIB#Oa^@=Bɤ^Iy65SttgF "' 4C*Zm*Qwî=1)k;C>0'ĢN/ZȳُG\N,ϵ:w"_0NWpI/fGFSWձNQ(j1}zx܍|RZpn]lo.}]-!;/wEX1*=TXwCޔSsCA'bL @\"vбNBDul˺$TH`{?+"G)AQJs4)jb>XWrByvțb}<\$q D'̗.#ILHu(~J +:.P٧q]|.C:,%$uxqU_5JSEaBH8zYp{R>oNkll&-?~lGaكY$&%q|@ +>YV& +k67Eӵ4 m ?]I⮙umR \Xg-C8<1>QrϕI oQͨi5QK-sj\TǙPqnP)Sd9m |ϯ[`HEIhyA@́+kʦ!q_ߡ%yX[ptƇ0K,g舆f<x ,@2_"/*SqdӨ^vg?%5.Ie,gǶ}vxBeY;~?HfHnHd믓%D,V~SCwc%:ӁLxʤNaj=D`Hh)RV,#ڽV6!s<^-,94)Յ}5q_p@It gDj?^L:ormޓi"pozpJ/J]ck]6q|9r6 8ؙ;[,/,mxax3˳:@%B>M˛oAr4O^D,Ӱ !xN[^U }Ã:uѾ +eU"lU^બRv_X51X#jzQ]?RSMUX_IƄ6Ù{@2T01hBne M]qs{v3yhH-Mm$>%1%]%!k"׋Yae!#\Ev3.D(_,9EgaP1N@~ɻo/_||U}ן鐂*)HB,`*d>ڭM,2nd{bnÅmFf͉~SKU8^ثö҉pSI %hA2|-IBC!י4)rSH=K8d0Ga@c7)`7A9bMrs@u`믋 5&vQ=X*(Rh%5zbsËFpaȉ%{TJd]-(]h`8#>stream +$w//;7Vr3̣u{%] ڡZ v|s.NB{'?1`1(n2Msj貣&Ixaą Wl}r[YWEϳ_ +QPjP[=S?{xGV7S`4|^dv߂c2pF@V\ywI{)Tri +F o$F*U 깡|q~m%sPbF]3eP*.OlJ:/*"SGaU4xxcY[k04)0q(OTۿ*m/\$@,RzS CphP3r|ZJ{LUTLիO!cgB'gg͘A^L֬"zt?"ɃԱp|x'm{v#ib|P Vkޙ^lNq>[0ȒO61K *e掲/]f~+eAw' & ]e{"5H i +DZA"gXo8idK +6} %FjAY ŝu.mlg'^dDtY 5c!KV.D:GPËpzAӲ IBTԭweL$~m"1Clьŀxd(XwZdIΊ[-4Yw}#Yo.aط4tfQZz %i|]gU*XL1ox< pܶCuNjhqw `#zLDQ*!o6L_ھhΙcH~ٲE]@m_US}kTA=F{߂ Jz'],Cא &af,>O[rE mC8M[<`sW|}\Z d7͙>ՒQ!ifQ Ngc'}hԮR5Hq42/h7@4E Wy =>\㸏1L \M  ˲^mn/`͠ۍWSt$`Vo{b/jl6^W!.p|ϳ eWMSZ6xEp )H,DPFAw3R- {R1G? *6ZJ/@bz !WuĹ>>ovYu  dkAS$IR=&Y 1@ +FЫGAAtrSS7Y(T'C gnTmԠ{$yq?Z`PC*San䠅v)Tϼ\ʽT@]i[/\% +dt- xԵ^oi/e﷏0S)T-Z\V9u|xa*[PS,ܽx!gfdmhCa';=˘o zhzQkm'>5Fݩ~3>?Xk$=Z3&BKuz A"ŻG5 +㪊)kfn[?0}+$yѺCѬk2 *iWto*>TE6 ơSCqʬU% ?sRg w)vu$ThS=d~;D<տF!SS/`sSï C*&W(Ԍjd:rY& .d3P/FyJ?Ҫu i $ V۪Gm!.z9މyxov; Ku'QDߙpt2LRLxNTΔeoǷl uY fo"v[zWCHɡ_)Ǎ+Hh;ɢuo- !Y4u8 ;PB@@}138+L 7i4=e;͝,N˼Wd=4EȴB>'%^Y]S 7  ġǖf\46`x\}^ d!gaN!ʿQFbѵNd 4iǑZ2V-E=ӨץgWG^y2TMԋa~حXBB9ShXc3G9hlL#fȮkq `%Nt TOq,Dګ^Z.Ok!VhkF #T,mNN{:NXH(g:qnG\y78 Aiip^W X:,ԮB8p \ht3XlIOo ]'WeJ桺j4/F$3 ۏ2ۼq~c/ #PA^)*iBoq?Cަ3>ѵ4wMV΍# ] oc MtCּ~!YehȒ-Za >Vj;ygۑh7n'< UiXU\y(y4WA[9:abIeY%+ሂ.С y%]32 Z5K WL + BncfP6J-Ӝ⒫.QJC*`TXhΕإi<']-劌RvoĒ+^2S::HD-D?nduxO3Y}^'Ѹ`+ۈ/8(,)EOqCqq_(GӹfLi: +^p"u~ 6mV3a°R>fw-g"NO!k"iѴbV74H; \'ӛ0cގyu 76˻1>!d$LH +QNK5n7UizzښQF9Ʉ"8`O6> +7j+ cԻxԺ+}NtaRL/I8 ؀‘:d-}Ϣa#R{-ɆQ|w?oƍ aX[~ Ⓖ=:իXA>K<~ M[XB!GBz#VM}r1d<[P8ܱl;| U!+V38m+MVPע .?:(Q>aZ(Zj-5:mOKD5HA19m/x{ X5pd2a?HC+ 9B[vn[JkwI^Lzl/З:IyX kyvq ˆ,¤AGwFPR OCCWl۰rUq"n")YИ繳G'|=/S2ߤSR//"RHof~(pBSѽ)H;۟~pޯ=x2Ƽ!X C4<9"Z>߿z; -( =$Uz}XТf`O-"?ԦH*TpBy9MRΒCВD!$Xa \NpqQP&qGtj;UtŌ xo͜WkfaŴ~KR@^7 B||޵F4*y=o$z,_k(:! ?@gI$iĐ sD|^*cL(rz|ܗgkr+O-'lT,5 a9H>ĵ;\(}ܦDLŵI,g=-X(JyS,=)bfuqK$Runv)iĥנ}oM$Q1ً'l|RJM4 ,Lx4n?xXUCçPE!fGgzsO~?)rȗu}{J8+&8h49%~ĕ@%<[It܈Հ0{ KJVGzmnQ,TtKK!+'a_0< yc +jUP0]\B|f*ݒ{cu6e\uC!]gbOXZ~Q$tӚG+Q*-pr +?/:>dlB7Jl`&E+ѹZȐ!)"?_L8 <0@zXUFaS)gyZr|~l8FD&p?a=y8-`l|Ұ%"ȹ㙧AH,DN"?;N:]`U|_!9b?vj +*˓+A)#nCY0l:x<(?WHjpx~zp09gFLJWho {b>|ڄ]XL-gvX!>%.c`_NEݍZYA9, @ۑ1PNt N?Sk*(8{vBAn& +=V[ T~b0:"~Tlbku'*U!2gMwݲcRap- *I&# gYIp.&m) j%K82djc> InpRU& \wr^}'},&^.Et4n)Aȅ Q@` +=Ft~#U>?G]zĨ( + (ϱ, '¦Xq?G/#{iM Q6TaB'嵃WNa{2:):AR( ^y^63`DY6eE P#@ogF$2v /#蓙́(kQp b%\t mT!?ֻ*:p= )Ȝp7WRZ8Ok,;~߽8Rݟ5! +ߐY +ݞ_DVO-CІw:vj撓Pq;u{#I`w%dtgO]J*`w"qR^CPBTـ9ZGtvJlL+_th'M=LwTW M8s QdJwROWWi9&e'GXaஞvsGO||h@u%yY"Z"fA +0Qr<SYI wnݰaMQ;JL +mJ:wm^I0CVb;B8y"eL" .۬f*Ƴ_ +M3:,Ds_  '9|LOHYi#ŕ28NJyޘ2=]L!hwB|Qŵ΄W>n=|hgh5N]MƝ U{<d~^Y|Қ@ʜ"xu4$q("-arlY_ɰO,?k=ؠ W&xk^m[#{]xd'8<0ea5(>P4aԿx+UWU +0 @   +i +}RF{jDS.@Pr,~#9o[ipPv + ޡ&B_]vt,3~zwͯ6>-G|)xhŌVV~h(nҸ8'Z +mA4O(QXhP<]jׇ9J 5fM]sr+;r繣*W%^#ScƇ{E%lV+[i,)m뛓%J!E +(;j!Չ +z&b;fv ԏ.0{pKgѯn Þ|4Ӿ1 P ؇ad5f##.*vvm?L_{7k¦+S߯;J TY yΙ7Gx n}Q9m }'2K[i%C͵.zhRz, [Hw\,,EY*1{fbt.|Ni^a|&n" ׽rAE{koqz_ x$Fk>8#dΆR\ۈI5,Z3\_)HX ipPXy%3La!sWAKI0Ay7 Y?8ْwCQj\*z_C^twepuIN#]L2r`yu),XRonKFQgI'*R.jmBۺY$L-H3&`j|f>c<9"̀Ww^zhFHSO=9k+vtJФ!Bdu&ߜKMV5:#9&yFp璵kv1^|Ii'~>hLݡ\lv4تaJS;#IqF/*F$V87ٳtU!YZJ>etތ-S'**bX`qqX_@޼OLt@iH\Rk'(I+ki;t2FKn9[$pI*.c<%Rg?]^|V-82[:R [ZYY!Q =8%bWTѨC"RZ iI9r =c0a:CضfyQZOD'.ANS`H(A3tx6kaÊйA d׳hGL!dt6&Gi3E'ń=CqV7&o' Ⱦ?b+w#M\ 3K\hSZ/ @V¶@Cjlv +I,1y谿.@wiqP)&e9P{#ڜ-;aqWiR;Վ^kE-xD=Sؽ#fd7߸KY^~[joY8>U&:)y7Y +Dُm2X;xwʂܧ5,f .ܳ"cFkZ8p"w)IeS<9ߛ]LR 2_?/4z?~q¢e9c`Ο'ɘ._~BUNngX=&Y<-;b-Aa*$Sa<^)\WLC18|ŧCa-MPhllE02Pڎt%[Af2seEܐN"+Acj${6Ɖӷb*n@L;҅_ho'-w2@stx@i-&; +J2<vwļΒ%⢷ה +̄|+^QL7oZ5-au* dzѸ}k[Z U]?w(' U +9SvTDu 8^Zlkbu柬qBq}vȇ3tj($kPв(y '!( :P*"~q*yal4|ID#r_K{8}i VPӂʽ#D'oN~gSlry*JF) +\nhZcMdMDq55!NP$3*$^a3=kRbIkHrߦ/h%2tCnUcK|t(bz% _Ge8,^N +Z;>q +nAJP̸dw/jlY1A,MX!мjuH[T[!n?r|fQnPIiA/`<1|c>9,wDuY-Qfnkv7[S=K]*U?›Rq鱔j1C =E,3lK# DD;u.YҌLsێXV*v:($ƨ.F/+iO 쨢М*L~X0]Ǯ5%J|u%av;bNtC =|jHbzs)!7C gRCH=?:tw C }#PGSclq/s |Q?#(VG9e\uY-1FZTN ]Eb߬PbyQKJ'C,$DdrxtqFyHb(Շ2PzQyT.]{`6'怵BkV8L67~J4+UriZqr[pj]A$@p`hI!<|޼jyLǴSV5gjFZU8#Gо +{V?9 @K!aZBQ +&tH;GE'HL(tnnQ:S^ik4j#„sU{*UTjv''IqQ*})?q DwT MxtrD [PϬi"Sg(0~BL 8:,,Bz8,"V4Ao7\Bol"҇y.g. ҖI&c$2"h%JpJ|b;Oбu DeTdI.uKS?6u,:lzi-, k,v.9F|E`t6B D-.{CP0BYe[>JN#81&kgC +6yٞ5,n蠰W]$sr)&fbǚ;aS'[큂XSøTh[ց*J^;-E\;]Ad֬d_(*!`ANn3ڍ-F 퇚ݎT>ٺórFdYF]]#'bU"N*;*Ks;]'̈́.]d#oU2^"r?`:Vr\+}r`s=ZL޶r3Io`ٱu|MT~kʇnE X JBmj | +endstream +endobj +88 0 obj <>stream +H\͎0y/gTU1%Ģ3J}p (J ӫYp>ۑeߵ}84mW1.3udTCÇ/v?u_×x6T>}4ulXDZN~Y6 xdn^xZ ߪK4ɺ1/:^*ıN1Z3ۦe߭j>slDSpNJ''k6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh9\pֹJp +%qAYΦ '@Y^vPD (K"cC@Ye1ޣ  gWn$,6F"t#a{Ѝl.aQG楪[/mKK9 +\#%^~.Wp_ʁR={*/hݳDz>98\8ߦTcb2,evqJ]|C?I,OPg +endstream +endobj +87 0 obj<> +endobj +90 0 obj <>stream +Hd͎0 +gtEt'DH BUQ|wLC8ٴ]L6ܧ)>3M/p,O9^};m^_5>}.a/]h?&Y}j4+</M e, CocTUMն,?n9zx=6@S`CQI-VNP$(^VDpR FHh ڿTTTTTTTTTTTTTTTTQE!lUJ8\%'$eI<&(Kt(KeIH@Y;*%HXdn$HXЍDt#a{Ѝl.aQG楪[ܯmKk9 +\!%^~)pX_ˁZ={*˯hݳDzwnr.|S>Mi”-mS&}i. +endstream +endobj +89 0 obj<> +endobj +92 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +91 0 obj<> +endobj +94 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +93 0 obj<> +endobj +96 0 obj <>stream +Ht0E;mbaA0qHmiߗtxBbѫs{zk'piڮ㵿!c<]g6L_R Y^S컦7mKb>8z?sٷM?udnpM +OKu&[eW }CXumݙm<3|DSpNJGGk6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh{-PY(9!l(K>AYΦ '@Y^&(K"MDʒHPVỲ(Fº t#J&Fb#n$҄' ܃n$Wgs >J6/U}*~i[_Qg/VGX)sZ|Rr/U9^~)G랽$իe𿟾s7 +qLLV0nu2eo0mJ +endstream +endobj +95 0 obj<> +endobj +98 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +97 0 obj<> +endobj +100 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +99 0 obj<> +endobj +102 0 obj <>stream +H\͎0SU>$` etEԴl" Bm9"m%wɿOCsi>L6ܧ&st}gB7ZY^osv0U?m^!OK`ߛ,68u<į+<%^c?+d__k}&ej 5CnTUMն,5,gέ޼h>@Glx&xV`KU`GS (( J> +endobj +84 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +105 0 obj <>stream +HW[o8~c $ +/.آ& 0lk`h#ӱd_6yHJfv_Zs.C?6kYɻwWJ!Ø\]_w?o$!I$$M'%v.n?×WuQJ]-}ry܌ɽ N>6;96Ά %,Qp)qA&Y\/WK;Ih\/HJ(-e o,d9$Hxi wYQrx*yv99>ZDp&>d}bRiqH9Ef%Өfy + reSQ1'#l_k׽t>|ǖ[2u3g%;=F[./,W7`cV}/9Wf^݃|he ӾUzRJ2φl[ 9_ 5nxhZ_O +fZlv}%7VYsa4<כZXRᒦTs*e}.Gw)O4T#&[pvk \<˵\V~]0/?kd(R?ce_:/d]kYԀPC:%;dHV?զWAvENLJ[Uvhș"XnsS5<RQTl5T`sxZTL+0p^~! P#$>JOQ|hƞ`"pOc0nfysJ#a2DpF2WC q7Y%ݰ܆5RZmqi(Z 8dp}ZUiaQAE{`rr&cxT 5b*}L/{+tVڡ=wHlGb/}doD0Bo!f_.%2#lFڗ]4>~iӴaD}8L:'s:Q** 3&B%.X{#bT]$ 4!0FmL_ *>qRþCAJQ{Brx᚝H>lN@ 6*?ə2O}|^ZYBn 42gIٲq!P&YL4@ū +%)īhx ~K.).1ls4< G;duS7 N>Ծ!d %/PsIˇ.H ēobO_ Jk'@V< Fyr¾_q| C>b7\2Jal!<+CUJIѳ٥ yC뻸Je YxL+Os`jS-b',|SBض ~bϘCj ל3"729{˛ f |ebXG5ISEHZjmVr1JXfw3tsЛv/z G<&n~vSSF{_ KkzӖ@QdGS=x͜cK +9_$d{Q ӏѨ'@?<T)*}~Tek]foK +*Ab&"ҟكϼ!i};[MWƧFZRz 籸].n?$ݻ7>&)m |ϯ-vD4H$A+km!dXr6_ߡ$Ό8^ 93|ŸY64 <{Cn!85&[upzA*Hh"#(#I8'%qJp>Un(NwAdC6%cĂ (T42QZ`xAݝ{9Mm/A݂\̘U'x:թ9tr;8 +[5bL_Җ8Zڸw{;JS|bx|_lsu=04FKϡ;NsLkG={p4L.z9 +olj%rb%xkFE9 PRB 'iS8ΐAfþQqp8 kfk'Ro +J0Fg F_/BJ~T|'Iiݝm:ێyPWGF[xd?G߽\=zaw/߾Z%g^^|r/,!%$0W*H]>-^0΀W1= eHfa .tw9tqY J9a4E7}}KxW/-l=ă//4.E$u!3M?V'AqZp |?ۃ!8b7~Н'48`RzWR3TD }(7Ls{xNU1 8z}m5W>Y|wm]w4w9>|*E/EȀ ۾4VCzk9SAV7 +ԕRIvkޒ¹Vm/w'oAyi H&Xa 8:Fn=*L H3`0 %r7c(Vn<!%cwYiP5pōDA @Rmu/<;[; cr5a`4Ѭ,FtU?`, 8//].XvvS\5p`X"qXɾ8:K]G ُv̝F3( 727eыȄ#GIىG3#$%-uB$M s[Q9cdO-mP=T,D]'*@ε6$b>stream +}}eB>h1i˰@&BcG >ƛ7/-kJvGɅM !э-ftclymEG -nt9xy5 꾊~-Gr^R +tE,0"tI{IrH{|ˈL3pӽ{;cCmr ~.?޿([y(^؀5yiC|TA}ACn \hTuh@Kb~ObCzq0ٱa cEEsW̍M(atx"0w.-cahHպjRb[0 +2vZ[d +*/)>քL /a~~߈:qWJ-3wj*)&AGG;ڵ4;UY1K$fK\=l" l&s~ +6H* b>";y#Yn/ÞnN9\͸OآxXRzڦiI'D|\o:a(^.:8;QvnRE9xD&xGו.kvAlYu +YytC w>xsv*.C7ěg^_ {.㣞fuB5qgV9lOiv l-QCz/.Gk)o[{,YVyP Y_]ulC|_l['*kNd26@{" 5X1e1 +QoY6>ՅO)O^r" gY\ſ˭^T98 :IGe4"Qa ro +@`-j  +Ez6axٱ\aCB D܆Tg'/࣫*bL4[lyf^f  ԗ5rL5kG$ +j?fOmLcr~^j_$6W[ Y{K6Z-e76_W=3)ֽkڼR9h2 |*Wv̚3l=B.nYpczXzX(+i\522W,FkfpuBVb?k;ޮ+rŌ=B1u K$<$[SRW^ԥgz$kXեɈb%WvYaf]pJ +t >=*&!ƴTKHndR'@oz8AhG놵әF.[BSDd"?so99p-eq$lg.25NU  JN-a 1<|ފ]OE7txv0s_yQq>N'z[-–9Y@u r`\c6!/er+oQ\:ȥoYP( vYɶi6-JؤI "&Ƶ؛qtVc/j eTN mdLJJ'K!j, +{^e g̏uk看#B В)Pei:_%4iC zdWY̍r>fheiGnL<O_(BP{Ys>pI h`PkӘ#NDoޕO.(a9NF\-Horp.^WV0C%B dfE[mkq͜Wt399" +D4E͘;sF9x7& <!5z!onHo_0L*wɍbC7o[QnbZa;p'GNz<\3T#J5ÜafID(F";D@RB[!I;8FqO%eg'284@MmTufZoR 8'W"bc2QيS#Yg2`HcE*~qktR]!R:;NХuli0R +Hiy aƝlCH]R<ű821P6E@Z]x 7]q itB|@) +b!>V^ NFcxϟ*|f|}eM=/@TMLe!I B[3s@Oh9\c̒c6^ƞ%q$ Y 9:T/A7Б>[_,pdwfo-P&A "޵ͦZ%Mz}7 XLY N cYtf-_Or"n2mףWX'5:cd`9 +ZG?ߛ1NG۞I$V =@o̶Bb 겏/nbAmFh\k_{,w~fE}L23&7nLt#M1ŽL0:E\=':Nq|eԚ;ڥ\עLn'^6X@@ԽJ'#~;Ann4h+n@ E4}s->:6M8*|mGN@heFƗdȚ]8cu<-iK +J+ +{Ój|(w8f{Oޡ~|/$=yz4 a87=b$P-p!ڔ@>Q }+aKb[npan }}Z}8\̀{ H=$nT%y"ity+-KƔ\<9*[|U'6tog[d5ۙz'ρr$0>10m}z2naY\ +(N9#-.tMRjuE.í1'5F(G(2po."Su"0 @   2 4` +12\Q׾ܑI_od<. !!P `+F8>qL27ޘrAcfc": MIvhw:\xa97L\oD z{Ҡ +?zޅx+ډ\5:Y_X,95 g[بS,du/)3|7CKpT( ~_z>GaIuPjqxp x/A"h;㤈95A.;{_z8&4`vL[剒 o B 5%Ν꯾BTX~pr`j4F!_dҳ +m5YDx%a 8wS,awIYj{7rP8"5Z@1+ Λ@ҊbƲ_/_JfؿCۨ (Y.fvCqV.C^BrM TzUK +v^Gx,$8HnϳiTyqg/'a2j8ki4=2߰dVZB]3RP4DMۦUiuVZ24I.ZzvMrEť/p -*S'6R|. %'d/@=ކBIW)ȶK:,nnWԿ+Qb8Tn5|H* +O/$[Bf,H0J~3iIa;ݙG7#I'Y5~T^usa)S{|>?Ocwe;cyXC ʂt,Kd;1\{e6h gV#:Ԡi]kf B A ]4P`eO?F~oZyo(;NO'o6PaY= D 5GPSZ8=f&2)n3b$*#(jl2=QM]CK?EebIr?3=o'BêPh)e +~ uY}d ,N,4hie:V +\i٧O?v7_#ORD!I*3"^eos=P~,tles5UF9P17]!h>X N^_AM#?ԐT`/_ܐ"8RU)$?5._zcȹT/oEi0Uq1#6vIkV.!޼q*n3ǺaMmLL鎍c_r?QIK~Hg%/^VeaR DG߹r.U3=.D# OUD CVyǻu-)&@4eϥh>0ǒxΪgQՍfwΦv(>)ѣr_2xߨ2ֻ ]G)cm♝l_)/ +H$0[ u  +T /x6ō!޹|kNʶ`A +[xh4aS._h[z 4'W{^I +MvN%` +#%_T+REҧ0x:g9u8+<̏g-dfީ[*wZcF#ښ:jrIpqM$G\+'M^> @PUNR Iem,'/s)eD6J_FPdIV@O;kDCSȭcߌ{6Fҿl*DpEjly 23m7AL11յ@?0.m9zMv1d# [AE K瘎{0~hH1PwR|vG/٘mxR7aB +-,s(%TdQ&idTL_psqa,w- +, +Ӕj=Vr˵_xe(EN䒿_bb}%0M/֤K0JOi{5w]ɤEYB34 4Y7u75K2$=LhރЎ\vvVۛHS1;-σ`F2\5 dO+=ZR& i"^H"ޮ=':6͏24S1' ;R2+ ~k +z93ǣ1 +G@_'%lwG`VJ҂wD"1`ߍƷe6}Lf^C~-\O::2N+CW5%'#gRHJL* =+ǵ:{Rut6xs}D cmQl殲ٲ~T3{1Yz +D+q +B5/֣5.Ȇt r!ȁy2~BNHuV_ok0Lп1!, WoXGj)E.wW9x3`oY!5[*Jf8E/0 gw ֩Jq5~n&㲽²]%;.꙰&RGUw.v|ŧEސ1ȯm rNPxϓ6V0m@&V@twJ xvUw > +ygO{ .3Sr\,_*mk8!ug *` ݓS Ox{ľ^<ŧ,l$xViZA[ט:j -7KXf>h +HzptjUPϊRhػ5.0O+}j*4T̳ -ΆGsj<]3^%bn|l6!jUQ0eqslF+"oVw'4cZG,/HhaPTJ5x$gާכHJ GHzc\yFw=0Vwvaԃ":l f6g ]MN;F,:,n'PDURr<?^O!0H=:ɪ 9@!WDD7>UW&< +m0l/r?3G؋Dz$T$;C:Ysmpcc:n#?5A0Հ%\XWpiY l6 y=Iwр +BOwI'C9ks;3Uj .V]7sq߭oZwe^(ϞO>rZ +YCvV/ ;""`*ņXE+"l)l}y>! a-Qho"5e76FTCfdjTlY[M>_JÈYI@N\>uR2}HnjtYOI% 8ׇiz=XSj +oyA@].R1XrZ.ގ^,  7A"ouDxH Afv6_g]eL2Ҁf.V8d#a>|Bp4RV4يGzǔD(/3ޱ6fl(*X%iX$1Iyw)>&˦u6Piٍ{ܛo$xwڑ09_IAdbfvjjѧOB3mvxf~x&8FZ@?uї!?¦YduRK&s]kZNG'ʶ{XFQ.Bύo#ɁSѸC1|~agB&l2·TN%P;{SM +2k]BFtN7*p/qv tP"V4RnOa˿4PbC/[L]7pj ];[>lCakP83tzp?CSnнCd7d7w{al e!>ؑ-ԁ`?eTUf(+Н=";tM՞VV! x^(S JwM# p-L,}:/=KQ_o}=fMq~T<|3CC#vQҨطWQsA,j-ڮ^'3 +^2V4kzIM˗d'_].Wk-SQ&YT2<`'@$& +endstream +endobj +108 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +107 0 obj<> +endobj +110 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +109 0 obj<> +endobj +112 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +111 0 obj<> +endobj +104 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +115 0 obj <>stream +HW]ܶ}_ǸhMuc5n2-F*&f_K(R3AC{νijWnիQg?OͩϮ_nfP2FLP}o~Ȯ~_r,pc$9aH $eo]}WC{7}_n6tn`YucyWe_5sь< +%48]ʮ^(zwrb]-%DŽOeD21VE>\}G$^zar,k޽֗:zr4"sa0!9 "7 т cE.oEwM*zvw[k[3v CkEpM@ (K!psNKw4'H[u;ecsX>t{".2سVNx|)S[뻤4v WV08 +!MioM4;OV'nQiwityTU1:Aß#;$W}+Wmu9P6_GwM(8s~N3==U鸀P U$A#hYWO%$ ɂj +lQĿ@ .ҠDDmLq̧S9G wTq:< +F$$m҄h +Twq$gk6U9ۍ,`Bi /ܗimy[6S`b<Ϟdž@7Ȍ)WY*sCE!#5*OV/ٗPbiß,ٕ0iq,gRDЗ<>EU7!  +v7{7eh)9&;]-l_;OQp^ǣ.1嚰Ao_&Hf%JH x {^ i8QwGKsOi]fHuɴ҉].:xbA~xI@źuLOH7=rA9^O[7Z\|$ (4@uۗU,V :? +3wgM ))L0= I2C(@pR+Ť7 9FxuU[BOYp`izp+ S^ðp9a/XX(3]͝𙳴^ؤ%z^ǘI-^oaEz*=w{;ohNeKWAsˍg,%gj\m_)7–V";*f>h|[aC%t]uͿf8MK45LvCuŰK."(Ug%8K#28ceÖ8MEQL(cnӥjT~ͻӵ@mJ\N@}[al"Z^3W dŢ X!F +MҴLgxt2|vm3 +znamh6 +IШYv.9J_5_kb^8^؏%Gape^w1PO UL-R[O$BAh G=#B9I` g$]bt, 3sՍJ/\sP:P쟽!5N%$~7Yg!Oj T%;8 d4OV:>P-rAB=*IS?+.i"wFާxuFDdJΦ[޼’ +S +A) XTظ2Xx3-[}N<9b]TcR$y] =5.Xvn̄ S鷓@? +IQ餁E˨9vsF2n` +>:j^rJ6=9}=o[#cf@}sxy}ջz=x?C<:;ݴ~;Af &Lo60&F$J"sنD6Bd4Z]yL1IK!6{DžE U(>'5(,"rsymBWM 8>$@.{(J"" +X}zHvϋv}]-gzitBܝ盄He-idyf0wK?1xy6y ^z-Vs4s2ٜq2y̸bd8Лz&eq녖s&y眠fN}pq"@ht{P + )~RRx%tQ+oW|Vcմ](7^]hj-4h $֪? d@ڽ/H$%|NvoCnrI+ yD:ޖCXDN=J)OtJ}u_O>M7ۗY/W.ժ+T/bd2Y' 7W}@gHJn/&Ēn5D +"`@K[D#zn(\|tMgS^zsa"ccW"e]Z !܆!E^{'_NdK7 'X"gkZXq!QBi$YO. TJ§ܹ̑{ȳQƸ&ъ rXha CR{&f}}jxz N ! <\+ޒa!#OyBG OUw’u߾4ԜZ&r'Nqh#әTN(VEJNn}F@e /*(SEwΓ FnETƖzcTMfSl59qJn.1k̝VA*0`9֋|~!wp.0^c'[,/p\z! +BSJ͚`oԴdMMC`#d+j1_7%nEH3,:߃@+ wK"C[b"DRaǍ-RգTle:hR,sU*.\1vxעVC΀ +ISQXWHr.Jy.t#]W5;M6$"w[?<+g$y 7(E9:zj,ԏ|: ~ +s՞TEOѠӐ閏w%YR)žA>,̗LK\hT}8~^f1~8HpH%_AE6MƟs]\ڏ."%_\H8N]Tgj$b)K ݌\=?yzCkǵ9WEd %싞U Z -4Z7(=d4/S`kN4-;5*]uCUdCp6 .K7.&KzqXNzPwϸZo +s +.obβ3Fs\ҕ{^`H#(s > Ssf_@eۃ06O׆9zGnr6iLܲw| +endstream +endobj +116 0 obj <>stream +R;#^4 Oq}{~,ns8S|Ub2HPtM5EӀ\Eσ (ÎNa;d1 J9d\eο + K(:U<*i|I~]:hL{c7APG'_jMp!XEդA"1m6e%3l1%J ZؖT~"pV=Pz~L\*uk؆ӊK{MذN('FO6AT6xwh#{)#oaC"]r* CbeĴbNu ڬFXdCWAJ::aS0t F3SW0pNUͬmbb|UX=C\O?}8I4FgT\ȉhݽ>l>*t:*oT Mf<GZd9bFK TxڦUZ6z#Y~r[CsMU/.oz +i/?A|ᔉ5w݌I9'-w;D yAq|5% vm)ѱun@"K`U4,J]kGD5ᐃ k :JOvquVDV(ONk.ߥ0;8O&[ŷ?($1N%*C|v7Kg֏ 23oZUŅYzA9{NAd5_O;f(DHw4;!]g)LOg{Q0^z!0cQ`w3Yphj0ɦuY|TZ;[T1=tA-S4boĵ^Ya0kőAq:3 +ٴ* +l(ы;ժ׋Jdϩ>jVb.퀣{ڝh?.{S 0[.l"ӞA;N֘ k|kiEʌuDB64M#IV?шZ5{ifkv[ v#$/uoMo-:6K,ڻ$ +a6ґehO3GNpQ6V"ΒWH~Cg­:X/N0>Y?LĘ側آ(Vco9U^6=k~Yk !W]0s߲Qdyo,*C`k0IA 8Qv7rl}bUڶ(f~Xfuu&4$t:]S[[ޞr04Pm"V +C%i"!,>SZ2q8LO3tk kY[D%[k\؜'f(82O.f>&? ++o:tx߳ {2Z-JƒM5GA)Vd?jn}f.VqrME֛MrK\&iNVMjH@kg}\reHUs/tz-1oְoQz8s~FjF߼uDD;qJtQ/k'M0%C Vňőz,|U+ Z|,|]x4x* S_}ʑ׾ӿ_xPԵI QM"ЩM<*0KM12Z)[5E:,N#-ul'G|^m'Ww؜PCvxNRͽwRp+c,a0h#ީǚ#r2t+>5Et`-sSEdJdeH2ofCbnݿ6>S#k.gH84:4\TJjK*Or5G)#Z;K <=4ZHFα2/^} n/ H|"&xP+{9Os:0 'Xֵ/O6#FYi;U2B|VK楌Nf]3&EJ#I1^82??o3vM|s iT'kԨ|X86pڌt[DOu_J"a4ھҼHu%@\b2N 9T;>8H3?N2~%aUBO/0W6 PۧY֦MעkbDG:szK 4 \whrC~#6he5Qդk}Ȓ45^!vRQpӭ[.4fbTSĤ +Ad:TRJ>~Bԡ< +* (%PdЇPpǬ"jjaP7Սg O9o?ȭ֕DsC!6b'r-,M2JO3d+o]7KZL8n6˥Q +^rUgQyA'[?Q03g,&6,$D7# +@&]@fI^աZ b,O½ ig2vadF^ВgGyUXQaIK'2G_W" 2TuKmlcjC9:F:11eo:ݚK[=Q|j9.F?ҝsܻ?{411Ye$KY,}TF6 z `V)+e<`XÊf+2V3ql`+沭eT&z Yi ֭,coWhD-%~7xKx:sS pȏSp H\bd3 0wv/sƦRT˜&o`)El笫 "~~Vş]$z)c, +-nCo߫@AP܅3%3R BeÓch?su+{u+F"WgD,iH΄=_Bο\KQ;' +}yb*S@rW0 @   jE  ɉ?exMn̬mK{|K7={W(/6-HoLfMK2  | :kk:Sf]iT$ܤooȟC祒lLvT +nPhqyR-)ųQn8JV>$zl2k vkeBiWY56g0Ev8U>]5zbF߆Bql&_x Ygz65tjf5f(^?LigVh ?ϨMy;,Leމ?')Rtagé}L9p(Ż+$FNo2բ߷>E0]i)S4`RU8jW qRuf4`8Ydo'`t!-5nC[N^27X-HTJ}"*+mf/"D}3ywQ(|'Z^nBxʀFAF<.:"N+^N)W#ֹ$El%bCqۜD6lhыtnc)35&,~ɔgoUQaL8r͏Gb[_O̹s^bp)ۇ.(⡢(s'w݆e6iG 4(X$r%2b\k$_$j)KGvMȎ%@+=G0F4״aRl{U;%-]MD&@ZMENeO(w_d-}&=3+:C$wTI ڴ$п`j'|sJ^kтvɽ.Zġ Iz%yʅM+u$TFI5Me +~4jP҃VpA⊋N#E1A'Z!|ůP@y$5~&T,t $4Wk᧻J? zڳڮ^~ft_50L 6A<1}[A#RkAM#c 3x1lRԙ)8-DpgIfdJ);x 0_Sv$@GL*pczqT8\ o#7(d B~`2VrjŲ_?kQU@:5R / +y`eU$PI fvL9>.Y}F=[z;\?r=T]YPSDj6F +n$3zE @i[TK"6m2QalϴaS$W[6 ӾΓrpRewiD D?,aCUts*P+ fՏH_9 V2(dQ)HZbJKaF,hqSM}.9 A; jG?×7m>~HĴdI5: 7G}xB .?)i>ʙێkI]6gh'Q>-e/,+p${y' +CUm<%zM^]zi̋f7~XuaNk~֘ÊV;uMWGtt"9J,O2.SlovSxh;dgv$h:P}wEЕ +*Ƒ WE={܊&y^1u>(K+WZU<PS_+W-v,dW؟;DOBY,W N*Ws~$lCowMQؽ͎Cp.!|USj֗OFR&?QG7L1(;1|%IW9'֎y.z! NUqDr/ޓl~tUor =И\PE bk8ѥ +3csCp+`0ûBv-Nb ú +x >Eѵ\k{ #߳7=F.,E|ؠ/aP,/V"k8.- +Gb;WVWZ_dp)̷ŐyiʷM017imP{cP'=8)}̿GJ@cK xkhXݪOgIEo34-/EC==ꓟc3*]D 쯛qe Ty`}TpkH}s=2V&s$s>SC/x=Uptzvdoftk~"R6wL4V}r[oѣYdI}41Remh ѿ(;PF4 e?ކL6^L'v(An2HִDDݡʌJ[xl +]3u^p@wT$1؏߃ 9C`+LM,Jsp) ygsNou*'== +Uvfŷͽ6]ہt)O9 +ReǤ<#9":Ɔr ‰0*9ƐLIT,e|:_0n zPޥ\<q}hӇ +0%E%&!`e0\nnrG%!R)H<K +2<׋[&rJ7gdzuYh42#Pk9v؉=-V|zB %OV,*wcTh_RgLk_wb޳1r"? v@+[uA,{J +( ^%ьJQW}SO:/1F½=WE1$ ї |uotJuI +6$7-ubjvAO +)^Wxmgj>?|v4וA[-f nn_(?FN*]Ix!ID92!9S'҄G!2δߋ{^k&묙z'S[7 hjFig\A^Xv '}OOj.LK7f|fF?lNymMM$*7s6:&9iymH-;!gG m+wɛa +#Q8!d=uN8{n=PH:]$6t5 pt +4gZ_@_ 5m[)kuJOdOmOHԫ!xLw)&N~fL : EtJWCuC'=Zt[HozTzY R&j/SXZlX. ))ո># Hm +endstream +endobj +118 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +117 0 obj<> +endobj +120 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +119 0 obj<> +endobj +122 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +121 0 obj<> +endobj +124 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +123 0 obj<> +endobj +126 0 obj <>stream +H\͎0y/gTU1%Ģ3J}p (J ӫYp>ۑeߵ}84mW1.3udTCÇ/v?u_×x6T>}4ulXDZN~Y6 xdn^xZ ߪK4ɺ1/:^*ıN1Z3ۦe߭j>slDSpNJ''k6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh9\pֹJp +%qAYΦ '@Y^vPD (K"cC@Ye1ޣ  gWn$,6F"t#a{Ѝl.aQG楪[/mKK9 +\#%^~.Wp_ʁR={*/hݳDz>98\8ߦTcb2,evqJ]|C?I,OPg +endstream +endobj +125 0 obj<> +endobj +114 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.479004 0.0 428.639 631.44]/Rotate 0/MediaBox[0.479004 0.0 428.639 631.44]>> +endobj +129 0 obj <>stream +HWk6>B )Jnl&E,46=VcKSIKIy6KD&ys/͘Ng׿֏i̮_gIF2$/_ʮ !(Xf~Q*/KDeSZ)Id^y'bT2d%f6mcӵ/Xoz}^ww_3ohdW/Wkol"9Be bCF2t^0rUUE&KW,[}Ӈ7B!c$*cyw+gSNnR6}9Uc rc+wxWEȅb'\7>1)s/M}al625pv8w!Է5l̰Y?sY.lQV4G|t1Ɉ%U .=M:˙p5wy•ncB)dQBPoDTq0*yئq_Za(=$`Ea> +R_% tRnv}wۍx\W~.iLUpq@L=t1{_)&%LI`S|C<a<="PVx7a%X62嗰YeY ȥ{^Es^:D>FEΨC%8 ͽ~<4m?M%Qta2)+1 qIS[Xkcsj`s>\`")&Y H<+ͣd@g?-L<ݐqH@Ii:AL8s_Wa/M$⍽# {݀dĴ<1|1fu!V[NxwoN.0@'ϻN[iIMBV+N3N{=>yPӱkW{Jj0ybItn Dj>KSI8;|pkdɕ Xʊaæonp/eKD= )pZ} ?asп@"Nq)O[DqeO>Lik^~$}ތ[Yl$13(mZI&pi:5EἩ=fh7XxPR}*w&"75#vz=a Tf<}i׃*1Co~E2෻E>^{ ȏbWrh*Pϼ'G2ʱ:E.p\;`1AY EޞahRs\pU_Xo#|Y_:u@#܁pۢS-Eb~#mQ:.ce?=%H?nZp;M4}<"z֍*%lԧA2+FP!Ln'ROJ/+#p7+M:c5nAou6[r*neyy pQ-|z)p Ig r7 ?80WZSz6!!]UuA9f:6;Zoxdz#c\ %@q<#FF5CWOg%Opy.x銸/)ϰ k?5htu|Ax%Dpf.!rJ7^t4gf<3.I=L\0>+VJe`C0>||7"h(Va@ȂNItCkG@CV[>܏b o?Tp~}:b s"T`1*@I8ϩ@Qcv70P3Pٓs&&@ ̏U#–rvOC\-<d}h}w],]E:ވVm4@h I؎JJuLu#%V^]$[RhlJ)j-@eIٌ}ow~q-xNiy?DTB]g ?;j"@=`$< X";FH++/ BȋMFZI\4ަsw7Dc^'Z⯒y<"INA(/M;4tJb` +& b$%4Nі2uA/Y ='zHC{hǀ& /,K[7§]f8], IN&^c4\gpX{kE5I1ITL!<$Kb2?zV 0U/\Ag3OObg@ˏ3g]f.:S8G+= +Mp@t)T>-3p'xVȂ[ +ZZwު[{/*n}ZYy$^?؎EA2D64M8 z(yG_XHD9B͒ڴIdY +,>m |w]O=bYio3punD>gP _2C#_ +D1d;DzOvm羶w{wlcp]%\~lki3lg@ù)|K1|/3' oe,O mDGJF(_vqyqbc\?CβilIpesA03[lK /ߘ>wv[R(꧍;ڡbľM)]{>Eoc\ar7̔vvyS +< AhL#TT"n_bW _zg>Bwdfڪgc +q{wgX37%-5>Kn~] jDhBt}&Ћ? Rr@CbǒISa02t;M#K׎84/w!*-pkb!ITn.͙xsxNJ&lh[`otm;;,; bf C۵Sh&'+{ +endstream +endobj +130 0 obj <>stream + pbbR;#^4 Ok+q]]{aTdjH31V:6YC,ہ:9 gy4A0m[b-ė,JΟ`՚),z?C6Z]`a%_7G2, 5Z%t4i#rF5,O'F^w.>I|Ln8\^<v#m{J8 7N ֨p4}hͯ3MeUUP2śHpU,f[]Bj>{Lq!:?M&@ iӍӬL5gBz%h![4Iwm1Q?W!@0"hӕݪp3.%gLp_]YcXfI;KGM2~hC& R6r2w&HF56IgPz=ᤒ !o. +3SfKVa~ab WV^Q^k$e2b=߄K_Ρ*׵\=$ f J pO quT.=P v 3tif7WIJ,eܮ-|lYCg: :;HuYw$ + 3ET) 'o ?l'b ( d }MM (S* j8%qa +Cy*vMSK 0"lRwhm4>R$ډGVV\off >,Ѫה9ls0Ⱳӹ3WVxN{yi5b%T^z>zAfDMzIHGLaH0*"XX>Ck,fiwSu!-?ao7Mԍ-A hAGpI=bO}lfȋv''gJ2_Qayg rY|,#FsF!5'EgZ2˼? +D5#1P>ލ2-WvXlw2$\kF*\b'G'd!L$)UX~VwXߋp^^uӹΩ­ DO}KVVlw_y}glrwUbR:Sm1qK|.Un0S9_&j`ÎUA51]e.#"H հN{iОjI]2UN +N.دho1|r2e07( SH xGq$žPN~6-f +z=x]h<^:H56F .⑎Hh囦M 耽xc0gL|#ڠ!RƄ5֎ V؆8&q])O4bP̯S(=܋{p|L3G΅nJZ~ + rӧNEJq, wT*ψ1m$QFL(cc V5* ~IuN +h.yNDә {ٯ9aH %1 ki j +eJ4X՗!kz +QVR~oX( +m 9)^8y\ + +[5NطZygeoːÖ~x9ݼ>ڦ[%D#|kp(IfH" qWI`C\0.?Zl"OvL!_cdKN|>V ۔Ctt)Or*Թ  5,_Z:=+AS~re~5ZQd4in-,LJZ$Jx4orho䅱%"U[Qo+:&"{rxdVhֆy# '7s3:H"M%Pb*:P2Cɻ:C\[j/YܬBs%y +xAP<sRw|e*_4!v}\}k&@Nj6 ԇB:Bnn qͽ6c5sd3DO[Q+1 1ɠ F68Af2p +nIfHE3-/Ȫ,v EO* lI*DᏱڡZ=2FwM +Z7"(f4ދT]QW F-n.] + ;aqM\WYR|[G2__ 2 +zFE :{OG3 gaЉg(7,L;ŐP%fqs5 8N\2_'TJ;M6-k0xlۑWza: ?\Lg5uԑ)0 @   4` +1[_o3l͙)bD9 ֪wMRgi޷&_h C~3af]/ԥF΀H9[ȃMQZ@>*CukS9L>w\Lp=Y lZ|=:슀y|¾ :Wss{;ky'[xͮƆyT 2s-.J?2]3G\ Qx8\WjY%,-Cdrgeс=rx{,.)ͱ֜lN#0~UԮ߀ +:?b&+'B%5. +aGQW*83t0xNA7embOܽ`fU+ݪ^o ~OKv;L_eYnou 5d8U Wl8,~ .ĩ#C)nHa;5Zf| Z۾f^\a5Q.(n;t0h9>(i24ʷ/ؚbz27 w|JYoD3!eDeU.VCg*Аbvȅ 나=qFݠEhàwPi%vh#%r.uX|hő>ϑgQX\ؠ ꔹI78Iְk3m$Ayݦ~_8N1[$ea,q{bV nj{7jYͣUQsn ٩+9zfno\'M>5KU9SgJ' +?ra3Լ1ȇ׾R;gЋA@_58C +(xB|;Ӏ6rmg$ϲ*V)^^y 塸v2A;ZQBFc V:`(׵o_։?w7E)!p9I?{s}V6QiR&5qMC/çe&:I, ź".3hM׮xHCvP<%_k8 .>ó4#c{>RrV`V9ءHi8eo> +$q$܂>)yk/b"2S6d?ɿGx̷Ц^z$__-@P_ԳIyK|\j[ +ЗD" #,;왨a~U[%b23cѣ_wKII_udLrE%?ix.ꜺM>kuaVX*pI~{:x߱" F ~}#? Q\ r0C4\ JPJ@R?Ȣ5QB/\;g''J.rI{ 吱 kJV Ԡ+PNZ}r5 T8 ki?}Ta8`"%K'i'h:64)UYZ$u3oԖL*\rо)" x){bڃ~cPP4%ɧ~fo @2F_qT\@L1S982 AZYKYtW#jE\4)R6V/ Elri}DߑNCȨԇS&#;O>᣾ˊ`N. -e $wCxOjč^5G[nzyU8ufa"K~*:!ô,(kg4ROU@޷v}ެm\ nxeSW $&B(c;; X9V1Pʝ$F1o%`K-bh 87tEԷYUZcS ܒ M \nLus063YB'dJFF +-_-ՎAiLO@2C L\iv6\pW:[5/+i(Ț /`a;j^b%l(?xb_A֝b翂ڶeN:0[)DT+_F{'0^I +OBiAiVx-utX:},!I!i!{Pd1%\(30ڛP ,Rk`Dt4;g!4|!\څ3}}I&53wF$^HfQ {Ow:)Rjng\ґv\\>Y4@Mϭf$XQb3;5=Fj +fqg̱ؑ>t'(sglbI1A>r^Q2`767VR*?*g%nt:@g f=e<#W Ys\bNV}I14\SvJ E4HjD-|n5Y+5 ˄~SvvwC" ޾bF.7*3GC=ɧ?vOP 'Zl_]ug0>̃JOD@P_s,BT@t!oyHC6tBG|wJ_:lb޽t`pKg$ +M9iM %룞2X +a^Nh WCB#6r2e)0_:@M9b' {1YI@mDmx]-C e$ɘf=*3Pc_H[9džlWQa:ȉ6oܒ3+Nv鷎AneIs"$}FѰxM1v(2X_∤)R8y"h \O24ZtB AhJ2>`7е1|cƛ}&0z#5sG"]9+B֏Am%пb`~ i۳ +zuVv)?n[6SfC}%SYݿ6Z4Te$/%,t''=k =B@o1͆F!wGt ?vBc( 1Fݿ"{;h:ƒe?C8fNj3,{icɑB`Y}Y-P@PVAށ,Q:Sӡ>Bc.mN "m soڗF[ a~hD–ONf"Z?g)(o늈nAZer+s"s*]vQV +^Cl/^UmG{hhH0jΔaXݣqʍ҆`PqwoRi|ᣧk ֥IZk_#HPzc*8v5GZE5K.^Lc^LM;vaxgF||Ђdhy3I]/WJ:s#rM%PFR=;v3iCB_[#.$ VɨG H"9S{􀣘>dBDA-cdոZjP% ʠީ^aO;]qnϖlq0)8g{ņFDYyx'0LEhnYiҏ$?1?'_|Qme^1]d S'NT\0 H#ꆌ&H,:zEl&[v%lg7nbnT$Md*ETsUpT ]eFJ7%;PH*!#=0}s9L{߻z4 }_& 3;~ܑECrdE+c2\NjURs6l1ЮC 2 +^ qMm/eo|3pC #j&7CF mQ!M?TM"TKLHDZ_yp5Yx`,2\n(KȔ8,#4X!`& #lUӧ0p"b5nv"^/Wk6ox"ZGnGb%Q jmTɈvN-#AJi!N˃kMt~63<,Za5Mq7S8ŋ J?jꃺRPQ$|")_"qG&70ql9 )[#\ ٷ>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +131 0 obj<> +endobj +134 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +133 0 obj<> +endobj +136 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +135 0 obj<> +endobj +128 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.479004 0.0 426.479 630.0]/Rotate 0/MediaBox[0.479004 0.0 426.479 630.0]>> +endobj +139 0 obj <>stream +HWkܶ>B^-_zA;vZ#ES\ wW44\J%EjKI}{ι||Tܝ͛K7D<9I7o~l~/)!9K9Ҳ$LTSJ"I}ܾ?mi|y([}Շo߿Ẃd:ФI6o-IhߐZ$>P+ɶO;"YP,$+YZ0/6/ߦWnmע6ޜf2p|/,K3}_?N7A H1euߚhUfA4Oۿ]#F.F.D9GՑ9&p4'Mt |ʪS& l BLzuՠQMڣb.'>8ns~Ѵ ]/Ü+SQlL)-K҂睪f'cдb//Q;wD +1pOER6k` +HZ圯 L96 .:G]pT7f)+1sa6++fT_\~1}.,<6ԯ'h#EVG4~/ ©EL(ՙA +tLZW6QNBEc/Sl Gv^݈blOm|aMHrΎ2-s@^ AVrHi3}X%on8K5h2t0- ++t_ĝ%$g@ŵ #gH_$` [fNruL>>w^S9Bٯ|ش;uTM <iU ͍B8j!..Nqa!D8oOë|%HÕаӒ9f}-vYnĆ"p)!by/Xŧ%7ʧjՏidz)A#wO4A#l<('.:!DjCR&,-@xޣ|R1Yu"Rд%Oӊ_fWl*F2PSpe9P=E?y+c}'>ݫ^ +8'};{ԛ0^agr"+`lHM#0fE+56ԣݲ q[C;v 7doS< ʝr5W踊c +ɮ̶NMm5 !U4&BY9 +7R׫Q{P +a.~Ȳ~ї1gsf|"OW"Ytn7>h}sԨx +@5k͕&qO].@)3S$4/t3B`?_>@V-{V7  { ʠ|F:j݊%5fzD1kgH{UNWznJ,w!yV'8 0zƒ<sj״OjOy WRɐ@6B:܌Q(NL̇o\\|η5R1dNס7g̋D5Mi&4z]ͯpc"3nEr ?sb't1\ %͗g7_7u]|{HkS.a'b^"da9ڒk(|p="-E(oJdEcMpk(ǀ0O5ͩ E:Ak—fFܪQ=jb9Sw@탵Pq˵GٴksNxEyd"bgs+28/’+ycr{Y =-O)Jg؄1; +)'nyRKO]\a\?,<.1BI5<iӣwk`M6֥z +endstream +endobj +140 0 obj <>stream +%q&mKM kLg[6d˪ff I>ɖ"[.o'WJ&v4d~*.qkta#WtYc$E,l޵"xay ruȳGˊ}mJ%[2 aoz7'Dlz,KFHZV.l殻зH +(pGWl*֬|"kd5GJyjT} j*H2BH6%CgNʛT*GM^Yd*7YkmO!SRӧΌA'ڔj YStB^bR13* M.iCҁL_1du8ׂNmynV@a,zy'fBUQ,+oz)!RpE\c)f_`!M(0R?v+g7kMYJYή7SOefh +ʊOm| N13䘐rv[ +7e%nqPݞt#4Wդ]F=FYXnV%PXksPSB ҍD2wXRK8t/ ddT>eq~r~Y/AC|w) 0. rDo&wO@S76ju7cRwofAha16ǦHDO'Ds"֒Fv %BP=܁r{Vĭ2S%iEcʹFeW\l'2qIީyp<?J`U3zjgm֙K79wd5qp.1JVO`ij*r:멪o?\If*ڻUosEMSqdBġ){aiR1[r=+Ϋ'/̡` VfMql3"}<_e!VaNA Um@"nO!ߥ*{v@R̤1g`:H _١g*/]$z +nk~$KWS0 3 NU RN`[=-n=&6ՌuE+G]/ +E23cs삻Jc9*7 nG=#:ԂIe8 O#gBA:Ej%S Ae͊RcC6E=k] Q*EOt+US;~L$unCK^|QxXˮ{e r~Gsk _`]~2`z$m4QVg,AZsHejЦJ1tcF%W%a)$ۈQpݨ +M$Wњ R`r[X9<v#cEq/tg.0Mz婉+/?p!P! ĺGϠ6ec+'6(ñ4|Q.z0jD!Q >X!Ol,݋fy,enp#%~YɝQ +(CۚS;<4z/ӤPrnd ?i"*yE5&ۅFVp,D-ɤK 0=ݶ1IN:K>T#2AϤ`Vjf3c):oH+.H);WKߎ6ߖH%t>v c|d# apET3+D\2i3*c׹ʘ)ڰԻ{t$oq'iu`8vOHus mBL 77/uHQ>Kcc%N^ C<'}voIČiMߛ c̺@Ro*=773GQ6woآ|"ݏ?OJepGA 0 + +Xhh %SQ\O|G'l-#]W&_ +fp4 (_~js^o8Aw ?(&(ЉFϠCIG' VetqP.m-G"H%tGC|LR(FomX7Dں u:tjNPQZT xx +8i<#M2}'?'SOq9X/'9^w S?^genZ|'eXﵪ6YFͼ*3LnM ;6ݷHa%a@;տFMҧ ̸~ށ9?iyݎgYZ,]G!kǕIp"poxNqI>bajzybnA'h$Avdbi[dw&ض[L->Gb#ɖf仴^JQvvJ3/O}EP.jn5~C}XP(@V> l&B>@U Ո4d;7> OVy=txgdiщ(@n a=C@s̓+T1å83KNX _s16_Ke}5L7t;dLQ5?ywϭo> +N@Kʲl.M3A@NlE"i 1tqPhr sr9]-_5lTd +;hrI-JŒA[ys}s[x] d.S +cCBVYlrP:3ZEuGG|F`sUE^iRNI,Rsk6#֩xvF% ҤPdZ!R'[O$&?NOv|ZW` Bi M1RK(h%-y(f,XGp6l +ȍiNT`V4%! +XwH5[kc,`0jG^oq ݤp7|Dm : 4qpB \LX$jޛ +DyNP?9l;@aH2yj.PAIt>/a<"n0qa&a +>3{y~P"g/8V 1hOֶg;f6U*mNPRCr+iOT {"gf_Uz8@낅x^F}0ܻalKR$6:^ԋ'`hw1+tCX;}Rq4F4ɓWkZ ^b`ˤ 6gbI7QAc)tdkDKU VId?b}CqOc_cI7l * 8s· ')$#*}!b܇]TRL@gv$¹M,>ҞP_L*ڑ4w'F ZRc#4A鿎0pq՟FM  3\+huTpM#):loA7`rCUUud/]a}<4}qk˵3xm2>̿?kk$PD(RH{DM[# +E+f(7C LJBb-tNY ʑ%пٮWf㝁_DIUaH9nI(ÖYGwwi#Fnm>+@Mj*/+GS0'fCR,E!_Ke;_ g??z+hKjnS뿽:+€)ݘpFCt}{͘tҩ;N\ gMƩXUzn A!?`jp.Ov#J*rEۨoZ5sQΉ9/l9Uw+3Gh9&MTHA:C[*Ecw13_BM%ydiQ6{ED؝lIį>'1'XCmel8xD]_=_tt:(+@!qH>ttHGSԵ}[e!m27lT6Ͱ?97%?R8~H9SO^:Ayt~"Mx6KH%h2{(h DZj.k)*6;@ʲs雰ı_Xᴉܞj F.Dbu0\РnpD,H1i?=ov~ + L j~D.1e^G)`Gk~QxX+8J! $->31t-g{)N(_`ڢф5* IYP#܁1^"cMV 駎3mlmU 2oazB/W-硦?L5-O=ykwYutgsc#g<` !BX9(J?+!@I;zn=PX>mg7h +IYtR?cW ?r)MvjRL b#111"-)@*0 `k:!- +F0iURlqX5@OWX)l~TձT8E0>wgb|sY È צ_zъ-}Zm9ba? fW};A%"TMB$UHI^$OJ?&\o$<4q]ec<4] 9GDqZ!QB105H!{a4]3hJ]^% >ϘRa\?u\ c+3Yp)mtoPirM m\B"U\UԴD %v%`aڐoe NPCS5pg6~VP6TaZH>0h"SL*_tn 1-umuoS@޴P9gȈrN a8:F9^$ +N^rv rwV^myey5BtPd?ๅX?>NNRb~K1J) +f\րcRZżpvNYhUhuY?x|]P)OFpZFi66hX?9m~:NYf{QoHuş)ڀ8Bޏ0`rGgY?m86 AHW$2حf&60:D "BR-l1mwWb=MPgIGi0G-8oH2Yam]=x}z:) Kcdqǹ6LjS7sB4IIH|BICF *dMOHZs:R*T/=>F1ED1I) +G51iƤ"DZFt91/e{3Q-V 'Lt^aFl+3"wamt +y֡% yεGCk QS! +jkr,tُ0Q?ߓ"B 9y|3[ 4AJF߸|;:~Bistcz0fFtBHlԥ[Lђ8 \:SVuzbe7sjdȈ2ZQJl㵐N}(ü8Sv|6'߬g5Qh[\ɂw M%}0&!ۙ}3ʔr!M ,)'Q3e_%YJ.UA# 90d` flkEǓo#~\Da]}[Ϣi;_g/|R1M< bE?) aZ >`baJdq}/&ke>]%?ĔTI">6psRDGṝkh]92яvRŶʔ.NJz5,ogoZ~Dg;7'@b=n!i||;QPj=x<^J"ĩwo%npw_'zSXڂ[5%zf{X>ڏ+#65>a 5B5^(`:52X V{ŎN58߄࿍Diǹi *p},W<)}Eg.c]qHÎn՞p0^P`@5<$e/re LmrĄ+-pVWHK2\F?௡ymlHޝ؆M-eSiġa,z-kfiC,rۿ*M"fS +$DeSjBvTqLl}i + +5O'm)g=`N*F"C*{dv l}3l j5;u33թhJ,Uj[G'g9.X:RP:C=l({?2nO`0FLΤ͊Qəz/SLtY4ۣ,t +N5™4NO4ԄKmn0o}#=.^;d?T @̎e9X^߻Ss^xĈ2i-9۱M rm3kX0hEQ AuX7[TxRZ%UD㍵gP6{M4IN xm8b3bAi x9qQ;z2Fm!+q'YNXoGcs-n|4m8lmּ^siXn$9J/f6mr',3 +<'5]ѐnym@enU`=&Ip; C?:gx ~2?4Jﭲե +jj2*ޒQ]`$X~7@ej ql`n9iA=Rʌko *{4 d38zhW:]Jg88d|+ݏ-t(W;-R.V0oYɖ=שABA='_0>ds}M*(OWRu-~V集fʋYGȃ'ɫXZT*Nl/f[IHn l{5IzyFb)m\ԎC3WXxvĹ^V8Dte[xkUl ")Pt{o$J[p I2"tL3zEuGv{⵴ 8Ed}m՞u'IY8E=f~!>xW]w14/>y7\I +c +kCՏeèvu!w⠋w=rVfs/D-x3*g-F( 6O}̈́VţZjwCBmf_1v2cGIPW*;0 ?5s$#T, Y(cp~'"9 C܅PU~V+up,!A6|7M~[I,~WLC`"(Fڠ_k'aRLa;rWn(v>Ek{3]KdX:qH +ж MჍN)&ނgqxJܞoyGn<._dgOlq\ա^lx/4x,K* }"90DwC+Mߞ2ı,jQz*"Cb@rJA7VʭŰa<+3+< P=DJ(~4s<0vRj'G6IFj|k_s y}A;OlSEDM5̩Q>õ(2xX\ z }V9{G ?">stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +141 0 obj<> +endobj +138 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +145 0 obj <>stream +HWnH}W14Jvvf1&3Db J-&%ik4_dM*q6cvWWթ:uuӕw~ruz(SEWW_ѧ$J"yI՛h&Np#ycgY)C永|{H7_wp}u]>]Cy[+ +Ie4"@Ɲw_W +'P[$q¢Wj#Hj?eĘEC.<78%՗j"3`@F1]dEw89x$}KcQc4?>^e,' yLJ?ǡ1~ܙs0H>)C##p3FL]ai1hVŋ۲GH4Hԁrl& YBԷ]}[Ɛ_f+gk8uO+Է.W}.$ Dz +rco˻޿nIbhtbQ) N֚9oXPp}8u.eWm*Y,RUPV*t Eߵ;KF{pK )?"dP (O^4uR7'N!ўw c3@8cV1M}L4-mZvд 09C5\Cۢ¥@$ >: SS,>v9Qo+7;{Dg2 +nqK(]p#MɎt8辩 (&PNC}\)6<M`,# &CBnWƓRΊތ3E& ЫH_/b2 y;244| 1S30l*i  m|2SZzwqLMo:w.*z%T.*0MI}C"G J3"cL X *4SS0QoOaf&lynؼV%KwۯAWB;c~VBzvGS, f5j@0K{4WgYS,Qc>-NP1_.'Tɛ貔8F6,+4ScT"B^g w>` x?Kd|.q8xP >BM@SS)] [gNCh(iηHSnH8M"vn#Lz` AFd.|bߒO~g9ЪdSK˦>G2KMuOҘaXϩ0Ɇ<<{) JR%HT?>ʊ.dp@|D4<4Uf %3{!R7ew7p2.xך[_h5ipG,J+aW՟;6@j4 +Pe + +PY17Wۢy҃A6fDzޮr` %H$v]3Mu)-wO)ۯᎀiBT/L ]u ' (ylS-4V'U[9pI_ۢZVIpv|>yy+嬁*8g:!7(2#a3 +CǝR 8f&OeqTuwaY Ҍw]Y{j;ЧkE 'Wwf@Sd-#ɭU' y*A!IۢM[#Tjy'OIknIoq&KQkC\S~5IT:4˄k`|Hq3y&ʶXG3( 0lo~ǔ(Ag)B8vq"Q>pB$MHVEddj!yLH9||вן瓘Es),2hDA*W[oe/^^cm)x[65n0K#ƱMm) &+}9 a1\wyY)VjkꃪI"7" +akGh&eИ)`` :N3kLȱS&مHRkƊ9P b@ed9zl_z +KK@N +M$V' F;02W\HVL}Z҈X] ԇPP@Cσ~L 芘 3r;gdUwJUa*o@m.)ٯmgfۡB,geg"v5Uxg5xftݛH^=Nnh9( d_@1= +K#㈖N8/ nuN9'uUSR +즣P"0<['׵RL~[䨪H(mFBUXcyxX` 9eRCAX3)}a +du[4OR fboߧ>FjOO3d)S<6024s +NA(}pb/fw* Tpv!h`R Y<ؕ;dͪ+?Ϋdm> 0c9d&sh`lm%$ۓb,9E[B١;ڹH-#yk f?q8v2ֻ,''R6v8(h_Ё%ؠӤvbk὆]Yf? +}3|pAA%q|OcnSP=@v7 4Mw:{yԷ|]),¨8_iOSOIf" F{%['h8)75xb0Bf9ȌM5^ fpC.} +1 㗖OYU8 (Fk )Z6{d9L`݊EұG*7A\):p8 ^1,fJtc\iGBa=8ZT +)a;o٬Z{7 ;xf3h+yJxǧ#$%Xc%N%Rb²Qo%':GfQiVx(sp,b1^Ӭ:e|#%:G'<&n_ٕh)^;Ij:]u8̠w؆`jxVC%6|QzIyڏ JCͻ ȄΠ|^FJ G +;v'O4"zKOX$9e8y pED@E)G/ِ֜?ue(@?U+,Vf9rCVN"N % U"yn>stream + iiRf=ϩq'gJzm=Iɿ 4$IJ=ԇ*sՑp|)ŕrծxz<m9.}u~l8e^sus{dv8gpقU]O.LCېXѶF)!U˓vdR6Mr,kh5&{w|IW1%l]/gZ>xѹ`(a#^a0 d!-K@m=@(w?Q6NHdWkM$6];l"G}~迱̈́8_iOvZl$ZzE%;dS/|!(3#qRu(_`c+\@ <kgNsdgZ/Ez7|9|4yd) TS}qU,Vϻ6>Q=Wyx^gwoF|nopb腝# 4hJ^Ё +ՏKDdm +$"lCԤ +zE[q֏e Ov<]jw3^+ʗ1:"oi'Sچڳj>{Uw$7CI;H4{s?a4SY$hyjOvXKt+&T<bH'D桀&*H${vb)[7E9Uߒr'r3͌Ɨ~_O!1:_ 5boIJT%qKR\Y!..ML-_v LeD2|-u=K#4fo"5@d[u7pj!=%{ f z ÷`Pȵf6 CL䖠'JeY4|r2)aИFm)1J#z)Ouar؂wVOS{_X:3fHQG!G)<:$Gsk:^6:TIA3 vcvaMkũ ܈ϵRr;(} wXD^tҬI>5DI>ZK(c8)Z3)z?uq"<1 ^xB_B|h{<9_ܘ=cbʴrsHWQ] +ю3a1..4Dzj}!йj}yX՛0`ӥsV[ňGs '(J{n!0DlșU\0%ɴתcz3!jx ywʐK`08Mǹ%Jp. ^z5U-,Zr~b;h!\VVŋpW$l(! oYtIzTRHDV6 gx*wTz@Wd]EcHwq\iݭKBL[VPYl2F; +sGM!A/9b_؅SBPP&ol3] +YNK +–\4.I4Gy+XW"zߵPJT֮7e;Oa}$q "2(a쎬(Q - kW -*47#0`qD{u9"dL*mC*? -i.pEI>b0 6Kt%56!Q1Oc2=YWvπM?\?xZp0ÄqYAUTnO8a2M{k#H׎e*7[1DxC|{v3ӊ,ì[>8bOgV,`5h *;S,g^)K`nm01x6le癎RjϗY7}InJVo,bbm- ;Wfw#<9 ڤf#Ž'-WZܐ=H.PY/-0RTiP񘴑dfRt+@3A临lю^REZ Ka ʧ$V61z, >=E2yRB_@7zBCn;730e״օ#n{ݸCњ)Xn OJqx; 1&?ACn' wÜ}rkwp9Gp-:.xڳ"ƐɴıIF c kmeu] [:vqh}E9A)u= O[S4f>< 1&!P$QU=oط~Wո wWcV1YD/M6]zX 0TBINomc9jFIܾ7\O/,ZHHރ2ۘ+OQŠT˒U%(Tg,Yt=s_&Nc4-cpقX\jָk픦ꬼKh0O5@c:zazy<µ@wq kM=S V綫rҫ%h qC'd6+V\=-{iL'S⊕Heg)'zWlwY4Ϭem . p p⋼Y{#^6ó8?2xY @ _#oOA&'^nt/aR@ayi^26NwQu?>1h|RcJXVBZJ^΀~SޚoffxP8RP`/XqŎd.@yj^*e#re'mMٯ,ZNK)M]Z@CSMЄH` $_d*Q dG2`NN4ObgI8M9ottA\ Al&9+PPkyg{J_,Rgh\A5'Z+ӽcXɉK$*`Oϊ OF)))O@7|_4Ķ;ՔT<V*P3b6ܬYl+Ј^]wm|?N0 @   qQrܐl^myZ&,ZoZҦCOqi +tt) WG^k!spR:V]@1 EوNkΦ+.eY) oS+T^ ݠoEkޫ.yZ +v!Fdѣtf|jr_IZ(kw^hoLsjj#.]|[A $6ؿoˏY0BJn~a{V@ȗuXJ. +vbnrhcƥYH>B}-N5UnI&8>D.^rF)[u)% 9zN7{̋,wMJ/Vܲ?rɢNTɍl}NjMx86W:| _ȭ W +w"l˝ʹGOa^Kr lC .Fݿָyw#&ur&sRn(VɰPQr'\k$&&YL +dʍn +D=QM8%e9FSy:bf$bb|s@~Вѓ>~mZAE9ڒU5 _φm]SŗDtmV2ЦMՊC(|R05HnynwZڃx E#1Y2gݫ]'_'A=]9ggC` +a.a>7"fP%lo;}eʢTK~RwJ*New bEa>vLVPR!Xpm3^4sT? 7CF +H$b_9sߔ?4k24ɀ6(- 룆YA9n\Qo ަT#%8~[e&4Q >M)Ӑ=Օ4FCDJ>:C~/\IL{.ds +Q^}?>yIt]u6%{JڼP8HAx/~F6K ^%~`VR2/S0Ļ+++1b=LmdHi9[;<f0;)!2 ),AC />N =N [ s*8c? %yk +f%/PRLa{|?M ToG٬UI. +%\& 3 eS.%fq+,0YjA_Qk` lh~l"e oDd*|18Ch)ɢ >gu~缳Z +?1P +Hˑ#xii\#P7"e[\]yz,OIGPw:yt"xF$z S/lPj ZkϘ}7|VsGؼod@fvlHb3#5 +MC)+x/zq/j24O{H? X"_N#U{1#79l -*ʧB_TgïBrekz18Gpp煛E{@!~)o%-aKr;u8Ik2J*,,$hbV:ooþE+hxqC .EPD~m޸ѭDjFJcKbpđ.-Z~u -T]j3p[ᆘZwh dT*}7 -}AΈְ.^5wJb[,(wubB).0w_7TsWOѹ~ (ge=Ypd7cxkƇ{?3Ϧl KgTD_ëΈjA@tcn+̐veI]9T\EVUq(X h.RT8B?Q4.dy>yd-`%DwGsLv% cZS) +QF U,3dԮN+M?C#ic[(O7Lk8 Z 9&ʲXةA.캱eÉ:-( C&ܚF(CPK|&7 팈b'$f_rJY#%R39>l|/0Y -uńZ^[KM]ɨS{PLixSuqiiw"E̕I^Xi׃iiF?f" 8]Z[|CЩ㿏{9AQyt)NeT]n^a`*K>xҽ+=p_PcRssڔ761ϭ=,oxyRU9Ɠa-C2t{?'ߐ'5^^Wqm^u4Še\ .JgPa3ƝL3EaY&RV3mF?(R^wPT)xɹtEʕAEJ dpp(IZljQM18 Ar%7S~P\-$rm/FG\̞V֜-\ܗK\$:骡P)%7\nj@8x9Z+iGe Y9L=:q3K+i]A3^I&8&3._Q*ל%z=; 3x}[eB~X=> ;.d)o֢FK|s\&"ᥛѵ$z&Ot2|jlG6O3W.fgXs-MQ{m[Xa .sثP:kvPp;mML t7.eXlFHJ45Dɖ2FW=s!*h1 XkA)*6Hz4=( m~K{lay/pvܑ=/2TSwVҧ+6g!U{~hdw1?aޏ-<cZofTU@OiEr{_9VA y4}7?ouս!"x +Vtie /$&*]k%+y@/ Pxb沂3AL3zz :f;PNzGQ! 4oR+wĭaƂ`JȫS QY֊j JTZb+ +@D=!Ѷj_ Ԅc]桢->~,\u3wC~g(nV12F85/T +%r fUkzͫL'aX80@(w.*hh'kň7@mwu)s 1CJd9MJPՄ526 sujZ3Ai?7_i(*0 n\k G Q3H8#d޼6eiF3"$B\̿NKs[G{ym򦶂+DZY{\Z_ZGN^Z +Vw>zdeۤh"ZQNMd&1KZW/Q%v8~H/ +endstream +endobj +148 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +147 0 obj<> +endobj +150 0 obj <>stream +Hln@E,I{( ("#Kcg^~)K9JrRg/u^ ղJO߹Q˅uQ8=&+ST׭:\2e +0kjH +endstream +endobj +149 0 obj<> +endobj +152 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +151 0 obj<> +endobj +154 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +153 0 obj<> +endobj +144 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +157 0 obj <>stream +HWk_)#K|Q,4t7hQA1[rR&/)Rv_}{ι wU=Do߮7'^ۯOIDdQFw>DW8Ie$R_d"!Ti4c=?ɵaF?7 !YGzM5ȶ14x*1dz{^VzDi٭8aEmjbsD>J?"m:$Y4.267$g_67:OUՑxog81/K KtC|qnVOisOϏ^Q8xDT,G~0H4ip*6 )'aY̊ī柏?ݿo\/F񻙖) 缌!|zު7rzͷ%`2 V%S)Tmzb/3l*2r3S'j3S?oe_}f4Qa>ċgN Ӭ?Eta;iB$;Y_01NC^{%c$bWN}h:Q$8el^Vɰzt:4<5tE۽zUJAuIbO`!AMeqQRձ݊C|!щc%R#3nz Gd6WOԌSԧ$ f/{&UNcJ0N‹dA`]c3`z9P᧧;ő/r;j يZ8MGpƜ\3G,}v%b +C 0IL39xaT3 dž/a"D e8'25۵~UtRDz2SaF N3qۣq^@,6[=ef^jZtĝП'E*Roy\bRRU9G#/s'0b_8 |D@ +Ӡc <鶇 + xfEܼŅ6(lzoJe?L833},}33'Y:6Ҽ$ Z<pJr_^(X!C(~jJbx MY$H! b d40 44>Xz7&qUǧ^> +-RO~@W(6 MF8G:dFmz?hoJ_ t _0>ᵗM=rp%HKxͨ w' Hofpq_G *a듻c"|BtNK.igځ\6Kx|I%q96+恏H&Haw{3j7ޭ388V5Aӌ,/h$z ϱzvcV^s9)ҫ?`v} 3g谑ⶔJCP[^ƨ_ M7k@vAl޺>m^YĄp*)57hL + Kx-3|FIBհ;L0E6ǥaR\ZY=~_oן>||x~Zo_s4)iWLȖP +xE񻱩gU`bV0RbNE"R{d1![6{G#뱭MBxuq1 JnVVhw~>3Qm]nM$Gr6OXD=[e% MqpDYwsc5rncb悍˚h*4 )|`Q!A5ѡ^a2ìW(g&K} l +_8RL:kҊihr{8MnDl +]Uu`K,_NW!Ggk&9 i=RԂ+l'䲰,[N>[Bd֤]+10vLbҘ=*MfN5d&SȭhsK me_}Ss1E͟:hF)-X1%}{%Eni@}-,%q #Ue 8|sq.=c i:i\@- C }R-L^/W./R,# >`w#3[ATqS;dz#E.1CaVKJL:~AZg3 +ՓC1FC[N8D0eZ ( ,&;{-Dy+~1Y*\\Djgy1j_\^G<}evza7D=,pKjaX_[{YiƙBmqm6#/^2GeShb[1 z\CH!vl$P`[PH̀'fA(CRBG29Urw jse\ X6ܠIH;o_e_=^F /nwu'Pi8 ͛ǔZtm雭 ؗxJu V>5e66ϲHgQgm8Zʺ +-ӂy׃p+Ќ?H:p6GOa9}$[@U$k +EWJ86v3@|V̈3/ǽkJCTKl}9VjzƁ_c ԂD=-u \hqʑWgFChnAd~ͼ_vL M:\ )"ET ]/e p*DR>lA$Y=np0'2'CJ;{bZpSN`f*p}}FkM(P.+qLfzsP6a88]=8C anvȨAy=a`oTo6PP ^!r hze><"8#/}܆<’Y|s90kr]V@HM(oSwl˝YfxT#.\Tm/ :x4 8l/耿G{)6EL{8kFS֢dyf7񡋆$("itӯNWʂ 2Gp7zRЍyἛnMpYE O1 +U**S-e4 b#*#"aL&v' SBFG +N]sƭxYS,i!,n?Lΐ$gNS2 ܈oPG(!kt22qgv8 +URնK2 )I4% ~TzYz PeؿǠUZzҩwe W/p7Πe5+.\QvGk]V]ZԚUV MAC̑!009IM*IłsN{_'I.Dӡ7侂A4S/;}&EYyu?JLZSvd! j{l3g /d-'e!|y*MmqK? o4# P\=x;|:.T!wrx;3&ڈcBoxj[E,3NCnэn2?8uqM{}r `R)I1&YRJff8'COo*}=PKf:n*1Fĭe&)  +\|}5'ϣfDq6y\ Ju8} `rfwU.Gmr3|IV@v6E#[*M.!%|5BR |34,g}TKYe@x1/`/ØPw(Q*W7NRfs.cºսNgO Ǚ~yP?]'8*3*tVYCo1}=sPD_|o2IHj @a "Qތ5riN.Oa~p +iAo+AE`/Ϙl_M13!sNuYST(iH;Q1o.Tb^%m}6sqJ"!N$ޗo+ۈucB%7w&Ta[͎]8.7Fjɲϒ/Cg;Is&j/92hnGq22 vUaW<5E^DCHBk!ifU*U(t_75A ,⩲5_@%5|?'F*c6$6|<0[В ס3Adu# +fIo3GȘt*BNe$ _BuaE.3fwٻ͒ր!a |da9{ElHҋX;'^ +endstream +endobj +158 0 obj <>stream +O8eֹזiŒ,83W'p2I|x4In~C~Q +Ǚ|<mFaC{59RE 7&X:6 ޴c'JCGn3{FFH=<%Caޅ,5TYyKKIxs#j)Qߐܿ8Np:rgyɉ:"fc9kf:8 +lx6qt7R$SKxE9xJ®K֤FVgBZVh54[үtƥu[=yNGS(֮V@dEq?dZq|$zj 0m_XAa^s"O[ ]i41^23n)e9K0g#9䅹=`j:8q1^bRLzMbwPvSoF[?+esM") /2_v(Q (COw?du\!jw(d_ĸB#+`iC*vZךY:ҋ3wVwG&5.<;f:- +:-Okel֥ʝ[i+m YhGс|a?wf!3TR|DE:7$%qDV׼DcͶv>'7bik%r? +5Ǫ"OYLHU}ifT.[l+UW{ Y#5ddRߣOfvm곣JVz֐XSq{3J&.~ rIȒ!TʢȎXc>؇Zc +-,r2hn.Rnt0W]"P93Λtt h.֡K1@O2oYߋMd9SxŤZ_|Tku66m$5Lu!%ޜvH\_չ8mʯ0 +A ۿh'w<֦Ђnp6)•}ެ Oӕ޲M݌<"WSd )l|he}ca/0)o*Gdڌ{G]n"_p^+ {:[;h~5z?chp3PA9y`A/#?_] ZDR!`:UTX=[MDpf%e@Ƶ}y~#.&XB fغә%hs1΃PvЇȐz.4i[S<,X:k"K׃toLou7=»p;Ϯ8N0Ś8tG@]ZrUnוmF! }B*qzwwT$}LXOYv#}eQ'nH4(d.JXmhwC0|dnN#gm rF#eϚ$mn%g)$oƴhez#0K_\ȈqKV"v@($/">?E^w4'F߳' +jo-3c e{UM=ȫTQ/9 b8} J 5CE=:bXI/h$TX1ΖH ߯$>}pV'C[o"2gXTt<|p5+Z1iu}1bW8s|*۶W {Y +{6WoR8O !Ԋ/p!m a09[Le? 'V 6$0slgJK=-);⺠dJ 'IODQnk RQאdl[cs$#@Ѥo6g<[kkO¾KɅ~=:Ws|ym8:y5@b4 ˙N_?X܎'Ӟ3;[~7o#_P_{D?Bn"߫'*@ZIQ~ B fw Tϥ'V2zvC8#ʮ8UiWVDcT$XSXFٱC\C9fy v̙@r?g).\Yn7Qnl3V|l@ފ;NG$撃.9sbB M_5&{--`û m((E֛\m,t@s 1#ÿCc+.$ebk.g&伢h ;kY)tyf$b;|JE]S;{NE5>{:sMGY+||QN',GlT0,~+t;jj{Q0 @ M  Y +DK$s~-;X +hci +ìlxi1J hf80Y.6j7jR7]Y~ȒAfȀW<BbY-` U_!z/~3L)]{fB'鎷qYoF━ijm[.DR~=<ܗ~gֽ>{ +lr QU-w|d$8ZtP?,_Uki t#ARV$1ST~+3_W 0v|]`^C f* *$S0EA ͭH$?'\5̓ ؜003N D_VSd3{ézR_y䡸J^<8?cub~X `+Ȣ{UGb)tsdwK2 BghO\13*RS9k<jid M=-O1>.7z Hr#^|t]Lw\;RƽD +00Vch~v஑^z*!,[ScUfk (fWSesn? cC5ķi#%nSO|iF,JqC=(HA b(Tb$8pF%f ,:kH͏@Qg7vu $là6$Km_\[/g0A$6(4+ V[JX.\}mN-R}cc9㴌k}cyU_F3DϾtO :&.HN1uQ'*MOk/ +"{.CsSt]co3{\:!P@V wۦf L2;_>#+'=t3! 1v( G%m.c垲ziHiv觅] ^Zsὢ"ő1?PQPFE\ZqDSvV- ֦.s(,ܷ4~4'oʗ :1*^lSUs`k=5rϰ.PdRSf|^\Ґ!o(_;V7jlۇTLsBD1ngzFb0nj08:|-aqd9tXmhE%E'EF#e~`}Ao*{ȟZB 3)"a8 ɧ!r|TaCߠC:.qu0)F>P9ԏ}p!ֺ,h%N` J F݇b=Le%`/u<JVoȜOj!BoC'ɫ/P)г] t vj1&x࢈HzS"'av9żKVY\D0.=UH+7M11:\%RLȏU^?TM [șuT!JL o׶ X83@\[L< -H"rIQ TWZ B]vuhmo#^^g1r}‘4{E2ZHfvޡ5@(HK(^zK`B߃" H +\k4p1kPLmE-]Ip9tP#qL.v35:WIqLzTf5B{{Xm#~S͗6AMY5;ZT=OE3J +ĢUT^K=e ֿ!AX{gmSQ3=g#lW5(bcAh Črp>2 y0WvJ_zF HGZAV#m^!ASnZfr<04ufh8]C# lH$'f 85Duu3>(S ƜsV<͌Z!1;ÏduoZSzu6v)$8mO9NIT@B>ŀxPc$ۈVc.' <#"_C&|M-'ÙDjiGZ9ߐ_V35C\ 9Fbö=@4DGqHa<*TJ=Y@V%[%4k[ރr;6lx,B ][}r5Fd|??_gStS`+苃H&HJ[>ºc* 8hoFZVF҆PF=ޅ>cZMa]U3WfkmL ИVMξISh+#?+PA\!q`uւjr-zF6KM0 +56vXPz~4$J3w)٘?dg/`;Z[ +TGbg/!Q:G):vY +vrVi++ɵ|No]yE%%x@nW..I:S{⢊) @ǀφP47[Oקj6 +^bx%)t\vR]n92 dAȹόku.lhn!4/!؇P#tݳLxcӭ!EqI$X)3AHRg8jOZRY%s9wf4gIKZհ_z)Kju*M#eGF*f bO#i|I|w׾FO]9o{a ޒj&9hH*n;Dek{E{gM|-z,/cuQ⸎O%x +$q.h -6j+mY2_vB]"xr'NI,!ls5^1mVɮ:7ВoƮoOpb˘+=*f&jtS΀T!.eK(_ZSB.W%_ۈX +Y7*ҒqNv(s~,pb9Q}|iW5J<0Eغnn<Y]ƈC^ ª#0?{P(,r|ߡVLF%/?LR6h$e#W .Ts'=rs K/IAE99r/Aw,BY'N0KX.it& }~&"R@"s쵊*h9:xW|(:O]+Vv>PN +pbC3$Ajɇ(EB@FgŚ܉XGDT2cAq7&S<4Wo9&곳}`c᛹ӱo.N=c8}z%SֺRe='B:6 +M@% oOR$K SZ=-xTEQ?61H]!b&!`c~˙ 7`[ԡ 3^ܯfͩ~HbUH_3}Li!"6{ sו.Y0&Sq3{0@ztG:#޵IB_:nWT)ުɟLF+W!ْ%ȒD]슏>䵴)m-aG]]~`yq!֬zg@*f~U&=P1Wl4jOH%F~24t@qG͊]CH-reÝe +eK>?Yc~ |l&|r]x/+}Ũ*&4Po謞3ž@ `ybMOȜDܒwdLz1/Iid%NVFyOeSYd clP` ݳ#5];>u},( 4$ܟu%lq4I.Jm!7.V*$=}o|yp2~yaڝE+[+uXHXEIw>=<A?₈*H3vRK׳Lʸ'_mxڨ 3 + /Μ/ F]#_֝8+ΚE' +endstream +endobj +160 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +159 0 obj<> +endobj +162 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +161 0 obj<> +endobj +156 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +165 0 obj <>stream +HWێ8}W1j^uAe1 jnkƖ<ܝޯߢE)Qv%$N:u}W죷oWO]xj}t}s Kw7?DILI"q&rߘ<4*O{}lZ~s(jqjo0U]USPx#gY$sSFUY-W?$j 1a2Z##Z4%1,e.'+j&!4HxN 4=IbDo/8tlijJ/:ͧgeկ_qb_uF?| 3Q LJxM?rG+㪤rC?͇F7|{X.z*f2*M<4#x23S~tJm.TLlN1/osU}o_+\uSx%i()-8Ͳ٫.(%/37Q^*,|:['p\KO`$t:%Y +Df(Ts\!q쪿iXx6!"_px٬Lq*,]THTnu87WEmo)g)`w40A;ǑK(`y(M{Fy4m_Խ: OEL,(n Eg,&~U?4Φ`o 3ʍnZW]Y#veFkU{9rrǤwv IMRCuɡF}{*Y0]ISm"e]PDx3` (׽'){Nqdhxj!x&fA.vj}2{*@ʁ lf1zVv0̰ Ao['$b„ `I1\6j7LZ,O8>)M#!I6xUN\=ᖟ#8ITȦ(ZdvET-`#M'bYuDAf!4&w;CV*] .xd@?γk7A?nU +%못sQW_G}UХNo;PҠх;CnQLi`N2þ(Uu*ZGФNh=mݷ(Vqkt0JO`<UѓKO`,y3t{FM# $9C7IcPy 2ۤmSӼDʘV&Vs]\Ӯ x;x9c8GpVjY]3mM[uqpwMCq C+cggsah jF+;UIn;}TtgLeVz`[IST8pٴoN 휠>o4)@" +B/G8كE("SWK9:W˪mX$mʪn0 0J.vjmȢ|bX,VD2 Ld`18 Z.ۜH_sdzJ-gѰR=<&`!eƉO\T\ˋr`pj|ÑyeV:MXb0bDFS|آY_sTŦ0׎ "W׮_1?B%!BBŢYs73d?@[=Nƚ6?jG1lBgUՒuZ=P27H31>iV~~VR9sZx{PhH^^Rfuh| _6x|σՈ25O +VũꗕdVxdZq+Ck;F?c!NMť솂 ^ӵys}E,!MSRXϦ&e;|j6{T;q 78Te0upoD Rk '!AR8Y˫x 8a=<)t,yOOsHCzpzPg<@۝W+QR6":$9QOw'.q7~Y4.[ܩWwAWft*h,Ӄa^U:]UjUB]oRUiTզU [+x"1|N1ks,"?@t2Q):D7l@ƸN$ PUr֯.S&Ox9Q4QhSH>p +.A*?h܂85n6ܽ .Sub ycZݔK6aԴoՏ?~~>~O.MVIt?h! Sa?PoקFbF"V|2,vjDtOt΂ň,F,ՓZU[%^TD??$SS:vB+q7}K8W/J|{>stream + xgg{4nQ\%`a+Tj^VsvA}lxr핰QIHgpb\6{c3|Yopf(H]s{ƾ@(4q F@~,..L ]mBu.ڠR>/PBܧPh?j}~2IPF>G2@ wSˎ@ Sm[|U~duՅYBw>H˜VYN$'ɢ+T #5h6,IFS !"A%\r#\I8ZUUK% k/7Hbʭ|o5aXOpӽlUyQy- qQ(Y`1R:L+k<Yx۽X)dݶ weۋW%} 1ˬc$?eRY~َNօT,&_;T&aX i^'?wrj p@ ^ !Qyl{+㭕oP轏p"qVmց%)&E/ LGwʿ\#ˑV%?/9٣ 10p +SUu?}j# 䃕rʦ0zI~}Z(t_6$f +="jus:)%H6 ֊Д_\3yd5-,%)(o`lO@#r7dTuˆXyHNhr`THr]Vj[v4g69n4v, <)p}SpF[%;h" q-RO)*ӡJ +|28\]q%1CcR>LX!T=^{;ĬXͳu|+۰hLfr0Oo03xgp;Φ-~Ș^+_(t^Wp^ߛ +L_[oB+r6dgeZ"G/V`ރ|Gl=Kv@"f݁ VGRqnp,ݜ{Q350[fJPOddu9XBbj,X}Q(牾 Ui&?H̓fbS͈6cI mgfUӼ4^;P2' '#ż@^ 8 z^<,;/K¼ ' YSpb8i?͐d Y)_p,sa>T-')*6BrK4sYCCwcKt65y3ڦQTƊͲMi Fk6`c**oMd=<4]%pCUdA*SޏJbu{=ev|3(vP8OGYO[=0%йn(A"\UeUy3 ֛_~K]!켿q6{,Ϡv4ҕ~"|؃L|Xb\d13AUJ^T+oyVUڭk:uزteR8#+h#uG-_uJz#P8ο$>YC+WD08\>XqM +h%23EVJbijuuʎ IAQKUIcaACǩI1C}47~bzCM'lM0 @ h  _G$ׇ^J$h2O!*Hm,;xDZ_FE0X͹g ~LBwF&(8}APѰ=j#<Ƀ/Wo8`HW`_7NX5D?QM}%Ao$(lE @S~_>UT w$2t5SA U+|* -$ hCm_"FR^WN2`KNe2fFBB7q-m 6ܲ׳ +J̱Ţ/?d2\oR0fسc"֊*rYS)QPgI[/q ĩTY-Tf<8XUwG60/LSW^KsyT42U~DЍAIɣGr6`SK猧4cd}iHe>۫_vP" H.rII 6qj z욮lMm0]՟bKo"py[$`'&$_/cGW\BdD?dy0N2!>aW\wI4+`F=p*VXxlj-4ȱ7m}RԇJJY3OcW[[ bd+ݻA =awkGH\ԵSox2dH7ⓗQ=`Ȩ\)DRSBsꁕ-ܗaPA u8W'$b}*h(ZጞV=eJC^BqcKwXS~_A@=|K$t34% HCg+vWsA*$}$&iծ@=88g/kgP?*LWOQdP8DZ4:ū3b",i?/*֤8QǐST4/rz0-\$:ڋcC:% z [;Sbs,)maYz[;BBmd)>IB7&uC9Ha7*f閭.lЍ[M7.ĮeA_&]4π+8Ѷ#Lޖ!=$$gvnfŠkZ{|-Ul?}vV_$ ~oOT/v+QX/ZA-yHmd+`~MZ(OqLU8fl+Q1XQ>>ةJ_w dfx\sʀ8_쳠XboX%&Qw72,nU4ee4 ^;+O،pa'f34`ӽP:F>3-;[u3QG˂؍U_Πфay"K 7K|pnDʞ;ⵦTW'?s6ZMRQǹKS1AQ~&br@-Og56+',pAEh0wtP>`f$$YYurnoCG[|>7Neeý3б5;wO2$zL+~ W-uju_ [?CSv U pɎN * '!/5mQ/=_ƄEJ +ܿ_cNp4XVcaI1ࠉG+Aw" gh3[[V4eVevGe}晿6i~=8LAAcI5Aqswl}}Ŏn'g\ :[80mX=FaGU*z cc(;)(YֻNx( ҔNdz.ڴv 6 +&䇍)((Ȣ 2' Wv(8:%?Gǽ=g=$_ejDp=li×V w}TEQX&ea%»iuhEߍcB\yyɨn +_* KȞ7*!՞D2[qmƫ7DNЖw!"G?4wMpy`  +/  my1Mpf,BgC-<3Ł[^~u<=ʒ@K,#󷑖hrXK,Sb[@bpwT9|Ww)G`*G#˹_u>^wfueS^1$c=<,"aP"T}[d;#;}~5Sc/P;Tt:幸IQ|@K=Xve\tg~Kpv>\o˛jvb9OK~elh5OY6{O ŕ=xnH\L9wH^PJf@El;>xK*Iń +](5YJN 痞Rm#B +emq}X|ÊmǧHuSHdt5D8I2 {KDJQU[Q@B^RB䑭2ZWYjuUشvΆV |(I)7_TS9?kq b*GսUl+ '%7F%1qQKh]Mo*<Իql]؄ jϏAt}[4cZ {qdS}Cعߴs!?kDbX(rEL cbSlO5Ppx)O ^D)M! :NQ&3棂dUSė%VF"{>P`G!J8:l;g e3O}8/|GIK+.B.mf#`&,((rC,8it6=fet yD,L mcw#Zt路piI*R-@tp,jꇺB\]nǹИ[qq?d*VPȾȉħBB$< B +S:T\@.ȩ830*<*0Mb2jǢ3Ҕr0 O˰J:M{- +yk'AqhSXs&lrWBӆwAO|ŷ5(-J!Bw=mkt7 PZ){)w8X1 C+ܹ[QR"(_li~ ljQ2)ucNDi1,\*Dt-#?l{.2!&G ycd=q#{6,iPUt_NÔ5)&sc_=> g;M#ݭ\h&  z63I5MK̚p>6QB(p 1* )(vR#̲J}U/TLLvn#t/l2@V{~nt U_?8*ٸ˴ڢMčPTǏoPhšD!pg%S*a}͔tKϕq% l6g4o}~]8Vp2] @Q"~HR]Nf8?BC '#wlIS~OW +Ol}/ +bS; yLMA27K1!XT3Wh .R+{B~$lj_Kv +M0"StsH0zuv{$y%pU9?M9&:ke4TCOKnOa|?7\\@ǧh]\0Ercqxek0kuB ` +Dᘭ"@uݫ0㣸rիP/F8!29+7?;k;N]Ǻ;uvC$_&o3-4G{{N˟OL"]y'ZKx = >ctܢI<& L!fdSUXα˺b9DLT=2yf9[ :' aG^@b\6\wpxC3}D .*Zhcx/ 򫷬g#3vBao#!ՙc˂5!*y{5G>:'4&3&2[>M8&aWLfC'ZF5cÐB+:m3+2 [H-OesM(fhH)j,,,~E jvA0>5 +`pTAUu^ +endstream +endobj +168 0 obj <>stream +Ht0E;mbaA0qHmiߗtxBbѫs{zk'piڮ㵿!c<]g6L_R Y^S컦7mKb>8z?sٷM?udnpM +OKu&[eW }CXumݙm<3|DSpNJGGk6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh{-PY(9!l(K>AYΦ '@Y^&(K"MDʒHPVỲ(Fº t#J&Fb#n$҄' ܃n$Wgs >J6/U}*~i[_Qg/VGX)sZ|Rr/U9^~)G랽$իe𿟾s7 +qLLV0nu2eo0mJ +endstream +endobj +167 0 obj<> +endobj +170 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +169 0 obj<> +endobj +172 0 obj <>stream +H\͎0y/gTU1%Ģ3J}p (J ӫYp>ۑeߵ}84mW1.3udTCÇ/v?u_×x6T>}4ulXDZN~Y6 xdn^xZ ߪK4ɺ1/:^*ıN1Z3ۦe߭j>slDSpNJ''k6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh9\pֹJp +%qAYΦ '@Y^vPD (K"cC@Ye1ޣ  gWn$,6F"t#a{Ѝl.aQG楪[/mKK9 +\#%^~.Wp_ʁR={*/hݳDz>98\8ߦTcb2,evqJ]|C?I,OPg +endstream +endobj +171 0 obj<> +endobj +174 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +173 0 obj<> +endobj +176 0 obj <>stream +Hln@E,I{( ("#Kcg^~)K9JrRg/u^ ղJO߹Q˅uQ8=&+ST׭:\2e +0kjH +endstream +endobj +175 0 obj<> +endobj +178 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +177 0 obj<> +endobj +164 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +181 0 obj <>stream +HW[oJ~ϯDd@p@Ztrv!!IL ov| خꪯnlF/^<:WvmtU}F(rv<BT/Ic)a38M86GooQ:ћw`y@ӈ'2"RDχ??i7+SѿT)5$Ɣ1) *.dȈ  ;.vbl5>.c̼9wGJyf +'KSjf +yYmV[{L쩾;SǣCCy ̦M=D)TZD0jUCO8N(zRQhcAԇW7Òe5k H3lK;930(MKueX(?@VuwG#aq77/CfecxqpPzx@bs8v QKZPb@QZq];m+ˁaC:{I$՘`hS~-ܝ!p]V*@y} FU:z?P)mFoN"=ܓ:(-0i"M%0OS +<(AҴHhcM8:v]lۢ= ()KX ;,>x؃#dMe~93ySsO?I'zHA͉OvwCZWjc8ĚQ"P#=$@=I) +g䰨'CHl}+ԞlQ~TyrS\M0\yAn&j-Du WVc*gZ35\f~i0>ú }4?BbΪ{xKfVK,d̔9'Ob@;qfz<:`,XֱsIf12hJ)IF&vMOy|R°dv,'uM-cm +lѲ2l7W(H5fEy=ބ ˆXw~DElEf †0fX]*bmx 1e.ZBA>¢fe=4=n)XmrCwue&]ip>+Ш&eHMyQJr8 3=r9W%C0ICE*cw6 ϺfS_M߄Tee:M֚\,!̱[!hڼ܌v0 `qT_lCK/Fhģ3(:F¶b +,ЅjX01uvaUXj-1=z$:@@ 3MsJ*$Ч@Ro5bPV6+I#ribnfw#}h|$9[f=uzOڋ955ܭnCKc&OF~m tulG## z ctjV:ݒ+2:ѹɚNY K?ȴ +YHXM~]dEVc;D`^w?YQl/5q"-׋1Ïcw.o '/M2S0E'#,Ǡ mQ۰;(יݞv{2Dm I5#;ƞlQXG)B6yݎS+ ".WσUrS4Vȉ ]V\>A[ 4Z=8bNF# U/CTS>첓Fٶǹ,@I &iSH3HI +4$ 7>6%NJl01m7OɄ ]瑱-<'Y7yՃ 5 [,VX SXObGA(<ð80M\qvf\»)msD1(^ݽ4aR[GyɨgUb$eth.+} 8H +| f_d 48:zp?$BҮLjӯl6"Z\9[_/~²^x=VYN) g ]ն"`XaO'XOy8NrB8B'pvv㮇Y&vAVl8j5&[\P 1 zN}SOG_R_:HHA(v ]L;ffPHEZx$L`LHoY=cRKwC/u.(x{3ߍpMM2~uf+2NVkRor림wOK!Ti'w`;5I"<~vDf4gО7Q['"6/|O(*P($M}N7T[L%.+9hNK~{L ܩRN ܸzbkB瀾y\o0iͽg@^S@ V6Ew+ īA"qT6'A0sw'dd>71jY +Tii'#^Uf%,*sy1\ӂl79$g4|csx4[Q"8l!Zx@j˾പ2qbPWQVY#_yho/|'DY`$d0h,j}T۴IBs 3H$bm9FYN:#)爌~ ST>aX˪NA g@ȗ Md,p#~f}AXTz + Š*.ԏ Brih̊r+7X +dͲ~|ȣ,+>t{ + Ydϖp>8Oi˞_L5Fs6fc>OUZI@z:{Z:S~IU/s'+✼ҎfZ*ʓ`A ? TU m端>Di+8U 16Zj(; +S Rc(oq{ʋBmR +K}e{g|,-K +@B=szxxl)|)%L)_D^~([vf %!8~t&_I`KFLd|0mng#fgv>mﳤ!TG F˙5z|G'TE N2Sq#&,POS#`>ɘBgptWXU2JI +'N)ƈC +/۞!5#nsC @= |k=JkdQAg:z[OCu4~Bbt2/_OyJG&:FU]5M,\1 +'_Gps+z($e%4gq46GW)WC\dY޷^w^˕mzσ e-JiuP:t|/՛cME bmFF]4`'5'>ͦNh]VXo,BDcEOHD|Fep/0A4-IEXI4|ll"ߎMlK@P!&iU0YU=ʶdT#^Ig2V)Fn9tE7$4~!26:mT$"rD}y s~ +endstream +endobj +182 0 obj <>stream +R;#^4 o7]1o>Wq=_ˆT}"A &?x$l4$UﲄVvQ +0'PWhH~'YkOҀw}$vzV/z=8?7pqM{'yTD]Qg(ÕN+?>O8ӛ{yGEhQa<=" Ӵl YIϷhJ{ޙdkwӆF銒s8Pzؕ:óԬspu׭_Ѥ݉cJ\>SgG;`u"ϳZm0YRҸď2Bxr&-),\2&OWQgkڸ% 2q] e_%D|P=1Skhgƅ KҤ} X"k{0_KPש׷DoاJc0r{Y%Dټ\I>!!29jeY1A,(Ymr~\?)/r[RK CĹ_O:mfJ63Cjz'Dbh=l}O\K4=>_}hѺ"kTIXf:OYcvq(ᝥO*|'@f({sj0^26șjrz 9I.yҺrn>*")q=7(T FM]l`)*:% #` +XixW4:':KK'B2)>9i͍i-߸B쁢R펐L#̧͂BA pq8\;l׹2dFüvu5wtn4ͿuRVO&Do3x9>^1$3L%1bX e^P鋴ԕtϏs[ !׽g<6R646n}n@/.\)'BAr,Cu"s۳V|ozWHg ¸] -X'lR,oIfHϮxVh):4%qL&4-MPTj%\\=cvdNq 4o6!H+QD"wdfhfnkcA8rIhkU ZGK*y,FK 1ߕ4ms)׏e13CgwUn8 0r0Uځ-sûF 7T- 0dN'<u;ˋ0p#t<%UM$UX3!eJ_R6Dr8 ׾ɌbRԾz-bъߨPt΂W/8g)Ҳ3pQh"r8n!Jy譮rAfFS~~p=AU)Te92XK-2ظP(Un5*e& 4..Z#K4kΟBjp@ ,~r +|?Z NS؞Z55GSF>e)[6Xgpv= + {(ɩj49VYo-ڴ. + t! #:?A@:--.&C5mU‚\߾`iQLFJrM׽Ÿ/D'|!I4+;ZBVp\PeN\7%8ߐВfM|ǒy٭C9Qqn#Y|oXĵ?!ve0RApie*Úwl +fc| +ߧ}P +Z=>&優}#NjNsZ%d|:[0,egӟ0k=aNm + 1,<V5- +rvj +)g9h\1Cu,RaП(6X0Ά||Jbev{xI<#e$@t:OGh(NʳБR;2}+id)a?^H;>F/$Α,x <@BwMQbq~]s1VT#[b_, BЈ=lV'749 DnUO\ =m|ݐ܌j/=sBh_kk\Ŧ#J>`dF*L*_*FDGt +"*DM7> #p)#HܽAһU֩[T]߂ah6OO޴T(־&bg7Y/'%#f}djkx6+D{m3S͂^m!P+Sptwߡ +Q"P/ x"c%Ԥ"><+ =g/.=WouBYɑ;{fJ*WCzŰKه\^䡕 bPݥe,͟ V*)%j% p0|p$y]4蘼`T^slTq3r7ƒqPyK0T $5zc N!e5Bb74X7 pHi"q)'~;+NB[ަ>JW3 wJ˩Tc=> Z#\xD2 ᶱw ȕcFQѐ絀-\76S/iC(lC=5vtŵQxUDA{=djEk0ѳ9Qr-fRcG}2EiSI#ZזDrPvtodj8kC0w~ވ/J.ts]gԋz7VKD&j+! +,%(fѰQuD(8̩]z5U0C>2PYX KK2GQ:?|#U^7Az?U2\ E=$](!jNư7ᬀĞv0F߈_5#^*FJ _ynq[0s9Nb ̱a$UE2(V.}D+b&7%V?~'Guؓ )!7ʁߗU-#_;ztv]YjCP6͙}N^6q`>)[}eYFDg2?vܭ2Mw5hEㇿ0 @   + գ,-(*@ęw͢C1ڎ[Cq=qI@fvS ˾Gwh:#)|Xv >=$}rS +e]y_yS܅XE:I XncNܪt%_]As%f?Hr?r5T|Ʋ< ' >5l S깇vsB4qhGv -w=D}Ծl{ؾ =龕۾N;~+Wl#3R{j4RwҲd>Սͥ>M/i6R^(G@[<(maCcn/!A:n idKknWTQثX AXI>ZeG ץF~N<*诛6(vκH֩3!U:Јrp*nUjj`m'd1ŭNp +1L(Tyb |fsE]+ `v`UϒD._RdUC%L()֬l(@y]EIWDx&nsI72 \ z~A'i/.AGc -Fϫ]yL9 `\ޤg"ߙ (L3N,7gb#iYYE,h9st㖈/ =KꙖ7Vndi4 4H2ebguطCCVnH5`zCBeLWj4 ++5/PNNU"3h^.2kcT;6Ǧ^ryȌNH!`pvib!}FC>jpPt[8a T\IMC8!(d "L +2‰ԥ6˽ۈVh3 NP.'S>[σ& ڀ5R_23[u3,o0q5KZmMXW feD i(LXe=c^ o7MD }?, 1z|K6mNhoHX~rxFxĉH6 +kߋKTږݝgD!5k-w> p#K[ WCo=uSt{|E/9?BjvFBΪ Oz2cm)V]f-z! g@#v[g9ZCcT,rrڥ^mRdfMD6FbpAI1WeK~B<01 F]S(Rny@ _6<_)d<{4/\MxMXgxBC݈U7D^8%l1컱ZI5 NG 5W}Eg+B"t{?zk8>zK;ݶ:yHJ!E1:ևd‚+% +\KLG+;y9@ܹ8m+,Wthw3/L8s7xW°=]]f>0ŝ@LI +sJYPHU|_MOĄ+KUvvtD/ M"ov.- (VV[b#S^!$0l^j3 Ku:ǖΚ\,҉Qؗ|༞%w,A +Ώ+~%=$0h[5W|5oÚf7 :>sa&VdpCAcPLԼWrϪ}vKbқ +U)  ⟕^ҡ'DK4Ւheo q.R~Kc ֲ~ aoBNkby +{Q|ʷH`cp|mzsΊdG@+5'NSly/Hҥ P+;C@_ؒq\ I,/KcPA~tPItm)P-GW'Cv(v]d0p" 3ȧ nQVNX7JBJېՌXOlHbxHT8g-w<ΐ6DocNKgTFUen7Z^2C ߦ0t.ZMSMvP]}j ,0kTө}XH(<<F@cEW.*TUǨ`Zv2Upfh|+[ +rHX:%._SnJT!t.꾵IgCV}#;sېyC6`,S]AGnҖ'm ;Ht ژ2$_wmxvX6>4 AŰF8ŲFPv]=V@ő8ڽ0J'cӛhsDpJbUCnEWN ;RpxRiz߲3 +uщq =&wh ol,h{uګ | GTrqE:G[[z]?+r e(Ë035~ N*شkp/X 1:$I90=`J{Lc =*.F0uGLe)V1-ܝ# #uĔ^u?,/,)XI 0 >W`{TזN?4(Js}4/~p~?L @C?%$5RB*b?},S0jg$fnɢfuB~,tq2DrS͋58k+HpZCc. +}DFsarMc6!jtm0,⌅c=R9ǃ?ؿ*,jRY=ڬ|d@l"-: $U+|frOz.F8L;Wml^XGE  C+TluHk2a}S0}6_s5ժEcwƀ~H?y7# 2Y =f;aC5/ +B94h Ao?`3hh³l?\:fpgotd->I$pn#52/?k|6D+ zsQl+V<4>PӽץY7V. ~.md?i* K!͝BusQedS^_BBv3Ѽa"; GUhM&cObnjrSsuǹxw @l9J70j%1w<#]{_>|jQys' rVdޡ 'UXt +FbT%t5 "M &UaY+wm9) `8[Z!̟8V&@WjGzCE+ o}ҊX?$%iwM)9 B،Csuom):v`"G6&Bߕ`2=KTlޜ%h&PPm8^oA忸JM0g[ '/h/ŭxh,r5;:wsхv.XX^oh77[sw^I%_8?X`/-)F7h19ם7F1XQ,Ń&PVhg,GXCmI,f6ز(jM8I?w1ct# d<GX$zΦ1"fto<D@þv?#"!a\nKF=:"5&gIĮUXg;[j"YXk5ؒy}?mxvSAАo5Vsk)_&7KAb&Lm>U:zEȻ-o0L +YwFuq{JWN6[E^'˹EDK-=f2@t<m3G~ Rf\ J4eF"n_ _1ؚL +P)'VgO12+j6i]^[q ދ?VyAty sz1n +_)ȾS + M1G}5-Xbj.T+kփDۑ ]7v^@NHtQ:!=o;\y;&W;^(cip@@;1/z)&+cIfW.21mx|)ˬJi_YbB.u ~(-.y4>҅r2I/!pL/irs>AFF rjO"F8N-=ũmK'H¥F,SK'-HDOUYEϽĜϷ +F+ljB9=>|d U?!NUH_gpD`X]ԛח2xU+bSӬ,#$F_>SۆOɎLbIJ$a)&VkyC.R~4~ާCt/2͗b3`- W:}9f^.7C +_V~"Az# X}q +.FA  wP dc[rdk/CrUV0l(-wkq騎%dySV:K" zWZ~fmw=N %= rփuA c X+?*TЭ@zgQn -Zo葏ƹ`]31W)LT!<>Qm +9yR;7^IfMxs%%{4+nÂ>n2߬h~@@S{MM=ˁЊD50n& /qzv]uuP4f|B68-_e6"r=Ep28:t*k|ն;FK zHSňFxt}k&DԆQ̴ʉ!_lnT(| ) xV@Z,uzy%[`ʫ>HN2 G +endstream +endobj +184 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +183 0 obj<> +endobj +186 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +185 0 obj<> +endobj +188 0 obj <>stream +Hln@E,I{( ("#Kcg^~)K9JrRg/u^ ղJO߹Q˅uQ8=&+ST׭:\2e +0kjH +endstream +endobj +187 0 obj<> +endobj +190 0 obj <>stream +Ht0E;mbaA0qHmiߗtxBbѫs{zk'piڮ㵿!c<]g6L_R Y^S컦7mKb>8z?sٷM?udnpM +OKu&[eW }CXumݙm<3|DSpNJGGk6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh{-PY(9!l(K>AYΦ '@Y^&(K"MDʒHPVỲ(Fº t#J&Fb#n$҄' ܃n$Wgs >J6/U}*~i[_Qg/VGX)sZ|Rr/U9^~)G랽$իe𿟾s7 +qLLV0nu2eo0mJ +endstream +endobj +189 0 obj<> +endobj +192 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +191 0 obj<> +endobj +180 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +195 0 obj <>stream +HWَ8}W1 dqRK$3hTLգTR/)RycK]9n(Y>xmw/^qO>ȋX=}{m7~,'h'I@y*!j\m 50 Y~~kZox< Ʒ챨hj +&cIS 'B7+nݑx&vG/yc10WPzjƱn%sx$&^i)VY1PƜ= &1yؾ}n +^SXf}ؼ}ed_n>¥Pi8 +*C5P(^~A<2{Ӈ~UR6cǏ*ʬ@9??I:?Q5QϢӗp DٴPM˕>Íź&EY֢szЇ ԗ;5s\zØρ:r?MT)b`]dz(o\BZ9iV(/zs9 rNT_94*=4T?mP'mfwTص6Uq,,8˹nQ깪 uGTl%Yt*{=X'N<I04 Ap`Qt+yV*3NSho[|ԝP$ҨZ6NSP.eTw="6fJx )%r,Tl-)>NCQLE)j###X$"J;+ aD= X@PPz?cj䊑 䛦ƫ&W#яEڏ]mh11J*~ע2Ilgc{4'f4ii4csƳF-5\iIlu wXɝ{J +%/^\ D +=p>K:5VrV.^mACwJGƚ|p;V-}{QdҔ`D`3GH jh2Tyل4DyEH5Ysć_$OQ\K9췏L{ wnX>/ݙo]W\ [!H{JСA]ETU%XtxzV͍i3R.X;5蔅XjGF}\d9ݩj\ٝIMy|hKYP+Fw+:_y8Cjm{6Q@;j?' YqT>}٪^ٌ .&af5O "NcJjяY?8wQ,V w?w^2\78Q̏OpL9nf4UtJ7۸ D{>EnWHZ,f +Է(6m,Wwh3#[59Z9"Q9w]1]}g>Ҡ“aԂk +vα֩WXI˅ަa+hE*hl5fZ+ K#2+pO=3lZڟRI+?~%B.1"3%)ia=") @MAN0% &8BW7 4enSGOFf7Db{ slRs4M}y%;s} b˂W ^ +vdHm.d6pH+61ּ1CՆ:օ)U#cSKɕ Sa} +Ѹ5ٍ%7Hy7nf3 ΄mdrҝ7\oĶi9)uuek D}ͣ-q~/iF%7XTNvțc5W i*RyS@PK*$+rVwsdUD͈ɦg6ykDH0Kl7곹BaM8o\@J! : yՒVbi}{_sE2a?o˗o_WwW=p*/IO) ~_H_T~Z(q uQ0lx(!/MEx몇p@"g7xþ;5~oMl"6P`)A԰bV7QKAؾeķ:++%\T؊Hf;"6s?v FfI0_v~ ێE +b]!`v=@8*߶Zѓ|0U%O-@m/R`Gk9UObO2!p$ MR ;ez13P]dsրNxkr7Q!J*x48&Nڏ{ ˸)qME!ԱIoJB{X*9pLwa8M Kk +wm +I(M\+d4SуlGY, " yؘoHnྐྵ*H:2ʒ^sk\װkϩ_}'(P`rm/zz]5Dh^or|~~1)W rnRd$M}0^TD}3*fkce2\"葖vXGڝ T\ .U,G8]1}K cGHe s)?,!Fav GՌU[5UӄZdEN5GZބn O'&q#ӰǂE/s.V2A0vhu?퍃 +iuQ]6 +endstream +endobj +196 0 obj <>stream + hhR's@LOicS0?5qe9ޱ N^Ofa +j\y!uE./-J{V]GV?dÒW8 lq^<ԖӪcN~6q( ey%/ٚEtܚG s cMIHrmO柏3K ;^xsk?rEx<ϤI1>Y[4pAx;!jSQniP5~h&ӯ? Um8[)eY}XK:ǟ%ou!R2pmˊp40˒]ѹ1kRv03Tл Pn+#Ra[6J;6x,hy!Q]붊ٛ{M qh#ӋNlҥ|jE"/T[-~AKE F2hVwkfYP$8I?7=[AMG^dZ;.𐟐`]3" 5t9N>Q?ʐbJ`ҋ3y"db If  Gnd,KofyQw\k-lv<@pL?ޡAF}vU565u;J)-x]? f_xPڅVbيGQ7 'y~_fI\vٽqg + xyaaQ|Z$]9DڑƦT+؟o#5{hSbQ][Qm T;Km\H5V\ H4jDR>;0}',wr;Y~w) |/n- 3&Q L8{}x~%6ϟ]SJc'Tμʓjȃz7_ rnzV.t>A9zqfxMՠTxeeU.cLy$jn}qw;GVvO!CHmӞ?Ҿekf@#cb﮻O񑮓TOI=T% U-|Y +AQRtiHe}kc1-$$(!*Е]MYXlx/GM88N9Z0ezޅ ]&ԈA]&=an3GPaU$肛N[ oL V +DCm9#!&5 j2i|$cBJfZG'C2$?DCw^qu~P^T9Yϩ{Υb oRVym3?:iamc*xOZaL`q4Ik_v(TniPiơ)і9;nxR1_xsf?A tAοotaQ +3{認cNQ +gmS{NwBH +WxB;.\;*pqq@U`U?:5Rl%)#P3!9@"ocX\7WG rt *MS#˄9bVNq95/u]MQNwH,RM`t^JY.Ⱦ?wѡpw +lMw⏞,;~> XLeKБǨ$%lh[;1OeO/׀^skg%@i'\.tƪ)_`TyӉu Q)'B"<4dh=fUYa/RiH.|/^0Җާ7ݗKIGR/(Mo&l2BNm#֤H;6QRqwIOEP2̂$BjJvb`w,9BHlQH.KZ +}7CL­2Ϯ_A!.1Ef,Od:0yjUa I9T4&6X5x[.|x꫕F>}?k41;(p'3n?fYg=d֫h\G)D/,%뗏VuPwL "8%Z kMMT~ښĂ#*]&ڍXL"cY\dkߎ8@*|'Qu}eA9{ѹX&:8&TtqYQ.[?_M\k# 88+*儉d=Y#X,TE@QؐtSn?Xjb˷:k 4\ھQ+첌 c7*D{࠭3bR-5ܶ@?^E啓e8KilE̹>5;~qP54l/~c/w1^F SM1qP^+ªu-LCNLG]&磱c n]7g W!`8A~i:ߵڕo9Uæcrz +AezB,]Ӥ`=ub6ӊELV +J7mӜe70+ݔ:Qu`9ttӛF|O[du ?0hh_#"00%-pd7B6on-;>i539[{K5\)U*4uL S0iy,h(0Ha3^a u3䗋k2ıϺXS9{Y,ѧCu` Zv>\Nvd uF_C>㻎,fL)Xa R>|V +^ǎDb%( +1ZA LR-惲1fǤZl-+l`,̕d(:JUX#k="]E\@%)PpjUpgƋuEqVL]eI="0 @ d  f + ۲,sl`An? +8{hI1&t.')L&MuD=87o[9)5uXX,B[V$j:m_ ][~1,EVlMleggUTl]1>: kzKs֤ϜWgߚg[~SL$&/`Vԁ}DκtJʐ'"s1hKM~vc .;v{We^0L]<1ݹ>M:N˵ťHS"rʌōϬ"%ΰtpu{LG^Ӹ^H ĊMu[.wbGmPB5#D# x)n .-G8 os0ٸ@g|%@[aܘ}RU~xTlE Zl\rfԋd ߸VTF+HM)V3{l @ڄSd2Ӆxg2]1K)k8^P 8y7;[ +b;/_F[CK)K&[a|ܞq>,ONm +#R4FʣMpr6 3} +0vvxq_b\3r nXUW,plSUVϝMc[(9Iȝ ;}FLHe~Є60xGbiɴ=HHP8F wlV}7_:QdE)8zPyv7gN98@ҙ`v5 +rk, j1a}3wq"*/Ѯg&B>aqeAѰ YpOU{ d q/U3s:_)-ayXGq\T)U1Li5P2k^ XBuǛbg~{ET(-fT/\QS32g]/ + &?;1'Ek!COPhR涩tTY@b 0Z rT{,t?$zt$Ch1" +ڦB"25 ($Jөh{9>")hmῴy|JcJ6O7΢ц;Rj딡ڤG +brڴjEC.ٻ2̘\6lҼSi>H4^L 1rs"MluP=@59n5* jaٴ".N3_?D +J`^;40H~H;>ӡcZρXClLjЊvch +8Mwe kAa17Rbأ/s(RM`HWªaV& 7!P}v gEL}1T˵Ǹ}x鹿>OՍb + +hW&E\Uz riL: 7Xj<3!P:k1h3{|/Ϗz1d=H\-";&8LAYDMW +{P]v aqJ]iB[.q /] P5O\p8럄Λ[3b^DO\>Y/ȟ䔡[⍩'V mS3ƱUn<\ +PN \aB@ѥ+){J 1.\bk E 0׺`s=DZh&נTq +O$2M [x2D2tKlO qAz{~6zK<Ն UL #Q%c8 [ʢ~)zn{^pcX:RՃuϾ^wӐW߰'y + ,Ha*~ush>B JĞ:3q"ʒpc{LO9F@A6q+J)lȠRFT: +h7.m㝊$&DxՔa7*h1bQ-lqѹa-\Gu`v$ +h-n{D2yTw 0|7;d\fL|q~jKwDOa]vr ^_Cql 1'v D +cFI+ySL*4S&Z:; p^l5yB7<^싱:7MZW3{[MLa +𔞰v*^袳qlZف2dz*|b/W`m|q/+L=&)ӣ(_dvw6Q*#xٰ8kTA4 +Sp;l@`rh=5͔ɠ^un6fC]4P5"Sl-ej6;$L&D5U{4ه#px!1\>}ihP b\ MsA]gf=x$'O8`=mlˆcK QB9}^~5UhX, +eB~=ŁXA- ݳhy' `IۑǪV*&:B=URfk&VCd#08dI%@0lK&Y)^! גھm;+}/g;5x=d /%g +thP?5iNKVx%b nm reԬDXQz=9x: ⠑75eo]#djX9j8K +N?jƔ @ha^Ed)ַɝ`5z*'zL/>ć`bi'OI[ %$3ca)8Bncb_t =m[;SN<melJAaIo[usLZٗ6VӃWcռke>`P< _*X/0א#vtupqKξvFWjSJ +SV4=U-_4۝1rDWPU: 8OF3U8V/.1U;by6sf%/(ecSJf#3{Q/;Z27BP05G-֣'VpwAǫѵZlQTL/ +endstream +endobj +198 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +197 0 obj<> +endobj +200 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +199 0 obj<> +endobj +194 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +203 0 obj <>stream +HW]oܸ}_!)bߔ#@mu6]IPczvF4_K(R3DK{=MW.9;;]>Trwy|E J(Ňd%EQ!H!Hf",M1%j8EE +N׽bunz.n^XUѕue_X3𜸷fI,Η%7Jp]a%bImo M %!ME*?MLJˤ7؛xyv>i[ߌ)aa|qw ^2^Zin+ ΟPFЬz,z;>CvBj>1WmhK#b69эBjʭAn`~zdy~SVdӳ_oBўccc-OmBU'Br/P۲Cp0~I/c' +n1mU&iy}xx6qr!pUrB\ Z 9l'z8ʒ?n6ŠXӊLV7ǚc}Q9Ib/CgG৵!pfR 74?dNWʪ7^oTjC(Rl1if=jH- ͼIwqqYf#6Z9 anm`a1#QiGnT>hbaQG胰Mf[l6OvKAԪV} ׵bQU|uR` xpШ^?~{c#QRXxeBŏ@!,!k>_}E +}O@zț!:q;Ii_?!??+d %KepEځ3>$M p pNz3߾ё_ȦQ݇Rf)ll!suڂU4I,FA8GHqu uEXz7X\"HZ|ZU}ۇ|ܨXN,(Sp8ecD0ʹnc|V^vu7Rp~#lCh\P-])m=W3"Qơd,pdT?߯\]ySVjc5,0Qx#ɉjJI;F(N<M]R0sEZ|J:f{mGp{rzdTTW4(Qz 0fP +<ā:#։ s>rqy!Y~NN>|HX2h]_7E+%HpD]#kϖnPEsSV$F8)nۻb7wcvm ydz'X">aަq *8/ߨvWWkcBp8dL/WhOYN~e4xt33K_ZGrgcN%zWR#G(m WP41H)(K[{* ,@T/;!ERXǛ7eqcYBsy# +V6 'yBi7BH1參9m10@V9kjk_*!C綱 $?Y* +bX]Tku D&LЁ(roeN|,|07"U3,8v ^Gwj?WUGiC3J|ݶB@+s7CW_/GBc! MPbB6*vpLR>DD5vJQ<٢'52{juwF + sYIc.%]tW/Sڝ7R8M d7Q&J@ٰE%h&Yg:z"b += HXӃ$`Dac4(M~+1RkpH]x)6xZ4޵ lYdl&^AB,\iM}֓)qR1)- ykW6/c}O?\5JS?B[mk;7y/YΚRYNX:^mמoɚHon鳃Dt:I;]P⫐vL!LA4t\rs'/3iQoLϣnZkK؂tvj.|3Rs!? uH( +}/ 7@b"d +P>w RD -Tn).q4w)XF)d^׋mapx~yNZ[IʸTՎ$ eQI NA-!r /xc=cTGTu:9H8\fJn}.7q?N]g]5L&[';>|z 7ɩcC+Je=EMfjmkh9xs +OoznT +%]L_W cW=!CH%3/D\#w.R3i0nF??!yM"@Ql{p^zX7C?.zd~kv=^OYw16t|72ϟ6S# +endstream +endobj +204 0 obj <>stream +m#(eM&N 2sw"iO@Z 544fyhC쉬6 ekw{&9e.!tgqHRJPAXNS|øg%OW=XA{ubF,Hucx> AP3% >/9cxNLB-tbʢxK ZNWR+v蝡6pptOo8WA^Mt#G&la[.hg?Jf12?-A[*[(֬BW ]p'(4;L̦P7 Zar&Wؓ"Ŵ"M^s;p =I#*=z~K~oe#K ݒTX}~>XI˶B,(Ŗ"jlXV'@Eo`~G{rI2Lv]|* tqkLTE$Z@E5JC:}[^@M4⬎,,xv숙^hh\S֑Q$$!06k +Ė/S*7?j*7b(ߣ Iu ^?Qע*=XAPp7>x(e@XȰ@Hu8> +k%X))5 .ӻu f@؎ݠOF{pӶ2̈́i Dn[gb}5dQBl]0p~ȟq3YMx(9=r&mK.aȚᮣ!)Cӈkl3h,O_Ѯ)" ȫ<%F?2{ApSePS#IǦwZ}zFt]i 0kvVQ}f<&N{A6YU>f2lCz=j" +V;zٍNl-`ht=Аpl=IhߘJes*EQjt;JV\.Ȫÿ0Mq}V/e}z7 +oa ?֢'7w JNrʡXFXEomPh|l_ׄJ墣qON$P63~[+Q}X)=2GY4EvP6'*tv~ftk0QyNPxI +M~kV5"EL{R?1 L}p( Ipߝ ey~hWNP#.X9B[R ~,.`T+Xy{oydt:SAdm_zmagG]ɦΘG \zj()sCWres)߯nЂA| Gz5103mXمX8mGe7eSބFe>ީnb4u]cضMP@GT_]Ѐ^"unlFC126 ~f8b{dDX*[rc 0OqqɌvpLgqR&2O.AV,xS5ݙ^7zC7/Ɠ~oOG5b^ LQT1V{_m3]֚v,']oi..Hl` WCR.U᥵>UV>Ҕ$l+!H9y6ij g"PM-Z<஽2$CP4?fz ^)Z-rio@y;02Q ^ͯg^w֖?BGqpL%-.]ψI[1@WY +$+{3ZP)ۧ U^t#3Pźq!c su' +tI,ACpa5[[wt(~Aj{"ڤmnY8ͶRe/%:yR=DI_dz9ah0-1òFӘ_Go~\ +بR]H#G;R֗+j=$#xr088v2)&ܿjnpߢ;xW"0Y;)"6}3 "DZ-jCs11}=/&+/r\J#.U#(]Tu .f{(BIV䞋GM(,>&KЯ]aV=9c+4ߡ]:e}*`QgP#LP&rG@Oqcsa4&o 85'/:ˤoc\wN_VE +H1/9=Sq03ess*_v&C`&v5{F AD9="lX;,ܦZ$dkIKm(8葮]zscQo^.NIF^GQMη/x/!^߷21t<ſw}`b>,$oʒ!"oe#QH"T@Noy+ڌ/XBQ~] #Y^|Gwd)" +adT.u_!sHN^k|DW7gBQyf_e +=Obu0= )e@{p>͐w D'rq#GUMɒ =u nO{^NxbtUzp<59oioMð*T$b~wrcM# +<8O3! Agʍ LeAQ lH "mFb8/362fkꃢ$ ٨5ujXzGg?Bfwa{QJJM +7ӡkUqQJhM'B1 U rW]@dY8PGu,&E=,MQc[KCEo7+]SwiAo>tI?Bi X)mr ȃ"е,F`_xܰݪۂ!߀{F芤Zv:%oFH]дu֖ImQsvYH$p45m3$| + S*DgRt,#dF!)ߍס-D}5:9sd+ЈJ: hGEWH)$`3G.`V3xv6\d֏ݣЏ,t=hÜ %w9:WD|F|Y\wyҲOkLnoܭ3[ 2۞v Q ֖gV%4B?'Nfuj=ǀǿ "[Wa&vЅVyRtw'q/j$.NHP=Y1ٶ>PG@a͆:I0l AĞݡȽ,BA$qPȅw5;cS_TըYJ|j}B2^]lZ P !.3 ءx;89JS6 䵀Țċ[Rx(βK z<ִp8Rkӊꕎ Y, bk~4NLn#jǾWPJ+ܰT@zRø9˒_gX\IEқGj|b drhW/F3YGv{0Djf2CZSN4)n9<9JO̫W&SsÍJ sG d@ +a%#'B"!1Ì8lR4w\8Q8p)q@yƝ+b%kj46"{zm)9`ǒ빮hXw/mRQ|o7t<]ҾG ҉7{2[jsZ'އIye}EV`h}aE_0p%BVsl|ahhYrA {zJ M8GX, +y'7YܕDX33Sa64ױm]!zφ;,n]Qj8TDu6 +e,4l=8J4_yҞ{-ʆ?#W +{H%0}, +:wFČ!-0pvdw5t|^!Wz +S}z%q)YŦ/$k10 @   QqoMI킄`*nu#OI@=D3:o_Wҡ0zWJJhta˺/<1f_y`:9zRmۦR$viib%},T^-l~¤fd * ¼TjP<J$/sO꼓}fv֔nbNCkX&"ré wzhDҴ (y"= +qfqsc^lf>9mh+E}@Ք\"bLQsP^*;\҆( zvsK=1?%.Yhsv#g2tʏAH g܇{Ul]_kߊ9 [ {, ÀȰYOPn;lSgIL'u)Μ +.-@glZ谙^mϞ?CԤN`)~nME/< +t{A:] `0_W^ţ 11cT:P,l׽4pqۋ,~e9$nЀXI!/} |}WSoA(18o(@7gRuXXg"ѮkC>|ҥ1ڐhJ;A]Q4Ovid H-vW_C.8O zJzH:L@l`lN u+#Y6,qKdS y;z4+!a5!I{bƕS7…<)!]C#(+Ƅ/鉲L+u1#e1hfw=ܯxO'8BW%[VrFIzdhP]c i0FԻo.JxE= 8׿B/8l}#]t%c볋YbguiBˬu4ҾQjSJ=(nZc^PB<d:ZZ0۬|/V qo3|n.(̯rP .ēXǃmh@A}k$t.5,z낃= snb PqNUʫ`ȏ XfF 7 Α\L3[XKIL&%|PC3_7)i1P`"i﹋PBCЦ(`ZJ3UWn~+c;WcYȸh>2y9xi\ٰ~.]{^$rꊷr{YRy}k z3hӉO 90/NCnu :#ߕ +LO<ξ$Wƒj0U3O\/i?XsuqvȧtlBhEshyI]='Ch2 5;~wQc%>B+La.syc 93,v]\ޤ5e>rF^_QS> V;j9{a&KnCTA|< I'y&(嘶No̷kL܍e{|!󤡸Vdm`m1owHu$5Ӹ9$a*5ߍC)WBMa .LJUՌKf0 LW^Gƥ2h±=!<=[t/ɷȸ=`!f\`ߊXx̄BN*ϸR6Ҵ!/ t4ϣúGӪi +N|ו&qQ($[R lK@݅b ]e:#VJj22?m/ +cPG (Z[4\ҪiyU_u R֨ x*ͮH dW7R1O5TsX7gf +\ƾE6mZ zvyU#g +r8AZJoʗ_3_66埨HN4#lj%QmUY0o#1kqȠdE]bΗF.I@!3Ũdڤ/x*}9|pϱd̊~m+oFX5RxL!v-T]蔬N_'+~TG6]"&h[X-9>̄}K_BsJ2x!H-.ǁ]ـ; +>OMSI n~E(#sockj~'S}kBt)[?d<Ķ L /RʻMGO%bՅ̏Rz<PÐj rހ!_71v AjLGwr}x 9MD`qIG 0(}Dt9ؓL:./wjQVENm@N4Ga.'^DNTc#9|!CiO8cin0in׹,ukwOvmй'XV'QU`S鉫0HbA "CQ xɂ|kjk0'aD$tN,h:(2.t0II`.ICtAҒm,uӲV jԝOk݂_3h] ޘ []r3bR \GsrwbI"Зڳ  ezPv^m TK{PӕI<'6ͫhv3J8wz0+ 5j8 )gdDk^EV.=-UYՐ)$?*6QdMhN Z*3uIҳQZ?,ɷz"ͺCdW2@"+bVȕޣddpVg(}RjfhE@oCD}`8wCZ'J??Oa$Zw=(ToŨQ49>jD).xiZ}6V "玲uW_OBv16/7i-[:ɢ/m_מ;-U-o D{g -H}2+hnǗ/z +ɵ/926ƫM5EG*׹ˆXa%XXdqp/Ĉk>\ZR#ur6*+x8q [3&OQ$'GWI . 7$r2 Ջiv`jw];27Ŭv^dX?nۅ@PY K} CU/JCTaBk c3[+O.Ah +endstream +endobj +206 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +205 0 obj<> +endobj +208 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +207 0 obj<> +endobj +210 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +209 0 obj<> +endobj +212 0 obj <>stream +H\͎0SU>$` etEԴl" Bm9"m%wɿOCsi>L6ܧ&st}gB7ZY^osv0U?m^!OK`ߛ,68u<į+<%^c?+d__k}&ej 5CnTUMն,5,gέ޼h>@Glx&xV`KU`GS (( J> +endobj +214 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +213 0 obj<> +endobj +202 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +217 0 obj <>stream +HWے۸}WeǕVʷԺ*.;v\)Z4L(RKR> P^>}u7Tb;/_m.G!{}~(4 __zm} (bIBy"ye5$$Ocl(x׮znϽb(෻M{ T!\쫦Ѯq,K8N4W$՛nC$VQ-&C %xf!A"_PA T לI0|K8 )ys>tܤtQGAQJC#:/u,Ƿށ;WT93ك(Oy<>SLe<(W7{\Q}j1!D}i@[=mj Fi! (W~V<B6z, s`@WTk>= +nNCUWcۻS1!Lt&#:H(A6},LJ5axS<TMYTԎ!l[ Ӵ@Sq'b;FXNx$/P Ҹ(G֫Cۈ˭)a_24LR9ضT#&LFƬbg l]L{'ڻ,+ U5i4$f> iVT wLb[W$‚S30Rt>: @CS;AG ȉnqc +`EYMhxڂt)fL@+2ɌM)Dq8X[ ⬯ pCfLL7婞<󠍨c{mqf}#/vf6Ѕ$6@,ֳCPn 㩁9"g,JF{}_Y#@ v=n`-QeWTn ՞/2dl=p+ꥄ! 08gMQ8Jqf"5Q,&M &q4C:Z5v3y%.3RU[<q I(O4Zz8DØf.M,F@dju +d{psq;a'.dr>OaeNr5е(nYݿj" J_b?vb'NM3Yw|&@!zU26۶+99!Y慄FV>Nau pŭc܅m<^7wXÒb0aՅ-.f]%g4k +~>_1u y0r31&][&C~Wt!$~5$=$xc+N(y$ekYSxn?LV00dhUK%wXTRx3ӉeI*u~r$9ZVb0pW*AP-Ma'tmu3LyQ)4O5BMybl%ȱ*E%-G)m JP#GlG +vש+avh4h3v/oO;RmKsQSn 䯦s`+y`R{tqIhwT+lBvPMY255z(6Is%S$*W +uL\ (g" z`4KU:Ө[G1`/M)wh* IZWN˵HѧY-6mEhdMe.>mV]՘Tʩ_o|˥'ᶨ(Ź5O]ʮk.CzFE^ _۪~1MK޿mƄ:'i$vKx#⸣a *mBij?g?(Ē1~M,f%df+_Y H+]gyd;F`+˷F P{$(bWRU…([Lˤ#A_YE(ə3MYǺVNtW>TVO@Ey 1d-KJJc aIZv+~ďc!P UmT +8-wwvfY`{l+5n HRTW]+зot<4gn ӋptM5BaSLo=ha]6uuI#t$zITłubU!BJ_fs]g;bPpgۺk3D}>C KY _RL Sa*ȨG3ɘd!$ioTX[}f$xD *`&X㗋E<5 f,Ѹe&CUtأX]b0Ʀ-}Y/V5!Cx'ʥ_z_]'?>l^I? >1ƀ;R h ZQp E0C 0C=̅[B5pLqGef=`: +endstream +endobj +218 0 obj <>stream +UB&w''m.5 %"~ UNcJӅzF<@=ĩHȄ"֡y5rK zM>0`9,o*o9,_/Pʓ'jeQ4kR:=V [s[d7ɡ\*j sJP61+Dӯwh|O^ +@?{ܴ7^[~7h}^ gtchw8h=]hH!qϼ \ް<QK7MGw# qWIraw;K^gm~۰˜hV%'_=-eWVS,do5#2j{@I`XDQ_h48>Cjt˦r^/98#&dZ0LAVM<%L~:D"V|^xvn +I0_<BjOiY֙2NE난xڼ z)K_ޯS!]KOqg-f=4)8|Qø4ڛJs-L _T`HΝ(kW;LAֶӦ8 +aBwo:X`B9O}Ϧ%DDyq3Ɣ9{eBT1O7XYt]vc}Ċ󠀬Ic"4YP<̯>Rn__"yK;ʄ'<(ܠ2?6,Ƞ-ٻ,,1: MQqDAR'&$ԕ-1~+g+ޢ? +  dOiH$yfW~|A[{{4-Ӌ钱bE8D+_kbES*bĘhK}U݊Scy{~f<lj-5w} W:is"b{@sҹ-<`9aEuBhsѲä;*Hg> fVmd.2P4CњIȖh?HkkToiۨ#-[HR!Z G%@T +82t+,Yl@oZtz:쾸Fe Bڏ9i{4.OqF]t Pfkճ[1"r13/5Mt@ @G+c[۳'ٳP3a<02IMŤ |^6@/pU%x4@IMo)q=V%gV"}MڎMM<_vp3[QBR)a4:@oȦ}!w¥ Aͽ忶nCυrd NOT.qfRT0)N"9|?4ÇКx/EA-ʵB$`j_,;kB q[Hp "( +*'?ʜ"a.q=^S2S;z>6Iѐ1:ƪ;/It0\٦p}]iass7b]"utef5ͭ63ͬ]Ѥ1ܒ#'k__5v0"|/Rd5vCZN0 \lN%GiUoOȔ%2/?ಷM7!+Э/>}f7 w 䳶t?׽x}TɅHús7o@n qG=rGrtJJZ"b6|GsXFjhy7,*\J\[͏d}6}R86uwރiXiZO\}RbM1VIpr;1c$LRAGf1-YgUPpDuuhlܹ)<<,I- 8 o:3In43g"+Iɭ:`` +Aܤg{a=vgq/v`Xv+g:0EȄ06É?㡺DK!̄|]CSOh Y_zcfIAO֒Hl4HR̅)6=LO}TzK)EЇP!WȮ멶d;w >'2qs:t %yՍ_>ŚگX<@飐P#%+@YJސF|.%>V'h;vc[%; 8m79F1kv_LM`BsG}7JܥyBUc6]΍'+?㴃 +;=#^|S!àsڶ_F%w棔ϓr"~Ų{ eлz;2dw*ܪ`o6$v;rQLr4m7ݞã_ӯ\x/k"6wjzli6o{̆<RdߊCѐ?i7Δ*6xv Zɜ߫fC3PQ(2;=`ውe IF`;K683:WFUGԙMj doC'Cd$#O=){1=EL-&,d}:21{'u,@h7(r-#f!XEx곋+f]/[$UۘcF׵TA_P'}(@\EVPzîhTmB>M;!JNOy%N]3芯t3n).fwtM[#.hAr H(]0 Wl̈谾5u#K:ސUutgEVٹ1Io[#yCau.QO[58Դ0W\=1]r#{J2Z+; oJ􀋪LnYg7yEϏxd*e[jBy3qa o4dK#!}D%J "c{*3KG/v1JxΫ!Tԕ$Ӹ +OM6XdVxSD܎j` i[̋%Fw[DtĵkOORȚ Rz)WR!e"eWɾ"RY]-!J~<^J.a}hәXeޮڍN*q5DdczѣwkPϬFj=2mڡ[;:YMY]a h3֐w9Jil1_r$+=No31~J0GC6VmqAaiGK*x~Ξmg vD.M/hf MiGvφMuȠZ&Dxlpfğ y%BC@qZfQ،\5R5wo!~Y7L~Naޔ J%'s>Ɔn=cN i@$^x⒅V?iK,+ P?wMs|'ː& mͻҨQn)mǕR_1*._@7Eι:DԘw5o?m0 Ds7T.x<7hƑd_>IԯX|!.kMgY&Xnz(AI-MӒ)i=A:[8Po5-do]g{Ŝ:7P*~%OCQdp\|zG?Vq%4'U^WUTjYw;M-=.9V̀A X< 9%XoxŞ)8{Ӽ[`cHo6@Ehyn6Bd%Z<ڲ"V"Ym^\,as\$90]X #Xj +`5T=5kS68V(t:$ǼC۩怎-q:XJQefz;n?g6}F#gHfq)14jB_PiH<~auRzuGodef>Py ڝ]T_ + ]2%35-B 1ܲ +ϼ{+n'|h"i |̙ MdbTy,m{u(r>MM(aY֛5YC ޓ5QlʻAmYE,VG#$R< cbc8T>6+P޽C~=vdw'a'KQnv~b4UJ.<"ZNlwУ5GwwvSW .Vu㗜T:vpAIHDqp#9M\2Wvk #*x{8@:0ŵڋ2+/|Qk_m nn/?m.>}X ciZt'e6k0 6S?,+L + <]2GH5a?Zr^UH{Ėٌg +bv'QT*''xԄ67H(zwrDj~69:}X]\Wd*EpqįNbw +ŲƓ+4?bɷhCcߑf3o\C,6el< +&@_7÷Yߦ xLՉ8E莩-'}w5KdC̅X#BW$Y1t3?ͫDzD²+x4R/5,u#@轮݊iu&KȖEЛm-bD4FNIȺWd^U#(eAS=..9̲Y7ǒ1b>'ZDzϏډ73H0;1$,cGEN.reZ=%gƛ!fvlf3vAA5^yFUoU4{2ϢK;?$Jņ5n2yUQf3.xIrSom/>5FjݣW(2j` Nni +EpWK;N_gr`!@q=)'lVn\)ZdWJ".,j+-J$d5 yOtڈPQ@, +a +WH LK ,i2o0:t>$ɼNOY?w tQbݝ=2"#R0=З%^wea@#"-8 ٢YK;t$63L&?4)l1۳(6~XQd>EKVz.[FO0 @  ىϼpcnV'*^%!&֎W!4o^:rRK8`2p|@hihtR"d-UwdY1SJ?8`f?qLq Ңߩ>ZTM7vӤcyS /]ZkrawLI\Xg0;b pO.'6BSU5яNc5x 8O\#EoCVvn$X^&IA ʷ{Nd)V@bTR>EwZsm'=9FGUXQnOc c)A 5zk ilYsV!v啮,ޱAd )0f(qTI~R,;@CHp0tR:e!<-E}o)MJI[(I=,F:{P+>D!HN-ܭQҳB'.$]΁ܸ-Y~20P;"NR xPi Dl8hg͈\cް6QnralxNy;fՌm).9lt)>GTH;sM w| ,SY'T_H"fӋrR' 퐹pm7Hnp$zgi"P<:9Z4jOlXxi6O ݊ݼ2C"('o{5J#lIdž֔5$eb{6mxڴ g%C3(}k}_6+i U'@S M0iXE&躡hycA^ᑫTEȳ[n8|6*&[B;<)n|~/qF\$m")>,ؼnp^Z:09BOP(SR]c:tW!-J1IpD2^nɁ1:*sъR'UTZ! qqN )ELcf㈟\Qljc%v{5,ِw"m.A74t$DJIGLQjekzVWsK*s#ojB +ٚH&z"7+<*ܔ>haGBiTBMU*89s ݩǬ]ϠD]k eEBب#7HXǢwIڧ߶5o*LN*ӱ8b,ar,hqKLM/Z4D9\h2юQbV Fzf@V)ÂK> +ٍ+Dv'BnB!GĞ_K&e̷%Ȟ ʢn+ʏԯ?@m-#hr݌C(&LKRYR˜'G"JxexPq# 2-2EtBe`n5 +3ĵ[>%7?~ JdrZ:=St D]c4LT8F0{>5zrhhoPyN?< {!3X8KpY% a3R5ȅ~\F.EŋNWG(6NL X]oȱCcS7哰M|v_FU-r\忉s½ZnL1-6rb -&ZIgζ#8Y޳FnzfDƙXPnA,ɤ\ݟ )0iG1&TtM}`'%wspw0 NGKfRZ=h+&Aᝌc;cewWܑaN HD-EeTF;c>},,d +endstream +endobj +220 0 obj <>stream +H\͎0SU>$` etEԴl" Bm9"m%wɿOCsi>L6ܧ&st}gB7ZY^osv0U?m^!OK`ߛ,68u<į+<%^c?+d__k}&ej 5CnTUMն,5,gέ޼h>@Glx&xV`KU`GS (( J> +endobj +222 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +221 0 obj<> +endobj +224 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +223 0 obj<> +endobj +226 0 obj <>stream +H\͎0y/gTU1%Ģ3J}p (J ӫYp>ۑeߵ}84mW1.3udTCÇ/v?u_×x6T>}4ulXDZN~Y6 xdn^xZ ߪK4ɺ1/:^*ıN1Z3ۦe߭j>slDSpNJ''k6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh9\pֹJp +%qAYΦ '@Y^vPD (K"cC@Ye1ޣ  gWn$,6F"t#a{Ѝl.aQG楪[/mKK9 +\#%^~.Wp_ʁR={*/hݳDz>98\8ߦTcb2,evqJ]|C?I,OPg +endstream +endobj +225 0 obj<> +endobj +228 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +227 0 obj<> +endobj +216 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +231 0 obj <>stream +HWێ8}W1j"Nw0A쌱E&X6msbK^Iv$E;/[u9Ubo-'V6^oQ&A¢wf$% /YQwiLqv_'8yg_7\ NfI@yɲheUw۶X&vNF_]f$~9[F YFr _,`$;`?„ƽ 8 #A ͢_i9I;}A!Q'!61ºә: g;Bg?/.?^w'):y#L0EwN#Yw 3<]Gy]oOqӇOI弻cHJ?1GZv>vhyw,޴{'}$LHޞjшŌ ܜP:|Q~]4ҧW1MBFzYN U_$d0RmӄF"iG̏ǹ})= X?ݞuU m]g օǂݭr(ע?Cc}ByXI_(}8  gL[oAaj$8%\b]q/gǪHe#wXɇրS I5e %; ۫B A{CJs#0})SK"{@o9Y8l9Yu9YW!Os + P_FR{roI*kqhHaY/PGxd|Pϙa$φͩOKR}/+)dgp4E3!~ފgWّpUEuXiPw^@؃h,a Ƅ! 0x1NʉM$u Mα.h`QK5 84]f]˕MA*;8W3{D=iTo/.\'ERVFbT2ŲoD[ȃI .EY5+ir\_iDRjq>ex(@zbFd.rPTX5@;I^Y3 q|Q6YECk+J@: !M)yu(TygF? }5?@ӣr2:EF%=Ey"!H,lȠ^ +"02趉2lXq;6I*O.E-sc[)o{MYH"_uvlkjce'x[C =ox2|4("&9$S2 pږX;P=Ur,NQH.I\8$vƳ˙ng1Ybu4V\h!ێݵw Cj;R`8 Er^!SnEn`crCiHJ6rDu'jě!+"D3)h1cCBrY/QaB-.0av_}Jũh +8FoYva(:.OW>(dd{)r0RLpWt{Jt ?q9{|o=}ݻxvG"5#iu5-5˒뉈|#_)7m:s<3Z;czRdaGQ|sVcF!= If}05Zk4D{e7\uuN(;C+Oiyu9 )7y* 9d; }}=*˭kϴvCyWr-W}8>s)uד9Z7ud:\*Vݼm{%] #(u6FJ)[^p؈RR3L ~MNb;%VsD pdbE k='QV8gL_!݆Ҧ]8u[{$sW/u6A/:Iꢂha판2al% +BkE R+۝FQ͹jdedz vm!}Zd:棗&c3*W* 2jTnP[c .3Afĕf sPjIIL2Ρg!#@&W]lEC(ץYj@F8օgj$IS |,KP#@Ru楨 jS.#k3wѩ`6%]8we0٦=ˁFUrj`2^mM`NGuyfFn{zƦxͲ)'&l̳~f!30MZ7}l93o8]v4ӡQ:\miY^qm!iAƧKorkJe~ߵ[? %>ƳKlRLvAM-d07zVخj;dښPq-)CJKThV0YWoBF- (Rhġ e (d&g´g:n,dCnnsYS0)D03.v,ڛ0gSиeBE mڟCaҢƜ{g|p KMeASI$⛣ ?'s}ó˂jZP4mhSŸө74s?mRF\ק?j9$s*}=2{솣}:Z?k%_qSk)1ZQz54lk/?EWuwЅKM(fj>4|yjCQs\-ZX+yS\\we w-Fnh.#KCvFj5 m*3t@>8۰O@$k^HI3SR:bj7YO__|7|?x(jqכĿHֱUpԪH =BaX՟Q ѱ(yosgOA:}(z.j P4i߉.ܹ=[Mf3Cpuh/;X#l7P]TБ8Y] Wa9]!Ns4dL%})t5BT_ sl;|#r3Y;ϸc`==B[r@ݟE1)KwvEٸ񆵙BY{doثRx(k#˩J^):aggPElT\t Zt=wudg&2g:@Z!I}uEVQҵ[OeۼWHl'wKvEi6apoZ?uӋ,J@P&=T0OBOW){^)d\4upcmfhϟ~CXDh>nip-lf]gqlSkuxmj-U7¶!کb'+5=*9BX,{_ޔj$Y>zM];Qr: \eɦj]LX5>t/q) ٲ:;/H@GϡjiFl&+]XL"M-YQ`.PR+3(}] QhDͳe7:,R0# +0X-N݄jwddRd!.׺YzQi[VY=z˛Z/ѣl*iJ*jZvJXQCz9!fÖ! +b>0 +YѢR3nvSiUw:5c.(!^̐mx XVcM~\(GUotحB%S i qA٦vM hp*&YQ·>stream +DRKxu +7(Q[\O5^юv7(t$jQ[Wx c|Ͽ[qf;<Xrx"T bs/:C1R]Æ] +C Go!Ho4,ӂ4aR_%wHTf%Q=Gm1r_>Kc%DnO]\ ֙yA搬fK8\qY= +q{ M$[iS/2[)yB8"gX/'aJ~t0^88iNIu[ -iq9.hHxb ,ocV +T +U iO[D[BUh/r9Rno_ XQe-%A7tNr 1ҁF ]CGec9(e1AniqP:Rq_]KJl^~󞷫dvaî\wm!b**԰%ݡhJ$ &ʈ '7I3MDapN#ӹ+77DpPͬEYJ"ڸHWqp}>Q\S'Ȩo&zPI@|6{?#uDH@Sea(TsVǁi;h? ;r!i,&4EC/ehէ%= q!g5sݹ4!@?OC)!}+ϩyNI=-'U:ϏS!f%(x[EXb70Q#[\ ~A-sP)a+ `ՠ{z}4ugA +`wIO #%~dh~?T;:N'YAo݇ 7WitjqV QQ1͈Fu=A7Ę;WTwdQ@_pk"~'s5xND"7]?kJ>I{j6XTeӾ뽏j{IFxgbK,霃Bٽn ]ZMlvU +wV}%*iO12S LztmtB8Tpq#2u%d* 4f( :"Tr4i{NRł!:s1 ׆25mwQ%"/XeA3.U^0nP鱀1^ή ?~2 W`٪!@KBfs+Ҙ~c3np0rAwIBh)v+4bx4dRɖ bhQ'@d5´xy:&zi;g`χO_@0a6z MT/S15@iѿU]ԴB ^c.V@ 䚥 e_ϙĤfv"Z ?*y̾K3K|= 6%3c [[iԃ]"UdH"[/<Br\t0 a1_z}[S+@BO:m=.w-\ @i_z]XǏ26yV*eߖˏ|rvK|voGp]j®ЊS?/H\z"v*:Wf}j=U]ORFSקĀ2*bߓ$- []oIAUwA%5qYV+{``*'r4PA0*mGMز6đZ+}Q9R ++ǿ=qL|>#kg% lOֆV o?6d"+8`}Cmj/}$UU Վt 'fA+*d*gEAs8 UUKvspƣwbe;7Bw?ȣm0\W1pJhMor[x+!4kZض"IZLXr"8ؒz +#p%QK=P-R=TST$tKjo &P7]xl5Z"Hsi~KP8?y g|9+I?X|T3 ?IJ7L0+U}a|N6?S[,JyKBqYL&wR4zHqi}Txdm"d +|&AsÌ'Ddhh,Tؽ1 X&|Kt,ƝRh׏0*,_P}ƣLl{9Ep2I #;L!,46 tN ]~Ĥa + |䮤Q( h+&S_\}m#IQIgGbЏå>JuUg1ȹurԊB[*4τx)WyKs_{Mk;(Dc1^#,`tyYXpWneCQ^l]+鴶:aEad'de& +4u87G x˼T cF/)ڠ6Ee-nt9{Z$ yQ7~WZ"E0*v‚dc!ejP.u: 4 V <1TM&Tn-%=LڮR#ߎ13B73 +ɦczpw~v6Fe`Wa?$:~,NsB4d<]1j{WܖGtӶSRmX0M[kD,vZߚo:55;.OxG퐭Qޗݺ&?9xv@pr$;DZYWo_G_P@}TnN"_JM4Ƈw[kނ7&7)E i:X_6-Z@xrb$G86eOSG }NfKh"u&@J2r>i.3/.nY;}r/b 8Lnf<0U>0JyG5 # 08Qq]CzW +cZ#lVNI>#JQMҩg[h#ié]ҵRNp#|Wc礻5|ϊN)26:f?t0.WSA 2 &a6#;!`Y߆IєE?x; ~)MH?6m.oP&e~GAX8r O7iR/,qn +gdkH+,]'uuLETI:ݭ}(m$!6O-&0irRztؤ Hj :A7;"5S Hpd):o!⺙J[>[Q[i\15mv^NLwwlA{TF@dMkQ/`@m|ej_+cT@+Z0 /Y ~e6a?-Dw4iQ)lPm/4;ܕ(idIEnuQ N.x(+J卡\*GPȒfNy5 FNteNՁ;|l7@V Q3T7'gq@ֺ3 .5hz&ԜF .,B4_PO+g5F7V^A*D/IݎL#"sKnH s ue +yFAYe <"yG/feD]ޢN@F \&5#?_ya=,}lШ cW~鄮r7meᄐhm"0D?(%)< +0 @ o  +(PB;;e(h #ha$ݬ ۋq1TvҶXQu ]u'5<$"u9&_D[3]5I,XAAp[nfnY=勾LdO%+Ao,in%=I\ӗ= +4AG}7 bȆ5ob>lA;kK3i!FU{=dwd>A(!x da.ih=6:š擊c4ōv(Hc*>8^k?Lnp p)[|&o!mAnNa[ɣ;5-ܺ/R?aeBhWI8A?Nai.r|Ï5}xQWOkɓ=Bg9c(TM淧}GTmj5*y}o0${Dyv@]pwtMb`YH)x $nzc!Yqd׆WmPB˗[gW~"McTF=s|ߌGb, 僈b6b{kEf;xSg}hD 5"CG/E(Tf7 Ҽq n " e4-G |Y +#ġo>a8bdK2t8Zk-Ƈ;dU, 祏z4+ \N\m?6R5ΠdNVƎN@g}$Ǩfvskg7C,Gz)3LUc57eգeouwGjx_%EePNT= {diDs} ;U?[]C{_N(%F,j@8F +c;5>A7N[rU/(VھixFؗ?O# eNcP*JF*>!>liP_y>~$Z1\(;ar-i|6|֨crl#yy.y~(>wFpZơ+ UyhUO,[]Ϭ>R)^JŔ9W? 2:-B|),*w籩dƜȲ6d**a^so+|Ÿ߯ IVKJX)~, i׭S`=҄37ME7y|$fx_'g>{|\p&(Jt/ۗconXOpj̬?dkګ KQ:3u#%=X`lF*D]2tÒAU8_UDǟR ڿ6vC +P\͟%zME, xmZ_42⒋#%;R&1LUy&_wNmh1iZqBN 9kʡ{0@4/gu m3{J0s&ʆ䋢saۈB5!#\ᔨpӃ*:ִ_+=%+!2]a7ۉ%YBWpD@3qߩo2>rT^d< C +fD@1Gǐ/fb,MB q!:Zᄈ!!@ +^ţ~&wTG\25)h-rqBR#pXg: O1Cl2nbA} %g, !A\^pW% R~n"a`~G37&2)0Ć/f̋GdqM-oxyYT2I!![7#4UM]l/9KbWc],BL}X}<LDGXGj*#" N15ٔϙf0gAy=wgb7f3^<>V k'gԞ~AmHo5D:9ڲ4] v$ >HTXe:T3\ bڻqEm'U}=mmkwC;E4pD+vzV"9혧%y@1yndR>5)hg2E}хc]tN9:>7Nfd2uo;5j6Or +Kb/!iq oJԪe~#S9Y8 Z( }u^An1ѹ[A(Xu !ls8 +Yn%;0D>:vӥ)VpX|pW/{܆⫣Yf:ތM {eڊF>ưmKpzGvaLl)C߇7V +sL`ZZ~{'N7* <ʹBS_w# q;vܮ_I,}#/!S{uby^ޕ}Ĝ9x,/+MzXFF=1 뒧z><77%λ+"\G/bV"fldh?Z1 kMeOwNOMۭ˨<#6fxn"Lq% &Q wȝXg0Ŭ(:K(SAm%EIS0x2Jkag*x,|[>,V( +OqM|Sπ"ȂɓV^ ڶs-˛ |uf8U hw#(S:09xCɉL1Ms9sŭkBuvm x: ޮ=_(Pj Ws`6_DuC^xyNۓ2>,ݵC'Ϫ^]"  +reI\x}zi(7ᒊFW {{).46n#^ݯVdQU*HqJ0,9^,m",0P'QAqƙ*sm qh|wxsA2B2@,?~>iJd2^K2g Q8_I* 2/g&T{zdy41ۈ>s8_ZGP1rT/O\Ҿ ѐ|( ȽWP硆UجH䦢u|*q2oO2#\B*0 *]SjD9:[rOkioBwBDl% +oGaӰ?Xo7$fR|hZx֊[0.3)IOm$o-Ո5h>\tpZ;Zc؎GMJ ^pTBhBT|x[(>0_ݛcV6֠CxJ'tymnObjjz8(n6VΏ2'Ԏv-Nn|:Ϩ*`'я-i[zPIt|k?+;6_?J{=H#`oU fyI0"5 +&z+wAYR:g^$A2_񀃒8& +6Qt%E*yx~:;#OTۻϬ +aZE|OlwZz䟿vQSʞiTe0/ԀJmх r 0L +3"R7}ϚH l;$4{] -drVj ;=y*J-䊫*TVli% ;'3ZxcRΗS)Crsc14 nH?olMpkLLJbrU)NJ?qs>g7OUb罜EY\_!I&d:dPΘ_/Ҏ3=$ |I cbBN Hfɇ+KH8()~?X~ECc{1|H9?J!|=M^}n #bU]F=P0vu\opg-5ހ"FK+N1(Ľ>|,=&{bWe@rCX +ؿ`:p} d`65 se8$*/miY(5æ|}'l4,I +1y{ 41ᓨ3ةRw(Sv~SqN|"Rq$* rMHtHmS@ٹ{ BgE9E*h!Fj? j=pKwGv'VVa%}߼ *X>fIնF)PdMtAzHJn`\H<2--H%xUWzX6p?r/ܣaZ6NsoVO/lZv:xUGwJw_FJ{v +wV2~m|H%vȞ +n6eX ;tX]lޘ4ql}su9Mlʤ +uM xcГvQà9Z#&ցjaFaGB/9 +endstream +endobj +234 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +233 0 obj<> +endobj +236 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +235 0 obj<> +endobj +238 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +237 0 obj<> +endobj +240 0 obj <>stream +Hln@E,I{( ("#Kcg^~)K9JrRg/u^ ղJO߹Q˅uQ8=&+ST׭:\2e +0kjH +endstream +endobj +239 0 obj<> +endobj +242 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +241 0 obj<> +endobj +230 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +245 0 obj <>stream +HWn8}W-6`˼"\`Me vk[-9d Ф9N3*4?-ə#Бm.՛1ccpwIRWM]Dizm1DuԚ'1Ms uG(?Q9zlNN2cT?h͒C K.v;n"8Eo1ORLyUp87~W#Yn }q1|ͯL]f@'(Q\cR&^ܔm ?b)ɹc !ԃKBtY`]P<2"kY)~4JE>HDCDҘZ{K;m3O7fI$95?J ,i`4~ϻr2OB"R8l#R[uy}9i8"8!7G#x|Zq` *7dly\.q 'a_4iuSS՟ñɱ5EZKȔw.e/sɀaJ4$e.)7r;<[4 ûG"~NDpW3jbH*w"")gGbМq0cB* XZ̭"/j/ۈ#""ݿaͰXX%i|EgKן:EƑ Q B m܆RFމ5}|bw(Do dt 0eaE~\WBL=0o7m;Ky +TXsh2@e(ئ]Y5O!+.x}ϊ!Xe Z< K2`hÛejg@lI0MgeW. z0URnDax؈6I9:ٝ@ީ2pk,MæO'M٨~K;5hGMkz(f"b̮NffzTrR-"o/ iʨmh Υa򿢑ǔ/0 \{F0 S81q(.L22 +d%1t.O}Uyg' dl@#wNF騳vO +cTLvU>stream +ONtK  wa_&o-tqUVBaᰢy^:ka~MU&nzX1l]3i6N-&KLm3e\y0\;-q(l$LΙrrRjǐٻ^ -mOhL@$@)cK!)3^b=7S"k_W"shVUo%'=e,&&g _ae4N0EޓGI[7{k=FZ>Ie5ؐ^>$3`+MjMpq}I|H9Uz6 +?WSw25FZD(G D/}G] q+J&[d$XrU/LPNH^`^u|jQ4Y U3CR?|C!eT,|֧}^yY✌Yz}{Hn;@,]G5ȢQ 0BKH]O/'ZfiZ1rbcCNOIFc,n*ouHD2loV.!oHh&,k$|͙ة=L%{;C]b( EلIf9]IȊ0Ǖ;  H<` ڙӱ|2dk3-$yהdW豞^_i;_' p$fjs6NY4[gĿrԑehϕX>/#-XCRjQ޹.B=mEaR@/4,GS!ޕU3:cs4k󤒵)%\d" +/O5.y +&Hb#Yϋ -=(E1X<7eMaI.%z㌄UELu*-VaNc'۾U-t9WW@c3 ^AyU9}EA[h^)<lǎ6bR<#7<3qMt'oy¹ӐŸNrɄv1  Lglf /Jup]ۜ e38~ \xwmGu)u^0BGJSCb^Idcɵ9B7B KRX931c3h YwA0Zדn}pYo9U8gr$rF |K9ǬeM -]#GHt K@^}{*͘#Z{V'N=Bz˓;4u ӆOTD(unVNC"!&cm-ONrZ1f AgYAy˧ҙy47m}%;#aNw^J::6GCA)4=hǣm 9=1&2M/ CHy|VTv,"`jkR#-TRkMŒ=%h=K4>FtHdw9VZYW.큇on 􀭀z5@? us bҷEVGcZS +novNt 50OQ 9qIt)pvfVY<Ã[э]m'{*Vٹ- +.oQ/L9rim1ՊgZJ$ 1q427n }Q4GҨ#]@4t{Qsjf?.+\:1{5_ Hl[(6OGw\Asb@o:n1"gfA܎cD6 +BԔG!ϡ/3,+ + +k=Mtxc7qh; .}Bt^+E +9Q1dȱr ^'ʡbĞD>6A5;N9_c ,8[i TZVΖ; +y1?*mw=Uܞ_?y.(sU7b74lV{{Bmfi9gr@=dHsxϩ +o}TuJU-jv+ #:6ma⢡:`oB9oUL-X>l !LOc4 ,LKv HڒlO#e.#wKm{$A:m Wj!qZ'z(wK=Y!޹ߏ™m˜/o +14Pd*VXIFHQc%i%a3W =V^ԋr*s-8ft}CƍH%%pH5?va24>Ҡ+˝I?ا +K)5-%(λ)וlT@#0A7w]A,<`$i_g>d$Dg|lWerF +puF&rHLǞIW\1eyDl(nxt6'cKnhT%:μ4%9 &,Z8|"NUY&sB3o &|w,C$"Q5 kYi>a2 {7? }[T^99zH|_޿=;M."fDU-E$5?۴%A?)lnKK_U`Gd^9}Ș̮9^䠲ͥnE*k2 SNq 2d:PfppE>ʙC3ﯦBrGTq=mQhQ:63-AݑSh ELO-)C6.@쨼yGw6S(ݨU`2J]}h~:ZY +!?ڑ]5{SN8F㣬>]zДIӺDzOmk4qlAM,?߅w |w^.yczA 5w3T.8>_!Uj-x.J59R#`9ʪ9PVvݺzxOyNʢiVzdc2`gKX4}oO<`TYRB_B2{(:bo8>:ns]h dg+jDEI[ e0 @ d : +=Y57JVˏƫӀFUt5n23%q>W*nGj0yr8f#r +cwVJ ˥b܇ HTIrőؾL24ΐTJxtᩉ#+gstwNy{h +_w2ݗ%S|#ݺLkkj]2) +RGE#vr*R"=cfd ˏ0և |d9rްs6)+"7OxV,:N45U ; +yZX X4zAvpՀ)8ī26ۦJ[84?,dx:YDqw+ڽ 6Kq7.b[;fqCEtW+!ce?dZ{kS5)"5^m#hR +W<ˬb \y.A?Kl@Ic(2vzu!:ؒ/kʃٹ" +DwU)S_'TO.u4|w4:6Sz(lWufb Yt4L[uXe_,Ǥ'sarnkˬB^^p:b܅ Ӣ{Bw羧(G1{pȌ^L) y#jI [1֯.Ց6j!ңݤ +˒֫8<Kf*^nko;|%U=#`ug=] M%eG/>*<ʧ;Ѿl/LԑfI3E-$<)t\_d |N2uΨ A'%At;d}*^4FiH^de/M.ZMHF:i"X 4'8zvP^gRZğq^o{RlRfuqH-RHZ'[s8xJL2:`~6^ f_uS6iFmBҕ؎J )*]+ M7}mhA#He) Qms+lXVm BdQS2I^9F9"V0A{ O[(ywY.J}B 6w8MQeB-)mj + $Y#M?YVs̄EuHcX'/g.^~k۵O@> ,@ muWVT20vTN4ncF\'V%-aLT-]6ls}Åxlc+[Y{n]#H])[̱lq-PCM{,j㇇HWz&HO{9Xi_1G7t6=3tbmݶH횒60,)~\r q3giڧa4DU5z& C$k|7R4Tk%AL] Z/)zEwv)uس]CIbSظQRaU>hr|72cm"B6[ը!|% 7_wRn`~Q,sjeC֟k*XY ޅpgȴw4D]_V&6vJI'$fM+.#nDo;Krܭ:/+kv|\[I. +O+ϩ0ڒuQD1 jz慩̂꺱W7(.<&2)`[,nt~cC[-W]- 4<u Ŏ ~Vp"Y)f 8/v&]Pϝ8<*cA.`~h"'~b#rq{CekK"5o͇ fa݌ oaxi}cl?.[tAwR(9D sYMjOXsll?ϼݱ bq䮸aFpvd** 6|cB)a4C-rA? 8L"!pwhi$ڧ=&F(ok$G!M\% nԅL &[(͠.٨ a2w͕~:1>+܇. tP ,qE-~ns} rxRKt'E]s_l7&'٣A x-hO­MJj{C рuxjj8of'D`|ӉGBV,w!Q*seMLTm9y'Vœ34MN[&po*/f _%æyةocH0wCFUIR>_<4ZY-gg>tTj;{; {(`g ơ,E >.8YwVU-Gai>0+d*>Em.h3|1fU\.}O +S{C- {0 +[%tұ.7N 7I8Ni/s_I Is}D1q co):!$UP),/erU{-/9m~=lmGoO-1[de6-]WεwP;w#?t IYw%{#Xp#ٸ/Z^8",^)5m PWsE Y)vT2*?i; +endstream +endobj +248 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +247 0 obj<> +endobj +250 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +249 0 obj<> +endobj +252 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +251 0 obj<> +endobj +254 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +253 0 obj<> +endobj +244 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.479004 0.0 426.479 630.0]/Rotate 0/MediaBox[0.479004 0.0 426.479 630.0]>> +endobj +257 0 obj <>stream +HWn8}Wm-.q'$N `!w˶j-mSs+ 4s.6Ŋ^m{|UXL@Z5)Rmeﻨ0dKi)˦{L*2A EUg\Y5DJ2]k8k{֎⺪!Iyǯ!q)QXІ.sŰX\;o2'14.]gҢ71 ` b]U6]4!)C4H#A,,NBFD$twv]լ++@l&0OllJY/(f]X%9 }gc] 14u`} j+.LIm˺¡ͅQI'ueW_=g/P {m2oLzLquxʭchه7MЀ"J.l}N*m*JFTM/,Fn#QiO }vsS-׭Un̊xp +'aWy[D@D\ޘ-$eʸ|z\~z`PrDᔛCٲ74,0n9\?J֨"{!Ǔ8 9h8yfݫ__qOU +hᾩ+ ]]],&XT19N2UgsWp/$ҵV6*O03{uX5Quw|A!-,őF"H:2qyrk¬]x% + \T!~_Ff'HLc:Flb<0I8F'v1Hat +ܼ4HNԦ 8*Asp@s^4m(siW1^\" Z) *),Qx߱)!HDb {7]^eaMCеy5;q;/>JmyO"5~.N0GP♉Ԅp)ܤg1Ku:K3\ $ʚzwCQOKܛ#R+n[5VLI~FC䪰Do*txʘ21I1XL=jYn@ATVBz7s6?*+ṗ#eyx)[hƥ͂q@%y5[7!욖|qsfH\0,X>[?5m'۪0`W j2Ù.pŽ;fk긫nyTdk4uiM_U#uHŽQUQV-[Ge!*K_DEc6ζʕHT=, 4dU{coۏR*ǐ1Iq c[*rC00v4f}-֙VmƐyT5zɔ^%Taִn"0 ~pbloD ebҩyVUUi ?f':lQFZP {Oٜ3NX cQ*K׍5B~&p0U.V ̠klqq_CLa2'^F|A9vZ!"s(VyȀa]k[bIxݶ>a$j#% IbF3T9'{}\Y2(h[ ݓRM gfĥ!}34c* +, :[5k'~G\e<`b wvKΣ9~M4h|u=ZC5^=7j5MrɺSo'UAYfK0 + +YTti?~.qm!:&D!IAIB'-祃 !)ZI׈P (oG܃ʃ ٢ʏg i¶~FY`p2AFKb"2}s|u\LtX=6] +,ow lHŪ]յm=G-kJg=dfo][d@PSVE+iNK:";ݜ8,1/ -a7C@U 2hS:arNwK>(h&|, e,O/k~P:V|U/eF6HZ"Sw-e񴔫eɁNEv欏Mhqx1q/m7M @^d@hQ6--񰞛ܺ9YytKRgY:(""BK_[72СpYv>,m${zh0cg,  9&t+ixx{&!9p6fG*~WϡyUl$7]'z$;)ln ՅO.&$Q߰ + kxN9Vy:+s <0a?rW{2b>F%iyS+_/9${5FO6:0x}l?^O~¢f^/vƃdcՈdA8dj +FŝE|M%^־l…f.ySIxQ,(~;&(2t)zo/Q[I <'[>S}3ҿsƿЎ+A{d?{A;\)d+E)tdd!BdE-d͠C -$D+:XcJǁixF  +@@}(}.}Hb|Y",œ% |/"wd"]qzl73·m8\ at2ܪnQy~oԖ@K)HSAq,sc' d&= !s$8ј49Th)->(K;%pʵ@kyr*Rqj\aR|= uSگ}wPhCd3"Ʃ^X no?< +endstream +endobj +258 0 obj <>stream + KiiR;#^4 OHRȽ +CZ es.g PD#0>5s? +ďJQ4 BG(ZRoE$Ife;h_u_Շ<akNhc`(7e7Ur"mZ>J\7,/3}`MVGǍ['ukNc]k +ͯ1f +CχO$'&FT4?*k {&Z/\ d߭%˴s3y_gIIG _)랣l=TCQ9f=˧;˓_oU'N(_O)ϥ!`.fTis^hjn}CCY +oa{ZU2+KѨjicǧܥ #KQ B3Rg26O|I-0Rb²9Bdx&DfP ߸#o}Y#͢ikO@[9!!̸}L\G.Ƴl|J[:E|峜 \`3-JGé$8ͤ|onX|2{('v1цL3iǪQ dbpi)AM럩5ܞbvfPH +vK}nk-Qf {>'BTKE#ui_}ϙj=9LIZ`T +MH$DvC bZcUCIL3%6ná* )I]5w:Ja[14HL +Bqٵ+gqk9}( .0L/dK]ڒ޻_UuLrz s0HYh*gV <( +=!IcP L15d9I;Z6hk9q#2YR7oϋ%_`&!K a%[NYI2+RS8pұC/[Ml [Vg< ?$ߪl,yP?ۊV47i>/i)mri_7ZݙnZ)~-?&Z! n4D/u +7C`omk%4RaC%W}`fSem7<@&SgϾ/zFf^EYDtvQB8Y6$QB`I,PLd HVΙD=[=ͺh(#1\;~k&zgh*m CzSmXч$wpbt!XxqqU牁 fbt8tC^,'/Ѐ3ߵNNr X.w *m"ދz׶H.(-N@NNaծE [ i.ѯ&Zr+ٝN g@qbeF*QH-x~2p%ڙ%.>KL_blj FAռbR 7@2osœBּ `Nr XCм>5Ff.jg |z tU2%BeHh=Xe@VI8f~g?TuVj._zO[?08BZ9XۇWE'3~vگJ Z=?uU''ײ@# Rfi}}Paő-q*Ǝ0.nYN8rM!ψJ(j񗓅h6vx[M Шk֪P]3UA~]FUxX(ro6XlI݂!f@K5URvIj8m"C+8 6جʑG/Z_}':^ +GӉM,ӡ3cq<4\϶b'nhJ<#6+1ٮd1,ѥd4_g}rƇZ2B=WNL&5CޛU7xp({S 4[8V%Wy~ɀFF@U 6.Bא,J!_X Xƭߡ;=,ءEU\[\bdL›+µK!Q#]o[q~o5*sgOl6LZ_~4Rwu~̌r8qToIjzpCJe~bY)tDlN4U`E8&;HեGҨQ*|FSoYaa#ݐt=?JT3!QsA<1Ki9 +eBu7 TZ6BAHf'MRG'c, f L):$ B 9D/=P{/Qj +CQ?cmEC@>} +&A!+ ZݖU7>jdMk~I-2v' -EjWJ;1"3r_\2]g l'Y=^q"9K$e蟭`l4|:+9F+r4\w6`i +><, +?3>㾠KkL?[\Z׿h@09;+E)Ŧ7IPa oZ9q)U,Y +KvI3~=n~OOfZ ~#T8j_P!%ooZڠB#rT}zS~+ Q@ȵ\85F6g@K` c fdk\MN3v)Y~ w?|?+l*N<4 jґt*$8-kFk}QB_l4䢛~,>5;:vOz[`0i,(n8v@^\`.Ɨ&/dr4 Uͤp\9hP ↠uL+4[ +=tWP CXHr&fb {v[EƮ"8Y_yET{l H!Yl] +0 A(2lpXy67v + Iju[W 6H? +ư]Qcc[-Brgi~ Vd%*k cH[˭wB@J0]";a۰a=CMl_2Ydq !`Q ez3zˉB/]HCfi-{-F* SߏTȭI3bYt:߁*V%#v)ilBW;IHlߡ7-wEK;IPB$>)6};:BbB&1o@NU -@Z+3&*a~ +6]DC)~ܑ%cJ^ճ<?Υ*wfB!9$C )M,egK=-fJa>E-OcXFVSp?(\[[g ?Ez}6cNX+`؛ ;! (1~"p$ֽm^v*%/iM`,]$r>EAbzlx!cX=$ ?,5g;~3_ߴu1i@6"kb <E `l2_P٘tP2kff345.c孁|}PY}6^Xnjo֮ueT$UecO@`^IqNodՐ*Rd&  ~92&Q,ߚT0kyfS^++o6Dߚ[lw~g ЅV`lk.p <5>X+I@a4ԉ_ {EqtK\[ępeb|Bk&K<޷m}絚@eKfn_Ckqŝh + %e:w9cD~\W?k$@unB+Jj(ДK!\,s +,}f=+ȏEb~W1^%JWkjKd$dGHx +5#7=}} +J2,^Iv|lq%b7A%3k 9(-UQxV;W#S@l>ռJ١f (v!d8-*H/]IPCesxgua&(?k3#ϊG\ +QcSCoJ~Q*J U<%g֊ 673×E]xĥC$F{sx^m~k[x5V +q¯ Bs ~ٰ;83 p~)lM zf4="|?ԌyYbc3E.;A7W_R]i$۳o糹UjNbt5쮌$v}A}=q> [L^'EF}r0 ͂P&AzY{i7p$5(D +G3.k4D0IĖ$׻qk!w^%\?ھM +[Cyq"K%}nMrmsqsIBns9!֨|g/.P0N0HsB^ "{i} ɋ&*p<*ȯ$Rə`a?["* +|X\R"ծۂLxD=Ko,͗N5M;z'5c4x%Y=<^#;bHjsԏZ4^| ے eE\;EN[I@O?E/O89Sp9X٦(Pႍu$-4b̚ w^ATp> +Ֆ8$#8c~ux?R&kH+F㭒aχj^)&`nZ"+@ذ )t6I c-&{M!lGQt1ă#U?Ќ5I/ILfE&#x^5ds'+:䛩M(dndj7.c(j^HY/r^MlL= pK3\ygMrȈ$xm9]D'MaF9ۂ[DZ2=`ҠPѶF +p ^7my8٣뵬n<1/]իUFV>"C3|D:.dj މc[ Y2T-+mPڥ3fx子9-K'OIQE-pj]{yJ WƶrYL@cѤ9_.Ov)Zba4BD-1SZ* $13Ul\=j(<3aX|)WxHe}%̀6:v>LA޾ g.?csB!XoI{Z{3uL? Cw^":jˬr!9^RA}AF𮩸TR5x@)R. +,8Ѽc|rRY0uX{(h8x5x~w4AΥRܒH4.!G> _iLU_9}\){jʦv28sAg"U6k|T6Ef:˒]068TJ[3Q]VjЀlX[tPRY,Y +0r|[wӁiUCTOKn<!WY,M1*:[YKPfgsSYmտ0[F#\nmT:Ц AN;\N, ]Oy#6~`"L/j>cP6Df. khT@.z:%cUS hZ'Z(! k8c6f+r CYÛ2M_Uq!-" ~(ukF28MvzVUR1Ѥ#&!AyA?\eԜU߱@X0vVai{idm? -Q}#jG1)9ǿ?Qq7Hu];p0_J[A0c9Сg:7h [wQrT:W)R^06`7>Kb+ eyB֟+Ձ^1J7D N:`A4A_!ֆ-uuo=O á-Ճ*VLR"`}{ֲHj9 BC`6!lwwi?ɇ'EP؛nT~2\vDM 8/ʘ5Vտxs\AROf)r4@C^XW2PC`Xl1pBa!+qF9R(L#I`-??G,"_[.!؋<ƴcV- *A?Ѯ*"]4ͩDdd6p5(6g6NB.z0׿;{qh^)k2u%v78ii'N|dj9 MvX#<2wbzQ? +endstream +endobj +260 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +259 0 obj<> +endobj +262 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +261 0 obj<> +endobj +264 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +263 0 obj<> +endobj +266 0 obj <>stream +Ht0E;mbaA0qHmiߗtxBbѫs{zk'piڮ㵿!c<]g6L_R Y^S컦7mKb>8z?sٷM?udnpM +OKu&[eW }CXumݙm<3|DSpNJGGk6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh{-PY(9!l(K>AYΦ '@Y^&(K"MDʒHPVỲ(Fº t#J&Fb#n$҄' ܃n$Wgs >J6/U}*~i[_Qg/VGX)sZ|Rr/U9^~)G랽$իe𿟾s7 +qLLV0nu2eo0mJ +endstream +endobj +265 0 obj<> +endobj +268 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +267 0 obj<> +endobj +256 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +271 0 obj <>stream +HW[s۸~ׯ[D\Itt|kln2Jmf)R(;C{HBl_YwVgmW.yv~:dsԜdu~|K~K4aD$w//|4BDD&8OhnDxo>anRh_Q)~_WLpB|s24ɘB7GVx2/7.}`)EAM%Q6_iB7ɼ8#'i/qH\" Uٚ0!&Au){2'Ȍ\"]m?^ջG={W^(z(Sѩ4 +gȷU{(cbduETu_hs#A:zFĮdf}4zڃf0ί^'LFSH=2ŝ89<{va0&tH_ϏWAh}3<-P]A+ -ž| ӡv嶨,q>4s]E, q+rzW\(q&u0gze;ojsllԛP1j;q` +!ۿtT@V8Mʪ:;-@mi.pN;m6S<0TMIE!4s4j^q&o>|"q08ƸXڟv_8|SOnSˤO͸.,6U}-FxdvMԆ4q6^簻oQyIT]#H7$|tg?_w'7Ӻ[9іu-m|նJ<#&jǼ?3SlLKܑ9vu%U癛EC=< OVڷ]{Zm<@ #|o1ut 7,cD.fOMM +dmW +==Sv;H;;\^slfSljfqafN}5$k2$W"T7پ 5#lRxHKdd6MUfE2iJG9",q{4#n~iJin~6u/cv/|,w +gH/%<nufXHD16APtW-N:\3's \@98hUrף-f'ϻM8Tm|y w jtdvIS$\yth/6`6V tnψꧨtni]Mnjs`-t:`Y@Tu?M*x4P淞`_5UFn.֋b!yv2ɻw:x/I`yT JtL 0gufP6㸛X6zOA5#~[<rH#׹c7!s 0r}r-:s,y?>|1hef66K{eM  Z(뇦zPICіG#K$lT/\\1|v095rz0ǘYpF!JTd^3"S 0ͭ\N vi-G5:q䶍H623Ea1nn,3\O9$Lˆ$W~x31_r}x4"\ -~c*C#k\D 'kj|y/c~\bq@ +_hӘ^p?8?I|a&M)c.{t3][PbHZY[u*:8A.V޺J5'ƗnAN|8GŠ2㢬() 4KںБc˸4IVds.tʫɐ#d3@C8Bv$- AMŤ)I%> b-b)y6TP P!Z`a_id*"օQ +k&תƅjUF#>3F)Q(Q]dj +%Tr&2i$笫hef4S jƌ]Rml66 T= /-}a,Zi1B/*-GB5rr\au<\.)qgYl5w^=NSu6']R%fKĹv]nrmR9mFmԇF"g2%0IcC-q2(}{4[n,W"r9ʿu +endstream +endobj +272 0 obj <>stream +U-ւHp-A diAҕ 3V`FNH$ \X<*RάQف]Qfwl eck{KY4Iͪ{㤕 U-oG:dC^TuFq uvVcK/Xf~Gg:X Fz]Pγ;S?5ZfB>i}e]O9kA[.v +?sҔMnX),t'M Įx'jM3o7s%كv% )wln>$honZnFRU]5V K{jlj5)yJљ)ASgFPqaUxky&K=b-uDb}V=r7zք<6`F6y{UW bus2ѲU>9gh;f<[XwL<"\HEuJeg}w<'%1q&X#)FtܲQ@Oɯ}2^Toٯ).|glLU&{}O,E3-0gYLT]s{Abӷ6r03Wh'Ÿ -UOl[:B t>qL {݀ 3NJl0!-dK¯g6%`"qAڪ<$R (  ҇_Өխw=Uo_28$A+gzq|@ހSyef)8i!? ,@A$!{;O3 +gs+´xcq۰_t^yLd:/s) P~ejNSYb@"Y,+A慠RRd@Rs">: +JLޣkfчP:#Tv}ƈa>{Eߒْ1M.*Arkg:vH4(̀fbvήQK^ֶY $ +SiJ_٘B%mX7/.Ӧ_29J.L +[)5Ew*K ^Ϣ7b.2Ίˏ^tkW~ M*"d;w)nQبwL@{g)Qir\=g;$`'/BXJ B;NiH'=O4XQqVot5mR&Ks '9pW&~霫u?_JֈtJ REiީjhYҸ(@"1uKo8SʝO&TyI|{I\[Bd˛}3L ?1]4Y5EDJ^Z1Ca 0;nxcba{GoO[(tő=lfSxR_[II:*[4a4P>jo;ߩ49993ߗ8n"1Bɭ6FsUsz(9Rx7RgG{z;y.@ ^Itv=4M8P!ԉR}O n!X"%j@c6/94V*P ;M/c:ry 'n9ꈇX$ǿ"#:Aǧ\WMe`Z@%9bmSh5Oi]bqg5yndX0<`'qef%B+F0*z= U ?E VY$%j$oY? |q 2};CKv6'l^ðM#E|K{FuuGGן()fP-^L +pdq=z +LČQs +8>l ^(r^ +_LU~\کs Cy\nqfIikG/s]Mg }{.8 av @FVV:%E)l ɸ&Xv /r/ڨ9# d/]S9B`:YLj* 㿲Mϖkfχ)8j ]&@aPMCtJÎ1H  ֤7O~lFzKR +*S./$؝+<{"ǰܚ(;h:/ kS5§WI-6㐂60s8_3X1+ٛ-pxmI d0C{|];,硘`+)$O$}.j8SݺӼcP4j&: H/sDK=sۣ8 ZFu(BGSy>mE ߽Ì%:|[f~dGMh6  +TG ʀ49Ե+]%`1kM Uʘ>;6̻YŒjmN*[_͔ ?z8?y{wqT$t N^Bt 3|!͝l*1b Җedmg z/?iG9r-2ݲ\jK_ 5EA/+wLӶ UftOvڨQbl L5BȰV{y-['DhNMy$WU_@ZKqd('#P Oe)Jtێ J`Atk+ 4OCRվ$@~|)0!'wrfㅪ\r+z.;?aA趻E6CdS%hʩsnK;USN`G^gҺC1c O^!=MNcuqM̴ +.4U=D=hgFEQ6L6{mΚ,p?Unstd/Zm76 æ;״ Kt#~Xɐ_{-̫ݵv`T+4i pߤ\eZeG*ڧ!\&(ke#x(bLDs9Tr!CI7j +ك/NoBqz̶ۭ aI!zM Cyh3TƢ,^^|E)='_[=IؕdbHL&luߐTCw%ZJ [> BApz(o],~l$Pd\"LRm%E ZwϴiT?ڼyi)2aK@X?ͨս69iPcz?~o+t'1nrLId 2`YF>Yڎ=CHkII40|BIUG0Bo¯ɀ]j2 fai6fS )IJi8d}>7C:0; +Rș"+g6v,U<)ׂcQJ˄9臾,gkӻpi'-X$J`(\/N~^i`5í-O%w |SJT yF3mӋ|%΂jNwؿP2! K mP]J描Oӫgz~J9idНO{\TYQly':̩{\wA_ؔyv869 + 7M Ux=#i )F_"(&n椊Hۍ_ njE/ql8߸2\eıZtVh>SS #}b9O$ӅK ύֶO^V9/{% Z^!5"|/60 iC\H{BAʋO]*!BG8s:oZp[:ʨK2˱r\{FJ6)cP mW)^6Eg$Ms0`T +r刄4noAlYZLI_Ȝ8VF(ⴊHLa2?_[9]Ftg]k>;-I/,urЯSYJbv6#*+f 1Q{84RD˳Lzᇧ%)wʼp0C"h{pڭcAբk4S +0wIi5d MzJMJp=֚?lj `JV&<ro&,x۩K |*.>ݰP<Ʈ=gNQJEе4j>REgF6J#@Q͗#j*Tf.qUw7p5j*;e4ex+FlmyiRwpDX#vǁTQa(2rf*ƕO &L|{?vWkvbQk6gQs|nwyLR=a&U}i~ e ylJa8T@$2~u)s@Vںc|v^ۆ{ ~{o܏:=! gM9%T=6ϫț4{C,Fh`gd66rO60D=sZef _LڵYh~5akw2+Nx3N}4 E4aZMIn.Vo)bIT}}#( KYh%쳴jI=Ra` ^D}3'/AOqnw/P QEAho)&xK ʓ 别eb ] \u uSZVAfRQ"/6&u,"bB:0W+*#\1imҤIJuie7JNЈ~U%Īs>%R_-$]H]Dh)&܍^ +[ƨܗKzǽr=a +N7QÝ`+"YՍ(-z"JX~CFwߊkCJ}<8~2v?xq}1}ݑ$Vz|Ob'")^ZA?7K-75l=c܁y55WCu$M%Y)S&M<2-hqb+E0h .AXwxuڛF,e?ࣜO{J_O%1g4Kċ&ؙh$m_p6ˋ$ KD^OPcn`+Blٖ"XoyO{Z!i1}ԹT}l>|28G'A%X)x(Xط{$:wAObtPKfl5HbjqroC>߀9t{})HH`Q9:~ +*> r`ǰah~ ~\je©* +m,A3Oͫti)\ZpNGuZNJYUvqh1p +u'@>8oE&X'I_LN3^m. ͋ m |ﺁşix <<Tbs68.̸o:m}J }xs[}EvnIcyc>▓C.:?Oh&QY =U M1IfaY!3))'78_>0왐- z90w]s?9 +#6n5҇;<]|\S22 aYP΁_3!~H?LY.hw?0\hϊmu{[c0 @   s6XhRV*sRt@;DpYrߦ2lW,__+bC.tC))p)N%W/sw 81mPF;36UiNo]~&J2^0ZNLxz˽okDUEAᙁhIzF(Cd:L,T r81lbdpps̞yaw&&`>KeɧZ#/5h͏0+ߏ[2bedookGmƜJG6Nܤ3qDw+i%5O'mt=}, Ħܿ%ƵYl*زNL9!|h^ u]x!)Q5WSU/, ,7×rY[:MV>K+)7Hjuc`v@Z#}]326Hd *wa|7 +iwwtbVKbNT>R)0R:PQ*R%~ x"#- >mQaTk!kLϼ"18spVggGcN+s,VfiCG:תLNa{ +YbȨiU!RuЂ.iz:j6C!S]k "iTw\֝U S!x~RNh5~ +;r˶ eD5[C"#znU<7³$2aeɈ cdŧiffu%&MGG+c-7a$ ycKr(6~EI;ٌ|y2JGԜRB9 li/mkǿKeq63\f |̀ֈD&>w}z=WO?#n&hgs'*3Œұ;0[Y]gakT6E#Tߓ#ՓߋcP026vӅ%F7iFkQ7хZ5!᷵ Azt\fFƜ<5+l!c¾9C9b ? ++t6t54I!-Z$X׳\iV1C`="d*py\&g͇snY1+ogʎ^L]yU۞4bR$6d![n/S0V)''+0X(z:)^@{-Z'e?U)QV~tKW*LKe[;:#' 3CfA=1|*yO*R!4Cy %G1NZD,E#aqalo:J,d[-4/y;KpO`5*7NNX2-Lxc'a.ÝEI 4-@i< eexj3_ dY{eayc4pTw\&mt$uL ڣQ an'0)s\` fˊc^lBc-.'e>Npa|OBw.š}k:263uby?/$\98F,|r]Jk LBȝᠼ@e2kiJ6֌L܋*>']dz㳮 rۈ6 tkt!ˤ.er8!_O6oC&7z*fj6o,Fqu\&%œKr}ʂueda/玬W"uwo9;ފDDLn>st"K?|ߗlLBLFBQmg1Rx89ec%J2W[#q7R/JsbH֧~- 0õ*Z1oa]d4>Ic4? 15>kmOp ф׏q[ Jԗ}YswAd"7}]|>C?!ְktrvyFP}VwK/)A?<[<wc^"cηY}A<,qzA+ OI{KjoRQuVFevZpl7S4'gc8.e9I!,q}֪Cm>J>t!sM8&W`KlBF.8' vX, XZ YܷXST3YHL mҦW "'71]1Oͫ>N8h$OD7"&h}C, Yn|N+z0 +78ɘ7_EmWIl!C 2ׁ!^MU+l%1r+Jc|䫃Os2Om՗wڨM{ @+EgQu s  UUe(D\;䝓95ƿBUv^%.nlaoa s"V5կj2*ub*OzX!Yǀ;.< DL-;>6y/L~8ha @wsZCpQlr30vF;*f'hr`Wx`4&ElPLl n` 0:cIWnyJLR8>[ ymVU!;f![EjpϜ34e>^Kv[W4ŮO>Z GC̀T״>yJ*Qm3P'۬ <ϋVl_ٹpmFfm5n zi? +endstream +endobj +274 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +273 0 obj<> +endobj +276 0 obj <>stream +Hd͎0 +gtEt'DH BUQ|wLC8ٴ]L6ܧ)>3M/p,O9^};m^_5>}.a/]h?&Y}j4+</M e, CocTUMն,?n9zx=6@S`CQI-VNP$(^VDpR FHh ڿTTTTTTTTTTTTTTTTQE!lUJ8\%'$eI<&(Kt(KeIH@Y;*%HXdn$HXЍDt#a{Ѝl.aQG楪[ܯmKk9 +\!%^~)pX_ˁZ={*˯hݳDzwnr.|S>Mi”-mS&}i. +endstream +endobj +275 0 obj<> +endobj +278 0 obj <>stream +Hl0E;mbꂲQ`NMB.}I'ĢWLk''Ӵ]㭿u4xn ΄$k5dy:||MzlY==Myڧ7qӥ}{b/cc۝}.X!`VhS|6Tu;m]3YgN^N4a#p +V +<<+&X+!(P ++PT +N + (  A*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|8(DM߳m:@ g$%lp%ae$D$, e xn$en$]HXlЍDt#a{Ѝl.aQG楪[/mKK9 +\!%^~.{I8G/@^~)GɞRN^^^rK"^ZV ;7cspp#>iڔ-vmS&}ήk +endstream +endobj +277 0 obj<> +endobj +280 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +279 0 obj<> +endobj +282 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +281 0 obj<> +endobj +284 0 obj <>stream +H\͎0y/gTU1%Ģ3J}p (J ӫYp>ۑeߵ}84mW1.3udTCÇ/v?u_×x6T>}4ulXDZN~Y6 xdn^xZ ߪK4ɺ1/:^*ıN1Z3ۦe߭j>slDSpNJ''k6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh9\pֹJp +%qAYΦ '@Y^vPD (K"cC@Ye1ޣ  gWn$,6F"t#a{Ѝl.aQG楪[/mKK9 +\#%^~.Wp_ʁR={*/hݳDz>98\8ߦTcb2,evqJ]|C?I,OPg +endstream +endobj +283 0 obj<> +endobj +286 0 obj <>stream +Ht0E;mbaA0qHmiߗtxBbѫs{zk'piڮ㵿!c<]g6L_R Y^S컦7mKb>8z?sٷM?udnpM +OKu&[eW }CXumݙm<3|DSpNJGGk6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh{-PY(9!l(K>AYΦ '@Y^&(K"MDʒHPVỲ(Fº t#J&Fb#n$҄' ܃n$Wgs >J6/U}*~i[_Qg/VGX)sZ|Rr/U9^~)G랽$իe𿟾s7 +qLLV0nu2eo0mJ +endstream +endobj +285 0 obj<> +endobj +270 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +289 0 obj <>stream +HW[o~[TN `i&H7.8(hil+ +Iq{9v_|f\s-oU᠒_&g JPˆHEׯ/.$'N!D >!L&)28YNPrYy P,OH..Sq[yZ'_Ζkb@'err<9['˛3 +N,Gl$4YOJ3=P,9M%I$gɫkb<ͥ, f8wRA\ +ŴsR,>p^c,-!lxJSGCm0*򷷿~ݽKC8~xnP18γ>&ܑ<uF ߯ԢS1 eQO2 9i9ר!ppAd2ﬧu}pW*gƗt'u'ImI lM!F_k'ƙL37mۋW \[̥>9e`102bnr`Q/BRsJ%x8ԕƥZ0Ϥ>uhϤv3J  +O'*DO+)l v.=PO@ 8,Q #>1oC7=D;SQ8D4( "\832 L7?PM)'Ӄ#8Jz2[/GGYG91>k6ƅ@ liz^[>gL-a!as5l}؉'vǦVQSl[5ڷe>j Vޖ{U {"7"mQV#$aݠ=K,KmS0_ޕնh:+>]"Q9AR0N\EeYU;r?0ʧoS?X:%&ʐV<3 +{8"x O3SGsY`fG9ΐt\)߯o<Cd|d?8dLCu@Ms::}>H=#@rVZyf7[ תB3Vh 7gc]$sW1WE/)h*Xy 1 !PwX8SB:$RO}4AԿnx~y8؎^q glG"p[`3l"(".3^+pƷ_% ɥi[>41I 37i5O)_wWcj.s[YV%6:0 Katu0'mͼm;,C4S8'61R=B; WZj㸕\|IRqr EA+)QEP]I`==[+j{ł( +zZVfՅL$t*ѱrVKNnP]dMb[b[yi]gPNlϣHV~PC l^jVkItY D7ƶ AZ15ңxND8p'NCulb/]ߜIyswRa9o4Z>: [/WRθuAv"dKȺ2S8oeT }Dsh>|n/lRN6'NYʰa {>vT?G1^\J+UA +1,ҾH۹؊N*iRoX+rmJ&+PV@s.m6l~~7rۃ&m!jXP)_h]p#Jro~XppNP@ICp5_Z8Ar&7)Ph?#a8,g{& ?[C%1=yt(4JN;o&D*iasJ D(4:@ 5,Yݴ\D3 +9DJ>ëۗC;ytUdp 6[kl ΀@"wS9Ǫ$TFibx4$8} +$ K:&٢ |-JqIoj ά2B%}+/,Y4_rf̗T~ɲJjiԼ̽ xzf̫f ,S` }?\؏ʻC,2Y㦗䚂YYl2k~Jw7U +endstream +endobj +290 0 obj <>stream +z'_&4~ VH:uT,o>җ+ ?OX")$“S\qF."3VsTvG"Qq9 IY]@uJeRMX DRD{O +Db0Qr.Pr3PMu_TZV.0/+<żu} +rGnDM4[잝pJc#'(>yZsxݓvaœ$q3t9P6I{H|qrvk#m+g0 jtA/ҋph\TFzʯK=6'o@)K4x$IX3NQ11fWs r?>Kx)it y}5grjT້D*"bzj!YmC>z P8b [VQ?|in4*$ V\q WeU'tzpa¯w,/9%w͓C45#};X؞v9llZ +BNS@nGTH:ųYA.z0D?L`agp?-{`|h gZjǵnp݊ri%D;!dQ'a/-әOp)٤:#N~+:9W:QɟSS\W-) Rno`sseIK>K`2<&WԐ*0K>1C/au%*<{1@:Ӱ՚}RI-QBKQW qou$d(/N}@ +դlEd|{r/|ݝeq`bֻ OXŸ6^LAMe9Mfȸk<]\ +QDOy;VPu9y%5/i~_zG#~&JCB".aC 0h?T/vΧIGǎ$Bzdx +ڐ@N嫙 +T]6>2`Gl,1#Zd44dG@ú::NjWf'/,v.505|ܴB<>kc_U':X ?]{ 5_qcA-|G:KsQ| +$ᩊd^9X2fB,AZ}!2r r>eT)Cvzâ`S_Gd V,jFCzTY.|Nm ^]"\L>+FOtVmѶJܾKQ 0y&K+Y5M#ep2fn$VC#`COS_5d?]eUR,n 晅XE9y Ef䘦.WUihFɱEgt@ZRIb".[k!ale`dx%C^,oC>([fueN['[nU9®_'Ԏ/o_ǂ&Cez1~5ދvY +N=UxcTbv)<+x2CQ&f}zb^RѰBִ)I+x\~W1F"ՐKsL;.11RtjΗes1ZOhXg0gC^? cL쮰Ȩ/f~[A7F =Y}ʛ qEފD̍Qh? @ABbDy!/}@E}]DKE99!: e`[E' +C* 3dAS&`$ᑇ1=Ţ5Hj4ɑlr/K=b*IjT4{_V5|DՃ\ +x17'Gzޕ8*<~UseIc'4tsȄq6-og E0wӓ uylQ;zdZ4 W?]> R.kP ) ҿX,G`h"儒Ӂ:۱ Q +kXć MxIy4&g(>ym^nӗ9?B`;NtO + fNJ +E11.i 4.Py9_z~U{#^TZ$M BQr b +ޭ:7 =GvǷË5`6dzC+%d^7"*~)(D2RJXLWrLEK`ZBC `ρ˂C6na޻x'?k"e'4 I?Ŭs-”Ot9#c7Zj8_xd\:v+\0ֳV?s X'aoG@<oy*Q?g:!i#hΠGG.R] 뻚Ee ~G#\1H P)AXOd ƒsSUnhNLNOj2>TEMTLv2lwiTϦ>)mK#U"tmMOFS8j*Me8^VY3IRsD}}*ECO':l;&؄W; WS!Y܍؉kx /^#ә|_ń(qdqƎ6N,?Y"Qz3%-R_-k,Po`\I䶰2s + +Gc6YDF.]/ČwZ |q<5\ظoCٮXXM1ܹwy/90pxIXha/ͬc +1O)skŌo!(ajt'ul4{ŝ~0f;kzQ*s$IKZTǷ/TG?2fJxs6J7r@.[4): +'^Ej*-9NWi$ 1@(#i_nE="oy0 '> A9?"*R9udɔKLD SvYZRia½h^- 6m::J$;n5 +0"lU_zWgiͭ#!At9]̚9 +h]p+xi"ܡ]^rի 3!9& 3At エÉJ\2|a@d:j>)۔޽k&qiӔd?s&1~]_0ޯlUug +B*OY0O`'[VL7nlFMlu6d 2 +:Y*#ހ g~os/[p8 ;+UѮiSf^G0L6O^( n}9U*9RQVf>RrCGȍ;W,j5^݈R| `$N&C)[ö!=#yt,m6p%E`O,X eoD(4:^#7 !b8k+ ٍf1>_NDTɅuTq$`'F&V+Rn2h? 8i!؈Dg0'UD]N&$yoXZUt0 (}}1 c,!%6+4/$Q=j -^C .TH0j|^(M +r3HJY:zAcο5Xe!oE*v]Ih7>cOLy޴4vGhl ˬC犫>sBS 'U@B"K&hߊ9fRue  jY&@f9|6ݑ9YuI%Sl7(Og 1j>G}uBBl4fmz'' ~w3OB-Lޘ'P6\|;*;rBOkǁ =W2Yt[}!h?19PY )o܆^07A"m{2F+|'IJx槌GyapNu@nح +L~]Qݵjr堆r{mR.}.K]eh$!+bNVψ<01;(81AivCZwۦ[thCB +/*&wK8&%c;v +Za n.bH<(T}2ڎWvӥLe"2 FG9C) +D췤QY+˱ zQ<搱O̪̥:ׇҖg +4ބ]6Zg!1'O +%=xc4=@ '.!HEíG&>wO:U̵#cЧd1$˲Yo_(MthRn1y7Id <6}:w3r0XG@nYqZp%gTdH@YS@)I5tqʓ +lbf3.p٢\Wm`/ۏ6#ސfL *5Cr@r[yAuU'BƯ, +T^S6M`r[o@eq׊oPRb!|=0" n8 V$ҡߴA (oyɭPwKXL#O3\^_D^pCpc%>MFgjA׷_cʭ E'j@mbyǞg[pnTVȜ07/'gԌ8ٓ$օ0:eb; M98ػTSu0,7ojN-6F؋e\b5k44Y Tk +f;Pa +endstream +endobj +292 0 obj <>stream +H\͎0y/gTU1%Ģ3J}p (J ӫYp>ۑeߵ}84mW1.3udTCÇ/v?u_×x6T>}4ulXDZN~Y6 xdn^xZ ߪK4ɺ1/:^*ıN1Z3ۦe߭j>slDSpNJ''k6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh9\pֹJp +%qAYΦ '@Y^vPD (K"cC@Ye1ޣ  gWn$,6F"t#a{Ѝl.aQG楪[/mKK9 +\#%^~.Wp_ʁR={*/hݳDz>98\8ߦTcb2,evqJ]|C?I,OPg +endstream +endobj +291 0 obj<> +endobj +294 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +293 0 obj<> +endobj +296 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +295 0 obj<> +endobj +298 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +297 0 obj<> +endobj +300 0 obj <>stream +Hd͎0 +gtEt'DH BUQ|wLC8ٴ]L6ܧ)>3M/p,O9^};m^_5>}.a/]h?&Y}j4+</M e, CocTUMն,?n9zx=6@S`CQI-VNP$(^VDpR FHh ڿTTTTTTTTTTTTTTTTQE!lUJ8\%'$eI<&(Kt(KeIH@Y;*%HXdn$HXЍDt#a{Ѝl.aQG楪[ܯmKk9 +\!%^~)pX_ˁZ={*˯hݳDzwnr.|S>Mi”-mS&}i. +endstream +endobj +299 0 obj<> +endobj +302 0 obj <>stream +Ht0E;mbaA0qHmiߗtxBbѫs{zk'piڮ㵿!c<]g6L_R Y^S컦7mKb>8z?sٷM?udnpM +OKu&[eW }CXumݙm<3|DSpNJGGk6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh{-PY(9!l(K>AYΦ '@Y^&(K"MDʒHPVỲ(Fº t#J&Fb#n$҄' ܃n$Wgs >J6/U}*~i[_Qg/VGX)sZ|Rr/U9^~)G랽$իe𿟾s7 +qLLV0nu2eo0mJ +endstream +endobj +301 0 obj<> +endobj +288 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +305 0 obj <>stream +HWn}W4T/u d=@q4 fYSMv7잉6/-vuԩS7۾>{fr,/ͩn>|hP2FD&(ʾÇ?fW__rd :W +s8n~>W~˛}_lv}ͺ9f7_]}n|.諦vPI3HFڻڇ+UՇe8[o&_8~ٺ02g4[`(<3y)' l}zCޮsic3\e\oY"y2u[*[Òk>_~q=8rDh(dI%Atnӯ_5賉䗏?NM)2Cm 3T֛zx2*M+Ø\*jc̑rxXC]/ J;os_<\[x!rJ=VM84,CԸd:ƭzlq$]B`oCyߦ฻&"=5' ՉrOܽ}=uo-cSWCJ5;p6'G<2yUJ0MOrvz:T8G(n{CkH5x1mNᣒsC*&fjQ9jF„Vݮ0G-g]qp&ϮoOZr"m;?ar)D1ұ@w8+=aFsBqMSwD)13u #CCS5:U{\kd  4)d"[.SUds#/,D)l.4['8Bj5w]>@gWͮ 2q\qVӠ* g*X}Y +PnH%1aQt^TІO Wxr[|@ %8~9u}՟(zE5ڟ ԥܽ.7/k|i5 +@~CXE4I=pش&%rټ^y="fF + +#fPɽ^?1 7/ HvSe0tx((09п |BŚjqsIL4.Y{K:Z8 ;(y EvPϴQh_ۆB̍Zt݂(H}4 2 [.)6X:<;,i]_fVc 9s)I,*P^M<)ծ؟9lOKmovv1?̋w4vPԕp4c|HSPD1)5B:{&W7"( h&5=>DWTZt4_ǾSs"l6Ɋ]W]+"q3U9P~pH*>,Bܝ]='<ҜoN6 BKx?Hf˵ٱcMZ9/[&/+*[kj: _AyOԻLX^ ApRlut@fod@M$K6$˟Eh:t^ /N{~>>vJZI[A-j:eܔKj1g@FH@{e؋M6X߱4Y7RHiYlbdO1e%?[Y[H4)*^xAXOVܽ2E{._f~Y`½lR 1MsVe^+-@ݾL:VC#6ؔ`7|7ֈƓa͖%*堼8d}olq>q ՓgavU^,mGf~؅ƵBPlۖu,mѬtu*Lo;t6`'-asTٝƾHujyW꒔/Y/yPUj!CJv0AN(--cɍoy QIN_b"|3|kkP4ھMxgN pyg=Sפ5=R]>stream +v`)?LX*f/}Ԩ˳ ('I_7ZE;݅\Tbi :VWF@'34f,0+!oN,g>#vƃ/3[`; @qr #3ڶ MɡO^kp8}~,3#(?4~'Yʹ?0#/0 ND9^(ko[ZIxÃT uvN2JaOET۠O6g(sf,E~y9RB,Ky:"Rv@@1@GM!lӣ?\NN ƮxV%:&ݪPQ$ysȋc sA6bX !lFi|koekSwY{RZߺrzJ{@zTV\Ox *lKظ.Y;UO"Ө]3a*`Ρl V(ME81C5O!͋ظZԃy4POpM>MXܾ-sr[g*/:mMTs͑Z?DyN 7%c xfs'lV`U𴭃ihkvL/0j?Fnm>ʼ À%f COI:IPkluvIpv4cF[9 +Sd7+qpdDNiK<"ZJ֑<߫oТa.:xIIn:)_c+2OhxRWzUrnř>j pEbN#Ee3lnQY1䷢ЏōQF\QNάi8BP*c|B G5ٺ]@ v?`Lsϵ'_ʳL9kۀ2OS` |}@ZLؿYouhHTsԣ+~!V^p_AiqcZ1$o@_' 54sG(D  (Xhxuəhl#C OdjŅqo Ƒ&(|aŽJdДe{.l/l3I-O nDݽc[]DG읇Ԩ +Q1@c 2.[ʴksRpLd pthT+-U`v|Av=S.pi#qMg ?QpG俢#t^_c%EYM\]x怃<3&nq$2+I~0iA1K:Awnx9&(UFvĽұނWX0yPh2F^ $@|;V+oXe?M`':%GЍmg<7n:xw1-'9'JmK27`#LSf߿ZGw5*hQ;.`\PV&.֏\`xpig z: @).N4=dCS']"ӍzNXʉ,Lel'raߌYC ce]YM;7M(J*w5pF}D3 @֨0ZRR \4jShVB$Qsb[aJxvAįq;Tc%2l|T y{P!%Tֲ$D;v]=r3]?u[=\KgA1`j;YXƄ JZ!Ǡ87Z? Vmۀ>&k +wVn#Z3B.8q5YIK) (OF"wkliy{Hz`q Q+Il\ĦW1X+ ~H?N~Q|""ޒf&6P nTt.U6L9#h +LE;_qPnv +9M[gL(q&Ǜԉ.߰OP3$ZƎXcas;mf&sWS`+Bx,X'rSj(j7 +ISEZoڊt2MYQ#H5-x^EX riɦn ! +],?uoFٕE姇- lg7HA/=ḺSCvp '8S 2IH1tfsڤo>o"GQk&W 3TbL$ЉgF0 )RT`H/nnBVڭM2_Jzm4$Ehd3 [G]6:0 tf13kz$震0B4^0yeKV83}~oxm7jnFb-L 2@eE:]焨_ͭmq+ z)c>ǵb!)zGݰг%ȗf䏤8-AŏK0bHFޟgzl=0Q5֣K}囟@qf +Mo\ JGeZӤ)tGLG` %SaYWo]9-~7 yTmEC$ Pd?ڍZhGjR]bE0q}AS 3 f%M(SݲQPyO9!u]d`s%HB ÎTףXML6Rx$dgp@bf%I0V&F}c](߭חx[&r)|"ǴӑxvO?B"|hA:^x02JPMrTq-ҽSYmD#JeuMo_ nw+v,+mSׂkəlGqd}\T+Jsq2%Q{q:N"mzbiMILPTvy`61,>6O밭dg{pdU`=/]7'W:V̰p`Q\)^ylWL!y^3^8Z 54='Z$jXBh H[GGпnϓVp:{ \R2dߍP]眃'1u]xdߙ7Ur&X%gO6[me-ĺBo͕_N~QC 7\n*(1nw=nlUojlUX22*2@rpX9Mzq쓩"{ + +aj[ +|?एPR0U Tfs1@Oj +eEEw[Ixa8^6Cȸ)"? SGG}7uQУS*֘#$_:Y2sY#-XSxӻHZ Aܢ|K#G{= :(mAE4tyRHk/)`V"K"&=>WD+VgeT#| p{ C~7oG)SX6LQ#`y%b_nZֻM9܊\>'g +Z +S#߭D0%<'ì2|@{H[~*utOHpjxeЇk`)np`~#x>)7pqD"fVz|[T 'ΠZn6yɅL@e%|#C/J~u1d wL<|~DЍ +Ǡ>֑.UU%OD S(џeQV",A FIA,`JBUKm7PEj]pCxogr0VC-D%<-Pfv;mؾ@f ޵K:z + Ԣiޞ5;)j;`C,A#wNn NnHYT. IH1Rq$1]  X^WQSaL/EEw]oz'ߦI[D-ϖ4<ky6淥\<ރ$\c\V'=MVTh=W$D>c0hdϥ^U2gHѐyuжJ#M<2M&zI3[Gˀ.#"nڗiAbQbʠoRٴGl=EFkL /JGDc?KMAw6Nqyք{6wlr @˗w@pD, Ļ^3xaj=g. +0ոg ì#nN%[pvKɋzy!\+s 3{!%uڇ4J`E^ĉ"\3|ΛiD:K|N  *_NJ>W 1|(Yoŵxd wPІ.`j^$γIn TU|#i؉o3 >4M>uST-w53a%NƝE;Ї=?po>.e&>*$0\E+y(a+QG-Vo.R_0=>eP +Y׾!@1+TH115nRE1*/BxzbC^)63#<x2;zŽ'$|M 4U*ngܤ@6g_* +Ź>éTBG1O go!!#8<;>u!`Z4~dy15b'({l>ʊYBJHyN:(&; k-Ŵ.d pHqGgOks'}SǖUxk9:@^+ήpRN}סgl1R$j&ܺɧ?ϊv'{d"Ŀ8ͮBSg `s׊40 +endstream +endobj +308 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +307 0 obj<> +endobj +310 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +309 0 obj<> +endobj +312 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +311 0 obj<> +endobj +314 0 obj <>stream +Hd͎0 +gtEt'DH BUQ|wLC8ٴ]L6ܧ)>3M/p,O9^};m^_5>}.a/]h?&Y}j4+</M e, CocTUMն,?n9zx=6@S`CQI-VNP$(^VDpR FHh ڿTTTTTTTTTTTTTTTTQE!lUJ8\%'$eI<&(Kt(KeIH@Y;*%HXdn$HXЍDt#a{Ѝl.aQG楪[ܯmKk9 +\!%^~)pX_ˁZ={*˯hݳDzwnr.|S>Mi”-mS&}i. +endstream +endobj +313 0 obj<> +endobj +316 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +315 0 obj<> +endobj +318 0 obj <>stream +Hl0E;mbꂲQ`NMB.}I'ĢWLk''Ӵ]㭿u4xn ΄$k5dy:||MzlY==Myڧ7qӥ}{b/cc۝}.X!`VhS|6Tu;m]3YgN^N4a#p +V +<<+&X+!(P ++PT +N + (  A*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|8(DM߳m:@ g$%lp%ae$D$, e xn$en$]HXlЍDt#a{Ѝl.aQG楪[/mKK9 +\!%^~.{I8G/@^~)GɞRN^^^rK"^ZV ;7cspp#>iڔ-vmS&}ήk +endstream +endobj +317 0 obj<> +endobj +304 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +321 0 obj <>stream +HW[ۺ~c +jERfS48M4(hn_ߡ-)R6җswn(wo֧ *N8OO[DAL aQݻ%%  ,h)'AQ>Qܮ N>.(i, x~,}وlqDqú=~4sn"A֫5w`[EJ.XD X!//?c,Y~WoTRZG}cYL/Ӑ@Q<;{)ecd~dvǿ|>a|sx˹ )yLC:' y>a=jS{5d(I|lb$Dqz3d/uW cOEuO DNDz;Lazhm&waBwRL^eqpo?ai;9AiMnwIE:N4{{m\`汭ʢ*βK(KRCm 0 Ƨ0ǮA+i\۝0&ٍ֚ٽrf~^LE5szBڝ60^I#6e#2Ufa*/mkiW?ߋzSKH,ĝ;'J P Mf uzQn_D5cnl3OsA6eu`({Q6rS^ݠz"6 ^Jgx U2Խqɐ%t5qfj2)AfmYx\ YȾ3&&Bb"_)H2ߵ({#x.L;≮Ng񼓲<3Iz " 5me38ԗqݸMA?݀,H_QUu?F1WrGj՛EюIpdyz=?-0A(XɟޤFTxM[F\A4 duyLG C[v][{YOϣJ0"dqUI$Qs$LMR)f9STg itFx> +y'F@‡& SFb}R58G4At^v/Bkyd7 Fc}Q b ! +㫵>cb\4i$bmT+X1^0PCj_@8lטJU'{O3pgF`Щ rצp"[6im]*!aab (עqm/랁$3KBJ5v4 J|ȝ {$,h&??'1 +#A|M3_h=fW~[K36f~4GfS8PǮsTfg乆}5` EE32ap(GN2  ׻D +E{,rǦهCSxuJ(wڏ)3%rW([ctCسTj)Axs hvZC>Nx{C0HN'”6%c~pG{Eߖ;`ZDU$+kA?V] ɷ70wYO&06PgC1!m%MFVD8Ӓfb0nhЪ:.QpTRD2p Mq8[;w ?,|Rұ+er` xö(%"]@7lˠ. 8R we +|_cY^3P_`_xS#d[e-nE#dmAͥ9Z4樑!Ŭg`Ѥga6-m 6poɎ>֓Ǣ)/@jŔ(ߛR*L-Y9O +6MH]LdL|&OD^AM"dzEGEb+H7]JXWEÓ$O}^=@׽su{{qw۫7vE +Zﹰy'~=uzy{Ak(SR~ca!8V@01=!>\PݷM3Z 0':K=J9/SS +`6YA=HKC'6Pa%(̷&1 H}o+D xQ 1 [URsK'U޵{YkR۹JFJ +O2PmXz]6R|Bp೛1QIJ{p%7Iux61ABP +^]QUlxDL' < ,spxPjsOWґ;j)e'e1k,fi +@JC~P5cH-M6C⭜) )D\f7]/p̮`e}j"CYWAau᥎+c'@sHNF!yby3),ƉfV$ǚHݼ[4V?_/84ea9;f7A\"*X昙cX!/B쯍ZmqYq6ԇ.s)EƍM-)o׼VhLMQ.yMkvz g i}q&\ {nb:錍)Do8L>O'`xݬ;6t^n{^YBhq}1ThBi%J9mLQƺ_:J5md#{xI45g F(MxZ [ ލMێMg_?humb:i&nx|a_0'+Ozzhu{{q_ }Q NAmLw?e,)8?ue6)EҔD.|-v+gDoe1 Sг+fବbDg=\쳔ۦ&>stream + '^^R;#^4 OFӹ;t2)6t;4_ FКj^*M=s&H{ ļvkM yY[j."-dS`0tZTU6l@~,*nSyӞ\;a~H&WPLK_i6]T8 +eMCW?%ߥk<aXGZq}x4|>پ_vr0eWIޝ[.q 3F‘ZuXwEQUE)) ТX\gMgeQgLʃW2C[4NiN&ckX2q*dTrw2*B,nJ;peCqy"&p=ˣz.$;']c9|H?{L8u.6=%g` +~}D25tNֳ{)}"S#=?}z^iC|oORe?\LLcsh-I?Z0ԼI9 )>#Esokz)SNoʥ()XtDzc M ofk. &6r]kVj'GL0 ?;oz ]K2,Tֿ*7$U4C~5W +zt?Oo~Pr .ݕC'K/O5$ F!ש*T@!j]w> +S\;7HXI]g&XW]~@rW9"Oh eRMs'fCQ`To(j_pQZ5ZVɊZ$`#Ȇp1/b BJ@j"g6uÝ y@1/Hˎ QcwzXx +B}Qzd[`"g9O-Mb76s/t02*2W­*C6V# 6Pvۨ<+x2no5W%-!kGΪ^*O4J2s4ᅡQ SoCcgdu$P'€n"W|r)&*_> ? 5e1⟃sg6T+aQܱ4jQ߃*Q+L^P|d@݄/ayDZ6%iʄ%q`u츖ed/?P3{"72A>V {a˖j|BÀE\d6'17Xf6]ktjM2\nAq@ #b&xMrB!WI2+W׉ h"m62ai>'4~9VsFOh:pf5wr)`-LE5c~voZoUAb?Fl'rmFr +N>eV>C+|@ul%`чĚ@ԢKȌXKI,T b8L-+[ +'9Nnԛ~-"W+fo9BW C*A5JlW2>w6cqRVСܢ6dJz epJSsG9~tGۭؒ;d1z'HH٭/pe/PSs_ӛOP%ǟ~9g02U'XV"ǬH;CT*I/˄f;36i͖os0[Ff |e{'CP wt#imY3\HE6wL'U-\JC(8ú~1gra$2,n/ 5W|=(ݽ"6%`8A^hLΔ z 5fbE 48nNP;B*.1䔇w07y0YS)^ +5 s'ksCeYdROZ !JM +igxǷzNq#]n#}wusMN&ƕiEgM'.Ha.8/w+k$MO'I4w:'B FImkBy#IUNj&! 帘keww5I-]'^՜}Fdp``H؂ _X:T]9ՆW%%2ʼn:^1lvF$; 2*zq^2f9W!= lCQ1̯*U~\#/$%mW:Qv cVlls妨 t-tLrcQ^QnDpevw[6*7a֨[7p{P&Kz;tK50 @ +  V l] 0L{RCV\Mܳa094oFAw9[ޔ :G]P'?g,7 +i"\=a[.|knPX$"SQA>Goy'EtA.TrCp}A5y: ӽ_w@/E$Òܰ7@fR,MN* 񸊬Dꪊfɳ^6my`T \92|Eozpc$._H `Tf(Y!4N1P[߁j}x[ ?d}?wŭ(J ΟV2"~v+F栦CH^Z% cMգІj;39}7&#DnIi q!'bȲ1ʴCPo} +ΞubՎ czuNfi֗#_o=ѵX*+Ln7*V ٘b70Rݱ B 8F +T@ Ȳv("]ś 6!1&NXry}٤.X.WObNи@x0kev?0ĽݩIJh䲣?yT~u;2/=wm%` Cص,ES^ "zPC19hfTu̪x\ʸ~]K,|@HMd`8.=)%g Ϥ4ZjyxՓB)& +m{Q;wpӜVm'JNӦIuZE`ފ jv%5mzH2;'ߒ-p1h%:YO/kp=ebt:MBn_R|N4 ,9@glѰ-WYֽK^OAPTiEMŀ[ ^j5vm_c6pm赟ZhMV4[+CmcAҩI +N +VL}Yz[Ȁn`ޤ1oSX,df(8Q7eXjDZ" z\yq&8qPykvB:Ke3sI{KO L m^J_h"f_đ sЫ6S" !6n L7Re$J;쎬Y lep*hyxv%6ÀHZ_P WضFXHޢ66Eij<(\g/*Tzn+H3'G |_UFH*H:FRԣR+@gW42!*ކrȂ+t"*=9fzb+>X %-5.= Sp3N۸GkX~$^`;j=(5#Jy8 ڈ &=߳HR9 ,n~3=i1Y, 4u)'K6`$'rXawdΊqv 5 TteU|hvZoWxv`xi+Wldj%Fa3!ԭR8[25ħ{W{@%K ()kyi v=8W)i9w2]:j.9nn,Sx/NNqEEK]2R-THw9/ (Y)Ⱦ 4DVB}aƵ.~5{ +4DZwխ?zl6됁vi78G=_]w4\fU[%jR"pwmT<Uxy 0∱aʳ8,G$@Z6W5YG+3Y,=&{egGM΁4tdbp;$o7 yFPo-޳Il9tWu,c5a-I4bhB+&d5Io0GÂX^!;lhQ`k Fji'Jc |2Qm`LR|[z~dxq.feQEy%#@AΣB^YWŮa'[hOl*4,a3C{Dā؟</ oWߏ8qz;&0B= |lJww[f3K[<1AIó[5oެ"N.& +CBHk_;fqĝ EIrbR'+0lq P>dT\Rу!šO`$f]|v4\0e{eWcsaw +oSU@(E{ +q.jr*u]' }@8CzfʥYU~JR'S*On˾ZBBp}zg.2E7ڋA".H,+%ཝ;<4~MuM6m02Ah#KvJ#3JL F, +~!HL7Cg46՟ecU.LlYGէ"Ʒ؂ ?XCW"oIppK/2TNB6?(C XÜ/Uɑ3@u1y: KVay 8V|>f p$;B@FuC)uӀ +>z7?%&5g;Y>5:ӈ}σ<{"n يpn-jږrwa5en )Y1kq c2Xlφ3Nk|W=^䀟.ٟk&Zo 6d0@IDoDq +5s0oX(>J`!zl ]weQM؍KLqi&/>w~.!OWq>b\~jrRc?1{@]- KE$bS坞+%'m"h5 +@xa%77o{>qSN/k=}糕H}O4bRTWSwõsz]䌴EBaWi5~% :a@F⣊\D*UjC5<}^Sq<U:cUd&X +NwW|͔"LA1_ř̩YWs䏌}cR$846_-3Xof0;' &3GLKM15]FrQ['l~Vgvo + }*MjS0dҿi]d|/cQ_CofOHr';3 H!S5Ly4}8F= *j͒?X{Xz>a]c RMX 0neyAπ3Ndc)=M`x:Z'硸U8(74%U-B[->x>}s碥o@0"$l!ӡh;GI1$LS/'(IpURt8ܟi<?ឣG+SA\=BK<K8$(w.ݪ+:WDFt3HW /|R +#:(/̘e&3r*s.N.qп3_δW9AA/ +Ao0^wO+GX8A8Rc$ׇ@Y)l}$gM|c~Iq]B{*UQP\!wF~G<(1 +4uBREus^Lَa9JL*`7&v&qJ[6;345& +Ycm"QU/f][UnV#r(l69;µ`jwHU4*$G 5Mc90oj5ٿT;-^k +LB $H|K<('2E8}I]섣֙D #0LC5 iCk?#¨$ZPҩ͸VO5hu ݒ *ҪgZ6 o n /% t㳚t~~G[XPʢuca4+@*>o]%@jlX^t3WM*~]Rx Z@9 B2ZDfelbcHayyLWѥfh[ju謚QkI6Ci^$^,b s'ԋ\~bۧx4C-' |ut2CxՊڀH;Z>m(QE4㴗I7i;1>p'}x`vgG*  'g'f۳Pd+2ی֜.1QV +B #~5B` sY~rz Ge!e-a?ډip@@(tޠĄVpB+SU_Wo嫩Uj7# b 37W|#DxcF'AV/ɇ#\\qJ?e\P8H&Tt +p"#WSh\]^N-VM8'?zxf:iqZ:KY6DeNbب +endstream +endobj +324 0 obj <>stream +H\͎0SU>$` etEԴl" Bm9"m%wɿOCsi>L6ܧ&st}gB7ZY^osv0U?m^!OK`ߛ,68u<į+<%^c?+d__k}&ej 5CnTUMն,5,gέ޼h>@Glx&xV`KU`GS (( J> +endobj +326 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +325 0 obj<> +endobj +320 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.479004 0.0 426.479 630.0]/Rotate 0/MediaBox[0.479004 0.0 426.479 630.0]>> +endobj +329 0 obj <>stream +HW]6}_ :S$4@Ql&`:8{)EQٗ&|s?ι?mWm|,_sujooW,(Jn߼y]r !DLGIFT*%"LM1VdG~k6_muzYMn O}y۲:X(TKP2u %8Yn.Pϒ +~|$&H=ɲNT +0J O`JM2U\d$R$^|XFaAGQEM"y3MLJ2 Y"`/>[vu0:X@Ҍ!1[gtFᡢ̔_M B,c] )0R3IԠ7~feSIʉ2G"]eqf2?p2󛶚m]CdKRiQ_t +]]6h=lK*YkEP.iʰr{l}1θ mUI,匘|9rS|eA`ʺd6r\RiɇQ*HTW|1k#6a&:2퇵#[TqUqCWڪ,7j졞pgy_\Z6SF&C'I$}WxwgR9`^-eXN +ta4EiX't~ Octۃ\.Ri(3fưq95P wLu|tFDžunW"h`,l[4?9,YinbS5~2e U=u|dP^TJ0ۛP(v!SX')'YHmD'jBА6jH:p 66{tfoa6SAaܛ8(jUyp[PE03bC XŜ]n.ڸUoS}v:ųҼnv2a"ċ>#ЍP=^ͮk9bk 2~2~֍~t]8;4i4lH&rv[D_/ ihYl.rz~#woAŌ7T)@t 5оB2;KAL~}x@XDjf'^G1JGDZ<:A2ך ~"](x=zQ~)9N㸾L'vn0~e>?L 7ͣB Nx8ւ'p8*{B3 +=2q_P >ɍR3j$Ee-*fhu*g$80OQ<j_ͬFU-eV|N9W0M*<jk 7 b('aT|X*&F80|톲9 e`?YFᗛ8lr>앿,Us?IV͸xq( .(?oylt#9^'/[..$SžuofVLjջb zGx +-L_10fHne^F߉^ƼdQ_98%a?FlnI$x {_b(:KXB|/D MnqB|tmD G~;}r_ױ$:axAjT\V5E@-id竸!A!~(NnNQWfMNc_ϾpuT7wHƍSO%85-ݿ"mbel o~|_W߿ۗ+&>|~#ZT8bg<׺1(Ɇև']q +y3!TF>,]Ox*⨫龄^Єg؛(!auZ㓧{ Ar0c;Cu(Ls0h2'[q'BHƬ$ߵzdqa +}w7noՒ4' ?L׻Ǿ|,(P,Jf뢹["*kFe4QPʥ3== +cX Dq%"CbHk9*iaM'T(]'ͬ H?z &-yElL%2g~@r~  9S 2Ħ )K[p$>a!.hMzF?PN=krc :6uq*Uv)']{ *3[=9T #o)?%fؖ˨%BEkCS["%w+͉ +wJ^r6h+>6M?ZtGDɓ*Y9R/uKAox$dҌ策+tvQ}vt!tE-iM\ChE7QPy43L(:~]'cNO)`V8δd l׾]hmB4&N .]k_dY54nķ(T7zWAlaX+}"o|oS @:E>stream +Tb67Xm̱ՠ)ND7e<~?ṻ5m1P$'>L "=˼tWgف/&AIު$_Xo$06>Q(' 2|t[ԉz%3Mm#]C$Wr<w%'@sm+H9v0o'A=}@۴Ig.[% OCyC$ L4nEL5bxq }UypxiUUTN=/CqcLb2d>@:Wm#fPD2}_Q߬tAl79wKeRmCN]q.1F7 ^ػӂ( |rZ 'S#9NtcAGbCI!d":{Eu;dGjlղ3?+݋PCMط>Ml=MLJLh9֫f"Ϟ +v@g0ԅ6m&(Ma+MqJʥoXkLO# 7PO1vDLр^hc!Mh@F[S/*^IvΫ}W`vޛUΰ؝xI:c~ +zӱ0%#'~kAߋ|QvP/{UQ#PSt6^Qמ˕<4iwuBH *zh\|tVb8ߧ3@j%P)4p^Jz$ڟ4VrFXl7 &ʎGC/ȜFtgn_:ͱ*AWM1Ʊe"5ZhyڢZo=#7l<\2d~icC\VMJ";"XկX-||l؂!M27Л-2ny:l>)OC`6Z0ZQ2&p)a~&ɡ]|ZZGCd)W!46Lް@\D-zw5y#%0'n?{ JO4s]jjq|1e k/` q:OMG']I,oT?ј/;⮝-lTvPܺ2@Ît7GZ؝h{U>eI>W[${e-]<|s@$x!Zs6]00de eSv4ikL +)LhD箑abG8/I + R>g0r*z=Ӷ#׶b$.F +r[s׌*^-QDd~V=gMCώgtq/SX,nguD^-D^ܭSM];!c\etw >wwvt,Vc^UT ϗuƻKRc3~qc:/fN`u-Px9PuAW^6\}f^}Tv8%$(|H#$vtP<_iv=oj$Hp(Oe#Fw"KY<;^ l;l32BQe"a=Zڜ*3b nmS@=%{@סP7<0ntox¥Fd!b7,Ҹ'cnF sI)$c)N$fPPn"FE׾uQz{PKrr"Å'?ITvE'GNT#Xp,LL542C:~^"OsSVk;^ޙ=IZOϤ܏M Xrg|0JO~)uM޳? `w9oT:<׈:,}.SH׋gT'B[~.k0b~.$Dʼn1L$7[z݅HZYa'}. G_fO!)eOޖ4gZTHs[c[T8#IuÅ1O:֯;bOb`EK~uT3b9(qauXm\>w~O=|x92_R,ـo9ΕB x([`ZlID2o\XF+87أ~yYIWݼ63YSD8(ƥ%[w<~l";q:}޻%6HD+ΡrUЅW,S?)]\1l  JΎ%nPGA,!6K'hwǸt8KR:%{2gV9{;V$ysU9lWW۟$rx{rه+DF7 fB ڮSjuE'/wfpW1F`m-욂m*t69I]:T_ӦZ A-];- ]l +a+kdGf])qDCE2)Xh2DQs(]\*:Vyoyаje׿/mFqmR +>?f# bk#+[vs#T%a&EbOn5x}& zƉfU7o T5ƣUܒ/U(1Rua[|pha_RTU#@O߅0 +>[nkJ.McA# V}^(_=>ԁ37Tg_.mdvWmS&.t0rp"g>Sɣ 4?Vü"矴;unKb^wh"SC@.ϧ` #)n!CI$XiWf0W "Ά[ؠ0[1(v=l5NtO7BXFm>F!,0Dl;2Lv= +<)P]@"6q\tܤy6@J -q"sN!7kiӘC +mT+*s{cBЁjpcR0{;mnʳH9vEתоn~uzG t0ǡ' bUu0U*w#B60 @   h`ӒjJ*c nM gi*skddqM!d'g/tZ%(kg"n`pQq1w QUc"kmi8WoȢs:xx,d$QD,ck pWw vAMd T鿒ԏkŇ!]/8.1]C:@'SVbp-yFj]6M:oE`Raa"QHiDN#b8;lg} gyEIs3j3nX<Z8vP,uA6~AR26*ck}>Ҵn=kd"mh(S"ڝj*r=O"!>ѰS1ի&{퉕Xֱ_[^'+zwDӨkZEx7d3Xy`K"=[; qjsuj0rA {2ۭТ>wXk;{pj4)1"4o=zyj;4++H fp*iC7xH䮁y,yFy#{1UQnQ qrd}d/^I9j/UK`֫;׀#B+0 BȬG5ʏG%HE +OKadgtLBN@A/kM鑅98 ӶI1^Qbo!['G^VZD}8",v;9̙A5kݸ8=&M C +CN|\G'ƊM7,q<7ЅOKIԞC!lN:N_\@ͪsԫ]؞\O[]koQc ةpg4bT?B5/n~rYJP  ))TqMt˓0l99I}<%-fu+O 6Xv@Qh"Q)J7_ +-_q($"TT8L/ +U$$8tm#/I:Cij-?ɦ<BzTg/T[o +[ )V5eRሂޏ_>]&& I +2ӉhSv,RL*}('O{AHsu#HhQbس ]]!4T" pNj5>5|Y('GV+?wk ]^0{Ӊ V롽pyoH{SK7Eݟ jൄEk#>h/`}#M8R@QgOq'ٺ9 o\EX.%!ScU'Ȓ@<ܬ"W|E#fH=]|qx;Q?Ko*, l_?,J&x˒o,XQ@?lJmG F8]h*V`M?/$]$K;7XU͉FgB=6G9>3QMX,--S84:Uz 5d.lU.TMW,l,UMF`@L~׽Q* sDf +2ax{jir72Oןj,g,?rk[rߪ&+]fQ=seaP5"x{Ti5r3)Nqo ]IWz$o?>'50ߏs4IQwLs'iL BXL X ]Ս36:GWrn!Wcŵ͞ 5> yM 6FAA#5b5. j-sxUg~s#yEh vHbFyA禖=E76~C="k+ew۾!s?yP"OHԽ:t(Sɡj y ++Zb_40Qi|ձ^^8A+[X'|WkjuhseMkM%ۨ0z*OZv+,p.IQmwks"ʆT_F' 3`[7τ4oQΩ$ +(sBp%6LjK:$eVf]I+KE%u".)$Bs>4?w轤sʈ܏Fҷԓ_yYIl&A.U*ر]]b= C7FİlxId{:dmI?"\ͤQrJSb[,`, +lx!QucGAidɘsFq.' QaXfqЛ|eHuAa|@dYs4PQ>s5/܎x0jq<@ŋϹqҤH-ej| _,WcqAWC LI}Y#cq7Ǧ>ݿL<80w1B§U\m*k2s77K˾ZxY-GC\Rޫa bs}ƃNWgJ$ݷGr քB-; OokMApt3,GTrWWZ. v3~>CK]ծ9MBGkGuA)+5{g&u؉1xM-FyY`U3w$f8+Z&ٴ_NF9@b8 0ba!M/p$یг +endstream +endobj +332 0 obj <>stream +Hl0E;mbꂲQ`NMB.}I'ĢWLk''Ӵ]㭿u4xn ΄$k5dy:||MzlY==Myڧ7qӥ}{b/cc۝}.X!`VhS|6Tu;m]3YgN^N4a#p +V +<<+&X+!(P ++PT +N + (  A*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|8(DM߳m:@ g$%lp%ae$D$, e xn$en$]HXlЍDt#a{Ѝl.aQG楪[/mKK9 +\!%^~.{I8G/@^~)GɞRN^^^rK"^ZV ;7cspp#>iڔ-vmS&}ήk +endstream +endobj +331 0 obj<> +endobj +334 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +333 0 obj<> +endobj +336 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +335 0 obj<> +endobj +338 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +337 0 obj<> +endobj +340 0 obj <>stream +Hd͎0 +gtEt'DH BUQ|wLC8ٴ]L6ܧ)>3M/p,O9^};m^_5>}.a/]h?&Y}j4+</M e, CocTUMն,?n9zx=6@S`CQI-VNP$(^VDpR FHh ڿTTTTTTTTTTTTTTTTQE!lUJ8\%'$eI<&(Kt(KeIH@Y;*%HXdn$HXЍDt#a{Ѝl.aQG楪[ܯmKk9 +\!%^~)pX_ˁZ={*˯hݳDzwnr.|S>Mi”-mS&}i. +endstream +endobj +339 0 obj<> +endobj +342 0 obj <>stream +Hln@E,I{( ("#Kcg^~)K9JrRg/u^ ղJO߹Q˅uQ8=&+ST׭:\2e +0kjH +endstream +endobj +341 0 obj<> +endobj +344 0 obj <>stream +Ht0E;mbaA0qHmiߗtxBbѫs{zk'piڮ㵿!c<]g6L_R Y^S컦7mKb>8z?sٷM?udnpM +OKu&[eW }CXumݙm<3|DSpNJGGk6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh{-PY(9!l(K>AYΦ '@Y^&(K"MDʒHPVỲ(Fº t#J&Fb#n$҄' ܃n$Wgs >J6/U}*~i[_Qg/VGX)sZ|Rr/U9^~)G랽$իe𿟾s7 +qLLV0nu2eo0mJ +endstream +endobj +343 0 obj<> +endobj +328 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[1.92041 0.0 427.92 630.0]/Rotate 0/MediaBox[1.92041 0.0 427.92 630.0]>> +endobj +347 0 obj <>stream +HWn8}W1ƺe"Drl0`vb;;{Fc>'Y~MX>{iaʝgNMɊD'A{@#ƹk(ɜ[X FC+o;+}Zj3g=u] AlL匪VP°ڮ&la+S6[e95O`&)oWAJ+F:L!iʉ ǘEdeW]yZ0m5O x=3H)IC9 +rjiIHm#@%Q@r쇪Ӣ: Wҫ\KdZn*75LO۪z!LTkrjk EHC8HMf4-$W¦s9<]TḯbB`yuM3cnNRF'虜qa +64Q]It̉L>gS5JO D bgP]3`k'*߼ W`Jz̎ 3fAn.Wzj=2,RGϘ[evQCYfkM<q|#VD12LPK)ք2hzt4Eii\w؜e}NvU3J8G9<0L$+6|2agOQ*DjlC3ȟ6R"x? b%ix@-lΔxxTn5Bc6*+n|qCE_ ltV7-86PL2Cއu-uQ$%ym`1HcW}-QPsz9Đ>=1>nCMlXoFcnfg f$lNܮ<f'Qz<A#͚pW2XAzW=1t_C t΢" &By= k<M?raP ۦ'Θe P.:a:-ѩ?{Gu2GkUdLA Lfkgy<#5 h'?};,$ +LOedW0<3f).kϹŽha Ѓ 21jql} +6@o5ƤiN JBOj;a|8&Ո=%vGt",A]9_(Ϝ$r*űGwQ@jT?OaP@Gr [g: +W^PB<ΎϤX9sv1ݳ߳Om"tdneְUvQ+NՄ )~=H'x}AB1gꘃ׆I6\K9\ B 7.$N b!55ex{Д6%yk@\`[D/yC[jy9+Bܴ[++3arsj<.?OHj=h@s(DgF? ƫ7rW bk%zfv'r)JdUd{r2flA~JkMɾ#Ofq~9Fbykowy&NYw^?a YD\;Yג*k%ӵv,Xvk)GpNuЦ_Ө;:` +q50>b7n<(X,Z uЎYWg5(سBGtMz]1/m6#S:p""vh۬X`<"4!Tm/|˟??~?Coͳ+^@ +77{}Qzɽ;JUdLԘAT桯a#28#C!8n<_}f37ͮΗʩ?9Ri?4=Z2)Jg0CHwiQkqsJ-o"`p +Ynhn= j!}S 7]G5Wz)Oa .jKQO.BX0ώI窧^Wrs. +/gDK&aVT ·w{*[>Y%em7m,[uܵ4]^-yo7I99IJQ{ȝt7KS0*Jp ̤ 9l"x]T Xzs.BV+ld7zLܫh.$0n}py4Zr%, FXXɑ юxq THA4:,4 +>_zr Hv׶B@)YxZ 5(F{txYHITjJcm.DY.oh4: s7õSυR/~8}d`nj\6Ð2Y݇-I}u=5]3鮋ɼk-s@On0¬ReFR3(sDv)9p#fh?lMMgO?ZGrshPU]fMLhJ|i+ @V[͔ SL +VZfGZCf"2Wϛ$D/K `ЙUEwD~oz7u+CS#CDX9hu&э@vܷw0 +<'YA$=WOx ZfPWw}zQ1 u"p2nmN}) +xٍ &&C0JRunwg}~Z* +\6I2J1L%-u /t@<#z:CE ?&rO!rLHnb!hSgl14 MsfbހЉ #C/ s_EH0M~=2B(HHqf^2DH9@ CФ2|NvYNG|%lLV!j|$so}aej24N>H3.I|đF.~RN۩Yros`z;`>@5| x$0O-CLbÊA7du0ﴪ~֋?,'޸}QâYl[aިnEWDS7dsl`bsv)Z%>pcT:̅>C>stream +z'\g=d 0,[wtveЬbv|gLa2:X;jrޒ4olhSUT[0,b_cXڑvyjB3}!BP3֡=JCӉ3Pi:w1\ bX-FJhPך:!zO1e#Ier_fz :A׺/uS-*wF#f޴Nyve6I y,Q"Wm]A+Xs8`nߎ-l4X/#p4F5I~|j"1{e4ًȝs;+X'#K&ie_~x., =@]hiyQMɉ\c{{D4YЧ\b"2RJC9ћtB6 e-* 3G4)_ ]qb0RwS00ĉQ Nh ˮWݍ}:}R8'yArњF:M~*95^Q>"B1 U9q+Ĵ~G>ɖ̿w =[Xx>Yy,F 8JtVwCLJWOy\m#''s3O+f2aL L%;DVQ ަ)O tN!&š;Y[ 6gNZPO^o8ℿ Ǻ^( $D[@vQorXa? +,E Ϣԑ'>uؚr)00̝GslLKfE!ӗ\ہ9޲r?ffsu|!6DM:-bI\+ WbOWR@ kt4ygoX.`[!"mO.}_T)ǨSS>wW1Rꆸ!i:EX0KgVe6)6s4/9#2|#蕟'gK/`A=qx9f(Of%qF@5%4b6$FDA1?] L~}pM&I1-4(&N/6mop@s};U[3K5[VoMfr-v +$}2΀:y|R?~4MA|'PdS~svޚbB|/H&ho4ǡx#CK5{ +[++aQIZ[]?+dž5d@t+ +""hjTкHՂ$8ԘhPj_\4S͓9תbΉgḛ̒nO\O JBhʂT57̢ʍbh,y}ڈ4f|0I߿FLl!P cuKrY IثљmP :/sA\G.+A[1(^Y֚^ODiqeFie^ գTAv[}4LyUe˲uZPX)B*D3FtvaBwܬ6.-4Mm+{0]+q¹ꔙϴztP~ADbiڙOՠ7˞6ƨ=qt|Mk{r(p/1-T(reo|4; LGi~QdhwE-Sx&j` +'NwRY ظ)NA7- wZd\WKGbGWuP:G 8:POfuEe(.l o\B\aئ7 0dF xa=[|:{MZ*s7WVTd$֟Al{51CCp5bb{2>UͭU"5cljq@:Ӿ$vd`a恪0?R8}!E^=܍2c e +o` ~#@GxdvB [H| lx0V`.{Qp"72nzg'1 2S%+pYAPs;|R?'<:y8Wԣt)A+  x: `FnG.o 焠W[%$8XD+h RfWtb.扐澸kX.{O3rč1%~2{F]*6RҮֲMY +Ǎ+ds fT(`hWI"dTT3B8C^'&D3b6=AS;9N_8B moѥ3< e7d"tNc}hyձ)Jgf*U4~hL!kK,1X8jO;oy!«_2ŭ k̨v`4D.#/ _sde[a7@%RI_s-$"RK?j*8_=UWU&v|HrOtl +C͐RC OO|.. gKWs{0sF^π0 giZs@f.r:L3;:6j$\ώW 5F> p w +"ƕ&іD%GGF6gBڢލb6#eBdoL4$@is;K=Ј7~114=9a^*iQa}3'KIN% P)y$RpBq֎ȞzI9~4s{ E N᧍X"yg{aHKSxX{_SͥuѰꕺܶ X 0|d5#ZlZuчl9o ;)Q[Bիڎ@x0=ɨ!kvgaS!=MT6C'o';VQh^/&E^?n@p}A1L%`ir4Y?2C8xyOp険G M pFOZsv۱LM@ y4q&f47.v2E4~RPO[`KIo3{` Ro;0 @   Y -ڿmVʘWyy@Z.Jjj3_l'LW/#H4MJzz:iQS +"C&T8@©G]v}C7 x,[nj +}EU#Eu dg]?׌6]l_]NtjP! +b(U)]AtK.MjfY_Td}$D˚N +&t4Yh2[P'F \PPh\?Ǒ)# r?Ok獊l =zq8”3{FoǏPz}]5U?H6ڳnMO7 '|n!=fKSec&V~keP A0> o5Oǣ}ݺR }!`hU7h `l %2xЯ8JnYEKΨc^y2|G$1!Xp:`$,=0]4V23z +mďS2j-?T`q\isx$|Uf{'ꮫg6#zTb_D͚2J_ N5 DWcE,XMlr)&b"?~|++Ҽp(lwO86m^T-e^z4hʇvbF\?or +^k EU짥/H +N~*&Q1]'v5Hx jC?Ow١Rn.t -IkcdY ŵ$]?fن6dS'¶?=kכֿ @CG!JG.g +<'Z]|ABUYC-ZS었l8SVC !QN)}iyS„j{F%)p|߼3^ joaJ0Vq@ķ6V\ic7~_=U4Ċiᱝz3#ƻX gXo|"v@PH$'IMO"{eP6;߳fxX3o*BQC\n) 1w/wz +y4hkR8JCɣpP`9 g7 6m[Qp8C{p += hz(~3Iä$\d=|j;ӪX ޞQ^d~^#kJ@#L(l5ld:'z^ʆa\fN-V ?r K%$0͙-U<TҎY6hY-4fy1W$ A_|Sӣgwx:WcsmDq襜͢]Tn8̱_ziAW +VO5ZFv>5X ۰ZqC'SVU5ĀD45+pR1TKɼ(з'G$J:&ᑝXy^e섛#7!A96,F矫-6 !m W`lHRP7ԙ&6FkVA!-"9B+#I;¨ ꉭE.OTWwVo)֞>\BkͶ}d( @].Ŗt43GfdX : [ޔ%Ji|Y?imB1Wѷ#\VvOS0KyNCHW&U>NrU XE}?>f?NqyV>Օh+}YaJ~N |çQE4'$iSIZ-0^V[<ҼS'4A7j>Oɞ`י4hMt>I + ˯Ndu 8>>O]`\3T\p>Y$jnu'*!UձO)l;}Zt%Hòl:8\Wzgϩ4rlҫK0 I涟46,|vJug;+a +Xp˷\N_V3} ǹ7?RƪmI;aE >wuO(ʭhemz&o8JnwaT1ZE -a 3.j-g{0ǿ$s3Qx7e`YW LvFQ-CRRF@Vvu"X-7tTxЃ׌: qJ_1Yu4a{h"(pz 8[/CA.[XqAmCy DE۔$ZS#Q"ԋv0_는61])l7BͫET9,+HgYp~gOj^bF/V{jrr+NM<`P VB$XlZ|Lj[.*ӥl!ɨwABEZac—6c-󆪯{uO䱗s,l`(h,ؤ#|u1>L`$Gʼna +* ]tu^D .$+o7ۣJL8T[{X+ySJХp>~7ÞܣEe[ W?SSGjXw),3e"4 !e+Ҹ/jݏ-U/kW(kO yK3JhvAd~Kng3Z^ 2/ ԴVdp4[e uw_j kY(}^.rerq_ +M{^ +"}<X׺h6QɃz=j`VǺNOX[a)/{ <۶THf?/pֿE`{qH ={BlS׮ /Aܽ5qrY`Hw8o!F64 +Km05P.4B_t?[f!YU1M.cLp|,XLCBrs/q/(ۀsH 8yN6yEy{_73 yUFAlUb߳0hoBgDCpI֏ XkR-a d׮/>X/9Srv"V?a;KK6/ Ni8&ʸ@^Jv` +sՉ$bXwٶMW2ɢ3"Swa~ojep`7y-PF9 J\jL:vźcJ|v4J/ҮTwϝJH9\!NQqP '5X`FNc!ϫT@T!|*&5#zV׺$-`~ҍ߿įT:QX%.*k`@}[wL#v`. RdP#t59丩ʬ.1; +NjF0L1E/ K̓j#5AGm{9</FsMVvsZ{K5/čBҵ/h[9.,26HdhWn7%W@p)} ~7ad]ӧ≪&k"HpMvl):LnQ.nO:[8{y*vUzq<ju=9Dn_FK(3ce)w[A%*SF\$Vc-/rmQSK1 Ĥ{㈝ԓCf4 ѾBe|'"qi~x+ +xv=yd kݤ&9b捃 0!Ġ-wZpޟu>_:]G8LMF/iZt g(c|?XH=MQWݒ[N*7CқV ,j!SEI .i> B4?IcF2K9VAn_!Sճ~mi].E§dLi{LGXF*yO)u>qb(rQWOr`XpfS+G3S -}h"\_#UƯ C?58O,LwV58PM(͓7%P8[zEp:q4{!E+}#<#"J 2ZȮYjbVb^ϕǔ[u#kvQK19ccnq>l LNuAx<"ɐڟ3A=O.^SW&uvҩsαoɝwy)kB8\ +ճ&׳58\!~5ixGB>U`b(3DunƤܞNaN=kg!0k!bTڅaTLRqrQ)!~^@mgdyCA+b6Le#/ +:yۿ,@%)ҮSW>K ۤRuG `UT{\^BNm4<1c,[ڠD =&T/fFir '& =h$8V6p,i,yŐ5Nc'xl$zĖUչyw;dLOH}mSNjJ,viwAˍO'[$hbnyEzǽL.48=ItMux+G +endstream +endobj +350 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +349 0 obj<> +endobj +352 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +351 0 obj<> +endobj +354 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +353 0 obj<> +endobj +356 0 obj <>stream +Hd͎0 +gtEt'DH BUQ|wLC8ٴ]L6ܧ)>3M/p,O9^};m^_5>}.a/]h?&Y}j4+</M e, CocTUMն,?n9zx=6@S`CQI-VNP$(^VDpR FHh ڿTTTTTTTTTTTTTTTTQE!lUJ8\%'$eI<&(Kt(KeIH@Y;*%HXdn$HXЍDt#a{Ѝl.aQG楪[ܯmKk9 +\!%^~)pX_ˁZ={*˯hݳDzwnr.|S>Mi”-mS&}i. +endstream +endobj +355 0 obj<> +endobj +358 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +357 0 obj<> +endobj +346 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +361 0 obj <>stream +H|Wkoܸ_o͢,>$Q`qͮLQh444~D^R/m}s~e5F]m^N2GҝÇ9DIieFutpx9OXg"MhT/>cwϋϰʽ8AoW]}ct-5DiDLx)Dutasq!M"m`qD!"ψE~ENG?qŠ鞘'Imo(_6/n6+Y̱F)d?,G:|/8!_^FP0#cJ4-3Y ݟ8H RƉP.dU4,< +z'\d1MrA9 ]U#sH8O2s@=ve𣷷_*||97w8 IdfPe_7/曜9~*RMЋcPKFc$1QQȾy%&Ӧ!u;L 1Ź$y~H,ܭ[#(cLuuБf u.ыLnZRcC iMq(KeYt7Ǹϡf@áb{'r\v^%]4y<+Ȃfs2bs&˝>nn*{JP-0sQ{/_UN~9,GT!0 ),zzI}PK,[9 +Rڝ^MX UC"",q*M [? F,>&FadP!ߚ>D TbyDoiZ 'L1!d%N »+qT@AlyF}<5^>c]C#2]ΈiN/wJ0ej1̀O:npx ?!yh%[M4VvN/P Z#Z+Os_ǮE#ks[+xr5]JL 9)4&8 NYz +YjAr[7 RzCW=f몉xAMNC1, \mټ =|'p^ZUI.%e(Ir9cGt'0+<h6["Vӣ%ݽ m "T2tp+aj Ԇ|A, oߒpe2dYL>e[z@w &S~gjW!K9ƅzUw΁ ABvAekGӾnъ5**b ۪>5l~V=BVFd->\<5 ݋#N?/ݙ0ˋ6 yK?7Yf+;:5&t2!EJO-PGてK Kys]}_%Z\bi v`+c8 U_y\3D7,5x&@u*ڏ3~5*_qD{ f3N +x .axZH?/ Ck84{k*$!Sys(*WH@ɍF4 LOe 7dJp7G1uʍIrx=ϰAh^1<>0~:[N'R@"kk|" ❰[=ΜD>.@Ж/sĽn˾:fIg%Tk K*Wl\O8 Itۛ?~_^"{չb)8zS \^A2Sc%~ -0?;rn"pz ܜU>LC@E*GM$ MQNqd׿.UHjtk<6Hn(=ޱ_}T>yJUƜO?Q:e9cJf'E[1٦]ߠfmY㸿wކ=ϊwܴ%`by ь:=;'rP/1H < A<~χz[A\WœH?aeh`@Xc *S&kiQi+q\\~o%H;9q &$j'Zz1+ΗS/U;_s2iz"̟ ! %1KcݬDG1ϼ37ljQZ[D|#h -dF% +'lVt06RH$3߽<+3#uf ™EХX$j!" V AZRtZF-}E* t]z0xLg< sB޽yN3?ӯ&"Կp0B?~Y(1T/VJX:DPPR,Wy`Iӿbw_ o,Ef5WUW]o6}0 2$JibX @,>33#[qR"/HjðL~{9P 1ofhւE:J$bă?JKܓ#M\9.,ᔌr bpz +IJ<- -mX뱋+aOO-dfyAMsVDDWuuhz=` &3]ȾMKJdeLM?VO@crAW1̐ +~[z +*=[ˮ;ЙLg6=NJ xq^xvO{ԭ4 +;ͪ.@rpi'YE#KctxYMy35 6<@ wYhYAU]G +MyԺktkL58iwela%?aߘ->UԎ#d$MsR Ha\|NxFTd^qkONfŭ-al1ҍjU&o!a8L.^!,t0P;Djݣ)Kª(RZ|N3zwBSgʲh(Ntު ؼi4X@MM.9'p޿5&2xtzyS{[=O/zsq5ϟmYH0lxvtJ +_D_gx:X]>;`n ؕT9(z*͹u5WtYڔhe/\v8T.`f:8thi >`[kJ0gjEjf XPz`)7 -h +^Um0vbIDV X*Os6c_ߞ}׷?goǫM@KE +f(L-BONlaAV *PŪrlu\O9$̺BJN ~9nl@,Ըѣ+QHrmWVd6fƟЂ0X&H +X:[>#樗gQ|y ۲Ӕ57܆ͣ?!E۰ $ aֵҊs3 =3T_ꎛM89ø w}{\qȽv^W]j()1JLB\-d$l LAO7M~*%c2CyִY2<oWz_JM "GFIIJJ+x~QCnz^p;!8J W>P24åqDnTv>U2qLЊׇv@{n9*I:& #sGΫ ]m ۝,Rin=4mh 734u3iQrd&UU.=(0:t-n'* ERPx߬ƝvsJΡoJ-5QvGQ +)@ $Y /UQ&T5\^ +csaݮ^({i~AV̘Շ۲:gI`-9QS!$9}VPP9DhQm6}}9}"蹏3ZGoSe)AF|-k0e-w9ݳCx{ v|U*H  Pʮ;]YJ]V{lD# ؚ^Yȗʹ%&*OKMfQfwYfAM]29z]UBː=W%y#|WR0~od w:=x-#Nj}z7&eM o"5xзudI}J^lgl R-PiVGBw]}UVW'Eu] Zn> 'HW`Wc3A]{ݦiw*ۛ +Q㵭_O LL9QZ5'}=U̍r/߶BSx>o.|t;[Mtl}>stream +!}Drqb]&Ɗ\3j)yaVoDvx Yl-r pwH&=gIgk#UѢzf}ڌj1f|m؏زc4 ih|jaxZD0dⱹ 48bM`-|Z3 FJ  iw |P9yG`a$Z"@z!:Z!? +[B0:QQEbL](JώcŃ~/xP2Kq1J$IjyJ!#Fb-$Al١1cG#AQ#:ZF]O5`?wQT:9yQDmć+/S/olWވT׮5ǤP:#r\acr4=( gݿ)qc%4`IE#Ƒ9U{V! +G7B~D'߶(iY$,_[#Iܦ8g=˫`7nWt?|8drW"줙β0&M/w(x% Pc*Xb*NJhvӶ!?R㿠'!~e*Hh&2E[;:4tag 8VhnUt♏ws( hc12-N+8%ZzpLB^׎ènڂ !ͣ*_*Mgr^HmfB3O&p3n=ܡްXh_2BQI#2 mɖ39B_I%ުЎ<^%`k=䨸5#YuZCEro H]g"Tе&/Љ2-@ld@/ڠKQL;T\O-}FhNM%áf!g|vBH; T#Qќx'_e{S}#J+g):SރS62qsB =SN4ۑArmh7$Z`gl$GHV֢-xǙHd(ThM6:uGncGDe$S(ߛק'=u|k6V'jmȉ}v ±OUݯUbfDew Icb_VNh2bH4,U~7Zjn%bS1sCCé;0Jj"XՉ1Ľqh!:mhM 2=]bѕ4^nv杻+,%Ҋa"^ +ILW;nf;_fg.@YrF6 )<uz=+]e2fWq +ǀrBXPO3 Km#[G'sv4x_c Y_f)$'(o=pkegSD5]Wff[ +0mԥYH:IK(X]*6[,˒̽4?7gd_9>mbcOe6 Or &^J"0`Ta~I<pbU?1`\11uOMkvg=/A_ +[|қH4mZs=F; KU\R5#ʅVrU .1ҀMKkP讶μHւ)3LUtދm9Pyާ Ӽ6r>fCw?x)BU;h%@eݻA6S4kI?Ӊv"GZ&)'1x{ӆSx,_iG%rc,m&a')0ù%!fȕl)umqlV2 ZmFCqRŕrysEQkUP.\cWmi ͔L 1M\Yh s{t-lg2"xG?^#dumMgs#H Jt\QyLD%<Np }e%xGc&mP n+'F0!atdQ Ww7s 7[~vCwCuxuWx +ؔG_ue2Pe8GVJ t@=9-/Ahꅐ<&]G; @Aj~((kdnkc3KcjD +\r&`&0hӌ-m\ po]ή Rg>w ITpY-&|o2V i*\I?`I(op|),^kn,y4 cFpl")GQZg4Y&ܟrqXo hXa T8>~Fl۳wB{+>w!{tRAؕt)5#}>/THVuxaU𼤂m̅ Y3jg 4L<* ]]*U45^(|P6gq(/ɭN:׸z̒:\p` /(gق_<>;KQ73>x1:}!!l59i o!N4/RVEX9}tO +@oU 4K~_zr9}lMoQi<b1+`M!c}H v p?[l'f+0Cܕ˵{thM"aPgaYLu6f.j~MqRǚ~;S }GfW/ >W#AZ"rBUEI[cж8Cf1K dVTlQdQ *0qOvQ,p¼\fT$^?p]Ȁ+ڊܔw8Ѿ)@ÈQ 3̰d|$;W)mZ"$Shoѷ7}W)˛ne!U̜% )ʨ΅IfilFvy^ ?3Jݸۤk9?&)5nwd) +VH?K(+xQqYbqȺEXV e|x8' +GM@!' o[(n/[|e\7XFf#LDץ9<`[5B?XAX%% .͏lK< VÕUA9|@eAv46%"B'# ! mCM6([}*{`"\ ʯ5t Hˤfz0<.je IemO:[kZ D H^<`EپrjAlF$`\#6E- C/4Dy;:s^p|p fkx 'ϡ 5wQWDGCXarttZ&&U7cdremAAS@:ջFY5Mmc#j'1d P&-Wf^3&瞔4;2+B:[EE 8H,zO d [(ozFu 7rLkF̶7..Pf,D]J323OݽZPJWv4nv)p*RT^?e,#eWt<UrԼiavjDFJrKC 9حSD1wn ,P쮠VRj + HE*]>}4~?'tE8 9sۅq~o0xWV3 + zFCk;Y *sKu'%㲧`i!"=WxD=.3ղ/ V~ >a+ُ{ղ޾`3wX(aT:Q=HwUJɁ +1Zq2nDŽ,'{\Df7Ki?"rL8ىPex,jym cùݱkWIخzdT N_÷HVD[w{Ga,XwQ?!m0 GD=+<̀Q~WJpM&$_y{Pf"G7p@QUp+t{ɖpNQ{:ogd캝_E];5קksb2.fס&9q8wX +ϟȢ~,'OnHHU)ca/3o +Bk5 |./\ ɦe +)Էb l*,6iY;AI?;3vZzz[=^ }";Sbԥ/‘"-kUT\q,Kfq[f3?{K,@ΈQ%F~UZ h]@.׿_QGZ. ՞s=v p `q9i27n;&*H& s2TbUio *۰WgZ*I>(hK %&h~{1VbY= +@?yW#'JC ֛>eXd` `A (%O*Cl& (t]XK Y #M7ĉe, >a?wQC/ +ԗd>qh9$H}GS477C`ډo e=i[T3ƞ>rku3?^$T.qliI3v@ΓfI>Bm6Cy,2YKE@ 4<(.&z{Yҹa'V+xhkWp|wX6}{O|Qď6)8&IF?]H`$*VCWZ E*4Nq>(7v1D'+bFhpk4N񁛰E5GfAݤjB ?8 ҂ٍ֚@8f .7ODXбO;:Dx'.8{Ț$1oo?9,E#BǗx%{腷C$`IFiV17-M2;Ψ(0>طveVϘdA\~/ +\K?_IaK m3XYnOȦ?L=Y##~NePAv\ `D\1 '9C|V ?7\o-DpSAX4Ay\˞fDi&^ߐ>fkG;2p1A?lG=aCݢH"AOKf3q~fč"ﳙڬ&숹m(%2!\Cws? zCh]֢ Gwg\z;YƯV$D~&([įK-r ’/’جXr-QEFws';Abgܣqz5Ykڽ 2NњIJ@zx4usbms=ٖTfʆ;rd0$[FYFh%F=Y9S1)9bۇgŖ{q,RPQi8 +  Ѣχtk0$e!8Mh.4 C=5AMˀJDޚ@@D/9;nx5rÈŕ%:'8Y6˶$i{^US pP+LĔr_0- p@ٷ{L&Iahaj]qH U*e\ۛJv޻sx\ a@>:]vzL}vc ߈ RnmN\hv-zf&Z@2H]/P;&c$^%)O^EnM˺ d! 9YZ76N lgLpyJxZqNbLb5>=[nzHd<׺Xvؘ8QA."V3X&E]ށ`#j^GnmwJnνrxDWʳBlX@Z>@Z{&$ +kaAXK цzSج4۟ +,8^-nyq/`Ss<$ӟH=܌WIu \]RQxB`K +Eܚ;Bf=4=j~F& 3r4W`~Nl*VaJ3N +϶DU|ze˽ ,Xz/ x9zbyTQq$ Sa!!/7,}S1& +a!"W +j>L{Ap}bM OXԊRM6Khgd ߅ے_A^i[5CK!̯SX4Hw̫9L V6i!Ş|5<ݑ ==$2R'jL;D}p݋8'jdEB7|a$;v T z/(`hroE-_5X 0 @   -4q[uRÅR)>&4~YtB?]p!]+۰lXJ +n(љZ;k{?SH Cϯ?\zA"(y؜'!jٰΐHL;ZNw>=*5L OtFxn7Z78q<{k{4y7ֿ8S^=ifB9&`:E?g&,7cQzwguvuO-`rW=+lBu3ƬA գcSz5:ΈpɚUN{l a|7Ẉڤ8!thY"Y+8SSWQ>E@(m_OoԪ!-w~@ϟဪ!/ $o;p^[bДpGLZ~3T.:)"=JxJq^loZʿ\7(ۃJ>|EB7Uӭ5g7[Y% Ж!dV3'jA1ׂ0qV*wopi +q';c`=yOQ(aNlʣWE{aZgQh#t%M䭠*=~,5`VnmG[I%\*4E\?#0 u]?k Eb AH[-2S2ok`Ѵ 4=nB]+ofAV72 [9U8n`D1O3ኆS3]'&.e93*c33Nb6G^-}b:'$ѡ[=*8q=gGbdЮV' +ffڇ΂QeVXkAσzXɓ X>k 0uXO[MOF˾dz|{ꪳCi1p<b) K}8"ĘLMޔvuXp$e+“*>;2Mۈu)WotD;;P epF! h P v/cD? +ҫJrNĹ5UPw1 +D!3 cS'9deJZ*:?/J[_QYBMԚ#$qfMj2l:՚7]i3+j /z 8| qd +ͻDIא,45,PC㌦6 HŽUlsJ{`)ic:8siQ뀏?Ok?/vngLEoSK5=PteW g7\D2WߒUXƩF jQ!v=h(Ҏ vef +ꌱycY-ҪDtZsF~*sirH#:DtLBmRͰ~AD"vXjaT?[n70&uSOtQa -+S]?Q:ȈZ ,0 i;s16 +N-Wͩ]q[݉߇^NLj +a'mVk ˥4g0ή닿RYH@ 4Y&Nە[0P"ʞb%fUBf%&>2p'Y̺v:6$ ]b34qhA͗dBl_f/>Ϧmݗ{,yp '62 UXsk[w,mնD?߻՗ӰoSs gClJ+qDJPH8p^z]1ZIuIpzCĂ,qS}@+ZpJW&9q9m"%?p#톯@`%$곺%E}"nvӝ30 +EŎKE*YΪWX#gCͅط_V.V|=?|9"﷋p S g:`ٕH^xZ8M0m*XwNYgAzPF..A@$C6Z66y*ǻ}y%Ma벛qbD {1Zhy<`G0Ȫ^.0)e|wSbnuO#T|GJI?ݕ!P +zV aDȗS޹+IgRLt:пYH#FFSnYנ`|.5d|6_%DdM,pz0 eI[kw &8ӂ+$] S7R~4"xAx! ͯ/a|Ydٷv!*WVļd= )*As6Xȣ˙V( om~ RX,wؼ$_ (pg@Kmu*!JBtiW;K;PRB+Q?0.hŸ2q 餔"81Uc[ã''0mMmt ne^_0/TB+a >ɒ}om$9WPhjK|Bmh,CL_mZm?7]_oKMض={+)" ) b$1٤];kL\(S$ 2ˍ9 H2M1pkP[al A04FX 0HrEGo["CK HB ;22 ٟMv)uEGH-Oy"ݏ>kNWeT{{Rj^UnG&Hj?UqM$J.}l?C>xpu,L:mcxEM(aR= i5}+Is=CjՍo R(Pa'+kmп" )LR`CXK.lMGDD)xoS _31D=< (!Rs0Fר9<腁/,:",N5(NjC}Daώvt¾bh*RDh= 9BHԇ"ɪZd<@'`'w!v~|vM~]u%|ʼn\D!ݣ+P&"Lس5-֋  a*^$*^dѫYSQR>^#aBa$pD&o!w8LJƒ)>2Xc%@Nm1PM^--=T5Bc maߺT)@^[`g$- sg}kl.pwScoFćVG(\6@r9{?W2{hi0iף2&!7=oN*'d0}…%:4AqLJp`F0% +,0)t3)o70@PvJV9 + D#Z}QWziFkxv FAeZQJo$ +?f-^{TܹrFEk5}Xd`"OV?_<뢫F狿>tD(h>!|8+ ┸hHB;ż2 )6  3kX 34S+mzpQ,UM" KA@v_`tīH=J[b:D(hScF`!ذ0&ˉӶ5ծ=o-`e2D$щ3YQT~ pcС soIK:*$+hSe=c:yf([]oS>5"]܏M`v>LR_T-"s,9@q&qԯ[M;ɦ95L6Pncue&gn6 tޤ6l&Sh8|r$lĘ$;:NQ;i+#['_[x>/&*1{9> ~* #Wu&%㑋Ї_KJ +baUIPDq eC$%A=v]ڝƉį|3J (uM>׿YjAP (RScRׯne 9~7I Q нF嗙z@$O^y(FLqe\O}󟉅>:V06F}3L{nL,  ѿJn? nMFGTi{9ggv9K%*Òsx),r-?I*nPhmo^`Zݖr$q^.vxg/2\c)Nt6Pۘ2:^[|-y9~#[Ue NCwD9 X es8LE몫ߕ?Yhy=u Fx7TjMqQ̡nJDtmƢ^ dbE?l_~`a=fv!Va5Mhc`cJkCos+J夅]ƚ i]m&9uai@__a>BbSDrvJޖu}lqyL:W2R@W%vzӑ(c|gnhMMP\թgY{OejxY>֙⩖tə'MwyOnӬqQm{NDLd85CwR -wC6[P4]~`N0s >7./7BTi pʹ(Kk-d7zXGo\i pKdh+ߛiC,Nȭ>kG68g*ш+ΚF-wQ1s[ߴp8sp}=8HRMWxa+ap˜7EyOF1E68LfPm{-zS]ei U_M\@53u)rv*~T֖F@ka/݊29k*=sFR`wTK8-]}\=q>\pTD:U.PlkB)rI2STۼ,Aa5|RA"/mfI(@vYs<_BS,1eZj{O(t<)ۡ(:$5(!/ȍ7uckP|}g]zXL)BޤX9T[N kz!3/ 42޷dԤ¨#L"sp&Uj: ~(#'9 繟%MBȚw6xKη-r >stream +Hln@E,I{( ("#Kcg^~)K9JrRg/u^ ղJO߹Q˅uQ8=&+ST׭:\2e +0kjH +endstream +endobj +363 0 obj<> +endobj +366 0 obj <>stream +Hd͎0 +gtEt'DH BUQ|wLC8ٴ]L6ܧ)>3M/p,O9^};m^_5>}.a/]h?&Y}j4+</M e, CocTUMն,?n9zx=6@S`CQI-VNP$(^VDpR FHh ڿTTTTTTTTTTTTTTTTQE!lUJ8\%'$eI<&(Kt(KeIH@Y;*%HXdn$HXЍDt#a{Ѝl.aQG楪[ܯmKk9 +\!%^~)pX_ˁZ={*˯hݳDzwnr.|S>Mi”-mS&}i. +endstream +endobj +365 0 obj<> +endobj +368 0 obj <>stream +H\͎0y/gTU1%Ģ3J}p (J ӫYp>ۑeߵ}84mW1.3udTCÇ/v?u_×x6T>}4ulXDZN~Y6 xdn^xZ ߪK4ɺ1/:^*ıN1Z3ۦe߭j>slDSpNJ''k6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh9\pֹJp +%qAYΦ '@Y^vPD (K"cC@Ye1ޣ  gWn$,6F"t#a{Ѝl.aQG楪[/mKK9 +\#%^~.Wp_ʁR={*/hݳDz>98\8ߦTcb2,evqJ]|C?I,OPg +endstream +endobj +367 0 obj<> +endobj +370 0 obj <>stream +H\͎0y/[UU|@b tâ?*mvP!BX&L(|#tcͦ1 fv}mO!st}gbd6cQçۜǾ~_?m^_5>}^G)/ytǗtMlaYxڌߚk2~2a66!MMIڃٷH}o6˙s7'xP86l*jZOhgAP DAR%hPPPPPPPPPPPPPPPPGhW\pֹ jp %AY g@Y^vPDޑ(K"cG@Yuޣ  g7n$,vF"t#a{Ѝl.aQG浪[ܯmkk9 +\#e^~){I8,G˯@^~-GɞZN^^^rK"^YG ̉.o*ܧ)028>qyOQ+Rd +endstream +endobj +369 0 obj<> +endobj +372 0 obj <>stream +Hl0E;mbꂲQ`NMB.}I'ĢWLk''Ӵ]㭿u4xn ΄$k5dy:||MzlY==Myڧ7qӥ}{b/cc۝}.X!`VhS|6Tu;m]3YgN^N4a#p +V +<<+&X+!(P ++PT +N + (  A*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|8(DM߳m:@ g$%lp%ae$D$, e xn$en$]HXlЍDt#a{Ѝl.aQG楪[/mKK9 +\!%^~.{I8G/@^~)GɞRN^^^rK"^ZV ;7cspp#>iڔ-vmS&}ήk +endstream +endobj +371 0 obj<> +endobj +374 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +373 0 obj<> +endobj +376 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +375 0 obj<> +endobj +378 0 obj <>stream +H\͎0y/[UU|@b)b3ݰJ۽qiQy܄mvn||ٔߧk7x cQۜ.)y6OnsxG+oS~8e}_% BeKK2/Uc\(^tCLSΩhݛEn9uzzk@@Ԏ F''[v;*JVxAPDpR DZVDTT!TTTTTTTTTTTTTTQE%l~.:AΆH@Y%,)Kʒ;eIw({t#a]t#FvЍNHn$,rx\%,*ټV={mM~-GAVa9 /Z9^k9_Qg/W<{{ȀW(ᯟ9QÅ3mF4&R&T?Y:^G2S0ne +endstream +endobj +377 0 obj<> +endobj +360 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.479004 0.0 430.56 631.681]/Rotate 0/MediaBox[0.479004 0.0 430.56 631.681]>> +endobj +381 0 obj <>stream +HW]sJ}ϯP Pי̷fMB((\T 2h%Voif<II/-{zO>}tE6ǏuvuT?sSHFOO<;M "Tļ"uSQ%2^p:k0= +;l%'Gj ':dx}.ʬ.҅q"OL6HR$'Ӄ)/NH2]`)StoLßdM6&,n @H8( "SM%ޯ\g`k#gܜR$? gd?W?x N;:~ cƛ(RaM' +)LgގNy;b G:FΈ֍r ޽c7 o}h}} ˴@Lb$o8VEYC8܂X_&Y6u-wICrnuyKe], Ҍ7zon{pe_rE]S͖>[BN^r3nvEC?nA4}3!erhN/dZn#16^*͓n}X~9.YW^I2dK`IԢw~Vr[IIO0@,ֿ.:#3Z %rf`̻^P o˼0B&werTA#&?NaƤWzmXVk +lVݓ0 v-2tJE9B=F7ףs^a5y#4u I&!5P Eg#=bq|W,1ؚᝪApD|V_orW;%p^j pHcؙ[Ԏa ظا1z,f\NS|N")ׇ=ŭ x][ [v@a. 'aЈ6-% Kj#YnKo* 8~>Y*?^[B#{1ǵVuU^QH܌Cbqދj` Z@F0"0q䗤#-ZIaMHFWfL>Eo?B7"Db/@ aXGջv?Cih6_|=`dJrUhWӰg_֋.ATJ` w8Yuvq5ҁLOjkg. aӇt8Y]cBkIJBJ?㹞wUi(Rq,;jAjJNdЏ.R_Wkr:ML4-iɫͮzFOgnvt@ g'gߎ}(r"oyD]'O&4# VnM°7᎗M*J7B0P*փXdB1p@:~v{oĐiF*_,':n XI_,|aLcHSm-M:,MbB!ߥ(0w!*G +ho׳ )[ 3^=#r\?.v8F$_0Oޖ΅q3gb+0yVo*;vi6+/1Xg^:= w]m#nnYbk b+ g/8V> \t 3*to!ա"2O{C7GK#ʻCL;ρ_;ފY6bF*E"3//Yopke+Bj|?e[c2=4^0tp#yuW$2{*J mS{<= Qa$h'a`h `qWGWwDh;h|G[cG&Wu8@Ь,./. d%9cH(Hi]95^|2g럙1bi1{Ā R<cS^J u 0ӧ̖cxϼM-8&x6Mr5䨪f9J*\ξaڡiԺ'_}td]H@LHLdQ8gO]@1`~UyC {L`E#Ą=Yܗ7=L"L Ǭ܏ w~edm1 ]Yy1kL`|3@tfě(D"1i2a*zPэrYp'wgM0ͨ A0y"W[}vȮ4}lÆ[􏣧`⪻lZU{gI#1asV X4<&V7OOm=KOzQL6;U0pt}&`p$C80VO/;Fdw%s|: %MXϐ^E;n` ~[t~p +E0g`ol7>9A:VW5#d}WUaR"doўm0OCb +D{ 91ϟ2XcSOYΓJ\ IF-;q%i@+);0<*T4J>Օ뷳&{W19^s`R" ``j" 4]W)kZIEL&N{'vL 5Ni[Bo:̳X?_?[̾|YLDi"PB_C{e^P FvN)FϒRJ9˽rx鯢~ xk@Tɿ6YjYZ[plYKtk;'"ԾTJ{1H#LCM[=7.Lfա`é'lgq%x郣nʪ3"fd[8@> ~LqVc43]Z#PQڪ&]/?P`;V=(mƪ'h-x~Ufscs@qE)_)RzgϠ>qr} 6l=63dR1yw8[|\>恃#䅩^/t٢,jߟ_c^,3o"JL +gIK?Q 5 P 62L_YVȻɮPMRxPbP P7UNnO'ğK!3Q;SUcBs:PۺJ'_hoqb1 z[>u,&w J=v|U߲.o$+^s7 * +FR]h}6}WךBIWa?W$ؓN1xۺI¨Hլ8 ĵ\)/޴( +5X';J (]t7X;!Qoa^~)=~ަp%\%G.4mDiǴU" Q5~!_(8BFJյn"D*KFN>Bcn7=wAB]FPd>]1쟮tcAٺbtIڼ"o]UzX}eE&@a8n0:AQs0o|mϟy,.y,ȉ$9,[֋r)hJ3ɦ= 1K6ڷ֧9Ծl40~LYn t_*۩Fr&/8HɶȒTؽen< Nst@, +-[0G9uDnppCjvLVsL"jQ⩋1&`Y`m]z#طDUf>._Bj'amjɋRؚ*`Q1x7tq,cvP%}Yjwl4CxsJVYձ$m+d "،_>stream +&U7ɨKOƺL:pH0н,< ʆu)4A3^|э 2e0;"'Z%v*nKߖo)ˡ9| +{eM/B{Ђo$$"$YSc#N28 +bV,uuArD*-~`.?OZ"iEȗxJX`͠c{F" zl,kDCvQ`c;bo;]Vq'hHƋ嬗 v?YdcYO3ڽcoKoH*V!5D7p瑛u\omu[u]#*t{j2$Ɇӕ'T7G]'WYb_< u~h~lGR@+62^DZ6sb/Si0Vܬ2g6H)LƩ抳\gL,骘<̍p6?Pކۈx#މ ;r= r}"?Z{y\.{CGEx;ijT0тLcEe +뫽AxKkŜ)ͦh|U}D~z/OCW`sR9g!QW8X5m {`_EBrT}3C6U7f[ HAqZD+?)cڳ+h#0Z㫰̬uv5ȭn.9>NQr9tLtObpS +"Lq$R5| ND~k@<;NFYU&9L(Y؄5,&(_Y&)_7Ìjco/ [8UeUYN A1&-/+^)d8%d~cfXmb婒s 4; ڳImzXz)TiL,nѢoIp@"HY{"s{ bE +`pxa_+~k$g!1L"-|rDy&'y\)}u\s^G[ÌrmWb`CJ6<Đp?[QBw3* +Țcgxv ݋l {ܔԧe(T_40/NUAhoVtWWDY[b'|f| i3íҤztPC3Nz,˽B"lDTE;fT}cОeג)UœTm|7B:)iw ܺM 6&{aƅ1:!d1[{PhntR;u".Q̋ 4Seb.pOཽD9nu&nA֐_3o+ɍ2p ,Cg=!X)b4Ls$"Hv7W|2, XºMCNlZOcs֦%[D"~j#&>+Y|5nf'd'IfP>D);җ%7SkjgS%܇G[a~ bqW mڴȁabAmR5ϓxz\8j<#%|]0!48=/ t- kD\pHſNgUh2I{Kr7 !_KaϽ!)[BO^_zQbPSr{_R+- u,,ouW;q;ltu?Du _ɐT.2_rئկ +GX $&8f=eT1Ib @LimyC*HѤ1p_s۶?gYԇ0?8{\:N ]=IBvv0V79U`PG+B=/:,3BNN%eJ}jkP +. +ͻȶ;/*O߼'G]t:4)G6,`G0b{S&#3Lӛ14x@fC!K%JRY*ZeQNweGlͻq_FJQ/v4߉6ɇ_̴@N!5LYxҬ0XVdמmvS\1clGdLJ#lvCU[ȾhXӃeX뜙g}q \ 'gȁ\b\s>)w9mWc'M_3.& +PGG}O㤮w?_2Jz }l b݃X~լ,m5eɅ6͝4c`){#tQ +I["[&1{~&yUn517xMr^Teb۬+;6 +`Sk4c>K;>Q\d,&F^>O^7 H@/pb(j{eU;v8HﴟrwhkҮO[P6LxVo18іI$Nv8ԲIpӪF$3]Llkiភg ށnbUjKvüwmH'Wp]cE3UTI>͚ [@=ty+4"$,EJo`iKH6AG٬*R !tKZjzzYlyf| 7 l9XXkG={/X_fHQn{G! a9V即A%ɵuk6aٗ% +EV4U7Ž`lI/>hc}++DR +&(/BA$n6YSO=($rm NŸ%}$0HѩvIlMgC-FP=CBHY bAW_xT U %<Ұi.“M*8R +&FtF.AGՃhklJo}< +Uhn5n-O øV]:i=99JZH}щ u7D5Cޠ/7"EsP;dLG?\4+|$Bܛo) :tEB'+,)i@|d]R:p؇mӗU%(:|<"BNH vuxkiM'nbQpP`VHd&M<ˠf`>+緔O'"\_sYM`/.t k@h30Wsi)Ɋab 9M٘k?pUŽ +:qC:Wζ;IA|Qf! `fՃ6uL(*T' !#|pLV^eΡ80 Hdޯ~kî6Mr\~K'%iu,vtûRWЉvD/}]=|rG$v#UZ:mս_,52d6bv yd7mP_^=XGOL%`׹PJ@4ʒy;QhȅѰo)k𝤥'Vr 1:x d|#5@7_}39>}eW)HR}rN%MG4ǭ<Ȁ_Zlu3:TⰠ(/ͧVXI1GkR \ˠ ]N!+x|EAo@h4[ru$"2m5v_zֆAX)=z9 '4pll3ʷoiA?z2A[=QzC6zyߪYIӑ9X(8Q֦8V~[ {`4r:5)Y4ڀC-eۈϥ[oT|c=5`ʳ9d!_A(+XжЯ["/v*\ZBlԔɇ )wϯacdE,c03(>'>nUԕbwbamS8 EJuQijCq{OLOw.y{Lz#.vyK1){ί/ LպJ+;@[8f{Ir,$g|FS +׌2t`' f_B\|f'Jxv֔- )UiPn!COCu7(xS:CKw;'NH%yΈҋ4y˳5 p$OzH[ gXijɾ#A1fS-oGѸB uz޵f7D/t<:)yy[)7;Eǜ 1/?IwUPXOc9\`(E,o6lA~A$ \|bTS\.T)`> IJFzŲNӘP=Jp3Hr +w$ZQtO8҅^]B`RzK @;ܤ?Ãrϻ@;m4GJfl>壚< @WĹLW 8r|2:b|rI&ͳ`;GdϰBі [CL|٩ vqHk>'}\@TJsai. v)ZV9`_YoASsNݖlCmocqа)G +j. +ڻ'ı11N\S@Ez b~ +OgP<~s{% +%!O:Qw:j!uHo`1kHaXno~1\ǐ7uKKY蜟\ +WX8 s1:g`MdbU_?@v] u=z%XmN ff[&`;3Լ6V_&gёTkT4'6G=_գPe`. žw ÇJF=we+PS)tqӇS0 C2԰Q_lzhjɸ)N2:6/ZPHa6&GRnbyr8rεX<4?]JFnRA@]0?"r 42q=S1Q#1!] + Vڠޭa."B>xN i].Yp%=C:w1$-â (v(I0:с!$ls^eEdsm<ZkH5w?65uܪKaŹ{q<ߠ|@; ֣Z^)a"py9kJrط\Bep.|/U,!-Xu +:\ +s+1Q9BTDrW .bN;lkoӅ썥=:eqBU̳wwn8 oBo9]U2{-\F1%5'ѩA-f'&N2>-ȏ-{"p_~fd汔E\2H8%#0u懥fɊ&0% +Bl*̠fh)2Kck%DS^"E#FSFN/+gR4VG&h}oUY y/X]X >B0X K$'R jG+r!a{__4ܵvxhD-CO?>p+d91'0-_ʾ&)ie)Lua)_zͽgyWɠpe‚ጆpLU~ '֮!&s[mݧq&q!C +=1ecdF 'r+h6fcxpDߌץ&,7bv +PWd)Å~ETGLQ~xK-| DZd1>Y畗{; IU \--Qv* yǻpoׇ]24;cf7^4:ka_GyzfBwm R\ql &bX}ݓO, +;|w EУVn͠; XVa { N2&VW8”#&Wq*q-m*'7|2 %hZ}]M%= 7Ney qo둴׍ 0ȇ:{c혘ada0bYml[;)蘭6m +R>%#D M"rO?uq\N]F:=^J,KnPŲUSHne~]Vѵߡd S`#if&8[B׳CNFO&v#D,6׾A8Ma)N>0 33:9^! (fK>?r|9V7~ÄO;7<:%I~CGn~ {~z7|&/9{[\y40 @ ~  %v )yf+95F+wlf" l#W<fp&|@ePQ<7Z[Y^L5 [ +R^φHgR9r.~=zqa_B> eN]( iP%NdJ[fa*{Po;`. = 0$ǬxEȋLg]p8b -S@pGAuW˔4A ZD8 AEYPLS0c"A H9iM!͓jXZ,Oi#z0B5Cq(ȾOF{W/gcck?_>%>t+%9(@02$4.29 KGGD7$(eX8n҅nS=|P5n⚃II +{фk0a_2ϜScn)Hmɱ̞S;GNY{>*j|[a̶ 󾖔7ʴ-Ut9 ^vp"{^ wY=>!YqYh54Ƈ7Tyn36 *e4!7;Q3Ṁ}Hf`Gcv2Ւ$wعpĵLT!qUXwK} .ų3 #c`i=sŊY^~OBwL)t~rH{;B3&]'`F*CcC$Y_7t EP֏c~iE5^-hOȹDNщv?ypc5y'K)촩w3r|u9~䛋iL;N>ʰ"S)<~," T)5ȨOЭ 7n8\aTt~rݑS{?ZW5_ݴK=OHMճ.s vV>'| ey t&k[qujoԏ&d¨(68MPM}Fa^V75T1; +{S30;T|{yXiِ0ڜ eb,[\o[lA64oĢx? h/\Y-)-«d&⅒V6Xi=y6XW/hzg].];8Q+Xhtq6ko )l9Av}xc`ob2-f@iF=Nh BXWb0V2>" Qb$hR5*{< +]Tk} wDwid ]l͛ϖCF ZWz8xBlP3ogWs)${ׄ% FSfD4dM~>wy5 p:AQ&%Q/,aɧp]P"ŻSUQ#uC=;W 3kA\{rjvX(IHA(r4gQ7 v% #zOT@YT)jv(4oH, M:1J*bϭK$,v45c0m!ZV?q0GUV2n x.'bc4q#ɚFB`)^n>LNWG=7<2N>V9vw3l#ȑ/1|Z)L"gJCE{6.}hl|iokAŸ02 s4P,7Uљ%R\7͠%B2ZD{Ut^$E%׊ q:'KQ&h:4\Cm +^3G~m.soCqB^7׮*y._Gب'վ*$Xz +qX(roIٻd4AH}cCZZPU_`BИKcecgL0ҽdw뚛`al9iUap] I$;ZX-y;ÇӁT8/?K.l'5O+z>S dH;C34tI@Pt󉹼2zտ@8H8զ9ڎ횦?u_Q2+B-UMTWP E1߄;DN7/3YPBzN FIvjǢӛg4E]ȟvl65Gg0 +hAm>VثaLSxǤ&D@diJѥ8}@dA4QT75T$t:O9ۈqrE4* iC\7~%' +|8`p;KI-^ kx ޖVw{7'S~NPuA4i+zy"Zć:+K0vБ(^p H}p 8;BR9Q.AböL"{vۯ3K"S=a8X*eA1H?LN(C^]|Q \E7DNN*3FEB2">jiR?:g@ Fu 2o;Ty>263Qȯc<&eJxV@8o?1;[T鯉mmJ8 =X$|i~-~Ҡ^7<ٴ7c>"myʑBǙ!-3)Ͻ_~^`3Hw&v5U{/5Edݖ]Uݵ$p/\{ ܏C)5>#S:nd -S`ޯg-S]fGv92٣jmn*^M>oAD|ykZZn2]&ڿ- = ݝ9K;%¯v4uoaMm{ t$ƬP$o2F {|n:IiWa>:k@+3YNEĀhVQ)\dCKw3W"Ȥ,U$=}*% +gpz4S+ DJe!K;Ԃ%ף keŸť=׳k%wȝt_[Q uVULo.m%x%Vt?pK@@*H_p/*_HdxQ $̷Y\$q!wsqS!^^ aߝ5HYr? z ܙcukR+=8AHn*9n]翔wQ#n>zλ-Q)Eyjkksԧ0HpfW8:UMϗb_"q(^=&rWYMq>hJLlUO4w0cR"LG`̽p/'ڛ.mJnLwk߷JE41x50 Bڀ6 8|/QGٍS!Sf!;wINy -Pvy FKH/oR|) i! )/ضt𛓏Y#0؛]+j(8o%Q6sBlxz~xT_ N=n@0[e-r(`Jk?@Lr":$c}RQUE\|G@r~z??ޢxo+lY)&}4i<-fbH2Ued8N y4xշ؟F=5nQ໋ϣ2F& ݻSqO~v֜q)LMV5W.NŤMLGУN 'H錺e?dzW)Ap<[p˃}j%x$yr/џCι}@@L4L@%| w@ 17 fB *'iX iq޺(>;a(C(2S173驢<S)d,Q+dQ+mn(JD< 9]N`J0KFBJkMtvEA < M 3D ?WPAۜ#z㉸d\m(Hc4E#xGM!"$5.Ř9PnI;&Mm#Un<)ɔnfU)׈c~^UhjjD+yZ/|Qze8<8ݨ}9wQ@D}C1ӂO &3C_>jl=OSaA_ edo23d%- +z#PJ΂cɂ,Ics[?cҩ/\/ wc|~ҹBmeɌI-N^q&oKOZZc'8x$}QvGU7a +E(vT+QȐs:},C{/ϟh:7zL=:-a +D~ Wjy钌?@?>H>XBjϪ D4T~˖=@).VqCZ^j>P5I_@paQYX˯sep0g $*B)|2LEɏY~ b.L|LrƧr ‚11Th^`L/m@J/`lw\a?G{eڣҤa~vO{[7mХwy~sU pGGHZ@f YFa~T @F|&b$@$r>[EmsT*\'m%@6~e!6t|=+EF:}{;TĒG̓HnEz#G͐ l86ݝ/5,SPLSBFH<'!?N!0+t~PY~dlI0 + Gt~#]T(\ +ʖ²m-=/#OGT]Boku׀9^vυZBfcE ]s[ +Hx/8Y +83G0>X%1Ca71quvP.&#+CoCeu i~/\Y⫢C1ǭF"~1P3!q ph2֔0VX˪rs[s҆{7%}=u|Ϫ2ygWiH˭^ES}C% +n)] j(|ZzJ\oTTKH<ϊK}CLp?x#AcL`< lb]0_U˷ʆ'<ض_Zsۭ,por ɾ/ V1IV3Y0{ףq(Mo=Jky"dҊw g=4$]iGް}'([CJ]Cxst0/%"31:u*z"sxS1Q &F*r5up'Ki-vFU}w6~2tbI?<_8p=WKSnS^ڨvϬ3˥p1x+ {Vڠ7M2j9S5BN$+ TP1d!{k-F rkN5ȸ_t Ṿ3"|7'-lKbzpEBVQKZTK4F+4e 50z2@*iXE)&s +#nb)/M"gq9gޔ#Y^fz MF:$6%h:y_=`_Z9i}mPT7j 6q_?|~:@6 &-mkO'e1ߊn +endstream +endobj +384 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +383 0 obj<> +endobj +386 0 obj <>stream +H\͎0 +_gb&i'YBW]|ϗ/[Mc%0e>kuCF΄ί7I7S×eyhGSUY3-.j|< ss7"}^bX!u-<moMM_%kv?Ls3bVY[m,5s:lg޼hCHXN8xxRpTpR((JhW*$*H 僠 +R>*H 僠 +R>*H 僠 +R>*H AE!lzΪ:@6$; Kt KȒH;"dIw ,6{p#ap#AvH;.FQ7>J4/U}Fs +9mK1zQA9ʥ?R[ GKvx/G{9Hf⽜Xc3zI$7(1QmB<&CRT7ķ9:NɲwFc +endstream +endobj +385 0 obj<> +endobj +388 0 obj <>stream +H\ˎ0E{l lzIncZHC@/[\6=*| ݪqUm74s\{7ddTӅuz?ey:|}]_vTU?ίϮ˧_QPMlĹi~1M/ê4}*Eۅe!~ǬҺVUYTqZy?6u0x6p'<đ''g +BXxn7@hQ *H 8Tp*H რ +>*H რ +>*H რ +>*H0PQ6"$`h YF>) Y,#@GzGYaC;MH;%[t{ qu4T‡Es+;4wZ4w{[ n/AYA9KRr A/Cr{9@/d^n//E/'9r{9XwőQ~zD9& fی +yN#%O.Lnot'R/`d +endstream +endobj +390 0 obj[1/space 2/space] +endobj +389 0 obj<> +endobj +387 0 obj<> +endobj +392 0 obj <>stream +Hln@E,I{( ("#Kcg^~)K9JrRg/u^ ղJO߹Q˅uQ8=&+ST׭:\2e +0kjH +endstream +endobj +391 0 obj<> +endobj +394 0 obj <>stream +H\0E @zmfӸ$=MRI.;7Iؘ<*/MuNGu~,Ȩ-􃛋2[c7)ʗn˫zeQP!vEm q[Z2w)ͤm/nꆨŋJ~?ōX4Z麶coMk'7]h ;88*jZ `pN+UA + +>*H რ +>*H რ +>*H რ +>*H0PQ6"$Pc@cdqMKՐšH;"dqw v{pápaw H;,ph:=qu4TG浨oj5\,z٣8rv/H >^#es9@/AE/Kˊrl.8]%3&cr``(_4xL”6Ii)>Ed +endstream +endobj +393 0 obj<> +endobj +396 0 obj <>stream +Ht0E;mbaA0qHmiߗtxBbѫs{zk'piڮ㵿!c<]g6L_R Y^S컦7mKb>8z?sٷM?udnpM +OKu&[eW }CXumݙm<3|DSpNJGGk6 +BTx*J#Q@ j"AT!hPPPPPPPPPPPPPPPPGh{-PY(9!l(K>AYΦ '@Y^&(K"MDʒHPVỲ(Fº t#J&Fb#n$҄' ܃n$Wgs >J6/U}*~i[_Qg/VGX)sZ|Rr/U9^~)G랽$իe𿟾s7 +qLLV0nu2eo0mJ +endstream +endobj +395 0 obj<> +endobj +398 0 obj <>stream +Hd͎0 +gtEt'DH BUQ|wLC8ٴ]L6ܧ)>3M/p,O9^};m^_5>}.a/]h?&Y}j4+</M e, CocTUMն,?n9zx=6@S`CQI-VNP$(^VDpR FHh ڿTTTTTTTTTTTTTTTTQE!lUJ8\%'$eI<&(Kt(KeIH@Y;*%HXdn$HXЍDt#a{Ѝl.aQG楪[ܯmKk9 +\!%^~)pX_ˁZ={*˯hݳDzwnr.|S>Mi”-mS&}i. +endstream +endobj +397 0 obj<> +endobj +380 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 428.16 631.44]/Rotate 0/MediaBox[0.0 0.0 428.16 631.44]>> +endobj +401 0 obj <>stream +HW]SH}WxTAӟj555U8` kLeԖbhb$VI_֗-}o>sFyF1sTzGGOǩ {_xgAcoT +/"DIAL.`A3\H )<'4$$KQYFtf_<^vx;GAH=ⅷ;a….#XǼ0SA"D PJyoWdz7N.3OLLR$i{_<@td-u]]ώᄦĞp&$*c$|=zOzv8L 'ld>umH`k3F.F¦Ԇ !Ɵ@H޳[(GX*qL +Qadd}DJ)sw) +0ϯeQχœ6vP +1]6cKT$i\]rH4ʿGMܝq^$^>os ǀeb2D$^ O~U<<=,*lLfZ _|Heߵn}>cjW :5)±x3AЯW $xS̲?k&.^$jZM+~{hvaRLD{Pr:#'eͧW0<A؝,4$q?w%X"庤` u},ߛnY acqoG,6ʑ<֒m,PO1 ~WPХ'~a}e@%r[Uwxŵw7l6L)9dn_BnYYV@~4jy|5;L3V)W^3#fINPW= +ǓWhfԾk 4ײ8_ +H',ILR=umq0WwJg#_Л7NFX-cc?9LƞY)+Nb:}~;jƭ񠚌ZNp]Wo(HW6GbZ#}y*ǕFh@_L`=l=}\t,Ͼe7<0f6ȇhw85$oam*aj$Us*ជHV TTdgp_ n6G[?1԰٥͂k fx btgY=.&=0Lz n*lt#Eܶ{u<0/?nf@fa3S C 1{s-qT<1kcdebĕAv0ZSPڅHFQ!Y^r䍣' +?ȡ7Ϟ(׳:GZ|ղܶDś٘, 2)Wȏ͊YOC H1VI«y|p&qg_b];o%7/]D6a&ר;D\NXF}Qnel ƎXGPHyIxPU^tOBbHOD`T†ANd9SG/?s Dg 3 #w +Z5Jµ ͳutFSSFcûoߕUfaK|xYn^au3ymgASͩ'463E8 Ol\h;1.m@m2Y Z{ZU>$TVa'y=KnԾ&nuLN"*'ݱ7'Ŧݜ S9'Q} 3$D0fPͦd@ 9{ŧjJI{E +*ټz *7flZ}w\jqt+mi}ifsx3یЪ,2x؎Cͥ,9 0Se_h@bف$!P \G yQ2ĉ8fTX@ ׷x:=z?c2b^@O㱯eav<m4 )3SЉBط<^3Z#ٯmTiu>B^yJ~"QK7K@(.\u@b{h?MyڑX ԙ$$A''B!MhAǁmh@kBfQ]NblVT?;!a#A}W1M.6@Ss^w&QQR\wfg:Oc;_Vǥ?ʭ6>%}ɸ{v" r_uRThYo=)I_ ƎQ4~?.~ڝLm8@%02qKR@TS!c\|9c/6ܳQAV/&4S(p=<{/:e>64͔]L} #>p fnAp,f|e P#0b\L:fJeMmo_FP.?[RRCş&hʅ:u9#iy>w0`jã_NWWΌw1j1/Ɠs K:7\fO#$}1D"PҮ/ҽ^:}%n??h1m6㣍qZ3řl@6t5zUՁm=F25wmeLWB! 2)K114y + q1ࢦ51 5w"&s5 )8FC@&Y X +O肯|)CI Lhz@{\MIyXט (vt(M6 ٤'= 1/4|XIBn%OeϘu ơY|_LS~Jqܦ،7޲_EFOB}̟v,De,208a f؃%&I68:Qbp7ў1/g8,C]X6Yt8'e u™ta1r[|p8J]G"a~`#쥨5\l7D& Dˢ:> + j2=n ` +Okm~bt,C%:rE*tibN=M nv”EJEz SrXXd(dz$tohI3q48Y}Su}4fg5x@D#4}uQ8pԖ0S]yC&I(6uƏqh]POp|Gh MnʶoveEZLʐ&X;Gi!|kPT V>5+&HA,n?:Gdm0b:}-V419#FXL|ViS @Sf.(hGk/5p|0*4D + DuU*xYnbkѼ~]ytoZq+ (|*x cTQlc:Qy2FSsZH/?o4:V pz!#J鹭v jHr?9h[!5i9ɝ*̝Xɸ9 ~O7PM + 1XGUS.wϩK>􆫽!`@kT%(<_M1#EY&R.PkW;Ϋm +ǺYV޼mÒٛxC;N:"_hvwKFWÊCJnն4006!1" uB?#z^$C"| lHV<}LNRҴc&l~pr6, +CMf)kekYNfOW ؑo7yCq %qPeeBa˥ጫÙ)T327:R +MD[(Kb-]W>bIkbUtb]"{b 24wqeuzIܝOEا;Ubp@MC\F SS M:Ko9Kl)" +E#T>{3)C=H*L1YUye%H0- `*CYD2=$+uQ '@f@ܐ7<=-L[UѪlg/h(M< U5xf(AKxwiql+H*- 쯁aWVͩ#aEJ 0nCق.vKY=xaMPN1$8V!4=6&hcmbR.7dNNϲC͊ X9>Kr#&X0{*F:E7Esl SȦ~u0rF,;P -M$J8bn h,9 ޝn9[|cxəǖ3FθqO66{N-L @:p=2Dj\AoX+2 @j$WZxʺ6mj}҄?lJˊONϗ|+¢mB~T$Sb59}tq.3ȷ6=^!b3̒Δ!)^e]WveT!p` }}r0S²uپ!Uì1\P6VX<G {n|sݦύU:\O'Z(xu-~{vRs )TFWn%ȕAV]fDβ+n{j ~{Ch0i6IXBʕHa_ C/C +endstream +endobj +402 0 obj <>stream +zgs*"Ű%R lt)>"@uMn9Ժ~ab3,6٬g_^o?\X ~zŶaS|գ=@Lv.lD {/o{*zx8 {_j~Zehx WC`Ἇv?ewya۲Ajٞt&TyϪ]Oxe}RmiJď]mDJפV?$TMD؞}'K +>(i[랏S!͛8m?p,І.CE6 +vw5֎4GYc-R^D!Zbϯ$X* N( Ғ++źE>ӡcCl(yY&ì@!>fl=I:\Jx/C[ƈTsp\hQFW&R]?2Sn+&)ksIHᅴLν5},o9"Ř)/Xp"Y+Znwgl_x*[1ӕ VCd `K^.q9~1T׆Kg _OcHU[8'1k2h5H@WEf 4QLC:9J-1HY?*z;{c3vbbɳC.m`^ӝ?|RR *w^F :98 FNWmxYfζeW{":s#hRDM\k|¶`̺d P>ҹ-@!fz Br Y/HƐP(,I0U7r)SҦz!peLa@9|>{2E/ʥTVv7f&F$vޢ=h!"Kkq_Q߮`>٪mceyDMTAܼ3>.ZL*POVsՊ Y"oX511zLn P~ji[>1{v(H}Q0?V!&$H rz&+zq:qm k?mɻpyS{Y2`O!jge3X[3 ?<dH,E$48VV./\:]ء$$W>R'v P&4@9RgF¤*k{܊`1S@N":G:8# GW'f ѮKEge=sB?Sx0`іrۗv5ŪV]2':I߮('̨ z>}>"~)F(HZi% K N/Z`!:.OI ^+\]%h,tƐĕ[ 88 Q͂vb^*yP{a~j_)zIΏ3Þp p4jY}B4)1;&7X^ͫayW1B&x6Ouw=B^)?HPg|?d 'X67(V? 7%O`.W* 1) -ѡt~ih +% %DDE$#H`7+)l nz5)`sIE-ck=;ITGUqRl|ueN]K( 80)ω{zvz.D /1U#PZqU+:;ftE@.A \/]+(jK=:jD('1":򋔇75烟9pxOXP X -[bчEmW-OΘWUxlOHLD +N+3h7؇/r_0e5StJ[78Ųl}Yq&ɓ#cG=DfA"걗mC72aDwncHbg |{U9SWLS}-gEs!J9gtYT0XSec'mȯAae`LqEgAU¤:jp=km + +[Оk?0oxKCX}xTdOq&rJ7%>5eU0z.ӚRv]Ml!7X{KΘhwDUbUrG_^t _}=2n 4{Y}OcF\\rx K$h`<6y@uz+2lZ>ezaz,i@k b>pQ#Burw N* ARasEݝsZ^%Q[g}FmK7u&\vuMa%bS){ĭ/@Q KUqjZڵ2f,%k%'fqBrP+j("a(NGC +"giw^FŁ F_rEXk.EzrX=B^..aTGN_#Z}8,!F RnϕOjT \m+4 lB\WA~"1g9_#-`bEdr w+:!v'X1F+4g?Bu + + ϑ+Xҋ 3/xߵ-31ۣH"鄪L.זjw+SnksrBпy0VWQbU"y ײ6 e&’Kޑ^6XQt#Ơōnxd -F,>_'{Y f^X$;r|Yk4!0"̦XSM&Y6pqHs?[Z ܦ@9$d6hwV\ܘ,x됩)1DaoQp  Q_qt[~U;:,g?z/pI-,@2:X[͗N^]w8֯I|/UWhnz "_O&<) +.p_)i; EJAh[x++lv&eOp4k-)l_͏7Ơ|/Jl` x~R'ER›c>~COJ|0NFnZkq%vdrl7 +/rCt8"bȚa zu!ZfS;>#*5Ϟ2TY<U5o'R ][2!*7ʹO>SԜ|H=μqf7eFBP +Ux?5 +D? d< ntUfeKds>jIˆR(I;84 ̇%%gp|^]4=#2Gcp!]#+*euAUmt}Rnɨ2^e?i]!g1NSX^GFZLhg*[xO\Yc0FnP9+XtQv>wn乛w(,50S&iGȈ(0|D.="`^b\ p?geW$#tO+VVWdviKվ?9RU޹WȜq3nw/l'(eLo4Ӽ ہ 3J^}9a|YWp2{'bF;MKB'.KzҡBU?+_-u _x36\8R@xL\*@#Ć|e(=x{ZmTG(XP^M貢d킠SA3J* )ˀ}{t^̕J9%'e0 @   d86$α%G&F}Ji=3`¸ŋi->Wk䋱c@O2&[)>V%?wHpq"q{dIP݃atBPEi8)dua:,Fm|u{N@ȁ(F3ο揽W^ &.s?Y6?ZNZߗfP?('g\=D #Paf?ҺF +UnD +Fd4⢙hTexlmXQAxXO{Lb.L {~ՎǪLBb, +"Ѣo&ݖ0!ݿXVVj^ЏE<':O1ykٶxa})zd.pcm(<)Dz |SN/ĿO<fty"/Ew6Yab`(@:ZD-gG 7'ea~TI/c0n2tC*rIь|G~(i($P w~؅q&b,l']U'QLm ^y@]K'M,%R=MW-n*0Esr 8 掣tƂIVD".* +=Id~3M)/QNwF\ՊL^DS>r?bUGwmLj?!+X R̝)yR{,jc +uagZ*Au.^_d[}q) +,drQf|է)*‡lLnIH,WɇTb%Y}Ɓ=2TqXYX{!?[uνtC_0@/\?tJ>n Uے0 +pC=N޶* GgڻP[wa?OY9 +|V5hmPwT('+rui).K"Orczn`Q>k +WȪTo]d@Gzlpfy*;\?Yha#>򻁇LX+>\awUb)Jv/8D+)E.\fM:γ뙐 Ql—$*$ +G5ܒNw5[(7ko·Y+ۓLGS.^vx:xVl>Yi%vkb٬#m :?\'LbлB%1t-\jrst39gJ,kKIxg.%MXZJkBA+*9;&mh +dlۅ3\MslrPݱOx8s~ԱQIĜb" 尴Vs!%3$ +^gc#K}>p:TBv.s|yְ5.+rEmCܙ4ݤ}h,4uYKׄէBUA`:rɼ:5 +FD2K +h+ +s=ۛgHFe2 .W/zYX~-an]8<Z`?x t8d +3ݽmzRy Z$ hϨ?wnJ))t3q}nBAq頽 ^V1 ZJ ]0MRAJ'{GX]Fr+smyx:3zUi[ tUIn~ΎjLsvW_ M5єi4oOpv%bm7 _OC:{AE֕l8&郈)AҼN6I(aqP:IeC,v´Eڪ1pS,Z }xOD]ilc9R#ڕ?+, ͸If,F,QT@E{f%x I%`W4ƽCW&A,0.vCE>wwPPFS~^>i>1u<@tS 3\[hϢKbh%'d۹v PKK)p!9 D_S룳?x|jv>Բ[tK߾ p[WRbg|ehE$?g;:n1& sSypDFM=ZPoNsWo1\:$`UPJb9kTAzy!o|-/FX5CW2/Jq,|arOVq)g +qr2%x;!§U{. +COбeDI +Ȩy: y7DKw~j  jRb<}3H{c-[\W=p2 KL1bn)d&ZR-􏔮v*j:ƠK ?4qQE/qb;49Ta>rVL䳹͐jIiT5P2dc˴Bl2N M)xhxH˔E`D<Ɖ=*" 1B8zE`q'h2gG/}] $zWʲ7: +@~!U101#45z> rH5f-9wtu҇]=CFFy6iL!P2nmbNE N6踫wp+Hq!|:< 29@mGeJy +`/E쌚=1ݏNٻM'ߋ,*,b`>?Cߏuv.9 Q + p>O&g͠ t؜2H]eQCj¶Nk>M(3ӎ hyzPn7+51E# w."Fr&V<>אB|FmhoRل6c[Wsq%/G(qU'sa~0)͏ӑSON~a[~X@hYB&[##Q6jx!B@4eԤaG28Wr𥃾v`薷ljr T̤j4[Ozc. ^Sڴ" ` cug#:Pyև[)63uGv3i`j7ΈW}Y_ea~*|4,kg}dO y,f7 I,tjev7y|(e> =׷ZG)8#&|n~Kr$u|EHiaERVsVW0ٟ1Rf{?if uc#o]b&i" +ts +^'!Y_W6vf (uy85D>>LvVI7;x4Yځ0)$NI#|BJȜ?;mt-=hcZ=3e0jN-YȌXѥ +oۻ +S[qy)|#E!$$DE[=MN4Bs {o+|,<ZqE̶I@pOR {9xp..,XB +̗ƂY8KMk,5hZ p-6h`07ϓ6F6[ Aيm>² =#z&ޯ݈ZrXt%P-nҋ|-2yƣn)[,^{*}֙f⌉EETfԑC0e +OҦl6tgX}%)x$rh7| Mq$9xZXi@JpyY`33'ӓdz|XcjUF1-B{\>?? -"I |p7 ]׳D_]t i0_0J GW?8>I>6_Z$wKVM*XLή:GVO μr}20aۙYݺAiJKS]=Gʮ |TYϫ4;JxMi5 +^ zWyVmL7S^xa@SåieGbs~gUu;)aWF6,+,؈ zt7>m1rA A1oƢCAњVMȶ;Gy@5$`k JK[?Y Tm0$m:G +F{.D%WAI:!tSA %_S fi<RxMYMNY`Y*Aꗄ_4Y^1#4j_64?)t?%aH9{|O-ټu4$p@@ő9(qZ F*L7Bz +| ΄MX.xR: +;g ]y HaW ScOdR'VmDWU~8`F +/Jؤ:&! Q+˓{LjQ)\ +%jU"Bi8A W ; Xw_ٿ32ߖu{7:I +8c+J~U`e ԒV,E[8xx]`-)ߥtf]S qpY9Ǯ+iyrMIlv hD='VzҝaCRQ.,Vï[a0$<[_=a^Q~EߦgťiX"'֒8!;SJkzڍ(4rmVM@I4<dF2o!aǒ'ZmxCBVH5a햎z xͥčCu`[\}Fek{9 .4:>~)4"HR"U5ohhi!yi2MpM<ɹ3z%ĨC UpQ}T>MrQ ޾}gEZOe5ɹGUsɝMjddJ1&#u2rl (Es ?x6ʏ^$y ZK\5yxs+ op@UdX _yܓr"t{hufkY33Hwtw[˟ `Ɨ SgLh5^Sm7:[PL$-֢azSI},`)x{1zigЀ:3l(SSc'6Cv3j ýŠ@nf@ +wA--]8}w\ +Ua!@s g9e9. q}BIO!|- /Xq&Ϸ g9]0 Bԓ h_FXG'C ؊!a`-u&ןBRl~ZU$#Aa|;m/tuȇΟ7N KA?}c9b@k먷 +/qX-vdqcӨ4Q=X +endstream +endobj +404 0 obj <>stream +Hd͎0 +gtEt'DH BUQ|wLC8ٴ]L6ܧ)>3M/p,O9^};m^_5>}.a/]h?&Y}j4+</M e, CocTUMն,?n9zx=6@S`CQI-VNP$(^VDpR FHh ڿTTTTTTTTTTTTTTTTQE!lUJ8\%'$eI<&(Kt(KeIH@Y;*%HXdn$HXЍDt#a{Ѝl.aQG楪[ܯmKk9 +\!%^~)pX_ˁZ={*˯hݳDzwnr.|S>Mi”-mS&}i. +endstream +endobj +403 0 obj<> +endobj +406 0 obj <>stream +H\͎0 +gL7YGM=1&B"d1o_ v#F>_??~1Nq1]?s]s/M2 ͔8vWSUY#-ޖռ4/}h?6vYmn܏_7xOK+ׅ/}BԄ87%ff̹ӛ]['(;OO + + +%A' +4g ( +D@G +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(* +fsV\pֹJp %AYΦ '@Y^vPD (K"@@Yeޣ  gwn$,F"t#a{Ѝl.aQG楪[omK[9 +\#%^~-pXʁV={*ohݳDz198\8fTsa2(erqJc|u)>Y>f, +endstream +endobj +405 0 obj<> +endobj +408 0 obj <>stream +H\͎0 +gn&mĘż}}.dzEg|n||1bnhxsݐ M24,Ie~5t}}zzh?&Ymn ״6xOa1V.<uMϻd coS\טUMն,k[\Zy;6@S`GSI=^AP$(^VBpQ FHh ڿTTTTTTTTTTTTTTTTQE!lzΪ:@ց$;(Kt(KʒH;"eIw(,V{t#a]t#NvЍAHn$,rx\%, +(ټT={mI~+GA^a9K˯9^[9Qg/W<{{HWQ_?=s<& 'ۈ +yNLƤ .Nnot'2e0tez +endstream +endobj +407 0 obj<> +endobj +410 0 obj <>stream +H\0E3_gX.ŴUΞ!MRi2}"WF'˟_}74cMm +ќ38ta^IK=fy:||rvY3-^<|o܅}4Mlĩ~xǷxl~Yx~o%\Ir04:!Nuڽٵ>}ߚ)6˙S7'f#p +l6 +<<)%*P +A' +' (4 +D@K +( +( +( +( +( +( +( +( +( +( +( +( +( +( +( +(*Jfs+(s T!l(K⾃$MN$,,#PDzGA@YUޣ  g7n$, +t#vx=F~u6(bJll׶y[uR.`/k{I8,G˯@^~-GɞZN^^^rK"^^G ̉r.~*ܦ)/28>~LqyʤO}+7dL +endstream +endobj +409 0 obj<> +endobj +400 0 obj<>/ProcSet[/PDF/Text/ImageB]/Font<>>>/CropBox[0.0 0.0 426.0 630.0]/Rotate 0/MediaBox[0.0 0.0 426.0 630.0]>> +endobj +413 0 obj <>stream +GauHLD0+Dj&H9tYn3-0*e9glRWkdcR[i?K\KY#N7)(eh9u\E;]T;"3,,nCO4IO9T[l_eS;LQT%0D;NRKi',1Le;i3D5T5@MI7"q>$%n4,$rfu3V:i=K3QXqen+kEg[rj&]9Fo&B8-6TJ#oe&^_u9q%&@Qrf#oThfTD"k;.\b#*%!/$a`#8"3(4;\'4nKe(7]58jo(X8CI_Pj62r4]%1kf5''(=-CXFCuJ9-C@rJe)X"rl$%JB>$Ths.4`Q6<,O?h3M7k5VU-4=[k85!Ckl)3;eY9U(9QpKqk/30po9TjN`6O0LUNK+RkYW(iT<=U+ZjR:o`mcJ\3cNAP=oWTmOqREj>k!INE+m^d()mNX#6[3\B!X7C`A#A(Wi],+Vp^UdJqqB!qb>iIPEY1qA[ft8Hsf:Z3NT8o&)F>V<(S>c_]9q5[Zeq8V<.0ES4P?U8XarjR-p6\qbWJc;5;Y4e:TNLUn?Q`k\CD7POn(WdQ_b<#9+\&g-D*HQ[G0=*g>b`$>V"#ij\VaC=U@NiKLgL"I`\A*JkBWY,b'HktM=pDl!0$\_X:X,m(nGFR@oLCB88(MUeCb)kc5s'5CoP?R=^9I?YArFmojFlm)3W*P>7o\T'0/m)fZEi"4S??e`iiIAQVj"?Po8r7HRe5/Gm!EaLG?$;1(b_.GJF\bG],4G(SK170$gL)43pK8d]J>qpgJuh9db)%#dPI*_IZFBVsSrO:q-*2LnTdY&[N06%l'#&H`&a;7G?kHL3b&/rr:,lth@mEZeg2YsM,S(S9ft9,c*QhRNRpY(IYM7H'9ZQ[KkT0juPpG`3J65q,^Mpk;5Wn&>Tn(IKF6%j`R@N"j]P>EO#MXOQJPWlJ2(#gM9=fN^+MV*$L:^L,8u(>U&Q)aeZI\GcVbE8bZbqoAP"BAG()2V4j3_/l;NDEs:18Ag#=uf77.l6P:J+AAhn,GhoD?2ejsA6G:e"YWk%fI\aATRt8#L-^1H)_Hp$FRdNKX<%i-;P-)M4cYgC?gOVeLBG,V^dHA&)JLfS\_@#_\*Z*#_kFme1a+2=+bn_lM0&F8",0GWJ/078>m8)R3V`LdOL-=;<0_*65ma#u9X^&[J'5Ib9k;N'BeC#f'TpAJP-V

>3*'O<@BN#SZr0sNcR\U.-,ZfMW5mSg6aCU\N(jk5[e[#.=%X/XU!\*?(UU1>62JQh@FeU'Ed)EB[$TPK3?`3eE'$@t5jBYCo5U'"'K3hY%N.m$qE + +endstream +endobj +415 0 obj <>stream +Gb"/id;fCLN^NdF5FoH`;SLu:!D#hq0&^Ya#rmIja_]6"o?Yt;e^`4#e^`4#e^`4#e^`4#e^`4#e^`2MR=;2-QnB:o)Pb?!WH@kmnKmoLN%bF*7?FUcQ3,OS]UsgPo?&dG"%i"9_q6-slqY!_Cg\J%Uo(r'0Q[LaheQ%Io=+#/`mCHZpe^_.pgV3g2+8j%AlKT;ls1C:>MnU<]_hqMs-O'O_2h$\!+FM(a='$aQs1C:>MnU<]_hqMs-Y7Z/@g2[TL:k)Y-MZc;nQYVhi>Yg&%+Ug!U&MOTV^$8"#^lf*a2SJ'pC3L@S>2h1(o/;gQ")rIP[eVIK^Y;2O>b1[,$tQQ0b#,CaG""@i*-B\V#e15;%kb0C=]#>4ke1Ii`o6']LYp3*kpI=*Mh$jo>-H"AW/Na$I8G^FTOjRo0o-=aM1U2`=77iaCm`@]0uNJV;;@6SO]7@+0-[^P1H,gQRLO/?s*g2>=uR8ni+6rM+KJ!Wq(lg[5qEoHSLerO(=:o4ILm>YB;@P91&%q;PbV7p5J,o(BPQgKGSf='pl#m@s[8YA8@;?mI.>48Bl`&jbZb=_L(=q-A?dNDK!flcFto&D6?\S[nP#UH&6SFq=?\K,F>JMqn.3?TU'dnC.V;2TA.B-buf7JEs1H]AW5rC#c$4F@3KJ=WCo]RJ3rVp.R&B"@UtH2K[4HBY=%EPD*qTdGKD7n/n@`GOi=OFe=^N-nFj*UY,"apV*d8F9i@]F[#d2Z6k,"9TVbBrjPR0kQe)L(F9(&L8]>\'SEUJ&,t[$sP)&6:K_Hf>(CfK4]M85J4W.<4<(L+GJ>iqf]Me;3h1G,8p4S3b=b23<J#s):,R"L$l-@?VhH1$8&XYIik7O=4BFQjp)/M=7lLlsI`_f/Mrh?M#B'#kB'B&gg6&hjA8i]Tboj.kn..lY`/2;_R9IcO.O]?*Yr?pt0J0.IS$$[]Q:X;p_jNDq-W3(PGk&>[EPYXGVX2)8hDtGDd0f<[!T09;p1e,I(L]4X)54N&71oI\Y5,uX:!u5cRSNQ&u+#4%o_,4?T/Uo/,:f1"l[W`oId-q\<:o5$"@j?)a:etE^o^o1;YY!6kE\\E-]F4BXCT938c]FR)_\@Qd(Jd?:dU''h/N#WuE[p'WsiU\B_sUYMl`d[BiTW>=Jr^N(-#`#d8-U]Mc-M9\BN3LFgb$`8K5LT;IN9&3ML;IngP]h/IY9A0i)?b"rIQm^Z#E(feI3>r7/k@I4(*$,W_^0!F?FP5M@IRoG(UGKe9/[BOk[,D[>jej$'q)--;+@ZkdZBTK1Gij/8ASL%Wau_FpBf>L5(a'B%,4'k_tb,D*OQl,G#^1[LAj"HfXRtO9G<**X=?5@jRr3>3EX+8Lh>@eD[C\_Mcu,lkY8@p*&6l6Y"Q'eZ#iP5n`h`gQLQa;RLCs-b60lIo;A8g.,GAb(nFmYBSL'bJk-4^WiNo'rD[#_n0=Lo7HJs6jFOL;tUml?7\!N)M':Y<)*h)08Gu=#]HedA;!'CGH]T.@RD@jJ:p;[3-u4%jO6,A4[BY9)f"sYH'1=MqM'k:]u7DOI&j8j"OD_R$/?]FDf<$rO=H2m'-kIF+$*KbI\$tLq?ekPE`F\I5nH49=8+8"kns_T^2KOo0Jh#;RD?X68X>VEXf?&="lYZ'p$Ldn4p#9!eLQf.ArVt*cqOisDlO/U,rt]*_WOEn.Nh^LQU-[h2Pb=co&kl>8\mn*k`uabCDnCO*o;?3rfZ)R8`[=^7oGi<53&\\B!K[?JQjJbd=c_fB-i\#$c5t>Vb4qRR!Us'=k4N][QKfP.Yol==c*nE0p`^]$GmU^-V7cBRX7.dQK0^@bN3m'ik/!O+pCW`-&-u&n73)O9l[k\#`m-LP5HVO\\-GH8T0fhRVY45+i%2[%1N[KcU*`['=o7WenalTAU:@a!5Y[(7^8hs*PSodnV4b#ZRgD/7GP#ma3H4-!!0#cRFV&1n]"QB/'HogK;)*E1%]tT69,d/4AARbj\;@7O.kt>5_q5b]$h^#`7ftUc]9mB+o-#H(Y#V'b'A%YsD.E!+H=D"WW^UHcpih4]$GuC#eD(Jn&[`5i9?%eOP'>$0fK)tHhu,iO:dI8_!+j>$?6_L!;i9<.;(f?WmT\0bF`+9CL;hG,\cGXUF'--OLHj>Ug+BDcq]mS=n.Di$G>dE67\*Q)&.jD7Y5jOBL69tQZPG?a=f,]\A8X5`Q,U!Q"7MO+,4Bh3Z'-0i/.ZA1bTqZZ]"qDJTqN9A:?&=X.!QCm$+?K)JUMIOq:S!?5c*e0AKus+M;]%3JG%K*!%uG-;Y^c92@Fmj%3]B`[t$i%#N?pfKD[4+?XAY8#o)?&PE?r[;k:A)*CKF+Amh!N_(HH*B$U=.`bBm9"S)CEq?,[XhrH/7#u=;9G1`i,f(=ZSr&dk7hD9!;l@f+Ea-DH;,t!4:QX*]@gS;T$g7.U]W=,Fn>)V[?A;9sK5;Ej7'#?!ZQp09hk2`:iT]3).:SqmI-lGpS.ZKrbuR$!2hF=8,Is0Ek!bA.mk4@,.EJ.:0`J2PP+(K)VG!aV&BDk1-*`^tMS8W-rHIdY_5/(m3EBBTC0E-1B6YFH2CpHF<9OgtY=g;H"lXaCNks\YI>N6^b[%C(0[n"Q($!u.P$.S-7*V/I#gYSENY0)O;V?*DdEtkn`J2JMRCe/K:ut7g&l5c4OC,#u4C`1KYA1C$ac:g##Se:j.fAN1lK"$EcOq`WEM+G%Alp,>NN$7Vd[*0IaUMtt`J1V`YD^g\;C>sV.#=+8OZe7_U6kE[qKa6:P&YqB]6@+;A8u_!;S&"7."'#bJVbK&qLHT8U.JZ6e3,ss$]K/p?!fnZL9Yb8(HQu(:-)ib11o^;#'.JXig*8.3X.iAr_S]plG6k?a(goWE;Q;AjQ4t:30F"MI+u#?s#7A=$2sCug10#:KDJ,&qoF(/kQP7%5&0?1A&,"2/'?5/SZ[K(u-9diQ4=^[j/K'V2GKB9d)(tZ/r&NiCB3,feEl,>HK^IU$8`":D@i<,iK)EWUD`d##b)qu%O2'["*1jLU^lO5?E7mc.YJ"M/`5h4N6NlA]4Wd284-UsA,J4J>[544NFSto9)nHOpco5"sBU)Klp$Li!d5^Y+]B7_8=4mCu:am2MJFdY>l^BiLP&#]*#GqI+Zg@Y0-?"Aa6^HLiA'ZoZ40PQr!Rm!g@#[]kQ(SQmKq*$r\pXW"9L?Si[HG7,5F<^pHQh*=tu'<5D(KLL.XVrn[mD)=ruhH2Y,_S5fkdkd8FjE>`#XRKrfdDEN'(C;Sc>b4g_VCAj(]dbrL0(t8)O*,QJ/b5Zd`A'a%H#aq"6I4a2'lTNr4%SAYr)Ui>dc'cV[9\6_Y;hT*O5kGNL/hk5$h>ZHI2o'J]t19JZ3l2sW@-"jV_LHj*:U&"nUY,LJS<%&TMI$$RDn9ri[Xnk*V]O^@$l:Y972Bd?H0V[-gKQ=MhK()Lb\?5Tan3#;IO4;HG;&(#cOr2_oB`KRTq#ts+M<"#VSJnT8`R<-Q,(1e4R;CDae6[*>CFdNPdAUKK[9"HS1&Hm*`>i"rqP5Y$;^D"gHIjEIm$(1Rt`C/jG+c7JC6XH/^BI*>?m>HcN:^Cr\g2(OmqAqh-W@RM&WnG$c5OW$TCrO#16FK+d;'^>b?aN.=%qGHb3#fg624A9Gn>A8N',1E#\1#5_lAr[]]H!SeFW3qm0bq+n9gVH)kC[l,Gnir97kKdcVB@/+ck8o#)'/*KHY5#9iRM(GWKLP'Q#P;$WXBXhG#k2!Ns[Q>gon5uDr-f,k)7$5ED#VQ0iH%+RCaL1W_I9&$Gp`If]:@#e96Hlir`%8*#FZDmuqsoP$R?(G$^8[:WN8MW]McXe5hU_hVK/Cb#KJQb1&Gj>U9[5h/WFK9n]Wd5G__,9NYb%=Bo=fM:s*Ymu?qr>m#W$\7b!UpT=+I+o*?$02gnqYAC"Y6ZrjSgKOhCj;i];e1AHBRj)V'IX8`f2pNlpYA#>p*,i/+It">lRp)LqPItrep7pe+d2"Cs=\1K7TnR;Q"Q>OpGn.*QD-h6;UV;Q$ZM#3EDRCp3M1o>-"QAsIjlI6AcHT-jQk^Q@&$u&oC)m*GX*e%hhWm-k&3dX,Q+S_DEQNnr&nAhRg)62o)5Yp=D&Nf(2VjRVNeY[e^gR,#h8:dUa&3'e,4hJ+Js6>Anlj>S?aC8[qJ#*7GN]fc"#-)F/nG/5>RnD6u0C5U`DEif"'GV%`IN?A3=Cu_7IrVnYpj:]?\3(FP:=G]Z[;G1$X"X(K_-)ehlahDLa"8g[f"*-sWd1-lO=!s0,Af89s`_-8LfLi/8Gl5%C`sB4ZPFiAGnbS>8!Zib"_fD_Z?F>Bi`$pYW[;=$.kYTo/3mXkCFD+F$7L?s'E=?iei!O1b*D7KMW>D@nI`kC;"kCQd,[%o@O&Mn^_XhaUEN7q(/@\A&=msV;Ya8Nor@O7EZ31Z?5XSk2>_04'(Z^@pGiD]='r,81MW@UgCC-4#/WmCE!=j"40YC[jZ)7oF_dtr%@.=uLb/6#I/.%In1;ELJWB0tCU1=Y&D5#;f^bi23gMD+*T4k_#F!f5*fMVXS3?cBrZJPGbT1oXR^-h2U+o-B6fr<,#&cLChW+MmjEZ6\`$6Df6D,#h]Y`OPk6n(j!ihQD\:euH52HJ^m!PmVXeN02N;c(AXpH]GY7?kI2d4[;q0sHPL+0JnnW?6>s96mD9FSYn?r-MXf#pOg<&[#Z*>bro+[uGcW7`BO%:nP0qG$!DPUu%f/PZhq).k&N<,[\ccg\'8og5Xh1>oQ;DM5K``DmNSF*!?C[>jU@k=If):=k.r#iCgWK;PR4NKTeMmm'h20P:F0pY_nN9Er'IZ<'lCqNg?3.d>2a2TUD#&e7Gr;TIW+@X5(J+TpHXo*Et/"b\=[S0Jc5Pe"]`j)e#nAuK'Y7iF8SXW8+*kZf*;R0RM(h%sX-%?kA_\B5)nB#Y=#6FFoe\;TV'H\WI^%R)C2kZ*#\atpZYa2bDJQ-\&VN)X`Z$OAHcB-MDHqV8E@I:#GtNI9"#a90)4lf9LBta92<,.4Z9=P`<'kBP5OpI:cg']l)^ukdKM$nqq@GrA[H;Ks,0q%q8VPYYSq@DIU8)m_H)gO2Y;%Q#f96(W-8XB(tp`MKh.?MH(JnpI[\2n@4RBT(j``6"Q@m6N9bc&KbdHb+fPaX,1Vo1WoJST63k,.hTuNK--1!Uj#M?f-C4%!ThH&.LVPKoqW@B`bPAhXGu$MJL`j@8%*qP'`"ahgQ<0kr&@+k_/lP&naEuXg6NlA]EHn!*R$F3k-bDh+-L)Lm:fRlP.-[.VSfe;Wmj!N%VAN:o8eq^CX+R>Y'M\m'n0Z;ROR&=o3sGF9'<0B)rsVn*<@pu9In&&$H0PZeGE_^o#f%;XmocjFX_BUR*?It9YX]8]R==T12W6REo'[I#cmke##'/@s^L*)[>^sp88[`MZo1KaB!#$CT12mkN?HPDW#VV7QCQ1GYPE*H!k2/&S0*N;@Fl4kBNlM=^q)Ec5%W%/&;Wg9RSa_?'Varr#NX8G0a#tUPDf8W;c>eAn$K4YST&m4W[4SrGnorG'aD\.*8]BGJhDan8c(qXF1,Z`!op8N*#d7"qmA_2uT]QoZ&tHr<9@td$hlu*?]C$%2K&a4fJJEe+%4bajSWrXZN"tFB)=m(XR,FV2`c'6@KPsu_lKY2'TD-?Dd2.IS=Rk\AUu7m>`c'6@KPsu_lKY1(Y@+HGSc@t)0DMf5eQ9Xq?'XW&`E--uY58r@?%'?!r@80Q.\0),@+U"e`j9$lL[hQ=/0p7"%>76dacl]Sc1m::60MYlb;KcmJeF@bo*5%^U=3#hAeK;I3GCcA2A9LDtEpr-8Z#[R<6[*nO@k3?V6rObt3YgWN:Mr_l[9i1ZX6GmX1Rc#bINu^&]0.bY^mZN.Z,nM#41N&$?s@%$UO9_t@E!2(=,b5^C0"[gO38&pec]%&WnS\?I1Agf#UoKW"ND_$fF8&pec]%&Wn*PEV_@+<%-RZDcrBkjZ9\*[5R+@c!X:kDQi;eUX@Z%@g%WNU$m\Q,Q37r?fQL[jMVga\pX9s$;Ek'];04DLh_[juPa[9G?4*-KlWq`!aFnA(;mOU@XTmIpOW4\-N\Q:-u'#joEUpA\Q#=d9PuTej*SCe77$Nh?k%VtJRID,9O7r`r=I[^&n!D?cj,G(T&$3qIe7,JnjXE7=\i/'eI^ZLsoRU#q*aEOS[ld!TMKe-I5lRUuj'X1ABBNIs+ck"'iZ78TaM3sa*3@*PlrN&Jpq2X=mfW(Kr_h`qYe9AVTtoRS#Yc/0PsK!Y98U^*164V0W1_!I%2kiYK7j-!`8b7poni5na"-drc41da#h<9S4:VRfI]5HOnHuCeZc4ndR--+K*X>n53`M^3/:Y,uD)).S0-qYEj3I]'E8!p&4JO`MPN*qc'DK6C"D`$AaC?WC[5j[6bAiL>M+:l\$$OmFc;;?Xc-cMnQHPe0pj8\UeQM(qIi_7A;;/Pegug6(h[;T'P]7bMeJlLVD;Kq>F>/#.qQu#kKuof+TBcqoPd[^1-TW*X+ar'3[)1nKci3/5l(bUo$?`1td2UM(]gXkLM>u8>K(jl^F'_=Pdj_)FK?SV!DN$(FJWE7LmD!]I[Df-#D>sj7!>H1phbEZ^%1;n(X+j$Os^_+gn![1^`J4nThU#W4%BYk!s\!jk2NT1G/9-T,BhM^cJ=m01N[,C95OHggGrH-pmB@1HsY.Sc*XNW.HtI-mKX"7>"QFkCZf0s"$NMK(uh2X-OZ6-,d$XbRfQuW-CE&CRsH)^/BD,r4E+=go<$21P#hDBblCD"Eh<5Xqb$6Y/.VLb%:GJdN."6C^0SiE2G?^=IYK.B+k;^\XWt=#78c>0i3/I08SC]QUfARpVt*.MOHODbRs%;Gbf0NFKA`r_o,OF'TQf#-YZ3kX/!WVL]]03HWi\D`s/3d8b9%A+nsY;M3J4H2:%mMY!DA3/\(DI\N8s&?mdc.OXh:2Ce,ccSGUHf1F\%iDCjg/L19MnYtPMGl0d+\".HN/a2K">Po_'s6PB1E4>Vbe^`3FUlQr('hc+3/&&Su9)XS(YLN1GUd:GN#8&MC.X8g]JE@&BWX/i91]&2u,e^`4#e^`4#e^`4#e^`4#e^`4#e^`4#"T8^E.F;)~> +endstream +endobj +416 0 obj<> +endobj +417 0 obj<> +endobj +418 0 obj<> +endobj +414 0 obj<>/Font<>>> +endobj +420 0 obj<>>> +endobj +421 0 obj<>>> +endobj +422 0 obj<>>> +endobj +423 0 obj<>>> +endobj +424 0 obj<>>> +endobj +419 0 obj[420 0 R 421 0 R 422 0 R 423 0 R 424 0 R] +endobj +412 0 obj<> +endobj +427 0 obj <>stream +GauI7?#S^l'Sc)P("PuJ]2EY2HgF^3"^1&PP!B,]\`ib(E=>NN0XXX'o[iiiJ7hP00o<8p#fEq1q`O=-1S%+tX=#T6'5K@?+IaVB$>\5.(4nbe$"d]![04?)&rnhP=FYe3[G\YmTn8hXY;r)VDWKBp?ZpUGiR(fi0IFX#WW79K_=Pj%VRA/09?*2hY!BY)7/i-a9IGLH8aZ)MHnr+7g0eL@h1W4oL',dud8Y_3dt"XDT^2/`?>kY1P5\2teWgPKRoMr@KM41jIqdr]_]Fr%+>6Xp(dUetquna%f(^A9_apBs<@[&AVI-?6L$@CR3*F;YdLTY3QaoMJqb?mj.gGp+&,+TR4F*Jk-DdU#.#\8s8cS:Gp\RW65<21Z51!X_Q.W45Or+]^U?+4fK7)L4&K='&RN#lJnqbd@HW//OZbL&?>qgU=bgp4:_8kY(MJB\p9XZ?nCWHZhY3,=t\R6NiE[qsUQ@]g:\&efK7V&PI(BcfDQO>6_\\OV(&t0[W)'r?5spO?$Ys-oVBq8?>#N)46Qo>d8HU%]F%W[CDi%1>fMAZC+M'Z/^0b(=AVW%GYqg8NdP3_4$"b+f4"E=$`o'_(mn(kUQ'EE!;[*Yj3%r]LiIhRZLhqgd?!lLq\b01^LuA2NlM9*#`1PIQ%XLjJ'R]5FeHGT@LJcA^o`dMM?Sk7hIot>U43l>.H&Dr&k`+J[Q84k`,pc3Ir@unCoD/(hF"e(/];l;.N-n]6cF5>/mLb!_.jS#"Gs@7KfH#J^NUJa:QY?9G9N7R@qMe%WB?go]Nt,KP#V)Fu$Oh0VLXO935SOb$ntD3"AUl'@_9FsZWPkFTUZp9QBC*U/n]F,mo/(th#0OTbkl_RA@RDq(U,Z2[d_-._FpF"pmk!mAS/O*tDi(0!.4bd/SKfh^.$oljn!0'P=M:6sEkU6iWlZJE4&ePO:/6ZYIZH*@@Wt`1^m/Fl_qS/,Of(ZK7YTWfdj0MIS'0GB2h_usd\tc9O2b`_kT8A;PA%BJ>%7,50MbJ?H75XELqTIt\]lEo98NM3.rSqE^](qDg$mu"UcmrQYK'02(^/"DPZiZW`&;PT#Ss35>-llS_sU2kECTD/G%AbmE>TB,UfBs+9+[K"jY%Nbr<9Vn8%\/P0*\mk-jE7rZQ7cmE7-m61*7mUl_L@,,qKQ4kAn8G$d)p=/R=U+nqm^K6^>HYHcBX=>n@i%_u_bSKhkO5Z'\VJ^.NGmeWs#XWNB7oIr+4EoD~> + +endstream +endobj +429 0 obj<>>> +endobj +430 0 obj<>>> +endobj +431 0 obj<>>> +endobj +432 0 obj<>>> +endobj +433 0 obj<>>> +endobj +434 0 obj<>>> +endobj +428 0 obj[429 0 R 430 0 R 431 0 R 432 0 R 433 0 R 434 0 R] +endobj +426 0 obj<> +endobj +437 0 obj <>stream +GatUrD0+\p&BE]".J/@_A>Uc$QCUdK"%fX#QV14qg?J8+_D)Cr_04,V@Iie96U9r?#jDd#aD8!OpM,2il:%h=:E!rk:itS==:uN%1hffTgkR("0F^CF#fT18-q_nE7tMeWIo%t(H;]L>dM4`U^3#O3`/9A9e#!"Lfs*-$O&:[(igc$H$?L+mP9n6'ijg0*bVXdSH/U>P^5.\%G[tLN%i[6D,Nb8;WC&5f63\:PGA"7A^Y7r@rn6!iRKC#eo46+_?g%04I$*JmT%_+e7V+HcB"gbh@g!$'2coq!cgXFg"7hi_\#sar#E6DjGb7"uaWB^hJCAm#S7;M'qK&12!Ep9mZ0J1Jge!#u`boZ$Bhg(V+3%lU+F.:fhl^qMiiM*(mdqolM0d*RB671I"bM)kfeUu&7DD)p:q1[Q>I!4?.4k9p)[_Kk>U]PKZ&*/BHSs)GtStm\`I4VF8C]FRHNgHK!D,rimHL#3B'm?[mp1R7ZE@O:kao"4_[RqWKQ(H/8(gXPBWr-h6)AI\1GTLNVAg4`Z'uq0RHRJiklE%9`IEOd+Z'[1,e<3VUtSpcP*B@GUfp0rcGNpa#n_On.b+i]Q:n0`+CWMra;mr,d-eB'WPbbHLq=S\hL=ndRXfhb!+:Cm!*F1W@"M5d=LTi`X2>,eG.DE>+FtS.;U+4L5/C.c=q-.c!Lb,)Za!6a&p>kZ'Fn7DVCLFTq_#Lnm,'Jlb=og@-g=a]i.E#^mi:hfa+kb6F#C0<[nSJ+"Xr?r`MU]u7<>"]_SoL)'o[W4gal[sufF=k,:"&B`9'ms.C>G!WF[WC_O)W;XH/VjbMcOY(q0sB*76e^F@i`D9W];OtlfQ9(N#f?>/dQ@ENCLg'[gDM1>BUN$-rpUg(Gk_Vb[RjH;BX*H+\CAf)Wg-#%tB[2mK20YW93XF6=A+,PiMGB@S.~> + +endstream +endobj +439 0 obj<>>> +endobj +440 0 obj<>>> +endobj +441 0 obj<>>> +endobj +438 0 obj[439 0 R 440 0 R 441 0 R] +endobj +436 0 obj<> +endobj +1 0 obj<> +endobj +442 0 obj<> +endobj +443 0 obj<> +endobj +xref +0 444 +0000000000 65535 f +0000608882 00000 n +0000000000 65536 n +0000014096 00000 n +0000000015 00000 n +0000013419 00000 n +0000001570 00000 n +0000013128 00000 n +0000013224 00000 n +0000013321 00000 n +0000014058 00000 n +0000013522 00000 n +0000013734 00000 n +0000013893 00000 n +0000000000 65536 n +0000045522 00000 n +0000014205 00000 n +0000015194 00000 n +0000016003 00000 n +0000016862 00000 n +0000017729 00000 n +0000018599 00000 n +0000019422 00000 n +0000020294 00000 n +0000021168 00000 n +0000040552 00000 n +0000039915 00000 n +0000041293 00000 n +0000040665 00000 n +0000042034 00000 n +0000041400 00000 n +0000042882 00000 n +0000042144 00000 n +0000042800 00000 n +0000042775 00000 n +0000044678 00000 n +0000044044 00000 n +0000045417 00000 n +0000044790 00000 n +0000000000 65536 n +0000062688 00000 n +0000045880 00000 n +0000050469 00000 n +0000060371 00000 n +0000059744 00000 n +0000061104 00000 n +0000060477 00000 n +0000061837 00000 n +0000061209 00000 n +0000062578 00000 n +0000061944 00000 n +0000000000 65536 n +0000078806 00000 n +0000062972 00000 n +0000067323 00000 n +0000077218 00000 n +0000076590 00000 n +0000077959 00000 n +0000077325 00000 n +0000078698 00000 n +0000078069 00000 n +0000000000 65536 n +0000093562 00000 n +0000079064 00000 n +0000082577 00000 n +0000091252 00000 n +0000090625 00000 n +0000091984 00000 n +0000091357 00000 n +0000092718 00000 n +0000092090 00000 n +0000093454 00000 n +0000092825 00000 n +0000000000 65536 n +0000110626 00000 n +0000093832 00000 n +0000096848 00000 n +0000106944 00000 n +0000106311 00000 n +0000108723 00000 n +0000108096 00000 n +0000109462 00000 n +0000108828 00000 n +0000000000 65536 n +0000136949 00000 n +0000110888 00000 n +0000115639 00000 n +0000131655 00000 n +0000131021 00000 n +0000132399 00000 n +0000131765 00000 n +0000133138 00000 n +0000132511 00000 n +0000133873 00000 n +0000133244 00000 n +0000134622 00000 n +0000133981 00000 n +0000135367 00000 n +0000134739 00000 n +0000136102 00000 n +0000135474 00000 n +0000136839 00000 n +0000136208 00000 n +0000000000 65536 n +0000154451 00000 n +0000137269 00000 n +0000141929 00000 n +0000152867 00000 n +0000152237 00000 n +0000153605 00000 n +0000152977 00000 n +0000154342 00000 n +0000153713 00000 n +0000000000 65536 n +0000172408 00000 n +0000154716 00000 n +0000159353 00000 n +0000169341 00000 n +0000168712 00000 n +0000170080 00000 n +0000169450 00000 n +0000170818 00000 n +0000170190 00000 n +0000171554 00000 n +0000170926 00000 n +0000172296 00000 n +0000171661 00000 n +0000000000 65536 n +0000187886 00000 n +0000172715 00000 n +0000176920 00000 n +0000186303 00000 n +0000185673 00000 n +0000187041 00000 n +0000186413 00000 n +0000187777 00000 n +0000187148 00000 n +0000000000 65536 n +0000204348 00000 n +0000188165 00000 n +0000190629 00000 n +0000204239 00000 n +0000203610 00000 n +0000000000 65536 n +0000220366 00000 n +0000204587 00000 n +0000209036 00000 n +0000218029 00000 n +0000217400 00000 n +0000218776 00000 n +0000218138 00000 n +0000219521 00000 n +0000218891 00000 n +0000220259 00000 n +0000219631 00000 n +0000000000 65536 n +0000237529 00000 n +0000220644 00000 n +0000225281 00000 n +0000236681 00000 n +0000236051 00000 n +0000237420 00000 n +0000236791 00000 n +0000000000 65536 n +0000257359 00000 n +0000237781 00000 n +0000243244 00000 n +0000253527 00000 n +0000252885 00000 n +0000254275 00000 n +0000253646 00000 n +0000255019 00000 n +0000254384 00000 n +0000255761 00000 n +0000255131 00000 n +0000256509 00000 n +0000255871 00000 n +0000257252 00000 n +0000256624 00000 n +0000000000 65536 n +0000277460 00000 n +0000257663 00000 n +0000262644 00000 n +0000274365 00000 n +0000273737 00000 n +0000275102 00000 n +0000274473 00000 n +0000275849 00000 n +0000275211 00000 n +0000276606 00000 n +0000275964 00000 n +0000277353 00000 n +0000276725 00000 n +0000000000 65536 n +0000293449 00000 n +0000277751 00000 n +0000282424 00000 n +0000292601 00000 n +0000291971 00000 n +0000293340 00000 n +0000292711 00000 n +0000000000 65536 n +0000311427 00000 n +0000293701 00000 n +0000297987 00000 n +0000308366 00000 n +0000307737 00000 n +0000309105 00000 n +0000308475 00000 n +0000309843 00000 n +0000309215 00000 n +0000310582 00000 n +0000309951 00000 n +0000311320 00000 n +0000310692 00000 n +0000000000 65536 n +0000329004 00000 n +0000311718 00000 n +0000314978 00000 n +0000325938 00000 n +0000325307 00000 n +0000326676 00000 n +0000326048 00000 n +0000327412 00000 n +0000326783 00000 n +0000328156 00000 n +0000327521 00000 n +0000328896 00000 n +0000328268 00000 n +0000000000 65536 n +0000349260 00000 n +0000329295 00000 n +0000334425 00000 n +0000346187 00000 n +0000345558 00000 n +0000346926 00000 n +0000346296 00000 n +0000347664 00000 n +0000347036 00000 n +0000348410 00000 n +0000347772 00000 n +0000349153 00000 n +0000348525 00000 n +0000000000 65536 n +0000365292 00000 n +0000349551 00000 n +0000353465 00000 n +0000362972 00000 n +0000362343 00000 n +0000363709 00000 n +0000363081 00000 n +0000364446 00000 n +0000363816 00000 n +0000365184 00000 n +0000364556 00000 n +0000000000 65536 n +0000383685 00000 n +0000365584 00000 n +0000370739 00000 n +0000380603 00000 n +0000379975 00000 n +0000381340 00000 n +0000380711 00000 n +0000382079 00000 n +0000381449 00000 n +0000382831 00000 n +0000382189 00000 n +0000383578 00000 n +0000382950 00000 n +0000000000 65536 n +0000405380 00000 n +0000383976 00000 n +0000387858 00000 n +0000400786 00000 n +0000400158 00000 n +0000401529 00000 n +0000400894 00000 n +0000402282 00000 n +0000401643 00000 n +0000403027 00000 n +0000402399 00000 n +0000403763 00000 n +0000403134 00000 n +0000404507 00000 n +0000403872 00000 n +0000405261 00000 n +0000404619 00000 n +0000000000 65536 n +0000424413 00000 n +0000405697 00000 n +0000409902 00000 n +0000420582 00000 n +0000419947 00000 n +0000421323 00000 n +0000420694 00000 n +0000422060 00000 n +0000421432 00000 n +0000422795 00000 n +0000422167 00000 n +0000423538 00000 n +0000422903 00000 n +0000424294 00000 n +0000423652 00000 n +0000000000 65536 n +0000443703 00000 n +0000424717 00000 n +0000429077 00000 n +0000439879 00000 n +0000439249 00000 n +0000440618 00000 n +0000439989 00000 n +0000441355 00000 n +0000440727 00000 n +0000442097 00000 n +0000441462 00000 n +0000442839 00000 n +0000442211 00000 n +0000443586 00000 n +0000442947 00000 n +0000000000 65536 n +0000459588 00000 n +0000444007 00000 n +0000448866 00000 n +0000458740 00000 n +0000458109 00000 n +0000459479 00000 n +0000458850 00000 n +0000000000 65536 n +0000479043 00000 n +0000459854 00000 n +0000464165 00000 n +0000474454 00000 n +0000473815 00000 n +0000475200 00000 n +0000474571 00000 n +0000475937 00000 n +0000475309 00000 n +0000476672 00000 n +0000476044 00000 n +0000477415 00000 n +0000476780 00000 n +0000478167 00000 n +0000477529 00000 n +0000478924 00000 n +0000478282 00000 n +0000000000 65536 n +0000499196 00000 n +0000479370 00000 n +0000484651 00000 n +0000496126 00000 n +0000495498 00000 n +0000496863 00000 n +0000496234 00000 n +0000497602 00000 n +0000496972 00000 n +0000498347 00000 n +0000497712 00000 n +0000499089 00000 n +0000498461 00000 n +0000000000 65536 n +0000529566 00000 n +0000499487 00000 n +0000505867 00000 n +0000523191 00000 n +0000522553 00000 n +0000523941 00000 n +0000523306 00000 n +0000524690 00000 n +0000524055 00000 n +0000525430 00000 n +0000524802 00000 n +0000526177 00000 n +0000525538 00000 n +0000526923 00000 n +0000526294 00000 n +0000527660 00000 n +0000527032 00000 n +0000528400 00000 n +0000527767 00000 n +0000000000 65536 n +0000563028 00000 n +0000529912 00000 n +0000536660 00000 n +0000555153 00000 n +0000554525 00000 n +0000555893 00000 n +0000555260 00000 n +0000557811 00000 n +0000557057 00000 n +0000557727 00000 n +0000557693 00000 n +0000559616 00000 n +0000558978 00000 n +0000560364 00000 n +0000559731 00000 n +0000562160 00000 n +0000561518 00000 n +0000562914 00000 n +0000562279 00000 n +0000000000 65536 n +0000587430 00000 n +0000563349 00000 n +0000570246 00000 n +0000585103 00000 n +0000584468 00000 n +0000585847 00000 n +0000585217 00000 n +0000586586 00000 n +0000585957 00000 n +0000587323 00000 n +0000586695 00000 n +0000000000 65536 n +0000602994 00000 n +0000587708 00000 n +0000601659 00000 n +0000589802 00000 n +0000601362 00000 n +0000601460 00000 n +0000601559 00000 n +0000602936 00000 n +0000601772 00000 n +0000602002 00000 n +0000602236 00000 n +0000602470 00000 n +0000602704 00000 n +0000000000 65536 n +0000606565 00000 n +0000603110 00000 n +0000606499 00000 n +0000605111 00000 n +0000605343 00000 n +0000605575 00000 n +0000605803 00000 n +0000606032 00000 n +0000606271 00000 n +0000000000 65536 n +0000608766 00000 n +0000606681 00000 n +0000608724 00000 n +0000608024 00000 n +0000608253 00000 n +0000608494 00000 n +0000609183 00000 n +0000609229 00000 n +trailer +<]/Root 442 0 R/Size 444/Info 443 0 R>> +startxref +609385 +%%EOF diff --git a/test-cassandra b/test-cassandra new file mode 100644 index 00000000..7c8f7ee2 --- /dev/null +++ b/test-cassandra @@ -0,0 +1,93 @@ + +from cassandra.cluster import Cluster +from cassandra.auth import PlainTextAuthProvider + +import sys + +def init(): + + cluster = Cluster(["localhost"]) + + session = cluster.connect() + + session.execute(""" + drop keyspace if exists trustgraph; + """); + + print(1/0) + + session.execute(""" + create keyspace if not exists trustgraph + with replication = { + 'class' : 'SimpleStrategy', + 'replication_factor' : 1 + }; + """); + + session.set_keyspace('trustgraph') + + session.execute(""" + create table if not exists triples ( + s text, + p text, + o text, + PRIMARY KEY (s, p) + ); + """); + + session.execute(""" + create index if not exists triples_p + ON triples (p); + """); + + session.execute(""" + create index if not exists triples_o + ON triples (o); + """); + + return session + +try: + session = init() + + session.execute( + "insert into triples (s, p, o) values (%s, %s, %s)", + ( + "http://example.com", + "http://example.org", + "http://example.net", + ) + ) + + session.execute( + "insert into triples (s, p, o) values (%s, %s, %s)", + ( + "http://example.com/2", + "http://example.org/2", + "http://example.net/1", + ) + ) + + session.execute( + "insert into triples (s, p, o) values (%s, %s, %s)", + ( + "http://example.com", + "http://example.org/2", + "http://example.net/3", + ) + ) + + rows = session.execute( + "select s, p, o from triples" + ) + + for s, p, o in rows: + print(s, p, o) + +except Exception as e: + + print("Exception: ", e) + + sys.exit(1) + + diff --git a/test-trustgraph b/test-trustgraph new file mode 100644 index 00000000..5d6950e3 --- /dev/null +++ b/test-trustgraph @@ -0,0 +1,82 @@ + +from trustgraph import TrustGraph + +t = TrustGraph() + +t.clear() + +t.insert( + "http://example.com", + "http://example.org", + "http://example.net" +) + +t.insert( + "http://example.com/2", + "http://example.org/2", + "http://example.net/1" +) + +t.insert( + "http://example.com", + "http://example.org/2", + "http://example.net" +) + +print("====") + +print("====") + +rows = t.get_all() +for s, p, o in rows: + print(s, p, o) + +print("====") + +rows = t.get_s("http://example.com/2") +for p, o in rows: + print(p, o) + +print("====") + +rows = t.get_p("http://example.org/2") +for s, o in rows: + print(s, o) + +print("====") + +rows = t.get_o("http://example.net") +for s, p in rows: + print(s, p) + +print("====") + +rows = t.get_sp("http://example.com", "http://example.org/2") +for o, in rows: + print(o) + +print("====") + +rows = t.get_po("http://example.com", "http://example.org/2") +for s, in rows: + print(s) + +print("====") + +rows = t.get_os("http://example.com", "http://example.org/2") +for p, in rows: + print(p) + +print("====") + +rows = t.get_spo( + "http://example.com", + "http://example.org", + "http://example.net" +) + +for p, in rows: + print(p) + +print("====") + diff --git a/tests/test-embeddings b/tests/test-embeddings new file mode 100755 index 00000000..e2bcdbde --- /dev/null +++ b/tests/test-embeddings @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 + +import pulsar +from trustgraph.embeddings_client import EmbeddingsClient + +embed = EmbeddingsClient(pulsar_host="pulsar://localhost:6650") + +prompt="Write a funny limerick about a llama" + +resp = embed.request(prompt) + +print(resp) + + + diff --git a/tests/test-graph-rag b/tests/test-graph-rag new file mode 100755 index 00000000..c6abfe05 --- /dev/null +++ b/tests/test-graph-rag @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +import pulsar +from trustgraph.graph_rag_client import GraphRagClient + +rag = GraphRagClient(pulsar_host="pulsar://localhost:6650") + +query="""This knowledge graph describes the Space Shuttle disaster. +Present 20 facts which are present in the knowledge graph.""" + +resp = rag.request(query) + +print(resp) + diff --git a/tests/test-llm b/tests/test-llm new file mode 100755 index 00000000..35177e81 --- /dev/null +++ b/tests/test-llm @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 + +import pulsar +from trustgraph.llm_client import LlmClient + +llm = LlmClient(pulsar_host="pulsar://localhost:6650") + +prompt="Write a funny limerick about a llama" + +resp = llm.request(prompt) + +print(resp) + +llm.close() + diff --git a/tests/test-milvus b/tests/test-milvus new file mode 100755 index 00000000..e95955dc --- /dev/null +++ b/tests/test-milvus @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + +from langchain_huggingface import HuggingFaceEmbeddings + +from edge_map import VectorStore + +client = VectorStore() + +embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") + +text="""A cat is a small animal. A dog is a large animal. +Cats say miaow. Dogs go woof. +""" + +embeds = embeddings.embed_documents([text])[0] + +text2="""If you couldn't download the model due to network issues, as a walkaround, you can use random vectors to represent the text and still finish the example. Just note that the search result won't reflect semantic similarity as the vectors are fake ones. +""" + +embeds2 = embeddings.embed_documents([text2])[0] + +client.insert(embeds, "animals") +client.insert(embeds, "vectors") + +query="""What noise does a cat make?""" + +qembeds = embeddings.embed_documents([query])[0] + +res = client.search( + qembeds, + limit=2 +) + +print(res) + diff --git a/trustgraph/__init__.py b/trustgraph/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trustgraph/chunker/__init__.py b/trustgraph/chunker/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trustgraph/chunker/recursive/__init__.py b/trustgraph/chunker/recursive/__init__.py new file mode 100644 index 00000000..3b816664 --- /dev/null +++ b/trustgraph/chunker/recursive/__init__.py @@ -0,0 +1,3 @@ + +from . chunker import * + diff --git a/trustgraph/chunker/recursive/__main__.py b/trustgraph/chunker/recursive/__main__.py new file mode 100644 index 00000000..18e14ad5 --- /dev/null +++ b/trustgraph/chunker/recursive/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from . chunker import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/chunker/recursive/chunker.py b/trustgraph/chunker/recursive/chunker.py new file mode 100755 index 00000000..ba5eb939 --- /dev/null +++ b/trustgraph/chunker/recursive/chunker.py @@ -0,0 +1,164 @@ + +""" +Simple decoder, accepts text documents on input, outputs chunks from the +as text as separate output objects. +""" + +import pulsar +from pulsar.schema import JsonSchema +import tempfile +import base64 +import os +import argparse +from langchain_text_splitters import RecursiveCharacterTextSplitter +import time + +from ... schema import TextDocument, Chunk, Source +from ... log_level import LogLevel + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + output_queue, + subscriber, + log_level, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(TextDocument), + ) + + self.producer = self.client.create_producer( + topic=output_queue, + schema=JsonSchema(Chunk), + ) + + self.text_splitter = RecursiveCharacterTextSplitter( + chunk_size=1000, + chunk_overlap=20, + length_function=len, + is_separator_regex=False, + ) + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + print(f"Chunking {v.source.id}...", flush=True) + + texts = self.text_splitter.create_documents( + [v.text.decode("utf-8")] + ) + + for ix, chunk in enumerate(texts): + + id = v.source.id + "-c" + str(ix) + + r = Chunk( + source=Source( + source=v.source.source, + id=id, + title=v.source.title + ), + chunk=chunk.page_content.encode("utf-8"), + ) + + self.producer.send(r) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + print("Done.", flush=True) + + except Exception as e: + print(e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='pdf-decoder', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'text-doc-load' + default_output_queue = 'chunk-load' + default_subscriber = 'chunker-recursive' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-o', '--output-queue', + default=default_output_queue, + help=f'Output queue (default: {default_output_queue})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + args = parser.parse_args() + + + while True: + + try: + + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + output_queue=args.output_queue, + subscriber=args.subscriber, + log_level=args.log_level, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + + diff --git a/trustgraph/decoder/__init__.py b/trustgraph/decoder/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trustgraph/decoder/pdf/__init__.py b/trustgraph/decoder/pdf/__init__.py new file mode 100644 index 00000000..0d8d9c78 --- /dev/null +++ b/trustgraph/decoder/pdf/__init__.py @@ -0,0 +1,3 @@ + +from . pdf_decoder import * + diff --git a/trustgraph/decoder/pdf/__main__.py b/trustgraph/decoder/pdf/__main__.py new file mode 100755 index 00000000..44dd026d --- /dev/null +++ b/trustgraph/decoder/pdf/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from . pdf_decoder import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/decoder/pdf/pdf_decoder.py b/trustgraph/decoder/pdf/pdf_decoder.py new file mode 100755 index 00000000..f892ebac --- /dev/null +++ b/trustgraph/decoder/pdf/pdf_decoder.py @@ -0,0 +1,159 @@ + +""" +Simple decoder, accepts PDF documents on input, outputs pages from the +PDF document as text as separate output objects. +""" + +import pulsar +from pulsar.schema import JsonSchema +from langchain_community.document_loaders import PyPDFLoader +import tempfile +import base64 +import os +import argparse +import time + +from ... schema import Document, TextDocument, Source +from ... log_level import LogLevel + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + output_queue, + subscriber, + log_level, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(Document), + ) + + self.producer = self.client.create_producer( + topic=output_queue, + schema=JsonSchema(TextDocument), + ) + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + print(f"Decoding {v.source.id}...", flush=True) + + with tempfile.NamedTemporaryFile(delete_on_close=False) as fp: + + fp.write(base64.b64decode(v.data)) + fp.close() + + with open(fp.name, mode='rb') as f: + + loader = PyPDFLoader(fp.name) + pages = loader.load() + + for ix, page in enumerate(pages): + + id = v.source.id + "-p" + str(ix) + r = TextDocument( + source=Source( + source=v.source.source, + title=v.source.title, + id=id, + ), + text=page.page_content.encode("utf-8"), + ) + + self.producer.send(r) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + print("Done.", flush=True) + + except Exception as e: + print(e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='pdf-decoder', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'document-load' + default_output_queue = 'text-doc-load' + default_subscriber = 'pdf-decoder' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-o', '--output-queue', + default=default_output_queue, + help=f'Output queue (default: {default_output_queue})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + args = parser.parse_args() + + while True: + + try: + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + output_queue=args.output_queue, + subscriber=args.subscriber, + log_level=args.log_level, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + diff --git a/trustgraph/edge_map.py b/trustgraph/edge_map.py new file mode 100644 index 00000000..55d9077f --- /dev/null +++ b/trustgraph/edge_map.py @@ -0,0 +1,102 @@ + +from pymilvus import MilvusClient, CollectionSchema, FieldSchema, DataType + +class VectorStore: + + def __init__(self, uri="http://localhost:19530"): + + self.client = MilvusClient(uri=uri) + + self.collection = "edges" + self.dimension = 384 + + if not self.client.has_collection(collection_name=self.collection): + self.init_collection() + + def init_collection(self): + + pkey_field = FieldSchema( + name="id", + dtype=DataType.INT64, + is_primary=True, + auto_id=True, + ) + + vec_field = FieldSchema( + name="vector", + dtype=DataType.FLOAT_VECTOR, + dim=self.dimension, + ) + + entity_field = FieldSchema( + name="entity", + dtype=DataType.VARCHAR, + max_length=65535, + ) + + schema = CollectionSchema( + fields = [pkey_field, vec_field, entity_field], + description = "Edge map schema", + ) + + self.client.create_collection( + collection_name=self.collection, + schema=schema, + metric_type="IP", + ) + + index_params = MilvusClient.prepare_index_params() + + index_params.add_index( + field_name="vector", + metric_type="COSINE", + index_type="FLAT", # IVF_FLAT?! + index_name="vector_index", + params={ "nlist": 128 } + ) + + self.client.create_index( + collection_name=self.collection, + index_params=index_params + ) + + def insert(self, embeds, entity): + + data = [ + { + "vector": embeds, + "entity": entity, + } + ] + + self.client.insert(collection_name=self.collection, data=data) + + def search(self, embeds, fields=["entity"], limit=10): + + search_params = { + "metric_type": "COSINE", + "params": { + "radius": 0.1, + "range_filter": 0.8 + } + } + + self.client.load_collection( + collection_name=self.collection, +# replica_number=1 + ) + + res = self.client.search( + collection_name=self.collection, + data=[embeds], + limit=limit, + output_fields=fields, + search_params=search_params, + )[0] + + self.client.release_collection( + collection_name=self.collection, + ) + + return res + diff --git a/trustgraph/embeddings/__init__.py b/trustgraph/embeddings/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trustgraph/embeddings/hf/__init__.py b/trustgraph/embeddings/hf/__init__.py new file mode 100644 index 00000000..7ccb0b37 --- /dev/null +++ b/trustgraph/embeddings/hf/__init__.py @@ -0,0 +1,3 @@ + +from . hf import * + diff --git a/trustgraph/embeddings/hf/__main__.py b/trustgraph/embeddings/hf/__main__.py new file mode 100755 index 00000000..89684e3e --- /dev/null +++ b/trustgraph/embeddings/hf/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from . hf import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/embeddings/hf/hf.py b/trustgraph/embeddings/hf/hf.py new file mode 100755 index 00000000..33890483 --- /dev/null +++ b/trustgraph/embeddings/hf/hf.py @@ -0,0 +1,161 @@ + +""" +Simple LLM service, performs text prompt completion using an Ollama service. +Input is prompt, output is response. +""" + +import pulsar +from pulsar.schema import JsonSchema +import tempfile +import base64 +import os +import argparse +from langchain_huggingface import HuggingFaceEmbeddings +import time + +from ... schema import EmbeddingsRequest, EmbeddingsResponse +from ... log_level import LogLevel + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + output_queue, + subscriber, + log_level, + model, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(EmbeddingsRequest), + ) + + self.producer = self.client.create_producer( + topic=output_queue, + schema=JsonSchema(EmbeddingsResponse), + ) + + self.embeddings = HuggingFaceEmbeddings(model_name=model) + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + + # Sender-produced ID + + id = msg.properties()["id"] + + print(f"Handling input {id}...", flush=True) + + text = v.text + embeds = self.embeddings.embed_documents([text]) + + print("Send response...", flush=True) + r = EmbeddingsResponse(vectors=embeds) + self.producer.send(r, properties={"id": id}) + + print("Done.", flush=True) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + except Exception as e: + + print("Exception:", e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + print("Closing", flush=True) + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='llm-ollama-text', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'embeddings' + default_output_queue = 'embeddings-response' + default_subscriber = 'embeddings-hf' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-o', '--output-queue', + default=default_output_queue, + help=f'Output queue (default: {default_output_queue})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + parser.add_argument( + '-m', '--model', + default="all-MiniLM-L6-v2", + help=f'LLM model (default: all-MiniLM-L6-v2)' + ) + + args = parser.parse_args() + + + while True: + + try: + + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + output_queue=args.output_queue, + subscriber=args.subscriber, + log_level=args.log_level, + model=args.model, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + diff --git a/trustgraph/embeddings/vectorize/__init__.py b/trustgraph/embeddings/vectorize/__init__.py new file mode 100644 index 00000000..31596b8c --- /dev/null +++ b/trustgraph/embeddings/vectorize/__init__.py @@ -0,0 +1,3 @@ + +from . vectorize import * + diff --git a/trustgraph/embeddings/vectorize/__main__.py b/trustgraph/embeddings/vectorize/__main__.py new file mode 100755 index 00000000..a578de8a --- /dev/null +++ b/trustgraph/embeddings/vectorize/__main__.py @@ -0,0 +1,6 @@ + +from . vectorize import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/embeddings/vectorize/vectorize.py b/trustgraph/embeddings/vectorize/vectorize.py new file mode 100755 index 00000000..b362470d --- /dev/null +++ b/trustgraph/embeddings/vectorize/vectorize.py @@ -0,0 +1,167 @@ + +""" +Vectorizer, applies an embedding algorithm to a chunk. Input is a chunk, +output is chunk and vectors. +""" + +import pulsar +from pulsar.schema import JsonSchema +import tempfile +import base64 +import os +import argparse +import time + +from ... schema import Chunk, VectorsChunk +from ... embeddings_client import EmbeddingsClient +from ... log_level import LogLevel + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + output_queue, + subscriber, + log_level, + model, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(Chunk), + ) + + self.producer = self.client.create_producer( + topic=output_queue, + schema=JsonSchema(VectorsChunk), + ) + + self.embeddings = EmbeddingsClient(pulsar_host=pulsar_host) + + def emit(self, source, chunk, vectors): + + r = VectorsChunk(source=source, chunk=chunk, vectors=vectors) + self.producer.send(r) + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + print(f"Indexing {v.source.id}...", flush=True) + + chunk = v.chunk.decode("utf-8") + + try: + + vectors = self.embeddings.request(chunk) + + self.emit( + source=v.source, + chunk=chunk.encode("utf-8"), + vectors=vectors + ) + + except Exception as e: + print("Exception:", e, flush=True) + + print("Done.", flush=True) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + except Exception as e: + + print("Exception:", e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='embeddings-vectorizer', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'chunk-load' + default_output_queue = 'vectors-chunk-load' + default_subscriber = 'embeddings-vectorizer' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-o', '--output-queue', + default=default_output_queue, + help=f'Output queue (default: {default_output_queue})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + parser.add_argument( + '-m', '--model', + default="all-MiniLM-L6-v2", + help=f'LLM model (default: all-MiniLM-L6-v2)' + ) + + args = parser.parse_args() + + while True: + + try: + + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + output_queue=args.output_queue, + subscriber=args.subscriber, + log_level=args.log_level, + model=args.model, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + diff --git a/trustgraph/embeddings_client.py b/trustgraph/embeddings_client.py new file mode 100644 index 00000000..e464e02f --- /dev/null +++ b/trustgraph/embeddings_client.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +import pulsar +import _pulsar +from pulsar.schema import JsonSchema +from trustgraph.schema import EmbeddingsRequest, EmbeddingsResponse +import hashlib +import uuid + +# Ugly +ERROR=_pulsar.LoggerLevel.Error +WARN=_pulsar.LoggerLevel.Warn +INFO=_pulsar.LoggerLevel.Info +DEBUG=_pulsar.LoggerLevel.Debug + +class EmbeddingsClient: + + def __init__( + self, log_level=ERROR, client_id=None, + pulsar_host="pulsar://pulsar:6650", + ): + + if client_id == None: + client_id = str(uuid.uuid4()) + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level), + ) + + self.producer = self.client.create_producer( + topic='embeddings', + schema=JsonSchema(EmbeddingsRequest), + chunking_enabled=True, + ) + + self.consumer = self.client.subscribe( + 'embeddings-response', client_id, + schema=JsonSchema(EmbeddingsResponse), + ) + + def request(self, text, timeout=500): + + id = str(uuid.uuid4()) + + r = EmbeddingsRequest( + text=text + ) + self.producer.send(r, properties={ "id": id }) + + while True: + + msg = self.consumer.receive(timeout_millis=timeout * 1000) + + mid = msg.properties()["id"] + + if mid == id: + resp = msg.value().vectors + self.consumer.acknowledge(msg) + return resp + + # Ignore messages with wrong ID + self.consumer.acknowledge(msg) + + def __del__(self): + + self.producer.close() + self.consumer.close() + self.client.close() + diff --git a/trustgraph/graph/__init__.py b/trustgraph/graph/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trustgraph/graph/cassandra_write/__init__.py b/trustgraph/graph/cassandra_write/__init__.py new file mode 100644 index 00000000..d891d55f --- /dev/null +++ b/trustgraph/graph/cassandra_write/__init__.py @@ -0,0 +1,3 @@ + +from . write import * + diff --git a/trustgraph/graph/cassandra_write/__main__.py b/trustgraph/graph/cassandra_write/__main__.py new file mode 100755 index 00000000..c05d8c6d --- /dev/null +++ b/trustgraph/graph/cassandra_write/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from . write import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/graph/cassandra_write/write.py b/trustgraph/graph/cassandra_write/write.py new file mode 100755 index 00000000..1b56b5ab --- /dev/null +++ b/trustgraph/graph/cassandra_write/write.py @@ -0,0 +1,144 @@ + +""" +Simple decoder, accepts PDF documents on input, outputs pages from the +PDF document as text as separate output objects. +""" + +import pulsar +from pulsar.schema import JsonSchema +import tempfile +import base64 +import os +import argparse +import time + +from ... trustgraph import TrustGraph +from ... schema import Triple +from ... log_level import LogLevel + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + subscriber, + log_level, + graph_host, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(Triple), + ) + + self.tg = TrustGraph([graph_host]) + + self.count = 0 + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + + self.tg.insert( + v.s.value, + v.p.value, + v.o.value + ) + + self.count += 1 + + if (self.count % 1000) == 0: + print(self.count, "...", flush=True) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + except Exception as e: + + print("Exception:", e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='graph-write-cassandra', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'graph-load' + default_subscriber = 'graph-write-cassandra' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + parser.add_argument( + '-g', '--graph-host', + default="localhost", + help=f'Output queue (default: localhost)' + ) + + args = parser.parse_args() + + while True: + + try: + + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + subscriber=args.subscriber, + log_level=args.log_level, + graph_host=args.graph_host, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + + diff --git a/trustgraph/graph_rag.py b/trustgraph/graph_rag.py new file mode 100644 index 00000000..4175698e --- /dev/null +++ b/trustgraph/graph_rag.py @@ -0,0 +1,227 @@ + +from trustgraph.trustgraph import TrustGraph +from trustgraph.edge_map import VectorStore +from trustgraph.trustgraph import TrustGraph +from trustgraph.llm_client import LlmClient +from trustgraph.embeddings_client import EmbeddingsClient + +LABEL="http://www.w3.org/2000/01/rdf-schema#label" +DEFINITION="http://www.w3.org/2004/02/skos/core#definition" + +class GraphRag: + + def __init__( + self, + graph_hosts=None, + pulsar_host="pulsar://pulsar:6650", + vector_store="http://milvus:19530", + verbose=False + ): + + self.verbose=verbose + + if graph_hosts == None: + graph_hosts = ["cassandra"] + + if self.verbose: + print("Initialising...", flush=True) + + self.graph = TrustGraph(graph_hosts) + + self.embeddings = EmbeddingsClient(pulsar_host=pulsar_host) + + self.vecstore = VectorStore(vector_store) + + self.entity_limit=50 + self.query_limit=30 + self.max_sg_size=3000 + + self.label_cache = {} + + self.llm = LlmClient(pulsar_host=pulsar_host) + + if self.verbose: + print("Initialised", flush=True) + + def get_vector(self, query): + + if self.verbose: + print("Compute embeddings...", flush=True) + + qembeds = self.embeddings.request(query) + + if self.verbose: + print("Done.", flush=True) + + return qembeds + + def get_entities(self, query): + + everything = [] + + vectors = self.get_vector(query) + + if self.verbose: + print("Get entities...", flush=True) + + for vector in vectors: + + res = self.vecstore.search( + vector, + limit=self.entity_limit + ) + + entities = set([ + item["entity"]["entity"] + for item in res + ]) + + everything.extend(entities) + + if self.verbose: + print("Entities:", flush=True) + for ent in everything: + print(" ", ent, flush=True) + + return everything + + def maybe_label(self, e): + + if e in self.label_cache: + return self.label_cache[e] + + res = self.graph.get_sp(e, LABEL) + res = list(res) + + if len(res) == 0: + self.label_cache[e] = e + return e + + self.label_cache[e] = res[0][0] + return self.label_cache[e] + + def get_nodes(self, query): + + ents = self.get_entities(query) + + if self.verbose: + print("Get labels...", flush=True) + + nodes = [ + self.maybe_label(e) + for e in ents + ] + + if self.verbose: + print("Nodes:", flush=True) + for node in nodes: + print(" ", node, flush=True) + + return nodes + + def get_subgraph(self, query): + + entities = self.get_entities(query) + + subgraph = set() + + if self.verbose: + print("Get subgraph...", flush=True) + + for e in entities: + + res = self.graph.get_s(e, limit=self.query_limit) + for p, o in res: + subgraph.add((e, p, o)) + + res = self.graph.get_p(e, limit=self.query_limit) + for s, o in res: + subgraph.add((s, e, o)) + + res = self.graph.get_o(e, limit=self.query_limit) + for s, p in res: + subgraph.add((s, p, e)) + + subgraph = list(subgraph) + + subgraph = subgraph[0:self.max_sg_size] + + if self.verbose: + print("Subgraph:", flush=True) + for edge in subgraph: + print(" ", str(edge), flush=True) + + if self.verbose: + print("Done.", flush=True) + + return subgraph + + def get_labelgraph(self, query): + + subgraph = self.get_subgraph(query) + + sg2 = [] + + for edge in subgraph: + + if edge[1] == LABEL: + continue + + s = self.maybe_label(edge[0]) + p = self.maybe_label(edge[1]) + o = self.maybe_label(edge[2]) + + sg2.append((s, p, o)) + + return sg2 + + def get_cypher(self, query): + + sg = self.get_labelgraph(query) + + sg2 = [] + + for s, p, o in sg: + + sg2.append(f"({s})-[{p}]->({o})") + + kg = "\n".join(sg2) + kg = kg.replace("\\", "-") + + return kg + + def get_graph_prompt(self, query): + + kg = self.get_cypher(query) + + prompt=f"""Study the knowledge graph provided, and use +the information to answer the question. The question should be answered +in plain English only. + + +{kg} + + +{query} + +""" + + return prompt + + def query(self, query): + + if self.verbose: + print("Construct prompt...", flush=True) + + prompt = self.get_graph_prompt(query) + + if self.verbose: + print("Invoke LLM...", flush=True) + + resp = self.llm.request(prompt) + + if self.verbose: + print("Done", flush=True) + + return resp + diff --git a/trustgraph/graph_rag_client.py b/trustgraph/graph_rag_client.py new file mode 100644 index 00000000..6f48e772 --- /dev/null +++ b/trustgraph/graph_rag_client.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +import pulsar +import _pulsar +from pulsar.schema import JsonSchema +from trustgraph.schema import GraphRagQuery, GraphRagResponse +import hashlib +import uuid + +# Ugly +ERROR=_pulsar.LoggerLevel.Error +WARN=_pulsar.LoggerLevel.Warn +INFO=_pulsar.LoggerLevel.Info +DEBUG=_pulsar.LoggerLevel.Debug + +class GraphRagClient: + + def __init__( + self, log_level=ERROR, client_id=None, + pulsar_host="pulsar://pulsar:6650", + ): + + if client_id == None: + client_id = str(uuid.uuid4()) + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level), + ) + + self.producer = self.client.create_producer( + topic='graph-rag-query', + schema=JsonSchema(GraphRagQuery), + chunking_enabled=True, + ) + + self.consumer = self.client.subscribe( + 'graph-rag-response', client_id, + schema=JsonSchema(GraphRagResponse), + ) + + def request(self, query, timeout=500): + + id = str(uuid.uuid4()) + + r = GraphRagQuery( + query=query + ) + self.producer.send(r, properties={ "id": id }) + + while True: + + msg = self.consumer.receive(timeout_millis=timeout * 1000) + + mid = msg.properties()["id"] + + if mid == id: + resp = msg.value().response + self.consumer.acknowledge(msg) + return resp + + # Ignore messages with wrong ID + self.consumer.acknowledge(msg) + + def __del__(self): + + self.client.close() + diff --git a/trustgraph/kg/__init__.py b/trustgraph/kg/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trustgraph/kg/extract_definitions/__init__.py b/trustgraph/kg/extract_definitions/__init__.py new file mode 100644 index 00000000..81287a3c --- /dev/null +++ b/trustgraph/kg/extract_definitions/__init__.py @@ -0,0 +1,3 @@ + +from . extract import * + diff --git a/trustgraph/kg/extract_definitions/__main__.py b/trustgraph/kg/extract_definitions/__main__.py new file mode 100755 index 00000000..403fe672 --- /dev/null +++ b/trustgraph/kg/extract_definitions/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from . extract import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/kg/extract_definitions/extract.py b/trustgraph/kg/extract_definitions/extract.py new file mode 100755 index 00000000..369aef59 --- /dev/null +++ b/trustgraph/kg/extract_definitions/extract.py @@ -0,0 +1,193 @@ + +""" +Simple decoder, accepts PDF documents on input, outputs pages from the +PDF document as text as separate output objects. +""" + +import pulsar +from pulsar.schema import JsonSchema +from langchain_community.document_loaders import PyPDFLoader +import tempfile +import base64 +import os +import argparse +import rdflib +import json +import urllib.parse +import time + +from ... schema import VectorsChunk, Triple, Source, Value +from ... log_level import LogLevel +from ... llm_client import LlmClient +from ... prompts import to_definitions +from ... rdf import TRUSTGRAPH_ENTITIES, DEFINITION + +DEFINITION_VALUE = Value(value=DEFINITION, is_uri=True) + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + output_queue, + subscriber, + log_level, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(VectorsChunk), + ) + + self.producer = self.client.create_producer( + topic=output_queue, + schema=JsonSchema(Triple), + ) + + self.llm = LlmClient(pulsar_host=pulsar_host) + + def to_uri(self, text): + + part = text.replace(" ", "-").lower().encode("utf-8") + quoted = urllib.parse.quote(part) + uri = TRUSTGRAPH_ENTITIES + quoted + + return uri + + def get_definitions(self, chunk): + + prompt = to_definitions(chunk) + resp = self.llm.request(prompt) + + defs = json.loads(resp) + + return defs + + def emit_edge(self, s, p, o): + + t = Triple(s=s, p=p, o=o) + self.producer.send(t) + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + print(f"Indexing {v.source.id}...", flush=True) + + chunk = v.chunk.decode("utf-8") + + g = rdflib.Graph() + + try: + + defs = self.get_definitions(chunk) + print(json.dumps(defs, indent=4), flush=True) + + for defn in defs: + + s = defn["entity"] + s_uri = self.to_uri(s) + + o = defn["definition"] + + s_value = Value(value=str(s_uri), is_uri=True) + o_value = Value(value=str(o), is_uri=False) + + self.emit_edge(s_value, DEFINITION_VALUE, o_value) + + except Exception as e: + print("Exception: ", e, flush=True) + + print("Done.", flush=True) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + except Exception as e: + + print("Exception: ", e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='pdf-decoder', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'vectors-chunk-load' + default_output_queue = 'graph-load' + default_subscriber = 'kg-extract-definitions' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-o', '--output-queue', + default=default_output_queue, + help=f'Output queue (default: {default_output_queue})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + args = parser.parse_args() + + while True: + + try: + + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + output_queue=args.output_queue, + subscriber=args.subscriber, + log_level=args.log_level, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + diff --git a/trustgraph/kg/extract_relationships/__init__.py b/trustgraph/kg/extract_relationships/__init__.py new file mode 100644 index 00000000..81287a3c --- /dev/null +++ b/trustgraph/kg/extract_relationships/__init__.py @@ -0,0 +1,3 @@ + +from . extract import * + diff --git a/trustgraph/kg/extract_relationships/__main__.py b/trustgraph/kg/extract_relationships/__main__.py new file mode 100755 index 00000000..403fe672 --- /dev/null +++ b/trustgraph/kg/extract_relationships/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from . extract import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/kg/extract_relationships/extract.py b/trustgraph/kg/extract_relationships/extract.py new file mode 100755 index 00000000..a47c3b6e --- /dev/null +++ b/trustgraph/kg/extract_relationships/extract.py @@ -0,0 +1,252 @@ + +""" +Simple decoder, accepts PDF documents on input, outputs pages from the +PDF document as text as separate output objects. +""" + +import pulsar +from pulsar.schema import JsonSchema +from langchain_community.document_loaders import PyPDFLoader +import tempfile +import base64 +import os +import argparse +import rdflib +import json +import urllib.parse +import time + +from ... schema import VectorsChunk, Triple, VectorsAssociation, Source, Value +from ... log_level import LogLevel +from ... llm_client import LlmClient +from ... prompts import to_relationships +from ... rdf import RDF_LABEL, TRUSTGRAPH_ENTITIES + +RDF_LABEL_VALUE = Value(value=RDF_LABEL, is_uri=True) + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + output_queue, + vec_queue, + subscriber, + log_level, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(VectorsChunk), + ) + + self.producer = self.client.create_producer( + topic=output_queue, + schema=JsonSchema(Triple), + ) + + self.vec_prod = self.client.create_producer( + topic=vec_queue, + schema=JsonSchema(VectorsAssociation), + ) + + self.llm = LlmClient(pulsar_host=pulsar_host) + + def to_uri(self, text): + + part = text.replace(" ", "-").lower().encode("utf-8") + quoted = urllib.parse.quote(part) + uri = TRUSTGRAPH_ENTITIES + quoted + + return uri + + def get_relationships(self, chunk): + + prompt = to_relationships(chunk) + resp = self.llm.request(prompt) + + rels = json.loads(resp) + + return rels + + def emit_edge(self, s, p, o): + + t = Triple(s=s, p=p, o=o) + self.producer.send(t) + + def emit_vec(self, ent, vec): + + r = VectorsAssociation(entity=ent, vectors=vec) + self.vec_prod.send(r) + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + print(f"Indexing {v.source.id}...", flush=True) + + chunk = v.chunk.decode("utf-8") + + g = rdflib.Graph() + + try: + + rels = self.get_relationships(chunk) + print(json.dumps(rels, indent=4), flush=True) + + for rel in rels: + + s = rel["subject"] + p = rel["predicate"] + o = rel["object"] + + s_uri = self.to_uri(s) + s_value = Value(value=str(s_uri), is_uri=True) + + p_uri = self.to_uri(p) + p_value = Value(value=str(p_uri), is_uri=True) + + if rel["object-entity"]: + o_uri = self.to_uri(o) + o_value = Value(value=str(o_uri), is_uri=True) + else: + o_value = Value(value=str(o), is_uri=False) + + self.emit_edge( + s_value, + p_value, + o_value + ) + + # Label for s + self.emit_edge( + s_value, + RDF_LABEL_VALUE, + Value(value=str(s), is_uri=False) + ) + + # Label for p + self.emit_edge( + p_value, + RDF_LABEL_VALUE, + Value(value=str(p), is_uri=False) + ) + + if rel["object-entity"]: + # Label for o + self.emit_edge( + o_value, + RDF_LABEL_VALUE, + Value(value=str(o), is_uri=False) + ) + + self.emit_vec(s_value, v.vectors) + self.emit_vec(p_value, v.vectors) + if rel["object-entity"]: + self.emit_vec(o_value, v.vectors) + + except Exception as e: + print("Exception: ", e, flush=True) + + print("Done.", flush=True) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + except Exception as e: + + print("Exception: ", e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='kg-extract-relationships', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'vectors-chunk-load' + default_output_queue = 'graph-load' + default_subscriber = 'kg-extract-relationships' + default_vector_queue='vectors-load' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-o', '--output-queue', + default=default_output_queue, + help=f'Output queue (default: {default_output_queue})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + parser.add_argument( + '-c', '--vector-queue', + default=default_vector_queue, + help=f'Vector output queue (default: {default_vector_queue})' + ) + + args = parser.parse_args() + + while True: + + try: + + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + output_queue=args.output_queue, + vec_queue=args.vector_queue, + subscriber=args.subscriber, + log_level=args.log_level, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + + diff --git a/trustgraph/llm/__init__.py b/trustgraph/llm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trustgraph/llm/azure_text/__init__.py b/trustgraph/llm/azure_text/__init__.py new file mode 100644 index 00000000..f2017af8 --- /dev/null +++ b/trustgraph/llm/azure_text/__init__.py @@ -0,0 +1,3 @@ + +from . llm import * + diff --git a/trustgraph/llm/azure_text/__main__.py b/trustgraph/llm/azure_text/__main__.py new file mode 100755 index 00000000..91342d2d --- /dev/null +++ b/trustgraph/llm/azure_text/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from . llm import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/llm/azure_text/llm.py b/trustgraph/llm/azure_text/llm.py new file mode 100755 index 00000000..c4f47b6a --- /dev/null +++ b/trustgraph/llm/azure_text/llm.py @@ -0,0 +1,213 @@ + +""" +Simple LLM service, performs text prompt completion using an Ollama service. +Input is prompt, output is response. +""" + +import pulsar +from pulsar.schema import JsonSchema +import tempfile +import base64 +import os +import argparse +from langchain_community.llms import Ollama +import requests +import time +import json + +from ... schema import TextCompletionRequest, TextCompletionResponse +from ... log_level import LogLevel + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + output_queue, + subscriber, + log_level, + endpoint, + token, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(TextCompletionRequest), + ) + + self.producer = self.client.create_producer( + topic=output_queue, + schema=JsonSchema(TextCompletionResponse), + ) + + self.endpoint = endpoint + self.token = token + + def build_prompt(self, system, content): + + data = { + "messages": [ + { + "role": "system", "content": system + }, + { + "role": "user", "content": content + } + ], + "max_tokens": 4192, + "temperature": 0.2, + "top_p": 1 + } + + body = json.dumps(data) + + return body + + def call_llm(self, body): + + url = self.endpoint + + # Replace this with the primary/secondary key, AMLToken, or + # Microsoft Entra ID token for the endpoint + api_key = self.token + + headers = { + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {api_key}' + } + + resp = requests.post(url, data=body, headers=headers) + result = resp.json() + + message_content = result['choices'][0]['message']['content'] + + return message_content + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + + # Sender-produced ID + + id = msg.properties()["id"] + + print(f"Handling prompt {id}...", flush=True) + + prompt = self.build_prompt( + "You are a helpful chatbot", + v.prompt + ) + + response = self.call_llm(prompt) + + print("Send response...", flush=True) + r = TextCompletionResponse(response=response) + self.producer.send(r, properties={"id": id}) + + print("Done.", flush=True) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + except Exception as e: + + print("Exception:", e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='llm-ollama-text', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'llm-complete-text' + default_output_queue = 'llm-complete-text-response' + default_subscriber = 'llm-ollama-text' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-o', '--output-queue', + default=default_output_queue, + help=f'Output queue (default: {default_output_queue})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + parser.add_argument( + '-e', '--endpoint', + help=f'LLM model endpoint' + ) + + parser.add_argument( + '-k', '--token', + help=f'LLM model token' + ) + + args = parser.parse_args() + + while True: + + try: + + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + output_queue=args.output_queue, + subscriber=args.subscriber, + log_level=args.log_level, + endpoint=args.endpoint, + token=args.token, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + + diff --git a/trustgraph/llm/claude_text/__init__.py b/trustgraph/llm/claude_text/__init__.py new file mode 100644 index 00000000..f2017af8 --- /dev/null +++ b/trustgraph/llm/claude_text/__init__.py @@ -0,0 +1,3 @@ + +from . llm import * + diff --git a/trustgraph/llm/claude_text/__main__.py b/trustgraph/llm/claude_text/__main__.py new file mode 100755 index 00000000..91342d2d --- /dev/null +++ b/trustgraph/llm/claude_text/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from . llm import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/llm/claude_text/llm.py b/trustgraph/llm/claude_text/llm.py new file mode 100755 index 00000000..85ffc9c7 --- /dev/null +++ b/trustgraph/llm/claude_text/llm.py @@ -0,0 +1,190 @@ + +""" +Simple LLM service, performs text prompt completion using Claude. +Input is prompt, output is response. +""" + +import pulsar +from pulsar.schema import JsonSchema +import tempfile +import base64 +import os +import argparse +import anthropic +import time + +from ... schema import TextCompletionRequest, TextCompletionResponse +from ... log_level import LogLevel + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + output_queue, + subscriber, + log_level, + model, + api_key, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(TextCompletionRequest), + ) + + self.producer = self.client.create_producer( + topic=output_queue, + schema=JsonSchema(TextCompletionResponse), + ) + + self.model = model + + self.claude = anthropic.Anthropic(api_key=api_key) + + print("Initialised", flush=True) + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + + # Sender-produced ID + + id = msg.properties()["id"] + + print(f"Handling prompt {id}...", flush=True) + + prompt = v.prompt + response = message = self.claude.messages.create( + model=self.model, + max_tokens=1000, + temperature=0.1, + system = "You are a helpful chatbot.", + messages=[ + { + "role": "user", + "content": [ + { + "type": "text", + "text": prompt + } + ] + } + ] + ) + + resp = response.content[0].text + print(resp, flush=True) + + print("Send response...", flush=True) + r = TextCompletionResponse(response=resp) + self.producer.send(r, properties={"id": id}) + + print("Done.", flush=True) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + except Exception as e: + + print("Exception:", e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='llm-ollama-text', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'llm-complete-text' + default_output_queue = 'llm-complete-text-response' + default_subscriber = 'llm-claude-text' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-o', '--output-queue', + default=default_output_queue, + help=f'Output queue (default: {default_output_queue})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + parser.add_argument( + '-m', '--model', + default="claude-3-5-sonnet-20240620", + help=f'LLM model (default: claude-3-5-sonnet-20240620)' + ) + + parser.add_argument( + '-k', '--api-key', + help=f'Claude API key' + ) + + args = parser.parse_args() + + while True: + + try: + + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + output_queue=args.output_queue, + subscriber=args.subscriber, + log_level=args.log_level, + model=args.model, + api_key=args.api_key, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + + diff --git a/trustgraph/llm/ollama_text/__init__.py b/trustgraph/llm/ollama_text/__init__.py new file mode 100644 index 00000000..f2017af8 --- /dev/null +++ b/trustgraph/llm/ollama_text/__init__.py @@ -0,0 +1,3 @@ + +from . llm import * + diff --git a/trustgraph/llm/ollama_text/__main__.py b/trustgraph/llm/ollama_text/__main__.py new file mode 100755 index 00000000..91342d2d --- /dev/null +++ b/trustgraph/llm/ollama_text/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from . llm import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/llm/ollama_text/llm.py b/trustgraph/llm/ollama_text/llm.py new file mode 100755 index 00000000..9d9c7dad --- /dev/null +++ b/trustgraph/llm/ollama_text/llm.py @@ -0,0 +1,169 @@ + +""" +Simple LLM service, performs text prompt completion using an Ollama service. +Input is prompt, output is response. +""" + +import pulsar +from pulsar.schema import JsonSchema +import tempfile +import base64 +import os +import argparse +from langchain_community.llms import Ollama +import time + +from ... schema import TextCompletionRequest, TextCompletionResponse +from ... log_level import LogLevel + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + output_queue, + subscriber, + log_level, + model, + ollama, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(TextCompletionRequest), + ) + + self.producer = self.client.create_producer( + topic=output_queue, + schema=JsonSchema(TextCompletionResponse), + ) + + self.llm = Ollama(base_url=ollama, model=model) + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + + # Sender-produced ID + + id = msg.properties()["id"] + + print(f"Handling prompt {id}...", flush=True) + + prompt = v.prompt + response = self.llm.invoke(prompt) + + print("Send response...", flush=True) + r = TextCompletionResponse(response=response) + self.producer.send(r, properties={"id": id}) + + print("Done.", flush=True) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + except Exception as e: + + print("Exception:", e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + print("Closing") + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='llm-ollama-text', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'llm-complete-text' + default_output_queue = 'llm-complete-text-response' + default_subscriber = 'llm-ollama-text' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-o', '--output-queue', + default=default_output_queue, + help=f'Output queue (default: {default_output_queue})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + parser.add_argument( + '-m', '--model', + default="gemma2", + help=f'LLM model (default: gemma2)' + ) + + parser.add_argument( + '-r', '--ollama', + default="http://localhost:11434", + help=f'ollama (default: http://localhost:11434)' + ) + + args = parser.parse_args() + + + while True: + + try: + + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + output_queue=args.output_queue, + subscriber=args.subscriber, + log_level=args.log_level, + model=args.model, + ollama=args.ollama, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + diff --git a/trustgraph/llm/vertexai_text/__init__.py b/trustgraph/llm/vertexai_text/__init__.py new file mode 100644 index 00000000..f2017af8 --- /dev/null +++ b/trustgraph/llm/vertexai_text/__init__.py @@ -0,0 +1,3 @@ + +from . llm import * + diff --git a/trustgraph/llm/vertexai_text/__main__.py b/trustgraph/llm/vertexai_text/__main__.py new file mode 100755 index 00000000..91342d2d --- /dev/null +++ b/trustgraph/llm/vertexai_text/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from . llm import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/llm/vertexai_text/llm.py b/trustgraph/llm/vertexai_text/llm.py new file mode 100755 index 00000000..44b55e62 --- /dev/null +++ b/trustgraph/llm/vertexai_text/llm.py @@ -0,0 +1,254 @@ + +""" +Simple LLM service, performs text prompt completion using an Ollama service. +Input is prompt, output is response. +""" + +import pulsar +from pulsar.schema import JsonSchema +import tempfile +import base64 +import os +import argparse +import vertexai +import time + +from google.oauth2 import service_account +import google + +from vertexai.preview.generative_models import ( + Content, + FunctionDeclaration, + GenerativeModel, + GenerationConfig, + HarmCategory, + HarmBlockThreshold, + Part, + Tool, +) + +from ... schema import TextCompletionRequest, TextCompletionResponse +from ... log_level import LogLevel + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + output_queue, + subscriber, + log_level, + credentials, + region, + model, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(TextCompletionRequest), + ) + + self.producer = self.client.create_producer( + topic=output_queue, + schema=JsonSchema(TextCompletionResponse), + ) + + self.parameters = { + "temperature": 0.2, + "top_p": 1.0, + "top_k": 32, + "candidate_count": 1, + "max_output_tokens": 8192, + } + + self.generation_config = GenerationConfig( + temperature=0.2, + top_p=1.0, + top_k=10, + candidate_count=1, + max_output_tokens=8191, + ) + + # Block none doesn't seem to work + block_level = HarmBlockThreshold.BLOCK_ONLY_HIGH + # block_level = HarmBlockThreshold.BLOCK_NONE + + self.safety_settings = { + HarmCategory.HARM_CATEGORY_HARASSMENT: block_level, + HarmCategory.HARM_CATEGORY_HATE_SPEECH: block_level, + HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: block_level, + HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: block_level, + } + + print("Initialise VertexAI...", flush=True) + + if credentials: + vertexai.init( + location=region, + credentials=credentials, + project=credentials.project_id, + ) + else: + vertexai.init( + location=region + ) + + print(f"Initialise model {model}", flush=True) + self.llm = GenerativeModel(model) + + print("Initialisation complete", flush=True) + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + + # Sender-produced ID + + id = msg.properties()["id"] + + print(f"Handling prompt {id}...", flush=True) + + prompt = v.prompt + + resp = self.llm.generate_content( + prompt, generation_config=self.generation_config, + safety_settings=self.safety_settings + ) + + resp = resp.text + + resp = resp.replace("```json", "") + resp = resp.replace("```", "") + + print("Send response...", flush=True) + r = TextCompletionResponse(response=resp) + self.producer.send(r, properties={"id": id}) + + print("Done.", flush=True) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + except google.api_core.exceptions.ResourceExhausted: + + print("429, resource busy, sleeping", flush=True) + time.sleep(15) + self.consumer.negative_acknowledge(msg) + + except Exception as e: + + print("Exception:", e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='llm-ollama-text', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'llm-complete-text' + default_output_queue = 'llm-complete-text-response' + default_subscriber = 'llm-vertexai-text' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-o', '--output-queue', + default=default_output_queue, + help=f'Output queue (default: {default_output_queue})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + parser.add_argument( + '-m', '--model', + default="gemini-1.0-pro-001", + help=f'LLM model (default: gemini-1.0-pro-001)' + ) + # Also: text-bison-32k + + parser.add_argument( + '-k', '--private-key', + help=f'Google Cloud private JSON file' + ) + + parser.add_argument( + '-r', '--region', + default='us-west1', + help=f'Google Cloud region (default: us-west1)', + ) + + args = parser.parse_args() + + if args.private_key: + credentials = service_account.Credentials.from_service_account_file( + args.private_key + ) + else: + credentials = None + + while True: + + try: + + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + output_queue=args.output_queue, + subscriber=args.subscriber, + log_level=args.log_level, + credentials=credentials, + region=args.region, + model=args.model, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + diff --git a/trustgraph/llm_client.py b/trustgraph/llm_client.py new file mode 100644 index 00000000..5e0df96d --- /dev/null +++ b/trustgraph/llm_client.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +import pulsar +import _pulsar +from pulsar.schema import JsonSchema +from trustgraph.schema import TextCompletionRequest, TextCompletionResponse +import hashlib +import uuid + +# Ugly +ERROR=_pulsar.LoggerLevel.Error +WARN=_pulsar.LoggerLevel.Warn +INFO=_pulsar.LoggerLevel.Info +DEBUG=_pulsar.LoggerLevel.Debug + +class LlmClient: + + def __init__( + self, log_level=ERROR, client_id=None, + pulsar_host="pulsar://pulsar:6650", + ): + + if client_id == None: + client_id = str(uuid.uuid4()) + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level), + ) + + self.producer = self.client.create_producer( + topic='llm-complete-text', + schema=JsonSchema(TextCompletionRequest), + chunking_enabled=True, + ) + + self.consumer = self.client.subscribe( + 'llm-complete-text-response', client_id, + schema=JsonSchema(TextCompletionResponse), + ) + + def request(self, prompt, timeout=500): + + id = str(uuid.uuid4()) + + + r = TextCompletionRequest( + prompt=prompt + ) + self.producer.send(r, properties={ "id": id }) + + while True: + + msg = self.consumer.receive(timeout_millis=timeout * 1000) + + mid = msg.properties()["id"] + + if mid == id: + resp = msg.value().response + self.consumer.acknowledge(msg) + return resp + + # Ignore messages with wrong ID + self.consumer.acknowledge(msg) + + def __del__(self): + + self.producer.close() + self.consumer.close() + self.client.close() + diff --git a/trustgraph/log_level.py b/trustgraph/log_level.py new file mode 100644 index 00000000..65486b29 --- /dev/null +++ b/trustgraph/log_level.py @@ -0,0 +1,20 @@ + +from enum import Enum +import _pulsar + +class LogLevel(Enum): + DEBUG = 'debug' + INFO = 'info' + WARN = 'warn' + ERROR = 'error' + + def __str__(self): + return self.value + + def to_pulsar(self): + if self == LogLevel.DEBUG: return _pulsar.LoggerLevel.Debug + if self == LogLevel.INFO: return _pulsar.LoggerLevel.Info + if self == LogLevel.WARN: return _pulsar.LoggerLevel.Warn + if self == LogLevel.ERROR: return _pulsar.LoggerLevel.Error + raise RuntimeError("Log level mismatch") + diff --git a/trustgraph/prompts.py b/trustgraph/prompts.py new file mode 100644 index 00000000..c6b91ff2 --- /dev/null +++ b/trustgraph/prompts.py @@ -0,0 +1,138 @@ + +def turtle_extract(text): + + prompt = f""" +Study the following text and extract knowledge as +information in Turtle RDF format. +When declaring any new URIs, use prefix, +and declare appropriate namespace tags. + + + +{text} + + + +Do not use placeholders for information you do not know. +You will respond only with raw Turtle RDF data. Do not provide +explanations. Do not use special characters in the abstract text. The +abstract must be written as plain text. Do not add markdown formatting. +""" + + return prompt + +def scholar(text): + + # Build the prompt for Article style extraction + jsonexample = """{ + "title": "Article title here", + "abstract": "Abstract text here", + "keywords": ["keyword1", "keyword2", "keyword3"], + "people": ["person1", "person2", "person3"] +}""" + + promptscholar = f"""Your task is to read the provided text and write a scholarly abstract to fully explain all of the concepts described in the provided text. The abstract must include all conceptual details. + +{text} + + + +- Structure: For the provided text, write a title, abstract, keywords, + and people for the concepts found in the provided text. Ignore + document formatting in the provided text such as table of contents, + headers, footers, section metadata, and URLs. +- Focus on Concepts The abstract must focus on concepts found in the + provided text. The abstract must be factually accurate. Do not + write any concepts not found in the provided text. Do not + speculate. Do not omit any conceptual details. +- Completeness: The abstract must capture all topics the reader will + need to understand the concepts found in the provided text. Describe + all terms, definitions, entities, people, events, concepts, + conceptual relationships, and any other topics necessary for the + reader to understand the concepts of the provided text. + +- Format: Respond in the form of a valid JSON object. + + +{jsonexample} + + +You will respond only with the JSON object. Do not provide +explanations. Do not use special characters in the abstract text. The +abstract must be written as plain text. +""" + + return promptscholar + +def to_json_ld(text): + + prompt = f""" +Study the following text and output any facts you discover in +well-structured JSON-LD format. +Use any schema you understand from schema.org to describe the facts. + + + +{text} + + + +You will respond only with raw JSON-LD data in JSON format. Do not provide +explanations. Do not use special characters in the abstract text. The +abstract must be written as plain text. Do not add markdown formatting +or headers or prefixes. Do not use information which is not present in +the input text. +""" + + return prompt + + +def to_relationships(text): + + prompt = f""" +Study the following text and derive entity relationships. For each +relationship, derive the subject, predicate and object of the relationship. +Output relationships in JSON format as an arary of objects with fields: +- subject: the subject of the relationship +- predicate: the predicate +- object: the object of the relationship +- object-entity: false if the object is a simple data type: name, value or date. true if it is an entity. + + + +{text} + + + +You will respond only with raw JSON format data. Do not provide +explanations. Do not use special characters in the abstract text. The +abstract must be written as plain text. Do not add markdown formatting +or headers or prefixes. +""" + + return prompt + +def to_definitions(text): + + prompt = f""" +Study the following text and derive definitions for any discovered entities. +Do not provide definitions for entities whose definitions are incomplete +or unknown. +Output relationships in JSON format as an arary of objects with fields: +- entity: the name of the entity +- definition: English text which defines the entity + + + +{text} + + + +You will respond only with raw JSON format data. Do not provide +explanations. Do not use special characters in the abstract text. The +abstract will be written as plain text. Do not add markdown formatting +or headers or prefixes. Do not include null or unknown definitions. +""" + + return prompt + diff --git a/trustgraph/rag/__init__.py b/trustgraph/rag/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trustgraph/rag/graph/__init__.py b/trustgraph/rag/graph/__init__.py new file mode 100644 index 00000000..432ae594 --- /dev/null +++ b/trustgraph/rag/graph/__init__.py @@ -0,0 +1,3 @@ + +from . rag import * + diff --git a/trustgraph/rag/graph/__main__.py b/trustgraph/rag/graph/__main__.py new file mode 100755 index 00000000..89ebb780 --- /dev/null +++ b/trustgraph/rag/graph/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from . rag import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/rag/graph/rag.py b/trustgraph/rag/graph/rag.py new file mode 100755 index 00000000..28ad298b --- /dev/null +++ b/trustgraph/rag/graph/rag.py @@ -0,0 +1,172 @@ + +""" +Simple RAG service, performs query using graph RAG an LLM. +Input is query, output is response. +""" + +import pulsar +from pulsar.schema import JsonSchema +import tempfile +import base64 +import os +import argparse +import time + +from ... schema import GraphRagQuery, GraphRagResponse +from ... log_level import LogLevel +from ... graph_rag import GraphRag + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + output_queue, + subscriber, + log_level, + graph_hosts, + vector_store, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(GraphRagQuery), + ) + + self.producer = self.client.create_producer( + topic=output_queue, + schema=JsonSchema(GraphRagResponse), + ) + + self.rag = GraphRag( + pulsar_host=pulsar_host, + graph_hosts=graph_hosts, + vector_store=vector_store, + verbose=True, + ) + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + + # Sender-produced ID + + id = msg.properties()["id"] + + print(f"Handling input {id}...", flush=True) + + response = self.rag.query(v.query) + + print("Send response...", flush=True) + r = GraphRagResponse(response = response) + self.producer.send(r, properties={"id": id}) + + print("Done.", flush=True) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + except Exception as e: + + print("Exception:", e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + print("Closing", flush=True) + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='llm-ollama-text', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'graph-rag-query' + default_output_queue = 'graph-rag-response' + default_subscriber = 'graph-rag' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-o', '--output-queue', + default=default_output_queue, + help=f'Output queue (default: {default_output_queue})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + parser.add_argument( + '-g', '--graph-hosts', + default='cassandra', + help=f'Graph hosts, comma separated (default: cassandra)' + ) + + parser.add_argument( + '-v', '--vector-store', + default='http://milvus:19530', + help=f'Vector host (default: http://milvus:19530)' + ) + + args = parser.parse_args() + + while True: + + try: + + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + output_queue=args.output_queue, + subscriber=args.subscriber, + log_level=args.log_level, + graph_hosts=args.graph_hosts.split(","), + vector_store=args.vector_store, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + diff --git a/trustgraph/schema.py b/trustgraph/schema.py new file mode 100644 index 00000000..d8fd4af7 --- /dev/null +++ b/trustgraph/schema.py @@ -0,0 +1,67 @@ + +from pulsar.schema import Record, Bytes, String, Boolean, Integer, Array, Double + +from enum import Enum + +#class Command(Enum): +# reindex = 1 + +#class IndexCommand(Record): +# command = Command + +class Value(Record): + value = String() + is_uri = Boolean() + type = String() + +class Source(Record): + source = String() + id = String() + title = String() + +class Document(Record): + source = Source() + data = Bytes() + +class TextDocument(Record): + source = Source() + text = Bytes() + +class Chunk(Record): + source = Source() + chunk = Bytes() + +class VectorsChunk(Record): + source = Source() + vectors = Array(Array(Double())) + chunk = Bytes() + +class VectorsAssociation(Record): + source = Source() + vectors = Array(Array(Double())) + entity = Value() + +class Triple(Record): + source = Source() + s = Value() + p = Value() + o = Value() + +class TextCompletionRequest(Record): + prompt = String() + +class TextCompletionResponse(Record): + response = String() + +class EmbeddingsRequest(Record): + text = String() + +class EmbeddingsResponse(Record): + vectors = Array(Array(Double())) + +class GraphRagQuery(Record): + query = String() + +class GraphRagResponse(Record): + response = String() + diff --git a/trustgraph/trustgraph.py b/trustgraph/trustgraph.py new file mode 100644 index 00000000..a7b53a06 --- /dev/null +++ b/trustgraph/trustgraph.py @@ -0,0 +1,108 @@ + +from cassandra.cluster import Cluster +from cassandra.auth import PlainTextAuthProvider + +class TrustGraph: + + def __init__(self, hosts=None): + + if hosts is None: + hosts = ["localhost"] + + self.cluster = Cluster(hosts) + self.session = self.cluster.connect() + + self.init() + + def clear(self): + + self.session.execute(""" + drop keyspace if exists trustgraph; + """); + + self.init() + + def init(self): + + self.session.execute(""" + create keyspace if not exists trustgraph + with replication = { + 'class' : 'SimpleStrategy', + 'replication_factor' : 1 + }; + """); + + self.session.set_keyspace('trustgraph') + + self.session.execute(""" + create table if not exists triples ( + s text, + p text, + o text, + PRIMARY KEY (s, p) + ); + """); + + self.session.execute(""" + create index if not exists triples_p + ON triples (p); + """); + + self.session.execute(""" + create index if not exists triples_o + ON triples (o); + """); + + def insert(self, s, p, o): + + self.session.execute( + "insert into triples (s, p, o) values (%s, %s, %s)", + (s, p, o) + ) + + def get_all(self, limit=50): + return self.session.execute( + f"select s, p, o from triples limit {limit}" + ) + + def get_s(self, s, limit=10): + return self.session.execute( + f"select p, o from triples where s = %s", + (s,) + ) + + def get_p(self, p, limit=10): + return self.session.execute( + f"select s, o from triples where p = %s limit {limit}", + (p,) + ) + + def get_o(self, o, limit=10): + return self.session.execute( + f"select s, p from triples where o = %s limit {limit}", + (o,) + ) + + def get_sp(self, s, p, limit=10): + return self.session.execute( + f"select o from triples where s = %s and p = %s limit {limit}", + (s, p) + ) + + def get_po(self, p, o, limit=10): + return self.session.execute( + f"select s from triples where p = %s and o = %s allow filtering limit {limit}", + (p, o) + ) + + def get_os(self, o, s, limit=10): + return self.session.execute( + f"select s from triples where o = %s and s = %s limit {limit}", + (o, s) + ) + + def get_spo(self, s, p, o, limit=10): + return self.session.execute( + f"""select s as x from triples where s = %s and p = %s and o = %s limit {limit}""", + (s, p, o) + ) diff --git a/trustgraph/vector/__init__.py b/trustgraph/vector/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/trustgraph/vector/milvus_write/__init__.py b/trustgraph/vector/milvus_write/__init__.py new file mode 100644 index 00000000..d891d55f --- /dev/null +++ b/trustgraph/vector/milvus_write/__init__.py @@ -0,0 +1,3 @@ + +from . write import * + diff --git a/trustgraph/vector/milvus_write/__main__.py b/trustgraph/vector/milvus_write/__main__.py new file mode 100755 index 00000000..c05d8c6d --- /dev/null +++ b/trustgraph/vector/milvus_write/__main__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 + +from . write import run + +if __name__ == '__main__': + run() + diff --git a/trustgraph/vector/milvus_write/write.py b/trustgraph/vector/milvus_write/write.py new file mode 100755 index 00000000..6a5700d9 --- /dev/null +++ b/trustgraph/vector/milvus_write/write.py @@ -0,0 +1,136 @@ + +""" +Simple decoder, accepts PDF documents on input, outputs pages from the +PDF document as text as separate output objects. +""" + +import pulsar +from pulsar.schema import JsonSchema +from langchain_community.document_loaders import PyPDFLoader +import tempfile +import base64 +import os +import argparse +import time + +from ... schema import VectorsAssociation +from ... log_level import LogLevel +from ... edge_map import VectorStore + +class Processor: + + def __init__( + self, + pulsar_host, + input_queue, + subscriber, + store_uri, + log_level, + ): + + self.client = pulsar.Client( + pulsar_host, + logger=pulsar.ConsoleLogger(log_level.to_pulsar()) + ) + + self.consumer = self.client.subscribe( + input_queue, subscriber, + schema=JsonSchema(VectorsAssociation), + ) + + self.vecstore = VectorStore(store_uri) + + def run(self): + + while True: + + msg = self.consumer.receive() + + try: + + v = msg.value() + + if v.entity.value != "": + for vec in v.vectors: + self.vecstore.insert(vec, v.entity.value) + + # Acknowledge successful processing of the message + self.consumer.acknowledge(msg) + + except Exception as e: + + print("Exception:", e, flush=True) + + # Message failed to be processed + self.consumer.negative_acknowledge(msg) + + def __del__(self): + self.client.close() + +def run(): + + parser = argparse.ArgumentParser( + prog='pdf-decoder', + description=__doc__, + ) + + default_pulsar_host = os.getenv("PULSAR_HOST", 'pulsar://pulsar:6650') + default_input_queue = 'vectors-load' + default_subscriber = 'vector-write-milvus' + + parser.add_argument( + '-p', '--pulsar-host', + default=default_pulsar_host, + help=f'Pulsar host (default: {default_pulsar_host})', + ) + + parser.add_argument( + '-i', '--input-queue', + default=default_input_queue, + help=f'Input queue (default: {default_input_queue})' + ) + + parser.add_argument( + '-s', '--subscriber', + default=default_subscriber, + help=f'Queue subscriber name (default: {default_subscriber})' + ) + + parser.add_argument( + '-l', '--log-level', + type=LogLevel, + default=LogLevel.INFO, + choices=list(LogLevel), + help=f'Output queue (default: info)' + ) + + parser.add_argument( + '-t', '--store-uri', + default="http://localhost:19530", + help=f'Milvus store URI (default: http://localhost:19530)' + ) + + args = parser.parse_args() + + while True: + + try: + + p = Processor( + pulsar_host=args.pulsar_host, + input_queue=args.input_queue, + subscriber=args.subscriber, + store_uri=args.store_uri, + log_level=args.log_level, + ) + + p.run() + + except Exception as e: + + print("Exception:", e, flush=True) + print("Will retry...", flush=True) + + time.sleep(10) + + diff --git a/trustgraphETL.py b/trustgraphETL.py new file mode 100644 index 00000000..91892625 --- /dev/null +++ b/trustgraphETL.py @@ -0,0 +1,718 @@ + +# import boto3 +import json +import re +import rdflib +import time +from langchain_community.document_loaders import PyPDFLoader +from langchain_community.llms import Ollama + +from mistralai.client import MistralClient +from mistralai.models.chat_completion import ChatMessage + +llm = Ollama( + base_url="http://monster:11434", +# model="deepseek-v2" +# model="phi3:14b" + model="gemma2" +) + +api_key = open("mistral-ai.key").read().strip() + +client = MistralClient(api_key=api_key) +model = "open-mixtral-8x7b" + +# from llama_index.core import Document +# from llama_index.core.node_parser import SentenceSplitter +# from unisim import TextSim + +# bedrock = boto3.client(service_name='bedrock-runtime', region_name="us-west-2") + +exampleXML = f"""## RDF/XML Examples: + +```xml + + + + + + + + + + + +``` + +```xml + + + + + RDF 1.1 XML Syntax + RDF 1.1 XML Syntax + RDF 1.1 XML Syntax + + + + Der Baum + Das Buch ist außergewöhnlich + The Tree + + +``` + +```xml + + + + + + + + + + + + +``` + +## RDF/XML Instructions: +1. All valid RDF/XML shall written with the following first line: +2. The subject of a RDF triple must be a URI, Uniform Resource Identifier. +3. The predicate of a RDF triple must be a URI, Uniform Resource Identier. +4. All URIs must use the following base URL: http://example.org/ +5. Predicates should be written using knowledge schema using the SKOS, Simple Knowledge Organization System, approach. +6. The object of a RDF triple can be a URI or a value. +7. If the object of a RDF triple is a value, the object should have a XSD type. +""" + +exampleTurtle = """Knowledge is written between <<<>>>>. That knowledge will be rewritten as RDF Turtle. + +<<>> + +Here's the RDF Turtle for the knowledge +```turtle +@prefix rdf: . +@prefix animal: . +@prefix prop: . +@prefix type: . +@prefix rdfs: . + +animal:fred + prop:has-legs 4 ; + prop:lives-with animal:hope ; + a type:cat ; + rdfs:label "Fred" . + +animal:hope + prop:has-legs 4 ; + prop:lives-with animal:fred ; + a type:cat ; + rdfs:label "Hope" . + +prop:has-legs + a rdfs:Property ; + rdfs:label "has legs" . + +prop:lives-with + a rdfs:Property ; + rdfs:label "lives with" . + +type:cat + a rdfs:Class ; + rdfs:label "cat" . +``` + +# RDF Turtle Rules +1. The object of a RDF triple can be a URI or a value. +2. If the object of a RDF triple is a value, the object should have a XSD type. +3. All triples must have a subject, predicate, and object. +4. A subject shall always be followed by a predicate and object. +5. When a subject has multiple sets of predicates and objects, use a semicolon character to separate each set of predicates and objects. +6. When a subject and predicate have multiple objects, use a comma character to separate the set of objects. +7. Use the 'a' character in place of the predicate 'is'. +8. Use @prefix rdf: . +9. Use @prefix rdfs: . +10. Use @prefix xsd: . +""" + +# Build the prompt for Article style extraction +def scholar(chunk): + promptscholar = f"""[INST]You are a scholar. You have profound knowledge of the provided text. Your task is to read the provided text and write an article to fully explain the provided text. + + # Provided Text: + {chunk} + + # Instructions: + ## Focus on Concepts + The article should focus on concepts in the provided text. The article should be factually accurate. Do not write any concepts not found in the provided text. Do not speculate. + + ## Completeness + The article should capture all topics the reader will need to understand the concepts found in the provided text. Describe all terms, definitions, entities, people, events, concepts, conceptual relationships, and any other topics necessary for the reader to understand the concepts of the provided text. + [/INST] + """ + return promptscholar + +# Build the prompt for the custom RDF/XML schema +def schema(article): + promptschema = f"""[INST]You are a scholar. You have profound understanding of knowledge schemas that are parsed into RDF knowledge graphs. Your task is to read the provided article and write a complete RDF/XML document for the provided article. You will respond only with the RDF/XML document. Do not provide explanations. Obey all RDF/XML instructions. + + # Provided Article: + {article} + + # Example RDF/XML and Instructions: + {exampleXML} + [/INST] + """ + return promptschema + +# Build the prompt for the SKOS style RDF/XML schema +def skos(article): + promptconcepts = f"""[INST]You are a scholar. You have profound understanding of knowledge schemas that are parsed into RDF knowledge graphs. Your task is to read the provided article and write a complete RDF/XML document for the provided article that uses SKOS, Simple Knowledge Organization System, to structure the conceptual relationships in the article. You will respond only with the RDF/XML document. Do not provide explanations. Obey all RDF/XML instructions. + + # Provided Article: + {article} + + # RDF/XML Example and Instructions: + {exampleXML} + [/INST] + """ + return promptconcepts + +# Add the outputs from the first pass to stabilize the build process +def example_follow(x1, x2): + exampleXML = f"""## RDF/XML Examples: + +```xml + + + + + + + + + + + +``` + +```xml + + + + + RDF 1.1 XML Syntax + RDF 1.1 XML Syntax + RDF 1.1 XML Syntax + + + + Der Baum + Das Buch ist außergewöhnlich + The Tree + + +``` + +```xml + + + + + + + + + + + + +``` + +```xml +{x1} +``` + +```xml +{x2} +``` + +## RDF/XML Instructions: +1. All valid RDF/XML shall written with the following first line: +2. The subject of a RDF triple must be a URI, Uniform Resource Identifier. +3. The predicate of a RDF triple must be a URI, Uniform Resource Identier. +4. All URIs must use the following base URL: http://example.org/ +5. Predicates should be written using knowledge schema using the SKOS, Simple Knowledge Organization System, approach. +6. The object of a RDF triple can be a URI or a value. +7. If the object of a RDF triple is a value, the object should have a XSD type. +""" + return exampleXML + +# Build the follow prompt for the custom RDF/XML schema +def schema_follow(article, example_follow): + promptschema = f"""[INST]You are a scholar. You have profound understanding of knowledge schemas that are parsed into RDF knowledge graphs. Your task is to read the provided article and write a complete RDF/XML document for the provided article. You will respond only with the RDF/XML document. Do not provide explanations. Obey all RDF/XML instructions. + + # Provided Article: + {article} + + # Example RDF/XML and Instructions: + {example_follow} + [/INST] + """ + return promptschema + +# Build the follow prompt for the SKOS style RDF/XML schema +def skos_follow(article, example_follow): + promptconcepts = f"""[INST]You are a scholar. You have profound understanding of knowledge schemas that are parsed into RDF knowledge graphs. Your task is to read the provided article and write a complete RDF/XML document for the provided article that uses SKOS, Simple Knowledge Organization System, to structure the conceptual relationships in the article. You will respond only with the RDF/XML document. Do not provide explanations. Obey all RDF/XML instructions. + + # Provided Article: + {article} + + # RDF/XML Example and Instructions: + {example_follow} + [/INST] + """ + return promptconcepts + + +def p1(chunk): + promptcustom = f"""[INST]You write knowledge schemas that are parsed into RDF knowledge graphs. You read the provided text and develop a knwoledge schema to represent the concepts. Your task is to read the provided text and write a RDF Turtle schema for the concepts found in the provided text. You will respond only with the RDF Turtle schema. Do not provide explanations. Obey all of the provided RDF Turtle rules. + + # RDF Turtle Example and Rules + {exampleTurtle} + + # Provided Text + {chunk} + [/INST] + """ + return promptcustom + +def p2(chunk): + promptconcepts = f"""[INST]You write knowledge schemas that are parsed into RDF knowledge graphs. You read the provided text and develop a knwoledge schema to represent the conceptual relationships in the text. Your task is to read the provided text and write a RDF Turtle schema for the concepts found in the provided text using SKOS, Simple Knowledge Organization System. You will respond only with the RDF Turtle schema. Do not provide explanations. Obey all of the provided RDF Turtle rules. + + # Valid RDF Turtle Example and Rules + {exampleTurtle} + + # Provided Text + {chunk} + [/INST] + """ + return promptconcepts + +def summaryprompt(chunk): + promptsummary = f"""[INST]You are an analyst. You read complex text and write a detailed summary. Your task is to read the provided text and write a thorough summary that captures all of the key points. + + # Provided text: + {chunk} + + # Instructions: + ## Summarize: + In clear and concise language, summarize the key points in the provided text. + + ## Key Points: + It is important to capture unique terms and their definitions, entities, people, events, concepts, conceptual relationships, and relationships between entities and people. + + ## Requirements: + Include all key points in the summary. Do not omit any facts that might be considered a key point. + [/INST] + """ + return promptsummary + +def extractpdf(path): + loader = PyPDFLoader(path) + pages = loader.load_and_split() + pdf = f"" + for page in pages: + content = page.page_content + pdf += "".join(content) + return pdf + +def chunktext(splitpdf, chunk_size, chunk_overlap): + node_parser = SentenceSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap) + nodes = node_parser.get_nodes_from_documents([Document(text=splitpdf)], show_progress=False) + textlist = [] + for node in nodes: + textnode = node.text + textlist.append(textnode) + return textlist + +def OLDcallmixtral(prompt): + + chat_response = client.chat( + model=model, + messages=[ + ChatMessage( + role="user", content=prompt + ) + ] + ) + + print(chat_response) + resp = chat_response.choices[0].message.content + print(resp) + + return resp + +def callmixtral(prompt): + + print(prompt) + resp = llm.invoke(prompt) + print(resp) + + return resp + +def extract_xml(text): + cleantext = replace_ampersand(text) + pattern = r'<\?xml version="1\.0"\?>.*?' + match = re.search(pattern, cleantext, re.DOTALL) + + if match: + return match.group() + else: + return None + +def replace_ampersand(text): + return text.replace('&', 'and') + +def convert_summary(dataset): + num_passes = len(dataset) + print("Beginning Converting to Summaries") + + start_time = time.time() # Start the timer + + summaries = [] + + for i in range(5): + print(f"Begin Pass {i+1}") + promptchunk = dataset[i] + prompt = summaryprompt(promptchunk) + output = callmixtral(prompt) + summaries.append(output) + print(f"Finished Pass {i+1}") + + end_time = time.time() # End the timer + total_time = end_time - start_time # Calculate the total time + print(f"Total time taken: {total_time:.2f} seconds") + return summaries + +def extract_articles(dataset): + num_passes = len(dataset) + print("Beginning Converting to Articles") + + start_time = time.time() # Start the timer + + articles = [] + + # Only Doing 5 chunks for now... + for i in range(5): + print(f"Begin Pass {i+1}") + promptchunk = dataset[i] + prompt = scholar(promptchunk) #Build the prompt + output = callmixtral(prompt) + articles.append(output) + print(f"Finished Pass {i+1}") + + end_time = time.time() # End the timer + total_time = end_time - start_time # Calculate the total time + print(f"Total time taken: {total_time:.2f} seconds") + return articles + +def full_extract(dataset): + g = rdflib.Graph() + num_passes = len(dataset) + print(f"Initializing Graph and beginning extraction:") + + start_time = time.time() # Start the timer + + for i in range(num_passes): + print(f"Begin Pass {i+1}") + output1 = "" + output2 = "" + promptchunk = dataset[i] + prompt1 = p1(promptchunk) + prompt2 = p2(promptchunk) + + output1 = callmixtral(prompt1) + + # Extract text between ### characters from output1 + match1 = re.search(r'###(.*?)###', output1, re.DOTALL) + if match1: + data1 = match1.group() + g.parse(data=data1, format="turtle") + print(f"Complete first half of Pass {i+1} from ###") + else: + g.parse(data=output1, format="turtle") + print(f"Complete first half of Pass {i+1} raw") + + output2 = callmixtral(prompt2) + + # Extract text between ### characters from output2 + match2 = re.search(r'###(.*?)###', output2, re.DOTALL) + if match2: + data2 = match2.group() + g.parse(data=data2, format="turtle") + print(f"Completed Pass {i+1} from ###") + else: + g.parse(data=output2, format="turtle") + print(f"Complete Pass {i+1} raw") + + running_length = len(g) + print(f"Pass {i+1} Graph Length: {running_length}") + + end_time = time.time() # End the timer + total_time = end_time - start_time # Calculate the total time + + print("Holy shit! This actually worked?!?!?!") + print(f"Total time taken: {total_time:.2f} seconds") + return g + +def firstpass_build(dataset): + firstpass = [] + out1 = "" + out2 = "" + chunk = dataset[0] + p1 = schema(chunk) + p2 = skos(chunk) + out1 = callmixtral(p1) + out2 = callmixtral(p2) + xml1 = extract_xml(out1) + xml2 = extract_xml(out2) + firstpass.append(xml1) + firstpass.append(xml2) + return firstpass + +def build_graph(dataset): + start_time = time.time() # Start the timer + + #Build the first set of outputs + firstset = [] + firstset = firstpass_build(dataset) + example1 = firstset[0] + example2 = firstset[1] + + #Build the new set of examples using first pass outputs + newexamples = example_follow(example1, example2) + + print(f"Initializing Graph:") + g = rdflib.Graph() + # Parse the outputs from the first pass function + g.parse(data=firstset[0], format="xml") + g.parse(data=firstset[1], format="xml") + print(f"Parsed First Pass, Graph Length: {len(g)}") + + num_passes = len(dataset) + + for i in range(1, num_passes, 1): + output1 = "" + output2 = "" + promptchunk = dataset[i] + prompt1 = schema_follow(promptchunk, newexamples) #Build the schema follow prompt + prompt2 = skos_follow(promptchunk, newexamples) #Build the SKOS follow prompt + + # Get schema style output + output1 = callmixtral(prompt1) + + # Extract text between ```xml``` characters from output1 + match1 = extract_xml(output1) + if match1: + data1 = match1 + g.parse(data=data1, format="xml") + + # Get SKOS style output + output2 = callmixtral(prompt2) + + # Extract text between ```xml``` characters from output2 + match2 = extract_xml(output2) + if match2: + data2 = match2 + g.parse(data=data2, format="xml") + + running_length = len(g) + print(f"Parsed Pass {i+1}, Graph Length: {running_length}") + + end_time = time.time() # End the timer + total_time = end_time - start_time # Calculate the total time + + outputpath = f"../Columbia_graph_extract.ttl" + g.serialize(destination=outputpath, format="turtle") + print("Holy shit! This actually worked?!?!?!") + print(f"Total time taken: {total_time:.2f} seconds") + return + +# Graph Building with some error handling and return the graph +def build_graph_robust(dataset): + start_time = time.time() # Start the timer + + #Build the first set of outputs + firstset = [] + firstset = firstpass_build(dataset) + example1 = firstset[0] + example2 = firstset[1] + + #Build the new set of examples using first pass outputs + newexamples = example_follow(example1, example2) + + print(f"Initializing Graph:") + g = rdflib.Graph() + # Parse the outputs from the first pass function + try: + g.parse(data=firstset[0], format="xml") + g.parse(data=firstset[1], format="xml") + print(f"Parsed First Pass, Graph Length: {len(g)}") + except Exception as e: + print(f"Error parsing first pass outputs: {str(e)}") + return None + + num_passes = len(dataset) + + i = 1 + while i < num_passes: + output1 = "" + output2 = "" + promptchunk = dataset[i] + prompt1 = schema_follow(promptchunk, newexamples) #Build the schema follow prompt + prompt2 = skos_follow(promptchunk, newexamples) #Build the SKOS follow prompt + + # Get schema style output + output1 = callmixtral(prompt1) + + # Extract text between ```xml``` characters from output1 + match1 = extract_xml(output1) + if match1: + data1 = match1 + try: + g.parse(data=data1, format="xml") + except Exception as e: + print(f"Error parsing schema output in pass {i+1}: {str(e)}\n\nTrying Again...") + continue + + # Get SKOS style output + output2 = callmixtral(prompt2) + + # Extract text between ```xml``` characters from output2 + match2 = extract_xml(output2) + if match2: + data2 = match2 + try: + g.parse(data=data2, format="xml") + except Exception as e: + print(f"Error parsing SKOS output in pass {i+1}: {str(e)}\n\nTrying Again...") + continue + + running_length = len(g) + print(f"Parsed Pass {i+1}, Graph Length: {running_length}") + i += 1 + + end_time = time.time() # End the timer + total_time = end_time - start_time # Calculate the total time + +# outputpath = f"./Columbia_graph_extract.ttl" +# g.serialize(destination=outputpath, format="turtle") + print("Holy shit! This actually worked?!?!?!") + print(f"Total time taken: {total_time:.2f} seconds") + return g + +# Get a list of subjects from graph as URIs +def get_subject_list(graph): + query = """ + SELECT DISTINCT ?subject + WHERE { + ?subject ?predicate ?object . + } + """ + + subjects = graph.query(query) + + subjectlist = [] + for row in subjects: + text = f"{row.subject}" + subjectlist.append(text) + + return subjectlist + +# Function for removing URI artifacts to return clean text +def clean_resource(resource): + # Remove the URL prefixes + cleaned_resource = resource.replace("http://example.org/", "") + cleaned_resource = cleaned_resource.replace("http://www.w3.org/2004/02/skos/core#", "") + cleaned_resource = cleaned_resource.replace("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "") + cleaned_resource = cleaned_resource.replace("http://www.w3.org/2001/XMLSchema#", "") + cleaned_resource = cleaned_resource.replace("http://purl.org/dc/elements/1.1/", "") + + # Replace special symbols with a space + cleaned_resource = re.sub(r'[_#/]', ' ', cleaned_resource) + + return cleaned_resource + +# Clean the entire subject list +def clean_subject_list(subjectlist): + cleaned_subjects = [] + for subject in subjectlist: + clean = f"{clean_resource(subject)}" + cleaned_subjects.append(clean) + + return cleaned_subjects + +# Dump all the triples from the Graph +def get_triples_list(graph): + triples_list = list(graph.triples((None, None, None))) + + semantic_list = [] + for subject, predicate, object in triples_list: + triple = f"{subject} {predicate} {object}" + semantic_list.append(triple) + + return semantic_list + +#Clean the entire triples list +def clean_triples_list(tripleslist): + cleaned_triples = [] + for triple in tripleslist: + cleaned_triple = clean_resource(triple) + cleaned_triples.append(cleaned_triple) + + return cleaned_triples + +# Build UniSim instance for graph subjects +def build_subject_Sim(graph): + subject_sim = TextSim() + subject_sim.reset_index() # Make sure it's empty + subject_sim = TextSim( + store_data=True, # set to False for large datasets to save memory + index_type="exact", # set to "approx" for large datasets to use ANN search + batch_size=128, # increasing batch_size on GPU may be faster + use_accelerator=True, # uses GPU if available, otherwise uses CPU + ) + + subjects = get_subject_list(graph) # Get the subjects + clean_subjects = clean_subject_list(subjects) # Clean the subjects + idx = subject_sim.add(clean_subjects) # Build sim + return subject_sim + +# Build UniSim instance for graph triples +def build_triples_Sim(graph): + triples_sim = TextSim() + triples_sim.reset_index() # Make sure it's empty + triples_sim = TextSim( + store_data=True, # set to False for large datasets to save memory + index_type="exact", # set to "approx" for large datasets to use ANN search + batch_size=128, # increasing batch_size on GPU may be faster + use_accelerator=True, # uses GPU if available, otherwise uses CPU + ) + + triples = get_triples_list(graph) # Get the triples + clean_triples = clean_triples_list(triples) # Clean the triples + idx = triples_sim.add(clean_triples) # Build sim + return triples_sim diff --git a/trustgraphETL2.py b/trustgraphETL2.py new file mode 100644 index 00000000..6e1dea79 --- /dev/null +++ b/trustgraphETL2.py @@ -0,0 +1,875 @@ + +import json +import re +import rdflib +import time +from langchain_community.document_loaders import PyPDFLoader +from llama_index.core import Document +from llama_index.core.node_parser import SentenceSplitter +from langchain_community.llms import Ollama + +llm = Ollama( + base_url="http://monster:11434", +# model="deepseek-v2" + model="phi3:14b" +# model="gemma2" +) + +exampleXML = f"""## RDF/XML Examples: + +```xml + + + + + + + + + + + +``` + +```xml + + + + + RDF 1.1 XML Syntax + RDF 1.1 XML Syntax + RDF 1.1 XML Syntax + + + + Der Baum + Das Buch ist außergewöhnlich + The Tree + + +``` + +```xml + + + + + + + + + + + + +``` + +## RDF/XML Instructions: +1. All valid RDF/XML shall written with the following first line: +2. The subject of a RDF triple must be a URI, Uniform Resource Identifier. +3. The predicate of a RDF triple must be a URI, Uniform Resource Identier. +4. All URIs must use the following base URL: http://example.org/ +5. Predicates should be written using knowledge schema using the SKOS, Simple Knowledge Organization System, approach. +6. The object of a RDF triple can be a URI or a value. +7. If the object of a RDF triple is a value, the object should have a XSD type. +""" + +exampleTurtle = """Knowledge is written between <<<>>>>. That knowledge will be rewritten as RDF Turtle. + +<<>> + +Here's the RDF Turtle for the knowledge +```turtle +@prefix rdf: . +@prefix animal: . +@prefix prop: . +@prefix type: . +@prefix rdfs: . + +animal:fred + prop:has-legs 4 ; + prop:lives-with animal:hope ; + a type:cat ; + rdfs:label "Fred" . + +animal:hope + prop:has-legs 4 ; + prop:lives-with animal:fred ; + a type:cat ; + rdfs:label "Hope" . + +prop:has-legs + a rdfs:Property ; + rdfs:label "has legs" . + +prop:lives-with + a rdfs:Property ; + rdfs:label "lives with" . + +type:cat + a rdfs:Class ; + rdfs:label "cat" . +``` + +# RDF Turtle Rules +1. The object of a RDF triple can be a URI or a value. +2. If the object of a RDF triple is a value, the object should have a XSD type. +3. All triples must have a subject, predicate, and object. +4. A subject shall always be followed by a predicate and object. +5. When a subject has multiple sets of predicates and objects, use a semicolon character to separate each set of predicates and objects. +6. When a subject and predicate have multiple objects, use a comma character to separate the set of objects. +7. Use the 'a' character in place of the predicate 'is'. +8. Use @prefix rdf: . +9. Use @prefix rdfs: . +10. Use @prefix xsd: . +""" + +# Build the prompt for Article style extraction +jsonexample = """{ + "title": "Article title here", + "abstract": "Abstract text here", + "keywords": ["keyword1", "keyword2", "keyword3"], + "people": ["person1", "person2", "person3"] +}""" + +def scholar(chunk): + promptscholar = f"""Your task is to read the provided text and write a scholarly abstract to fully explain all of the concepts described in the provided text. The abstract should include all conceptual details. + +{chunk} + + + +- Structure: For the provided text, write a title, abstract, keywords, + and people for the concepts found in the provided text. Ignore + document formatting in the provided text such as table of contents, + headers, footers, section metadata, and URLs. +- Focus on Concepts The abstract should focus on concepts found in the + provided text. The abstract should be factually accurate. Do not + write any concepts not found in the provided text. Do not + speculate. Do not omit any conceptual details. +- Completeness: The abstract should capture all topics the reader will + need to understand the concepts found in the provided text. Describe + all terms, definitions, entities, people, events, concepts, + conceptual relationships, and any other topics necessary for the + reader to understand the concepts of the provided text. + +- Format: Respond in the form of a valid JSON object. + + +{jsonexample} + + +You will respond only with the JSON object. Do not provide +explanations. Do not use special characters in the abstract text. The +abstract should be written as plain text. +""" + + return promptscholar + +# Build the prompt for the custom RDF/XML schema +def schema(article): + promptschema = f"""[INST]You are a scholar. Your subject of expertise is {article['title']}. You have expert understanding of knowledge schemas that are parsed into RDF knowledge graphs. Your task is to read the provided article and write a complete RDF/XML document for the provided article. You will respond only with the RDF/XML document. Do not provide explanations. Obey all RDF/XML instructions. + + # Provided Article: + {article['abstract']} + + # Example RDF/XML and Instructions: + {exampleXML} + [/INST] + + # Keyword Annotations: + Add RDF/XML labels to the applicable concepts using the following list of keywords: + {article['keywords']} + + # People Annotations: + + Add RDF/XML labels to the applicable concepts using the following list of people: + {article['people']} + """ + return promptschema + +# Build the prompt for the SKOS style RDF/XML schema +def skos(article): + promptconcepts = f"""[INST]You are a scholar. Your subject of expertise is {article['title']}. You have expert understanding of knowledge schemas that are parsed into RDF knowledge graphs. Your task is to read the provided article and write a complete RDF/XML document for the provided article that uses SKOS, Simple Knowledge Organization System, to structure the conceptual relationships in the article. You will respond only with the RDF/XML document. Do not provide explanations. Obey all RDF/XML instructions. + + # Provided Article: + {article['abstract']} + + # RDF/XML Example and Instructions: + {exampleXML} + + # Keyword Annotations: + Add RDF/XML labels to the applicable concepts using the following list of keywords: + {article['keywords']} + + # People Annotations: + Add RDF/XML labels to the applicable concepts using the following list of people: + {article['people']} + [/INST] + """ + return promptconcepts + +# Add the outputs from the first pass to stabilize the build process +def example_follow(x1, x2): + exampleXML = f"""## RDF/XML Examples: + +```xml + + + + + + + + + + + +``` + +```xml + + + + + RDF 1.1 XML Syntax + RDF 1.1 XML Syntax + RDF 1.1 XML Syntax + + + + Der Baum + Das Buch ist außergewöhnlich + The Tree + + +``` + +```xml + + + + + + + + + + + + +``` + +```xml +{x1} +``` + +```xml +{x2} +``` + +## RDF/XML Instructions: +1. All valid RDF/XML shall written with the following first line: +2. The subject of a RDF triple must be a URI, Uniform Resource Identifier. +3. The predicate of a RDF triple must be a URI, Uniform Resource Identier. +4. All URIs must use the following base URL: http://example.org/ +5. Predicates should be written using knowledge schema using the SKOS, Simple Knowledge Organization System, approach. +6. The object of a RDF triple can be a URI or a value. +7. If the object of a RDF triple is a value, the object should have a XSD type. +""" + return exampleXML + +# Build the follow prompt for the custom RDF/XML schema +def schema_follow(article, example_follow): + promptschema = f"""[INST]You are a scholar. Your subject of expertise is {article['title']}. You have expert understanding of knowledge schemas that are parsed into RDF knowledge graphs. Your task is to read the provided article and write a complete RDF/XML document for the provided article. You will respond only with the RDF/XML document. Do not provide explanations. Obey all RDF/XML instructions. + + # Provided Article: + {article['abstract']} + + # Example RDF/XML and Instructions: + {example_follow} + + # Keyword Annotations: + Add RDF/XML labels to the applicable concepts using the following list of keywords: + {article['keywords']} + + # People Annotations: + Add RDF/XML labels to the applicable concepts using the following list of people: + {article['people']} + [/INST] + """ + return promptschema + +# Build the follow prompt for the SKOS style RDF/XML schema +def skos_follow(article, example_follow): + promptconcepts = f"""[INST]You are a scholar. Your subject of expertise is {article['title']}. You have expert understanding of knowledge schemas that are parsed into RDF knowledge graphs. Your task is to read the provided article and write a complete RDF/XML document for the provided article that uses SKOS, Simple Knowledge Organization System, to structure the conceptual relationships in the article. You will respond only with the RDF/XML document. Do not provide explanations. Obey all RDF/XML instructions. + + # Provided Article: + {article['abstract']} + + # RDF/XML Example and Instructions: + {example_follow} + + # Keyword Annotations: + Add RDF/XML labels to the applicable concepts using the following list of keywords: + {article['keywords']} + + # People Annotations: + Add RDF/XML labels to the applicable concepts using the following list of people: + {article['people']} + [/INST] + """ + return promptconcepts + + +def p1(chunk): + promptcustom = f"""[INST]You write knowledge schemas that are parsed into RDF knowledge graphs. You read the provided text and develop a knwoledge schema to represent the concepts. Your task is to read the provided text and write a RDF Turtle schema for the concepts found in the provided text. You will respond only with the RDF Turtle schema. Do not provide explanations. Obey all of the provided RDF Turtle rules. + + # RDF Turtle Example and Rules + {exampleTurtle} + + # Provided Text + {chunk} + [/INST] + """ + return promptcustom + +def p2(chunk): + promptconcepts = f"""[INST]You write knowledge schemas that are parsed into RDF knowledge graphs. You read the provided text and develop a knwoledge schema to represent the conceptual relationships in the text. Your task is to read the provided text and write a RDF Turtle schema for the concepts found in the provided text using SKOS, Simple Knowledge Organization System. You will respond only with the RDF Turtle schema. Do not provide explanations. Obey all of the provided RDF Turtle rules. + + # Valid RDF Turtle Example and Rules + {exampleTurtle} + + # Provided Text + {chunk} + [/INST] + """ + return promptconcepts + +def summaryprompt(chunk): + promptsummary = f"""[INST]You are an analyst. You read complex text and write a detailed summary. Your task is to read the provided text and write a thorough summary that captures all of the key points. + + # Provided text: + {chunk} + + # Instructions: + ## Summarize: + In clear and concise language, summarize the key points in the provided text. + + ## Key Points: + It is important to capture unique terms and their definitions, entities, people, events, concepts, conceptual relationships, and relationships between entities and people. + + ## Requirements: + Include all key points in the summary. Do not omit any facts that might be considered a key point. + [/INST] + """ + return promptsummary + +def extractpdf(path): + loader = PyPDFLoader(path) + pages = loader.load_and_split() + pdf = f"" + for page in pages: + content = page.page_content + pdf += "".join(content) + return pdf + +def chunktext(splitpdf, chunk_size, chunk_overlap): + node_parser = SentenceSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap) + nodes = node_parser.get_nodes_from_documents([Document(text=splitpdf)], show_progress=False) + textlist = [] + for node in nodes: + textnode = node.text + textlist.append(textnode) + return textlist + +def OLDcallmixtral(prompt): + body = json.dumps({ + "prompt": prompt, + "max_tokens": 4096, + "temperature": 0.0, + "top_p": 0.95, + "top_k": 30 + }) + + modelId = 'mistral.mixtral-8x7b-instruct-v0:1' + accept = 'application/json' + contentType = 'application/json' + response = bedrock.invoke_model(body=body, modelId=modelId, accept=accept, contentType=contentType) + metadata = response['ResponseMetadata']['HTTPHeaders'] + inputtokens = metadata['x-amzn-bedrock-input-token-count'] + outputtokens = metadata['x-amzn-bedrock-output-token-count'] + response_body = json.loads(response.get("body").read()) + outputtext = response_body['outputs'][0]['text'] + output = { + "text": outputtext, + "input_tokens": inputtokens, + "output_tokens": outputtokens + } + return output + +def callmixtral(prompt): + + resp = llm.invoke(prompt) + return resp + +def count_tokens(metadata): + inputtokens + + +def extract_xml(text): + cleantext = replace_ampersand(text) + pattern = r'<\?xml version="1\.0"\?>.*?' + match = re.search(pattern, cleantext, re.DOTALL) + + if match: + return match.group() + else: + return None + +def replace_ampersand(text): + return text.replace('&', 'and') + +# Not currently using +def load_json_from_string(json_string): + # Remove newline characters + json_string = json_string.replace('\n', '') + + # Check if the string contains ```json delimiters + if "```json" in json_string: + # Find the start and end indices of the JSON object + start_index = json_string.find("```json") + 7 + end_index = json_string.rfind("```") + + # Extract the JSON object from the string + json_object = json_string[start_index:end_index].strip() + else: + # Assume the entire string is a valid JSON object + json_object = json_string + + try: + # Load the JSON object as a dictionary + data_dict = json.loads(json_object) + return data_dict + except json.JSONDecodeError: + # Return None if the string is not a valid JSON object + return None + +# Returns JSON for the Scholar Abstract process +def extract_json_from_output(output): + # Get the text content from the output dictionary + text_content = output['text'] + + # Define the keys we're interested in + target_keys = ['title', 'abstract', 'keywords', 'people'] + + # Initialize an empty dictionary to store our extracted data + extracted_data = {} + + # Use regex to find JSON-like structures for each key + for key in target_keys: + pattern = r'"{0}"\s*:\s*(\[.*?\]|\{{.*?\}}|".*?")'.format(re.escape(key)) + match = re.search(pattern, text_content, re.DOTALL) + if match: + # Extract the value and remove any leading/trailing whitespace + value = match.group(1).strip() + + # If the value is a list or dict, parse it + if value.startswith('[') or value.startswith('{'): + try: + extracted_data[key] = json.loads(value) + except json.JSONDecodeError: + # If parsing fails, store it as a string + extracted_data[key] = value + else: + # Remove quotes for string values + extracted_data[key] = value.strip('"') + + return extracted_data + +# Not currently using +def convert_summary(dataset): + num_passes = len(dataset) + print("Beginning Converting to Summaries") + + start_time = time.time() # Start the timer + + summaries = [] + + for i in range(5): + print(f"Begin Pass {i+1}") + promptchunk = dataset[i] + prompt = summaryprompt(promptchunk) + output = callmixtral(prompt) + outputtext = output['text'] + summaries.append(outputtext) + print(f"Finished Pass {i+1}") + + end_time = time.time() # End the timer + total_time = end_time - start_time # Calculate the total time + print(f"Total time taken: {total_time:.2f} seconds") + return summaries + +def count_tokens(in_tokens, out_tokens, running_total): + running_total['input_tokens'] = running_total['input_tokens'] + in_tokens + running_total['output_tokens'] = running_total['output_tokens'] + out_tokens + running_count = {'input_tokens': running_total['input_tokens'], 'output_tokens': running_total['output_tokens']} + return running_count + +def extract_articles(dataset): + num_passes = len(dataset) + + # Initialize the token counts since this is the first step + in_tokens = 0 + out_tokens = 0 + running_total = {'input_tokens': 0, 'output_tokens': 0} + running = count_tokens(in_tokens, out_tokens, running_total) + print("Beginning Converting to Articles") + print(f"Current Input Tokens: {running['input_tokens']}\nCurrent Output Tokens: {running['output_tokens']}") + + start_time = time.time() # Start the timer + + articles = [] + + i = 0 + while i < num_passes: + print(f"Begin Pass {i+1}") + promptchunk = dataset[i] + prompt = scholar(promptchunk) #Build the prompt + output = callmixtral(prompt) + outputjson = extract_json_from_output(output) + + # Check for valid JSON + if outputjson is None: + print(f"Failed to parse JSON in Pass {i+1}. Retrying...") + continue # Restart the loop for this index + + articles.append(outputjson) + running = count_tokens(int(output['input_tokens']), int(output['output_tokens']), running) + print(f"Finished Pass {i+1}") + print(f"Pass {i+1} Input Tokens: {output['input_tokens']}\nPass{i+1} Output Tokens: {output['output_tokens']}") + + i += 1 # Only increment if successful + + end_time = time.time() # End the timer + total_time = end_time - start_time # Calculate the total time + + inputcost = running['input_tokens'] * priceperinput + outputcost = running['output_tokens'] * priceperoutput + totalcost = round(inputcost + outputcost,2) + + print(f"Total time taken: {total_time:.2f} seconds") + print(f"Total Input Tokens: {running['input_tokens']}\nTotal Output Tokens: {running['output_tokens']}") + print(f"Total Cost: ${totalcost}") + return articles + +# NOT CURRENTLY USING +def full_extract(dataset): + g = rdflib.Graph() + num_passes = len(dataset) + print(f"Initializing Graph and beginning extraction:") + + start_time = time.time() # Start the timer + + for i in range(num_passes): + print(f"Begin Pass {i+1}") + output1 = "" + output2 = "" + promptchunk = dataset[i] + prompt1 = p1(promptchunk) + prompt2 = p2(promptchunk) + + output1 = callmixtral(prompt1) + output1text = output1['text'] + + # Extract text between ### characters from output1 + match1 = re.search(r'###(.*?)###', output1text, re.DOTALL) + if match1: + data1 = match1.group() + g.parse(data=data1, format="turtle") + print(f"Complete first half of Pass {i+1} from ###") + else: + g.parse(data=output1text, format="turtle") + print(f"Complete first half of Pass {i+1} raw") + + output2 = callmixtral(prompt2) + output2text = output2['text'] + + # Extract text between ### characters from output2 + match2 = re.search(r'###(.*?)###', output2text, re.DOTALL) + if match2: + data2 = match2.group() + g.parse(data=data2, format="turtle") + print(f"Completed Pass {i+1} from ###") + else: + g.parse(data=output2text, format="turtle") + print(f"Complete Pass {i+1} raw") + + running_length = len(g) + print(f"Pass {i+1} Graph Length: {running_length}") + + end_time = time.time() # End the timer + total_time = end_time - start_time # Calculate the total time + + outputpath = f"../Columbia_graph_extract.ttl" + g.serialize(destination=outputpath) + print("Holy shit! This actually worked?!?!?!") + print(f"Total time taken: {total_time:.2f} seconds") + return + +def firstpass_build(dataset): + firstpass = [] + out1 = "" + out2 = "" + chunk = dataset[0] + p1 = schema(chunk) + p2 = skos(chunk) + out1 = callmixtral(p1) + out1text = out1['text'] + out2 = callmixtral(p2) + out2text = out2['text'] + xml1 = extract_xml(out1text) + xml2 = extract_xml(out2text) + firstpass.append(xml1) + firstpass.append(xml2) + return firstpass + +# NOT CURRENTLY USING +def build_graph(dataset): + start_time = time.time() # Start the timer + + #Build the first set of outputs + firstset = [] + firstset = firstpass_build(dataset) + example1 = firstset[0] + example2 = firstset[1] + + #Build the new set of examples using first pass outputs + newexamples = example_follow(example1, example2) + + print(f"Initializing Graph:") + g = rdflib.Graph() + # Parse the outputs from the first pass function + g.parse(data=firstset[0], format="xml") + g.parse(data=firstset[1], format="xml") + print(f"Parsed First Pass, Graph Length: {len(g)}") + + num_passes = len(dataset) + + for i in range(1, num_passes, 1): + output1 = "" + output2 = "" + promptchunk = dataset[i] + prompt1 = schema_follow(promptchunk, newexamples) #Build the schema follow prompt + prompt2 = skos_follow(promptchunk, newexamples) #Build the SKOS follow prompt + + # Get schema style output + output1 = callmixtral(prompt1) + output1text = output1['text'] + + # Extract text between ```xml``` characters from output1 + match1 = extract_xml(output1text) + if match1: + data1 = match1 + g.parse(data=data1, format="xml") + + # Get SKOS style output + output2 = callmixtral(prompt2) + output2text = output2['text'] + + # Extract text between ```xml``` characters from output2 + match2 = extract_xml(output2text) + if match2: + data2 = match2 + g.parse(data=data2, format="xml") + + running_length = len(g) + print(f"Parsed Pass {i+1}, Graph Length: {running_length}") + + end_time = time.time() # End the timer + total_time = end_time - start_time # Calculate the total time + + outputpath = f"../Columbia_graph_extract.ttl" + g.serialize(destination=outputpath, format="turtle") + print("Holy shit! This actually worked?!?!?!") + print(f"Total time taken: {total_time:.2f} seconds") + return + +# Graph Building with some error handling and return the graph +def build_graph_robust(dataset): + start_time = time.time() # Start the timer + + #Build the first set of outputs + firstset = [] + firstset = firstpass_build(dataset) + example1 = firstset[0] + example2 = firstset[1] + + #Build the new set of examples using first pass outputs + newexamples = example_follow(example1, example2) + + print(f"Initializing Graph:") + g = rdflib.Graph() + # Parse the outputs from the first pass function + try: + g.parse(data=firstset[0], format="xml") + g.parse(data=firstset[1], format="xml") + print(f"Parsed First Pass, Graph Length: {len(g)}") + except Exception as e: + print(f"Error parsing first pass outputs: {str(e)}") + return + + num_passes = len(dataset) + + i = 1 + while i < num_passes: + output1 = "" + output2 = "" + promptchunk = dataset[i] + prompt1 = schema_follow(promptchunk, newexamples) #Build the schema follow prompt + prompt2 = skos_follow(promptchunk, newexamples) #Build the SKOS follow prompt + + # Get schema style output + output1 = callmixtral(prompt1) + output1text = output1['text'] + + # Extract text between ```xml``` characters from output1 + match1 = extract_xml(output1text) + if match1: + data1 = match1 + try: + g.parse(data=data1, format="xml") + except Exception as e: + print(f"Error parsing schema output in pass {i+1}: {str(e)}\n\nTrying Again...") + continue + + # Get SKOS style output + output2 = callmixtral(prompt2) + output2text = output2['text'] + + # Extract text between ```xml``` characters from output2 + match2 = extract_xml(output2text) + if match2: + data2 = match2 + try: + g.parse(data=data2, format="xml") + except Exception as e: + print(f"Error parsing SKOS output in pass {i+1}: {str(e)}\n\nTrying Again...") + continue + + running_length = len(g) + print(f"Parsed Pass {i+1}, Graph Length: {running_length}") + i += 1 + + end_time = time.time() # End the timer + total_time = end_time - start_time # Calculate the total time + + # Don't write graph file for testing + #outputpath = f"./Columbia_graph_extract.ttl" + #g.serialize(destination=outputpath, format="turtle") + print("Holy shit! This actually worked?!?!?!") + print(f"Total time taken: {total_time:.2f} seconds") + return g + +# Get a list of subjects from graph as URIs +def get_subject_list(graph): + query = """ + SELECT DISTINCT ?subject + WHERE { + ?subject ?predicate ?object . + } + """ + + subjects = graph.query(query) + + subjectlist = [] + for row in subjects: + text = f"{row.subject}" + subjectlist.append(text) + + return subjectlist + +# Function for removing URI artifacts to return clean text +def clean_resource(resource): + # Remove the URL prefixes + cleaned_resource = resource.replace("http://example.org/", "") + cleaned_resource = cleaned_resource.replace("http://www.w3.org/2004/02/skos/core#", "") + cleaned_resource = cleaned_resource.replace("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "") + cleaned_resource = cleaned_resource.replace("http://www.w3.org/2001/XMLSchema#", "") + cleaned_resource = cleaned_resource.replace("http://purl.org/dc/elements/1.1/", "") + + # Replace special symbols with a space + cleaned_resource = re.sub(r'[_#/]', ' ', cleaned_resource) + + return cleaned_resource + +# Clean the entire subject list +def clean_subject_list(subjectlist): + cleaned_subjects = [] + for subject in subjectlist: + clean = f"{clean_resource(subject)}" + cleaned_subjects.append(clean) + + return cleaned_subjects + +# Dump all the triples from the Graph +def get_triples_list(graph): + triples_list = list(graph.triples((None, None, None))) + + semantic_list = [] + for subject, predicate, object in triples_list: + triple = f"{subject} {predicate} {object}" + semantic_list.append(triple) + + return semantic_list + +#Clean the entire triples list +def clean_triples_list(tripleslist): + cleaned_triples = [] + for triple in tripleslist: + cleaned_triple = clean_resource(triple) + cleaned_triples.append(cleaned_triple) + + return cleaned_triples + +# Build UniSim instance for graph subjects +def build_subject_Sim(graph): + subject_sim = TextSim() + subject_sim.reset_index() # Make sure it's empty + subject_sim = TextSim( + store_data=True, # set to False for large datasets to save memory + index_type="exact", # set to "approx" for large datasets to use ANN search + batch_size=128, # increasing batch_size on GPU may be faster + use_accelerator=True, # uses GPU if available, otherwise uses CPU + ) + + subjects = get_subject_list(graph) # Get the subjects + clean_subjects = clean_subject_list(subjects) # Clean the subjects + idx = subject_sim.add(clean_subjects) # Build sim + return subject_sim + +# Build UniSim instance for graph triples +def build_triples_Sim(graph): + triples_sim = TextSim() + triples_sim.reset_index() # Make sure it's empty + triples_sim = TextSim( + store_data=True, # set to False for large datasets to save memory + index_type="exact", # set to "approx" for large datasets to use ANN search + batch_size=128, # increasing batch_size on GPU may be faster + use_accelerator=True, # uses GPU if available, otherwise uses CPU + ) + + triples = get_triples_list(graph) # Get the triples + clean_triples = clean_triples_list(triples) # Clean the triples + idx = triples_sim.add(clean_triples) # Build sim + return triples_sim