From 1ecbad3a65d7688b86c901bcfccd0df011f25dee Mon Sep 17 00:00:00 2001 From: saharNooby Date: Sun, 2 Apr 2023 12:53:41 +0400 Subject: [PATCH] Remove unused files --- .devops/full.Dockerfile | 17 - .devops/main.Dockerfile | 18 - .devops/tools.sh | 40 - .dockerignore | 24 - .github/ISSUE_TEMPLATE/custom.md | 185 --- .github/workflows/build.yml | 454 ------- .github/workflows/docker.yml | 63 - CMakeLists.txt | 109 +- Makefile | 45 +- Package.swift | 20 - README.md | 21 +- SHA256SUMS | 20 - convert-ggml-to-pth.py | 294 ----- convert-gpt4all-to-ggml.py | 107 -- convert-gptq-to-ggml.py | 167 --- convert-pth-to-ggml.py | 179 --- convert-unversioned-ggml-to-ggml.py | 100 -- examples/CMakeLists.txt | 37 - examples/alpaca.sh | 10 - examples/chat-13B.bat | 57 - examples/chat-13B.sh | 53 - examples/chat.sh | 16 - examples/common.cpp | 311 ----- examples/common.h | 95 -- examples/embedding/CMakeLists.txt | 4 - examples/embedding/README.md | 3 - examples/embedding/embedding.cpp | 101 -- examples/main/CMakeLists.txt | 4 - examples/main/README.md | 3 - examples/main/main.cpp | 455 ------- examples/main_rwkv/CMakeLists.txt | 4 - examples/main_rwkv/README.md | 3 - examples/main_rwkv/main_rwkv.cpp | 133 -- examples/perplexity/CMakeLists.txt | 4 - examples/perplexity/README.md | 3 - examples/perplexity/perplexity.cpp | 142 -- examples/quantize/CMakeLists.txt | 4 - examples/quantize/README.md | 3 - examples/quantize/quantize.cpp | 58 - examples/reason-act.sh | 17 - flake.lock | 43 - flake.nix | 49 - llama.cpp | 1864 --------------------------- llama.h | 152 --- models/ggml-vocab.bin | Bin 432610 -> 0 bytes prompts/alpaca.txt | 1 - prompts/chat-with-bob.txt | 7 - prompts/dan.txt | 2 - prompts/reason-act.txt | 18 - quantize.py | 131 -- rwkv.h | 4 +- spm-headers/llama.h | 1 - tests/CMakeLists.txt | 10 - tests/test-double-float.c | 53 - tests/test-quantize.c | 42 - tests/test-tokenizer-0.cpp | 83 -- 56 files changed, 57 insertions(+), 5786 deletions(-) delete mode 100644 .devops/full.Dockerfile delete mode 100644 .devops/main.Dockerfile delete mode 100755 .devops/tools.sh delete mode 100644 .dockerignore delete mode 100644 .github/ISSUE_TEMPLATE/custom.md delete mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/docker.yml delete mode 100644 Package.swift delete mode 100644 SHA256SUMS delete mode 100644 convert-ggml-to-pth.py delete mode 100644 convert-gpt4all-to-ggml.py delete mode 100644 convert-gptq-to-ggml.py delete mode 100644 convert-pth-to-ggml.py delete mode 100644 convert-unversioned-ggml-to-ggml.py delete mode 100644 examples/CMakeLists.txt delete mode 100755 examples/alpaca.sh delete mode 100644 examples/chat-13B.bat delete mode 100755 examples/chat-13B.sh delete mode 100755 examples/chat.sh delete mode 100644 examples/common.cpp delete mode 100644 examples/common.h delete mode 100644 examples/embedding/CMakeLists.txt delete mode 100644 examples/embedding/README.md delete mode 100644 examples/embedding/embedding.cpp delete mode 100644 examples/main/CMakeLists.txt delete mode 100644 examples/main/README.md delete mode 100644 examples/main/main.cpp delete mode 100644 examples/main_rwkv/CMakeLists.txt delete mode 100644 examples/main_rwkv/README.md delete mode 100644 examples/main_rwkv/main_rwkv.cpp delete mode 100644 examples/perplexity/CMakeLists.txt delete mode 100644 examples/perplexity/README.md delete mode 100644 examples/perplexity/perplexity.cpp delete mode 100644 examples/quantize/CMakeLists.txt delete mode 100644 examples/quantize/README.md delete mode 100644 examples/quantize/quantize.cpp delete mode 100755 examples/reason-act.sh delete mode 100644 flake.lock delete mode 100644 flake.nix delete mode 100644 llama.cpp delete mode 100644 llama.h delete mode 100644 models/ggml-vocab.bin delete mode 100644 prompts/alpaca.txt delete mode 100644 prompts/chat-with-bob.txt delete mode 100644 prompts/dan.txt delete mode 100644 prompts/reason-act.txt delete mode 100644 quantize.py delete mode 120000 spm-headers/llama.h delete mode 100644 tests/CMakeLists.txt delete mode 100644 tests/test-double-float.c delete mode 100644 tests/test-quantize.c delete mode 100644 tests/test-tokenizer-0.cpp diff --git a/.devops/full.Dockerfile b/.devops/full.Dockerfile deleted file mode 100644 index 2b3a20c..0000000 --- a/.devops/full.Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -ARG UBUNTU_VERSION=22.04 - -FROM ubuntu:$UBUNTU_VERSION as build - -RUN apt-get update && \ - apt-get install -y build-essential python3 python3-pip - -RUN pip install --upgrade pip setuptools wheel \ - && pip install numpy requests sentencepiece torch tqdm - -WORKDIR /app - -COPY . . - -RUN make - -ENTRYPOINT ["/app/.devops/tools.sh"] diff --git a/.devops/main.Dockerfile b/.devops/main.Dockerfile deleted file mode 100644 index cd575ef..0000000 --- a/.devops/main.Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -ARG UBUNTU_VERSION=22.04 - -FROM ubuntu:$UBUNTU_VERSION as build - -RUN apt-get update && \ - apt-get install -y build-essential - -WORKDIR /app - -COPY . . - -RUN make - -FROM ubuntu:$UBUNTU_VERSION as runtime - -COPY --from=build /app/main /main - -ENTRYPOINT [ "/main" ] \ No newline at end of file diff --git a/.devops/tools.sh b/.devops/tools.sh deleted file mode 100755 index b0196b6..0000000 --- a/.devops/tools.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -set -e - -# Read the first argument into a variable -arg1="$1" - -# Shift the arguments to remove the first one -shift - -# Join the remaining arguments into a single string -arg2="$@" - -if [[ $arg1 == '--convert' || $arg1 == '-c' ]]; then - python3 ./convert-pth-to-ggml.py $arg2 -elif [[ $arg1 == '--quantize' || $arg1 == '-q' ]]; then - ./quantize $arg2 -elif [[ $arg1 == '--run' || $arg1 == '-r' ]]; then - ./main $arg2 -elif [[ $arg1 == '--all-in-one' || $arg1 == '-a' ]]; then - echo "Converting PTH to GGML..." - for i in `ls $1/$2/ggml-model-f16.bin*`; do - if [ -f "${i/f16/q4_0}" ]; then - echo "Skip model quantization, it already exists: ${i/f16/q4_0}" - else - echo "Converting PTH to GGML: $i into ${i/f16/q4_0}..." - ./quantize "$i" "${i/f16/q4_0}" 2 - fi - done -else - echo "Unknown command: $arg1" - echo "Available commands: " - echo " --run (-r): Run a model previously converted into ggml" - echo " ex: -m /models/7B/ggml-model-q4_0.bin -p \"Building a website can be done in 10 simple steps:\" -n 512" - echo " --convert (-c): Convert a llama model into ggml" - echo " ex: \"/models/7B/\" 1" - echo " --quantize (-q): Optimize with quantization process ggml" - echo " ex: \"/models/7B/ggml-model-f16.bin\" \"/models/7B/ggml-model-q4_0.bin\" 2" - echo " --all-in-one (-a): Execute --convert & --quantize" - echo " ex: \"/models/\" 7B" -fi diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 952990f..0000000 --- a/.dockerignore +++ /dev/null @@ -1,24 +0,0 @@ -*.o -*.a -.cache/ -.vs/ -.vscode/ -.DS_Store - -build/ -build-em/ -build-debug/ -build-release/ -build-static/ -build-no-accel/ -build-sanitize-addr/ -build-sanitize-thread/ - -models/* - -/main -/quantize - -arm_neon.h -compile_commands.json -Dockerfile \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md deleted file mode 100644 index 0d50880..0000000 --- a/.github/ISSUE_TEMPLATE/custom.md +++ /dev/null @@ -1,185 +0,0 @@ ---- -name: Issue and enhancement template -about: Used to report issues and request enhancements for llama.cpp -title: "[User] Insert summary of your issue or enhancement.." -labels: '' -assignees: '' - ---- - -# Prerequisites - -Please answer the following questions for yourself before submitting an issue. - -- [ ] I am running the latest code. Development is very rapid so there are no tagged versions as of now. -- [ ] I carefully followed the [README.md](https://github.com/ggerganov/llama.cpp/blob/master/README.md). -- [ ] I [searched using keywords relevant to my issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/filtering-and-searching-issues-and-pull-requests) to make sure that I am creating a new issue that is not already open (or closed). -- [ ] I reviewed the [Discussions](https://github.com/ggerganov/llama.cpp/discussions), and have a new bug or useful enhancement to share. - -# Expected Behavior - -Please provide a detailed written description of what you were trying to do, and what you expected `llama.cpp` to do. - -# Current Behavior - -Please provide a detailed written description of what `llama.cpp` did, instead. - -# Environment and Context - -Please provide detailed information about your computer setup. This is important in case the issue is not reproducible except for under certain specific conditions. - -* Physical (or virtual) hardware you are using, e.g. for Linux: - -`$ lscpu` - -* Operating System, e.g. for Linux: - -`$ uname -a` - -* SDK version, e.g. for Linux: - -``` -$ python3 --version -$ make --version -$ g++ --version -``` - -# Failure Information (for bugs) - -Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template. - -# Steps to Reproduce - -Please provide detailed steps for reproducing the issue. We are not sitting in front of your screen, so the more detail the better. - -1. step 1 -2. step 2 -3. step 3 -4. etc. - -# Failure Logs - -Please include any relevant log snippets or files. If it works under one configuration but not under another, please provide logs for both configurations and their corresponding outputs so it is easy to see where behavior changes. - -Also, please try to **avoid using screenshots** if at all possible. Instead, copy/paste the console output and use [Github's markdown](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) to cleanly format your logs for easy readability. - -Example environment info: -``` -llama.cpp$ git log | head -1 -commit 2af23d30434a677c6416812eea52ccc0af65119c - -llama.cpp$ lscpu | egrep "AMD|Flags" -Vendor ID: AuthenticAMD -Model name: AMD Ryzen Threadripper 1950X 16-Core Processor -Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid amd_dcm aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb hw_pstate ssbd ibpb vmmcall fsgsbase bmi1 avx2 smep bmi2 rdseed adx smap clflushopt sha_ni xsaveopt xsavec xgetbv1 xsaves clzero irperf xsaveerptr arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif overflow_recov succor smca sme sev -Virtualization: AMD-V - -llama.cpp$ python3 --version -Python 3.10.9 - -llama.cpp$ pip list | egrep "torch|numpy|sentencepiece" -numpy 1.24.2 -numpydoc 1.5.0 -sentencepiece 0.1.97 -torch 1.13.1 -torchvision 0.14.1 - -llama.cpp$ make --version | head -1 -GNU Make 4.3 - -$ md5sum ./models/65B/ggml-model-q4_0.bin -dbdd682cce80e2d6e93cefc7449df487 ./models/65B/ggml-model-q4_0.bin -``` - -Example run with the Linux command [perf](https://www.brendangregg.com/perf.html) -``` -llama.cpp$ perf stat ./main -m ./models/65B/ggml-model-q4_0.bin -t 16 -n 1024 -p "Please close your issue when it has been answered." -main: seed = 1679149377 -llama_model_load: loading model from './models/65B/ggml-model-q4_0.bin' - please wait ... -llama_model_load: n_vocab = 32000 -llama_model_load: n_ctx = 512 -llama_model_load: n_embd = 8192 -llama_model_load: n_mult = 256 -llama_model_load: n_head = 64 -llama_model_load: n_layer = 80 -llama_model_load: n_rot = 128 -llama_model_load: f16 = 2 -llama_model_load: n_ff = 22016 -llama_model_load: n_parts = 8 -llama_model_load: ggml ctx size = 41477.73 MB -llama_model_load: memory_size = 2560.00 MB, n_mem = 40960 -llama_model_load: loading model part 1/8 from './models/65B/ggml-model-q4_0.bin' -llama_model_load: .......................................................................................... done -llama_model_load: model size = 4869.09 MB / num tensors = 723 -llama_model_load: loading model part 2/8 from './models/65B/ggml-model-q4_0.bin.1' -llama_model_load: .......................................................................................... done -llama_model_load: model size = 4869.09 MB / num tensors = 723 -llama_model_load: loading model part 3/8 from './models/65B/ggml-model-q4_0.bin.2' -llama_model_load: .......................................................................................... done -llama_model_load: model size = 4869.09 MB / num tensors = 723 -llama_model_load: loading model part 4/8 from './models/65B/ggml-model-q4_0.bin.3' -llama_model_load: .......................................................................................... done -llama_model_load: model size = 4869.09 MB / num tensors = 723 -llama_model_load: loading model part 5/8 from './models/65B/ggml-model-q4_0.bin.4' -llama_model_load: .......................................................................................... done -llama_model_load: model size = 4869.09 MB / num tensors = 723 -llama_model_load: loading model part 6/8 from './models/65B/ggml-model-q4_0.bin.5' -llama_model_load: .......................................................................................... done -llama_model_load: model size = 4869.09 MB / num tensors = 723 -llama_model_load: loading model part 7/8 from './models/65B/ggml-model-q4_0.bin.6' -llama_model_load: .......................................................................................... done -llama_model_load: model size = 4869.09 MB / num tensors = 723 -llama_model_load: loading model part 8/8 from './models/65B/ggml-model-q4_0.bin.7' -llama_model_load: .......................................................................................... done -llama_model_load: model size = 4869.09 MB / num tensors = 723 - -system_info: n_threads = 16 / 32 | AVX = 1 | AVX2 = 1 | AVX512 = 0 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 0 | SSE3 = 1 | VSX = 0 | - -main: prompt: 'Please close your issue when it has been answered.' -main: number of tokens in prompt = 11 - 1 -> '' - 12148 -> 'Please' - 3802 -> ' close' - 596 -> ' your' - 2228 -> ' issue' - 746 -> ' when' - 372 -> ' it' - 756 -> ' has' - 1063 -> ' been' - 7699 -> ' answered' - 29889 -> '.' - -sampling parameters: temp = 0.800000, top_k = 40, top_p = 0.950000, repeat_last_n = 64, repeat_penalty = 1.300000 - - -Please close your issue when it has been answered. -@duncan-donut: I'm trying to figure out what kind of "support" you need for this script and why, exactly? Is there a question about how the code works that hasn't already been addressed in one or more comments below this ticket, or are we talking something else entirely like some sorta bugfixing job because your server setup is different from mine?? -I can understand if your site needs to be running smoothly and you need help with a fix of sorts but there should really be nothing wrong here that the code itself could not handle. And given that I'm getting reports about how it works perfectly well on some other servers, what exactly are we talking? A detailed report will do wonders in helping us get this resolved for ya quickly so please take your time and describe the issue(s) you see as clearly & concisely as possible!! -@duncan-donut: I'm not sure if you have access to cPanel but you could try these instructions. It is worth a shot! Let me know how it goes (or what error message, exactly!) when/if ya give that code a go? [end of text] - - -main: mem per token = 71159620 bytes -main: load time = 19309.95 ms -main: sample time = 168.62 ms -main: predict time = 223895.61 ms / 888.47 ms per token -main: total time = 246406.42 ms - - Performance counter stats for './main -m ./models/65B/ggml-model-q4_0.bin -t 16 -n 1024 -p Please close your issue when it has been answered.': - - 3636882.89 msec task-clock # 14.677 CPUs utilized - 13509 context-switches # 3.714 /sec - 2436 cpu-migrations # 0.670 /sec - 10476679 page-faults # 2.881 K/sec - 13133115082869 cycles # 3.611 GHz (16.77%) - 29314462753 stalled-cycles-frontend # 0.22% frontend cycles idle (16.76%) - 10294402631459 stalled-cycles-backend # 78.39% backend cycles idle (16.74%) - 23479217109614 instructions # 1.79 insn per cycle - # 0.44 stalled cycles per insn (16.76%) - 2353072268027 branches # 647.002 M/sec (16.77%) - 1998682780 branch-misses # 0.08% of all branches (16.76%) - - 247.802177522 seconds time elapsed - - 3618.573072000 seconds user - 18.491698000 seconds sys -``` diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 88e70e4..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,454 +0,0 @@ -name: CI - -on: - workflow_dispatch: # allows manual triggering - inputs: - create_release: - description: 'Create new release' - required: true - type: boolean - push: - paths: ['.github/workflows/**', '**/CMakeLists.txt', '**/Makefile', '**/*.h', '**/*.c', '**/*.cpp'] - pull_request: - types: [opened, synchronize, edited, reopened, review_requested, ready_for_review] - paths: ['**/CMakeLists.txt', '**/Makefile', '**/*.h', '**/*.c', '**/*.cpp'] - -env: - BRANCH_NAME: ${{ github.head_ref || github.ref_name }} - -jobs: - ubuntu-latest-make: - runs-on: ubuntu-latest - - steps: - - name: Clone - id: checkout - uses: actions/checkout@v1 - - - name: Dependencies - id: depends - run: | - sudo apt-get update - sudo apt-get install build-essential - - - name: Build - id: make_build - run: | - make - - ubuntu-latest-cmake: - runs-on: ubuntu-latest - - steps: - - name: Clone - id: checkout - uses: actions/checkout@v1 - - - name: Dependencies - id: depends - run: | - sudo apt-get update - sudo apt-get install build-essential - - - name: Build - id: cmake_build - run: | - mkdir build - cd build - cmake .. - cmake --build . --config Release - - - name: Test - id: cmake_test - run: | - cd build - ctest --verbose - - ubuntu-latest-cmake-sanitizer: - runs-on: ubuntu-latest - - continue-on-error: true - - strategy: - matrix: - sanitizer: [ADDRESS, THREAD, UNDEFINED] - build_type: [Debug, Release] - accelerate: [ON, OFF] - - steps: - - name: Clone - id: checkout - uses: actions/checkout@v1 - - - name: Dependencies - id: depends - run: | - sudo apt-get update - sudo apt-get install build-essential - - - name: Build - id: cmake_build - run: | - mkdir build - cd build - cmake .. -DLLAMA_SANITIZE_${{ matrix.sanitizer }}=ON -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DLLAMA_ACCELERATE=${{ matrix.accelerate }} - cmake --build . --config ${{ matrix.build_type }} - - - name: Test - id: cmake_test - run: | - cd build - ctest --verbose - - macOS-latest-make: - runs-on: macos-latest - - steps: - - name: Clone - id: checkout - uses: actions/checkout@v1 - - - name: Dependencies - id: depends - run: | - brew update - - - name: Build - id: make_build - run: | - make - - macOS-latest-cmake: - runs-on: macOS-latest - - steps: - - name: Clone - id: checkout - uses: actions/checkout@v1 - - - name: Dependencies - id: depends - run: | - brew update - - - name: Build - id: cmake_build - run: | - mkdir build - cd build - cmake -DLLAMA_AVX2=OFF .. - cmake --build . --config Release - - - name: Test - id: cmake_test - run: | - cd build - ctest --verbose - - windows-latest-cmake: - runs-on: windows-latest - - strategy: - matrix: - include: - - build: 'avx2' - defines: '' - - build: 'avx' - defines: '-DLLAMA_AVX2=OFF' - - build: 'avx512' - defines: '-DLLAMA_AVX512=ON' - - steps: - - name: Clone - id: checkout - uses: actions/checkout@v1 - - - name: Build - id: cmake_build - run: | - mkdir build - cd build - cmake .. ${{ matrix.defines }} - cmake --build . --config Release - - - name: Check AVX512F support - id: check_avx512f - if: ${{ matrix.build == 'avx512' }} - continue-on-error: true - run: | - cd build - $vcdir = $(vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath) - $msvc = $(join-path $vcdir $('VC\Tools\MSVC\'+$(gc -raw $(join-path $vcdir 'VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt')).Trim())) - $cl = $(join-path $msvc 'bin\Hostx64\x64\cl.exe') - echo 'int main(void){unsigned int a[4];__cpuid(a,7);return !(a[1]&65536);}' >> avx512f.c - & $cl /O2 /GS- /kernel avx512f.c /link /nodefaultlib /entry:main - .\avx512f.exe && echo "AVX512F: YES" && ( echo HAS_AVX512F=1 >> $env:GITHUB_ENV ) || echo "AVX512F: NO" - - - name: Test - id: cmake_test - if: ${{ matrix.build != 'avx512' || env.HAS_AVX512F == '1' }} # Test AVX-512 only when possible - run: | - cd build - ctest -C Release --verbose - - - name: Get commit hash - id: commit - if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} - uses: pr-mpt/actions-commit-hash@v2 - - - name: Pack artifacts - id: pack_artifacts - if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} - run: | - 7z a llama-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-${{ matrix.build }}-x64.zip .\build\bin\Release\* - - - name: Upload artifacts - if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} - uses: actions/upload-artifact@v3 - with: - path: | - llama-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-${{ matrix.build }}-x64.zip - - release: - if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) || github.event.inputs.create_release == 'true' }} - - runs-on: ubuntu-latest - - needs: - - ubuntu-latest-make - - ubuntu-latest-cmake - - macOS-latest-make - - macOS-latest-cmake - - windows-latest-cmake - - steps: - - name: Download artifacts - id: download-artifact - uses: actions/download-artifact@v3 - - - name: Get commit hash - id: commit - uses: pr-mpt/actions-commit-hash@v2 - - - name: Create release - id: create_release - uses: anzz1/action-create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }} - - - name: Upload release - id: upload_release - uses: actions/github-script@v3 - with: - github-token: ${{secrets.GITHUB_TOKEN}} - script: | - const path = require('path'); - const fs = require('fs'); - const release_id = '${{ steps.create_release.outputs.id }}'; - for (let file of await fs.readdirSync('./artifact')) { - if (path.extname(file) === '.zip') { - console.log('uploadReleaseAsset', file); - await github.repos.uploadReleaseAsset({ - owner: context.repo.owner, - repo: context.repo.repo, - release_id: release_id, - name: file, - data: await fs.readFileSync(`./artifact/${file}`) - }); - } - } - -# ubuntu-latest-gcc: -# runs-on: ubuntu-latest -# -# strategy: -# matrix: -# build: [Debug, Release] -# -# steps: -# - name: Clone -# uses: actions/checkout@v1 -# -# - name: Dependencies -# run: | -# sudo apt-get update -# sudo apt-get install build-essential -# sudo apt-get install cmake -# -# - name: Configure -# run: cmake . -DCMAKE_BUILD_TYPE=${{ matrix.build }} -# -# - name: Build -# run: | -# make -# -# ubuntu-latest-clang: -# runs-on: ubuntu-latest -# -# strategy: -# matrix: -# build: [Debug, Release] -# -# steps: -# - name: Clone -# uses: actions/checkout@v1 -# -# - name: Dependencies -# run: | -# sudo apt-get update -# sudo apt-get install build-essential -# sudo apt-get install cmake -# -# - name: Configure -# run: cmake . -DCMAKE_BUILD_TYPE=${{ matrix.build }} -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -# -# - name: Build -# run: | -# make -# -# ubuntu-latest-gcc-sanitized: -# runs-on: ubuntu-latest -# -# strategy: -# matrix: -# sanitizer: [ADDRESS, THREAD, UNDEFINED] -# -# steps: -# - name: Clone -# uses: actions/checkout@v1 -# -# - name: Dependencies -# run: | -# sudo apt-get update -# sudo apt-get install build-essential -# sudo apt-get install cmake -# -# - name: Configure -# run: cmake . -DCMAKE_BUILD_TYPE=Debug -DLLAMA_SANITIZE_${{ matrix.sanitizer }}=ON -# -# - name: Build -# run: | -# make -# -# windows: -# runs-on: windows-latest -# -# strategy: -# matrix: -# build: [Release] -# arch: [Win32, x64] -# include: -# - arch: Win32 -# s2arc: x86 -# - arch: x64 -# s2arc: x64 -# -# steps: -# - name: Clone -# uses: actions/checkout@v1 -# -# - name: Add msbuild to PATH -# uses: microsoft/setup-msbuild@v1 -# -# - name: Configure -# run: > -# cmake -S . -B ./build -A ${{ matrix.arch }} -# -DCMAKE_BUILD_TYPE=${{ matrix.build }} -# -# - name: Build -# run: | -# cd ./build -# msbuild ALL_BUILD.vcxproj -t:build -p:configuration=${{ matrix.build }} -p:platform=${{ matrix.arch }} -# -# - name: Upload binaries -# uses: actions/upload-artifact@v1 -# with: -# name: llama-bin-${{ matrix.arch }} -# path: build/bin/${{ matrix.build }} -# -# windows-blas: -# runs-on: windows-latest -# -# strategy: -# matrix: -# build: [Release] -# arch: [Win32, x64] -# blas: [ON] -# include: -# - arch: Win32 -# obzip: https://github.com/xianyi/OpenBLAS/releases/download/v0.3.21/OpenBLAS-0.3.21-x86.zip -# s2arc: x86 -# - arch: x64 -# obzip: https://github.com/xianyi/OpenBLAS/releases/download/v0.3.21/OpenBLAS-0.3.21-x64.zip -# s2arc: x64 -# -# steps: -# - name: Clone -# uses: actions/checkout@v1 -# -# - name: Add msbuild to PATH -# uses: microsoft/setup-msbuild@v1 -# -# - name: Fetch OpenBLAS -# if: matrix.blas == 'ON' -# run: | -# C:/msys64/usr/bin/wget.exe -qO blas.zip ${{ matrix.obzip }} -# 7z x blas.zip -oblas -y -# copy blas/include/cblas.h . -# copy blas/include/openblas_config.h . -# echo "blasdir=$env:GITHUB_WORKSPACE/blas" >> $env:GITHUB_ENV -# -# - name: Configure -# run: > -# cmake -S . -B ./build -A ${{ matrix.arch }} -# -DCMAKE_BUILD_TYPE=${{ matrix.build }} -# -DLLAMA_SUPPORT_OPENBLAS=${{ matrix.blas }} -# -DCMAKE_LIBRARY_PATH="$env:blasdir/lib" -# -# - name: Build -# run: | -# cd ./build -# msbuild ALL_BUILD.vcxproj -t:build -p:configuration=${{ matrix.build }} -p:platform=${{ matrix.arch }} -# -# - name: Copy libopenblas.dll -# if: matrix.blas == 'ON' -# run: copy "$env:blasdir/bin/libopenblas.dll" build/bin/${{ matrix.build }} -# -# - name: Upload binaries -# if: matrix.blas == 'ON' -# uses: actions/upload-artifact@v1 -# with: -# name: llama-blas-bin-${{ matrix.arch }} -# path: build/bin/${{ matrix.build }} -# -# emscripten: -# runs-on: ubuntu-latest -# -# strategy: -# matrix: -# build: [Release] -# -# steps: -# - name: Clone -# uses: actions/checkout@v1 -# -# - name: Dependencies -# run: | -# wget -q https://github.com/emscripten-core/emsdk/archive/master.tar.gz -# tar -xvf master.tar.gz -# emsdk-master/emsdk update -# emsdk-master/emsdk install latest -# emsdk-master/emsdk activate latest -# -# - name: Configure -# run: echo "tmp" -# -# - name: Build -# run: | -# pushd emsdk-master -# source ./emsdk_env.sh -# popd -# emcmake cmake . -DCMAKE_BUILD_TYPE=${{ matrix.build }} -# make diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml deleted file mode 100644 index f70821d..0000000 --- a/.github/workflows/docker.yml +++ /dev/null @@ -1,63 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# GitHub recommends pinning actions to a commit SHA. -# To get a newer version, you will need to update the SHA. -# You can also reference a tag or branch, but the action may change without warning. - -name: Publish Docker image - -on: - pull_request: - push: - branches: - - master - -jobs: - push_to_registry: - name: Push Docker image to Docker Hub - runs-on: ubuntu-latest - env: - COMMIT_SHA: ${{ github.sha }} - strategy: - matrix: - config: - - { tag: "light", dockerfile: ".devops/main.Dockerfile" } - - { tag: "full", dockerfile: ".devops/full.Dockerfile" } - steps: - - name: Check out the repo - uses: actions/checkout@v3 - - - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - - name: Log in to Docker Hub - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push Docker image (versioned) - if: github.event_name == 'push' - uses: docker/build-push-action@v4 - with: - context: . - push: true - platforms: linux/amd64,linux/arm64 - tags: "ghcr.io/ggerganov/llama.cpp:${{ matrix.config.tag }}-${{ env.COMMIT_SHA }}" - file: ${{ matrix.config.dockerfile }} - - - name: Build and push Docker image (tagged) - uses: docker/build-push-action@v4 - with: - context: . - push: ${{ github.event_name == 'push' }} - platforms: linux/amd64,linux/arm64 - tags: "ghcr.io/ggerganov/llama.cpp:${{ matrix.config.tag }}" - file: ${{ matrix.config.dockerfile }} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 793c017..a68e3ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.12) # Don't bump this version for no reason -project("llama.cpp" C CXX) +project("rwkv.cpp" C CXX) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -11,18 +11,18 @@ endif() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) - set(LLAMA_STANDALONE ON) + set(RWKV_STANDALONE ON) # configure project version # TODO else() - set(LLAMA_STANDALONE OFF) + set(RWKV_STANDALONE OFF) endif() if (EMSCRIPTEN) set(BUILD_SHARED_LIBS_DEFAULT OFF) - option(LLAMA_WASM_SINGLE_FILE "llama: embed WASM inside the generated llama.js" ON) + option(RWKV_WASM_SINGLE_FILE "rwkv: embed WASM inside the generated rwkv.js" ON) else() if (MINGW) set(BUILD_SHARED_LIBS_DEFAULT OFF) @@ -37,32 +37,29 @@ endif() # # general -option(LLAMA_STATIC "llama: static link libraries" OFF) -option(LLAMA_NATIVE "llama: enable -march=native flag" OFF) -option(LLAMA_LTO "llama: enable link time optimization" OFF) +option(RWKV_STATIC "rwkv: static link libraries" OFF) +option(RWKV_NATIVE "rwkv: enable -march=native flag" OFF) +option(RWKV_LTO "rwkv: enable link time optimization" OFF) # debug -option(LLAMA_ALL_WARNINGS "llama: enable all compiler warnings" ON) -option(LLAMA_ALL_WARNINGS_3RD_PARTY "llama: enable all compiler warnings in 3rd party libs" OFF) -option(LLAMA_GPROF "llama: enable gprof" OFF) +option(RWKV_ALL_WARNINGS "rwkv: enable all compiler warnings" ON) +option(RWKV_ALL_WARNINGS_3RD_PARTY "rwkv: enable all compiler warnings in 3rd party libs" OFF) +option(RWKV_GPROF "rwkv: enable gprof" OFF) # sanitizers -option(LLAMA_SANITIZE_THREAD "llama: enable thread sanitizer" OFF) -option(LLAMA_SANITIZE_ADDRESS "llama: enable address sanitizer" OFF) -option(LLAMA_SANITIZE_UNDEFINED "llama: enable undefined sanitizer" OFF) +option(RWKV_SANITIZE_THREAD "rwkv: enable thread sanitizer" OFF) +option(RWKV_SANITIZE_ADDRESS "rwkv: enable address sanitizer" OFF) +option(RWKV_SANITIZE_UNDEFINED "rwkv: enable undefined sanitizer" OFF) # instruction set specific -option(LLAMA_AVX "llama: enable AVX" ON) -option(LLAMA_AVX2 "llama: enable AVX2" ON) -option(LLAMA_AVX512 "llama: enable AVX512" OFF) -option(LLAMA_FMA "llama: enable FMA" ON) +option(RWKV_AVX "rwkv: enable AVX" ON) +option(RWKV_AVX2 "rwkv: enable AVX2" ON) +option(RWKV_AVX512 "rwkv: enable AVX512" OFF) +option(RWKV_FMA "rwkv: enable FMA" ON) # 3rd party libs -option(LLAMA_ACCELERATE "llama: enable Accelerate framework" ON) -option(LLAMA_OPENBLAS "llama: use OpenBLAS" OFF) - -option(LLAMA_BUILD_TESTS "llama: build tests" ${LLAMA_STANDALONE}) -option(LLAMA_BUILD_EXAMPLES "llama: build examples" ${LLAMA_STANDALONE}) +option(RWKV_ACCELERATE "rwkv: enable Accelerate framework" ON) +option(RWKV_OPENBLAS "rwkv: use OpenBLAS" OFF) # # Compile flags @@ -74,35 +71,35 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) if (NOT MSVC) - if (LLAMA_SANITIZE_THREAD) + if (RWKV_SANITIZE_THREAD) add_compile_options(-fsanitize=thread) link_libraries(-fsanitize=thread) endif() - if (LLAMA_SANITIZE_ADDRESS) + if (RWKV_SANITIZE_ADDRESS) add_compile_options(-fsanitize=address -fno-omit-frame-pointer) link_libraries(-fsanitize=address) endif() - if (LLAMA_SANITIZE_UNDEFINED) + if (RWKV_SANITIZE_UNDEFINED) add_compile_options(-fsanitize=undefined) link_libraries(-fsanitize=undefined) endif() endif() -if (APPLE AND LLAMA_ACCELERATE) +if (APPLE AND RWKV_ACCELERATE) find_library(ACCELERATE_FRAMEWORK Accelerate) if (ACCELERATE_FRAMEWORK) message(STATUS "Accelerate framework found") add_compile_definitions(GGML_USE_ACCELERATE) - set(LLAMA_EXTRA_LIBS ${LLAMA_EXTRA_LIBS} ${ACCELERATE_FRAMEWORK}) + set(RWKV_EXTRA_LIBS ${RWKV_EXTRA_LIBS} ${ACCELERATE_FRAMEWORK}) else() message(WARNING "Accelerate framework not found") endif() endif() -if (LLAMA_OPENBLAS) - if (LLAMA_STATIC) +if (RWKV_OPENBLAS) + if (RWKV_STATIC) set(BLA_STATIC ON) endif() @@ -118,7 +115,7 @@ if (LLAMA_OPENBLAS) endif() endif() -if (LLAMA_ALL_WARNINGS) +if (RWKV_ALL_WARNINGS) if (NOT MSVC) set(c_flags -Wall @@ -149,7 +146,7 @@ if (LLAMA_ALL_WARNINGS) endif() -if (LLAMA_LTO) +if (RWKV_LTO) include(CheckIPOSupported) check_ipo_supported(RESULT result OUTPUT output) if (result) @@ -164,16 +161,16 @@ endif() # feel free to update the Makefile for your architecture and send a pull request or issue message(STATUS "CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") if (NOT MSVC) - if (LLAMA_STATIC) + if (RWKV_STATIC) add_link_options(-static) if (MINGW) add_link_options(-static-libgcc -static-libstdc++) endif() endif() - if (LLAMA_GPROF) + if (RWKV_GPROF) add_compile_options(-pg) endif() - if (LLAMA_NATIVE) + if (RWKV_NATIVE) add_compile_options(-march=native) endif() endif() @@ -191,25 +188,25 @@ if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES elseif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^(x86_64|i686|AMD64)$") message(STATUS "x86 detected") if (MSVC) - if (LLAMA_AVX512) + if (RWKV_AVX512) add_compile_options(/arch:AVX512) - elseif (LLAMA_AVX2) + elseif (RWKV_AVX2) add_compile_options(/arch:AVX2) - elseif (LLAMA_AVX) + elseif (RWKV_AVX) add_compile_options(/arch:AVX) endif() else() add_compile_options(-mf16c) - if (LLAMA_FMA) + if (RWKV_FMA) add_compile_options(-mfma) endif() - if (LLAMA_AVX) + if (RWKV_AVX) add_compile_options(-mavx) endif() - if (LLAMA_AVX2) + if (RWKV_AVX2) add_compile_options(-mavx2) endif() - if (LLAMA_AVX512) + if (RWKV_AVX512) add_compile_options(-mavx512f) # add_compile_options(-mavx512cd) # add_compile_options(-mavx512dq) @@ -231,44 +228,20 @@ add_library(ggml OBJECT target_include_directories(ggml PUBLIC .) target_compile_features(ggml PUBLIC c_std_11) # don't bump -target_link_libraries(ggml PRIVATE Threads::Threads ${LLAMA_EXTRA_LIBS}) +target_link_libraries(ggml PRIVATE Threads::Threads ${RWKV_EXTRA_LIBS}) if (BUILD_SHARED_LIBS) set_target_properties(ggml PROPERTIES POSITION_INDEPENDENT_CODE ON) endif() -add_library(llama - llama.cpp - llama.h) - add_library(rwkv rwkv.cpp rwkv.h) -target_include_directories(llama PUBLIC .) -target_compile_features(llama PUBLIC cxx_std_11) # don't bump -target_link_libraries(llama PRIVATE ggml ${LLAMA_EXTRA_LIBS}) - target_include_directories(rwkv PUBLIC .) target_compile_features(rwkv PUBLIC cxx_std_11) # don't bump -target_link_libraries(rwkv PRIVATE ggml ${LLAMA_EXTRA_LIBS}) +target_link_libraries(rwkv PRIVATE ggml ${RWKV_EXTRA_LIBS}) if (BUILD_SHARED_LIBS) - set_target_properties(llama PROPERTIES POSITION_INDEPENDENT_CODE ON) - target_compile_definitions(llama PRIVATE LLAMA_SHARED LLAMA_BUILD) - set_target_properties(rwkv PROPERTIES POSITION_INDEPENDENT_CODE ON) - target_compile_definitions(rwkv PRIVATE LLAMA_SHARED LLAMA_BUILD) -endif() - -# -# programs, examples and tests -# - -if (LLAMA_BUILD_TESTS AND NOT CMAKE_JS_VERSION) - enable_testing() - add_subdirectory(tests) -endif () - -if (LLAMA_BUILD_EXAMPLES) - add_subdirectory(examples) + target_compile_definitions(rwkv PRIVATE RWKV_SHARED RWKV_BUILD) endif() diff --git a/Makefile b/Makefile index e4e63b0..4f88194 100644 --- a/Makefile +++ b/Makefile @@ -168,7 +168,7 @@ ifneq ($(filter ppc64%,$(UNAME_M)),) CXXFLAGS += -std=c++23 -DGGML_BIG_ENDIAN endif endif -ifndef LLAMA_NO_ACCELERATE +ifndef RWKV_NO_ACCELERATE # Mac M1 - include Accelerate framework. # `-framework Accelerate` works on Mac Intel as well, with negliable performance boost (as of the predict time). ifeq ($(UNAME_S),Darwin) @@ -176,11 +176,11 @@ ifndef LLAMA_NO_ACCELERATE LDFLAGS += -framework Accelerate endif endif -ifdef LLAMA_OPENBLAS +ifdef RWKV_OPENBLAS CFLAGS += -DGGML_USE_OPENBLAS -I/usr/local/include/openblas LDFLAGS += -lopenblas endif -ifdef LLAMA_GPROF +ifdef RWKV_GPROF CFLAGS += -pg CXXFLAGS += -pg endif @@ -205,7 +205,7 @@ endif # Print build information # -$(info I llama.cpp build info: ) +$(info I rwkv.cpp build info: ) $(info I UNAME_S: $(UNAME_S)) $(info I UNAME_P: $(UNAME_P)) $(info I UNAME_M: $(UNAME_M)) @@ -216,7 +216,7 @@ $(info I CC: $(CCV)) $(info I CXX: $(CXXV)) $(info ) -default: main quantize perplexity embedding +default: rwkv.o # # Build library @@ -225,40 +225,5 @@ default: main quantize perplexity embedding ggml.o: ggml.c ggml.h $(CC) $(CFLAGS) -c ggml.c -o ggml.o -llama.o: llama.cpp llama.h - $(CXX) $(CXXFLAGS) -c llama.cpp -o llama.o - rwkv.o: rwkv.cpp rwkv.h $(CXX) $(CXXFLAGS) -c rwkv.cpp -o rwkv.o - -common.o: examples/common.cpp examples/common.h - $(CXX) $(CXXFLAGS) -c examples/common.cpp -o common.o - -clean: - rm -vf *.o main quantize perplexity embedding - -main: examples/main/main.cpp ggml.o llama.o common.o - $(CXX) $(CXXFLAGS) examples/main/main.cpp ggml.o llama.o common.o -o main $(LDFLAGS) - @echo - @echo '==== Run ./main -h for help. ====' - @echo - -main_rwkv: examples/main_rwkv/main_rwkv.cpp ggml.o rwkv.o common.o - $(CXX) $(CXXFLAGS) examples/main_rwkv/main_rwkv.cpp ggml.o rwkv.o common.o -o main_rwkv $(LDFLAGS) - -quantize: examples/quantize/quantize.cpp ggml.o llama.o - $(CXX) $(CXXFLAGS) examples/quantize/quantize.cpp ggml.o llama.o -o quantize $(LDFLAGS) - -perplexity: examples/perplexity/perplexity.cpp ggml.o llama.o common.o - $(CXX) $(CXXFLAGS) examples/perplexity/perplexity.cpp ggml.o llama.o common.o -o perplexity $(LDFLAGS) - -embedding: examples/embedding/embedding.cpp ggml.o llama.o common.o - $(CXX) $(CXXFLAGS) examples/embedding/embedding.cpp ggml.o llama.o common.o -o embedding $(LDFLAGS) - -# -# Tests -# - -.PHONY: tests -tests: - bash ./tests/run-tests.sh diff --git a/Package.swift b/Package.swift deleted file mode 100644 index 79d13c8..0000000 --- a/Package.swift +++ /dev/null @@ -1,20 +0,0 @@ -// swift-tools-version:5.3 - -import PackageDescription - -let package = Package( - name: "llama", - products: [ - .library(name: "llama", targets: ["llama"]), - ], - targets: [ - .target( - name: "llama", - path: ".", - sources: ["ggml.c", "llama.cpp"], - publicHeadersPath: "spm-headers", - cSettings: [.unsafeFlags(["-Wno-shorten-64-to-32"])] - ), - ], - cxxLanguageStandard: .cxx11 -) diff --git a/README.md b/README.md index d3c9fd0..89cd6e0 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,22 @@ # rwkv.cpp -This is a port of [BlinkDL/RWKV-LM](https://github.com/BlinkDL/RWKV-LM) to [ggerganov/ggml](https://github.com/ggerganov/ggml). The end goal is to allow 4-bit quanized inference on CPU. +This is a port of [BlinkDL/RWKV-LM](https://github.com/BlinkDL/RWKV-LM) to [ggerganov/ggml](https://github.com/ggerganov/ggml). -**WORK IN PROGRESS!** **Status**: FP32, FP16 and INT4 inference work. INT4 gives not so good quality, need to properly measure and compare perplexity. +Besides usual **FP32**, it supports **FP16** and **quantized INT4** inference on CPU. This project is **CPU only**. + +**WORK IN PROGRESS!** **Status**: INT4 gives not so good quality, need to properly measure and compare perplexity. ## Plan 1. Create Python script with sampling and simple chat interface 2. Measure performance and quality of different model sizes and data types -3. Clean up the repo (remove llama related files and mentions) -4. Write a good `README.md` and publish links to this repo -5. Create pull request to main `ggml` repo with all improvements made here +3. Write a good `README.md` and publish links to this repo +4. Create pull request to main `ggml` repo with all improvements made here ## Structure -This repo is based on the [llama.cpp repo](https://github.com/ggerganov/llama.cpp). RWKV-related code is in these directories: - -- `./rwkv`: directory containing Python scripts for conversion, inference and validation -- `./examples/main_rwkw`: directory containing script that loads and infers RWKV model - -Please do not change files in other directories — this will make pulling recent changes easier. +- `./rwkv.h`, `./rwkv.cpp`: source code of the shared library. +- `./rwkv`: directory containing Python scripts for conversion, inference and validation. ## How to use @@ -32,7 +29,7 @@ Requirements: [git](https://gitforwindows.org/), [CMake](https://cmake.org/downl ```commandline git clone https://github.com/saharNooby/rwkv.cpp.git cd rwkv.cpp -cmake -DBUILD_SHARED_LIBS=ON -DLLAMA_BUILD_TESTS=OFF -DLLAMA_BUILD_EXAMPLES=OFF . +cmake -DBUILD_SHARED_LIBS=ON . cmake --build . --config Release ``` diff --git a/SHA256SUMS b/SHA256SUMS deleted file mode 100644 index 63fac21..0000000 --- a/SHA256SUMS +++ /dev/null @@ -1,20 +0,0 @@ -700df0d3013b703a806d2ae7f1bfb8e59814e3d06ae78be0c66368a50059f33d models/7B/consolidated.00.pth -7e89e242ddc0dd6f060b43ca219ce8b3e8f08959a72cb3c0855df8bb04d46265 models/7B/params.json -745bf4e29a4dd6f411e72976d92b452da1b49168a4f41c951cfcc8051823cf08 models/13B/consolidated.00.pth -d5ccbcc465c71c0de439a5aeffebe8344c68a519bce70bc7f9f92654ee567085 models/13B/consolidated.01.pth -4ab77bec4d4405ccb66a97b282574c89a94417e3c32e5f68f37e2876fc21322f models/13B/params.json -e23294a58552d8cdec5b7e8abb87993b97ea6eced4178ff2697c02472539d067 models/30B/consolidated.00.pth -4e077b7136c7ae2302e954860cf64930458d3076fcde9443f4d0e939e95903ff models/30B/consolidated.01.pth -24a87f01028cbd3a12de551dcedb712346c0b5cbdeff1454e0ddf2df9b675378 models/30B/consolidated.02.pth -1adfcef71420886119544949767f6a56cb6339b4d5fcde755d80fe68b49de93b models/30B/consolidated.03.pth -2c07118ea98d69dbe7810d88520e30288fa994751b337f8fca02b171955f44cb models/30B/params.json -135c563f6b3938114458183afb01adc9a63bef3d8ff7cccc3977e5d3664ecafe models/65B/consolidated.00.pth -9a600b37b19d38c7e43809485f70d17d1dc12206c07efa83bc72bb498a568bde models/65B/consolidated.01.pth -e7babf7c5606f165a3756f527cb0fedc4f83e67ef1290391e52fb1cce5f26770 models/65B/consolidated.02.pth -73176ffb426b40482f2aa67ae1217ef79fbbd1fff5482bae5060cdc5a24ab70e models/65B/consolidated.03.pth -882e6431d0b08a8bc66261a0d3607da21cbaeafa96a24e7e59777632dbdac225 models/65B/consolidated.04.pth -a287c0dfe49081626567c7fe87f74cce5831f58e459b427b5e05567641f47b78 models/65B/consolidated.05.pth -72b4eba67a1a3b18cb67a85b70f8f1640caae9b40033ea943fb166bd80a7b36b models/65B/consolidated.06.pth -d27f5b0677d7ff129ceacd73fd461c4d06910ad7787cf217b249948c3f3bc638 models/65B/consolidated.07.pth -999ed1659b469ccc2a941714c0a9656fa571d17c9f7c8c7589817ca90edef51b models/65B/params.json -9e556afd44213b6bd1be2b850ebbbd98f5481437a8021afaf58ee7fb1818d347 models/tokenizer.model diff --git a/convert-ggml-to-pth.py b/convert-ggml-to-pth.py deleted file mode 100644 index 20158c9..0000000 --- a/convert-ggml-to-pth.py +++ /dev/null @@ -1,294 +0,0 @@ -# Author: github.com/ductai199x -import argparse -import os -import struct - -import numpy as np -import torch -from numba import njit -from tqdm.auto import tqdm - - -def read_header(fin): - values = struct.unpack("i" * 9, fin.read(4 * 9)) - _, _, vocab_size, dim, multiple_of, n_heads, n_layers, rot, ftype = values - return { - "vocab_size": vocab_size, - "dim": dim, - "multiple_of": multiple_of, - "n_heads": n_heads, - "n_layers": n_layers, - }, ftype - - -def read_tokens(fin, vocab_size): - tokens = [] - for _ in range(vocab_size): - text_len = struct.unpack("i", fin.read(4))[0] - text_bytes = fin.read(text_len) - try: - text = text_bytes.decode("utf-8") - except UnicodeDecodeError: - text = text_bytes.decode("utf-8", "replace") - score = struct.unpack("f", fin.read(4))[0] - tokens.append((text, score)) - return tokens - - -@njit -def dequantize_weights_numba(fin_data, n_rows, n_cols): - qk = 32 - nb = n_cols // qk - bs = 4 + (qk // 2) - - weights = np.zeros((n_rows, n_cols), dtype=np.float32) - data_pos = 0 - - for row in range(n_rows): - for block in range(nb): - d = np.frombuffer(fin_data[data_pos : data_pos + 4], dtype=np.float32)[0] - data_pos += 4 - packed_values = fin_data[data_pos : data_pos + (qk // 2)] - data_pos += qk // 2 - - for i in range(qk // 2): - packed_value = packed_values[i] - v0 = np.float32((packed_value & 0b00001111) - 8) * d - v1 = np.float32((packed_value >> 4) - 8) * d - - weights[row, block * qk + 2 * i] = v0 - weights[row, block * qk + 2 * i + 1] = v1 - - return weights - - -def dequantize_weights(fin, n_rows, n_cols): - qk = 32 - nb = n_cols // qk - data_size = n_rows * n_cols // 2 + n_rows * nb * 4 - fin_data = fin.read(data_size) - return dequantize_weights_numba(fin_data, n_rows, n_cols) - - -def read_variables(fin): - model = {} - pbar = tqdm(total=os.path.getsize(fin.name), unit="B", unit_scale=True, desc="Reading variables") - while True: - start_pos = fin.tell() - try: - n_dims, name_length, ftype_cur = struct.unpack("iii", fin.read(4 * 3)) - except struct.error: - break - - shape = tuple(struct.unpack("i" * n_dims, fin.read(4 * n_dims))) - shape = shape[::-1] - name = fin.read(name_length).decode("utf-8") - - if ftype_cur == 2: - # 4-bit quantized weights - dtype = np.uint8 - data = dequantize_weights(fin, shape[0], shape[1]) - data = data.reshape(shape) - elif ftype_cur == 0: - dtype = np.float32 - data_size = np.prod(shape) - data = np.fromfile(fin, dtype=dtype, count=data_size).reshape(shape) - elif ftype_cur == 1: - dtype = np.float16 - data_size = np.prod(shape) - data = np.fromfile(fin, dtype=dtype, count=data_size).reshape(shape) - - model[name] = torch.tensor(data, dtype=torch.float32 if dtype == np.float32 else torch.float16) - - pbar.update(fin.tell() - start_pos) - - return model - - -def convert_to_hf_format(model, hparams): - # This works for llama 7B, need to test with other models - n_layers = hparams["n_layers"] - n_heads = hparams["n_heads"] - dim = hparams["dim"] - dims_per_head = dim // n_heads - base = 10000.0 - inv_freq = 1.0 / (base ** (torch.arange(0, dims_per_head, 2).float() / dims_per_head)) - - # permute for sliced rotary - def permute(w): - return w.view(n_heads, dim // n_heads // 2, 2, dim).transpose(1, 2).reshape(dim, dim) - - state_dict = {} - for layer_i in range(n_layers): - state_dict.update( - { - f"model.layers.{layer_i}.self_attn.q_proj.weight": permute( - model[f"layers.{layer_i}.attention.wq.weight"] - ), - f"model.layers.{layer_i}.self_attn.k_proj.weight": permute( - model[f"layers.{layer_i}.attention.wk.weight"] - ), - f"model.layers.{layer_i}.self_attn.v_proj.weight": model[ - f"layers.{layer_i}.attention.wv.weight" - ], - f"model.layers.{layer_i}.self_attn.o_proj.weight": model[ - f"layers.{layer_i}.attention.wo.weight" - ], - f"model.layers.{layer_i}.mlp.gate_proj.weight": model[ - f"layers.{layer_i}.feed_forward.w1.weight" - ], - f"model.layers.{layer_i}.mlp.down_proj.weight": model[ - f"layers.{layer_i}.feed_forward.w2.weight" - ], - f"model.layers.{layer_i}.mlp.up_proj.weight": model[ - f"layers.{layer_i}.feed_forward.w3.weight" - ], - f"model.layers.{layer_i}.input_layernorm.weight": model[ - f"layers.{layer_i}.attention_norm.weight" - ], - f"model.layers.{layer_i}.post_attention_layernorm.weight": model[ - f"layers.{layer_i}.ffn_norm.weight" - ], - } - ) - state_dict[f"model.layers.{layer_i}.self_attn.rotary_emb.inv_freq"] = inv_freq - state_dict.update( - { - "model.embed_tokens.weight": model["tok_embeddings.weight"], - "model.norm.weight": model["norm.weight"], - "lm_head.weight": model["output.weight"], - } - ) - - return state_dict - - -def chat(model, hparams, llama_dir): - from transformers import (GenerationConfig, LlamaForCausalLM, - LlamaTokenizer, StoppingCriteria, - StoppingCriteriaList) - from transformers.models.llama.configuration_llama import LlamaConfig - - class StoppingCriteriaSub(StoppingCriteria): - def __init__(self): - super().__init__() - - def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor, stops=[]): - print(tokenizer.decode(input_ids[0]), end="", flush=True) - if input_ids[0][-1] == 13: - return True - - return False - - config = LlamaConfig( - vocab_size=hparams["vocab_size"], - dim=hparams["dim"], - num_hidden_layers=hparams["n_layers"], - num_attention_heads=hparams["n_heads"], - ) - - llama = LlamaForCausalLM(config=config) - llama.load_state_dict(state_dict=model, strict=True) - tokenizer = LlamaTokenizer.from_pretrained(llama_dir) - - device = torch.device("cpu") - llama = llama.to(device) - - ctx = """You are AI. -This is a dialog, where User interacts with AI. AI is helpful, kind, obedient, honest, respectful, direct, concise, should try to protect User's privacy, and knows its own limits. Also, AI must answer User and AI cannot stop the conversation by itself. -User: Hello, AI. -AI: Hello! How can I assist you today? -""" - print(ctx.rstrip("\n")) - while True: - print("-" * 60) - prompt = input(f"User: ") - if ctx != "": - ctx = ctx + "User: " + prompt + "\n" - else: - ctx = prompt + "\nAI:" - - ctx = (ctx[-1920:]) if len(ctx) >= 2048 else ctx - - print("-" * 60) - if len(ctx.strip()) > 0: - input_ids = tokenizer(ctx, return_tensors="pt")["input_ids"].to(device) - generation_config = GenerationConfig( - temperature=0.8, - top_p=0.95, - top_k=50, - repetition_penalty=1.1764, - ) - with torch.no_grad(): - generation_output = llama.generate( - input_ids=input_ids, - generation_config=generation_config, - return_dict_in_generate=True, - output_scores=True, - max_length=2048, - do_sample=True, - stopping_criteria=StoppingCriteriaList([StoppingCriteriaSub()]), - ) - s = generation_output.sequences[0] - decoded = tokenizer.decode(s) - ctx = decoded + "\n" - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument( - "--input_dir", "-i", type=str, required=True, help="The input directory containing the ggml files." - ) - parser.add_argument( - "--prefix", - "-p", - type=str, - required=True, - help="The prefix of the ggml files (ggml-model-f16 or ggml-model-q4_0).", - ) - parser.add_argument( - "--hf", - action="store_true", - help="Whether to save the model in the huggingface format. (default: False)", - ) - parser.add_argument( - "--chat", "-c", action="store_true", help="Whether to open a chat with the model. (default: False)" - ) - args = parser.parse_args() - - llama_dir = os.path.abspath(f"{args.input_dir}/../") - - ggml_files = sorted( - [f"{args.input_dir}/{f}" for f in os.listdir(args.input_dir) if f.startswith(args.prefix)] - ) - - fin = open(ggml_files[0], "rb") - hparams, ftype = read_header(fin) - tokens = read_tokens(fin, hparams["vocab_size"]) - model = read_variables(fin) - - for f in tqdm(ggml_files[1:]): - fin = open(f, "rb") - read_header(fin) - read_tokens(fin, hparams["vocab_size"]) - model.update(read_variables(fin)) - - if args.hf: - model = convert_to_hf_format(model, hparams) - - pth_ckpt = { - "state_dict": model, - "hparams": hparams, - "tokens": tokens, - } - - torch.save(pth_ckpt, f"{args.input_dir}/{args.prefix}-to-torch.pth") - - if args.chat: - if not args.hf: - model = convert_to_hf_format(model, hparams) - chat(model, hparams, llama_dir) - - -if __name__ == "__main__": - main() diff --git a/convert-gpt4all-to-ggml.py b/convert-gpt4all-to-ggml.py deleted file mode 100644 index f1d9d7a..0000000 --- a/convert-gpt4all-to-ggml.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python3 - -# -# TODO: deduplicate GPT4All with convert-unversioned-ggml-to-ggml.py -# - -# Original by https://github.com/eiz -# https://github.com/ggerganov/llama.cpp/issues/324#issuecomment-1476227818 -import argparse -import glob -import os -import struct -import sys -from sentencepiece import SentencePieceProcessor - -HPARAMS = keys = ["vocab_size", "dim", "multiple_of", "n_heads", "n_layers"] - -def parse_args(): - parser = argparse.ArgumentParser(description='Upgrade a GPT4All model to the current format') - parser.add_argument('gpt4all_model', help='path to gpt4all-lora-quantized.bin') - parser.add_argument('tokenizer_model', help='path to LLaMA tokenizer.model file') - return parser.parse_args() - -def read_header(f_in): - struct_fmt = "i" * (3 + len(HPARAMS)) - struct_size = struct.calcsize(struct_fmt) - buf = f_in.read(struct_size) - return struct.unpack(struct_fmt, buf) - -def write_header(f_out, header): - (magic, vocab_size, dim, multiple_of, n_heads, n_layers, rot, ftype) = header - - if magic != 0x67676d6c: - raise Exception('Invalid file magic. Must be an old style ggml file.') - - values = [ - 0x67676d66, # magic: ggml in hex - 1, # file version - vocab_size, - dim, - multiple_of, - n_heads, - n_layers, - rot, - ftype - ] - f_out.write(struct.pack("i" * len(values), *values)) - -def write_tokens(fout, tokenizer): - for i in range(tokenizer.vocab_size()): - if tokenizer.is_unknown(i): - text = " \u2047 ".encode("utf-8") - elif tokenizer.is_control(i): - text = b"" - elif tokenizer.is_byte(i): - piece = tokenizer.id_to_piece(i) - if len(piece) != 6: - print(f"Invalid token: {piece}") - sys.exit(1) - byte_value = int(piece[3:-1], 16) - text = struct.pack("B", byte_value) - else: - text = tokenizer.id_to_piece(i).replace("\u2581", " ").encode("utf-8") - fout.write(struct.pack("i", len(text))) - fout.write(text) - fout.write(struct.pack("f", tokenizer.get_score(i))) - - # TODO: GPT4All - add extra token - text = "".encode("utf-8") - fout.write(struct.pack("i", len(text))) - fout.write(text) - fout.write(struct.pack("f", 0.0)) - -def read_tokens(f_in, tokenizer): - for i in range(tokenizer.vocab_size()): - len_b = f_in.read(4) - (length,) = struct.unpack("i", len_b) - f_in.read(length) - -def copy_all_data(f_out, f_in): - while True: - buf = f_in.read(1024 * 1024) - if not buf: - break - f_out.write(buf) - -def convert_one_file(path_in, tokenizer): - path_tmp = f"{path_in}.tmp" - path_orig= f"{path_in}.orig" - print(f"converting {path_in}") - with open(path_in, "rb") as f_in, open(path_tmp, "wb") as f_out: - write_header(f_out, read_header(f_in)) - read_tokens(f_in, tokenizer) - write_tokens(f_out, tokenizer) - copy_all_data(f_out, f_in) - os.rename(path_in, path_orig) - os.rename(path_tmp, path_in) - -def main(): - args = parse_args() - - tokenizer = SentencePieceProcessor(args.tokenizer_model) - - convert_one_file(args.gpt4all_model, tokenizer) - -if __name__ == "__main__": - main() diff --git a/convert-gptq-to-ggml.py b/convert-gptq-to-ggml.py deleted file mode 100644 index 6c77808..0000000 --- a/convert-gptq-to-ggml.py +++ /dev/null @@ -1,167 +0,0 @@ -# Convert a GPTQ quantized LLaMA model to a ggml compatible file -# Based on: https://github.com/qwopqwop200/GPTQ-for-LLaMa -# -import os -import re -import sys -import json -import struct -import numpy as np -import torch -from sentencepiece import SentencePieceProcessor - -if len(sys.argv) != 4: - print("Usage: convert-gptq-to-ggml.py llamaXXb-4bit.pt tokenizer.model out.bin\n") - sys.exit(1) - -fname_model = sys.argv[1] -fname_tokenizer = sys.argv[2] -dir_out = sys.argv[3] - -model = torch.load(fname_model, map_location="cpu") - -n_vocab, n_embd = model['model.embed_tokens.weight'].shape -n_layer = 1 + max(int(m.group(1)) for name in model - if (m := re.match(r'model\.layers\.([0-9]+)', name))) - -# hardcoded: -n_mult = 256 -n_head = {32: 32, 40: 40, 60: 52, 80: 64}[n_layer] - -tokenizer = SentencePieceProcessor(fname_tokenizer) - -assert tokenizer.vocab_size() == n_vocab - -fname_out = sys.argv[3] - -fout = open(fname_out, "wb") - -fout.write(struct.pack("i", 0x67676d66)) # magic: ggmf in hex -fout.write(struct.pack("i", 1)) # file version -fout.write(struct.pack("i", n_vocab)) -fout.write(struct.pack("i", n_embd)) -fout.write(struct.pack("i", n_mult)) -fout.write(struct.pack("i", n_head)) -fout.write(struct.pack("i", n_layer)) -fout.write(struct.pack("i", n_embd // n_head)) # rot (obsolete) -fout.write(struct.pack("i", 4)) - - -# This loop unchanged from convert-pth-to-ggml.py: -for i in range(tokenizer.vocab_size()): - if tokenizer.is_unknown(i): - text = " \u2047 ".encode("utf-8") - elif tokenizer.is_control(i): - text = b"" - elif tokenizer.is_byte(i): - piece = tokenizer.id_to_piece(i) - if len(piece) != 6: - print(f"Invalid token: {piece}") - sys.exit(1) - byte_value = int(piece[3:-1], 16) - text = struct.pack("B", byte_value) - else: - text = tokenizer.id_to_piece(i).replace("\u2581", " ").encode("utf-8") - fout.write(struct.pack("i", len(text))) - fout.write(text) - fout.write(struct.pack("f", tokenizer.get_score(i))) - -def write_header(shape, dst_name, ftype_cur): - sname = dst_name.encode('utf-8') - fout.write(struct.pack("iii", len(shape), len(sname), ftype_cur)) - fout.write(struct.pack("i" * len(shape), *shape[::-1])) - fout.write(sname) - -def convert_non_q4(src_name, dst_name): - v = model[src_name] - shape = v.shape - print("Processing non-Q4 variable: " + src_name + " with shape: ", shape, " and type: ", v.dtype) - if len(shape) == 1: - print(" Converting to float32") - v = v.to(torch.float32) - - ftype_cur = {torch.float16: 1, torch.float32: 0}[v.dtype] - - # header - write_header(shape, dst_name, ftype_cur) - - # data - v.numpy().tofile(fout) - -def convert_q4(src_name, dst_name, permute=False): - zeros = model[f"{src_name}.zeros"].numpy() - scales = model[f"{src_name}.scales"].numpy() - bias = model[f"{src_name}.bias"].numpy() - qweight = model[f"{src_name}.qweight"].numpy().T # transpose - - # Q4_1 does not support bias; good thing the bias is always all zeros. - assert not np.any(bias) - - # Each int32 item is actually 8 int4 items packed together, and it's transposed. - shape = (qweight.shape[0], qweight.shape[1] * 8) - - print("Processing Q4 variable: " + src_name + " with shape: ", shape) - - # The output format has the int4 weights in groups of 32 rather than 8. - # It looks like this: - # For each row: - # For each group of 32 columns: - # - addend (float32, 4 bytes) - # - scale (float32, 4 bytes) - # - weights (int4 * 32, 16 bytes) - # Note that in the input, the scales and addends are shared between all - # the columns in a row, so we end up wasting quite a bit of memory with - # repeated scales and addends. - - addends = -zeros # flip sign - - # Since the output format is mixed between integers and floats, we have - # to hackily view the floats as int32s just so numpy will let us - # concatenate them. - addends_view = addends.view(dtype=np.int32) - scales_view = scales.view(dtype=np.int32) - - # Split into groups of 4 columns (i.e. 32 columns of quantized data): - grouped = qweight.reshape([qweight.shape[0], qweight.shape[1] // 4, 4]) - - # Repeat addends and scales: - addends_rep = np.atleast_3d(addends_view).repeat(grouped.shape[1], axis=1) - scales_rep = np.atleast_3d(scales_view).repeat(grouped.shape[1], axis=1) - - blob = np.concatenate([scales_rep, addends_rep, grouped], axis=2, casting='no') - - if permute: - # Permute some rows to undo the permutation done by convert_llama_weights_to_hf.py. - # This can be done after the above conversion because it doesn't affect column order/layout. - blob = (blob.reshape(n_head, 2, shape[0] // n_head // 2, *blob.shape[1:]) - .swapaxes(1, 2) - .reshape(blob.shape)) - - # header - write_header(shape, dst_name, 3) # ftype = Q4_1 - - # data - blob.tofile(fout) - -convert_non_q4("model.embed_tokens.weight", "tok_embeddings.weight") -convert_non_q4("model.norm.weight", "norm.weight") -convert_non_q4("lm_head.weight", "output.weight") - -for i in range(n_layer): - convert_q4(f"model.layers.{i}.self_attn.q_proj", f"layers.{i}.attention.wq.weight", permute=True) - convert_q4(f"model.layers.{i}.self_attn.k_proj", f"layers.{i}.attention.wk.weight", permute=True) - convert_q4(f"model.layers.{i}.self_attn.v_proj", f"layers.{i}.attention.wv.weight") - convert_q4(f"model.layers.{i}.self_attn.o_proj", f"layers.{i}.attention.wo.weight") - - convert_q4(f"model.layers.{i}.mlp.gate_proj", f"layers.{i}.feed_forward.w1.weight") - convert_q4(f"model.layers.{i}.mlp.down_proj", f"layers.{i}.feed_forward.w2.weight") - convert_q4(f"model.layers.{i}.mlp.up_proj", f"layers.{i}.feed_forward.w3.weight") - - convert_non_q4(f"model.layers.{i}.input_layernorm.weight", f"layers.{i}.attention_norm.weight") - convert_non_q4(f"model.layers.{i}.post_attention_layernorm.weight", f"layers.{i}.ffn_norm.weight") - - -fout.close() - -print("Done. Output file: " + fname_out) -print("") diff --git a/convert-pth-to-ggml.py b/convert-pth-to-ggml.py deleted file mode 100644 index d83f8a1..0000000 --- a/convert-pth-to-ggml.py +++ /dev/null @@ -1,179 +0,0 @@ -# Convert a LLaMA model checkpoint to a ggml compatible file -# -# Load the model using Torch -# Iterate over all variables and write them to a binary file. -# -# For each variable, write the following: -# - Number of dimensions (int) -# - Name length (int) -# - Dimensions (int[n_dims]) -# - Name (char[name_length]) -# - Data (float[n_dims]) -# -# At the start of the ggml file we write the model parameters -# and vocabulary. -# - -import argparse -import os -import sys -import json -import struct -import numpy as np -import torch - -from sentencepiece import SentencePieceProcessor - -def parse_args(): - - parser = argparse.ArgumentParser(description='Convert a LLaMA model checkpoint to a ggml compatible file') - parser.add_argument('dir_model', help='directory containing the model checkpoint') - parser.add_argument('ftype', help='file type (0: float32, 1: float16)', type=int, choices=[0, 1], default=1) - parser.add_argument('vocab_only', help='only write vocab to file', type=int, default=0, nargs='?') - return parser.parse_args() - -def get_n_parts(dim): - - mappings = {4096: 1, 5120: 2, 6656: 4, 8192: 8} - n_parts = mappings.get(dim) - if n_parts is None: - print(f"Invalid dim: {dim}") - sys.exit(1) - - print(f"n_parts = {n_parts}\n") - return n_parts - -def load_hparams_and_tokenizer(dir_model): - - # `dir_model` is something like `models/7B` or `models/7B/`. - # "tokenizer.model" is expected under model's parent dir. - # When `dir_model` is a symlink, f"{dir_model}/../tokenizer.model" would not be found. - # Let's use the model's parent dir directly. - model_parent_dir = os.path.dirname(os.path.normpath(dir_model)) - - fname_hparams = f"{dir_model}/params.json" - fname_tokenizer = f"{model_parent_dir}/tokenizer.model" - - with open(fname_hparams, "r") as f: - hparams = json.load(f) - print(hparams) - - tokenizer = SentencePieceProcessor(fname_tokenizer) - hparams.update({"vocab_size": tokenizer.vocab_size()}) - - return hparams, tokenizer - -def write_header(fout, hparams, ftype): - - keys = ["vocab_size", "dim", "multiple_of", "n_heads", "n_layers"] - values = [ - 0x67676d66, # magic: ggmf in hex - 1, # file version - *[hparams[key] for key in keys], - hparams["dim"] // hparams["n_heads"], # rot (obsolete) - ftype - ] - fout.write(struct.pack("i" * len(values), *values)) - -def write_tokens(fout, tokenizer): - - for i in range(tokenizer.vocab_size()): - if tokenizer.is_unknown(i): - text = " \u2047 ".encode("utf-8") - elif tokenizer.is_control(i): - text = b"" - elif tokenizer.is_byte(i): - piece = tokenizer.id_to_piece(i) - if len(piece) != 6: - print(f"Invalid token: {piece}") - sys.exit(1) - byte_value = int(piece[3:-1], 16) - text = struct.pack("B", byte_value) - else: - text = tokenizer.id_to_piece(i).replace("\u2581", " ").encode("utf-8") - fout.write(struct.pack("i", len(text))) - fout.write(text) - fout.write(struct.pack("f", tokenizer.get_score(i))) - -def process_and_write_variables(fout, model, ftype): - - for name, datao in model.items(): - - if name.endswith("freqs"): - continue - - shape = datao.shape - - print(f"Processing variable: {name} with shape: {shape} and type: {datao.dtype}") - - data = datao.numpy().squeeze() - n_dims = len(shape) - - # default type is fp16 - ftype_cur = 1 - if ftype == 0 or n_dims == 1: - print(" Converting to float32") - data = data.astype(np.float32) - ftype_cur = 0 - - # header - sname = name.encode('utf-8') - fout.write(struct.pack("iii", len(data.shape), len(sname), ftype_cur)) - for dim in reversed(data.shape): - fout.write(struct.pack("i", dim)) - fout.write(sname) - - # data output to file - data.tofile(fout) - -def main(): - - args = parse_args() - dir_model = args.dir_model - ftype = args.ftype - ftype_str = ["f32", "f16"] - - hparams, tokenizer = load_hparams_and_tokenizer(dir_model) - - print(args) - - # if only writing vocab to file - if args.vocab_only: - - fname_model = f"{dir_model}/consolidated.00.pth" - fname_out = f"{dir_model}/ggml-vocab.bin" - - print(f"Extracting only the vocab from '{fname_model}'\n") - - - with open(fname_out, "wb") as fout: - write_header(fout, hparams, ftype) - write_tokens(fout, tokenizer) - - - print(f"Done. Output file: {fname_out}\n") - - return - - n_parts = get_n_parts(hparams["dim"]) - - for p in range(n_parts): - - print(f"Processing part {p+1} of {n_parts}\n") - - fname_model = f"{dir_model}/consolidated.0{p}.pth" - fname_out = f"{dir_model}/ggml-model-{ftype_str[ftype]}.bin{'' if p == 0 else '.' + str(p)}" - - model = torch.load(fname_model, map_location="cpu") - - with open(fname_out, "wb") as fout: - write_header(fout, hparams, ftype) - write_tokens(fout, tokenizer) - process_and_write_variables(fout, model, ftype) - - del model - - print(f"Done. Output file: {fname_out}, (part {p})\n") - -if __name__ == "__main__": - main() diff --git a/convert-unversioned-ggml-to-ggml.py b/convert-unversioned-ggml-to-ggml.py deleted file mode 100644 index 33b6243..0000000 --- a/convert-unversioned-ggml-to-ggml.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python3 -# Original by https://github.com/eiz -# https://github.com/ggerganov/llama.cpp/issues/324#issuecomment-1476227818 -import argparse -import glob -import os -import struct -import sys -from sentencepiece import SentencePieceProcessor - -HPARAMS = keys = ["vocab_size", "dim", "multiple_of", "n_heads", "n_layers"] - -def parse_args(): - parser = argparse.ArgumentParser(description='Upgrade old ggml model files to the current format') - parser.add_argument('dir_model', help='directory containing ggml .bin files') - parser.add_argument('tokenizer_model', help='path to LLaMA tokenizer.model file') - return parser.parse_args() - -def read_header(f_in): - struct_fmt = "i" * (3 + len(HPARAMS)) - struct_size = struct.calcsize(struct_fmt) - buf = f_in.read(struct_size) - return struct.unpack(struct_fmt, buf) - -def write_header(f_out, header): - (magic, vocab_size, dim, multiple_of, n_heads, n_layers, rot, ftype) = header - - if magic != 0x67676d6c: - raise Exception('Invalid file magic. Must be an old style ggml file.') - - values = [ - 0x67676d66, # magic: ggml in hex - 1, # file version - vocab_size, - dim, - multiple_of, - n_heads, - n_layers, - rot, - ftype - ] - f_out.write(struct.pack("i" * len(values), *values)) - -def write_tokens(fout, tokenizer): - for i in range(tokenizer.vocab_size()): - if tokenizer.is_unknown(i): - text = " \u2047 ".encode("utf-8") - elif tokenizer.is_control(i): - text = b"" - elif tokenizer.is_byte(i): - piece = tokenizer.id_to_piece(i) - if len(piece) != 6: - print(f"Invalid token: {piece}") - sys.exit(1) - byte_value = int(piece[3:-1], 16) - text = struct.pack("B", byte_value) - else: - text = tokenizer.id_to_piece(i).replace("\u2581", " ").encode("utf-8") - fout.write(struct.pack("i", len(text))) - fout.write(text) - fout.write(struct.pack("f", tokenizer.get_score(i))) - -def read_tokens(f_in, tokenizer): - for i in range(tokenizer.vocab_size()): - len_b = f_in.read(4) - (length,) = struct.unpack("i", len_b) - f_in.read(length) - -def copy_all_data(f_out, f_in): - while True: - buf = f_in.read(1024 * 1024) - if not buf: - break - f_out.write(buf) - -def convert_one_file(path_in, tokenizer): - path_tmp = f"{path_in}.tmp" - path_orig= f"{path_in}.orig" - print(f"converting {path_in}") - with open(path_in, "rb") as f_in, open(path_tmp, "wb") as f_out: - write_header(f_out, read_header(f_in)) - read_tokens(f_in, tokenizer) - write_tokens(f_out, tokenizer) - copy_all_data(f_out, f_in) - os.rename(path_in, path_orig) - os.rename(path_tmp, path_in) - -def main(): - args = parse_args() - files = [] - files.extend(glob.glob(f"{args.dir_model}/*.bin")) - files.extend(glob.glob(f"{args.dir_model}/*.bin.*")) - - tokenizer = SentencePieceProcessor(args.tokenizer_model) - - for file in files: - convert_one_file(file, tokenizer) - -if __name__ == "__main__": - main() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt deleted file mode 100644 index c8f16df..0000000 --- a/examples/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -# dependencies - -find_package(Threads REQUIRED) - -# third-party - -# ... - -# common - -set(TARGET common) - -add_library(${TARGET} OBJECT - common.h - common.cpp - ) - -if (BUILD_SHARED_LIBS) - set_target_properties(${TARGET} PROPERTIES POSITION_INDEPENDENT_CODE ON) -endif() - -target_include_directories(${TARGET} PUBLIC .) -target_compile_features(${TARGET} PUBLIC cxx_std_11) -target_link_libraries(${TARGET} PRIVATE llama) - -# examples - -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) - -if (EMSCRIPTEN) -else() - add_subdirectory(main) - add_subdirectory(main_rwkv) - add_subdirectory(quantize) - add_subdirectory(perplexity) - add_subdirectory(embedding) -endif() diff --git a/examples/alpaca.sh b/examples/alpaca.sh deleted file mode 100755 index 4c9aa50..0000000 --- a/examples/alpaca.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# -# Temporary script - will be removed in the future -# - -cd `dirname $0` -cd .. - -./main -m ./models/ggml-alpaca-7b-q4.bin --color -f ./prompts/alpaca.txt -ins -b 256 --top_k 10000 --temp 0.2 --repeat_penalty 1 -t 7 diff --git a/examples/chat-13B.bat b/examples/chat-13B.bat deleted file mode 100644 index c5c8ac6..0000000 --- a/examples/chat-13B.bat +++ /dev/null @@ -1,57 +0,0 @@ -@setlocal disabledelayedexpansion enableextensions -@echo off - -cd /d "%~dp0.." -if not "%errorlevel%"=="0" ( - echo Unable to change directory. - pause - exit /b 1 -) - -if not defined MODEL set "MODEL=models\13B\ggml-model-q4_0.bin" -if not defined USER_NAME set "USER_NAME=User" -if not defined AI_NAME set "AI_NAME=ChatLLaMa" -rem Adjust to the number of CPU cores you want to use. -rem if not defined N_THREAD set "N_THREAD=8" -rem Number of tokens to predict (made it larger than default because we want a long interaction) -if not defined N_PREDICTS set "N_PREDICTS=2048" -if not defined GEN_OPTIONS set "GEN_OPTIONS=--ctx_size 2048 --temp 0.7 --top_k 40 --top_p 0.5 --repeat_last_n 256 --batch_size 1024 --repeat_penalty 1.17647" - -rem Default main script paths -set "DEFAULT_MAIN_SCRIPT_PATHS=main.exe build\bin\main.exe" - -rem Get main script path from command line arguments -set "MAIN_SCRIPT_PATH=%~1" - -rem If the main script path was not specified, try the default paths -if not defined MAIN_SCRIPT_PATH ( - for %%i in (%DEFAULT_MAIN_SCRIPT_PATHS%) do ( - if exist "%%i" set "MAIN_SCRIPT_PATH=%%i" - ) -) - -rem If the main script path was not found, tell the user how to specify it -if not defined MAIN_SCRIPT_PATH ( - echo The main script could not be found. Please provide the path to the main script as 1st argument to this script, or place the main script in one of the default locations: - echo %DEFAULT_MAIN_SCRIPT_PATHS% - pause - exit /b 1 -) - -rem Default context, feel free to edit it -set "PROMPT_TEXT=Text transcript of a never ending dialog, where %USER_NAME% interacts with an AI assistant named %AI_NAME%. %AI_NAME% is helpful, kind, honest, friendly, good at writing and never fails to answer %USER_NAME%'s requests immediately and with details and precision. There are no annotations like (30 seconds passed...) or (to himself), just what %USER_NAME% and %AI_NAME% say aloud to each other. The dialog lasts for years, the entirety of it is shared below. It's 10000 pages long. The transcript only includes text, it does not include markup like HTML and Markdown." - -rem Set a temporary variable if N_THREAD is set -if defined N_THREAD ( - set "_N_THREAD=--threads %N_THREAD%" -) else ( - set "_N_THREAD=" -) - -rem Run the script -echo "%MAIN_SCRIPT_PATH%" %GEN_OPTIONS% %_N_THREAD% ^ - --model "%MODEL%" ^ - --n_predict %N_PREDICTS% ^ - --color --interactive ^ - --reverse-prompt "%USER_NAME%:" ^ - --prompt "%PROMPT_TEXT%" diff --git a/examples/chat-13B.sh b/examples/chat-13B.sh deleted file mode 100755 index 4265d7b..0000000 --- a/examples/chat-13B.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -cd "$(dirname "$0")/.." || exit - -MODEL="${MODEL:-./models/13B/ggml-model-q4_0.bin}" -USER_NAME="${USER_NAME:-User}" -AI_NAME="${AI_NAME:-ChatLLaMa}" - -# Adjust to the number of CPU cores you want to use. -N_THREAD="${N_THREAD:-8}" -# Number of tokens to predict (made it larger than default because we want a long interaction) -N_PREDICTS="${N_PREDICTS:-2048}" - -# Note: you can also override the generation options by specifying them on the command line: -# For example, override the context size by doing: ./chatLLaMa --ctx_size 1024 -GEN_OPTIONS="${GEN_OPTIONS:---ctx_size 2048 --temp 0.7 --top_k 40 --top_p 0.5 --repeat_last_n 256 --batch_size 1024 --repeat_penalty 1.17647}" - -# shellcheck disable=SC2086 # Intended splitting of GEN_OPTIONS -./main $GEN_OPTIONS \ - --model "$MODEL" \ - --threads "$N_THREAD" \ - --n_predict "$N_PREDICTS" \ - --color --interactive \ - --reverse-prompt "${USER_NAME}:" \ - --prompt " -Text transcript of a never ending dialog, where ${USER_NAME} interacts with an AI assistant named ${AI_NAME}. -${AI_NAME} is helpful, kind, honest, friendly, good at writing and never fails to answer ${USER_NAME}’s requests immediately and with details and precision. -There are no annotations like (30 seconds passed...) or (to himself), just what ${USER_NAME} and ${AI_NAME} say aloud to each other. -The dialog lasts for years, the entirety of it is shared below. It's 10000 pages long. -The transcript only includes text, it does not include markup like HTML and Markdown. - -$USER_NAME: Hello, $AI_NAME! -$AI_NAME: Hello $USER_NAME! How may I help you today? -$USER_NAME: What time is it? -$AI_NAME: It is $(date +%H:%M). -$USER_NAME: What year is it? -$AI_NAME: We are in $(date +%Y). -$USER_NAME: Please tell me the largest city in Europe. -$AI_NAME: The largest city in Europe is Moscow, the capital of Russia. -$USER_NAME: What can you tell me about Moscow? -$AI_NAME: Moscow, on the Moskva River in western Russia, is the nation’s cosmopolitan capital. In its historic core is the Kremlin, a complex that’s home to the president and tsarist treasures in the Armoury. Outside its walls is Red Square, Russia’s symbolic center. -$USER_NAME: What is a cat? -$AI_NAME: A cat is a domestic species of small carnivorous mammal. It is the only domesticated species in the family Felidae. -$USER_NAME: How do I pass command line arguments to a Node.js program? -$AI_NAME: The arguments are stored in process.argv. - - argv[0] is the path to the Node. js executable. - argv[1] is the path to the script file. - argv[2] is the first argument passed to the script. - argv[3] is the second argument passed to the script and so on. -$USER_NAME: Name a color. -$AI_NAME: Blue -$USER_NAME:" "$@" diff --git a/examples/chat.sh b/examples/chat.sh deleted file mode 100755 index 9a928ef..0000000 --- a/examples/chat.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# -# Temporary script - will be removed in the future -# - -cd `dirname $0` -cd .. - -# Important: -# -# "--keep 48" is based on the contents of prompts/chat-with-bob.txt -# -./main -m ./models/7B/ggml-model-q4_0.bin -c 512 -b 1024 -n 256 --keep 48 \ - --repeat_penalty 1.0 --color -i \ - -r "User:" -f prompts/chat-with-bob.txt diff --git a/examples/common.cpp b/examples/common.cpp deleted file mode 100644 index af3ad9e..0000000 --- a/examples/common.cpp +++ /dev/null @@ -1,311 +0,0 @@ -#include "common.h" - -#include "ggml.h" - -#include -#include -#include -#include -#include -#include - -#if defined(_MSC_VER) || defined(__MINGW32__) -#include // using malloc.h with MSC/MINGW -#elif !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) -#include -#endif - -#if defined (_WIN32) -#pragma comment(lib,"kernel32.lib") -extern "C" __declspec(dllimport) void* __stdcall GetStdHandle(unsigned long nStdHandle); -extern "C" __declspec(dllimport) int __stdcall GetConsoleMode(void* hConsoleHandle, unsigned long* lpMode); -extern "C" __declspec(dllimport) int __stdcall SetConsoleMode(void* hConsoleHandle, unsigned long dwMode); -extern "C" __declspec(dllimport) int __stdcall SetConsoleCP(unsigned int wCodePageID); -extern "C" __declspec(dllimport) int __stdcall SetConsoleOutputCP(unsigned int wCodePageID); -#endif - -bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { - // determine sensible default number of threads. - // std::thread::hardware_concurrency may not be equal to the number of cores, or may return 0. -#ifdef __linux__ - std::ifstream cpuinfo("/proc/cpuinfo"); - params.n_threads = std::count(std::istream_iterator(cpuinfo), - std::istream_iterator(), - std::string("processor")); -#endif - if (params.n_threads == 0) { - params.n_threads = std::max(1, (int32_t) std::thread::hardware_concurrency()); - } - - bool invalid_param = false; - std::string arg; - for (int i = 1; i < argc; i++) { - arg = argv[i]; - - if (arg == "-s" || arg == "--seed") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.seed = std::stoi(argv[i]); - } else if (arg == "-t" || arg == "--threads") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.n_threads = std::stoi(argv[i]); - } else if (arg == "-p" || arg == "--prompt") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.prompt = argv[i]; - } else if (arg == "-f" || arg == "--file") { - if (++i >= argc) { - invalid_param = true; - break; - } - std::ifstream file(argv[i]); - std::copy(std::istreambuf_iterator(file), std::istreambuf_iterator(), back_inserter(params.prompt)); - if (params.prompt.back() == '\n') { - params.prompt.pop_back(); - } - } else if (arg == "-n" || arg == "--n_predict") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.n_predict = std::stoi(argv[i]); - } else if (arg == "--top_k") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.top_k = std::stoi(argv[i]); - } else if (arg == "-c" || arg == "--ctx_size") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.n_ctx = std::stoi(argv[i]); - } else if (arg == "--memory_f32") { - params.memory_f16 = false; - } else if (arg == "--top_p") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.top_p = std::stof(argv[i]); - } else if (arg == "--temp") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.temp = std::stof(argv[i]); - } else if (arg == "--repeat_last_n") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.repeat_last_n = std::stoi(argv[i]); - } else if (arg == "--repeat_penalty") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.repeat_penalty = std::stof(argv[i]); - } else if (arg == "-b" || arg == "--batch_size") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.n_batch = std::stoi(argv[i]); - params.n_batch = std::min(512, params.n_batch); - } else if (arg == "--keep") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.n_keep = std::stoi(argv[i]); - } else if (arg == "-m" || arg == "--model") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.model = argv[i]; - } else if (arg == "-i" || arg == "--interactive") { - params.interactive = true; - } else if (arg == "--embedding") { - params.embedding = true; - } else if (arg == "--interactive-start") { - params.interactive = true; - } else if (arg == "--interactive-first") { - params.interactive_start = true; - } else if (arg == "-ins" || arg == "--instruct") { - params.instruct = true; - } else if (arg == "--color") { - params.use_color = true; - } else if (arg == "--mlock") { - params.use_mlock = true; - } else if (arg == "--mtest") { - params.mem_test = true; - } else if (arg == "--verbose-prompt") { - params.verbose_prompt = true; - } else if (arg == "-r" || arg == "--reverse-prompt") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.antiprompt.push_back(argv[i]); - } else if (arg == "--perplexity") { - params.perplexity = true; - } else if (arg == "--ignore-eos") { - params.ignore_eos = true; - } else if (arg == "--n_parts") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.n_parts = std::stoi(argv[i]); - } else if (arg == "-h" || arg == "--help") { - gpt_print_usage(argc, argv, params); - exit(0); - } else if (arg == "--random-prompt") { - params.random_prompt = true; - } else if (arg == "--in-prefix") { - if (++i >= argc) { - invalid_param = true; - break; - } - params.input_prefix = argv[i]; - } else { - fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); - gpt_print_usage(argc, argv, params); - exit(1); - } - } - if (invalid_param) { - fprintf(stderr, "error: invalid parameter for argument: %s\n", arg.c_str()); - gpt_print_usage(argc, argv, params); - exit(1); - } - - return true; -} - -void gpt_print_usage(int /*argc*/, char ** argv, const gpt_params & params) { - fprintf(stderr, "usage: %s [options]\n", argv[0]); - fprintf(stderr, "\n"); - fprintf(stderr, "options:\n"); - fprintf(stderr, " -h, --help show this help message and exit\n"); - fprintf(stderr, " -i, --interactive run in interactive mode\n"); - fprintf(stderr, " --interactive-first run in interactive mode and wait for input right away\n"); - fprintf(stderr, " -ins, --instruct run in instruction mode (use with Alpaca models)\n"); - fprintf(stderr, " -r PROMPT, --reverse-prompt PROMPT\n"); - fprintf(stderr, " run in interactive mode and poll user input upon seeing PROMPT (can be\n"); - fprintf(stderr, " specified more than once for multiple prompts).\n"); - fprintf(stderr, " --color colorise output to distinguish prompt and user input from generations\n"); - fprintf(stderr, " -s SEED, --seed SEED RNG seed (default: -1, use random seed for <= 0)\n"); - fprintf(stderr, " -t N, --threads N number of threads to use during computation (default: %d)\n", params.n_threads); - fprintf(stderr, " -p PROMPT, --prompt PROMPT\n"); - fprintf(stderr, " prompt to start generation with (default: empty)\n"); - fprintf(stderr, " --random-prompt start with a randomized prompt.\n"); - fprintf(stderr, " --in-prefix STRING string to prefix user inputs with (default: empty)\n"); - fprintf(stderr, " -f FNAME, --file FNAME\n"); - fprintf(stderr, " prompt file to start generation.\n"); - fprintf(stderr, " -n N, --n_predict N number of tokens to predict (default: %d, -1 = infinity)\n", params.n_predict); - fprintf(stderr, " --top_k N top-k sampling (default: %d)\n", params.top_k); - fprintf(stderr, " --top_p N top-p sampling (default: %.1f)\n", (double)params.top_p); - fprintf(stderr, " --repeat_last_n N last n tokens to consider for penalize (default: %d)\n", params.repeat_last_n); - fprintf(stderr, " --repeat_penalty N penalize repeat sequence of tokens (default: %.1f)\n", (double)params.repeat_penalty); - fprintf(stderr, " -c N, --ctx_size N size of the prompt context (default: %d)\n", params.n_ctx); - fprintf(stderr, " --ignore-eos ignore end of stream token and continue generating\n"); - fprintf(stderr, " --memory_f32 use f32 instead of f16 for memory key+value\n"); - fprintf(stderr, " --temp N temperature (default: %.1f)\n", (double)params.temp); - fprintf(stderr, " --n_parts N number of model parts (default: -1 = determine from dimensions)\n"); - fprintf(stderr, " -b N, --batch_size N batch size for prompt processing (default: %d)\n", params.n_batch); - fprintf(stderr, " --perplexity compute perplexity over the prompt\n"); - fprintf(stderr, " --keep number of tokens to keep from the initial prompt (default: %d, -1 = all)\n", params.n_keep); - if (ggml_mlock_supported()) { - fprintf(stderr, " --mlock force system to keep model in RAM rather than swapping or compressing\n"); - } - fprintf(stderr, " --mtest compute maximum memory usage\n"); - fprintf(stderr, " --verbose-prompt print prompt before generation\n"); - fprintf(stderr, " -m FNAME, --model FNAME\n"); - fprintf(stderr, " model path (default: %s)\n", params.model.c_str()); - fprintf(stderr, "\n"); -} - -std::string gpt_random_prompt(std::mt19937 & rng) { - const int r = rng() % 10; - switch (r) { - case 0: return "So"; - case 1: return "Once upon a time"; - case 2: return "When"; - case 3: return "The"; - case 4: return "After"; - case 5: return "If"; - case 6: return "import"; - case 7: return "He"; - case 8: return "She"; - case 9: return "They"; - default: return "To"; - } - - return "The"; -} - -// TODO: not great allocating this every time -std::vector llama_tokenize(struct llama_context * ctx, const std::string & text, bool add_bos) { - // initialize to prompt numer of chars, since n_tokens <= n_prompt_chars - std::vector res(text.size() + (int)add_bos); - int n = llama_tokenize(ctx, text.c_str(), res.data(), res.size(), add_bos); - assert(n >= 0); - res.resize(n); - - return res; -} - -/* Keep track of current color of output, and emit ANSI code if it changes. */ -void set_console_color(console_state & con_st, console_color_t color) { - if (con_st.use_color && con_st.color != color) { - switch(color) { - case CONSOLE_COLOR_DEFAULT: - printf(ANSI_COLOR_RESET); - break; - case CONSOLE_COLOR_PROMPT: - printf(ANSI_COLOR_YELLOW); - break; - case CONSOLE_COLOR_USER_INPUT: - printf(ANSI_BOLD ANSI_COLOR_GREEN); - break; - } - con_st.color = color; - } -} - -#if defined (_WIN32) -void win32_console_init(bool enable_color) { - unsigned long dwMode = 0; - void* hConOut = GetStdHandle((unsigned long)-11); // STD_OUTPUT_HANDLE (-11) - if (!hConOut || hConOut == (void*)-1 || !GetConsoleMode(hConOut, &dwMode)) { - hConOut = GetStdHandle((unsigned long)-12); // STD_ERROR_HANDLE (-12) - if (hConOut && (hConOut == (void*)-1 || !GetConsoleMode(hConOut, &dwMode))) { - hConOut = 0; - } - } - if (hConOut) { - // Enable ANSI colors on Windows 10+ - if (enable_color && !(dwMode & 0x4)) { - SetConsoleMode(hConOut, dwMode | 0x4); // ENABLE_VIRTUAL_TERMINAL_PROCESSING (0x4) - } - // Set console output codepage to UTF8 - SetConsoleOutputCP(65001); // CP_UTF8 - } - void* hConIn = GetStdHandle((unsigned long)-10); // STD_INPUT_HANDLE (-10) - if (hConIn && hConIn != (void*)-1 && GetConsoleMode(hConIn, &dwMode)) { - // Set console input codepage to UTF8 - SetConsoleCP(65001); // CP_UTF8 - } -} -#endif diff --git a/examples/common.h b/examples/common.h deleted file mode 100644 index 1505aa9..0000000 --- a/examples/common.h +++ /dev/null @@ -1,95 +0,0 @@ -// Various helper functions and utilities - -#pragma once - -#include "llama.h" - -#include -#include -#include -#include - -// -// CLI argument parsing -// - -struct gpt_params { - int32_t seed = -1; // RNG seed - int32_t n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency()); - int32_t n_predict = 128; // new tokens to predict - int32_t repeat_last_n = 64; // last n tokens to penalize - int32_t n_parts = -1; // amount of model parts (-1 = determine from model dimensions) - int32_t n_ctx = 512; // context size - int32_t n_batch = 8; // batch size for prompt processing - int32_t n_keep = 0; // number of tokens to keep from initial prompt - - // sampling parameters - int32_t top_k = 40; - float top_p = 0.95f; - float temp = 0.80f; - float repeat_penalty = 1.10f; - - std::string model = "models/lamma-7B/ggml-model.bin"; // model path - std::string prompt = ""; - std::string input_prefix = ""; // string to prefix user inputs with - - - std::vector antiprompt; // string upon seeing which more user input is prompted - - bool memory_f16 = true; // use f16 instead of f32 for memory kv - bool random_prompt = false; // do not randomize prompt if none provided - bool use_color = false; // use color to distinguish generations and inputs - bool interactive = false; // interactive mode - - bool embedding = false; // get only sentence embedding - bool interactive_start = false; // wait for user input immediately - - bool instruct = false; // instruction mode (used for Alpaca models) - bool ignore_eos = false; // do not stop generating after eos - bool perplexity = false; // compute perplexity over the prompt - bool use_mlock = false; // use mlock to keep model in memory - bool mem_test = false; // compute maximum memory usage - bool verbose_prompt = false; // print prompt tokens before generation -}; - -bool gpt_params_parse(int argc, char ** argv, gpt_params & params); - -void gpt_print_usage(int argc, char ** argv, const gpt_params & params); - -std::string gpt_random_prompt(std::mt19937 & rng); - -// -// Vocab utils -// - -std::vector llama_tokenize(struct llama_context * ctx, const std::string & text, bool add_bos); - -// -// Console utils -// - -#define ANSI_COLOR_RED "\x1b[31m" -#define ANSI_COLOR_GREEN "\x1b[32m" -#define ANSI_COLOR_YELLOW "\x1b[33m" -#define ANSI_COLOR_BLUE "\x1b[34m" -#define ANSI_COLOR_MAGENTA "\x1b[35m" -#define ANSI_COLOR_CYAN "\x1b[36m" -#define ANSI_COLOR_RESET "\x1b[0m" -#define ANSI_BOLD "\x1b[1m" - -enum console_color_t { - CONSOLE_COLOR_DEFAULT=0, - CONSOLE_COLOR_PROMPT, - CONSOLE_COLOR_USER_INPUT -}; - -struct console_state { - bool use_color = false; - console_color_t color = CONSOLE_COLOR_DEFAULT; -}; - -void set_console_color(console_state & con_st, console_color_t color); - -#if defined (_WIN32) -void win32_console_init(bool enable_color); -#endif diff --git a/examples/embedding/CMakeLists.txt b/examples/embedding/CMakeLists.txt deleted file mode 100644 index 88c425d..0000000 --- a/examples/embedding/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(TARGET embedding) -add_executable(${TARGET} embedding.cpp) -target_link_libraries(${TARGET} PRIVATE common llama ${CMAKE_THREAD_LIBS_INIT}) -target_compile_features(${TARGET} PRIVATE cxx_std_11) diff --git a/examples/embedding/README.md b/examples/embedding/README.md deleted file mode 100644 index 21d8be6..0000000 --- a/examples/embedding/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# embedding - -TODO diff --git a/examples/embedding/embedding.cpp b/examples/embedding/embedding.cpp deleted file mode 100644 index d397f35..0000000 --- a/examples/embedding/embedding.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "common.h" -#include "llama.h" - -int main(int argc, char ** argv) { - gpt_params params; - params.model = "models/llama-7B/ggml-model.bin"; - - if (gpt_params_parse(argc, argv, params) == false) { - return 1; - } - - params.embedding = true; - - if (params.n_ctx > 2048) { - fprintf(stderr, "%s: warning: model does not support context sizes greater than 2048 tokens (%d specified);" - "expect poor results\n", __func__, params.n_ctx); - } - - if (params.seed <= 0) { - params.seed = time(NULL); - } - - fprintf(stderr, "%s: seed = %d\n", __func__, params.seed); - - std::mt19937 rng(params.seed); - if (params.random_prompt) { - params.prompt = gpt_random_prompt(rng); - } - - llama_context * ctx; - - // load the model - { - auto lparams = llama_context_default_params(); - - lparams.n_ctx = params.n_ctx; - lparams.n_parts = params.n_parts; - lparams.seed = params.seed; - lparams.f16_kv = params.memory_f16; - lparams.logits_all = params.perplexity; - lparams.use_mlock = params.use_mlock; - lparams.embedding = params.embedding; - - ctx = llama_init_from_file(params.model.c_str(), lparams); - - if (ctx == NULL) { - fprintf(stderr, "%s: error: failed to load model '%s'\n", __func__, params.model.c_str()); - return 1; - } - } - - // print system information - { - fprintf(stderr, "\n"); - fprintf(stderr, "system_info: n_threads = %d / %d | %s\n", - params.n_threads, std::thread::hardware_concurrency(), llama_print_system_info()); - } - - int n_past = 0; - - // Add a space in front of the first character to match OG llama tokenizer behavior - params.prompt.insert(0, 1, ' '); - - // tokenize the prompt - auto embd_inp = ::llama_tokenize(ctx, params.prompt, true); - - // determine newline token - auto llama_token_newline = ::llama_tokenize(ctx, "\n", false); - - if (params.verbose_prompt) { - fprintf(stderr, "\n"); - fprintf(stderr, "%s: prompt: '%s'\n", __func__, params.prompt.c_str()); - fprintf(stderr, "%s: number of tokens in prompt = %zu\n", __func__, embd_inp.size()); - for (int i = 0; i < (int) embd_inp.size(); i++) { - fprintf(stderr, "%6d -> '%s'\n", embd_inp[i], llama_token_to_str(ctx, embd_inp[i])); - } - fprintf(stderr, "\n"); - } - - if (params.embedding){ - if (embd_inp.size() > 0) { - if (llama_eval(ctx, embd_inp.data(), embd_inp.size(), n_past, params.n_threads)) { - fprintf(stderr, "%s : failed to eval\n", __func__); - return 1; - } - } - - const int n_embd = llama_n_embd(ctx); - const auto embeddings = llama_get_embeddings(ctx); - - for (int i = 0; i < n_embd; i++) { - printf("%f ", embeddings[i]); - } - printf("\n"); - } - - llama_print_timings(ctx); - llama_free(ctx); - - return 0; -} diff --git a/examples/main/CMakeLists.txt b/examples/main/CMakeLists.txt deleted file mode 100644 index b2dcc29..0000000 --- a/examples/main/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(TARGET main) -add_executable(${TARGET} main.cpp) -target_link_libraries(${TARGET} PRIVATE common llama ${CMAKE_THREAD_LIBS_INIT}) -target_compile_features(${TARGET} PRIVATE cxx_std_11) diff --git a/examples/main/README.md b/examples/main/README.md deleted file mode 100644 index 4701aa5..0000000 --- a/examples/main/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# main - -TODO diff --git a/examples/main/main.cpp b/examples/main/main.cpp deleted file mode 100644 index 3130aef..0000000 --- a/examples/main/main.cpp +++ /dev/null @@ -1,455 +0,0 @@ -#include "common.h" -#include "llama.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__)) -#include -#include -#elif defined (_WIN32) -#include -#endif - -static console_state con_st; - -static bool is_interacting = false; - -#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__)) || defined (_WIN32) -void sigint_handler(int signo) { - set_console_color(con_st, CONSOLE_COLOR_DEFAULT); - printf("\n"); // this also force flush stdout. - if (signo == SIGINT) { - if (!is_interacting) { - is_interacting=true; - } else { - _exit(130); - } - } -} -#endif - -int main(int argc, char ** argv) { - gpt_params params; - params.model = "models/llama-7B/ggml-model.bin"; - - if (gpt_params_parse(argc, argv, params) == false) { - return 1; - } - - // save choice to use color for later - // (note for later: this is a slightly awkward choice) - con_st.use_color = params.use_color; - -#if defined (_WIN32) - win32_console_init(params.use_color); -#endif - - if (params.perplexity) { - printf("\n************\n"); - printf("%s: please use the 'perplexity' tool for perplexity calculations\n", __func__); - printf("************\n\n"); - - return 0; - } - - if (params.embedding) { - printf("\n************\n"); - printf("%s: please use the 'embedding' tool for embedding calculations\n", __func__); - printf("************\n\n"); - - return 0; - } - - if (params.n_ctx > 2048) { - fprintf(stderr, "%s: warning: model does not support context sizes greater than 2048 tokens (%d specified);" - "expect poor results\n", __func__, params.n_ctx); - } - - if (params.seed <= 0) { - params.seed = time(NULL); - } - - fprintf(stderr, "%s: seed = %d\n", __func__, params.seed); - - std::mt19937 rng(params.seed); - if (params.random_prompt) { - params.prompt = gpt_random_prompt(rng); - } - -// params.prompt = R"(// this function checks if the number n is prime -//bool is_prime(int n) {)"; - - llama_context * ctx; - - // load the model - { - auto lparams = llama_context_default_params(); - - lparams.n_ctx = params.n_ctx; - lparams.n_parts = params.n_parts; - lparams.seed = params.seed; - lparams.f16_kv = params.memory_f16; - lparams.use_mlock = params.use_mlock; - - ctx = llama_init_from_file(params.model.c_str(), lparams); - - if (ctx == NULL) { - fprintf(stderr, "%s: error: failed to load model '%s'\n", __func__, params.model.c_str()); - return 1; - } - } - - // print system information - { - fprintf(stderr, "\n"); - fprintf(stderr, "system_info: n_threads = %d / %d | %s\n", - params.n_threads, std::thread::hardware_concurrency(), llama_print_system_info()); - } - - // determine the maximum memory usage needed to do inference for the given n_batch and n_predict parameters - // uncomment the "used_mem" line in llama.cpp to see the results - if (params.mem_test) { - { - const std::vector tmp(params.n_batch, 0); - llama_eval(ctx, tmp.data(), tmp.size(), 0, params.n_threads); - } - - { - const std::vector tmp = { 0, }; - llama_eval(ctx, tmp.data(), tmp.size(), params.n_predict - 1, params.n_threads); - } - - llama_print_timings(ctx); - llama_free(ctx); - - return 0; - } - - // Add a space in front of the first character to match OG llama tokenizer behavior - params.prompt.insert(0, 1, ' '); - - // tokenize the prompt - auto embd_inp = ::llama_tokenize(ctx, params.prompt, true); - - const int n_ctx = llama_n_ctx(ctx); - - if ((int) embd_inp.size() > n_ctx - 4) { - fprintf(stderr, "%s: error: prompt is too long (%d tokens, max %d)\n", __func__, (int) embd_inp.size(), n_ctx - 4); - return 1; - } - - // number of tokens to keep when resetting context - if (params.n_keep < 0 || params.n_keep > (int)embd_inp.size() || params.instruct) { - params.n_keep = (int)embd_inp.size(); - } - - // prefix & suffix for instruct mode - const auto inp_pfx = ::llama_tokenize(ctx, "\n\n### Instruction:\n\n", true); - const auto inp_sfx = ::llama_tokenize(ctx, "\n\n### Response:\n\n", false); - - // in instruct mode, we inject a prefix and a suffix to each input by the user - if (params.instruct) { - params.interactive_start = true; - params.antiprompt.push_back("### Instruction:\n\n"); - } - - // enable interactive mode if reverse prompt or interactive start is specified - if (params.antiprompt.size() != 0 || params.interactive_start) { - params.interactive = true; - } - - // determine newline token - auto llama_token_newline = ::llama_tokenize(ctx, "\n", false); - - if (params.verbose_prompt) { - fprintf(stderr, "\n"); - fprintf(stderr, "%s: prompt: '%s'\n", __func__, params.prompt.c_str()); - fprintf(stderr, "%s: number of tokens in prompt = %zu\n", __func__, embd_inp.size()); - for (int i = 0; i < (int) embd_inp.size(); i++) { - fprintf(stderr, "%6d -> '%s'\n", embd_inp[i], llama_token_to_str(ctx, embd_inp[i])); - } - if (params.n_keep > 0) { - fprintf(stderr, "%s: static prompt based on n_keep: '", __func__); - for (int i = 0; i < params.n_keep; i++) { - fprintf(stderr, "%s", llama_token_to_str(ctx, embd_inp[i])); - } - fprintf(stderr, "'\n"); - } - fprintf(stderr, "\n"); - } - - if (params.interactive) { -#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__)) - struct sigaction sigint_action; - sigint_action.sa_handler = sigint_handler; - sigemptyset (&sigint_action.sa_mask); - sigint_action.sa_flags = 0; - sigaction(SIGINT, &sigint_action, NULL); -#elif defined (_WIN32) - signal(SIGINT, sigint_handler); -#endif - - fprintf(stderr, "%s: interactive mode on.\n", __func__); - - if (params.antiprompt.size()) { - for (auto antiprompt : params.antiprompt) { - fprintf(stderr, "Reverse prompt: '%s'\n", antiprompt.c_str()); - } - } - - if (!params.input_prefix.empty()) { - fprintf(stderr, "Input prefix: '%s'\n", params.input_prefix.c_str()); - } - } - fprintf(stderr, "sampling: temp = %f, top_k = %d, top_p = %f, repeat_last_n = %i, repeat_penalty = %f\n", - params.temp, params.top_k, params.top_p, params.repeat_last_n, params.repeat_penalty); - fprintf(stderr, "generate: n_ctx = %d, n_batch = %d, n_predict = %d, n_keep = %d\n", n_ctx, params.n_batch, params.n_predict, params.n_keep); - fprintf(stderr, "\n\n"); - - // TODO: replace with ring-buffer - std::vector last_n_tokens(n_ctx); - std::fill(last_n_tokens.begin(), last_n_tokens.end(), 0); - - if (params.interactive) { - fprintf(stderr, "== Running in interactive mode. ==\n" -#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__)) || defined (_WIN32) - " - Press Ctrl+C to interject at any time.\n" -#endif - " - Press Return to return control to LLaMa.\n" - " - If you want to submit another line, end your input in '\\'.\n\n"); - is_interacting = params.interactive_start; - } - - bool is_antiprompt = false; - bool input_noecho = false; - - int n_past = 0; - int n_remain = params.n_predict; - int n_consumed = 0; - - // the first thing we will do is to output the prompt, so set color accordingly - set_console_color(con_st, CONSOLE_COLOR_PROMPT); - - std::vector embd; - - while (n_remain != 0 || params.interactive) { - // predict - if (embd.size() > 0) { - // infinite text generation via context swapping - // if we run out of context: - // - take the n_keep first tokens from the original prompt (via n_past) - // - take half of the last (n_ctx - n_keep) tokens and recompute the logits in a batch - if (n_past + (int) embd.size() > n_ctx) { - const int n_left = n_past - params.n_keep; - - n_past = params.n_keep; - - // insert n_left/2 tokens at the start of embd from last_n_tokens - embd.insert(embd.begin(), last_n_tokens.begin() + n_ctx - n_left/2 - embd.size(), last_n_tokens.end() - embd.size()); - - //printf("\n---\n"); - //printf("resetting: '"); - //for (int i = 0; i < (int) embd.size(); i++) { - // printf("%s", llama_token_to_str(ctx, embd[i])); - //} - //printf("'\n"); - //printf("\n---\n"); - } - - if (llama_eval(ctx, embd.data(), embd.size(), n_past, params.n_threads)) { - fprintf(stderr, "%s : failed to eval\n", __func__); - return 1; - } - } - - n_past += embd.size(); - embd.clear(); - - if ((int) embd_inp.size() <= n_consumed && !is_interacting) { - // out of user input, sample next token - const int32_t top_k = params.top_k; - const float top_p = params.top_p; - const float temp = params.temp; - const float repeat_penalty = params.repeat_penalty; - - llama_token id = 0; - - { - auto logits = llama_get_logits(ctx); - - if (params.ignore_eos) { - logits[llama_token_eos()] = 0; - } - - id = llama_sample_top_p_top_k(ctx, - last_n_tokens.data() + n_ctx - params.repeat_last_n, - params.repeat_last_n, top_k, top_p, temp, repeat_penalty); - - last_n_tokens.erase(last_n_tokens.begin()); - last_n_tokens.push_back(id); - } - - // replace end of text token with newline token when in interactive mode - if (id == llama_token_eos() && params.interactive && !params.instruct) { - id = llama_token_newline.front(); - if (params.antiprompt.size() != 0) { - // tokenize and inject first reverse prompt - const auto first_antiprompt = ::llama_tokenize(ctx, params.antiprompt.front(), false); - embd_inp.insert(embd_inp.end(), first_antiprompt.begin(), first_antiprompt.end()); - } - } - - // add it to the context - embd.push_back(id); - - // echo this to console - input_noecho = false; - - // decrement remaining sampling budget - --n_remain; - } else { - // some user input remains from prompt or interaction, forward it to processing - while ((int) embd_inp.size() > n_consumed) { - embd.push_back(embd_inp[n_consumed]); - last_n_tokens.erase(last_n_tokens.begin()); - last_n_tokens.push_back(embd_inp[n_consumed]); - ++n_consumed; - if ((int) embd.size() >= params.n_batch) { - break; - } - } - } - - // display text - if (!input_noecho) { - for (auto id : embd) { - printf("%s", llama_token_to_str(ctx, id)); - } - fflush(stdout); - } - // reset color to default if we there is no pending user input - if (!input_noecho && (int)embd_inp.size() == n_consumed) { - set_console_color(con_st, CONSOLE_COLOR_DEFAULT); - } - - // in interactive mode, and not currently processing queued inputs; - // check if we should prompt the user for more - if (params.interactive && (int) embd_inp.size() <= n_consumed) { - - // check for reverse prompt - if (params.antiprompt.size()) { - std::string last_output; - for (auto id : last_n_tokens) { - last_output += llama_token_to_str(ctx, id); - } - - is_antiprompt = false; - // Check if each of the reverse prompts appears at the end of the output. - for (std::string & antiprompt : params.antiprompt) { - if (last_output.find(antiprompt.c_str(), last_output.length() - antiprompt.length(), antiprompt.length()) != std::string::npos) { - is_interacting = true; - is_antiprompt = true; - set_console_color(con_st, CONSOLE_COLOR_USER_INPUT); - fflush(stdout); - break; - } - } - } - - if (n_past > 0 && is_interacting) { - // potentially set color to indicate we are taking user input - set_console_color(con_st, CONSOLE_COLOR_USER_INPUT); - - if (params.instruct) { - printf("\n> "); - } - - std::string buffer; - if (!params.input_prefix.empty()) { - buffer += params.input_prefix; - printf("%s", buffer.c_str()); - } - - std::string line; - bool another_line = true; - do { - if (!std::getline(std::cin, line)) { - // input stream is bad or EOF received - return 0; - } - if (line.empty() || line.back() != '\\') { - another_line = false; - } else { - line.pop_back(); // Remove the continue character - } - buffer += line + '\n'; // Append the line to the result - } while (another_line); - - // done taking input, reset color - set_console_color(con_st, CONSOLE_COLOR_DEFAULT); - - // Add tokens to embd only if the input buffer is non-empty - // Entering a empty line lets the user pass control back - if (buffer.length() > 1) { - - // instruct mode: insert instruction prefix - if (params.instruct && !is_antiprompt) { - n_consumed = embd_inp.size(); - embd_inp.insert(embd_inp.end(), inp_pfx.begin(), inp_pfx.end()); - } - - auto line_inp = ::llama_tokenize(ctx, buffer, false); - embd_inp.insert(embd_inp.end(), line_inp.begin(), line_inp.end()); - - // instruct mode: insert response suffix - if (params.instruct) { - embd_inp.insert(embd_inp.end(), inp_sfx.begin(), inp_sfx.end()); - } - - n_remain -= line_inp.size(); - } - - input_noecho = true; // do not echo this again - } - - if (n_past > 0) { - is_interacting = false; - } - } - - // end of text token - if (embd.back() == llama_token_eos()) { - if (params.instruct) { - is_interacting = true; - } else { - fprintf(stderr, " [end of text]\n"); - break; - } - } - - // In interactive mode, respect the maximum number of tokens and drop back to user input when reached. - if (params.interactive && n_remain <= 0 && params.n_predict != -1) { - n_remain = params.n_predict; - is_interacting = true; - } - } - -#if defined (_WIN32) - signal(SIGINT, SIG_DFL); -#endif - - llama_print_timings(ctx); - llama_free(ctx); - - set_console_color(con_st, CONSOLE_COLOR_DEFAULT); - - return 0; -} diff --git a/examples/main_rwkv/CMakeLists.txt b/examples/main_rwkv/CMakeLists.txt deleted file mode 100644 index 4305410..0000000 --- a/examples/main_rwkv/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(TARGET main_rwkv) -add_executable(${TARGET} main_rwkv.cpp) -target_link_libraries(${TARGET} PRIVATE rwkv ggml ${CMAKE_THREAD_LIBS_INIT}) -target_compile_features(${TARGET} PRIVATE cxx_std_11) diff --git a/examples/main_rwkv/README.md b/examples/main_rwkv/README.md deleted file mode 100644 index 41464bb..0000000 --- a/examples/main_rwkv/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# main_rwkv - -Runner for RWKV language model. diff --git a/examples/main_rwkv/main_rwkv.cpp b/examples/main_rwkv/main_rwkv.cpp deleted file mode 100644 index fa32ae8..0000000 --- a/examples/main_rwkv/main_rwkv.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include "ggml.h" -#include "rwkv.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// --- Utilities --- - -// Checks that x is not false. If x is false, prints fancy message to stderr and aborts the execution. -#define RWKV_ASSERT(x, ...) \ - do { \ - if (!(x)) { \ - fprintf(stderr, "*** Assertion failed ***\n"); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, "\n%s:%d: %s\n", __FILE__, __LINE__, #x); \ - abort(); \ - } \ - } while (0) - -// Formats and prints a message to stderr. Trailing newline is added automatically. -#define RWKV_LOG(...) do { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); } while (0) - -// --- Script --- - -// Usage: main_rwkv.exe "C:\model.bin" "C:\state_in.bin" "C:\state_out.bin" "C:\logits_out.bin" [thread count] -// Token index is 0-based. -// Thread count is optional and defaults to std::thread::hardware_concurrency() / 2. -// To start from new state, pass empty string instead of input state file path. -int main(int argc, char ** argv) { - ggml_run_test_suite(); - - fprintf(stderr, "%s\n", rwkv_get_system_info_string()); - - RWKV_ASSERT(argc - 1 == 5 || argc - 1 == 6, "Expected 5 or 6 arguments, got %d", argc - 1); - char * model_path = argv[1]; - char * token_s = argv[2]; - char * state_in_path = argv[3]; - char * state_out_path = argv[4]; - char * logits_out_path = argv[5]; - - int32_t token = strtol(token_s, (char **) NULL, 10); - RWKV_LOG("Token index is %d", token); - - bool create_new_state = strcmp(state_in_path, "") == 0; - - int n_threads; - - if (argc - 1 == 6) { - n_threads = strtol(argv[6], (char **) NULL, 10); - } else { - n_threads = 0; - } - - if (n_threads == 0) { - n_threads = std::max(1, (int32_t) std::thread::hardware_concurrency() / 2); - } else { - RWKV_ASSERT(n_threads > 0, "Thread couns %d is not positive", n_threads); - } - - RWKV_LOG("Using %d threads", n_threads); - - struct rwkv_context * ctx = rwkv_init_from_file(model_path, n_threads); - - RWKV_ASSERT(ctx != NULL, "Failed to load the model"); - - size_t state_buffer_size = rwkv_get_state_buffer_element_count(ctx) * sizeof(float); - size_t logits_buffer_size = rwkv_get_logits_buffer_element_count(ctx) * sizeof(float); - - float * state_buffer = (float *) calloc(1, state_buffer_size); - float * logits_buffer = (float *) calloc(1, logits_buffer_size); - - if (!create_new_state) { - RWKV_LOG("Loading state from %s", state_in_path); - - FILE * state_in_file = fopen(state_in_path, "rb"); - RWKV_ASSERT(state_in_file != NULL, "Failed to open file %s", state_in_path); - - // TODO Saving/loading raw data makes state cache machine-dependent - RWKV_ASSERT(fread(state_buffer, 1, state_buffer_size, state_in_file) == state_buffer_size, "Failed to read state from a file"); - - fclose(state_in_file); - } - - bool result = rwkv_eval( - ctx, - token, - create_new_state ? NULL : state_buffer, - state_buffer, - logits_buffer - ); - - RWKV_ASSERT(result, "Failed to evaluate the model"); - - { - RWKV_LOG("Saving state to %s", state_out_path); - - FILE * state_out_file = fopen(state_out_path, "wb"); - RWKV_ASSERT(state_out_file != NULL, "Failed to open file %s", state_out_path); - - RWKV_ASSERT(fwrite(state_buffer, 1, state_buffer_size, state_out_file) == state_buffer_size, "Failed to write state to a file"); - - fclose(state_out_file); - } - - { - RWKV_LOG("Saving logits to %s", logits_out_path); - - FILE * logits_out_file = fopen(logits_out_path, "wb"); - RWKV_ASSERT(logits_out_file != NULL, "Failed to open file %s", logits_out_path); - - RWKV_ASSERT(fwrite(logits_buffer, 1, logits_buffer_size, logits_out_file) == logits_buffer_size, "Failed to write logits to a file"); - - fclose(logits_out_file); - } - - rwkv_free(ctx); - - delete state_buffer; - delete logits_buffer; - - RWKV_LOG("OK"); - - return 0; -} diff --git a/examples/perplexity/CMakeLists.txt b/examples/perplexity/CMakeLists.txt deleted file mode 100644 index 5836df8..0000000 --- a/examples/perplexity/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(TARGET perplexity) -add_executable(${TARGET} perplexity.cpp) -target_link_libraries(${TARGET} PRIVATE common llama ${CMAKE_THREAD_LIBS_INIT}) -target_compile_features(${TARGET} PRIVATE cxx_std_11) diff --git a/examples/perplexity/README.md b/examples/perplexity/README.md deleted file mode 100644 index a932275..0000000 --- a/examples/perplexity/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# perplexity - -TODO diff --git a/examples/perplexity/perplexity.cpp b/examples/perplexity/perplexity.cpp deleted file mode 100644 index 07ed0a8..0000000 --- a/examples/perplexity/perplexity.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include "common.h" -#include "llama.h" - -#include - -std::vector softmax(const std::vector& logits) { - std::vector probs(logits.size()); - float max_logit = logits[0]; - for (float v : logits) max_logit = std::max(max_logit, v); - double sum_exp = 0.0; - for (size_t i = 0; i < logits.size(); i++) { - // Subtract the maximum logit value from the current logit value for numerical stability - const float logit = logits[i] - max_logit; - const float exp_logit = expf(logit); - sum_exp += exp_logit; - probs[i] = exp_logit; - } - for (size_t i = 0; i < probs.size(); i++) probs[i] /= sum_exp; - return probs; -} - -void perplexity(llama_context * ctx, const gpt_params & params) { - // Download: https://s3.amazonaws.com/research.metamind.io/wikitext/wikitext-2-raw-v1.zip?ref=salesforce-research - // Run `./perplexity -m models/7B/ggml-model-q4_0.bin -f wiki.test.raw` - // Output: `perplexity: 13.5106 [114/114]` - auto tokens = ::llama_tokenize(ctx, params.prompt, true); - - int count = 0; - int seq_count = tokens.size() / params.n_ctx; - - double nll = 0.0; - - fprintf(stderr, "%s : calculating perplexity over %d chunks\n", __func__, seq_count); - - for (int i = 0; i < seq_count; ++i) { - int start = i * params.n_ctx; - int end = start + params.n_ctx - 1; // TODO: this is not optimal, e.g. it makes the batch 511 instead of 512 - // it is better to always be power of 2 for better performance - std::vector embd(tokens.begin() + start, tokens.begin() + end); - auto start_t = std::chrono::high_resolution_clock::now(); - if (llama_eval(ctx, embd.data(), embd.size(), 0, params.n_threads)) { - fprintf(stderr, "%s : failed to eval\n", __func__); - return; - } - auto end_t = std::chrono::high_resolution_clock::now(); - if (i == 0) { - const float seconds = std::chrono::duration(end_t - start_t).count(); - printf("%.2f seconds per pass - ETA %.2f hours\n", seconds, (seconds * seq_count) / (60.0*60.0)); - } - // We get the logits for all the tokens in the context window (params.n_ctx) - // from llama_eval above. Now, based on https://huggingface.co/docs/transformers/perplexity, - // calculate the perplexity over the last half the window (so the model always has - // some context to predict the token). - // - // We rely on the fact that attention in the forward pass only looks at previous - // tokens here, so the logits returned for each token are an accurate representation - // of what the model would have predicted at that point. - // - // Example, we have a context window of 512, we will compute perplexity for each of the - // last 256 tokens. Then, we split the input up into context window size chunks to - // process the entire prompt. - - auto logits = llama_get_logits(ctx); - for (int j = params.n_ctx / 2; j < params.n_ctx - 1; ++j) { - // Calculate probability of next token, given the previous ones. - int n_vocab = llama_n_vocab(ctx); - std::vector tok_logits( - logits + j * n_vocab, - logits + (j + 1) * n_vocab); - const float prob = softmax(tok_logits)[tokens[start + j + 1]]; - nll += -std::log(prob); - ++count; - } - // perplexity is e^(average negative log-likelihood) - printf("[%d]%.4lf,", i + 1, std::exp(nll / count)); - fflush(stdout); - } - printf("\n"); -} - -int main(int argc, char ** argv) { - gpt_params params; - params.model = "models/llama-7B/ggml-model.bin"; - - if (gpt_params_parse(argc, argv, params) == false) { - return 1; - } - - params.perplexity = true; - - if (params.n_ctx > 2048) { - fprintf(stderr, "%s: warning: model does not support context sizes greater than 2048 tokens (%d specified);" - "expect poor results\n", __func__, params.n_ctx); - } - - if (params.seed <= 0) { - params.seed = time(NULL); - } - - fprintf(stderr, "%s: seed = %d\n", __func__, params.seed); - - std::mt19937 rng(params.seed); - if (params.random_prompt) { - params.prompt = gpt_random_prompt(rng); - } - - llama_context * ctx; - - // load the model - { - auto lparams = llama_context_default_params(); - - lparams.n_ctx = params.n_ctx; - lparams.n_parts = params.n_parts; - lparams.seed = params.seed; - lparams.f16_kv = params.memory_f16; - lparams.logits_all = params.perplexity; - lparams.use_mlock = params.use_mlock; - lparams.embedding = params.embedding; - - ctx = llama_init_from_file(params.model.c_str(), lparams); - - if (ctx == NULL) { - fprintf(stderr, "%s: error: failed to load model '%s'\n", __func__, params.model.c_str()); - return 1; - } - } - - // print system information - { - fprintf(stderr, "\n"); - fprintf(stderr, "system_info: n_threads = %d / %d | %s\n", - params.n_threads, std::thread::hardware_concurrency(), llama_print_system_info()); - } - - perplexity(ctx, params); - - llama_print_timings(ctx); - llama_free(ctx); - - return 0; -} diff --git a/examples/quantize/CMakeLists.txt b/examples/quantize/CMakeLists.txt deleted file mode 100644 index fb27d45..0000000 --- a/examples/quantize/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(TARGET quantize) -add_executable(${TARGET} quantize.cpp) -target_link_libraries(${TARGET} PRIVATE llama ${CMAKE_THREAD_LIBS_INIT}) -target_compile_features(${TARGET} PRIVATE cxx_std_11) diff --git a/examples/quantize/README.md b/examples/quantize/README.md deleted file mode 100644 index f349e91..0000000 --- a/examples/quantize/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# quantize - -TODO diff --git a/examples/quantize/quantize.cpp b/examples/quantize/quantize.cpp deleted file mode 100644 index b444328..0000000 --- a/examples/quantize/quantize.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "ggml.h" -#include "llama.h" - -#include -#include - -// usage: -// ./llama-quantize models/llama/ggml-model.bin models/llama/ggml-model-quant.bin type -// -int main(int argc, char ** argv) { - ggml_time_init(); - - if (argc != 4) { - fprintf(stderr, "usage: %s model-f32.bin model-quant.bin type\n", argv[0]); - fprintf(stderr, " type = 2 - q4_0\n"); - fprintf(stderr, " type = 3 - q4_1\n"); - return 1; - } - - // needed to initialize f16 tables - { - struct ggml_init_params params = { 0, NULL }; - struct ggml_context * ctx = ggml_init(params); - ggml_free(ctx); - } - - const std::string fname_inp = argv[1]; - const std::string fname_out = argv[2]; - - const int itype = atoi(argv[3]); - - const int64_t t_main_start_us = ggml_time_us(); - - int64_t t_quantize_us = 0; - - // load the model - { - const int64_t t_start_us = ggml_time_us(); - - if (llama_model_quantize(fname_inp.c_str(), fname_out.c_str(), itype)) { - fprintf(stderr, "%s: failed to quantize model from '%s'\n", __func__, fname_inp.c_str()); - return 1; - } - - t_quantize_us = ggml_time_us() - t_start_us; - } - - // report timing - { - const int64_t t_main_end_us = ggml_time_us(); - - printf("\n"); - printf("%s: quantize time = %8.2f ms\n", __func__, t_quantize_us/1000.0); - printf("%s: total time = %8.2f ms\n", __func__, (t_main_end_us - t_main_start_us)/1000.0); - } - - return 0; -} diff --git a/examples/reason-act.sh b/examples/reason-act.sh deleted file mode 100755 index e7fe655..0000000 --- a/examples/reason-act.sh +++ /dev/null @@ -1,17 +0,0 @@ - -#!/bin/bash - -cd `dirname $0` -cd .. - -# get -m model parameter otherwise defer to default -if [ "$1" == "-m" ]; then - MODEL="-m $2 " -fi - -./main $MODEL --color \ - -f ./prompts/reason-act.txt \ - -i --interactive-first \ - --top_k 10000 --temp 0.2 --repeat_penalty 1 -t 7 -c 2048 \ - -r "Question:" -r "Observation:" --in-prefix " " \ - -n -1 diff --git a/flake.lock b/flake.lock deleted file mode 100644 index 343996d..0000000 --- a/flake.lock +++ /dev/null @@ -1,43 +0,0 @@ -{ - "nodes": { - "flake-utils": { - "locked": { - "lastModified": 1676283394, - "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1678470307, - "narHash": "sha256-OEeMUr3ueLIXyW/OaFUX5jUdimyQwMg/7e+/Q0gC/QE=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "0c4800d579af4ed98ecc47d464a5e7b0870c4b1f", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 4c2717e..0000000 --- a/flake.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - flake-utils.url = "github:numtide/flake-utils"; - }; - outputs = { self, nixpkgs, flake-utils }: - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = import nixpkgs { - inherit system; - }; - llama-python = pkgs.python310.withPackages (ps: with ps; [ - torch - numpy - sentencepiece - ]); - in - { - packages.default = pkgs.stdenv.mkDerivation { - name = "llama.cpp"; - src = ./.; - nativeBuildInputs = with pkgs; [ cmake ]; - buildInputs = with pkgs; lib.optionals stdenv.isDarwin [ - darwin.apple_sdk.frameworks.Accelerate - ]; - cmakeFlags = with pkgs; lib.optionals (system == "aarch64-darwin") [ - "-DCMAKE_C_FLAGS=-D__ARM_FEATURE_DOTPROD=1" - ]; - installPhase = '' - mkdir -p $out/bin - mv bin/main $out/bin/llama - mv bin/quantize $out/bin/quantize - echo "#!${llama-python}/bin/python" > $out/bin/convert-pth-to-ggml - cat ${./convert-pth-to-ggml.py} >> $out/bin/convert-pth-to-ggml - chmod +x $out/bin/convert-pth-to-ggml - ''; - meta.mainProgram = "llama"; - }; - devShells.default = pkgs.mkShell { - packages = with pkgs; [ - cmake - llama-python - ] ++ lib.optionals stdenv.isDarwin [ - darwin.apple_sdk.frameworks.Accelerate - ]; - }; - } - ); -} diff --git a/llama.cpp b/llama.cpp deleted file mode 100644 index e4998ef..0000000 --- a/llama.cpp +++ /dev/null @@ -1,1864 +0,0 @@ -#include "llama.h" - -#include "ggml.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LLAMA_USE_SCRATCH -#define LLAMA_MAX_SCRATCH_BUFFERS 16 - -#define LLAMA_ASSERT(x) \ - do { \ - if (!(x)) { \ - fprintf(stderr, "LLAMA_ASSERT: %s:%d: %s\n", __FILE__, __LINE__, #x); \ - abort(); \ - } \ - } while (0) - - -// determine number of model parts based on the dimension -static const std::unordered_map LLAMA_N_PARTS = { - { 4096, 1 }, - { 5120, 2 }, - { 6656, 4 }, - { 8192, 8 }, -}; - -// available llama models -enum e_model { - MODEL_UNKNOWN, - MODEL_7B, - MODEL_13B, - MODEL_30B, - MODEL_65B, -}; - -static const size_t MB = 1024*1024; - -// computed for n_ctx == 2048 -// TODO: dynamically determine these sizes -// needs modifications in ggml - -static const std::map MEM_REQ_SCRATCH0 = { - { MODEL_7B, 512ull*MB }, - { MODEL_13B, 512ull*MB }, - { MODEL_30B, 512ull*MB }, - { MODEL_65B, 512ull*MB }, -}; - -static const std::map MEM_REQ_SCRATCH1 = { - { MODEL_7B, 512ull*MB }, - { MODEL_13B, 512ull*MB }, - { MODEL_30B, 512ull*MB }, - { MODEL_65B, 512ull*MB }, -}; - -// 2*n_embd*n_ctx*n_layer*sizeof(float16) -static const std::map MEM_REQ_KV_SELF = { - { MODEL_7B, 1026ull*MB }, - { MODEL_13B, 1608ull*MB }, - { MODEL_30B, 3124ull*MB }, - { MODEL_65B, 5120ull*MB }, -}; - -// this is mostly needed for temporary mul_mat buffers to dequantize the data -// not actually needed if BLAS is disabled -static const std::map MEM_REQ_EVAL = { - { MODEL_7B, 768ull*MB }, - { MODEL_13B, 1024ull*MB }, - { MODEL_30B, 1280ull*MB }, - { MODEL_65B, 1536ull*MB }, -}; - -// default hparams (LLaMA 7B) -struct llama_hparams { - int32_t n_vocab = 32000; - int32_t n_ctx = 512; // this is provided as user input? - int32_t n_embd = 4096; - int32_t n_mult = 256; - int32_t n_head = 32; - int32_t n_layer = 32; - int32_t n_rot = 64; - int32_t f16 = 1; -}; - -struct llama_layer { - // normalization - struct ggml_tensor * attention_norm; - - // attention - struct ggml_tensor * wq; - struct ggml_tensor * wk; - struct ggml_tensor * wv; - struct ggml_tensor * wo; - - // normalization - struct ggml_tensor * ffn_norm; - - // ff - struct ggml_tensor * w1; - struct ggml_tensor * w2; - struct ggml_tensor * w3; -}; - -struct llama_kv_cache { - struct ggml_tensor * k; - struct ggml_tensor * v; - - struct ggml_context * ctx; - - std::vector buf; - - int n; // number of tokens currently in the cache -}; - -struct llama_model { - e_model type = MODEL_UNKNOWN; - - llama_hparams hparams; - - struct ggml_tensor * tok_embeddings; - - struct ggml_tensor * norm; - struct ggml_tensor * output; - - std::vector layers; - - // context - struct ggml_context * ctx; - - // key + value cache for the self attention - // TODO: move to llama_state - struct llama_kv_cache kv_self; - - // the model memory buffer - std::vector buf; - - // tensors - int n_loaded; - std::unordered_map tensors; -}; - -struct llama_vocab { - using id = int32_t; - using token = std::string; - - struct token_score { - token tok; - float score; - }; - - std::unordered_map token_to_id; - std::vector id_to_token; -}; - -struct llama_context { - std::mt19937 rng; - - int64_t t_load_us = 0; - int64_t t_start_us = 0; - - int64_t t_sample_us = 0; - int64_t t_eval_us = 0; - int64_t t_p_eval_us = 0; - - int32_t n_sample = 0; // number of tokens sampled - int32_t n_eval = 0; // number of eval calls - int32_t n_p_eval = 0; // number of tokens in eval calls for the prompt (with batch size > 1) - - llama_model model; - llama_vocab vocab; - - size_t mem_per_token = 0; - - // decode output (2-dimensional array: [n_tokens][n_vocab]) - std::vector logits; - bool logits_all = false; - - // input embedding (1-dimensional array: [n_embd]) - std::vector embedding; - - // memory buffers used to evaluate the model - // TODO: move in llama_state - std::vector buf_compute; - std::vector buf_scratch[LLAMA_MAX_SCRATCH_BUFFERS]; - - int buf_last = 0; - size_t buf_max_size[LLAMA_MAX_SCRATCH_BUFFERS] = { 0 }; - - void use_buf(struct ggml_context * ctx, int i) { -#if defined(LLAMA_USE_SCRATCH) - size_t last_size = 0; - - if (i == -1) { - last_size = ggml_set_scratch(ctx, { 0, 0, nullptr, }); - } else { - auto & buf = buf_scratch[i]; - last_size = ggml_set_scratch(ctx, { 0, buf.size(), buf.data(), }); - } - - if (buf_last >= 0) { - buf_max_size[buf_last] = std::max(buf_max_size[buf_last], last_size); - } - - buf_last = i; -#else - (void) i; - (void) ctx; -#endif - } - - size_t get_buf_max_mem(int i) const { -#if defined(LLAMA_USE_SCRATCH) - return buf_max_size[i]; -#else - (void) i; - return 0; -#endif - } -}; - -// -// kv cache -// - -static bool kv_cache_init( - const struct llama_hparams & hparams, - struct llama_kv_cache & cache, - ggml_type wtype, - int n_ctx) { - const int n_embd = hparams.n_embd; - const int n_layer = hparams.n_layer; - - const int n_mem = n_layer*n_ctx; - const int n_elements = n_embd*n_mem; - - cache.buf.resize(2u*n_elements*ggml_type_size(wtype) + 2u*MB); - - struct ggml_init_params params; - params.mem_size = cache.buf.size(); - params.mem_buffer = cache.buf.data(); - - cache.ctx = ggml_init(params); - - if (!cache.ctx) { - fprintf(stderr, "%s: failed to allocate memory for kv cache\n", __func__); - return false; - } - - cache.k = ggml_new_tensor_1d(cache.ctx, wtype, n_elements); - cache.v = ggml_new_tensor_1d(cache.ctx, wtype, n_elements); - - return true; -} - -static void kv_cache_free(struct llama_kv_cache & cache) { - if (cache.ctx) { - ggml_free(cache.ctx); - cache.ctx = nullptr; - } -} - -struct llama_context_params llama_context_default_params() { - struct llama_context_params result = { - /*.n_ctx =*/ 512, - /*.n_parts =*/ -1, - /*.seed =*/ 0, - /*.f16_kv =*/ false, - /*.logits_all =*/ false, - /*.vocab_only =*/ false, - /*.use_mlock =*/ false, - /*.embedding =*/ false, - /*.progress_callback =*/ nullptr, - /*.progress_callback_user_data =*/ nullptr, - }; - - return result; -} - -// -// model loading -// - -static bool llama_model_load( - const std::string & fname, - llama_context & lctx, - int n_ctx, - int n_parts, - ggml_type memory_type, - bool vocab_only, - llama_progress_callback progress_callback, - void *progress_callback_user_data) { - fprintf(stderr, "%s: loading model from '%s' - please wait ...\n", __func__, fname.c_str()); - - const int64_t t_start_us = ggml_time_us(); - - lctx.t_start_us = t_start_us; - - std::vector f_buf(1024*1024); - - auto & model = lctx.model; - auto & vocab = lctx.vocab; - - auto fin = std::ifstream(fname, std::ios::binary); - fin.rdbuf()->pubsetbuf(f_buf.data(), f_buf.size()); - if (!fin) { - fprintf(stderr, "%s: failed to open '%s'\n", __func__, fname.c_str()); - return false; - } - - // verify magic - { - uint32_t magic; - fin.read((char *) &magic, sizeof(magic)); - if (magic == LLAMA_FILE_MAGIC_UNVERSIONED) { - fprintf(stderr, "%s: invalid model file '%s' (too old, regenerate your model files or convert them with convert-unversioned-ggml-to-ggml.py!)\n", - __func__, fname.c_str()); - return false; - } - if (magic != LLAMA_FILE_MAGIC) { - fprintf(stderr, "%s: invalid model file '%s' (bad magic)\n", __func__, fname.c_str()); - return false; - } - - uint32_t format_version; - fin.read((char *) &format_version, sizeof(format_version)); - - if (format_version != LLAMA_FILE_VERSION) { - fprintf(stderr, "%s: invalid model file '%s' (unsupported format version %" PRIu32 ", expected %d)\n", - __func__, fname.c_str(), format_version, LLAMA_FILE_VERSION); - return false; - } - } - - int n_ff = 0; - - // load hparams - { - auto & hparams = model.hparams; - - fin.read((char *) &hparams.n_vocab, sizeof(hparams.n_vocab)); - //fin.read((char *) &hparams.n_ctx, sizeof(hparams.n_ctx)); - fin.read((char *) &hparams.n_embd, sizeof(hparams.n_embd)); - fin.read((char *) &hparams.n_mult, sizeof(hparams.n_mult)); - fin.read((char *) &hparams.n_head, sizeof(hparams.n_head)); - fin.read((char *) &hparams.n_layer, sizeof(hparams.n_layer)); - fin.read((char *) &hparams.n_rot, sizeof(hparams.n_rot)); - fin.read((char *) &hparams.f16, sizeof(hparams.f16)); - - hparams.n_ctx = n_ctx; - - n_ff = ((2*(4*hparams.n_embd)/3 + hparams.n_mult - 1)/hparams.n_mult)*hparams.n_mult; - - if (n_parts < 1) { - n_parts = LLAMA_N_PARTS.at(hparams.n_embd); - } - - // temp warning to tell the user to use "--n_parts" - if (hparams.f16 == 4 && n_parts != 1) { - fprintf(stderr, "%s: GPTQ model detected - are you sure n_parts should be %d? we normally expect it to be 1\n", __func__, n_parts); - fprintf(stderr, "%s: use '--n_parts 1' if necessary\n", __func__); - } - - if (hparams.n_layer == 32) { - model.type = e_model::MODEL_7B; - } - - if (hparams.n_layer == 40) { - model.type = e_model::MODEL_13B; - } - - if (hparams.n_layer == 60) { - model.type = e_model::MODEL_30B; - } - - if (hparams.n_layer == 80) { - model.type = e_model::MODEL_65B; - } - - fprintf(stderr, "%s: n_vocab = %d\n", __func__, hparams.n_vocab); - fprintf(stderr, "%s: n_ctx = %d\n", __func__, hparams.n_ctx); - fprintf(stderr, "%s: n_embd = %d\n", __func__, hparams.n_embd); - fprintf(stderr, "%s: n_mult = %d\n", __func__, hparams.n_mult); - fprintf(stderr, "%s: n_head = %d\n", __func__, hparams.n_head); - fprintf(stderr, "%s: n_layer = %d\n", __func__, hparams.n_layer); - fprintf(stderr, "%s: n_rot = %d\n", __func__, hparams.n_rot); - fprintf(stderr, "%s: f16 = %d\n", __func__, hparams.f16); - fprintf(stderr, "%s: n_ff = %d\n", __func__, n_ff); - fprintf(stderr, "%s: n_parts = %d\n", __func__, n_parts); - fprintf(stderr, "%s: type = %d\n", __func__, model.type); - } - - // load vocab - { - std::string word; - vocab.id_to_token.resize(model.hparams.n_vocab); - std::vector tmp(64); - - for (int i = 0; i < model.hparams.n_vocab; i++) { - uint32_t len; - fin.read((char *) &len, sizeof(len)); - - word.resize(len); - if (len > 0) { - tmp.resize(len); - fin.read(tmp.data(), len); - word.assign(tmp.data(), len); - } else { - word.clear(); - } - - float score; - fin.read((char *) &score, sizeof(score)); - - vocab.token_to_id[word] = i; - - auto &tok_score = vocab.id_to_token[i]; - tok_score.tok = word; - tok_score.score = score; - } - } - - if (vocab_only) { - return true; - } - - // for the big tensors, we have the option to store the data in 16-bit floats or quantized - // in order to save memory and also to speed up the computation - // wtype is for per-layer weights, while vtype is for other weights - ggml_type wtype, vtype; - switch (model.hparams.f16) { - case 0: wtype = vtype = GGML_TYPE_F32; break; - case 1: wtype = vtype = GGML_TYPE_F16; break; - case 2: wtype = vtype = GGML_TYPE_Q4_0; break; - case 3: wtype = vtype = GGML_TYPE_Q4_1; break; - case 4: wtype = GGML_TYPE_Q4_1; vtype = GGML_TYPE_F16; break; - default: - { - fprintf(stderr, "%s: invalid model file '%s' (bad f16 value %d)\n", - __func__, fname.c_str(), model.hparams.f16); - return false; - } - } - - auto & ctx = model.ctx; - - size_t ctx_size = 0; - - { - const auto & hparams = model.hparams; - - const int n_embd = hparams.n_embd; - const int n_layer = hparams.n_layer; - const int n_ctx = hparams.n_ctx; - const int n_vocab = hparams.n_vocab; - - ctx_size += n_embd*n_vocab*ggml_type_sizef(vtype); // tok_embeddings - - ctx_size += n_embd*ggml_type_sizef(GGML_TYPE_F32); // norm - - ctx_size += n_embd*n_vocab*ggml_type_sizef(vtype); // output - - ctx_size += n_layer*(n_embd*ggml_type_sizef(GGML_TYPE_F32)); // attention_norm - - ctx_size += n_layer*(n_embd*n_embd*ggml_type_sizef(wtype)); // wq - ctx_size += n_layer*(n_embd*n_embd*ggml_type_sizef(wtype)); // wk - ctx_size += n_layer*(n_embd*n_embd*ggml_type_sizef(wtype)); // wv - ctx_size += n_layer*(n_embd*n_embd*ggml_type_sizef(wtype)); // wo - - ctx_size += n_layer*(n_embd*ggml_type_sizef(GGML_TYPE_F32)); // ffn_norm - - ctx_size += n_layer*(n_ff*n_embd*ggml_type_sizef(wtype)); // w1 - ctx_size += n_layer*(n_ff*n_embd*ggml_type_sizef(wtype)); // w2 - ctx_size += n_layer*(n_ff*n_embd*ggml_type_sizef(wtype)); // w3 - - ctx_size += n_ctx*n_layer*n_embd*ggml_type_sizef(memory_type); // memory_k - ctx_size += n_ctx*n_layer*n_embd*ggml_type_sizef(memory_type); // memory_v - - ctx_size += (5 + 10*n_layer)*256; // object overhead - - fprintf(stderr, "%s: ggml ctx size = %6.2f MB\n", __func__, ctx_size/(1024.0*1024.0)); - } - - // print memory requirements - { - const size_t scale = memory_type == GGML_TYPE_F32 ? 2 : 1; - - // this is the total memory required to run the inference - const size_t mem_required = - ctx_size + - MEM_REQ_SCRATCH0.at(model.type) + - MEM_REQ_SCRATCH1.at(model.type) + - MEM_REQ_EVAL.at (model.type); - - // this is the memory required by one llama_state - const size_t mem_required_state = - scale*MEM_REQ_KV_SELF.at(model.type); - - fprintf(stderr, "%s: mem required = %7.2f MB (+ %7.2f MB per state)\n", __func__, - mem_required / 1024.0 / 1024.0, mem_required_state / 1024.0 / 1024.0); - } - - // create the ggml context - { - lctx.model.buf.resize(ctx_size); - - struct ggml_init_params params = { - /*.mem_size =*/ lctx.model.buf.size(), - /*.mem_buffer =*/ lctx.model.buf.data(), - }; - - model.ctx = ggml_init(params); - if (!model.ctx) { - fprintf(stderr, "%s: ggml_init() failed\n", __func__); - return false; - } - } - - // prepare memory for the weights - { - const auto & hparams = model.hparams; - - const int n_embd = hparams.n_embd; - const int n_layer = hparams.n_layer; - const int n_vocab = hparams.n_vocab; - - model.layers.resize(n_layer); - - model.tok_embeddings = ggml_new_tensor_2d(ctx, vtype, n_embd, n_vocab); - - model.norm = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, n_embd); - model.output = ggml_new_tensor_2d(ctx, vtype, n_embd, n_vocab); - - // map by name - model.tensors["tok_embeddings.weight"] = model.tok_embeddings; - - model.tensors["norm.weight"] = model.norm; - model.tensors["output.weight"] = model.output; - - for (int i = 0; i < n_layer; ++i) { - auto & layer = model.layers[i]; - - layer.attention_norm = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, n_embd); - - layer.wq = ggml_new_tensor_2d(ctx, wtype, n_embd, n_embd); - layer.wk = ggml_new_tensor_2d(ctx, wtype, n_embd, n_embd); - layer.wv = ggml_new_tensor_2d(ctx, wtype, n_embd, n_embd); - layer.wo = ggml_new_tensor_2d(ctx, wtype, n_embd, n_embd); - - layer.ffn_norm = ggml_new_tensor_1d(ctx, GGML_TYPE_F32, n_embd); - - layer.w1 = ggml_new_tensor_2d(ctx, wtype, n_embd, n_ff); - layer.w2 = ggml_new_tensor_2d(ctx, wtype, n_ff, n_embd); - layer.w3 = ggml_new_tensor_2d(ctx, wtype, n_embd, n_ff); - - // map by name - model.tensors["layers." + std::to_string(i) + ".attention_norm.weight"] = layer.attention_norm; - - model.tensors["layers." + std::to_string(i) + ".attention.wq.weight"] = layer.wq; - model.tensors["layers." + std::to_string(i) + ".attention.wk.weight"] = layer.wk; - model.tensors["layers." + std::to_string(i) + ".attention.wv.weight"] = layer.wv; - model.tensors["layers." + std::to_string(i) + ".attention.wo.weight"] = layer.wo; - - model.tensors["layers." + std::to_string(i) + ".ffn_norm.weight"] = layer.ffn_norm; - - model.tensors["layers." + std::to_string(i) + ".feed_forward.w1.weight"] = layer.w1; - model.tensors["layers." + std::to_string(i) + ".feed_forward.w2.weight"] = layer.w2; - model.tensors["layers." + std::to_string(i) + ".feed_forward.w3.weight"] = layer.w3; - } - } - - const size_t file_offset = fin.tellg(); - - fin.close(); - - std::vector tmp; - - if (progress_callback) { - progress_callback(0.0, progress_callback_user_data); - } - - for (int i = 0; i < n_parts; ++i) { - const int part_id = i; - //const int part_id = n_parts - i - 1; - - std::string fname_part = fname; - if (i > 0) { - fname_part += "." + std::to_string(i); - } - - fprintf(stderr, "%s: loading model part %d/%d from '%s'\n", __func__, i+1, n_parts, fname_part.c_str()); - - fin = std::ifstream(fname_part, std::ios::binary); - fin.rdbuf()->pubsetbuf(f_buf.data(), f_buf.size()); - - fin.seekg(0, fin.end); - const size_t file_size = fin.tellg(); - - fin.seekg(file_offset); - - // load weights - { - size_t total_size = 0; - - model.n_loaded = 0; - - fprintf(stderr, "%s: ", __func__); - - while (true) { - int32_t n_dims; - int32_t length; - int32_t ftype; - - fin.read(reinterpret_cast(&n_dims), sizeof(n_dims)); - fin.read(reinterpret_cast(&length), sizeof(length)); - fin.read(reinterpret_cast(&ftype), sizeof(ftype)); - - if (fin.eof()) { - break; - } - - int32_t nelements = 1; - int32_t ne[2] = { 1, 1 }; - for (int i = 0; i < n_dims; ++i) { - fin.read(reinterpret_cast(&ne[i]), sizeof(ne[i])); - nelements *= ne[i]; - } - - std::string name(length, 0); - fin.read(&name[0], length); - - if (model.tensors.find(name.data()) == model.tensors.end()) { - fprintf(stderr, "%s: unknown tensor '%s' in model file\n", __func__, name.data()); - return false; - } - - // split_type = 0: split by columns - // split_type = 1: split by rows - int split_type = 0; - - // split_type = 0: - // regex: - // - tok_embeddings.* - // - layers.*.attention.wo.weight - // - layers.*.feed_forward.w2.weight - - // split_type = 1: - // regex: - // - output.* - // - layers.*.attention.wq.weight - // - layers.*.attention.wk.weight - // - layers.*.attention.wv.weight - // - layers.*.feed_forward.w1.weight - // - layers.*.feed_forward.w3.weight - if (name.find("tok_embeddings") != std::string::npos) { - split_type = 0; - } else if (name.find("layers") != std::string::npos) { - if (name.find("attention.wo.weight") != std::string::npos) { - split_type = 0; - } else if (name.find("feed_forward.w2.weight") != std::string::npos) { - split_type = 0; - } else { - split_type = 1; - } - } else if (name.find("output") != std::string::npos) { - split_type = 1; - } - - auto tensor = model.tensors[name.data()]; - - if (n_dims == 1) { - if (ggml_nelements(tensor) != nelements) { - fprintf(stderr, "%s: tensor '%s' has wrong size in model file\n", __func__, name.data()); - return false; - } - } else { - if (ggml_nelements(tensor)/n_parts != nelements) { - fprintf(stderr, "%s: tensor '%s' has wrong size in model file\n", __func__, name.data()); - return false; - } - } - - if (n_dims == 1) { - if (tensor->ne[0] != ne[0] || tensor->ne[1] != ne[1]) { - fprintf(stderr, "%s: tensor '%s' has wrong shape in model file: got [%d, %d], expected [%d, %d]\n", - __func__, name.data(), tensor->ne[0], tensor->ne[1], ne[0], ne[1]); - return false; - } - } else { - if (split_type == 0) { - if (tensor->ne[0]/n_parts != ne[0] || tensor->ne[1] != ne[1]) { - fprintf(stderr, "%s: tensor '%s' has wrong shape in model file: got [%d, %d], expected [%d, %d]\n", - __func__, name.data(), tensor->ne[0]/n_parts, tensor->ne[1], ne[0], ne[1]); - return false; - } - } else { - if (tensor->ne[0] != ne[0] || tensor->ne[1]/n_parts != ne[1]) { - fprintf(stderr, "%s: tensor '%s' has wrong shape in model file: got [%d, %d], expected [%d, %d]\n", - __func__, name.data(), tensor->ne[0], tensor->ne[1]/n_parts, ne[0], ne[1]); - return false; - } - } - } - - if (0) { - static const char * ftype_str[] = { "f32", "f16", "q4_0", "q4_1", }; - fprintf(stderr, "%24s - [%5d, %5d], type = %6s, split = %d\n", name.data(), ne[0], ne[1], ftype_str[ftype], split_type); - } - - size_t bpe = 0; - - switch (ftype) { - case 0: bpe = ggml_type_size(GGML_TYPE_F32); break; - case 1: bpe = ggml_type_size(GGML_TYPE_F16); break; - case 2: bpe = ggml_type_size(GGML_TYPE_Q4_0); assert(ne[0] % 64 == 0); break; - case 3: bpe = ggml_type_size(GGML_TYPE_Q4_1); assert(ne[0] % 64 == 0); break; - default: - { - fprintf(stderr, "%s: unknown ftype %d in model file\n", __func__, ftype); - return false; - } - }; - - if (n_dims == 1 || n_parts == 1) { - if ((nelements*bpe)/ggml_blck_size(tensor->type) != ggml_nbytes(tensor)) { - fprintf(stderr, "%s: tensor '%s' has wrong size in model file: got %zu, expected %zu\n", - __func__, name.data(), ggml_nbytes(tensor), nelements*bpe); - return false; - } - - if (part_id == 0) { - fin.read(reinterpret_cast(tensor->data), ggml_nbytes(tensor)); - } else { - fin.seekg(ggml_nbytes(tensor), std::ios::cur); - } - - total_size += ggml_nbytes(tensor); - } else { - if ((nelements*bpe)/ggml_blck_size(tensor->type) != ggml_nbytes(tensor)/n_parts) { - fprintf(stderr, "%s: tensor '%s' has wrong size in model file: got %zu, expected %zu\n", - __func__, name.data(), ggml_nbytes(tensor)/n_parts, nelements*bpe); - return false; - } - - if (split_type == 0) { - const int np0 = ne[0]; - - const size_t row_size = (tensor->ne[0]/ggml_blck_size(tensor->type))*ggml_type_size(tensor->type); - assert(row_size == tensor->nb[1]); - - for (int i1 = 0; i1 < ne[1]; ++i1) { - const size_t offset_row = i1*row_size; - const size_t offset = offset_row + ((part_id*np0)/ggml_blck_size(tensor->type))*ggml_type_size(tensor->type); - fin.read(reinterpret_cast(tensor->data) + offset, row_size/n_parts); - } - } else { - const int np1 = ne[1]; - - const size_t row_size = (tensor->ne[0]/ggml_blck_size(tensor->type))*ggml_type_size(tensor->type); - - for (int i1 = 0; i1 < ne[1]; ++i1) { - const size_t offset_row = (i1 + part_id*np1)*row_size; - fin.read(reinterpret_cast(tensor->data) + offset_row, row_size); - } - } - - total_size += ggml_nbytes(tensor)/n_parts; - } - - //fprintf(stderr, "%42s - [%5d, %5d], type = %6s, %6.2f MB\n", name.data(), ne[0], ne[1], ftype == 0 ? "float" : "f16", ggml_nbytes(tensor)/1024.0/1024.0); - model.n_loaded++; - - // progress - if (progress_callback) { - float current_file_progress = float(size_t(fin.tellg()) - file_offset) / float(file_size - file_offset); - float current_progress = (float(i) + current_file_progress) / float(n_parts); - progress_callback(current_progress, progress_callback_user_data); - } - if (model.n_loaded % 8 == 0) { - fprintf(stderr, "."); - fflush(stderr); - } - } - - fprintf(stderr, " done\n"); - - fprintf(stderr, "%s: model size = %8.2f MB / num tensors = %d\n", __func__, total_size/1024.0/1024.0, model.n_loaded); - if (model.n_loaded == 0) { - fprintf(stderr, "%s: WARN no tensors loaded from model file - assuming empty model for testing\n", __func__); - } else if (model.n_loaded != (int) model.tensors.size()) { - fprintf(stderr, "%s: ERROR not all tensors loaded from model file - expected %zu, got %d\n", __func__, model.tensors.size(), model.n_loaded); - return false; - } - } - - fin.close(); - } - - lctx.t_load_us = ggml_time_us() - t_start_us; - - if (progress_callback) { - progress_callback(1.0, progress_callback_user_data); - } - - return true; -} - -// evaluate the transformer -// -// - lctx: llama context -// - tokens: new batch of tokens to process -// - n_past: the context size so far -// - n_threads: number of threads to use -// -static bool llama_eval_internal( - llama_context & lctx, - const llama_token * tokens, - const int n_tokens, - const int n_past, - const int n_threads) { - const int64_t t_start_us = ggml_time_us(); - - const int N = n_tokens; - - const auto & model = lctx.model; - const auto & hparams = model.hparams; - - auto & kv_self = model.kv_self; - - LLAMA_ASSERT(!!kv_self.ctx); - - const int n_embd = hparams.n_embd; - const int n_layer = hparams.n_layer; - const int n_ctx = hparams.n_ctx; - const int n_head = hparams.n_head; - const int n_vocab = hparams.n_vocab; - const int n_rot = hparams.n_embd/hparams.n_head; - - auto & mem_per_token = lctx.mem_per_token; - auto & buf_compute = lctx.buf_compute; - - struct ggml_init_params params = { - /*.mem_size =*/ buf_compute.size(), - /*.mem_buffer =*/ buf_compute.data(), - }; - - struct ggml_context * ctx0 = ggml_init(params); - - // for big prompts, if BLAS is enabled, it is better to use only one thread - // otherwise, the threads are spin-lock waiting for the BLAS calls and are degrading the performance - ggml_cgraph gf = {}; - gf.n_threads = N >= 32 && ggml_cpu_has_blas() ? 1 : n_threads; - - struct ggml_tensor * embd = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, N); - memcpy(embd->data, tokens, N*ggml_element_size(embd)); - - struct ggml_tensor * inpL = ggml_get_rows(ctx0, model.tok_embeddings, embd); - - for (int il = 0; il < n_layer; ++il) { - struct ggml_tensor * inpSA = inpL; - - struct ggml_tensor * cur; - - lctx.use_buf(ctx0, 0); - - // norm - { - cur = ggml_rms_norm(ctx0, inpL); - - // cur = attention_norm*cur - cur = ggml_mul(ctx0, - ggml_repeat(ctx0, model.layers[il].attention_norm, cur), - cur); - } - - // self-attention - { - struct ggml_tensor * Qcur = ggml_mul_mat(ctx0, model.layers[il].wq, cur); - struct ggml_tensor * Kcur = ggml_mul_mat(ctx0, model.layers[il].wk, cur); - struct ggml_tensor * Vcur = ggml_mul_mat(ctx0, model.layers[il].wv, cur); - - // store key and value to memory - if (N >= 1) { - struct ggml_tensor * k = ggml_view_1d(ctx0, kv_self.k, N*n_embd, (ggml_element_size(kv_self.k)*n_embd)*(il*n_ctx + n_past)); - struct ggml_tensor * v = ggml_view_1d(ctx0, kv_self.v, N*n_embd, (ggml_element_size(kv_self.v)*n_embd)*(il*n_ctx + n_past)); - - ggml_build_forward_expand(&gf, ggml_cpy(ctx0, Kcur, k)); - ggml_build_forward_expand(&gf, ggml_cpy(ctx0, Vcur, v)); - } - - // Q = Qcur.contiguous().view(n_embd/n_head, n_head, N).permute(0, 2, 1, 3) - struct ggml_tensor * Q = - ggml_permute(ctx0, - ggml_rope(ctx0, - ggml_cpy(ctx0, - Qcur, - ggml_new_tensor_3d(ctx0, GGML_TYPE_F32, n_embd/n_head, n_head, N)), - n_past, n_rot, 0), - 0, 2, 1, 3); - - // K = Kmem.view(n_embd/n_head, n_head, n_past + N).permute(0, 2, 1, 3) - struct ggml_tensor * K = - ggml_permute(ctx0, - ggml_rope(ctx0, - ggml_reshape_3d(ctx0, - ggml_view_1d(ctx0, kv_self.k, (n_past + N)*n_embd, il*n_ctx*ggml_element_size(kv_self.k)*n_embd), - n_embd/n_head, n_head, n_past + N), - n_past, n_rot, 1), - 0, 2, 1, 3); - - // K * Q - struct ggml_tensor * KQ = ggml_mul_mat(ctx0, K, Q); - - // KQ_scaled = KQ / sqrt(n_embd/n_head) - struct ggml_tensor * KQ_scaled = - ggml_scale(ctx0, - KQ, - ggml_new_f32(ctx0, 1.0f/sqrtf(float(n_embd)/n_head))); - - // KQ_masked = mask_past(KQ_scaled) - struct ggml_tensor * KQ_masked = ggml_diag_mask_inf(ctx0, KQ_scaled, n_past); - - // KQ = soft_max(KQ_masked) - struct ggml_tensor * KQ_soft_max = ggml_soft_max(ctx0, KQ_masked); - - // V_trans = Vmem.view(n_embd/n_head, n_head, n_past + N).permute(1, 2, 0, 3).contiguous() - struct ggml_tensor * V_trans = - ggml_cpy(ctx0, - ggml_permute(ctx0, - ggml_reshape_3d(ctx0, - ggml_view_1d(ctx0, kv_self.v, (n_past + N)*n_embd, il*n_ctx*ggml_element_size(kv_self.v)*n_embd), - n_embd/n_head, n_head, n_past + N), - 1, 2, 0, 3), - ggml_new_tensor_3d(ctx0, kv_self.v->type, n_past + N, n_embd/n_head, n_head)); - - // KQV = transpose(V) * KQ_soft_max - struct ggml_tensor * KQV = ggml_mul_mat(ctx0, V_trans, KQ_soft_max); - - // KQV_merged = KQV.permute(0, 2, 1, 3) - struct ggml_tensor * KQV_merged = ggml_permute(ctx0, KQV, 0, 2, 1, 3); - - // cur = KQV_merged.contiguous().view(n_embd, N) - cur = ggml_cpy(ctx0, - KQV_merged, - ggml_new_tensor_2d(ctx0, GGML_TYPE_F32, n_embd, N)); - - // projection (no bias) - cur = ggml_mul_mat(ctx0, - model.layers[il].wo, - cur); - } - - lctx.use_buf(ctx0, 1); - - struct ggml_tensor * inpFF = ggml_add(ctx0, cur, inpSA); - - // feed-forward network - { - // norm - { - cur = ggml_rms_norm(ctx0, inpFF); - - // cur = ffn_norm*cur - cur = ggml_mul(ctx0, - ggml_repeat(ctx0, model.layers[il].ffn_norm, cur), - cur); - } - - struct ggml_tensor * tmp = ggml_mul_mat(ctx0, - model.layers[il].w3, - cur); - - cur = ggml_mul_mat(ctx0, - model.layers[il].w1, - cur); - - // SILU activation - cur = ggml_silu(ctx0, cur); - - cur = ggml_mul(ctx0, cur, tmp); - - cur = ggml_mul_mat(ctx0, - model.layers[il].w2, - cur); - } - - cur = ggml_add(ctx0, cur, inpFF); - - // input for next layer - inpL = cur; - } - - lctx.use_buf(ctx0, 0); - - // used at the end to optionally extract the embeddings - struct ggml_tensor * embeddings = NULL; - - // norm - { - - inpL = ggml_rms_norm(ctx0, inpL); - - // inpL = norm*inpL - inpL = ggml_mul(ctx0, - ggml_repeat(ctx0, model.norm, inpL), - inpL); - - embeddings = inpL; - } - - // lm_head - inpL = ggml_mul_mat(ctx0, model.output, inpL); - - lctx.use_buf(ctx0, -1); - - // logits -> probs - //inpL = ggml_soft_max(ctx0, inpL); - - // run the computation - ggml_build_forward_expand(&gf, inpL); - ggml_graph_compute (ctx0, &gf); - - //if (n_past%100 == 0) { - // ggml_graph_print (&gf); - // ggml_graph_dump_dot(&gf, NULL, "gpt-2.dot"); - //} - - //embd_w.resize(n_vocab*N); - //memcpy(embd_w.data(), ggml_get_data(inpL), sizeof(float)*n_vocab*N); - - // extract logits - { - auto & logits_out = lctx.logits; - - if (lctx.logits_all) { - logits_out.resize(n_vocab * N); - memcpy(logits_out.data(), (float *) ggml_get_data(inpL), sizeof(float)*n_vocab*N); - } else { - // return result for just the last token - logits_out.resize(n_vocab); - memcpy(logits_out.data(), (float *) ggml_get_data(inpL) + (n_vocab*(N-1)), sizeof(float)*n_vocab); - } - } - - // extract embeddings - if (lctx.embedding.size()) { - auto & embedding_out = lctx.embedding; - - embedding_out.resize(n_embd); - memcpy(embedding_out.data(), (float *) ggml_get_data(embeddings) + (n_embd*(N - 1)), sizeof(float)*n_embd); - } - - if (mem_per_token == 0) { - mem_per_token = ggml_used_mem(ctx0)/N; - } - -#if 0 - printf("\n%s: used_mem = %.3f MB, scratch -- %.3f MB %.3f MB\n", __func__, - ggml_used_mem(ctx0)/1024.0/1024.0, - lctx.get_buf_max_mem(0)/1024.0/1024.0, - lctx.get_buf_max_mem(1)/1024.0/1024.0); -#endif - - ggml_free(ctx0); - - // measure the performance only for the single-token evals - if (N == 1) { - lctx.t_eval_us += ggml_time_us() - t_start_us; - lctx.n_eval++; - } - else if (N > 1) { - lctx.t_p_eval_us += ggml_time_us() - t_start_us; - lctx.n_p_eval += N; - } - - return true; -} - -// -// tokenizer -// - -static size_t utf8_len(char src) { - const size_t lookup[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4 }; - uint8_t highbits = static_cast(src) >> 4; - return lookup[highbits]; -} - -struct llama_sp_symbol { - using index = int; - index prev; - index next; - const char * text; - size_t n; -}; - -struct llama_sp_bigram { - struct comparator { - bool operator()(llama_sp_bigram & l, llama_sp_bigram & r) { - return (l.score < r.score) || (l.score == r.score && l.left > r.left); - } - }; - using queue_storage = std::vector; - using queue = std::priority_queue; - llama_sp_symbol::index left; - llama_sp_symbol::index right; - float score; - size_t size; -}; - -// original implementation: -// https://github.com/ggerganov/llama.cpp/commit/074bea2eb1f1349a0118239c4152914aecaa1be4 -struct llama_tokenizer { - llama_tokenizer(const llama_vocab & vocab): vocab_(vocab) {} - - void tokenize(const std::string & text, std::vector & output) { - // split string into utf8 chars - int index = 0; - size_t offs = 0; - while (offs < text.size()) { - llama_sp_symbol sym; - size_t char_len = std::min(text.size() - offs, utf8_len(text[offs])); - sym.text = text.c_str() + offs; - sym.n = char_len; - offs += char_len; - sym.prev = index - 1; - sym.next = offs == text.size() ? -1 : index + 1; - index++; - symbols_.emplace_back(std::move(sym)); - } - - // seed the work queue with all possible 2-character tokens. - for (size_t i = 1; i < symbols_.size(); ++i) { - try_add_bigram(i - 1, i); - } - - // keep substituting the highest frequency pairs for as long as we can. - while (!work_queue_.empty()) { - auto bigram = work_queue_.top(); - work_queue_.pop(); - - auto & left_sym = symbols_[bigram.left]; - auto & right_sym = symbols_[bigram.right]; - - // if one of the symbols already got merged, skip it. - if (left_sym.n == 0 || right_sym.n == 0 || - left_sym.n + right_sym.n != bigram.size) { - continue; - } - - // merge the right sym into the left one - left_sym.n += right_sym.n; - right_sym.n = 0; - - //printf("left = '%*s' size = %zu\n", (int) left_sym.n, left_sym.text, bigram.size); - - // remove the right sym from the chain - left_sym.next = right_sym.next; - if (right_sym.next >= 0) { - symbols_[right_sym.next].prev = bigram.left; - } - - // find more substitutions - try_add_bigram(left_sym.prev, bigram.left); - try_add_bigram(bigram.left, left_sym.next); - } - - for (int i = 0; i != -1; i = symbols_[i].next) { - auto & symbol = symbols_[i]; - auto token = vocab_.token_to_id.find(std::string(symbol.text, symbol.n)); - - if (token == vocab_.token_to_id.end()) { - // output any symbols that did not form tokens as bytes. - for (int j = 0; j < (int) symbol.n; ++j) { - llama_vocab::id token_id = static_cast(symbol.text[j]) + 3; - output.push_back(token_id); - } - } else { - output.push_back((*token).second); - } - } - } - -private: - void try_add_bigram(int left, int right) { - if (left == -1 || right == -1) { - return; - } - - const std::string text = std::string(symbols_[left].text, symbols_[left].n + symbols_[right].n); - auto token = vocab_.token_to_id.find(text); - - if (token == vocab_.token_to_id.end()) { - return; - } - - if (static_cast((*token).second) >= vocab_.id_to_token.size()) { - return; - } - - const auto &tok_score = vocab_.id_to_token[(*token).second]; - - llama_sp_bigram bigram; - bigram.left = left; - bigram.right = right; - bigram.score = tok_score.score; - bigram.size = text.size(); - work_queue_.push(bigram); - } - - const llama_vocab & vocab_; - std::vector symbols_; - llama_sp_bigram::queue work_queue_; -}; - -static std::vector llama_tokenize(const llama_vocab & vocab, const std::string & text, bool bos) { - llama_tokenizer tokenizer(vocab); - std::vector output; - - if (text.size() == 0) { - return output; - } - - if (bos) { - output.push_back(1); - } - - tokenizer.tokenize(text, output); - return output; -} - -// -// sampling -// - -static void sample_top_k(std::vector> & logits_id, int top_k) { - // find the top k tokens - std::partial_sort( - logits_id.begin(), - logits_id.begin() + top_k, logits_id.end(), - [](const std::pair & a, const std::pair & b) { - return a.first > b.first; - }); - - logits_id.resize(top_k); -} - -static llama_vocab::id llama_sample_top_p_top_k( - llama_context & lctx, - const std::vector & last_n_tokens, - int top_k, - float top_p, - float temp, - float repeat_penalty) { - auto & rng = lctx.rng; - - const int n_logits = lctx.model.hparams.n_vocab; - - const auto & logits = lctx.logits; - const auto * plogits = logits.data() + logits.size() - n_logits; - - std::vector> logits_id; - logits_id.reserve(n_logits); - - { - const float scale = 1.0f/temp; - for (int i = 0; i < n_logits; ++i) { - // repetition penalty from ctrl paper (https://arxiv.org/abs/1909.05858) - // credit https://github.com/facebookresearch/llama/compare/main...shawwn:llama:main - if (std::find(last_n_tokens.begin(), last_n_tokens.end(), i) != last_n_tokens.end()) { - // if score < 0 then repetition penalty has to multiplied to reduce the previous token probability - if (plogits[i] < 0.0f) { - logits_id.push_back(std::make_pair(plogits[i]*scale*repeat_penalty, i)); - } else { - logits_id.push_back(std::make_pair(plogits[i]*scale/repeat_penalty, i)); - } - } else { - logits_id.push_back(std::make_pair(plogits[i]*scale, i)); - } - } - } - - sample_top_k(logits_id, top_k); - - float maxl = -std::numeric_limits::infinity(); - for (const auto & kv : logits_id) { - maxl = std::max(maxl, kv.first); - } - - // compute probs for the top k tokens - std::vector probs; - probs.reserve(logits_id.size()); - - double sum = 0.0; - for (const auto & kv : logits_id) { - const float p = expf(kv.first - maxl); - probs.push_back(p); - sum += p; - } - - // normalize the probs - for (auto & p : probs) { - p /= sum; - } - - if (top_p < 1.0) { - double cumsum = 0.0; - for (int i = 0; i < (int) probs.size(); i++) { - cumsum += probs[i]; - if (cumsum >= top_p) { - probs.resize(i + 1); - logits_id.resize(i + 1); - break; - } - } - - cumsum = 1.0/cumsum; - for (int i = 0; i < (int) probs.size(); i++) { - probs[i] *= cumsum; - } - } - - //printf("\n"); - //for (int i = 0; i < (int) 10; i++) { - // printf("%d: '%s' %f\n", i, vocab.id_to_token.at(logits_id[i].second).c_str(), probs[i]); - //} - //printf("\n\n"); - //exit(0); - - std::discrete_distribution<> dist(probs.begin(), probs.end()); - int idx = dist(rng); - - return logits_id[idx].second; -} - -// -// quantization -// - -// TODO: reuse code from the llama_model_load() somehow -static bool llama_model_quantize_internal(const std::string & fname_inp, const std::string & fname_out, int itype) { - ggml_type type = GGML_TYPE_Q4_1; - - switch (itype) { - case 2: type = GGML_TYPE_Q4_0; break; - case 3: type = GGML_TYPE_Q4_1; break; - default: fprintf(stderr, "%s: invalid quantization type %d\n", __func__, itype); return 1; - }; - - if (type != GGML_TYPE_Q4_0 && type != GGML_TYPE_Q4_1) { - fprintf(stderr, "%s: invalid quantization type %d\n", __func__, type); - return false; - } - - llama_vocab vocab; - - printf("%s: loading model from '%s'\n", __func__, fname_inp.c_str()); - - auto finp = std::ifstream(fname_inp, std::ios::binary); - if (!finp) { - fprintf(stderr, "%s: failed to open '%s' for reading\n", __func__, fname_inp.c_str()); - return false; - } - - auto fout = std::ofstream(fname_out, std::ios::binary); - if (!fout) { - fprintf(stderr, "%s: failed to open '%s' for writing\n", __func__, fname_out.c_str()); - return false; - } - - // verify magic - { - uint32_t magic; - finp.read((char *) &magic, sizeof(magic)); - if (magic == LLAMA_FILE_MAGIC_UNVERSIONED) { - fprintf(stderr, "%s: invalid model file '%s' (too old, regenerate your model files!)\n", - __func__, fname_inp.c_str()); - return false; - } - if (magic != LLAMA_FILE_MAGIC) { - fprintf(stderr, "%s: invalid model file '%s' (bad magic)\n", __func__, fname_inp.c_str()); - return false; - } - - fout.write((char *) &magic, sizeof(magic)); - - uint32_t format_version; - finp.read((char *) &format_version, sizeof(format_version)); - - if (format_version != LLAMA_FILE_VERSION) { - fprintf(stderr, "%s: invalid model file '%s' (unsupported format version %" PRIu32 ", expected %d)\n", - __func__, fname_inp.c_str(), format_version, LLAMA_FILE_VERSION); - return false; - } - - fout.write((char *) &format_version, sizeof(format_version)); - } - - llama_hparams hparams; - - // load hparams - { - finp.read((char *) &hparams.n_vocab, sizeof(hparams.n_vocab)); - //finp.read((char *) &hparams.n_ctx, sizeof(hparams.n_ctx)); - finp.read((char *) &hparams.n_embd, sizeof(hparams.n_embd)); - finp.read((char *) &hparams.n_mult, sizeof(hparams.n_mult)); - finp.read((char *) &hparams.n_head, sizeof(hparams.n_head)); - finp.read((char *) &hparams.n_layer, sizeof(hparams.n_layer)); - finp.read((char *) &hparams.n_rot, sizeof(hparams.n_rot)); - finp.read((char *) &hparams.f16, sizeof(hparams.f16)); - - printf("%s: n_vocab = %d\n", __func__, hparams.n_vocab); - printf("%s: n_ctx = %d\n", __func__, hparams.n_ctx); - printf("%s: n_embd = %d\n", __func__, hparams.n_embd); - printf("%s: n_mult = %d\n", __func__, hparams.n_mult); - printf("%s: n_head = %d\n", __func__, hparams.n_head); - printf("%s: n_layer = %d\n", __func__, hparams.n_layer); - printf("%s: f16 = %d\n", __func__, hparams.f16); - - fout.write((char *) &hparams.n_vocab, sizeof(hparams.n_vocab)); - //fout.write((char *) &hparams.n_ctx, sizeof(hparams.n_ctx)); - fout.write((char *) &hparams.n_embd, sizeof(hparams.n_embd)); - fout.write((char *) &hparams.n_mult, sizeof(hparams.n_mult)); - fout.write((char *) &hparams.n_head, sizeof(hparams.n_head)); - fout.write((char *) &hparams.n_layer, sizeof(hparams.n_layer)); - fout.write((char *) &hparams.n_rot, sizeof(hparams.n_rot)); - fout.write((char *) &itype, sizeof(hparams.f16)); - } - - // load vocab - { - const int32_t n_vocab = hparams.n_vocab; - - if (n_vocab != hparams.n_vocab) { - fprintf(stderr, "%s: invalid model file '%s' (bad vocab size %d != %d)\n", - __func__, fname_inp.c_str(), n_vocab, hparams.n_vocab); - return false; - } - - std::vector word(32); - vocab.id_to_token.resize(n_vocab); - for (int i = 0; i < n_vocab; i++) { - uint32_t len; - finp.read ((char *) &len, sizeof(len)); - fout.write((char *) &len, sizeof(len)); - - word.resize(len); - finp.read ((char *) word.data(), len); - fout.write((char *) word.data(), len); - - float score; - finp.read ((char *) &score, sizeof(score)); - fout.write((char *) &score, sizeof(score)); - - vocab.token_to_id[word.data()] = i; - - auto &tok_score = vocab.id_to_token[i]; - tok_score.tok = word.data(); - tok_score.score = score; - } - } - - // load weights - { - size_t total_size_org = 0; - size_t total_size_new = 0; - - std::vector work; - - std::vector data_u8; - std::vector data_f16; - std::vector data_f32; - - std::vector hist_all(1 << 4, 0); - - while (true) { - int32_t n_dims; - int32_t length; - int32_t ftype; - - finp.read(reinterpret_cast(&n_dims), sizeof(n_dims)); - finp.read(reinterpret_cast(&length), sizeof(length)); - finp.read(reinterpret_cast(&ftype), sizeof(ftype)); - - if (finp.eof()) { - break; - } - - int32_t nelements = 1; - int32_t ne[2] = { 1, 1 }; - for (int i = 0; i < n_dims; ++i) { - finp.read (reinterpret_cast(&ne[i]), sizeof(ne[i])); - nelements *= ne[i]; - } - - std::string name(length, 0); - finp.read (&name[0], length); - - { - static const char * ftype_str[] = { "f32", "f16", "q4_0", "q4_1", }; - printf("%48s - [%5d, %5d], type = %6s ", name.data(), ne[0], ne[1], ftype_str[ftype]); - } - - // regexes of tensor names to be quantized - const std::vector k_names = { - ".*weight", - }; - - bool quantize = false; - for (const auto & s : k_names) { - if (std::regex_match(name, std::regex(s))) { - quantize = true; - break; - } - } - - // quantize only 2D tensors - quantize &= (n_dims == 2); - - if (quantize) { - if (ftype != 0 && ftype != 1) { - fprintf(stderr, "%s: unsupported ftype %d for integer quantization\n", __func__, ftype); - return false; - } - - if (ftype == 1) { - data_f16.resize(nelements); - finp.read(reinterpret_cast(data_f16.data()), nelements * sizeof(ggml_fp16_t)); - data_f32.resize(nelements); - for (int i = 0; i < nelements; ++i) { - data_f32[i] = ggml_fp16_to_fp32(data_f16[i]); - } - } else { - data_f32.resize(nelements); - finp.read(reinterpret_cast(data_f32.data()), nelements * sizeof(float)); - } - - ftype = itype; - } else { - const int bpe = (ftype == 0) ? sizeof(float) : sizeof(uint16_t); - - data_u8.resize(nelements*bpe); - finp.read(reinterpret_cast(data_u8.data()), nelements * bpe); - } - - fout.write(reinterpret_cast(&n_dims), sizeof(n_dims)); - fout.write(reinterpret_cast(&length), sizeof(length)); - fout.write(reinterpret_cast(&ftype), sizeof(ftype)); - for (int i = 0; i < n_dims; ++i) { - fout.write(reinterpret_cast(&ne[i]), sizeof(ne[i])); - } - fout.write(&name[0], length); - - if (quantize) { - printf("quantizing .. "); - work.resize(nelements); // for quantization - - size_t cur_size = 0; - std::vector hist_cur(1 << 4, 0); - - switch (type) { - case GGML_TYPE_Q4_0: - { - cur_size = ggml_quantize_q4_0(data_f32.data(), work.data(), nelements, ne[0], hist_cur.data()); - } break; - case GGML_TYPE_Q4_1: - { - cur_size = ggml_quantize_q4_1(data_f32.data(), work.data(), nelements, ne[0], hist_cur.data()); - } break; - default: - { - fprintf(stderr, "%s: unsupported quantization type %d\n", __func__, type); - return false; - } - } - - fout.write(reinterpret_cast(work.data()), cur_size); - total_size_new += cur_size; - - printf("size = %8.2f MB -> %8.2f MB | hist: ", nelements * sizeof(float)/1024.0/1024.0, cur_size/1024.0/1024.0); - for (int i = 0; i < (int) hist_cur.size(); ++i) { - hist_all[i] += hist_cur[i]; - } - - for (int i = 0; i < (int) hist_cur.size(); ++i) { - printf("%5.3f ", hist_cur[i] / float(nelements)); - } - printf("\n"); - } else { - printf("size = %8.3f MB\n", data_u8.size()/1024.0/1024.0); - fout.write(reinterpret_cast(data_u8.data()), data_u8.size()); - total_size_new += data_u8.size(); - } - - total_size_org += nelements * sizeof(float); - } - - printf("%s: model size = %8.2f MB\n", __func__, total_size_org/1024.0/1024.0); - printf("%s: quant size = %8.2f MB\n", __func__, total_size_new/1024.0/1024.0); - - { - int64_t sum_all = 0; - for (int i = 0; i < (int) hist_all.size(); ++i) { - sum_all += hist_all[i]; - } - - printf("%s: hist: ", __func__); - for (int i = 0; i < (int) hist_all.size(); ++i) { - printf("%5.3f ", hist_all[i] / float(sum_all)); - } - printf("\n"); - } - } - - finp.close(); - fout.close(); - - return true; -} - -// -// interface implementation -// - -struct llama_context * llama_init_from_file( - const char * path_model, - struct llama_context_params params) { - ggml_time_init(); - - llama_context * ctx = new llama_context; - - if (params.seed <= 0) { - params.seed = time(NULL); - } - - ctx->rng = std::mt19937(params.seed); - ctx->logits_all = params.logits_all; - - ggml_type memory_type = params.f16_kv ? GGML_TYPE_F16 : GGML_TYPE_F32; - - if (!llama_model_load(path_model, *ctx, params.n_ctx, params.n_parts, memory_type, - params.vocab_only, params.progress_callback, - params.progress_callback_user_data)) { - fprintf(stderr, "%s: failed to load model\n", __func__); - llama_free(ctx); - return nullptr; - } - - if (params.use_mlock) { - char *err; - if (!ggml_mlock(ctx->model.ctx, &err)) { - fprintf(stderr, "%s\n", err); - free(err); - llama_free(ctx); - return nullptr; - } - } - - // reserve memory for context buffers - { - if (!kv_cache_init(ctx->model.hparams, ctx->model.kv_self, memory_type, ctx->model.hparams.n_ctx)) { - fprintf(stderr, "%s: kv_cache_init() failed for self-attention cache\n", __func__); - llama_free(ctx); - return nullptr; - } - - { - const size_t memory_size = ggml_nbytes(ctx->model.kv_self.k) + ggml_nbytes(ctx->model.kv_self.v); - fprintf(stderr, "%s: kv self size = %7.2f MB\n", __func__, memory_size / 1024.0 / 1024.0); - } - - const auto & hparams = ctx->model.hparams; - - // resized during inference - if (params.logits_all) { - ctx->logits.reserve(hparams.n_ctx*hparams.n_vocab); - } else { - ctx->logits.reserve(hparams.n_ctx); - } - - if (params.embedding){ - ctx->embedding.resize(hparams.n_embd); - } - - ctx->buf_compute.resize(MEM_REQ_EVAL.at(ctx->model.type)); - - ctx->buf_scratch[0].resize(MEM_REQ_SCRATCH0.at(ctx->model.type)); - ctx->buf_scratch[1].resize(MEM_REQ_SCRATCH1.at(ctx->model.type)); - } - - return ctx; -} - -void llama_free(struct llama_context * ctx) { - kv_cache_free(ctx->model.kv_self); - - if (ctx->model.ctx) { - ggml_free(ctx->model.ctx); - } - - delete ctx; -} - -int llama_model_quantize( - const char * fname_inp, - const char * fname_out, - int itype) { - if (!llama_model_quantize_internal(fname_inp, fname_out, itype)) { - fprintf(stderr, "%s: failed to quantize\n", __func__); - return 1; - } - - return 0; -} - -int llama_eval( - struct llama_context * ctx, - const llama_token * tokens, - int n_tokens, - int n_past, - int n_threads) { - if (!llama_eval_internal(*ctx, tokens, n_tokens, n_past, n_threads)) { - fprintf(stderr, "%s: failed to eval\n", __func__); - return 1; - } - - return 0; -} - -int llama_tokenize( - struct llama_context * ctx, - const char * text, - llama_token * tokens, - int n_max_tokens, - bool add_bos) { - auto res = llama_tokenize(ctx->vocab, text, add_bos); - - if (n_max_tokens < (int) res.size()) { - fprintf(stderr, "%s: too many tokens\n", __func__); - return -((int) res.size()); - } - - for (size_t i = 0; i < res.size(); i++) { - tokens[i] = res[i]; - } - - return res.size(); -} - -int llama_n_vocab(struct llama_context * ctx) { - return ctx->vocab.id_to_token.size(); -} - -int llama_n_ctx(struct llama_context * ctx) { - return ctx->model.hparams.n_ctx; -} - -int llama_n_embd(struct llama_context * ctx) { - return ctx->model.hparams.n_embd; -} - -float * llama_get_logits(struct llama_context * ctx) { - return ctx->logits.data(); -} - -float * llama_get_embeddings(struct llama_context * ctx) { - return ctx->embedding.data(); -} - -const char * llama_token_to_str(struct llama_context * ctx, llama_token token) { - if (token >= llama_n_vocab(ctx)) { - return nullptr; - } - - return ctx->vocab.id_to_token[token].tok.c_str(); -} - -llama_token llama_token_bos() { - return 1; -} - -llama_token llama_token_eos() { - return 2; -} - -llama_token llama_sample_top_p_top_k( - llama_context * ctx, - const llama_token * last_n_tokens_data, - int last_n_tokens_size, - int top_k, - float top_p, - float temp, - float repeat_penalty) { - const int64_t t_start_sample_us = ggml_time_us(); - - llama_token result = 0; - - // TODO: avoid this ... - const auto last_n_tokens = std::vector(last_n_tokens_data, last_n_tokens_data + last_n_tokens_size); - - result = llama_sample_top_p_top_k( - *ctx, - last_n_tokens, - top_k, - top_p, - temp, - repeat_penalty); - - ctx->t_sample_us += ggml_time_us() - t_start_sample_us; - ctx->n_sample++; - - return result; -} - - -void llama_print_timings(struct llama_context * ctx) { - const int64_t t_end_us = ggml_time_us(); - - const int32_t n_sample = std::max(1, ctx->n_sample); - const int32_t n_eval = std::max(1, ctx->n_eval); - const int32_t n_p_eval = std::max(1, ctx->n_p_eval); - - fprintf(stderr, "\n"); - fprintf(stderr, "%s: load time = %8.2f ms\n", __func__, ctx->t_load_us / 1000.0); - fprintf(stderr, "%s: sample time = %8.2f ms / %5d runs (%8.2f ms per run)\n", __func__, 1e-3 * ctx->t_sample_us, n_sample, 1e-3 * ctx->t_sample_us / n_sample); - fprintf(stderr, "%s: prompt eval time = %8.2f ms / %5d tokens (%8.2f ms per token)\n", __func__, 1e-3 * ctx->t_p_eval_us, n_p_eval, 1e-3 * ctx->t_p_eval_us / n_p_eval); - fprintf(stderr, "%s: eval time = %8.2f ms / %5d runs (%8.2f ms per run)\n", __func__, 1e-3 * ctx->t_eval_us, n_eval, 1e-3 * ctx->t_eval_us / n_eval); - fprintf(stderr, "%s: total time = %8.2f ms\n", __func__, (t_end_us - ctx->t_start_us)/1000.0); -} - -void llama_reset_timings(struct llama_context * ctx) { - ctx->t_start_us = ggml_time_us(); - - ctx->t_sample_us = ctx->n_sample = 0; - ctx->t_eval_us = ctx->n_eval = 0; - ctx->t_p_eval_us = ctx->n_p_eval = 0; -} - -const char * llama_print_system_info(void) { - static std::string s; - - s = ""; - s += "AVX = " + std::to_string(ggml_cpu_has_avx()) + " | "; - s += "AVX2 = " + std::to_string(ggml_cpu_has_avx2()) + " | "; - s += "AVX512 = " + std::to_string(ggml_cpu_has_avx512()) + " | "; - s += "FMA = " + std::to_string(ggml_cpu_has_fma()) + " | "; - s += "NEON = " + std::to_string(ggml_cpu_has_neon()) + " | "; - s += "ARM_FMA = " + std::to_string(ggml_cpu_has_arm_fma()) + " | "; - s += "F16C = " + std::to_string(ggml_cpu_has_f16c()) + " | "; - s += "FP16_VA = " + std::to_string(ggml_cpu_has_fp16_va()) + " | "; - s += "WASM_SIMD = " + std::to_string(ggml_cpu_has_wasm_simd()) + " | "; - s += "BLAS = " + std::to_string(ggml_cpu_has_blas()) + " | "; - s += "SSE3 = " + std::to_string(ggml_cpu_has_sse3()) + " | "; - s += "VSX = " + std::to_string(ggml_cpu_has_vsx()) + " | "; - - return s.c_str(); -} diff --git a/llama.h b/llama.h deleted file mode 100644 index 3368de3..0000000 --- a/llama.h +++ /dev/null @@ -1,152 +0,0 @@ -#ifndef LLAMA_H -#define LLAMA_H - -#include -#include -#include - -#ifdef LLAMA_SHARED -# if defined(_WIN32) && !defined(__MINGW32__) -# ifdef LLAMA_BUILD -# define LLAMA_API __declspec(dllexport) -# else -# define LLAMA_API __declspec(dllimport) -# endif -# else -# define LLAMA_API __attribute__ ((visibility ("default"))) -# endif -#else -# define LLAMA_API -#endif - -#define LLAMA_FILE_VERSION 1 -#define LLAMA_FILE_MAGIC 0x67676d66 // 'ggmf' in hex -#define LLAMA_FILE_MAGIC_UNVERSIONED 0x67676d6c // pre-versioned files - -#ifdef __cplusplus -extern "C" { -#endif - - // - // C interface - // - // TODO: show sample usage - // - - struct llama_context; - - typedef int llama_token; - - typedef struct llama_token_data { - llama_token id; // token id - - float p; // probability of the token - float plog; // log probability of the token - - } llama_token_data; - - typedef void (*llama_progress_callback)(float progress, void *ctx); - - struct llama_context_params { - int n_ctx; // text context - int n_parts; // -1 for default - int seed; // RNG seed, 0 for random - - bool f16_kv; // use fp16 for KV cache - bool logits_all; // the llama_eval() call computes all logits, not just the last one - bool vocab_only; // only load the vocabulary, no weights - bool use_mlock; // force system to keep model in RAM - bool embedding; // embedding mode only - - // called with a progress value between 0 and 1, pass NULL to disable - llama_progress_callback progress_callback; - // context pointer passed to the progress callback - void * progress_callback_user_data; - }; - - LLAMA_API struct llama_context_params llama_context_default_params(); - - // Various functions for loading a ggml llama model. - // Allocate (almost) all memory needed for the model. - // Return NULL on failure - LLAMA_API struct llama_context * llama_init_from_file( - const char * path_model, - struct llama_context_params params); - - // Frees all allocated memory - LLAMA_API void llama_free(struct llama_context * ctx); - - // TODO: not great API - very likely to change - // Returns 0 on success - LLAMA_API int llama_model_quantize( - const char * fname_inp, - const char * fname_out, - int itype); - - // Run the llama inference to obtain the logits and probabilities for the next token. - // tokens + n_tokens is the provided batch of new tokens to process - // n_past is the number of tokens to use from previous eval calls - // Returns 0 on success - LLAMA_API int llama_eval( - struct llama_context * ctx, - const llama_token * tokens, - int n_tokens, - int n_past, - int n_threads); - - // Convert the provided text into tokens. - // The tokens pointer must be large enough to hold the resulting tokens. - // Returns the number of tokens on success, no more than n_max_tokens - // Returns a negative number on failure - the number of tokens that would have been returned - // TODO: not sure if correct - LLAMA_API int llama_tokenize( - struct llama_context * ctx, - const char * text, - llama_token * tokens, - int n_max_tokens, - bool add_bos); - - LLAMA_API int llama_n_vocab(struct llama_context * ctx); - LLAMA_API int llama_n_ctx (struct llama_context * ctx); - LLAMA_API int llama_n_embd (struct llama_context * ctx); - - // Token logits obtained from the last call to llama_eval() - // The logits for the last token are stored in the last row - // Can be mutated in order to change the probabilities of the next token - // Rows: n_tokens - // Cols: n_vocab - LLAMA_API float * llama_get_logits(struct llama_context * ctx); - - // Get the embeddings for the input - // shape: [n_embd] (1-dimensional) - LLAMA_API float * llama_get_embeddings(struct llama_context * ctx); - - // Token Id -> String. Uses the vocabulary in the provided context - LLAMA_API const char * llama_token_to_str(struct llama_context * ctx, llama_token token); - - // Special tokens - LLAMA_API llama_token llama_token_bos(); - LLAMA_API llama_token llama_token_eos(); - - // TODO: improve the last_n_tokens interface ? - LLAMA_API llama_token llama_sample_top_p_top_k( - struct llama_context * ctx, - const llama_token * last_n_tokens_data, - int last_n_tokens_size, - int top_k, - float top_p, - float temp, - float repeat_penalty); - - // Performance information - LLAMA_API void llama_print_timings(struct llama_context * ctx); - LLAMA_API void llama_reset_timings(struct llama_context * ctx); - - // Print system information - LLAMA_API const char * llama_print_system_info(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/models/ggml-vocab.bin b/models/ggml-vocab.bin deleted file mode 100644 index 3651f708e80eaa74f2f0004bbcfd8744b15e48e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 432610 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 z zd;|_5&GLAZdvHrky{4k?8w9GD*1W<~BlMWji)*6Npl3Z5pKg|i;GAtWVXhv0nscO2Q9G4v+*q-{-X%U#$VC~>nm!UdSGBNx9mMQAYmOb_V}0Mm^tpZO zVW4!0Rr{pj8#i|FD~7WZ(c)=?_$XxIJq66A#_gG4pkKkW0CmN4jkm{D0ro=Q;x=o^ z&Llz^b}P6eXGB4bgkHC!XGEud$g!;>XHh8>#ohIIRK-P^1Mf_t;PL)JJE_O5rC~cI z$iC5Ac1F~6741HUUxi*doN#l15>=B$)niox-~sWgqYoJaL1JE%ibT%vhpLD#$MK$y)+|FD>$wSnC;`<4A5$Lm-Feyv?0Sq}0@C`7>$X z@#u3>*mw*R zcHP(al-dz?kapA26^`jdah!>!5d)5xMQ5~c5t1dDSg^^@1vF*Yvw1;tKQ!)n!om}X z-4CpBD;TncXu}ZLk!?}k_-)_Ki;1J6iSrA7l6^0!G0{9=Nta`WTcL{;0b(2U-Og5H z!eN!ioDW}%PAe*3dCk^iXs$CJw~Z)jc0=(^fw`OvNszO|uwnAa_ConibV*18+l@lV z9-T2)xxJW^3j`695sf|6xU+MuwjaH^&XRLbjnhU%B5&OBga&Lb48~)<5Lgj2i$lGL zZ+apG@I(0%dm6~xWWdkV5y_72dHmc!PJ(0uB4e`SjcGX+igqGeDoyOk#&3KVXu$b?bfC}9qSK~qGEgB=; zf$OW(?;WjHB?JhT)??Lr9_+bG(3Gg}xuG$9ZcN)kLjkRq)isI=J)8?h(pImkVY}EQ zAZd$hDc77ptHOtA6&Tb`NMLe$Vdz)`i3dsQqw!T<-+t)pxsX zM$oxjaIXt&lV*QT2>knhZ}Y1C1xBLxR2xwU+PJ7a=A8XPyz~@+v#46+@j(yQsQq<< zYZY1XIM|}5D>!WV_k(dwKM1Kq@EgX z+o`5Rp=^TO*aS8k;{ddZCXqp#oT;rcpt-gLe|y5AsNd{7VZfR~kmF`0ZvDPyHBE_9 z-Hyul{91u#e`7N0RF=6+5dCSr%1Ctt)TS5$F$lQ6vx?|{V1DryI=xcIoiS2<~ zMlnji{`*P%$fJ}+keqa^q?vLfR;Onh5AXg)&|(A z1Z4Cu1vF#un=w(Y*Jh>6YsUR-xu<3<%mKTv=bjs^(S`UZ=kWE3K8wU{;e?Am#~_TQ zKoH*~-!YuwURFE!SX)u2SbcD?qZbbxPzSjq`dWF3CC`ub@|PqgCN#YfU-D;tTR*eS zn6$A`bg0|0nkM^)ILP~LM;`@sbJB9SzE0ncAV&J0;{->xy=c}ukwTK#L-jr;F~`1o z;N}iuk2Hd>{|>86)na4wtK(x8U`c6*F~KRCpM8agXswg9)lw!J06+d$Jus%9$hW@z^HU)x&6-QPMLM_4oj|_MA zX%*P)+Xc%B83LtoDCVON|1h4h0=84_ww95OLYV>9b=8T=y8~?VjXUH7D+r;iZ+yy% zfzVa>KCmB(9$Rp|QyZie+*D+g$uU zLSX87Jrfxf$x3{YoF{mNknaaDjG53XL`CS|7KKi5h!0fq?Vk}edMSpGtQd!FS(ss5 zWGgDU8Y^QpaPW)9nrd|;uwGY}+}Kb z+MdLO+=d383R5nBzvb%sm-Z}1*EU+T=Ydh9M;auz3!Vp2dJ$IG&ZaTp`*`GRqA-qH zzw9498*4m?+&m`Vv9pPmJR#8Wvx)o=vGv*sJ^LNiP72t_kexa!+Rgcb%+xab^j)in zmS;IkE93bzrlVD=GJLzws?Ulcy$<6>w>9w^^0nFkJihfal;dhOh=#FVUBCaTHAM}4 zlrS`j7cAdlCZoeE9cL_eR@*^?N7?jrz4@~`{P4L*R`h=1?hM4?cDe!$+Z1A+;6M)uc z$~9fqIeS*BRQysncwcG;=7ilSX+WHvnU8UIG+nfN`pQ`gNfpuCofVhC0aA`axezl( zB<>kojM{Dufk;Jj+?2N^LEKt~nwQl;TE!JrdHuAlMyHkk^S{|zJQtzE^_V%%sa4`p zZbZ>d0`YIg&=9EMU8f;W+_+&o0(z~%cH<*KHhukWipJ>n1i?cE*+bQ=s_Lo(ivb(SW0mauJti%OQLBdtD^KDXJ79Yn-wN50%c2Q9D-a0DoYi_B^W{Pw zdlBt=kviJBL@!sGJM73g9W_{Sj=TEc=s8h`+eX>3b6W4$*mLe8BvCWBNk4H;WOkmj z_@rtfR4KAP?NmTO7%*X3)ayluSP{>+ST&VV3FAh1%X5jmrw|2Wcvh{qY%aaCQmcfScBKo=Y3iJKwdgXylRIK(1TJ!KQnYfMl zdhyMp$5zWz?8fGvH-0TfeTjv>9?h_&!*liAH%aK{Vak8cRBdWVSIGsl9iP)JW_R>F z>1Is3=d>w=g2y+)J)uf0LudaU1`gpKfhJtVaZ7s?Se)^*^&sjxzYS-NGo5<+_Q&X0 z4u#D5e2YCfr}Jj4A5}$S@Sg^lRzEJEsny8V&xY-}3go`{A|~8zG!RU-=nVUD(&rs% z5lpvA;3kSP?WoGLYxICwrQUAzlRXdCv861eP<)LOEs6TB6AaK!wunZ1@rPwwdXCT>cpM3yujdLi_)%BZQ(o#av5;o4y;>n z+`f(NzYtA&$%1D^75VAdOI!vOahFEQT8er^Q9@D@*t2}FYqcri@=AqG|Gog5X`2x| z?!quvHY+5ujvo%$oWN1S(wkQS;vg7Aji!X;{=OcaKU?dYhfUz*OHC>zH^dpE`amG8A^yF~pufI%CoxA-C12m9H!AAk^|rM>Wx-XS!( zvm6Km_jkibT#zsF84uOrz+Fs}pQw(9QXR3U8fIcd=aX4lE=i?PZ1Z<25MxGTEPr`7DC z7xCOtwPYf_YNrI%oi&qJMi$L3_1w0K=)o17$bLE81Sj3rtSazfJ-Y?ARY&d76hX#M zIMvRu^F|YQUi*TkIf+jK5BI*_u=?}jbPH3~q;_0pac5}>s2nQpt+H;d0riXv%5#Bj zGa9?RdPw_0vT3)@a$A>IBG#}jRVShlR3|vx1^DKL0O~nrt$03dJe-#OZlW<1m^YI- zRYz{=d?NMSWgA!3NXKPUww&Fzp~oDmoXuF4CBm~Nzt|Dmj!7nr6ZT;&!yV!0j18>XZWO0z93J6h zPo4PLU=M{bUk6i=Z~x5p)zrgH^HCnDX14WDx9lK>M*g>gYoZ=UnR79RF*dAHP`jxB zQ3`|?Uk?8jEZ=-%dlpqOFv2}mFQkj%_Vb2?6ilS z-Y%qd0*^Z6+xzhgX;pmso}Eye-jwv}q+W_iba_fmGPHs&XvzeS{DU69sNzDR*ai^SiSSb?P+TSNH(+7t%h0 zRp+|1)7ErB`-m$^5cPazEivR_cTsHBsM4V(-I|kdD1iZCpl(5eT2V4RHIhj~RfxUP28 zR%1kMXKYPq_m2>{XI)KPAMX3+#syuPQ7(qw4})jnH%YG$&USngOwcEY8HTV#fc+}C zs}4QZ7_=Clf}_b1KTC}u`o5T%mdvHB1St1fWUsNuHl<}F&)N4p~Qg` zcp?ypbjdlazMLn$g#jC)$(a7L9_!+HOpE7t zP@#WpnQCG~#W{FU2P+l;PMUf{kK;n{s=%aqig5w8`eNDz#;;q=MeQ8yvM3G$!3Gbm z?ims4qLfdBnRC1#bse;(z|rloTh!M$zN$`(0VJid^QDlBb{Cy!@)~A8hBTe}{cOXP z*1UBE_Lww458c0Sf{}9o+*@?>D?VRQqe+X}t+9uqcF9H4rI?bAeuB*ksPAKN%TpS3 z^G7xvvq&Ig24gePLCVGI6fyhqTe^i`Qa{cGez|_nA~vs4T<5#pQ-4T~QPt`BZa*8s zLI6!m$s@5Z#t-;hu(2aVd?2*9e(DjKmZJ2U$J=k@R=ynL=)8hd7hByu~U2IQp~wUc_rWD(-iGZDD)Ty6a~oMIBESF|PqzD@YL$}#|0 zpQ?a7Sypj~wy|$? zdYy}4Yudv+mN6e@ChD|ZZM0c|&d5tWY;%FL+j+ajZ$1joxozb=b&_2kw)^_s9SVq0 zE7-)!cGhJv-jJZND?JbfA6~H~wJwgMB8cug5C^X4=T|;`%~qqc!USJpEoQ_SFKB!{ znv9TUXG8TyCy8fon`&P|_O`7$zQNj#1|pYD+V2XFGuT~5FKvE8JybRKmQ9=cetBZB zsD7kp4sX(C>4W6mg~Hu{>~U0VVnaC$h_24FC&FiRV#=PX4l+}G3!*-5<@P*=*389? zE%}8eEJc3%A7*V@#0@g=JJOcOt>gUVOLnwPryhx-##}LRtSvbs|Kb1gXUE$_LE*Q} zXFSoCzCH^T-L9Q%OZ1en(VbF3R!pWPS(_G?JDDfJg9J?7@9<@A!|I+kzKQvbj@^>cQ{O{Tgu7kDqRmnU`Fi|)>_AwP@}hmM6vV5&)|R;KV#^hjK|Av=hrp7uiy%f~82wt^P0MCohR|Kkip1ic^!e2&h|9N#=IE0C8XQI(%j;q<26C9>oO1y4!s^?y|^Qwo06PH%~y!A8OdGxb~-LQpn z^Isr4`WFoVmmQ>R*UTlw=q&( z;ybPaSQDf!(KA$!+HGIeV1OarM=>7ENHBK(U&hOw?Q#6XnTP>1c3aq6MwbP;d{Uk= zxx&ucQx)bsj>EG{X@joovgbm8TjzCrP+q9dj&#J?!29-Kx)TSmbqwWNMHjjWf z=uTaSD}z&B6gDDtZ;j`#HxP0PMAn4(48l{_q@%IUmt7+|f!I`X`qfXZTTMnM*zCCG z30RM7pNjzu=?mi+Qj>w3gH}={_&nTs^o&*2kWFbo3;>%?tOci4R{838-?y0n=GQ|U z$W=1n_L*~m8mS;WF5G-nMAro)d@p(>O~L(`f4_hwdyfUx+*)>di7g6b#*M`u1PrXX zxq~g~%{OzpUe+53{+L-_(OX(Xxbp;zQh|U(@pXtkgD|{c>#Etp`OfO!&?jz4!45ao z%nu0LzN}4O?!_3y*^YiuyxXEjv)#Qcvw#o?B{dQYcu!-^SV0ff8EQ!%+I}GEkz~HK zN9sCD1bPq{W3y<;NLs_mM< zr5A^HtIg>Q#j!r-%^s^F z{E{8UH|ayo{3L+kzcOi01MfaQ0Sx1__+GvJWQ2n#p9`&I(Tgj&0G>giVjm`=D+1!k zhdQG?$@!`s{ZOabFlyi=OFs5tqSdYc?ozztA0`6jzBFJb)GqrFw@vcYeJH9J^t5$& z8VLTt_MchyVOfmoqBo>2WFP-f`u-Q#_ zbAp+{DOq06>;^<}(DPaR4XrEi@NffeveK<-Ab9XVi9@pxvxzOOJ1mkfS>@QTf(`+~ zgiE&ffK9EW7h)cA>Wl|so~63aru2sY-~fwl`opy4eW%K1^mMt&W&_y^*jCMH@+*mb zF|YnG98WF;_u^X+A&OHkDF*Hb3S$#!#uq-+(#C?0Qv40s;1&aNJ9s=O4>uX;;NBYV z7`-H&^|E>rwxJfe9uDqJ4eWz2Y+Ju}`0Vby zoD`(*wkuG51#Ww)G>FNnJ&cZfCI@X_4cw`b^ZAj0=FZxInodytag4tmX`CI#3mgk7 zJypNdV^0N=I~weyo?qq9p2u{KBYR7x4bYg1lSszeb^AiTOa@f62kkm?+_oO4@pcix z8M5ywXvwkmL~6`DC;joL+}A%e0kO3Qlj&Zs{WqYuD8@(`w&zrPB4^JDlnF?7!zIQQ z?V?JezWkct&z14o&)S1%s?;ivX=rtOB5dv!7&YseW4vUw(E^0s#=0*0feEbFBMCFD zNw~N;^4kS#2~>wYD!hw}TJ-}4iXAY!?0`Ad4+&d75XM5D@I>V)qorTKy41@JK#b?Y#S02r1zCBS8r$}O3eNOCNl#_MF?#FWjK1mC| zpEpeL76a_riLHM~31A)s3LV%3qtlCN;@mFTvZf`&ig_h|@4(E(Rs*7ojelorF(XJ= zhqh3y$7|mxIwS%&#H9G1%YtOp*=F>J2l~jMZU4TWi{VD!vgP19aL zFWxDQB4&H2aen=uCT`n)02*f9*`ol2;?HkPb`TSiYrkxd)ju}`*VrFM$z6|FB|00-B^-W4-!nYlby% z5?&en_Ah;zTZ=kRv4=3v42T!}{*enD*|;pPYAOC2u60pDd}HfUZ<))3I4!JOWynup zG&N}O<_3c^c?{H3X!Y1opyIcrgl8$B-ev8M2O{t|IJ4@7nC}3Y*2`TaKs`1ih+F?S z?()ppKxJ?Qc^9i@u0xwAxtsi;LRveoE*kjOb}vTm-X*`X`+BI71rC)BeGaFhZZCt{Ndnj7=hq6TQo!8}_^(Os~4xB>F4xH(r71bntZ{&MJ zQHBVfgHO0Z!7j-dS4{?#uE$e(E#`Cpu!%ceO$VN5Sy(dx360EGHXDdFVEa#gz_~!V zq0Q!_30?+vFZv^g0GihOs&t9_#zGXF!QpAr7V|O}a%XY2DutDLpek-Y#QCzMw%`5k zX#H6Xy8C zfGpNv1Gf}brR~PM!X9y}i|>XA5|cbYJXEKiE|a}sKL+*EI_E1i+K=K#H%=Tbo6a8y zJ^XX=d)0z{zuOLDimnX|qO*A-Ts_(EfIWTrrH~9@PvPS8XE7_tkO&zTFLym`;0u8) z^qE~rgySMYF5yS6=m7k9!j7sSgT>!i~slY9N$b|@Y zGQgbv%uWTEj^whP#Tyb8_~eQJf{Mv1RpOS}tgEUkiMENpPwcyDRfA6)wweHdtv*yy ztA4hAM%KD3!TlmrP9W-4lPJ{g0MK+L?Fc#IGy8_v5+FyA%eShp%(DSnPUCcaagw6v zk4G9V%J0Zy1?M2!nSZlOL(-G4V+loe3CIM#?*YhVMD^{{74E) zU?sg~B%PWd)b6-|!zB`c$fi_?W{};0xJ5B@9d}TeM>`Kd26rMG7fA zT%+X}25a}?`O>*YyB|~e-w5RpV@#oz7GnYmsG?ko@gUx>5x>&ygO;NALYgpJjF zm+wlz|JS*{w$(BsE(3D{T#NDj3ES^)ZC&k#NIH(BC176Va@l{!He<>v-?42$yv2>) zcFH|({nSmVc4OQn!g37Q-j&$6!b8}};bGJm#GA3-_Vot);eww>fu5LhHj#rs&vTxw z+2a_AdmA1G7#t2@-=17ar^<*wgsEbn7nj^h^UH=LMCXt0 z5soSAib9x0gew9z!hN6+AUej`m#i4Ih(Lh1f{OUqeg`V)4TC;( zGd3;=`AJMvu4+%=404Z|U)XejOqpA4CW@2Z&ft!89(#2gKwXE0c5&T2@_`5wP}F0ur(6 z22d8+YCyU{I5-GTkV>rtTOI~!`2PFoL8z8N2lK*+WoW#nptURP~L!_%g?8*@88 zaFa`3ydW%r@eEXZh8)op@pivFYrca!Kk=wMvK~9Qs*|LD%A=Wk;p13e1S#u<>phId zirD~X{UmxL_a-tJL2_}@GvQt;;!gWqtIG3@MD5ldq&jv@onhZvP)wL3*L3<_K=Pu; zyLf0EyOzkZc?y|3N5}DNB0ZGZ>^dh@m?a(5Z|tNBNBWEG({@U4>^Ckm$*yTNark4b z=9&f-JL3frS6)k`^ID}EIg>* zeI4|YS=8z^#v}m2ixLrhlMp8AdfL8Q0{ewI1%Xl4@~0PoZ6i9!C4P zU`}0&?TA%Z*3#H?Ou;Q=-7}g+x1xbUXQS;|X29lDjY|OMUVPhToEHKm#NqvRUv&tT z$ib%q_8gKLEXK?ouB4E-+AeF**Y-*{bctnYr*%p>a6W~E(@MQC~UA4+E5rpz$fx$2*Wr01^ zm~l(A{isOxVN~ftiS5I~ogb(O*lZn-qn-zNu|xG#`Rcp>&YncCrO~_gRF#+r7SuBp zxc7rS*O=Vr#t+pOT77=Ma{V3}8|zH#_yUq{JJOj5X|lg}5dQC|-Y_4*m%xsx-hbrJ zj(3VqnQDZfe!V-LbNcw+)8d^r#ce_--c_>1TaGwhMQ4^-mZ_Qs2`Q8b~%@~ zs_6G7r!0mmor%_wz7UxaXLHrdw&tw1Gm&RUyVZ4yJYDS0>FFnTz0f6A1jm~Irl23B zN$wQUmt%TctI);4igP&^?b;BQ=G8S0X6VJCtQcbfVU~621=}>g@TrkchZSOO(uKh9 zkyea$SSF)8=+yQg4iqzKHN~C+DvL7Au!bfv;F(ex;f)9x7C`!0fi|N_C~}dWjXA~7 zizJP6D#(ou*t{Aib>h8fy!TI>A@`#N>NT#&3o#o?zz$ox7(Y0#oeW+c#EgIa$F?Lm zp3oT*)AXOmC^PWx8FoewLos#joTIJjIXiO()q$FSh{JW>HZ-{|orh_#P1QrJJ8s*0 z-daK+u@l&CEupWpT|vO)3`yUfs@46$cfV^71&vI2Nu9f|R(u>6!ah%!>sOoNe&-Laf#|?y-nzO6y zQua|=zgI?F2nI*_k=V<={vI3=K1#HQK_2FrDnLGoV)M8Pva`shPpAN4qqCA9m5*a~ zN`j`4%jcuCpoZD#l5J4-kq*O-l<==2>J#*d6T{;oRI0ovFY~IX-A*I|3{`|HnJ8V8 zWHkcKq+6?HatwBc-3O#TnztiVV^?ev;u(1=p}LRKHZaJ5TJ<;v z-;`7LK5Kl?e86*t@H!h%r)I&$E!OpssJ7SDx6X!i#}v88av?e{jh38WEUJT1qG}CA ztv({HmI4GSSl_dV23>A;Yt#h;Qy-=M}t^#71Cr1{&BD);D2dx1*1A%i6G= z0M#My+C_o2#+a9VBuE|?J1<(ERxA7afTX{WFL*(jc3S#1JW0o0xjUi29 zW(W<)xx8TKKtk!_mI!}2){Wo%c zB8o=I#(U)BL|$3`PRWjboXCP)Q7$w(_OW*1km=j;s0n6vLNzl2rNNAxjJE=NGQ{?= zjydi%Mau*vxyE`zz>4S}8Q#d!0TBT45%+j*MFVO42B^0aU#C$KfP=Ds5e?< zm3EeKavN)>z^;!q-^pTc$}Mtyi|JOk$$jT{RuHhtSN_n7AM1KNhCMjzWk{%w^rC_+ zeXNbDeCH)5Q4D13FGp-j5Qk+|Jsmg=^-SXT8ZhxVbO(~zk41{G=pCtVI8nj z#%q>g|H5{o!xUg=uUz(HGMoK{J&dvuJXdUAFFk`UczzUv#p)-y9v!Gt+>M-HejMl! zTEPwj2HZ0K=Yd-%mg?v2sd~Fb?5QNNR4a~zK6|cDPb3F>p{|nMzu!LX6Vcir+KMBe zq~(_F&DzmVv5S$6O14CS*9{TRGy;bQM}L9NQ*9k+gI zby2bJE>3{;pTuov9eV`N`^|Y^O@VkLDReN!jQTLLm_Wx1_5Q+gF{D_z`4~mWq6q{R z<*gHiNzSpZD8JGb(Es|&?LW1`Cuz^R)PY{csjV0j*}|$GiiUd&posp=O7RJr zZ`gR$I}gu2rDxJ`{f$irq75z^nbClf_~o}YTL#U7o{OPE2OPumpNJg!p2&)v4X}H{ zE9<|7nF~SV??>0zKP&{C4t$svqX(|q77vKOyMy_>YzhkWW~>7(&pF{eq+yHPJWW=`yzOux}(gybtS5sfayNc zrQ>ZFUeaaLN4rEy9nL}?>q?ZG_w>fcyF`GPtFYsp=t|>1*KQ}(pv^;R*{QCuRrR=q zazXPTL|K=Xf_q?uZ$*Wgq5b9LtPI%K+|Agk)N7VQTvDxmKKZWI2xn|3t+q=$h35j2 zT)r-_zTkn0>h; z0R*h8D|Q&S*1An6-Cf#_hM6=D!Gaop9)DKUApYQ08|n&=5|3$vO)(4nO9=kQRtgBj z3iR(fE-c-Cg2|rJThjXf%BIWHgCW>V858$Q^p8BNsuA33E{a)gZW!|`n-^vh#nA1& zs6f>4Nz@!fg$_JY+%$O5C`S>C%@QkOF@6}4kq(kgVS}|R@oP0no|+sMR9$5V+LIZ` ziVCwaSAMPPV{ZKx#a=*k6+}8k)-{B!pVA>7LNQv8leMXNJafjj<8%CyBhq#P=Zi^z zW4qBYj0&1*w0c^6Wy|!OokMd`5#1$?CJabr^x)wm25uwaB4*~NTJIexxSmyiT0Xg5 zM|}r^s1ZEY*{`fN;Bi6izfP*axeUq9>|Qj+-<$iPpki)##}-r|GrC0;q?FVT)Se#vBv|@X92SW|mSYNG za7Pf*b2*Hjnv*bfRWST)wY7lpFG()D9`%|a5OO61Mg$^*kbv2Kd`ADuY~_#i%Go;ThK2_kzoaF;&zSt6!h7nC3WOcX&72E32##Ak_yJ5bWeDdVIdUCA{yEBSE#y+KUp%BQ93$8)-m(~Ri7n#bI%2qkf+b97S64g&smLNyKG45 zlxhRD^OriB+w)czjsH9~_WX(UYU~+NnlvP=^-I?BS=wfZ$;8&)suz!_jo?$YGA;p@ z7p5@09-6N+@Fq;aZKBo2o7*=MAR^{<3Tg|`2*k#%C};%L#%(BCBxeRI#kdQ|$vkDj zc$E4fdDo^?y0t`XYiBN}H82hw51;A2G&3>s3!H3dqGzLdx=7hvREPiQ5qCQOS+MV} ztZ?4*@7TTWsZq@H{QyB!0E9vddUG=+`d|F)<@NI`ro%H=J`e&f>O@#?OEDg9%1KeM ztQl$H^05+tQ>0m2)%;`xBwe>P%?}fblqRaRC7<$*cteE7{BEkV+-MS!*>()xeY%;u z9lg3P$)i8+mV59Uz@A?C8dQ83K(Q!s&4b<;zQ>V$6zdjeLf30Ukiv}*Lb8Nd6=x7G zA8KSx#9Do#pYQg6{rC1XrU-CEq~rWtvu6R4J?T1&8;^$gVT8Cw$s6N^V7ZZ?eV#~j z>({sK$mfap2z}aXM?a72-zYh%j;R12d@hZjCyM3XOx!Fa@h4Q#7YJveUJB%4z{u=# z(QmqakqK6>1g-OHw^gX$ew5jj(QjjM)T-jSZ)?q}RVAx@&1wX=f6@cP)PAn>7Z2wC z>sA+-GSk{M3 zJRKsF=+*TrPD-$+>Q#JLAsQDE>0{RUxma1UCx1NjMLG6tUd z{G0#XrERQGPfhr5gHldM2YxLbwi$f_zsVt{S+!XK8B1FBs5y{)h2~W=bAxQoBfA%U zW2gaNs%EGjNvIH0eQm%NHQv`N?SWu%UH#8c?UJgq**4g6eA=8MvaLin?l^y!i}dQ} zVqQYN$Dr2&lzV;u!qx-Hk^V_!RU7K?gDTsM-#dtvj2od79fbAEnT_+)pv zz3d4AcvJDa4`Ug?+IbYHbYl!?d;*uPNwBf9V7l8^kEFR6pFS^#9=#1Ov9XrykwR|&WUpv|@ zk~t6O3Cnj(6-Nh|fa9vz=h6ob!)}r1SwD?WMytm5=5!JU$Vqrv+|{Eds}K9m?zEOW zu2^MvBKt{<{i?c?P8(IeUspAO)#}-U2U?Bbu|N71zE&mK7`$4YN_>&C4C|u=qaJJ0 z^K1V)vuG{qDr;!8)-u{I|Ic-c2S>IwNGx5;m)oOz>r|N^xPDEyt|-fMLF-npiMW1l zg&1vz-}kN9E!rcPyF@rc>M^O)tP~T~<}R=#fQ>m|cBeEkKl*nzEqJ5yg`H8AtzQq? zY@kb=ZP@z}n^TjD&uu=CyUA&LPrv3{?Y@2`6Ze!Y2n)O)*-#b(V*=80@IQ#g7YWF; z6!^i^`xdzzMKI&G5{-z2%8t3JidbNBA-`p7dL`kEZhLBnQ|72`sGX-Eq2i|A8vVqA zz~aL+Hrq~o7z|Z^X}jGbUv>@mcS2IQrw*7>xQ=0a7|4(pgk5!C>xV4ONiLG4QjdfJ z>tf9gVi>nzXCKG&7(T3rdL|6{ggxojz8wzMe*1VDKY1n^(#Z}%EYIQ-G*7`0!Yw}6 z*KTk}t<>!c;Tg8)W<7$c+@`P(_^9`2fsEm*&mtVNqdg+Ivz{}YG(kOyE_!$SqUDfsrYz=t*=s)<2HrMrBX=(mCP|lvX9E z*>#){tJUT`0_4@i&xNgjvRXk#Fp4B=%<6jL%e>r6>eT_9KjhsMc%*(Jn*?BN&vK1}r$;i#6X9VR~ zaz=k+&VCQYM7tkX!Bwv%mBN0roX0g44N!!K)3d3-Wq8o0WB6x~_0PofSr334RmjUd zCzRx};qj_$UMQ10&TU)oMb*!KWcO9j0Cxh{zYyOJ)7t^ee%)nkQFSZH<@+F}kA?CJ zF3U?Vrxp{OWmUU^x!#I?XQ|@&yBb}c{>0Ye@k7)QF@sLxqzj6vaCUQo+ly`Xq;2>Q zUbpS&5(7;4#NUZ_Tp(ojQy;c9HB8J#&uD+0*zP)tfylqv;unNP8!E$sR zNM@`bKQNC&rs^GchEXHfDZO#$^WX=W;Oc%?5k&>an%iE$brJAzi9uHd4k-UfiPxKG z{wDiVO`r}#X0-tVZ#Oisbt-YcORHCj>u5Non*tW%DQHeT4ImA;)sk;(wbqybvc?iw zEbUUc=wu98SYC~BC*;d?2Ab?dLl7FrUT<0`pZ$?_s~(qhXt^K&ue|!|yH*Tfet8;- zXR>ZsDPW}x)VQ|Uc%XTmq(?T@tLv_7*F9L=hD~dx6Nf!cI+2-}`L?Z}CQp~yfbHvP zE}pmkoS>mE4b697u897K8*h368!+HRUiR9ImP%>vi^K zDH;(DglSpU_rZ$PR-yn|Ghb*m#+ZD@U2M6g`D(af>w#hk(fmfQws<#@#|L{ex`MX= z__lz5{Z~+5JpKgniXO8o&9)9l?)046N!^f(sYH#`HYl(wvrn&=@hIT7@q&3qza}h^zzE|A^&dC?xFo(mDm> zi_d;kXFmY zL9D8FmQO*&ZB4+q(EIiDH?}T3up@A}{6=4*e(aSz#<^J0O~LQ=IEmYO&L#o8qvtQa z`20t<8^52sa^Cg?kxk1*a1Y}vc-+;bkll}}MXm^sG)#<0iI;Gof}x&?>-Jdlmo*b) zGo~Vi9e5H`(ZXSa8;w1U!L@nPAJR-}dYi7;b0Hxs411y9TRO}N!A`np;VZYtupqh^e)kf7J z19+tiRJM2DwFL$3oA`1$yU`lMN%9=eevpfUCOpDz(!x}XJ@gmZ4V#ek=x zXMBbbK~2YS&SMi~GcUgtN*Cv*XEpB1%2#bp6^R7R@AKt>mIGVeD@eu2Mb}NzJTR3f z-us>17lesY$rfTDo-t)Ho;z5k4+4cTx2IkT?9LFe6ivITal09{6+s#$S?_98;$F;D zuBjj^+_v@K}C@u|jf?srStL*YDtviV6&MGqU( zQ>~|wF-04E7UM+J$|8AQhLQH$g1v~v$8ItKM_~PluG&&=^ZvBnZ;$$1AMH;xQMz&6 zj;T)8!^P`(f1LS5IYc>nLbWo;;AFo@whbmEiQZ2M9A=m7&RMi`dm>K0is;rqUS)v4 z3XN8&4V27gR^2aB?nNV6w3+}%W-m<1RKzLAk!y8PQ6UlP_2yD-w`u7Yk&qN7X@y(# z-i+if+0?ei2)gSmrygWMoDZy^2QATo^O0uWBBUX{zR&Y zCnUmOTD@~IqANsq4>-x~e%z^6UJan^HAFp%mlRH8J@CASG)0diC1OcOm5!dF z+qNB5`Z(F*_r1Sn!`@W~lRZV;&sBgp1=4@00!A=w`+ClDtg%OdENsmP{DK__@b>?S z8A|{zdXUe<_+o8tcWh4t!B?3*jgpRZ*LtQm1(LSsQRa@Fgt85Q*uuj?UQhJW7lMZW zkE!>8t-8$e|4$4t#IO@$_!)kNnEPcrif)H5F~ksu@k>h!1q*iD3XIcnX}N80+uPpj zy|<;UfE5uDtHb!^>#`0%7hTpx!%SF3x9hTgiA6#TG1U-53^BwILkuy*5JLY?x)Z5oaa3M&;K*4CmlEZTZrS=6Wg1aK_=OA`frj=Xd=AIdgkY;vfY1p$^lZkcE^voA@BYSc?w^Q z%$%kN94M`6Xtb=ln|{6DasdH>N|Kc1)h1KMDBX&xNBBRh z=0-O0dyeZCiYh7!z|bwaB!M*e?C-sO_*lfmRzb6+G;s%QDoQbI$u>x|_RU z1Q7nmrzbgwVm=UfujI};sIE8&ew+dfj}fs-p&z3Y0{$W?I?|&HV*DoCcr?mAcn43J zzz+Efcf3ch^~#h%IwX~7UaL>CKGiSJRdiTG&qn`M_;!2-Wyd-S{2FR4lW9(PB`ed^Z* zcSvIPt2qoC%X&c7S{`X_w}YxS{eIqsoQGn0Fs*b(@31QN^|EqDgq_PBK6`;Qaz|st z>{Udz$JB88{a*NzoE=xgOcT`FRQ%4d=T7K15;6pq`i-$9XE5q);i@>Jg=lGQw6pp% zhWDgUj{e9{isbB^_CZ@R7jzo^d_WjSntnkL%9yBLjAcSN>)Q28)hR_qYnN5lPMpMg zWCT}Y`Wqu;+*Ls&xE$sv`d!$Hr|R`Uge}I5-Ov{gt1AyIm(CiD_khjHrNh(hkuYp_ zE}e&85i@m8PUooj@jt;@&D9sme$;+8Pi-CCaNLX8MGSp ziOzDs7O8;1TL`yn^#SPaye$#1@(9N&8kD+;p_xm^XC+%K4QIK~DdV}yGOkc5H|M{* z$i*6Rr<3mn;!xOego#Pn*(A^y5L&Z9`weC-YRtJGgO$frGpDoYVWyc=M2?$sx^f80 z<_A6n*zAa*)pzEQo(LQEoJZ}=stD~J=Qx+sMc~r6WLA1Zh9y569lJ7< z01r9c>_IyEK|80)J)SH2d~~r!x~B^@+??ed#D?JeaFx;$!B2BhIMl zOXoT>Lu8})I}dc9)yBt4j|{LxunaZH#l6Cv$ zC?`&!+u>)Uyq>-hX`q7(xDR)ZTRwifCtfkyIXTGTuS7c{qQGYGfQ?3Z6G87$J#Ev# z{o0w(j9^KK$(ilaR|bt9t@db5DtViXzFY*gPZN^F-hNK^s}0PbXHPj0(?xI`CoSxt zdR~X^hI`W=iViT<i+=vgA5uFW#VNs_ zKMYeEQ(*u;PBnS{D(tM2v6?B?*Qppt6DC(@sw?aHW?Xs_6=egh58il`q~`+b23)bQ zeU7f%wh)2DnWhUGV+k#mZ?cO4m!s;Df9+DBqX-I@qjWX06ps>nMR+f){TsU)$hqC> zwLoUg`c;qE^(a7CU^ikKjwd@)>(}li!6)|^k)!){8N;f{4RUsWIxrCA++K6~_26NO zhN1J^{?m!qOSV)WvIkM?*t`IMtkvBOF+b@)ExV<#@niO@Hk1qc)47H(#2z~O!KVR2 zQy&>n{101HtwqYS+W6gqZQqhWrjQ?lI9uAEj&EJ-dRwNS)9()2@_wCuNI56HRs>v< z(h^8I%5ahJ7}QPii3MpV;^=1e1hvs=Em7nWEd-nG>KMf|88vKEpn))etGc7VN_%?< z%}|I7ROgm{6yp8CS$Lp(h;@kU7Z4QZssr|5xOsKA8b{kC*;EHEQN%H*67##Z;ETYu zF&f2)9Kmf{6mz<;s6=oy5r4qQ!A&fuY?o%o;~DMguhP`mcPAn4qzW_3AF_Rd``PZa zPxfmJtSUKzRH>W$=%D^QeHaPGp%??VX0IJqYqHPz^Liv^#cjh&!xF_Fts>?#aR9`Q zsY%3-I37*NvW1eCn}F>%rQSRenw{v^d*(Dq@`b~jNB}YnhDYO+DrblcYiFXwWq5cJ zsf4$tXfv_@31>i(!#+EwL2xutWS`f^*pSOqF7&4drZi#~)gC%@+%CnS+x>RF93L~B zExS@3pNC>|1E{NkP?@Xanx>Gb>~>v0`*}cb#CmYG`NPM3Y6E(d?pbWJ2C7V3C#J%) z2Xyv)4|yzqZciA$0UciF+A$a_+uQ*iu#Z2)CM?=xTY^d4`~jW&-pDJkKsDRftZTH) zfDTQYN8mun89-J~zh#R82vI#arnS+ZbW_|#O9Co4mxu7Or2)xbcErZZG#b=ywmfQ* zO)kkZS5*7#9Q0s}4Fh_n8$4n~QRv@dt|bYrftYanf*ZI9a?)hF44O$N}c=j_@S^Sd(VZu$G8d4qy&9EeYM zopl0K&<1jLNL@}J;Tby|-4`(gJ|bxKaQ)EINA;zP*^UW=A?UB;(dp{eM;>jlDd9uD zM(k}*RM#Hm&q=i?X9;7guIn4^jB026va+)Qh$|HSeP%!>v^-2aw-g%N&Z%~?SF-c5 zj)YxhtD~`t)}B9e$S$g9;@e@8QvJ=UUXBi(ueB>NBgxJbt4q}@4Z45nGRuvm!9)> zn^n;lE4fx@1%HGb$Ce8qo>0I}K5Z!6j>zf9Jg%Rb7aM3fJ5= zK^i9FQVPjFps}PoH3+#0iWJ3wxACTxLg9GwjnXqT{&a=6Ljs zmy0LQo64t4^WFnVTFhrc&Zo3=SPnkJ36rAv^!E^@6 z2RC7}2lZ;Dz+9a+XHe&Lwc7|`?`w0TE`FdkZ!mbW=?~m*#pXv_t|?E>xnM9}AD6^s z^pV6Yz;yb6}!@6HU;ADq35&NEPOI6iGazy#+0-OAEI*-A;a2L zAAF&r5ae$Xewb<#2VTFsiI;4f)e5sKNF>XuB(nkXHdmdRY*Gy71NHjp6D2DKHY=Ul z@F#IF-7%FM5>O4{*Cce-AAJcX0v1jxiCI*qB}MGrqk23fHd*b&BV_LrGD+RAKM)%r z-tz$seF&C{w3_}}9~6WZSF6YBJ9)uvjiYRIo#@X2JE9(lT151Rqr!vt*Pn)C(Rn)# zPe+f|6Yb1`Ck1MGbKb}yj|(OF89;PK(`n~jyn>w@ERNefW(zwC01VSL1{ zsES{)P^ec`rLo1XMN{0e(8gX@gJB#$Zm3J#sdy%bbSgG_X5(2yB20g|-DVG^L&$+7 zPLh73d&WUezcZ~Qn3*@E)98XcB*uhF3ScWCrfk8GjxJK6$jR81i-C3 zWSF-o+FnZ(cy+kp*T& zR|Yic0|TAux2*Z*1auEr%aF)%tOgNcw-2Qg`_N+Bq~6!KF*NUMM+}_X0h0`<*Uf>> zJ@?dFHZaA91i7f?qKE*ume+5jG1zLV-z_PeU}Z>GS3B;oIIGxbH0pwo+ZJW6b}jcn zehRBmB5e-ol1VSPyG@fpF9uNT8|_9wBQSZ4LTq1*)9v1DzY0hx!;u?Gw;z;^bMUSa zI~d!buH6nr#UuDI91aNUxU20*d<>42pRl8n3@c{7FV5d#Rw4tn2 zRQ?kh8mX=%-9D+xnYxW_c1piL+Y7sUruugmfNJ=^Tx>HjF*qusS{k!+L#O{A*HRO! z)?@8?;E)Mtj-BSS^TKyDnd4p10EY>8bTL4er~lP1#qSoT?y@ElhQ}BDiW)rHO01Tc z9N6J&)%m}fX5OxA^vFoKlL*%fP$_Ac*zTD^+SHvyUqjYg zQ%DD!SVSdTq-xI3lSfF^GVVsxZA%I|y=-x3bC1Jp~nAusvgWdg)TB1Lv<1ln@uVUjG%s<#B zft&e9Fzbl!VUHnO(`nkQVL{*cv!}YA=F@U9#MbE(xc}z0BGZS5tr!I`=!n27T7nFe z8dg@&EjFsEnbtAe7XA5oVRt!)J`wAQpCwWff=|b2v%H>rqB<5%+>wbSo{YgDUw1BM zU$piCB-5AZJz2QHt8cXffgQIRchtf7>dY5;k`HODzE3%!>X=&u=LJ>!?4@)I9SxM4 z$gglL2D7r&j;l2hk=f)^(XseCkNR~&Fg)}G_vuNsyLWqyovNfyZAzNA9q6W`@CNawAXD}X_sQ2FeXl( z5SLXMu@M0q+zj(d;9n1G)Kzf8=&G7Sz`{Ces3Z!(-08ZuTr~zlWsG&WAza+|%y*y_ zb?VT!yUR~0E#0i5PHN&cW*5^jMyu@tDBK!~>4YP5vbn`LJ+E_qpiGPDA^F`Rn_o<) zFZ1B9?zIJ~l;>1>=(kKU9aHxbVzO%lJR{vYM>W2&hjPnOs};!h-`WzjZx&FBA|6tpqLIc<0MEvfh;V#XePV8p~Y>zN%lyl2u z%!ivY+CCvbre52xR`9OJl7j1iT4m}nE8rv+b@L?!r<+%1?T{LH;wtB_>~K_ZjVn$l zPTe1gm8^_muEw!DDlCg-qKqCB9{6=IFUO!p5RO3{;3~!128vMJXcMjad0) zzQIax9-l}@&xO)N&3!@-o_n@ueW%WT;d$tOrQr!J3n$kTE;74+vrB9^&%i@>%x{{ULvS_=?T^5!HR%F>^YF4PXGyjD6xIw?C|D8S9q~FEF z89pJ(fk0i!5VA$RZ@=5xg`Wp*+oT4W^<*6Dh{1slPp55GQN8b zJCvNnEU&tWkSxZ0yU3Sua1K?-Jq=f=-!K6Lj}SslbvB{DZuH;0P(4D_o|xlb z-)obq1`UUtG-j}cjG$pJyg%kETf%JTKzxj(2ue4%04{DGE9cM?x_20xXK6^DJBOo1 z3bJrSUAe!w9Ssa>er3lrMJf0L)|bZvjGrXQ6-kpK{K=stuJ%ND%xBuEM#{40tO12c2 zq8pbtVHc_a5M92T96WXV+oF<=^9Ee#lFsjO41etdwpLcvIx&%T+P6u3Jjx6)IFV_y!fa4{{1C)1>}TE;#ksEF6DT zYb`=Pi2xvM+6BY2EpZA3gC&xXrb95=IL17Zn*%TRXw2$&pNpAuF|wYLJ4)vDh2F&81SDOxqSyiw@TlJWNCbq4M z%*R&lX@nLwSrYk^obI67($lq1OW#NUhyBsGF%M=30&7p;MU35&UTra~=~dJSk$_{G zt=W6D!Hx*TDs1w21qFKg-F`c!+S5nSydIBvYDModrQeWSLv|v%$L$zhesteVkfgkw zQU`4Vb|xkuIi$U3XG`J_A$k%|=&Xto)U!ut0w9mV2|K3|)ct&KpBH+B*Rl)hjlGS2 z&MwBRqQ-i`9~8S3yW?KF9HVwk)fF}3`SIi_R|7HRBqRp6Yx+#8VXorq>I*9&yAdO+ z8%}z|a@zKYdH%?H&MK$F7qrPSn_W(4bi~cP=akc_g4#l)ipH?4Ba41vo@$Zku+Qe} z&xK--Ef8pSvXh6Iaylt`Eo=0Vc_arFy-1xBU|InYY6ULSV2tb4uN0K z$qd?#MHSSq%;fQyyoY&9nWHK7zJ2>I?LhZQEJ1E7gtX zMuTLqwX4xbJ@nkQ7|T|6EJxvbb-i8I&i9QNcv5DWRkVef}8p501LOrmPECtVKRg*4T#uA0dbic6-JQIL_vGO(OjW6 zoEcW5LH%Zm(;pDl1K~`3Bin}5!C`P`WV$0!dT2EY@5Dd;z?Ry6H&8`SCcbXNfgQ>iU8+qnp{RUI_0`D5 zXVkRFS&X52ybxH&nfUA*8u6fl=Wb2}#n{RSnK}=PY8Uk33yEY#eR9w18kw?7nu0Dr zHkUO-y{@=)T!|rj5H;t=t_uI@*HiH4YcY8R=#J|uaY7IB?Z(g8xgC!Ur{k7MHdC{P z(*X)=+S&TTFv(B#oZ)nAG2!d7xx+fs?wFl4RP%<@G?F}az8YncWs5BsPCKbnvF%9k7~!GV?ETZ?{FmB3zpkh`m;z8VVk})|N#7-2_!wI-KrvHg0m9M2;|J z%LLeipDh<)7h|E7<#?>nAUU6?8yjN8DG_l~;D8ISELoZb#rJt=xRL%tO z7LP+gJhSMz-h<5AjDTfULld5hig=rG;OxALrVn!|T!`PVW2tsA01Ope(tjz&%uH^< zL%~nl<@l4o)-a3yU|)#=xB-z}4FLY|^H>TrH~qicb^RueebH`2EmtMuMKO|2o?@HW ztP!2B9={meeP#AYI()TXPrPJvRF(Dd(EoEsbbblhle2jv=>TC!)bH~(eN-?K^?M_AzP$AGbL{9TJ=emNH;)QGLp{lnLl;fQdM$Z z)t0GuY&o2=wB_;H)!hqCZYu&@9kSwv5gnFtQj;Wod6S9UcbDONWX$#wcNJa}2$1*x65KbjAkZMa$?4GF9(m70}NzL2hkN(T{ z>F0LhVC>iUddU202Ld_QfjDho2L;WK@sJ&=4$&<+?Qjf{q&59zo}D8C=}{+-Mn$LL z2_q=nHm zD8pvIIqa;e*Co{vgv*Qo60r1G1VB6|0Jvil!!v*5>8kbH%DMh}ofgVhiqnX~_EO#;)`O)}YLp`0PEY{eC@ zxD7@pUr)Sg?Sa0>w!m{xCCL@GL)}4jcv!>tY;)9v@L`}?)#RZkd0!wh)QgXmdLheO3{U9%ls4CP9Gu>$7cJ)9D_@rB|)DOuuEjqQk%Sf3_!3>*MH7s#0MP z&M+#mJkVJCRjJE0$Ooc?7mFqb)%7E2FL4=+)mTjm4lp?^aPB&JWNSpYc-<}V{%X@7 zjiCT7sm_kYtj5)hvzbh68*0)8TQiMu4MhCEL1$$;aMe<#yVsVwsdLi98GjU@!H z;MRCSpwPNJ1=dO^1M7X%CuCwAO{&qhd1hJPtw`;!Rw z!Gjok2UAA$`dh0?K3;8vecUogOa*PDzq{8o&^{iL>(L3m_;y3TGi%ucHkyuCPl4k# zYg8wX-Vm{0D%rwP69Iiu;2;1F(eN7LbPOH1Oy=|sJ#(ZtcVZd%lxY~=mS9=cTQ6bD%q-leDkO-4R#9$yhWX1SyHxkm3WlzCpd2b zk&s12>j<1$F`M5UzrUXNC(8z~PE_LTR4n{#kcNcn#LxC?xm1s?NSoPMeS#L*#<_4IXq+dQNG_jZBxEvD@ zq%;K4w&O7uT>LzP0Uwzdr~ibCV6M2ePmYRQDS13m_tVJQDV1Y7$U}5S!~N{J&;Dp< zqdPJZ5l?qir%-YyKXdVi`r$0@-%fly^_T-ZtW@G6X zxknXR!Lf7_Gj;hcn?0tJNN(^UtRd#ar^kLkqB1u={WQT)%p21+P>tS<#_t)MFVJi< z)^@>II=LMSAGFMv=82Ha9v0|5s~OYLbO#NO=he#vxhPO+=G51!t!Fo05^Y;C3r!l6 zrBz^_>c~T#FN=o#(;wLKv2?N|ezX-))lYv)ZqlHtka(DQt15(;KVQu%x##!4yT@8I z477nnl5ZC((2}-EKQo)}u?{uPkTnBzH>)vfK!OfNNvnHhSS~=J%_Q?!pyN|8^FG_5 z7=J*M<(4j-%W8F(2#m(KI=L3N3F?NvvKy;U=&NnG%Oe8piXPoX7DZvK6XND9gz;nm zsYe^IFS=vaJ>v=Qp$d6p$s!$Na1Q5SRAgUs{5TGWq6@c_>axSCN^GW4I}-4lNnLnU zwen+I3z*Fx8%tMh`$jviI;B2nw<(RVk6Z)zE~#LZhYdO@yjvTUc=J^Bh#@;v=9w|Q z3OJIbx9#lBA?HDNCeVevD|!feJE!7dY1hxkW(&a+y9h!wCVJ)#w(Uh#halv-u}jg{ z(DYl$0seA8PsT;CA9f`=FF-Bv^aUiQv}D&}@+sLu{Nd}-w1=Fde~TF1$ke$r=ZvQli+dmp%Uo6J>a}^}>425Xd7H2L=}e;$ zjMjt;!9q2oFOJF-TdrnYN0B?jBl8iyLJ0hle^#sCBogJ^3HtAAe`iYrURS|0cPty% zHPIPQpxR{GV1QN#QOv{ODdX87GFm)oZJ_UpsxlV*LpfPfQ-cr@S=hsp1o_84?M zxo~XL%`teqyNo+_P^k?+nJpGoP5RP13Fe@hmnL3a`GcS1T6atowVI^@! z?FgUVU}sg;BTjRd&csL&E4^ap0*?qUjYxD{yS~+Hn|Xm6Wh$Km zAD=)QsH&NU^=(!YRk3|R_CkELC)2TQ;6bU4R?r5dGO#7_$rSl2FBMjBUM$VBC>v&H zRfcW(lbTXzaR>0?MMn`8+SqxRm^P@F>DO`S4FvqS_`}{T{y=!wx=~Xj%`TokHFa>hH5j zJFJm!Y+cjdXh&kUoWVUB!&rqfh3Dj$icm45B-Em0>Q>uSAkRyYMA#<;F0in_zT%4+qq4=!_w zepb5jwp2gsc<`5P(>;JL2pSF@z52^AbnMr7URT5)u!0*-8i@uqUR$@xnuN>pUs-dE zqlGYxg>r$Qoh{pRTX`5T*g}oUc~I9bZ;C-8dPR0(9q~!nKLRV+W{riU5-^8RJy#zR88zMNo3NtanL2W!k7}4ealtdf(U?2rw0JXZ({6=>?{RG{ z)4nSp58t#0+M{82=Lc;vaKd}g#Vh;b6N1D;6YP(HZz+_gkJQELg)FiR4#qJ7!L`|m&f@}-(!RO_&XiW9r`Jxz=)15; zJsH0V5M!qTZv7*6CjRWnS*`h*d?OJ6>K6Fg&-!S3nLUM7Rs=Y9KhgJKN&GYUxOW;fzDVqdfE z+Fba?mHTYg_H;&4;;VFqW=ApNU^d&F>X$2LZSM9sHLvlc&fA_&4HjWorES+P;H`Bx z77sbIV7m?n0UAhEOg7x@I=sZ|E_H9Qn(gUWJHxR^KQoP3X-9W1i$p6JAh1Tvd!p2( z>apK%)@1>%tuOE4&zDElWO@&#D+H)}h?v4??bVQX3G-0>h7iDBdwXc>5g4E&-HBzi zRAVg~Ci5+zn>%JJJ2PXLs+pp@0Z*cnjfW8sOK>os>9@O_59s(lv zrxiApTVL);t6JL;1QM{gugW6}R+pERSYPvIZy-=+&XGw{AE?R;lbDe1NXIR+@Lrp*Ka;->W^soOG`TdkSVjdaA8BZ`nkbmTVZ|2h5G_ZPT&9?Q zYIh`r|L0~~5*Q({Mi@=ddi9g-CKOw=@+{2GDcJHIdhLT1r}l~+x;8xbNw`on2nnKL z;&-@1S4KTA2@BaAeW8AGS6gd|Vhpm84q1Ejmv*#^hBn3Ad8!rO$sLkeIYsHA**v|1 zZH{SqxX-dN;#EA}mJ=4u?zNDQZq^X8gsZoxB6p&*ihgH`$k9jj8+Syg*D5UN9-9cX z%P{ahdAkB$F^2>J{e9rY8Be)#6E!@!<7bWiXMe!zjI73xo%^C`9e!}rZ`poL=+B04 zc0d)}cFVguC_K=aQu~k){Ooyz9)|<*N3bh662I|4wxfY~`!KSDWAU+OguD2-Aanki zOf0;kELmrqh>vn77BMHQJC?yAN)_;IHxqeAzY8TEp|erTlb8{fEdX@EI@q}?=zj*$ z^QzaN7yClB=>Ov)z8HA7ks;(#fa6j=0_UhNbaoyM?~3ZN>#(EQk?vqzyuufa@@v`y zY+$<{VC02$BRU{DpxIOD9B#=u&uFurN+;{%{|#$8`>AxYdJv7xc`6-Gu4XJBSgyJH zUX3s=Ik(JvO5432`4HY7E+v@%R60pzbcL#%DHH$7(;8;fM~0JNHR^+HZ;ONom;Wm` zOw>lDuJNt5t3k3m`48)ODqT1QlpmZv zwMMEjT;|Qrsw~6!(HlOM?i_BtZhRBi%lRmM%&+)j^owPWTisRE2R2|SEMgSG;|{Y0 zx5Y@@4SM1!T|oq8z>G{)HD)XuT^z+)IMivZ*S z$`H0r=`%}Era|_{3H9DTeaKG6cs#k}sTdDrjq=Q#xj7ZMR|Lem!A`O~*^Ce&GNg;n z&P5?2NSrL~e4vta6BksIYt{`oEwK0vx#)n+PgQ|EfeWHvRRQ4+pGyaV+0GS*sUsZW`yf? zwu%S_z_z(fA9WBBaFY{yOnv+FF553A^vVqqyb%2!PEhKu`H_`&d(=&A1csOMCer=v z_F$E^pTl6>F_G?tMfZ{pZNB<~t6>k`IdM~BGuZ8Je6~Qq8&^JTcLnyHp4cKIED-HP z#f8x|JaQ5%*F^1lAH&^&GuMF=iT`bjCenTK;4key;X+&sqBjZ#w)07vVv7SNHl#@o zy+n1lc5|ffk1}HPaSC|Rg=iP|zyr}6p??@Tle7FX}hKzOt2KbHP^O>f+uq6*VH*iH!tkzvFE*)|O$r znVgLWwmse5S=aR0witJs`LgX$d7|JFSwA6YY#O+#odHeK7Ov8Oh5?cb9J01sNaA)) zCddih69iCUN;!;f@v~Rm`CaTh%4FcWY0a87_EO9iPAZVo`(ljFJF+pE>6fE&8Qg8Z zD!bsF;lC0y$RP&m0Zj&8TJ~yS+)x;Xqr~t-MZ@{5y%rsmQz&@%Y&aAhbh-BKjVMlH zj^uEBIHn3huy3$zZ)&WquFO3WMQc3{dd}XCkq{smRFB3N@vYdgf2l%2DZyDe_VZHW zt>8L_cLewMi~jarJ06uiN&uDLueK#N77oi(stI@2X&-1{zx?&z*og_f$&EwAn<^*; zG*xb+Oiy13E*@Z6EHeq#J0WTc zZjvw$P9xiw8g}NfPP?Gl=p5?rwy&xSfb|T4MPqC7-U^nvK6MpTg=Khi43SOXXSoI*f`d)~AhEtVY z3#ciu`VT6AIfWyP-{q|Z`%zd8;^58Rx}hdXqG&&57OFv-0R>~J(Le~ele4=68Ri4JChgxvD*pJx z=|9_jQMKpeKU!_zfw3aTaNS$~cJfPo@ zrYLTrrYH8p#*st&pdh=_CoS1>L2h+Ro02`Gkxd`&wG~e%a-_}Gd8A_MwR-&_(>whZ z+G)7V2K^yX`?%VcZIzZ3`@%G}O#9^(2F!h%Z_cSaLMb;ndL|ddBCCjVmp5HuVLxK8dFS^rKn(Ja< zh_PL_mEr>l$1$q}oULxi$wM&`gLENiuZ>12BTi|u$D_1=*o`c<1)zF&t=thGzGOBL zNU!GF->Cv30`l(d(pDZEwcSsr%Q3~5b#hngr9IVI!buXTz%#ZthP-BzO-ARqAHhGq z6kqF5)ACA2?;M9?_Od`{*wLlJsQVK6ZLnXEh$d^V1bRIz^Z~(vPjHjkR|C#Q_Z~PH zAL+V(t%@0*O@8s(p(uq@DBBx?h@pI+9oFwgtR3vlsMHS6Wk=$}LowLfsx|H$-cjLz zw84$A{vt%TAdWv4$T24*~ys7BG#f6`zSyV8WToJ9|-MP@6+n%p@qM;GqJ~JP7r+WY4n5d*(U*I z3o^XCosAw>wr#LaW9pnJaVKY+i5nP^3O2*`xjMm)1uFbpbibNs)xHRrXpM=Mb3U4J zoN`DjzZ5#{s1+|nZ{667eigqPnWT%VlBwHZU+d2+U8{I0z^;bh?zV4K!oI~;L%p)rpArr3#>InS??E5%6TnbQ}BoI`e?U00+$ovph zp$N%C5mk8^kSb^G$ADaca$}^>Xg5@&fan}6l`ZyDjIoJ8c(yaWatJ%icFRt2a!H_u zYrW0dskhDmlv7Lyy~tGQNW#QM!HalyajM53h8OhnGV8 z-50Q(Ot;z?wVM*a_>+QYalmX!^y!l5`_Yz$I#k{FS7-JF)YE_9sJ2wd4DQuAk-6IWpn0JruM5F#4Kkum&^T`lti1$0HXAkkcIpOIsD6y?x11 ztEmc({4=&TV6+g;usMFOuWPgQ@w=U))S@m={V8v)`g0p`AFN%!2Rx$ihJe}VnxjqC z1r47K=JYXvDBvsE5kHyy$DRso3&$qyf>8Rj+dC$DE`dI2&n z$VjP?QUJ?b;M`0Uu6}`rdxsv%M?Yocur?H{mrYjxerSqOjJH|EO6mv~0GFm$1TxvR zjKm_h^W5caG*%U-bWT6F&$ysKE&KZxQw|a3W(+&j=UVQ!w#2vDL;ypm#&~u{_0@<7 zS@2ydWKW_PwB1n^RSkY#d!lM9w;}KP-klQ2w2}zk^F>VxVV=Mf_L9ny(8&X{?2Eb{ z;lmvmU)GT(ZRh@&fgU`G?G=G&Z`{;w2ULKF0y6B?nBR8dNgRwNg5fERZAHP=ZLg`A zT}s5Tz`0N&L#w?JUv+TzxT*%2HHgIDjE*brSaBrqLm{0^1Ky7Bu>G^6+9Al^>@U#{ zrx6&ysE0)}Z`YW;6H`<-kW9{xYx22cg>gHjpQoOw*lGRDtV8*&rbH3+9r1~_5BCWg z4ws3Xjc)q8@nQUQr+5 z0Z(PYzKqT`dj7x*`ryVUpXFCVxURLqF2=MLiWpS!^nER88wtQ>mjVEK$ye-~KmyH= z=%vds7bJN9R-^WfjHK;KAjBltcUmRFwUHnmErWVn1;6IW?d|)RX%EXqU^O-LoICbI z^gV(fwOv;=%|k`tZ`J*e%bb2d#jy_^fBd zsi7My*{$)hiD*$aJ3g}hmffb-ZQKMlN54Bi-pPZf-{k=mm~)@e`maMi*}`Y^qz5&B!fI3<;VX28-K~BLgJm>(q_U3z63Z=X_XVgVsNssNRZFxP&VMY{ zgb^mymIOAW&b9jm5Yw3SW-blnJTH8YJrG~YKDJB{5Cz+V>K79g#6HVoE?@;pOw>cw zGSdCp3QYye=P$LZ-|L@AG)db!YY-ZQ^X0h{?!*dn;vM4!^)*5s`L%%rT4FAr=9r%~ z9&*<`Yu2k~hDWdy!%kRfG4iWF`Ii-kKV#1kSG9ac92~Rl}O%B^!x+ zfc-td&f6OZ_BgN0mYCe{E2ttHR0lc+u3N?IST*3TV!ttUVYL}9#)e~8;|Lm zDyZYdC99=AxT>HR-d3$Kj

X2AQFf{Y5ZGdDa5QdQPOh6E*&!){d(oVfRb+es%e{ zCHve^S=Bl*8vEcGy&=wi+_cd-QAMq-**=V^dKkqSgE<+W+%xXd_feqN3q5k`8ByqX z1z~}f&d%vr1|Fjx^axmt#2;KHle_>viFH{CMKoY%g;+~di+vgetLmED8f_*pD)R7t zuCdo_w{tOe_`zZO;^#pod*kx~0FO7O;LE@}hlYUlx)7Bc!)@;?LE?Jhk-Zpo+3CJv zzmB>xxXIcj;WF&X_HTr6jxBguty&U!F=XFXCsqPH+2UV`;k!K|R7c*v)0|cM2F4>} zuw9KoZ7HyizmE?T{-hR+ZC8zE1(z4aJj!r+F-IQa`o~xc93Dnm*`-&h-N{spx_6}~qbfSITU9ml80Igt^_y&>op#%Z@O{P!(9nlWalFg5HDQAV< z8QnFK4AvIxO3yROf4fURA7$TUqA_|8TNs1F>(6tH)u;%fwcGBFqM1LsvdC!V-#Vl zWDg2P8|*P^z8D#~!{Oy((4A-o^R{A_PMPzVVfk1e6%cjMU&Ah)=oIujgOA`{Np+L-JVpwDTJ=ITUvqWPV+J~~Um!9=yS2sPQJwFaI<63kh93>wn961 zNw&bX36I0EV_A0voc?alN54BJFX?di#7wyFn@hiKZ$QRagab4g>)t@=rQu=}CSK8jUob6;-9`&4xKFoB56c3PuY{15+NX95PgxF_tB z_^2D6{%1R@CViD0stWtG3f=>k&IDSrG5I{^t``x>xj-?w`0+4(p`JRkBX(Ymk}Uck z?aP=YD6e!+U{`e^#*X9`meamceHXtXyS}I|H{yZy`dVEMd+MM|)wNDyc0}zSIP4ou zfQOGyHWzkTh$RILUUT-X5L<(p$(6vl84ZhDlYJLmvHV=RS7T0^hlv&Wef7h|sn_CT zrKi#TAubV*?Zu^lyz9D(UGs$0Q!q6xcH`z2L6-OdlPZF&v!2yejFP<@ix||-cB?8NlW|6N_Op_K5^ejoXRAIjyfE)3&7k|)9m zrnhyq)4J||@{0hPB&?poZ_4IAt7o<7V)@(kp}3jz0w1iYIRSS>Jv6BZL<0^wtkRg& zTz5X3UU(!KDF1}on$_#=uBb`Gr|wc00g13Ee^&4RDh?(b#6mS3cR4^!bXiBl{9e2J z+4LO#J&a*=UctG??$e;KG4{)u(8N&)*@Fg9h1?6S=a{l3F(Q{^+x^e#`FB6V0Expat*_1us*Jp~2zVh&zUbB%R13x% zDMU$oV6+Y))rM#F^rb{2>AKq#ons0Idl*yc#*28MS%(UVA;Bs>9$j*528bmY<6qfq zUC}{5B8IGn20M|U_e7iN*AbIiF2n1v2$z1hSYDl4=7d)4Er(n zwNmUK65>9Cs`|s3_pPGt`v$lhMgkRoQ%ChXDT2oX_6TuEVvJpc#P+vthfu_s+25N9 z;pAc0UCp-h+4MNxG&J=Xe7gi|(Za>HTV2$7`rAE$=2raHZLbQN9$D9DlQ9P#Qw-iP zs%71Ld|!MNho|4Mm(?{k-xZJFwmcK z0nXL0Lv~cN;aS4}5<9O#Zn&QhsZn!*P->N_EMW zGTWWrjLb#|wp(_mrwXIARY`&|Yj?W2unVs{9HtK<+l&evB4 zq7enxox(TciHBj{ZGnK2`PofN+@R{N-RYg1{p(*KGSkws5ze+_l(qTa9XE zpdFpDy<456MTJ+4F6D1>pHRydIRCYQW(!aAVqt&ZefQatfR<9jV-%|P-CI0o;l7-cYswtRO4llJE{#azUj%G1TUn)0FDa(D1KK=cJ& zg8*e+mnon=pKdzqfLytgo&C z!KcXVxLfZzs%GV2XpNaA1LU~1M_nSF!t!m1FBlLWzD+St?iK)`$D)gep$9tzqdkZ3 zf;}EngPB;TtEe{%3T^ym?27(E7HdBOIZ4Ps;{@a-Gg%8gTufw{`fN-Dxkb(oc`XtrTrY(y|a+UxJxs5aeLzm3P~ z`Pq=uwh3q_BAZUz5%{=AuZtGTHW8CD`0>Bn&iGvE-4~D`VV#+KIX>YOkmTC_SO`+96iAw5 zuLKgDb)=_Jh`Ccr&GPE*(`9_?l*MjVJphW~K@yh05C- z`fO`#OK$0hV-)bqo%W_aa?^(~96F*Qk<$_0QE1@5GL*=;5@D0nP%KB&cq}mWvSRF>WCn+yr6bgMffqWu|Ey) zy>g46Q5iy7_SNTcM|5TtmK9~XZ_IOownhORztETaZ6fPAALwBmfWkRvUusYzJVzH| zrW#k;S1~sv)JF5>VX7|1+;CEzOUv5VyAw4>ULDt5DG>Ih7!ziZJ@$H||Lf0ZsU+`Rd)_pf~u^qR&0_-Y}O`CZxtq<1L z@IDxZdA5dy!r)RFnwP1oG1aFq!gM8xc5CLrm{}i-)dt%IE%0v z2pbni`ReX2PYb>zKCu;X<;VR3T}N>7nALH&1AZWCr8^O~iTLEA^MFndYEqn@wB>;- zga}SD6?^D85fpXxwnEil<0@7kvyWX5FHJ+t>UxCFt72YioXu!bM;i*I6eo3U%s8#c zM&dH7W_9PZEZ66dtruL~ch;iOEZ%IbffkNQ$qcYPre$3SF>HfYAk&?K`J&t9irJ*@ zkPhIz$p0tou^2dfvfoM_f$LCbZqObN2shsqAZ%7QDJMZEAW`pbfxDcW8on}0s{s2 zj|fdF@y8?paT$rX9MOD@6JTAaHFTE;JYdXtpj~!N=eB72b4GARx+7{dcjt(y5Q{$j zuI<#)Cabeu`VF&QvfcVkmTcZib&Ch@UZD;X&Fx67$(Zk?HJ`GVVr0acEEK2TvVHO0 zUV!D{f_ho=GW~A04|ViRHBefhz)~t@dhk(Y7TA-DwAfOB>9inwJSP zz$0=fs^N0y#)fYMh?#>ZQxC`X^(*?#sD~Ud$yC+rmi|6_TP5z=>KE0~fPj9B7f}#U zeGm^`7&NW1ccO|*Y3z7Ff`ER%`uFL#iZ-Rcll|I05ES=iv=gc`-iIxOeW-%z6POm9 ztX>Fi@a`dDKT_e^#+B`MN_&`#f>bBYzF@k0S{=BA@QkVsx>xZhnx5v)VSlO4s-*1J zBA*6&{bYW%nV1jaOZk!dJXS25VxQxur*@eZ$lEXCbPticC+FOXomcG$xQly4082p< zNF4E;sP43>gD7V}U&Xp(G6Vt_g??e~2QZe`ASgF%R-Yicss zmvxt)A2ewN#PkDpUE{_=&Sgnu`!Qw>>JSBM z^b<33o2wd`N88%$_C0!n)~8tAHc!~}$#073xnoayINOr=m^fu6n;$L6RZBDsyHjv0 z$g&pfNzZg5CI4V|?Md|PO{tX3;xpCZRvD;;YUIP`398wn`!6YG{FQUE>+TpuOPwv+ zlPC)%WxH=rdZw{vtPFeFnp%O%paOz&T^wH+N@0SrB)&>1Xwm%w1G~f-SgH>qYO%Ht z2qtDN{zjpYRADdQz4qXqL}-*oZMje)5s5vd`PhoM+S$7m(b3A3&!b-T2D_T9p}Lp~ zTH@@&DlJ5r7t)$yklQ}IV+-L$c5!MasN!|+5T{1BG+ zb=ZdJ5|K3P zkrj$$^e9`8c1xzMoBNs_PaqP(WiqWlfNbo+DiRyyokqFw( zK(fhmAnp?)Y*KJ?ZpLpfRc921h-`RlUu<;5 z7hYf9Q!fioEFH-z6diJBJ1hB$ije+v*#V(d*U(_E?h&(49QF(`;!+M)ar2zx&men# zEkJRJxE0!=7;xv9D{o!(qFyo(vUdV1=7L-7c;I`J1${qC-KXBBG;j}hWFJ(4KvJN1 z49vHpLh*h1VKhq|;YrOAd4268{dAu7R5VeXAXJXg#Ivy3nSf5hUC!|*vAf*MzlV2& zFcN_$c00Kw$oo{Nk;ob8YAgg&He!rJg)p_B2f&9@?wE7&g}n_M=!=--h_py&JM7t)oXT`o!yOoF=IU;s3aBAD)elQpUey!TmuP5={rRXKnOMfGT zAAj;!9d=p2Gj0B6#S z%n#AE=LZGk_4q`r#I0gKMpHj7u1~w6KF|y-w4c;F+aVd8J}2ejj6@JEL>V+j+tm{Q^}+ z?LB07={NKv(HjHfc5b?b0)ncN8y#I-P4p~&{%)a<@g8@>A~kDkCkgz0LVaZpXG(gi zjaL4EB4mxP@}RqOE~$Pc`P2OZf`X)COZEGnd-36YK)-vOs9P2-D&(Lp+k;gMQ@*#d zEstS(-q2(?`;exmgl*u8=k<`!c!;I#%;#t-H%mi_qpm_fT`KvAFm&I5p88W5S7_ zjkh6|&O^O9)v&2L&pw%t=_AwN0+Wu|a5yjKgD`nqxtj(geAyD_fQUf@LJX%4L6cCVgRkX^6?-{qyIlm-+y3VhO}6g0_DU2KvIDLgJP@O5>+8*%_q8Y-S@lJaqM%IPE@$k(>P4NV?_NHd1FtifAF(>v&R3K3q$u*FXy&b)@ zb`mo;5U58V348Vz74b^`mmSmZd+)_&`5pbI?T!@4Wfj|=+z7GZMqeJ@7P6}Ht$Yh9$d5!>1A4#S;!eiX;`O`5j z&XzNp|7~Y9=Z%f_i8jF?(!sMaKsJtFJ)hp(b2o$6&BTsruCvbt;eXv@=c1WYQgEL~P$y0sV85jbG6xk6oXq(D+V+c%ougpHEy8=cg*% z`d$k%RQUK$r=GKGYPeFa;r2s-Ex>`YT-Vh))8<4u&WD5cqgs2)R)&2ehRU-yeHa_4 zpEQqk2mx%b9xgxV+=jR8O|Mm=CP{dquM9aik!jx=RZ&HF_@vo;^{)05xO{KZM`?_N zQZ{FAdSs{HEZHxj4f0uxb8YV4;5bnLYj1I_zh}4aJ?-x~HVOq8&F^Ad2 zJ>4H)mFc%R?@Oy?C6A2zfM&t&R+fgxZLJ_;MCoL4b3k0U!qx{O zXbZTXtwqo>4Bc9zXti=;wpWYDyRji)CmLc?Al2@ktFG1>v&Z(P86`;F$&GziqFG znRLn$0D9k{9^Rb6a-JMCb!BbKne77%+pBBmXRk}URxZ>WT%gvdVZu)eqhvE;Bf zqZOH^Sn4D3)sBNw*51~ZX=$;enu8&DE*`}I-GXxBSTx9|=sxeLS~)qC9*=QULqlcl zeKq8M@3X1cc&l6O19kKJg?3`E2>xW&4QKzMD)m7boK#!SpJX2iav0)y$gxu@&3g{P z)B26^#gLuR?@Y(_Ibv-!Ceokv#ULpv80 zhQ?gDHe_GKV7Nuj#|FVF&Ldn_?8~Uzlw^rRb|Jnc_U1*@H~d4Q`s`u=AZ?QbMPCcm zo&ttsc1d%!WyrqKuV2;J<-Mopas}kj<|)^IPK17t%A(If$+xuBrurAj(HJ4*TdX)geJ>%5UcGj+p=n1?Xm? z3pLo46&yoqUeICSN==6JcfXJx{7$UQ7YQwHt`E7n?h6<_=sn?;YE>^&e!><9h(^zB z$GyBn;4^Nye1Bl)Jp<^NEqx(95D#v)2Q)C$lqjl}1@v{Dn0*nfCO&&%ABk+UToB2z zjJaxcLDGHBtGwcc)5<>tfyci5fc=p)wG6aA<_@*ekTpcZ@B?_yR%v{g>UvPurWZt3 zVB3w2yp!;2qxC8mjWt)-2&oKCjv7S|Y3p7%eFqzd#d05}lwvojHLy&E`D~4GpcU~< zAnh?zT%PPEOnRaidIIv#Hbt?^#hk8rEc!%~#jV+)FKh~kL}ibwY4ZJG(Kp9(jPt6- z3L>J&1^~>b8A6YmbYTz3C2ctk4|fJG@_r4dW4q;rL>PVH^bt5Fhne@R7_*2P&$(2> z*~Ds>p*$*4w{B?6gBOj&cwBt$Ib23#XNrY^|0WPzv~I0iXWN9WdoQsCb_DK3He$O? zM7OB=+-rjvZ~+^4_{96~(f~HBvE8w+Qq-zFv4#Y5#tl+!xCBWM$ox*mq^<3U?;q`WG%mZY_Wfu~8i5kgN~WT$4XVXH zh%)H+Ay};w`mBeGZ~@(i>L-Ih^;kL|9>VHmG-*S7&b)r4NkByGvYJx@ju?%@aXRK_ z{V;@?ozYr(8o5t|>HxOZcD6b@Q1YLu%GSPqn+YseyRzkToouK(I2YOO#O6UONXT0> znCi;S#5qgnqm+jlqnsi8GHwO}32;z7eBcH3+UN00ztVt^$g-tSTUPgYiZ;&>G2)3; z>p`uRy1yhuTN_u~H__KfiZVh3;TX@#9B%(FNS@EVED0~LuBd4q=c4ao>fAEm4|etD z^@V@g5aKNRUR5(YerMM-9eBz!*dOBW9ly5g(OU!L+mC?>k*K(;$eb9}N;&%})@(gz zk-NesbyKo{u0Vr=x@9sw8fBup&C*X&+}W*@dOCYK33wrpQA1@g9Cn+2W*#24Ig{zR z?MpBIFDCV#64lswy}6U8lN7hEjZmnQqJbOzC3cE65%2RR^^AMmHoPGx(`yDN=;k`d zZNA#$@iAm~svpE-+%5|y#ZM9Mo~ZZK{lM-DNF?7w3Y-b#c~;$qyle{tGk0@G5A)ft6|bzyFZkQyb$LJ_uMy-M&G8MBu7 z?fUvw{oYa_-eCJ=+V9YnyLmi)2|u(Af`Xaf^y>&@V~jXOrW7QPRo8@o2oT5}F(@Yk z-m%AHi!EGaoAr}Gw$>GYoqpA_@w2vNjbZdpirsS|N181sV)D^1 z&eLxAITZb3T*OH%M*Akr$`Qm0GK)!`J^jXzWZXt#VS9%Oq&ga%xJJ*z#OP@hoMbvc zFr2`!4t?p4=$^bMZh|lo-4h3qVeizahI#LH#TMYf^8_k>m+g)XMo6NrKH~Y=9>L`{ z@3OstIp+)hXELxI?j5$5V&UQKFeSs-&i2LRE&m_(vMQ1~g*+;O<`9a6S0)pw_vA0_ zKn!-ci!=SIdLh~rFOVJ77xba$iF@tlaUf94kR1wyAPKo;-UujA$p~PhrgKlwk8cVc zlyi0@s-aCN+S`H8BbqEZGTZgyT{l(7M0fXpu7`X3>%2F3df@nYRqTsea#-y zW~?*(shEoCOq90!rhX8hntA_DL{s-Mvkz6^DZA~YCZ;lIA8CMfaLn9~r_?t&9O)dg z{j|QZd372sYiBfOwCO2K(IZeTP^|~7sYI?>Kk$mlil`Wdc3&t zp25O%j-ZYEbMlK9^*%Kdo@4sorr+Z|pQ{csu#9;$5VyZ5G4l|rEKxP{1TEtRx?Amz z_~IDAe9nJS65cxZYP(Y%5i15s>x=2>&a8UG?oyq8BD)V+MyR@-5$Nr-g#lpL^H$dg zw!4Bdin|4F@j_GXb-$7%ECRKiQ+O~%T$UPHEOX3^-)gg1eZrUWMqWGiOzD}T^_H0 zMT~vTN~;%2nR-NN4N=Qu<8xY9sc8CjL<>#&P5#r0tqsTsREP`^?TNl<>tpTGlYw&- z3*Vx}%D}w2yp_||8V%a`-5wndqTJyQ*$_pKwy&~H(MbauPJ2uR(|<-p+M(YmSNr4o zokc-on{N&=ZR@U>Pp4(OEvwa$P!0yICpPKEzqVh_#ma}TjP+}lvKV#c)e&0Ek`2Wg z5QqiM1V^|Se^^IU3=RrW-~tr{*3SG^go?Y`Kwgdr>dI!)dVm`>#FcyH#nbM#;TQH_NoWoP7Ad#V ztI-+nOR_#Y7_-aO{91KJ;S-oYq^qjymJ|bayn*b;!iA=yhmXWW7GGf+-qk8z)C0EKUI-Gu+SGXG2=6@C7aq~ z_IcpT9q5@b&IKTp7@W&5G+%4n7SN-CoR89V-C5qtFIBn@Q#a37Y!|Aq|BHab$Ds?q zQg!$m*HK*55Lf#Qd>um|)wheu{vBugOE>od{v|LR_Dyu=0rGM6h^2FbT92miZG5M| zi5#OVFDBA!RlR-pqSSN_*O{V3<4@YvSl;9o$z*J??=?-G$`Ta|neP2xL`Xy@BKk!{#CLr>u6kTIA|iTR$(eEd z(>Ts=W-_onMh<}zwL>W&Oxk80A0 zWoXgVnboV^J3H7TOAK!b&#q-&>xCSsXb?h6S1yW1{~ZxFnn^WiSk$^GnpKDFGtsK4 zDE`1lW2JTnvfaY46cyGg)kp_dQgGhqff3{p=W@XjVSg&4)i%249gWXVKHy~QoFf&X5 zi8Vat%m5t2+r<7U%tcv;QI)rqAZX))3im}2RsF6saxYB!XyyLG5Sn++145+*6NLu_ zA(vBUkPZWyMT*x)({E1P1MA>@foW3S!ru|%Us+d2|^1T(ei zvDdiW1N?pdO^&tLujL>(S1U&&4j5?RF}bP_YIdFdV|0Qy^dVtz|Jpe0dj?&`CH=|E zg59vRaZwx*^2GkYMK1^aiaTz{=JlvI<*}40#W78I-J+U%7RPZF)uc>#Bu;p55(k&w zPik)Zxi(MfXI;J@y(7}4GtRh|8n()7o|JT_8Z0ifXFa3k9!poVbKcNAeA55vyjmmN zc|6{5T~N#f$%G9ME<~2%Vv4u)mG36Zh2M6!b=V+WaKo0t?os6M1Wt8BZe+Xz-qS2A z8c)6_g+9o0h(8dVj5in`3XU&3X7D2;yN4RkXZ`WD8e;O?7T*}= zxqt1SdX8LCD&j`zjqePzFY~#4uMemx67wGnj)x>c`+n4dc0eY6@;>a$rw-R-JXY@i zaco)j>lbt5^2bEOGNKD?!@tBd6)k}Rx(Ley{ITJJXV+?2ojqLgWj%aRIe?In#n01O|D-Oy)ezq!mlf{8?+j6 z3_f`^`eOj{9;;NVg4a^qr)`t(t`g!PR=Y66EvzwiTxV%`v(}?W1Q6|>$+Q0zo%%CD z7_iOpba!Jb-4i`3L3cbF>y0Xs4MJIOi2lb!#JHq#sCg&{+?b~p-29MHUfhc!de}vX z--$y%D!6zT6He9DmZuDLlL{&gW1C{q$RlYOCh6=0-j<7z&|{;|fRW=rXrz{4EtY}B zHVYUAGA#B(?i2L@``}?6lSTg&TdHUR_s{W&L0~~lM+5Pw@wsPF{leHPe2|!7k7InW zJQydy$oA?{uD+yq822TR)tv&u%bEAuE;US3*kl@ayWxFY$;b-^Vvm-hg@B`b1tV>d zVxQ3@DHdP*RS748IABCB>?!2@pyBmRotT_Df#~9pM}VEnNE~))UP--EuMWh^TDQN= z+jK;*u`Y>M+;*gE>fhq1rv@*Fl2_}P>P@hHjtkLrt%(yxbi6C$WuEjj+{?&M85&Ma z>*KW1#snZO>Cd>Va5=9D@;ZWEpEWd26d@VTJ>~~aTK^UMhIjtuoj=BTHD)6~N#8Ie z=8`l~{zxT4yk%HznZYaGRwwmK7smzttc-NWyVYqPBxY^A_t<%v8)Q23L18%G zzqH|z5EDt3rSLmh1BEdLHtiPcJ5_PTMX5^7r%N3jc%(UAbLvxs-pV3By%xSGGlW zFYT^Y7nL;qjcfE#!vy!mwQie=)edfz>$Z#P=JSO_3Y~Gi`e8BRhV6wEqEt)2!W&&P z&+5JKD{+%hN1O6$+`L_c5r>Pyn3X%PV!Xub<}El~5Q%~?#McaC$>|)9nd*129XnM6 z&Lov{^yhU0V=;Gop~d7>8%;6&yi2pi)zOcZCvMs9w*xOBjz9huaqITNX#DaY;x=_% zWC4GP+dY_cJ0oYrMBHI$>BR#bhiAD{SP*!WT<6C7-g0{{5Z<`4q$pJg&LIC}jecgJ z+&bY}sf9cctfAf`ZA$U!5|<&hOjqY+E+gwFULD3OQ(3W{pov;9hEpsFqDhUDK~H^r zvyiORp=oRtpwYp+cvh+%Y%Y2W0ywTxVeN{08e8K&52pqRd0(vd+NA=N`g;7XQTyUi zmjbM{-ZyxoLNd@M8bq$`Xmt83vk4OxKwmXo-N~2qRL7p%Z@us(oYX}0t6=IxDiH?$ zW;KT~SU{@kzYr&~Yk+XTeKD*Cqw|94&9iK?e{YK6N43mB^&Uujk15$+} zNSyb6Uo?=hwFvk{y#07X4It*wNug2s<@9(aTSHT;uBBU!p@?2 zz33&%SL$ElQ=@?A@4EO*@F1IK;&c5jyZ8$MYiDR*sx>JlULqdMR|cJ-AK=Kp_QasE zOFKeB4lrBasPP!_&c0RSspl|3Xp8UEL!}i;`MoM3^@<;i`J&1A(R(#Lk$D0j)%?j* zIGSNVQWz7D7XmlPb#U3^h1$SqrWWq<$BRON_&<3?%QG0m8da~ycjk)6MYtCC+V1+w z#|sJKvKpRfArL`{+;f#0RDQiWt`_`C3uF@S|HlhqST`BhK3>Q%!5+{HUH5q5J}StT ziw#@ic)c4Es(=^I4UeBMhB-^{1HDnu&mNl_H$AS0V%j9*2zRrw^Xa#XAKF|H&+ z#>(@~)pcDLyC2I8gbED^;j%6xf`p_vF zD2$IV)MkZP>eyeyJ&IswMju%ov(I$bZru0^-!PYJ^ze4c!`R5o#u6s>pt zfwU9q_Zlul(h7wgFm?oH;zSL(W>1=I46CS?90d$x)a~k+S+3)8*M!)TH_>IO8-c5t z^k)woF;A}tG_QT5aBL5H_@jNX`EflYD*wyBS$zXP^=n(OtGlK!lJFTrg5 zoVO)6DfzCjE>)wnb?k{ZybHRadV-CBqDcPV@|l1LBuP6OZ@X_MHlzDo@Mj8{pf~So zs91`oS?PQ3Kcy+}8_DIFcK8ET%iw7c-4E6Kiss+OM`}Sz4qP^>J@MGf*l^W*35j+) zZtEAdCY>ANQ-f}!+xX0_>QcpvqR?fS@{PwAUMS)-uz|ibz~!XG$)S9uzVTNjk(3W@ z4Yq1Ld{WZ?jR%A9H@@{=he$)I@i2rf{7$2oPNdrJ1-USKX?F92a7y$2loS1EG=?(6 zP5fkp(-oHuA3H=rP=M!?XP@sg_UN>#*n zpgh2?+EGXwE}wAhSL>sK@S#7h@dx(t6LGCS8oJOrUndZwq!~&M`1&1%K+pQeU&al_ zf~d(EZ|+95!W4!%x@kwD#tPq;FTI# z9wBEJ$w7h8Y)l()NNV-(K6vSs#<~F?z>)q~<%xjP!_?_M7q$?KkV|~EKOrXLP>(e` zL?%*Zone@{M>zzsRs(_hFn#U%SkH)YY;^mQprk9hjYcn8pdJladPQ!^^&V0>6Aezl zDfaJ>K%s?a(AWqj_{H)@5ZDxt#*oKc+>z3Ls4a#KgvH~X#r-_$ImTa(1jE{Rl|}c& zCc)|LAOgdrSEacp?W-Oz%2*0xr5O);Y@>LN#Aa_aX1UnIJ>>DUVhQrFduoJ1iY+d{ zram4~0Sq%w+D8q&v1?;y=G^LfqwW2%%>Y_5>*{uYz?DN5)hM5D$!YC0jDCFMIj*}r z4Hup(mrf>U*{u{hkr-I2;2H z2+7Hb^vKY*tl*ZA{-Q8nhcu~Y|8sU6R>fk+__8XNScz#MG!aKUq)8b6c%?dqL1Ltk zY*=MoMX7kq_}z<`$CB*hLMR_^JhV>i5Q|<-6_xRoP8vE&?9n)-4~!+SvODdr(yEoa z`i$_ctz8tad6+5ApNO+w3tTY`#!2bWd>ZHh=6a9u7|Ka{w@unMd0;gV#xBRs# zRk!iB4{ym#z^WXN3u=g2UA*fl#E=PVHk_E^JvUxKsQux1-(O54xBCa)(IeSie^;WpJN()iZ)|D#I^&cqxzgw7O+pMc(so#i8&s_d`Ao z2_Zf=8Yo@4_P#K*ni5KoSL7vVs1RMV7iq(W_}X9aX2`L>al6!B<%9WKwd3x;KfY60 z+PW91$oE>cvC)hv@Pj_E9cL1L6wFjTq09QIIx@oYqyQnF&^xdjUZX@qzU+xY5gSuY zjZuxhDi|sumznm2C8vH2UGaog8h6Gg3aP|Lg2&-iPy8QDhjzu)Pl%Az!F^@!VMcV# z6S}6-2*^Vr5`g-Ib4o?>bx(+{qt{H|&FhWtNSYz%0B$hUrVL(%VJZjW#wR59ZAIf~ zjQbG}rJU(z73E+mPZSQJvXF2f)BSttQi8AQcm0ay}8_P6tXle82Bow(SV!41kw$Wg)INMdkqfMS>^gP)3k4Ce<(QC6GN21k85$wDT z)54YhOo1JnY*lrrDTTSuA0w$zTJ4V(o<*@nvpAcmg=;n6btpfvCFh2Wc7d!CmrgH8 z1CJQ^JVZC$+N(=yqenn_({k$93sW|q^2YRgz8VHIlEZ*zq{NLIQV;cLz;i-|t7AZZ z!jpGY$c=aP#kflv@&18KZK{rrl-Ds?JsK$}PCs2D17k_?fSZuZvCvKLX((|jiH^g> zZ5Ad|2eC+cNWUvsHpaukH}3$w7I*a_m6eo4huvFCK1N@z?nce& z$vC2x<(-*UNv{|IZu7k8k9uz?6=pY_&oO~s#lJXi6dDndpU^mX&}9VMlUm|UBP1zS zrRA7}#c6>V%)b20=wL>`+af-9b$BNxJ#9SW3xUS0@MwJL+J#>wQh-0Pr%tP>ud97!oE?mp z_|rFP45)SSt><|KtAO}bCBx}6@x6Xmx}gL=7zkmZi~VZHMEs~?2o8@<0a;!&`Vl(| ztxQP@8}zcBA}Axg$1dMls1|oTWgRhXXCa&=AZebmE7XwS)2Vp7a;Io;NqCStjjMJR za#Aj((-7{Hakbz<&&xVrv$IgRMZ?6F)6c0BJ#n3(_LnHo*BfdJJC0q6=yhkI*1z~o z+^C9JlO_?qNqA#@kKolH$dN=zW#{>lO(37^oHW0#rtd7Yo`^swqh|={ul_z}3h7Gm ziZ5nHvs`hg3$N2T8bKw)AhPl1s#9`fK`T`cX&imtqN%EYTgj|*tJ@I_A~q`O9w#&Zj9>SgBSn5hhzRuaUMVCZj1$P+yX`FiMx#H%8WTu5Fcou#jvd%MYW?77438aq@?0MX^+LH!&fC)Z|G z&s>7>kO7m&6aSigrabI@%O#dNLPSx?2yaoFhDD8w;}Lbik%o3XstK%D`9T(^!bZnz>qS|RX#hlchYiW#AYQ1oIQ=E1U zQoy5JG^oXBltAn?%}bgmrnL<+nX{hWyv+yWoWS4{5$83Ae6__Js)PYr8ZEr3Ek*)| zAv|mb;w^8vL4ww&bLrb2@#{~;1z&%1#)8hiYve{!uJE3bLtxUw6u$2Zq8Lw>Cslml zi5x=I_~A}HQ+fx`66B?s5hy-#2lw*m=f+tV9~&7MLM{vJPX!^>rg71oFB?SU_NhDP z^_WprKC8}a#&`MLA9rV5gfH}gwvh|%OMReyVT!);+}+)k!N9&&Ph$g!SidoVHj>B0 zxBjSY8-e7h)~vKO{NA|YzR=sr1LFsy1Q(MgF+c8fTE)x|hN&+!D5cmZ<0rv*{R{^p z{v_EcTaB;F{KeCPg}D4rh2YiVP|=xp-n2gzf<^MdxZ+ReQv*oAeoS%n=eG5D^Z!Zj zyykRs!vo__A~H+Twc{E!sjP#HU;8KBag)G;aa-Ihgqsm9b61e6@lSrk5}l=};#ozm_34IA#DbxiVQ|o;qz*F$ju^-N zF-rq$C#1w2HyPzE6?5IB*z~N6d4JNokd^iG%5Gv)JzO%H)Y7U<7JtRMi6G3$dQM~yJ6rk1Spa+04f z4RESxqr0Htl0S)ISvN>Z5khRoGC}I)qU?_b;aJ}9oc3r`ml+ZznhbWdjHcOOVS_X5 zaH~;nt!;{xLb-z2Zd!o$ zI*ls6Y&;4*o#YTI(!m~oay^LKQ(XXG)i|S&){oV~9Ipl6Kw9c^Sv%4P~ z(@`&E>RRERpi1LLk?r))@BB~5#wL$(?eAk!KLW4|__nE=ewEiyLp?fi*D7JM|F{AM;SujGo!rLEitdRZUCKofX}& ztqN(dYXnH!{aLIVNa5&yQ<;@a%TAAF>Okz$&)Sxj*lkpco@kGzsx{-}?DZ73v3d5X zej3#5cPAj1A*2tud2L<-2h{|E`=4=0P1-S8J?sTYrNGOspJu#q#IT5_gOWd9F~Y_E zja_7|4*FO&$hmvIHRVS z;b0_Q6Jl^BJor4^R;;DYRX0X|TRXv<;I_`Y6r1>X!wbgg(T)42`c1B-bxFK+>3TpH zL*8O^2~gWW8uNTCtkA=yDD4vuU?FY`7u_G@CLWwWh*HxZpLqt;I_hM6u92+# zIk?UjuH1obR(xsHG71RR0caVu64U=KzV?W_yV%5-oNE3T!qt6il#vS!B^&#ldgOih zFC4e;g=KFBocckH(&6DpH9``TzKBQTCxh=vFCD1du0rLOHey%b8kg-Vbd88*(z9Hy zZyr5)zObJ0;9 zfn+V0XfT-r37I1=-(_k!^(rrj2DO|zg@(O98ugXpCX73qyl&~dle5;WNgxVUv2^_+tywO*CEU+X05^IbjV@^TB+DpSuFVbjt&&}w1vgb~( zS9wb)>3jFC5}fhZ|J%RlF(lG#WI*2ayTqpu>6+j#a5B+vG}=bs2L?2b^iYl=7p(8v zh>+A^MoJT|7~pYR%vM4SlohQQXny9A#$ofrk;Nw9`qoPI~Vup zcm5cggnAhvyiqnexuqDH!Me6;yYr8Fn$;MZ49EheGm-dpzES8{i7l0${J_0)N(h z#uh(#2wCiR4=~w?o_pee0A;)%j>JI&O3ig|ip&qWdS5RIUr}Hl7D9w8gFYH^2iixt zx+B%L8Ksz+idQtZSWu?QE^o9r>iHo>K^*hQ7b3+Rh~vVz7peA%>SU$)$w}`Op`TBK zQ>sbasyOW~=|G_h&bT)GE_RFA<7@758KxCy1vvA949B@$g%;N}#CcaCvvj;6q*~-F z@TPZ1)6Zt~Z>ci(8^luZpq!W@UeIiyB}LXrq74Iu8H)G(JJbEXuWA$IrXgEkeBc{1 zMULeGmo~8<8k7U7e53&r^e8^|lyB(8B9c@ao++d(BXQ9mHEGWFsn#tea&&VSJ|+ zgqdF#-@A{Rwu$sr`oTlsDEz1TpAfQ3MY8KwrDcyEfe@-2z3-sjY+^-wZ15~QagMyR%!{l zq1&sx^vTMmtLlBmDE+oeoXyq3p@j{|?p~wnT!;#?u~wZD_I51VpDg#vujfXmN0H2P zZ**(Kh-sneJ%*2=%(@Z;WxYx>j96Rr3tYyti2(!2wI-yvP+r&35yPrP7}dTQ)$jhi zhsNEQkchEKc&5=4p__+e(sRc=^Uf+NlLrhxRk0*5){G@HlQRCz!fIphxj#mVMWm;AR9&Pvm9MP=v#_Q%wi%t}kc%D;1*O|H zd;fTU>`>neleouDbx^sNOK+D7Dt9OO+Fjjd>D-usaQ65Qv_fVIZQSeqo5EXcNcX9A za^sz`Umxj0G7tw;kt>sT2ns{DD`pud%H_QS z%9@(Y&}q%`IO4`LUXYru@u?Gq|9Z_`B2pe_q-Q<3{arjKg(^zoyz|bxWCZEq8wQic zHwsw)rq-&7ccey(V=w&B+v>VP9<>WTR;+FDjeFNH2q@3ArA6?2MrGVHPJe-` zRTav|Bhpahl@iywOP*^8T=3Y~Euu~8&W^a=fUr5ifsuRq2K7@JCd>C|+$d1Z5SC1_ zbCY@*O~Jy=?qx-KdXe7P2%w*j>H1B!ZQ{SVx5fFunz>uVz33YLz4#W*sF(9<<`~+!ePU26%Ccs?E7SZgt~H7W+0MK7uHQe2i|A!cDNaqdMliK=1TN z8s)`&S5z{{Sm4Rpn6WpwBkuC|O5AkwlB?OR{SARiF?o7xos2reP$ZJ57yRWUzv_=A z?u-Q|h>d5vlc+QsGWJG;k>)`QmW>)t$@tmij=AQGaJSiT?nZ7Lt-A{^^_v;9Vx^}v zUH6h|qFq?!s-2m${yu+ihVqn#<)hjcJ|!Zq~-5iACtzRiG%fkDpdY{ZanCwnBtLtJ~n&O6@m~x`=Khj zsCY@%=-Ny)_7Sl~Fi|)4#3P=Jk!`Te_Ll-wFxropy2=`9NH0R7-*8;nzeO`K8A>S=exo3Ag=6c)6FmGZFxhT_e7L956D)HHpu}XWN*47qCSkqTb@o_ zJo2ccNmO^(la0m&9h8eZH(&ZM-Zcu?=#Kf-_nwf&EjivdxC|eXy0iGe2MHz|4hut6 zcixo2#Xb_6a9-RC8{%Wv#c-Posy{w4+AHC-v8d5kiYno)KXn;|oXz%`q1H@5XFt~n zFjc{u-xJYVCOy71j11enExvNAl?Zp@Yj<9s5qIeBo89O2=D_}ju~efLl6 zAu}=uF(`#$d3Kv&l{Ksxkzz-@^!?Ppk-0AMm$xh z6FeI`<1&3z>N5Pv3JO#-F2J}((8)|o#*L>$h8cabtJgiH!&!Km+#bU8`lrez4Bs6$=x5rM z+-Q_BQ6Yb$IxU8(q^B~Pwo$+y)i?nXS>$x#R7uktNHN^e4B=Gtx-(sOV-YRQQb{KH zi8%s`XKvSUc?ZokpnRxc2gL%-Q)2`Gta02T6fw41KN7b-C6a)+C3%3txZZYYK0CS! zalgGfA^*(fb2RRFN=ywQ5ei3lr?A0Y3BO1E?#72N78qw@XCnN*%Rm;A7Zsdp3`EKr za&G85mAo00KI)Ccy#yYaY}-h598GdM7%qFNFbcgmJ_;yU7EwW?>QvtTw`el_jGQpS z`D^yVOt$s(N2@l{qQ~=ty+(2x>n}|gmlGy9>ihL4#>P1q z17827DEWunMXHYoze}gXRY>Wjj0{$vkm9nsPWT+v(}GRny*4ln&d3LS_wPN5^(!R9`Zq#14Pr(UuFg(<_UXsXunPEIshhHt*KR z``5)DBU=v}hMNGf#a(k_-nb*N&-e~u>B|#T>)V!z9R=d|v*V!txDZ#oL!L*Jx4G_V zHF4NzEKdgEWv^BZ);&k`8!aerPFKPT1e)qDN7K(Rj(PHm*j3dsPxwHbP&L9`q}Jf1 zzRJ)?;*>$uu2_j-&uK%y@bBDVXFR^V(jZQ+x$K=SM7lWZkA^O|g>xF#?|%2++b-+clowE3@LVq(MF*DFhwpm2h?~l-j|iA2 zrrRSjMMvrO4x{pcuQMLwdB&5J3K_Ax^!|}r!=oaY`Ph@)05kiE!QPX>Q!aXThM=-U z#8EYtA2p?_4HB?^I6l`3-*b0-p$568(A_VeI)5E6e2&-8pxh*Pt%Jtsb8q-~n!U@ovA!t2Q&&5m+p}c$klU+AU0P`h{ z9@6cW$c=lhkRI!2;pgo!@#+~wfIy~3wM%Y>P^cc=KmKlR+_p!Qkp$puJ096^$hRBr z)Lu3l&q@uclE%{5pQ^A{`!wczZIb1BEEagKpwNWC@dw9mSJW6L%-{w@v~?O|$GYCA zH~0>0z=?uW1wVkK5Q(c$vwW>Nza3h&E_P#xO)fFa)qmCNh95jtZ6VF(5#ZuIvz9%8N7KU zEw45kL2~M1pW|j5iGGb3R(tuuU&j{jrwxcwa3?AJ$|K%y8#y13s$J4cXvS6_Jst!k zHV_@GZj_8EfzP9{Ky;mwQoJ@i_(dh%83sCgetuM5_>W@JhSVZ{gdp^dQ=e zJqFl>mkh}xyJGL93COS!`;1Y~1Sf*}2p9IdLeV_N0nfs~)WP96C}at_kLU;;rKX|j zw{f_-TtjW~vRm|_e2gO=UNX3_=&u;|Ko_HrqxypArR4OOr>$jlERGvqhG;n9C9Tz_ zm4U)Z4@>Mj6Mf1Z-7`@5l+y+_#DLBiAk=h-u$#KWvqbmoyH-p7>$gn5z~bskBse11k_bO_6jtY9j#vLa=D9x(Xp!Vh#4Q4ZY$7v~-zq?s z#{VU56CkW3%LR42KI?ir8&cGGhlW$4;Yey&<^^h|PzhM`xK?}b zWYl=L?HNYDPE9H;_e8yZqEm|{o;1`I$Qf9vWokc;f;AfSyEns`HwyWT0bWcIo4mfu zd-2nXW_@ALpN<8smxi4J*Oh{TaJn;Aspm1Y7WWy^@z3>oNn zKydpZFGFgENEUVAu>Ri7Jv*ufa6IYDHEwwL%`0c~Cij-^B{8XHX(ac6E6SFbgY=-_ zEY0Yg&_~s*%(^QcQq6_K#L;NT=iI~ET`Ov1i-BC&nfsM_ctk+j#t<|N#iJfM&(IRO zW2@ILBm8XB?|1e<-?pn&rD=F_VkmZa5$;3kwzJv+FSO+9W0&`H3wlrTA;946R%6^; zGYs1vm**o<9wmDXBG;(|yV&QmvW)!VDD3z9pc8gN`9;wZU_^ev_&p7meo((Ns&5=} z>x}Epd>_{I4wksXFITbM3ky%om^k7;6mB!$L9h4^2yS|D#KX_g*#G-Gk0DSv<}XF{ zKkjMaeur~CAtd0$2jiqxhw$KWO89V@lu+EKz1+OK2jh(AUxto@@tVJRZWLbT?9<|x z?^)WKbhU`0&S`OH|02$N3ki+)nltf=JAOUuIU<3`lE|NxUI7j2W-g1r~1w%qmNhPv#0flT0z=e0yQRM^|>a4 z`tgO3OjCL6C%^RIQwErm@s&!8yW`3D+GEG-BZFRiV@%eiPedk=`_{D)HE|h#=f#6# zCI5zsnsLNuW`0l+x-ss(9}P95uR;udQdxKJCU#it6+J{Wk8Rdvdo_}rm^?pB;N^SE zHN9zKGN$d7Ua>CqqF3xK#3oIa<4XPJ4b>l4?bYjxu26su#no!W9^w>Vn@oYP$O3WKS&lB3_dVD*d`aP8vsh)M5|P-!ed*oHmZLmB>Y z)Nq#O#YQ|2P#t&UDoeDfTA#G1F=?FgnfrhXYV+ek0pewZ(wO@jA^zs-3OvW<@K`+L z>NOco=V8Gi7zAQ!=>7U7oTU1g~CPbfPTo9@lM0Pt{dI>cn25KZz$lDM8Y;+;@s&3R}V zoh2MHIK(vfIODgP9sn_2!G98E%unmUrzwP35uZ#;WCJ+qgBxm$pVYvF2@t!bj%4vUJ ze_cKtALy^lBo9u{^4L(iE5t`a4hz|2u8zjXUbz)Xo8uGrdv6!Lhgz=1M zAoSr>T&52$6%^Q)KO@3dbd>1bradFdx{wI=BXPwu=Zo9@!c6v_@5Awo0dwUug&5_K z)59E)S3Oh6?d-L4CaSs@u7w5BU{Y`)#5*cClqXr5J_wR7G*FRHe zbY&ruiW`hLCNTsqS1(O0>P^px@Gc^LIdgflN-Aumidq!2z?g2>#B%0k2Z5O3iUcs7 z`E$RbEVDE$Y~@HuQ+C}PPe$ut-^5_d6TOZhuDSW9mf8l!lA;^A1C7Y$4!F+^I?8=*yyTzDAXP<;2+$^yMq+7R6oq z{f9sNVRh7aQcx|XiBp{*LMf6Xt@ljMy102?EYUQyaHlLY?jwau;cPaz;<{eqPc|B4 zQZHDGCiPb7NDEoPAd6A7KBLX~HzLH5SgEG9?5ungtWr~?0ex|wFzZLL39q$U^S<%t zIALpy(}f+7@zmq26;5e9NPrzdf?HJ%s8slm-Qq3;3$y?o= za7=pomM~`z2;ibkCHf>c%!8iy6@9R@n^hATFhO>zvz41A9)6}UmFRnRRnsbPAMA=P z?rW$^3BMlESa64mM-3UjsiUz~9|Y7U1M9ZxMCX$rCwjZjK(RZXI?VfIho_SuJZY%E z(?ggAueZyU+tzU=U`uf=srK|Z80`^883_^+k7LO*h2E@yk_rf7hQZkHChYVLap2Ms zgnpMGkO#fM^=Y&vT5w1soBjLyA+#W~~h-xkDqH7SW6-|&jUmZCmEYAX=ACr09}>T*K| zlkeANu1oQ;{$3f%OmClfG)0_xIxecO%0{GRpSoU8N_Rgq$~X@(9t5^($7+?w z=NAT(dMXm2ed*=OD7O9am4ITqhYr(2C2w73oX77{3%GQ}qT=V4{KB{HID<#Ucb8Tk zPt^F{_#wWDAH0?3u8tqw0@3nd{N(xSgw({oLXOBP`CMGKuTV#rvE<$_-&cqbD!?LD zpSDj#mXxL4afNDPNtWErmHTu-wh_#O)P@-!4Y{rBXQ24FTD@QgG#1ymU}?s>zE+)7 z;1TlLxlVAKG2;cq_4^9l?db1|8}^BiPr}`?i{r+9<+QE+W!$7D6=XRCVz^mND)q~w z;(lt_G%>x302juLeUjhu)=xJHJjQ3LG~P#ujn1Dkbn4c_iSWe~;e?GATY)qYQk9t+_&#;9{jCEPQoc3h` zj3S*`Z}5^_*i&Alje?!eANai{72+<4;pRj%YXm7_DQB%!9sUkQ?#g|I3s^{q)=W3E z6e&Th+9!r9En$ZzsypjG0cpu-!>L+a?P=khPNcWx8V{QjF%WCLz_b1#+BGEH9onPQ zzbCl@x;=o}j7EV+iJN0o(jV(RQ;nFn4oAPga=A9dfGU!m8;jW?14&LC)5KwYwi9L} z7jo1Mc|)@c#|NA(t zk*8@5B<_qmsKe(yUK2`Od*g9dzac8v_!w2x0&(8I8}X=mL%*5*!FW@EST6#ayybNmVOz=0!ZKx7QFcdUU> z_#j8)@@ES{T0sbeY5x1dw8p;TS&;#*j(iTF!&E8$nx{wODnlf|!x*p5tDmh(cQc;H zHP4<;{a|-yX1G=r**Q$aSX`&ima+Erc@19gPUwOsJ7c)P*x=iFG2 zRK*VwM%?VC*cj-3su+h>q|_5J-E}$Oy)i=wRY;2zGgVC{tugD_^VfoEIW*}h_}6?o zWF)7UBTQQEsfoF2jxj@9%ro33+!x~(ce$)LrL4DlPA=>$QQU45f?TcaNeF!0?xy%* z5bRtZSc<_!->DD$dXdM?cQw-R;b!@)=yRC^9=%B8?|Qbd2{V5aHPtCd{ZubLwRO*m zX>kVM;uRY8s$UC@6uPKG;6P(pwQ>nSUgYp6qrsgo8AE#6=#RQC_GptPp|$xQG9r7V zod``?F4HC(W9CrL=v=8m_sPBRN+0ThJ^jc z_fm-dYQg<62pr7n6d3RS)v&2Mi99 zydfUc2X@F@+?!oeVt_s54;(O`iid@05^kao#}-d5HtO7cnda~H%iN?W`L$}*s3zI93 zJ^q5v!wPDz_Su48$38DXMvYGS-G0|=9Zq|s1MX}EXZ)alcVh2;$aBl2!-03h*c=ud zUVm+)7zV}5Rn$_Ea5RqSGr5nvV_$K5HcH6|J`qQ~9yN>Nm{3?GL!ILWRG;nwIGCuA zTP9r-PWs5@m6dO9HuNbWlGX_Dk59&F@5xf-Qih~6TEF$LKR5N~c+DegAPvh|FILGc zmrU=-zxZXmUEMNFN?b4^j$Gx8E$^yn zEjCU#zr3e;$=zDgJR*cu_sFE7ot}z?=>5<5QP{kBb`2D9L?46~>+9#`0*FP~mg^b#Y^SVJL+?i7(y7g~y8m;VTs`h1}vv z^|j}ZG>Na-B zJ$4z|%l)=76bD=UA<-7zrb%M6mC!kP&~Nv&V4sEICQnQw(%8jOy;C0z#rA!^;8&)v zo*xVRy9WX9UHZ+nH5fG>BtF;>1!M$unjPduQLmpBJb9NGkD`iC%k96!GU36gR=lr< z{e>`(v`3@Xf@mO2+(b0F>v3{zH5*y9pX;L4Yj)w!NNdl;N~6M~0bMA6Sf$xw7p7M2 zK7F;cHZO%)TWz3Ir`E?BVN&vOptz2;0)#MoRASEdOM`@eO}4w!XpmiFAi9MHHju?` zqDPQXkG>S^U60uqh<-yMR!_#$TNeXf2?B2xZP!qB4gZS^8a67gX$Bz9)Hjp}YqMfJY09~ecdkY%VzS!kyXuxc4w@MJ9u(4y0O4_=~nz2{E zyOZ1B=f49j_8b1+@Ii4vWtKRIXdmPeHDv3xCH3Z%l>|FAkP7(j+lM{B9sNb5Q&l-}EaUe9`@ zVS0wZQEe^Hk@wwFDf>RC?hZdvp`{vrPbPZ(NTb9(kG1&NL&miY3tH8xG!v2Fq9Nk8 z#dZIwt3jnk<10?U~({?Dny0nt{*h(Sm*J|08 zdVz1;@uE&5`)EFXPkNQ_{O2Vcmhbf&$ribm^_$JVK7RCNh=L4GEn}U>PbzLoPtABv zbPjvW3;=f7bA?t;9UPsE%bzRcG1DsW)S3322psv4i{|wTl~(ZOz`XKGm$LeVeMI`I zQf@~Ks^aSB^fD@1ur!Gvv7|b}ovS~teNIHV#67#t2&KzAg6iv4ufi#g8(hSFo9;|E zx`>blag%<(euj(bX5+F9$yr9KsHhC1na5(fK@{d=FlIa_%DkMHC#X-vOpmG^1<7d4 zaxr7#J-{ZPBTTUiWUl5uCr*PSi>FcMCYxuB77=dn7XKc>b>LPH5VMZXxXm9;khHj6 zAKW=e+V2qJMe&rb-gm0|VqS>>83I`Mm_`GGM1OBvPjHD?roLfMlnA-O3;1fv5Tj9F>AJ_jn*^g1?P9Zj zc8zU}R{ey;#!6LBF%k!Om2f1WWLw;)612b>)poVMFz(9t^BNC7y^qu3bgl7jo`9aU z|2%ZeF;a5V>0&Olb4*8JT$J4W?a!qEMDjH`8h7q92oC&Z$G$6hR(Bfn8pM9Pgct-Ew}DhL?AGZ;p2le!D5}^! z8aWyBre2(Sp41<1kC-j?c}`(&2Dlmad*rPXLtTqXY_tQ$i(O3lL6wVFgU>h}hYYNR z(HwT&QKEDb*Ul4;A8s zRRLd%G!M!*T%1sase`C-NeCi@pyqvX%G)O&`*GTsHWJ3hY2`+0CgQvxkin8PAa2w?mWsD{(?~X9x!VvoWcU5t6qA%X_bft4q`trPQh-4}y9PbC7JWN>gB}Vy&0*u57?a@cZh7c$zFZoz) z;gS>5Cu*B){?KR%y?N2YUz83tpSq)QqQK#3X%v^CZD1V-;&TlenZ@b&LRFb}_}Tcf zI+|)c@vl@|d@lbZzSh@LObEd68)3**(w+>+x5gk3dVFW>VFdo?JCDcrM(EzI;S37v zdEpgR-k?8vCZGbSQ!?(^Pr{JEq4<;>IA1&{(n#&H1ELp>g47n59}wx{)*Fp!2hJCJ z9#*CszfCLDuW6m z$hbv6D=p1&t2^143^2RvHsgj99FnWsT@kU<9Rh`547U-3B1y!2b;nDWn|6Vwm`8DW z_S|K>;NLo;Mr9S^!{*bg&iya|$W*<*Fq`6fULu@eL*;z7%%$mbLg;g2obip)46)Ir zWK#oDQ*}ID#702s(d<&(!n+2e)umk-5rIWtS*_jEOU(b_SfxP@WVogKjPUxdPQGKc ziu$Ks#uipU(+d|B_*zdgH&(QJ!dBKqr(t)%*CsdHt!h|Y_C}9>qYT~<>pe@ISn5Q- zHx8C_sn6|<0RikMLgkPV>OfV>IT=>T#D@MDtxh!IQe*r;VLp~O$0qf{({?l_h0UdG zVh^Zw2hrLeRBJAA1Ra|%VL2KP8EjIYcvuCMK5ok`>SD&7@rbHm0LJV+>Jcx@Xx6~m zs%m}hu}zJ!dn5amey1CB?C^B`YyR}P3B&CCWvg-Rb)&uKewOuMBMVZ{C+hkW2b=?9 ze|a_i7uPb9XdZYcb)8j3x*27bwx`^7VJd-7d%{vTpC#_uh>nzrN#Ztym;GKHKjY; z1$U$1;P0vkn_G_jd#*Qtn{K@C%`BB&eBi+l?=MAY@u53S*2H{QhN}KZvpR47uj6C= ztkkx|C;B+O&?SU%*50&CFs;Dm?lRE^CGB ziyw_~?TULETjM8vB~4-@#q)(^;RS`mChCgIo-YJ&EOWQT<g1nHXr2mp#!4)UFRph+EWk zTA;_R?r$X3t+(j|3JQ(5-6Om^T|(my*CPWKbWnX&2;a&>BIZ9|Zr<*(SfEbQX8SHT z!1kVCc80|piXqggD7~`Cd*vdI8Q1j^p+>MA;tr@9F^f3$4bN8}z8TCTrAdvRz{N;8 znvBqeCyG42*`Lk1p!kEhEmA>llYCRJR9p0ngyHeZpsvWc`@}?dYog7ZCfUboe-gVf zgS@TrxJI}ZW36$R|M$O%cEe%ekQ6iHohmGWXu9>Az?ays>i42eLj*tf*5P}WcfA~i-By)AUU((NHe*Z-sw5^T9o-PK3W)6v&wFPVT zXzY8gxV{airT2AhtS3370pk|IL-s@A(2&}+yx~96cfubA;IxKR$1%OR?mD z$&<7DPo8Nk4C7#-cIA8$hUehVxO2vh1Vp{E-_ey_X+i9v_Qq4i*a4i`4j9{jBg%yw0ujr54v8 zy!5avY{m^jsJ!nWh_2cMF^-#z_eP$KHygFO+%80_bG>5NJY641hAEjLcootgAQPEs zESA^CEEix>iq2trI_RY>S-p`q5~q!M ztucO>ZxIkW--jMdQ;7#wFCf(ft4oZ!?Pxh2?o>%?=%Fe1~7_w>#*_cPSZ_*j|w|9G6>Stxv z{qcYX);bXny2rdyczkU>sOJzzwD?(+_>B*#A<2#7Vf|b`G89{cPz{N=;}NeQ(J)5h zQDXx=9Eq*^Xi2;1*e1N2%S)S+x!tJp41pBx@Ca+UdUyKw+TZ^^c6nu&V;A1hJH&Hh zx7u~$+{(qZ$93DWIoazm)-8;E>TEf|l$NFnbib=1u!sZxotcIY8u#K}dPt4fV#S{( z4h!DwxwGPB)x!>%H9Mk@ly5)~1+8I4?cH(I^9d`Ls?1|5A`1rDKaAVr);Qrlm*W@^ zC%u{of(9Y>ams!E;SX_I%{f)4k->taFfhx8Si@4&;=vte@{h( z(wO>dyze4x0|>wMfr>H)&Om&4uqZWCRh_Ctn;sH-&ZiP)rP$*0{QlSniaN@b{)xNq z;W-%>H4nY7KNp{>J09EVv;3L9@WMzV#m_aco^~?Gf1%&xheR&w0Z*pOqki}C0*NbSJo_yA3OsskV-rqjW{+oJ@J#* zzrH@=1!(}ANkW}0$Yn2x{$&7@Ephn^=TrEZ_d~H`kU{>m7j);7Trgb;@p*hf#IR%P zc%~P+@&(;GmMiXP#QO1P1m-FE{!tKveqxOA4n#>NxSGN!wE zhQHDO6y|EC@EPbGi&@5JWm*=^@kd{pP0ZC8#)e=K*|GBs1M{h(8@S~K-S^l)6A-qi zjo^&88mBfMx3?J-wg|m(yAk9a$NLCdwL63WVVUAi!L8+q%Nq^Vp}I{q0gAX-;BND} zOCJ6%6%)j>ghQ;+EODd!6+uv)5g13ET<`gl=j#%6*ha2{Wk%-G8EL3umy99dlcG^z zNQOQTP42%frDU)I&F*57i?UU}XRjd^;mYb7Okm4Q%B)!BEr6ObEk^HC-QF~8UhTTj zGXzX*q&3yL>4EyMvDT<>D4uui?r|{!y-v+4IZ|PfyFJCt%v4 zRTBN0fM24t8&Er5iU1ih5aLWj`CNjJ6X5|o@(yGbDJ2>Ace8T`Z1N~dh(m;NF)2hj zA%vqd*gp8Dcu;*;e({Ug>|K-ZSnbw$$ha2ePcbNXSdEpOdW#!(48kXX_%M<_xL{q3@E zj>ASd^B%tJ-$Sqezi~wUB^4j;j#oTgoVnty+8IYZ*Y*8qgO90UTgL>6BaJB63%l-w zde6Li*uM71Ni}OKiBC@%&(y%gX-#<_f{QcyJM;%4^P1qXa4A(dt6E*?+|FrkcmSVQ z6=+b3(%$eWmLO?=)4!2y#asGa-%M=yw>{4p$|4^P7mPGQ7l!k$zwRZ;L{Ge@x|L)( zQRl_`?hW>s-aha=U;x__AG%@fB;uU-$TMBTTMQ!iadqNl_3??&nL5s~y=Wl3WryNZ zeUzggpJ}{Pr~Be_{XJDu1M!7h5Y2&{$ljup==R!Pf2b|K@^Z01G6y+3^XnIERtBS8 z?x4&Nm-Cge&A#ynn=<faDUYJi(~$) z@smnAdWp3YheYW(f`}R66E8bd$fHy*ak-08dSmI!Q)SvAF|8Q6h(Sz+_7#Uj9a~0u zBjLtzs8F@^e}F6=DrAws|4niAp+fl@*ge;%n@Y=Q8!E_aRjJYlRliQZ(W@dNHQ+%6 zJV>idc*5jUy+)N$lxH|saDc6|O1o&WhMnqhFyT(T0Gu4?0huv;@c z!lKE?5hP|-|Bx?eA}hr#^)-eMX{hI%xQCP8Eu~I7*eocZ%1{BnW`i)$7B3ku3-7jM0A@NM9{Tb%IPc~we zx@cR^dr*krV2lapYT^CcmRKVQDEHA8YIGGeItZReqTSz?;zXw=BSlL|54x)h`E0(g zhzs3QoowP+!wYg%t@mz*)ksUkJV=<@cm*aiwBLY6o`T$@k5!Nu%fbhrjA73hho5ac zDrC8kdSl#G+d6m~rWO7sFBK2wbljeFFN@P-@d1@V2pCy=JSaE>e(j9S`dwL!m*Yc* znIbxp%Md(A?FhNT6R0D$sC;pe%B3^%Bbvv>%i~dZ2gf%NTfG!A^wj;aO(VfEDWe2# zclF{4Ao+<;VfLwdwZYy zQ^twd?|Ebfc#oBZ#Jm@0AT(SQTX~&Q*B@Vk*J8?kc~2XUQVX6oreNuHA1Dl*&d5G+$Z9%bZCFmeWn>%yycJf zF)YX4Rv)m^xNEq8T#V356~Ni!;rMd_q*4WyeuS+bsM9erEYsve&jty)nfs44tDK)A z!+Gc7_*mr_8m30}6W2!Y#1rqLwgwCaCma$75&F~}rMCVvV?cnDk@(z$!-R|+qw$67 zVG$KyUP7)TzS0tOwhzYFYTlOqNb!w3##fn1{#HeU=&=XlyXq{n=`yk6_ud&v0x+%P z(Ei}YWOLw=`lD}!WI;1JYiIoAa;*OuRlI0A@(j=WpHqyaIof3}iWqVbl0fFILoD+b z3&E?@BEg&XqV7B_@p%^4^clTI z6{iluS`q?4B?|{IiM;N`LU4zQ=j!$Pn9L=L8(u6FcLiG68>{`M+c}i$CVwlMAI3E5 zxuVd2QF*a229P;9)yH)Gfs`MRqC|X#8*uk!c+#0Jhu1|4Np|{KFG^mSmIf&_fc&OC z{v6>~;nh4Ib2X+)2eGF%#ypK_>Lm{PEy8>QruVn%XY-;(ahrZFYHp6(g+J2ee@-j> zxI>Lcx=>f&Y1F`_o10?3F|qeTTG*wj@&a|GS+!1 z?m>=KZ?qfQ&}qjKmyAGxmw8L1c%9v%P{IwK>YA?6jpUt)Mm6Y$GDMT7?b7aReo?PA zWUV+-%EYUz~_>0m6p_<^LwPbCTYn$T{RB>|613i3hy_FzF~U_q!ne+_#%O7isdwJU`@FBPttGr-xrWU(DjFnPxHr z{YY%_e6?WF_=tzxO5E^xR6DZ`Ps*)=Q@ovsAE2+a>|*TO)ut!+T^0&;Nh)HWriB!KQ0Pp9uwTWnpXuU!pgN@) zw&S3ubOoC!RW9 zIHqP;%@mo~ac`h}pCcLOe4X$hN`~J!X`D$qKn|!=0-X0p9;rC(g_F)X&S=Ew3rvAu z^U83=ZiurU(*^?Tq=#ZT`{$~ADTU=pdet8mhZ*(w4a4t7-N!}orZ-wQ&VXfayrq-U zba%XMIL(7H+`1q*uu*t(#Jl>kR`EU8-Oz=@JH5PbEE{_fnSY?wN6-}?`jR6O!bfhh z5KapRhWOYs+JwW$CoWsLu(@{0!sfW>vQBI_KJ@@dTb#!GpLqbVSKSyxW56TC1~;b0 zB))KQdb0Dd>54Cf8TS*)>aUC@H^xMKUA=7f7i!2GDZX)Ei-*&eExr}#$`V!sYV1u- z^wRI$OA1tY7LjgCW$j%X<45<=PQt4A$pg6;W*`n1>R4HbD)4;M&Dd9UhNM8jN<0uS}nYgu01Sz z-8z`J*>GHEj1>6z`YL{K(c^K0zm{dF`nb_w8+*I@#^NT!$*5TAYj(3sap2~Xtf;hV z@E_Cl4Zi}@!J~18(QE1IC%}NwBb!moazR~J*HFw+0p7_&F;@i(3u5!!dFlsHWX3Ir z3w=u>!T~Ir`{6^BXIm1d5+V}~1ZmQdR6JS?de_g!XS9En|Cr?n5nZljp7Ke@g39R5G)%8tffj|{B@ znXC!TqYjGEWoPVnDHmBgTDv&l(gCQzx;W_d&1i#3RuS%MeWwm^_Z~K?$#?Q_HL7@D zvl(~+9PzBw{2X!i6{B2>7?P8DRKPHL?~7yV3OkEr&Q73PIIf}o2C>Zv_r$f1MB=2s znlSJrvB+Ut6Y$_qT1D%0JUT6SrtUmS;*5HG=TYeHYl022i?iMa2t9epY7$F2g2MJd zMp8m^-j&)mV1)gKKgc!P6>oY1A-H4s9K>7dWh109-qvq;AKtS9FH)F6#*+EB1K}1F=&k8F~%5Uj4{R-V~jDz zJfG|L{oc$xk5O~~`+K{7uh;u^sY#|NiF2OkZ5UP(_*Esy4>1Gspk1tVHNy;epK{@G z&*I{LthNZ7C!jt*QCm#ga1PPbSA!8gtDT_qIy)4fpWnfuq1kqAH zZaYkM3fsTZN)XG*}bhGVM z%W5$cMWW&(MuYV;44z(tGp3AOy}m$6vg z!1=?pdc3J51eUs&J!QvGg<9f$>zz4 zZ1(h0w9w*(NJZ^bwC)pIeD=|TVN#gV=9R`Lk1O9F9Ui1P@$nih`xs2BXFmv6N22F_ zX4D=^0w;~c2tYt2=2))@!K%m=I;AWd)X8ra#6}O_P$hw)LNav;))JtzM=LhW?djFe zmC#vzo*b-0lH{8`q2DZAxbU|zxKBv5;FP2m^Fj}KA4oK^xnr?g%S9m7(Re@*&OSK?Gx4D2d_7p> zA@z_i1aHQ}TK$c`j7L0lBX&4=mgw(`{w^LrQ~R|vko$-nI^%#|fjShg=~%&WJE+P4 zxGAR9%O+lo!8qghXHhQ*6d7nv_EZwgd$o^F+D{6ql*TjvM;I zi)Kiv6J8h`@sPQn6cCkm7?D#xN$o9h+M{HAz&PU;z07MU-qWc5xG708wtq88-2LX)EX)u0tv#q03)z|+eeli?Lz=$@mU(8E}j>n(^s^WtE!j$A2 z{jYK1exa{SUG-92w7=lZVgqxrtECh*F4?bBKbQ&RGydJBD&1a4rOWo0=YD0w^0<6| zL7|nA?VEB#=Ij@iZe{(`nE47rQzC@5WQ{A;wjR>rDvi!L!E;g#x%erDoQ`W$?RI$a zYYht_X*kv61m$t3i0$G3irJ8dRUoqNn5UjAZAACI&b7;n|a9?aPh~hC-t=rMSB_!q_i{CF=ixqJxCkTwgMU!Nqi>CA_l+-6$;Eic>zW~Z4y)Rouq{X3 zemPojV)E36%T!xVReH?B%^oET_Hi#F&uJPyoltA2z(htTRg>|6{FLUx>s5?nV0ccu z?d@c^V%g5#yh6uAIOkj$im;|BxP2*dMZ?FB9r%JzI_fAU6PH-X7U z#9xFE>xUulFZj!uG=;^rsxK~70URmvpo?6qi5zHg@n3}Ih#8n6Jumr7L32=53gvRC z>Si!bq_e7uS@? z+_3Z2U_RFMH@NE(j3^cuJiO*u0Q^eS9Y|(4ZgfpT*RZ%Z{iPtl*3rx$m2y5TYW1fI za@fowmC=}Q(WprgfFS?cId3ffmg@YSKXQi_>o*?Tu#?_|eEN`vE!DWih~kx~SH(*D z#y9x)5VD^}Lx<@iOVs2gO0S_JNnZ7rLN1k^ge5_G-RuUdN%MuaD6Oc=S`8|1 z+Avu%qRq|W*0}g-G1Z~wWQt5h?;5Y}NGEj5+P@SOMd12%{xcCMdt$v|BALk~h-x%8 z82rwzuGr`~uMpDy!cFM6KQnw8jL$;nK5!CE`>a&6NjfAO=J z@-$YH_jZTsl!S);aksi`2bmD`RYfF&&damQ3!E3 z?XF@falijik8p>hN1Ps==1kb~fLo>rCLT0kO~~>d@_4X%h<1D8VNa0PPKI+({g0?I znRsFU9`$Sy`X*lVn4=_LDb4MKV6&yjH z%E2AM-RrQcG^3?WYoen%%9sM;cv<9TGXiM&nmDFmh#w!vJxtFO2;hW2QXCv7RjIOa zI8N#3GRWrBnsiZb&%_xo!D@tf-SI|kac1|%oBlmTsQ+fT4~wr2(B@78qQy7b!xBuR1nBXe!a5Y&lJ8ube2zFX zeD7r)OttY31^{bpyv=ZK`O&3$ec~rW%ehP=v^a34_>1H#e8B;s!YxVCkwfHwI6gpx zOdXDk4ivNo=btf)FLvct%t5&8m-urK{SZ&frRo;{$$_{`{S*d}G>~z*`l${T+n_lI zEQF&-0yipVgt{vZ2%#=-j4KZatwY#tiL2DSGBi=0?2M}q2yyak12cE+8r4n9&Y`&0 zvs(${Tk&*OqeQPtfRP5v{s2m`Uotyiv& zW-l+hj#*xdKo;rCS#PZ!kyJcZqwRo15^%7jElo*Thhb{r9bcoa$ObtBgSgfMB6b*! zb?%2aa;d0XuknBTo1eu7k52|8UY?EmD*NzCbh%YKMjssI9z%_>Lhk{Kgfsfebct)< zCrDD96q^kvj0ZQ{zU9_gVjhG;6itKFmKTs_9#Jw(RZ*PkGG{1r{xjPu`-|q!M1d~2WDJ|M<$Wy?a}KP4Vk-I8xO?HnHQWhX7wuFrTMIh+JVND^hg&%n=r6$fe!lWa(d z=s^$CNr)iK@umgl?QIPN%Rc1F%Mbvh6G0sI)}#*}(pUk6njB72-4IxzoQ-3KA?0-l z8-U@s|H4r#0g_=R)w@ExWtEc#^JjmEQyM7UE4US>y^y%-ps3WSX{s1+=r^h7P*bYA zOp-e`k{rxi26k*~+SR-*0HMoyjX=W5WTFz%Bm7rS0Pxnw#J~F2(MFgYlV4*_(28 z;&TmxBoBWT4U+l7#^OsAVDJc<^fryvlwMz}<}fn2t?`Xvo9aCMr})+{H>-zWrWo6# z-sU^^kVgjZm7e%saMWR>hNJrS_~C%~vF@78F@2qW^nw%}4?$l&5EzCiKF16;0Nmfhac5pz_L2q7qWHwzD!f0Ic#7$>%z0m`Q5hq{eqmdyx*7Kjt6KHA zDg$pdsvY-{V08rY@p?2Ao1j%5fn0e*(d;4&TM*H;)Q$zAz|Ovi5T?~@S2C>=K#Q~1 zrsf$TxEdX`21G#Tp(8B1A;y0_4OG{6~mHsMxXbk1@UvTVVm7+$xFk02Hn+`bV%{)@feN8 z$g|?KU%?YcIb}wD1qQ*FS|oy-4$nRpllm&LOvxisJB2TlhkmLCA6e_+xFH*2hsI7p1tzJ#pZZ-%0)2y*}a%E8{*-%*N4izc+Pk7z$~( zXW7u)91pmFIIkn|ptlP%N`>Tj$bVRYqH8SuXC8L-+tR}M5dpL&>7;G(sCun-VWa!l zvjy#!v|xB=6g2j@nv&6+bM=Hl$k14O1opB!+Ty8a^-%HdB&96*)ZW@3k(=b3R}RwC zwZ)h~JQ>e;UsJ-BS84yVXVRn?PlNPr=Y`9FB5^_b8#XP#O18;3VFs+$r=3}c^L2A8*bgTod@Dgf1Le4K=_tF*3U<){I;4`HZF>@ z`g_Xcs`0M=jt_sl=lUyB#rb}%r$eCRb6!?NG-)5};|M=7+P^J6^g@t3IF%alk$N2M z?~jkw$vE^ucYNYg!+U^x0vy<{#Tw}-M0AJz$UW6Q^nA672rcj>Fjxx^rPQtCXmKOIPkqE)>18Un;+B^ zFnE-pJ$@7vD_1lT-cG+s$cYcE;?8cUu6?S zEFlfl3g7u0yBe1qEV#4|-ErC|U8+ySpj{c|_cHafB83u{A1o$w6cwKtZn-pDa}E~t z+g&9I*FjTsJnw=DsLMlIOx>|s=oQIw)_a^36Inls9^js`6Rj)9%gcu;f(N=MQ_ z6a)LF+5%*f`xihWs|;%U1iJ=CYxaU{{QGFp&yn~z8iw{nn@8Eo0(59`?p)c> z(G+Vul?)Zo8EgI3J2-*#b)Dfxp_rzo>)l5Ouf+!S-&PB}wNYgN)DvCa>^n2PQVHAG zT(Tx59%FGVmVJ~xp{pD%RBaqzmLs=4`L9&2i+MYH#j|2pF@H%nLdcA5d*au z`fb$E-!Yno!Q<+Ngm*|eCJh1SflR=$&C3Jk%lH~GrMeZQ{##;)4#;_P+!V*$?FP7H zX86$9>7fW655C#u-U;xWTC029TOSeX;$H91cu(BtxoqbYR7(!j`(5+wgE-^tt~Ki% z8;S?C?__ks1~6Zy2Q|j1&0YvUPj zYdRSgJ;bZ;{8Q{VoS@D);7+k}%wV1ey&Sy2y!dG)I<3m@Jj6La%4=1K-8k*R zk#r$|<4m8?0{jm5&o?|)M<$$nQy*zkfQC{Z+!gTt+wO3zNb=9>ix?bfrS-1wIoCtZ zUoe*fdi8L;?*r356z2p#k7#CC!3fr?og;tf{;?3_ng2*b`IA}@TdJT7RoAU`ZGj*FfX%H;9p1-bY+VWW=o4)&M$FZCsq zM2d?qeNHTCI~{SuFMCcrTRRIf`>!~0K38xvPI4IbxN05(Sd=R?7Fa12&R41sexTgq zt29u?a3y+W2J^mJJ!gtgvJ;bXOS3D~U|jp05Q6AMF4eK9sQWw9askvSIGPhj&C_pI zVtZVt-<1YX^L)bx!_E^LH#}F+``m@|Vu4qZJfQut&})P{EidAYUXi3JM)Q!yO;p@O)Q!CdiM_UfiBzN-l013 zx!R~!V>qFAsRV1~V!hqt{_8VvK6=w$Z(ZGJcl5c-JF%D^ip@IO6<^8{7b*r-1$3CI zlp)U?w2HR!xq?#be;uQSxqW4f*B0(yVS;wXq({5!`h~Hrc9%d8>^s2?JbYVq2sUDe zk3?TdqnK#(ZjDxH%@}7p)f24mSnP7chUyqv(|Zi!&UgM9f!)0xB{Sxgy}Qo~fUqyq zg2w#@X`JXlyS)?p)2jag^@ATtS|B~>W<5$s9uH}bo2q^Buqvie1b6ol^>_APd8Hmz zrEXkiAM-+V@KB)Nf81cTLBnjp{Ue@mIjY9IX?qOSuOTm=Qqk6e#|dp9ATw%ZPdx1d z4ZSLE@<=@MoG4D@Ce;y?pBXG`zd$VhSFgkYeO3M;U-~%cFQOx|i_;o-_Q}niamcOk z8Q|_5_6lIPi6dfX992zHCXL68e)A@E#xaB5e#h!K?%!#oc|yNmKh`r9C$%uM`_NEo zpOfWee^POO+WWkWcPq~LV{#a#?Ty+qA+;fj_BU%6I(57$?;VS`)B>vk_|La%+h2_9 z(LtWAt@B_pNO{-ofgJn6B>Cb!%@eyK67#^=y>AGLX5w6}zmg^n4&eirPHf^G{IFK~ zJdfvL$cm3NXY{y4i`DP-JAU_v_{2~U+c_nMpK3Yq{E5%pAMYxLJlX(+5^0?Lg=dcf z64h|JIDBd7Nq~v#e|hr1(k0$JUC`y`u6))nm@bch+sYMj;k0mK z9SqM{T%>}e<1SW%3fN*xT%uYI)PAYkpk!x}E}Je$5HV&~T&~}h6|Hx~9Q~f^e|=Y6 zp?>GzaD7}kEtIO5U~!c}srz+Ytr5FGk_0r+7%WP%TGy)9@aRNT+#d6`w8fa~5m$Gw zhhfkZlAFhK)egwW(?>TYRuVZ*~#&^Q5A^+UXI^Q?u0xq zs2o++Zd3JJydd?vRzeRgw~bWR>hJ7HJCodY)g779y1c`QMtkQ3kg5%LFxS_4_(`oS}5Uz|x zs|RjRVn5oZMGoOr-;X6dx2D5?;Y_Ea6MtD_5K@lFOT5+<@JqI<_PXhUYtXQ+cNxTO zYJ32A!?ZpAGEs0k2W1QoQvM=2e3!b$*SA$`CzX*f46>!7dT z0mU{ICtD7;sFoRo8whu}pN0~l=5B2c#$;G=qTt!-en*F=@B;BiV_GELqjp6fML+@< zrS(VL=T55I;E!3r`#nV0_KZHZTVKV{awZ<|1W{cjpbx4kvIock$i;^=;bE*KAFgd$ z5v?R6{)iTe{2xQ{sK+3C9P9Mhv{-cVhGgvde8}J!RlU-HsNxCrJ2?Af?D3lZ?04~$ z0Vjk`Cj5)N22~;LpEjs<=nS|@&!{_s<`9j*uw~jWLhp0L4!En7-lciqK{W+FteBSV%`zGQ|L&|++ZkXy|#8caB>_p;i zHJg9^FE_?ntrvt~GDq*~IcesW78(RJ&wKu!8^dJ(Io|ij$}#Z#IZfd=8{z{EKSYX$ z4_$*i+&%G;W`okR*w}yU$+ZYmed4OE`Fecn^DuxWV=O-NBq06rJfzdo=dR6Z*b-lO zw+NIrmM)rKdM!}4##bJtNi56Pf~^&W{5Kv0qz47|t^1f5njk3hV0`CE!0dkSWnWS4 zn%&Er5I1RnM2lbj6yuTCIxtM!M-;qgJ95uk~y;;d_fj^?5y{ zj*dh2EJ0G&-X8OwFNi5A(zFUlvJTzVb!wk96-2~*_qG`xcqndgZ$bfFxCPIjDVkWa zcgI45i?BC&v>OE!Z!!&UayNLQLLuF(np>+~C7bFkZkSH5oZeeK2stz}WD}-3nr>w? z%rl;ku~<{cbjVBea{x1-r3R&)XQJN2Z5`f>Nm7IRhjK_=Xrs3fT0Du_nr~f`;C+49 z#Oudnl^3Ddrbn{?Xdt50Ac?l4MWgl;sj*e9Do|$_w;J-)7NyoOIt)ik{{R}QHHI*g zEUc}~2`rzF?m9Q^Nk!WjB8>I!xOwGm%VUE-8WY29JinIdU)JT0GTd8+m+KL1q!Wu? zFU~Mn(cO1qO-_OuOj`vDkrYN_Q1xy{88)P!6UYxoyaZ`L_U9P&pkN+O=D26F@#jB} zNteLV($_Y9B}(LL$}8Vg#bT03c+VG_VyL<`)gCFGxLbcAAY$fxO#Q)5H@OWHO&F|Q z2HeUBBKNqwP=ft&uRrtdf)DP~LZv5tXWZ|yW^@$1zPmNI%If9ufZ?wvgX@F(b8~f5 zJmh623>orM&uhhK8bv*#TEnPbAJxwuUg^hlB^UmOc)SK@?p_KAo=~mTJXw3RMVts} z?4Hsvy>v#9p4ynapYgOBb&pTPGXjz1klnH04+>rzHI>u>6}M%EnuG5D1uHM7J-bHi z2@iPTaT*h*4(-oO*qAm$sW2Pnu4TfjvLHXiSJH$X&^4RUMD?V zrmsKc(}?UyQSdaOO{~Hh7r_vL^d{ns=S58L=uD&7|0kZH>3CB;7sK~I##{O-&>o4m z)z|euC+V^mgc6ygoQQW-de^+4$9skqoJ1B8e_)Rot9ECITX%_woUV!P_U z6m!{B$;ZWq3N9U<;2Fbw^^hf$f|L*hDxd1G|Cwhy4WQ>95(3ZAru+$+WXuyh!Jc(z)jqYO8=P@u)AB2AUBP9BvxViSHC&5w0W-o5hoHAed zc-(5B(Ny3@h>CQP*Ru&n=G9!q#Tu@Y`y5L&-`V3OxbxCOg&6tGZ?BJfH^Sz(#D8f} zMRFmfxVurM$Uai`wJDkeKO-}JG?kX(WbhK#r-%oIGTJ^g%4T;-) z2GHXUM2Gh*anfk4Q8gS=&^hY&WCn6w=O)c509mgODZ@7$DtC!Ni7&uTsN7MaJKZ`*@F#r0E zznvdLhVAUXaBfDlUYKUglyfv%1LY`xNQKBujBD+C$46qacI=P|vS@#dZC;H{#Z_R+ zUz3P6I%9{%8O}o=cN_K*)Ui9&;p@-gCFvF;ywSsPkGtnFN3h9m-m6yqQ&0`}`TVWs zorB}KUoF!%2<_=^ABxt|Ozk)o54c}4c_lCDNu@LcN(Kw8cu2i%$%Z77QkwZS^ zKh%wGD$3y4tF=O1jdb8?O(yYQVw!kHu+{>z@7K28u`CXFC);v`4|>3HGGtD>pgtw2 zhy2l+J`9Hsi5Xy4nQcA2@lzppRCQjzr+aF9%=mKrO{!`*Ol{ggwHn90xF}e-DJQ)2 zBdH%`nNIp`nf=F}5)uPmQ%$=^w#R7!2}wL2XVegs*Ef)wkT<-RD3s$(!Bb!4=x=!h z>_?DYV&$swQH-T+@>z{XsDt!I%aGyksv|`Is3Q$4sRj^uyzevA)IXk%JLgo$D~-=u zeBi>o|IFjV+L1{6|Cf_FkB_`bjj7YxED`nhoK_3^2GR#rF1XI^_^D-q<* zfB((z;tTgwg14u6%aGT0ml8 zeWx)~Q&)}eJ%8d05GV8pPdJ06&BTv7NVhk|Po8={g&eqe;ct*h27o6o*9!$n7Mkpj zap4OENsd;xX7G!+=mp`$<$&A?xqq>~75s+DUGhS~&uMOtLx|c|iU%eZt}5#+o-dcX zY;s~S$-6l(2zwLLiu3|$fqjL*u($1%9(PMRzB0~LFPur%u8x1=>KBAS30tMu)YqtK zWm#s7h-=+crqM7`GqRR9{|0ir;7jLFq?Lh!Nt5TUq2$T8{CWnQjJ?&j9#)l zVR5Tqsu1O*8jA$MFRot@i)*VpN~GDrSmIAx=q@$z5G054+xN+9zPRx5ox`Ue~g0d2IA7 zQR8N+dX7z(N?8SbMcijkMz8I4pUu1;q$yD~Zo#40>=j2ZTjX*v=w5mLM~%hB5O9_IRhPqkZ>jem&AS_yWzT(WHfZK5m1Qd0&1zEA-Q zcNo@^SugH(aoTy5kS04{(96Co*H*tD7rosEwV|3K!+1dVCq)JY^ar(c)gEN*52@WS7zSaj3MwNw$3EgddS*+= ztw(+KK(JijqGNhYP1EkU8jpMY^q!6CQXg^sNbgLbq(>9w+0QWBc$$iQ=+X` z<7tCX2V!}~a6{N2y+0EBRWVKIw#5NeOyV>SdZBvBnUG$gG3{PDpoI@^laPHsSnZ0DSfBH z;hjeT`?Stbl`DQmW1vhzcQ+Vsc#Y91rm6Is9-?V=d%WdkB9#L{7jhBbRyTvy&2d&0 zdw3P%UBi<0)FgZMjBq;xgL+vI|MeH?={b#;y4Os&_<@_INC;0$)y5bNC4Irc3>~kAwc5JKQq+EYJP-`YLXxNNe4Cpgw-|jwG>&Rv>=z zy0`yBbE3pJEH)C-aR{^53l0}#vVLJ)c(`DT+c62e=&){VT@M#HWnsDl7rQCsH)`Uz z#Gg&#;V(U0a9m{#5AbCwYCwRW=-0oh8d4~)3 zUW3bmsm$v%=pgS)%y&bm+P<;4p*Cj{{l4?xVu31x?K)$j`dl_V0qJ+6ph?S-%_$_m zNfqz9Yr`MnX7{+NxXs?89?6PWY?p7<%vatPiv(6Bt;O@&qs%-katE}X)NqEqD2r9<7X@hEvt|KBNc0w+ zieJt9L$rE|iDx=zpN}>*-+cOy-O=IUc#p<02}wcQ8i50fKsmbBU}s3<&RC~Thp}l{ z@AX9`mL%f_k0H!OCKI*eHBYzPE(1ISz&-8}_de#{>xJN~5_v#<;?BW&gWgoU_2r}w{9#s>k z=_GS^s3wAgLTkm{Ziy5R5{<~}8Uz9kz;~&si|)}XRT@^sy(&m$G-A&CbbzcXh@?`i(PmH6B)jWM&`HpDQiAS&tglK3>~A zj*qE~4AGh&bY%sGQ9WZb`NEQzI#O32t%sI$b;;x9*m06g2;*iJgs`eo>kHh{X ztvn{%aa5lm`QmLgDc*+Q|P8t>~K-1dflsd14 zKsc>w^q1sTXZ!$i|Dom+kg<|E8Q*Qtly3D z3}=R~cvl1P*d+s*N&Zg6dw$cw39r6$UkVb64CQ?vka1pNQk;0T$-h7@u)}BmZ`Z~T)kHxYfui%#|MAn79=~wE07^`E}@@wtP>;F6u-*{Xy z67ULr>mkVZYs-=E40d}uO<*jm6O=BisU#sxtXn9qR08#*s-!F{mB>T!lSbQ&bR&)k zU(N1=ro76&IK_cr_FI?uZns znbH=fR3mg2ABxLe#LF_?A9Id~uS_v6>>n(ti`!CB6<2CVt_tp)+v6%jMD6rWiK|sS zFh2W2iVv^RICv3p?XEpiD1$WNtO(KuGypMIUDVP(#Jt)p(nLsO!`Ey@$2VUkU@#D> zYmK00T%cM*RZzxgEIcA?mwL?+LW=Q{-RLQh4g?+bO`be)EQjJ|PnW8Q)|l=sUQ?DP z6`i;0vl;R#w{4NPhN7uhtdHDbY=qnn5kV%^S?YfAJ3tXn%X$M`Umb`B{l4pZ>}(qi zZpruqp#^?wa#uFBUS;T6U=ByK3sdU}d@b%4CMsHMW8(ae5zT0{sW1(6qr-(cLb)hw z-0f+m(h)3H*B3C7&f{YlG^NZH;rg@kpV9Dz_1orI>s~mmx%s zpXvU34B={C+g=@kUW7$`u0@E@t<_Dj*|kG38IE0@~rGyxIeq&n@mgBEPG~iP?Y6 z^k2ojfo0w4LvZ#HxZPc91;LNvJdOJAacO%$)4JEA^3AWhm9M^&v% z8`svD@hDg`5r&BW;@FYGk8B}ifuV!ON*lTp9n6t01-@}aL0mXr2uOjz)(Y{ar@bOwaNnve2_jmkoVROF5;@J&QjurotfqjL z9WnvVBu(*XAIW!TTi-3Rnb>{XMk8Emi&8_c6N~m3;|U9a75@mr5^p{Nhs&? zM+3>@FeszrpL}{(E-%jHg=vqYLX6-5I*SXA3i&N-T231C3y&7`3XcITdy#7Pmk>RD zaq-b|ZW>m{C8|}yzN;rLb$?wGJz&(h?5J>LN-K+v!{tYXn2B;Y3L1?$M+?&K9Ksa* zilY`bzrcw>{Q|vnrMt^_7}LM2JX8Z(*SPvZO}q-ivSv*$T-`#swHtHlU-lrIr9jlf9hh@ zOusF3p#lvTxxrW}z|(pMwkxkny{bY#&+dzc+A2tu$QvJx?)mHB8 zVQ=k4%^%JF%G{oV(ek$)O}}$5S&v#Z5F%&z&Ni2m3$OzNHR6Fshk9P#)*fqAwX&S> zX0cX(PfPuEHCX;FAE#LFY9nc3y`lDj6+vtiFy%lTi!Lp|M2c#9T&+G0WO{Ydip(=P z?&$OKw4Oizo7J|`$zw6-bBG}Wgeb9N-B)WJ?pPzLm=XJ9)CFzHYL0th`glHvW71!E zk5X})d!HEZjVU!kxW+TT!*}3pG1zAt?)KEtS|>5O(-Xuk0X(ovfTaxr*bb8+1KM3k zLjtS&JAr*P2-J3{#uY1Xy@r4L{+KZCP=a=IdeKih`-iCyKzrK<+2dN%VpG2~qh=aaqke0-g zO#}j_G(3Ftak~zAW?N?WZHmLSLx|@Pugy`HvDbYuqYnk_Jm!+R)|G@=_XlEhxKb_m zGK|_!>hD-hf~HQn(z1!J&N%I}C~;%*W^)^hclBERr(eZ;E*cv_{+C*a_uaM!$!+o;=e*X1 z<%|ymN9*V?p5Gs;sM20Io{xMGrdY?1wR8hX$wAzHqWLu7*_xVKdi_+D3E49kpJ|aQ z&8_jddK^x(p3eBf{Ua0L4u4sDX-cj@?4xGlD^-Aqz_%*C7Hqtd+>CEjl=1n9AoHzZ zyR)@1z7uREeFa+d@4Xe{8PV_u)nn?t@uS# zY%Mk(ME7~IV8sk88gtY)?{e<*75XY%`73dyJ0a`Ee~GIE?j)4;)h~)5D7q)74~}bI z6sjMbeHN3#xK?AVzYEr?qTi6UaG9=_gwWZeF;7Em#rl*?nl2k?&y5gkT8TG0)Qioiw zNl;ZfGE#M{Qb|`@t2cYh+aO`0#Z5BtM5_iFW~B-uZ}Xre%PNi&9p05>6FAUE-uYjU znrk!;@fCkhfTFeMw>PPubsniVr?B2@kAV(3=wpMxURhTk8(nfIqF^BJda+Pu8|Fuk z+jnKS@Lqp#{05@WP4IR>&>fpy*4IzQs6l_+me2c;Kh|W}{t>UqYV70tWAsIlYpJhS zRI?b@YP|Cp(%i|vwj>5#ZC4dv=R{1YE6f@))Wwe4?Z~*Z>EU{JZM`AacDj%^NMfp8 z>KP)I?YqZ|ysA0`1CAEc!ww)5iu?Sri3EUgzvtXu*vi=LD_x{`l%vUXZJ2rZNkM=a zIwnFcAV&nAnEJpH0UgOBE~!V%6p!iyLu*K#$7(Zv{+)k;l(B{EAPCmvyAGrVRbqOGV7Ils|mpPnLCz zv+$|F8HIBGOqX{>M|^(%d}8KaaQqiu5XL~p_obH#Q-b))C98?RHRYfa}NE4I& zm=S_$p4bLi6Bp=nq?7PVz=3DtX-QY>rk-4wGD|zaHeH+8zsM^sJ^)LJBM(0d90FG$WQA-sFCv=rV&= z+^lbW9Ywm_;<;eEe1F_(h|{UMKVR2HE+xhS{H065N=G=H&&Lu?eE^NkQm#v^|jouLMD2lBn0iXFCkQo#zYLzSWB0VK1i7KR#$xzQSVjJL)qP?lC zCR1#ye{VuT-=;w_-cg7C%tO`}YxHMAzQkJ3<4!oKSm$wm4L67fiua*?`<9Hawm}_a zB)Hh9iYSeSh#1!8W_NJQFs${u-howTCIjp>JnbBbK97d#5{p`Yoc-T8d=A!@kW3w* z_Wv0}g0XJx${2CQ){Ln;s&iaN%mV+pFWI6=!+?YY!<20<8tEJ%UV)3yGh!CI!$suN z!Tn^$N}d0Go}4%mJ7+|DmVDA>0|;H6prsLB&;uIUjceL<+;n)yE0L3o0LslbT3--mX(V`p3uOwB`@Y zX^epgG0wQv0MBu};aTFWh!S`#-kdofQ9C2yme`UA#!kdr-iu|KgC^c~Gs6ECCi1L6 z8^+TANhFJ%@vdgPWKq25gNBN{MET>k$NTOK^jPhRa|Q?*!$f@GkFg0PMjz?}R0&=B zktWs1N_^}}kSGMj^Rg6W4)``cb?;abu-%`zZswtg&ubsEM-jm4BLnYt#+NSP`c&hq zS`VN;TvNO+XCF#$l=#MF22jbF~geKFVh^PiH2{EU`IEUkMRm5U+D(1X&rsR?b zjc}0|w?KM@L4&gE>cnIxu2c`HnNNkvRqkN~1J0{G6wei;@-;6NoXe!+T6cocXS!!j zM@40ItD9r48;ur^<9Y6G+3n47ohC`(Xf}DiXN=c9!46&$0ddDby32t%J*&;|k-)T2 z#YhbjZSIa6U(!p6LbVSr1BDn0O$}SuU9|Q$yMxqFKtSH&0t)2q@eQDN2 z*dI4Z?^T3#iv@T|)4fD}w;})J04&v9m(_Jdy?%~v>WT(Wv>6e9qq^EMFU70aBcy^jq*1(aD7A*;{6Z-X5jfreH-;Fj6ltE@X40tjFgPR~T)_5g}JqF%X z|2zPx;5-rQJYIXr+XV9TH@766SYw06hui^s)^@c7+u=>_s{J8d8uF3u@lYU}@#yu( z*aRPa-t`szd7L+UEtg{#$Eh52%_2k`a?N2l9}I~I&PJ?owt!mRFY!$dd%^d1*9a32mQNo z7;Nh0=-HaD-NPQ~j-)_~E*~=@^?pZNOFZg%n_A4L?y=eeJ^`>?#Y{~dj~o1BLaiRI z9g+JUm8>A#{|K4ARDxw945*+T9?M)EPpbf5i=lW%eB{c4R@R2oGb&{t!Bi3ESp z8<1vG6OaPaFBQW67e9|fde88nt8ui4)nyYG;HaAABTjtoYRnke6>v<)^!s;zAe8HI zcaOzu(Z-)p_y1{Lob+V#h)%~TbzS+pKg4M@Ay5b)p*=mL8K%~AOT3|vOq2r-RTq`p z1_|yPZ~645_<)6Z+lK?!i}8tWtkTa4EVS^bEM2#OF*xb()s7j6vAinpyXTSF7hXRW z=lqp2mGSt%{S2bc|Im|wQs=$;NMGgoKprblD=o?SeB$+4-F;hpTI(Do0Q{vv!9qF3 zwx7E&Q>YUn&;1jXh&YE|YGqOmSOgefX#`Ynh-$y~c5%8`oTTi((VF&SD)_B?ZG+(^ z=z+f`v6)17>C>4(j>mcn-}i%Bt|Z{^j|PwXiZ(rd@=D>H2>Hnq7st+|jSpgLWU|ME zKZ^-<>X0rxR&dVo=LUmJ{>5cA{oX>etZ>p_g zid&9zI&MBDYz$rmwW83}_i7F_Oy*$Rss_+_PU^BqD^%&5n4G}<9NL@U?3zcq)oqU@ z?h)?29E+ufU|{y>B&y{4V-C54@)Esy9*~##fBIy-6b(KXX=>i+mF`J9*d}#?cO<4q zJ+VrQLl&fH_8!#nWVN`-)-^|%dhGWQ+Z=O9KBQ8TCfkd@0M%Bsf zC~wD)mFKy6A|?$xgfBugEOBC6?JAV`gj1S$Iu(=BL?0wYhfuv+Ahs#-XYBOIxARWy z^6%Tw-`wMwbfk?Yq1jc`pZfay^c%}Il480Vi=UphyS+}z@x%pvKy`~m@Iiqw`@#s3 zOCHiJ9d_hIJS^~$5+`5t$T9Ori5y=ns*kkiA-dlAJtN*03P*6M=Z!fzyZ?A?UF4n1 zo<8BfY(bVS4dfo5d_d;S%kc)|DKGjuj$9f-?iJi{h(qzT>l0BNv2SXN$Tsa!2L_Y) z-|yC(NHk6)oYr-Qh$z{e5+NPbLN#Kxo~LwLn>xfvJEWgI5R-@9>*z!#b35u@;q(d@ zFjHHUB%dI7^YtuQ432pdKu|;sh~sXzg5*Snf7Pj3@b_`j&kPu3CkniDH9S>o3)=`9 zJ?+n497s9OXADr!?6Xi@Z|DnS^z<5g)58>{B^H%$X&x04^}X#P-pdl`@T~U${*qJO z4R(6hHLBb2Y-5++t6lO;bCX%o-`55J#BiK*vQ}v!PA9?JFx1eL%f$0eusC|#ht^GnDmBOxm zsXpN^aSW~PTd})1sqtKh3P z9vAxqi|9YcB`=GrhxJT0qpU_;`m!~lsq4W7_A-5^TTBUkdb!5NR2Ri^sxaml7+%y= z9uch8W3<$@*Tt0vrYmLL@U1VODdfW-$LDI*%UHwPQXO;9AfaIWsNJ^AuXIa5(x z*huX1=Du9WjPB~@n5X{M<)OLGLv>_kTYN#)BfNiJzZ>+mJfokH9LylLC9A&BeUoW= zB5qWNgr+C!^vi{$D8c>{eI;dZvs;q;p*e05nBYiOEQSy^~g8v5{U+|O?HztpgH?{-ZvCO;0fNv2-Kz5J9-_Is z6Z8gPTYs<kj|yTWE{923LGA@$4)#@l6-GE%dx+}3z>E116qx zLGtJE!ONmm39F3}8zP)S2gQe~zp}lfJwEax!5@;VBtF(^Ea2h#qy}!v@d$W|dgW8W zqf^HV|CtA_NBa1=JK6$U$~F2zMeWtW-uSY1&>rXRycAy=|nw zFQ}sMt&T(*mmQb(vw=vq$Mw2_X?qK|9&=oH*B{~v4PNQO>4%lM@_0d!l|S6IAgJCyo3A7azVO`!CbM+g3us`Ox1F;C#`D+XAzht6z7d=SU z!NxaeI;3$C`IeY(!EsB=ODtIyVxd>1ewZV7qq^%RY#?#hZaQA>^6!5iH@i|@icW7i zE?mVj6d*fBL^NrInzYz^liRnn&JQiKWg^i96lN8p0%1$@|EWJ7Rv#(v0#84pJtuDFU_9#C z6^gz)1rd)OH$$6z8%V1d45rJ})?-TH$oK!PDO0TH1g^ zu0L7r>o5LxhczmQK90KI9^~IM`i*}M(qDJkJd9frx>Q%g4kAu?$#IEfb50s;RJX$! zvS~0*)y@|OKTqFjjkdfEM;3Rpij{f8-AtB*4R5Mab<0G&<^8?u`d|Ksc-tSKtmARk zKy^rv^{xkMCiw9H=k`6-#VHmen)iL1(g9mxlH#1#0n^YFpY_BC8g$+EP4S^1D^h@u zJSB*%t+4z&-XCiuC>8l4eWHe2k-~oJX^iwwvYem&e_t*s1U~n;X#I#2NOxa&9-XA_ zgj4)dV-xdkJic;w8DV5gd|g{=II=DAjpo;kOr3ZNYLuK+e5Yz#tB6D~%N1}FT(KX# z2&3s-Snyi>=q~gAcE(SxunE^=!tLZ-;}yN;nGK59J70(kUMaW>p#(Vf72ylJ@`F`h z5yl0}^~A-mNKH975SQp@rS-PB^p%35>#+8MXuiw^zq>vze?`P$W6aSXn=!k*LZelN zX8$d&)bC+3iN{s12z{eBg+|2~R|9i?a2mZvAE-Hy++M5k-gzL&`>5z^e0U3n^)dGq zvC*(*>GCtrpULMyWM1d72buMJcZm#)B-9?fm$Q@Z0}K2;486RGi7#}+#AY{YzzqCH z$xWIWaZ=)D_lU3&!LECNP8&;ukXu!_5_6qj$D&t6StNVSwc-{n_O?K|K`$5fafw=_ zz0{ zqEAgY%qf-J?6Fp+fCLSxKijvKc*aAu;lM;Wz=%6N_wWDDJu&K!YIS03jC+^PhZl)S zcg542HbL9GwrK6A4CV+1eLM7<$i=vLstQD2?9`u=<&Rw+=eB|l-D_s*B4x*8pcWTox3-W2kg~FwROZJ6YKd&A9def#ei|OThX>*zL3P(3 zcErP;LjwjzzWeLQ4aX5C61>Xl5RpG7pq4e)wJndw^#O%|BIXH$+nmhJ9)D!mz$ZB5^3C;nZE@6*$p$~alP$dN$&v@h0WR|=rZcRe;^dUN+io^{hrhqibML1dFFT=7VJp3;;4Zd$?cwTx9y$yZ1u-6H6d;wkrOn2$@7FGr%v=A{w_|s z34mvCw^Qn_lkgG@3#=9P+YXY&udn)Rmnj*|XyzipSnG@#(Kru48&D6NQbwAiLZ96)Pu5M*QmdFcl|Q1RR=|K7!~)nEQLOE)f?Vv zoiR_pVFL(rph_#SM8UXLQ^AD>l7>b%oG8esn4?RBu|R-iasY7SLNx}7(fCFW$9Cha zc|yd(mf0sqyVE-VX8!?8wBF*zc8mJ1lw86i=_Purt0byoxn^RK=LzQR2Tv|`i_}4+ zxgep0+ydKRDTbCB2HwuTsQ036O^PQPT!c*^p={kVWGbCUleaU2Jg@Q^5Mm(BUZUCC zfMIa7s7K_gIr~<3l8B4VYpd;a#=R|}tD-|SQV|V?i8X3I3A=?ms2R10n;_YfO1!#JC@e9RmIIf9sFC4d^?60%4^pdS~riqTruEl58{&}uiZTc>>tFXgLmb9YO%JW?Un3sQ)b=dBRgTqGesI%p z99K`3cCsLx@Zlq0>^Ke+T)vY&ql@B{7l_36VoOf@4uS4DmFqUA%vstKXu09U%p*`r*YThy$LS1D~=;#M_d zS<>`sk;X{HZQ2Me_K-Xi>GHEgZI>ek=|CM3OWpB`e%`@)FR>|;6Vc$tBNJ7GmC^XB zaE-GV^pA}6N0Sz4GbG6>gP*JzUMMO^GxHV=GW%?XI%rj`Jenz06+GND%+C=kchq*V zb0 z!_(U%kg&2!r>S1moJ8Z(=RTSmM+)*3M!_k*TJZkuFp94hYAf*r0Zh`cVTZeD#h`gO?tb-5 z!Ma5z3vnV%#ZGmW(EyO83aHH1P?+_5Jf%teu>k2_jer82_}4{>d!PSeWj}T9_qPADX3rFgpbS;Q*wOl@7z@^kt2>vZ9#Hbel#Vmo)BcHmOni>LfM{}=}iMq;jF zJ2~weQiYYm*q}VWhr9|%oZvL|LF6bN{i6n&EVdAgNk_5TGdg~i?Za`*^Unw%$Gr(M zSc2p9(4{RzS)B9&welR2jnmU1)LsUeJZ%{85*&&%>MEIk3TNVt+BqfU#y|=l-*n?t zXy97(mM1RH`ErWhR)12EpH+3DLtw@T|LNB4ymD;Sd!D2M7|uSKradz>?9 zo09PPz#jvJ5%rXd&jiQmquLCs$>V?QbDB&huF_oGPqbX!SUtt3`aN~}j|gIYi!$WR zp+YWx?zU|iduTK-{TKcV7^9oq!|cPCx`n-4;w!p*VT)D$H#NABi1);| zDjnqrz+}LqdP;4bm`Z*xuwH)>SNb1nhX)Fv7{31K?e4&&=O?#9Z;BZ9q%i7oc00p!jc6=>&uXxvMqSf1G>$ zFXI+1PD8b~6EOlJ+mq+58;PRC_=Q5`Nn3QXkV`zkWDC)|wAeEs=NL0 zwhfOFsKRJ9K(IL^(`fS-VLY+9>Tun5xOl|dvBux5PkH3m3P|uda)fmTl7QyOprRof;JmUV1%9@)FG?L z2{;k{kpIHdik>{t(TG})4d4Ybs@6o1BdkV@yD#1^^wX0%=NP?q}hXqm}$yeeLbuu_Ra2%{hsh}22?Ao@&Q9Vdk_qKQ1_;|fTyMbI(}N+mIMey8S)@Kof(ehuzJf| zOJB)nAJtI5{ngx~(IE15jiZxht?6odiC z=#={H*gg`cJq4IJk^pDCf-`Py1U}qm$-s61%RoC7W=e!qZ|G99eA9(ebK}3A0qFS`y zk2G{2!9_;nW3N$15^|qtVw|P4M@}N)Q-NI$M`kYk%)oSU1`zW4m4S>Tt~oqc#vS~^ ztAiP#%@Ds7EMr7Ijjs%5S9KsI7GJBVJA+|;qp_f>u;W8g_^m+0v4^yS-?<&?<;(~2 zy?2>hRX=#9ZJkr`qrt;UiNo=em$LAKa0d~uoheLd*X%2C!E3^w(1k=$cujb*j$K|gTgj`{p z=D0?oeqSvA&vm^*9pOZeMFuqDm9G`V%(bjp8SIR!)XRFjv95mYJTnd+C|+jQyk=^F z)J%zAJw1FQJEP){OlBQ(J)2xew4eG)!wQhdb(&i-@|^#g6_B(0QU}azZxE2^%+eTh zJQjG!l=@+Vu+XC*Eg0Ocx>&;$9R1|TGD=#BD%&i7*HNn)# zUgkcL91g@{e>5ZXjU}qrP6%u6>rxdpR0pvsuGa?$6PBalHR1MDcp;AYr)aD}laxV* zl}>|`3~sUevt-YsOxb{ztaXUca> zz^l>bo$4IlLaq+j$!c^6JVLAT0I%_!ire4X8Wf#dw{ytXseiFmAocZz3UNPpF%@{;S43!^IDY%pYu{y@RvyG4xlm6Yjydkz}taLmX zjwy{*L}tmFABi2_v<3tyNWjpMs>^XiXgk#nA@hb}mwuy;>y3N^#NxQ$8w1u;ew7ok+jUZokHH?;Rvmn@^YQEBK`$2Gk0t+#=Zryr@r!s^Rk@JD5p#q#O$IcPpa=G>@5UJO`m z;#hGa4r{=YS60B(&G^{VvsZDCRq!7dE?gLI`lPOgX~z-}jQQ5zoP@mO)A6>K zt_>%P;W+EBI>HKOMLojoYQ6!+F$hi2Wt5GF4*u7 z-4GoH6w61i)pFQ_0Mg}?@IU#!CLJChtJ$ySF8Q$EE zF!H&VwE;87iP?QvByt^#D^xKt9S{DMr^+kX(i~Um@0ft0O^B=2!AKuAt1RC& z9z1=KQy|HSzV=i>&5%UX1*80zlozXyCS0+3|K^?&$~pTmo1T2yJVP}>>b71?jJz&w z!`(4oy;TTdl>TV_d7W=i`9#l9e=P8_v<-9Y7uGsfWV6F@qf57R66E(Lje^yBdG&90 zFBuu-mQ#hkX&oi;b^2`Gda4j4D0^d(VPifoGLyxcNu{1JP(86k{X?j8t(JQ97DrHx zdX3O9%t|-78$!EGY=uu%QJQ&1lYWC$h`*rU*r^Rfvzv4>Zw^39?Ew4_;`6l%;7S7r zDwnj)h0Uo%>QG^dxXSXbab=uF(&#a3x??j~$gzFq75m)2Cf6x_XD9m1TWRNJ8C z7#JRjjhcT^b`iqJ!xDXlptz?*#?*WPQ*<4@n$RZV7DS)mP0L%HhP1ooXoWt{T$D)eFsjbn#K zKs7uXck4I0Nn-xhMkD$Yl=D=_L6c6!2KHvE2^|j@f-9!)cTKu;x-}Sr(6YZCVjCQkHl^{iW1Bao`?T=4KGU$bjSF%PrdL{?{Ryds@|! z>>iG1PMs;#Q+{E8pQd2UdcU85LY|aIJPvpb0h~>WgB}Y|Mq*kMX}kT-IOJjb`?888> zYMjSbUf0%%-D_)IpR+Z}sLI$(< zu2-V1GasFJ&j4b8ONc+0o&FPs2PE0{c|i%~K<6K5q}0^Jhkgg;8U%vn)_&v;ZpUh! z8wyG4*_nQCDiX_t_{q{95?87-(u8v5L=jyzThK~3JzcGu%TgD7jpwsv0u$zIYeS%An2L%g1ch0` ziprWp>yI2?w{&TArfJ$xMTv-5AR;0fLJTp+cnLAY z7-Q~l?e%}?IrkDf{XX^Vz4qE4&tBha<^5)^2#krV>9ZbTTV6<#bAH<#1w@hKg)eOe(jS@6~e*y29gmVV0COjcaXnfTY$A zp(}zD?$QmhS2&m?YTpzSu7hsklBAXt;^xG*-GAaDwhld^W9jX-f}XI4vEki1&u;ti zb;JVJqd7g-*lK+-WDaeGlez)nTEun1jb!Vziq)vvyiAe}sc*GA=*I75iz`ZPgN8}E zf{8jD&_>fBiO9EISwM-xhs zW8k-!ggkNKLmK-o$dINQEt%vsR5?7$AzclwojQuX@R%J|$F*H89rmgo z(xvs9pp+m)P;DiH3EPmjBLOE7C5QA2J1Sg}QT>BI7R~XnaBt(|*}-=kg`brZnhFX4 z*WF{gIPGyGx9bNw#J1xv8S&TQ5z=_@$>`c5xQNnQ;iB+CDZIX?~-(gc> zzgaj*HQh*tK{?5m0Oic3o5VdfafLY|xEB*e#Bq32KvvCG!>CjIJJS%(ZYU z-nyOxCXj^k+F56SZ)-$I-x~X3IP{rmHUFFt@yi%!+O*a7mAc|%Z(ql6oGl7=M+m^_ zdku8EE3io!^Nk)-s`z_qS(2xC1)STr0es|dslKAU!!dxhvhVen90HHn5Am2?JvK6$ zl)I%>MfQMxlR?QIjNe_PYq5v)_ZqIJhev|SqB^U$aq*(qjiTd6?kiV4znLGRM@B+c zt%!^#k4D#gVff#vvoaFowyD3+zQ!I`OLxNJz)l!Rx949?u_vOL*OF#`o)jVr$=W_q zUAWmX;@eXriHKI=m7Y^8uSqf~AXPqRljE;czT0k70xAkokE@xQVeXm++@i6`P7mNP zHtBTD&{&X6cRiXZ+-qAq_!yrKzzv?fbCy7%0Zj@IzO30J!F;%W9=c<50@0=Jixgln zC^-LZb2W zUa!d0DS}dYHjtaIPS}#b5S5FEjQ-v#G`)qSm#McZZTK3z>8<+yWIUS;bTM9fOi;7c zjf9Brfi`#;ag%JcUCL0+JRd&?VLDgG0NlXf zU9Xv97GUA~%rBb?Y?1V$^vj!m9>?)QW2*Hqw}8$`0k;sjfLZ z5Isiz9z)i_7`Qb#JN4S3_|9;&_jvxKxH%jxAVCH9QF%4a&|*p=y%tDyq@s7P3#nR| zQDR);DSfORc2s)~)6~gDZpYLX6(Mr&an1cX_c!mc6PjvsBc6CC^{%ID5MpPi0&}7i z3wAny^n0E_9FNq{6<3I3X9Q&IFyG-we9|o~HkyHJY$D&kozpTmVZ8MW$#y=vaVN0h z7lbui$Q{&W7X`Dot! zy?>Lv?&k`)7Z_3`4r0(s=ntHreH$3&p5;3FE{@VqC(p3&V?+-fNb>g&(F~tx9FNW> z%GluEF!sRNxQ~cZ!r2Xg59$wNdtF6*>A%@SXM;ErVd`Sh!+KAG1w2JLz~izGBzZ_T z+IV$fpWAS0e&lS>6;2XYAW3x3hT$>Q6DOlgpFI``<*F+em)hfJgFGXny5i8i{U@9q zb2gvw zGX7#VSreh)aef_6zc%G;q7yk>r@TZmtJ7;!&nEKS42LmY6LY;L*T7Q9)aWR&)uMcd% z8+shuigw4HAiT`oX=~Ejp@=|U)k;8o+{hmyVVhc@R3Eesp_p>*pzhUUn8mC+J9l2* z4EIlX+nx+Qo}Jbg$PiG2TauQhp13^!n$|_bCRit`hsIQs@c?0>!PaL;IA5_r3xOIa zbgmn97;bHP%{J+G&G2#CEc84BB2c%)E6;yxTVoHM3&z!Yn|2gBLU_ma`|v6C<{{WG zMaMyy9NQ6FNRH=`&U<^qSF2cJCgm$Q-z*cG*~tv?4lpGBpHTFKU29zeI<5D7L$1tuE2hKE(`09~bf{{R z;b25Zysu^W*TV-qBy%+Wl6-scxx4gBJ9jqhlyQ+KR}-hKDXX}h7r;^+G2FZ1LZIpK zHy4GMCt|`Agi4};$l|KnI=iebqHG>w%ay>m4C|SvMY|g7>F(eib}f1>a{t-uni;8$ z-TmN();-_cOhN8IJS=oh%k5^oKD%l7jkR_wz~pM7C7%b9xLDe4A?fLt@b<%q8tpFq zcSMpequtV)Qu|6Mc_g@fEi_1%z|CNHw3jabA_x2_eeOr>Zgk=P!3pY{*x1@uyB7m6 zZ(M$(2{A!@mEUPeic;$J?_*&X78;^5^bgS#$pia~jfS1nBgEW69!I6oAg_p~6e+O> zM-#2fmE-R8kY0Hy2$-pdM-zSN$L)7C5uw&r3cQSln0xkD@Gy_WLmn5Qf;}2T#daqa z{jumq7=t}Nnh0f4P1WM6MK&RxNE_sd=bq58t}`ZH?8$)R!2~?7VZIa9papMKNa9m! z0Ih>TaE3TH8YI6GLC!CWNrCy#iLg;yPYvLwq`{_)2HA158cT9ANqSQQ(`KSIrjOni znB2|#pKOLkUrKfdR%K=^7#RUu?CJR3jlINXML#e`&+kNGwg8noId@@aj+VNA&5%74 zzi~*xWU2x39pnfl95rw$TfD;NXCOFn$zOB9Xku0v0f;HTP*TOSUxD+3Tj6X&DR;B~wypGsP>=Y@O~ywqx)Gu%ddtX?QK zBP!>uAzq;~Am*h>7`##-qX)G_18nlna!K(Bmuj0%2MLqWZleO$(4<9343C=+3mT5# ztA6X&vZv6&6L38}nsp5k{9H7BdTeecVw12NHLt@d#)}Wwx|j#)PDoxP)DeFfdcEFw zVD5$(lHw*b+oTFmBRAw z6}Cm_p7zC?-iU^IIs4RnCvaR$j`RDq8{J(EYdpio0i78y<^IfskX?xh6zstL!cL1<;#+El|t43Hsz>zZ2v1e&whH@4F+-Alh@;g6cV9YlyTN&QxG9KAj2 zQe=s{m^}D)D0SDu1@zcMZ-+#>v_5$zvxN`GUpRcpO%F0X?rlj&?&+1H{`u6#Ylz;) z#$?`nB!-weZQ2ZbRPTm=jrkrU@MC{QhwM)HD+vW6Fd#A$;w^z)&S}1BPrRMTIxB%@ z=1DbeNhMP!3R?n>A%Ji)_Ea<;{x!~&mU}xcawg{1@#H5pNn^w7^>|3^I_h09QmmK7P_+Ro)zcbkdG}gbOdZ!K%tI`Dc|c`0XrPt|4lX;+l~xETuR>WB z?OG6xp}21+9>f!%4R*TkdX4bx9YC9`#VtWS;92mOXLBI8%!>Gpgw|>+_4hSIt*?qH z=Sr5_^IBkJ67oJ|6YD4b5jvYSTWk%Qm8*53vf7BH|1mJKB?jOsdBxfU$nzv|XLZB` za%fXXrGpZtpc8f1>?L(_y)$yz%a`_30YZix7uY-Yy=f-K9Bf)g5rPu?Sm-b`APlW|S_*SU5o zW>H&LR6{P_3`rM}-B7#H-pYUt`td!Zb*b>oD=2bDv~!JcMmDOKTuyL^5ZGAzQVK$y zkM(0M+-$?;%=9m0OYUVP$e|RE$fo^`OPg#=TZuZwgQH;PE@!hxHsRC063`b`Ew`(B z!!r35d@Z}|j`4UL<^_9)UDpAI4|57d`O@g$f&uC?&GEVXAWM1k?cghFu^bedi~A|q z$YgHCOj}(sWS?u=m1N$u+p+Z3c&6GH0d&=itL#ewtwywhsGu(4MccwjfE@F#G1=~Q9M=r_9 zdik8Y686}X0GZ39AM4{b zFAmtS749Bd8YAOUzz#9PvX~*>Kcuf0<}Q;bcF2}!cbD0;dRSGmDZuq zxE6mf;#1WjCI7Ao*gyK|v}snShA=k+d9pn&53EX-R+TMYWGl2nI7?yw#4pZP#(U4k zfuy=h>$3=@5CN)cofN?--_7bchqwk~5^y}~wKmHZd*FmMX!K-BIBaw)vb` zTW39!Lj;3v(X2^dOf~Rx!7utH$c64<*xO=*lRwNB{>C}5?J+zTK5gu!*ipzlBv+`Q zXWXgJqyjbiuK07l6ABySIlBdo)k8|1uve4nYVR5OmF?3Q9>8$gUXCYMi4sx2UmID* zGlcDc7LwzNITm%u!5D5b-1#9P=O6B2VKmS+WUpq^ZftJ0*EDiHMr1sj)Qm*ncI5u& zl>E<+#w)IPJep#VhQ@X~9v4^9GCL7qQ5taoP6|*F3v){2r3BQcbrK?58U9Neg&WS( zW1P`^+|Gghh0KG|-u0Hg4>p=jm|~vEd;OfYy%q|DpAKW6k16qi4jB`>^m(b;WF*^eT>x5ghBxK-{`#@jP0F7q3U5@-S+>$JBi5U>T&&zH%@rm zidoSctCct!Y4f;TIYz4!p^E;YTOgF$DUMYcQk_9wxA7|_)c6K?vs!* zhrvYHQ|i{7r>p>q;6TPxN82PJR?X>|9L@OFamDMiDe8rzr)Ra8Dn#%v`khVJJI8~v z1v6s4ZXNYVHuCbmqv*07N%HqHmoB3JgFXFDVjGALm=)6;euEpo%VulE*0l6vgJQ+z zyc4Vp*F*}pdnP*8F0#2Xwrdc);`qFGf~O$^DbiXe2Y7zWX>rx!I$IFGxr&fTW4X%v z`nqc(Wr&r=>oGDNSy}upg{!dg_?_#8YA%W2IEZ#xMJz&Rez3mLs^Xw5t6ON*YLCs# zYNAcj!&{veDo>Cgvd8jh*MN(=t*`PYn2XHDOD$1?Rh;>L<73DIu>Rr z86wd0Qd>>v4UPQ58U&*Xw!A6OaHn0e)CSKf_R9(uO_)Pa-j@qSBsiRyaltp zK9-QX#Wtv=qJTCA7%ECQ`Q0S^ix5rnwpmb8=`5CDi;iYjJzw+I07-cr+ZKpoz$Qn1 z{N@8AMg2R8J@6|Ug5_TJ{-y2E5hNFfb07`2GX@3I4xV-e0B#A2z61hv44d8_;a;++ z##!FI(UA|w$?U#(>Aa2yyS*F-`PpLIuU@3GZh>$d(D;;AcY6)RUi63B#8h!J9MU|= z&ev{-^?;2Uf29CAX-RP;*!` z2udW2gO*`2!{5>Nb*;fyCvgFH^|qY>z7bu37sb2P(>B{Zz2>^LZ(~q`{i)tdgsH|M z_%OK+eJ|LN^3Iv}9|GZaI6d^}<6Xj}gf#w%-Bbsr_{;eqg-g1I|1WH%=XG&&to-?Lp_JCfXlLVE09(?wYp&B<{y{2MC| z?1+MKGQQ+Kc721M?YkmdX<|8DW~qu<^1*dkb^Pux43e8rBY=`C)anB3TqV(CoNjh+ zx&Go}FZrQh=~rl3yrew|d(v#$7fK3l_Xx1g-n9#`OoQy-IYF0R2E zq8TPQmt&gZ#Po7?v}pJicVtajAll+(1KZV+t=ON%?t9Agn1XvU+Ij)2^(r{FL5Sfyw=o(O z8kyRr>@0hh6jw}b&U%qm9yee;kq{}r*0$b15G`G{O+A~C2hh|u*>+9NuT7*Lj`2%c zQ1Zaqj%+f{fr9DIfR%6eimtl^%YE=tGNs*`2Xc_@(K-S&vyATzwD3srFM40L(65Bz zkCXDUmL;DU3fmupjr?hcppB{NADV{MpTRIKVAi zyqH@bqp6_Rlhp&=*lWTbMY6j=;+&*aLnnfb;YbXQl+QLC)vGr6mtH%j1+5~HogEKM zhL1OqKsY7iv=ea;%zwd7YRKMpQdc$DsaVbC#wHJIA!m{Rkx636-V#21Cau(`?6EUi zO#*3cBw9x5rO|l7{f<9y{O<3=-SE7yEcE*Yd?5yFC8=hj>K8RwvEQF#=cSMcu8EAw zTqc)=0a?!J!fsy);7eWXxT>k(?25~+UDIk4szTZnXs}(6#=U(5NTG3TbM4RBXSz9& zCf(hV&&OGen}WvQ8evy%X*-d*lSPddpKCG*Yp^M|qrHD%d2)X7urn;5abu+}Yp_k@EX+8?(zj z%W3#dsJVIyEpEKwGdyWO#BVQ)V)kw#Q9qvlGkf6OL?v?t3X0i-?*@Tg+}jH)_fR|~ zeftS}SPhfvU|c-ZA*}b>_<)wHC0~OYVG2Y3d^b@$_y*!=;`fU$PM&Fxzne(x+!t)Z zyNQISk2{H->RyYNzC9^q;B+xrO?)?zNLS-WZndZMx{4gb)cSrm*oA6xgm?~HH`Pyy zG5bBzesVx2y(tSeC181h5z-6shp91xmB_WzqoErgI&8+fI*Kk+{w;R_W*D0(B#W_` z*wY%LhYx?&yW#@~pMaT}9n&l!mPX^bM+Xjd&{BaYBWT0ss#|40`DG9@_3l}(2RT0$ z2-mFUR_A#Z#BjZ9IR(XP*y47L(szRiAZuun#=~8?OrTxt#KE&%(27Xn=^yBln09}2 z-YNoc&BBs8s|vta&0$lj<6%+F(q+|FlPw&PtVx?%7u|BtA?+_0^xBk#y4O}{$2_4D zv<1=`*wprW)B;w}7@at6dp^LVNcz?B=Xrne6RVFcc1sP*+YnC?w{1=DCjLAJFZ>_w zH%fU2D6ZZ=SesU;(i4z%WNY!y*!hlHLB|JG*sHzP9edSWZ$0k@*Fw7dM!%jo9esgO zZehI*sF#;4&D%P)UDW9G3LbTh4e3wVMPTofAJzJI6R(6GvLF(>L5(u^aIUb80r>y< z(;xZIHff!K5(j2;%qnHg+7jptFxuAmbG>H?-ImSIW1f%Nc7brl08?$jUW&G4^*Lob zVl-l>U5whPH`QEiyE4>TG5i&hzshdCE^Dl}J=$X;YLgaduRah`ldehU&U2{ji^VJ- zw3h?b*0z4zuSHx_ZwIt3UewPH2E+~zk?{zqL$O+v(FOLlU`N%b8M^>H;j!$?#^VrOL+sOe)^P*xL zFk#y6Y6)D6SFmrQZGB@Sn*Dp~i173a`&N{|OQLnH3!UC~fp0~neXpkEvmyt+aBD2I zm|aN3YUEc9L-xRhAcLqvohV*NS8EOD)BR~;s`k)@L^n}Fg4@Fv(#?+=CZ$IncOk?% zcT?cd5_B4kTkFsMj}Chz9uT)VV~<`4rDCRKBQL`R(L`=Z4+wcYkXeX(B$RuCIu}tv z*`A1DU1i(YiQsubR~K?EqdG4$@q*mdQ&lmSvD~U;PYFt8S8u!Jge_Vse|y>{2`pii z*fwo)Ae1Yhk{kI|w@uOOQqRJKFd7S&TT04?>H6);?ipG{PnytWGh;+@kTB_|HGD4_ zeQcKcv}0JAeIZ0=@*T~IpSg0%b6>d65ITayVWUKwtI4{ZRBjscvRQe?nE3*`rn}!3 z#3B=3h+vyk-^J0ii2H+37)_9nCY)i2eyh_%!M$XcM=xA>lLB#tfYh#Oab@yKJysHzgmb_u zJ@OTIa_c`I%hZ6%cy%Dw?>A(<;McgU+@ObroG5FG4yaVDMSp*`6(w<-;8I-#-(Bm_ zyQ)SQ!NUCo@*{~2Q(KEiEC--RJyFx)CT4v)PR&Fb9c)1q8_*w0d{IzH+d6@(#3#tJ z01RD7{NQudwmzoN1#Phn8l*CneA=j|dN=mjCLNBo>uj@Lz+3}*i$E8rh|PN2dLh_C z&)tp^x2F};&$j5iu&BnitFxDar%X(A<|a)Mh_*w()*vmfbvmhulx7aryRwCKU&`Hr z<+@lhH0bzYRj|EkhSnJ3czOl{O;=J_v!3P!9&;=)7}zbLcsda7o5>FD!4O7 zG>GT-@5Ki!-CLtE<*C#DH#?`UV+YcAe?Gb{@ek)hwn3gGiHTfP(}l>p+`412`Eg<6 zLF0kcmjiGsiux<+okB?Xc(3Y4X?D#?GBemU;kmH3+OBJU)EBcGF+T{5+tMHapJ^kX zb=|{F0WRu;qoMUJy(DV@*%;#GQj8^utliG0=hprs_C>aG$@dhmn=f^&pccdbYG0`} zJL1(XzZS{_v|RuW5acxVCjxS7FfjIH;Do`x4=H+L^vbV6 z)_p2|=azI0S}uN ztx8o%QIR$2VeFN$f3+4ppwc6kgGMMJ*&Mm;I|MQ%*l^yg5Fk;{WBb(HoS?2vvGYBF zJjKVIP3+6C^#g?$u4Wcx!`Ho+xTbYjt%ig^19F0`*EST9T4{rN)N>KwcN;z0(XnpI zUf^v-%7*u(vp>q$8D5@SqHQBZ1hxjiwr*6U+thEVdxzQfm|O|Y6~123Qq2~TfM*Wn z4k1Gvi|y3QRLJB6Mzvk<$%^ka0aNNVE<-P%wmW*QX@w))qq%i=HFnxw4PU^gmwbWo zgfK&}r@efC-tD$uze!182h^vs(ep1K)RI02Nn!?v)Ud0aRDtoEOOgbEYF0aZ3cISk z7LRau$^Y|p&7`I=dCE|9?Y$%{I71jLcycN`8ok0#_{Vlk2h}4#o4SZ+(HQxTHT`^r zC$i=7_)@3CC$n#tM{Z8{ekJu$0NJ2_c3MEj_VbDV&fd}(CCOD{ot@GAx{+f?blT+I zgNg^JG#3D7j5Ae8Oj7Ulha;Hg_RDe5I0)^N2fzI5&QbR;34@= z@9T)~1n3rg!|ZOLjF&gO-Z$|gcWdLn*gcI>f@dF@kMsnm!a4db#td~G6Z$^TUcyE7 zgFti)QkU&wqM>YJeOECj<$;Td9I_AGmk-7R(f=&sLl;AktZl@DicGTwd-!6y7S{jl z1sfMXb1y8g@fY=lbN?fIV=A>rE(RS9-8y^tsQ!?2M;;gSnEIm}eEeb}@~z5zG2voR zZ}(j4vnK-G+}hsm;Wx-)_2fm7{C&w3;@ROnm}_Fd$U(L}0pn8_(>Fss)Uzi^e}$5y zl~gJ@&91%&F=vthQ%NzgtdsR}xu z7f0P1OHvs0xbZtz?^e+aJ?<7L-E57GyL@u@o1;CztqD!85LpNVW^)Ceu!)|vHZQ<* z5`E`i()@TlyO|8ojcvBzViJ1(^9xoiER$gC`G!mN2U6{mLkZr#OoLDsaGjM$$Hgmc zi4f^)h0az4c#>i!jXW z?8qb!(d4(YQV`nk$yyb^;fp)$c|jwm6`pmVzFL2v9yBUoM4o#6VJ&wbd;}Tm1#0-e z;cOd|VAWAR_F79!aE&8kZCYHq<=0t9^r~<*P9c7u-Ap8Jcbp};Z8(Em+F%&Asf;=45>k`CDu`95q6BkGScXut}aQJ=X0**@grW}PQg>We}z0Xc%h#|=*FQe0OU`Bq~ zY;VN`)}Vj0Gx6tXlYeX@0YDDrqZt4umLf>c3I4(s?Amrd`jMl}F2uU#AW>`Vq8{KR z$iNU2o3zR<>o6qkCKd)}eMN`Q710o7yBdw3tF&uc1!m&9!|O2=sebH6;DD@B4^{ar zo+4we-Hcvn#*(4+Rv?0viOu|6xVy*&Q5BBZ^6@azJP~XOPT?Z?Qlp~-^%_%O#bR~$ za|wJMV2BiTk>`%Ucu_vPs|liMYNf4zE#E}XTxC&--P7*|uF!7-3L-bod-h#SyKIGh zA8jhQ*zE@)?9pEBX77*sji2ir{*68Geo(z69C~oigYSo^iERVh=lh9F;_C^!fnk^% z_F;8!FB=f+wQ=tU$z6!A2>z4!JB|+!9*2%AZVU$PhoZh8WRfq91Nc}x@u^TP#U6h@ zQB*WDDNpGHK`lmvXI|j)L;&Kr;EDTwVhD02>8r&o`hFtv1K3NSie_X|?X_I|uJh2~ zNdZ5%X81RqXMbyxV`e#cb;xC6>83>Md>`91HGUJ*O3K~%ohxOzW(W!~f$o+zQ(ef^ zYflSeVocveu-{~}Vj;qnVD|gEB3!|omA;rG*d^E^o)PSV^NhVVH(u2&tgW?q8S*Vy zU`V~I={Kk3AO&0Sexjm_7Fn@&XOY*bb}zP4tz!{!*PL_Ku`J+{YLr0GKoAQsE-y=B z5pheiiWsl9pI~63L8=7AEB|qfIjq&u(d`7}UxkVvO)P%FY2>J z@gyR&Xoz{@;oNIY(G@A0g>BJ5DNv?O4}s1pQ8~cMCVfFwfGqN3*QJeckrzq0%LzeHkKnTag))H1>L1 zoUb3W{n;{;&5f)^@dO3hh6sBw8#3LHBob6d?jCX*#RgD^F>kL1F5z0*Xs-!1ICmnP z>~%dZ?cm!ddwr|}ccC49e^gaw-MKw61yJ^5F-)s_#@q3Dm^t^>#%*>&#}Xoj8HCH9 z*__k_2>Al5Q`%A3Msfi`wNL}A6Wfoa2Ne^?;H^L&8NR{J2*6N77wa)1>1%;xj+@=CN2}$S3vLMD)}+(^OuLKk;%_k_Z?v27nj6KVJ8u1X@-Sod zL=ZIC=K*V|vB_?0M@z~9{DsD=ZLPO2^#ZL{pM9l;KpS%uZOQN4N-9)gz4J}$?2f(+ z9NFBuLZ7<=z!~VbZ-gXMcBjFOb}vxK4gaHk8>8}l5&apzQ<(PmF^^nLqub|x(0EN= z%d=pltVofcOM4=n{sUv9iKKRSwb_GXK|x^$hU}rSM44~`w}+!mSO3}u8#k72?EgB| z#;a$=;!1mDETl>+q|t?A zhlZuoCJMqpYsc^_&GwWY*R=YZeoxi_H#*C@1-{C}NA=exOj)(@YHnSHLY83u*)#2c<{D)t59; z#WAVj*TJ$hP%9q9Txn%m%O%Szt$ZvoHdG#^ek$_bXWnwza5AlAEodsDXIUD$<4N)!-1@QY-pgVvS}xRU|? zXdTh>(%&<9K^qJCcX_0x4rS2oh0>;?bGXeq#a*Pds!&Ee#gBy_m7RH zWW!_shI|%2{ce_hgDdcWrjC`@`JaRF8PpF_D{U-TO~2ti-iEG6>~OsA>B35yt#_l# z#;?Vm!8TBuRQPykLedo-iC)uQoMuO3ZQy3WAOxu#+05 zg4Lx;S~e(_HFDIe{}5?+?JbQ;C5#=~trQUCs<9Du^>+p&&O5t3d8s@4x zF6-?_sYCRN8hd8I>uQYF-W{Ef*o|0^7Q~Uy)XyE8T#0Z~{c0E1*sZZ(a+89QFUxoF zbG=`TH{5OY%@eWgm)RFuGaM=M_NA5+*%1cltLO%$YP7Ef!uR%0{3hD5)$V2+&`O;F z`zGEjae?rj0I&5bkl(5qE=5ievjZL)f+JKF{61?yJT2wCg(L;gxEpY)y_9HJ4yl}E z(e}WlL<|WdAfL>GmlBmE?PZ@mbSZAvltU+dyAQ|PTr<&m<1Pga@}OM=%6K9$(cQuy zxs*uNvf3hh^iq&v^z3bo?N~ZvG^%0|FZg)8INXk~r$AOKFds=Wxv=63r&d#ouxmo82~=4&k}n?yWl`CRaw@oSB#6Zb9AN=PKBrci7Wf76M(d3eOTATu@%2 zH^te`7I?xo@Q6TSoue*(!%=xuYrGKm^SSYc)#!r3nWue28g}i_d_9&X6{aoFLL*#w zLQE@;z9lsai|Q6yX*Os-mIbJ+mBni^q0}v_wepx#$MAkzaw+jW?E_XJh%Lhh`>CmI zRf18}%!axDK($t|#a*&%)SA+U9WGM!Xg-p?`k9RvJ<>orOS zHAJr&)JBkiv() zAu!=C@*+$dg_k>T^xCG_z-d4IE885XaNM|sw`jGB{lnj?m3*!h$rjyhcAgME|zzog>oo)OkcCFEN3R;z?J=&%2`IKnccI#b}CwSbW6(ITXT9_rhhh=ZHvfYi)~Jo^ zTJj#?^6I7Jdi}Hi&p&%j`(Nu<1J@oE7GKx;<2*^Q3T(y^EpKH%rB&@{;00kJawUFK zr;!}?fn%u$xUkVDqEngM(FhCGWQxgoekvA#4<6CvbX=_A4&Yp{y`{;q{gKPbCCM`Z z4R>s}`;G|1WbghhT+FC2#E^}<-MJXdYwOr~tv0DG`|N_2aqIwJ-kWwY#tzRh)X9Hq zV}jE#=xU?Ov4)0v6G1Sog0Ahsd!GQrFaXsLNO8y4D{Z7CbBENV7woxKg;v z&jOg6mhyH}Z+kI9b-N<$RyIQ~yt)Yw+0O%4ud)Fy?uvg~Gox5ay?vpX4S0?elG(=! za7~=HucBwp)mE%I`}wsn#Zbyd-HEO>jZL76?@=J0^dw#)@SFG)aw}Wxo(3suO2rkw z4FsqYhB)po>Ma}Ko0-fGn|dT9O7YZg*|dP5pm?=L3=cQWA?;4 zdO7sK*t1}+{d#!(auD%q^6d~Ts;4DHqL5l4oP8**jgIF)0vhrsm;f&B609bD|oMzNZ9!$U;Q7#3CeS3)lDQ*@{tf(q`xZ z&qxy2U%t;&kV3f6o{nd~UHxvgSz2Dk$I}{qV0J)u%I66i=Vb3wX%&hGJfr1@Z~rag z?_52SJkB%6&J)_M15BaO7)b-|o>o|z1%gH{U9!HiRmJKK-6nySm1e;IF@1q$F_RkT zNuQN#$vbi8Ay_n^x)#_fG-1*<;jgP^&yqH?#i|96eRBJGjatHAKz5_02l(P0yIeb- zBx@qadTd1uf!ir5>!TxA9#B?kCy`s2!t>b*Ayg+N(rOKYb{N~J5Fj4Sm%l+>_m90Y zw%?kxTD?PLSwV7T1zKW%(phGYtW8K_c?IQ;?9?QOX>9$Z@3BIhnit8o*d48NMYSc1 z7h8`IS>(}DeSs#KNTbxb4Mf|zu4d=0*If?w9fIjTAlxAxHl+U5m~3o)j52_v7QQcT4-mIOJ2;+oot$QnA=J$MO*#Hp8|EQgPQ>1X(@c{frcwz2RfE?b-JKiBIB$ zy_9W<(?6GDZAXB2zILY$HcVXNmUpQy-a}nD=1Q+kQ3g>~A9xF!>g;g-%w8gPKH3z5%ZzAySL7o(Ud~Wx$w8 zm9_Yt%CWpA2z9`xBB`D_yWp|yh(=5Ks=1AhM!#GI?9(xA6z8z;4*dSh7}JH%bW85q+U^dHXDW5B~=i4&Y0zdwrf1h+oCSy!lh7{gr(kE0s#H z(C|)d8kbtQFSv`&T@CNbbqDs1W`e^iN6cej?`f-RASJ|ErvgmhYRI19!_D@cPEBoJ zBhuaXvA}5M?1%Wdux6pz2Z?S$VcdxKzz2yOEnQ|0eh_rki3l0s?nz-kyx#x$4Gdo2Wjq&-Rosa6MQq5byOYJSi4;(g#6Gv8B~hkqugj zOf@;sUr05`DS}%GcRDpzBZqE*Lpxn-z#T$tD02La4-&O>7b*xMaiQ^y2=3`u8tiF3 zyH6*f8#e2M#3odu-eQBC8J->Ex3eO&+>TL#oe+(E0>&rFa49P6p}2B z8`o{s{iSx*B(r#4qYzs`c^9FD>1k&j&`IN1?>QE&Nnl{o z2CPM^=r&Zmi!>xA`1X{?q~n9Ao-u~d3xTIaXV_KU5RJ5 zh*%R?gR3#;b#Ob^0v|WX@bO+3pd=EqA~#|(xjMJWe5QwH&;N5X9*_-TZf^w;XQ-L< z=kdg1IB~tL<)-q9$0vUgBMf#Df#|4x8F1X2`Y-J(4ex90yxG^;#gihy2Kcn^#GyN}^syf0^do&)25@k$8(knr*i`rA@GAiL1cVP!RG$DQy4OXxxt^|oD9WA`n?j~ zbh=P1;4|6kb+=|*N$f`5TALa0UHji-Psb|oJ^4L7D_&7oopUlfz`>yX$>v;1EC>~6 z?3w6+%;@eJbEDDFAS7&F{3gE%qUM!!5x^R|KLf%sHdAeg`+P=xdvQQ5Vz)|TZe9q7 z1d>s+qD=FltfZ9(X6S(ttCz$BCAYY$DxxQHX;GhC0j%muh}v#hbOT+rp6j6qe%NXR zxtc;ibpb5rwK8nE_N9`n7>JiE^jOu^vlbp>rMfM_fVfKCI^7fG`74RY%)WtH~PN*Q`E3F#)asq)$QaV-EPTG^uF=McS-ICzI5JKxxyfq6YBm&?|%~K7>Nx zGyGcwlWuJ|$tX@-`X^-3o@m-O{2N@;tWV<&twk8emna*ri$ZTTLrT>(F9*vacWWgeQW- z>ozd%c2|0i%|5M{`$^|rN&a&5ARkH>8IKUnZNDbb_L1BfY#=yjcIS968YtT zfg;GRM589U*i~&A)_Q1|vzph`t*(bF!LG;qTvG$pePBmU{#w>p} z$!@6`i40G9MDFK8l#pguNZyXukxqh-{)@nA_+T^Y*(=fw{t54eqhYDDuVR>L#4CbC z1uTW@_u3sjy0pYlcVnu(1LRbQpE)@6doe=Sz{o$_x0+)G1{D$v1!!l=sM#H_x(0^- zh-LAIY!(O`euvqIL4<;gv)~VWn21d$^))-~!4HF;HQ>j_34BP86!b+bu!lcP6x1Ch zKysWQRc0|qTXDsT-7TBQ{$Lb3fVSoB%g8h!4p#@w)=2C7UZO#{Lm`W?sC2S?RL*F$mE(_#W8; zO^vATq{S$XZk`sp-AV+E0W~{PuwL+cWV@m|W-Mc-lXN9H=gPZtU)UeUq z3kS7YwZ^Z*Hrs18Iu;OrR7F-NM7@afa*d9I$S-V#9$Gw2`^pc4$FJ#X$dW3o3aAuP z>%-*wd^QG5h@4O4X)m+0F* z3^MDN5}Hwk%yk6T7ytDBCM(46F4vEA2ef?mp!H}`+%pR6ET^?Ea3m1MFPZ_(?{A#S ztkWhtquT0}VMr5pJp{+V)1a&udTudDXT!g$4Kd*JFZ`u#)TBFM=nzgeX_HEp)l@94 zuCvW?&dbYf%l#cl_0P8oQ6gda%KdiQrooZE`=gwfZP)su$i}7NB|TA~2jO)`hO1j( zymr75+bNi>lo$+gbC;%Df;QK73pc`iI|gx;-J_KO0}PmZ6Hf7eWC%xE1!})#x&O*z@D!$Y!rU8q+R+i6GiuEP~jRPGK~i*bjA2Kj+G7Kr7B|K5&&n3(4r+fnFsJqVY< z2~7uA>yt50lCpTVr&C%*C%l(_nLho~*^VnoKlkYG?JZ$b;RcQ~fz4VL%6;TUw64{z zRpN6V)pISb46eP&30_~*HF`VmGheRjdocp zNDf!Px>4kc{?g6G;Xx0WK%)naUtTf$n)>6RNAc6^v5~nR^b$AX4V&RS<7e?96b*RX zJ(_a68B*jsiFNhF5o9*CyV(gRi)q9=*f#>%Hhi+fEp7L7E<9%gEB$RiBgH%4 z(|7Se;0X`kt09UcKgU1l(d`A4iK952Q$4I0_#0gfNv>h|c!NEt2Z9fAIJz3wVNzoK z5l^j6_VCpZP&u+J{B_2ghLgaC3^JNjkFD9L#p8F2ZPIpm0x&LmzVOX@z0egqTLcRA zv1{$N2Fl1!Z(iDB+pY#%=Np^M7A}iz*TQt5swKIC=2+ns#%)LTfq8h9`{C}?SZJ4t z{|r1`DVux^cdIYKD%iR9TutmOHom=r;xR7pVNlY5!fZK8FUMl%NtCuf0H9@Z59|ZN zmWw=9*y2dxQxvP*=b^HPgbXLH$qvWF330_so}kZw>WI81v^#0F*YvEzg>{^ink%tm*#bLIEbT;COVcjWpeCdId7_hP*~qboTB zzm2C}R75P#cUm4iGn2gey`Ei%?FDjv2r$!DO*8u_=pDI3xb7eLNM4i9eiF4D+Dd!y zqeM+}MfDT~Rfm@0;|LTF>xr8l$#0yVn%X=S^7xN}4v9PDfIJd#V1AKB)z) zgf^K`p?#0XOXoo-V>;oZAe7w*I(`S)6CVXdf6gi2li8rK-Muz30Of{Hrfld>#bb^1 z+POdgix|E|{@@ZA(+Q=^YtT5Wo~=s;tEU#`$!U=Yf3oTYn;m~1{tX7KIYPNE-%4FHd*&lCC2mRlU1DJ8 zeiSz!UpmVS6&&D>m?y|}2om!@3SI%p(Q}&G0)ZUci#O6nE7lTKA!c`2X|~Dk7)xD8 zmo$jBEz_j)>i}M^y(_sNJhdc{Zy$ceDg-_GJdjad9ZR`AtU54(R&+WmYBez%zq3>3 zByRjVb+1H#<5OB5fIXmpMZ7_3ZlU&{t&GR+{9y7~T%~?ZttoH$^O}EAX{oJ_33>)0 zVpHq0^O9_Iz-`d{IbJAGo3vQzuyLQa2>%KaL|B`elCqqG)}bLulk1FKA%?`Q2c@lE z;aBdS8$AND82>-(`zR5QQUYG0NA1#OHMTCAz!IQS9?}9A!;z5A6@FvAMyBEmM0JDU zv2f(TjR}$AyCKEx+opI+{s&Zio8!S9X0c=nt>Tnc#&|us3 zb_onjy}hI%VcPm^N5FBdyGxHdbto4>()pfUb+ap`#sz~VGXNo@_!qfHfa-^j@m}Y8BlDjo zRp~}TKFh;_7j&=7UX8Q$)73NWH4WVaA}|hldp+J!2gi=6OQEsdjtT`vz@fyBMXS{_ zSKD!|765SCJ`uz60l8w~4Lhkx<7o;B6_8rI*7>AQ2mG-eWB+1r>03?|B2_LVe&UR# z#cm_yy8nTVWTT;n>$Fi}zqGw0-$FeUJEuP^@1S`nSHO7<>4Foha3S6&kvUo3E^00P zO9U&VfU&?TS5#MRmt&fZc)4EDdU{~0TOhCMnM`QxF1|z2v|@3IUDurPd?I~(jEG{Q zr;O^j4fa{gz?p1plQ)HMabrhw3T3<%!&j3k&_0i*o^6doaa&E(Y7ii5U&QzHpI)>t zW5lzs5VmVyY4{2^?0v0=XWb5WM>jD(EDd--r|hzKqXBmWpUF2dAg9oS^zNx|Ef=hP ztIc{$p2UOx$W*sp<@qROBa4GM!g5G zC1U7C1i#EUBM)5*qFTjPJgnc(lInHbwM5+V&4bue#$OAPf*rP{bpSSmAdN?25HzM9 z3T2PRAj7{Ivd1)hjaRemvB$3|oyY$#Q0&qkluHw0(4j_l=ZR~H4RB`o(l6~v!D&Y8 z&R09}T2Le;Q9k2NXVjm%mRaedxN}a=h+92_xN%L2E=~#Qk`y|V1850{&$Iqa(HJGf zR6|*(#`-Kp=|E)%r^wSaDz{o!XD>x#a4d>Ox!T0X_@y~he`&?;km}6a(=ih~=&<+N ztQZCVndCS+JJz--@6jZ4guwv0u3$NziRBpiWjFbXqFs(F3PLMH#tuLyPon90)8=1G z97!E}iI5MIu;5xyX!J$SljhSDiv^{#3l(#zM#K8&wROt$$QdW0n3c!+;oy;UDYisi zE8I=FA~2)MWvx}k??G3nRjW}g3TUg*1J_=?)y0{p$4IeU1F;pZMOdLnw@G0fUKy*E zV{37XStS^RgpfctM#?QNuC Q3sD@^?G2`yfp*>KX80^O|dR)nUZ+62uKwew(0k? zB(~@f8m{N!I2Clv;}eT&6WuY4YZsfXM`JcQ<>?dB=r!TG24d;_R!?lgI)SdGE)=}* z(6vO1SO3`7>x^=LQc11XHUzR>9tiy;;^szeB77I2Z77Q=Y+#!-GU=H+ZL?sP5}Abt zbc>c5Q}otoMjQyIf18>Si`W9(?e`bi?X54x6BSVXl2M6RxTbS^9$ExpI1&$J z@x+(ms1CtO7|~-fsfwk~*>U0GF|LgW04Ji46ClzlXrr($dMR`=>PG7nS%>n>P6wdB zm^Rbi(t17@)`2sc6Lf$t$(8aW0XetGqaa2F8ILohWFVgtdIRX#&Z{LFY3OOZ7;q)- zMKxN4U41N$SHoJn9I%ijrP;WmX3z3LUKOl1_iMWrFUp;Bx~>;R2-|ieJAhO_BAU!S z!i(2##X%VC?Hfem{yaNKEFi@9c1#?#N7NxcVP6ECiiKq;a&;o> z$md1E`FPXo?v`K22vlO{)4HQ(gu>v2c2|pa>F<#kkQ(fp*oIo%D^p#)djY54HDKSW zaS|_F_wt?aOFV0@eIHv!8Up(vetK08`#4ca&(F&F<|DKRK2EfU41CFM?omGvek?JI z#4GL{j{Nzf;unq8}SJ}U?1qSC*uJYh%nEI8nFaN8WJqr zZ^xIP`#7XpS3Y=#3Y!#@_q&(^Q>ZR&aUJL^Bc^M_H;o+ zapx*>B-H;IB3nH(rjRFRg+2Xo;!a3FX|q1g$T?wgaF4S;PM2nJnaznt!~ZveX@<9CHm?Xj>37A(1;XDGszVU!hVBzBn?dSXn&7Rj1@* zR-SE*tMO6-ax^PTV&vTFDOM44%6ag1m6o8lpE6@^gR0J!04KKsw+n{T_zR8)TnOp# z)Cs@YnTM=_8^*D|OTd8I>3+rrE{6^h^%~a=+eM3bU-ZHBLy-xBL)$0iK zQ|T8MT)}S|K2BCY?H`y8Q^Tf3kF}_wS;4j#qb`qrr{iNemE5np<@di8v?YXfk;4Nk z3v#IjDCCFMT2F>DTHQY3L9tUVD3s4X&v6`abK0Uo{*K zkyIN5q8cF>QFU6$1b|z|F^(M|2HhO0uMQQ~YVp0+X;z+4U8pJq_{bP54Y9?sV_6RReRpVZ8 zdo@$!F?Zf}VeYi;i}9SEK|*6Zcw^7>y+2-6_jGkN*@0{W$sNFrd@x|UABC$S?NE%% zRe)F;P`I4C$Q|`+*3knlAfefp>(+6iDDCy=Is7^T*AdOP#zlHN8gFvLzg}m@wAaP` z9nE%JXMsX0?yK!w(+M5^Uh3P1U)#yRa2ZTj^1nExfsxT5DG6Da#4TLu=uPa8Mzml|q0RDr~P zv1FBO@YgX+Gwy^`a8awpy?OE(-i<+BtLIGUH`!4bCQobu+4!Dzq=!uL-v*d9WSXIB zXzXrgc*ZpKz3{*EQnG0L@bPF$WknwUo;=26h$Ti$yPl|HuAMBp4_r?qVCtk9_F(*+ zHtnbO(Dg)2bFki|D7qe!p>xE4uyJ~YYNXx9$AfF+8|;zmA^NtX`D2ccUJr`GZ9*>O zW_v8!7S;Q``gp*^7~sn^K}{?3ZO9Nrvj|dcDne#Y>M>8gZ@!#~*QE=kT6c#_8BYG6 z3h4bk^HNcH{PJcYtK^GK4`ej7HAh%`R<)$&(UTyz%)M-U3(jw zopral@kpsnG6oFVJgt%&06i1b{Oh4zcSRby0l1I_+9_w9j##lEmvV$kqwinnpOpy~ zvM3f)w7t<2BRwwhwnR9?&i7h{hFRJ%NEvI-;ZvnqED9mdm%lptCw3nKE9m60ZuNpi zb?QLL(C)~MVaqkd%6to2Up-K}no?*&ySTsER>caa8nZnguP*({t){VIHH(U^KDsY; z*JNvmHt56()+E$RoPA3*PFtdBAvxu>={31eJIG;3=Z@>aST06aO?9z!vI@}!ohOI7 zTQlRF^m_8j9z8c9{`w*Bi^iqwZnF)j=NhhKTc=Zl8#)6GML#^U&{;w^)@#xYI6!RB ziGs!R{HsT7qwox4h!3+Vy5l3{d81F*=2#3W*V&fr^lnWeEK$<7HQwgdtg~(U`4`h{ zyAUewZ)j+-moyRQLw$rD8M>$=iD8MEiA#%XLU= zf*DzcyTig51152+uf{U4)^Rgq?tM*ouUNbSS0n*kD0`tD31sUj0e3V8Ze|nhn4o%) zEmcF+3qmpofhR~bTNpPTo{Y9`@#K>_rP(j4w$srHng}eG^UsX?3UW!@udaCqD@yO$rtk5!(7m(3GT<3&Q$IShA`tr?I`TfK7@y4*v#y)Z|Zs z+;*n83umNkN(|B3+iz0?z=9WSy4HnEX*MG;TI{ATN^l2+aC+rj;z0DY8dC_(W(mvo z)*ck#gEm_O)=-rUq0SXTb7H_=_?2fq35r~lH0HdUt4X<%FI;u!1@QcuHppm93r>@1 zEr=JbO-+<>(GtSg!F7~s_DuvFSXn%fsg4~gj|Z=AgQJn=RcPaWunK`F;-FzB6&|S9 zI_1zSpy)Kw-+mH&O~Sj6?ye-Si+Sbo?OYzXo%!;Pls+PQZ+ z^b)g3N8`xfTOm6>p5`c(bM4k&NPGmZ?srv>wg+CRFBxn50*|`#g*Fhthj5@Ll|nqA z9A{QTp9EzN?_sh~aN^g0G8$>{_G7bfcMC6pM{!d~-Uba4xz~^qSz6r=X%@l zhTf@tO>*?_0Da`rR@H$@v0{vu?M_Rs*iMuf#Zq!BzzmOC9E7Ep{P+~%*w`jmJc zxYy!$2lhLAU2A;bqx48Nx~nL{newP`tyo<3*LF-`%iI8K#{(4gYbfiYQ?dxJuZ}!n z3wAQzdQAa4rGCrM(UUnhmbr_#`L~2YEgI0_!}L0%mYDIF)`;-IJsv`rjN_wmjJT*z zr0wu*G3NrubuE3J9d5_a9ECV+OhdVvyw5HNjN&fO0D48Q zN=QRXl0fZrDxnCqxfXL(!5jY1u1EWB?k2wY8!>wJ+m$Ey_$*0PmJ$Z#{)NlI#CbLsW>j!iH$N;w6A=_7U$_yJ z35^#-tI>77K zf72en5fr}NmFE+LG2w`?^^n>das5`MRDAZN+LpL0#6-1qpHnvkJf&wZDdFebR*H>7uMV4K*n8SY>N8803>O2YK%uhZP*1od$nL$J_i)S`U@6S*PKK0X9l?9 zrAsU9Y0dLlymDs6Z>#`hV+d5Bgf6bn`7`1q$i{AZBe5>IOaI;G#`x|zT#LWcym-Vm zkRoK}$Mmtx!u2l*n0S$K3t6#NCIvi|YSp^QsRo8+0iVPjR<8XnV4ld^l6di-rcSa7 z;nYnM1vj=pj8t<&s{Z6)3@^|_-(=g;l=_%k`)i8EZSVJgT41bwR4BVnS>GBrd~cT#Dvrob2XuI>KiSc}>c z0q)ANHem?abat1m=H}~&Ik~2Z15wb~=EhXoaqAY26v@E9S4)+0L0DhxX1{CG24XB% zf1%d4b@8f;s5cvmS8lcUWKQd|F)02=mJqj7Z-~}qW#lT|s38`$xXZ;RHRf}7QiUGX zHpluE;GebxZhUb7*{azt3@gPpeUocR&5&}aY>!iV|Bn1idnq6_;VHW#Fvv}vKHYZ4 zpMUbg3${xu>dC`Aqs4BG(c#7u+Fkc*?-&tP&{1uHbm4A@JsC&!|M;1mioVXL zqU87sVT9R-MT9E(RUWCBxWmjhZuS6M2pV^;*NA>CBmk5>c#a6h@GxBl^5a$lC~ z`U5_Nr1v8@{zgn=2t~|iT9(8X{T|ljgx!p{xw0<1rJXJ!d+O)<^O;xdwg5Jv6YC#- zrN_Rw5iDo}zT2+C_htJsaLRcYt$h`MR(Ynbul0g+fisept;BPS*xi`-;*z2|96Ib9 zwQRr+VE42{5HDAAe;W{c(MH>MdgV?RNRQv&Uwj-$;0}J!>k3a4*kJZ)P$goo*V+T0 zCMpR_(axp(;HRTWJS|1<^pJknk~03`PlLL;po?Oh3vAq{aZgrqX%^u!kkr%TKMkT> znKDpNvs)vP`VXaVz^Gm0o_Q&&`eT9tmj1Ex{d46!9(}yZRNf|h8dSTd(M#MywV(Jj zk-8uK*q#)6<;-YeOu`H5U`~AM(;%$qT|8tpCm8OAo+8gC>3uEXF2@TtSxC2cpf7Q{ z8NeXne)&$-6vlqV!}NHCYPy@?!x_<$sy2PCz9TaQDBs`g`Q7blbwx=<28K`LgwPXJ zT%X_CHv7|1ZdJPK6gup=ML}Rr^s9q3KtKibS-&SxB+dOa5!9-M&)GaJA2m?jJ`>9B z`5F|NY@IF81H983D~_I(tYT@*BjvgMy_H2PxH)d>ay_)VHg}0eaMyo#(M?Q2#s5py z+Xq#Bt@)ncNu^R&%4?-kmX%3a7US3+Pp)k{j^j9vZL2XJ<56R)F}ByXeL;hUD6Pa8 zkH^})h=7QQfQX2QTSP@fMBKcH7NEy?971ekjO{ghZ`d19j`4cEb}E%h&3FC2&rbLK zYk&5$-q-KMU#mEBija+Ge);c}oRr<623%6;!Mlr?l zI`??Xky|KaUn&P0>qCNGo%cV+MtdXPb%k<6^h6VE=EI@77cUvLTA%-gXDI|pie~G& z_1L1^dB)n3&D#bVm!}Q_w#nPl_ZMTkRR!lso3X?4^dVpJMC`PG>)C22V3*!T-Ym|8 zexJf;FXuvLgkM9d`E{oxzd*V@4|buP$$G~?1IVx%UC{1FroJ(ESj`((UqZI!BY~Ri z$T6?)(l|t}9Ng*-cTLR~Ew67yzSTz80dL0KiUKR<)^%L6XKfe#R}G!H$RAU_E4G;D zv3w=5qB}FurS^x@6e{%U5iD7Ta@Evo_FEMyqFXZL48kw}GZJaf0hMy%LvmBmDutQH zf}Bw~IbNWpevT4pib3IMWsZGQjU~#{w(+R7D)j6{pw2S-9`!Hkt*$vLaSH4NJ9*Ua7NE3$gqEDOvJHGDcO zV%m*g=d6$1u+S{OY#H6O`sMge_la)BEo&;;Pj1=zA4+}OzOjFQ5}eDTQ^|e3=j#Jh z#ObocH-G9*g5I&Xm2)@X#9b4)eM@hlHwX8u0(l-M9``MOPFK^Nvc?0e!&!XKAL^mZ zn(+^KWQBHH6IA~QS}>=5;9UV1R;1pIBe-?jbqb--9je?B8REyi(_9HRttjSeo83 zKQ=aR%HwBS*I=l5WMk9bgkiB@96j+Msj?RLIoCJ&5xs4H-ISX{)ZveAxDJ1{yU20G zBX3;Le%u-Gjnkhv+EGiwNX58@QE)0V%JNJ#Bu+2fJbCmZuUFpq&lqFzaqk`PSQN7p zX&`)TEM40DW4Xs!T9vMw885dF7rg6@dL~#wXRc1zlt4X-iI0BmI=RWq?MznqBrD_Z z+8g+3PPUZRe#XNSQ!FL#tXMpz+TSHE+*V9et#LI8)0GYv!`z&NhH@=V4kFkP&9Yo< z;k0NSZ-|_2rQXUTXI^)UITjUPqq*|z?UA~hAm_zuZ^Osj6SbJQaPIXI3$2b=d03=0 zx!^=YXjt+{I@!EMg*NHAgy7yocNqE-Ga0~A1&nj5jLR%L3waDlpV#t78j-mJR8FCT z4~8qgR(f}P$tPc6rM-=A6@+_~Td~TboXw}W#&|AQvEx;?_6ptuqq3~w2qh5-79Z~$ zaL02tTG4nw+q*_8G4>#w5sFRb_q}EBFJ7`3NtU*^u1})`*z!mN1h)L%Zm=-pKCEXW59SML^~%)&6qD zpW6ROw;V5~d0=E%ad0O)p}=bHqVk_ zqv;f6^39Fc(|>{jb91&!_%0Vc^14$#qF;4biWMzugcrc*dN76+Z~&_}Ie-O+Ivb@EGnGuOXbJkqH~gHmii&V8nUg2XMJ zjV3FJ7UEomv{*Q|QpSN~tNmTDsFlv+IT1%G-wREMlklV|P@c%hFDwvM~oRckD5Kx^Bk?+>N<$tDYLL z_biI7w3cySylDfgh8M~KH+S$---X){@U#$qwC{vpShAa6{}g)?R8wlf&x+F- z#l$c6`f$+BZCv->az6UK=A*n+=~KM&z1Ja8t7SD_{ay{f)Afm&)P7B#wPrfVLVoJ@ zXI}r_>w|Sya6ASpBHrJ55ktPWrC_Rc^O`h^R>u(8`f$MZ=J#HY{m0*~#L(}(F4?oG z!r>g(zK1C)p2uW&DvxoqXX0%o7&m*%I<^-WE*Ezj&Ipq%{5%;|}RB+2?T$kR6 zk#b`fLKR+dg121zy#@;Hr)iAOeQ9G%V9OYn@Xq%dcDv0xx4_J^IAc`-ZW-ibj8n$r zR&R0pRc?=QyoF#V;cbNT&7WYI?mFhSfiTf(hNkTJW=)dgk_1}U;A+ogWiRe`Z0V<1 zy?Yj-r&_&p<0~1{RPMx%-I%T{^Y%FA$K6yh)5<`LB%Eiljhtn9oVS_E2wXm1joBvI zx|*N67yBHO$kwPkdNS7}?`>a4Tik9%Xx{hUh~uCBGZrY58(qV?&`QH$Hyh4HmiPzM z81RhKF0pLS`)n;wmRdz{|AxH}mf2rUhuog=ausUrj@4N4@6W-hR?`~&_c#7mcaDon z`0hN8x18ziV>sPEw@0>0S$d!28LWv_FptZxMZD!8X$yyx>n+KT*Ku<-83}q(;$%9K zmKzicAKhjo+LM^Uao{H7&uCR3$@0eJoo;FXTP(R5T*>6sFDk`H?6|in)M}pQz;@-L z-A_;05zB?sNnrnvQ>rQl+cSU^bOyvDn;&^~or=YOqO?Pns z=by3Ky$b%PU>%5pn3?3|Ua6ke}`&^S(Ns_f`Z|zixxtwN+syI)|!CJ@&kk zzeq&%*X+9WptV%GL7x?M&1RbC!egruTI|C>tTx^086P*@pIU9YCf+?(*FHV7*yr;y zoagq8--~zSO1w}-xbe5AW&KiKImDzzquA@$RZQ4X*xlt5eVz6x1A+dL0~0)0|OIQ&BEt zaj)5p90n`S8H<--h~iwx@g8TQ`r}T2Q@2QeSiPM03=OIiqwXR*0S;S+Szcy1MfSJs z&tgvE@U|i!Gjb}1D_`vB+{Vxdi-Y<|$yDj*t=tyOStr5BpcZ#IgZZ3WN23&!jb=PE zHd>DDr>VB5(^7e4||#JxK|8>b$&d)Uw9af3B-wih|N~6*oH-W8C6@z%+%~K$}GDqoym& z^@E>nV?&Rb76o4;_fTiqBl3D@Hc_)<|38yT=^QJ4GA+uk!Cb32T8h=MY@P%OoL6vJ zh>vH1{BwDbx_nq@nc5nUMZp{Tl&Ku-hLLP1+!0W>SGFYfNVyQ;wa!a_eNR4i+l~BU zmjyLWlMx(N45v!VEo(eN#-)W7Ru?VQ-dbsI#*QfKd&)O-UN8 zp^~oRNM23royqdab0n_rw^@uyn>{;5+ZE&W1M%1)7jNs9Z_!Tk$eYJDb6?v@^ z&}(dc_Rv^Yw7(pWRF!$%cDLe`ZqH!B?~!4}ar3lH#YrDr9%GLg^hP^>^&8|Uk8V20 z=}2zSMuZ%7xM3nE4|$dv_qsmbJZmQME!GcNqyo!nS2+!Tq@c*YE4QbEV)HkfyQn3K zgR?uGS1Pq|OLVZc%%0QSb?!<+r$$+>z#M~d3sfaq&m(buiD~|bOSuy7;CECN)ExnC z{N#E)_tnS7PdFogs}nv$wSsS;YB*{nUL5}kYLy%65O@t=ot5JEPRqUC{(R(SwGH-X zjXR$eu=4$$OW#fQN^pqJF1^J{w~?cGR(-4L)L9c^BgmI|E3R2Nob9|ez3ZHBxe1e7 znQ26a#pf0g*Wrf#xlf3LjGGEOf5!U@aLdAS!O5F)xsUL6ER!@&icYIpsff7kfG&%A ziQ8qx9ecN&Uf7lmoSxp5v$p`mp3|N^J5mnwI19Bha~6XK7L*2-IJIJ24=rYHa8RH2 zk^Os*rQU>~sziHz@dzs(u0^$=$7<`ntx2ofFCc1fpdFKT`U!pVF@u%>_y*yzo*b7= zF`%-3>U=`{qYg z8}$;nH|mY_f3jNT{ZL!*b5H}h8D7`Ch$b_*U+{~v_5OQ{fsncs>JhmP?Uj)FFsnr# zDGho3>Du^B8>vSWva@yvHJ|4v?$&V!DGq)B{9bq9^^n)=a8Hpcr@RFSHDc%fu{dhc;Oou99+)SPW8fKZ|S6<8OIWFNXa~%D*EAX~5 z7)Pg643GId=r%PtrW|2DsYZo3Wplo_ib^X-3OI)MQ2rL9EN^ba<`m3ETi(3wOiwF$ zjAEkd+9teXmF5lUX@1xK+Dhd(`CPn~KF3>z_`&d2Y8q<$S%`F!biPO4W zWr=>s<#(E&*Za7TD@B~~eeo_o2sdVqH&2OF-R2UmrB1y?+6S}>a#K})&>Q8Gvs0%V zkf_4#pqlt5%LC73b70F0M(w}Lkh43q#r`MItT&a)kgSN>{hoP|ZI%j8bh%?g+bsuN z_xTJvLSA<^a~5_gxozusJByHp^5L`0FLa}6q{h@pAc4_CC5)OwSez?kF>#Y<9MaaMv=xx5SP2?paRX z!^fX+HpVm%R_94uH%yb<=GusXkW+r526 z&YE9W0JpTn#m&Lt8{X8_9VZ`R@%}UKCc+zG^`gJyK;mP5Zg1LuH(+y_7-|tO;g{*H z+hCaG#9i!3&0EVeN926l@V5PRtqI@$;T9V^!S%G%gc0_i+e{oua%WW8qQdzOj1+q} zAdU*FUGjEzsZqeS{?QgQrv`3uY>X9xSD&xPJNmPjYhVc&8@5r!QE$`FSu$|foQ@0I z#EK@gl6V)NQxzN^_8QN`Etp`%bX}CQyu_Z=ipgDjzLAs6J)S){Z_409pB(lE7mKNl zHAOk6%|BXaP*&P2Hg%+7njG8>U6^hec7|6lQ-7!n$||0vn6}3AZZu2u?>Tp-{*e8n zSrkrC<|?wdBKn zY?bS=)KX&~L)%x&>Z_!#jD%)x`#r>{4^@BU6!`4TL7p2c)$soVm=MtR{J$DMkpMWU)L zZsZhfioK-l)j)jPwpQi}|$>?ORo z;y5yuLw;dvkZoC-M@?7nAY+cjJJZ|KM6QZ`{m5G6S%q$hzkUGu`t!#>{?i{;puob! zZ=qra*K;i|)Lr-PZY-8F=l|ZcuSCgz;l|9RiiXpShxInVUluJ&r-DmB4{&*#;UE#meHE_t+C zF0Yq-z5&(>QWkj~$9^9zVhx_H<^%bKvguv~MaP7ZEr=yJbl^huii} z@^q`W+|A>niq@O#x)-=h(Qe=%6sWX z<1Kw*?Sr#@(B%LuvzyUBR!%su<$!)bkAcPq*yqOMsXZ08#FyEIKU2yaSGyW|9&6;? z@c{4YLA8D~A-5-(WyIhBdJ)#WYbs`-Yk z*Hfw9G`w3~7Ei&mHaEGIJ&dq4XRqUlVZ)6!TvebJDOau zL{__fnMvI@v;^w+=CE!%jZ2|?2?Cg`BFE8IB&JyHu5WKjUPJxHsrLUPj%nQL-Zc5; zhd@KSihnk50!zkBOKh!E0-I$qF5*0Ewq>8=hC0^$9Lv7bYN2A0Il5D#+_aph)V%(L znn73)3+o+o#6m0Hr=M^MAB&VCPqI=AVTt+V`2#n^Un;l7T-W{r%d8CC^QB$@H$Sbu zKUwz$=NlX_tJ zvtrZgCi_MuIpZVjP?8_eP$}zmr_~fME8#=jrI>iZ57mXbZ^$kRZ&hK`t{r6ekZL~G z(i~>G6?>kW^=8-~j_fxf(<*tUON4Vz1){#zSmaodmUGz5IRdx3laXtg;94ywoO%D@ z+49zLb$rYV0bDOt;^NTz7XYE$LNO$eee3}-= zJ!QysTC`(--<-IAa|sWuR0(E1w}BiO0#90CvhG-U>RIW zg8+DHzS-ZdYd?i&7MrbMao1Cx+x=_VAiPkvxQ)3TFO`e!?z|x9p>m;xN~#Unvue-c z85Uz+W{F>n-L55i)Y!8@VUvhgdejrX>keSN+T(RoaqsbgzGnV-;KxmI2K9KoY9dD= zuM6X5&ct8^SoGck?r`>~8%^Rh?w|05e8VDOljtn!ylH=_ea_m(&>pWp-sYCq*gu-% zy6v3m(&C>o#Y=y=c=5L7@FTbAJzO4XsLC?|JfcU_K5xP+vxe^2Xq;u`1Gh3l6`7G% zu379kMp<;fcXPI7=#1scdU$mI}&3p@F#qv=d`#FiqJQGjckn zo5MPH^*Uzu=nybF0B)gp-K=&SXDRLl+|P6sJKK`t?KsYO$ebRn7*Ku9864ocz+8)# zBM@%o%roz9Np8b7EHFnFosIlLD=iIeU%;Xsja{}~_Gf&L21{-jLT*i5BNVu47TvW|P&?B3@kXta`EMRE)e1 zlc!g#+`P(wcRz6s$Q#q_!PBOLw|cTo8RiI@GrR2;+pp_E*kO{GN*6akt+X@vGVF?# zoW~G+maz|L%;k6UkZOgY{y(ks@S9AR-|ee;wm!oO#xt(`+MIn$Zi4FV`RyOaA=|R8 z*cBxsw3g`O330En;uN4FlvWsjZ1L993XmsXfDUlPK!(hQRX{ zq1c|`ES@R(0wv~+s|{KFCQGf@Jc?&GvzN)cYv5Rza(lbpbpxFWCGY8Ta-smgW#6=9 zXnq5gu@{DOt!=2Xy4gz20;(Q!Ro7DIMlDZqpjy7&X%arr8hfQYCFoj<`(w5O-0gBj zs#C=!aa3Dx@w}U`&V5e}mX13+?6p7vb9c(nY($#uukMUPi~V&bL%D?5s&t)gh%LBg zZak;s%|8|M>K&6+!K^OZ{<;+`ZYC+VpvUM}{ko)w|Uo2iuE>ig3A)@{>i7I+rc7MhGQrFnssP<|^4eVA90QkxC zGkY!K^{ETpVTD0rjumN$K61kwCUgCV*8}qP@b+B?M>I{PJ{^ZQLoBwKN-OW%j;Ood z>W&u5;3(OVHUf^L1<9f!c%mIxmMXF0bIQ=qPqos zgq3LZXWQMrcU;8l_~ZWZA2Cwdk9&9KVvLe6?!Y-yR~T(+aM6ZsD7P@iD2>%zSmkH& zj-}{&cg{BzL!(MEh=aC$7|e|D|A-_ z-`EvmXZ{f@#hmDJ$!=gihAcC z|9~Cl>v!A%+iA~gv9~(04!f-6Trj5YJevrgJagxqlTPJg;RcSCk*>%0-fU!8d_1y( zObhR{l-%iNWGmgzxNMSRIa=WE>e_%@`(ih_RU!isdqAU1AbS#MA>$MyaLz0h?|9Ewe(;NaUemYBQJH`@nO5 zp3)|}v5RO+rX=9krqI(yO!T@QeI`^T*$Hir$CQ(m9E)m;M>P^3K0y&6qcFI~sIp5hW( zEGW;nah%_(5^QFtdris5xv>J;R03xTH<8Qn9dhG)&#(A~m2M#u=kva4;W*lj$1STQ zo;RcYNp=a`_S7pdcP2W`aiLoP*y=5^bwxCmbSk&h6_E!L`@-iT(Fq;*y2IVb*DQ#R-;F` z{b)9#mW{>SdPJYa=NZ|-V{2+yVy@otZf9q7aKK)MHJ{?C`KIx}B$}MJ6xl_(C;Qx< z$mi}}0CqumVXrtx59_w@rPsjzrG?^!+T26Kk19gky9*ZJC$V?f{b%L!divJn&+$vF z4%kh84n)0fjoWB$`1MLuU8twQ&0Wr@`X{~Ye2lL}^(4HhFt6fpy3&Iz%%>ZuT);V~ zBBVuCXVz%2#lRlU9l+g>AyM^d&U8DsJMe~i;DX0|nt$hP)CBB1lfCs%GZHBc!BMdc()OUI#WOnUb-Ux*&SH!LQ@xoTsZ}Ir`|nd}$nx~g-~1WIe?*KNcU%hs>D z)>Gwuhf~3r7WKv=ECMxSr&|Slm`J6y1k8+jedW7fV3w+a->YZ00kbWi?y9XM%(3J* ztl5OQ;@Ru?X3mQ}4%)?~8Hz8kzzX#K8Z5NegRdx`9@jDW$}Cc>?$jn?6LVgWi{*-xcRpc-dD+Sd&Pp-Qg|5ablepL*qgg z!|FA>Vg=jnC7aLld2TqrL)qgc_cSi_>r3XDmEyKOD`}Sn=Xxv~L!X|QO=OX(&@?8) z1zJm#U*yNguqW#_^B75{xg~G{j_jz`U%d5X?@+I|E|Oz@y2`l4oU1>w*qmooIBwkE zAm4ZmhX@6hNY@ee4OdWPMdSX9cOh@FMfje3x+N+Gjs3cAqtv`ET=f3@8H@e_WftpP z4v@>Oz}v1L=RQG&{<$j{SbV>^&E$~p3sl+@{AfO^%z^e}+1;E`bTov*)mh8M3@+QC zMmcuMpYFJKZL9!1^uwWQowX1tGC{?6t=^)Y&+#O8E*0&DwL54hLD91M*k3or;wfcs z>qCou2fPo$4KC}@s)%QCyvQXY4ta3xe@e<-*wSW6aRq{JZHIjfPQBS3%D)jc?O_)o zH|RY5A9oPZokzNE_UfQE#^78hENbIK?}s zo%P64VwdfvT0up^JF0okC9ImGVcK{aP~hj$qgdl?5Y4L@5w%==%44SSGy>eG|I~0@ z#~|@|9D8Q&x*H5wYIFadyKpq~tIW*8F5a-3bz|;9Blj9IsXT#S&Rf>x}4)%|ba`--=gyz21V~0AB6Y z43WqDlkl4UaO}rEZ;(92&G`VY_ui0Z5L>&!67S%cW=OAQpIocvbmR^D$IXb3lksM+ zy3~aUU(l2cm1`9>ZE@4K~_4&LHumUJX__lHiU2b2Hg$$>|{Q zl&4ad$+gL;ijh`IH({D(c_xn!VtVY4+ftaR0KfU|f59xp$vy>0En+oA?&ZQ^;A|L}pX8z;eXN7PlT3TK#dG!5u&0d$1^0WgEOBGfR{M zr(M0Y_s0L?4rY$|WK*XDYSv1Uj1_{_SSi?mRRWql5O6hCKy_IGH!KB-*eIZWtRMlK z1Z$Bb_zYVFpCVb1gl&S4v0bnpI|SpfQ?LfR1iW8NFcztT&yg4*1%Hh^!Fc2grl3IZK8gg3QQYedZ`g#CNVEc_f(a-Syo++dNK^=Bz;D57Q7O?9 zR0;loGlD;&TJSfh5&QVuD zf`3L(umEAf|A`(eKpmnI%|@Szn(n3=&c2;B`6v7Yr8sBZdf;;tlhD z6>m!PA%+U3Vwhkq-V*#CZ=3In7;cg8#|Wb$#F^`5j8uTX!zjUj#%Oc9fH5M@Q{FLI zBgTr@XO2^Vf53S2b`cZIaStXM?ZqT>J%`B(@b{P^Sc$3T=EpRNMq|1K+>MzM?Zhm> zGRzkIZD zZ9uP#MO=VY3h|$?#$0m|FXEZC^`f?BB#63>W24E=A~6=rVQiA{>vSZU$9!xtI)-GU z5^ReFDaCdRQj8tuT#B7WdDtatKLwxBNu-Ks>@{7P-h~W_sDY9hi}@(BO}HC5M*EN} z>MBQ`=<7qsH`!4Xh-lrY$YcjlY*c^}b3K7lqhlx&QKPlo=m;vz^$h%?t};}Lt{+F0 z$qwR-Q3a~awFNaIZpPG_j7v#IM^G=~iKqsX9Y(AZH%wINc8WrG{sJ#NWjcU+oREI86*CE_7^5d?#X5pTQN6PPu+AiaP=;mQO z6kSipBaIzCMDXqV^&TGit_L=I=b-Hd!@>$I`3B2nnz6L!5am!bqbU zjItmp7%jS;f-xp5#XF+5CX5wbKZtRnjuebH%E1J4ZNfxR=LJlPl_V9DCA@zMQ$+1P zOf~1iJWR9D<(Mw|Iv+F5IlTz8Vr9w3>=;&Hj$vj#<{Dm^tw>NtSq=DHgzOm+b)V`=ANl?6GAHKNWdh!=Go#(GiP86=o%BQ}b@ zN=KsTyL4=dMOcR<;SX1@V2j+_Gm&heo3YKDo3CQKgx9ZNhv=(R>@-;>c9|>%K8rjx z1*sBtr6XO`aTXb(&P&J?wVgt?=z0orL|vK4HP;i!6WzaneDl|g0&~5JBGGrdQ5-AP zMU+U`UV>6{&On(_Hp)d`rJ+L9Ru6wH@Lp6(*x7s9txFPDijGLk_ z595|RcBi%AwuD`$(PB@7*hFA}z$1|F+zOvNjY)gopbz^lR^T5|B3-2a@1L88uT zyly^yg%~X1{YDJ2i1y$Ob58Z)O$pmBV5m74W0XA|BV$RIV3dR%2QfO9;BJhOuss9sh;9~Rtmw-l7$^F+0OO6SFhTTH1}4U$$-pED zI}Ty8=>9oO5q+0}sU|y(Y38pM(_Bq`egy;m@vzaxe|U`ig^}O z9u|ncIgW**>p56t{_?OyfrFR!VX3e?wGqqYe!m{eC5-q_VTHM;oyAJIe|-$AVuAcv zBMcuqjd(-fd90V$wo6DbVP+;aO88wW5@Ug?uu0hMOGT30@8n^Ngh78Rk|n%fjcuY^ zY$D|xO3T9z2|LeWr|7Fa*d^zlz&ZFN{PqA+V_}MsE)1t;B171nmWfP@sRr3G;c4VZ z*tH+IqVLj>7Yn`z`4)W{3XIO6NX|V0ABrXHEJuli!9X2KW3e}*%-m0)+~@!*j0)fv zeaj6>(fvA9Sv)8A;Y=*b6R5T*Q_@i*ueX{}E9%Ndot(p|S*SPX7BpCxv@-~pyDtw- zCQUt$7L#U{q1BM_UsD8M?L(XBdKo%mfhurA!p=h66n%LHx8&T@)P&pST!PM6>^^h} zgZ^6Fv6#}*aMwH(HQ}BxaxM?|6+v4y9*FMO;Gy|E#8y+n?{X0oeOrOBoTGfyVJ_B#xV6D z;)S8c6IdUU29O|(7N5sP;lR;)BnrcOcVm;Vx1bhD!tPW~zJ>iM2azlc2KHc^^4L~| z?V|5|*kR6%KI{}mj~>7-xwmJ-C;Ij%Qso@>H6dNtTTq1zxqp?5ObH|Y)5sS7(2|85 zVX$Q{a)tecdypsWPT7lmVNYNm3KUnTA4L*I&Q+pV!W*?HkuX}Cg;EK>37|~EA6ha| zF6>ULMuprToQGe+ux~#qWA25h5(fQMIAa({LA64Cc>p!$HRUjBCH(df>Llz5WTRdf z_T`|#F!K}w!cgNmG+C%qXc2X`qE*!9$2EBj`mdr**uz(-!=&|9xFPILJ&T(Pb^Ri4 znJ}dlx6SLN6m-h{|2vK@6Z#8r$FQ;$cZHGK{kSKu-yXw#3Hy%c;DN9^4Bx<1=@La-3AQdl! zy}5hwQW#D@iXSa2jrhsJr)1#g7*^sJVI-#s81P!iU_Bev0k3&&OU0`aMjGq!nuOo_ zF-Y{yS-dW~eieh|G3?`L)FSfx@rJqY$D1+t0~jjd?KBJ%b!6Zz(RW#RTOPalatx2* zK8z5C(vBm}0{Jjf!l0kibzyJ8F^m?5v&u0>Uc0jJPRwfnW6eFI0ORD|c?{#tJ#Y#W zgrT$&OcX{l^Ds#msVTwanBS9_q6pd=Fje&J5loYFcgiVDm+)Q-X2!xC$1Gt_;0$I9 zBl$U)W8sfut_e%4Fi*nHd@P8CXR~U;!&oF?IOP(S#N01nsocLjj%DUvkb>pHZVqNv z#PAGO%4=H-R*Akji8bcTQDVG=_X1ciy1o|)M(40G77x!(3&SZ5*d+I^Y9z&kwb&wz z7BwPS7z}VdQ(oH+VY`I=XStp!3^nh;PPum;#V*m;C*YHFcj^hG3L~YpNEb#+IW(2m z_5x%|7*4N1b}UpSatu?rtSOA_u120P)N~yAhG|^cR9s)SqDaDEVPkVa=*Dr> z$zxAoFX|=ym&0ffeU*uTMOn~-CW|ud1X@g*S%Ox1Z99o;683W9&?XEu?m>rzN-4w* zdHpUAH)F#6xFrmp+=JV4?>dW43*VB5F7uj}fjh#UKojm7HXg@4VdU~r+>iOq#)FuL zy?AII&K<&|n1^x%g~5|PgoV*dm(dgRP=u&3oRx__;SVh-cx+{8#efz3Jf6xq)Z)W4 z6Q<$0#l-Iag@pHN@lwL*(F^#|us9b#S@H~MRLEMfhD3p z6Xqh_yyhH2hAz}#!HP$cY5twymhnt1>v!cf4EQem+EJj#SUP1PtDhKqctFu!R>;E!P;DlOes zRGHUIj##aX^{AFGvj044VpxP)!`!Q=6ZSOapk5d*%148+H!lMLVc(uJXfnT7kE6w~ z`2<>p!N4V4Q@Y<)qD{gOrve@3?ytlRVK^m#oAP@5JZ?$Yosx~)!oErlT7{vjmFN-% zYdC5(Y4dK}HR;I|+*4dP@^N2uie!xdwUKB zi~dxAAr`!#8gB@Du9V_U3zV0Mp~BFW0EP*>Q?BAIVYsLTZ<~j!4H$0H?86u#{NYL& z;><(yUW`<_-{oVJgpng<7%l8+%D@<5G|Pu~V$!`BE9^U7g>k}Q;3CEgBbgbPAPlEm z#zduX=R78f+I*O7K6i8Q8pA3~mHYjZm?mNWo*YboXnqgv$0A|mav7GGH1jl;3j2J!u}s+S&Kri?C7DeiVtKe>sg!@)&H)L6R_% z$w911Ypx<$UT>vho4KEF#CG98wjVo$Jy)(`r-iD#ie18PE};5^A7Fvhf63C zM$1Z3Dvaz)L79071W+#QJLE@&`8|3PeqsO73RDWaQx2d?x#=jx855=*M76N*>S5Ff z2Tu7=D-70Cr`0?hKZJT=@3D($Fe#sSz@(>}&}8MkiWbrRO0>#3$_0;W65eV=o9L@T zbjUf9mx~+1V1O4$n{;;?ZdsrL+?Mc3Wi>j5kLk5b7_GaAJHp-qj%0;>*%xq67`no> zR`YP784rZvq62tn(kxojQDU8k5EQiq5SDZBdU)JGgbKid%zgP}xfgik9 zcA&fvuLz@Mhw!T5kpNyZtUZ81!pQy;c>M>j8UF47220rMZ^95^u)YRw2nPz&@ur13 z(u$$NaON2d6Gk&D@s{DyT)Zs|*4JUUu-li75yHssEW`REGIP)YX2>()8iiyH#sSlG>;I6%xY{IO)m?Ggf zS1?t=A6kxKnlMtf7t@8ICN{Og?$lrXz!W>~wfK9D%U@y0@gimsOSRf2t z&A>uo*moR@g#AZ2qBRfvGM5T_kJMn9^4NJC%O&hiJ&qN^NK++N3i}H$W0f#kd<<*M zFPr#yVW^oq{ldq!J|qZxnhLN{DLlwPqJ&S5mtvE!JM9#bg#CN=VM{DjE|P_j{Rglu zhIQDkxb6qAL&6}}6?Y1|Q@G)8UQ74FC$AmnkZN9Q&LCYlaFmxc3VW`UBU9LaYB#cl zVP8IS3=f|~t}x;+L7qi>3i+ZtB`A<{sQDm@%;$--C^kHD1SP_7K|M-^!I~PBnTP#s zYfXA;4=RMAE4A^-{|wT7I8)d~CAz}B1J zavvImk;7F82>()8j3!}EQz2T+!?|L#DzSTwxMspD2hk>B`(AWN7%tw88|Hq#2{(mN z-znS@_B0;DZDBXHF**&onbBn)uI$4dVX*!%?ka_U<(O8&h_40r4fp%;Kp0BP$3qLn zR{W8$|8NC@CcU%=VPUwa0X-(IsYO)S%MnDMuo4FZMet2MewMI1^#Xno_5@0SXI_IF$;-hj!hsVl zcvaYQ^(bC@<~6PDg%~7ZsQCb1H*BfJU}68!d<+qGr`F>QVGkeKo5E;dH--v(*^Unr z1_PORODWvvu{86Vwj0Brc?$l|jyc779PejVPEcLEH@9Chp@ts3sNhEp|lFD5_YGZ$C{Y*Fye*1rw(Af zFj{;P35Ipe*eHzTWg$@*yi$oxhJh+1sYbr!mX~?m&s79rciKK|6NY>NY`4lijUDFo z@=5G8_bV5$OW1qtBz)#!_gSPGme(WQJQOq|!|-q`GKJyd3}g%Ys)~^#jI`prj zzc5<92bIDndoxib3|*t*|?FKk9`2MF&wY34AdHqD zM?e_KY(SHFXiPziNwcYtD(vS{$2F6lq)Mu?aOWU8MD2%hL(bv!gScrqY``rEpJa1@ zYwiVk=rrVO*CmYR?7M7`b`~kCpS=br_Ja|6Bo{T4_(JnDpT`jMn^KH7{+pH}a`2{vQ4Y6djJJf5%%gZ) z*ju?D!ws|cV1%$cwE=PFcW)s^8t$j5M&UsE1&mg@H`w4x7%r^DJLX4Kp1AvHd**&e>$cJA73oTRAJxMJ(#8}eA9~Q684tt z!A!%fM$8h1n$BUiu)pvs<_P=tUclU#hm)8m4A!5(0!7<(1`ADC8Nec8WH)vCV^Tks z3ZvZXT_)^5?8kE9z|j`0Fu$i#uu>R0mXB4!Xl(#%guQ&*;)MfTN?k9E>`Oy}Fw{gX z17SaR#uJst>wavKFj{&PNy1>wF>I0hmnV=cVPsz+wn=!)hwT=qyahYVz4bD73J1#5 zu}c^(Zh}wPO@)(GVf0)M(uI9jk03+Xe>e}B!ifJYvW0)i4j@Mu&aObNc___Cp0Ixp z8{C+b3kt$$0k_43z2zw=HawSw62ptlC>4e?TTmwK<7#WUNi!~?LO76-1HUlB6^Ba0 zJZ_8$`zrV1j4;}ihicW+w<)MGuQg?;HQZN%I^h#O-+JM|kvue*^kO{%!fU(mEHCu=oH;P zi7wHd3%DbXQFfho&G`iGNf<6Xg!?f(jR)rS=y5z01}o3wkuY>61wmn?H3wl~PjeA^ zguPb|ASw*j)S*up&Pu~$;a?6HU_e>;*Frp%u)p{!o(V&~3wSP!W?se%VL0YAP;FSveBnV^;hSpUx!2-`5ADS(!pMOuc-64>0$vmLx9-Crlja@4 z>xTaQ82sF8Tia4FM8du*9uP41-I;h(80O;EP+^F>JHujl7HgGLCYE{jGrlCaGOEtt&VW_bJWx^h=NtO%4*(Xt<2yXM7m3eKZrmVRa@uZcomrEFD zgguQ%Q7!C0LRDGI>uJNTaID>-D{{jtMHbD(F>_~TNw18z;NN?Ivzd{hB>*5i+MPQ zk;0zlYK#&_tBzx|u%9chW6Uo#wB9l4k!FlFY2_J=Qx?AQW4wgj+-sd6jGpsjqA6j<%PCbnU<~Q>&77F`|xU68+ScD}KKB=Y=8ew0>Su7I{9IwT4VYK`VR+tB_ zaji6IX&P1udz<%TjWBpJ74gFE)IC@)?7LEp1Yx8;7aN67PGurd7|toiCSmk^0g{CM zzH)3)b|2;;S;Ao8GPar5y5ra`?9Hvk4q;Cq4Lhxn8Q3LZq%Z?MVemY+%!JWW>e34P zi!UO>9!VB5CG0zuk8EM@*~7?@`!^ioO8A$;dgKWs``O+KgFL-aAnZHNbzDPk85Apm zHmW9AsLUfM74}}PLYXB{hjIx+0bW%s>}fd)zlCDCD}_Nn8(d*GRTs_(qk;3N7WOnZ zqej?!n1>UDLH7A|hSbxl7e-if4d(ZB0|GJWQ8Wn$4ppPYFtrw~!jP{3*M#9i9N`Kh z=QGe@xSt1I4V(7krujYW!!5(i6Sytxt2vHNVe|-(b=f1~QGN+SSDJBG!drWBPr@E{ z3ipNGKDM~RNX~9N6h_nc^on-Mf=9nW?N!+{#~2)lV4BWiv#4x>-l*RUIpg~6Kh z7!dX}XXB|bT#$)p!sv+_JU73W^YOwwWFNvy;S-Mkeza%JYndbraXIa03IB8!zew26 zAsb$3jLYx%72%VErFiv)R#A`T?89pkN4aV+$gr^pufOmb%zNn=EMdrZ4nu@tY8|{G z_uHv>Q^Ia4tPU0Sa6C0k7^&HVw+ve@;ca2x`EwX<$g>(Fggvc$5hn~aR%4{FKPw%h zgpu8QF>-S=*u!pAtmYIiB=~yldR+eIg`MunXmBQXU zHn=7|&3!Y&g7b(sEN;bm!@XHZ5QaDe*(mJigGw|k$;KvOFi?ynVZ_fNt|6DYA!u~RjDF9o|qZAamgbEx?gQZ4*`Zk!4GsBxJgjB>t|X@2?f zWt-o9KI91d+0Et(2kJ_ZCybsvhkRjg%^?&BBaJ*WD-4yDpjg;Ju7sf$s@w`A7YcD-*jt){ z2f`qiwI2%m4rJkx@Gr#y1kFQLEyBXy`f~IL`->_N6+XTkK%el3mLqs93^wp&nE5?^ z2~UNQ-52o8kUBNbg;BocFN8tvQN1*2whuoFdm8iblSy+=;b&p*sb>5ljBqys|HEr^ zLsXS~McAF1fmaPv3h_F8-80d*+&nX%RNmhx45#zltuWG3h)u%Y=3___Mp>9Gis1HXBuf}PnTc)YwcrxA z3;$A_jvc~q>2B;4_FeL0moQqyv$w+T6zVGodr$F%gD_axfDB<@6P0j<{gp+?7WOoA z_e>bxeGs|AU{wHl=GRBF1KQehvbQf0!&mugXN z9{BQC2z%KM`Ay16ZKYuix6g#p`evLF2CwiOuCSZOSZaiQ+$63QhRTkiPS|_45%uO_ zUltlndMOV9Ves;PGzp`{IcPDgYDBAfsJV!1!Y9@BXftUg?+F)nr?%jRJ(yMqXjB@AjnPFW8 zo(p?hcjJZSya+Evw{r2LoFiAu@sqH>fUCK}Cwr^#i{a^d;HCF*c3j3QFTM6RdYo$u z!hTK%UK946KZ!xYP~&;LE{xQj#$e$So`D!*9-15RhOj3}fiHxfbd`Hs%@nv#>zecfJq{h5aQoi6wko zTZ$!$>zgJlwNROUEHli`!g9I)nFC#;a;%hdZwuR7VUQ1OjWE>AajvkhmE&B6>L@{i z=;2XpG@n%JNi^hI!6sp3|3xGTpB(gKi$YyLie%Bh?8i1a2QTo%gCQ3yb{N)Nz)oSr z&m#}QUZ))<>^pq{spjEmD$)&W3y@(Rjvqm$68okS*%A)aRv|~&!)>cvVYK`*@`U}> zEyx!J{VgaE{)OrvMZ!o?DT;;BqVp&b_H(#XDtvM(2W3jPvkc`DhG>4ELfG5thhNxt z^#Ce`k>drZQmC)8aYn*mO%7%KDOwn>}L zpwsZuUUUij&L71clU^vtU6bxF#XVvF2_DuJ{w1B~9)!WFt9U4k29D#A`Sl$`P*wJz z6=CyQSBoBVKg`xv7)hb|1M|S?$YaBX5)24KSDNtD{AL`%Gs7loY4zC!VID%LI&1-`HT!Pmm3{&Z3 zkc8ju#p@>IQo>+i505ksvG5!hzag(*pT(OJMlRQ5s4!YzhGD|Kx_Z22p^i7=ZDFv! z62le2mpoV|y3LkWbmurm%408&C5^I}uI6F1aDct*7>lX(0^SjZc)Ve(FhcF6al$a0 z%<;mW#!5^OM$5QyChWa%5tD>{SIaQjJRIbzf=N&8##G_si!GQY>`uwUbYW!wKFqW- zn~%4x%t30V+BHbt?-h^2^2VqDq8ikX$css?@jS|`PT%bYbctHItfqRYdR>n7mr z7#oJXhKyk@kE|FMv&fmzdK%k?EFLe2vqB0xVwh^7WXR0Oo;c*AUl!eqWmLowQ_1_H z*D0bZ`soxLLvE5Cijh;rks-e-4ROdF;-)yUnm85XT{cFT2XJ3O^w?veBL;Q?mtt5= zqAN~VI(scnxhTF7;}Uywi9Yl2eKAP(a4SYm0{5bKUcrOtGDrPrVtGjLNu1dS7?{yo z8PDR_cJQJ*cvr`(27Mk2elww#gLg6HJLW@-w`v%gfD`U3h!L~?p6Fg#2*lB12H~7- oOvSL #include -#ifdef LLAMA_SHARED +#ifdef RWKV_SHARED # if defined(_WIN32) && !defined(__MINGW32__) -# ifdef LLAMA_BUILD +# ifdef RWKV_BUILD # define RWKV_API __declspec(dllexport) # else # define RWKV_API __declspec(dllimport) diff --git a/spm-headers/llama.h b/spm-headers/llama.h deleted file mode 120000 index 9acceb9..0000000 --- a/spm-headers/llama.h +++ /dev/null @@ -1 +0,0 @@ -../llama.h \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt deleted file mode 100644 index 157d733..0000000 --- a/tests/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -function(llama_add_test source) - get_filename_component(TEST_TARGET ${source} NAME_WE) - add_executable(${TEST_TARGET} ${source}) - target_link_libraries(${TEST_TARGET} PRIVATE llama) - add_test(NAME ${TEST_TARGET} COMMAND $ ${ARGN}) -endfunction() - -# llama_add_test(test-double-float.c) # SLOW -llama_add_test(test-quantize.c) -llama_add_test(test-tokenizer-0.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../models/ggml-vocab.bin) diff --git a/tests/test-double-float.c b/tests/test-double-float.c deleted file mode 100644 index 89dafc9..0000000 --- a/tests/test-double-float.c +++ /dev/null @@ -1,53 +0,0 @@ -// These tests may take a long time! -// They are to prove that conversion from double to float of various functions in ggml.c doesn't affect the result. -// This is done by checking all finite (non-NaN, non-infinite) floats. - -#undef NDEBUG -#include -#include -#include -#include - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdouble-promotion" - -// ggml.c::quantize_row_q4_0_reference -inline static uint8_t round_orig(float v0) { return ((int8_t) (round(v0))) + 8; } - -// ggml.c::ggml_silu_f32 -inline static float silu_orig(float x) { - return x/(1.0 + exp(-x)); -} - -#pragma GCC diagnostic pop - -// ggml.c::quantize_row_q4_0_reference -inline static uint8_t round_float(float v0) { return (int8_t)roundf(v0) + 8; } - -// ggml.c::ggml_silu_f32 -inline static float silu_float(float x) { - return x/(1.0f + expf(-x)); -} - -int main(void) { - uint32_t x = UINT32_MAX; - do { - float f = *(float *)&x; - assert(!isfinite(f) || (round_orig(f) == round_float(f))); - } while (x--); - -#ifdef __F16C__ - // GELU and SILU implementations are used with a FP16 lookup table. - // The original and float-only results are not equal for all inputs after converting to FP16. - // GELU is an approximation anyway (tanh), not tested here. - // For SILU, verify that the results are at least the closest floating point numbers, if the FP16 values don't match. - for (x = 0; x <= UINT16_MAX; x++) { - float f = _cvtsh_ss(x); - const float so = silu_orig(f); - const float sf = silu_float(f); - assert( (_cvtss_sh(so, 0) == _cvtss_sh(sf, 0)) - || (nextafterf(so, sf) == sf) - || (nextafterf(sf, so) == so)); - } -#endif -} diff --git a/tests/test-quantize.c b/tests/test-quantize.c deleted file mode 100644 index 993e9dc..0000000 --- a/tests/test-quantize.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "ggml.h" -#undef NDEBUG -#include -#include - -int main(void) { - #define QK 32 - float src[QK]; - uint8_t dst[24]; - int64_t hist[16]; - - for (int i = 0; i < QK; i++) { - src[i] = (float)(i + 1); - } - - size_t size = ggml_quantize_q4_0(src, dst, QK, QK, hist); - assert(size == 20); - float max_result = ((float *)dst)[0]; - float max_expected = src[31] / ((1 << 3) - 1); - assert(max_result == max_expected); - for (int i = 0; i < QK; i++) { - uint8_t q4_result = (i % 2) ? (dst[sizeof(float) + i/2] >> 4) : (dst[sizeof(float) + i/2] & 0xF); - uint8_t q4_expected = roundf(src[i] / max_expected) + 8; - assert(q4_result == q4_expected); - } - - size = ggml_quantize_q4_1(src, dst, QK, QK, hist); - assert(size == 24); - float delta_result = ((float *)dst)[0]; - float delta_expected = (src[31] - src[0]) / ((1 << 4) - 1); - assert(delta_result == delta_expected); - float min_result = ((float *)dst)[1]; - float min_expected = src[0]; - assert(min_result == min_expected); - for (int i = 0; i < QK; i++) { - uint8_t q4_result = (i % 2) ? (dst[sizeof(float)*2 + i/2] >> 4) : (dst[sizeof(float)*2 + i/2] & 0xF); - uint8_t q4_expected = roundf((src[i] - min_expected) / delta_expected); - assert(q4_result == q4_expected); - } - - return 0; -} diff --git a/tests/test-tokenizer-0.cpp b/tests/test-tokenizer-0.cpp deleted file mode 100644 index 55b086d..0000000 --- a/tests/test-tokenizer-0.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "llama.h" - -#include -#include -#include -#include - -static const std::map> k_tests = { - { "Hello World", { 1, 10994, 2787, }, }, - { " Hello World", { 1, 15043, 2787, }, }, - { " Hello World!", { 1, 15043, 2787, 29991, }, }, - { " this is 🦙.cpp", { 1, 445, 338, 29871, 243, 162, 169, 156, 29889, 8223, }, }, - { "w048 7tuijk dsdfhu", { 1, 29893, 29900, 29946, 29947, 29871, 29955, 9161, 13535, 18031, 2176, 6905, }, }, - { "нещо на Български", { 1, 821, 4851, 665, 1386, 29713, 1305, }, }, -}; - -int main(int argc, char **argv) { - if (argc < 2) { - fprintf(stderr, "Usage: %s \n", argv[0]); - return 1; - } - - const std::string fname = argv[1]; - - fprintf(stderr, "%s : reading vocab from: '%s'\n", __func__, fname.c_str()); - - llama_context * ctx; - - // load the vocab - { - auto lparams = llama_context_default_params(); - - lparams.vocab_only = true; - - ctx = llama_init_from_file(fname.c_str(), lparams); - - if (ctx == NULL) { - fprintf(stderr, "%s: error: failed to load vocab '%s'\n", __func__, fname.c_str()); - return 1; - } - } - - const int n_vocab = llama_n_vocab(ctx); - - if (n_vocab != 32000) { - fprintf(stderr, "%s : expected 32000 tokens, got %d\n", __func__, n_vocab); - return 2; - } - - for (const auto & test_kv : k_tests) { - std::vector res(test_kv.first.size()); - const int n = llama_tokenize(ctx, test_kv.first.c_str(), res.data(), res.size(), true); - res.resize(n); - - bool correct = res.size() == test_kv.second.size(); - - for (int i = 0; i < (int) res.size() && correct; ++i) { - if (res[i] != test_kv.second[i]) { - correct = false; - } - } - - if (!correct) { - fprintf(stderr, "%s : failed test: '%s'\n", __func__, test_kv.first.c_str()); - fprintf(stderr, "%s : expected tokens: ", __func__); - for (const auto & t : test_kv.second) { - fprintf(stderr, "%6d, ", t); - } - fprintf(stderr, "\n"); - fprintf(stderr, "%s : got tokens: ", __func__); - for (const auto & t : res) { - fprintf(stderr, "%6d, ", t); - } - fprintf(stderr, "\n"); - - return 3; - } - } - - llama_free(ctx); - - return 0; -}