diff --git a/.circleci/test.yml b/.circleci/test.yml index 305544a94e..7e2f892cbf 100644 --- a/.circleci/test.yml +++ b/.circleci/test.yml @@ -62,7 +62,7 @@ jobs: pip install -U numpy pip install git+https://github.com/open-mmlab/mmengine.git@main pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' pip install git+https://github.com/open-mmlab/mmdetection.git@dev-3.x pip install -r requirements/tests.txt pip install -r requirements/albu.txt @@ -83,7 +83,7 @@ jobs: type: string cuda: type: enum - enum: ["11.0"] + enum: ["11.0", "11.7"] cudnn: type: integer default: 8 @@ -111,7 +111,7 @@ jobs: docker exec mmpose pip install -U numpy docker exec mmpose pip install -e /mmengine docker exec mmpose pip install -U openmim - docker exec mmpose mim install 'mmcv >= 2.0.0rc1' + docker exec mmpose mim install 'mmcv >= 2.0.0' docker exec mmpose pip install -e /mmdetection docker exec mmpose pip install -r requirements/tests.txt docker exec mmpose pip install -r requirements/albu.txt @@ -157,8 +157,8 @@ workflows: - lint - build_cpu: name: maximum_version_cpu - torch: 1.13.0 - torchvision: 0.14.0 + torch: 2.0.0 + torchvision: 0.15.1 python: 3.9.0 requires: - minimum_version_cpu @@ -174,6 +174,13 @@ workflows: cuda: "11.0" requires: - hold + - build_cuda: + name: maximum_version_gpu + torch: 2.0.0 + cuda: "11.7" + cudnn: 8 + requires: + - hold merge_stage_test: when: not: diff --git a/.github/ISSUE_TEMPLATE/1-bug-report.yml b/.github/ISSUE_TEMPLATE/1-bug-report.yml new file mode 100644 index 0000000000..c3682b9964 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-bug-report.yml @@ -0,0 +1,92 @@ +name: "🐞 Bug report" +description: "Create a report to help us reproduce and fix the bug" +labels: bug +title: "[Bug] " + +body: + - type: markdown + attributes: + value: | + ## Note + For general usage questions or idea discussions, please post it to our [**Forum**](https://github.com/open-mmlab/mmpose/discussions) + Please fill in as **much** of the following form as you're able to. **The clearer the description, the shorter it will take to solve it.** + + - type: checkboxes + attributes: + label: Prerequisite + description: Please check the following items before creating a new issue. + options: + - label: I have searched [Issues](https://github.com/open-mmlab/mmpose/issues) and [Discussions](https://github.com/open-mmlab/mmpose/discussions) but cannot get the expected help. + required: true + - label: The bug has not been fixed in the latest version(https://github.com/open-mmlab/mmpose). + required: true + + - type: textarea + attributes: + label: Environment + description: | + Please run following commands and and copy-paste it here: + - `python -c "from mmpose.utils import collect_env; print(collect_env())"` to collect necessary environment information. + - `pip list | grep mm` to collect repositories related to OpenMMLab. + - \[Optional\] Other environment variables that may be related (such as `$PATH`, `$LD_LIBRARY_PATH`, `$PYTHONPATH`, etc.) + validations: + required: true + + - type: textarea + attributes: + label: Reproduces the problem - code sample + description: | + Please provide a code sample that reproduces the problem you ran into. It can be a Colab link or just a code snippet. + placeholder: | + ```python + # Sample code to reproduce the problem + ``` + validations: + required: true + + - type: textarea + attributes: + label: Reproduces the problem - command or script + description: | + What command or script did you run? + placeholder: | + ```shell + The command or script you run. + ``` + validations: + required: true + + - type: textarea + attributes: + label: Reproduces the problem - error message + description: | + Please provide the error message or logs you got, with the full traceback. + + Tip: You can attach screenshots or log files by dragging them into the text area.. + placeholder: | + ``` + The error message or logs you got, with the full traceback. + ``` + validations: + required: true + + - type: textarea + attributes: + label: Additional information + description: | + Tell us anything else you think we should know. + + Tip: You can attach screenshots or log files by dragging them into the text area. + placeholder: | + 1. What's your expected result? + 2. What dataset did you use? + 3. What do you think might be the reason? + + - type: markdown + attributes: + value: | + ## Acknowledgement + Thanks for taking the time to fill out this report. + + If you have already identified the reason, we strongly appreciate you creating a new PR to fix it [**Here**](https://github.com/open-mmlab/mmpose/pulls)! + Please refer to [**Contribution Guide**](https://mmpose.readthedocs.io/en/latest/contribution_guide.html) for contributing. diff --git a/.github/ISSUE_TEMPLATE/2-feature_request.yml b/.github/ISSUE_TEMPLATE/2-feature_request.yml new file mode 100644 index 0000000000..fc726c89de --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-feature_request.yml @@ -0,0 +1,37 @@ +name: 🚀 Feature request +description: Suggest an idea for this project +labels: feature-request +title: "[Feature] " + +body: + - type: markdown + attributes: + value: | + ## Note + For general usage questions or idea discussions, please post it to our [**Forum**](https://github.com/open-mmlab/mmpose/discussions) + + Please fill in as **much** of the following form as you're able to. **The clearer the description, the shorter it will take to solve it.** + + - type: textarea + attributes: + label: What is the feature? + description: Tell us more about the feature and how this feature can help. + placeholder: | + E.g., It is inconvenient when \[....\]. + validations: + required: true + + - type: textarea + attributes: + label: Any other context? + description: | + Have you considered any alternative solutions or features? If so, what are they? Also, feel free to add any other context or screenshots about the feature request here. + + - type: markdown + attributes: + value: | + ## Acknowledgement + Thanks for taking the time to fill out this report. + + We strongly appreciate you creating a new PR to implement it [**Here**](https://github.com/open-mmlab/mmpose/pulls)! + Please refer to [**Contribution Guide**](https://mmpose.readthedocs.io/en/latest/contribution_guide.html) for contributing. diff --git a/.github/ISSUE_TEMPLATE/3-documentation.yml b/.github/ISSUE_TEMPLATE/3-documentation.yml new file mode 100644 index 0000000000..39cb104683 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3-documentation.yml @@ -0,0 +1,35 @@ +name: 📚 Documentation +description: Report an issue related to the documentation. +labels: "docs" +title: "[Docs] " + +body: + - type: markdown + attributes: + value: | + ## Note + For general usage questions or idea discussions, please post it to our [**Forum**](https://github.com/open-mmlab/mmpose/discussions) + Please fill in as **much** of the following form as you're able to. **The clearer the description, the shorter it will take to solve it.** + + - type: textarea + attributes: + label: 📚 The doc issue + description: > + A clear and concise description the issue. + validations: + required: true + + - type: textarea + attributes: + label: Suggest a potential alternative/fix + description: > + Tell us how we could improve the documentation in this regard. + + - type: markdown + attributes: + value: | + ## Acknowledgement + Thanks for taking the time to fill out this report. + + If you have already identified the reason, we strongly appreciate you creating a new PR to fix it [**here**](https://github.com/open-mmlab/mmpose/pulls)! + Please refer to [**Contribution Guide**](https://mmpose.readthedocs.io/en/latest/contribution_guide.html) for contributing. diff --git a/.github/ISSUE_TEMPLATE/error-report.md b/.github/ISSUE_TEMPLATE/error-report.md deleted file mode 100644 index 6c7bdea9a1..0000000000 --- a/.github/ISSUE_TEMPLATE/error-report.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -name: Error report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' ---- - -Thanks for your error report and we appreciate it a lot. -If you feel we have helped you, give us a STAR! :satisfied: - -**Checklist** - -1. I have searched related issues but cannot get the expected help. -2. The bug has not been fixed in the latest version. - -**Describe the bug** - -A clear and concise description of what the bug is. - -**Reproduction** - -- What command or script did you run? - -``` -A placeholder for the command. -``` - -- What config did you run? - -``` -A placeholder for the config. -``` - -- Did you make any modifications on the code or config? Did you understand what you have modified? -- What dataset did you use? - -**Environment** - -1. Please run `PYTHONPATH=${PWD}:$PYTHONPATH python mmpose/utils/collect_env.py` to collect necessary environment information and paste it here. -2. You may add addition that may be helpful for locating the problem, such as - -- How you installed PyTorch \[e.g., pip, conda, source\] -- Other environment variables that may be related (such as `$PATH`, `$LD_LIBRARY_PATH`, `$PYTHONPATH`, etc.) - -**Error traceback** - -If applicable, paste the error traceback here. - -``` -A placeholder for traceback. -``` - -**Bug fix** - -If you have already identified the reason, you can provide the information here. If you are willing to create a PR to fix it, please also leave a comment here and that would be much appreciated! diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index b4ea6903ed..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' ---- - -Thanks for your feature request and we will review and plan for it when necessary. -If you feel we have helped you, give us a STAR! :satisfied: - -**Steps** - -1. Check if the feature has been requested in the [meta issue](https://github.com/open-mmlab/mmpose/issues/9), and if so, click thumb up button. -2. Post the feature request in the [meta issue](https://github.com/open-mmlab/mmpose/issues/9), if it is new. - -**Describe the feature** - -**Motivation** - -A clear and concise description of the motivation of the feature. - -1. Ex1. It is inconvenient when \[....\]. -2. Ex2. There is a recent paper \[....\], which is very helpful for \[....\]. - -**Related resources** - -If there is an official code released or third-party implementations, please also provide the information here, which would be very helpful. - -**Additional context** - -Add any other context or screenshots about the feature request here. -If you would like to implement the feature and create a PR, please leave a comment here and that would be much appreciated. diff --git a/.github/ISSUE_TEMPLATE/general_questions.md b/.github/ISSUE_TEMPLATE/general_questions.md deleted file mode 100644 index f02dd63a80..0000000000 --- a/.github/ISSUE_TEMPLATE/general_questions.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: General questions -about: Ask general questions to get help -title: '' -labels: '' -assignees: '' ---- diff --git a/.github/ISSUE_TEMPLATE/reimplementation_questions.md b/.github/ISSUE_TEMPLATE/reimplementation_questions.md deleted file mode 100644 index 5e1f91e39f..0000000000 --- a/.github/ISSUE_TEMPLATE/reimplementation_questions.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -name: Reimplementation Questions -about: Ask about questions during model reimplementation -title: '' -labels: reimplementation -assignees: '' ---- - -If you feel we have helped you, give us a STAR! :satisfied: - -**Notice** - -There are several common situations in the reimplementation issues as below - -1. Reimplement a model in the model zoo using the provided configs. -2. Reimplement a model in the model zoo on other dataset (e.g., custom datasets). -3. Reimplement a custom model but all the components are implemented in MMPose. -4. Reimplement a custom model with new modules implemented by yourself. - -There are several things to do for different cases as below. - -- For case 1 & 3, please follow the steps in the following sections thus we could help to quick identify the issue. -- For case 2 & 4, please understand that we are not able to do much help here because we usually do not know the full code and the users should be responsible to the code they write. -- One suggestion for case 2 & 4 is that the users should first check whether the bug lies in the self-implemented code or the original code. For example, users can first make sure that the same model runs well on supported datasets. If you still need help, please describe what you have done and what you obtain in the issue, and follow the steps in the following sections and try as clear as possible so that we can better help you. - -**Checklist** - -1. I have searched related issues but cannot get the expected help. -2. The issue has not been fixed in the latest version. - -**Describe the issue** - -A clear and concise description of what the problem you meet and what have you done. - -**Reproduction** - -- What command or script did you run? - -``` -A placeholder for the command. -``` - -- What config dir you run? - -``` -A placeholder for the config. -``` - -- Did you make any modifications on the code or config? Did you understand what you have modified? -- What dataset did you use? - -**Environment** - -1. Please run `PYTHONPATH=${PWD}:$PYTHONPATH python mmpose/utils/collect_env.py` to collect necessary environment information and paste it here. -2. You may add addition that may be helpful for locating the problem, such as - -- How you installed PyTorch \[e.g., pip, conda, source\] -- Other environment variables that may be related (such as `$PATH`, `$LD_LIBRARY_PATH`, `$PYTHONPATH`, etc.) - -**Results** - -If applicable, paste the related results here, e.g., what you expect and what you get. - -``` -A placeholder for results comparison -``` - -**Issue fix** - -If you have already identified the reason, you can provide the information here. If you are willing to create a PR to fix it, please also leave a comment here and that would be much appreciated! diff --git a/.github/workflows/merge_stage_test.yml b/.github/workflows/merge_stage_test.yml index a9ff9715d9..bb60ad40fa 100644 --- a/.github/workflows/merge_stage_test.yml +++ b/.github/workflows/merge_stage_test.yml @@ -18,7 +18,7 @@ concurrency: jobs: build_cpu_py: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 strategy: matrix: python-version: [3.8, 3.9] @@ -27,9 +27,9 @@ jobs: - torch: 1.8.1 torchvision: 0.9.1 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip @@ -43,12 +43,15 @@ jobs: - name: Install MMCV run: | pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' - name: Install MMDet - run: pip install git+https://github.com/open-mmlab/mmdetection.git@dev-3.x + run: | + python -m pip install --upgrade pip setuptools wheel + pip install git+https://github.com/open-mmlab/mmdetection.git@dev-3.x - name: Install other dependencies run: | pip install -r requirements/tests.txt + pip install -r requirements/runtime.txt pip install -r requirements/albu.txt pip install -r requirements/poseval.txt - name: Build and install @@ -60,16 +63,14 @@ jobs: coverage report -m build_cpu_pt: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 strategy: matrix: python-version: [3.7] - torch: [1.6.0, 1.7.1, 1.8.1, 1.9.1, 1.10.1, 1.11.0, 1.12.1, 1.13.0] + torch: [1.8.0, 1.8.1, 1.9.1, 1.10.1, 1.11.0, 1.12.1, 1.13.0] include: - - torch: 1.6.0 - torchvision: 0.7.0 - - torch: 1.7.1 - torchvision: 0.8.2 + - torch: 1.8.0 + torchvision: 0.9.0 - torch: 1.8.1 torchvision: 0.9.1 - torch: 1.9.1 @@ -82,10 +83,13 @@ jobs: torchvision: 0.13.1 - torch: 1.13.0 torchvision: 0.14.0 + - torch: 2.0.0 + torchvision: 0.15.1 + python-version: 3.8 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip @@ -99,12 +103,15 @@ jobs: - name: Install MMCV run: | pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' - name: Install MMDet - run: pip install git+https://github.com/open-mmlab/mmdetection.git@dev-3.x + run: | + python -m pip install --upgrade pip setuptools wheel + pip install git+https://github.com/open-mmlab/mmdetection.git@dev-3.x - name: Install other dependencies run: | pip install -r requirements/tests.txt + pip install -r requirements/runtime.txt pip install -r requirements/albu.txt pip install -r requirements/poseval.txt - name: Build and install @@ -126,7 +133,7 @@ jobs: fail_ci_if_error: false build_cu102: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 container: image: pytorch/pytorch:1.8.1-cuda10.2-cudnn7-devel strategy: @@ -136,9 +143,9 @@ jobs: - torch: 1.8.1 cuda: 10.2 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip @@ -158,27 +165,38 @@ jobs: pip install -U numpy pip install git+https://github.com/open-mmlab/mmengine.git@main pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' pip install git+https://github.com/open-mmlab/mmdetection.git@dev-3.x pip install -r requirements/tests.txt + pip install -r requirements/runtime.txt pip install -r requirements/albu.txt pip install -r requirements/poseval.txt - name: Build and install + run: rm -rf .eggs && pip install -e . + - name: Run unittests and generate coverage report run: | - python setup.py check -m -s - TORCH_CUDA_ARCH_LIST=7.0 pip install -e . + coverage run --branch --source mmpose -m pytest tests/ + coverage xml + coverage report -m build_windows: - runs-on: ${{ matrix.os }} + runs-on: windows-2022 strategy: matrix: os: [windows-2022] python: [3.7] platform: [cpu, cu111] + torch: [1.8.1] + torchvision: [0.9.1] + include: + - python-version: 3.8 + platform: cu117 + torch: 2.0.0 + torchvision: 0.15.1 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip @@ -186,20 +204,22 @@ jobs: - name: Install lmdb run: python -m pip install lmdb - name: Install PyTorch - run: python -m pip install torch==1.8.1+${{matrix.platform}} torchvision==0.9.1+${{matrix.platform}} -f https://download.pytorch.org/whl/lts/1.8/torch_lts.html + run: python -m pip install torch==${{matrix.torch}}+${{matrix.platform}} torchvision==${{matrix.torchvision}}+${{matrix.platform}} -f https://download.pytorch.org/whl/${{matrix.platform}}/torch_stable.html - name: Install mmpose dependencies run: | python -m pip install -U numpy python -m pip install git+https://github.com/open-mmlab/mmengine.git@main python -m pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' python -m pip install git+https://github.com/open-mmlab/mmdetection.git@dev-3.x python -m pip install -r requirements/tests.txt + python -m pip install -r requirements/runtime.txt python -m pip install -r requirements/albu.txt python -m pip install -r requirements/poseval.txt - name: Build and install run: | - python -m pip install -e . + python -m pip install --upgrade pip setuptools wheel + python -m pip install -e . -v - name: Run unittests and generate coverage report run: | pytest tests/ diff --git a/.github/workflows/pr_stage_test.yml b/.github/workflows/pr_stage_test.yml index 74d041d0b0..5ed6fc8ae7 100644 --- a/.github/workflows/pr_stage_test.yml +++ b/.github/workflows/pr_stage_test.yml @@ -16,7 +16,7 @@ concurrency: jobs: build_cpu: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 strategy: matrix: python-version: [3.7] @@ -24,9 +24,9 @@ jobs: - torch: 1.8.1 torchvision: 0.9.1 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip @@ -37,12 +37,14 @@ jobs: run: pip install torch==${{matrix.torch}}+cpu torchvision==${{matrix.torchvision}}+cpu -f https://download.pytorch.org/whl/torch_stable.html - name: Install mmpose dependencies run: | + python -m pip install --upgrade pip setuptools wheel pip install -U numpy pip install git+https://github.com/open-mmlab/mmengine.git@main pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' pip install git+https://github.com/open-mmlab/mmdetection.git@dev-3.x pip install -r requirements/tests.txt + pip install -r requirements/runtime.txt pip install -r requirements/albu.txt pip install -r requirements/poseval.txt - name: Build and install @@ -63,16 +65,16 @@ jobs: fail_ci_if_error: false build_cu102: - runs-on: ubuntu-18.04 + runs-on: ubuntu-22.04 container: image: pytorch/pytorch:1.8.1-cuda10.2-cudnn7-devel strategy: matrix: python-version: [3.7] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip @@ -93,27 +95,78 @@ jobs: pip install -U numpy pip install git+https://github.com/open-mmlab/mmengine.git@main pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' pip install git+https://github.com/open-mmlab/mmdetection.git@dev-3.x pip install -r requirements/tests.txt + pip install -r requirements/runtime.txt pip install -r requirements/albu.txt pip install -r requirements/poseval.txt - name: Build and install + run: rm -rf .eggs && pip install -e . + - name: Run unittests and generate coverage report run: | - python setup.py check -m -s - TORCH_CUDA_ARCH_LIST=7.0 pip install -e . + coverage run --branch --source mmpose -m pytest tests/ + coverage xml + coverage report -m + + build_cu117: + runs-on: ubuntu-22.04 + container: + image: pytorch/pytorch:2.0.0-cuda11.7-cudnn8-devel + strategy: + matrix: + python-version: [3.9] + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Upgrade pip + run: pip install pip --upgrade + - name: Fetch GPG keys + run: | + apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub + apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/7fa2af80.pub + - name: Install system dependencies + run: apt-get update && apt-get install -y ffmpeg libsm6 libxext6 git ninja-build libglib2.0-0 libxrender-dev + - name: Install mmpose dependencies + run: | + pip install -U numpy + pip install git+https://github.com/open-mmlab/mmengine.git@main + pip install -U openmim + mim install 'mmcv >= 2.0.0' + pip install git+https://github.com/open-mmlab/mmdetection.git@dev-3.x + pip install -r requirements/tests.txt + pip install -r requirements/runtime.txt + pip install -r requirements/albu.txt + pip install -r requirements/poseval.txt + - name: Build and install + run: rm -rf .eggs && pip install -e . + - name: Run unittests and generate coverage report + run: | + coverage run --branch --source mmpose -m pytest tests/ + coverage xml + coverage report -m build_windows: - runs-on: ${{ matrix.os }} + runs-on: windows-2022 strategy: matrix: os: [windows-2022] python: [3.7] platform: [cpu, cu111] + torch: [1.8.1] + torchvision: [0.9.1] + include: + - python-version: 3.8 + platform: cu117 + torch: 2.0.0 + torchvision: 0.15.1 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Upgrade pip @@ -121,20 +174,21 @@ jobs: - name: Install lmdb run: python -m pip install lmdb - name: Install PyTorch - run: python -m pip install torch==1.8.1+${{matrix.platform}} torchvision==0.9.1+${{matrix.platform}} -f https://download.pytorch.org/whl/lts/1.8/torch_lts.html + run: python -m pip install torch==${{matrix.torch}}+${{matrix.platform}} torchvision==${{matrix.torchvision}}+${{matrix.platform}} -f https://download.pytorch.org/whl/${{matrix.platform}}/torch_stable.html - name: Install mmpose dependencies run: | python -m pip install -U numpy python -m pip install git+https://github.com/open-mmlab/mmengine.git@main python -m pip install -U openmim - mim install 'mmcv >= 2.0.0rc1' + mim install 'mmcv >= 2.0.0' python -m pip install git+https://github.com/open-mmlab/mmdetection.git@dev-3.x python -m pip install -r requirements/tests.txt python -m pip install -r requirements/albu.txt python -m pip install -r requirements/poseval.txt - name: Build and install run: | - python -m pip install -e . + python -m pip install --upgrade pip setuptools wheel + python -m pip install -e . -v - name: Run unittests and generate coverage report run: | pytest tests/ diff --git a/.owners.yml b/.owners.yml new file mode 100644 index 0000000000..2050b43c10 --- /dev/null +++ b/.owners.yml @@ -0,0 +1,16 @@ +assign: + issues: enabled + pull_requests: disabled + strategy: + # random + daily-shift-based + scedule: + '*/1 * * * *' + assignees: + - Tau-J + - LareinaM + - Ben-Louis + - LareinaM + - Ben-Louis + - Tau-J + - Tau-J diff --git a/MANIFEST.in b/MANIFEST.in index 8a93c252bd..c6d3090b1c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,6 @@ include requirements/*.txt include mmpose/.mim/model-index.yml +include mmpose/.mim/dataset-index.yml recursive-include mmpose/.mim/configs *.py *.yml recursive-include mmpose/.mim/tools *.py *.sh recursive-include mmpose/.mim/demo *.py diff --git a/README.md b/README.md index 823324c3bd..b250d570b3 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ [![actions](https://github.com/open-mmlab/mmpose/workflows/build/badge.svg)](https://github.com/open-mmlab/mmpose/actions) [![codecov](https://codecov.io/gh/open-mmlab/mmpose/branch/latest/graph/badge.svg)](https://codecov.io/gh/open-mmlab/mmpose) [![PyPI](https://img.shields.io/pypi/v/mmpose)](https://pypi.org/project/mmpose/) -[![LICENSE](https://img.shields.io/github/license/open-mmlab/mmpose.svg)](https://github.com/open-mmlab/mmpose/blob/master/LICENSE) +[![LICENSE](https://img.shields.io/github/license/open-mmlab/mmpose.svg)](https://github.com/open-mmlab/mmpose/blob/main/LICENSE) [![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/open-mmlab/mmpose.svg)](https://github.com/open-mmlab/mmpose/issues) [![Percentage of issues still open](https://isitmaintained.com/badge/open/open-mmlab/mmpose.svg)](https://github.com/open-mmlab/mmpose/issues) @@ -63,7 +63,7 @@ English | [简体中文](README_CN.md) MMPose is an open-source toolbox for pose estimation based on PyTorch. It is a part of the [OpenMMLab project](https://github.com/open-mmlab). -The master branch works with **PyTorch 1.6+**. +The main branch works with **PyTorch 1.8+**. https://user-images.githubusercontent.com/15977946/124654387-0fd3c500-ded1-11eb-84f6-24eeddbf4d91.mp4 @@ -75,7 +75,7 @@ https://user-images.githubusercontent.com/15977946/124654387-0fd3c500-ded1-11eb- - **Support diverse tasks** We support a wide spectrum of mainstream pose analysis tasks in current research community, including 2d multi-person human pose estimation, 2d hand pose estimation, 2d face landmark detection, 133 keypoint whole-body human pose estimation, 3d human mesh recovery, fashion landmark detection and animal pose estimation. - See [Demo](demo/docs/) for more information. + See [Demo](demo/docs/en) for more information. - **Higher efficiency and higher accuracy** @@ -97,9 +97,12 @@ https://user-images.githubusercontent.com/15977946/124654387-0fd3c500-ded1-11eb- ## What's New -- We are excited to release **YOLOX-Pose**, a One-Stage multi-person pose estimation model based on YOLOX. Checkout our [project page](/projects/yolox-pose/) for more details. +- We are glad to support 3 new datasets: + - (CVPR 2023) [Human-Art](https://github.com/IDEA-Research/HumanArt) + - (CVPR 2022) [Animal Kingdom](https://github.com/sutdcv/Animal-Kingdom) + - (AAAI 2020) [LaPa](https://github.com/JDAI-CV/lapa-dataset/) -![yolox-pose_intro](https://user-images.githubusercontent.com/26127467/226655503-3cee746e-6e42-40be-82ae-6e7cae2a4c7e.jpg) +![image](https://github.com/open-mmlab/mmpose/assets/13503330/c9171dbb-7e7a-4c39-98e3-c92932182efb) - Welcome to [*projects of MMPose*](/projects/README.md), where you can access to the latest features of MMPose, and share your ideas and codes with the community at once. Contribution to MMPose will be simple and smooth: @@ -108,20 +111,22 @@ https://user-images.githubusercontent.com/15977946/124654387-0fd3c500-ded1-11eb- - Build individual projects with full power of MMPose but not bound up with heavy frameworks - Checkout new projects: - [RTMPose](/projects/rtmpose/) - - [YOLOX-Pose](/projects/yolox-pose/) + - [YOLOX-Pose](/projects/yolox_pose/) - [MMPose4AIGC](/projects/mmpose4aigc/) + - [Simple Keypoints](/projects/skps/) - Become a contributors and make MMPose greater. Start your journey from the [example project](/projects/example_project/)
-- 2022-04-06: MMPose [v1.0.0](https://github.com/open-mmlab/mmpose/releases/tag/v1.0.0) is officially released, with the main updates including: +- 2023-07-04: MMPose [v1.1.0](https://github.com/open-mmlab/mmpose/releases/tag/v1.1.0) is officially released, with the main updates including: - - Release of [YOLOX-Pose](/projects/yolox-pose/), a One-Stage multi-person pose estimation model based on YOLOX - - Development of [MMPose for AIGC](/projects/mmpose4aigc/) based on RTMPose, generating high-quality skeleton images for Pose-guided AIGC projects - - Support for OpenPose-style skeleton visualization - - More complete and user-friendly [documentation and tutorials](https://mmpose.readthedocs.io/en/latest/overview.html) + - Support new datasets: Human-Art, Animal Kingdom and LaPa. + - Support new config type that is more user-friendly and flexible. + - Improve RTMPose with better performance. + - Migrate 3D pose estimation models on h36m. + - Inference speedup and webcam inference with all demo scripts. - Please refer to the [release notes](https://github.com/open-mmlab/mmpose/releases/tag/v1.0.0) for more updates brought by MMPose v1.0.0! + Please refer to the [release notes](https://github.com/open-mmlab/mmpose/releases/tag/v1.1.0) for more updates brought by MMPose v1.1.0! ## 0.x / 1.x Migration @@ -139,18 +144,18 @@ MMPose v1.0.0 is a major update, including many API and config file changes. Cur | HigherHRNet (CVPR 2020) | | | DeepPose (CVPR 2014) | done | | RLE (ICCV 2021) | done | -| SoftWingloss (TIP 2021) | | -| VideoPose3D (CVPR 2019) | | +| SoftWingloss (TIP 2021) | done | +| VideoPose3D (CVPR 2019) | done | | Hourglass (ECCV 2016) | done | | LiteHRNet (CVPR 2021) | done | | AdaptiveWingloss (ICCV 2019) | done | | SimpleBaseline2D (ECCV 2018) | done | | PoseWarper (NeurIPS 2019) | | -| SimpleBaseline3D (ICCV 2017) | | +| SimpleBaseline3D (ICCV 2017) | done | | HMR (CVPR 2018) | | | UDP (CVPR 2020) | done | | VIPNAS (CVPR 2021) | done | -| Wingloss (CVPR 2018) | | +| Wingloss (CVPR 2018) | done | | DarkPose (CVPR 2020) | done | | Associative Embedding (NIPS 2017) | in progress | | VoxelPose (ECCV 2020) | | @@ -214,13 +219,13 @@ A summary can be found in the [Model Zoo](https://mmpose.readthedocs.io/en/lates - [x] [DeepPose](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/algorithms.html#deeppose-cvpr-2014) (CVPR'2014) - [x] [CPM](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/backbones.html#cpm-cvpr-2016) (CVPR'2016) - [x] [Hourglass](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/backbones.html#hourglass-eccv-2016) (ECCV'2016) -- [ ] [SimpleBaseline3D](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/algorithms.html#simplebaseline3d-iccv-2017) (ICCV'2017) +- [x] [SimpleBaseline3D](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/algorithms.html#simplebaseline3d-iccv-2017) (ICCV'2017) - [ ] [Associative Embedding](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/algorithms.html#associative-embedding-nips-2017) (NeurIPS'2017) - [x] [SimpleBaseline2D](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/algorithms.html#simplebaseline2d-eccv-2018) (ECCV'2018) - [x] [DSNT](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/algorithms.html#dsnt-2018) (ArXiv'2021) - [x] [HRNet](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/backbones.html#hrnet-cvpr-2019) (CVPR'2019) - [x] [IPR](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/algorithms.html#ipr-eccv-2018) (ECCV'2018) -- [ ] [VideoPose3D](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/algorithms.html#videopose3d-cvpr-2019) (CVPR'2019) +- [x] [VideoPose3D](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/algorithms.html#videopose3d-cvpr-2019) (CVPR'2019) - [x] [HRNetv2](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/backbones.html#hrnetv2-tpami-2019) (TPAMI'2019) - [x] [MSPN](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/backbones.html#mspn-arxiv-2019) (ArXiv'2019) - [x] [SCNet](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/backbones.html#scnet-cvpr-2020) (CVPR'2020) @@ -238,14 +243,14 @@ A summary can be found in the [Model Zoo](https://mmpose.readthedocs.io/en/lates
Supported techniques: -- [ ] [FPN](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#fpn-cvpr-2017) (CVPR'2017) -- [ ] [FP16](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#fp16-arxiv-2017) (ArXiv'2017) -- [ ] [Wingloss](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#wingloss-cvpr-2018) (CVPR'2018) -- [ ] [AdaptiveWingloss](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#adaptivewingloss-iccv-2019) (ICCV'2019) +- [x] [FPN](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#fpn-cvpr-2017) (CVPR'2017) +- [x] [FP16](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#fp16-arxiv-2017) (ArXiv'2017) +- [x] [Wingloss](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#wingloss-cvpr-2018) (CVPR'2018) +- [x] [AdaptiveWingloss](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#adaptivewingloss-iccv-2019) (ICCV'2019) - [x] [DarkPose](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#darkpose-cvpr-2020) (CVPR'2020) - [x] [UDP](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#udp-cvpr-2020) (CVPR'2020) -- [ ] [Albumentations](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#albumentations-information-2020) (Information'2020) -- [ ] [SoftWingloss](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#softwingloss-tip-2021) (TIP'2021) +- [x] [Albumentations](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#albumentations-information-2020) (Information'2020) +- [x] [SoftWingloss](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#softwingloss-tip-2021) (TIP'2021) - [x] [RLE](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#rle-iccv-2021) (ICCV'2021)
@@ -284,6 +289,8 @@ A summary can be found in the [Model Zoo](https://mmpose.readthedocs.io/en/lates - [x] [InterHand2.6M](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/datasets.html#interhand2-6m-eccv-2020) \[[homepage](https://mks0601.github.io/InterHand2.6M/)\] (ECCV'2020) - [x] [AP-10K](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/datasets.html#ap-10k-neurips-2021) \[[homepage](https://github.com/AlexTheBad/AP-10K)\] (NeurIPS'2021) - [x] [Horse-10](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/datasets.html#horse-10-wacv-2021) \[[homepage](http://www.mackenziemathislab.org/horse10)\] (WACV'2021) +- [x] [Human-Art](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/datasets.html#human-art-cvpr-2023) \[[homepage](https://idea-research.github.io/HumanArt/)\] (CVPR'2023) +- [x] [LaPa](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/datasets.html#lapa-aaai-2020) \[[homepage](https://github.com/JDAI-CV/lapa-dataset)\] (AAAI'2020) @@ -309,7 +316,7 @@ A summary can be found in the [Model Zoo](https://mmpose.readthedocs.io/en/lates ### Model Request -We will keep up with the latest progress of the community, and support more popular algorithms and frameworks. If you have any feature requests, please feel free to leave a comment in [MMPose Roadmap](https://github.com/open-mmlab/mmpose/issues/9). +We will keep up with the latest progress of the community, and support more popular algorithms and frameworks. If you have any feature requests, please feel free to leave a comment in [MMPose Roadmap](https://github.com/open-mmlab/mmpose/issues/2258). ## Contributing @@ -342,21 +349,20 @@ This project is released under the [Apache 2.0 license](LICENSE). - [MMEngine](https://github.com/open-mmlab/mmengine): OpenMMLab foundational library for training deep learning models. - [MMCV](https://github.com/open-mmlab/mmcv): OpenMMLab foundational library for computer vision. -- [MIM](https://github.com/open-mmlab/mim): MIM installs OpenMMLab packages. -- [MMClassification](https://github.com/open-mmlab/mmclassification): OpenMMLab image classification toolbox and benchmark. +- [MMPreTrain](https://github.com/open-mmlab/mmpretrain): OpenMMLab pre-training toolbox and benchmark. +- [MMagic](https://github.com/open-mmlab/mmagic): Open**MM**Lab **A**dvanced, **G**enerative and **I**ntelligent **C**reation toolbox. - [MMDetection](https://github.com/open-mmlab/mmdetection): OpenMMLab detection toolbox and benchmark. - [MMDetection3D](https://github.com/open-mmlab/mmdetection3d): OpenMMLab's next-generation platform for general 3D object detection. - [MMRotate](https://github.com/open-mmlab/mmrotate): OpenMMLab rotated object detection toolbox and benchmark. +- [MMTracking](https://github.com/open-mmlab/mmtracking): OpenMMLab video perception toolbox and benchmark. - [MMSegmentation](https://github.com/open-mmlab/mmsegmentation): OpenMMLab semantic segmentation toolbox and benchmark. - [MMOCR](https://github.com/open-mmlab/mmocr): OpenMMLab text detection, recognition, and understanding toolbox. - [MMPose](https://github.com/open-mmlab/mmpose): OpenMMLab pose estimation toolbox and benchmark. - [MMHuman3D](https://github.com/open-mmlab/mmhuman3d): OpenMMLab 3D human parametric model toolbox and benchmark. -- [MMSelfSup](https://github.com/open-mmlab/mmselfsup): OpenMMLab self-supervised learning toolbox and benchmark. -- [MMRazor](https://github.com/open-mmlab/mmrazor): OpenMMLab model compression toolbox and benchmark. - [MMFewShot](https://github.com/open-mmlab/mmfewshot): OpenMMLab fewshot learning toolbox and benchmark. - [MMAction2](https://github.com/open-mmlab/mmaction2): OpenMMLab's next-generation action understanding toolbox and benchmark. -- [MMTracking](https://github.com/open-mmlab/mmtracking): OpenMMLab video perception toolbox and benchmark. - [MMFlow](https://github.com/open-mmlab/mmflow): OpenMMLab optical flow toolbox and benchmark. -- [MMEditing](https://github.com/open-mmlab/mmediting): OpenMMLab image and video editing toolbox. -- [MMGeneration](https://github.com/open-mmlab/mmgeneration): OpenMMLab image and video generative models toolbox. - [MMDeploy](https://github.com/open-mmlab/mmdeploy): OpenMMLab Model Deployment Framework. +- [MMRazor](https://github.com/open-mmlab/mmrazor): OpenMMLab model compression toolbox and benchmark. +- [MIM](https://github.com/open-mmlab/mim): MIM installs OpenMMLab packages. +- [Playground](https://github.com/open-mmlab/playground): A central hub for gathering and showcasing amazing projects built upon OpenMMLab. diff --git a/README_CN.md b/README_CN.md index ff5f14c50b..48672c2a88 100644 --- a/README_CN.md +++ b/README_CN.md @@ -22,7 +22,7 @@ [![actions](https://github.com/open-mmlab/mmpose/workflows/build/badge.svg)](https://github.com/open-mmlab/mmpose/actions) [![codecov](https://codecov.io/gh/open-mmlab/mmpose/branch/latest/graph/badge.svg)](https://codecov.io/gh/open-mmlab/mmpose) [![PyPI](https://img.shields.io/pypi/v/mmpose)](https://pypi.org/project/mmpose/) -[![LICENSE](https://img.shields.io/github/license/open-mmlab/mmpose.svg)](https://github.com/open-mmlab/mmpose/blob/master/LICENSE) +[![LICENSE](https://img.shields.io/github/license/open-mmlab/mmpose.svg)](https://github.com/open-mmlab/mmpose/blob/main/LICENSE) [![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/open-mmlab/mmpose.svg)](https://github.com/open-mmlab/mmpose/issues) [![Percentage of issues still open](https://isitmaintained.com/badge/open/open-mmlab/mmpose.svg)](https://github.com/open-mmlab/mmpose/issues) @@ -62,7 +62,7 @@ MMPose 是一款基于 PyTorch 的姿态分析的开源工具箱,是 [OpenMMLab](https://github.com/open-mmlab) 项目的成员之一。 -主分支代码目前支持 **PyTorch 1.6 以上**的版本。 +主分支代码目前支持 **PyTorch 1.8 以上**的版本。 https://user-images.githubusercontent.com/15977946/124654387-0fd3c500-ded1-11eb-84f6-24eeddbf4d91.mp4 @@ -72,7 +72,7 @@ https://user-images.githubusercontent.com/15977946/124654387-0fd3c500-ded1-11eb- - **支持多种人体姿态分析相关任务** MMPose 支持当前学界广泛关注的主流姿态分析任务:主要包括 2D多人姿态估计、2D手部姿态估计、2D人脸关键点检测、133关键点的全身人体姿态估计、3D人体形状恢复、服饰关键点检测、动物关键点检测等。 - 具体请参考 [功能演示](demo/docs/)。 + 具体请参考 [功能演示](demo/docs/zh_cn/)。 - **更高的精度和更快的速度** @@ -95,7 +95,10 @@ https://user-images.githubusercontent.com/15977946/124654387-0fd3c500-ded1-11eb- ## 最新进展 -- 我们发布了 **YOLOX-Pose**,一个基于 YOLOX 的 One-Stage 多人姿态估计模型。更多信息敬请参阅 YOLOX-Pose [项目主页](/projects/yolox_pose/) +- 我们支持了三个新的数据集: + - (CVPR 2023) [Human-Art](https://github.com/IDEA-Research/HumanArt) + - (CVPR 2022) [Animal Kingdom](https://github.com/sutdcv/Animal-Kingdom) + - (AAAI 2020) [LaPa](https://github.com/JDAI-CV/lapa-dataset/) ![yolox-pose_intro](https://user-images.githubusercontent.com/26127467/226655503-3cee746e-6e42-40be-82ae-6e7cae2a4c7e.jpg) @@ -106,20 +109,22 @@ https://user-images.githubusercontent.com/15977946/124654387-0fd3c500-ded1-11eb- - 通过独立项目的形式,利用 MMPose 的强大功能,同时不被代码框架所束缚 - 最新添加的项目包括: - [RTMPose](/projects/rtmpose/) - - [YOLOX-Pose](/projects/yolox-pose/) + - [YOLOX-Pose](/projects/yolox_pose/) - [MMPose4AIGC](/projects/mmpose4aigc/) + - [Simple Keypoints](/projects/skps/) - 从简单的 [示例项目](/projects/example_project/) 开启您的 MMPose 代码贡献者之旅吧,让我们共同打造更好用的 MMPose!
-- 2022-04-06:MMPose [v1.0.0](https://github.com/open-mmlab/mmpose/releases/tag/v1.0.0) 正式发布了,主要更新包括: +- 2023-07-04:MMPose [v1.1.0](https://github.com/open-mmlab/mmpose/releases/tag/v1.1.0) 正式发布了,主要更新包括: - - 发布了 [YOLOX-Pose](/projects/yolox-pose/),一个基于 YOLOX 的 One-Stage 多人姿态估计模型 - - 基于 RTMPose 开发的 [MMPose for AIGC](/projects/mmpose4aigc/),生成高质量骨架图片用于 Pose-guided AIGC 项目 - - 支持 OpenPose 风格的骨架可视化 - - 更加完善、友好的 [文档和教程](https://mmpose.readthedocs.io/zh_CN/latest/overview.html) + - 支持新数据集:Human-Art、Animal Kingdom、LaPa。 + - 支持新的配置文件风格,支持 IDE 跳转和搜索。 + - 提供更强性能的 RTMPose 模型。 + - 迁移 3D 姿态估计算法。 + - 加速推理脚本,全部 demo 脚本支持摄像头推理。 - 请查看完整的 [版本说明](https://github.com/open-mmlab/mmpose/releases/tag/v1.0.0) 以了解更多 MMPose v1.0.0 带来的更新! + 请查看完整的 [版本说明](https://github.com/open-mmlab/mmpose/releases/tag/v1.1.0) 以了解更多 MMPose v1.1.0 带来的更新! ## 0.x / 1.x 迁移 @@ -137,18 +142,18 @@ MMPose v1.0.0 是一个重大更新,包括了大量的 API 和配置文件的 | HigherHRNet (CVPR 2020) | | | DeepPose (CVPR 2014) | done | | RLE (ICCV 2021) | done | -| SoftWingloss (TIP 2021) | | -| VideoPose3D (CVPR 2019) | | +| SoftWingloss (TIP 2021) | done | +| VideoPose3D (CVPR 2019) | done | | Hourglass (ECCV 2016) | done | | LiteHRNet (CVPR 2021) | done | | AdaptiveWingloss (ICCV 2019) | done | | SimpleBaseline2D (ECCV 2018) | done | | PoseWarper (NeurIPS 2019) | | -| SimpleBaseline3D (ICCV 2017) | | +| SimpleBaseline3D (ICCV 2017) | done | | HMR (CVPR 2018) | | | UDP (CVPR 2020) | done | | VIPNAS (CVPR 2021) | done | -| Wingloss (CVPR 2018) | | +| Wingloss (CVPR 2018) | done | | DarkPose (CVPR 2020) | done | | Associative Embedding (NIPS 2017) | in progress | | VoxelPose (ECCV 2020) | | @@ -212,13 +217,13 @@ MMPose v1.0.0 是一个重大更新,包括了大量的 API 和配置文件的 - [x] [DeepPose](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/algorithms.html#deeppose-cvpr-2014) (CVPR'2014) - [x] [CPM](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/backbones.html#cpm-cvpr-2016) (CVPR'2016) - [x] [Hourglass](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/backbones.html#hourglass-eccv-2016) (ECCV'2016) -- [ ] [SimpleBaseline3D](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/algorithms.html#simplebaseline3d-iccv-2017) (ICCV'2017) +- [x] [SimpleBaseline3D](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/algorithms.html#simplebaseline3d-iccv-2017) (ICCV'2017) - [ ] [Associative Embedding](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/algorithms.html#associative-embedding-nips-2017) (NeurIPS'2017) - [x] [SimpleBaseline2D](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/algorithms.html#simplebaseline2d-eccv-2018) (ECCV'2018) - [x] [DSNT](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/algorithms.html#dsnt-2018) (ArXiv'2021) - [x] [HRNet](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/backbones.html#hrnet-cvpr-2019) (CVPR'2019) - [x] [IPR](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/algorithms.html#ipr-eccv-2018) (ECCV'2018) -- [ ] [VideoPose3D](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/algorithms.html#videopose3d-cvpr-2019) (CVPR'2019) +- [x] [VideoPose3D](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/algorithms.html#videopose3d-cvpr-2019) (CVPR'2019) - [x] [HRNetv2](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/backbones.html#hrnetv2-tpami-2019) (TPAMI'2019) - [x] [MSPN](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/backbones.html#mspn-arxiv-2019) (ArXiv'2019) - [x] [SCNet](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/backbones.html#scnet-cvpr-2020) (CVPR'2020) @@ -236,14 +241,14 @@ MMPose v1.0.0 是一个重大更新,包括了大量的 API 和配置文件的
支持的技术 -- [ ] [FPN](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#fpn-cvpr-2017) (CVPR'2017) -- [ ] [FP16](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#fp16-arxiv-2017) (ArXiv'2017) -- [ ] [Wingloss](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#wingloss-cvpr-2018) (CVPR'2018) -- [ ] [AdaptiveWingloss](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#adaptivewingloss-iccv-2019) (ICCV'2019) +- [x] [FPN](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#fpn-cvpr-2017) (CVPR'2017) +- [x] [FP16](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#fp16-arxiv-2017) (ArXiv'2017) +- [x] [Wingloss](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#wingloss-cvpr-2018) (CVPR'2018) +- [x] [AdaptiveWingloss](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#adaptivewingloss-iccv-2019) (ICCV'2019) - [x] [DarkPose](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#darkpose-cvpr-2020) (CVPR'2020) - [x] [UDP](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#udp-cvpr-2020) (CVPR'2020) -- [ ] [Albumentations](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#albumentations-information-2020) (Information'2020) -- [ ] [SoftWingloss](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#softwingloss-tip-2021) (TIP'2021) +- [x] [Albumentations](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#albumentations-information-2020) (Information'2020) +- [x] [SoftWingloss](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#softwingloss-tip-2021) (TIP'2021) - [x] [RLE](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/techniques.html#rle-iccv-2021) (ICCV'2021)
@@ -282,6 +287,8 @@ MMPose v1.0.0 是一个重大更新,包括了大量的 API 和配置文件的 - [x] [InterHand2.6M](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/datasets.html#interhand2-6m-eccv-2020) \[[主页](https://mks0601.github.io/InterHand2.6M/)\] (ECCV'2020) - [x] [AP-10K](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/datasets.html#ap-10k-neurips-2021) \[[主页](https://github.com/AlexTheBad/AP-10K)\] (NeurIPS'2021) - [x] [Horse-10](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/datasets.html#horse-10-wacv-2021) \[[主页](http://www.mackenziemathislab.org/horse10)\] (WACV'2021) +- [x] [Human-Art](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/datasets.html#human-art-cvpr-2023) \[[主页](https://idea-research.github.io/HumanArt/)\] (CVPR'2023) +- [x] [LaPa](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo_papers/datasets.html#lapa-aaai-2020) \[[主页](https://github.com/JDAI-CV/lapa-dataset)\] (AAAI'2020) @@ -307,7 +314,7 @@ MMPose v1.0.0 是一个重大更新,包括了大量的 API 和配置文件的 ### 模型需求 -我们将跟进学界的最新进展,并支持更多算法和框架。如果您对 MMPose 有任何功能需求,请随时在 [MMPose Roadmap](https://github.com/open-mmlab/mmpose/issues/9) 中留言。 +我们将跟进学界的最新进展,并支持更多算法和框架。如果您对 MMPose 有任何功能需求,请随时在 [MMPose Roadmap](https://github.com/open-mmlab/mmpose/issues/2258) 中留言。 ## 参与贡献 @@ -339,24 +346,23 @@ MMPose 是一款由不同学校和公司共同贡献的开源项目。我们感 - [MMEngine](https://github.com/open-mmlab/mmengine): OpenMMLab 深度学习模型训练基础库 - [MMCV](https://github.com/open-mmlab/mmcv): OpenMMLab 计算机视觉基础库 -- [MIM](https://github.com/open-mmlab/mim): OpenMMlab 项目、算法、模型的统一入口 -- [MMClassification](https://github.com/open-mmlab/mmclassification): OpenMMLab 图像分类工具箱 +- [MMPreTrain](https://github.com/open-mmlab/mmpretrain): OpenMMLab 深度学习预训练工具箱 +- [MMagic](https://github.com/open-mmlab/mmagic): OpenMMLab 新一代人工智能内容生成(AIGC)工具箱 - [MMDetection](https://github.com/open-mmlab/mmdetection): OpenMMLab 目标检测工具箱 - [MMDetection3D](https://github.com/open-mmlab/mmdetection3d): OpenMMLab 新一代通用 3D 目标检测平台 - [MMRotate](https://github.com/open-mmlab/mmrotate): OpenMMLab 旋转框检测工具箱与测试基准 +- [MMTracking](https://github.com/open-mmlab/mmtracking): OpenMMLab 一体化视频目标感知平台 - [MMSegmentation](https://github.com/open-mmlab/mmsegmentation): OpenMMLab 语义分割工具箱 - [MMOCR](https://github.com/open-mmlab/mmocr): OpenMMLab 全流程文字检测识别理解工具包 - [MMPose](https://github.com/open-mmlab/mmpose): OpenMMLab 姿态估计工具箱 - [MMHuman3D](https://github.com/open-mmlab/mmhuman3d): OpenMMLab 人体参数化模型工具箱与测试基准 -- [MMSelfSup](https://github.com/open-mmlab/mmselfsup): OpenMMLab 自监督学习工具箱与测试基准 -- [MMRazor](https://github.com/open-mmlab/mmrazor): OpenMMLab 模型压缩工具箱与测试基准 - [MMFewShot](https://github.com/open-mmlab/mmfewshot): OpenMMLab 少样本学习工具箱与测试基准 - [MMAction2](https://github.com/open-mmlab/mmaction2): OpenMMLab 新一代视频理解工具箱 -- [MMTracking](https://github.com/open-mmlab/mmtracking): OpenMMLab 一体化视频目标感知平台 - [MMFlow](https://github.com/open-mmlab/mmflow): OpenMMLab 光流估计工具箱与测试基准 -- [MMEditing](https://github.com/open-mmlab/mmediting): OpenMMLab 图像视频编辑工具箱 -- [MMGeneration](https://github.com/open-mmlab/mmgeneration): OpenMMLab 图片视频生成模型工具箱 - [MMDeploy](https://github.com/open-mmlab/mmdeploy): OpenMMLab 模型部署框架 +- [MMRazor](https://github.com/open-mmlab/mmrazor): OpenMMLab 模型压缩工具箱与测试基准 +- [MIM](https://github.com/open-mmlab/mim): OpenMMlab 项目、算法、模型的统一入口 +- [Playground](https://github.com/open-mmlab/playground): 收集和展示 OpenMMLab 相关的前沿、有趣的社区项目 ## 欢迎加入 OpenMMLab 社区 diff --git a/configs/_base_/datasets/ak.py b/configs/_base_/datasets/ak.py new file mode 100644 index 0000000000..e8b12f5a31 --- /dev/null +++ b/configs/_base_/datasets/ak.py @@ -0,0 +1,267 @@ +dataset_info = dict( + dataset_name='Animal Kingdom', + paper_info=dict( + author='Singapore University of Technology and Design, Singapore.' + ' Xun Long Ng, Kian Eng Ong, Qichen Zheng,' + ' Yun Ni, Si Yong Yeo, Jun Liu.', + title='Animal Kingdom: ' + 'A Large and Diverse Dataset for Animal Behavior Understanding', + container='Conference on Computer Vision ' + 'and Pattern Recognition (CVPR)', + year='2022', + homepage='https://sutdcv.github.io/Animal-Kingdom', + version='1.0 (2022-06)', + date_created='2022-06', + ), + keypoint_info={ + 0: + dict( + name='Head_Mid_Top', + id=0, + color=(225, 0, 255), + type='upper', + swap=''), + 1: + dict( + name='Eye_Left', + id=1, + color=[220, 20, 60], + type='upper', + swap='Eye_Right'), + 2: + dict( + name='Eye_Right', + id=2, + color=[0, 255, 255], + type='upper', + swap='Eye_Left'), + 3: + dict( + name='Mouth_Front_Top', + id=3, + color=(0, 255, 42), + type='upper', + swap=''), + 4: + dict( + name='Mouth_Back_Left', + id=4, + color=[221, 160, 221], + type='upper', + swap='Mouth_Back_Right'), + 5: + dict( + name='Mouth_Back_Right', + id=5, + color=[135, 206, 250], + type='upper', + swap='Mouth_Back_Left'), + 6: + dict( + name='Mouth_Front_Bottom', + id=6, + color=[50, 205, 50], + type='upper', + swap=''), + 7: + dict( + name='Shoulder_Left', + id=7, + color=[255, 182, 193], + type='upper', + swap='Shoulder_Right'), + 8: + dict( + name='Shoulder_Right', + id=8, + color=[0, 191, 255], + type='upper', + swap='Shoulder_Left'), + 9: + dict( + name='Elbow_Left', + id=9, + color=[255, 105, 180], + type='upper', + swap='Elbow_Right'), + 10: + dict( + name='Elbow_Right', + id=10, + color=[30, 144, 255], + type='upper', + swap='Elbow_Left'), + 11: + dict( + name='Wrist_Left', + id=11, + color=[255, 20, 147], + type='upper', + swap='Wrist_Right'), + 12: + dict( + name='Wrist_Right', + id=12, + color=[0, 0, 255], + type='upper', + swap='Wrist_Left'), + 13: + dict( + name='Torso_Mid_Back', + id=13, + color=(185, 3, 221), + type='upper', + swap=''), + 14: + dict( + name='Hip_Left', + id=14, + color=[255, 215, 0], + type='lower', + swap='Hip_Right'), + 15: + dict( + name='Hip_Right', + id=15, + color=[147, 112, 219], + type='lower', + swap='Hip_Left'), + 16: + dict( + name='Knee_Left', + id=16, + color=[255, 165, 0], + type='lower', + swap='Knee_Right'), + 17: + dict( + name='Knee_Right', + id=17, + color=[138, 43, 226], + type='lower', + swap='Knee_Left'), + 18: + dict( + name='Ankle_Left', + id=18, + color=[255, 140, 0], + type='lower', + swap='Ankle_Right'), + 19: + dict( + name='Ankle_Right', + id=19, + color=[128, 0, 128], + type='lower', + swap='Ankle_Left'), + 20: + dict( + name='Tail_Top_Back', + id=20, + color=(0, 251, 255), + type='lower', + swap=''), + 21: + dict( + name='Tail_Mid_Back', + id=21, + color=[32, 178, 170], + type='lower', + swap=''), + 22: + dict( + name='Tail_End_Back', + id=22, + color=(0, 102, 102), + type='lower', + swap='') + }, + skeleton_info={ + 0: + dict(link=('Eye_Left', 'Head_Mid_Top'), id=0, color=[220, 20, 60]), + 1: + dict(link=('Eye_Right', 'Head_Mid_Top'), id=1, color=[0, 255, 255]), + 2: + dict( + link=('Mouth_Front_Top', 'Mouth_Back_Left'), + id=2, + color=[221, 160, 221]), + 3: + dict( + link=('Mouth_Front_Top', 'Mouth_Back_Right'), + id=3, + color=[135, 206, 250]), + 4: + dict( + link=('Mouth_Front_Bottom', 'Mouth_Back_Left'), + id=4, + color=[221, 160, 221]), + 5: + dict( + link=('Mouth_Front_Bottom', 'Mouth_Back_Right'), + id=5, + color=[135, 206, 250]), + 6: + dict( + link=('Head_Mid_Top', 'Torso_Mid_Back'), id=6, + color=(225, 0, 255)), + 7: + dict( + link=('Torso_Mid_Back', 'Tail_Top_Back'), + id=7, + color=(185, 3, 221)), + 8: + dict( + link=('Tail_Top_Back', 'Tail_Mid_Back'), id=8, + color=(0, 251, 255)), + 9: + dict( + link=('Tail_Mid_Back', 'Tail_End_Back'), + id=9, + color=[32, 178, 170]), + 10: + dict( + link=('Head_Mid_Top', 'Shoulder_Left'), + id=10, + color=[255, 182, 193]), + 11: + dict( + link=('Head_Mid_Top', 'Shoulder_Right'), + id=11, + color=[0, 191, 255]), + 12: + dict( + link=('Shoulder_Left', 'Elbow_Left'), id=12, color=[255, 105, + 180]), + 13: + dict( + link=('Shoulder_Right', 'Elbow_Right'), + id=13, + color=[30, 144, 255]), + 14: + dict(link=('Elbow_Left', 'Wrist_Left'), id=14, color=[255, 20, 147]), + 15: + dict(link=('Elbow_Right', 'Wrist_Right'), id=15, color=[0, 0, 255]), + 16: + dict(link=('Tail_Top_Back', 'Hip_Left'), id=16, color=[255, 215, 0]), + 17: + dict( + link=('Tail_Top_Back', 'Hip_Right'), id=17, color=[147, 112, 219]), + 18: + dict(link=('Hip_Left', 'Knee_Left'), id=18, color=[255, 165, 0]), + 19: + dict(link=('Hip_Right', 'Knee_Right'), id=19, color=[138, 43, 226]), + 20: + dict(link=('Knee_Left', 'Ankle_Left'), id=20, color=[255, 140, 0]), + 21: + dict(link=('Knee_Right', 'Ankle_Right'), id=21, color=[128, 0, 128]) + }, + joint_weights=[ + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1., 1., 1. + ], + sigmas=[ + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, 0.025, + 0.025, 0.025, 0.025 + ]) diff --git a/configs/_base_/datasets/coco_openpose.py b/configs/_base_/datasets/coco_openpose.py index 9aedd9f0e4..cce11b27f1 100644 --- a/configs/_base_/datasets/coco_openpose.py +++ b/configs/_base_/datasets/coco_openpose.py @@ -12,77 +12,77 @@ ), keypoint_info={ 0: - dict(name='nose', id=0, color=[255, 0, 85], type='upper', swap=''), + dict(name='nose', id=0, color=[255, 0, 0], type='upper', swap=''), 1: - dict(name='neck', id=1, color=[255, 0, 0], type='upper', swap=''), + dict(name='neck', id=1, color=[255, 85, 0], type='upper', swap=''), 2: dict( name='right_shoulder', id=2, - color=[255, 85, 0], + color=[255, 170, 0], type='upper', swap='left_shoulder'), 3: dict( name='right_elbow', id=3, - color=[255, 170, 0], + color=[255, 255, 0], type='upper', swap='left_elbow'), 4: dict( name='right_wrist', id=4, - color=[255, 255, 0], + color=[170, 255, 0], type='upper', swap='left_wrist'), 5: dict( name='left_shoulder', id=5, - color=[170, 255, 0], + color=[85, 255, 0], type='upper', swap='right_shoulder'), 6: dict( name='left_elbow', id=6, - color=[85, 255, 0], + color=[0, 255, 0], type='upper', swap='right_elbow'), 7: dict( name='left_wrist', id=7, - color=[0, 255, 0], + color=[0, 255, 85], type='upper', swap='right_wrist'), 8: dict( name='right_hip', id=8, - color=[255, 0, 170], + color=[0, 255, 170], type='lower', swap='left_hip'), 9: dict( name='right_knee', id=9, - color=[255, 0, 255], + color=[0, 255, 255], type='lower', swap='left_knee'), 10: dict( name='right_ankle', id=10, - color=[170, 0, 255], + color=[0, 170, 255], type='lower', swap='left_ankle'), 11: dict( name='left_hip', id=11, - color=[85, 255, 0], + color=[0, 85, 255], type='lower', swap='right_hip'), 12: @@ -96,59 +96,59 @@ dict( name='left_ankle', id=13, - color=[0, 85, 255], + color=[85, 0, 255], type='lower', swap='right_ankle'), 14: dict( name='right_eye', id=14, - color=[0, 255, 170], + color=[170, 0, 255], type='upper', swap='left_eye'), 15: dict( name='left_eye', id=15, - color=[0, 255, 255], + color=[255, 0, 255], type='upper', swap='right_eye'), 16: dict( name='right_ear', id=16, - color=[0, 170, 255], + color=[255, 0, 170], type='upper', swap='left_ear'), 17: dict( name='left_ear', id=17, - color=[0, 170, 255], + color=[255, 0, 85], type='upper', swap='right_ear'), }, skeleton_info={ - 0: dict(link=('neck', 'right_shoulder'), id=0, color=[255, 0, 85]), - 1: dict(link=('neck', 'left_shoulder'), id=1, color=[255, 0, 0]), - 2: - dict(link=('right_shoulder', 'right_elbow'), id=2, color=[255, 85, 0]), + 0: dict(link=('neck', 'right_shoulder'), id=0, color=[255, 0, 0]), + 1: dict(link=('neck', 'left_shoulder'), id=1, color=[255, 85, 0]), + 2: dict( + link=('right_shoulder', 'right_elbow'), id=2, color=[255, 170, 0]), 3: - dict(link=('right_elbow', 'right_wrist'), id=3, color=[255, 170, 0]), + dict(link=('right_elbow', 'right_wrist'), id=3, color=[255, 255, 0]), 4: - dict(link=('left_shoulder', 'left_elbow'), id=4, color=[255, 255, 0]), - 5: dict(link=('left_elbow', 'left_wrist'), id=5, color=[170, 255, 0]), - 6: dict(link=('neck', 'right_hip'), id=6, color=[85, 255, 0]), - 7: dict(link=('right_hip', 'right_knee'), id=7, color=[0, 255, 0]), - 8: dict(link=('right_knee', 'right_ankle'), id=8, color=[0, 255, 85]), - 9: dict(link=('neck', 'left_hip'), id=9, color=[0, 255, 170]), - 10: dict(link=('left_hip', 'left_knee'), id=10, color=[0, 255, 225]), - 11: dict(link=('left_knee', 'left_ankle'), id=11, color=[0, 170, 255]), - 12: dict(link=('neck', 'nose'), id=12, color=[0, 85, 255]), - 13: dict(link=('nose', 'right_eye'), id=13, color=[0, 0, 255]), - 14: dict(link=('right_eye', 'right_ear'), id=14, color=[255, 0, 170]), - 15: dict(link=('nose', 'left_eye'), id=15, color=[170, 0, 255]), - 16: dict(link=('left_eye', 'left_ear'), id=16, color=[255, 0, 255]), + dict(link=('left_shoulder', 'left_elbow'), id=4, color=[170, 255, 0]), + 5: dict(link=('left_elbow', 'left_wrist'), id=5, color=[85, 255, 0]), + 6: dict(link=('neck', 'right_hip'), id=6, color=[0, 255, 0]), + 7: dict(link=('right_hip', 'right_knee'), id=7, color=[0, 255, 85]), + 8: dict(link=('right_knee', 'right_ankle'), id=8, color=[0, 255, 170]), + 9: dict(link=('neck', 'left_hip'), id=9, color=[0, 255, 225]), + 10: dict(link=('left_hip', 'left_knee'), id=10, color=[0, 170, 255]), + 11: dict(link=('left_knee', 'left_ankle'), id=11, color=[0, 85, 255]), + 12: dict(link=('neck', 'nose'), id=12, color=[0, 0, 255]), + 13: dict(link=('nose', 'right_eye'), id=13, color=[255, 0, 170]), + 14: dict(link=('right_eye', 'right_ear'), id=14, color=[170, 0, 255]), + 15: dict(link=('nose', 'left_eye'), id=15, color=[255, 0, 255]), + 16: dict(link=('left_eye', 'left_ear'), id=16, color=[255, 0, 170]), }, joint_weights=[1.] * 18, sigmas=[ diff --git a/configs/_base_/datasets/deepfashion2.py b/configs/_base_/datasets/deepfashion2.py new file mode 100644 index 0000000000..f65d1bb591 --- /dev/null +++ b/configs/_base_/datasets/deepfashion2.py @@ -0,0 +1,2660 @@ +colors = dict( + sss=[255, 128, 0], # short_sleeve_shirt + lss=[255, 0, 128], # long_sleeved_shirt + sso=[128, 0, 255], # short_sleeved_outwear + lso=[0, 128, 255], # long_sleeved_outwear + vest=[0, 128, 128], # vest + sling=[0, 0, 128], # sling + shorts=[128, 128, 128], # shorts + trousers=[128, 0, 128], # trousers + skirt=[64, 128, 128], # skirt + ssd=[64, 64, 128], # short_sleeved_dress + lsd=[128, 64, 0], # long_sleeved_dress + vd=[128, 64, 255], # vest_dress + sd=[128, 64, 0], # sling_dress +) +dataset_info = dict( + dataset_name='deepfashion2', + paper_info=dict( + author='Yuying Ge and Ruimao Zhang and Lingyun Wu ' + 'and Xiaogang Wang and Xiaoou Tang and Ping Luo', + title='DeepFashion2: A Versatile Benchmark for ' + 'Detection, Pose Estimation, Segmentation and ' + 'Re-Identification of Clothing Images', + container='Proceedings of IEEE Conference on Computer ' + 'Vision and Pattern Recognition (CVPR)', + year='2019', + homepage='https://github.com/switchablenorms/DeepFashion2', + ), + keypoint_info={ + # short_sleeved_shirt + 0: + dict(name='sss_kpt1', id=0, color=colors['sss'], type='', swap=''), + 1: + dict( + name='sss_kpt2', + id=1, + color=colors['sss'], + type='', + swap='sss_kpt6'), + 2: + dict( + name='sss_kpt3', + id=2, + color=colors['sss'], + type='', + swap='sss_kpt5'), + 3: + dict(name='sss_kpt4', id=3, color=colors['sss'], type='', swap=''), + 4: + dict( + name='sss_kpt5', + id=4, + color=colors['sss'], + type='', + swap='sss_kpt3'), + 5: + dict( + name='sss_kpt6', + id=5, + color=colors['sss'], + type='', + swap='sss_kpt2'), + 6: + dict( + name='sss_kpt7', + id=6, + color=colors['sss'], + type='', + swap='sss_kpt25'), + 7: + dict( + name='sss_kpt8', + id=7, + color=colors['sss'], + type='', + swap='sss_kpt24'), + 8: + dict( + name='sss_kpt9', + id=8, + color=colors['sss'], + type='', + swap='sss_kpt23'), + 9: + dict( + name='sss_kpt10', + id=9, + color=colors['sss'], + type='', + swap='sss_kpt22'), + 10: + dict( + name='sss_kpt11', + id=10, + color=colors['sss'], + type='', + swap='sss_kpt21'), + 11: + dict( + name='sss_kpt12', + id=11, + color=colors['sss'], + type='', + swap='sss_kpt20'), + 12: + dict( + name='sss_kpt13', + id=12, + color=colors['sss'], + type='', + swap='sss_kpt19'), + 13: + dict( + name='sss_kpt14', + id=13, + color=colors['sss'], + type='', + swap='sss_kpt18'), + 14: + dict( + name='sss_kpt15', + id=14, + color=colors['sss'], + type='', + swap='sss_kpt17'), + 15: + dict(name='sss_kpt16', id=15, color=colors['sss'], type='', swap=''), + 16: + dict( + name='sss_kpt17', + id=16, + color=colors['sss'], + type='', + swap='sss_kpt15'), + 17: + dict( + name='sss_kpt18', + id=17, + color=colors['sss'], + type='', + swap='sss_kpt14'), + 18: + dict( + name='sss_kpt19', + id=18, + color=colors['sss'], + type='', + swap='sss_kpt13'), + 19: + dict( + name='sss_kpt20', + id=19, + color=colors['sss'], + type='', + swap='sss_kpt12'), + 20: + dict( + name='sss_kpt21', + id=20, + color=colors['sss'], + type='', + swap='sss_kpt11'), + 21: + dict( + name='sss_kpt22', + id=21, + color=colors['sss'], + type='', + swap='sss_kpt10'), + 22: + dict( + name='sss_kpt23', + id=22, + color=colors['sss'], + type='', + swap='sss_kpt9'), + 23: + dict( + name='sss_kpt24', + id=23, + color=colors['sss'], + type='', + swap='sss_kpt8'), + 24: + dict( + name='sss_kpt25', + id=24, + color=colors['sss'], + type='', + swap='sss_kpt7'), + # long_sleeved_shirt + 25: + dict(name='lss_kpt1', id=25, color=colors['lss'], type='', swap=''), + 26: + dict( + name='lss_kpt2', + id=26, + color=colors['lss'], + type='', + swap='lss_kpt6'), + 27: + dict( + name='lss_kpt3', + id=27, + color=colors['lss'], + type='', + swap='lss_kpt5'), + 28: + dict(name='lss_kpt4', id=28, color=colors['lss'], type='', swap=''), + 29: + dict( + name='lss_kpt5', + id=29, + color=colors['lss'], + type='', + swap='lss_kpt3'), + 30: + dict( + name='lss_kpt6', + id=30, + color=colors['lss'], + type='', + swap='lss_kpt2'), + 31: + dict( + name='lss_kpt7', + id=31, + color=colors['lss'], + type='', + swap='lss_kpt33'), + 32: + dict( + name='lss_kpt8', + id=32, + color=colors['lss'], + type='', + swap='lss_kpt32'), + 33: + dict( + name='lss_kpt9', + id=33, + color=colors['lss'], + type='', + swap='lss_kpt31'), + 34: + dict( + name='lss_kpt10', + id=34, + color=colors['lss'], + type='', + swap='lss_kpt30'), + 35: + dict( + name='lss_kpt11', + id=35, + color=colors['lss'], + type='', + swap='lss_kpt29'), + 36: + dict( + name='lss_kpt12', + id=36, + color=colors['lss'], + type='', + swap='lss_kpt28'), + 37: + dict( + name='lss_kpt13', + id=37, + color=colors['lss'], + type='', + swap='lss_kpt27'), + 38: + dict( + name='lss_kpt14', + id=38, + color=colors['lss'], + type='', + swap='lss_kpt26'), + 39: + dict( + name='lss_kpt15', + id=39, + color=colors['lss'], + type='', + swap='lss_kpt25'), + 40: + dict( + name='lss_kpt16', + id=40, + color=colors['lss'], + type='', + swap='lss_kpt24'), + 41: + dict( + name='lss_kpt17', + id=41, + color=colors['lss'], + type='', + swap='lss_kpt23'), + 42: + dict( + name='lss_kpt18', + id=42, + color=colors['lss'], + type='', + swap='lss_kpt22'), + 43: + dict( + name='lss_kpt19', + id=43, + color=colors['lss'], + type='', + swap='lss_kpt21'), + 44: + dict(name='lss_kpt20', id=44, color=colors['lss'], type='', swap=''), + 45: + dict( + name='lss_kpt21', + id=45, + color=colors['lss'], + type='', + swap='lss_kpt19'), + 46: + dict( + name='lss_kpt22', + id=46, + color=colors['lss'], + type='', + swap='lss_kpt18'), + 47: + dict( + name='lss_kpt23', + id=47, + color=colors['lss'], + type='', + swap='lss_kpt17'), + 48: + dict( + name='lss_kpt24', + id=48, + color=colors['lss'], + type='', + swap='lss_kpt16'), + 49: + dict( + name='lss_kpt25', + id=49, + color=colors['lss'], + type='', + swap='lss_kpt15'), + 50: + dict( + name='lss_kpt26', + id=50, + color=colors['lss'], + type='', + swap='lss_kpt14'), + 51: + dict( + name='lss_kpt27', + id=51, + color=colors['lss'], + type='', + swap='lss_kpt13'), + 52: + dict( + name='lss_kpt28', + id=52, + color=colors['lss'], + type='', + swap='lss_kpt12'), + 53: + dict( + name='lss_kpt29', + id=53, + color=colors['lss'], + type='', + swap='lss_kpt11'), + 54: + dict( + name='lss_kpt30', + id=54, + color=colors['lss'], + type='', + swap='lss_kpt10'), + 55: + dict( + name='lss_kpt31', + id=55, + color=colors['lss'], + type='', + swap='lss_kpt9'), + 56: + dict( + name='lss_kpt32', + id=56, + color=colors['lss'], + type='', + swap='lss_kpt8'), + 57: + dict( + name='lss_kpt33', + id=57, + color=colors['lss'], + type='', + swap='lss_kpt7'), + # short_sleeved_outwear + 58: + dict(name='sso_kpt1', id=58, color=colors['sso'], type='', swap=''), + 59: + dict( + name='sso_kpt2', + id=59, + color=colors['sso'], + type='', + swap='sso_kpt26'), + 60: + dict( + name='sso_kpt3', + id=60, + color=colors['sso'], + type='', + swap='sso_kpt5'), + 61: + dict( + name='sso_kpt4', + id=61, + color=colors['sso'], + type='', + swap='sso_kpt6'), + 62: + dict( + name='sso_kpt5', + id=62, + color=colors['sso'], + type='', + swap='sso_kpt3'), + 63: + dict( + name='sso_kpt6', + id=63, + color=colors['sso'], + type='', + swap='sso_kpt4'), + 64: + dict( + name='sso_kpt7', + id=64, + color=colors['sso'], + type='', + swap='sso_kpt25'), + 65: + dict( + name='sso_kpt8', + id=65, + color=colors['sso'], + type='', + swap='sso_kpt24'), + 66: + dict( + name='sso_kpt9', + id=66, + color=colors['sso'], + type='', + swap='sso_kpt23'), + 67: + dict( + name='sso_kpt10', + id=67, + color=colors['sso'], + type='', + swap='sso_kpt22'), + 68: + dict( + name='sso_kpt11', + id=68, + color=colors['sso'], + type='', + swap='sso_kpt21'), + 69: + dict( + name='sso_kpt12', + id=69, + color=colors['sso'], + type='', + swap='sso_kpt20'), + 70: + dict( + name='sso_kpt13', + id=70, + color=colors['sso'], + type='', + swap='sso_kpt19'), + 71: + dict( + name='sso_kpt14', + id=71, + color=colors['sso'], + type='', + swap='sso_kpt18'), + 72: + dict( + name='sso_kpt15', + id=72, + color=colors['sso'], + type='', + swap='sso_kpt17'), + 73: + dict( + name='sso_kpt16', + id=73, + color=colors['sso'], + type='', + swap='sso_kpt29'), + 74: + dict( + name='sso_kpt17', + id=74, + color=colors['sso'], + type='', + swap='sso_kpt15'), + 75: + dict( + name='sso_kpt18', + id=75, + color=colors['sso'], + type='', + swap='sso_kpt14'), + 76: + dict( + name='sso_kpt19', + id=76, + color=colors['sso'], + type='', + swap='sso_kpt13'), + 77: + dict( + name='sso_kpt20', + id=77, + color=colors['sso'], + type='', + swap='sso_kpt12'), + 78: + dict( + name='sso_kpt21', + id=78, + color=colors['sso'], + type='', + swap='sso_kpt11'), + 79: + dict( + name='sso_kpt22', + id=79, + color=colors['sso'], + type='', + swap='sso_kpt10'), + 80: + dict( + name='sso_kpt23', + id=80, + color=colors['sso'], + type='', + swap='sso_kpt9'), + 81: + dict( + name='sso_kpt24', + id=81, + color=colors['sso'], + type='', + swap='sso_kpt8'), + 82: + dict( + name='sso_kpt25', + id=82, + color=colors['sso'], + type='', + swap='sso_kpt7'), + 83: + dict( + name='sso_kpt26', + id=83, + color=colors['sso'], + type='', + swap='sso_kpt2'), + 84: + dict( + name='sso_kpt27', + id=84, + color=colors['sso'], + type='', + swap='sso_kpt30'), + 85: + dict( + name='sso_kpt28', + id=85, + color=colors['sso'], + type='', + swap='sso_kpt31'), + 86: + dict( + name='sso_kpt29', + id=86, + color=colors['sso'], + type='', + swap='sso_kpt16'), + 87: + dict( + name='sso_kpt30', + id=87, + color=colors['sso'], + type='', + swap='sso_kpt27'), + 88: + dict( + name='sso_kpt31', + id=88, + color=colors['sso'], + type='', + swap='sso_kpt28'), + # long_sleeved_outwear + 89: + dict(name='lso_kpt1', id=89, color=colors['lso'], type='', swap=''), + 90: + dict( + name='lso_kpt2', + id=90, + color=colors['lso'], + type='', + swap='lso_kpt6'), + 91: + dict( + name='lso_kpt3', + id=91, + color=colors['lso'], + type='', + swap='lso_kpt5'), + 92: + dict( + name='lso_kpt4', + id=92, + color=colors['lso'], + type='', + swap='lso_kpt34'), + 93: + dict( + name='lso_kpt5', + id=93, + color=colors['lso'], + type='', + swap='lso_kpt3'), + 94: + dict( + name='lso_kpt6', + id=94, + color=colors['lso'], + type='', + swap='lso_kpt2'), + 95: + dict( + name='lso_kpt7', + id=95, + color=colors['lso'], + type='', + swap='lso_kpt33'), + 96: + dict( + name='lso_kpt8', + id=96, + color=colors['lso'], + type='', + swap='lso_kpt32'), + 97: + dict( + name='lso_kpt9', + id=97, + color=colors['lso'], + type='', + swap='lso_kpt31'), + 98: + dict( + name='lso_kpt10', + id=98, + color=colors['lso'], + type='', + swap='lso_kpt30'), + 99: + dict( + name='lso_kpt11', + id=99, + color=colors['lso'], + type='', + swap='lso_kpt29'), + 100: + dict( + name='lso_kpt12', + id=100, + color=colors['lso'], + type='', + swap='lso_kpt28'), + 101: + dict( + name='lso_kpt13', + id=101, + color=colors['lso'], + type='', + swap='lso_kpt27'), + 102: + dict( + name='lso_kpt14', + id=102, + color=colors['lso'], + type='', + swap='lso_kpt26'), + 103: + dict( + name='lso_kpt15', + id=103, + color=colors['lso'], + type='', + swap='lso_kpt25'), + 104: + dict( + name='lso_kpt16', + id=104, + color=colors['lso'], + type='', + swap='lso_kpt24'), + 105: + dict( + name='lso_kpt17', + id=105, + color=colors['lso'], + type='', + swap='lso_kpt23'), + 106: + dict( + name='lso_kpt18', + id=106, + color=colors['lso'], + type='', + swap='lso_kpt22'), + 107: + dict( + name='lso_kpt19', + id=107, + color=colors['lso'], + type='', + swap='lso_kpt21'), + 108: + dict( + name='lso_kpt20', + id=108, + color=colors['lso'], + type='', + swap='lso_kpt37'), + 109: + dict( + name='lso_kpt21', + id=109, + color=colors['lso'], + type='', + swap='lso_kpt19'), + 110: + dict( + name='lso_kpt22', + id=110, + color=colors['lso'], + type='', + swap='lso_kpt18'), + 111: + dict( + name='lso_kpt23', + id=111, + color=colors['lso'], + type='', + swap='lso_kpt17'), + 112: + dict( + name='lso_kpt24', + id=112, + color=colors['lso'], + type='', + swap='lso_kpt16'), + 113: + dict( + name='lso_kpt25', + id=113, + color=colors['lso'], + type='', + swap='lso_kpt15'), + 114: + dict( + name='lso_kpt26', + id=114, + color=colors['lso'], + type='', + swap='lso_kpt14'), + 115: + dict( + name='lso_kpt27', + id=115, + color=colors['lso'], + type='', + swap='lso_kpt13'), + 116: + dict( + name='lso_kpt28', + id=116, + color=colors['lso'], + type='', + swap='lso_kpt12'), + 117: + dict( + name='lso_kpt29', + id=117, + color=colors['lso'], + type='', + swap='lso_kpt11'), + 118: + dict( + name='lso_kpt30', + id=118, + color=colors['lso'], + type='', + swap='lso_kpt10'), + 119: + dict( + name='lso_kpt31', + id=119, + color=colors['lso'], + type='', + swap='lso_kpt9'), + 120: + dict( + name='lso_kpt32', + id=120, + color=colors['lso'], + type='', + swap='lso_kpt8'), + 121: + dict( + name='lso_kpt33', + id=121, + color=colors['lso'], + type='', + swap='lso_kpt7'), + 122: + dict( + name='lso_kpt34', + id=122, + color=colors['lso'], + type='', + swap='lso_kpt4'), + 123: + dict( + name='lso_kpt35', + id=123, + color=colors['lso'], + type='', + swap='lso_kpt38'), + 124: + dict( + name='lso_kpt36', + id=124, + color=colors['lso'], + type='', + swap='lso_kpt39'), + 125: + dict( + name='lso_kpt37', + id=125, + color=colors['lso'], + type='', + swap='lso_kpt20'), + 126: + dict( + name='lso_kpt38', + id=126, + color=colors['lso'], + type='', + swap='lso_kpt35'), + 127: + dict( + name='lso_kpt39', + id=127, + color=colors['lso'], + type='', + swap='lso_kpt36'), + # vest + 128: + dict(name='vest_kpt1', id=128, color=colors['vest'], type='', swap=''), + 129: + dict( + name='vest_kpt2', + id=129, + color=colors['vest'], + type='', + swap='vest_kpt6'), + 130: + dict( + name='vest_kpt3', + id=130, + color=colors['vest'], + type='', + swap='vest_kpt5'), + 131: + dict(name='vest_kpt4', id=131, color=colors['vest'], type='', swap=''), + 132: + dict( + name='vest_kpt5', + id=132, + color=colors['vest'], + type='', + swap='vest_kpt3'), + 133: + dict( + name='vest_kpt6', + id=133, + color=colors['vest'], + type='', + swap='vest_kpt2'), + 134: + dict( + name='vest_kpt7', + id=134, + color=colors['vest'], + type='', + swap='vest_kpt15'), + 135: + dict( + name='vest_kpt8', + id=135, + color=colors['vest'], + type='', + swap='vest_kpt14'), + 136: + dict( + name='vest_kpt9', + id=136, + color=colors['vest'], + type='', + swap='vest_kpt13'), + 137: + dict( + name='vest_kpt10', + id=137, + color=colors['vest'], + type='', + swap='vest_kpt12'), + 138: + dict( + name='vest_kpt11', id=138, color=colors['vest'], type='', swap=''), + 139: + dict( + name='vest_kpt12', + id=139, + color=colors['vest'], + type='', + swap='vest_kpt10'), + 140: + dict( + name='vest_kpt13', id=140, color=colors['vest'], type='', swap=''), + 141: + dict( + name='vest_kpt14', + id=141, + color=colors['vest'], + type='', + swap='vest_kpt8'), + 142: + dict( + name='vest_kpt15', + id=142, + color=colors['vest'], + type='', + swap='vest_kpt7'), + # sling + 143: + dict( + name='sling_kpt1', id=143, color=colors['sling'], type='', + swap=''), + 144: + dict( + name='sling_kpt2', + id=144, + color=colors['sling'], + type='', + swap='sling_kpt6'), + 145: + dict( + name='sling_kpt3', + id=145, + color=colors['sling'], + type='', + swap='sling_kpt5'), + 146: + dict( + name='sling_kpt4', id=146, color=colors['sling'], type='', + swap=''), + 147: + dict( + name='sling_kpt5', + id=147, + color=colors['sling'], + type='', + swap='sling_kpt3'), + 148: + dict( + name='sling_kpt6', + id=148, + color=colors['sling'], + type='', + swap='sling_kpt2'), + 149: + dict( + name='sling_kpt7', + id=149, + color=colors['sling'], + type='', + swap='sling_kpt15'), + 150: + dict( + name='sling_kpt8', + id=150, + color=colors['sling'], + type='', + swap='sling_kpt14'), + 151: + dict( + name='sling_kpt9', + id=151, + color=colors['sling'], + type='', + swap='sling_kpt13'), + 152: + dict( + name='sling_kpt10', + id=152, + color=colors['sling'], + type='', + swap='sling_kpt12'), + 153: + dict( + name='sling_kpt11', + id=153, + color=colors['sling'], + type='', + swap=''), + 154: + dict( + name='sling_kpt12', + id=154, + color=colors['sling'], + type='', + swap='sling_kpt10'), + 155: + dict( + name='sling_kpt13', + id=155, + color=colors['sling'], + type='', + swap='sling_kpt9'), + 156: + dict( + name='sling_kpt14', + id=156, + color=colors['sling'], + type='', + swap='sling_kpt8'), + 157: + dict( + name='sling_kpt15', + id=157, + color=colors['sling'], + type='', + swap='sling_kpt7'), + # shorts + 158: + dict( + name='shorts_kpt1', + id=158, + color=colors['shorts'], + type='', + swap='shorts_kpt3'), + 159: + dict( + name='shorts_kpt2', + id=159, + color=colors['shorts'], + type='', + swap=''), + 160: + dict( + name='shorts_kpt3', + id=160, + color=colors['shorts'], + type='', + swap='shorts_kpt1'), + 161: + dict( + name='shorts_kpt4', + id=161, + color=colors['shorts'], + type='', + swap='shorts_kpt10'), + 162: + dict( + name='shorts_kpt5', + id=162, + color=colors['shorts'], + type='', + swap='shorts_kpt9'), + 163: + dict( + name='shorts_kpt6', + id=163, + color=colors['shorts'], + type='', + swap='shorts_kpt8'), + 164: + dict( + name='shorts_kpt7', + id=164, + color=colors['shorts'], + type='', + swap=''), + 165: + dict( + name='shorts_kpt8', + id=165, + color=colors['shorts'], + type='', + swap='shorts_kpt6'), + 166: + dict( + name='shorts_kpt9', + id=166, + color=colors['shorts'], + type='', + swap='shorts_kpt5'), + 167: + dict( + name='shorts_kpt10', + id=167, + color=colors['shorts'], + type='', + swap='shorts_kpt4'), + # trousers + 168: + dict( + name='trousers_kpt1', + id=168, + color=colors['trousers'], + type='', + swap='trousers_kpt3'), + 169: + dict( + name='trousers_kpt2', + id=169, + color=colors['trousers'], + type='', + swap=''), + 170: + dict( + name='trousers_kpt3', + id=170, + color=colors['trousers'], + type='', + swap='trousers_kpt1'), + 171: + dict( + name='trousers_kpt4', + id=171, + color=colors['trousers'], + type='', + swap='trousers_kpt14'), + 172: + dict( + name='trousers_kpt5', + id=172, + color=colors['trousers'], + type='', + swap='trousers_kpt13'), + 173: + dict( + name='trousers_kpt6', + id=173, + color=colors['trousers'], + type='', + swap='trousers_kpt12'), + 174: + dict( + name='trousers_kpt7', + id=174, + color=colors['trousers'], + type='', + swap='trousers_kpt11'), + 175: + dict( + name='trousers_kpt8', + id=175, + color=colors['trousers'], + type='', + swap='trousers_kpt10'), + 176: + dict( + name='trousers_kpt9', + id=176, + color=colors['trousers'], + type='', + swap=''), + 177: + dict( + name='trousers_kpt10', + id=177, + color=colors['trousers'], + type='', + swap='trousers_kpt8'), + 178: + dict( + name='trousers_kpt11', + id=178, + color=colors['trousers'], + type='', + swap='trousers_kpt7'), + 179: + dict( + name='trousers_kpt12', + id=179, + color=colors['trousers'], + type='', + swap='trousers_kpt6'), + 180: + dict( + name='trousers_kpt13', + id=180, + color=colors['trousers'], + type='', + swap='trousers_kpt5'), + 181: + dict( + name='trousers_kpt14', + id=181, + color=colors['trousers'], + type='', + swap='trousers_kpt4'), + # skirt + 182: + dict( + name='skirt_kpt1', + id=182, + color=colors['skirt'], + type='', + swap='skirt_kpt3'), + 183: + dict( + name='skirt_kpt2', id=183, color=colors['skirt'], type='', + swap=''), + 184: + dict( + name='skirt_kpt3', + id=184, + color=colors['skirt'], + type='', + swap='skirt_kpt1'), + 185: + dict( + name='skirt_kpt4', + id=185, + color=colors['skirt'], + type='', + swap='skirt_kpt8'), + 186: + dict( + name='skirt_kpt5', + id=186, + color=colors['skirt'], + type='', + swap='skirt_kpt7'), + 187: + dict( + name='skirt_kpt6', id=187, color=colors['skirt'], type='', + swap=''), + 188: + dict( + name='skirt_kpt7', + id=188, + color=colors['skirt'], + type='', + swap='skirt_kpt5'), + 189: + dict( + name='skirt_kpt8', + id=189, + color=colors['skirt'], + type='', + swap='skirt_kpt4'), + # short_sleeved_dress + 190: + dict(name='ssd_kpt1', id=190, color=colors['ssd'], type='', swap=''), + 191: + dict( + name='ssd_kpt2', + id=191, + color=colors['ssd'], + type='', + swap='ssd_kpt6'), + 192: + dict( + name='ssd_kpt3', + id=192, + color=colors['ssd'], + type='', + swap='ssd_kpt5'), + 193: + dict(name='ssd_kpt4', id=193, color=colors['ssd'], type='', swap=''), + 194: + dict( + name='ssd_kpt5', + id=194, + color=colors['ssd'], + type='', + swap='ssd_kpt3'), + 195: + dict( + name='ssd_kpt6', + id=195, + color=colors['ssd'], + type='', + swap='ssd_kpt2'), + 196: + dict( + name='ssd_kpt7', + id=196, + color=colors['ssd'], + type='', + swap='ssd_kpt29'), + 197: + dict( + name='ssd_kpt8', + id=197, + color=colors['ssd'], + type='', + swap='ssd_kpt28'), + 198: + dict( + name='ssd_kpt9', + id=198, + color=colors['ssd'], + type='', + swap='ssd_kpt27'), + 199: + dict( + name='ssd_kpt10', + id=199, + color=colors['ssd'], + type='', + swap='ssd_kpt26'), + 200: + dict( + name='ssd_kpt11', + id=200, + color=colors['ssd'], + type='', + swap='ssd_kpt25'), + 201: + dict( + name='ssd_kpt12', + id=201, + color=colors['ssd'], + type='', + swap='ssd_kpt24'), + 202: + dict( + name='ssd_kpt13', + id=202, + color=colors['ssd'], + type='', + swap='ssd_kpt23'), + 203: + dict( + name='ssd_kpt14', + id=203, + color=colors['ssd'], + type='', + swap='ssd_kpt22'), + 204: + dict( + name='ssd_kpt15', + id=204, + color=colors['ssd'], + type='', + swap='ssd_kpt21'), + 205: + dict( + name='ssd_kpt16', + id=205, + color=colors['ssd'], + type='', + swap='ssd_kpt20'), + 206: + dict( + name='ssd_kpt17', + id=206, + color=colors['ssd'], + type='', + swap='ssd_kpt19'), + 207: + dict(name='ssd_kpt18', id=207, color=colors['ssd'], type='', swap=''), + 208: + dict( + name='ssd_kpt19', + id=208, + color=colors['ssd'], + type='', + swap='ssd_kpt17'), + 209: + dict( + name='ssd_kpt20', + id=209, + color=colors['ssd'], + type='', + swap='ssd_kpt16'), + 210: + dict( + name='ssd_kpt21', + id=210, + color=colors['ssd'], + type='', + swap='ssd_kpt15'), + 211: + dict( + name='ssd_kpt22', + id=211, + color=colors['ssd'], + type='', + swap='ssd_kpt14'), + 212: + dict( + name='ssd_kpt23', + id=212, + color=colors['ssd'], + type='', + swap='ssd_kpt13'), + 213: + dict( + name='ssd_kpt24', + id=213, + color=colors['ssd'], + type='', + swap='ssd_kpt12'), + 214: + dict( + name='ssd_kpt25', + id=214, + color=colors['ssd'], + type='', + swap='ssd_kpt11'), + 215: + dict( + name='ssd_kpt26', + id=215, + color=colors['ssd'], + type='', + swap='ssd_kpt10'), + 216: + dict( + name='ssd_kpt27', + id=216, + color=colors['ssd'], + type='', + swap='ssd_kpt9'), + 217: + dict( + name='ssd_kpt28', + id=217, + color=colors['ssd'], + type='', + swap='ssd_kpt8'), + 218: + dict( + name='ssd_kpt29', + id=218, + color=colors['ssd'], + type='', + swap='ssd_kpt7'), + # long_sleeved_dress + 219: + dict(name='lsd_kpt1', id=219, color=colors['lsd'], type='', swap=''), + 220: + dict( + name='lsd_kpt2', + id=220, + color=colors['lsd'], + type='', + swap='lsd_kpt6'), + 221: + dict( + name='lsd_kpt3', + id=221, + color=colors['lsd'], + type='', + swap='lsd_kpt5'), + 222: + dict(name='lsd_kpt4', id=222, color=colors['lsd'], type='', swap=''), + 223: + dict( + name='lsd_kpt5', + id=223, + color=colors['lsd'], + type='', + swap='lsd_kpt3'), + 224: + dict( + name='lsd_kpt6', + id=224, + color=colors['lsd'], + type='', + swap='lsd_kpt2'), + 225: + dict( + name='lsd_kpt7', + id=225, + color=colors['lsd'], + type='', + swap='lsd_kpt37'), + 226: + dict( + name='lsd_kpt8', + id=226, + color=colors['lsd'], + type='', + swap='lsd_kpt36'), + 227: + dict( + name='lsd_kpt9', + id=227, + color=colors['lsd'], + type='', + swap='lsd_kpt35'), + 228: + dict( + name='lsd_kpt10', + id=228, + color=colors['lsd'], + type='', + swap='lsd_kpt34'), + 229: + dict( + name='lsd_kpt11', + id=229, + color=colors['lsd'], + type='', + swap='lsd_kpt33'), + 230: + dict( + name='lsd_kpt12', + id=230, + color=colors['lsd'], + type='', + swap='lsd_kpt32'), + 231: + dict( + name='lsd_kpt13', + id=231, + color=colors['lsd'], + type='', + swap='lsd_kpt31'), + 232: + dict( + name='lsd_kpt14', + id=232, + color=colors['lsd'], + type='', + swap='lsd_kpt30'), + 233: + dict( + name='lsd_kpt15', + id=233, + color=colors['lsd'], + type='', + swap='lsd_kpt29'), + 234: + dict( + name='lsd_kpt16', + id=234, + color=colors['lsd'], + type='', + swap='lsd_kpt28'), + 235: + dict( + name='lsd_kpt17', + id=235, + color=colors['lsd'], + type='', + swap='lsd_kpt27'), + 236: + dict( + name='lsd_kpt18', + id=236, + color=colors['lsd'], + type='', + swap='lsd_kpt26'), + 237: + dict( + name='lsd_kpt19', + id=237, + color=colors['lsd'], + type='', + swap='lsd_kpt25'), + 238: + dict( + name='lsd_kpt20', + id=238, + color=colors['lsd'], + type='', + swap='lsd_kpt24'), + 239: + dict( + name='lsd_kpt21', + id=239, + color=colors['lsd'], + type='', + swap='lsd_kpt23'), + 240: + dict(name='lsd_kpt22', id=240, color=colors['lsd'], type='', swap=''), + 241: + dict( + name='lsd_kpt23', + id=241, + color=colors['lsd'], + type='', + swap='lsd_kpt21'), + 242: + dict( + name='lsd_kpt24', + id=242, + color=colors['lsd'], + type='', + swap='lsd_kpt20'), + 243: + dict( + name='lsd_kpt25', + id=243, + color=colors['lsd'], + type='', + swap='lsd_kpt19'), + 244: + dict( + name='lsd_kpt26', + id=244, + color=colors['lsd'], + type='', + swap='lsd_kpt18'), + 245: + dict( + name='lsd_kpt27', + id=245, + color=colors['lsd'], + type='', + swap='lsd_kpt17'), + 246: + dict( + name='lsd_kpt28', + id=246, + color=colors['lsd'], + type='', + swap='lsd_kpt16'), + 247: + dict( + name='lsd_kpt29', + id=247, + color=colors['lsd'], + type='', + swap='lsd_kpt15'), + 248: + dict( + name='lsd_kpt30', + id=248, + color=colors['lsd'], + type='', + swap='lsd_kpt14'), + 249: + dict( + name='lsd_kpt31', + id=249, + color=colors['lsd'], + type='', + swap='lsd_kpt13'), + 250: + dict( + name='lsd_kpt32', + id=250, + color=colors['lsd'], + type='', + swap='lsd_kpt12'), + 251: + dict( + name='lsd_kpt33', + id=251, + color=colors['lsd'], + type='', + swap='lsd_kpt11'), + 252: + dict( + name='lsd_kpt34', + id=252, + color=colors['lsd'], + type='', + swap='lsd_kpt10'), + 253: + dict( + name='lsd_kpt35', + id=253, + color=colors['lsd'], + type='', + swap='lsd_kpt9'), + 254: + dict( + name='lsd_kpt36', + id=254, + color=colors['lsd'], + type='', + swap='lsd_kpt8'), + 255: + dict( + name='lsd_kpt37', + id=255, + color=colors['lsd'], + type='', + swap='lsd_kpt7'), + # vest_dress + 256: + dict(name='vd_kpt1', id=256, color=colors['vd'], type='', swap=''), + 257: + dict( + name='vd_kpt2', + id=257, + color=colors['vd'], + type='', + swap='vd_kpt6'), + 258: + dict( + name='vd_kpt3', + id=258, + color=colors['vd'], + type='', + swap='vd_kpt5'), + 259: + dict(name='vd_kpt4', id=259, color=colors['vd'], type='', swap=''), + 260: + dict( + name='vd_kpt5', + id=260, + color=colors['vd'], + type='', + swap='vd_kpt3'), + 261: + dict( + name='vd_kpt6', + id=261, + color=colors['vd'], + type='', + swap='vd_kpt2'), + 262: + dict( + name='vd_kpt7', + id=262, + color=colors['vd'], + type='', + swap='vd_kpt19'), + 263: + dict( + name='vd_kpt8', + id=263, + color=colors['vd'], + type='', + swap='vd_kpt18'), + 264: + dict( + name='vd_kpt9', + id=264, + color=colors['vd'], + type='', + swap='vd_kpt17'), + 265: + dict( + name='vd_kpt10', + id=265, + color=colors['vd'], + type='', + swap='vd_kpt16'), + 266: + dict( + name='vd_kpt11', + id=266, + color=colors['vd'], + type='', + swap='vd_kpt15'), + 267: + dict( + name='vd_kpt12', + id=267, + color=colors['vd'], + type='', + swap='vd_kpt14'), + 268: + dict(name='vd_kpt13', id=268, color=colors['vd'], type='', swap=''), + 269: + dict( + name='vd_kpt14', + id=269, + color=colors['vd'], + type='', + swap='vd_kpt12'), + 270: + dict( + name='vd_kpt15', + id=270, + color=colors['vd'], + type='', + swap='vd_kpt11'), + 271: + dict( + name='vd_kpt16', + id=271, + color=colors['vd'], + type='', + swap='vd_kpt10'), + 272: + dict( + name='vd_kpt17', + id=272, + color=colors['vd'], + type='', + swap='vd_kpt9'), + 273: + dict( + name='vd_kpt18', + id=273, + color=colors['vd'], + type='', + swap='vd_kpt8'), + 274: + dict( + name='vd_kpt19', + id=274, + color=colors['vd'], + type='', + swap='vd_kpt7'), + # sling_dress + 275: + dict(name='sd_kpt1', id=275, color=colors['sd'], type='', swap=''), + 276: + dict( + name='sd_kpt2', + id=276, + color=colors['sd'], + type='', + swap='sd_kpt6'), + 277: + dict( + name='sd_kpt3', + id=277, + color=colors['sd'], + type='', + swap='sd_kpt5'), + 278: + dict(name='sd_kpt4', id=278, color=colors['sd'], type='', swap=''), + 279: + dict( + name='sd_kpt5', + id=279, + color=colors['sd'], + type='', + swap='sd_kpt3'), + 280: + dict( + name='sd_kpt6', + id=280, + color=colors['sd'], + type='', + swap='sd_kpt2'), + 281: + dict( + name='sd_kpt7', + id=281, + color=colors['sd'], + type='', + swap='sd_kpt19'), + 282: + dict( + name='sd_kpt8', + id=282, + color=colors['sd'], + type='', + swap='sd_kpt18'), + 283: + dict( + name='sd_kpt9', + id=283, + color=colors['sd'], + type='', + swap='sd_kpt17'), + 284: + dict( + name='sd_kpt10', + id=284, + color=colors['sd'], + type='', + swap='sd_kpt16'), + 285: + dict( + name='sd_kpt11', + id=285, + color=colors['sd'], + type='', + swap='sd_kpt15'), + 286: + dict( + name='sd_kpt12', + id=286, + color=colors['sd'], + type='', + swap='sd_kpt14'), + 287: + dict(name='sd_kpt13', id=287, color=colors['sd'], type='', swap=''), + 288: + dict( + name='sd_kpt14', + id=288, + color=colors['sd'], + type='', + swap='sd_kpt12'), + 289: + dict( + name='sd_kpt15', + id=289, + color=colors['sd'], + type='', + swap='sd_kpt11'), + 290: + dict( + name='sd_kpt16', + id=290, + color=colors['sd'], + type='', + swap='sd_kpt10'), + 291: + dict( + name='sd_kpt17', + id=291, + color=colors['sd'], + type='', + swap='sd_kpt9'), + 292: + dict( + name='sd_kpt18', + id=292, + color=colors['sd'], + type='', + swap='sd_kpt8'), + 293: + dict( + name='sd_kpt19', + id=293, + color=colors['sd'], + type='', + swap='sd_kpt7'), + }, + skeleton_info={ + # short_sleeved_shirt + 0: + dict(link=('sss_kpt1', 'sss_kpt2'), id=0, color=[255, 128, 0]), + 1: + dict(link=('sss_kpt2', 'sss_kpt7'), id=1, color=[255, 128, 0]), + 2: + dict(link=('sss_kpt7', 'sss_kpt8'), id=2, color=[255, 128, 0]), + 3: + dict(link=('sss_kpt8', 'sss_kpt9'), id=3, color=[255, 128, 0]), + 4: + dict(link=('sss_kpt9', 'sss_kpt10'), id=4, color=[255, 128, 0]), + 5: + dict(link=('sss_kpt10', 'sss_kpt11'), id=5, color=[255, 128, 0]), + 6: + dict(link=('sss_kpt11', 'sss_kpt12'), id=6, color=[255, 128, 0]), + 7: + dict(link=('sss_kpt12', 'sss_kpt13'), id=7, color=[255, 128, 0]), + 8: + dict(link=('sss_kpt13', 'sss_kpt14'), id=8, color=[255, 128, 0]), + 9: + dict(link=('sss_kpt14', 'sss_kpt15'), id=9, color=[255, 128, 0]), + 10: + dict(link=('sss_kpt15', 'sss_kpt16'), id=10, color=[255, 128, 0]), + 11: + dict(link=('sss_kpt16', 'sss_kpt17'), id=11, color=[255, 128, 0]), + 12: + dict(link=('sss_kpt17', 'sss_kpt18'), id=12, color=[255, 128, 0]), + 13: + dict(link=('sss_kpt18', 'sss_kpt19'), id=13, color=[255, 128, 0]), + 14: + dict(link=('sss_kpt19', 'sss_kpt20'), id=14, color=[255, 128, 0]), + 15: + dict(link=('sss_kpt20', 'sss_kpt21'), id=15, color=[255, 128, 0]), + 16: + dict(link=('sss_kpt21', 'sss_kpt22'), id=16, color=[255, 128, 0]), + 17: + dict(link=('sss_kpt22', 'sss_kpt23'), id=17, color=[255, 128, 0]), + 18: + dict(link=('sss_kpt23', 'sss_kpt24'), id=18, color=[255, 128, 0]), + 19: + dict(link=('sss_kpt24', 'sss_kpt25'), id=19, color=[255, 128, 0]), + 20: + dict(link=('sss_kpt25', 'sss_kpt6'), id=20, color=[255, 128, 0]), + 21: + dict(link=('sss_kpt6', 'sss_kpt1'), id=21, color=[255, 128, 0]), + 22: + dict(link=('sss_kpt2', 'sss_kpt3'), id=22, color=[255, 128, 0]), + 23: + dict(link=('sss_kpt3', 'sss_kpt4'), id=23, color=[255, 128, 0]), + 24: + dict(link=('sss_kpt4', 'sss_kpt5'), id=24, color=[255, 128, 0]), + 25: + dict(link=('sss_kpt5', 'sss_kpt6'), id=25, color=[255, 128, 0]), + # long_sleeve_shirt + 26: + dict(link=('lss_kpt1', 'lss_kpt2'), id=26, color=[255, 0, 128]), + 27: + dict(link=('lss_kpt2', 'lss_kpt7'), id=27, color=[255, 0, 128]), + 28: + dict(link=('lss_kpt7', 'lss_kpt8'), id=28, color=[255, 0, 128]), + 29: + dict(link=('lss_kpt8', 'lss_kpt9'), id=29, color=[255, 0, 128]), + 30: + dict(link=('lss_kpt9', 'lss_kpt10'), id=30, color=[255, 0, 128]), + 31: + dict(link=('lss_kpt10', 'lss_kpt11'), id=31, color=[255, 0, 128]), + 32: + dict(link=('lss_kpt11', 'lss_kpt12'), id=32, color=[255, 0, 128]), + 33: + dict(link=('lss_kpt12', 'lss_kpt13'), id=33, color=[255, 0, 128]), + 34: + dict(link=('lss_kpt13', 'lss_kpt14'), id=34, color=[255, 0, 128]), + 35: + dict(link=('lss_kpt14', 'lss_kpt15'), id=35, color=[255, 0, 128]), + 36: + dict(link=('lss_kpt15', 'lss_kpt16'), id=36, color=[255, 0, 128]), + 37: + dict(link=('lss_kpt16', 'lss_kpt17'), id=37, color=[255, 0, 128]), + 38: + dict(link=('lss_kpt17', 'lss_kpt18'), id=38, color=[255, 0, 128]), + 39: + dict(link=('lss_kpt18', 'lss_kpt19'), id=39, color=[255, 0, 128]), + 40: + dict(link=('lss_kpt19', 'lss_kpt20'), id=40, color=[255, 0, 128]), + 41: + dict(link=('lss_kpt20', 'lss_kpt21'), id=41, color=[255, 0, 128]), + 42: + dict(link=('lss_kpt21', 'lss_kpt22'), id=42, color=[255, 0, 128]), + 43: + dict(link=('lss_kpt22', 'lss_kpt23'), id=43, color=[255, 0, 128]), + 44: + dict(link=('lss_kpt23', 'lss_kpt24'), id=44, color=[255, 0, 128]), + 45: + dict(link=('lss_kpt24', 'lss_kpt25'), id=45, color=[255, 0, 128]), + 46: + dict(link=('lss_kpt25', 'lss_kpt26'), id=46, color=[255, 0, 128]), + 47: + dict(link=('lss_kpt26', 'lss_kpt27'), id=47, color=[255, 0, 128]), + 48: + dict(link=('lss_kpt27', 'lss_kpt28'), id=48, color=[255, 0, 128]), + 49: + dict(link=('lss_kpt28', 'lss_kpt29'), id=49, color=[255, 0, 128]), + 50: + dict(link=('lss_kpt29', 'lss_kpt30'), id=50, color=[255, 0, 128]), + 51: + dict(link=('lss_kpt30', 'lss_kpt31'), id=51, color=[255, 0, 128]), + 52: + dict(link=('lss_kpt31', 'lss_kpt32'), id=52, color=[255, 0, 128]), + 53: + dict(link=('lss_kpt32', 'lss_kpt33'), id=53, color=[255, 0, 128]), + 54: + dict(link=('lss_kpt33', 'lss_kpt6'), id=54, color=[255, 0, 128]), + 55: + dict(link=('lss_kpt6', 'lss_kpt5'), id=55, color=[255, 0, 128]), + 56: + dict(link=('lss_kpt5', 'lss_kpt4'), id=56, color=[255, 0, 128]), + 57: + dict(link=('lss_kpt4', 'lss_kpt3'), id=57, color=[255, 0, 128]), + 58: + dict(link=('lss_kpt3', 'lss_kpt2'), id=58, color=[255, 0, 128]), + 59: + dict(link=('lss_kpt6', 'lss_kpt1'), id=59, color=[255, 0, 128]), + # short_sleeved_outwear + 60: + dict(link=('sso_kpt1', 'sso_kpt4'), id=60, color=[128, 0, 255]), + 61: + dict(link=('sso_kpt4', 'sso_kpt7'), id=61, color=[128, 0, 255]), + 62: + dict(link=('sso_kpt7', 'sso_kpt8'), id=62, color=[128, 0, 255]), + 63: + dict(link=('sso_kpt8', 'sso_kpt9'), id=63, color=[128, 0, 255]), + 64: + dict(link=('sso_kpt9', 'sso_kpt10'), id=64, color=[128, 0, 255]), + 65: + dict(link=('sso_kpt10', 'sso_kpt11'), id=65, color=[128, 0, 255]), + 66: + dict(link=('sso_kpt11', 'sso_kpt12'), id=66, color=[128, 0, 255]), + 67: + dict(link=('sso_kpt12', 'sso_kpt13'), id=67, color=[128, 0, 255]), + 68: + dict(link=('sso_kpt13', 'sso_kpt14'), id=68, color=[128, 0, 255]), + 69: + dict(link=('sso_kpt14', 'sso_kpt15'), id=69, color=[128, 0, 255]), + 70: + dict(link=('sso_kpt15', 'sso_kpt16'), id=70, color=[128, 0, 255]), + 71: + dict(link=('sso_kpt16', 'sso_kpt31'), id=71, color=[128, 0, 255]), + 72: + dict(link=('sso_kpt31', 'sso_kpt30'), id=72, color=[128, 0, 255]), + 73: + dict(link=('sso_kpt30', 'sso_kpt2'), id=73, color=[128, 0, 255]), + 74: + dict(link=('sso_kpt2', 'sso_kpt3'), id=74, color=[128, 0, 255]), + 75: + dict(link=('sso_kpt3', 'sso_kpt4'), id=75, color=[128, 0, 255]), + 76: + dict(link=('sso_kpt1', 'sso_kpt6'), id=76, color=[128, 0, 255]), + 77: + dict(link=('sso_kpt6', 'sso_kpt25'), id=77, color=[128, 0, 255]), + 78: + dict(link=('sso_kpt25', 'sso_kpt24'), id=78, color=[128, 0, 255]), + 79: + dict(link=('sso_kpt24', 'sso_kpt23'), id=79, color=[128, 0, 255]), + 80: + dict(link=('sso_kpt23', 'sso_kpt22'), id=80, color=[128, 0, 255]), + 81: + dict(link=('sso_kpt22', 'sso_kpt21'), id=81, color=[128, 0, 255]), + 82: + dict(link=('sso_kpt21', 'sso_kpt20'), id=82, color=[128, 0, 255]), + 83: + dict(link=('sso_kpt20', 'sso_kpt19'), id=83, color=[128, 0, 255]), + 84: + dict(link=('sso_kpt19', 'sso_kpt18'), id=84, color=[128, 0, 255]), + 85: + dict(link=('sso_kpt18', 'sso_kpt17'), id=85, color=[128, 0, 255]), + 86: + dict(link=('sso_kpt17', 'sso_kpt29'), id=86, color=[128, 0, 255]), + 87: + dict(link=('sso_kpt29', 'sso_kpt28'), id=87, color=[128, 0, 255]), + 88: + dict(link=('sso_kpt28', 'sso_kpt27'), id=88, color=[128, 0, 255]), + 89: + dict(link=('sso_kpt27', 'sso_kpt26'), id=89, color=[128, 0, 255]), + 90: + dict(link=('sso_kpt26', 'sso_kpt5'), id=90, color=[128, 0, 255]), + 91: + dict(link=('sso_kpt5', 'sso_kpt6'), id=91, color=[128, 0, 255]), + # long_sleeved_outwear + 92: + dict(link=('lso_kpt1', 'lso_kpt2'), id=92, color=[0, 128, 255]), + 93: + dict(link=('lso_kpt2', 'lso_kpt7'), id=93, color=[0, 128, 255]), + 94: + dict(link=('lso_kpt7', 'lso_kpt8'), id=94, color=[0, 128, 255]), + 95: + dict(link=('lso_kpt8', 'lso_kpt9'), id=95, color=[0, 128, 255]), + 96: + dict(link=('lso_kpt9', 'lso_kpt10'), id=96, color=[0, 128, 255]), + 97: + dict(link=('lso_kpt10', 'lso_kpt11'), id=97, color=[0, 128, 255]), + 98: + dict(link=('lso_kpt11', 'lso_kpt12'), id=98, color=[0, 128, 255]), + 99: + dict(link=('lso_kpt12', 'lso_kpt13'), id=99, color=[0, 128, 255]), + 100: + dict(link=('lso_kpt13', 'lso_kpt14'), id=100, color=[0, 128, 255]), + 101: + dict(link=('lso_kpt14', 'lso_kpt15'), id=101, color=[0, 128, 255]), + 102: + dict(link=('lso_kpt15', 'lso_kpt16'), id=102, color=[0, 128, 255]), + 103: + dict(link=('lso_kpt16', 'lso_kpt17'), id=103, color=[0, 128, 255]), + 104: + dict(link=('lso_kpt17', 'lso_kpt18'), id=104, color=[0, 128, 255]), + 105: + dict(link=('lso_kpt18', 'lso_kpt19'), id=105, color=[0, 128, 255]), + 106: + dict(link=('lso_kpt19', 'lso_kpt20'), id=106, color=[0, 128, 255]), + 107: + dict(link=('lso_kpt20', 'lso_kpt39'), id=107, color=[0, 128, 255]), + 108: + dict(link=('lso_kpt39', 'lso_kpt38'), id=108, color=[0, 128, 255]), + 109: + dict(link=('lso_kpt38', 'lso_kpt4'), id=109, color=[0, 128, 255]), + 110: + dict(link=('lso_kpt4', 'lso_kpt3'), id=110, color=[0, 128, 255]), + 111: + dict(link=('lso_kpt3', 'lso_kpt2'), id=111, color=[0, 128, 255]), + 112: + dict(link=('lso_kpt1', 'lso_kpt6'), id=112, color=[0, 128, 255]), + 113: + dict(link=('lso_kpt6', 'lso_kpt33'), id=113, color=[0, 128, 255]), + 114: + dict(link=('lso_kpt33', 'lso_kpt32'), id=114, color=[0, 128, 255]), + 115: + dict(link=('lso_kpt32', 'lso_kpt31'), id=115, color=[0, 128, 255]), + 116: + dict(link=('lso_kpt31', 'lso_kpt30'), id=116, color=[0, 128, 255]), + 117: + dict(link=('lso_kpt30', 'lso_kpt29'), id=117, color=[0, 128, 255]), + 118: + dict(link=('lso_kpt29', 'lso_kpt28'), id=118, color=[0, 128, 255]), + 119: + dict(link=('lso_kpt28', 'lso_kpt27'), id=119, color=[0, 128, 255]), + 120: + dict(link=('lso_kpt27', 'lso_kpt26'), id=120, color=[0, 128, 255]), + 121: + dict(link=('lso_kpt26', 'lso_kpt25'), id=121, color=[0, 128, 255]), + 122: + dict(link=('lso_kpt25', 'lso_kpt24'), id=122, color=[0, 128, 255]), + 123: + dict(link=('lso_kpt24', 'lso_kpt23'), id=123, color=[0, 128, 255]), + 124: + dict(link=('lso_kpt23', 'lso_kpt22'), id=124, color=[0, 128, 255]), + 125: + dict(link=('lso_kpt22', 'lso_kpt21'), id=125, color=[0, 128, 255]), + 126: + dict(link=('lso_kpt21', 'lso_kpt37'), id=126, color=[0, 128, 255]), + 127: + dict(link=('lso_kpt37', 'lso_kpt36'), id=127, color=[0, 128, 255]), + 128: + dict(link=('lso_kpt36', 'lso_kpt35'), id=128, color=[0, 128, 255]), + 129: + dict(link=('lso_kpt35', 'lso_kpt34'), id=129, color=[0, 128, 255]), + 130: + dict(link=('lso_kpt34', 'lso_kpt5'), id=130, color=[0, 128, 255]), + 131: + dict(link=('lso_kpt5', 'lso_kpt6'), id=131, color=[0, 128, 255]), + # vest + 132: + dict(link=('vest_kpt1', 'vest_kpt2'), id=132, color=[0, 128, 128]), + 133: + dict(link=('vest_kpt2', 'vest_kpt7'), id=133, color=[0, 128, 128]), + 134: + dict(link=('vest_kpt7', 'vest_kpt8'), id=134, color=[0, 128, 128]), + 135: + dict(link=('vest_kpt8', 'vest_kpt9'), id=135, color=[0, 128, 128]), + 136: + dict(link=('vest_kpt9', 'vest_kpt10'), id=136, color=[0, 128, 128]), + 137: + dict(link=('vest_kpt10', 'vest_kpt11'), id=137, color=[0, 128, 128]), + 138: + dict(link=('vest_kpt11', 'vest_kpt12'), id=138, color=[0, 128, 128]), + 139: + dict(link=('vest_kpt12', 'vest_kpt13'), id=139, color=[0, 128, 128]), + 140: + dict(link=('vest_kpt13', 'vest_kpt14'), id=140, color=[0, 128, 128]), + 141: + dict(link=('vest_kpt14', 'vest_kpt15'), id=141, color=[0, 128, 128]), + 142: + dict(link=('vest_kpt15', 'vest_kpt6'), id=142, color=[0, 128, 128]), + 143: + dict(link=('vest_kpt6', 'vest_kpt1'), id=143, color=[0, 128, 128]), + 144: + dict(link=('vest_kpt2', 'vest_kpt3'), id=144, color=[0, 128, 128]), + 145: + dict(link=('vest_kpt3', 'vest_kpt4'), id=145, color=[0, 128, 128]), + 146: + dict(link=('vest_kpt4', 'vest_kpt5'), id=146, color=[0, 128, 128]), + 147: + dict(link=('vest_kpt5', 'vest_kpt6'), id=147, color=[0, 128, 128]), + # sling + 148: + dict(link=('sling_kpt1', 'sling_kpt2'), id=148, color=[0, 0, 128]), + 149: + dict(link=('sling_kpt2', 'sling_kpt8'), id=149, color=[0, 0, 128]), + 150: + dict(link=('sling_kpt8', 'sling_kpt9'), id=150, color=[0, 0, 128]), + 151: + dict(link=('sling_kpt9', 'sling_kpt10'), id=151, color=[0, 0, 128]), + 152: + dict(link=('sling_kpt10', 'sling_kpt11'), id=152, color=[0, 0, 128]), + 153: + dict(link=('sling_kpt11', 'sling_kpt12'), id=153, color=[0, 0, 128]), + 154: + dict(link=('sling_kpt12', 'sling_kpt13'), id=154, color=[0, 0, 128]), + 155: + dict(link=('sling_kpt13', 'sling_kpt14'), id=155, color=[0, 0, 128]), + 156: + dict(link=('sling_kpt14', 'sling_kpt6'), id=156, color=[0, 0, 128]), + 157: + dict(link=('sling_kpt2', 'sling_kpt7'), id=157, color=[0, 0, 128]), + 158: + dict(link=('sling_kpt6', 'sling_kpt15'), id=158, color=[0, 0, 128]), + 159: + dict(link=('sling_kpt2', 'sling_kpt3'), id=159, color=[0, 0, 128]), + 160: + dict(link=('sling_kpt3', 'sling_kpt4'), id=160, color=[0, 0, 128]), + 161: + dict(link=('sling_kpt4', 'sling_kpt5'), id=161, color=[0, 0, 128]), + 162: + dict(link=('sling_kpt5', 'sling_kpt6'), id=162, color=[0, 0, 128]), + 163: + dict(link=('sling_kpt1', 'sling_kpt6'), id=163, color=[0, 0, 128]), + # shorts + 164: + dict( + link=('shorts_kpt1', 'shorts_kpt4'), id=164, color=[128, 128, + 128]), + 165: + dict( + link=('shorts_kpt4', 'shorts_kpt5'), id=165, color=[128, 128, + 128]), + 166: + dict( + link=('shorts_kpt5', 'shorts_kpt6'), id=166, color=[128, 128, + 128]), + 167: + dict( + link=('shorts_kpt6', 'shorts_kpt7'), id=167, color=[128, 128, + 128]), + 168: + dict( + link=('shorts_kpt7', 'shorts_kpt8'), id=168, color=[128, 128, + 128]), + 169: + dict( + link=('shorts_kpt8', 'shorts_kpt9'), id=169, color=[128, 128, + 128]), + 170: + dict( + link=('shorts_kpt9', 'shorts_kpt10'), + id=170, + color=[128, 128, 128]), + 171: + dict( + link=('shorts_kpt10', 'shorts_kpt3'), + id=171, + color=[128, 128, 128]), + 172: + dict( + link=('shorts_kpt3', 'shorts_kpt2'), id=172, color=[128, 128, + 128]), + 173: + dict( + link=('shorts_kpt2', 'shorts_kpt1'), id=173, color=[128, 128, + 128]), + # trousers + 174: + dict( + link=('trousers_kpt1', 'trousers_kpt4'), + id=174, + color=[128, 0, 128]), + 175: + dict( + link=('trousers_kpt4', 'trousers_kpt5'), + id=175, + color=[128, 0, 128]), + 176: + dict( + link=('trousers_kpt5', 'trousers_kpt6'), + id=176, + color=[128, 0, 128]), + 177: + dict( + link=('trousers_kpt6', 'trousers_kpt7'), + id=177, + color=[128, 0, 128]), + 178: + dict( + link=('trousers_kpt7', 'trousers_kpt8'), + id=178, + color=[128, 0, 128]), + 179: + dict( + link=('trousers_kpt8', 'trousers_kpt9'), + id=179, + color=[128, 0, 128]), + 180: + dict( + link=('trousers_kpt9', 'trousers_kpt10'), + id=180, + color=[128, 0, 128]), + 181: + dict( + link=('trousers_kpt10', 'trousers_kpt11'), + id=181, + color=[128, 0, 128]), + 182: + dict( + link=('trousers_kpt11', 'trousers_kpt12'), + id=182, + color=[128, 0, 128]), + 183: + dict( + link=('trousers_kpt12', 'trousers_kpt13'), + id=183, + color=[128, 0, 128]), + 184: + dict( + link=('trousers_kpt13', 'trousers_kpt14'), + id=184, + color=[128, 0, 128]), + 185: + dict( + link=('trousers_kpt14', 'trousers_kpt3'), + id=185, + color=[128, 0, 128]), + 186: + dict( + link=('trousers_kpt3', 'trousers_kpt2'), + id=186, + color=[128, 0, 128]), + 187: + dict( + link=('trousers_kpt2', 'trousers_kpt1'), + id=187, + color=[128, 0, 128]), + # skirt + 188: + dict(link=('skirt_kpt1', 'skirt_kpt4'), id=188, color=[64, 128, 128]), + 189: + dict(link=('skirt_kpt4', 'skirt_kpt5'), id=189, color=[64, 128, 128]), + 190: + dict(link=('skirt_kpt5', 'skirt_kpt6'), id=190, color=[64, 128, 128]), + 191: + dict(link=('skirt_kpt6', 'skirt_kpt7'), id=191, color=[64, 128, 128]), + 192: + dict(link=('skirt_kpt7', 'skirt_kpt8'), id=192, color=[64, 128, 128]), + 193: + dict(link=('skirt_kpt8', 'skirt_kpt3'), id=193, color=[64, 128, 128]), + 194: + dict(link=('skirt_kpt3', 'skirt_kpt2'), id=194, color=[64, 128, 128]), + 195: + dict(link=('skirt_kpt2', 'skirt_kpt1'), id=195, color=[64, 128, 128]), + # short_sleeved_dress + 196: + dict(link=('ssd_kpt1', 'ssd_kpt2'), id=196, color=[64, 64, 128]), + 197: + dict(link=('ssd_kpt2', 'ssd_kpt7'), id=197, color=[64, 64, 128]), + 198: + dict(link=('ssd_kpt7', 'ssd_kpt8'), id=198, color=[64, 64, 128]), + 199: + dict(link=('ssd_kpt8', 'ssd_kpt9'), id=199, color=[64, 64, 128]), + 200: + dict(link=('ssd_kpt9', 'ssd_kpt10'), id=200, color=[64, 64, 128]), + 201: + dict(link=('ssd_kpt10', 'ssd_kpt11'), id=201, color=[64, 64, 128]), + 202: + dict(link=('ssd_kpt11', 'ssd_kpt12'), id=202, color=[64, 64, 128]), + 203: + dict(link=('ssd_kpt12', 'ssd_kpt13'), id=203, color=[64, 64, 128]), + 204: + dict(link=('ssd_kpt13', 'ssd_kpt14'), id=204, color=[64, 64, 128]), + 205: + dict(link=('ssd_kpt14', 'ssd_kpt15'), id=205, color=[64, 64, 128]), + 206: + dict(link=('ssd_kpt15', 'ssd_kpt16'), id=206, color=[64, 64, 128]), + 207: + dict(link=('ssd_kpt16', 'ssd_kpt17'), id=207, color=[64, 64, 128]), + 208: + dict(link=('ssd_kpt17', 'ssd_kpt18'), id=208, color=[64, 64, 128]), + 209: + dict(link=('ssd_kpt18', 'ssd_kpt19'), id=209, color=[64, 64, 128]), + 210: + dict(link=('ssd_kpt19', 'ssd_kpt20'), id=210, color=[64, 64, 128]), + 211: + dict(link=('ssd_kpt20', 'ssd_kpt21'), id=211, color=[64, 64, 128]), + 212: + dict(link=('ssd_kpt21', 'ssd_kpt22'), id=212, color=[64, 64, 128]), + 213: + dict(link=('ssd_kpt22', 'ssd_kpt23'), id=213, color=[64, 64, 128]), + 214: + dict(link=('ssd_kpt23', 'ssd_kpt24'), id=214, color=[64, 64, 128]), + 215: + dict(link=('ssd_kpt24', 'ssd_kpt25'), id=215, color=[64, 64, 128]), + 216: + dict(link=('ssd_kpt25', 'ssd_kpt26'), id=216, color=[64, 64, 128]), + 217: + dict(link=('ssd_kpt26', 'ssd_kpt27'), id=217, color=[64, 64, 128]), + 218: + dict(link=('ssd_kpt27', 'ssd_kpt28'), id=218, color=[64, 64, 128]), + 219: + dict(link=('ssd_kpt28', 'ssd_kpt29'), id=219, color=[64, 64, 128]), + 220: + dict(link=('ssd_kpt29', 'ssd_kpt6'), id=220, color=[64, 64, 128]), + 221: + dict(link=('ssd_kpt6', 'ssd_kpt5'), id=221, color=[64, 64, 128]), + 222: + dict(link=('ssd_kpt5', 'ssd_kpt4'), id=222, color=[64, 64, 128]), + 223: + dict(link=('ssd_kpt4', 'ssd_kpt3'), id=223, color=[64, 64, 128]), + 224: + dict(link=('ssd_kpt3', 'ssd_kpt2'), id=224, color=[64, 64, 128]), + 225: + dict(link=('ssd_kpt6', 'ssd_kpt1'), id=225, color=[64, 64, 128]), + # long_sleeved_dress + 226: + dict(link=('lsd_kpt1', 'lsd_kpt2'), id=226, color=[128, 64, 0]), + 227: + dict(link=('lsd_kpt2', 'lsd_kpt7'), id=228, color=[128, 64, 0]), + 228: + dict(link=('lsd_kpt7', 'lsd_kpt8'), id=228, color=[128, 64, 0]), + 229: + dict(link=('lsd_kpt8', 'lsd_kpt9'), id=229, color=[128, 64, 0]), + 230: + dict(link=('lsd_kpt9', 'lsd_kpt10'), id=230, color=[128, 64, 0]), + 231: + dict(link=('lsd_kpt10', 'lsd_kpt11'), id=231, color=[128, 64, 0]), + 232: + dict(link=('lsd_kpt11', 'lsd_kpt12'), id=232, color=[128, 64, 0]), + 233: + dict(link=('lsd_kpt12', 'lsd_kpt13'), id=233, color=[128, 64, 0]), + 234: + dict(link=('lsd_kpt13', 'lsd_kpt14'), id=234, color=[128, 64, 0]), + 235: + dict(link=('lsd_kpt14', 'lsd_kpt15'), id=235, color=[128, 64, 0]), + 236: + dict(link=('lsd_kpt15', 'lsd_kpt16'), id=236, color=[128, 64, 0]), + 237: + dict(link=('lsd_kpt16', 'lsd_kpt17'), id=237, color=[128, 64, 0]), + 238: + dict(link=('lsd_kpt17', 'lsd_kpt18'), id=238, color=[128, 64, 0]), + 239: + dict(link=('lsd_kpt18', 'lsd_kpt19'), id=239, color=[128, 64, 0]), + 240: + dict(link=('lsd_kpt19', 'lsd_kpt20'), id=240, color=[128, 64, 0]), + 241: + dict(link=('lsd_kpt20', 'lsd_kpt21'), id=241, color=[128, 64, 0]), + 242: + dict(link=('lsd_kpt21', 'lsd_kpt22'), id=242, color=[128, 64, 0]), + 243: + dict(link=('lsd_kpt22', 'lsd_kpt23'), id=243, color=[128, 64, 0]), + 244: + dict(link=('lsd_kpt23', 'lsd_kpt24'), id=244, color=[128, 64, 0]), + 245: + dict(link=('lsd_kpt24', 'lsd_kpt25'), id=245, color=[128, 64, 0]), + 246: + dict(link=('lsd_kpt25', 'lsd_kpt26'), id=246, color=[128, 64, 0]), + 247: + dict(link=('lsd_kpt26', 'lsd_kpt27'), id=247, color=[128, 64, 0]), + 248: + dict(link=('lsd_kpt27', 'lsd_kpt28'), id=248, color=[128, 64, 0]), + 249: + dict(link=('lsd_kpt28', 'lsd_kpt29'), id=249, color=[128, 64, 0]), + 250: + dict(link=('lsd_kpt29', 'lsd_kpt30'), id=250, color=[128, 64, 0]), + 251: + dict(link=('lsd_kpt30', 'lsd_kpt31'), id=251, color=[128, 64, 0]), + 252: + dict(link=('lsd_kpt31', 'lsd_kpt32'), id=252, color=[128, 64, 0]), + 253: + dict(link=('lsd_kpt32', 'lsd_kpt33'), id=253, color=[128, 64, 0]), + 254: + dict(link=('lsd_kpt33', 'lsd_kpt34'), id=254, color=[128, 64, 0]), + 255: + dict(link=('lsd_kpt34', 'lsd_kpt35'), id=255, color=[128, 64, 0]), + 256: + dict(link=('lsd_kpt35', 'lsd_kpt36'), id=256, color=[128, 64, 0]), + 257: + dict(link=('lsd_kpt36', 'lsd_kpt37'), id=257, color=[128, 64, 0]), + 258: + dict(link=('lsd_kpt37', 'lsd_kpt6'), id=258, color=[128, 64, 0]), + 259: + dict(link=('lsd_kpt6', 'lsd_kpt5'), id=259, color=[128, 64, 0]), + 260: + dict(link=('lsd_kpt5', 'lsd_kpt4'), id=260, color=[128, 64, 0]), + 261: + dict(link=('lsd_kpt4', 'lsd_kpt3'), id=261, color=[128, 64, 0]), + 262: + dict(link=('lsd_kpt3', 'lsd_kpt2'), id=262, color=[128, 64, 0]), + 263: + dict(link=('lsd_kpt6', 'lsd_kpt1'), id=263, color=[128, 64, 0]), + # vest_dress + 264: + dict(link=('vd_kpt1', 'vd_kpt2'), id=264, color=[128, 64, 255]), + 265: + dict(link=('vd_kpt2', 'vd_kpt7'), id=265, color=[128, 64, 255]), + 266: + dict(link=('vd_kpt7', 'vd_kpt8'), id=266, color=[128, 64, 255]), + 267: + dict(link=('vd_kpt8', 'vd_kpt9'), id=267, color=[128, 64, 255]), + 268: + dict(link=('vd_kpt9', 'vd_kpt10'), id=268, color=[128, 64, 255]), + 269: + dict(link=('vd_kpt10', 'vd_kpt11'), id=269, color=[128, 64, 255]), + 270: + dict(link=('vd_kpt11', 'vd_kpt12'), id=270, color=[128, 64, 255]), + 271: + dict(link=('vd_kpt12', 'vd_kpt13'), id=271, color=[128, 64, 255]), + 272: + dict(link=('vd_kpt13', 'vd_kpt14'), id=272, color=[128, 64, 255]), + 273: + dict(link=('vd_kpt14', 'vd_kpt15'), id=273, color=[128, 64, 255]), + 274: + dict(link=('vd_kpt15', 'vd_kpt16'), id=274, color=[128, 64, 255]), + 275: + dict(link=('vd_kpt16', 'vd_kpt17'), id=275, color=[128, 64, 255]), + 276: + dict(link=('vd_kpt17', 'vd_kpt18'), id=276, color=[128, 64, 255]), + 277: + dict(link=('vd_kpt18', 'vd_kpt19'), id=277, color=[128, 64, 255]), + 278: + dict(link=('vd_kpt19', 'vd_kpt6'), id=278, color=[128, 64, 255]), + 279: + dict(link=('vd_kpt6', 'vd_kpt5'), id=279, color=[128, 64, 255]), + 280: + dict(link=('vd_kpt5', 'vd_kpt4'), id=280, color=[128, 64, 255]), + 281: + dict(link=('vd_kpt4', 'vd_kpt3'), id=281, color=[128, 64, 255]), + 282: + dict(link=('vd_kpt3', 'vd_kpt2'), id=282, color=[128, 64, 255]), + 283: + dict(link=('vd_kpt6', 'vd_kpt1'), id=283, color=[128, 64, 255]), + # sling_dress + 284: + dict(link=('sd_kpt1', 'sd_kpt2'), id=284, color=[128, 64, 0]), + 285: + dict(link=('sd_kpt2', 'sd_kpt8'), id=285, color=[128, 64, 0]), + 286: + dict(link=('sd_kpt8', 'sd_kpt9'), id=286, color=[128, 64, 0]), + 287: + dict(link=('sd_kpt9', 'sd_kpt10'), id=287, color=[128, 64, 0]), + 288: + dict(link=('sd_kpt10', 'sd_kpt11'), id=288, color=[128, 64, 0]), + 289: + dict(link=('sd_kpt11', 'sd_kpt12'), id=289, color=[128, 64, 0]), + 290: + dict(link=('sd_kpt12', 'sd_kpt13'), id=290, color=[128, 64, 0]), + 291: + dict(link=('sd_kpt13', 'sd_kpt14'), id=291, color=[128, 64, 0]), + 292: + dict(link=('sd_kpt14', 'sd_kpt15'), id=292, color=[128, 64, 0]), + 293: + dict(link=('sd_kpt15', 'sd_kpt16'), id=293, color=[128, 64, 0]), + 294: + dict(link=('sd_kpt16', 'sd_kpt17'), id=294, color=[128, 64, 0]), + 295: + dict(link=('sd_kpt17', 'sd_kpt18'), id=295, color=[128, 64, 0]), + 296: + dict(link=('sd_kpt18', 'sd_kpt6'), id=296, color=[128, 64, 0]), + 297: + dict(link=('sd_kpt6', 'sd_kpt5'), id=297, color=[128, 64, 0]), + 298: + dict(link=('sd_kpt5', 'sd_kpt4'), id=298, color=[128, 64, 0]), + 299: + dict(link=('sd_kpt4', 'sd_kpt3'), id=299, color=[128, 64, 0]), + 300: + dict(link=('sd_kpt3', 'sd_kpt2'), id=300, color=[128, 64, 0]), + 301: + dict(link=('sd_kpt2', 'sd_kpt7'), id=301, color=[128, 64, 0]), + 302: + dict(link=('sd_kpt6', 'sd_kpt19'), id=302, color=[128, 64, 0]), + 303: + dict(link=('sd_kpt6', 'sd_kpt1'), id=303, color=[128, 64, 0]), + }, + joint_weights=[1.] * 294, + sigmas=[]) diff --git a/configs/_base_/datasets/halpe26.py b/configs/_base_/datasets/halpe26.py new file mode 100644 index 0000000000..cb4df83874 --- /dev/null +++ b/configs/_base_/datasets/halpe26.py @@ -0,0 +1,274 @@ +dataset_info = dict( + dataset_name='halpe26', + paper_info=dict( + author='Li, Yong-Lu and Xu, Liang and Liu, Xinpeng and Huang, Xijie' + ' and Xu, Yue and Wang, Shiyi and Fang, Hao-Shu' + ' and Ma, Ze and Chen, Mingyang and Lu, Cewu', + title='PaStaNet: Toward Human Activity Knowledge Engine', + container='CVPR', + year='2020', + homepage='https://github.com/Fang-Haoshu/Halpe-FullBody/', + ), + keypoint_info={ + 0: + dict(name='nose', id=0, color=[51, 153, 255], type='upper', swap=''), + 1: + dict( + name='left_eye', + id=1, + color=[51, 153, 255], + type='upper', + swap='right_eye'), + 2: + dict( + name='right_eye', + id=2, + color=[51, 153, 255], + type='upper', + swap='left_eye'), + 3: + dict( + name='left_ear', + id=3, + color=[51, 153, 255], + type='upper', + swap='right_ear'), + 4: + dict( + name='right_ear', + id=4, + color=[51, 153, 255], + type='upper', + swap='left_ear'), + 5: + dict( + name='left_shoulder', + id=5, + color=[0, 255, 0], + type='upper', + swap='right_shoulder'), + 6: + dict( + name='right_shoulder', + id=6, + color=[255, 128, 0], + type='upper', + swap='left_shoulder'), + 7: + dict( + name='left_elbow', + id=7, + color=[0, 255, 0], + type='upper', + swap='right_elbow'), + 8: + dict( + name='right_elbow', + id=8, + color=[255, 128, 0], + type='upper', + swap='left_elbow'), + 9: + dict( + name='left_wrist', + id=9, + color=[0, 255, 0], + type='upper', + swap='right_wrist'), + 10: + dict( + name='right_wrist', + id=10, + color=[255, 128, 0], + type='upper', + swap='left_wrist'), + 11: + dict( + name='left_hip', + id=11, + color=[0, 255, 0], + type='lower', + swap='right_hip'), + 12: + dict( + name='right_hip', + id=12, + color=[255, 128, 0], + type='lower', + swap='left_hip'), + 13: + dict( + name='left_knee', + id=13, + color=[0, 255, 0], + type='lower', + swap='right_knee'), + 14: + dict( + name='right_knee', + id=14, + color=[255, 128, 0], + type='lower', + swap='left_knee'), + 15: + dict( + name='left_ankle', + id=15, + color=[0, 255, 0], + type='lower', + swap='right_ankle'), + 16: + dict( + name='right_ankle', + id=16, + color=[255, 128, 0], + type='lower', + swap='left_ankle'), + 17: + dict(name='head', id=17, color=[255, 128, 0], type='upper', swap=''), + 18: + dict(name='neck', id=18, color=[255, 128, 0], type='upper', swap=''), + 19: + dict(name='hip', id=19, color=[255, 128, 0], type='lower', swap=''), + 20: + dict( + name='left_big_toe', + id=20, + color=[255, 128, 0], + type='lower', + swap='right_big_toe'), + 21: + dict( + name='right_big_toe', + id=21, + color=[255, 128, 0], + type='lower', + swap='left_big_toe'), + 22: + dict( + name='left_small_toe', + id=22, + color=[255, 128, 0], + type='lower', + swap='right_small_toe'), + 23: + dict( + name='right_small_toe', + id=23, + color=[255, 128, 0], + type='lower', + swap='left_small_toe'), + 24: + dict( + name='left_heel', + id=24, + color=[255, 128, 0], + type='lower', + swap='right_heel'), + 25: + dict( + name='right_heel', + id=25, + color=[255, 128, 0], + type='lower', + swap='left_heel') + }, + skeleton_info={ + 0: + dict(link=('left_ankle', 'left_knee'), id=0, color=[0, 255, 0]), + 1: + dict(link=('left_knee', 'left_hip'), id=1, color=[0, 255, 0]), + 2: + dict(link=('left_hip', 'hip'), id=2, color=[0, 255, 0]), + 3: + dict(link=('right_ankle', 'right_knee'), id=3, color=[255, 128, 0]), + 4: + dict(link=('right_knee', 'right_hip'), id=4, color=[255, 128, 0]), + 5: + dict(link=('right_hip', 'hip'), id=5, color=[255, 128, 0]), + 6: + dict(link=('head', 'neck'), id=6, color=[51, 153, 255]), + 7: + dict(link=('neck', 'hip'), id=7, color=[51, 153, 255]), + 8: + dict(link=('neck', 'left_shoulder'), id=8, color=[0, 255, 0]), + 9: + dict(link=('left_shoulder', 'left_elbow'), id=9, color=[0, 255, 0]), + 10: + dict(link=('left_elbow', 'left_wrist'), id=10, color=[0, 255, 0]), + 11: + dict(link=('neck', 'right_shoulder'), id=11, color=[255, 128, 0]), + 12: + dict( + link=('right_shoulder', 'right_elbow'), id=12, color=[255, 128, + 0]), + 13: + dict(link=('right_elbow', 'right_wrist'), id=13, color=[255, 128, 0]), + 14: + dict(link=('left_eye', 'right_eye'), id=14, color=[51, 153, 255]), + 15: + dict(link=('nose', 'left_eye'), id=15, color=[51, 153, 255]), + 16: + dict(link=('nose', 'right_eye'), id=16, color=[51, 153, 255]), + 17: + dict(link=('left_eye', 'left_ear'), id=17, color=[51, 153, 255]), + 18: + dict(link=('right_eye', 'right_ear'), id=18, color=[51, 153, 255]), + 19: + dict(link=('left_ear', 'left_shoulder'), id=19, color=[51, 153, 255]), + 20: + dict( + link=('right_ear', 'right_shoulder'), id=20, color=[51, 153, 255]), + 21: + dict(link=('left_ankle', 'left_big_toe'), id=21, color=[0, 255, 0]), + 22: + dict(link=('left_ankle', 'left_small_toe'), id=22, color=[0, 255, 0]), + 23: + dict(link=('left_ankle', 'left_heel'), id=23, color=[0, 255, 0]), + 24: + dict( + link=('right_ankle', 'right_big_toe'), id=24, color=[255, 128, 0]), + 25: + dict( + link=('right_ankle', 'right_small_toe'), + id=25, + color=[255, 128, 0]), + 26: + dict(link=('right_ankle', 'right_heel'), id=26, color=[255, 128, 0]), + }, + # the joint_weights is modified by MMPose Team + joint_weights=[ + 1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5, + 1.5 + ] + [1., 1., 1.2] + [1.5] * 6, + + # 'https://github.com/Fang-Haoshu/Halpe-FullBody/blob/master/' + # 'HalpeCOCOAPI/PythonAPI/halpecocotools/cocoeval.py#L245' + sigmas=[ + 0.026, + 0.025, + 0.025, + 0.035, + 0.035, + 0.079, + 0.079, + 0.072, + 0.072, + 0.062, + 0.062, + 0.107, + 0.107, + 0.087, + 0.087, + 0.089, + 0.089, + 0.026, + 0.026, + 0.066, + 0.079, + 0.079, + 0.079, + 0.079, + 0.079, + 0.079, + ]) diff --git a/configs/_base_/datasets/humanart.py b/configs/_base_/datasets/humanart.py new file mode 100644 index 0000000000..b549269b69 --- /dev/null +++ b/configs/_base_/datasets/humanart.py @@ -0,0 +1,181 @@ +dataset_info = dict( + dataset_name='Human-Art', + paper_info=dict( + author='Ju, Xuan and Zeng, Ailing and ' + 'Wang, Jianan and Xu, Qiang and Zhang, Lei', + title='Human-Art: A Versatile Human-Centric Dataset ' + 'Bridging Natural and Artificial Scenes', + container='Proceedings of the IEEE/CVF Conference on ' + 'Computer Vision and Pattern Recognition', + year='2023', + homepage='https://idea-research.github.io/HumanArt/', + ), + keypoint_info={ + 0: + dict(name='nose', id=0, color=[51, 153, 255], type='upper', swap=''), + 1: + dict( + name='left_eye', + id=1, + color=[51, 153, 255], + type='upper', + swap='right_eye'), + 2: + dict( + name='right_eye', + id=2, + color=[51, 153, 255], + type='upper', + swap='left_eye'), + 3: + dict( + name='left_ear', + id=3, + color=[51, 153, 255], + type='upper', + swap='right_ear'), + 4: + dict( + name='right_ear', + id=4, + color=[51, 153, 255], + type='upper', + swap='left_ear'), + 5: + dict( + name='left_shoulder', + id=5, + color=[0, 255, 0], + type='upper', + swap='right_shoulder'), + 6: + dict( + name='right_shoulder', + id=6, + color=[255, 128, 0], + type='upper', + swap='left_shoulder'), + 7: + dict( + name='left_elbow', + id=7, + color=[0, 255, 0], + type='upper', + swap='right_elbow'), + 8: + dict( + name='right_elbow', + id=8, + color=[255, 128, 0], + type='upper', + swap='left_elbow'), + 9: + dict( + name='left_wrist', + id=9, + color=[0, 255, 0], + type='upper', + swap='right_wrist'), + 10: + dict( + name='right_wrist', + id=10, + color=[255, 128, 0], + type='upper', + swap='left_wrist'), + 11: + dict( + name='left_hip', + id=11, + color=[0, 255, 0], + type='lower', + swap='right_hip'), + 12: + dict( + name='right_hip', + id=12, + color=[255, 128, 0], + type='lower', + swap='left_hip'), + 13: + dict( + name='left_knee', + id=13, + color=[0, 255, 0], + type='lower', + swap='right_knee'), + 14: + dict( + name='right_knee', + id=14, + color=[255, 128, 0], + type='lower', + swap='left_knee'), + 15: + dict( + name='left_ankle', + id=15, + color=[0, 255, 0], + type='lower', + swap='right_ankle'), + 16: + dict( + name='right_ankle', + id=16, + color=[255, 128, 0], + type='lower', + swap='left_ankle') + }, + skeleton_info={ + 0: + dict(link=('left_ankle', 'left_knee'), id=0, color=[0, 255, 0]), + 1: + dict(link=('left_knee', 'left_hip'), id=1, color=[0, 255, 0]), + 2: + dict(link=('right_ankle', 'right_knee'), id=2, color=[255, 128, 0]), + 3: + dict(link=('right_knee', 'right_hip'), id=3, color=[255, 128, 0]), + 4: + dict(link=('left_hip', 'right_hip'), id=4, color=[51, 153, 255]), + 5: + dict(link=('left_shoulder', 'left_hip'), id=5, color=[51, 153, 255]), + 6: + dict(link=('right_shoulder', 'right_hip'), id=6, color=[51, 153, 255]), + 7: + dict( + link=('left_shoulder', 'right_shoulder'), + id=7, + color=[51, 153, 255]), + 8: + dict(link=('left_shoulder', 'left_elbow'), id=8, color=[0, 255, 0]), + 9: + dict( + link=('right_shoulder', 'right_elbow'), id=9, color=[255, 128, 0]), + 10: + dict(link=('left_elbow', 'left_wrist'), id=10, color=[0, 255, 0]), + 11: + dict(link=('right_elbow', 'right_wrist'), id=11, color=[255, 128, 0]), + 12: + dict(link=('left_eye', 'right_eye'), id=12, color=[51, 153, 255]), + 13: + dict(link=('nose', 'left_eye'), id=13, color=[51, 153, 255]), + 14: + dict(link=('nose', 'right_eye'), id=14, color=[51, 153, 255]), + 15: + dict(link=('left_eye', 'left_ear'), id=15, color=[51, 153, 255]), + 16: + dict(link=('right_eye', 'right_ear'), id=16, color=[51, 153, 255]), + 17: + dict(link=('left_ear', 'left_shoulder'), id=17, color=[51, 153, 255]), + 18: + dict( + link=('right_ear', 'right_shoulder'), id=18, color=[51, 153, 255]) + }, + joint_weights=[ + 1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5, + 1.5 + ], + sigmas=[ + 0.026, 0.025, 0.025, 0.035, 0.035, 0.079, 0.079, 0.072, 0.072, 0.062, + 0.062, 0.107, 0.107, 0.087, 0.087, 0.089, 0.089 + ]) diff --git a/configs/_base_/datasets/humanart_aic.py b/configs/_base_/datasets/humanart_aic.py new file mode 100644 index 0000000000..e999427536 --- /dev/null +++ b/configs/_base_/datasets/humanart_aic.py @@ -0,0 +1,205 @@ +dataset_info = dict( + dataset_name='humanart', + paper_info=[ + dict( + author='Ju, Xuan and Zeng, Ailing and ' + 'Wang, Jianan and Xu, Qiang and Zhang, ' + 'Lei', + title='Human-Art: A Versatile Human-Centric Dataset ' + 'Bridging Natural and Artificial Scenes', + container='CVPR', + year='2023', + homepage='https://idea-research.github.io/HumanArt/', + ), + dict( + author='Wu, Jiahong and Zheng, He and Zhao, Bo and ' + 'Li, Yixin and Yan, Baoming and Liang, Rui and ' + 'Wang, Wenjia and Zhou, Shipei and Lin, Guosen and ' + 'Fu, Yanwei and others', + title='Ai challenger: A large-scale dataset for going ' + 'deeper in image understanding', + container='arXiv', + year='2017', + homepage='https://github.com/AIChallenger/AI_Challenger_2017', + ), + ], + keypoint_info={ + 0: + dict(name='nose', id=0, color=[51, 153, 255], type='upper', swap=''), + 1: + dict( + name='left_eye', + id=1, + color=[51, 153, 255], + type='upper', + swap='right_eye'), + 2: + dict( + name='right_eye', + id=2, + color=[51, 153, 255], + type='upper', + swap='left_eye'), + 3: + dict( + name='left_ear', + id=3, + color=[51, 153, 255], + type='upper', + swap='right_ear'), + 4: + dict( + name='right_ear', + id=4, + color=[51, 153, 255], + type='upper', + swap='left_ear'), + 5: + dict( + name='left_shoulder', + id=5, + color=[0, 255, 0], + type='upper', + swap='right_shoulder'), + 6: + dict( + name='right_shoulder', + id=6, + color=[255, 128, 0], + type='upper', + swap='left_shoulder'), + 7: + dict( + name='left_elbow', + id=7, + color=[0, 255, 0], + type='upper', + swap='right_elbow'), + 8: + dict( + name='right_elbow', + id=8, + color=[255, 128, 0], + type='upper', + swap='left_elbow'), + 9: + dict( + name='left_wrist', + id=9, + color=[0, 255, 0], + type='upper', + swap='right_wrist'), + 10: + dict( + name='right_wrist', + id=10, + color=[255, 128, 0], + type='upper', + swap='left_wrist'), + 11: + dict( + name='left_hip', + id=11, + color=[0, 255, 0], + type='lower', + swap='right_hip'), + 12: + dict( + name='right_hip', + id=12, + color=[255, 128, 0], + type='lower', + swap='left_hip'), + 13: + dict( + name='left_knee', + id=13, + color=[0, 255, 0], + type='lower', + swap='right_knee'), + 14: + dict( + name='right_knee', + id=14, + color=[255, 128, 0], + type='lower', + swap='left_knee'), + 15: + dict( + name='left_ankle', + id=15, + color=[0, 255, 0], + type='lower', + swap='right_ankle'), + 16: + dict( + name='right_ankle', + id=16, + color=[255, 128, 0], + type='lower', + swap='left_ankle'), + 17: + dict( + name='head_top', + id=17, + color=[51, 153, 255], + type='upper', + swap=''), + 18: + dict(name='neck', id=18, color=[51, 153, 255], type='upper', swap='') + }, + skeleton_info={ + 0: + dict(link=('left_ankle', 'left_knee'), id=0, color=[0, 255, 0]), + 1: + dict(link=('left_knee', 'left_hip'), id=1, color=[0, 255, 0]), + 2: + dict(link=('right_ankle', 'right_knee'), id=2, color=[255, 128, 0]), + 3: + dict(link=('right_knee', 'right_hip'), id=3, color=[255, 128, 0]), + 4: + dict(link=('left_hip', 'right_hip'), id=4, color=[51, 153, 255]), + 5: + dict(link=('left_shoulder', 'left_hip'), id=5, color=[51, 153, 255]), + 6: + dict(link=('right_shoulder', 'right_hip'), id=6, color=[51, 153, 255]), + 7: + dict( + link=('left_shoulder', 'right_shoulder'), + id=7, + color=[51, 153, 255]), + 8: + dict(link=('left_shoulder', 'left_elbow'), id=8, color=[0, 255, 0]), + 9: + dict( + link=('right_shoulder', 'right_elbow'), id=9, color=[255, 128, 0]), + 10: + dict(link=('left_elbow', 'left_wrist'), id=10, color=[0, 255, 0]), + 11: + dict(link=('right_elbow', 'right_wrist'), id=11, color=[255, 128, 0]), + 12: + dict(link=('left_eye', 'right_eye'), id=12, color=[51, 153, 255]), + 13: + dict(link=('nose', 'left_eye'), id=13, color=[51, 153, 255]), + 14: + dict(link=('nose', 'right_eye'), id=14, color=[51, 153, 255]), + 15: + dict(link=('left_eye', 'left_ear'), id=15, color=[51, 153, 255]), + 16: + dict(link=('right_eye', 'right_ear'), id=16, color=[51, 153, 255]), + 17: + dict(link=('left_ear', 'left_shoulder'), id=17, color=[51, 153, 255]), + 18: + dict( + link=('right_ear', 'right_shoulder'), id=18, color=[51, 153, 255]), + 19: + dict(link=('head_top', 'neck'), id=11, color=[51, 153, 255]), + }, + joint_weights=[ + 1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5, + 1.5, 1.5 + ], + sigmas=[ + 0.026, 0.025, 0.025, 0.035, 0.035, 0.079, 0.079, 0.072, 0.072, 0.062, + 0.062, 0.107, 0.107, 0.087, 0.087, 0.089, 0.089, 0.026, 0.026 + ]) diff --git a/configs/_base_/datasets/lapa.py b/configs/_base_/datasets/lapa.py new file mode 100644 index 0000000000..26a0843404 --- /dev/null +++ b/configs/_base_/datasets/lapa.py @@ -0,0 +1,688 @@ +dataset_info = dict( + dataset_name='lapa', + paper_info=dict( + author='Liu, Yinglu and Shi, Hailin and Shen, Hao and Si, ' + 'Yue and Wang, Xiaobo and Mei, Tao', + title='A New Dataset and Boundary-Attention Semantic ' + 'Segmentation for Face Parsing.', + container='Proceedings of the AAAI Conference on ' + 'Artificial Intelligence 2020', + year='2020', + homepage='https://github.com/JDAI-CV/lapa-dataset', + ), + keypoint_info={ + 0: + dict( + name='kpt-0', id=0, color=[255, 0, 0], type='upper', + swap='kpt-32'), + 1: + dict( + name='kpt-1', id=1, color=[255, 0, 0], type='upper', + swap='kpt-31'), + 2: + dict( + name='kpt-2', id=2, color=[255, 0, 0], type='upper', + swap='kpt-30'), + 3: + dict( + name='kpt-3', id=3, color=[255, 0, 0], type='lower', + swap='kpt-29'), + 4: + dict( + name='kpt-4', id=4, color=[255, 0, 0], type='lower', + swap='kpt-28'), + 5: + dict( + name='kpt-5', id=5, color=[255, 0, 0], type='lower', + swap='kpt-27'), + 6: + dict( + name='kpt-6', id=6, color=[255, 0, 0], type='lower', + swap='kpt-26'), + 7: + dict( + name='kpt-7', id=7, color=[255, 0, 0], type='lower', + swap='kpt-25'), + 8: + dict( + name='kpt-8', id=8, color=[255, 0, 0], type='lower', + swap='kpt-24'), + 9: + dict( + name='kpt-9', id=9, color=[255, 0, 0], type='lower', + swap='kpt-23'), + 10: + dict( + name='kpt-10', + id=10, + color=[255, 0, 0], + type='lower', + swap='kpt-22'), + 11: + dict( + name='kpt-11', + id=11, + color=[255, 0, 0], + type='lower', + swap='kpt-21'), + 12: + dict( + name='kpt-12', + id=12, + color=[255, 0, 0], + type='lower', + swap='kpt-20'), + 13: + dict( + name='kpt-13', + id=13, + color=[255, 0, 0], + type='lower', + swap='kpt-19'), + 14: + dict( + name='kpt-14', + id=14, + color=[255, 0, 0], + type='lower', + swap='kpt-18'), + 15: + dict( + name='kpt-15', + id=15, + color=[255, 0, 0], + type='lower', + swap='kpt-17'), + 16: + dict(name='kpt-16', id=16, color=[255, 0, 0], type='lower', swap=''), + 17: + dict( + name='kpt-17', + id=17, + color=[255, 0, 0], + type='lower', + swap='kpt-15'), + 18: + dict( + name='kpt-18', + id=18, + color=[255, 0, 0], + type='lower', + swap='kpt-14'), + 19: + dict( + name='kpt-19', + id=19, + color=[255, 0, 0], + type='lower', + swap='kpt-13'), + 20: + dict( + name='kpt-20', + id=20, + color=[255, 0, 0], + type='lower', + swap='kpt-12'), + 21: + dict( + name='kpt-21', + id=21, + color=[255, 0, 0], + type='lower', + swap='kpt-11'), + 22: + dict( + name='kpt-22', + id=22, + color=[255, 0, 0], + type='lower', + swap='kpt-10'), + 23: + dict( + name='kpt-23', + id=23, + color=[255, 0, 0], + type='lower', + swap='kpt-9'), + 24: + dict( + name='kpt-24', + id=24, + color=[255, 0, 0], + type='lower', + swap='kpt-8'), + 25: + dict( + name='kpt-25', + id=25, + color=[255, 0, 0], + type='lower', + swap='kpt-7'), + 26: + dict( + name='kpt-26', + id=26, + color=[255, 0, 0], + type='lower', + swap='kpt-6'), + 27: + dict( + name='kpt-27', + id=27, + color=[255, 0, 0], + type='lower', + swap='kpt-5'), + 28: + dict( + name='kpt-28', + id=28, + color=[255, 0, 0], + type='lower', + swap='kpt-4'), + 29: + dict( + name='kpt-29', + id=29, + color=[255, 0, 0], + type='lower', + swap='kpt-3'), + 30: + dict( + name='kpt-30', + id=30, + color=[255, 0, 0], + type='upper', + swap='kpt-2'), + 31: + dict( + name='kpt-31', + id=31, + color=[255, 0, 0], + type='upper', + swap='kpt-1'), + 32: + dict( + name='kpt-32', + id=32, + color=[255, 0, 0], + type='upper', + swap='kpt-0'), + 33: + dict( + name='kpt-33', + id=33, + color=[255, 0, 0], + type='upper', + swap='kpt-46'), + 34: + dict( + name='kpt-34', + id=34, + color=[255, 0, 0], + type='upper', + swap='kpt-45'), + 35: + dict( + name='kpt-35', + id=35, + color=[255, 0, 0], + type='upper', + swap='kpt-44'), + 36: + dict( + name='kpt-36', + id=36, + color=[255, 0, 0], + type='upper', + swap='kpt-43'), + 37: + dict( + name='kpt-37', + id=37, + color=[255, 0, 0], + type='upper', + swap='kpt-42'), + 38: + dict( + name='kpt-38', + id=38, + color=[255, 0, 0], + type='upper', + swap='kpt-50'), + 39: + dict( + name='kpt-39', + id=39, + color=[255, 0, 0], + type='upper', + swap='kpt-49'), + 40: + dict( + name='kpt-40', + id=40, + color=[255, 0, 0], + type='upper', + swap='kpt-48'), + 41: + dict( + name='kpt-41', + id=41, + color=[255, 0, 0], + type='upper', + swap='kpt-47'), + 42: + dict( + name='kpt-42', + id=42, + color=[255, 0, 0], + type='upper', + swap='kpt-37'), + 43: + dict( + name='kpt-43', + id=43, + color=[255, 0, 0], + type='upper', + swap='kpt-36'), + 44: + dict( + name='kpt-44', + id=44, + color=[255, 0, 0], + type='upper', + swap='kpt-35'), + 45: + dict( + name='kpt-45', + id=45, + color=[255, 0, 0], + type='upper', + swap='kpt-34'), + 46: + dict( + name='kpt-46', + id=46, + color=[255, 0, 0], + type='upper', + swap='kpt-33'), + 47: + dict( + name='kpt-47', + id=47, + color=[255, 0, 0], + type='upper', + swap='kpt-41'), + 48: + dict( + name='kpt-48', + id=48, + color=[255, 0, 0], + type='upper', + swap='kpt-40'), + 49: + dict( + name='kpt-49', + id=49, + color=[255, 0, 0], + type='upper', + swap='kpt-39'), + 50: + dict( + name='kpt-50', + id=50, + color=[255, 0, 0], + type='upper', + swap='kpt-38'), + 51: + dict(name='kpt-51', id=51, color=[255, 0, 0], type='upper', swap=''), + 52: + dict(name='kpt-52', id=52, color=[255, 0, 0], type='upper', swap=''), + 53: + dict(name='kpt-53', id=53, color=[255, 0, 0], type='lower', swap=''), + 54: + dict(name='kpt-54', id=54, color=[255, 0, 0], type='lower', swap=''), + 55: + dict( + name='kpt-55', + id=55, + color=[255, 0, 0], + type='upper', + swap='kpt-65'), + 56: + dict( + name='kpt-56', + id=56, + color=[255, 0, 0], + type='lower', + swap='kpt-64'), + 57: + dict( + name='kpt-57', + id=57, + color=[255, 0, 0], + type='lower', + swap='kpt-63'), + 58: + dict( + name='kpt-58', + id=58, + color=[255, 0, 0], + type='lower', + swap='kpt-62'), + 59: + dict( + name='kpt-59', + id=59, + color=[255, 0, 0], + type='lower', + swap='kpt-61'), + 60: + dict(name='kpt-60', id=60, color=[255, 0, 0], type='lower', swap=''), + 61: + dict( + name='kpt-61', + id=61, + color=[255, 0, 0], + type='lower', + swap='kpt-59'), + 62: + dict( + name='kpt-62', + id=62, + color=[255, 0, 0], + type='lower', + swap='kpt-58'), + 63: + dict( + name='kpt-63', + id=63, + color=[255, 0, 0], + type='lower', + swap='kpt-57'), + 64: + dict( + name='kpt-64', + id=64, + color=[255, 0, 0], + type='lower', + swap='kpt-56'), + 65: + dict( + name='kpt-65', + id=65, + color=[255, 0, 0], + type='upper', + swap='kpt-55'), + 66: + dict( + name='kpt-66', + id=66, + color=[255, 0, 0], + type='upper', + swap='kpt-79'), + 67: + dict( + name='kpt-67', + id=67, + color=[255, 0, 0], + type='upper', + swap='kpt-78'), + 68: + dict( + name='kpt-68', + id=68, + color=[255, 0, 0], + type='upper', + swap='kpt-77'), + 69: + dict( + name='kpt-69', + id=69, + color=[255, 0, 0], + type='upper', + swap='kpt-76'), + 70: + dict( + name='kpt-70', + id=70, + color=[255, 0, 0], + type='upper', + swap='kpt-75'), + 71: + dict( + name='kpt-71', + id=71, + color=[255, 0, 0], + type='upper', + swap='kpt-82'), + 72: + dict( + name='kpt-72', + id=72, + color=[255, 0, 0], + type='upper', + swap='kpt-81'), + 73: + dict( + name='kpt-73', + id=73, + color=[255, 0, 0], + type='upper', + swap='kpt-80'), + 74: + dict( + name='kpt-74', + id=74, + color=[255, 0, 0], + type='upper', + swap='kpt-83'), + 75: + dict( + name='kpt-75', + id=75, + color=[255, 0, 0], + type='upper', + swap='kpt-70'), + 76: + dict( + name='kpt-76', + id=76, + color=[255, 0, 0], + type='upper', + swap='kpt-69'), + 77: + dict( + name='kpt-77', + id=77, + color=[255, 0, 0], + type='upper', + swap='kpt-68'), + 78: + dict( + name='kpt-78', + id=78, + color=[255, 0, 0], + type='upper', + swap='kpt-67'), + 79: + dict( + name='kpt-79', + id=79, + color=[255, 0, 0], + type='upper', + swap='kpt-66'), + 80: + dict( + name='kpt-80', + id=80, + color=[255, 0, 0], + type='upper', + swap='kpt-73'), + 81: + dict( + name='kpt-81', + id=81, + color=[255, 0, 0], + type='upper', + swap='kpt-72'), + 82: + dict( + name='kpt-82', + id=82, + color=[255, 0, 0], + type='upper', + swap='kpt-71'), + 83: + dict( + name='kpt-83', + id=83, + color=[255, 0, 0], + type='upper', + swap='kpt-74'), + 84: + dict( + name='kpt-84', + id=84, + color=[255, 0, 0], + type='lower', + swap='kpt-90'), + 85: + dict( + name='kpt-85', + id=85, + color=[255, 0, 0], + type='lower', + swap='kpt-89'), + 86: + dict( + name='kpt-86', + id=86, + color=[255, 0, 0], + type='lower', + swap='kpt-88'), + 87: + dict(name='kpt-87', id=87, color=[255, 0, 0], type='lower', swap=''), + 88: + dict( + name='kpt-88', + id=88, + color=[255, 0, 0], + type='lower', + swap='kpt-86'), + 89: + dict( + name='kpt-89', + id=89, + color=[255, 0, 0], + type='lower', + swap='kpt-85'), + 90: + dict( + name='kpt-90', + id=90, + color=[255, 0, 0], + type='lower', + swap='kpt-84'), + 91: + dict( + name='kpt-91', + id=91, + color=[255, 0, 0], + type='lower', + swap='kpt-95'), + 92: + dict( + name='kpt-92', + id=92, + color=[255, 0, 0], + type='lower', + swap='kpt-94'), + 93: + dict(name='kpt-93', id=93, color=[255, 0, 0], type='lower', swap=''), + 94: + dict( + name='kpt-94', + id=94, + color=[255, 0, 0], + type='lower', + swap='kpt-92'), + 95: + dict( + name='kpt-95', + id=95, + color=[255, 0, 0], + type='lower', + swap='kpt-91'), + 96: + dict( + name='kpt-96', + id=96, + color=[255, 0, 0], + type='lower', + swap='kpt-100'), + 97: + dict( + name='kpt-97', + id=97, + color=[255, 0, 0], + type='lower', + swap='kpt-99'), + 98: + dict(name='kpt-98', id=98, color=[255, 0, 0], type='lower', swap=''), + 99: + dict( + name='kpt-99', + id=99, + color=[255, 0, 0], + type='lower', + swap='kpt-97'), + 100: + dict( + name='kpt-100', + id=100, + color=[255, 0, 0], + type='lower', + swap='kpt-96'), + 101: + dict( + name='kpt-101', + id=101, + color=[255, 0, 0], + type='lower', + swap='kpt-103'), + 102: + dict(name='kpt-102', id=102, color=[255, 0, 0], type='lower', swap=''), + 103: + dict( + name='kpt-103', + id=103, + color=[255, 0, 0], + type='lower', + swap='kpt-101'), + 104: + dict( + name='kpt-104', + id=104, + color=[255, 0, 0], + type='upper', + swap='kpt-105'), + 105: + dict( + name='kpt-105', + id=105, + color=[255, 0, 0], + type='upper', + swap='kpt-104') + }, + skeleton_info={}, + joint_weights=[ + 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, + 0.8, 0.8, 0.8, 0.8, 0.8, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, + 2.0, 2.0, 2.0, 2.0, 1.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 1.0, + 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, + 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.0, 1.0 + ], + sigmas=[]) diff --git a/configs/animal_2d_keypoint/README.md b/configs/animal_2d_keypoint/README.md index f1e38cb6ba..efcc3841a5 100644 --- a/configs/animal_2d_keypoint/README.md +++ b/configs/animal_2d_keypoint/README.md @@ -9,7 +9,7 @@ Please follow [DATA Preparation](/docs/en/dataset_zoo/2d_animal_keypoint.md) to ## Demo -Please follow [DEMO](/demo/docs/2d_animal_demo.md) to generate fancy demos. +Please follow [DEMO](/demo/docs/en/2d_animal_demo.md) to generate fancy demos.
diff --git a/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose-m_8xb64-210e_ap10k-256x256.py b/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose-m_8xb64-210e_ap10k-256x256.py index 6d88b8cc08..0e8c007b31 100644 --- a/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose-m_8xb64-210e_ap10k-256x256.py +++ b/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose-m_8xb64-210e_ap10k-256x256.py @@ -24,7 +24,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -69,14 +68,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(8, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose_ap10k.md b/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose_ap10k.md index 6303a131da..4d035a3725 100644 --- a/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose_ap10k.md +++ b/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose_ap10k.md @@ -22,4 +22,4 @@ Results on AP-10K validation set | Arch | Input Size | AP | AP50 | AP75 | APM | APL | ckpt | log | | :----------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :------------: | :------------: | :-----------------------------------------: | :----------------------------------------: | -| [rtmpose-m](./rtmpose-m_8xb64-210e_ap10k-256x256.py) | 256x256 | 0.722 | 0.939 | 0.788 | 0.569 | 0.728 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-ap10k_pt-aic-coco_210e-256x256-7a041aa1_20230206.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-ap10k_pt-aic-coco_210e-256x256-7a041aa1_20230206.json) | +| [rtmpose-m](/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose-m_8xb64-210e_ap10k-256x256.py) | 256x256 | 0.722 | 0.939 | 0.788 | 0.569 | 0.728 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-ap10k_pt-aic-coco_210e-256x256-7a041aa1_20230206.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-ap10k_pt-aic-coco_210e-256x256-7a041aa1_20230206.json) | diff --git a/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose_ap10k.yml b/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose_ap10k.yml index f051bb4513..0441d9e65f 100644 --- a/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose_ap10k.yml +++ b/configs/animal_2d_keypoint/rtmpose/ap10k/rtmpose_ap10k.yml @@ -16,4 +16,4 @@ Models: AP (L): 0.728 AP (M): 0.569 Task: Animal 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-ap10k_pt-aic-coco_210e-256x256-7a041aa1_20230206.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-ap10k_pt-aic-coco_210e-256x256-7a041aa1_20230206.pth diff --git a/configs/animal_2d_keypoint/topdown_heatmap/README.md b/configs/animal_2d_keypoint/topdown_heatmap/README.md index b4f8e366ff..90a440dc28 100644 --- a/configs/animal_2d_keypoint/topdown_heatmap/README.md +++ b/configs/animal_2d_keypoint/topdown_heatmap/README.md @@ -52,3 +52,17 @@ Results on Grévy’s Zebra test set | ResNet-152 | 160x160 | 0.921 | 1.67 | [resnet_zebra.md](./zebra/resnet_zebra.md) | | ResNet-101 | 160x160 | 0.915 | 1.83 | [resnet_zebra.md](./zebra/resnet_zebra.md) | | ResNet-50 | 160x160 | 0.914 | 1.87 | [resnet_zebra.md](./zebra/resnet_zebra.md) | + +### Animal-Kingdom Dataset + +Results on AnimalKingdom test set + +| Model | Input Size | class | PCK(0.05) | Details and Download | +| :-------: | :--------: | :-----------: | :-------: | :---------------------------------------------------: | +| HRNet-w32 | 256x256 | P1 | 0.6323 | [hrnet_animalkingdom.md](./ak/hrnet_animalkingdom.md) | +| HRNet-w32 | 256x256 | P2 | 0.3741 | [hrnet_animalkingdom.md](./ak/hrnet_animalkingdom.md) | +| HRNet-w32 | 256x256 | P3_mammals | 0.571 | [hrnet_animalkingdom.md](./ak/hrnet_animalkingdom.md) | +| HRNet-w32 | 256x256 | P3_amphibians | 0.5358 | [hrnet_animalkingdom.md](./ak/hrnet_animalkingdom.md) | +| HRNet-w32 | 256x256 | P3_reptiles | 0.51 | [hrnet_animalkingdom.md](./ak/hrnet_animalkingdom.md) | +| HRNet-w32 | 256x256 | P3_birds | 0.7671 | [hrnet_animalkingdom.md](./ak/hrnet_animalkingdom.md) | +| HRNet-w32 | 256x256 | P3_fishes | 0.6406 | [hrnet_animalkingdom.md](./ak/hrnet_animalkingdom.md) | diff --git a/configs/animal_2d_keypoint/topdown_heatmap/ak/hrnet_animalkingdom.md b/configs/animal_2d_keypoint/topdown_heatmap/ak/hrnet_animalkingdom.md new file mode 100644 index 0000000000..f32fb49d90 --- /dev/null +++ b/configs/animal_2d_keypoint/topdown_heatmap/ak/hrnet_animalkingdom.md @@ -0,0 +1,47 @@ + + +
+HRNet (CVPR'2019) + +```bibtex +@inproceedings{sun2019deep, + title={Deep high-resolution representation learning for human pose estimation}, + author={Sun, Ke and Xiao, Bin and Liu, Dong and Wang, Jingdong}, + booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, + pages={5693--5703}, + year={2019} +} +``` + +
+ + + +
+AnimalKingdom (CVPR'2022) + +```bibtex +@InProceedings{ + Ng_2022_CVPR, + author = {Ng, Xun Long and Ong, Kian Eng and Zheng, Qichen and Ni, Yun and Yeo, Si Yong and Liu, Jun}, + title = {Animal Kingdom: A Large and Diverse Dataset for Animal Behavior Understanding}, + booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)}, + month = {June}, + year = {2022}, + pages = {19023-19034} + } +``` + +
+ +Results on AnimalKingdom validation set + +| Arch | Input Size | PCK(0.05) | Official Repo | Paper | ckpt | log | +| ------------------------------------------------------ | ---------- | --------- | ------------- | ------ | ------------------------------------------------------ | ------------------------------------------------------ | +| [P1_hrnet_w32](configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P1-256x256.py) | 256x256 | 0.6323 | 0.6342 | 0.6606 | [ckpt](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P1-256x256-08bf96cb_20230519.pth) | [log](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P1-256x256-08bf96cb_20230519.json) | +| [P2_hrnet_w32](configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P2-256x256.py) | 256x256 | 0.3741 | 0.3726 | 0.393 | [ckpt](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P2-256x256-2396cc58_20230519.pth) | [log](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P2-256x256-2396cc58_20230519.json) | +| [P3_mammals_hrnet_w32](configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_mammal-256x256.py) | 256x256 | 0.571 | 0.5719 | 0.6159 | [ckpt](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_mammal-256x256-e8aadf02_20230519.pth) | [log](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_mammal-256x256-e8aadf02_20230519.json) | +| [P3_amphibians_hrnet_w32](configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_amphibian-256x256.py) | 256x256 | 0.5358 | 0.5432 | 0.5674 | [ckpt](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_amphibian-256x256-845085f9_20230519.pth) | [log](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_amphibian-256x256-845085f9_20230519.json) | +| [P3_reptiles_hrnet_w32](configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_reptile-256x256.py) | 256x256 | 0.51 | 0.5 | 0.5606 | [ckpt](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_reptile-256x256-e8440c16_20230519.pth) | [log](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_reptile-256x256-e8440c16_20230519.json) | +| [P3_birds_hrnet_w32](configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_bird-256x256.py) | 256x256 | 0.7671 | 0.7636 | 0.7735 | [ckpt](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_bird-256x256-566feff5_20230519.pth) | [log](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_bird-256x256-566feff5_20230519.json) | +| [P3_fishes_hrnet_w32](configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_fish-256x256.py) | 256x256 | 0.6406 | 0.636 | 0.6825 | [ckpt](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_fish-256x256-76c3999f_20230519.pth) | [log](https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_fish-256x256-76c3999f_20230519.json) | diff --git a/configs/animal_2d_keypoint/topdown_heatmap/ak/hrnet_animalkingdom.yml b/configs/animal_2d_keypoint/topdown_heatmap/ak/hrnet_animalkingdom.yml new file mode 100644 index 0000000000..12f208a10b --- /dev/null +++ b/configs/animal_2d_keypoint/topdown_heatmap/ak/hrnet_animalkingdom.yml @@ -0,0 +1,86 @@ +Models: +- Config: configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P1-256x256.py + In Collection: HRNet + Metadata: + Architecture: &id001 + - HRNet + Training Data: AnimalKingdom_P1 + Name: td-hm_hrnet-w32_8xb32-300e_animalkingdom_P1-256x256 + Results: + - Dataset: AnimalKingdom + Metrics: + PCK: 0.6323 + Task: Animal 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P1-256x256-08bf96cb_20230519.pth +- Config: configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P2-256x256.py + In Collection: HRNet + Metadata: + Architecture: *id001 + Training Data: AnimalKingdom_P2 + Name: td-hm_hrnet-w32_8xb32-300e_animalkingdom_P2-256x256 + Results: + - Dataset: AnimalKingdom + Metrics: + PCK: 0.3741 + Task: Animal 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P2-256x256-2396cc58_20230519.pth +- Config: configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_amphibian-256x256.py + In Collection: HRNet + Metadata: + Architecture: *id001 + Training Data: AnimalKingdom_P3_amphibian + Name: td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_amphibian-256x256 + Results: + - Dataset: AnimalKingdom + Metrics: + PCK: 0.5358 + Task: Animal 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_amphibian-256x256-845085f9_20230519.pth +- Config: configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_bird-256x256.py + In Collection: HRNet + Metadata: + Architecture: *id001 + Training Data: AnimalKingdom_P3_bird + Name: td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_bird-256x256 + Results: + - Dataset: AnimalKingdom + Metrics: + PCK: 0.7671 + Task: Animal 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_bird-256x256-566feff5_20230519.pth +- Config: configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_fish-256x256.py + In Collection: HRNet + Metadata: + Architecture: *id001 + Training Data: AnimalKingdom_P3_fish + Name: td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_fish-256x256 + Results: + - Dataset: AnimalKingdom + Metrics: + PCK: 0.6406 + Task: Animal 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_fish-256x256-76c3999f_20230519.pth +- Config: configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_mammal-256x256.py + In Collection: HRNet + Metadata: + Architecture: *id001 + Training Data: AnimalKingdom_P3_mammal + Name: td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_mammal-256x256 + Results: + - Dataset: AnimalKingdom + Metrics: + PCK: 0.571 + Task: Animal 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_mammal-256x256-e8aadf02_20230519.pth +- Config: configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_reptile-256x256.py + In Collection: HRNet + Metadata: + Architecture: *id001 + Training Data: AnimalKingdom_P3_reptile + Name: td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_reptile-256x256 + Results: + - Dataset: AnimalKingdom + Metrics: + PCK: 0.51 + Task: Animal 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/animal_2d_keypoint/topdown_heatmap/animal_kingdom/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_reptile-256x256-e8440c16_20230519.pth diff --git a/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P1-256x256.py b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P1-256x256.py new file mode 100644 index 0000000000..0e7eb0136e --- /dev/null +++ b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P1-256x256.py @@ -0,0 +1,146 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=300, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='AdamW', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict(checkpoint=dict(save_best='PCK', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(256, 256), heatmap_size=(64, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='HRNet', + in_channels=3, + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'pretrain_models/hrnet_w32-36af842e.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=32, + out_channels=23, + deconv_out_channels=None, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'AnimalKingdomDataset' +data_mode = 'topdown' +data_root = 'data/ak/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P1/train.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=24, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P1/test.json', + data_prefix=dict(img='images/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [dict(type='PCKAccuracy', thr=0.05), dict(type='AUC')] +test_evaluator = val_evaluator diff --git a/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P2-256x256.py b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P2-256x256.py new file mode 100644 index 0000000000..f42057f8aa --- /dev/null +++ b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P2-256x256.py @@ -0,0 +1,146 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=300, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='AdamW', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict(checkpoint=dict(save_best='PCK', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(256, 256), heatmap_size=(64, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='HRNet', + in_channels=3, + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'pretrain_models/hrnet_w32-36af842e.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=32, + out_channels=23, + deconv_out_channels=None, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'AnimalKingdomDataset' +data_mode = 'topdown' +data_root = 'data/ak/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P2/train.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=24, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P2/test.json', + data_prefix=dict(img='images/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [dict(type='PCKAccuracy', thr=0.05), dict(type='AUC')] +test_evaluator = val_evaluator diff --git a/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_amphibian-256x256.py b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_amphibian-256x256.py new file mode 100644 index 0000000000..5a83e7a97b --- /dev/null +++ b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_amphibian-256x256.py @@ -0,0 +1,146 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=300, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='AdamW', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict(checkpoint=dict(save_best='PCK', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(256, 256), heatmap_size=(64, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='HRNet', + in_channels=3, + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'pretrain_models/hrnet_w32-36af842e.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=32, + out_channels=23, + deconv_out_channels=None, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'AnimalKingdomDataset' +data_mode = 'topdown' +data_root = 'data/ak/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P3_amphibian/train.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=24, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P3_amphibian/test.json', + data_prefix=dict(img='images/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [dict(type='PCKAccuracy', thr=0.05), dict(type='AUC')] +test_evaluator = val_evaluator diff --git a/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_bird-256x256.py b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_bird-256x256.py new file mode 100644 index 0000000000..ca3c91af61 --- /dev/null +++ b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_bird-256x256.py @@ -0,0 +1,146 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=300, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='AdamW', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict(checkpoint=dict(save_best='PCK', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(256, 256), heatmap_size=(64, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='HRNet', + in_channels=3, + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'pretrain_models/hrnet_w32-36af842e.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=32, + out_channels=23, + deconv_out_channels=None, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'AnimalKingdomDataset' +data_mode = 'topdown' +data_root = 'data/ak/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P3_bird/train.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=24, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P3_bird/test.json', + data_prefix=dict(img='images/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [dict(type='PCKAccuracy', thr=0.05), dict(type='AUC')] +test_evaluator = val_evaluator diff --git a/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_fish-256x256.py b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_fish-256x256.py new file mode 100644 index 0000000000..3923f30d10 --- /dev/null +++ b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_fish-256x256.py @@ -0,0 +1,146 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=300, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='AdamW', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict(checkpoint=dict(save_best='PCK', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(256, 256), heatmap_size=(64, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='HRNet', + in_channels=3, + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'pretrain_models/hrnet_w32-36af842e.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=32, + out_channels=23, + deconv_out_channels=None, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'AnimalKingdomDataset' +data_mode = 'topdown' +data_root = 'data/ak/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P3_fish/train.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=24, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P3_fish/test.json', + data_prefix=dict(img='images/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [dict(type='PCKAccuracy', thr=0.05), dict(type='AUC')] +test_evaluator = val_evaluator diff --git a/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_mammal-256x256.py b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_mammal-256x256.py new file mode 100644 index 0000000000..d061c4b6fb --- /dev/null +++ b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_mammal-256x256.py @@ -0,0 +1,146 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=300, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='AdamW', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict(checkpoint=dict(save_best='PCK', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(256, 256), heatmap_size=(64, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='HRNet', + in_channels=3, + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'pretrain_models/hrnet_w32-36af842e.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=32, + out_channels=23, + deconv_out_channels=None, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'AnimalKingdomDataset' +data_mode = 'topdown' +data_root = 'data/ak/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P3_mammal/train.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=24, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P3_mammal/test.json', + data_prefix=dict(img='images/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [dict(type='PCKAccuracy', thr=0.05), dict(type='AUC')] +test_evaluator = val_evaluator diff --git a/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_reptile-256x256.py b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_reptile-256x256.py new file mode 100644 index 0000000000..b06a49936b --- /dev/null +++ b/configs/animal_2d_keypoint/topdown_heatmap/ak/td-hm_hrnet-w32_8xb32-300e_animalkingdom_P3_reptile-256x256.py @@ -0,0 +1,146 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=300, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='AdamW', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict(checkpoint=dict(save_best='PCK', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(256, 256), heatmap_size=(64, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='HRNet', + in_channels=3, + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'pretrain_models/hrnet_w32-36af842e.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=32, + out_channels=23, + deconv_out_channels=None, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'AnimalKingdomDataset' +data_mode = 'topdown' +data_root = 'data/ak/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P3_reptile/train.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=24, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/ak_P3_reptile/test.json', + data_prefix=dict(img='images/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [dict(type='PCKAccuracy', thr=0.05), dict(type='AUC')] +test_evaluator = val_evaluator diff --git a/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext-m_udp_8xb64-210e_ap10k-256x256.py b/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext-m_udp_8xb64-210e_ap10k-256x256.py index fa3139a71a..844d17df4e 100644 --- a/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext-m_udp_8xb64-210e_ap10k-256x256.py +++ b/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext-m_udp_8xb64-210e_ap10k-256x256.py @@ -73,7 +73,7 @@ loss=dict(type='KeypointMSELoss', use_target_weight=True), decoder=codec), test_cfg=dict( - flip_test=False, + flip_test=True, flip_mode='heatmap', shift_heatmap=False, )) diff --git a/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext_udp_ap10k.md b/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext_udp_ap10k.md index 4ba6b39b3e..fb10359685 100644 --- a/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext_udp_ap10k.md +++ b/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext_udp_ap10k.md @@ -55,4 +55,4 @@ Results on AP-10K validation set | Arch | Input Size | AP | AP50 | AP75 | APM | APL | ckpt | log | | :----------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :------------: | :------------: | :-----------------------------------------: | :----------------------------------------: | -| [pose_cspnext_m](/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext-m_udp_8xb64-210e_ap10k-256x256.py) | 256x256 | 0.703 | 0.944 | 0.776 | 0.513 | 0.710 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-ap10k_pt-in1k_210e-256x256-1f2d947a_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-ap10k_pt-in1k_210e-256x256-1f2d947a_20230123.json) | +| [pose_cspnext_m](/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext-m_udp_8xb64-210e_ap10k-256x256.py) | 256x256 | 0.703 | 0.944 | 0.776 | 0.513 | 0.710 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-ap10k_pt-in1k_210e-256x256-1f2d947a_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-ap10k_pt-in1k_210e-256x256-1f2d947a_20230123.json) | diff --git a/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext_udp_ap10k.yml b/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext_udp_ap10k.yml index fed9bdf116..8fedc88374 100644 --- a/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext_udp_ap10k.yml +++ b/configs/animal_2d_keypoint/topdown_heatmap/ap10k/cspnext_udp_ap10k.yml @@ -16,4 +16,4 @@ Models: AP (L): 0.71 AP (M): 0.513 Task: Animal 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-ap10k_pt-in1k_210e-256x256-1f2d947a_20230123.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-ap10k_pt-in1k_210e-256x256-1f2d947a_20230123.pth diff --git a/configs/body_2d_keypoint/README.md b/configs/body_2d_keypoint/README.md index 468f960754..d005d3fed7 100644 --- a/configs/body_2d_keypoint/README.md +++ b/configs/body_2d_keypoint/README.md @@ -14,7 +14,7 @@ Please follow [DATA Preparation](/docs/en/dataset_zoo/2d_body_keypoint.md) to pr ## Demo -Please follow [Demo](/demo/docs/2d_human_pose_demo.md#2d-human-pose-demo) to run demos. +Please follow [Demo](/demo/docs/en/2d_human_pose_demo.md#2d-human-pose-demo) to run demos.

diff --git a/configs/body_2d_keypoint/dekr/crowdpose/hrnet_crowdpose.md b/configs/body_2d_keypoint/dekr/crowdpose/hrnet_crowdpose.md index ea58d95b7f..0bbedbe696 100644 --- a/configs/body_2d_keypoint/dekr/crowdpose/hrnet_crowdpose.md +++ b/configs/body_2d_keypoint/dekr/crowdpose/hrnet_crowdpose.md @@ -52,5 +52,5 @@ Results on CrowdPose test without multi-scale test | Arch | Input Size | AP | AP50 | AP75 | AP (E) | AP (M) | AP (H) | ckpt | log | | :--------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :----: | :----: | :----: | :--------------------------------------------: | :-------------------------------------------: | -| [HRNet-w32](/configs/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w32_8xb10-300e_crowdpose-512x512.py) | 512x512 | 0.663 | 0.857 | 0.714 | 0.740 | 0.671 | 0.576 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w32_8xb10-140e_crowdpose-512x512_147bae97-20221228.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w32_8xb10-140e_crowdpose-512x512_20221228.json) | +| [HRNet-w32](/configs/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w32_8xb10-300e_crowdpose-512x512.py) | 512x512 | 0.663 | 0.857 | 0.714 | 0.740 | 0.671 | 0.576 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w32_8xb10-300e_crowdpose-512x512_147bae97-20221228.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w32_8xb10-300e_crowdpose-512x512_20221228.json) | | [HRNet-w48](/configs/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w48_8xb5-300e_crowdpose-640x640.py) | 640x640 | 0.679 | 0.869 | 0.731 | 0.753 | 0.688 | 0.593 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w48_8xb5-300e_crowdpose-640x640_4ea6031e-20230128.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w48_8xb5-300e_crowdpose-640x640_20230128.json) | diff --git a/configs/body_2d_keypoint/dekr/crowdpose/hrnet_crowdpose.yml b/configs/body_2d_keypoint/dekr/crowdpose/hrnet_crowdpose.yml index 02312e8cba..5bbb7f4b25 100644 --- a/configs/body_2d_keypoint/dekr/crowdpose/hrnet_crowdpose.yml +++ b/configs/body_2d_keypoint/dekr/crowdpose/hrnet_crowdpose.yml @@ -17,7 +17,7 @@ Models: AP (M): 0.671 AP (L): 0.576 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w32_8xb10-140e_crowdpose-512x512_147bae97-20221228.pth + Weights: https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w32_8xb10-300e_crowdpose-512x512_147bae97-20221228.pth - Config: configs/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w48_8xb5-300e_crowdpose-640x640.py In Collection: DEKR Metadata: @@ -34,4 +34,4 @@ Models: AP (M): 0.688 AP (L): 0.593 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/bottom_up/dekr/hrnet_w48_crowdpose_640x640-ef6b6040_20220930.pth + Weights: https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/dekr/crowdpose/dekr_hrnet-w48_8xb5-300e_crowdpose-640x640_4ea6031e-20230128.pth diff --git a/configs/body_2d_keypoint/integral_regression/coco/resnet_debias_coco.md b/configs/body_2d_keypoint/integral_regression/coco/resnet_debias_coco.md index 0820fdd296..40e3660e4f 100644 --- a/configs/body_2d_keypoint/integral_regression/coco/resnet_debias_coco.md +++ b/configs/body_2d_keypoint/integral_regression/coco/resnet_debias_coco.md @@ -54,4 +54,4 @@ Results on COCO val2017 with detector having human AP of 56.4 on COCO val2017 da | Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | | :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | -| [debias-ipr_resnet_50](/configs/body_2d_keypoint/integral_regression/coco/ipr_res50_debias--8xb64-210e_coco-256x256.py) | 256x256 | 0.675 | 0.872 | 0.740 | 0.765 | 0.928 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/integral_regression/coco/ipr_res50_debias-8xb64-210e_coco-256x256-055a7699_20220913.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/integral_regression/coco/ipr_res50_debias-8xb64-210e_coco-256x256-055a7699_20220913.log.json) | +| [debias-ipr_resnet_50](/configs/body_2d_keypoint/integral_regression/coco/ipr_res50_debias-8xb64-210e_coco-256x256.py) | 256x256 | 0.675 | 0.872 | 0.740 | 0.765 | 0.928 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/integral_regression/coco/ipr_res50_debias-8xb64-210e_coco-256x256-055a7699_20220913.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/integral_regression/coco/ipr_res50_debias-8xb64-210e_coco-256x256-055a7699_20220913.log.json) | diff --git a/configs/body_2d_keypoint/rtmpose/README.md b/configs/body_2d_keypoint/rtmpose/README.md index 3037974917..38fd938376 100644 --- a/configs/body_2d_keypoint/rtmpose/README.md +++ b/configs/body_2d_keypoint/rtmpose/README.md @@ -37,3 +37,21 @@ Results on CrowdPose test with [YOLOv3](https://github.com/eriklindernoren/PyTor | Model | Input Size | AP | AR | Details and Download | | :-------: | :--------: | :---: | :---: | :------------------------------------------------------: | | RTMPose-m | 256x192 | 0.706 | 0.788 | [rtmpose_crowdpose.md](./crowdpose/rtmpose_crowdpose.md) | + +### Human-Art Dataset + +Results on Human-Art validation dataset with detector having human AP of 56.2 on Human-Art validation dataset + +| Model | Input Size | AP | AR | Details and Download | +| :-------: | :--------: | :---: | :---: | :---------------------------------------------------: | +| RTMPose-s | 256x192 | 0.311 | 0.381 | [rtmpose_humanart.md](./humanart/rtmpose_humanart.md) | +| RTMPose-m | 256x192 | 0.355 | 0.417 | [rtmpose_humanart.md](./humanart/rtmpose_humanart.md) | +| RTMPose-l | 256x192 | 0.378 | 0.442 | [rtmpose_humanart.md](./humanart/rtmpose_humanart.md) | + +Results on Human-Art validation dataset with ground-truth bounding-box + +| Model | Input Size | AP | AR | Details and Download | +| :-------: | :--------: | :---: | :---: | :---------------------------------------------------: | +| RTMPose-s | 256x192 | 0.698 | 0.732 | [rtmpose_humanart.md](./humanart/rtmpose_humanart.md) | +| RTMPose-m | 256x192 | 0.728 | 0.759 | [rtmpose_humanart.md](./humanart/rtmpose_humanart.md) | +| RTMPose-l | 256x192 | 0.753 | 0.783 | [rtmpose_humanart.md](./humanart/rtmpose_humanart.md) | diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb256-420e_body8-256x192.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb256-420e_body8-256x192.py new file mode 100644 index 0000000000..1cf3380435 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb256-420e_body8-256x192.py @@ -0,0 +1,553 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +max_epochs = 420 +stage2_num_epochs = 20 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + # use cosine lr from 210 to 420 epoch + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(192, 256), + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=1., + widen_factor=1., + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-l_udp-body7_210e-256x192-5e9558ef_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=1024, + out_channels=17, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# mapping +aic_coco = [ + (0, 6), + (1, 8), + (2, 10), + (3, 5), + (4, 7), + (5, 9), + (6, 12), + (7, 14), + (8, 16), + (9, 11), + (10, 13), + (11, 15), +] + +crowdpose_coco = [ + (0, 5), + (1, 6), + (2, 7), + (3, 8), + (4, 9), + (5, 10), + (6, 11), + (7, 12), + (8, 13), + (9, 14), + (10, 15), + (11, 16), +] + +mpii_coco = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_coco = [ + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_coco = [ + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +ochuman_coco = [ + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +posetrack_coco = [ + (0, 0), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_train2017.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=aic_coco) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=crowdpose_coco) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=mpii_coco) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=jhmdb_coco) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=halpe_coco) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=posetrack_coco) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=aic_coco) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=crowdpose_coco) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=mpii_coco) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=jhmdb_coco) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=halpe_coco) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=ochuman_coco) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=posetrack_coco) + ], +) + +val_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + bbox_file=f'{data_root}coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', + data_prefix=dict(img='detection/coco/val2017/'), + test_mode=True, + pipeline=val_pipeline, + )) + +test_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) +# default_hooks = dict( +# checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'coco/annotations/person_keypoints_val2017.json') +test_evaluator = [ + dict(type='PCKAccuracy', thr=0.1), + dict(type='AUC'), + dict(type='EPE'), +] diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb256-420e_body8-384x288.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb256-420e_body8-384x288.py new file mode 100644 index 0000000000..19b3c8afb6 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb256-420e_body8-384x288.py @@ -0,0 +1,553 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +max_epochs = 420 +stage2_num_epochs = 20 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + # use cosine lr from 210 to 420 epoch + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(288, 384), + sigma=(6., 6.93), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=1., + widen_factor=1., + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-l_udp-body7_210e-384x288-b15bc30d_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=1024, + out_channels=17, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# mapping +aic_coco = [ + (0, 6), + (1, 8), + (2, 10), + (3, 5), + (4, 7), + (5, 9), + (6, 12), + (7, 14), + (8, 16), + (9, 11), + (10, 13), + (11, 15), +] + +crowdpose_coco = [ + (0, 5), + (1, 6), + (2, 7), + (3, 8), + (4, 9), + (5, 10), + (6, 11), + (7, 12), + (8, 13), + (9, 14), + (10, 15), + (11, 16), +] + +mpii_coco = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_coco = [ + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_coco = [ + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +ochuman_coco = [ + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +posetrack_coco = [ + (0, 0), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_train2017.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=aic_coco) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=crowdpose_coco) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=mpii_coco) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=jhmdb_coco) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=halpe_coco) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=posetrack_coco) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=aic_coco) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=crowdpose_coco) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=mpii_coco) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=jhmdb_coco) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=halpe_coco) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=ochuman_coco) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=posetrack_coco) + ], +) + +val_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + bbox_file=f'{data_root}coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', + data_prefix=dict(img='detection/coco/val2017/'), + test_mode=True, + pipeline=val_pipeline, + )) + +test_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) +# default_hooks = dict( +# checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'coco/annotations/person_keypoints_val2017.json') +test_evaluator = [ + dict(type='PCKAccuracy', thr=0.1), + dict(type='AUC'), + dict(type='EPE'), +] diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb512-700e_body8-halpe26-256x192.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb512-700e_body8-halpe26-256x192.py new file mode 100644 index 0000000000..293a5f07ea --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb512-700e_body8-halpe26-256x192.py @@ -0,0 +1,535 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (192, 256) + +# runtime +max_epochs = 700 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 512 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=1., + widen_factor=1., + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-256x192-4dba18fc_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=1024, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=5, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=5, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb512-700e_body8-halpe26-384x288.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb512-700e_body8-halpe26-384x288.py new file mode 100644 index 0000000000..0aa16f3db4 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb512-700e_body8-halpe26-384x288.py @@ -0,0 +1,535 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (288, 384) + +# runtime +max_epochs = 700 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 512 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(6., 6.93), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=1., + widen_factor=1., + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-384x288-3f5a1437_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=1024, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb256-420e_body8-256x192.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb256-420e_body8-256x192.py new file mode 100644 index 0000000000..be462bfddf --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb256-420e_body8-256x192.py @@ -0,0 +1,553 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +max_epochs = 420 +stage2_num_epochs = 20 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + # use cosine lr from 210 to 420 epoch + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(192, 256), + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.67, + widen_factor=0.75, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-m_udp-body7_210e-256x192-e0c9327b_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=768, + out_channels=17, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0.0, + drop_path=0.0, + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True, )) + +# base dataset settings +dataset_type = 'CocoDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# mapping +aic_coco = [ + (0, 6), + (1, 8), + (2, 10), + (3, 5), + (4, 7), + (5, 9), + (6, 12), + (7, 14), + (8, 16), + (9, 11), + (10, 13), + (11, 15), +] + +crowdpose_coco = [ + (0, 5), + (1, 6), + (2, 7), + (3, 8), + (4, 9), + (5, 10), + (6, 11), + (7, 12), + (8, 13), + (9, 14), + (10, 15), + (11, 16), +] + +mpii_coco = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_coco = [ + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_coco = [ + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +ochuman_coco = [ + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +posetrack_coco = [ + (0, 0), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_train2017.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=aic_coco) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=crowdpose_coco) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=mpii_coco) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=jhmdb_coco) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=halpe_coco) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=posetrack_coco) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=aic_coco) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=crowdpose_coco) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=mpii_coco) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=jhmdb_coco) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=halpe_coco) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=ochuman_coco) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=posetrack_coco) + ], +) + +val_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + bbox_file=f'{data_root}coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', + data_prefix=dict(img='detection/coco/val2017/'), + test_mode=True, + pipeline=val_pipeline, + )) + +test_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) +# default_hooks = dict( +# checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'coco/annotations/person_keypoints_val2017.json') +test_evaluator = [ + dict(type='PCKAccuracy', thr=0.1), + dict(type='AUC'), + dict(type='EPE') +] diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb256-420e_body8-384x288.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb256-420e_body8-384x288.py new file mode 100644 index 0000000000..64cfc8a604 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb256-420e_body8-384x288.py @@ -0,0 +1,553 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +max_epochs = 420 +stage2_num_epochs = 20 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + # use cosine lr from 210 to 420 epoch + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(288, 384), + sigma=(6., 6.93), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.67, + widen_factor=0.75, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-m_udp-body7_210e-384x288-b9bc2b57_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=768, + out_channels=17, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0.0, + drop_path=0.0, + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True, )) + +# base dataset settings +dataset_type = 'CocoDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# mapping +aic_coco = [ + (0, 6), + (1, 8), + (2, 10), + (3, 5), + (4, 7), + (5, 9), + (6, 12), + (7, 14), + (8, 16), + (9, 11), + (10, 13), + (11, 15), +] + +crowdpose_coco = [ + (0, 5), + (1, 6), + (2, 7), + (3, 8), + (4, 9), + (5, 10), + (6, 11), + (7, 12), + (8, 13), + (9, 14), + (10, 15), + (11, 16), +] + +mpii_coco = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_coco = [ + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_coco = [ + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +ochuman_coco = [ + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +posetrack_coco = [ + (0, 0), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_train2017.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=aic_coco) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=crowdpose_coco) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=mpii_coco) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=jhmdb_coco) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=halpe_coco) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=posetrack_coco) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=aic_coco) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=crowdpose_coco) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=mpii_coco) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=jhmdb_coco) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=halpe_coco) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=ochuman_coco) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=posetrack_coco) + ], +) + +val_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + bbox_file=f'{data_root}coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', + data_prefix=dict(img='detection/coco/val2017/'), + test_mode=True, + pipeline=val_pipeline, + )) + +test_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) +# default_hooks = dict( +# checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'coco/annotations/person_keypoints_val2017.json') +test_evaluator = [ + dict(type='PCKAccuracy', thr=0.1), + dict(type='AUC'), + dict(type='EPE') +] diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb512-700e_body8-halpe26-256x192.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb512-700e_body8-halpe26-256x192.py new file mode 100644 index 0000000000..e694dd27d9 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb512-700e_body8-halpe26-256x192.py @@ -0,0 +1,529 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (192, 256) + +# runtime +max_epochs = 700 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 512 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.67, + widen_factor=0.75, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/rtmpose-m_simcc-body7_pt-body7_420e-256x192-e48f03d0_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=768, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb512-700e_body8-halpe26-384x288.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb512-700e_body8-halpe26-384x288.py new file mode 100644 index 0000000000..5ee967a309 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb512-700e_body8-halpe26-384x288.py @@ -0,0 +1,542 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (288, 384) + +# runtime +max_epochs = 700 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 512 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(6., 6.93), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.67, + widen_factor=0.75, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/rtmpose-m_simcc-body7_pt-body7_420e-384x288-65e718c4_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=768, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +# backend_args = dict(backend='local') +backend_args = dict( + backend='petrel', + path_mapping=dict({ + f'{data_root}': 's3://openmmlab/datasets/', + f'{data_root}': 's3://openmmlab/datasets/' + })) + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +# default_hooks = dict( +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-s_8xb1024-700e_body8-halpe26-256x192.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-s_8xb1024-700e_body8-halpe26-256x192.py new file mode 100644 index 0000000000..05e6ec0980 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-s_8xb1024-700e_body8-halpe26-256x192.py @@ -0,0 +1,535 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (192, 256) + +# runtime +max_epochs = 700 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 1024 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.0), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.33, + widen_factor=0.5, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/rtmpose-s_simcc-body7_pt-body7_420e-256x192-acd4a1ef_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=512, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.6, 1.4], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.6, 1.4], + rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-s_8xb256-420e_body8-256x192.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-s_8xb256-420e_body8-256x192.py new file mode 100644 index 0000000000..7d0a697751 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-s_8xb256-420e_body8-256x192.py @@ -0,0 +1,553 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +max_epochs = 420 +stage2_num_epochs = 20 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.0), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + # use cosine lr from 210 to 420 epoch + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(192, 256), + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.33, + widen_factor=0.5, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-s_udp-body7_210e-256x192-8c9ccbdb_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=512, + out_channels=17, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.6, 1.4], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# mapping +aic_coco = [ + (0, 6), + (1, 8), + (2, 10), + (3, 5), + (4, 7), + (5, 9), + (6, 12), + (7, 14), + (8, 16), + (9, 11), + (10, 13), + (11, 15), +] + +crowdpose_coco = [ + (0, 5), + (1, 6), + (2, 7), + (3, 8), + (4, 9), + (5, 10), + (6, 11), + (7, 12), + (8, 13), + (9, 14), + (10, 15), + (11, 16), +] + +mpii_coco = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_coco = [ + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_coco = [ + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +ochuman_coco = [ + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +posetrack_coco = [ + (0, 0), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_train2017.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=aic_coco) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=crowdpose_coco) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=mpii_coco) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=jhmdb_coco) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=halpe_coco) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=posetrack_coco) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=aic_coco) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=crowdpose_coco) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=mpii_coco) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=jhmdb_coco) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=halpe_coco) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=ochuman_coco) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=posetrack_coco) + ], +) + +val_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + bbox_file=f'{data_root}coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', + data_prefix=dict(img='detection/coco/val2017/'), + test_mode=True, + pipeline=val_pipeline, + )) + +test_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) +# default_hooks = dict( +# checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'coco/annotations/person_keypoints_val2017.json') +test_evaluator = [ + dict(type='PCKAccuracy', thr=0.1), + dict(type='AUC'), + dict(type='EPE') +] diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-t_8xb1024-700e_body8-halpe26-256x192.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-t_8xb1024-700e_body8-halpe26-256x192.py new file mode 100644 index 0000000000..8d70bd27ae --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-t_8xb1024-700e_body8-halpe26-256x192.py @@ -0,0 +1,536 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (192, 256) + +# runtime +max_epochs = 700 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 1024 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.167, + widen_factor=0.375, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-tiny_udp-body7_210e-256x192-a3775292_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=384, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.6, 1.4], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.6, 1.4], + rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + # dict( + # type='EMAHook', + # ema_type='ExpMomentumEMA', + # momentum=0.0002, + # update_buffers=True, + # priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-t_8xb256-420e_body8-256x192.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-t_8xb256-420e_body8-256x192.py new file mode 100644 index 0000000000..bdc7f80a2b --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-t_8xb256-420e_body8-256x192.py @@ -0,0 +1,554 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +max_epochs = 420 +stage2_num_epochs = 20 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + # use cosine lr from 210 to 420 epoch + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(192, 256), + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.167, + widen_factor=0.375, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-tiny_udp-body7_210e-256x192-a3775292_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=384, + out_channels=17, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.6, 1.4], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# mapping +aic_coco = [ + (0, 6), + (1, 8), + (2, 10), + (3, 5), + (4, 7), + (5, 9), + (6, 12), + (7, 14), + (8, 16), + (9, 11), + (10, 13), + (11, 15), +] + +crowdpose_coco = [ + (0, 5), + (1, 6), + (2, 7), + (3, 8), + (4, 9), + (5, 10), + (6, 11), + (7, 12), + (8, 13), + (9, 14), + (10, 15), + (11, 16), +] + +mpii_coco = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_coco = [ + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_coco = [ + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +ochuman_coco = [ + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +posetrack_coco = [ + (0, 0), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_train2017.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=aic_coco) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=crowdpose_coco) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=mpii_coco) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=jhmdb_coco) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=halpe_coco) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=posetrack_coco) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=aic_coco) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=crowdpose_coco) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=mpii_coco) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=jhmdb_coco) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=halpe_coco) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict(type='KeypointConverter', num_keypoints=17, mapping=ochuman_coco) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=17, mapping=posetrack_coco) + ], +) + +val_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + bbox_file=f'{data_root}coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', + data_prefix=dict(img='detection/coco/val2017/'), + test_mode=True, + pipeline=val_pipeline, + )) + +test_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) +# default_hooks = dict( +# checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + # dict( + # type='EMAHook', + # ema_type='ExpMomentumEMA', + # momentum=0.0002, + # update_buffers=True, + # priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'coco/annotations/person_keypoints_val2017.json') + +test_evaluator = [ + dict(type='PCKAccuracy', thr=0.1), + dict(type='AUC'), + dict(type='EPE') +] diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose-x_8xb256-700e_body8-halpe26-384x288.py b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-x_8xb256-700e_body8-halpe26-384x288.py new file mode 100644 index 0000000000..e50aa42f0e --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose-x_8xb256-700e_body8-halpe26-384x288.py @@ -0,0 +1,535 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (288, 384) + +# runtime +max_epochs = 700 +stage2_num_epochs = 20 +base_lr = 4e-3 +train_batch_size = 256 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(6., 6.93), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=1.33, + widen_factor=1.25, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-x_udp-body7_210e-384x288-d28b58e6_20230529.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=1280, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose_body8-coco.md b/configs/body_2d_keypoint/rtmpose/body8/rtmpose_body8-coco.md new file mode 100644 index 0000000000..5355a7f35b --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose_body8-coco.md @@ -0,0 +1,76 @@ + + +
+RTMPose (arXiv'2023) + +```bibtex +@misc{https://doi.org/10.48550/arxiv.2303.07399, + doi = {10.48550/ARXIV.2303.07399}, + url = {https://arxiv.org/abs/2303.07399}, + author = {Jiang, Tao and Lu, Peng and Zhang, Li and Ma, Ningsheng and Han, Rui and Lyu, Chengqi and Li, Yining and Chen, Kai}, + keywords = {Computer Vision and Pattern Recognition (cs.CV), FOS: Computer and information sciences, FOS: Computer and information sciences}, + title = {RTMPose: Real-Time Multi-Person Pose Estimation based on MMPose}, + publisher = {arXiv}, + year = {2023}, + copyright = {Creative Commons Attribution 4.0 International} +} + +``` + +
+ + + +
+RTMDet (arXiv'2022) + +```bibtex +@misc{lyu2022rtmdet, + title={RTMDet: An Empirical Study of Designing Real-Time Object Detectors}, + author={Chengqi Lyu and Wenwei Zhang and Haian Huang and Yue Zhou and Yudong Wang and Yanyi Liu and Shilong Zhang and Kai Chen}, + year={2022}, + eprint={2212.07784}, + archivePrefix={arXiv}, + primaryClass={cs.CV} +} +``` + +
+ + + +
+COCO (ECCV'2014) + +```bibtex +@inproceedings{lin2014microsoft, + title={Microsoft coco: Common objects in context}, + author={Lin, Tsung-Yi and Maire, Michael and Belongie, Serge and Hays, James and Perona, Pietro and Ramanan, Deva and Doll{\'a}r, Piotr and Zitnick, C Lawrence}, + booktitle={European conference on computer vision}, + pages={740--755}, + year={2014}, + organization={Springer} +} +``` + +
+ +- Results on COCO val2017 with detector having human AP of 56.4 on COCO val2017 dataset. +- `*` denotes model trained on 7 public datasets: + - [AI Challenger](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#aic) + - [MS COCO](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#coco) + - [CrowdPose](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#crowdpose) + - [MPII](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#mpii) + - [sub-JHMDB](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#sub-jhmdb-dataset) + - [Halpe](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_wholebody_keypoint.html#halpe) + - [PoseTrack18](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#posetrack18) +- `Body8` denotes the addition of the [OCHuman](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#ochuman) dataset, in addition to the 7 datasets mentioned above, for evaluation. + +| Config | Input Size | AP
(COCO) | PCK@0.1
(Body8) | AUC
(Body8) | EPE
(Body8) | Params(M) | FLOPS(G) | Download | +| :--------------------------------------------: | :--------: | :---------------: | :---------------------: | :-----------------: | :-----------------: | :-------: | :------: | :-----------------------------------------------: | +| [RTMPose-t\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-t_8xb256-420e_body8-256x192.py) | 256x192 | 65.9 | 91.44 | 63.18 | 19.45 | 3.34 | 0.36 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_simcc-body7_pt-body7_420e-256x192-026a1439_20230504.pth) | +| [RTMPose-s\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-s_8xb256-420e_body8-256x192.py) | 256x192 | 69.7 | 92.45 | 65.15 | 17.85 | 5.47 | 0.68 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-body7_pt-body7_420e-256x192-acd4a1ef_20230504.pth) | +| [RTMPose-m\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb256-420e_body8-256x192.py) | 256x192 | 74.9 | 94.25 | 68.59 | 15.12 | 13.59 | 1.93 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7_420e-256x192-e48f03d0_20230504.pth) | +| [RTMPose-l\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb256-420e_body8-256x192.py) | 256x192 | 76.7 | 95.08 | 70.14 | 13.79 | 27.66 | 4.16 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-256x192-4dba18fc_20230504.pth) | +| [RTMPose-m\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb256-420e_body8-384x288.py) | 384x288 | 76.6 | 94.64 | 70.38 | 13.98 | 13.72 | 4.33 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7_420e-384x288-65e718c4_20230504.pth) | +| [RTMPose-l\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb256-420e_body8-384x288.py) | 384x288 | 78.3 | 95.36 | 71.58 | 13.08 | 27.79 | 9.35 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-384x288-3f5a1437_20230504.pth) | diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose_body8-coco.yml b/configs/body_2d_keypoint/rtmpose/body8/rtmpose_body8-coco.yml new file mode 100644 index 0000000000..9299eccb77 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose_body8-coco.yml @@ -0,0 +1,93 @@ +Collections: +- Name: RTMPose + Paper: + Title: "RTMPose: Real-Time Multi-Person Pose Estimation based on MMPose" + URL: https://arxiv.org/abs/2303.07399 + README: https://github.com/open-mmlab/mmpose/blob/main/projects/rtmpose/README.md +Models: +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-t_8xb256-420e_body8-256x192.py + In Collection: RTMPose + Metadata: + Architecture: &id001 + - RTMPose + Training Data: &id002 + - AI Challenger + - COCO + - CrowdPose + - MPII + - sub-JHMDB + - Halpe + - PoseTrack18 + Name: rtmpose-t_8xb256-420e_body8-256x192 + Results: + - Dataset: Body8 + Metrics: + AP: 0.659 + Mean@0.1: 0.914 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_simcc-body7_pt-body7_420e-256x192-026a1439_20230504.pth +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-s_8xb256-420e_body8-256x192.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-s_8xb256-420e_body8-256x192 + Results: + - Dataset: Body8 + Metrics: + AP: 0.697 + Mean@0.1: 0.925 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-body7_pt-body7_420e-256x192-acd4a1ef_20230504.pth +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb256-420e_body8-256x192.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-m_8xb256-420e_body8-256x192 + Results: + - Dataset: Body8 + Metrics: + AP: 0.749 + Mean@0.1: 0.943 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7_420e-256x192-e48f03d0_20230504.pth +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb256-420e_body8-256x192.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-l_8xb256-420e_body8-256x192 + Results: + - Dataset: Body8 + Metrics: + AP: 0.767 + Mean@0.1: 0.951 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-256x192-4dba18fc_20230504.pth +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb256-420e_body8-384x288.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-m_8xb256-420e_body8-384x288 + Results: + - Dataset: Body8 + Metrics: + AP: 0.766 + Mean@0.1: 0.946 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7_420e-384x288-65e718c4_20230504.pth +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb256-420e_body8-384x288.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-l_8xb256-420e_body8-384x288 + Results: + - Dataset: Body8 + Metrics: + AP: 0.783 + Mean@0.1: 0.964 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-384x288-3f5a1437_20230504.pth diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose_body8-halpe26.md b/configs/body_2d_keypoint/rtmpose/body8/rtmpose_body8-halpe26.md new file mode 100644 index 0000000000..153b71c663 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose_body8-halpe26.md @@ -0,0 +1,74 @@ + + +
+RTMPose (arXiv'2023) + +```bibtex +@misc{https://doi.org/10.48550/arxiv.2303.07399, + doi = {10.48550/ARXIV.2303.07399}, + url = {https://arxiv.org/abs/2303.07399}, + author = {Jiang, Tao and Lu, Peng and Zhang, Li and Ma, Ningsheng and Han, Rui and Lyu, Chengqi and Li, Yining and Chen, Kai}, + keywords = {Computer Vision and Pattern Recognition (cs.CV), FOS: Computer and information sciences, FOS: Computer and information sciences}, + title = {RTMPose: Real-Time Multi-Person Pose Estimation based on MMPose}, + publisher = {arXiv}, + year = {2023}, + copyright = {Creative Commons Attribution 4.0 International} +} + +``` + +
+ + + +
+RTMDet (arXiv'2022) + +```bibtex +@misc{lyu2022rtmdet, + title={RTMDet: An Empirical Study of Designing Real-Time Object Detectors}, + author={Chengqi Lyu and Wenwei Zhang and Haian Huang and Yue Zhou and Yudong Wang and Yanyi Liu and Shilong Zhang and Kai Chen}, + year={2022}, + eprint={2212.07784}, + archivePrefix={arXiv}, + primaryClass={cs.CV} +} +``` + +
+ + + +
+AlphaPose (TPAMI'2022) + +```bibtex +@article{alphapose, + author = {Fang, Hao-Shu and Li, Jiefeng and Tang, Hongyang and Xu, Chao and Zhu, Haoyi and Xiu, Yuliang and Li, Yong-Lu and Lu, Cewu}, + journal = {IEEE Transactions on Pattern Analysis and Machine Intelligence}, + title = {AlphaPose: Whole-Body Regional Multi-Person Pose Estimation and Tracking in Real-Time}, + year = {2022} +} +``` + +
+ +- `*` denotes model trained on 7 public datasets: + - [AI Challenger](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#aic) + - [MS COCO](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#coco) + - [CrowdPose](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#crowdpose) + - [MPII](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#mpii) + - [sub-JHMDB](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#sub-jhmdb-dataset) + - [Halpe](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_wholebody_keypoint.html#halpe) + - [PoseTrack18](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#posetrack18) +- `Body8` denotes the addition of the [OCHuman](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#ochuman) dataset, in addition to the 7 datasets mentioned above, for evaluation. + +| Config | Input Size | PCK@0.1
(Body8) | AUC
(Body8) | Params(M) | FLOPS(G) | Download | +| :--------------------------------------------------------------: | :--------: | :---------------------: | :-----------------: | :-------: | :------: | :-----------------------------------------------------------------: | +| [RTMPose-t\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-t_8xb1024-700e_body8-halpe26-256x192.py) | 256x192 | 91.89 | 66.35 | 3.51 | 0.37 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_simcc-body7_pt-body7-halpe26_700e-256x192-6020f8a6_20230605.pth) | +| [RTMPose-s\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-s_8xb1024-700e_body8-halpe26-256x192.py) | 256x192 | 93.01 | 68.62 | 5.70 | 0.70 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-body7_pt-body7-halpe26_700e-256x192-7f134165_20230605.pth) | +| [RTMPose-m\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb512-700e_body8-halpe26-256x192.py) | 256x192 | 94.75 | 71.91 | 13.93 | 1.95 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7-halpe26_700e-256x192-4d3e73dd_20230605.pth) | +| [RTMPose-l\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb512-700e_body8-halpe26-256x192.py) | 256x192 | 95.37 | 73.19 | 28.11 | 4.19 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7-halpe26_700e-256x192-2abb7558_20230605.pth) | +| [RTMPose-m\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb512-700e_body8-halpe26-384x288.py) | 384x288 | 95.15 | 73.56 | 14.06 | 4.37 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7-halpe26_700e-384x288-89e6428b_20230605.pth) | +| [RTMPose-l\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb512-700e_body8-halpe26-384x288.py) | 384x288 | 95.56 | 74.38 | 28.24 | 9.40 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7-halpe26_700e-384x288-734182ce_20230605.pth) | +| [RTMPose-x\*](/configs/body_2d_keypoint/rtmpose/body8/rtmpose-x_8xb256-700e_body8-halpe26-384x288.py) | 384x288 | 95.74 | 74.82 | 50.00 | 17.29 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-x_simcc-body7_pt-body7-halpe26_700e-384x288-7fb6e239_20230606.pth) | diff --git a/configs/body_2d_keypoint/rtmpose/body8/rtmpose_body8-halpe26.yml b/configs/body_2d_keypoint/rtmpose/body8/rtmpose_body8-halpe26.yml new file mode 100644 index 0000000000..ceef6f9998 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/body8/rtmpose_body8-halpe26.yml @@ -0,0 +1,106 @@ +Collections: +- Name: RTMPose + Paper: + Title: "RTMPose: Real-Time Multi-Person Pose Estimation based on MMPose" + URL: https://arxiv.org/abs/2303.07399 + README: https://github.com/open-mmlab/mmpose/blob/main/projects/rtmpose/README.md +Models: +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-t_8xb1024-700e_body8-halpe26-256x192.py + In Collection: RTMPose + Metadata: + Architecture: &id001 + - RTMPose + Training Data: &id002 + - AI Challenger + - COCO + - CrowdPose + - MPII + - sub-JHMDB + - Halpe + - PoseTrack18 + Name: rtmpose-t_8xb1024-700e_body8-halpe26-256x192 + Results: + - Dataset: Body8 + Metrics: + Mean@0.1: 0.919 + AUC: 0.664 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_simcc-body7_pt-body7-halpe26_700e-256x192-6020f8a6_20230605.pth +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-s_8xb1024-700e_body8-halpe26-256x192.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-s_8xb1024-700e_body8-halpe26-256x192 + Results: + - Dataset: Body8 + Metrics: + Mean@0.1: 0.930 + AUC: 0.682 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-body7_pt-body7-halpe26_700e-256x192-7f134165_20230605.pth +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb512-700e_body8-halpe26-256x192.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-m_8xb512-700e_body8-halpe26-256x192 + Results: + - Dataset: Body8 + Metrics: + Mean@0.1: 0.947 + AUC: 0.719 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7-halpe26_700e-256x192-4d3e73dd_20230605.pth +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb512-700e_body8-halpe26-256x192.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-l_8xb512-700e_body8-halpe26-256x192 + Results: + - Dataset: Body8 + Metrics: + Mean@0.1: 0.954 + AUC: 0.732 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7-halpe26_700e-256x192-2abb7558_20230605.pth +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-m_8xb512-700e_body8-halpe26-384x288.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-m_8xb512-700e_body8-halpe26-384x288 + Results: + - Dataset: Body8 + Metrics: + Mean@0.1: 0.952 + AUC: 0.736 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7-halpe26_700e-384x288-89e6428b_20230605.pth +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-l_8xb512-700e_body8-halpe26-384x288.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-l_8xb512-700e_body8-halpe26-384x288 + Results: + - Dataset: Body8 + Metrics: + Mean@0.1: 0.956 + AUC: 0.744 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7-halpe26_700e-384x288-734182ce_20230605.pth +- Config: configs/body_2d_keypoint/rtmpose/body8/rtmpose-x_8xb256-700e_body8-halpe26-384x288.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-x_8xb256-700e_body8-halpe26-384x288 + Results: + - Dataset: Body8 + Metrics: + Mean@0.1: 0.957 + AUC: 0.748 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-x_simcc-body7_pt-body7-halpe26_700e-384x288-7fb6e239_20230606.pth diff --git a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_aic-coco-256x192.py b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_aic-coco-256x192.py index 5f6e938131..662bd72924 100644 --- a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_aic-coco-256x192.py +++ b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_aic-coco-256x192.py @@ -69,14 +69,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa + 'rtmposev1/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=1024, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_aic-coco-384x288.py b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_aic-coco-384x288.py index 0cf994ab2c..7b5895962b 100644 --- a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_aic-coco-384x288.py +++ b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_aic-coco-384x288.py @@ -69,14 +69,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa + 'rtmposev1/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=1024, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(9, 12), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_coco-256x192.py b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_coco-256x192.py index adecf6d16b..7d77b88fde 100644 --- a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_coco-256x192.py +++ b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_coco-256x192.py @@ -69,14 +69,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa + 'rtmposev1/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=1024, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_aic-coco-256x192.py b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_aic-coco-256x192.py index 2f15c711f4..c7840f6c46 100644 --- a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_aic-coco-256x192.py +++ b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_aic-coco-256x192.py @@ -69,14 +69,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_aic-coco-384x288.py b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_aic-coco-384x288.py index da01074db3..1293a1ae1c 100644 --- a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_aic-coco-384x288.py +++ b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_aic-coco-384x288.py @@ -69,14 +69,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(9, 12), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_coco-256x192.py b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_coco-256x192.py index 67d0356b5c..f21d0e18c6 100644 --- a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_coco-256x192.py +++ b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_coco-256x192.py @@ -69,14 +69,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_aic-coco-256x192.py b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_aic-coco-256x192.py index 77f02df6f4..6c9e9fdc55 100644 --- a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_aic-coco-256x192.py +++ b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_aic-coco-256x192.py @@ -69,14 +69,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth' # noqa + 'rtmposev1/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=512, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_coco-256x192.py b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_coco-256x192.py index 425bb3ab4d..c0abcbb1dd 100644 --- a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_coco-256x192.py +++ b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_coco-256x192.py @@ -69,14 +69,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth' # noqa + 'rtmposev1/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=512, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_aic-coco-256x192.py b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_aic-coco-256x192.py index fbcf8b3446..215a297944 100644 --- a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_aic-coco-256x192.py +++ b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_aic-coco-256x192.py @@ -69,14 +69,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth' # noqa + 'rtmposev1/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=384, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_coco-256x192.py b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_coco-256x192.py index 54d20c3607..cbe0978b2b 100644 --- a/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_coco-256x192.py +++ b/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_coco-256x192.py @@ -69,14 +69,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth' # noqa + 'rtmposev1/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=384, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/body_2d_keypoint/rtmpose/coco/rtmpose_coco.md b/configs/body_2d_keypoint/rtmpose/coco/rtmpose_coco.md index 2b3d4447e1..d3cc9298df 100644 --- a/configs/body_2d_keypoint/rtmpose/coco/rtmpose_coco.md +++ b/configs/body_2d_keypoint/rtmpose/coco/rtmpose_coco.md @@ -59,13 +59,13 @@ Results on COCO val2017 with detector having human AP of 56.4 on COCO val2017 da | Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | | :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | -| [rtmpose-t](./rtmpose-t_8xb256-420e_coco-256x192.py) | 256x192 | 0.682 | 0.883 | 0.759 | 0.736 | 0.920 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.json) | -| [rtmpose-s](./rtmpose-s_8xb256-420e_coco-256x192.py) | 256x192 | 0.716 | 0.892 | 0.789 | 0.768 | 0.929 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.json) | -| [rtmpose-m](./rtmpose-m_8xb256-420e_coco-256x192.py) | 256x192 | 0.746 | 0.899 | 0.817 | 0.795 | 0.935 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco_pt-aic-coco_420e-256x192-d8dd5ca4_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco_pt-aic-coco_420e-256x192-d8dd5ca4_20230127.json) | -| [rtmpose-l](./rtmpose-l_8xb256-420e_coco-256x192.py) | 256x192 | 0.758 | 0.906 | 0.826 | 0.806 | 0.942 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco_pt-aic-coco_420e-256x192-1352a4d2_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco_pt-aic-coco_420e-256x192-1352a4d2_20230127.json) | -| [rtmpose-t-aic-coco](./rtmpose-t_8xb256-420e_aic-coco-256x192.py) | 256x192 | 0.685 | 0.880 | 0.761 | 0.738 | 0.918 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.json) | -| [rtmpose-s-aic-coco](./rtmpose-s_8xb256-420e_aic-coco-256x192.py) | 256x192 | 0.722 | 0.892 | 0.794 | 0.772 | 0.929 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.json) | -| [rtmpose-m-aic-coco](./rtmpose-m_8xb256-420e_aic-coco-256x192.py) | 256x192 | 0.758 | 0.903 | 0.826 | 0.806 | 0.940 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.json) | -| [rtmpose-l-aic-coco](./rtmpose-l_8xb256-420e_aic-coco-256x192.py) | 256x192 | 0.765 | 0.906 | 0.835 | 0.813 | 0.942 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.json) | -| [rtmpose-m-aic-coco](./rtmpose-m_8xb256-420e_aic-coco-384x288.py) | 384x288 | 0.770 | 0.908 | 0.833 | 0.816 | 0.943 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-384x288-a62a0b32_20230228.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-384x288-a62a0b32_20230228.json) | -| [rtmpose-l-aic-coco](./rtmpose-l_8xb256-420e_aic-coco-384x288.py) | 384x288 | 0.773 | 0.907 | 0.835 | 0.819 | 0.942 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-384x288-97d6cb0f_20230228.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-384x288-97d6cb0f_20230228.json) | +| [rtmpose-t](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_coco-256x192.py) | 256x192 | 0.682 | 0.883 | 0.759 | 0.736 | 0.920 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.json) | +| [rtmpose-s](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_coco-256x192.py) | 256x192 | 0.716 | 0.892 | 0.789 | 0.768 | 0.929 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.json) | +| [rtmpose-m](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_coco-256x192.py) | 256x192 | 0.746 | 0.899 | 0.817 | 0.795 | 0.935 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco_pt-aic-coco_420e-256x192-d8dd5ca4_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco_pt-aic-coco_420e-256x192-d8dd5ca4_20230127.json) | +| [rtmpose-l](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_coco-256x192.py) | 256x192 | 0.758 | 0.906 | 0.826 | 0.806 | 0.942 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco_pt-aic-coco_420e-256x192-1352a4d2_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco_pt-aic-coco_420e-256x192-1352a4d2_20230127.json) | +| [rtmpose-t-aic-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_aic-coco-256x192.py) | 256x192 | 0.685 | 0.880 | 0.761 | 0.738 | 0.918 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.json) | +| [rtmpose-s-aic-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_aic-coco-256x192.py) | 256x192 | 0.722 | 0.892 | 0.794 | 0.772 | 0.929 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.json) | +| [rtmpose-m-aic-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_aic-coco-256x192.py) | 256x192 | 0.758 | 0.903 | 0.826 | 0.806 | 0.940 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.json) | +| [rtmpose-l-aic-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_aic-coco-256x192.py) | 256x192 | 0.765 | 0.906 | 0.835 | 0.813 | 0.942 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.json) | +| [rtmpose-m-aic-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_aic-coco-384x288.py) | 384x288 | 0.770 | 0.908 | 0.833 | 0.816 | 0.943 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-384x288-a62a0b32_20230228.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-384x288-a62a0b32_20230228.json) | +| [rtmpose-l-aic-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_aic-coco-384x288.py) | 384x288 | 0.773 | 0.907 | 0.835 | 0.819 | 0.942 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-384x288-97d6cb0f_20230228.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-384x288-97d6cb0f_20230228.json) | diff --git a/configs/body_2d_keypoint/rtmpose/coco/rtmpose_coco.yml b/configs/body_2d_keypoint/rtmpose/coco/rtmpose_coco.yml index 49b2f850ac..bebe64b3b7 100644 --- a/configs/body_2d_keypoint/rtmpose/coco/rtmpose_coco.yml +++ b/configs/body_2d_keypoint/rtmpose/coco/rtmpose_coco.yml @@ -21,7 +21,7 @@ Models: AR: 0.736 AR@0.5: 0.92 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.pth - Config: configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_coco-256x192.py In Collection: RTMPose Metadata: @@ -37,7 +37,7 @@ Models: AR: 0.768 AR@0.5: 0.929 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.pth - Config: configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_coco-256x192.py In Collection: RTMPose Metadata: @@ -53,7 +53,7 @@ Models: AR: 0.795 AR@0.5: 0.935 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco_pt-aic-coco_420e-256x192-d8dd5ca4_20230127.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco_pt-aic-coco_420e-256x192-d8dd5ca4_20230127.pth - Config: configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_coco-256x192.py In Collection: RTMPose Metadata: @@ -69,7 +69,7 @@ Models: AR: 0.806 AR@0.5: 0.942 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco_pt-aic-coco_420e-256x192-1352a4d2_20230127.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco_pt-aic-coco_420e-256x192-1352a4d2_20230127.pth - Config: configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_aic-coco-256x192.py In Collection: RTMPose Metadata: @@ -87,7 +87,7 @@ Models: AR: 0.738 AR@0.5: 0.918 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth - Config: configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_aic-coco-256x192.py In Collection: RTMPose Metadata: @@ -103,7 +103,7 @@ Models: AR: 0.772 AR@0.5: 0.929 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth - Config: configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_aic-coco-256x192.py In Collection: RTMPose Alias: human @@ -120,7 +120,7 @@ Models: AR: 0.806 AR@0.5: 0.94 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth - Config: configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_aic-coco-256x192.py In Collection: RTMPose Metadata: @@ -136,7 +136,7 @@ Models: AR: 0.813 AR@0.5: 0.942 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth - Config: configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_aic-coco-384x288.py In Collection: RTMPose Metadata: @@ -152,7 +152,7 @@ Models: AR: 0.816 AR@0.5: 0.943 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-384x288-a62a0b32_20230228.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-384x288-a62a0b32_20230228.pth - Config: configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_aic-coco-384x288.py In Collection: RTMPose Metadata: @@ -168,4 +168,4 @@ Models: AR: 0.819 AR@0.5: 0.942 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-384x288-97d6cb0f_20230228.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-384x288-97d6cb0f_20230228.pth diff --git a/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose-m_8xb64-210e_crowdpose-256x192.py b/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose-m_8xb64-210e_crowdpose-256x192.py index 505fb54264..e93a2f1099 100644 --- a/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose-m_8xb64-210e_crowdpose-256x192.py +++ b/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose-m_8xb64-210e_crowdpose-256x192.py @@ -24,7 +24,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -69,14 +68,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, out_channels=14, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose_crowdpose.md b/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose_crowdpose.md index 35048ee9ef..42bcf0f65f 100644 --- a/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose_crowdpose.md +++ b/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose_crowdpose.md @@ -57,4 +57,4 @@ Results on CrowdPose test with [YOLOv3](https://github.com/eriklindernoren/PyTor | Arch | Input Size | AP | AP50 | AP75 | AP (E) | AP (M) | AP (H) | ckpt | log | | :--------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :----: | :----: | :----: | :--------------------------------------------: | :-------------------------------------------: | -| [rtmpose-m](./rtmpose-m_8xb64-210e_crowdpose-256x192.py) | 256x192 | 0.706 | 0.841 | 0.765 | 0.799 | 0.719 | 0.582 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-crowdpose_pt-aic-coco_210e-256x192-e6192cac_20230224.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-crowdpose_pt-aic-coco_210e-256x192-e6192cac_20230224.json) | +| [rtmpose-m](/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose-m_8xb64-210e_crowdpose-256x192.py) | 256x192 | 0.706 | 0.841 | 0.765 | 0.799 | 0.719 | 0.582 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-crowdpose_pt-aic-coco_210e-256x192-e6192cac_20230224.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-crowdpose_pt-aic-coco_210e-256x192-e6192cac_20230224.json) | diff --git a/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose_crowdpose.yml b/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose_crowdpose.yml index 4b61697b0b..5fb842f563 100644 --- a/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose_crowdpose.yml +++ b/configs/body_2d_keypoint/rtmpose/crowdpose/rtmpose_crowdpose.yml @@ -16,4 +16,4 @@ Models: AP (M): 0.719 AP (L): 0.582 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-crowdpose_pt-aic-coco_210e-256x192-e6192cac_20230224.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-crowdpose_pt-aic-coco_210e-256x192-e6192cac_20230224.pth diff --git a/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-l_8xb256-420e_humanart-256x192.py b/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-l_8xb256-420e_humanart-256x192.py new file mode 100644 index 0000000000..384a712d95 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-l_8xb256-420e_humanart-256x192.py @@ -0,0 +1,232 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +max_epochs = 420 +stage2_num_epochs = 30 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + # use cosine lr from 210 to 420 epoch + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(192, 256), + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=1., + widen_factor=1., + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=1024, + out_channels=17, + input_size=codec['input_size'], + in_featuremap_size=(6, 8), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'HumanArtDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') +# backend_args = dict( +# backend='petrel', +# path_mapping=dict({ +# f'{data_root}': 's3://openmmlab/datasets/detection/coco/', +# f'{data_root}': 's3://openmmlab/datasets/detection/coco/' +# })) + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.6, 1.4], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/training_humanart_coco.json', + data_prefix=dict(img=''), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/validation_humanart.json', + # bbox_file=f'{data_root}HumanArt/person_detection_results/' + # 'HumanArt_validation_detections_AP_H_56_person.json', + data_prefix=dict(img=''), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'HumanArt/annotations/validation_humanart.json') +test_evaluator = val_evaluator diff --git a/projects/rtmpose/rtmpose/face_2d_keypoint/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py b/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-m_8xb256-420e_humanart-256x192.py similarity index 83% rename from projects/rtmpose/rtmpose/face_2d_keypoint/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py rename to configs/body_2d_keypoint/rtmpose/humanart/rtmpose-m_8xb256-420e_humanart-256x192.py index b595682932..30178cbb6d 100644 --- a/projects/rtmpose/rtmpose/face_2d_keypoint/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py +++ b/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-m_8xb256-420e_humanart-256x192.py @@ -1,11 +1,11 @@ -_base_ = ['mmpose::_base_/default_runtime.py'] +_base_ = ['../../../_base_/default_runtime.py'] # runtime -max_epochs = 60 -stage2_num_epochs = 10 +max_epochs = 420 +stage2_num_epochs = 30 base_lr = 4e-3 -train_cfg = dict(max_epochs=max_epochs, val_interval=1) +train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) # optimizer @@ -24,7 +24,7 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch + # use cosine lr from 210 to 420 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -35,13 +35,13 @@ ] # automatically scaling LR based on the actual training batch size -auto_scale_lr = dict(base_batch_size=512) +auto_scale_lr = dict(base_batch_size=1024) # codec settings codec = dict( type='SimCCLabel', - input_size=(256, 256), - sigma=(5.66, 5.66), + input_size=(192, 256), + sigma=(4.9, 5.66), simcc_split_ratio=2.0, normalize=False, use_dark=False) @@ -74,9 +74,9 @@ head=dict( type='RTMCCHead', in_channels=768, - out_channels=68, + out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(8, 8), + in_featuremap_size=(6, 8), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -94,12 +94,12 @@ beta=10., label_softmax=True), decoder=codec), - test_cfg=dict(flip_test=True, )) + test_cfg=dict(flip_test=True)) # base dataset settings -dataset_type = 'CocoWholeBodyFaceDataset' +dataset_type = 'HumanArtDataset' data_mode = 'topdown' -data_root = 'data/coco/' +data_root = 'data/' backend_args = dict(backend='local') # backend_args = dict( @@ -114,7 +114,7 @@ dict(type='LoadImage', backend_args=backend_args), dict(type='GetBBoxCenterScale'), dict(type='RandomFlip', direction='horizontal'), - # dict(type='RandomHalfBody'), + dict(type='RandomHalfBody'), dict( type='RandomBBoxTransform', scale_factor=[0.6, 1.4], rotate_factor=80), dict(type='TopdownAffine', input_size=codec['input_size']), @@ -132,7 +132,7 @@ min_holes=1, min_height=0.2, min_width=0.2, - p=1.0), + p=1.), ]), dict(type='GenerateTarget', encoder=codec), dict(type='PackPoseInputs') @@ -148,7 +148,7 @@ dict(type='LoadImage', backend_args=backend_args), dict(type='GetBBoxCenterScale'), dict(type='RandomFlip', direction='horizontal'), - # dict(type='RandomHalfBody'), + dict(type='RandomHalfBody'), dict( type='RandomBBoxTransform', shift_factor=0., @@ -177,7 +177,7 @@ # data loaders train_dataloader = dict( - batch_size=32, + batch_size=256, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), @@ -185,12 +185,12 @@ type=dataset_type, data_root=data_root, data_mode=data_mode, - ann_file='annotations/coco_wholebody_train_v1.0.json', - data_prefix=dict(img='train2017/'), + ann_file='HumanArt/annotations/training_humanart_coco.json', + data_prefix=dict(img=''), pipeline=train_pipeline, )) val_dataloader = dict( - batch_size=32, + batch_size=64, num_workers=10, persistent_workers=True, drop_last=False, @@ -199,8 +199,10 @@ type=dataset_type, data_root=data_root, data_mode=data_mode, - ann_file='annotations/coco_wholebody_val_v1.0.json', - data_prefix=dict(img='val2017/'), + ann_file='HumanArt/annotations/validation_humanart.json', + # bbox_file=f'{data_root}HumanArt/person_detection_results/' + # 'HumanArt_validation_detections_AP_H_56_person.json', + data_prefix=dict(img=''), test_mode=True, pipeline=val_pipeline, )) @@ -208,8 +210,7 @@ # hooks default_hooks = dict( - checkpoint=dict( - save_best='NME', rule='less', max_keep_ckpts=1, interval=1)) + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) custom_hooks = [ dict( @@ -226,7 +227,6 @@ # evaluators val_evaluator = dict( - type='NME', - norm_mode='keypoint_distance', -) + type='CocoMetric', + ann_file=data_root + 'HumanArt/annotations/validation_humanart.json') test_evaluator = val_evaluator diff --git a/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-s_8xb256-420e_humanart-256x192.py b/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-s_8xb256-420e_humanart-256x192.py new file mode 100644 index 0000000000..b4263f25e7 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-s_8xb256-420e_humanart-256x192.py @@ -0,0 +1,232 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +max_epochs = 420 +stage2_num_epochs = 30 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + # use cosine lr from 210 to 420 epoch + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(192, 256), + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.33, + widen_factor=0.5, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmpose/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=512, + out_channels=17, + input_size=codec['input_size'], + in_featuremap_size=(6, 8), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'HumanArtDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') +# backend_args = dict( +# backend='petrel', +# path_mapping=dict({ +# f'{data_root}': 's3://openmmlab/datasets/detection/coco/', +# f'{data_root}': 's3://openmmlab/datasets/detection/coco/' +# })) + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.6, 1.4], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/training_humanart_coco.json', + data_prefix=dict(img=''), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/validation_humanart.json', + # bbox_file=f'{data_root}HumanArt/person_detection_results/' + # 'HumanArt_validation_detections_AP_H_56_person.json', + data_prefix=dict(img=''), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'HumanArt/annotations/validation_humanart.json') +test_evaluator = val_evaluator diff --git a/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-t_8xb256-420e_humanart-256x192.py b/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-t_8xb256-420e_humanart-256x192.py new file mode 100644 index 0000000000..869f04217d --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-t_8xb256-420e_humanart-256x192.py @@ -0,0 +1,233 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +max_epochs = 420 +stage2_num_epochs = 30 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + # use cosine lr from 210 to 420 epoch + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(192, 256), + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.167, + widen_factor=0.375, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmpose/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=384, + out_channels=17, + input_size=codec['input_size'], + in_featuremap_size=(6, 8), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'HumanArtDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') +# backend_args = dict( +# backend='petrel', +# path_mapping=dict({ +# f'{data_root}': 's3://openmmlab/datasets/detection/coco/', +# f'{data_root}': 's3://openmmlab/datasets/detection/coco/' +# })) + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.6, 1.4], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/training_humanart_coco.json', + data_prefix=dict(img=''), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/validation_humanart.json', + # bbox_file=f'{data_root}HumanArt/person_detection_results/' + # 'HumanArt_validation_detections_AP_H_56_person.json', + data_prefix=dict(img=''), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + # Turn off EMA while training the tiny model + # dict( + # type='EMAHook', + # ema_type='ExpMomentumEMA', + # momentum=0.0002, + # update_buffers=True, + # priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'HumanArt/annotations/validation_humanart.json') +test_evaluator = val_evaluator diff --git a/configs/body_2d_keypoint/rtmpose/humanart/rtmpose_humanart.md b/configs/body_2d_keypoint/rtmpose/humanart/rtmpose_humanart.md new file mode 100644 index 0000000000..385ce0612a --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/humanart/rtmpose_humanart.md @@ -0,0 +1,117 @@ + + +
+RTMPose (arXiv'2023) + +```bibtex +@misc{https://doi.org/10.48550/arxiv.2303.07399, + doi = {10.48550/ARXIV.2303.07399}, + url = {https://arxiv.org/abs/2303.07399}, + author = {Jiang, Tao and Lu, Peng and Zhang, Li and Ma, Ningsheng and Han, Rui and Lyu, Chengqi and Li, Yining and Chen, Kai}, + keywords = {Computer Vision and Pattern Recognition (cs.CV), FOS: Computer and information sciences, FOS: Computer and information sciences}, + title = {RTMPose: Real-Time Multi-Person Pose Estimation based on MMPose}, + publisher = {arXiv}, + year = {2023}, + copyright = {Creative Commons Attribution 4.0 International} +} + +``` + +
+ + + +
+RTMDet (arXiv'2022) + +```bibtex +@misc{lyu2022rtmdet, + title={RTMDet: An Empirical Study of Designing Real-Time Object Detectors}, + author={Chengqi Lyu and Wenwei Zhang and Haian Huang and Yue Zhou and Yudong Wang and Yanyi Liu and Shilong Zhang and Kai Chen}, + year={2022}, + eprint={2212.07784}, + archivePrefix={arXiv}, + primaryClass={cs.CV} +} +``` + +
+ + + +
+COCO (ECCV'2014) + +```bibtex +@inproceedings{lin2014microsoft, + title={Microsoft coco: Common objects in context}, + author={Lin, Tsung-Yi and Maire, Michael and Belongie, Serge and Hays, James and Perona, Pietro and Ramanan, Deva and Doll{\'a}r, Piotr and Zitnick, C Lawrence}, + booktitle={European conference on computer vision}, + pages={740--755}, + year={2014}, + organization={Springer} +} +``` + +
+ +
+Human-Art (CVPR'2023) + +```bibtex +@inproceedings{ju2023humanart, + title={Human-Art: A Versatile Human-Centric Dataset Bridging Natural and Artificial Scenes}, + author={Ju, Xuan and Zeng, Ailing and Jianan, Wang and Qiang, Xu and Lei, Zhang}, + booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), + year={2023}} +``` + +
+ +Results on Human-Art validation dataset with detector having human AP of 56.2 on Human-Art validation dataset + +| Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | +| :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | +| [rtmpose-t-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_coco-256x192.py) | 256x192 | 0.161 | 0.283 | 0.154 | 0.221 | 0.373 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.json) | +| [rtmpose-t-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-t_8xb256-420e_humanart-256x192.py) | 256x192 | 0.249 | 0.395 | 0.256 | 0.323 | 0.485 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_8xb256-420e_humanart-256x192-60b68c98_20230612.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_8xb256-420e_humanart-256x192-60b68c98_20230612.json) | +| [rtmpose-s-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_coco-256x192.py) | 256x192 | 0.199 | 0.328 | 0.198 | 0.261 | 0.418 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.json) | +| [rtmpose-s-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-s_8xb256-420e_humanart-256x192.py) | 256x192 | 0.311 | 0.462 | 0.323 | 0.381 | 0.540 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_8xb256-420e_humanart-256x192-5a3ac943_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_8xb256-420e_humanart-256x192-5a3ac943_20230611.json) | +| [rtmpose-m-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_coco-256x192.py) | 256x192 | 0.239 | 0.372 | 0.243 | 0.302 | 0.455 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco_pt-aic-coco_420e-256x192-d8dd5ca4_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco_pt-aic-coco_420e-256x192-d8dd5ca4_20230127.json) | +| [rtmpose-m-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-m_8xb256-420e_humanart-256x192.py) | 256x192 | 0.355 | 0.503 | 0.377 | 0.417 | 0.568 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_8xb256-420e_humanart-256x192-8430627b_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_8xb256-420e_humanart-256x192-8430627b_20230611.json) | +| [rtmpose-l-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_coco-256x192.py) | 256x192 | 0.260 | 0.393 | 0.267 | 0.323 | 0.472 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco_pt-aic-coco_420e-256x192-1352a4d2_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco_pt-aic-coco_420e-256x192-1352a4d2_20230127.json) | +| [rtmpose-l-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-l_8xb256-420e_humanart-256x192.py) | 256x192 | 0.378 | 0.521 | 0.399 | 0.442 | 0.584 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_8xb256-420e_humanart-256x192-389f2cb0_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_8xb256-420e_humanart-256x192-389f2cb0_20230611.json) | + +Results on Human-Art validation dataset with ground-truth bounding-box + +| Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | +| :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | +| [rtmpose-t-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_coco-256x192.py) | 256x192 | 0.444 | 0.725 | 0.453 | 0.488 | 0.750 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.json) | +| [rtmpose-t-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-t_8xb256-420e_humanart-256x192.py) | 256x192 | 0.655 | 0.872 | 0.720 | 0.693 | 0.890 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_8xb256-420e_humanart-256x192-60b68c98_20230612.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_8xb256-420e_humanart-256x192-60b68c98_20230612.json) | +| [rtmpose-s-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_coco-256x192.py) | 256x192 | 0.480 | 0.739 | 0.498 | 0.521 | 0.763 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.json) | +| [rtmpose-s-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-s_8xb256-420e_humanart-256x192.py) | 256x192 | 0.698 | 0.893 | 0.768 | 0.732 | 0.903 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_8xb256-420e_humanart-256x192-5a3ac943_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_8xb256-420e_humanart-256x192-5a3ac943_20230611.json) | +| [rtmpose-m-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_coco-256x192.py) | 256x192 | 0.532 | 0.765 | 0.563 | 0.571 | 0.789 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco_pt-aic-coco_420e-256x192-d8dd5ca4_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco_pt-aic-coco_420e-256x192-d8dd5ca4_20230127.json) | +| [rtmpose-m-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-m_8xb256-420e_humanart-256x192.py) | 256x192 | 0.728 | 0.895 | 0.791 | 0.759 | 0.906 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_8xb256-420e_humanart-256x192-8430627b_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_8xb256-420e_humanart-256x192-8430627b_20230611.json) | +| [rtmpose-l-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_coco-256x192.py) | 256x192 | 0.564 | 0.789 | 0.602 | 0.599 | 0.808 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco_pt-aic-coco_420e-256x192-1352a4d2_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco_pt-aic-coco_420e-256x192-1352a4d2_20230127.json) | +| [rtmpose-l-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-l_8xb256-420e_humanart-256x192.py) | 256x192 | 0.753 | 0.905 | 0.812 | 0.783 | 0.915 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_8xb256-420e_humanart-256x192-389f2cb0_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_8xb256-420e_humanart-256x192-389f2cb0_20230611.json) | + +Results on COCO val2017 with detector having human AP of 56.4 on COCO val2017 dataset + +| Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | +| :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | +| [rtmpose-t-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-t_8xb256-420e_coco-256x192.py) | 256x192 | 0.682 | 0.883 | 0.759 | 0.736 | 0.920 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-coco_pt-aic-coco_420e-256x192-e613ba3f_20230127.json) | +| [rtmpose-t-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-t_8xb256-420e_humanart-256x192.py) | 256x192 | 0.665 | 0.875 | 0.739 | 0.721 | 0.916 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_8xb256-420e_humanart-256x192-60b68c98_20230612.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_8xb256-420e_humanart-256x192-60b68c98_20230612.json) | +| [rtmpose-s-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-s_8xb256-420e_coco-256x192.py) | 256x192 | 0.716 | 0.892 | 0.789 | 0.768 | 0.929 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-coco_pt-aic-coco_420e-256x192-8edcf0d7_20230127.json) | +| [rtmpose-s-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-s_8xb256-420e_humanart-256x192.py) | 256x192 | 0.706 | 0.888 | 0.780 | 0.759 | 0.928 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_8xb256-420e_humanart-256x192-5a3ac943_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_8xb256-420e_humanart-256x192-5a3ac943_20230611.json) | +| [rtmpose-m-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_coco-256x192.py) | 256x192 | 0.746 | 0.899 | 0.817 | 0.795 | 0.935 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco_pt-aic-coco_420e-256x192-d8dd5ca4_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco_pt-aic-coco_420e-256x192-d8dd5ca4_20230127.json) | +| [rtmpose-m-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-m_8xb256-420e_humanart-256x192.py) | 256x192 | 0.725 | 0.892 | 0.795 | 0.775 | 0.929 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_8xb256-420e_humanart-256x192-8430627b_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_8xb256-420e_humanart-256x192-8430627b_20230611.json) | +| [rtmpose-l-coco](/configs/body_2d_keypoint/rtmpose/coco/rtmpose-l_8xb256-420e_coco-256x192.py) | 256x192 | 0.758 | 0.906 | 0.826 | 0.806 | 0.942 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco_pt-aic-coco_420e-256x192-1352a4d2_20230127.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco_pt-aic-coco_420e-256x192-1352a4d2_20230127.json) | +| [rtmpose-l-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-l_8xb256-420e_humanart-256x192.py) | 256x192 | 0.748 | 0.901 | 0.816 | 0.796 | 0.938 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_8xb256-420e_humanart-256x192-389f2cb0_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_8xb256-420e_humanart-256x192-389f2cb0_20230611.json) | + +Results on COCO val2017 with ground-truth bounding box + +| Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | +| :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | +| [rtmpose-t-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-t_8xb256-420e_humanart-256x192.py) | 256x192 | 0.679 | 0.895 | 0.755 | 0.710 | 0.907 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_8xb256-420e_humanart-256x192-60b68c98_20230612.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_8xb256-420e_humanart-256x192-60b68c98_20230612.json) | +| [rtmpose-s-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-s_8xb256-420e_humanart-256x192.py) | 256x192 | 0.725 | 0.916 | 0.798 | 0.753 | 0.925 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_8xb256-420e_humanart-256x192-5a3ac943_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_8xb256-420e_humanart-256x192-5a3ac943_20230611.json) | +| [rtmpose-m-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-m_8xb256-420e_humanart-256x192.py) | 256x192 | 0.744 | 0.916 | 0.818 | 0.770 | 0.930 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_8xb256-420e_humanart-256x192-8430627b_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_8xb256-420e_humanart-256x192-8430627b_20230611.json) | +| [rtmpose-l-humanart-coco](/configs/body_2d_keypoint/rtmpose/humanart/rtmpose-l_8xb256-420e_humanart-256x192.py) | 256x192 | 0.770 | 0.927 | 0.840 | 0.794 | 0.939 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_8xb256-420e_humanart-256x192-389f2cb0_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_8xb256-420e_humanart-256x192-389f2cb0_20230611.json) | diff --git a/configs/body_2d_keypoint/rtmpose/humanart/rtmpose_humanart.yml b/configs/body_2d_keypoint/rtmpose/humanart/rtmpose_humanart.yml new file mode 100644 index 0000000000..2d6cf6ff26 --- /dev/null +++ b/configs/body_2d_keypoint/rtmpose/humanart/rtmpose_humanart.yml @@ -0,0 +1,138 @@ +Collections: +- Name: RTMPose + Paper: + Title: "RTMPose: Real-Time Multi-Person Pose Estimation based on MMPose" + URL: https://arxiv.org/abs/2303.07399 + README: https://github.com/open-mmlab/mmpose/blob/main/projects/rtmpose/README.md +Models: +- Config: configs/body_2d_keypoint/rtmpose/humanart/rtmpose-l_8xb256-420e_humanart-256x192.py + In Collection: RTMPose + Metadata: + Architecture: &id001 + - RTMPose + Training Data: &id002 + - COCO + - Human-Art + Name: rtmpose-l_8xb256-420e_humanart-256x192 + Results: + - Dataset: COCO + Metrics: + AP: 0.748 + AP@0.5: 0.901 + AP@0.75: 0.816 + AR: 0.796 + AR@0.5: 0.938 + Task: Body 2D Keypoint + - Dataset: Human-Art + Metrics: + AP: 0.378 + AP@0.5: 0.521 + AP@0.75: 0.399 + AR: 0.442 + AR@0.5: 0.584 + Task: Body 2D Keypoint + - Dataset: Human-Art(GT) + Metrics: + AP: 0.753 + AP@0.5: 0.905 + AP@0.75: 0.812 + AR: 0.783 + AR@0.5: 0.915 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_8xb256-420e_humanart-256x192-389f2cb0_20230611.pth +- Config: configs/body_2d_keypoint/rtmpose/humanart/rtmpose-m_8xb256-420e_humanart-256x192.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-m_8xb256-420e_humanart-256x192 + Results: + - Dataset: COCO + Metrics: + AP: 0.725 + AP@0.5: 0.892 + AP@0.75: 0.795 + AR: 0.775 + AR@0.5: 0.929 + Task: Body 2D Keypoint + - Dataset: Human-Art + Metrics: + AP: 0.355 + AP@0.5: 0.503 + AP@0.75: 0.377 + AR: 0.417 + AR@0.5: 0.568 + Task: Body 2D Keypoint + - Dataset: Human-Art(GT) + Metrics: + AP: 0.728 + AP@0.5: 0.895 + AP@0.75: 0.791 + AR: 0.759 + AR@0.5: 0.906 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_8xb256-420e_humanart-256x192-8430627b_20230611.pth +- Config: configs/body_2d_keypoint/rtmpose/humanart/rtmpose-s_8xb256-420e_humanart-256x192.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-s_8xb256-420e_humanart-256x192 + Results: + - Dataset: COCO + Metrics: + AP: 0.706 + AP@0.5: 0.888 + AP@0.75: 0.780 + AR: 0.759 + AR@0.5: 0.928 + Task: Body 2D Keypoint + - Dataset: Human-Art + Metrics: + AP: 0.311 + AP@0.5: 0.462 + AP@0.75: 0.323 + AR: 0.381 + AR@0.5: 0.540 + Task: Body 2D Keypoint + - Dataset: Human-Art(GT) + Metrics: + AP: 0.698 + AP@0.5: 0.893 + AP@0.75: 0.768 + AR: 0.732 + AR@0.5: 0.903 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_8xb256-420e_humanart-256x192-5a3ac943_20230611.pth +- Config: configs/body_2d_keypoint/rtmpose/humanart/rtmpose-t_8xb256-420e_humanart-256x192.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-t_8xb256-420e_humanart-256x192 + Results: + - Dataset: COCO + Metrics: + AP: 0.665 + AP@0.5: 0.875 + AP@0.75: 0.739 + AR: 0.721 + AR@0.5: 0.916 + Task: Body 2D Keypoint + - Dataset: Human-Art + Metrics: + AP: 0.249 + AP@0.5: 0.395 + AP@0.75: 0.256 + AR: 0.323 + AR@0.5: 0.485 + Task: Body 2D Keypoint + - Dataset: Human-Art(GT) + Metrics: + AP: 0.655 + AP@0.5: 0.872 + AP@0.75: 0.720 + AR: 0.693 + AR@0.5: 0.890 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_8xb256-420e_humanart-256x192-60b68c98_20230612.pth diff --git a/configs/body_2d_keypoint/rtmpose/mpii/rtmpose-m_8xb64-210e_mpii-256x256.py b/configs/body_2d_keypoint/rtmpose/mpii/rtmpose-m_8xb64-210e_mpii-256x256.py index ea920b46e7..ca67020f51 100644 --- a/configs/body_2d_keypoint/rtmpose/mpii/rtmpose-m_8xb64-210e_mpii-256x256.py +++ b/configs/body_2d_keypoint/rtmpose/mpii/rtmpose-m_8xb64-210e_mpii-256x256.py @@ -68,14 +68,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, out_channels=16, input_size=codec['input_size'], - in_featuremap_size=(8, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/body_2d_keypoint/rtmpose/mpii/rtmpose_mpii.md b/configs/body_2d_keypoint/rtmpose/mpii/rtmpose_mpii.md index b9c8f5a6bd..990edb45eb 100644 --- a/configs/body_2d_keypoint/rtmpose/mpii/rtmpose_mpii.md +++ b/configs/body_2d_keypoint/rtmpose/mpii/rtmpose_mpii.md @@ -38,6 +38,6 @@ Results on MPII val set -| Arch | Input Size | Mean / w. flip | Mean@0.1 | ckpt | log | -| :-------------------------------------------------- | :--------: | :------------: | :------: | :---------------------------------------------------------: | :--------------------------------------------------------: | -| [rtmpose-m](./rtmpose-m_8xb64-210e_mpii-256x256.py) | 256x256 | 0.907 | 0.348 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-mpii_pt-aic-coco_210e-256x256-ec4dbec8_20230206.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-mpii_pt-aic-coco_210e-256x256-ec4dbec8_20230206.json) | +| Arch | Input Size | Mean / w. flip | Mean@0.1 | ckpt | log | +| :------------------------------------------------------- | :--------: | :------------: | :------: | :------------------------------------------------------: | :------------------------------------------------------: | +| [rtmpose-m](/configs/body_2d_keypoint/rtmpose/mpii/rtmpose-m_8xb64-210e_mpii-256x256.py) | 256x256 | 0.907 | 0.348 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-mpii_pt-aic-coco_210e-256x256-ec4dbec8_20230206.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-mpii_pt-aic-coco_210e-256x256-ec4dbec8_20230206.json) | diff --git a/configs/body_2d_keypoint/rtmpose/mpii/rtmpose_mpii.yml b/configs/body_2d_keypoint/rtmpose/mpii/rtmpose_mpii.yml index bf07697088..2e1eb28659 100644 --- a/configs/body_2d_keypoint/rtmpose/mpii/rtmpose_mpii.yml +++ b/configs/body_2d_keypoint/rtmpose/mpii/rtmpose_mpii.yml @@ -12,4 +12,4 @@ Models: Mean: 0.907 Mean@0.1: 0.348 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-mpii_pt-aic-coco_210e-256x256-ec4dbec8_20230206.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-mpii_pt-aic-coco_210e-256x256-ec4dbec8_20230206.pth diff --git a/configs/body_2d_keypoint/simcc/coco/simcc_mobilenetv2_wo-deconv-8xb64-210e_coco-256x192.py b/configs/body_2d_keypoint/simcc/coco/simcc_mobilenetv2_wo-deconv-8xb64-210e_coco-256x192.py index 65101ada88..800803d190 100644 --- a/configs/body_2d_keypoint/simcc/coco/simcc_mobilenetv2_wo-deconv-8xb64-210e_coco-256x192.py +++ b/configs/body_2d_keypoint/simcc/coco/simcc_mobilenetv2_wo-deconv-8xb64-210e_coco-256x192.py @@ -51,7 +51,7 @@ in_channels=1280, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], deconv_out_channels=None, loss=dict(type='KLDiscretLoss', use_target_weight=True), diff --git a/configs/body_2d_keypoint/simcc/coco/simcc_res50_8xb32-140e_coco-384x288.py b/configs/body_2d_keypoint/simcc/coco/simcc_res50_8xb32-140e_coco-384x288.py index 8ed9586bfb..c04358299f 100644 --- a/configs/body_2d_keypoint/simcc/coco/simcc_res50_8xb32-140e_coco-384x288.py +++ b/configs/body_2d_keypoint/simcc/coco/simcc_res50_8xb32-140e_coco-384x288.py @@ -48,7 +48,7 @@ in_channels=2048, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(9, 12), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], loss=dict(type='KLDiscretLoss', use_target_weight=True), decoder=codec), diff --git a/configs/body_2d_keypoint/simcc/coco/simcc_res50_8xb64-210e_coco-256x192.py b/configs/body_2d_keypoint/simcc/coco/simcc_res50_8xb64-210e_coco-256x192.py index 1e1fe440d1..33232a4463 100644 --- a/configs/body_2d_keypoint/simcc/coco/simcc_res50_8xb64-210e_coco-256x192.py +++ b/configs/body_2d_keypoint/simcc/coco/simcc_res50_8xb64-210e_coco-256x192.py @@ -42,7 +42,7 @@ in_channels=2048, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], loss=dict(type='KLDiscretLoss', use_target_weight=True), decoder=codec), diff --git a/configs/body_2d_keypoint/simcc/coco/simcc_vipnas-mbv3_8xb64-210e_coco-256x192.py b/configs/body_2d_keypoint/simcc/coco/simcc_vipnas-mbv3_8xb64-210e_coco-256x192.py index ea61b0fb4f..ba8ba040cb 100644 --- a/configs/body_2d_keypoint/simcc/coco/simcc_vipnas-mbv3_8xb64-210e_coco-256x192.py +++ b/configs/body_2d_keypoint/simcc/coco/simcc_vipnas-mbv3_8xb64-210e_coco-256x192.py @@ -44,7 +44,7 @@ in_channels=160, out_channels=17, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], deconv_type='vipnas', deconv_out_channels=(160, 160, 160), diff --git a/configs/body_2d_keypoint/simcc/mpii/simcc_res50_wo-deconv-8xb64-210e_mpii-256x256.py b/configs/body_2d_keypoint/simcc/mpii/simcc_res50_wo-deconv-8xb64-210e_mpii-256x256.py index 965fda71e6..ef8b47959e 100644 --- a/configs/body_2d_keypoint/simcc/mpii/simcc_res50_wo-deconv-8xb64-210e_mpii-256x256.py +++ b/configs/body_2d_keypoint/simcc/mpii/simcc_res50_wo-deconv-8xb64-210e_mpii-256x256.py @@ -48,7 +48,7 @@ in_channels=2048, out_channels=16, input_size=codec['input_size'], - in_featuremap_size=(8, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], deconv_out_channels=None, loss=dict(type='KLDiscretLoss', use_target_weight=True), diff --git a/configs/body_2d_keypoint/topdown_heatmap/README.md b/configs/body_2d_keypoint/topdown_heatmap/README.md index 9e23b874bc..47aae219e4 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/README.md +++ b/configs/body_2d_keypoint/topdown_heatmap/README.md @@ -115,3 +115,19 @@ Results on PoseTrack2018 val with ground-truth bounding boxes. | HRNet-w48 | 256x192 | 84.6 | [hrnet_posetrack18.md](./posetrack18/hrnet_posetrack18.md) | | HRNet-w32 | 256x192 | 83.4 | [hrnet_posetrack18.md](./posetrack18/hrnet_posetrack18.md) | | ResNet-50 | 256x192 | 81.2 | [resnet_posetrack18.md](./posetrack18/resnet_posetrack18.md) | + +### Human-Art Dataset + +Results on Human-Art validation dataset with detector having human AP of 56.2 on Human-Art validation dataset + +| Model | Input Size | AP | AR | Details and Download | +| :-------: | :--------: | :---: | :---: | :---------------------------------------------------: | +| ViTPose-s | 256x192 | 0.381 | 0.448 | [vitpose_humanart.md](./humanart/vitpose_humanart.md) | +| ViTPose-b | 256x192 | 0.410 | 0.475 | [vitpose_humanart.md](./humanart/vitpose_humanart.md) | + +Results on Human-Art validation dataset with ground-truth bounding-box + +| Model | Input Size | AP | AR | Details and Download | +| :-------: | :--------: | :---: | :---: | :---------------------------------------------------: | +| ViTPose-s | 256x192 | 0.738 | 0.768 | [vitpose_humanart.md](./humanart/vitpose_humanart.md) | +| ViTPose-b | 256x192 | 0.759 | 0.790 | [vitpose_humanart.md](./humanart/vitpose_humanart.md) | diff --git a/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext_udp_coco.md b/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext_udp_coco.md index 213a4669a2..7aad2bf6b3 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext_udp_coco.md +++ b/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext_udp_coco.md @@ -55,14 +55,14 @@ Results on COCO val2017 with detector having human AP of 56.4 on COCO val2017 da | Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | | :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | -| [pose_cspnext_t_udp](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-tiny_udp_8xb256-210e_coco-256x192.py) | 256x192 | 0.665 | 0.874 | 0.723 | 0.723 | 0.917 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_udp-coco_pt-in1k_210e-256x192-0908dd2d_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_udp-coco_pt-in1k_210e-256x192-0908dd2d_20230123.json) | -| [pose_cspnext_s_udp](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-s_udp_8xb256-210e_coco-256x192.py) | 256x192 | 0.697 | 0.886 | 0.776 | 0.753 | 0.929 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_udp-coco_pt-in1k_210e-256x192-92dbfc1d_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_udp-coco_pt-in1k_210e-256x192-92dbfc1d_20230123.json) | -| [pose_cspnext_m_udp](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-m_udp_8xb256-210e_coco-256x192.py) | 256x192 | 0.732 | 0.896 | 0.806 | 0.785 | 0.937 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-coco_pt-in1k_210e-256x192-95f5967e_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-coco_pt-in1k_210e-256x192-95f5967e_20230123.json) | -| [pose_cspnext_l_udp](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-l_udp_8xb256-210e_coco-256x192.py) | 256x192 | 0.750 | 0.904 | 0.822 | 0.800 | 0.941 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_udp-coco_pt-in1k_210e-256x192-661cdd8c_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_udp-coco_pt-in1k_210e-256x192-661cdd8c_20230123.json) | -| [pose_cspnext_t_udp_aic_coco](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-tiny_udp_8xb256-210e_aic-coco-256x192.py) | 256x192 | 0.655 | 0.884 | 0.731 | 0.689 | 0.890 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.json) | -| [pose_cspnext_s_udp_aic_coco](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-s_udp_8xb256-210e_aic-coco-256x192.py) | 256x192 | 0.700 | 0.905 | 0.783 | 0.733 | 0.918 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.json) | -| [pose_cspnext_m_udp_aic_coco](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-m_udp_8xb256-210e_aic-coco-256x192.py) | 256x192 | 0.748 | 0.925 | 0.818 | 0.777 | 0.933 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.json) | -| [pose_cspnext_l_udp_aic_coco](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-l_udp_8xb256-210e_aic-coco-256x192.py) | 256x192 | 0.772 | 0.936 | 0.839 | 0.799 | 0.943 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.json) | +| [pose_cspnext_t_udp](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-tiny_udp_8xb256-210e_coco-256x192.py) | 256x192 | 0.665 | 0.874 | 0.723 | 0.723 | 0.917 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-tiny_udp-coco_pt-in1k_210e-256x192-0908dd2d_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-tiny_udp-coco_pt-in1k_210e-256x192-0908dd2d_20230123.json) | +| [pose_cspnext_s_udp](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-s_udp_8xb256-210e_coco-256x192.py) | 256x192 | 0.697 | 0.886 | 0.776 | 0.753 | 0.929 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-s_udp-coco_pt-in1k_210e-256x192-92dbfc1d_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-s_udp-coco_pt-in1k_210e-256x192-92dbfc1d_20230123.json) | +| [pose_cspnext_m_udp](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-m_udp_8xb256-210e_coco-256x192.py) | 256x192 | 0.732 | 0.896 | 0.806 | 0.785 | 0.937 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-coco_pt-in1k_210e-256x192-95f5967e_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-coco_pt-in1k_210e-256x192-95f5967e_20230123.json) | +| [pose_cspnext_l_udp](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-l_udp_8xb256-210e_coco-256x192.py) | 256x192 | 0.750 | 0.904 | 0.822 | 0.800 | 0.941 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-l_udp-coco_pt-in1k_210e-256x192-661cdd8c_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-l_udp-coco_pt-in1k_210e-256x192-661cdd8c_20230123.json) | +| [pose_cspnext_t_udp_aic_coco](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-tiny_udp_8xb256-210e_aic-coco-256x192.py) | 256x192 | 0.655 | 0.884 | 0.731 | 0.689 | 0.890 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.json) | +| [pose_cspnext_s_udp_aic_coco](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-s_udp_8xb256-210e_aic-coco-256x192.py) | 256x192 | 0.700 | 0.905 | 0.783 | 0.733 | 0.918 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.json) | +| [pose_cspnext_m_udp_aic_coco](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-m_udp_8xb256-210e_aic-coco-256x192.py) | 256x192 | 0.748 | 0.925 | 0.818 | 0.777 | 0.933 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.json) | +| [pose_cspnext_l_udp_aic_coco](/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-l_udp_8xb256-210e_aic-coco-256x192.py) | 256x192 | 0.772 | 0.936 | 0.839 | 0.799 | 0.943 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.json) | Note that, UDP also adopts the unbiased encoding/decoding algorithm of [DARK](https://mmpose.readthedocs.io/en/latest/model_zoo_papers/techniques.html#darkpose-cvpr-2020). diff --git a/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext_udp_coco.yml b/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext_udp_coco.yml index 9db9a46c65..aab5c44e1b 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext_udp_coco.yml +++ b/configs/body_2d_keypoint/topdown_heatmap/coco/cspnext_udp_coco.yml @@ -16,7 +16,7 @@ Models: AR: 0.723 AR@0.5: 0.917 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_udp-coco_pt-in1k_210e-256x192-0908dd2d_20230123.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-tiny_udp-coco_pt-in1k_210e-256x192-0908dd2d_20230123.pth - Config: configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-s_udp_8xb256-210e_coco-256x192.py In Collection: UDP Metadata: @@ -32,7 +32,7 @@ Models: AR: 0.753 AR@0.5: 0.929 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_udp-coco_pt-in1k_210e-256x192-92dbfc1d_20230123.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-s_udp-coco_pt-in1k_210e-256x192-92dbfc1d_20230123.pth - Config: configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-m_udp_8xb256-210e_coco-256x192.py In Collection: UDP Metadata: @@ -48,7 +48,7 @@ Models: AR: 0.785 AR@0.5: 0.937 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-coco_pt-in1k_210e-256x192-95f5967e_20230123.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-coco_pt-in1k_210e-256x192-95f5967e_20230123.pth - Config: configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-l_udp_8xb256-210e_coco-256x192.py In Collection: UDP Metadata: @@ -64,7 +64,7 @@ Models: AR: 0.8 AR@0.5: 0.941 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_udp-coco_pt-in1k_210e-256x192-661cdd8c_20230123.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-l_udp-coco_pt-in1k_210e-256x192-661cdd8c_20230123.pth - Config: configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-tiny_udp_8xb256-210e_aic-coco-256x192.py In Collection: UDP Metadata: @@ -82,7 +82,7 @@ Models: AR: 0.689 AR@0.5: 0.89 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth - Config: configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-s_udp_8xb256-210e_aic-coco-256x192.py In Collection: UDP Metadata: @@ -100,7 +100,7 @@ Models: AR: 0.733 AR@0.5: 0.918 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth - Config: configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-m_udp_8xb256-210e_aic-coco-256x192.py In Collection: UDP Metadata: @@ -118,7 +118,7 @@ Models: AR: 0.777 AR@0.5: 0.933 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth - Config: configs/body_2d_keypoint/topdown_heatmap/coco/cspnext-l_udp_8xb256-210e_aic-coco-256x192.py In Collection: UDP Metadata: @@ -136,4 +136,4 @@ Models: AR: 0.799 AR@0.5: 0.943 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth diff --git a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base-simple_8xb64-210e_coco-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base-simple_8xb64-210e_coco-256x192.py index 13eb5f373a..9732371787 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base-simple_8xb64-210e_coco-256x192.py +++ b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base-simple_8xb64-210e_coco-256x192.py @@ -59,14 +59,14 @@ std=[58.395, 57.12, 57.375], bgr_to_rgb=True), backbone=dict( - type='mmcls.VisionTransformer', + type='mmpretrain.VisionTransformer', arch='base', img_size=(256, 192), patch_size=16, qkv_bias=True, drop_path_rate=0.3, with_cls_token=False, - output_cls_token=False, + out_type='featmap', patch_cfg=dict(padding=2), init_cfg=dict( type='Pretrained', diff --git a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192.py index 8725fa2ca0..fc08c61dff 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192.py +++ b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192.py @@ -59,14 +59,14 @@ std=[58.395, 57.12, 57.375], bgr_to_rgb=True), backbone=dict( - type='mmcls.VisionTransformer', + type='mmpretrain.VisionTransformer', arch='base', img_size=(256, 192), patch_size=16, qkv_bias=True, drop_path_rate=0.3, with_cls_token=False, - output_cls_token=False, + out_type='featmap', patch_cfg=dict(padding=2), init_cfg=dict( type='Pretrained', diff --git a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge-simple_8xb64-210e_coco-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge-simple_8xb64-210e_coco-256x192.py index 9539de25c4..7d94f97c1b 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge-simple_8xb64-210e_coco-256x192.py +++ b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge-simple_8xb64-210e_coco-256x192.py @@ -59,14 +59,14 @@ std=[58.395, 57.12, 57.375], bgr_to_rgb=True), backbone=dict( - type='mmcls.VisionTransformer', + type='mmpretrain.VisionTransformer', arch='huge', img_size=(256, 192), patch_size=16, qkv_bias=True, drop_path_rate=0.55, with_cls_token=False, - output_cls_token=False, + out_type='featmap', patch_cfg=dict(padding=2), init_cfg=dict( type='Pretrained', diff --git a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192.py index 1953188a19..4aa2c21c1f 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192.py +++ b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192.py @@ -59,14 +59,14 @@ std=[58.395, 57.12, 57.375], bgr_to_rgb=True), backbone=dict( - type='mmcls.VisionTransformer', + type='mmpretrain.VisionTransformer', arch='huge', img_size=(256, 192), patch_size=16, qkv_bias=True, drop_path_rate=0.55, with_cls_token=False, - output_cls_token=False, + out_type='featmap', patch_cfg=dict(padding=2), init_cfg=dict( type='Pretrained', diff --git a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large-simple_8xb64-210e_coco-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large-simple_8xb64-210e_coco-256x192.py index 8086b09410..cf875d5167 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large-simple_8xb64-210e_coco-256x192.py +++ b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large-simple_8xb64-210e_coco-256x192.py @@ -59,14 +59,14 @@ std=[58.395, 57.12, 57.375], bgr_to_rgb=True), backbone=dict( - type='mmcls.VisionTransformer', + type='mmpretrain.VisionTransformer', arch='large', img_size=(256, 192), patch_size=16, qkv_bias=True, drop_path_rate=0.5, with_cls_token=False, - output_cls_token=False, + out_type='featmap', patch_cfg=dict(padding=2), init_cfg=dict( type='Pretrained', diff --git a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large_8xb64-210e_coco-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large_8xb64-210e_coco-256x192.py index 43d5df7154..5ba6eafb4b 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large_8xb64-210e_coco-256x192.py +++ b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large_8xb64-210e_coco-256x192.py @@ -59,14 +59,14 @@ std=[58.395, 57.12, 57.375], bgr_to_rgb=True), backbone=dict( - type='mmcls.VisionTransformer', + type='mmpretrain.VisionTransformer', arch='large', img_size=(256, 192), patch_size=16, qkv_bias=True, drop_path_rate=0.5, with_cls_token=False, - output_cls_token=False, + out_type='featmap', patch_cfg=dict(padding=2), init_cfg=dict( type='Pretrained', diff --git a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small-simple_8xb64-210e_coco-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small-simple_8xb64-210e_coco-256x192.py index b57b0d3735..88bd3e43e3 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small-simple_8xb64-210e_coco-256x192.py +++ b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small-simple_8xb64-210e_coco-256x192.py @@ -59,7 +59,7 @@ std=[58.395, 57.12, 57.375], bgr_to_rgb=True), backbone=dict( - type='mmcls.VisionTransformer', + type='mmpretrain.VisionTransformer', arch={ 'embed_dims': 384, 'num_layers': 12, @@ -71,7 +71,7 @@ qkv_bias=True, drop_path_rate=0.1, with_cls_token=False, - output_cls_token=False, + out_type='featmap', patch_cfg=dict(padding=2), init_cfg=dict( type='Pretrained', diff --git a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192.py index 5d08a31a02..791f9b5945 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192.py +++ b/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192.py @@ -59,7 +59,7 @@ std=[58.395, 57.12, 57.375], bgr_to_rgb=True), backbone=dict( - type='mmcls.VisionTransformer', + type='mmpretrain.VisionTransformer', arch={ 'embed_dims': 384, 'num_layers': 12, @@ -71,7 +71,7 @@ qkv_bias=True, drop_path_rate=0.1, with_cls_token=False, - output_cls_token=False, + out_type='featmap', patch_cfg=dict(padding=2), init_cfg=dict( type='Pretrained', diff --git a/configs/body_2d_keypoint/topdown_heatmap/coco/vitpose_coco.md b/configs/body_2d_keypoint/topdown_heatmap/coco/vitpose_coco.md index f9266001d5..68baf35aec 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/coco/vitpose_coco.md +++ b/configs/body_2d_keypoint/topdown_heatmap/coco/vitpose_coco.md @@ -1,14 +1,13 @@ -To utilize ViTPose, you'll need to have [MMClassification](https://github.com/open-mmlab/mmclassification). To install the required version, run the following command: +To utilize ViTPose, you'll need to have [MMPreTrain](https://github.com/open-mmlab/mmpretrain). To install the required version, run the following command: ```shell -mim install 'mmcls>=1.0.0rc5' +mim install 'mmpretrain>=1.0.0' ```
- -ViTPose (NeurIPS'2022) +ViTPose (NeurIPS'2022) ```bibtex @inproceedings{ @@ -58,5 +57,5 @@ Results on COCO val2017 with detector having human AP of 56.4 on COCO val2017 da | :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | | [ViTPose-S](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small-simple_8xb64-210e_coco-256x192.py) | 256x192 | 0.736 | 0.900 | 0.811 | 0.790 | 0.940 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small-simple_8xb64-210e_coco-256x192-4c101a76_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small-simple_8xb64-210e_coco-256x192-4c101a76_20230314.json) | | [ViTPose-B](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base-simple_8xb64-210e_coco-256x192.py) | 256x192 | 0.756 | 0.906 | 0.826 | 0.809 | 0.946 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base-simple_8xb64-210e_coco-256x192-0b8234ea_20230407.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base-simple_8xb64-210e_coco-256x192-0b8234ea_20230407.json) | -| [ViTPose-L](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large-simple_8xb64-210e_coco-256x192.py) | 256x192 | 0.781 | 0.914 | 0.853 | 0.833 | 0.952 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large-simple_8xb64-210e_coco-256x192-3a7ee9e1_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large-simple_8xb64-210e_coco-256x192-3a7ee9e1_20230314.json) | +| [ViTPose-L](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large-simple_8xb64-210e_coco-256x192.py) | 256x192 | 0.780 | 0.914 | 0.851 | 0.833 | 0.952 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large-simple_8xb64-210e_coco-256x192-3a7ee9e1_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large-simple_8xb64-210e_coco-256x192-3a7ee9e1_20230314.json) | | [ViTPose-H](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge-simple_8xb64-210e_coco-256x192.py) | 256x192 | 0.789 | 0.916 | 0.856 | 0.839 | 0.953 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge-simple_8xb64-210e_coco-256x192-ffd48c05_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge-simple_8xb64-210e_coco-256x192-ffd48c05_20230314.json) | diff --git a/configs/body_2d_keypoint/topdown_heatmap/coco/vitpose_coco.yml b/configs/body_2d_keypoint/topdown_heatmap/coco/vitpose_coco.yml index 6d1cc7db15..10cc7bf972 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/coco/vitpose_coco.yml +++ b/configs/body_2d_keypoint/topdown_heatmap/coco/vitpose_coco.yml @@ -128,9 +128,9 @@ Models: Results: - Dataset: COCO Metrics: - AP: 0.781 + AP: 0.780 AP@0.5: 0.914 - AP@0.75: 0.853 + AP@0.75: 0.851 AR: 0.833 AR@0.5: 0.952 Task: Body 2D Keypoint diff --git a/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext-m_udp_8xb64-210e_crowpose-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext-m_udp_8xb64-210e_crowpose-256x192.py index b1ba19a130..b083719303 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext-m_udp_8xb64-210e_crowpose-256x192.py +++ b/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext-m_udp_8xb64-210e_crowpose-256x192.py @@ -24,7 +24,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, diff --git a/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext_udp_crowdpose.md b/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext_udp_crowdpose.md index 80cf3466ca..24c3534838 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext_udp_crowdpose.md +++ b/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext_udp_crowdpose.md @@ -53,4 +53,4 @@ Results on CrowdPose test with [YOLOv3](https://github.com/eriklindernoren/PyTor | Arch | Input Size | AP | AP50 | AP75 | AP (E) | AP (M) | AP (H) | ckpt | log | | :--------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :----: | :----: | :----: | :--------------------------------------------: | :-------------------------------------------: | -| [pose_cspnext_m](/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext-m_udp_8xb64-210e_crowpose-256x192.py) | 256x192 | 0.662 | 0.821 | 0.723 | 0.759 | 0.675 | 0.539 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-crowdpose_pt-in1k_210e-256x192-f591079f_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-crowdpose_pt-in1k_210e-256x192-f591079f_20230123.json) | +| [pose_cspnext_m](/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext-m_udp_8xb64-210e_crowpose-256x192.py) | 256x192 | 0.662 | 0.821 | 0.723 | 0.759 | 0.675 | 0.539 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-crowdpose_pt-in1k_210e-256x192-f591079f_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-crowdpose_pt-in1k_210e-256x192-f591079f_20230123.json) | diff --git a/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext_udp_crowdpose.yml b/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext_udp_crowdpose.yml index 0dd4538134..6e5b4cd691 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext_udp_crowdpose.yml +++ b/configs/body_2d_keypoint/topdown_heatmap/crowdpose/cspnext_udp_crowdpose.yml @@ -17,4 +17,4 @@ Models: AP@0.5: 0.821 AP@0.75: 0.723 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-crowdpose_pt-in1k_210e-256x192-f591079f_20230123.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-crowdpose_pt-in1k_210e-256x192-f591079f_20230123.pth diff --git a/configs/body_2d_keypoint/topdown_heatmap/humanart/hrnet_humanart.md b/configs/body_2d_keypoint/topdown_heatmap/humanart/hrnet_humanart.md new file mode 100644 index 0000000000..6e5f3476cb --- /dev/null +++ b/configs/body_2d_keypoint/topdown_heatmap/humanart/hrnet_humanart.md @@ -0,0 +1,80 @@ + + +
+HRNet (CVPR'2019) + +```bibtex +@inproceedings{sun2019deep, + title={Deep high-resolution representation learning for human pose estimation}, + author={Sun, Ke and Xiao, Bin and Liu, Dong and Wang, Jingdong}, + booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, + pages={5693--5703}, + year={2019} +} +``` + +
+ + + +
+COCO (ECCV'2014) + +```bibtex +@inproceedings{lin2014microsoft, + title={Microsoft coco: Common objects in context}, + author={Lin, Tsung-Yi and Maire, Michael and Belongie, Serge and Hays, James and Perona, Pietro and Ramanan, Deva and Doll{\'a}r, Piotr and Zitnick, C Lawrence}, + booktitle={European conference on computer vision}, + pages={740--755}, + year={2014}, + organization={Springer} +} +``` + +
+ +
+Human-Art (CVPR'2023) + +```bibtex +@inproceedings{ju2023humanart, + title={Human-Art: A Versatile Human-Centric Dataset Bridging Natural and Artificial Scenes}, + author={Ju, Xuan and Zeng, Ailing and Jianan, Wang and Qiang, Xu and Lei, Zhang}, + booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), + year={2023}} +``` + +
+ +Results on Human-Art validation dataset with detector having human AP of 56.2 on Human-Art validation dataset + +> With classic decoder + +| Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | +| :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | +| [pose_hrnet_w32-coco](configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192.py) | 256x192 | 0.252 | 0.397 | 0.255 | 0.321 | 0.485 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192-81c58e40_20220909.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192_20220909.log) | +| [pose_hrnet_w32-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w32_8xb64-210e_humanart-256x192.py) | 256x192 | 0.399 | 0.545 | 0.420 | 0.466 | 0.613 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w32_8xb64-210e_humanart-256x192-0773ef0b_20230614.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w32_8xb64-210e_humanart-256x192-0773ef0b_20230614.json) | +| [pose_hrnet_w48-coco](configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_8xb32-210e_coco-256x192.py) | 256x192 | 0.271 | 0.413 | 0.277 | 0.339 | 0.499 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_8xb32-210e_coco-256x192-0e67c616_20220913.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_8xb32-210e_coco-256x192_20220913.log) | +| [pose_hrnet_w48-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w48_8xb32-210e_humanart-256x192.py) | 256x192 | 0.417 | 0.553 | 0.442 | 0.481 | 0.617 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w48_8xb32-210e_humanart-256x192-05178983_20230614.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w48_8xb32-210e_humanart-256x192-05178983_20230614.json) | + +Results on Human-Art validation dataset with ground-truth bounding-box + +> With classic decoder + +| Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | +| :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | +| [pose_hrnet_w32-coco](configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192.py) | 256x192 | 0.533 | 0.771 | 0.562 | 0.574 | 0.792 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192-81c58e40_20220909.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192_20220909.log) | +| [pose_hrnet_w32-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w32_8xb64-210e_humanart-256x192.py) | 256x192 | 0.754 | 0.906 | 0.812 | 0.783 | 0.916 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w32_8xb64-210e_humanart-256x192-0773ef0b_20230614.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w32_8xb64-210e_humanart-256x192-0773ef0b_20230614.json) | +| [pose_hrnet_w48-coco](configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_8xb32-210e_coco-256x192.py) | 256x192 | 0.557 | 0.782 | 0.593 | 0.595 | 0.804 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_8xb32-210e_coco-256x192-0e67c616_20220913.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_8xb32-210e_coco-256x192_20220913.log) | +| [pose_hrnet_w48-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w48_8xb32-210e_humanart-256x192.py) | 256x192 | 0.769 | 0.906 | 0.825 | 0.796 | 0.919 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w48_8xb32-210e_humanart-256x192-05178983_20230614.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w48_8xb32-210e_humanart-256x192-05178983_20230614.json) | + +Results on COCO val2017 with detector having human AP of 56.4 on COCO val2017 dataset + +> With classic decoder + +| Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | +| :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | +| [pose_hrnet_w32-coco](configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192.py) | 256x192 | 0.749 | 0.906 | 0.821 | 0.804 | 0.945 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192-81c58e40_20220909.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192_20220909.log) | +| [pose_hrnet_w32-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w32_8xb64-210e_humanart-256x192.py) | 256x192 | 0.741 | 0.902 | 0.814 | 0.795 | 0.941 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w32_8xb64-210e_humanart-256x192-0773ef0b_20230614.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w32_8xb64-210e_humanart-256x192-0773ef0b_20230614.json) | +| [pose_hrnet_w48-coco](configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_8xb32-210e_coco-256x192.py) | 256x192 | 0.756 | 0.908 | 0.826 | 0.809 | 0.945 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_8xb32-210e_coco-256x192-0e67c616_20220913.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_8xb32-210e_coco-256x192_20220913.log) | +| [pose_hrnet_w48-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w48_8xb32-210e_humanart-256x192.py) | 256x192 | 0.751 | 0.905 | 0.822 | 0.805 | 0.943 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w48_8xb32-210e_humanart-256x192-05178983_20230614.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w48_8xb32-210e_humanart-256x192-05178983_20230614.json) | diff --git a/configs/body_2d_keypoint/topdown_heatmap/humanart/hrnet_humanart.yml b/configs/body_2d_keypoint/topdown_heatmap/humanart/hrnet_humanart.yml new file mode 100755 index 0000000000..08aa3f1f47 --- /dev/null +++ b/configs/body_2d_keypoint/topdown_heatmap/humanart/hrnet_humanart.yml @@ -0,0 +1,74 @@ +Collections: +- Name: HRNet + Paper: + Title: Deep high-resolution representation learning for human pose estimation + URL: http://openaccess.thecvf.com/content_CVPR_2019/html/Sun_Deep_High-Resolution_Representation_Learning_for_Human_Pose_Estimation_CVPR_2019_paper.html + README: https://github.com/open-mmlab/mmpose/blob/main/docs/src/papers/backbones/hrnet.md +Models: +- Config: configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w32_8xb64-210e_humanart-256x192.py + In Collection: HRNet + Metadata: + Architecture: &id001 + - HRNet + Training Data: &id002 + - COCO + - Human-Art + Name: td-hm_hrnet-w32_8xb64-210e_humanart-256x192 + Results: + - Dataset: COCO + Metrics: + AP: 0.741 + AP@0.5: 0.902 + AP@0.75: 0.814 + AR: 0.795 + AR@0.5: 0.941 + Task: Body 2D Keypoint + - Dataset: Human-Art + Metrics: + AP: 0.399 + AP@0.5: 0.545 + AP@0.75: 0.420 + AR: 0.466 + AR@0.5: 0.613 + Task: Body 2D Keypoint + - Dataset: Human-Art(GT) + Metrics: + AP: 0.754 + AP@0.5: 0.906 + AP@0.75: 0.812 + AR: 0.783 + AR@0.5: 0.916 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w32_8xb64-210e_humanart-256x192-0773ef0b_20230614.pth +- Config: configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w48_8xb32-210e_humanart-256x192.py + In Collection: HRNet + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: td-hm_hrnet-w48_8xb32-210e_humanart-256x192 + Results: + - Dataset: COCO + Metrics: + AP: 0.751 + AP@0.5: 0.905 + AP@0.75: 0.822 + AR: 0.805 + AR@0.5: 0.943 + Task: Body 2D Keypoint + - Dataset: Human-Art + Metrics: + AP: 0.417 + AP@0.5: 0.553 + AP@0.75: 0.442 + AR: 0.481 + AR@0.5: 0.617 + Task: Body 2D Keypoint + - Dataset: Human-Art(GT) + Metrics: + AP: 0.769 + AP@0.5: 0.906 + AP@0.75: 0.825 + AR: 0.796 + AR@0.5: 0.919 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_hrnet-w48_8xb32-210e_humanart-256x192-05178983_20230614.pth diff --git a/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-base_8xb64-210e_humanart-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-base_8xb64-210e_humanart-256x192.py new file mode 100644 index 0000000000..4aa431e044 --- /dev/null +++ b/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-base_8xb64-210e_humanart-256x192.py @@ -0,0 +1,150 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +custom_imports = dict( + imports=['mmpose.engine.optim_wrappers.layer_decay_optim_wrapper'], + allow_failed_imports=False) + +optim_wrapper = dict( + optimizer=dict( + type='AdamW', lr=5e-4, betas=(0.9, 0.999), weight_decay=0.1), + paramwise_cfg=dict( + num_layers=12, + layer_decay_rate=0.75, + custom_keys={ + 'bias': dict(decay_multi=0.0), + 'pos_embed': dict(decay_mult=0.0), + 'relative_position_bias_table': dict(decay_mult=0.0), + 'norm': dict(decay_mult=0.0), + }, + ), + constructor='LayerDecayOptimWrapperConstructor', + clip_grad=dict(max_norm=1., norm_type=2), +) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) + +# codec settings +codec = dict( + type='UDPHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='mmpretrain.VisionTransformer', + arch='base', + img_size=(256, 192), + patch_size=16, + qkv_bias=True, + drop_path_rate=0.3, + with_cls_token=False, + out_type='featmap', + patch_cfg=dict(padding=2), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'v1/pretrained_models/mae_pretrain_vit_base.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=768, + out_channels=17, + deconv_out_channels=(256, 256), + deconv_kernel_sizes=(4, 4), + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=False, + )) + +# base dataset settings +data_root = 'data/' +dataset_type = 'HumanArtDataset' +data_mode = 'topdown' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size'], use_udp=True), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size'], use_udp=True), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=4, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/training_humanart_coco.json', + data_prefix=dict(img=''), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=4, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/validation_humanart.json', + bbox_file=f'{data_root}HumanArt/person_detection_results/' + 'HumanArt_validation_detections_AP_H_56_person.json', + data_prefix=dict(img=''), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'HumanArt/annotations/validation_humanart.json') +test_evaluator = val_evaluator diff --git a/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192.py new file mode 100644 index 0000000000..925f68e3d1 --- /dev/null +++ b/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192.py @@ -0,0 +1,150 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +custom_imports = dict( + imports=['mmpose.engine.optim_wrappers.layer_decay_optim_wrapper'], + allow_failed_imports=False) + +optim_wrapper = dict( + optimizer=dict( + type='AdamW', lr=5e-4, betas=(0.9, 0.999), weight_decay=0.1), + paramwise_cfg=dict( + num_layers=32, + layer_decay_rate=0.85, + custom_keys={ + 'bias': dict(decay_multi=0.0), + 'pos_embed': dict(decay_mult=0.0), + 'relative_position_bias_table': dict(decay_mult=0.0), + 'norm': dict(decay_mult=0.0), + }, + ), + constructor='LayerDecayOptimWrapperConstructor', + clip_grad=dict(max_norm=1., norm_type=2), +) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) + +# codec settings +codec = dict( + type='UDPHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='mmcls.VisionTransformer', + arch='huge', + img_size=(256, 192), + patch_size=16, + qkv_bias=True, + drop_path_rate=0.55, + with_cls_token=False, + output_cls_token=False, + patch_cfg=dict(padding=2), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'v1/pretrained_models/mae_pretrain_vit_huge.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=1280, + out_channels=17, + deconv_out_channels=(256, 256), + deconv_kernel_sizes=(4, 4), + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=False, + )) + +# base dataset settings +data_root = 'data/' +dataset_type = 'HumanArtDataset' +data_mode = 'topdown' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size'], use_udp=True), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size'], use_udp=True), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=4, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/training_humanart_coco.json', + data_prefix=dict(img=''), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=4, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/validation_humanart.json', + bbox_file=f'{data_root}HumanArt/person_detection_results/' + 'HumanArt_validation_detections_AP_H_56_person.json', + data_prefix=dict(img=''), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'HumanArt/annotations/validation_humanart.json') +test_evaluator = val_evaluator diff --git a/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-large_8xb64-210e_humanart-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-large_8xb64-210e_humanart-256x192.py new file mode 100644 index 0000000000..7ea9dbf395 --- /dev/null +++ b/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-large_8xb64-210e_humanart-256x192.py @@ -0,0 +1,150 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +custom_imports = dict( + imports=['mmpose.engine.optim_wrappers.layer_decay_optim_wrapper'], + allow_failed_imports=False) + +optim_wrapper = dict( + optimizer=dict( + type='AdamW', lr=5e-4, betas=(0.9, 0.999), weight_decay=0.1), + paramwise_cfg=dict( + num_layers=24, + layer_decay_rate=0.8, + custom_keys={ + 'bias': dict(decay_multi=0.0), + 'pos_embed': dict(decay_mult=0.0), + 'relative_position_bias_table': dict(decay_mult=0.0), + 'norm': dict(decay_mult=0.0), + }, + ), + constructor='LayerDecayOptimWrapperConstructor', + clip_grad=dict(max_norm=1., norm_type=2), +) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) + +# codec settings +codec = dict( + type='UDPHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='mmcls.VisionTransformer', + arch='large', + img_size=(256, 192), + patch_size=16, + qkv_bias=True, + drop_path_rate=0.5, + with_cls_token=False, + output_cls_token=False, + patch_cfg=dict(padding=2), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'v1/pretrained_models/mae_pretrain_vit_large.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=1024, + out_channels=17, + deconv_out_channels=(256, 256), + deconv_kernel_sizes=(4, 4), + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=False, + )) + +# base dataset settings +data_root = 'data/' +dataset_type = 'HumanArtDataset' +data_mode = 'topdown' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size'], use_udp=True), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size'], use_udp=True), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=4, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/training_humanart_coco.json', + data_prefix=dict(img=''), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=4, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/validation_humanart.json', + bbox_file=f'{data_root}HumanArt/person_detection_results/' + 'HumanArt_validation_detections_AP_H_56_person.json', + data_prefix=dict(img=''), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'HumanArt/annotations/validation_humanart.json') +test_evaluator = val_evaluator diff --git a/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-small_8xb64-210e_humanart-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-small_8xb64-210e_humanart-256x192.py new file mode 100644 index 0000000000..ed7817d2fe --- /dev/null +++ b/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-small_8xb64-210e_humanart-256x192.py @@ -0,0 +1,155 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +custom_imports = dict( + imports=['mmpose.engine.optim_wrappers.layer_decay_optim_wrapper'], + allow_failed_imports=False) + +optim_wrapper = dict( + optimizer=dict( + type='AdamW', lr=5e-4, betas=(0.9, 0.999), weight_decay=0.1), + paramwise_cfg=dict( + num_layers=12, + layer_decay_rate=0.8, + custom_keys={ + 'bias': dict(decay_multi=0.0), + 'pos_embed': dict(decay_mult=0.0), + 'relative_position_bias_table': dict(decay_mult=0.0), + 'norm': dict(decay_mult=0.0), + }, + ), + constructor='LayerDecayOptimWrapperConstructor', + clip_grad=dict(max_norm=1., norm_type=2), +) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) + +# codec settings +codec = dict( + type='UDPHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='mmpretrain.VisionTransformer', + arch={ + 'embed_dims': 384, + 'num_layers': 12, + 'num_heads': 12, + 'feedforward_channels': 384 * 4 + }, + img_size=(256, 192), + patch_size=16, + qkv_bias=True, + drop_path_rate=0.1, + with_cls_token=False, + out_type='featmap', + patch_cfg=dict(padding=2), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'v1/pretrained_models/mae_pretrain_vit_small.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=384, + out_channels=17, + deconv_out_channels=(256, 256), + deconv_kernel_sizes=(4, 4), + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=False, + )) + +# base dataset settings +data_root = 'data/' +dataset_type = 'HumanArtDataset' +data_mode = 'topdown' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size'], use_udp=True), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size'], use_udp=True), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=4, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/training_humanart_coco.json', + data_prefix=dict(img=''), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=4, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/validation_humanart.json', + bbox_file=f'{data_root}HumanArt/person_detection_results/' + 'HumanArt_validation_detections_AP_H_56_person.json', + data_prefix=dict(img=''), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'HumanArt/annotations/validation_humanart.json') +test_evaluator = val_evaluator diff --git a/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w32_8xb64-210e_humanart-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w32_8xb64-210e_humanart-256x192.py new file mode 100644 index 0000000000..bf9fa25beb --- /dev/null +++ b/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w32_8xb64-210e_humanart-256x192.py @@ -0,0 +1,150 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict(checkpoint=dict(save_best='coco/AP', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='HRNet', + in_channels=3, + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(32, 64)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(32, 64, 128)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(32, 64, 128, 256))), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'pretrain_models/hrnet_w32-36af842e.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=32, + out_channels=17, + deconv_out_channels=None, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'HumanArtDataset' +data_mode = 'topdown' +data_root = 'data/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/training_humanart_coco.json', + data_prefix=dict(img=''), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/validation_humanart.json', + bbox_file=f'{data_root}HumanArt/person_detection_results/' + 'HumanArt_validation_detections_AP_H_56_person.json', + data_prefix=dict(img=''), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'HumanArt/annotations/validation_humanart.json') +test_evaluator = val_evaluator diff --git a/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w48_8xb32-210e_humanart-256x192.py b/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w48_8xb32-210e_humanart-256x192.py new file mode 100644 index 0000000000..6a5ae0707c --- /dev/null +++ b/configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_hrnet-w48_8xb32-210e_humanart-256x192.py @@ -0,0 +1,150 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict(checkpoint=dict(save_best='coco/AP', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='HRNet', + in_channels=3, + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(48, 96)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(48, 96, 192)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(48, 96, 192, 384))), + init_cfg=dict( + type='Pretrained', + checkpoint='https://download.openmmlab.com/mmpose/' + 'pretrain_models/hrnet_w48-8ef0771d.pth'), + ), + head=dict( + type='HeatmapHead', + in_channels=48, + out_channels=17, + deconv_out_channels=None, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'HumanArtDataset' +data_mode = 'topdown' +data_root = 'data/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/training_humanart_coco.json', + data_prefix=dict(img=''), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='HumanArt/annotations/validation_humanart.json', + bbox_file=f'{data_root}HumanArt/person_detection_results/' + 'HumanArt_validation_detections_AP_H_56_person.json', + data_prefix=dict(img=''), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'HumanArt/annotations/validation_humanart.json') +test_evaluator = val_evaluator diff --git a/configs/body_2d_keypoint/topdown_heatmap/humanart/vitpose_humanart.md b/configs/body_2d_keypoint/topdown_heatmap/humanart/vitpose_humanart.md new file mode 100644 index 0000000000..a4d2dd6c50 --- /dev/null +++ b/configs/body_2d_keypoint/topdown_heatmap/humanart/vitpose_humanart.md @@ -0,0 +1,97 @@ +To utilize ViTPose, you'll need to have [MMPreTrain](https://github.com/open-mmlab/mmpretrain). To install the required version, run the following command: + +```shell +mim install 'mmpretrain>=1.0.0' +``` + + + +
+ +ViTPose (NeurIPS'2022) + +```bibtex +@inproceedings{ + xu2022vitpose, + title={Vi{TP}ose: Simple Vision Transformer Baselines for Human Pose Estimation}, + author={Yufei Xu and Jing Zhang and Qiming Zhang and Dacheng Tao}, + booktitle={Advances in Neural Information Processing Systems}, + year={2022}, +} +``` + +
+ + + +
+COCO-WholeBody (ECCV'2020) + +```bibtex +@inproceedings{jin2020whole, + title={Whole-Body Human Pose Estimation in the Wild}, + author={Jin, Sheng and Xu, Lumin and Xu, Jin and Wang, Can and Liu, Wentao and Qian, Chen and Ouyang, Wanli and Luo, Ping}, + booktitle={Proceedings of the European Conference on Computer Vision (ECCV)}, + year={2020} +} +``` + +
+ +
+Human-Art (CVPR'2023) + +```bibtex +@inproceedings{ju2023humanart, + title={Human-Art: A Versatile Human-Centric Dataset Bridging Natural and Artificial Scenes}, + author={Ju, Xuan and Zeng, Ailing and Jianan, Wang and Qiang, Xu and Lei, Zhang}, + booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), + year={2023}} +``` + +
+ +Results on Human-Art validation dataset with detector having human AP of 56.2 on Human-Art validation dataset + +> With classic decoder + +| Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | +| :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | +| [ViTPose-S-coco](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192.py) | 256x192 | 0.228 | 0.371 | 0.229 | 0.298 | 0.467 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192-62d7a712_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192-62d7a712_20230314.json) | +| [ViTPose-S-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-small_8xb64-210e_humanart-256x192.py) | 256x192 | 0.381 | 0.532 | 0.405 | 0.448 | 0.602 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-small_8xb64-210e_humanart-256x192-5cbe2bfc_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-small_8xb64-210e_humanart-256x192-5cbe2bfc_20230611.json) | +| [ViTPose-B-coco](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192.py) | 256x192 | 0.270 | 0.423 | 0.272 | 0.340 | 0.510 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192-216eae50_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192-216eae50_20230314.json) | +| [ViTPose-B-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-base_8xb64-210e_humanart-256x192.py) | 256x192 | 0.410 | 0.549 | 0.434 | 0.475 | 0.615 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-base_8xb64-210e_humanart-256x192-b417f546_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-base_8xb64-210e_humanart-256x192-b417f546_20230611.json) | +| [ViTPose-L-coco](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192.py) | 256x192 | 0.342 | 0.498 | 0.357 | 0.413 | 0.577 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large_8xb64-210e_coco-256x192-53609f55_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large_8xb64-210e_coco-256x192-53609f55_20230314.json) | +| [ViTPose-L-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-base_8xb64-210e_humanart-256x192.py) | 256x192 | 0.459 | 0.592 | 0.487 | 0.525 | 0.656 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-large_8xb64-210e_humanart-256x192-9aba9345_20230614.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-large_8xb64-210e_humanart-256x192-9aba9345_20230614.json) | +| [ViTPose-H-coco](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192.py) | 256x192 | 0.377 | 0.541 | 0.391 | 0.447 | 0.615 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192-e32adcd4_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192-e32adcd4_20230314.json) | +| [ViTPose-H-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192.py) | 256x192 | 0.468 | 0.594 | 0.498 | 0.534 | 0.655 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192-603bb573_20230612.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192-603bb573_20230612.json) | + +Results on Human-Art validation dataset with ground-truth bounding-box + +> With classic decoder + +| Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | +| :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | +| [ViTPose-S-coco](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192.py) | 256x192 | 0.507 | 0.758 | 0.531 | 0.551 | 0.780 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192-62d7a712_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192-62d7a712_20230314.json) | +| [ViTPose-S-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-small_8xb64-210e_humanart-256x192.py) | 256x192 | 0.738 | 0.905 | 0.802 | 0.768 | 0.911 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-small_8xb64-210e_humanart-256x192-5cbe2bfc_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-small_8xb64-210e_humanart-256x192-5cbe2bfc_20230611.json) | +| [ViTPose-B-coco](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192.py) | 256x192 | 0.555 | 0.782 | 0.590 | 0.599 | 0.809 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192-216eae50_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192-216eae50_20230314.json) | +| [ViTPose-B-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-base_8xb64-210e_humanart-256x192.py) | 256x192 | 0.759 | 0.905 | 0.823 | 0.790 | 0.917 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-base_8xb64-210e_humanart-256x192-b417f546_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-base_8xb64-210e_humanart-256x192-b417f546_20230611.json) | +| [ViTPose-L-coco](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192.py) | 256x192 | 0.637 | 0.838 | 0.689 | 0.677 | 0.859 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large_8xb64-210e_coco-256x192-53609f55_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large_8xb64-210e_coco-256x192-53609f55_20230314.json) | +| [ViTPose-L-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-base_8xb64-210e_humanart-256x192.py) | 256x192 | 0.789 | 0.916 | 0.845 | 0.819 | 0.929 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-large_8xb64-210e_humanart-256x192-9aba9345_20230614.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-large_8xb64-210e_humanart-256x192-9aba9345_20230614.json) | +| [ViTPose-H-coco](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192.py) | 256x192 | 0.665 | 0.860 | 0.715 | 0.701 | 0.871 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192-e32adcd4_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192-e32adcd4_20230314.json) | +| [ViTPose-H-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192.py) | 256x192 | 0.800 | 0.926 | 0.855 | 0.828 | 0.933 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192-603bb573_20230612.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192-603bb573_20230612.json) | + +Results on COCO val2017 with detector having human AP of 56.4 on COCO val2017 dataset + +> With classic decoder + +| Arch | Input Size | AP | AP50 | AP75 | AR | AR50 | ckpt | log | +| :-------------------------------------------- | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :-------------------------------------------: | :-------------------------------------------: | +| [ViTPose-S-coco](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192.py) | 256x192 | 0.739 | 0.903 | 0.816 | 0.792 | 0.942 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192-62d7a712_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-small_8xb64-210e_coco-256x192-62d7a712_20230314.json) | +| [ViTPose-S-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-small_8xb64-210e_humanart-256x192.py) | 256x192 | 0.737 | 0.902 | 0.811 | 0.792 | 0.942 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-small_8xb64-210e_humanart-256x192-5cbe2bfc_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-small_8xb64-210e_humanart-256x192-5cbe2bfc_20230611.json) | +| [ViTPose-B-coco](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192.py) | 256x192 | 0.757 | 0.905 | 0.829 | 0.810 | 0.946 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192-216eae50_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-base_8xb64-210e_coco-256x192-216eae50_20230314.json) | +| [ViTPose-B-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-base_8xb64-210e_humanart-256x192.py) | 256x192 | 0.758 | 0.906 | 0.829 | 0.812 | 0.946 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-base_8xb64-210e_humanart-256x192-b417f546_20230611.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-base_8xb64-210e_humanart-256x192-b417f546_20230611.json) | +| [ViTPose-L-coco](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large_8xb64-210e_coco-256x192.py) | 256x192 | 0.782 | 0.914 | 0.850 | 0.834 | 0.952 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large_8xb64-210e_coco-256x192-53609f55_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-large_8xb64-210e_coco-256x192-53609f55_20230314.json) | +| [ViTPose-L-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-base_8xb64-210e_humanart-256x192.py) | 256x192 | 0.782 | 0.914 | 0.849 | 0.835 | 0.953 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-large_8xb64-210e_humanart-256x192-9aba9345_20230614.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-large_8xb64-210e_humanart-256x192-9aba9345_20230614.json) | +| [ViTPose-H-coco](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192.py) | 256x192 | 0.788 | 0.917 | 0.855 | 0.839 | 0.954 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192-e32adcd4_20230314.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_ViTPose-huge_8xb64-210e_coco-256x192-e32adcd4_20230314.json) | +| [ViTPose-H-humanart-coco](configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192.py) | 256x192 | 0.788 | 0.914 | 0.853 | 0.841 | 0.956 | [ckpt](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192-603bb573_20230612.pth) | [log](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192-603bb573_20230612.json) | diff --git a/configs/body_2d_keypoint/topdown_heatmap/humanart/vitpose_humanart.yml b/configs/body_2d_keypoint/topdown_heatmap/humanart/vitpose_humanart.yml new file mode 100644 index 0000000000..cbbe965c2d --- /dev/null +++ b/configs/body_2d_keypoint/topdown_heatmap/humanart/vitpose_humanart.yml @@ -0,0 +1,145 @@ +Collections: +- Name: ViTPose + Paper: + Title: 'ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation' + URL: https://arxiv.org/abs/2204.12484 + README: https://github.com/open-mmlab/mmpose/blob/main/docs/src/papers/algorithms/vitpose.md + Metadata: + Training Resources: 8x A100 GPUs +Models: +- Config: configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-small_8xb64-210e_humanart-256x192.py + In Collection: ViTPose + Metadata: + Architecture: &id001 + - ViTPose + - Classic Head + Model Size: Small + Training Data: &id002 + - COCO + - Human-Art + Name: td-hm_ViTPose-small_8xb64-210e_humanart-256x192 + Results: + - Dataset: COCO + Metrics: + AP: 0.737 + AP@0.5: 0.902 + AP@0.75: 0.811 + AR: 0.792 + AR@0.5: 0.942 + Task: Body 2D Keypoint + - Dataset: Human-Art + Metrics: + AP: 0.381 + AP@0.5: 0.532 + AP@0.75: 0.405 + AR: 0.448 + AR@0.5: 0.602 + Task: Body 2D Keypoint + - Dataset: Human-Art(GT) + Metrics: + AP: 0.738 + AP@0.5: 0.905 + AP@0.75: 0.802 + AR: 0.768 + AR@0.5: 0.911 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-small_8xb64-210e_humanart-256x192-5cbe2bfc_20230611.pth +- Config: configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-base_8xb64-210e_humanart-256x192.py + In Collection: ViTPose + Metadata: + Architecture: *id001 + Model Size: Base + Training Data: *id002 + Name: td-hm_ViTPose-base_8xb64-210e_humanart-256x192 + Results: + - Dataset: COCO + Metrics: + AP: 0.758 + AP@0.5: 0.906 + AP@0.75: 0.829 + AR: 0.812 + AR@0.5: 0.946 + Task: Body 2D Keypoint + - Dataset: Human-Art + Metrics: + AP: 0.410 + AP@0.5: 0.549 + AP@0.75: 0.434 + AR: 0.475 + AR@0.5: 0.615 + Task: Body 2D Keypoint + - Dataset: Human-Art(GT) + Metrics: + AP: 0.759 + AP@0.5: 0.905 + AP@0.75: 0.823 + AR: 0.790 + AR@0.5: 0.917 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-base_8xb64-210e_humanart-256x192-b417f546_20230611.pth +- Config: configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-large_8xb64-210e_humanart-256x192.py + In Collection: ViTPose + Metadata: + Architecture: *id001 + Model Size: Large + Training Data: *id002 + Name: td-hm_ViTPose-large_8xb64-210e_humanart-256x192 + Results: + - Dataset: COCO + Metrics: + AP: 0.782 + AP@0.5: 0.914 + AP@0.75: 0.849 + AR: 0.835 + AR@0.5: 0.953 + Task: Body 2D Keypoint + - Dataset: Human-Art + Metrics: + AP: 0.459 + AP@0.5: 0.592 + AP@0.75: 0.487 + AR: 0.525 + AR@0.5: 0.656 + Task: Body 2D Keypoint + - Dataset: Human-Art(GT) + Metrics: + AP: 0.789 + AP@0.5: 0.916 + AP@0.75: 0.845 + AR: 0.819 + AR@0.5: 0.929 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-large_8xb64-210e_humanart-256x192-9aba9345_20230614.pth +- Config: configs/body_2d_keypoint/topdown_heatmap/humanart/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192.py + In Collection: ViTPose + Metadata: + Architecture: *id001 + Model Size: Huge + Training Data: *id002 + Name: td-hm_ViTPose-huge_8xb64-210e_humanart-256x192 + Results: + - Dataset: COCO + Metrics: + AP: 0.788 + AP@0.5: 0.914 + AP@0.75: 0.853 + AR: 0.841 + AR@0.5: 0.956 + Task: Body 2D Keypoint + - Dataset: Human-Art + Metrics: + AP: 0.468 + AP@0.5: 0.594 + AP@0.75: 0.498 + AR: 0.534 + AR@0.5: 0.655 + Task: Body 2D Keypoint + - Dataset: Human-Art(GT) + Metrics: + AP: 0.800 + AP@0.5: 0.926 + AP@0.75: 0.855 + AR: 0.828 + AR@0.5: 0.933 + Task: Body 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/human_art/td-hm_ViTPose-huge_8xb64-210e_humanart-256x192-603bb573_20230612.pth diff --git a/configs/body_2d_keypoint/topdown_heatmap/mpii/cspnext_udp_mpii.md b/configs/body_2d_keypoint/topdown_heatmap/mpii/cspnext_udp_mpii.md index 895de8119a..80aec4c28e 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/mpii/cspnext_udp_mpii.md +++ b/configs/body_2d_keypoint/topdown_heatmap/mpii/cspnext_udp_mpii.md @@ -54,4 +54,4 @@ Results on MPII val set | Arch | Input Size | Mean | Mean@0.1 | ckpt | log | | :---------------------------------------------------------- | :--------: | :---: | :------: | :---------------------------------------------------------: | :---------------------------------------------------------: | -| [pose_hrnet_w32](/configs/body_2d_keypoint/topdown_heatmap/mpii/cspnext-m_udp_8xb64-210e_mpii-256x256.py) | 256x256 | 0.902 | 0.303 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-mpii_pt-in1k_210e-256x256-68d0402f_20230208.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-mpii_pt-in1k_210e-256x256-68d0402f_20230208.json) | +| [pose_hrnet_w32](/configs/body_2d_keypoint/topdown_heatmap/mpii/cspnext-m_udp_8xb64-210e_mpii-256x256.py) | 256x256 | 0.902 | 0.303 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-mpii_pt-in1k_210e-256x256-68d0402f_20230208.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-mpii_pt-in1k_210e-256x256-68d0402f_20230208.json) | diff --git a/configs/body_2d_keypoint/topdown_heatmap/mpii/cspnext_udp_mpii.yml b/configs/body_2d_keypoint/topdown_heatmap/mpii/cspnext_udp_mpii.yml index b31e42b8af..7256f3b154 100644 --- a/configs/body_2d_keypoint/topdown_heatmap/mpii/cspnext_udp_mpii.yml +++ b/configs/body_2d_keypoint/topdown_heatmap/mpii/cspnext_udp_mpii.yml @@ -13,4 +13,4 @@ Models: Mean: 0.902 Mean@0.1: 0.303 Task: Body 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-mpii_pt-in1k_210e-256x256-68d0402f_20230208.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-mpii_pt-in1k_210e-256x256-68d0402f_20230208.pth diff --git a/configs/body_3d_keypoint/README.md b/configs/body_3d_keypoint/README.md index 698e970cb3..b67f7ce7ac 100644 --- a/configs/body_3d_keypoint/README.md +++ b/configs/body_3d_keypoint/README.md @@ -8,6 +8,6 @@ Please follow [DATA Preparation](/docs/en/dataset_zoo/3d_body_keypoint.md) to pr ## Demo -Please follow [Demo](/demo/docs/3d_human_pose_demo.md) to run demos. +Please follow [Demo](/demo/docs/en/3d_human_pose_demo.md) to run demos.
diff --git a/configs/body_3d_keypoint/pose_lift/README.md b/configs/body_3d_keypoint/pose_lift/README.md new file mode 100644 index 0000000000..7e5f9f7e2a --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/README.md @@ -0,0 +1,51 @@ +# Single-view 3D Human Body Pose Estimation + +## Video-based Single-view 3D Human Body Pose Estimation + +Video-based 3D pose estimation is the detection and analysis of X, Y, Z coordinates of human body joints from a sequence of RGB images. + +For single-person 3D pose estimation from a monocular camera, existing works can be classified into three categories: + +(1) from 2D poses to 3D poses (2D-to-3D pose lifting) + +(2) jointly learning 2D and 3D poses, and + +(3) directly regressing 3D poses from images. + +### Results and Models + +#### Human3.6m Dataset + +| Arch | Receptive Field | MPJPE | P-MPJPE | N-MPJPE | ckpt | log | + +| :------------------------------------------------------ | :-------------: | :---: | :-----: | :-----: | :------------------------------------------------------: | :-----------------------------------------------------: | + +| [VideoPose3D-supervised](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-supv_8xb128-80e_h36m.py) | 27 | 40.1 | 30.1 | / | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_supervised-fe8fbba9_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_supervised_20210527.log.json) | + +| [VideoPose3D-supervised](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-81frm-supv_8xb128-80e_h36m.py) | 81 | 39.1 | 29.3 | / | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_81frames_fullconv_supervised-1f2d1104_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_81frames_fullconv_supervised_20210527.log.json) | + +| [VideoPose3D-supervised](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv_8xb128-80e_h36m.py) | 243 | | | / | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised-880bea25_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised_20210527.log.json) | + +| [VideoPose3D-supervised-CPN](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-1frm-supv-cpn-ft_8xb128-80e_h36m.py) | 1 | 53.0 | 41.3 | / | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_1frame_fullconv_supervised_cpn_ft-5c3afaed_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_1frame_fullconv_supervised_cpn_ft_20210527.log.json) | + +| [VideoPose3D-supervised-CPN](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv-cpn-ft_8xb128-200e_h36m.py) | 243 | | | / | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised_cpn_ft-88f5abbb_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised_cpn_ft_20210527.log.json) | + +| [VideoPose3D-semi-supervised](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-semi-supv_8xb64-200e_h36m.py) | 27 | 57.2 | 42.4 | 54.2 | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_semi-supervised-54aef83b_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_semi-supervised_20210527.log.json) | + +| [VideoPose3D-semi-supervised-CPN](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-semi-supv-cpn-ft_8xb64-200e_h36m.py) | 27 | 67.3 | 50.4 | 63.6 | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_semi-supervised_cpn_ft-71be9cde_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_semi-supervised_cpn_ft_20210527.log.json) | + +## Image-based Single-view 3D Human Body Pose Estimation + +3D pose estimation is the detection and analysis of X, Y, Z coordinates of human body joints from an RGB image. +For single-person 3D pose estimation from a monocular camera, existing works can be classified into three categories: +(1) from 2D poses to 3D poses (2D-to-3D pose lifting) +(2) jointly learning 2D and 3D poses, and +(3) directly regressing 3D poses from images. + +### Results and Models + +#### Human3.6m Dataset + +| Arch | MPJPE | P-MPJPE | N-MPJPE | ckpt | log | +| :------------------------------------------------------ | :-------------: | :---: | :-----: | :-----: | :------------------------------------------------------: | :-----------------------------------------------------: | +| [SimpleBaseline3D-tcn](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_simplebaseline3d_8xb64-200e_h36m.py) | 43.4 | 34.3 | /|[ckpt](https://download.openmmlab.com/mmpose/body3d/simple_baseline/simple3Dbaseline_h36m-f0ad73a4_20210419.pth) | [log](https://download.openmmlab.com/mmpose/body3d/simple_baseline/20210415_065056.log.json) | diff --git a/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_simplebaseline3d_8xb64-200e_h36m.py b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_simplebaseline3d_8xb64-200e_h36m.py new file mode 100644 index 0000000000..b3c1c2db80 --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_simplebaseline3d_8xb64-200e_h36m.py @@ -0,0 +1,168 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +vis_backends = [ + dict(type='LocalVisBackend'), +] +visualizer = dict( + type='Pose3dLocalVisualizer', vis_backends=vis_backends, name='visualizer') + +# runtime +train_cfg = dict(max_epochs=200, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict(type='Adam', lr=1e-3)) + +# learning policy +param_scheduler = [ + dict(type='StepLR', step_size=100000, gamma=0.96, end=80, by_epoch=False) +] + +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict( + checkpoint=dict( + type='CheckpointHook', + save_best='MPJPE', + rule='less', + max_keep_ckpts=1)) + +# codec settings +# 3D keypoint normalization parameters +# From file: '{data_root}/annotation_body3d/fps50/joint3d_rel_stats.pkl' +target_mean = [[-2.55652589e-04, -7.11960570e-03, -9.81433052e-04], + [-5.65463051e-03, 3.19636009e-01, 7.19329269e-02], + [-1.01705840e-02, 6.91147892e-01, 1.55352986e-01], + [2.55651315e-04, 7.11954606e-03, 9.81423866e-04], + [-5.09729780e-03, 3.27040413e-01, 7.22258095e-02], + [-9.99656606e-03, 7.08277383e-01, 1.58016408e-01], + [2.90583676e-03, -2.11363307e-01, -4.74210915e-02], + [5.67537804e-03, -4.35088906e-01, -9.76974016e-02], + [5.93884964e-03, -4.91891970e-01, -1.10666618e-01], + [7.37352083e-03, -5.83948619e-01, -1.31171400e-01], + [5.41920653e-03, -3.83931702e-01, -8.68145417e-02], + [2.95964662e-03, -1.87567488e-01, -4.34536934e-02], + [1.26585822e-03, -1.20170579e-01, -2.82526049e-02], + [4.67186639e-03, -3.83644089e-01, -8.55125784e-02], + [1.67648571e-03, -1.97007177e-01, -4.31368364e-02], + [8.70569015e-04, -1.68664569e-01, -3.73902498e-02]], +target_std = [[0.11072244, 0.02238818, 0.07246294], + [0.15856311, 0.18933832, 0.20880479], + [0.19179935, 0.24320062, 0.24756193], + [0.11072181, 0.02238805, 0.07246253], + [0.15880454, 0.19977188, 0.2147063], + [0.18001944, 0.25052739, 0.24853247], + [0.05210694, 0.05211406, 0.06908241], + [0.09515367, 0.10133032, 0.12899733], + [0.11742458, 0.12648469, 0.16465091], + [0.12360297, 0.13085539, 0.16433336], + [0.14602232, 0.09707956, 0.13952731], + [0.24347532, 0.12982249, 0.20230181], + [0.2446877, 0.21501816, 0.23938235], + [0.13876084, 0.1008926, 0.1424411], + [0.23687529, 0.14491219, 0.20980829], + [0.24400695, 0.23975028, 0.25520584]] +# 2D keypoint normalization parameters +# From file: '{data_root}/annotation_body3d/fps50/joint2d_stats.pkl' +keypoints_mean = [[532.08351635, 419.74137558], [531.80953144, 418.2607141], + [530.68456967, 493.54259285], [529.36968722, 575.96448516], + [532.29767646, 421.28483336], [531.93946631, 494.72186795], + [529.71984447, 578.96110365], [532.93699382, 370.65225054], + [534.1101856, 317.90342311], [534.55416813, 304.24143901], + [534.86955004, 282.31030885], [534.11308566, 330.11296796], + [533.53637525, 376.2742511], [533.49380107, 391.72324565], + [533.52579142, 330.09494668], [532.50804964, 374.190479], + [532.72786934, 380.61615716]], +keypoints_std = [[107.73640054, 63.35908715], [119.00836213, 64.1215443], + [119.12412107, 50.53806215], [120.61688045, 56.38444891], + [101.95735275, 62.89636486], [106.24832897, 48.41178119], + [108.46734966, 54.58177071], [109.07369806, 68.70443672], + [111.20130351, 74.87287863], [111.63203838, 77.80542514], + [113.22330788, 79.90670556], [105.7145833, 73.27049436], + [107.05804267, 73.93175781], [107.97449418, 83.30391802], + [121.60675105, 74.25691526], [134.34378973, 77.48125087], + [131.79990652, 89.86721124]] +codec = dict( + type='ImagePoseLifting', + num_keypoints=17, + root_index=0, + remove_root=True, + target_mean=target_mean, + target_std=target_std, + keypoints_mean=keypoints_mean, + keypoints_std=keypoints_std) + +# model settings +model = dict( + type='PoseLifter', + backbone=dict( + type='TCN', + in_channels=2 * 17, + stem_channels=1024, + num_blocks=2, + kernel_sizes=(1, 1, 1), + dropout=0.5, + ), + head=dict( + type='TemporalRegressionHead', + in_channels=1024, + num_joints=16, + loss=dict(type='MSELoss'), + decoder=codec, + )) + +# base dataset settings +dataset_type = 'Human36mDataset' +data_root = 'data/h36m/' + +# pipelines +train_pipeline = [ + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root', 'target_root_index', 'target_mean', + 'target_std')) +] +val_pipeline = train_pipeline + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_train.npz', + seq_len=1, + causal=True, + keypoint_2d_src='gt', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_test.npz', + seq_len=1, + causal=True, + keypoint_2d_src='gt', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='MPJPE', mode='mpjpe'), + dict(type='MPJPE', mode='p-mpjpe') +] +test_evaluator = val_evaluator diff --git a/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-1frm-supv-cpn-ft_8xb128-80e_h36m.py b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-1frm-supv-cpn-ft_8xb128-80e_h36m.py new file mode 100644 index 0000000000..0cbf89142d --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-1frm-supv-cpn-ft_8xb128-80e_h36m.py @@ -0,0 +1,132 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +vis_backends = [ + dict(type='LocalVisBackend'), +] +visualizer = dict( + type='Pose3dLocalVisualizer', vis_backends=vis_backends, name='visualizer') + +# runtime +train_cfg = dict(max_epochs=80, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict(type='Adam', lr=1e-4)) + +# learning policy +param_scheduler = [ + dict(type='ExponentialLR', gamma=0.98, end=80, by_epoch=True) +] + +auto_scale_lr = dict(base_batch_size=1024) + +# hooks +default_hooks = dict( + checkpoint=dict( + type='CheckpointHook', + save_best='MPJPE', + rule='less', + max_keep_ckpts=1), + logger=dict(type='LoggerHook', interval=20), +) + +# codec settings +codec = dict( + type='VideoPoseLifting', + num_keypoints=17, + zero_center=True, + root_index=0, + remove_root=False) + +# model settings +model = dict( + type='PoseLifter', + backbone=dict( + type='TCN', + in_channels=2 * 17, + stem_channels=1024, + num_blocks=4, + kernel_sizes=(1, 1, 1, 1, 1), + dropout=0.25, + use_stride_conv=True, + ), + head=dict( + type='TemporalRegressionHead', + in_channels=1024, + num_joints=17, + loss=dict(type='MPJPELoss'), + decoder=codec, + )) + +# base dataset settings +dataset_type = 'Human36mDataset' +data_root = 'data/h36m/' + +# pipelines +train_pipeline = [ + dict( + type='RandomFlipAroundRoot', + keypoints_flip_cfg=dict(), + target_flip_cfg=dict(), + ), + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root')) +] +val_pipeline = [ + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root')) +] + +# data loaders +train_dataloader = dict( + batch_size=128, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_train.npz', + seq_len=1, + causal=False, + pad_video_seq=False, + keypoint_2d_src='detection', + keypoint_2d_det_file='joint_2d_det_files/cpn_ft_h36m_dbb_train.npy', + camera_param_file='annotation_body3d/cameras.pkl', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + ), +) +val_dataloader = dict( + batch_size=128, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_test.npz', + seq_len=1, + causal=False, + pad_video_seq=False, + keypoint_2d_src='detection', + keypoint_2d_det_file='joint_2d_det_files/cpn_ft_h36m_dbb_test.npy', + camera_param_file='annotation_body3d/cameras.pkl', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=val_pipeline, + test_mode=True, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='MPJPE', mode='mpjpe'), + dict(type='MPJPE', mode='p-mpjpe') +] +test_evaluator = val_evaluator diff --git a/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv-cpn-ft_8xb128-200e_h36m.py b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv-cpn-ft_8xb128-200e_h36m.py new file mode 100644 index 0000000000..3ef3df570b --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv-cpn-ft_8xb128-200e_h36m.py @@ -0,0 +1,132 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +vis_backends = [ + dict(type='LocalVisBackend'), +] +visualizer = dict( + type='Pose3dLocalVisualizer', vis_backends=vis_backends, name='visualizer') + +# runtime +train_cfg = dict(max_epochs=200, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict(type='Adam', lr=1e-4)) + +# learning policy +param_scheduler = [ + dict(type='ExponentialLR', gamma=0.98, end=200, by_epoch=True) +] + +auto_scale_lr = dict(base_batch_size=1024) + +# hooks +default_hooks = dict( + checkpoint=dict( + type='CheckpointHook', + save_best='MPJPE', + rule='less', + max_keep_ckpts=1), + logger=dict(type='LoggerHook', interval=20), +) + +# codec settings +codec = dict( + type='VideoPoseLifting', + num_keypoints=17, + zero_center=True, + root_index=0, + remove_root=False) + +# model settings +model = dict( + type='PoseLifter', + backbone=dict( + type='TCN', + in_channels=2 * 17, + stem_channels=1024, + num_blocks=4, + kernel_sizes=(3, 3, 3, 3, 3), + dropout=0.25, + use_stride_conv=True, + ), + head=dict( + type='TemporalRegressionHead', + in_channels=1024, + num_joints=17, + loss=dict(type='MPJPELoss'), + decoder=codec, + )) + +# base dataset settings +dataset_type = 'Human36mDataset' +data_root = 'data/h36m/' + +# pipelines +train_pipeline = [ + dict( + type='RandomFlipAroundRoot', + keypoints_flip_cfg=dict(), + target_flip_cfg=dict(), + ), + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root')) +] +val_pipeline = [ + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root')) +] + +# data loaders +train_dataloader = dict( + batch_size=128, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_train.npz', + seq_len=243, + causal=False, + pad_video_seq=True, + keypoint_2d_src='detection', + keypoint_2d_det_file='joint_2d_det_files/cpn_ft_h36m_dbb_train.npy', + camera_param_file='annotation_body3d/cameras.pkl', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + ), +) +val_dataloader = dict( + batch_size=128, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_test.npz', + seq_len=243, + causal=False, + pad_video_seq=True, + keypoint_2d_src='detection', + keypoint_2d_det_file='joint_2d_det_files/cpn_ft_h36m_dbb_test.npy', + camera_param_file='annotation_body3d/cameras.pkl', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=val_pipeline, + test_mode=True, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='MPJPE', mode='mpjpe'), + dict(type='MPJPE', mode='p-mpjpe') +] +test_evaluator = val_evaluator diff --git a/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv_8xb128-80e_h36m.py b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv_8xb128-80e_h36m.py new file mode 100644 index 0000000000..0f311ac5cf --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv_8xb128-80e_h36m.py @@ -0,0 +1,128 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +vis_backends = [ + dict(type='LocalVisBackend'), +] +visualizer = dict( + type='Pose3dLocalVisualizer', vis_backends=vis_backends, name='visualizer') + +# runtime +train_cfg = dict(max_epochs=80, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict(type='Adam', lr=1e-3)) + +# learning policy +param_scheduler = [ + dict(type='ExponentialLR', gamma=0.975, end=80, by_epoch=True) +] + +auto_scale_lr = dict(base_batch_size=1024) + +# hooks +default_hooks = dict( + checkpoint=dict( + type='CheckpointHook', + save_best='MPJPE', + rule='less', + max_keep_ckpts=1), + logger=dict(type='LoggerHook', interval=20), +) + +# codec settings +codec = dict( + type='VideoPoseLifting', + num_keypoints=17, + zero_center=True, + root_index=0, + remove_root=False) + +# model settings +model = dict( + type='PoseLifter', + backbone=dict( + type='TCN', + in_channels=2 * 17, + stem_channels=1024, + num_blocks=4, + kernel_sizes=(3, 3, 3, 3, 3), + dropout=0.25, + use_stride_conv=True, + ), + head=dict( + type='TemporalRegressionHead', + in_channels=1024, + num_joints=17, + loss=dict(type='MPJPELoss'), + decoder=codec, + )) + +# base dataset settings +dataset_type = 'Human36mDataset' +data_root = 'data/h36m/' + +# pipelines +train_pipeline = [ + dict( + type='RandomFlipAroundRoot', + keypoints_flip_cfg=dict(), + target_flip_cfg=dict(), + ), + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root')) +] +val_pipeline = [ + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root')) +] + +# data loaders +train_dataloader = dict( + batch_size=128, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_train.npz', + seq_len=243, + causal=False, + pad_video_seq=True, + camera_param_file='annotation_body3d/cameras.pkl', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + ), +) +val_dataloader = dict( + batch_size=128, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_test.npz', + seq_len=243, + causal=False, + pad_video_seq=True, + camera_param_file='annotation_body3d/cameras.pkl', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=val_pipeline, + test_mode=True, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='MPJPE', mode='mpjpe'), + dict(type='MPJPE', mode='p-mpjpe') +] +test_evaluator = val_evaluator diff --git a/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-semi-supv-cpn-ft_8xb64-200e_h36m.py b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-semi-supv-cpn-ft_8xb64-200e_h36m.py new file mode 100644 index 0000000000..08bcda8ed7 --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-semi-supv-cpn-ft_8xb64-200e_h36m.py @@ -0,0 +1,119 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +vis_backends = [ + dict(type='LocalVisBackend'), +] +visualizer = dict( + type='Pose3dLocalVisualizer', vis_backends=vis_backends, name='visualizer') + +# runtime +train_cfg = None + +# optimizer + +# learning policy + +auto_scale_lr = dict(base_batch_size=1024) + +# hooks +default_hooks = dict( + checkpoint=dict( + type='CheckpointHook', + save_best='MPJPE', + rule='less', + max_keep_ckpts=1), + logger=dict(type='LoggerHook', interval=20), +) + +# codec settings +codec = dict( + type='VideoPoseLifting', + num_keypoints=17, + zero_center=True, + root_index=0, + remove_root=False) + +# model settings +model = dict( + type='PoseLifter', + backbone=dict( + type='TCN', + in_channels=2 * 17, + stem_channels=1024, + num_blocks=2, + kernel_sizes=(3, 3, 3), + dropout=0.25, + use_stride_conv=True, + ), + head=dict( + type='TemporalRegressionHead', + in_channels=1024, + num_joints=17, + loss=dict(type='MPJPELoss'), + decoder=codec, + ), + traj_backbone=dict( + type='TCN', + in_channels=2 * 17, + stem_channels=1024, + num_blocks=2, + kernel_sizes=(3, 3, 3), + dropout=0.25, + use_stride_conv=True, + ), + traj_head=dict( + type='TrajectoryRegressionHead', + in_channels=1024, + num_joints=1, + loss=dict(type='MPJPELoss', use_target_weight=True), + decoder=codec, + ), + semi_loss=dict( + type='SemiSupervisionLoss', + joint_parents=[0, 0, 1, 2, 0, 4, 5, 0, 7, 8, 9, 8, 11, 12, 8, 14, 15], + warmup_iterations=1311376 // 64 // 8 * 5), +) + +# base dataset settings +dataset_type = 'Human36mDataset' +data_root = 'data/h36m/' + +# pipelines +val_pipeline = [ + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root')) +] + +# data loaders +val_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_test.npz', + seq_len=27, + causal=False, + pad_video_seq=True, + keypoint_2d_src='detection', + keypoint_2d_det_file='joint_2d_det_files/cpn_ft_h36m_dbb_test.npy', + camera_param_file='annotation_body3d/cameras.pkl', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=val_pipeline, + test_mode=True, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='MPJPE', mode='mpjpe'), + dict(type='MPJPE', mode='p-mpjpe'), + dict(type='MPJPE', mode='n-mpjpe') +] +test_evaluator = val_evaluator diff --git a/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-semi-supv_8xb64-200e_h36m.py b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-semi-supv_8xb64-200e_h36m.py new file mode 100644 index 0000000000..d145f05b17 --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-semi-supv_8xb64-200e_h36m.py @@ -0,0 +1,117 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +vis_backends = [ + dict(type='LocalVisBackend'), +] +visualizer = dict( + type='Pose3dLocalVisualizer', vis_backends=vis_backends, name='visualizer') + +# runtime +train_cfg = None + +# optimizer + +# learning policy + +auto_scale_lr = dict(base_batch_size=1024) + +# hooks +default_hooks = dict( + checkpoint=dict( + type='CheckpointHook', + save_best='MPJPE', + rule='less', + max_keep_ckpts=1), + logger=dict(type='LoggerHook', interval=20), +) + +# codec settings +codec = dict( + type='VideoPoseLifting', + num_keypoints=17, + zero_center=True, + root_index=0, + remove_root=False) + +# model settings +model = dict( + type='PoseLifter', + backbone=dict( + type='TCN', + in_channels=2 * 17, + stem_channels=1024, + num_blocks=2, + kernel_sizes=(3, 3, 3), + dropout=0.25, + use_stride_conv=True, + ), + head=dict( + type='TemporalRegressionHead', + in_channels=1024, + num_joints=17, + loss=dict(type='MPJPELoss'), + decoder=codec, + ), + traj_backbone=dict( + type='TCN', + in_channels=2 * 17, + stem_channels=1024, + num_blocks=2, + kernel_sizes=(3, 3, 3), + dropout=0.25, + use_stride_conv=True, + ), + traj_head=dict( + type='TrajectoryRegressionHead', + in_channels=1024, + num_joints=1, + loss=dict(type='MPJPELoss', use_target_weight=True), + decoder=codec, + ), + semi_loss=dict( + type='SemiSupervisionLoss', + joint_parents=[0, 0, 1, 2, 0, 4, 5, 0, 7, 8, 9, 8, 11, 12, 8, 14, 15], + warmup_iterations=1311376 // 64 // 8 * 5), +) + +# base dataset settings +dataset_type = 'Human36mDataset' +data_root = 'data/h36m/' + +# pipelines +val_pipeline = [ + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root')) +] + +# data loaders +val_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_test.npz', + seq_len=27, + causal=False, + pad_video_seq=True, + camera_param_file='annotation_body3d/cameras.pkl', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=val_pipeline, + test_mode=True, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='MPJPE', mode='mpjpe'), + dict(type='MPJPE', mode='p-mpjpe'), + dict(type='MPJPE', mode='n-mpjpe') +] +test_evaluator = val_evaluator diff --git a/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-supv_8xb128-80e_h36m.py b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-supv_8xb128-80e_h36m.py new file mode 100644 index 0000000000..2589b493a6 --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-supv_8xb128-80e_h36m.py @@ -0,0 +1,128 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +vis_backends = [ + dict(type='LocalVisBackend'), +] +visualizer = dict( + type='Pose3dLocalVisualizer', vis_backends=vis_backends, name='visualizer') + +# runtime +train_cfg = dict(max_epochs=80, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict(type='Adam', lr=1e-3)) + +# learning policy +param_scheduler = [ + dict(type='ExponentialLR', gamma=0.975, end=80, by_epoch=True) +] + +auto_scale_lr = dict(base_batch_size=1024) + +# hooks +default_hooks = dict( + checkpoint=dict( + type='CheckpointHook', + save_best='MPJPE', + rule='less', + max_keep_ckpts=1), + logger=dict(type='LoggerHook', interval=20), +) + +# codec settings +codec = dict( + type='VideoPoseLifting', + num_keypoints=17, + zero_center=True, + root_index=0, + remove_root=False) + +# model settings +model = dict( + type='PoseLifter', + backbone=dict( + type='TCN', + in_channels=2 * 17, + stem_channels=1024, + num_blocks=2, + kernel_sizes=(3, 3, 3), + dropout=0.25, + use_stride_conv=True, + ), + head=dict( + type='TemporalRegressionHead', + in_channels=1024, + num_joints=17, + loss=dict(type='MPJPELoss'), + decoder=codec, + )) + +# base dataset settings +dataset_type = 'Human36mDataset' +data_root = 'data/h36m/' + +# pipelines +train_pipeline = [ + dict( + type='RandomFlipAroundRoot', + keypoints_flip_cfg=dict(), + target_flip_cfg=dict(), + ), + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root')) +] +val_pipeline = [ + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root')) +] + +# data loaders +train_dataloader = dict( + batch_size=128, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_train.npz', + seq_len=27, + causal=False, + pad_video_seq=True, + camera_param_file='annotation_body3d/cameras.pkl', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + ), +) +val_dataloader = dict( + batch_size=128, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_test.npz', + seq_len=27, + causal=False, + pad_video_seq=True, + camera_param_file='annotation_body3d/cameras.pkl', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=val_pipeline, + test_mode=True, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='MPJPE', mode='mpjpe'), + dict(type='MPJPE', mode='p-mpjpe') +] +test_evaluator = val_evaluator diff --git a/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-81frm-supv_8xb128-80e_h36m.py b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-81frm-supv_8xb128-80e_h36m.py new file mode 100644 index 0000000000..f2c27e423d --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-81frm-supv_8xb128-80e_h36m.py @@ -0,0 +1,128 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +vis_backends = [ + dict(type='LocalVisBackend'), +] +visualizer = dict( + type='Pose3dLocalVisualizer', vis_backends=vis_backends, name='visualizer') + +# runtime +train_cfg = dict(max_epochs=80, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict(type='Adam', lr=1e-3)) + +# learning policy +param_scheduler = [ + dict(type='ExponentialLR', gamma=0.975, end=80, by_epoch=True) +] + +auto_scale_lr = dict(base_batch_size=1024) + +# hooks +default_hooks = dict( + checkpoint=dict( + type='CheckpointHook', + save_best='MPJPE', + rule='less', + max_keep_ckpts=1), + logger=dict(type='LoggerHook', interval=20), +) + +# codec settings +codec = dict( + type='VideoPoseLifting', + num_keypoints=17, + zero_center=True, + root_index=0, + remove_root=False) + +# model settings +model = dict( + type='PoseLifter', + backbone=dict( + type='TCN', + in_channels=2 * 17, + stem_channels=1024, + num_blocks=3, + kernel_sizes=(3, 3, 3, 3), + dropout=0.25, + use_stride_conv=True, + ), + head=dict( + type='TemporalRegressionHead', + in_channels=1024, + num_joints=17, + loss=dict(type='MPJPELoss'), + decoder=codec, + )) + +# base dataset settings +dataset_type = 'Human36mDataset' +data_root = 'data/h36m/' + +# pipelines +train_pipeline = [ + dict( + type='RandomFlipAroundRoot', + keypoints_flip_cfg=dict(), + target_flip_cfg=dict(), + ), + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root')) +] +val_pipeline = [ + dict(type='GenerateTarget', encoder=codec), + dict( + type='PackPoseInputs', + meta_keys=('id', 'category_id', 'target_img_path', 'flip_indices', + 'target_root')) +] + +# data loaders +train_dataloader = dict( + batch_size=128, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_train.npz', + seq_len=81, + causal=False, + pad_video_seq=True, + camera_param_file='annotation_body3d/cameras.pkl', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + ), +) +val_dataloader = dict( + batch_size=128, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + ann_file='annotation_body3d/fps50/h36m_test.npz', + seq_len=81, + causal=False, + pad_video_seq=True, + camera_param_file='annotation_body3d/cameras.pkl', + data_root=data_root, + data_prefix=dict(img='images/'), + pipeline=val_pipeline, + test_mode=True, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='MPJPE', mode='mpjpe'), + dict(type='MPJPE', mode='p-mpjpe') +] +test_evaluator = val_evaluator diff --git a/configs/body_3d_keypoint/pose_lift/h36m/simplebaseline3d_h36m.md b/configs/body_3d_keypoint/pose_lift/h36m/simplebaseline3d_h36m.md new file mode 100644 index 0000000000..9bc1876315 --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/h36m/simplebaseline3d_h36m.md @@ -0,0 +1,44 @@ + + +
+SimpleBaseline3D (ICCV'2017) + +```bibtex +@inproceedings{martinez_2017_3dbaseline, + title={A simple yet effective baseline for 3d human pose estimation}, + author={Martinez, Julieta and Hossain, Rayat and Romero, Javier and Little, James J.}, + booktitle={ICCV}, + year={2017} +} +``` + +
+ + + +
+Human3.6M (TPAMI'2014) + +```bibtex +@article{h36m_pami, + author = {Ionescu, Catalin and Papava, Dragos and Olaru, Vlad and Sminchisescu, Cristian}, + title = {Human3.6M: Large Scale Datasets and Predictive Methods for 3D Human Sensing in Natural Environments}, + journal = {IEEE Transactions on Pattern Analysis and Machine Intelligence}, + publisher = {IEEE Computer Society}, + volume = {36}, + number = {7}, + pages = {1325-1339}, + month = {jul}, + year = {2014} +} +``` + +
+ +Results on Human3.6M dataset with ground truth 2D detections + +| Arch | MPJPE | P-MPJPE | ckpt | log | +| :-------------------------------------------------------------- | :---: | :-----: | :-------------------------------------------------------------: | :------------------------------------------------------------: | +| [SimpleBaseline3D-tcn1](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_simplebaseline3d_8xb64-200e_h36m.py) | 43.4 | 34.3 | [ckpt](https://download.openmmlab.com/mmpose/body3d/simple_baseline/simple3Dbaseline_h36m-f0ad73a4_20210419.pth) | [log](https://download.openmmlab.com/mmpose/body3d/simple_baseline/20210415_065056.log.json) | + +1 Differing from the original paper, we didn't apply the `max-norm constraint` because we found this led to a better convergence and performance. diff --git a/configs/body_3d_keypoint/pose_lift/h36m/simplebaseline3d_h36m.yml b/configs/body_3d_keypoint/pose_lift/h36m/simplebaseline3d_h36m.yml new file mode 100644 index 0000000000..1a8f32f82c --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/h36m/simplebaseline3d_h36m.yml @@ -0,0 +1,21 @@ +Collections: +- Name: SimpleBaseline3D + Paper: + Title: A simple yet effective baseline for 3d human pose estimation + URL: http://openaccess.thecvf.com/content_iccv_2017/html/Martinez_A_Simple_yet_ICCV_2017_paper.html + README: https://github.com/open-mmlab/mmpose/blob/main/docs/en/papers/algorithms/simplebaseline3d.md +Models: +- Config: configs/body_3d_keypoint/pose_lift/h36m/pose-lift_simplebaseline3d_8xb64-200e_h36m.py + In Collection: SimpleBaseline3D + Metadata: + Architecture: &id001 + - SimpleBaseline3D + Training Data: Human3.6M + Name: pose-lift_simplebaseline3d_8xb64-200e_h36m + Results: + - Dataset: Human3.6M + Metrics: + MPJPE: 43.4 + P-MPJPE: 34.3 + Task: Body 3D Keypoint + Weights: https://download.openmmlab.com/mmpose/body3d/simple_baseline/simple3Dbaseline_h36m-f0ad73a4_20210419.pth diff --git a/configs/body_3d_keypoint/pose_lift/h36m/videopose3d_h36m.md b/configs/body_3d_keypoint/pose_lift/h36m/videopose3d_h36m.md new file mode 100644 index 0000000000..f1c75d786a --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/h36m/videopose3d_h36m.md @@ -0,0 +1,67 @@ + + +
+ +VideoPose3D (CVPR'2019) + +```bibtex +@inproceedings{pavllo20193d, +title={3d human pose estimation in video with temporal convolutions and semi-supervised training}, +author={Pavllo, Dario and Feichtenhofer, Christoph and Grangier, David and Auli, Michael}, +booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition}, +pages={7753--7762}, +year={2019} +} +``` + +
+ + + +
+Human3.6M (TPAMI'2014) + +```bibtex +@article{h36m_pami, +author = {Ionescu, Catalin and Papava, Dragos and Olaru, Vlad and Sminchisescu, Cristian}, +title = {Human3.6M: Large Scale Datasets and Predictive Methods for 3D Human Sensing in Natural Environments}, +journal = {IEEE Transactions on Pattern Analysis and Machine Intelligence}, +publisher = {IEEE Computer Society}, +volume = {36}, +number = {7}, +pages = {1325-1339}, +month = {jul}, +year = {2014} +} +``` + +
+ +Testing results on Human3.6M dataset with ground truth 2D detections, supervised training + +| Arch | Receptive Field | MPJPE | P-MPJPE | ckpt | log | +| :--------------------------------------------------------- | :-------------: | :---: | :-----: | :--------------------------------------------------------: | :-------------------------------------------------------: | +| [VideoPose3D](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-supv_8xb128-80e_h36m.py) | 27 | 40.1 | 30.1 | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_supervised-fe8fbba9_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_supervised_20210527.log.json) | +| [VideoPose3D](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-81frm-supv_8xb128-80e_h36m.py) | 81 | 39.1 | 29.3 | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_81frames_fullconv_supervised-1f2d1104_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_81frames_fullconv_supervised_20210527.log.json) | +| [VideoPose3D](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv_8xb128-80e_h36m.py) | 243 | | | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised-880bea25_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised_20210527.log.json) | + +Testing results on Human3.6M dataset with CPN 2D detections1, supervised training + +| Arch | Receptive Field | MPJPE | P-MPJPE | ckpt | log | +| :--------------------------------------------------------- | :-------------: | :---: | :-----: | :--------------------------------------------------------: | :-------------------------------------------------------: | +| [VideoPose3D](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-1frm-supv-cpn-ft_8xb128-80e_h36m.py) | 1 | 53.0 | 41.3 | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_1frame_fullconv_supervised_cpn_ft-5c3afaed_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_1frame_fullconv_supervised_cpn_ft_20210527.log.json) | +| [VideoPose3D](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv-cpn-ft_8xb128-200e_h36m.py) | 243 | | | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised_cpn_ft-88f5abbb_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised_cpn_ft_20210527.log.json) | + +Testing results on Human3.6M dataset with ground truth 2D detections, semi-supervised training + +| Training Data | Arch | Receptive Field | MPJPE | P-MPJPE | N-MPJPE | ckpt | log | +| :------------ | :-------------------------------------------------: | :-------------: | :---: | :-----: | :-----: | :-------------------------------------------------: | :-------------------------------------------------: | +| 10% S1 | [VideoPose3D](/configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-semi-supv_8xb64-200e_h36m.py) | 27 | 57.2 | 42.4 | 54.2 | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_semi-supervised-54aef83b_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_semi-supervised_20210527.log.json) | + +Testing results on Human3.6M dataset with CPN 2D detections1, semi-supervised training + +| Training Data | Arch | Receptive Field | MPJPE | P-MPJPE | N-MPJPE | ckpt | log | +| :------------ | :----------------------------: | :-------------: | :---: | :-----: | :-----: | :------------------------------------------------------------: | :-----------------------------------------------------------: | +| 10% S1 | [VideoPose3D](/configs/xxx.py) | 27 | 67.3 | 50.4 | 63.6 | [ckpt](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_semi-supervised_cpn_ft-71be9cde_20210527.pth) | [log](https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_semi-supervised_cpn_ft_20210527.log.json) | + +1 CPN 2D detections are provided by [official repo](https://github.com/facebookresearch/VideoPose3D/blob/master/DATASETS.md). The reformatted version used in this repository can be downloaded from [train_detection](https://download.openmmlab.com/mmpose/body3d/videopose/cpn_ft_h36m_dbb_train.npy) and [test_detection](https://download.openmmlab.com/mmpose/body3d/videopose/cpn_ft_h36m_dbb_test.npy). diff --git a/configs/body_3d_keypoint/pose_lift/h36m/videopose3d_h36m.yml b/configs/body_3d_keypoint/pose_lift/h36m/videopose3d_h36m.yml new file mode 100644 index 0000000000..6b9d92c115 --- /dev/null +++ b/configs/body_3d_keypoint/pose_lift/h36m/videopose3d_h36m.yml @@ -0,0 +1,103 @@ +Collections: +- Name: VideoPose3D + Paper: + Title: 3d human pose estimation in video with temporal convolutions and semi-supervised + training + URL: http://openaccess.thecvf.com/content_CVPR_2019/html/Pavllo_3D_Human_Pose_Estimation_in_Video_With_Temporal_Convolutions_and_CVPR_2019_paper.html + README: https://github.com/open-mmlab/mmpose/blob/main/docs/en/papers/algorithms/videopose3d.md +Models: +- Config: configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv_8xb128-80e_h36m.py + In Collection: VideoPose3D + Metadata: + Architecture: &id001 + - VideoPose3D + Training Data: Human3.6M + Name: pose-lift_videopose3d-243frm-supv_8xb128-80e_h36m + Results: + - Dataset: Human3.6M + Metrics: + MPJPE: 40.0 + P-MPJPE: 30.1 + Task: Body 3D Keypoint + Weights: https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_supervised-fe8fbba9_20210527.pth +- Config: configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-81frm-supv_8xb128-80e_h36m.py + In Collection: VideoPose3D + Metadata: + Architecture: *id001 + Training Data: Human3.6M + Name: pose-lift_videopose3d-81frm-supv_8xb128-80e_h36m + Results: + - Dataset: Human3.6M + Metrics: + MPJPE: 38.9 + P-MPJPE: 29.2 + Task: Body 3D Keypoint + Weights: https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_81frames_fullconv_supervised-1f2d1104_20210527.pth +- Config: configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv_8xb128-80e_h36m.py + In Collection: VideoPose3D + Metadata: + Architecture: *id001 + Training Data: Human3.6M + Name: pose-lift_videopose3d-243frm-supv_8xb128-80e_h36m + Results: + - Dataset: Human3.6M + Metrics: + MPJPE: 37.6 + P-MPJPE: 28.3 + Task: Body 3D Keypoint + Weights: https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised-880bea25_20210527.pth +- Config: configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-1frm-supv-cpn-ft_8xb128-80e_h36m.py + In Collection: VideoPose3D + Metadata: + Architecture: *id001 + Training Data: Human3.6M + Name: pose-lift_videopose3d-1frm-supv-cpn-ft_8xb128-80e_h36m + Results: + - Dataset: Human3.6M + Metrics: + MPJPE: 52.9 + P-MPJPE: 41.3 + Task: Body 3D Keypoint + Weights: https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_1frame_fullconv_supervised_cpn_ft-5c3afaed_20210527.pth +- Config: configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv-cpn-ft_8xb128-200e_h36m.py + In Collection: VideoPose3D + Alias: human3d + Metadata: + Architecture: *id001 + Training Data: Human3.6M + Name: pose-lift_videopose3d-243frm-supv-cpn-ft_8xb128-200e_h36m + Results: + - Dataset: Human3.6M + Metrics: + MPJPE: 47.9 + P-MPJPE: 38.0 + Task: Body 3D Keypoint + Weights: https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised_cpn_ft-88f5abbb_20210527.pth +- Config: configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-semi-supv_8xb64-200e_h36m.py + In Collection: VideoPose3D + Metadata: + Architecture: *id001 + Training Data: Human3.6M + Name: pose-lift_videopose3d-27frm-semi-supv_8xb64-200e_h36m + Results: + - Dataset: Human3.6M + Metrics: + MPJPE: 58.1 + N-MPJPE: 54.7 + P-MPJPE: 42.8 + Task: Body 3D Keypoint + Weights: https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_semi-supervised-54aef83b_20210527.pth +- Config: configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-27frm-semi-supv-cpn-ft_8xb64-200e_h36m.py + In Collection: VideoPose3D + Metadata: + Architecture: *id001 + Training Data: Human3.6M + Name: pose-lift_videopose3d-27frm-semi-supv-cpn-ft_8xb64-200e_h36m + Results: + - Dataset: Human3.6M + Metrics: + MPJPE: 67.4 + N-MPJPE: 63.2 + P-MPJPE: 50.1 + Task: Body 3D Keypoint + Weights: https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_27frames_fullconv_semi-supervised_cpn_ft-71be9cde_20210527.pth diff --git a/configs/face_2d_keypoint/README.md b/configs/face_2d_keypoint/README.md index b77c632b00..9f9370a754 100644 --- a/configs/face_2d_keypoint/README.md +++ b/configs/face_2d_keypoint/README.md @@ -11,6 +11,6 @@ Please follow [DATA Preparation](/docs/en/dataset_zoo/2d_face_keypoint.md) to pr ## Demo -Please follow [Demo](/demo/docs/2d_face_demo.md) to run demos. +Please follow [Demo](/demo/docs/en/2d_face_demo.md) to run demos.
diff --git a/configs/face_2d_keypoint/rtmpose/README.md b/configs/face_2d_keypoint/rtmpose/README.md index d309696bed..d0c7f55fb4 100644 --- a/configs/face_2d_keypoint/rtmpose/README.md +++ b/configs/face_2d_keypoint/rtmpose/README.md @@ -22,3 +22,11 @@ Results on WFLW dataset | Model | Input Size | NME | Details and Download | | :-------: | :--------: | :--: | :---------------------------------------: | | RTMPose-m | 256x256 | 4.01 | [rtmpose_wflw.md](./wflw/rtmpose_wflw.md) | + +### LaPa Dataset + +Results on LaPa dataset + +| Model | Input Size | NME | Details and Download | +| :-------: | :--------: | :--: | :---------------------------------------: | +| RTMPose-m | 256x256 | 1.29 | [rtmpose_lapa.md](./lapa/rtmpose_lapa.md) | diff --git a/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py b/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py index b5ca13b5aa..958a361c07 100644 --- a/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py +++ b/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py @@ -24,7 +24,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -69,14 +68,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, out_channels=68, input_size=codec['input_size'], - in_featuremap_size=(8, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose_coco_wholebody_face.md b/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose_coco_wholebody_face.md index 913fabe99c..77d99bc63f 100644 --- a/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose_coco_wholebody_face.md +++ b/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose_coco_wholebody_face.md @@ -36,4 +36,4 @@ Results on COCO-WholeBody-Face val set | Arch | Input Size | NME | ckpt | log | | :------------------------------------------------------------ | :--------: | :----: | :------------------------------------------------------------: | :-----------------------------------------------------------: | -| [pose_rtmpose_m](/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py) | 256x256 | 0.0466 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody-face_pt-aic-coco_60e-256x256-62026ef2_20230228.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody-face_pt-aic-coco_60e-256x256-62026ef2_20230228.json) | +| [pose_rtmpose_m](/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py) | 256x256 | 0.0466 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco-wholebody-face_pt-aic-coco_60e-256x256-62026ef2_20230228.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco-wholebody-face_pt-aic-coco_60e-256x256-62026ef2_20230228.json) | diff --git a/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose_coco_wholebody_face.yml b/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose_coco_wholebody_face.yml index 81c96b9eec..fdc2599e71 100644 --- a/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose_coco_wholebody_face.yml +++ b/configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose_coco_wholebody_face.yml @@ -11,4 +11,4 @@ Models: Metrics: NME: 0.0466 Task: Face 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody-face_pt-aic-coco_60e-256x256-62026ef2_20230228.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco-wholebody-face_pt-aic-coco_60e-256x256-62026ef2_20230228.pth diff --git a/configs/face_2d_keypoint/rtmpose/face6/rtmpose-m_8xb256-120e_face6-256x256.py b/configs/face_2d_keypoint/rtmpose/face6/rtmpose-m_8xb256-120e_face6-256x256.py new file mode 100644 index 0000000000..abbb2ce985 --- /dev/null +++ b/configs/face_2d_keypoint/rtmpose/face6/rtmpose-m_8xb256-120e_face6-256x256.py @@ -0,0 +1,690 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# lapa coco wflw 300w cofw halpe + +# runtime +max_epochs = 120 +stage2_num_epochs = 10 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=1) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.005, + begin=30, + end=max_epochs, + T_max=max_epochs - 30, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(256, 256), + sigma=(5.66, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.67, + widen_factor=0.75, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmdetection/v3.0/' + 'rtmdet/cspnext_rsb_pretrain/cspnext-m_8xb256-rsb-a1-600e_in1k-ecb3bbd9.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=768, + out_channels=106, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True, )) + +# base dataset settings +dataset_type = 'LapaDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.2), + dict(type='MedianBlur', p=0.2), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# train dataset +dataset_lapa = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='LaPa/annotations/lapa_trainval.json', + data_prefix=dict(img='pose/LaPa/'), + pipeline=[], +) + +kpt_68_to_106 = [ + # + (0, 0), + (1, 2), + (2, 4), + (3, 6), + (4, 8), + (5, 10), + (6, 12), + (7, 14), + (8, 16), + (9, 18), + (10, 20), + (11, 22), + (12, 24), + (13, 26), + (14, 28), + (15, 30), + (16, 32), + # + (17, 33), + (18, 34), + (19, 35), + (20, 36), + (21, 37), + # + (22, 42), + (23, 43), + (24, 44), + (25, 45), + (26, 46), + # + (27, 51), + (28, 52), + (29, 53), + (30, 54), + # + (31, 58), + (32, 59), + (33, 60), + (34, 61), + (35, 62), + # + (36, 66), + (39, 70), + # + ((37, 38), 68), + ((40, 41), 72), + # + (42, 75), + (45, 79), + # + ((43, 44), 77), + ((46, 47), 81), + # + (48, 84), + (49, 85), + (50, 86), + (51, 87), + (52, 88), + (53, 89), + (54, 90), + (55, 91), + (56, 92), + (57, 93), + (58, 94), + (59, 95), + (60, 96), + (61, 97), + (62, 98), + (63, 99), + (64, 100), + (65, 101), + (66, 102), + (67, 103) +] + +mapping_halpe = [ + # + (26, 0), + (27, 2), + (28, 4), + (29, 6), + (30, 8), + (31, 10), + (32, 12), + (33, 14), + (34, 16), + (35, 18), + (36, 20), + (37, 22), + (38, 24), + (39, 26), + (40, 28), + (41, 30), + (42, 32), + # + (43, 33), + (44, 34), + (45, 35), + (46, 36), + (47, 37), + # + (48, 42), + (49, 43), + (50, 44), + (51, 45), + (52, 46), + # + (53, 51), + (54, 52), + (55, 53), + (56, 54), + # + (57, 58), + (58, 59), + (59, 60), + (60, 61), + (61, 62), + # + (62, 66), + (65, 70), + # + ((63, 64), 68), + ((66, 67), 72), + # + (68, 75), + (71, 79), + # + ((69, 70), 77), + ((72, 73), 81), + # + (74, 84), + (75, 85), + (76, 86), + (77, 87), + (78, 88), + (79, 89), + (80, 90), + (81, 91), + (82, 92), + (83, 93), + (84, 94), + (85, 95), + (86, 96), + (87, 97), + (88, 98), + (89, 99), + (90, 100), + (91, 101), + (92, 102), + (93, 103) +] + +mapping_wflw = [ + # + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), + (17, 17), + (18, 18), + (19, 19), + (20, 20), + (21, 21), + (22, 22), + (23, 23), + (24, 24), + (25, 25), + (26, 26), + (27, 27), + (28, 28), + (29, 29), + (30, 30), + (31, 31), + (32, 32), + # + (33, 33), + (34, 34), + (35, 35), + (36, 36), + (37, 37), + (38, 38), + (39, 39), + (40, 40), + (41, 41), + # + (42, 42), + (43, 43), + (44, 44), + (45, 45), + (46, 46), + (47, 47), + (48, 48), + (49, 49), + (50, 50), + # + (51, 51), + (52, 52), + (53, 53), + (54, 54), + # + (55, 58), + (56, 59), + (57, 60), + (58, 61), + (59, 62), + # + (60, 66), + (61, 67), + (62, 68), + (63, 69), + (64, 70), + (65, 71), + (66, 72), + (67, 73), + # + (68, 75), + (69, 76), + (70, 77), + (71, 78), + (72, 79), + (73, 80), + (74, 81), + (75, 82), + # + (76, 84), + (77, 85), + (78, 86), + (79, 87), + (80, 88), + (81, 89), + (82, 90), + (83, 91), + (84, 92), + (85, 93), + (86, 94), + (87, 95), + (88, 96), + (89, 97), + (90, 98), + (91, 99), + (92, 100), + (93, 101), + (94, 102), + (95, 103), + # + (96, 104), + # + (97, 105) +] + +mapping_cofw = [ + # + (0, 33), + (2, 38), + (4, 35), + (5, 40), + # + (1, 46), + (3, 50), + (6, 44), + (7, 48), + # + (8, 60), + (10, 64), + (12, 62), + (13, 66), + # + (9, 72), + (11, 68), + (14, 70), + (15, 74), + # + (18, 57), + (19, 63), + (20, 54), + (21, 60), + # + (22, 84), + (23, 90), + (24, 87), + (25, 98), + (26, 102), + (27, 93), + # + (28, 16) +] +dataset_coco = dict( + type='CocoWholeBodyFaceDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=kpt_68_to_106) + ], +) + +dataset_wflw = dict( + type='WFLWDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='wflw/annotations/face_landmarks_wflw_train.json', + data_prefix=dict(img='pose/WFLW/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_wflw) + ], +) + +dataset_300w = dict( + type='Face300WDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='300w/annotations/face_landmarks_300w_train.json', + data_prefix=dict(img='pose/300w/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=kpt_68_to_106) + ], +) + +dataset_cofw = dict( + type='COFWDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='cofw/annotations/cofw_train.json', + data_prefix=dict(img='pose/COFW/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_cofw) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_133kpt.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_halpe) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/lapa.py'), + datasets=[ + dataset_lapa, dataset_coco, dataset_wflw, dataset_300w, + dataset_cofw, dataset_halpe + ], + pipeline=train_pipeline, + test_mode=False, + )) +val_dataloader = dict( + batch_size=32, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='LaPa/annotations/lapa_test.json', + data_prefix=dict(img='pose/LaPa/'), + test_mode=True, + pipeline=val_pipeline, + )) + +# test dataset +val_lapa = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='LaPa/annotations/lapa_test.json', + data_prefix=dict(img='pose/LaPa/'), + pipeline=[], +) + +val_coco = dict( + type='CocoWholeBodyFaceDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=kpt_68_to_106) + ], +) + +val_wflw = dict( + type='WFLWDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='wflw/annotations/face_landmarks_wflw_test.json', + data_prefix=dict(img='pose/WFLW/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_wflw) + ], +) + +val_300w = dict( + type='Face300WDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='300w/annotations/face_landmarks_300w_test.json', + data_prefix=dict(img='pose/300w/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=kpt_68_to_106) + ], +) + +val_cofw = dict( + type='COFWDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='cofw/annotations/cofw_test.json', + data_prefix=dict(img='pose/COFW/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_cofw) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_halpe) + ], +) + +test_dataloader = dict( + batch_size=32, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/lapa.py'), + datasets=[val_lapa, val_coco, val_wflw, val_300w, val_cofw, val_halpe], + pipeline=val_pipeline, + test_mode=True, + )) + +# hooks +default_hooks = dict( + checkpoint=dict( + save_best='NME', rule='less', max_keep_ckpts=1, interval=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='NME', + norm_mode='keypoint_distance', +) +test_evaluator = val_evaluator diff --git a/configs/face_2d_keypoint/rtmpose/face6/rtmpose-s_8xb256-120e_face6-256x256.py b/configs/face_2d_keypoint/rtmpose/face6/rtmpose-s_8xb256-120e_face6-256x256.py new file mode 100644 index 0000000000..62fa305115 --- /dev/null +++ b/configs/face_2d_keypoint/rtmpose/face6/rtmpose-s_8xb256-120e_face6-256x256.py @@ -0,0 +1,691 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# lapa coco wflw 300w cofw halpe + +# runtime +max_epochs = 120 +stage2_num_epochs = 10 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=1) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.005, + begin=30, + end=max_epochs, + T_max=max_epochs - 30, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(256, 256), + sigma=(5.66, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.33, + widen_factor=0.5, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmdetection/v3.0/' + 'rtmdet/cspnext_rsb_pretrain/cspnext-s_imagenet_600e-ea671761.pth') + ), + head=dict( + type='RTMCCHead', + in_channels=512, + out_channels=106, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True, )) + +# base dataset settings +dataset_type = 'LapaDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.2), + dict(type='MedianBlur', p=0.2), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +# train dataset +dataset_lapa = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='LaPa/annotations/lapa_trainval.json', + data_prefix=dict(img='pose/LaPa/'), + pipeline=[], +) + +kpt_68_to_106 = [ + # + (0, 0), + (1, 2), + (2, 4), + (3, 6), + (4, 8), + (5, 10), + (6, 12), + (7, 14), + (8, 16), + (9, 18), + (10, 20), + (11, 22), + (12, 24), + (13, 26), + (14, 28), + (15, 30), + (16, 32), + # + (17, 33), + (18, 34), + (19, 35), + (20, 36), + (21, 37), + # + (22, 42), + (23, 43), + (24, 44), + (25, 45), + (26, 46), + # + (27, 51), + (28, 52), + (29, 53), + (30, 54), + # + (31, 58), + (32, 59), + (33, 60), + (34, 61), + (35, 62), + # + (36, 66), + (39, 70), + # + ((37, 38), 68), + ((40, 41), 72), + # + (42, 75), + (45, 79), + # + ((43, 44), 77), + ((46, 47), 81), + # + (48, 84), + (49, 85), + (50, 86), + (51, 87), + (52, 88), + (53, 89), + (54, 90), + (55, 91), + (56, 92), + (57, 93), + (58, 94), + (59, 95), + (60, 96), + (61, 97), + (62, 98), + (63, 99), + (64, 100), + (65, 101), + (66, 102), + (67, 103) +] + +mapping_halpe = [ + # + (26, 0), + (27, 2), + (28, 4), + (29, 6), + (30, 8), + (31, 10), + (32, 12), + (33, 14), + (34, 16), + (35, 18), + (36, 20), + (37, 22), + (38, 24), + (39, 26), + (40, 28), + (41, 30), + (42, 32), + # + (43, 33), + (44, 34), + (45, 35), + (46, 36), + (47, 37), + # + (48, 42), + (49, 43), + (50, 44), + (51, 45), + (52, 46), + # + (53, 51), + (54, 52), + (55, 53), + (56, 54), + # + (57, 58), + (58, 59), + (59, 60), + (60, 61), + (61, 62), + # + (62, 66), + (65, 70), + # + ((63, 64), 68), + ((66, 67), 72), + # + (68, 75), + (71, 79), + # + ((69, 70), 77), + ((72, 73), 81), + # + (74, 84), + (75, 85), + (76, 86), + (77, 87), + (78, 88), + (79, 89), + (80, 90), + (81, 91), + (82, 92), + (83, 93), + (84, 94), + (85, 95), + (86, 96), + (87, 97), + (88, 98), + (89, 99), + (90, 100), + (91, 101), + (92, 102), + (93, 103) +] + +mapping_wflw = [ + # + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), + (17, 17), + (18, 18), + (19, 19), + (20, 20), + (21, 21), + (22, 22), + (23, 23), + (24, 24), + (25, 25), + (26, 26), + (27, 27), + (28, 28), + (29, 29), + (30, 30), + (31, 31), + (32, 32), + # + (33, 33), + (34, 34), + (35, 35), + (36, 36), + (37, 37), + (38, 38), + (39, 39), + (40, 40), + (41, 41), + # + (42, 42), + (43, 43), + (44, 44), + (45, 45), + (46, 46), + (47, 47), + (48, 48), + (49, 49), + (50, 50), + # + (51, 51), + (52, 52), + (53, 53), + (54, 54), + # + (55, 58), + (56, 59), + (57, 60), + (58, 61), + (59, 62), + # + (60, 66), + (61, 67), + (62, 68), + (63, 69), + (64, 70), + (65, 71), + (66, 72), + (67, 73), + # + (68, 75), + (69, 76), + (70, 77), + (71, 78), + (72, 79), + (73, 80), + (74, 81), + (75, 82), + # + (76, 84), + (77, 85), + (78, 86), + (79, 87), + (80, 88), + (81, 89), + (82, 90), + (83, 91), + (84, 92), + (85, 93), + (86, 94), + (87, 95), + (88, 96), + (89, 97), + (90, 98), + (91, 99), + (92, 100), + (93, 101), + (94, 102), + (95, 103), + # + (96, 104), + # + (97, 105) +] + +mapping_cofw = [ + # + (0, 33), + (2, 38), + (4, 35), + (5, 40), + # + (1, 46), + (3, 50), + (6, 44), + (7, 48), + # + (8, 60), + (10, 64), + (12, 62), + (13, 66), + # + (9, 72), + (11, 68), + (14, 70), + (15, 74), + # + (18, 57), + (19, 63), + (20, 54), + (21, 60), + # + (22, 84), + (23, 90), + (24, 87), + (25, 98), + (26, 102), + (27, 93), + # + (28, 16) +] +dataset_coco = dict( + type='CocoWholeBodyFaceDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=kpt_68_to_106) + ], +) + +dataset_wflw = dict( + type='WFLWDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='wflw/annotations/face_landmarks_wflw_train.json', + data_prefix=dict(img='pose/WFLW/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_wflw) + ], +) + +dataset_300w = dict( + type='Face300WDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='300w/annotations/face_landmarks_300w_train.json', + data_prefix=dict(img='pose/300w/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=kpt_68_to_106) + ], +) + +dataset_cofw = dict( + type='COFWDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='cofw/annotations/cofw_train.json', + data_prefix=dict(img='pose/COFW/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_cofw) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_133kpt.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_halpe) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/lapa.py'), + datasets=[ + dataset_lapa, dataset_coco, dataset_wflw, dataset_300w, + dataset_cofw, dataset_halpe + ], + pipeline=train_pipeline, + test_mode=False, + )) +val_dataloader = dict( + batch_size=32, + num_workers=10, + pin_memory=True, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='LaPa/annotations/lapa_test.json', + data_prefix=dict(img='pose/LaPa/'), + test_mode=True, + pipeline=val_pipeline, + )) + +# test dataset +val_lapa = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='LaPa/annotations/lapa_test.json', + data_prefix=dict(img='pose/LaPa/'), + pipeline=[], +) + +val_coco = dict( + type='CocoWholeBodyFaceDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=kpt_68_to_106) + ], +) + +val_wflw = dict( + type='WFLWDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='wflw/annotations/face_landmarks_wflw_test.json', + data_prefix=dict(img='pose/WFLW/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_wflw) + ], +) + +val_300w = dict( + type='Face300WDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='300w/annotations/face_landmarks_300w_test.json', + data_prefix=dict(img='pose/300w/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=kpt_68_to_106) + ], +) + +val_cofw = dict( + type='COFWDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='cofw/annotations/cofw_test.json', + data_prefix=dict(img='pose/COFW/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_cofw) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_halpe) + ], +) + +test_dataloader = dict( + batch_size=32, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/lapa.py'), + datasets=[val_lapa, val_coco, val_wflw, val_300w, val_cofw, val_halpe], + pipeline=val_pipeline, + test_mode=True, + )) + +# hooks +default_hooks = dict( + checkpoint=dict( + save_best='NME', rule='less', max_keep_ckpts=1, interval=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='NME', + norm_mode='keypoint_distance', +) +test_evaluator = val_evaluator diff --git a/configs/face_2d_keypoint/rtmpose/face6/rtmpose-t_8xb256-120e_face6-256x256.py b/configs/face_2d_keypoint/rtmpose/face6/rtmpose-t_8xb256-120e_face6-256x256.py new file mode 100644 index 0000000000..751bedffe7 --- /dev/null +++ b/configs/face_2d_keypoint/rtmpose/face6/rtmpose-t_8xb256-120e_face6-256x256.py @@ -0,0 +1,689 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# lapa coco wflw 300w cofw halpe + +# runtime +max_epochs = 120 +stage2_num_epochs = 10 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=1) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.005, + begin=30, + end=max_epochs, + T_max=90, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(256, 256), + sigma=(5.66, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.167, + widen_factor=0.375, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmdetection/v3.0/' + 'rtmdet/cspnext_rsb_pretrain/cspnext-tiny_imagenet_600e-3a2dd350.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=384, + out_channels=106, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True, )) + +# base dataset settings +dataset_type = 'LapaDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.2), + dict(type='MedianBlur', p=0.2), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +# train dataset +dataset_lapa = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='LaPa/annotations/lapa_trainval.json', + data_prefix=dict(img='pose/LaPa/'), + pipeline=[], +) + +kpt_68_to_106 = [ + # + (0, 0), + (1, 2), + (2, 4), + (3, 6), + (4, 8), + (5, 10), + (6, 12), + (7, 14), + (8, 16), + (9, 18), + (10, 20), + (11, 22), + (12, 24), + (13, 26), + (14, 28), + (15, 30), + (16, 32), + # + (17, 33), + (18, 34), + (19, 35), + (20, 36), + (21, 37), + # + (22, 42), + (23, 43), + (24, 44), + (25, 45), + (26, 46), + # + (27, 51), + (28, 52), + (29, 53), + (30, 54), + # + (31, 58), + (32, 59), + (33, 60), + (34, 61), + (35, 62), + # + (36, 66), + (39, 70), + # + ((37, 38), 68), + ((40, 41), 72), + # + (42, 75), + (45, 79), + # + ((43, 44), 77), + ((46, 47), 81), + # + (48, 84), + (49, 85), + (50, 86), + (51, 87), + (52, 88), + (53, 89), + (54, 90), + (55, 91), + (56, 92), + (57, 93), + (58, 94), + (59, 95), + (60, 96), + (61, 97), + (62, 98), + (63, 99), + (64, 100), + (65, 101), + (66, 102), + (67, 103) +] + +mapping_halpe = [ + # + (26, 0), + (27, 2), + (28, 4), + (29, 6), + (30, 8), + (31, 10), + (32, 12), + (33, 14), + (34, 16), + (35, 18), + (36, 20), + (37, 22), + (38, 24), + (39, 26), + (40, 28), + (41, 30), + (42, 32), + # + (43, 33), + (44, 34), + (45, 35), + (46, 36), + (47, 37), + # + (48, 42), + (49, 43), + (50, 44), + (51, 45), + (52, 46), + # + (53, 51), + (54, 52), + (55, 53), + (56, 54), + # + (57, 58), + (58, 59), + (59, 60), + (60, 61), + (61, 62), + # + (62, 66), + (65, 70), + # + ((63, 64), 68), + ((66, 67), 72), + # + (68, 75), + (71, 79), + # + ((69, 70), 77), + ((72, 73), 81), + # + (74, 84), + (75, 85), + (76, 86), + (77, 87), + (78, 88), + (79, 89), + (80, 90), + (81, 91), + (82, 92), + (83, 93), + (84, 94), + (85, 95), + (86, 96), + (87, 97), + (88, 98), + (89, 99), + (90, 100), + (91, 101), + (92, 102), + (93, 103) +] + +mapping_wflw = [ + # + (0, 0), + (1, 1), + (2, 2), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), + (17, 17), + (18, 18), + (19, 19), + (20, 20), + (21, 21), + (22, 22), + (23, 23), + (24, 24), + (25, 25), + (26, 26), + (27, 27), + (28, 28), + (29, 29), + (30, 30), + (31, 31), + (32, 32), + # + (33, 33), + (34, 34), + (35, 35), + (36, 36), + (37, 37), + (38, 38), + (39, 39), + (40, 40), + (41, 41), + # + (42, 42), + (43, 43), + (44, 44), + (45, 45), + (46, 46), + (47, 47), + (48, 48), + (49, 49), + (50, 50), + # + (51, 51), + (52, 52), + (53, 53), + (54, 54), + # + (55, 58), + (56, 59), + (57, 60), + (58, 61), + (59, 62), + # + (60, 66), + (61, 67), + (62, 68), + (63, 69), + (64, 70), + (65, 71), + (66, 72), + (67, 73), + # + (68, 75), + (69, 76), + (70, 77), + (71, 78), + (72, 79), + (73, 80), + (74, 81), + (75, 82), + # + (76, 84), + (77, 85), + (78, 86), + (79, 87), + (80, 88), + (81, 89), + (82, 90), + (83, 91), + (84, 92), + (85, 93), + (86, 94), + (87, 95), + (88, 96), + (89, 97), + (90, 98), + (91, 99), + (92, 100), + (93, 101), + (94, 102), + (95, 103), + # + (96, 104), + # + (97, 105) +] + +mapping_cofw = [ + # + (0, 33), + (2, 38), + (4, 35), + (5, 40), + # + (1, 46), + (3, 50), + (6, 44), + (7, 48), + # + (8, 60), + (10, 64), + (12, 62), + (13, 66), + # + (9, 72), + (11, 68), + (14, 70), + (15, 74), + # + (18, 57), + (19, 63), + (20, 54), + (21, 60), + # + (22, 84), + (23, 90), + (24, 87), + (25, 98), + (26, 102), + (27, 93), + # + (28, 16) +] +dataset_coco = dict( + type='CocoWholeBodyFaceDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=kpt_68_to_106) + ], +) + +dataset_wflw = dict( + type='WFLWDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='wflw/annotations/face_landmarks_wflw_train.json', + data_prefix=dict(img='pose/WFLW/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_wflw) + ], +) + +dataset_300w = dict( + type='Face300WDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='300w/annotations/face_landmarks_300w_train.json', + data_prefix=dict(img='pose/300w/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=kpt_68_to_106) + ], +) + +dataset_cofw = dict( + type='COFWDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='cofw/annotations/cofw_train.json', + data_prefix=dict(img='pose/COFW/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_cofw) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_133kpt.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_halpe) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/lapa.py'), + datasets=[ + dataset_lapa, dataset_coco, dataset_wflw, dataset_300w, + dataset_cofw, dataset_halpe + ], + pipeline=train_pipeline, + test_mode=False, + )) +val_dataloader = dict( + batch_size=32, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='LaPa/annotations/lapa_test.json', + data_prefix=dict(img='pose/LaPa/'), + test_mode=True, + pipeline=val_pipeline, + )) + +# test dataset +val_lapa = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='LaPa/annotations/lapa_test.json', + data_prefix=dict(img='pose/LaPa/'), + pipeline=[], +) + +val_coco = dict( + type='CocoWholeBodyFaceDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=kpt_68_to_106) + ], +) + +val_wflw = dict( + type='WFLWDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='wflw/annotations/face_landmarks_wflw_test.json', + data_prefix=dict(img='pose/WFLW/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_wflw) + ], +) + +val_300w = dict( + type='Face300WDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='300w/annotations/face_landmarks_300w_test.json', + data_prefix=dict(img='pose/300w/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=kpt_68_to_106) + ], +) + +val_cofw = dict( + type='COFWDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='cofw/annotations/cofw_test.json', + data_prefix=dict(img='pose/COFW/images/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_cofw) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', num_keypoints=106, mapping=mapping_halpe) + ], +) + +test_dataloader = dict( + batch_size=32, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/lapa.py'), + datasets=[val_lapa, val_coco, val_wflw, val_300w, val_cofw, val_halpe], + pipeline=val_pipeline, + test_mode=True, + )) + +# hooks +default_hooks = dict( + checkpoint=dict( + save_best='NME', rule='less', max_keep_ckpts=1, interval=1)) + +custom_hooks = [ + # dict( + # type='EMAHook', + # ema_type='ExpMomentumEMA', + # momentum=0.0002, + # update_buffers=True, + # priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='NME', + norm_mode='keypoint_distance', +) +test_evaluator = val_evaluator diff --git a/configs/face_2d_keypoint/rtmpose/face6/rtmpose_face6.md b/configs/face_2d_keypoint/rtmpose/face6/rtmpose_face6.md new file mode 100644 index 0000000000..254633e42c --- /dev/null +++ b/configs/face_2d_keypoint/rtmpose/face6/rtmpose_face6.md @@ -0,0 +1,71 @@ + + +
+RTMPose (arXiv'2023) + +```bibtex +@misc{https://doi.org/10.48550/arxiv.2303.07399, + doi = {10.48550/ARXIV.2303.07399}, + url = {https://arxiv.org/abs/2303.07399}, + author = {Jiang, Tao and Lu, Peng and Zhang, Li and Ma, Ningsheng and Han, Rui and Lyu, Chengqi and Li, Yining and Chen, Kai}, + keywords = {Computer Vision and Pattern Recognition (cs.CV), FOS: Computer and information sciences, FOS: Computer and information sciences}, + title = {RTMPose: Real-Time Multi-Person Pose Estimation based on MMPose}, + publisher = {arXiv}, + year = {2023}, + copyright = {Creative Commons Attribution 4.0 International} +} + +``` + +
+ + + +
+RTMDet (arXiv'2022) + +```bibtex +@misc{lyu2022rtmdet, + title={RTMDet: An Empirical Study of Designing Real-Time Object Detectors}, + author={Chengqi Lyu and Wenwei Zhang and Haian Huang and Yue Zhou and Yudong Wang and Yanyi Liu and Shilong Zhang and Kai Chen}, + year={2022}, + eprint={2212.07784}, + archivePrefix={arXiv}, + primaryClass={cs.CV} +} +``` + +
+ + + +
+COCO (ECCV'2014) + +```bibtex +@inproceedings{lin2014microsoft, + title={Microsoft coco: Common objects in context}, + author={Lin, Tsung-Yi and Maire, Michael and Belongie, Serge and Hays, James and Perona, Pietro and Ramanan, Deva and Doll{\'a}r, Piotr and Zitnick, C Lawrence}, + booktitle={European conference on computer vision}, + pages={740--755}, + year={2014}, + organization={Springer} +} +``` + +
+ +- Results on COCO val2017 with detector having human AP of 56.4 on COCO val2017 dataset. +- `Face6` and `*` denote model trained on 6 public datasets: + - [COCO-Wholebody-Face](https://github.com/jin-s13/COCO-WholeBody/) + - [WFLW](https://wywu.github.io/projects/LAB/WFLW.html) + - [300W](https://ibug.doc.ic.ac.uk/resources/300-W/) + - [COFW](http://www.vision.caltech.edu/xpburgos/ICCV13/) + - [Halpe](https://github.com/Fang-Haoshu/Halpe-FullBody/) + - [LaPa](https://github.com/JDAI-CV/lapa-dataset) + +| Config | Input Size | NME
(LaPa) | FLOPS
(G) | Download | +| :--------------------------------------------------------------------------: | :--------: | :----------------: | :---------------: | :-----------------------------------------------------------------------------: | +| [RTMPose-t\*](./rtmpose/face_2d_keypoint/rtmpose-t_8xb256-120e_lapa-256x256.py) | 256x256 | 1.67 | 0.652 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_simcc-face6_pt-in1k_120e-256x256-df79d9a5_20230529.pth) | +| [RTMPose-s\*](./rtmpose/face_2d_keypoint/rtmpose-m_8xb256-120e_lapa-256x256.py) | 256x256 | 1.59 | 1.119 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-face6_pt-in1k_120e-256x256-d779fdef_20230529.pth) | +| [RTMPose-m\*](./rtmpose/face_2d_keypoint/rtmpose-m_8xb256-120e_lapa-256x256.py) | 256x256 | 1.44 | 2.852 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-face6_pt-in1k_120e-256x256-72a37400_20230529.pth) | diff --git a/configs/face_2d_keypoint/rtmpose/face6/rtmpose_face6.yml b/configs/face_2d_keypoint/rtmpose/face6/rtmpose_face6.yml new file mode 100644 index 0000000000..2cd822a337 --- /dev/null +++ b/configs/face_2d_keypoint/rtmpose/face6/rtmpose_face6.yml @@ -0,0 +1,50 @@ +Collections: +- Name: RTMPose + Paper: + Title: "RTMPose: Real-Time Multi-Person Pose Estimation based on MMPose" + URL: https://arxiv.org/abs/2303.07399 + README: https://github.com/open-mmlab/mmpose/blob/main/projects/rtmpose/README.md +Models: +- Config: configs/face_2d_keypoint/rtmpose/face6/rtmpose-t_8xb256-120e_face6-256x256.py + In Collection: RTMPose + Metadata: + Architecture: &id001 + - RTMPose + Training Data: &id002 + - COCO-Wholebody-Face + - WFLW + - 300W + - COFW + - Halpe + - LaPa + Name: rtmpose-t_8xb256-120e_face6-256x256 + Results: + - Dataset: Face6 + Metrics: + NME: 1.67 + Task: Face 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_simcc-face6_pt-in1k_120e-256x256-df79d9a5_20230529.pth +- Config: configs/face_2d_keypoint/rtmpose/face6/rtmpose-s_8xb256-120e_face6-256x256.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-s_8xb256-120e_face6-256x256 + Results: + - Dataset: Face6 + Metrics: + NME: 1.59 + Task: Face 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-face6_pt-in1k_120e-256x256-d779fdef_20230529.pth +- Config: configs/face_2d_keypoint/rtmpose/face6/rtmpose-m_8xb256-120e_face6-256x256.py + In Collection: RTMPose + Metadata: + Architecture: *id001 + Training Data: *id002 + Name: rtmpose-m_8xb256-120e_face6-256x256 + Results: + - Dataset: Face6 + Metrics: + NME: 1.44 + Task: Face 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-face6_pt-in1k_120e-256x256-72a37400_20230529.pth diff --git a/configs/face_2d_keypoint/rtmpose/lapa/rtmpose-m_8xb64-120e_lapa-256x256.py b/configs/face_2d_keypoint/rtmpose/lapa/rtmpose-m_8xb64-120e_lapa-256x256.py new file mode 100644 index 0000000000..fee1201db1 --- /dev/null +++ b/configs/face_2d_keypoint/rtmpose/lapa/rtmpose-m_8xb64-120e_lapa-256x256.py @@ -0,0 +1,246 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +max_epochs = 120 +stage2_num_epochs = 10 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=1) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(256, 256), + sigma=(5.66, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.67, + widen_factor=0.75, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=768, + out_channels=106, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True, )) + +# base dataset settings +dataset_type = 'LapaDataset' +data_mode = 'topdown' +data_root = 'data/LaPa/' + +backend_args = dict(backend='local') +# backend_args = dict( +# backend='petrel', +# path_mapping=dict({ +# f'{data_root}': 's3://openmmlab/datasets/pose/LaPa/', +# f'{data_root}': 's3://openmmlab/datasets/pose/LaPa/' +# })) + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.2), + dict(type='MedianBlur', p=0.2), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + # dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=32, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/lapa_train.json', + data_prefix=dict(img=''), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/lapa_val.json', + data_prefix=dict(img=''), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = dict( + batch_size=32, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/lapa_test.json', + data_prefix=dict(img=''), + test_mode=True, + pipeline=val_pipeline, + )) + +# hooks +default_hooks = dict( + checkpoint=dict( + save_best='NME', rule='less', max_keep_ckpts=1, interval=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='NME', + norm_mode='keypoint_distance', +) +test_evaluator = val_evaluator diff --git a/configs/face_2d_keypoint/rtmpose/lapa/rtmpose_lapa.md b/configs/face_2d_keypoint/rtmpose/lapa/rtmpose_lapa.md new file mode 100644 index 0000000000..9638de7551 --- /dev/null +++ b/configs/face_2d_keypoint/rtmpose/lapa/rtmpose_lapa.md @@ -0,0 +1,40 @@ + + +
+RTMDet (ArXiv 2022) + +```bibtex +@misc{lyu2022rtmdet, + title={RTMDet: An Empirical Study of Designing Real-Time Object Detectors}, + author={Chengqi Lyu and Wenwei Zhang and Haian Huang and Yue Zhou and Yudong Wang and Yanyi Liu and Shilong Zhang and Kai Chen}, + year={2022}, + eprint={2212.07784}, + archivePrefix={arXiv}, + primaryClass={cs.CV} +} +``` + +
+ + + +
+LaPa (AAAI'2020) + +```bibtex +@inproceedings{liu2020new, + title={A New Dataset and Boundary-Attention Semantic Segmentation for Face Parsing.}, + author={Liu, Yinglu and Shi, Hailin and Shen, Hao and Si, Yue and Wang, Xiaobo and Mei, Tao}, + booktitle={AAAI}, + pages={11637--11644}, + year={2020} +} +``` + +
+ +Results on LaPa val set + +| Arch | Input Size | NME | ckpt | log | +| :------------------------------------------------------------- | :--------: | :--: | :------------------------------------------------------------: | :------------------------------------------------------------: | +| [pose_rtmpose_m](/configs/face_2d_keypoint/rtmpose/lapa/rtmpose-m_8xb64-120e_lapa-256x256.py) | 256x256 | 1.29 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-lapa_pt-aic-coco_120e-256x256-762b1ae2_20230422.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-lapa_pt-aic-coco_120e-256x256-762b1ae2_20230422.json) | diff --git a/configs/face_2d_keypoint/rtmpose/lapa/rtmpose_lapa.yml b/configs/face_2d_keypoint/rtmpose/lapa/rtmpose_lapa.yml new file mode 100644 index 0000000000..96acff8de6 --- /dev/null +++ b/configs/face_2d_keypoint/rtmpose/lapa/rtmpose_lapa.yml @@ -0,0 +1,15 @@ +Models: +- Config: configs/face_2d_keypoint/rtmpose/lapa/rtmpose-m_8xb64-120e_lapa-256x256.py + In Collection: RTMPose + Alias: face + Metadata: + Architecture: + - RTMPose + Training Data: LaPa + Name: rtmpose-m_8xb64-120e_lapa-256x256 + Results: + - Dataset: WFLW + Metrics: + NME: 1.29 + Task: Face 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-lapa_pt-aic-coco_120e-256x256-762b1ae2_20230422.pth diff --git a/configs/face_2d_keypoint/rtmpose/wflw/rtmpose-m_8xb64-60e_wflw-256x256.py b/configs/face_2d_keypoint/rtmpose/wflw/rtmpose-m_8xb64-60e_wflw-256x256.py index 8179511e83..cbfd788d60 100644 --- a/configs/face_2d_keypoint/rtmpose/wflw/rtmpose-m_8xb64-60e_wflw-256x256.py +++ b/configs/face_2d_keypoint/rtmpose/wflw/rtmpose-m_8xb64-60e_wflw-256x256.py @@ -24,7 +24,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -69,14 +68,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, out_channels=98, input_size=codec['input_size'], - in_featuremap_size=(8, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/face_2d_keypoint/rtmpose/wflw/rtmpose_wflw.md b/configs/face_2d_keypoint/rtmpose/wflw/rtmpose_wflw.md index 2b7903cec5..b0070258da 100644 --- a/configs/face_2d_keypoint/rtmpose/wflw/rtmpose_wflw.md +++ b/configs/face_2d_keypoint/rtmpose/wflw/rtmpose_wflw.md @@ -39,4 +39,4 @@ The model is trained on WFLW train. | Arch | Input Size | NME | ckpt | log | | :------------------------------------------------------------- | :--------: | :--: | :------------------------------------------------------------: | :------------------------------------------------------------: | -| [pose_rtmpose_m](/configs/face_2d_keypoint/rtmpose/wflw/rtmpose-m_8xb64-60e_wflw-256x256.py) | 256x256 | 4.01 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-wflw_pt-aic-coco_60e-256x256-dc1dcdcf_20230228.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-wflw_pt-aic-coco_60e-256x256-dc1dcdcf_20230228.json) | +| [pose_rtmpose_m](/configs/face_2d_keypoint/rtmpose/wflw/rtmpose-m_8xb64-60e_wflw-256x256.py) | 256x256 | 4.01 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-wflw_pt-aic-coco_60e-256x256-dc1dcdcf_20230228.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-wflw_pt-aic-coco_60e-256x256-dc1dcdcf_20230228.json) | diff --git a/configs/face_2d_keypoint/rtmpose/wflw/rtmpose_wflw.yml b/configs/face_2d_keypoint/rtmpose/wflw/rtmpose_wflw.yml index 8896f30131..deee03a7dd 100644 --- a/configs/face_2d_keypoint/rtmpose/wflw/rtmpose_wflw.yml +++ b/configs/face_2d_keypoint/rtmpose/wflw/rtmpose_wflw.yml @@ -12,4 +12,4 @@ Models: Metrics: NME: 4.01 Task: Face 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-wflw_pt-aic-coco_60e-256x256-dc1dcdcf_20230228.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-wflw_pt-aic-coco_60e-256x256-dc1dcdcf_20230228.pth diff --git a/configs/face_2d_keypoint/topdown_regression/README.md b/configs/face_2d_keypoint/topdown_regression/README.md new file mode 100644 index 0000000000..5d20cb9a31 --- /dev/null +++ b/configs/face_2d_keypoint/topdown_regression/README.md @@ -0,0 +1,19 @@ +# Top-down regression-based pose estimation + +Top-down methods divide the task into two stages: object detection, followed by single-object pose estimation given object bounding boxes. At the 2nd stage, regression based methods directly regress the keypoint coordinates given the features extracted from the bounding box area, following the paradigm introduced in [Deeppose: Human pose estimation via deep neural networks](http://openaccess.thecvf.com/content_cvpr_2014/html/Toshev_DeepPose_Human_Pose_2014_CVPR_paper.html). + +
+ +
+ +## Results and Models + +### WFLW Dataset + +Result on WFLW test set + +| Model | Input Size | NME | ckpt | log | +| :-------------------------------------------------------------- | :--------: | :--: | :------------------------------------------------------------: | :-----------------------------------------------------------: | +| [ResNet-50](/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_8xb64-210e_wflw-256x256.py) | 256x256 | 4.88 | [ckpt](https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256-92d0ba7f_20210303.pth) | [log](https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256_20210303.log.json) | +| [ResNet-50+WingLoss](/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_wingloss_8xb64-210e_wflw-256x256.py) | 256x256 | 4.67 | [ckpt](https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256_wingloss-f82a5e53_20210303.pth) | [log](https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256_wingloss_20210303.log.json) | +| [ResNet-50+SoftWingLoss](/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_softwingloss_8xb64-210e_wflw-256x256.py) | 256x256 | 4.44 | [ckpt](https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256_softwingloss-4d34f22a_20211212.pth) | [log](https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256_softwingloss_20211212.log.json) | diff --git a/configs/face_2d_keypoint/topdown_regression/wflw/resnet_softwingloss_wflw.md b/configs/face_2d_keypoint/topdown_regression/wflw/resnet_softwingloss_wflw.md new file mode 100644 index 0000000000..f1d9629d0a --- /dev/null +++ b/configs/face_2d_keypoint/topdown_regression/wflw/resnet_softwingloss_wflw.md @@ -0,0 +1,75 @@ + + +
+DeepPose (CVPR'2014) + +```bibtex +@inproceedings{toshev2014deeppose, + title={Deeppose: Human pose estimation via deep neural networks}, + author={Toshev, Alexander and Szegedy, Christian}, + booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, + pages={1653--1660}, + year={2014} +} +``` + +
+ + + +
+ResNet (CVPR'2016) + +```bibtex +@inproceedings{he2016deep, + title={Deep residual learning for image recognition}, + author={He, Kaiming and Zhang, Xiangyu and Ren, Shaoqing and Sun, Jian}, + booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, + pages={770--778}, + year={2016} +} +``` + +
+ + + +
+SoftWingloss (TIP'2021) + +```bibtex +@article{lin2021structure, + title={Structure-Coherent Deep Feature Learning for Robust Face Alignment}, + author={Lin, Chunze and Zhu, Beier and Wang, Quan and Liao, Renjie and Qian, Chen and Lu, Jiwen and Zhou, Jie}, + journal={IEEE Transactions on Image Processing}, + year={2021}, + publisher={IEEE} +} +``` + +
+ + + +
+WFLW (CVPR'2018) + +```bibtex +@inproceedings{wu2018look, + title={Look at boundary: A boundary-aware face alignment algorithm}, + author={Wu, Wayne and Qian, Chen and Yang, Shuo and Wang, Quan and Cai, Yici and Zhou, Qiang}, + booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, + pages={2129--2138}, + year={2018} +} +``` + +
+ +Results on WFLW dataset + +The model is trained on WFLW train set. + +| Model | Input Size | NME | ckpt | log | +| :-------------------------------------------------------------- | :--------: | :--: | :------------------------------------------------------------: | :-----------------------------------------------------------: | +| [ResNet-50+SoftWingLoss](/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_softwingloss_8xb64-210e_wflw-256x256.py) | 256x256 | 4.44 | [ckpt](https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256_softwingloss-4d34f22a_20211212.pth) | [log](https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256_softwingloss_20211212.log.json) | diff --git a/configs/face_2d_keypoint/topdown_regression/wflw/resnet_softwingloss_wflw.yml b/configs/face_2d_keypoint/topdown_regression/wflw/resnet_softwingloss_wflw.yml new file mode 100644 index 0000000000..7c65215ccc --- /dev/null +++ b/configs/face_2d_keypoint/topdown_regression/wflw/resnet_softwingloss_wflw.yml @@ -0,0 +1,16 @@ +Models: +- Config: configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_softwingloss_8xb64-210e_wflw-256x256.py + In Collection: ResNet + Metadata: + Architecture: + - DeepPose + - ResNet + - SoftWingloss + Training Data: WFLW + Name: td-reg_res50_softwingloss_8xb64-210e_wflw-256x256 + Results: + - Dataset: WFLW + Metrics: + NME: 4.44 + Task: Face 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256_softwingloss-4d34f22a_20211212.pth diff --git a/configs/face_2d_keypoint/topdown_regression/wflw/resnet_wflw.md b/configs/face_2d_keypoint/topdown_regression/wflw/resnet_wflw.md new file mode 100644 index 0000000000..1ec3e76dba --- /dev/null +++ b/configs/face_2d_keypoint/topdown_regression/wflw/resnet_wflw.md @@ -0,0 +1,58 @@ + + +
+DeepPose (CVPR'2014) + +```bibtex +@inproceedings{toshev2014deeppose, + title={Deeppose: Human pose estimation via deep neural networks}, + author={Toshev, Alexander and Szegedy, Christian}, + booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, + pages={1653--1660}, + year={2014} +} +``` + +
+ + + +
+ResNet (CVPR'2016) + +```bibtex +@inproceedings{he2016deep, + title={Deep residual learning for image recognition}, + author={He, Kaiming and Zhang, Xiangyu and Ren, Shaoqing and Sun, Jian}, + booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, + pages={770--778}, + year={2016} +} +``` + +
+ + + +
+WFLW (CVPR'2018) + +```bibtex +@inproceedings{wu2018look, + title={Look at boundary: A boundary-aware face alignment algorithm}, + author={Wu, Wayne and Qian, Chen and Yang, Shuo and Wang, Quan and Cai, Yici and Zhou, Qiang}, + booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, + pages={2129--2138}, + year={2018} +} +``` + +
+ +Results on WFLW dataset + +The model is trained on WFLW train set. + +| Model | Input Size | NME | ckpt | log | +| :-------------------------------------------------------------- | :--------: | :--: | :------------------------------------------------------------: | :-----------------------------------------------------------: | +| [ResNet-50](/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_8xb64-210e_wflw-256x256.py) | 256x256 | 4.88 | [ckpt](https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256-92d0ba7f_20210303.pth) | [log](https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256_20210303.log.json) | diff --git a/configs/face_2d_keypoint/topdown_regression/wflw/resnet_wflw.yml b/configs/face_2d_keypoint/topdown_regression/wflw/resnet_wflw.yml new file mode 100644 index 0000000000..81c7b79a7e --- /dev/null +++ b/configs/face_2d_keypoint/topdown_regression/wflw/resnet_wflw.yml @@ -0,0 +1,15 @@ +Models: +- Config: configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_8xb64-210e_wflw-256x256.py + In Collection: ResNet + Metadata: + Architecture: + - DeepPose + - ResNet + Training Data: WFLW + Name: td-reg_res50_8x64e-210e_wflw-256x256 + Results: + - Dataset: WFLW + Metrics: + NME: 4.88 + Task: Face 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256-92d0ba7f_20210303.pth diff --git a/configs/face_2d_keypoint/topdown_regression/wflw/resnet_wingloss_wflw.md b/configs/face_2d_keypoint/topdown_regression/wflw/resnet_wingloss_wflw.md new file mode 100644 index 0000000000..51477143d1 --- /dev/null +++ b/configs/face_2d_keypoint/topdown_regression/wflw/resnet_wingloss_wflw.md @@ -0,0 +1,76 @@ + + +
+DeepPose (CVPR'2014) + +```bibtex +@inproceedings{toshev2014deeppose, + title={Deeppose: Human pose estimation via deep neural networks}, + author={Toshev, Alexander and Szegedy, Christian}, + booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, + pages={1653--1660}, + year={2014} +} +``` + +
+ + + +
+ResNet (CVPR'2016) + +```bibtex +@inproceedings{he2016deep, + title={Deep residual learning for image recognition}, + author={He, Kaiming and Zhang, Xiangyu and Ren, Shaoqing and Sun, Jian}, + booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, + pages={770--778}, + year={2016} +} +``` + +
+ + + +
+Wingloss (CVPR'2018) + +```bibtex +@inproceedings{feng2018wing, + title={Wing Loss for Robust Facial Landmark Localisation with Convolutional Neural Networks}, + author={Feng, Zhen-Hua and Kittler, Josef and Awais, Muhammad and Huber, Patrik and Wu, Xiao-Jun}, + booktitle={Computer Vision and Pattern Recognition (CVPR), 2018 IEEE Conference on}, + year={2018}, + pages ={2235-2245}, + organization={IEEE} +} +``` + +
+ + + +
+WFLW (CVPR'2018) + +```bibtex +@inproceedings{wu2018look, + title={Look at boundary: A boundary-aware face alignment algorithm}, + author={Wu, Wayne and Qian, Chen and Yang, Shuo and Wang, Quan and Cai, Yici and Zhou, Qiang}, + booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, + pages={2129--2138}, + year={2018} +} +``` + +
+ +Results on WFLW dataset + +The model is trained on WFLW train set. + +| Model | Input Size | NME | ckpt | log | +| :-------------------------------------------------------------- | :--------: | :--: | :------------------------------------------------------------: | :-----------------------------------------------------------: | +| [ResNet-50+WingLoss](/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_wingloss_8xb64-210e_wflw-256x256.py) | 256x256 | 4.67 | [ckpt](https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256_wingloss-f82a5e53_20210303.pth) | [log](https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256_wingloss_20210303.log.json) | diff --git a/configs/face_2d_keypoint/topdown_regression/wflw/resnet_wingloss_wflw.yml b/configs/face_2d_keypoint/topdown_regression/wflw/resnet_wingloss_wflw.yml new file mode 100644 index 0000000000..49b409121a --- /dev/null +++ b/configs/face_2d_keypoint/topdown_regression/wflw/resnet_wingloss_wflw.yml @@ -0,0 +1,16 @@ +Models: +- Config: configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_wingloss_8xb64-210e_wflw-256x256.py + In Collection: ResNet + Metadata: + Architecture: + - DeepPose + - ResNet + - WingLoss + Training Data: WFLW + Name: td-reg_res50_wingloss_8xb64-210e_wflw-256x256 + Results: + - Dataset: WFLW + Metrics: + NME: 4.67 + Task: Face 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/face/deeppose/deeppose_res50_wflw_256x256_wingloss-f82a5e53_20210303.pth diff --git a/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_8xb64-210e_wflw-256x256.py b/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_8xb64-210e_wflw-256x256.py new file mode 100644 index 0000000000..2742f497b8 --- /dev/null +++ b/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_8xb64-210e_wflw-256x256.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# codec settings +codec = dict(type='RegressionLabel', input_size=(256, 256)) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='RegressionHead', + in_channels=2048, + num_joints=98, + loss=dict(type='SmoothL1Loss', use_target_weight=True), + decoder=codec), + train_cfg=dict(), + test_cfg=dict( + flip_test=True, + shift_coords=True, + )) + +# base dataset settings +dataset_type = 'WFLWDataset' +data_mode = 'topdown' +data_root = 'data/wflw/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict( + type='RandomBBoxTransform', + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# dataloaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/face_landmarks_wflw_train.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/face_landmarks_wflw_test.json', + data_prefix=dict(img='images/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# hooks +default_hooks = dict(checkpoint=dict(save_best='NME', rule='less')) + +# evaluators +val_evaluator = dict( + type='NME', + norm_mode='keypoint_distance', +) +test_evaluator = val_evaluator diff --git a/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_softwingloss_8xb64-210e_wflw-256x256.py b/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_softwingloss_8xb64-210e_wflw-256x256.py new file mode 100644 index 0000000000..eb4199073d --- /dev/null +++ b/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_softwingloss_8xb64-210e_wflw-256x256.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# codec settings +codec = dict(type='RegressionLabel', input_size=(256, 256)) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='RegressionHead', + in_channels=2048, + num_joints=98, + loss=dict(type='SoftWingLoss', use_target_weight=True), + decoder=codec), + train_cfg=dict(), + test_cfg=dict( + flip_test=True, + shift_coords=True, + )) + +# base dataset settings +dataset_type = 'WFLWDataset' +data_mode = 'topdown' +data_root = 'data/wflw/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict( + type='RandomBBoxTransform', + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# dataloaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/face_landmarks_wflw_train.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/face_landmarks_wflw_test.json', + data_prefix=dict(img='images/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# hooks +default_hooks = dict(checkpoint=dict(save_best='NME', rule='less')) + +# evaluators +val_evaluator = dict( + type='NME', + norm_mode='keypoint_distance', +) +test_evaluator = val_evaluator diff --git a/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_wingloss_8xb64-210e_wflw-256x256.py b/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_wingloss_8xb64-210e_wflw-256x256.py new file mode 100644 index 0000000000..ab519cd401 --- /dev/null +++ b/configs/face_2d_keypoint/topdown_regression/wflw/td-reg_res50_wingloss_8xb64-210e_wflw-256x256.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# codec settings +codec = dict(type='RegressionLabel', input_size=(256, 256)) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + neck=dict(type='GlobalAveragePooling'), + head=dict( + type='RegressionHead', + in_channels=2048, + num_joints=98, + loss=dict(type='WingLoss', use_target_weight=True), + decoder=codec), + train_cfg=dict(), + test_cfg=dict( + flip_test=True, + shift_coords=True, + )) + +# base dataset settings +dataset_type = 'WFLWDataset' +data_mode = 'topdown' +data_root = 'data/wflw/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict( + type='RandomBBoxTransform', + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# dataloaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/face_landmarks_wflw_train.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/face_landmarks_wflw_test.json', + data_prefix=dict(img='images/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# hooks +default_hooks = dict(checkpoint=dict(save_best='NME', rule='less')) + +# evaluators +val_evaluator = dict( + type='NME', + norm_mode='keypoint_distance', +) +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/res50_deepfashion2.md b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/res50_deepfashion2.md new file mode 100644 index 0000000000..1dcfd59313 --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/res50_deepfashion2.md @@ -0,0 +1,67 @@ + + +
+SimpleBaseline2D (ECCV'2018) + +```bibtex +@inproceedings{xiao2018simple, + title={Simple baselines for human pose estimation and tracking}, + author={Xiao, Bin and Wu, Haiping and Wei, Yichen}, + booktitle={Proceedings of the European conference on computer vision (ECCV)}, + pages={466--481}, + year={2018} +} +``` + +
+ + + +
+ResNet (CVPR'2016) + +```bibtex +@inproceedings{he2016deep, + title={Deep residual learning for image recognition}, + author={He, Kaiming and Zhang, Xiangyu and Ren, Shaoqing and Sun, Jian}, + booktitle={Proceedings of the IEEE conference on computer vision and pattern recognition}, + pages={770--778}, + year={2016} +} +``` + +
+ + + +
+DeepFashion2 (CVPR'2019) + +```bibtex +@article{DeepFashion2, + author = {Yuying Ge and Ruimao Zhang and Lingyun Wu and Xiaogang Wang and Xiaoou Tang and Ping Luo}, + title={A Versatile Benchmark for Detection, Pose Estimation, Segmentation and Re-Identification of Clothing Images}, + journal={CVPR}, + year={2019} +} +``` + +
+ +Results on DeepFashion2 val set + +| Set | Arch | Input Size | PCK@0.2 | AUC | EPE | ckpt | log | +| :-------------------- | :-------------------------------------------------: | :--------: | :-----: | :---: | :--: | :-------------------------------------------------: | :-------------------------------------------------: | +| short_sleeved_shirt | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_6xb64-210e_deepfasion2-short-sleeved-shirt-256x192.py) | 256x192 | 0.988 | 0.703 | 10.2 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_short_sleeved_shirt_256x192-21e1c5da_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_short_sleeved_shirt_256x192_20221208.log.json) | +| long_sleeved_shirt | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-long-sleeved-shirt-256x192.py) | 256x192 | 0.973 | 0.587 | 16.6 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_long_sleeved_shirt_256x192-8679e7e3_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_long_sleeved_shirt_256x192_20221208.log.json) | +| short_sleeved_outwear | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-short-sleeved-outwear-256x192.py) | 256x192 | 0.966 | 0.408 | 24.0 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_short_sleeved_outwear_256x192-a04c1298_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_short_sleeved_outwear_256x192_20221208.log.json) | +| long_sleeved_outwear | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-long-sleeved-outwear-256x192.py) | 256x192 | 0.987 | 0.517 | 18.1 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_long_sleeved_outwear_256x192-31fbaecf_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_long_sleeved_outwear_256x192_20221208.log.json) | +| vest | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-vest-256x192.py) | 256x192 | 0.981 | 0.643 | 12.7 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_vest_256x192-4c48d05c_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_vest_256x192_20221208.log.json) | +| sling | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-sling-256x192.py) | 256x192 | 0.940 | 0.557 | 21.6 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_sling_256x192-ebb2b736_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_sling_256x192_20221208.log.json) | +| shorts | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_3xb64-210e_deepfasion2-shorts-256x192.py) | 256x192 | 0.975 | 0.682 | 12.4 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_shorts_256x192-9ab23592_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_shorts_256x192_20221208.log.json) | +| trousers | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_2xb64-210e_deepfasion2-trousers-256x192.py) | 256x192 | 0.973 | 0.625 | 14.8 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_trousers_256x192-3e632257_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_trousers_256x192_20221208.log.json) | +| skirt | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-skirt-256x192.py) | 256x192 | 0.952 | 0.653 | 16.6 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_skirt_256x192-09573469_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_skirt_256x192_20221208.log.json) | +| short_sleeved_dress | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-short-sleeved-dress-256x192.py) | 256x192 | 0.980 | 0.603 | 15.6 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_short_sleeved_dress_256x192-1345b07a_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_short_sleeved_dress_256x192_20221208.log.json) | +| long_sleeved_dress | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-long-sleeved-dress-256x192.py) | 256x192 | 0.976 | 0.518 | 20.1 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_long_sleeved_dress_256x192-87bac74e_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_long_sleeved_dress_256x192_20221208.log.json) | +| vest_dress | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-vest-dress-256x192.py) | 256x192 | 0.980 | 0.600 | 16.0 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_vest_dress_256x192-fb3fbd6f_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_vest_dress_256x192_20221208.log.json) | +| sling_dress | [pose_resnet_50](/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-sling-dress-256x192.py) | 256x192 | 0.967 | 0.544 | 19.5 | [ckpt](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_sling_dress_256x192-8ebae0eb_20221208.pth) | [log](https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_sling_dress_256x192_20221208.log.json) | diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/res50_deepfasion2.yml b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/res50_deepfasion2.yml new file mode 100644 index 0000000000..28825fa011 --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/res50_deepfasion2.yml @@ -0,0 +1,185 @@ +Models: +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_6xb64-210e_deepfasion2-short-sleeved-shirt-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: &id001 + - SimpleBaseline2D + - ResNet + Training Data: DeepFashion2 + Name: td-hm_res50_6xb64-210e_deepfasion2-short-sleeved-shirt-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.703 + EPE: 10.2 + PCK@0.2: 0.988 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_short_sleeved_shirt_256x192-21e1c5da_20221208.pth +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-long-sleeved-shirt-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: *id001 + Training Data: DeepFashion2 + Name: td-hm_res50_8xb64-210e_deepfasion2-long-sleeved-shirt-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.587 + EPE: 16.5 + PCK@0.2: 0.973 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_long_sleeved_shirt_256x192-8679e7e3_20221208.pth +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-short-sleeved-outwear-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: *id001 + Training Data: DeepFashion2 + Name: td-hm_res50_8xb64-210e_deepfasion2-short-sleeved-outwear-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.408 + EPE: 24.0 + PCK@0.2: 0.966 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_short_sleeved_outwear_256x192-a04c1298_20221208.pth +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-long-sleeved-outwear-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: *id001 + Training Data: DeepFashion2 + Name: td-hm_res50_8xb64-210e_deepfasion2-long-sleeved-outwear-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.517 + EPE: 18.1 + PCK@0.2: 0.987 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_long_sleeved_outwear_256x192-31fbaecf_20221208.pth +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-vest-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: *id001 + Training Data: DeepFashion2 + Name: td-hm_res50_4xb64-210e_deepfasion2-vest-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.643 + EPE: 12.7 + PCK@0.2: 0.981 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_vest_256x192-4c48d05c_20221208.pth +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-sling-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: *id001 + Training Data: DeepFashion2 + Name: td-hm_res50_4xb64-210e_deepfasion2-sling-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.557 + EPE: 21.6 + PCK@0.2: 0.94 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_sling_256x192-ebb2b736_20221208.pth +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_3xb64-210e_deepfasion2-shorts-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: *id001 + Training Data: DeepFashion2 + Name: td-hm_res50_3xb64-210e_deepfasion2-shorts-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.682 + EPE: 12.4 + PCK@0.2: 0.975 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_shorts_256x192-9ab23592_20221208.pth +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_2xb64-210e_deepfasion2-trousers-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: *id001 + Training Data: DeepFashion2 + Name: td-hm_res50_2xb64-210e_deepfasion2-trousers-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.625 + EPE: 14.8 + PCK@0.2: 0.973 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_trousers_256x192-3e632257_20221208.pth +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-skirt-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: *id001 + Training Data: DeepFashion2 + Name: td-hm_res50_1xb64-210e_deepfasion2-skirt-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.653 + EPE: 16.6 + PCK@0.2: 0.952 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_skirt_256x192-09573469_20221208.pth +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-short-sleeved-dress-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: *id001 + Training Data: DeepFashion2 + Name: td-hm_res50_4xb64-210e_deepfasion2-short-sleeved-dress-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.603 + EPE: 15.6 + PCK@0.2: 0.98 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_short_sleeved_dress_256x192-1345b07a_20221208.pth +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-long-sleeved-dress-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: *id001 + Training Data: DeepFashion2 + Name: td-hm_res50_1xb64-210e_deepfasion2-long-sleeved-dress-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.518 + EPE: 20.1 + PCK@0.2: 0.976 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_long_sleeved_dress_256x192-87bac74e_20221208.pth +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-vest-dress-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: *id001 + Training Data: DeepFashion2 + Name: td-hm_res50_1xb64-210e_deepfasion2-vest-dress-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.6 + EPE: 16.0 + PCK@0.2: 0.98 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_vest_dress_256x192-fb3fbd6f_20221208.pth +- Config: configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-sling-dress-256x192.py + In Collection: SimpleBaseline2D + Metadata: + Architecture: *id001 + Training Data: DeepFashion2 + Name: td-hm_res50_4xb64-210e_deepfasion2-sling-dress-256x192 + Results: + - Dataset: DeepFashion2 + Metrics: + AUC: 0.544 + EPE: 19.5 + PCK@0.2: 0.967 + Task: Fashion 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/fashion/resnet/res50_deepfashion2_sling_dress_256x192-8ebae0eb_20221208.pth diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-long-sleeved-dress-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-long-sleeved-dress-256x192.py new file mode 100644 index 0000000000..09dfaaa390 --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-long-sleeved-dress-256x192.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=64) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_long_sleeved_dress_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/deepfashion2_long_sleeved_dress_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-skirt-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-skirt-256x192.py new file mode 100644 index 0000000000..f0e6f0c632 --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-skirt-256x192.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=64) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_skirt_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/deepfashion2_skirt_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-vest-dress-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-vest-dress-256x192.py new file mode 100644 index 0000000000..9bed742199 --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_1xb64-210e_deepfasion2-vest-dress-256x192.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=64) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_vest_dress_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/deepfashion2_vest_dress_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_2xb64-210e_deepfasion2-trousers-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_2xb64-210e_deepfasion2-trousers-256x192.py new file mode 100644 index 0000000000..617e59ae74 --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_2xb64-210e_deepfasion2-trousers-256x192.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=128) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_trousers_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/deepfashion2_trousers_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_3xb64-210e_deepfasion2-shorts-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_3xb64-210e_deepfasion2-shorts-256x192.py new file mode 100644 index 0000000000..aa3b2774fc --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_3xb64-210e_deepfasion2-shorts-256x192.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=192) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_shorts_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/deepfashion2_shorts_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-short-sleeved-dress-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-short-sleeved-dress-256x192.py new file mode 100644 index 0000000000..0bfcabaa54 --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-short-sleeved-dress-256x192.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=256) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_short_sleeved_dress_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/deepfashion2_short_sleeved_dress_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-sling-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-sling-256x192.py new file mode 100644 index 0000000000..f627eb182c --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-sling-256x192.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=256) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_sling_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/deepfashion2_sling_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-sling-dress-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-sling-dress-256x192.py new file mode 100644 index 0000000000..8b59607060 --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-sling-dress-256x192.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=256) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_sling_dress_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/deepfashion2_sling_dress_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-vest-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-vest-256x192.py new file mode 100644 index 0000000000..4249d5a897 --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_4xb64-210e_deepfasion2-vest-256x192.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=256) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_vest_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/deepfashion2_vest_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_6xb64-210e_deepfasion2-short-sleeved-shirt-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_6xb64-210e_deepfasion2-short-sleeved-shirt-256x192.py new file mode 100644 index 0000000000..4161952dcf --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_6xb64-210e_deepfasion2-short-sleeved-shirt-256x192.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=384) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_short_sleeved_shirt_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/deepfashion2_short_sleeved_shirt_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-long-sleeved-outwear-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-long-sleeved-outwear-256x192.py new file mode 100644 index 0000000000..36e0318bf7 --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-long-sleeved-outwear-256x192.py @@ -0,0 +1,123 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_long_sleeved_outwear_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/' + 'deepfashion2_long_sleeved_outwear_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-long-sleeved-shirt-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-long-sleeved-shirt-256x192.py new file mode 100644 index 0000000000..f82e3cb5fb --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-long-sleeved-shirt-256x192.py @@ -0,0 +1,122 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_long_sleeved_shirt_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/deepfashion2_long_sleeved_shirt_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-short-sleeved-outwear-256x192.py b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-short-sleeved-outwear-256x192.py new file mode 100644 index 0000000000..30db99de9e --- /dev/null +++ b/configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/td-hm_res50_8xb64-210e_deepfasion2-short-sleeved-outwear-256x192.py @@ -0,0 +1,123 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type='Adam', + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict( + logger=dict(type='LoggerHook', interval=10), + checkpoint=dict(save_best='AUC', rule='greater')) + +# codec settings +codec = dict( + type='MSRAHeatmap', input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='ResNet', + depth=50, + init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50'), + ), + head=dict( + type='HeatmapHead', + in_channels=2048, + out_channels=294, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'DeepFashion2Dataset' +data_mode = 'topdown' +data_root = 'data/deepfasion2/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='train/deepfashion2_short_sleeved_outwear_train.json', + data_prefix=dict(img='train/image/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='validation/' + 'deepfashion2_short_sleeved_outwear_validation.json', + data_prefix=dict(img='validation/image/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE'), +] +test_evaluator = val_evaluator diff --git a/configs/hand_2d_keypoint/README.md b/configs/hand_2d_keypoint/README.md index cbe39fd39a..6f7758290e 100644 --- a/configs/hand_2d_keypoint/README.md +++ b/configs/hand_2d_keypoint/README.md @@ -11,7 +11,7 @@ Please follow [DATA Preparation](/docs/en/dataset_zoo/2d_hand_keypoint.md) to pr ## Demo -Please follow [Demo](/demo/docs/2d_hand_demo.md) to run demos. +Please follow [Demo](/demo/docs/en/2d_hand_demo.md) to run demos.
diff --git a/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py b/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py index d7056389d8..48c7193394 100644 --- a/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py +++ b/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py @@ -24,7 +24,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -69,14 +68,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, out_channels=21, input_size=codec['input_size'], - in_featuremap_size=(8, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( diff --git a/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose_coco_wholebody_hand.md b/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose_coco_wholebody_hand.md index cffb706493..b2a5957e6e 100644 --- a/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose_coco_wholebody_hand.md +++ b/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose_coco_wholebody_hand.md @@ -36,4 +36,4 @@ Results on COCO-WholeBody-Hand val set | Arch | Input Size | PCK@0.2 | AUC | EPE | ckpt | log | | :--------------------------------------------------------- | :--------: | :-----: | :---: | :--: | :--------------------------------------------------------: | :--------------------------------------------------------: | -| [rtmpose_m](/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py) | 256x256 | 0.815 | 0.837 | 4.51 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody-hand_pt-aic-coco_210e-256x256-99477206_20230228.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody-hand_pt-aic-coco_210e-256x256-99477206_20230228.json) | +| [rtmpose_m](/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py) | 256x256 | 0.815 | 0.837 | 4.51 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco-wholebody-hand_pt-aic-coco_210e-256x256-99477206_20230228.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco-wholebody-hand_pt-aic-coco_210e-256x256-99477206_20230228.json) | diff --git a/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose_coco_wholebody_hand.yml b/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose_coco_wholebody_hand.yml index 44cb41bc85..2f87733605 100644 --- a/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose_coco_wholebody_hand.yml +++ b/configs/hand_2d_keypoint/rtmpose/coco_wholebody_hand/rtmpose_coco_wholebody_hand.yml @@ -14,4 +14,4 @@ Models: EPE: 4.51 PCK@0.2: 0.837 Task: Hand 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody-hand_pt-aic-coco_210e-256x256-99477206_20230228.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco-wholebody-hand_pt-aic-coco_210e-256x256-99477206_20230228.pth diff --git a/configs/hand_2d_keypoint/rtmpose/hand5/rtmpose-m_8xb256-210e_hand5-256x256.py b/configs/hand_2d_keypoint/rtmpose/hand5/rtmpose-m_8xb256-210e_hand5-256x256.py new file mode 100644 index 0000000000..f329f1cb1d --- /dev/null +++ b/configs/hand_2d_keypoint/rtmpose/hand5/rtmpose-m_8xb256-210e_hand5-256x256.py @@ -0,0 +1,380 @@ +_base_ = ['../../../_base_/default_runtime.py'] + +# coco-hand onehand10k freihand2d rhd2d halpehand + +# runtime +max_epochs = 210 +stage2_num_epochs = 10 +base_lr = 4e-3 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=256) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=(256, 256), + sigma=(5.66, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.67, + widen_factor=0.75, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=768, + out_channels=21, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True, )) + +# base dataset settings +dataset_type = 'CocoWholeBodyHandDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + # dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], + rotate_factor=180), + dict(type='RandomFlip', direction='horizontal'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + # dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=180), + dict(type='RandomFlip', direction='horizontal'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.2), + dict(type='MedianBlur', p=0.2), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[], +) + +dataset_onehand10k = dict( + type='OneHand10KDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='onehand10k/annotations/onehand10k_train.json', + data_prefix=dict(img='pose/OneHand10K/'), + pipeline=[], +) + +dataset_freihand = dict( + type='FreiHandDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='freihand/annotations/freihand_train.json', + data_prefix=dict(img='pose/FreiHand/'), + pipeline=[], +) + +dataset_rhd = dict( + type='Rhd2DDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='rhd/annotations/rhd_train.json', + data_prefix=dict(img='pose/RHD/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=21, + mapping=[ + (0, 0), + (1, 4), + (2, 3), + (3, 2), + (4, 1), + (5, 8), + (6, 7), + (7, 6), + (8, 5), + (9, 12), + (10, 11), + (11, 10), + (12, 9), + (13, 16), + (14, 15), + (15, 14), + (16, 13), + (17, 20), + (18, 19), + (19, 18), + (20, 17), + ]) + ], +) + +dataset_halpehand = dict( + type='HalpeHandDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015/'), + pipeline=[], +) + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict( + from_file='configs/_base_/datasets/coco_wholebody_hand.py'), + datasets=[ + dataset_coco, dataset_onehand10k, dataset_freihand, dataset_rhd, + dataset_halpehand + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# test datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[], +) + +val_onehand10k = dict( + type='OneHand10KDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='onehand10k/annotations/onehand10k_test.json', + data_prefix=dict(img='pose/OneHand10K/'), + pipeline=[], +) + +val_freihand = dict( + type='FreiHandDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='freihand/annotations/freihand_test.json', + data_prefix=dict(img='pose/FreiHand/'), + pipeline=[], +) + +val_rhd = dict( + type='Rhd2DDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='rhd/annotations/rhd_test.json', + data_prefix=dict(img='pose/RHD/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=21, + mapping=[ + (0, 0), + (1, 4), + (2, 3), + (3, 2), + (4, 1), + (5, 8), + (6, 7), + (7, 6), + (8, 5), + (9, 12), + (10, 11), + (11, 10), + (12, 9), + (13, 16), + (14, 15), + (15, 14), + (16, 13), + (17, 20), + (18, 19), + (19, 18), + (20, 17), + ]) + ], +) + +val_halpehand = dict( + type='HalpeHandDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[], +) + +test_dataloader = dict( + batch_size=32, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict( + from_file='configs/_base_/datasets/coco_wholebody_hand.py'), + datasets=[ + val_coco, val_onehand10k, val_freihand, val_rhd, val_halpehand + ], + pipeline=val_pipeline, + test_mode=True, + )) + +val_dataloader = test_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = [ + dict(type='PCKAccuracy', thr=0.2), + dict(type='AUC'), + dict(type='EPE') +] +test_evaluator = val_evaluator diff --git a/configs/hand_2d_keypoint/rtmpose/hand5/rtmpose_hand5.md b/configs/hand_2d_keypoint/rtmpose/hand5/rtmpose_hand5.md new file mode 100644 index 0000000000..361770dad2 --- /dev/null +++ b/configs/hand_2d_keypoint/rtmpose/hand5/rtmpose_hand5.md @@ -0,0 +1,67 @@ + + +
+RTMPose (arXiv'2023) + +```bibtex +@misc{https://doi.org/10.48550/arxiv.2303.07399, + doi = {10.48550/ARXIV.2303.07399}, + url = {https://arxiv.org/abs/2303.07399}, + author = {Jiang, Tao and Lu, Peng and Zhang, Li and Ma, Ningsheng and Han, Rui and Lyu, Chengqi and Li, Yining and Chen, Kai}, + keywords = {Computer Vision and Pattern Recognition (cs.CV), FOS: Computer and information sciences, FOS: Computer and information sciences}, + title = {RTMPose: Real-Time Multi-Person Pose Estimation based on MMPose}, + publisher = {arXiv}, + year = {2023}, + copyright = {Creative Commons Attribution 4.0 International} +} + +``` + +
+ + + +
+RTMDet (arXiv'2022) + +```bibtex +@misc{lyu2022rtmdet, + title={RTMDet: An Empirical Study of Designing Real-Time Object Detectors}, + author={Chengqi Lyu and Wenwei Zhang and Haian Huang and Yue Zhou and Yudong Wang and Yanyi Liu and Shilong Zhang and Kai Chen}, + year={2022}, + eprint={2212.07784}, + archivePrefix={arXiv}, + primaryClass={cs.CV} +} +``` + +
+ + + +
+COCO (ECCV'2014) + +```bibtex +@inproceedings{lin2014microsoft, + title={Microsoft coco: Common objects in context}, + author={Lin, Tsung-Yi and Maire, Michael and Belongie, Serge and Hays, James and Perona, Pietro and Ramanan, Deva and Doll{\'a}r, Piotr and Zitnick, C Lawrence}, + booktitle={European conference on computer vision}, + pages={740--755}, + year={2014}, + organization={Springer} +} +``` + +
+ +- `Hand5` and `*` denote model trained on 5 public datasets: + - [COCO-Wholebody-Hand](https://github.com/jin-s13/COCO-WholeBody/) + - [OneHand10K](https://www.yangangwang.com/papers/WANG-MCC-2018-10.html) + - [FreiHand2d](https://lmb.informatik.uni-freiburg.de/projects/freihand/) + - [RHD2d](https://lmb.informatik.uni-freiburg.de/resources/datasets/RenderedHandposeDataset.en.html) + - [Halpe](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_wholebody_keypoint.html#halpe) + +| Config | Input Size | PCK@0.2
(COCO-Wholebody-Hand) | PCK@0.2
(Hand5) | AUC
(Hand5) | EPE
(Hand5) | FLOPS(G) | Download | +| :---------------------------------------: | :--------: | :-----------------------------------: | :---------------------: | :-----------------: | :-----------------: | :------: | :-----------------------------------------: | +| [RTMPose-m\*
(alpha version)](./rtmpose/hand_2d_keypoint/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py) | 256x256 | 81.5 | 96.4 | 83.9 | 5.06 | 2.581 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-hand5_pt-aic-coco_210e-256x256-74fb594_20230320.pth) | diff --git a/configs/hand_2d_keypoint/rtmpose/hand5/rtmpose_hand5.yml b/configs/hand_2d_keypoint/rtmpose/hand5/rtmpose_hand5.yml new file mode 100644 index 0000000000..a8dfd42e39 --- /dev/null +++ b/configs/hand_2d_keypoint/rtmpose/hand5/rtmpose_hand5.yml @@ -0,0 +1,27 @@ +Collections: +- Name: RTMPose + Paper: + Title: "RTMPose: Real-Time Multi-Person Pose Estimation based on MMPose" + URL: https://arxiv.org/abs/2303.07399 + README: https://github.com/open-mmlab/mmpose/blob/main/projects/rtmpose/README.md +Models: +- Config: configs/hand_2d_keypoint/rtmpose/hand5/rtmpose-m_8xb256-210e_hand5-256x256.py + In Collection: RTMPose + Metadata: + Architecture: &id001 + - RTMPose + Training Data: &id002 + - COCO-Wholebody-Hand + - OneHand10K + - FreiHand2d + - RHD2d + - Halpe + Name: rtmpose-m_8xb256-210e_hand5-256x256 + Results: + - Dataset: Hand5 + Metrics: + PCK@0.2: 0.964 + AUC: 0.839 + EPE: 5.06 + Task: Hand 2D Keypoint + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-hand5_pt-aic-coco_210e-256x256-74fb594_20230320.pth diff --git a/configs/hand_gesture/README.md b/configs/hand_gesture/README.md index 1e91904116..7cc5bb323b 100644 --- a/configs/hand_gesture/README.md +++ b/configs/hand_gesture/README.md @@ -8,6 +8,6 @@ Please follow [DATA Preparation](/docs/en/dataset_zoo/2d_hand_gesture.md) to pre ## Demo -Please follow [Demo](/demo/docs/gesture_recognition_demo.md) to run the demo. +Please follow [Demo](/demo/docs/en/gesture_recognition_demo.md) to run the demo. diff --git a/configs/wholebody_2d_keypoint/README.md b/configs/wholebody_2d_keypoint/README.md index 2b5f8812bf..362a6a8976 100644 --- a/configs/wholebody_2d_keypoint/README.md +++ b/configs/wholebody_2d_keypoint/README.md @@ -14,6 +14,6 @@ Please follow [DATA Preparation](/docs/en/dataset_zoo/2d_wholebody_keypoint.md) ## Demo -Please follow [Demo](/demo/docs/2d_wholebody_pose_demo.md) to run demos. +Please follow [Demo](/demo/docs/en/2d_wholebody_pose_demo.md) to run demos.
diff --git a/configs/wholebody_2d_keypoint/rtmpose/README.md b/configs/wholebody_2d_keypoint/rtmpose/README.md index 47e488567c..ac40c016aa 100644 --- a/configs/wholebody_2d_keypoint/rtmpose/README.md +++ b/configs/wholebody_2d_keypoint/rtmpose/README.md @@ -13,6 +13,6 @@ Results on COCO-WholeBody v1.0 val with detector having human AP of 56.4 on COCO | Model | Input Size | Whole AP | Whole AR | Details and Download | | :-------: | :--------: | :------: | :------: | :---------------------------------------------------------------------: | -| RTMPose-m | 256x192 | 0.604 | 0.667 | [rtmpose_coco-wholebody.md](./coco-wholebody/rtmpose_coco-wholebody.md) | -| RTMPose-l | 256x192 | 0.632 | 0.694 | [rtmpose_coco-wholebody.md](./coco-wholebody/rtmpose_coco-wholebody.md) | -| RTMPose-l | 384x288 | 0.670 | 0.723 | [rtmpose_coco-wholebody.md](./coco-wholebody/rtmpose_coco-wholebody.md) | +| RTMPose-m | 256x192 | 0.582 | 0.674 | [rtmpose_coco-wholebody.md](./coco-wholebody/rtmpose_coco-wholebody.md) | +| RTMPose-l | 256x192 | 0.611 | 0.700 | [rtmpose_coco-wholebody.md](./coco-wholebody/rtmpose_coco-wholebody.md) | +| RTMPose-l | 384x288 | 0.648 | 0.730 | [rtmpose_coco-wholebody.md](./coco-wholebody/rtmpose_coco-wholebody.md) | diff --git a/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py b/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py index 12dae96c16..af2c133f22 100644 --- a/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py +++ b/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py @@ -24,7 +24,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -69,14 +68,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa + 'rtmposev1/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=1024, out_channels=133, input_size=codec['input_size'], - in_featuremap_size=(9, 12), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -202,6 +201,8 @@ ann_file='annotations/coco_wholebody_val_v1.0.json', data_prefix=dict(img='val2017/'), test_mode=True, + bbox_file='data/coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', pipeline=val_pipeline, )) test_dataloader = val_dataloader diff --git a/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py b/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py index 2625192deb..7765c9ec44 100644 --- a/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py +++ b/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py @@ -24,7 +24,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -69,14 +68,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa + 'rtmposev1/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=1024, out_channels=133, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -202,6 +201,8 @@ ann_file='annotations/coco_wholebody_val_v1.0.json', data_prefix=dict(img='val2017/'), test_mode=True, + bbox_file='data/coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', pipeline=val_pipeline, )) test_dataloader = val_dataloader diff --git a/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py b/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py index f3eea9deb0..1e2afc518d 100644 --- a/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py +++ b/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py @@ -24,7 +24,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -69,14 +68,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, out_channels=133, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -202,6 +201,8 @@ ann_file='annotations/coco_wholebody_val_v1.0.json', data_prefix=dict(img='val2017/'), test_mode=True, + bbox_file='data/coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', pipeline=val_pipeline, )) test_dataloader = val_dataloader diff --git a/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose_coco-wholebody.md b/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose_coco-wholebody.md index 75cf6245ff..e43c0b3750 100644 --- a/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose_coco-wholebody.md +++ b/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose_coco-wholebody.md @@ -57,6 +57,6 @@ Results on COCO-WholeBody v1.0 val with detector having human AP of 56.4 on COCO | Arch | Input Size | Body AP | Body AR | Foot AP | Foot AR | Face AP | Face AR | Hand AP | Hand AR | Whole AP | Whole AR | ckpt | log | | :-------------------------------------- | :--------: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :------: | :------: | :--------------------------------------: | :-------------------------------------: | -| [rtmpose-m](./rtmpose-m_8xb64-270e_coco-wholebody-256x192.py) | 256x192 | 0.697 | 0.743 | 0.660 | 0.749 | 0.822 | 0.858 | 0.483 | 0.564 | 0.604 | 0.667 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.json) | -| [rtmpose-l](./rtmpose-l_8xb64-270e_coco-wholebody-256x192.py) | 256x192 | 0.721 | 0.764 | 0.693 | 0.780 | 0.844 | 0.876 | 0.523 | 0.600 | 0.632 | 0.694 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-256x192-6f206314_20230124.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-256x192-6f206314_20230124.json) | -| [rtmpose-l](./rtmpose-l_8xb32-270e_coco-wholebody-384x288.py) | 384x288 | 0.736 | 0.776 | 0.738 | 0.810 | 0.895 | 0.918 | 0.591 | 0.659 | 0.670 | 0.723 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.json) | +| [rtmpose-m](/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py) | 256x192 | 0.673 | 0.750 | 0.615 | 0.752 | 0.813 | 0.871 | 0.475 | 0.589 | 0.582 | 0.674 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.json) | +| [rtmpose-l](/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py) | 256x192 | 0.695 | 0.769 | 0.658 | 0.785 | 0.833 | 0.887 | 0.519 | 0.628 | 0.611 | 0.700 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-256x192-6f206314_20230124.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-256x192-6f206314_20230124.json) | +| [rtmpose-l](/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py) | 384x288 | 0.712 | 0.781 | 0.693 | 0.811 | 0.882 | 0.919 | 0.579 | 0.677 | 0.648 | 0.730 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.json) | diff --git a/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose_coco-wholebody.yml b/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose_coco-wholebody.yml index b73d154e6d..049f348899 100644 --- a/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose_coco-wholebody.yml +++ b/configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose_coco-wholebody.yml @@ -10,18 +10,18 @@ Models: Results: - Dataset: COCO-WholeBody Metrics: - Body AP: 0.697 - Body AR: 0.743 - Face AP: 0.822 - Face AR: 0.858 - Foot AP: 0.66 - Foot AR: 0.749 - Hand AP: 0.483 - Hand AR: 0.564 - Whole AP: 0.604 - Whole AR: 0.667 + Body AP: 0.673 + Body AR: 0.750 + Face AP: 0.813 + Face AR: 0.871 + Foot AP: 0.615 + Foot AR: 0.752 + Hand AP: 0.475 + Hand AR: 0.589 + Whole AP: 0.582 + Whole AR: 0.674 Task: Wholebody 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.pth - Config: configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py In Collection: RTMPose Metadata: @@ -31,18 +31,18 @@ Models: Results: - Dataset: COCO-WholeBody Metrics: - Body AP: 0.721 - Body AR: 0.764 - Face AP: 0.844 - Face AR: 0.876 - Foot AP: 0.693 - Foot AR: 0.78 - Hand AP: 0.523 - Hand AR: 0.6 - Whole AP: 0.632 - Whole AR: 0.694 + Body AP: 0.695 + Body AR: 0.769 + Face AP: 0.833 + Face AR: 0.887 + Foot AP: 0.658 + Foot AR: 0.785 + Hand AP: 0.519 + Hand AR: 0.628 + Whole AP: 0.611 + Whole AR: 0.700 Task: Wholebody 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-256x192-6f206314_20230124.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-256x192-6f206314_20230124.pth - Config: configs/wholebody_2d_keypoint/rtmpose/coco-wholebody/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py In Collection: RTMPose Metadata: @@ -52,15 +52,15 @@ Models: Results: - Dataset: COCO-WholeBody Metrics: - Body AP: 0.736 - Body AR: 0.776 - Face AP: 0.895 - Face AR: 0.918 - Foot AP: 0.738 - Foot AR: 0.81 - Hand AP: 0.591 - Hand AR: 0.659 - Whole AP: 0.67 - Whole AR: 0.723 + Body AP: 0.712 + Body AR: 0.781 + Face AP: 0.882 + Face AR: 0.919 + Foot AP: 0.693 + Foot AR: 0.811 + Hand AP: 0.579 + Hand AR: 0.677 + Whole AP: 0.648 + Whole AR: 0.730 Task: Wholebody 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.pth diff --git a/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext-l_udp_8xb64-210e_coco-wholebody-256x192.py b/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext-l_udp_8xb64-210e_coco-wholebody-256x192.py index 2112e19e76..7182e7a3ed 100644 --- a/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext-l_udp_8xb64-210e_coco-wholebody-256x192.py +++ b/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext-l_udp_8xb64-210e_coco-wholebody-256x192.py @@ -24,7 +24,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, diff --git a/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext-m_udp_8xb64-210e_coco-wholebody-256x192.py b/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext-m_udp_8xb64-210e_coco-wholebody-256x192.py index bfcb5c3917..05fae649b8 100644 --- a/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext-m_udp_8xb64-210e_coco-wholebody-256x192.py +++ b/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext-m_udp_8xb64-210e_coco-wholebody-256x192.py @@ -24,7 +24,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, diff --git a/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext_udp_coco-wholebody.md b/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext_udp_coco-wholebody.md index 3ada8a0c96..1fc4a78dfb 100644 --- a/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext_udp_coco-wholebody.md +++ b/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext_udp_coco-wholebody.md @@ -53,4 +53,4 @@ Results on COCO-WholeBody v1.0 val with detector having human AP of 56.4 on COCO | Arch | Input Size | Body AP | Body AR | Foot AP | Foot AR | Face AP | Face AR | Hand AP | Hand AR | Whole AP | Whole AR | ckpt | log | | :-------------------------------------- | :--------: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :------: | :------: | :--------------------------------------: | :-------------------------------------: | -| [pose_cspnext_m_udp](/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext-m_udp_8xb64-210e_coco-wholebody-256x192.py) | 256x192 | 0.687 | 0.735 | 0.680 | 0.763 | 0.697 | 0.755 | 0.460 | 0.543 | 0.567 | 0.641 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-coco-wholebody_pt-in1k_210e-256x192-320fa258_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-coco-wholebody_pt-in1k_210e-256x192-320fa258_20230123.json) | +| [pose_cspnext_m_udp](/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext-m_udp_8xb64-210e_coco-wholebody-256x192.py) | 256x192 | 0.687 | 0.735 | 0.680 | 0.763 | 0.697 | 0.755 | 0.460 | 0.543 | 0.567 | 0.641 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-coco-wholebody_pt-in1k_210e-256x192-320fa258_20230123.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-coco-wholebody_pt-in1k_210e-256x192-320fa258_20230123.json) | diff --git a/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext_udp_coco-wholebody.yml b/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext_udp_coco-wholebody.yml index d12b989dad..ebdcc7146e 100644 --- a/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext_udp_coco-wholebody.yml +++ b/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext_udp_coco-wholebody.yml @@ -21,4 +21,4 @@ Models: Whole AP: 0.567 Whole AR: 0.641 Task: Wholebody 2D Keypoint - Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_udp-coco-wholebody_pt-in1k_210e-256x192-320fa258_20230123.pth + Weights: https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-coco-wholebody_pt-in1k_210e-256x192-320fa258_20230123.pth diff --git a/dataset-index.yml b/dataset-index.yml new file mode 100644 index 0000000000..a6acc57cc4 --- /dev/null +++ b/dataset-index.yml @@ -0,0 +1,71 @@ +coco2017: + dataset: COCO_2017 + download_root: data + data_root: data/pose + script: tools/dataset_converters/scripts/preprocess_coco2017.sh + +mpii: + dataset: MPII_Human_Pose + download_root: data + data_root: data/pose + script: tools/dataset_converters/scripts/preprocess_mpii.sh + +aic: + dataset: AI_Challenger + download_root: data + data_root: data/pose + script: tools/dataset_converters/scripts/preprocess_aic.sh + +crowdpose: + dataset: CrowdPose + download_root: data + data_root: data/pose + script: tools/dataset_converters/scripts/preprocess_crowdpose.sh + +halpe: + dataset: Halpe + download_root: data + data_root: data/pose + script: tools/dataset_converters/scripts/preprocess_halpe.sh + +lapa: + dataset: LaPa + download_root: data + data_root: data/pose + script: tools/dataset_converters/scripts/preprocess_lapa.sh + +300w: + dataset: 300w + download_root: data + data_root: data/pose + script: tools/dataset_converters/scripts/preprocess_300w.sh + +wflw: + dataset: WFLW + download_root: data + data_root: data/pose + script: tools/dataset_converters/scripts/preprocess_wflw.sh + +onehand10k: + dataset: OneHand10K + download_root: data + data_root: data/pose + script: tools/dataset_converters/scripts/preprocess_onehand10k.sh + +freihand: + dataset: FreiHAND + download_root: data + data_root: data/pose + script: tools/dataset_converters/scripts/preprocess_freihand.sh + +ap10k: + dataset: AP-10K + download_root: data + data_root: data/pose + script: tools/dataset_converters/scripts/preprocess_ap10k.sh + +hagrid: + dataset: HaGRID + download_root: data + data_root: data/pose + script: tools/dataset_converters/scripts/preprocess_hagrid.sh diff --git a/demo/MMPose_Tutorial.ipynb b/demo/MMPose_Tutorial.ipynb index 313a93fa50..0e9ff9b57f 100644 --- a/demo/MMPose_Tutorial.ipynb +++ b/demo/MMPose_Tutorial.ipynb @@ -1,24 +1,17 @@ { "cells": [ { + "attachments": {}, "cell_type": "markdown", "metadata": { "id": "F77yOqgkX8p4" }, "source": [ - "\"Open" + "\"Open" ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "bfKI5TJRs_Db" - }, - "outputs": [], - "source": [] - }, - { + "attachments": {}, "cell_type": "markdown", "metadata": { "id": "8xX3YewOtqV0" @@ -36,6 +29,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": { "id": "bkw-kUD8t3t8" @@ -48,13 +42,13 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "0f_Ebb2otWtd", - "outputId": "95a1c9bb-2092-41da-c308-5d1751178bdf" + "outputId": "8c16b8ae-b927-41d5-c49e-d61ba6798a2d" }, "outputs": [ { @@ -62,12 +56,12 @@ "output_type": "stream", "text": [ "nvcc: NVIDIA (R) Cuda compiler driver\n", - "Copyright (c) 2005-2020 NVIDIA Corporation\n", - "Built on Mon_Oct_12_20:09:46_PDT_2020\n", - "Cuda compilation tools, release 11.1, V11.1.105\n", - "Build cuda_11.1.TC455_06.29190527_0\n", - "gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0\n", - "Copyright (C) 2017 Free Software Foundation, Inc.\n", + "Copyright (c) 2005-2022 NVIDIA Corporation\n", + "Built on Wed_Sep_21_10:33:58_PDT_2022\n", + "Cuda compilation tools, release 11.8, V11.8.89\n", + "Build cuda_11.8.r11.8/compiler.31833905_0\n", + "gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0\n", + "Copyright (C) 2019 Free Software Foundation, Inc.\n", "This is free software; see the source for copying conditions. There is NO\n", "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", "\n", @@ -88,191 +82,289 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "igSm4jhihE2M", + "outputId": "0d521640-a4d7-4264-889c-df862e9c332f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Looking in indexes: https://download.pytorch.org/whl/cu118, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Requirement already satisfied: torch in /usr/local/lib/python3.9/dist-packages (2.0.0+cu118)\n", + "Requirement already satisfied: torchvision in /usr/local/lib/python3.9/dist-packages (0.15.1+cu118)\n", + "Requirement already satisfied: torchaudio in /usr/local/lib/python3.9/dist-packages (2.0.1+cu118)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.9/dist-packages (from torch) (3.1)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.9/dist-packages (from torch) (3.11.0)\n", + "Requirement already satisfied: sympy in /usr/local/lib/python3.9/dist-packages (from torch) (1.11.1)\n", + "Requirement already satisfied: triton==2.0.0 in /usr/local/lib/python3.9/dist-packages (from torch) (2.0.0)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.9/dist-packages (from torch) (3.1.2)\n", + "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.9/dist-packages (from torch) (4.5.0)\n", + "Requirement already satisfied: cmake in /usr/local/lib/python3.9/dist-packages (from triton==2.0.0->torch) (3.25.2)\n", + "Requirement already satisfied: lit in /usr/local/lib/python3.9/dist-packages (from triton==2.0.0->torch) (16.0.1)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.9/dist-packages (from torchvision) (1.22.4)\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.9/dist-packages (from torchvision) (2.27.1)\n", + "Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in /usr/local/lib/python3.9/dist-packages (from torchvision) (8.4.0)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.9/dist-packages (from jinja2->torch) (2.1.2)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.9/dist-packages (from requests->torchvision) (3.4)\n", + "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/local/lib/python3.9/dist-packages (from requests->torchvision) (1.26.15)\n", + "Requirement already satisfied: charset-normalizer~=2.0.0 in /usr/local/lib/python3.9/dist-packages (from requests->torchvision) (2.0.12)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.9/dist-packages (from requests->torchvision) (2022.12.7)\n", + "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.9/dist-packages (from sympy->torch) (1.3.0)\n" + ] + } + ], + "source": [ + "# install dependencies: (if your colab has CUDA 11.8)\n", + "%pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118" + ] + }, + { + "cell_type": "code", + "execution_count": 3, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "MLcoZr3ot9iw", - "outputId": "6f486798-00bb-48d9-90e5-c63ccadd0113" + "outputId": "70e5d18e-746c-41a3-a761-6303b79eaf02" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", - "Looking in links: https://download.pytorch.org/whl/torch_stable.html\n", - "Collecting torch==1.10.0+cu111\n", - " Downloading https://download.pytorch.org/whl/cu111/torch-1.10.0%2Bcu111-cp37-cp37m-linux_x86_64.whl (2137.6 MB)\n", - "\u001b[K |████████████▌ | 834.1 MB 1.3 MB/s eta 0:16:42tcmalloc: large alloc 1147494400 bytes == 0x3935e000 @ 0x7f955b2e9615 0x592b76 0x4df71e 0x59afff 0x515655 0x549576 0x593fce 0x548ae9 0x51566f 0x549576 0x593fce 0x548ae9 0x5127f1 0x598e3b 0x511f68 0x598e3b 0x511f68 0x598e3b 0x511f68 0x4bc98a 0x532e76 0x594b72 0x515600 0x549576 0x593fce 0x548ae9 0x5127f1 0x549576 0x593fce 0x5118f8 0x593dd7\n", - "\u001b[K |███████████████▉ | 1055.7 MB 1.3 MB/s eta 0:13:59tcmalloc: large alloc 1434370048 bytes == 0x7d9b4000 @ 0x7f955b2e9615 0x592b76 0x4df71e 0x59afff 0x515655 0x549576 0x593fce 0x548ae9 0x51566f 0x549576 0x593fce 0x548ae9 0x5127f1 0x598e3b 0x511f68 0x598e3b 0x511f68 0x598e3b 0x511f68 0x4bc98a 0x532e76 0x594b72 0x515600 0x549576 0x593fce 0x548ae9 0x5127f1 0x549576 0x593fce 0x5118f8 0x593dd7\n", - "\u001b[K |████████████████████ | 1336.2 MB 1.3 MB/s eta 0:10:21tcmalloc: large alloc 1792966656 bytes == 0x27e6000 @ 0x7f955b2e9615 0x592b76 0x4df71e 0x59afff 0x515655 0x549576 0x593fce 0x548ae9 0x51566f 0x549576 0x593fce 0x548ae9 0x5127f1 0x598e3b 0x511f68 0x598e3b 0x511f68 0x598e3b 0x511f68 0x4bc98a 0x532e76 0x594b72 0x515600 0x549576 0x593fce 0x548ae9 0x5127f1 0x549576 0x593fce 0x5118f8 0x593dd7\n", - "\u001b[K |█████████████████████████▎ | 1691.1 MB 1.2 MB/s eta 0:05:58tcmalloc: large alloc 2241208320 bytes == 0x6d5ce000 @ 0x7f955b2e9615 0x592b76 0x4df71e 0x59afff 0x515655 0x549576 0x593fce 0x548ae9 0x51566f 0x549576 0x593fce 0x548ae9 0x5127f1 0x598e3b 0x511f68 0x598e3b 0x511f68 0x598e3b 0x511f68 0x4bc98a 0x532e76 0x594b72 0x515600 0x549576 0x593fce 0x548ae9 0x5127f1 0x549576 0x593fce 0x5118f8 0x593dd7\n", - "\u001b[K |████████████████████████████████| 2137.6 MB 1.2 MB/s eta 0:00:01tcmalloc: large alloc 2137645056 bytes == 0xf2f30000 @ 0x7f955b2e81e7 0x4a3940 0x4a39cc 0x592b76 0x4df71e 0x59afff 0x515655 0x549576 0x593fce 0x511e2c 0x549576 0x593fce 0x511e2c 0x549576 0x593fce 0x511e2c 0x549576 0x593fce 0x511e2c 0x549576 0x593fce 0x511e2c 0x593dd7 0x511e2c 0x549576 0x593fce 0x548ae9 0x5127f1 0x549576 0x593fce 0x548ae9\n", - "tcmalloc: large alloc 2672058368 bytes == 0x1e6a8a000 @ 0x7f955b2e9615 0x592b76 0x4df71e 0x59afff 0x515655 0x549576 0x593fce 0x511e2c 0x549576 0x593fce 0x511e2c 0x549576 0x593fce 0x511e2c 0x549576 0x593fce 0x511e2c 0x549576 0x593fce 0x511e2c 0x593dd7 0x511e2c 0x549576 0x593fce 0x548ae9 0x5127f1 0x549576 0x593fce 0x548ae9 0x5127f1 0x549576\n", - "\u001b[K |████████████████████████████████| 2137.6 MB 413 bytes/s \n", - "\u001b[?25hCollecting torchvision==0.11.0+cu111\n", - " Downloading https://download.pytorch.org/whl/cu111/torchvision-0.11.0%2Bcu111-cp37-cp37m-linux_x86_64.whl (21.9 MB)\n", - "\u001b[K |████████████████████████████████| 21.9 MB 4.4 MB/s \n", - "\u001b[?25hRequirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from torch==1.10.0+cu111) (4.1.1)\n", - "Requirement already satisfied: pillow!=8.3.0,>=5.3.0 in /usr/local/lib/python3.7/dist-packages (from torchvision==0.11.0+cu111) (7.1.2)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from torchvision==0.11.0+cu111) (1.21.6)\n", - "Installing collected packages: torch, torchvision\n", - " Attempting uninstall: torch\n", - " Found existing installation: torch 1.12.1+cu113\n", - " Uninstalling torch-1.12.1+cu113:\n", - " Successfully uninstalled torch-1.12.1+cu113\n", - " Attempting uninstall: torchvision\n", - " Found existing installation: torchvision 0.13.1+cu113\n", - " Uninstalling torchvision-0.13.1+cu113:\n", - " Successfully uninstalled torchvision-0.13.1+cu113\n", - "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n", - "torchtext 0.13.1 requires torch==1.12.1, but you have torch 1.10.0+cu111 which is incompatible.\n", - "torchaudio 0.12.1+cu113 requires torch==1.12.1, but you have torch 1.10.0+cu111 which is incompatible.\u001b[0m\n", - "Successfully installed torch-1.10.0+cu111 torchvision-0.11.0+cu111\n", "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", "Collecting openmim\n", - " Downloading openmim-0.3.1-py2.py3-none-any.whl (50 kB)\n", - "\u001b[K |████████████████████████████████| 50 kB 5.7 MB/s \n", - "\u001b[?25hRequirement already satisfied: pip>=19.3 in /usr/local/lib/python3.7/dist-packages (from openmim) (21.1.3)\n", - "Requirement already satisfied: tabulate in /usr/local/lib/python3.7/dist-packages (from openmim) (0.8.10)\n", - "Requirement already satisfied: pandas in /usr/local/lib/python3.7/dist-packages (from openmim) (1.3.5)\n", + " Downloading openmim-0.3.7-py2.py3-none-any.whl (51 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m51.3/51.3 kB\u001b[0m \u001b[31m1.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: tabulate in /usr/local/lib/python3.9/dist-packages (from openmim) (0.8.10)\n", + "Requirement already satisfied: rich in /usr/local/lib/python3.9/dist-packages (from openmim) (13.3.3)\n", + "Requirement already satisfied: pip>=19.3 in /usr/local/lib/python3.9/dist-packages (from openmim) (23.0.1)\n", + "Collecting colorama\n", + " Downloading colorama-0.4.6-py2.py3-none-any.whl (25 kB)\n", "Collecting model-index\n", " Downloading model_index-0.1.11-py3-none-any.whl (34 kB)\n", - "Requirement already satisfied: Click in /usr/local/lib/python3.7/dist-packages (from openmim) (7.1.2)\n", - "Collecting colorama\n", - " Downloading colorama-0.4.5-py2.py3-none-any.whl (16 kB)\n", - "Requirement already satisfied: requests in /usr/local/lib/python3.7/dist-packages (from openmim) (2.23.0)\n", - "Collecting rich\n", - " Downloading rich-12.5.1-py3-none-any.whl (235 kB)\n", - "\u001b[K |████████████████████████████████| 235 kB 60.9 MB/s \n", - "\u001b[?25hRequirement already satisfied: markdown in /usr/local/lib/python3.7/dist-packages (from model-index->openmim) (3.4.1)\n", + "Requirement already satisfied: pandas in /usr/local/lib/python3.9/dist-packages (from openmim) (1.5.3)\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.9/dist-packages (from openmim) (2.27.1)\n", + "Requirement already satisfied: Click in /usr/local/lib/python3.9/dist-packages (from openmim) (8.1.3)\n", + "Requirement already satisfied: markdown in /usr/local/lib/python3.9/dist-packages (from model-index->openmim) (3.4.3)\n", "Collecting ordered-set\n", " Downloading ordered_set-4.1.0-py3-none-any.whl (7.6 kB)\n", - "Requirement already satisfied: pyyaml in /usr/local/lib/python3.7/dist-packages (from model-index->openmim) (6.0)\n", - "Requirement already satisfied: importlib-metadata>=4.4 in /usr/local/lib/python3.7/dist-packages (from markdown->model-index->openmim) (4.12.0)\n", - "Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.7/dist-packages (from importlib-metadata>=4.4->markdown->model-index->openmim) (3.8.1)\n", - "Requirement already satisfied: typing-extensions>=3.6.4 in /usr/local/lib/python3.7/dist-packages (from importlib-metadata>=4.4->markdown->model-index->openmim) (4.1.1)\n", - "Requirement already satisfied: python-dateutil>=2.7.3 in /usr/local/lib/python3.7/dist-packages (from pandas->openmim) (2.8.2)\n", - "Requirement already satisfied: numpy>=1.17.3 in /usr/local/lib/python3.7/dist-packages (from pandas->openmim) (1.21.6)\n", - "Requirement already satisfied: pytz>=2017.3 in /usr/local/lib/python3.7/dist-packages (from pandas->openmim) (2022.2.1)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil>=2.7.3->pandas->openmim) (1.15.0)\n", - "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests->openmim) (1.24.3)\n", - "Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests->openmim) (2.10)\n", - "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests->openmim) (2022.6.15)\n", - "Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests->openmim) (3.0.4)\n", - "Collecting commonmark<0.10.0,>=0.9.0\n", - " Downloading commonmark-0.9.1-py2.py3-none-any.whl (51 kB)\n", - "\u001b[K |████████████████████████████████| 51 kB 6.5 MB/s \n", - "\u001b[?25hRequirement already satisfied: pygments<3.0.0,>=2.6.0 in /usr/local/lib/python3.7/dist-packages (from rich->openmim) (2.6.1)\n", - "Installing collected packages: ordered-set, commonmark, rich, model-index, colorama, openmim\n", - "Successfully installed colorama-0.4.5 commonmark-0.9.1 model-index-0.1.11 openmim-0.3.1 ordered-set-4.1.0 rich-12.5.1\n", + "Requirement already satisfied: pyyaml in /usr/local/lib/python3.9/dist-packages (from model-index->openmim) (6.0)\n", + "Requirement already satisfied: numpy>=1.20.3 in /usr/local/lib/python3.9/dist-packages (from pandas->openmim) (1.22.4)\n", + "Requirement already satisfied: python-dateutil>=2.8.1 in /usr/local/lib/python3.9/dist-packages (from pandas->openmim) (2.8.2)\n", + "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.9/dist-packages (from pandas->openmim) (2022.7.1)\n", + "Requirement already satisfied: charset-normalizer~=2.0.0 in /usr/local/lib/python3.9/dist-packages (from requests->openmim) (2.0.12)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.9/dist-packages (from requests->openmim) (2022.12.7)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.9/dist-packages (from requests->openmim) (3.4)\n", + "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/local/lib/python3.9/dist-packages (from requests->openmim) (1.26.15)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.9/dist-packages (from rich->openmim) (2.14.0)\n", + "Requirement already satisfied: markdown-it-py<3.0.0,>=2.2.0 in /usr/local/lib/python3.9/dist-packages (from rich->openmim) (2.2.0)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.9/dist-packages (from markdown-it-py<3.0.0,>=2.2.0->rich->openmim) (0.1.2)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.9/dist-packages (from python-dateutil>=2.8.1->pandas->openmim) (1.16.0)\n", + "Requirement already satisfied: importlib-metadata>=4.4 in /usr/local/lib/python3.9/dist-packages (from markdown->model-index->openmim) (6.2.0)\n", + "Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.9/dist-packages (from importlib-metadata>=4.4->markdown->model-index->openmim) (3.15.0)\n", + "Installing collected packages: ordered-set, colorama, model-index, openmim\n", + "Successfully installed colorama-0.4.6 model-index-0.1.11 openmim-0.3.7 ordered-set-4.1.0\n", + "/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", - "Looking in links: https://download.openmmlab.com/mmcv/dist/cu111/torch1.10.0/index.html\n", + "Looking in links: https://download.openmmlab.com/mmcv/dist/cu118/torch2.0.0/index.html\n", "Collecting mmengine\n", - " Downloading mmengine-0.1.0-py3-none-any.whl (280 kB)\n", - "\u001b[K |████████████████████████████████| 280 kB 29.0 MB/s \n", - "\u001b[?25hRequirement already satisfied: matplotlib in /usr/local/lib/python3.7/dist-packages (from mmengine) (3.2.2)\n", - "Collecting addict\n", - " Downloading addict-2.4.0-py3-none-any.whl (3.8 kB)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from mmengine) (1.21.6)\n", - "Requirement already satisfied: pyyaml in /usr/local/lib/python3.7/dist-packages (from mmengine) (6.0)\n", + " Downloading mmengine-0.7.2-py3-none-any.whl (366 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m366.9/366.9 kB\u001b[0m \u001b[31m14.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: rich in /usr/local/lib/python3.9/dist-packages (from mmengine) (13.3.3)\n", + "Requirement already satisfied: matplotlib in /usr/local/lib/python3.9/dist-packages (from mmengine) (3.7.1)\n", + "Requirement already satisfied: pyyaml in /usr/local/lib/python3.9/dist-packages (from mmengine) (6.0)\n", + "Requirement already satisfied: opencv-python>=3 in /usr/local/lib/python3.9/dist-packages (from mmengine) (4.7.0.72)\n", "Collecting yapf\n", " Downloading yapf-0.32.0-py2.py3-none-any.whl (190 kB)\n", - "\u001b[K |████████████████████████████████| 190 kB 82.8 MB/s \n", - "\u001b[?25hRequirement already satisfied: opencv-python>=3 in /usr/local/lib/python3.7/dist-packages (from mmengine) (4.6.0.66)\n", - "Requirement already satisfied: termcolor in /usr/local/lib/python3.7/dist-packages (from mmengine) (1.1.0)\n", - "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmengine) (3.0.9)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmengine) (0.11.0)\n", - "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmengine) (1.4.4)\n", - "Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmengine) (2.8.2)\n", - "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from kiwisolver>=1.0.1->matplotlib->mmengine) (4.1.1)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil>=2.1->matplotlib->mmengine) (1.15.0)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m190.2/190.2 kB\u001b[0m \u001b[31m17.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: termcolor in /usr/local/lib/python3.9/dist-packages (from mmengine) (2.2.0)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.9/dist-packages (from mmengine) (1.22.4)\n", + "Collecting addict\n", + " Downloading addict-2.4.0-py3-none-any.whl (3.8 kB)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine) (1.4.4)\n", + "Requirement already satisfied: importlib-resources>=3.2.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine) (5.12.0)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine) (23.0)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine) (0.11.0)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine) (2.8.2)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine) (4.39.3)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine) (3.0.9)\n", + "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine) (8.4.0)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine) (1.0.7)\n", + "Requirement already satisfied: markdown-it-py<3.0.0,>=2.2.0 in /usr/local/lib/python3.9/dist-packages (from rich->mmengine) (2.2.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.9/dist-packages (from rich->mmengine) (2.14.0)\n", + "Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.9/dist-packages (from importlib-resources>=3.2.0->matplotlib->mmengine) (3.15.0)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.9/dist-packages (from markdown-it-py<3.0.0,>=2.2.0->rich->mmengine) (0.1.2)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.9/dist-packages (from python-dateutil>=2.7->matplotlib->mmengine) (1.16.0)\n", "Installing collected packages: yapf, addict, mmengine\n", - "Successfully installed addict-2.4.0 mmengine-0.1.0 yapf-0.32.0\n", + "/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", + "/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", + "/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", + "/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", + "Successfully installed addict-2.4.0 mmengine-0.7.2 yapf-0.32.0\n", + "/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", - "Looking in links: https://download.openmmlab.com/mmcv/dist/cu111/torch1.10.0/index.html\n", + "Looking in links: https://download.openmmlab.com/mmcv/dist/cu118/torch2.0.0/index.html\n", "Collecting mmcv>=2.0.0rc1\n", - " Downloading https://download.openmmlab.com/mmcv/dist/cu111/torch1.10.0/mmcv-2.0.0rc1-cp37-cp37m-manylinux1_x86_64.whl (47.5 MB)\n", - "\u001b[K |████████████████████████████████| 47.5 MB 11.3 MB/s \n", - "\u001b[?25hRequirement already satisfied: addict in /usr/local/lib/python3.7/dist-packages (from mmcv>=2.0.0rc1) (2.4.0)\n", - "Requirement already satisfied: pyyaml in /usr/local/lib/python3.7/dist-packages (from mmcv>=2.0.0rc1) (6.0)\n", - "Requirement already satisfied: yapf in /usr/local/lib/python3.7/dist-packages (from mmcv>=2.0.0rc1) (0.32.0)\n", - "Requirement already satisfied: opencv-python>=3 in /usr/local/lib/python3.7/dist-packages (from mmcv>=2.0.0rc1) (4.6.0.66)\n", - "Requirement already satisfied: mmengine in /usr/local/lib/python3.7/dist-packages (from mmcv>=2.0.0rc1) (0.1.0)\n", - "Requirement already satisfied: packaging in /usr/local/lib/python3.7/dist-packages (from mmcv>=2.0.0rc1) (21.3)\n", - "Requirement already satisfied: Pillow in /usr/local/lib/python3.7/dist-packages (from mmcv>=2.0.0rc1) (7.1.2)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from mmcv>=2.0.0rc1) (1.21.6)\n", - "Requirement already satisfied: termcolor in /usr/local/lib/python3.7/dist-packages (from mmengine->mmcv>=2.0.0rc1) (1.1.0)\n", - "Requirement already satisfied: matplotlib in /usr/local/lib/python3.7/dist-packages (from mmengine->mmcv>=2.0.0rc1) (3.2.2)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmengine->mmcv>=2.0.0rc1) (0.11.0)\n", - "Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmengine->mmcv>=2.0.0rc1) (2.8.2)\n", - "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmengine->mmcv>=2.0.0rc1) (3.0.9)\n", - "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmengine->mmcv>=2.0.0rc1) (1.4.4)\n", - "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from kiwisolver>=1.0.1->matplotlib->mmengine->mmcv>=2.0.0rc1) (4.1.1)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil>=2.1->matplotlib->mmengine->mmcv>=2.0.0rc1) (1.15.0)\n", + " Downloading https://download.openmmlab.com/mmcv/dist/cu118/torch2.0.0/mmcv-2.0.0-cp39-cp39-manylinux1_x86_64.whl (74.4 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m74.4/74.4 MB\u001b[0m \u001b[31m12.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: mmengine>=0.2.0 in /usr/local/lib/python3.9/dist-packages (from mmcv>=2.0.0rc1) (0.7.2)\n", + "Requirement already satisfied: yapf in /usr/local/lib/python3.9/dist-packages (from mmcv>=2.0.0rc1) (0.32.0)\n", + "Requirement already satisfied: packaging in /usr/local/lib/python3.9/dist-packages (from mmcv>=2.0.0rc1) (23.0)\n", + "Requirement already satisfied: addict in /usr/local/lib/python3.9/dist-packages (from mmcv>=2.0.0rc1) (2.4.0)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.9/dist-packages (from mmcv>=2.0.0rc1) (1.22.4)\n", + "Requirement already satisfied: pyyaml in /usr/local/lib/python3.9/dist-packages (from mmcv>=2.0.0rc1) (6.0)\n", + "Requirement already satisfied: opencv-python>=3 in /usr/local/lib/python3.9/dist-packages (from mmcv>=2.0.0rc1) (4.7.0.72)\n", + "Requirement already satisfied: Pillow in /usr/local/lib/python3.9/dist-packages (from mmcv>=2.0.0rc1) (8.4.0)\n", + "Requirement already satisfied: matplotlib in /usr/local/lib/python3.9/dist-packages (from mmengine>=0.2.0->mmcv>=2.0.0rc1) (3.7.1)\n", + "Requirement already satisfied: rich in /usr/local/lib/python3.9/dist-packages (from mmengine>=0.2.0->mmcv>=2.0.0rc1) (13.3.3)\n", + "Requirement already satisfied: termcolor in /usr/local/lib/python3.9/dist-packages (from mmengine>=0.2.0->mmcv>=2.0.0rc1) (2.2.0)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine>=0.2.0->mmcv>=2.0.0rc1) (2.8.2)\n", + "Requirement already satisfied: importlib-resources>=3.2.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine>=0.2.0->mmcv>=2.0.0rc1) (5.12.0)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine>=0.2.0->mmcv>=2.0.0rc1) (0.11.0)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine>=0.2.0->mmcv>=2.0.0rc1) (4.39.3)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine>=0.2.0->mmcv>=2.0.0rc1) (3.0.9)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine>=0.2.0->mmcv>=2.0.0rc1) (1.4.4)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmengine>=0.2.0->mmcv>=2.0.0rc1) (1.0.7)\n", + "Requirement already satisfied: markdown-it-py<3.0.0,>=2.2.0 in /usr/local/lib/python3.9/dist-packages (from rich->mmengine>=0.2.0->mmcv>=2.0.0rc1) (2.2.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.9/dist-packages (from rich->mmengine>=0.2.0->mmcv>=2.0.0rc1) (2.14.0)\n", + "Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.9/dist-packages (from importlib-resources>=3.2.0->matplotlib->mmengine>=0.2.0->mmcv>=2.0.0rc1) (3.15.0)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.9/dist-packages (from markdown-it-py<3.0.0,>=2.2.0->rich->mmengine>=0.2.0->mmcv>=2.0.0rc1) (0.1.2)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.9/dist-packages (from python-dateutil>=2.7->matplotlib->mmengine>=0.2.0->mmcv>=2.0.0rc1) (1.16.0)\n", "Installing collected packages: mmcv\n", - "Successfully installed mmcv-2.0.0rc1\n", + "/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", + "/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", + "Successfully installed mmcv-2.0.0\n", + "/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", - "Looking in links: https://download.openmmlab.com/mmcv/dist/cu111/torch1.10.0/index.html\n", + "Looking in links: https://download.openmmlab.com/mmcv/dist/cu118/torch2.0.0/index.html\n", "Collecting mmdet>=3.0.0rc0\n", - " Downloading mmdet-3.0.0rc0-py3-none-any.whl (1.5 MB)\n", - "\u001b[K |████████████████████████████████| 1.5 MB 27.0 MB/s \n", - "\u001b[?25hLooking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", - "Collecting mmdet==3.0.0rc0\n", - " Downloading mmdet-3.0.0rc0.tar.gz (810 kB)\n", - "\u001b[K |████████████████████████████████| 810 kB 27.2 MB/s \n", - "\u001b[?25hSaved /tmp/tmp92449vla/mmdet-3.0.0rc0.tar.gz\n", - "Successfully downloaded mmdet\n", - "\u001b[33mGet 'mim' extra requirements from `mminstall.txt` for mmdet 3.0.0rc0: ['mmcv<2.1.0,>=2.0.0rc1', 'mmengine'].\u001b[0m\n", - "Requirement already satisfied: matplotlib in /usr/local/lib/python3.7/dist-packages (from mmdet>=3.0.0rc0) (3.2.2)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from mmdet>=3.0.0rc0) (1.21.6)\n", - "Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from mmdet>=3.0.0rc0) (1.15.0)\n", - "Requirement already satisfied: pycocotools in /usr/local/lib/python3.7/dist-packages (from mmdet>=3.0.0rc0) (2.0.4)\n", + " Downloading mmdet-3.0.0-py3-none-any.whl (1.7 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.7/1.7 MB\u001b[0m \u001b[31m71.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: six in /usr/local/lib/python3.9/dist-packages (from mmdet>=3.0.0rc0) (1.16.0)\n", "Collecting terminaltables\n", " Downloading terminaltables-3.1.10-py2.py3-none-any.whl (15 kB)\n", - "Requirement already satisfied: mmcv<2.1.0,>=2.0.0rc1 in /usr/local/lib/python3.7/dist-packages (from mmdet>=3.0.0rc0) (2.0.0rc1)\n", - "Requirement already satisfied: mmengine in /usr/local/lib/python3.7/dist-packages (from mmdet>=3.0.0rc0) (0.1.0)\n", - "Requirement already satisfied: packaging in /usr/local/lib/python3.7/dist-packages (from mmcv<2.1.0,>=2.0.0rc1->mmdet>=3.0.0rc0) (21.3)\n", - "Requirement already satisfied: addict in /usr/local/lib/python3.7/dist-packages (from mmcv<2.1.0,>=2.0.0rc1->mmdet>=3.0.0rc0) (2.4.0)\n", - "Requirement already satisfied: Pillow in /usr/local/lib/python3.7/dist-packages (from mmcv<2.1.0,>=2.0.0rc1->mmdet>=3.0.0rc0) (7.1.2)\n", - "Requirement already satisfied: opencv-python>=3 in /usr/local/lib/python3.7/dist-packages (from mmcv<2.1.0,>=2.0.0rc1->mmdet>=3.0.0rc0) (4.6.0.66)\n", - "Requirement already satisfied: pyyaml in /usr/local/lib/python3.7/dist-packages (from mmcv<2.1.0,>=2.0.0rc1->mmdet>=3.0.0rc0) (6.0)\n", - "Requirement already satisfied: yapf in /usr/local/lib/python3.7/dist-packages (from mmcv<2.1.0,>=2.0.0rc1->mmdet>=3.0.0rc0) (0.32.0)\n", - "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmdet>=3.0.0rc0) (3.0.9)\n", - "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmdet>=3.0.0rc0) (1.4.4)\n", - "Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmdet>=3.0.0rc0) (2.8.2)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmdet>=3.0.0rc0) (0.11.0)\n", - "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from kiwisolver>=1.0.1->matplotlib->mmdet>=3.0.0rc0) (4.1.1)\n", - "Requirement already satisfied: termcolor in /usr/local/lib/python3.7/dist-packages (from mmengine->mmdet>=3.0.0rc0) (1.1.0)\n", - "\u001b[33mUsing cached `mminstall.txt` for mmdet==3.0.0rc0: /root/.cache/mim/mminstall/mmdet==3.0.0rc0.txt\u001b[0m\n", - "\u001b[33mGet 'mim' extra requirements from `mminstall.txt` for mmdet 3.0.0rc0: ['mmcv<2.1.0,>=2.0.0rc1', 'mmengine'].\u001b[0m\n", + "Requirement already satisfied: pycocotools in /usr/local/lib/python3.9/dist-packages (from mmdet>=3.0.0rc0) (2.0.6)\n", + "Requirement already satisfied: scipy in /usr/local/lib/python3.9/dist-packages (from mmdet>=3.0.0rc0) (1.10.1)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.9/dist-packages (from mmdet>=3.0.0rc0) (1.22.4)\n", + "Requirement already satisfied: matplotlib in /usr/local/lib/python3.9/dist-packages (from mmdet>=3.0.0rc0) (3.7.1)\n", + "Requirement already satisfied: shapely in /usr/local/lib/python3.9/dist-packages (from mmdet>=3.0.0rc0) (2.0.1)\n", + "Requirement already satisfied: mmengine<1.0.0,>=0.7.1 in /usr/local/lib/python3.9/dist-packages (from mmdet>=3.0.0rc0) (0.7.2)\n", + "Requirement already satisfied: mmcv<2.1.0,>=2.0.0rc4 in /usr/local/lib/python3.9/dist-packages (from mmdet>=3.0.0rc0) (2.0.0)\n", + "Requirement already satisfied: pyyaml in /usr/local/lib/python3.9/dist-packages (from mmcv<2.1.0,>=2.0.0rc4->mmdet>=3.0.0rc0) (6.0)\n", + "Requirement already satisfied: packaging in /usr/local/lib/python3.9/dist-packages (from mmcv<2.1.0,>=2.0.0rc4->mmdet>=3.0.0rc0) (23.0)\n", + "Requirement already satisfied: opencv-python>=3 in /usr/local/lib/python3.9/dist-packages (from mmcv<2.1.0,>=2.0.0rc4->mmdet>=3.0.0rc0) (4.7.0.72)\n", + "Requirement already satisfied: addict in /usr/local/lib/python3.9/dist-packages (from mmcv<2.1.0,>=2.0.0rc4->mmdet>=3.0.0rc0) (2.4.0)\n", + "Requirement already satisfied: Pillow in /usr/local/lib/python3.9/dist-packages (from mmcv<2.1.0,>=2.0.0rc4->mmdet>=3.0.0rc0) (8.4.0)\n", + "Requirement already satisfied: yapf in /usr/local/lib/python3.9/dist-packages (from mmcv<2.1.0,>=2.0.0rc4->mmdet>=3.0.0rc0) (0.32.0)\n", + "Requirement already satisfied: termcolor in /usr/local/lib/python3.9/dist-packages (from mmengine<1.0.0,>=0.7.1->mmdet>=3.0.0rc0) (2.2.0)\n", + "Requirement already satisfied: rich in /usr/local/lib/python3.9/dist-packages (from mmengine<1.0.0,>=0.7.1->mmdet>=3.0.0rc0) (13.3.3)\n", + "Requirement already satisfied: importlib-resources>=3.2.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmdet>=3.0.0rc0) (5.12.0)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmdet>=3.0.0rc0) (2.8.2)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmdet>=3.0.0rc0) (4.39.3)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmdet>=3.0.0rc0) (1.4.4)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmdet>=3.0.0rc0) (0.11.0)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmdet>=3.0.0rc0) (1.0.7)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmdet>=3.0.0rc0) (3.0.9)\n", + "Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.9/dist-packages (from importlib-resources>=3.2.0->matplotlib->mmdet>=3.0.0rc0) (3.15.0)\n", + "Requirement already satisfied: markdown-it-py<3.0.0,>=2.2.0 in /usr/local/lib/python3.9/dist-packages (from rich->mmengine<1.0.0,>=0.7.1->mmdet>=3.0.0rc0) (2.2.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.9/dist-packages (from rich->mmengine<1.0.0,>=0.7.1->mmdet>=3.0.0rc0) (2.14.0)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.9/dist-packages (from markdown-it-py<3.0.0,>=2.2.0->rich->mmengine<1.0.0,>=0.7.1->mmdet>=3.0.0rc0) (0.1.2)\n", "Installing collected packages: terminaltables, mmdet\n", - "Successfully installed mmdet-3.0.0rc0 terminaltables-3.1.10\n" + "/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", + "/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", + "/usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", + "Successfully installed mmdet-3.0.0 terminaltables-3.1.10\n" ] } ], "source": [ - "# install dependencies: (use cu111 because colab has CUDA 11.1)\n", - "%pip install torch==1.10.0+cu111 torchvision==0.11.0+cu111 -f https://download.pytorch.org/whl/torch_stable.html\n", - "\n", "# install MMEngine, MMCV and MMDetection using MIM\n", "%pip install -U openmim\n", "!mim install mmengine\n", - "!mim install \"mmcv>=2.0.0rc1\"\n", - "!mim install \"mmdet>=3.0.0rc0\"" + "!mim install \"mmcv>=2.0.0\"\n", + "!mim install \"mmdet>=3.0.0\"" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "42hRcloJhE2N", + "outputId": "9175e011-82c0-438d-f378-264e8467eb09" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "Collecting git+https://github.com/jin-s13/xtcocoapi\n", + " Cloning https://github.com/jin-s13/xtcocoapi to /tmp/pip-req-build-6ts8xw10\n", + " Running command git clone --filter=blob:none --quiet https://github.com/jin-s13/xtcocoapi /tmp/pip-req-build-6ts8xw10\n", + " Resolved https://github.com/jin-s13/xtcocoapi to commit 86a60cab276e619dac5d22834a36dceaf7aa0a38\n", + " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Requirement already satisfied: setuptools>=18.0 in /usr/local/lib/python3.9/dist-packages (from xtcocotools==1.13) (67.6.1)\n", + "Requirement already satisfied: cython>=0.27.3 in /usr/local/lib/python3.9/dist-packages (from xtcocotools==1.13) (0.29.34)\n", + "Requirement already satisfied: matplotlib>=2.1.0 in /usr/local/lib/python3.9/dist-packages (from xtcocotools==1.13) (3.7.1)\n", + "Requirement already satisfied: numpy>=1.20.0 in /usr/local/lib/python3.9/dist-packages (from xtcocotools==1.13) (1.22.4)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.1.0->xtcocotools==1.13) (1.4.4)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.1.0->xtcocotools==1.13) (4.39.3)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.1.0->xtcocotools==1.13) (1.0.7)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.1.0->xtcocotools==1.13) (0.11.0)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.1.0->xtcocotools==1.13) (23.0)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.1.0->xtcocotools==1.13) (3.0.9)\n", + "Requirement already satisfied: importlib-resources>=3.2.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.1.0->xtcocotools==1.13) (5.12.0)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.1.0->xtcocotools==1.13) (2.8.2)\n", + "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib>=2.1.0->xtcocotools==1.13) (8.4.0)\n", + "Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.9/dist-packages (from importlib-resources>=3.2.0->matplotlib>=2.1.0->xtcocotools==1.13) (3.15.0)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.9/dist-packages (from python-dateutil>=2.7->matplotlib>=2.1.0->xtcocotools==1.13) (1.16.0)\n", + "Building wheels for collected packages: xtcocotools\n", + " Building wheel for xtcocotools (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for xtcocotools: filename=xtcocotools-1.13-cp39-cp39-linux_x86_64.whl size=402078 sha256=e6a1d4ea868ca2cbd8151f85509641b20b24745a9b8b353348ba8386c35ee6c6\n", + " Stored in directory: /tmp/pip-ephem-wheel-cache-a15wpqzs/wheels/3f/df/8b/d3eff2ded4b03a665d977a0baa328d9efa2f9ac9971929a222\n", + "Successfully built xtcocotools\n", + "Installing collected packages: xtcocotools\n", + "Successfully installed xtcocotools-1.13\n" + ] + } + ], + "source": [ + "# for better Colab compatibility, install xtcocotools from source\n", + "%pip install git+https://github.com/jin-s13/xtcocoapi" + ] + }, + { + "cell_type": "code", + "execution_count": 5, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "lzuSKOjMvJZu", - "outputId": "97f7e562-a645-4457-a042-46f4fcf6a93f" + "outputId": "d6a7a3f8-2d96-40a6-a7c4-65697e18ffc9" }, "outputs": [ { @@ -280,196 +372,173 @@ "output_type": "stream", "text": [ "Cloning into 'mmpose'...\n", - "remote: Enumerating objects: 21717, done.\u001b[K\n", - "remote: Counting objects: 100% (773/773), done.\u001b[K\n", - "remote: Compressing objects: 100% (492/492), done.\u001b[K\n", - "remote: Total 21717 (delta 451), reused 482 (delta 259), pack-reused 20944\u001b[K\n", - "Receiving objects: 100% (21717/21717), 25.74 MiB | 37.98 MiB/s, done.\n", - "Resolving deltas: 100% (15347/15347), done.\n", + "remote: Enumerating objects: 26225, done.\u001b[K\n", + "remote: Counting objects: 100% (97/97), done.\u001b[K\n", + "remote: Compressing objects: 100% (67/67), done.\u001b[K\n", + "remote: Total 26225 (delta 33), reused 67 (delta 28), pack-reused 26128\u001b[K\n", + "Receiving objects: 100% (26225/26225), 28.06 MiB | 13.36 MiB/s, done.\n", + "Resolving deltas: 100% (18673/18673), done.\n", "/content/mmpose\n", "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", - "Ignoring dataclasses: markers 'python_version == \"3.6\"' don't match your environment\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from -r requirements/build.txt (line 2)) (1.21.6)\n", - "Requirement already satisfied: torch>=1.6 in /usr/local/lib/python3.7/dist-packages (from -r requirements/build.txt (line 3)) (1.10.0+cu111)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.9/dist-packages (from -r requirements/build.txt (line 2)) (1.22.4)\n", + "Requirement already satisfied: torch>=1.6 in /usr/local/lib/python3.9/dist-packages (from -r requirements/build.txt (line 3)) (2.0.0+cu118)\n", "Collecting chumpy\n", " Downloading chumpy-0.70.tar.gz (50 kB)\n", - "\u001b[K |████████████████████████████████| 50 kB 2.7 MB/s \n", - "\u001b[?25hCollecting json_tricks\n", - " Downloading json_tricks-3.15.5-py2.py3-none-any.whl (26 kB)\n", - "Requirement already satisfied: matplotlib in /usr/local/lib/python3.7/dist-packages (from -r requirements/runtime.txt (line 4)) (3.2.2)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m50.6/50.6 kB\u001b[0m \u001b[31m2.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Collecting json_tricks\n", + " Downloading json_tricks-3.16.1-py2.py3-none-any.whl (27 kB)\n", + "Requirement already satisfied: matplotlib in /usr/local/lib/python3.9/dist-packages (from -r requirements/runtime.txt (line 3)) (3.7.1)\n", "Collecting munkres\n", " Downloading munkres-1.1.4-py2.py3-none-any.whl (7.0 kB)\n", - "Requirement already satisfied: opencv-python in /usr/local/lib/python3.7/dist-packages (from -r requirements/runtime.txt (line 7)) (4.6.0.66)\n", - "Requirement already satisfied: pillow in /usr/local/lib/python3.7/dist-packages (from -r requirements/runtime.txt (line 8)) (7.1.2)\n", - "Requirement already satisfied: scipy in /usr/local/lib/python3.7/dist-packages (from -r requirements/runtime.txt (line 9)) (1.7.3)\n", - "Requirement already satisfied: torchvision in /usr/local/lib/python3.7/dist-packages (from -r requirements/runtime.txt (line 10)) (0.11.0+cu111)\n", - "Collecting xtcocotools>=1.12\n", - " Downloading xtcocotools-1.12-cp37-cp37m-manylinux1_x86_64.whl (276 kB)\n", - "\u001b[K |████████████████████████████████| 276 kB 31.0 MB/s \n", - "\u001b[?25hCollecting coverage\n", - " Downloading coverage-6.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (209 kB)\n", - "\u001b[K |████████████████████████████████| 209 kB 69.7 MB/s \n", + "Requirement already satisfied: opencv-python in /usr/local/lib/python3.9/dist-packages (from -r requirements/runtime.txt (line 6)) (4.7.0.72)\n", + "Requirement already satisfied: pillow in /usr/local/lib/python3.9/dist-packages (from -r requirements/runtime.txt (line 7)) (8.4.0)\n", + "Requirement already satisfied: scipy in /usr/local/lib/python3.9/dist-packages (from -r requirements/runtime.txt (line 8)) (1.10.1)\n", + "Requirement already satisfied: torchvision in /usr/local/lib/python3.9/dist-packages (from -r requirements/runtime.txt (line 9)) (0.15.1+cu118)\n", + "Requirement already satisfied: xtcocotools>=1.12 in /usr/local/lib/python3.9/dist-packages (from -r requirements/runtime.txt (line 10)) (1.13)\n", + "Collecting coverage\n", + " Downloading coverage-7.2.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (227 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m227.5/227.5 kB\u001b[0m \u001b[31m27.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting flake8\n", - " Downloading flake8-5.0.4-py2.py3-none-any.whl (61 kB)\n", - "\u001b[K |████████████████████████████████| 61 kB 392 kB/s \n", + " Downloading flake8-6.0.0-py2.py3-none-any.whl (57 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m57.8/57.8 kB\u001b[0m \u001b[31m6.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting interrogate\n", " Downloading interrogate-1.5.0-py3-none-any.whl (45 kB)\n", - "\u001b[K |████████████████████████████████| 45 kB 3.0 MB/s \n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m45.3/45.3 kB\u001b[0m \u001b[31m5.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting isort==4.3.21\n", " Downloading isort-4.3.21-py2.py3-none-any.whl (42 kB)\n", - "\u001b[K |████████████████████████████████| 42 kB 876 kB/s \n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m42.3/42.3 kB\u001b[0m \u001b[31m5.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting parameterized\n", - " Downloading parameterized-0.8.1-py2.py3-none-any.whl (26 kB)\n", - "Requirement already satisfied: pytest in /usr/local/lib/python3.7/dist-packages (from -r requirements/tests.txt (line 6)) (3.6.4)\n", + " Downloading parameterized-0.9.0-py2.py3-none-any.whl (20 kB)\n", + "Requirement already satisfied: pytest in /usr/local/lib/python3.9/dist-packages (from -r requirements/tests.txt (line 6)) (7.2.2)\n", "Collecting pytest-runner\n", " Downloading pytest_runner-6.0.0-py3-none-any.whl (7.2 kB)\n", "Collecting xdoctest>=0.10.0\n", - " Downloading xdoctest-1.1.0-py3-none-any.whl (135 kB)\n", - "\u001b[K |████████████████████████████████| 135 kB 43.8 MB/s \n", - "\u001b[?25hRequirement already satisfied: yapf in /usr/local/lib/python3.7/dist-packages (from -r requirements/tests.txt (line 9)) (0.32.0)\n", - "Requirement already satisfied: requests in /usr/local/lib/python3.7/dist-packages (from -r requirements/optional.txt (line 1)) (2.23.0)\n", - "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from torch>=1.6->-r requirements/build.txt (line 3)) (4.1.1)\n", - "Requirement already satisfied: setuptools>=18.0 in /usr/local/lib/python3.7/dist-packages (from xtcocotools>=1.12->-r requirements/runtime.txt (line 11)) (57.4.0)\n", - "Requirement already satisfied: cython>=0.27.3 in /usr/local/lib/python3.7/dist-packages (from xtcocotools>=1.12->-r requirements/runtime.txt (line 11)) (0.29.32)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib->-r requirements/runtime.txt (line 4)) (0.11.0)\n", - "Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->-r requirements/runtime.txt (line 4)) (2.8.2)\n", - "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->-r requirements/runtime.txt (line 4)) (3.0.9)\n", - "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->-r requirements/runtime.txt (line 4)) (1.4.4)\n", - "Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from xdoctest>=0.10.0->-r requirements/tests.txt (line 8)) (1.15.0)\n", - "Collecting pycodestyle<2.10.0,>=2.9.0\n", - " Downloading pycodestyle-2.9.1-py2.py3-none-any.whl (41 kB)\n", - "\u001b[K |████████████████████████████████| 41 kB 379 kB/s \n", - "\u001b[?25hCollecting pyflakes<2.6.0,>=2.5.0\n", - " Downloading pyflakes-2.5.0-py2.py3-none-any.whl (66 kB)\n", - "\u001b[K |████████████████████████████████| 66 kB 3.1 MB/s \n", - "\u001b[?25hCollecting importlib-metadata<4.3,>=1.1.0\n", - " Downloading importlib_metadata-4.2.0-py3-none-any.whl (16 kB)\n", - "Collecting mccabe<0.8.0,>=0.7.0\n", + " Downloading xdoctest-1.1.1-py3-none-any.whl (137 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m137.6/137.6 kB\u001b[0m \u001b[31m14.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: yapf in /usr/local/lib/python3.9/dist-packages (from -r requirements/tests.txt (line 9)) (0.32.0)\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.9/dist-packages (from -r requirements/optional.txt (line 1)) (2.27.1)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.9/dist-packages (from torch>=1.6->-r requirements/build.txt (line 3)) (3.11.0)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.9/dist-packages (from torch>=1.6->-r requirements/build.txt (line 3)) (3.1)\n", + "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.9/dist-packages (from torch>=1.6->-r requirements/build.txt (line 3)) (4.5.0)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.9/dist-packages (from torch>=1.6->-r requirements/build.txt (line 3)) (3.1.2)\n", + "Requirement already satisfied: triton==2.0.0 in /usr/local/lib/python3.9/dist-packages (from torch>=1.6->-r requirements/build.txt (line 3)) (2.0.0)\n", + "Requirement already satisfied: sympy in /usr/local/lib/python3.9/dist-packages (from torch>=1.6->-r requirements/build.txt (line 3)) (1.11.1)\n", + "Requirement already satisfied: cmake in /usr/local/lib/python3.9/dist-packages (from triton==2.0.0->torch>=1.6->-r requirements/build.txt (line 3)) (3.25.2)\n", + "Requirement already satisfied: lit in /usr/local/lib/python3.9/dist-packages (from triton==2.0.0->torch>=1.6->-r requirements/build.txt (line 3)) (16.0.1)\n", + "Requirement already satisfied: six>=1.11.0 in /usr/local/lib/python3.9/dist-packages (from chumpy->-r requirements/runtime.txt (line 1)) (1.16.0)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->-r requirements/runtime.txt (line 3)) (4.39.3)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->-r requirements/runtime.txt (line 3)) (3.0.9)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->-r requirements/runtime.txt (line 3)) (1.4.4)\n", + "Requirement already satisfied: importlib-resources>=3.2.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->-r requirements/runtime.txt (line 3)) (5.12.0)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.9/dist-packages (from matplotlib->-r requirements/runtime.txt (line 3)) (2.8.2)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->-r requirements/runtime.txt (line 3)) (23.0)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->-r requirements/runtime.txt (line 3)) (1.0.7)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.9/dist-packages (from matplotlib->-r requirements/runtime.txt (line 3)) (0.11.0)\n", + "Requirement already satisfied: setuptools>=18.0 in /usr/local/lib/python3.9/dist-packages (from xtcocotools>=1.12->-r requirements/runtime.txt (line 10)) (67.6.1)\n", + "Requirement already satisfied: cython>=0.27.3 in /usr/local/lib/python3.9/dist-packages (from xtcocotools>=1.12->-r requirements/runtime.txt (line 10)) (0.29.34)\n", + "Collecting pyflakes<3.1.0,>=3.0.0\n", + " Downloading pyflakes-3.0.1-py2.py3-none-any.whl (62 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m62.8/62.8 kB\u001b[0m \u001b[31m5.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting pycodestyle<2.11.0,>=2.10.0\n", + " Downloading pycodestyle-2.10.0-py2.py3-none-any.whl (41 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m41.3/41.3 kB\u001b[0m \u001b[31m4.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting mccabe<0.8.0,>=0.7.0\n", " Downloading mccabe-0.7.0-py2.py3-none-any.whl (7.3 kB)\n", - "Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.7/dist-packages (from importlib-metadata<4.3,>=1.1.0->flake8->-r requirements/tests.txt (line 2)) (3.8.1)\n", - "Requirement already satisfied: tabulate in /usr/local/lib/python3.7/dist-packages (from interrogate->-r requirements/tests.txt (line 3)) (0.8.10)\n", - "Requirement already satisfied: colorama in /usr/local/lib/python3.7/dist-packages (from interrogate->-r requirements/tests.txt (line 3)) (0.4.5)\n", - "Requirement already satisfied: py in /usr/local/lib/python3.7/dist-packages (from interrogate->-r requirements/tests.txt (line 3)) (1.11.0)\n", - "Requirement already satisfied: attrs in /usr/local/lib/python3.7/dist-packages (from interrogate->-r requirements/tests.txt (line 3)) (22.1.0)\n", - "Requirement already satisfied: click>=7.1 in /usr/local/lib/python3.7/dist-packages (from interrogate->-r requirements/tests.txt (line 3)) (7.1.2)\n", - "Requirement already satisfied: toml in /usr/local/lib/python3.7/dist-packages (from interrogate->-r requirements/tests.txt (line 3)) (0.10.2)\n", - "Requirement already satisfied: pluggy<0.8,>=0.5 in /usr/local/lib/python3.7/dist-packages (from pytest->-r requirements/tests.txt (line 6)) (0.7.1)\n", - "Requirement already satisfied: atomicwrites>=1.0 in /usr/local/lib/python3.7/dist-packages (from pytest->-r requirements/tests.txt (line 6)) (1.4.1)\n", - "Requirement already satisfied: more-itertools>=4.0.0 in /usr/local/lib/python3.7/dist-packages (from pytest->-r requirements/tests.txt (line 6)) (8.14.0)\n", - "Requirement already satisfied: chardet<4,>=3.0.2 in /usr/local/lib/python3.7/dist-packages (from requests->-r requirements/optional.txt (line 1)) (3.0.4)\n", - "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/dist-packages (from requests->-r requirements/optional.txt (line 1)) (2022.6.15)\n", - "Requirement already satisfied: idna<3,>=2.5 in /usr/local/lib/python3.7/dist-packages (from requests->-r requirements/optional.txt (line 1)) (2.10)\n", - "Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/dist-packages (from requests->-r requirements/optional.txt (line 1)) (1.24.3)\n", + "Collecting py\n", + " Downloading py-1.11.0-py2.py3-none-any.whl (98 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m98.7/98.7 kB\u001b[0m \u001b[31m11.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: colorama in /usr/local/lib/python3.9/dist-packages (from interrogate->-r requirements/tests.txt (line 3)) (0.4.6)\n", + "Requirement already satisfied: toml in /usr/local/lib/python3.9/dist-packages (from interrogate->-r requirements/tests.txt (line 3)) (0.10.2)\n", + "Requirement already satisfied: attrs in /usr/local/lib/python3.9/dist-packages (from interrogate->-r requirements/tests.txt (line 3)) (22.2.0)\n", + "Requirement already satisfied: tabulate in /usr/local/lib/python3.9/dist-packages (from interrogate->-r requirements/tests.txt (line 3)) (0.8.10)\n", + "Requirement already satisfied: click>=7.1 in /usr/local/lib/python3.9/dist-packages (from interrogate->-r requirements/tests.txt (line 3)) (8.1.3)\n", + "Requirement already satisfied: tomli>=1.0.0 in /usr/local/lib/python3.9/dist-packages (from pytest->-r requirements/tests.txt (line 6)) (2.0.1)\n", + "Requirement already satisfied: pluggy<2.0,>=0.12 in /usr/local/lib/python3.9/dist-packages (from pytest->-r requirements/tests.txt (line 6)) (1.0.0)\n", + "Requirement already satisfied: iniconfig in /usr/local/lib/python3.9/dist-packages (from pytest->-r requirements/tests.txt (line 6)) (2.0.0)\n", + "Requirement already satisfied: exceptiongroup>=1.0.0rc8 in /usr/local/lib/python3.9/dist-packages (from pytest->-r requirements/tests.txt (line 6)) (1.1.1)\n", + "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/local/lib/python3.9/dist-packages (from requests->-r requirements/optional.txt (line 1)) (1.26.15)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.9/dist-packages (from requests->-r requirements/optional.txt (line 1)) (2022.12.7)\n", + "Requirement already satisfied: charset-normalizer~=2.0.0 in /usr/local/lib/python3.9/dist-packages (from requests->-r requirements/optional.txt (line 1)) (2.0.12)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.9/dist-packages (from requests->-r requirements/optional.txt (line 1)) (3.4)\n", + "Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.9/dist-packages (from importlib-resources>=3.2.0->matplotlib->-r requirements/runtime.txt (line 3)) (3.15.0)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.9/dist-packages (from jinja2->torch>=1.6->-r requirements/build.txt (line 3)) (2.1.2)\n", + "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.9/dist-packages (from sympy->torch>=1.6->-r requirements/build.txt (line 3)) (1.3.0)\n", "Building wheels for collected packages: chumpy\n", " Building wheel for chumpy (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - " Created wheel for chumpy: filename=chumpy-0.70-py3-none-any.whl size=58285 sha256=1f1b6753e54dfbc86e01aba0f525a7d5771d73387934b07d29505242475908a1\n", - " Stored in directory: /root/.cache/pip/wheels/59/68/de/5e0c5d77e573e8c150e69e07a25035e6b6a04952d6e1814dbc\n", + " Created wheel for chumpy: filename=chumpy-0.70-py3-none-any.whl size=58282 sha256=ccde33ce99f135241a3f9ed380871cf8e4a569053d21b0ceba97809ddf3b26c8\n", + " Stored in directory: /root/.cache/pip/wheels/71/b5/d3/bbff0d638d797944856371a4ee326f9ffb1829083a383bba77\n", "Successfully built chumpy\n", - "Installing collected packages: pyflakes, pycodestyle, mccabe, importlib-metadata, xtcocotools, xdoctest, pytest-runner, parameterized, munkres, json-tricks, isort, interrogate, flake8, coverage, chumpy\n", - " Attempting uninstall: importlib-metadata\n", - " Found existing installation: importlib-metadata 4.12.0\n", - " Uninstalling importlib-metadata-4.12.0:\n", - " Successfully uninstalled importlib-metadata-4.12.0\n", - "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n", - "markdown 3.4.1 requires importlib-metadata>=4.4; python_version < \"3.10\", but you have importlib-metadata 4.2.0 which is incompatible.\n", - "gym 0.25.2 requires importlib-metadata>=4.8.0; python_version < \"3.10\", but you have importlib-metadata 4.2.0 which is incompatible.\u001b[0m\n", - "Successfully installed chumpy-0.70 coverage-6.4.4 flake8-5.0.4 importlib-metadata-4.2.0 interrogate-1.5.0 isort-4.3.21 json-tricks-3.15.5 mccabe-0.7.0 munkres-1.1.4 parameterized-0.8.1 pycodestyle-2.9.1 pyflakes-2.5.0 pytest-runner-6.0.0 xdoctest-1.1.0 xtcocotools-1.12\n", - "Using pip 21.1.3 from /usr/local/lib/python3.7/dist-packages/pip (python 3.7)\n", - "Value for scheme.platlib does not match. Please report this to \n", - "distutils: /usr/local/lib/python3.7/dist-packages\n", - "sysconfig: /usr/lib/python3.7/site-packages\n", - "Value for scheme.purelib does not match. Please report this to \n", - "distutils: /usr/local/lib/python3.7/dist-packages\n", - "sysconfig: /usr/lib/python3.7/site-packages\n", - "Value for scheme.headers does not match. Please report this to \n", - "distutils: /usr/local/include/python3.7/UNKNOWN\n", - "sysconfig: /usr/include/python3.7m/UNKNOWN\n", - "Value for scheme.scripts does not match. Please report this to \n", - "distutils: /usr/local/bin\n", - "sysconfig: /usr/bin\n", - "Value for scheme.data does not match. Please report this to \n", - "distutils: /usr/local\n", - "sysconfig: /usr\n", - "Additional context:\n", - "user = False\n", - "home = None\n", - "root = None\n", - "prefix = None\n", - "Non-user install because site-packages writeable\n", - "Created temporary directory: /tmp/pip-ephem-wheel-cache-6spdtpz_\n", - "Created temporary directory: /tmp/pip-req-tracker-pdrld3yb\n", - "Initialized build tracking at /tmp/pip-req-tracker-pdrld3yb\n", - "Created build tracker: /tmp/pip-req-tracker-pdrld3yb\n", - "Entered build tracker: /tmp/pip-req-tracker-pdrld3yb\n", - "Created temporary directory: /tmp/pip-install-llx1o5zd\n", + "Installing collected packages: munkres, json_tricks, xdoctest, pytest-runner, pyflakes, pycodestyle, py, parameterized, mccabe, isort, coverage, interrogate, flake8, chumpy\n", + "Successfully installed chumpy-0.70 coverage-7.2.3 flake8-6.0.0 interrogate-1.5.0 isort-4.3.21 json_tricks-3.16.1 mccabe-0.7.0 munkres-1.1.4 parameterized-0.9.0 py-1.11.0 pycodestyle-2.10.0 pyflakes-3.0.1 pytest-runner-6.0.0 xdoctest-1.1.1\n", + "Using pip 23.0.1 from /usr/local/lib/python3.9/dist-packages/pip (python 3.9)\n", "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", "Obtaining file:///content/mmpose\n", - " Added file:///content/mmpose to build tracker '/tmp/pip-req-tracker-pdrld3yb'\n", - " Running setup.py (path:/content/mmpose/setup.py) egg_info for package from file:///content/mmpose\n", - " Created temporary directory: /tmp/pip-pip-egg-info-e9ps6kvl\n", - " Running command python setup.py egg_info\n", - " running egg_info\n", - " creating /tmp/pip-pip-egg-info-e9ps6kvl/mmpose.egg-info\n", - " writing /tmp/pip-pip-egg-info-e9ps6kvl/mmpose.egg-info/PKG-INFO\n", - " writing dependency_links to /tmp/pip-pip-egg-info-e9ps6kvl/mmpose.egg-info/dependency_links.txt\n", - " writing requirements to /tmp/pip-pip-egg-info-e9ps6kvl/mmpose.egg-info/requires.txt\n", - " writing top-level names to /tmp/pip-pip-egg-info-e9ps6kvl/mmpose.egg-info/top_level.txt\n", - " writing manifest file '/tmp/pip-pip-egg-info-e9ps6kvl/mmpose.egg-info/SOURCES.txt'\n", - " reading manifest template 'MANIFEST.in'\n", - " warning: no files found matching 'mmpose/.mim/model-index.yml'\n", - " warning: no files found matching '*.py' under directory 'mmpose/.mim/configs'\n", - " warning: no files found matching '*.yml' under directory 'mmpose/.mim/configs'\n", - " warning: no files found matching '*.py' under directory 'mmpose/.mim/tools'\n", - " warning: no files found matching '*.sh' under directory 'mmpose/.mim/tools'\n", - " warning: no files found matching '*.py' under directory 'mmpose/.mim/demo'\n", - " adding license file 'LICENSE'\n", - " writing manifest file '/tmp/pip-pip-egg-info-e9ps6kvl/mmpose.egg-info/SOURCES.txt'\n", - " Source in /content/mmpose has version 1.0.0b0, which satisfies requirement mmpose==1.0.0b0 from file:///content/mmpose\n", - " Removed mmpose==1.0.0b0 from file:///content/mmpose from build tracker '/tmp/pip-req-tracker-pdrld3yb'\n", - "Requirement already satisfied: chumpy in /usr/local/lib/python3.7/dist-packages (from mmpose==1.0.0b0) (0.70)\n", - "Requirement already satisfied: json_tricks in /usr/local/lib/python3.7/dist-packages (from mmpose==1.0.0b0) (3.15.5)\n", - "Requirement already satisfied: matplotlib in /usr/local/lib/python3.7/dist-packages (from mmpose==1.0.0b0) (3.2.2)\n", - "Requirement already satisfied: munkres in /usr/local/lib/python3.7/dist-packages (from mmpose==1.0.0b0) (1.1.4)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.7/dist-packages (from mmpose==1.0.0b0) (1.21.6)\n", - "Requirement already satisfied: opencv-python in /usr/local/lib/python3.7/dist-packages (from mmpose==1.0.0b0) (4.6.0.66)\n", - "Requirement already satisfied: pillow in /usr/local/lib/python3.7/dist-packages (from mmpose==1.0.0b0) (7.1.2)\n", - "Requirement already satisfied: scipy in /usr/local/lib/python3.7/dist-packages (from mmpose==1.0.0b0) (1.7.3)\n", - "Requirement already satisfied: torchvision in /usr/local/lib/python3.7/dist-packages (from mmpose==1.0.0b0) (0.11.0+cu111)\n", - "Requirement already satisfied: xtcocotools>=1.12 in /usr/local/lib/python3.7/dist-packages (from mmpose==1.0.0b0) (1.12)\n", - "Requirement already satisfied: cython>=0.27.3 in /usr/local/lib/python3.7/dist-packages (from xtcocotools>=1.12->mmpose==1.0.0b0) (0.29.32)\n", - "Requirement already satisfied: setuptools>=18.0 in /usr/local/lib/python3.7/dist-packages (from xtcocotools>=1.12->mmpose==1.0.0b0) (57.4.0)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmpose==1.0.0b0) (0.11.0)\n", - "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmpose==1.0.0b0) (1.4.4)\n", - "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmpose==1.0.0b0) (3.0.9)\n", - "Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->mmpose==1.0.0b0) (2.8.2)\n", - "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from kiwisolver>=1.0.1->matplotlib->mmpose==1.0.0b0) (4.1.1)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil>=2.1->matplotlib->mmpose==1.0.0b0) (1.15.0)\n", - "Requirement already satisfied: torch==1.10.0+cu111 in /usr/local/lib/python3.7/dist-packages (from torchvision->mmpose==1.0.0b0) (1.10.0+cu111)\n", - "Created temporary directory: /tmp/pip-unpack-tkpwtsgw\n", + " Running command python setup.py egg_info\n", + " running egg_info\n", + " creating /tmp/pip-pip-egg-info-tatkegdw/mmpose.egg-info\n", + " writing /tmp/pip-pip-egg-info-tatkegdw/mmpose.egg-info/PKG-INFO\n", + " writing dependency_links to /tmp/pip-pip-egg-info-tatkegdw/mmpose.egg-info/dependency_links.txt\n", + " writing requirements to /tmp/pip-pip-egg-info-tatkegdw/mmpose.egg-info/requires.txt\n", + " writing top-level names to /tmp/pip-pip-egg-info-tatkegdw/mmpose.egg-info/top_level.txt\n", + " writing manifest file '/tmp/pip-pip-egg-info-tatkegdw/mmpose.egg-info/SOURCES.txt'\n", + " reading manifest file '/tmp/pip-pip-egg-info-tatkegdw/mmpose.egg-info/SOURCES.txt'\n", + " reading manifest template 'MANIFEST.in'\n", + " warning: no files found matching 'mmpose/.mim/model-index.yml'\n", + " warning: no files found matching '*.py' under directory 'mmpose/.mim/configs'\n", + " warning: no files found matching '*.yml' under directory 'mmpose/.mim/configs'\n", + " warning: no files found matching '*.py' under directory 'mmpose/.mim/tools'\n", + " warning: no files found matching '*.sh' under directory 'mmpose/.mim/tools'\n", + " warning: no files found matching '*.py' under directory 'mmpose/.mim/demo'\n", + " adding license file 'LICENSE'\n", + " writing manifest file '/tmp/pip-pip-egg-info-tatkegdw/mmpose.egg-info/SOURCES.txt'\n", + " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Requirement already satisfied: chumpy in /usr/local/lib/python3.9/dist-packages (from mmpose==1.0.0) (0.70)\n", + "Requirement already satisfied: json_tricks in /usr/local/lib/python3.9/dist-packages (from mmpose==1.0.0) (3.16.1)\n", + "Requirement already satisfied: matplotlib in /usr/local/lib/python3.9/dist-packages (from mmpose==1.0.0) (3.7.1)\n", + "Requirement already satisfied: munkres in /usr/local/lib/python3.9/dist-packages (from mmpose==1.0.0) (1.1.4)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.9/dist-packages (from mmpose==1.0.0) (1.22.4)\n", + "Requirement already satisfied: opencv-python in /usr/local/lib/python3.9/dist-packages (from mmpose==1.0.0) (4.7.0.72)\n", + "Requirement already satisfied: pillow in /usr/local/lib/python3.9/dist-packages (from mmpose==1.0.0) (8.4.0)\n", + "Requirement already satisfied: scipy in /usr/local/lib/python3.9/dist-packages (from mmpose==1.0.0) (1.10.1)\n", + "Requirement already satisfied: torchvision in /usr/local/lib/python3.9/dist-packages (from mmpose==1.0.0) (0.15.1+cu118)\n", + "Requirement already satisfied: xtcocotools>=1.12 in /usr/local/lib/python3.9/dist-packages (from mmpose==1.0.0) (1.13)\n", + "Requirement already satisfied: cython>=0.27.3 in /usr/local/lib/python3.9/dist-packages (from xtcocotools>=1.12->mmpose==1.0.0) (0.29.34)\n", + "Requirement already satisfied: setuptools>=18.0 in /usr/local/lib/python3.9/dist-packages (from xtcocotools>=1.12->mmpose==1.0.0) (67.6.1)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmpose==1.0.0) (1.0.7)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmpose==1.0.0) (0.11.0)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmpose==1.0.0) (2.8.2)\n", + "Requirement already satisfied: importlib-resources>=3.2.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmpose==1.0.0) (5.12.0)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmpose==1.0.0) (23.0)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmpose==1.0.0) (4.39.3)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmpose==1.0.0) (1.4.4)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->mmpose==1.0.0) (3.0.9)\n", + "Requirement already satisfied: six>=1.11.0 in /usr/local/lib/python3.9/dist-packages (from chumpy->mmpose==1.0.0) (1.16.0)\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.9/dist-packages (from torchvision->mmpose==1.0.0) (2.27.1)\n", + "Requirement already satisfied: torch==2.0.0 in /usr/local/lib/python3.9/dist-packages (from torchvision->mmpose==1.0.0) (2.0.0+cu118)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.9/dist-packages (from torch==2.0.0->torchvision->mmpose==1.0.0) (3.11.0)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.9/dist-packages (from torch==2.0.0->torchvision->mmpose==1.0.0) (3.1.2)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.9/dist-packages (from torch==2.0.0->torchvision->mmpose==1.0.0) (3.1)\n", + "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.9/dist-packages (from torch==2.0.0->torchvision->mmpose==1.0.0) (4.5.0)\n", + "Requirement already satisfied: triton==2.0.0 in /usr/local/lib/python3.9/dist-packages (from torch==2.0.0->torchvision->mmpose==1.0.0) (2.0.0)\n", + "Requirement already satisfied: sympy in /usr/local/lib/python3.9/dist-packages (from torch==2.0.0->torchvision->mmpose==1.0.0) (1.11.1)\n", + "Requirement already satisfied: cmake in /usr/local/lib/python3.9/dist-packages (from triton==2.0.0->torch==2.0.0->torchvision->mmpose==1.0.0) (3.25.2)\n", + "Requirement already satisfied: lit in /usr/local/lib/python3.9/dist-packages (from triton==2.0.0->torch==2.0.0->torchvision->mmpose==1.0.0) (16.0.1)\n", + "Requirement already satisfied: zipp>=3.1.0 in /usr/local/lib/python3.9/dist-packages (from importlib-resources>=3.2.0->matplotlib->mmpose==1.0.0) (3.15.0)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.9/dist-packages (from requests->torchvision->mmpose==1.0.0) (2022.12.7)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.9/dist-packages (from requests->torchvision->mmpose==1.0.0) (3.4)\n", + "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /usr/local/lib/python3.9/dist-packages (from requests->torchvision->mmpose==1.0.0) (1.26.15)\n", + "Requirement already satisfied: charset-normalizer~=2.0.0 in /usr/local/lib/python3.9/dist-packages (from requests->torchvision->mmpose==1.0.0) (2.0.12)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.9/dist-packages (from jinja2->torch==2.0.0->torchvision->mmpose==1.0.0) (2.1.2)\n", + "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.9/dist-packages (from sympy->torch==2.0.0->torchvision->mmpose==1.0.0) (1.3.0)\n", "Installing collected packages: mmpose\n", - " Value for scheme.platlib does not match. Please report this to \n", - " distutils: /usr/local/lib/python3.7/dist-packages\n", - " sysconfig: /usr/lib/python3.7/site-packages\n", - " Value for scheme.purelib does not match. Please report this to \n", - " distutils: /usr/local/lib/python3.7/dist-packages\n", - " sysconfig: /usr/lib/python3.7/site-packages\n", - " Value for scheme.headers does not match. Please report this to \n", - " distutils: /usr/local/include/python3.7/mmpose\n", - " sysconfig: /usr/include/python3.7m/mmpose\n", - " Value for scheme.scripts does not match. Please report this to \n", - " distutils: /usr/local/bin\n", - " sysconfig: /usr/bin\n", - " Value for scheme.data does not match. Please report this to \n", - " distutils: /usr/local\n", - " sysconfig: /usr\n", - " Additional context:\n", - " user = False\n", - " home = None\n", - " root = None\n", - " prefix = None\n", " Running setup.py develop for mmpose\n", - " Running command /usr/bin/python3 -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '\"'\"'/content/mmpose/setup.py'\"'\"'; __file__='\"'\"'/content/mmpose/setup.py'\"'\"';f = getattr(tokenize, '\"'\"'open'\"'\"', open)(__file__) if os.path.exists(__file__) else io.StringIO('\"'\"'from setuptools import setup; setup()'\"'\"');code = f.read().replace('\"'\"'\\r\\n'\"'\"', '\"'\"'\\n'\"'\"');f.close();exec(compile(code, __file__, '\"'\"'exec'\"'\"'))' develop --no-deps\n", + " Running command python setup.py develop\n", " running develop\n", + " /usr/local/lib/python3.9/dist-packages/setuptools/command/easy_install.py:144: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", + " /usr/local/lib/python3.9/dist-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.\n", + " warnings.warn(\n", " running egg_info\n", " creating mmpose.egg-info\n", " writing mmpose.egg-info/PKG-INFO\n", @@ -477,46 +546,23 @@ " writing requirements to mmpose.egg-info/requires.txt\n", " writing top-level names to mmpose.egg-info/top_level.txt\n", " writing manifest file 'mmpose.egg-info/SOURCES.txt'\n", + " reading manifest file 'mmpose.egg-info/SOURCES.txt'\n", " reading manifest template 'MANIFEST.in'\n", - " warning: no files found matching '*.yml' under directory 'mmpose/.mim/configs'\n", " adding license file 'LICENSE'\n", " writing manifest file 'mmpose.egg-info/SOURCES.txt'\n", " running build_ext\n", - " Creating /usr/local/lib/python3.7/dist-packages/mmpose.egg-link (link to .)\n", - " Adding mmpose 1.0.0b0 to easy-install.pth file\n", + " Creating /usr/local/lib/python3.9/dist-packages/mmpose.egg-link (link to .)\n", + " Adding mmpose 1.0.0 to easy-install.pth file\n", "\n", " Installed /content/mmpose\n", - "Value for scheme.platlib does not match. Please report this to \n", - "distutils: /usr/local/lib/python3.7/dist-packages\n", - "sysconfig: /usr/lib/python3.7/site-packages\n", - "Value for scheme.purelib does not match. Please report this to \n", - "distutils: /usr/local/lib/python3.7/dist-packages\n", - "sysconfig: /usr/lib/python3.7/site-packages\n", - "Value for scheme.headers does not match. Please report this to \n", - "distutils: /usr/local/include/python3.7/UNKNOWN\n", - "sysconfig: /usr/include/python3.7m/UNKNOWN\n", - "Value for scheme.scripts does not match. Please report this to \n", - "distutils: /usr/local/bin\n", - "sysconfig: /usr/bin\n", - "Value for scheme.data does not match. Please report this to \n", - "distutils: /usr/local\n", - "sysconfig: /usr\n", - "Additional context:\n", - "user = False\n", - "home = None\n", - "root = None\n", - "prefix = None\n", - "Successfully installed mmpose-1.0.0b0\n", - "Removed build tracker: '/tmp/pip-req-tracker-pdrld3yb'\n" + "Successfully installed mmpose-1.0.0\n" ] } ], "source": [ - "!git clone https://github.com/open-mmlab/mmpose.git -b 1.x\n", - "# \"-b 1.x\" means checkout to the `1.x` branch.\n", + "!git clone https://github.com/open-mmlab/mmpose.git\n", + "# The master branch is version 1.x \n", "%cd mmpose\n", - "# for better Colab compatibility, install xtcocotools from source", - "%pip install git+https://github.com/jin-s13/xtcocoapi", "%pip install -r requirements.txt\n", "%pip install -v -e .\n", "# \"-v\" means verbose, or more output\n", @@ -526,25 +572,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "Miy2zVRcw6kL", - "outputId": "7cd77092-31ab-49f6-a0bd-1749db488164" + "outputId": "1cbae5a0-249a-4cb2-980a-7db592c759da" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "torch version: 1.10.0+cu111 False\n", - "torchvision version: 0.11.0+cu111\n", - "mmpose version: 1.0.0b0\n", - "No CUDA runtime is found, using CUDA_HOME='/usr/local/cuda'\n", - "cuda version: 11.1\n", - "compiler information: GCC 7.3\n" + "torch version: 2.0.0+cu118 True\n", + "torchvision version: 0.15.1+cu118\n", + "mmpose version: 1.0.0\n", + "cuda version: 11.8\n", + "compiler information: GCC 9.3\n" ] } ], @@ -568,6 +613,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": { "id": "r2bf94XpyFnk" @@ -580,43 +626,48 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 7, "metadata": { "colab": { - "base_uri": "https://localhost:8080/", - "height": 643, - "referenced_widgets": [ - "13ac80b3ee9d4ce1bc1405a3d69c3c73", - "7abbd13654ff480183deb3d71dddf3e0", - "59c9f043983849e19df8cc2f4253b04a", - "990e4db4f7824bc994eff6ef91d4675b", - "d227d12439aa449cb267f393e43a1eff", - "21afdf2781cd45c3b541a769bfca494b", - "305bb5675d1a4a71ae47614db0c96b67", - "c06dc4651af24be3ba658102043658f9", - "7811af5efbc34360b06eb795ff9e7a6c", - "214f964729e140d5b8ab6ca5f342d416", - "6674d0f99ac94805840a1f7a216606c8" - ] + "base_uri": "https://localhost:8080/" }, "id": "JjTt4LZAx_lK", - "outputId": "5b1af791-bd17-44bc-c7ac-2e36fa18eb53" + "outputId": "485b62c4-226b-45fb-a864-99c2a029353c" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "http loads checkpoint from path: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth\n", - "http loads checkpoint from path: https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w32_coco_256x192-c78dce93_20200708.pth\n" + "Loads checkpoint by http backend from path: https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Downloading: \"https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth\" to /root/.cache/torch/hub/checkpoints/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loads checkpoint by http backend from path: https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w32_coco_256x192-c78dce93_20200708.pth\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "/home/PJLAB/jiangtao/Documents/git-clone/mmengine/mmengine/visualization/visualizer.py:170: UserWarning: `Visualizer` backend is not initialized because save_dir is None.\n", - " warnings.warn('`Visualizer` backend is not initialized '\n" + "Downloading: \"https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w32_coco_256x192-c78dce93_20200708.pth\" to /root/.cache/torch/hub/checkpoints/hrnet_w32_coco_256x192-c78dce93_20200708.pth\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "04/13 16:14:37 - mmengine - WARNING - `Visualizer` backend is not initialized because save_dir is None.\n" ] } ], @@ -683,7 +734,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 8, "metadata": { "id": "tsSM0NRPEG1Z" }, @@ -695,7 +746,9 @@ " \"\"\"Visualize predicted keypoints (and heatmaps) of one image.\"\"\"\n", "\n", " # predict bbox\n", - " init_default_scope(detector.cfg.get('default_scope', 'mmdet'))\n", + " scope = detector.cfg.get('default_scope', 'mmdet')\n", + " if scope is not None:\n", + " init_default_scope(scope)\n", " detect_result = inference_detector(detector, img_path)\n", " pred_instance = detect_result.pred_instances.cpu().numpy()\n", " bboxes = np.concatenate(\n", @@ -709,8 +762,7 @@ " data_samples = merge_data_samples(pose_results)\n", "\n", " # show the results\n", - " img = mmcv.imread(img_path)\n", - " img = mmcv.imconvert(img, 'bgr', 'rgb')\n", + " img = mmcv.imread(img_path, channel_order='rgb')\n", "\n", " visualizer.add_datasample(\n", " 'result',\n", @@ -722,34 +774,38 @@ " show=False,\n", " wait_time=show_interval,\n", " out_file=out_file,\n", - " kpt_score_thr=0.3)" + " kpt_thr=0.3)" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 9, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "ogj5h9x-HiMA", - "outputId": "3a32c96c-6ba4-41bf-c006-49152054bbf7" + "outputId": "71452169-c16a-4a61-b558-f7518fcefaa0" }, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "04/13 16:15:22 - mmengine - WARNING - The current default scope \"mmpose\" is not \"mmdet\", `init_default_scope` will force set the currentdefault scope to \"mmdet\".\n", + "04/13 16:15:29 - mmengine - WARNING - The current default scope \"mmdet\" is not \"mmpose\", `init_default_scope` will force set the currentdefault scope to \"mmpose\".\n" + ] + }, { "name": "stderr", "output_type": "stream", "text": [ - "/home/PJLAB/jiangtao/anaconda3/envs/pt19cu113/lib/python3.7/site-packages/mmdet/utils/setup_env.py:83: UserWarning: The current default scope \"mmpose\" is not \"mmdet\", `register_all_modules` will force the currentdefault scope to be \"mmdet\". If this is not expected, please set `init_default_scope=False`.\n", - " warnings.warn('The current default scope '\n", - "/home/PJLAB/jiangtao/Documents/git-clone/mmpose/mmpose/utils/setup_env.py:79: UserWarning: The current default scope \"mmdet\" is not \"mmpose\", `register_all_modules` will force the currentdefault scope to be \"mmpose\". If this is not expected, please set `init_default_scope=False`.\n", - " warnings.warn('The current default scope '\n", - "/home/PJLAB/jiangtao/Documents/git-clone/mmengine/mmengine/visualization/visualizer.py:632: UserWarning: Warning: The circle is out of bounds, the drawn circle may not be in the image\n", - " ' the drawn circle may not be in the image', UserWarning)\n", - "/home/PJLAB/jiangtao/Documents/git-clone/mmengine/mmengine/visualization/visualizer.py:709: UserWarning: Warning: The bbox is out of bounds, the drawn bbox may not be in the image\n", - " ' the drawn bbox may not be in the image', UserWarning)\n", - "/home/PJLAB/jiangtao/Documents/git-clone/mmengine/mmengine/visualization/visualizer.py:779: UserWarning: Warning: The polygon is out of bounds, the drawn polygon may not be in the image\n", - " ' the drawn polygon may not be in the image', UserWarning)\n" + "/usr/local/lib/python3.9/dist-packages/mmengine/visualization/visualizer.py:664: UserWarning: Warning: The circle is out of bounds, the drawn circle may not be in the image\n", + " warnings.warn(\n", + "/usr/local/lib/python3.9/dist-packages/mmengine/visualization/visualizer.py:741: UserWarning: Warning: The bbox is out of bounds, the drawn bbox may not be in the image\n", + " warnings.warn(\n", + "/usr/local/lib/python3.9/dist-packages/mmengine/visualization/visualizer.py:812: UserWarning: Warning: The polygon is out of bounds, the drawn polygon may not be in the image\n", + " warnings.warn(\n" ] } ], @@ -767,21 +823,21 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": { "colab": { "base_uri": "https://localhost:8080/", - "height": 954 + "height": 801 }, "id": "CEYxupWT3aJY", - "outputId": "9e131e02-453c-4a4c-fe83-731b28e3d8ef" + "outputId": "05acd979-25b1-4b18-8738-d6b9edc6bfe1" }, "outputs": [ { "data": { - "image/png": "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1hZZvNSGE6M6Wrxk0eWXXfe+971/0URxTJZGCS3E/NxovPmB+44/4czz/+6Cy75++Ve/9mkztVFLsXYu9ly841tn/H7rqDzz20fOjE0SHkEJAEl0ZEmIYA+7WAdmAIRwcDDZjBfmtm/attvyVc9/3nNfcfaLDjt89Zato5nZBdogZI01VEa2IHcuzLbI6cHEikWLL73k0+95z/mTU4sGgxLZalwXajTDCaKhKGJi0fTSFctWLF4xnPJmatkLnvXUmZuv//013z34mGffuDO/8fSL6tN3No8eHrj38Y896pQfffMzM9vXLVq255Of+oK1d9x4923XLZosex5y0lNPef7yFcu2bdn6jc/905atd77l3Pf9yVOesnXD3fsfePC2nTP/cfFnn3Lik7ds3nbhhRf+539+/rgTnrpzdsGbEhFZA0CM24homsbdMxOAinUoRNZSSobQMSJFMiGSBkbPhDKckITIDkl3hxvJiDZ7AEi6O0lJmchM7iIAESGJbsUcMACRC6UUVN6x5fZzf/yKfz75M/ss36dwaY4wGNT5HPO2BxYA1HELYOBF0jiqdYpTMIFkEqKhR2XHzABkprublVprKN2dJJBIATBBErwgEkiSMgJgirKwdPfokUTP3U2ICLgBaNsWMHdHx0QhMxFpZjLCSIKiJAAkMxORAMxMkpklIQIpRBJw2rxTWYelkRRtNTO6AfDIFDpVKcnMSileLEOddmHk7qUUSfCSmYVIAo1HhIMU1EPPwY4eZqQb2pARgCQHJVVlQg2MJAD2lCmJZBrH43Fj3hmNRhExGAzgJglAZhZaZrq7JACZyUExkKkwKJKRrfKumbXnXf3Kfzzp0wctO5SkAHWMokXOIX3J1PSNt1x36X+851lnPuv6q9cddeifDxc/eP755x9z9Amj2BZaeODuTY87+uidO+au+/GPSsOZLfa6c47eMbf+C5/cvM9By373q1vOesWRhz9e733D3YuXTJz5jBOvufaKV7zsVeef//51G+fp45gbcGDJ1gUHa9LMSOIRmSmJqewFNBwOYQQgCcqBNQAyczwel1JklGRm7p49kgAiQlKhAahKkt4U9dwdKTOT1LZhZpmVPUS6O8nMDAhGGQEMkpLYg5uk6NEtM5Fy91IKyYhQDRnd3QRJmQnAzGqt0xOjM55++k133of5kedouHTpZDMoY58fLMx8ZbNt4eK/WrOolPs373zOs0763Kc/v3bjfNM0EiUZBCDGIYmFmWlm7h4R2VYza5pmIVoD8UdKKZJC2TRNOxqTdHdJiGwzMrNpGhNYPKEOHyYUWpsBQESHZGY2XgDUrGZOgcmIaNsRyWZQYJ6ZTJGUdPu2W8695pUXnHDJgUsPbcwB3LrlpvOuOfuCEy85ePnhANxdEkkYa62Z6bROZgJIiA8TOpIsFZlJwGgdMDNNCIgkABPYkxGA2goSQEAdM3NQHWNmmlBKiQhrSkIR0cBIyhjKDouTrLUOzCTVWgGUUpjKTDOLmmZGoG3bUorTSGZmOAEUWgeApIAA0KC0yHHDCZW5zZt2XvyJH1z+vS+UHA3LlLANmN4xp912XwGbr7OLXvi/z/rlz371k5/+YOXK3UbtAqmprN8881fLh+0Z3z5qw8xASPXQMxEABdIFBARjpyArEBCABkbSGkPxzfdtnxj4WWc96+zXvOiwww7asGnH9pl2anrag6RqtCZAJD2idfeJitk6F0Vr9ll9+Td+9K63vUM7ZobQ4n332O+Ag2jNwkJdumT5xNTksScev2avPe648/6oM/eufeCQA9dsuv3nN131xT0fdcTSI0/43h2//eUlX/bP+t6fOuUxRz7txz/43MLMrZxYcsopr7n55p+vv/WK6Wa416GnnXDmi1euXL5j684fXv7vN97wo+ef9brTz3zmVFnYf9/DfvOHW2767R9e/6ZXDwYTL3jBC952znmnnX7yztlxRFhxRUqKiEJz97bn7jZs3J1E1GpmAjsRYaCIh5FECpEAktZBZERgl5TRzJgyMxkBqIddDDAzRISZuTOUJDOTiIWZdmJiAopiFsm1s7efc9XL/umkzx649MgosyhNu+BTNN50zwyAxouZZaakUI5qO2WNmVUlSTOTBCMARZoZjB1JSAFwUOaSQplM6wieMLJ1jwhnRxQkZWahQQKZRCglcRenAIaZKRFKkgZKNCEsFOowhZ6ZwS2UAEiWUiKijlvrpcLdCZNE0swk1VqtmAQKpJMEkqlUZEhGSWZGMiJImplqACBpZkmoQ3Q8IaOIjtMAJBSQg0iZQBIASUlJhFDMpZDEnoO1VpJwSygTCThlZhRE1RqSSCqy1mpCKaUpxd3HbTsejycnJ5OQRDd02gBgZlXZUY1s67oda9/589d85LhL9pk+oJRC0s2cFonwUdMMY3bHtT/58B3rb/z5tZv+6q1P+Myl61/0vPMXL28/dfElRx/5xO3btlx22def87znfv6znzniyMc+uHHdrTfft/9+q9514aPf/obv13bxROy226Pm3/r+Y171/O/93Qfee+996/bce89zznvvrffsmBxOmDCO6u5WHCkTZIyIzCSduyghADlqO+6emQBYvGkaACJIuruBmYlIAJkJN5ImgGKvpiKCnZSbsZdSm+FNQYokAEmZiUck1KEAo4wdEyggg2SaBUSy0ChISmTWLDQAtVbrNAVU1mHV5oky1UYpTbStj3N+8aIl2x9c988X/+UTn7zqlt9v/8V1D/zsmluNU8uX7+YD33jD+snPLhl+aLDbbisfenDbq1//kg/9/d/fvH528cQUocwELQmmANRarSkAEsrMiEpgMBgQlj30JLFnZgCElATRzEhmpmpIQuMkMxNAMZeEyOIut8ykweiZCcDhJMcxNrPMpJsiATDl3lRVE8wsM2utd+64/dxrz/7IUy/aa+mBTTMwcN3228696hX/cPwlhyw/vNZWTSFpgjk7o7ZmZilFEgBJ6JkZSQAJRVuZGg6azIxImqHjJokpAAF12HEDoEh2Uuxlh+iQBECy1mo9d0+IJIDMRIqPqBnujpQJkjJzHNXM3B0ASQCj0cicpRSSKQNghlorlBNlCCAJSQtlbHWwuFozWf/+/3x/7W1a2HbD7//7R4PFDamF7f74xz/+jee+sdbJzZvun146XLd2/S9/9suf//znylHx9lMn/PZJq3ec+b1jbts2nbWllEAmRJiVmtkkSAbCmYFI0K0gWYecqt4CKM1i+sadm9qZnU/7s+POecNbj37SEds3tVvGWwd1MMF2wQw+BJxwuBWE2tadY2nULizMjQaynGx8245ff+o/ePcdi+dnl73sReWoR9+yfuP6m+8t1syP5rbPbomdO3bsbMej7aUM/uJ/PX/jjdfc8eOvLF487Uv3vQ/7fmbfixf+Zsua0w56/KoX3PCrqx66+zdTSx71tGe85L9/+8v7b/llGcSaA4552ikvXLPv/tu2z3z321+644ZvPv/PX/rYxxy7z34rDzr0yGuvvX7d+jv23mO/P/zhd6c9/fQTTz2pRicHpclMUdiFFCSZkBFt26I0JN09s7p7ZgIgicgkvCkks4aD7i4JSZpqBMnMHEclmYky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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAMQCAIAAAA4vkODAAEAAElEQVR4nGT9TcitW7ctBrXW+3ie+b5r7/2dv3s9Cf6gci8oJqIBTSCgFgLWBAuCBAtBJDGKBUGwYkGwFhAJRANqzUKCJBVBJQoWggkxSAzGGDT+BGIM995zzve313rnfMborVno43nXPnGx+djs713znfOZY/Sf1ltrnf+D/+k/TRw2hYgEacoACAFAEOh/AwBQiZREIzOBKElUDHKWiSUAkZkjULZRRxzXdZEkKQlAcGSEbAC2l/fLS+j/QjLh/nnbBds8gnPOzByPsdZaS8zIzLxmZhbcL26CBiBj9N8FAkAYQEjiMEn8//2ZS0EmaDsikABQVUccdhEAWaDs/jHismkEmWRCZVQYzzDsZESEiaqyfeQYVSJsgkRGf9IwSPp+FP3GGAZAR/9f/bn6/5L0NA9mWpdLRJYJVXKYERFkZl7XM48hKTMDadtARAAwimQEMo8jR2YOYozxeDtHHg5+fukAAkk6QQCfX9M+CPczvL8vijDhfiiG+pUM3n9hWZIMSULJuv9u/4kA6YT7x4EEA7FgAP29fP5e2+J+dH1c+z9+vr1l9fc4GABUy2C/pbIA0EDJ0qRdotxHsaokVZXNqmmbGbarCkAyzFhrLYkZJCFTRB+REkmGcb8lynGMpYoIRFTV4LD0/v5e16tgwcwMoKrgEBFQZpJ8PackoyLCNjNd9ThOSWTKhj0YLyyS0PrFV5NwAIgIUSHaxURE2IyIzCRNh+05Z0Q8Ho/ruj4+PoAwolARkXRmRoTWjIgVIaEfBckxoqqqisYYo7+XIw5JY4w159sxrut6rRdzxHgzUFXl9cZ9IDsmOCiUiVFjzlcOAlprRYyRp01jRkSHgjyO8zwhvT6eC6QcEV/e3799+wZgrpWZkSDZT6CvDFwkVwByIscYQUrqm6UOVAAcn3EhIqTVTz5GSiKyqqLjY/+5j2Lsy8IFH3EEOS3bA76gY7kYDiYIkbLTRWRmHzAANs/zzWuSJKBCRETEaz5zMDggTqzMJHOt/V0nrKoIyCSgESmICAMZYFrriFSH6AisSvCiOxJGjIiwSxIggZlZdZ830qXzPK/1conM4zgEV1UEXOqzFIGIfRKAGIzV8bcwMvfrrCKZSUsdKCYNMkjXsk0mEBmHjXLZFSOllWBatlfARDrDKNTb8fanf/qn/8a/8W+MMRwkWdaPb4/n85mZ11JmQisi+liutfrYV5VWRQySJTloCgg6woDLLvAgLangPnhLlcmhALk+Dy40Aq5VDP4iNNVyB7rM/PxfAI/HY72ux3m+6spMTXVsH1VlIfMolYExYlmZGQwA5f5liJ2FWcsMkKwqwyJASDoMAQEQDINGAAD7O/iMmxFhVJXvfIDBILnWkvo/igIiCAUNIjkKLimOwcCc01VH5sijqmbEtHdU7axAReRwSMo7tQGwC6BgAiQtguL3oN1xX5kha63VuUHV554FA+b9WkrKtEGAFJIwBR2ijSRdIpnMVQsuRZDsJ0b3TaeDAZMEO6LKtnWnlv6uIzpgdcggMiiUVOvxwxeioCVi8ChNR7xer8xYa53naXtxgiDSYSBQgfsGiiLtSAAwRcCOJEEEgWBXYtgZvB/lfu++c2EiQRn9HffPkSi6n23n/k5MZdUqr+pT11/ZjmbHQUCfLwuIgOwAvZPrL+umBGF85lyS7sRsR0Qw+q8oHCIZABIo+LPiIbnfNO+DA+6Ya6wdBdSpt49rCUiaHOAQSRZQCURw2bkLD8G2AxT8Wj7GGJGU0xpnCpi4GCSJrrr8/bmutdZamdm/dNUieRzHkvrmIwhakquLHdi/eBD9Xf6lQ61MgrYdkXCogGQSJZkQ/JrXqmX0Q6skR2RVLa+OsZmJ8loLiEAEiCWXAmRGRvR7lrSsDBbxWpMZ53hfwn6GZMaYFggaSRGkMAzbgoMMEBGZKbBguc6RVQU5Mqrq559/Zh+KvofwnC9pkTzO7GQAwNIuZ0mAEUF3ZEBX0Z3Rw9DdX+Qdoz7jVT9KSXC4K0My45AkyxB3EeFdPfPO+vi84UBGEEXKiDACkh2uQkQcxwFpTQ2iIkBB7LjP8EhG1+PB4QiwvDuTiFgqEzSDLCKWVvJAKIBVyB2rGIZBW7aiGyF39P9lK9IhHehYFWk+3t6fz+c4h2CUvCy4T+yOs7bE8pJkIWEkhrCqRgTp13xFBDM6vhCIiMgol2yhDB8RMG2s6xpjZIAMQUGyDHb0sCxJwZGUUf/6/+P/9sMPP9g2HJFVijG6xg0TqyKSqzJzWUfujFtVOdKMudYR6SAibUP3TQTlIkMMuPrJBEhHRJQUkZ83TdIxxnUVum6NPm9Ik5mJHV8+Q1zBC6attYjo2D4yjyXleWjOCIwxul5YNTtukuzskAyAJiNjt7MiCUslhYQcgBkmtMN37JJqJ+xuLh2lAgoA7K5HAISVoGnv43v3TuHso2OtVQE8Hg9J1XVNpCQKRgAMmhwZeSRr7WsmdW3Qp0skibT1ywRMRrg7F4EeOfpOFgvIjpKAOjvB7Kwlgx1HyM7FyxoMkFXFked5dDiAQ/33dzsOkoiwrojoDLHW+mzjOr7EXW1//vczmMIzsYw/RC6sZ5I20ufxUNVxHNf1PMeRmWOMr9dXmODGBhwkTEPCrosBMm2utRhgDHLnvP6VC+oE3FnC+ksRCuxEaGrfTO5wFl2ZATAMu7RUC6WqWnO3Hfcb4ISCcXgnRBEG12CUgV3X+xc5mJ2UP2Nf/y1bhO5mPSIIOqANK6BvGD7vEBlBdQfxiwTMzPrM+vf9AYKE5koyxvAul5wRGXmFbOMOarYd9B3ByxhEMuZ8VdjC6YMR/WFhB4hw2Hkc6G8ey3ZwWLxeK89khGAASxKMsCwqGdY+3gBQdt5VHfYtDdgwmLRRVYmcLNuZ2X1wVQEUMcDPaq8zAcA5MS3tTiHKhmAG6ccYx3FUlcVIwlhrmbgsGCjbDEf2/XIpAkBAvmESA7SDGuOYml7OcfSROh5nWOw0SUYX0WRw2AtkZn68nhEB8jzP7s7JbgMbSYI3OnJjJxJUnZxEZKRtIuMGnEqiNDLKKhNwQqrqX9evHxEds3crTErsQ+m7orMAxIISHNIqrxERMDxAR9jlqsx8PI6IACVRdiaWis6+HV13HyoDqkIOysGGEx1Iygo+8ryGMGtZRz9fqO4bsy+v7wC480J1IiVDwMhRVQxGRM31er3qmuN4B+rzvnc7ZldZwR1gbUREgxwimDGr/Frvb+daUikiFm3giXXqGApokbEsDpcuIBgeR9hVsGv1SexrF6AVAEQNDhV+/PHH67qO4xikgWT89re/zczBgYSlM4cakGNGkBkuZBwCug5YdNBhpojlBvAq6VJH8jAo3+coZBf8i2ILADIPaUYEMmD00wAwGCGf45DkSNt1zQTrmvtNBRIsYthGRtUEZHutC4BXBZXMajjRlsAQICBdElHuRJ/koOt6vgjrsxchboRVuOHBz/+1PUsjQtb+ABTDDMOUJDrIqi5AILk0397e3s7zui7INBDdic8EOoEFYaOrshk3KL1jk5AkGLUfHsmNKWqXJyQtVYkZx3FI0hT3tYRBMKAiTBNiGMMgaBq2YAEx0iQYMgEva0G2BiFANskw4zNVObxhoxvbcARjWf3kP59bZ5S1rnXke4xT+u36ds3rPcbI7OQ9xjCQ47zW6y1i1kUnACKgfWhImkDnS7lQkuacDo8jJYEcDPh+d7AhrrIt3rewH/6dKhtq3u/zF0WGmdKSBNqrNBfkWpoqbQh6PXwE4UlkOkcECISpPU244fedNh13+uxaDfunULAJuKM0BiMZDpaFoHT34584dkDy92BqD6HoMCox1JeC0fenykREpKDucYMAs1HopT03ANnnJBrG1OMMyLYcZES9auQhwtqNb1VtCMswMKsiQqpuascY3VbiqojolrQskmMM2576ZX0GAEwRCcBBywzJgAPUKgQZkJcciejOGA7Y/WwZDvb1iv7tQVdVQCNGRNYyjH4slF9zfv34eDvPt8fbx8fHGAz69XoNDgC6s5qgDIw9vukjScV9FIN5N6SfgZ5UhDT3odOqGPnl7U2FNWdwdLVRtu2wr9eyFGOnlx4EeMcbExF5tyMw6J4zyR00DTbi09gEATIzTFVJNcYwJa/Sfqfgbiv7YLjcFUIZjAgxjEDU3VTbC7IZFBnRjehaS6sakXo8jscxPtbLJBKRoC2hutkCqqYYw4oRtpMuks5yUdThAJcEFMewTKIR487i7CoBAZj0rlplI8hIrjPHt7W6uRJDS48vP3x7vbpMzLv/ikwBWDuYASZ3nFzWdJ6PYQOux+M9cX18+4bwI2MaVWslGGnYRAVSUaqkxxgRsdZyFchRLlhEqKOlOkdKqKrMJJJI0pZGxPH+3ul6MNbS19eTZA4WvWoPqmK3/zoy+8ZGDynU0UNLlbFvHgCjusOGY7Ef4AIQ7g/rF69xHq7GyditZsNma2CM0EIfpVXKIyQdzgjanhaAsYTzPK7rymR//sfj3ctE0aLCHU5d1aiFQdoZiGS3yHKpGAMRpJhhWUBZ4Q1PfbYpVTWro2Cp58xVn31qp+uybQo3iEnYfjvPdV3Mkdy4/MhzWeORFr3WWuqwC6AISPvghyWVTdF2uBGPuwy8y8PI7AY4YtiYswBkBNCjLyBAd+onEdMFOMlIkyx7wWWfFVZxjGHC4DQvP/JQlhtptsDo1AHFOc6qqnXf/Ybw3Zg07lhwd2MRGfHUeobjzDHLY2AMzXq8vVXVx8fHBlFzT9zTA9jNCkkEBJMKZl9L2423I5EjJCXD4UCYHSe5bKg+A71ig2AkExnoG7KzIGCSUd2pQAiguu8MeC2pai0tle2AE8xgCjjhyOI+VNlzY2485HPArB6zYp+oDvHYPR4MZOQe/Uolm3CQ96yad0/Q0+XoarcHvSSquodNcIyj75IsjmFTwgwcmQejh8Tdc1d6zABUTQoIQtizg/nKzAXPpTEGgo/Ho+aaAPbouRpTJQ0pj2NdJentOCVVWXKOI1QjsysGqOQoQ1I2APaXEjDINNmQmGOUZuPc0hwcMdIWCobrqu4agw1vJmrGebiHFNJa63GeY6Qwq5aWg2PHbZsZe5zMXGtJOjDWNd+Pc9S41gsWxsEzZU+9Lpd4hJFwx+2uPBI0sVTMSLAs2KJez+fgaDymx6JEwktSxiF4zpXHyeZSyGOMpdmA82eX109FvsOVPkkn7pti0XB9omUZEYw4Vq1SHceBFXapihml2kCPwz0/7oq2rwYQUCBJWiBxGAtQkuM4EJi6VJlpK6KLM0fs3vr5fJIgnZnHkT3ZT1ByjlQRQDJH5no9DZDSXE4O4Vkzy0oPx9QMnUiUVw+EBUSDdd+HSiC7IcQmBFzPMcasFV2Bk9+uuTt+Ut3fkkSWNnYFbG5B1QSQmaHhlxop/fWvf52ZyFh20CMilGYUMeW0wzGLY3yxVMZ6VcQhZDCIJ0ABssaGqFBe6fcxMiJcWlfl6CCF67oA2LwQY4w4Hzl4XZfoJKWifOY4xtgkp1UiFiGAQYDBOImFItDR0jKBCFooaCQhjEBmSILTQqPlmX3UioxIMGLBLo2glgaDwTCRQ8uROeesLvozU3MdkZZhjAitKxlCSDiDy1paPToccfiTdLNkT2cygpbNel2PtwO1MUr3AOlCxlh0ScFh7VEclERqzjGGvGj88R/+0a9//WvH23GMta4jshw2B6mh8AHLnZISYRIY5YhRRFkI01hG/5aR3TIljSjTMNMEowQLThquYIzz/eNVmDOPyDz7awaJ4Kx6c5gWa5e9wGIV64sPgaJQyIwBYFlT16hjDNmEUGIgTyzPUKYjeJAu1DiGqoiUVKFADeeVhIK1VqzqQ0EkczBUs6ooWevBUU+U7YwMSgLxWhWBH/7gfV71ek3ymLa0RmgXStrjZyNczIPXmog4k2tdxxgHD0whRiVWOLyGiYIo2IsLQq3v6G5kjkweYWB2sseNwu2egwQHXNIqzTmrtKBLVbpsOBjHMSVcM3/IcmHWgYiM7kgiWatQ/UUSYJ/aCqaycIePAAkJlg8ShiwCQfYwuGb1VFXdiXaPrg0GmFFAlUbEDcy54dvxGPP1dESQWs5Era5jOmP1Ve2ZSXM64rKTIMcSzOMNOaWyMx8WAvl6TdtwKSMALoPQ6CrHVA4oyNH0IU+AaS4CVV1OZhyQvCplHY9rzhz5mX+j6Q5lZbosPCMG3WyMsL2uslkBUKDGmZn89vNHZkrl0RwcgcsZj8chLa9akTjPsWRbVQdi9iSDfBxv15qzLhKCx/GAXWM2giMUVg3GYLqAOAiUJs1M5jG0KhyXZnO+Xq/XMR6lCg9JlQoHnaC1qnwxR45RegI4g+zqWD0tlSIl/+FPv/r28bNKCHqHywv5KJXlZKwljDC5Lh1HSipN2yOSoFYtIIAMhKawJqBMMd5naXBSmcnJN7CMuSYiwpItjlh+PMbi0utSjlwAQ+ml15fHkXi8Ss1OzcGIQwKNvo52uYLic0GkULTO8OtK5CA5C7OUxyNUqqs4oSiOKDMRYFk913MfmHv8ikIAA6wG6EkTiqJhqhq9sSELO5siVt9sGiaDBLk0YbKphUDtTiEbRkhMwTwOA1ZWc7vWmhoeQzltofQWKSnSCquuX/3qx+fzW1VJYCkVL6ZtWEApk0zM9RhHxYtkiQvrOI61h+Jgxk08cs2roUTIZxzcvZiCLGmthYyDh2FAY0SjdBkBMfOhNQMLEVIUOExjZoOIwBKWKtwXjYk9k3B3zPYmlb5sQrWw+UOgzAiEJV2uyAPy+AR8dlW4y2mLgOVq6qoan5G16OgvIhqCEqqnX24y5JzT5OPxaPyKB1EImeDKbmLyNJuKs5sw+Kdf/epas3GVLlHnnBEDtZgnjPImJTYvNHq+SECLzRhCZAZKU3OtCxxA7BOZlCi64DfRHTObGdAjK8MjVgA9a7SxKiLGHfFvKBgBCBiNI3eHnbBrTUXmr371/vV17ZY6zjwIoFSG70Fjj2ZULEkRkMCDmYmmavkmSJNdIFdNMQE7WPA7j8s14chIi4UinKPRheu1+bqf3f3I0yg1wMhgRle7aylsVE3XHPkWOYAhuLTpBH08pamaKJa8qttg5Bjew7ao6qTVXSlw96bRHZ1AC96vs+a1pkv9f5d0XVcYyOGPV+TQI4BsdKJuxsfnEf3sZrj5VXfO8fef+cxDe/LXtUDsvkdEswvvDqBxX5BMbhKs2NV9M6KRDKNBVGdmOvfci+yQ1L+hoqfhCa9+MActsFn0VQtQxEg6GQXpcSaDxvJyFafTEHPVHCTBpVruuAJJQbIvXoTJst08OdcxNvPo7oAdmUxGYFJ9xXjz7dfa3C3W5qaSJDMfp9loYglOsJkBFvfnlhruL4q5AQlZMUHwQCCjrGkFV2REj21zNHdgubCUme6KUBTwcmWBwEi7uCRrNmqVpMoRuAJnjlo+SFU1HaxKzgRVDu9pfVGOwKngGL/7+ruyImIALJ2g8v16LQBHjC9fvnz9+rVKJjTwURMUk+f5mHPCFn0M+Fq8VIk8YjDL4LJyx1NJAVyuYBJMRlWhySEZr2sZ5RHkUuCToEMeNIO+6uUgM12NiqUpq0OMbYDOzMGwK6BUQIKj56xwtNggRhIJRIfq72f7cxYt32UxCFQQnzTQ7vB+IcH4/Jf7KoWpLmSbR2LA9f3HWm6AMIOwy06GqrwW7wE2jQBVL6R7Pol7CGghB9e1ro9nzeLIiGFXyUbdgXS/Tsf/4zwy8/m8MrPpSv1SsT5pdxlhERWNV0/e9N6eVeYgImstByMgrTnnGKfANa/Tw6VjJMfxtS6ACs5V2eX6L5l6EWHMnlRb3MMsNCd8IVMIUnYRMhEYJQcOxMWY1jtzfMdh0VPCsEsd6+yCJSx/j8mRGCNIavkT77Y9OHxLFIKcc35CQFJJ+ys1EMZgODDnOh/ndV1wPD+uqspx7kqhT2DnPYrfE7BQHfeozVcUI0fEKq+ppN/OwPvb+iiwuxy4R0tyEAXSYUtyIgS43PB9H3ztt/0dU6pPxAYENECSVVNoKULkJn0047FImtZdzPRLRsJqHIhjjBxcS5ZLffdgAZbpIJMDQLDDFBpiVZM+2Z1hBJ2OI6jIS05Dhqt2QthslU48NCQCMCW79swgEGAuHnCGXlyvjC9FBxOJO7VIgr3W8uxRR1hTmcAi4IqIuEmiG9NusmXnhOYvLtXSpj7PWraX9okYEQ5SRqJ/EWFmZIb4HdzeabJLwx7D91X+JNi7aTrfc/b9IExspty/g7QVEajawHVm64hkxUhWJwKAWtB5nqwFYEQu1SeVw3aSBmZYAonzPANwrRIgLQpgbsnGzV8zairRUFcUnfICJhw1HVmAvFHT/iytGGnyqDbmHEemvAKI/P6UINCIjKVyBrRsEdk/UoabPtMKQwvX2u/qRl2ahEESzJ6/ZByB1+a6E43rNydWSWjZPjKTQTvKWbqIJsDMWbaacQOw2TctINslKaP20MWSMtMuMsGK4CkkrDUX6UABSiPiTbY2Wa8jwSAy+PRMoCkwVWWrYVUILbypeX379q1qMuM8Dq1VcMaIiDMPvyZpIzzLQWWewUeEzWdVAZO2PZiWkSFpjBEYLAhIRo+sZzeITVpnf9jR0zPs0RruHLZGjJ2WwmVmh4vPuQ+qgFcojOgRWkdFIcEK2eqLBrjPpITsuObN/M/PyQuLzVzpedxWqzSyFZ8p/H4dYWsl9p35JPLUJmpaTS/4rGjV9AgBMWJXqyTtymTzFNdakzwiAZSqW2SIqNYGNj+mof7M7C7R53HYXrU+i4zPO263GqwnjB2YGUg4lxegDAJcuutU10vXGcceXI4zItZSHOcL4hgvmNdq8B+qB1Ox73vz2yzYtcCSPhme++mJQVbCSwfgTsBwICUv4BEcY6y5KI0eQ+Hm2kWETIodqgcH2RetZSyEfLTGQ777BsnOW7NxnieA67pa4OmS4BUOZBpDELDCLcySVGZmfFyvPo5jB0ocmVWLwapdcX1GGNvYVAlGjB7eEGAC0lpimUzfIloXOrIYTUbZCpuO+3Yx8nB01UmCEYpoisRgBOAtj9kALJtnEVySJMSw+PKcP9eBMc5DxFrLGNgoCsHrTsbOQbu7eR096vsUs0oFIbr9XeEgQ03BtoN8qo7IYdngoDNcHCLCmwKA1efaGUBUFTIiRsuqYQdA8hAQWZSIIKKKE+GcIw7FPeDpm25LteSqKhdWt+kiJLmKsu4s2IPD3RPfiO6s1fpaAGupqk8OWjbQg8aIcXzS0FqK3JoifAdXQXO3GLvBZQBsOlY/wGjSHzeTG1rWXZx+Pzy4SW9d38V+t94KeI4xhG62ZJtVMcZWpEQN0CM2iW2u7qPfz8fHa+6UL2nJBDLXupgxInkXNIZpPGJ0hRcgxxCqW963QFnRVRajtMLIgLQGgxEiijsH65PsVt9V2u/nYwuaAcGDuXnoCDRZhjRZ1hiBLfnDiOyXqPsrUCuc9sRwAx6bQx++3zxyT4vNgR6lO1xEgqEBVVhkitjEvVLXq5HJ/EQjmuDHjIRRILV/4wKXVo5M8O39/Pj46P5z2ebGPxEk0ThrF2jneQ7GMl5rxkiraETAbo6bfnh7/7heuluo5iFW1VrrOI5IvKpOHiFD+jhUksQD42rNg8wmGVhrrWw9X8umVb61TFJTG4qIgmBXzYJFkwddTZHoSGgULMTRDbO0bBnugJ7oiqyrQohRhDwCO7AAaPCzIb1Pofy+mNFcnt1KEk26v98nszP0hum0Extu5OlOorZNMDmaD0iqqZB9ICJCrIwU7Jvh2AF8jFFV17X6fUagUNd1jTHOcVjKDN1QE29s6TPF3seP8znX0hG51hqt1yIFm0lSukmaIqWQ80iATaqdc/YnCmCMMcaoOSGP5K6XxSAHh2quWhzZStYYQ9fsYIjsLImCpWo8gVsMQskRZMRBFCSzG4CM+DwbZSU5CKfHJyXBNj7DqPtzRDNLt6QpSNKqOWcn4J6rdUunlpbfPOwWBqy10mjorGl3EQQh+5qz1QvHcbSIcH/lFBzBQeQnuY7A2IoIkFy1eXeSZkU1prnJftWs9wo0+RMAPyVamyvRUAoAuoMvzbJjd722m6FdMrKVvg2dRKtY7KUKjtRGQzHyYJMh59OyYfYHpYmyjK3shI0mPbHVYp9HHDdqC1BeaDhaJNOoUtibIs1ddmWenb1GPEB1/xccGKuzu81lhz4pxAg4MiN4dRlRIjkTBZyFR44KDO56q3X3DShV/5s2yGwihFB4zsZRPtvlX17X/o76VVzdC7emc9huAhWMDC7VVB0SpQw0fY83D5y/KL/2cQ3aELS/ndigTd43tsWy8z6QfdK6qQ0GY4M3mUm7uL9iNtoWjDZRKRzHEREdzjIzhUWCLG7F9takytnUpMaEYGzWRXJDP/1PIBgIDZTt0gAprMBhHCbbLmBPs9qIZjcvcUvJewa972AcETF1fT6Z83xDrbqu83F+e34wyVZNe/Pj+tVO4IyxtJixpCI8oqoCsVF5lADS0VP1rmhvsjlkGL4JH31/N++Pg2GUQK9SBkhpKQhQREbkYIgyoHtg0tVt5rHWClPyGNnz2m47+mu2yJY/MlvKSBKgm5C8POAxhshvWnEEOdZaBwMHZpXt8zzaR8i2Zdxy3vM8Y0dJrbUephMXbeuhQeFlvULRNdOnSvvuGgVHtMASXjUyLTfxwjbRSOTGbDnCs0wFGtstoLO1TK+mj3Qhzui4zCNZ2sBIUxRJgHPLfAlwRPSQQoXILbyEm/m5uaJt2xF3BKxWJsY2XrpPxy+yL7Z+CXtA102ksqkXbCWLGufbuYhEqWqrHGMfj7J5nid3lqmIOB/RTamkTAYAdseykbOm+nfRcF1XRIxxrl+UTf19RWaWI9idksllLKuoYfKWSwEgkqAFlVetBqFRyuBPP/7069/+9oijSsFxHFHwTpyrIiJBwfsb9mahjtvDgaR6yAACiCWRCsIY3h5MFXlYLyiFB0JHjsL9XWagowxamLiZNXa76NywXsal6uzb7amJMbI9RXxTan2P3xYixdEUaEJByqEis5pCVRUtdpKPMdQUx8ypamZZZnbH2Q0kyFqzr8rO2AwmjNVPYYzxON8/1pPYJV4KgexjtGBgD1+14xEBvYhge0oYq1qCdyJ2f7cJt+ixM4UjPyVlG9gMdHl4rALAVlQDDEdmijPiU2L/fZw56zp5IHNZVLGxkka9Y48fP5s7QGE6WQaEo5RGkRpgNRUFjC3uFFAGyjegSJJsZxygkHClmUSUw/aBye8JzJ8X0aZR5dpTpjIIqIhidP326VSl27zsiOzZxGdi3nY5QRSqqicIhkHCJWaXqLaNJNljTKsc3Pohg/EpcOpGiD0ZuG/1rkLW1nO2mHZ/GrXMF+gavMvzu+FuBRxJZsSmvTM1duUW9nDajkFWLYtumvuWQc+5iAiO22ssilirIiMMqJoO2s42hmOtjr7RI7p2aUIYaM1FqRx3424w2MJildgQn2mgfZHOVg8DAD6u15yTEc/nM/aAan81jMYeqHJkIFhWaF/bbLMiZ8PPn0VhN5UlYcTBQbWllTkix3l5NowZau5ssYRLSr+9veW2nNI4MMZ4zYlxFPbkJxgVXVWjnXMoU46xTZTWWiOTEdf1BPD7+TOyP0OMRX/K+ZqvzwVrBYhKHuc4Xq9XRMy1jky46GJGu3d9nZPc7PcuEW03HtP6q1pO4DTFUUllEMpqNKUTK7KVJx2ZbFcBOHN08+4tGL1ad2gVeLi6OwxiJbdq5bpW5C0c8wb65SaOZNgJngWpsYwotjmUVXU6cNe7WqVoD7itgm3U674dTXxs2Ci3Ag1tEyBZvyjU9Nlz3pXpPl005LLDwX5gHYCH2seNXUnYHplocw8qxtDKtW7iSAMfNbUW8/3uAfsdiigA8h7u+jucsCy6mWiqiGhvxO7QSurpCe+f1vY2I0qrDfgcmVsXd0RfGXUV4lJfpZWSDQUR4QqYVS4dx6NrtYaX8Ik3PF8NxhqI1kTABGLOPHNtranDWFXOyMyisVrd7kFS9xwev+wzZJS6z+jaU2hLoOESAtFsFrI2iMSq8v35fUOdUgOJewhXUEAJHMf58fGRmV51HIe9fb/A5poRCKFuHU5AoKMHBCIMQxqZBm/94MguVta65vMRWSix3ym69q8NBCGRQtVyjBG4ay5bsQ/btIJUbKJtxyKhSedBelm1KjKPMWiRiEC5PPaJiQNeMwIBjoOv6ap7vvILwLa7BWVAdtmqYoTAXcBin1apHb5cq5+xrDlrjEDGUg07gtoFaw9DUnKTYFoeR1KEHNJ6W3EFV7oGB3jACVRVLNLBZPMl6kYMukext0FFwVU1jbbVrA4YXXJZADR64Lf/Y1lLtWou0VYbaYkgo9a8FADWscdCcDNLWxwVvziUsFCNu/YQ+BcntmHR6sRodcrfKOHN4Oi6rS8tMloy93n5d8F+27dFBjPWWswIIzPrmmxztWUwqiqZBTXGRGZV1WwNvIg8Rqh7jl3pZec1wSfjaACGLIumoCvEYmyUzGBj8dF300QyMmliWZrV1bGk4zE+n8Pz44rMMcb89u3Lly+v64N3GqZxU83wUTVm1znx2L46Hubr+7MOEBaIhJkEiTNGBwdRMY6RZ1ydvQh2/kiRReBaEatT+2enorV43lgXRDZ3x4CTDUPr0wWs08NzC15xjqHC6HRX9UIAupXiu2dHUNK8Ks8cOZ5zeSTJheaRD5UEdfxHcM6pEQwyzsbQ1ny211ciZVRQXnhVkhkR5zhWVcSiy4XbGm9JZxy/dICRVDCDoRYBQQ3PEHAIPjPBfXJqLYw0MwJNJUNkcxex4y+fmO1+0GkuIoCCl/vs61YUdas3vg9HY/cYXcgJiHKPfGmGXexpFVheRkr6bJDtLh3MzQPkjaV1t27DufHOZuhsJk0/LUBqpEYCHIGmuc25BuHkcTw2zXoMAEvNvNyuZC1wAppivOdTcwq01joi2Qk+oyt703KHd9rOHjzRcexJB2HeFU67pzW1KDNlf3s+j+PwvA4PlYvLCTWUNUKrmFFoBUTSOCJH5EuK6CEIJUtKMIIxkmOs6wLCoDOq1AoFJhFuU9sNHm6fXoOBPlI33puNn0lym9HMaoIul9u1LkHNWeP8vDb+Bc9lAGU9oYEIIGs5OIPr+eyb1p3iGCO2AycAqLYmFUmpLevMYIHWHvbazsxrvciMOKonL9EDXLefor2BeHTPFKZS264oGphpttFwJwYxwxEGlyQogr80NyYTDQ4nhNYFWLoTt2oysYkNYTvzrKqP13XPIEOaTetqp6rC8vJabSdJ2SBaOdqyu+aW1zVhMCOPA5cGAsdx1VV2BlwL7RfYB81bdRstYQModCO/P0UOM8eqdIuuhGOXKWfJLIMOKih4QoYzU4pPirXtgqKAG9zu9qVNuW0T2e4o1P4vq4unT8cDeK0V0Q52kUJUn4BqgEIjIvao37e6aTtHGDLH9+TbgY8APvnAu/yvWrNUFZl907ramypaY+xBbEcP3kILy8GszfAcJLWuA5HHMeeVGXaGjZI+Ee9Ejw8yk+BaS1gxRifOPg/NGHBEcjxZQ4a2Hv80bV4MB8ORoXYeWPfrx8hS2TMZJlylltOwOPi7n3/+fBYkf/zxx3VdOaiaEdGWTI2QbV9P451ZS4yocguSl2pEptgGh03I7BIsIhXLq6ZVVWaIIfOqxfaMNcNAQaVMpsHz7XktkjGONnQr8zzelpTgSNoMeOmzK2IoAB3jWKpWHjgcRs0FaklgfKzKYdMBw4wtDrSjPer6XuO6rhcL41CJ0OBYyAiUaoyoa4JORhyR6z7Rax3HAZGG5qrxYKfCoGBGjAhoy+INTOsROSLHma6VujtRLQSXjKAsrIGOX5s8akCghNF1yXmeIeBGE5t2IPRfyI17ut4VyyrRltlGc/2NRrP/2PAqtg1nQ1Dr9svZXB9ydfnku7NxxPY/COlmUrQfHGhXBzNJarurNqlHP32GzcjMVGEZliLaSqFvfTU6tbOdqkdVETFy2LYUweqRH294qnqw58y8ZfmWlLdRCsi2T+mB93m+zVmjmMjVbNMIeQmOQN6WD1qtCDAKI7OyM9Rh+3ldj/cvr9eLxUzO6zry7ciYdbUfwHxtWLebmWY6P1fH8bFQUGtzmJn9qMf7QSZfL6F8nBwDr1dElJYnln0cmRNjeYevkWmX1hURchEPsjtXra5VwXaSCxBwjqMQkgZDSz+9v/32dz/33Ktq9tt9jMdLOo8xGkp1FdsLLUhGVq0wovRicSoej+PSQgBesxwRAhkhKRE0E5YXthtfPNekOA7YrzHCJvOhF+GommMcdV1INI9HNgz5Gu2LGZFHhAuGqKIPDtlZFnKlArzgUyE42tutEAzLCmshIiEXCsECSzDyTa5Agb//+dsjT006U0EKJKYmg2Uk2mIPAiuQJZbG8fjy+KnW+vbtG44kg4Zrwm0QGFwIEYgFEXpjUpAWYQY8VPOVHEKcOXjVRIUxDWenge4C0bIuDi6XywEcMViVx/Dw5VUnDyeqoWct1as0q/o7PBDHmWut5QXz9PE43iStVQjuWz8DsZG9EaElyFrb6AwUxQcfNR2wjDwkVJmDwxBKznbbw6BvpLGreIIYG19pN1QWTELEKK21vExpPl8Rcc0XAKm6vSbQapYYA9WWSC5UDqYoe+ej8USdR3C5HvNwpBITmfZUKVQFR4Z8IGx8rLKVZAyuO3u01PZaK8ZY2L5BiYR9Zgq66kJpjDHtZZADzXx3SCiY4WDPLGRpMBuvIUdvYGDlDYDdCTjj529fXXobj+ixZHb5uG0fAILb+g12aBuBHwzY1nOSxPFAyp5ROViSjvTHsuFzCEwiW96whZB77wiTyEwwAscxEpxq4Hez+B/gcuXxdq0lwMzqmIPHsjOSkdooJwLsvRL2o1ug4OLa3ghjHEKPH2E7xU5FEiIP18J+dCjLOb9dcxzvq2zhwABxxFm5crlUlQSuzPTy8pE2wwmupXO8VU0EytfLkZGnIyXSTK6pNhPi4NLERmc8PGBk1GtgLgwdo+BBo065WOcYLmHVkaxaD45AHAd+fn0cOYZZWivGhLppC0cClZRLVxlRwctrxAgEaWlFCAFh9rw480B3XQcwCRxRJTIz1rpsH8dRhoVn+BhHQPXxSo6IseRVPB1L9SUOQt/mFRFvx1jtQQI88rQ0X2uMcWasulCV+VhLj/ME81qvJTAfw7WqntfLcIycXpaO4+hjeNU6Insg/Bhvc85Ir7kyBkGv1tanXazFkRznqhqM5FhLjBBgGjnosn1gBN35Y2AswYLgPA8PvdY6FY/znPPVZK6a1/s4JWmFiXmqrhrM8KElkAtlF8PDGQ4RL0rhXNY9GLPrDEagqr5+QJytHnRBc2VGeMKRDhNrwYxh7VEEqr0KM5glLgjAqgvA3olkk1FVkcNiuTbBPTMPPZ/P7npby3FkVtXz+cSRq22eWozVjqdS4JjXsrk8f/Xjj2vpemmuizjDd7ep7ncUwKIzgUyoPbPCZlnpsLirM4u1GMXYy16O4xB1022ObqYWLTjLvtk3hzkyKEyYEQWVdJqPXjsDzDmBoMMbzNxTnq4k8Ata/IKaoT0yOZJGQgarVkNBm/UWkcZq39PekgL6utZaRSxGWz9GRMSI3LZEkipagtn4MACXJSCtb7///XDGYRHXdZ395smMXLdxa26YSglKGse4rmscx6zlSMxX+IgDm7kNyKqqWh3zvlfHc1ZLbp7zmpo1temLaqaNNbchUXp/40+tC/WFIzN71CMYwc3qUU9WMcbgSMAJkYOqWxj271Ao4rPT/fwKZF0oZyyv57yUKK2XCvSodO5RaO9pkR1RiYzAe4YCCp4LNn4+4lxvUeP58fWIx8wndV35w9uqef9ytzFeNLZIKpuMWVVqj2EC2ta7tlXVZnuNBm9D/EIy3XIjSV5ZKHvZi/3d8ZF5Mn/3eo2IvZOKELz2rq8kkfr+TFgm6cyiFoBakZlNZqnV7dF3TscngnH/idFOgxQ86wIiMgTh+cojaXgWgxoBtUBmz2tvWkYjaHzN+TgOky6X1BTZHtUm4vl8fn5xbRhQ1zzGgPF6bRS8dt+zaXbbbjYiIDLk75fu8+ezTdk+SUP3yYGD1fZUATszQZe0ULQR6Tb6LjV5d4ywq/0FM8OY8tLEcaS5x8YxCGDW1Vj9kAaO5FE1ASc4GJZeqECOSENLTgSijZeP1vDtIx1xrZXFJ5zjrBKhZek1j+OgZXsGoi+UURm2D0cy0s0JAG9x/Cd/874stNX2cWOMq6616pPHhMbjX+UDcsU4l+SaQGT0haaaXXQkwAKX6tDuzTtULxiEj9SzRkQMlluv19+7pqoZWLrr6Mhca91g9T3tsidUATdnAYYYnX0DdioQ3laCl6tUufDIoW2sTjJQMmzQERO1ahIZI0FIy0QGkvl6vQCd5ym4bAddjvOIOTGL0JQrGHAGFmIIKYFx0YqwleVlEQxjbJZvVKDCoTwRr6ixBFVFnsIMP45zrbX2QfMYQaAVsQaiGlMSnGILpZsDRRo+IpHZCGp33GutCR05rtfL98IcCFMTDjLbMD4iHFx7+JfREqoYxzHmnGvpuq6+XINDUqiadtxGX+3GFhUkq4xS/7DlZYYa+9vm9EdSrON8//j4kNY9UUNv5mLs7RsMQkY078xVK8HtVoc936ARIwDUXJnBSNtHhGyVUHsbw140BKCHx+WIDZuUi9vPLByMT8Ty/pPgqwXCQZRredKVfHe0THhi01KDSWJyRgQQ6CtlN9PaU8w8xtFyH9uX1nQrj93t7yC2dIWtGsTgmJyf6MqCQB3MU+2H3hofrEDN1fcYuM2XEXOW3FK5C9sTByMCjjkcroEIO5Zpp/0e6VJmbgigypGAtalMCGuWMAujt3ewfVNFcLsXdpr7SwYdn5nYqmOiatVacdXjOL69vsVrPc7zsiVeWEeLTfufzDn0ppyDIlD1lbTW+zd/jFj+XeQBrI9HvevxuNrBt79WrVblbmplv5+mT6kX1PiWxfdooG6qSWmy7/qezcIFBjdt/zgos3QCy9Kqj1UXVyKlahS91RSPx+P1euWtPPw8UfIimJHtm3YeD2yNznbMl90YwOdR/KxgbCvWl8eX66XpQsYIaC1EQMqN+hfNtVzWiO8aFZJkSoXqMSaWZLqsFkI3R2YBNedxHJ+f4uPjoyW6BFYV7TgG7i1yvPHSct311oYif3EMvrPub5FtMyf3SLJUrmin9F53Y6pQPbtbhLVftdoi2GXXkS0eW1X19vboKrxhz7aSQZMzUAE+E4Mqq7J7dkQL+/LwqgTycWiuWgskH0dEaAqkXAbJZHscHfn8+u2n9y+ras35/ngDrOjtS62+a1OIpgwrDN/LEpIhF5kqNJuizb27JejWpqpaEbSn8s00rvng0NKrKh5HG701DajHE7NWO6YKnmstOpMWm/VNm1qBOMcx3yJyLF8lbUJiD7OTx7FX03qViF7X1mzq9rtWoKdGrS2+Z/swstWHTONe/4AMSuOIgxjAVXILXjZ/TWiWckbvXiI49uCSY4xpMqK6SMhULWkmuJ6vE/jrf+2v/d//9X/dx+FgXZNWxsPsWKkOvzQW+HCIMsNjT+IThuOL4EQ4JmQgrCsp+Dkv7GhPS6NHleoXBZAhAhnSxM1MUWkwCJheU2cOkm3odZ6D9mteeQwV2n8jMyUyEgh43kXS7U4Muvek1tVTkK8fr/fHQXKtaw2hbQjbZR3w9kOI3r/hyBbDuLcAuMRxhw+S21Ghr3dExN2eqqqryBRgLwqJUUGiMjzijBEEF1idtzCh+Hzdm+YjqR/X99BzOxH2Z++5nwBxZ9ZkGLX0PdjVBoL2JY4mwyQK3eLCMiEmfctHBSXSOxlvytyu8WEgHufbnC/NlW/n+9v79e0jRmYevfO1R+l77pJRczaNkMxrrSTLyki8lhivFkW3u6QcC1fViKgd4/acaa2FGIPtCgnaS22OsB6ikkhMq1zZdMrbeaq/Gmw+kwFpP4zvpk4tjhzHSRLcZKloHij+Uva12917YwSz6lVrQqQvV7WzC1s6D2m2IUK/wqIGfS76CGUci2D8/k1YNg7y9TOP8yOu1DjGa/556EF5x6btiLXna0nA39fvuKRtK+HtjnFfKHYY6URR28EuyAg+r2cTQEfkGSFk740abK1A2V5SkkkHNJSLjk+WKrBNWQE3Sd5LJV/8/NNteqtAfa9M+UzAyy0YW2K/VavkyCJzOcHVVLUWpGWT0m43Je0tBZIiA1L1F32LsFtpEmNsJV5L8rYYL7pxQ6PIat+J0J6H7lSPcBmwj6SqlXvfT0K7UYLAL+TjRH4ygaO3kHrBGBzMbDM6efv4WjYqhOzddrHlZ2RKMyM7Fgl9m7GJF8D7lK4icXJEhDVtBfhkDSAsaJXmQBbiuhaHudnpEI0QSY5kxBm5mpal0XtFL5WIIQIoouBh2Vzc0osI2pW9X8SUcagDhD5VbOSWETVccYevzYbrEckRD4NLFQGwV6Ml3csMvDGM5nu2FvHztSU2zR52L9JugB7dn/QWgCXp/XwInGv1/el3F47aJsy0i3shCEsiHWPcRVUMS8FqQM71Pk6Ss65flKD4VDfIXlVtVxFNKIRFLJTkEaG9v3LzVCLSGdP1r/xf/9XHl/e11mrfMjDKFa6Wq7cSngD0DYXlUZFrk2yupJrezh5oIqBTY1FhXuzeEbOu1+s1+t1WVZ/6Nm0pzSOPpdrjHdnhMQYycnmq2MABw1WryqSuGmOMcUrfVy9IGtAyYEdmE3Eheqm1qlKvPu1tzLZyrRVgbm/X5oJA2NybVgj013mX7wrvnm+fBaS9ZPUMv+wkj/Go3qfd4zk3bROm2tqh3VOXlbek/Rgj6DlnD77Dm8dUVdhTyX3zN9u9E0wHYzUfHXV7ZB0Z43al+fxhkhOLxIEkXJCosEdtu7vPoLrFMnCAbM+oziDeQZ/n8Re/+fXbMX54vP3+4+N6vo6kQJmrqh2SSxpjvNaEmkvqtRZHriUe6aqIeCYe8ClmLwcNXvJ1Oxp+Hu45J5ERQ6XtBdWcu+YdLsyaHTTbWD9y7xQazUvq5UBp21HK2Ov/1DkLEpZzRG7G3CcZFCQisj0BIz9Hn5I6AV9rlXW5rlofH7P5hz/P1/i0rAPFFZaI05ZZ3TshOUBwLH+BLn/4W6HWeNShhw5f9Rfvx2PVFhXQu39tyLVa0rq//n2fAbQNU2ZgC4sr77UffUv6E/Q7sP3mKHrBk6YqgHAkKOrt7e3b8+ucs5dffXwogBXtgP09/IRJBYhqk/jW1u14u+k2mSmri1ttgTLABlzxfF4AOOK6nj1iuprx3os6DNtn5JF5ycBq8PmToPe9tYqGyei7PjhGzrotBlv5Wr1gOZdWIrdhwuvqqO62m23SQlfiN6y6pKZEfU+07bk/CND1eX3uOdHBqko6gmvZ4nGMEGVx70mSJbAIJGMKAUccN88ggkNSRmQEsRkKu3YpzdidrAMKGJSQGdAeZrecMDOJEDTnPHNI95KfqohYa7H4GEdVva6LGWvN9fyIM0MRW8y5Rc/3rPkOA7YVVvfGfwkl0q3Ol/T+9sPz+dxmF92rV5GcNOAjh+cabLuDcgbXaoXlJzQIm2YabDqwbZcZl1CS5xpjnCPKrLVXDvB25OjX/awAsu3KO8t6L3hoepek5bIqMnHvLQGdSRBuQKRUUQDW0jhuNZC/D6oknbeGtrAlZLA0ZXLVysyC55wIZqRKakPiH96mFOQJFrC0zhhpDWnRRYtI6yF7nFNlYt503cOkKK8xMSMGiOATdZozwhJKzceUPTqjdKneJ7hNVTRXtSRAu/DpJxKq8+0LydfrldIxhijZweh93SSNstjl77qFN59foQGOrHUlBoKdgz+uGVjH8Z66RdZbAAFg76A1EHLQA/cOWqKMXmUo79/epy1zSFqrSfnjGHvR3uFY6dJeUFXBaDH1XAXO6KkpK/AwHpFimYpoblsrqRAR5e+wXldtfcTbdmH7NpDZpnu9YA6R4Npvr5cRlQaHwCog2u0s5JDVHrqu7urZupTeHQSGwvbn4I/A8/n8K3/lj1H6+tvf/fjTF9vzORHRYGMXTNLaq5RRe893hLbtHMum9BYH7VmNsDtWABjCx+pZJmOTGE9/SvVvBwYEgwO2vK7HCMNrDvBAHAiMeEpoAB97NRzAZI5xPtfsrtHpZvOPTAIvqfV2fRQMWFiflmS3XQ4D0eVGyWvhmoOYcwUT92m5a5l2/FySVq738zEHCjyXH4Ua8W3U8bw04/d8fPwJv3y9Xt9ef/RXf/q49PzG4Hdxs71PYbdmuLXvtzXBd/ueHiM0GQGAC5k3fNcjFlcZtSrbWyToupkQQURoraqC49N9ogvSJB3xixEwHN3PNSDu6n1m+0sqtw7YAsdnLfiZm3cF2U4C4DkOVcGCeXBcqog6TMoXKiNhf4qw2W7+vyhMu9fviNgBV6sCMec8jseqixljjI+PjwEwPxNkbELlLnbbj9pdfX3mVWm33xFt3+6IqDmxIhGyPmecrbtmWHN1SbSPgT2XIvdAHjbp0RvaHVUzzzPjWPMVwY6Qy8qOYL9oItVCC8axF5+v1bcW0UiG/d2e6FUrM9/G+Zy3E/5dVTQ40U6HY4yP60liPM75uqIVyUERQ+lNEcAQw6je2CYSSmyfPnq3xeWQFI4cGy9oHq10z6f6eQYpV01YYxwoXwLgk4xgN2qVNDRskbUp9bjXeWXQNJhnJhnQFOQcZ3mV5jkeLjnjurFJtEzIbeJxYyRx+3MBuq0j7+yrQGqA9lkUeGVMazDej/Pp2W4TnX0+QR0co9x0iTawNUmOGAxXL7PaMEazlGhfVRgIOTFG5ISYI4G9JRcYbb3XdtN970sst1hGkpIxiLbHxAjVUbZ0iB99/wE0XFr1kjAYWjXGKDCPt6oJ+YjRgrAv7+9VNevqqn3OF7MH7SHJ4uPtjBg///wtrEbYSV6v1XGon3U/jhax5kgqV4W05DnysEuQ7UeOuleD1b38NZAr3cSQ5epPjj1ZCstg0WT2ztMqu14vAK05sf1atVcp9Y5q7zXAAtHcSe7osUEZ6amrXkCbslYDOtgiV9wOfd+TEG4rH5pYcBoUkrFuPUyzxJon7/ZUqOrd4/cWv0ES1mRrhknmYOzgVZDEthbcydkiGvPNI+ac18czAl++fLmez2KP7owe1dsu4etXhiEhs92a8Kl/jUHmyxVT3chSLqwFY6//LpLX8kGOjLU9M6BaNyBPQF4F6s1t3Mo4QsblGmPUZjZvaDMzADMzuivciNya5GCstmTPOBodUjC6sSuz45rXvaJq5x67iKma31e1rIgRI2mVv39l7mpOwLWeOd6kRCgdhgN/4wf88PiTH2f97f+nf2n+yZ/8W/++v/Lnf+s3R/6KfFZpVU01AF3b48h2L2jv0ru9x0kDr9erje/L2341OJC7ZCn7cZ41J4O1VtnuRV9WyC0oLNSrKsjn60Uy41C1EIWyKTFi/oIFLbR+BwfgVbXlpiCZkb1+ISVVj3paUfb5AAtSHA9JdL2/nd9ezzlrcCS4Wo4Y2ZoOrVevR8OmBXyqLXe5Uza6fbxrapfMeJznqmrTlGs+z/NsspXvvzjOXgRpZpT2iP1O7VYrl7LhNJAMuYBzxHPRktlcsO0v7fb3rmL051Pf8eVll5ChslDUyBgMLZcUgeYJIxLgt9czIo5jT1sABFmmLIWNfDAjbwHP7WpgUU0ics7rYkT1Q7qe416CfqtC7qoFqPCs9RjHsiS8v7/P1wtEc2i28bABRApbZGwSh1VtIm0biNrEK9gUMTKPZPtJtRdQT4IzDklDeHt7X9dTwLKudWUe5Ci/3Hs1bAmq2ptAzrNKYdJSKTPawV6Dl1ZIFgfHeZ5LvJZ8E7K80WkCWGsdSUt7l8PS96raQWaTaZY1GBFHp9G7YMKZo1AIMIiJsoluVm5AKKNL3rxB6R4xAIgDjtjmQBH9NMZ5Fp1xmjL5sl+WvOw6elUNzB6ZFBddI8bsjaEsUmQyWhZgVQWHYrHaEmQeSTGjGaBLdK0aSb+/n0eev/nN7xA54jjH47dfn295BHGttdb66f2LtKoF0jv5FHrFn1xVXCk9Sb49Hmtdr9ery0ySHrkFk75rVWnRh1tIEMphOZORh2XRskR6BGxpn0zUzhOwBiPZ4KTMA55EoLccWQ2rnnk0MbsBjyajlpTAob0iicBp0FTSDATTyt64lwFyckVtz8s2MpSKGdLKG3NTgdvNJ0iPFpxg2T6RA0GiiGzdW0Tch2M1oP2qiNiUCd/K+xx9bgJRS6YiIjPGOD/Ws7eSqO0D0ZxYBOO1ZgaOPP78z//8HOPt7e3rfA2zXUIj4hzHx89ff3i8XWs29ibNFu31wDUiNJcH0FC/rDkpqZxt7EVDvq5r2iqc51leVcqmDjQM5jVie1BXMsdRNX1d5zgeBbUXT/Mb4YKDUJVQORJ7ZsNxDgevWme+fRq8ZGZkciRit93qLR+xG7zGcvoCt6mWYNKz6gy6fcnJ3b4wSHwE0i7pSS2uyfrV76+/49fXn/xf/uf/nv/hP/r1P/Z3ff32m//QX/u7//f/4D/Eb//Wcf7R12/fltUbLXcPjG3VEiSR6G1dd89pIDbaoczEtujpszDMOs685jPbnHscx/KULhaII8cjM+VapYR47w/HXlSWY0zPIx76hRc0u9AMKmOtS0vjtnWx7R7U2eS+odj1yJ38eG8X7lF3o6bCnPPtiAX0wt3TFFjpWGEDEaT5i227S0UL8nEc6Lk1cJ7n82MpeD7Or1+/WjchiKy53t/fI9CrUkV05boVVBE9P5bVMZbhjKbRcu+A6apxpMX97G9j8ExUrTPPqmUbjUNSPCh7tJUeUV6skCAGuJLD3vK2ti8GVWC7Y666e0ikwhZWmVrs3SJgyUSMwVdNIiLzeHt8na8AjuCiaGa2GsMka66IWJrTGGN4qRehfMzrhzhebPIpVhJALqbdSv0il50j2yKprMLKYqIN3raZ3pw2it1Arw0sNS5o+0scP719+VvPb0tC9DaU9BLPtu6CiRu4pogDMVUZZuSSZS+0vd3Q0hFKDpteXmvawr2FzHd1siOhavcD28On3TTpQqOMMlr1n8xlxbIZC9Ja78dIe9b8Wa/gqLUAcIwIwNHo92yED/Le5c4wQc35kjDG6AlsF8dedYxsrHq2Rp9MxhHjZWMpwExWxOrxmRyibzlMo1+bJQil4kr0oL6Shzi3zLtI5DFIDnh8m4rreRzH0gz5Y74w8gmFI2L8+OPb12/f0Jsypx2E6KADFTQqSazJjCNdegFdpDcgT1Rv2ezCEFUgWIViZfaetUBaMDV6j/rjOG1f17OhhP7aDhpMIbSt+yoitT/aCCiDq1avMaAx18cPP375+PY6jsPmwZAXySUrQoCqSCp6tSBSEzwORrVZnUj6LQGfzVvr/R9AhXgw5+fKgdxL3DvCfv35lYzMRPiV9QqleRBGG7DufS+Px+P3X2XiDSG0pl5tSLLWivZxjt56rAWYCvOYVx6R5IgE8FxzqeD2HXr9xON1nOuJxzvf+fb1+fXx+NWL+rH4sX6ux3E9E5wX3uYwrzHYim5h8zajrnp/O17zWtc1QKqq5pQdeV4v2ddCRJzxGDCG2pbrPN/W6wLq/e0HSd9WmVkSljKAWgEi8+N5dRIVJbQoiyNHdueUQ3MN84xxHMfH81mWiPr4+hgHbJDjcQYcVmZO3vr63fS5d4n2IK0nr00YgeqRo66ZYzBte/str+t4fx+TjrWkY8T4Nt//6K/+7f/cP/n3/E/+Z3/x7f/7b//n/8v4R/5H/69/7p/4D/z3/rGfYv75i3o93c0rw1bziW1nHuCimWj9ntqYNRKOQ1aER0SS5Yi0y1XryMPln3/9+zwGSwdjxPjgdZhLkcfI8mtOnsMSu0ST0MQuxJEHHAPhWfELXn2PP6J57OUvWT/+9NOf/fo3+XhrK+BQ2h5YOc6pIl1aaEs0BwJVFTEYvNwGp0hhjd1nP8BYOs8zz+Pn56vLfUSDc80fBIDRE9AIV5BcKidzhN4g+Xp+dOe5GghgHGO85jXGQJAOrzWQjLGyXEq6bSkPdTGar9mqFe7Z88jntZwj1lpY5w9v3749HzwJVK18DD9HmYy3QkEaHO3KbF0rM8khUCnCyVU6AcJtkpeIwUjBU45pgBkoDVJLPR259tp7HIzhNkVycT1f1zgOr+tgel4/KKpqxTCF7RfN8zhea/7Jn/zR7373O2fmlKd++vEPzhx/9ps/yyNfnoWD6d7rd+bIx7GmSAw5pcOOyPJe0DiO4XQvlmiv37e3t9frlTky46PmI0bZIf90vv/6+fu385wv/dmv/6JF5l1DSjKNxWC8nY/lpXmNcRTgSy9dkVx22E2jIR2BA2rhiuwivn38PMYIHJr2G7FeB/B2Hh8fMx3JKIVzrlL4OMfLtVDH8eYPIrmhJBxh+rU+zjGySOM8377i40rMxeA4hL4hIUNcwaZrhiAmhcHwqn07Ri7zcMB6TSc02OxQFZrTrOTBMOc8BqRCylMRIaLZhfAK5irF0LLIGExKOCitITFOldgTVUYZiwY8ag/tkxnjGA5SKtw06Awwo9ntpQZg7zGnnZyqkaeBWmW2HxjaHGMXONs/3+SI5NI23/Gnpecu5CHJKtyla3cJYwxEu6BuqUxmMvP589c8kMcu2zOSSK/FIwh9DlnuUQ5brdFM97WujGjlQyTsorYPcHjvWojRW4n6UcjqWdTx8fNHnkdnX5KZ5zniui7cvUjdpJL+95EsqCyKyQw0J4mfpMzGOnr9IjOuqjyPVtvEyKUa57GuuRG3NpUK9nIHR1sQ+LoutVaXJEaSWW/Aq6bwOPUKv/3ueP9T1F/8GB8fH+9/MM6fv4n5a59v9fxN1a/GsUc/n++qLfrmfPWrXmtCtT3cq76lIDYJ+xV10SFzrfeffpxz5qAUH8+vJMeIKsVIGgM+RADCUADMqkWbDaz3N6CuJWV50ssewtQ6J8PQOb4+Px7jGI+zzVoHw5lxjM/ijDfhwnd983q91pzRg3/EGElyzhkjATQKd5xva60aDsVbvD2fzzz45/zd3/X+712av/lH/vH/z3/h7//T+dsfPl7+K3+V7z+M8Rdf+TXXaFrNumaFkAwBs2IEIgpYYFto9o7WCefIEVhrTU12IUZGjGtWJMbZyIrInGsxelmFpYtqq4+Z6doDjtH3sbdlswdWo3ex3aibgNKVzIwjQtDX5wTTdu+sNTU4FrHWDCOTIw/m4zVnwQw84nDh6elL75mMeEZxDJSwCkmPfNp8vt7GY87Zu8Fv3fjN9wnKCMvezuppk8tSkBGJT5FMP5Ax5pzXWt1jucUkVUfvpyE5THIRZaFWbC4P7i0xfYZdoAQXRmRXEmZqNX7GXx74BjDemCX3nM9tNeQYRLGJwJn9yYgFK+rtfHu9Xmee4moRQRufMYLcRqpqFk52TTKG4oWYEWfZdI047etmyI8x5pznEa+PD0hzVWZm5LePn597NhSz2mI2QA+OXhAqITOVhJv1VoYzKYVrChER13V1DGx1taSpOiM/aj6YAH6/XmcclxyxHehtsIVq4Ag40qsajd8UKnwapaIVtM0ZoExy9bD8muM8RkKIH7+8V9W3b88vL7zAV+otRrBe6HolI47Box9mJIxYa8UG2ZmZr5Jdx3GuueaIVUWXUYfyjXsD0IIy9oGADHiAB/NJLVWVPx2bC2By7TT16eDZHlnIqswUSpK0ViUDEjJCdjKOyNUFJdSIRcaAsTwt6UNf3s44xnOVUW1IWHMGx8hctapZ37EHiwPBrHYEYoKIuAgUHsd5zSdMlHopRG+3YBz9zjMim20YjhjVylnZBKO3bKmkiGjTVG3Jmn1rDT7/fNbuQCwvVUiqrR2CJS6/fXlvU1mSRmlWL+MQ15IGuFoQJFLDQGECTReOx+NRVb1/idFWCWh9cG/oyczVD/x+L5+8wbe3s6o4xudCva8fczDaqig4bB977wJUwECPBQMYchKOFDFgBmfPBaTVa9uRJDWX7OM4mjVP5xnHBUVbhQQAh0CggrrqiDTCxMiGGFZVHcH5sr+sM6TL11wf49ePpd+MP/7Vv/uv/jp+9+KPx5//mwPnk/7V23HV9Tn7u8ud3hdYzLFNqW9+ltpFnK1J2fum2iiiHRUyM45AW3lyr98VfdGzRfwAHWGPZO+vaHtXuy/0wHrZbR1quVY5aRs1K8nLnq/ncRxHbsRyruuGT1t0QtuQWmi4pbfWGCeA1+uFxDgCoEtHfifSv9eoN/x+6gdHFI6/+bt/9u/+D/9n/97/zB/8y//K3/5fOr/Or//Sf/8f/U/9F/+rf+O3f3E+5SOjXBFPqJJpPjhW4Bpl+oBTMUQiiihipUMVAMRsi4jYYinG0FroxZLe5KD1mq08a9cUdjRfolDx+tVPf/h2nn/2t/5ir4U54vl8vt7HUb+gAgNzYMDvCl4uegbmmnGca13naFk7W6Dpe95GmXu3cdpaYVMPjuWlSBeOyDICHI9HVc1r5XnImHM624Gg+9FybHVz8thMtGjMjcCQ0BtWwOYS7zlrZq6lrenz91ECgpd1xKjPCRSixceI5W3hDnrXtwTQqv6rkvlyJRGka5GjjRVj7/0R0HaO0a3PZjUHEWwksXnV29eDVNqMC1gRhNYqRkbEqyofR9St/rJ1V84G3vg2WbEil56BJE9jhgPxubemi/L2xmcOGwpoVTOnyxzjrCqUmMDNM21svlSZAdCWrOwZwj2RaJC507wkMO1tzT2rKHvEgRhjDEH2ggKsrn7SMeKNx4SRAXsoWn61rLP54sDOKN3JqHnjbiBKJdvP5zfaZ47fzY8vb48h/va3v888BsOuRWW7UJbQi+vpa80cPI6sWXJkcq3e+xJVM+W4moRYtVWI3z0WWibUsjVZosYYHWOjzfBVI4/l1Vpeb2onFb1TCr1Mdoxx5GOtFeLyZjJWVY9IXGoWghC9If6pheC/6w//5Nu3b8/rdXBkHsdxzFpxHHC8ajXlfifgRJVGk3Q2DNhupm16Fb1dS3t/1n1QGKGquFFQseymrjHu7SJluRlmIiM/J0NdotoLXY50GXDvim7Rgm5ZZ5LMs4FZ2+M4fS+JZPRaq/z28UF6L4MGEaxybrOhZiTWeRwke+lhi28AiCITGzRLRLgWyRHWnojRpgRR13WFfzEwA463h+ZFsjQleRpAkDk4tZiREW09sBtzEp90rd5GJ3TKW+HBhAvWXPXjjz89r1dbLtz+xzCQDkSAkb31bGs5yXsZSYkfP/w4ron1Nb788IHxdh3zT97/E7/+3V//Z/7pX/3N//Pv/v1/5z//9/y9/3bxj2LRfLk+xSHehh4KbK+u/sa1u/zWP3CFK3qZg2k4WZkPt7klrGb92fv9CED6bk+AXny0/R964UFJweBgsBhC2UYVwuEoQe1/Q1dV1URGZq5asKvcreR+qvejHmO8Xq8559vb27Xqui5Es7f8WjNBOjQXRz4ej1lrKsbz43FW5fjZ649W/uaZ/9t/4O//+/7B/9rzn//f5T/+T/70D/7X/4W/9nfy43ffvGLFk4qyqxKYKo7U1Li9SSpUfVEEGOk7XBJjHA2VS+4VC/2ndyGPMb483p6MuV6AVbOklqUSyHGW+Zvf/GZ0wXc8ruv57VkkvyyuXzCwAAwpybnHC01s4hjUbDQrBUg4QESIEHCtayyncTBeVu8LGmMM5GWV62Q8jvHt42PlQOLkoVK3X7kMOHlT25qNu51F2vaf1QTmwIJQdRwHgKpluvuzqurKaYzR/CkJcRvGCF7rGmOEkRGjBQ5RrmZfO5NVFcgdXCJCVgC96AKgrCGD7WKx989TRD5Ze1hmB7jZh6jAsUd5MiBktE4mim8xUKC2eY7loGdzbNs1//Z1IomMozQz1m0qcCV7u856XTsKJrRK6G54rVqsSXL0fsMKmdEwn4L3ZoLoLY8Gfe90JKu9vTYLkCQ/1eq7QZcv+lQUGUeydLHyct7GBm7HXrNXw9Z8VY9PWwHMnqC73BeaRxdGDKj1eNVTEtwrg6pMV5Dnj18+vn688cx4dOnHiCWrKqpn1ZTKKEegCnEI5SqO3EabTc5v/iH4KnvY0oE4Ec02b+amYbF36gRu/lev5gWgKn3a2vd2eHqb3DaNWdtdX7OJ9Il7R9i212WgN6hhVOtyiapa67quK49jlHTVH/7xn/z88e33P3/T5vFs9xveftwjQSUPA/YLBVQqCnhdV5sFjv01OoyQyyuIBKSl7swDE+t2paTtNWt7AMX3aM7N32pOlbctAr5rtppnQVj22n8LBEZ3M7WtGW13fTlGvr+/zzmb9qKtoKr+Hcc4fvzxx69fv85rnucJwKi1gE1/H/usxaZEb18bt76813H0ss71008/vV4vkgX3Bulv357bmYU8jsMlsv0WYMRQNBeuQqSiN8W2vV8vqjbZLHbNRLbl7IhI5gMxyyhVW7Y1QHBP+DrniFCpgQIA7cO5kvn6yEq8fampH6z5x3/yn/tf/S9//F/8U3jUjz/+4eNf+Mf+gX/xX/wf/zf/239rPn9Ad9Tfl0x4X1qSLMnMGNEGbYBJVLUxAyKyFy+qKIrj/H6ULTKC2VJp3ulxPymwPTIBNMUDIArFBh+2dKekaFP9XjJXNZ/zODKPXGt92GE8WxPFbQAU4OKu45bqPM+19PHxMhERvW7lPI6M8GqlRPreQPfit3rgy+v5yuOs+dQ7f/6z3/zqr/yr/5V/+K/9W//Pv/jTL+tv/PXrz/4m4nxPvxzS2quc7gFEV7C9P0I3z7MXxn+qK2xImrVnMxGhuXdaeZXDc9XPc605Y2wy4TlGRMyrWjti8TwfZK/5FnKQjghXmzV+/+MWEbC17GfpVSWvVmBrVjFHo4y8qWFjjPZdaH/OQ0jwmrNxtwAvTzzXcWbvn/+Dn37q3/H1erb54dqwVri9vYmxliCH2aAsspfPnrmtK28lXq8C8IGsKt8OrARLVVXvMQ4DRMs6BE2s4vZcbIOXiNireexV88yBMKBIzjUjONhSwL5EG6/e9z16j2pXyUjQcJpvyIIXrYCB6PRcnk0zh8aRSyo7Rn703snGuIntbWKnIV5BZBJIumfeXdw3/1rnebYiy2uttVToj0PS2wOEc87z9ujbWfLuRk7uzQetlogcVdW7/BqCfnv7Ium6ro7+v/rxy6v0+v3XHCMz5zXPL2+Y9ezNQ06XQjFAypyadnHvZQqZgV72o+rVyMjbi6iiN4iv4xhaa4ws0OZ5HnVNJN6+rpHHC2ZhMJ++II04+mm0swr24u2IitdzRoQCmvOIZLRvwbjYveOIUpiTOeGwWulvtvKtG3Mm+Hw9m3bjOREcvYbIXF2qhKitVR+gewRwHI3DYK8dPJ71IrnJv2ohBySXjBGy0zjG8ee//c15vqVcg2v5b/zFn62piDgj65qZqQgG5VXlMVps2m+2tBplbSjfiohme+ImeYYxxtibJLvQ1xK+r3urpnV/qmPFMNp/IzPzdk4mMsdnfP4OREtqORINOKqqpDaS/eM//uPuYrvLKevj+Xy9XoEk866aG3nZ23R+//vfkzzOlJe8/uAP/iD2vooj4tM1c7NnG9l2F37NuwMyYPZK5tbSoXdgkdYqGsk4cmyGJGTXyAwwNoDd6uDCWrw3B+xU005ZpIipemmtgB7jLz5+bivKaDHfyMwccb++1ub6YlfribS5lmp9++Llx3r6+eOlv/nH7//J/+M/+9f+N//U3/bv/8P3X/3J3/pn/on/9T/03/q3EeOH8w1/8G1F5zf9pdAdJD8NDFzaOMRWnGJYj8JZTYRilL8Ur2t52//iPM8xztUuG90HJF/hZ3jShUKtXeDcU/P+0qtqlCGVVXS7Q1MO7T21/X56jjBVC+yTttYOWpKWISFGtuHO54sznIOvj8ti/3i7oj6fz3XNPKhX+vGjn5qOCwfwPH739V/4j/4d/+//zn/3/a//bT/+ir+L1x+MH9fSWiva2uZ8LOnkMZbPMZScXt18hDzKTR9RoMzy/pZ9j6tLs3sU3ZQiAJZGnvPyKsLjMb4c4z1ipHMtAVHl61oFOzjGPsA6tiPO5z8KmjzNY7mqrEput8Ky26kGiOpvvzTA06RRxIxINU5zX/BWx8IXPV8XS2/nyWN8na+rrhMY8GEOcDhTGGYaQ5jsZaphgkwaIQ9JQN0ZOMbYpgXBbIIQeR8QbO+Ukbp1TLt0X4UlVKOuklTLMmXL3pFatdbiBufsG9fZCewOOABSsLSs1T2TioUBqqa89im93TYoZ/kMxqyYGoVDGMhHDFHdWMdG3zgaoZaLoM1S7aURYERtEaqu+fx0YnheV+/zjlsuQebd7G5GqhDCLXYCgjzGGJlst5BfzBc3pQbqPqE/78frxTnzcT7O8zEOH4lrrbvxYLdNGcytHWXEGL3pNRyc3he2F/C1WJG3JyuCmTTlYMGrbGDO2Sn2w+s4T9SKhLzOHGeOoHvRFGPnEYZppDNiOLYVz+bu0FiV5VzN7+bc4CcuqP/p2High/+Y1/X+/n6eZ/UKlgjKR/RQbMe69jJs+dB+7MiOcp9pbkPA31eP+/5G7iVviIhxPN5acvDD+5cf3r+o8Pb2VlWrKh8nR34mx/5dQ0QKAEQ1Hxfh0dIqMrdpHzPzU7A227Y3Qt3TbhtV2N7eAmQwJS3XIwJwf1zuNmWbcnQlgNvHThLvSfR94vaeaIf+7G/+rXEeb29vVdN2M7PaLLeDVwMjyV2Hjsac7wd6XdfHxwcAlugmazXrDL3xQVQvpUN79EUDaU5m+2viLtuvOc/znKx+z9d1+VbZZzIth9Ui0zaNMQo+IuZczDS3rrHPUxYyo8B1TfSm5HystRjESGagEbAOlxJyW4d2ICeyoZVxPNbP9Fmc8Zv0X71++I//y//8v/n4+Beff/qf/m/8w/PX11/9D/5H/g9/3/j1qONSvXH1ckqAyFYzxVbTWIjelMsNUPSEJ00uUb0yMnohDWGNMbzK5UhMrblWHgNEymkc7foUMlFwcIDEXTDxUzvvrZ8xSAjgso9IBb+8v9e6qiYZy2UOch6MJoiZvFN6Qc6ItcSM6/my63x7jMej9zzM1wuOHGPNeRzHT19+eD6fq8w4dEH55a3w4Re//LSe81e/+/2/9q/9q/xXvv3B8/jV8bd9vf7iEpCvhcxSXpVG+xkewFlYpskiets82wGt7C3UB4CR242rynFEh11RNt21Q68Cohmo+XHRtKJxJfWRT2ltE2oGjB8QM+5yAwBwiA7O3q5dNYA4RohThfZz2sQZtjJw83cIGYwRyKJMt0nQCoj1PrLF8sG4ruv5mykpzwfJue0x2husYa1PVV5XCUhmUFAF4/W63t6+jLZBzTzPExzP51NappOjuZDADmkXiXa6qzXu6VJXn59LKhsD7FMZ5NIsmzEkHBzFKstti4m7j2xcAQi5nSr3wKispM3F1c0RopE4GLHw/yPrz2Jty7fzPuwbzX/Otfc+p05V3f5eseclRVKUQllUQ0qiECkRJVmCBMGAA6cxAgN5SfIW+CEIEuQlQGIjCATYkBHACiIEMRTLMg2JkUlTtBpLIqmGpMT2iu3tb3Wn2XutOf9jjC8PY6596iobB4VC1Tn77LXWnP85mu/7fSKL27CoGUV1I7kz1YfmFECP8GdF0/XJEl1SLpzJOpXvqDB4HcSGdmF1kau+dPXP1qgcctkijluieSD9qUnjK2AN9mtNaWZmEMCw0eXdshzSxXVdz+ddVbe5W9LWZc55iUlgn9OWYbNKkNLaYQlSBKZaEYMG0lSjEQglymaoQaTzbPqihxAUi4hxNOLptuSsoUbq5WS53z8dS4ruGZ986yPvvPPVMOuVbUeztKg+q6rgi89KQt2az3uAFD11JAoyhVllqiOR15Gk4lguHiU46e4Jxhbe4o8OV2UPaGANShUS5GNUSnasr1aVDt1iG2MQYqIdMy9HtSJQ62S0MjvPcNdtv7z5xjPGMZe9zF3XkVX73K5yY33sOR0qXixBqThB0VLxmV0ddxPcRVDkTnK77P34rEwQY4yhErMSaTjGSpHHkaOqyGo0jx+mmuO9yUxRHOE8CaK8t8UkO/GtCtpFAVLED8pMZqa5q2olM8ljXkkzk2pAWGlh3IzHHosdi1RFkQEXSgPrefzfECABVWchMqVoZqIIRkUNtQ5Bcj8ssyRFDMjrv0tVNPBMGFRtuqEmrVt510Ukg4KsqnY0ZptfxTuvjajMXJZli03VLdn1smaBpKkoHUhmE++6kKlWWItQE8Nk258uNy8WfuL5F599/n3nm29+5Vfyr/7f3/rNP/Vzn3nrV7/7+8YH9w9LSYzs/BIqhChpw75JJyxBCRMnJnlgeiyT5hQh1LKspXYsUZlzDmt0xl4Uddlzv4FRJbpukHI1IaxiRqgqVS1FrceBWVXZvCKIUliEYrZ3kDjvZ8k6DU9QSnxozAqJBizZ4SBs0FRVoJozLLKuJwpi23xdai/RcSjpRHplUFV7pN9dNOSkb1bh6TLny+VBRdYbsbd/7j/4v/4Pvvd7vvjn/uLzL59vbp/lJWBFwXnuYxk5w1UzUsdaSahoEdkBlpqKYLnII7KMHzKhPezz6IGAyt3U2URYDPR3SgZyURPq1cFLoLKmu4sooRH1AS9W+uEpdAqE8BAXgTnglaSqSKkacxY4REGNLKqkoExcDbMMUi5OBGu3mjOHqJI5yqfRbGMmMWCrjf0ydXg/yh5jwa6hJJQoVZ+twxl6mAtAM5tzOxZAmedt694iQaWWNOn5SAnNynWyqqggkSJ5NOWyxDGphhwTrBbxjtRS2LIMXy+v7sW8mJ3/InIAdK7mZ1axl9mLqBBIlmqZ7FWOXiVQ2CweRPeEsWUIqkxQMcWcZES40B8tmiJNSUBSSqbBy01SFrUoZKbgYJeLdKiGukcrP1jtEggG++GRqUQqC4xqjbTiGvI8hawQkdUX61VdP5PMEsg5W4VwuVx6BqCm4soZqQZVKebqiFSzZF0t5B2YBhMVgxAIwAWiZJrIUN/74tEjiQ84BoepojYiS02FFREqUtyj9COyhsu55oC76Oe/9hUzGYrI64bK/XXxysxkolQ9k0C5j33f/WbZCzt2VXUxZ4tHppd12lgfrS2hENX1dn3+6rkNH2P0GeFujXMQgVMGj+HnfpVtjTE4pYAixO3m5vRwuecMdXMZJVWgm0Uvkg2nsZASLHFzkTJ/2C89sRvLuu/7aZwUYoVhfqlIVqd8ZKb8h3/5v3SKGl7lPlkndQZTYPWhsHVT9f4jnLmvGBVs2+Nq6jpmRMM6m4iE66Ki/8Ug3SaLOYAoVIESqi6EQcylD3QANJt79iyigy96HxigNRO9sWFmPXhkHgDCZVm6qJwRw10iltN6yWmrV9W+bbfrqYJF6ZKw5wBVxcNYCTV06XUd9VBg1XlTpEEoFooChXCWqjb/oKrM2hKtpccyuKqECT24/y4OH0wwk4bKXFQmq2NShxp5WM/HOMwzmdNMriACd3eyJQ51iPL0CvgUOXNfGAYHFxf/4GZ8rOb3/4tf/fRYfv1f/Hef+UPf/9Xv/p7/+rfev7On5+UVZrovMjNBG+qUFE2FJVV7+35khNUVeKvUy7y0RepmLAAmKyEndVaoU1W5Y8tK49AOBBIUh2jV4VKz4RkCVDBae9L4/QqmwEWzNqCtsoKSISOTulRy6vAsy+AyZMbD0FMvU69ds7S8NiSYNNhRb40hpEK2TsO+ykObZb2MQa8ezChMRKAye42yO95c9cuf+56//iPj//B/+slf/NxHnvnlwXRMyXJfaJozHGJmKT2jSCEzZ79jBa060OJ95ZtZz8FQ7GidbvWaBty3pOvaqsOjpWOZmRpyVnon0AkrykjSgT2xuD+6a7rAVxstRBpAQpJV0AIjwkQXlaMsBpuU7mouWhWzMn0BOaBERkSSqi7Fdij0KK8vuZrtcWynw0FXsCsWYwoXNvSxRCnFKJToquLuFVSFmUUlS2bx1B8fCyJUqYLyQHwfaCGVx6BxIWHrECCSKoGOZjJNEUNdIxe3mFXVKW0q7NngMGfkFpsNp8CSAoN1fT+rquO89twPOg1wWm8vc6+C21IyURxy/PBRNexgkhOaV7fQcegVp6KvwO4fxHSPElPHATG25o4VW5gimo+Lqsf+QURmzcVc1WcyWXpEPlQyVLUiXzdVyxARblubH4/z54rQFxy93USlACq98lNDJcjrKX2tDk11FZPinpECXVQhnLvrKEoJxhhouHxQYA1RqRmrae5zKmwsFalUGCh10DCur4tyNOvtiIsI8ZEFOhBTokbvSaE7AFNjKYQ5Xa01xi20NKH7Ytq54pkHlp08psnwtlWoRIOpqsfH4YvtMbVUsk627givgkqYUFSTmblLnJabzOwNfZcLzfYi5ebmBhmH1aKzNVmK4e6M2cKEEugyCjQsvStvcI1TGVVeckrxQljCZLjPWceougULM49rwS0ph1wKuUcl9vYt9iy5f6Zu5AFkQQwu3qVdQVsGoeIqii48iQZgiYgkzIYZIkJ45Y9H2DJclMhu1pTUw3MIFRG3Wdm1XusYdR2zcozBTKk6jdO+h5l1vOxxLR4nuFZVaSPs7TXGrCqFI7EbhdQQWjUOZkk28x1Iqqm5mkSgUMgCqSJWOJJmOkDBNVAmgDVTJgMmbtiPO+fmZr3Mvar6lATayDi1p4ZZ5hJV1/Voz9yOcVqSd1gKuCyLFXT/4KPbmKebv/UHvm3Fs8tnP/Xnv+9bvu07vvfbfuLv/vavfvHmtJaPWaUqEJldcrO8/IY2ccgX8ipcFxElQvLNN9+cl82HbBkAeqzIrGm4UfXCvrhGLJDZ35Kp/TyHEnk6nZ48efLlL33V3Q8SXjRQRTtbhEhAeSi/pJ9MehB3kR1JLMik6elxWOLtaeKx2mO1+kCrgiLFQFbWsT6oPIQCjYQU1cZ44Uq0PiQPAG/mfP58/eR3f+Hlf/Z9P/PPPvlNH3/35avb5amywjQFeqSpCNsNIX4UGTYOfxehqgbZI7VqrOtBvWtjno9DctM/DI45bo8c+lULIGYz00iYVpW4RVFtZAQPr31RpF7H+0JoTpMEhdNgdUVhX1W+YgKRPY8FTbGDW9v2Y8hazHv9aWOwMvZQVRcK5JCAurdPg2RJi5h6EXCkVQOyCMseNfMypWg6eghyrNY+ZCtQi+rwQa0jzVdgKio1YxmLiES3ht6CgKyYE+gVs6sOsaTQwTxyukRkLKOq9tm3GITI7FdAFxdIZE7TzFQyIxfXqFK1KpqNq30lOhZdFZAo0kQKVRnZKk5VJqamFpXwozguqKSKlRTi4Ad2YKweSqNHHZ90qikmQS8tYQFNg2/CsENoS8sFBIg2SbGIWlREQDW90halEBmFa9rShwDdJDmULbcQJDqOFUIMNNW/WgHrva7oeB+UyDGQxR7qPpabh5oKdYpDkKwCgZLjGi4wW73caMJroO1rwf6Vat6pYY3lEuay+pEfVGnmiSxUViZL3aSwiJJUHxSct0sBGAtJVkZEIQ89bBUPTqARrOLBVGwJOZCZaiYiGvDUMinRyRCRdn5GECgRH6d19dPl4Qx0akczGaREWiy975f2QA8bh3NEjnpO21Jk6qpRzcDbVVsXBZKuc6boFGkikg1jll32hhqzCSG4amX7DhcZvsy4VGExPTAYXcqLiNj1NyrQ+nmkCNix82yZglHleBQi2xxCAIX2tovM7hWiO4DRym1I58xkEaxSSoElMMieYWYUdHIifDD2nLH6gPYlKy3z1Wv+c99L/bqqasdRcxy9u4BkmSwEid2yAKUqkFLrOCUpcqX6srH/dvB85XoYkh0P6yWVISAjOczdrfCwbSb+utfsuU2YCGOGD2WD1A2smvtuZoUAqp3GSrmmtBGUsPJ9u+HNebndJd6+hD+k2DtD9Bd/+Z2333z46Ptf/fzdk31eyArIAjWIFhtXWcgwaLXV4Lhd+xECoBDMaayZc4ylIatSmAYpFmxXGCR7HccOiDKCCfrwmnj16tXz9z843dwB6CeiEoUDmdayLRFpROIhf8h9+LrPNHN5XMbDkBApU1HWIqOaBp7ZF+us9MYikvsWwnwsvISPT3QWo2bpuM5Mj//YPjRabFG+nPjyj/2J+Tf+P5/53/7vnr+4v+Wc4iUsZLtoD+9DVwskj0ZQHt89Qm5v1/1qYder+iYPTKZUFSNFtRGGWaGmbddrlmBPPoxQUlqCJaLhAEIYEoeu8fqlxzIWqVRI/y0Ozevh17JwCjroHGzAI9unPKgxp5lIW0XV1puRmUi6HMGCc85nT56+evWqa0fykEMBGjjINmQdRmMxMnu5WawbH9H2HmJmAGBCxXv/1z9VCyMfMwxa15nH2WmtuhIU3MbpVJGcQSBYtg6t13qlziRtX6xeF/BdbJuZyNXJBJGiikpyUUcJCiaqbFXM0Qe3Q/OYnCWAau4e1DJD6zgbq9sjUlgqkiUilkhvaRXgAFlu66xpnROqbDo6WbE4io6j84nOOnBDZSWEh0wmSUWpYkor2ksAPcQQCKZe2yG53mDHtAwyvIFwMueUgtKGaGSnWvnxYnukTEJRB/NEFCpQMxvrwof9QxddH3YQILo9G4N74CC21vAVWW2r6Is0WEoRgwnVlUTEbsJhvsdcllPMJEqEQerwVbQKNWd2pnUvErTfy+J1M9gPq/ZErr4sy/LifN/PnDqkT4ZMlhjomQXdDGnwohGppXSYi8hSzGSCjNC6JjWx6prn6AqKlZSyB0VXYS/64qlgoQU6omqmEQRU62igYRBoVRGZYGmnGIqiKhNXuG5mJo/Or0AX3fd93y9NxSSZmcMfsUSHSbwH0Dz093icqDSnRNAg+0PEeIjo6uqJuXZ2XfZWFVCRTLzuderAsPaY7moqkOvVRm7buaqiMsFZGVFKVR5phjjE5RasVu223P/1xdTkYVUpmapTFSXSkhrBKGzbOSKqXuu8+qc6tOKUIWpEZ8eqiO5coLfLuppqhrGG6GJq3j9vNtGi188KU9VKXAHU5WONzDnn0QLbUShoz/BFTW4V9uknNyaXBTp4ez9cT8v004n6hcvlb/8X/6/z/+rf/+yv/RLuni2XtSWCVtCkAFAJRbvb0fN5UzF9VEoLsW1bT9iqKiNyBlVCchSE3FFbTGQFK4T9qBOx1irD9LTe3tzcteTVRV3U3d1dhJmpbqpqOlScJUduo3LPc1feEWUmJp1poyUQU4pG5cyggIKdSdKEonT3XllAvZ0218vm9dXVSRfXp8chcezhGJaT6bp/7R39A9/3m19856N/78efvPXJF9tDIb3KC4FKoaQYFeqPW9hHMtpxORXdfdjR7qDqeABna4HtcRv9+M4vPgTVELXmkvajfUBZNRGXmBgyXS7KUFSVxod+JYM128NyaHhFVb1pB5mtohcxHGLaVld5q6NJmnuyDph2VUUuYs2YH1dt46N0iFfXKfrVXlOc8iDlspkkRiCqpeDVfAkwuxA5YB1tw4l2YcjVYNZasMx8FMUcPSy0quacVdXXqqr2xdo/Zw8DeyQm18y3x7v1+hmZJF0woKu6lhgMWQapalxw+fVw6z8mV0qPqpsNQK8nG6ytotaP6uPQq+p6rNXgElVyGMVClOtp6NDrj6QiIlkKFBCq0exDQtufQWZmZVaVNrAYRJQWHWKsNg5ocVDEFE2WeP1iRVyMyBk5A5HD7MnpptVb0UnoAprStExSMRFLwiksiWSreR/2+c6rF0uJFRKcrF3Y7YpktRWGDV4XO27Da1hcE0N4Vef0wVIRuDqGI8Igc9+Bitzb/DHMl2Xp6215cothk2jurBU0ZaFHRzGaqpu6QaUvFTyGx8uBsz7eDtezVAiXve7CCpwuvWlNMJvhQfTDHnX1XMGGWt9KlWDHEYg9eupaYq2HXbYLBSQOwamZtY27ruB63RaliBHWC/nLTjJvRiiq4/RMTdQKg7KWgOkC07axl7Xm4EA/P4q2jy+SXXtpZ873BEx4zXGt1kyq0EEj9OBSiZkABZSZqB6DSvbWU47sXoh0N91fizmzSFYmsjiD5DJOe/ESCRGQjuukkWz97OvnfVbNyH3WjJrB6BCt2IvZlgcoxZJSFFLGGCbSaCUFmzvf46+v/7LW9R+ld2+qVJmoike3wOMVGRF9pqj6ed+2OdW9OgjFHB3AAqXY9ZEPoTpt8+cse/eBLxQcppUmGlssFVPGLW372Lf6n/0zn/nlf/nk6Xrv5w6VK3AHNiYBK3hzoUUex1a9zyip1VzMLjGX0wlZEuXuhfQtd0PM8p2XuU/t5cjxikTEl1HgnHPbNjZAQ0REelXTZ+UYQxXtQHisIo+FCjBrUjlUUCXC02khs1xTMFnnzEvVxgxFK4bXdYzRamG2TWPufPyS6zOpCyxc68XHBzMAE9k26lCdC07r53//H5h/5S9/NObl9u2qUJaCCkHD63qJ3CdoNzRXRS5Jgzy8um+5lgK9X2iDeVvgjgezaRuWlGCkQVy0/1lVQlxULoLJjv6kgytzYY62vX3o19e3Ja8fBn3DP77Sw2tHWOeVXx8Ys0d51a4pFXam9FGvzMvWz/KXL18+zjwBPN5Kx/NY6vH/kodK3WAiMosdrMjr5LKk2kl9jFuy2FYFvD5S+laqwpwNoLFW5OUlGJzEXhSx3tiJSNbMmqexuDuz5Kpg6kAbAgdiSK6WbtM9o1R2zjIJBTE7rUitp+EuMCmTqNf2lcOymECVa3tzl9RRECIgO8r9QNxnZstWOoQxYu+wUbQsJsESleXQxhceKwa5epAe65LrG9KqT76u9j4kvnmsMuVxvcLsR1Gp6DKmcJtzsnZEDLy2ZR8cov5Yjfm6Zm20k7sDOqAOUSo7luPggLKqlwO4lrxH6cKrj/nxhbQkODPdFlLmzDFG/34XTYFZ42xFsmLfgcIw4NDcmVlEkDKsHwdWalGYyT4hZ+X9ZTuWgTwEvNfqU0haElln48Xhhbs6iMj/2tt4fd8Nh+3rML4CCmiGRIFiFCuBKCEhnDzEuV+38Xy83ymtqRI1EYcAFciQ5DGXp4Mmau3ulo6wUR2emeuyrOva37TXEl0sf11dIzSFibKCV5r049laHzrsyOu2nOyY9C3mFkf1bUIfuq5rR1heD1EU2Dcyr6ipQ5of2RqWMYYQW2x9KdTVg9sNCg7JGFzR5UyTv/rnfOyGRZkmrEJWChKiHaTrNsbaxV3fA22ZHW3oFKQiFKEoO1JSp2JK3sd+rpmiqRaQLbeqGMP6su5evF/4Ze5vvPEGVKIIsc4Ioh6bNl6VtST7FFvrTMr0mzverZvCtPYzb+1h6EnAetDT+hs/+AP3//K3Pvvj/2j92Mc3x66ktbjLupP2Vm13p1iPn2ZRwKxt28Q0k+1JQFZEPFkWVQ3I6uPOHYvuhlVGc9Ii9orsLrDXjS1EigiRIxQZ19TIvpZ8qA9VBRt3C6zrMGFWz581a6qVpWAPLVpyUGSmTlhh2+a2bZfL+ZAywdx9WZae4hytRh3zoojIK2GUciT9AjCzE09pQtviftM/+UP1Sr7hX/7z5cmtA6mAyio2KAnuOMCxxy1AfayQ6tpZ94XXL1APf2c3JFC2o/UYbAzXjP3IrK3qU6zPiz2jQGXdqDKmZS5ZFgJoXK+3UKRAMqxSUXE18fedYkfmd1XkdXby+kzvW8vMilFAe2xUdbizqsVlkBpXa2ZdVQI4Zs5tQKoeISgwhSGqhNNKJRVe4HEW24cPhO6MlzGWZVGDovpXxf6om2vyT/+pYI9/XaikZHC29/uqBeuPozfZfVMvy6JX/+VjcQnAIQpI0UVFOMyFUB7spMeVQddXVWWKddhhfyiasA0aRulExYlKSEuxFI2JbEnpa3yCmLbn+Hw+R/QKy6hWhZT2RJUlvQ5UTh6YVzw+uq7VlcrwrkQna+eckpOR8rqIuR6zB+6GiYqYczJrcV/HWHx06WOEg8YylrErcpkuZXJYzCsyAnuM4M6slpv1FI2kCNzuTjd99doVoISiwur1/PloRgEYpA9nkgbLWaT4urRmUN1Jrj4MR1SUCOPh4gWnYKaIlHFqbphX3N7rGYmqd9vWxN9rGdEMnyIZQ2m6TK6ToropIyoYSpiomj3G58ykqvcF8Ch3oIoOt2V0aXg8aB8/4tcV0mvrcGb2ck157QGWKdZm9LZhuQlMJi1oEYzM2eVwhXAKAZ1Rl20CgMpl32dU4rFQpQjN5HV1/AhwgXaeaKG5b8dqudu7yQpwF/FldGmsj4DDanfKVJQSKGEigyRLqkyCVdc+sqHWk4Xeo2Uysi0+/QB7XX/hwEEDYPcHUgkGj3/OmgAWILRKahGsQGpRZRV79XC57FHXu/T1kVo1eFyUPTYY4JKYuevooaiwpAowdXcTPS3LsvrjE6izGZD17Nmzm/W225E+uCPKrs73fjklFZITkeOtsaxxeT/w6t5iRw0djLHsPhEyPF6+996TJ1/7n/zFj/yDv/etv/45nEZLnFzUKU6DWFxl70pI0SmLiomiCBWlvvHkGUlR7ZXb4mOX4h6ZeSEZWe2uydr2/V87pq/djERUV0jL6gAiKqJ6jNPDD1vs8RhVWzPTXd014whFnjWRhYTTrFRhR+2dOcYqvY3vdyz3ObesOcboUrJTQFB0tcfp4usR6lE+ChcVTrkZ9vJe3/rkV3/f9y8//t9+Yr7Q5ZSi1za+54OMK7GhqqjHFiaTABL0McS03cFjjB7sQ3tcqSJybAy7B3ITUyKrJ1cCNcyMJSiHSoIXqZdWzxd5dbKKR/7M40vIejwHEuheVgUNWOhP5DDaPh4XbAUNgSG4WU8mEhGtG79sTTtAxL6uay9Wj9ITLb1UUnqmfiV/cWZev7F+uJ8gqVRkWR0dZIuN9zln7o+xLo8n5rEJOoYKeKx6TXTWnIhgmerqZjiKp2ZZvD7ZzVTV1bqjeHyGPXaHxz/dhDz58MwlD95FQaMam4NjmHeU6SSzyRtHKd/0FcEUbsyAKNVK55xzzp7BChXAHrHN2R3VHnmFHVW7AxaoiVCkHGnsfc0qnZlZj01ZUprDtcoYND8en9I80fYpKI8bWYr2uFsBhq+LLcNMos4vXmGbMmcxcGWA4Kri6UqiH+QKoYqajTFul3Wy9jq2k8fhT0rxtI7Fbc6ZmWZj8bWLmDp+Cx/pFkSSOTOkscAiDRTZ9z158FVLpUzKxIabyAJ195ubGxXpuAghIgLKbT9XTkF1rnnXHED15acQE+/h0wFSpK1lKtwHNy8BvDtloVZqZVV1IL3CxG2L2XAqVageLPs+mXFsVBtwhrw2x/3NSJGS3jR114vEdRyVSrEAFXInelOoqlT4WGtoKhLZ1+4iZkns0W14v/EUE3Mdi16zReXrF6KZ020R0xKNHjb1CBf9+FMRa+1+HixhiXmgN0QM2ZF/EtuOSoWsdsxzutQ9LQ6RjlftRaOqiluCrdR9841nkpXb7u4Q8dulW7EPV8G9U+mm/F9bFVAkhEYs0DGGj7FALVmgDRdru/0VPdOkIRVo15CS2sZ2pORwN1ZFOG3Y0vb/dh9t2xYRTdiPSpLBWtf1K1/80vPnz0/LamYZkZmLuWmfehChWGc/VCDj4ZIVJxus4Wke+0UnZ0HmBeaXuKjc7eOdb/ue+x/+vU9+5qee+WnpLVrxQkY73ev4BE3VIUPU1RRgNsKK5w9exHnuWTszM7V4zunut77MiHutG9jbspbrcnPiVYo21DoGE0DlEU48Y2tvol6/5EpfEjlSrVWdVFLaY+06REbMUpXdEEN3l1c1zxUbane7qMRkpV6r1KPmjdj2iH3fYx46wf6LWsfQOa+PF3BfvYMv1jpl1mU9Sc0v/fD3P/zDn/rI536b6ypUJLKt86AJYhwVUl5b/C4ixbSZRwUspzUqC9B2K6o0Qu6xDJJiRrx6eJiZD5eLiHR203I6RVWA5RqglXJLL7WJm01KbehYxR5/DUEKGhTj+frxzOtuSPspdbgKj6Ec5NB55D7nZetycD+OUetAXHc/n8+q2tOFo0ekSh1HT1WrW3H8NUXWwSfS4oBimFzJkSC12AXRYxDntm19Nu0Rs2HnHyov+kg5+tEKMnW4GJBhUawQQ4Nx+pX2o3rf96rKffZFqAR4UJ9UdXe5oPYhD7VtwnNcSpqdOeo4ka0pnioHdHrOucfsOLKqiipKTRSv+1pNohjC2RVd8fEZI+YUlGIGIMN0uC1Vtc29KswkwKgSclAGxZrmtTzSrqTfcrLpkLJlTFapwa0OVzcxjr+OJK59p4iIcgqn8L5mCuia4HKznG5vAuztbwoCDGEqmqvg4ELRYrKmMMDZESPAFO6ozqmUKNni+fPnIsdY+Dpe0iGjjhjzw66N69BFtcP0SlARu5lBKS6LGqp8GVvxEik2ctYi41LxsG8E3F0ALQ6BFha3ZgpIpYHWx/nrzYggr+J7ACinkYxKgzglBaHQsZjZULOuNq6a3Fm9amJJdW9GZs+5ZpwzJw8tY6s6RhcZx7Q1q6eAwVI3pX7Y5KnUIDJF74mLqKsJi5iqMNEh7hCt9KG0ox4JZOph/F3EpBKWw+PITptTMJaEi3qdqmDlA+oDxdDUUd6655CMmmCeSm6SS6TEpBw5u0AHN8aWETYCNkUCBGoydDGSlyol1rEUA1KSsVA85FaWBYvC3n/5anehqc5aVCiwxYIx55yZe2Wp2OqlhJqnLAkveGGYqw8tUfCNcapgXwdOG+5nTGMhpkEWW9z9zTffWNQWHcSaNBN38M0nN8Ma724bJxOmYyoiL2500ZX+1O+idDvvug4Amtyz1AZQsvh6us2kFqUSqJ4v7cWZOndhouYuyQULHZXbrIQBMqEuZeLJBPS8C96Mu0J8+Wu/8eqP/pnbu+Xtf/DP8LE35HxZZH8iSwSVAdlJYZWBCsa+NXBHfen2axdiyM3NauKLLZHidgrVXZNSA8tU30QXHejMzEp1CwaVkDIzX0VZqWAiwBtfSkrBJcsKcOMwiIwx1tMgpjqy8HDJuXPmnrlBigHugZhWOSo85wosMZdItQQTs1NeJGVGJWCdgbMMe2RnReUlZkAKi8qpGESqreKnFFxw61oQWel8553lO37gy9/9bZ/+x38fYpf5YhWRXCo2lVIMT7Pr0H5miClJKCeLXvAai0nGaAt0F3w7hNqP45JKTFiRMzGKJiKQWLRQ+3a+F9ImbCcmNzJNgBqWamEIMCP5+KsKj3KKFC2pUeUgpSi1qKzqUTVrFhDFUtuyktTKhblpAvVQMYIfX27evL1dUbvNmcxZq/q6uK++c4YkfJTKnrtUrgbXEpdWDnP2lIBuB4p2y7NpYRgd6dxRKdrU96UhNjCo73FUw92sKyj9MFAzX6ogkiazZTg9IVTVXuhmJlVYghKWRXUD4ywRKkqUmpBL1tYP4+QdTjd+i8lT2g1GJWz4aTgsW2AiJQypKZU6d4ouc8/V1BSZmZRMosR15CzOGILKZCSKAttR0ypiF1SwMniqZaGvYsVYTa3SzNaxOEx9eHtlyypVilZ1NVpARIrBCiNawyiNAEJp0iGL2qJihcvLc6gGZBKTRTWxlViZ64mQShctSlJE/RJ82NNEmdj36BW7sQZ0pcJlY14kSg/IVM4NSl+dTM3dq4aOKJ025s1Sxl4wUSWRUKbMB92kpNUSrZkVEXU3G3lAZorQ0nFJ1JEVJMPciDvxJ7YIU4SRFy+spirMK/9YqAuNOsRXjhHCBNUwRLXSkQ2L2ZkpChkVIvRdZ0l5P2GVImI6GlO1AVO1J9ilAuWiRjWYE0ogklmHXifTIUNgJFmRuX3kraeRF/bjuWZqlTFrapHb3HRSU4AqRA/Zu0hTtPe0c9Ok7+X+vlmZW4/J1HCkrOiHLD2iwn19+27N+90Xf1m5wBfUvsa+J93NJC5nEfGlbSomBRMRE7RfS1uBGXrVyPCIAZACo+ZwbzFkG9IyU4HMcoopxLzAYFyYIqXqzgOKaxCyLqgosR0o5pw3p7s5Z2bM2E9PnzJTN0bzdTtqufmChz0pHnfGhRYHmEKGeU9Kz+ftsu855/DVxlxF5pzmNmcKrPM53ua4Z2yIBbrCUnBhglgrTUjVyKiGkItUVaA0oTziyXu255ml4u4N+J7zYtbrB3YO1aM8hCQgVUWYTojbq/3h9kaXNz/6y1/4yvd/9+/6xN/5uw+/+1u+evMEisvYFimpJTiIMkVUkSkuwZxVoGiv7lSqao8ZUT3X86rO/WbUcD3G+ZXp2Q3S4zixKA23cRzxtyQuc6dpad2cbvYMkMOMooxUtXG6yWT3q73MKAHoLdPd58YQMYfI3q5ucwFEdT2Nbc6JUldEQXBY8GIu46QqPDbKqIrmOy5uGeEVJBcDzWZebHghHxLLwvoDP1h/42++/Se/NG/fPuPeaeKmupB8osvGaa4WcLH9fFHVRC3uQs3M0/C6jivnnKaDfNUXz83Nk4h4eLioGguZ22kdqkts+yShTor4aZe9h4qjhVEmSaZQ1SD1iMwBwN5296JHy8QPOwqPxVsfeW04WXxkHA6ZmjEZKtxWuwmbVa9yt51no4k2vTqB0ShSGCb3eU41MxvmxXjUmADooJSqUpXMhGAZp8ys9iwU3WzOaWYPl8uyLHPuxxLiUIewZ5JSnc5ThWjhQzUiB2hJipAFrjdrZu4Ro5CKVFOUdTbhsZcutTY60U3MDn9d1ixpoG5To5ViBZxarJABRWbe3N7MSgIbUxe/xK5Cgy3my+KXy0NlQIoqE5ShVdAiEK5S4kfqNQBIaiXppkrdYvY6Wc2iAhGirpXCasFJCQRinK2jJqDQVpI5jPboypN20reU30z3SJLDtckIPWBDI9ZxGHJbYI/DuEyAj7JQJKBlqkIXZs/G3NXddlpUaZtQxBp1dwx9K5gH6SFzPw7q4xAAixCqajDnnGpK9RPG1AoIASNaaVngXNQLLLkoRWRAadwkTbSp3WUyhe2AT9AijrbygNkqtAj3lFKprBsbSGbGYlaVj9b562qskpvATEsEHXWBjgMgwHKzjBJAVW9v1h7GVJWZR4S4xSw3A+QrX3vXdZ0skm5mdZUmkmVinbcqlRBW6HWZJceQhKpUg8G0rjtaqJNU2Gru6M0S2sTSo2OH6LK+ernvxX1ByEv6+SyoWpzltJqu/uZYnuWUCoG5oFxxQBkpSSGU8GNj0c48lLvbId/PFu/02aHUYe5qEJkR5+0yM6Fqwwvc59zn3DNItvQ6TfaKuGwPDw8CO5+3fQ+DuS+Xh4ecO7RXqlDCC9brHIWYH8FwyIYmRkQVGFlVLfKr1hqow9RgZkuHm+77nkhqUudZqkzULAfC6ohFM900q5VgbsNkVT+JrCXurm4997juMLjYsbNsN0gvz8YYKk5+aJ/3Wg2nIrLYEhAdyNxzz+XurX+Gxd97/snP/Qt7YpH2ESEjQwxjXovTq5QfHGOYaitIGz1QFGiXaLFzltRlXmCw1adwfXab4yrUhGXwSF5SLVFm83Yox3inV7DSm2AGGXSKifZ2x8m+AER5NT2L2VDQ1VQ7vU7MhpmJsNEWMM2qQxh8DDzVbanHzHEcqUQL1EHmzMxSeeC+ec1Fg3GxCpbE/jR8PH/5tT/0g1/D9sY//vs3pzeUsMwEJoyk5DEuripUmOpqfmoXUNU6xqMwBIDbkpl+ZEjrq1evLpfd3ZtD030Vsio1aVm6TyahsDb1hmQgexOkHG72uN08VJMwYwNlRLKYGaxMVnX7fc2eAlV9XW9U3WBKpQrUgxUQktOwAQnZTSFmhEIYedljj0wwRSekcFgwD7ZilR3o/NemryOMFph7kox94hBVRUScbm+gkqx2lPVG6dgBFxWGBuU/luYCwZArMlg+JEoSkVQIsWQpkYo0MeGpKJWNN2/TjkMEkKxCMgOVXUCQTNbDPgWVsdvVT7LFzE4gSEHWaVk7LYbAlrEzUQlgss5z58HEPozw3Vcd77oyFXvtl7kby12T4Wr7vpeA1fY9dYEqUrTEm7kBaouJ8hqQoywnq46dTmbu0Ux8q2q48PUoyJLKHmKFakqTQRlgtiX02BzE46qoxw9ZpSlWqoQeqBaBSkGQh6y9jiTxIrMq3Bf3RdVVfYzVdVQijzSa4x3uu1JVE9yyTPwGJhmX2qdCVQdNYSlaHaPNbH+UtDBbtHG8JHEdFLfbLa/S1DarKJCuvQeESGQG2IP6LBRYhfbj9aYAr78Oh44I1WDC2GfMDRlSqSjmxKEYL5EjM6bILMydBecVfXMcxKptZGdZEAkqyyL8Rb6zc+uK89gWiLgonNs+68j20KpwHJLJHQSuwBcKwQUWQBCL1sPz0tIH8jKwVgG+bRddhkzBDh2liY/aR7/y8I5Up0CiQ21LUAVp4aJ4sazoPATMCSGggIdWAqSXBWMWRVCk5xHd0HdvKjCBootSMUET8Y4LhSpVOh9qmKAG/S3/1JG4yXbRyWbQEiGCZdaZ3kear4mWpIjUVTlVVSJahca5q3gGKUamGshKjlEpM1IB1VVdqPsewirhleqgCYQImr2skq7mY3RMH7ij0bWSOc2lKhuUago0mqT1UTjKNyUUvFQo7In7Jilu+6uH07d+83vf87u+8e/90/vf+Z2/7c/uLyV3T9eY3LeJ5eZ0iogZuYwx55RMJRe3gsQsdrqGmfYooJTKmFOhvepvg5PAHntxEh3MJ1eSKIgE0WFeO6jM+WDDV291PTsJLCnaDrejmmjPZUnlkJbM16KNsgsR8cUqEqb7nKpKZc4YZjNC7Qoqj2iTsTLQOtJir7qfLKdX54tRuVUhb0QyJQFfPF5tD5/45Ksf+H3f8Pf//vv//T/9arm7uewpqskSbHJQ2dy9IkS45+6+mOrMHcDDw8OnPvWpZVl++7d/e1mWWRlTTW8i9yqagcz1ZB3JXlU7RVTaDk5LZhxIqyOGFZ2DoiKMpAr5elFKNqmnkfKl4vL4DuIIPFfRzKRy3y/I2DLbbmtmd7JyYoJLUEFAbs8d+x2w4wQ4wiWUrBJIUioOcwV42CgydlVUoSmJ/QRqJPtHPvLW8/ffhxyBCtHEOn7IWNxIliKBBMiCHa2bqrW6zZq8Ydbn5rZtvDrjKdhERFqPfpAHznoAQo6nlzRAhpaZma1kJmqYi0kQbXc2k0bV7rH3G+hYc9IWGWaXZD+YRZB6vC29+wQJAVVUNPZIqTHGEI2IqEOIO2wtlZxlxCXT7EAPNierR04HIo7VNsx+RLCEzBAzgpHlogZIPc5BqkrcVJWRppqZy7K0TDwevwlwTcMBxI5egmFqIhZ1BLipDgpUqo/ZnMGEqFg13rM5TClHCgK75SVpZvt+EelYmXHoaomqomD4cPPKucooyoWztAZkNW06hc8KEzPzZESElYgsZVEESotmWh1UIVLk9B5vGLr4O84/sgHaqrOy24moCROEgFpHiMPVZ6Xgh4RaOCK5jJLLMqqOEMyYRXJZljHGq4cHEQOzP3dVtaHJWCBbZqkmSsW6FVYqlamkoUQq4H/lvf/za+vgYwXQubPHqhxHFsgVpnbcHzye2uih9CFdMhESLEIv0o9nALjv39abHuID4oqg+jDEh/1/H7/lh/4fj/8rx98lVyH1o2DyqsT++m/5+utIX5DHl3T8U0QA/s/e/Pc/Jh9rxf/WKWrEKWW3pth3cLqqahFWMlluC4C8BuiZOQhFZMoyRlFUJSJAgFykpkrL4JJ8OQqATC6qpdK0NFRpqrUUjGg2Sc9u2U9YEylrA4+I1LHqZ2aa9ychODT30s8+aIiZccy5B3f4yTjP95cP/uyffva3f+wzf+snv/gX/4JjqGTuvg0dpdvlAhHBkWqy2PLy5UuVoSqmCtGqEG0WPMVt7ruPkbMu513Vz/cXKTZttZl7AmVGiVShkyK7mQMFig7ghCKqNFMBhVRVCiiYVDNjJZmGsn5fmIfA4dGx1yRHsjNtshW8199jwxtC2SVUGwMyw8w2wJTMQqlAprCERTyBIeo8RobcS5racjm/+4N/5Bt/8ife/vmf+vIf/OP7qwtOIzEh5mTnP5Ds4IPKChCVbpI5l8W/+tWvtuP5srcrWbsLHcNEZN8vInT3WdTjUSFVoaI3J79cLnu1d8cHD2flRCbStBfG8vVXulwT1JXzqmyHkEgVwAwdgsaIXQVqAA6P1lQ6ZZqAmlUXsxOlTCoKV5qSEspqf+VOElKZ7m6mEYfbuA7WjT5KkXt2lbl96EdVkuwcR2YLdVFHZ3v8SLRiWQfoQh9lnAHC1EQSmY0bUC0UiZ7INxyRQhZEpAPARbTx4ziadc8qqe7Zha1mZ0KZydu7257cmtndGJfLJSJqQaBe3t+PMYYaI2/MydxBFofZup72fT+0rmycjpP5sG8mvq4rpR5e3d/d3Z18eXl5MNGacRrLBA1EBTGi+dU4NOEJ1woREVb7TYvClMkO9gkmVQ8cepFm0gDYuo4HtGd4pJXwSjw6OC2d9oFSbfihsLqxFipnFaRERRv7lqkUg4JgdX6cEMKiqriOyPbpUg81N9j4fe341P4Jq6oSSYqWFAoCM6tog2K6LVHliaGSJlkYQYCb9KOVj8f+9QSQNSkdoydSijYRkFxLXNEgF19P67ren1/tEapOpFyhdR/6Vnq9AzsToknUkgfnq/raUdWZTEYVVG2Y7XP2MGbGZmqs44/j+pDqCetSlCpVEWg28uxPPfkffcQ/KcJkEzsAkYWMgqgFqx5tGhQ/aO8KUuVIBHNoWiEpc/zz9/D2m29+6mb5xd/63J/4PW/Fpu988N7qa15CbOyoUgxbpKKLr845KT4+EEPVccTFE0dtpaHNH+RqYzJv11PMvVQ6MDyY7ZicmR0Hq6oDCiANJLzg7nS9XB5MjUEAOqyK7+xf/G/Of+3CyxwySoS1oaywQMXUQLqhURpkdf2Ys1SSpbCqNKgc2rFKGMlqwX0cSB0VeqKk1zGQKL8kjDT1WVjM2AF9TMUEq+rGhwJjVkUESIGJavVADqqImD3GXH30eXckOeKAaBgALajKnOrrhfnW6Y17grws+/yq25O/+D/85r/6N7799/2eX/wd33L78nKxu90WJSLmsixqtu9pw3UZNK3r1keEYibCitizxI2iAaFrZrpJoaku7AdMX+D12pDOAl2tSM3sDCxVLUY/RWamazP1tHeH132VdmwTRKpqy2otcdSsKl8GgMxqr7i4FRNZY4ye9/bG8Tj1P2QbW0NFuG1TMB72+87mNF13RkmFUKekBWz4B++ev/07n3/yGz720z9z9wN/7NWAswYrMFi7jtHriS4NbYwks1rl0R0ou/vpn2GseX7YzEZVDzl12ztQZAdpBwQ7M6eaFcOwABDVIBXFXq0JOj3ow4VmF6HX1RKvsy86oSIt3C2ycKjGkhxmEXtTIFBRagZtykLHcIJcTYu1N6aKOFCTclTVj94HQKNyXD2gnST72BVFxNDx/L3nZqMENSeAsYx2ix59/NW42CedaOGqyuyzG+huT0jOGT3fVpEsqHpaCtWrjRVHN21sFcWHN+UsUo2mztl7NUqXAJFZabIUNApk2VWMLVf2bKtDREzcZpUo6qo37u1JjwgKNB8RM2qqqkNyn1RZxxByz2BWr1EPKAygTWaHKEoBA0u0xMAgFYC1IJuN4FYzSh0MIFLJ3vYXpAuTA48/Y+sLoq4vv6fZAPQYCcjhFmbWFaAlHf+CUh4/JOvoELPvS1JUAFNkj1vNBVmqKOR19UAyvbzFyCIyxFicOVV1w1x0DLAqJ0vdB0UrQ6SDZtubEU2PL7FFUVKZwSg9Nl2iptkwziPtL7OUTHCP7bTeEojMebncPzzAoHr0B831OxqGD11gPYroBNh+KkcdweR9qTcGZJ/5aN4wMyKz5rJ4Zu5FmCyKBichuyeXBy0hVKhgijqAt/wTH/PPXM/HbL24sSqh6lTp+R4FKs4KZDXE0cy6JU+k8+E+3/pbX3rrc3giv/XwJ7/3W/78H/2+z9irX/iVr+zzO8P9E8/efTq2+80vEyfdTUe3+Y8rjR5iMOfwde+YIVRVLeaH0BGCygGfUgsWyEyV5ToBNrOsCquZUchRg8p28RvLzJd1lcXv88XivtyNZVnef/6B9Vr1LDzSakULAyIFKHYhInkgmBQ8HiiqChMcs2Ntnu6eOykLTlQyjqWIuQxHZs6Tx0QRMF0WPxWDdWGUAExvuxhEslwh0D3LpZMwm8MPoVQEzc1l7lNEtm07jaUqVTWLIngc/AIloqK6R7k45wyL+/v7OW6IeLos/uL5l//wDy//4J985sf+9m/+L//XL1/M29MZL5BrrTenqmqBTES8dz778COvKQ/qqarBhxBeZe5zzt7ro4ncRXVRkdlH/NfTGVVViqFAFQtSGQnMudzcrmNc2sAWNIOJBquNxS4q1GL7vKFuEaHgGIY8QBONJ2u7XtVx+jQZb/H2HUo7wgEM08q8NzqqBgzGqqFApTDOgKLG3IvQRXdyZD6zm3f/6J988yd+9KO/9gsvvvGz/rDfQF5RNy3s+xG00ACjtq+Yzcyqcl8EkmR7oEXEKm/W9bzNMbwfBj3wd3egeTji7nPO82UHdEUUJFX2TiotrGoD6sa2179+Avcgt6+HngAK9CjFD0AsCIVBS68uKfVFCYGlM1T8mHgD5I6oSKf0RqvNtFVRYLIWXbrACJaU9DeHqqs356RPqzpQfKLQHsJ3uzDGmJe5LkvhyIASCBzsYvcKJu9PE5AkRZnFm/W099IT1aHZmZQSFy2rNIAc1WK0CoUlRcSu71UJhKWVNIcQEArMx1DNlGFGyrZtIpKJiNr3XYRu5lWichrreUayVG3PubhbaUlFVc39UDkIhKicRuR1VyoipdrOq41zuOUsGR4sFaZUQQTs7InqvFCBVYWaEEey01GKKpUsI0JFsliEiQlIdlxIPT6A205GssSPbaegB7gdyKZiyd3MMoM11DQzRBPXsV2mUgUkRCKCakATvnvOqT25q9hstL9/qiAzx1ifPr07v3wlV05cN0t7BsHTcBq2mSSH6NNxisrLvjt8KqP2QQFl9gQQdgWME8Awj64IodGP/57BVvfYAfJ0exvFrQJQcxdSrRviUkCPjBNhvebqV/XK4yp3ghpgB/oOEftj+d6TeRFEzHVdZ0cQ2nKEU+mRWQ4WCVGQuZYqC9kZaOIkJitYDsURj0BtKKigWAu8h4XMglFVrWc7FJJGqQqivnr7e362nt6+cf9vGJ+/8m+881/+ovxHP/uu49nXvvLOF967X5/d/uFvefLnvgNP7J337O5UIuJgIvO6QnARWYYvy4ptzsqiQolhNcUFCjn6PMicc6ioaqmKacURmirFISiYJqeBbieIEVH5MLfazouqqyhrPz8MU1450law5MVI46nERRPwZBEpnY5pjy2OQiHe5TxYYVfpqXry3G1z9f6A6j5y20xS1IQqyRSeTcjSvcxPk5WZj9Azdzut6/sfvNjdxCjAKNUqM93taGyWxeecq49+nrHi8JbJIWIUVGlJiWGk5ol1RtZwlCzLuimXfYM++8q/++999K/+p9/xEz/+Kz/0J+L5+3Z7gtR+2VYfw0fMaWZiDlSmUil2YCZwTHcNyMi9TCN3qthA1DTT9mC46KMbODOlyE5wrVIdYygXWblQADK2y4NU2y6rGVUR0vk2pFk/qASqRSpkQAXUYo+/qqSir9Pc991MFvdWaBcwt92Gi0lz6110XcfDw8NaEnM3qCBbcA4wK93WlA1ILHoLnfvcTrcP5w+e/9AfefZf/LXP/MQ//tK/9zsDfN9TMm+JC1DRwXBHGrkpYo+Gl0X0gASAutucm8oo0mxU1czdTIphi9QUtyPwwMwgllnLslzmvdJNFi+4WFVRLUWAyEo+Mn8BqhBa7LmJeJJGNtA1G2BDRUN5ZWYBwuLdzc32cEZhUUXBgAQjE8CiKqZ77lQPkJUOUehQSyFJ66F3VWNrg9nNbluiAdzd3b18+bIqluUUlwkRgskyX7KnFDOgLWAXkki0nEhEUYe6lSIiGkkKUnLWBEpV93lZfYjIyXyPSC2lGFUg1DpoTcxQcbXocZtI93+pCaYrTL3QD0WRoi0DosESEXW77FvXEAExF/exxewrmZGL+Uk9s1SRgi2nuyMBogdgLY5DJyNRWxA7VCeTJao6WaaorFRAfUgZqgQBB9RIrxnNG6+rUiiLBwTfiig5apdeobt4PPIHTUswfM2eFYlDYBCiKIamZV2PwdPNen64RNJgM7fFtVimBsqcPQ9XM5kZTa/rMklEFFYiRbj6ML/sm9uyrmsVzudNNQEsY+QhYr3a7k13lERJlJvtGc/vHxQ1xogqT7LT2qmeVVAMzW0zExdR1XVZL1sTX1K9oZjo1XuKhEoBtu37Npcxsi/RokKGerXVSO0YDEhVuzMUcpSeR8qKKqEmFT0LMZMxVpKZeYlyVzMlPSIEGOYPD5dlWYxZkKyqxu0ACpHi7jaoktXCSgfYiru9UtUIGM1os87aM9UjI9PVW1OmD44bylhSz/Xg9a5898+9/+yf/OIX890v7nF3rvvf/ZnbX/3Vd//az3zO3nrrm263b/j2j373m5/59V9758d//v2f++Dmf/rdH//s7de+Fmp+66Eq844a4kiZznMhYjdXmymMEsy5qY0jwkw5sWuxaWcSKJ3MaAlJVbn7nogMW9VTFl2ztrtnt++/eH7SU1EoexRnPwp0AMAEwQlOhBEqksqCidgExAyRAprL7Xp7uVxmhJgUNnUtBsUFomqFJJOifXbYAQXCOWecTFMPK6YgWArLFHFfMjtMLLoScs3a7u/vbVlUJfY51GBIQRQBPemB+8qk31inM5i1ExrFTWEquthaOTmnDGXWfdXAqUTUJonc87z46fyF+W3f8s6bn/yGH/mR59/xez731psffXjYdTyMpWoiqS6RJ9gLyHKibBECPH365OX9q64YTqcl9hJIPy1YNPfFdd93EW0L58xwNTeTIgTphqjhzlmpIikPtXsTUQ05YarJBtdSXDjLzdV0y6gqc6vKjFAdATFxDWhiWuu+CixjqQlUZ6aazUxVnauBcKoISnjOub2aJ7GZAbq698Je0nV4VrmEhqcIgD01VbXy8hD2iU9/8If+4Mf+yU+99cM//NWPPvGzngYimYSI7nuoelQSFCkiP/WxT7/3/vuXy8Xcm3yMKKXSskBTzxmu4/bmdNm3IsWOVCjtaHTW6lYx1QyFIpVK19U1MCuLovH1U2gXVxWotScYXkpj6t6bVRURT2AiV0CBAp16Pp8LXHiwlJtRrAfJIdXEdI1tf3pa1pvTu++/L2PZmX2SJw4taOf1mjiDoWRwFMzs/vkLqIjY+bzB9Mac+04TcFp7QBfrMW9QOl9UTdnheDK0aLDqobGbsnMdproRYn6iaEXKoiUqNUUOpxtF5ejgVMUjA0o1Z1ZmNcUGzACS7a2SUmnVknlpAcTNspxsPGw7Sqp42fdGNCB4cxolIYZglI7mxb519zQv+2W/6PBZQTLUtMiSUglOh5fKq8u2+BBnZjY6SlWf+IgoU9svG4B1sahorOI4tuCtQKW1QFJEMUFUQU0VzNp1XS97FOXUUingAkI5VN9+8uSLD/eD4qkibm4NOxSRIUvRHu63JDE48+Hkg3v1Fv/m7kax9TMGxbu7u7mdTRWqIlpVSgp0brvc+h4J6GlZTHWbZ7XY5z6g+36B20S1j9kgRjHOKNEjURyMUNfYNxdPCNz2mdqy6UqbJb50ulSyYn/wYRVTOaQsbWNKJlYG6xmW+WY+4+0Dar2EYHkxVHLeCHYRuZd6A+sb4/b5q/u6ycw7ZlGeLxgqNqOZ3YIj3S0NlpKTxSxFqCqzfACBPYMqpZASJIcOTBb49Okb733w/hiDJd0JTOSYhSNlMHSmotetVQqCaQpBqExvGYhJuZZrKqTEk+M+T2saTc4Vtx/7nP4bP/qv9Md+6Rfee/7y/OwZP37rd+N3fmr5p+++J+tYHx7uX7z/D3/iV3/mp7/2ez/72d//HW9+9fn4j386fn1+4tOnRbZ3z8Lpy9mX3aosF3JQMLP2WUGFrbosMgaPJZDZMTPuFKNEHgTmKlcM94ywpqZlmUlxN5PL5dJD09NpeSTbtaKqBwUCOUEGZdDsIIyz4avIWNexLMuMuGwbOla2qhJWCrH+u2blFcqv9aHTUFscyIKU8nB1ScvViygp9xB2YKaLa4qFDFoDd0Rk1uw2IuZWjG2Ph31LUEznnMUQ1cgcFC9oT77JyQpFmBDZOQe47n5ImsiSVWl4/vCb//af3rflM3/nx25Ob7wEd6tlO5vfxcmFXrapmrEuTLhR5XK5MMtELZnnDcDlcmmCbv/z+LGFFKjISV2jck+qhGJMFbEdmuJWrhOKEVR3H2OYO5FtsXdRBXS4eI9DD5MigHVdqdLgvQJTMUQVkgz2CQ5rEuKRK5C5hioshDuTkV4Qkd0whdmj86bwMBukXLGby+lmWVbX13P9wov33/vDP3D/8sUnfvFn/ebNu9VfRelyBPWYmUEa5daekM9/4Qudc/XIgi6yA+dbnJKFqtq2rVOzBCVKec1KbIkJHmfMeo1TRKesa8O8Xn/1d9svmxTHNY0q8+gXD5ERYHV0wX3BVP8tJimAWwq27MJTA7xEnsYy3EnZL9PFhTBRyZAPxQP0D9C32NpETcGFGQp1c8UQKGufl9NpsU5VUae5qmdNBYZgJUemZgAl1n6eRv2lGsCM2EUopk4ZBacUGAqSg62sfoSg4fFns06+7beziZIGsuMo2r51nUAKqNLR6z0sjQjG7J/kkR9eAlEtSkRlJo9slXy4XKgiLqpqVwdaHaTU7GEuiouPK8khK+G2qHh/ypn55I2nb7z5rBMqXJxBxdQGf3IBl66ORI/lTsvLzUzdz+dtjOHtDbtu1oTKkss2n6i5WjinVSId4iZqiJqvLyrA3fuQiV5dXHZmQRXDVLX2eVyfr7NtxEyWtQ8hpdj9eXt5f79HHQ7AdZF1DcLMXDQjtMgZe/RsPGuGC0RkZhRkZ6YgKiklBjG0GCUFJaUKZCm1Jn05pWIlRuG2bscCLE+eni46333/g1/41d+6T5cnz2LlOD+cvPYsfy51O4G8fPn9d3LUnKP01S57iFMaXdI5aRhjnMZikDamNL1xn9le1LlnY7pZZUllmWpJ54Tmi4cX0GZX1O1wiXmrQ9zMRjs5xVwFguPozNUUtZtREFMRLNQReHc83UWnS1xuavvacvPpn/nSR/4ff/dXfuErXzqtT5699fRJzMuXv/I0x1Osv/nOfc39XO9/9UH9Y3zv4eV/+Xf+8Xj7zW99tt5v8R//9P75y82t++K22tInTxmjkY3aENPrSK2qsuliDRiTFpr35TJw3DwVV4NjlYi5uIpU7UBFVId+idfjo+hf+5qKUExhQLLR44227htYCUNJNZNvjHGym1LzgrnY0AVKFbtqLesaPlMVWumF9ve9jnkoGmSolaDR0XjEc1IbWg2g34ZEishQW8Q6CaD35ccsTQmpbBXE9cyuzMdopobY6eu8bhHYoqbLzeXhZX7iG3/pT/3Q7U/8N9/+y79UH//4cr/rs5tQu0kLyCJTSnaUGGxou13HGA0EFSD3uZjXjK4Y5mVbfbjoFcU++4DoDyWT8HSjMkyDHqmhWgPZ+oU2VmpjKZEAZsbMmLmL0F1FOOc253b1qFdJwbCYLyodyiHXNCdSGqFOSptrvarliWEVlXPbB+mH5pw2tJRTmCadV3O5PPSx23OgMcZ+eXn/7b/z8ru++9mP/60nLx6+NkRiU2Lmviwe+yVr9o6zj10z6xoiWLMlwh0qEon+IJbF3CMqItog251vQwVaaCZHcIX26Z/XQMOuzDry7MO/juKyUjIenYj9fvU1YIQAr9PRHwsMwepr1y5jmLqoS+O1z5f7yIzMLavUiNfBEo8345GwVAT5ELuvC0klbpeRc4+qFNyMRVXVbYgbJBWE5iwXLWBHXSQ2zdCWcpcgRDomPhqYLML1NAYFQDSTIss6XUoq1epD0RRT2P/CLrRQwhY3iRBywDrEvt44cUQF9At8jLKAKHF3e6p5PFXuL+equjnduS2uWNxUdY9t54ziZd+2bYNqdh6xmbuvy81R9xw3Nx7l+n239mi3U332KIqZmZuxFlCFWXgoPFTt/TAmeaRqisxMUtRtZkgGAQwRVSkisqq2CiHIlMaiV/T67/HcGGMwy1WTQiClTUh6RpaKw05UFdmvK/xjFQoQ+WESS6fLdGLj4dQv5Iy57xUZLAJhMl1ExrW4rIgQpY3RoQLtmECvCUmSs7KQlOqy2cRZFhHJPWHjbj298UYGPv8bX/lXX8NP/sY3//Tz3/2ff/G7/tKvfNevfPnOav/4ad6qnVxOckN/8gD4G3cTDyhYnRaen+qpVFppW+RRbDFiziqoOuo4VfYtMvj222+bmasNaF9FZBYyGCd1mbnaULCzbLMqGVUFU6p0tp73haeqj5FqgGZlSmv4oUS1xxQslbOF5fbW04//yHtv//Vf/K07vzuf/HK+/4jcfHyJ88jf970f+VJe5ov3RW4NN7NGyR3wUPvdP/rnv/593/mRy8vtKx/M/+9vPPl3vvOjy+VBDMmxcElGaWy5A0pRmqcSApoaREUik2Tj2q+P0cpsA63u+06Ku297iKtAqsJc2eEBJVTOeQEHCKKHi+AjK7XJtBTT1xW9iJQwYy+VPjWYYLH5U2vKZulRAoTCk7MOqF7btUheN7vQKm2ch1BwKC1UBFEiImAygxAYTdglkWkzVlDMzGHWgyaR6+PErICKaW6WaIBL8RCUlTQPiYfMuMpEKo/mYI8cui522d97uf25v/DV/+7vf/o/+0+/9r//Pz6sT4pFhm8046A8VKmKRknBpOPtmAq6pohSWzbf/1jvbmcEqhYbW0WyEgkFixZpLRwHNAXQVIFax9ZWzTYjZdtS6qB6LT6qqni0ayZHsNIhkaiePEtJtUutRcwV0QqyMca2bQapxklnkU2mF1FRMk2FOIggRW0tqQrldWISAFXP4HZJZ5XLr//BP/zGf/J/efvn/uk7v/+PrPn8/bksaq9evbpZV5IPDw/qliySVdzPe0cIZKYAYsrkMtZgbTElo3G/N8tpWZaXD/dof2obprWLQMMRBiBDtQnDvaC6Xdbzts38Oh8wpNpBWlU8UvIegQCQOv57K3FExESPlWelpt+o77kjMXzJzJhzmJ333X2ZhJtSWOSeIUjQQLoqr1rlzFSR5WZ5uNzfjCX2uZ3DTFNgw7VUbNyft9E7mjZBzbIQaQSxAICD/RCodUgLYuMYx+KA6HaicKmoAK5HuOHSJAAe0sgWQ6mgU4cNxxAFTOkb0JRXy2UXLkCx6jAuVVWFoDrdqxJztsSvBxkerMvcSdg12JHqhFIkCw1YJIWZMHhBVZsGk9uuqkyIIx+zqlRZUtDLvgEQlb4CBUhuoJKgHK6Hg7UNUWiLTgQKFRevKkPbLqzxda5WyM688cKgKmVnHhlDpKuJovPIL/s21put9sVGFkwEVFXNyg0l5BA8evxUpI/jD/KdvS6EEdR8PXKryM6L2uekgJEKEbOcJW5LdSQoiMxK4RjQyMRVOyYwr5YfN5YRJgdcyuaoqss8L8t4bsvL33rnN3/rN37+n/70HVKffde//OD79du/8aOfOkO+9Fc+vz+TuFtPv/9T588++dKL54bVBc4JB2BfLDkRxvM74qQc9iE2KTp85pRyMmGaWdcjAu+8/6UqVUIOqRp7bADBe3OKqaVlhBEmrkDtrKGWXpVARaaThGCP6e7bDNUlEgJ3qY4kDkVWSUEJLVERyPwb76x/86e+/OSpz9pvLgb4V+7thSbyyenlwz/53BdQxZt9Fl1psW6APAm5t5//3OV7vuHT599+55e/gvvvvHV5nkVfV6vI4srlwq2788fsKpHDDdQDtMzgtfhCVYLZca8lY4yxLOcZOedJncbhHpFC7Q17j5fQ8sEWOl9DYFzVzJKSQIvGs3MzO18BOATr0BKgT9Kb5WnpfexVdaMjhyyTPXMWVVFmP8VVhTABigeIvIc3hyGke2BDr9JEwDJIRCmFRxN7GDyuXoc0HFiJtiArZCr6oOkYlyMDq5jIHnzJtRo4Khda5qY3drNd5vrWu//Wv/3k//YffvOP/9c//6f+dHzx/WXZH4Y7akLFeJu+4Ygy7SJXfbRGV4dXhNjRCc2MmHMMyyMRTCOjvVOtysHMTahmAg6KU1nkcMm4ubkRkVcPDzlnl/3MQqSQ45isnkVEbYiIqW4sCp0CcMsOH0QbGR9v/u7AIDBWqpaBiQU6YKEytZigFCgmPmfyKtWuqhZoHNUYpBMS9+Xm5v335n/vB+bHvvHNf/iTT3/ojwfyZHcZD+sYRxIDyWNdXe5GFRvuevDZ5ZoOm6zHYJ+G2EXUYb47vD8QdHYWiUSRKmK22FjUIvbMmNuOfJ0619dzlRClqiqaFa+HHyLNNu6ONXD9bVBQ+GgoklrXm8zZMmBVm3Muy6LqcybQISIJlopAkKjhNwcpVqRqV3XMTOI8dx12WtbYp2Zij/ssP61qiuo3KgDcuL+IqaqmpkBVzR7UC5Y9eWyKOjFMVNH5TkoMKERTOE0k6ZSoI2jq6Mq/rihRtE2eKDn8LXWQGAnAIHpV2fZnVFWNoe0TJjNjBq+wCGgIse+7iEC09myVaETVtcvNDOmZdtWlwlnMNPNCmNm+bUP9QIlRKkGGL6OBbqoa+0S0zaErE5XjRLqGOIn0p1OF02kAeLic33jjDZz3nXPOaTZUOHxp36qJocMmGrcogvaUDalgkZlpOroWiUwVVKIv/tYQkOFqyzJE5FFR9X6+8/98/h+0XFdwXLuPWAcegvoD44Dr77oe8PjQZ3XYUYHrN7sCJPq5gDpM/+g/1QfdK27nS9asN8T+hJxPb77c/uXIn68530nVsehb9rXkO8BvvC9PX+1PfNYZEAVSZJA9b5ODbyFXH9n1wngkSwgOvdpj/9bM1///r0fy6+PLkQY3Xf9kvyJ//R4cRtK2Y0iHIhxpVg3eEC0R7vaZp0/W37ik2CtZHLbh/nZ/Vb6+1LtTxmXLVxf18TFqoGbILio4bdsWQ9/YKP/q1z54+umnH3zt3d96+eS7Prrev8iTAJLlEmU3vnSik9T1cmM0LbqfRVlHBG8/pIPVslgx3fd9zlkQd2dSqHuQFAPdtFiAfWhcxuo3/Xi/1MSF1R+qNtGe109dRNQzs9HwYooq2fezwlgmmMKRSGvJh5iJiJqgpCBAicpSMyr3nhBClRERQXMyrUpUvf2dhII7kXsTCovAwTFwQ2VmjdNpXZaHhweFwFSBhSJHFGO/eWKmEGgdp9H1gXRcNyYjl20EZV3wzhe+9gN/+NlP//NP/fX//OO/+3t+7WOfsnfe4ZMxC55jlayqcXfatg089ohWcBGUhZUN7z2Wucw5e2My63Akjs55UztXpYlJCBsqh5IKKZJaKVWtQ5HD5nSs4XueuYxRDuzN/pCZZUdi1euSgoIh2u7yR9/Lvu9N4CJSmi6Ftge0xqeMqjw65N49l0oKl/4BEmbGqg5IFxEGap4fPvPJL/7eH/idP/qjN7/0s+9+62fG1x7ofOONZ+++/56IrLc35/PZ4QXMSgD7ftmLZkOuthBFR5U2FruQErz64qUAZPdYvU0gm3VAVDBU/Jr7p9u2dd7A452vAqhW9eK01mWpQ6kq1+htkdZl8oBVkJRrGNZWu69LPwLFR1aR5adF5hTWEEhjszqQV7CxHssUCiB9h2BZT68+eP90OrF4vn9Y3EktkXFa99koynz6xt2tyMuXz/f9suiKQu+6j+ZchCJmUnKgmipDlW0gV232hrFHnB3JLLKhTD+0tZcWtXKBCYTMbHvCNd6gP/RG/2aPxvqcud4qAAusRL976vbYG+SMnm102K1kg2m5xySpMG3CQU/+RbQDZTtCQoBebmeadnodcezXsjdWFSlFMatMwXqMw3F4T1VHHYJuqyqDNEjS1XKGqiBRVS2SK206gpw4NsZFsicf3ngWyrZNF31y9+TFixci8urVq3Vd1URSd6aKoKrPmYCUyt6sm4OyMrKmQP7M2//jm/3psiyPD9T+l4iAjqwqBgquCqllLHuEcxEropIEVEpUQczScZD9jktWWLWM01JV3awo9twz+fT22Re/8KVf/41//i3f+PuyXuV69yO/+DvyyZtvSnIsW7ySr0Du4o2P3N3VzUvO96f9wOn+ez/1+ZxWWENeLXZjKXvsOWopF9EqlhSJyACg4n1qCSpZUI8MoJ7c3vESAUb7sK6GGrJ0+IxQM1YN6RhQkjTj9emuAFxEUBi2ROxmGhXunjOKBKjFARiF6imAio4X7/LmlzbneMPrnvUK9eYFb7pd9lcvP/7Wk9OT8erlF2t50+wmAZWns+7HK/vIafngtE/Olw/vb7+JTe4+97WH3/VxES6c7Ec/kWABkDpWjMe9LWji2ePW4XCyEaebm/O2kZIZnQIv4D4vJxvJJsnIMR4LiOo1nbYrCwGka7GLYG9+EOkKhaJKYaksqEC8fXikqri7oraZkiVjcVUUU7GK7kXlgUo5VjztlevWWayzoPVwIjb9VY6+62DPEdAxrGF+Um0VR4oK+l6F6hEc5o9rGDMoqezjyilOAaRsqPrRD/RBKxKZu9QbU/bFT2EcYjO/8Bf+zZt/+tPf9CN/8/3/+b97v97cRb2UMRBS2ARrn1aJlnSxuM9UEROdc47ldInL8NPdnT+8elmkNh6kyjrDWcxdg5k6pChhInLAVQjuoobtMiFloouPAmdmsqCGDEbKlaLY5vFph1++OtZbLJEU8WtbgKN9vPb9jahLZGGvolRHu0wtN+ut7DKaalkgCnRfeDiJj41sRNrtzQa7e/ni+Q/+wPs/+RPf9s/+yZc/+82nfDHWpw8vH9yWYEXEsix9K4o0YFygsriCumfUEf/SZCpxscyAedu90Y8glqhUJq6TVDOzZcicEYFIGTbGEB/Z6+YPfbV9UYBiB4kfPuGuaaAq6ohJENcw12JRD//p/vDQu+cetHZCWhbcOga4siYEM9NEIejw4LoiKsV0Ztbc7+7u9n1f1EzGvkf2Z5I7WAcVJ+YQFTFdBxKzMlm9+VZ1wWHbPbSL1bc/RcSXIVEpoAqjvM8MSphYlh+4GiQ49MhBKKmje2wYEwiUuUm20pt9ICYIUkXrSG5vOEOPzpQq27yMMZhBSjNw9n0f60KwkOsYte/DNJNm2qnVQjAPXU9/7jWDgtwSVXvAGOpN3Jb+hqrq6p15x0Jkilc7jsChYmSaEDILS0dWiElEsOp0Om3nS9PFhzmDajbnJNObeINDNqUtqyddpEQF8urVq/aR39zcMDLnzmEG8WAUOHy6DBkVGXg8jZsILQSe8qNvjU+4Oa9hfD1F5+Cz0+395TwjKByLVdWyns643OgNkYWZlCpdxjIcuZ8vFGmqj4CkmaHE1NyrGf+CTMsQar2xvXP+9jc/O9/jbcm+fqdfvqVqQu6f6Rsv5CP5BLJ7fWV90L0yv+nt0z86374h3/G93/QvTg8D/s3nemVG+NjlMlKlXWy96DGKWCWEs6qGKwWTMB+Qqn2uY4nMDhV97GalaKqTIS4kh7U4oC2sUO0QsGY04djSH82HJDkh4QWnUGUqpnYoB5Dl9WTb7Kvn28WH7UPj7VMF6t5fLTfL6UsP2y//1iu9+RTuBsvsPmU+HyqmNRO6Pr2RMZ58hKdP4PSJl+dbuUyOsbmy3GatzBYT0bVliyktjDoWP68NZHIABWOWlDx79mzpJBygc6yyJgHRI9Szg1kA/9AhdW2FRQB4wJJW0OpNMwktdDrKa0WlXnMcg+WqMhYpySChDitQ3DqosfPIFEecdUQUpU2xzZ3ve8BDrdpphARpXmobM/JIbjIXHwopM6meJ4tsMc/bpScFUWVmC/UkfrLhQ9WFjjKmNAVIHr/0Kv4+FfeSk5we8iK8xTtf5ac/9YUf/uPLT/3db/25z4+3PsZID99lXowmnvf7QlnU+gKSxWlarshy98pcxog5z/cPva62ZA9hQnHOeZkXF/WCslSxyx4yHekVPsDlSFB3tbZOXj8dpQrNqVJqR+x0ySHRJA5toEIAO5C5x4C3PzJzgRSRtk+y0oSuBvPUAjcvZzmoqIrpi4khtUJSBFVRDKoEIyKW1T/6sTe3h3tVrfv3t89+85e/95ve+Ec/86nPv3rnLcxtb9KWiCSjKoQ5FusxnYiYWWezq7arAu7ajQ6um2Z2UySlLUESAmXS2kOrqjlnRvR7RXLbtj0jenNx/fUohzYbbnbeLgf9owhov4czEz2cx9GHPT5mHDz5UComrXTpSInINAnFXjMFe027Wfu/tFS4T1tVrSt1coG6WrJ2Yheq2Wq+QIfj5B1pJw+X875FJc4z9tyFeSJuiFPKkqWosgO4T2a/Lf18qooaQKVnelJUaSoiluzEpB7P6pXoW1VZRzd2FBxVIjLGOPnw4+y8JiKDs45ok2RV1XWVpCwR823uJBfXygkevKdCquowFdY6jpD2rPmYy9vCzOMiMUXzq6/wh84WfD3GAPZ9bxFQ5K6GOdly66wNCFWYDtO1WYn9nlvPjeeRHUeyC/RlWY5Ds/iCMxiDXItCTEYgzaWvwN6FJ9iPkKGmUaq6i1Sn0ydVda/8kEz29XFaLLURyaJATEzFNFlQeTW3++2CYSUlhBVkjxNVimMYTJPo0Xdnao7Uk1ifyU7x1BPMZm3cqWbqKFOq+enFfYQ+GevHbha5e+tjf++3fXuSz04j7k77KDLrRc3g/eX5i4d3d5lf/mAu8e6Pvrv80lc/c3eSMeftehKtU/rdvOks0S5hGdnG7dgaiWvHVExHgRkcY52SVLqoEchCVrJSsde0xcR6VUqJWigW1Yq8R0G1N8hk2rF0MF1ICmLarKqTuhVLsXE30SV5L9s3fPxbbuFfkuenRWZklCxpu+ENeXjvgxe/8ny7eRLcn4iJ3fqua26vJJ+++9UPIC+wfQnv/tKT/ZW8efOry7/z3u+6u7XLXhbYMMY5BqrAlAoVGoSiBuuzQdVTu4FNValEFSLDzPbzpVeSvQMnoGUiRG0qBKy1VcGLtR9amitbjN2OnL0g2pZlkgfnFEbUcQPlPrs1MTMVVmiR1KTJOpaIKFaDHlI1GAK4oHeySa5qLRIkj6A4N0XWvk4hsqaJmiByc9UhKpWAiYyZpSpiAmDA0+ZpWRHYycVvGGluF2DK1ISmOMXR9EFp4xAEUdQrlXfOHcCqoonL+aUYNLa5jP3Vln/237r/2V/42I/+v9//rv/Nl8aQ2p/I3YXn8hYEHNL8ypSqAbIItznnMk5zzr4LF1tiMvV4BCLgHArp4WKJIGM0SxowlmelQkUjNhctQwghZjY0UgSoKBcriNolygJwNAFIU8R1UnZwwRglUybBQJjanPtpnLYZQw3jtpcLIKuZfRkDFgomF7q4358nBShz8aqASCIpLNEia6+Hy/MnOmrTbUzLevEH/uj9f/SXPv2zP/PFP/ZHAi91uNzDT1v6vNSdiJwuRanFnJQ5c4xRFYh0M7IUwgNVIWaDkcNGyEQJE0YHINBEa4qQiXVYKqIO7qBgrIHUSn3dAWcVisNsm5uOxRRP1/XFBy/F3U0kalaK6TZ0DYzULHBdVMjt3la7pC/mStaCQi0im0TOMjVUmoiUuK655YrVRIl59Jek0wxSQbPxcN5KdNFboFSBCooIhVOCUFXOHGJ77lRdfMkZBqFUNX1GRQuaNLWZldX2FUkQZoSjKOZBlFLAmDHUBNZ8iMvlsizLsiwxa9u2dV17hHxQwmA2RiYv5yDpokds6HXjd1QlkKZ/qTIrYiYBS7ou3Q7ocIq2rHiIVtV97BDd96iqOdPMxJV7OKQqdDgZDsnKOWX1wSwAVN22TVVLYDvHGFlzXdftMt39vG8xdylLprp0NT9sycyUKe4oFndRgAcgITOhNJeqGov50Pkwb9a1EuucPaEPiFxRxVV1GktXh1XlvhDomMjV5bIHRf3kpM7MPO/DRjCbroVIBY2EIPtiBLqj7tGCiWTEJqZutW+rj9zT3c/7hHQyryo6iH7fApS2xYTaaEYxS6gVIj5c8fCS2y12kQXcnfn+B+dP6G9v9sZ8nq/w8MGLl4X7F7auQz6QvejDnZhnwe34qMRlHXvO2zfy+X/1pTdul/3b346bXXR+4kHfW/wyeEPhzOiomxJkUoclslSqVE1dxCHmwiz3lcK2+UGhwIImljVxBa3WC3DPcHdkRl6sBTYZLiIGal7hOFFkuGqqGiWDQY4xltYrOfLh/W/8+Ke+6xNf/rWfC3mKpyV7lcke9cHz50+wfGr9wufO/+KrH3n7xfNXX9pitSU+WudveHr52LNnv+Mzn3z25jLxie/7g38Kz1/9L/7yP3zvB3/47dMXUPsr1zWWO9aDYJjDUDmT10yCnuge3pJjcSvaUnpQsrLHTCVoGyZ6gf3ou3jcSVSVqErbvFQLbTA5zq++347JNIBrrFB3MLwmrJkNkMwsll6rY3m8eauak9oUnjH8NPzl/Vm1cOgntQo9f1jEAjULFLroECUwWXboIR8Xt72Lgphu+64ic9LdFx9R002RoEiooJuGSoNYkTaqapg3FfnVq1eVuSyLQKbDKNKYt5IVJUM+92d/+Lv/0n/y0R/7sS/9+T83vvKVh/X/R9V/h1uSnfW9+JtWVe29T+owPT2pJ0ia0YwyGmUEQhIGiRyMwQmMr4zTz/4RbF/fx4nrhCPGlo1tsDEm2CZIKGAFBAKhLKGs0Ywmx87dJ+1dVWu94f6xap8Zt/SMRvPM033OPlVrveH7/XyNIglimSYQUA0bERFEgOCEyEeEH4KoVNVIQdVtHlQ7rXBAQ6BKWQNomkZEqJi7RoC5CbOkVHkObg5rIQwnbpiy5YoWsoRgitUTiY4eXJ9d8LpSZeaqi0DEMo6bi81+HNrEQ5+bpulzFRYRgJipYSCgVl0H1wkSYTggBBgzq0d16NY129ACW8wzHVxe7t75vMNrbmw/+aHN177sAGBG0c+ZsCWTzQJZRqOUiIOwZD1qyxwg53GWGnc3NwAIQjAAgKCo0bVQNc9EjgLrKENhblOTI5dSLJSIEjeLtt1d7tkzLg5E2NrYuHp5t13Mx6xdN7t0uGq7OQbmvidhchSFGi0CCiQcAWaR0qwf82YXPh4SMGSYbW1EVh2cpWl5UmxZOALZRIrEcI0pcmOatZhZIHDDFAyBFlOoyNrXXIUsNSkAK8AcotYZUHEcwehqzExMDsDOEuABBdzIOFgCc9hRVmCspXPmhUnMbGNjI+dcNYybm5uHh4eUGpikJEdTtAo8AZ/2UUiIFl79e/V9MatHR22sAwAKQVQssJsoEImZNSy57pI9VAsRzdpWi6tqtpxY1NzAKRxIhpLRg0Hq4iClNPYDJWmaBpmDZXRFhEFLMC7zEGGGwdUNhciSmHgijVB0QB7uWFn8oDWLlzHMIqJr2jzm5XKZ2rZfjYhYP7TKDEkNI7OZmWqbIjXobm6GakSUBCDKFB0CoaoQRGsbwnqZHYDgEB4IgIQSRzKTo/kiMhKKhSNxww7gCa26vAJKnc9HFdsSImqgefHAks0tSNZapACPaLVVTByI5km6UbaIz+6NgoHjuDvfOiXHrtsoG7PihxHm+disqWbCGTc2ZGJwQnU3KHPv3vvILX9u9oVNj6uLWPTlCraLokfDQmAgIAuDwA3n4ydPXNm9WtwYyV1ns9kwDFAKJSFirTR/JicyMwE0izoAYJy0mRa+OZsPeVx/OkkIsZGUiEul2E8uBQ2ABGxgJTxNiHCGRgrvPLKbv+NlN777U+d9+0Rfsrp2KXkQ7uzg5z/wrac+f/Or7zrZza7ZeBVeO7/u9F1v/bl/9p3f+X3a5/n81ENP7P7ZP/F9l57Yi5tXN5z61ceWdsvJmSy10UzkWQYubV2DVf8XAhwJbRAnTVx4GFA1YjReXx93CJBpLIKIYtORxIBQGbWETFU+6OZeVcHTtgkRCaFGma0vbKuHByEiKoZ7dUVVeqYOYcyYJE03rnsABCHFFMCMiOGgBu5FLCwUsI7Sag3uEQDMnosR1MgkqmN/RGSKygiEI4pyFbKiQjAAwhRyUlXQ4KHMBCiVRRkQRMHkDFS8YcaA/nCJFVaOVIYxRAo4OzBRMFFEsRym+urXXPzAB2750Acvv/Rljx3fWPRqBGpGQqoa4UCTE7nqMNUNuZrKK+QhLBQJyetGkCbuIISHBYYWn0nDROqec+YabgQkVHUeHhE1b44oiBkinCYbukckJMVwC4K69QNE5PWe10O7prGIUAyDLnWllDL2BND3PQCIyAwg55z7YevYjpn144rXKsYp1DHCIQggzEXEYo3pMwdGGxTazoiaMS/PXHf+Za943gfeffz+B3af+7y0ux+NjEqB1LeFwDqX4p5SwyKA7hDqlrhB5IAprWUyrK21kfUTgAhHZASEcHAHI2Qz6/veJ5rutGJfrg6IKK15n9M17zifz2cbG7q/p0OZNZ276liY2Zm0XltaANkhzFcJgZBNuZtvYAzCTF1TxjIcLAFonmZjmOY8laFeu746bA9GdncS9nUgY31PAwMJTM3dDYy5wkSIIxDJ0SbJFgAGhTsT1SQAIoLASh4Nd0SsAaVE1CAD1a5Aq8muahsqM3LaHFmulyJz6vs+pVR0lEQWseaFxbqSnmTFYA4YQuQwLTOFaL1QADOPqKPjaTOd2hZrPQoOrszk6JPvECeLpBavteCi7fIwAhNzm3Vk5ro8NTOEcAcr3khLjATO4RSsZohRqVxYLDXcMq3MqTa5EVWrHaEAkE0BkZCQuK4YzYwNMKXKRm2aBgjNgZuEHlpGZpZEEWGBYPWLRlWf9qw4ORp47Sub3gsIAAOg4oaqlOr0lGgdUgl1A8jsobiW6URgEPj6qmbmrIUQ1V2QLDS0pmalqaMJRUQGDsDKcYdaMbgzYjj20qGTauGuONLu7iDLJ1Lrg18izwVvHPuTnYwOB1EYCfau7ktg10lEFC0JIuuYY5h1Ked84LOPXbzjB258IPUHA7bHRs5iAWBWzA0ngSERQ0+2W5YjQzaTKER4MPbhTuJVmY1IiIxWOw9EYZik7FKJs9VmNqFXgJiFkSSqwYYRqmmNqkqIuqp8Zm6chRkDjcApTiZ4/+fv+Ykf+K6X3falP7p4tWVqebbUQ/ZNQ9vUw7f8+E88+6Vfv7d3eLA/nD598mO/9/HrTt398INXP/WpPzpz0w2LWfOvfuof3Pbcu1YP3rNg2T17cOL29uFdm8kOwKGVOUOpKyugyYiJBBjsYPG0LxkBvIZGKNcsHcej6HVzoikTiAGQnk5FZkR1I0GZbq+na+cadl3/vQmVMJVyNX+xUrknGUU2o0SIVMvMym0wCHOLUszBonZSyA7mpppFWJAwpswsdfMAIXaucSLV7YCTc6mKs+hIqh/PrNlT4tAQoYjQYiRsYeIcoWUaEgRicAQYEsuEBDEjIlyveRSDNAwhCFrAQCihrDaO/d6f+FN7//gf3vye/33xh35QD1faKS+DhBnYnsFusKgIWQREixonurY0IOEUROOIiEHgHkQQwYRtUzH9joiNpIlN4Q4IGOhQj0IAdwsjYnO3MAgioDroqF9AIBoCRnAAMQW4QkQpWL09zG6OiKWUra2tiDg4OKhPPwoLNqvVSt1SYnJajx7rXx0AzaOmHtZ9dH0q0GFTmsOVjm1DsILdi2df9rIbf+/9pz79qa8899pH9IqmZF7myr0bQUlFMgU6hVVzO0YYGkMgRziCh7vVgQ0BUOjT3pKaqDdVhIhg4OGkVYxYfZaEgATqgfVbnsoIYusLAOhgHp4Im8wGXtgjEEYEgGDEMrapCwQtox4uN9rWQCzapukIIhd3c7IAIBittNy6AQCDlFLqIGdSjQCTyw6d8rW+ERHNrTJ+kIJxsqNOBQYy1izKp4WyCkBgmkQIQLhme5CFMyUzq0xTRCcmAnYqlfxZ/ziqyBEkm3BeUBEllBppO4/12hUZkQGcYsrJq+W3g9VPOBDDq78J61VUSqnxcyklAFB1s0KG4NWJBCSMWDNxQ5CPFuERYUXdvQpax3FsulZEeDIROAEGWSBBxFjyYrGonvZx7JsuBZC5Nsxj0SBUdxJEjPplRERxkzo7rlkNNSbPfDogAoSwLzWlDasEnonNLGupKkXTmqoCROQQZpZA3AIAmRsAqNp7gxAwD496xz9DCiNIxas1kfHIS+RhbAjVSl3fKHdEswAO1+LqWJyYw0HJDVyQI6JuoOvv7esFvJu5K0ljEUxUs5/Nx7k0HNT7mPH4l8/TqVWvtNEl2rx++54rq37vojU9y4KAox951uZlL4YUAdm6JjXIB6uRY5Vmm/Ny5Q++uPGsrRPPn5/dP8Shy5WAVt3NU+RuWAQQ4dXLV2azWSsshE3TlDFL2/SRa8k8BfFG4DQomsQHtdqrhycGam1lEczMwAQRmKupqwWoLk9mxgZoDFMIUhcUa+oWyq47tfPYPfkzFy7+wz/90u/6Zx/Szc0YXWTBFjLjA9OHL1x64O3ve/i+T1x3yw3v+e0Pfes3f+0dzz39xNlLL3n5qxLHsa308Y99enWwu3nzs16ZLn3q3JMrfOlidhUsDm3YgBSIAuTkuObsANRR+vQjrvv92toGYmUO1PITjsAa9bUkwkohqCnQ5rYmeCAeBV+AuQVATaFimDIx6t8TkdQ/EwGZAtnCPQAlQZT6GzISeG1Y6z9wqwQToAgMqkeqq0ZN1IMwkAQA5iXcRYQipIojCbwyoNQASJBq5VizPQAAMdI06/a1aaWy91Ew6gTWoq6365YbBs9VBtJ2nZmpWd1dubtwfVe43jDIJMRlb3/31udefM3rn/OxD97y0hff8/wX6MHlDZmZWW18j87N+ngxp9q1mTkzT0F/MfkV62dNGAyEEU4AR0nXQjBdqMEsGM6VFhgT/iamtxqomAqhORLlADR3AgOaLmGoiTcQyJXaQiLFXET6YVllKX3fFzMSGUpOKSFAMW3bNgGj2yRHj3jm92YQAJS1si2nS1Fdl1pmkcaiRbgbVnjrLcuXvap89aO//PAnRhFYxTRImaTvR/7cyVmIky/w6f+Nycs43f84GQin0utojhfrvIX6lK9lgYhT7fIMK2LAMxgUk3ERpt8Bmdjr3DscBwSgcAdwViylcJMiQEuRJCKN1RSXgBieNm3GOllyKlwDAuJPbv748XRqci0yhak7EgTU0WRAFXZHOGJtPX29Za3HlhLX+NQpzKpWohpeGASwAXbTEZSIIKIF6t0soIbbrEd87mv7by2UK3yjmtdxOkmDkGogx3S6+BqhYFblJ4FcwpEQmHBiVDFRIBYAIIbar9cFEyEVHQHAp8bRzJyIUNiLl1KweKVu5ZwZiYndghAjyTgUEkHAoWQAX8zaqP8aY1TdbzEiMisWkx4bJkW7a0XYAIgDENo6KbVAnX9R4tSwLJcH28d2MOfVaoBp6usknIiKmapbeN1klRzFlYimxwPCwwPAwGEtPq3axpQSC00XZzisV+cIWP36GIFQs5JwigOiaUJQiiGihRus5XUatZA4evmQGMAtD/B/SIsZgtxixp5thZBaTE8Oi8ditqC2szCDc97PsLO8BxvHbFAnnjEPPgi7lrFfjeEyrg4AnLstiFKgt4Sbwr/1+f3r795sOGcaQRs40vkSAgB6AEADyKmpfpVipnkMgr4MDRBT4+BW116CznVrLQShtdhSY6oJymG1jqmTFjchpEU3215srFuLGq2DjEhgQcjq4FAwUBiKbc22vvO1m//t7V/41b/1DX/zG5/zk+++rzk2n41N9iuz6PI1tw9aLl58cHd3f/PssVe9/Flf/MI9yva9f/yHfu6tb1UbS/hf/et/7Td+5be/8U1v7uiRj559Qg/7xtMhbaWa2InALCiVgeAAUIWIrFwDPj2IACbyCAI4ua9jjD0CARPXcBwWZJbaUJqZugF4DR+3yUFRD6iAgOJuEIJEGFVTLijC7BRMdUCK9RavY25nsaIAkIjdvebGJCQVaIlrx4QVZonoSISJKk0/CJnq7jgi3JSZm2Cb8AJAgMhgDkh19XhE2YUaYRIerSQjMDOc4uTQGMEcI5ogAKx0EUNSHTC1ABE5Z1PEqcIgD+XgQKpPQUAKtsAN2DhcHVz9ru89+6WP3PJbb3vqWWcu4qKEctSwQ9Q6BEOEOtA2RwBmsXpEOzBwVGfrusqpQk0EQI8cKpOszd0n9ggCCDMEFlecXNoAhEDkGgyoaziGAyRER7DJMEqAaBQQSAgEDEHDkM1t9J4bFpTqZkopMfPEpASourmUEhyxKQAQKMIAyCa7insFJh9tZRFGKF1HNx0/df7SQV92udiTL3rh5hfex0t58+0/unN10XZ5IAZPJYCwMDAAsDRmRTUTpzBomtY9HzHDw6Zb1iHAsY5zOCEAuHntNesRZV5Dv1mEp7l4GBEfZeQAQCmFCAnEvPKVMNBRXYzcoemaQXN4mTcwLJcYYTjkYSXmFy9ene8cy2XX9vtVX665+bYTtz6ndxCvdQIGBDG7WUJGmIJhL+WL71v+aomxlkxHHWSYg/mEIvYaPesRHqiVXQVrAwJW6B5TXwoTuPu8m9VsJSvGdf6EMalwa6ojGk+2wCoM9mIaEQTojvXDcVdOVT0IzKkmxNVB6PSxTwN/pKiEZgtGrNxL1Vg3iPG0hwIqcnmxWIzjWKlArrY9m5vqMtcQi/rbToWmBcyInAzACYIByaPObK0mqEZISrWEyqpdIz4WCCYIK8pRjcjsph4+JVGuHWJ1tjR4ERRkYGSop8H0erqHtm27v7/vAG3b1i0MYmjOPt0xTEiuViyvE6e4gkeQpZbzCHyUlbuuBa0UI55+dhgWHhAO0484IAIRPILpaLYEbOEA6hUbEACBDi1xwQmu4kFH9B6WidqrqsXqu66AAlVShZTNZ7PZU+eGwTd3dk6Me5cQSK/qfHuctYuS57N00B+OuQlR8azIwCkhdsyK6NmCaPtg6FXbnZYtrvvcxeWrrz8rhx4N1VO3Uo+Omv6cNaXkpkjUirgDILacRrUICAipIxlwdASAcEMmUBVmr/bN9S8PjYAkRJyEEGezbjabqWo4JJEwdzcT3AQkIlN3hFTTf2e4d5DvvvPkfbvwPz54/gff9OIn+oP/9v5L5eSsl1NoY7Sbpaf7/+jj7fFrHxn7P/893/OT/+BfvuCOF5w+duKOu176/LvuOtx79H/9/M8/94W3f+jdv3jh/ntjftd88TrI3DW+OmDmhBgikibym2s4uzsEEiiGVcwFINSvMjwTmCoApjWduN7LUMHLzLQuZ8BDA3JWAKAqGEAqR90HIRHVaUq9YBiBwoM5NU0Sqpq2VL1zat32ou/7ccj1FV2I1E+/d0NEmUJTA6qPhBCx4rUqLgASgKcUVUY9hckXM7OYXGKpjvgwtHqhKrsBfDRNgV3TFHBVIEMDAwTKagROYIgRjgEE0ERI16lqmHlQnXu4V9gyBYUHEAUzshOah6OCLnJc3d4ev+XbTv/Sb976O78zftv35sPDmiJw1I1FBGMAg5sBgEhCnIwWwBRRQRlrB0at3CPWzY1DTBZVQUJEtTqAnrrGhthiGv4ysjEDhAICBEaVcNU7Kaa2v8pVDSUiECmgaSTnnEjUshu07cygMKfcD5VE42bMZCUzMxDWBFqECdUCUzw5CNX/i1TLQeZNWazKcOHqRVam1On+8vD259j1N/Pqq2cOWty8ZV6WYyOzkRUZeCRsVLVeQ5FMmlaLEzC1ceSVCnIGBCb1Es4R69E9IhLUcUAtwmoWKQCsn3GycAKkZ6igscOsjshBAUEEkG1IRCc2Ng/2l2MppzZF81L3Lst+fuTBe68eXlEtttJWZkNztdj+dcdO0TJ2rts4M7vlsFdDT1gBa0HMIFGD1dzdInI1JkBMcm6isCJEDqlWMxGIRGEQCEA+TYammTBG1ChsVDUmQgZGrOw2QEwiPhatOyiIhCQQBcAwhCRcgzCrxjrrwt0Fm9Cqnis7W8f29/dLcXNFprqlIiJmnppvAHernEqoXx0AWEAEcJUBFAQGQJGmfvhZywyimCJixZ1UVAtRAHplpFdsi5khyVBGCw/E2WxWWRYVxMHAmNjyWHPMEDHnjBHSzWIKiTdHcANA17BKRAOUiHBbewjATSLQ0IAAhJhrYo102XJWrW8fMZcyikioqVYfFBNRBJgZBcAUJ+4BUF28buvRHXjdjCADVRENgJn1PtSjD7B+lR4QRXMlpgRXBxdYOIG5GUMy4Grjd6/0AwhCQQ4Pda2VZb2fSgkm8YhiAWCBhOEMJpxK6Rvu3CUsvnTfQ7y9efVghIVsQ3vtdtpdMOBoy71DHDe6nUPtJUfLMwh1K4ZGlgPUo/XRb9rAre7imPjy6sSXrzZvvB4vN7O5OUIITikUsN5oaMtjKDMlrOxSc/OUWmN0dwhPjBgQOul1RnAwq1TgiCiqiGgQnUjxmPI7wgQJMTG3DSZBJCFGD0JYhc1RyGIlSm0KtWrUarePveVPfftf/XNvee5L/8xnnrj0lm967WLx6X/7m/fQ1tyuOUFAD9z3yPd/25seunzFcO//fstb/sbf+Ov/+31v+/7v+qevetUbPvGx9++NuMzDZx66fKG54Sp//fNue+XWzubelX3g+dZWx4xVQCxICGDupLk4TOwJBCcmIkYIM80jalBwwajuoDp0MowITzy93hpBALDeKxBRLZkxIIBjkl5i9VYyPe0Prg/6HBmjSKTUJp6lWDverGhi4bnU3zClBBGqpWk23BVjyudxCENw4oSAVjvgWjFCHfiDeSR0CAkWBwBQosG1caw0BjN3EMEa3qICLQeEuZAIMXkQzlZl9KaR6cxGj5r6GoiYgBkxROpuYxyL1uGccANo7AbQaFWQcetszaHrrLt6yb/uOx740Kfv/P2Pnn3Zay/fcEL6KBU7N+3JNYgIMDVcSjEvajrpBomylhS0pmpTxToHVhk3FLV26kdDszJzpRBAVZ64VvtjIEgrEJS1iLlN2hUoGBzBwqHGAA5oEObOCBRYwpk5WxEhdyWk7e2tw34QZMsF11pcQgQKAC5esEK0cK3xQwZECrKIND0twUwawQQ8QOJF9tym3mGWMujOzu5dd1L+4vbD56++/Hl+ZUzQGLuDGVgbwUR1KFrcwUOYIQjAJk+5GnpwkqAAnS7agIm1yyhH0+WpjnyGpB8RE4mOmdPTO2Azw6jBHMncGsSunR3a8Fh/ZbHRLYzG809eufjE2UsPPXH/Q5G9L27IY79CH7d35gDdld1Hztz0rM2Tp/cuXZ3LZmko+9hSNx2dtfGpWeSAUJn/KQmKTBNlSCkNo01atghAcjCIgKPeF/iIYAZgANAhB2FxbSRZ0YbFigWBCZFBAsquI6gCWrggj1qk5vysFZqIaOCoHoRAJsR7V6+aGaMwp8H6IAJHIwJAd6uaeYio4iZZB0tgOAH3ZiKTcLsUZyB1Q8Q2yf7uVeYETJgEAy7uXmHmpul8gnwGIjGzutWjuZ3N1E1VGZFFimkwgRp4CHHFZnVN2847VeXKDTEVaWrVbAEcHBjMzMj1NCciJgbziAKQqubFwQ0BggG8Dg4Jqu5JmdndVJWYzGxq0r0GAwMAJEoR4eoptR6+0kxE4QASpoaAAhQR5lOoV32RTDMAChOjIGIIHhEmq5cMPRg5UI0JgxgCDCEwAh19cBVXqKUYVZ9HzRYBTk24I+ZArusDDwT2knBEDIgt72+9bvEHH/vd133NZjQZx93Hzu+eH28rJZ1cpMXW8Yf3z89oq9DYDyt35WbmioQphai1uSlnrrl493VXL18oZ/3c/QcvetJlVg6R26kHq5OoOihg7jypKlOkRF4sEVHTjlqkKgvWHFZkAWQPBCyxhvq5QKhVknfJAwlz1XgACiGlpmlSSgCI06xPAglDoHjwLFJiUsw0W5RsJzb97m/6kR/98f/0b3769Ou+8U33nH/yT3z93Xdsbf6dX/747rlucfKG//aB93/yc585e9n6lJRe8J3/7wdkfqs++28/9Fh02AzHTt5yenux2djuBi+fOnnjTUvvIDWLZmOOqxUQm4NDQ9AjR14WbjYAVjCCM4qEgAiBmjkEMDUyZmVmQBeCCLSqaCdKbWtWAhEQHMBMK4xd3dQwggwQTZvEAIYQm5LmzBqeTcNUkCACkQpaojQNSs2TCNIkuYKY/PVtQB1QEzMSUGqJaNp7rE8HejrS42nacJ0j1emWr5lECWDOHRSr/xAAPGztepfsLsTTdg1JzQr41mIbSiAGT44f0rraxFD1NjWIWErhJCyYVUspgOaAVZ5mCIzhnlduc0vAeqjDFox73/09q3/308953/sOfvhPHvZlNk829o13CPkAteVtg7Euc1EhAdVGNtCJE6C7K9VYdKJSTIRmbRqGEkQWUeUGmIIS1qOvZK36Z6/pBABREMBIHYiYYsxZmDsSzyOgMyAhT9oTJjfvXU8eW+z3vQ3ednMWynkoXiR5FA7CEQoDSMRGO1P1UsoMkwKUSiBUl0pDQjQdBZGYHDE1AOALSjWtZQfiwKNQtxM0pDH63Yt3v0S/+psbX/wk3P0NI2TKCUJSk3lMSgWIRJqccytNcYMpLz5apOwWTIJgEKmZkULx0pCwwqguXTuqMRIEOSkR2ZSzyeYO6KbeIBNRLnZ0AUvb2LAKdqICFL2lmedWaZZ2/PDCuUc+e/6BL439/tkDfOD8xc354sRi63B1MELZ3tzYWw1Y0NLq3JUkn/vI+fPnn33nS57/stfnEYk9GUGAgwWgOTE3bj0wrS8tCBQiHsvKcHQzYigZ25mU0iMQoJJJCApNkul6ewahuWeIBDVzPojIIIygWKaGIFzDhKCRJiIgDB0b99ozhU98XQ9PQgOWxFKr7lI0pYSBpkPnXE3VlgslaFNSVUYwpBoGXIelYSZJci4oVEoRIgSU8FJGqJ2yBaXG1Vri0ZwDEnfGGOZ1H8qYuEnDOBIRCpF2qe10XAUCiShEsJg7hrXtLK+WCJza5B5N08y6brW3THMZLavnRprSKzdJzYSmwMRxHAHRSZXrFd4wkoUnEXVnShX2xuiIYUURseVUTIu6hXeVeE2kPqG+zAsnlllbVkOTUsk5l4JM6JbAVY3ciYiDMAiYGBg0KAUCIDdgAAH9MLpH7t3EwQLJIgyRomjGiJQwF1UNwgo5RWRXTCyFMoAyMeewVoI4HKUvJDGOuRSLsFmbMDDHEGCostXGoGMP0M/vxmvbTz3y4YaufRJf8sToTKe6DvvE43JoRkCzNoZmsbG3XHnRBhSDV4ibeEl969KyfedXrhUS3JIhl9c+tfz46R2PJXAHAFRWDWyYH6oxRRnNoAYbRWEiC3U1QCY1w5oHX7fegWCMyChIgR4iUs0LgsiI883FcLBskYBgZSpA2HEzkyaEELFxiAhnnJvsic8jqzTNIbSLdiy600K2jTteffjKw+/5Fz/7o+dJ3vTqb7z0xP5z73z2f/2/r/t//sPvfHW35xf8hS9D0VMpUZvbw1N88sKl++ebkObHbv3y710d4pHD7XTp4vV3Xnf9ydf41uYvPx5Nuu7O2eXnb63asSM5JNzoU6aBLKQlX/qygS3FHGDhQZ4AAZEMIywkEUulYk1otGlAClxgWpIBYACquWtBYoFQcEKkmhMUDIhqVhWPdWWbTcG8aRqMmvfiYU40NWru3nRtbUQEyS0mbjuAUwgSETEJEcXaH3KkET06KNdf5zpDZpKPrH/VeKP1v1brVAxoarHvdYKDAtFGADFIIBpSJe2BOTg6IoZOyK3MFIQYTUqsiYtFVNnR0UKXiIhWnqIYdNuriwfLl9z1+Ctf9pyP/uH1d9/11EtfubxwbiYnvPSQyiwvIMLJFU2qkxWQglIl4TtmoJQ6wECP0GBgrOL2ahMGNAv3iYEAlfnsjljHCVxKQSL39d4OgGCyCQJApXRDHaBjrV00whlxKLmSp3IZajTeAA7oswoBZQIAIDByEwgkdnQKCq8ejlYSMDlhmnX1A081mK9OulMUDGjkmM7JsFBYRo9IxzfLbD47+9XZYw8/cv1NslRcDD4Kigvw9vb21d39us9LSJOqIzBDEAmZFzBX81VfVCuepbiJCCKjKwnqNLKiidswmeMmXUwQVrLSUQc8my0q8XQcx7bw2DHNnPefeOLzH7104fHifuUQyPKcwoex98OxX7WzbjzMy4Plzsk5yvzJx5/qLy23Nja/+JlPHr/uphtuu7OUgiDuXjRLkzzQ1VhYdFqaqASEhuO87UzzSnWRWkGagYTwsgyQuARRQN2wMvNRdgUzSwUzuVU8eO1HE5KWYBamtckHOMitznIjfMrMKdXshBHJ0MOq86GZOExRPESQCJklAUaEllIhblpDWuoEpb7/lTmJFOgWwQBV5+XuWYt5IHJCsjF3i9k4jp6SEoAGMyOAqpJCy5SwKaWYeyklsUw/OICKgiZEtRwRxOhWapB2BgOyrCZMHpBzlrYx041Fl3N2tSrbdDD3cI+6IhlLFqGch6bpsCbIgpdRu6679vip8+fPg/k1O8fPX7o8n81Xw9IBopi7N00jNZHJI+chQnMuNUkQhcswEqIyu1bviYng2io/ffjqjl6/oensUjMmUlUgLGOeNa2qF/OCUblmBh6BGB6B4C7eMGEgCamZi5uBEcc4mLmnxMxNKSUl2t4+vuxXiVocM9Hc0R7dO+t83QN7d+yqIt6Mp1qIC5B91DbnYSMSp3JYWmEtoF2IEYUebsywzQtBeOj8yQFWaZ6SUbdz7Ivv+dff+W2v/IXrXnxm1VPXrBJhWYFwEeeC6D7lLk65sRHhVXcznccwrUfXMwA3cwsv6ormUvtpEFVKYkX7fpSulQqvA6yCvtr2ARIqlHnhBFvg/ThHNqYuqy0ImoMHhze/5qGf3/ue9/7iL9x447W3nbprdXChEfgPP/qGv/U/PvJHXz7XbWwGnnOft4d2QR7fuKDjxz7HLz59y6VPPvv0Cx6DZ5+5+zXNYoMQsG33+2F7GL4cJwo1r906X0bwZLq/u9icm7X9sJ90sce5CWNzCHRUCpiSWChowtB7Iq7PTb3tyMM8eViu5FAHilI8CMIZQVGqba5uAAEisUJYKVY0IkILREBKYz9UXmA1MwBADXCthtqaGBoSqtXYRwqGRIwkLMwMTJN8ccKmT03zM6/h+leOoLW41d2pgSqhXUexrO1SiLVQqGkS9Z9HBLREsSYJ19YcAQmi+No5KhFRl+vFrZTqv9cjh3j9etpQTexjTy13Szr/7d+9/MKn2w9+ZOPM87vFdj+W0kBg8g67MhK2GfWoa43K2QhECPagwHAH5IyOCUczqusRRFsruWoIZjhiZa1oJOIwq4tAqCYXnDLk6jdXtVsYoQEUDpPfEACcmFeroZhySkQUFDUfkIgSwFFgMyIIMSFGcBfUIDggM5MFM9fbOAFFTMyBSgjiJBHRmY8CrQJnGwnFvSz7xSLZYv7ogW588UtbZ247iNw4kRMIIYMTozACJ0nDMKBwILDDGNYgEgAyMaIAYCukCoyODCQM2LA0XbdcHlAwPCNKxSMmPT8LPVMCDVATXkuukj7WNjs1PBzc/5nff/iBL/dJWLpLZy94k9Lm8SsXL636PEAZDq82hJubi1XfH5Sh6xoXuro82Dqxc/7sQ9dfdwtwM2WQIAJ4eAg36E7hCFPWdYWZEyWNMpsthmElODtYrhCjhndU16jgBGWbphcAFt44GIY7gAQgWGDN36XQmibmAOvBaRVSIAUguqqbKQAIUzETYQoiJHd3BAtvWDqiohoURFx9XIjohL0rcIXt1OV0YECtWc2sUqVq4A8iR4SrSV0tmRGAlZG5qotImgRHjjV3QAcEYgiAMEVhDLBSuGnQHcMD3VQxrKoEJjVlqLMLUCJRVWQupo0whpkVwonE3o+5UqjaxEMuzPXqh5yHyg/pOkmLRZ/zxf1dZXT3q6vDgjaOfSUFAD5ddidu3L2UEQGa1Ax5nG9sDcNggG4huXa0QSCBrhSGHjXcov4ODBE1YLRayrx6EoDAzKQRQDVTDYtqN6rmJa/5FwwtAVDRkViIaMFNbyWTCsR8Y7Hsx5yziADgctmbByXfx9Zst/X5Fs73Z91w/ctfdu4L/3LrZ37ywet/N31be2rW7j2aYgapqArb4eoyb0kiPLjqbZuPHbR04NzymNKlY9DFMOYCqZu975abX/+ZD9z25jt3BWe6YkJsaCO1lM3QKnDcg9wACRgmLzxUMdo6eDYmQXhVQETdIjISIdSf8mroE9Lm5sZ2c/L8pYsCAMZoiSSwJgoAAFsUSpTAOKcRx1mmfuZl89SGf/RzV/7Lx2+d3/RNWy+8ZvG1899byds/+sj3vvTYzSk9uYJ//udf/+9+49Pv/INH4tQpg4MZS+PbB9chXf/N9NhHr8qdV+54ySnZSotNJmk35r0hYnsp5PiFy1+lE3fCk6eY9oa9OHbj/hP3lbFZNWMCSrCZvSRkAfZsHvUFxCTiCAzInJqmqeFudWxLHu6mbmKiqsXXjaYFIxIDC1VQZxOCCJoHo8GLVlVRKWUoebQaxqgAzszuXd1NJggzq8D9qV9lrqpZIqbJFw9EhMx1D18v13Wcw9P9SuD60lxfwDgZSADqPsT/j765xtwG4RSPWLUkasAE8DSfNSZ8vINgqNU1xuQwQ0yqJqaqpVBxU1XUKXUcyR0aAeeZ2OFVuO6Wx77vB794/3uO733h6xav3cXzG0ZLmiGuei6JEzuFlynyYF36ASCksJiOCSGKiFST62qoXEyGMMQJ2eNu9YxjwVKcGSOQWQqsTS811qn29cgEVBPloMI+MFBEmCMCmVKXmJkB591M1ZEnWkAQgjkhVPg5AGD1SiIk4qp2cwSjaIOFua4VYjYLhOJWBTwzNZIwKlAKNs0hqBLgbPaJF96a+aHX7p6F+YYbyZyhkTa792MnCcxDTQDRwhGCBWuKggcIwdqDTJWLwugaagoeZsXBAKQ+mXV3Pj07R1v/Z5R0iJxzrhupWtNsg332Ux/6ypc+BUYeTTPDkcqyH7Q/iIBhVOnaY1ubaDr0ucjh1vwYku3t7YKDpHjovi+cOn3rDc9+QX84VudAKSWi6iegEHgERxVLIyD2eXSMZEDSBMkQQ9u2YTDmFUFqKFUO3VTRMkWEO9r6Ma9JChGBREDIkSZbGlWolpqZIPna/CpEpdQHe0rBIkDysElkD44u8Iz9uXsAUBIEQrNK/Z12MWY1iwoZXZURs6q7p5T6fsz90DQNKhQbiSiDNdiGGRHBUAzN3VmkEQpE1QDC4CltlwBrBEX9STFiXwoDi0jbtMZSq1LzCVsxGS+ZIwoi5jwgEwRZ0aIajiQNBvRjrof+hL1cl++qObAd+wEkIYWrZncBVFcLtHCpG2QznUzPLtJUoXjTNHt7e23btm0ax9EtgkCYoDreHISIELV4RV1OiEDwCLBwpMnP5hYAtBqH2jNMQCl1qNveMCRGt15X86Z1hkJuEZ2FI2VkinKw7GMdwCNIHpBEBiuduUM78KzIYrTLQYt7muf/vl55z6s++l+/8E9/4r7XDdffsTGnftQ5lcTzS4w+m8dyvjMenpT7brKzx9PFm2K/86sRHOhQ5EN/oGd+7Ecuvff+1z92zy+eeXE7joFpyGE2FqeEROSVfAB1El1JyWvFLqy3jVUBXeX6jEQiqsoA4VEMEKdCrR+yOZiZQJV4IiIgeujRW+1IMJJCCZFL3Xwz5s35j9+3+bYPXbzmha9JmwsEuNoHom0eu+YXPjV88w3jK1+0uPjQ3t/85tdec3zx8+/4I5jdyAvfS1lQACyfeNYf3HX8WTKbX3s9RKR5C0QOSPkwuvlBpO2HH7vnum6Lz89k+/F7P7i443mX26XuLgU2OM5xtwFE1S6gmiMipbYhEUIR6bquaZqqyqsNItWtuCoKH/2XVQOBAL0o1aM2nBQggLMLu6oXVQsftKibW54zZy0w9G1qSDjMY/CcqU1NmHpqaXIITbNiwqf/PmKyYCJOgYBANVRl6mXrBfx0AeVT9YTVWrOWZU5lNdSJ9+QKmNyNlUxCHDwdyGsYWBhEOCBTfa/YzMzYLCKgEKvVGWAyy6KllKnSdxRHTovsI3eUr16+9kWv/c1b7j9/y73bezfdGDsFSsJwE3RULgnY1mRQh5qQU2fFEDVSzWuYqCECIhOCutf4cER014ioDTQAIFIdILu7SEJYt1wBWA3iWL8r5EnPU43g0EhCDGZu21mgA1MrCQNaSd4Cc6o1D61zR8yMK9eappkBM0MEiwRPFlcza0laSapTpK6qesPIPoDlBLFXEGABcniYEUhffudnT95zonvsWzZeu7e66gxZi02e79CwPIyz2WIsVd7iDXLxdT0XFqkBNWTS8AAKdBQK9ZwHEg5FX9sxATyqbyqI1i/s0QXs7hHetq0g9X2faPPC1fsfefgrMlq07VLw3NVLNGCvuc9jy7OGG5Fm0S22Z7PLh3tpLHOT4sjbO6axWg4Bu4/d/+ANz7lTNbepw2BEE2HV0jRJgut16e5UAzBdmVMxQ4Scc91/E/DOzo7msHGoTmKaSoeIQBGpTwLHRAnXCn8UIgsLR4SaHFwpBrhGHKjqfGOzgpSz5pSSWACjIjKJACTiEt5rkbYx96l3cY+iNctr1IxYRzXT+xgRTCTB7t62rar2fT+bzTbm3eXLlwkbN5W2SU0DHkIYHmJRolRKvJkDTQnGUxkEIETqvlgsDvaXVAPCqQUAV8vjWBPCgYmlyVFKLoAIQeom0qhaYrZ1yEQpFoQMFBSWnZkRkFhMvWk5Z2UWdxjK0Laz+mYRWSkFKyXUEan+sIS5FstATcrZU0oOqKZdI+FaIgO6MXqo1+s3CAAMORGTazhGhLrHtIBbu+nWYzliUjUUdgQkBA+tCC+IIHCMIGdMCEyEzEgRWgYnCFCDZsxj0zRd21ge3a0mlHg0i0W7Wl3p+yeXuycRtppxn66b/b/nv+2XvnLrf7n9U/fd+Dt/6yv3/fLZl8GJa4bZibCrN+SLt1y97672/MkzPe1fwqHpmq4I5rKA7ePDctzZKG9cHMJ88/qXvKrbP0CGcCipnQcaZWBMxccJTIA17B2riz0MHatf2dcPT72Ga4AQBpb12iiAAsjMXE0RR7XFYiGAkBwbR8UAAnHEACdorR/aLctZTm5tYj68CJ+9r33fvVfmN85uLLt7SrTYccCDAHPfOUHvuffR3bP73/31t9x/5ZHvfs1dpxbdT7/74/vDZpOS0qEPDMdPb+0fPLXrp29IVItBwI596LYQrDRt2h/nG9dtvOA5x/r+4U9+7sLP/uVr/sT/tbzt5lU5EHJvPMzUw3KpBJZ67rdtEpEqI6s1oCOYa7VJEFXfvIdDScXMkIks3MzcNTxrqYm9NGvdqajnPLp7Imo58bSgNC0jgsMK6igypQQepRQRrX8urH84wnRU0zhV4dt0vx5dpc/8NV3bML386JMJJp5uaWp/ty7SnzGL5ro8qRKwCaPJMCWd1hsZapdfp+i1P6iHQpDV6tXM0Lhm9bi7WbSuuSAhpZxWvJqxvP7k1/7MLR96e/+lv/6V13hsBY/gKNKAoUepFhpkmqT1SICQFBtugGUcxwC0CGQKx46d4GlrzWTbx0CSanV1IHdFRLdgsArgOUp49GoKB4xwjyAGRExMXRJmRuGURESQqW0SAyJQTWydipsKbSGqhij0CAYKQKjWlMC0bkbXXHsAkGhqwFXXdZaLQoniVGLlXtv3/Tx4+JmdG37v9nO/2z36mgdfTTw3IgkXMxQ2U4FoZ3OAUAcCMICmMvFrQ0BEIg1yjgIBwuiIQgRCXiplpG6fAmuwLESlwDDV5ONnaAvQEdDMmNHMZB5nP3dP3l9qs3O43KcotCp9Qonu1ptvXu7ub2xshMDV8+d9MT9x+mSuOiMrs8WcHU/OTiz3D648ft/F8y/e2b7Wyzr1aFq+GgYgkCEYoyMwesuCBgaQUsLi4gZI6jgcLgMTgSNSw6k61hjRtdTXFoImiiXWa9gjwHHNkA6ICEH26jykAIiaVRCEBlYf79oxETgATd6k0Aibonk9qlkKa+iWVa6vg6MDIFbGcIEKYoRw1bqJGIYB3EVkWFv/G2rysqdZN4YzcRACcTChe0UtgAM6GEJ9ywglqwOTqQmzZZsWWADMOGphZFVDkggspk3TMUK4IwKQWMlVBlEVaqq5FtBuJsymCgBaKjQj1L3pulLGlFLRXNy4SWZGTbJBG5ZRi5m17dxda52xbp2r0ZxUMyASkaipVsodEkEQR4Q6tIhBFVWAaw5MXSlhBaVNePUkdVbTBCpEAtKACVMJgIhtEsIQj5m0RkDqDtEGqVnbtqUUJmibpuQBkQgCadgbhig+W5weCuHJ7prTtzZtd91dXg6PfccXbv2evdt+4Rs++Vfu/a2fuv+6r5TLX7Nx9dnXxzVb286zg8V2GrfPy94h0aUb3nju9Nf2i2us2QY3GHfPNPzkxU9euuZaplXC1jw8ymg6E4JEUOoZ7u6BRBMUCkKQoAqPjtaFUwdE7l4bkfqxBBIFIKBFpNRSgGUTiHA3U11LdqdebUyFeWxOpvFd73lgSf/TzlybD7W3sydfvNmU1GxAqISOjiO2Kfj0Hc/+xG//0n1PfPkv/9A37R2U173ozhtPnPyHv/g753qx2Q7BUnvtabHY2Sl74/WnTyqCR+jhLmGybhOBRx38d35z78Y/e2EsL/+Jv/jeL31m61/+2Ilv/+FrfuSvPPHIFxcsQixIQUZQvbZAGPUhPrL3cUVnOCXiOq0dhzyOIyUySWam4cRBgOqmEOza9jNiki6hCoW0OEM3Qao57CUcq1MtF82FOYmINY03QUQped0V1Rlv5Q/Uv0FhogkUhwFHM4pn/Iygzkvrk1hHkFNeIYTFUVNYlyswtcuTsyPAnHjyWSHh+taIihk66ohqlzxd80S1kyMiYHd3SmJmpKqqNVRuFUNkQHQpvErUSLcbqxf0z3nFlac+8twn//Dqg2944AWXwZvIe6lpNFF4APL6+5qmJxC5ZhUDIkuEJaSwIMcgJGCidUQtAAAQcL1Y3IOQqu/ZPRSmZE1zC7AK7E6MQlwpWpSoEWpJarQDN0kIU0rIkohlYlISEApx1Y07RDAlXHeSazIak7g78iRGn1FSNyCckj0QEWAcRxQcAca1Vl6Leylg7manyuaLhjs+8eyvfvr8Y1/X35ExdzY4o4NTYveQJi0Pe2AyIA6vEZ/kFszhEyAfkBNTI4Lh6uZAjaRSDCkIiCp9jFIQKjhNaOb/o6ojInfNORszMYy2/9DDnz1/9rHl2EHnx2eLDe62O2xOtH1/sDNLAPboY0+1JGG0tz/gKrTsRdaB2n5cPcjando+fXyey7Jt+HAoyODuxbxNjYbVo3/istX2D8ncpW3HcdWmOYa7R2q4lFyJMiLChGZOQSSsqmoFgQKi8mWr2xQRa849TaEqWAMTHadsbEQEiHHsq69XRCyc2oYDkkVxK+hVs9pJwmLEhAEGQcLMEqqefcKxQbi7iDytuQDmdRx3DYastS85UAAQ7h8eLqSptv6ohSFERGpSSilpLqoqKIpaA48AYbVaIYm6MXPbthEBDGYFGEC9nc28711NhJ3DORKLFw2iYsoIYWoewkEQ7hCuFZFYJwH1IuxmjbpDBAxDwxwlJyIPEIdjWzvjOF4ZDwwq1aRunYBqnaEBhE3Xah6PHTt+6cJFV89uFW5DiAkFAcGD3QlMyaNaaSZYdABEbW0AINSCq3C06gSBURwxiZDVnLdpA511aJqZEKaIYlbcg6VBkuQWlfIZplr9g1k1AY0Ag3Wn89VrztxZjp0WQBCGEN7YPv2KrXc+mG783Jf//vbl3/y61ZO7xz69ar44jPecw8NudWofFrMTG8733vWDV3fu6rsTpVl4/VHPT612r/zbZ//AzVtXz+SHDLAtpXRTRsBheItS8zgCrG5AYYp0hxpLEkdHenUSVcBTVHEzmlnlw1ixLjWmVo9jCY++jMvcsyMjmUyG9G5+6vKjF576xz92y0c/uHXmFTf+X/+UTu6Uz311OBYZZ8wpSMBVSCB8dNPAn/ixb/ntX/n1X/k3//11r3jueOtzDjeOf/+f/7bf/eSTDz72cLNrx+A8hN86frbrb7mq3zZCAqTCM0QgHbVdHG5fd8t//ul8TXf1ujvLwxePvfG1+3/4gb13/tKLvvHPbL/425567BNdSkmEGcXF3WcpNZKarqv3X71aDOuk1o8dO9l1Xcl6eHCwv78Pa+2GuaNHIh6sFAwwFU1ItMHtFs0sNQ5Rygjo6g5mM1Ui8slYG4gQauqjZkspuVopRUSqdFBVw5yTNITMVC/DSnT2o841pglnLYv0CP68xlzUL5XWG1Ve++psAlwiQA10mQqt8KMhJALwlGQZgUAU6FDFTRYBhFhPMhExNAZG52lNK6KqqtoUPkzKNO6zHzsYeuA9cXD61ief/5FbLr//9ifuvnjDYtUddtRqSpDHSj10q5gvYQZCV2N0tOwOSBSggG4RzkiGRHWwUP1+VO2h7lATVdWsaZtax6g6ek26mHSzDTMjtZJAkoGllBohIa71lszajpiECRkA2qYhImZyCBPgILApcgTXaWEuhABugUxQ+aeIAKAWyAkZzY0BQQ0tksYqj5FzDIOvBsi5P1z2VhQDEHBbXrF35mN6/+ef9fAf++qtyxml7AxtUWXkcRxXeweVsQaA6FFCuQaeMRMymruQI6BBAui62SqPBXyWFuiolt3dipZS6sQ01Bwg3FJK2fLTFzCTO1QxDhMJNy/85lfsba3snNqVvb29YdEcvzSeb3ISaYRgNax8hhs729I26Xg3m6VhU3hz3jab186lObmYd+2zr7vmZroBFIhBUgqLLjVmNus698r7IKkbMopKJQgryJRrb8CIpkSYWCJMVQGrNjAmYAUTAym4Vv83BSEmRnZWAtVAQkKYAAi1VQ6IiJzzbDYrpTBzMe26ecLI5gGhbgLoxYKjd2MnRCYCRKybdVTrSA50NDdBmS5Qd4ypyK13CWDUEVcdt7JFm2QEdyHsmq7rbBi5QGICcFDL7ohYwh3JCcFBVTfnm8vlMlhMFUnMAsjNlIgCrPqkm0b63iUEADhRgJuVra2NK7u7yDXkLSCciMaK1nFPTGrBzBsb8+Vy6aE5AzfctG3Ont0AHD2QeSjl4ML52hgUN2aWlEopibjr2lIKCxTX1WpILJcuXI5AQmEmHy0CI7DGzkdUVYcJNVVK6e6AU2YcV8x21DjrwABQQ3dhWoVWD3H9mGvvzyJgC0idWvbA7IU7tsgxlHBwiMRCNecbUS2AZITC2jZN/4Bv+vEbmZmbZi1NxGZ54YY7Nh9c2a81d3/36vwf3ntw3xv+whOnXrTb0nw88Cc+Kg+88+z8xefa2wrOtd2qIhAACIhz3amdRf+V2DpxeE439GQuWBhiGHl74WSY6y0TYYBwdOcWrKq+6RBmJMRgRKAK4VdEcDd1bRoCgBijVh6llK5N4mZ5ZYe03Bxwf97RYZ4DHC5OfOaPzj65F3/tv//25R//a/O3/8qZT73r3m/6gXMXz+uZPnXzIOGymo+XVmnb0kah5vxAP//Fxbf/ybc8f/mln/2tD9375GY7OxDh7e3m5c+/49qr9778gd/Yjnzf8Vd+6pavyeqR2K0AEnresYMxNpc7N3z+VX/mFf/+b39meKots604sdicO23e995ffeGrX3vNiefm4bJh4Qa7CAvH1HQtUJNYpNoyIiJKEBGhXLh01aNHZFPoWobg4gGsbiQOgRaGZLKgYS5EgNJK185KKejRJeokRUSuiAl3VTVX04oTcNcILLkMteScd204q7ZNM1PPGOFNysMwTx2gAzOYYytlzI0wANSkI4/glMgmtsf6QsVgwNoSIrq7whQyDzUcau1ZpICaoEeMHk6AHlbfT0Rx14AIciRWM6QpuQhioutxEndrm8ZyCWFVzUQppZCCVgbleSmFyXOelTTK3snhxLc/eOoDd114x+0P/qnPvUR1nCEqY1IqZkYMAEhkAayWkLKHgQlRuAogBCNCaiRnHUwBGZAZ0ENBcABrHAQRa6RmmaIOE0dUhjQRETCjEIk0bWoUyrxtmSQRt20rTESUUkKmWk/UD80RamBk6wQAyBPOPgACHepxgQAJA+qIDd0qzDlq1VNje4qp5aKqvQ2lH60vy2V/MBwO4xiBDaEwMcvL48wNV2/40vHHzm2tnrM6dW5OPBYM4SET83xjgaP24QCGTOSerbAwqhJKAEhxJpzN5w7Wm21ubiJizpkbHkYUk2U6ryPL2DH10qQhBTsUP0x48ugCDhyUkyHOuzLPSduuO3Pzq577+ojZ8vDQd+MQl80wAMRhink0CLZxbHFQhmHVH4Rtdc0GHO/cDtkddCirPvGl4fBMt9miHNuU/Vw6ItPOorcAD0fEBpzcpk2EBpsXCTeIGOqoH8NbFkL34CygBKn6JBO1PLMxK7mbsQQihqlFjAYAIIwBhKkppThWcTKFFU6N5tJK24jUrUqbGg7HYHIr6kLi4YagWZumAYuGeDGbuetYMgIHU3FgYGbMOQeFAjg4Tpm45EJogUEFwzRqK+simQShT57Ucj8IeC4AKVJpWAI7xEELEQkEeQiEzLpBVyioZThx7FjfL4urGzFwqDbAmE0AL1++TMLYNlhGg3pX4f7hipvWS+6hDpU6AFAKYOBovCDYAOa5X0WEUAoH0xi8ZydBrrpM9wADQWFkxDCoZ4OlJgXiYKODYzQsSSzXIUbd94pDTwooJSgRI2RzbaU1JzQzqKBsDEQGxoAZshA6eHELj83F1uHh4ZqXJy2JWt6Yz2aLzbPnLszn86zaingeu8SK0UliSn3fS1oMq9EZrc7AYgpiD4aI+UjLjRb+aLjLzdpWMAzBvAwoHcw2MWe94bUPPf6r//rR8ut/7O/65nHy1Hg3T+3FW9984tRLtmw8Np+f3Tq1npzH9B/Ew2g3vTwxu/6mw/svJd5xTCTBGWkOYRjRWCBgDnAgoTAEdocgMycEImyY3LRJNFIkYi9oZu7E0hUNwgChw7FvmiYoDF1K2HL/yX25cdyZ46NfvubG24bVXZ/8wuU7b7vp279p84l3/vr42d8/ueXH3/9fZmdeZZSoaanb8HHJLKvZqQAQ7bvxYphTA//187eBvySefYceXo22A5mhK/d7q8WtV6//3q2Hfu/xM9/BssDZxpE0idMMZu1LNg8vvveXPvqt/0+S5uZ3/ZOn7uoeu23P/eDmTwU9+NjBuSujpsXGrbk8W709OwABAABJREFUBXF5GLJQ1wirBpESMmEdwlQeUFU/UqLWzbuuG5YDwhAR1M6bUlLbrPqhI5cGlgOLbCAAN81Mug6bQMhR6n3VBCkKmTEXVQ6y6u6ot3ANMFot3dXatk0NAbACWMMwjC3LYT5opGGk0hAejhHhNQrOg3lyOBztQqbhLUUlA3PVO8AajbQe8NI6A9UBCKlmlx79qq1VRKnaLiIMc/ApHrr21DFx92p69IS3ZebAEhHrCArOyI6SgQuW4kGm3/DkCz93/Yc+etO5Fz711PPPnTk/P79ZTjiNRDR5rSoYkoASz6wdhoHalJo0ltznUVKa9PXARTWxuJmIFC+CuN4iOUxw0GlGLFR3ugAAjMTMraSmaUC6lBICJeKu61gIA5jZGmYkJEIgDOcAckTEmuN0VOg8PViu4ZEWiBX+URmUT3vGEFGteNGcs+YyrpY569D34zh40ZYldW3GOY2cZnKy3Xnz7nN+7sSFD1771Refu2lbc0i38iHm7YaDmucNmQNYLu6g7rwOz8EJV4odCUekeVejbziJzFo1WyQ1zQvdbA2pjcEoWbdAL7K9Sdinp+f5Du2xZc6OPZYr43LnrD41u/TU1hMzb2aMsMkGZVzMBm2S+SBXfYYP3fcox/YLr33p183uuP7Ys7c3btrf+8Wt2SsO9cSXL3/5Y5f+5+5mOX4ysS96zS21oEuEQYOGwTurEjvwxO7upRCRdMKr4fjxY4eHh9nDAymlQlQsL5AZw9yLesOoqjlrtc77pM5ba12m1EtHCi+KiJYLUa1fIedcJdnjUJIwMtf4vHEcAUASuYHBZPkrpcxSU2fUNXnW6rnp6uoeWqlNVgozd83M3YuXKA5eu2GMQEMKD9fiEIxIEG6gOhJGSqlGtQBWPV893NwiiCR7uFW8JB7sL9VyxZIjI7ezrCMAEnXQD2VUoGJoLXBC1prKoKHu2+2Ga3jxiGhREBNEOFrumuKuCk3TmFnXdaWMlEQtaqiDuzoCSk0jKjzJ5QiBEZgADYgJ0NTDDY1TapGrQ7FgdJKyQmIppXgoCw55JG4DMgBU8XmEAxpAmJUS02+uWpb9WAF8Hs7EGgYAs9kMALo2qWViECRiOjIBqDsQGcRsMe/7XseCSVDEwc1NABYUA7AV6RKc7J9azm8BSRQE0gGiRbeX5gM07bj66qkbaPMUbp6w+XYPsEKKMlyY30DtDJ8BqQbEylRCBAt08mIyxxxChRid0K24KmNyNMEKuXJE5cBSDIgZbRrHB6FxIwbIAQSE4R7EMKllibgTHoGymzMOmgU8Lo1b1zz01Z0Pf3RrfssDf+zrH+0feeO3nOm+/KVLf/qfyKc/cmrr5EVtj+Vd+sq72jf+g7x1Ml94FG3Y2NlxbtAK6UoQnvfA/5R7PvDmN/3AWw9eMLvxxc3JWyIiygDSWJofLC8tXvhm/5o3bOP21ZGyYoCjK5LMQEvf7+x+4Vr83OK37v2D7/zH+ObVYy/5xwAuAR8u/ty3f/qO/uLgkiNtNsdUD7klHyMPYySOXsPBixqnuojV4AgjRigJMfby/rXHTjfUS6KzF1dti4fj7uZip1+tDg6XSk3xAIKEzCxO4e5NFWgwaYdsFqDuzhBOIZX3KK6jE5Kp5pyLjsMwtF1pW+OEvvRM1EibWPqiIFKWpWEBjDFCiAEgcCSceEB1eF6PnFjbgoWkbrxonQNBASJSqoGSJzqnuVa/jeMkJjq6ZpCgKCAQ1YejOv9ijXGfzLjkNAmvpdK6GkEDIhBFJwrCEHL1JfGJXfrmB2/5z19z33vvfOTOC9sn+m4pZQ6kCLG2XVIAI6ZAhZw6Uh+HZZ+61M5EXUf1UGfAuUhN7VKfBMY4Tc4B1nsUxCDiNqUjeZ2INCzT1r/hlBIhM3OXGmI8WkNERA0DAkBDMIz19ADW73n9m6e16BRAEehTuNJR9JaZYfi46l1t6Ps8jDquxqIH/aGrtUIppW5j48AOAGneJD/ZfmN+4S/vfvoD25//gcNXHc+zXfRG0BhbA82FCVrHglIQ3b2YIaKH1sSqWmGklNquYWZBYuQqGVPKecnzZrOkUnToYj6bb3lzcHi57O3uTS5MAABYdH0czBYz34FTp05de83mlS98dtXcvT0eDlC0hwI+Bx2U93ST9i/pg++5/Jav/bPXzu88lm6+8Zruvst7n/jo+645devZJx84e/bTt91w/V/95v/wb774o1869+WX3voNtCqtNaONjqtkvPDuAMgBVmYDa0JqRLjGIDW0GpZZS9fOSymlOAgJthBWSl1YcvGA6jYi8CDGmrjtdYpuEVwjSAE8lJAiDFHqiNg8EKC62wFCiJi5lHE+75bLXqc/Ety9ndZDxu42eIXGeASjBxgRE6VSimpxAFN3GBCZBCv93AIFEACVUIJqcisCswTJHMArDM4NFpSCKYehASA4EgIMeUxt51U0yZyHIo1U9itSMjfhJufcr/okIsIQilUqCEwEEpgIiMRQAIujBiBzCiBHdYhutjEMgxAgShnHUgo6NsgrCoMAhCB2K+6KFKlNno2ImOo7xRFBUxKr6ZRFbR5Y3fYBYEXRQTUgrBGZvnhEjOQQgAIBphoVEA4k3DiCIFYgdlCNoiFVSw0Vw4uXL7vDYrFYA7MNkcyNpIa4RCCYZoVMCJ2wY4WvgRAIcQGZNQSrcbEzP1BephbC2/4CMx3KDkaQZ5XFl577w0F1Dxu12AZEkMbHpZdhZ3XxYOsGYAF3gKhMmwAkCDLCyGNqIoOSztW545nmZXHqWtJiFt40ydGHMUQcIufctu049kI8pf0QAhMAAyGoQ9QEenTE4gYRCQgcglhK0dMXHrv7yny865WfecG3r5J9y7fecfknf+rqv/rbNyyuGRIfrB437vabzS/f/RbbOvXYb/zUTv8AvfQHY8ZzgezQ6Hjzg7++df4zi2Pd2Y/+9uxlL7e9J3HnxgCgZjbtpZqbLitc1s3pkCDA8aDJyzI/2RfDfnz3F/ZevXXXnZ/7O5/4QUp7/3Bxyc6/4B+SYbeLX/kTe2+j//TG+98S/dXt2el7PvvEzbfvdKlBS6UfOZHlYlAQx+kWSxIRSE4FLHzr+PEP/sH//pl/9vcOD/d//bc+8Ovvfc+/+1f//Du+/ft+7G/9/SsHK+FstrLqbjIzAgevMeVGAIg6BVvWIWgDocXN1ADgafqVwajFowegBkjdvW1WVroQRITErGHMURW8NQslfPIsIiPikS/+6EpgpGogRsR6rQqST0upaQVRmwY0sAgPq/fr0QUG6xsX1z7RI7sUETGRuQNTgDMzVLx7lYsEcMD01CMZkpBvlLyf7GufeNbHb9j7wg1n3/PsR7/3vtuXkc3IwoPDqfLzA2o9JAERwkQkphmY2DxUg1oKFyTEoHmrZmEQRVGk7pMqUocZRUSE29SmlCRxFe+IiNTzIlG9mIkIq9oNkZlronIdF/jUSKMj8DNU5QCTJi6qSK1qFNfeMazbd3dTNTMrOvaDFR3HVd/3pV+NpuDRte2sSW3btvPFoswEaWPWaqPPS2e+uX/B23c+8vnZE98hLxxK33Cr4FWJKmZgDrPEowKAxcQiRUSqMBChOj9viBtJjBQBDcKhptNbaa9fdhzN/PQewpNf/II9kZtr/OT11922/fyj72zzYJ+uPsAPnrdHPlvu+XDs93aTrF78rNvbkxfLrqW+005mvVO7e+7gvrc99Y/+yj997Qvf/Pf/+c/sPvFfT8nsgm8eOzb76sNyZmf72LUAx/oTduwlx183lvMLaosWgrBu1h9kVwPsCzgCJGYKMlUmrolG1LXDMDKliXsFWOVaRAYeQUJM4R4RjYj6hIuBOulAQnR3P8qgr59SYoYjoZ9b27TVIVYd2+PYz9qOiCooKhBhXd0CAAsGhTtURwCRmKsDhIS75zAPIOaIGNWYoYm6ZiaYZDduEBQI4cIgLEgajsQh2BC7YYCHhRaKFjkhKQQSijRlzADgaiLSzWdjxWmR5VHRY2OxSNL4kDHAHJJACgpkYxYHxFCGJppdK0wQQlAl3WCG6NKMyx7BZ22XR00pafHU8FBy4BQEvvZJirtqNgZ+hnPS1gdOQMLGOAUBoQO6EBkQQFApxVi4TutaaYfDg9QwIGOEaUBYXQWvZaShpYg0RFQjqtC9YdGI1WoQIZHEDDnniEAGA5ucmVXsNumaHAWZOCIwgoCQISEhoDZ2mIss0vXN5fu7uwCAQ8f2GCJSwCxfTfnw9s/8DHr60st/bOx2VOY1QhKWu5E6OLgg3cay26x7XFiTbSAQI+aiHnGanso6NMPihp3NQ97ftVhG3/HMNAdQ4QBVZsaOoWSBhOA69F1KRNRKalgisMJTgcmLAkS4URC4YytRgeoA6Chbly7c/vZ/fuzut3z2h/+Mb156JRye+/6/1P3226+75fmr5RUsMZw8fen84a/9+HuWJ265+QNvvffKQwcX7rv0mR+57nVvfP7zb19eePLY6oGUB43Z0vMm7G8JHdSwuX4/2gU1izCdHAY0KdOx9Bv9JW22CkQAMPPz7jxzdUj3/uB2f+0f5PTu44/+5OXn/v7y5IfGHdx8LD51zXte/Nh3b1/dWczlwx/95Gc/N/zwW/7sQw8+emyxcJRcxqPnDBGxMACAuSAUjc3trZ//uZ8+d/6xMupvve2X3v6OD1x//PrPf+pj//Fn/ulf/et/87HHHrVcwHEANXR2okAXNECISBFjoEONr8QpbAu8oi8BLMAAJ0ydmw3DCgrkrk1eGm4PoWy0M91fjkKgNYerMnudOXGSUsqRgjXwaBBdR9AMhA7hCITMgMysVW7GzMzVSFMLN/dJEW3qNUm7GlsqphERwwF9rSUBJ6I6f3bwSkKoUi8CqnTKCoiomjV31/DA0Tn10L7+kZvvOfn4793+1Nc8de3xfnuQEhbkLlPUDFd5uUgXWTU7M0NgQ2Ku4A6MLbcEkVpxQhHRMWMkI6sM9HraikjbpJQSsTRN0zSJuQqk6sUsR7r36T71qOvbyddbXV1TRCJU3jdURVuVBdVBA0KsI5jWifExrRjMKvxvHMc89uM46phzP6zGlaBszubSNqmVpmnapt2QGTB17cZCZjZrfuDqK97Vf/Ztm1/83oOXbkAgYqu2EgsAtsjgiTCg1GY9CCeMO0EilhoWSSTCzEzCgZTDtubzfHCp29nM2zed/dQnHv7IR2954Ute8+o7/PFl/PbbL33yJ48u4McvP77JzcHlq4tbrtPnPvelP/xPrnnPL3/+bR9+66/97tv+1//+T+f/B23tHZbZ5gY+ee/w6le87mu/7s2f+dC9L3nZGXzxDZ3xsTOn92080LPzizfd+/hDn/zMw1/7/CtMDpSvPXZs9/ApMEOLVmlldtDkmk4lxVMCbJp21iGi9gMpzWSulkspkpIjWClIFBGzthuzTh4h1SowrplIlch2JEhkZveo9Sb45Nar9hh3zzkjQISVPqeUEHEYhmEY1LReukfaflWVVsCIqtZ9vV8goggcxxzutSAgFJQp0WhCtdaHwqdKXESIjtLj4eiVRSL3CIBEjBZmJTgkJQ+btWnIWRrWYsuhlyZBooa5X64akeXyAIBmXVdUpWEMoxrhQgGAGu5qFiARiByWwjNxAcQIokloCMPQm066WjULsHaWEnX1U6r2JKEGMTQ8IAABQxHqW1WHT0g8bZMsEIMM1MyQpZvLashMGO7Lw8NETIhApVZJCMBMlCPAkU29qCoBIE3pMBXRQQxdapBBs6GjiACTuWPD1f6g6muJnDOSQ2QvlVcvYaQYBCEMZo3NFsev+eKD9+rpu2H38QVoSRtBwdaDlp1LX24v/lHs3CU+uh4ENzweKIpvnEB32jiB0oJrtW48sybf3D+/4ctjp+nZ3QnVdJ77y3u7QSPCYiZioZ20vWZTb9sZIpaSE4JV4xswIpZSTp28ZrlcBoAQpsRYlTdmiIyOpmo6ISjaWTeOo6jGheM797/jX93wrn9747V3XDp3/41EeuKYmVnGPd+7tLv9P/7mh3K79S3/+s2r5bmv3PZd9+y3lPjhL9zz+p3zs4PlELNIlprlIrb6Vb4mX0nzxV6Yz7ciD4CAksAyVfMXJ3AHTsPGaaMGILq2tbZ5qpOBntfzvVtfBadxdexz+zd/qNkFS9GfwE2kr1zziW84+M6zZ594zWu/9jMf/3Qpi1VZxf4h9AsMj4h6Lk8vLYJ4M5bVzs7xz37qj84/+eSxnWtK8V/4L/+J0sbm1uk8DO9+12/d/dJX3/LcO8MZwqeoevBwgAicAr+AmcPNItQttHgoRgiRgjVCiOwO7iBIgYEUY3isemjAQYlk1DjoV4omweuT5aihrj5Fefo1xmesHoMmeR4CIdfLpl5LnERCAqmeICU8Ijy7u4epmYX50bIz1vanow4YYGr3RKSYdl1XRaTuzsgFHatY2iHcDbyAqxlqu1XypabccX7zGx+5/X13fvn3bnnsz33xJYOUQAggA2QSJGIE8MiHh/O2a5sUCCVAQ7PlWWqIUFoRrELWcDVGajoZdCT8PxxlTZtEhFhSqhpzOfJQiQgdUd9q0AVgrFOhj35NthYHRIxwniiZAACTzToCBMHDwat3mwDNzM1KKWUcVLVfrcZxHJYrVc05U9M00mzMFiSMbeoWXcMNjy0iHCz4We3OoeU7t2571vKGr+w89unmwoubG/dtFKI5iJmRUBKCodg8wZoQfnQl0ETyRAAgnFYPCg6EdnA4O30TnL988V/8o+tvuvlrv/2P77/zHQ/97L93zQ0NN3//nz36rs+dv3Lqjpef/p7XNTN86sNfOl+euvn0zfqZD//497/h7/yDt977+Os/+NivHY9ZX/DG24Y/eveHP/3xT73sRS+9/typx6889pWDBx556h7w4WTaSPP07BuuffGZW7544ZNfbD94/7u+tHn2+q/52lddeur8aCOEoSkb5okkRRSQhzKWLMRCVMKYORdLKUUEgrdMRASOFEAYFfONiERYbJ0DfZQhXeVD5lU6CxG1zUXEoh4Rs9msDKO7N41sbm4sl0t3WywWeSgUU5bU9KgAMIpZVleRGuNr0xYWgwISsa8buQCrjGhz0zXeTSE8ggCZiZvkGoDOLMiMSBhoFigBiQiRCN2UE2OE5iLV7GsGIpKo4w6ZxpwtlAShEZ0IdBEe6EoOhZAjqFhJEGFkOGJIaET1JzODBSIAmkeEWfVkY9nY2FoOIzeSFRhRLZdRSykQRETqCgDwDGx4jfWsVSwZjAgghAFNAEAaAjSckKvRow7J6rApJS5WiAgBBKVpRFwAavolSCImDiSpEUmmaI4eTuYWxIwBZuFmIFBHXlP4NlAlGtQcOeYEFTcctUmH7JYO8Lbn3vJv/91/7L/jX9sX3nnxkU9uvuZPJjQLTwQ7Fz95x4PvtO74eOnhZnXJ4CSmLZUZAKCOQRKz7bCClbviMSlOIgBpdvXxu//oN255/D3/YnvzuTc8+4Uv+pp0+/OuPnV2Q6CUA/F25SsJniMV14al5WawUdEqQ7BhMoQnLpzDgLZtkcEZKaB40cq9RjPwRIII6harPiJkuX3iwt/+2c1dGd/39vR77z597HRubXV4iLu7A9qT17zg1/7Cr4H5t/zL1+ClR3Fn58y5z9xz3anmsfOP7z76lYubL7p28+DiEptN9Pac7W40euOTv3f5rh/aKlf79ph2C6ttPjceDsTgDuFBVLir48EVALmVS+dumy8/+4pf22/ee/V6fs57P3v8qy+88pwvoIEPEQ6HdPlwGBfB48qe/+JXPf7k/i23vvBLn/94SlaFw8xMjJUsGBGJmzGCm4P/9cs/d8M1156/sr8c9hui7RPH1TS7LTa2f/6//cJdL3rp7a+9LRC0H0YaqlVfADHAqgVVw92RiYAKgqmZWUWpwVoSVTO4RIgTOyAWY8DDftU6H8aBSjCSMVT23qTYPxoUx4SYRnp6XOYRWDGi7lHXwMSUJKWUBqqe1ya1tX9yd6iaxMot8HCdngkCVC/rCL7JeIcBAQY1NT3CtUyVPgICoTsJw1QuIXqIe2hghiVgSH+V4XUP3/WpG5/88J2Pv/TiDTdd2vIgZ3CIHFYR0IR04ppjh1f3LTIxq6tBzNrUNtJQCkJHsKLztjMzIACMrutoslKvPUWJRSSYEwsL1cN0+nw8KqMg1gQuiHUIR6X0I9ThgUcAgmFwgEHwesccE2IMIWt1eEwjUHMrauY59+M45nHs+34cxzL2jkCJmlnXSifdLKXUdKmbzVJqKRpCbBXCYMByg2z+ELzy7+nbfoM+cXecaYOCkYmQzBmREFpsAp55AU+ZQohTdKNPS6NwCAhk2bnxxstvf//5n/v7r/zhv3awcdtnf/QvnJ5t3vza7+q+9RV84qTedvPTh+pPvvWpv/unt9/zHWevPHX8s5+8alcvPvsFr/vLf++XfvJvPm7/6OWvfdVD54fm5mYxLPwGOvMt8Xfe8Zde+Zmv+8bnffdtG7dyavw6bghX1i/b3f54/1S+/wuPvW/z1u39R6786j0/+/I3vmZYln1bllERvY22Tmx60EIgqcG6mg3Syg5tKBB1LE1KSGi5UJJSCgtXh2jHHMiIay/ANF6uXBlX0ymFej0a8UANd3fVjAAiOOQxDiEQU2oPD1eJpaa405o8E45ARtPDU5HS62veIrtWGHTN+KubJWYMM2VCQAhwNEdPACQYEUxJEhA2xTNiIlJmJnCFCLWWJRDbWWdFV6sVABUbF5ubfd9H4OZ8fnBw0Eor5MKwykNNLg+PlFIUNUFECg2LKaMLERnZ3KLmrmIyJKE6MgBCQYzxcL/r5vv7+9J241hEaLlcIjAhJmmj2kYAUaYCNSLqzKvOfYmQ2pZKmYaUFgyRGJ0Ey4TmrXDyiOAmFcvuxMjkEohayI0B0Aphwyk1HGTugQLoQslKJkIDMMuASIHVsyXUaClCbOtxgk14A0DgCmWB6mWAMDMtdtMdZ/7Tb/z7K3f/habf+8p//0uad7/Dv4o71wtTN1yead+0MajExtZ1D7374ef/4Ly/UGTTWKCMRWaR5sASjUA4ag+c0rDf9MvDEze/6Pf/47Me+sNnaXzfOf97n/5f73jPr3/vt3zPa/7Un1l+9fxBO2cYZyEjhSO2JEYwoCcgChKR2Wx2dXeXag0N4O4pqL69jVENGs+uATiUzESMFKopJdk+feoFd9/SrU4tvuUN+siPPPJjf/umz93TnNg5d/XCU6ef/z//0jvS8tIbfv4729d8/eY3/vHjW2fu/Yk/ff2V9vypO66z4SOP8410duv4yau7/eaihzzsc3vN5S/d/Pj7H7/hDd3q3Jg2vDkWlABpGsQTVesnunXDXhu61V9608f/zamhv9QfPPaKx67O799+8kdNDrV7oDmgvOm6AD+MY4cnV9Zfv3XL5z/72Re95kUG13R88823yFfu+UDTSKJJeVgfVzNjPCiyuPrIU/fc82lU0rQ4fs3J/YtPHhzE6eNpmYcmdf1q99Mf/f2x2YVbadn3GUcEQOARARjMjBE011sTISbBVGIR4WEYs2ZzRSRmqe+zh/EISlBKSZQKhlBiU0M42sfUyVsNx3ZzX2M10PHoAq5nTcmmqlNbQMRNamddIZzQH5VqhqBuIlJ3KhCOHla0IoqIyEPdfe27DWZOjO5eMMAjiayWy6Zp+iGntnELrtE6TBFR9cO1YyiRh4iu4LzZafavvukrd/yPl37hXXd94a98+OsYoGX29RLICIBpvy/OSQCL2azbBICGsCFBjkiczVLbAVCXWF0hccOCQEeLXiJiIWa2gKZpGpYAhyrRAcTp+HjaNr1uc2MEq95oAKDwuj5ngBKOAKWe5l4J2+gIAlMomyOEmhV1dfToc19K6VerUoqOQxAK82w2a7q2aWcptfNullgwEJgiEQC1AQFZRC748o/xC//96j2/s/3Fv7H6tpbICAGQOYFZyuFt4+AYSOvtZn0wAKABWvYrwilWGVPiWTeaPvr//8vbH3r/69/6y5/93T/Q3/oPr/zFt1775lf8/k+/ffjmbzhxchueEUc45xvS5sI/9o5rFW3nho1v/YtPnnzwq+9951/8oR/9J//2x979vl/fgJNf/rpjz3rTGcbtneuPHTu+dcMGvu3sf+hX/oJTt1Ps3HJsa9Ucp/GpXIaPPvau2295/tkLV208df7wqT/86sdO+qn+YLRsXXIYjChXFbTSBNAwd0WfObgrMWYt3DVBNI4qTQPhiCxIJTKzENBqHEMIqUqF6zPkQRPVtc45GTHnnFJSNUQEZCJjJIxomqaS07OqiNSbTJqmznWmWUINKSICMyCKiHpuanjBCDNkjKBsJiJB1GuecTKmaehNgAFNICYCaigIcCwWAdbIRpPcNcis5xDihbSXD/f2loccQMIRQNJkNU5NmK8Oe0ZBh6y5Sd1WszAzDAyIcAvhMaIBdALzaDWCsBCwEYUoGGIlcAASMiOQWbiVLG1TvFTiWyK2YiIdIrpa0VJTUhzBzYRSncM5CUVUbAaRFAwLbwwRsYQXmEjFAYyhbdvmrBaBdS9GmKaJHUS4qk0lLTgQEgk5BXkguAMzo7g7QhihqGqDCTHc1DxSsCCpKjA5RDEVaeoRKECtCDEPrsVKO+uOzxd/+Id/eN/erde99hW7v/Adx3fK5cfx4MpTL/Qrl5tufurk4dkDSIu+aCtw/WN/gB4P3fV9jXmgq4c1m83q8jA7xl4W/XkF6jeuh8DZ8mI0s7N3vObOL77roo5/7MabPpBu/mSUd/7Gb5xFu/WbX/viw243qIQ30CRAVUUnxihugliGvD9mCkhIDaaiY5tSdgQPNK2+fyMwQ6VoTRDAIkKodxUI/PnfuPf9H7mw2Iq/+APPfeMvv/uev/j9t376Q0/e9upf+ZFf2zg4+/rDt535L7+9Zdfu60VAvvVNb3rkV351dewNLmPMj73j3MbL8yM3NsxxzUw2gnYfO34jBc/6S5e3b8/dMaiooXDOvZRD49aka4dDTM1tj3zszO4jL8bd4epTLgkzvPTd8OiftI1Hv3V5+v39iVUApD3Qzbi4/fiZ83dYyYZiZf9//ud/9f/7ibde2Lt4bOfkHc9/9ZOf+1AsupF4IwFoipI1DvaWZfPk1rnPPTT0NjtNi329eu7CSPL6Hbjt9HD/6Zc8eHaW8J7hsDx+8X682dFhmXOXNBe2JFIGsbQkbwG1Ti+1JHRwCAElJm5drYakeYxSFx5GlJzcI5wJCcFCo46p1JgxwttGahoMNEyQ1DIAFEVJKcxTSqCFkUqACzpR8Sga6N6Gm5YkbR4LM4+WTT0C2QG0YBgFbi42L1w4nzoS8nEwcmZQQq8kcVOwCAt2t/CMHqDs7rlfoaRxVRDY6vygbcMRmzSoB2E2D3Pycpg6KVe42Xr1U/LRG7764HWrT9zy0Bseu0PRD6kkQTJB3U5+ZQCctalifYihm8+jZDMDkGQ0r4plRmBquUmEBIKILAIA3Eyy5wDv2q5OI56eK0PUM8jMgBCFixYighp0YXyEhPOpeLB1cW1HQ+aj9KcBTFDAw9Xr0H307K7jquQ85LGvZJU2tU0jnGTWbTaJ27aVVig1xCxBrWMAuGBhkawr8lu746+5ePuvnfz0O/DDf7V585OrfWzdiswt7c1W4kI6UewRkYXcvaLXSlZvhcZxCCUX04PxEw/4v/jJ65YXTv3cez/373/hum+/69k/97mv/Py77nnjW9qz99xw440ZFNIzxortqthWOr6Vt58Ff/fHl7e/Yv7Bn7l6+O6f+68fbry5/adePZ4//OpPfVK/fOX6N9524uUnvTRBvLGd02bzA3d+0/bm6S/977eRXnz2q7/p0dj/2JXZo6tXDTi77rt7mO3e1+2nx/d3dXU8cBgl5hY5MGAmMkui6hDUEIOpUgRScSNJUCzQCf8/st47zK6ruv9eZe99zr13qkajLlmWi9yNC2AMphdjICT0BEISUkkhvzRIQt60XxJSgUAob0ICCQQIgZBQbIOxjQHb2Mbdsq1iSVbXSFNvO+fsvdZ6/9h3RJ7nnUePH3tmPHM1c85Ze631/X6+oqCuCLGJjZhDb2oWnFrtDaMCEgKCqhITEpmoiiZS731sKmTsVj3vCgYUiWhGjhRRzVhVkgXvQWhISklR0szEFHlaXFzM0JXKYLIs+92VolUmIEOOYOCgjFRbzlhh5xAAHGVnDBFxSk0gRiPxJGCBGFRUIzIFpqhlEytRBDJHCE0C8stxGMp2XdcZQcdOidGTr+taUkJiEcnbkZQSM6sZZ4g9ICEVqbKEZmyACQQ8ZpAUMLGZpGgALhQCms9zTBZCIQnrlNmtGrUhsmRAYs7Q0BKYAIOBtyJZ7VwIodCY8kw+CohZqDEAWjAx46RGCMwmElHEzCNbqokcgpGYR1RiVGFCAKwlJZIMHCrFUJu8UU5qgFBJYkcczVQRidipgYIWRSulhrgYpn5HfQMEisnTcMil7zHRhJtZxJ4tL0APZws3eXzvZQ+e7Fmz8ac+N/etDyw9/EgqFtGVDxw9+syzrxisLMHBwy3ftpjazuqlBiSUR7/97FP3La+/vGslrMw9fdUvJ9+BcgokRZWEDgwwNUODtUcf3X/xKy7+9M9Vk5v9wvIv8rq7ml2t9tjj372VLz1r7uCjr7zoqoXWhn4zR57GdTJq6vgyggwVMr7NAIRgmBpGrmpxHgTR2ExjuyybOrEIACoIGakpI3tid+D04MmjcXJD0U3wvr974t4Xnn7zb33wjr/5iy+//i/X9Q7/7I9fUD/1G033+OH6ifGVU3Fy6/YXvWHrTf++1D94bO0OmHu6tWXj3Z2f4E53y/aLcPOVK61NgISaOiuHxo9+nwB6ay+OvqNhLEifUy2hw5rGFw5Nw/Al9/8ZnFqpKmBsuoadztjODz1+7ob182PXNGt/Yc1RrqP5ymSiVW8NH3nVO99x44eTnT02MV6OTW7aumFu8eTp04ONm3fghWnf0bs6rmRoo0vQIPqp2dnWoi1994nbzXtdhiH6GlYu2rLukkvWHtErdj3pl7AaT5e/+Dnj1SzM28FaEho1fQVASTWTiYGANkkcMJlSduUygqgziTFJI1Q4xxzrKgF65GjKnKHiBnn/qiMHKvpMVzdAVDTFHJWrBGxmjtBzyHxmxxxC0CSaUAWiiaKYIkrSaGDMYIOqdkmS5qA9YgJlYMDl7gryCLPiHZkBqTNUMDDTHKauIKrqEDOzAgBEBFUUySAliUVoKagLblAPXCiIaaLsNMNGhQwECg9x2IqdHzt+xd9Ofee28+avWlycrDdPRu5rN2CRilhiGYInMGQjIiHSlFB0NEYwoewmcgR5b0yUNcChKMwsZ0oiIpM/o+C3//WmqvEMX9O73NyoKqpJ0jNtcbZ15ZAJXo2ezanmmgnhZgRYnVFlAUiKMdaq2iSRmDM/vPc+hLIoy1C44Fves/eevdPsEMvTMwAwLUyNiyE3K1q9rrzyP3qPfNU//rOD68pQxNhzrjSEUjyKwP+a2OSjA+axHBekQ8YJaJYN+iat+qufnR0ubf2Dz973sQ+Xj9wOLzlvz39+r/tHf7h2YVdrcrobxjy2Eeoz9TcNtfC9Xj2R/s//M3zJ1Z/4l8eO0I+0nvWGzectwI2fSxcuTf7a1snWSv+j+x79t3vXPL1j5wu23g8PNRzX8MZqkU7efc/KnuNbJiYOfufeOzZeWZcvl2jWeNfy/uw1J6qS42ObYXc3UVlKNEkIlnM8OUEyA8tx5AQECGRooqMViFqK0hB673IWAhKtRt5KVkuZKKwawMgAiUrHTd2gWUpx4/qNJ0+dSiIhhKpRE3POIWrKYemootGieOeJ3eLKInsnpswuNjEHFJZlScxg2KRMulDNzmPQzJiDEacOlDAAkjF7V8fYckFEoqnDETsppSSWjbCoIoronAMwUGiahohGpgIzEDWULBMTEVQUWLUwrHrNnXPZsQDClUdKhElqUohKio1nEMkdJxGBWh56F2U5rOs8QgsODDEpMQbnnEeqmyaZGZLLGC+xxMDgyQg0ISUDEfCgbMqJFFUh5TzabKBGU/WGrdZYr99vtTrDpkZGIFRTl3DkYARwREE5O6eSAZghgidylBX+QERARkCi2TlCIJrn6w0ulzpbuUUFJhnO1G4Oezw5FU3l9Jx3Mxec95rx9a2J47t637rx9FP7v/873xw/9OADt/7RVMsNlmR8YurJuVNPLi+c44tjgyphfxI6A+Uw3h66qjUIprF14C5M0q3r9tbr+huuFKnEl0O3Na/424FsZv0Op0+XW8oP3Rk29Hf9whufZ/iyYvOtKM2JQ+9+9ksPXMyH/uYjm179vFOz500vr9TFEpdrF6QvKj4/ONTATDQBADpHzknKhRmD46qqTBEAmFEVgcnjaCTp4vKpNbJch84F1Z0XbDp01mHbd+6Pf+PHP3jOY7e88pM/Hltf6u08q11b2V9JwCdPx22XXjn2uj886+kjxTNe56c28sQMAFiK8yf3bTn5g3PSwuSJ3WX1ZH/YBwlNKB5f8xccZejbtR9HPwFg7ZWTarL5zk+Vjz1pg2GJmAAlKgBP++KSO3/iO6+gyd7NzQqgKzbdpxf8145zfunvPv7in/vYj/78z938D9e96NXXXveS+YUlYmeJlo+dWL/uvKHVc8ceDtxExdDmYdO02hsf+Oa3Dz6+ryy8s4gAsYlhuNJvvfiru4PTfWmlvPYF1206K/zL3XdNrjfTVA+GGKMYJtZEBpJSUCJWQBNBNENFQpUUo6SoRigKCRRcQLUIGopAq0bevFWFkY3CkoqaCgAg+dz9ZRGKEeV4CFMiJELnfJMFDjTaewGAgsWUxAQSe0coyl6SAgCwAYNx6Tw7qesQHABkKkV+hFn2Eyka2yq4xjwHQKW88sER7V8RWkUgB0CqqL7w6BARkjSu47AKE1qbc1VplRbPWjr3RUcO3r7jwE0Xrf/Vh7d2S/YwWfnOWOrW7dCJTjWxRwMEsJTEEzmmBHAmMAoARswpNVcGyK8bLKvqVEEBjCFvBM/8VDNdIW8YRYSa0VQ/11cVOyNAAzRVXX2sU2YNnpE+SnaFJUj5h8+MBJpEkzCiWQKA4HxZliGU3vtQFGVZulCMoN80coPBqqSaACIJaVGktIzDq8cvvmx5y6MbDtwUn3oDXnGcKwBASVawi1FcRtjBGc0RIgKQ4IABBuO9cCp1Y+usTefs+PKnujcfvO+3f+eav343vOof73/WG9Y/+ocbxvzi7A5JEWNfCuf/d3YHIHc1/ejrB6+5+oOfW5jrQ3vLhAi1p8OWl70jnZgHeWDn77+9+8v7Dv/OHfOfPvDgvcc3XbadL+vIlu6Jzad1e9s2nvfUxul+vf7x45t1GI3XUpsoENbQcnF50zPLA09v8AOKRY2F0HL2WZNajpgEBkVjy/EgLJIQEFCJCM04KhNEpsaMmWKUFgeUZLy6P4PRD0UAGLCpajPzPngOp06dIgB0LqkiURIhZ84xEAbPiKiNtsFLTIo4NtGJmm0BMj45Ucccv6LaKDnviJFJJK5aG0a50nndY6Ae8tSKAYARU0rOBRklHIqqWnYlAWaycb4IiYg8mWRflQKAyz8Q1YyRjyKKesYcaGfyvDNVFg0dcQRBEAKHJGCJIOAIIIIIWaxX+qASGYGBkQ1Nk6a8mFGlplb2pKpCkLNMyEBQFQBJAK2pEcky5Z5ZFM2BQ4CkCpRl0JgUcAQzkQgKlv2KKTBLEmJTZMsLAkW0EcDV/Ei6ZmZgIiIaNVmOmzIDgeyoJLAkAgLawvZyWFHhfmy55ak1a2qc/u4DHBcmXv5TMy++Mh16ove3f9T/ymc3TG/4+Ov/brEY/90v/O7TAzlK7MtOUy8FdV+48/HfecVz277uDuoBli32jdeipw0au6KWFFzY2JkeP3j7kxuu5u5cbE1J6KDGIEM3Pu36R6rDc3ye7Z2+eGcL7IXXLv7Pd9+09fKb6oexnPjL9/3JX//lx85718/e84mP4fPr05sualdB6m4gInTNSEygo1x5wvzMUWVfejOLMaHaCARtho5XRZdGRA4lTTzwj3987b9esf30dAfuHHv9+7sXXaX3XXXnR0K9NLzxc3rBXz/h9BjoCZg6ieOyh+Dyd7hzTk+cfGpx7nj10G10fN+adsewM2x2jcfbwa9bKbhF5aDbPfnoXqv/uXrOT1E8BG4M2Y8Nuq7uthaPXnjf13HocbK1HPsT45smxid6Rw5M1v2Ta5+14eB9b3rnUntqbM/M1qePHWttXL+1v+EXv/AP//pj7/34q3/up2/+4CWnn9Pv98tO6dkv+0Hv2PHt264syE4ffqw9PlGlQVlJ3T1RdY8j1B03vVTNi50an1pzzjNuuP8kprl51zn7tW8+a0330Kc+//2Ji84bVHU9rE51jwVf1mYYwAFjg74AIULH3nuH1vIeNIHjRo0ECblSbWIqnHOAapJD6RGRVjs2YEAlNVWifNQ2QEViXO25HCXVJAkdO8cGQg6JvIgxEiNyZrBZUjU1i/XAOUJEDp7ZmxmDIShpU/gQMuFF1XuPZkx0xsVhZC7jGJEMjQkwW5CZGUZyeTYiNCZ2ZSmGQPnDDGaByYoWFCzIU+S9SNnwj/af84OlA9+d2v+CzTsumJ8uWzyIiK3xlpoyIhoSqIhkfC95QyAksOzAzxRbdsTkcsTsqF6eQe+CIaCsMnpVRDSXzaw7J8oGzfz0HL0BZuOpEaKa2qjrzUpzVRVJ+UuJ5Ux4AlQDoFwA1IgYnR+ZcT0XRcv5IidusXf/e0+fB+JgMDLPKDYGXqMXS2h1y70xXbGr2vUFuveGtNOATJoBWUiojlZf7KrlBkba1Da6FaNyaf7EfHPWhTvbm8vT//Vw/MRHLn3Pz+x/bK/9yfun99xLk9PddROTR04MtJ4oZuvZtelg90z51bHF5Rpodvbjn9q9stjjmbOG1ZghJEU/4dOK2YPbn9j9tztfeu3sJ9+27g8eP/7Htx65+2n8RNobxo+d81DaOGnTluZ6k5f9Ls3M8MQm8myhi23Pg7FkxXgHy3Oet7jny+s6ISh2UcEgJomcmDzTKO9FJOd6rb4qAWJwRA4opYSORSKSEUGMNYJlmxwRpZTOSPdlFIGFahnpN4rUJfbksOTQLlsAOhgMMrZirNWuBsMQQlIbVM0oogC0Hg6Qgtrqt1BjIJHESIkMcXTmA6Ocr25AjrmfKgIqhYMrakmGZkmESVUpX09EJmoGwOB5RKRPKTGamNAIWmd5HkM00lkjoqpEwxyvNNJCZlwkgDIQYgOSQNrOOQ4xl1E1511G2mdsCxDmXAcky+lpCQ0BxVAFmlQbYWbhZWgJAIAJExCSgDEViDZiXoLVSTxCFGFAEHWhAAMilyxWsfGhjHVThGCmbIDo9AxaTnOSiObZVBQLzMCQ7y/PLAASU07UzhTfLEbJvwunThar3mzLpQ6u9K94+Osbdl5UbT93ccul668/b+VP3ysf+5uNbdedXHPrZa/YdfWbX/bJdxQLT719Yv37lhY09c++4MJOe/z+B+/54Ldued2znlm6Vh0xtmEN+H6r1Ni01qzt2emFhcVDTz6p7hGOOnjWOy1VZORLL64zPPTExbLr1Hwa33DsoaZ+zP6h/fo1/SPNdceXzm3KA07uuuuua6+56m3veNMv/e5v7/rofxzn6TS7rjOIfS6dI7MEoiISvM9ybjETU2/YDKui8AiIhN65siyXe11YlfjkG98h4f959uGLsTvrJ77Vfsfft/7sufVNV8m9T/zETz566vdPb7ksHeoAQEdDsTy/rjpx7eWb23PHer//HGqaGy/6SbnsJUuukVpLOB1mrpgbjrWam9bguiHWE5Nrpi6c6R2+84Dp/GU/5mZD0MpXvc1777zitg9D6lbOij6wptScYLJBKxWoBy5+2bXf/BAYJbHO8QXqr6w995w60Lpq/a/d/Kl/evE7/+lVv/yWb/zJVcdf5kjBoofWxJqO+fqcC58NvcHKyh4X2hXQ2Jr2htl1DoolS+rgR178k5dedh1Mtk/de+KcnRtf/cyZR+/97lfu+MEFz3vR6epYU2u3VqcJUl2BQa2kHhP5JEzmQ2EwCg7SFI3JABUhSkoAaiaiwXuHzpKAJxoxH1fjjxgAMpRlFB04UiSDIIIgGKESeiIBc9nKzMCIoJiUGMzByGZjCq4IZGAmKWkWWDGBI0BzGhOWXiQyu5Cjv1WzC0NEVEfpvLnz1NWbf7UjzGZhCy6EoiD2RtyIOucCeSJiwqb0noAiEBbNRFpO+tx03msXrvxM+64vzT7y1/a6FVmcLLTftMCiYWTmBGKElsw5Z4QKmiNccj5jrp1ogAZ1zHw+a5oql1QcRVbkigtnCnB+WiWQLH2PMWbha37epZSSiukIQ8irMY5Z6AQAuVHOnwYACcgRMiATBufZO+c9eBeYveccc+lccD744JjRiAxRVlnRkM1OYAogBhwxQSWEReKl4eJ1xcVrB2seXbt/16lD22lLV6sAMNAU0I2aegBbpaFZMtFkwBQMBuvPO3/D2PqwctNDvd/4pU2zsPDn9w/2P6Br1kyGKamW7cipgbSmzrkkzm6YPuc5Rzffd6YANzd+o7Vhy2M337b82uvi+HopJ0ETDhZxbFpgElYWqlu2nf/vg/NvffTYTlx6xs51H//NRT6udx+o9hx66jtP2r3H6MHQ2nrl5IZr3fRZ5MYQiKDYZGlRrZakLR6fPW+Hf8nT+77linUeAMBS0oolOAJEFmAkWZ1DOCQjlJQsAQA0JUpMZcJSRgiSShP5QGb0v5xIP/wnk6gpYJNiuywkNibGBElqUNdA1kWydy6lpASh6FSxUTJTbbfHhv2uz8GUzCbiXM7hMUPIWmhYxSSNbkoiJFKzJkZybGbkWEQNoW6afAFlILtb3XRkFRU551cBF4iYzVdN0xABAJlZzHajVU+gmeiINQsEI5YMACTVSIaITiEheSIvGiFRVFd4IJKRQrNBT4JQFBSjILL3gVQbSwCJWJMBGrCAqgkYMgFSgaRiyIhs7MRyuTAEdWYpqSopADGypMwOEA+5nQB22KTaOTeURARIjmTEmVrlzYEDHOGDbGQrGNmc1NhxPeibGcAPYXyIqE3TzE5sOX5i+113TO979AI7Pfzyf37/hne1n/38Ez/y4sn7vj89tbam6QNjUzf96PsvuPcLV3//c0vFxEta7f9pwcOpfejJQ6//yZ88fvrEsSNP/8/3H3rFRZcUbZi2chn7oUSyYvnIiWEzJMCZqelBb2j33RLuvj1cer2ee0k54VxDy8dP7G27eunk0Redmqx+/dC13/Lt6qGd+r39+2f/7+RTT1i5dla09Zl/+fwddz784V/+zd6e/ac8dscntB4kakNKOeo0zzMAcygnerZkSUWJXCsUZhqbxiE1krKhNMZaRNx4qLdgmnG22138950/Q5M7i1feZa/YLAc26K4dX/vjrTe8agnCOfz4gd7WtevLzTx1eqIl7cn19cJVe7/wyLqw+dLX28IRdqZ1dXrdudMHz7XFB9VtGeqpcR7y+qnzcXd57weentl69uLC9qceL0/s75K0JifTSrc20pIJGj12aMZN7Nv5wqacuHTXNxwIadEy9GCxPd6GzmLq8cC9/ca/+tKL/vqzr3xvfWfveXvf6Ah8JWHCnzx6tChbV137qscfLJ868nBncgpqfeiJ3cYOBgsveOELw+aX/PmnH5mcrl74jLNt4dFPf/5Y5M4b3/SWfYf31L3TSXRuBTbOTshgWKCr66GBU9KUmpnxsYKdDiMDCdQKgDE5g5QxjZLAjMk5QjYkzHD6vIYcPYDQkAmSGJgSEqIyoHeUUxUE1RHlGHMycs6DatIU0I0aBzUVA0VGBgRNElW9Z02iRgbKxIzoiPMrYgQaIQjyLm7UqBHQGU4WESPkDebqdQNoZrnt0yRMRoQTrY73IdP+auTAKTSc2gZNKpui5HSq3X9HeuldKwcen9nzzZX735iuOdKcDEEXlVqKCSQnNXliAgTL062R2ntk+ReJdUOAAoAEWc6NpmaYQ75oFJ0wsm+emdkOqgEiFj6oqni/ugZOVdVkP1UjSVWDY8Y8nRZmBsXcXYlITBEAEhOi8+w9c1EURavE4JCoQA4hhODIeSbnfWY9Gdlq+liOpQMQ1JSigaW6UW4qXwcr+klVhmtl8nl66Zf4/n8PD/1xf1LVKdZofgmbcvUkpiODCGYkGRetvQ/fff7ml42fJftvfqj82AfXTy72DleNzPn154REQbpoiO3Nk9e9otl0bnPs+N5nPxuLF5wpwAvf+e7izuu+efVblzZfAuzAFJBschNZArXO2HSprRc+/4ZO2b34SZy/e+2Tn7nGn7+jPsvjBb2tL3+kaT9cHdwZDj0fh1PQtEAJDACo25VEnqo+d8Z8I5df+sxTi/sH3cPMCJlLgYxMmVjhXCgKl7fvZ6YFisSAKsDoklggGuGlyDGzpZFcbvTJq+y2JkVR8N674AeDQUEUgk+i3lEI3jkHiqqqSUDNTJOYiMnqI57JI7KYFAQxiQKBKHOeMFmjmvXwOdvWVseJgNCYBmUArFImS2COPc5qSh4xKEZGxJxGmC/REEJKyRHVdc3AGWZjiLD6N8rlJ++8R8dKxMCUTVi5HhKB5oDt7NlXdZ5y2iMTOeaUEgJk9T4AIDLYqssfTTQ5F2KdQLMLFNWM8odMwAyN02jbbmoJQInQogKRKrgQqrpOOTCbgJhUkiNOamiQsa8je1iePRGoqQHw6g8kH7IBIfs4ACiqOOeAWFOOmaIqNtrYmvUz/u4fnDxw8CjAiU7x9Cl+yeyOn//el47e/PGTvWZ8bN1CgsJ3b/6JfysGyzd88V1Dr6aDucHgF8rWr4RUx8WpqfD21779rz/6NwvLSzc9/tA1O87hgGOEWFuI9TJEZHJM23acnZZ6ZTQA8HSgOX5UHzs1/cbfvq9fT3em7/+125t1T+K33+3iZUvjN7XW0kGs9APefjz5OKFV7SY3H9v9xC/98/v+8f0feujz37jyhTc8fXxpJnGfRroaW2W05aELOlJRIvKe67pmZoWsA2VVHbFKEN1YEEiwptVskO/8yvK7+37dcwZf2yFP1GH25Anc9c3HVmbx/N/5E3hqBma140J7ek1nvc6PT9ni8asbdHd+5gfUOu+Zry1I6zryGK855517v/2R/u473OT0oNECh2losmmNHNl72d5+5GolSBHNutZGl6RyiYcqNO6h7u++7CWTi0enTzyoncInwGgd6Gw754p6obe01Fsz027jxNu/89dfqia++Ly/WA7zL3/o5930xJGTh9sxlO3wyL79G866KnT8vu/eMrbjAjc2PbFuA0g6eqp/fPjQmrNnrBp847Y9m9aXV132DGP3+IE9J47Y5GVrBoB79q1cNLVJUxJAknwoBTR2zhFSjsJARE9IgCAZZ2dmIqaezTQlTSGETLNFPLO7zbcEFeQxqSc0M0YlQANVoCITVZghH6EB1cy7oD88LxuqZbMvIjpiYBwfH+/3hgqmWcFESKZs5JCYAG20RkMCFUBEtWzNyXcNII2ww6tz29VLBzh/oCgKYBeKApHYOVVtgYskhs5QGUwVvOMV7m/Hbb+wcN17J/77MzN3XXf8vDGYGNLytFKDyIaGKCKMqCIAhkzeMwHmMVQSaZqmqRozEwWRyJTPAYTIuc7lMCIYpYWnlLLOR4HQzMSnrDgzEyBU1dg0ZohMYpBSAlHvWFW9y2mMCmZqlNKIxOQQvWPvXfBFKIsQAntCRO9K55nyiQQhqqQkAAoC2eCHuopIAq2q2kTrQbXCXWnUJDWgCZVl8RXpgq9MPfJdt+vhdNb63lkJu1pMDNMgo9oxzx0yd5FsfHz8ie/eu3Kk2vCGybn7npr/0ld3/vQvH//P1pqVm6b85mLtcGzDKTJItGN+/Jq63DS/fkf94tc/4aeO1KOH7/6eO/KXB4T9zOmnQ/cUmdXtyTL1nec+jxv5prUBtF5eeyn3Hx7MzDxx8RtqPxuV3YKz5fX0+Dnbw+vmKBrgMDpbnVyCWY8LTk17+bh0tpyztRz0lq++4qUP3vrluphDREeOAVkBENQwiVHA7IIDQzEFZAQgdJgaYo6gdY7wEGRAJ9bkyM5Vdi9kRRJgy7sqmaqCYrssTJJzDj3lJEMzdMQjzbxJ0zTEjCpqQkj1oFbVqlZXuKoa5L8NMqlqjMlw5JMZ2Y4FDFRWI0+YOcWoqpoD1piZsR9rBjYzNQEAZgQjI2Ty3o8myWeEjWbmvR82CUbvpDMnXUTOEIzR/Yi4OhBScMSVKLEFcLUZgjIGQHYsCIYK5BGxcF7R1DBFAEVCM0gAyoxADiIQIKIJwqi9BzDVRkf8YyI2dQDGpARKBHVMOYxETGOT7zpFRs2PC2Ay8N6pqndeVWtRI4Jcz8VM8oROzQwBGQkYgDCp5nMrquUwDNVGcTQB8IXv7dl/+uZvTp21c3B07/29uacgfefEwie8/4fNW3c2bve+x1ybbnvhe46c9cw3feB6R63leFIwHZqduW4Ar1b+eoKHf/DQjguufutP/OS9j9677+EnvvrEE88YLj1r2/kToW3QG0+um2oMvhcH5URrWMcEpi2oW3zRAw86ixu2XH5oy5P9sbP84g7xKzx/UTr7P3sblMDGXc2vxeV/68bCWpV2pjccfuToH7/3T5pB99TK6de/7h379j0JRSsLApIkZmZDIpKUuhJd8GIQYwbymahhcCSqCtJEZkYGR6YEwaEpcAf625bvuIQfRIsRN+i4Y4axx+4Pp6GanN26Zfqphx/c/6G/Tfffsu3QXLtcF6H3zFi2b/3MD7C38/p3jvfnyXs/u+HHfvbv7/vK3849dNOayalhC1vUWtPy2+97ypZq8rGTTD07XeoTEAUzXwJjd0VcOHjJa3Y8eUuVZNo59ckMmq07jq5fVxRw9tlnrawsFYVfWl75se//ytRw3def9Q/D8fk33PpeDqZtODq/NOFtXgebt11+sLhv+XMfXhvWzRXj0+uLxRtO2w3/XY13edDZuufS2RvP+d6dh5uVfpp0a6ZxeIplB5443B1eIJ5xGFPBDtQsxTbxoN8tyjYVWJOUxqlJLvgIygIxRc9UlAxqAErOGWJWGCGO9ChomW5FiOBGkBBhBGYSADYyTY653R7rDwZsmLEbAKBAQESOUSBjIkyJ2GJTu6zOEEkqRIQOARCBDYTJ5YmfCz7GRlUdlYiGqGcm4oCZOLPKyM00H8QmimoOL4FGmrFWiWhFqwBDDj6mqqihNqwbA0KDGpknsFyR0y8ur3ru0Ue/c86+j/Zu/79zr4wVNRwlqpIZmDTRcUCDHGpUhEJEYowpaZNiVVV11YCZGsYYCc1MmVFVDYmZKR9hVlPHc+KyiI5NjGsSTcqekqTV4Bd1zsUoAOBcHiFYbpSRhJnMcNWu7Nm7oijQNITgi9K74EKGIKhHRqKRWURgpNPJjNqoCGS5lc9rL7KmqU21qquBWyIpKqrLJAOlWA63DqYvWVr7yOYT35vf/4b+WYdb/YlFNBr2ISu9KeviYmoQsfTh1GLzvLe+dLgCT/3Bn2/eeb4/9/If1IPnQ/+8F9euPUQmaI8DL03AbXfsuOGuzS9/5KSdjD80IXWa7rP86cvf97bx+X2f/rkvVp3pVHSiH2uIwbRoVlhrALxj2xvJXhdin5WVnTmOo4MiPi3qxTeAZ6RsuQInv7Ky/f1LO5a2L521ee3PL57obx4f33r5VfNP34yRgvMuGaJy8IKggHU95FVZiollGZaBAbJm07YoIgGamIGIAhI5yxN9gFzGVJUNAnIURIckQt4758wAkXNhyyENquaCyxwVNGsVoWkSojH7RgUMOt6L6bCpAnvNiGJTM2OgHE6vI7P+KjI9pgTmCCaK9kq/lwoEogIZ2KmOTm+jdQgCM0cRZg7e5zY3r58lpQzLY/5hoFmu97XUjgOvvjlHAJk9gZUTB+DNVV4ckkcwj3lzQ47RUGMKoYimjAgQxGoDJbYUUxIRJVVKVT8BgiNC55A8sfBIwKimiKpYMwISgxKYc2StoqySSJN6/Z4LPop45wpypGcW2SamMTVi6oWASBg1GZk4MERQQgDw+cZVXUUVYUrC7KM0koQcM7ms+ZiYmNj7vTvK2Wnon3wiLh/opJlqgltxheUt+5/65LrZ87Zsvn3q/Nte/u7n3fSXW/bctoS6fMVLirf85I7r3/CNt73k5/cduKUVvvPQPY8+vuvnf+4XXnrlyy8867I777vjgSePLpwcXnb25i0bZ6msxXs2qua7WiiWYanX8NqLptpnPfnyly+0rptfs76hF8ze+4vK/eHE3qPX/IGvyQy6a2BqUcdfwMNPu3Yi1wEqsWz8Qw8+Ggp+cM9TG2a3XHb1844cP5YnLSqSCb4+J/aQbxKUjgEZUOvYGJOqoWLpg5CklFI0VyspWD/ylJdlmtki9xM2DbXB9FR5rpcH4kK3PVGdeGLXnk9+Sv7ry+uHS210jn3SfgmFI9zpcfqe/3rAe3nh29eBdYZVdyxd8dr33H/la4984z/Om39yw/yhHUPsLvWaonJ1KYUPKUIoWhr7UdsuKWjVGltYf97i2rNe+pVb2jMz873ejFHA+MCBxzf80VtnL31muvK1577qlQNoUdn0ZfjCXb8wWU1/7rl/vuwW3n7bn1ZLAGPQp7HlU83YlPD0psWHfnDR2ZctXrFl9zu+reeEhgthhbLb3Xnn3tkHZ5ZefqGdv3vf4tSYP2GnLemY7xqCIbh8RGU1wcTBQzIzRnbEoOaQMZN7DLz3hgBiJTqmVTElGgHm+CFkYqa8k2fiYDnN1BlCDlggp43mVJw6FKxJaTWtiFTRjNEhKhIAmYE1SRKSAB2bO8VIgIpEsRJl5KJwLlRJgtOSCxwpjxxaUoM8oGMiZDWjLBMb+WiZIImaOUAl8MSBnS88kPnARDTCRYCrOdbWgIoYOiSrrW6aSCk28FNw3fe7x2+dffRFKzuv7O88RU8VbhxTDdF5dVgOArSYyoDDYYoOKRAKJLUmC7VSFaOCjQQtQORUAVlTEk+MiKrGzCHTFbxD1qoZEFHhA6CWjk2TAyJyDSihiZilpiBywefTP5FTFWam0fOdmFkNkX27PSYSHZlJQnaGvskr2UqiGhBmZSOqsWEF4hSQaagpEFuTyPGw11fVbtVvpYqowaQVEXhemh8iTz7v+I4Ht3W/se7gNU/tnxj6bliAirFESrFGVzgMyS/pysb2tKyEdefu3LR9w6GPfq63/0F9128/eceX3AP3bb2h7yfVOaQy7R6/4Lbwo3e0X/s0nMdHpdObv7izMnn0qVwnvTbjF1y69IxLZ2/atfOef33khb86Pn+oak9aZ4wklrHLGK989COO3Z7z37R/+pkV+f+dy1YDAHAN+aCGASIrdsuVla03Tx14w4kLbm5Vh/am6o823/yW4Xsm+1dtXrdj76kNVGGrjaU4IyOCpOiDSmJYVcAX7FJKZkkAqGA0KHOIL7MYpCaamWFCcpaMiPORxzFbkpocASCNqikzIzs2IxAkNFVRASBRHPYbVUpJHXI1GBCREcVYMRLX3HiGpJ3QGlS1ApEjNPJJGp8IFJREDcCFvFdgQOe5agoKiZlbrQBkIkLo0RQIfWkAYpSVZSISzAhpRODKdnNFA2M0ZG6aKhNmRCzPqAONAWgOnURESaYC5Fy0hjKenMwHAxAwAjEuvYmamJi5IvQlAgApc2qSJQPAqKTEampKjr3rNE2TNOddYlQjdGTGaOCSoqgZYFBjQxgf70x02kcPHQVwqkJtLyAoQILJmvUbNp08NQdGBIxmUlXsTIlTrLKYI6kmNTAgBTRoRJMSOUYQFVFVRC8i7IKZWWyS9Mi7wI4FewcPrltZOUXyQMCxOFPzQqWxrFrOwU8cOvzpC555y9s+tuHwQy+98xNPP/c5+mM/e8k1rzxxZGVsvgev+cn0t3/2pnL801W/16++duuNP/rqHz9y7PBzrrq6e0Hv9ttuH0rct3j84s3nlGvP749t12dceHxsc2/ynKazHgBQ0vTJPWOLe7fsvvnYM+4+cu3DC7PD87/6+JZHX3L8otuE1CEAWavQXkSesKqSVHfNUMsWhKKD8dOf+qff2rimM7ttsLDcNMk550wTSL9ufBFakZx3qW4sSO7AWCFGRaJqOHTOkXcxqVusnRmeGISZ1mCZZlqcauE6zALQQbtmhr7kek/tefuL/e6D26w3gdgNbRRFpmQKAVOdMKULNm9dc/d/73vkrqOXXDe35pzeRDM8dbw5ePKKAw/uXD4+E9rDalgEW+G167ACqY3KGEVLGjONsYa2tiU8fOlrXTPY/vBtCn3vPVZL9at/b0uvV9zyj3bvzYv33fitr543c/mLZ8+/cvLc83Fqw/OO/nTrvu3/evU7PzHxnnd+5yM4dIXFYVE9/v2vH/nnv79KJu86Mf/ULy/o2ZDG+jqznNtQ329xx+TtD+3/q8me+N7e5WKmGm+HX3jbq5vlbrcRbhcWxTMKqFFdlh2zMzkt4L2vYsPMwsBmrKCqyYERoUEAFFXLB3uzDAZCRIdMSMaIiMwspgAjKJWpAJEm0SxdzrL+PBwWTWqgFtglFMeOi6I/jA7JTAFVzZIKEI+Qe2YAIy8jjMjP6JjyfDnGNBLumpoiOa//i3pvlusymigAenKOPKHDvJxUIzXO8XBqKlKbIRAwMUK3dXrHysSrj1x44zkPfWL2nv+7PDU9XNv4rhpBSUUIIp4Ni4Ia9C0sTJNE8+bBUfDmua6RUYUM8gxZk4TAZpZxPzQKGURVLYJDRBUa2VoAsiKUmAFRsx0agDm3UD/ct6GKGROSjIDb2XOZjHhlZWms00ki3nsgbGJNiRMI5pk9QhRVE4bR3H4ZEtXGUfsOY0oBqK4qUamqWjtGAN1+j4gEzIdwujd/bmqtnfen18YfTB97xrH1i34wEbnpIwDFDhRNW1MCtNmztk6s2b5eZDAHh278irN45AO/m+694+rzys5UMgeLE7Ov37i3pra3ep0cuXz4HUoynLq86Rew49r8SxcwXTcxd9Hr+vMlEq/Z8535C1/iJGozAIIg1dknbyf0Kkth6eB4ub1XrE3kYHVECaMhSTYlmwMOGHc/+90xnFrz1E8Uva29DffJwBGd+OR5f/Tbj3x0HZ+/aeM2WwBENzG9ZjjsKqA3BEgK5rwHUSJSEUIkQO89OMSMXwYywhH6Xy06ZyO1riIy5faXGUAjGRsWgODZERfOR4cQoyRNllRBQVSyFlU0phqkDEUdmyiSUpqenKwGddUbeGLPARHBIKXESMzARgYwmp2qKVrugAmYQ1lb0mo41iqDYdOoMaEg0Wg2nz18o74WDEw1aca5wUjmYFFFmiaE0Gq1EHEwGACwjsJj8g5IzNCHQOTzXY/AWSxm2bme58tJGCmJsHNN02RfOyLKqu8RYXWaDWgAkgyBAyOscvrEakSM0ZiRRg+kDBtJw15/0F0BADMhorqpAKBVlAysTPOnTntDyUoMAg9MIlXdeEMsvDliEFAyREFAEwQwFBUjAyRz5IjYQDXGpKYcQGm2M3ni1FxrSwd6S1XRvl1PlX2FgEMVHqQI1cYZPues2fdd+wsTrck//Ohr903i+f92Y3ffSjUv3ZN7ynjeWc9+5X2tP/3F1L4bF/aZe2rX43/x8Huuf/nrJ2Z2PtI7ufU1f+A3XhS2XrJ/5hxgDwCuNzc1PLJl7h47ufv799z463N7t5xeOrLz/OKl1923547DL16YOvR2w9hbf397EXrTkEo4vUHPuq08PeadqGOqhsOibA3rWsxIjcz+8aMfec/v/XlyrkikSStKgWHT2vUnTs5LqWap4KAxEbMR9qshuWBNA2aqSswG5hpx/75vyx+ee4RRl3HmaL8odHy25R5a8zPd/sYppVAN2k/tbnVa0SYW6wFHQWZBZHJNjEVwky4sPrWnKCauag5d8o1/GJQzg3LNTG9p7VTBY1PLTXFIU2vMQg1j0psvkm8UWAownpoZHl8sxze4tvSX+3t3vnD7k7cW29ev9NK6IwdPXHjl/Asv3qale8Yrjn71L6on71x74ige+fTTN31e2q0ocXxqZqycuv6Ktd/857v/7wXPfuVbNroTMKz7oX9qHaw5WuA9frF7TeWdT2ujqbplhAlft4e4HAY7j8E4XDK95ZVXvZhmj31y4Xu7Dv7g/OlzJ6Aj4lyH6xTbhYuxLyJEGZusnbFOPRgWzkcVQuDs2ee8Y8l+AzTEjHvGVaw8Z1jxqvnPMOfOIjkg54KAmCKREclIN4higqbM7CBFUEYIjiVJTFL6ggDJaX7EG+YCw2UovHdEuipWytoljBqR8yl7VJWZCQgh39YIAGAjSVQGaSMjEboRkRLyMH0ETGeFFCXGqCNxBzkkr7AY+28cXHlv/8DxyZVvTj7+o/UVNWrb+0nkbuBWDIwoLMgB1bIH2jIG20kIgXM4XEoSE5kXjYFdSqkIXjQSGpNLKSFYK3jVUaRrLsw8ikZ2BoLIoEbMYKvBwExIRjQKfwQAJg+Q8+oM0ciUfEgZ3IQsVplZSkNFgJGzYrQCABU0EFNFIOZALI0MYzMcLaGhrqsBDgBATb2hmg76fUFck6YuOzp5x8yJezcfO+fwjK/TctEAuraGNBgES12y9skjYd1F1ZiOr6OTX7gp7dk73Qybh+6eXbN57eZ5IvRFs4ZO72weqFJo+zqh7/F0LMZ6OKHj0yfiiCiejOLegW56ob7tFfD/e+uPbTkxc8n///0wggPjqiCe8gN9ANhzce2uXzEaKA2LxSu62768UiTBE2uQv7fxKz964leKMMHs261xIkJkGomNuCSUqgEA5zCqtjpt730UcQRoufaCqAKh98zMmio1ysG6MvKdKQLW2nhDZZMQWoCIkBw4M+dDtCQiuXbKqk2cGCbHp1dWVhBRRYqiWFpa8hyMLCXtDfre+xA8IqaUkigYKoIiOTNBNIKE5pQqb8GgNB81gkBiA89sgug8koApWLbYImQ3rjPEnI2Zj3jEYEqMHEIws+FwmI03eXiWL0EAzR9NqpAF1ZiNUM4MyFBREQ2YGAARg3OqidGBKBloTNnsi/9L9UkAKqqYYfJGJgCaBRAKwMAiMjIzGznvCucRNOUtdTKNEQ3a7XZKqiDsfJTUDp5UdXW3DQDeF4mAwShppUkkoZmqCURmIEMABcXMm8lZC2LGLkgSi9Bd7oXCLa/Me9C7uT49tJJUquWWLy47S3/pkpVz18g90y//5+1vfc69b1/THm56YuHA7//m2b/+4ZPHn9b12x54avcrX/mqx17yqmN33f3T217/ocmzx7ddXK698MSmC0+V4zPPARkuV8d22dFH4q7/6izudif37nl8VxdqK7laSbNs54/tWC5WWocOdHZvunY48703HW4feslw5q7B2CIAtLrgK1har+76Kn5Kx/Z1ujIIRRjWQ2NOGhlpYnpSAv/HZz/5U7/wawcPzqkjMkyajg2WU+GZrCi9NZLVpMAI5BQMaNWkqkoZzv31Q+t1eeJ/rr97hdb0UvHd4+MTZ//e8sbny5G7BRyLtamsajKIgQzAcREASJrIjmsTGDTrxiaWUjMvMDa1dQ22N8CyrJ9Z7C3Glf3k4nRYMyjbVcfRqWXRRDsuilr7pw9WJ08X3nVXDo6thP5Z24+c+5yrP/+urX//Lw/99y3Ln/jd/o/cMBdTssfXbrzs7J/5yOnDt8zf/uW4+/vjqSm7BID18MQAD194oFMeGLvxq92vfe3YK181PfVE3QmzVVzYPb3j1X/0G3/nf60paiODFsAchMrJxsTjqbDW81/efsaheOzkLQePHcBtun7dpEVA1woKFmusxcrgyhKThbJIKXlHVdWkHKhAyEmVQPN0NAsN0MQDaK4No943Hyoxp5spKhgkxRzgY6CqhqCryUuimv2mZiZIhilKUlXErAUzD5AACZEhB+OONMwOAVf9qbjqMBu9AIPT6UQjUUclOVdccORg9T2jHCFEYiLgsikLbDsJ7IJzDghNLcWYUqqbuqljSnHUbTsmEN8r+qFeu9C+tpn+wo6Hbhob7FiEaZ3pS03ex2XwHoEwDdQFAOTVp6sBgIJGjMmENDYpNiLJRNDISCiROZZEuppeDECEKS+I0cgIDBx6AyFgXQ1YAABVs1XtCSqiGRJlEh6SU9UkSUzMjIG1VnLehzL2ExGBKjMlNRUVlQxAABglKHFZUJUaSRqY1VDMGBfSyUbr03FO1BDBOU+GnrlKFRD2sbX1qNm6+adD/7GW37oYBqASsN21Zswf1b7T4Pbd+/T5lzIC7x48+uW/A314fNtOG/ByWk5l6rNOeuhCZ9PSF1938kN+ErH0PbcpTZy9Z/Of9P7r30/f+G9nSumEDgqYgK2bmmNLu7k/6cYTQjWzFp59FfaglsZNdCK5XmvjgY3PTxiib4MBENtIvoA/HEqDVe19EQ+jFicuff9w5juz99v8Zuh1ljtx+uF4+zP7LztdHxVIxwZPD6s+AiooJp5tb40UNc8MAAO76Ykp59zi4mIi0Jy77fKaxdRMFIiocIzIMUZLKSuh0Kwknyw5oICMnhHRG2p+vGsGtmhaNapledNKb1nMiqLQqiKiTnu8qWsEdsFjdqCe4ZchgowS24kIFIQNABiQoyhCCg7MqQgKksNI7BRzfg4aICEhAiqxy2nYaqY54310BB7502OMjij39FVVeV+EokjSJB0Z3EWk8D7Poc6YGJ1zRNm2kxRIVZkIAJgxJwwKrF7nWd0PgJn8jyBggmoiWeWHRMAEoIZgoxATAgDR6IhH0SwSkSBn24BojDGEkKpUtosGUhGYmlSwj8x1jA0YiSUAJGMFh2wAnPf6AAaZWAKqiKiAWtBYpNpMAxCURdX0fclaDXc3/UOu5QZaY10YXLm+ft9zV5i0X2793NaPPnf5c2/x/+6f7XeubDjyn5888OJXVltetXDy1AMrxw88VJ142UfvekUJANtS3T+xpznx+PKur9bHHxvOPSmnTyJAINh61o5mtnxo9yMKUCSPDQ/Lzo7xJFIN6v448Mq3vm5Er/vD8rY3vaje8Fcb91Mi8xUC2Ms/3br1DTXcMajfxfJ5UzT2IUpCBCQ4OXf8x9764/uGi3ffddulVz/v9MnllvkasVhOvlWWDj27ngyccykKqkWJCuZo1LihGjp2AABoh7sBAJZo5lfufiYtbfrdF54/I67SNpeT3veaZlhgMLQKWp5i0zREziOBIpYeEHtVLBy0RK2eX8QusufFo+04NDcuYbI7qMZ8ZxCAaWpC55tTc62mf8IATNbE/uy7fvvAnY+evuZ1hnz1z/7s0dTx5GH8rKWzzuFTzRit7eLTcaracv2PXfLatx98/L6n7/yfpQfv7u7bTyhBG4DhzCPw5ue2v/yN4f/cNvea61uTT9KuDRs2P/91l2x4tgNMmCAAVAhVwNmhA2lrZTHe/+3PPfJAc82LX/esa16wZ+UhMiGi0A6pGSDEji/qQVU6VOLcxYpYLbUnSim5IiCSqUbI4UjoiYmRjDJHQgHdakUctRfAYhkCi47QwCRBkobRkXN1bEDBe4eIsa7NxJCjJAXwRUBgqZuMO0fPOXwUR4GFaKAZs6eK7JjImB2uKoeXdf7Dc38LAAgj9gcCwuozFuEMxylT+Eb3KiHlir56hjCDEbzxTNkefZ1M8AEEA0ZqHZo/7fX9zbc2pvERgxNX73jLM7szP5XRkX11PpZZFpZTV898Sn5Jo89cdd/mBF/8X+DAM3+71RJsuOrGzt9ytbcbfcIqRMBU1Hu/2hDT6sfzOeaH33H0/yJSD/MPYSSwM0SABpoFnbtx8FkH/swxaDTMNTVE7mH4Tm+50K9Ut0/WQRukvgkidBHBSMFv7rbmD8s3B9rrxqtX4BIg3meqgBS8tiYSOzhO44V99qa1BmCgUfVkPDXff/wlFBr80R9mzFnwpgNIexhxgKDa90AAc43f6ze3TRXACMEQe93PCHlDMszV10byY01GLv97auZSseB7W9PxOQ1LczWlXWqc5uzIgp74m+EvJa1PNUf+a/4TnkKexwLAO/i9M25NUiACH3woi6VhX0w5cEAYplRHZfyhQymKeEZyZCKeHTMrQPayDwYDSWai0oziTJBBEZJotjmJjZzi2TQgYIzsPTZNE0Jo6mSknjiShhAARitby6iQfPbM+g3LunYERGBwYoQkKZnnSCRETqGjrsEMW/zhcTb/ql3mcwHQ6r0/UmiZZc9JFm15789Q27KDWUSIgci32+2maQZVlbfXLsd/kYmoAIACEYkqex9jBIKsZQMAJECkzJxDACKHaKqRGZHYZHQ0MQVAHuUBGxBzphKQYxPNqrFaaiJyLlRVQ44VhDmYWWpi4djM0HMgVzVNC9lAFUQNMEfsCIojJGea8XoIiGpAhOhwmBIzsppQqlQa0Lqfpjudo8zNUtcTcWVhavw9zzrJqJvG4d2bPz1hC28f/O3eda9/Ei8+8nNXHHYXz9vZcITAthSbythbuWrrzMrH3/WMh2+/TO23lo48hFVJbdOI2jShJEHiNN9dPLbnaMu3Y2jqgBO+A4PqBZGLtOLDuEiaDEUFrnz6WtLxs3d/6+AYJQdbd9EzP5uuvdtf89HJd7/v5OBfu3Sdt99kqs0TkQIZkPGtN99y9hUXPbZ2obf7nktnz0OhernSmbEpManjUm9IoUhgKbtDDQK7JDJyqSJ6QacqAXBdJwHAMs0Q0cLC0hO7n3zp2WdLGoikYFonahwiQadpJS+IqDH5okxig34VQjCCCKENQ0xIuDwYWCdw5dcW0ZtPk62xxe6yFmPLvJzG22PVQOPKxX/8kd71r3r4N375ede8tnXujsePXLy1NH9w39YXvmbxbx5YfOFz64amknanLaivTz+9Z+7Y5s1XbLzguZsufzHq8NSJp+ulw+nI/iOHD08e3rvc67/tzYuf++RjX/7O8Mf//Zcv6F4/jt0D4fEwcGlTggSgJmcNa0JK5HskS7xpYdvvvf+9c0hPHL0HERos2+1xaJCQa0FBaHXGtOlTsZqXacqEoomYmhH9H0FRBSKZoBbGQS2X3ZwXvzqFhoyLEYMElnlzgAhgSa3RiIiihjjCgyKiKaIjFDJLKaqCpSgCtpoSC24EgUoiwkT4v8ua5VnRaiPoDBF/bOots27d6vEcDMEhn6k2GZOZB9CuDN6HEIoMoCDnAFBFG0lNbGKMIsoAlrt2QkNmGyYMAH7a+9PFwp9vuKVbuHccef4VacvAEgSRYdL8ihMBZS0YY24PRg5KjcOhmjZ1qurKEETUewaAwMxEagZiMcZkCmYKJkirpDBCMB6t3U3MRNR0VGzNjD055ywvXcxMNakSuSipruvStweDQdkp8lMun9/z0kEBR7QsAEYCIkSUGM0xAQbmKGIAhDjfnPhK9zOvGvvxDWGzgBEhEaMZGlSspWmnGbt3+uBNFxydSPCa+89u9yZqHFARqF+5iTX26APnz9Ub3/HeR373jy/Z1LnvwMLk/d/SYrJsmggGLf/ynzhhxm/beONvLfzaM+V2aaCpSdAe/Xq/GXKl7RaEMwW4jk2kgblOi8fmTE9Xw0mmNqQ5SctXnzWzaSuvDKhoeWddnty17YaBmxQOVbnWiICcr5eLakVCa1hOO4m9zXcOZx+b3vUbe1/5chlbcsPSYOCxmLGzL5i/4g0nf3W+PvrxPb//2qm3rS83qNJcdfSrS5+hAsFziwtC1JhMkldwxKBAphxV1UTFDC3F7ODxZUmAycw5JoQYo0jUJORcW6BhUcagZEQJjcViSslUwQhAkWE1ui8T3EyN0KWozIwATGyrgY8joxG6FOsoKV8SuMriYMTs72awiGKEHRcsUykYB2Q+d5WqhoCqhARmYBZjzAoPIjLV7JQbXYHM2cuX8zSJaDgcBg6Ayt7n6M+YYr/fz8m7zjkgAlO1BjUTKwHJwGgUrjzyLJlm0YfRmQUwIKARqCIZ5SpNo91S1hKSga5GnDERucDeGYmpppSAMCVlZKIsyUAOhKCBOFbRmERVGwnk2XEMFIQlNTUp5ChuxOxfglHkuTtzTKGSCgBtoEuChfeCa6Ynv3/XnUuL3YlOqZrM83ljy9Oumij17ok3PhauZWt+ceP9ADART24ePHbpQ7elm+/b+vbXT0+OWaRBv7VtXfv7/nTrxO7FmXXvGRv79W7vZMAyOgqFi9F77EV5xllbCsPTJ+e1jpOdsaVmuIn0Cur0ZRmamkIRhzLu3bFLXlR259763sfBddCNUd2XtFJT3NQLE29rL91R6wdic424t5a2mxCxaZpWq9Xrdh+78XbP/LDoygtfecOb3lZ1/LDbWyp4XIiIQgiVRENLSVohpLpBHK17EFERXNkqEWBda1SAgw+d9lQCa5yj4aKH2DcgIhADrMyr1AkckXdVqhGxdJxSg+Rd7MbQwnXrl8/bufWaV5347AenDxxL1C16zRHE8TAJ/eWZF71q/b9++qG/+Dv56HvXaFm3tl3zgX/tA401rcNbd96woTr97j87+IFfbpeh+1t/XA8EAnk0F43bMxGauaV9eMqxX1Nge2xs0/SGiwc7eFMritjyYCDVwu/vXfjQzC9/5uf/fudDDww3nrQ2DFs1MMA8cOM1SGG+3fclY/h0sc2ta8Gm5eHhwnuqyIGPBuiMk29Dy9RHxDq4iRDKsuh2u2PtVqqGhJiTKaNpjuxNaJC1vIRA6HHUOCJiLoP5T1JNpglwtA4wNAI18M4lNQU1tXpYMWMZCkOAJoGaJ58omhgREVAjyZJkx8LIOAFZIkUgAmiskO31+VnADCJqZmto7Xq3eVVyBQo2OqcbJJUoYghoSAbelY5d4MDsmTyhByBwUEvdYKxZgCGDA9EUER0FcamD2IhLODy3uegFcXDL1ke/Fk689OBFa4tpqnvDNgNQgqpiHecAhIboiBwxGjQp1rEBauq6riw10JiZOckbL8hZcGYKGjVmMoOZAQVEdEgIypwncyammkTYFCDvwZnZATmkHKqskIwsaTLjJqU6RgbPqeUr5xhD6RGxCK38jIuQOZ7ARAwoYAriCo9qDZonZrGIltAwCoObdRu2trb3+310DtGcd2Rg7BJGj/7awfgDxic2L/SPF+c8ubbfUewP3fRGq+tzvn7/5u2Xhfb5U4NxN/OCTT+4aao/VkKhXcDtm7aMP3VZYQ8tX1j4iy+e726svUeUFPfclTYeXTPcuF4OPlXS1JkCvNTiyWYsWu3IxpOtSA8MJ1zYwmP33LovXlusX7e+XFA3xmvC8pqHv3iq3Hly5pKj5zwDkkoYp8I8D41bHaJOWm4df2Pdfdtg652waR6CpbopezAD61yreOX+t21qnePQBSxmw6Zz11zgXTvMe1gCApsoWylGTGZAqYkCiEhJFXuDBlSIqiaRGogyUkopQmLMJCkCGm0QySCYNZ5CBDKsGcgSR6pNgVFzBV6FtuQBSumDRmViQR2lehA1mjyyiLjgwUBVMx+N2YslRnRI5hFAeeTJxhqAAArjQrHWFMFcCJwEEQWSgmXcsaBlthajQ4bc4GqKRgZACkbONU2TyzMi9ldWcpIHASWDHL+NjERkIu2yZYbOswJYBjBniA4igwGaY26aJvMdgaiua+8cjBrf0RkRBBSA1AmYmBkgEBBzbtsZzTnKDTVmIk1EkUhGOZ0ppXoEvBHxzqWmJs+esUnJOZ/ENOlY0erqIBiBZ3KhU6ceMQCEBOKMCDk/TUABMjYuQZOAGZmcFdKoRyCt77rz1habc64WHaT+plYyhBbrK+JXHut9JCzvv8geuxwe6q/M92p44jub6MiR6vxy9pf+4sT9j89sHsOpYvaNr5//2ufK/srasv1bOP3uetG5NRaHzoXY6MzkxKlTpxaG3Yrl4suu3PvkrhjTy9tTHaSVGDuu7Jpxacl6xy562dYnbgtk4qhBIVLyJVEICuSc/zTKDwr51368a4C/XaZPRJ+dVKDtDWtx0CjZ7ffctv/pg29680+eu3373KlTEQouQj5pEoECeO9TSrGuDQAdO0JQJR/89PTaCeqJYQ8nHXMzSIIAwrq0YFGqokQyBDUoG3DBOUccU50sqSZGmOx0HCNNznb+42vTH/rYWb/+mydn1ndXBrVfHl628zS1dnzyq+EL9yxKf/L1r3/4i9/b/ob/Y1e8eu7bX5sJ1b2//7vTw9NHV5aaMLbmPTec1ZyYWFqpn/fawzQWcFHGgQeG7CQBo8Y0OH7w8TR/hJqFwdKx+ad3ydze3sFDC3v3NkeejCt9nYefufnDM/ObHr/qttOTJ4+NP2WFwQmgFkkZ4SjBAtsKbPt4a/nLMDh9uj5+fGOnFKmNgEk9NAwxat14HFAtWAdsmqbp9XqZBsXBj/oqRE3SaDO0VGkSERRBRGMCNVBb1SSPjqW5qVVABRMDSdZIEjExreuoqrGRmBR9IOejSQPmifNaC4xENMYcYeQYDQ2yAxURM0ERmDJVx+CHQ91VNI+emZKNNr4GKSW1ZJJyk3FmnGaGTVXHuk4pakoS62o4HPYHw/6w6Vdx2KQmZoSFmQEhOS48tNoFoqMCgDvLduwtS5eO9cNTnWNfH39qTeRF77xqiiIVsaa6rjMcZ+S2HPmOSAmNXfb7mlkZApqlplHV3Kbk8WPuAFJKI7qPqKS8BRQxjSpiFmOMURTIkJvV5AwCzns7RgS1VDfSRAbq9Wt2LqUEoMF5N7LHuIyLy3TBkbqHwHtPzORdixwzR4ekVgqqZwAA0H5vhdBgtLlHIgIzJ4X4Zm2cuOzEWKX6wLbugJpUOTVqtKV79m09emilPum6dHs7PP700WL//cogzkFspUHvkuuWj+wf/+97rwEAPHHq5ByfPLDusRvXHt09afWAnn6Kyfdh6cyftWNrdWKi1tZwvJwCKM59xjk/9/srZz9zf909O6ZDD+5ZWopubCzROMHkeqLZxQcnH/379Xu+FqrlMJw3s9p3DDE0C25svPBTLnaG536I+y0A3HhkbP1BCBquP/ZL58VLg5CKAmLwZUppOByyYyYsWwUROecAbWQ5T1r3Bqk/jKCDullYWZ6bPz3fXR40tRBEGM2TETHG2FS1rU6YFSEAAGqyBCmqagOKIt773G5mjmO2qyEiKRIiqjE65xw5FjAKLl85I/mB5tXsaEeSez2xpJDfBWbSjuQ5DEFO1/3MY/SiU87ZCN+t/+vqdUSu9AENUhMlJkQsnM/9bv5e3vtOp5PHzvkayxfziB4TY55L55tLkuXbGQAQ2RRVCNTQIDU1AYJaq9XyPNKKa5Iz2igzk9EDgBGZXcgGgTwbyl4DUDNRMgDVpmlSSkSOEL33ScUFj6tD8uGw70xFYkQjH0yAjb0rKk0tRGJwqiwipMaECBJy4wtGNnpZIAAKKC1rRXNDwYJKqnVqsvPAI/ecOrGnPcYrgy4nYs8nh0JmpUMEbZRfu/Sha9Mt03YqJhwk/UoVJmBaeqfG14/58896eteB3R/5a33/BzeDr8wd7A4vP//Cv5w4Nzan6iJQBLXGkV+zZfO5m7d40ZN7Dg9IL6D2j7qpk8vLlbkaa1/61sbty+2tp7defu7ubydtQ21+qXZDSENAaiORpURE/jEun9vBz7N9rKJ/S36SSuYxHwa9QZPEraTpcnxu8cQ/ffwDX/qvz8dAylw3KTYNm5Iao610u6LqiYkImYBQAKnfGw4G9cxYvRhLQ1paXCnXls8/7+I1k+Xscneae2GYJJlhq8SqTCDgI0Jwky1m9KE1rI8vnaqrJd2y0297xtyhXvehRybWMlx49aY///edX//u4Fc/WOy4qircybKlE+dv2LJ+WB298F8/dWjLdnr4O9N77zv+iufsunvX2NKxzfvvH2/MTYwfueDioq4dtEIP6mANqxRVNCtaJTg5tvjUvmMPDOMp8jwUrSn5SRhbf/Z4GCvJNWNHSXzotbpjpxtXOQ1umicHE2Nx2n2Pyj/oXP+PP3WZ/9XXvP6dV/VPlHE5hrFCQ/aJiniL4JS4SkENLRl6AEIgTdLv96uqEhABNVAGJiVK6pEQWJSSQoxJCQUhmtaZ05P9HCJISgqsBFFEaySNsXbgkIm9C50iQkoaY4yg6NHXmtRMAJMKgAEKWAoeCnKpbvpVv05S1zE1Yk3yKEoWITWxghQtCRAoqMWYUpOP6jFGRCZyKakmgAgj5gChiEaxRq2fmtqkFqmaWDVN1aQkUkvdHfYGcVDHodS11Q0m9ezKUJSFd0WJVjZlWUQXo3Td+Jpl9+YDzwf0n9vwyFN4dLqZ6DmsbFm9d+KRAlAAoKx5FomqKWoEZU1CYETgkJo6ISIQkuBIyIJQpbjcH4hxMt/IsNam1qZou6QNMxExqU8KaiEpDgZ1k5IooA+NYkqaxBq1WiwBJiVBjojBY4oREQE5zwx96dgZADtDUkFtUEDFMClLREhEioEIrVBzCCoRmgYN0qDRqElMk5EgJQ1ArVBQGLokyTdXHNlU9nX3ZP/w7Mnxfo+wbKTZ+NiTGhAPHi+jJt/uff79m5clchnne8L1+TuOlB15+OZWb3yLa4YP/0+6+8aZ++4OdbO2Ra0eEptHKEPROvMnze2WU0fH/uqD/JFvLWvx3Nf90nXv+7PzPvzByV/5FX/BlqK3sO/AvuQ8oZJKjwvHME7luoe/yAv7qVrxi4f90tFW/2gHbGKw3KPylZvDH/b+7YL+CwFt7cHyim/C//nmu17W/VkXWbxKaWgw7koXbNJzSQEACaImJQMiiqa9punWtS9bg8FgsTvodvvVyqAA4sTDfnP02NxKd9gdNoNhbIaNNNGSpLqBJKhmSWJKmBeoxJhU64jeY1KpGmdWtgtzIKSI0imCsJhFgaguGiqoeDAUwwzgrZsYoyEOmmGyJsWhRBXAlJLWQmrDuhrWdWpsgFEsmagvQi2gQqrUbzSKOKLSeW/mCNBENaXUVLESEbEklgyhIYumCpDIATsF6A/rOpoZNrFqB6eqjBaACmRvZjEhYpOiQyUUAiFCIBSJLNJSiYjGjn3IYu0MpSHnatEEmKJqMjayZADApXOkjhRStJjYyGEgIgrQOE7olMukJKNQpqSaaoak4iC/bs3ZXy32jUZVhSaRNA4b014oVaVmJJcwD+eFuUEzA8oRDeBMfQQWMCeGolWUvi7k/4ypXwULY2OP3nPvmC+rCC2DZBVEfPhEa7HB8WC3F681DpsnJDAsDbFWu/VgcVdcnuu4otZHbvrM8fe+Dn7/+vbH/3TDo/cpU8uo1SoPHXngihb/adh61gC62FWwNdPTM0DjU+sHIMfr3sXJ/T9lOYwryjIJooKduq5OnTix8xoA2PbYLR4rBB/HfXv7Oj8+TQUSDocttcbAYTNQfGfBby/01TK8sz+8uE5JXG3keOPFZy/G5eHyQrM0/51bv/HtPd/vzIaGUyUqCUWiQPKOQmQOXsBiSrnxcYDaWzm9oc0LdQkAm7Zt+KWX//hlL7jiazffsf/h/3p5e33f+Y1pWKp2ByW30TcNV/0hRAc1jW878qpr15yzZfPVr3j80x/q/tqbZ1/zq0tjk+de+/wDX7t7odCp061n/Myb9t9z/7bts91X/3a4cuPu3/q1dd+9XW/4ybO+d/vez31o81jZGp86fPENFz7xTXadNFhZvOia7mQL6qqJ2got1DoJjnU6dWxiI2BGjE1TP31o34UXrpmZXVMvYW+4Ug0XU2q4CLu3/8B5b3WkgibSbGljS/5Yt7WyvT73sp949UULL2214ZIrLr/rjW+endDh9rVNNZdwkGWNgKo8kjLkvZFzjpCZsmJQCfPp0RgEkE2FHPsimGJT1Sml4ELuezLoOJMf1fIQ3yxFFwK7ACrOOcdeVUEsNVFVHWDpstde42qMPCCxdwbYYgdo3vtYZSCiRkt5z1LFpqqNgy/IoWNhJAI0BDAlZHIGpiKJpKn6mNNeAJSI6YeBaCAqqo4AUjLATGs1NKOkhpokh3rmt9WIXJcHA84hmVMPHqyfmsUAr1iavXVhev+aE/++5uHfO7G9R4mtLdHMBVwdDzCggoCamKJhbnBzjlGKadTbhxBrQcyoz2RmzK6JNhwOnXPee0Cqo6UkzAJGKYkYGELdJERMKdEqQmvIgICSt1+GEURMGtEw0sUgAsQ6sacsFsu8fsgWcAIwXO2XOEuNTDWLw0a/YgDIVi4zZCKHSJRMqbHgfOXwpFZre3TuXOfRC/v37uye99SkBJ75+o2zjz5hrZJOHcf+gRdfcGH7i7q4Vjp1rAorO+nSa3t77ylPLcPi+LqxpWPsWERXBv0WwvhEJ/Qb59suLVaD/g9H0BPbJn/mF9uXXqYwNr9xcnZ45IM3//Vrdzz75e//wK6/vWLqn//xs0/f8/jabVfsvGClfhosJN+uq97RY/vpE7/Yu/w1dsGLwvj6qQ4/88AT39943abi4HMO37rn9NyznrfjwbfC29697vy9dfinayg2qfSJkM0AsAgT6Dr9GLUkAMTkuU31YFjXtREOBoMitPr97sLCQoXgiIFQ1BCEmBSsX1cuoflg0TMjeee9N7Ek0RUud4e5c2XmqJJSyusBRJSYLwxW1KiRFMV7RvIKSTUiKGIQqKoKVgFb+VrKPlrvnGoyAAQFpYzRMEQ1EDPPHIiReNRnggGY5WFMEXLLbqOLSgFGmVaZTTjywjUVGkhKeSkVWi3QRtWcc2aCWd5PvG3btiNHjohIg+wAxbImUsmREmoSzgGmaJm7CUA5XaRkn1LiIiRVkxRCMIkoKobeB4Ua4ygMW9RCaEFSy0lFIwoemqGIiUSMSmieWFe1FewLYpaYCJ2KqSYAaIYNAIllmhACGNoInIZ5w2mmIIQIZlEFDEUSeq6qquUdGnfK4sSRw4cOPc3eaRJVSYrouKrl6SWmbemLxc+uq/eeHtKggUGE0xX+40NuGGPRnsIbv1B89StrrUplRyEQckLBpu+aFlg4dPzwMybG/roY+xbIbd04AJ2rV1rFxLoY3zC15gYsUQYnm1j6Ti/1PFpsYkjx4EU3rDv8yPRgRUHVloPo4FhqpkN5Yvnk1EaNPc+hagaeOaXEX/D0kJd/G8Y7Bvp7ZedjRX+lv+HsbVe94ZVL/a6tVJ3ZtUeD/OPf/dXP/NyvYKu9tNxtO3ZJkzS1sdTqkAJSrGvXaTtQmly/dtwfXJISAH7ix3903brJD33yS5/9198rtP7G+OzywokrPP9OvVQGrJpUbTibLU698zcPfuHGLc+89Lzf+/P9N321fvSe+rFdl//puw8N5qoVe/rDf+bu+M+z3vKRvd/+1uzWdfE7t9RPjRenHj/8mheev2//uAP9z4/oeGvz2Gxsh+74xvnZc1/+9T/1dY2uPPyy67vLg2mLsdXiFEPbmWEaxmRKwKICZMzY8vzAw9/dtuWcDdNbm9qDpbHZUhqs2wMDAK9cqT+01Nm4dhjGtGXLx0/sPX7r5Gcem3zLG1eOb0qLu3XsnKI90ZyY92EcKiUzQMgKUURCQMZRxFhZlq1WQQyaJMY6D3ckmTdNGoHIAMuyLIIrPJspMTtigFVIRJZioYZWCcxN04A6x+SQfVEMh3V+sgTnvfdCIy0JMmWbYsEuB/8yYKfTWVlexj7E1JCBKqSULCUkoMjsjHm13hvkaHQTMjMFI6KkChqzOiyKEgXOSTfozRpSK31RS6SsWFYzXFVmZWYds3PBrb5l+2ZIJh5TnSI6LtBb7HtcG6fevHTh+8aXb1779AvirmeunDtfNMTgRQlIQQVMQVHR1HJIaZa25EwFDkxEdTOsBgnRMXMmdKJCjJJTxiUBIRlB3QiCi4IAFg0y9DCnStR1jQhVVY8GmcQiKiCgiEaMGEhQhZkQ0TkmouAKQqeSkxYULW+gQUHBTJBcPhoAqJGaAOY6AAYmJgrCyERA3hEzkikrJgHzbQUf2s85uOmJzY8dGe+fOBcvemhx5Y7/Gdt6YRxKPTjd/Z//mbnl+xhCbMSbb9fxGS9ZEqF79m+r3aA3s2Vs8ViMiZmVcTk1ZatjhvWwctiXZ77kTAGe+t0Pdradt7jrsa1nz55cv/2/yiNf//aRC8OWubs/UH/0ny5N8pp12w9Pdg7OPzWlziZ8I9X0uulOGMO55vQjXx/f9e1Nz7lo09zSw+PPmL/87e+680NhuPfZi01ccxIAHBwZlGsLHwDAVT6VfSdIiEvLy+PtSe9cGiQzS5CGw6HEGGMc1g0izs3NMUEyJXajs6mBZRUVATskhRRjt2kAwHnfKkPpAwGmqhopKrJ+cGS0Hbl0ADGmmGNAASDGCMTeKHfeycABE6CioYmqmpGiri47UxZbIYxcSTHGbIVXABd8zuBNTURUdk4IDNASgEAIDhGLoqjrGvLaOCu00WVizEh0QCSOLIn3bjismb3GFEIwTZkKGYiYuWmakydPVk3D3lsOUMjCJQRmyrHhSMSIjMg+E1XVzCwZAas2YGogOZ6N1BgQzDVNoypGObOTkZwag0U7c+xefTOzgKQMgOrYmyWxrJJTVCdiDWl2ThKDJHEuiNnItWaQVab5SzkwzSIsQARIhIjo1WmjPnDGv09OTx584pFh1V27dq00sZY655aunShffd7y1/e5Q1dvXxcfnR+Qmd59hN9/Dy91nQP1DVgi3xkPU1sWji4W7QHEYVlMKxeuAd/gynkbD84dH2/8m9za10745bnuoZNVpzy1bXxtOTYxv7zS7S0XFAhSCA00TN6T4cGLXnbxXZ9qfM3olDCsBFhTmPJYMbkLBjX2U+qhtkQTEznnqicbe37BfyXy/qr3Ymm/s3P3V765/tEncbyF7WLct5/etTut9D/8vj9/49t+euvOC5cWB4U6xNTY0GFbJTnAdig0iTOw+vjp9ZcV0lkLAP/y//5rv3da5k5vnxifGNu4fLrbbRbvd3jkulec/f3vhNmtF/z3vV9/17tf9Oqffezex07vPuqPme45SmjS1Hs//Ln2z71tttzQufz6/rfun//EF/Hg3pOHjq5pnazmhltwcmjD9hTHem0samcyBJV+/+6rXupSvX3vHfVwQL/4e/snpsYXawikwEZSgaC4GsQxp6hEXNcVe4qxmZhsHTvx1NLK8Z0XPG/D2h3HT59s6nqmWo8IXJGM6XCqGQ52NxOMNQSxjU/0thyK5drzJjfPHAN66a+/b49id2UherBsn9CRP4UAHRISGEIRAhGoKjsOIRRFkU+4OV86Sg6/Q0fsGEXEe8yRIIw58BJHsQFgBiimjM6zIyKNCYk7HZfvpZSUiEQiOc5SjrpJIoLOZ/Q/Io51OqZKhHVsUpRB3TRNo4CeGQmQyRDzMVxGZB8gzhsxEBE0G01zVyEh+UZXE1UlREPLPS4zOecRkdij8wBgAM4574uciZv1MoiYHIgDFaAE3lHQUCAut4rrB9c8ePKpWzYd+uT0Y89J50/V2CAKMwmYAICY5ade7iZXBVMuNE1jqiICas57QNbRCZmco3wGJyIKhQAkRVLy3sfReYFFs6TMxaTMvixCjDH4thmaQDIyQzQZxVeA5VjAvJnLNpXsg1LU1XVg/kmZ4siKldH0lFMhDY0Q3KiEM7P3nhznr+CJI0AkowInhn7BpYvn1607PXHyLDuwZvGZX/zaCRUbIDaV76w79jcfHJQ0s2Z6pak0wuzZePbl/fvu3eak045Vb3rz1IndTYwBIISi11STaoVrJzkVf+Yv1vzc7515mBYJ7r3pu1rWO66+oDe17b7hHMwNv7nr/jcvh2Zl/kC3ufjK62XDBfv3PA7VickWULWS+mRFx18QZjedj9MbCvZw+LG73/Olq7/9z/A/fxE3n7dc68TZ0wDA1F9z3gtwx/b+YuXXttrDIoydEoncX3H94UClkmgm2vSF16z0+nl30OtX6HhQVaEsYiMiiZnLIoBRjGKmDES8WlQARGRYNSlpYNeZ6AwGPTJIpmVZiogvAgCcMcsSUUEcRRDBOawATExSamB0bAVEUUUCSdmcw86FM/C4bL/JA5WmaRpJuhoy7UfcaQNARRjxswBbrRYzx1SXZdmklFJyWUZAoxsQgOxMgDGSQH5cYIyRSAyiI1aJ3vvchSPi4uJiq9XKeV9ZnxyYVM2SoHfMfrTf1VGEw2hCBiCm6Fhig0ymqaokOKfAGUJLAGKkCmqKaE1KrImMFPGMCCNX4qw2NGJw7ES8QmMo7CQJIEoy59nMCEd8PAUFwNzxE4xCPw2UwcTUwBBWZWgGHhDMqWqyBoAmy/LwU3tFGwUbDofouI6NI/qJnSvTpf3+dyfo0vbXd8u37ipPdenoAMASGLjCJVPEcRf7aW6hA65O1LYJkcLHfipXUvRhif0gNTEeanHblVG6FyhrGhv4cu74YeeoDK1CmgqGJB1BMJXFrZcNx2d2PnVb5Imy6TZqUsb+wnyH2l3lOyhC6pQM4iBzW5xzJREQ0nupf9uK/mPTv3PFv6Mzd8fRKStM0jxKa3yMp9YQps9+6iO/+H/eM7PhnFNzSyipLJ2kpIbgfNTkDJ2B7bjqmTPjN+1rJgFgMH3uxpWF427P8eq403OkSKh04fZLXvu1r331VW/fvnZqd23DOz+hh34nrN2hS7dMnFUUV1++dt3EoO5c8MZX1haPf+cJmZnobN/c/9qnynEKw7He5nM7utgbDClMxUEVi8iaODWDdpv7xYFLXrH9iW8NF+e3ffAfbpu6ID1wB0zP9ABbUX1BlcIE+C43UtcIHEJhViSVVqvTr4atdhljvP/hb27ecuE5G3cK6OWHrvvezi9O1usX4tF62gASVGniCFi/Pvs/pwatqcmJpnfg4IVXvrLeeUF314PFVIhVTrFWA2MAVCPIz1jHwXnPqxPX4L33zmXjvKoqCKdkCKaYof/OiXMjFbRfxayfuSebFAMiFgxmTB5bFlNCMlM0s6DKzgGAZXiEkuNgSCLC5DDfKgatVukc17EaDKqUUvI+xigiwXEiZUJngEYCCmpOUVDMQFJKlM6kDZqp9w5H6EpIqvlDQIgjnYh3wRM6Dt77ApAhh+WxRyZEZKT87BuoIRk5iCUUKdbt0FGixODpZ3ov+17/P/Z2Dn5x4r6fXn7F0/G0byv2kcwoaSOiJmQAhia51hER6SoSiIm994Nh7ZzzgSWZSFJV731RFJUaGBlAAgRyqqoCZuZdaSpKaiJlu/TOV1UiRCgI2fPoWWOkgpBE0CubmV/9rWV1DBEpyOjZkkXugEhI5GAEGciu4JGmhpUQ0Xtf+IIz3hDJoXPoIAVEALR+6WxQt0LnWXOb/nvznocvGlzW340Wmu2b27uPDoqJ5c78eFkMNRbR1PuLX3C4u1w+/D3lOEdg3elNZ+2703sfY2Szuqm7vcHmzsTR3uHZ515nMjhTgJtqntik3W4GvYnT+/BY/8TcU/d8pXv08ped86yX7rj1sxsf+Pxxuu7CV/6CfPgP6rn9/QsuKFJsWnVrUPL6UDvtfP/e21/7d0XdfcnXf19SU5w6jtT4+3YBwLE17vK3vqtLYyWsAA1cZ7JeHKokiak7rBU01bWqLSyvNLaAiP1+37uiP6hCCETUJC1CEJFRSqZlLCITQeAQVWSkPEJCNLNGEg4GTZNyfLuqppTYO+ec0chpGtgRETWNYjIzQE4opuoSKkJEi5owieGoCuZam1IqsipV8hhGjTgZiGa2BZfOs3Mj0zQAmjISsjOznC7nAy8sLWUtWF3XzD43poLoVptLkWiGInnDxcDJSJKBpuS4BADTPFTBLNFSVQuIBoaaiAExqbKpgvlsL1RjxhxxSETMWKk69hZNkxA59GSICUChLsqg6qwBAhOJmiqHYq5ARIcjImt+nYgoq8xXRENPBOATsWrjhM2DGTp2CKMTiVFCy9Z7BCRDzlscAOecoiWVDCeAUZqiSY67dgCWBt2VfXufDME1TeNcqKQuQ/CWfv1Zw8/v8k+dlvNDa6kXTxxjBEVHiK4x9S60yEXXr60lE+tdU9fdXvBxaCvOksSyREenBw7dclBKVW9xmZmOoVLVTNlkcAwoaNzz1oYJS92CysrSvsuu93Vv++P39mPPwAlWg/GxrR/77GPv+Y0Lx4oj3An7D0fTaDo2Pj4cDuuYMUTgnAs3lunZJJ+smpu78Ceh+PdZN05LVx3WZ/fM9/ye4L8WPvxXf/6qH3vzy1/zur17nqr7qRgrJWmdIisgmWsV5RzytrHe0/0CAJ61M+xemnLL685rtXDrpB4c1BPp0sMnT3zridk/+ENo2cJnP77eQTFu02efU9xz0/ynP+y+971jx5daj333wKGHxl76qrBtzVk3PPcHt97WZi7ceJqEzqETDa0QWyEhsnIamlbWmi5iPXDFwe3XvOD+j1/yvUfnx2Yf+X8/sGW8rFL0vjDQWlLLFYhYClK73esNLDamqAJNLSqWTAK2fOEPHtk7OHX8wvOu42bHcx976/cu/bQftgbd49IMix5SlLNvK9bf3uu1sFfRcnN8YeHgk0/+IPpW0bMADZjmsQmOOC6GSMwcioKAvC9arSKXKCTHBMSGBkkjUaNgpmgCzjkmSJnG7nBUfpGYPSKCUdnK3lzQDMNyVJCdyUA1w5GA0ExECM6EgYtzLnN/QM0F16Q6JO9cQCDqDQY2yDutqEJKbEokgpDDw6s0zDsZQGLyiBilGfV0ZmiIRN5zRsalFMk5co4cIzOxyypKIpcJvbBK+DIEBFDVMfGNNi6BOtSMi/WsFpddvNjO/ZHexV8s7/yse/JFfNm2sG45Vk3RYMyTc0nZeqtmKs65pqmy9tKxR2TVNKwr51k1gQAiB3aIbACIXFVDdgzGgE6zKwpBVK0RR5w9l4UPZtbudJwLwECOFfKSzxwYoolEjVE02qpDmph9CNmIbNl1DQo5fZ0pLxcUzEwyaiBv0RgZADhvLkkVkJkdZQeqMroklRC1Ch8Jrzmx+RtLe7rb5btvvfLHPnZPe2rsqIitzLf8WBwMeXKMOq1N25fWbR7ceP/F2ml8nVR4MD47uXwizzdU1ZFb7g/Wjk0GoPLB7y2ef/6ZAjzYd+zSl5y3ZcO64w/vX6jWxP5Faza/aWLjcw+fkFNnw563/cjE/JM/9YYbBh/6k07vOJ5z/ev/7p+/9ifv2Z6WFji1B+XOfU8vdnY+9ozr3/IvP99uaFi4w7KyFlqdZQYAvOFV/Suej6ePFePrWNLpo4+L9jTFBnwcGx+ePK710NQiFJrEOTc9ObW80puanDQA8UwEZpiBw8w8EvIDGkhBzpsm/f+oes94u67q3HuUOddau5yuakmWJduyLfeKCwabajqEXhMgCRBC6s1NcpNLbgqE9EJCICEhJIBDDcQ0U9x7t+UuS5as3k7dZa055xjj/TD3EbzHH6zfsayztfdaa8wxxvM8f0HLgamcBfB1Xedfe1/me4GRnHNEaBlYK4BqBRNwESQlw4zVM0+gKjnS0gzAiEeOWAAQEcC8VHYpWYgxppSJgYzEDkFUIKF3zjkkJylBdh8gcOFTChKkKEadtHMuJRndGobsR4snAIhiaOZcEWKfmBTEMec6P7IDqJNkgJJ/dJKExCBqJgDgiBAgJRHKZvfluTEhESUIRJhSYiMzJXLMrpbIjosmsoohgWFEAMfKFDUVZmpGRAyERMsWPtDCOSBvKJbAoSEwADeslJda3kyQ0HvOe6KMxSYAUGNmBgZAZjZHZOaXzdYAUVWjmjr0VAaNZcHP7tq+e/fOqZXdMGwsGTKC2rvOHKzp2p/dXcYYyVfa9Du+HKahNzQzh9SNqXTxsKWWQBGxZ6k7fYKFXlX3qaokiRFwhc0wOvIdLaVQdNZp3BIGdQcFfCe4vu+xlRySq9qp1a56YeeWq0584keDLvdXrxi6iQs/9bl//dgfb7zsqqWi89yLfuaNL3jFZ3/9LYeGTadoiaaiKJqmaVdVCMERoQg9S/zaqcHv9PQPw4GX77RkOIEKaAj1Ban+mWH3T8du+N43tj1y1/s/8Bto7X1z+ybak2kYyTt06JLvHtwrra0LmzZtAoDtjx/btHbwzLHxXuhNHB5Y8NxMXFWl+b/841X/9JnhnXdMfunTMzK+93c/UD2xoyP95hN3l0vNeKubSl71klcvjrvhkzc88O9/suqOu7A7VicxIEx949IqWBpyURTkxtNwtr/YA62ffMtHlP2L/uAjcwcOPnjdDyepRWNVObQCUS0pMBj10mCi7DYgiGimAPkJqK1WJ2m0GCGVVQUhLjy7Z9ulV7zsbcNfXvXE1B2bv3tkclw0tdvV2bdtvlRfufpj9r2/+5M1DZ9x9kuf+WBRt9tcD5MCAOgovlmBnAKQITE757xzY50uZpsvELPPw2EzEEkOWMQnFREzMgCIKRHl5zSTd46YiBx5RlIA5zifiF3bq2qUqKiVL/MNNZp05j2KM0cuR0NbldefpqqOOKRIDY7uAcMs+4ixkYwNTtaQSVRkIMAoBqOmjUSsaSIzG5CBiSkBK4xCCPISC1S9L0buDnLLJ2IejatRM5diNLMyAICE2lh0ISVDAaxqFrYaGjLYw7M/N7z8tsGu58aOfmZw28fd20F7JpBMTdVUNaZkimqECJCOG5yCJrKf5MsDQD6dx2RkCuyQ0BETEkKGGkHe8xFh6T3ByDQJmJCw2+mWRUs0ZtoEM+fsAyIQKzRJiHUIIaUAoMRkpGIGo6UzGQjAMnYZcshAll5RnnAyo3OMRK7wVHgFIUNDVFVRJd9E58G4laRRHpbQ3SWnPysPrm8OvOWc/Z+76+Sb7gpTHSfgmzoVnfrYQmdq7LxLD+zb2Z69bn684JpxaXo9EJUHnpUYseCCPKrUoVkymfInzu/eNaHpeAGG4dJzDz/71R/uv3m3Lr7578l3u7I0WJgvN+IQYn/9i3ZMnzfYWV3Ka89LYZp977++e8W997fnjzYc2wvVoLvwH7+/7ZQnbjzjye/VhB1om8yHjSf3Fw4DLPRfcn7cc2CiakGnOHbXg1IlqJLUzfzhZ8dm1ieIwdTAnMJ4p53XCqtXrTCgqFL68WY4QF+klACV0Jlh5Yuy8kQwXBzIcuqYQzKzOoZoOjE1aaJLS0sppYIpIw1GUkkDNWN2qomIgMkxxCYVBoAYCAyhUFTj4CDPbDLNN6XEBGbICAZaMFnhsikgR1WAmhaECJ4oxZSD1CwPaUVijLkdJ6Ls4RGJ2a6Wd9UpIpKM3EoKABxjZOZhGJaVt2SOClE1MEQMTc3Mlqt4CCYGbJpBwMxEgAglUFI0zqcOynapPLBxztUp4mjFi/nGYoBQFTFGh44dUxQH2KIiJgmGx81+hEYEnhnRRDSnw5uJ987MwGEygDRSjeSge4HRlsobZUeWZU9yztBkigasaIqGmEaAYIumMUVVTBBXzUzfe+NjYFYUhVeuIQmIt/hbl4UvP0H7abozXqNrNaGXPKj3LnGEFEW6hJaGLnWcpziYAxy4gWuKobpYBqq4IKqwXkgd4uHSYU0AyWZWdFJTDdolhSjJpdRpau0UwoNjQxkf9OZWbTx0yuUX3P1Xg5/74Mlvfd11L77q1DVnX/HRa/VAP540ubRhw/DI7Ef+8M8//bE/mqv7DDis60ypibG/ZcuWfr+3c9eecjF2/6Dd3Omba/tAAHOYWgYEsIR4iAe/v9Te0dr55JPXX/f1Nes2n3fpxQf3Ha1c1wzJO2ehmYD5yvrb9hFsACpg2xPutFM3hCNw+MhiWt1bf2R4IhTxnu/1Lt+svd60c6FV4J33lW0J1u3w+HAcwSIB7/+r/9M/9Fw7hZkSOrR2jhYmUzlwTGNTVRjGpjesF0Ot4o+l9Vu6V1yy+sMfvvXYOWsP97e/452n/cybHxsOV01WMrTkqdHBCiVDqtla5JckShPzzFOWsT8xRnIYucnbVYBqfjB/853/WcCqLdXGV6Vrn5p/GEpY609treuGzXjembR3YubQ0r5UhWF/Ycb7OiX0hURDtJx1rgDgCJHQc2a+ppgTTYgcI1N2xhORQ58HQc45ZsxxtGajq9OI8wwyS3EIiJkAzBWegEWUiMqyJRZYXf6/IB97R1wWAyTnvWJWOSgXLCIORxT3lIKZldXIbFrXg2FoICQSCKaJ1Ct55ggQQ1AzMVUCSZp50aqmIs5x0sw/YQUlwKIsNSOAFMkAR8LLkQQmr6Byp5iHcgAUbOCAh5QwQCSvWihEZ4lrXugsrdfuzx153sfHvv+jsceunr/jZXbBHp3PVXYkT1MjRGIOdR1TEImIKKI5fD4/9I4Ph8HAOSeAdV1XXCU1ESVPBJrMyHKcooSUKu8KX3rvylbF5LwvahtN2JxzHkkzEtaoInRUkUEgSCqaJKgAoecCkRFzbBwCABmAaJBAmMnOmmswERXOISIQIRMRGuTOzBA4xRjNVUO/6AdAbR2n+PTTz39421NXvvTw6Z2DV6zv3Rj9HESUnkOJ/VaFW07d1xkPN/33TOgqMHDi+elVANA5sst7H2n05AXHixony/2nDod3HHPH6+8nn117cDEtFTSzYm0RnpUFngvoyOFSHdVmjz518sruMZn7ztv+YmHVme/98R+M3/f1edo42w2TIcQV7oZr/qLXWfne/3lrGs7OROmR777tQ/vOuXjdprPLdOGSG8IY2dj40aeegDIJTzjuN4PeDMtkYYt9K4kRwfvkmEYH0KLQZexPNdYFY62UiLLNvfKF914lQreVT2BkAGYpCaIVpctnzTzBZnYaU2YAM6AaMFJRFFEtJRFNtcQKSRygohchIGFA1CKSknhXFM5JspRSURSqqSx9v99nzwXQMJuEVJnZIYWUyrLstNp1XasCEtUxiKkzFNO8llo2EUC+QXDZbR9VMF/hBMyYQswda6fVQkQzIHXmU0hS+EJzuhvgsKnRgMCpkYAZsxKYiUNijxABAMTUFFSVCLLdllQK58QQkKMYpOQLD6IEVFEBoGbJSAYxgioSkDlDJeIsWEazbImoGogM0YGKdYw0SSAMbChYFEWM4n1JBCmmoihE1QPJT4WGjybZgOidSwYKEQ0QHVIiUISyrGjAzvkQ6wceuK8zPrm40KsQy6oVhd5+anPiuP4BvPB5V6z9/tf+B4kgNRIjV75lzswg1Sva3Sr1W1AEHE74Vs/hZCzbw6V+RRGLFrh+bCYqhkYXL7p8xUd+r8VMRX/n33+qvOXHPSjHQZ5dN+Mmz5p87L5mct36H92085N/u+vhvYp8+Yc/vPcbX1i7Y7ZoTTfP3Pb012/Y/Mo3BFpbr90kB54py5Pe9tv/7z8/8dGlfm9ycrIehqZput3uM888oypVuyUITUoOuXkKYYvZSoMaoEEYM0CRfdp/XWw9O3bzD68XkH37XvfOd7/v2T2HkySqwYlZtxgw2Xcfn4cN8Esvv/yhbau+ev3dg2Zlu7V6Yvx5L3rRK/GmvwFud2M/jU8upjpy0W2lNkmyANGV3oSxpFLn961ctY4VFuqlIaKngsSl4RzK0aOpANbOhc+beOO721s3jZ91aaxl5/XfepBPPvuGv3/BWVsfPXVL9cMf6coVEoeUUoEUHCOqa4J5TxCBUTUbhIwpk/5oMAi+XSAiiymbs6ZZSLXtO5oaq9qnnXpmM0jgqMK6bOrHHmp2Pv3UmpOmG5KJctwclqkUs4SAhkLEwKyU1MiRVyY0RUgxIBMVPAxNIeLZEWluD0VNs3EoJRMFNGUANQIkNUhigFAwEIqpQ8bl+VGua4bIUBjnxauZCTCZEYCRgaCaJiJiYkXKDyaE5R0MQOmNgAmGYMYEVHAY1nVdMxBEiSB1aBAxJDS1JCCeuWCVFCV2Wu2y6DSDvvOECIiQ6eSqllIEAg8SYu3yntOiIRyvmtkEQqNMaAusDlCiVuwR4iAumCM1q4wHg94B6L8MNn776KYH1u38t+b2y2a3uMQxj8tUE5qZJUzJgrKIWUzSrlox9gVALTnLMmIwQCYiUFFNBsikAsyIDsGGDskTmmFUhSitgr13eW3PzI4IIbYYc8AkEQLkWg0iIKCNWSq8BIGkzliSsXeKqhpyx2w58syAiAKwR2IdRf7mgbMxASCyR1+YqkrM+Q5Ro48VxbDgB9QH4iU3N9Gqj51y/e51z8btG3XfL15R/OCLumlLPRA5eGyybEM5PPPKpWce7vZmK28SG42oi2OrAaBY2B9hyOyaQTJwhfNl1DR1zqdPuObTN88dfwp2tdWZ6G0gPSZ7aLHU3kK/qb3nqhFql4P5/mxZFZ0uHtt+39UfenLzWe/77r9dvO8rvlekqty3Ysutl7/3Bdf9wdTOO7unXrDAbC972+xLX3TTr73/0pe8pfWazt5y+xPdB1Zvn5gOLZhZWx1eem5pQQaL1XicN4jBoQ0NyJdlWZTHJ7RAyOwE8qreCHJkOnnvkyRHTi2zhDJYE0II4DyqVcZJUy0xkpklYk9IiCSASliBD6wh1CBm3lhSmSrDwVw57grGOpaLddESVQdOl4ah2ynDMCRTYxyIofnCXMK4OGy67CrkoSSP5JZZJY6oHwZRk3OuaRoCJmAA8AjSJFeymTBTkmgoRVbeZfiAChKbISjl3Y+ABQmFK0ARTJEFEUsmi5L5oIaa1d35oOuJFZICKgqYagSnpaGy57oeeHYpQQSrynGJPTZgNNVkCMzMCg4oOlMwFCiEklokFsjspkjERpIQPDgFUCE0XHChANIg4HgI6h1blBLBSidhWLmSTDSC896SIXPApGCAoxjqDEJBAA9JEKkqNQpaQE+U1BujkjnqTo4/t3dHb+5YMcapJqGy6TV1WPiNS+RuO/XI6Zd+/4/+tju9GgA4Dh1iAokRS+9rrC+hMobeou+txMljg7lqcipOT8wfni2VicH5pqqVhr35grb++9d33vnw4NmDC4tH08MPxZ95M156xcMf/b/nfPYb1abLbz0dL3/7W5fm/EmvfNsPeecKGs5df/3Fb3kvxGew0+Xatb7z1Yf/86+n/vfH58LRqpjp9Rc3blj7K7/70Ws//+9PP/Zou10xcx0Ds0dkk5SDyeI5CSNabYAALYB5A0UbM+ednRODhHKs45y79YZvP/vc9vd+8NdC8vNLQ8eElR0GgLroAsCff+mHrz9r+v+978qv37P9/ocP7X1u7osTU2de8DOn3/6V/vjKcth0KSJ1qDWTBvPJWeoyGkJA9jZ043r4EGl0aosYB+R64+v9JZdNnr5lzUtfjhe/iHY/fnDnruFNj23/9d9sHdy9cMLFzf9+37k77rBf+8Mn7t8xMVE2zSxTu+CRV9Wza3eqwVIP0YwYkVRHrL2maQDI+4KaaAAOsfAZ74OOuaqq3Xsf2bfvyVUrT1ioh22mudnD1C2Ozu7ZetKqWhoS80CNRzBxBgp5UzRKjgVUMQUFkTzNHaE3g2jQxjnPzllKvqpCkhSiR9IkIQVlhGQpJV+4oigQsa7r3BNHSDkuLidBAoAhmZnzLAAgqjhiqGTlJDCBaDIBiCNZEKJaMrSf7iCXRcvshOIyhziE4L1XUxEJEAwgiaQmQB6VAsYQVCTmrRWZoDrn1DTGiAgiGkJQACfGUXJGdd77MrOkJCnF5agv1dQQm1mIEQHIgBKa6DHfjNVyrGCw/vsPnP3UxJ4dq+FLi3e9Z3jFvC1EqCsUiQDJDbHfTtgYpKbJIhTnChEBIAXiZaGmjhKICNEISTWakQGhkuVIIIiMYgh5vm2Wde2kYKPEJBhpR4+LwFNKkhKo5VKcxPIQRH8qymqZ4zDqcpwioCkiEBooGjIYigIYiFpIRGZqIkHUUDFgo+wKBWnjgLiana9vu2Ns6ei5d+7avem0p86fvOPM8aufme8VWDkyiudctmgAd9/UiTGIKHtHAIOJdeVgnpNIlLGJjYvWd/Fo48tyYfHzb/7s19ddsGl+3/ECLNL0caynS+M4PrBGuu0V3upBjIFg0KPBfI8aN14QTbeGDy+uPPmj7/z45bdf+CvPXVsv9a57zcemZ3e/4tKZuY3/Z+1Vb3x8cVfjvT7zmNv31A+bTw5o6fZV33uyc58/0W2dv/Q1N75i/cQpu66/pT1VzVe0Kg4GLRVl7gEXVVkxMxBiBjOLqaiAocMRzwdgRNXQmPJHBqZgFmPKB1XvudfrefKOyJFrwpBAY0yeKkRyoomSJK8pCIaidiqtxE1dVVuX5q747g0H16674ZwL+v265SoA6nKlSw0RcOEAEsdY13XfsYNiHHyoa2DqVC0q/eLSkjfwQClqXnplCb2iAlCQ6JxzxKMg85TjSlEVsrIMADQvk/OORlURmNmTNzMEI+/QIFjMqbWkBKKmhGRg0IjkqDsBYe8AkBwxoDAAGIO2XCEi3jtj16Rsg1QEThoVwEyJHRAzKgMoaWKJoKhIiGxgngzQEWbohZhGi4qegR07NDIDSwYIZKBgyOSrajhsCND7MokgmUQ7vopSyc4RgByCCwUzxBiYDFRiikQFmBtj7VksJvm2b98Sh3M4Pi6pSYtLCOlX33DqKdNP/e72ld/90l92WmNUdAEgNEMwxNpLKabRQXG5ay+53ZOpG1JKM5013B3u39G2YONTqS+Hm6XYak++4PW2dGjXX/3Z+AUXLqXm+b/5ka8PHz35qjdOvuSVR8JqwzWzh3cl5/lFr4uzB8fOPXfuyNZzaO/sQ994+uYvTb76NaccemLfu16zedijS686uub0NPdkq6gEO3t2P9eG9gc+/Nv33HPL97799cXDh8a7YzHpMIYTT1y/OL+wtLDQqVrmUtSAgnAQbK3B0LJ2B4HMLKtlZ2baYeHo9V/+wlvf8/OtEh0Sb6oqANiyeesegKMJ//G/71g55S7etOYX3nRWb745aFNwdNFBMd72nVY1HJh2KExUS3tkMlkYDEERSRZ6kanbjK0MK1rjF1yw+jVvmtp8aoTYrNkY7n/s0Je/qNf+S/vxo9hbbO/fs4rnoT193fPf3Fk8fMbpa5dOOFfveLg9OT6ZpB+RCCSlVlm1Wq3+0sLWrVufeuoppIyNWaZROlYjExUVQHTOsXOIKGAJQcDalVe1vXu3c6uMiEXJ49NTzGwsXedFRMFUDQhkORg2t6HImVRh7DwSm1oMKUq/9K4oClADwJgSmAlAowkNQoiM2IycADlr2zIWyXvPeQu7nM98XJ1hhGbWBPPEeQodkqgqiDrmoOIy88gsw8IIEdSMR6dsGVmKDHIQhFpVlJo0hOCczw8D9ozosAZyzORyrI/3rX6/r5KZZUiAKgmZRVUQPSOIxBgNGSA/XbJTglQVeXREGFUvESzIoqJajrTMnl1ErGobqNTReql/4nDsVQdP/sqpO745/dj54YSNx8bnkCNCkcKgjEUfl1K2YzoC7fUG+Y0qilJVj/PGzcBycgdkEJICIKqYISgYj3BIBTvLzskRjkKByRFCxgbr6JvH1+2ST0XB2DAgGC/bokaaAyRSRMTMP0akpIagjhIYGroMzUsGZqiJVNDQxEKd8n5OLRg7B1j1oByf7D15T/fIUbN1L/rikz987ab9U8Wzv/yS8z500+TE6rl0ZHJseNr5/Ydun4lSJBPkDLnS/tTa9uy+kmtL7WODY9Wgjg479dFtZff2+afXTqyWQe94AW6qsSI0Acv5uJDfnyhd5Z4bH6Y5KVesmV47Uw+GTZw/umCTPVs30/rOC9+0U179gVee8tw2/vXD102++l2H77/94XphdmEwOdV55oHbd7+5v+3DfU0YPC11Fn1TPtS6dfcLH/uVO/9i7XRLjMIJa2LTjDfSwwBoYENNkRGAUMEIXU7AiKJZdMBEo/ktQKbxOcchBGRCguFwSMxV1RIDZwaWByISIYBoJGayOkiBrrYGJTnQeUY08AInzg3f8bnP1gtH1nk68cjBL1z6snl1rpnVquU0EmKKmoK1uUWekvQNfOWcUFHHUIKm0BBDu/CmI+kDIS278wgEhNAwI6Il75UyHcQhmoKajMIYgVSX7wgzMyGmHDmJqAmsMAIDMFSzCKY24oXTcYoXQPZWmKKhlagRNAFR5UItHe8YCUMYgokCY/b6M2IWJeTJDChjyLiGJGxgGc7ABEiADMiOScwMk+PKDFQhWjIzcD4bmSVGMcvz9iiBnBPVGKPPeSBGy4+gETQtL9FLzyIRAKksUwRknEdaMTn59LNP+dPXlvetBJGZk9ZsvPz8Ezed+qvxH27Y377+2ofaVUdQtXAAoCYL0Lh6obDOwNyV3c5UfWhPpAm0WT+3qr/qiOyXcrqcqpJQWgUr/u8/DC1Nrrt09l8+7c3GJlvN8OCjX/gf/c4PWy//pae+fes5P/Mzd33zP55/xaVPvuFd0+dd8eBHf/m5G04YXPD75Zd/74xnH7Fnno4/uK4qcJxS9OWB51/ZDBe6ODWEprBm0nf7QfcePHLq1vO2bDnriUceuuHH1w/nj46Pdw8dOJhSqqqyubPRlyssoJUGHYAaoAXQA02G9xovpyLOH1585WuuTsqf/Ju/fvPb3+1Mk/kaAO5+bAgb4LQNM9v7k/N9+fZd+9Y8O7v2lDNfeuTGjfd+/hgMO0d6R8UB+LB0TA45Uh4AuFPPaJ11YXfzhrETxjtbLk1nn+ahWrjh+nhk/2N3PEK3/niKl/zGLc1s/dzM2LZVqza+/30X/M+1dNdNRN1HT33ZqY99f/Lt731mz46xVlW0cThP3jdmUrbbqtI0DTAt9JaccwIWg2Szh0hyziFSvzcsSg+IitCkOGorEURhOEitVqvdbvtOKw7qpgkxqCnveWbH2c+7oN/maedDCgWAY5aozjkUVE1GBJCzZiClZGKAqAKWRMUQrKhAEZzRoKlHea2mISQRAUEEUtWYALJx1hU/7bcbbYiPByAjmCQiMlFX+CYmANCYvHOD0BTsRgrFLIUiwuyUWs52FpGkEjOUTS2E4LwHxBCCEbaqtpmVVlJgRqrK0nuff3er05EYAcA5IqKkqJChw440zxGYmYl9lqpm3dnobP9T5KU8OJeUMOlxVYghAFNqZEgioAppKM2rDm25bfWh/auGX2ge/O3ZK1V4QFqRtWIt4gRJIeaV7/HtVFYlI/6kWBohWs6iAkUCGunCmJCJDBzAstFoRJMFACADVIsa89GHYRSbkF9tIPOC+UHJynkOASqIBAaEAKLZSJo/R869jYLhaBUn5AQQALL+hQDNUBWCqIKBUmqwX6qUqUOQbn0Y1HDlxOp7j1x6z/wPXjj9xFWbzpm4aYsnLIoLXnykt8AP3V1F0bJVZXG7IxqsWD++cFBaZWNWGMrKGZtbcJZuPunkYsur+ocP9PknO+DUp6pcLFO1xDDWLjA46daeV0QoxldD7eHoUk3Oa2hVrFrp0WOLm63PNX19m5576LHOjf916+HHo3e6ZjVR6i0Np8844+k3rAZbSn6QcCguYcFjfpzL8oa1/77i6992byEjXGyGHWmlomVq0lijURUAohkiRWafVFJKOTLDMR9H8mUe7mBoRISmWSIUmxjqBGq95icOK9FI3tUxoCbPrmYTDWKAWBHEtoYj0xOvveHHzdx+aU9ZpSt/fMOWdSfed8qWEjQkLpQAtWwXAx3UgwUqSnKdJDLUxI49jGBZHlmbCG5EeFRVkUgEnjikkO9fUSEiAGSkqAkBmpRFKux4JLQm8stDF03JvDFalhOSIZSCZhaXs6kz3WF01ANABw6ImBHRM5tZQiPnUtSUUgHOQhqEwIVnIZVoaCRYFA5MHKAHqllJMOcHYO59Dcxxhi4bQmPCamyAJibaeIIoRAQFEWJSQ1NA8lyEGGOQZAkApGlSSlVVSbLcqOT7QkUMAJCSDEEMgsN8fiAz06JgqWl6bOLuv/hquvykl3zwPT7AwNLwwOHihs9tvPLIz/7ILVVVy7wDZa4AQPvzY73B+LrVwwUcDA+8rbMp9YaF6jG0Pk15Pbzit/7voSPWd/Wal15z++//3tsufct9X/1SePY/ez/476lXvPKp+7Z1HaypHp2a2TB20uTOv/zUaW5+8MOvzy88N7W0+ORvvLv93a/veOEH6Ozm8ps+L3Go3e5kOV2Hfr3Yi+c+b9fmC9rH9qXY0gJZdWEppLJB1cX5gMBnnHfpGedfdOMPvnvPHbd2CgeVNamJP270fUYbSFFhCiAaBIRxg9XmvlHkYHAAaI+N3XjLzWddeMHzrrho+9PbnHe2dowBYMdSXA0wJe51zztz7/6lZ5fg8J7DunPxzN95Fx+8qt6/B+YO+hUr3OTkxMo11aYzcWZyugjaW1zSYjCMg3seXPrPf937yG2dIawcmzkMceaULfvOPv2fD+w68OTT+z3Ujx6ywf4Pn3Dqur3NUcBmauXhlae84MF/r8983ZFb7mlNcJmcH6uGas65DBuQFKuic+ToURvJcSB7gULC3AiVZckE2RuTUjJR54p81XK7qOsBkw2GSxW5ZBZTXZQ0+8TTN//9v218/pXtfh2cN4iAyMso8syJyu2dmQWzFnOOi5MQY4yc9zQIAmxmilA3w4nuWK/XyxbSHDBJREXpU5Sm7uWXbcs2p3xL0/JXLoohBAockgCAhEiIriqbplnG9i7HXhgIjlBfeSKaUd75HLC8meBWt5Pfk6Io+qEkxHa73Spb+XmXyWjMrCr5aZLtSeQyP2mUCok0SrzLIZSqNkKtmYmkZJr7VBBj5EhGvmBHloTzQJ5knNuNRUYwazrHJn5mx8n/esa2RyaP3LBi3/P3rO2VwsCNVU0pzqMOmQnz2GBU6gkAgNFpJp0BADIsUxySJXKUq6sjZnSEDoiSJhpxgkf9BBpoEhnFRyr/ZNphMcbEZGJJpXCeiHSUzDHqmHP7ki+JkWqMGMxolOA/arRlGVOcUqYagxioYDDpGNYJyvleM+3CM8+0n9vbWjlGdYpRz/3Wk3c//9KdM2nXK9efce2zJ56H609ufvyNGU1ATJ2x8dnZWURoUlqcOGHF7vtcpPbKqcGxw+nwbFmWB1QPbnpJyZPzuAO4dbxKFUn6AZLjbqyHgs1gGIZDF48lCL0hFKle166U3FIrHRq2ulVTzhTztmL1tJf+0oUPf/bZlzx/aaLbsY5gbQxlw9c/+48AIa4tgAdF7ceOdgerm16rV/W69/J3Xms9LVsDU9dvPEDd1GLQRB2kiHVCGxlmzAbZdQbEuUkahV0ULhcgMRKRsvTOudBEypEpioBsIwCzJhgVEhSrmBOhiZGCkLJIdLKqSRt3z5OHhGnhyqu6q0450OggIvRZbIEAgySxSo0LVzrDmGJpHC1ZBE+uH2vnHKnVAC4FGnGxiYjQDMmQjJF12aw8Cs+Jo7spO4xHrh5VZmT2IQRHHEJAg8I5Gk2MMRKagRgYoTOy7AlUSJh3H2xmvKzqyjaL0Bu2W11VtZjQcbvVUjNkl6KqaD7WqBqqqSYrSSWBGKGhmKgCAnp27HIuR84JAh0dg5Ik0BwP6oiRABBQRDPGSRFMrYmh2+7MzMzMHTsmyIjIxDm8KLvmk6qYjnfG+/1+bo41ma+4qYerp9c+cPetD+54qLXz4b2dLpXl4tHZaPH+X0w3P+du3j/RipqwGZY03R4DAC/10VZ7Wl0vHX51a/pUwd02x0yTH/uLdeef9d13vOGtH/jwvR/5nS3rZ+qFWNYymE+LzeKpk5sWXvhCmO5uvuLVzXNLcwuPTx3e++x73nzK3gMPfe2Lz7Nq7sYfrQIATCeX47dd9KYNO28P7al00jndJx8d4AIVVQdx+xXn2SCGkkoFxG5oFgflsFB2zhFYSOnI/OGiqK55zRsvueQF133z2u1PP9ltt1u+CL/fLH18noxgFsyMmGxa9UTVn0vwiSI//AO3pA533XTnJb922ep165zX8Jb194vBP1568x/B7zy858GH7uHuhrGNK/2lJ53wjne+ceXKlUfPfN46F7ngCFwt9NLBx3r3fWewf+/BZ56Th5/o7d/e1QanZ+joscs76wZvfe+fHtu/Z673T6/63U9f908LBm8++5L5zpov7vjzzqqTzlnVrffv4IIfOvNqjs0Fl6yf1XGEQae9AtIiRcfYHQ6HrvCWBAmYGSOqJjCrWh0AFNWiKkREk7RamQkFRui8z9mwmbcLTO12u6kHmjTl5a7acLBUxjDdGTuMCSqqwMWYYklWZ08nmrEu7zYAgBmJRoZ/WVb/jvpUkFz1U4wLaVFERVRAzY3aLxVTjdnqJyJq0ZZXvHmjfPxMVDiPiCgURc0sj6AlRFWFfEDOZO/RA9YQETKwVnX0h4sKmBFWVVVV1eLiYg7tanXax+aImNutioC8d0AYVTw5TBpjtIwF9Q4RmZ2qenZGSXO1EvPLvkkeIVxQM7oYSVERMUkixyoGFnNatjEmFYdxiF5MXbToi73l4JKjJ90/u++R6WPfW7l969GpIsGRogbqtpuei5gcO1fGGM3EzMqyhctOD015/zaCsOY9d9XyWV2OQJybETJkAHUOyQxNNBdOTWpi4DJJGY8vgEejMxEVAYScdukUDBUc5/KffSn5TICOEVEJ2YAVVRUBcyZRWp6QA2FOyU8qiIiAQxLngSsv42N850PSP9Ia25BWtIOkjV95ZMtHzn9kc+ehd2w952tPvvj5gwPPFbufrpjZAHq9nvccY0SC/tTaTfc/lxzjYmOuiLY4CaSunJs5s10fs6LVhonjBbhpxW5iHUJd+nWycPEqt/qEyelqasU0z6zyq2dWTPqyn442Q79jd/jKI8/c8vjBmTPXhHUnvbx8Ir3r1e1F343HzEQ0cqtbD3WIe1JvWCcDhGqxKGqKfRq26tg/EDrmdYyYVXii1XJiHBIgaKhTVkqimhgiKqiIJFN2PovpGZAYSZaVw5LMbFA3KfSKogIzkeSIETVnL4uYAaYYq6piojoGMDZjL2JUi+B8wZcdnK92PdyH2sE4H2zw0C0/Mzb+HX/JI2Oo5AdRWlpUfREIkSGA6/hOAw06hqQakwGGOlbIRVWKRkBgdIX3RCQSATKjmmIUGPmxAcGWtdD57h4ltHNmQJmQAaEjHD1XVNXAiCgDdAlUEZVQ1bIYizFnbSKYiQgYJVJD6IArO+PoXb/fL8tCJUkjjhGK0lx+SZbAECGhGYMpiqFDYMSCuCFJqmgWNUulyAExsjIkRAVpGZkDEWmagI48OWZCM8nBfzEBgSMeDAZ5l6kEpS8Q828BZgIAU42CsTIziakREe9Li0zqmfQr131zvDPFBc5pHO833enpF56weMHapZd9uRj3QAVxYz5IpBIA6jp1yHbPHjvP+D3d9tHFI9PmwML+W27Z8Oo3Trz915YOGH3v39f+w9cPltFWVcNpW3P6xe65h3rHjs387M/G3tHFQ7tXv/xN27Z959Rv/WCFXzUxOT4UHver6v68WWsOw+4NF17+3Y91FkKzd0eEXsKJzuxg9oxNvXMu7xyZawp0laubWKArKE2V47U0wxTIF20uwOzAof2d8c67fvGDzzz+xLf/+2u92WP0DHTeNxFfHupzh1wwP+nwOg7vruXjoQEoP9FmZtRhWaBpuvmm727ZssWd3JndqIYAG/wxAPj2yx7+xMPn/M/2+T3bj1x51slr16zav3tYFUZ1YWvDcx/7ff+dfy1BqhSrBIyuW5Xa7dZ+9QkbTtIrN986c8rHb/767PYHz73oqtmHf/ihwVy1e9cZKzb8v7k9g2b4she+ZsuDdw16u8fXrXnm5Jec+PQtkxdt2T/c1ZBMIg65pFa7m2K7rOq6Jl8gARpooYyUJJRVO4kGSb5wqJZCJOIEFmPMzuDs0QkpChgmVNGqqqQJZA5MGbl0Zcs7XtFtCapIcISMrk5ZXe3Y5SNt9jk4z8SIUZCodD7ByIqjquQ4hQRmddMg4uzCfFVVAOSQUtIMPosxHnfspJSSpHzOjyppBIoBInKesQTvvYrEODLCemHW/PRBAEuSJ0ACajTy5mZSioww9AbGDpEkNMGgVZRVq0REjKksSzMFhFa7lWs/A3p2BqpgKSVXeMoyK6BMO85ncYSs7CUCZHZYMIQ8OedclgAgoXDXk4EjZ5l76JAcK2PLnE8wQA8kJEZMEPGaPac8Nrn01PiBH5zw7LufOqkpuQJVLiSpL7J9hYuilSUsyMTMiKbJMrMhP6MBgExzPIiCgeHxAgyILYej8TXmZl0FFJFIjJiJOR9ZbBkMR0kiqHpnADmUSUgRUZPocgylUdbPjYy/RHn3BRkkYKIZPqyqgIYEgkpgxEiA4J0OC2tzyW7+iSeu+vCHn7rrIb7/hsnWujU1nv7fT9/3WxcdvHDD2te3JmYWr//OagVgRDFtlnpVu0whqq+aznR7dq8OewM93JtaLTGd0AwXLz7LYjLPYzYeLR4vwEgE5rijcqj+vQ+c8rKr1x84tP/I/oOb1py87/B8UdW3PnT7ZDG1YuO6885qv/iyi+7ZfvhPHl016C3NtI6uGi71sCg7kwNmH4Z+rDu3+6lyX22IpAYIkftD7tcOMEG5KON7vbYLaLmqLDiU0CXqtSAgVO2Si6zYzzcCZ3d9jqlhh2pFUeDyaVJEwmAoKeW0Yx3FPtuwGRihxgQ5po0IIZvWzSnUTiuqsOCE0QceMz1U2dylL53e8URoVRNxX7H78NzmU86578vnFrxv66n7127Yu3bjvC/TYK6lfSdDk6hUmJiJJkllVYZURzUYRiqZ0NkyB3N0TY5yeqwoChExQkXIOZRkYBYFFJhd4QBH2QICZiqSj2dGZppHyqww0p4piKlaUjADwwToMfvN2UY+N0MYSPJirNGJOMZkwu2ilgRNyCd+SSnG6AgMkdRBSqqaEHJQtjEBGCVVFs+OGFRTrp2qEsWApECPhGQC5ABIxIQU0GWShEqSGBFRoyJwdkuiCeRbCREBwazyVa/XU4t5iiWGILJ61aobb/n+4b17T5heYTEmHSQSCOG3nze8c5+/6WkpJuoGXQTulK2SKwBIsIStzkumVrx/x0EbLAwBk8YSEW+/kY8cuObPf+/Wd//yqojHnrpneLQ564HHj7z80qW9j9cBTkSMq9fghVsmpkrbMNPtr0vC1O7zHDSOUnO01Yp1CrvOujoV7RMf/1FTDONRR521FQTV2XDly+p+RdhQGMQyrZ4sF48NK5gUjCklMAqN5ilrUbjhsNdbqtdt2vzLv/5bd99+61133j43dzT+F1bfmoQURcTA3F+V4Fz8ozoglh9vOaRo4orWtseevOiCSxwCeAIEKDkBQIX9z5z51el1v79tZ/t973n30aXIhYkPAeqyvQpPPG1VPZw84cTZ1BBwtLiETTO3tHrL6T+47NXXPnz9tu//97Sm1RtPO23rFfD0Y8WPvjTWWXnj2LrPX/tnqzad/PqZNfW1n+xOrrn7RT+7Y9Nl1zz6b2NXfnD23h+2u2NkrbHSfIQasSjLnHkNYDFGR2xmagSI7MqCKiQA0dIXRARRky+BIEqmlSAiKhh6E1FtpNUqdahqAmgizcGnd6zdckr7BF5icGIFe98qIWThVf5y7AuPkIMuXOFTFNL8vC4AIGpMQThr/xBDjMyc0/KKohh59pef7/kBnoVwCGAEJqoKpiPBgvOc62LWGOegDwYEtIyCEBFyzCoxxtQEjYJMAAACTQy5ACOShuS9r6oq3y2QtGq18pAcEMl7Acvmd01iosiAYohYlqWKHX/BkmKGDaDjUYkCZGYgMu+yhDV3MIjoRzs8Mz8awxIYqFVUDgi7KbhI6o2sLmI7jIUzwxkv3L/nupP33LHi0ZfPbVqzOHOUl8hPdMoemPPej9ItmPPSGwwFFZPmAsySBIwByVSEDZUgAQoTMDoEZ0AGQc0IctoAiJoiOOcZlIhGC2zmfI4JkkoBYFBG1YQABAyGSuiRRGSUu5mXGs6ZGakQck4PYSQyk5jyElhFTBQxpzJlLnCCZMlpWfDEkOpde8d/4d2v/suPff2N7zn83S+vg3DG/2xb86ELoq9fdtbc9gfKQwuutbxNbLfb/f6SZ+pPrweA7uw+K8Fd8u7zf/F3Wsfmdt743+Pn9pe+fs9w+oWD+sgGP3O8AB+xYTdV7S4OYFj68o5b7r7/5lusgq8e/WLZaQ8O904544zHn7npvidveeEL3txPsv4FH+aq8+xdd95zeuv9569biAvt4YSDofOuVU0e6Q023IzP9CBzXUMbUhsAcfwgE/KZ3x+r1q6kojfO7WpiRaVxvtXFRWw59JVDZFQjRsmXOgAySUxFUTBgu9USSaNdD8BYqyVqTROhcDElA0EGKnl6bGrQ6w+HQ0SKquw9GlC+PpnZkpn3TatXhK7JgfGxf3rpVRuvfPVCK9TzS65glmSXhKnHnjhp250n3nMfjHXnL77g6c1bDpZra8NFaTpNH5LWKQBTGNbRIN/tLcdZeSTJEAyR8/ykCUMzc0URh0MAEFNfeAXjUaicX1aViXOOmdvtdkopH+byRAuhiKk28mIgYkkTqCFAgcQEkuUIzqkq6nI+NiKqhRAMpCh8IlOA8U4H6uGw3/POAzFospiAEJlAlaIktJSDXXN3Qs4Fdcwj+DcTIJoIAXcc9bUxEEOOhgVxLdmL4VIQ7/3S0hIxlGU5HDQCwcyACdUEDRELdjkHVGISaJwjsWIZsmSmoT+Yv/+mH3RMjg7nk8YipIbTZSvrS9fJq6+FEzedPnHSSdt+dOtUWfU0Tra6AED18Koa3rN0dKFrtS8m5xZLLD1PdpcOLv7W+/dWM1P3Xr9qbLL/t3+Nqm0umsNHVruVra4eCMM1b/6l+dk9zZ3feu6/XrDhoTvd1Fpcmo++5VZQSyaWDi5WZbP/5Bd0Fg6sO/RElRzPdFrTU4e3P95+/webK15a79k+xqsKI8CyEWvKllE/BqemBUKr7eqQEpDHNjcBQBYXBsp2wVVXb7nw/MVDhx9/+IGnH31sAIswogYo/blj8eljDZj5P63QsHQ+Nem/v/Md9xOXRR66oo3ZkVWL9/3rX//bc4cGYW5JC99ODp2mQeD1mxeBoOmlUJfJsdeCOhoX5IStx/qDn1ux8c6rT/raLV+amO2dsmKVu/mGgMDXvPszjz0MoXnda9+2+rYfl+tO/vd1W3c1XXXFFdc877newmB2oVoxYwETIFVYqkdE16qyytdTMSJMovfe52WtIRjCyAYexIECQKGZL2veOREBS8BFKnRpbhFKZENWJCzPe9db2pVflF5FRgK8nBrnmASMGQkBJKljAq6AmaDqVMNmyI5SCnl03MRgaGAYVMB7B6pJSk9gNaCvqirLx6IKEjIyJVAEFkTNh0tMKZAhE6CB956zxBo0FzwAGEVRZnCbSAhNIhLnQqxTkJSSKTogXd6JemQEjSlAno+bRRFyRAZoIEmU1cBQIlOukqySFW1SFEWKAmYxBEbKeXsgWvgiHwicc2iI3uXnCDCrKrFDRNY0MghhPmMs4+tNyblWYQAgVqCHDnhXxHcdufrBqa8cnOAvrN/2f/dfqdhJxuDHOrFIbOjYAxmCEhKiMxJVKE1VNYnLcjNTM+MCGRzA6PLA0U8HAZcDvVU1mTrHAGCWAFgsn4OIAcHQ1EhAPGlIqKBREZELJ3WDkgyRGfPm25Jk0dDocxFloozEQEQsXdIciYuIyOBVzBODWUmuBiAMqeykup5M8Y5f+tmVN9zz8k//y+FHfvO573+l+toPTvqfB9+25ogj+/qjK9YP+gMphcAzDVOfwOoQe1MbAaALYew3/+Xvbvvxvt/6mV94+4e7F5938MnvbubeB1/QBLfm379/8HgBvmTN6v5c/0AgH6EstDkc5mLaWK5cecHU6rHzJ8f8c3t3rX/R6jOe96IjR3YeOtD7xs72Cc3++1PU/mC+GZ9K7aYzwOhD0+r4NOgf0b5c/Jfj37l2qVi07mFUxlYfXYA1z/iLvmj1Wy9BdwtY8F4iSNUYI5VUVlyZmZIRWsF4XP3gyiqLgUMKRDA67YE6IkwjVgg71gRIBOQSijijlhMxMiKAnNZcgLWjGiF7EwyVSK1UROPQ7LcgNRWVb0QGBDhWHLnywieff/bM0cWxJ55af8+D537ve5dNrZg76YzdZ2x9cmpqvqV+wBZqiNJ21SClKfQ1DRsLRFRhiQkiAjqLGByRmfUX++i4ZBfRhhJLQ2Dy7DTF8cmJQ0eOdFotZ1SYq5tgZmiKQKhGXMRayFUpNY5IRdHAiImoZG+qEQMQeWZg1GTArGAiSdAyfizf70VRLi31FaDTrkLMM30WsIGIQ4MYoxgyAbHm0Z0ogpnnximKOSVkVjBFIjBV9cZgwJYcIqdIvrAMBiU1gLIoQpOEOAEaCDEZI4siUVF4SFpLY2jsyYhDLaUnDU1U6VrLu+q58di+7PQV+2fGwGvSwey8DsPHXnVwe2B9+RvXrpl65vPXAeCcD13VXlGuAvgHnpzEdBiWPLVxrNLktNDF+aOtzhrZ9uBEZLV2H2rXnpzQcqjzgEAzfnbv/DTJ7nddZEqrETaLaTktItDtJtNi3h0tetOd0LjJnWe9YsuTPy7CoFYXjy3tqZdO/JOPt1/9vju+9pXpmUkJyVwZUt0MC8RA5rPlMKImNfLOVKM0VKhjlkY9F3NHe+yLlRtOesfFF3//uuu++9//Oj62Ymk4HJ+aWFiYo7+ujCj9cQNI7b/o1imW7fLYkcMODBSgFkzMAOBQHNEvPS8+vHe/WqdsVQEghmimhVh37Sroroc0rFLbzBBsoVmamKnm7/7e1Tq36aJXPFat4xr67SNTgWTp8Q1rVj6wunv/d36wcs2GS2dD3Hbv5IaTdjX98RMuaC/umXntOU/84MHueIcGtXZ91XhAz/44nWN51gqABjbito7UUgqZLwRElvF2ICzkU0opCRJJghDCIISiKvuxATBirjrtg7sPnHnhBYcEG4urWlM9rHtLQ0C0qOYtOSqYC8wORkjOMmJaDDRFAjK1GOpsN2qa2lQFEhnkiFoiane6eTuLy4YcUAMm0mwvMDNzwOwLXgajIlOOdPe+Ot43//SbkE0aKTkRcQ0HCiEEETFFZMppyjmzTslERGIyACV0wDnzOYQQIKpJghFHoZEmv7sGUMfANgrSG6SQOz+PjCkyc+E8GwIzIuYMu7zuAs3m4GJ0gDueUqujw/4y03Dke85ovwkcf/PsWX8zfu+TY/sf6Bw6z87q26GuTEglyICIHggAzBEhO0DN6XhmmiSrvvOhkm3k5spvoCIkMDNric+vQY9/LTcfo2U255JsAOCYkkpeGRyXWTnnlrmukFVoeTxAAJD9xKJ5uFSWpYhIEpdbMufKsoxJsFUkAEUzs0JAqXTDY/0f3b666VH39N51//qD73x17Xt/dstr31K94a0bFx5/1cPv/PPLrr7ziLzh7++rO+PWxKYJJWJEK8Y7Cxs2girM7zr4Z+9/SXfj92d37XzkUSZPa0Jz5LbQe+zMU874+FtXHi/AJ25sv+4PdoUVJ6n3c/PpzLPPuuCqi6ar1vYnF4/VOzavOad90tldSIiG/hV/f28am7MrJg7/eKBvuvqceuFQt7QYBi1PTSLyRe/QgQ7C6h+yMUztZKcESVpDPvP7xZX/MePN6PxTobm5ZN9xZUgAlccMlXUuv5+qOlIgji4ZIsdu+b/mzQUphEz2ZFbL7SbmK2k4HGoSgrxwzyWbmbksqoRmOCKjOKLCUdJoSYFdBUxEzpDUAgIFtYb73VVzV647+sKXjh06PLl928ptD55/zw+3TkzOb9q6e+s5uycm5ro0kFQuDbunTsZdPEApKm7I0BpwxTCFFVgtNY0WjIwAEAELMW8YSpVkwxQIcO/BA2WrSmDIGGMDyFm+QTQy+scYQYXIokgUGy2LzeoYLAlXjogUgICAFLOO2IwRFUDMfFZkejIyD0jiTGpNOJr+MalCk/P7ANOyQhPUwIwKR+IMUcgIjFXZVFAaUDJvZgIKo4NOQEQFKMrKs2vqxaQSl2rLAdLIIkkAyQwElJHJoWAGobrC11JjbNpFSWZFCd/70rWdLRs2Ta6Z8i3XrqBwW2n/8+Rf/9f+Kx676/bntu8oGHynlOQFyirDLmd3DFptwMaWhtPzjp0OahzDtnXY25gYallh21mIcTAPVKtUxVwoisJcsaouxXFoeWCqQmgAKwYfWtI7NtkaNokW3NSRtVu3/ujPD288zW1ax696/7lveRXX5c3XfcmVhYjAyNDFCE6BU1RVQAJWQBAENoMEYIhNqgt2HecXQxKEJsnT23dedcVVEgbf+dZXJifHpI5MFTLETwBDkf64rh2Vn+jEGBnR5d5X1UxHfCt2BOzn5/rsIbaKoih8WZgZBi1Wrp5r0cyqdv9obUsDiL5DYzCoq3HqHer3qslds8+iDNesPmvat3RucOSFb/iHm3+YYvORN/zypm9/ad4PxU+tp9Xb11/46rX1E3c8vG92e3dl0XYt1yxyNRa8FTSKP+Qsx+dRGUYbBTvCTwUpKAK5UQFWVeHIkZkFY1SyynEAgyjknSX1VTm/tNh/7N71M1Vr/Tkk7WGZ2gFLLMVURMwZAiNmsh8AkRkwc5MiM4OM4h0ASBVALH9AGqP3rihGrWS0BAIjD4waMCqYy0kQBplTIgBkTAiMBN4zOcfeEReuAETvfDJ1PouBwTK0L+tsNVbVCPMQQhAdlZPMtLdlKLYRGqEhCIJk0pCaJTFVQcyFIUga5ch7BkMqXErJAJJKTJGNEYFSSpyKjCPMGzgCB5jfIgAgwECjwpaph2aGyyFZo18gyKicARk0VXp774obDu98bPXcv0889K/9Uw3H0aoCU7ZbOkNENEdITJIzeFVVJQfpKx3XT432wTDqfQuzZJoPPWTLnfjyF45MRaM8DVuO7cWUlrP+/eioxy6/i5koh4iy7OUgIiUj772MlHSF86paYoEIGZNsZnk5gmgCVtf1KuqecM7lO+/deaA5staOTbTWTC0NDn7y7/Z98i9DNfG+39wwNz7xsTM2nVVN7/zsw5tjHFiIBXKgBvHWpcMHqPRLh5dmd5dJt0w36wu38vDezw6r00494XWvfevv/9E/Tb3+U5ev6B8vwIObZg/5qS40BaRuAe3Cf+u7dx/Ytffi7/7mtS/rnz72onfNHLk3XDXdXXH7ruqR6Q//8gWxfaAzXNh/89OH33BWMzvbdFvdZrAEUAnw8Oghp3DsbIkte/GHcdVTBY3Z6gMT7GOr33cXXCwnr7NH1XmHTCSo+Yb1Hj3lZYqNJL6wvExFYiYenZ+QiA2IWZeteiIiqESkSKpaKNryLub4B1ewE4IcTYqIYOqQcl6VMoKnAlkQAK1EVgRWs4Idx1azGKMdGav2vuAF7nkXrDqysPbx7esfe/CcB2++sL1ifsOZD5x9ypF1K585sCDTbrIxiMG5UpFCFC9uAZIHFAGHiL5A4iwBoKQgI9BWt2o1IULJdV175wxEc0JNTujPpEugbNvJl6YmyfrHwvs8uUUUG8k/R8wPReWkYJCQCK0UBAXzBIDsnVMwwqSC2e4LSORSEiJ0mMnHWBQeEUdDIkKzrKAgUUuizqGJqSIxonPErKpqOhg2YLUvi0KVGc0wpVSgzwGTlP9GjlA5CyWyJRqMXdHCgopO9ci9d+z43o/bN1W7iAdhkFTY8Dtvs8cn4K8/d4fFwo2NuWEyDmWV+sOFU0/Y5NAef/VLZ7753ydW44uFX3DaHg6dJYJqOH8ExZWdLrdYmwR1BHKhmC6qsr/UECuB+IqqotVvEgxmNapQqBUb8nXheP1Z3XMuefbcN4LZFX/0B5NnbMJubb3iwD9/6sD133Pv+wD0DyiyqpJqWZaqNBioKimIQ2QEshFeNgeVOCTHrtf02bFDNLGi6sz2Bhde/pK5udn77ry5KktPPIx1VbbSnzZjneml35k1Nf5jXxXlqAC3PeQHvgIi0OGZF0zPrK7r0K+HzXDoPTviirVYsTKsPNGevruADpcqaHUhdQ/KOEgEQjrbLIiVZ245fcUNn5k48+xPTpbbbr5vZuOWk8bG09wz43H86d23bHnBhx4fW9Ed3/fE7fecfdoJh5Ol1phiRNC2FkLKlGXwucYCMQERA2J24hDCyNZmDtFQ0QiyyNBZLgyiWnI17PV9VYbQz31PTMF5PuW8S8547VtuePCpsRJDrxm6gBoJSJkRuTDEpNGhIXnIxkDTmHLrI2YipghJLCd5jHfaSWKoG1V1zjO7qIoshJAkpSSUU7QYPDEgjGqeEtLyuRfNOOecjzrItJywcfw7RITo89pSUhi1m6P7CpCJzBhZQZMlIjIGIpczrbJSM/dvx/vUrEG1JAJZFDN6LQrmFCQpAaHLDwsQgkhWGOTQiZErIzt8lv+VUWTLBTjrWkf+Xcss1eVNB2hdTIz92uCaDy5+9fEV+/6nefzt/pJjoUFiR8jLBVgZAQlNjQEMnRItE3LymxPzdhtg5Js0AASPrtaEyzC70Qkmj8TFEDFLnUffoVE8DQBkKCwAaJJsy0YmWxbgJBn9UGZWMgbkikUkpZSnMscWKyKq2q12qy0ijkdONo84tWbN8OCx3vbnrvnnP9j+9l+4/f+8v3XXzYHjWFGN8czaU/tr/UPf3fy79XD3gfM3P3fJ9Ck3HUTPPhhDOdviiUF5eHqjzO3ZpjoGuGvf7ilLT+29f+9L/+7wNz/+87/y9recv+ML9/zP7Re96ngBDvMHqja5fnIJqyl32/e+cdMT+9pj686YOvk9L/ztgwee8MPPD3bclk5+x52T72wdvHf+iQOTq05vdeIX7hsszffecn776Ox8qyRJYTCoB0fmJqh64uKGImy8r2gHx8e4hJCqFlHdvvTSvgAYRGe1iiPHBmC27NCWtHwBAxIgmKnLEwgAQSEDILTcFzOPpicAGXFPAJLdsSPOAaEbucK855xJy469Y0sSY2zqYAZYMLMDwwSKBA7JATQowLqUUgsK7lZd5fH5MCA6sGLs4DWXPvKCC2b2zZ+0/+CKx+995RdvoOnVz56xdfaUcw5sWDNnxYIm9qkaDkxBfGvo/HSMS63gJIAUoaw6sahNPZKqKoImm56YbppGLKmqjcgmyEgiYslExFQQOFvdEZCZkcgAgqTMmtafBKETAZgoieTDbiuqkcWSFK0UM9OMbzIlDWogZopIMSXnHJipJuccACiId17MCgQEEMBEoIaGRsKCokkQkcgfNxwiYOELSaEe9LxnA/CuEPEEzAi5CNlyiwQATNgqy+GwsSRRNAVpTbbvvfP21WMTQ9eeGhvH3tJA6kvWwstPPfwbd2wYm7bQG0BoxLcQCxRphbpbjRnBlf/7y/te+YMn/uQDG57bt8J1BmMVROqHUCnWSMk8DiHUDUIqyRVDhXq+TCgy7ANFEujPgmuVJ50+OOEEPKGaOuOFnUteOXbiZllD1Ek//rFbN29Szx649s6l+36k37+xmN+1/v2/9vAQCBQERCIqAYvEgAImoqRmZKPhBBLm2C9D9Cmlqt1qhrVHBwgJbKjKST74y//731xx0w3XTUxMFMp1f+ichT8WP2zFPxwmjXikchmdfDx7xYDr1rp94y9FhaJw3BpnkVqiJhg2A00tbK8GgTjeng1LYyqYtAOduDC/aWrTD321FPslFOvXnuv3HG3OvGT3oV1rN6x/4wtfVdz2owO9fnXhJSve/s4jF7/fP1Hf953Pv+OSM56s54rxlX6wWHU7DJLcEK0ws9GLwuUpNObmDmQZA6IIuQDkkpIvFyJCBlVlJzHEoigkNZ12S5uhQELEdtW676ufb/Y8O/P6d9eDhkokgGR4/CoadVcCiAZopJBCMjNJKd/5QZKCKRAQEtDSoG+g7ary3kvSJEIFqyoYxJAULK9yRQSS4LKA2S1Dg80squTf4NmJJHLLEolgudU8Xi0gA9xyO0bg3KiaEhEQMpKCeWURG2EBycRk1KuiAZrlHC9EYyABA8wDVVULolEFADiLN3PMo41SLEA0rwGyzjzX4CzvKgCPHxSOX0iIKKgIo5mby2vanMme/FFvLxjb9LL5s68bv//z3bte1Jy1otXpSxIEx+wMzbLwGI1G4jjOgpvl1AIBKzQnOkAehORnOiJ2koPlncVPF2Dzo1/TTwehqPKIw5hG9uKU8oPyODGG8/bX0DTTaTBKQsSyLLMZGgBcWRBRq2qVrcrMMunBSueqsqH+kS9/+tC3f7D/G287/dd/9+03fvfZ+7bv+PpX9bZrp+udV1wdDu+H4UF/2gVn7V849NQvXXHpzd+ksfEwaJ6qFxf70iVPU+un5vevUGIKWrTn02B+1aXHNl1R3Dy75+DRVRu3bNn1H/sPbjxegHFmozNJLXLz1E7uTe96zztQa8G6eM/iwXTOhlcd7P/i868Z/69tKHv4U79wsc4fLaTeNJOeSuGhhfZb0SSlvmGboNdbxKCNuv2X12seYKrRHLfKDoemLeVw3YrqvHPSwhwAhNAEaYCdxKhmsWmihdGUIvuACXMgHwQ1BDHRUfAEgqiq2jJh2syy/dzMTJX9iEU/kkaP5hlQeCLn80egqKZQx+QKj4iVgBEQgCAoIUcTUw5SFWXLOJo0MPQleOROMphPwXcOr+wc2bJ5zZtePbj1nlO3P7PuwfvX3Xnj+bzi6AXn7Tzz9AMrZ4YrV8wvLLEBxMEsUpVcLNmBdaSJFRbiQ2NYFBICeZrvL0xOTvt2tbi4WBAhj1i5ZiYgo2svjZz0ZqI6oi0hoGre9qBIylc+AIhIBPEREHHoEwN3DM0gkTkxRGMEZARHSiACiNgkCyEUntGxxOQ8eV+ElApuIxCCEQpCMotmgiQqo5EbqmlUIyEiYpdiQE0rV84sLS2iYxs9fjAZstho1aWj5E1PrkwwJOOqCE3qjrWPPPvcnh3PtsarJtWzszWqlaT/6/ylnQvun2+ba5pUOY4+enOmXtvdodSnnHPhLrSDe56dOOuilV+8+5n/+Ntjn/unsfnQNat8ReQrNG5qjI3D4RCl1wAjOF8sdleGtasnzrvEbbpw7NSt1fpTcP2GlSuKqrCwkBZ3zM7e8o3B7T+K2/c+9fYvnHnPfy5+7TcrcdPGM9brbT3n4Qsvj73draIlAqhmZIOlnqp6XyZNmIHjIJi3G0gOANE1aoVzOkwFMpUcRVITKlcmkfsf3PaK1715duHwtgfuqorWqaecrAw7t+9wH2dMbB9Lw/09h4SKRTJohAAg+ak7z/vntowNC1JpwNg512LCkqVpXKsMZ540+8iwo4MxqjJuuVc41aK3YnKuO3lgfl97ywkrPQ9n5+Tgk+8ZX7fqshdNllNHXrX6wk99Cs9atfvxQ/9z07H62ft/5fJLn7t/W/W8c2HQlzGqA3SxwpiwIDKwZdwbHU+uwPzcPJ7SBqNWGDnDPo0MGNRguT+z/D+HEFxG2xotLCyed82bXvjBn7vxx/dNjLsYqWoXZAbhJ42XmXnJNDmrSctM9/7pYSahSuJROhIw+5BEDIqiEENrIiIyYDLVHM2QhNCSGbsR4C//pUxRLIP0LMsmzYwRQMQILS2XNABb3lxmRbSYoo4G0cf70dxtKnhNkpLko4mS8WC0Nc/Dulx7PLGmlPM9RGTUYWSPcp5g57xGBROFkEwsaZ7fAgMoYoaPjTLocLSVBxjVTsRlsByO9N60HFAVfVFavw/F/3JX3Xzsof3js58NP/5D9/YAg+zmz9EWZgZgjKA5F0Uz7zFPwtktryFgOXDj+DManTvei//kUlmuu/aTYMsRWKIAR0TkR55sL8vpRUy0PDVd3qLlmi15IwMAfrlLblUVE/uq8FVZsIOkZhZVsSqOPvBk+OEdDvvwlc/c/bXPPvKyt2/++de8/sKdY2dU8fDEmByci7z56U+/ZN+f/cvqg0uXrt15+sTpe+P+Gbf/UJhMbt7CYHp959HvFeNlq5xujiw40KfXnL9u7cHnv/vlN91w48tf9qrzT556+sd/ffwv2776N1J3mtSSiz/Ytu979z+0awcdbtxSb75vRYganKzurMTzLpk8+OSf/P2x0zdNTMPS4Z6bXDGzf/euZ3cN152wcmEQABAlYRMSwYEr9LRv+cIxJChnihQY5hbLV17TrF1pB48aAKbUBqwtiURA0OXVo5mBgqAYjSz1kDTrCoFQj0fomCFx9m2xI9CcVvZTQyA/Cqai5UAeQMuifQBAdlygqRo70kTJIovly5OARAEgAZYh1hSEyAdwCROAJ682bMVBBGmOHdl7cJ8/cf19m9c//crnt57cs7lUd913L7zzDj82eXTLabvOOfPIzIrZzsQc1hZjp588FFyUyASinTYljSIIBih69MAh8o4cE5GNkgDARCjHz/kiSF15772PMQ5DY6iOuCh8XSczcarMCAhqSQEUDBM0CGDmghpj45KZuWBxeayFBrkME3kiauLQLZ9ZkcEQkyoROTPBqIRoSmIsaEbmyKuZjmDoZjnm3MikcARQDPo955xAznylEJIBkZixLZ+ERyfgkCITQLKQ4opu565HHhYRdYVPAA5DjFun9fVb4q/+aFINy7F2vxmYVBU4K2Rcao1Ujq/lAJ3K6AANKn/SB/6YXvOLB2786pHHbiueeIgOHQ1NFCRuj/uZTbhmA208tdq4gc++cuXZV3TWuIoHNbT786D7nzv2wy+m7U/CY3uHD9+++tQ1S6vW9RZ7B07b2rQmz7j7q2vGVixIbCc61ODBt/5CfwBjMkMcEvuoETWrUTXFUSYfjtaHCmAC5pEY0AGIJF8VZlIPhr4siqIIoSnQuxIXBoOffd+vfq1o33Xnj3v9hdnFpl1VZVHIsWpx35ytM9drnzxfrJub35EmNgPAtvP/o01lqw0WTC3GYVRicsyMCWMpYCedTpHHpnkhSukLNKtVW0pwYP+5BfzWCeduPGlt+9Bj869+xaoLXnj2qWs6qzamYuqkFfH2W554+DNf+Oev//vWP37kjS84894//aXOz77NmgYr6XQ6/V4aJJ3sViqjfjcLN2yZ6qWOIBtNEClPNQEMISOGEMABGwIy5OUcMKXQzMzMHA2HmlBLjJXZxMTE4v7n7vnHf1nx0pf0Fxcm2qUBFOjZlIk9sRJmk4OZJtOkwuZDCFx4QIx1cM4BsYiACiOqoRmycwgoQZhRTAFAAMQ0ZbyBAbFz5MFMMj9EzVSTWDLwZDEkIVUxdsRplIKZM6WPrx5zBJjl0/LoPWFC/GlhWm4dhRJBMjMg0NwJGCAQOZ9fORkgIhWouqyJcQ4Rk+lokI8FLEdVi0htofQ+mhagZsrMDrwDAMeEqNkxBKNOW0ZHJGOkEVYRkfJMGE0BnNYCrVmsN1Vr3t6/9LPdm69rPfPi/raL/RYRFVQEVAQBoJx5tNywLjdMo4oblwksPBoUABiYYixyeOfyAWCZ4pBNimCWJdD5L0iqZIAEaDwq2A4AgFSPN9zHo8FMAQEajd57RMwFJteDVqoQkYjLsvSQVaVqYKp46kuuWf/j2x/+1KfnH7l95tDOwQ3/uWn6P0OXBjNjU9VSEFKzdZtnX/O1j37uYx96qlj0b99S/b/b5xNNtMdk46rhtl1xcv3Y4jGisV6n0z8yO+PwMLmXrTv6Tjv/2/d/9h927f/83/3FQL94vAB/78ZPlhd8CFudzuqpT3zzGAhxVUgbO64b0ziNl1AfGtt8Ovb6D993AP3CN+85VpQmq1dX/Tkpq2989/pP/P77Fncd6XQmm8Uj9eEDfGJa3KRrb3MRUknYm52jokjTU6e8/rV9IFe2mKhqlaVvJZQSKiJstzqFrwD+/3dxvpgdIlqe+efzbL4gFUacBkIAgJHajtATJxvlgOb3PC8dyJWGiMSWSRiQ6bxBCWoDiNSwRYtegAQVwSQkoGhQJjSjvkfR2AXSVttFDQlb5YRi7WOvXqqXqNi78QTprozv3fjkod2rHtu24ZFt59x7u67sxFPOfGrrlsMnbT0y0VkMi+NQU6vk6IoQCKxTVk3TOHLdsZYrq8FwOLoHltci2XOo0LSKkomYAAom38rbEInR0FJSM2MokE1HTiSIphmE3iCgCg6RDAIhkTM1yCKY5aWJqlaOk4pjBzTaVXlmVRVoYAT3JTAiI08kCGrDXH3zgT//gSbKVWFJ2HlVJeQYo6owYAJQRgCDmIXXBmBBUsPkia1pGAlSfGbn04kVsmjUrK7rj74Q9yzxf20fq7q4sLBQFh0HmBgQ3QHpv/aFL2uNz7gjwkU51LlqWMjuWWu1Ou/4rRPgN7A+sNRfIKF21SnHxnB8GrsOnXjipYNNb9fTw+8+EB+4Xg4801ba++jj4/2eh7R25fqFN/3sJx977ND+w3sGR1dseOWqNMSrti7+663V1Io69ekjv3dk9erxYWLfREPiwgHEJhWtiiDOLwSuCjJCyFAnZMsSQQWikqEv0hiAmif2iuY4OYUoBBgaPXx08Z0/96Fket89t09MTFbVOKgNXrcEhxFWmMM6Hbj6z772tW2rTj4DBgA0Ttjrh6Jb+KnJ1Y44NFDXTRNDrwlFPzTrNpNx/+jBlGCA3pw3x0srW4MLrqpmOi/5lV91W68oTixKX/Z68MyjTw4f3LHq5BWXnX7mhZedf8naKze/+j2MduKn/l/3yvOXTjqp3HdooUXtoxFLZKJ+LxTOk2MkyroqJCjIETH81Fd+EOeT12icaGCYjSCjCQkiItPhI0fQzDmnnIpWdWx2/tJNZ2084+Sds4vjbfZcRJXkyJDIEyM5Q0NQB2IqoihWa1A0BMsLEu9cEwJBDqoxYgcAKWreUxOiR44xNinmNC5E9K4oXZFiBKXlPs5MMUf+pyAmAZmIQlmWAHF0bnVOVQGUAInIp8TMYJZ1uYCEsHxjE+XGH2CUUpmlQAqqGvNcOCs7bEQyJgQAzzmY15U5zsZY0XkmASM2gGQqYMEkmSkQqqJQfjqyMJCRARsFVLblSQXkaHrLdREyWgjzP6hoAiYOnAhjsQ+PfIhffMvck0/O9P8mXP9fcAZCNAXlfKLPojNLWdwCuNzoj+bQfFx0DaZm+QeBQ8pxh7astwKgvFd0RABqiiNqw+iLmQHN4YgNQMvB3QbAiJn07kadQ1Yk+BhjHkGLCKoxkkNGzGz5SlIyIvTF1PRUOda2Ggay/lWf/vjd3/qfpb/92svWP7Zy6tGykJIXwIDIjU/LYBEuag//6DOPHdq6accbX3/rx246a1hJHf22PeXYKq26NNifFg/KIs0Azq+7lDdfuGv29E/tLadf91nZ8fd/9g//MDf3ExoSD47K/v+u117dOgxrpjvDbkFBDMGsWtcOzY571p16cjMxsff+uyZXjiUtdDpF9V7iOCBNrHvgth1PPfbAKWddubSQ5mefluHs4YsaAFh7B0mKHmoHk6E/t/qVL5s483TZuaeqKkKkVgnOVa5sYxsBi6Koup2shyew5bgYMzNkIEDHnAcMCuSAXFGIKo0iP0HBQEXNIEmBbDFgluDldBMAVEvEMYkZmJpJijESqII1hmKpVB6SBollLQnQgCpvwCzRokGkhh23GrWqiIiBrUXGEpZQe+RdWbqQpvsyN7+rqMq5dSceO/X0PS/vrXp2V/vRR9c/9cR5t94VZjqDc87dd+YF+09Y7/s+YdMwCqKCUeHRjL0fNE0iYDMQy3iQ4+sbQCwrD2puFIJrYj85MvqiyBckAnnPCaCuawBIhIBIBiYaUYig4sJX7RhjSkFUEVkBRExVWjR6RDAROIdmJkqICb0H8IYKElHVmQN1gLUiOBqdTc1yAC0ihihVUUqMTEWQROQ8oQkkiQmMVUE05vGEQVRRoJSapIm9015/MDdXjVUgqSRQsC1r4NUnLf7Gj9tzS0tVUTpTTE0o0DGP+8neoQOnb11XF569xujHy05PekkLP0ydHbuGZRXVleVaKqp68WB/+8O02DSLu3t7HuLDC3r/7RNpOHb+C7f5sj9zemqNXXbRZfEL/zK96axbrnnpxz71ydNmZn77je/9qx99RU+4pHn21gkLAO3e4mz3537t4NUv99vuCq1uqW3yIYmiIyQHGIuyssUIZJYAwRygZ0fIYipgajaUOptX0bmgQc0gJDIEMq9lUjTS3QcOv+M9H+z3hs88/UDQbtMfyGRDLbIETvfuevBXf+WUX/jtVSecCM9AsOSTTrRa+/Y/duP19z67+9FzTnveaadvHZ8+dW17Y7lGu/1THn/160Ub6k6215+ezjlzet1WXrVy7SljCWBu33DHA49t++E2G7o7v/+lW+/9/nt/7iOdBze32sX/+t3/O1FtnH9qrL/91u5z28d+5y8P7d+GHS4ihjKntlcM0SE4ZiZis5CEySkgGHgwAkMCcKhoAOAMTFWJGVBECBGYVcUQyLFrMJphBhapEaEDGOu2H77+i9K8avKCi4Yywt14IcBcMFQVl10rAkny6heYhsNGDKt269hwCBYLdhAzgokNs5QRk2lokvMYUjTDZKNTb8GgFhMLM4DkiB+utQFyKaUoseKCRCEoGimYr8qkgnWdNRRR1TkHzHFZ5kDECAyE4DRhGsUrMhCyZV4jKuSkYkE1yRghBgMEJhJLVHiNWhRFztNoUvSuEFMAFlYCkib43BarRNMQtI0ugpEnAEBwHknFEBSYyJAFzExGSRaI+afbaLMOy2nJDpACB9+gVUnTRNX55f6LfmN47ROd/n/07vn58ryDjfOaEAeCRUFFrWqYyAgQUo60ygcsYpaRsyhLsH6yh87tFI0kfHk8goSigZGIR9Ls0cOOTHDU4GYjVjYbiKozJ2CZrwiIkrPswZwhISNQpsaNnM8eDJWpE21YmCu6U/35w4//8b9wAdDZsOl1r7/tG1+58W++fMZr3jnlb28j+paC4HCRwXPZtvaKVj/wa3og1W/s6Zf3/tHMgX/6w7hn11DcYHIFAODhp+ax1WbYc8X7jlz9ERw/cSlGmVgFF59ebTn/gU9fw/3h8QKsXZ3a8/XkZqTT7g+SSleQCle2+9tX293vefc1n6tfvDXtSA99cWHLy2ZpDAbWKWONcsThGotpqf6rv/jE57/1cocUDuxRsEOXubFdMtmvHDaxO+lXt9M+Wf3Sd87Xfd9u+5oAscOtdqtjZse8JyLf9h3HgGwI2YeaZxKIBgnNzPlKVWnZYwYA3kAoG7/QJXWSxFQcQcI2VVmvpKqS5b6oKIFUUW0YGsgCYAMMsazaSeoGtYwKTUhigN5QyZVIruMp1rGwwiX0BYHCGKprt4eLvUCEil10A40AJs7QV7WZ7w+oVy+ozG3cKFtO3dY0m/ccW7/jcf/UAyvuuOfgSSfe/ZrzqzNOWlevmB6UYQgAEKt0NPba7AxYg1UFBY2ohuSSQqca6zchNjW1OuiKMiSU1JBYUUiToktOgZUETMmaWKsAIgubgBUC5rlIgAUXqp3xznBYqwl5cuwG9VCTMCKoDhCI2CUa9gIzu9KRQwXRZtBaMSODOgVFTxhiRVWM0dCc42QaVTygFxSDxOiQ8olTQFzeA5oBileVkCIgOtYmUIsA0IIZDgNqq+iMOe31Fxb6sy3rxnakSADyvy7rHerjt/aumOjE+fn5qakp4hSWxLSqhwurNpxK1//oYPVDf9rz1EudBmOu1Q91IrGWY00tR8OlwaoTV227/p/9X/3v6Wq11UdWMjjRVZde9YNLLv3PH90kLh3atzctzF351ne97aqr5ybW/N1//Qf059/42ldWs/v6Vs1suuSkg9/ofu3GAQ7c5nPCxVfs3XbnWGt8qqxmQ2gJGUUg9gVr0GZJO52xGrTlYgJS54cSWyyQhIhFlQmSYAVtFQGCQOoT+MjROS1Tu5aG2Sfghx/5s1O23jOInzm8O7iWWwjSHsV3u97RAydeeM7OJxoA4IlOszggTTDwX7728weeueOHrX876ZQrr3nT+07YvO7JL9/+kpe/6Ox/unamY9yhhbnaFp1IGPb5r37nL5687wdrNm256+77juy455d/56MTM9NnrL/wnR/81bnB7jdefcvhm6+bu/Z3n/ntO98wsb36zY8+s+uJiXbsG7CqNXVBnv2QVEW4aZrcxuWlKRhQTqUyNAWSTEI//rwFI0TF493wqMP0yImgSQVyZE0ERLQ4O/viX/7AyqkTds83BXmLQ+cLgALNoqSEgsgCJjkaCgyYJIFFVDADWpofMJpzZTOIhaMYo4CQW55eqqlqPwobFeh97rcYRKTOx/ckZVnWdS0hIYKkVFVVhTwcDvMOMpiQQRzU3nszUJFoqmBRzEPmloA4ZDJGyCIlW9YTgYGpwvK2WmTkj8TlJXqQ5ImBqFONpRSo8KrKTKraKkpTUCRV8VnyVvggKYfgkSqaRlIHXNehqipUizFWrVJNwHAUlf+TDyQzi/CnimL+LqgZsapwK/ZLP3EA5l7UPeOquZOvX7f7m3Dzq8OZLWirV21KdTSMkZ3m4SUAUG66M0oBRiGfOloD/9RHf/zSgJFIL5/N0cgAARDV8PgKwyCLvEwhbwfyqyVEsIxTBcj7kOOtvJpQVl+LQzTHMW+JjNAAbVxhmIp45z99pv7831Q0Vmr/6L9+9Oi6l77rE3+2ZrwbHxvX2f2IIBHMjaWpaSf7BbDnZw6u3/zDJ/c4V0xvvmbyYxfWn/uLM5b+a+H5Z/wVwG+/+NnZU/vfO3LJ9sveI750nvvK9dhaGjblik0nvenTe7+4rII2szg+Z4oHH42zM3DZuYX1rOjFV9xwdMtNNjP8x8de6fYtvfmq+dmb1hyY9bpSfYclFF1RI90f68q7hx996jc+9KH/+M+vV348QDh4Oay5q+AgjZH3fGD2yNZ3/9zkC85ePHa01e4UWhCSK3xRFADgpUCkoizLssqTCMlDkVyAVahwZgaGI6w1gYARESbNdjUzQ2cmLqkkU3SmqhJTVhhQ1sIki2gEYKolu5gSGiQ1Y04pio4MS2KmoIRC6Ia9YX6q5JtCFRWImVWgGIaas9tMl1KDItGElJgZQJXQEFDZR8W6b0O7d/2a7aedPP6SqztP7T6w58lt+PT9q5/srj7xzHr1yXOrNu8fX71QdXVCQJZcYtS+1s5IzEsApxE6uGqsCo2gKafGHDfeB2GVxpOtMLcE0vfYQlcZ1JaMUM1AhJCYHZg655iYifI9XlVVjFGBPBfkKaUUm8ZxkVISiOpEyUTV1Ilpt6xs0MQYhcFE0buhqaA6VygYiFaGSNQ4A7VKiQizIBYAEpho9uInS6oAhpSFkfVgYKYqamwmNggDN9FeWloaDocrJlfUaWgJTmjVbzu9/v1bWiECEaUYRSTUwF32rrswf3RqbPW5Wy7avbAUH3+wPbNp4OxYGk60Wm7QRNPoMIFyVQvOa0mVc9Nla6m1gerD7uIrPnfqBf/+qb951RWXvv+l7/joNz779MO9uccfpRdc9v2HHunt2X3y6WetbY89srCw6DeuIH7DQ98bf252bsPJJ37p6w8/eWhybikaD+sE5SzaKs5zMjIjM48I5gXIO0xqJlnvYphVImDU4tgs6iKyq4S9UKCIHVw13j28f6ku4/jSwvjRQ6uP7PLP7X/NlplXrRh7z6NPPn17RW9obE6diKYztqbJsWe+/tfw4j+TR+5bf+Ulexfl/CtPPf2U0/fsfHB61abLr7li64bV3/zqZ7/zrf+6/bYfXXvt9Tf96OZbfvhdrZceeuy2hdlDn/jE177wmT+sQ/8z7/u1w/sOvPJVf3zNe9/ysjS9trfw7K0397/3Tffj7weMiz//5+rLdRtX7H7u2bGt61tyaHFADoGZYkDzidmTLQPnHWepbRbi5gyI0fNRLYNxAExBcQSkHIE5bVkwiSNtEtKyqBIADt326NoXn2RWU6kxeiTzECwvkRAQQXPMwuhnQZTAzDEEEyUiRGeaiIGIokaJQjYK/TdRM4sARCich0viyBMh5/QlMuecY59iDYgppUK1ZmvIKgTOf83SB9PkzCmaKIiiqoEk1kgopmzsSD0ZGxJxNggCABllQK+oimiQpCaAI4WL5NgOQw2SUmq1SjAkYqIRmy+psIEjFkliyZBSSg6cApioI0wKdV0XpZcQEzvnXIxN5lahLdtmLSvjIAOjYLTHtWwmyZ9dH6RNhWgSB67Ggedfp1fcufQvO7rHPrnw/Y+5Nx+IgwpbpMNE6IGXObw/UeoTjER6x/EUWRqyXHWX6+9Pxsx5B0wwYurkYjr6M83U6PjYDQEABRBy6C/89BkCEQFNCDN+GRjVRqQBcIwIlsT52TK6+mhzxrs/sPKt1zT3PLLjG994cOXzr3zz+w5i8aNbHn2+W7+p09uMe8sycH+O6yEWBK412ak2n7P1mvWbDu4m5iVqr7j4V6dat3aub69li1PjMr554ufPPmp8762dnyNEAyEEKCtUcidfxidek1/ncM9DCIOIJ1xxxuIlL37qb/7uvnDRNe5PPxdXLrAu2fxF/NzLFy76zY9O/mhLvyzaJ8/RxmqIkZcWx7Esm4ndC7OHHnQ0NjHeLWZoz7MPlW0+coGc/V8ppTDt2nGhf0LRXvf6t6rEsvRVYF8WSOi9L4oCEYtUIGHhi7JsKZgp8PKVAD+d4gIgiXN2hMtTjWWZupnl2XUEZREUNbPk0igAVYVURQGTEZGRpShBNGcxqmrSCACqYAbOFWYGKsyWKZb5fUNGBUuqQaXFZTLzSoaqSSlGMysQUYFVFU0J0bOpiqjGJGVaPZsWeguI1px6YvucM95Z1xftmnss7nj4xIN3r97VOaN9er3xefvXrdtTzRwrWT3bILqwCP02FQ17Px/qSlG64k1JvSSHkNjQE0FREoWmiaoBg4A5xJKoNkEjAvQFa6NYMqokBKtrpGLQr51zDGBIYhajsCtiP6YUpqbH+mkphdRutyFJ6YpIUBRukIaucNqPZVkOYtMuKo0pMRoDJEVRRFOghOhNzLKWEnNsteT0GbP8/SwElZSHYDFZIkQxQ18szi9EUa6c6yMC/Obz6sVINy5sOXjwyaIoyqo1NzeP1PaKM2PNNK7dtOVc2Ptgvf5Nk2vXdk5a29v5XCGw2CxyqyzQOzVWESi0divXnkIJNB1KaIStJ8875/Of+8cVJ5z0inPPOfjEvb0jEECff/ppncXmsAZQPWFmxQm24m/vvXHy6t+ZGuyvb739P1evfdNHPiq8YW7/LVU3cYKGJ8dlhZVEAv8fXf8dZtdV3ovj7/uutXY5bfqMumRJtuTeOxjbdAyEGiAJkAAhjdzccJObcpOQQAK5JJSEhCTAvQmBAAESWqg2BhuMe5XcZHVpNBpNn9P23mu97/v7Y52RxX2+v/P4kY80Z/Y5e++z1ts+RaOogB1cUyscRK0zqASkeZ73+/2yqgiMD5A5a30JGgKCZXCipQ2LK8upsa7dHz96aNv0HGgfbTK7WDRVPn7u9o988+Q3rz+ECDYAjF50xcZsKj05DQC99/33YxP15B2/s3j1jbe89dfVzDcbm37ld//o6J75u+6+26OfGhv/yYPfePcvvUqcvOqmN49NnnXTc9+oyfBzXvb8V73hD86/7OI/Hnfj6YbH//QD+PgjM4eOtboLQ7ZenrOj2rdv382/NFEUzen9fO4lWkkPbCOtB65EVRJiiwxgVcmYSPhjFQOEuFbnre2GIjJQ0FRVRIWou6SifPoFXFRFVXpU9oEALUMIYWhiLPf+8bt/vO3mm062F1rWFogVGQCN81rWIACKcQfQ+EbsK4NAFrM0K8uSRUKQPE/FD2QRZYCzRRU1HpkCM3tHiGgRjIABNYklIl8FihaEzKjQ63QFNCEjAJ5AQBJVgwSeCaCKEv8qIkIqFklFSicBQqDgnEsMaGAWFOWILBWRCLnkykfoSvAMCqWvNNWiKM7ddU5ntd3pdJI02j9wLB+dc2VZMjMmBirRwFaAglTeVxzQkCUWMS6xp4EkqmTMGjwKADASgEEwotjij3CNYDEoXg2BBsY8C75nrVuu+jtqZ7+puOQTzb3/2Xj41b3dl9NFM9JJEBMDWDkivxZ7T1eosNZcfjbiDmA+OqiJ16rbMwJwLKN1gNU842dolBhUIhVtUCYP5sTROu50eR3VtKJTjREQAKEIASNQhUTCcr2f8UizfvnGqSNHt366MfztC65ubN71rf3tPq0krUtmzFt+1/z5Edi2PRxMal6gBGoKNsLs7AN/+RlXfn00ET61MtSYyS84aIBP1SYneXp92q6y/H53SahvhSRDAFUqCRXFsgTj6he+K37A4PbKU3+QDp89Xxy95JINt349/8WZ907bPljUYZ2450Od9T9cueBzxZz9yVvHerdtr3f7TKxiW23TDa0N+tT2s8e3XzD20pe9rl/iytMnOpcaSXjdXSYPLJmFojv8iletP++yYnE+GOdzQ54A0JBBR4hoyBCgJSJrUBUI5YwAvDbFVyUkC/a0oAqqKhswAKAsg1aHChnh4A1gJIN57w0DAjkUQlBVT9hjH0CUAQXJA6FChFogRvZx9LgPhBZJgVUZVK1xisgsBpABMAR1VFWVZQgGEjQhsSEwKthBHwhYGJHYG0+2SUYM+8L3uitgaVdVO2flmhcc4rnW8p2bj+yd2vPgunvwrIld5cbLZrdvP5JOnMxsJ9Bw6q3x7LumCrUyF8gEgyAo5RVVUhUoImyRALWQoBgxKRSzZIfEqhYJHFohsWQVA4pLjMY+g0jpq+ZQc35hyYpaMmW/ij4iEriWp957QNPu95I8AQDjjJS+nmX9bs+5NCHDiIG8smRixZhqMJWXiHBURWI1AqRRSH6wFRtjILI2CFTVkmEDZNzsyRPW2q3Nzgt3tXcMhTeeV/3zI+aRx/fZJGFFY0yjVePuqmbpavBbUN5OvvbYo+WLJ1qbzlo6NZ8PtTSw9aHbKQqVLHW5TUpxBA0OVRuCs1NVdzq96sp9tfGbLnveCzZc1LS1Tx544PCxvRdcf8MNmBycmb37vqd277rs13Zf9tWD+w8cfOqq//6KCw/c9tjujenUtnUvfdMTj+9ho/3QaFmj2q0IrCKiERBBBkRCUgVEEkek4IAEoQqBo4srS07CQCgGFcUBCxMgB6xXvjU3M3X8WNo+ikurPsmNVHXNV2x/CIb+PJvc8X7827ccthXi5puvP/LIw81jRwGgMTzkHvze8gO3zV501bm3vPqG3/zD9tarTxxZsmP+v73nL060ly6/+KLzLjjrf3/287bqk2uclTU3XHrtyQ78/sKrV/Z8/cFP//XIHd+Z7VdNcG3oD23YbNoLyR/9zfhvvf2R17zzsXZz8kefzV52QdCsWJ5tbWjkoSo8sjKRGs0gVGAUQQdQBRqAXmkAf40CYbEdorGOOcP89aeKHkSM2D+NhvJEiGitPfTUnhte89qi6rkKFNEoJEEBkYU9hDWkyBqyHxHYGSIJlYJYm/XK4IMYlysCGgIZVN5xGKmIZECiQgqRQcQoFxkdlohkze8WERNA733dmNjTiGhkYEZEZ2wvVKdxK5GjxBTLbLEEYOIolAIwGCBAkWj9Pcg/omUYIkb6A5EtyzJPsyOHj1pDzrmgEfENLCyBjVEfQgghKiiGwhuiwByPiYhF1Tc2L4oitU5VfRXyPBcBAoUzQekxH0KIMmWn78Xp+1VTA2iFqxxMaft1X58Ji29LXnjr0oGDY/jh8ttfyi7NV6myklRBY18XANai4OnO9mkg1SBennZ9OV3Iru31g9bz6U44rQXSGFL5jO+MDlDN8VCRxByZyGsRXRkgEUBFT4qIqZKoemYh6Pju1M66po3Z6c57P/noNx9bziYnh7ZvSLuhaJl1Va1kfxdccgVfcyP95GDYuqM47jmEuY5o5+AdUn96ITFkkFjLqVsE2pqNyhJNDPvZLyVvv735pr3pdS2e3+SfPgpnlVUwztokIWOSej585XPjKfD6XZXZQ8kUb9n+9MJDYeNE4zmLmzws01LjsZcknS37n/s6r0uGJsMVVf6DaceJS0fq42NQCt7/rX0/+dhvf+SFOHXRbOua//jeY/OPPd7/LbQdGHvYWsgr9a003/jzP98vi6KqXJ4ErgaXkU4vGYABN93AQKpsLQDHVYkegAxFZyAAAFFGJGYgJAKUQaUMRiLfXxHRAiFQdNuLHCVDVBRFnN8TaAheRa0xRiWImsiUEyVjnLXAEqcEIoBIwqyK1lpLpsCKBAtirEIVpDLkGEqCVLEiDQqiglXAIF40CsyBg2DFBk+ImbNGdZY4lW62TFuWh95x/LJk/OoHx6bv2Xhsb/bUU5ueSjcPbfbrLjo2tm0m2XQERLKW2l6/CparlDJyItAPlRdvkEtGsSAi6tmA6QsrsiVUg6xAwMYZRbTWqiGL5H2Ja9bgqpIYa60VCSYx/dKHIAgG0AZAD+JqrmVqPQ2FL+MW4cgV3a5YYuXEixFRK2JQDYKoeHbpoHOga4ksESkQRZKYxk2GBSKFzDi1CsaHvrP2+NFD774mvOG8E6CyqSmIcPkG+fgr8Pd+kJRqVJWsqQ2P9Ip2tzf7M7/5rmT/sad8023fzeq7J+eHJicEFNAMN5re+64vSylT5k7WLzvLGUHKStj0B6ZftPSVscXp8ar7Cbvzx3uevmZ8y6+uhqNLi5+bPt4cSs/fOtUrFr6674HWhgs5HZ18+JsLx0/d8I7f7vVl8fgeQ5ql9T53peqCqxsJYikiVg0SAQgBJ04VstRJ6b2vCB0AiYQ8SbrlaqKppK707Bg8UepMvtpfd+ro6OEjre50L2/pFdcmS7P+8BE0PUKV7vLMxh3v3PnizV94xEqWTe7c/Pj/+a9hUQDocDU1tmE8sH9i74HH7nvmAzgyNdHfdm66beeVu26i5tjS3Y8c/6/bz6s31Qc+8tC8nnr013++ufsybG1qXHHRhuJRGJmUK88++eT+S7/w5X3fuy/rTzeuumH1S1/X7RevavqaUTg1dj4/ua++fryZcVkuEiRIDkW1chZVIqlGhSh+k+R0WD1zrDjY1hFIB9h5GMi0DypXDxIqz0XJoiWFICHn+syx6XNHh4rlstv03LTcRpslFXhQFZY4TVYAVVYc+O4RaAgBLSYmbffaqpKmiSqHwABgaSChB6f/NKCCFpBEoyqQpiADEiOkWQYAkcILUKbWiQRmNkQgGnlnPgRRZYOEFKFGwhgkeAIBQDRkSY2AsPceRaPrihDG0RewhBC895FkFJvpIQSX2FBWAaBer1c+YFQUItPv9ThICL0Y6Y0nY20pEqM4iFhVa4wSeu8dofc+sYlNUUQogp1Q1iYCaxcBNPJ2AMDAoOUYb2SBkqNqQM3EKbEV6fdb6cZf6V33R+XXH673/rV/zy/Z647yKQUjCRPH0esZByfUtcTr/98D15Rb4utjBF9L0PD0oQYvAIGYLKAOFKwhxobT9dmz72Uk8r+JkIClEo+IKSIynb9u87e/fu/ffnH5ECbZ5NaNl2yppaYo+31TYQEVWSLFPv4j/f4z9NWb0+9NwGItrPaW6nOPj56Yo/p6IdBVHQo8lwwvYRLYmMs7t/547KV/O/6x+O6rZnzVjBNAlqRnnm+t2Rg8ObcB5/5rfP5dBngYGg9DA2AKAABWtn+WaL9wJX4Bu6Gav2vD5rfmo6O+10ZbTr38Revf9tI9SR566TBNrS679ts+fvSGN03eG0bUrYopi+kAAQAASURBVDrcqNgN3MARAW+NsbqGvD/zyg+G84N4fLrnHFF4RoGiSOia5g3S4LYgkSLG3DfqhyOiAQRro+vO6cyVWUWgUm/ZaaVN54pSJM/7/b4icgUMbMhFcAaSAUuM4GKwFzCGgJWZ400UES9CQD74qBgVdUOcD2pQiYKIilokhsACYL2VMNzPgsk8GvAgiC1ISpYi1QD9DuNwf/TyAxufP7PtWLO/r7507+jTT6/fv3/34ebZrQ29kUvmptY/k21fctQj3za9RDkPRJVhDQHYmcxaDb5UFoMIlkitiR0FIIPGOFFllTjeibCSqFQuIgp88sQMEYZQgXBKaRkYANI0raqqlmcC0C+KVqtV9nvtslRVYiVrDaBXz4ZSskzAgAqYWmOUNJpfR7SExUjVdyIasdsskXsJAKysgkroLCSql6VPv+FcnxmcqvFoDpXgcM1eOln+j2vs++8eCBsUQp5qjaa88lfes6SN8jlf8KZWhwJb9cXZufHRUUjSIlTMXE9zz4HUoxaJy1DA6WqR1munphF6Py7d4b48euLIp179c1Of/b9lWixdtfvgw3eN1bNLzjrHG+4f3X/eOz9mudzeOfTQWHKFdI7vf/jYiWNbL76ovbQ8BKbMag203RBlmYB04D0JGs9MqqqKNn3CYABtkgQJlNdYODMAokxOfTHSLxsri8P79zU682XN5Ve+ML342pOP/9jOnqzKrqvV2pWtn3fJocuuusoNWcqboCb8+I7JtAEArhu4G6o0IJqz3vEni97Tpz84snLXyXt/XNH/YaEhkBbQcaMNVkbojG25+MZXbPy9vz6yb3Hz2eu+/+O7n/uR/2jfdH76ozk6f6Pe9fDYlgueeP1Nrfb0/lf8Wd5fTS67rmpPU4u8dmbufnTr8y9YWVoNiI4JUhTmqPwSI18kdyLiYP5AeLpeiRXtoBsYewQG14pFDiGgMACwqoDKmtZgr9+56X/+j+PHj1c9nxnns3JVPLMDiGajp4ku8ZgKAEwhyYwqIVFCNrBHDMYYQxYAiOxpwmhkLoboR4QYKaYDOQIc8CAjd2VAIY2nAMQEbA2reAQDmKW5L0pTiRIGVEZki1ypBLFIagAVUFRQSLnUgWAQEHCQEEL0G45gLFDwHGL0qKqqlmZRmUQJHRsRKVH7/T6hiZ/Ke0YFcCFItC+WaDpOiECOg2Bm2AdOAkAa2BtLKPpsQyI+w8jfRQVFUYzEnrW2ICN2QpEnQz4sCmYpiSbJXLXy6vz6r6/e89Bo8Y/++9fR1nFM2xbdoP5EgNgKRgSMwv4Ez5KDYbDnKwAQxys90KZ/NnCi4YHGJ+gaqS2SgGFQn6FGUZE11C4OyPeACoKABKqaCq1aAJA6WxToOrBEtT5mCXzsyz/6wjcnNu/asXOkFYS4r8td73KoU82A9EOItl1LZfmt9IZ/4jf+zpNfeMeDnzrg5rns+1ClOLTg+77fQ6pWC/PtLe/46rrfnnY7Luz++DUrf3OV3NmXfDWZvJNedEf+GjEpgTjuQ9luLT15yYl/j2e01Dzn6PqbZ0YuV7LWnwpJ9/Bz/ySknZDPU8gQSh3J06RsDku7v3DuNReawrEph7dPGURjcK7KTCGZTeb70Kf2qefcfeJ5vfGHGk/fLLvuTqQs8osugnXDWno0Kl44OZ14gZ6hkrPWVY4MBo2iogDAoBFJOyDDrw3aT2fWqhrvcFQiBUIThVBQo2IlIhKJqmFmyhNrKFQBAChxiHEZgo1yN4RR0DEEYUEMXgG48pgmMJCyVYFAjAEwYQ2I1jrLWqAYgMqgIjpCAkZjLDksSxHxTABQglSkZMhaKpDQKyYKQtYbRFNU/T7wcqXZKbzSTF5zuNWrlw+NLzw8dOTJTUfnti6ubrEbi/ScxYkLDo9OHbPJYhWM+CyBJCMJiSKR5VzQJSkjcmBgh4SEBoissaxMgEqVMne7ROSDOOeQrXof0XBQhuHh0ZWVdhYlBHxwNumu9PqpJ6KyLIEMiBprFWU4q/eKbqXKKqwEXlkCEAZACRZAJC5qBIM2mnyCMSGwSwwzG0WLCAoSAqgEonq9tnDixM9sWzCEm5qc2bhCYX1digpeuKX3iUfyhR6AqNieLKy8/d3vL7q6dGx5+Hmv8k8oGmrVG11nD506OdEYqdfrPsUQgmHtig71qNdZtkS+HKbQ6U4M7X/tL7/vnz/sTiz90XW/OvXZT/vR3GTjR/rGz53qWTfT1S/e85ONF165ffct7qkfnXjmqZ95689df9MLf+6d73zVz78VO8VwYhUMWdccG12dmbWkRjROoQIzi0eMzRiqwKuoJRdrK+Nsa2h4aWlOSp8qInC6vDw5f3K8vxJWV0AqamypXXxxMTGSb5miRFNu1K996erciW5tqLVpRzi6ZF0rn5+fG7rzAbjgOgAQZ4Sq0mJNi94jd+363n995+TChvnHr/3c9x593/tr3WP2vHMXPvyhzb/09iXMYWL9uicPrspy74m9riiefPBYzXardduPfOFHreUnHv7Hh5ITzxzZ99A6i3VID1/xsxvSts9Gk85CmqfthUNP/vtnL3z5h7gNXUOup5BLCKKBjDGWjLAIcFRrEhEW1SCyBrGhNQ8AsyZCGZd/bMUwc7/TDSGUwN4HYwwEVtUkz5aCHWpsXph7uj6axDKz4wQACdDE3QJUaNDiVFWkJMDAvL6W5gCUJ2meJRzN7Y0ZmAR7z8xR/YoRwTpEkxjrEBIXreZdbEQjPrvhMLMYNMwqasmEEFgkG2mGELr9wqkxAijgBBVQo0VB3NhEiQgptuOJRTRw5C6zsIiyCgcNKhBFeQOLhgrKLMs63W6SZ0HKAdpFxAsjRg08E1BDtFIRNWgrLSsOQJgwJWmiMlD99KHKbOKlTNiiifjmwZB1rXQEBTmj0hnsnmkIwaQ9361jvULvIc2JK+23XfIHxRt+fvWjp0bsv56680/SN87zfMO7Ihn8Lsizs14AQmVFMGsV1//zUFWKKK3T9syYAApDkNOjCtTYnhORyC4Vjd1qZVATvxM4YDYjIYAQYQe4xpZVVtG71I26nISPavXMdGfvU7WzX3Z1EqohJzP9xLEqghj1EqxJAlf9IAg2RZS+a1TV3mxj33HwQ2m/Xbm0I7pcFmZ4y13P+bmPXv/OfjpyY/uLfzH/+t3+YY+O0Ryr1m/whz5f/6W0N2dB1RgBaZzcc9mhrwxRFF2G0c7eDbMPcQIHt9301Ka3AazffPc/zZ7/ofbGO8QWAGCWd5oAQyWNV+utvlhrua3V+sygoN4RSoDEe+hs/MGxS/84uEVJis7W5h0fWHjioL/lXbh585aRrZPzBxdsXQBA1nKUwf2FSMyKlzc2kzTSXk8LqpzZezhjxC5KFlnXFjgCABESgBpcS1WBmRUi8dChB++9pqQIaWoAoC4piGYmZ/bee1BWgIql8gKqWgWbODYO0bCspXOqJRpgaEOwZISkNChl4NQaNchiPTglRhXQUpVBjTIBClpghEqshtTiqtOkMITeI2dkjZIkaQihIChM1wcjK8klC5NX1zevPlPds3Hm6dHpgyMzxyZnbtuWTFXjFx1ff/GBofETCCtdmyad0C0MW7R5UBVmBCKwDGIgQUIih6hEJFpyQDRV5YmIg4qIKpJSVVVKNqnn3F4xVoIq+5AliTWZQXaKVb9kS9baQoI6ml9cSIfzpKfoQZQDQRyEMlelMYiAOkB6DrSHgnhAMJTlaVUUHBQDxRVjyZXKeZodOXD/xkaoJ2RI2xWOZNrmvGWK0ZopVuWSKb3ziCGihaWVN775Z3/rt//gridPaqNXLc8G2J1yoSKtJHcTk6vtbn/VZ0maZKmkmLUBrUkwW0TJ6kW12l//+rd//u7vQdn93d/8wHOS5g8vuri8+TnnfP/r120c/s751/Rmpr/18H2XbZp42djZn0jWXR6+99xv/OAphf/1gY9MbapNtcaOrB7Beg1ZMpAj0yeMIxQhBhAJBqIQolVENWXwaMQZS1EPhjCo752YSWwa8tQX/Yn5xbGjx7ITB7VYqScJd0lqptCqmJumh58wra16ye6VK68pZ2dgfsFwt5taq4H9A4/Vq5XCBwBgSA3anIOrj8w99MND7/6TK//8t6oive+v/mLp2596+V2HH7rrO3j+hRv/8i/D7U+GxB/5wbd2NM/qn1ogrPvOofzRA8d/79X+vh9WCCNmpObyVeuw0VjdcMH0ut1X6ixV074Pw1s233frP4+2EJMNhZlrhqFuHlLlQGAcCUIZpfZVCSCCgMAPgM1xC/beR/saFY66+aEKzKzKzB6EvUdm0YoJVJQZNHhWxqaBVdPzjud9SQoJOopYXQQwpIoiSGhYWCVYa8kHAEJrAJxKyPO8liax452kDq1xZFDBGvCBLKgkA54DElhL1jhEJGsMUNR8iG5PaeIMIXtGroKAqCijVVOyzMyeZFALSSWMqlYRFcA6HBSUiGTImiDiUmMRxVdJknSCEFHFQRWiAbh1lksfQBFRgINKCKHslWSSTlHGRCCOeaIksiB4DorGWVRmkZDnufclAAQRNFU/AFqTsPSL0lgnjBZtBcGhIzsYtHoVQ4bQQJCohsGgSCiiGvWkgAAkIQzEVgnUi6DDtO27Oxtb3tC79hP6yOeG73tR77xL8OpTbn8Lml7RalDUTKASCFlmpAhnTCRO7+kqoBF0Gx0aIiAbFRH71EMhUhPLWTFRelQ5Gk6qEChbCABGwCExeSUjQgYUfGWRKqQ+GTCU12XEEtlshf2J5e5tj/rPP9qXofo5l51ddIqu1wVVMj1VdDZH9qrUl2BKNKKqlfcewRBVTzfX+2o089Mdl5aZn0633P/y9zx+9ZtAZPd9n/mN9ENbzaG8Rt7gsmssSMurPbwwdvHTf58OXbVan6gFbCw+7I/cF0YbMDr6bK3vVUOSdPq13uF+uq6XlBse/VN49P8rTWnCIFkKDDYDAAEDAGK6Ry7+H2qCb84AQDnc7/dwcad8/6Np8rYvXHHwD2xrvfbbIIHASATHRd0vIonMQFUJkVUQZTU0ynMDQHSRiaSvWDRbRRTk6MZGGCeacWYsoIooAjGRNGjIkWeP1oCKQWBmi0l02nA2ERGnXFVEYvtlAYpcFMYQs3KaiZcckyoEJEmSRJVLCQYUERIFAuVSrTHO5BAAERmJLYJy5tJOp2MxpInrdkt0DiwaYJVQWQuKLhAoW5ck0VKClENhrWVmZCQICLKSEUiVdeiGJzZeazd1hsLR4VP3bTx6YPzo96YO/mjbxOb+xPbF+q7DW6Zm7MgcM0EYotU0IGKtZyBHEBELGRCAOA4AUDfGh9DP08SrlCUTgSG0ZIClKo8cO9ZoDXkvwlxLUy575DxTYpTAGQU1iA4dk7haTmUI1laAzGpkMCZgMBQqMISGCC0hogqAgjU5GmEyCsYYRQEkqEDUVlQZyS1mjzz+Y7iURMAQFQwV67CrmNU6BxQq7qMdCsaASp1qSx02oWOTUdLKC4BTr2wqVdPIGhC63ZXujO3ltlbPra1RPds03BQYWVn1L3zV/3744YMPP9yg+v/5l7/7aKMe6q1XzC9ffWQhPfCp99742vbEeKPRaEBydPtl7LKX/e4v3vbNb/79X77rd//0z4YaN51aWaGUSDxVBomSzHIpHsFYVAVkyciKI2ZWAGYFRmPJGArAAmrBOrSdpFfr4MTs7OTxQ/XuSfBzJh0RD+3RegNSU6zq8LjbtBsvvLg3OlLPHSdNxKWq6GWNupV298Hvff7V687q+QIAnKn6xmPH9bEcagyv/MuHVr75eRVXXzg2njX3fepDve/+1+Tktv3f2ru49+6GAKBp33Bt87xLsZ71P3jr0Oy+xtzxUTO0WE+BK65obHTbQn/p9mtuQdDJztO1kZFlyIuZ+T3/8ok3vfYNYpdzTqu8coGrskpIQ7SDZXmW3SkaVCBEcfABHpZ5IHGXJk7WWEMi8Ska45xzlS8AgIMIqQrEqc/i3LwX1sAGkBDFhzKUsSQKIURoxsBlCBEHEsoDvoQxJqroZVmWO2ucBUORAJMkSWAJKqGsAMAYgwTGGEIzwHwOTPogzplYFRFtYiUMOJERRaVrvFdjUBgRgAaGoRLVJghVfSUmNc46ciFUTCBViUje+zi4xYGFsE2SRAtW1RCCWAGJNCEhIh81RmRw3SJk2hiDYJg9IsZGVrQPMoiWwPvSG4I8s8b4qoq3w3sBRFI0xoA1a2zsCE5fA0ifUZgOsqhnGbzRJEfTCudt5+f4ed9aeXx+LP3oyq2fqV1A3gaQRFkgZyjFiJoEQmEE2a6hsdaOCYpIILF/ufZ28d8BlcrEGEOkDF41GCWjRoJqEtJAglQZIsZEfKBQ2GDLtCNinSGUbChRqqaca4opuLr/SPKVPYvHO6FoJ8faKLVsqNVUgJWVDvhxhVJVLdRUNfhVRCOKDOpDMOBHbK+CTJg8ri5S/WRrhE8988zmnfc/7388c8mra52Fq7/1wd13/O1wv3+0pUM3EK5XpzTXGCog/beZq2rJ9nW1g8PHf7CevMFGH3tSmzBARad6NgDbVp6i2AZqCmDSYjhkj2F10dLWLy2f9RUQj7184zfK4fArxch5XJ8CDbVqOslGV8JwTGQWd3xOsAyNOXZdEFLizjqxSHt39V//Ire+WNk/nKnazKVBKzNAV62BsIDgp0cDg3sUb0WcGSP+FEidYp86ssVgsPTiL1KUn4yd59PC0ABCJMiRpUcilgeTZmb2mObWez9Sa/R7BWe1brcvRkoOntRzQGUIUmKFBnLjwkA3JtbeEYYpAOCcQSJmDswFx51Eq1Aa45jZKxhjrDNkLbOKqjU4MjLU6XQwqi4DAAMKWpES2CMmrBagb7hjsOGRFsJ58xue89SWUyO9Bzae2Lf+1IGRI/vGi9sm9qwPG86eX3/23Mj2g2HLoityx0a7IJBiT7niMk0ckuEQkAAxy6D0llOtIXMwha2qyoFh13KpL8IAe+GroeE6sICoN0qKFpGjQp1AAI1yRhH7gqg6YFSAkENQUjFYWSIEq5AwoIn4KyJjBIiMRq1QFucJ8qXF9uHZbj8Zh3I2CE00jKhJ0FeIFdSQesu4qeouJk0cGhr62q3feef/nAEaNgolrQadygUSNqSYWj/RWl+b1HYZ2qu9pf5i6Vf73Xmz5C1Red6FT7z8pSc/+fHrXnpLM09SluFO++wCJh/ff2K5k196Wb5169k3v2RpZNe51573xF7ODvXfdc0FW6/Y9upX//zZndq+sJBwrmI61K1hI5hcOm2mBKMEtwgBRt9qEcgCOjKKwiw9CJlSQlg6Xh6C5iJvOD5jTx1rzZ40vihNi1zStz4tV32vldTH3dZdYupU9ceGxvooplZCo+HTnNZZi878qHXh3RftuCHMAsA42vVeVq0uUo5lMdQY7a8YS20cyZrrtp/86/eOAiT06PTtt2ZZKPvdrc97aTKVnfjSP+Id35w6/KRm44s5Di0V+fK8qdliauJEX44tzx8+6+oxXd480jSeRiwUbLZsOV+yjIukK95BXkez5IACAoToz2MAZUDllUix1aiDE0mEzIajl6LGNTyQSmZmH2IJyCKDAaRADEJE5KxVr6igLFHKRAMDAosMRMhFQghJkhgYoP+TJIl1grVkrbXOZGlKgC5JIjAkbjEmCAknFKEig32EiERUAcyak9qgc37aXGEw5JJoeSISkAwBpC6JMOS1Hq4igrUWvMcsyVwCoitFLyHMrGv7PpH10fyNEBDFS1n2LRkAAdCo9ux9MEaDcEwPYs2BiAoUg6bRyNOJPB/11UARBWQAWkHEEII1BkBVOFQ+Nmrj8rNRLxBAhQURbYRCKeAAa4MDU/ZBX1fXLpSqalJWQlvTyXdU1723+NHe8cWvHL/j9SM3zxazkDuouCa1ru3X1DMjoAhHi8rTe/XpSAwAkZJ8RgAAsCloVQUWInJkITbV0JigFaiVkIuWpB7BeFJxjaZMpYkjWu6X3TbOLiffnfV7TiwcmnUnQg9sM0FGU01MJFrJUj9IJgxsAAykwqxYGVBVKD2LyAiu/kLti89P78qxKOvuB8XVn1595ZzfdtfO5z75mv956JznNXozFz3yyUuP3TvfOdHeceHi8T3S7k9/XbevtyOj2Uc2v+rh2vWHOuNvaD0yjsctuqzQLnUU0zQ1XFU2bT0bzqCv3qyD3lEkGyqmLO1uZlweOfL6fPHcoPtrs5c30tV+c1TqEwhCyKa1rldpNBoDgKVt3wALnHRN1UpWJkmrYujQcjNMtPXSX7xifrRZVVRTA1pVDmNxixLlYAefAREJ1lyqYmNfB3j2SAk3gLz28gFcfgDnGLC/4hRfIoh9jUE2CM+AiOisjStnEDJp0KMONoBoYh0B2obxPpBCCAFLtQQhoIIaMmxMqHwZqrCGFVhThTTRu8mQAoEqGWPEh8H4OcrUKwqCRUQwIgKgxhCJrqwsISKiiR1cVbXGlFYlIIIyiAFroyeDgjGmi72+DY0FvGFh/bVPTC0PV89squ5dd2hheOH20UN3rK9v3L3u/Pa6rTOt3UfTqZXakrS5JkndiQh4SiTXwJ761hKh1qHsKavNgfO8CpXzZb8gQAMgRpPEteoNFS5W+t4hEBkFEDECCFo6NNXaPkaKA//mSMwLIspIighoEiJScKocZ/mIoBRfowAMEoRBymartrra/eTd/f9+pT28xBta0qo5FiFkY9MHO0Oj63YUT0yrxzpkKyeOf+ZTf/O23/6rZx6fDpJ5BSueVZVwuTNz8In7H7rnh7svu3zrWdsmGtsqaTQnxldqzRkWeObBqY//5e9lY2H66JBiZ3xzff1Uc3TX8A0vw8vObWVJb3pl3+GDW3ds+pP/8UvHLvnj+sKTND76J7//V4++83eesSPdKy6FudWGCZlrUImifU5T8IqIBh0ox4oufuPKlJJ+FTBwYoxJmWxQxrLK20vDM/Mjx5+CTjfYlEFtkD6wCwL9YJDCoSOpa1RVxSKBKMsbXVih4WFWdI3MBtVmPux06w8mdjUBPn/WK6/TfOfikR1+oaKi9PP1sNCxTpZ0cemZtD5EVAC4jeDBNcGa1TvuDHfcltVcZpKl8fWNlbmJFe25Fl/7qkVPT/7ke0Om3s2HlzddfnmtWxsZ534PfL+q9Irf/l+wcpgDBBeysl8Eb5whtV5lIAiJwDzgEenaygzCz/YbjSJQpUpExlrFNa86Zu99xVUYwHApinsMOEuioBrXZOAq1rjGGw4hsg+99xqXPaFGC1gUawYeCUhgrWXghFJLxlgrOPDeUaREjUlQRAhB1lwTAAQRfQinPRVEOZbFqkhkEQMhsEr8d1BVoFAWatAZcpaCFy+eRZTY1pxhLUOJiU0rNElSEaaUBEBCjbSQEAKAhIpdHotgBQA0lBjLPoTKgyVBZRVFBDKASoAEIMxR3UOjUZKqM8YZ671nhMRaa20l3opB4xTBcyA0xhLwwG6IFFFU1jBZeNrhcbAxnynDDAy6Bs6iYAwV+bRduSW/6dvTjz46evhjtdtv6u1o1KaW+6suM+LJsCqqpYyhBwz6LPga4q3WyFmEM/wYEKIaNoVKidiaoBpQowOACJOxCRth9CGk1rqhzDrNy+rwjPn+fO/uE9X+U7q0Qv0CxBIk9ZrBWsaGOsgQKuyU/cgAVAURBvEqBlQdYeULAusMDenih4feM2kWHPgUCwfJ87N7aHTT5xrP+1bt9zcevOfG+//xlX/2q7Orbx3Vdxxd0KYU3D3SLvsLT947857fl5X6jxsXdVstMGZP0bqBVOyyykRRLVIImg0EP09fVQlVkmTrFve40RslAaY0mFwBkMusfQHyOZnMqR3SfBSADFSo2veOQwDDYByBKjKYgT24Mhb9VWlpMzXrR+pz51+6Ugw3RDhXLCQ7/b4KGuUmY/Nfnr3rg/+vccMY1AhGANZpKRVBUIrwWiVBAOAz7DRwIJkySLBO2xjGppQCKAzcGqy1Jk29rwyAL8rEpQKau1rlPTgyChykU/arIFbUEWnNdnpFXO9R0EYjfw7RGGAFkbBGSiQlCd6vwTiMIHjhiLY3hjwLGpu5NPaxiIDIsIBDg4QYpDJQkjgvTrSbQE3IBMfqZrPK2Ir63s2lV802rmw0inF7cGz+rol9hycOHW0eMK3WunOHL1zZuvtIvvlgDiccp2gzKZJOURNgcmBrYqskUCJNtb2kqKBHwSbWkagPwaaWVU7Oncptgi5JomeAag/FG0UGxwBoYl5tLQHDAH6JhqlSRVKwAZ0iWFXSioAYYU0xnn2c8ikgliUa9Nbp1m3bPv/oY5tbjdee0zm8JNSWzNmzW5zn+fvv8DfeODG2bqRThBVYdUOTH/+bv76iyjf/+h8u9ntwHEtrSm5PjJ/17f/zD5/71PsKB+M/3HjB9q0vf+1vV7Ws8+g3Lr/4xbv/416/dIxCPTGhbrUYnzh361VuMiz35Nie/U9+/v92Z5/59L983gxVn/mb/7z1+7eff/M/70wfe+uv/dHhX33HurO2rdx8ZffAiZFsKAiBL3rGCpNV0UEFhdZRCBLYA4Cx1BXp1yETytWytVZN1u1Luz156PjQ8Sdy6RANKwgnSca40l8SyOw1N7qt5y6vLKfHnnbjw54w2MQDi0WQRGbmQlixValzIOvLY3lnPQDsXbfpsaFXTnFmZg+eXcxsSHWq6CbdY2OLi7V+t7d6IlFnpV0knHSLet7ESYV2zlQHhgmWYuN5s9fcXD7n1bLrqiOf/zDd81UcGj689RpGe/kQLy8tZHZ4YWGuF7LJyS0jea29cjztJxX3JXdcSSVd4IigQQUMwoOdRdQrwxnG6Wv9roHgMgJIYBGB6CAVxe0QfQiiEqd98VdcmnSLfhk8OSsqJNAuuz5UYjWEAEAiYq313huD1hhjLTMzcERRxUo6coFiCCEkiqE6MiBBSTF2ntf08CpRSdM0KlUBACKRIysiIsYaEQsqA0taFhUUEC8BwETt4kH2TUREylIQ5MZCGYK1GgIF8aiA5nQ5GDcmAjTGqBcAMMaGEIxxiOicAxCIHjIGAWQwecMBuskYCwBJllki730IAUVNYrxwFbxRComwr7Ay1trEAPPAsjRugmd2BZ7df8/sFf90bGYAJEp92ofSIzcweZe+5M373seXJh+fuf29tV9eMitpMBV0CVU5sSaUZAyYMzOzeJEskqCepnGffqACm3oUyU4InQT1goiASbvX5TRpNqmRusrzkRPtn+wLd5+sji7UBMklrbIokszYNGTOSuXbCsUqO0WbmGCCKCtDaTwiVAXXjVH0ABw0DYLWhSS4d9Y+M0HzY7Q4SisdbP2g/uYv1t+1aNdvbz9wwae/eMlPPrT/JW8pjr89W146slIaosrY4GV08qL2Ju6HbplvDOK00vG6f2K1ddKN1hMz73veaU2l05PU2aBntKClXvQrUy5e+OQXHz7/rVk4qWTFWG8bVUJqkn5tEpEUyYS+IFnlGi9qMP1sOIAdtt4d2VDuPEJVIq5XDR3VZo8Qmj3Trk1Mwi3QYUA17DvkmgGZQKP9Fwx4d6dj6pl3H0SjxTIOMHmnA/fgy7FG5ic83bImQKIYiAflMiIRRt65njZviHIoRIPhMWJmjARO6paZydnKe+tcnmVahSp4cBQCS+nVJiZLQCmGzLhaASQWuiKS5VlWq3W7/bJX8hqDH9ZKAubB1EaV2QdEV3oWLgGlVqsNDTUXFxeNS63XyhAipqIkEhCQwCmWDgm8ABowDWhwwlVLSwLx5Obx3LnN5z+5eXWiv2fdkT1jM4dac9PDR787VJ88f+Li1Y0XTY+sP+ZqK9iirG99aXucJGRzVO1VXW+xKSOldCHBTqdnrPHMRDbJcla1hEZAQAMICRIgg1jWAGgMJYiGkAcCtwAgmWQBWQwHEjCaoCU1qbiATESxi3Y6x0JEUEOI3V55w80vevKJJ/7+gfybT1W/eH3r3A1D9z729OXnbX8pHbxy58VFUVxwwQXf/873pqa2KK1Cvn7uHz/Id3259lufBLi+mSWun7RnV9/2jnd8//v/vLQsWV7LxtZv3tL8wJ9+YHbuIL555aW/9j958aoTvshDAbW84cPXv/3vT939/cw1/u0//vayCy56wYtfvlrO/Prr/9tdD/54y03vQNCXmmT1j98+vnP70ht+uTvbnsybfRQNIdLhbBGqHAwLs1ciYxBRaQDU14zVBSNoPFpXcVJ10rnjtcNHh08drnVDmWcGexTUBPJljxp12LBdnn9zvzGKRw4kG7epYHniyebwqviaIGKSpkemV390my1tMk6ZZuLcKAA0qrJelqdMiVNbQuOyR2yRYBrEv/HGSxqmZ4OX+Xl/at8Q8/HD0+XxQ+uT2urC0uTWTXM0enjd+pUtu1obt7qlxYmDT46u27lfJOu3/UW35POHFY7Vm+uWpg+u+jAx4adoZM9td17+tpdUVVBy0hEwIhrp7mqQFJCZAdUgiUQ/Hqmqgct3nKQOyq8B3FLX+lEKAwgrqiqKkjNxcWrgvFZb7XUVgVU4REIRIRErswqiBgkODagacqfT6hg70zQFVGZ2znkOQgPrbEGM1CAlHEgKI0hkQA2oL1r5EiMOK35+sOoMM8vAE0J1ze5eRAHBOccEHEWKY5WPaJACcoNc1qyvrKxkACFwIEzAlBIAIQoGWWvXTH71tDqH5wEMyloLHMBaBAVSoeh3xmjQkgHC6FGqzABgkNAiGVBLIgEgFgcGAFRAWCsIp/0QB2hVQ6eDwen9d+AtCD/VpYxnHWOxR8iSUkzaK1auGrv0VYs3fHv/PV+bOnTL/MPXrT//cHcpB/DGWAZGdDLQo5S14wAqRctBoNO7+hqQJ57+KqIhcJHBIuLRAhpz1lQdPR44VXz5md5dh+hgJ2fIcwgh62RsEpZKq26FGIQrH0LFkDeMcGbmS59WaYpQciEWNVNrMIQqYvd6vZ5zhgOAn79u6N4Wtido4bDd/dbJBxToBb1/f/7sP4+Ux/cvbqoQ09HU1EVOUtpYZ9qLveV7kmSbobTzxBNTakT7UquXBWdQtDZuf3zunJvkkYXeiqgOpGkR+9UZZgy+PzE6kbuMFp+5+oG/Orr1hafGL6g0L23T9U5VtUkwTgHI9wAp8atiM4M5OPEmed66YvHY40/ffWVn+0/M0ojUT0raA1W7RAHXD3e3XX70bB2vtF0rDNRIqzP41s+2HM5MfdaEJwcxGAaaKlGtBc4gL8WiOcp069rvRm4DwwBPYKPamgIRiYOBKFrsCA8Ei8kqGCQhIHIBAyI4MiIigfvGu2CccyBa5lyWJbA06nkIIYInYgJvkBSViKoqBKm8DwPcBrNIiPKWP3VesW5mNZaqqkoz572fmZ0jIsWgoAgolkg08QAEAlAX7DI0ORWjDCpQKUm9RE5MDo0gvV6tVwOqzejzZnbdmOw4PtJ5bOvsvsbM9Ojh740+fetwfWrX1gtXtuycqe+eaY52rYgrHbIjRZeGqpQOZmmapktFn9nnJs1N1jC5S0xZ9hm1jyIqdUaj2BUshBERxRBIYIjUTTCkqoV4UDAMVk0ChNagoUBAQRlERAygEsWCmEVUOIgsLcu2nReedfY5Jw7uO8lj/+Mbi6955fNf9xt/89TRk1f33vMXV868+N9Wf/Htv3bnd7+der/IeScLd+Std+/df88fvgX+9EBNlvId62qh9o2v//2Rw8etwl/8yUef+/zf+NfPvO+Jx+/GRuOsS3bc+dXPfuyv379py2ivD4f27f2XT3/+/b/3cze88PrzzrkYxLz59e86ujB9y4te+qLX/472F2Z2bpg9+viBv3rFJW9+z8yd3+20Z23WUk8mUzWAmrerojmcur50uVjzXBvsTlFDiTWUCiiWhE1nZXT6yMTh/W5+Go1wo2lNTfxqpSERDRvG0m1X6YYNnohPHrehnwC1D55yM/NVc6EaVfF98P1wZH9y/Kj17Fl9mk946RqAzDCmyZY8qwJIZ7bltOiXL7nx8gmsekVe5TXcuRG3X66uNnvi+CP79hkztGFTc+GkNzi7qTY+0aSRk6unsGvO2fjEh94+ZhvqhhfPf+HI/V9Y7j2YvOm9y4Kt5lg9TTijyR2jS912EfpYUUaIpBi4slYDGyRAivQYAyLMxlpRjgE4PgxZipIxLFGILTKAJQyowCAxFDEBMg3y3LIsi6KoijJ1SZQyDpVXfHZFIaKAJsbEuamxNj6Jx1RVlkBEZNSCCkJMjQ2gKgCrUhxJCQdhZlSJH8BzMMY4dNaYqDll1BAaBh9x0VEAgMiyBmMcAwuiAUNRqXhQCEhqqFsVYSkYVXWkoSJBcWjQAEAVPK5Z1RrjVDXNM+hDt1+0UmttAiwcAkWtooirVo16ewAiotamiEiAykLMhkySJMxcFIW11sYOsw9gaKCkk1gxMshvTpekiLGOiY0HjIgsRUSKLuuRU7uWNCMA9A0OcU1VS2NWsfuHG97wo/0PdnaUf7vyvWtXt5Y1qlWaBvRWBEzCylEBG3CgszHgPUe/RsQzOt0DC3cdFvSB+6xlveaGmk0OuLTS+fxdvR8fDY8et6LDrYaMuI73nUIsd3gJJUhwajAIJqbSAKRN8adY3EqYSNPC9nveD+WtpSKW8cShMuoQzQY7e5l94hJ67LrmvZe4pwyKAiBhLp22GftB7XWztGF3+0c7h+7pItvJCXRp0cz90X2m+FEYeuHJZbwgrYq9947YZmYTDmDyHEuF/updKxdePPZgk9PVEApkl7kQQj1vnD7fQL1Kg1aluO64QuuZzyazerCTPnLVBzmpBwm2XEm5A4rd2hQaN9I7dcm3P3HH5T+LW/I31575/bs+dfTzn6w9mlXvLhQELTWbY8ND40OrjTd/78U4dsAm63pZRhVWaVnrrWnCxgx4IDypQiDABObMGLzWq4A1T41nbxIJSoQpwrOvjDTeQZyOWmeqg4QWIbITB2ncGcHernGfZM3UObGJqgRkSByAhqIMRWUTl6ROvdSUfRWYuV95730VfISIiYiABlZrLTAAiCrXs7xXVrEXJVEZWQaATeHKlz5N036/n2UZKJG1ZSWJUackDsWQxmwd1BtseKwSsEIlhQJ8rqCIKYtPmIxtWmvZLubFKvQa/Wpsjp5/ZNNN+dbZ8fLprQtPTp04lh24dejpH6yvj/Y2XLQ8deHixNZpai5gH1w/dUVauW7ZK0p1xhhSVYcAyqESjto5noG5F10SWawH76IN8UA6UCkqygr5kok8GgZUYxNF4kDR7gJQlRHWuEmqopI4o8Gzmk4Rnnvjzf93756h4fGh0dEvffk/+4W+4md+4Vb7a2/0v//8MVy3Yev6TduOzczWsmQyaXyT9cVubKdbBwCn/uztzfO3D7/+nS95+zuvvPGGH9761ZGtN88t23vve8BjtaFOGzac/Zu/9kLfmbv2+je2TyzsuOlFX/naVzc08re99S8rwn950Ss3XHTdldrMnrj/kb/7y/aDP37q1++8SmfO+fqPT33jR0+u7DtreLxYDf20QI9NqJWhYxHKLqsNKLi2LZFq0EEzgCygU1Xt15fnxw4dGT5+LOsvo6XKNEx/wQII1BWWOM3oouthy9mVFegXWci6h0+srq4wNhvDI6WnMHti9MSJ5f1Pw+GjFisrQosH72sv7dt43s0GoOdJl1bNqQWuFX6l6rJesHNrE4vp5VmTDdlVcquLqfPHO7V7fvSdnMY376jDwQPNxG+cWp96XFnoTCf+rNEpe2qFZhcyrRbHt5VD63Y99qPjMt/99iemahvTa64b3rQp69H6q194fHGPq2pii06OrnRCNhkMvgXJMMQBK2gIvDbfHdRYhpRQ10gLsfwNIXhfhlCpsvhKRKwza50lQAWXWBWxSNZaYwwpBPEYBWxpEO8j+lcQRNVGnXHmOCr2RVkGb4yxxnnxilBxiOV45hJCg4jCa04sQUIIChKNhM89f/f09Ey33cmy3DnHIt57jVaDAOzZmKCCRIqCRBSqEtAAUpQMgOh7bwhAcuNE1SWJBEZrggpwMEJoDQG6LI12UqDAzFWoYtvZGOO9d2SMMdFj1yIJgkiwREliAcCXlYQQEaGZSwShqgIzl8GTgiWTJgkRWTIiQAiOzBkbK8Ka7JQCk9pnuxFAOuAFrUkjyUBLMur0ikjNekYnCCnRarG8a2jnG0du+bh97L51Jz5/5L7X1F48ryeRUIUclRXYJOp3IupAZzgGXhoM/s8UmwQBxZ6sNnKaaGSI9SNz4TuP9+7cz0+eksWgrczVh0GgW3otS8fBSNBEc5E+kgdkBwg9AmNLkyxTaIol1XbZt4kjNt1+mQiB8ubeQy/JV69I91zqHtuWnASA2TD2RHXObBhlxf8cefeXG7/x18eeZxOzN7/hjvQVXx7//fC2tHnLvt1Tob1n2R367tbi0faW6++44/svu+kWQrN6/AGn2gY7lBWnIHinKeQL63fdemL9NcljXQ9C+bBHcq7TLk8H4MqTMWVie428BdJOk1p7pRpFZxFIuURE46iEMmvE7Lbqds89fPftr/nzXqd9+x0/PPTwD0eHRyYennr6TU9u/+3zJm/YPCTDG7+aXnHfrqHn37Jw2z+c++Z3LbWkVSgCdpIEC4XokBELwYEUWhymMugZ4OUzxv//z2MAy4oqKGsyozqw91jT96YoP3N6kDFw+jKAz7ZVwAAJrpXEseImhdh8Qh+QwNTIOYesrFLkAqW3NnAQIiqtpZIEVJXL0ltrgFlVOXhQFQ2AViSompjzrSnGh4HWLGrwpTHGoA2i3U6ZJGlAzw4tggFkA0bRMTCBN5Un9AQ5GyNWcocsUHkjoIlV5qrfaWVJEaiyDmsuUFV1u9khfM70hhtqm+Yn2ns2n3piZG66+fRtIwdum6q3zpu89NTktTMT4zPZ+lPNAoq2VGwsJYgKhVYBUAylXgMBqkoIlQKKJhwNN0UFDBkEY4wNyADCKoYy0KDApILMAo6BRNQhqxk0sUSEB7NyIwyIwVi3tLy8+/zLLrjwqmeefty0cGS49Z1vfWFpafW3//A9Pzl+3gde8MTdk9kFV14//Z1/G3FT00uzaujpjEdTAYDNK73mZ/5h5t8/OXPtTaOveesrX/Gqwm6bT/wff/TfZmefWZkpTLbrj/7wIz+88xtuaNPV5z7nhte8ua+rv/Ohvz92qIeze+SZk0//3dv9T25b7XdGr75m+eoX+3zo3FddPPNPHxn9p4/seP7Ll0SV+3kgAVYohK3P1FRlVhkGCiGIQJoRDeaEoIpiIe32msdOtA7ury9Mp8BoEh+SintNHPe6qrlmmy/tBK2NTIXJ4WShz3mOE1Pp04+bvofrLuwvLur88fTo7MrDD2DnlCu6ziTWuWzL9puWj/RPLR3bDHDs4I/8/CmraY+LRl7bvWXL1uHWoYMnMMPMzSceKXcuqR+fmR4b27Zp21bvS0yGa4FPLXUdFMOtsfVDTW8KyusjV79Ov/dxfttfuFA+tf8bhn36zE8QQ/m5oZWrXnb2W35reOLsrtZCp584xo5QnWq+7DsLos6gQUg0QlUxWCOBQwhgSAGEuaoqQoOiQYHSAZE3ep+VImUZxJMKlBIMkWEMCOLS0kuj2VxaXtWAIQCAKAIay4G5qCyAcQZLyeu5FwZDNk8yMZWyqgaVONbyLL7Xr1trRNAQKkjF4JisISKjGEAqDgawLPpRky8IP/3MYVW21ngugQZYDwZvmDxIgUJZQlo6jvIrpUUbe+AigVUILSIyApF11nVXV9I0RcQgAtZVwacIwGwMYggJYsxXrCUXEBGdInl1CgoCBGCjQS/HPUtFQ6VElJiMCcgmqtoXUUUliNEXLApw3PwCD2oLVTUMAYMSgiETjEFRQTCkoGgQDABE6V0gg0BiGUFUVAlRaaB8QkQIDiQFkSrrDklyvCjeNfHS7z5098wNk5849p0Xdc4zQ6O9Xq8BPdGGcR1Vp14VjHNWkVkFnCt9AIO1sihqLZESKqq4cvV8POE8aRxY7N3xk5XvHaoemTU+JJSaemonnLgCq1AUQVNlRae+rDhj6fbJTwTXDUmZshVR9ImAAvUTcaAlhLN47hr7yGW1B0ftw+93B/5t43vO0uSB3q72xpd/qb/1Y49u++Dvvfzf/+uB9677l2MHDn2x8d/e0PnoBfZJFNjRefrCxW8trdSfevjcO3fesG/dL9y/kNvmazYNv3Rpzx07Mp5fnU11Yz4zbbmbhyIJrCZHNhxWbT17iK7fVTxja+q7BTtbR1+QPR3MRDoEGaWNwrczGZ73q/0SsV3Y6UdWJs6npBlcrdNcB4iknBRL6dLcwbMu8UmyMB/+EV5km4f7T32sGp98z+v/9oYdr3zmvx45dNt3L3/li/UtL7z/z3/21S3XmUyobQXLSgEsyEDrmQwgAkZWEgkkSoPAGQvWNch7zJAQ0GiUlBEwpIaUAxACKgGAQV2bHSCAjZFbAIAYdc3wahDZ4+RhMMQxqEQoakSJkNdgYBGeEVtZFlXJsopVtczeWMvsvVcDFEKaWV8FzwHRhBAsErNGaTl0yUq/ayGL3LqYi4sKK5BSKEtnEgGwlLT7PWMMARBYpwwBFFnIkhIpFhVbawNSilZZQrRbrRiMgVo9t+hZjEtpNC/LksueMYZLBRZoWuODULlScf1Y+qLpHS9rXHBo6+yeibk9zdl5e/iO0WfunJrYumvzBcX4pmfMuuN5bY4FRTIXMmhYoqAdSq2ycMEQTJZIxRUHQ0Y5ENrRfGil28lV+hF9aSoxiGqR1JFRFkQUVDDkhUjBKGhgBkVnwQMBOi0C1QKXzXqtLPiml79k75P3rtPRpao3Nr6u1zvxrl9+nSxNH/htO3X/e8aHn3PeOVcuzMxtGB/vBvlSu3tOswUAXd+baAxvKoO/49beHbftzZvljh3pxg3ddefUr7psbPzcxelTl7/6NTe+4ec7Xa+dpSP3316/4zvfPnQiXTnR2fdgHmj9a39p9frnThw7denn7vjMPfvTxV717l9t/PArrdEN3xzJrnZm3veStJkag1ZDt0rFATlR50S0RTUDRbckmxiDaKlq92rLC82Z6clD+83KnLEovgLnRV2NJed+kaWsIhfuwvqmIrRtv9AqmFW0qyf71qVn7ZAk607Ppg/dHxb2JXOnlDJfz0LPW0XmvFp/zi6TNhlgx/brdXyW2W9bN3z9dVc16zZ4CoGdYwiJS6wnLPqy1INMoNPpGFQJfqTZ0sy1cpdZI2k3CxgELn7T67/03Y9X+dbRcrYzuv2Cc3YPHzjamn1ixaxfao61jQwbsFy6Wt+EfscM1Q20rWRo0EKUFCdAVhFWYgYyhpBVBgsYEVVUKQKjEJF9iD6+UrH3XmIIWnMYFRQkjeUsQ5RtEsWI8tBYuilBUAGFMvi11hYGVCIDKOpFAwOLKChy33vDgawhQEZiZmPJGIOKZVVRYiqRqvLO2qLfN9a2221HyM7kaSYiVemjIKJyEIKBqR/AANaBcUImIqwxDMpg3kWogRWMLdgP+mwKyYBvKxGfAiZqmVLsCsbNKvZmzUC+l5w1ETalRuObBi8AUCcDACWH2OWLU25VtQKGKP6Ha4wRDoGchbUBsKHBGDjiv3mtXllTLQMGJIJobhA/8ulBGgNa6adpWlZUtEg781pv/G7+hl859G/h7ImPPvG1DyS/eZwWNAwnVovKkabGCpNWIAHAmTT4fmqJ2FQ00g3txNOEg2RirNdvf++A/897lw7M0WqZS2rXNWxaei++1ysryj1g6dGgeuEiUAJJ0CXDjQRghntOASDxrrYqq2cp7aK7r032Xdncc2X26LhZAoD9YfNXix2zrvPANe99+b+ctfWc1ld/6apPfuy2N7x6J+eN2dXyxHPffVv7CdJw88pn21ov1S1JjQH3Pjh6/UOfLx/+2gVveOG+rL5Qjv3kmF89+5aHgI4ZWf/YkYnhS7vLe1rSNVVg8swefD7G2amd1/zghz968dTTAZoBq0pyX/ZOB+B6YwSUMHjPrf3zR7vtHhQFs3P3/V+85YPUPeXyYbEpl30HFRX+4ts/8sCL/ufGI48dXOFFWR66+T2TWy459PVfWypW2t3Sjk8+7zd+86HD8/e+64XvmTj2+HR543yvk4G1Sb3ybfNTep8xsg406UAB6DTOmU+bZ/z09DT2MBQGppBwBqJnkOHRYI3HEQchyhmWG2ceZ/DnYJ4zkE4cvFKViAZzCohmroP2OHi0xlgkAxhM8N5H1iI6IsB2v8tImDoU4bJoYFoCVr5w4FLriqIgIuei9o4haxBNVYUIqDYmERE2RkUFgJQJGBWQxKYOwcQUw1orqizMzAaQEeOYpqqqKIZT9CsiMg6NGHJZURXDI42i2+sZ64vOWU+tP+fJsZ9pXXh8U/fh9Qf3ZkenzVOnmqZ3TX2rH9q2PHH+oaFNhyropVi6Xr3Iw0oPUI2rhdSUZqXqMgkZhrLWs/2Oq3pJAItsAkmimisWiaALNDw83OGqWxapdcTqrdWIu0woISQPiOCsS6jGIkao7Pc7K70tW3decuV1j99/dz42NXdq8dKLJnbv3r28qv++cOjtU/f8zMW37HnMzswdP/uCzf3D5SnRb5U1AMjQdLvBDOed575Cfvi1DR7C3sdWHn+E0h+c/HSvl2OrrwcAEko8VU225WXXn5jatv2aly6cOrb9d95/fOb4jte/7j8/9I/P++WLHv7oXx7e+dapp78//MOvbJnc/GVu3PfYvhf9bF65jAX6BqzHFGulr4SCCHDZzamejTZXVvuNAArWl6ujnfbooUONI0/kvZXSWUsZuVx8lWZlRxMJASEYdhllNLmRl05wr8cuYZr39Xp6zo6qYeHYk42j+3HfM9521Fgy1paA1loAS5oqF2haAFAb3dTTYsfW4ddee12S4nKXTV0y9mkwrZH6/XsPHjs5KwKJSaKjQKOWmYjaR4cBOLP9ynsvzZZ7+Lbbm9t37GusP2/u7p//6O1uV23PFz77/W98b/NFV9zw+rfUm41lXW1k6Vy/M0rrskbFHhw1M4d27REDjPdeWIG5IvQcSERwzWdemZkJgUVCCCGEqqqiIUEkNqiFgWa5iJAq8sAcjWLHVAAQCBVADKohUopGLlHxQ1kqVHNGoxURVUJghahLxw4RPaqpKhNh04BKyD1vrWXQ3uoqWmdYrHgwWPlSWVQhMKdpSolRBWQgGKCdjTES/Q1RFeW06aKqAhAKlFaQ2RrDRSBjUSVEZyQ8PQPFGFCj9LFBC4Mmu8UBspEAwAAigXNucF5mMDOrJCAM6LwRWRYNqNRZRfQqorFjH1vNalVRwQCaNfmEOAMmIkVRQFDl2CcUEBBCUgOqA63lgdAjgPGaOlOG0KR8tezUE1wQ/8KpG57zxHfu2er/s3Xo59qPbJk6p91ut32SWicsBJa1y2pBScAjZAjch0KVN+fiRuonTurXf3jk9n35gRlZNzJac33rCmGzslzZzDj2GaadsgeU2rLXt5KE3AmC9hNHIVToXA2Lq/jEufTw5Y0nrq3t2WaOEGoHmg+Xu/+58/qH+mcftJeuwshS+cyC+7ODne11lG3D+bG50Kyt48SHDjYpO24v+0Zy8Y3zn6oYT8I4KCz44X/xb3vZ/OfnOR+95hJ39lTrGTpLZyeai5NNeryUE3Zs78z4Y+/+9o+K9tlP3ZH1azUdovJE05mFkzPa2nbk7Nfd+cS7b9y4rlOQG4LM5qdDkRcfyEmfe74H6PIkTZtZDZN271T9Jx88cdFbRYSVHRmScvM33z+1cuLErufd9O//64dbXu4Cr87eg+uuf+4v/SfP/rha5V27L/rMd+667WOv/dHN62pnj3cfWSir5d5IC8u+BwVs4lrUFECz1gtGABnQanHQlMY4BooEeVVQ0TXYLKqIRjKwrhHY1qYKICJARGfkagaerY8HMTsaHw1Ux2M8JgQ1sRk+8HXQ079yGiqICC4qh7AhQD+gGpAn0ysrRUjrGZdV1S0NITrX8R7ZDw0Ndbvdkn2E54AoV56c9awGWVXreY6IDFp6FjSARAaATMzzUQktWiYwIGiYgx+0lpCZKxU0pGiNMXmettttQBHRxKTGCBAouX4RKMkr4DQzp2Q5I8kx236odsnhy8vWpXtH5/eOnNjbmj6eHzjSOnr3ZWPNy+tXdCcveHJ43amhkc5QzuVcWi3mRZ2FuKoA1aMJnboZ7iz0OQlqaxRIuSKQBMlbYEszxWoClFlXhkCJJQ+INgK1YvYNAAhSBTEOnXMWEJS7Pbn5Ba94cs+DQTv1Wut73/vBi176kt/9/b/+t8/+/cUn7rnB/euuc1/w8IN3HX1mTpgaDXhouLUZYGPZ1szM9qsL//CPnnjlqw+84w1br7+h+bwXzX3qH2oXX0R799kJ19o0XlTbRjel5WMPXvauv53fNrV821eCzg+fu2l8fPKhb3733B1jh277r5XPfuHUX//eCx7+7rps+DGyn+xO677V2VMnEmurMu49REpxVxSt+omRbr/f7RkHnIV61Wse2986caQxPW0dSC2vu6zf7klTbVlQVYO6a9ewoWiX+9XMdNh9vviaOblCuc1sEya2qC2r0K5NTvB1E8X0qWT/Q+TIiPXNRJfb1nPVXp0vV6lhhhzAwuLMc3fteN4V51a+fejI6p0/fur5L7pyrI5p3jh6au7E8kpjdLLo9etJliRJWXWLqnLG1LIUnSXAlY5vZGlWs8J9WFmeX3c1CE8euveB/bff/Xt/t3Di5HlDk/U79u85cPfU2Zdc9ht/7rCDx7mVZ32uU8M7blDKMfSCIWOMBgYAMeJLISJSYtAIcY5Qo6LsK6RVVSGiD77ol7EEpCLgmgQxCaigY7EhOENxekSAAyMjUQQQFiUVFEsWFQgQWLjyYDFOmIFlAPSV6OZjUVBQgBAFYjONQMnYsqwUoVf0VZVB1FcOXMViLaEoh0iww4rFlJgai0RhDc0f34JEjUWAgQEhg8aTRUQNKsBAVCkHQANgGCwRpea0x4MxBggNgAhbIUR01rm1VkF8WASrhJZOB3hniAhBMCJROV4bBIEoYJIQEVmDREAY62Naoy9F41UAEFVDBIhRC2kNkDU4JqyZ7DIARG9rWGOIgnoxSgSBE5NUiMH3lxr2vevf8vq7P9K5Yf2f/fhr/zb+20tGjGVhVeMFBNg6BSQBATTYrzDFfGrSPXTCfPEns3eedL1itAa98VwgnChWGyu223B1ohAYqoVqlTv10XrPlw2TGOOM7xPlTW1faR64fP3TF8PDl2dPNl1fgJ4pz+pOXfn2n7zWb3re6Oadjy6t3nuiGE6bE4l1HARs4NAnaTaSo4tlPbHIPVfUmtb4tPrWCbGEn3xo2/2jf7LRHDtZ1e+mK7fNH/jl7uw0+OFrfuZU1W+O5zI0tC2dgL5c2E2uGavyv331zkNLB65+w7EdN7qLrjiHqN8+e3n6yetqP5wayz9/ZOM+e8Xlxd7GyFlL/VNbR4ZPR6Nep99RzZO04L7z0uvJyVPtWol5mp0Fczt++IHF9eeUY1tqoZwcLTf/7v/65l0n6kvTY4cfq8ZfkjFBbbi7dOxR2LTzvJdjmL317unbPvPHX3nlBRs2lCtLoTG5c9U1nXdOgjEYqt7pmfsZICzgtfAJAITP6jsP/DnOqHSfTdpOmy3T4MWDmDTAcAyAe1FrOoL84P/zofisV+UZHwPOQPzJ2jhaAdBYlEh/t1GHI65BJVNVBXvqG8hHm+12WzxnjGxMv9+PRbmigIGqqtAassgcRMgSGALmYJzNa7Wi34/vG0JAFTCoqtLrG0PRby0ICsTNDUQ4+CqvN4qi8KGczMc3bdq0b99+4xwa41GBuZbl/aASuG5sv+o1OU3qeZpnVconQycJdufx8XOeGX3ZyK6nh1cOjRx7aN3xOZj98Z577tm0fvP4+M7ark1zrQ377fp5F6gC55zKUm7qlGnZIdIEEwqhkaU9BbGUeUSVKoh1CbNACDVriqIUdLRG/Yp22gAArElqvQYNxKhpQvPz87vPOf+a59x8x61f37H14m4Tv/Pdr6+2q4vOP/uO5lsu95/5+R1LXyNXy4a7VY96whAA4Mft8jzxEIp9//7FrW//lYMXPP/qr9z62If+pLfjoiu//o3/vOGSG3/5D7rXPkefPDzzw6+O3LTjyIEHFu/bs/z0wcnNk3M/vqf3yKPy+EM8c3h09vjSc38DiK5+6rvH0+b7ux304Fspl51+PkxgnAKlpmAwxiIzKeXB9KndGm7aopJTM63Zo+sPHtbeCgzn3U41hFRxMC5FDpTXqomNlDdXV2dtWaYh0LFjRgqaHOXjJxKoir7HU4s0O12rpzq6sbuurps25vseC1Z6KFmnT0DWIFlI0iQ5NX98I8CNz73opu1T0F093On++9fu2nrWulpiNJQ+18eemm9OjJRtHxcMi0+SDImy1BljOtzVUodbzQL6oS/Lnd7ya5srcy/R3gN7qn2tY6vZvH/1Za+aefq+xAo/dOvcQ985uO3ckde+xK4erRKoYeISSiXzliMuSTDq/g8EGskagxBQMSgNtmxQ1aKqYrs55o+D1jMgGwQGiWgQgxznTIgIBCyxXIs+WwOER6zhAA1GQYnBG6CAKHMQFkXRaLeghkiir+z/64rnhfM8j1ygsiyjkB77oAih8gRYcRS8TIT7xhgxIc5TI8GfjIncR7NGrPIEIqIIKiqgIoKoHLwiiAZDxqA1ZMiYwRGioiSBqKqaLDhCzJzLTRq790SxtTyQ4nJk4qUDVBFxaRqEq8DKrAPFQGOQEsDEJpEMzczAagAMEpioHRQ7B4gEQko0MBQCRBrAkhERkIyyAACqyto+GdvUbMCzOgM+BGvTgiUHXi3md2265E33XPp3i4fu37b6tSN3vH7nS/cvztVTU4kx1iM3AAtERswZe87WhxqdT34rfPrJnFtJ5pMh6dbssQ14qOThQ3Zz5htQLYFr9U92/+odYxua5mc+uG/L9qnd5cPnVQ89Z/LJK+zerW4GAGb8yBG46Cv4pnW7XvS47vydvzv0p79xybeLo632+CtG0no7aQZNE5pZCP1C6hMGgY6t6rqx+qHFxa6BfCyf76+EBESTB+fwxrHVp1Ufpy33VWelajvSuOnJe1yYx8bEwt99uPrkeyt0+fCU33qWO+d8OueKdnN554OPbChx5Ft/93r58Mcv/o3vXPXzQyP19TsuXtp9VUF82dTMwZH33/ODX7y6cZK8K7vPsgMqAfKs/YVgHDocnxpu5thd9idPdg8tzvV9t7lv38bzzpaJYbz47UvuvCM7dj3n23+p2eaqWUtWV9sKLmA3Xfr8wSEze/SHt/3d5OJj2xvnLC0ttje+qj9xXUlSq5ZLqAVuU9aCXoxtZzSBIx9IMLZOeMAQWnOlPA1dXks3ow3zafEWWAvP8TmhiVylQcxbq4MHPZ8zI+8aOyiOnHFN8HIt/K9V3ACigmtGTKKMCESEzpExxCaiO1MkUoFUyCCS8WVSiUdAD1JxAAAkYtaqLKxzzIwhYrMxSZwxSGQUFVAMaGCvghHtiJRYZ4kIgL0PRBQn1LHHToguTaLaQeKypaWlXq9nDKZpao3ngKmrsw+pAZOSL3wjHephVRa9ggtr0wTqINg33aJZ+FV79tHaedl5zxvbNT22si/sPfjU4b164sDoAd29buyidefOT5x3ZHLdfmotlMOlTEsvXZeEQqkvvbzgShzWA3FPqizLQBgFTGJDCEHFORcYB/xpBEQMPoAqkAApCiK6ei0fHslkbuHQsaMvf+Ub9j2xx4deVfmRsckHH7hr35OPvOGNb9478dIX9L65YTI5tbSMmPYAG0AA8LGcr+4O/SrD0S9+prr0ohd/7Zt7P/Z3vf/9vvP+9H2dE6v+4FPrrrz+rvseGDs20zo1PXPkmZ2X7JqYvPrs85+/98Pvzu6+i/c90wIjm7bJ0OSBHVeMTT/2UKf3KerNSdWqtVSTYVdfJOMUjFVNVSsmRRSogDLEbqg2jg2v3vvw2InpodnptNOr6rXEJ9BftnljVTmTqp6Mtsc3mp07NGm6B1dMuch1gMXFbKFDo5sXQ6BuCe0e3HufP3IIztpsgqm3mmZ4tD8y1OI+IEtRQZpZY8zU5Fg1S+du3rIKkAnsO3J4fNPI97+5B126a9dmkLbY5PYfP7TcTdt+VTykxhiVsoI0qwH4wFWoyrSZJnne6a6mRuc2H/rKZX/fSbvjX/+txV0fmfm572+8f/fNT33ihi3Xnpo/VdXLo3d8vfrMJw595F3rzv2P+rrRqkRO+zUYUiuJTaKBgaoqSFgb3Hph0cgwGhjOnab8R9CvSHS1p35ZYQT4gGENAJEjSoKR1wBrhWJsO/hYuhlEAjRk3GA4ZCLFUYLEFRuElYVVlDAxCVUgA/rQs/m1AURjFMQgJGlKhEmShMqTghjs9/vMUdabAquIuMyBaCKAqLGdFZMPp0gEEn0VGREZGKsQVERILRkI7AiNoCVCi+CIiCzGKGwirymoqGqaJISYpS53afyXWMhqBFIFjsiU4D0RhRDUETElURBbBm721tq4ScUzJSIgIEMaU5A1BjBGz64IEB1UtgBwBu1kTexXKQp9S+SXkIJF9gReuGGpKMuciK21Vf1JmP7183/u2/f+wfEXj/3NzPdfuHJ9K615rhJINEjArjFOgQx4LWF0nL54Z+dT+2rj65JqAUbC0Xdmn7oyfQQAVKXbGPrX7qu+0r2hU/afOzF/E+xpHLn3yLV3T5X7UvIB0/s7O77de84LXvKSl3+KLrj80r9+49nfuv3g8MaNG0QkHH3LTRv/6weHni7bnZ5urLlH+gsma+ZOLLQTCGTo6JHOyy7eefL2k0UBFuRUqCUGlkd2pQRXjbc/AYGCG+m154bGdk8f+7nZb50iJFpcl9RC4bMA3fZBO/MEH3q886m/MmBHCaxzIRQWzOaZx5eWZssDpR0173je8ALSg62NZ121Sa+8c9/Jx8YXHp5/4gfxUienntw4VlNfLoujBNaZetHTvFWbHB87d9Nwd/lwr1c0Nm3sjJsqmWxmO+9+ei/UL7j83s/cM/XKtB3KWpUF6kg4K0jZLL45v3HumcfyofqKOCtnh9Zm3b09kdqilC5UmU2hrCJVd9AGiZqjODB5HAxcT09/RWVt/eoa8IJ04BiNoISRCT8Q/B8gPWKzea0yjof9f8S/AGCtnTKgIwvgadB1/FqiKEYHiHg8ATJoiAZ4BlEUiCmsxERdveaQWky86612G9YVNdOpqpzy0G6bxBVFwSKJy1iDqqIqWQMQ+2WhVqsJqNcwMtzqFX3PzAykxKwAogaT1CorALEEEAWEitlAFJIja61IKPvdTqezYcOmuYWlPKUG2F5VqKEGJrWhoYOdY3XAPmsGzqKiCYFKJWX2ECiYsjtk+kG5Zy5enrhk+HW9evd4euj+1T1Hbp85avefGK8dOv8ie+HElvbQxceN3TNUO+g9FdU4ElMzyZb9igUqXFqVZd1aleABKXGCa8M/FVKQwMKsLAogQKrqvW/VmyIyv7hkLYQQDOWvesNb/+Gv/nx8ZKSqXFpLO0X/H/7xY/8xTHt/mf/qBeZnP19ADZU1c0MAoAsnH27ki3nv/Olj9739rTPbzoGD+9YhHXt4r7p/GC/9of3TrbExW8u6rTy5/kW9s69bfXL/obnHzcFnSgCfJTNBmssnUg4Hzn9p777/+HOzYiVx2XBwhVkoTvU6o8Nj3aItBgIXFiyWlYIImHZYaSIs3frDbdMnsuUZI5UY7fa6tSqVRtIte5lJyryZ7DrH7Nhla1Ne+i2AVgg9Z7iz4men0x27sNBwaI+t+rT/mVq/UwwlhXYJbSCfVdyXChKDqQvsbVFW08dPvuKqV+48f+vnlmHKPw5m/ef+44GZ4/0Ld23cNDpUy3XPk0ePHFtNsqToFIrYEUaQVqu1tLxqDGapWT81kVqzuLhYr9f9WOdzV36woG6YuYC4vnrut5g7xy/Zc2Dz7aMPrLNEYWH18tf95vRVV+3/wO8e+eI/7Pq9Dy50jhutY5qg7QnYoOLQAICynpaWjDKTkWpijEFQiH4MA54SR9suFCVAjfgqVlKCqG4DQhWjZzAUx8MsMFiUcWWLouiaCzEFFVBBFQMoCB6EB3k8GiSDZBwhrnnQIhpAY9AYg5YcGZe6qqqyNFXVtNks+2UhQQIzsQERgcAsIqFSsDbWmE7XHP1igeoGmlzMbEOg4FGlUrWKBoiNDGplMqmxzrg4vTLGWENEhIYcgKo6dkhonUtSZ2BACiIiwOCcgwTQkK5tPcZaYBZjwKK3rGsPl1gFQCIRiD26eCFUFa1FY093tk9HXSKKDoox9mrcojS6QTwrxgEDKBYaIQfkkVXEoCGW4AzYjLBjh5r/PXnJ7z717RNnD3340c+/7+LfPDA/k1tWtmC8QqKKooVzjXan+38ecWkzXTy10vDLf976s0maq2m3jn1BGNLVPxv68H9r/N9JMzdpl+F+ONiZGr7gxvffd8OPFi/+xz9++a/978f2zbXu/PVLqvJLN184/rmvPPm+Dx869+KFj//Zeaj9nzy9es4Gc9+PGa5N0tQmI80FXc7QVgKlVxWxZBX56ErZIDhrUzp0yiyyLLgNv3ieHDx8atmPTXZ9Z2SoWOr/8X0f9X7W9OsNJysEhq0m2HVa13Hb17Haxn7V1Q1jYaldL3W57jfrTKaWGtUzvf4ffaF9/rGvzakPF9xCGy5qmRU557V8wS/GK+qK5bkjPxybvad16IkJ6i73etbalX5vYX5JzAjWi42bxqAOxXz38ZGdd3z7q82X/cZZD32j1Tu50JoIqfGVggaieh/D8aML15+9+5wX3PTkrd/ae2h1/JId2dbd7Kt+Q5ANct8rhSRjCboWZTXSkAZ/lzgHhbXyN6h4DhhUVQXWZGIp5niD1xiIuEjUnxLzBsGoVx55bj8Ve/EMVNfpsKwIqkhr0vG6VqCvwaIHtTLpwAoiokFiepqgJSIDmAbTqQK7JB01UJay3B6zLiRZu90OZZXneVEUELiR18qyH/rekk1qeZo6R2iRxKAIn14OMT8VERYJoFAookmMYVYDHLXgBdEqKWFVBUR1LlXVubk5NK4soNlM+90Vk6b9Slf6p8CZsiqyzFBIvGBSgbEi6iX4BBskecGL9dz1fHE0qYru8tRifWuy4YoN5x9rrBw3s4cWnzx069MH9CdHt47dv2lq5NUbt62On33IbD1g/GpNEklNVVKTADM0odNP6mmaZ6u9borOKZYqABDFkU5TPSE6xxmupGMlVaSAZaOenppd2H3etc+5+cV33f7t+tBQ8EqErebwStV7923Fp1/ee8HZ2Q+Oi+EcbSKh3HnhOQf2Hvqz5tQvm+oG9uUzezpJM5x/fvcb/0Ff+/Joku/7peenWcNi5cemtvzhB+a+++Wx9qnsm/9Vp0ZwsK4o0A5NM/zLpit8a+rI09+q+yQk3iFQD6FG3/nm13/51/974QgN2GBIKKAhhLSCMVE6dXJi+nB9ccYhB1WPkhCXY7Wq1xWSen3EX3RlcdZZtbM3FZ7w5AyyDxULpokUdOpwmD3qlueKpx+vJXlAUGtxbGJ45yXiceXE3ej7YCAxtbJY9Q7s+onhP3r+G25q3zl//JOfa/zbdeUX68ceALr4a8Mv2Do5kpTVwVNLjz19TLRGXCkHTyZxJrVJUZat1vDIyFCSJ57sfOFxaH0H3cPZfvvEOzNxtcWry8bh9viDgFjrbbzH3Xpe9oKp9kYYrp08/MTWi2/kN/7Rwb96y9DrfiGdXK/cKbAvVc1gZZDAWFCNOog++H5V+qIUBGEVEbDR0ixal2hiXafTievUh5BaV1VVz6hBIDIgioKBtEysdwYohmmtOMRhcFSXjqir02m1DKTwIh4KRFBRkciCQWFUQWOIMBqnEJIz1hi01gpxq9W4+sqr7rnv3n5VJkmiQet5jsGnxvgqlP2KFUwIYCgy7eLugNaQQTTGGWvQMokzRp0JlY94aEFiZCVS1YwsKVo0hGScMZkzSogYcciDOpgIER1miGTTxGWpO2PbctbhQPgPwBIABBVktkhRb8SIgahD5L1VEktJMuA6M7OImCiAlaaGDBmLhuJ+GsuWM3a6iL2JEBQVBaWBeAKeNvpFrQATTFCKyigba5SysmRTJExHq4WXXnTjl35478O76avu4Z87eN+6DZcsFidcQg5GNDrVSD0bTh/bc2LRQxPaBswb8m9NmblxXBqlhQyquG2zUh17/zR/S3f02le+7oa/+7q+43nn3Xhh772/cOsj8+U129Y9+v2n7nx88vkX7Np7/8m3v2nL5+48ef756QXnNM6bsvfsXdq9e5JuX9xztJORK4Oy16ikbQQQYa7DU+NpURt/y0fveukFU7NLq585MiP5xL13Pf7lH8yNjQz53KwuJn9z91+e17/zGcqG8nY3pFnotIiWyzBMo1j2u1Wn5TKQFZ3YLZ64d8zQyNbFlZovAqYbatxvTj6+9VdSn8rKCbt8am7uxOYvvf2aK54Tb+vKpud0t954fNer4Dlcm9vbOnzH8OE7cLbX41LL2ZHxsdUkHD701Parf+GCF55zX/1o+1irlX6oNzV6sLUBAtQw7SgPZ3gM9bwR+75fGHrfP71gk7u1ZjurQxeMLR3tiimTjR1dVJMY0TSUsuZLFt1zZDD14WhGeLpJrAAswiIUi6do2QmDL4KqEiiRRQWwA0slXUt5Y/OZ19bamhTHT8VgAMCf/jsiRBIgD8Rc448AEGx0fwAQFRWOoEwYlNsap1FKpAnWWs1QVraq8tT4sWRhdbnqVcPDw/1+n1kTNAAS+mXuHDZqhYa17hoiorUWlEIlKkjGiAiYQWEuyiKEEryoeA4cGAENNRqN7nInEotVwUZaARgvzAInV9tAOYEpoQRDTkDQYWAHRCgVBbDOgsUglUDNFTZrza4urUtGFotq0mGn1m2bamm+K6VuhJFzWs9fHu/M1hYOrj5z+PZnDtYPnEr84xefC9sbZ8PYrsezzSfHh9qgCZYJ9IeSVa5qfXYBRHyPCJ3xoYLAEfXOwoBgnS36Ia1b0VLJgKTWOpYydfXO6tKNL3jBvQ/+KERPuyoIAkP65X30zmP9v31huOTzTXJBbE19sX5kasmemK8W/kayCvWStMW+75++dx00EsACdGtNiqJP0AtLtPKuNw0heK6G0PUTa2nqySZ/E6qHy/7ojmvXl13dd48Yh6Ysur16uq7S5dmTh0PVV2Blk4srGTRJuOqaftmcXxx55lA2e6SsGYaUnAsJ5T3vegVWyBdf44e3+q1T2Gp11NVHR0K7gsSKE86TpO31qUP99MEw84SpVitZNWlOHZWEqlPzxbETdPARj33n8tAPBtwwql1dWg63/qZrzGPzQgDg3lwKvZcNP7h9HKZ33bIidGym161tTBojy2nianVOa2yyDrpgkmmyAcwgH10jIsrCVL66EGrzvn7y8PPeUuuM9YeW2nZ52E8dm3q8vljPi2aa2/lnDmy78YXHv/zq2kpncaiol0HKxJiOIKq1VdTWACWiXllUVVVUpa+Cc2kUlICYMIKqsO8FjV6ZZLywklFLaVAg5LLMXCKgKtJQJBErir5yxBbIe48ARhkVPCtbtYTe+7Hx0aIoyspH0isTSvAmoHG2QmENOVgR8WWZJAkRKSoDG5eqIcu4utK954GHiiCJyxHQkLrUoe+L2MqUzhoRKYqBlI+qOmsZgVWcTa011hgitNZaJPYysImP3iMAIQRjLRMY54JqkiSUJJUPzlhDBokSlxg7EO801trKIKIlcqd5F4pERDhQgI5wUBFBEauGGKwxABCYBUFETJ4iYgpgkKy1iuCFRNUCOuMCikECQ6xArNEuhqOGqgIpKaAQCuoaT1QhiBIimMjTVCJFMCqipQVEtQSsGioXv1eu1gbXxN/b/vrX/eSv+8/d8dHbvvlPGy/oiCOxIaksqkFXaNFCONZVI81mj1bLzo31u5zKCC1bZUbbllqG/WVuLcr4nlO7L7r+lpO+3hhb/tO/euD33rrrw3947qe/c/x/v+s5u7bbq8+fnLD0lj/fe9516z/zl8//0cPH3vXXD/XXbfz0nYsmrfKtzQf3lZbaSaE6sq4s55voSrAIcGCm+KN/mnFD+WOH4d4npmvD9d3P3bB48Phnn+xMtlpO0+nZxQ/e9/4Xd+++3ydjlqu+E1eOqF3OhhPyPi1N0MR5g2rzIXnkMYumk6T9AOOwvH3pxANnnZv9/6h673Dbzqref4zxlllW2f3s02t6rySEQAISitQLShexIcpV9F71ioIiiuXHFbxeC4iKIIogqLQAgdDSICG9nySnn93barO8ZYzfH3Pvo3c968lzsk/WPuvsrDnfUb7fz7fw5IetEcZyTuUZVJUe33Ni27sW7/zk1uHz6DWTf9hpzbTPeUFx6IVLl//MwjW/bIuV8ZPfmzl9tzn5aDF3JNs5e8//PPzk2Ccm7/oLkz/w6M/e/btvTfu3nGw9eohEWYbleoineu/8jXNPPLn27eWrf/KNf+6e+ZW9xZHkBK1fe9nIj5Qf9I3NKLcEkaMIsASGZrbMAiABILL8l9YTRDRgZHHiGBgBgwvoUWvdKLbQauCgABQAQFSASpMCEoRNbBo3KGnQSCLiG5qMIDQb3zPDZdriUcetzEvCJjClkXHxFqRWgiCSaioFAs8RCBQQCkoEq22M0WPANGEE9iHTahrGeqZwLhDaEELtpKgLo1TazdfW1pIkURSsTogIlEaBTNsYHZIWjkluNwZ9BhMZUMNqvdGSjonGpMo6XwUfQYsLaAl8QERrbfMmWUSCRPaglFKqqiqlFAcmoiQxSlkfAodgdcoRahG01pWjhNrOVRRxsegZY/qoMCIh25iUhlexXlsvuqtqH03tbu981vQNp7Pjy6b//fd9avbGy6996zV3ZSfv0Yvb5n1yOlx9esf2xbxsU0SoDZIFqh2wUxgi0oiRItfIKFCV9RR5dKhRmYSilhC0wpRVrIa9zuyObTMHy6VFIVciA7EiTVH+x7fSO36i9z8u2PjgDxIyifjyvgce4YyMbyuRz4K+p9PuFrTdtK12iqOGpGa1QY70mHYxT8dUkpZB962at3Ck6q1VpacIL4tjL7lpqL/bf19f3ZzInTjWnarqngYU7z/1sY/85M//cn+jHECFaUxcp7U6bC09YZ58Il8euB2zkqdx7nSagPGpA8Pbujysefu+5Irn5MP1WPTTOAmdMTVRBDVReaIwAqNMsR5++L2sNqQsR3ahhhzViYUIt9qnDtu547E9xlXpTZpDSQPSEEbb4clQkjaLAPCn0x+tt+U9mnKYwioAAEzvgWlwwhSc8zXGKtZFigzVSNUl+UpHN1hbRpGxVjZcXfrhe35XjcV6doOc9u1R1+0rREAJMPfL1Sx0EyWFuDFKRemxH3/2iVPHWztn512vFUdWa2SDiJtGWEQXgwveBd/4EBp5glLUNGHGmKJ2zeCLttB0zMzCWhsgyfPUF1VTobvIQMSaHLAXRkOoLQmwR/GiBTVS4CiE8ysrBglYcpvUjfapYchHFmRmcEq4LjKbhBCMMUTqzJy8gVcWRZFlGTNbpVGjNQYS9C6C0qrBZGpd1zUqSpVmESRMjLXGaK2tNgCgrCEBgoiIpCIAaK2bG1EE0dqIiCZlUXHtldFN4a0QWGKTztu0qs2xrdUmUBNgkwoEwo14qnFVNkIwZraJaX62FGPzxabWQUMKUJMSBGDVjO+UUkYbEFRb/o1N0ZuiBovfdDmNkDUiNrP62ETT0ebQshlfbo7ftxom3ho0Rl+nne4zYeXig5f/1NfO/7tqdOvu9c8/8M2XXPGjC6O1LLiaTApMSjlFUPsCYglBox6jgaWgUABNYDhWz56XnrQYWLglp2wOH/nHR79yfwIdPvKhIzc8b+w7D6z/6ofu23+g9RcfeFgZ1zlr5n/976e6SbkSKaiJtG3ShvhEZQtVqVLKYGywUInptzZC7EfhpLvo2lgWMctie6qb77Sj+uFe77HxyWoD61Dk/+vpj16YPHKzRkvlsvdpdxxUfqzeyDtFrJxC0ZkNENDEKvpElGSdqQvPefSBe88BOrjxtftV2+mlgF1tSumowdxiruJUR1/24glJfvdM+3f//R9TxcZY2T/rgXebu2uavWQ4fsnS7stPHHobcMg3DvuddyydukUKwrnZuYt+J9hoKlh+2SfzWtZO7rO+/KkX7+KRcmNLz5woU73wxe0XLWd//qdrH7jj0hcfk55aP6YYnOI8SY7rrFedBJAYJHpGxOhjg2CLgUERAsZN8sampkFAvI/sAzMr/E/MHDsmItDQ4EsjIqCQwkjIIIJARkmIDa6OFCo4sxNGQdjcI291ubK50Pl/OuMz82nYTDdEAGBNwEIstokfBQ4goImYgUgprQAAxRFAZCDM0ywh70i7GEwS0szWdd1b37AmFQZQjWSSEDFGBggFRmMNRfDeG21DxcToh/X2drtGPHLq6bWNlUsuvDg37aoYFfWamKx5e+w3OYjNzUcBQuTKe6VUM6NCFseFTVNu/A9bdgYistY65yLHxFhmJiRgIaVQYKiCDtzxiEoXKvalkv7I9mQvjB3Ipy786d9LutY8oH/MXmi76tHkxORlk0evLu8d9s97HHcft3lle7BOZmIjxVYdKwnjwGRVFRL2wBAr5JQShTpwjORIKc0oNVA7XVtYGvQ3bGpLV5nESmTxEQjvPlb+7cPd99ww+scHS2qNsStFokb2wNJKV5kXR32JHgIkxkby7CvQScwozVM/Kom9H1bQDpntoFBwTneQ/8zhoVb+4HWndv6aXBrjCwv1JVP+6YiQYowhxPvuufPQxTuec+1PnFg91WWS3nz3+DPJk0cm6n61fVvx/BeM1cat3dwbLhmoQouTi1/OfoMzQxMp0TiUQxgWblSSNdTNM5sFJzrr1qGyCXkpYmWAXJuyUQy0NO8WjgGwb00WVE5SN8ZBMHboV3U3idpn08mgiycO+YcPhcd2hWfa3KuL4ZG11peeObiyPqfK9cqva89Gp5ntKKPTblenSYyilc3GxjAxkz5ZO3VkaenE2PI2Hu+72I/Gg0Cvs4CAuk5Y4o5wdtUqU9OasdujL1qZOXTgBY9+/g/x3AviGvtWNTIYEbXWVmkOEQDqug4hRA42SRgEmOu6BtgkMRVFpZE8Sgxh84BstjsgjcRqY2PDohJSItKclAoVMKAgRJYm96C5Eq0eloVSylprtOYYlTIBUBwHBVEkEIAEjrw1ruUG+lgHjzEYYzhE7z1rY0AwojFGEwqw1oY0Eesk0dYY731duUZotknACEEjpUmqSCkiYwwAIGyeV80kQIVNqbHW2hrduIBM81MS2Yw2YuKtu5LaEkU3g0HY8mAg4paBiBp01xmwSdMHg6BSRCI68pm5HTOLIhFRpESkCQEkAUVEumnNm0gqINm0miit8Ez+Y+PvbDQ5/8+sEBq3MTczf4DwXwALm1slY4tQKVSLw/Lnn/vzN3/mV5d/Yvt3ZPFFrm5RUpPT0USshQVBR0EdhgCtEmFFpmdpSEgYa4t4IFkSkZJtYLXQ3v83H7wzmTk0cbaqoVgchU/evDgxvfvOY9X3Dg+TMV2FyYlQ7r+sM7/RyUdVJyEZRenG0kMmqajSqLFelvJKMaV7L9q94/DG+hOkyvQvRwg0ph0wII5UO6xWPOGiIIHeNzz5pecOP4ukG/cLIFMfBAhRuN94VUXqZvXZzOcFCoBF3C6kiPlfpH3HYNJq9qWAr+PUbp0a6lX8PW38f2Gkp7tPTie6H3/4YPRBGa+eiuYLskayqiBpeZOFhRwWEsE4gDdXjz4ECCAFxNPV+J+x22YyvNNlwwD//oO6nStzrutF+PpEcjfomeE3yke+BcLYrExxS3pHaNmwi0KbcZ8hcB28EoWKmjgQQgBmEfEhRudjbHJGuBE9KQ6bxHXnWelGbM9BPACikkYzpREASGGjBqHNLndLF71lZ6It5zGc8RyLiIhiiFv/0iw/ZAuwRZvjZ5FNfAcCYmh0C4iwKUJEEQFFpvKBlDXRBx5VpUKy2uRpUnoOIViTIGIzkGuM9WM6HZYOkWL0EoRAsaZawyCoOg4++w9/VfbW5p9948te9nqbtAoofO2s0gK8OaVHbN6SMfbQoUPf//73W92O2pyvh1Qlm7PurRQyFCEAoxQzIrDVGGMkQhDSSgMyxai0FoPCbIUsIyvyMbLKhvWo87SMfLE+aWa6xcJILjPbXu6u/7nio199+ptLY1fEN07sXWidf3hyZk6m19yIvDZpqWLbBgAkVlbA2JxUSqhEWKACBUIcVGwn+ejkBoeIbWNNpkltLK8a1ENXTk5O/vVj3VceevqvXk5/P4t1a/Spt6w9sw5/9UD7tqOFRsqNiWgEtABh9FprHyOEYLW2ANGFTpZiZXwZAlEna6+/exHPx1b9PBLbv/RrYFkWMb7S8+OSf7VtjFlZWekm6b9/8gvPvuRF09mkPvzw1MIJPX+4HUMvyfXV13aueGF9/ERIVC4TvO8coIDnnOdoKIefjqz9rl2+Wsb+IKwu6Lzlc1O4um1TRgoh6oFnCqln1lSU0Uxud6O1sVCVyGy625yt2Gd5p+6dWrn6Eq0wEsaU4pgsfXLtuX2zr+OPsqueGozlxb7/WIcd3Ux1u6BmxrMZkFYNG2meDV1FRBr0eGecrF3a2Di1dDKG4aGzD9bHzUOHPpf3psrxtSg+ap/2u0mR29XOiU+fuPpV1+KKf/yhf/7oF770tnf99+dc8CKz7kerKzw2uzZcyUZkNDGRb4wxACySJEmat3uDvtaWIWpSSZI456qqUsp4jpV3pJUxBjUMh0MiJqLRaICK0jRVTJ4jkvIx+BgaIpZVWisdY3MjiCJQe99WGhEkxLLyaZoGCc5HRmbPqtFqRgYCJqyBQWB9fX3TfrP1UEqVsarrOkkSAmlokYgCwFanzBwjK0ZLSkTAWBFhRQZNY4tq8O5NugMCISBgg+WRZo9FRMjcrMQIkAR8jKRUjDHyZvHbHOpNFUxGMwiAxMgcRalGogrM3Lg4mPnMcbi5bOOtX28pWRFRKdXcj4Qac3XzdjfvYJt2wCgAoDQ1eRQgIMLCglsnLzfDQpImzab54hkb11ax3wSwI+Pml9QoQk5GkpHbaKed39r+E799/JbvTj39/aV7nzV+lQ8qAqYMtQ8qMhiFyhikUSmHdz7/PPfxFZiexTmUkKt65PUGjxVR30tX5DszKgKS5IPUWl0mnlRMxvJuK8/celFEMPXjJ1uUVBmopYqiH8BijX6ElE5NtqbnHr98/vtxe+clv/Mb3eHIwc61cv/ScPD4I6ce+cHxY2ddMr3vQJ4nzzzxAOHYpdXiT9//11ODwWndzr11apR4W6Q61URWiwsqsa6qvKtyYoSUXRRNxhjHTpAhoGp3x6h+hsY/cv7PLO49h1dXX3H52Nn7k//7uZGPKwdO3bW3vu3Mh/BKdf65zzwRVVHZ1HhKmdZ0oIkEyhIjH3l9+wuvPoGrPwtx+8Jlfzi5KGGc+i0F6zNY2dZfvxeFpyH/+evOYq7Gu2P/+B+3fX2tvX8Kj83Rcy+nmw4tzZVJGgVQOxl2bGZ1q511J2jaOUdE3nsW8b6uqkppalSEAJtS5xijr+rm9D3jHhQEoqhDaEYogTZdeQCgWGtHRCQITWaRUopjRIGozrh3+IwouvkUbarzYVMRLZu1OZ3ZG29es4KIyHUA0+xemGFrbBOFtcLI0Ai1AKmZVRNpJIcYY9RGyJBzLsbIbLjymw5ABBHxMRAgM/SjkyBGwGpTKOdjJODpTiuy/uq//9vUWPecKy+tIRnVLoemNqMzNeiZS4MRhmXxwMMPpa08z/Ner5doQ4TOORTYjOuJEZv8qOblRhkyIVZEwABKKxFRpJufCRGNylIpBczaWgXgKaYmLTgmrY7V1i7GTi+Wuv/Ria9vS9Vb7x4/cfnSHXc/5r9PD79l384Ld+4YTBw8mnTmgUZcsCqkBuCcxlOWSHU0ViNlPjVMrKJLIiXmofvuQ+fStDPoVaDYpgkF1loPBoPDxeiDd9kP31T10se/TNceGo+HJuCmA72P3W9/7ZsaiJQ1AbhypUWNSkVmQh29l8iUZNDZxumEysaTsVnaOb790Jg+Od0unlu3jtTqKUgBdgs8g/gmrr9Qg0Cr1cq2bS9XBx/9xEd/81WvlyeeGNs4olhKHyUbp+2z6bAoTz1jjIG9+8pnX58c38h4oMYmqqwDvaKVj5fKEES9ui5zSy1mZxRpqcLQaIxViCSSmEb/q+IaYV2AQZ2KsAOOmsz6RjB28affpNO8M5tMa0/g17wvfXVKdF2LtXmn5/ekO3bvGMtPzp9ImJf6yzGsjOdjo7o0iUmSRBlT+0Airj8qwnCq3d6xfe/K99s7d1+5eP4DemVHObFWZBu2122ryfAb6u4HPoP9UQvbPzx2x/j2ydXDp8dfYMJ51xRSxfV5IYnBqLJUuBkCKBAFIMaYiRhjmkMGWJyrAAAVRWFiBoBGrqWQmrq4WRIzc5a1yv4QCZljlmWEWmcJK4xEmlSDceIAEsUISGQxehSdUWZUlVZpAqUwSIyR0CtkZM1oQUnkoNFz1KKam0Jd1w3lgrQSiXVdQ6vNzEQUglhrYwDYFFMxIjZ3KxF2IRilowh4T0TC6MBrLYgRAWIMUdjF0LxKa40CrnbaGOdcBCSiyjtmRuEGYKKUan4RQTTH6IOweO+dc2eUWUQkSjWzvv/q6GjwWM3gWoiaqp8jIyLQfyYck2xqahBRNsv0M9EI3Pw3wTkEIdkMaRdscJjUuEo2q4S4qVAFQVFb6YFNO4LQlB25SkK/jIGhZZd78zdccMNPLA8/NP7tv89/cMFwbxRL5DxxFaOUJRJxJB0V+NHJfa87+uS3LmydHrqiHdfm48xanQDwXzzzyo2el8kOGt5YrDgAj3qzmBc4RPFLJkdKIYxijiauiAjG0Z6W2jWR799H1529/dkXXfrKt73wpvXV15968uETBk69ak7vYQ4x7p/O07e/+nn3PPWOp25+5OH3/pt54L6Dx8Kr+l85/+hnN6qNSsYuDsoD1ASdmXHXrygfdwO2GGMVq6G10SbipOmIx7I2zajFjWjrQEILZTY1cygcu/bpP/733c99cPs5zz2488u/ff9bRgvP6z1yOSw9IFNn7tdDXtrLtg6mjBFzndRhh/MwNyjBmNQeO/FM27+wNf/7a2f/LW5b6c9Ke13BJGmkWFA37E+ovP1bKy8/d+zAORd2ZWF5fccOfU65tDpr47fual+rd+6fLft+YL3oyb1JjEaU5aQsCyAkotpVIuxc7agEAGttkxcEvOloCJG99z5yCKG5ipsKz7tojFGAjFG2LMI6Gmr0jlo1L282TQQY1Oahvrn53Tqz4lby95bxTUSaEG7V1LKbuxIGQNFai48MzLxJ/GhIqyQQHQCLOuNqAmxsF6AoyZImQElZY9OkLqu6rlsZ1QQxxi2LI0ThWNcmSB2hRFAomjCzcHpp7tHDD83a7lte/+NXXnfd2OSY26i/devt/aqXWCVBSbNKF0EAYfYcBaj5u9feYTFKshQFog+kgL3fKkSCUspq3YSpuOC12pSwMQOD+BAyokCAnpNIBjUY42KwpFNUXBajXCELSmWihHbCWgPHbYt6lg7JSy7fToNLRqcXtj11W7U4//ETfDC77dUzM7575Yk9O47bseUWMGr0IRMQNswabdNB+cASATQeOXIksSZUZTUcBa210c4VzNzpdAjk7ZcNAsNL6n+9LXt1boAFaoY3XdV6Mrnwi8cmOelgaxLTMduZUe0p1Zoy7WnVnlatSZV2/2u9wrEOK8shW/Gt+aPPfws8BTCFMCXQEt7Nqos0pCzLCl/qJDxx34MnO53rARa1SqJNOAizcnHDrYqh9PLnVnv25Lt2xRJ7vkqjDRMd6K+o3GBm635ljx7zTz2Oiws6Qmwpq8hXFVjdbXV7YSiVtAh8MVTKBLKZTsNwXRDJurhQLLz7Db1zd2kxE8JuhBNdWUsxkBqw4FrsAsgDcv322T1U+P27r8iVLTQzB4bIIRokrj0iMnJvYTmsb7S77aw9Oeq7WTO5/Wtveurp/cvPfmguPgb71s/fuLz/22riZPWWn/zvH//Wzfcf++ZLr7vhZ97wC6XNC4Eds1Nz8wt21+7hcJiQVAYUAoeoIiukLMus0ojK1VWa5s2qlQiYOdQcgxB71AoJkyTxjQM4slIqSW1Z+eGgkMDKKoFIBIiYGNscCRwisKDQZs6BSJqmVVUpgBD8+Ph4Xdc+hkbKiVEUI4koQhHxKMGHNE2D88zQaiVN1+i9r+u6+RRorQPEEEKapszspU6SBFia+07giATee0Il1KT2NscYxBCaQVgMIcYAhEHYOcc+aNokRzKzxv+EWFWuBhYjDACGVJN9RCFUIiUXLFzXdYWVnNFIa7LRNAfhZn7RVuuJsHXKatWU3s0960yXDLDJWGhsYRogCjfn+uYF0GziAZFAIzWWwUYU1miGYRMGQhQ39azNcI+2iCjNH9TcLp2MQFvgyOtiU//02pHXpM+5b+n4d7bPf+f4Q9e7S0eJY+8KhRvFMBVyAYPy7QQPwODv8994Od581fAz3VzEtB/p7fv84Mfu8OOOoxkuQemvnah2HTh4wVnpNQdngoYk4EkuF+cJIVeaCcLUuNo5NZvlNJGWZMc2wlkF8Buf+5z9//Glx3C2N1gxX/zY2Fs/yOsbHoC9f3qJ0p/7tY3tR8bXTvzix66f0KoXcYHJQJon4nU91KjTsWJ1w0xOB+c72tZeqIopO00+kInBQ113iiz219lICFWetoqpdjVY39gztX/Xrp9cvFV631m5p3d9knbasqrsYyHtdv9zBL17DlctazRGh3akVQWt7lQEJ+wghtnVq1uHP11P3DJ/5S9RlLoFGzNRXApV0p7bd/NvXTXsUXcyFgDzTxZv+di9vbEdk/kKBuwX1FOjv37S/K/uoB5FpYn6PbFZBU6QiXRzlDrnmMUHH5o5cwwhhDMMDRHxkUdVGXxERFSEW4BI4QgAsQGvb1GxlA9ExBJRq2Z0rIgaIUhzISihM7vf5jPqYzwD3ICtpQcAE+mtbTQ17wcbHI0iqnzTLYuIRxBCbArYBuu29YjMQhhisEorpZgZiTQhG6MAS1dDklRVdWab0zz6IAYNxgAoTqJG+tw//MPiySMf+9y/Xn/Fc9cHw/5q/9jjT69uLNmxdhCPm0ChAAAk0GiwNotvRIvW1QEAFJIxpiiKJEmQt2xdELnxJggASoyMsQGPNT8QFogGSRQ7jkgkkTWgc85HDkmqXEy1QVBQO5/6tLJMrSIZaKfK+RO7h2nZ6e5r33De467efezb20/Ndaul/sqDZ62m59l9C+y+J2WLd/bbghRBeQqsPRCCJIntFv1B4cs0NUV/mBrrYogugFYWSUR+7BK7bxwjS5t6e+NTb5h5aJ1mejQdUcNu2Hnmf0GxHoarYbQqxZpffLJ4+o5Yrte9hfP3zT7zyN3rC8dCuVFfuwZ/4GGbwBRACjC79WJBRJQgMcbV1VWtNdikM9P9yN13XXjR2ZlPq13bsLeQVREpTffu90keRalWmrqwlmqtU8q72JnQIx9Gw1CV/MRh8/hDYfWUjSQmKZxocEogQqiLUS4oSucqGamsqEYpu1jWip2Yjj25fPLV1x9/zfMOBKMD2LXxq+eeuSVLsRa77vNKMma8df2cZ4qMYUFjIjWNBD2KzhTGqKx1Htj5SACWRuCnds7YzowisEmirO6P+ufOvbD9FxckJ0899e8fOv7kQvVA/MnX/tyf/cvf9Fr8W7/8BxcdOH9ubRnyctt02z34JTOxpzh0MCtEEqdqba0GTVEYibywiy66sp1mzjlg0VrH6JlZGSPIUEdjksrV/X7fKD0zORVj3NjYqFGcC1lqjDEIYpVeX10LvpYQ2QdkoYYSywKRQQAUueCt0o1HphoNPQAQ6dCY/NETCERkwciEZMzm0dLE7jZztigcnAdCpbCoyhBCNI1eWovRTVZxCIEUNtSLuq5zm0XnIwgRUQwkoJVCRGNMCCHGIAhBuK5dqANwxRKU1jH45sLz3jOCRHYS2QkABIybdzdEllhSyZGrqhrFUWMTag7gerMT2MTl/2dUnPDmcUvYHKXN5RtCEMImwxEFmikd42YXcuaEbm6yuDlYbOybLLFZLgMTaUXNAay3YF2CELfSA+m/Rt0giohTkBV1rcE7SFzUENcJfzF/7rHqln+ZfPLqE2etxZjUXKm4EjQG7Bra8FliYnsKv/NVes6bf/bTX05/J//Am07/xsNrh1oZFckws+XGk8u//obWG3782lHfa8wWe1Iji9Hjxh6YkCiBgdLYdqHu+WptEY74jfGpKS/Q3U75Dx9ITj7Rs+NTnan+5z/df+27bDYp7DkUXA7V2Pknr7jkuk/+wtoF5/UfOwI5tYJY32JyNBrFG2+68Ou3fONNP7P/K39PMV8lGut0jBhfU0UKnIJEZTEpRIx1dli1JscHKNqHCof5enZCHvXcaWc2nVVLJZ4cxKxaz4yDxf9kQffTKo1pYTBV2jsZCwmgi7GwoPrju75502eVPFHte3NnjYeTqJ2ERGCjwwITD73oyUNzE5PT//rFh3ftPviyZ3U64xNrqHePw6pL1mW+nYzPLYR7FsevnTi67IzFrC/rHcoFiSg23qGqrkU4hFCjCyEwSDN6QcSGqNoMY5pxKLKwNMonIaLIYVOhwJGAkAVEkMhLMMY4v8leZpaGpwZb9JumZNzclYTA/2WCS7I5iD4zo2bAxuaLjRyaNtfJzeCtAYIgYqYTZg74n07iGDfrAPYBN1OtcTOgJUZA0YSamhX1ZjlORC2GOvoIFCSkSMeefqbf7z/7ec+ZnNix0RsYUmRh5sBsa3m+KFxLJU5i3IJ0NqQLRBJmEVYmcSEk1nrndWpEZHbbtuWVFYAmfwWJtI+img4k0a4oNRIjAQES2EQrlACiCJAFUBjJaA0sSEzAKakQ6kEWiNByqthzshq9VVxjmq3rwL5qDVU+4snJs15fHXrBN1bv3zl3eHLjeFY/qU9ANvy7645cHPW+ldb5cxOz6xadHmJV0cDmbrTUCxDEahusi0ECchSBoEiHEG7YWQOAJiDxI2xfXn1nUpYneLkT11ph5Uc/NvAbCxl5TTAqi/bk2MbGhiUNoiNCiNXK2oG1UyeCi76qJ54a68N67EWYEIgA2wFKAQ8yFHlUMm937Ntx4tQprVIeudF6sTxmvhzozTr0j823aSD5ZNlfz9cGCrHCKk9zb1SSpRllcUwpmRC36p95yp04oY4cLnrHrMYYJUbWSoMXJI0SFDIHI9GNqA4GLLCmCKRLSE2oRlO7F199PWUt+etbtDbqA3cdvGj14v9zxUIZ9DBmPe7c4Z538/AaTIxRWEWXCnsOBjUyGmRXlyRaA6bGeg6T7fZEqxUpjmc6S30NRT6mTh19Znlu+dWvfMX/vfvTvYufes2N7/z87V/cvmfHz73m5zut6ZPLS9P796qF3r+/+zem5x7LrjnbORMYeQhioXK1UZqIDFAoa6VUYkz0QSnFyE071aCUXPAJYl3XgNDIoObn5xv9UV3XWichsPcuSYwoTtPUGBM1OZQieh+aKxi8AomgBTAwWMOw6atoGO0RraLm6o0gJAIRkZGAQ2iygbX23qdp6mOItd/qAgEgljF2OjPlcLT54QLQpIio9r65wLqdzmAwjMygyBgTY4TI1hjabAI2FVhCKAzee1d5MKKFUVEsCvYhhlDVdZIkYshzbMwWAYKE2Jy1FZeReTQaDfWQGgYeISJo2QxFjlui0ObAayhaTT0hIlrrJqileSEZDZEbXVUUjghKNtvZZnDddAYAgIJRYgRpwsxQSBAiohLhJnH0/z2AG82ZiGwGKG215hBQkhj6WlMcqRS9FHhs53DHC9O9n5957IHx8uynXH885aKqKzWsMAQ1yWyzkMV28LhY6hfftB8ehOO9PVmWyMhLVMDpmKku3HP2kw/NgWDpbdSrLON9GSbOrSoJmBmoPUSUtLYxI2FndnPHqVLA9ONGBCI2I19IKM23PgmveI/tL6nYZlt/b063oZw9fduOC5419+jxyYFIuy50ZkuNVNY297pSvWJYw+4P/lmVZsfe82uZ6aelWBdTrhHaoDSH4XqozIEDdUz56DOTWKStCahHKQDFuUw6Q69iGGCKoBNRusl93GoTEgGXx1SVKm3hSlKOF8pwvtHpfOoXPqN99cY/e+O//HHBCqdXYbU1vbx3BOPL9rZXnPzms9/97Uf+6Y9fedXBmUvOMd+448iJ4XDP9PYsqfz6qdv+17Wv/6M7TrZ2fPuYuWK6m1uOI8BMl1QH4Wa4AQBlXUbmqnZVqJmZULkQm4xCH4NzjrYSihhEGpU+i2CovQAhaoUcRYQEFQOIcIikiQRGo6GIECqSzdVvQ6tFVMwceHMFyyHK1qnZnJEAACjNFQEAgTfjvxSCiGgg0ko0NX2zJQUsEtmbSjbhVoAoQhhjVEEhIwpobRDRNettIiAFBMwcFTkRo5W2ifdekQH2CWlQeuSqoCnrdMqyft6zn3vBvoO9uo7ALLxj154XvWDme7d+u+TCcIKIQhaA2QdQgADsw9jYROVdU+u30oyZEam3tq4IkETRJlAohBBZtNZ5aoAlTfMo7Fgix8QYkJCSdt6zRWJIgILzYJQkilhcYACbxw5I0MEHZuVaFk1BvcwF0paNDTBClNUYsqI10TevnL+gTs2p6aWHJlrfiffEuPrQxL33TyTfOjh2aLD9ksWpPcfT8X4+IZPfP/4IKFCJqkfB+dgdG9PC671VAWDm4XB4hpj2vvW3eSFLjACOMQjddOVLi3J8baN3/PTcefvPPnLqRJIaHZV3EtglqTn21OE073ryQRytk/6K5pdFmtNxKsAkQAQ4DtbY7lcmS6hW19eJKPR7VSs550euTCd23AK9V4zy7pNH5Nzz8dA54Fz95OOybSqahLgbNQCtOiJYW02GvugvJvfcqRfnO62kECVMQGwgYuSAxEoRmQpC1KNMk9PUBhsrrimmEdAEqrV6+ZVw4LJD3z869bHP6/X+8MSjT5yavKHi79y89qzPrr/g5LCVZ5SQ19qkSiOBSEwDBiLNIIA7pmfWVlcjxKCU0SZrT3mR1KsBDgHHEsqOH3uqv1Zeds2zn376oUNm393Pfezux7/Og9ZPvO5XU2mRH7R2nLV48+cWPvme6QN78t27Rw98N152SRmdpnGUSkQiQ3NPb1KRADiiiiyGLARHoMrhIEmSlCAYoEgQg4rakAmmDogBo0EbyrKdQdJO+8Oh0Uk1qjyLJiLRmkiBAWBAzjCnSAJRaxLghmaxNdJpHPuKmQ1qJKEmJwc9RyXCRBTZSfC1OGCkGD2SAYTAdXRg1NLaeqjqhHRNqJEQmAQQODKT0Q6QizoQaK3rYRVQVGKH3psglBgnHhFi5ROyAFRzKEKZIjnnmv2KSPTsp2enl1dWUsqZmSUyiwL0MaCxzFxwYJHAsSgKZkiSBACUUrUBqVjCllFBac+RAS2AUsqHYIzx3otImqaKqF8MG9SXAIdGJobkvTeIQAoIY4wo0AwMBQBRY+Bmgm2AlCGvAAMTB1RaKxNBvPdaa6UphIBGx2E11un2feVi0ACpsXWoQVRmLDM7jgB9EkiS5Mjw9Nv1c/VY8uudj71j6tnPXT142o8c+VFhcrNnNa7dODM+kAgAnZjaZAwAtpnefLZtJE7A+KHZMbsteLU0mNdiMQAHSey6Z98HUUppdI4p+pCYXlUk7W2zR/7uI2e/4931jrPjCLZf96aFu++ZQjHRsFJLX/7qjhe9HSkZar8Wxp4p8KW7qNq2bf5r/5iodu/QdHp0rpP4qlOX6zyx7wCN0n7SuvLOe9XVVzz8jl+eed2PHfyt999z5RV7rjp/VSbcrTcbvZ7LRPfD70+v/lEaqnjsB/Nf/2r7859ppXvY98kkfQkZBETyLGQrDBb+y4MMV4FzRGjp0lctULXFCPKZn/nHsjPztg/dNLO69us/ae56lXnyptaxAxfh3IQ8+2bedkwS/+43XBqK5UeP+n+9/8S3nlhLxw5N7nELx8qXPnfPfLnsQbtAp0ejHx7feem2x2owEANKKyrhYoSpEUWVr1nE126U1MwcKyEB7wMieucUEQlwZEFk5CisGsdOHY0xHBiDV0o1NR8DeO9L1KoWGYyi28zfbKo6G8kBo9XRB1TkOGqtlYAVapDpERAArNVNaehcZa0lgTTN66rGLS1CIDFIRhkvHAm01hTFAoGiZmXjnOvkLUZwwQshiYBIppNmC2N0AiKh9l4LM6PSECIAjEYjpVSUKFoAPHNtFKKP+3bu/qVf/pVsfOrwiWMinGfJwX37n3js8P33PTgzPc09X2uAyJm1VVUbS00mfABeHq3maZYmxntQCpVVgpAnbT8qUVEARAQSNlobY5yP/WGvlaYueDIWOACAcy5VJkQhMkSU5EmoakvkogOJCtEmttMZW1ycT5LEIwnqIJHYpzppt7P1tQ0EDSoXYCuCSVmL6pHvOt51otM6MvOY5C9/5HmnDrijE4On8sX7O4/dn+r0wt37l7vPXxvMPbROp9d9q+2M7Nwxu9wbeF+rVIcyAJpbT7feckk/SsNJAtuEeiAobfT0eR//zS8NC88IG6PBXbd8768++uGHH74nQWTRSCpEMDbrD4cxxryVV64OfwJ6zMbnBhgQMMM4gIPWJ9ozT2xf7C7LSj9J9NDqK15749KRU8u337zG5tPTu/77+Qfmr7oWL7pYry6TnfBp1h5thHohmCRppeVa7Z96ys6fToqREk5Dwb11z7khUSCRtSQOFQEbRM4pGwFFHdNRrLnn0pbxyTAZxVFhDpy9c/bgxDcfm/v4p2cz1r1+OTYxrhylFObd2PxoPBkLUotHiXVtMDYrBEu29JXN2hTrwXo/NalSqqxrRZCQ9t6PlFeDuF4W5WChHLqde84LdXXkh98+Fy67m75avAjePf3+qk2YdYYb60c/8Lr2E0/s7O50J09vPHn4ond9YH5q59GlORkvg2elFCBH5s3E7ghKIUuwyjKHGP3k5PgLb3r+LbfcUleulbYdlMZ2qlCE4Ehnvlxv5V1xYazbtalVSeJHA9JIgApEaWZxxpDWyCxKKYwMXpSxickYJATmGHHLF5sYABDmTTsNMwOpZvAFACE0tbYGNiLCURRwJAGtAI3W1OyCAkQfm0h6jm4zqRAhuF6vAtZEVDIGJqJYV6R14Tn1AQxaq4dl6bgGEReD7WYDVwOjRUEALULAq3OLVpvSu1aSEmOQMKwr0kYJi2Mvnpl94E1DV4xaa+eczSwAKMC6GkLjNSRk5qBVCMHatN8fNlO7fr+vtRatt9yGcEZ5JSI1CyOhokYf15QFqMhHUYHJ6CisI7BCJjRIzEEjIW5JuqjJagchVJ5Ho1FEAKMoyoiHyhpmiCqISBErpZRiKMsyoNxZPjA91s4vmLnre/dsOzVSew/0+qcG5RUhZRnitjQCyVKZ/9MP+6fc8lXjcNH0+mNPnZpIWzG4/jDoFg3L42v1yICyaDjIECBg1Jq01uxDSXFCd9eGzs901W3fmVm4R11xoHy8EjJTz3v+038G0YAvQGdJNv/g2ve/MHXTf++snP5umYyTv7Bt5t7wC6v3fPv8mV3pWRcUqxkPjmnVBajjcKPcGL3gE387vOWuU6+cMaFz1SOP3/2pT5PxZ3/pq4/dfNveX/jpyPT9d73zVT/+U09+8dGVe/5latv506btolFJLSrPjKrKwSD6Nqgxj7XRSfh/G2DXSTqWqrUQEUCHyE7JV9/6D6f3XfnTf/3q7tpjUk0g1m/8Yve3nv493nt5G5x77Pz6nR+Ar113YqOzdpf+k387Nn7O/vZEJzOr7VHn0LYwFeubbzl92baxmYmV+59sfWt9/MD2nSE/ORF2oZR+5MAozQLeKwEUqb1j9FqZcjhK01Rrba0tyzIIE0sjn7dZ6qtSaxVjFEEXHBEBBwLWpKIAENqsE9aHLtRBGp8hGlLiPArXpDyKCaiRWEAi++gii28yPZk3TfCYxhgDR00kghGgdHUzakJEohhQfGCjPROSVqX3FAWUCcJC2Ol0RGRUNRT3iIqyJGUfC1cYY1ikjsEqzcS8Je9oFsxak1LKcyRRW0UDGGO8qw8eOkuYH7v/ER/qycmJdtY+dvz477zvvb/6a//zkksvPn7idCuxzNzOW7V3IURgyWxi0HLtQSDTmrRyMWitWyZbgSpXNhHQiS2CC0AYRUVpJUkIAZWBUAPLVHcsa2en5+dSm0QBFnFVJZEbN3+zdI9RNjY2muva1xXpVCmDAnVdgoQYIyIohZEZFXAFRpNiCVyOUlgWloG0T9c/snCWHsO5meH9rSOPuMNL9r4nxtRTu7r5b+6ZfO2Pl//xZHbLqfmnT7WU+BSiSaBjktJ/+Qk5eR3uGxezuVkAAGQ0gDR39i8efWyhlbZAJE3br3rNqy+98vIP/MF7vvalzxsDIQZNCccAAEmS1HXdbrd9EfDdGC8E9ULhfSxvD/qLduMve3X3mFJKQhiG8vyXvnj98PETdz+STowrZf7j9DNv+OmfHLv0Wb3+aMRmvN0qhqv10sm8k6pOty43bH+teuBRvfgwEvnCKm1rJiUFKyscrY6hjqQUJXUVooBKNIVKKM2dTXSvnu644IsV39129TWy7fz1r30jW5wbTY5pwNhiGvVWEgrDMvRHq9PY9RAMUG4NIEel0jQdrPayLI1lHRJ0dZlpq0WLpkhQRR84oAJkXZ86NQCvs9yNjlxyzuWHnv+qO773tfGTO3e8bdfCV/w4jx2/687wT38wPjxO286LS4v9PN/3y7/Ref3PLt3/RDTWK7aRlFICIBBRaQFwHDVpo1QzINVo6ro+efJkZG51WmVZpmmOWmId81bOPuTQ8d6TNqPajYoixtjqtCvnnaKooZFBNaKhEEIDjgAEAQiAIhC29MbNcasUMDMRACki4rhpZ3RupLUFQhQTAgcXtNYqSQW8C4FEiCVjzSKOsCQmDwyMJKHJAQJAgRADKkQfwUVqbLu1U0xKq9GwTFLT3+jliQXY9D/URZGyJmWabKagQBkdgKrIFlVVVdiUFEoHZhAiBkQAkbIsWtzSWofg6ro0Jqkq17TCzrlmj2ttSkj9UdFut1vdzqAYhRCaGXtd+yZ7XIECaMKCWSNorUNgz15pi4gcI3JkBIqiEhU8i3fMDKiCSABxLIhIoJA9CjTrbUEmrROdxCi+dqxEHGgyhlRdOAUSpNbW1DFqQQgeIgeUOvrlx05Nh2r438797u2LP76wc4lMKWvK7A1RpR0ZejPbon7g21emYRzaCQWTV1LnzArrklXhjPahDlEUEJHnKBJ9FOVIgiiFa9BXQRlftT76Z9t/+71ulOmwsT7qpzsOxWdfF37wQOya1MdxnFj7978fu/71j5rseD95cXtYbQz2X/OyR6956eD7t6ytHFOqaNG4iV4mxstPf+L0o4+tdMfat9+aZPll3/3i6WL1of/19pd95J+W7h/qex+cN+ng4dsvff0bb33f3+2Q+Qte+wvzh5987Pd/afu+7XhqaGwxGoqOoLNpn0JkUnWota+kPnMAt1O0kDqwqCollCj/3Rd/4PGLX/mqT75t+sgDicqqtNwn9KW9P/aNPVdtw2XrLHz3JfNX34q/+eH9P7zpTz8/nDq0B1sqbDBtH1up+m++fqLbmVrw23u3PHXTlM124neeWvju2OSPHaiZCw+aQDwCRZbA3Fi+ERRjjN7a1LN4V1fedcbHnHPReSKMMVZVldrEBR9ZtFYNvoqBAMEDBxZgieLEqAikTVrXNQBVIba6GbBIkAZ9JZEFxDQKf+FGPIgBlVLGmCzLXKi99wCb4LnAUWkFWjWGBCWsrT7D17NKA4oPQSnlmXuDPiIaEYjc7rSrqnKlU0oFH5z3yhoQcMEZY2TLQNjskqzSymipaw0YgdJsM0aMfUDE2nuVJ1alg7K84/Y7x8fGfvc97/nnT39qdqx94/Nu/OHd9wQfRIRI57nmEBUgGShj7HS73vtRWaZpCgCD0XAszYMwE/gYMIAiEGA0ysdglCJmRAwkB8452N/opWoLs6OVRDCkRERIovew5StsCog8zbyPBoEVCKP3fgvLwyyBGGICEhmdAFGLVZ8JBKoUHEk1iJPr6cvg4hfm5z41tf4wzx1ZO7UxduTEjnb+7suy//GsqW+dWL7lUfzOUbU8ZBCenJYkf/VXyu+9HjPthSwjNXnRK/vfvL7/Z7YZ7WvfCFaOnVyZ3Lbvnb/0mz/8/h3z88db3QlA7VwNDS8IsdfrGWO88/phIw+JJnQTRfhpN/bXE1Pj00efecaadM855+zvtr/7lQfSzqQaYtaKA/R/9OXP/eX1128s9cyJ47iymFiEsrbOry+dzhYWh3NPJ8fvjb1CzWznpISIRCoDqKmxovugU0FOfF95y4lS3jNiEdwuTC+bmWG/IuXYiTe86uk95+Rrc+7w/em4dVgTs4xCvPisvQBQU75t9/gAvEgevO9Vo7V+r1haG8wvF77ql8PBYKMYjTSp4HysnRXUEdB7I6K4UCO9PhwN6zCj8JJrzn9m7uQnPvfB57/uLRctvfDxHd9FtvP/8Q/40f+x27eT9FC59ER1xTUX/fm/TbziF4ZrIZ/dlhqbcbvhRyjEzVTgLYJE8/NtdpOVqx9+5JEkSUVAJSmQ1gA6SLUxAuHIJIrAqMhApNMkiS5abVBR7Zy1KQrFCMJKqxRBbyFnSUSYAVEBqUbBiBI9cwTQWjcDWKWRFIhIq51qg8HVITqlUClkDmU1UEwKkZkDSC2RQbSgZVQEIBF40+DYfH+LCn1MlWGQofhSQzI+hqkto09SE4JLUxtjBETXiK2IfGJK4goZtdJI4EIupsWGfGQQSEwNrJAMU0O4bNpWDZQkSQjBWqsTy8jNIi1Gb4wC1eyDMTG23W7X3i0sLaIibQ0zT01NkdFKY57aNLPWWmNMg0oQYNQKCJGEFBABERk6wwwhYxQqtanzItJaazKICIpEN5HPaIyxmuqqQsSslVprE2NJAFEZUkQaYNPjWHvXrKURMVi7a3Xiui9SOVg4Nl3dG5ZybonlJBQ6mrYdL9fwTc9Kb9zr1xwCwNzJ3nieMqaDPMe2RSdTkzC7Y2+ijdaajCallNFEpLXNsixotqT43LP2fv6fthdrrjU9clRGDwFR8rGrX1Bx2cEO+BGEovfUw6cP33nvaGZChbNbjoGI8x0//z9PAE13u4ndWZvoiWxBU+2p1uMPnf3923e1x0N3rP9g9dSrXnT5a9+04+0/fuqeL6Em99Qj1Zc/m59z6ILzW+bKF+LBc0898b2J9/3BNcdOH/+Fd61cfpX8yq8tX3gxgfTWl8NwkYh8mk9uP3jmKRHKYoV97WquanX79b9854ve9eLP/dYVP/xSklZ15F1J+sjuF/5p9zXTw/li0Z8qRwMTt338PcL0zvQ3njhlE+NotW+sW19aWx3aD3197rf+6nFVbSSz8q3DcuNZ8A/vGB834SsnJyrDBUaVGwJgBG+pBBYAAuUDa209RwZBRc31q5E8QIybqr12u6211loLokGCEJWAAY0BDFKqDYQYJGiC2YmpHHUmMJ61JLK2how2iTXG2EQnWmWJTYy2Sjc54tbq1GgSjq6WyFprTWgUWW2MMVrrJEmaz6e1afMZU0ppUhIZeTOBraG3aq2ZOYQAkSFyjLEsS1KwJfluynEnIZIACRhFpFAbRQiKkBAJBWMIdRXqqhmJt9ttC6CiZDYxxmz0env273/jW978z5//7D998uPjY52J8TFDikMMzmMjOvOxZa0vqlg5gxRrp6OkqA2pGKO2NoSgFWqExqsiiK50VukYPAPf9+D9Tzz5eJNh06yqJPgYfQiOGUSwoaPAJsg7GEUQA9d19A4RhaEZKsToUZhD9N557yVEUGTJQNyEB4/8cKSGq1n/uF5bG7gdz7Rf9cglv/bMy1//2GXPeXTirKMuGQ2Gr9krf/6C8ltvrP70enXjjiKtJpfL40eT9z/8PABY5fENmVwYu/rpGz67ct1fMXMx6hdlb1CubQyW6hiPHV/cu/e8a5793EaN0/gVm09UnuetVqvxfzbKFRFR/5+BA+Be68tR1W516+DOveLSu+5+iDFRFB3WsfDd7bu/f89Df/vZjx245MoKOTiX7jpQHzxUri23Hron3vFN9a2vmtkpuvE5MKrzWgBYRx+xwwi+lZeYZzHJmCqgmKSKUq0s+TrFeE63DetL/tAhf+0LfGdsPzD/2YdbajU1SV453crS887ddlbWBgD2sN7bQMOaUzbZuGkn7aRZ7KcSWq2sjqGoSkUaKBKqGGNmdYziXcXenq4enyvWn2cGV/pC//O96PjqK159bG647b4DwyvXnnj8T/bd8qWJqUvWR8fqsXzvOz/WueElMgjrx4+urD5z1eUvf9LuiHFO66SROhttGsSaUUoRxdAMpDcVja1W2/sYA5BWw/5qtz3Z7rQIcH1jhFqATaKwFhCFHgFADKEWnGp1q6rarJUgKIXcSHYBUDaTbUNDjxJWiIDIrLQmY7bsjABEigFcUTcCEBCKMQJylmfWtubXeynphAFBRReCUayQARJQzbVqjQ0hYIP10NQ2KZfusgsu6lfFo4efGJ9I6tLZJsBeIwAwgjKb6CmjFJfeKsVIiOiCV0aX7HWatk3WL0cueE0qtUldlI2GuYlMShJrTFIHf0ZvrAiRBZRqev0tN1AEhYiYZVnT/lZQLSws5HlukBTpzVmxUgAcomcOCtCgUk0gkoDW0OzGYmSNJIo0gmJCRUxILCZCM9xrigOrjCaFLFPbJnvDHqPY5q6XGDI21C7GqI31MVijDETFYEghaK/Zkrnqymf/oL5t9Vz7xPG5K5cOjkmbVcbQN2EEOJKUlk8W2/IcAF58efzq1wfpJHLty1UHXRk5iD4gNjEYiiEqpQmMRo2IGUzLNn3l5/6lc9e35kHTkQfzF7wlVOuStcu1xT0vf8eTf/uRid7puazbftFLz3/dT87nl55exxdPBGFhZTY2Bjuufn7/V98/9+H3TE3OssuARJv1mjM0Uz4MI8Dsar348z+yl5WP2e2vfPm2i58/84a3PfCnH9j1jj9arXujOaX695z+9IfUwvz1n//Gye+P9px/6e6f/ensov3fWzwpTz6w/T0fwO37+n/w3nxwYhn/0y2DASaAK+87kNx91Y987TV/8Oxv//Xlt37I27ZsuG6rux6SX5FnveWNs6/ZnT+8VBz7wYM3+7Fjc6n+s1+p3/u76Y/eLN+/0egOJZKR7feKXpZ1p+zCfO+yPdPIQ5tAKe1LdpsP37z66kPji27VA2iRSAoRlGgBCAGCQpEYYlCgQBGCOOeQJc1zV1UcgzGm3+9Ls79gVg3fpWnERLTWxhhmIGFEtbS8aIhQGSKCCDFGpTRDFBFDOkIEwAhCiIYIGAgACZvkbolCiFGESAFKBAjBKTIooJBkCwtzRslPRJtGJGbaEjckSTIY9kXEJCkRiIhWCiLUZU1EVukIsVFIMPNmqiBHBcghaKUYhBQam9R1HTkWZUCBNE0RsXY+SbLV1dUdO3a9/nVv/PfPfObo0eMvefGPgkIiCMHBJt6AfIyKSGtSmzctQESPMdEqRWQAIaklEoqKERjA6H5VKE3iA0UypArnSICZJcRmBBiEwXlm1ggA2EjWRWKv6hFQ5MjITevJW5nrzYTfBh2MeKhdUTigAZYCoCsiDIhGRZP6CBRBSz+4nPPs/vLRz33l7CvP33/Z+Op12D9Ii7ryb9iP/+0KPjro3/6o//wT7FYA4PjV/5hdfH3KeajqqgpeuKxKBRJrR4Ct8Y4gepZnjh5VSiNLMRxqo0Q209v8lsR1c8aJmDyRxptD+csj+BS5ym0/+9CoqMoTTyftjiC1MoheYll2utnf/eNnn3fjy7vbxlhn9cSYHOnpux8xc0fsyvKgpyZ//92Ld95Gch9oUKrtlLJqaAplOrYC34cRKtLSTVkgepXqAGpSYaJqqQbW2SMHZrMa93zi48OuWnL1WBSf5iQIF1502cLGUQDIx2Z7I21w2yjUBj37YW+43KvX2NYCRW4j4oi0ChyB0EMs6zqCeF+H4Hq9o0sr7gqtnjUozerqjsXDk7rctvvcGGX7yvNUSQtTXx5Pz+utHtbXvfac9982fsWL1o4+kObwlc9+6r2//fof3Pu5VAiBG/0zbUX6WG0U6ib3qDHsiohEjp5jEK0t1PWuHbtIY+Fcryx0ojObKeGirpRVEPmM67eqqm3bZ42VvJ20WqnSwhIiOxYvIMyBABufAwBoIqXQKN0UyHKG09S8NxRr2oIJiBZGEUQw0bOrooqiAYGQNXmNoJUmlYNCFCJAFCI68wcx80jLWqzmVpYQMVWmqiqValTA2OyoaGpqqqpcQ35xzpHRESTP2syQZS0R6Xa7En2/LlObdHSiBCpXshJEMZu3FXExlGXZDMeY+UyTarUSYKVJaTLGAIlSaO0m0MN7n6fZ5OS4UmiVJhBk0QiNo3qrjdCJscYoIrCKjDHaKG2U1Sax1mqTGpsanVpjlCZArUkr1Jq0IaVRa51aowjrqkizRBtDRImxpLAsR4hijCEFaWKyxGyf2WYUKU1pmqjUANaxbL3m72fxvtUj58Unuksz4+TBe+1cGgvr55f4135s32UHtwFAFjaUUomyWmvTHs9bmOuq5wetLFcKAVk1OVSaAJiI7PbW1Z++dfvnPumTGQfcXzpZLK7VMc3VWCxrnJ7sv/TV1Y++dv/n7tj9vk+V259z53DbpAoH7EBnkKSUKFl+cvX8n/v10Rvfsba+2MqSSDzknJFAfJK0EgkmSbvtHTEbx6cemP3yN+Qvf/+Hl810Yu+C975rkFzR2dvdd8m+ctS78Q//9603f4/i6anrnr/yTDjy2ZsHn/rns//s49VzXjHz8jf3zrmoHKndf/uFM8/44Q8eZmi94+cevO5Hb37bP5x7/NYbP/NOfe75xoIdmyjr8unzn/PuP3zDa9vusS98Uf7x/Rd94lfe+tm3X7/DtI68yH7nJdWbP1RkS1GCBIOkk0zlFAHd7319OGq3Lz6/vViOPvEX909MjI0c33oq6+jEObd5HviYgW6C/VihC56IBGKoXWMcIqK6LBufjtY2/pfDjxEoMaLBQxAEH0Pl6shslLLWotFOQU1SctA2aWV5Zk1zqQoCg3jeFOErAdyCfgBi0/ACiyIE4RACsiCLAtSEwFGCby7Mxl/UMOkic+M2Bmjcs8wSAcCkiQ/OB1fXVVNoksBEd0w3Aakojbew+WdVVU1gTO1d82h+CxE5SiQog+uXI8d+NBpoMuvLa7nN3/gTby2K4g//6A/u+cHdidGNF8vHEAm6E+N1DJV3jByJwahIoJHSNC2rihGCd+wcgQQOLoa6KEPtXFHXPozKqqxdURRFXdV17Z2LIdR1Xdd1WZZVVTnnyrIMIVRVVdd1VdZVXTvvg3d1XUcXvY/MHGrnq9qVblQOfe28CEeMEbQXEKmkdtFAVDqIBhSt0aQARDYxeTfJuofvuL93y2M7/3H5go/ycw+fe9nqrunYM4ekevPB+NkX1M9SANDZf26xCksrq6PRoB71MQYSElFJ1jp4cI8hlxh+9NEHXc2KEgCwiWlaXmttURQxBgBploxKKUMmMMgfK7hQ4st95Hj2hRceeeJw7WXIOOhvDNaXR2XPra+G1A2L6k//9I92bz9H2ym3tBru+QE8eHcxOBHTItnfOf57v0pf/6KembHOxnpF1+tFadALmGgUZ76aTlqJ7RR1oVTd7/djUNtsQv1epavw8A9ad9wy9b3vuv7CotVTVSsopQZeR88PPPzEC/fuAICZ2V0X9pLO7FQYpf0hc5Igc8cpdmGUJkfm1jQgYrBKA1EMHoBjWUpd+dFw7tjK9ce+999e/KOrneeUD965MH7g+A2v2WCYcqX/2P/ddzmeeJEe/d+lsXe9d8eNP98f9jeWF7ZPH1xbHdz/8Ddb3ck//5Pfet5Nr73s4itHPFJEmyA6pUQkRBERQAbkECMKWGtDCFmauToAcFl6paD2orWN4OsIY5OdlX7fBZ8ZHVy0JgkxBoSjJ09G5uFw6FwtDaRZWYwgIppUs97ghg/VmAYRiEhCjMAN/QMRRZAZSFOsa0FmYWEB0FUZYhSdmdgEHoikqIhBiAJw4AAiJLgVZL2ZgoBexjqdhYWF1fnFVmLI6rquEq19k3vIsr6y3mq1iKg/7HVbOZAqi3pYjDqdTu1GmkxwNQo0OuQYmRCNTZxzJKwMaSBwoIhQQICzLGulWVEUm/cXQU1IAoKqmZeJNN5fVgolIqKwDwSiyHCTp4YokRGAkBCQUJhAEGgLDbzZUjBYbVCrIOzLSkIUYKsUi9AmZRCYtCIVBUQpZIgCQqSFUEBbk7by6LwwhLomRKM1x5AYi4oiQjpUMReKo0OHzt4D64f3jJ7oxYNPhxnRPUp4LT20C//yodVt02ZppceTtLZRw3inpr4wR/aAaM3stokReBDnfQyIQiDCAgg2s9vveMR85dOnxgMUve37z1tYrkKaRzMcQtVS4/5E/6q3f5ATCC5Zf+rUInVOeHVTd2BdiRaEx6ow7LY6vSPr57z3Lw5n3Y1P/FFubJbu0lotyvEuTpqYr7u1tjIhmJh0lTKJqIMH95Ygd77/L8dmd3au2nPXn//tWRuD9Xuf6P3z30xd9Jdf/j+/+6rf/OBn3/uRm770nfGX3XD8r7862jUdYxlvuKLzrCvOdMDbJ7onXvpq9bPv/Y/b07O30Ut2+6de/bYLXv+WU2/4kbHOTBrryy+97ORD37jlA+9LYZ4StUITh37yLe993dQff+bh7/zjr6gL7y/e+b/pD/6iKoPGoaKsNGnK6exs532fOhZ7/tO/eRX1jp9cXJq0/adPTD9nWlN0HoQ3XXCMIKgFOGbWxuglcJIkaZr2er1Wq6VQNSOosq4aaS4iap1EqCHGhkzOEoWRRFBkuj2+0Vvjqu52xpIkWVpYpjRl9JtgCdociTUW9MZTTKhAETO7GKAGZiYEAIwxxq2AXhExxrjabwaaiTQ7GmFuhIohBGCOMRpjrLUxBkYYFYVFbYz1zlVVxcABuChH3nsUwBh9DIioSCNAjFGiIJEPnohAwDmnUDnnQCiN1kcHGMGoOgQXAxFtlEMI8tofe93Xv/q122/77rnnni2CIqCV5dKvlytGMM/zoq60NRwdIYooT1hKUIAQREKsIEYQSgzXUQFWzkctEYE4pqQZSAKHGIDEcURFAAQsRXCNSyKEzZxWCYLIGphZSGGEKKLYewCSCGCZCy9ArHUwCiIhQpbqDraiqsDXRlllEgSjmTW7tKv7w4UrXvUCe+mB6pEjy6eOtD5ycnLHvtmzp0ZXTi/uoWPThzuHjsMJOL4a2R7rpLPVcJBopcVokSC8+8DMZz/zqUvOPfv8y646fHi4ffv2YW/n3PxxVLrhf1VVqbVmFmttMRppYwCQAMFg+sPU3yb+1+v81qm8nS0++dRke2KnlYvPuWDfZWedfehqYTUWlx+bO/m7f/eZv7395rf+2M+Up0/bC87zR56hWoYxtDhMz+6NBUY/CnknqHb0/Twbh4210cp6bhMa6y67kfVFptRGcJ2sU4S4zGGfGUtzRgpTKUC1+mjWib3VYZ6aCsJspl1wR546ee+pObgGMLHnHDqHtP3+0Tm0MmPHK+GRCXmapsGPtXJvKLrILGVVI0KSGiGsgj9y/NgF5+2b3f6Cxx/8bo4hZAcevvDcUI/GimH/P35/7+rGvm8k3/vDQv/K78J5rxgdeeI/vvE3t37ti3/+l1879fRDlODH//7Jn3vdxScXn37+C29aOrrU7XaV0SINTRgBRGvtpWZiagJ/OCiFZTnqdMYKH3vFOgSVJUYYGTOmenXkE6VBcR0DWT3wtQI0CKk2iKauGoajFcYorq6jgKDGEIJjQaWVUogiwA0GSyllrNKaiqKIUUDQ6KyOo4ieLErkGOKWD15BECBhq0RYR/GuIqWCABhq9iWNcsRzREVCZIJEYNvKFDNmCSsSEvasQJNusnw4Ou8gGkVGEQMgcGLSwWBgrWbkoiqVUhoUAKDVGDjTFlwATaAIAwIioChSzFzXdXS+KSOIAAHSJHPOCYhzjrRqOATBh2YCAZEjitY6wqZUUmPD8yAUCiEAASI02Uabs3wJhATAELk5qAGEFJGgUlR6T4DEggJGKWEJyEJoBEMIZJrRA3gX8k7bC4yqMrGWmTut9sLCwu6du4bFaG3Yt2kSsbZVVlr9mqXL/u6RWx86kMNdd6Tq7GDyhVheM6vX+6MD3R3nXb9z+Ei2vl500pEfSk0WkCeyzMfFXqHIRWgAnUAIooka/e3UFz9XmArr8UrWcC3bOP4FftVd3fOfRWsrS22YLnNfu7BSsU3a4/nXF/Ip7S5qcSVj5KCjdKWzChl0un68PO+3P3Dq/HNXf+9XD2ycoMk942anduRiSNPUOavFKZFK1XHk4cC129/xa23Voge/lZz7sh32X/ViefKDv3YV2Cdf9IJLdszc9yvvOjfrLh155J4L37vvp35s94Uv/VoRr/zQhx/69t1nDuDpwj7vI598z7+td3z/Zy6V8ujFO9/z7KO3/NM0Qqqwvevcx//1Dx7uj6YVZedcpS/5kekbbtpx6fUnnrrnJec5fVy+9Xe/63/zF0c/+s/y0HXm4GESzk6fV83tzTxt63ZOWfeuj9x78W71hovGLXdOOuxHr0FVtScUNHrEXgBAQUqGQ+zmrfX1dZWkTfaXC55okw69ufhohr0xpklSFAU1iNkQUchq471f6K1FXyfWlkVRDEttjSepvE+ZowIB8DEIg2giwIaJ7iBuls5N7Hdko7UPHgBo6/ivK9fklVV1mSRJI5n2ziGiAIQQRJA55HkeQ4g++Ohj4wYOElzT/npWIMi9oo+IOjYiEialQW9WBMzcfE9upE9Ede2b36iYk1T5EJADEbm6ttpEXztQbnXteTfekGb23/7t36699trp6VkEVYWaAFuJpcT4ciSiSCshqoNQ5VMwlXee2ccIPmY2qfqjCBijaK2jj0opIl1xIEbkSAIxBEEAEebonLNaIZJzQSkEUN7XJkmlYXUjAECMIhKMUgSKjPYQvPIRYYxQCGtSEIhMolREnShjE6UdMAdv0hQTY3R773nnFFDc/pt/0tad6CqXxViWu2f3GO6OXTjzIy9+1jn5ZNRt0iQbJDOkdQKKWuOTUDgB319b+vVf/ulffuevXHfDNVMT7cqFnTv2LCyeavJgYGsN3Czpd+7aFUJYXV3VSjuREIL6Yx2/4mffNL10eBEDn78v/ZN3f3C+c1BTd25YpHG9+OFXrrj4qm0Tt/3bVz/37Cuv3HvOlcuWcWYcnjg+mWVltMVgQ0i6ozhIXF4rkDzWp2trW9kMVT4Go4xjXgUal9aEXukZi8crLpTfk3W7zni14+jGgyujMA6qilFbM2LRKDq1MaENAHh6zlfJsJOo8yYnFwdDV4LgCIH6rsQkkTRT7GLpBIOPYXIs8zHt1/XxZ45P7Nwx0PnN+UW7r9p90WP3Lu+9fDRzfvfE43jz+7bTmM+Tc76/49vJo8efl71k0X381n/97tf+pZ2Y//2Bn1JGPftZNxyc6bzt5953avGxqYmZQ7LW63sXQGtEZHSihEKsRKFSChUysyAqRO+r/Xt2Hz91vBpVZCgwK6UUCtexZaxzTqij2XOsSJkYY05AqCdaLSQpXEA1TBBHG8NzLtlz18b4xtJwfGoHYVAQdSCtbCDvxRN6IIpOVFRRFEPQhrx3EqIO6CQCkUWKzFGiQQqKLKH4ElE5AVBKaYWuTJyttUKiUDkRVCyIwJl2Em1AUjpgNAFQWAOikGBwEWyacJAQvUjMWnmvKsShUgpJEqtJgKTBFSCiAmBgAUWjUEuiAYCbW5wARtKkEZsyNhJRAw70wqEsGERrhWqTQJumqQKsyloIjdXIEH2wVpXRp9Y0/HTHgRGYIyFCEwDLLEBRBIyqOWjAOtRKFAmQ0t55ReSDFxQGjtEbk7gYRJRGUkwefGZtXdeSJiECiIzW+kmShFEFhohoZXkRABaWFgHAgiJPwNqZ0pR+J+y89MEd39u+9NDP7Es/utZWnaeXa8SxdCy89SXT173joVee1xpvuXoIiCZDV4UC0TkxifN1oqGoybSGJmYYsOSxqbx+5DTMzVW5iuVGO9oRj1KEk598/9V/+sVVkomR8iYxoYa2gYBHBvp0SF8y0Y8xJAYYOSAyowEUK7bQw2c2znrrm/ovfOHT7/kl+/UvnMc5T45JonWVYAVeFSFRWuWtqenBd247fPvz1GR37JxLT3/oLyb7q7OXXRaeGPPV/EQ+40aj6bu+GZhXv/1Pl9rWyd+6/9HHHt2hBYvRwp99+MwBbF73uo/fdamv3B9dX335/3z01S+8/thtR8y7fymMz5yM+cL80/HAvvNe+IrWdddnZ5+Fti2sN049efrJR2nn5I/MHk6PTH7lG69zr/8rfO6XxOeMUFA0x8/O//mX1zZMqxqt6rGvPzZagXpDFbpP6zwxRvMBnIQ0V2IkEoCJogyKSK8YUpKUISTGchCtVBUdM7P3WhtgBIQonlFiic47hVoii6CABPaAMSHr6jpJ7QjqimsbSYvJsnxjuKpdE9UpGBmC8golshdItTIg4KNRqigrZU3hK/ANs73KskyT9t73+0MRtJaKUdmMr6Nn2UrnZPZOYixEIYDW7AP7AEqzAAEH4iBCThgJgDVgFaTdzp1zwXvhqLU2SpdFwdJwrMRYO6wrIki08XXNBisxyAQhMngCqMuKAazBzvj44sLC5Vdcnbc6p0+f1kryVtYZ29YIrZeXl7XVSBBCIJ0iOgAgIOUisiBAVDgKhYqEwgLsIzOCMGtQxCjkkTEKsjKMjCwSQavUe9eyZsOPUjAEiMbGUZXkrYggJKg2AZ1CVDsPHEjIkMpIoSFrjMWEIlqlE21AkUpINTwBrZDIc5ztdKYuOHjizjv3nbV9fjXaoCeZVidaq1xRtX7iO08evuOHP/J8WXsW7dm748n7H9+ddnzWtu3iL9//Gzf9t5vOO/9FqxtLwLA2/8yddz744OOnzznrssOHv3PxJc964IHv55aCGBImQ3v37jv+1LGiKH2MEqJogLLWbRO/kcE9Ze8Xe+XzSwH1zJG5Hz5w18a01nVvat8BaKXV7oszw9cenPnifY9+7atfef30Tl0OKmlNq2yovQ4RRUSRbyVcYdTEYYSoLHSgHHjPSQBUMUKbrzzfHJ1zSeI5dnQsefDQMkcKneXT3LUtMqVyJNFAOjYiAmTQOJa2AeCJ4/OPHjvBre7E/rFrbrgCjNdphphkSSvPEvbeF5VVseitTuetxJmpjKXsXXT+3qnp7sIzxw/Soow69z3nBeu7zoEn70u+/OeTnIEQ77986sUfHh/ufHzya//fn7/3meM/uOK6V4nmtdEzp+ZXXvSin3ri8JFnP/uFP/+zv8eCV1xxdZLl3MSeMDOCQFRqE4WqtmL2lFJpmj744IO9tfXEWGAG5hACh2CUZYZWZpFcBTUrRq6s+Ha3Pbdy6u/++R8TYzNQM3k3tUlrvHvs9On+YKBaSqFuURtFq1QH4wE4xSRhBMcYWW0mgWNZV6WvQ+mtNomxemvZoK2JCEZpYNnM3AXQWvsYrE2DIWZ2o5IQGYE1ESBXjjgGjIBsEDyEKFEiewhCSFoVVQUAWZblSd7K8oQMNtG/URRgAKkwBBQSaPCcDBJAYmOxjbEhwTZ0vSYOAQhZhEVcVfvaKQZ2Hn0Ez4oxlC7EOBoWVVkDALKURVVXDhGHVSk+uKKuOPSrIvogLqLVHGKSJMLgXWgamrqsIDJW3gjGGMEoryCCxBiD8xbIDYprrrzmp37ybe2xbu0dahVwc35ojPGlY2ZSqnL1em+jM9Y1NkXSNsm89y74EFkAitK3mLrU3cCkLDZeaa7cU03XaTmW8bjPT85X1idVhb/0t3Pv/4XzA6VptW4w01ozKI2dPXlHRyhZhyIwR1VsZMOayzil5e7FJNxzRKSwHsUJp2MMCUGu7v1e/+5bbXvnUKNXQy8SOfcJ3zdszZhwwNR1qgSVsonjWBtIA/sYcSayct96609MObn2X/5t17/e/tjzbpgv13hh3tcbtlMn7V0TISdouajtJG2f6OwsBO78dvfk0wl1508tt+sNdKPSDZRSIVG2253Zdpbbd9asTcI/ffzse+976mWvedZ3vto8r/zeLV94eu/8XPHWj7x5/jd+9pJPfmzuXe90v/OeojV9/8zB5RteNvOev7nwjz637afepQ5dUaythEFtyC989zbqqNTwYAN/dsfxi7bNQdSyfT5OLsjkAtjC7zq88lO/R9jTdooQ8jY9+nCRUzIqqvlTdTuUCbdiSzwFABAkIS0irU6biGL0MfreYCNJDGqsK88RhEgEXfBlXZW19yGGEAAoBBZGjoCggosYAQC0MSGyNQYZ6uCLqlxbWzFMDiSGQAE8YgQhDyyokZxzRVGGEFyILnjnHEdhUiFGASyruqrrsqqajVLpahdDCKEsS9jKqHbONZm7EmJd1nVZNSkLEaRGdsCeYwiBY8TAEKLUXjQUvh65CrRyzGVw/WLoJTJEFlFal2XZyD6YOU1TEYk+NNIhImIQIAIhAMqyVrsz5gOfc+5527fvPHL05He/c/uxw0+gSIxRJamg9iFaaxMFlhRHicysoWI3KgoAIMYzIaREDd0ORSQIKxeDAm8JEW0EFGhYVNba2rs8zRq3QghhZmYmBBdAUJEW1BGgDlx7ICRrksS0Wq28nWVZlqZpg+tJbJLneSvNGq9EmqbtLE+s1ajG9s4mBS/PrYx86yWsryVYBn82p79Ztd6FE/u6M8VYPtWqTq37YrA0u23yjns/+/d/+/v793Tv+OGdR44+mefgqgDkl/pFTXjk+z+84Vk7nn76yNT2s6c73cIFEg4EGnC4tmHyrDcY+LKCxGitpmdnq9FIa9Ef0mvnzZWX9TvjnYUS48J66J8YDbi1MQ9Pfo+K0xuj3o0v+hEV8YePPXr/nd+eyXIfBwXEqNsapPKV1LULdSfJWp22QlJkQCoITiOUFkURAVcPP2mHfW/BRKdGOrHd1vTubfsvMl2jgvdajCAC97E/1CVlVveHNSgHAKjyotLfuO0HS2tFubx89q6dSYRqbeOZxx5YPPGECjx/cuW8/fWPvnjf2edYx2unVw6vrC6eePrIaGk0tX1b2U0zPeR1X9/3jV23fnCPTUDq0VXPobf+9862HbMP7r9/8quPPPaFZx598I1veefV17x62E/e8Y5f606M+xCKsl5bL5Qe/9znv1QW3lorsqm2ZeTSbyLOAcDoRCsbY7TWNh4GiGy10cpS4xNGFeowipCRtqw0paAIkmxxtXflBRc/etcPjx07kk2OlRBFJFVJ4BiYNaAgB415q1OXFTQa4Fg7RCYExEa5kAAljEkAyKxoqkJEZRSgYqDAGSgIPkaPLM1ya3NtjBRQlDXGJBxBEJqpl0WFHIFEJCJwkFgHLyGaxDKIj7Ehyja3g2JQhDokQCxSQqzZCQcrSES1BgfshSWyCkw+EkdQgIagiSUnZIWRIBJHAg/cSASdc95FV4eyLOu6jjF6H0IIMYTgvfe+weRWtRPBBmhQOR8FnPN1XVdF6ZxfXloZFCPPcTgaFaMRCbhRGQG991K74dr6aG19VAwLCbUiB1DGsLi6vLq+VgyG5DkUlfYBgerKFaOysXwopRpJbKP03uj31jbWUVHw0Xs/Go1A/LpfXylG7Or12C/JnDva5+2gP9UPFBzhAPDFF018+vaVv/nXhdbE+NUHeH11pQBAAqmGMzPDxY2TGIpQlrXCQYzOlQNYO1qqr96bTS4+I1lVQLtCE3ZP9FuIRm2X5PS/fdiOhUHFVGFuBKE/N0zmon1We6i1whg9x+AFFXXJVgpDVaed9PTf/d45t3zm0Zdcv/R/PjZ53ZUXfP3L3X//7vrP/8LS7O7+oDccrRWjFaNKZQWlLVO7B7t2+Olu2m1ztYRLD3vXV+NtBIuedZpGgjDc6J88YgnydKrOMZ3My+6u5vm5n/zEsUPPefNfvX7n/D36e7ft9NJRYbm9K7zvUxf/8T9d8NZfnLnkSueGxcLJUG+k289NdX7X+9/b3jNlds5sVAPW+p6LQm/X6faoDdpJayBJIRPL0B7EmZXwrPtrqCgwem9avhVdK4a1SiqaiKrMo0690mQAhJmi8Gg0YmabpQDQ7XaVUqPRSCkDAI2SOQZxgWvvqqryPm4ucZm3tJCklEEFOkuCMHhuJ1mWZYyMwD4w1Ox8rJjBS3TRBQ8hig/ReQEo67qoSlLG+ygh1t55FkZopIhJksUYG28xomKkLc4Mi8QmcTzP8zRNjdKNQZGZZZMN1OyapcFXNsLt5rshSmOZa44tQkVE2ipBaGA1zOy9HwyHCpUCbKBDQA2NQInWpasPP/P0sKzqyEXtDh4659Chc4LHe+++a215fnJy0vsoCFmWcYgoHOuAAEG4ir4zOX7O+ec55xJrjTHaGo3NkhyaoRcQVsiKIRVCRLHKWt1KbG4NoiiF3kdr0hDYkKnqWilUAsBSBx9QTGLT1HazrJskSZ5kWZJtPay1iJRak6VJmiVJkqTGWmuTJDHaEtGEmSgHdXc8cyvLhwifrAZUjX5prPsJWPoy9X7GkN4otndobr363re+3d0xK9F+7l/+LgW56RWvW13qifcoGWDaX1k6sGvmyaPPzO4/pMvqgcdvfdOvvuvSay9tnMplWQ76I6tNmqZAqJPEOTcqiyRvO9efuXd/drLdf+c6EALozz9y17a0KGH02JPfGcvHZWzPgPPLLrh65/bu3MIzTy0sLKyGRKWl8uCHzhU5QVSBh6Mq1utzi1EYmNHXNTArFFIWFLSS1Hnt6lAObKeFmat7p9XCkdGT98LAWcqiFmFLnIvHltI0MzV56dn7oFgHgJIg0XGqNT1/bLlXxZEb7d03u2N2bHZsHIq6d2pxVyefmGkrq1odMCYuza+xOJ3nKk8znQ5PuznnZ37w5Svu/cQ0TCb1yvD615Q3/nqhpm6/49vyFe3PLscvvmCqM27b7Z/5qd/58//z1Zte9KpBsWKMTVJdufWxzo7Z2V24hU1vYvFijFmaNxuUZsQPsHkV6cQCQBCOwlW1ybCMQUjbWIXRaCBaD2uXoVYeWu3xU/Nzb//Vd15wwQU8qhJGq6xKrE0yRDRkXXSF6w+KHgChVwSoDDaXNMfYlJDDqix8HQmQ9HBUNqr3VtYOzpMAoRhSnbyjlFLKbHnRdGCxrEIUh9KeGEuMrYeFiIyCy/K0iWEhZRrKNShSyoggAVitm9zf5i9Oxo6C01pnRiskQWh6R8uoAQkgIgSFbJQyOlWmrex/9VLLZoAviIjDEBQ7ZEwNK4yARe08SxAOIQTPCrVEiFHq4D1HxRCRHIAEQZYq+NK7UNW+DkQ6BA6Bs6ylyETPrazdZ+cVBOCJ8e4bXvOag7v2hkEBIYayzm3y9OGnPvfZfy2KQhmNGlmhiwEAWq0Wx+id29jY8ByLulpZXl1f29i3bx8R9XsD730MgYOUcRQCu7JyEOuA9Wjpecf2zKyh33/UgF5zydMnR90uPffq7m/81MGlvp2B6rnnWN4YBVScM/g4Pjm7XklwMhoOdctUTl+Ybrvj6GTZ1x2sqkFE73OB0dMn7Uap60GgtLjvDnro2/smpkvyJQTx7oejzqxx+1IvgbPAWZZB7VKihLEKIR/vLjx+J//zxybbB6bq3vJ7337kxueUf/kfs2ddfOH//dAF374//fQ9/u1v7111/QakS/NHYX2OBht5UeZgSLccjKtku7TGylHbRVcRU2Nko3YH0sBxxLVCahXu2zf8QvO895o3vvQz7zqwcL/xfmz7uY+n9ptza0/XdWpVXDrZH9SjoO3Yts7+/VpX67d+62s/df2Bs6Z2XPPiYn4twfEy9p7a/oCLGNIaGCEQzc+KEHd6wFCfcz/TiOsBlE7ruVFvo93WL7vpgI9Ok5UaJaHQhGtpHwITadSKmcnoPM/Lumruy0apzc88bbpvEQBRCNBabTQlSaKUSpJEa8scg3CSZAp1nrZMkp6J9dWbAWIROIoII2ig6EOe50SktAZURJRlGQAo1EopjVopQ6Tb7bayRmgrbzvGzSAHZt6K3BYRBFDKGDK02Z4CRiYBDQ0Lj4AwKBUMKQYtmNsE4+bAjBBh68St68a1iDFGITTGsGcREQ6NvTZE9hxjjMaosYlxZQgUMMjqxvq2me3Pu+H5MzMzDz744JGnn04UEEhdVojoQszyNpI2xrRaufdubW3NpElkENxsf63SDYJeEBlAZZkxxqDSmpRVxhhrVGI0EaBWCnATv6NwVA6NMRZVamySmKyVJnmSpmm71WpnebfdSrMky9NWK8/zzBqDiNbYBt2zaa8nIiCNpEnVJnQIl9frwpr5UP9oJ//xlv768srRaNZ9lkCSpTyeynJBd37zy5Hhikteevnlz7nvntMXXHbt+sogRGPasmP7vsefPrFw+kRI5dSoPkjhW8nOqdvue8WPvDJibNnUJllAwcgSIxsFPoJIFNQqidFfdOnVs/+yV14u9bllt9M+emrYkV4r6bp8n19f1+2O+IX100ff9IpXri+urwxPPvXoreOnntIajEQEAYIEEC1JXbfG2uCFAbXNFKWKEhTCQFWI0ZqKVN7a5jhzQ+5ecDX9+GtHL7ixv222aGmWWqBCza2swyPWkfn1L7kh/+ESAKzXedZOoh/aBA8/cbI7TXlre3u8MxX3n149dXz+1AtecM5Yd3pjw3XGcMeO7tzibCm9EOL82vFUdkzEatftHz+3rlzSKesTR/fcCJe+aEebj93/3fmHbn/7iz/06/wsvPH0jWe/Y9x0e73exMTE+trIUDt40CCJSTl4a/KqXjcGEJWLoghJtA+iEyUiRtkQQmTWqBkk+hA5otJ1XaM2QspzzGwyGAwmJjsQXG9U2IScL7XKCOOp00exdP31jfbUTBlrEUnJ2kopQNYgISbKAmGEuNxfv3jv+Xt37fzmt27LslaI8UzYQGptjDFWwSobgEvnNnwPU+NAGCAB1FqXDq21ZV01geREBCxKE5H01tbR6iRLY4ypUVmrHd3/T9V7hll2XWXCK+y9T7ipUudutVpqZcnKsrJzzjlgDDZDMjOYMQYTPAaGzAzRZggegzFgAzYGnKMsS7ItS1aOre5W51i5bjjn7LDW9+NUi/nq6acftbq6qu69++611rveMARiNYQNKFMACMMJqZA1vm4QERBSSuSykCIyGWNay4t1QqkPSNRYZQUrYNcvJhLSGlLLkQIFVAHVM9rHdT1VCCmE0GbRIGKWZbVvAOgZRgMRiQIRiwgxhRQtUQiJjQVIuc0m47FGbe+syWRiiBGxaZoSGAWaGD3I3I6tN2Y3LywvoxIZDr4WScwcYgKAEAJnWUptopQHJetsSqHxnq2xSCoyXB1edsllTdM89dRTKijJm0DQ6WClObJp1Jegp9NLHt31mbNPFCTdMv7gycn0ZjqP6o/+6f2/dGGnSMNzdvbvemzBho4Fl0G9eHKtTMWYKVMzrnDA8YtHOvefyFxXKVDDZqhjYKtQRyCgbn92Os0Pn/7oH5/7BzfSUFNojunGU9G8cnqBNeRZv6lGUPtOnklTxe6gn7JyU/7YL31oF8aVMAKVfv8su+f+hV94/cm/uGzHW95R3fzcwa3XbnvdlWujMNp73H/3zlOP3G1uu41PPN6ZZJA5mC4lZTkrMOlUJ1Rar1WmkzKkKrIm40pS8N+/4o23v+KX25p0y5d/76YHvohrx/n8G27nsPDEEUHYeOGzpnacu7ZauboaH3546dEnmqeemjx2fxUXb3rPL2997TuPPvkkdigL47N6Gw73M4AkJCAEJFADNqR5QAlkh7zsG6wLsp1mOpbZOC8feaQ5u2gynJnkTR21ZeNFEWQGIg2oqgqytra2DrRCIlBLKEhCqkkNGUTD6yo1g4jImNr4UFFnXR0CGxZKk8kkkOZ5DjFqkMCASY2oWIMKVkBZWTiFCACCIKqgEJsGEVlFoiBiPamSyqiaREkCCglE2yAHaj3yDK8be0pMTZJWUkW0XhFb47xWhytJFFQIGKD152kVzG3ad4zRGFM3jXMuy3gyqY0xhSt88oKICdiub68UgZmjgqgioXNmNFprbQayLBtNxhs2bLjhOS+47bbbvv7VL5999lmXPOuy7Tt2NkmJswYSWVNVYwK1zI33RadsTeVas5127GZkQiAiF1NNCiQlGKcEBAKgmHLroopzLkZhZgaFzBrC5NgaztU6Y6y1yGQzh0DGIiITUSscNckgArXQRWudpAgICsrMmbHOlpsHU5ianut8GeKrm3w1d3t8c9Wg87S6vxwHKDtzeX2Pdr5821d/ZP99L37+tbc+/wX3PfztS254/skndy8snxacPv+Cc+781p79Bw4/77qbB6l4Krfo1352//g/brnB9UtFCJKscSlElzmQpCpsrI+BgIGAs8L+Ww5vwvjzDb87P7E6euyJA1uv2P7wsTSaHsC+b1NnSrPNl1w51TX/8NC3H7Av3bizdDOr2LguW59SAlE2TECdskyNV9RkHI9q45I3GkRMJY1JedmrxydTMTvz6rdMv+mVdrBl+0RGJ/bE1Wr80APVN7+py0dHGdhOaQB0ZW35+vM3wRGYyTtHF1YHs12b5Wxx5KvltTDXLYcrY/WjAhi9p1SxQlUNp+dwMNXVcYCAU2XJHbzszs9vns4OnjymYCZXv56uf9umwQDrtW997x9++I3v7dGGDQd3Vi/1rz3x7oXhWseZ2tdFngcPzjFAij5okaZ7M1GCT7Wq5NY1vlIBbVFakXYptB52ZAmYfWw0BDJOVeu6ttaujUfWmNXxpABmIQ2qbCdJXTXetX3n9OxskNR60nashQCZddAgkxauExL6apJleN7uHQ/d/8ATjzzZmZtGotgEZMIkwdesjhC5yKu1kZo2VoVi0gTJWZeSjKpaFFv1FIGmJEi2AQ8ROIjL8mhpEnyv6NR1vbi8YoUFJTVijEOGKOCIEJMCIK17JguCJK+KDjlIaiSxQoEWVAGJMptLEJUIKiAJAEXIKwMqnhl7z5BOAYBaFz8Rh6hAJjOh8QAAIQEAAypoaC8jY0BFRCIji1pBYVBCB2QIhRWJkqQWkCiL0tdNa5KnCCmFoihCHb75tW/u3r27Pz21vLyKIBPf7NyxfXZm7pFHHiGiNvEmM1ZIUkqmvU2IQgjbN23quvzIsaObN2++5ZYbvv3t7zDzzNzcqZMnEyCFRKhZPpi41TphbE7v3DN16c76u70TO4fl3SfCT11U/vvXTl1x5Q4/zOrx4vfuXRxMzfhqaQBw4Xlzjz1xcCrjQNzxJTpo6vyLi3MpDkNv07xMTXM9lsGAwNhyUjVR8qWF+aLoLNz3raNf//j0C97rTx+8py6m/OI5U0tzbuf86jJ1nU5iY4hyrpfWNu2e2/+Fvx/ce0eRTTeerOvyeKTYn+l20tGDi7/1i1U2mGzcsHDryzoveD7fcNP2H33HXPGOuABLT+6Br3925e5vp/1Hpg7tqSg5Kp0relDE3Wc1J497UjUBu7lB2LPrZV94259ec9fftC/xSz7/m0mbxVe99tHpZy3/0//Z0OsOx6eru2//wX9/0eLiYifkbKLhnDds2vmW18694YeqtcnivqeWadWwNhUMzr94Y29J9W7rc597sFE2rkIeoM5UJZ3ekkzWKwfAsSk2Rhcm88P5ii+a2TgaznNZ5BFXk6qqkUwJ2z1GkWUpQZsuH2MkMiBCRGf0asqMhOCsQ0RDyM6mlBhBQgTFoGqJQwi5cwlUICKaEAIaJpUYIgAYVWyZiyBZlrGl8XhonFXFGCWzthXdtTQiQNSoTdMkFWQ2yDGqJRZJbVltY0haVQMhoEKEJACGgVXrNi+4zdsUUFELaJCiCEC7TwVl40WJWAidtU1dP+vyy594Yk8KsbWKC5KsyVq/eQAAAURGECZt3bU6RRlCSCkhwNRUfzKZJLTPee4LHvzBPQ89+IOF+ZO3PO8FO3burmMkJBDpdrvJh6ZpOnkx9rUSGEMtOcsgQQQgUlWLBAwZsjEmty5zBggkaYwRVBIixASFFRFW4cyRCK7fcOCMdW59wCViRFnfJgAAEhuDgG3LrrgevkvMoNq+3JnGCDZX09jmRTiVYzWbilcVitK5sK4+XVdRw1ypS0MaDasfeeOrXvemd1z4rGv2PnXyuhfaCy9/1nCx6m7jc3ddfsdtX7XVeGlxZVTBz+3YffbC6v3dwSe//flU+zpnBHLEI/G33HjrXbffqUxRkVGJGNiSodOHT9k/KsKfTJr/ReY++ff77//VW57D1mOvPz135XDSjFZPbzj3wksvuvi+Rx548uChb6X4I5XxZUieQSWScojB6Mr8ohqgBKkaE2IdG2tMQ1owJoNYez73/M2vefPsNc+ZdHMAsSZNlec1bmAveVa+9eyV797eW5lvjh82olr0epPjo4jZu9904/cePvj9h44N67CxX4CWJw4tbn3WWVu2DLg8++SxesvWLVV7EkMxleF5O8tH98QRrhX9gd1/39rCoyOXdYuZU2/4zXrDbjM+XqfswCNPLB96uth0waP33T06mfQ9q/5Tp/IkSl2XZUkSGxAIhMqGY4zdzvTTh/dn3XV7Jstm0kysKbz3uc3bOAGXZYgYfPKhBiBmGo/Gqtrp9GKMrbMxN+gNUVFoaiSZkkxZmKVx9bGPfezGm56/sLhMjsSQcdZ6JsCMTdU0aDJB6XXKH37LG751+z3zK6OD+/aassgQoyYlRWs8akyNJm+dUUJrDTRhutcfN3WqKlPkTRI0Nkg0xqQUiUhSUsTMWsvQNE0ii0qhbjCKkIB1BJBiRMcSUwoJjIuSWoxdQxSJzDYmsdY0KbFPGRMiTlItQJk1GZmASVWNEgsysqICUSCVpAAKeCZHQZQQBbS9ZdpGX0SQz7DGFDW1zuzJZs6nSAqMbb0Wa0yUhEiSkqiGqmFsZ+l1JWUIDRm01q5Ig8JW0QgcP3DkyL6DzIzeC3HpssX5hVMnT+e9DtusrusIqYMmQCSipqnaL7Vp06YW4S+K4vjx4//62c/t378/y7KqqhQgaiTWrMzIYKFoakXGsBxe9NCmE1vr4SNlA50nTlvsyFuvn5bvd7Lx4R9/887f/OgR1x0wH5yfX6XSTsrp1IxWUyh09btLu9IiD5zMo//y9mv+y+Ev2+SHpqaqQ1lBySeQEPOzTOfIR35r9srn7dWdp6M5/9gXfux97/nlX/uH573q1U89fWzKzIz9JOu6MnO1P7HyN39yacyWrQZcyupilFFg6IzHrsjLqWIKSl04vfzpv5BPfrjZsvP47su6V13evfntm6/dnf/Pn5+FX145uuoeeHR0+HjY8+DSA98La4tmIO7ASq4RQ5IxLW296p/e/pGzn7ztFY9/bH1ou/yyr1+/bekNb+q99X9tT5NGZ/sXPNvuusJuKrbk0zNbL5c8zzcPaNN2zIrq+PGn/ulfn/OuHz/w9JPqbARIo+XzHjuPrjDdSXdsKrAJygl4g4sDBbRfu6ZXhVGyHms7f6g3M3AAl5+3JivBFXkVErKvkygAS0DEZlK3rqWTyaTT6TC7GGNICQFBVBAFSFEVCUEBiNlgm2xIKCBRgAAIDaHWzWhsgiJoFElJAI1rRxtUVQYUgETgkJAhRs/MGhMAOTYpRQBRw5AgSmQwQEiEItrKc0lFBFUSIoqqiCAZCTGCt8TOOU0CIoiALTIkkqgFeBEBFIEQQNYTkb337GwbzNA0ycbULTsPPfigYeesDTHGkNCRpnXPJlVlsqBqkJAlBmYlS2wsJkpsTAih1+vVIUKSW5//gk6n+N7d3/nKl77w3Oe/+Nrrbhg21XA4ZmZFYpdVvnHGaorJGCJqRcyx8aqaYhQRzW2pbMmqRbVkkRQVEa0xQcWIJoPGGK0DFc4oZmTRMWW2ZagZZQNUuDzi+k5QFRSAIwMiu3YCpjZgFFv3FQTRJESdaevr4TRu/3xYpM5EQh/9JMfTfzA497Nal46nc53dddHUnqeX5sd//dd/ASwg+tCB7z3y4J4XXH39n/7tX/78z//8I/u+MT9qpjb2ji0fjWdd7PDwPxx98mtPHO0W3aoJM71pBBhOhnfccUenLCZNowiUko910e0bK6unFzZ9cdvpXzkIP1vN/Le5I08d5uB37Lzsrnsfvfki4O65vPVSqVZuvuzs7z32QLFSF296xZPf+O6GxVOaO8jQ+hAcuKCSkVQNF5lNEl0WUuxGBJfVIbgmVqybXv/m2Re/oo5eKpSavWMM2m0mVMTBTc/uXnl5hGb4nTvM6cWVtX41V1Bcy5qYvejySy7bse0bDzxxbLnOHGbd/OTSwtzUlpTGVb3amwbBJBTJZLWsdTdy51QvytpkMjp/zw9mhVydzd/wI8fZFQe/m9vNVdc+eeJJhfCNv//dRot3/fIH/jz/mcd6D+1ONxoDgI01RdNEgoRMMaDL1ZjcGseAQVKKCSFmuZEk7Ultf6+qquXptcll1XhyxeVXnDh5cmlpxVrLSCklNUkQoBpPqtV8sClBCqEyrKp6+PCh/sxcJ8+aumbShCqgPuHAuaoadYvsxKn5j/7dp7pFt6kar6mNSAMAAiRElFSYLDFDSMomqqjhUV2hM6y5IBhjmiRMhCCGmKxrmsCITYpRoSgLS+wnlSVOjpzNRnWVscvYBBVC7VibRBOgEnrvLWH7pTJjk2ppXN00HtUZZGVLJorMT9bs+mKM0RgABdAWgJP1ARiBEAQEgVRFJBFoS45EDDEWnQIRJ5OJUex0utbapZVlJYQEeZ5LCk2KlDli01FXVRUaTsk74CBijAkpWWvH42FrnOtTnIrU8icjYzCAyOOqNrlVwCQpgWzcvCmkuLY2YkQQVFACZEtFd6au625Rbt++fd/evTNbtrg8O3Tk0OpkuH3nWYuLi6cXTlmbMWUoKWtgKVSFIjEE0yky4FOjyzP/Fczmsvi9/amTBieWRscPwnlbmu5MlEKNxT5mKToQ9JNFaDz0yo7fUvih5AVOzPTy5J7i7LdOb7LLB2auv2X8/XtjM1bMcjIuihSwfRxO/OZ7Hvr5O7e4yb7vfopC+O1fe305+OpVN7/45MFVZ9x4ZdTZvn3+ri8NnnhA+rPg18R0Q6qoMd08w8zJiFK21mRq3aBnp5BnNsTR8h1fyB753vCTf7NSV/6mVxYXXTF7y9XF5Vf1XngDdt+E4Oslx3uHS4t7dO8D9dEjo9D9xIU/vUFG737p1BcGr3pGhvTAhrX58p7njp6MOvGU73juW3e88IUro2HOxcTFzBdD12Qnj+WDTSf/44vT939z5WW3Nilm7MZxldJMOT9z6/de9s2bvojLU1qcxKVZmnRUkv3s8+jY1mUShtUuFbaP4kwV/cLSrkFnKSwltjZhYWSRFBrRlhQTQlhbjXmep5TasTK13giYRDFpa3vDhgmAGBgQJUSbZ3VdiwgAe++hCdaYgJpAEYABIxMANYgoSAIBNaWAiFIakQTrOUjYGrwDABoWxnZSk6i9Xq+JwalWTb1eKVLKnG3NYlNUlzsVGIYmQGBngVohL4qkTC1Cm/qJgJhQIyiokgARJh8cGwIybFWViI1jESmKos15a4MQAgiiimibyV0W/RACsSBC4xMBssHMuhBClGSsFYTSOhFxbG59/ov6M7Pfuu1rX/rCv4dq8qxrru8U5bipiQgIy7IsnQPRkW+e2W2DMUyELrPEURM4i4gkyoDsLBBbEU6KmEp2LRDVmZkJpCYBZxYALFNbzpltlERsbWwZ7+2C68wdQ0zExEwIKbWxpLieDllRrCvocLapP7sycbVM2XTezM6tMXxmVDcatpEFgLt+cG9Y7pdZSXlunF1bWd2/98Duiy/89D/9XT7Vufqqa3fPXTZaOdztbC7yas+WDW/71qe/MakddVJKXXLLy8udqf6WzVvWxqNAYNkEjSSJ2HT7/STeGJsm2vvr/tovreR/0GuWw3f+43OXvPXHVusdqpItP2EJ1sLJ5936so9+9o7Dx+87cHj3jh2bzzpxuOr2yqJc9UsUklqbam/yDADAsA/J2VITZDNbxssLtDTfv/qiqQuv0jpmFXAm3LFeXHLVWMhImfpUDBAVypfMmST6kc9+5errT+0o8q6lU8Nhb6p47YtuePqJA997as+qj6OjaXVt0u0Otm3p9wunSfJSG63qBvuFveKs9O20ofPo93uTowS0tOPcPbsv4dUV193WNcq2dHWj2sztPPdlr/yZ4dJ8Xncf33XPJfddbWI+cjyXwJo0Ie5JR6n2sSlMVljbpFUhIjRGLGKqwFNMo6ayRRl8JKUUBIgBSEm8Xx70TZZvPn7sWMdtACNidTQBPz69c8uGc87f+fjeA6bsro2afnf6F/77+//hM1/CCMvVKBeTYkyUQMEqo9ecC4ha5P3T8yvHdEkIu1wkL2qgDsHl1jnDmGtUAogEhpkEG/BMnJoGEbUJ4ExmEIICQMNKGgCikDEEJZvogyFTgY7BG4QYxDKTgoI6skG1RgWWGERULHNQTSJEQIiI6Bx2XTkeThSNiEeLMSZjjKTY7ZVVVUUMKqpez6zTAAFDklqTjcqOGxQ0hptIYBhJRTM2EMU6F9gA2rXRqmN2TCGpkJ00PiPDjNRa/aBiTpKEyCRVyriNjiEFBEYlADJo1CkDRJ8IMEoCw87lMXofU8e5GlI9nlSTCTKV7DxxG1PnvZ+Znu5mnVOnTj289igi7tu3N4RgrcudYyH1YjlnZJUQU4plf4ooJBARkmrofYH+nPHCHO1cFs8VrAz9x7+tb7T9OFn7lT9ZFFcOx2uDjgX0riWbuIFpUt0xjXZ5+UA16LrghmqeLi46d3K8OrK3RunuvLA6djRQjUnHoZ7tb9xnz5r3/Bp36kN3fj0rp7um+eSf/2K/GGy56CJ/ctTNypBGp/78dy60bimszaRimniEda1Znk+lrBjrcqFcyxqFLo5MrQ8WMzv6P/xfvrVxql7yF7rpjU9/z3z6j0/8pdiZ2XpA/pzds896jj3/snL3jqnzdsMN1wjLH31BskbetuXAntPzT9vTzxTgxy88tQE2ja+7OPv2o6fycmrLOWvH9qEpa5mwKxtLOYSIrszzyWR+y86zTt/19albrh/GKgL2Bv3J2F987Jrsazv+/qwvxa0nyWe87wLz1Zvgqeu0453h6IxLnWgmSGDUDvFEHRksAtRQNxGSIKQoyKllGiCAeiEiBooqKME6B9akJrIgqaqmSahLto001rTZxgRArd84qI2ATYyZZfIJBAUws6XUNSeBzGoSEjAmE0gESKApJFHg3KIkIcDMgpcCEJitySqo67rO8zw0MUcnqEoIIAGSzWxqYlKRmIC0m2e9Xm9ldRVSQgBTFBgjMYtgO3cbYxxim0OQlBKCoiCiEXRsjDPrJiGEgJq1mQrEwpiZLFXV9dfc+Oijj4mkvEDkpECInDM45xhNSqlwhTE2pRTPkECDpKB4/Y03Oee++pUvffWbX1sbrV5303NzY6OvyNlaZKrsYjX2zhljYuOVoez0VRUlOWOb4FvChyAgmbahMWRDLiVYC6alcSBpxsy2FX/adQNdZAAwZJCxQSKCgMEl0LQekZZIWgMlTUJM4CiEIElVIKBfaKpSe00cv9n2t0RYtLQ/VJ9Zmp/ubCgS9no1AJysOpzZqV5x6vTyyDemVx5/ZM+5V1zcmZn52F9+5G+ZRePbzbte+LJbHn34kQ3G/M3yJN8ww2vDGlMlSgia4rhuACImAEQbyVJex3qwYWrpxGmumjofDT41u/bfVld/Yt6+f+77B596TQaL6rMN5QB2NvVk8cQJ7C3t2rzhgaOHcX5yatcFftMWXT45HCVhZ601ZVds8lBlEWrBbqfw3nur9vBTuXP62lcMXvIaHkylEJMDVRT0SGA1Y8TGIielxoe6VgMmiQwKPH70+OIWferI8fPO2TkZV1jNn7t756Ztg7u+t/f4qUULGXg/PR1cibGCTmCxGUZKosXG/vmTLO5RhabCYnju843W01mnTrrkvV87dNENL7nhuS8+/9zzlxZOZIQXHLn6ye131/f/bOmCS7aCCYF1Pks8wixgUMpLQFNPki1sTPWb3vDGr339G0cPnD5r+86BMadOnTLWKgiwqkaISTnvz83ccfe9TnHD1NQkNiiKEPuY77jwkqXlU6RkBKT2m2bnXv3+9y2O11wvn4QmSEDGlLRKPonUIBONAMCKqjgo+2hwOB6JJsrMcDg879xdDvH48eNYsBjS4AElxHVyY0trUtVi0BPQuq6Ns0nFEokIGi7ASIpV9CIyCWNBYFFVJSQmkiQtd8kYkhiZUYhMG8liLSMZZ0NoiHBtdZJndnq6t7y8bG0xGQdrWTUQMeg6zRKUWjZESqkNUm3pV+sccoKWoqIIwJhlebt28r4W0CIkzjJPAoQZGEoIDAKxTfBlptbDL2JrFSQhxRajI2NQlKwhoqgiSbpFiRhDCEgokDQJkckANCaXmdWVlSzLTOa8j1yWDClFcd0ixliWJZK24u8YxGYuRbHOKYqAOmuMMSlhEhmPxyE227Ztq5tmdXU1z3OVjjF1P699pDJ6KNOjR9KLtgx6tsIO9ghTbleWJsO6p/mYA652eeD9fzydP1FvKsLRoh55e6LJd96fn3OduePAoZUSdHT4UI3JYA+yaKRXr9UHXvcbGx//+rXdez/897d94Kff8c+f/8pv/94fH35679aLLp3asOW0xb1/87Nz+x+LpZsKvTWIJkrP9XpQnq5WtapK4tSQSTTVpWBL85y3fmvj5i/c/dj4u3efPHYSi/KsXRdufv5r3nnl5eXPvW9wEuXxh+NXvjAJfhkhzs1pb/vn3/xXSxt3P/eRP7z/rC2z/blbNz7rmQJ87PP/sf3q8qkfu3Lm2/fvvuLF+bYN9fL8XN6tMfooq057ZdG1naN7Ht5wbG+xfVe68IrViVah6UHW6WSLK8soaceps+yd74rP+3bx8R+i71/jY6jTKZt3aQKchyE1uRSxHkXHh57Am69zx9fqiWEnitGDChoLRN57ay0BRxFS8CG0EqMm+PVloQAigkhmXd4pU0jWOSIKyYfk2VmKFIKYzImvQ0iGjTEUJJFBk1tGm1RCCJwUEZENGI4xuU7BSGSQg7RQdpFlbHmdGGyKqIKqxiEyobGtRCCmwMyYZSSYkqYog8FgbsOG1bW1jRs3TiYTALDW5kXWTpbtQ2jfU6pKQAlBQA2xAbBIyGzAorajQqtvakPWEA0L0alTp4qiQISUgnPOZUUIyXLR4skti1hiAkAACCkgmxBCjHFc1Vded13RKb/0xc9/9/ZvrS6vXH/L8wcbNtaTqiyy5dVFdq5fFgBAzrWWO4jISCnE9suqamtsh4ioQNhuccmyY2YCBEKilkVuEFEJSaHF2AEUCPMkUbmIuRAoekZSQOOddigSKCIwqmpE9aQBZCTJLy7XNk4H8xfDeSED4wiy8t7urBv7P2LpWwCAUd1dqesQ1sAwte07wvD4fHfQjz5Ya6vl1ZOHn7zlhdc87wXP/o0P/WziEGvyXjM13MkDJqmjMQZd+yqLYDPxjYBs2LJ1/xN7IuiOzZtPHDvJH6b0fs//K99zaPFr3/jawrD5zreOPfn4gWMrCxlJjbEYbCmtffiJB+8/fcCuVC/ONp7c0nVHjuVZtx6PZTjMi75KnRsNtUcAO5Smu3HqTW+efflLspkZ7z0CapsRtc5KU0XseJykJiJgbr33pl/m1XJjNukw0adv+86lTxy64borp6fnqtGqNcVN11957733jzwdW1y6dMuUAUmo6ogTR1SjouDP2jW1cGeN4psdl5466+w4rGsqeIZZoGP6vcJ2ynxh1AzKTq8szj9+62fO/W2xa6tep2TOWqVSA3twydpuEjZuSgmz3GSZGXn9xN996qprLl+p1zq9nAAxRmJaretOp8NAKBAh1CEZdowsoEiJmaHhjdNTG+bmnnjqsVOLy4PuNCqEED79r595x7vfORqt9W1uMjMaT5BN7StmFklAuC5CUPDegwdKWKu3BoyhVNcvfeUrP/uZf11rasgzIrDWeu/z3CXL3nsACCFW0Rsk53IgSiFUoxGAuCIn5hSiJ7XKNgS0jhArTqoQY7LEklJuHSOwhMzYEUqMkZEy6+pUtzkO0ScmmtRVE+osK4KPzjlC9Y03qEEmkJJBRARq852UFFq1gyRNJAACZJkRtKV6EiJTm5XIapghGGGiDpjQeJehEvgkyGRpfWcsIgZJlJhZCakd00VYUQFYgAhjSsS0bmVAqioqQsQaU57n3ntG4jzPs8xkGWdcSXQmU6MoWpbl6dOnN23aFGIMIVhnmLkoioX5xeXl5SyzTV2vrE6mBjPWMTPPzk3Pz8+nlDZv3jyZTHwDpeCWvNq31kGw1oRs2o0h72I1wnJ3P6w2fpRiZmVFJEl2Lvgvz29/cn5qY2hW2QSL1ahUN3p4+9Unj30myxelzgxoNykkX2fQQdpz3UsXN13wpk/87CP7vr3jD//2k1/ft7RY/+lf/MVvv//n/voj7//w//3y7EVXPrGwaAFT6k0w9gYWgccjyxj6RY+U4spa76JLH772ii/ff7/ZfeF3DhzXR59451tec/jo2mf/+ZMAK3sevuMlL7pu8Lf/1yBrJ/Mp11z70MPJWrYw/LvX/tKpHZe/BO6afs6Nk9UVvzIqp+eeKcBnLU0tfvfx7IfPf/Kybddc/jyMwWS91abBHBntrqne/s9/3vYG4/0P431fO+v5v3twY2dluDqFJnVczAhIc2sqpWx1ugKgmaEaMECbe70RQLSQm7wG6uSZcrY6TivN3NieiKA5GTApgYOkyY8DBGZOKqJCSinGJgYyDKApRCJICVoaLSSwbFaGQ8emZSe0kSGIBABkCUCdc22pVgVmAkZDxhqOKTETKxhCMhwxqWTqk2Xy3g8G/RhjlOTQRE6tt3xWthVUW92RBhEENpSSZebcOkJumiYGpwBHjx7N8zzG2Ov16rouy1JBAKCFl9q5sAWuGVlIE6glNkAEoKStO6uup40BKLUJb0iUrPXe9/t9ZorRIyJbk5ISqHMuqTDbVqxviFNKGWaVb4waMgweq7o5/6KL8073a1/49/seuHcS/Y3PedHWzTtM8GisEBMgAGTW2cwlFSJyxqYQU+u2HZPCOkTcOrg7Y4mI2baapba9IGrjWTGBgiIBtpstRNTcakioFIwkUYSEoOwkJz5jdw8hRQrRxtjEUIwqqX2vX+L07GXN8K02u3M8udRsWpTh35hhzxVnlQkATq8u9U0pIGidbYLEJCLV6eWpjXPHjxx1MabM3vb9h/7P//5DxfTxv/1kYQ02Sy5z6CO0lC8A2yur1IxXVnpAgkSGUbQ36Nejsc3yk8dPKCL+dYE/P8b3rlW/5D7yyX9RaETB9jf2ZqdJlBgyLUwBw1MLhe0Oz9ltdl1ZfO8uqGUIq+76Kwso157ca5ux2ixDHVGIW+d6Nz1v9s2vgW4/jUeC1PqToyhRG/ahCUCSoGFEgCTWZWZ2evCe977u7B88EYLxaeqBg6NDp75z+ZVnXbn73Gh8M/JXX73r9ruf8JG3bJ2hioVDYzjUCRg4UVNVdqbnLtg0ddmbD8GNdZ2EJslkKU46kYbg8ykS6gCMpT44XtDLwkWffo48fPa9rxi9w3Q7VT3CKP0OAZmUciB0BW3auO2JPac6nQKhKjvu1OmTKdLevU/lWSaQpqenr7ngwttvv6PX6QIgGelT6X30KILRGWQlLfPjK6cPfP/AYHZGiVSNAozqyYFDBzNn/aTacvZ2HmSPnXqy2xtAkjzPwEfidQsrAKhjVFWb2b4rmqbpluWJEyf+6V/+Zb3tFbKZQ6QQQqvfb9+NiJgQQDBJjKBN07zg1ufWdX3n3Xf5ARdJDZFLEA3XnPqChZIkIqKqqmzmyNnheC3P7ERTCLElHNa+EdDRZNxmoiWNpFR0plJKlR8NeiYFsZhFCjEFOgNVA2BKQVWB13lWSArMqmqQDBJASiKgUE8qRGYhy0aTAESfpNbYHfRKl68tLWfWouPopZUTgAHnspQqREaErG20ERSA2SUVYRRkR9ZHD60rGBIAOCRRrNWbwoiqddYYQ6KGoe9cUHFs1p8Ka5nZOIM1tM74IlJ2CpfZajyZnZ254dnP3vf00+3gjoidTqfT6YxGoxACOJrKO2c3p+9e2RmZYzAksBb7hLpR/PxqDtXsKE3GAbtdt8HFfaOt3zo963BlhaIDrU+OYdNctjY5ZHt7Nl573fFv74e1DhQjQ3mCnFPy5YMv++D2o/eYna4czez93f+2+7d3Zudf9WNvfOmjj96j0PzCz7/143975y2/8clHzzln5Q9/e4vthnJ75puEx0zocQZ1PdFdO9fe+eY/+7t/XNh77zsv2PW+nduXdrziofvu/MLnvpAKM9h48W984B3X/Ms/Dh9+RPudJvhMO7xSTeIpt2Prv/7w3z9+1suuKR6zayeGq4k8uOli9PiRZwpwfwCPvG7TuBhf+qMv3ri6eUWSB8mdwQRZr7e4/yl/YF9A7heuuPEFeOOVo6cOWguBTWHYSj5ZHUJB2ICqxbVePbXUMSbL8sW12lGXMhOxSiZfwspitpXGr79qtp4cVjFZsm6qOHRiDKpkEETImBBC+5oiosszHwMzKSI700wqa9fjwUSETBvAlVJSRG31wUkCaQqSGBiVkggAMAEBWGvRsDEGMmuJDTFZrL2nxGCBramqKi+LJtTO5JnJmmrinBNQY0yL5RrjQggQtU06UqPGECITIDjb7ZQAQIN+G2FECDPTUwBgLQOAgK5/JoCeYai0SXEEas16fhq0fOkzLw2uF2BFpswO1iObAIwpAaQoCufyajIy1kZJbeToeqUPsQm+3+mOJlVd1y1Du/Fh67btr3zDW+/4xhcfvO8HKysrL3rRq84/7zyJkUOyJRtjCJiIrHXrxVSBCFBBWUQjIgKtz8GEBgCQGc/oiKhtMNqNACogKCAgkaggaEysSTI1UTmysAOAOlaVEQAFJjGcUJNKk3AsqdCotfr50cLy8cv69Z+sDH91+uyvLB35cgq92W3Ncj1wdUiwGLM6hTLLJUTL3DQeAA7ue/qiW58NgBEAMZhu/o9/9/Gl5VOdTt5QByYJTGPKPKQIIsAwHK40kkCtR6vaNCls3rKlaZq1xeVep1eNxzYrdMGVH4fJu4f2DwZuNJPZEJM2FAEssuW6MdKs2aYg9McXDu4+Z8OPvP7Y0okpe2n+gquzi6/Kyi29U8dNClD5ev5Ef7ZXbt+RbC5IMB7FLIMmEREpKMT2eEgrCWMgBBQFUWONWVlZ2j85/NazNts63OJn79t7YkXpzvv3HT++cs3FZ5+zbaDQefYVl3WfeLRPUntNGZKIMuVoVCXjMsW44zk3L9zxvQNHDuOuXZuonKSiU3u3YXORlu1dt9H+e7MTB5q0OhE1BBueB4/v/bVrPv5kecs1Mze/ND97hz85b0axyocdEqUNU9NziLy2NiLDsWmOHzuRjJsq58iaCicRcHVxwVEKcUyGQyPGGABiYpHGi+S5E4DObL+n3dy64bgCYwAAkxnkPQKxTIcOHKiddPJODIGRRsNh4pRSIGcRsfVERKYYY2gaEkw+mixfaibOOUPOJKzrmohEQARaiLe18uHMhabJjDWW68lkbWW1qipDlkIkoAYEGYU4YUxRjbFeAQhdnqHhqh4DUSNx0O2xj1VVqWpSFdXWl0BiiipAZjyZpJSyIq+ahpUwoVFCBsMmSAJVZiJso2kNyDrUBIZRBBGjCp7pG5IKA+B6i6ZiGAU7NmsmjYRIuWM2pOAlEpESWuK27AEAMztrUkpIAgCoaNGkJG1kcpZlrUEmW44+MnGRZZyaFgm0bIg4t46tIcDpXreqqjaO1DknkoiYiLZs2ry6uuq9d8ZaNqFqpvqD3bt3n1pYWFxYKIo8BD89PdXpdMbDYa/TqUMYy2TnlJ09mpZENTfkcZI6ANDvLh2IJYQmstV8sNsde2Rt28ee3mjchKBXLx2sbIdjQ6eO5XMblyv4+ty1l538nusPZLRaSAlajSOevOHlq1sufOH9f372b//Z/a+5+dLl8f73veaGf//+VTc8/9EffNu67Nf/x++sdm33xPKNv/Jbj5x95cEP/sTuow+j21pKL3WsXzk8eN+v/ZXrffk3fyuMF9727vf+5MbN9y+d/q2P/09ZXuxu2/GTr3/r+UcOzf7h708WF6ScMcMJ9DlPzaKDje/7nS9c8qaHFrddLvdtW3ikMWq4yHLArm1GK88U4Oy228q3vuzwpFm+embxfrGVZH2HySPmVIXxkVOb3/pyF008cXjDua85XQe1nPXt+MjyzGUzmHwTU0fNKEUMiivTOL0WieKoIucKNxm5Dorr1BxttTLOLtgAB8dLO6BwVEc/qlez6blNcAqb4E3GZZ6P2/hLa1NKGpNl0x4bY0xkJiJr7DqNPmONCUQRIUVhRsNUe4+OC+NCSDGGLLPGEBIwo9HWXAKcsW3JYGYGowmMsyKa51nSmHPeuuKY9QjO9ZCGXFERLHHWdS2krBLN+vANrVVke0oNsYgMBoPWKs44xjOufO1epi3ArUA/SgBRPgMvqSoBn+mJgVpJHygxaCRrbasbbsswM4fQWOcAwBgnCESEou0eyhhT1zWBWuKUFFVSkKYJOzdtf/Ur32zRPfjgPV/44j/f9NwXXn3Vs0vjqqbucocsszXsLCJiAjKgCIYQRDUZIFUEJCUiFAIAoDPMzPWRgto3e/uI205aKCEAGhtiIoWucCKD7BCoR72MTEu8ggQaJCVlQfLSOHPUNGPkLRlwY5jCPc0qF+V71D06v/CDabdz1i01nqTMIdT12JGxRZH5RomRaegrVTXOVpX54LnnvWb7ee/+we2PLK9mk0XOOUygYc0zA0YTRgRTRATSgBWTSUG73W6om4ytqjpjU/S9PB/+nuh/UfjJmH0kE18TFSBVTCQShDVqzACLmcGJYyc//5XP/eR73nvRL34wrg2LXbuCSq6xOG+3V8+Ud/0lZF0lklWh16TKQBxHZjSKAJDOVF9BACaXQBRcljGgApl6XN3+/W/8yFV7pgv7xlc+58blldu/89Bj+0+cWKy/cfcDt1519bPOnyl5dPklF0Q+7rJ+B42g9hgU6jUUIuSkYsrezTc/a2/ad7AODNaurXHR//I/nrX33+ZAJs7WW6/ddPWV5exUHOmlT/7z/S/ft/LTnzj93b9e+bMtnTf/+NS7fzafmfULR01wWkdEjNE75RABgU3GqKKota8osydOnzhx5HCv1wOmoNLPstXx2GQ5R7XWQIZCyKIhhNI4ilKyTYZUlV3GQj4KOoPG2AxESEVCisTUekihJPCJAQUFAqiIGiSBzGWJQCm1wRo969pQFxX0TWyphu0VEEMEQrImxjgou3v37m2RKxOiMicAZ9gpWMQam8gqqpAiimIdiMGxoaR+rYoE69Y8qkRkiJqqBgDj8iZWyMCGUK1liqHqdouJT0oqLVOUSVDRMpN1WYYe2+Z3HdlTSCqICkyoQswhiUGKEo010SE3iHXqGBcJA6Zup+sUJ80inLEhExFUJVJrWS0qQUxBVVWDsy6GZBgJwDEpuXaiQYuWGEByYiXKnDN51gpIuMiqyRhaD1siFcnzPKXY9v4xxlbK0soip6amJpPJV77yFZdnZVkYYwCgzTQtisIYwy5P4jfnxRSvnIpbGYYoaWwyAGDwHDeabm+yPDrw+Im5a3f97d5B7pw0TTkmKjZVw0PUnRutzft9T/XP23UfXnFk5qpzVu86AgDgByBBO/e/6Fe2Pfy5reduPfnIiSO+2rZp98zxR+97+4t+6ssPLQtevnkq2zzzky8//9zNl7/xJ3/hpW99w6Hrb7zn1//73Bc/sw0kg+lxb8faJ//9XVdc+Ir3/Oj+UXnfU3f/n2F1fO14wWHNTr3wlptvWF2O//4v49I5dblM3DVXjx64+2RJ43e868CVr7nr+NaLwmOXyEnIO9MxNlo0Op5Td2J48pkCPPfUycu/Nz72vE1PD4/s6y3ujrucSGVkUGs0advVV3GvN1lcQfNELKZPn7i/zjlvNGX5bHe2AUlI1mYdSiFjWp1Kg2UKNAGcKuw0Z5PKaldM5mtjTdR3vvCCMBrj2qE1o0KZaTDSCIkK2zNIo7Vhm20gmgghJo+CZAwjSYjGGFUEQgFd98YCNIzGWDA2QQIA51xATSmRgiU0SABgkBjZWadnkNW2PlhjncmEJCigD4bYEDOSI+tj5DKPMRhjrCEFaK1V0ZFKYHLCEiNnLksadT1Fu+VKaAvAIGKrghVIRAbOuMsBACogYmwDGGQ9m7adLFUVlQERCYgIVUSkZXJDIERoY8naSbdliSMyIgIhiqACtkwOSSCaUmoRb0jRh+icwxBS8o3wK9/0zk6/c9cdX/3W1740Wh4+/7kv7Ez1FCmkSMIQpb2dLDuRCISMoESKICi0PtgiALXfmnC9yXjGdKyd4nFdhwKKGoksFxz88WZhOa0cHx+qUrVvZf9qt1HVGH1r7NU+CUMdQjXvlGbAj308f2rjOfHUE3FyWNMe8SfQXbR9+5apQ0s1NzTOwfbVNAICSkS9Xr87NUBEm2Wc9B27d7ymszUceeJPp3b9LK09PdiACrlk46U94+XTHEdCoFmX1SEmsYkSAEA56Bdoow95nreg+9iPZ3nryj8eCT8zsf/sZLW7sjy2FgAjSjQdK02aLvvjlWquM1hcOv2ZT/3Vn33kbx4/xb0QRWMVfeZECCWuoFhTBSCBjFcFI6TcV0kd8Hr0FiACEzGhYU4QYwCAmDRyMr1B/7pn3+iX79i34P/i8b/auvH8t7/0VU/uP/SNe+5dqoqv3n3f2uo5V110DuHqSl3UaWKDa0zMk43kQUgVTWb86iR24OzzihX0xxeKbiF8z3dunjnun3fz07h19qqXlJfd6rbOddg6m66bufBb296C//zJjV956ti//sXa3//P5Ts+d8kvfqS84aZwctFgyLKCqWyCJKgLy6FJiEWDNTGBpH63Cx3yPooXMs6nhIZVk3MZgMSo1pJKyk1u2WiKnTIfVhPDtmoaMIaIkAyx8aF2CbKiw2QkQAKFdnkJaNmklFRTVuSq6n1DgC6343FlnDPGVL5ht74Kag8oMYCgpliUnTYzABUQAJ1hypg4YDJK3QisLCjKBMZi0BxIAWamp4bDYZ2aCCoo1lr00TKbIgfC0WiESI4NAChgZm3bsqOKEnTyoqonmS0AIKkSEgH5pgFkdk5EAQEVjIKH1hCBkFAJVATOeOVEEFAxxFkTI2DsuCYlk8SAri0tAvF6qAOujxpKSUFFImuGbZuP4oyRJA7ZIINBUCBEY2yU1FJdgm8sUt4tIUrb8qOI983s7OzOrTsOHjy4trYGiEmk7HZ6ne7S0lJrmNDtdrGhTqeTZdnT+/a3r0trMdbr9VS1LEtEHI1GULiwhkWezttMe/bGHC1RtgRTALAV6xOMaTy0g/DwgeKxDVubfMVNhlq7RVNZ1lRPpdFCr7uxTo3f80Rn57P/4dxX/tpDPzCdAoeLK3Zw6LpXrW0698q/fdv0H35kwhte/fnv06bpR97+I+f94Cvffd0F/+V3Pzv9wmf/7i/8t9W1xRPFU5//t/9934Pf+q//7Vde8kf/dPJH7nzsL/9k+rYvbfATrk7QnUc33Qk7Nm189i/80lt/+UMzAMnTWbu298/ZVU+wKacHSp2dsw+dd8GTk9H1L3ozvf31+2XrXcd37OJjt+Z7VGk8kVhibDwpD0ONT+x/pgAzmNnPP8U3dJehuX3LoWue3LaUa85ZZSDaRrzJEo/2PNzPbOPiUFP0mU1KAZlmYGkJEWPjAyimCKtTML3cytUmsUarZWYoUdaQZiXQ8HOPnhpEuOGsEutVYsqEopekwoCCpEACkCR0ikKTNME751q9UOs5JSKta0yUYNkaY1C0TaWMQSKIYUbVJOJMGxKKUSOTMcRlWbSGU2wIAJitMcYQBw0AYl2WmgCZoZQym3GWASKZFudez/pud0ZtoWUwbA0zE5oWMxYBQ9z2f957NiYzJqXk0AHhM892CzUTIJh16LaFuIGwfYBtVjetZ2Uz0XrKOCAgtpmdgIbavpYJgyRmhijrntKECdRLEh+Qqa6r9o3TYR7XVUppKflENJwMb37+izudzu233Xb3HXf40eRFr37VdH+AQHXVZCW1zy2QGiaDRIQtCSu1q2oFAGmfitZPA1qepighICorisiZvwFVyBP6UB1cPHj3qQeW4lLC1XEc37P00PTyoZb+2Rp6tw+8bupZN9PoknNz43zyiWq0jLFJ8Wxf3Gz80SLc/tgeOsefXBWLpVZroUgERQihCaHswsmTJ8/ZNENEm13vJ7qDUxqfuvjW5fOuvXLDBW5qLovUpbS4vHbs3rvyhQP+1J7Fpx+hamiJvCchVZFG09z0DBBOJpMLLji/qeqn9+/PCKY/3Dv1zoXhGxa7f1VOdcrQ1A2LxzSVT3GHT5xadGgtIRWD+x54sgnBUT4uOB9qMN2AjSgmYQumYRAIJqpTw4agQKkinIEVkYmJCAkFIjMiJiJjGCSZsje49fxrdz++/ejILn99T1pb+T8f3feOd7z+DS+49rsPPfbogfEj+49fsPtcg57rcXImUZSUlkUKkSyZymGcjJyzpiLv6svOm5Xx6SNVb+vxe2M+f99NH+CzLt+yfc6GpbWjS8b0EsbdC5fYC7InrjzytnM/uOOd7zn8qb9b+/vf/sFP33zRf/9w/10/M1kYOQJmbZIXpCaAISMqgg4Fk28iBs4MOsSopM1EtHQm+tAkb9BYNlJ718kcuyjBWSOEpAApCjEUOYkyEgDleW49iQ9AgIgGKYVICmxANREBGZcQVJPLMwbydZMDMlDTeHaZagIg0YjAKhGQW15J9F4JlQmjqOq4jc5WzbMsJjEm8ykiohMoXJGqMCEhhcloTND6RCKQiVEyYE3QTCpgYqTM2BSipCAoBEaEcyLAiBRTBAbrU3TOkWpSIcMkDIIppaaqVBRVreGEogRMDASGMKVEbFJKxlhVVSRUCCiIBCGxqmUQAhFlayBEAWjtuRmpjewOkuqmbjt3y5j3OitLy9aZhGLJOjIpJAYkkwmkEKNxdudZO+ZHQ6kaRQXUrRs3jUNzwe5zkQwiGGNclhHRpBob4m63W/uGgSdU+QxEAAEAAElEQVRNnVLi4MmavCyKopAYAKCl0qhq+27v9Xq5aDNjs56bPKhICdAhND5NAIBpdRwwJ2ZsTm3pzixPisaOFfou0mhSIVlHpjNYHZ+gwbQJWO/5+qPnX/fFrc9/3dFvP26hK/Dwyz648+Evbzv06J4P/tfdH/iDo1+9r/rSXxWr48VbXtG742tP/uQLynf/znt/+bfT2uTowYdvvPDaj//LR77+tX/51N/c3bvk2td+7R8PP1Ad/dRfDr/yD9NP7i9FNv7wu373s5931dE1mL30uTf/+gvetPhnf+zmj6LNsm0bf+/ssy8X++Zbn7t4y8v3nF69u7l0g1l9jnlYtRRObkabiRjGCJRY7NrwmZJQZN1076MXnbjg/k2DJ8y+k1NXd33RgHOAZay0V8RTR7LDD3Tf8kPHTh1G6zqKDU3yol6ePzn0pzFKA2Jszgi8NPBnPd2EwEqYsoVhMyhjYAqUB4+bpuD7j9ZvvXVQuroZc5rqNLiSVWSAaiOtr3KbgtXyhJ1zikiAjCTr9zm311MCpZQUpHDZOlcYFAAqHxMCEcYYY4yucC0oqkTGcQhtkA+0REJVjZIoRWuMRSYLHhSsrWPU3GJK6+QXQlRgJmNMUmkNKoiQ2RCRILQV2iBKiFnhNElRZO2yxmaGpA04+U9bgha5gTNvDV43uFJCQgSi1LbAREyAIgoAiAbaCFNQZoqiTdMgovdN3QadhWCMIUIfAxoGRCCu6hqYal+lKK1LHRE1CQr2kKJIcf2tryw6c9/8+ufuvv+O1ca//CUvPeecc7z3GhOxEUkMyITt6rolaxpYH3SRUdcH3pYZvf4XZ2w326xvUARSUMKmGj+0+MQja0/VstQr3GIwIFrazLoMACS0JC4GAAUgy5pK19jjtDY9yk/h6i6FN+Z9BbkzmEcrgV62pRNWo6tlNet1TYCgIQO2Ga5ORrmS1N44+8YXvfzei178jc3njPK50zYS2G4TGplQ3ss3T21/2Ws6pph/8Pv0g6+a44+vLRxMqcY4Ll2edzv79jzF1hLA04cOaky9Ij9y9KA7WdJniuqnVvIPh6R2jCZPDGAna9GR7+bZmEQhddg8/tgDD3//4bOvuXpteSJMFhuF3AU1TOT9KCNiGxvPpjYRKjXOGWASERBYz/ATlZQoRO7mE4l5UpMSHTl68jPfuo80bNx87i/+6ofP2f2sJx6551/+/d+bxXjLTddcvvXcsLbw8IGDYwsT04UYJYhENAJBcIJBQkJEYZFSeqk0Nlx9w/TFW/K++kO9a+LchYWNTT1Mk2DBRcehOzBm7oKlax/ofnX5xGpKdudPv+/if3kie+5b7vnjnzv24V/tb+wBF6KWtO5HIpAiGEbqIku9esXl511y6fmxDoUpHeei6NiRyV3ZyazNC2ccGscMSKlBpcaLjyFZ8siQZECsyTix7CxLTBxcji2rgpkYNXMGQooxgjNKCpNJMw6kWV1JAAnWTYSBHKtXxclkFDUoBGszRBZAzl1uO+ohBQiIwaBxDJqoXfOIAkbGZIgaEVNk0LHEoEyTGKuU2JIxSBIcYcOhoZQMKRCxzbollxkWrtPrWufQOrAcJA2mZ2wnx5xdVhAZRGY0IQS2Fi0pCoNFVXQuOsughjAZgyohiSIRtaQSMYbIcFIBYCKDBsFwAFChjIwN0ZG1aFqWuI/Bx6RIg8F0rAMpsZJEXVsZZuSskFM2SoAETJhZtogIO7dvf+kLX3zJpZfbCBLFKhUmW1hdrSb1A48+/tBDDzeNVwCX2Q0b51S1rpuUBARQ0ZElwWZcD5dWcpdND6bKvGNtVpZlt9/LywwZELUsstgxSjzTy7ZPh3o0hOV5Ha6u+T4AdC3lFozVPvULKhIlDRX6ZjRcbhqEGJSbWuuyKKipiym0c+faxx/4+NQ1j2aXnmuzJ298y2jDuc/64gcz7GSP37vnR15S/p9f4SN7N/z4L+76wucOX3rt9vG4++H3Pf2ut3/gPe9927t/+tGTp3af+7yffPfb77r9w+96/lX/6x2/uHq4uuXXfu55375n62e+c/p1r37ksadegPqK5zxn92Xn/PDNL1r70E9vWlvoos2Gp09s2rLlsaeec83NR2593dPHjt7ubywpvLLzUOmILVhirg0lAIiEKYzWJisnn/nV+DjItr740LNM1cwX4e5ybz9m4MbMEyuOG1ePFu0VlyVrT9SBCaYwF8kBZHrDlB0Lq2RaWO8hVLw6C9MrKoY4EUqe5xpTXUuydR1GN+yYfdZGWl0YjYmRHE5qko4QK6KEmkUIFUDaifAZbi2zFeWkLAkskhFxioXLJCoAVT6oqoSYQpSYBFRTgpDa8IaqqROBkIbgl1bXPECjGhFFQGKKMYmCZxNCqpq6CR5DgpAUNQN0yBaIgBEZ2ShwElUBQUI2AkjIKmCJWYgFELFVADqTGbJE1nAGZNkaZBJGsAyWyTCxYTbGWGsdZxYMgVmPHjKOyeZAzGxbz2cyxJYVIhgGpDbyREIQSXVdhyjifYg+SowSJ5MJCKQ6pDq0+6Om9oSsMTWTygB2stxpAmVTDESgrlavu+6a17z2jf3ehr0P3v3Zf/n4/v2P5d0sokRIQNAa3kVUYRTAdh3eCpGiqCLEmEDX3UsYgQkF2Gvw4JEIEkiMAdIoyl2LD9w//2jVLBXWJLAqhohBIySCRku0GZiU0jrhAwk1uE1TvZqKGX0J8w2uc9yHfbJ0N0cuuaz9bEfK2Z2ldC2CqmaqE26cOmM4SLW04i/7qd9bfNv/+qtNl+xLdn60Ui5Xxcow+Cop1nFCk7EbLiwvHR8GGZz/XLjhrf1LXjBVntXvbaBgZqY3Hl08jY0HRojo8l4is3njdkTsfaSv21L1Q5KcKVNQikVpHKbg68lo7OdXZOwNYajjo3vvnhlQbcCCiYIikTg0mhpDNgGHaJxNNg/WIiZlJkGHxhIjshCrMUrsIVbjCYcURSYiRkHvuueBpetP7F+YfdIcffnrf/iKy67+t3/9m69+79OXD2+46Yadi2Hh6LET58wNnCxWtrAUERCI1lsoaVVqUEaadGI57th87Zyrd9z/lbMLQbQpr3xl+vlcWXJkaSSgzbqXLLzw387//WSGY+hkRxbMdHnNn/39vX984cGP/pZt7IW/8RtsqipSRWg0wzxK1WhWcp4vr45C3Rh2KWkCpYwdOsMGQACFmQG4zQqrNSKRCHAjCMCGK5W1aowcAcWwY0ZI7WpUEFQNp6hVU5MxigQx1tX48ksvLSl/6PE9mBkRYBANkQw14n2dLrv80sOHDyIyCIqIqDZNY8iygCVOMQCIYUwRMHi1SEQCam3Weni1egBNQshkCYBjqmNc3y3lxnkfCYAQreXQeE2toRvF6C3bGMPs7Ozq6mpLadF1ZItadEkAnDGqShHXOY2i0ZAqso/C6kxLM4EWOAMgkcRkAQXXtRNyxjkXVJOoJgmtRXN7k0pM8/PzBllaQhYgMCkSgCZQTalNsNi2bdvGTRvuueeeNlVwOBqHGNsN03gyaQnPEmVS171eL8SYUjp06BAAAIGIMFNrGVgU65AjgI7H43bqbW1qyeZncEXNAQ05TGHnVOfs82RxtaNQV94AQBmGJFxFtYzgGxpFSCGPFFAbEBCQxjvImSBSLUy11m7z2bB45M/LCz8Exx97+Qe23vdvmw4eGlHl8pm+6/m1E9M/9f6zf/O/fefdPyn7769/74+WvvTVwZ1ffPwlX7vwR3/0ore+oX/Zy5584LGfecdVimFp7awH7v3kR/7kOy94/ksuuOFFL/jHz6ztPTG582sX7zv2qrpa++s/HlXNsDpqZzqDl75NL7r6RdsfOHB4CA/ce+fGNybFN/UfmsqM98LMw/GErKEUvfebNu6s5vefXj71nxC04eO97gvg2m1Le/cUi7cPDrw8XQ2jjpgk1lS0VtNC99wrT506xblxLl8aTrIsWzu5snJgf+zkRj2YYLvWZjEs9rQ3KrJJCqgokxjzbr4zdE76FZKi6FbXbS9PHzsd6iYFgyxsLEcEUEOsAkBI2roVqoAyEiEGSRpqoyyIdQyucLmham3EeV77hgA7eUFEQdZ3wJokNl4RyBgiJAXDtihdPak0qYBqE3KXGbYCEJtGHYMqILb2eYgICiklQ+vEqDMj3zrxMKXUCmLPmGchE7WG6Ejcbl4RkYlbRLEdzZ/hYZ3ZkZ7hOdJ/8hmf+Zt1/BnPuLYSte8jJFCFEEITfJvCWVWVaJt7qO16K8akAMwsCK0ImIiYOaVUN01VVQLibOZ9ned5G116+ZVXTU9P/8dnP7Vn78FP/N0n3/L2N1977bW+RiASCaS5YQsAShpCaGmeRBQ0UUoqQBRTTMTMSAqQCTZqEklMEQLYojjdHLvv6bv3LjzWHQws2tgoGzSGADRfx7I1IaqKQY5REDDElAU5vfdghVispV1uYz1eEwhv4M3fHZ2e7xmnOJ3JFx/ZF7nr61HGgwBYNNGXjas0cLHlBT+28/pXf+/pvaBsEZkxOkAElxBjUkiNsc4VnbFfq4aRXO+6m5erpcm+B/tFt4GxAJZld2V9JMWmaRzAWjPxKL1HMPti4d/f2M8UnBsT0trKIrKZ2bJx57btO3fuuvvO7y2fmk/E37/vBz+05p3gxKgAUZNiYShKy2UhphbLaV/6IAmRW9vwqAmSKDApEFHd1I6K9t42gLx956bC6oHj4e8e+9aFWx941S23vOfnPvSP//BnjQ/lnr+/bvPMPcfPrlYnoVtG5MH6fkDaw3Xm7FFjEqeODNJwVYtUn3fD5U8fStl4flzkRTYmKUKdS2EdMI/iNadu/eeLfv3J6R9cvnCzK8u4NJ6fpOs/+Ot3r9YHPvE/M+cHuy9YHceB9T6CME46pqvEmB06cnTQm3IuTykpaLsiUk1ERLxOHEDE9XAx0Vg1QQIi2k5HEQJqYvWYCIQYtSUUEAFRqOqzNp4/NRg8+PijLisKNIby6ONiWE7gC2YQqMe1c6WiAFGe2z1P7rXWxtgYssYYlaRJJ1i1KSiCAKAeRAiITIEsoklVJLY/ZIyxCb6tHACIDEkYEcjaFNWqsAgjAwgk9D4QAQNW40mWZyEEZ7lpqsxYYBMlJUiI2PI6CE1M3lpGRUUAhBZSIiJNoIJouF2gtimnLdjFZI0xoGE9+nT90kBJIooxRkBFxE6nMxwOnXOt/kpUCEAQEpNRAIRI0FJF2Flj+NTC/PzyQqffO+vcXY888kiovKoOpqaqqjpn587xeHzkyBEAcNY2TZMkjsfj9mi26Z5FUTDxyspKuwCuqsoabtuXNgijvc6stW3uWx9dxdyou/pZ5qMPHW+qQWHtiBMADIo1TZ4BS0dBAERTrMeV9Ps2Dj2KIpmqaYwxmXW41nQM+LSYT286Ner+4SXv609tf+0d71gB6ANNZNmPqgi5uf0r6b2p+MePXfD7fzX9th9bGO2Ws5/Vu/sLo49/fOHj/zddePmlb/ulb33l9nsPTs654NIP/OjNRw/tv/++r/zsT/zCJ//s9OXPu/miS66/5JUXOFqr3vsz2LPF4ulTK5Px9MzTf/Bbm1f1mH96//N+eiWWr535wRQHItPyZrtlMZyM29MuEJZPnaIU/rMWJO7PbsLpbc9trtq7+oWjgxMPLO+9ga5egKGzGeL8oCyD6602R3xslMFkxhmbHV+oRo/oFVeAtZRkUHR6djRa2wAAsbeE8xvEuhKindhh17qJjdbe+Zh938s3NouH0jjmrhO4Sr49z8rI6AyqogoAYLsCQ0SALMuamBSRiRICACXVqBBDyKxlpElTt3Nzaw7TcWXkCIbZGBBVL7XUbRxvFeq2SFvUka9bXxsTFUXb1rbdxaJgSx5ERFoPIIztLdmecAUlRVFp0ePWQQIU15MSWnZSa+kFbb4YmjPSIkERRCVEPbNIRQDAM/aMQEz/b8HWMx9E1DRNWwJ9iFVVtfncTQzOOZR1F/Qk0hbdOoUWRWj/SUt6mEwmmhKgFkWuAnnuEDH4eMmll8/NbfzMv/7TY488+vGPfmK8Uj3n+TerCGiWUjKG23SKqGKJAaCuayVUVUPoo6iqM9RmwHiqmAuNypl6q08v7H/oxD2Hxo9R1hFFxZTlxkk9jpUACJVIEThFTW2NiCLRUODU2LVk/QBsrfgX9bEpizslWb/yodltt+fxc3FpQ6knJy4KFGQ1RQMhacfVXvtzZ7/ug/3nvGjfoWUvqbROWAnQ+CgCNSoyGI8mmJrSpB6mwwcDo18brz7yCJw+FLdud3l3eWHV2dyHUJZ5Nayz0lYSiwZnss5aip0/6S1//XT/VRL/MTZsr3vhizadv1NE/GiSZflVL73ZW9x370Nf/dJX6/85yooBJRyH2jhjGkBnUJICIEBKKUgiBWYrpAqQQNvWChGJkkFKoOtWJzEBokGQY8eW3FkeTI6SHj24dPDEF2686rwffecvfePBh/718a2vvnTw4IrJyjXhvJ84mf88Q2faPgSAlGVThWnm56mYa5YWz3rOs8unq70H4whNGGtwTafLqQlQUG3SxuVd0/XGU5feufWJW4+eHnachRQXnzpw8fv/x0OP37nvY7/XvOcX7ew5NsRyqru2Oup3RDSJQuaK8aRGZNXkLFtGEEBUJsB1yRoAQEop+qBgYooGBBTaJRIRoAeT0IIyqqCCgBFCRWS2Zbk8HpJhZg4glNk9T+9zaLdv2rK4spyIzKAXQtQQHQjYDAmaJqgqGanrWlEEKYhHpBgjEzAoCjIajeBTfCYkWDQKQBRRREZC5JQSKhlaVyyIpKhxfZmEEGMgBaK23xBNEVGt5eRDGwUqHhVbugSpCiIysDEGQWMUUBBQj2qjCCBadqiq6Ix9pgtGbBWAxMoCEhEBSBHabZwikKUQkkFshbmqCogxRkXIhdVxAjVJkmoCLNpcMgU06xYlRZnv378fAFqO6Gg0GlUTe/JkSmk8Gp1//vndbnfv3r2dXifG2F5M7Q8mIjG0vYLUdc3MgG1C4rrimZEISZO0wWe1QWIX/Oq526Zu2Fz+896q12t0ZCvJSq2tdwbUEVpHUe2w0iI347UhCtpEASJlxnvPmiZTWniyaRtPVsz0IH/xm5cf/8HSwcVLy+p0lVi7GWQBl80TB5ce+/PiTa/b+FM/du/vfWSKm3jFzat+XK3Ctb/xa098+457f/OtxYbt17ztJxamuh/4/T+647ZHr7n2hrtv/+vbv/LP3/zSR3/7D/9433e/+W//9um3vuNdhxbnTy4d5pS2fPmzr33X//jW3h8cec3PHYkzr+k8ckkfVkcqIs651pIpM3aqOzheHZ+fLK3tP0qm88zhj5htvfryNVq9YuXcOdOb70y+Uz56fX1RX+3S/Gmztm/jpTcdWT2eHM6V/RW/2s+yyLyh1t07uvvZGd9YVwJJz8mJpWkASDNDHO9AX+W2O4wTu1z1ZorJytIvv+HSpw8tZLSW2TwF9eoNFzEInLGIQkSD/MwUyNiaKiFkmY9RRB2xhthEL4SUkke0zCmFtgNrz57ElotEZ1AWFoBJaFhARICw9g0AEGM7D2QxPTN9GmM0gjGmxVXb+vdMaVRVFcFWG4TrXKq2+wSAdX4UALRmISm1vZ6QEq5HdK9/HVBFZUNt2QZoHdefISy1nOb//Kbr2/EQ22/kU2xiiCoppclkEgBCSKa1lI+h/WTLZK2VmNo/Iq7nZyuhRSdJvfdZlmVZRrheUOe2bHrHO979H//2mbu+ffs/ferjK0sLr37t6zkTQKMxtVkRiFiFOtSNtXYyaQwSOAMghliTBEkIZHudjdO9wpRLw+r7+++599DtJ+rTJpvpsAMyJrOQEkTtUMaATainpdOgrPqKLRFikbkQgqQ0xsygOV2f6k/3pz1UIT5M9knU//CLN2tnA4wzA6er6MRQ1s3QLodxN/nV6C569a9kz7rh6SOnxqt134WmzxkaQ6QGQdAqCkhAbeLY2qz2o9Hayuzu7c3iQRwdMYWZTHxmsuHqaOX0aQAkhbLIQvAO0WMKxEWl4W4x385X/uvS9jsuuvytr1l8cv/X/+4zOhzbzK3WQ2Ye9HpnvfoFsKH38J7HLjjv2eMmDopcfFCygiJIqgl0fRRGYkZiUk2SJLV4xpl2DRAxyzKN6/+fFGDL9HRpQiUmCc8Oepyb2+596mP/8KmLN21bsHNfPZTNDGqwc6UUlUNQAiWVZ2ZfVU0isaxIwljyzIioMyun1/JZtBu6moQRrEPnLCKmpGiy7uYdV09e9nW4rR41fVNaU/Rnu9mGneWuYvvP/fkIp+fUxE45wbQ2WbSFNVVhUnKETQyUcUJhRg21tHG5610qtML2lFKMUZsQQhIgYUwEggCiDCiMygSGE2NETQQJQQEKa/cfevrIieNFlrMCEqE1U71+1u+Pfd0ri5Jzp8YSK1N0NmlUQrJGEGrfhOSbGEIIRqBrM0esqlFBGCUzIw3t9rQFkYJPhqgFUUXAWj4zB0OKGoO0iltgUkJFQCY0rIRRwVqLiJl1iNjKIVJrNqskCC2BBVqCMa4LdlW11fC0YFpbzFSTYCtOQGOIqJWLxDP3JrXmz+0fWxP5Vt0YYwRYdx5Y/+IMSRVEA0hKqcVkYggxBAZ0bIwxddUcPXLMN6GVhDrnNmzY4L1fWFiwzrVVudfv+yaMx+MWi2tfxxZmjjHWdT2ZTKqqCiFMJpN0xnC/9X9XRGQyzpI1iqljNlW+uPpCYll1PqsNjLXMYSEWq4mlwe6Qp4/ND0tFM6wxScp0bEOEqFL3O5kjcdLV1FMburumexdcYIvi9FNHf/uiH/mHqWumsm4nNLX1hktnJv0sW/nCbd9955s3nr81uc7oS3/RP/yD6de++clTae7Hf+nSLz2+8d3v+86ffmjtJ14x8/GP/fjzn3vhFTftvuTam175pr/8i88cffrw7/zOz8xs6c1uKx3Nv+m8i174hc+8972//9U77ly8+S17Zy+7lR/eli+v1ZMW+R8PR01VV+NJCmltbS2l1JEiVBPO9ZlfC3FxjB2BsDWbu7U+T+t4f37k6eJEb6bsZWG6v3F1YeXE8X1CWBo3XfZ9ig0EZwg6dhUCOsmKsgN+1wz75QIAwvQiN7URqbUqyoxn4NjJ+I7nbvuH2/ccavzMwIUQ0bBxedsvtmdGRAjAELXZdahgkByyxpS7LHeOUA0CSgohtDl9bdYZM7eLiZZR/IyUpeVhESAzGyTwEWJSH1PtY92kOoCPmKSpvW9CU/sYUgwpxhhkvSS3s8gzF6KIhODbubPt9tpTLSKS1v+7rYsxxiRRVRD/f+ojAnyG6Ls+TBPqGdXv+uCL6yTjFjp+BvduW8y6rifjqqqquq4r37QUaCJyzjnnWiytKIr2yXmmV1ZV733TNIoAQM7lrNSCRsTY6ZZoSZJOT0//0Dve8dKXvXg0Gn7xi5//5Kc+MTc7fe655/b7fRRtmqbxdV3XRVFs2bJl+5at3W43+uDrxjnX6XT63d7UYDA3mO50ZkcSHzrx4H1H7lrUxU6vm7MzeT6RsFpPliaTEVoxDhHBYENZpNxw0bXdLuVGgERJJYvGZh3MOj4ZRZflxbSYBmBn5PO4mNk2BwCLVR8ZIabxZCGTYuyrbW/42bkXvoZszNHmllBsM6qrSTMOYRTjWFKTUghJfGRNICkf1Q24zqbz7NwWHdUCnehD7ZvJ8lB8mp6eDY0nBEJFppBiM6nQYEUxfijoFXrWhy7+/ic+9b3PfjZoLR3jWfpTM0Wn1/j06N9/ae8d991993enNruhiSPWhgEQW6BFVQHQGOuMNcSqSglbJKZ93ckwGVZDradbC8kAgAHQtWqcUYxoCmuG9SQr3MbO7IHx6J+//a2rL75oBujk0mOu2yw2blagYQYQAtB1K9F1dKWherKKXU618Zis5FyP/Ja5vAllM66bcd6YxelBZzCzFRbmT3/1rzfOPPmNX3vki7/44m0n+pBn2iko72646JoLf/Hnj/zQzyysrEztlCEZl3fqWEMmfbB13bg8b5omz3NUyUy2Y+vWQ6dOAUBrKyFnfm87kYgqqEGlffO3B5eTN6CUUCJSYEI0qqhikedmZkQkjirn8nYgNQiaEEgrEMiNFQIvmTNJpWmaGH1rltrtd4crq612sA3ljSqkBCAUgDXZOmlOMaWyKOqmsdbGGAkgqbaVktZNfqgNB2SDqiigZEyM4sjEGAUSI6WkNrMgur4oyvLGeyVFZEkJIIkogBCapmmib0QTIJRlOUWdtWoVYuxQTnkWQmgN8Fq2CACAJERYJ2ITCQKAGEAARsTae2MMiDBjCAggSdE6iyF6AidigIJlh5QJBsbSOQCoJhNjrTHGIGWZJQVRaSEKq9Y51+12x+Px4SNHnj5wIM9zY0y/N6jqSYzRsE3Rr41HFk2n01lbW1PVTqczHo97vV4btkMtZsBEAK3UUgMwg6fh0LuLNs5M0VAUe0CK8Nbp7zzXP3G67n755LlfXz3njc+//uTeg98+YFMIvq6KvI8GY4yTyaiwqanmM0JM/cmkOfvWa4cHDlRLh1yn+4Wzf+bpjQ/91MFPl6t7c5oWP01udOVgw6n/+PdT9z3KF1wUs8HxrRef++zrlw/vG37us7LrosnS/l1Zf26cHf7q1xe/8jmz64KrX/ma1//y7+DUuRsv3Pqm939gds3vfeyJKZ4d//7vP+vqF/7lf3y6uvD5D53/4osnd589N8/D7tDUZadomiakmBflaDiMybenPWQWVtbykX9mIKst2nIGEWtduRmv/PLCg6vbw+3uyctwx5ou9gY7933vm3zx+aNqzdYSQyXdUpZXRX10BatI0Pk4mSplxyxnezoVAA9WNKpYIcrCxNoApXML835bMX32IFZrk02DTbWX4IVb8gDieqCQthHzQERM67WHc2eADLuQkU9RFBmZkUTEGWMMtXyr1mMuqbQeuowIClGTBq9JAcAwSYwtoAeIIcYkxMJtiXqmykaljDhShCRERMiCsl5lRQBVfRARtP9ZNdsEzzbft934EiOiPbPchRZvXF/utPRgRIltqMP6DlgQnpmSn6nZ601ASClJUqmrxnvvmybUTR18CzX75Ht5yUQqgogCGpsGZd26mYgkRFBFxKQiMTLlqpplGSYgBSZoJuMsy0LSSRgaSz/+U/919/kX/+VfffhLX/78ZFL/6gc/tGXzptF4uLq20j7PO7fv2Lx5cwxpPB5PqjERTU1NreuSgawxx1ZWb3v4m4+e+K4UE2xMPaqn+jiK4IC2d2ZL24vkTg+PgVKqcTE/QULGshiy5GJQY0pN0qNs6+zs0XgIrPGUyGBdj03ZfZhHz6/dxmwFAJZGkZNOyJT5rA7ns6tede6L31XVyz456uEGQrSuEZ8YVZWCqkgwiARWUQQj8MSZcstGO7WhXlgbi+1qg5gJgq99ZrILLjz/sUcfHI2Gpo1VdaaMWKXg6jA3edbw8Mnv7P5scbIzN7Wh9k2nKDWJcZaL7NTy4mx3ZnVl4f/+zcd+6O0/OtBSmiSOK++dJGJqTQYlJllHPYCF251gUkkiKC0VgEAJzvittrsMtSAZxWE0iVJustCkxtR52Z+vxk8+vn/LpukNM1MjbwparTVHSqgg1G4XYV06hhhCSsRDtqau12DSSyCNJLs86GxdFRGb5bPn1H5t9S9/137pU7Zae/aGqU/9D5i/cP6Cu1fX8tVUG4Z8393/evizn7j+f/zBD5ZPDlfGpkxZU5ErxqGqU2RnfeMRASSxMU0IxxYX5cyJf+YCQlRq59r1ID+1CK05nA+hSslrYlQBFVKDGJIIaJWa00uLqml2MKPITJQgiWOrFilSSgZcEik7eaNxPGoMKSMmBSAKTYWk0UdEBoJJ4wGR+Bk4KqSMOEZrbVmWKSXD3NYzx6yCUZKACrRujlbVP4Pxt49OEJhZUmJnAcT7aIwRAct58EkhQZt8qMqmrW6aUKXlOiVV1fGoGvNYGBixCXVKsc1OBkQE0jbDBRmAgAnatl3kzKJBALgoiqZpGDHGUBRFVVVtV56xURUATbB+x0RAEVDVxvsNGzZkWTY/P98OCt57QWjNfVaWlweDQZusHlJ0NqtDpBTJGhWYm91w8ODBs3bsMIU7cvjouiYSaDyuiCBIckCaNLaRZ7Z10UMBgDzlCYeUQCyVC43pTs9t/LD+cFdHFCYmnNpWuGdfduB9nV0/8407Hnz4qXjF7/CIrjr3gice34e5Y0TgfOyXLzhr+/EjCyGuzGy/lrPi6CPfM1P9NMnm7NrTZ1//G9mmHz3+hUuO3p4gNDhzdFIX5ZZdx/eNt22vLr26u/WsU08f0cas1MMrrr/4q5/6q+KaW/c98J1OEKZucezAqQ//6f4P/0HZmcte/sZj0Bm60/7goV0HT/Quvvib93y9vuktD9303t3NkStX9jcb87EsG1esjseZsYo4aWownFIMmtRQiMOiFfaf+ejrTH/jrAAtYH2enn1lOO+7zdMP9I+dOLBnuj978uBpmXMxd2WmUpEQMtu1kyfPyjop6ztRzjo0lih8Vsf3DNVrPZxeMYkD96zUyI1irzc9PjBcuemsjdXqMANaWF5i4wznoAEEVCHLrXFOU0ohrnfqTKgIqs65FCK0mzBUkMSIBNjmFGgCXicfRUQmMmgBQqSkiKhEoklFGUGATOZAUlTRFCybqNI0wbaEjHZiVrFgU0rgAQnIZmjwGRC4razrE3aSFlMxxgioqqYzXA0GbB2vBHRdmPP//2BABE3cll9FbKW06zD1unOyqoioQIotX1NrHwDAGtPUtWEuMBulpAjPWIMBgGVqgleRjE0I/hnc0hhDTCkIIor4utYYTZZlqlp2im63n1IYlGWRb0yQpjZM/+z7/uuuc3b/+od+7Ztf//Lq6uqvfvCDF1xwQa/XWVxcFpFO2fVNEIS8U2ZloapAFJIAU+P9XQe//8C+e55e2tdg1HEMYbUoipUgW2zvuZfcdO3Z1+Y0GEW/d+WRu+/89+fsuk58MaxWT66dnl9e9LACEAtDfjgEmUlFSgY6JneC03XtS8I4OdWUIxdekRMALDVRqcgg4nhtNLPxpre/33WKuNiwlWEdJ05yE4KSjcoJBAlQswQRkjfikikTUGcq27IZOBbTfbtpSzr0FDurQBJV2Ty+52kf1OU5M6/Wkyl1IdY++sHszDUveu6X3vdR+IzYF5fNnSBol4ejLLN+ec2OmFOqZTiY3Xho7/5DTz16/k0vGJ+uXKKxEw4kiICsKilFSIIG2RoABTKIADGCyPrRQUiSEBGtA4iqagAQpAKAIJ1Ux1Aaz5A5zZtqW8aLy2sZyK6zXIoatTQ68YDMTAwoLRatqm39QwnjemIzFjQ0hhg0QhM72fTCih2j8/ffJp/4s97RvdOb5mK/9KdOb3/YPfaO/JatH9i+9Zxyy5ynbqH541/5ywc+/teXf+R3P//5b22AbsjHwUPfdCv2sYVXNSmboEEAR0201Pa52v4c7QI1pUSMioJAjtiAMqiAJgIiC0qSUpRaohI7BEakpmlecuP1+/fvX1kbdktHQZB0HUYDMiiIqBknFAhpKstDrJsgKgEAQpLcWQKMATAqobCzkhKgWjYQQVWTkZj8qVMn2oV8t9ttl6lBNYTAqADUwryICKAtriUxAjIKlmXR1HVmbJMiQGtcZ6OPQEjGRPUaE0EylpA0hMhAoJTnOdSMEQGg1pRFVRKxrmddVQcRIWuMAqgaw0T/Dy1FBZJoTK3OUSEJs2UmAkQjIlmWAZkQAjB3PU5AA0EeJCLUJEUgj+qcu/GWm+fn50+cPkUKEgOKtnnJqfFzc3Orq6uj8dh1CiWsvW+/9fLycpnlqkqI4/G4Xls2xvT7/aWlJRHodDrtYwdNMUYkEiRzBoYhgpTKKlaZ6UAMnZkdb+v+31sPfvT8TSeMjVM59ktQCMtVnBw+cFNth2e96pHRaCovVocrAcQ0HgQTGHVmfnUYShubTu/SK5b2PkknxmCCL4bA3X51pN7Y/TP3Xy6evv6tR/7trOXHxwnT3NkH6+ycN75x89XP2f+1L2267jIzt/O+55x/+v4v75jedPb7P/DYbT9Y1LoP2fw/fWzL8uq5v/a/H/v2Fzecc+7Jf/7T83/il5vvfHfQLb9z/+3+xrc98ro/3mnG1z74H3TFhpw6IS0xTLNpggoCEEKU5GMKSYg4q5qlU8dymDxTD+jim81MEYZ1aftNii+0l901fPjk1Km7usfesLbliXSsc/7uMBw764jKCnDANmoSiUuFXUtVbyylLaoQtkzpltni9PIg27xmB3nVVLmxwqGql6dJX7R701CzHGvWMmMIKQYvhSPnHI4hhhhNYgBkQpGQkgCQsZm1oMTWeIwpJcsGrTTBe02OrWWjmloU2hgHhL6J3U5Rp4nGlBAiphbxZUVGFtFWsK6qCaGtZ2c4Chg1EqzLxGOM1nKMUUT1DM6sIEkghtB+jj7TxRCrKhK1Cfbt/NuSFlv6TKukfQayRmxH4pYcI//PvIsALWrdutW2xAlsuSA2hipGTUmTtHRQVS3KUlCN4V7eGY5HdVOVnW637KwsLMYYB90eM6+srFRVRda0Moo8d7OzG5xzwUdV7XW6c3Nz/X6P0JJBm2chxdOLo1e95qWzM1MfeP8H7r33+7/6K7/0Cx/4xefcemu/PwUATAZgPSscEKRVBRuqQ3Pi5MlqdXzzBbfelJ59ev4UEAfR/4+9/4yy7KruvtE551prp5Mqd3d17lZ3q5UjyoAAGXCAx8YYE5wTvsY2tsHYPNgGY2w/9uOEczYYg8EgMpggjEACgSSUU2d1d3V3deWT9t4rzPl+WKdK4obxjjvGO+57P3hrCFrVders2mfvNdec8z9//1JsZav9s/tvuvA6I+nAhcKodtJKVHrlruv2tPYjheW1c4fPHn5q/si58vxatbo0XD1w4a7OZHhQHh7K8Mq0eJltHZXFUKRU1R1bhQkEgCXnK+0KI70h7b/pJ5tbd53rrSa5JcmaqvYI1qkUmFk8iAIhpACBQHLPTmNVr2jdWsub6tyZ8cnZfmtHrWfQOBZCpgBgkoJQuv1VJ2Esb6yurhw8ePDIocOX33bLybvur7/m6FHdf+Oy+a+WQgJCQTJ5oy6r8da4mWrWC6XSerm/nOfQr52gThRpTT6wZybUZBSQFxIiZBGhyMHXKEAChMQcCzQQjcJARJOgZgCAynpEwkDtjDLUfXJGF3kB0KpLSQmGJMSSGvQSgIFEBMXhaAhPSKOw9t7awOARBYS9L+ukXW4uWghr5//l9y86fz7MbO2tnYSknbzpjTe0T33ukn+f2fzTuiJVCYN27G9+6x/c975/OfWZr3c2Ff1KFw68rUpjCpChtddef/X8/Pzpk3Mt0wBFoM2wKnlQNdqtsqpSITQqMGoxNYAR1AqRjCdkMgop1MwiGBhRWNRkM9OKFlYFRHKVnjo1BwSBgifGBIwyBkEpFkFKc2ZAYW+ptGiMAWAINYZAQgLoKocAWaKGDFlqNIivQVAJaIcOlBinSUNZd6+69OKdO3d+/o4vZUWDHOsgBFpQPAdCEbaIhKgRPAgrZq1QgnMlM+CAndGkalAEJTjKDFiPAR2ojIJ1dqIxU9d1OVwG5Sk1vbpE9gCYqqTQuZUAJEbAC2glKtFpmlprkb13LssyZobAFlgQiSAxBlhc8KiQAnMAYUgoddapxKAgoAYGa1ADSghsSLxrpimwOOsCyN1f/9pabwDaBOdJOC6uxOCDEOp2a8w510iy2tV1EjQpV9VT4xOrve6Z+XOUpJUP45OT7MOgLE2Wlv2B99YGb6xJDSllFGGmFbqgjUFA71mTRa1sY+gHjQmmFzx/541PBKWnVT0XWJaGoaF8i6pd27e+qtX/y7+6ffKKG8/rLQtPr1AKDKqB1nkn3qwtdk2Sz1x8QKfZ0lOPh3EVnISKxQ5KcrmxCroPbdr72Phbn3fu3u88+/G955+eUemRX//Z6oJrdv+PH8CyPvlXf3AZbqofuGuzk2Of++jM2NTyzIya2TG51B0mg5OP3dk50z2vHt7VN8Vbf2F4wXMeXlnSr3rT3Te9bZrspQ+8b/nIXbuuf91wrTKUA9eJ9/1aciKTakUNIcdUjxUTfHbJP30spWQjADc3bUmKrW7YBa+Hhi/ILtp9JDt+xeoD470Xd3sqMb1erRnY8RDLlJVnlzG2M+oGaWKqU67R85D9eGfX5NrDq23fWcOqNiofgC28SdrtYV3++f3ldXvCd41XPT+sWSskpT0oE5wHAG1ISQARAlSKunY+ydO+tUppAC0uFszZhyBIjtjWzhilWSlC8FzoLLgQy72LPQYRz0FphUjBOqVUlmX9QQWANtiYLwbnEm186bUmDEhaAyF7TihJbCIijRBlE+icS7K0rmsgCsETo0kN14FIpXna0q0sy/rdfn9tzfsQR4fSNCUirQ0RmiSNi6jW2mhNSkXjvgAhRuXg2AXv2UtMshlIq+A9IIKMmn/OudLVzOyDraHywRd5vmn75OTkZK9fElGWZf2FXr02nN463mxndTNtQTbWGQMAs8TD4VAnxhgjCK1GK0mSJDGeAwdGkh6tDFzXxTmRoRKRwOHYkkxfNPabf/m23/v9dz74xN1v+703vfrp1936kluHNTvPKKx0ZBaxAvEg7CXTpirqfXt2EhECTk9PxhGpWMPXKj289KTEajjCqd7xypcne0cCOgIirWa2bpme3cxBnPe9XveCfVs/fvLfh8Xa1NSW/6q7d6Rd8CmoYIpqq05uHXf3WeDpfHtjcm7+bGP/rsbzLp2vHvRWey9ANTgnYIRDrbRiRhZH6KPuKXAKWOugBF3AXJe97gK5gdtey0LFCljKAIBIrMAQcQpAXoSTdmMRzm67ZV897h/94tfN9hb9WVn/Xim3OHlUaRInpdIEhR+YnrEVTwOTfPquz+y4+pJT3TJzOvRDgiYwx34BEooAIhhtIHCAqItniTN5iLkudjS3M7NSGEIAQh0QZjYlANCtEwvs3RAoZ1QtlbFJV5a6m1vNXDf6ZZlpCgLiHJEmJEYMLMgsjAzArnLOiaCAgGgfggKzacvm1VWXtirP7XRsp1s6YXxtk3zbH/0DPO+Gi5c/86E9f3Fo9a6d/X0oqqDUBjv/FF7wwhcf+tIXir71WA8Ar7/6MluGR556rNlsnjrydO2sMcZKyE0y6PW2zk7Nbtp83wMPNoqGr60NjrTRxhQm6/ZWE5NC1CQrJGHvLDGvhnqvmTS9GsaNQ6HIisvSs2fPplp10hzqEISpaTwE611iMvFBKWWdJ4LUYFn2sjhyH723gBlJCANiygC1cySsFSoKAkSkQVQzx+BZm5XB4Dnbt2tSCtQwuBQVg8Sy1mhPDQIAmcmtrQCVcJSiiE4UGTOWJQMYhhASZvGVAyCkXAAANJn5+Xki0jphBiRQqIFgREaPrDscsW2YMQQZbfFJKUQgJQJeWFGc3aSAIgQoBCyWAxICKYZAqXLexo4URswPAoqgiNa6qqxRemxsbFCV586dS5LMe5+ahINHRJFQOyFFp86dGWs1t+/Y0RsOBrYkoi1btpw5dXptbY1BmDlYN+x1y3IQd4szk1NrdsULF0VRlmWmW/HR11pLLLsTKqWCoEef9RKj7MogfPhfP3hg79pUVtdKFmulGuNsTO6XK6ntoD870Ro+/XezF77iTOPStOzXZB01ghuoTJNKJYGpiy9ZPvpENeiBGJNkeUEDqjIWu1LWqytJssrFxB0Tl39l9porFx567qm7bl470jp876nfv29p0ziz63Gts5kyS8aq4dpaP+PgjhyT1oS2Gf/ze8el2vqg1FNbP3L56z6XXvb7PzT7r1tfoVleuPzAve/9rct+7qeXRBEPtYgdQpGlE610ue727SD1xlvbaBam037yr9+zpR4u0TM94FRjEINGkKlCuxm3XKMvOn76jiMXLDw8szbNxXl0qWmUoUeoEiJnh/X5pWSs4QlK9sSePTiVrGH33DnClel6YjHNmKwtnMKksGEVqWFAjTmwEGs2gCCIIQTe4AcXJqucVVot+4V/G74bh1GdBTJqVUj8Z5SQAkA1oiAiIvZxo9fK6/NC60s9igh2kdcTUIpcKpY4p0sAGE1oNpqvMjLdYxmZiMSXYoQ7jbpXokilWUqkYjYavbZi2hpFVuvoyoh4ihOe8aUb/wMbXxAZvTh+E7OMJgQB4JmKNAfmWI3XlaauwqPwDF8r5ssrKCLrfEiMf7UBspKNN4ZndeHWrx0SxktMipgZAZUi/i6XXqqf6j3wO0888jcLm6ZnpmJtHCgia0e/DK4PRoOsXzAY/YbPLsLLaBYVKl+e7p34w3vflupsvUk+msjC6GF6SK3Vy/B9blnPTaFZCc5gAJAhgyV/Z8PdSzB8Ya9Sw2CtHV89Vv+uPRdQGDn6CMGGtyM+c73X7yMAJcgogggqwCQt+eB29HlqNdbzNnrwhKAU+WB7gZFoMfh+MTxLx+r/4Ul1vQh8AOzz+7gDsyxj7633pFTJVQmAhBL4ffUH7v/UQy5sKAH+n1sSsD519owL1rNO96++44NbGtvjnc4iWiutAwIAtiaQTTNv5KbRHa6u1PVU6N166YV790wsdY9kiQ7EwdfoAhNw8AFEa2Jm75lIY61QgEGcr8kIENZu0O2JA2ovpqvbp+HSa8Ohr4mrTGcy37xz+dDi3uyi3Lce2fJfe45dlECjzhTWmtEn1Ghu3nH25OPjzfHVgdWNpNUq6sc5FWgUxY6pHfc//GBR5P1+P9NGLK+udlOVZVlzgBadYx8GvgaAqYnJsiyFndYGSayrEcUG3/HkQcqm8YsrBGBjCzmERqsZfyMRlICuttFOoB5UCjAAa1K97uoLXnDr4cOHHzl2slEUta8VIAARQJZkVVW5XLGzyJIggGcCNEjEUoeQEDU7Y+eXl//un/6pmebDuoIk8TYE8bjeSpeNI0SeAUTCrefaO4chLNUVelZKYZp455Rn9t6hKCalVEAtiIIEIuw4M0YFhABAQBoNKaWUSAjCAMQszoX1OxtdkBBEoWghCYyEATEgK0JxgTSJQJaYqKZOjXbOoUCq00hdH/mHMxulvfcqMeN5trq6KoE1KeccCSulCp0Mh0NlTJEYDmFpcVGEC5U4hcvLy7EzZ0gFASHav2/f+YWFsVY7z/Nz586jNlmWGmMYpK5rrXXkGAhA7IohAbthkU0AdUuT5UTf/fLNk8vUVEkyDNPjWd9AWFiuQ73UrQiUiKrd4lX85OknPw4XvjHnvD9caVLb8UCBnth3CZmk98SDGbD3gIHEi23kCrW02zw2EexiMqxMf+D7/p7mnvsuvfpDUN7Q/erNp754wcrT5LXHZGiTau9E93SvkXdY05bJlIjEep/y8Wb7G7j7ruTSM3ZHOyx/aNNPDBhfXj/46G//yN69l6Uze4dhJeGOzRZYGgmLOIcutIM44UqBsnLu6NxHTxz5HwlOtHZtPPybv+M7g+8Zh+Cw2TKhN7wlvfT2c19Y3nr6Tnnyxzo3gmMUqKRs5g3f7VkECW4w1qjYN0SxQQkVBdvsZ1fvHn5zuS17jzsLOs1tsCgLU7TFuzrp5PvHz7PzOtUiorWqynJmZoZMkC6nJhGRIs201otDj4Avab5qwmyKy6AiRQLeBhecUloReOdEkUTfEa1HqlIARDCkNjyy6nok0F1ZWQFFzrm6rlNjrHVeOEkSQpwaG+sPhoPBwCQmSdIkSaIRnFIaUCRwlmV1XXsOWhlhLq3ttFpjnXaSpdPT0zpNxHFizNBVwhycr6vaOR9RMHmeW+9SkxijY1WZRvMXsqFrJSJQI7azMButouYZSWujAYBiQXsduIFEiTGglQ8+hEAMRBS8FwCVGBEJ3iPGBroQIBJFTwciRK3QR6I2j6aWEePIhSLyIGmSICKzmMSwBGEu0kaQwV/++T986pMfd0249MU3vfaHfihr5L26ykA5Dqg0ekYi1qAi6mSkBUFEJKUgVtSj3AhHts2n1o79wTfe+qZr3znb2Q1BNsS5seRug988Zb76iU/9yp/8Vj629Rb0j/RXksbkrW71LyBMcfFrt6xih3/iM2NVWarW5v2vfXNj8mA3hKQO1XCtG+pEa6MNQ0rgCUERAAsLr98niGyQXCA2QDAQpdWwnjv79X+DXjdJ0HnQWiNwpGvbetVJBV6qQXf/cy5Z6q6dfvJQkjVq8loH/1uV+t5UnlYgJA4bzab33oUAKEWa91ZXv++3X/Hi733FmYUySxSMpDIjFsVobJNotHsREGYg1FrPdU/80Td/c1D3pYjhOPY3hYErAEiKsVa9hVGXtn/Jnj1XXrjzgpmWRn2uO+fXrBJlrUsw8czBBR8EFDHHq4whBFTRB090mgRhDqxV4SxOtvn4Z/5908um0qtuHn7qb2aLZG3u6MKnbh/7qZ9fObt66dLNX5r+cJ8c03Bbd991y9/bHGa1hfbUtnD8XuHJsYn2Y08drod1p9MR5pXV7srqamYSOywFpD0+1ltdPXlufrw9VQ+cR0FQqSKnlLXWZ1m0CmTvvVfRoUgFyZp5o91aPdvTmcFE5zbDLrACy6GuPbAAgCYCwaFz1tcio9F+o8khfvmrX63rOiMDLqTaWGu9MClVlwPPoVEnLBKQPQqLxCEctj7TJhCXrm6YvJEUdfBaaXDBQwjCEoSiyWi8p0EFZiF07DmADTbRI3MDVjpXmpnLwIJac0BQotH5OggnpAgwOK9MYiWUYUStAkIWnygTx7Gcc0atu7BFe3AQ8p6ZFeGoHq40AHjHQASk0PvEmHowBIBojJii+o7bvuORxx87evRo3mz4CLkVYOHMJKfPzN14/Q1a67On55IkyZNkWFfeu6mpKSfcHw6UUpkmW1ZaUZ7n9aDMkzTRqQ+WiEIImzfNvPi2W79x34NPPfVUq9WamJjo9XpKKSBs5AV51tpEEBYCgBplJzopUIXgTToUb7qzL/1uc8cXBmdWyDJWg5z7IOAYBmxO9PCpc2uv/N4fO7myMjl/uAp/19/+6nZhrFkuelN1GycvvnLl8JN2UIESRV4AA4MZOpsKChZsOJn14wmKqJU1vXwqpW53svOJra/4QHrN9vMP31w+ta+a21edyU4s5DVCAgOjn2BaUPi0n3ykuPRU+8K1NM3bO6eLIr30hrPQ/PH22c/97Guec801jZf80CA5m5QJqmEWxpm4Fk1BjC4q5YY+kEvSJD+2drSv8vdPb7uqKDYC8H41wbkWSyG3VsYG9ak9ofHy/MZPdh97eGJ+Ydg7v1xPNHUTEyIyY03rKugPrUm9iLjQlrRPpif1RA6d8Um90vLjy0YS3+03W9nmma2HF89lenJLs5o2y1USQk1x21oUxeLi4jLMk1LRa4gRqtLGz2VCz2zSW7TWeZIOBgPUWhdpWdfW10QkKqSiIhMGAEiNDIK894oIDGitA3ONFhG5lJm8WZUlKjQNnaVpCKFoNGa3b5uYmGgm6dHjxxYXl4pGI8uyiYkJpWk4HDabzaIo6rpOtKmqutvrDYfDfr/fGuuMtdozm6ZFZGQw7IUiW+DZOQ1LTFujrUjsKwNANGhiZiGhdWuTOIkU9RwxMMcW8sarmLmZFyN3MsQotARSRBScFRGS0SgXI0TIDGgjISAKwTNcEVjvZ8efOZpgBtBILCHigBTp+J1+pMoEk+t3v+svLtx04K//7E8//g8fVivJm9/6pv3bZwbdgSApk4ALNniTaq5d3EyMNkQjFwqKWwEZFScEESWEVGXbW7v3jF24EXo3roZzbqzRnm0eMv3MGTnvssuluH2t+4P5psnhycNJ9hyEY33EAagVbjUu6C7NlD2bbJ9FqLTKU6VTSFMFAUkpVZBKUUIIwxC8iBLUgEoxWalcRRq5u7y2ttraclFr7ytWv/J+STkJAgx5YlDQkKoq1wsBguAajetNK+fXcFmrDElpeA/Sr5H6eYQfxcQkCaS266KVhQbSuYHl9M4Pf/H1r/v5pqQahGh05WMrRERCJDHgKCGp65qjI6cPIMIgDLLhEa1DAAoWAI6fHZxePX/xwdmXv/CGa/fuTp0+0lv76n1H15ZO7to9bqhSNZQWQgi180anqJRzdSx4es8eENVG/UTiLWudWx4UY1dfXq90iyuuXb3qxomvfrrRnj3zgT8wB68sX7B7Pnv6VPNJLUYBPdL5yh3bPvDDh37zov5zJ6ZnW0VrWJWTnSai8g7ssDTGeJQiTUMIxAhG9at6MBxcesUVq8vL588tsCYlXJalR07y9uLyciPPXRBESQQ5SO08cuiGOh8OG0lWQl31+4lGAMhEKQEnKFrFhBg9c2UhTeJNp5SxzlsXrAtaGxRh8bZyqJUCDOKV0QrIshihAgiDBAYkroGdloYEFEx0OqpECEJgcF4Z7Z1wCBHuQ0RIqEj5wKgIUAkBAWFCxOyFC50wgrOenE/TdOBdCEE5lSB54YqdMcYzK3GJSYN1sUASbwWlWEZyYtjYsAty9G0SEURAhqDEoyhhZCAWIPAgCekQROlEITnrjdZ1Xd9//wPRu0lrzdaKoDYGEdn5PG88/viTZTnITJLnea/XU4kxxsyfmssaxXjenJqZXl1dJc9FXlTDYZZl3jpEMMbkRRHX4uXlbsytz507Nzs722o1Tp2ZG28UdV230lxEfAhJVI0BhyBEpEj7QS9JxmzqQ7Dj5c1/89XOS+REQjRZQJ5Q6WTNmeD9+57svPaHf/jxQ488cu+96aZN4+HYlcXhry5fCOPZWJq2LjpAWi8+8oAE0nF2ABEUi8hEZoKV1coLG+gOMTGh1aFmW0wYLC/gmSfbjcbirhd+0F0h1bCztJLSArlhnSAX00zNribsTCuY1MpNkEpcP7/2us7ui/bMP/XwO7//4isu2f7qXz938pvDToerSqfJELgIQpXXKgdQFpwGchp8ioOTR7vczyE9mo1vhIq3//3ffM/zLr/isluLZgc9DP3qIMkOptd/7PiXViYnv+KPviC/pMtdQLWyvDI21rRr/QlTFJObWcBrZaFfqCLYoQX1ma+fl6tnpNn3blm7JNdsMMES6kRNSD8xduDGmjn6YENwItJoNMpQwBDYczbesrYS75VWIFKkSTtvloMhs1VBOPjgASSgC55rCFwaIyKJQkXoA4sIBR+sA6OSJBkMe3meX3zhwXa73V1dCyGkzYIE0jRt5IVSCkmlRR5CEOf2X3jggiBx2M9kaSRtxBmhZqNlrc2LxqbNm621iAiKvPcKSWmy0W4b0YfA66kNcMTUKCLSpCvnYi06PlNeRuODiAiESkYRMUTnX8JokRSDcQy3cczXcQAERoCIulRGPDvx0bGYmRWQ1hTbnHFljy6KLKMnOu5TR+H5WUf8/pH3MIJWhkG899FDDISdU244eNNb3rh109bfe+dvffwT/35u6ew73vGOvQf29lYrDVASG1IagPNEmEEwxhURAaDRCr8uPQMgGf3VyMaBRlsHiWeCAgrQD2Fsog3Meyamn5w7dZsyl1BR+N6PmaKqoFFQd1kGflgEmtpzUDcaq0+fTGZndNHGQYCQSJpQAuQtcwAAAWAfgP06AkIqJYlCo/JV6Ot0cuHEN7nbLZJWpSb6S+dyDYFdnYhJUpWYWqGqRRRqTNbqYVlXRdEIzieUVHVd/GVz8Ntd85jYgyU0RI4BfbYhX0cMajAo22Njd95558ljh7fuuXppuZ+gip/pxucePx1B8BxQIEmS0WIbuQVxFhwkUhY0EjQzBoAquJ94zfW3XX9NQyXHT5//0r0Pnji74GqzZUKCcxCcl+BRWDgu8WKD1iMygyHjvBARSAjsGo1GotWw30XgyYnGmePzx+//zPNuuGXqJ35t/pFv7uwPZrVaeNsPv/ehnWAQEOaKIwpU4dttO/HP+3/zlx96z4F093Ovf9EXvvblZtooe32xkJmECUFB6a0gKKW8SO2sydsPP/x4q2gAgC/rALxvz55ev392eVXrpKxdHLQ1xtTOE9FQi7LinBt6O2bMzMzMwwtPIeHAlWMEqYdQeq3Jx65nYhpp4pxzLnCoQxCjEu89ewnEIQRtiDkQUSNJIkDDE4qEAIIsohFEwPmGVk44EUVEdfBKqUIp733aaZZ1pUOQEZM2NmCImbXRXhiAvedEa+ccGU1Czg4NqRREUpXnJtRDJ0FGvmcCRB5EFDGzr6vUZFEJorXWohUSS0BCIpK4JUcZtbVg1H6DIIIgiC4EDdGBFQEgxOJ8CIoANXmCJM/Onp8H4FarVbmY6CAAJEnSLytQNHRDYxIiKorCey8izjnTyPddeAC1euihhxqNBhrdHQ6yLGPn0zRtt1r9waDf76vEBPbfevCBs/Pn0iSLVcc8zzudTiMvAnujEm1MzO8ZQaFSmhARnE+aTT8YstZK6d7C/NPq+//1oRM/fpV3WV4LiWZS+OXystYVB7/xja8dO3JyeuuW7sqAJi543U/v+351//CzJ7Z15K8v+syWc58d4OlzNI2csQekoLTUnub7XjCg8kbrOpDy3tQuJUKduem9dnroAqMbjvF4Z8v27uZ6QYtGSUoNRgPWHaZQlpx202EiSWr2XTS25+LlB+/rf/J/XnZg18wv/unZe+7mphtD1lQM2bXZewDvnBBWDEZDi7FMCMp+9bm7Lj9/cuHgweXlwcb6OwxzX/6GffzEmRuuvHzn5l3VoLemg9x7ctuF03PQezw5eWW93Q5Zt5KUtDi/cPbcxFizaraoN9TOC6QWg5J2K9HbZpOHVlIAGO7ERm/Tgqdz88OZsS0nF+fVUqUOmM2FrgOWw77WWlic9YE5ftDWVoPBYLwz1tnUKPqNyy+/Ynu+69ixY2dXl0AlwpKkaWHM2tpaXUp7rN1otQElTdNmXjjnCBXF6qVzzloR2b59++bNmxBxZmoaADxGbb4CAOGR13WcrNPaoGJBJKNFpI7UJx55S8e4FefIvbDWKiEK1o0y0cinUwoVxsxGJVrhKNrZ4CMNNF7qGCkRERUxM3MIADF5VUQYm0HrGJBRNrgRvGPnEhFx3fxAKUOmZhvN68QLAGlNG7FNax3zzhAEWUDYkPLRhUmpDfV1LBcTSBAgROudMSZJklGmHlSSOVurxYX+q173fTt3bn/jG3/hrru+8iu/8MZff/tvXHfNc/q9ARIFDhr0oCpzkxASESHQenssvktAil7IACMZCeI6GjauRwiKotsjQiowOdnMm2P9QVnnyTv7PWeUqaRBsMlUP5/VJ8q0ULnOyBy4dmzf3uXTp1afeKReXVh57OtVv0tbds/e+tJ02wWpq4NwBcDCWlQc/mJkG3wDYU9RaNENNeeuu2RNplqqPpX/wMLZI/Xasi97KytnMfhGkvVq58RYV6skzVoNIgjOizD6kGeF+5SFt4N/Q63nE8cOt2J1Sx8/ruGP20miBIKAfvef/Olf/sO/LsG3HdHqNd4aIbhYIY43j8j6lVr/mCLTRQtAf3keAN7y8z+5dc++lZXyI1978HP3fauEdGejk4prNnwjV6FMKh9I+UBIpCT4uPkiYO8ZCLKEo9MngnjrbOVsyVmSdavh1IVXzmzPl449Pb57pnj7+0+97ZXT1hy7cens6rl6ahwEPTnNqm9WAoapavPdOz/WefJ1Jz7/5daOYtX2W9rMTBQLq+cJyTmvlDJFVte1okS8J0obCQ16wzQ1rSztdrvzi112XnzQifbMiYpCX0FhROQAJftxlkbQlOhFNyzZCsvO7VvdORcgYYXWe4GgkYipVw211pQqz4wKRQKgsLC2ITcmMLNSQBQEKTXWWgOaog+MiNaZaKq8S7LMCEBgJK1Ia0LwzME5R3H6kIQYFKwPIwUQ55wQGmM0kSbFzOzYCSQGE5bgfUVYhwFXTillCS0ReJcwKi9aa0EYsqvZBh5tVDUpCEwCwQcGASCIJQscdXeARUA8MgWIKhFBjUjAYhiseKUUkyBK0ShQwForhJlJN5LpIB5Y93q9LE1r76KSRYw6dWZubGysHgwj8evM3NxgMMhVavvV9MxMWQ36/f6WrVvKspw/f15rneRZCCGAdPs9nSZJYuq6jjysVrPJ3unEGG2SJBFCL8yOASBih7XKB3WllUbvWbCRm8NHn7jhpe96591fzM99but4OtBTh8Kec/P9Y8c+qFPYPDWxsDQnlM9OTjeHd77C3lVdjH/PbxXUb6h/O7t05S1HXnlf/6AopUmBpoIGtS8YjYSe768qnXJKtYEQ2tQLQn0vHALrBNYCrdgugU5qqmAgKm0NVemrOgimzpRQ+aW0XUxfdd3Kg/c9fe89F17z41f8xBXHHjq8PH9q+sIL0kG9wGWr3yrTWilkrZUPcaWXoTWNsbnh6uf9ubEGXrK4qq9+wcYq8PTKiUrDQ4cfOXfmXGMy2TYxXTab7a/e/xxufGRb/9DU4onlpy/l/UphCVIHb62tlBw5c9YKNvLC6ip4EmhW9VpStKnexACtdKE80Roz6NNOCa4w7efeuOU5V7bPnO8J+uaBCxAxgrsfn3/YHDb79+3ZO35hWZYTExNl0UsOm7zIxycmLm4Uu+o6S1Id2fVKVVVdVZVCajYbMSalaVo7G5f76L1NRMYYF3xNQIpqZ5VSGUNgtj7EQBiroMygFEZ/TK2TWKCldc+fmCyaJGXnbHB5koPjqqoSbQDAsxAqUBjtEB1zzHoRRz8QEdezmVFEJBqlPoIRXg2jFiAiEkVne4FRiXijjQqB2fnIYweASGOOno0BRGttrTUqUSp6uccMmqJsK4RRDi2IgaNX2EjnJRK9Dkfl0IiGGPUnw2gTYIwJ7MWnxH1S2eJSee3N173nfR/8xV94/f333//rb/71N7/5zd/9PS9ZXBsSKcusVcrWo4JRQT5yvUAASGJv61ntYUCIOFvSSmEsQeMIC6/Umh5Mj2/f3B5fIwuUPrdhtq2Wx1r2O8d2HTl1eFuBRaWG9arOtvlmxwTYcclz5h56cOXpU56qdlunKmlBbr0LwYU4HSkCQgDA4iF41qJBzzZ4Buuk+7Ww47qvD5trTs9ccuPMwasi3qs/WHLlcM+WmbXF0+/7o58fb6bLvhqsdquy1DpB8jagt7X8moUFlFlxjRoApWY8p+V/hPqRKv18RsSCyeOPPuXLPqiNaxBvCQXrTQFjTKzVR1QWaYU0ch8AiOUDQiTta3frNQcA7ty5ffbz3zx9+5e+sbi0Ol5MbyqUUOK8z9CQwkp8BnntvABZ73SSJJA45zRSkiSRQZEpLSgW0dsKiLJcs7fdQVlMTN35iQ9MbL35YPNlZt8B87t/O/cbP3n6ugbgoOvnQaTg9vRw20J2slQ9xk1PZ/duav/KqXaWJK204XvLLviKQYA510kAqbwLIMboBNF520iTqelNJ0+e3Lp9J6CfXz6fqdSkytU2TVNblybJgre2rAjEBMlJD8taCJWCmby5kOWadWesdebsqkqUALk6aKWDUCTFalK+tkWaOq5NkhCCtRbyZgguODcqA1hPwaRgUAFojREem2kC5folgeVEgdF18Cnp4J1HTvLMDocMOnhh5hACrkN0RUSRRo3IgkS+jo8rCAipJGgdwKOwswxJgVqHuk6JSJvSVaTIIQhzO2/Vw1JrtSGdDCEQoBce6U9HFTYEIUJiYGTxGth7HRUExIEAPStAo5C9M0QgHOq61WqBD6CViNTeRXyBJkShSPFNtaE8r6rKe9fpdK6//vqzp+fOnjmzNuh3lAohJCZz0f4F0ORZVVX9fr8oClDxBjPR+klr7YWVpi2bZ8uyLKths9nUWoOgEEYTuBACsoAgKaygboRWBT0lUIX+7Nj+lq1+/11v2Dy+qaqm6bQHGPaH91IiRashzvWH89t2XjQ/P982525dORcMKkm/NPGT39f/64N0+ByNvXP37T/45BsG0hAmbxNnOqy9Ip/mOfrU1b1q0B9PJy0teeRAiQZToIi0Br7XVIX3AwXUBJWbLoR+7sDWtR1QkiBt27bjpS/rPv3U8rcegt6SjJeL89u+8E9vv/lHXuWHydABQhhmZSftDGy/UZtAHDLlgF1KRiXLx5bOLw+qsVaYNvjUQxsB+JL9F65U3ebEzkphc3wymZ5xA4a0ftHe2+449tHVy7p3bz5/ydyBM4PlPZOzCdDRpbXG1mm9aztUrpmmnCVopeTVC7ZednjuJNxdA0AJ72g9TbyAXm3HbVeVp2zjVd936SXfU8xXzcQ457RJnHPGGN+pGmcaF1ywd+/YXiJyzj21tMQiQaAOgRIzkTfFO60IEWv2SbMoxtohiJIAIQSQij1rAiRErAV1noqI816TQkRb2QSRAJhFkRbkmH0CKhBIEu1crbWOHNYYijY4zFpr7zfadaZ2lgiNMhyYNmA+AkQkHDQpYWFm0khaAQBzqF2NG5BniB4N8d+R1FYpFY1PAjOzAHgCtZExI6IClOjcFfiZ/vGobQyCG01h5EhKMjrKHkebDEKWEesjvjV4FhEOAtGOheIQQ3QSU56DVnqjKeu91yYB54xpo+KAtLxW7dm3+z3/8oFff/Ob7rzjS7/xm795dmnhx3/kh1b7dUBSARFD7H7LuvPxaFMCgPxMBzp4LyIhsOdAXryw1jrKcmNyj56KsXYx1hwu97TSL7H9TyH8uB7/yNLyf1L4h1wuGCZXDcKha144uXVfLziYwPGZKXukgzxW9U8H06uhcmHoA2sGLShAMa/SIlqY61QlUDv7pA05XdrpT6qVChEhXfTsKochzdTY5vFtmXX1d/3Aa2Txvvf/3V83N29JUVEQL4IuQGLUJeQOMNTxAwPoATSAtwY6pvj7a/lcKiE0G2MP3P/Qvfd85cBzvrPqDUdlGBGJ0nFQRBiCi7cEqSiaG13AuPLiepzW27fNPP/gXngQ3vFXn/vyQyc6Y8XM1DQpZcNwU5MWa6fQsPg6EVMHwNRwpVTqbJAAGtBoShQUzaRf16w1AIJTygMiMkBAbKsxX/VvfsF3z+OB4WCQnnly5rJbzG/8U2/pewkVYAAANXDKaEQCFAbxiodh/jwtN9fK8XxbMF3TsyFYC+A56EDKKFCKfTWeNxZrC+KttbESnhYNXVvDJC6ElFbK7lTeERuoqVWqxdnAbLncMbZ5eWWtXLaXXHfD+UNzfDw88OBj25p7ONQGCVkI0IsHVIAGUOk8dcyzO3cqpLm5s632pAMvVtksBQDjsZKaEmOQStfXJrM1gyhbs4DDzFQiaEMuiiR4xaAAmGpAqxP2oojAh8SY0vkQPHEolGJwGFAESSfKaGbWCjAEZg7eqjhHocSxc9Vw746dp84v1nWdGIUoEhwAdcue0gZEgYAGJYow0b6ySMpLSDh49ibJEFGYRzQBg8QkICWLAmxkRV0NUUHEVz3zVAt3B30R8cgKMM5taKWYmYURhUEosCJUwhw4WPfYw4+ISHOsIyKtZnPQ79e2BILSV9baNM9sZTvtsWanXfYHS0tLiUnz8VZ/MGDnJybGt8xsquu6LMsib4BgjLUKAYXruo67lsCBgEBpxz1QKKwSducH9rbXvfbr9zy41F1tZJyaTYniXBcCxrHrs2sWrT95x0d+4S3fc33zsHetjgw/pb+/xlxB+XDj1on6WMG9F3We+PTajXVgoxNfe6W502gmSbLSrbhoI+t2pzWo1dpaX2HP17pGZfIh1+JlSVgze1UYtDoUbVMk1tVmMMTG2PbbXj6cPz33xdtTrbKJSd9rP/ju/3XwebcU2/ctDE61daJUqzsY9oY9qy17BPTa9ZgMUTI101/cdOS1r7nswW+dPnb4OKpsIyjMnX5gvDO9bebydgfmHj/ZSi4fU1k1277+O3/8ik8e/sriQ8fbR/ff+MOXVxc1JzKdNu/60hd1s3PjjTfkQ9/Poc25xZ4tk9kt6a+945361rstgH1Tt/szCTwp6h8OJfc9vacx9vaf+9iV+760d+813cEQiJz3SBGO4kWkDqEWEe8Dc0AEHJXeAKAKtRJgxzJCY3Goa3AhJDpOTQIIIYoEEURF4L0gCIL3XsGoySooQCYAExEIROoAAYIAaQNEgT0CIIpSyIwMTCSew7qciBBRo0KW0WBLhFCsn8BIlrhOpIriDCIdxcexABvPQjggETIAaolehCQEqERIJAgrUjFjUxCH9UbZs5CS0ZuN+qYxpAMwKR1R7QDAzhMiAcXWr0KKo0wRRS0wCtc6DjuJAAcQZARk5tiBXqd8cITaiRMRxmjjzRpVf1C1pyb+7J//5h2/+tbPfeSDf/qH7zp3duWNb3yD1tZ1g1aFgyGIJhU4iLICCToOSgKCdqCYjDFKaRM/ZmDlQRg9lg5VVmFinPNpBZLnKk8yWR32a9aHlbN+9W1D2AP1ZCcBGD7uaZxa6XNvM5twuFLkWA4aumpWhHu6PlP9E0XVnyw2u0Gd5EnpQ0ppypqITbB9XWR1GCLcs2gpZEQHNWooGME3FQy7xeLxu2fWXJI1uWNEN7++cuLdf/vHsLb0X9+8a2LPLnfvYw4r1CoNUB3wiAANFBHoA54m2cQwLpILXiiehAkbqfR7cPLM8tWF6y7ZJEmAUERi/ZnFK1IS4VeigIUAWQRGWhtgHwBIKRARXRTpancZAL786GPFWKvValnHGfRrHFuxoHTmTbDgNSOiZJT2QxW8eM8aCYkQlWP24ohIE8mIwqrirYRaShMaA+3GiwnVnGrvzFRfza9uuuG6vU/+xIPhL4qBGo6Hgek590gwlHMnSZJLwjXf/N//q7l1qnfhBYPTp3Wq00whGluVlBgmABJUVDSKvGgmK64uXTW/kCf54bmTtq6LogjkFRl09XOuuOrRRx9PdFoNhm5YiaayhsWV7ou/48DqA/fXbO/6xteXqMcCrfExYRKEIAAGSRnkUNWuUIaZ8yINIczPz2tSxiiRkIhAajKtrPVOXNbKnXNDtlmSWeubzXa/37fWIkmRN2N/dwgBlSSAWpSVwBgMKZYQAJgQFRlQcSgZCNl7pRQZHUtnsTtV13WrUIO66nsHIopBCzjg+bXFCCgAiNNwJMyaSIBBiQQIyBGcSUYziPZSKUmATMyMAT2BBAmWAztBVEYHH5yvTaq996DIVzbW30IIxmQAEjUsWifRN1AplabpcDiMBcOyP6iGVilFibHBi8iZM2fGx8cPXHSwHpa1tVGSWqRZI8vLssREE9FgMOh3u3mep2m6srjkhZWQLavz589HZGAUfGmtna3j0hO8j0KteIkMYA0BOThOUtx87szZi6/e85a/+Jk73/fQF7/yn4PiUVATIF6cL0yKwmON1j+/910S3AWtvlS5Se332PfeXvzs7c1f+Ld2CwASHja3nt26BmsLy3V3BbtB7GDQq0CzdmLFhzSZq/uIqMbaCG3tnXF1CKEYyx22AyQZaeGB4MDZPq30fW9AnU1bv+N73HAwd+cX8/ZWCDB05SNL/VtueXk+YwfDlXYxMdMa27R5y8BWq8srY83W/PK8BpNlRVVVs1un73vgU/d960sHD2z50Zuu+9KX7rnv7rWNAOyGM5VbefTIl4EobaXqwfrk6VNvfefbN104+csLr37ogYeWxwZf6T/0Wzf86Lk1Hkq3BNfaumN2qnn2zGojKbiWQJPSWO2r4cM/9wW/fQAepMXOWtkj8DuS/XFePDV1enkpoYYoIGFEJQgoiCwCDAgRP0AjzQkAwDMplCIC0HFufl2xQonyKES00RARkdhCI60ZIQhHUwMkEgCM6F2W0exNJLYCkQgBsQ/MYSRCFo7eWRL8+uzvKO2Edb1SLAVv6KTin2PtNNZ7NwrIWmsexWlijp6GCF6EwPkaRjBKYESNsYtNbqSm5FGBGoGIhJDC+pmPiJUCACQBFG2UNJ9d3hT6tnnTjW+Iai8FGB8BLwyISkWDlNGvuv4iJCIvAQAktsx5JMMe8nAc8nf+zttnd8ze/md/94G//v2VhbNv+9W3F1O03F/KuS2qGvq8CJVo7Z1jUsqxwwqM0qTYMgQAAGRPKmhrLDaYhMQiDrQyEtKF0NuxpTMxNulXD2O7/Uk3+LVdV5+hvju19vLCAayurrk7ivyyRsOHQssQB9hiNb1jur/WednL6eA1g7uXjh6b27Gl0RxUA6XyoDNyjkEGRidlbYG8rM9+sQgEYS8SJqTwau3Msjtx+EHGCu1q6Ifdu3f95A8975fe8qsfe9Gn627X2Uobwxyc9xAwFgaBAD0BAiTxV0NwoBAkAAQBCcHb3JjRvcEg8Ez5It5C8cc8+8MCAGSJN3/cw2kEvOebj3zHuP7BF97w2a8cx0aqwhKamRSHqU6h9glptpxi4lVAcJnJgpcAEhkxLIIgAKijCBtREwUVYnVeQIyUlUbFpeHeyfmT7e3ZFqX0mcUbrvzdL4195fzag7ANENFrnyxBa6Vvzent7/qK+uw96g2/PnAw3nbNdOb44tlmlqYqFed1miGiD1IN63Mr/bTdtODFmImJqZuufs77P/4fnKmsDJY5NcmhJw+nJtm2bfvcyVPW+XJYT0y0O53OHXfcmTUb2jTKynrjiSgBapjUOcfOKzJ1ZRVhgmCtzYs0etFkyQjTSkKauYSgfEgIvQIAphC0oeDEWt8oUALHUBEbMJ4g9ZIogkR7kESQ64BKM6kqeI8BgqCMKmCgkDABxCRJRqUnEWZQylSenWPFmogCiAckhOGqE/SpSQMgCaAwk1fRk1gEAGzwjEF8AA0SggYmB0FLH31iEg2IHETQCscpwxACi7cBm0lReyfeG6M9BwQwpNh5ESEcmSfGcREKI0RlnM5UWUIiMR/aNDW1troGAAf27wfCBx5+6HnPe54h9eADDwiHztgYMpNWZTVkhLSRKUBhTkzaKvIiS51zq2srBNge6yCBD06AlVLW2ogZBkUhBI2klHK6zK2xVARVD1y/IH74kfmLXq3yq0P5x/vP3YthAEmSNRv50J1lgqfmTh7+9N/k2Th7GpQlpZJB+WeDWxGwrNtPwuUP0DXf4Ot8etnkxTvIGABg76pe166tmf5QrSyjG9resrOpk3robZJkgoaI/PJyWF0R6Nmy54Rxum1vPF1u8jDcsnf8VajN6S98Fq1U5YpWSdGEquLN+y+Y3pOAptlt29tFwySJ14AsTdBrrkaoUJpFnp89f/QzH78/VPu/8NSZyemFq27acs0lN2484Z/+8InDRxemp6b6vbqVtE8P5l7y0he++Ud/6rGV7m033rrvyOX36Sc/c+rzb7jke1QyOX9qcWVttbN7a9nzkiaudkRagptsN/5y/vfcrorGiSlAWyBjqAFP0/ANg6XXzl139bXbt+0ZrPWisVDEM5AahYFYCI2FT1IKAQmj+kSBsOcQJCilYjU3JgfREDAOAeL6BAsiBiBEidAL2bAz8pjmRVwpI3I5Gr0JghIgBE8UAw+RQhTPrJ8xL8dnr4kMcQgfBEkihxGA10Wq8qxjVBmGkbDZkNooKjKASTREBAdHdkSIOwiKchsGCDFDRhaAOLS3fhqjEnE0KsFv+2JY/7MSCM9sIOCZVylScewYAAAISRAYwuiKPSuQIzIjjmrsIoCoUIlEWid3/VAn2Rt/5Zc3TW9+3+/8zqc/+PdLy2d/722/O7V783ChHxKVUYViXLDxQ5FGSjaAs6wDaOXIMUig1AfQWIshQR2cYWCnkaoyI4PObxvfFPxgrJn3Btnb8+Xy1LIy6sZ0+CsAX1iqzBWvnNh1dbFSnrTDocHV5QVaCkjn+6GamBn7vr1Hv3XEfuGBKzcXmxEt+JpJh0DNYEqduOAIAEjHeKQgSuC0tBabYW7v9Vf6m272mABVXNlNg4Xl82tXXnrxS77zpV+552vtIl8b9EkrIFb3KI8oDgFExhhaAAg4RKyRvmkgeBaERBNIs1l0u0yko+MR8IiohEQiIWrrBEa1w3ifCIBWlBjDIlHfrhdXeotzZdUxX7z/uFfsbT9rtS1LgTZPMucpI0KPNTASo+eo79Oa1q17RGlEog0gyOjTZREgBNAWSw1tC2d7S83tMw2nnCbUCk4uvyF73+9veTnAk5OHJIeGAKL1L/kdHPvEHfnVt5258MLBydM3Pf/qwbmV03OkC+M5aG2QJS0ytDbYkJq021tNRbfyYnFl+UOf+cRUZ9IIdtHmYHq2TBJtV/uPLjw0tmWmZp9pkxGlSl9x6WWPHzqc54USr6MVn8KAQImpnS3rOk1TFgwuFGmikNiHWImNWxsGDonSSvvaEmDUNyVZVgdfss2yrD/oxufJ1nWSpkQE1rtUcWoyIqwtKKq9BREMHFuzG64SoxaQGpF3EDHScWNHoQ6W2aekGaUWywypNipOFyESUnR9QVBEpBVgGH0unoOsz58xQsi0EtDOpxhIgQPwCD6IOI8aSQKg+Nr2Q+T+qNrbVBtCjFgaIgIQ7/2wdtHRLH720UAtvl10d2kWjW63G7w3xiwvL4NWW7Zs6a6srqwuZ1mKiL1eT0S01jObNy0sLxFRqk2/22u1Wvv27Ws2m87btbW1cjC03pVlmabp+NRkqNxgOHTOaa1VYkIIEhgAyBWVX3XoU8DMVGfWyo/dO3zTy8LUvplf/sML/+1d33ru91zRD+D7fnDyJW6Bbz537siZw/d99UvDyYsyf5iYmXC87gHAOKyRXZ3sP3T36ZUTK4sgA5VPzG6dqdMMi3bemUi3bp9YD8l1t8sra00eHHvyyeHiajh/NlUNzIOjJm3amd74aPnq20NmQWjvo39v1orj5/6I7WbRaAS51018snp+Zdv+q6+95fr5xUErN+zFiUIAb8tgQGnI0ulut59k8Od//pciWFa9+aW1uTPy6BMr1z1n58a6vHnbRQ89+dCYMkk795Qtnzj0mj999TCBuvY9BT99wXd/c/nJR/XRu8889rJLn3vPN5cnWpON6WZtgxajjXipwOUp0h3m854DTDIwYIVJbXzhaRJZwsIlS5dV7b6tkolWWKsFMY42ChFESdG6k8dGjzCapGzIQGNki1EZEDb0zIAiwApwxKhAEor9V/bBxWFcRNSkREbyq0i0gPVBoBD8SBEUo04ktQGP2FHflhGOxmbUqHIYkTQjR7KNpGUkk1yfMxEkQSR5FtOLUEAg8MiIcBT4hFkAMcoYcZ0XsR5oRQGGdT7Seo/2mZaqAoyJ8jNnK6DW6wPfdv7rL4f1hT7aSa3zu0aGpKPdBjMqimJdWddOR7NRZ6wfSqjK1/zoa3Zu2fz3v/TGb3z6w6/v1r/9P3/34PW7uwvOgMU0mJA6JE5E9TymKSU5CI8unogONUgVBIW1gJD32gdWhlWmy9pZGt++xUPuaq3WBuNF2Wm3VlbmNqcaAA5pffXlV7agPsMrSaqRQufaq6rhzrqbpBOrJd01K3Mvv/bo7FT90c9fVtWbxsdT9miMHdb9NCSKNaBE3/iNxAMFladB3eirJkMrkyXUtW3vsAo05V0rv/bWt33hlht9xUQUndpwXukvpvbHSqgB+ggaYACyRBKE3mNE2JhsaWn54MEDL3nJS86vDp+9WWRmkQCxNU4bOyKCZ1UynA+R8YCAqEgvnl2cbO4oA6E/dvnUxUW79diZk8JT3jjIWJADO2TpQ+hojaKdH8bAEOexWDyyYuQER8n4qGuCwoICorO8KFpudanRMNq5DqUp6aoh42wmTrRua//IP8rbDvSe0z/+rW0P4LW3d5pn+qG5/XyjEexwPE+/+o1v4TBNJzPL4oS1NpCY1X4PEY1Jh8yJgNPiq2EOymT5WjlIjNFinAt5I9cE01u3dsYnjs2d0lon2hw5fHIwGCwunjMJO+7PTG9KmySrwMzaUFnXUTswNTV19PixIm/GClU8ABKtIcYYz0IMQTAAGFHWh6DF154DKA0jQTgqESnLUmudKo1OMgQiCAB18BKYKvYKkEWLWGavMIRQKJOicgBJkigEpUgE2+32cDi01mOQEryLzKm4WAQXCBIyzByn5mMsBglKJcSEgAZ0EESlIXgBtAh5AKWUU1BL4BCE0aDW1oE2sdkrAEppAlSoOUhmkrquNSkFaOualEqLPFXKhRoAYoUAQtBpEgVl4AOJAMjU+MTJkyedcxMTE6fn5qLb68LCgnV1o9GYmpoqy3J1dXV8cmLz5s1k9GAwqIdlo9natWvXxMRElMxsmskBJYRQVVUAaTQa9aBqNJvMTEbH2ZK4eDnbrd2YCvnacHXPzNaP3nnqUG/WrC0O2seoCoeP3f89u3eN7ywcHFp9qJ0efR4Nzm6zFxy4/Ll/+6l//IHvQRZYo7ShgYOUZJKMzqylX1i4ttGwwbMbVmePnkClnQ3AoBMjaaIzPb1lNhRZ3pn2nW27910KAOy96/aH/RW7Mqg63+q98qHQsNDq7njkj9qrtxy5/Ef6N30tWbw1+dIByQKNt33SgDL55JeeuvGWKwWy2rkERziyZtoacqnQdHsr4+Pjd33161/8wn9ecvCy5YUe43IVqgPbL7vnvrueWZSleNFLvgtBu+Bve8FLVhbPXnDRwcVl1qmx3fDcS5+z5TPbz2058dcPfOhVV968cOZcd7U31WgjabaOGYIAJrBWq9XminQDEpkVkyxnZT2QCxgSQQHcWdRHE18Px0uzGu2CAACBAQQRAEes+FGAGiV7Gy0DQhSFwhK3aHEmh+OfARFICGLjNnCIg6Qx1gIBCcXs0wmvYwfg2QeDCHN06gUACIyIqdJhnU+wsRoKxjmZ0VdABIBhPVzxhrh3PW8erbBECCAsbhT1ZTSJGmJWGamZuI6mRCdMiEYpFGCRIMwERGrE0x95WkeMDIsIyzP7A5J4PWGjNr6R1Er0cgdhlLj1VErRiNUMUZItEl/9DLJjY0uBpOLGQgFGNggqYzQEwJWl7vNf8oLJsfe+/5ff/oW7/vPnfvX029/2h7e+8PrBqrLkIAQGTpzhluHakiUEZpI8S5RW1Eg6nXGHogQcO+ykmpR1Igr7WIaUJidTSOqGoV5LL/R7HJTtyyWzZRB8x8/ceLetjpQd1lMICmw1oDNe0roRnuzDrrU9F5juoRPDq7fMj/2Pj3zoc9eeW7ho09SmqiqCWbZU5C6AUEAIBADiQYgFUKmApaqH6Le6hRtb76vC2D1rr0kUZ1m21h3u3X/gN9/6m29605uyRst6JgKtdfhDhJ8ooYt0eqSugiHA72byOJJWyuiJ6ckDBy9MG227OMjSCG6T9fmraMc3GjMjUhstDFIEAJ7FjbifKCwaAFLyFSv4v+NYMec2212v+8grz733cGPVpagc/Z+/6r+P/z7+Lz9yze20OtXTaiaVdu4qz567efs3n35RkP+PT4cvh+XSWmPQXa6Wc+g4dtCcyscmGmNN3Z5IO+32lm3KXAL3/nBQA1vM5b39x2/68e7Oj9LctHvFPebL+/7fkGT//+NouzZYQAHOQ8i9NAUA0CIA4PJ/P6X/ffxfcHRS/o1b7MsPsgDkjf319G2bZPkszgQk0LmiXSKLYM/9//q0WgKTkvzPAiqSpsAJlM8pWCNA+T9/7f+Xx38/SP99/Pfx38d/H/99/Pfxf8OhZ2ZbL2g1t7nmJ95w8Xz7hjW1Y1Db5X735InlQ4cOrQy7hRo3ZBpZ4coVTQmNSivMEs1txDOjYCBBCKjWuVwoxCggArbfHxh2U20jrdzlEKTXqXMNaWiYOTy21e284GffOPuaV/XvuOP8o3ftvuaG7vGl8998rNXKuisDgaTTxoEbEqaZSSQEW/H09DQG7veHrBBMmju2pPuhtqXPVKqQnARllGExpCg1T8+dTpXWDLWzrYkGpWql363ZN4r2ucWFxdXzDOKr2vu6kWfVYGiUccNqrNHy3lc2sBeIw71EiMp7RgwiimuHiWIEIGKlHAgoTeJDcEmi13s3KtaykjyzZVUjOwhGaRxWgGqQBHSimDVRqtAbMklSpEnDmOV+XyEQUWaSWCxi5sAsrJA1BAIvpBJRIhw0ktbKhwASgKL3i+LRVDEhwGg+gjCapAmqQBAkIKEBBdEk3DC1Utuz2pDSurbO8ajrpnRSl6UxhgSazeb49u1lWZ4/f95aS0aj8NjY2LYts0VRPPnkk+x8o5F3Gm3nXH84OHPmzNatW8fHxycnJ733vW631+v5EJqtxq5duxrtFjP3+31woWg1txU5s3jrDKksy7ywD15ENI74QXkz+gErVRREFCWjUXwIAN77pNi6mereoG5t3jxcG3z04bW0tX2lm7c7meTVgRt2p61ieWE1N5tbLVNTL21uaob0qpva311j38LHFr7/c5/895feap7/ikuedM2T5eSLXt588j1r3oxZbzNJe1ATc5YR+Fpr8bVrpg2sNaiplWCBQ9E9318+u6zRB99I83KmMm97f+a3p7w97e86sedHy+QJUEEaQ5wBurzi41N2kDQQvHKHjnInz07wkCXxwVspm1p5V3NSGOA8M9rAZ//zw3ZQ3fXlO9vtZq9rtmzauWf73u7a4sYj/Su//DuN1lhtfZZSb7DIYarTnu6RFNYs2e4FU5tf1rzxb+j8/frQg3Mn1lbOT26eGksnBmKV0siuSLNuz89ux6kvTcE0yZLwJPNUiYiZaZBN+oPVibv1pluK1lhjWQCYiRSMlB8jHUpEdscWb2zuIo7uQAVaCBmiTkQ0kmAECI3ETbhu7Rz/7EJQIwEXxWEPYGFmpShAEBEe2QwhAEtYrzPTupkPAEQN9rOKsesl2Q1F9HoL+VljQlF7sXH+GwJXimongmfq67ECqcwGhBdHU0UCgCpKzIDjHDMw0GiKF5/1viASEcHrVWIQCQEAGEdsgI1v3vilGEEBEgAjksRJl5FhQwgBlcZnEyLju4zAdqO1SUSYUFgQEUtvdfTraz49v3bRNVf87HvfPfYLb7rnzs/+0q/81G+/6e3f98pXrJTpqhpMg+Ehee9dwmbcNFTqVsQtlFxaPnJ8fq5UIUuH7GzpQqUdYJ6nm1qtzVv9GlRJroOzvQrA17b8s5cMr9/bbDecB/588WOMakXNKEgDalaArk5oOtHL1dr44Sfwxlee2j08caKb79ydv/kHH/jjDw2PnLp631RjhZsZQ00BQCAytUGERYEyQEr1jE0wxQGuzjvXBX0uX903PkY6JEnz5NzSL77xF//9Qx+895v3F2PjzaIxWOvKTQEA6GMZn0ISMUCEWGKIUvo8T5aXzj7v1ludJ9AmYr822sC0fgTxMVISjEbH4+Ng0kSpEYOFiPQ2vTw2XIVgO0+8e0q9u7vpxU9f9PYJou1XNq6/cNs99z2gcBkRsQqkiBEUmPh+CHEOU5AIAAOzQoUKgCh6FAIIokLnRcAxdEWorNpJy6SZBKqaNfj8fHZiz9pVgxMDajSnXvZD4y9/7exm/sfX/diBK3cf63eFnTHETowCz1YAs0YxKIe7t+9YPHNuqX9eNzLtlc+Tsru8a2aGm8Xho0faXAgyi/IhGMLFxcXAkCbaWzsx3tEa19bWfvS1P/KxT32yLv1kpz0/mFOK0GhITB18JcEozI0yRcbOiQ02VFmaKqXW1npKKZMkw6qkgEopDggAPq4WAJYdIaVp1uutBeuazXYdJ//Fc60DBHSYIgn6GlgB5lZqib7NShMRQAhcVZW3dZ4mSZIYRVmWWmvrugQAk6i6Lo0KHCxz8KQF0SRKbTyT7ImifnOkrSBCQWDyOo4EEgVmjcQg4iVVSrTyRCLBMKRBJEEgKKsBMyskh4LOB/GzU9M7d+/atGlTlmVGJ4PB4NSpUwvnz4ui6enpycnJLTObrKtJoVF6enq61WqHENa63RDCxMRE1JEBAG/eLFEdTZimqYiIhKmxSWEOAMYopRQVKCLWWmQkbQiQ2QNiVLTGQIsMXliBiu0WYY4QHpK6X4YKswtmijf/w9cXm1NFb22lTtuUjzWnF4/35g8tjV9VrJQDM/GkUnvYNhS6Gaxu7Tz2ji/De5+851w/+/w/2gsfPvxTf/5KINhvV19606GPf+XKZLJD7FJjfF3lJuPgOs1WP6tLlhXPZMstRpmsOD+0rmgnaDJiT77RXOqZp+3E4zLRUy4NzQGcmoIOgmJgARggj+s8OJJ8pvjqo+e/+PlHrnj+pUuL1gJlJlGgAnjk4IO0xuTBbz307+//wPXX7+AwsLVkzWzfhZfWa+Od9p6NALxrzz4HQwb98MMP/sd//OOerTtf/4afWjvTJch0ZpY8/NTB2/71oc8MOmv/dvQrbVuPdSYoMzy0BkkSVQ2rvdvb//nJD33+J/5Tf8CwYhywFIEZEiqmJ2f23/uiT8//x/n542Np03YDaBYUBBYQZhlJgYRFJO7AR66oPIpzSiAEZhBgIQEZBW7W62Kr0Z0cVw8iHSd0o7uqxICEUebKOFrYYqyLgZk4CqZGIRMQEIFDEK1jgxjl28IwrHeLR13eDR9D+TYJ8QgvBYBBojwKRjFWkEUEIg1bEGgEcAVEEBA9+g1BSIhAAQoLCIsasSol9ptlFIOBEDcU0iIowPBtQqpnnTkwgiKllBERCCwioKIZomBUdD9rxkkwAkNGMp0olnxmx5OgK2tIofahDY2zKytj2ze/6r1/P/nWtzfe90+/9Vu/cW7h3Gt/5ie2+ry35mQSOoUeVtK95/Gnb/9E/yufO+kO2xcsn/3bn5nEKwY7tyht0rwlu/atzGyuTt6n7vi8quYnbnrJwR0Hdu1+/lA56p+9bRffcmE30z6V/oLaioCrapOFXEGdiHeYizaANsfJ5tTyyaXGV+7d9cK91bh5KlmFnbP+l1/1+N9+cvjUqZtbjWZQaASBIcYdBmbmIEHQsHeW0nSYDGnyoewHmCYxNHbMNBqtpN/tUZIPLNz43Fvuv/c+RPTeW+DwXEeHVXqaAIGBHLALPjWpSJ0lBSKC2GuueQ57YPEMBhVFmP+zt0qw3tMP0awCRzoDFI4fcPwgdF1VThiIce34eVfI8u3u9PLKlX+QNvPSDa+6+OIT579ZV4OcE49qaFlJCCEIRwyb9p6REbUSlojkjTpAEQ4gCOBTVHa45+AFJ+ZCI/FZriVom1hi0yI4l5+8YfmVSRpqoP7JRZPi0bmePPXU5tf+zPHDRyg3ULdWpZ8iBbJK6V45TIrsG/ffl6Had+CCI3MnCTOo2ShdBgdl3yAwMhEYUJioQV2ljBw8aKVSM1gcnj+7unfHnk/c/hGVqERCb3nVQSBUO7fvePqBM1NTUwnh7u07+71e2Q8Gqfb1aP7VC6H2wfuyHF1oZK79RLvlQUJdJ6iYCMF0u2vXXX9tPSzv/ea30qKRpWlZD1cHPWOMp2DSvB6WCjWLWOZEG8/OcdAimoxWhBoxIRKM5irRl9R7j6iE2QiKSSuwWqcYkAOg0pULGn1gDhC0oRCQEY1KveMgXkAqb1lZZAwAIYgJuiIXwWl+UCqGNDNDNyzrcmpqKk0zIRkfH28VjSLLW51W1sh2Ts0WzQYQWmtBUWes3W5dBBdd5HA0XOGdJ6L9F+yLsFzrvBNutFtx8YrRtypLnaUCQEbH/UHUbAfvCXVgp0iHEGwIRmljjPUORSIFTCMgonNe6XWxTpTGbdDqEQIzsBKjJkg9+ODjH7w/37I/mV/tPvTk7I9c8fiS79Km5Mx5e4GfcatDaZIfX/XLm5HTi+b+qpL0L79ZVnplvDPRN4Mnv1G/89Xv+fX3fGffZy986dqxc4cOHdsmDWOcprzoBlG6EUq2NphEpUqXRiA0vHGuoZWEpiu5r4aJlZMt5VNy6LAfTA0kMLUGIjBMWDAsbVVpC6qSh0ZPZC6pP/XZB6+7bU9t66wxQYGDS1HbFJ1DzvL0Ix/5yE/+5E8//NB/tDsIkIkKpw6fWDh92qhqY3V+1zt/NcnH9h+4aGZTUmSrL7rplcaIU2lDeU/50qC7b+sF1z+x+w66/0vVY7csjF148KK6CNInjbzK5dapsW888PUf+7nXj+vZ9H/qsz96Gm7BLOS1c6vnFvv/NPjpm3/6Ne/57snpXTWRD31DJjDHUR4SoRjARCIlFAIH7+VZprUiQACklODIWAARVWLEhWfiCogIBmECIhAWwZELLsSIzQIKRQFGmocXRhZgQRYS8M4hkZBSSgfxSIhKU8xFRSIG7hktMWHkJ8T0dePPMffdCHsRSwkAGJntQeJMBG1EzJgJISgcbYGjj61HQUIGEGFgUIgQ07SoU4Znpb8xsmIcZhit34jICCKCUV8pG5dxA4epR+ZIhFEIJ8hK6w3R1vpBGx8BkeLgI5gzblNExCNIoxBrC5BaKx0adoW3tNrf9+4/mJjaOv7Xf/TX/+utT50/+T//57vau9Lls+eP/ePnlj92e/j6F5owmE7SsKWTqHTy4FXFzueaK67vze5cbbQG1OhhogeDfNsl7X//+/5H3nNw896fazTerRtpdvHz9hwty4WJbICpPEaXn1E7ejQFAAFIQAkIogbhgIWjuWbR+NbjuzG4W26cy3zvsUP1Nfsm3/EjT33om/rOO65Zls3jYwkFJUEi+IIwEJNRJslaqSsaecFi67UJLezwfEYdxs25znuOncD3vuL7/uwP/8h7W/XKNDXuZodf1ZV30WscWHLStXN5guy4V/bzZtppdrprIcsyAolOrCEEtU4VZeZ1Lf0oJ1539oDgHQEaRS54L15rDCkxATaoLrL6dE3TS1/8o/f9y4ELr7j28ktq68o6CHSQFslqRU4cOhuINCKFEILzaSMjEQ9W66K2nhQ08szVA6OMMBjUlLVOnziuafeho8trZdg1syUR9E66rfmBXttR7iYiBUhaJ1NjC1/6Vtv2GrPTq0/cN84trWvnBVVlOPVOTGrssEq0NkmaFC3FOpBLGTkx3WHp54etouEQsyCsPLnkkgsPHj9yeLw5M9ZpPTq8pzk57oGYvTbmubc89/Dhw6fPnhMWL27YW7v84oMLC4utsenl5VUbfFqk/X4/TbT3Hok4QLQjFcHgGCiQ0gLU65bNZrPylUdJAJiAWD999LTWlDUyY3QIrpk2hvUwPmHeVoTogxVFrMGHoUZdNAohLJ3VWiutNREDeBRf2TRLjDGhqq2vEFXtaoxTu+K11qQB0KUJjmXNRqtJREtLS1mW5nk+OTlZ1tWjcwtU43jRbCWd4XAodd0q0larEcdBlpaW9h/Y1Sia3W7XGNPpdDrtdpqmSZLkeZ4kSTyfEILjUIfAQWQkzgQkVAgKKWYeEbvgRGpbiwj7gOvG44EoAQ0ASmsGCRwi3RoAUJFnFgQRr5GEBQA2GAiJNg5CCFYhiEgE8rEQADiyRVDsfQnKqMxr3wjClHj0VvyeifDr//voYHrvZG0nOsXtn+vu3LHjBTef/t6XXnRizi3X/TqMdXB1MN3VZzGRUzvPf+oT6vk9++WxVuOKS2471zs+/+TDg6f1v731vtf/3a3Dk+5Fz6sfP4xAORjOOLCmPntUSUKGAAc6kDVDtKFfFxJAgkfyqUdlQBp0z5X+pm/CYgsmugAAmnG5Db5QDx/A7kSWmIqGwdS0gq0dU+/5/NG3PF2NjU34snKGU3S9oDVJMy+OPvXEi5730tXF83/+v/946+yO+eWTqNJOY1jVK0jPkLAuv/zSsZb+/Gc/ojL+03f/2bVXv3hhyeWGayTFLsWkl8kvbP7+O07f8+CewyrVL+w8j71C4qCGSlr9cv6VL/2eyvZCIhc0rrr4Mwc+/7+/jHuhwR19NHVrw1/78C/9wwf+9abnPffsXB/SRJCQR3kV0ogXgYjKjaaPTMxYEYGUl2fmaxFRCEREQojNqvUcFElAQAiYgosWJYioYj4iIYZPR7HsDBQkRY2EISL/kAkUIoIwi4tBlxHQeQBAXI9zAIIBAGh0EoiRmTCKUxjUqIYetxQQRoa7rEfpMgGID34d4sEwCpACI5daAiIASyEWinE0Z8gSqwKsKUbl0djKiONMRFprQAggAXjdCAHXe3/fZjvIDCiViDgORkfr30BEXDtZLwwIghCSBAgCLKLQW4eI1tqNLQgAGE8hCaIJPBAwcKi1gl5NWj3vHW9q7Zya+l9/9vg/vf+zZ7o3bZ1d/OBHZP6hTENrcptpXo5bZ2B3hztfPnvjSycu/t6VqfbAZofPLKV2KfHCJOPPv3XTy1/s/urPyo/944tKc6bq/2WausFyaNr51u6/6Pzqp4sfEcBEKoQw4c/1aaynJgFRIKmgZWWCUhaXH1q8rP1UuOMrngh+9ycfnBybe/0tT10ye+KDn7viyRM7i/b+dMxLXZDY4CloTk2zpF3UqAtnLDe7Ml8fOQELq8cm7l+57vVT+rkGiRA++7Hbp2a29gdrjUYDpzwfDPkf5hFpAIhpaqqq2joz060GtrJp0J3WhCmoCg4kMBiGoJUiEOYggjEeew5KAAIDCwjgSOgOMYdBREUaGDSh9F36WDnRNG42XZtOq/M+u5Ce2LLt8ot3Nx554JRwv5mG4cCx7oD0AztEFAkhhDzLjC4AgJ3N8sx5j4ASwFaV1jreM8HjoF5JFU12ZipCBcN+b7mZzzQb6lg2DwCTwx1DUJZZqWy86Z745L/uPHBZ6LTGVZEGXvP9glINGkmhxtpZo7DTalrrH33koaLRCiCMwTt+7nNvPnn8xMmTpwFZtELgENyhQ4fY15ub+fTMeJqqc2fOaE29Xm9mcuquu+4KIZgkVV6J45OnT22/cE+v39+xc+fRE0+3283FxUUiQkXBsVZaE4gY771GUgBBpBz2G40GsQyGPa11CE6b1DIXjWxu7pQxanrzpnPnzuV5Q0TyJB3WFeBolt4YY51TmnKVlmW5d+/F55cWpddlBgxMggLSHwz3771g955dSZKsLK8ePXp0rT+YHB9r5gURZVkxMTEWza6VpqnOhEkSRKyqShultc7zvHI2nzMfv+e9z7n2ul1j+621zltDKk3TLMuI6PTp081Oe9PM5hCCtbbRaCCP2EDxOa+DH9l/j1ZYXO+E4Sit4WdyhVHeAMgoQCPAdXzhqF9FJIBIKibEG7amSinxIY5RjoZA1i1OkUZtto0AIxAQlY6iA5MRV4hdw2lXbEO0BJgdb97+xcc+fHZ860xS28U6b6acvOt/X/2JzzS+/zvHHr3n3150647xnXJyKZPx47Jp33Me+GSti4Xv3l386b1r5YrL86t2Xf0VnQ4ePT539Fzl0yrArsnGli1quASu4Ax0yiSAlnBgoJGaXJQrAgOQMVAjg+mJQGBVC/lz5gPXyq4Tsh2lavLuUzBoYK8D8y34x9tCvbpmLUJTUmy0pFUUZzH70j0Pvvhlz1/up5T0manRyIfdnmSl+OaX7/z39//bn2zfOVGX1dRk23o3OaGI9i8sntm4PqsrC3Onzr7h//Hzd9/zFUWgFAwH5ciXngGBhv3yyiuvuu7Tm3urzWo5b+ySLEDX6rPn5669svMrv/iu5d7Spsn9q/XisQcPHbzh4tc976e+dsenjp0702zbzdt2dpqdn/6hH940MXPJlc8rLTL6uGcaZXwi0X4AtRIRZInzOcLM7EHQyYhGgc+aypXwLPtYGVV3YQPwAQCxLRq7rQIgwgJhPU8FEGFGRK11JEUQYMRWQvypfiO1hZhZAkB8n/WxH3rGpybeZswsgdYL3RKJlRt/KxJPKYDE4R/RmtYthKNlQixoJ7xu2CAxuCPH4R/xRCNoiay7JG10E0dPHCAKRHOIDSoA4jM1c46CDlKwPu4y+jmEcbca68zRFp2IFKEDfvZk6ugsoxubRUVUawRENmRYhKWubR7Ka37+R5uPH/+Bf/pr9Yl/LmvK2pS1tgZtQGm1c6v5jpeXu9v13IOrl7/g625q5YmlcVnZPzZmp7LmZtpdUDi5cP6/HpAnH4fhGmK4waqv+sGDsP/Izp+6b+yVY7zwyu6f3JveVqvmgppd1rMMSOy0L71KWWW52Wvq89zthmHvS0/sdNgokoWTg8Xj3Y5ao4v3nv2t1993z+MLX/jc2ZOPzowl052Ogowqu1KeOmOLQcD9VdJzsFIkm9qXT3fPrg30F7w+DS5hWEHKT5w8dn7h5MT4rDJFecsKAJiv5wwEpBFABIn0YFDaYImo2WldccUFs7PbTs8LIYKwc8F7P0K+rQ+Ox+0hUrSDGoFiAMHoJNLyR37SAOJEAWoxRrDLwQfBlrGvuu1qq9RAOQkQHJukqK1nrtrNMa21c25tbS0Ep7Uu0qwoJheW1rzzSqFS6G1lEg0QRAFCQgCN9pbAmGjfaTUSwNXF5dUentz7CADM2j0NplRsYsL5cxLu+Nj2X/n9Rw4f6Q767U5WTDQ3NyY14Om5s8CRN8J1XSNLkiTOVmi0aEAFd999t06MxyAirEh5QQlTU5O7d+6oK79zx9abbnjOv/zLe6cnJn/yx358eXl5cXFRa31y7vTJuWPa6IsvvviJx55qNBqPP/VkkiRzc3OXXXbZ8vLymXNnkySxVe2cM2SyxMSCU6LThqTWWofiapsoLSIrw5KMJoEk0WmaLi0tHTx4UASPHznqvUdCACYkZCzLEhCdswCstX7owQebrZZ1ttVqkUA5HJoku/Siiy86eLDZbIQQ2s32zPQ0C3bazY3HzxgDAIGZiJxzoCgIJ3kmIqQQiBJKx8YntNHj4+MzE1PMHGBkfxTr27sv2Euo6rpGxCRJqqraWBYRERUhROAoIAuuK54AQAAVIBCtMxWe0Xows0SIIFE81Vi+ExEURIEQRpQDgpFYhiEOZQI8q78FACTAPFo1FWBsAaIAIFMgJvYhRIqvuKATZEm8DMXaP/v06fbEdqgWSCW6H5SGscm5w4/OvuuR7c0tl//kWx753uelt373YtfMq7GPHhx85p5rb5k+sGPXiyePfvB82Ts0c8V3XVvWd/obmxMPz9Q9vcfc/cDKcr11bIwqC9agACjGlJFQ5Uku1gIaYWYtnkIClDnGROqCwVwgIupv3uxu/KK/5j7ePA/M9PEris/fjFbpJNPppqEblErKWnUaK42ZzZ/4r+Ovfs0LV1eBnVLGlK5UYFqN7OjRY//0T//w/Oe+9InHHyjdYjNtN/Ls3Oluo4mJ0hsXrZm3p8azb933zXvuvu8tb/1V70DrRGtNCp31iIp9aBXty+n6Ux98Ym7+ax8R/Qd/fvO850sP7n/k6w+dWzr0S3/8o2vHNj/wma8+efbQV7/2td2bn37Z6374zLGnP3z7e572J7ds3n7R/gONNFOJCVVJIBuTjvCsQ2u90X3A0aZLjRIuYcQR321jy7VxFwEwkdn4yoZ4KobtjW9TcfIbJAgDcMyQXfARayMjJRdpUoKj+3Y9+V7/gQDC65VtYBHayCxFRCkEgWdP5SIiEMYmN627Cm50UiMPcvT4RH0WC4l44Fgxkuh5MpJoxelpJGEUFIGRoRhhAkpEPPC6c50gC0Wp2nrlYOOCCIKwoFZ6vVG9caqkFbCw80REasT0GHFy1rncER4Sn3eJ/jECQmQcWwVESjd0WPLH//kLyUdv33rv1+302IpN2kICIXMNzgYhmRkeflJOn+y+4uVhCs7Mnb9A8otnitae8W0TqRsM+l/+xsmPfAwe/Jo++5AGI3m2iGp19lrzvNc/fsmtE/XJ1535pZ+mvxdf/9749FG6DD33qVMHk/lS+6rZP33xkQ8c3/aS4zte5Gdmx5YeOjj4YrtafXz7i//jP384sCkHOPaVlefv/9yV1z5x5c/d8eBXTz/wb2X5lfEt+Q5o9o9ufVFv7AVscp230uwSYp+iN9uDbfx6z9abyCilROCFL3rxBz54u5CqqsreVNERHc4qwFiZE+FAWvUHA9GSp/mZcyd/5LLvS7ICoFTKMDMHLyyCikjLOoMlKq82BAfRhAEBHI9ykpi0aBFsarsZVhLwIGAxB+AFdcGhY91V7galdu3atWVqR54jOIYUE5M3Go3VXvexxx7r9XpT4xOzs7NTU1Nrg9VTp04dP/60rZ1G7R2K0oBKgVWUp2a2PygNOqjbpEFrQHSn81OZbyRr+aBBanU4fvHsN3//XQBlcfNt4dyhCw9esH/XzuZke3xiquoOtp0++60H72eE8YnxZl4sLy+nqU6LxmDQ61XDTqu5Y8vWBx57ZHxsTAkFQ3tmt4+PT85smpyamhz0y80z+Ynj07Yuk9R0xtrtTmvnrh0gWLSaTy08yp6zLCuK7Morr5yemgnWnT59moiCdalJsiyb3byp0+wcP368211NkiRN06uuvWa6M370+LG+rdI0Jc8iEhCWl5dJYMvs5na73RrrTIxPlmU53u48+OC3qqpi5gDUaDQ2bdoKigSh02rGNxoM+1u2bNm2bVs1LIf9gcmKnTu2AcBgMEySRCnV7nSItLBn5kjFCsHH8hwAMXtginDd6CNECgHReicsla3LskREUKNOFUW9qKLIykFFIeqj4wM8svV8FpaW1ptVzBDpuvjMPnod+xe/gswBiZEw4iqBoyEaigCwCyEo0RsbeUGIjt8bK90onPMoqqtvzzyeWYBAGxOcx+AboH0uuDIM+zd3/vHj37i/n+7vuAFrppAjrAYlqo1TdeJ4uFCt2V1/9O7uv31i+KZfv+LVJ//WNhqHDzwHV/o/+BM3vu2DH+wOuSp0u7354uYTD9U//Bu//43nX9H/wjd3D9wk4hABvHDQqAR1AEOaBCpEVjZECm9IGFWgoIIo66v+Gtcl1VYfv9T8xxX1L33Y3/DY+GdeBl5brGwIw/6a1gRIlSg3b61Jv/F49+ihI2ZsTwhpVdeqSDw7Rj729P1pBg8//DCC77RmB73eoNub2aL3HWwXjemNS3T08GnqyeNPPTm7dfv+Cy49s9DtdNqusiGwQuTAHEQY9k027rrvwwcvOvDFj370yBt/btvOS+aePPQ77/7l7/9fF4qqF04/jf7qtf8MK8uHe/3Vf/ibv33xbS9+/c++8ct3f/mGm67/w9/9A895d+izFISfFSw3VEvMlXUAjDJCsHEI7IOIkI5OIoLf5iIPG2FMRETCsz7lZ5YwWP+irKuiaATHQDXyYQVNZuNWEUGREV8KEGSUT6uISnh2xIoxONKJ4n8okFH+Cev7AIy8vwDP0iSPXgkiChkgGpPIKOkRDqCBYKT6BhaOmisAAFKyzkSKNXbRiIAMsN6Kjk7AI20tI0X41/rJxKQcIgoRAET8xllRvDQCo+w8qt4ISauNkYEo2iIgIgIi4RAUIiCyUJAEkBq6v7Dyqbf87ky/O5Fp2b230T+3R/OwkhVpzndgq9+W0GrRNGsrpzof/bv8VbJvT3Xw0i3jnWTw1Jn+332x/6n38rFvpCZUGkxnvFZ0fPtz7rz1F48dfGGxcPzcf/zG5tUPvfiGE9mkPdIz31++5WMzv/V4dqOzgYNBlPHVwwePv1/L8iXH/+XquU8c33TDE9tefP+lb6ZQmXoN+gBJQyVuENSnH3/1icf+68ILnrrkiuqSv37ksfvvf+Ljp49038pbbxMkKCZ9MQbMrDIffJItcHHhe78x/fpL/LhJAPwHP/AJQw32lYD4G2v8qgbkkZbFWgks0SWTrVKKUCanp3wAVEBEwIGUlohY+XZ4uIx8P9b/k9dLQSAkFAVy2oMKQk1VG6MG0uhW+aKffNhe+rW//PSrb7ryB19+Q6lWULJME5CqvdLgAEAl5rLLLiOiVtGIVgFpIxkbG0vT9PATR6z1AuKcI8US6tbYVpCGYBhrJBSUQkpNkkm+XJyeGWy3a0ur549t2XflA5/+8qm/e9uuG18i23ad/dxHrvu+5+4/cIEG4w0lm/JGo0Eaa+/279+fmWRpaSlNU50mS/Pnj8+dHKyseeuuuvLKLTObGmmOaTLe7iBiHexKt2tQ+yA+1IgogaO7p4gI0uzs7A033vjFb30oOH/dNdeNj49PTUwy8+zsbFWWO3fscN53Op0sy7z3U1MToKhoNgBkvNkp0mxyctITAIBBQsRBXVlXF2mWpikieuHgudVqXXzxwYnJztmzZ3du33Hu/PyOHTs6nc6gKhExLxreupiVRnM9V9UE6HyISxEpFUtG1lqVCAkAYuw8pWkqDLV3EQYrIpqUiCitEJFHqQONhh4QibRE5D0he5fkmfc+6pOtc8ycZRn7ABG4E9j79X05kedA676qG6U2jiUwxGcvZ6OqIK6H0iAMIoERFUYT03XaphfGIECKCGF0Q44WYuQR6O/ZYlRez7ZR0AbRWntXG0nBkAazWPX2TI2dOfX0uz+1NjGzZ8UO8izxNvQwiBLvJbNDHYo6F24Nx1q4Ot/8+185+sZb7/lz/cIJ0+nkFq7d+st/8/w7bz918qFvfvyD759qbMPveOnRpZuOfrKe2Qp7kuH8cmaaPmHJMKmJQ0pikprEE2S+cJG+Kd7ZAUoQV6NzTTQhpdAugCQ4H45t4e//rwVebnDOug3odQba6QScJ0tUqKw4s8Dnzw4v3EZLy5UyZIdoUhd8fvedDwc/DAFAzOL5pQsv0S/+rn1VWDp5bKHTaW6EkX2pmZ9zh4+u/PTP/SQlXkQGg0ojkUJmJjJaJ3UFL3jpd/7R772lRhJv//Fv/+bd7/6TX3r3b17/+tmVFR8qnJytx64+t+vQzOnzR7VTkg8/+5//uf/gRc20+JHXvM6qfLXvEkUhIOF6zW295oGASmsiQFQooLRGwHgHCvCo7yCw8ZJ4MygY3bGxHLpebVWGRuHWrw/VbMTgEAKqUSbhvY03nsRs+FnjPaNordWI0Sgh5t//r+F/FEzj/wkTqjhTENcKAAgiMbA9u+oT3yVhiuvraNmNsyGEmhmRWCSqYZFjVBSHAjE6xlxWBAIwiB8RuBRi7F8DCyPghpMSrHeaR4sYjC5XfN3GuwdhHNXfZQSRRiTAaLKEHAvbo30zIiaoIEt0oOBra9AA6UQ9/tn/KubK6Vfc3Fuq/+rMZ9Ta6l6VnIbmkWa2oLCp8ufU2ct5Yc/EjrOyIovHN33k3/Le+PJXvlp9+n2w/HCilR9rVZhKTffve849z/+lk/tunp57/LXv+/nkvs/8Tqq+nuX/emjsd244Pz8wWVK+5OQfTa7d8WjjKgU0MTjVHJxnxaLHCLRyg90nP7HlxBe+ccWbzk9cXOczAADiEVNFIeXqiLvB3Zc+/C3X2rx360Uv3/Oqau7x7yoHWmQzkAZEIAMgoE2g2WEdckg+/zT/xCXpqePHH3n0oVSn3lV2PPBBb/4gVQjB2bqutdZpYmJLLn7Waab27TswLBkRFRIIIKIoQsb1ogUKPgMvYwCFzyBF8VlKaRHRzHC6ajeFJoqmZ7U4xH8Ir/V2ODu29YW33aATT5wEjUPnAYQ1iw/ee6VpemZqtGN1zMzsU0K1Y/veZtYKIZxfmD89P9ceb6ahEyQfuIpIo0dgbxo5ae0EFhonZ3rbMuDiggPnDn396d/+6UmCy1/98/fefdfmidaDjz2kHF948LIGpzaRPE337t+XJIn3vrJ2ZmYmruDbd+xodzqtZlNCMHkaK+6B2TknIh5C8KwUY/R+0jqOGURHZ/4/yHrvOEuO6l78nFNV3X3j5JnNeaXdVVrlLIIAgQgSORljg21sYz9jY/thg/2e43O237MNNhiDMcFEAUIgkhAIIZTTSqvNOU28Mzd1d1Wd8/ujuu+M/Lt/8IHlzr19u6vqpG/wrlqtrlm9Oo7jnTt2bWpuy9Lcex9FUa/XM8Y0m83Qm82yzDq3efNmMtoLCwGmzrFXSjF7RMxszsxAWK1WScA5x15QK2bO87xeqa5au2bt2rXAMjk5CYROuFqtivPWWlKkkJQm65zkOQJ473UcWWu1NmGLaq3DLhKFwIIq6C0XYRsRhNE6Fw4jpQoHCA+B3QPhJ7M4ZGRmEgJFwSkhtAojbYKv6sA9YpDNiQh4BiypGmVTxYsEL47wWnkeIYpGHYyHQ75ORftRtDKMZQ5e/KFfDrHMKiBokAfH8f9ffkZEDCnLFk2Mqc19X3NcXzt8+qm9/+tLz+YTF9ddx4q2PkO2hno61xa0MmN9SHML2hqf9ZNa9Y82f/d0NvzBL71y5D77K79Buy+D62+5+oFjL/zeHY83Ko1e4sySHxnOsObTXDlJqk3lCFFEa+0xTB2VWKcZPOYsjtGLImKsciSkbCK57dleli3m3nvSSPtWeZLRbTP54YtS161pI1rGRtR0q8uq6ZhQsePk5NnuRcZnOdeMUgha606n8+gjj1fiZKi6+uTZY7e/bfOui/UjP8wP7I3bHTTRzHIgATM2Nj40srB+3SZEZLFEFUH03hljEFTu3WKnO7Vu00W7rj925LmRNUPPPLTnYx/9cnJee6y+Y6E1P1SrOJziyulqY0Pe/dY73/FLj+559NiJM8dOHM27CxPjazoZZZAbJOC6h7QQNQx8XwAAUERFSVpOFijEWgne8oEDLEFqcVDsakSlkFc8eg7UpvCZK4SIhCUsV/FFCFNIDOKcQwEABlIDVjERGVJOnAxmqwL8fGLPYF0NXkqHzjGwLyQnUWkFEET2STB8DoR5kEiGLCAKMRxBDgFAfAl4ZoRwUoMKMThU2MC6NJNg5vI2sgiz5wHUC4QEnMvKpKRsaYKE7S3iy/Z+ee4TishAkZuIio50SZWhsg8vhB5EWDJd/KJEdE95RgDnzzy8Z8sNl+ep/uq37/j+8SfTSq0SjyWqppPEc2/R079h+jQmv7i4VFlvSGH/p19Y+ubd2F1sIp1tNi03tIU9W69/4FW/e3rD7tVHH33tR9+88anvDsVxN1JTEO+DPPGykKpXfHnb1tHoHTs3WUo3zD8ISRU4taAZQStHxOIRIea43k9G47zlUAOA6EQAHBhHSVcPz1U2Fw/y2fKJFneFByBwBQ5EpXlktTw3J8Oj5ouf+ebZs8fHm5M5m8rLIgu96KdxnudRFEVRhCLOBYKZsPN5P5+amrriquvSDBGR2QU2B3JY/xSAL4iC2oR8KHxx0ZMAQCgCd1hv+kzePNBbP2Hah47io/bC73VuWrduy02XqC3jm46e3Ds+ud21RYhQabQZcOZFR0ksIi4YyKMCRS7NAIFIhsfqo2NDSmh9e+P6uemJqYkho7959+PWZlFijFIsPnMZIwHns7WjFy29pDq6cc+d/3X2o39anTtjbnxRZ+flX/mD9/3Ob7y7umaqGccxRYioHXvxWmvHnkHq9Xq32wWASqWS2bw5MszMoCjPbFhSkSqcueI4jiOTpj2tUSmV9q33nowW7xklqVbSXj/rp8LS7fd9A8jo3FrwhFo5CdRDydN+pHQoagvoIKEScuwciEYCgUyYFIl1ufiKSdgzBZNUxCiK8jxnhchCiKR07h0qxZ4JKNJKKeWyHJQiIO88EUVR7L2PlHZlTWmtDQvIWiuCkTaI6JxD5MAER0UkBITgJRDACql34eUmXnmQBa2SsO0HlHBgJiJZVhPAMKgIVB8qZAS8wPNK0sCnKMrSwKpg8d6HgL3SvLw4C4wCB+XhgkUO55nFBz8aH/w8AhAWCn6LrOSNlC9WHEkCJjcqrsa1B7797e9//alHai8isEimqXsdx0K6qepeZ2dsKpZj8WK9oIAyG8yzbxx78H1H3gkb1enZxoc+1Llg1B9r1Vy8sTa+uX/4Tr/Yjs480h+5TXy/4fqOI0sZiu4rYPFKRAOCc95ZsD4XtM5q7zVznqfz6MQ5lTqKclJRc6SqVQUh9rMTs4zdHW19zA7FVUx9irLYY6UqEIFyQuR1VD15boE8A2kiJJMyxvOzixs3nLe0ND939tQb3r5peEL95Yce8Xlcr1f6qa3UK4PbsnHTuvEpGB69cM+TJ1/3OqU1iXilIg/YTftaxToy1npE2H31i7906NENeuy5h5/93hUfv+kXL2ydma1WKk07ssh28axRGQC4NTsuPX5m7qk9eyqV2ite88pVGzedmUkrlUqW9xMDzDQovAq0HoBlDygrH/8gmUMiYBGSYJEqyxoUOBisKkQfUFBQWAAh0UA4I5CXLDAiBnAyEmmtGcF6F7qsIt5DAA+HI2Fw/iKUFaeUk46iXYRChCAUgpMvS8wBApHACZIHVqEY9QVQUKTwnw+nrVYoJRIaRdwKfBpw0UMGAEVYrO3CxBA1FmWqBywmw8WsV6M8r1+/Mtkl4YIVzTywhAr/3WhFgIGnx8wKKVI6pN0+/LkiLA0NHQDlDKAjpU3OUaMyt/8o9/ocRZ+742t3HzhcGdmwJvImwVRlxB6FjVGA9Gg6cSha+sXuEpJGHI05VyPjS33Lvey5y2++9yXvn1l7wfpDP37dv75hzdN3J8TAmOcq1nZ7Hh2sR+uG+WQ7IuK+tV1vTZyxQ/ZQ9ejjvudIZYnR5LDnNHcqDQASNAQQ9ebypOlNHdgb7hvJx058a6yS6WpNCx3CS9qja1OuE1gAZtBhqgCARpGAWBat8PTs0n/8x78ntZoX8Yz2upQOKDiNxsR5bp3Lgx+dsGPh0dHxzmKnVqvVG8Mnz+Wmqm2eGWPCSUslrLAwu2RXrDEuOj2hxaeC4sPAVmQxNX/x7AvE16v1VRXHGtSmbfGVl18mbnGq0SQvoNh4Yg+kyXjjyqF9AWS1BQGZVMj8mIh87pMkWbtq9fD48PF9j0+fXZjcsn6pO505VU2aXqNJpDm0ZqZ2pvkA3P8/X8NPPjc+RCnAxT/7F489fXR1LNe+4PrMVKxLhakvXLPSR9aESCgizrlQ+Xlh0Mp7L5o8c0TECBbF51msY6XAMwt7ZrCWnTAQehBjTG4dIoYOQ4lpUs4xkOjIMAiDKKW0IkbQSCgAnpkhMZFzDsNHK0MayYsAREnMzBrQSuDsonOMSgVlDK21BQCF4tg5BiREZaJInEcQ8KyI2DrSChFJyPsC2GJQ+VIZIGAoSJFSBliYoYTesNYqd560UkoxMbCgVuiEy1gZsCqEZEghCCFqHTG7AjHvHCIWhhOEpEhr7XK73CfR2jmG0uYFyyMMsRwpESIoEV92Wgop+2D5IstHCYYJdHC8GLSsQ1aPPhRQoVcZFq8MypL/dgA5z6DY9tPKaGTblQ//1yemf/DNpfU/r/V402V709z10vVJI1X93CsEiaxXrFLb5UizS8W5P9h614l89LPT1zEqGs6RayfdJIyboWoK3srErkY20zt718iWF4BEuVE96lW91kxWS+5cFZRWyhrF4rX1oh3nuQVvwUeRaqooSRIHyHnixVmf9SVjblMX8MyE37Bf8qsiRskyTuJcDIvqtvvYT5NmXeu8Y3NFRqjjnAKXVYdqDz300ImTB4dq+oW3DKNuffhvjtQr66pNlfWXbn/DlS+6+YWDm5OnmlCfnn3uxKl7HnvspouuuHKx1Q+bNIoiAXLOVeq1c2c7rhKvXrVu37NHr/7Fm17+q7uP7T2VjI9Gw7TIqcWWdIeffPB7wyOrP/7hP1voz5+3bdveZ555w5tej4aVtypPwGjrWwSVQXD1wgFMR4jiPAZbAi7Q8uI8M6OERR5GujgA8YVqDQAEmFBJwP+VJFsW4WAJXGCYAitJEFCY2fnUWtAqRMGy7EMszLvYgwgJFR6qBIP0FILZiZCIL22IJFRLCgdhOySpodEHRkko6EuFLxEhZlHE3guLYw8sXPiKkvKMGDA4gIXGBhY9ZQy6ICCegVkRIaB3jpQJH84l0UBEYm0AgPF5u0YpQ1J0qkIdhjrQBooLc4V5GYY6gZd/CIfLQ0VBwUZbj0JdA7mBeNEmqnb8oaeyfv9z93zpyyceXbtuHUsHSWVqRFzUpl7MaK3Vikb7rU5c/zi10OdRRWzVZD3/4NVv+MmLfnNhctuWZ79303/9xobjT0SSLXlE0an3JBDFuI51BWF9Mz/R1h6yjjTmWG23cRrHfclZIib0IoQpERIyWVXrtkRYuQwicHHT5EteV4CU2Cy3nWF7zk8fPnbsaK9r1Wv/MuW6wp6IElFhqgYIiMoLIkpEqAiaceXg0b0gIyAGVG6vS6MHEmZwLhcE0sYLsHNRFLk8ZWZr/a233gpCXkDyvBJp61xRD7BHDPIYKjDWEFdQA6QwDwm+bYMjVA8P13Zun8jmahUVb9zaeMFVl+5Yvf7gmYVVk/muCyfnpjtxFKdoIUIizc4GxTeFFPy3iZQPPQ3HHhRahhgw0tqRVT4Zgj0//un8f3y1+Uu/bRoTzYrpKYkWZ1vnZg4/d499cRZ/5N+Hn66o4alzS8cm3/A78SWX5F/5zC++9CqOvO/2IkicFkEnisgzW4daGaXD2JKI2LMm8MxoRSNaFkSMFCGhBYcCPs214igkIDZmn7IX63yBzkViZ4VEQMBbAu8FAUCTUpqKyQoIEgYCByjIvSNF1lqFSAJggYwJAEtEYgWG0YP4IH3HXmEoKplElFJeA7PHgi8PXAJRCvcU7wFA2BORX2HvOMh5vTAoQmECYJJAEgQm8QyeCVG8K1CeAqENoIBEAHyhhCfOe2ZQKldOYXHEBGdTrY0HdM6JsOPg5oTBrwYRAZiCnh4QIlpg7cijhAIYAFBASZkhASoyIgLAhpQHGXQpFSAw+zTXWhOAE1ZKMUMBuwZBBBGGclYcJnBYgloFGBGd8wYlRxqZqB/cd/hTH/mYas28872/+CvfWbvYbbf62Rt39W/dver3vnLc+mZV5S4XwlpPlmoqTq3PBXZXTr9h5OH3HH9XW1CRR/AaxZtMAfT72phKDFP+kvfaH72fD3w5u+TX1dIMVb32NeSMbIRRz6GpovF2KWWTKAXsqkoJJt5LxNjPsl6aS7ePEQE6QVsZGvKWuF9RxzbgtjONqOd1QyqT0Gl307lGhNdvGn/h5bt3rGMLtXUbh3ptiVkk8t2sOYGwZkh1u6dHR0dXr6t8/pNnk2TI+kWXm3f/5oVpuvh3f/2lQQCemtxw8uTJStJQcY/cJ/7+yisXLXvjFJAGw04sZwBmYe5cRZnrbrz9kYnvvfhXLjt69DCMj1ZUP++YaCOcO7h4z78/d+mF2+984PuTtY2ve/W7k1VrNozdef01LzjVyiBWWoCAxcdaIQcNJkQFy21iBGIAAfRSQEAZgUmQmYg8gGc/CCQEKMIBpS8iRKJRIyCzY2BFugCvMIaWDwmgUR4YQICQEZiFPDtwUWyEhdkDBwEPUUSktQcSTYBomb2IQlECCODQF0W1EKIwAbEwM3hgM8jOCxlaIsl8rpRmZuHgpCseipGQ1grYD05YEUQgRiZCEfCeQST4JYP3SkhYMExhESnSZdMYnMuJabBBmEEEXAH2LmbOjEJEqCR3XgEpQDK6iKyh0y1YRHABCHLBiICkBMhoxAJcVqS4zITojYoIMcu4EWepHHr8yUf3PnRvvzNZX0c2hkrNRRHlvg8d4kjYp5BdOZSdv+mchuhHWfIM6hlfOX7V2++64ReWRtZuf/yO13/mZyaPPjfr+garuUVEcVpAKFNArEbVUrWLa+v5PSdrGtD3cKnT8WNDPu15VXWEHkgZFJv3M1FxRBGatD2xeGC6sd3YnjU11mMkjgGdbiSnHz/w9BNtWk3Vi6oXXNkbvTTqzfp+S0bWFwKcAUEnoFHqRpDgutXw1bu+tOUlt5749v0sPdqgZaenv4ssOIUSY+SZWAA1pz5PKO4L99OZF77kZo4x1hYi1XdOFQu+KHDFIyISautzKl+hX4KOAyYwpHQFCnpqbOh3b7912J2HRrMl23MZZwvTpzetG8kycMLOWVGIgnlmCVAcEIla2WAUQERLDNooFCYUxwZUrDSnfOS+h8aO3J/+4R6Oaiea0HeAC21yrVM3IABMntviosQunaquPn/qHT8z38o3nJqPx7ukta5om3MfXVUw18oQ5t5BqaMWCq9y5DlYll6ESRQgKqWdy1VkAAqdMA9CRChMZWOMiEyUABSAXu8YIw0A3kuoXEVEvA84KCn8laGsRHXIOoOqInCJLEJQAqhUARv27L0HEQcSlV6BoSOkkUiWM/HyJxSPh6R8eCv8JjWqcr+IiICiQWc2FJdYAmEGdYDWKkgAlOdIAG4EIAhj8BUPyBcQRGWM4QJoXaA5wqfpyKBjh8EELfCyUUCc8+GXUvE1hAiaFCF5b5fjbukHF27p4GqLmlgKxV1g/9++uhDfCO1xERHQRmcur9eHtJGvfP6O733nrjVDE7/9v/7HPc/ggVPtW65pvnKb31Ad3bJ+6LJVeO8xATIQ237KibKLYAmkkpsPrPvc4Wzyv05fN1Sv2l5OjhyKAyb2gsQV0yU1NPN4fMMfL/zgd8c3v6Cttuos7auONlEt4kwQUVLJ+5mrOBRQLNTnqsuWjOaco6hCBnPdHPZa56pX96N5mnpDkZPuoTXyyh+hmewt9jGf3zYV33jTtqsvXT0x1Eg7rqXAZbgwnS5tbxtGboNqz/LqsUozHm5sYV4crl/1O7/9nt/5wK+PT46+4xcnDx/Z983PZ0PN0UEAZv/MYruzZvXVaRrfdecP3vTmh6669uq5Vkdh3O2nUUTIpIBaS2dMdfjS3RfkNxxfPNOqueZoI2lsrFAUH5058KU/ePiiaNuoZBvWb3zL635heNfmtPHE+172e0ml2WrnFdIA3SzjSEeDQSMEqJR1IsIFwApDYF6erhaIpv+uMyUicRQx80C+eLAGBtM7IsISCYwlDjEsf2NMoAMVjevw7aCQMHTFnfeiVMlQAhUETYXBM0UKoLhUKobTAABCZU/o+XuTBAqgImIIn0FGJhghAwIRsQ5ZdcGVXwmZHvwu7wYmp6C1RtRECokcOyiRaGEGRCTOOa0Ulx2t5c4BMxba2FyeP+F4sbJiaoPLICCPqIsRwIr3A4BVkDDlzA5xNI5PPfzY/Xd+6xHfiuoj1vWQtNHa2gwyBSQM3dGEP3jZwfOGMwBA4ctN8r7G8Eff/R+mcdUlT3318o/8Te3MnmELogmhmlqCxFvXa+TcYSBOG8noEKoKdNbV85n2EGqx/exsp6N4BCFR3jtBj8JWovLpsPWRMptPfb113nsxnY98z6uIfC5su/X1vOpSfMH6mjA3JrLqRKVzavWZJ2ZWXyB2sYcVjhoKPBEZgpFYtJZhQy87j9/0/v/TjWvX/vrP/viv/g6vqwNAfk+/Kk0L3EULwEqMZlWPEwST5/n6NevWrds0v5ARKvaQRBXxYThIxaMp9WQCXGnwfElrrRUgIiEQYjmd0SLUWlImhsz162Qksnf96LmZU89csPPqzPnAWkEZoOlAmWXG4aA3KMCAyOzCQY4CXpzSujU923vkie0bLm+dm0l8W9KsxjXWsYrWH97RBzi5+kBf6dacru3+w48oSJyec/2ZyvatppG0TncSlQxp7bJcEQmJDoP3MEFRiogCnplBQCQ4gEqJxbV5jsJRNen1U+c9gxBRlmW9TteQyiUPqocSOkUIxkTBG5RIswtSX8jsENFbF0YmQQFAEcVxTAJF2837cPeLQIUldacsBQKJT2tCRYVsRaAAInrmcEaEKlMKU0kYBCERQS47UQNWRtmbEpEAkaeVUnnP31ch71Xl57tiYCsoAenEufMAQEYTomOnWSlERSqsHhFBpUABK1VUwgLI4lGUUEBeBtoElFiS4DVtbVY0XkqkZbDpcMJCEpALIoIUOg2hmyeolXDh80pl1RvOEe99HMd5nvd6vWazOT+z9MlP/euZU2de+pIXv/xlLx2q6Y/881PKNH/xonhkcmrv3mPjI41uKj3jJnS1l/sRSNN+NdFd9uri2p7bhh79lSPvUXFitAbviCoMngg0kxWxDmo737Pw+F+en9j0gpsXnviiesEfqiWlISIVpb5d1cMCtk8Zo9aK+5Y9+ApYGysHukpgnfRVovoZeKlA3qJTFY5Q+1xJ4+SuxdGvz/LZa7euev1123dsHrGSLHbx1OmeUT1xUb0WpX1OF1HXGx6sjlCh2XvgXKXWqFf1qtUXnjreQoKbX6U67fg7X4zHx4ec7w525eJiUkmaJ0/v0waTKn/6s5+79rqr2XLGvaQae6cAIFbQWsxgurdn7N6J9RXOZO21WxfOHf30b96/NC2L5w5f0V47vqn6/eMn3/OBPxyNG9FWm6wb3jl0bbudRRQJa48dodi63GAEAyowIRECFqwjZBJCED8YJEDpOT8Y9xYLWxUiaPj/Q9Qjoi/3LyEEgFZYiAopVMZChEgcCHISZqsiFBqCGASKwDsRKRxKVChniRAYimga+AUCQdKNmDCM8hAHCGQPQDFFzA5UsSyRQ2YujOGADKdx2KniBfSKBFpKgLdSihEYiwGwEAohIwgAahV0C8MdCIyGIrVfTkQQQAoCQpnHYIkkX7npBn/inHMlJMUJh140lGluOHYsOy1GCCXv/+gjH3967sT82qnY5hqH4wrmPkr7adVkNlXVCv7RNYe21PKaySlpfq3x3s/Ubuksvfe83r07P/6hm6f3n0wXDTsGgljFrBTOZ6l4hHR0e37ZCz1kjYfuGRG3Aer1SA4tRXGfMsye7S9d4SwkemwxXTRh0OY8oTYaBLxnTVSxc1fu+fDeda+YH9+lfcbCzblnhpaOnlr7Aq0TRmJT1Xlb2d788JbVJ37cmri439ysOG8mpJXUtSiCHaP2tRfpM888cOCh5zIj509uuObtb/vB5Z+lA2p8aawLXXA+iSpOWzReoWZIgKWi+abrrt2y9bzjs1mMRrFLu2kUhw4lAwAUAgcQ8qOQMiJiAZQJOs3hVFcEiERKt5Y6R45PV0bW9F3n8VOnH3r4EPf6n/7nt0FSm13oeOEojiR3SmvLXhktIhjqMAABLtVVJSGdeyYBUAQKLftmPTly+KQ9O51POYJM5XEXvFNsqBIpNb32ZG1aNX3lVGdm14f+X3/1hWNRJ7IEkMUbN2Q9AC9WOWQQRVrQr1jBIQDDAL4RiLAAFCR4WJDAqEhr6vf7kY7YCRF1l9qXXnzJ+PhogCFAMM9RUQiWYed7ZqUKfQDvPRCZsl4OyItC2gmWufBO2KBazkUGSb3n4H9RxEUoZjnh+YSzoARqDCrDkPPqEJ5DJQElTCPsq4AiCQHMlfNmIWLhUFIEtmXRoi8D+SBhAgBRgQmJyMJF8gxGBBWhIHsO25ZLrZZiw3tGBtQ4qGcY/ADbWfR3gti4BKzrsiV7iQxEVagxFPdkoJOFSN7bcM20wl0k3OQASo+iyFqrlKrX6/v37/+3D38UYv+mt7zpkot3N8bwjq8+tzetbRrTo8NTszP9WlVZNVttkD4O/aFOimzZqHhe5RXW9ncnvnQwXf1f3RsMiLUWCDVpE1p3hASY2owiU735j/c/fQec3BtBJzn8IK+5HEwOidb9qjHK93PlolRjmndiT058u9dTBDHpLM10HDWxgqhcNQZoJWpVSqIRWPXTpyYA4Fd+Q99avzrt947P9DSKJmtqZPVwgxIN/fmF/PjBsxdfFaUtzl1OUFvqdKemkiy13//h90+dnLnm6u0bN/DnP3F2fLLufM+56uApDw03TIyCabslQ8ND3/jmnZf+2+Xv+aV3nD0naT+lZIlsLBYWFhYPzz1y0bZKNRsb3pl84+Pfv+PvHuSe+Hzx2mtvWXfJ1r/99Ic/9DcfvmDNptOnexCdGPNbfbdqOWXjAA2qRHFktGePAEqAiUiVcPcy3HIYu+EgsiKEVuygsizuOVKBvS/Nfwbxpli3/w3NF5raRYtq+aPCFsBlUa2SRMusSu02KWpEDwAKB4WLACGzIEMQNx+UqkVNWZjeo8+9FyZmUFSwB1EJB0TZisinlqtPKWETgzvDzICiNGnQyz9KJGwHUIi+QE5BWQeHPv9yMA6nEGKARSIisgQzAimFa1Ag9y58ZgjAWuvM2YDUGRwpxS91zEZhZpuj1ZM/efxbd941O1XVnpCsMj73SSpLWoPLVLMa37SmtbmaDpl8ZuiSX5u6DwAuav9zJ3/2za0/fnSouXh2VS1SNl3ICbm75EV14lF93Qvg+lfhpS8YG2t2nvhR/8GHK9HcxfXTAHCkNzQbQaS6c/P6yPGFizevPxdl5JwmUEjM3rEgCiJa4FiUuOlL9/8HHWz04rpyC1bggSv/IOrN5rVJAEBvmUxWmaDuTBolFz725/e+5D9vGV9494snZxdtN5VGnKGYtZP0rY/9OAM/Ob7h+1/+6q2/8e7kNc3sm+3mxMjskcVEx5VE9bJMrBIQhlTXajNnjm3avEEUWgdxTGzZmKgEWyGDrORMki76gkQacfkRe2ZmRxQiKepz062//O6na3xvxEPa8FBTv/sNV1LDnD3V0pVYoYayuoqNZpBBG6TM9MK0g733KEETFYghY44NnD58rOKMn++aWBTpGlYiVuz8Qjrfvmho7Gx6eOng1vf+df2VL9ezs/PnsmQobrUWJtZuTftc8ShOnGblVUZOE7LIIHFzzoXTnJkJCUihALMbLHp03Ov3TKRDVAtz6/GxsdmZmQsv3NXPszRNk6QKngOtzoeeNgXYVAG7MNrYLA3B3uZWStKOZW9IgaJwXmBJZwxJUBCmGYAni8PIMylFZcwOMTJYmYRrZmZxnpE9oAc0Ax4tlFNdEfAsZVYLYXIlIrTMKpMSdkHyvFMscP60Li0QAAjAsgWAKIp4hdIyEoj4Qb4cmnuIofRACiRGQkACCQiS8oZjIVfLwTbO+xC/B6lAsdWFTKm9F65WqQKzAOVNGxypIR7neR66HY1qDQC+c/e3P/vZz16w87y3/+K7psYme10LafvLD843J9dz71RLxjrOekOVOEk7tG407sk8WFORc303rpS7Inri1uYjv3D0fQwVJ1YxcoTIXjIG1h5QNAJnaSoM7colbwOpdp77q2E82VE3TR87R7V4cuOqKKPFvJ0ZrmTgxWWZreU21sKgFzu9ofGhjKmVYxSjhy7Fq+MMDWUGoqUl+Z1XX/o3Pu5sPDv7ZJcE6lFDNImP2EsS6Yee/uld950+8Gzv5hsmv3LT9iXMvXEpwdmzZ5e6x9esGXrisX1XXjMxNjKcJNPrNmenj9dq1aEt29cPVsXR40+JrSql4grUqs1NG5MjR/btf/ZkfbRaqzX7/Wa1lnc7pxfOPLv2mjW2ayvbss997L67/ubRNaOTad0B1p/Z88ShE/saZqjb7i0KS3NRN9Nxe1G1odtIohjYKW+896wZSBc90CDrP7DhVEoIMUSjwQZBAK2ozK7CE0dBZqGyrl1Z+4Z0n0gH2Y6Vf0UlNj7EkpCcFfO254t1hP/pXWkAh+TDBmdkZFYCAApBQMLIlIUVFF6EEK6OWQTCzEiIwnL13rP4SGlRAY0cIN3l3hQQBCqHZYPNOLhCEQmpx2DnlhERADjkLd57sA6MVkp5EYLl0ZIsI28RkdSA71Ww/4vNSOVRg4ha6yiK8nz5kBzcUgYhBvDg0GsFT3/vJ0/4lKNhXGpjpVqtYcoxco65U5Iozq+eaCOgqtbPg/3XpHc/EN/yUPUVx7PP/NOmP5oY7p1YdfDGYw/Vjz6m8hatvUZfcwve9MKhVVtdFFc57y62cx+TY5be1mYE0N1wcnGs1Z2r6MeMevjMyQ1TQ6ri8gxQMEli59gLg5dAxQTrGAAjFdkedJe8gXMTV3BA/rnMpItRupjVJ71ORJn20I72+usZtY5dd8lN1vKuEkAGsLJI//rvHzVVba019ep37vj3/B+yXf4Fz+79KVQNVXW32ybSmrSIeOXytFuN9Stec9tix6EC63MFIOAL40kp+w3locgF4p28L/A0A6wMSiF3LyC6WjNrVq0xMh4xDg2PSZ7u2DqVp4Ziw8yxiZxzTjhS2lpLRITIUrRAQ+0SIrEDV4yBHEdhyOKgdewk4YKRDR3IWaUOkBUqYIXx9JqF4b121ZW3117z8wv7jwwliWkm7YV82+WXVLdtXWrZmlYIynj2WjvOxEJYRmH1rEwYmTlQaJYbuQKMEBkDIq3WvFaxMbVuv4+kp6amnGMQNCaWICnDjFDQHlCR9z6JYuasVGqlwXqlku0Qgx6wdwYpdtEpBVaDAFluvOD0OUhgKeTdAUIlxWGhEERhoQkVZjahKB/ANQGlnMg6WW4xIaKUYgVSNLEJEBkL0vfgOIMVL0YILXceTMTLBhwzMAJqpZQipYKRS2gAsGMQAgVBgd+DGKUGtx0LorBY55x3vqQgSzk7BwBEYMDBoTBoXCtNUOob4IDDzhzAtApxbLR+4sT0Jz/5ycNHDr3q1a985e23gkraS73x4cb+Z/c9MOPWboI0jTYPNboAdz87fbx14qET+fAQJVmdpP+377zw1/7v00vV5AOTX96frfly+3rTz1ysSJAJmV3R0UckQKVUVVTXKz9zanjny9LuwZa/dFPr0Pt/7wLfz373k08tVlY3K1q63X4fwcZa0SJ0X3795U/tPcmilVLAijGJvGWjoe+UEnSxMj0r0dmlyrr+eUeTZ6BGOXrPDFa0z2KtXY+vvuiKG6+UA8c7H/vEffc+cvya89YttZpzra5kenR0pDnWveyCl8TmlK7u+cG30vO37zh84IB15tln5gZP1jldqRgltajaSXvnzkyfcVdc0sv6s0dm643RdWtXf/POz77vvb+5buO6//mP723xGYLKd//9odG165LJ5vQzzzQb4yhgOyQ223LNkU7rwihpaFL1ZGIx62U2TZKE2ApLoiMbBKaBB60OLi2BhYuGHDOHsDqYzsJyHxVWZGbFYGbwQ8ot7gEK1SdYFvaTQko3jgY65FKQ18M4A/D5UlseJOShAICoNJV2TLKcpyJiGGUBYUhhRQQch8FTETUVhrJVSWGkyz74/vnBrysqIQEQLsfhVIhpURFo1YqBGqxIOABQhAr37qCmTkVx78EzS+Cf04C/hEIrJDMH29kNwnyZ/YT7bOKIA7F1BZcJWEgryZ2uaO707nnske7YSC1HRRzHdeTESeZ9DC7auFmmJl0EbQe8r3rDi/Kvv+3Ye99hF4+MrvufamZz/9HZsdsOv/w1e1UMAEMzR9YOx2u2rGm0Z1QPGn4+tTM9bGIUS6wrqR0fUpmFDe0zqzfXH5jOHsuWTi6pR6Znb9o+6RLvM8fMpBWVjQ0EAEUVItRKDMYpZeJzjDBIXYNUXJcUOrEeYg+o0Bxce6v2C188Mp/a/LYLxqZGGu18adNE4zMf/9ixYydGR6ayfjfGOH8RAGRDx9bf8oErH/r4p3oz57A2zGC8WIxUHaOZ1txtt7zssqtvPHB6KYmrWd5HVMwu8MJ5hZt1CLYFFl2W5ymB0S4rngsAaKMVuzxPq9WGcoszt730wmuv23TiRKpiFZPO+ykRRUmcOSvCpWA5kwymyBQE5zDS4BCKrimSRgaoGCO66pp5nvbqPGSMoMqdRJXh2tyaU+ueWrvuA3/Xa814M3yme3a0siVbenZiZCiPSYG0IQVdqYnui8SCmbOFLzcXqi4IaIVJwK7oQdFAZwQR2API6Oholro89/Vm83Of/+LNr7iNNBGRMlo8O+EiNxGx3iEXgAWNJCgBAxwQazqOEJGl+MeV85UVLQEImo5Qas0P3sNKPIjzToEqH0A48kHEI0sIrxiSXBDPrLUOirclgKJIAix7Cc2NUDIAIBWqGlKC1JYj2Yp5asgSvDAiDq4wfLghhcWwDaH0Cl15DjIhhVG/CHpkZCNQpgTBkVdCp5DFO2+VVoUQPLNjpjLPgODmG44QwBV9cmTxxKjK7KHoEwACQBzH99//yL9+9F+SJPnlX/7lSy65JPPO9yygalTh0989i9VVztpurr/61Pxzp1ufu3dh9fjwZHOK1Fw7kfnTnYqe+sNfiT/9r5+4ufbYe07/ntF1SVhl4k1HMbInRlFEhtAyi9F9oxz0arXk3KIb2fzmP33rhre+dXdGonx88yWTL/ngvUemJybrta50CebbYAxE37j7KYqgUktmuh7QVSs2d8YjqKpC7y23YxlZNdL5wg/273rHtlOj+1NLlahaQQvGUdLIbO4hn+1wtRVvW1/5i9+9ffbcdLYt5wTrpjY2Hs/9JN5xwQ4anlk4N9FaGKqOwPTZ9Pxd1Yfv6zSHaoPntXbt2sm1tto8t3ZDY9OW6rfvkvvvfe5Nb5R6bWxu5thC66Fjh2fSfnby7MzXvnjHTbdf86PPPhvR6HnrLxufaq4Z2XJw78OLrbSB3Y0vnhy9XLcef4ZWmbH6RkJyFuKoKplnBMeWLAspQY/FhlxW/wZBJyDsJZgSBcqZ50BRHRxTEGi4hZtW2FDLUXmQ2gIEJVReqQblvS8WklZhOxtjvPfAg4CqgqxVaBRprZm4UJPm4t8liOaXHSYM5oQQmMOh3HQrN7KI2NC7BiSFipR3hS7sYOsN3gkQuA5QZgYFfjm8IXgGS7kBg0oDlN4PiMTgBzvUOadMWQ+U/psEWNgdP0+Pvfj28gaGoVHA6LL3nsoe9eBqC+cV1IgSRdHJfUfuPXSgaip51qvEEcTk8o6mqlAvx3ius/jCF9f8KepCbSMfPKx2bjb7IRLy+xoob/YfPoQH/33xzZd/+4cbsHNk4qLZq19z8CTnMgEAQ9gYw5GxWI8lZqQ2NpodGhvOzy6qE2OVyrUbs4dm4wOtNq06eDzdMC6jwwY9Z87GsUGtFLP3jhShSCk3T4xic2/mj/r1QrbndaVTGVc+86ZOwgZc4ttnRy8He6wJ/p5jh7TK3rZ7q4HMZfyFL30Cpdpj50k5Ar6+j/vpgb/59K4bb7z5t371wMOP7bvrnpRTYV3t+8Woj9698fVvyQCElet2K7VEPHqfB54RkPIhwyozHo1GCktsUIEvioOUrGg3AoDu9PyQS5q0KDJaiWove9numQUVI9vQ5iVSWmfeIZFOtHbCxRG9fDSHUQR5DvJoihQzeEKvYGzNBFuswaSzx7t2LgMzDLEXzmp6aZ1s3/K6Xlu5NDfaGqg1FB08c+KGW3fnOassr5H0QUBjzIrTNmkTVmpYuKG5FGvj2SkoNqFzxZyGiKx3SMgsSsQYg4py56fWren2eohAuihTkySBpYImEcJZFEXW5rGKStw/DYJ6GMaEs2OAUQpSFYNiN4xboKxEi6wfMHyj+OLuM7MBo7RmBCm+HZRShAGdBADgg/cpLmf9EP5WWBAYi5Ml7ECAokMwCL2DlAAgzOqxUP0Lp1gQ9IFCwCio4oFIKKYH8T7IWBKiE1ZBGMKxiCALAhqkAJAREfEMCIo0lvNuo3HAREatAjzNQ5HBBLonaVUi8tl7zx7KOXHxiqKk3+9++ctf/ta3vrXrgp3vfOc7x8ZGlpZaGmIFgkbNTh//3qF4dGw89UvVav3/fvX0ptHsjg/s/MJ3j33zWTs6VGfpgG786JnDr7h049deeO+hmQ2fOLrT1BdAUaVOZEl7hWK6kgNxrLXNMAcTI4xH8cLp9Io105/725eOTm48PtNSjA781Pjmn/5j7RXv/fyzixsqtV6KtaQf6cSNVOoZpRn6WCoOrUdnAKtQSYUy0xt24/M6rziD1fHpx0Zmbvvuhokq98VmkAp64arBkajCcZNhYX4GUtVSYk7P51PDkeT89rfd/uBDj9z59R814njbeeefPjI0urojurVuYuT0hr5IfzkAb98/MhYvzft9T50YHW288XWvWJy+AUlMhDu27/qTP/nHz/7nV8bGx/u9/DuffPKHX3q43cJmvVYfjXpRtPP8y5pT6+696zMLrezXfv6WhgzJtuPe2BF7ixCKjYAcKMoAQGv2pAZ6igKIqJEUBoGJMPElAA5mHiXQBxwVtWxxehSgCAzDHR+CXjmw1FoDaGY3yHCL5c0SR5GU415ewZVHVLCcEAtyAaQI2i9BtHXQKA5OHggoAhyIxgBQ9g8BAFGt8HIFREUK2XnPToAUkrWWmY0xoGhg51VUOaHFXP7SMvQWbYDcu0HraEW8JE9Q8kRLvLSIcy6w5wnJi4grQBVIwP55A+agxYFKmwLLtox6K0hT3gfJLY2l7IlSWmtmQIJaVX3xJ49ML3RGGkmVFFSqFtBwDZiBQEXR0WONB+9p73zLmiNzu290n5jG8ZrxAGiV9iQWa3e4N8/Xts1vOv3SO/9u2/wn23u/Pvn7f3XMDJ/Oo/nFpRkz/lS/mZlR+IMf1lund7jHp3qPnVu7d+upoxsrC1ubuMf50+3Fxw/l1+7enBA4xwYBmQkAnNdGxZ4ycMTgnSz1+1nfxfPP6k0nXWMNYeSTBiiD4ivZgiGqddowwU7S3LUorn/niF1fnb39xlX7n3v6iaeOXHLJ1sf3HmxGNcn6vZv8+iMbe/Xu/vsePvHUvktufemrPvj+E0893T15stvt5g5v2rXz+utuml9gQ3Gi0DqnKDFKY6lqHAQ4PLMq0qbA/ggMNB+m/oiAWqGiILsvIlppAMqHh3zN6ze8ZseGtcNnTvaSKiqvGAEUevEoxY7xhAzBgQ6wrKMFhQWhwEYZBOXFK2bJuL7zAjFRmp5Nosain4trzTQTSdoLekYUrB69MT02HderHp0ovdjvbxgZHt9xUW+hL7HqojZEIMS+j0kFQraLmIdkUGtAYhYmEg1KKxEZiJGEeECAyMQKc5cpVem0W/32UiCyO+eSJLLMzuVh2wTPAGRhcMDixIXJqFKkSC1TaFwRb9I0LQSfnQv3wZBi7zPnoyiKTCETT0guwClRitrds0ZiLMbYUIRADDuUkX2g5hHCwHpICgloRPQKlaiydQYSRHxETJis8QCVVmQDIboiQgBX+1KyRweg2eBQIwIvSGQAPEPY3lSk5QKKjBeHwfQNCEALeiQBYLZUdJ5DGibeM6ESAO8CO1nQKELFzjvnUCsVmXDUsnfhsSqtGQkEdWzEee+cACBhUq105uf+5V/+5cCBA29885te+tJbQLDbyeKo7kEW8s628bHvfGvuMMimarvRs/MdvnJL/bdfVDOsd22Lvv5UB53rOzXUUP/03dlHv3/Xdy/+8dIL/vPPLtyVtdv/9JVzbqRiEsasB5hQFFEvMzW9qmpPzSo1lp893X/7JdHf/fmrumrqyMlerWZy9BWgM2lrJBn5+j+84bqf/8y07AY+oQQhp3m1BEZVsMnQRk1aJeIwxTxGU8PhHNMqIGiTRHpuz5be6zq/f/fX5PSqmZY723HU5loz3jSkkgZetHnkxiuHN1TWnumm02daqybXzM9n69dteN9v/+wXvjC9eDaePpEawuPP0tTq9ds2+be/u7nYXhgE4LPTs2vG1l510XjUsPuOyOPP1l98/QX3fPfrm7adv5T3b3nNax564CcHDpxpjA3VSXf7SWPCpd3Ouen5DZsai/PTazevGWmMX/jqkStft+XImfYUrd8gL63j9sx3SLEggoABAB9Ad8B+uf7zII69FOJKroiOwgLAVEh5F5ZEUACFBrriTpiCBEZo6SiNQemCrQqDWS6Ic4QUzLziKCoDpiCitRYRxC9H6xCXBmcCEgU0V+jeiRfvWQuAAtJKGNgPWHbIgdzIwgwoAIo8s3cZloKOAhDk5AJIgssB0wDWFERCPIjWOlwGO0+kQuVtFYYhcTEOLIcyIp4INSIFSSzmILZFtjD0BGApkW4gEMZ9VHYOgAUQWWy4vQX+B0S8C1rFRjRoct4SobM+czZJEmY2wD6qdHN44MH9WlAj51HU1IkHv+ilqslwYiC94FKd97JnjwzfMjY/nU2y6s54s9SmM9WIa9nXKj87T2sm8rkntp134cbrrlw4tLjvsaU9j6266cVjC3NaH1rwU23Q4N3c5z7Xnljjr7n43lW/3H3PxF0AJpurnHx67ZHHu+cOtlqH9p/rbRuNgLwBrGkjrHKCCrM1xjoC0E44z5mti4zavucT+658H2YS2SUhg5yBSSZPPzGbbBpeOHq2mUsaDedM+fRnDnZvuHDk1HP7uJt3F1sV5SPC3iT7853/d1jsLY2MjWZZ/9HPfQNGo/MvvmzkovM3Nkbnzx69bmRqYt3Gs9NpNcIuWe2NiM/YgmWtdRCvV0RaB9myYgLDVrwXYwwG304BdIyOEQE4BC7AoUYyPrpp3wMPb1q3y2VaNFgXKVUSXQS5MAAJkxUsjRwAih7LMj6eg9MOkbXc66UTE1PZeENYvDQS11NCfV6qqcb8Fg/Qqp8bS+Jh4H5XeCyitH1u1XqiKGLvSBAQvffBsY6xWKZFQcmsEBgLRVMpB0JKKfFMivI8FxFR5FlirfPcpWm6ds0655y1WbUKM3PWKksEkY7CQYIQqKilH2fYooGWGA6O0NrlMPSCSqUCAIPaV8JcFovm7QA/DCUamABQEYaNGaZNzllri2avIhDx5Rh1cJiWeXe5jaAQOhAqQBY4UJoFQKDgJLychYhAcEMPNyfgm7h4DxFJWTqUTcRiG/83JCry8mWQKvQqPYvzPgoKfERYXqYQalIBExj61l7Esw9cqUJpHtCz5xJV7pwzSayUcs4FrpcxRmn99FNP33nHHXmefvAPPnT++ed1Ov1etx+G96nCOo2wze76yZGJoYuqHddXUUb9ONGVNWsfeezAnn2gVN2jr+qu62NzHP732NceX1z/b49P3Xz1lniTbd6598BpVK5br9eNtpHVUK3Mp5nXNDKsZs/1f+a85B//8paT3arz00O1ocwqMhkLV6GysNgbW7Xmnz5ww+ve/1Bt5wU2PSGVRsVrFdsOz7M3dd/wYrlSNdzzgUJBpTaYOHNiIwDsiU/6Y2tHKv7idcO7tybH56fv3Q9Jqp45dvLbj81tHD70jtsv3lRVactGUZr1KpLXxyZzUmd0NT9xJLOu533tmQNNPtjod5eHIMqveqo1t9g+o2V9u90eH7vnR/fcf/ZsZ2H6zHVXvOzm11x57S3XOHz86NF+hucinDBWC3C3k3Zz5aPe6JnOjpdd8Z4Pbp6Zxonkwp3+5cauytUsYlIWuyvWDECsjZQeWUUjRIAgjIqCF0wxZQwMBSmQiGE7L1OSAMCDKEAk0lQ0S7z3VK7VFbMeBih4wFJ0boEgqGuJLxd/WEiyAoqBEmrbsqs0oOSKDEwGFRaAwYJ5WLTWQ9guOsBBP64YeJf9XjKF/eLK5rn3XgEqAil5eqF8LTZmIaU+2N+hP18g03wY5ykKgpHOW2RQwdEkIMFDXyFcgC90ESB06gGstSs9Hz2ElJ08hJEBQUG+JxHx7IgRIjp7ZvHgwf1Ki7PeVCpEus8qQuhBrxJpn4m19mfftuooXH/j3J9/aWZy/URlbQXPTfufnNUnNql74rVjkUTqsZ21/MyObW7P2Ig9u/CTB+mSF83PHsL24pleMrFxfOzMMf3TT13I/TdszX78SPymvZsv23zF1I3XnKudP3zlW4aHVgPAbLrUaR0c6xxe7U/3e4ebS6d1TDbzGDlASdNet9WbPzeXdfpEWkWzF7X/dGHnq86M7wQdV6W7RtVr861nr7v0xif/c+GiCzKt2iIX1J+YOTL/+Mmpb3zpS0t23rXqgo0e9OGFAgAnPj87bJo5giUV10i6dv+9P546tP7E0UPvXbf52vff1kdIEzMknIgG1MJIpAZA1AEICRgDzhwLh4wipnhhAci9y71DVIjA6DV735o59cMHj33ot9542RWXnzq3qKMKsRbJy0O8zBhRBCT4bBf7QHiAvZMScIGKwtc750ZHR+q7NvW+/0NpbFL1WLl+3VR7nbNzV61FOTs523SSegUVH1dGhpZmz60+b8oCeAYAUIgeiMETkRAqQyLC1jEV6R54xwCoNTMH1nNYy0UwNoWYYu4sg0RR0u12u50+KcxSQAIiYOdT56XMVZVSRKo4EXTAdgWqTJCXAIUEZX2Z91NjDKllIdyw5UxAzSGJeBZW4daxt+w1KaICZFI+KglTIkQULlBghT3ZinFXOEb+W0iWEq4SpDq4JAKF000G/OzQu4DlV4EIkEJDIPzecFIQUe5duKTBPK/4QGYIYkY8oCWzKk0/igOlBE8hosZCSgxBOe8ABLUOLevyNGZrbYC1e4A8z6uNOjMrUrVazVp75513/vin9+++4KLbX/fakZHm3FzLCVdqVQBi56tso2p15tTcN08PNdc1++lR44dGI/WTp6Yf2REfnc5MTaWV9ryuJb26S/rXyHPXVx7/8rq/f80VF56bbjuDH/rZ6w6cbW9bO/HJbz7ykwPVqALsqIZJijC9aK+uLP3t3738bDsG6VR8PReHxC7LUzQ1ZSu6OnN6/qYbL3vfW4//zVfPjK0e7XZmKB5CrMQuXbsuWZjtOG8w73KkGEDKDakQAcQsjWG7PnXp0bcMv/rybVNDTT2ho1NnVz/27BPxRBPj+myezsylD/31j37u1ov+6Fc3zi/ZVmt+5wW7Vq/69GLrrIqWFuZn77zzjtNnz60e39zt92b7BwbPN0kWx0fXL6X99VtaV+4eOnb6RNx61/iaC/7pw3/xiY985ET7zOl6c9Nrh3on9elnjz30vb3dmSyddeIyTbRqzUQ12bjD0cG5k+ePvvIS9YaOZBTPRrbpyZYYu+XVJCJ5nhutVVhCRJExAMDes/dIREAYsMEsIY0bzIBhoLc8MMFEHLCBwzsGvdnSVwaKEhWAVggSqCKphWVHIBzUBcV1EqAKKhxhV2AITygiyx1nAFCFhV9gR3BxMYWBAQeebkHMCyJzZZ7qGUp9hXDgFmHYutBNKsiECKgIAQhK3r8spwgSxEAGUFMK14heRARDbwxLXGf4NG9dcQ89F4EWIHSVB9M6GTAkRYLafEC9KKVMUJeDQJVUp08unTp1Ik6U9ypJKiKIXcvKGSBmjZHd+4z72hC9+QU9S1F/W31fPZ422f/8jDunTG/y2Pz3v5+8aOvEMG/Kn9i//uLZjdclB79CJ/eoxVPS6k5D59wcrr547dL+bp1BGR3X+vGiGp9fPL74g6umv7HxupFzT/UfWhid23hDvGZnY80uXnfD6foqANCuP9w7Otw6OLp0tN46oNqHgGWk0UxV1F7qtlvt2bknm4ePX7ZlvLH5QnXRS55af/bASF3ZpaGDP6rsOI8h82ktl/Gda5781j3//GhLR0kz9W2tQZDc9Yz7VbxocoC81Rlpjlhc6iFUK7WTs9NXTax6ydrVwy+8ppNaBt0zgF5pIctSAeUUEFFgp9PySB4ECYPuU5k4sngQQVKo9GALaCCp6OidP//iX/7lVx455Shh5dlol7sB56wgdGKxFNxgrayo1RgIvTAQBcsxRQqQUGD7bW9/6vsPbuLT7FYvVnuVLCGrOtvceH81g1QSFhd7hLksH0q71fW7e/2MQ+7MiM+DCIJG8hqwpPE49goQmY0xzjmFBCyhpvTeB9eEOI6VUh4ZAJZarSRJsqwfKGXhzcVCB2EebG0QBSWaDITK8W3YVOV+DkscoMAKFXeKyAcJ3JBiB4koAUSy3jKgLtq2BYaZiCwzlpoeHEYdUKAqBmcCIq7Aai6DO0K2JQIoGLpzg+MGIBTLK1TyB9YohSateO9DkaG1Zi6m3SGPFgpkyBUDKgJEUIJhzgEAqCh0s5e/cVB2D3A0ZXZPJfE3zJ98IDrZIDeNAJBUKuFKGrXqmdNn//M/PgUEP/PWt11x+WVZ5loLnSipVJSy1gJ4UNQXV0/0T/aemBobWkynq6qZs89s+69+fe2YH7/t+g0PPXXkKw+cmxirudhrpz84+m8zyYUTV/zCvoUDf/8fe268cfNLN63esnnkqq1rvvDdZ8SnpIyBjuNhImwsHP4/H3lhj2tZ3q7qob7psaio19exGFSeMgRSSh07hR989w3f+f6nnupfMBTVslxZx8bU5ha5L1AbNYRx2u5TwcMZTPcRkeToxuS802/edv6+g9htzZ/L7Njaqe0b4KmZfhLlFV3NuFJZLx/73H237Iivf8nOxW5aH4kbY/H2aFXak3pdvfzWN5w80ca0O75p1ee+9oXBamGYefLBn9xywUW9/knm3v79EwvnDuvjh7dee9Hb/sfP/fzPvg0aYxs2bD626tnd2zZd8+ZL56YXZo4feu4nebQQPfPTJw8f/Pw1t1719qnf3GCuWbIzTKOc13rSNhgFhOCg7VTUYQHBAxAMZMoIAVSiJUKLbFCfIXPRcSr/ZXmBAQmhrCC8CgIozSIDjYsQ4gbLDFf+fwAIoFbgB1euTOQikZZBbEYggYC7JizoBiJCxYXJQExnAKEypIJCVrEr9TJYIexiAnBlF634gQP4oRdBwAGEZjlUL19q6L2FxpQs48AFWUghoHh2hEoppVEFEwUoU38iFCoaC8VeQy5TkyKQI6JTYVeqQfnu2UNwAbYwfbabpb2oASiRAGS5q2m/aJQS4D7rCCqjdCh+5au7f316fGztmrinjE3T0WZncv3k0w1oPfVYDb917hUv7QItVUeODY1tE7CyQBwPn3d+Ldez7ZOjGme54tAMjacAoJfMOu9/jHj4BOw4I8O7R2/a33n8qa88d192JIm2bF7zwu07krUXt4c2t6ubzo5feXDDqwGAXNZoHRppHRprHRmb3jd5Zr9Nl0ylMnr+rsM37rj3uv+70Di1+rtf5+SOT/+fr0bHV9OxV+vYHutla8YFlvarSRPXzHCOXa6lboFvSPX9kWZrqnEtGp7vdOuxjq1XXWvrdMv6NWbHFrtjU3YurWAlQ08Q6NssJfIGRXx4XoXYgwSTLkFQFFD6BWEplGGDBayVJha45OLzbO6d91FUU8zWZgIDT03G0lJ4EA/Ca5DMrogWJZGNGQnS1F/+0tvO/HHjxEf/58TJE7E0OCOV6JmhmcmlTQqrzuXdtDPSaEI2X63Z+tDIXKtvlEYurjiQBxSg815K+sry1hroL0IB2UfELMuUUiQQxzEACIsCZOerSWW02Zifn9e6MA8J8cYXQ1yw7MsoGMZUEDqr8rwCEgBAKWVMxMyBxoqIoZUqCCVuq9hooV4UkWDvHHrpzztBwmd7BhEFy/26QX6DJaUvvF+VSW6xM4WYhQAZhEq4R2GtGvLy4qwrPsrQslUqAAzC9uA5Ds4+WAaPSDiVggp+me6VFCwBRBqQH7BsYodTA9VyK9t777Jcl0Tkol0WKg0RYwwzg4LDh4/++8c/Pjo88q5feNfQyHC3mwIAauWcC/cwcBm1d8MVufuJ3nw+IY2UUXSujNZ+rmIarSvf/PnP/J9Xrm6qOYmHuvOXNB68pvrMcxd9cebk8V428ku3X7B+bKQ+FZ18YuEPfvDEdw/2q9WqJxTXqFXM7PFTv/3GrZfs3nHkcHe4TrnpiNcmz3P0GiqiM8o0p+2oOdrP+zS89nd++dJ3/PER2LaGwaJGpUzWt0pVXJ8jRSBBGUwLIIsAU1gG+tTWY7seP/hsl8j5Siw2T1x6zebVB4/PxNXhRoPyvu1JrFdt+tr9z7z69Rce2L/wvW/tAcwf+MljP/P2N509e3pm7uRb3vTW+kT1f/3ah+7+wh2DxXnxxbvvf/jJY5d4pWVmpmtpwdKJi+jCDTL1o6OPfOyv/2L1lmvf9DO333jxTY8fvKcbd3pLrcsuu8KfOf4vn/jXZtN84P2/8bZf+R/ox6fTVkMPR1neMb7KNQc2PNNBEqGRmICMyfNcnAdEz5w7KyCklVAxLWFmAWCQlbUvlB5EgwwPRIikSFrLF0kg2/CgBi33lBRwqpJHu/LTBq/BwobBYCX0ocvgh6Wec/jwghAPQAKklk9JKPdFeQ04wFsNziIdZHCYizeUGyqwVwcbsxSuAS5J/IPsofDQJhSBMGkORkahkA0t/XDCqzAvQ/LskXTAmgHi8vyLMOgGltezAhetgjMBYeA8AoOgVlEv8wLQWcpy2zfi4ygOStqLyF6kzzAkABnaBr7pitpoOnMfbEmiBBazej3Slf54jZMIsmix9eQPzNRWe/FVqemfaybXQcU7Hxk08Tqfzl6+baNvJmk+P+RsrUYA0Omq8xXdn0Q/hUjum992PQ1ti146kmzr5g8/tbA029pHh1ctnFu/ZvhiE/Vz33XJYmPDYnPLUmPzzMTFR7e+EpDQ22b7xIg9c6771AObv9K1z5r2LtPbenbnr0ClN3P1F4bi2sjeW2zevWD1BSf0c/tPdus7ru888qRSvebmZGHXEv6N7rNbPdIEocV2l7zKIuqA28y0a26x9qKbG1nUchlGkuQeNAp4Ek6VxL4gc+KKgx0xMMBDKlliiYxBCvr7y8aaWqOqjta++u0nrrx0e11X08ywsqS1eLt8TENwbCUQUMFH4L8VW1BMSYt1ppT3HpwQ43xvZmjjBav+4hvHPvUn8J3PDEcx6MbcmkM75i7nupH5bGK0JqNDrbu+s/2GCxko/DmzAxbUBVoSPCNiIZkRuL8gSlRIQAhwaWmpUqnEwaRPqSzLKlE8OLLzPI+j+uzszImTx3ZsP6/fzxERUcVaBzEKhMLbhEp7cJHQQiDy4pwPg20JvTWE0KpdGXLCf4pnrVRxEARhFIAw6AJVdF+FSCh4bYMHCRFxJQojtIzd4PgYwDgRAEAHq08s4mqRWBXfWJwpRQ0iKBjK4MKNNcTRQYgVKVpcUBbZ3nthDlO6cC4s8ypIDXReKEgaSbG9EVEFZd3y0ATPqIhKVPbgRhGRNsZaCyhaKV1gVQpJbUT0uX3sscd27959662vEJHFxUX2EkVR0A3s9/tElGWZiCBMzpyafezkUj48PMzDKKnSec8N/c4nDv7Hn13ymT+/vSo9rzVJ3o3k9xqff6i7/b7FHZfuOi8+PW84XlL4n3c+8vkvnHWVeGzVkEaZ93m1GXV7fP1G/YFfvX76aKdZr6XpXK8DtaSi2OYUZ56rHlmDr1cqJBLZk6dat9xy7fVfOL53Tobr2Heptyauk2PJrHfcN2EOB6E7qhCVCHvH1RNbll7yjSPfXbh666qTrX5UtT1buXjbVH7PsbQDM9NZ7OqmUpGh9MFT/G8f+atv/+i7p87uXb922/Dw6FfveibPWwcO7Hv8yf/IsK6PPPvGS5d7qLV8zxWXDaM/MUwjM1l72BHx9siM3PXt7184tbbRrZx36fB4deriTTuu2nndmaOt9WvGnnnm6X+985eB+n//z//ytre8/egx9rgQa3H5gpGRiJc81osIUYLkwxIK6aBSCrVGDghbEQHrC5tLAPBFR0ScMPHzDo3BSyGCYAE1+e+6UYWFH5UF6SCgLodzKGyCwpIeLLaVZ9TyBy4rBgICOOdCtyaMukI1aZm1iPz/SMkIwCJa6zAqduyppNjyypZ3gE0oJCIGkNLSWAiRl/vtxQ8p7UYEMYDJizIclQ6ymFC8j0rt2wIjCQCFsXIJsnXAgMwcHOGL5AaRCAeaXyKMpANzCjE05QnB9HNOYgAA763RVRMby4wgaCJyUANhYuuy2o6fe4v79++dGr9jb/ONm1sEkenqG6+qR5vzB85xBBWdzy888NXG1OpsYtWsanSw5tHnNo2oYydM/+Ri+ys/Sr5zR8X06w1hhm5HdqloLclRUBkm1ad6q+bS2praTnC1anTfTOeZbrb3XO1ih43NU9osmSyrnX24evrB9aLYSSbxwvDW1shWWXfBwsh5RyeuHtr7K010PlqwybmZ8+4hQN3n+Yv+a/WBm05Mzzz+1MPrN0STa6fq237hafW12fs/Vt2NAEA/iQnl2PFT9chIpNKeq1eTVNLrolE1OTpx80ttx2mtbSKUowG0KApRswQsrZAKiIdBaC3Udj3bokGjB899JV1NW2s9e6UwiqJex5mYNJhcclR68GED5RpEBBYqi8KwIIsCdMXkI2THHjwRNaTeb+/VjZHt7/uHEzt3H//kH27uSWuzxA/AqFadhFLJqt3W/LEDjV9+Q97zZULKQbADhVBAWEARFe0iQCIRJq1QwFobaVOr1XSpZgcAlUqFmS17l3PwVbbeMfgXv+RFa9asKfzRPINSGgmJYIWgVbGfmQl1MK4omvgsDEHCTpiXgRiBh4BlP82KKyc1AEH8U7FCtOxXHhmDnjMTEJH4gsVPRJY9UgA3h6IJZEU1vLy9CRFAAnRFAFFKUZSybwbLZO1BOytIYoVyU0QCr3tASgvcD0IaHGdcSPyIIIQEyEMJiodgBVc88ZDdh4VCRIV1UTFMI0FRSCqKsNAYKcQyMZy8wcJdayG8/PLLkzheWlpyzpk4AgClSalo4MoQTsPGkDvyTOtwe3j1eLOdtkfELDlIKi5ateovPvvor113/lcffO7QGVy/3l0TPXRZ5enXn/nrOz919Irx/a971dap2ojN3fH9rZffsvX6LaO//42nKyYalSQVXZ07+ZF/vnkmi3JtG4Z9q1ozzoGkHmISInGOSGUKY23T79//2GLn6GWXXf6uV61/90fnJyujACk1qW9VzHHVpD2ACLUABtAcAQp7YCCQ5PTGJc3fPnf/Tee/woMhqPouDY/SSy6fGGqOuu5CZzE/OZ09fe7sYbP66VnZuePiay6/rdddJOWXFjNTf+zGG15t00rHp+PbXwbV7w62dK/yWIwLis3ek63ZmbypR0aGj1Hcwmu6pzo4gkPS7J587MmZxZnRVZM3v/jKb9z1+Xf+3LvSdu+Vt77ytte8fv+RBQ9SUYpyJcpz1Cff9OKEHWChN75yp3OJZ2aQEMxwhR4WlABdFcQRCQeEdShbo8WSXuEgAuWYRkRggF0OSAfEAFCwwgBCXExbkMsLgxV6jWX0DaI0xXm2opYNSuyDNw/+kIhAipp4sO+E2Xnvy/4NM4v3XhWytSTLf17cH8+lq+DyznXCqvRoCqmGrMhImFlLKealqGgHCIhnUIRKQRgSB7+WFT+QiACLoVIY6A4yA1kWgmAIxgDB+TP0TQVBVC/N+rmYCHSMpBWZJJCGtXDkLKpR7rdyUlSr3Hjtlgv6j37w8c1nUHXOpc1J0+r3rr82mReRM7Jhe3vIbXz8ibPTzz5df91OjI0Fi73c61p/uJ4/sX/2Hz7QPPTjCd0EXdfNhbQDXTKbQF+e9040kwUauruzeOnxZP2+RUnpAYT2+KYXXf/i6c7i4X37h/ziJZuTTsQ5K069sS7yoF1nYnrPxMK+eufB0bT3T3/0gOBO132lWdp17EXvjLve1lSeLBGo/uqnZh9oHRyKzqMLmwr69eT81/2y7SwsXftFPKDcSYlZ6SRm8kO6MjRVO3z6xJr1ky+0dXXBhcOj49NzrqJMjsAagcEJI5IGZVWBepMVqANEpBUChaoAuoMM2opl3qi11q5NP/PrV8dRhY1DaLOLvQYMXnzFSwZDhKIzU+AdGGAAFCyMa8IYwgSxYsd7T57RNKxJ+RP7d73yjRaHTn3s/b1xnpweooY3MVfqo+np/evO39TYPDVzYikxSWF4opUoDHYfzntxXiulUIcGVNlQImQfalxQOkx/EdFaq4wmrYAFFeU+B6pEsf7SF7947Q0vfNcv/GK7Gyx7ndZ6IG9ZhKhQp0pxjHCemSiCcqMaY6hUywvHjda6aJ+GNR3uRjDHCC1tBChHBYVnS4mdBgAvjIIexAtrKtpoqKj4hEHFSRhGaqpEiBBgIB2VZyEACnFx/MiKXwQCYeS6PAYeWBxisUuVUrjiT1YWu6Ez5pgJsDCGA/EioQMoskIvesUIzcpgEkZEhZ5fOLC5hImCImHw7J3nWGsWYZaxsTHrcmCJkjhM90UE2A9OEyLK87yu4keOnYuixPhckW6hrUqsfWrzru7A1Prkf134skZ07+eesX+48T8f6l9w//xVl25NX3PhqsmhVTH0vNcf/OVbmlXcc7QDve7Q8LhtyuKh05/9gyvGzt9y8sSRanNtu5vaIR8zxT7GqCrc5pQ7edY6OdNsjGRjzcs2n39iSS/a6RuuXLP9q6c4tpEf73VcpZqmyIhxg7Ul58UHEykNyN4CACGoo1MA8Gz92QX36ooSIsyRnYvef/tl/V4UJZkz1OvbvN365N2Hzh6p8/BSZ9GePHVs1wXbd+y65PCRptjmzOzZETPco5kjz2WDgCdufNXUxPTc8ZFRJrTH5s9lkT999LS1eOH22r5nn/TJU2v0N37w02Trhvfdf+83/vav/qReH9924YYvfPrr8x3fJNWXfle4qox33pMYyEAESyNwEZFSpo2IkBA8M7LR2jsXVpEqFJ9CcBQIRnvMSBQ2adgCuhxDeO8pJKCIEHJTKXyx0JMQKR3QEQXcF4SsYgpi9MA6eHAhDawIBoE8uCaEs9GHJACLIjOs2HA9xWb03heWpDAQ9PBlfGTvw4kRPnyQQYaZ6oBNNIjB4XcVNAii4CfBIKiISIktqoUV07twzVIMxTyxwsIhBoFIcxh5r2B/BKJgocgVWlxQKM0tZzArIDskQWSXvBckj4XGgHJZLmAcgzaYJBEIsTgMcqIqcb6VGtTW1S647a3yn0fatbv3yvDIqU5ng2r0f/rI4oXb61B3yuDF58VHn+0IMh25b+He6vz+RyVOhpby3rf/o/2JaffIPePp6SGY8rWMfdoYVr0liVPIY3edw/19OBgnWV3/kLDuat0o3XzRtTftuunIsWePPPlTFPuj46e0n9y8fk1EOkVgyRlBtHhtVYXifn9kZhaibj9+bvzZT/r4VNxf6I6CskDkSKSreuSWNoxODq2tLB3qS+qpgete9Ka9L7lD/8hFUUSUVlT1XHexkeNC1ieQTXFlSHjo1pdBzIkjrBC5vGIhZfYoBnwvNhXSgsAMUpJHBmspDOYVqMHYDgBC8zKEGgDQjVplok5EzTZ7ghy4ZpXV2oiItVYXRHLAwugAwiAWVcADi/dMmth7B6gICZDFqkgyD2BiSmA0bhykc9LOVg2t91l/9SUX/WBXBADmwbOt62alrqJ5222OTtz89tZ0t+rrbHIWz8DEopURZgTSSGGS5lAYUTwTELAAeKN01utXk8QzexAwKs9yEmAGQgDS3jpmZkv9XgaYrN+8NfdFRHTOOZejojCjEgQGIYUAgB58nhEiaOWD6wShZwZSwICoSARLMeqBinKBhJSC5igk4DnQf0mIkMBzgfwMXWIotMY1kUkKOgcRERZxlAt3NBHPAEACbmC4DUV3G0L1QBRYjMFZBQCIQQkQKQEwJgYgn2eImNSqxc4XABEgjKKImT1AFCUULIPDKgkC9KQYwRR0BQsQ0CsB1yeEwsIipaYVgtLKChYHpSJkwYA+EfHCGskYI8zsmBhABJg1gmC4QSAIBs0gQhvBDHLFROI8InhCsWiqrN1P96VpMtVjARRjc4WEEC30Ft5y+3nfvuvJH+/pvv+9l/UO/OuF8b6fPfW3s2n/Fy5Ze+MNq/c9Mz+9mI2urT/01LHmaPw3n3ukEo9jAu3Trf/xmuGXveLiZw/1k2hY+j1CqIoBBJ0g2Nwy5eAJfGSSpFrB1GWxbFh3PgI3V0+9/qrjn3i420jsnBlmTxo1SKevxpXtJ3Ec/JVFwJg4yx0hLS01aWZyfuLoidn+2qFa2s8BsSZybN7nckZ6kyLdRNNQHP/ee15599f/7dDRUzvOH4mS7UNDQ/sOfbs136/XNs/PnxzdvCaOlnZc+Oxg58dqZKq++9TSnqHGJGB9pLE6jitRbcG53HO2ftvwULIFAOSCnRuHd992+wvf/SvXP/bgwuVXvvj+576Z9tdOja0i5UeaEzZziBh5cR6EgHyfsIJKRIAVEJIXxZDrVDmPJgHrM0JtjAEQKrTMAYSggOKRADjvkYAJgvJpbm3oJA1qXywNFcSLVto5VzS1gZRSIB4QHDsda52JZ4dEGkmYbSHOqhUVDEYf1CcgsIZZPAaqwSDmMYEHUW6ATyoGd8WYVhWQfiVARM57UsoQccHj5cLYPWxAEVgxcAlpaBC+8cwYhDAJwyQLWKQgNCM/v2xSSoEQKfEgQEAA4sKURzHbcAJgmC4GJBUgEAEZz058AWoJkDdShQ5BKIgLSoIiBbrrlhqUiCevhWynza6/bxY2bjAKIq9U3mSVO0amKM8E0ApYcCgm2nLdq27u/cGf71t7y6t/5u7vff2xvdPVo+rD/5Te9urGjhsWGzGNjvfueg69arrZ2d43/0mnfWVUrvr6Sx+rs1U6moeqVb2RlDKE2ojvLJlM5RrlfIyu7mf7KpUcjYZ+W/ial7z2kguu/8pnPjF3+hCMIER6c6onT51Zt5j1tkwujdQka1IGGQJGFGsce/oQHXm6es5VFj6u8qGjN78gaft+A3zkKY0AdbKUVLOFHx2YyXFJkisWUdI+VHdN8nmp+uvRqq63lrpeZzXBNNEuz3xc33rstLri0o03v2R+OiejmT2CZAQKsQooKNpn1hMzax2BiEbM81zr0NgDo4wTJk2OvXNBPwkIIOgTEWoA0EabF95wQ2QUFrMRNpHqdXugSCMJiCIFpXFNqEiYGZkDNjiMQ6z4SGlk0joCiDKbKtKRodOnjn3//odXbb1ibMjYbpYt9usjprszAgC8c6/ZPt3cfE222LPt4WYUjQ/XZl2LJBYG75iJkajA8UpZggOiotBblxJAVK1WQ86oiBz74LvoAQmQSFmb1ZKKtfaqq666dPfu0eGRtN/37MSrKIqYnSYFAmC9FgQizy4IeiECsGhEWFZUJhw4WFORsnLZbSOgMCPCQJUGACm8CAepKEDRRhdfzIIECRQwgATzA1LMnGe5tTauVgbpNgAgCwuTLydwgF7RAN0ozFKEMwmTpJA5caAAiUf2RaXLArLsmiIu0L5AKQVUJP5KkQLgoIBPCCLB+bGsdMtLQoVFmV+6QbBwkKEPxYF1ubUAYIwJ5AcEDNJXBVAAUWvtnGPA0PQTAYTgaYfgRIJYIKDWBiAIHSlkgZ4/dqo1VN3gXB8JQJvMea0gxqFHD3bfftOu3Rf72dPt35367IPppd/l62vq3JNHj7/18m1qRO7+1vcv3rVh+/qRX/37+3RjsjlkOh139ar8T3/rtfvP+kqDLSO4UDeEZJbDBUdxnPXBeUFEpXVSraBwr9s9fvzkW2/d8c933780NhZRRxkib73UDaeglBd2Aug59BWCE1nkJTu+yW45cfKhpa1jjY5iFRm2TsBVeRx9iwAYK/0sPn5i7uZX3HY73Xzq9AlStTxtb94wNj+/JD6uV+PpuemlVnzk8I2DAFypZTMzDxKuS3sikOf5oW63m9R6pLOk2ttyXm3L5hnS/ZHGBV//7J/svnLqz/953Zah+9esu+Dee+/+3vcf+fm3/06zOTmxZhqgOj4+5fKsUa+wy9k2GdjnqYIYwJJyYjUA9yu5sEKqkEeW1HMmIBlkUDAJPKMVYQHL4tlLQAsrVAAgpeY5AFjnarVav993wf9HaxExUaSBnXMi3lpHREopQOVzr7URK8UEA1FBGE+w9wVx2KzQiFVK8YBFH5YulWAov4xDHCQBWGImBp0qLOdTGsr0WsomD2FgDcIKMGOQ34TSHqoYF4kQD3JvDK0mLqXuim8P2QoG+EaRPoQPDj38QQdrGUqG5fUwD5IAFqAADaLi9AAABGTo1LUOJhNZmlI0nj/45OmDJzfs2NTpZbW1Q6PrNy7l+2IbOcksskHn8xiAa5e8+g3qS9bL91vX/49f/bXayM59T/3pFVe3a8OrvvwNucahXAM9VF64wgR6HiuqooaQ+0kuWaKVdDIHolkDIIsiqTX83AktWT/mRrfSuVnJsbb5YXXYWL1h/aabr3/Vlz73qYUz+9VwAqRvanVf790ayNzsifb0TG9ipDMxOt+sqJoaT93Q0YXkyAn0lU0/fuPp1W+avfCteeNY1gBtwSp01YXa3AVypJIZOz0fPXNIjZ+/sXOmNV5307ueAQB5ckvLHq5XhvrUUWKiXjZSQ7V507q9h1a/8Y21+lC/01FGSdGAKHKmsDhQEwoBoji27BlhWay0qJOASCvllVLLo4gyImhmtnkvUpok1BjU7faNMSoAmpzzUsw8RCQo48dx7L0vskhmRDDGeJsnUW1+vlWtV+Kk2uv1xobNY48c/sc//fXJ87eNNlf/4rs/dOnOC+aB4je/TPc/ttZGh+7+6uZd50nuzl+95djT9x54eOb2X/256bN9HSS8EIM1QtgcK7SZEGAgagGhM0lKQbDPo0LTjpyQIu+81rrVao1PTD7++JOPP/HE8aNHLt59aSe1AJx7rwB9bgPAN3SLNSqPUuIytHgX0EpS6N45DMQseR4apbwVyAGXUQruIJTxikpIM65QFAmU33LTIgsXJDJxzhnruOwVKyjfCcuv5a8eqF9B4KEFddDCVwCLLqCAiFaKAjPceVBUssWLTIK54C087ygJKr7lYSQS6Blls0WRrJD+GPwu75cNmpY7YIjAJSBchEpAu9baEwRdgiDHPfhAUkqjABffS6QQdcXgzPTCqSWKh8jmEgnlHpWwtXayEf3nEwvDOr1468jcI5++uHL4jWf/X5LPq1Uj392bwucf/o2Xn/9r73rZwdn5D/zz/dnYurpud7N63D/2sb+79UzHimjUqK3WZUNCpNDlDs8dSVerVSRljCFPnh2S7vWzVVsnLlynnmz1oghQahm3FeYWCYTQC6miqSEiAmjZD5tK/+Rme+09h+7s33Il+bZH5hygluBIHZzUAFg4YpcenUs36UpUGdqwtUJE1Wo90pH3fnZmfrdwvZJ47vV7y6siiuPmUKXZaGRZf2lpif3SYitdmO9Nn12cnZuemT51eM/+uZmzVv3wmaeOxQpffdMPOx3ZsXP7K29+18035idPt+bmDx05MnPszGfXrdl14eb35l5Prq3EsRkdmRK0zEJcz7IUwTO7qC8OrVWgVEWIrCVgIkvWWyIiUggKAMUp8JogQHeFwYWCL3RoA3uw3++XYHjKnSMi551RFOKuc06As8wRUVhCIiG1EcLicJOyOTRYP6ETqKAoBMuVXUQsDPJYK6h0g2p4oCtQ9IUHVoMrJq9QwqeFinI5wBoBy9l4+VIryBQogAAWCnwylrzfAJb2IgBctspRhF2IyZ5lBX0FC1mRgOcQXDHeKiK046LpXU7Hwp5FSRASwV7bZpU6ZBkc+of/t/WGl1AV7IzbtmHt7osv+/YPHo8qFaXYO88+JsVA+dgNb33d4iU/al/8vg/+82J/7rVved2XF5/D2kfWbujPPjV2fE5zLjqLR5u1pQUPvunQVKmt0KDK8zwzOk65p42pMIhYIV9pSn9RKlHVZmmPogmT/ALRZGf2K0I3v/Ztjz17bM8zj8qQHnWdt3fyVxjFkrdTrxVH6WJ0YrF56vgwoCdVZTJpLoSza86bGf1bpT6p4i+sOkBZFQxH7eGx1uQZr1vzZ58xsYusqY1vTaOR7v49/XS+d/vBSmvT6KbX2v3/l+tVZV2SYn9E5z1bO3Fk4+VXbX7D688t5IlnVg6gBNaCIgrApwLQAwCgERG0UlAg2ItOqBcOd74AEclgEYGIaBFGcJow7VutI0QkSrTW3hXtzTDcDdAGZh/ARFA2TFiEJQi+uE6n4zijKMrzXMTHEfz4vh9Wh9cbik+e2vv7f/Ku21/x2itfeEt+XXfomNl6/sWnnrxv4cPJRX/+kYNP7/+zv/ybN77gMkZhZiCDiMwupJiaFCkVPECC3ibD8hQTEcnoANjhPM+zPKqZLMsUKBavKFIKm81mwNpffMklo6OjmgARSStNSpz3oZ2jUDB4eBOVmF6ttZS+T6E5HHo/PBill3nxyo2B5egIgjN4wCmukKoZZBKIKM4LS5hglRgz1MbEYcDDAooGu5dooG5RFKFF3C1nQsE4ZjnDEvAgAuJBjDEAYIxhkdzaUJIOmBuDk4JLs0Km5bVFuIx+Kn9giSLwpf+S58D4CjBUKQuIgSVDKHxDyTuY5oZvV0oxMCiEgB0tAf0ggkQKVMCOObCKgD0PjSQPPzm/qIZHIBMUxUAMJJ4dg2TjpnPZ1pHRYXjd+Fcemrn0aTqPE8OL6dhI58dP4j0P/OD3f/78y7dvcC4fTvo6iuenT/7jr18wumH8+OklrSykNZ2wt37lkwp33jlHWiWRQaBQuGvRqkGViku0ecGO6IF7MRnWvp/FPmIlQYeMmUWQgIPkRCDSOlD6xBa47fP70xlW52tRhtFGRD384KfujSqjUwkOr5Urtm/atX7YLranFxcQxUkuTD5X83OnTAXSTCKqN5sjfXdq8ATz3NQqoxMTEzbPkqQy1BxZvT7atKVpIjQRdNu9ah3ZU6+t20uzJ089/cD9T952Wwd48sMf/eMobjRGjtTijS+85pfWTe7Ys+e53sZHH37uzy5e+sfK0NAzT++ZXD22es22hYVjccVUkmalGoGPNebOOfE9EIuSATKQFfFBHct7DyACHilHxJBRqzCwYLYDv1uRAGkkIvSsAIGFvbdWTKS8K+rUANpw1g62kkjINxERi2FzieR4fh5ZCrbTcnhe3qf/HZf9PETVYEMhYg5FGFZQmHZD0Z0qquvlgBd0z1ZEdyk4aYGksIzExnLXCgISsfMCoEIHO7yNEOV5HzW4xMHAW0r9+WKTlkIlJapchYPCEPY5r4KvRErFjXOfuhNOHfVbJ23fD8e1k0fP7nn64Vq14QTF5THqzGeKXPPSN7zM3DepWnfO3njh3FFL7o6P3v34Qz9Zv1ZNDjujqkvzvSrz6Eg6uRZ6S6uU6nrsTSgwS/0uC2grLmaGqjJG2IqNm0QE3SXquz5prjvogVNR9S0GL9E6e+an+x5+8Eo8cWkeX2uj1VSfTTs5LAyBER3FUSJIeWYpy9mlzpCqqlzMV9/5L/XFs6/90w89+mbz8Gtcb5gxqtKxFzWe23TihX9KL6fFjy/uWLWjObm5p+omjtPWwkLt280ndo/f9IqTRw7S0W+Do9QQLPZwYg1MH9r5tjfkjXE6k/qkIM+Fk9YHYLsUJneDAgNYAkNEKSXLjY1gdjdgQyzjD0REK6UqtdiLQ23E5SxCAZ2kjIiwFwjNSZaAuzOkOESm8hVUqLyQMlGzqj1njkUp00/hskuvEv4qOW40h6o+uvNzH7vnq3f0vnS8MbT2Cw7T1RvsmaMffucbNm0ZedXrXz6xZizJlvcGYtl15oEaThEqFVK4snAsBgGHMIiN4zjLMh0ZdqK0do6ZIXPei3R6Xev94uJiZsN4PLTmbZLECGALIyCRAA8JY3PvoigKXxF6sOFu+NBaLl+DuIWIKgAlSrIBBDgzi8BA61UAILCPQqCy1jpmY4yUpEaWZX0+KVhlZcwPglNSKEsTFYqSK0MphcUh4koVrMCeQq2EkMWLKg6UAR4yXJiXgBpAERHHQqEzUKDQRSTQKAfe5gDgSkdIKcTAlRo4sA6AaQPIaynHEdT1bHmrvfdSSJCEZV5ArwEgZxuqAVeuWmt9JaJDZztdrk4AZ8zMoI0WazUZBkrao/tbasO+/6q2n7sj/nCMTUjtZNPM5MbX8o2TlSsuGfrtP73L66kGVU+eSX/+xtpbXn/BnuP9URP1XO5UpmQZ7gsrqh+llNJGRKTUuBcR55kFHFdue+l5f/ntp7VMOc61ri2yM8IoJAFzC8jChASASJQ5phObAeBEY1+3f22iqghkxVXrdLhnF5Yk7ne7z+af/Vb/wg3Zb7zzsiFO+31rfd7r5iRRtV6LYjl3dobd2W5vLLXLJXCrlU6t6ioVC2dZljEz6iWUJR35xcXFA88dW716cmx0HZkcIN246fLLrrzJ5arf49fia8+cntaRn54+N9OaB23O27VzJvv41l1rpo/MrYrN0SNHPvvZz1YqY299++s2bBo7fWrBqOGRsfFKpaK0A3CKDakYALz1IErKWUdY6dZa770xCZZNoEH8CIskieOBOJqIZFlar9e1quR5LsKCQVRoeVGtDJAra19c4YhQaH2sEMcIlzPoGk5McwABAABJREFU/YAvA+HzukvLuMLnxTyAAGsARAms/WUS87KUx/J/rojB4eWLwZNgUfcuR9+Q+gdR3EFCQESApaTd8/lUyKAUBmWrwPKC8mRm5kAYC4cJMiAyADmRDH1dScdF9Siae+zMwU/855OjceIW1+QKYvjuD+8/cHrP6snhrJ1pxXnqTAxIjfp1P/em+ZdPj9xw4cveM794urNI933vc53Z43W/htScdYvjQ8pqdbLlj+4bMsYCqWZfT1JfZTmqTDB2wFpTEkfEuXdQaQAAdBYNgANtenlH2byiTJ9gJyB/787LlY8qo5qTVHfPZHPgJBLloggcEQtqYNBMnhQiSpq7H73uf8+sueDtf//K8db8yz+sbvqXpF6jPS/5ta++7FVRGptK5/Br/2F19+Xjj2/PcPJcK5k/uS9depy3LsHnmt2jP1z3ottOP1z1P/zP3VftOnrs1OzCuV0bt2686apeHytEfaUw9xgM60rCGCCgFNj6wP3kUrAloO0Awhor5v3hiRcndtlx1N77Tr/TGGmyCINPKkmn06lWq52ldrVa1aTyLA8Nn9AmIoBYG8veex+KqjzPEVGpGiOIz4SUUoY9tRfzyy6/qjnkhhru3Nklqq8ZWjNOuZmZWHSP0nPt4+fm+iO12mJnenjqph8+8OT73/VzHIm3TiEBgFIY0mdvnTifJIlzTgijSAGgc8VxH1ouzBxFUZCzMMYIAgOLs1pVvLchN9yyZcuRI0dGR8cUKULlvTAXP4ElrFBBESeipJwGAaQ2R0StVGhCuqA+E8pQREQMNHlHRdJQdJ5WiCcLgBCqUmcqXC2VKnFYRiYPhdNnMEXzuVdKMQJ778EHu0ARGWwwD0zB3aFQyShqVoBlkCSAaK3DhYTnHa7K6Ci3loh0sKoJxF/vgy0oBXpRGDIFmVkOLtYQsNiDIhuDOwyi996xN1TELeaC+TgIXcuhN0wNyvNRghAPBJ1BKA+l4p5wkI5iQSJCDSiKjEc0JCdmvaEEnA+KulZYGeUtsjgYjv7ijjOPrv9/j1Wv7K6+bO99p0bWjNQiGcHk2OzxP3jPNf/06X17FpPx0Wim19vUnP+j973ixLSqqbzNJtGUg8QuZsNUVjMAYK0VEW2UMDALoCCSiTQVbVQ63eELL9p++67H7j5m6xXV5n41Nu0+VCjghzmAhhGDPAkKKjm5BpzqrTrc6dnYVDK20HfJ6MiGOM6Ubo41ar2u6OTBY/ZLX9zzztfHMwstL9TvZ7W4vnCurRSArhgZ7nR6eZ4OjvhGMpr2sumzx5Dc5MTaPKtLZrM8Zei3WvONoUZzqJ5lXdvPtIqtnZ6Zt+KrOk7zFCM9DirfvGGSveUM4gR63X9InV2IF5WefvmWW29+8Uu/dudn584d1jbas/cbU+fft8adH6sLlb4gNtuiaDLNNABWktHAkhNgARvaNYqqWikvqZTiiForIhQpirTABVeKvHV53l+zetW5c+ds3hkeHrYOoihJ015QoPOFmu7zzjIAQBBcuQgH+bEwDVLewAcJmHx43mtlvYvlXGkQucMrYhQBYRECJhTCotkjhRTD4ENCHgy4/C9BHifkytEKimCp5Q6IyAHRyTLgO4V/HFROQooERAKbC0ih9469FBXzoAVd5iKD/x7e76S2mLdr1WSpnc99+KMnhtR0dbL11MH1N8ORVvvub31tpBmB9aTAsidtEEidd/3FzXO782c+7//3+FSz2+l96r8+2s8Oj61aZZrtSjMnGna9HrOwxNUkS21jpnP0Rqmu87wIHn0caWhBFmlNbK1YEWk0AADSRZ1Uk55zdTPS8VmaLaE3HRPXIuik2tR83p5VKNo4UGRsxWZ5RFUAsWnfYdBFRCXq6M6bH7n5t17wld/fcPxx5SAXXWGEeN1j2y4kqjeSDJ742aWRg+fe8p2x9JqGHeq0ekkSJbeMTwPIj9Xpn3xu1a2vXP3aX9k/c9p3jo5uGJt/av8VV16y9rxd+0/3bGQiAUsMK/OwYnYgChQAE5JSipFDjAgK/VDGglBMFs1ULLoU4XzTAlCvV5MkSlOnjZ6fn++2O5W4Oj8/770fGRkJ1mDLydcAXq8KEJZzjq3LWZIo8hbBa+ctotKJSZdaZ08dODNdmRquz3XmfF9RBLzR2U8ttZca69ZOVFVM0jp5+Dk+eOCi//dHC32KokjrwOgt9IqVUoiaiFAXVBnvbdir4nwURf1+X0eGmfM0DfNpBmHHAk5RiECkiR59+JFLL9l93o5d7W4PA1yNlGOX5xYQSQUbw0J0hgtcLgEDM6dcyG4oTUgUmciHw6IcyypBXkHbD/8XlCoERX1ZpvZYUhcACVjQaL2iJ6aISMBFEOTdB1u3GAuFzwNEJIHlmSsAFLZOAAM+rhAACwJEShtSghTS5NAAEJGcHQkoVoHtoJSy3gUPUQRQhcMaK8CcLUDIxIvhu5Q0DyiH8VQq1A8OLC6PGyj5iEqpKIrYOReyH8/OO621kuDuVPyKguMGQIaCCDEphd4hYhQleb+z90ynWZ3wvqsAAck5qyIBRw6NSPqeDd/d2Tj9lXUfefNlu3avHvmNTz03a1adPXr0H3/p0qN7u3c9OL92dS3zHd/N/vTXt9ZWDS3uVaouRNaDrlPd2b7tWyqFOY0xuc3yNNNWV2t1pRSX6hBBmRUAapBl+dAvvfGKO/70oZHJ9bad61SSSlXluRNmEOe8Ugo8Q8illMdM67Mb3Ibj063O1lX1fj9VYKxxumn8zFzerTtGEtscUrN9r10Vs74mPVqrNmv1NEsAGLUC5cCuQpUvrz1QvX7Hudw7PH703PBounHTeq3AOopNL8/zTnexUR+OcKifttglzESqZ3POMwKZlk6lJ20dVZM6e2tUkk5Vk7WTWzrZBidzVWj+3Dt+q7W4j218ffNVUmvY9HAv/0Gafo6FDG0+l06k2eLRM4+PT9wSRZGJ6xGNImmtIiTnoQcSkyog+EV4QzDaBLSH1ipN00oSbd6y/jOf+crp06cf+PH9b/2Zd7zsllecPn2mUq0iovNeFQxyCcsekAppZUTn/aAQwWXJdArowpXlKUgxfR0E3cF2G0S+8PkSBiMrgFqhAEUQKaMuPH+ETAIDKbqBGXbAGBIsn+SMA6H94tuDHB6rQl2HEVQQm1MlXisIHKIq/qyQXOLwL+Gs1lqz48H1rDyXIp95FZGB01+95+CBn1bPv3K3T/Xho/WFMw/86PGZo3uaoxUnRCQOI3ZOwE+88Jd+dvF3+smGR7JLhw8d/rd//PCxIz9JGms9zo1PVUbOKsns6AjMazzyTDp7LpLGfJ0nrgSdpMfb5EcUdp113g4rhWnmnFUEtSGf9zG3ojlNABjnY4UVX0nR6Wyhz5GgdBa8SbxjNGmC5J2SSFeyvI1g0EPE2hKlnGfN5p3v+Mjmvffc+L1/ZIW5MSlETcbHRtYeaU4mooBi5bL13/n99huPPvfWf97yuUtHa3HldW958rI/hsN1/5xdf/1Lu5mY2We3vPW39nzmj7d221nmLn3pTa0lRG9ZTCDsAi8TVr04YiFhT4NOTNBiQQDy3qMKrDCUFdyk0qk11CFKKaVBYGRkWCkVTCarlWS4OcIMk6umOkttl+WGlPeeCbXWQEgg1loTR0qp48ePVyqV0aFhj6g0WNcB1oYMBll+6T+z96ef/OS/fvazX/3e3T+ojTQrptKqz0INzsPz86rtzi1k1YmoOvKh9/7m5l2bm6sms9YCUsLMbB1qRYqISDwAFKKPUE4TETEUhex8YNGQFOmwAgJCIWYnJCDO+9yJjy7aseu+7/5g777nrrn2uv58x0QGBcKdAgCfOwAgCRJXrIPdIXhAhUSBg+u9ZxFxjpkJg+j1CkMkWtbxIClEUYgDowBV4axUULAHZ4QEtoNI6FCgB2HvRYLW/HIkY+bAYiw3VZikukJlpzCuD9JXxbkWcHpcnDgh5VeACGiFJbTFRQqtbx9sEMGzZyjE2r0XZlAMBBia/FzUDaG4EWZhVxR2WmtUagDXYgyJAAykQ6mU/Ss4oAErhxj6K8XdCHUDFUN0D4KK0IEAKDLCecgcu52lQ3MLUW07F0Rk0gTczytSqcQw3VK/s+Y/7KaX9yauWJpx339yuhIpp1yeEIK5+5GjOF4Dn3T6eN2m3utu/f/Ies84S47yXvgJVR1OmLw5a5VzRgKBiEKAyNGYYGzAxgYHnH19HeAlXPsajG0wxmBskXM2AokkEKCAUEJZuyttDhNP6u6qep73Q3WfGXzPTx9GszNn+nRX1ZP+4ZKH9/nJWRZXebWBxElPsiTXfJx62sREBRMAiKlnjSeP7SYGUDBZ6/hK78onnPKsk3/2zcO6udvyRFwdB5iM1buqpmnuyyrOhNRqq0r8/pOH2/cduHH+zC0bEBU4mTTZ1llz56MsU0hA1tBCSBfzkE/aqbKFlCiENE0xMd77rJUw22LUs5yO9/hEe4pp8/LycsBKxBtjJrqZd4DcYsYTJ074goZakglkHCCmyQyAlEWf0FeVDMLhLCEmZJxVcALp/KBAPJJgKmA5HSK0N225ULFAMK68zKo6rUblsDd8VPHhsnc76GB58VP3jG5ins54x7xa7yrnhKhlTRtRRbyrmoyBMHiP4EMIxChe1q+fW1g88Wd/9tdzc3O/9muv/f73vnnOWadW5aDVyilCsVQVUULwITBbbVrFSBDX27i/HQH8qgqRMNk0IerDUAkg+mKvjmOhCdJxlao2DtmNNA0a1gZIpSJxVoIAYlZnFjjukEPkfWJ9IMTGpdbSmmNBLo2HRSNHH0IYa3J57wEpalPjmmE2jcM2Qpqm4y1fIxxFLHGTZ8A4JyZmV41MpzM8KnfdcEORzxxZPnjykYdPe+T43f+24YY79qetsqAOiEDpCIGNys4nbpztPuXY1z9z4jkbzt39kx9957GDt810Jlb80o4ZWp/CcDhI2va8i5LrPTx6IIWsnSblxlBOFsWIhhZRC7dCQkqdAEWoAqo1tj3lhj2qsOKRBC5BKABXVJQGjc0CFqRZzimEMiCodZUXgxM+DDNK+lUZDKUpSVkR6rdf+2Ehc/Un3ughUVbwBQlQOnnr7GaZ6E44XvS9nlRdSbd/4337Xvqr+5/7Z6d/7sN9SsIp904/fFn70ie7HTP8WNV/7FDI3fbHvezEvd/aPH3w8qc+b+jUU5apgKiDgBpqkgsbjP4aShIRPyreB0RkthCbchEBwas9labv0+jkozKzAZCJbgrKoKWKUVcIVAHQWjs5ORnBhyJC1gigKgbQtN2uqoKZJ6cmkiQBg2yML7wxU2RD5UfGUDtv3XrrNz77pT9/8iWvfu4r1u2+aNePvnvs/rsPbHnaSXthabTXT03PPrbv0em898CDD3zu25/6xG9888RC6VlSAUJUu6ryH1SFwMTFTUjM0fsWlYqqytiCKhoIIpQlLgTUoIrGGkWtgidwoIpChw8fe/oznrZ186aqckhSFMMsTeK4EwGjo7BTFwUBnHPMTGQAQKUW12RARqugKiqshJympqwqYPLeJ2BQxsUgRsEsQIjTYmFERVC1tfWvQiQcu8CIgUBEiaITG4Bq8HVrHRGN4djZCCDq6kRkbHsSw7MXIV8PrgJCBICQaJw5eVAPSgQGSUQIFIExabZoEFVlw5V3CZCqOgQBBVFCQAUnQpiCMkK0KdZo78PMqBC8xDa7l0BMJklVBTyE4ABAxjL6kZAlMOZiYj0WAWLGIOMyQn2IR7MxpgxFarrkoALHzKESMwGLB8Px/uSGaarKURCDTLmK57b4MhTu1Z1vb8b9/9+h/++v/+Tzr3vjuT+5e2GRW5vc0pzpfun+Y/e7ssvpIB9Vh4vffMO2+SK1WBVlyZwZwypBQSOPPISAho0xRVmKQp7n1trhcBhvcpIk41ZSCMEAexsWBu2/fNP533nTz8LsqUW/JzRtfZA0dm6CavCM6jVDztWPslwO7dBzfrzUky2b2sW+4aKWR32YqgzkyiazRb/wPpjElCsnb714OuuPOF1ZPuwLITQTuToFDLphbktodEABIM8z76updILRqOqocosrgyzLtPQhKAB5cW5UWMqYWTJ1tGStJcPMFAJ3zGxibAjBVQNmHox6zNxqtViQQMFZQOmVJ4gtc+X8khpmm0zm+cTU2UwXVPNnZul3zzz5b2etGRVHK3fw4PwdpT9x375P4vLFKUx1Jjd2J9eldiKxXUBGUsDKWsozqwr9/vDHN/3wxu9/57nPedZpp576nGdd9ft//Ofbd5188PCxxKbQwCGx7jTXOAwiDCAqQGRQarqEqsbjEiKynnSc+NbZXmSVaB3bxnVibDNRbW5PSKhBAigTxZoUAYXAiRDVktHS2LA3jSkdb15LVHP5AUBr+0FYxUYBqJLUEtPEJF6FAAgVkaLdnEqIMD7QZsmhkzo/MIIh/mxkVysYRDSoGkoUoyygopCqBlQJ3hhTlDiqNJlJf744PPrY/JVhtBLuv+Eb1x7srDfJtIyKQpKOkEtLKqotz/rDV/Xfi4h7Zl7wk69++kc3fbebWpeJW9KTtrJ6feR+nWrj3GzwI+kPBj6d7So9u4e7pTLI3hRDnjK6MsU01IJSsj4TsK2JsreEUMLo5FNL08q8b7U65d7bWwM2CXqXGwiqhTNk1EiogFssy0q5y8RWUz6s8IhLW9x9xW/vOfvq53/gBdnCQbKp9b6ijgV5OJk6dNbTkyw9trSv38NWq4MtTpentn/13Xtf9lv7nvm2Td/93XJu75bb3jh56ZPLxcUTJ346aI/M6IHZkLfPv+rXXnrlhi1z9zw62mjMQIFaaEYKaIBBVeOBKRgPMiGK2sKAa6ds0ZsZVt2ymQgBgkTwEkktvkS0buO60lVkWENtPzkcDPM8zdI0mu4lSVJ6lyRGgAigqqrUJiGEiYkJIirLEhHzFpFxw0EpEgrf37K59ZMfPvz1T41+/sMvtGf9K3/lWb/1psNfvPbBG+RRANgll2prabSuUGlt3XXahZc+9cEH75+bPd1IGUBEG89RBQkBARK2EHwAVS8BQyztE+bUWB9CxAsa4noBKngvapCJSIjYuKoKqvf84hfD3lKSJOWoIKJutzXsD7I8Fak7UfXOjPTipiMU2Qh1MQoRZQmqioYkhMKX1EjKhRCsMX6sq9Uw9sZt4TqBjd7GWGfERBSVNWvFdtDI6qmHw4oRfFtXC4wc7Q4hnjs14rGuxkIz9KKoPtUk9VBrQY9nVEQEilHFlJmxFraNLOEmhRibsiEYY1y9sLSmcTT3RwSCSARVRfGiWkUrADW68/ENg4I2siQAEPUOvNZGTvDLKBgljKdnxl3VIhh2qGhs8DKXwI0P7B9IHkIJgVNDKt4JKzrPrtXlP+l8+MvLT7xvevu/fODinRs2/ubL7d9+7ObvPuRncnPLXYMUOy3LCwN35tTi0570+OPLSwYbk4lmXK0AIp6ItNHpbLVaKsE5lySJjlW7x2xRIldV2rVH3eC8cy/8tSc/9KHb5qc3JK2ROGtU1TtvicvSqSqhUYTSplistB49adQZfOXw/uv/wC0Olwu/6Eft9jQXJoFiEFpZl0wXyLqqO5EdXfCdvE28Hrwb9IaGJ6enZ5aXl355MhWbkGg40QAIODGRE5EhQwkVRREXobUpsxGRUVkQcuUcIibWGsNGosAMewlAmOe5c240Gnkf8jxJTepCRWQkOBVAkCAozlWVY5OAjBpXGDfdPX1u8ixGwxP3t/f/8NRd10xTWhXLS6OHDs3frYqIaZZ2s3SCKVtaWtn/6GP79x+84+d3bt269fnPf/7DD+991zv/79/8zTuvvuape/ceS5JEar462AZxibgqfM4KPm6KNTCCcfERdaRX+9JNch8rWgDAJjA3u1XjqaqICCh1wEZSpFqLREBX7XwjCyCG1cbBsBm+UlTRq5EZ2NCHap/jCB1rilQRYSLmqGgHaBgDRg0RRqrtpwBUlWuuAcq4xQUAEBA4gCKAhmATIyIomhAqYUC1Ck5xUGIGTAAPP3zw2aefvP2hhx/D9Xfnc0QmFMJk2gmVpXNQmtOvzua2vvD4R2+Vy2ZPe/zBr/6wmj+wbvs2gbLnVzZusl++s7ztZ/yS57exPDoc4SCsn5HhNSfgbFxeAewoEc/MC27QLLGZE0ukGY96YdTulkf3JskfvKN91cupXM46neH9D/ff/vpWuT9AZlMLoaWu3/U0MiXkWbvMRon4IeWlTVMLLvMwXNpw2o0vfteF3/vAmXf+IJAJFYGxzpczLD+65NLl03d3jgyOVrquk010sqWllTS1kwvnbrzurw89989FHQDke85JkiRMd6d2blvpHUq87J9/YBNd1t610/c4N3kPylQR+0bsLxHVxl4LY/3juK6CrLb3oAHBxD6rNPjBZioPqmqyPM3b7L1TBWMTQ9mwGHW77aIYOUJj2Vg+euSYEq7fuKG3tIIKk5OTEfRRuUBEEddflYhuSMjWti1NHDuy+IUvfvo33/img8eW7r3nZ+/8q8+94FWndjd1kx3GLeJ3v/jJU864dMfObQ/c+8Dy8olHH/3Zug0vRxgVI+GEVZXG45a6rsdoURJqNGktdFG3fBkkiPNefWAiZk6IgdgHQcSyLL0Pvd7g6U+/6l8/8E83/+QnL3zJS47ML6NCnueuLJgp3iSpLYHjELKelUa/cUJS0IAaQAUEEMCJ+qCqaZoaw6oaKldVlU2SmrEz7kRFicXGPkW1rlbqHBmQaqF5BAWN8T9qckXTFfl/UMQNM2p8iABAWZbRIwVXmQkAAEGac6HmEdV/uihGnNgYTuI8GxHZsAZQDRi9biASwVUFuOEjIWJAVYmFOijUlg7xpIsbHmJpvmqopYiEoIKA0T6zkbRVUGjo6dL0aAQjwAFVtXJqrENgqJywuIqslLfs6wW7DtUbzKzVkfMqKUJfDL7Yf2kLHfqVo3/2xy8/H4riFw8c3rQuv2CLve7OEW9t54hVUaYpuwPHXvnqnZNdObhYJXlLNIRQ50PRI5mbQ7w+kUUVkIiITQjBWDs+ryMcodVqOfVB3fG+vOX1F37+J9cpnIXtyhdiyZCgsdaLRHEGD8qKeWbLQzsBQLbvfWK2ecfWU006msZ8aIcLC9XxAys/P1o9eqTf66vtJi4YtZawandbVd+fvGPzwPulhYPbd+xYWe67Ju2LK4GIsiytiirLWgLeGFNVDgBarVa7vX1lZaXXWw4qbJiZyVhmjgow8TSJphchhCRJmLnf7wNh4SqPrYitZdSqKKPUatrKRQSVVIcAMCx7gEqGRuUwTd2wqgq3pKDGTG2aOw8EDXNVDZXcqFwqy5FzbjQql5f6IdidO0/fvevM5ZX5u+66a+OmDf9x7UcmJyf37DvRaneq0tnG8R4iOmHtCYBKRFRryzQF7hoZjXEqrM1r/HBrgHQcB2kdwwEhesihgGCzl6KYpcYDV5uDIr4/4C+///hP1HMiUakHQPVrTBlaezEUuQOx/xQNyFVVQA2ACKgGWE27IZ4ykaegWpP3sN7vxAa9BA0JsiEqURSAgKVMfc9VCWw/85Lfvvue9Yf2Ym94S2fb/aZrtLDWiviiGKSZGa6EnS/402v6/zkZjjy69d8+/elPP3jfTVOT3B/MY+hMzWTrN/s7v51AYu570H3/IVq5Qk/T8nmLo13iKhy0NEuS7qHhUhu8RaveBUNUVkcA2+3trcm9/WQzv+CVgwMr+oubC0tHPvHR9vG9TnNMRAcnhgYQQJJ1vliyBQxoJa8IEvUueG1xGI04/drrPzd15KHHffEPweQ+SJIWGpKCBisTJx096cogEHx/W2uCWtxbHCZkoAMrw3Lj3ufRTfsOPOHfuD9ryw1oMMta3XPPShenj3zvJ3LwOOd683Lrir29qTlBzRTJJ5JgQz0XH0UOYuUTaTLj3N0ASdObVBCUIE3JUZ+9Xrz3dWGGYIzl0WBEGTGbclQFosRYkVAURcRb5SHtTnQE0DmXZRlBLaEcQrDG1lhqY5YWTrRaE61W4opiZkvn3z74xSRJjh078ePvfW1ibhOl6Zc+sW/79s7kS3K3yC987esfPbTPKCYIOWZ333znFz7x2de/8Y9CAYBVlKOgmlwXG0feGCONAmLkBYH3AGAMuRAifdAYk1gbg42GIM4DYp7noN4Y02q1VPWUU05xPpBCPDetSaIZw3ijelUDNLYWCHEEHUe2DTU2Hk9xyznnbIQWWxuNGaRxSKzDT423Wq2x1kZTbcpWrF2emsS8wU+C4QRqSh8xetHVy22uGaLGugJi0/omJDYGCXEVD6lraiVmJoV4waRgjAFQ7z2RUUFSRSYmUiJfi5rS+D7IGj/EqI0XtQjqA6WJxPHimk9ac4KjjPC4LK5rFsRYGYtIaOzZm25hGA1LA4aMk1JYrXfulj2jvN0CP0JJQpAATpFM0MT63578r6/2r7yve8mvvfuO9cWeKy489cYH9n7nXphblxYnitJU3Xa7X7n1ndE1T9l1eNHUjtFN40hVGwmRenAeG/6xCUFsxv2G1Xqda+Be35VTaWt5ZeXk00/63Ws2/s03l6c3Zh4kpQQEyijkhOw1UELGEyRJeWIdjFqy7aHfe9bvFIsycglwj8Is7e6ay0pAV5wY3nDPsYeO30fM1jIb0x/2Ttqx+ee33Pq+97+/1xu96EUveNnLXrG0uDJ+slmWRaPrvN3yTohrPa8kSay1Ubo8TdPBYECGQTG2uFqtloo455jrVV2WZafTGZVFWJFuq6sFOhdGo5IoypUG0OCcK8SjICO50gHAYrEYQiirIpu2qoGsADsAES0q1w9Bg6+SJGHgdnu22yUistaec9bFxEJI3gsAJAl5D4uLy8eP99rtdlW6cWyz1rqqYqYgHoEiZR2poeuIKiGvWV24piD+f79ARK9N7StNLBRQijYoEGJSPM6AdQxwXE3OmjNq1ZB77b9G3oTWI2GENX5r4+Jp9aoQGwoCAICgICFxhIMERIzEB21abqqKwojIYwof1MEbmULpmImJQnTAFCxD6K0UpGYoVefyJ/e+8m8TD977SHfu+2CIjLiyAkEFSmj52PLZz/odmdj4mqUPH0zO+9C3H7jr5q8m3Cuwa6Acjo5vmkzvvs/tPWpz7lT9opOxBPe8wfFJNQPAqc0XFNXK8vFHQmd280VXLiz79uMfh1/7b77qyunLrwqzxtx5xeLSZPnxT7bPPSs790LcsJm+/6P1z34JnH3OsQ/+U7apPXv5s1duu3X05b+fPfPK8mnXmLvvLm78ZPrit8jZFy69950d53/06//Sm93+K+95csrtQpYTMy2ykoLmjs2uK09smYUT8zQ1rbmUQ+j5UafTSfomlarqVFN3/vahiz8eWou45WF3+NQiwVx4dnYbXKIHe8vl0WOPnn7mZ/cef9XMusy4wUgM+1DVQmzYqKUCgCIURRXhuyGEqqqIDJnoEAxIxLEPCqoIRKvpYO1/Q2gIcVSMxIv4yhKKqHOVMnTa7bXgZyYmwADBUhJd3EMIriojOaeqqompyZRb4qs0SRD1uq9/dzhaFvSn7j778Py+DdOTu3dt9yFZ2HbrTH/buVdesutIe3F5eO5FZx85fthVeHj+OFAIbmRsMg4wiIiGY1BxrkKsxVSRiQGYLSL6YsTMnGXI5CtXeAcAJrGhcquJsOG8nR2bP7GwsJBkWfzwzjlLTBGYqkDMq5QGBGgMi8ZYDCLCNXoUpMDWImJZluPwD0zadIT+x1bUX978q/+0ppDVSLRVVYSEWOOjQojy9EEFRE3DRxrzDeL7RxZWzWtiWhMvASIyj2pHVW34kfFoQERQraqKrAGEOHMXBW0sE2ydrGnj/FDr8tdnYqhtElAxwtkiA93AKk9aY84EtZczxsI3gq4QVtFhdWyDtTfEOG9sXgb0yiZJOwbve2Tfo4fz6W2EQxCSyvnAwVDJnl6efmMzHXtV8Y/loLryHHj3G1+9Ibfv//KNX3uomEBOMnHBOektLZsX754+5dRNdz8y6LY4gCZJEnwttBJF1cd3TOL8Js+iRevakz2mC1FpZAiapG31wInZf9S9/hWXfeY7/31MzjCmqrwzZII0jGsiQPZJUI+p7SYHd/fX7b3/keXZVut4b1HYWh0EHDhvTNdOd+3znniWT7cuLg+Nlv2iPGnr5hu++a2/f8+7PvvJa392175vXvfV17zmVwaj/nhRTU5OMxMQusp3JtreORGx1o51y5M0m82z2dnZsiyLooxLHVQj3jumI61WO04sW5321NQUIpZF1e/3B4OBoCKBTayqIZMOipFBLFxpuU4TvQ/zi0sn8DgQttvtqlBV8GVYXu6laYogSBQEfKnGoPelDysEGkJI01xEy6qKHTxjTJJkrvKISNbEHS2NHo4xRgUkOoA1I3CEWikWf3mo8T+yz7Xdo9qjt0EkxOUaNXih0XurmzpxHtyoTa3d5vTLclrjwZOCINYitQRrEJEoIegYs7m2dAZD6GqIXxz0RiBORGWSUnyO8VYAAEoAAG3gFM1uR+89IybILgTHaoCtwnDQkwEM2tNpkeD6hF/868Pbbr4rNYe6nbQoxaTOOR8oJbNx/ZbsSa8+Y/iDHaObP996+y/u/H6xcrTbzsvg1aVJpzhy2N50lyhmuRml6/zJvZU7gHrMVgo67xn+9/7+wIffY47vufBdn106cHyuWuHnXr3/zofXP++1FeV871cBwG3ebU7ZWgyX2umOhe99K+S2+9LXHskpe8WvZhdcbk9eX91xf3vn45J3vs/uPnvhuuvdbd+bveoV/tJLe4eWDl/wrJ/73Vd84e1nvukvFgcqX/4Y4dFw592YeGlt3v2217/tlJM+c9NjP3jk+HKYNDiYywyZbBigbdGUsthakHSQLm2759lvOfUzH8v66x3hvKGZU06l9sx8sUKj/jePq949+I2z5iYmMPQl1J3FMA7DMVhE7baYoDMzM6lC5SpmNhSbGqj18F8BAA3F+C2gWEPiIxiYAFATYxFZVQnZmoSQBSGEsLi4OBgMDHFRFK4Yxby1v9IjojRNEZGN+CAhhAcfvO/eX9x15OgBCXjj9+7Zd/jE/n3L27aenE1svuf+h4qNS+V9R97/3nd877t77r1r5bZbHj1yoLjh2z/qtDcrmGEYodY9zBhXjDFsDTIhU8wsACBSAFyovK85yt772ouJSBGqUNf4zjknwfuKGe6///4sy4DQS/Aq4/5PWNO+i+8QuYaR4BlPpfiKN857X1VVjHtOQjws4t+KzyP+7vgJNQ3h1a+h6T+Pvx+bGKvpDq5BrkPdhYKmozX+yfG/QpCqqqJF8bi1NX7bGEXqv4WgjedSHPUBQIT7js+RcT0Qr4lq8CgbY+rbwrzaq4+ZfgzM0pAiRAIKGIxql+O/KCJBV2/I+Hxcex+ifQUpMKAljoI+ncy0k+5oUMxNJdfddnAI0y2sFAlIFIjJGtYU/O90PvrV0TMO6nYdFNu3tH5w456tT3vvB752eEebglY9GRqfO0lhcPRNLz9teUDd3ETh8eCj4LBSFPdvcpQ6a6H6U8QGIK95YYOBDOozhyGEzCbecb5x2+++cNP8kQNZkqoqECTGIqKAoGHxAUSVLaGYQyf5HY8d7oWe95RJrgSSOU7aaDorrr/i9p1YUuwEgdnpiY2bZj71iWs//l/Xfujf/mPnjm3/de2Hzz77bFVYe0lVVXkJ3ntlKENFzMZaEztDqhr128kQUSx88zyPreaGYhvSNI3BgsnEVZckSbvV6rTbBIzIedbqdDqtvD09PRt/PU3TdrezacvmmZkZQgwh9Hq90bA4cvh4rzeKSCLFoghLQbQsyxDcaNQbDJaXlhYG/eHSUu/oseUjRxdEOctaxpgsT5PUEmtcdaRgrY3RKIiwsdHFoV7DxPFrIhqLOGKd7RA1dLJxwBtvtHFfWho/0NWqtrHcHsfy+IVgZArS+J2hCfncqAVE3Eac3Y53dHyNL4Csifz7cQxuttLqNdS2DxrEu3GEHp9X40dmjEEiacxGURRE0XtBEOer4AFJnUMEXBn6kpgtOADnN1161f5zrr5VaKgc0BNag6bV6ZYjt+WprxhmM7/DH+rz+o/dnvePPNpqT4zUZAyirNTO8vIF15QveerKCi0uPWTWLXsCEPU5mOKM84PRTnvb+b//X+HoseKLH02f/sR9H/94nmbDdLp44OHOkfsAoKLZzsS2vL1p/ic3L73nb9efvGHBjOz+x/LTzw99LX54++DW73X+4m0LmFT3P5xqUtptSdkb7d1nnv3SL8jOHQ/ffPHmAT31+e3LLrG/8QZ/xUsXtTxejjb87Z/wE87fms+9+cozf/PSDZOmnLAZtzpBhi3oK8mI2W27HQB2X/f3KLzveX9YJiMLnFRySEs/3U7WzYSQ5qPwg0eOXXvX4bQXWomxaRId42K49d4HBVWM/ztOiaqq8t7HoUCsiWM7qh4QrFl7ceEZ5/309IwLQozWsPfBpAkEtTb13hsjiU2Fraz04hv1estTU1Mri0tJnm3btmV+fjE4nySJc2CNDHqjPDMLh8sDjz52xnmTk+che7P+Rec/sOfnjta/6FdmPrzuvq2HN+nx/r0L1011OpPdznRn3Uufd8Fv/9prl04sT7XbASGooKyh9ERtqSCRzBxlj+vRC6jzTgGifAQSo7jYJxQRMMzA3pdlWXmv3Va+efOmoijGkSOGxKZ5JWu3gdaQKw0oSBS8QBAjFMNDXP2iWtORVceFbRg7+2Lt4lB7E41vPVN0LluN0Fj/jCBgE5aCiNbcbQJQatT2ojnM6naFplNPEIXdI0YbAJiYayX3X4rl9XWCQgjaNEPSNCWiqhkGK9b8DEHANUoaa98kHgdkzdhrhghBRLwo4agqrbUYIBYrsXGDiC742C2LYNGYryPWH2IclXWsq2cZg1Hx3mk7p6JXfP3WQTK7XipXIYEGJTRiUfQl3c+tp/l/7L1BykFrfeuBh0fXPGfbte9+ZZK5V7z9pu6GjRaNbdtyWS7bbM44d1dv3iaZc6E+LuOtYOba+EuwPumwHnlEiMD4jo15nyIiKh2AXjEkSx0wlZSHFvF5L7vkQ9/7+qOj0lrrQjBEELXGrDFAlsNQqhYmycFTh5f/d1UsnbNj05HDCzLtuUglA4eCo9Dhyd6o7C8dmOfhL+4dfuKTn77nrpv/6yMfPvusk77/o9see+zIi17y4kNHjjPb8dNxPiRJogwQAiBGFDoSMrN3UAUPKsYYEU+GM2PHja6Yfllrm0I9FpcIisF5k9hWuz09qyG4NLGIqMGhwkS7E3/dWtvpdvNRyxgzPTm1feNOkya9Xs+VQ2JK02x2eqMgWLJFMUSCJLXOlSu9xaha4yU4z/5IYYyZmJhIksSYxBgG8LEoHyPgYgUcfS2hHrJIADVjvfT/KbBRRzhYU6quDaioGFHKNS8IEVAb1xMYn5vxX6MAHTBqI+Ycl2sVfB19VWqVjyi5EEJEcYzlKsEgNaa/QWtYIiIKAhEqNjqdMagjaRBGWpt2/1KGgVgbJmK9JrVxXXSqXhUSTgVdEOnwaM9jRZjK5mYLLBnsug2Ty69+3d4P7u1W4lAHVZFSMuitnH3+BXruC9f37z2j/8VvjK756jc+NmHKIISSVB4pVT/y6zb0n3LuzL17l7ZS9zlOZ9stRNeFTsZ+45bTN2/avfyKlw0+9eH+Df+69R2fGnZ2h5/ev+0trx500l5naGdWfEnDMNseLsD0uonJ1sopZ6177q8fvuuxjbtnlx490t3QPbx/z/Y3/F7r3KeV+w663dO6tJSet3vltNMWb77num1Po+Ceu+/69W99y+J/fC676pLpJ1+9f++RzhXXnPIHb8ovuTI9Vq6IUKd6zkUXrJva/6Ef732kcmmbsDIJg2qxsOW2dHFHdvzU3V/7hwde9vojz3jb1m+/O6i2PZXqqBgI55MJLHB5w6HeuoxfdtYG58roIxIt2+pOCZrYDgaQcT2DiKqNu0DwqsqiwE1MaWYEMbRFV3kYlaUqG5MzsyBkecuVjpnjrEhEOp1Op9NBxHa77ZwDVAItylJVnXNpmtqExLtWa+KU07tv+8t/PP2sza96zVW33fWtDk0uL/euOP2a79zwo4PFshro2PaT33zV9pndN9/6naNHh7MbNr/hrW+VdmfPXUe27myR5kFDxNTXx3GI/j4aT22RmlEf1SiAOdLTnQukQYOwiU5dJCrG2CA+VslJkux5+GFkhJg4k42uZTX6GGCc3SgEAIgy8cAAAD44FVBspJgRy7KM5qaqitwMRxGcc1hrFpo6hEMdV7RuIyM2hOa49+LUrR6sBlFVgxTiHKEJUfGDxyx7daSEdVOLiJSa/vAaeWrfcJTHnWdVHef1EZtnyZJCtAc3xqCKV5Ew1nyulQTGuNN65TWtgqhkjQqkwEiIoBRTJDJIXkPUkLLWEqCAWjbxmUZp8vGBwk0jAccNdhEV8VWZcBLEO+s708ndP314z/HJ6VNIBqTWhqpCwlBxrtVvz137xeLqvW6Lsd4WeBzwmCsXFkcHDi+86HETP9zjelDkQXu93iteunlion2i3++EDMAbgxDEWuudcxqoUQ5qDutVexwiUlHvPTfTbo66pExFVaatVqbQD1XIsLVcZVvX/c6LT3v9Px/YuHOrF2GEJLHDEADAKFYuw9yFEdCRzWDdl5fuP/zdcs9DNJDjw2CnhVqZ3bk1P2Pb3Lmn7Hzw7ge++KWPPbrfSdXbumPjr776Nd10dhjwf//1H6VJtlD08rwzjjTGpl5FxeetlvceGj4bMAkpQ93FQYDgRQkoJkbOaSPcOF7kGpXXRJxzEiogmpjoiEi0wEptogo240hJB4CiHAEqMc3OzbQm8qIqJ6cnF5dzVciyTJAUAUnyVha8pAmlUzOd9uTS4sLy8rKxGQDkeXtysguoVTXyoUwhT5MsZkLj2TZZA0DUyCIQEQDV3kFrgfRr5DUCKHkZP8Rx+qiqyASGx1tMVYGJDWsVoOlpxzhdIz9l/M4YQKgJh4nhceIICRFjjMoJGxQJDcYQscaDOOfrWRsTI0ljFhFCYOTgvPc+zTNAjTRI4Hr+JSLUtOJV1cc6G0kZGVZxYTagkDKTppYHZSDCljl07wNZr8wuP9ePDElYXvJ7VpaXCmp1RnlF0hJfwbC/svPKl96fr/ub8r2k4X0/zRJckaxtfODQczZlNlqGkzZPHlxe+q+v6EmFuQCPHy3aQL1pGRkMcu3/OXjD592Bh2nhoWxu1xCD+8jfzaw8sjiYlx/elHS46xaGZvPUW/93dfft7tCRgx/5wIbE9753Pdx+68KujcVDR5InXEFH9meXXvboO97qbrtx+xv+bMlRftaleKh/556FvZPmV677h+7Pvrj4xu+Wd9/kFt4285bXnnzN+Zve/GzetH5wfKVqmcwPPUyCuifsWD/bMdf+dP8dS6lPggUImve33Dpx6BIwPLFy9s7r377n2X/Mi7u2//S3DMCw79hMjjqlk9Qriet/fa/dNlecvynRIKJj6V5UjLwSjM1RRK318oxBJEG0bDCqaIg0rpq1L1x8fKhgmNmFcmZ2AkTBw8pgqQo+zbMsSZ3zzOycy1p5nudSuojoS9M0jEbeqYrL83ZRjVzwAoYopcQvr+DefQ//0z/+8z/9w4c++elfJHZqosuvedWuA/nXF954DADuevoDe/ko35Qs3RBO6WzcvfXs44eqyS5u27WOSI0gk0XkKlSxie4Kl9oMjYgEYiaGEAIbDiEgAjKpCKgyo4ggU40xDrFAq5iSzJpOTnseeXB2dvLU3eeURWWAK1eKiEECREJMjIlIIoMUQkisjdwMgxSKSp0HwsKXWZZF3Y9+bzA1NVUURdzGMTevxXiIlMipmMQG71nQGONDICSGaAaoyCSgQSRSXkiBsTa7QiZPCC4AooEIIUYhQCZRpSAmCp0QelQEMBoh2o3ZjkgMsUoIhkK04AghOiYlyCBaqZAhAiIgAPDBB++JOZYC4gJZg4gRrRfBAoDqg7AxquCrQCQGqZnmRrBJTQ62CSMA12O8VUR+nE+Lodp1asxgVgkqUPpxFzEelFiPYIWrkWM2vlpvO++58dFed/1UNfSQSnCZ2qDqbPWK9AsztPSBldc5KohaE3k40u/1loudUxMX7dhu8uM3/OXN6fSWgR+dNrX0K9c8+1CvTA1arjXNxRASmSyNhFr1HqCG6UVFm5j6WGKHqhKc9xF5i0AJkQgo2VAWLrEYJCusZOHIwRPPv+by//zSf/xkhNNWKvXoyWgiWpS2zRTaiB7VPnIWAPyC77vzutmsYzs4KXb4cK90ozB44Ei7OHjq5l+87fUnX44vvfiC0YG9e4OrXvac7dNzs9t2nbTjpF1Hjy60O5PjVAagnuIDQCicIVKwDj0nBkSNEgJU4hxjizOJyqohIIJhAkIFIWMlBGyGEUooQY21wQevIQIdRJEBFYWJgjonAYkZyRJkSaYAo6oKpSSYoNQ8GSeBogNgAE8AliFoURRgeXJ2dm5mrmBx/SERJe3cV65DlgErlYaRT6s6MEFEvKtbx06kads0AbjWRV+1n1LE2rh3bflb55c1jBoEVBAYiZEggCOMK9x5H6j28cVQU95jFwdFpeH4VavytAzNVJqJPAAyR6pifEwkSIhRnVYQAMiHYCOQAoCxHtl4FaiqBBLEyLysW8yISARMXJOSYxhQ0NpVBmMULilH6VUM7aH2bRpkcQq61aN32Fse9K98A6RMRehJdcctNwdXAE45rBKXF6Plx135rPvp9Jnq2GWDj19//PSf3n5XO8sgAKh3QsZkjkYBZddm2PcgHLg/OSkNxbCophRFSrBzYnXxQTj+YAe6QtOwdNj/1WvRi2Kr/2evqQRYQ/5SLU7aFW6+x7Uq+8QrzLc/Uf3wq+HdP8wQg7Ix+eD7n25ZOHGttF1lErP47t8MkNru9N7vff/Hb/70Zdf9w+6v/G3QIj+WZUbS9srs7omW3Vj0B3JiiLV1eIuqojA8yHHHptm3PXPuQ3fdd8Njzmp7qXW4mtnTvfU3gLny2t73lG23vmX/Jf+cLJw09YunBJROzqGCAqosy8j7YuX41x9ITprYMNPmUnyBOOPNCjvFkIfEYUUGo10Ns0VUL0EloHBFBKIMyGxUJUJrXFloy0dfOAUxKirO18Wf891uVwmLqoxJsUGam5urvFteXMqTdDgYQMJZlmnj1TMa9AeDQTI9nbQx+CCKC/Ojq65+7mmnnfG9H353x65NSMlgeOj9N/1t+BcHmwMASC6FDMJFPfsx2//Twde+9ulXve4FBIGACQQJ1XtgZOAQfBzBegkaxHvPtOqDFGNDUIm7K4bAuF1VVb0ScUCpqgqFXdCs1bLWjopCRGKDNCrIsDUAqArGmGjlqE1vuaoqTKxq7Vofxy3xB6J7Wgghy7J6MzOp90QUKidB0NSlagCQqgIT20K1Iq2KQggaQmITQQVDAvV0hxSsYODavSQG+DHCQqHulgtgxNqgRKRmo8LRWFfFADY2bcQI4ARFQkaGEKIkPEdztzVFwzhHi44RGgSJlGoWNBAaE5uT9TE3rq1BV7Ggq00FBEAY99kgBlXV0JyPFE80E/1wAjRumjEMB6RRnpuRiEmPHD347fv9xFQGZUAKBAKWDeO0jN7UvfazxbMPua1tDQX60rVSOtqegNv3Lf/0O4/c9WiFrWnRcuHI8B2/elpnIp8/MkhaUY6UJB7lquCFEZk5tYyIzvsQgoQQA4CIFK6Kj0lBEYERhRGJQTUOIQVECJkQ0Sb5RADzh68/84V/s2h2TnkHJet0KH1qKl96ZnRAxplikpbmzEn71t37NJYW0gqVlEx2XV7NwSaTyl0PPtZletwLrlpeGC2vLLXz7NixY61Wi5kf3ftYu9ONIo7jFzWmW/HBWGvr+QQCM6MCg0aBPESW8UOhegGI8whRbwWC1hQdIrRkOY5Latacar0REkKQEFGB4GuZM15dBqqAQBFXAQikUbw06lAxIhhiwIwhycH7ID4QUZJYVSUJsX5FXbPMGssBAFhT8a4aohjiqISjuoqbY2MiOiH+8Hg1UqMYVX8nMoZjQRxTRabayxrUUy0xq6KrGpMxuSTQyGZDbnpFIQQhwyC/hNiI7e7IoSDVUDe/Ke5ugxT3cqyrxlAV9EIKtMaXJX4MQYBVq1YQERBAJtURG8hKGlhUf3yiu3Hv9T9tfe3z0wWPbv6+efIzhcKxPcceeviB1oQJAyDEYbVy3jmX/sqf/t1H7uPH3fkHnfX73/mD2cyMmCa8W/SaQLstVWEq9ElqunjPL8rNmy589q9dA5//Ahz+bwBMTFJCvyNThm2wlUIJDj3nnCMLZDiV5iEZhsmddrT+HJyb48nN5Z03632/6IrqxLqRq0SGytoCKz7YBFPu+Cx3ULWqQRmWv/Sr/3fTgTufcsP7aLab+pmlpUPyW3/x5A+8Y/loMez38jwflVViMgCIsuFSlVzZNM2K7LFffOVd+dxV7rRLR9tuAYDpIxeKkyw1IDR9828MJ/cceNpfwaPvbZfnMBJ6bxLjQ2DQkKd7Dh368oPhNRftzoCUwJVVC60nqLSK91wxROYkclQrpjjZkeiCZ9iwMSZBQKoLjzHbEyEqH9vEVMF77wUhMTbGGGvtkSNH2u12PJSXl5cdSp7nZNhXjog6nY6KWGOkDEjcbqcLo4VuN//Epz5++OCRbTs2u1ABdunPR9qiaqYCBdqIpZS4iMG7+Zcf3PrBU3btPK0sDCARj4pCmDnOBa1JRIOTIIAWaKxXEwMbMSqA+OC9T9N01B+oapZlZVVZa+PtMMYQm36vAMJW3tm8bXvlyiTPEkhqNJb3kSIZfWNieydanplIK1JgNqhKyM57BFECVRhv5uiS5FUiSCSqOBGRD6HyzhhjiINItO1jiGKZDecAqQKJm5UVascxBqm5S6sTXKWasBjnpQDAiLXNDsWBv+emcSpRS0Siu1E9Po6RL4AQkQIQUJxuRsAar9GRH08y4qvGgQdR0BBWpwONwXl9BI4dIBSi7ABGYpIZG0dGopGOVYlWm3K6hulRP2IAVYEgDBoocaS7NvFnP//YvuW52VnINQxJAMSqquIr2p+dxJV/6b+2YG1pWo7KJO9XduPvffCh3shMTZkJWzo1vZIvnS1f/pLzDx8tWAg1hzAq1I9rbohqoyFEMN34xK9nw7H/H3wEA3L0W6aoNCRai6mBZUbk4FWFlpZHz3ziFU/b9dGfDLHdmpIw8GysZI4kCUYV2QaCyuzf5bbsCb4zGoHghAWPFVGwg8yvHKtSKTsTZnlhFECn5maLoti8c+doOEyN7XSwrKrYqFiNQ6pMFghVFNZwxuIDBgQGRkbf+Ntjk1OGUJfOOkb6NOriOjZMECFEMtxA7QAajnuMr/EVhzyqKg28mKl21RQE8KtktjgcCYarokrZIJLTGjaIiCax0YctZsY1aolIa1m1um07DrTa8HPG8xpkbtaYEtDavjSsQTXGBRBXfuwMGwUXBScBIIgPARApMdS0oE1tvlDHVI7e31xfEagCoGHjRep/bXrI9Sg4VsWqqBJVdQHASYgokNhmW3ttkdEXq3xpjg9ERMGoi1unrYABFEQz5p4PjAzlYGJm/YmfP3LgD/5kfen65bH09tvgSc8E5B8/fPfC8sKGSahkqFnuhqOJ9tzn71qeS5I37b79vqObbt/nWllHVBUTY6B00qKW+mGeVZinB44sPu7KS3c/5QXHTrpk+XOE+o2RL6bTqYDq/AiddE0OhKMwQmTVYMwEZFwllCcHjxwYHP3W25ORp9t+OFkc9V2qwjIpsySAHGDkjAfqlkpSrKQoiSRffsU/jTqzr/7nl4IdVvPY5yN7nvOanyrl193+hMvP9SGMXGUSy4LeS9JqIyk5rkaSpnrjjQ9+7/M/OvnsasvMugcvujNf2pkWm3wCKAHQiuWN1/+v3gv2HPqV/33yF957cPOdbsMeBpsePHXuwSuDnyysuWnP4tbOsaeePMejkRgm9YjWsCCyiCBjBC+LiHgPECXUgK1VrIUqQ6MPofXzVAAwTSKF4upZ6aA/mJiYAADv/ZGFxagUE0Loj4rhcDgxO9VutR577LGyctu3bhsMhxOTk66q9h84sG7dur37Hp6b6ZZlefvttxMbZmssrUz3wilSpRWkQELdfnvF9mQqcM8WlxfT3+T162YfeaTkrBoOwKZMzOIFsWZHUGqIjHhXR7gGBYNE3nsANMbgGp3huM8JpCgcpQaY2+32/PziM65+5sf/86OHDx8+7bTTXOVjfGIkm9joQDLek6sxnigSABBJEKLFWnRVE5E8z1W1qqpYfIuISWxwVcRnihMfREiAGA1jFNZQhSC+oQ8xczAEohHmEY9IUXXBj2nEdUxqcMyIAGNoVWgqbKyHkRDPnbHxi0YBDUQiSxxAUdSrSBCLFDtZY6NlaNjl8UAfH1vNaUWWwOuq9wOgIqIZ+5wzINXdPwaIHW9Y8xIExDqF59pWY9Vu6H84E8cvSMEgudEy5BPl0vEPfOnYxNwu9mUAShMWoMRDQoM3ZNd+YfS8o26LMvTcwLRBh/2OnWvPznZZqpVlKHJpq+yf/+3f2VIl7JYDJ6kuV5gjjJwHRaIkSZQwErAVKUKyg4hgJEnXVxvJNrH7IiLSOApAXUbHa/eiqqDeh4US//hXdz3/7/bg1GSy1PIpBT8IWa6jYZonxiRs0B7aXVz4AzB7507+aaoTAY4iVCi26OFLH//cwX1bRTOTJr4qQxBOkqpySZqBAipEFsT4CqGR448JnBJWwUf9lPHYE2JnJQqnrsEekjUYhcmah9KEkzokx1nvGGwSLTmtYefcWP6pTqpiWCLEZkMhxsAgwki1v+0qhDCgEpFTwbXi5yLia6HjVUhmAzzG1XUSNRphfKkRyRF/jIERIIqrYMMvWAU0MYEPGoKMjUwaKBZH5UkEEI0yPbHnFxl0Y1E5wQZYsQY/2GzV+iQxSNFyOKwBPdRmR402QIgenYgaBBqARfwsSkiEEXRW78dG1QeanJuaVhkiGkCvUoTKSOpIOgksH+/d84dvnthza5jelggXX/44X3SpPO0Zj/zkDoN9Ky1njR+Vu3acXm47c9nOPP3IxzfLjX99426TBW8KCRUQoiYd0sArxcheep7M5cENZs8+/TI31KSbbnz578PdP+PEmRN9MTTJ1iMtUNkmapXsgaxJfAKapu0WpWa48p3vt37h1AO2JkOa+ZEkoGqsFzKGRzTMJB/qyKC2PIXE3Hbxi++55KXP/fgbN7h9K4sLndPP2vDmf+6efc7R7/zoPf/6L4dPvOR5z3qWBOecq4IgIriI4QBOgoTeB9/7LyE1T37cup8ceu+JzbdNLF4MAiSVOkQwo2ox9MrNn3rHgTf9+oOvfGO6sD12Nvrr71w549sn3/QnZmmnePOt+47vnGudMWGXGTNfeeUUOGhkmqhgYGAisiZlZtUQQAVqXno8umOwpYYRKiIGAFJrUfTI0aOdTmdqdibzIU5c0jTtybKWwU5bYgQJO3fu6Ha788eOG2O2bt26sLi4tLiYb9nWL0abN61/ZO8+7/30zpO+/70f3/zT2yYmuv3hUrczU0wSKOWz7BUml6ao0FaaDCeqZIKLQdhyzpleQU1BhlO2EOUggFUxKvKwNUUxtFyvyHj2WWsB1Tln0cRoEcm4NSsretMaElUmGvVH6+fa11337Z/fecfs9EwIIVSOE8tIqbHqAzERN8eEXyX50RqzszHNI+4WanSAI1QNg0cCUInE5SjgkBqWWt2CUqqvM2iNlI5pLDsJoEroGVCAAC2gBvH0S/EJGicGrVuFzWETgcrQJA1Sh/Y4DTLE2FBaiQhEAjUiUxFlBrVuJdSDYwygVVXFlRRl32u1KyUAjoSm+qRDkohNaXK41VjbQFWlcc4YnzuxAaANFmb1YAUY690H0LGLakAVzLZ0ky/f8Ojty90tuzmUWBrMVZFQLL46/WwHhx8Y/HppIHPqAQMQmMlhUAjDURFM0hm2BsPF1hNOCS941mWHl0vKpBvM8mSfigBEjPGEQ4iWEhHhIiqqHKHdABH+E59CrP5V6nE7ISqhOvXkETE2ZpgBBMnwieXlxz3p4qd8av/18+Vst63loDA5lR7TxBkMEKwP5rEd4ZmHDetcZ97o0REOrViTpMtm/2R21m+98ZV2BgVEVVCJvVgyIfY3mUxiOdRqIeMsIfpsNFqn2Ox8iL1cAEABsqyqkRYWdVIJ6k7AOJyHEFZ1KgzyGvfPuOoUwTnnKm+tVZFgMAI9SVGixOsaphmMffeaKhlAUGs6gLHGe6+MRiOwPHaMIO7r8U4crzQcgzTrEw3H1zzu3GKjVqHUYBF0Nc+Lwj51j3dNrR+xXQqKjas3JhaUKSiKevGEjI3JoAIgRpXfRn8OARA1Nqwi0NLU23OcSdSLHOtkwnvvnCNrrLXU3OS4kbHBdgHhGOfMCmN5EMFf6iFBk8t68AzGOjtYl1fXfaPziztaUxPlaLnMiZYeks/+68GVhYP77m0lPNTMkyz35l//xj965NQXZEX1ivyrx+fTr9yTmSlwgZhaCFZg4JTKXnfXrqUXPT+/9+HB3I7Hn3LmydWgSBKTGDBz68KbX1d96vPJfT8flSvQXt/1kNAwtDBUiQZvEZL2umymAoBl6BDxqGU7YRDEh8yCI/bK1nmocm9CUnWBHHMPuT+x87oX/f25t3z60nu+2ls+Yc948snX/kvnzLMWji4+52lPmtq07Utf+PLCUv9Vr3iZomDKCkEDaAAvcPLG7vvf+/4HHrlr9onph5/zGdgtsm6lT/fc8ezfaN/+vO7dV6hqIJ8hg0XqzfgNe8vZfaCIilx0gXHvE95z+jf/vkQ8XMj19x7edvkpoL0ARKKFusSwMUajRL4EEFSNSXCINjyIqIiMyCZaODRG1HFcoqBV6QAgz3OyxrugzSQVAObm5vqDHhuqRqEsS9tqj0aF+JAae+LEiTzPd520uyzLqZnpsj/0Lpy0e6dhfeiBXzz84EOt9nSrlfsRzHElW2hkzULw87JMQwMdEVHXB0J79eOe7Z36yuZ5a1SMrFVGYjarGylOf9GM4aljHXyDodZyIirLMqoaFa4CABWlJMKLNU2SKFN1+umne+8jmM2qrUMp1uDnIB6agVAkYwCAMQZEIdTEgvi30jR1zhVFMb4SDR6VPKgK1CNSAIMUQJ04gChfCYQYwUcB6ulpgzglrGEUUfwGY8VSl79NgxcaRkQU5ozExoAgUBdf46cbGppTCCEC32MsFAQgtMSxoFeN1qjRXwXrUVecmTWN6OZcU4CwWv7G9D/UVW99eTU6/5fIEjForXqVhxoRujZgK6FpeFaIOO4rqmrwnHVxePjIX3/o5+tOevLA9zdMpIUrRECRJrH/2uTazxYvPCEbUg2qglpCPzekOSwT2iRNB1BBYLu4/51/8/gF5uDQoi5Zr4WgUzFkjCFALwKVGGZD7L3EI5uIBCHy/BjQGON8pdIkNLEHzzFJERRAQ6AI4AkxQDDExtsqbb3mOVu+9S/zg2nTCQpBLBhrwtAzAlmi9NCpABB2HgPpBDqCbtJK4vyAk90/euzHl+142dY8aeVsjbFokME7YQQ0WM8X/1+VicYCBIKAiYG2CV1cE501SC0Q0fR+IIioYhPLm94LNrkmxlURLSYRUFVRoagcSp1vqSqt/XWFMT8vXh8zo9QhCiAWjRhrhLg4EzYUGsdsa1jBl6WSalOLr6ky64/bLDMOa9YnjuWiQHVNFhtAaQz2ri+KEAXWNHsQEUUDCmtd5wpoTAFIQcms1soiSggQECn2F8drfvWJhFo5BBselIAAoCESkSr4SPYd79xauiFOvhs3p/HRV0fl1X4YNsq29YeKPSoiSg1bTyPr3Ylq4Utf2ZikBXlrq0Bg59aVN9103979i3lmyHoMadE/++JLvn3PQdyEL5t87NS9X37Pz6eyiU7PrRBWqm1QT2koqjQx1XOuhvmFwV23DC56+lVZN4X5wRJNHv/Gl2TzwoYrruie9bzet75RXvcZu+9nRgriNgOi7Qvb0pWpjCaSeQDIvFtKggfnRDOb+co7LSFtSXAhqCSZESOZKf1KntKXX/uB9nD+6i/8cX/5aOcZLz/jg/+sU+sWTowm0q7u4iuNmYHnffP73zlx+Ohbfuc3lbEYjXJKEAEMHl889onPfn7i4vUPv/XnmitkAQCCW0nM/MolH+eVsnvfRSbtAtLC6d8EsVS0Je9DZVFtaPUA2QEd2XZTZ9+TU/I37pfzNi1esSupMEUAqMoyjvCsoahVixTFDEpfxu9D9LdrhFPqGkZi6oakCiGE4MLk5GSapqOyEFBjkhCCaBAN09PTKysrzDwzM1NVFRKxsZ1OhxQymxTDEYgG59sTE2effbZhXVk+evToo+1OIiIr/eGGLcU7fvc8eAwW9ogMEDoiW6tgPfbRetqyf/NnP3TdrT+9e91cazRcIeMgiDjvnIs1BzMzYCfNx2CEuOxGo5Evq1jdE1FVVVFSYFgWcZmmrTwGMQJUHxKLg5Xe8vLy+vVzitBqtYDJq5RlWZRlc/LXOySu9ZoeKhLjcbTUjd+MyUGcC6pI8E6DgCiKBm2wiKpVVWkzUi29q6qqck4aBYyY/2JiyDAjsQCJQhAnoRD/P6Q5mkMHo9xVLE3qn2juyVgfg4hsI5gVT6oQpQZEQiMILlAXBwxIChAkhFCWJQQxSPGb8Yv488bEN6a1PYCxNMf4CyJiMlzbdZElTthE/DA2Y7Z4iEe3wbFhsDbKWV7Fa90VQEugdjYPn/nxgyf4ZCuA6ofDE1IBkUGmVyWfyLH4QPXahLAFCAxkWtTVZZYq5VLMcFS2Mjvai2998bZzLt69PN+zLZMkuaJPaMJAHu+Sl+Cci6x5aSTBAcBJUFVjTJ6k1lpoegnjFzbNUk4NWaOKzoXaxhGYkLMET5wYXXXVRU/Y3k+qiUHAtlnx6HQI5MSSQxTYfxII9dYfXOy3yIWWx0CesnxLe8IF3rd0b1IZViEFr+JUwDIatMRaeYie8GteUZcBACwxM6MKgaIKoI65OkQUaS/jcDV+OtoICERtFoNkkKLgqIiQNWQ4dk0YkAGzLMvzvB6VhlBbXcWG7SpyUCVyFRA44tvZxD8qjIjIComxsUjVqNtljQMpvKtbKa7WOojvWde1a9KOGnIFq43fuITGS84Fv2a7rBLeRCRA80WcOUTMlGgADTFPDRKcj2UordGfGfd+pVZjqBPH8ebFRrZwdZRLq78bSx1BoIRNmhgkFHUSoiMONGlofShJgCDqQ9z7XiXunTpyR62beHlMQMieK3STrdbw1p/lt91RuEFq0QOnPaOCfqZzaxoEocy0pN7Q8QuufmH38S/KRvNn7P0HC/4zd08PZCRqGBLGFoAMToBfOfDUp9Kje8OHP0yL5qxLz7rArZTDqYnillvo+o/DwqGV972HVlY2vvw1s+/7hPnTD4Snv2Zl6+n9tAulymCQyfyOrbeccc4jqnDWE/pPeGHvjB1D59wIjRC2jVg/MuAnMrBh2ejyaDQ/EdIbr/jTo1vPe95HXltye8Pfvv/Mz386THZDT9q5qaScySa2nnTqGZed/pIXvejEwvxfve0dS/PL3awLAMNRb2Y6/dp/X//YkYWllz46sTHJdiPOCQjwdFXNHEEOS1d8PZjSld4PytHsfeKdkoPKgnXJYB0oStIX0GLjIxmniDjA9PoHjs73gA16wAgKVlXxQXz0qfcxLTOJBUJVRAXGuLMizFQ0+PHSNaCaZZkxBhmDCCeWlKqqUvAKVA5HzrkxJLjVaSuTSRMEUtWjh49MTE5Za9GYyhXKsm793P33HOwt9Xbv2nVicdiZSt/0ZxP/9a937z/CyQcDHE5c7qmFHWOnzYydoZdXZ9LT3b/9x//+u7/7SJbnrjJZQv3BMDWJzWz0swMABFHU2F+NF7OystJKs263O9ao6vf7RVHYLK2PziCqmiYJAARXBZd1Op2TTjopbyfLyyOvAopZlpVlabMEG+6s85WBesNAozVDRNqEnHg93ntrbZ7nIjIqyySpAdUaVYSifAZR7RxMRApC6IOYBsHBEC3E0CgFUEVQRmATI5+KBGxaTFEHQyHOuqAxeR5fpBIC1coeQTVm3MwcyYLIBI2mTyzbEBFEjbXOqUogpBjsYlESvI8HZ/Ae1k7cE1MfcCAxUJFha9MgPiJD4rlWO340Ej+NukaDGiPE6PIrqGvq+3ikomFEJcCaAhwCqE6s53t//MCfXHv0lIsuHi6tMHLpuyZLzsA7n2RufEP20Vv9+SaAoFTG22FVGXZDl6RZKIRhmHZaK8dGV5y2+Ae/ec3+g24q7/rRQAx2bTbyg5CmqYKIAmCSpBV7HwIGHwvf8RmttZW6gionVmL1jRQgejkHAAjBMSWKikymwdRoAMHEYJFmU7/+/A2/++972lsmfH8yGKcgQEkQdeJQiY9uLTc+Gu4+l2Y7oSIIASVZCYOQDg4duqfcdrmfqpA4BhVXVYkhECAEH4IGqQ0cAQAgTZJ6DGwMEwE1a1jVSQjiasa4ABEZ4mhki42DHqwRRFsbqyhaDxHFDnRcLRwhfqLBe2PMWBIyZq6yBrc8xhOh18CAoBgkqAQSDYGDpClZIsWazBbUi2KaZlKW8UrGwD1Y01zBmgIXy0+IhBzgRoR3TeQjotpByNfBm2rFVqp9QTTEdlSEKUAIHlQYLbFVioOoqgGOjYMoAESFsSQqcQrAWKBDVSWgMVE4iZlrrVZVZaKmZUWGNM6aI7W3bmjVIDJoJtaWTYhYMKm3fOynxzx+Fa5lONqcU7A85X/4g1vw7z5wJiyfaOtgCCHosAudqngs6TyKrbQEW6VV0Jf8ym9OnfaE/tG5p+YHzv/Fp7/22MRx0x6FIh/ZlYpdOJFl2amnVi9+zjpIwwf+DdLJ7MVPeW5rdiNx6Q4+6D/69x1YQcTqjk+Vd98JV78yfeZL1j/vFXrNS0ZLK+HIQXzsIeofuSi7tg0LBucVCjuVY4tOfor3c63HbvJgYMlOkk9S8ivowXYRnUW5+5wrf3T17z31wa9ve/1vbbzyinWnbXWD5bxIRu0QQqCUB+UwZd65YduE6SLD17/6jf/7zve+5c2/vX33lmHZzxP44bduUFjqnTVPjGVSUR/tUuKz4CcqSJbJU3/2ft53TlASIWIURJAEApbdowBxuqcsmlSC1LYS7lwqbz3cu2bSOjGQAvrVfnKdfqkQGGVUXX181LiySo0QVFUCEIOIwBREimFhrTXWMNPKaNAy1gfNOp3RaJRnLRJkY+fn561Nut3usWMnnHPrNm6IJPjjJ45Mz8yYDhZO2lO7120+dTi4a8OGLc9/0bZvf+W+678s207dWr0tnHj13unz7WQr966VPDCX/Uv62dtPnHJKOhqd+JPf+933/fN/igk+UA1A9Q5BiBIxRqAiQa/eV7XczNzcnKpWwXsJvhIQqaoqTdNWllZVRQqi3rIdDEfGJIGkN5CLHnfpdd/8xrFjS2mSGWBAKoclmsg4AEF0qtYkMd7EswMNW0oGo36SJKBalmX8JrDxzrmqQgRrTdMGj8VdnLAqxOS3QRFHt20irKqKUpskiVZqyUqosDncMRJ8AUC1nkoSOgkGSUUZQEXUsMRaAqO/cBzQIgG6eHwYjkUyNFocoIqiARtBHxFPhN4RKDJjrDBUI+rNgUKEUNVADyAypBBBsxRUg5KCJaagqlUcxXmUtVM09QFC9AOp8bRa60kjIkljje69d8ElSeK9B66cmMQjGnYkOZgQTCundGn+975yaMPJZ/YXFnySIkgLlv88/4+Lk9vW03ELbo4W/mnizz8yfMn1oyc6SqAqTW6hX5kWQaUYRJeX3/XXFy2Ncktu5MpoBulGI0S2BF6CaWoUIrJp4spKVFgR13QUJap4goL3BpijFboKEQJYFC2qAmwwzACoCCoaG5gkXFg+sVw990mXvf/aLz6wPJUlntFqAPGaMDJam9rs0K5q6wNOnggaFCklG6xJR5Xi9CPFI4eHC/molbc9uMSYYIhFKRAgiVF2QaQBtQFAqQFMlGgQUeCAEjxwNNVQY2xogPpVVcVxb0wxoZ7IIBIxkfM+6j84EDBkfN2mBu99Vakx1lofQohwfWvq5E8iGQNrn9DGMkhKJ6XLWtaToKiCr7xDJkumkKqoSjAG44jUcBk8AxgE9F4NGTQxcIKCd84YY42RWipOIM5EARQJoB4AxRQBx4TaoEBNLhvzKkIEEFAKHmHVSsR7LyjMbJAQNHhRFkUCinMZolBzbuOEj5mZOGIbiSh2kta205yEOM5oGASKBKIB2DCwJQYBjKW/YRBlJBAFwGh/GUWkRaQCIibmRq48xFqfGClI5auKTV5JQF/lScpqPLo86Txyz88uOnpsKXVZmVSQ9MKKc8GE1t2aVOy5skQABn96112PnPr8uVy6N75v29alV99x2tH5IZN2p+FxW/3u06tt28uN61sTqf7HRxZHva1XPbV96uMvYLBF5fv/+eH84G2DDS2BIjcdOf4w/Ofbl677tLnoafnFT0zPvsCcfBZefPHW/R9oP2yzyiSjChXzjiriINl5xla7+Kp3Em/CBDKPpbGJcUbzRLjoJNfPbzupBU/51avWz5r1KQyXl0SpB46GEaiEqjpyDgAmJzpnnnQSPPNJ13//lnf847+84Q2/etm5Zy4dPnDnbXf8/t++4Z3Zu4ZuCAJhEWUhYBugK6rD1K7rbEg6/Q3WJvvmTx9uP4xlC9KBCmpSYDCmmAbFqSNnkcK8KSclWDE3Pnz4kvWduTlTDhNgw7YmSkSiTtQjZDRYx98IKDagAAqhcqrqUQEEghgicpULbc077VhclmXZyvJQlkmSOh+yJBXnh0XpXJXmmSFz/PjxIAIMIThEQ8CTk5MW26PFwlG5vDif2NbSQnji1d3F5dEtP6At2+bEDXvfkree+4R1U/6f/3LP/D1mc8l7jx7auuWkR/cdW5yfL93RH//0Jxdd+oSyWCHIRZxJVDy6omJGIJWgCORcMdZeNsYMh8Pl3nJirTZyP8tLK0TUbrWCd4NBwYkF0dj/7HY6Z511zuTk5GAwiLARRFUvEAICMjF6CbFB39jjkFK/7CMiMVdVBQ1HtqqqetaF9fCG1KiqxJynmcUaYyKGBQCMMeJ8nMhqiNJCgdmQYY0e9VoTBElXIyUomrGtAiAze13FodTtgbjbCceH8LiLDg0zYbXHOGYijiEbTa8sVhJrf3c1rYvszea3xo2B0JgIAcQ6chW2zRRbhaslFMYrEWVAVDBIQsTK4oWAsEpZybeBgFpl3nf9mbmkHZae91e3PDzYlk1DUJEQci7f3P3kRcntbeqvwxMO7CwunhD8zeyTB9ymO6tTrc2rwXKAdnsommV7Hjr+z2/ZuOv0U46fKIjAsF29dUFCKAGgcs6uwTkzM4Ra2RUbsA8AEGAAcD4IakKMzWAbUQQkM7YWK1GNbdVo+czQY2r7UrtbZl/87G1/9Zl+trML/UKyFFBdCIjsvNKBk/xTvxh8AogWjDK20UDGncr3y+Fg1B8Nk85EimqQok6ZKmjwqhDivR2vB2nMuIipVo6DGqI0jgprn924HYqISZJ4bapbZkQce2E50bpFDJCkKWIt1RmLwDi5DFwPXJgMJzZKeI7XDCKOBbeldrxADcJExpiiKIwxURJ19bOAmgaWEX+rzo9FHIiV+BFBDAZQCopBPDZ2KfXEBFBQQIE5UgkamPIY4Rj7z6vEBBGJGnI2SZgwhKBBIrFIINT65swEGqEVIoG0xpdRIyE+7ktz9Ns2sTZSVUVBpAiZrOFvukZmMs7NI/8DGnhHCIGtiU7kEITGFuAAqkCGM5NXZciyJAgE0ODd+un2TXc8dMsXvnrVROaOc1+kFxYZNanMfsu3t1oLx8kYtb7XyqrjxaPGzpnvvO/x7f+460SyxOEVT3XnXphMzIwOL7t9D7duuLE4dDCgw97iromNx84567kT9gxlGHzjevu9z3GqhTKpaJCEBTXPFx4pv3lP/7p/H2w4OWw/1Ww9/dxTr0M7b/Gwx7Swc6wulaU0LJfp5m1bVx7d8ezpZcUp1rIATVIllfCFh9Q7fd6+72zfdPLk3OZ+CDZPg189+Go38hAAYFiN5uZmzr/owpl1W79x3Xf+6R/fV73udZvWtak7/a2Pf7s4uaBZI+hxToFFOwoIsuxKO8p4x6gUj6ONv3janrN+aGBWlEM60GCUApUtO5gzBy4dcJU4LJU4tw+t9G453n/2VOotcMy2kcQ7IUySBFVQwVdRQAZixTjWQDPRFgUEAIjZqGqWpbWjy3DYarVSY6uqStIMAHq9XrfVTtO0EGl12kmenTh8bHFpaW5uDpgiCqndbhtOrQmD4YJTnJ2d7A+Pn1jS2dl19/9iZXKmOxwcf+SB4QteuW5u6/JfPuseNhPdrpGJ0RlnnG6trSq3dev5RVXe/rM7Lrj4cqJJxX6aTAx6vtUFo6EqhSjqCdRnBAN67wcrvVar1UMU57HxDBEEFllYXEyNEQATGMAjYlWUDz30kDjf7/eHw6E1tWqHiDjnADSUFWYA0XhOa1KT954TG4e+8fQJ3guiNabWPW/oXBHkEluX6r02r2gBNGaRRs0EbOyVNE7iEGt16GakRaIeFREj1SSeFJHGE3dsvVcb4Uls6uxxX25t8xDWNgDjDzRAKV0DPFn7ntCYJNaEB4RVd8U1VJBxo56invaaV5D62jix41hORKDBh2CTJIRgkKLbEyKGFieFZkQj1x+h3bGhM+wvPP/t379zZef0lBmhWEkcDiaS5ScnP05wtBUPA0AFpoN9y+5A2PDi1hfuHv0Jg0mER1hJku3ds/KWZ7Z/62WX73t0QCYlggAaQiNiZZCYXeXF+3r2CaoSDLGKkDWAFNVfxx8KVdFwZLCKiJeADTifTaqqIL42V4QosACGTQiDhJNDC/DsK3b9/ee+U5ZbWvaEF0aRuanpdivZv7CM8+u1u3zkTe9Z7B5rL01v3Hv6KXtOH7FPDZ/oLQ2r3qiYJmNESVQFESCAgCpEzrehVRT0uCHGEO3vKDo8xqevqorAY2XNNS80zMwgCMQIol41RGURRY3A6uaZMtcQoTUJijZdGVyzAiPIK3aDOPIGOc5YGuR2EIMExJTYuBmpEUQbh9u1KzmuPe89AXiGKAzIXi1AEHGoFKlNIuNm9erlxV9fA+FSVWhotYARaMZRgsN7D1i7sVHDabZE6kMkWdSNbkRAJQWRCLeuYRPAhNQAHSNVoXmJCDiVpCYXEZEX0THGmw1IzVdSQjbRFBgVBeOkADHi26ObGZGJQsQ2s148MXvnOu02E7z3/7z/7r33Hth+ysZ847Dcb8JyarqpjG6q7FGAZ567vG6HTk12ZmbhpzNv7RUPP2XiH562ceGG1sa//JM0nzAPHvYf+Vi4754uegmwOekUOQbOjm7esmNux3OUJ4d77ik//ffrbFGZTuacIjqG4GczxiIUytQBpUP3jg7dLQzpqwE7jJPBV8aP5oUonaiomIfjlf/h3y0+cm1vcgqEDBImTMPBTac85f4n/s7zPv57Z7zxGa0zto2KgTrVoiVZiCcY1C6otTeRsehcOTk5eeppneFw2Erhvz72mUsfd/4pF5zy1Y9/LL2h5V5S0QnrZx3MKQBQ37SqVPd6d3erNZUsl8N1/Y0bv/2Wo1f9KyqawQyQjOb2uNbSzm/+A/kEoMxCWlmyTpY0++6BxYvWtTZOp4UoqFhiLxgAYsUlIYQQYo0XhSKYa1RvYlNjEg0eQAjRqOpwOHSZI8NTM9OurIjIRxVGY9bPzhVFMRwM0jQ1iVHVvNUajkbHTxybmp3ZsmVLVbqq8gapCn5qYrIA2jiZn3n2dheKwUKy0isXl1ZW5t3jnzTznJfO/ft7B897/uuWV048eP+Dl132uKNHjs8vHBdvp2Y7Bw/3HnzwkZnp5NCR+cROjkajJFdXGWsya6sqFOMYVgyGEe/jfFWU2G63q1GR2sQHKVwVt1aWtUJVpHkWgkR3s6nJid7KYHKqG8NhjKZjaKKqRnRVDatRDc4BU1SzqlGjMQ2vC9+6RACIKgx1HDIxMINyc1hoo/JvCI01gFrvU61z2GiAG+mGNSgznnSEUW5TfZAQrLWCq6wk/eVxnTZiEeNQp01PVWNd3XTGxuXF+BdhzWtcDxGtMqGVUBE0wmitIV0N2DG5i9Xe+HrizJsagqMSxpM0/isDsjGhgcPkeS4CzjlWV3WMH5RpMr2zKzfedu9vfvSheTh//dSKlIvpADnNUJNL4AGFsAGPW/THwsxRWb+Bj3VxmGN5nnkMTLZUrCRZmbnJQ4cGLz3ZveutV+/ZWxWpz8HKKl1qdWxjrRVAY0wA1Uj/UFCiSKfRGuIEKLVoQxqbn813COK8AQbiUIEVLCESoSqBMKBzGVMpCD743SfteNyudd853m+1Ui/BtrLFwWjoBrxrsX/lNwDAzR4nKnuzC4N1Nw83HT75h09AAOHgoCpL7713TpgRgBE9EBpNaw3QNa9xYFOoHx+t+YH4w04CNhmSYM0ti2sVMbZ/ailFtnV7WkJDjmByror7KESJ0+bG1jG+QbDXyVmzF9gYCEHWBmyJKH0RH0ySjrPACGICQjKrVs0xTCZJgohVVQETi6IKAHhCIERCq4iGVRUjWMl7qn2IUBWgRkJgcycUoOY3ENfZCVLtTOqh7l0zEjAz1gQBGnekRDXO4QEAar6yqnoREYm+gdHHSUREJariEKAlBoIyaq+pRm9yAa0lwKxB5Ii1VAUQjXJhUb6DGrYCIKqKIjCx96FwhTUJoIYgeZ4n1rzqd//iZ9/7Nm7efJ2mr0wADXucSYJbcWCenLztdeasXXb/o8l//ueeE+ll/rlPmv/M/9oy3V+Y5j/6xrpBWSwcr1YW2omZbXec5cGw6lUDs/PsDMlcdO6vzp10Uu/owRPv/78bVu4dZnMEeUjmVYGBvXVi1BBxSeBkJe0CYqfsOcm03U7wBKbiQFOqAsBAuCejR8zG1saNev0XyZReqzTQwa2XfO9Vv37xbZ994d/+avfKS3uHhszWKnjTKCKsWfBxwyUmQ5Z40l58/lmEIUlat95x77atu1/5uj/6zH+9ny/1gmpWbMhEC+m2zY5tO16579eOzqQ/qsJ0sTKg1B45c+tn3j485Sflxn2EtnXwovkLP+2m9k0e3xqIvIogUiV51npoYfjzw8vXTG0MrkREX/MLMFQe2IzlAURC3DURFoOIHqSxtmNQMTFpS9PUBR/9RlxRxlN0WBYi0s5yie5aIILQarVGo9HKsBcrzqIoUpOy4YAUfFpqzyucfto5ZWmWjuvsOg+Ub9yaX/PSLfff1mINd9x7u6tk/ca5u+5+YDAoM2vOP+/8A4f2J3l73769H7v22je+4TX791fOlSZREej1KzaCYCIMIm6qqqpiKTwajWKiEEKoKscmKghKipjmWVGViU3JGmR2wbe7ncmJaW7c1GOiLU3zJwJMiLlyLlYDFMfpXmx0Z2uE2lU1SECtjWCrqpLGbzUGzgj3WK0+GzhVjEY++KgE1BxPHJtOSlTbhUKkBikRoqhvQhcgeAncmOWNz9O1rMG1MbXuNIICIBpeq9UgIqQQgtQFyhpeUC29u4ZWqIACGv8uIiITNpyW+JFVVRqBDlVVH7w2/owIY5h0nTTE6t+a4D0zj6pSFa21pThdSXZvTffsPfzGj+z50j2uPXneNCwMVUpqtdoyArBkiXyOo0nseaUVmEgYJc7VEEh9ZvsBCHyy5OGSucG//vVlh1cSZJeYyVD1sUGgrjY5FQAUDUcOTB2cnLPGRCWNsUl7TCmMMT5InNATYTLG7jW9C1VtQowCKiGhESuZ1wFIGtJw+J4fYPuZPDVtqwrBQGo8FCvXvF+4AgU/fUIUSCgbdI9ufax98rodD52WJalAnOjHs76ZcQKBqmlEqdY+XAAABAYkIh/8OLCtjR/jmxCfII9J9qpVVUVlt8beJ6iqSWwE37I2gLsmr8I1vrbjP2SJwy8BoSEG75j3xS5LrIydD6paFAUzxxHPeO1FZ6HxpXoVpgijpvEHxma4QYikNQcdGMYXCTFTHN8fXEVRwZh3BKRNGxhr2L9RwqDinVdVYoMUex8aLTlFxKuoj9BnoDX5a7wtIQQvwdTnCo87RAEARU1qSEFDDbZiQmBjkCJ7OiYBMedQDaqrN3a8j5CQictilLBJktz5ShGyNMeAf/Snf3r9Z745t2Gm6LuvwOGTJmYuzPP+sC99pDPy5/7ZdpWj1YjILOzexuaCP5ivHrpk9oOvOXPpi3s7iS89wKZN7alJv3LiqIOJ0cB7j5dfTts2nlg4cNnllz7ZLZbDz3xm4hf/vTI52R0lRTWELBBgCC7xOvRICQcfNOHc99kzn335jdQ5s/+9PvvNXZhIC1UoBI8OoBfsj7OLLnjsoZxNklvQrDStL//Gv8+Mjv3R711itu6SR3utTNAnRRVMO6Cv4aLNzdGgEoKEChsbGDWWL7jgvLTdOvPcs278wa2mm736xX/wmTd/1L36iH+m8iRv2tTe8ej6yQ9fuOuSJ1x8SfvwPfMPyhZEIRmmxaS555n4oGFmQHAz+x578rsn9nxasBVU0LsyTTQUonDTwf6FO/1sYgrv4tFiFUFBRNGaFtTw1iRJIl2+LEutkdCCjQU1MREz9fv9yCYqy7IoirijjDHdbrdwVcwbR8MibvWZdXObN21p5W0VyJM0Epu8eodVYtgF6K8ENwgnjodt26bPPOPs9dvnOV367rcf2vvoPYNeNSqWdp1y2ote/PI/euv/2rBx3d4DD4QQHnrooW075j7zyS+87W8+kKdJO8/ciFTZ2lgm1hQCYwxZExV5JGiaZKNhIUGd89r0qSxxv9/3Eqy1sQMctauWl5d7g/5wMKpKF3dIXcABgkKEAsUUJMuyen6Dq3o0cT+UZemCRyZijOBGbOZGY1dIRAyg8d1UlQHZkAYJXkCRyVjimPZ6CXEmCmNFm3pwxRGxiY3JaFxqUdrbYPMzDVtmXJKOj5XxF/Wx21Qn8f3rYZ4qKcT/tPEnrtvLTLUujyoEQS8QahdM733kGkpTxY6vk5kZMIQQbzis4SXX53XlSu+8SlVVMRMiorydDkb92aS9fV3xT/95x9P+9u4vP9bdsmFbV466QOCZwfvAVJTWuaHv7OIDBaQV2I14bCMdmrN9QR5ptld32UGeISc8N63HP/iOxy2m67wss0UeBiIgrmdvIcRaguONGV9JvDOxQ9JwdlZfMd6M0Qa1AnMTTlLkDDmJLE3QQOABKgTvSx8qY8l4LCX933/+TFk+PvSSKFFAS6zb98i6A5APQBEUTJko6qjTCyiHTn1QDKWUgGC7nTHHeC/eVzVmTn8p9K4NqLH2jQqO4yVBY6OLX/YFWrv2xrOMqqqGxajyDgBFNISQJEkkvscNGLXix4+4LltF486K7zZehETY8G5XCe4xzhljbJpgs97ijqiDbkQMNOmviFRVFQHzJCoI3qAassQpMsYWaJOP1lNSRS9aunrljnU5xtE3foTxMh5fcPw6ngAQQRuyKniCv/wCgLIs47JXXZ06oYKTUPeKoXYFjpmE+hCtz+rOc4PxHl/n2meKtXQNAVNt/RuLIh/aWQ5QO1UYY5jt//7Lt3/hC19Zv3WzgYJVSkf3hqLlEwk4ksGjp6Q337eyMMTDJya+dgPslyccSJ62/rF///UL8wT0P+5bVxhTiOnk8MTH8cte2H39q9wFp49e/PzsnItX7rm7fclVr5o8fWbh6L2Dr3+euUx8x1SBuKeKipBLcKYkcTqsck7JkU7tPHbeUz81teG3/vuuuw6UheR92ODDhPMd76bXmbS37+Qn3PLd7JZvorGi+QAPfevZb13aeMafvmB7tWlTubI4tBhKiwh5gqlfgzaMT4Hrk9CmbWMMUc3dZ7aXXnKer5auef5VNpsQV73xZb+z5XMXd19h37P/kvP+ZMudl4/u++x9o8XD/+fv/u2eT32uKnpCy62gAUkJOahxwiLbrv9Dny8euOKDKEqJRVTvvfXDnO19C8OHjg/SLLM2JSLxQUSIbQjBEFfBj9fD+HiMvaCYnIUQgoIRUOdXDfuWlpZarZaIlGVpszSoIFOe5eVwlCSJZVN6Z0CnpqaSJCmKIuoXumqEJhMj5HnQDy54k1RBZP/e4rRzR+tmn5Nk989u6jGdQpk7cvTEj2++cTAYodwxOzubtumKJ1y9Y8eODRsmTxzuf/u73/jWN799xZOunJ2Z6vX7YELwwDDhXF1zR+VnYCrL0lqbZVkcFCVpWrjKe9/JW1lqi6rIsixS45MkIeTLL7/8xLHjibX12hWJFCbTWBE0PWExzJlNRESDKNXT/viKB3RUFoqbhBteLDQ4kbjHoqINMQIoA3kdM20wYihK70TErTH9DkAAQlA7eoICMker4AbvUy8/BpRGjm58pP6/cXesQjVGXa3+wJqDWFXHKJ61Z4rWVsy1plJML5qWIOmaLveYf0lEaZpCU4fF/rML3hBHfmr9HefikWqt7S33Nq6fOPLYw3/8wWPfnc93b9290fnDxXJu046jAZaCkjmFTDvUe8fUu/qaHwybJmgwjUtWiiGkx3RWAb7tn15kTjg7+uADX377ZeumNh9d7neCd0nquTTIEMWeWFGilEH8bCoiDNHnJgJgMISAxKoSDz6IY0UNcaURkwT1jTGzIKghdk7ju1L0fq/VEoxNi2qJ3TTy8sr89HkXnXbStmNHqwzafbSkLNXGfYKg2QhAqUrTQVYJubz0xg0mVwIIgm2lnW7HivchMJKoAoJhNki+dP5/PPRGfAdiZ2IstzROI2g8RqUoC1pzxyvvROJ0hCxQWTnvfQwbqOBDxC3Ws//o6gXUjH5VIdT3COrZtECEjqsiAgKKSJxlaCMMDgBRKROJrULs0EaI4uqFKSCgh6ZubgBWnpFF2QkxBguegAKwk7H0F652aBqtx//Be44+EYioIIiNsLQoxRKZowm5MQZQnHPBOaBa+FYbXFiTg9Z8UO99lCVhZkNkskw01E4VPhBR7EWR4br2jUy2sXmGD8wWpZEbo1rKZLzTMeK3iUE1HltOPWIcJvqJydbHrv3KZz//pY0bNvuqX1YwMKO24I8KuYKz06l9rO2XJiY2TMndd9Kx+fKxo3z0lDfywqPf/vg3/88rTnz1WPd7D07aNNEqHH5ssP+h7PyLkksuGWw6WQ4dctf/yF7z7Ddf/JSrh8eOV1+5sd17RNLJ4XDBYZpJIGsBKmcwLywBCMqoWsyzierUi3+Ute96+E7C6s9uX/euiV2XmH1YVYp6dNTuL185/N5N5ehI1trIAfr9gwee+Tt3X/mm33gcbJkYmhUdGNtSFgyVqJjEOBRuskzRtQ/UqyejrORETNrq9QbTU/a97377RY+/5tdf/7pvff1bj9x/yxWXn375U7Z8+UO33vDNYve53aUT1dve9e5LLp24+innlTPlDYuzxwb9YIWUbFBEXzHTyqaNP/6NQ0/84Pr7r84XzwmQSSgtUqlU+nD7Y4sXbO3mNgEXPKEwBgQybIKGOl0GLyG6ZeBqltWM5IANAhJSZpMQgjgfTX9d8IaIDBeuct7pSGPcir8mIt6LSCUCBEDRFoCGVWiRx7RDLlS7dm2QxP3khuLkU2DrDv+fH5x/2rPO+f43lw4fnb/owvMeO3i0qEb9paOsrTf/3u+eeeYFS0vL6qTTbj/zadfcft/HP/GFr1zzzLds33760mKPKAFajvjV0bC01nrvl5aW4qmR53mccsctYYxxzoEx1toYfgREnMdWe+8je9bPzYUQtXEEAMbJJo6xiyLB+0jyidFJLQFEa2FOQs1t9TEdJoPRSFV1HLyxSa7x/8mUI3LHOZewGeta171qjjk4qkJAQEVxPia86uuBGTNb4tUxMK2WNbBm6gZrKgxFEBWNHqa46q2kqpZ4HLZjmV7/gw9BtSbyImKtt4UBNAETBeXX/qHQqPbX/7uKfKnzAxkfnaiiATwyUezhAtNwNNi6dfo73/npb3+ssjOTp29Jy8FSD23L8NAHAXGQ5OAG4rql/PvG3+tS79cWPvDG7se2wf4edhFUAhLQDeFpPxldNjNB9x8YvurJsxecs/vQ/MoETaAxoIaSuG5VVAySoobgicgYDqDiPBoDTRoS8epRuVcVEKO1FGC0wgNNIq9bKapNBRUEUkNB6v6SEWQlCIJBBClJ8lA6k3aMwokh+VKSlg9SsOTkPZcZqIJQQ2JVMR4AUBADQSAAnGpPtNtZCCvikNM6DVJVDQVQNKRYG3/rGqt+LgooGhu5IqIhAEPkz6iqkxAtQOKCsdaKUBzx5HmuQaKsjyUSy6v2lADGGCaK3Q5rLa9y04OqxjpVAQLUnV1BUARgShvN+gjpF+fYxo5uzHJXBSBDCOIkTVNjTPAOmsI6rrQErSdxoCRqAlilACoMFEXffF0HE5noV2obQ8MxWCHW2XWSimPhmvh/JE5iXWoQogxNKb70DhkAwNS1bJ2VMrGTWis79kiijAkzq0EkMEIBQggBRbwhAEiMjcrSIQTEMXYalEibvgVRfayxRufIeGsIsUZ/RgScSWxRFK1W69ChE//ygX+dnJpjm45ELJp2ZQqW5eHwq+i2w4Tv9Nefab5zfW+0aFw+f8+D5297ztUrX/3zN5x24uTJ8q3f2zGdIVIRUhCwi2H03VuKnz+YDEZTuKQTGzetm86q5RU5tOJ/8rmc+obyrrWhHPXDZJCBqqIYZCgTyUaYX/qs+cnNs48ef0Gy+OTTdh7wp67j6VsW3B9e/9icyEpZXnrhM54pMj0aYZ5oeWwpIL7pL79zydsuWgdPnOpp6UvTTchUNCDvFVoGyJs+YVov8jp/BgBABQeBpKoqxISLyqVpXhbDl73gmk9/+Rvqqte+6bdS27r3B59dfuDxR/Yc3bj18MIR1xsNfvv3HveMZ7z6p7esfPrf/91e/KSJU58+Or4oRJ6CEggJA66/7SULZ377kWe+85yPfkTMpLZ0saxYMGG67djCsxc7J63fRF7SxI5Yi+DaNsHCG2vixrRsx2cm1oezRkQTMhkFQMbFleU8SYnIIHnnEyDKs1FVMHMnb4EoBECTIpoUHRFJZLcQktqyKDAAkTHkR8VwXTp79llnfOGz1//+W19/773v+uZXq2TiUDZ9+IZvZttP8ffc7fY8tOfQ0SOzG8+8cPdm5IPziz/58W33n3TSFTfd+LNbbvrh5MyObquc23b9V760/5UvvbY916180JAgMAIaY7z3VTFqd1pZmjvnvHPQTC5rmyBriLkGCobAoABQlOXM3JzGLh6zNpqxUcNWQV1VaVrXuKoaTaOUUIMQgUEKlaOmewCKiiQI1tYxKb4nmzjFUY3sQwSUKCMiNaw6hFqXUUKstOoel2iUZScBIgoSoh2KF98IM0bTq1pzQ0SwgXFFzzhUGNP841gMABiJiREgAUqQFWKsABGp1MOakro+rBFjL0RFvQYA0MhLBiWiClTFZ0pE7AlUgUIjpTsmLFEM5yAoDNHlSWPPIHhRQDRGHWiKLNwTf+quiY9++bY//tTSrpNOdb4cFqWxFryIFy6CU/RGEFBSec/U28+zD75s5QN3+VP+YOUvr05/fGnyswnsHdHZb+lVe6qzUlsuFLB1qfeHr7rsmFNDbcvDnrRacf4KgZtZZR1pEIKqQcIsFREIABLbFBIDbS1a0ohsI2JiEiTyzqOuqlWnyOBjEYSIaJAYKSZ2RBTKfkqpQalCdbxy559y8hPOvu1jv1jauL4LQhWW8PDFFD4GZUsQJCkHMxUAsEvYm5lDm07o0R3ZyZsn14F1oTQ2YwFSDKjivVdlG+fNaxqWnBkBtTE5cJ6IAypEez6E2pNHQBMmNPFcj8NwChp8GRA0KDFpQ9cOISCRATA2EQQBBaiNHBAxt4kCqKEovoHGRA6UUCOa7QMokEJKJt7GAOpRgwaimvSPPhauBCAxGRWRaNDrIUAtfKnENNZAVlIURQGF4L2AMYZiPobApMTqAwQhDIYggJIgEeu4HxBCUEWFClREEjbGGEKMxulo0BgSEQUNEZZBEE08Y4gVRGstEMZkQQDIsASpEXyN9kjpHQgaYmY2MUE3NUlpOByqD3kUQTLsJagoG4bGllgQEInZaOUJyVqLErz33rsksSEEAWRmCCFImdiQZ/Yv3v2hw/uPb948U476xGnm7AjFSF8Nfb9iI4PffPLOLz0ox4+Pzjpv5lMfn9nwkje3R/s/sONfT53sjzz+zoXH0nv0W/smxLskSaxhIip6Xdt2WWeZtfff3/oCQOuKxz9++rd+v/rI+8uD9+ackrbRFsfIADgAKbAroyW98KqvTu646eGbN3GSl8nz5y6+6Me3HT575rq77nT94khh120/8xk7z5j8wj9msDKQudnnvfCgnfr5U/7CjOB1uwZCoGJJSpASQVSNYhUUkRL0jfpQ7FcgAJCIAAKpVSNKxBVa1oWlxXY+e+XF53/4I+/cvrU4Z/1lxk3ddPOdT3jK2Xd/Z3jH0i/e9/6nHtiXvfwF/2f/Yz+e7K6bXVrcMbO9mtg0GK0gtrOQZaNKrS2pvf3bf/zgK3/r4OO+sO72V0mFQCn4kUc4UsK37u+/YSZQJmUoTZl3QUeqllUAEIC8IBlBCir1AcuWgJmivXMwwXtUEO9K0G63W5ZlUbmJiQlflSmztex9RQiFq46eOL775FMp5KOqNEBIFEKoqspVktlEA5auJDKLS4Orn/WMr379kw/u/+JzX7r5p9cf+P5X0mc9/8X3330UZGHb9uMH9vbbreySC48D7N37yIjuOHjGmVsefaj97nf91Vm7T/3Rj3/YSvxv/G6yMpg/cOzHF2x59mC0YLQdxDGzOG+ZMU0BQH1gQLS2KArvfRzcjiu8yLhy3o+bRQcOHIhqgmOhuDHyqD5kIaoGsapGcZLYLvNNxykmtjF5T9iEBupWl5t1OSgBNE4mEGHsUlKUJVHswxpVjbJ1ibHRHAnWdALHEylBwNpCqeYBjdu84wJ0dRAriqLA0bZXJZqVjnWIasm9miRCRLBGv7Cu1DV2cgQinTGK/QKAKgBUvgqoBmtRsNAknrUIkeh4/o2IAsAUc7zVi2zulSMTWO2oKk9Z1/nEF3/+1s8WJ+08xQ8LgYCqXtR770WDAUTMArGXP5369xfm179l/h13VmdYwArSL7grrisuZgKmaUv90rpQ5Yfuu/+Tf3Xp+rlN+4/00la3DIZYAyRMNXd8DC4bmy85DfX0d43Tqo5r/FVStcb63jQthzHwOzRBfbyi1qY1Jp9YcfNTdh2SN7aQyldukXE9UggVChKPWtltTx496esAwJVFBPbWjnIMtPnu00dDv3XLtoluplphQyEjQKxbDqi6ilEav9Z2KZys8tPWLhgbCEhoDSAAsR5IMAEhiWitmacqXN+CsZsCNK20sqpMmmRpHsdg4/lLU8MRWQMAlYQo0h6N+bAWBQfLRlXVh3pZriLVa9ByaFyYnHNZmo+b5+PnEqchIYQo+oWAEkRAmZgQVAQCIIBQPcVp+O91k8qw8d4HUHVOG+cV72vBn2g9GXPcOMbzVS3PFyM4ENZbtD4lkBobkuhRVtcMVRVb4tQcFAkbAQTR4B2rWuboblHpKuhS6s8FiBjEx/sfpf+ROKgAqAQMUMxNzXzt6zd++tOf3rRtQ+kKUUjAr3DlvBhiA65CvaVFOKjm98vjn3DSV687nq67oHXmM1984A9mbTGZhBOF2dSq/uLigxOsX3p4AhVIkBGET0jlJNX5xeMrC4vr5rpheiZ54vNx+xOXP/1O/ck38v6KWGvbGWIhqITz3anN9510ytd/8BVaWjgUls94/HPgwJHebHVdOXj0yF2daRw4+6zLnz5z961+ZaFk3HLNq2/a+fjFif+frPcOs+SozofPOVXV3TdNntmctYqrHFAiS4DIYJID4IATtvlhjG2cA8bGBmNjDCYnYzIGiZyRUE4raZU2553dyXNjd1fVOd8f1d0z8jePHh7topm5HerEN0zsXUz+9OrByLBPvOoD04qPckkbc6FWXPH5KKbyRJ68zYWMFvKCKKSjpP7gnoce2/eoBty75ztDz/xhvX7OS4bX/+zBw2s3bfjwu1/2xa9/4pufPhaNDW1Zu9H5eH5mv/32f697zq+PrtnayWeJeCAGVabR+9OXjTz8qulrPzx68AbVXiOFhAPmg/7hxW7X+iYREgpb6yyRssyZcERKIYp4YQZhKDnoiEFwXXsQ0lqjwPjoWLPeyLIsrtfqzcZSr5P3rfJqYWaRLdhcrPXr1m3o9XoHDh+w1iKqQS9lJwDUbDYZwZBKTKRVkvYxiVr/8YF/f3j3nt337T171/YrnjWWibr0mfXGSON5Lz/7Jb+47gWvqvc7SzOn06ffcO5V126fOXN71pk9b8slg+7Cxbt2XHftruX5yCTt4fGk1wWxyuXivbd5KsGOFCg4AAbF2lqzEdUSJxzVEm2UdTmLt84FewZmbjabeZ6PjI5u3LiRFJLCKDaBzxDyLlQGAiHLVpjeEhlbLHW0juO4VqsF1wcFiFxgRqovRRQprZDC+C6Ettw7LBXUw2/BYPDAHEJ/Jd1s2Vv2RbIsNXsr+K5atamFFc0pDlM7YV75Y0kyoVXJIMQXJ/yUT7LKoKMK3EEYKHx7+CeAv4pQvlqmo/x0Ug72GcQL57nL87wAvwi7IuwjZWQpGrTd2EjzR/c89LYvnlmzfaztOrlii+IRnWMRRC+aQeWO2b+i8c23Dn/qncu/+9X82XkA8VtPHjesX8MwlNrUKpUt4LH9Rz77Zxc/88rNR063h+uR2J43pNBZIufToKO7GjhGRKQLdcDVKTNQjyp74+Jbys0CM0OVnQlRkTI6hGlcJY8AlWWht41a09qOuA55FKu3b5sE2yXSwA6FNHHrJ6/QJ7eBQNSuR8sN00+ifrLz1utbnTGwcNbkeUoXHrKhww4iz1prHZkAYqJVX+HRh6k5lbCyoOdcklsklF+VsWZARQSdSwBAKuyhwtsQXv7Ayguva1CBhmB7ZXTIRsCikTQUmIOgSIyIFQ3JGBMOTlHreA7cNlUF05K/G7IXltAwa61WxujIeufYQ6m9Gn5mgCg654KdObGQgGIAz+wEhFYeIq4yhyCUwv+pAMgUwEOtiAgB0jTNsqyYJGOVDwswPP3/WHxVPgifOTygAM9USoVBOlcgMkSJNcZGjGJNFiVDzsXnUvq6Iwa9GhQGYEEGQgZx7EERA6JWwWgWEU2kpk8tvO+9HxyfmkRka73WUS5WNNUxVk5hnsdiu5A8sJ8Pziaf+d/eqVNTF7/4NSP21AvTT24aygGgrt2WVqZJfuui06MJESIQegSF2vh6loK15td+/68uuvLZg9nF2Ki152+afPu75Y8/0r30hZlTsrQowiZqKmv8xOajIm6+PdYYGxpef9P2XTuXT8xu3H7Pnj0KbHvBbR0euX5u1j1wlx2f0q986xd1dPs3/vO+tU9/8TlwdpO1Vy6UIJWSGqIClBX4PVQvrXOOrWObU2aVF+WQ8jxBydq9LVPjp48d23///Ru2n7v/sWafG1/cd7TdW7hm/Zb+fOcHX512h3dtXL8loqgjkEVe1WoT9nB87Cf1dA4kUR5rYh3YPFYaZPyO31Rp6+gz/5G9N0qD+DzLIqAjS+mjR09rQecFJSej0WZ52fCEYBLaG3ZWhL2z3hey8957zcxepNPtxVEwA+43h1oqs9ooINUYGrZZ3mq14qjeSwdREicN7SGL4ka/m6OCJDL9rGOtpdYQEbKyzDzTbU9N7rjxuX/+7//64QdufzRKfD+f3bR5+JpnbJkcXT80NtOeacbDR9e1Zl265+iBVtS6evis6d9/54Y1zQtPzXRPHn90fOiaxXQ/iyYFue23GpCmkGZZIwDE8jxOEgdex5Fn1x/0tNaIIMCpzYOyoNHGex9WI+GlX79+fTi0RWQE9q7IkZWIRDjJK4cfUOsV7aSivRPPEmSOVpZnClAUERFbJ2WDRQLB6FRrbahYfYUjXfw653O2SKS1RlTVrwgONrBKrwoKhSxZ6YOlmDaH7woLuUBqLJTci3S4EnGQSzKVAK9uNcr0HL4CrIxL8Y3wtVrpVwhD0CwuP2guBhcXRAD27BWZQhgXsHJqAiAdQeagNdWYOXr4dz5yKt66Ebup1gqtR2aRkIDFOQ9KBOX6ePd7xv/pc92XfrzzK9r5sGonBOXskWMddKwSWl70dvHEF//yqqsunDp8Urim2/1BvV7PnHMeuYYKCFwxFQzBHfzK3poAK0dFKoFpAKxQVdwkRARVONhgAMKUi9fwWEO2w0o7ujRbVGg1EUexqFaNl10MaZp4JSAGIENEANSi1dw6NTu16f6zskiGF4fGD2+xxqcqbZrh7RNnCWUcxJicBLkW5CKXMAIUYjIrmSBE51BUFjtOgYBs0EoDISjizDJzWaQV1kaenQtnBEBQJGBOibzCcI0aKWTJ0I2hVklkCrQnYGhaAQEUKgyOjuK8FxAuESRh1VKBsJxzBSmo3KDDU2c8PnfOOdPUWus8zwEk6HhIyYXD0kJRgHPngEUpTUpxyVBG0AENhivLmfJeCaIAEGGYzIsgC2OQkTcsAJ4HbhBuby2qRVHkgMMlOOEwUKoODrIERyZYRZLRpS2VlCU1ADj26AvUgUL0LOysAkSi4D+4epSCWKyfREStmtMUPGzkofrwJz/2icOHj42vG86yPpDJnXWCCWpNOqU8Z2LlY9XI2jhQ9QbL2PqzZje95Jen/3hd3M8ZDYlCROLRxDuhqzZ3vn9sBBlJgJ2DuJkO7Bvf+NvPfuEr/+7v//jUEw9vu/CiZ1xz00XXXDl+w/MGFz7DPfGwves/QX03HcwzACwu7CA1smPb8UMPTzRHlqdPP7J543enu+hPXDeybdvIuvO3X9jcurn5zmePXnjtfl/b+1vPa/7Fj7aP0Yt3DAgVuBiwLRIhCq+SAKrOo4iE2OK9L6IiAClt2YIXJOo7Z2pqemb29Pzs2ZdfrRHaC743PxKf/cRff+voe/79H3/jFS/70N+9Y8PGdS+4+lnfu+Mn/T5Hw4NB1tqx6dKsczzdffP5z3n9A51+5NyQDPeXvdG92qCx7idvO/ayP1s69yejB5/n+plY10pqyyLHFgMKUEgHLLP2joIHZXB2L7KJUsVmEJDLqlSHXi9IWDQajW632+8OmvV6lnYWOu1Wq6ViGqTdTqfT7XZHxsfWr9sszHnfNurNPMtAY0RxY6TlvQdvyAsB1JqNxdn56665UL/9dd/5xi379x159Yvf6Fh968tfeeaz4uGRxqZtyZIdytp9axpRbWLd1MjpU3uOnzz241tOP7Fnfv2myT988y+v23h9bNbnjuuNcWbUsdNxFNSv4jjupYMkScLqN0BqmRkEQVApLSzhzFTDK0Scnp7euHFjEYHDSVArFTqW/D9EJAACDBBgVUoBhGLWujyEVypDrVbFblEBcpnCQVGBTBERwkipSi4/5GARUUXUKPGZsILkqiL46uK6GF+sKGkUO0gqUc2AGFgKUHAQCyb46tYWqMiXxSinhHSFX6EAgx1M+KPHlbo+jLhFxAXfhorf6TlIiOjAXBRhRlV6UK8uIMJ/3hfLrjmBs6/76D7d2gqQsm2KzQWy0G5BEMX3XhOdXzv+yfE/uyO97B2zf8jEwh6RQCtCiFKVK891vdAWtXjs5r+48qILNu2fdXGEID2Kh9NUEJ0XUJ7AqYo4iogBGy/V1YXPGNYNoREMu2EsjIaqG4UsQligqQnDNBjCgKwM66vLMgDwaMCToGcEGVCuYXp6WkU7nHOBs+qcJ/Ru3dHo9NTYk2tzqTc8CYto7vV75w5fPlobcdTXFBERc1HV+EAXRwgd9+pCKhzsQtqlhAcWdkYivhRQDGVWALPAKoBmUZ5iUJvBkB0LMThSRCs8nKBoUW27ARAkCMkVAx4CEAGSYmwOnnPvTeX4SSrcXieiS2smpf7vm8PeE2Lg+wVnrcxZBKy23tU7TERaGeesZwmDAUYVdkZQ0Yoq5+ynvpjVGQnaZxWLn4goTMJzm6b9dNBLmo2VOXxYQwRyoFJAKz9NlZMVTSrPc8u+4g2KCMkK5woAQm5WgIrIWgcAgRxRjApCpcheESptwgY6PClA0gnOzizccvP3ksR4myJqBEJKyYFFLwBooohbNu9jpDCuKcRMloee/uohN/Pc5U9hA5YydaZvtrQyQqh7j2CmYkdCjtiL1JPYUR5rthnNHJvf89Ctvdk93YXHebn/8GOPP+uG55y1aTtfe8XCVX+kHjgAv/jK9q0/HTt+cNe+R3/xvIvvaq3r2c5gZMv8+Ze9enJi56Z36ziJfaontnDiZw7NfuCW/z1/sLTuNe+caU6+5bJBK217oy2L1lEoH6sVXngg1eo33C5SYa4RVkIaI8fMBFoAai3z+J77c8u1JF880NMTEz/99qmX/vLa3Xfcf2ThC9nB5i9deeldg2TBD2565Wvv/MnNe5dgrbbf+N5XNqzf9rznbN2g2v1k5HhnMOh3CGuZMSg0tO9ZQweeOf3Mf42fvBhtPUItHljL8bbPnEUEmxsCn5NNIBJAX8i4FqKKNs+9cJ5lvpRT9c5pREjTfm281u320zRPksjnWS9LKSHvfbvdJlKjzaHxsQlEHB0anjlzBgBGWkPO5c1mM8uyTrc3ZEY0kohLIm9zn3Z8q1aPE/Wyl7/wphueMTO7mNtk/8F99Ubr4OHHgXozj0yjg+mZcanV8t7y9z7/pRe84IY/eOtXL9l28Me33Twxuuaqa57V7aVjI5sy13fOJzXFDgjRJHHuXZIkGmAwGChNyNJIah4kS3Nmr7UOSy+DhRKTLVc769atm5gcL4cYwcirwPpCNfYhqpx0EYBWgZzD0CPY4ChF3pXAtpLJ44SFRVdBxBUgFoUU5LFglVZUuUUFIgqOh1J6A1OpELI6mgOAEIBfmRszCJXjPoACYhquRKpPXwKFVoJauGwBKKxMV0JG1QWiBKBN+ZMJAYRKJT9WyMzKC4TPIEW1zuWGA8KeD0QAKwW+8ldInvF5a+Ft79/90PL6bZtzt1wbmEXKjWhkx+x9sE0klimZ+8zo207bqd858TcgxMqBAuccASuBnHxXRbMH2hc3uh/7m+u3X7T1+HRnpAmUG5RGJs4TJ0oDgR1kkTKZK4XAsHAeLsoQH9wDMKzPAxlFKmpNYZCBiIIsgmDZA1eFGgKRRiJSYSVcZQ4q9S4UxiReMCW0Whpg7a5zJ7/8aI+HCAG8AwFHKHbd0aFHt3qfW2+s1gBOaeyl/XO3nSvegQKFgfMtElDZ4hEIgJzLFTwl+0LZ6JeZpngixWiUSGMhbVaUCKvkmgmVAiQgV2U1AQDxzkppUkvV1WExP9CkgglPYOAAQBBwDgdKK4WEYf4cQlLFpl3RqEGsTIVDRvcgxhhUlCQJAFBZZyulEhOJiA/KIQIiYq3NXFaMfBEwFKDCqEprbc/ISISweqSxUrjIigps2PqUj89DQXcJyZODTHQ4KoEkJSLChFTt2ouDzEVYYMCq4heRLMtCv+5QNJETF0JHuPY0y5ElXAUR+QIOrRDRkEIgQnLIBaJbxHs/Nt76xle+v3fv3jXrx53PERK2LvggW3DKglPaYFJjckyx06DZD53f3HXjtcf+UnwuAEMRpwNaSPVEzY3Evp25ua5WAszACtPMxSY2UfzN736pMbL29W942/98/l8nGk0/PHT3j/77tm//29v/4eNnn33t0omOFdV84cvXvfgdp/be8/DN38mOTY/ng2TtlqGzzrvu2hvandlHD55UCa5bt+7Yj3/Wy5dvfejb/hufW/+mjx6/+BVvvlRGtc85VqybES/laDQgrsjbAgBjGNwxM2skLjToimEDWNE14syLRRAwJNPHj3jLktKl155zxwOPkB966IGFP/yL7fX4xOe/33jm9etvdI3vf+nW2Qs2XHfVteae3Y9OH2iMTqzZZM50fnTme1+D9b84fPZrF/pp3fY6LtZavPDkd//g8G+9Yf6ZH17/gz8RQkfQiqID88uPzzXP3zDh+mIilXtSyjj2IT6gKiztrXdVIVjFIp1nWbez7Ee8Mcp7n3tnFCwtLraGRkeGRpi53W4vLy9HRmtNoHhydK1SqttdarVGSGES634vEwtcT5xjO+g06sNJA7I83XvoxIEDez//yc9FunXBrrOHxxr9Lp44MjhyeGH7tgvWtNav3yZTG8ZHxtfDYOo33/rbVzz9XDt37tDYyP333/7wY3dcdPEF995z39XXPG2h39Fap2k/SGS4LA/zK40U4A/pIAvmgGmaFl0UIEChrSEFeZeQ4OTJk5s3bQFBZ733ecBkgRSqJFKlnDIohB2eUkSEjlfmY95xmI1U2ZGDN4uILV38nHMIEEWRNsaDaK25jDIFzqtM3qoQuw8jZEbEMLIuC21VjVyEEFaFDw9F1gwXIatm6USFjnGVaYJXMSLKKimt1VNTLAfFIYr4MLIDQC8B7alWb3/Llq8ayXqQgCANHymEG2DhQhxZmNkxb5xIvn/3w5+4V20+J1lYXmxyTDbzJLHV4rzPXFBRTjD7xNQ7DGSvOfVvZ6QWs2VEoxQLD9gCy8IJu2P9mbe+dPytv3hTG82Z0+2oZsAheJWjKMzRwECkRsZEkUNvwFTxUSpKAEIBd6/isgBJED7A1X2SlPVHAlTFZcceET2RglIBsdoTh5zCDNxhdFo12LGPlmsS3bV7tlnbihQQvCyivMp4YjpePNd60CA2mGL0PTPvHDvHcx7Hses7raPwBIuZXMDTaYWAEazInEkJlaLSu7OoDssSpCqJsFpYAjrnxDNCUXuF0F88agzSSyRYCH8U4UMKCjWH10AgSEuCiLeFZH5Z/YEwh4xY5e+qBi0+VcmtL2Qoqg7SxMwc+HBZlnmQOI5ZvFaGrWMRUkEfvlST1aSDf5dzhZ4XKRGxngOluMBiBOvcshhFQBAMkDMXaMosVa3svScQozWizm2h9A5CRoWxRCHbXiXacMDDvzsuxxXlixd+oCFFCpQXRDSoCUmQrXgu1LNBY+H8KIyCgEoDCIcFFiEAAbOJdJrKz372s1pdEXhxyOIQRAGx9waVkMvRW9S1egSRyQQsm7XX/iL3lxYe/CbvpNmBnqq5dXULAO2cAHDrcHb1pvYPTo1owQQ1DKlBj6yJB93ZW27+2O+86W0f+scv75tbOLLn/vjCpyUJ7N974suf/b39x38Y/6r+7v9+YWbPocMHHn/WM2668Hm/9Ol3vgUe//nhx++68bJdn/uvD/7sJx+uN9c2x0ZdRq/+5T8+/8B0tP7K3Ve+9hnb4GnNrmZVM40O5t08NzoRZyvEXPHGhm2BFH0FBsEEwaJMjihlRiQk7qeZTsZPn5mdXVxoNOn3/98b5/7+H448nj1+5+jOTe3hzcnEhtq//stHfu2mF736P/7x1r9+97HZA1c991d2zvzENg/UtOt430izZufr22nj3birp00i/dRGjq0MhiZ++KszL/7QyJMvSE5eiDoi4TPOfu2xubUj4+MR9/M0jpNe7owmQcXMyAwikdK1OFGkjIrCMjucDK2V8lm6sDjPAkQEwpEGbSDS6LMBaYWQe59ZQlQwM7fcTKLcZYBusOhTm0YqQqTDJ5aI5tNe3/t+npKJ3ez8oelTeURrt561uG3bRBzNzs0/emb+wbPPn4r0ltQ+evf+WzCtD/LGtc941nCj/ql//szXP/EdhUObztp07dNu+M53vnfq5LGjR89s3rTx/Is3pKmhZez3+2HwJMzBMS1L0ySpJTEJgE2zJEmc42AaKIFRAhAniXOu3++Pj47FtSQk6TALCo0mSwHBKtwO1FOWu1HprkoKAXQFbhIo5CmqE0WklVIg4EqZLWftYDCImE0SB+hm6JMUYDWMCkxKxEInqPrLUF7wivAkVfvcKnqGUFvBhUQk0DyoEN8QcR64uLrq/BfRo/zfIguIKEAqlrgAAAGCWDQIjj2K9wKIvixOFBKj2NyTUaSUFxHw4VOSrDRlCpCQQBWXZgf9P/rC0bGp86V9JrZNYI9qhMX28xQAJOiLsP/w2nedHx966bF/O5NNEYF3lsig9Q0hnbsI6INv2fbcp21pTdQPnhlocloZHmhlODeS6nTI1p1ljhgsW+/TKIrYETwlO4bhInjmAHSDYrAe/vEl+GilpwEO44oAvQKA3Dsum03ln9LrF1MBECR2WPeotFGuph57/MTPn+BkxxhJ39NAGIEbbuoYkJhFw15HSLl3CtnlfqjR2ji0niUDaSBnRQGBiArRS+D2oNbiGZ/aBGMJYqgar2IowkWlJQBMgkDMTAJQCoUSkWgNCtEVZhJYgJMZn6q4VUyMAIWZkChsLp1XFDDamNo89G0CIgA5e+89acWlAEhIz1IgwkDDCo5Pa131lxYZCLx3SBhI/2maKk3sxZAKq98wYKokcQio6HyZbZ5JqNQRuNQWFZFgVlXE7/JLAQahIlSkmJywd1YQoihSCC63aZoiFUYR4pFKTpFnj4ThIAdV2nBjw6IvSNOEX1GpQzvh4BAKihjEiUeAoCestPYrKjhhjeS9daFhKNjGIqiw0UgO7Dt81113NOrGsyUxznlSzJZYGe3YEmgQ8dZrHRMOYtWoDSW7nrf4s49/Z39y42Rt2wj0rW5EzjL1rBKRJxdbb75getdo/zdu3TlQ9UZs+r6d99OxZM1yu/vJf3z7a3ecv+uGGy5+zXPz2i8PYWP/I4/NnX5i6ryb9g3d98ht35o9sFcgPvvqXY/O3Z4lXWhm59x47f1Le+858s2t11y565Knn5qeu3zL+vXuaPuGax/YeSPRvmvGs8MDpzLlnIhyRsVgEcgXbwiwcLD4ExGJtGHmoPMqQTshlJtCDlkLEUjqvT15ytayeIJP9aa/dfuTz/+Vmz7zuc+fOd75xFfq17/EnXPpjFq7485HHn3y03/7/EvXjQ3ix3d/etvFW+PhiX687/wxPzy0xsL8geMfranfmuUxn3NOqUWJ47j18JVLW7eduOpdW255N/mYAbME7jgzd/GTCxduafZzj6B8pNF5IAQRQlLeg8jJ7pHUDU52j0IxBwXHXmsTjY5ONRut/qCXJJrF5WkPAE6dOebVHgvHfJ7lNh4fvgRl7WLntIJFoGnPc1GkHUu329XQHG1umMkeiKKI1bxPrKWa1PWGdS+sxRu3bD0/6yee08kJ2bgzakTbDa4fZPPPfKaLh/czHgH7ZOcCePThhdm5A93M7j001Wi2s2x57xODiYkNt3zjR1/4wuzk5PhLX/KibdvWdTreOsmyLLNZv99vNVomNtb1AFupZYOe2SP7OI5RyGhjrXXes0iS1BYXlybUuCkVRUK6LRq1oCUDGHzoQr3qxCmlgMN4F9kLETEUnkWoKAz3gw9SkOiz1npkCPORUojHA+a5S5Komgc6YSMYpm1IxYmiAF7lIARtPaEyEaA49goUSmEe6QAds5RcBRRgBGQpN7ul628JEQp9bdG6S6ibWQjQMwD6YtlMiADCAuA0kABIwJiVjCZFSlCUKEBdWq35cldNAujYIAppAREQUOQQBCypKEdJ8lgo7aA7d7z5zx/dfXp5anxt3u8n1kQMy5JZcXUvOXttAPrCfzf2sRc2bnvjib96uH8JYTbgfi2K62i9iVNnzlozd/O7n+fU0OJCNjPdieMYw6YAM2RUqGqpziUjrWqgvBIBajC7UE2X6jkqsLPZh1ColAo5uMoNyoaDzQBcmMUiWuCwrKQCkKwDQYURfGqJCIiC+SsROfbgwWHdUAYg8325fLz2od1PdmXdOKadPMtAEyBK2244CgDDS6bWaKT9LGcXqVp3MHvJ8DU6qXnMRUBizezIeQEgMj5wfgDYifcrFm1QTJJJKUUCsTbBnqVITgEiFMDJZZXghMG58PZmWdZqtZCBsNQ6FmbGSEdsHQiA51BlWlvo3wKBJh30OsK0ObyGtSi27K33uWOp6sXMqshUBQGWGnNOOPesSQVMtYgYUipskcgLoY5MKIOCCp1iEGRAct4KA2qlCJk5LH4ZxSGDJgXB6xoEUQuwD8eyqEjY+aIYAQianUQE3pNChYTAhhB8UZLmzoGA0qb4eMYwM2dWtAIAncToPWqT2pxIDwZpFEXBdV2g0ADgEjXGIBZYG40CEBWWkSIQQLNkDIuAY1BKG0M6VOQAAD63AEDgERWwBu8iJXfeuntxsb1p06Z+vy8oGFFuLaBVDiyCcFjaC7J4gTqo5hW/wlm3ff//chq9/Y4db7rg5LM3LmYSocjRTvypJ9bcPj3yxQNjn3jO/p++dM+v/ujc3Ys6dk0EyXigtDoRxz/fe//I7u/VPnGuet0b+5dcMbFp7a//zjtOLhz814P34/PdyLPWkZOv5u+dtzP1Vy6ZZHjfmrv3zt478oaaRN1H+TsykX5raZ4I87HNvcWvrW/J397hAQvZICFADMs2AijUg8r6UoQFwrCkgIuEMRaW5RwG5fsC5ME2e8mCUvJF+97oDKjnK7W4zI5+nGd3dU0yDnhDtOROfjQ6FEMzXzf3YHQ40nGsc7vc54VF50lgMWm+pwNRrsOQAyFHAsZbOJ84dYTeFvXGAZAHhAx/s1vWPlmLDDB4Eh1MZVdVrJC6wcnO0X+5789ilYQwJCIaQML8VhvlnPNWasmQ996YSWdrWXpRFCd93x2K13e6g8Hy/NFD9uSp+W63NzWxLR1YQbVu/cRPf/SDiy56+h23/6jTThuNWr/Xvf4Zz7npRefdd989oyMji0uHjp58gqR13bU3uTyZWZzp9dWaoR1PHJjOJRsbWxbg4aGp2Pjt5w0D6gMHv7Zz18ax5Mpb7/x8vf60Jx6ffdinvd7iBedfMjo+smHzmvGJzd62SBvSZD0BaQDbbAwNsjkCJARvGdAKeBYhJiKyzg0GgzBszrKMmeM4DnAGDMmnBGcJrLQyHDw7Q1AL+7ASvQnl9DUoCYQNMQepGs+uVKMNvTIz2zTDihdU/XARm1utNbOEaWHgVLCX3LtYK0Slg8i8ByFBImAhQAGUEjizuimBcn5edckYCAUERFQNrIWDpkEhzgWFHQ4iojgQIuDwCzCAzQCCQalImHs/dXYtIgAihTBQWCiSsCFhQyC55yiV3K8Zjh548sQ/3dNZO7lmJMkA9Zn2InvPsT5rCI7PRrkXyN2vj93y1vEv/OXMb393cDVQ5lmaoEYiWrb1sXqycHT67b+yVQZDc71OZOIkijloSAYaNKFlr5GYOc8ydGSMUUTChTAFr2ITBbNlI4oKxbTwRAoGWsY+5FFm8KXid0irKEV/DAAogESaCOMirIf5h4gErzrM2Xvw6JtRknbbX7/teDS5vZcOwDpjDAoiUW/NUVxu4aC34E2EnoVFA3K0Y+2u3EMUE4G1lokUhk/uXJjThJVmVTT8n9dAyslH9bJV70bVH8MqnEG4wNDGhelruJNcCV+vmh+EsCgiwGIDoU5ARPLcBjxT6NUCSQpApGxt82CpFB4ZFcQtZI505JwL4ch7D+HOeW9EiQAXGnwiSCpgNcSHI0NYNL6hg9dKIbMXCU2wUlQqR66ws1yYNgmAiCsQZCt3z1mf57liTGo1Y4zl4hdFZalnS7M47z04T0S9TjeKDQC26o00TRtJzQkzOwDwzotnrXWktIh463wYnlWOYMEQqfT5DqMyVfptB5ypVsazA6DAotBKAUCe585Fx44fUUrlaQogROC9AxZNJOhEEMSHgCXi2VmOG41Lblq69RNi+0qp5Yzf+8DG/3x0/YZWbi0d72gGRITbTgw9+393/feN+7/9kj1vu337Nx43pBkVapfHpI6Ob2z/8m+vb66dP/y4jkaydPf0vr3rbnjZW/BvFu79lpw84PuZ6h1t5Co2dW5Fc81kuDXZ63U6y3kmWl1zzWhz0u7f++2XvSs5+uN/ffUz0h7kiE7lBBZZk07Y9TTUmFkpLRLKyxIKo3Kf1gg9EgspzyKSaUyccGGMgsAAbPXUePO/Pvb25d4T2WkBGGIZNJvr1kxtZr/ct8eao2bpeG50I889TKfn7PgFHe28/as3w0iy6fxmr3ZydK1ZPzVxev90z112cupFD8/3pzSlkFnTIsal7Z9d2vWDDV/90+ZgW15HyZHS9A3njl+9fmqJrPIqIi3iWTwhEmkvfLxz6H33/9XbL3/n5qHtjhmV8t5rEcnzXCSAmFjrmK2r15rtwWB8YovPvXiu1btjYyP1ZmNktHXt1TckdYmMXpjrnTx1hpSv1Wpbt1zS7c1HtadrVc/5FFB348ba3OCnVOufmJ4777wLWqPAMOBoL/pz0jzbtHlzPZm+/txp29+mILaujxB1BjNnTqW9Pi/ORuPnjs91ePM5Z+08f+Gy67fU/cvanVmbw94nD+7dd2hscu/GDVtaQ2MjYyaOmix6eWkWOEQE1CrOc9domiiJ89xlWRbFtcADds5FUdTr9SqQBYTurwSCrKzIVzn6hXBVmGaXoSuEOA7TkBI/BQFIXA4hqzzNzBDIlFXIC/m+DH9USgJViGsXFlqlDqIIiKB7qovLSkgFYA6DxxVUQrgcrRUAeOHcF0oOIbYWobmEsYQlJyOw4yC25wtR4ULAEsrfC+WaMFy90rTy3SG8ARIhg0Sk2DFFKIAi0Yjq/u2n9pjhDTUDxNn9Z3hqeCjhPOu3DzmLggPwz2ve/Z71//HRhZd9dPGVWoFYn8eccK3d79e1zM7iRWuzZz/9rGPTXkdKRDQpR2CtJQFUCgWIkH0hmxC0xgQ4UrryPGcKja1wwLQEzHfhzEChkCYkjpARIYzoq9zjmVQJzHTel6OGMIqAp5KqwzCDNKLEAtxM6NCRY/cdipJNJs9zo5UHjIBJKd5wIp4dbZBY68WgYbJsxfO5G3f1srzZVIE/o5FAISAKkbCI58J8FJ5SiFUvnhcBz4X8+FM9r7hCGq5aBgd51EpBXgIOoOyew6tVvQNYJuEqexXHRhEgoqKgU1H8fChSOgAYUuXGBwEgLJ41KQIMLqjFwDbkVUK2HnClVgi/lwO4SQQBEERs4YNCCMWvLyrNov4IJkxY0vZWVKBX6tQVh0oiAssSAN7lYiisyfM8L5jHIoSoQvEtEugDqmSpeW/DoVJGY4hLzvsS5q2gVLUDgHLrFED6IQGLiAfQXMi+VsUTMwOQMDAyUSDCcpZlShEgs7fsXBRFQKiQHDAIeIawOkEUzzh65asl67fv+yoKByFvRMy8ObgctJs4xAUCmO4lL/7mBe+97tCHn3XgyvHuO+7dmKGJmROUpW7ve4/tH3rdpZue9rTF++5e+Ny/nvX7f8nnnNvqHMOJbesvfk46Np598ZPpY3do1rlaPzm9QJ2H4Hm/OnTFlY0N61tD4wtf/PiXXvYhf+TQuenS1qlLBu1ZlZu8Riheu9oAbAMS69vMrMgIhpFT8IYiEod1YKuiqO9ck6lN0BKRXDINiUBGmCgt/XRu29Tm81o3ff7mOUXR448dNLHVqp8N5kYnmVS3PtLcvnNqYo2uN6P+6NKSW16z7/ALYHj30WWEyXUbrvrOV7+979jjDaO+8On3dce2f/jegycyTcqbTJMZWvfAH/WuePD0Sz9/zuc/VUvzmsSZWVyD9c0jGzdY45QX1iHMa62DW4YIx5Ssb23ZOrqTvQTcSSG7mKYpERkTe+9B6cEgS2pqYWGBlMTapBkPUq9ibfvZqTMz4vuLS/NaJTqq1Wtxd5Cefc4FSd3feMOLAODkyVMiPDE5lTR7s+f1RxtbTkw/YdS5c/Oz03P3et9LavaxJ+6II5pZ3N+Mt/TSJ5PY1uvNiXXNoXFz7oUbhofR5rOQD9iNz3ePxTSxZmr4wPRH0u7a9VPXXXzpxRTlp0/35xb21KYnjDo0PNIYGW3UTBNVtLzUty4HlWcWBlmeJIlSqtPujo2NLS8vH15YOP+CC7QxGAAyUKSWYliw+kBW3aQiIRQi9iHrQCAvgS+AspWuVtgMqXLzBqsOWPDBIKIAFSYiFg8iSql6VPPeB0e2ohwmQq0MEnj24hVp1EiEvrQNroLg6q8wCKVCuJKrDJ05G5i/WLo2havjQCpe9bMCYbxSWAwiWFgKrnpfcrdWRdsQfYgISu/0CuBKyltQzJ6F8kxvncSPfOWRO6fHztmIRxZ547D8xoX2K3fMJBtGU1KxJfHpjvr+j6//h592r/yL07+HitgDkkIvaZa3WnHkYf74iT/4+wsXfd3Hg0ZUC655oZ4I+UlEPHvSyogqlBcBgMV7b7QGRK7om0E/yXknGERJww8JqyYgUsHnOfBSlCJVFmQBXI5MAlSZZATetS+qrlCNee8BhSNNFhBwogmf+flBH68dVdQmZRGJTKTyNPe8/nB9vjkcrVl2i47rCUs/W6ohrG1OtbudDbrhPYr3ucuhGMYEEmkxtFBl/1S9CVUR4EHoqXDoqvFdycEsvqoHAeJIhypQWKyzqxJwwYopX5kAjy7AWtUPD5yCQAIMd4NL5IG11npOkiS8mVhWcRBAzuzD6SgKViREjLQpNjNY/BbEAkUFJcopZFkiAkW2dFxYKTGLfh2oRD5CQHuUF1Jwu0tcGDNrJIiianIA1ckFiKIISkZiOAbhYxljRCN73+12I2PSPI/iOE7i3Fld2qkxMyDqEqUViicscSTVBw6vInMhqBcH4TznmDlJIudcwLgAgGfnLEdRZPOUaIjZEVGv10mimggXDToE2QonIlQfbl780vYdn0wwZ6NtzkGQyXqPKK56iGXUsqDecvvO++aH/unqw2dPdH/jx+cv26bVOdHgiSfv/tx7Dv7SM18SHX5EnXOxv+b5M/fduv7i86MrXkLbt7Zv/VFn7Xkjr31zttynjeuGZtrHP/e365/2S+nivuTT75qenv3Omz6Vt8YOffbNr3jFjRRzz1JDx+Q9WIUalXYuTVHVAaxXBMCCguSYnWWvWGuIUeW9zEbaodTJYGY7orX1KSLkvqc8qWhocdk94/lXnZp9/LJLrnvXu96968KdNpU8w4cevk/hmOTNu344fd45Y4udo7uuuuKR3Z0rrtolw/olesN3v/2DOWt+6RW/GY/UfuFNvzo5su7o0elLHoFZm/RJIknBtTOfr/nun5z4xT9cuPQr40+8dJ7SrRri4+/ZZ1501tZfjny7551SSAoFmL0PE/OAx5GSxA8AGkr/OGNMnqdFj5j1IR3EUcvbrOdSE404gUG/A4Raw3KnP+jmpGCpM7Nx07pmLZmZPd7vZa3WcD87bQdqaHjKLOXNkanNm1Q6kEsvu6jX4R3bz0uS5/Z7feF2v99b7vvO0msHvXRx+XRvEQ8f2bv71mO9Xmdh/qBOsubQqCRHLr5izXnnTXY7Q3vbP37ui+n49D1+5rIf/uBbM+nN26Zec801Nx46vK+mm3sO70ezNNQa3bzpgqGRqajh04GxKRNRr5sKCRL2+/35hbmzzjprkGeMYZkQQicG0eZqBB3uiyot6sJECFWA4AU1HJaCaRMoLQXelVeCGFRZClalcwgdFQISSiiAg7Bz2UxT4CcIuyyLkyjsqguhIFRFaGWRok+D1ee2ECdcFQ3Lg42IqLSqDnYRecsYtPJdq36gL3pcCd0kIlUmE6sHA0QkCEQqmJEpQeIiUWmjBpkjxeSjZp2PnDz1T99xI2sbS6lr1nHfdO/Lf3V+o3bff9yuzxqWxX62GdpfX/vXh+263zj+F4BGA/ddrgwlzrAeqCw7Noiff0ny4mdfcOBUV6GkNldagbD1Lqi5BR7I6nEiAfoCEQyZd8UwAwLSCgERCuw6MpZiaKUzoyrbIQEJmqPhz770iWMUVT59EFCaECS8LSEBhwW/DLwxBkGly3Pfv79P9bqzVmmtPNicObKkW7LhqN53dieLPSliAOR00N05cm7DDC/wgjKgAFkpKN3rAo0/aLFJYRyyctVVmqkAfYgroD8padZBlAoAkKSo3gCqeZhSSiltSjBXYeRHKy5GICKKVr+BK686AgCweBQUwqC1zt4ji6AUl1/WgtU76UECVrEgFocRgyl2rr60PSgeokAQSw8L1HBaLfssyyCOAQB5xQBOSjBxdcDD3CJkxZg0Bzo1lnwhJCzp+FVB6diTgNbagwzyLMyrnLXGGNQqtMsYzGCck+AmV4vChiAU66gUM6c2DxL0ofythlirRxTVUcXSCQRBYtLWWm20UvXcZoAURXp+fvH2O++Mk8TlNo50rd7Mc7e0tJREMbOH0CwoZEYRP3b9r4nL5m79VKKASIdRlWMg4OA3VdSrQACsilpNfebxLU/OxZ+4Yf9PX777Td899+7ZBkhkdHQyW9g398Rlj989OlrLPv/JvD27qNTC7Xetf8lNi3vuWv+M50f1Rv++70VL23DDBSqKBx9403I2ezjLfva8d5oLnt098iP75NF0bDjOoJYntkFEkMSSu34Nan3dj7UWIgUIYCTEF4xrRntjnVVaacwbqNI0zdsz7XWbhn3X16KadalJIi/K5WnWbo+ZLVomZk8vb9m0dW569srLn/3YnmNs3et+4ddPHj350r9/5RXnnfPrv/66wXH99r9938c+9A8mrscb+OKzho4tzf38sehlv/Dcr3/y61/+6W1XXHJ2ffLSNSPJ9EJqQLfRGgXNw5e2HnvuzDP+c/Toc2qL628Y+fYE3ProvdfVm3ObdrTUkmN2SmvvvTAopUKRzCwB/k9EIKIB4ETvqCDwoJCFMtYgolhATnPbEXIiWg90fzCwGWoFkQYe4kF/dlDLzjg310Fm6dLg+JnD2qBz+cHjT9ZmW625YWcpzRcbtdGJsfEkJu+FIDYR+NxhDcyaWgtHpmoNZnU5nQOUgaDL9eL8mXSQPfjAntMnZj95z11nn6suvOysj3x6ZmpjMqIGa87etFb9v8PHHt595L7TswfGxtzk2Zv6yyPT7eU9935OqebIyJp1G9ZOjEz0+31m7qW9OIojo+bk9PbRzU+c2eO9856jKGL2SHR8+RA89avKMQBAjgvuqAgFb0JAESFV8Iwr7KWU5NHVk73VZ6wgxRIJAgpxcCoqA3qlwgGeCcVnhSeoJw8OIUj+kggV0gtVnK0ScIiu1d9jMXDWgWIRIm/12YKcqgTLvdCmhIlihaetiL0StIdWJpCyWkYbFTOAoEZdFiICgN7xkIlyFuv6G8eTV7znyV5rw0bd6boEEfoRXfg7D26crE/WOM24ifTpTX9OwK89+rcdqUecK4FYIfhBjsYrZ2yNFw793d/dNL0wUICKtENhkCr6Vx+WtGLnhSWMXsELixhtcm+x7DkCFMuQMsZk4otmv3xwITpX+oiASCxc3pbCrEI8FCUZVok5iKMRaQAK1p+AElno2bTVaB7Yv3jXvmz4/ChPC5FSoyNGnQ0vQpwnS5C6HHykEgaG3PmdU5eCxAoRIlBaGAzqlW1uMcYQQQEhVKsScDWxxABCLjvFYKVV9cpcdsZFgRcGACARxtWYZMWIOiCTAQRXKLNhJi2r2kQIDReACmKNhUZLUQ1orZHAWV/Qa4JqViC/ITJhYXfIK4o0K3scKA9R5QaWZSKFc3BokbVRDdPwnsPSpNoKB8XQMDqSSpSmLCjDmL2aEIQ9URCBB4BiC44Fp8vmmS4R477stsNvEWYAMsFiHDFN016vlyQJCFQK7QKCjCJivVMMoFccyaryaPUjLq83DGAlqkV57sALAg0GvVqtNjLcCv51IaREUWStD1hxz0wognL+eHbTts7I2Oh/X/Pa+u4P+0FngCquJdrEllmAVaAsQlGDIiJysPkSRLEyuPNM6xnfvOBzzz7wjVc++va7t33hkTEFOCD3w8MHk1pz56GHkkNPjCqdff+LysDcobuaebc/d/r4gQdo+aACOKbQxCP3msbd8ejs2Hlnv+SP2qceOPrBP4VJuW0xuvKxo5dMTfqOG+hBpuqcN0RnaEZ73V6e5ySstRbwIl48a0NiLVI916cAmLiWdWl5dq4ezTtvFiQHtkm9+ZOf//fPfn7L+Wddve/gbUvzJ269O9+68dztl52zsHDr+Vfy2NptG7dPn5i9q7Nc/8r3vzIydOqS4/57v/RLG1Py3fgQPbhm4vxn/fWfjebtm2/+xtmbtu5a7E58+556/1h0w/Pdlu1u0BEGTKKEs+0/+cNHt//S8ef8y4XT4z+Z/OZtfqx3+12f/6OfvPMd7zjn8iv63Y4UO76ydhcAKeq88CZrEfno4+8FCE1BKMEK/x3vw3SIAtJToDAlAVyBd+FxpMocTYr/k0WYvT8sImwKoVo0OkJCIsXssZBjEnYeAupNytFWeH8JqU54DvBOvh/uuf/0Pb0kzU/1rPuTKKohqEajPni8Z3QyONPOH11IovHYDBuj7CDLF1z+ZKpUVKslxhgiCg3h/Pz8l3/aSGpJMWFFLC9FELARNatoHr64hI2UK8+VFVEIDdV/VsU4AODC3QypVJUranDrMIyvi41pcXSjUCKtcixQmuI4ydK8mIsSiDAVQKiVBlsC3rliWsr/cfAuEkOeWxHhVWm+CIgB4B8WuAhBHBg8u7CmYiiMBQEA0INw7qQcj2P5JSLMDgUUIBRoLQna6IiYi88sT0w2Pvm1+368b2jjudanMajM9HTa4D5MHl4wcbTYA/nC+r/ZER999cl/XZYJDoxrIFRapy4zuU6a06dm3/6i9RddsGHfibTViJk9ebBZHhR3vfeESFqJiHXOKE0EQX87pA3vfBLFUnojBkZ/MWgFCSqSIoXURuhoXXnHClnsclLgvX1Kt1fcfAl8FgAqfXapYplbm4009L//4Ak1toZIe43Ks9fkvbBo3rAPAJK5esrLDWpkPvdEzvLmoZ3ddIAechbjscRGFbmzGFQIq1Wm91Wqk9J5Agk1FsK5wbpbELTWxpgVe8pwCcyoyDmHSkvALTGX6Y2CD1LIaqgK4C6UM2GogOUACgkBNWDAUgXob3gjASVQZgMHoWrQSYITSWmRWzKAMSgfBfDwUwcw4TKxLAqZ2ToPBFEUKaWK63KevXfERISKNKkgFsMILByESZgolAyVQkgYdjNz4AGHTxt4/EEYBB3rKA4rgABvDuKykdLe+8xmUS0BAB1HzjqHOaEq6wlRgCr4wZQWxcWyAMGxh1Lx4yklgi9esHKJjKAjn6dxHI+MDB8+eGZmZiaKEq2jPM/n5hZYBJAFWesIxL35otOvOntZAL667k8N2Hcm/3LwRvvnP19nWQBZaWAn4hkEw3QvyNhKQewWRIhRjNDSQvzKmy9453WHPnDdoctHlv78zg0tX5ubO/15NK8Z2XpVZ5Yhb/LscAb2yDxLLKcfR2NOJduODo/MbL/8sV66fPCRRZNf8KYPcNad2f3NhpuJcO2xO/fdOX5s7Y3fM9l8v99ysKQlmfVLrJC9YmYQUsqAKKUMeEBEh9bRQpaO+oUX+uT7taSrR9TBxZ5jL4IaR9Olw4v90Zuu/0OtU8zT5OJrL9l1w+6HfrJt67lo5u+646EX/+bivkcevvjyi5GW+r39r3/byxcWTm694EHjO3Y5Zt64MPPzxWhoU/3XbnzVa+/56Tcves6zzx+a/NmDH9O9W9fC5FEtSCqlpA9RozO08clnHb30lgOTpuY5t435Z/5oMDX/hW9N/O1lVxWaN0Srh4uBLh9M5hhBv+uqjyz1FmtJgoilzhyySCDEgIhzXuu41+6wt0qpHBkYCEhpYBFSSqNyWe4Bs0Hfe0giozR6HGS9SMVWgfGeSUlcbwiriakGUmOQ9npLvTwfIDpgndR1rFq1ulJUyzkDZITIe+elh5CgJEpLq9GIa9Zb3e0uPblvd943arTjPF9wznMf2r2v0VAHT3+yJudcesFLMrswPjE8v9Q5fPgwCALT1m3bNm3a/MXPf/GqC5+2fft2X5IuwvlRSmmI1jU2ru4pi6AB4BUCoCdkRFAhBHj2nliKpqFcAAdpVhN4FKGOLBBYAABGKS48eUE8Y4CY4koIC/+ijRKRLBtoSoAEEVm8BwFmFWwMS2GmqlwFAFD4f+DZUk6htTaAK+2voWKfF3CkVa4uKjIkEU9ECBJQSyHks3AUmzBLCR7hKx2wCAZMUPibQuOT0PklVGNDODcz+8+3LJ215byl9lw/TxoKBypNcuWpL9LL7dA/TH3ohsZdv3L0HenEZWPcXuqkulbrOUgZRnQ8DLi85M4ZN3/ypqcfnu7V44bpD9IImbHoRawLOGf2jmjFL5YEKitipVSQoQiXqpQihRwklBVV3SFTmU0BXKmJiFK6Z4cRtaYyOVTb0DAtBAjkb+fKzQU457xSiqKs17l937Ia2qhS7XwaQYTsjESoYLDhCbRKLU9keqCY8oGK6wQAI7VRC6kh8ojeaiLnvXcsRACl95QEGbenvrcVyC68CQXMGFEBeu89+6J1C5ZEvrAhClfjvRfPFft5tThzJfUVCuSVyqNU9KzqEgDIra1ewuqreifJaEPkhZFBKRV2ukqArUNEKPQpufDJCE8hCL+thmIF+l1o9I0Rj9bbzNmYjASYFVHI8Y7ZOctAOohBYiF+B55ZGBVW0PdQW0sJHlud7ImIC3ILA4AiiqLYsheRWJssyxh8eCERcZClwJIkicszZzNjTKgMJOx0CINhapi3r2iSEwXNECqnEcUuXMKrZfI8Awh6nIYQdz/42J/+yV+fOHFiamI8TzOtIgYR55CA2QHgC7ctv+rs5VhJ1By5beK3Xtl+/1paaEyot1428667pxw4k8REyjkfoYZgaRoeKBTucIKCoKWmfEJ53//x7efuXjj1L9ccPn/c/vr3dy5HsVh1l24OgWlEyMAWhnxCM9Ho6aF1g1Zrfs265fpIZ2hNdtdXcziz9cXvMlPbj//v2/WpU/OQNvpnoic+852F8+65eXHDGjuxKUswdp1B3ygWj2wRyeZ5p7O41O4BkLPgva/jWDftN8fjXVsn7nqgHZll7wdK1ZAgVkOZPamj1u/9xifvvO1gr39qdHTXWWsu+59PfvGcHRd89dN7h0dql1/xW9/79DeedsXzU2lF4tzikw/fLFvPe/2//Okbd24E14rXbJjttMEv/CyZSs89703XXf3SO/fcOvW085571RvuvuerR9UTjq7q2m5il89Kjiebf/7TDT9KLJ5pWe2J7bxPPWzC215/Z7vbBmEjRALeeyVl+QxBTrbog/WUWTOUDDcajaiWZFmWZVlreCjPc5SycI4BAOyIZWcRkYAIteOiKkREQ9hX/VoSp2naG/Qb9WagoneTbr/fJ6NJQBHVa43U57qvN2/adPLY0VjIUz2KIgTlna9HzUiiZq1JgMysjC7fQgxWCsoBdFEIJ1rrL3j6FYqhn6XWu+X+4mU7t3Ta8yMXprq9PTumFnvdH3zpJ7/w8hc8d9fzGDxLdmj/qfse+eEkqg20YUdrJ1I0yFLLmQATmqTWsK6PXiEJKnEuB9QMkQB7TCOnjTHeCQmisPPWe0sKHESE7KxHiqJY5bZnvAYfWW+xJBohgSJSChjB+TC/xmD9q0hVEoAQdHGLXI6MyIDABREVEQ1pRvACDBwRMYoXCJ72GJb7zleqftXoLMQ8LUEbnwqCU2jcLWecxXFsSLEEA1QiJCdOrGd0SikmBMDQxIMrWFJE5EHEs0YKYtQJkAcQ7V0mxkTLYFuimVMbC/eTqab/nffvnh9aF2ftDa2hC3YuUCf/9t68PjHcn10exEO/0frSm0e/8sdn3vKDwY1yfNELDcUNHuCGGs3ZPmMjTRRMH/nYe27o6mjAVPfLPW0UiEaFpb0MsDfGEClmDl68yFKv1cq9vAAiKAp4ceEwOwYi8prY+TD2x4qZoxEANAN4LoyjFGEpp1wM86EYgGClfBSSAvsgDS4CzByW0yqh3Y8+ed9ifctkLfUDbchb8WAV1QaDmmx8NFmsq7zZApOhjaOey3wc14dr47mNKO7V8yYYYHZUjpoLfqkUfvHMzHaFCcyViRCIiGhUAKDCwroq9RSFAiKKgi6PDy0jIWhViGoVG2IuPSec10oJiGPnAYTBsScixajKSpSZHQeJEHTOIZAhFSlNiFop0gYAGJxzLixoC16cKkMNQGhPw2xJBXHKCkvNIgQMAkgIKDqkQnTsSQQRExWx96nLQhqLtQmVkDGGPDlkXjGBCOogACiKyXs2SIgq9LJAKMBBZTuMlUmCZCl48cpoKbwHy40yQq3ZCKnaW4E0I5Y8z8GzMQbQ9Qc9AEiSJNhXhN0zIYEiDVQQH0iBZ++sUkoAhFBAlFKOgUFUZCgfKDRRlLjBQCu32G3/1u++df703NTEhHhGJBREYY3kvEfRKPZ1Zy8SwMam/c7QyxyaTW5fs9Wwy/3nbO58/LE185kRJ4ReIwX5OQiyncIKUaF2ziGSQUQHhJyB8wiffnT08ZnoM887+KNXPfIbP9x557Q/ZO1nprbH51zGY+vdAHri45onXRupj+a2L2jgsXvy/Q+Pn3fT2PW/MX3LX6V3fYkmdiRrdtQW251ue/Nm2TF82b598/sfhZMzx2Tgxzasaxg1t7AIAEbpKy97/nUX7Dh89GhSrw0NDZ2ZOQGnz6i2e/DuW9qnqTuIuz3OnU3qDYTFqL503rYXHD9xx/iWgxvoii9/7ePznSM3Pf95s7NHl9OfXbD9hmhk7zOe/op+Ontm6eD9j+177atef+/dP4eJP3v5qzkfxF6c8a0RhdFFLeUfWDp+eP3Fb3n52IvcsWOzXa+ObkjoMxev+cbZw2MbknnxR7943hkNOTGwBs/k2cMEo9c4hPeffuyczsWtCRXBEjnraCr1HkGAMpQIsOe8AGY6y1PPbrm9VMvrqFWtVisUicuzGpZeABAgEt12FzDXOlI6vK9s6nVjzCBLrbPGGCQAFKUJCeIkQmMGvX4cxyG1p9ng+JGjKKzIsAcQUlqFHiJNU+99pA0RRQiFXiOpqggd2JxBvPfdbjfAHxrN5sjQhqmxDQqjNH/a3Ozymdmj2ycur4/F7/u3j77+Db966ZXXzMyc3rbjadu2XnX46BMHzzx2rHPi7C07105MNuM6SjKw2aDfBiBHWQxIGQNq1iTUB2cTVcsdiDilUMBnuUMgRYmzbBQBk2bvXNdzFJsWsPcycFy4foZJ5kofwIWQFa4iAWPQbHVemCUY6wKWbXExiAugHmYGVZgwVtPPsAcOKCGEpywyi54jcFFWjdAhGP0qYF4RAQ6+ExyEok1A2HIhf20dEcUm8lDISIeOMBgAA8qy4JDEKSInTLmvmZi8thDBkt2+hr9392Nf3jO2YWtjebBgs8HjR8U58dJodzIrcGN82z9OfPCji7/w2aXnOMmiejLR8x3ntGoeSTvNOjXYHNt74v2/tfW8XWOz852GrvVgqOmz3BvWLrijV61e1WYREQinWRZUmUo4KJT3U6Do1VGBKlIaSzEkIAyNcxAWJq1ZVkBYUJkLlRNULvnfEKQNpVR3Kn6f2J5dt6n1zf3z4BUZLeycOKXIYAOxCznitqPx3LCJOU8T51GDR4SEqJ60BpmLjFIahDzJStMp1cUCBI2GoF9RPd/qYhHRWY+IATIWREKql6r8DoFVL0/IjtX0tdrRFuYNRifK2NzlLgcWAAEUD55KopQmFZBp3hVyMVmeM4u1tmC6IwmhsASabLETkcJCuAIxhg9TDKsR2Toi4mK5m9fjuvMBdF7yhgWYBYnisPYurWSVUr4oSVXQOJcyDYcttY4qO2QxuhAJAQzHcUVhLBw5JMSn3t5qFVUNAAQxCHcX0pgKG40Ge7HWoi7cCUXEsw8KMMWWxPvAjwiYfBExWufOEpHSqt8fGKMU8iBtm0Szo3/+2490l5am1k+mWR7MyBiAXbURkOGYNw3ZhpFY8YvyL302/9N/nvj0e8TvmHzg7OUfb79gz9KeoyI5ESky1rpqqIHMQYI2KHVaa5GDeLhH0hpp91zzuf973ieee/AbL33iz27f+OnHxvtzhweD3tilN+gdZ8d9Bz4TwcVeP/P9hko0s0kaa1/7L70nb1u+8yuUjCZnPa2+6Wzc9wTvu/XQvodvfP71b/3HPz188GB7aXl5fmZ2qT9/pnf6zP4sy5bmF07O7s1hIc2y8WR8Yt3U1c96WWyibqc91KjvPGtro9VstYaX2t3jR07009O1Wm1+1h47+fDE6K6lRf/aX/xNINn96P7164af+fQ/mJ55oq9/PHdkz6UXPRuYkM3Xb/7chedece8998dGAfUR0WgYHtLdxci01NTk8vyRf1s7/vJmt5Y9+tAVlz1D1Yfcmh+IfxzmodfyBybzjFROYjrKHQJULNshmUoaWL8fbt/kzrOz8fjIxNRk1B50tCCLOCfMzHlUTyLnGjrLCok76/Kh1khk4hDCJCiiR5ExplhroXiQ4ZERZg7mHlongZZuXU7aNGv1tN8LIEZE1HE0yDOX+aSWkNGBJRIp7cF7K41GK4CkRDCKTFCWWVmH5HmtVmNmnxde1lDukgWAtKpHERFlPk97C0SRIdQ0MjEZjU6NZ7m97umbL7vgukefePDxPY8fPXn7+Fmf3rL2nCi6QtpbTx6aP31wYWR4bNPWsQ3rx8dHtzTjcQftzLMVdIgGfQyAKXipW6eV6XoGwMD+J/EsbI0mUeCyvJ7Uxlsji+3l1PZ98FFZITQFm+5ij6rLXa/3K5K8WmvvnYfAqSgGblh6BVRHuii0WcR50USiBBiomJFWxoKrJ36VRCUoAFhxESGpHOaVSCE9DYxh40sAohVzcHKT0FqhUkgKSHlmzz4MbAVDjyegwYNv5pR5ByiZzxTnKOibiU0H//jZdPO5yUgvs6jmu/kix2TySFOWd3fVjn583d//sPe0v5v/XYKsruI068/aWtSwyvdUwszxoWPH//EN69/4i9efOp0prkHMwZCbVYZSagWXsJci37hC8bwqLzxIlmW1OBIsKCtFsC4poVBINMrKUxOx3tkg7qFIKUVaBf/aagoKq76KGelqo+UAX2Vio6xLf7L7TLO10focWSLU4NiKeGqY+Fhvcr710A72fQuJ0o4zxZjVVT0yjX5voElpw875FWqrFAoYxbEtPQCqD7OirRjehHJh7ECEC5uEEOWrRBLuAzMzB5g3+/LnhzkHi+TOAoABgx5Dkg6cHI3/1xk3FAFBGw4AzMBAGPeKaK2LOXP5waoLKSCHq+D9oQfIwUeEoIKeDFrr2DrWNvxZIRqlSxJ2Acrz3hf8gmDHEm6RYPhggBg678ohsfr8mggAw40q/n51Ei7qvBWgZTjFwe5JSi41EIpnJaZwNyEIkyrLXnOhjocEGnV4R0NdgoiiCAHDFqMo0AGAxbOrJ3EKnq0kNawPNf793V/69re/tm7tZKedUqwIhSlstoUgoCoLTc1ISaSA8/a7nrxgUN94fOxZd0Y3/mz8t3ovHd/w/P7gyP354Xuzw/erheMVGrTqExhBCAPhnpmJALmQQ5nu0qu+c/bfPO34e59x4rKp/ltvm7DpfHrgQQLwazeTTrDdJeJESZZ2qTG+6fUfAJATX3tLPz2ZeMzOHDdrtrXOunB8/Wj7+MzBbCqurT/vwjXkcu18J+XMzaYZ9zrdznL7zJkznU5naWlp+syp2+6457a7HtZaj7SG2u2lQwf3X3bZZeedd96uCy6qxa3G0LptWy7YeY56evxs55ywyjN00BNL7XbfxM7mL1mcX44jHPTnuu1tl8kl06ePr53Y5N1/zUyfjmLV6Sx7P9g7Pat6+fxit9PvZb1Oa+qnmxqNy6PW0pc/Nf70G7v2zTk/TPCkLNjB4FBXvG8sSWYVKC9MSkcU5+3ukIlRs0maH/3oJ0+deOhtb//tep2MNrGZMvUodfPtvM+uppVSaZrWajVEzAepOB9FkQhHUWytjeM4CN4qpdJsICK1Wl1EeunACwcogdIUxa04qYXCOdKKmTNnjTJxkjS0RsHhZiuO45mZmW63W6sn4+PjeWbZS5ZlRketVouI0jQVwjDY8Y6DmTuV2vFFK6kKAedMPAmJSBKP5rYDyqRuLu01jIl15OwAh1tDz7z+OS6HSzo7u71dncHPhtfenY3dPLxly6B7wfLCxkcfmX30webo2NG1G1trN46vnVzX0A0g8pB3Bn3SJopEQZ+9VqRByFlRKlEaPGdKUbufbVzfmp0+et89+6+86pk5MGMuhJo0hP1UoQmwUtJTlUpLwQ0RYe9RhFYZEVa+91hKJVQLZmH2XkABlPK2IiIIAlTCulaCoIeCVhl2+WH+VmQaAKUj5pW4WVXxiAWyN5BVVNkJhdlDEZTDZwMAgBqhg9zmnMakUs/tfGjdeNcN1g2rD3xh9wEHG/u6neXaQwQeJHMWAfob1OkvbvzzfdnmN596x4B1jMqCqyFuX9M9sDDCDYfdJi+c+PSbN7/uJdfsn+1oIdBKFBnudjUY0Fxh4p7a+kdR5L334IPjmxNWJUXbg0dRBCjCyMCET1lmB7zVijJDCJsAAe/GjIREZbdU3uRQmCJiRcQN/VPIkZ59Uo+77blHT0hjtOEhVQTMkkSmUc8WF6Jk7YO+lUUzQ5wTkENgIjOwdm1jCNAw9pRSyuhB7hXC6s8JUKiu6PIjrSSJAp1X3JNyQh4qD/HCwAKlLGKVL0sodGEkEO5mhUYW5sQk4f0MrkRUjp2xNCisXmwp3/WqO0TEAId03mIp2oyroAkBIw0AUJKFinGCSKS0eCaBLM9UZKy1kdGois4ejQ4Fevgt3loqZaSqIZMiA6XpJ1S+EYhY8hfC5+GSy15M3ZVm5lKHGAEKzGNFa8ZKZT1ce8jXVAyllVKGFCJmPh/kWRRFKGBdDmgQkb1455RSRuuASw+9b+5d4TSjddB1r4o6Ad+sJybC9/z9pz74X++ZWjPqPNUinbMlpVFc4SKKAITgZTGVE1113tggnP9tw9bQoYt7By+c/u+e07/0wAvyjdc1dl47csNbUEeuPZMdum9w+N7BwXu5O4tBvF0AUVApEFEeCUqTcmIAyB3/yZ2bHpyN//2Zp84bz97wgy1HTu2vLy3ri25wE03kjrc1pVScuMama1o7rjn4gVd2Ty2Z0QtdTFBbU7PN3Nf1+NlTG6/Ix5vzM7O1SFDAx55rQzGPNoaiqUlk5gs8i3jH3lo7yLPe8lKWWhGcnj45e8lFneX2Y3se3X3v/WT0+g1b1m14eGhkNE6isbGxNeNT3gvFlogIqNvHbnepWZ9k7o8Nb59cR5nzF132rG536dKrGoBZvTasojgCtqQ1s4bBQp6yR9dPjy7N9/YcWPzhLR1wj+7vD5vL2+nWg9MH59fNdC89KXWGOvitDg0ZY5LlJG/3Jh9sNs+ZfOLIoc999r2aZqfGhnujdy6OHD516quN/rPHx68cGqFa4JbFcZzneThs3vv5+fkkSYIQTRRFeZ6LgmAlRkp3uu2wfQwtHSJqo1UppN5oNDQhM8dYE5FmqxWRGvRT732v12u1WlEUWXGziwsR6qGhoSiKwuFZXFxc7nbq9fr4yGgURWma9vv9fr9fr9cR0VobGcPMYCEXYYQoNoYUIKaZj+IkqC8oMoNsRtk4jlSWDzKrBExtuDU0+mqbvza3vfnentTubjQfHBv/4bpNjW5v08Lihif3jh3etzA8eWJivLZ+zcTadVvHhic8eJcPwBGSzn1OCnVCzLkipRV1up3Ldm34xtdu/o9/f3+e8q+8Yf6Vv/iL0zP9SLWUKpEmsipilup8FbKjysQh7lR/DFESACho0QX6YyWhAMCFiqKwBgBatdgrRar/j0xHCfGo2qTwGZzLV3dOZbhEcV4FwkkwbtIFuQhLPzsiKkBABEopdqgUWwCd52z9xJapo4cf7/d7uH7yoz8+Pta6tN2bS30cJ3kNKLV5ZE2sFj6/5e+8qNcf+6s+iEanleaO37Jh/NyNsmd+Lpvh8cbBW97/wrN2rt8/kydKUFOuRGweaSWKVG5Y+XC9VfrBVeIqImLiiJkNFDi7gqkEvBpAVMxey3p/9Y1j54GoBIcXsZWIVKnKtPK1CrwPBY+lIJNYa8eIjh+fXUrrQ5HqZrkmDUQuksQYkEG88zgARGeaRAopU4Aq1j53a5trCbWAj3XNAQb7FPn/qU7CU+kr1XWtfp2k/L+lyhwASilbNl4ABU1i9fcCAHixqyb8pqTkBoXO8BoX49/qBS5V0li42KeuAuSLCAtTScOoCutw02Sl5y5gdAEwRqDZOkWFwxggUmSclOBGCNZRhWeJc45Y4iQpNsrMjMXwqcr6iChU+O8yUaAhgSuYCLyK/ktEIp65hHwTVs+6OkfVcwnFnJTKWYgkAOw8ezE6QiBtKM/zPM/jOLbWutSGIYEJUOrq9ypARG9ddSsAwDtXN9pa/66//sT/fO4Dk6NN60AYEHpKRQqL/tsRhScgCAZgc9MqlIPL0WjMdcO5x7mBzj398Ghj4fheOL536baPU1Svb7si2f60xtnXNy55EQBkp/dmh+7Njj2Qn3yE2HlhZKKw/ncOQFAIURyTMvz5/eP75uufecGRn75i76/+YNv9p87Yfd/Is8vHz9plaay31G1G40PbntF+4JtbcX7shTvSelNF6xKBhvkO1kZm9PoFXrt/9qzDi3zJGmFfc+J9vxMJd7HQGzGkAhBdaRVj3FyzJs9cnrvJySkibDbrnXa71+t5O0hTs7B8utNpd5Zk9vT0Pnly29ZNLGR0bWgU6vWxpBZZnxHgfOeMXcA4jpeXFwnjpYXZOGpmfpbB1nAIOXORlpxNRCau151Z21wbPXNz/7zzH3xs98lb733g+L1nnry/116GYwAft3TK8BRDk2Ndb3aGzJzdOL9te3axoP3Pf/nntHPw/HMu23vgvsmzNtp4/+c+efMV5xy97JLObbd/5dwt12ooDeSFsJcOIqUBoNfpRXEcRdFgMGDxxDRgVkqxOEO6XIkJsFAAMSIgi9aKmXPnRUQbRUR5nlvxkTGurHBFRKs4IRyKasaYPM9L8yKpRXEjqYU6ILzlcRwnSRKOrjGm3W6H11cbk+e5OG+UJm3ZGaXAc2pd3mwM9zqD1LejetP5jEWcbaAsCHZNs7Zm6JKWv67vstTPd3tPZIMHN204MN95eGauuTS7vtsbf+yJAxOjT06uiXaetSk2Y8NDmwXZsEltnqW5MWYwyBTSjm0bPv6JT3/2k5/4/P/89+vf8Ks7zz83y1S91rK+S9QoOqRVqKjV/1JAaolCqZ7nOZQDN60UGhNmqmGzyIXWIISBGiIqTQWTzEoYLGutkRQ7D09NDGW+LaDJGglU+ZFWIVSrFTsGi3URYS6gwiX3A6hoNAuYUlH5IxKyQudZRy1J28lEvX14/4efcWM36x570b8OTzw7GwyGVGxa6sxy77IdQ7c/kscq/9iGf9psTr/oyH/O86hRXiG6PI+H6SDPPv7QaHsh+4Mrk7/6o5fk8djRYzOmnngk9iqhSEClnZ6ONCoUX4wNqh4r/EsoJatgWoWwwuStiPrF42BhglJHAldqI0Q0pHxod8p9YUgwRStZrhilIC6thGYpZMcQAYQhNvDIwTNdiEe1p1wJW41mkKU+jQC6vOk4AMTzBo0jj1SQjnH98A4AEGfrtab3Ie+WFsVlmgxtOK/Ko6tTcvUCVAkyTC2qvFVuIgpPreKZIoS+v/SUxOI/ALHWhtQL8JTKssqdoVihVVi/gLSiVRITRkXM7Jil9OWEwCVQKuDg9KqJryAppTxIwC43dH3gcm0MIgVpM2Z2wsHLJIyIiEhRseEWQlAUBus+t6wLjQtUFJrZQAAP38hYgK0qTiBLrsov8Ox9QQ0uzSCxMpMIY6dw2wOkoComvBJDJnxC9hzwNNZa9kWODxs8IlKRqW6U9z5KYvA8GAyC1whpXTfJO/7ivZ//4qc2rpm0uQesUa0nAwLxwrKKKlkQGv/h2unzx9OP7Zm4el2vZ8sphch9Z2r/dt9IzjkiIiixg+7e2zpP3jr33X+LR9Y2dl6TbL+qcdFNQ9e+XlyWn3hkcOT+7Mh97vQhVMx5oQEKAEYZzCWp6Sd7+vlf3vaRF5z+xksP/PXd6z70SKqfeMjMHR3ZumZiZBjO+TO3dLS1+91j649lM+3luRziRr0ejaxJ1o6uH7V7lqLJTv2l1m6jaKgnA8ylgXEHME87SZJESmdZJgJKae9EqSh3LqoPRfUwFLQ5u+bQeJS08kG/2YKJqXEg6ff7eZal6aDdbidxC6V/eH+b1HLSAFRRHFstwzZd6ixzljsTuwjHrZuzjodHmplua92MXCLMiFp8O88d5k2f6EZEuy64LOepb996S031Fp84fvTYUfWeUf+2JTxFa9Zsa9Rqvdn5sZmxXz/8J+OXXf7B//jAYw98bmykefzMwScODDYsbcyelyZrLjl702sOH/q9l71x/9c+29ZEBRkmz3MisrkzxpjEBCqYZ1dgBJiNMcIgINoUOI7wpNl5bQicd5J773UchZJTo2JQtVrcH6QFokpkqNUa2DyuJeg4qJ6GI9psNqutUmism80mlPIUSinn3Nq1awv5Hq1ExOfW5nma2U6/kyQJomYxgz43h42wdhIEjoymLrhYYd11jcf5GVxo1nRL11rJNRg/w7nu2vbJCzfMnlh4NIYx5NZ9Dz/y+H735LGjmzZsbtWeXD+5Zs2aDa16K4rH2Pmx8dFuZ/Dxj37g+PShr3/z22/+3bfuvPCKK57+tBMn50CUiZvgVoZ7q1sTDwHjRAGhpcpNkop1kLUNUhIK0bJnYF2CboqUAcwCyIyBaRmiqGcuhqgrMbFgy1S6WFwky1Jjzq+OvyzeigdBFQSNCZCJmbG0WvLOCWG1L2RmjSQAAVTsWAB83cRoFdfj8aHoQ3/84eF44ngydqR1YT2f7pk8zZQwpnnrgd09ari/n/zQsxsPvO7o3z02WGcUgtcevAdOctXLWq3u0c/+wXkvffElh066LE2HapPEWVdpHfe8tZoaUWTTPBPlDSku7d+pzEaImJgIAIKAfojLhafCU1qKCnpWPCPGcgiLCAAaC1d2RvCOxXkWAUXBSCdMJuH/P2yoRh0ipJUgASmVqANnMhfFjvMoqpPtS8+rRDtWSfNUd/y4WaqhU85oDdp7r7WIh00jZ7G3iqSRKGEk8ey5cpIACM56CIHS9lT9L6ByPRD+pA0ABBESEuAgY4mimRDRgyCVjW/ZZwOAC77OZToBFrZOAEEFEnxp7yEizgMAEwaDP0TA4ObHzMzOuSBLieXetwJDQFn8hao0aIZUp6bKYSrSoAQ9E6FGQlQgoElB+E2lQhmW2G9kCU7AAQlFREHBKhS1VjxxUaBoUFgGMSJSmgCAFIAnkYIJHja4pBCQijz3VK4iEQlKVfuqQhmekQgUklbA6D0jAjMTEJFib4koMjp8jJLkVt4QAtIqxMahoaHBYKAi02hE7/6Hj/z3/3xs46a1gwF7p5gWlB0SnTsWYC9SPEcAAcZfOmfuty+a/eNb13/8santw+lN29obm3k7V7ceb909PSQkyLmwKB0xs/dWKXQuh6VT/uFbenu+a4yJ1+7Um6+Itlw+dN2v0bN+1/cWsyMPdPfdmR66iztnQDwAi9c1HaXCZ9zQG3429ccXH/jHa6cvn5z8k5+Z2ZMn+4PpiRf/NURDe//t+dnJOaCelibJCCfO2e7DSkd114WFKTcvG09dv0Pg3BeDj6PUG8UpuVocOZuDVibSQVSOWFye6ZqxNg3TFxHvnFMJ6ETF8bCXVKsoy7IoVp0ONFtxvxFFsSIhlnTQz3vd1DoGZOTFRCsnkOXOLTnhOfamXm+2O/PaQE4jEwYmJ5IeNKMoQsq9qBrr5Sxt6cYlu7ar2ksWF6+7b/LWE9/96tD3ZfbnfMnfvWjL8zb2Hj65+cc7r4hfsf0FL/zG17//5U/9c2ws0IZLL3zazKljB2cfcZ3+iT2Pza05eOnVf73n1jtfct3rtAeJoziUWoo0W5fneRLHSZKEZqIgy4b9kNaxNtZa0lrrKMsGWmsdxSHuB0Ri5iwHryEPsUkcOx1HgRmSmCgdpCYyeZoZY5z3pCjWGkqhnNCyhKCJJbFBa62NAkWR0iiQW+ed9cLkRWsdiwxSSdM0TiJBilumVhsH0ZymqVBcM+ITZxbSPlnp1eq1GkWe89z30acmN8pgMrTJw85zRp++sHiq1pTrRkamTz+5MHdm/ujuA3NyZvM2kd3Dw8NA6HJ76vipRx99FAWvv/bK3/yN37ryqmt/9/ffMn18QWsFHjAXoMKGpdoVlc0uVTvUol1zjIgeQSlCAvRBdhlFIQO61GmttdJegp0aVjPAKn2KSDC6V6Xta0DzhlDrSxYsPEXHgAJWJZgA8yox/apQ8MKEpMp0ooCMplyKBFZhfMKFaNB9ybXPxyfMD7/y1S/f/5C+6PpH9rt1tVHfnjXW9MFqzYmWbmLePPSlXxv55p+cesv9gytRsWUloHJKG8PJicPy9LWHP/HvL6ttSu4/0WsZIKUyK47y1oB8nGTGWemzBoWRGK+9rhIeIiJj4SBbqlyFzimkYWYGZqikjBGRipE65z5gyKnUTw7OF8wggXVNqCONAlYKAxsAoPK//z8JGBFRkTAX0qGMdQ2nZvpJMsSSLy9lI3U0SZyR2KweNU/ayUGyMGxM1Ldc005pjJRWYCZb6yV3RlNkwIl4lwFqkXICsaI6CqEx8/KU5X+4vuIxFZ5FPqC/iUiVSPvQ2kK5ughmbtWM3Xvvy/aaiHQUMbMSIB2F8QwqkkIZHQXAMYsP0jpQjWqKmkbEl9hMa20ou6uGvvhdRc+9imEMAACZzRWgFhQRrUypmGECkKpqfEWkSO0EQbSkuMCy20YABFEQ7ELCwsV7Zl9WXmG3HdDvzjmttRWXZY6IYm2UUkBQbNDLFr9CqAAAaeWtkzDhJ0IiLnWsAoIpbPrSNA1TPRIojMaD69FgoJSKa4lzFhG0Ueyln6WoqNGI3v/+D/3HRz66ccO6dOAEsTZswI73Bh00sadgVSihBFICV63pve+ZJz/z2NgnHp8AgANL8QcfXgMAUGj1aBFnTIyI3gkCGq0FrNYE5TQ0iiJcOpnNHe3d+yWOtFm3K9l2VbL1ismX/yUi2dlD/QN3Dg7c0zlx9/xgWfu61toO7Lvu3PTA6doHnn3k7K1Lr2kNzfJLaPwXZr/815vi9sbr7cGjjUbSIaKjs9maJJocah89uRTxuqxp+ej8Nz/z1Wede3FjfEMHJa2pOigSPTI86qxtt9taa0IipYyO2AF7h060JgA0WucDp1SciZBSmcs1NupNBUp7R/XWWNrv5ANeu3a9d9jpdBh8p50nNZ3aNrhR0e2aBp9nWtW8dCM11ogVgcrywan5Xm47UaOWxJEsL9LIME20ullGqn3+jrW93gZBOPzk0cce+daVO1/yJ5ved+q9u+3iKZiobb76+vsffOyz7/k9zafXrbliIZs5sP/2yy9+Vm9m/hg/efjAQ4vXvPD8S357+67X5emsJgG2TmvNIuIch5GOSB4mwx6ceK11ZKLcOSGHiqKgg8peGa05UCvFEYXtWnDdCroHLgR/osREZT1rnLAxJlZaFU7wxTQmHLncu6LfQiBF2hQ2XowQGkUymjyD8xhm1Ybq9Waguud57nPv1MAkcVTXEQ6JZzHCaQ0xjZWmnJkyEEEh1IoUWefQeYCs6/OhRtNbs2Z4/aapa1CljpcXlk7aPh47enR5qT3oDmrNxhVXXvL8F97YTwcutze++MXbtm85fOgMKm0g8koAETxKAEARKKWjIGVnnU1T732cJEprx4EZAoAQSwEAkVLLHn1hAOALpTAIN7GwEIDC0JcEjDGpzcF7EYmN5uA/oxUjwQqasdQ1Ay8iBFCyolQAZ1HhHIFh9qUBmQVBuFQ5AETrHAKQKXqUQLkVQNDKWh9FCgR6/YV777p3dO15be5sX9fMegvLYmvQbZrWoG0HRl46+rO/n/rEvy+8+uOLL4gVRTnUGi5jEajP75n5tWub7/3XV7XPuMVTcS1eEjFkDYPVaAaxBxbwRIhaGBCJtagCi4uEoQkLazwsB7AFpgExjPgQAHy4zUFbH0EAkbQuNOKq2SwIEJFnFkJA9BD8kdAAGkErhe1VacBcmFigL3cEAJqUeM8kUQRIQDpl1pgObrp4ePfeXk/Q8kCJilonsrFu6+BaAIlRKbIa4k7eW9NYuyHa1Ol3GsOJqWPecbo2LJxba31utdYaddhuklYqKtJhlX9JgFG8MCoipcR7rRQqY13uvVOoEJFEoSbvQ/ZZcZYkDPtmAGAkUEjCUNgIlTNw9E4jMhIEzYaIBFA8kxSVpgCIgCJdYbUAUSGZIP3BAiKeczKamYULL20QcMIBpS+EAdvFIuBZKPhrA6BoUiBBDDLIdvuAOirYEwiJMhGpUCph6JVJgAU0oTK+4okJCq4y1oRSb8QLgyMiAUBPSivvfc4s3hORUdqyzfM8KbQ2g4EpCqHkDgmDvVqovcPjUAoD/CN4dpFAeCFDxYDs89wCSxxFzrm828tdpmPN0TAAKWPHRpsf/9CX3//eT05NDmfMDlkhkSimggehmDSgMDJ7IhpP+p9+/qHdM7W337bGeycQtgYELIAE7EX6RASMHiSUkezFCymKBDx7n/s8vEekDWmD1vGRh/qHH2izt7pe335VfcfVjXOfO3zNr6zxNj/+WP/gnd2DP+ueOiGu9+UpeeDp8dceye7IF/9i+EU/HPvf47/8X5P/Mb5uFM/e0nO5dOfdjVeYyQkB7Y/Nmjvuy0/OC7Qm77/vyFdu/tn/e8vvJcayi0kGGAcHM2406sycO0uRgWBuDwSaWCSKIsveKMUgMaCIQiBFzg5SBYLGa62T+pSIsHfeezSYp5nNcw08NjIeRzXH9UB/BRaAutYEOmrVG5Ex3vvOcrs36Nt+putmNu3q02lcr9WiOI6wEfPFZ235yVRzbOLsN731b3lpkM9Oe9fbfMFVZ+b8+9/z1nZv+pd/48/PPue6L3z2PxNaenjP3RsuW39CHehb+8QTj7cXZnLLRFprZSBUPuKTWpyQISJr7VNEDr0PfW0YO4NSSqlS4ztU1ViJ5VaCD4gYKVXI+peLRq01e1c1LpWBlyoRiRpIIXGpAq+RqLISE2DPoV6NdIQFF5OCoETVloV/SW2ukQDF5pYRVGQipRHABmyIBPGKlTUYaTOwfUR0vNzrgjBFUWN85DKayDZtv8AoAhRFmrSxHjyDAdfpdY8cnY2SGpDK8jwo2foSrxFOtYOi/VJKhZar9LFZgaVUtwsLoxcpDu6q0kREwAsSeSnk65RQqF2K4MtSKFUxo1ZExT636NgqGb/Q0AhoIAeMKNX4uuh1kCJjwkjNg4RC3jmrACOjc2cVktJaBJDIeR8pzdbbPGu2pp54dG+tNuztcNzyc0dvrm9+ubU06C6vH5/Yah/60Lr3frd77QeO/VqCuTI1wU6UN88IyLH9H/qdC171xitPHQfPDVUDZZMYxCJmxsWuaLDKXqrEkHsAZqU0KWXLLqRIS2GtyxKc9ZRSkdKOGKr5fBgSAq3cvaJYKW4OABitWcQxA4SbRh5RKTLlFDr0QEIF6RNLzDQzh7koCIKgG8CaZmJtr6Wb//TGXa9+x22nuNZI6sh9k7Sz0d7YXMuyVbrOIizc6XW3jp3TGBpqz6e1uvZeTKSZRBiMKZgt3vugwaTKjm31GAMDPbfCJPuC/7Oachr4Bavfw9AsAwIBBoYuBi5+IYBVyKUV93nVyoMdV71sMWwAAAAXJjeljAZR0BEp5Kt8Rbzm4ruEV4HLWSoR6QqiHORUBYlQhYFQYBEpIg/irA2XmXsLlUsVAHsu6nwXXu+y81YEKI5ZSiPRUrqm6JuLgTYiGWJmheSd94DgWQEKgo4MM2fOhjW2Knd5wCvqYGEOoVTA3kvwVhDCMEF1zgWxjlCCYJ4zM2bIGSB3lcLxyeGP/9fn/vnd75scG3aaXJpFQt5xl/th426YcwDPElZLMfn/ft5Bx/jG725xYhAFi3kGB0XbUHkxCEsFnRMkUYLMXSRBFOdsv99zdhDX6pFJAFSo8AQY0nb/iR/0H/s+OE+TG5pnXx9vvXboutePPvfNftDun7lz+Rnf2Tf6k6e9Yv/Xbr7sg3Ov+au19fdd4Tb98+C8H9duvbt938ONNdvxjI94Xy5Km7oZG++wbk4N2YU5+d/P//A5z3/hOeevy3p9jCDxIV6iiAChcY4RQFAQFUF4gZk5zLqiQFIVYGZCNMYLQpYNcmvZB0g7JUnSSGo2yxuNFgEKchRFykQi4qwf9HuBkeuFc5s554zWtUa9OdQKenCjjdYgzxaWFpeWF6MoikycNBsvf82r3vTrfza5duNiLx1+/i5JsbXtwn/8yzeeOXjH7/7RB1/+il+59Yd3nD45/Yzrznv00e7MiblkS9yHwf69T7SXl0fHp/pZqsOwFwASpSJjHHvvfRzHzq6g81eHJ3beAzFzYL2Gb8/FaaBwWlajDZVSztnq3Ia/D/HCu6DEuzLMCd9bVM0iIEBSQJmqKVPR3IR4F94eJETMvSOiMDavUE7siwLc5vnS0lIzabSazaJLIAoi1QNrLTMRGd1AFTGyiFdRwdBtD+YZfKRjmzOi0lorkw3yQRxHipFImzhGxCzLApzburyiEBUlBQRkowrsAqVURdwM96QIRauQq+EOBKXMKjiGQgQARClEdM55lKCVU8ZQUKgk7Go9gwTX7uLGS3nVWGr3UDDiCLlqFQJWYWE5wSXyGQgVAgpUVu25dcwMSrTWOfuaMbWoPt+efdf7/+p9//aJR27/ydTai9cmg0d/9g9nv+Cfjrbbo/zExzf9+WODbW879PYsyj1xH9JmPLrv1Oxlo51Pf/qF28/esP/gfD0aV6YNYIQk4wHpGH3h/RSeNRGGTRcAgPPV7SpKFioZVIjAhZctlcCWUE8yoi6caSVsKLVSIILMIW95BCciIrHSEu4OIgh4YARkLCQ/gzCFh8pnTjQpoRUzxyqUDwA2jw1hvjSfD1/1J3dq58dj7g56xrR57TQoacwOEXsgzj16Q1mWnTN1fpZzLj5JAJUhdha8wRUxSKVVjDpMLCr+wuoETIhBspuZyRRCLp4LcWxFWiv0uQ0JL3xgKSexUr2fQfoRixQY2D7VL6repWINXwl3YJGqi2K9RJtX9yQcVaBCriYYxYSPbdlXlWh1A8UVp1ihLnNzUbOCIjI67GXD9pcEfGBgVwxAhQgUmN7Oeyr7+BCFJASTyvgBA78dypMBzEwCJBJiEngO/H0QsBxm/QrCIC2s5Fcph4eXczWAkYG1iaqX1hgjWnxuB/00BAdh0KqmI2V9e2Rs4r8/860/f8c7166bBEIaOE3KIevIiPXs/Jo1U6DVmYU5zp0wo8h7rzt4/tjghf+7c2GQAArialkYFvGCjFi0QERUEuBFRJwfICOIZy8g5CinTKOAhxjYUUHBcsKeBBDEzR1dXpzP7voy6Thec0Fr55W1Z12+4dj7Nh7TNjn99sb4q7bteNcjx68dwF/d6M5qbt+y4aIt9cHdB3u3PjqnANDWKKqpmm9qsv1sx1nxJJz8+Q9+vuuC37fmNLlxhi5CYFICCYbtg1LKCrOIUio0PBSsukSK2UlgOyAZoxCR8jzYyCKLTTNWShDq9brWxvpM60hrDYISSZIkzubOOcc+/HAPMuj2hCFSCkQGLo/rtbFID3pdb533vt9ur59c42ESatGIi2xty8iWNR/74Lv37rnjb9/1/YuuvvrQyYMn5w50srmHnrxn+1kXPXjkISBcOzl1aO/BPQ/tfs4LXghZwH0UJTT2+31ENHFkjAHBJElCJhAqaPVElOd5LYoBMZfCWoeI0BfmdFhZepUbtUJVpxz9KaXCGSClq4dfRQGtdaiYmV0oFaXkgxfZgIuJFiCGwkQICo15QSdiPTOL4aIGV168Y2e9996zExQnhe5ghfnKrbXsbdZTWhNJWLW6zCllEEjrGBFNxOH8GKXQxACojHHOGU0ut0EDNsuyAsdR1s7MjCLhTAJ4RPDIgCsBGgAKTm0pGVF9+0qyFEEWJy78JSCFyFtsyim0vi403SHqBWq/BOekVb+rKqeq7ucpn0RABPKi+0EpiR9KKU3KkBnkg6CgqaCwFu512sMTI3awSJH++Od/+8Pv+f5k4wKA7NDhe1/38l+uGTi49z8m17/ow2vflULyhoN/v2gxSgB9bThKjh07/gfPrL3z/71yVjUPHu6aZAy5j1ahkpTSqNbM+4O6Ih/sPWAFs1OUcaVySyXdAKVoYojcJBAQuR7Ei1AQOfIu87Y4vQTgBQiRQSMFaopGDFtwF0o9KHKqF2EULHerq01wRQQErHcKiYNkRIGRFhFJM7nowtGpr3WGGr4/wMZIrTPPBFNxcsBNLQCAXm6xUiAOBCLQSuDcqV39PDOGYsNZ6hQyKi3ClWGRFw7OBgBQEflWnmZIY7bo5MAoCI73FAFAUGcLHDkSqRRMuVzqFxvhsAkvGmMK1W2VFFfGBoToC4J4OHHh6ZgSp7kaLl4RXovXzzNbz2WCp+DTsmo+VL3/q55q8VAQMXNWgy54YkWHHfBnTzlfZa1LCMgswlIEDpYAtgMs1FiL90oRqIJr45wjAee9MQZWEbQQ0Ql7a5FIKU0YEHsoIuLZl7CP6kp5FbVJyv2IIHjrAEDHEVuXpmlx/KMkk/bY5NjPfv7w+/79E5t2nsOS9TtZokkDsvMiLApFqUarqbWaX1xwiID4u7tOvebs+d/84bY9C8NCApKH6FLcuuCcCsoLA6kwt8eSig0ARtcFPACEwohIE0beYc6pUUoIQQqbnUIrQIxzGVKO7PzJ+5dPPHL89/4UhpNmcl1j7qqFsz9/yJ944Gz4xC3wpS/yt5pHbzh4+NKzct6Gj85H//7w+L55iZXzNmI9OLOYnLnf7Tyr7+GnC6duGhpdm9u2MqUvKgIgIIvNc4yiequZpqlLbZZlYaKjVLn2WKV3JAxaGVMzUsa9EBW5dOtiYBHxrjCBTZLEc5xlmXh2HMxCVH2oFeA8eZpl3ncHfaVUXK+RF/GcZVm9Tl/59mda0c6Xv+zG7Zt3/PCW7zz6wL3vfu+3d5y9s790RjJjrd20bor7WWemPTFWO5mfGRkdOQ3L3UE/3Hldq9X6vV64kjiOgx9wP0ubSSMg4AO2JYywwhUaJOd9gBoZVIjIhMGxmleBErHEJoTqskLnhvwR+E5F4QxCXOoQEXj2DKKqgwoQ0KekiKCQPQoHyBPoYM9HRb0ZOvIwtYjj2GW5994Ys37dBm0UW+ecq9frQZ82z/OwSIgUse3m+SDtucjUoihCNOGwBYk4rRWzY2ZPYJT2IOysUQrYE4ECsNbV4wQAHPFqP9Eq7RXm7SwIpNRKdADPVZcG1U1b1U8opcICKYwBrPXBXjvUsNVsXwJKUxgrP3bg3Isvn0gVCEKSRs9QETQBsBz5eSoyGQHqYMTnGQGtz0won0h57wnRumzb5vED+4781V+8+ZffdPHpg8voJ5oNPztb37Bu+Ec/+NrYxIaL121/S/MNG1T+tqX/PJPXBsPj9YW0OaSOHTj0l6/b8M7ffd6eM4uS9Ulb8mfAtMQ3nAxqmLiBRrReIiIHgYVVsVPCokFROJmEFNJtRSAJ99Mz++BXSIVdLhaELGLmPM9JFaUPhsZFwuuHyExIqBWyBPWr8N+E9vr/oGCrG4uIjMX61IOoQulBLWe8Y9tZjeaTfchj1jNzksdSy8g3zuTjA0p13NbEyoNz5AcMI/HI+uHN1maNOjbqUZ55jBVbRuaApAvXwswhJVTJb+UjKdKlOEkoWcWXeplBOwxXZu+qVH8kKagsCtAJO7dirszM4LnC9OGqJliRglX4L+UL1FOWZVwvCuPqU60eeiNi6QlTJIBwXzWSrCIHry5DV+bbYUdgDDNzqU3mmQFQaY1YmF5RlYhDBiJUSEqhcCHxHd55X/kNSannyhCYeuAZSlmPEAeKH8XBKAKBAdgDcqw1V/x+Du5jhbR1RYqD4Bm86oCHlycMlqJaopTq9/tOD6Ymx+6+6+Hvfvee//dHf/q0ay7/n899+tOf+mRjpBGYYNY7JMXsDx87Ap4RiUCetXn5b64+/v4H13794IQgWGEdOv9ST75cQwELhm0YFBcAROy9R4oK3EhQAPXI5IlIl8HMs0UAY2IpRpJKQUaswAOSdc6BEUk6y5tuaY/dIhNSz9TNY7L3tfL1W+R3T7bnNHjBnOj8Cf8fz5h+24+mnugQ1AxZaNZ91q/vfcLUGqde8uKDzdGWjYE8YoVsR/S+kDKVFJk5SQpZmICyDJJBHNbqWiGArAIDhvehVquFs+994VVaScpIKS+DiEprhdoJO+/D71aEumGGSfXTASCGck0pVachz/y866/++3f+y+nDJy677uqPfuCfX/mi1+7YedbM7InUSW14OAPVs37Tutbx4wc2X77hhEhq7bqNG3bsPKvb7Xp22js7PDwU8m6aZvVGAgCt5pChYrEUKV0eV0ZEVOSdZ+/JKKWUeCFEY2L0zpWzXygzsVIKKo374AFRTqFDaxWiVRjlQzlWqs5zVfMWJkLylNgHhAH3UTEdq5G49z6Ah8sWHAOOjsG1Wq3C+kZEKvUGZlB1HXMjwn4/9S6vN2LnM0YLEhMqAAJPOo4EJWcr4I2KxDsAqMU1X2ra5XkeGuiVBWF5/BAx4B3+P7LeO86Sq7gXr6pzTve9d+LmpM3SKoIikkCZJGMw2M82YDBgP5IBkw02yfAA++FswPgBFhgwJgojQCQhhCQQQQnlrF1t1OYwMzd0n1NVvz/qdM+I33wwHnZ37tzbfbriNyDNT+cAQMAQs3kW1n7wVgUMcksRmgcpX2QbP4pyCCGEIAoMjAqtm5uQ2u82O3R7D+0WkJrFqsVfJbSuyBEoqSTmOtpGARptEOdJEiM5AEqpXr1i0Y0/ue6f//GK1esnf/WLe675n61TyzoHjs36EvbvP1QQ7H7s4Q+dt+upk7MvuHLFg/rlKe15t7rjoux6+LlbVn7wNV+7d9tswE7qShnLGDURuJAoETCiRtcYN+VDtdBLoN21q6DYTVReYG4BLdoZG6dbEeXsL2mh0IrfZi2OSgTtNlQEAhm2RwRMOMkonuZyuLDEBABSwAXHXiyFE3nv68jdMTr5OLptX+z26Lxl5S/2zBwjWl/uP7h4UBwcrzQSOE8UIPZn+xvHN3SLRYfmji5b1kFEIBQ1t3RVESKyilOphX9rWgiBtkOFmdns0ABI0GZTRIzMSRsb4OZLVU3EgdSafspY62ajnJmEzfm0dMiNWHQeojlyzmFr75jvXb6DRCSgXLdiVWBjfBFRBOQmN2sm6aYFGGxasKJiZlXxztMCuSulbDGpIGgEZnpC5lZW5xyrsCQk9M4jorKQ84jKObMiIyhoO7EDAHLOIltiLkJge66JmNl2ZFVdc0xYBnIUFoA2tGHlYkNSmL9BIkWDniMiYBnF2j5mrxv27zr8qY9+8ZKnP3flyhWDWXHcDZg8UCSqhZNKFz0AxsRM6up4wpL6U5c+9OOd0x++eY2IiLPHuOVDLoDrm2ZDswhv5OQcoWMxDUsQTQC5fkkJi6JAJON2OfQuDyBBlECdE0LEmARIwiPd+OShS8lNq4geLhiGsLcDL34ufOfrcNwkDKOKcj/R433/pnNm/vf3hqCLJro94N7EWGfC9++6Y/b6n9/90ped7QZdcjVYY9CMDENRFEXBmjEHIQRTkbILHlPNKauqtQFWEFli6QrVeTsZRNUUfVnkGq6lNhB552JVQwM/8t5LYlV1iEml2+uhd7EapZQ8OfPofNpTL33RS7Z96C/f8NMfLToy7P/nl7Zv37/7+X/wB8OZfjUzmoQIsT8xtcUf5LnBEAGHo7hk8RpOevjosUDO7969e8WqlUuXLo3Ck73ecDjMiIBGp9Dmda1Ee82pCCGEwA4t8SAAOt+mQPPPMY14W3m2YTS3wkREFDqBiJIKtI9Qc0DNp69BmSICqmj7KHkkQ7oaakMTo6rBjlp0SXsDbMgMAAZaKUJZ17WAGBIbOK8SvfesQXWkkACHCigSQIOnMVX1nhA1QWQRYWVW7wttxkoGorMEGTql+dIIgtqcpqkhhJXIqaa2UXOQV3eijPCbCaaNO2LNHyKKxhgpI3ex2ZyhCkjNgqAipk9pL0FA5MjCGer8YBwAiLwDVZOMno/bhAogyQNG0ZhSG0NFJAEDhpSSd0TBx7pmqd/6lj8bjJau3nROLQcXL5rYfmS4dHE8dkC7XQWceM0Z+589vfON16+7fbS66/rV0Z1hbLsSxIF+7MrPPHR4joL4kgpBcVz4rlBIlSAzFUJFkWpwOiNuDJrAnJf+maqb84FtBIHQKhhqdh/YAKHtkgbnk2ZKkl09VXWAteR9mEGQENBm+zUnMtskItMU1cbdL0fYxGq/ountVLMGBylo47dDDsamFj37hMU37+z3lk/vjLp4bKycHbmxw9WSfnlgwjMBR/I+eT+XZtYvPh6140iXTJQpCQjUKmPODxIHRx6zOTcvkBx3iv//HAxZLAIdOURpOb5tMpBW3WnesTenP6sRs9Bp84uqZtmcf2lTWdo3NSejP7U20vbPJA97c4MJ2jySLNF6d0dAiEDez9NyvPcIauGFGpxmWyioKqBKFO+zq5hNNrI+uQKiOp3fIsOCQUUUVpAiFIQkIo4oKUOjrYELugVIrAAMmlREpUW6tU0tilLma2CVIkJ+k42GCVHwwXlzKsNmH7cw1nnvjUbIqGVZJo6ION4d+9u//sT42OJLL7vo0e07jhw59vBDDyLzkKMn0piIXC08SnWBzked6Mjnn/Xg/mF47XWbiHw24XQEycA92N5bVVG0TVMjcNmWBAgqrAoIQojks5ZnSiJJXYmE3lKC8ZTMNVjqhMDkAjj0OAVfD3jWY0ti72g56rNAB3AESyMum9WxAcwIzMLkohIWFZXrTC2fKv/0okuuvuPBxw8eSe4ocJruLhYY3Hvvbk5awNAIbqoKLEiE3vW6BTknzMCiMg8zQkRRxtARERRtB4e2REOzvwzBErD9raoa89a3OCfUDLckBwAdH6wVjOYKKAIOkyTHGspOGVQSpzoCwP7+3uc8+/If/+S5d9/yy6WLlj8+u++73/no7OH9L3/tm1IaLVuxfnLqlDB+3FMuOvugPLgVH66quP6kjWXZTSkN49AvW7bk4MGDR2dn1q1bB4Qm/aiKCNzWvG1B14KhRIQBnPO+4yXpYDgsCNGkbSijc+2wWpUxHxGaFxQR05PLaIgmOmhiJYLcNYJBNfJ8lK1VRbAFkkE9wVpLTZKIyLRmmBkQkICUrCslIgc4HA6f0LgQaUADragMnOpoVEPtyQWXyDmXYoUEaSQZTIhCAKAMUtWJnHOCKpLKskzMsY6+CHlETo2tqbD51WcD4MtIVOMAAQAASURBVGxtBFaWtk+jCIObr5ERnffYUB6zYo7VLsF5MON0RES0MpCZ0TsbwzXDpeydZ98750ofUkqjWBH5TqcDnFp4ljaeowBAos47DMFikjUopldRc2JhF3A4HC5ftnhYH/2z1736He96167HTvntUy5a94qJ933kq/t3ug3rjsPaXbB2z18/5dhntq774kPFBWdM33DXrqnx9UeGh3jmwH997m+WnnDC9l2zkxPjdV3X3hfk05AZRqHDPKqZO6oEyhyz7IeqZg+jZqTmwMCdzbLQtPmJGNSB2QS13nMAAILivDPaqF1288fNileg2mgFE2AgFyhDhIyOZXdTICuWAEAWJxNBVXN9tzcWyCXrHgz0pLqnX5xz7prhlfc/0l0WIPnUg7C350fVkv7YfSvIFZGHIF7FK/D65ZsTo/e+Exx2OoPBnCooZ5/2KlUAEEIofUgqSZjAmr0FKGjMZ08zR7yZiDQj6DaXaOPmxAsMQtQg4nZJm/JLJT/77cdspnm55G0fKLApfXPl7R9oBiJnZpw2GYCIkMgKRm0MpuxtUEOaoMZSTNHZEM4SBgAwaysso6rg0fsCjcGtOK93bbOlOoIjZ5pdzo2q2jwrY4ptUdJeAREIxkQirGIdikCAiCSthRQLBY9m/FwGh4U2uySzsRERqyECOYmpAYJAO9myD+Wa3O8JQtGdmiq/862fffY//vNN73jHMM7e88ADoP5Xt944OTklLJFZXd4fdcnbR/7k0x9d0a2f+a1T+lyURWDmqq5VFMGbLTmYRvQCl4t2NtTWYdjY3wE4ELOuDQBCprVjYiSOVQSEFQzeNSqLEhiq5KGomaXzq/SUncseXrP3yDbREcEmwR5MPa7v/i4ULlS9VROdJSB9GuzoeijHJ1/8h79/2QuW3XjPL/fsHazduOrBhx/9wXf/55G7b549OOgunYSq9tREUyJLuVWKJRCreh/s0FrzQ0ijuipCsCtgbYUSJuGUouEHHaD3fjQcOu9D4a0ly7bRLpu4FEWBDkyTyp4p9R4RY4xOgRFZjM8JnV7Xs1Yp0jAtWrLo93//Zb/4wTVaziwquuyqn9/0+RVrtvzBS1543KbuxJKJ+x/6yaUXPw+LJUXZ9c53y97k5FRRdkexpjrx1HRn7uihh+67M/aHlKVcnThgAghOPYGj0C3MZLAAr8jYEeeRyNd1Kruy5YTFmzcu6vYK6TjxxEIeyTQqFQHIZNuccyGQM4tQaxmJCMgBuXlFCFQFQYfoUIiiakzc2gYQkQJEFXBEPrhQRJVBNYrCLngBzR6lznnyCJRQsRtGkMg79K7X65nklkfSxGgMfe8SaARgAvIUpQKX0OMojih4QPKhEFUhZIRRimJoDxBQhhSdQhxVpBAoQCUZApBYEkvikrxpsqdYp1gHRE9IwA5FITkP5IMj770P5HxGUKIqS0z2P1NKo9GIJTkETyoOuKnHbZcJBFg4Mst0QjMtUEcJtErRJKtUs5QgAKiySLIKwCk4BSeiyjaAIk+iqo5cWQiCgiAJaO2wDJhKV/RHx5avGH/0wTvf+udvn+mP/vRPL/75jV8mDdo77opP/Ycv3MxgbkPv8Mcv3P+1B8q3Xj0IaXjjz+8cc/29u2591e9d/OCDt138zBfv2dPvdsaGNftQOEkqEZGdINZFGaaKUAZMDhhNZhPQe++dCbGJQyDQpPOAHVVVFhDlmIhVEhNrezGhWXNyHTWxR7LXRERyGcPlzEdPwTLHMNWcJLFYVvCAPoPnmgRACCGX2IbdBRYS1cQpJRNBLCh4peQkzsLKxb0lS7kokkB/JHMFxrnxo9JNnQPTFY/qoHPFqIjYi27L4qfMDPdOLaIw6Yd98UgkOnRlDu6EjDKMI8MSo4KKMCgTtP+JnDBJUHTOqfPCKqwgHBoOVW6IRFvd/6JTtrsJu1YpJY6JOQEBmQxL4SE4F7wLHh2p6V11CiqDC97kxljFBhKREwrmoV/hkFBAJYkkqJUTKqOwJAWTwzOuIVhRPop1zUkQMqqZAIJzRfA+r2Nd8D4U2PXQcZWkYV3ZQzcaVilywEYAxDsl1EZN03tT9PHBBRAgIl8WyXyTmoPEzJFTEk7IdYxm7JZ5laBR2JApIsI2pmYpnHcCyhLIAUsgF0LodDrdbpdESTLYfmGnYaUMMAQvqi6KYoA6aadb3n77I1d8+qpXveHPFi1e+uMf37l3167vf/1rEPtIRQJNInYxUEESg+h7ztrxjOOOvPaGk7Yd7QlCOTFGnSIRIrmaWFAQBBWSdTt5xsaIyApJlBHVOSaIIEikNkdyBQsM62okNTuVogO+AGejEnEegeuqfywNHUHlvR8vOqVAXemZp3fe0e9dfs0l8sPF7lHwtxbShZfd1D2F1vsQujpL9VFfHQSiVIwfnht+/OprP/7Nz23fvn3d+pXPvvwFH/rw3/7t339icvHJex4/MO4KCY7RgxZVXUdgRdCae6xJNKr265ESkh08RElSoIcoqU5RNYJY6xycL4qyLEvX1Mtj4+NFUQjkVtNGoY68Jw8CUiVOKXivqkoYQQTUBR9CQKJerzfe7XkkEZmbm6vrUbcIRYerkV7ytIsvfvZzjw7mBFMtneDLH37303ffftfKdWOXPePZoZo48vhDMQ5D2Vm98Yybfn7DN772hcnJ8bGi4/fs2RPT8MmnnXpwX9r62H1Llq5YvGQNupmAPU6JkYxvJ1HIoapEHJTU474ChkpHq9dMHd6/8y/f/O5Qjr3xre9SJkEsyxJTEnSOvC32rX6ElhbTACaJyJFTJLPPY2Z0viFrZgUoInJEwAwNsRUt6qIo5LpVVSUxEirnLsE3ZGIEIDGDGgDEmhN6V7gCWEzZIO/wPcWYcosvYG1lv9/vdrsppZQSMqO3pSiqZlPelFJG2aE16EgZvzEPpGoqZtXEgETosnGKqqgwZlQntChfwrZlsQbUqrEMOjLCdROecnEr2T9OVRPHLBpqcwijcDY4wMJ5w8FpM6bLtXBmjjJmSWRlVmNeAYBKTS4KjMd6bsPqZbfcfMN//dcnXvW21X/wrP/z0pf/zv964UXve8+7Nhy/6jOf+fy5Zz7r4Narv/i8wa/3hT//8ZinbpUG05Nrq3p0wknLP/LPH9x71B+eGyEQcoJ6VEcsu71RXRVFMDqBtDsLR2jSPLaHaAWZCQx7Ai1+u+nn5kc1C6D4RISU9Z8XDmMAgNA1o9k8EpQG1BZjREfOuVYZyjlH3hFr45ABlNURQREksikfMSgqCmiBDgGUqVdCdQjjDGOHnZCTqaJ7x3DpLAC4Qx1BmKgoFu5Amlk7tXZ6YnF/tr942qcaHQo4KsCDIhB5U29AH6vRcDjsdrvOOY0JEP2CDji1rbl3CtispcHYvUkUEZOwQ9IGdmRCnG6BhrYlDPPbIsROWaoAsMZUtzN851xA4tzciq1yicjAUNruL2zkoJksZ6N7kxoDYVBEAW60vVwjeqoNKzg35c0UmojE1saEXMfCBypKrqPdvrquUT0AaAMgsC9mXgguoYY6paqGCGlNFGzw3miRADUcfWPxB3I1p/bg5ZGVI49omjkLF4qmOmvvXGKqWNBn5oVpK8ZUICkKcnITU8XcXPXRf7ni3AtOedOf/++5uboWlPT0v969/7Gdv66lb9cjZrwLuOBfsPHAm8/c84GbN1zz2CSiIsvhw4dTSoQuTyAUBFQyxyyjnrNBaR4kOABxdnwUnSgY6EDRURa4Za8xjYQrUhaNcZQExDkkcrPVqOtTWRz1bnKslGUrjg7S+k1HX3Led7bcdOOnYuLxRxd94/KxP/7m0jQaujTb1X2qOlv77Xsfv3s/3Hzz9/Ye2FNLuemR0/ce3n/66RecfvoZo9GR226//bTTj0euCdCFUFDhXIiRWViKAKoWCe1gMwuEEEJIoB4aZQUFTimmhEXu9Iyoog3kzRchjiq7U5noEQJYyE2pKEsAiDGGEIBcPapy5GyKV1s8M/NwOCyLLlA1PT3+tre/86H77j6wf7sPFeJYNdh59be/tOmE/xto8TDyzNFqakUfIa5ZvW6089jnPvf5p5x78dMuvNBv3Lj+0IERJ/Tjj/Zo5dGDo6p6ZPWqDeokpTQ2NpZEmTmUhVlhCHYGw0pjPez3T3nS8bfc/Mu3v/H173jzmz7/pS9+5tOfePtfvnv3vlnW2uy0kkTfqPTaeRXINkH2JSIodX5WvTM7B9Xsw+obMjsiOhda1pq9lGn9hVAIQoyxrut242uXm0RVhJRUUCRZ6LX0k1JygLZ1Z+ZKZDAYWOtcliUnSSquCBLjzLFj1JCbSZWIKsnMZrXkBJIFhAB8mAdttqEkb7C8S8yo4iGLLWujl8MIrlHJR8SM37JZX2PfCwAWFUzZAFhSM6BGRRFuIEUsScc6XUHhJA6J5vdxaLnc+jZmRmzKF2xyEiIoqG3lQFJKdZ1h+h79SIYrly8+uPuRN//Za573h2f8zbtu2LLuKVf8v5988B/+4MjuQ7+9YXLfla99ySZ5xumzx0b+JVdPkutCJZ1u0enh44/t/Mjf/9tIujP94djYGKAMh3Od4DkmTVz4rkAEwlYSElvBjVY6W9S0r50pJcE8zrx9MFoMvFJW5bSmCgWdJ0AUVlEbFbbTfmzngW2ARsRArl2rGnWNxFZfaPcl5wPMlWIb08GRgBp63gECCwrsPdyfrbTrOhXHpMdCOASLBsDojnVVYeTAK0jV37j0Au9KD7OLJksekXNJEEFJuWYFh2QYCGGVlKAwtLavhds6rz3/aPA6ZSIPIK38pENlm7hL/pFskWtgHSJYkF8BQEUNI1g4j4g2dRBQEDUdCQiuZZPCAjy2kjp0AOBcsEqYFERYmnF3UXhrVVXR1hwtIiHfesOfa5OS0eJuLs8RQBL7wnkko/J772PMWFmSTOprntz8shZqWny1LoDNW+o1PB0pSKAsqM4sLAkEWJTYl4WNju3YJM0QFnRmVpYPFjaNQdKsrG5vwwFmbCYkSQAY0ehhKFf9z/fvvOOBcnz61l/tuv3W25avW1QWy2/42fWTU2Oqpfd2WSIAhKI4fWn/Xy965MpHln7i7jXz8AhRB1kjwQEAAdsDQq08uM2irfJ22pQjRCTgwQGiQ1GVCKLm/ovgiRyIilSgRSg6OQ7DiIoQqBfjkX41N+4XHdw/3Ds71Rk/YfHyw6L4lPMuv3Dud//lSa++Z/GSUw+u8mFxHBw7ePTY0f5sBPrm/ictWtqrxM0NZut45OZfXf2Ln39nOBx1iq7zxSWXXnTOU07ct++IoIBBH1QE3YhjEXLy02wll2k16J2hNNS+N1IMYqqjNjoK2pAUNCVvgD6RqqpsDuq9DxQwOVYlo2UmBptPFoFjSpp5jwpqEC1VrSsBVw+q0ZlnnfHe93/kja//E1cM05C5wK3bf/5Xb//Dg/u3ajzccScWa88QUXRu85aTH37oro//69+fcOIWv2Tx6sHs/rvv+8WKjbs7UzsdF3v3Tj/80LanPOW8devWVVXFyuPj4zFGh5RS6s8dHQwGpXenP+nEr33pq2/+89d+61v/88zLL7viC58799yzh/1kAnYsSZXK4KQyUNLCbRyQKhA5cIZBaFYRRhpxRjVDVHREkHsXcKSKqkwNs6Ep7ecd6BZ+b3Ezoxkxg6hNK9VgfNoQ4CzpKjavoOjLYmJiAhHn5ubYOaNgtb8CCbx3SdSaYY/emFqchBq5DGgeOZv8iDCKamJFYlJLz1kCJYNq8mNMRERPyAdtsZLfnkMEVIJM/Ld3xaqq5BCE8kq4QWm13aEx5ADA7E6NYG3GgjYfcEAIgD6YCrCiolcUQRRUYCxLneJ47LnP+e3+7Ozll7zqlOP3fOLj/wYBd373misurQ/vPzpGfvWaGAA+dgvvmp31XAXqDmO1f88Db3zzK1/0opfvPiAd8sKsDsqxnnCUqJxS4UIKC9BgMl+jtfc6N6lIAASkqOgWIE7bzrXNx1ZntJVfnvuhtjAuaUwh252c2QZk0qc9gaKChiNSVEUWtgO8YLiNgAiAnvJoxJHdU9NWVi7C2HDvMM3UkwHmEGPhCypGs8uG/kiXWCmJKjhwjHHDspNSBZOTVIZiUAEFr2qwGObmc7XDTGauqqrT6bTwvfYrqZAAOArkgFXJ2S4IEQWUzF+PEHVBZgIAhdZ4o+2DAQDRi2iVRuScYaZUFQkdEJFTTyBKCpaKcgIVAVRzyyB0gGiiMN6oE6oMikAxxTylaDQ+2/bROYekzBzraM9X67vbHhLnHLDUKQu7kqr33rgJLEkly6GbwXYLfrR43Z4cjyYukAfRxr7Dxp7SkpOqAgsDE1GqaovCzhZnTcXQZvScdw1iZuwjFQcYvAeAqqoMK86s3S6NapdSmpru3vyru77ype8wV6M0WLZ88s5f3/zc9c+rhqOox5yb1DSGOEBEZhKRJWX16YvufPBo760/2yxARsKiBouuqspAbsH5b94kAgplflauH7PYjCP0iAhI4NUxcawUHCJ6DDGNpFZQ5/PrC6sA+64L/eERQC67nqvRrbfKslXxjIsObj5x3ZJlZ7z8lX95Cp/x+ep9H3nGlk9eM50e+/GBAwdA070Hu/926/QDxx4nx1wLoRx6fDuRc0hVVc0SgS//5I9/9x3vfOufvPK1W3fu75adQb9f+NL6dyuwsnt001AhoYKmZA5y6hgRsSgKF4I0CrXWyHnvM8CeHCGScxYtU3PafREkMeWBjaooOgJCKgtp5FNSSlHZVmOuoKrWMoR9hw5e8vTL/ux1b/nYv3xgYsIHLoIMxrujpVu2bNi06cKLnvXo0Yfvxp8pDA8dPTIxNvbAfXcePHzI+w4/5fwTl2wt77j9jri8v2HDphM3rt25e/v41CS4xiwTwAHGmI4dPow+nrBpY3927r3ve9+PfvCt7/3g2xdfevG//Mt/3PvgQ0+98MLDR+ZCGFOoU0qOiljXLVoV8tyjwQYtGDE1h8NGQAgLsFoMStYAGb/OdO5t4IakZs6j2qHCEpjZf9rjhJCt0dHmqoRE6ARyI2gIEc1s0W63K6zMTBiLbqfT6fT7/ZRSCME14uyZCR0cIpbOm1ElubxnAkjA0MJTpQWmEgJg6UObyGtOiKAqLNnEV6GZeokQzNfm9uMmddh2zMapV0eqYlACw3pY5BKR4XDonPMu5FqkZSiauqSoc64FSLOpO0IG7qZR5Qrnva9TzazeOWt9hsP+CRuKP3vN2x565OEvffnzz3j6s9ZuPHHf4bnnPHn8VSfsG8zg2kU6BgMPeoinnr2ljuPH3dM746wLhzt2HaHRuf2ZA7fddtu6U56cOCkooBeFWIsPBSge6x8Zm5xAnZ8KtGm1GSTkxkUQTK3GU/a6cQvkJNtKpe112iyeOLb56TeKG8PFBHJRG98enY9Z1vA5O5kNFqHR2UYHaDfIOE6qKsySkzwKKBaF68Sjwwq9H1OnqpwC6NHR0kE4MAYJCDChRowkxZYVpwwH/ZWbiv4gJa40egYmzTaSJgCEonYmq6riBcCx9tNhg5xXlaaJyx0jAKCNlFqxEMtlNjk3hGzNZOTpJwK1shoDAlt5wTYJhBTZIQVyhKgND9BUirKMnTCocqZTZzjQwltjUor2I9LAcw0RzcymPC9gZVk+G8xc+kCNAK33ebGCiA7JHHGR8qZGUPIaYoFt1HzJwgKiSdkiRZ5DilARRObLYmkU6wxe69oZVfOe2zi2sC4EhCIUVVXlmtLuReKkqqCiEQB6427/ocOf//w3B1WdZLh5/QnLlo39/T9+KAG8+S3vHu8EUHRhAFEtDnvgT110b0D53z8+WbAkQlZGQAWXmoJGVJ2QAjJmfXLMcSj3xgCZmZ3Pj2FxAOzogiMVD8g+BGUmEleQiogkFkBUJEHx1ewIy1HRWe7VRVclWnr193eov3fN+k1nn3/p6WefQ9r9vT1//oX1H/rLbf/+44999bhlfgbKvUdLiolqVtKiU4DW4+M9YFLm8U4XPc0NB/v27/zaV776R3/8SvNOLkMQlpqTFOAEkUhtsmXKbhYiCDnVzjlAkMQWHaChHWKzDYFmm5Aka6YFCyNWn8VUp1iGIhk5uyisbVNRoLza6RRdRIeozIxEdV0VRYeBC98B0te8/vX333//j6/90kR3dT2nc3J4ev30maeff/yJJxX98sY90xec9NTr9t549PChyy9/5gknbPZjvem50cxxx63esmVzXfOwD+TqJ5+yvpI0MzsbQkEqVVUFcvaenB//4fe+//d/+8F1G1dd97MbZ2YH9z+050Mf/Pv3/98PFZ2xqjpQYExcF0XhFIwP2ca7hV/mLAPNdAiaKtLUZxBRm2WP0SIsUORTbklVTN0NRNU36gQWcESEvMMmYhKgCUA6cgTKzDElm1mZYHJKSRMXRRFCoGD5ZjgajYio9AG9cxLKsvTem8kEM5MvWlk7K+QJnQ9UKyPmCWquXewoSK7rk4pHT94BACpJ4qYPg3YYgIiKmUWjqsqSIDvrKQIzyxPlfrz3BKgCgNlnBoFUtRXmFNCak6hYVrANu3GWsGEu2Qs63wwAwZWhAwCpVmHesHHRl//7C5/5jy+86EWvuOX2e6/4j8uqem79xg0vPeFeVVlVUgEpkNYMHZnx0Hn6kl0/erj74INTy1f1Nj55/3333efGBqAl+BEqaWQCGit6dT0aae3GSompDXZtKsFGSheIUFQQOCURoUyr0BbS3EZD+2pTchsKMyVJDbc0L05iV8kj+U6nhf2jWvepwQoUyBW0Ctsd5JRya+WcGdW1g35StYmuDclTGnVct98f+tDHeknCIXulsWP10n7v7pXAwAGY/KA6ssyvWD+5YTCsJheNVQN0AVAR1SkkIAeSOaPaSAcAQKdbSmNj3H7eHJIoo+hNj72taPO1QoQkgGBO3u2FQgEGZWECKorCOWdTATLGoCIKeluLe8wq0wuupCgkZlWNMZpqc35hUFslCDe1YLNWh4x5gDrG9ia20QAR66puj4RQno274CFlPThwpqGClCUBGrUQRw6Aga024sbXWRfgBhacN5qv2EShwXi3+HBREQRP1Opg4wKZCABgzURzbkzPtIFlWG2BiKRQOGcWjUIaa1HQ8anOt751y733POKLOqX62h/eePKmkwdzo69c+fUHH7l9vFOmiiQMSy2tTv7IhY+duWz2D39wxt5hB0CJkCiYEROQzxuYQKRkrAjIBlDWGbT8nfnyVIC0QUG3SrqqKkIuFEU3DPtapQE2Bs8p1aPhCGDUcZMuTMeKvXfOF+K5OjL42fXXHXfCzksvuJxcZzQYvHTw+i/y335p4h3jqXpo72Lyrih1EEdUJueUGSITAzuM3mFk5ohLl2/sjNLOXft+8fNbnnzOU5KrSCSJlr1uhIhKbeIgndc5ISJBJOeUIIGiIiHGmKSZcmXCUkvLJswbOs6A/KYgSzFGZbaNhqqGTmk1mV2WJAyqrdxCb3wipQTMhL1R1Z+cGn/b2991+x0/nZnd2fMrRoPRw/ffLgLL1yzvre3o47p5w6b1f7zpkbvueOnL/nTR1LRXqEHGorgjM3Mq3heMMDYzPMzJlWXH3m4Ioa7rUBQrV6+894H7f/ij7517/nkv+qOX79zed0X5rne+8Ulnbn7hS172+J5jnbILBKXrsCR0COhBRZt7qwBtl9OEWESPpJgq0TpGtSkZEGX3HwO8q6oZms5HCrUfdyKJiNA5D82Cyla8C9CeLszD2WtNGDy1DVaWFyQh4/7Pe06UZdn2WJbGmFlUSNoUhYSKAFKzegjBEZFHBFFyJCI2kyQkIVu1gTXp1Jj6EaILWXKrxelBbmQz60NBUuT23Dj0gCoqCIDk2m2W/ayqFp1utoVgdkUJQ2wlf9vQlie6RKR5P2TanqCa4V3kvY3QqxEh9MbK7Q/vetWrX7F+w6YP/u1bfuvZv7ft0QOLl0/292/dMjGc6hYeR4cHoJ1xkHoS6h5VsQjlga1XffnkJYtHD99zz2f/63OnnnL+nt3ivCNyPpRcR+HoPPVCj0EhKSeTtBWTurQrX9e15ICRP4LBWc1vccGYNFdm1PA62gOmmUroAOwoNRIWFqtAAJWZY4yeSCiPn8UhMSCAt2G/XSXbTzfpX7OmYSNG1ihOtEWnA6ySeOVjh/vMpRRVjGPDel853JGmRp39PVRUiGO1OzbsP2nLeardqckBgBcSAnLAqCFpTMjeewEG22DZ5EbFk0uppqanyQGEWRbspBnEEHnYtJuASA6hVUYkQEHXVmAhd37z7TURIibbc6hyzEQaZ/AC51Dm6cJ21QGAa0ZvtaiZOiJ6B4oe1abArWkgABJR4bwx8fIIV1Qxu58Zj0CYY0pRhLwjJVBlFUSnxlFq0qFyyiwUVSJvwmaC4J23RzJ7SipYC2WHzdxcstqaQ2zq5vmHBUBVa072cKlZQLaWEqq+CLY6swTcbnzquvbek1mYN0GJEH0RhoPh9OJFWx858t3vXNft+UMH965ateZd73njpo0n3nnXfQ9v3V6UGhzEREDjiSsR+dOTH3/ZiY+/7ecn3X5ksSKnlICEiFiFAJ1DNe1M55zzImxh06B24jCLUxAJsJgYSxOdWdQ5hwAI6JDUgaAQuhRVmJwLjlxdV6PBHJDts1yf61CpR4lyTGix1Dg5PnXo2PYdP9177plnqSBRbxrc5pvOue+VP3WfXB4PjjgWIkheQbt1H3ulFzdyDp0rYl079Kra7/cXL1v5wH33//cXv3Lu0546MxrWdUXoNAm5JpuGIDExsw5HtqY1tKbpFqM3DBkgPGEetnBFhaLgcsGaDzwoetd1rq5rKkIoisFg0ApYhk6JiJ6C/aIYGUCIqK6T8xAoWHCpY3zSmae+7GVv+Ng//SVOJOp0+/XwoW333Xrz7ad0TgaGWA9P3HTSBz7wodPPPnM4HHrVMSRwLmpSX4hKOeKjwU27UFtzJqpJ2BdBHFYpnnnak9e+70NKuG/vQRHokX/pS15x4kkbZ471U3TOKRIDeOd94prAG8LSxh8AIKqgapVLdgpqkhwiGRtdEqfI5JzJa6CCqEJD8LermVQdOMSsz2coFGxpiw3fXFUUKIdPVU5JUMkRGWqRxXlHiKBaS6b8+0bmwmBvJiTimlWBDSVQlAElMWCj+9oI1lvnRJqxECklFXFEFSlpBkQREYqyiHOkzXbKqMbzFbpavmdEdJ6QEQAkJgHJUsSIzjnfJpLmZ62rMHZHWZZIZDIFhultFdfyykqy20G+MyIOHSCKsigTQdnVXs9NjvnLX/gSgMmJqQ3PfeYrB31Zt2Hj3GBfVyGl2ix4x6cWP7Ln2FgBk2NQBMKERShqmZkYW/76N/3hc37nwt3bR0VPHZdJNEISryjqAZGlQ77GdhJAYILMwqpaFoWIpBZhK2AKRJxZpPOiSwv7eAP1QIPgIxPH0EZsQ4FsVqnMAEVRcB1NVYeoge8SqbBZyYI1zaKq6hSR0AXvpHFfloyLbqR0ne3ViMiHEGSELKNhLLrLoah4ptiybO7Jz37q5+hXdLiHiCKp8lDXo4s3nNcfyIplhUTyJWBC0hjIIXhRsYex7Qux+ZghBGE1GHD+7I7mtUFYrFbFFoRiWabRzc5qGxmKoGiaBo0eedsZpJTIuzzX0eySGW0IXwTEFoqRK2R7jkz5xLTYIqcYI5EHUjN4sPGSUX2yeKcoZ8UYRM0jaE+5MwOi4L0CCKESAks7IqKF9B4g69c1Z5s8gcotb4Pyc85ZchoMBk4yA5CIrAhglVjFtm3Kt7VRR7fugJDUdE4RUTS1zGZRIswZXcQ5l4QlahabU3CIZVmywMRkT1W//MXv79z5uAuj2ZnB29/2jtXLjt+6bfspZ5ywacuWrQ8dBMdUxFoYES9cfezD5z16xf3H/ffDKxAZCW2QZlwph1RVQ8v9AkrBY1JhwcajRE27Fz0haFO82vsHQgajGqkwI4BD7xwQ0ij1FaJolFSJxqIEERlWgxSH0p0KWPXceE1BiTvkZEDjU4sx1Nddc+35512+6eQ1N11/787/2Ae/1OHv9YvPTYFnwqQ1A2jougHXBRJXFYVCU4oanQ/DuUOLFo+vXHXc9df/7Bc/vfW8C86e67NzIdbJERC6Vuu+qY0UEQXUZ8iQknNICMnoXoLBG8JjwcADgvPMzCyuKBAzRJGCdzEvKEejkR3jFg9BRN4HACiKoqoqydz2hOw0AYZhURQpaR2qV77yjdf+8NoHH75pydTKWHfHis6W9Zs7HRKVmZmDe2YeWbdubWJNMRJoRRgRiFyRGARi6buglYgAizHbPDmOSVgLCsMYu2Pjve7YunXHdcdLKvHCS5++bOXGxIReVVmjQIxaM6lHSKSAopgydA7NvS34hKoILniHQRm996FTMnOKnFhYRERQFJOY/5cHCIgEqo3eGDiQvANaEHZFPFLHBSJC78RhdNLn0VBTDcIIhTjHCpFVlQkyt8+5oui0da5FIgZlwDzoAPRoe2PRpLbUx4KwDBE1dEoDZEEgu2iGhGKR5ofER3GSQU/zChsup8y8xGplJQCKEDqhKCggLDA2N6V4R7pAzzL3hZhTrEdKwjFGSFGVFUFBg/fEWveHWicb3CF0RQCQHdWoyYGrEmsIFUmt7AkDpgKr/bt3fO5Tn738smfce//uc84556yn8aoNUnaLOKq7YfERrd3UevVjLODqI6vG4opeIsIaOjHpY4dRh3PDQXrTm957tMLoSs8omkgF1bTBMQGwQgLN1wFJYjKGpaoCYR0rs4hul75FUYAjH5zVOpFFkZxzAagAdC6QwbbJGcjIqXKKCTWhKqErSvQhp20gR0byyfWTxBo4qbKJk0tDFKZmvM2QPf6a20EUfFEUQEa6BAYFzsrnVYq+pEG/vn1n3UXGwVw98HsG2x8rdwKA37tYVZic1INpv2HFklPQ7SsnOyx1CZ5jEvKVqyNI4YPRxI1GbyghRARFqdkBUvDtf5hZEnNMRk515Ann5UcSaiKICEkzgtc5V/hgmSaEoABq6mop2nzBgfPola3kc1h4KgN4Zx+fa2ZWADJsi8Rk6xGmzMU0KBQnTsKqDJHNTEZVR7G2tqPVBkFUkSSSPKFDCI5KHwCgFo6oGhwWHhWI1SlAYonJ0BWIaM+puY6SWpUh6IA8tg1QLjLM9QGhTrHolOSd4V1qTtbfmBiLnUNDw0pMXsBxrkiMd24VSbIqWwCdVyQqg3qqUjSiYKCydAgqATyqR0RGSaAppaKkH1xz3bU/+snEOAyPjVavWHvilie//S2vu+rKbxzbW+/deW+3LFknY4w+4fru8IpL7vvl3qkP37qRAEFyGaQsDgkVmJl8QOcFUBVHVR9j3U1SRCZWAPAC3QgksXAFJ1UU9BhRxVNyNVJyIFBHVYHCxQJ8p9CkENmDAPdjmmOp67quh1UBvtubnvShpPEKnSsmvRQpOvCYkp8qxu59+Pb/+p8vPPrwo5/93L/O3nWg/G4n/XnVKRFFFb2SA0WHgXxITFqgC77jJwShnw4ORwfi3GDtcauPzVU/ue5aH8Gp5zp23FgiMlyOxYFeb7zsdY2D7skllZRSUAyKACA+e6hrYlIonC+cN05pkhxwsPAjjtZlBSCqkhCGTmlVWkbtELoiWNBmjgAyGg1UGR2RDwU6VXRFAC1RCVWqOk2t6L7+LW/pdlZ7T1jQ+PKlf/CKF55x1rnOucFsFcpJVX7ggQdYxLe5vR1UWufRZgIRicKREwEC5XrQesEWioaIvU7XuoF2vmeh6jc0ehCVwCGiqe3kBoWMbidmBSUi9uJ5BB8CIjoiFrVhrPPBIOAiQg3wLz85ROZXk1BRIQAVmFvkCCyIkcQjYVJgLojADNu9M6v2djLZTCry/zToORqCRAXRIyqwCggRISApCBE5RwTGu7dE3q6I8pTDcHTkctfOT5DFQUS7dg4wNerNxl+kBmOpzRhWRBBdbGwtVNXWOO3IhUV4NIp1BIWYMoZeEIwcIjDrA8WoKiWLqlbdXlnHqOzGxzDFwTe/8Z0De4/88he/uu3WW4Zz/S0nb/G+GBvzp589/qKXr55eNPa+t1+1e3f3qkfDSzalA1W5yA8nSmTRGSmwhz+719PSs84/cfp1r3/lkrXTu3an0g8GI3TeJngIDfXTVJSBbKIAVpcIMxI650QBjGaQazeykh8cilH6yDlyMdbeoAKcCOdVnAxh54IXAEnMmsiERlyjOChGUYBEmlSEk3MOiTim9hGwgZUJCAlBW6Xldk9VVa2gtvuYQDWxB4+IQF4ib73nEZiUyOt603PlqttuHv7CzQY/mo0jVigPHpz5nc2/s7xeciTsdM7VMUpVNyUCenASUwu9xgxrsA4sL3oXYLCg3XW183lTCzdYk/fe4CTUGBtbQdYesMJGrJIndVZGigiQmtKjad34tsMjJ5JaA297nbK0hSVY59GeyRhj4Xx7E9sHRBO3aucLr22+/ka0Nc9gyI8VNWgjkQyaV4Io7BoAHWKGYuTtTFQiAgRSEARon1B4AurT2l8A8N6hZPYEQytUmt1TCMk1Si82XGFzZIO8xrF2mxBZUgL2rquqCpGwEBaBempq6sGHd3/2iq9V9SAUaTia3Xjq5iVLlrznPe85/qQt//2Vqw4fPbR00STXkcj3Anzhmff1k3v19ScOk6raJUXQBpFKqJnM3Fy0hEqUvCMFIm8eAgnBgx+OZovgBAOKK0khidMOoNQoYXx8rOjGfhVUii70qapdpXUlzEEdq9TK5fRYYg7gOEqUWHZDVQ0BqPQFx6RaJSwWjU38+oaf7Lz/7kceuX2yx/Dx3syPDvcvnfPfKwnUlyUIVVWFJEWgKmEVRwGVlVatfEqsqoPHDq/ZSGPjne9+71uvePkfLVu5EhlAxSG5AM1yBImUJbtVYgON1kb22WYf2Jzw+UkGQKorDMFuuvlRQmNj1TbKbbnWBnDJOuS6YDSixkG17JMPsMjMsWPP+73fvu/uX3/q3/5p1crFSyaX7tn1uC5h56jX6bhxvO6mG/7uwx95yQtf1RotgEOCRsPdHg9s1eDAYyKDM7b+YvaB26cFs95phvhnReh5goQ2y18UVVLwDeDFPpiBAuzqdIqe5Sf0jhAVW0mtzJ3XeXuDJyxp7EsQ1FoWVWodXRBJkTAL7oMnJRBESRxHVXAFdlymwzYn2D4O+qDKsHBrSKikJBkuCwAgoohSs3ghaeaoC7SvXSNV7yFrNuX3PO8XMC9ej5jlDHIWX7DmXBiYsNFBtSG2a9zftFnbOwUhDM54nuiyLbH5mwJgF0F90BSBbFEAgupWLiseffTu//vBj245/oR/++T/Oe3UM1esdM/93Uvvu/eB2286/MgD47NzBwVvfdbzl3zgny76hw9dfcUtxbnr163oP3jEucIhg8Ykxaru7nPWHb3yYOHrzSecsP+Qkh/6OKVdVmVsEB85ASjb1kARPLkFLjaaUlqIt7LnKjfKCOaj4JGURRMn28QkFpMRUQU0mB4qKgGSQXOBYoxJhZA8UquwGEJAo4SBArPX7HqZn8DmDcOC2Zdr9MjsRVoSiGSJAE7C472JPY/ec+TuL0Xf8Z2VFRyu7x7gb4PfMwaD7pQfX7t2w/f3Xn/xuc+Jc3HsBFLIBRk6JwIOBIk8heSEmYHztKPN/IiYVMy4wr6yclODe1dVo8gTUZZps+ZeFUwKUUETExEDWJ298DTaGfNCJhxrgQIhK8wQUSvlCE24AATT6zC8mCkFOu9sTCoiC5E+piuUGnqJ4HxxY1zbuilkSZsyw7KvqW0z15xQ0Nqg/HQYO9ECiyISmqo+5Gya76o0aL72vCEiq2hkcHm8RETkyFMQkZqZmb3Ov3lpgDkAEBrpj6ZSzx+EApbUVS4YBmXhODnn2fsiKn/jyquOHj2k6uf6yYfeo49su/+BHaecuPH711z7X1/83MTkOAMLYHD+X55254aJ4W9f/eSDAzL1TVU13rw2ijQLQjECgHeOHSYAZfHMzioFR8JVCA6AQINzBUvtnCOlsugkkiGPDuzYPRV6x61atffAzr1H9k33ep2yHJAfpREGQsU4qIIrakmFL13hItdAnghSimVRooKEsvAymjuya+exboGaaHSzo5/70RsH498PzOypI+iAVKUWdqHocRzMVHOLVp16+XNfWQ/6V37zk0cOH3jN/34FYDw6c2T5cWt7RTEcDBwQEagyAiFRVdf5AVTxjgwr2ZaSrCICRrqzprmuaxUJITBmQ1VNrMI2uEZENcWjHNSbur9RdLAz1l5qaXiwdtnLsqvKMQqhA4K5obz4pS+789abfvHznxw9NluNBgV0nfPLV62aO1pte2B3Gs5+4T8/4tu324T1nBe9z/AwZm6ETBERIydyuYBtf9ZKTCKyxRuDkohzzjtP86roYiIPoCCipl1gn23exoYQG2BbW+fa30VhZ1thNbWJHP6MhsQLcp79+4KcAETN1qeC4BUJMNZpFGsXvC8L43X47hgpRGhoJJhlFmC+Hp/fvbWtLTOTczleiJgtqyFm2wmza+yeUrJeLcvRtGXKPOx2gRJvfrCbbS7DPEKPGhBBjNEWuqHwiBCcl3peisFacafAmMMlAKAjh8TM3rxeJSkgKDtPiOSpO5zrj4+N3XvHzdf88Cc/uPrqa4vqla969ewxvfYHP73lpn1veOe5l11+6L1vu27ZihXeL7nqi9vuu7n44Mee/+8f//7v/OuBF527+lnHHV3Zq/pcXLe9+P73yv/z0d897cGrVk6ffPyJmx7d1e8VEyx1zAUOYKv/QGiDUG2QirYUtECfUoJWBD8XauiRgEAVyDtlQdKqGnnvBSAJl85Jk5kMUyMimkRDC3+1SlnUzOEdCQAuIDJ5JCDUOrWznFxNGrWfPDXcJxFTUmz4Y08E1gooMy8u08e/euXhujjnKSfdd/92F5I/vPjYoq3u52ODrx7ADemO2285//STDuzcp7j1uaetrpUNma+ckIhRRSFQs7FeqJ0OQM4pKKbfZBm0ySPT3uraZH3yk9XuWRRsq5NTqxF1BLBpc7XZAZtbkc4XJGgABWh0LexPNLFwgkZNmpwL5MqiyEWMqJJqYzKdh0MKiOidE0OutXCqlqBsJBBrUIyjyJJITEjHFWE+ItqHcuQw72JyuWwKJAYNY87+xnlMja2WdfuAswohNQJfjG7+8SQiyeYKkOl9je2bpPmRSWOdSQCYYtUpu3XksuuyqDrEbnfym9+46bof39jthaOHo0KsUn355ZccPbb/Vzfvf/ihRwEkBAfKoVO8+aSHXrDx4J/85NR7j4wLpFZn28K1CZzZXberZzVcrTUqAREFBODcAGU1oi4DuBJriehCp1PENNp9cAeJ27h+0x+96o8uvey800456aH7H7vi01+8+uqvjaiYGF80NjFWpQGAMoIkLYuxqqoKdI4CIiYB73wSRvFVVfmA1O1ERsJJwujibPlvxfBLg3R2LH/tR3UtkFTYY6HiY107p6HoLVmyfmrxqrAcVq89ZfvWm9evO+5Zlz9jVA9nZ/v1cG7R9EThwihVzsKzqDlKoaOCvNS1PTTOObXpTo78qo3VniiLCkDohCKm5L2nQCZcaJE2xtjr9Sz+eKQoiugU0HrodqQ0f6NFyKEtX+t6JDGFEMpQxFRjCSvXrPzXT1zxnW9/fdXKNaeedvo9e+8E0HKi3LzqpPe/55SnX3zZ+z/wFs+Nv0KTUJsg7gkQMedgMVylI2ff5ISan+T5x56IoMh/DWD4ykw0Mi0eJAJRROCY0LnW2LzJz0BEw2oUnDebARFpalsCsF2OM/8EuxzOhzZ0tsUsAJirBSIIKBIF50yAAoMHAGH2Mc+E0YfUeAi1LwXzb+w35Rra+tdoxCKC0oBOEdURLahDERFakciUgBBEXTNDZlCtE1He6baFMwDYUE5VUTR4LwgNxmQ+E1sCoMatmREAgZxDh8a2UYBmPIMO28bDyFGI4CoWJCVRjtWypV3C/s5te/bs2v6MZ5z37ve877vfu/7rX/n84sXT9937yKteeM+fvPH4r1337Pe+5Wd7HsNTTjv92OGZt73y+r/71KWPb/vxV2+d+e7DONZbPxqNxsfHy870X7/lm/t23XbN9f94+AgE8Bx9DQJQK3rKRlbYFhyWL0kVUW1zhoiBHIb5G2HWMc1ZTZyrxbbgcBYOa8wqgACAmnd46Jz1S0lFJDnn7A4jYsZqmbgE5+8dUO0Isl+bInMemFPunNpf2hZ8iGirh7bXBACjD1x3403LFi96/rMve+yR/45Qaifqlmrsh6vKRYux7493a55x3DM/85F/L8pxry993u/9weHBjDPuECKSisgwsVe0hhVFK83UIMpP04IBdFO5tyfQjkdbsCOiI6pTtFZi4Q8SUXCEJhkn8zbD9gEZxTmXufJE3vvEGmN0PhgIqHA+am0e20RIgM47apymzU5QGopBe91U8xYKoN372C+F3EP7wiqG9u9UFQCT1daCC5+aXAeQEmRXIvtrMRdui8stT8kmTws0goxt7xjQiuD867jt2YPzqQE0ZXhpyya3E9ZcUUQEUkTnvK+qWJRFSomTdy6NT3S3bzv8qU/+57GZI34AmroVj7Zs2fKud71z2Ie5Qb3x+ONv+uX1Bw4eGx/vXbpk5zvPfPTv79j4g50rECOiM0wqIoqAGSoDzPcMAGCyQ0Lo7M8JgYhVgdUJgC8FUEEItFvgaDjYs2v32FjnWU9/1kte9PwLn3bm+Pj4IGp/EM8594zzzzvjBz/67Q+878NbH9y2du3auq5ZkyIqgST1vjAQLSL5bCcv2uFxcVVNozSqq5mx8e6KVcfv33mvfh/xEareMEh/3AUsnWcEQeisWX/iwWP752Z2cwIXOkmqid7U+g0nPfTr6398zQ83Hb9x6coVae4oAh881J+cWLZ46dTYGMzOQooyrCvjpA2HQ5eVd1FVIbEgGM8IkVS55mS6GSICqETOBFsQkVt8AKiIDIdDizZmWICYV8vaoL3mQ3SuYmlUjUIIRVGI9yha17WqpqFITItWLvvzd7yZCA4eGBIFRFIXqJwoe/qcP/ytdcf/jzcJOvOwUlVLnogoolZKOecos+9RBAofRAQQwdPCp1oRQbhti6HpGObnQnbm8141pxBjGVoFTQqKgAq0QKYKcjlv5qyAqICKeQKp1gvalrQd9tpLRQcOEFkcK6oSYWYjCHTKcjAcWjMhKiiJfABhanVxm99r+d4UDBwgIWmzS/DOm4OmNEazudwWIe9KzEQgZgbK4w4L99h411h2b/foVpcAZP2d6FQQOKaFKb+99/aCttgD1VGsOqGw1iajzUWMkNqI/TbHpelCvC+rKha+QNS6Gi1fNv7ow49+9Stf3P7IgeUrF7/+9X/0uc9+7T//67OXXnaZMK9aOX3PPXf++98/sHtH958+ffFfvvaWPdvmFi2Ghx86+I0v7Hn127Z85C8PTi+NB/YfWTy9qtvtDUeHd+x88APvft/ZT7lk96GZTujGVLluhDqQNf2iNodvz4kDTDBv15On9/PNBJgYi8uOsIiG2EQE5hCCEnr0phGRhJWThSRqzrDkZo44s2nyCqNW9kiA6IAQs7+sCUFjO8hSAc6nlFsSsPftSApaVqhBDu0+KghLd3xi2dT4PXf97G8+tGPpspX17IysUOgK3TngQ3urLv9638P9K/ectmXdjoMHHnhg+wt7cOhQohAAIUkkIO8KVQZR16jH2FBEQJkTyHy11+bLdlIioNScFm3LYiKHREiCwqAO0WY5C/NHzu4LXtM5h0CIklGFmtBhCCEZHAmRyBE68t4WrCICJhyWe8Q8ol9oByQiQJm7avVhO+5rWAya+bstAMJK4Qbq3xZD802qIoiySrLA2gRNQXAL/LABIFs1mEa0dRqSZ3H25LZtOioIs6iCc+jzISFA1ywdVdUFDwDa6HUIKDVbI++LmEYA4F2Bro41fepTn9+z54Hp6cWd0KmTzh3Z3+/3P/yhfz7tpNPPv+hp3/7Odx/fs2t6emJdsf//XXT/d7ev+Ohda5veY4Hep9hQXu3/HKIsgIk4V5ACCLKCekJEQgikFTBh6vouV7p/1/7lS7uvefnvvfylf3zS6ZuHc8oMBw8OgYA1HTo6Klxx8bOe/pVTnvSv//SxL//3l6YXL1L1FvICOF8E0Uwkc45mZma6Y+P9mWMR/DCGM8/atEQP1zP940467Sdzxw5sfbz7773hP8z1Tl25Vk7Z9dg9kUe+6J529tPuve/OmSN7ywJ7nQIJRNKqVWsmJ5fdftvND9z/9Cd1O1W/v3jx9NxgeGj/1j17wpe//OUNGza9+CV/FMgP6ypJpuc5csB562cuZ8oCDtDl/WkRgjKbEqCdhJgtXTIDzcaKqkoK1v461+zvQNrnfeHBg0b5dTQaAUBZlhbRSAeuKGdmB4PaIaIDX5YFgDpxgnJ0hntl/5RTN/qFCdIjoULSfEc1S08Jemf0jDZiYkN7R8TsskCoOUlo+85IQdGcZ+dL8tbBGxyZVlMziGZs4F0GVXPOIRoHlxFaMTob4wCi+U5Dm+9txeUAWZWtY2bRxFam2sOGAoBIZWAjZCgiq2O2ulEaJFr7VKvJWyROgN57YFFHqsggSQWzZp4FuJw7VTNiy0K2UTYzAUkBGuWEZJ5hC57hNsvaz7ZrNrvOwXt0zkJDzk8tHVMhxijW+CqIIoiCggBWKYpKvg7NhULEmmvfEa5rYVy+YvxnN/34r/7iPePlmmc/76Tfee4L3/++jzz04LaTTz772OwoVnNLFy+77OnPcyFddeVNpQ/v/MA5b3/lDWXYvPl4ufrr91322xec9dT9t/+8NzneY5Y1q5b++Cc3//nr/+Jt733Xrr1z6MsowXUBUvDkktRop6thpjmTjUqsDceDghcF5jzTc85lq5yUrMoBR55IQAAgCRvlw85GGYqUkvVhzjmxHleEzSVPRCRb0tpdKGw8xTleIyGYiGI7lM4nGpRFGxVGjw4RW49Iu1nee2tYRexWQErsAabGJsbHx5cuWco8dDiTTh0AAD0oI1dTNVLmAwf3TI6N3/mLH7zrXW8fVuCL0oQEUcm0Lq2btKOJ3jUqfAAKor/ZAbcVsEEaG/ZBruHa3Yc0S2Jp5jTtXwGAQ2czCma2ghgdoYH/vWPmGGun1Ol06lxnsi2SnfOGrYQFMrGWLA3eIo0jePuWUvaumZ9vQ44XQIAeUNSufK4QRMQnMI4iZII9SKbeZeHJFoWnDQgLm/GVa3T8rVYz0IZiWyi4LIgdMuQNWvFSBXIYjYWhoCoGIERAYUHzB2zvhSqICkhKEUSd54CdKs5NdMe/fdVPv/Odq8c7YzKimisBneiN79y17Y5bfnbxJc89/5ILzLRt0o/+++n37eh333DDidLOkCEnWYAMS8AmYlg3pg0VO08eEL2NDxUUmRF73aIeDQ7u3bVk0bLXveZP//erXnzSycsPH6kO7DuGVLBS8B1UQUUgnB32Dw/nxnqdv/+7D510wqb3ve/93d54UXjQFOvRbJ9D2UEIqKgInfGxienx9WvXlT0XetN/+PwL5+6/6e4bvr9hwp173oWHjx7S/zoM755zb4XTfnzZ3p3bR/GAjuHcUBITgpTB13UV6ySA04uWTC2aPnRk25GjB0ej0ZEDu6cme4P+6AtXfP5pl56/atWqD3/4gyeeeOJFl1yYVFyD/BcRjpGZM1fbdrSYQzRLas6UgeXsaUGTibczTAqdTk9VLZFnUKyjoiiYo6kFtPEZ8/q1eS69BwBrf9GRpwAK3bLDMvLeQ+LRsFLA0jtPg05nSqqOQPJt6spFlUjiRESmJDWPu5y3CmjwuvM4FJ9SsoYSEQHEqnJqlQXbkWyeygIqMYnL5rjzECoLtVxHdFlaHaAVIzQysECTeICspW5EDwxNxmL7YKoZDdodnO2QkNUJDBwqx9IHVOWYHBGWJACORQFaSduc2zw18gPzmg8ApCoG8AHvDADl0LUdRvvk2xcRoSOIrO1z0nRLtibE+Y1O09eLmJJRIOcWig42cruSRfnFsGw21iNymQfX8PyieVkDtgFPmz23IlVxBOomx3u33P7T//76h97zwRfedP3Wtct/6/4HHr7/obvOOvOSio+yjh7fMXvc2tWzM4PrfnLt1BL8wbce2njCGb//ipVf+uSOdcdPJ+3/6sY9lzxn6sff25Gk89zfvvSGG3/83ne/7/3v/z9bDwypyzxwWlR1FZ2t3GR+2N6WU2CIRhFmrjmVhBlgoqrKXuZhEWLK1QvuODV0rDwmivPyEaZ+oKrism4aETUEsZzduY7OOYcoBn81jqnDQhZgIF3e0TCzSawkY0Z5bynKDF+tP8OmCyGiEMKBg4cf2PbwTM0zW7c6qcqpKd0EMETe672SE1d0OhDhp7+67Q9f8ke/d/kzHj0wCEWhigoafAEAXLOqRq8Lk73E7H49UsEm1bVfvjEjcs7FVGPjdEQK3IydSAG8k7xmRTuTHskoGfMRqgWOSrKJLUKj8STmbusAwNKeHd0WhWTAZskwiZzzQoM+Je/MEtykMOwfsDZcPAUASKokyvbkZaV1q5GhtcTOW2REDQ4ANCYAMHK23YU8uzLstwJ4T2roPBXmjPJDBAIRMdGQpFqQU9WkDADeeYLc+KKo+QvHGIU5b3YU2sUhNQonRmDzZalCLIroyi48/vjjd9y2lYKr46j0VNVHAcb6A12yYvniJRM7d+y75ppr7r333tljR776jEcnQvrDH58xYO9DApEc7khhfh7fjMEVEA1Gmg+tB0kAbHZBQojoAoGnvTsOdQr3ipe/+FWvffFJJx2/9+DM3Y8e6o2NOewgKEutXFv7wFz3QqeToD8cHIzD17z1T1duWPuet/+VzsyVoBPr12zYdDxSGI3S1OSiTq97waUXrzxu1SPb9nCa2/Xo46l2c1IO0/DQrrtOPO2S3adfeOtPrvKfdkffsvvoTyrRkoiGdZ+wTCnWsV9BWY8SW2B1xeSi6Z07Dj3wwH3rN2/uBfVIO3fsWbFi1W89+/Ki6Hz36qvrujZ6d6oj+QyMQO86IVgja0CZrOSLoIkAwCZbzEyNXJ2d9hZ20G76mkiclLNygyOipl9qcwEAeW89kjWMeboDwKO5UafTcepcQhbEgAAqCo4nk5+DsTA7cllAxEBi1sYRuirFXkIiSmoHkkDyGixPlbOwKqqYbTo6F1SVRQSFnM3iwBFFRwxq+k3Y4PU9qVMzlUN0baRzqsDIVDgVYBVfBAJURVJgZJX5Wg9s0ePIOAOI6LxThmQrbRMudECmMOeIQrAGq3SoFFCB0PsyAAjmDjHL93vXRFURSKCJ569PlqJNgCACSqgxtahpRTBvwVYxGJqGWFgY0aMzDQ3bhZeQGeXmn2NKD46AyIECoJJ3SZWVwWSfY/Tqg/fGVKnrutvt2uQQDQUbGUCtfs9HJCYeJURg5uFolDVGiLwgi6jDUIbBzMGdj31r47ruFZ/48uvfds7nPvu3L/5f7//oJz75mf+44uzTn3bs6OH77/jG1PTiq7/17VNOe/K+A1v37Nr9tS/c/Z5/OPVrX7x/x87hyiWb7rzl0DOedxbCA+96x1/s2r31z9/wZ3/xzr9+YOdMt+wQd8UnhxB8xyT7yedri+gs0GYbmSpmbI5oHFXoXQgBAZVcQnXOOXCld+aybu7cNu0wQhEiJtu8IqJoxwVENN1NU/mHZukbgpN5iWkQT1EFBYBQrepSQAWTQGFCBkFVj3mCKiAg6J0DgDiqrF/Hwkkq63So43tJvC80Rjfk4cTE5MF9+865rPO6d53/wN3Hbv7p47+84UFYQ+5RX0hHsRIKPOz7JUs7ROvWH4cFxxg7LqBJiSAJgvdZCsMHbylKQJlUgAmdrYQWJmBtaBiOSBKbKH/eDXnnBTWxJubgsEFfeXNAMWkYZ0BlIHQi4pDynlUAQFnEHlhfFihKGJIkUqC8GmBTVSPWyBEICZAMR60YFFOKGYQsSoClc5XM16CQ5w2qpmOJiIhCKlFQtDTYRBMfraSwcVpSUVEUREfgyVjaJGCgR0urNidXI0ALU1QiCs5LUy6AAgEiKyKU5G1+EDxlTw7RyEIKzrvcWbqyqipy6J1HhyZowwRVqkGl48vsQCU68iNKRS9JKPxHv3HznmNTp538tLtvvRYnRojl6Jg+5eyz3/SON6XUPXRwz9hUOT3ReevGHz1t6tAf/ejsx+d6CBVIKQQeVCSSogCqZo/KKBIEADEBOxTT3HTok2AqsZdcBFAfxtEdmD0Y52Z/63kX/cUb33bGeaccOxgf3b2/SMViklHVZ1eCOsRSPXlgjbEsXK16BEejWBc1bd9+8KxNm/7mec/DHY9MDPvTf/Jif/qpDzx24LH7d3kKw2pw232/5l/dMDMb6+qY98Vl5z+p2D8xWDo9UR5z++980vr19yxefOzjc/C2tP2S68Z+3OkfkV631+2IIHiYZOQqHYO5w37JFKGKnww+BKwP7ty7bsNSV3YG/b4Evuqb37/nnrve9Ja3X3DpxTODikWKEKRxqTG5GFENITiiGKMkVWbnnEqmmavpurCYEAUiSmIH6IpCVY0wkxSc8yJSsyBASuILF0XM+zrGqAJN22OcBQKVGJuFCACA64w5REwJbI2lwghYS2SsuEaoUxnQtwCNdqjtyBWEnIx2N79tBta29wVpWIkGilFVW6uYaUy2DsvZElVV2DKSAyTDBTTdsGu4xSAq5rEKBKj251l8R5CA0DdzrXbnGpNpwaioKZ5jQ45y6BfqkLXpEBpGU9N7KZud3HyDngdOInls23a0GV5rIuaZI6SqCpSfbSTkxARoTGFo2s18V5oFeH5LLRRLxAw7FyDcVdV28OaAS74p26NKYpVmYuGNhcjKoL4Bo0p+QQRCdFb0CAbKFGwkUcWSuA6Lu8WPr//JwYP3Pf8FZ//6V9++5tsP/8ErBg/d+y9/et6XX/eqiTe86RWbNm65/DnP2XD8cX/1ng+fcMIJ3/vetyenrrnvzl27Hi0vftbqa7/Z6U55DDqs3JYTNx8+NLtixYp3/tV7tz7G3V5XWYhc15Xmbt+sSxd2wNqMLyVvu32DlGEGytYlYBMBIiCAzPPBAMjMSdU3miQGevQCQMQIYufJIF3JzAnmx/uwAKzkGvFIZhFVRHJI6Bw3ukUWxLP6qTU8hK6h66SURDkQ94rJalQjMsfC+8prx9HcfY99Kfh4y8/3Pu2S9Rc/c+XenWe859Tv1o+pKieuy6LATnn06BHVtGTxquHQO+eGdRUQiZwIU/Ah+JSSK0I+sbbBQacgzOyb+gOe+KXNWIscGjKl3Vlg8MaFdSH790XOAnCi7bOxgE6DSDDvPcUpgaEOKSeYpAosKBn/n0elSaLUzjkrYW3p4EKIKgbFR3RAWjjP7jfNrBaGHUN9orNGICsHMOfVHZjXEjVcjMQ2QybNphFWNjnE1FTqC3+RnT0bjTgkc73I+3LM2kFi3bgjBw5xvlmHxn0IFFNiEfaFU0UQJW2MwB2h4LiEuYqLFeUttz76vWvvm1i24aRNp4b7flnFY4UPiu7y5z5/5arj9u0dbFh34mw18/trbzrh0C/e/atTbzowicQu+BTRQXIEDklQmTmhIPkksQCSAiTVBQCgCxqcCyNJhaoqcomFuhp42/7tT9m86S/e9TcveMHlw/5o3/46SSyKxX7Mj2oJBUpCSSPnZDQ8dmjf4fEwIeXYoCgAxkB6M6NBf/bA4EffX3zbzSXFHWNp/OEDBwb3Pbj38QN7D0yPd5SwRx2ZXMFuxEe5P5irAQZQHpWJY0f06L4Da867cO36k2Zu3eG/Umx93s0r/uYMEeiWPnSmKmZ1yk5nB/3ZYb3KdagUSskhKZVbd+245oYfPv1Zz7zgnAtf8Pzn+tCpqt/tjY0llpS4KAphYWZfeGZRFRC1hYgabB5EFTj7JOXdok1Sk4pANk23rZ6qMttKNNMNHLj5Y8mSNJqKnCckQmm0DRExF5ZP5MRak6CqYC8CSs6hI+GkqphSdiC305zbNTWu0Py8tMlVoKqski3KWbR5rnL6UTMEABBVBLaUKop5ZWKI1ZyB8rQnS8Nbz6GIAIomhGUpJCsQgaaqNpsEyA+DpXW2zZw0S7v2YuGCYW8TUgABs4bRgi/D5hCCyRq0N8kBgoMozZBKtdHxVxFxrOScLuB9oiNEMt+M9ldkDBFhyx63yp2ZBRvFksSISB4NGYQNlbBZQudbgwYu4wjNIjml5BrcmUorvgdktsqEPgQqrGAHH0IuoJzTxCokOoOlv+ee7X4MDs/e/5LXjg+PVAd3zCxb/dA3r37vZRe/4T3vfv83vnnVxs1POnxwsP/Atsd2P/rbz/vdLVtOetvPX757a7lp02LvZycWrTz3/BPSSOYGw2t/cvV11//k4a0jLdOYm6hSZfsYG0WSgqK2pnVtKFQriWwV3AxwUowSIxF5tnDMSASZzUymle8aPJeKAVpBVWtgT54akBeDCkBkKRq0fIsQxmbRbrApQsTGXUdEkJxI3sE3SBcAQufIcA62ioacsVClTlVwrsSQUmSO1eTk5KNb7/qXj3zx17+Yc6781lceXbWmeO3rXupO1elf06Gj/aUrFs3O9CfGO4sXr7jvvoc2bzq+jiMRKUPhKUufWkojzV4FmdvGrAigJKzQkGQWPvNP+L6ZJms2gUZEZABODZIA5g0qCnKp2Qq1m1oATQscLECV8kI6i2loNswAQkBHdjPGu70GxpEDSEoJvfPO2+7cftB7752LzV7zNxIwAGTBEJZo5TuRIIjk4jpvd59IAPVI2Hh6ShNYW6Hp9smihq6R35vOn0nnnNmZ4bzHAzQVJLTnpyiKBizGhMQx+SKUZWk1ByKO6tqJ96xTwR87OvzsF36R4tjhvTOzyzZuevLFt/3yqu7kGJXguuHKq7595de+/qxnXP6CM6Y2PvSaHx4754oHpxxFYVWxaJRAYWJqotPpHJk5NtufI4cM4BOxQkRM1CEmVRlWcxM9HIUx3+cxDQdnD4Y0fN9bX/9nb35dMV3u2lvXRQFu2EWqBoM0eyhOr4j3b68f2wVYVY/v3nPvw+XmjUefds7WQT3ae2zPod37js3NHZp58trlqyUePnXj2o2bppTuvfFHvGHD9Ibjj1LvwYf39/v90aEjOw/vrRJXc3MJ9ZY77ovDfsFSJ+zX6Xc3zS1bszHcGdy/1MM/qeAPh/IhSjyQuiKtAUYOtHTIaRRjleIg1n0iuu3Wu6aXrxz1577yla+tXrrupFO2zI1GQnhsbtYSZKxqu1+pToiIhEpA6qFoVvgNpduefY+EoMJcliUKN65fKlaxI6B3igY4EGgsH6xsRUQDJ7WHxw6s7bMWHq35mphFQJg5Iw80n+92heybFJj/VBoyGbUIwAUtoH3rkBwgZCV6hWyn04BWRIkQTBoGsRVA5izTAvY+pFHSsH7aPoxHYpWFPZzZY9uaB0XBoYCiApupsOUizqxZbZR92oekfZ6tlAaAAAS2BM0VcX6ioki75slX3HvnHML8pAtaChaCcySqzI0QvxXOSV0bblpaBeVf0qbSdm3ZZhFEtIQxH0lZjJvBreM3YrZVFoXm0qlmaYj5zOGdATIFgJxzAzOcQVUzGwMlRUSO0imWxFp/53d/6+V/cP09t8cTzqiXL59ZPL3xW18/dNWV//wnr9bnPPe33vLmD3z/mm+vWLn06CP7tm579MTNZy5btsTR1M5dW8/ePDk+GTu9ZavW0cx+2rV957e+cxO7RepH4GAwGJBCxRxjNGk344YiASrpwpoMwGTEVFUS2zonhGBNpzMtVoQkIsygTGITCM3kK2YWaflzWHgiB5G9c7YbZ4KkkhdCRO2TM18Oq5K2MDlCURSNDcDYHNozDQnR8L2NFwg2/41SaeQEXhxIp4P9Yzg5Sddf+8vbbzr2xrf+0aH99d69e2+44Yb3/u1nZ145e/7onNH47v7gMKBz1D1y5Njq46b++gPvePLpV/vOKgAQJERAj2rjehM6bfgCbYoy2U6e98j9zS/NaKT5GhqaDZY2k+r2mtjuxkFD6m1+C0CGVTQnE6gd4AtITO11aOtU2+a05Xv7e5GlYX08ATgJqkBPmFdJA4kyFxq7/jXP48+5kTfSBV8ZDUDWr5roWc7BIeRm4zeWfMZWsbjEC8S5HBijCQ2y11Y5bUi07bW2nk5Ew1pSHV2ZJ1lWegq54Wi0aqr8n6/cdvNdRwpf8tzMtp0z52w5Y+f9v6pnDhVF+S//8JHRoNq3Z9umXnVe90e/erz7kh9A6Naa0PtulKgyFO8RdWrR4kVTk6oqkQlQwFVBu4xjrlNxQkJmhd70fokynBsbwv5Dey4+/4y/++cPnHXqaQ8dOjrz092TMjy0Y6+kYXfdiQe/9z2YCCOhx3703QNzh+b6xw4c2j/wJa/e0L/huqXrNqxYsmLJqqnzT928ZvnKNStXjnVLRCynJ4re2IcPyhWf+eTYeKeeHaCjxDoWujjecaDj3aIsw8zMgU7okECnKLoBHt+7fdFUr+iNyyMzYz+dOvTybeEfxwUgxn4A6JbTFLQ/2x/MznW65f4Dj+8/vKc71uvPxf5gx+oV6wZy7AfX/uSiyy8BglCGoD5FNoU47/38+VQQFkUKrsCM+Js/fiklIAVUBalStFuPiI0AH6Aq+IAGeTIk//y6d34B2pRuSkTACUQy36RpvRCRTbVUEdGZ9oAPBSJK4npUUcMj9TZ7EVzgqApZU6nN5/ZXucA0GJmpwiESorQYEJ23NrM3IqDtqNk2uAJqvPi2XpjPTApK2krNZd9vyA+qPWxmlAS5es7kh5xxFwAvDUvSRgR780bMb6h7LVzxCY+9PXjGxsjJOHhVNTbzwnIEWSgPyBVFBRSzYvBvRsA8XYD5iGMv0mbQ9nmWxOhAiVjFwYKiZB73iCW5JAkR1aOxRZNKXdcBCYkEAZhbp0818wBAUFQGjw4BJQoiUgCk/uBIZ/OmtWc81V39nTu4fvHkxXTDD6575MHJJavXbt/98Gz/wu07f7Fn77bppWPPe+7/2rVrBznZvv3BSy59DnXvHtZrlq/csvnUyW7Z++j//ddPfOLjm48/+/FDNXmlWDBwCMECZQ70JrEidvFRSR00wHaGovCx0UDN6PGUjEtgWwoiyiholpTYXlla3dMGwVsIKmjCptoDIMAu+gQJWIQl29w0NRM6MnFHVjEgLhGRd5CkfaRVFQUEwUxhc9e4cDikWpRdQWBNKens3GhqcvzhBx++4pOfP/OczYlnv/ilL6xYsWJqemKweQgAj313ZvPmE1B7vpRf/OKak7c8+ejh8MDdO3bve/SUJx9/+PBMjOxNH5zAYV5aq0BsPPuccw4wmdMQPPHMLZhXIUCjHzUvjGX/ph2l1nVtVaCxls2FsH1w8uclq/TylwlaCaiIzm/Tzb8vu2BArawE3kBtzbTWBoLY0K8bUhkb2wPmq/x5pS2rce3w203XxhKufYc5FJiVFy6ApBECIKGnlpexYFRgX7Gq28+7sI2WxMyMgibXCwsIcu3v5cbMUUXqGMsQhnVVVVUIgeskIr4sRqmaXDJx92N7PvW1W8vjVvUEcNbvP3Jw9yyec9lzvvWl/zjv9NPf/Na/OnTgyJF9j/zp6H1Oyk9XL1+y5MFjx46UZa8ajkRqH5CcA5bB3FysqsFgiIh1VaeUDqYRVCOoBuDCWG9qstfrzh44a3J6xamnLB+bPn7LSec9+2K8/9Btt3z34P1bRysn7p3o7vzUJ8tzz3/wR1dX3//O0bVbasDFvTDeWTK15aTzTli/6bhNk0tWLT5h45J1K8d6ZQf8nLIQQgUQqVJNWnM1eOc7Xnf/A/f88tqfr9i0qU8VxgQVu4QsVPiglXT8RBRR0k4JNc9tf+CuPd0x31vq3BR/go5+5cHp39msN3Zuu/OO2X4qxtdRoGElc6OooTw606/ruQlfqFCSuHvPfvbDa3/045c9+NIzn3TKwYOHumU3hEA+iEgUHo0Gpn5qh8TM40HV6qr2UM3nMsA6Ru89W0HWbFgE8i7VIYJDb+eeRVXrOnlPCwtWiz+uCQUW09s/t/YHnygPBQCenAlTp5RAwStLG9/nD27zvTyRhGrtV97x2jFtVr0A4IiU1NQSsp5UE78EcgPqmmepzaxtNjId6daRUrLS23wFoGoWo0ZHVCVz0muUsygzHKzZX3jRn5DpmxF0+98oKioYfOtqHnB+G1vXdX4/CzoPRHSI3jlqbnAwg0BqO+pmyLmgBf+N9mXhqwHkBD8/xzDvFPsecstitm7eOWguvooKZFG6/FKEIMpGM3fEzcqwxZrW1RAAoCcw4iXF2HXXfmJs6c//7h/+8cLLnvnD79+wYqlcs/OzTzr9zI997F+/+Llv3HPPPaMR7pnae+ap592855bd+uhUZ+XiqanJ1R0na088edUfvPj0rffu++u//sf//eo/23OgwiI66XmMjgoWcYjOuVGsAcCbslWw6sAW4/k0O+c8Ekk2W9VGehAAvG1QFAgphHn6kDyxYaKG9lZLAp6XLAVVVqEQDHzLtrMQZZejLSAKKmQLaszab5LmnVEX2OVqFqLKewUABMhFQ4SIQM45FZeqNLXI/e2HPrdz17bTTrlkurcBoVMNKfLM2FmdPsChW3aXneJpF59YluWJm886/Umnbt91x09/eU1McyDJOQR1KSVgIIeKxGo2i2rhAABAIRFm6PX/bwG88IQDoEH/5k8dArp5OUl7lNrRkdnntdGqPaIZMLiQCmHoLZ2ntznn7CQiYuiUuEAkBBsktiOEZhEAjhQUWE14auE/bn8LATpy7ZKYmr37/NipVVx36BQMcpgXA7nPBgK0Th0he4djUwG7TkfbRnzBV8sPpIx+sTwPsAAKSkSIWTBEQMBRKIsG7+ZjjFVVlYAu1ld8/paD4JZPdmRu1I/QocG2rYfPfdK6J51x6eTExNpVa1cuXr1l+HdL+1tvPPWql1xywaLvfufLX/kCEXkP5MpU1Wk0ZObds7PDasSqVAbv/eTk5NOm109tWLP5uHWnnnzq0o1rVqQh3vjTif179h067Ddv3v3UJ//n3/z7aPvDh6brmW37p04+aXjkYNnRpY/u2rJx7fK//pvjlq5afPrmxcuW9qAYG+8wMPlQMwwqiKoHZ2qA2Y74WlBdkFDWwouo4OGwO9n7p4/9/Rte/qrb7r57cuUyqSKi+aP0B0k9lijkwRH52K973UkncTgzEBkXjXp94e4a67/20MQNpxw8tK/bGUcpo4BKFatRrAb7H3+snpvVsQK6PqokqQsqhv0jt//i9qecccr42BgCWTFq25NOp1PXeRYNACDaWBCQ+V63hydD7RVKH8BR5MQxWTmbxZ1QTNgfckNlyB1Lprai4jYgiEjbwqEtUJsHJ8ZqnsLjQBrJFAAwAoVzLqXkcYG6U86jgLlbtRXRAg/F9jFARLVGHXOzi9rIM+F8Gre/sqfI6MLUSHGIzI9O8+dBGyg3sywDVZJNeNQ2zVm6tvkptl/lyMAxOegYW8llCbr5kG28KcgluTYbYtfkXVYRZiJi+3AIgKg8/5EXXHTwPiQVFiFA770DrFKMKQXnF6bV+W9wvtRo/0H7b2zfXJCDtk63jA55s2tfAo0uQavrq0qOiqJwAlEycIlY8+BOgTlBntULc2RJAuK9d6nX64WxcTnhhEuXL3nGt35w/Qc/8rQ1y1e/4sWvP/H4026/+ZaXvfh/8XAs4THBWuT0s88++6wzz3nk0Tul6m/fed+Fpyxa1D3pghefe8E55z/jAqyT27WXfa/seVeN5nwYTwBSS1t5AAASQWK7ZYrZzr19ZiplXiBaEsBnT0mfL9e80iagKqJou03HFleVonpC0cJ5Tsky8yjWtXJhiPtG5VTZLLbBBd/AmghNV1YS19GXRSa8GMrRQBwg2JDxG7BRU2l5lyWohVcu7976y1u+eeU3161d/atf/SoU8PwXPOdnP7u+qjq6JfndvhgtPlbt/dEPv7vquOVPfepTo9t2rHrooosu+sB7/+2r33iWJ0RyKSWwuQioOo9N12tvP6lYKZnPw4ImeP7g2ecqnCzkcYHaPExStPff7XZVNUqWs+aa2zV5S46w78WU1xRSypjqEPxwWLeLXiumFv52ZmZhBU0qkMXFBBGN5WhBQ0VjjGZppY3AcvuGdcHWxr6cc2VZAgvDfM62k5BECuehncTZ/xNlFddU/ND0FTnpunzAXKvxqYqiCRW9QxYVk7MlRtvNEQBETnYbbNbknAs+pCY8iogjsppv6aLedTc8dP3PH1u5eTXUiN773pjMHhUNv7h964XnXHDHr37w0pe+9I1n7Lho88++O/3+bceWjqd904uXHzh8JPRrgkjkSf3YWHfx1OLlK5YtXb5s8fJlm084/uTTTl5/3FosYxgWB+v4+GMP7fjm166/9ZeDJdNHyce9h+Hhh/CaKxdvWLPiOWdv6i0+66ILggurFy1dtHFThFHXUY3FIA18CgX7w9XsgblDofRqqnNKjgpCn3RcKChBSVCl1ClpODM3Vnb6/WrV6mWf/ty/vfZPXnvnHfetWL5mNBqpHymhL0NKUSsoioJTJCSptZKI6oIL6H2MWn5q9eATD6eTh72HOyhJCSkEqhJBAh7ueuw+1NgpFw81OV9AXWtC59ytt/z6T1/xRySYlE2GCK3lTdyS+6uqso9A3qkKtfWoI1QC0SSMbTHKGRJoKcVaJktqyiLZ6BBtLGyNtdoIj8gFIlVMyXZkUZhg3n3HF8GsHttWVphVNTIz6CjWRKQIvg3l9ETzBxM3SDSviWO/nlizUkdOvWgfo41E2oaCrDtBRGCf0P6NAAMokKHLxGCw0DQx81kKM+XJHlFFRaScXBcsnLhJyAvnZm0Fzaqu6aEdOHKEqDaksi8AcOQcUSXJtJbsH3Pz+eyymIbAwlZjWFcGYY+cUkqW101sua0PcIGqrZCyMqf8iShTuYhsOS/N5E3NwhMBtKU4Yzv3QKPHgA3JC+cTNdFKMz3M3l4RggLUnCh4QDR6q3BC1LGx7vhEp5TRlVdd+V9f/MbJJz+JPJIfPO/pzz26c+adf/nqdWs3XXD+mccOpd/5g1NWn7Dj4NH9n/zH67/wJXznO97231++7bFHb33N6y4+7+zLT9zy21NLyn3bZofjTrvd6EljrGY1dMdGXKWohiSyyI6ORMQ7VzGXzpoPbaMtokMEGwJLg1czTRiXGtxyCyOw3rQxvfe+yGhWVQLogKs1JZUqRUsbmhhYoCzbQVB7W1FEuQnNVmw1Uyx8IgIxcgIjyDYNIsB8nkOEWIPzEFxRx9mxcb7yK98aH+seO3K4Gnau+sa1k4sWM/uVx+mxLbU+SNOLwonHb6hqdp3quuu/++n/t2ftulOe8pR1q1etn5oYP3BwVkGKonCgLEmNuYvgkaSBCDkEWzJZPsMFk9U8g2kkmTSl9oMkycOxNr9aPosxlj4YTpiIhJMFCFqgep3rDEAktLWC1HVyyTk06Zu2orUHh2MiImiMp5SQCZjFLdiiJWaHRMEjQ524rahoAfokONLEGcBlLvcsDeIQuBmZtEnUKqPMnsgOGdCGl3bI197Z9hBa4owxZrdy1MIHBTCiJhpvOGkWmva5dQGVGCMqIHgWAWeyR06FrTPbPXP0Xz53nV8UnPjRaDgxuZwnDiRaynNz04uW7N654+jex1974eQbN970he1nX797yV0Pf9Z7v3rN8nPOO23T5rXTk1OLFi1etXzN5lM21aOqqob9fv/xfXurVD143703XPfjmQOzhwYzpbJWs8dGRzecc/q6YvrpKzeuPf+UYry3YtGSJUumoQQiTH044gEjHB0Mkqa+9EZ6sJM6I60Q5lzRKakYjeqe9wQingSYavVBo6aaBKIW5EcjQXKHJXZA+32ZXLX2E1f850tf/rJHHn10zdSyYawd+5ojkobCq9SiyblezaId75OQcqqjdwG/Pz3cE+rX7er+5enkNQlEAvZ+UPO+A4f27n88eakigxdKQADKUBTF7ffcs2/P42vXHzcYVpk8AqAgIXhocIudIgiCijmKC6ozIo5zRv4WMOtjRE8Owvx20tYnli88Ocl6A4QoiE40USOu3h5OVaVGjVwa0J+d4VAW2jSxGSXgHSA6R0VR1Cman4gXQBcKEM2jJFQBBYQEQOgK8KqKDIhkOzT0JYIgZhMuc1YxcobauBMXlJmirihdKDjbhrBRU0QEAkqT+G3+bE9FrWy6JFbyazPaqklBFYkU0KbcDCoL0m07RBI0Cz/NDCtOIkrolBQ9oprTPSOSKVullLz3AQgRnWtwWFl9GmyIbNq2NvFPtrKyNXmjeavZlkoDZj/5trO3tXdwgZkpOFXVxIJCTKrK5ovn8jydjE5oRX2D+ZKG/qiqiI4ci7AjDwCoSQVBSgwepEJ0wZNwJQJIBXlNARWQRcqi4zqRgIazs/fefc2fv/qvZ2aPTo6vuuvXd73z3e976tMuIJT/9XuXvfUv3vPLX91y74P3ffRj779r63u/c9Vwojz1uc8/9aorb/7UP//b7IG9f/UXb1u5fOW2rdUs337Ho7f/7Nu/HPXTB9/zjlPPfsq+w3OuSyMpe1oK1QKKgaxCceoAYCQJvE8CKtEcseq69kh2nwsi21UQEEQGxOC9MCtAHSNbKQdNMiAzqcOUahEJ5ACQWWrIwKKyLGOMmrjT6ZhjKzWeCgiICgyqhClGbUUkHTrnA6txSGOM0KhS+0BRrMhTA04732hVIgAoIVcRHfa7pTu49+DPf/lrpnjWBUtXbSyWrdi0aBGVxcTadZOvPv6L/FU+dqSq+jNPu+ypew9tW7tm6pKLT7vl1kf+58rPvOG1f6JEibUokJMIogA6MYwYCkISRpHCbD3IbO8UkkC7+YCMkFLvGvgBqqY2NDgiYta6BiBgILM5KUx13JgFERC7RRljrIejTqcTyKHzSQVFnQHaEVkEgquFvTjBbCaoCNIoI5J3xgEzsab2CSWkvCpLrCIZui9SeG9lpgteGiclVa2bmjU4n2JyRFCEGKPHeQVpG3jUwkCYQMnl8p1VmE1NFpTZJFYAQNGLArHty7zaTloFVByCuUhATKISJaHDThlSVXsoQLzIsFZbEwbnCwWloIicUkCKJTvAKgYEKYPOTnTcZz9750P7q/VLj5s7fEwWLzpwaE88NFNVVQG0adncnT//wbte+/Q3uL85MP3M5c/56ouq+hn9PbGiFSsmVqxYMTc3t2PHjtm5ODfYd+N1Pz28b99wNMeUyGMc1r3xye7U1PiK6WlYMjw6t2P76MUveu2zL7+40wGSNDdyoDqaG+7af8wVwSA1wXlVJPAFeoaq58eFxKOKeE3REU32gk13jDcIIRc3XSwTpkSuBC8uUmLxJFXkmI5bs/zT//7xV73qVXt2752eXlxVVWmWFRptI6OSyAkmJ8ICCOiFUYeu+5njBn/52PS/VrC3V3ooeMSh7B+d23n/ncpHponII8CQkWrnRFI53jtyYP8jDz2+YdNxMdW+6GZErHolMGqcVUUIiATkndZ1PeqLwFhvnDTEFAN5Cg4g8x6l6bhEBB0VIWidBLSua1uQOSuzOWqDmcUFXCNqBNWxwQfY+sMFb3QmxAXKMwY8sm2OgiQuffCo85M0MCyz4fEVFFiayS8oSjLeS9E814iEC8yOLPktAIAYtsU6wtbNtCUAZPy0CfpmlKMCEBI+ESPNzCIKniKzUsZmpxYbbBMkme/97c2YVIKy2AKofSceyTbJ+T0TUgZ3P6EcFhHrq1zwTcdqbXX2xeuM9VoQUDsfY2YiB/MS/00ynWchASJSOwhV5fQEEGkuRxBbydz5+5ph6qTihBnREwIQiox8AQDovRORWJN3JEnqeoaROn1xBJPTOBrp3m0P7j54xZGZmw4f3tXn4ebNl77oRc/+wpe+7Fz16KP3f/MbV21Yf8Lv/+5z9u0+ev21N339i9+78NnnXvLMh7/75SMbNp0y6N+5aFqe/3svveuR+2f69cN3bB85PfmizU966qk3fvOml7/yVV/9+hfWrznlaNROEI3NMAAAkq0t0Vrb4INp9aqxhxDNzFxSptmwgQaYIfv+kvMevQcVRVBFsY1+g+2yq2r6TQRgiB6rhbtF2V5JtSOd1cjneyAjjaSUGJS8Q1GAPJDKz7NFbMLgMjuFFGyYIZRRxkSEmgAVgMqi98ubfrV37wPL1gzPPHfj0Uoe27n79ltT/2j3/gcemtlWT+xZOjZGv77zsX0HedGS1atWLI8TB5/7u2evXAvnPO38ugIlNJMDew+s7L3PZBSElNJwOLRf6q0Z9h4XzGZsUKzcENYVWlAbNICJJIKoFAggr1SxRV0B2MUXESWsUjT0ADgDdmSKBHhHCKgOoqYUpbX/agpPNktHk9yCbH1o3XxmWDZmjpoa62uWlD8mmSulSXdZYKmqqqoq733R7RRFYQhYaGxOiMgTRk6+IStSo5hmbyihAotjk9MCQdACBYMHcAKlK5QTCFJR5AtVIJOgoAcHKQj6mkdlkDpREcEFLySpmkF04jtOfIEDRgFAFpPQmuktmfjez+776GduK5ZN7z9yJHTUD/ctLuO6Mye7Dk85df2KxeFPXrLpBdveMNLlvz7t748d3cojOTJzYHZ29p57Dhw5PBtHlSSMNRSldsc9BqLkguvMHJudG9a7dm+bOXpk2J/bvXN7IH3Xu9/5zEvOG83NzRyMDok9Fs06DDgTvBEV86SQmfOE32S6TXCsNapqRSBK523RJnazEBHAFYE5hRAkxdn+3KmnnvgP//APr3rlawaDQVmWKSVW8Q6Z2XunKgDz8A4wqBxi5yurhm/ZMXj5rsl/OsE5H8UnkcMz+/mxQSgW08RSLboMTpEI1EFyEWQo9z1w/0WXnc3MGiN5W3x4VE3N3sRCKDNzTMwsSK5wSUVTNS9m2ljMYUN2FdNjSMk1L4ILvoQy8HAhT9WuXnDzwKu2RebE6DyAMGeMoffeuQDNNtOeFwb12UahWZHmf2F4RZGkidCoUEpEwZuz2Dw/NS0Y/kCzwW37DMvTkFenyYDdC4MFLNjFqiqreIOaifV6xIhgvCY0PWABltSoTBDmRNqsorF9Y1n3Jm8H3fxwwNRxFvBrTdTeNbZ3bSSyK6UmBkuojSBAqeXC9wwLnPJCCLY5aOV1LIK0rJX82QmoIR2hgLT1AQJK3ue1N1gXTNeZmVxy1HHBxZhUPZr1kSpz8iWriMdSOAGUY2Pl+OI0IyFW9S+u+Xk33hgmHqmLn4SAm9dv+b0XTvzzB26cmBz7s1e/6XVv+PMLLnjqKSedfdHTnvq1K3+0dMttf/zGZVd/8d61Jx135rnnXPScQxqnPvQ3f7Vsas39jzy4fsPxHOmUM06YnTsyt6e/fO2qpz39nKuvOvLJj3/y01f8v/3b+iWV7BIIiYhHsqWpjexSSqmu1UoTM4ByGV9r8q0MyoY+NTcks4VGU1cnA/yKdX+BOEl7hLRBzmNMAJJMj9A8Im1J3EyVlVqtvvyz4F1BxKCmB6ItC9uwhM3iHxHrFDvkVdWErHEBsQc1BOIUq8nJ3o0/+eG+3bvOPecFf/e+r69YsrksJoZDXrN+ctOrzrgj/IJ52K/d4hVL9+w+Mjs72x8suf++x5yb/cyX/u65v/WKI7Mj5wJSvuOmsMPNzJYADWSgqkbDNSWBhX7AYAZ8AKCaUvK+aGNJWyi7BSVgW3/bMc7eZc65IrRjW6sUvffYrGmN7144ryAt8pCZOTKoEkBwHsUinoKCxKQsHik1SNH2rlERPBYOsK7rFKMrgh0GFE2cWjcObcbgJpfvg0+NZVNSBpZMTzL1+UYWFBGBnKq6pAoCohqjceXVIJzsQYCBBYA8IaEHRwA1k2MihOgkpUEQcXWtruwCJESoU+Fw5FClLkaqLgjWAOMaQkkwivVEZ2rnjiPf/t6Nz7x4xZNOXb562arV61dM9WDRxNLayeyRQwf27jg6c+wpD70LRjs/PPP6bf/1ZWZGCH5sSafHve5Ub3yZn5Kjh4/OzB7Y8/ih/tzgcH9m5uixONdn5ggSnJ/uje/fu+PMs578sY/985PPOnHvvqMpgfOlJASIqqZ/n/GJIlLFEQajXrvWN1pYAdQ7Z7pAVs2ERjqQzObQKTlDHYLYug0cAARfKMixmcGFF53/3r9+3zvf+c6y2wEQ5xAAnMeYauccKIN6mN/ZIwHSXOh+dc3si3d2PrFGqx5S4QsWSEePzY71VtZJBEEkIjCkSkGQCnLyyKPbkIiCV2nE/xEY5vOXc84cyRCxQ8QhGNwJmq5MxHKKRW8FADVdypwjwJQUjSnTDiQJ8p9YUAYxySmsjIbXdJhtHomcWzhoNJ0kxpaPKo0yq7dnwCMlzSrK9qCS5OTRPi1EVBRFZLH+oO3Y2rrbvsEGjoHZGxgR0SMoYqtsYFekTdVt4CA1NUHzaEQLCuZaKqqhcTSzMlkacYD2lzKo0aly8FLUZq21MLMCzE95tXF6b+8ZtAcEgZC00SlpwT5KGQ7XBrV2LU1ExlT5DWIINki3dr5tc2ki9OR4AcBIWk5nZGyy1PwlAhDGFGPoqFBERZRkFsNIo3qknqA7JmVRDgdx9+M77//Z9ffufqA/mA0br924eN2hudnZw6vKicGwxme9YOnM7Mb/+rcfPnDPg0+/6Pd373tg5+TObdv3vvrlL3zs4CNnPemctRPdu+/YdnDnzLMvf+bsUbf+xFN2bX8gVv19O/bODkdFJ2w+bm16fO/hnbuLRYtOOf74t775LXtnpRO8yEhdCU0Wa5YoxMBJxaaX2PDAiKjV41QAFLRVDQBk4pYIp6xrkJevJtrpsT0/2uiuGPilvbUmegyNyYnFdFW1DVCOSgtU+EtfQACxwplZCVXyisR0UEWkTjUSgSNT0LRHURMruRiTcuAa7r37vk9+6qOvftWfnXPW/8fWf8dZl1V14vAKe59z76341JNz50DT5BzErIgBFDAOBkBHcRzRcczjIKCOA+gYxlERMWfHNIIgiEgS6ABN5/zkUPVUvvees/da6/fH2udUNe9bH+1PU111695z9lnxG56bsuYMq09aPfMza9PrpgAg36P8ilZ/U1+uX3z77bfPze6dmT11zbX7vuJLv3FlY0pi3EXGwg7i4Pwr6XwA+6TYNbsqmPsT4teFOlm0nHMGjRx63y3v8KjTl/g88AR32o24KzcjoOPJcxJw+xdASdmVp/qVec7Zl+NYJO1M3TkNwAwsizL4vqYvxPtHuFVl5ioMsLMRCyGEuuprXEFwoTRX7xoMBm5aHEKgGEv8NSNmMPcy9HCP5v8pKREBuyQwAKGJWcqbUYhQmzwYjAhj07QhRBGpyBpkNYyKjJyDSSaccq5tgAg1yzBGYso5T6eTyQZIRgqbtqkwkVRNJ+Nk+Qfe8F3DkW6tXrp4aXznfZ+ebly6cmZ9+coq4ZgkvHrpI9eMbntX/M+L17/gyxf3jYYLSPHv/+EDd9378bUrzfbWdHtrWbMxZjQ0GlqwesCDuZkqMjK10+bSubPf+u2vfMtb3jKcmTl7aUshQkA15IpVRKVUIYDFal7NsqSuMyrNojd2jRUUHsWQc9bptOIwrGoVAZG2bSkWJ2zstvgxxty0YGSgK2tb3/DqVz1+5vRv/NpvLC3uEUna3cRy2FyCVw1AEZkYEHH23SfG33F6+qpL/PsnAgcMAYERKWVkyorKoGDZCFRBEKTi06dPN02DiLar38MehpmyZRFIRn16Khx3VRHXn0IiIjbUDhIIAMDEhobQW9uVkO7alCFCSk5gNKReTQgAQM1tlwFBpYwQvBbUbG5njmo555SymZEBA1q3Sw5+cAMSxUDQUYbUZS5KPvbnoYtTQTX3qKvSbvbiuoSOgIDOpYTYs2BBPPZN/c54to+hndA8AvZqyogI3RTFESiKhdpUsGpWJHEQ0eW0ulwY+hcH0U7iHf1+dP2rfN5BtF2fugRBKz+vXmt3wcueCFvrA1AR8Nu9WgDAQP3P9FHS/ym7MCD9tfCElEQISinaX2ev2iQjE7dNjrE2y9LCaDRY2B+m4+aB+x96+PHPzh84e+Hc1j23b9934WPNVZNJc83ZzQcuXfn3Q/tOVnig2dz3mY/MPP95L7zlScfe/uZ//eQdZ5/3vC+OQ53bS4+ee4jh6x574NLNTzv2pKd94fratJmOqNp86NTWTFh60k0LdT28uHm5la2NrZWM6fLja8/+oqe99h3fuLh46NxaMwyKwLk1joCIxQrbQE2zZjEFz3kIPmJhREaKyKkb0VNvpWdGBnE4gA506lWRoRceGaFbDvQ3GsrZ6Fs3KXv0oq+yu9pziGwf38119pmZWRGsA1OU1G7qDzn2NthdQwbopjhQD4hNHn74rr1793z367/7He/41fvueyDjdOFFB5tf2BxTlpBAQQapXYDl/3LuzJ8+uPTY0qmzjxDIV375183UR9a2JATNOTdNw0UI3VCNERQKJhm7ZSoiBh/wqfZprP9EESMHJsacVUSzZf9oiGVr4x+tv9rWMbClTa7gt3NcRac5UwzQIRuo+zKn5HbIfGauY3TlTlcyYUAvd5jJSVNt00DXm3axAAyg7G6c7sDkEptZxZeR1MHB+l9ymEhuk6RcVZXjOdSKPX33sPuYwgCMh0NXO0BVtQzgBpQMJAFQTDk3BinnljkiynaCQQgcLCEZV5WFwfygCVAJbGtut8bb9z26ubJeHz6wdOB40OHlZvW++z5zZX0ltbC6vLE9uTwzY1trqxvbmYQp0nA0H0LYN7f30J6rH7ty9unth7925sO/c/GLBl/8/TfP7mnTliFvbco//9Pfrqw9urR0DJFHowFzlNxAxoaamWow3Z5KFTkM1lYuaZ7+z3f8wmte+01rG+PN1S3CKtQVmjtACiErKQGCi4IhUOAqMkhGRNEMVm5Z2R0AtG3rQ/4ikWs2TS0HEoVsiikFJAwmIiqZnXfr3LMY2vGYCL7v+9/w4H0PfvCDH1xa3NNKE0P0IgkKFwassxwFCkQE50fD9xwef8eZPX9xHSqioAqFENS2OSAIgQHYwExdIxKpWl/f3J42c/Oj1KpBRkRTVJXy5PpYSEsDJyJEoW0zM2ZJZlZVFRiqKHIgLB64vT8sFDASaJeGiciozMz7OOyny00JyzBJ1DqCTtl17pI0QMaqe14cpO2YRzMr7phGVqxdTEEtBNIs5nLEBgxd+lFhl0nvSHK7nwdwKpGZuViVE38ditazFDoHpCdkHX+ysxgbETlBBcuypshUAlPOWXLqq2ZmjjG2vkAywE4po39BH0Hv+jaBQ6LAZTF20i13sl99ILPOIFlsJ+P2Ienz8uhOuUTkTZUVYLJ5IxWMdl+u3b/bVZS7WDYA0I30VXU6nZKBa4sLmAVDxJwkhIDSENNgyPWinj195oMfuPvB+x5eXtl+/otuufj40t13TNfW2+e96FmfevQz99x+6pq9exYWvuWxTxw8dAxXtt7fpJSWJ7Ojg//nj1/bblw7rJ5KgacpGNP29uT4wpGt8ViUFuZlMr6SNgOqMM4NZ3hu79yBkyfmBjqanbF638JwpmZqWZY3EitlymR1xZS0NQTVbIa9BTozS2dD5PwfdGoZQPHk8NPfy5J3nSuoOYmqn/OEEFxfHLsdfDldbbEINELFwjRWVQUrE9Ein6KkhoBqyjEwBhdeUFVgMgTn9feTcxNFosDMVTAz6QDz1E0ygEktDurR2c2Uktx9z71v/+VfrAbxe7/3jb/+tLdlSnZcYR4AAA5Anm/3bu575GsvvHLyA6PZD3729jtSO2rbJFIYe8wcidO0YWaFMjDouYN91QiOwe7Gif7lbbGmXCjgIbpI544/jGtfEyAR6M58y8ykTVVVKULbtsWmhUraTiqBArgjcsra3QUREZBS+CNp59+XOwYIAgACxyI7X9dROxXM8uBYSRL8RAEQ6sxW+5teTCbYV/XutwZWYCIKjsYywSJwhMVr0czARJOqMkJNbEaqamCMrNnDd2zMFDHMzBJTXfH8ILeBU0ZYa9Ly2sb5C2FlJS1fPv/wudWzDy1fPtceOgJPfubmA2fPnPnLC1dODVMYb2wlmC7s2Tc/v6iE0+2Z2frIddccX95KG02zvD48f2n15msHn/7gX46a237l6+/9w3v3/Pfbht8w+6ntcWotz86OrlxZO3Dk5PzePVeurIApETfNFECQAmFst5tRXSnlRx+798k33vj2t//PZ77g6atXJlkhhCApa2vucEORICKk3K97/BEAKNBFVVXbEQ2kTt2lr1xLgEJTKc2uP6pERIgZoGkaZ/6AgBkOBoPJZDIcDN761jd/y7c8/Ngjj+7Zs7eZTAOzOG+/I2jsRD9kAJj/3esv/vW/Tr/scvWPe5kqUxaRqooCYKRmAgJmwKoENhPj2sbG5ubmnqX5tmkMjJmRgiqJJB9PIhZIbN/k+FdZ2RKbQis5W0Yi4BKOS2aFDtCDgGqFWQQEWnQaoHP+6MO+b2fNzNMcV5Fxx5/ezBx1YgiuoVtVladhVa1Hw9C/uQ6rAkQETKCAoCRmYA4OdM5vn/xsl9Fm3zL6q5UP05US3hT6N7mjCYopMe2UHt6FiCqA5Cw5BwDZPTruIjh2w0ZUsyxoPQK0yBF2mVLQJTN9FgHkBQGCQsmPyICIxUkoa2lxbFdL0X+cvsLo97IVh76x1k440zm40GFB1VTAeoDqTnbfpTmQ1eX1d83Si7iHVlUlIm3bQidcUFVVEsp5wsDzoyosxoceemjlyoVsl+69++ywmls8QIPRoYdPfXph4fgNN10/v3DdRx76lxiH999+x9J1LxwvHxwcunNlPAr2/L0LJw9fNTx85HiaYqrnLi+fz7y+fDEMquH+YxvSwp76ZhrAZJoOzh1dvGFWYW4Yc6xG0xyZqJZQj+ZTrWNp262sI03S6DgQWaybnGaQCgjAFSj9QyGi89/9UidNZuoK4m4a1ilMlQ5PVVkJ2e0tPFgDGQViLb45/VRgp6CxjqFUurTO6AIQUDpNUTPr1NmKUBeUEXcCzabWNDtpScpamgw0BjdsoHI2ir0V2KRNtHexunJleXXt3Cc/+cnz586eOH7Lv93xYfvGhDNkQ6F1tmXMCxnm4dL08tzemeXDD1/84Hh17dKNNz2pno3p0pXAQyKqR0Mzk+mUuIMiqrf9XpuymSVRRDQVAtqdgPvSLZuCKBgwlwGdJ6qyYq8rRDQC1B3cShbpYTiIuMNlssIpQDWXgHUgYUppt2pHzllEHF3p0laq2mtjUc+f7kZOO0UDWCDuJ3jMjIDgO+Bc4Hj+bHqzi2qtCSj4D2e01o1a1UJXspgPxMzQFAEiUFbNIE6AJqLAkZkGg1pBeMgThTzJsrK9eebC9voGrSzLheX06CPNuUcmV86vbK2d3t4+O2nWUrMxSZdHo/V9jwzuu/vgkaP79u8/Uo+uu+W6m264+cQN1973yKl3/s7vX3Xzl931eLW8ttl+9AwMq9RMeK152lOu+dTHPohrn/ubVz30wObcD37k+i/4wmd97au+bGNzjBSapkHI//G1r33vP/7zr/76W2dn0ARnYtWmbSJtWx7Ozky2r6xcufCNr/76//6zb9qzd9/5Sxs1DUXawBACMRoRT7OYgeVsXbByiXVQA9Xu4pc7XuDiohVy2zTZtK7rojgGSkSpzTsOykRmFmNEooorr+eAqeLgKqFt2x4+vu+Xfunt3/kd39G203oQU0rqTTAqFPQLOpXfzIwg3jVb//vS6mse3Pu3+ygyB8k5q0RjRBQggWDRSBGQoKo5N6kZT0pIRE0pedPHnaueV+0lcSCoaAjkpzelNG0LoTTnzCHYE61RQQ2RmZnI1Ld7Vrp2camJXSmmFMHeoBJ2ew+fuEDo0L1I4OrqCECIROhDzZRSM56EfqrjJZLr36kI+KaL1FR8Vm6EYERIqqVkLpt8URFJzkM17JtCBzl7TWVUZKz7NMNVLIYKWRAxIBFSloxhZ6xtHc8anQO6S/zIM6v/EeqQ1arZUSRIVGT9O7UHRIeOEYBpP5DufjfnjF2BRkRurVjOLj4Bb0WdjLP/VtIdArhPJGoKRSWo+6Se5HEXAK3nPSuYqREX4Hc5NFDwWdO2kZQHg8HcqJpM8vbWlopAFRaXBtbavffcs3rl3Cc/cffM7NKeg7a+Jrz/wtNe3N53h+xdevY/v+/u666t7rv7wp2PPjR6wdyzX/yKj73/n44f2fqyJ70q2N4TVx8YDJv18crKlSsrl1to1/cszNWj+eNHFpcWua6GddxLVaI4w4xklseYMJuGSdNGtklqJWaxdZwQxGE7zFWumMZxZBWOxu32gAXUmNixlEzuM0PEGIwAMak4jJmIuBp4q0I7ztO+ZRcRgcDuOqK9XgqYolrK5JD4LrjvPsOeMplZwXyahIFRrH8FKBBZ7C+4F4EAoFyspnugRHmcDAHIqbTknZmBuhoZIULVTCdVDZeXL507d+lDH7q9GswDwD0rnxEQqMAAbNVgG2bnRk2V9hxdmk+LL3r5sw5fufquuz74pFufs7Fhs7PzbW7G48lwONQsGQSSeR2mhN77UgehENO6rsUwq+R2Z4LSYYwDqCkpCGgqszIn/vrxa5rkma6vicGXu4j+PBqYYCc1hShmbju403EieMyNMRbZAFQiQnd6yOKK8SDaaecYuOMhdms301ItdSV1QGKk4gDMFDkAhz4BO/zKMz1XQU3QLKm4aAYR5SSutGqEnUsGMAIjaaBqdjgYkBBkNW11utVMxlv4wDk9fwEefhRPn83nL69dPL16+bHx1srlzekVaS8ZLFPc4AEt7RsuLs2eWFg8sO/ak4dfdPTI0aXDRw6fXDpydG7/3uFincfAIa9tbf3OD//Oxz74b6PqRMDrCJvZQU7YKOpTn7KUm3sunb/rH1/6YEX2Hf/y1EblzMWV973v0zkbB50ZjhhHDw5PfequOy0mrEgTTVNDHJosMyNdWb/MBj/3prd+z/d818q0uby+TRQzJqyolcyAYpBzU8+OWslRgUNgQOnGeU7sFCNEVlAAoLDjMIGCVVWhinXGWWKWco7Y7w0ZEZvcgBZGRk+w8SbBf2h1df3Zz7n1zW/+2Te+8YcCo5duOWcCIAqAiAqmO8u4ZGn0rhOrv3lnfvY0fnamGtrAZibbTCqCAEgUoaoGuQmt5LYVaNvpdAqiRFTVMecMRoYgOfVjsDJYJQSzULGZtVmYY1UNcs4pNaoFyVQ6orIzREQEMaNCbnCIR1kLUhQDd7tmLgI12inygedt9+oGI8CUUozRxfVKY4Dk/+7Rya9z4EElIgwYKKqqZgHC2NsOIwIHU4Us4LcwoMgOSoKZDUEIIhBQ4VmWR1pUVIop+i7tWUNIOVWZ1OFnTADQ5swGkVh9yjGovagXkTYnVa1j5WqoZtZJgpU9lqpCYNd99f9TAOsaVgAIhKYJswO5gwI5K1RRVbWiwC5JqE50MZE2hMBMbdv63/LnH8rAwaxjPtRELu2EoqRmklNVLH086DMzGZBhhk7OWtVjNwBwN5xQQOziYDSOHBRD0s3DB+fXVy598O8/9twXPHXvvpPrUwW49P/+9uMVnr4E4899In7LV77kfR/78Kk7JouL+zY3B6cfmL/jE5/dv2hp+/zhE8+86blPGt41edfjt91/8f6v+OJXP/tZTxsMOemm8GoznV+amV9cvOZpNy7FeoYoOHR22iICKVgrlbWmOZe6gUB1qmyWBaWtquGAhiICbWMAEoExEqBADhIAclZTkBhjDAUiEBzH7xqaiCbKSKaW2wYRiYKCQ3AVy1oQiTgxgBtwUTc58LvfV0JWzLTdwJUBp21LRKGKbdsSIKnVVdV60VNFEEVRYAR0X1WhXmwykjtikVgWZXaVflCRLBmBTEyyDodDAEiSBYOzcZnRkGZqTS3c/cA9Z86cOnfuj2I9bGV7uDZqdEO2BPZaOMJ7j9fjIAjIKbRtfvC9929vrj/rWS84fuLAlStrWM9UEJRFJKtZPZgx0RgDmjYiQBQCA8B0OuZAkSmnqc8H6rruk2jOucg3+r4tUkoFY0/k75YRMUk2k2aSAxaMOhEhs4JlMCNw7p/zgXoBZ0XDQEYgWbAVAMCKx9Mxc6hjFQe1bbMhCAcycgUpJQADR05FimXeqSKaBYAxADIqUlARYA5giALMHLnKOQsnUhzESpHMMCABkVYWsqaKpRVoszGaGooxUw6BUAd1gJpsEBURBFIDtnFlcmY1XViZPnbKzpyFU4/b44+3Fy+sb1y5sHXlQrN5ObWrAGvIG1VN8wtzV9+8sHfvkRPHnnzyquMnTx49cfLgkaMzCwu8NESo4gAUbGszbW/qyvo2XNmeW5qhTfr+//RTn7ztU/PHl1YvPHLwydee3qDAtnV5cs3RvXW18dFPvP+XX/jg0/Zvfe37bz2XBnXdPnTPnffc9omMNjs/LynJNIch1vVwbmZGRAGEiEBkJlaXLzx+4uSxt7/jHS984XOX17dELBATsdO8gi96wWKM2kgNJB7nu1OBAAyIQOYZoRCQuAz7iJAMidlcv0gDcqAQgQXKSsCLaQrs0GFry2QrSdJd8v7M8dKl9Ze+9KsuXVh+05vetLRnn5gimqoRgaEaqalEjk07qUYzCLn+14Ph4Zmt77pv5j8/36RqVY2nwVhMkdjQSIwJWNCQOG5gEjKaTseWAkRSsjozAkoWYBBL3oN6snAmLSOaicOgSq8bCBm1M+yKXEmxI1UPDREp5eRTBFeNRjTQnZkQgIll7Fbm0O1NyhivqtosIFBxIKKsqiYIkAFbMwWNIQwHdchN662AT3PcLz01rU+ofIZDgKGqrJvF7ex+/H/GUFUVmCLs0GG942SOfTFLvcybUylEfVroK6WUEgPWVSW5GDH2IGcTzSmB2mAwoMBgO4Z2AEWyEVXBl9CiudshlfrAzCdjAFBxIMQswlWUlMU0ELsYveRciu4YEdFXjzHGnsPa10pkTzDEYMeNs7EoImZTfylyfCaSowELML8DvkNHVQTALKII2Pdwnp9gfW44+NhH/+V//c/fqAjf9e7f/sk3fc9mekDy+a126ey5pa//6qXL953/98cfvOUp18/NLH7yznPX37RhWzNXXfWca561dBNdc9tHPvC5372t2hdmrh185zd/2ZOPXDvezlW1NDd7axX22CAiECpORbc2VNXBdzo7S20zRcRQRRHhHhlHGGOV26RIg8FAVVtpB4ORptZ33u6oDGred3pv5BfK7edCCMOqhv8f7Lp/te0Uu30wABBZJ3RMDnfkTu9QAVU1GGLHugOA7MUTQjKByAogKkRUIQOZZlEqfhiKIGBcCnYCAAyoKTdNA0LVoI7Eqsoh2C62jD9vqMYUyuQNMOWGMATGtk0Bg9Agt/C52+8L9SLYOk4bGe4JqbEPVPVX5hmOW7FdzmNtATfCxvrWtVeOxpUD9z/6sac+7UlHDh773AMXYhi1uR0O6o3xZoyRCFSxzUIxRirNaAihrmt0aGRW4Cc41HoC9qa5vM/OE9crbujwjdWgNlEMoCmPx+MYYzUcSO/V2PFosVs2l2LXL4XTQRkZ0Aw1K2hu/Jvmw0ItG2osaHZ078IsVc0gZApEEQrbMYGZSKCAWSTnVNdRVVPeIqIURqSSchMAMPAURXOulVsMIZlFthEOkaJhE2lrCGGSZVPWT61tXzwrl8+HcxfokYfTmYebi9vjKxcm65fX1i9f0ekZgDMcVjlM43CwuDB/6Oo9h49fc+zk8auvO3H1dfuPHJpdWhrNz80szCFDVmiSNTldUa03Ocs2m0iqOEgdSOJwbl8QpB/74R//0Ac+dODIXrF8+tTDC0duPTyaOT0Jswfmjlw1e/tH/ul11z/+mhvP/fBHbrrn8tJswISYA/P8COt6bm4uT9u0NcYqVFXY2FgjCmCoSebm6scff/iLvvgLfu3XfmXv3r3nL14JIVCI/ogx72BKsGzQLdmOCxB0U5wMxmJIjOQM7CydSAMD5CzM7qX8+f40fdLyMSK4RlDwdTCaiUMu/FdyEkbe3Nr6ttd865W1lV/9lV+fn19k5m7xn5kjEOW2DXEgKRNBJJp793Wrb/rM5MTG4Ny8qhpgEyjmEFRbS+OQsykjzmKV65lqOGhyE0IIVKkKITbTabbCZXczBusknvzcgqfPXXLifWveNq2ISJWJCrNC3Y4vBCNkZJ/3ZNUQiLoRpkf4yMEAPFn0j4n4eAwIO3vpDjVdjFMiBzcUB9EQiFVVU04pq/OFAcGgnTYOf4BdPEjuTLlLZ+n0A4ScM2FRlfQP1r8bJ4PLLvhiuUyD2vM3EYW69pABBj4t7rOvpzH35vNFdZIyl2ZmRCLG0M3EuJuWuO6/7UJzePgmorZpzUwmEgd15GhZ3GWBO1mAnh9V7pzD4boxDLg3mwOYwXoovJkZOfba+7yenmTgE7CdzUFJJGju1qKum+evTy6WZtikOL8HHnroyr5DJ3/1Xd/2I2982+/92a9893/8wgvn5558c/vwY825x15w603h8Y302U+eJ7mzmpnbf/BLTlUrK5fv/Ngf/NUwDZ76pBt+9L/8J5lJ//Wj/21h7rq9iy9c2lMBVUk1K6StbWYmRlMlNCRTFTNZX5F9Bw9sb297h9q2bV3XqkpA5IA+5hBKElLNXpQ0OTFz4KBoSKQifo9CCFJUk01V3aLKdkHNscOKd/qOhVQtKqBkCKHDysEOiIMIsFMsVzFlZicFKUKNbABJRQEwhmSGSKgl44KaHwxHFJuhmEJPhDVLKTGSP8Pl1pnGGAnZa0cOwUwQoRNnL28Y6iSTGKp0/uID25v56c+4YfnS+lTk8qX1599xTL537dEr63mVbECcEROGhp7/0S+N9eg5z3zlRz/w4X9+/98/+/lfdXljTETj8bgOUcwk5RjrEMK0bcyUuChvlLURU8BIYrsFSWDXlsSHhElyHy98HWRdEgWASCyhwMVFJOdch4j9ZN5UXLLBrSwRGcg6Z0+PSqioWSmQas4556YFgNDDqUT9CWIsgS8JWWrBcoxMscqACowhGDdZNBJXIWA2QwQe5Jw5bQQKiCgIQW2GkGciDBgqaCc6nWRZn2wur2xdPGuPPz587Bycvbi9fGZ68Vy7ur6xuXZ5unahna5DWGddA2gXFuubb146dnLvoSPPu+rk0auOXX/i5MKB/fP7Dw9mZolABJJYtpwTi+ny6jjnXCFXIQZDS9pQUw0AZDgcUUqQc1rcw20LP/5jP/m3f/tXRw8cHbcUiCdp5dSDH7/2yV+yulndcHz2/s9+8CnV5976wsffde/RP37ggGJuswbHsxo04/FaasFBwmPJeRqroEkZGavq7NnTr3rV1/3Sr/wqM65cWaurATB1oJBQlDK7R8mbVUTq7FaxUJGcIoA7i4z+56lDyJYGSc20KDAhk3Uahbv/ipkBsZmKup12qWXNrOIKEdt2Kqr/5Ud+aHNr63d/591LS/s0C6jFGB3H4M8RcSQCIhr9w/H1/3zf5mseij//NEQmYk4qBE1kU6sMg5gaTgNEHaiZr05SVkQNjJHQ37GZtZL7LOPDFv+Y3ruiV/Rm2QfpgINYKfssTQNXZhI4CJfcYYQBAyISc85t6tRscBcomoiYKLUJADhwgYyUkN7DeX2XC+b3vXMpDqVbDQy5KKGAA716rwJmfzIBXM965zmHHvZs5netHzKLqQ+dYDB0vU7PtdSZmVgxBt6hJJtZRhhQSP5OOwJiJI6DQe5I3IHYLWPRQEWxx4AYIBUccr/W8g/SbwVEBAObajOeqOpoNMLOrsdlH7DT/fB7oJ3RbPehSzmZbUcpuv8+9v4qzGSF1ORKe9gVLuVH1fz/+2MNu5CHaKCag01Xzw+/6Zu/6P3v+euPfej2CO2+fdeAxXHanufrXvgUOXfmsbZCbOnkLQvHnvz0u+/997f/0i/aePPmE09+3dd+6/VPPjKaPWKAp9ZPIdfze082NGozgIlqRrRBNUcMiKAqktssGbNBVlVN0yY37fr6+t69e4fD4fb2dikV23ZmZqZtW/chcQBOQCKA0OmXOSsOO+ELF3VzsU8gFJFQRUQqYmudpYFqpxjc6wkjl0l+SuLHTLXsIykgsRRDrA5z5ycoa2MuJF5eok0t+u0jKz7wskPIRjWfpjrO3H0Xit9AZ54BAAQUI5d04qTGnAUxhKAqBhjrSqVaGOW11fEP/8ib3vBd3xNCOnbNvn97/8Nv/bkfeMmrP/tT33fn5WvH9deyWCIJ1UfnNt8yvv3qj/yXn/yRC+cee+W3Peltv/j2t/2va/ceetJ4Mm1FKyYToRg0tdPCeU27OnJkDubAcMkqknXnhLpFgVcYKaW+cOmTrh+ztm0jsbvzDgaDpOUZ992K9zTARLue0FIjmjMTwIkKdRVFdjpsX9OqGgYGM5ZC+PYBuCFoznFQA9STNtk0xxgDGbaNB5UsOYlwVRNHrriiKg4G2yLGkVrY2thqV9bl4nI6e2l86t7qzCU4/djk4pl25eJ4bX19e3tdmpXAq2YrkXV+AffOze27cenEicNHDj7zuhsOHDpy/OTJ/QcOLC4uxiELGgTYbDAnXdua5Evrms1MeBAwEE8t1N5KBBGZWktEMKIRNOMJcLTt1gBoNAztGP7rD/3kP733PSePHktbyUIUE56J5y88cNOx2bc+m3n5k1vHzr3y+uVPXlz8qduuTVHRQEERCLMhACtYEs+EGLBtE5MFJEC5dOnC6177mrf+3M+sjZvtte2Z0WzOKskpZKCqRWbfANVtzouwXz8TKYkWC1iVdxwvSkIC2CG/OoCGmX1zDJ13MvUr0p70EdAyWAd3sSxuB8cYRVI1HCTNeSI//dM/vbKy+ld/8ZdHDx7ZnkxQDEwjV+qenpKYBmaAU5r546u2Xv+Q/Z9beL0u8lYACqZW7DuIsAbeWN665777n/rMm9psSbHkEYJIEdwxWrSHHH5eiPbU2+N5zSxZGbh2QPoWzKq69jxq3fwGuuS9o17SzTi1Y+SHLuL5i2su0Fp3QPfvGzj0pe1X76HNKYTASBCKxoU/LVWsPBhFYiSPNapm2lFByp0wcBEQ6/he/na1u7s55xhjPyosES2wH4UnaNgSUWDNOygqKVsMZGYSYaIQyDo7MzRgQDHFTpaFmYtQu9f4TJEKQ79UCaoOh4sxOpt7NBqNm2nbtlTVIlJVlTd83qsRkW8urUvB1ikz9zejD0zmzndqiNDfBusw1URkYOBI9x35z87P1Qoi1yV+ETDQvLFKnv2lX3rbr//yb5x/cO+LvuD529Ojc4PZB++/MDPU2Zv1sfsutdvV3WfPvPsPf/PpVz3z27/2lS940Ytn5xebNJ2mKreRg02mZ1ShabPmNIjs2dfMEk5BS2lhmJWBOAzruL01nkwmjiybTqfOC3TDHBFpmsbvlMfZtm2BmJirEEVEUvYo4MrAOWftkkGJAlTglEhUyNxdHdMvFgCgHxJYp2fkFjSesEuaMb8pRbTSX6Si0BbSvfajp1LzSXZnyaqqGEu2iMRGXi9aQPKxs2cRrHbhE7s4hUw552JVxQDgXbsF4nG7tTA3+Mwd9zz+0MrefXsMQWHy5V+38LJvmnz7qz995vSeZ9x0/MKfr8ZFWr1PD+1Lb/jZLzz2pKrW9tHHzsyP5FnP2/+Hv/fb//3n3rayOq3qIZhUg6GkFgDAcJLaem5G1fMnAZRRkIigCAZuOskRjw6DwQARnerg2JDIYSd07jQH3ZiHiweXw7vUFETJCNmVm93irdwR7XaLZakckENIbQaAUA/YLSMVWsvu3ACd+ZiCggFRkFbQoEZOmtN4SnWcGY0aBmQcVoAIaDDdmGwsr2+urev5i3rmHD52Lp09tXX21PTSxY0rly+tXQGA89Celck2UB6MaHZh/vixhcNHDh49fuuJk0evuWb/8SNze/fsO3R4bmGeI0wVAKAdw8bWZH2zCduIkgOAVkMz00ai+jHjgBGBZFBgMghWuxJeVkuSqaoqEFNEGo3qzbXmB773xz720Q9de/3hjdWpZtaqJVDEmW+58cLrT/5Z1da5Gl9/44TQlptqfoBrY9KJcjTDrIChitEPm2Q0CMMoiRFRc3P+3GNv+P7/+Na3/uTy8rgFnZmdUwVkCj0pw4Sg45WU5ZyXsJ3um/Whq0QYopIzHGxR0ioa2BNGzeh4FwQAch4N7G4hOoWDMscCzKYqiopSIBluoGOtpje96WceffiRe++6Z8++Pdvb217+hiq27TQOR5IyGRDCzB+f3Hr9Q9uvfnTxt25V1YYlqA6Is4XMkFQr4hqoCfX73/cvL/vqLycgjiSKgGxs4NoMVvhU0DV1O0mn04YqscVlF5wzjO5FaCK5Ik4pmWQDty7nz/vgiFhx8KFRztmyuKFWSQc7VEkyc/izEhb/QQSgyIogukPlL2Nkc3ZOV+d445xzTpBijDFGZDdmQ3/TRAGREM3xw8TsvMzymQF7akRvC4h9LYwFFi/drKwMQDo7Gp+ZoAESwRN9acwA1UDUEANzJiBAV47dKcfMrJCSykSu66uwSS0BYuCKBu5VZx1qzBv9XviiD1W9s8Luf/bbsr7D9iED+6zSdlejpW9w1KjTIjvGlAZ0vdbChvJfiTECcAvb2wnm9x18zeu+6ffe/Ud333fpzGo6//jZLVuNMnro4Xtn5+ZvPHbD6778G46+9vuOXnu0merGKl1ZnVIVWxWqU9KAIQLitG3QJbFbY4pMAalDVwGAkbPtiGhmZgYAvLttmmZ7Y3N+z+LW1tb6+vpoNJqfn2fm6fbYF43NdCpESOSKRZ7DZBdfi5i8iRARzcVmgwA985pZgZkUI0roLqm7AmRfK5irvnEgYqe0mmQAQwQzgc4TNzdtBogxStvmlBRBNStC4ecR1XXdz0KKlQh27UF5AovWaxWjdVM+RlJTx3mGEBye7Z2/M6wiB1WtwnAy4YP795967O7zKxcam/m+H3zGjc9c/+ZX/dqD94Tnv+Cpe/fu2VxuT3/m/Dd9x4Hv+k83vv/vT/3dzy48+vgviqbLZ7avvW7p615549bG5SoO6yrkDCKGHNA0Na2q2ZQRkcowUXPOWTIRKZJldb8B/xqNRj61AqCqqtp26nhJ3xw7Vh+52HBRDNB1ve7vxjFIYeoLwc4Bxg4R0ov6dnWnhFC1mM0sBA5VhG7/UorJEq9NinDBTD2owwCBrCJDo2bSXtlYH29sbl26lC9dmp4+M378scn58+3y8pULF9fWlze0vTDZujKdbiJuDiPMz89ee+zQaGnv8WO3nLz6xIkTh6+7av+h/Qf37Z09sMg8QxGywGRs03HTtDK5uN0k40qtSaAa64ojC4IQhBCrLIaKrJmyIRIFCsCIEWoxzaaGqgTZ+XII1sYI7XQ82b9v9uL5y9/73T/+mbtvP3LNwZXNTeBYzVQIyYyfs7T53becjWj7eXXPUmaEs9vVVXPj/3rrgz/24avrOJtti4mQA3EQEUPLjDFGU0GEQawfO/vYf/ze17/5LT+5fGViwETYtrkv+kMgM4tciZgzfKAvE50I220Kip2eP2OdJF9hSPeKvO6xBz0H0hSBiAKxdq/tjDvsB91ZiBkDWecLWYIhQzaVNnm8nU6aAwcW3/Tm//6d/+G1W1tbzoIF0HbahHqgORGhKhIHWq1m/vb4xjc/vPDum3jCkLMSJgYMoTasTAQhoS3u23/7Z+6767P3Pf95T1/dHgeuwYRq0s604/OS7u52saPGdsU9IgVEI8aix4eIoJhS6/1bCEHAzdyCea/sqtGdejkRTXOOoWAyyq2h4GM260iSWEDDCmAc2Ekx/ueK04DrehkWFxHtaMHU8SABwG0JwCMfAGgnQeWKKoGxW/XhrrEGRC67om4yLFZ2Qj2QXVVBtHwk1+hSAygyOv4raKjobg2IgUJ3TQlod4PL3akKMRSoN1iH4ytifp4+q7oCtZRSXdcMOE0tMGXTtm2tXzdS8VvdOXbd+mT3EmWn7EA01VLEqEp3ZEtANCDDTs/cjStgl3vyzutkU9KMMlPF6Xgjnzh584/+2A//6q//drt6eTodX7N0+MYbb37FS77iOc969nBhMM2wmfSxs1N3ciYOmGAmDscJhMbGrZUdHxoFCGZgGVsU85YcjQCIydAAEbiqPNlsbW2Z2ezsbDOeuIz46vIKGUwmk5TS0aNHva1XM1WRpmHmGNl5gdr5YmYtvNLeFDJ0qsUe5Q0BVFQ19CuAAlAzMiRin0GBKCq411ux3PHL2JHqTNQnGQv7lrIqV2HAwROtiCCCEVKnqqEKIRA6YsKVszrnzqxFajGpdHNyR/iVfqiIDwC4WiUjCQugRRiB6cH9B/75A38/Nz8chquWlpbe81cP3X37/LU3HDpz5oHTj9SXLmz/9C8fevaLFl/7DZ+473Pj+T1BLR09fM23f8/L/+Hv//Ev/vyTL3jh3c941pcsr6wLAHJQU80SY4XIOSuAZSsMwKJVlEUBHfvaH6FqUOe2oN5CCACVz96lo9KaGbiPZydgS6p+R1JKwQKY7UzeoPifSsedY2YMQVXJgIjanKlwbjGllFJjplkaSQ1yVVVcDQYcaO+emf17FjTbWNq1tUsXH7iwfO7CxoWLkzPnt0+dGV+63KxeMLPV9bULKytjlBXJm2Q2HFRLi4f3nDy0d/8tR4+duO6aq06cOH746JFDh2b2LQzqERI2AllABKatXVqTgU4mSYGwqrQyUg3IWNVC00YZNJAQqI/lADHr1CNfqBACMwdkEVVRKCqIaiYMGMBbDWx5olIfOLTw4L0P/6c3/Ngjjz5w+Mjhza1VtjmjZgK5stkk+ZVXXwC0IzPTmSCBYJpxqc5TCc/Yu3HN3uaR9RoIRYUVgjcLFBK0woCN1TFcuHDqO7/zP/zUT/3E5eUNoJjVqhg76X1xzqsHZ7e5NTOzjMiud1Hivrmn+OdtcN1IG4ssnR+MfhBFiO7w4zFZtHOvAB+99L0QI1HZRPh/w0gMAE1u6rqONGjblgMi8erm+LkvfPob3/jGn/ypHz985EjbTIpAtZqBQEB0yxPD2d+7buvVj01e9vjcX18DXJkZON+fyUIRvadBmGzAxz5+x4tf9HQkZSJtQUOPtCrzUeiG7btAWN0/mQAg+FVSMFNB6wno09QaYBVKvasO5EGJMZqJiqoqUyEW55zr0VA7SDmiPwLJ+X5Qxm8I4F2rgEFR9UFEZDMJaEBd4ePXsfTyMTAUYwAfBTvDkmLwZFnCZAdCUUNCjjE6UDLn7CVWFuGqisbO9zUEy5ZUsMlVVXEV+2OBANYZajoCwE3T/QYrGBOBgZQSHPzQSJcUAcp3cJddFBAykjOpvdBTQlV1nSMFqwa1qbnDYBlcIJq5QzjUde2yJv4GegQpGfRaYH5MfUXNMZipk5r81Yo9FCFhLOP2fvjjC/BuY6GdbqKaaZZWNxkWKDPEdGWaR/XSG37guydrMjfYExdajENCPX9xO01xWAMIDrCS3GDIbc4WZy1khraWkTU1KEaIuWkt5BijIhDHtm0BCYHLkwmkJgaqkneIoWaxqlZXVyeTyezMaGF2rg/izXRaVRUhZgQmyipg2OSUVDgGfz6139pCmQGQwQ643UydgNfVRqVY6ecDXOYgjOwao16iKZiqOF8ti7j7RQihGtT1cABJ2IAIc9O2kgeDgRIoWgTMbUJ2dfqCB/Z8HHrfbMKKK83SSukIAcD9tvuh1tbW1mhmSMBEXAUWkbadEpjVMAfhzs999MRVTwVd3d6a/9zdmywLAFf27KkvX9T1zfN/+t7XCV5+xQv+GmTx6LVLNdvKpbPHTux9+cu/40Vf+JJfesfbfu1X3v2rv/a0hZnZ1a0pEokhVQGATVFlUlWVahFD9edfTYzi/Nyc7irj2rZFA9+keF1fVZWq+gS+CA1CCUy+zqfAzkTwWQV1oEWn+LuEO/iQ02c4BprFsriFZpJkiMO6JoKZdhgCL+2ZP7B3b9vq5ubmhXPntre23/OP79eL/3xl+dLq6fOTK6tbly6N169Mm+1xnm5J25jI7MLS/n1zR5aG1x87evjIs48cv+7qa08eP3H8xFWLexcXFmeZUcFaxUkLbaMrTQsbGxkVKwqlB+ShggQYkCByVpoEgpAjQsggVicQAI4YokEFnDELmLsZswAKUkCMpKhQE2fxolF8tutas2Yo7f4Dc5/+1COve+0Pbm6t7Dt4oJ20Q1hCADWZYiZLoQ637NkcBZ2LQgintgbjTCdmpvMxb6fq1j3rD21FtpAJjRAQCCAAhqQDhlANz18489Kv/NK3vPVnxuNxVnTumWRj5pxbACdagiQngvuiVE2ByHYlS4FujLzTFHXTO4cg+XSKiCKxSlFdEXP5fUQzUHOl+q7f2PHzANGEYh1/VlTNVR+IUkoMRSE8BJrmZmOjec13/Id/+dcP/vM///PhQwfaNgOgWkYKAmLAjICI1ZmF4YcOr77mgdm/PpGFmChw5e88m6AhAghpPb943/2PbKxNOUDbttEqyy12Hja7OxkRIS6OCn3p4M0wAzvZPWUB1IBEgCDA0ZfPktq2VCXk3L9pVRXG0U7/GoLPn/35IiIGTCm1WapRjVCUqH0QjVg28eiO0aKmFkLHDnY+LgCgQdktYwF0GEKsq7ZtJ20z6B18EQBQtdMrABBTzZ0tQQwBzMxGhqJGCoyUwFChAuLIzJXjPjxeZysj0FY6mBlglhJrAAC6LaC78Fq2ZBqIBQ3Rp//9VNO1vw37X6GC0gGmQATE1jWmXhbEupo0U28svCkiCkRkAsmSqsYYycAI/XhRYOeHIWIH+PRJjSbTlIsvFQBBVgIkwgTZYEdiWkQMlJkzgqFJKtBuz0N1XXMLAkJklgwRm3Y71rODPTzOohsIMBURRmYQSGgIGU1V89hGoxGQ5VZQMNsYsEEERQUmydq22wTIzKnVUMUQkQiSCnZqjkCdDwaiqK6vr4vIwvysqDZN07atGZrBypW1wWBQVZXbNDpKyx0uzWcMDMgkqfU+1Vf1SQUJkFwG3aCslojLTAxQDajY3fjLUiAzxFj5aMF8sKkIEZsWVKGqTUVSQgKMrFOlQORmWJE4Zw1VNLNMBpEtCVdsRJKRGFiJA5iVVYiaVcQERmCmDC5k5u6wEM1k2mxbNvf6VlQ0JQoBCcFySjwzuPOO82tbK3PzC9Vc+OxtW69+7dzevx498NB5bLd+5beftnblc//p9ffUo6tGM5ttWp00YW7+sHL967/5tld87at+5Id/6h/+8V9/9Z1/8F3f+T1hECeTXFWV2DgreXLJOglUATaqbqySIwYaVka2e4xCxYylDcREoCiImKU1A2+VmiaJCFWx4uDoWFXjMPBrbpqzihoQGQREYm0VRInNHYFFTK2ZqaswGNRxABWaAZiNx9MrVzYee+yxjfXNv/qLv8kX/ubShYsXL164nE+dufXU//7nt8MlMFFCyyIcw/z8/OKx4yf37z9x4sSxY8eOHb36+IkThw4d2rNnb13H4SAAQZN0YyKNyvmVcfZVAnAnvYJWVVFLggg+cSEAzVZ04BWTuEoREEKNA+CcM0DWGCaWHTLCuVUFMYxVTCkVXL1iJpCUQ2DXh2EKYsCiR4/u/dC/fPb1r/ve6XS6tGc2tw0AGWZFUcCglSCA5tlKrpqbEsJaG1abWJNAf9yBQqokxIAS0FpLSHEqLQNE4pXls894+q1v+bm3bjdp2rR1XYtlAktmQbppJYAHyaZJzNHQEDEOauhk3SCgKeWcg2HRO3I7ZMJobibEjnt3H08FYzDXKQI1QEYkY1VUMBXLoCWWugZFVmFG7jk5VsRfkyn4C3r0F3fM5ZxsMIQ3/9ybPvOZz2xtjUejum0ZoCHDmE0rMxQ01TbP/u7Vl//gY5svvjj6yAF2GSAFQGVyRBZGqCtuHr948dLG6pH9h1PaFFbOmEgQ0aTHDkcQbXMLZoJl8KngXmhmZm2n1UF1zLkNIXqOCGLAJN3SmxFBsiFAm4xJiRKoggYg782w+6Je8ppIRdT1Q7EYukCndg5AiCyoJkoIAQPTLlHJvnbwjSF1sF4nn1hKuS2+rdR9+Zvw2Z12acnDLqKvvTsgNoGp+exCVRjK4k07JxNfVu1+M9DDg31f12nAKppKbrNA9E+O2sHlzWzHLbgfHbs5BKJ129fSHEdy7Xvfl2e1MkwI2KEVuoimYmJumkSdDpf5KI+QfArkPR2igklOBEgUTLVtk6KGEIh2OyuYSDsczVinMu2zX1f88c+b2mxeIsTYNilNprulcQHAoWTVoG6axhFVSQVUsgoBRmZ3xfFbaYg2zaGuEBG5bdvp9vZmVVVxUBNjVUfvgUzUWUY+rhnwgJgxhlZyUiEK9WDgf32apiDKVazruo6VZfFpZ4xRVBUsdl5giFiFiIhZM5ghUgjc21Mys0+3smW1ogks7sGC0Qypk0K07gxIkrqq62E1mYxzzkSoHFVZUwNV5UQpRSBvbc1MLBCqOs4AQYVCyNIGq5iozS1HArM2a+AICpKzogIaUwBCEwXQEEI9P0IsaGRgzHkcEAbDWqbTKtJDD9910423rKysTiaTlbO6dkm/6GUH/ubdp9/4Mzceu2nwY6//eM68/9hovIoQ5uf2D5qt6Utf8pV7Fg/eccdt2eilX/4lqdn6xL994OZbbpqd2zOdpFBFI0spcVxm228mkoF5aCQpRSDA7K7Lu6CehRDSxWKsDaDiKtTkQ2bHkUXGzk3ce5qUTVQ0ZDCRVo2IBoNBQCbGwbCuajQzCwQE4+lge6tZX9s8e/a+9UunT58+df782Qvnz168ePGyXjj/7FO/9U+/YufLk0cHQG/RpaXFq45ds2/fvmPXnjx27MTJq686sP/g0r69i4tLVYWqkBsQg63JeDOntfE45zaEwFWsqCYA6yacAIaEjkym0p1oT9f2fOAi4Nj5wXiAAYBAHIkVQYv0OjKj5BFQ4gCmypUbDKjaJOQKEuUJWPRKTebmRlNJv/27f/3mn/15TbC0d18z2TKFuqo1gxIykRmqyfc96fQNC+NxprFSzXpydhJJAWCjDQBw1+o8MIFOmCtpDREt5BiIjFavbMwvjN729l+Yn59Z3dgAhZzEnaprP/+iqfODIQocA2ahwAomKZsJABGTDwC5E0ztByRoIOqGRAW3GH2d7wNaolDk5BDQ0JCZLXcdlyuDamsuxtClnD4FdMG2mIVAB4byN7GxvXX99Sd+4id+4o0/9P2j4ckQJmo1oRC5klVJE/yphfjZxfXX3D/zb4eIAlNUcHqNlhyWNSKmyXhjfe3g0gERIQ7gGzQA60Y75hwHEwBE2uktofvgLlpg7rNi7hwPZW5fnm4q7j5mbuPWNA2JL9Q8bQkDWi7CYf26Fg2RSDWjoDrPtBCmoTPn3sF0hd33pieMqWqZyiK1bZOsRaaqqgaDQWpa/3j9Vd5dd/dsMH8azFmYCBiIDAwNCcgAiI2MiApSidHfQD8l8I+0u6zQlJ30otixghCRoSfzOH6bOoBrQI8upuhaMYUOJloEOtQ3AE8UIsdu1+WpH3EHSub/STvOsSfCYrpg5kgHBkxJEbXUDcyIagxmFkNERDNxFIy/oAq4bKmXM7mT3mzblqwIaSmiZTEz9/fq32T/hj1rhhBym5IK5kyBu3W7AYCBUSctwlUUMMiCkYhhOIgisrG2SrFck5nRrBuwq2ph1DGLSJMyENbDgSpkT/AE2MEcPPBpzl7gIWKaTikG4gBqgSIRiaiI+sADEbEfR5MBeK1bpHnM+zImAPPBKSMFYnPuBBgz18HUth+8966jR49ec/LwlfXxtMmSIXJop00m8tzftm2apuFwKE3ORMNB1bQtRgqBt7Y2h4MBmGnKaToRCaGKvtS0bJJbp2hXlYUQFRVchUMyF7k0YWBUayxPN5sAbDhGGX3iox946dfdcuGMrF7g+z699PJvueGTH3nsC15y1Yfec8c3/+ej//vNF8YXbfHInjyOV85cfNNbf+hLv/xVk2YSFuvxeHzg6GJFJ0XbKo4CVk2zYamdnVka1rjRJoOWIBMEBDYQMFKQZn1zMBjUo2H/JHYBl8QSAgZyl0xpmmRWjg0AWJtzcVFFwoCIxQF4ZjyKIz9aVUVosLExXt1eufTg6oUL506deuzs2bMXL14+d/701ubKyuo5nA7U8vb2psdkPmDMdMM111z11GuOHj164uTVdIjeefF/ve21v/aUo8+cmRlaAFVIrTVtzllW1rb9iZOUHfjJzDFERlK0LBpMEItSuHs2Z1OTNngr3MVTM/Nx3xNCRHdBsLsshOQ4EiDULGCAIbWthDgHQVM7VckxDMAGWcc4iNI0s/Vgfm52fdL87V//07v+z+996rZPHzhwYDAzaCYToBgiNyqhDtIKA+yp89uff/dXHF/5i4cP3rC4HdAODNuZIMlwdRq3E9+xPP/I1hwQRMRImBKCEZppypIkt5O3veN/Hz95fH1rEwmqepimjSEhllkddU690HHzYkkkGV2rXLOiUYgk5n4kaoahqHV44BIw69aWfRK1LCWLsse1IjXKwWlIZmjkgRpMTQmeQGzxkO+0FmY29+wqHj+qqiHy5ZXmld/48ve+973v+6d/OnhwHwqoZpVWkyEzAxkiGM6865q1X759+Qc/qzeMdSHFi6OZfzs6+77jmJkIGQwkD0fVzGAIAOxwBGJfkED3MWFXXgiwg8yyTmiT/YddjpiKrpSptrqjYVC0tBDYtTNVNYuDmQIXVn7btp4jUkolLAcOSqZmJAhsvrJ09QgokBe/5gwYevRXqVk8CwOmXR63/tOaRSyj+toCpJMsVlXLgoFLH77LxBsAsqoYBCsgOzNUMTEJDht2FrMvAnccZJ/A7ekbxmzqUGF1TA0F6hDO1lfynR53cHFaU+qfT1FffniD1edaRKw4iIgjv2DXF1GhbwNAVVU9Y4yIiBGhYNYAwKfcYFCF8nggW7/v5Bj8hbVDfWNPRe3ePHbALk9padoEKqoXRoWrTUTuZqWdoq8fsqZpOAZCHAwGjldX1UL7IwIreiY+ycg5U4zeBPjdjzFWVdW2bTOZIFBAGri0oYCjCYiIkUurqqYKqmVVzIBA5CZaPmFPOWcR8rqBxDgglhGLK7ox9rxdIyJkMiqq3eVPUFcuxCCtSsqqxSuQmMVUTA8emP+NX//1P/nj37/xxptvvvmWr/36VyztPaQ8MEsWzMwmTcvMhcadJQYCgPFkQkQm1qbGDKZNW0eynABlPJlQQ/VgkLPEWAM64S/3RWaRjzcL9aCdTuoQRWQ0Gm1Pt1VRWiUbxRgnk+aFz3vZuYsPfO5zf/HQA4u3f1Lf8j+ffPbMhV9/x8o3vObIa96w+PP/9fSeA09K6fKhA8NnP/OLz12Yrm9sbSxXayvN59IDcbR43bW33PfZR9bWH7/u2hsHcbA2vDg32jeYP2qwAgBkdW7HqplCRIZ6ZiaLyC4taGGjwKGKKC75OHUYBQVCZBFpUxaRdtpUVajrOlY8PzOoalSElNLGenXp/MVLly6dP3P61OnHL126cPrc2QsXzm2tbk/GG81ko5mOmSMqhhD27FmY3b+w/8De66677uixEwf2H+YD9I5H3/Q/vusdT7/muRxBBe6+dO/vv/c3B7N7xgk3roxZGgBQYPd8ChQJWDX7OkQRRCQSByxjp+QOSEQYAqG3Ce4sC1K4gtCX0aqOhdkxTcEOekNEItk5ihCYDDVLUkXkqopJtiSbGVVxRnIWGUNt8wNYnJt96NGz7/79j/zDX/zd3XffNdozvPrqa5pmur29Xdd1mw0IskFqpwzh6Xs3f/PFn5uN+ds+8JQPnNv/DVefe91NZ86O6w7oAI9sDH/hzqsNURVCGEybKYASEQgx0frm8q//2ju+8AtfuHxlA5lCCJPJJBLHGHPKDIauo4L9gRQrpudmnUyCh0rotY536dj7xNH8InZNVLk4u6KTL8qsf0KBvJEkewLyVGVnV4UdKt4AVAE7r25/6su7dTViyz/5kz/94AP3XrmyWnFAs2ytIRIktYBMhhQ+Mw8T2v6Gx8OFEUTTY7n9ps3xsy7u/8Xn4BSx4mZzctVTrjt09JCoEbGjmjvXO3QN87IMDkx9kuqCrYgQBerZqgBVVZm52xn6CJ2jj2l9ocmqud+vM7hUg6pqksxayLF9+ELEbLnbFCgi9ZhzQCAql9Eve+hvm++Wc9nvYkBi4kAch3G3H3iniKCK3YTBAEPwXUKvtrE7oxgadDr4iEiERqCSvQDpr0JfoeyaZnRvDBEDq2oPr4Vu0tt/9dnI/26bc/k+ubCwM6Cz91g9pNOrh+zTChFV9Tzn6bkvCApk18yHeGY2G2fMTHZZCDumKlBQU0Qj4myaJXsD5/i5/tP5K4cQnKCpqg4Ol+6rdN6EpoaBUc3xjbsb36ZpYoxuDpOzgEEIwdtlf/Z8wd9fVf/g5CxehMgBgWoOXNP29raZDeqhZZlKy0Sxqmqqk2RLZoQkKLnYJ0Riw6LUnRDadqqqVVVFDu7GSEhoMG2aEEI94LZ1jkoIIfj57u8XIgLiEwgS3QHtdxN1XVcccs4ppbZtuYpIeOb8ystf9YqFvbN7F5fW1tY+8MH3PvMZzzt69NrJNHEVQ6hUvbYILknhvx4HtSEDoqpwrFNKeTIWSQ7SZkBWVMBA3HbueACgCkQBCEwLdLqu62Y8qarB6sZ6jGwIdRysr0/WNperKjxw39lvfM3L/+jPf2917bF/+KtqcQmuvfbYLU9Z/+23Xfi133/6K75t8vH35WrP4oWNyeu++ychX5yO15/1koX5Pen05yZVdXpYfclf/f6Zixfal3/9K86f2b60evvzXnz1F33pm+qRNU0TORKhu7w17RRp0DSplZ0lMMdAUpxYYsWSfWeiAFLX1Wg4cBZTGO5tW1hf3Tjz6Nm11dXz58+ePn36/Pmzlx+/fP78+e2ttTZNtravNO2YI9V1jFGW9hzaf80t+/cdOnHixImrTu4/ePDo0eMHDx/at28JAIiCAdx78T4+HSEMzl9a9WHI+sZYRMeTxoZGAExVCEEAc1bVTEQMfrZRzRi9YCYVKSGbiwxx21ncAFNk9g/8ec8UIppan2D6MOKPP6ARlsffT2AIwXAgOROHuqbpdNqm7UEd987PQ4KPfPzOP/vTv7nt3z+xvHIWB3jwhqN5DKvTbWaiURSxyAhitRlz+LabLvzMMx6468rc17/vGWfHIwD7y0cOf+rynpeevHxydjxO4aPnFz98fkHAgegwaXIVouYUAk+2x5Pp5tve/vMvf8VXLa9NkIOIEMJoNELTaWoAAbuO02Olh2kAspyBCUyziovrIWHOGZyOQbzrKhEzZ+uXPtC1Niq+IfZ14RN5H6rgoFgFcygqIiIHBiUrtn99+jBEipWIQvHhtqLpS9yKEU4m0/r6m06+7Ku/7ld/6W2HjxxJKall0goK3QQg0PbrH6HVqIebVG8iICiGlWFz3er6Vz+08Gc3JZTpdHzkyKHZ+cHqlcZEq2pgOWUqwxAE4F20VaLQO61T58elqobmWm8AgCU4ozdj2TTnDGogGkIIxMYmlou/SLfU80iVmtS2bopMtCPoAQCAVnzPAQk7uLi33F1qs+DiVl11UNhHiDgcDj1mobF1s0EvFlJK2XTXwBZjjIw7ybAvrESEDMTBr4gKyGYiKgY5J4+MJe0hcicG2d176qq8knR7X+Gk0tc7+ER5AeupV90XdLh8ZGIMEQgLNaUr3DzTEwK47MAOjg4RHXRqWbKagPXyim1TiG7F8wvVlzLqP2+gqrRLtAw5mGafWffv0A8EdbZI/hndfy2GiN5wmxCioplqSsk1O/viBgAqDsAgqZWcwV0iYmHgGJETpLkbkmjKfje3JmNVPbhv//b2tqkOBiNEbNvWEdDjyWRg1hPMc9OSSy93ta2//1iFNgsiZlOdTiXGyIHdATSrqk4mk6TifDPsxuAdSQCJKKsUaSqfCkJxx+pDQIzRvaUdi+CWIDmlJCFA+Mqv+VbJeW5ukBJMxtPt7aYaDnLO07bxc7idWxPVOgYiigEIU25rGjASICbUGGovpIZhSICgyOAkWkUMjMHM/I44Dc/EkCxJioM6iw4GAwCoA002pgfmZ7iy0dzs7bd/+vWvf/07f/P//vz/+Ll7P/3YH74Tv+cH0jf+h6Pb2/qLP3H2R99y3WMPPXjnp6p6QLL/Ey/60sXhYHD+9ObZh7dPPzq99alPWW8f1dlTr/++d1574+F/+Nv3PPCJ5tA195w7/4FrT35VMx1L2Kp4zmg6aaDNUxgEI+y9vMpdVq2qajQa1KEaHMDApAqTzTweTy+eXjl16szZ02cefPSu5UuXz58/u7J8aWtjbWNjVXJLBMC5qgbzc4uHDu4/eODGw4ePHT56/OjRo8evPrl36eDCwsLSnjkHOaUWphNpRZdXpxxJdZpSWtvaEJVpboZVrapGGAgBjERIs5kl5OzxwTHGmqWrqlVEQA0VTB24B0wMBI4QyCIiCMDG4DM9clzujoG0Hxo/O+zqEh6TCXM26uQwoSvNEdGwRULGSqbNTD1Y3Ds4e2bt/e9/75/+2T/effttotM9B5YWDxzQaZu3JspMvkpUUNXAAREra3/pxY989clLv3XfybfccUMryIAGWQEe2xr+xj3HwAi1azNB0YwMIaCZzczMra9eQmp/67d+5au+6ssuLW+qETA4JzsgAfqDjB4fnDDXxXeAzn/TW/9OsImRgQBEVXLuA5qAiWTqJSd7S2lEVNN+6AgFUkruP9vRvrUj66MCIvgI0zqVlb5Zoqhd98Iu6EAGormKgza1pjJp02u/+zvvv//+D3zgPfsW96ugmYBJQDbSfHicnrIGU/JPSGuVzuW8bxwnc1tffGr2z66zNk2m2whl5OPtBxIx7AiJlOvT8XSK+EIXb51Cjbs0oLB0xtn7MeBOz1VVVYnEZ87KZYFoviF2vmtdFYE8I0XtNS3UBNQEFA0o7KQV3dneUtcBd72zmWtJG3YOU74w6GtGT8MYuA6MTM6jdVZyXdeO1uwbF6+JkNmTJREBoZl2iu47dBQnopkBMPSaR/3PaOEHIyO5nKHmDESRA3QmybuTLhmYA3q9YHPb9qKmRh1svquJzHcApFqaTu+9nGyD7pNIJCSqKio5Z2SKFHPObnhG7lHVyVhTl3HFLRYQDd0YABEZO0uAwuxS7R3i+v1udIJym0CFlMkhX56qQ6nf/U94BdMVqqoIdYwARfE1m0Xjtm1F5LHlByxLltRMp22TZmdnWs2rl69cag7EGKXT2fcgqGZt2ypCYPbJdW5ar7h116jfKQlgaAhJJKWEAMEF3iTXHIGpmU5VdTgzMxqNmMnECMCFSDkWqwzoKg9E7Ab+DsgEABBRNEACL3QUwEHvZhpCPLWhiJjPZiJi15VtPFiUU5FSMxmP27bds7g0badVVatKO5kszs8BAVcRgFWNibeN26bJDuYGAQDnzTNHA1HJHCtmjrEG0JSanMWs0JpVRSGde2jpK7/ty97/qQ995O6Pf8krvvQFX/AFl6bLzd6GMvzKO+/+sq89/OJv3Jpcefo7/+qzX/HKvQeu1337xxbjQ6fbja3Hjx1auvop9ZNfOp/S6UfW6Ekv/gI+DB/4zPvy4vZXfOOX3/XgO69Zvn3m4FNXmyvaCuQKdOyiL1WqY1UNaWcHHAKqWjtuti6uX7lyZfny6vLK5fNnz1y4cH515dLyyqX1jfXUTkeD2LYJAGdGcwtH5o886dqDBw/uP3Bg76GTBw8dOnT4wNzCwuz8bFVVbiyWFDdkc3nrysObKFkQNBCLZAUiAgUJIdb14FJzwUc7xXtUAdUQdkwPTZS4ICV3opVbsAS/mGgIzKzZSdgJgTx/AFP/+BgaQ4Ceu9HFASbeTX4lZ9Oo+Z3yp5KQimecCjObtjlt713cNxnD7/zG3/72u37n0ccfGQzjzNzCfDUn4yQpc6zAcpWEGU3RlABVwG6Yv/KuL3xgb92+/iPPfM+ZQwY+YDbAQObPKbqqEVrRyzckYkTVyHzm8Yeuv+HkL//SLz7rOU+/eGkNqA4Ivguoqiq1qaRbUSV2iHJPgvdRo386N0ExcrVU5I5n6xGUiJjZuWegO2PFvg/GXWhZNUNTQDSi3tc5e91QUouaQfYVqqLn4Ejsbnhq1nWhBoDUMXMUp2Bs0I637cjx/S9+8Uve997/Z8SlGDJDMiVLJzbBAEYKBjgJtDyA3OreRocJMsrCRFchiO6bn7eUEZGIc5vc+wAMimFvad488JvHeQCwLEaInSaBd4sezQISB1cUACIE9sFpp4uHnFJpTY0AnMjcATw5ujOpohoGNrO2bQMhIJiC+9Zbp3VIRfDfzfcwICL0mk1EisDet2mxceizkTqtMGLg4AYMpYxihk5Mp/dCRyd0MqiCluIoiwKqsYIh1MOBdcq6kbiXFPeZrar6ihc7PWo0NTIVkSSmGmPlY0kFr4JFO7S2ay9ANx9GxH6qbC7pgMjQ+yuUHA+EDnYt2QXAXJofylifiEAl5xy5ohgGITgVEnzP6qxlk8jRi3AAwsIARgwM4uyjshtAAkYGgB5vXFaqzESUcutT9Nw2dV0Dl9KHmVPTlkDWi5/5gicGmTbT1Pq/F2kzwoiRiH71Mz9XfqnT5XSrVrtfAwef2xiAmULZ/4DuWofvCmgAvbadU5yt+96u6rP8T39RBACf1hB0QAB/NIo5iHUPSxdJO+hYKbj7f+8qXK+etA+8iFgeOegnsdj93P+fNcf62iqYxRgNrKpqVfVnkoiqKuKuuOYJv8hQd7ah5SPCzl8Av54KIfDCa2R6ceVic+kPt26n/YP6eHRkzJ9cORW3oBqcr54Hf7BqeJU/E1ZdFwPTOTnzyWkd2mE73RJls7U9dr9ahlnIud04tvrIqT+fWflAkkzMRfeii68p59S2/cX3/9m2bU6+jk9lR7gHeC/7NGIUuKrjKAyrWMWqCpEaHp/Cx07jYwCftDWzVQ8XO3fSb4SfDlcS1SLz0M+fujUXYo0zzNEIU0qNgAFkgFaBiNkyKZWBnIhlf9JrlYygRshIIAWYGmMNKE6YkX6spZZzRgIIQBRhl8WNxyjvTgjRMfCimlR8BmNm4P4EVhT6Ukqz9agaVB/7t0+99a1v/dy9Dw7nFg4fOol5TErN+hYFApaU23owk8SQMhhpthDiN179+Juf+8jDGzPf9i8vfnyyQAwmqtDaE0agxc/AeSVmxgQxxK0r2yvbK6989cve/KafnlvYc/HCehyOGs2mRhSqqhKxECrPrG1KnYe5E3MUDMiAAafTieuuW4F2ExlIFjEBwoCFVOK6oUTkTUuneQC9tkH3TzRVZ0iCqJq47Tshq5j0oBZm6hJ28WOFvskrYtTdVj77HlpMiWJgzjlvrOtTnn7ToSMnp5ONWM0lA0ZDMgDVCXj0AadEodogAwBkBDMbG4oNY33jtdfllETA2kxEAmZG4CtWROgAJdAp0VInOVLWSUCdixQHtJSSo5/MrB5UWSRJAvcUMciiZhm5HB4kMrM2J3+UfAPd1XxFViGEgC5XjI5VEPPe2pzZy94IglrArH5enc7l4F5VdbGV3AkA9WlV2+RWqQFQ/AFlAu+sVQrOy4onNhqYCQERk7N0QU3EejEBhwsZYYyRidDAyxAFdNEfFx5SVTQCMbIdWHJSAQdXm5m5VRywQRZpNXl8RkQ2YDUC04DKhFZA4WqqptgVRJVbO3SaDJbdiS8oeWsIWSRJLsE/C1sAg4RgoOjrGAV3h2mahgLXda0iqKhmFbNIYkTo6BPgfnmIudM6V6c/dRv+Ms8BBDVFFS3lDnctuxB1lCcwM2q0DpFiKFMU1RijAVy1eM3//pI/2Wq3XHjLVDULIq1srQWkmdGwnTaRQ6hiyuIHIyAhQCva5uS3yWMiB1YtkFSf2ABAdhNGUFUtNn8AqpZNLYkBcghFG0uBAebn55AIRDEQEaoAI0L3GPu9hi5KihbRFehwjP1CAVzjxWs1wKqu2dN4oN2DE9/wEBKWYwxoOL+wgGq5TW0zEQAzzand3Fh9z//7uwfvu/uqq06Y5D1Le6+78aalvQe4HszNL83OzgUOo+GwmgVESllzUlOeTqcpSc4ZEg8XZ0TykFf/8f0/vLgkzWT2/rumpx9Ye/zU+PDxg8Nq4Yu/6GW/9bu/P1jcvPrYwtOef932lUvnVx4lW6jD8Qubj7AtnD61dvnMII0rps0f/O/fIwQPPfzYtceeetvj/7gU9nzXq9/w8EOX1jfWVy5fPHf29IUL5y8un9u4eGHt0trm1mafgOMgqqYQw749B4aj4b6lIwcPHj5w4MDRo0f37z+47+CBmdn50WjkUkam0DSpSdmvmIgEKvM66FGNTIhEnj2ozEhCCITkMFbEothjZkA4U8+dWDzp5K8QqKoJEYggBEIDC7zjJ4qoBNlyTk0dKz+fXVWlIZBZMmAwCRzZdeUAM1oc1IHQzFLTeoEOokxExALmgN4MQLESAiAKEJRyrSg6SJUM2kYFNQLWoyptTM+vnn/P3/3Rb777zjQ+cuSIKqXxOkRCVAlgBAxhUEcehGa6DUKIOhzK/3jOva+69uLvPXD0v91+s1BtACJGQAGqDJlMAJEAk5FhAtIMSVMeDgbatmcff/jWW07+yI+9+au+5ss2x/nyxpYRynTKwEYA5CR4n5Z7p8TRB8OMgVjMRFqx7NwQ7a6mgAGImhpCRZxzNtPA7NYCOQsABCQrnBFy/Wif82nx2/YRoNu7EUJomzZnAcRqOEDT1DbMXMXQtg0jG0DcpZZsngVEmVlFERFUM4N7s6iqioHWBu1Tn/rUm2588qc+9eFR7Q4E1KCi8uAzs80WyyICgA2zXrMNANgQTjjcPx8TNe3WvuNz1z/9+pwiawI0RdUERJ5xUU3dtRYck2TGXQ1ORMTBp6QZBBAAQQAwsHRiGK0KIBBEVRVAZo7k6B/zOCYpkUEMpKbTybjmATNny56IAoRuwszKwGLZB6OA4iL8BlmL1o2RhWwKWXmXKqSqKhiIElHA4ohgnQAedL4ZwOTUESgE7bIk7jhl4CzPwNyb6QI4ehmHcajON1N1vB8DmqqalokSU8Qyyy01V7e68M/pU1MwjBwUjIKLDrP/CQQqyw9y3WjfsAMgFaKLGRMJaK+A4SCyoiy+6+/2GyYAqEIZ+bZtm/I0hMAxALCYgBaVPv8c2mqR0CqLaQam5ObPgcu6RbFNyVWUseg/g7NusGPBYudkINnMrKpiYCo2iE4b67uOupQy3otoN5FDsEOzx/yapJSkTaYaQlgKGyml2cEgjJxl1GY2ABDNAWkwGASOk7ZpUhtCqGMVY+0ltttGmZmB5pzBMFtBkEE3xgJRgTJNAHIbTfRpT1Ac1sM4ihjY1+/FENPPXZeD+4a1xGlkLDCQ8qUuONchBnqhUwplXOFvMufsSB80ICKRDpLGiLXxiBty1WJbvH7uC5/2FePt9WZ7e7y1/f0/+Lp3/9Lvv/hFX/DMZzz7T//0z4+dPHHw8AEK4cCBI4cOHTh06MDCwsLs7OyRI8diGMwuzs/sHdz5sQ/PxKC0cPn+41vDtW9/1f+U9W9/0fNv+vIX/dnWZOuBz9z1jp/72SMYH7kzn7995bq93/CSr3zFL//Cjxutfvrjn+Cm3rOvueqapZtuPXjiqv1rV5r3vfuvpMWmSfeHz73wJc+5/84H/+t/+PHl1eVLF05vbixrbup6OL9ndnHxyDOufc6B/Yf7K3Pw8PEjR44ePHhwad/S4uLicHFmcX6BiMho0jaImLIvmtSyqdgcAY+i06yT5LDbPanLqZ5ivW52IGQPHlQoCrvU7YMQUZO3oeUBAAN1lXcikCxg2DcoBoroZwA7EGk39yt7sXIGaCfamJlK98R1ay/ufMQpMAPmnFNy75BABsphmm0umE4aHNSJdY6qlckla+OV97137Q9+a0V1Zv5AY0jNtgVD0ewKa668L6INkBEyXzu39VsvuvvYzPQNH7nlrx8/YoYASS0NBwORjAErCikpI7XThusqqdahBoAw4OXLZ2bn4o/86Pd957d/1/6DC5cvbyWV4XDYNmkymdShVgQX7SjzeSZSVzgiICBERTAynzsW7oWIC4sWkggYIWa/zR16lLkAy4v9QAG+dQbzu1S7S6Pc6QXVVZVFcs44bZi5pgAGMm0BwG0gds+WygADduidnVBUEpGZmbmmmRikyaSd37fnliff+KF/ee+e+T2holYA1ACF2jD8syObP/kgJKT1CqLiNNBGBYpzf3YCDTTLvn375ufnjRAD+66q9zB263dMCNTNFM058ghEgoBMCiBmHn362ZhHXehWkF2v6whwA4RQV+ozMUJVQzFjQKKk0koLjlbpuC1EhICKBlhgQNxNCDR3NsySyce8ItJb1nsIY2Lqzjnu8mBq27YOEXwfI4JcbhUWc1bPOLt4uj7k7fYQPfrLed4FfiXIzEbEiNwlwl6hsJ8kJBUiQgrcP4EgAODtpjfrSuq4nlbyMETFEiz8WoJXR26b1UV5v/q9bw/0DF2nJAIyEDujCXa4ZQTIITBz+aDdvSQDJasHlWk5vl6yNHkS6qqHTfmtFQDqsEV+F3bGDKq9Nqm/Vf/3IoTWA+79yibXuOds6mS43LaICEyBgy/picjMeVYAAM1k6tIZo0GtWaqqqqpqPJlyFZF0c219c7MZDEYYuK4iAlmWRid1XQPANLX+0WIVYozaipcAO0e5GzwAo2ueBuCAIIAJNBg5fptiiHVFMYCK5oKMMDMfJrv8IXbTQneNKlWRmuPdiDmbEw3R98pm1k6nfn0cHx45KIKqRop+bdziFAkFzNBiNkVUsZWVNQohVLMyCot7D/3Jn//9H7z7D44fPvKi57/g9KkL//aRD58/f7ZpmtFodro9reKQKIzHWzPzoyzTffuW9swc/NSnPzYazYUQnv705336jgf/6S/e0LT8zd/6nL85+8epXWu3m4OH9t1258rSwSOi6bf+z9tvuGbpt37vt/ftP/ToQ//62GOnttP5jc0Hua0vLm+eOVvTYLixdTnWsLV58c//5M+n2/nktftPHjvwzFuvv+bqk1dfdf3Cwp650fFqP+7fd3A4mN0pTZSmk7ZN05xbIxtvNzmtgZqbZIcQQqgoBo6sYuozgrJWFyqjPOjCkeu7+XKiiOL55RVTMwvEAgrq82j0+Ye5ioAVAbuerVtietYSoHsHCVEEF/3dEQDo15Md8KdslLQbpWYRLHFyV5RRxUEsfmIA2VREQLIBwESRhg0lipUJxKV45o57qn+9bf3JV69/8qOLPE31gohAkBSAUzQsDDRHBZCb/xm84tpzb3vug6e26q/8h2c8tDVHBMyhqqqkqZ8JuX+sgQ0HM0nbYV2jwdb6xtralS/+khf/2E+88RnPvHlleXxpeaOPq2S4MDvXtm2/WfF04pnMsTjuS1Qs1YpIvgGAdbsz6PgUTsDzR6DbJBY8lK/DsKtcfXOZXSCiy/q77Whtl7lQzhm8j8TOrdMxVo4TKhAwl3AvxTSVo2XMPJlsM0ekVHGdWrjhxquXlg5OJtthMOM334wAtP6b/Vs//AhsAl2uyp5qO8z+n2voM7PCSZrpgb37qqqajKeGRIWEEsjUwGWKzQwsF/eBlHNRIzHHbGegQETkEAX0nVuhZiiUYXUHM98Ja7u83WpvsnzxRAhmxUjeg7a3TwGDgBJ0I1WkrlYAIgCV1sfA3jH0N6+/8QRuxhds1xd2EhBQ8E07jkC9Lhd0fLLSZXesmLJnBShTVSOi4CmsvPtd9VdfSuAulpTfUX+rFNh9h4DMOfvO2epPQAxRy2zDGyJXqjJvE6kjN3MnT+9SGL6WLi1UJyEGJaMUVy4iilUN7qjcna3yJkXBjANjwJxEVQOSoKmqU4am02lKaTgcOvSpWEg+kdQLAMxccegdav07QNiktgqxvyBdIWLmuw99gqEYYM9cLdc/Etd1LTk3zVSVFubnNWV3v84q1ajOIggwOztbVVWM9aRt2rZ1R+nxeDKZTHowc4isSuvr6/6QM2FZuxSWAlLRPiVEjEAebRmVkEXEL2vO2VIKoapCdHKXIXmjXBCqouLLoI5MZZJL8SRKnbd0CAGZrXANHbmjvQ+xGyg1Ofmxge5PUwfjRAciIKuoTBIZjdfGgwq/9/v/87iZnj179kff8rPfcN+9jz360MMPPPjvn/jIzExtxuPt6eFjRwlDPRw0TXPPQw9ddd1TOK63m/HuB27fc3D/eHt9jui9//gX0+0cY20GC/sWEq3v2bfnNd/6xl/7X7+wZ/91w2q0cmYF45P/8M/+7tzdt28nm2YOZsG2DhxceMrTbxCsHnv4zA1PGrzu9T/6wCOf/aqvedl0Yoyjtm0ppO3JGmq9sTVZ35zCrq/JZBsRYxUYsAojAmLyUUpxZTCznHeYAo6XAAAGzB3Gx6OrP9A7XYKv9a1jUXhha2AA7velXccqxRxGyyt3HAdmdl4hEQCiYzIAICD2eM9esDqlFMuyzLMr9D7c3eHu8M/UaY+3Sa1o7xihbyvNrGUaaZJ2ilJtzw6qRx5f//Xfm7/p0NK1L1hL201sRxuTYT2HW5OKqjZPOFQEoilLsUMLNcFbn/vIt9904c8f2v+jH7+usQoBJGWuKISQk6q29WAIotmwirVp1iQBK20nFy6efu7znv6d3/lTX/M1L51kvXBpk5DNNSAUpMmhrtu2tW5BBk8k0YKz+TtoIXaR0FxHoRM2KI+GKnEQyeWaY+lzAcAfrK4TKL9uKh4grAvm2u31+5EndvtU6Pa+vWONETpOXcFUtNsJuoiCeuByXmKMESBU0aYT2d5uvvVbX/XQA2ff+c5fnR8MEZERVQXUdNb0yHT089fxuQEsCl8a1J/eiy0bgiJIykuLCwyYJIdQOSSNwXoUkUPHCzMasWUIxVahMJAYzCFm3pgCgJKDaQTAPG2bmfvwlfNutisVFHFpAJ/CFvi9ZZE2cYUhRjU1E+uQKyklN6FFX9Zo0dlFtZBSKi1Fl438cdJdYiJ9XgwhSJsEzFfuO7fcjDomch8F+mTg0y2xMlbyl3ITAjd3o268/HmpaPef6F+5ixkFheIDInCjCIOcMyAMYiWe+MGgQLuFAAOSMLnSWL/thm5Rj443Uf8soN357osP6sXG0OHcuPN+PD0gBkIRMS2wulKOMAUDMrAsuWk1ROgAzH1o669z/9lV1Re+paryJ7JNjh/IZuU2kGPWyKuywMx1TUSCKiL+84GLv7oBWECITIht29Z1TVlSSsBkIhi4DhFC8R5AIKbAhGa2WEdvNIlobmZkZg5s0Y5bXOCavTIRIpmxESEpggAwQgU8RSOm0DHQsqik7NdGwWyX97uVIQcXjVozF4MsF83ARBFNJJsJc5RyT4OZIUbPzSkl5zthDEWT0MHtxACQkyaQGGOWHDkwo6YcAyVVSfVjj6/EulpYOppzfuozv+DFL/7ynNN47eJkMtnY2PjUpz711//3L8+ePb19bmswqJ/1wmffc8dDYYBjOjcazaT21HAUMlabkzUcDaY4Tu3kusOHDu178gfe/7F/HP1JPTf3oY+896lPeR7Nx7i1Ftr1TR3P82Q2DAdh7vylrWxz1934lOc+9yWf+ui///Lb/9t11161uOe6P3jX773sq79++cpp5IA0O7uImNV39P0XMw6G86rQNokwiCTmCggV1QIQsiIkyQOKu88edpgrF6Xvzvwu2roBdBv6EBgRsxqIdsJ6XaHcg31UVJw7lM2sR1wSldGXOzC5rj0TZREmAupdwLsJs/Sfy9ECZbfnDl3WNb7U7XEEjHyv3xkyeo07wLqBjQghWMxKyx+7bfDw/fz8q9fuv2gbk1msj1T2kVYWh1HHgDF4NMg5V1UgxKP11ju/9KHrFidv/Ldr//CBA27b5p1CznmyPRYmDrUIIkQiMMPhcAYHunL+dIjylrf+9Ld966sGo8GV1a0maawHLmUjItVwIG1yA9DdebcPOB7BA5IDOhF81+vXJFpOPvB0ahaq+dbNg7n7mvcQdOy0d6xDtFUcjBi9DXTxV799nccAdSsAIwQfojo0MWsxKCQqSn6E3sOUrgnRUDuCJVShmk7bEDqtCKBzFy7feednXLavrC9UDTE/cxMY6n/dGx6ZKYUFuTSmsalIWlhYIMLOYA3LNIsc11PqclUt+dwxpbsknkAVlPoe3cwUi7egI4L671uHO+n0nE1hVx7GYG7jVLrwYr0KUAbvBR/atUlgvi4oOc49YIKZqYiqVhzMTDoneQHph6IMBUhMRBRjSklAGRhpZ+TdN2R9WgK3ESya0GhSqgif42NhxCc3NXOCTVZxF53d1RZ2JZuIYDdSFxF18gyq+UxbzSs4cqhXt3cyw96VQU29uNPOvAJ7sKKBj+OsKynKgx1DObkAAObQLTCgXeq7ffkJAA6ntiLyZy7aFZitU7EIIUynUyi6MEX+uifI+5eIiAozByqmImZGgMRB2oREzMyAZSq46wtt5/24Hm7/zphZEXLObc4+dnHBZDbHxEtPOfODht1CDhEjcT2ovEll92xXHQwGOhhOxtOUks/oXA/b1wcKSNrtlQitHGGqIjka0B+VumZNOaeG60okO53REE3VpUBp59oqAe0+FWYWmZVLXgVVRhTRpmmIaDAYDQYDSa3PV1TNOVqMkFKiUJlZVVVZk5d3WcXIlFUDKlFluncwlJxB2wC6uXZ5bc0oIIcRz45mBgtf861PuuX5L3jokbtn5uPq6uXB3PDE82+bwBrik5eGB2KYcn00hcGiEuGwbXTvgXDXx87AFhy47+FP3XYHJ7n6Va+cmeWNjXN33vnoiRMnbrrp0GZKp9fPbmzfd9UN+8ZXmk/e9g8ffM/ftA3O7wm/8Stvv/Upz7rx5meN1y9/wXOffnl1KwOub0wENCBJbvrTmFKOkatQcUUxRn9McpacxczNwYm99JSi9NNPejzKgD+mZruVZb39ol2iQog7nFQ/dn3MQiY1AzY0QzUwEC0ubAUj4lAvQ8SCPgUmBXAfce0EXzsCAnbt7y6wj3g1H1z+EDtKPZo5rY8Qs2rTNIbASKMYrR5By+OBjO//rH34Qzxehi3Ye+uTL199aPxvn7tRImobUs5VTMqo7p2FAPTS48tvf9GDy5P4VX/35M8tz3JAhyAoGHMEwFYa5IHlXAXmgI4429pc3riyeuuTTv7sm3/m1qfcvLm5ubE5qQbDEJQINBsQhhCm03YwGFhuTcssjXEnxfZFkvVKQf1OsDAPyLMc9EzojkgJALvQyOrPpphQB5vq7eOIUbJC1x0Z7VJ1eGLv6yGVYiAF6BSKUASYGCJi8ZP1xOzOxB4WJ5NJVQ0ADCAgGoKZhu3JdnCFJS04PjRrn72Gy7F6eMCmiCiAZIQIbMqAqrqwsIBum9umEMjn0CFUIGomiLsaEpEKg5moCRJhKFQ3M4NUKjuXQ/Zoj4jFKnHXlSdAQxYRIKTO0x072Hn5Qylrl4YFzLd+4CQ04hAq7ugiHLh0pF7LVlWlVHQtRATVHAHnPDkiAlFRsZwphuClb0/MMCOfaQDmJ0BkAByNBYzd/IqIfGisqmoCyGgasFR1JpolS07DwUypAUWlo79Q57+oWrB8fQjw0wBgkoXRpxzQ+frl0sIymbe0WrbiHpTNrMxUJXsTUUBM/mcJVXXSTL2I3sW9Iyyyq5pNzdBnEX2tGmOk7n9ShwxSAFMNMWBg9wkIRR5PJpMJFbt4bNtERBUHCaWess6BrjwrMQCTZ0rrVmAV8g4hUk1Mc84uDloPBv3lYoAMgAaRYxW4DtHMmmlLBrGuU851iKZaygc1DsxYNkO9V52ZDQYD7ZAdNij/FQAioxEWdTBRIFJEclt2V50lqpkd65banB2ojEDMWZIk8TPkgR8R2ZN42bvvyOD1RR52FlKoQISaBQvMxEzUpX+sEM0pt0kkBaTA7Gx4EbE6pJTrWJkouMFUBsuqzG3ObgiKSHOzi01ugJBaQ9QAsH358vGlQzccv3Z1bQuuomh466EvzmnCwBDi2mRDdStmk3gF7UJVjds8fPeHPv7wXY895eanLdf3P+VFNzfbW//6qX/4p//3dzecOD4zC9vr9oYf/OZ/fv+/jScvvPex269+8bFnPO0lPp2641Ofu/jgpeUrp8+cX/vxn/jZA/uPHjx49fW3Hnj2c583isNub7jzNZ2kqgYAhSyM0czMoQbMqkqKHh0cMd6nWI9cHT0PGbCHTxoCGKoqd3My7ebIZcTc1aiFEJn7vpWIGREYECRnsEgRCANxWUh5x6YW4xNSe9cla00V7JIZ6e++Vw9e8/kszetCRSrcwxC4qE8IAWzzeGFrsLJ1cfv+26d//jdzZ+8fwySfPZ8IdWEPSj4ZZS600zxneZMDWDYGZIb/9syHvufWC3/7yNIPfeTazZaJCF3lAgxVjYo4lLaTKsSACAJb62sbm6tXnTjy/T/2fa9+9TcMBoOVKxuBIwQaT1OsQ5smwzCcTCZxMKyHg+3xeDQYmqVS0yCygWMXDJSIyUmynRp8CTVqBMQxqJZS3J8ztxjPKSOit2I796sUPN2IHjqvdyDoh5q8cyMAwNt0j5beKogKJPm8CShkH3QUNC6RayqwSIsGSBRjLSIiKYQqSzs3Nzx/buXcuXMhhCQZlL1cN7P0nPXwyTmVbMiEwY+fyx8iGgVeWJzzE2U9BcbbNgRG17TvFlWEDOyIHDVTEacvIiKVJhWLokgWz6ymamo9+6IETyDXX1LNqm51795xpYjt5xZUmOrU75UBkGPgbpvQN8peZYZyoc1yzqaKRBWzUZFkMrPQPXLZtGkaF6Yog1/fWID7+ILPcPsyDTkgYuiYwX2VHQgjV40U8A6WuZJyoFiN2mlpTFUVuibMD5An1/5wlGNB5DMuVTEinwwX0a/AERAQxY21waiofpWlFHQgTwdbWqeK5dAtQjIBx4ihy3sSIpGVGQIiYkSH9pCb7BhoIN+aQwgF/iMikH2aBEmye7UCQBJxXJUj4Nq29Q/oN96lcFwOhXBnxyOm4KKsTGSAav6R+lEwmBXEuKt0ERKR5AwupeJzZSIwdQpHDKFpGmdxSM5kwI677kB5YhlEAQkJVSHllFQilcRGyHVdV1VlZsRIMbQpbU8n5O1LYDQIhoQEjIJQgRkgE2NEkyymCsZMjIRAYt7KKhEgkpogBNg1BenPki8CRCQgMWAMgZmbppEso6oOIZhpO5kSQRVjNQwOQsEYfPIxTS1yCCFgq6zIACJmxACYAQSBARQhg0IkQBVpgi+0B6SqplDxjKqub29N8vZkMhnLeH64F2NYnyw341RJtWe+SimNp7a+ubKRP/7gfdPnPf/IV7xs69KlC8PzNz/z+c/VNP83f/Qn199w7Ve/rr3/c/e95Ycu3X7b+48ePqSTmZtuvnZhe9+f/cYfnb947sabDnzPDx1qxxvN+JrV1ZXl1dUL5z87Wb945oHD15+YgUOHEOpBtdDnp8AzORkCq+Zs2kapQzTkDFAFZgyOFQgBVXYJxnVp2Le5pipmvkNlZkMgMRFx9Ywe3O9EPlXrlem8iDcTiKXoR8cCeHMmKpZKNejSA93sOqfUl9TYNXlmlqYpIu8eIfrPcCh5oj+o3XHVEINlzEkMtaoqNmiaBpivbF+59Ce/u/DxT4zSZCs2IbV2+nOrd/373M1Pnrx/z4G08szN9Y8MB/PEY4VIcrDe/u0vfeAp+8Y//tGr3nXPQTEBVlLLOQsIBcYOUoCIdYSZYdxYWd1cW73hxmve9N/e+OVf8UX7l/Ysr463tyd1XWdFpgDIKU1DCG3T+GfMOccYp23DSJaz82eclMjM7qWNzuwMzFRK/2lqzXAwGAAhgKfVoqbo00SvknNH+eqWSsiGfadkvSoTMnLwZoI7K3u/vFkFCQMFaZO0CVkRIISgJp7tuBf3VZMdhlnxFEpNDoGY2U1hQwgqZGaA8P73fejSpQsHDi2kVhHRee0whPy0rZn/cbUEZCRDEp9voonPH9GqujaDwA5w1pQzonAYECKo7FSTCAiQQJm95jbfeZEBE2UquKJg3D8FTGRAqpnM3O+u64xZLVnBHzAAojpssNwd6+zDzUwNOQYTsEAsZMXYEL1U1Y7e4h5WQaatN09uU1NCm/ibRuuWr4IAiEqUswYkss78oYrOXzK1GKvUtGaWkgxiQF/kOM6oH6QgqFFKCQODgUFBNolBISlXoZTVZUomFQdEalVcmy2EIIwAECkGQA2Yc5Zc+rM+PYdYAULyqUk3KJDOuhhEo98Ss8BshGRWNKtEzNTndYhYU5Bp620BmTFAMlPGULoDRVVCBCTPSUWbDSGXsb/59YlAmhMDDAYDh4a1OYkBItezs2iqKft6xndgNVQMaAKxqia59fxtWS2LYfZN2yBWPtZmDIjGzKgGndoAGUQgC8HEa2EoWGV0mgOZqLrSfV0BAIKGECIU5dFi/2cGWKmqH5KKA3DozzcRBpe86XTdUK3CEOqZNmQRoVxUBn3rw2rAqGyZDJlxKhUwMJmYd1fEQVUZ2Rc8ZlaY4pIRg9f+/v0QQoxR2qTlq8VQc8UYaoisbc7TFqoQKVgWGlRg6v1fDANXuzTJqW3DcKiIhuL7alWBrGRGgCISmKVtfXfeIpCSQwNiXQGT5lxTNYjVJNT1mCxPEXlhtGTDgmNhsoN7ji/uefrW5suff+vStF3d2Fwhok9++o7xhfb6G66FaviX//f/3Xvvk2ZGCz/9ppfefc99mxcGew9UgeYo0oH9h06cPHjfXY89/Ohnplv3zi/M4pCOL/G1t6rBlGG6vX5ubXMf6dO26qrPQDPzBwfxOoU5g8iMczyc2jaSgDJAQCSzpsaENDNNLRFlSISBqTJrIDMACeTAmJNGqqTNxhpjSJIjESFlUQsUYkxNZgUDYUQIVDo2LN4v2qQyLuJOk847D0QAdBKUgGFwCX5gjNqR3bvWAYgCDE0NLRuq1vVQtVE1jkwK6ivnGETV3HA654HRBGwwRAwVNNC0W8AhzNWA4cLf/VX84IdlMAUxbIwjrD3+4Ik2rDz7uZP9J/eevvKsAB+2JDoE3nrJsSv/+wsf3kr0sr+78bblWY5IObBhS9OKw56ZeUDcbqfMCJaHodpe3zx34cyxY4d/+Id+5Ju+5Ztn5+uV5e1T51cJmWLIAAqiORNRHSsxNSZJGR0nyBFC0XBgAhFJOScVKo2tP4YJjRwzKyIBIwEjYk5TIuIQNBfIMSCJWWO53xrs9C3MioE6YLlZLhsuKlBQBmxFiP4/tv483LbtqgtFf6213seYcxW7OvuUOTmpE07gJCEhBSQkGAyFFAooUUQFLvDgGr0q3/X54IqgiHoFr6gooj7EJ09BEQllqIKEBEhCKpKQOqcu9j5nF2uvteaco/fW2v2j9T7m3Fz39xHO2WfvucYco49W/grOOSdiMHkD2WAYGjsDAKkaUykRl1xyomGotRKJbwoRWehGAYOwsLC5JYWRV3ZaA3S8OX3Lr/66SBFVMw03eFPUl6yw8PyOvWwEOIkLta0CCVXHvBYp5JITuSaDT2rTxokoiUNjA8JtSewW0nhEkoexg16Te1UXkYDXA3CYOQdIIsrGREwsKu1tDhf3LIGQDiVUuDslFmGde2sis0oMMq+k3tmWOSjIwpIYTuQQ4rRFyu3yL4Wd4H3h6u6BXEzCknmz2ZSupaxTIaJhGJy8TmW1WsX8PaVFhIPJmu4E+kaZmTPYHHNx57NzZ9OggHfpFgBhw5fHwd2iBg9dJSGJfcOQBiEJIREmbjbRtXGX551x9Khx4Ig67UdYVa2YSJPKRF+ltKsN4H7bLjc4GM+DMrg5RDizmNk0TdjZDc9lJvqyZLPZxCcEi1rVWKQxzYhAnodcphpD6YODA1utzGwYhlprYpn6+N2qIqeT9SqzlFJKOeXcTZo7cbmN06dNy6OBsgleSSeTtGDXtoMeu393D4W57eiirWLbeiTqjLZiAouDdrYmDih8QApqejxEhTuchREgA7CwcM7SG6BQMI7cT6Hm1xpfJBbtM8gZDRAfyzmNLLXW9Xo9y5iTg1LiEc6k7lUrT2DmTsJCEyGfCmeeaiEiApl6lNWcMplPOiEWB0xqmiXVUmqXJS+bKeaiSp6Ix8UC/cAQN/ZLDDZKXZP4uVsG1c1mZVYWe4f7X/j6L12OuHr9+Bu++ZvKZvPIpx746Ic++PD9j156/KmHP3by3vc98dKXfq5zec/73v7qV3/h3/mnr/7oQz+0PLj9+FiI7PRGRV0AWC4vn5xevfTIF50ePwk+M5+3c7du9g8eW+6XWy4+LfHh9c3ehduetUjngclwtdZ9Ei6Wa1UWrsaoPOyl05NVSsllI5YIqU4rFjP1lAfVul6fGqfMgTuCmpZSBCCGz3xKcw81PuZWDbtzR2JyjEP6qi/eCMwOPFHL7vDv58zBJEGrkyS1rr1WDVSqMIXSELWzF8O9lRaxvDm9WsfloR5UZnFfLg4/+hu/vv8rP0d7q+vr4/1JMRyeVl9ef+z08ccuft4Lbtxx8b9/UH5x/xBJUK9/90sf/asvfviX7z/7prc978lTZJbk4uyQRAWmlGRg5tVqtVmd1rI5LvV5n/Gcb/2Kb/6ar/mqO+66eP366cOPXkuSJQ8hfxWthse7lmlIudZKIl1kLXZSzCybmAkPuc3du1IVO6nqVBu2ObEQBaiSyahONZQbiMihQh72ZfNodDtdCMQW4GwMNkL0cfHepfB8VC2lcHPYbeseZyIWaowjC00FIiql+FRSSika8SCIb0Mfu3s1A4OcIbBCh+cWH/7QJz/20Q8sFsvNujqHqAGnlKZXPUlHIn+4X0VEsgMcdApnQlOUvHbtqL3mDf7HJE3goe7AeJk5EZMZNUp6LwSZmBrBnHcwtvG/zYO1o/8jkILA6O5DQCkFWiFtNhw/a4uEdMBjno45i3V6AMSJFWpqTCQdtRUmNjNYLm5xgNPUTEDRxtVaPfX69OZcZaYOj8GpldpMMHLuIHYCYKrcxBnZXRtyakcWnN2dQMRGsCah6iCKaYCIGDWhRFerwYjLyX3H4rdU7ziyeUJFfZmBDskGg7tZYUzanck8VMMUwpwkjmnRmjh5G/G03arBKzVtz0Bjlq7/MrnCbkKD94fSXqRYAKxWKyKqpjJyrSYiaZB6uoFWIh/HsZgeHx+nlKpbIolNTGYxUDTK5jrk0d1FsoJK2fgOl4yIoCBhLTWgFk1GNnBh3eaTFETNAZqCU0KNGxe7qDkORoDz1p20Y9YDJ5i4aaE7BZaNm4qCc0dUVlNVW7Bw5OO42kB7wNM4lFJoC3c3dwez1YYSmre5RM0xKa6qujlTWNlG+BZzJEnjIKDqYcLBVurmdJXGYb6TeSFm1gARqsGIk4CTMriTVBnCZomDTS9hsmRmXo2I1EppWrvZLFywOM8kequbWpiyqpvhlosXmEN+0Y9PNovF4s7Fcxbp7Otf+2WifHy8Oj596skrn7rtlnve8pZf+h+/9ZsXbz3z1re+5ZZ79u951vMOF5u7bue4yOP1kZa8WiH52dvvemjv4m8eX3nJfNIuf/RrVk8cafrER8v9L7nvS/LiqQc+/Vi2e87t3Xr2wuGZswvVnIQqjqfCJ+unJC9JHanUyUeROtiQM0o1VHguRYbFAFV4NSELBwJvJEs3iwaXQyC4cwfMXfqNtaqI9VuEC++FGlOIQsRlC9pj3QmIzRUgL0Zyq9MGAEuCeuyVW9B0JGoiuO7O5HUP5zZnS6H1crW0wXl88PfeNfzov78x3S+yHE+WRNfs2lPr5eEtvKA3/9xbfvwnfubBJx7df9p1Ts8fy794w0c/5/br3/t7z/hn77/TGUkoEUEtDcPaleHnz59V2zz86EOlTM9//vNf9+rP+6I//obP+pzPPn9+cXRUHn3iqogwSSw9yKuAHeSEqE7IPDATkMYdUDgcxdXMkMPJu0mNzvVKHPhQATSNabMW0MBEzEGcr6WICIxI2Nx2o1Db68EbwqfddP4j7YIHDTzm1eYEaIdDUsfioIPPKYACwavRABI3ek9Iy7e3gMi8khkaJDvv7eX3v+fD165fvuXcWVVNnMwlMDbllUfpXQfsXOuagiBDIgSHu1ZnKpvp0YcfiY1SfDzMGVxszruNWepVJ68BgI3hPIRJGv/c4BB2opbKmhB9h0b3gG9WnYmTOIQAzIfWLPDSc9ihHTZB/Ml2tnf2O2jQOYY08FMK5EL85UD8+uw86FBrA+thGDILM9eO2o22KdJJMY1AltOgql4157zZbKZpoh1De+5aNgZvd4GMep9khJD2px0a3LaCAJMk2DRfbWwsAsIdl7FLO55tQOYCEEAsqOJqwSQQIoKapKTozhBwMkM4WUf+CKpoN3KIYSw1nAj66Nu9VmZmadhj9LKmHXViEQmX+DZUEBmZvarWalklLSI3sGMYBiOsVquzwyCdN+Z9iGdmLGRVwyJisVgw10HSkId4drNTBzOjVmkg8ObGIi1ruqqSOxNnSW3gbzAyuLeBmFME0/b+OzW2iTWeLm3XSeg3mTgJmMQgfXoRR5tmHgsxMeZmF30TP0Q8DVBD6uVXAOl5S6UAQMKz6E9wsbIMQuxVp1Amc1c3CvHmnNggKdVaBRRS4ZUbdH876mDebDabWhZ5GIbBu0SaqjKnWnX2h3CPZiDoE80GQ2NVFVFTISKSmWgUnWqhcRhhE6AscKfluH92cfbktLicFp0+9cDjzInTam/vwl3nXrY+5j/79d/+p9/4DZefePgdv/3O7//u737iicvPfs5nnL1lfcfTT579vL3bb5c7nr6+5Va96+kHe+PjOj376t575ptz/eqHL9ymj33yM06OLtz/6bdP9Zlnbr908Vn/+dGrT/uDjz3D0+LOpz9zf3n72bO3nTncv+XwdrP1Zl0Sn81naFOuEaSUTZJlnLTlko9uPJVSSrIPh8agYN50zBS+/p7G/dQ2O+1TFkKzUIWniMtMc9kd8c40nhdx2AAAsWk2eN3UlHhYLEspBCYydw0DxkjVcTZqWzYlmkqVg8KaqW4O967d/+Dxj/3Y2csfob2ln55Q0RX7mQG5XP10Gd784T/4bRxsnnZPOjn6gtue+JHXfbQ6f83Pf9ZvP3rAOU3TmomsSW75wLzYH69euVR188Vf8vpv/MZvvO++zzzY21PFtRvHDz54mVLOaQDAwlFxduvrfmxiF1aqJ5bg/DIoTMsMZD4bYzdnNmvgZwsFghjgmQUTl4EyKW97zv/JL9pRGghA+Fzi9JvPROQBoup/R0QiwWVh9y2Si5ljiRzPXUM4ZSdrgCHcXW2o5R8isVqJzS2L6KXHr/3cf//ZnEAQ86ptMUhKWj/nxvKf3wVgCKFUNaCaiMOckRcZ4CeffJLD3piIKAhFrf7aTXWt6d9ldkHYm1uGiDDNrUW7YCePdgvY0Zbq5CWjprmUA0IobbHmZq6Gxv7oALdSDQ1CEcmihbMklluJwGHS6h3T1K+GmbmuN6rmTCmlarrZbDSlYRhI20o/Cg3M3YzGmD4BoCRGqG5uvsgJbh6UfQaZK2JWnAHEZIXaLDcSHhG1pmrb5ahW2yCohfAIo/HQvCqhOUOICAlnCnRGq9rmBOy9QZwn7e0UmjGzajNQCuY4ESli5486heMeQk7MS/W+n5/JEjmLMkJVgHv2dXhYiQEoptGobWohojQODdddqogYfJqmlHMtJWzXPLGITNOUUipWYymrU+ksZE8pbaZ1kjzVUrTGFCjaRLf2f+Gr1Q8RYXZTBiSRgKpv5y0UwCcmMyObvTIRWgvqWw9EauC5LTCK0HIzcaOdOTszDyax0tapBHYDM42kNuR5lDhuJkkYgTeBAGHekimFSXvAsOPXvOmX5sUWL6qzMIc3m7upWTUIO0mtJu57e3vBpIqRvqrmnEOgA0x5GJroP3w1bRIop5wkTYhRc/u5ou6BlnSPUQSIzCwlcSd3jiGKmbElYl4s9opspulkHEZTOT0u45hrnVjWw0I4y4IWBmcaa82r1WZdUxZcvlqFpuXZC1/7F/7M67/kNf/j137j4SeuPu+5n/Xwg4+8/z2//863Pnp68tQLXnjruDjV8uhdz/7Y8z7z9jngvvhl955cX+DZl27QL9flZz/20Y/94ad//75NuvvOjz7rM6lsPvdn/v3jL3xRPnuBlsPLnvn8u/fOndk/c+uQeTrxBS1OVwRe8eCqBK/rCQvaL+sNBgWTNGJfp3qzaMxVCAxq4wRsXy4KZdieCfoCuEGt58NpcO40m6aewQy4CBMgkqZ1IRNAjIkSOWyqGqqo86tNXT8H4E1ZTws6yOeuPPbI9K9+VD7+npoP5PjoCCaZzzrduLF66yr/t8OLj5xbHJ5Z3nK1fsuLH/4bL/rE2x49941vfcHJWp2dtO6FhQOZubL7/rC4evXqhYvnv/fvfc8bvui1AI6O1o9ePiIimO7vH5apksOZaq3DmN3dp3gBGq7TmhenGFOgXuAeHSYcBmftNwcMbhAe6tRE1M41SsJEBh+WQ7wgBBMiZq61VitDHucmVeeM670A7wsjAHCdZ11CPGOeI4hJW0JRhIOGEDOTxvdsIcXNlGBwVI1ecVbqIIrdVQJt1P1wf/Gud3z0Xe/6vcViod5ou8TExNO9N/zA0u8e1lrAo4gkYncn47g5VphFVHuiVSOJcxUCPpF9Gdieh4LKLAKBmqlZpym3dVLDCUYuoq690fa27atFTGsv/XZeGwNc0+LuIDQfPG3HeEyZI3PVOutqEcisOpSYQlw9aRvyN0mg3te7mQmRgJ0pNcI8amMGNdKtu8/OX0SUJFNqAdfMcs5pyEH4KK7ecKhEPXvFq8ddcSSmtBAOnBn6DwKBBZPWGV89P9f4V23z3T6fFMgOHW37Ye45SXJKnpxbSRL3vVjznGBsv46IxG6zeiietFs/aY2pl0Z3BjPzaeq8MeeGI+1HPGgaBq+hXKEap812NEAMGjo469UmpbS/GFbTxswmnVTbGxk6oKqahxTo6MVicXqyWt04Gsdxb2hSl/NIJL504/KCnd3CW9Q9Fg7cpXTDCjAqniRSmudl38ISMfO6FtpheJOTA5HD0NmB7b8q3J2EVZVBOedB0gRSVSaSHLhxazJq5k4esTyqhvkEBkuSrfvWwGYuRPsz0VlV7ZfV+H+cmU2J0NbcoGiIU2ORpUjica9ySIQ2pWiNBB91j5utVqthGIpp4A9EhCSHdgRi2BA+1vBqlZmiwWBmd4qJDpRzWuzvH+pUCLy/vzw+PnZgrbRMF4hPzKZBzoCq08mSzxpNizwQOyBF6ZEnjiTtvf7L31jX15ntS7/sdSl9/cn66o2jyn5G1R/8+INXbjzw/HufOyfgi+eeWff5GXedvPxFWCzO7g+4/6FH/t1/+trLjxWzU6T3ftU3fIWnD57q+xN+/d1v/4qTa/dcvGdz8bbbP+PezzLg8smlg/1z63UVcpZS65R4qZZIJ/JQ/PHMQo5AsDOzkUfWiW5Henx3d+2K4AHHFZZ5DOYzk5BAZpwlgALUN8HUJcdhWCyGzenGzJbLcVMKC4mEqYPPFWSUxQl0nOwWOlglu/r23zr+qZ+2T77/3CIdHV/xxMtN3pumj0L/Uzn/a+fuOKh1H+vbbhz9s9d/8DV3PvWP3vesf/Tup533RFAR9VqhVKFIGJaLZUrXn3rqzrtu+9f/5kefe++zHn38SZHs7ikP6nSwWM7yauxIKWsJOfooE3pn1i844D9zuxZ1CZkLcYT6WitqQ3KE7LzVZooKgKy96YXJY3ZI4CTUSEtbnzRjYm/cgzk+YOcZxT/Pw3/fbY5DFZF5/lvsBETC2woFhtqBBDyzU4PQJ0YkzHB2UUrxgr/ll38DrovxzDRV6aBOIqqvuoE17X3kLEY6UXMCsbE5nIQZClR192ExRkcayBl3AygYwNRQymiQY0J0pq232MluZaq5/+hoW2hevMWb22oIiq2c9JviIQHXUlbIkmwbvPnz1+t10EDmnieiJKbKk1JqNLzkfZUivZyMzJSXCwBQs1KdKUvHoFojz3tHtxNRNWUnJdda3Qlg67J/TuzkCDWUPuDgcATtVzzHjljcUh9L2mx9xWkvpcm1urG7mjaKJ5OAotsLPpyZWSmekk6tY5vb6FhSKbNQ+EBxoKmZ2eCu1tzCADcYqYCki+fFOx77mGBlBMh+kOZIGsc0D8m0VY5wRwDU3Y1gVa2qEXsjJpK755yr1RqGJ4qqxasiJQjnnKGWc4qH4O5WagUZIXYP1W2gtNls1ut1SikfLgA0LhsRBfLQrIG+O8KlmIVnn5gRSwreJjU4FZLM6yGaf3HweLufaxSZ3G0upNHBoz4M0peqLjCoqgHh2EhEMVefuqB/lI3tjAEig7eLd0dU6sTERhbiDERUSmlu85K82yIFpDnn7IQozMGUlQFYci1VDBBhSeouQwY45GGZuWpB6EgRdCrTag3g8PBwkQd3j7zrTLCwVQEQPGwy99ADt27PLJIACEXI5egC1a0UE8mlTAKXVB2aBzaI2rSankpVkyyVT8kT+QGIUoapbE5ORQ6Ma0qAD6vVyiitTk+Op4cHOUAdF+Oi2BXh4d7Pvjstnnt6uqXirO3EkzOyOV09unbkqzPnbn/t5/2Vhx77ry942lccT5949OgHzox33XXbbfnwupffW+CWd73zU29/23t+Vn/lOc95xtPvfdbq+LHDs3L+9nx6I91y/umQDaGaljQOIVKZ9g6CJ1Oj8AkWTCPQd7Ho3upxTq0MUvWqqQO25/K3HSo04s02MZCb68B5ss04pFvvPrfZ6NH14zFlM6MkDTWNBiNC+ARbPciLpzYn1//lT0zv/80zl69OUo5Wq4F85Vf3DL9zuviRdO7xcxeehrrneM75o3/z+R8S9q9+yws/fHTbuX25fmMiLqQ+LkYA5jUPMqZ8dHT9zPlzP/rv/tWznv2sxx9/Mg1ZiAPvqFaOVxqaaynlaZqmMo0pl6lEFJauujxPblHbW8YsbUxLLEK1ToSo3uDurISYz6euIdjFRGNHG74XaJpIsFIjI+ZxcMW8QqbAkKqq/FHuWWg5VLjWhhdJXTfUqRHMfE4tHfI2Z4E5WzPICAFbMaPZb6OlRocgDUt88hMPvvnNPz+OrUE3ixJF3L2+6iS/93DwJe1JZtqsVlZLrcqcEidjUObqdvbsYci1EYcNA9sOPXre40bmE4t87NL36AonI1GIiJVK0QaYGZOE6WBAWlob3XwKQwbVCV2uqd+HVgXA6vYdFImiYx7yt9i4ZdNVjY1JUjh3Nt6uSlmTqiEZZLvTjhZqbhScKYa0EdnnAqQ5P4PVyRH3qZNurVECs1AsCBHgDYAaqtnQMgdi3wCm6jaCydoUi8JMlLxqTTJIzMEABMZKzcziVMFcZ089lng4McBMKcFs0hrJILEwxYYS1iT3EOyaENMQbgB6Vl4LAAEAAElEQVRjSWJwm8oMNohWkhi1ViahDlyc85WaHV8/muOLmVFI/AQl1iURQxIzHx4eFtPT03XQimIWV9drVF0sFicnJ5SEGJzTOI7Hx8cHBwf7hwethuguHO2nU1NCqRansmF0k2QRKZOJMKXQ8Xa3kMcgi7WwpHlBy3AAQxrm6T0RJWJKJMyUBrLtyfPguxGC5igipdZNLSmlsFuICX/Eo4GaeIJX3dR1QBnBTIxYNJmZe9Ts6n1n3Pye424Hvsw9BI9SSlWrJWb3jFZgCYcSrbkDTFaNiDglMs85T1U3dSMgJhqHodZqqqUUSzQMwyIvtYufJ+IyTTI0NCIRjePoqjaVlNIM+zQiCGchB9hMoaCNWWFK00aAlFKqdTNwkpRLWZt7tcnZGDYMvNFBZC3jXqKahM1MK41JHfvjmFUdajIyD4tst1U9WR2xndzgtJwfAfEZoY0XoXy0kAMfFsd69WUv/7P3Hb3x4q362GOPfN/3PPSnvvJzf+w//djBefrMV350efbDn/dlT/ui/XPXLp27fuWDF277lY++6zN+9hceWx7Ia177hhtPPpiX041jWuxfODxzjpnHvLh4thLR2bPnJYtpQUfJtvkKgWJFF4teYcQWHwTqBtjNTxZzV1Fdo9SGqZl1aXk/PTq9484L683xv/6X//zCxdu+8iu+6vrRWmis1nTZpJPCmy611TOy9/G3/Wz6tf+8GOjI82K9Rl17qVnzb9KdP3x2WQud26CS/dnP+vh3vujT77507lt/83lPrnPmcZoKZ3Uge6qAJyIahPn09NQJP/Svfviepz/n8lNHy72zqmpTZWYYEmdFCe61TpXAOWdwEkrQqZTihBTdvzW2rvfkp27mcHehBEqao4dmYmIP+BY8iA8SwAMREWiTx2ZOBiNiGDKLweId7H7t3MNyow+UKVxe2ja6bTabhrRx+MVFKeMeqBTqWQQ92c6tWtU6SBJwqVGMwXNqM7AIj1ahZAQ2OI37B/SRP/zE5ctP3H7ruXW5QTwywogPk5b6yhvjj992sl7lnG89d+tTx1OplTgb+KRqMV9Jdve9vb248qA1cih/9nqCuk91gxBtAeChFUEknJJQobiN6AvsGGDCWUhmTN+2vtSGH54RWgDcjMNngWiWLubZu6Kzok2jU6hwN0ZI4ZORQJJXNTKipIiI4dGDEHkQlYwRvb6A2UwTuYFSqqWG9mDLlAZnArt5ZVDuOKCiBlOJx29q5tOkHgS0lGZEUmTcaZpYHGB02aO4Blav7CIyTKGdRNVMXU3NyCDMnYja4GNR0wQOkMndN6GYKonZqxsRNrW0iSVETd3cyI1QyR2eJIkx1OC6Wa3DM7GfPHf3nAeFN+h4UTI3Rxpys/TotndKcEDN9s7sExpbyUOpIGUFLSSvi5o7C2lgMOBOZlOt7ptaxuVCFgODwrZsdXqq5jlnrWbqYBvH0UqddBOVV845Saqm5kbC7uHQbYG645xKKdOmhBtE5JUIgVY1oO8SJy7g70ThY1WmiSjwaMLxxrpDQNa2yLwDxxK4DEPUesMwVLf1ej26LxYLMoezEUikukM4MROjmJpa2RQRSWkwQgjPgs2tkoOsMbadyYSsamIh4ViAxbVoqcTAZC6sAgFRTg5iIkOUqaGxzkRt8JRzamL901qiJIEMOZ+WExVrTR3HDJ+zLKJYzizS9QeYmRBrL5DBNOy2hIiSc87iTE4ws8HAnEyIPInDzBIv3eqAxESOZGUaknhNzEYiHt20OHDgZpREoO5spW70mJKktHA3x3ATBsdXClB2wz7EteqARV3dyAu5dHnaO7j1//oXP7q3TM94zhu+46//tfe+Uy7ees7p5Nwt689+Zb5wKz/8wNGFZ7zvL7zpZWcXX3j30z7zwQce4TO/9qH3bB64//ELh2cfvP+hV73q81bJplIvX3r4rjvvXgxLZEESciJnNhihuqa8Z7apOtVaAXIldxpSXvlp2awPl2eqk0FD6iCxZCymsrJciYRIoFZrdUrPfsHeW37mV37x5/77k1ev/fa7fuerv/qrk4wmlMhrBVGefDXysKapbmyf0plbD97x+++T//LmWxbLYztaT9d0TQe0ulHzr05nfuZw7wb4riUn3/zAyz7whqdf+mcffPY/fN+zq5mIH0/HLLF3JU7sbGYuMhjo2pXr/+QHv//zX/FZD1++QeTr0xNBQyoFrHYDYSXqDq3qbiHWn5KEYVQfEXHHqbGwqrlB2piaat0ERNWCRNNa4d6iNH+kqE0i3ooCDImQXWCcmCEMFLfw9RUmZRSvBBKR6gVaAQnaGJiMYOZUNaTx3L3reiaAYvIVAgPYyb4ADJ7zQMzBxiZzuJOquGud8mJZXUNIWZycpWJVNofvf88HErGqJ9mbFExmUGPW5678Ql383tnkXDfl8kMPnix4ECal2y8sXuHT1etXDhSLQ3vFM+8w4cQDgXWCEBcpVNDRukCsMIThIBazACeRSNYyiYGCgE60mjbR4psqm4DbTCv0i+YclBw9fhgRITGMVFUgJgj3V85NOKE6iKgSWHJMW2GViAkGuNUY2gmnBFCKBrSiaXBTQzA54DFSQPccdCDk6IjI1Tpfs802RUShs+AGdfFSIenwWzCFGKX3UXGn6rfNRIA4AjGA+WFHbYaOkIprizUJxQJYtcOqGVb7CKLDa3eaM6iVWqKENAZpIJlDjsBcjR2p4XhUCSJMGgKkbn2UyuYewGRhh2upMVkK6cox52kq1JSrm7R3zjkmFewIcHjOmZlKUbLEzMMwgPx0sw7P4MRSSYloXC6JqDZYj4EboE5E6qbG3Yg6LnXm5WaziTQcLfBUpvjuYmYE7koxMxJt3mFw7jqjTcrcoW6dtpRSCvyCSCulI3kbc51KDOpTSh4tJ1PU+4Fpiv8Un1xLcSYioQ4mjyp1yClA3WaotZIweeOPxdzG0Fjg7MzCQ5bVtDHTnHNKGQDMRcjYTd3MjLbae3Hnfa6LezPt7kSBl/ZmLOG1TBNzMjNXK6YxKxuGoWym2AWMqTlJeFCKHaYaqGDufgDqRuZt008MIkaPWuiSC0IAq0qAJohIRDalUKdv0gyNCUFTZs5tAqmqgAF1kGym88ofc5dCjRDCnFxryCznxbgpZbU6uXq13v3MW3/uLf+FyYXH9bEen6iqD8OwPtmsNpcXZ/Vg+ax1vfzsZ7/Q9EV3ve7E0uaJRx/7vFd+wa233r6ZahqHp566ypzSclyv16hVRDRlFs6SslrlE7ZMvGA396p+ymSb6fRwf1mh02mVnMBkrsMw2OTFTykTMZe1w4rQdNed54nwt/637/jIxz/0H/6/P/m1f/qNf/97vt9ZTvXK0m51RlkkwZonOabpwsG5fNay8pt/+X2/+73f+Q37ZaWq5cbZqy6Zp6PxJy7c/fOeD6fFfn3ivqcvf+C+39lP5Rt/7aW/8PgtDAfVGGMJESAwVICRBubE/NhD9/+d7/mur/v6r3r0iWvMOe6wdHmvPhaKhj8SpSvaoDhEcrCDC2md65BDoxHzvjwGyyRofjjufXPMbkZz5ovfaw9aWKgtQZ3a39KG+nGggap5VhwTtKDUzoy2XelyHD3o+ATuaCP0xcKcdMPwIFq96DXQGOCB3Jxn1eGACHePP+Duw97w1FPXf//3fz8icDWL+YEZFDq94ggV6T2HUeVvMmVw0U229BnT0df4Vd6biqTl0z/z6c9/pho2gCeVqhWkxpmIuhVxe7+I0Vt58uLUSDHBLxXKRTWEGaKWGtN2cU59oxHBNrAjAVYIrBcjHPnYglEWCa4RAWLMqXJzyZJyokZnr2bT4APnnIJosfPCK+BEqKrmgWoN17+myBJo10hj/efFzPN/joOPvDlvc+dml6RpOupMECQJr9ZIl0CMvmOUbck5ApyqqhsJs3As/MyMvFtzO4g8CKC9VOxLJnd3ZSNwyNSBmQlsVdnhWYSaqR7UJQkYSubrgn74BOTmprW6kaQ4V6qaGrKfVLVORVX3F0uf5dDC3MJNSzVgHMcmPzkVI4x7WUOcjAO/3uZ4e8tlqXWQNGllkAJmVoCcc2RZCNdal8slmaeUpmlS1WEYQmVoWq03tQzDEATueBZBLECnr7Ft1VwxD6ncZgACt0WPoZtUN/x5Jws5AR2rb33qFaPsSWt0EEQNHNtOf5IYijlR10eCwqnU+Fh3I5HgAFiALeEVJiIQklB0q+osZA44haJLeKkBodPrnYdGFI/Um6B3FA1mZK5ezEwSE0PdMosDktirMWNMIxGJe51K7DWk72I2tWQWzikG6TWOpVvs9YOPiJ7sjb1Z7jo0flsrM6mGlnKcDo7q0MzGcZzfx7ixgQAPZUF0e66QnapqCZZZkPP8xjXQba+xiIeUB5iWUobFMrNgHOC2Wo+rzWR6UusVGLnR/uHBRk/z3t549jaS4caqcJJ1JbcN5+JTeu5zPrOUUosi8VTswvlbiWg9nQ6SrOoiL546upYXI6svOBVyYR7TwNhnyovlhToM7n7jaEqynHRyOqYB5LluKqwOzJtTlqRnz9CFs/vXn5Sf/emf/tF/+wNf+6e+/ru+6ztf+bmf9+V/4ov+0jf+uU8/dJpkv+qNjErICh/q3t65/MDjT/7iD//mb7/tp9/9gU+86dy+XNjjx9a2OeZp/YilH7Ez71jzbboB7C++8Nrfeenv/sGVg296+8s+eXkz5LUkEqapbNg59lARMZfLfduUhz/9yf/ju77jW7/lGx574lra3/epPR1F0wyO/fcgw5yfiEiYU89YbW8WU9BqtoOEaiQU83mfqk3YeUcOSCsx+87e0XfQMwH5nX+zRzxjSKCr0Wl+7uTkKW1xmvG/IW5l4wgiGXLalhQxDPemPB9GZyDiBs6Vjsps6F0GGdC+V2ZmFrZ4Qx2T1nEc3/++D37wgx9c7u+5uymGIQVSBI76imP5wD5OOdRbmIFqQxqguOvkyA+GTdGTlHD3ndOw2JtsLw2TKIHcMVDqfraY71KMl4VIA+cUYgdOGg+ilNW0KSUiq5dSOKckY5ZUSnE16/VUwMJzbvyOCF+qGuOIoGm1HxoLcsRzacQk6k7ADnIQOwLEIMTR7/Fc7GAHmigEWHO2oaD0CXeZ/nnBQCklr+pmVTpBpf8iCklMm0/StoyiaB/bHiJ+p9bq3gx3+7lpPRALrVarRDyOo4Sav3QspRoT+U6/SyQG4x1/YnRIFxFxcN7n88RMAjeHGrOk4FYRhRo2Sk0hjNx3W1FzCFPwieMThLsjT+cmaXc8DEndMHNGs9ByZo54WkyrWwB2WKG1hd0kUmst0xS7RkoyN22mBqLQHd3bXzBzuMcwUTUr0zRTjUeAuxoJd//jwLG7u3e64TyEADjKaiGOGrjJpITinU4h0qY6zY+4qiYZRTKzht0T0DRfZiO7KIwCJIW2VYdTVNbk3HEiHhku5CfFQ51SdcjSsALcbjX6zgbC0ivc1MvbyP8iW9ZwbMdLKdRtN/vQhYjIvdHP3JyIhmHgnGLSE8cpSmBVzXlMaahWAk9XpylgpdSlSNopDCHxJDD3qg2lqR2g1JdoCRTjVzCxBA+0CRXNNfhuoFytVimlMeW4qxbyokwB2BbeJuC5uY/oX81gJKC16jStnWmQwUHOKzOTtBjTXt1UI9us67A3Oq3VD7WeDOPgdEHLseRUyzIPfONkHaHc1HMeTCuZB9zXQap6uH+QUtqcro6ObzBNT1z5Tc5PXl7XaXPtxpX3jYeDyPlzd5+dihEfrDbLTakHB2NKvhycjDnD1T70oQ/92i986H3vec+dt9/xQz/wwx//1COv+bxXf/u3/YW//je/6yOfuHa4OHCCplP1A/JptU77d+UH3v6+t77pb77nY7//vozls55xeDDRVT2Va8NgJ3c8+0eu4N28d57W58b6fa/6g6981pM//unnfdc77uFTfel9z37k8avH168Ni7ypJpwcCLDIwd7+6uTGlacu/Z3v+f+86X/95stXrihJOZ1GNHmjOay5u8HD0IWI0J4mDI0OEKBCD1ADLEKy9mGMTiVekPayeAslnaZh4RdHfSuJnRGjmUHNOiSWHUSwYDWZbgOvGUiYydlNjUKqApTahTAzRw8Q/FLWhpqOrTAIBu+uQe5Va9A1u8Vk7FyZo3xphBHvbL2m8SjEhPe9+wOr1er82XOlFAQ4mpqzvb7qxvDmW6zvbjOMcqqal7y69647D//SN1+6cuXcmfOLZz4tnb2zmPO0GihbGmAOnaHakay6tKI1YSUgiJIWkEAAVE1AwzAQuZXGYmVmLU2EuDXQnboZjy7Ov4gk5mguw6E84gz5NuNIj0iNzTmTsoTTOES0NLNE5gKym/1GIme4moHExAhz+TMv9qjPx+IANdXozoduuXbn0MwJsj2zTiBrOk3c2sSo5eKAtVPee2jv7oeYQzkhduDV3auCCX3fFvfi//mj3YiEc+ZAirXBqVZ28qqVKADi8QmjpAonZnJrYF2EwQu7GiNuHcBNdyYiNTNPWqEWmWO2Q2Zmlm4PucNBauqYO/kb7uM4skhYypdSNmWSTuvmnbFVAIPnKULMvdkMRIEMmtlWdPNgc0Y5zx8VtyvRdtdTqS1+nCnTsK2md+cKDftnRDRwYmZt3wS1NsdTnS3WbYtA2T1s8/mhkJgmCsfFlNIsmWlVlTS8S+Ojkrd5rJl5lkRcm6bVFkyLNhfieM3mag9tjdGyonAqWkSSEwUVMiYHZrbIQy1V4aVozpkTpZRYUnUrWq1tzdkpPFKQUorIBfeYxruauc2McHeHugWnv0t6AQgwTDzBLpjaljvoZfjpVERkGIa9cVFMa60yDJtaynqLgxv69p0dYEpmdVOUaMyhXx7tETuG5SibzUZSMptSGph5s1bOzlB1JU9uLkOtm5QHmWoVdq01c4iOKblllqJGKalwcUtOuplqrUhSnW+9+Pp/+A++8/O+/Hkg+/jH33n80CcXS79242j/IC3G82f27j09OXji0Sc+9bE/PL5+XIkvXX70icefOr5Rjo9Pnvf8e4a8+K7v+t7zt138qf/231/44s/46Kcu7R9eqLUQ5QrZW0td4vxF+tjbPvjOb/+rlx9+14WL5+8a77q6Pvu4+Onh5bNHTz60Ofvmp9/90TWdvfHgF3/mub/9ot86n06/5a33vvWJ57md4lzeT7ckPyqbSs5JcnikGmFc5GuXLsngP/Qv/vHXfu2XP/HYkXkK+3erdbbK4UCJUvi99yAfUbuJgrURbgyT1Q1wIsosja1TG/+Q+iyKeyfTszuzA+S6s5WbizOK3Qq8icv206UU66HW4bRimiN/ONhN1anRsZMkEZlqsapaS+ZWsovDQmKBiYQJQgRJTgJ2RPvRjm6f1riDkrD5bmcVsFkn22zsne9892KxMDhxatWzMNzt7rXdNeV3ngW3tXrlYW9/nHTvrpPVcPTwcOdth+cOj689dch7jKxCvDe6aZ2KE1Ji76rwAZxo1xZg2664Z2bkzXJtoBZhVEtKaRzHcbn0Xvj2uNE2dACCAa+qXr12b15mngvr6Cy3uWZbKnHPvgRAHbUaEQ/LvXjTU3B7dqOwuw/DYFUj6Guf4KIjpVNKTtsAx8zVLXggtEOBdWsQvvl4zWcoPk5VY5gZAL8woouc0dMwxc5ksVjEdw19DyYwSEDg4N2agrr6timcb9aD5Lk2kWiYGWqu5iDKQhTLcg/RPHOExw4RtFadHZbMKxzm1FU+0J2IgkAmoNjSId6z3verKgurqhDHBjHa3yDYRAoBU4TOUkqpVRtG31pp3BAfvehRjb/YnB5ynqmrIqJmtVYZ8mzzMfdSTXS1790juNcwrg6MwI7AUIxcwKEo2cdQvP1eTJzTVhYjDig7OXMIccyjNpu5Ew1Z3Vi6QNxCkiETEYc+bQc3WSiNzXpJZtWawBkJE0i6BqyZVQaEUbfjuPiJzIkEtZRgaLRD1UD+8wsTbsakapG/vZkYUuRU1AoJQhbVUqFGSYZhwLwoyol7193XTpjvfpO8nndvasZzJm40hgjc0oX0cPMvEs6UTQxqm82mBc6UAAyz6F3/6VGFxAhRUgi8gsCqhdnVnMxlyGaeMkHLweFyvV5TzlwVOhitx3xovgE72/4wei0i2eA+8FBrdbecUkrJaxM7KqqBhuWUHNhbDGUznT175o1f+7++58HfIzq4+xlvHI7Pvu23f/3jH7r/oQc+Ni7tB//p657//Hte8JzP0nX51V9986133vmaz//csweHFy7eutw/uPTUpTvvvOPb/sq33X77HTfW9tFPniyXB1pPNlXyABRZL+rZxd6DD1x921/7GxcvfXB62ovetrZLciMP+x+aLCn/YT3/L6fhvX/w4J15fOMLnvy+l//up472vuk3X3PZn3a0frh6ecbF5z109crlxy/fcsstm83KzJx1sRg3m9XDjzz6yhff949+4B8874XPfujRp3JakDIUQiCR2D216RQRp6DUd6s17xucNj70NlMGS5BcAhQ+ixeGrQ9zTBZNMQf3dkTdPeTjdvzL5/DIHrY8Tg62dpojCs+LDHdnhldSt5R4rsKjeoC6u6c0OFVVbWJuqs6N4Nfjv0VCiuM6A9B8t5ZV02aH5Rref0zmYMfycHH/px7/wz/8yMHBgbq7MIwgEGGHTa88ApDefZZ68U0Y9pCB4WWc7zy59vg//SfVii2W+esPZXxuWTElVrYhixJxdbT5t6si9GKjBlILAmEkVAKDIU5wVWfPWeKlbhKbapKT9fmuM4nPGOGmD9NKfq2VGj5jG0Z0vhNMag3s0vuNfh6IhGEeSJc0ad3WC9EnwaNwMBA7YkMViGp2bFzdvWiTSul6p87Mcc52uxsDhXEyEOh2D5fE0KaIjnaQBKCYcpII/GZdHoWIeNaS5BAuzcK9loSqEsMQXsQOazVIcppb/rjsbTIWqLnXCrVZmDA+KrMk4lCFIeJq1aumnKq1eNruY59IxF0jILpbUGsY5+lltH2bzeb09HSxtyCgVgrpqxAlrqZeNWBfGmVsEgmDl2hqhZ0pzAPinkxaTWtKqZhKkk0tg6Rwl6q1hhuxSDNK876B3n1pg9tQS1FphR6j3a6oA9xjbQkysqhngOo6d+09cQJMiqZ93QKOcBzK5ovMHE+Tukm47pjH7RQH5K5xG0WS18qcRaiLdUAkuLcUPXQphYxDeol7g6iqjciEdnVzNQl3YlCSpmU2C5m5DSm7OweMpaq6Aa3ocXcaRacSdzunBGCz2SyGkQWbzWaz2eRxyDkjYT60ZmF8GeMpa+VOKAhtcTQkQy6lhHA6MzMnIpacdv3UdgMuiEk8MbO0A2ZqqhbMy7yzAw6RLwAQZvPJNkMeg2eZCJKYFOrqOlX1PO4ZQZ2Hxb6q5sSllMT7p6fHOedhWJpV1c2w0FKT1cqSxpzMqqpaIhYB3FQHSa6GIa2nyQlWysGwtz5avf51r15+Sn/mN//d/Q+8+72/8YcPP/zwfffd98f/xJfcedutd9393Dwutaav+vNf/+e/9eve+54PJamv+pyXXj+eqgtnsQk3rtpDD1/jRRr39siROdFYAFtvRMYb19b5rW/6Zrly9aEXvpYPS3n0eLp8tKjT4wv798fLt09nDl997yufuPTXnvm2P/PcK/+/j9/+Xb/73PPnbz1/297lp1x8+eCDDw/Teu9w/3h1PGYZF8N6vX74wU/eetv5v/s9f+ub/tJfLKpXr9wgEjJnITNTGFMbys3hxdV0Z6HTH/HctARMtpfs6CVnj0jjOLb/pHB46gF9JgKBiT1U27l3LvGjCZFrgWhPmQnmTiaM1CKpA2BjAMZwZ9uUgPgyc7y5TQPHEDMAMo/nG2XcxkrE9UQpopyZmatVY8fcJIX8bTjWI3yEAiFLFKX32UHe++73PvXk9XO3nClWHGSOISUDs1t91Y30kf10Y+kSzFsqQtem+jQ6foZd34ysn/jQeOaM3vY0OreUMemx2kY9mRFcCJMhpeBGegckcZveCZlGuDZ3Mq9eiCSlFJ29mcW2yIoZoTnAMhsh/DrDv1fLjqNLE/olItKp8CyYFS+7cPx/d7dQEoXHRJqAWidyA7VCPJ2cnIzjGLtVd7dmce29ZQn0VcMHEVOzmbTtzDMR11qNGpGUt+vYEFPjWiu4Fflx8uZoVUqJ7V0pRXJ4a2zHpA7rDTbXohZajyFTbBAiEAos2jkiCgJxZkmSdBYe7yLI7u7BqOqo+iRSVbXWlJInLlUpiCdMygZ2HpIXNWuTajTlGqiphqqteXMacAtnbqiBMENp4i+eOXOmWiWAhUhRStnUIiJpyHErmPthlrbeHqW55tVa0UfW83s7TZOIBOBZ4c1DmxCzWSKSnEJdJPWlaaSE8EykTnTWLi42l9vxJSINoztpMIcpVEcJ9mpAVU3ajdemxs5F63rahPdWFPXRpkfXTl3eyMyCkhugQSeN7tMIVY3cmXOoZEl3U5jTNgCrrm5QpJS4v+2u3hwXaVZ1aEkxiYiAwO6O2LQSUK1qGSQBxIxaFfBanRhuDSDTRM57hlsMo5m5+TAMiUJqo/SIWVvV1RtoNyMPH2GzYPjF0h1k7jnnMeXA7hULg3eSXjDN7ctOmRLB1+cFdxy8ePTzrxDA0S4Uk4YM56owJUk5hlQpDeaFE9U6qXpKTMJOLmlYSJ6m9bCYrCzW6+OUUkqH6+k0E4sM7CCQuqQ8AJi0QiglslIl5UmrLAadClW7TmUY8fi16yyHy+Xy3P7h1Ucf+lNf+CW2v3z2s+58+l3PXJ2wmqfh9OqRXXlquHjr8/7wgx/55bd8+N77nlVR1ROsmp/CMq348DxvprIpSC6OhPHk/N6tD3/qwcff97sPvfKLLj3tOY/+7I9dIr3jzmeenvqT0P+yxrm7zrx6eeNvveI37lie/NXffsFPfvoeFH3i0mNPXn5c3WnEAl7zYGXa31/Wsn7k0UcWi+Ev/sU3vulN3/6cZ9956cqNskHOS3YlVtU1j6PWXfumm+rI+GfbyiG0d4SdLGQSCTGxZADOlGie9FCnk4hI6OoERFw6G7OYxkm+GZPcVmzqIUw3HwImclOb3xaHkRODQOCU1MxDl5EQCv+EaF6EyFMSojzpZAYnCItpkGttRvMHHgNqcA8MvxslYgM0CnrhNgNgiuRRin3gAx+IDYu6E5MIu1uwE6aXXx/ffoGZ0SQbIWW6fmKvomvPTzc2JPn8wXo42Hva0/af8cJsi82iMNOe8bRSGOnIuqk5Z2IK7mUIkQtRdYQ2gTO38YAZkVdtyDczy5JSGlt7A4K56nZL2NaCaKt8AiLqmmo1nWuxefhBDfNFRCyylRgzDSE/YTTVRQanUtR9mk9MnKFQdApJdOMQoA5Z65BNYXAwtz2F7Ab5gpOqggBpQTwEQadah8XoahLzgcCgMjFIqy4WC5BYqYMkFHOYEHfqWZNXk74KVVWH22rNzDJkcweRKJEjXAUjUDqTmrHCO/OjOQcAZpbMKYmLu5MLc2JSY+YB8LQVYwM8boknDIHH7jSkmOJmSIVF+hFirS2VxT0spQSoNXRq2lOsdRiGBAGwHEYzs00pphwIgrBDpiYIiakmZoBYkiUodz2QBvYTJ458Fs8+wL3KTfA97h8cAnINQy5hZmcAVFVbi9wHrc6BO6Bovikg39L7tsxcEaUGei73bnXs3Ms1uDvEweCmt0AkoHh8KaVQdqTAUQoHgpoZAiqSBnIyRzFmqma22QhRMS9qPIOP2MWhasLhdGeTTtyGVgRQ3UwcaiRVo+Ns4ngFzBy1GDPMXAzCyZncHGQAUWY2IwiBaRQm9qlGhRSyvZxEawm5FVHPOe8NY6lV4cSoaKOUmC7mJBUO00rKzEI0iEyu1Fxw2N0VRuIgTxbHRkW4rUJiDweJOVrxqanldOQLpRBTgLvTvCEEAE/EEK5uq2mTaXAyMJjhwbBnUneqDdA5DI37mFmoltLWZmd8cLOkqrUeiQiyOaCxeGK4TUBIMLHFO0WUkayaECPzSGaTD2kgt1L0hfe9+E/+xNfcdvHgkw9cu379+nJ/Ly8GAjOWQwYybCovetFzj46OPv7Rj128ePHw8HA9bdarzdXVk0tw3ZyT5TItls6ndSqjDCd6+pEH3/yhFz3rBp3ZtyPc9tzNIx9dUrVxWNKeJ/+TFz75/c/8+COnyze8+bM+cXzofkLMDqqGnAdymPpiGPIiP/HIw4nqV/2JL/7Lb/p/3XvfvVeOT+5//Ap7IqJJ1ywMJkoLM2WzLNm7A0cMsdQsSRosubtBQ/1KodFmVa+SRFxCuRMUGgFAE1CTvpoRdhBksRyZJNojYo4glnMuWt2MXWZ5RSIHmU0WaOSUmKi32g6P+VbMgTpkFe6V4URCIqAA2LeqkU2ngiwTkbuJpCHMFDyZuEJVy6lODZkhCWCS5FpZm+6vdjv2NAyraWWGPA5alVmYsTrB+z/8QR6pAMILkO0txtPT48w4vbjS56zyD50pqgd+sOaVEbOXl7z0ea+7/sj+x69MB4fY+JCujy98+XjXxY3XBSevXt1lLxu8qEJ8Y5M4C3KmBLKeQQFmrb5arRbDyIlDRRgh0FiaBbuzC2SQtEZpQwVusoWYKgE8ZDicyVkcIHMRzo7K1cxSEgGmaTLXREmtROYibkU3gSKIOXgyuJOIgDnt7y+pE0Vqrc1veaeIA5oFCoM638ZhxoD2tS6D1EIn2t0UQGJhR611kbOZF602ZIC8mrsLOAAsTXtT4KGd6+TWUKmqjaQfl0HdViFASWWt0Vsvl0s1o05Hnq/fzL1P7X3mPhEBThayULG+wMwyat/aEbB7dNocEDEwGGSt9myWwLGYYWSW6EXS7GPfF0Lx03NKFIb23heozC3Y90njPHuwyXQqIsI5xX9NofDqzrGrYGrzfvdg8kkSM2OzLdzAgifdWDHc9DY6SC8nd28+SyGg786GlIRBaUcY1kwR9to7X2eekgnIzRiQYevFNOQs/d0exzFaJSJaLBZhrtWeaW+ja8gA3dxVQIiJA80ff0zhktg6fywGMGrttWfmlNJyuYxj7H0s1h8uiqnrFvgdJlHWBPU8GgIiDmsUnYoztwEyswDuFhD9IY9x9jabjdYa5A1zbXAPMyJar9dTscViYZMi1uTVVFWbdpcZxam+qYsKcyxqjL/AwQbSvmO1zNsimeC1BkQgwG7zrYuJFKTB40MvbJ4HqKrCWv6O3bwb+sq81MmJF4sFd2Vs6l46Zu3BRRM223xZrbtfYbcdHBZDKYUkEdF6tTke1kfXbyz2z128eJGZvQeTKE8lJQBnzp5d7i+vXLny0CMPp2E0s/OHtw97gKTptLIcL5aHlAuXxQcf/I8/+VN/+/2fOrj7njuWizuf8cLnj5IefOyxpz/r8MZTl//hax7/uuc9/tOfvu1//51n3Fg3b0m1mlJKBHglyHIxXLt27fjGk6/7gs//G3/jf3v5Kz57vaqPX77OJEs5BGoMIbSWyLUSsnXuXVXYzIxBALlaMRchyRk926l6LdPW8I9a+Y7tMAPoIz4AZrBSDcYSXSkBrYwnIk5BoXCJVS/grgxKi9HMap1qbe9+bDRUS39eNz0UuIVWYOhyBAYoxqSqlsyIjIlYpHi0HCAiSiICDrJcqT45pca2QF/0EBHnlAxlM5nbkBcJDFPXstzf//BHPvXAAw/s7e3FVYzDUrUOw2JTi7ymAsjvvLiP4fp4vL8h57J3261f+pLPfNb7r69yobKZFmcO8sH5FzxnOSwDtgZphb/BEzNJju+l0yaA3SH0VMldjYecOYWbrVFz/hEi460LUfsWriEa3/gaQTMDplA9Y3KvETkjhOVuegEgBPEiosDahgidyk9uBEpEOUs7WdGZ7OaJtjVQi6LJ+6o/jk51m4nYIpKC9haTT2zNtyNOwZyAWkrKmXPSBtVBEmkDTYspTUiWNOdLs5iLNoCDTiWWprMhgYU64zSZcEqJk6C2bV9M0cmciQxeSgloUnSKrVYIlhshXKL7qxIaNgBgMeFEYxKEinec42ayFqfcibj9c9CT0lbDpE0fZuaou5urOLuhlKnlEhEAAeSZG9l4BO6exsHMpk4rGiR5cwak2RVr/kHuLs0VsXEQIQwBdT2Q9mT7qx5ArajygpYfZ7e6Z3PpsTSuPLnDEYPWmeLiHVo1L7RmbJfZdirL3fx1HnGPqWE6dod1ADxo52Fc4Q3T70wSUs2dHR6SwgIytxn+MCcJACVO5jiQeRh4iEiOBrqD+yItxeoiclPok8TtjNFvsDxiEoJ+qe6eIEhzYeqBlfNaQ918BnDlnM11mqaEmS4fVhNRDga3sqIleDSdMkYeF+7ezk1tCHYHQnG+32QBxw1ErDl2a5di6gTqgHBqRBQHYr9ibURm5hSqS22m2rI1iVeFIN4jFjGy2s0qdCohVM7ShAxlB0Eyn2QAtdo2qBE5ZFwclM20nso4jgFjiT+pqiyknIYkxTSPi9vuuHPv4HC9Xu/v74tV3hvV+daDXNb8q7/6X376J9/yVV/zElx4x0f/IK3reOXx9127/OgLXvHqr/lzX/7vf+LH7xyv/8LXPXpHevJvvO05P/XJO6vFC43EFJIoDOQk0zTd/+n777nn7r/73d/3p//cGyXzk9eP1utpkEVOo1Vn6dqW7oLGtkAIXZhZDHZna9QuaywVYLKmkRnk0y32Pk4UUbTA21es2WoBlAjaKWQNQryFMTLIHcwelmVmxixFpyCnxKFUVSeeXXOwQwBpaSbsqztau6GycwY5XMkbmtrMYgsii9TiYiOfzM+3Asjc+HyhAE8AM5EpG0CmWpihCs786U8/cOPajQsXb3WnYlpKyQEgYN289LI8uExPLJDSUKsNe6PQtJo2//HH8vHV9S0j8iC2LhefPT7zuVprnSoRiTQLcIalJC0r78TSYIjQkIgojwvLVkqx0KgjMg0ZRPJYDHiL/eHyF70/Cc8AZy7WUptIcFl0KpNO0K2ZRBc0I2bO1HSF2itcVUs1t1orrFGezKxlX+3K6QJyp6iUzUxA4U4fFUGt1al7RITLLNrMkzsUs50qNYOzyOnJyZ7IIGmCmnsiFuZaaxjgzHnR1bpwTxy4xIzMjcQSMWtOUTnlCHPNrEoYANQBZA43WGfmASmGkDZXkcxR7AvIpaEBpe9OvG+p3d3Q6gxnYpOUEiWRzn+Ppah104xtLuQtwjAy+pxThzSatP54tpCaXw/vKGLsdBLzpHez2RTmJn9IIbW2E9oc7l47/aa66YyWYvbmi9wSj/fme67gWgPYx5mxzp9FRokabyqSq3Rvy/kLzr7ffjObPBI/gWYqMxHVWpMQGVXcjOcKEp7DyMKLkCIBx1kK1K4I4OqmqpQSYunLlDnPCbhtmDopK3OOwxMrc+9Wm+iTGzMLgGmcAWZItyK3HQ5bjXahVW0Bim8ovLj4WoqYzFVF/CBXL2UjucFgox9VDjBaomanpKrq1d1L/EV1i7FEZpGUEGUzEakStlceEq0kNPs47QZZ6Yo3/W1qjx/MiVgZ0R7NvHYgfCR5wQut2zvZKtrwuoBRF+CstZJ2FH2nG8xlWfyaN+gcuyiiakR59GkdEnj9tfH1ej0MQx7yptTWtdR67ty5k5MTEdnL51a22jsYjo78Lb/0X37+l/7t//gfv/XH/+QXT48fXbqGC2eR6t7Zs2m6evlTjx5+1fPr97/oD45s75vf9cd/7WPXgcIipRa4MFniPA4jOZ586tI0nX7T//Ln3/RXvu1pd9197eh00soiOY0gKFVDhQmoTw7mewiIcHWLe7J9oRyUJAiBBI4g64HA36lOdl/A+TT+kfs2s87cEZ1DvCZBNAr7c2ZWN3ZwYvabdtIcDrXuVm17Wojmy0jEpm1Z1mI1MTFTKezwxA42M3Ils8CoujujP2VC5HvBVmdqhl4CULO0GCMCGExECtwTPv6xTwS9FnCRXKuKSJmmcVxc+5yn8jvPeeI1lGsC0bWc7ltfvbdc2RzUqnlJWKEMz/sMvvWCbhpE2RA8Pg8ZjRYzZ7jP/PJOhZmRmfqgN8TtRYaogAeWqIHiiUA4orYTiNrjsL5uMzOY10gx8YG8HbI6wbx6WG7U7WSOOicq4n4UN97qwi7S3aJtChqYV1chDjUkq2psiUVEduEec/IzOFuXYybE7zjcCEFmFfdBxJ1rFHLCVtvayj0EObYzz5RSW7IQ5ZxjshesxwDWqnvgbNfrtcCYOVymiaiVGF2OgDsWunUh3eYh7oa7k7n2cx+P0AhwJw20tkUrZ4oUM9LAJTE7QvU8CqTGR8LNvWzwoefXLG51oO/adKt57ICI5pK19ZGlIenRaT/VTR3cRxLb0Gl9JNiaTmbmIEMXrVFHS6cDzv+7yENcuVn3c40K2pUAJ1gvw82NzIlb5MU8MGAO/+PWy3bNJmbO45DR5cmjBClh+mQy5GaT7G6w+XSGweU82GSQkXvTPe+xmijE4tOODdFc9ARKAEymDdsySJpT0VwJRaSYydkeQgGuDjeH19i8BruD4k7CKPiA3EHUvbClAJznDouLB8rMARpfLBahIwpgSCMzN0UX9kBszafCe/dctIafabtmV4U7MHKOwELxdsZ03RvsLt6R+Vd8/bgh8eExRKaAhQjPIWM+rk2zPjWX8jjnbR7DJCLmTkwBbEGQVUyhFpDyOdOjl+CANXs+GICUm5R65C106zOAMouApvWKufFodCrjOB7u7a/X6+Pp2v7+/pnD4Tu+97tPrt24+2lnvvlbX/2Sz/7iH/2hXzw9mS7m5Up1unrl+tWH/9wtv/Ktn3PpN688+y/+tzOWT9x1GBLYoSaUmdJiWJSyunz5ic952Uu+87v+5mte+/Kjo/Wjl66KiDslYFws1+u1C1zYNDRdotAkuIfosfWXfs5q7ACBrK3eAaiDzE21eh2Wi7n6t51hw9wVzCk28IPcQ1ngg2zHcSj+aItmMbKqlXMC4HWm33vQTmNm5h1PMP9coPU82nMqzQ1A8IbBIINR20tNExEh3SQ/4EzSy1Dv298/EujcXYjULWC2DzzwEDMnlvWmAJ5ZSlEwl4XoC072/8OzBpMbw7TkVKwsyuqPrS8tUjmdeCle/HTId5x50cuGw2zd+Mu1gsh3KhgiMqKAysYBgzBvJnbUqYAp5wxzs5paxtkW2XNGQ1U0oBy4tkRA7jGQn2eIFnp87g4nEnUDhTKQ9B/tiKU4mq5o+xlV53aXiJKBUrBgrTESY7YuEAbF21jcTNsCzHsy28038cZGlFezYIOUAH+PWdUklgdutZQ0DjSkTDyvnAMfKxB319hINsSWJ7THHFcs3a9QUoqaRUt1bpzT6LGi5WoZXd26bE1Uc1HROHeXkAaabVkkJkvYGZk2OVbaPqF2AjlMNoHIxDvEqjmoKZB6/hCOwsYpyUhtWVi6jmicIJ9pQkTcVwMkje6pbrWG0PfNqx0JVr/ND4WZA15fa2XZEm/mX7Yjrz3fhvji3iwQtiUz2J223W3E0Li92tcNs8QENYiyWidmzH+RG1pdQIjx1sxYIyI4uqwfejR3IoK5MIdLGBESMXXGze6rHnqcRF5mZSv3UgqMg6UTICNVrX08ED83ZCZD48bc1KoaHDLPTna/OJjYmgxkvEbZJYq8mClJpwCMkluAa4JXrVwwVTWtbXLf5gSRRLGDoY1JIACwhCRHSJG7R0WGZqZjpqREfzSOpK5qm1KK/tgdzs1rnSCJEubhU59ymwVtn0SEd/YpMXziJFG5CxppMhplzBK7O/MPACw0SJ4rACISoaJGTMwSAp8AyHy52FPVRBZiZLQj45CHtHdwIBv59V/+2bf+xk/dd+/rz9+yOHNw93/9D5/+uZ977y3Li7Way+rOg8W/ef2TLzy/+sFPv/zdeMPTn/fQxz72kdX6eD1RSmkcl0y8tziz3tw4XV3/h//wu7/+L32dG1++dOKQxeG+lVpXG8fgk41pnEydEpGbmxPIHL59ja1sV+PzQYp0KCIsVGtlODNL928NlEZUndQhmXMBvc3E3MbU3Nil0Xb3rZbHNqy9R4lQUX2HSNIuxsxbkdCCs8R73Q/JHOh8e/0KRU3sFeQY4ICYQGNGqvHX3KzGHrCZAXV6ISXJXQOgDU0DuGAuwgLmlFdXTx9++OG9vT0ickT7mKCaUjp66eNgLN55UEHJ0+B6lOQrN+tXbE6v5+lcusALKaXU2+/ml7xgr+CY4L2P2i1fIh14oM1BjdhZa3C0oVrVjTTAPClxsUJM3HNwQ0G5NSRsVENNSICJKOeh1lrKhnuuCckRY3dY2yrP3ppu0e45duaCsdZPzUOhwd/MTIkigYNgXuOqkqQgg83F1xwvrA+duP8nAI7mhwx3chjCIzYWGwkcKkXeBTe2nSIRRdvkRA5Pqck5pdy0nVv+83aP5rObc2aiVZloZw0Tbjnc5LMZQOkgnVjLhgujV4/MZISYoaWUovdtPy6UqXd0AVt2EYa7mpE3+dZIJNJXBd3Ftse1Zhpm88Wj22JHJvOti2Qbc8U5hjAxibRso6rCzGkr7DyPs+YHlFnCEKKWWidj5iFnNEovsZADQm0pWFW5q6850/zVY3RG1iIOEe1iRuZec46zoe2MPvmULouRbo4vQIO2tUTVd6UAGpEmhKKCPFctPMWCsR7s6BaHwLEfCQhVA1oHqiB8y/s7UGuNvDpNU8QFWSyYmYqGJQkAyaloNH/Mwrn3ygIyayMQ7FScJJyJmEhn3FxDyvTVace1BuRpU0sOtzi0AE1EQhxDXgDaKf/zBKg9UGooBO5qcZq3ZG53dUCtwszXNfym5uzr7gEs8KoppUB18ZCZuSmQq1Wd0jgwKFRU3T3ya0gNci+BI1IToG6BtAg64/zoc07aN+u7RQAR6VSFExGnFidARAznjotsKIudppCZq9t6PQ3DUGvJQzqzv/+BD3/k+7/zR55x7/vOHdx4+FOPveD5L3/s8q//zI+/o7rIgZ5sHv/6z73n777kQ8cTfc3PP/ODK9nbe+dycXDPM+7mNJyc3njyicen9WZvTy499eCNo2v//F/8k2/6pj/z0ENX1lM5OLylFoUagw4PD09PTzdFAZYhM2fyOlfYkQZBZBpmBu0mbKe4wqlrH86mrnEYat/0A1D1cBcDEzTel4xWyhQ3GDnNg4S2fowck4gEWs1gVqPPDkJBrW1biy78IsxOqJuyGxwie2vfv4TWRLyGZF5rVXNXY/YOemEQc2IKE5RazTWQvRB2IHOOj5rFGqPJiVeIma0qzEl4HPNDDz3y4IMP5pxVy5ByqDhE3emvuiKXxsPHDq+NcnaNkzS9cEOv06uboSaX62njaX/YDPufed/T73nWaW0kPWnK2g5YCH4FGCosooNmAHD4rESIMFPVEq9Y7UpK3d83pLIYCoucAGdAKcKSi3CtG3LMCgHbCiDoYaHJHbEWBEfDbjIBDHMnZxECWa+54wil7SQzCm3rhUz0mtYUkeY/07T4OxoY/UUtEffCtdhdQ+gypXixTYiIJQu7J05edfIKJslJRMLMlZgINE2TJJYkCNUttIKxLeeIUkrTNDmae6uAgts6aZs8R9U/x33MQhYOMxvyEJ8cd8vMNEyZchP/66aPTcNLQk5FtXaNXwI5e91USsJNLjVEngOlNUehjj/HTWAoYprLmkQs8/CwWYZ4tD61m+ySIzfKXXjVs/cxdCCVWixwTHViIhFJIl7dqk7uYTFGREkSM1Pf3NRa1TQOIvf9DYAwTATmyS8FNDjquxB5mPPE3Ap4X5LFkwqPoN1Ji7sz4GmO1/3TOQTuiBQsEpNzn9Fx7ilQV8wECMi2H7hd96IvFJhZe2EuXbMzrpm670FEw+oWGzsNy1VYU1Lp7fiMkggtmhCeJHUrmmIAENN59yQEEgLDbZ6+lFLMLC9GnQqlQHMrMw0pq6qup5xz9OVxQ7R7bM9ZtmdfCT1nT1F4NwyXuwuJM9d1uWmlCoCplCJtcaxODJC6ulZyUJJsbGabzSae+1xiEhFAItxm+H0HaWYOD9yfwkMjNuRplTz3Z4rt8Dm2HrnWOsjQZLhAGrI5HcJpVZlZoU3OOrGBBCIimzItl0sRfvMv/NIv/NxPy8Vf/uo/+7q6vvbLv/helFe/7lC/5dvl6uMnD1+7cduhf+0L3vfWJ2759l8/e7Sy5fL65ctXl8uzz33+fUPew5N89jmHDz/06RtHV7/oy177Td/wv7zyFa944P4j0GJc7K82axERTcOQNrWkcdhM65xFyMinJAPA6tXNQmQ0yOnuIG367egSbyKi8FKn+HbDMKCrc5iqiAzDYO6qk6qDda50VWed9uQxgNOoR33eAc+1b8T3MACOyK5qnAQQq5O7B70jSre8QwBpgIwolPvApl1/qSIyDoMrlI0E1W2qJRyyRSRoc0ScjJiEmRt4ofk3s3XxanY4M5LUWjPgTMXUYUvGk9evnqxO9/b23N1MtVp8kpnWl13ff8+tfnjh/HVdy7GP/IYb6zuWj08TJ9/Pg8hUbiyWh5/7mtPieZp0ECISFu+TAweqaZ3KkPK8QTcLAC1BUPs0DkDsTKc6ASTEfdjQ9KtTSqQFXdIAsbkzd1jKKf6ZdvhB6Pu4fhg6IpWoaiEwhW6YOzvYCYCkJF0ZiYgSw92QOPriQJexyIBJMwty2yYS0MTlRYpbWO5kxN8CDSHR03g9AIKnb2ZKIGEGiSK+GFg1hNOYwSDHYhjLelOx3l/uAYTqtRZmjqwWLoGzWps5lsOImPo4peXo5gLeE5mmSdVkyJykTiUugDzkTlraGMz78ETiH3gxAvCqUynjOEaFEjPblJL23J9DaVndmTLEFxLKvW7mzJO1Hf5uckLDGQJMxLEb4HCpiyBbvfY8zcJMOc1vde7IuMiEUQ81RIC5wZk5BbEx1kVMiDEmEYCcMzp1x8lcdZbiiYpwGBpzupSyqzgRh+vmvl+YuZjCuz5qgPOZwERqiaj2zj7O4mq1yuMgWXoNxGaWupdieBiYWSQwc1N4NmAyESEzYa5Rh1ZVkDBbVXU1xyziQyTqxRiJ2NUUgYyw3PGD8XATE8PJTVJer9fMHExxBqWw+bLaU3gD+pFwdWNKZhoWRmbKzKGZhUSxlCUDyNm9lOLAyEx9ADA3tZvNJhEnp6qacq6qsdonFtlfaKnuOyAydG8GokS82WxoyOpVTUVkALQUY8K85nAytcX+XkAjt/mX2d0D/UsEckUrbin6k8qQnHlzkyROnRoKTLKY+d64cKailZkHYrc2ElF4MYWqEAtIAE0IEGmFK4NIxMHaFvzVqzaftLDhassGMhfCpIVzdjW1ukEdPYMXTnaQ0zjSP/jH//pFL7z7r3z7X7hsz3/skj3jOdefecv9X3zt/3zuRTs83LODgy/cPHEw4K0P7339zy+9LrA8XZ0YD3Vaby5durTanG4mtmJ33v7MH/zHf/lPfOVrV6e4dn2Vh9GIi9boQqpPXjURA0xprGYTGRG5VAEJiUvzKYusaKZOxEDgfufaJboF6TWNhsyoGnPToWDmcczxt8xdFkPcKOp9thvI3GYdFcKmFnePxjGzcOZSzN0ZVKsiQd0lRM8ocR8Xxv022KaWnLPkFJD9UkoSiZ0OutFhHKeoccM9bsbB1cjotVmysES8ARlSzuYttg2RO9xV44aEDStcjYXg5B6WusIaqjNV3cWzqWDhm/uOzvzgM2mqTGWzOPMiv3rfhUfr0ZLdVTKJrlcsL773js++b0yLDZ0WCyyiJmIQFVMwyZAXqAar1ZmTSI7+xN1LNSICuVV1d4EQ0cg5XnndQklSbDJTSsSuqtYhJlGs05AYxHAiKHl1J3MxTszupPCYybl76HBZCbg73EvoZofebynl9PQ05zwMg7s34SRvznEYUiaiUksKdkoUsyLkwV9FVXUCk7hbdROn6paUQa7U5yYNAcg5Z6ulmTQxEdjcq2k1zZKYGdb6JHf3BsElajPSJjrNAUtrntQU8+FoyKLDdHbuTjIRiMJhkKjBo0KVxNypc5pn9yTqP25uBVoX0ne0MeuYZ6eQUI1xAqx3eHPApc4raMu2na0Y9V+zMGn862az8Xk0bToXVsw8SJpzITqzTVUDCB0/y4hm9hd2VvJEBKLctMIZcaSqVY8Nljg3mfJ42bRTmEA2S0j2NOzu3rTIt1OQtvo269vrnZ+eWWAO8hkie5NMbm/043QlClcUn2sRavzqEBJqIBF2JlBkqVqrQEgQEt4CkpScqZrWUrEDcmFJSXLay/GvHkzxEGnlREQuflPCTsm2km2Y66F5Ugr0xQoRO7GwMHEUZ/3Jxg+KlfY8qoqVj3e4e91MQiwpzedBgvgLyiyr01M180rRTtVSN149LL1jPW8dZhKlw81UE+5VlHbi8ZwnWu+OmxY6c0UfBxJqOlDI2ELYGawUE2wAYx7iEcScYO4txAGHkZo5jIrVuQzt99ENDk7CKkxaZTGMm7LKwpn3Bl5DaTNdHcbDZR7/3vf+4HOff+df+LqvevLx46feffiP//bfrOVd/+GN+ZaT1TCV88P1TOoDHjxK58f6ZffmN38KStUsyTSsV4+urj2+GO+5fvLIZ7zwRf/tp3/szNnlY4/dUFBKydyYMOYUYzABQU3Joxli52JqapNO8wsYty7tYAJ0JkD0lYfsML5sdtaat8Vqc7YWEYGE5QscTggZQQXIYrTarJDix81D/uBtRnvAhmaAbaE67pDtBhIxLqJOLWMeJMX4dFNLzDXjNLh7KINoJ/LFlrDNihwuoUdr1v9AyEyycFjn2LYKYc4NPzsX9GWqtVqt1ayacxzpWRV5eukRsvM7zms5PZXFnaurX5OvjcdrU6m+ttGXEE18/mWv2rvl3FQLc8oha6Vaw+YzMt6moEdU72oQEg1cCgI9c2qRPObUjWzZIa5m1SyscVhEEnWJfm+PcnO6ymBhhrmn5stG1nIFzdC5bsvLuXvPMC2GBRHhGHA31VLK/NakGJeFMAd1L8ycUq0VTjGWc2/rBReGbZGrPeEjpNYwk8ollPfa+C4KqEDZxFIRjKBAzJ3WMAwOi53fPDmZA5+7GzDnVKcu9dujYVOL7mPkyJfeo2cs5wJOJSzzynPOWO7kDM7J3INWmzz0kiz6j/gWk1avLjlFd25oQxjdycRzhLWb14e2wyXlHcRME5PqpptzoE/E3j/H+wzKzChJI/QTqE1qez7ozyXaqXAQbUzwqPAa+NpUp1kJK74C9eCy3qwclnNGh0RVN3dLM520I9KYSFhiz6o7dNJEDGbfCfrzr/nYRR5rxU2UIzs+RfM/UGdfxEYnxu2qmoiFJDiWqmrtYpITp9SXati66jLzMAxt2NsVUuZo2FQ75lzblJwZoWm/84dbfKM2pkbTvaJCyszO2+pK4Tzn3dlRY6c/LlVJ4MHqdw9FwCFn6y+8NwFCQG1gmUxT7Nc7ZtDMMouR8U1ZrpmS9ju+61TTIXLwyKM+T1l2IAWB7VRVIoSfnBE5Q0sREXRQbs6ZLCT72R1MlJjbX2Ewe63tKFrkEm1a4urKgmKa8rher8dFFrjW4pSvH0+333G4t5Qf/Ec/+vx7n/Ht3/ZVH/vY6uve+KUffP/vpZGffZiepuXcheXe5jTDFWwkF5Z6rONXPvPKT3/iQpkq7Bg5j3k5LIbLV979hi/+6u//P38wjYsnnrzC+UwkPKC9jEIQyeSkvQSjJEI8EDnZVEqxMsMaVDVU2YWkF/AwbNfAIRxLFG3LPNLfUga258e8ulXTxJJiW0kIWlG8c7SzI/QuVOLExdy9RtAIqIGrNbiAN6zcHJOr2rxaMrONl8DnLxaLMMLz/osDFV+jS/P5VAR+nXPiDuE229GBcJm/Y/u57ARkTkZW3WLtnIgTcVlvqk7uydScGEhCSRLVV1zja8k+OYxMCf75duNZ5dJJnVajpimZKNXBLpy/7fVvqENWXbOShA8Lb+UrArWqM4Bx9nPTqFJ3EGo7W5L2KnX3Ww/FISCqndSZ1d6xPothyQ7T0gwzkjhIPNQu4FZ9p8tqryGTVoWDvJe9wJiHw71992YI2zgM7q5qgUZm5lqsmoavpRefHZBIOFg07t37sInM9GfQTwzvgEqAti1r3YBwEpnNOlpJKLEfbfaKcXRshz3Sbhy3Ozwnj1jPzLd4TnjtVejlJIRjOY2c6Y/gqgAiqNb52Xh0lszYaRQCHWdmZKaqdXaOCw3Irr+PDoid78Ac6LdvoPtsPtguPXxudzJQ/E0jGKFxD+LQlLbYJqK2RgLInFzmO0AdIufuyG1rSESUJWD7HEDl3hTOVU60+NXNahERpjYV6JDMnV+Nse8QNm3DqHb34kbtlA5zGwFA0PRM0myk1glIM5BtvgHUJgo78Sx0NhK7k1kDhcY9DQaz7Jh0zR+kcCsbxSweT/PVxgKPd7Zl6Ix29xgateKG+0a5hdcY9wAOnumStMPeRn+g1ZThslMeMXNmcXPr8PJaaxIRafB4SYmS+DTFx3IThOeoLqP7aojrrri5fTLRRPWvuhuF26vhcMJW/GH37xJxSKQJu7u5i7a9kjTFvnYD5+aglgoEtpcjIIAJQpmy755wtdhADQO0gjmVumZxrQaEvArddc/B5Qc2f/+Hf+ALvuTVX/knXnvtqdOf+q8/9sEPfPCWWy4O2e679fj69enW0YnpibUcY3l+wJ6c7CW/czjeK0v1ZbHJ6joP505OT9/017/z+7//+566oqcnmuWcg0RSrdP8HEWkGuXuC65wqDpzOI8tU9psNm3DJwwwgi1a1To9VGcsj4abtYc/Wxs/9Ez/R24ygES8sVrcnSUw5wIO0OwcyuZw1G44SIYE4/BcsU5t8kCHzTzd/qLlYZgj56zRVt1stY49znZdWmo1a5zjPsNjB3XPkt2xHFMDVYSUUKauaAv3GhevKWdhCTVYuItgsRiC1ODuwbEnGCDTy6/kd104nNKV5C+yJ/+4PrXarNbDuK9eBhKm1UqXL3vl/vOft16VxGJQjiYkJsxVg1ZBzpD+/qJHkv66zRcPIHTuAHDTyTDr1MRe6AT7dJuDw5GQg3XJSSQxNfpim8jGNBAeAP74fDMNzc4o+szM1EHkHYwZF5Z2ckOptVELzIyTuCFIXg3XxxTNF8+piztIzxE4TOvy4tt8Q83qXEA9cxMU2mertB3puOu2QtkWIH0DamYMNu+KTl1xu9cv1uO1oy9fnSlCCfc/Nrf/nIT6eWVGbD+ts0GY2YgibQOAMHf29xyqonltOn9mcSLnlDZfzByX54wSHwhgbuuiT53Tf+TCZhbWUYlGUZa2pTIAmh2f2OcEMMMrND7QiYg8mLU7Y17pdMz4WSGKJiJ5SK1LrrE/b8ew9QcQ96ZlV93M4NZu1/ywGiNrRqnAzZSoi4xqB/rz9iu3P0mBMoNHiRD3JMau/Zn2HE9GqG7S202NfABSM7ftPMDdKYmIOIx0SwjevdvL5ZJmHlr/X06NCjXXcHMwbW+1eSQeoqZIM4dL7JR3s163EaznPO5iq7E4dve6mTabTeEi4yAi681m5BFMbkgS1lisO7znqFl7DVHNbipDdyuM3SpwvjAnWHfa2ClDiYhCozR+P+ac/QDLnFTaqYtXUppon4V+WMSkXogwN8Vy7hPast4kGROxsjBzmaoSSPyOM+nf/buf/sff/z2nx4/d/8kP/73/93c89tClCcOFO8+N0Gkle4ejyBOnq7LcY+XslYWUISS8XC4vX36caS8d7umpnpSjTb3mZTo9xtHVaRylrmvFtFgsMrcmj0iAVEoxKITD3dLMqqmBZhtKI6gqOkTO3WXWggXCDC7etbgDu9omu88Cto0b8TtLyrVWrcWSSU4QdmaDp9puuHUZh/45LCIxkHN3K5WSaKjCNXFWoE8EEfY2fZI842qZ2Url0M4sbUcw5ExEtc9C4jdTg/vFa95+IeZbsTnKmZmJuVvU9PmK2jRNIY/YfjRhf39/GAYgBAMIsFKKpDK95Pr+//WM6zrtbcqX4niP6xFGcV1rljGL6snZs/d86VfQkNIxbPAmAO9ucIWLJCbyMJbtmr4WsKm5y+oyrn3G0848M2KjFxlBRAQUpnwxoqxuXC1itYiEnQa1OjMFUYBBwf+MImxXyonN4Rq4OMlMzE0wSrjGKoaZmZPkFL1wZonRUDxv6dwy5yZjNNfv8Q/SRTmYWECxvW0/vqpZG84Yw4Mc1heoMcYKjWLemdDGvw5IUVz0XEWRVDa1zNnxpvjST1wsC2PxDqYu9L8tJA0e5h3uTsJNgMO20Wc+7nOcJaIS717j4nsHIrJZI5ijDzHILLEgb9eN2wPRg+BuNJyj8CyMFb9ahb4FWnY9BN0yXNGpH/NzySzF1Hd6jjZyn9pNjKvst0KNtwCcuVoKnGrUlLGDbylTW9XZbk6oIhJA205rvmPo/Jl29VsqhyPSauBTrJ0E7LQIu+VLhBVwb4IjusyMQ2lnIHyE2id4KKoxBabZzMxDJzwRM3mwA+cH4e7Tar02FxEZMnc5z5QSgUAM2a6T44Fyn/XFRakZkc/Tkfl8zp8/DEMUanF35kbWokDvf2ze5kaHnVIqdVIzZtkF3G4DOoJ0Hpe0BQqgzxu8c8qre621rW/6Q4Q7i8zVtvtWGw8dt0/ebJu9d8xxkVGO55yZuNYahHXM92SWJu2nov1EYUpCauxEbEoVLl48sTtjHA/+3nf/6x/4Z3/r4q3lzLlbf+mX/+Pe3vLC+TtFN5XAlJOkdz1m+689uHZyfGaYbh1N8wYGy8sNhk+uDr/sq/7MmVsOfO/S44+986knjk5u8JNH77l+bbXcHzZ6XARUrJbNuFiQe4Uxi2ooaSvvoDQAuHmFW6k557hj2p0BOaCmf6QQmWd75rbDvgOA1Hfk0oSAWj0HzyxIsV+FVSU1Ek5JAsQ054z5cTOoTmWzWS/ykFNa9yLSAXKob9NneG5an6ygl0EApmkaJWEn4s2xNILA/L2qh5MhWibuXypawyiq5oAFIDu1LifgJiF83mp3cE4551IqYCJZ3WrV6QXHvrTFBy4srH65X30JX79UJk9MOB7ksGJcb3z/FS8+99KXUylC49oUQdSiKHipwhIzCTuTW0UX6vEGPFUzQ68Y3B3Y1qbqZOYEbkvAqhqAmD7KRkw4LE60MzNLajSNOZFbfKYzCGlHdc49Bd/EK8yUlZljP0Mi4XcXnUnyjt0NSuKYsvXxlLs7gRrMJDXKo0/sHGLRDZ8DdyBzb3m7pFX7nhog/pDZi60ep9DUide897jo0CFvo0vvHGByJxaK5aP1ZaG1hwwBwZzmw0QANxnIuJUtu3sD74YzDHof09Kowsxm17lWxXDUPhaWhVEKwFxrJQmSGeKrUdftq6WhSXfD5XwWd/Nxu6rURLexk54BSBfEaL9pzqB0cziev6C7wzGLN0Xeap+jFssFNQu7I6L4Wze9gbFS6nOt7dicHeaqqkLDnP7ZGxADQJUuMTHTSwgAwo6EqKk4M5E7YM4psMdhggDsZO7dYwMA5upO4K3BZRMB2FpvRg1UqQ15oh2f08/8Uaqa0lZ5xcxUG0E7iYTgdtwEr1pKWRwOm1qD6TRnNY4adqqp87wD39S27AbcrAYVP33+cMRwfpbmFgKTmwfYsgdfrNdrMl8uFierdXXLidaljOPIO77O/89iZb7Om6I/YERJkntzlmTvFeoOsiwSTHxBVaVizgHxRjT3tdX4sFKIKAy8rVQw58VYtbhDmystSBsuhZhD3E37xRARkgio+DRtypiXTATn82eX//VnfvGf/tu/+ZJXHWzWuPbo4bnzd+wd7B+cvf2hh+8f00I5IZ186nL9/dPnfsHtTzz8xCO3HdpyoKdOdTWlYVj88LvseV/w9HtffOv1cvW+V7yAaHV67cyrX/odeQ/Xj09YlAepG/NSggQSxEVAExNC8cZ6KQmKTqXJtoSyW85BYjStFGnYsUU5mIcXC88pfKfonENcL8IAIgYVWHgIkDmKuirU2AJyse0K5qcpcAHG1DDz8XoOw+BVtQfd3TMwZ/E51KQhZx5CAp8oXiJS99DMiQQc0cE6n0K6EnUmsVlUDgBRLaXt2vqPJYugjZRSQjKzGts6s3G5EEnr9TpncVcGO2zzyiOc8ua95xZsd5qaTfskxVVLvp59H1wWi6e/7gvywb6fTuoTu6BhaFoAUzfb0g6zu1r3CoMkZqE2uwqElhAZM9jhTLXfxiw5zrO7iggVjel1SyPsgYJmB2eVnJrgsyNck4kkksAMF3UKyVcnojyk1JdxkdfqVIKAF48mEUHNwtvcwkI2Hr82U2MDPBiowrGyNlerCmdOWR1E5uay9dXaUUkkYnPmpvagVs0sCYiZnNqyamdjNweF+df8B0jatF3dVC0WdU4IPxJW7x2ZKTkBKToVb15y8WYxowQniDnCq+SWSMpU53ozxr/BBLAdiYOGYwRSStXUzIRYCVariITG9aR1HMcmizgP2HtfFWPe3dj3R96Z+UVtYIeeaZjIyDisNPsvswbccKBqjT/vMzQ5QjDcBZAE8KQa02AWpK4kR0TzOjClFOwsMxNJOTajAVMPgf5+xXGh1hVN5+ufC4IGUSeCtexVHZDmgNT/HMJ7KlapRGRM84zLrOnwoX/ZeO4xkDBsv6dHrRJjusxmFpQD2pEMC7LsPOGI1X6cMGbOw7DZbOJljsJuOYyqJRqIYFhFTTOkDCY1U1P1tppxwKxBxnYfJfV+Hb2bmXRa5MHd19UjJDDYzIkQNM+Ukji0VFIfRLTPCclc5tY2tVC4RUHvaJJ779Ww4zJi/Uq0zye8Y6niM+cOOBrgnVlmr2gN3Cclc+4PTz2wNwY1QLMEjbfRSyNB9MubbMWyyOO4Or0hhqcuX333Ox+98sQTX/GnXnb/hz999ZE0jLD1eHL9+qZOA2XgpFo6PDy4euOJH/nDW287s3zWwfqTTz2xd7A4WFzcnJYbL37TJ3/25z71S7/4K7+8QjmVvP85r3rxd/zv33fLxWce3biRiJKe19UpxmZsambCDHhOyWql3pu2r00UFV4YrYPaVq5Bf4mmaRrHkYikfzGP2qg3LbvcJKhpH43OUTHuz+BUzQ0W43oDqlvRkmULL9p+TquHiAIe293PrGUKBxN30ibc1Gq1diVNvle1xedYEnF/NdA012jmH/M2c1e3hIZvkpQiVsxxvp2BeZMY0l3E1tnwA6eVqqrmnJMM8d6VugmhMH3Fjfzuw/2TTR3SP8fyd/3Cl9XVnayU9s4lN+J04dZzn/Vidl1Xl1SIxsRZde01jpYw04wligFfwHh3mpMAa851KqDWKicElKTdpRRKyXUbtOcXWVgSsWmFmpGKACSuRvDMogEtauyaCEfC7BPUt2hzSiRDSkRYDDnsjgCYaqqlhPGzEZxDnsxjx2FVHc3Q0LWCmEXq5GQ+DIMRQhvXqiLYxIQtGEGkmMbbKMNgpepUFymBoEVda+hytctzRBXGRETcAE3kWkM1Rtw9GcipmI55CK3z5ETqDK91QylZZnUlJrYuNyLsMfMUbuvPJBJtq5s4ORhd8iGuJM6KldqiW08wQuxq6Oi4SL2xaojuQbWyc6AZA/cfibbpsxNxEnCjphFT4hQ1NQMViJl583FyTFrNPOXMoFqrkfE4sPDpZhMlZ8QCIQI1bHl1kyQDtzCqtYmkg4hj92C+ZLYoqGsQuT3nHEsH6i2sWWkdktvJRlNKDmdmdSezJl7D5AQRoQovZRwGZ5qHmT3WCJFVt5QYTqpKKZsTtM7j3BDXFSfv6oNM7EzMKfA+TETmBBg3nJq7o6h6dZZaK8aBHFY1syjcXFNiVYvmWFXhzkzqRl2ymJs0Y+sClZH2FlqVQu3WNBxznJ1IQh0lgdw8PEwmGHnQpBKMVRVt5RwVRc+FBCaOvcAM2DGzzNmoeckl50yiMGVnEfGG11KgWs0HSwDURYgSc1igoeuQzwMVIso7dVBx9W7qYGYSIrBgZgGMrZV35G7uOhVKWSRLN9HjxRASeOwwZmcRSq4O8ig13B2JBeJVy2qN5TB6w8h6FksMhRiUqjkIrJMC4ODhsIyLw2GwG1eOxOxf/PCPDqN8+1/+hvW0ye9+7sc+fv/5i3tIN2T/ItZP1I0Qcyk2DLy3WL7kxa+4/tSNb/jJ61/64ue/5o4XfPxd70i33/74rV94+a0nhxfTgvYf/tR07dq0PLv32j/2Z+6885lPXrnGJO5A3qjo3rgsTXul9fvulZnJKElSdm26SpUMAyVL4gDt8BQinEKaInrq3gMAJq1hxwlTFqa2N22BxbRWasDJxJKoOcNLLJsdLR3CAQQv3/pKzqy7fwS8v0zc1pxBGiTSGpET8K5+ysQ0BBvVXaeigEQbxKJu1ri/W+fZOQYyCOZuUVc1AiqZkbOVqO9pkQdTNRYzy0ylTjAPzJc7uAELM5m5UXIR1icuX1+dHmdJtZRE7IxJV+UVR3v/5q6azctGPf9aqQ/ccvEF0/q51y/dm4ZxdXp8z93Lp99TJuSRsMbK14fjmWEYpk0xYpEE90bNIaAq0Q75Tau5D8MgCLlJh7pHmRsu1oyQM3GOUqNGx5Vjv0sunBDTIzcjZSRVtak4a6DQg7vrMcyVHM1ab3ZBkMCnh9uAAkXVgaLaNkEa4VHybs7nkKgmgyHwkN6nqdqk9lsRZ+4ACYl2Qb44FrXWmQAXENNaa2hEzIhTVdVJox2k1ptugbKELkvbmlHvxTUFWyPUmhROzNAYOOyIyzcE9E1IVOz8mrP+PJzxvv0NRsoumG3+u0FsKWisJGr9IsUOf676c87eMZbeYTjMHG9RS1HN56ehQYJVddMlBiKOaOYbbDablNI4jq17ti797FuxazOr1kdJXa3U+/4bfSoV0wioxWI/buYc0IPFOPsQQ40ASQkOV2v3p3fJgQidtIYY9+4URKt6U+Mmamx3dmrInbnGj4YDfboAQDs4KLMArS+coXZz9+yMlJg5lINqtcigLSExx5hK2tZNlYe8KVMpZRzHuXFkZkVzH+KmFsJNoMqnMAKZPQGpT0fiu1OXFHX3sOClQHwEH19N3QCqWueDHbzE6LAXKVPfm0pQqxtOp33TMjVpFyZxkBuqG1HfuTsaj6sBkrcnp/W+3uTTtSoROXl1AyyIjwZrvhDu7N58COMOzyLe8WkeYIQOhwQ1O0MQizBR7RLxwYohSSwMUyaJ0DOOOcKFmQ1Dvnrlxg98/z997gsOLl64/TWv+Zw773ja7//eh9//vt//5KcfHBZlfXpjdR37y+ODxbNX0w2F7o0Xrl6/8oRd/7Y/++2/8daflTP7P/P2T7z91guPPXHbU+/4g3tfurn82MnmaDh7VjY1P+czP+Pvfe/f//zXvPLyU6fjsJhf4XEcve9HrPN11KzUmnNWNWdiNKufLkjwPwkdmDWk1Gqn54aDRZTdDUVMHLoWcSerW5Q7MK8W80SX6IRujksAFouFdx5w/BLinHPRKhR2XdSBI+xq0iNnqBt5H3iOKQPIYSBhZlW1N6bkOxCNPqOOk1zM5uhnDX8X/nvhTdBaDjMj7qi60DRGBjHgmhgABUsBwkRDSr/7tt+5fPnSrbfdAg/moNpnFT+r8jv7PG0mMnM6TMOlE3vA/NfSufNF0tX1N7/8c+XcudXR6dJ445rJix6HN50ZYBqAwWbtRQh0etzGCkf4oqZ+n7mJVMfW3Fqzu52TtfFYOBHCqltMNfqmoRFNravIhUVe5qSqppWIsgikmXD3u7sFCrh7wF+qacwzhtiI9DzE2AJqWHLDaEQGjcScUnLXKBlg5k4KNAEWbi6Zc/MX3V5rEOGY+U5wSuJhpdBtNDrOqy9uGarm8Ibzh5coz/uEDcCMDg9ZM28QOw5nEsVNTiONQ2otSzOzEfEOZDE6lTmTBbYZAc3tgkHwNkzOOc82fHOqiIKjtNK1BWsyD7/r+Otw7IgmzFEuLrqVDESUiDFku3nhp11Dipm5M08ULoATgudKO95wZhbC7u4ekWXnKIQjztaehcwh7IScpVZnONTIGjhcOJUyoW+esFOuWe/4Y9I13xNjdLhPY5KxOzFnaTTB+VC6bdMbADerbhHo5wzn2MKXnBuR2hJTgJCDUUccQVN2CNkQYmu0KBHBtoagmEZyTlUrd0l9RzNKsqkEmAWhXO8ONKm/ltvmiIy2/kcgFqOeiEfQaf6+A+yPbxQzmRgIJycymHkok/ccG74jTAE36wg7atZTYEeZr203lNP2KcQBZu6ny5smFkDoJJnws9MdLUzuLgItATB70ARimBd240SpEQdqc9CKXbtybLXUNA15vig3SymVUiTZt37bn/+p//zjj91//KKX4IN/8J4HP/3Q2972m5euPrS3uOU5zz73uZ9/8Fu//MQH33d9eW5Bi3U5vTKMtnd2+RM//R9e/9rPv+XiM3/gt/+Psn5M0nD+3D0veMGFb/1rT/+tX7py7ZFn3PfZL/0rf+1bzp277fFLN4Y8MnNon3XWkLOwdAUoo2ZWPd9VZqaG06X43d3UGIcx0hL6sHr+r9uv2UeazhxTa6MW0xvrzr3CzUyndiRiscM7OhLtwKjFQB9Ehgp4O/kUSKvmmxLAjziQ2q0volmiJN3pdqebakv69kO5ky3nCjjQNN4bmKo14jnIAkqr7kwNMoLEQx6JYSC1lt5AIFdJ1C1Z5OOf+PSwFIO6VWI3s/rKY0zE71569Zy82gSpZTrh6sNi+ciNq694xR974zd9qx2vRMQMJcvhMJJyMeXQs1QdyFNKlBLAzjqL+Vg3/mJmNfPmOdslJTpGek4l/T7E4D2MwrlW9ZlxQ+Q3q/ZWt2Lqm+o+hXYHNbBeDV6teuRg6hMxapKsgflpQY/TZrOJtz3Mkdxb5RXZFz2hujtggAQKZuZ9dj5rfCBijmcE3dEHjoNV0eZzqhrbUO6gFTOLRrbn0Z1uuIu/Gzxx0w3vl0Rm5uwtVEM4MYGhpqYzdC3O8dxc7Bq3Wfse7T1srW28av0Let9Ms4O4kfDmAx3vFXWolJlJFgDoDvaZZeCtdUG8c+hws/m1pJvZIMycUwrgVXwLAYXGLzlExPqBaKfBmkPLfElzctWboRn9SihKInfHDFXrfyDqIS82U2jinqPHlGAmRB6IysA6ewd98ckMIo4RDFp1aeRtbt/rPACAIIp67wOD1Dem3H1OrNSpUxUp1rFqFBuvLnBBRNr1Bb2PQ+baVq2wkJkHhzKOHzNb9zSdb6CwgGBapmmKwkK6FIOZoY+yd6NzBHQEBCkeYq+EpNNvWt88v2zVnBB0ICdQV9tmaz5xKXGthjmCSpJeVRA5mbcNSANd7zzgqqH/CgCBloDP9JhozYkxP3d3Z4d2rGxkYgHZDtCXnIRD2aXpM5hbBYkTd7HunDO5uXtggc3JqpZS1hFhctPuPzzYm45XGD547kK9fnT2p/7/P/vQQx86f/7Wu255NhFfewqg9C1/6/yH3zv+t5986PjqbWcO946nKycnJ17tHW/7Hxdu+ejZw0F4EN5j0K/89/tNb3nJKy68/akrX/SGLz08uHjlqZPFuDSzaZoWi0UxlZ35CvVRR5wiIkxWAAzcVPHjuU52E0m6v5ut4o8qMODQtUu4Mwlj+xzcPYBpPk+eumOpdSRte1xubAi1wjneppT+b/b+Pdj2NbsKw8aY81tr73Pu7du3u+lWowcICUkIJCTEQ+ERnoEqkJBDrBhsbCo4wYBtgisVJ+WquFIuUsGJHedRJYKJnTi4cAxFyggMMZJsCDKWkQ3IQlJLLanV6m61+v2499xz9l6/75szf4w5v7VOK/k3f2l3173n7rP3Wuv3PeZjzDHHDAsAntCz+PlEVtikfMmQQWzHgBsZgMw8Hh5zrgvmJgToa8+1XTfNdfutO/ctZJA0ODLjOC5+GjaGXK+lmUuAKNx9IWOtlXEaJ1ymDxwr0nA639/fjY9+4hM/8IM/9Pa3vz0zL2tKVe345jfHDzyN58ej0TjMzus43MfpHu985ytzvvErvvIdrz3h58Jzxhh+t5gP82RPl+eMMNXjHx8zc9zdrwy3U9w4HbNhZoMW60IiCUe7kpcnl6A4Ou2q5BprPGetp9E4Gr+Uq0GRRdaKtXIfDKC8jZQ3MpOE3lA9BV4KVKErrGKDhESidxFmtmXldzbt7isrdoJyqM0RyIhYwnkUfN2SO/as42gi0pwTNyYyM+dagm3NrFnQrQWfi6CyiYXYeTl+7lfS3AKQnrDiA/U7cS9nJytfsAdjvMR9sD2fWMY0cqd9q+rLZV7tthR3OimniSxuMG744WyDp0tYZ8XMo+LYGoBT0XeFXrsaVAIR/SG3Tdl3hjtXljtxY3OkIiOyI/Ca+FoVgdW7sGIR1NhLj+pDGD4i4rKmn4azxExuaSZ7xfbpr0BqrjSaenDNXIOqc6mdVKb8Okyiod1tSm6jt3qvRM61GiMZtMwryej2Lt2am2yFZ7TV8x7vuA98zcUjMWqqkr6utHAOktSYTloiFV86G+yZc2VUCrWfYgMANzTD/TmLE8BExFo9ChMwJyKDGblWhr7Lyqs3JYc1VKf7yG8sf9PFs4bolZiX6jU3UNg2GbUs/dT1Km4QF7SJJMHiAbn7leu3YpjNnJE5SKOtkqrl8JGIJ6f7u4dzZhpHBJ6e7s42vv/vf+e733v3o+/74Hd95//2Xe96z1d8+dd/xde+EQ/23/zDN5P8v/+5z77znU9//z/72v/y3/jl3/G//tBHPvDK+ek7nr/5xhl44xPHRz70AS6cn7yNZ7x2/9TtxV/9Cz/6/d/zRf/Gv/Vnv+FX/8pPvjGfuB/HoQEPESEIaoxxmYfaefcZ0/1lXk9ONkvgdNNukLvLqL/qO2atW6V7V1t/K2Kls60OhbzJRhTO6Md2ZlwfI2M1cGVgkJVsLezDqaQQEKUob7/2J2RjPK5tjKVa1X4WufaF66PhhjxIwrLm+qU4AaL+pcBNmNvp5AzbeVomFjQ0BKfkistaKx7z+ZvPnt7ff/LheOWVV9ZauaYPn7/++fk/fJ3M5evuYQ6cn8PCnDOZp1ff8e4f+c6//v/+jb/9V//eb/X11kM+2Iw1Tkc+1wChk3kMe3x8PI5jiRLq189vJbKQEXPbkylgychwybvhJsDa14fkTEHE1eJ/+1dLMGYfpNPpZJZia94GOlejhMzoTj4Rr+biDGtSpwL8OlJzzrWOW4rKth06NDcwYCXjm/yxB3fw5a/ri+R1d0+n0630BAVaVUBRKXhE6CLNY2XmsFLzUSunKrIO7rXLm6xdibj12LvtovQD+yPxBvlhz88p46vo0qqpzvvrdDrd39/vUGOttfDSI+vDm9n5fJZ1fpyHJuLtAIqk93XeG6Y3un4nS7lm224mvDvw0H5O4Y6qs7d1o/2wuJkEsiWTUiHPzVLrOxGBZDYxTS8ip3X7+bUOoitrmrqSpx21YA9cOuYOvzZ/rVr7b0R/6uC6qaKsnm8dyMuae2uAG38QVePsELWzhxthzn2G5YCGn+7O97f2sSyU+0ai0hjEJqaRvKxZAw0bIDGzYb5VKnUdzj5O5nU40covG1e/OW/1wTIjoloqh6caOjJzz4jMBNJM/cuxH6QWpkqzGGP41TXUMd6VsH4dWCKOmdJI75FEtyup+xgt13A1xMM1UNn66/ZBzMy80LPb12RXbeKYCtPnvNyf/XRaH/rwD338kz/w1/7ST33v33zlldfe8y/+yX/ha7/2V2cef+Cffe/b3vEpO813/IK3f+6z+Wf+9Ed+/Afv/2d/6pd91Tc8++xnP+k8v3j26Tc/80ZcjjHGwov1aI+PLz71mTe/4Vd/w1/+K9/1Lb/vW956eLw7P2jBnzx5QkCkK+UAo2uWmTWjV+sz/OQ2AtxXZt10c9xeyS+4WduS9GsuRerskgpJs7qtW2i2jI8m2q4oQqXZuPnKFvHeplXkj62J0Yk6IuLs11/0G7m9WEtp4jwOZYqa2CWnpZMPVEJmZoyMY67LEcdkpEM4dEhxYowTYRnYMpYPD88FJpnZ3TjV1UiEc2bA7XS6A8AZX/NLfsnv/Z3/necvns11QazT6XT8ohf5nunf9yRyYq5nvt4cl9M5gIcXePHxT37MPvnWvJzv7MmTE54M2HC7eyXvnj6mtK7iiLWQp/s7O421DvTQs6sLaBu7d7DvDm6v5Bd4XwA3M32vtjSi3vH2FmTnkO4nac2W0buZFydlOGNRndB8qX1+Rhuyqy6EvtQGw5FyltFzLveHVk4mDZi0KwzoNzpb7n4chxoH11oOCMLdZ+XKQ3Enr2lQV3uXzPeZJxsOdc0OFyvLaqIC1o0U37Z0t0Grvn/EWhEjdSUIAeJdD9j50F59/H8r82wEO3gNjafFKkQw1aiX9tLngXFqvu0Xxicyc/v1q8HN3QkemsVtmtPdJSvDfq6rd+n32r6kP3amuNBbmSSxqhKg8jmy8PMgqUHOImeeTufYslC0Zcqjw06DwWx1X9lr7yx/jAFjZA732UMOBi161BKHuZrQKWmu6mRIe8lx7o6nmSEQIrYUhru7X148jDAOp3oqyBUxQBqP5nDGKqgKgLjcas9fa+1pgLMHnu9jIAu4r5ms3pzzRNJokSWqQM5YmSEmQTUrR2pQB9u67ePHSBLZpI/Lccw5709nGx5uIBnwhRVhp9pB92paswrqNzBQZ0CWeB/O61lljdi5HuPdN8L6/SB26uXDVtbdP9+dgOvRYuW+VVCvwnAVjwHSaXY2jcwZN81LPs655hhDZI77JwN4/le+8y//jb/6H/3QD/9Y5iv/xB/8733Dr/p1P/ljH/rb//l3v/HZT/2m3/b6n/yf/qH/23d8+H0f+E9fffLOIP+v3/G+Pxy//o/9yW/+03/qr3/iJ17/yl/6yz/9Mx+Jcff8+cOZr4/EJz7+sT/0h//4/+Jf+1dgpw999NP345VBh9lxHGrcjwjR0zd7sQwO947ctNK5+XCdNGRi7HD8JbitkOcbm+6gjs3+DpbGdg2ogcL0pqmCLrv2hL747Fp+EpwhQi9U+1eUSbPzPSrNSMtIpGdEzMfHStyLKtVISWrGecRxuaAxVYUjty5Hp0WeqpbopnG5qoBmfj4nrGM+AsjH1FRZl8pHpoHmPjOYjMCxptmYucbpDszzCcRBi9PZXvzG5wi88o/esU7BtTIQa4UFja/ev8LT0/HK659/x/3lK9/7wvKNh4fXnr7D0h4m4HfEzExNa1V5CMBQetm9GJUo6vZ1INUewffTvex6X+LmtLBdfStiuQu6T/EE9uWy5nkA1zrgnFMTmWhZ3J5MDgfB4fCKqTOz533egIckafAosPFyuay1/HxClwNJSpWpxsJ4jdrVK6wMN8+uk4lku+2dIUnu0GnXRcraVYnb1K56Ot2Tj+ty5FxzXUTNBbDWOplLbtjdsTEQNla5M/i4WlI92rocIiDR1R9ssn5YUbJzN+AqeRVHxQ47Xkar9p7pZF8eH0VtW12E3tFAZi7COoeT51PkIfKNBh2czAjMtSTeWR1KO2rIcpwb+dkX5rZsv0N4ufBoxg1ZhSo3M3cNvc/MXDFOJwLHDCDWnEFq4xreVHy3LNsRiu60hcnmkv4c3Y7jOI8TWlinoshcGmGYrb4Lgyc0bnLLTOpxjlib3LRPpX5gznm5XFQ2BhIr3N06hZURMWWO5JZUMzMJQu0EMVRauz/P0AC16u4ddmLXeMyMqLJxRDgdAKMS3GJ7QRtTx+PkV/VBa2aKfL+iln52rsvxuOJ8dzeZHH5qhCCiQEjQI7COl+rr+58hcvJaX0CmjQhxrbTp5lVd1tZLgkTHqY6lpRm3tloba2MW7pKqdAKan1rvUl7+pTSCDc/uzSIlXGGf+dTH/+Zf+Mt/8f/x7+LhbR/60Kf+tf/NH/llX/s7fuwnfuT/8B3/OvnxcZ5/8c9/8F/6V7/8d//j7x5/9Vd98IMfOZ8ZtD//77z/n/8TX/dP/9Gv+jN/6mc+8tFXTsw5/cn9q6+99o6f+vCP/5/+9//uH/4j3/7hn372/PE4Pzk/HC8eg7by7u7uchwRcX9/P9fKo1r8RePwnhOlstcY50Qe65KZp9NJ3aRmdrneLyMHq6Ab0h3zlWVpumsWrWh0VCdFEfhLs/AmD9NEk+3Vsza0LQwwNhv0BqXIm3V2d6ASBrbcVa9/16SHzwgD7u7vzUQmSXfPls98KbknjWDjf208I0nQARrHseYqQM7XWjT4sHWsy+WSmeZuwDqmlcw74b7ox7w8xGH34/F442mOFeutZ5fj1z3zH77H55nBRw32PA9Dnpg5X9jgGvfr2d3dHP48eH76cExyDYD3w6fPyDHGzHj++DBoJx+RpVeobiKSjDyaHL4JHwooMjKJ0zjtn0QhQGWs3EmrLpW9a6tnKmdaVuAaSaxjmekHDt4UIDTKU/VckEjFRpTJJekVsxrMHMWlqtb+OWe6m8HcaOCyK00GNHLJCw4/nU62Esjsqok6ya5CoPs1sxVYCD8NfaIoKQWLrLIuI8lwt5mx1uGnYcOP48AKTtELyYU5L0qjH2IaOTTNY62aZeSuuzFjBjUJIm04wWCaicdZYp4qmmsnzj5qduO6ipUoTbwK3gJpTmgeakXPaa6ZYmOMY8455/39vbkdxwHkyf1AWaWVaYbM2GK81bEKqOs/Ee4u8HmEaUA3Ota6OIDQ1ZFZn8dhp+FEkIvm5iHBWOIxcMrEXHTbCZ+ZISJG49iJyMgrhZjwU0TMtWCs2c+ZnOv+dM6RDw8PmTkjzufzk6f3D3M6G9RVO8sBAy5qapbWhDI2PwNIzHlR9HrXYSnhPmKFXUFd9ybcDc/M2SOkSGpa2pXv7Yxcx0wFnrg/OZyRsYKkRgmcWPrJ5Z4Tc86FPD05+/JAzpjmLpCfMyxSw5T0YQYktRGBPPlgorqz3IKZKyxyOozMFQMmZ6x5UyNzGZxGHQDXVOl4MiyGR4Tg5vU4j1hjjBy2iFKXXNPcz25rrXRDA6cqJVhkxkHn7EFD+jrd3RtZvLnhMCeQKxx5zMlM6gwgIxFOzfgdZiKixDHpDnNoHpTEF0vRD2jmtmLdAFZbcwAhN+IWmbnmoKWfFo7H52/8pb/wp/+L7/qp4/mr8+HFP/HP/JO/5Ku++UD8/b/3fc8/++HXX331dHf/0z9xfNdf/sy3/YFXP/Tht97//ocnT17hyucvfub/8n/+zB/9l3/xt/3Bt/37f+YTfHqmDb87fejDP/En/uS//Pt+/7d/4KfeIH2ccr54MewkhGEdERHn81kp4Oq5EUGgLRKtBnAdcWTmSM655nzcLZQn2JorbYm1K0HgyNT4ry161ZrkXGtZJoefWozWCQ5XM3QUiQ9mwnYrRyhEoTJtc46lrgWzze0MIkknsGJFOAwr3MvMHsfhY2y0RoocERiAuvOzOhVd8IRf61R10WTWaBYqWdLWWitXRoB5OjJJMcLINLMZayLcxkqY+2kDh0YDc67DfNgxIk/mPPvpdPrgT/7QevY53L+Sv+b543/3+eO3PeMn7fN/4kNPvvOV00+cnz+uV+4G1vPF07rL+8vp+OhPfvXX/bqvee97DqaUSe4Ou5xoR4QPZnjCE5qlTfBILJpnkv7kyQnGiOXmwieUmVQ5YB0Rgch57o/dZfzTyQDMdYin5SnQT0y3HMchUgvIzZg7+VAEFiG+ZOVF1b44J82EPUDNDsBY6YGgxuKsgcrTXwpj3R0ac5Xq5UMQucfXtJBQgdKRJ9pSJ1lDrztg13E8jmO3qyq9y07eOx15qRiuzxTdb+7uSp2jmrHW5TIzM09+d3c3L8daSyLP4pKoaFd9nNbqwXNFhJ2Hq76uS/By9oAbulYHPlFpKJtLDVT8qJGvN0lAjZ1w34h9dlyMTOXaK1auVhoRSMteruEuqcu16kWqB98B5IrjOHDSmEvEXDSjypYRrpoHqBa3ORfcfNTcaZPmzm0KpYdvXRh0+kKWqngx4LqUoIGmqnBYDw/JgIElomJ28uG9a9KRTBQkmZmMtUC1MmaPTK6VZFXObmbxEkanb32ZvSP156YySodEbb/Zunobk606BYGbwXAakw6xE41MnOi44ShFj5eA6ohiWAyPatBsc8MrJ5F5nT+x8z+Z1rQiZWWmBtidfKxc5/s7JE1tfu4adXLyERG3rJyaHbOWoeB0NlxpTbTZqcw2AXuhjqOHLXq3S7XImqih2ROvIyIdEWF01YkLlyECMR/WGMNOQ4O79Cy3T5ovk9uddxEvBsbPfuwffubzP/t3vvfhbn3xwc980zf/2q/95d/44Z/+yI+87x9993f9x6+//s758OJ89rGe/p3v/tiXf8UX/ZZv4X/9X//sT//wl9298sbwVz77ifk3/tIn/sAfe/INv/atH/7+u1ff9fDs2eO/9D/+V/74n/wX3njjTcWQDy8u7lxZFJmjHcycMzK3nrMMnXdioMt1lupLH7y4KV25V7kuM0vIpcaxJcQIpFKlVFltWxtTZCsVbr8yNKPrxyTXOoTs6CdXZs4FLBhjrQlmpchFcdC4NjsN0hlXIot3052AE/0GAE2OM7Mjlnq+5WxyvdQgsJ83JM2TCVWLfaiP/+RDIOgYw8m5lpmdxzjiQCZoJy/2T73FWIm7GeRxz6Dd483P4TOf+uxXfN1rn/69n3rz21/kKXEPAut3Pnvrt7/19E89ffq95+PF4QP2xNLiFA+v5uXbvuVbn37xOz7xqc/e2Rlux/BT8DEO5YpOU0dEX66E0cBqEtM/Akr3Xa35KXAojQmvvc6N3vdJLo28ZKlJN0KfIyMz1lJYQxIrVuQY57r16q4eV52APOYecmNmSoPDuES3Jyxt1LDV6wg2CRhY7j3LJG03a1Zwd1NIiChpFaAGY+yHcRfDtwa63rpYCeRuY5Gd7G9npm4HRGktlo2QJY2lTBHMI3NYpchbdHeM8TiPhcwISSFu1PE4prhtPYaItyjuF9iR+lQ7RQbgzEyCkLBGY3QUAaF1MKS5KLD0bpzu7u5GQA0bmrtJ0GFWdqFCGXejkVZdXLZ7zubMzOr0IJG55owbqggly5bASu2B1ouFWyMzsZJNMdiLnLd0TSlzXTsmriB2iOIZAeBeiBaQmWrUkXS0BHSORmfAugzJ6tAuk13lBnWfV3dHBCuj7U9XTsUMWXV3CWK4u0wempRYO8V6he19tVCyUtGjujpuKD5kRCysyBg0ZjihStgO2vYtjQjOFQYgo9oKO16RH8L1S5AJtgfVtMoqPZhoPDMWaRhF+zKzBCPj1GfPbqZlk7SmmMnY1gcLSRIbX24KiNa9AWDyrcScepcU/1LLSNVDI6TxAeByWTlUf6xDMnNFzJOd07p5uqMTc8vrHNaK7fTZJt+4P7/22Y//2Pve95+89ex4e75+8meffvMzX/nVv+zHf/KDv/hLv+xvffffeO2V8cr56UffeHZ3h3GKN9/6+L/3b//dP/7ar/hDf+xr/nf/6k+/+Px77l/9/KtvP/3IDzz76R/98t/yO/0Hv/+jD8++6D/8i//2b/jNv/4jH3l2Ot2dTiMiXnnllcvlwWzMo4ArTd+QVoZbVRO0nrMZbSQ1ZELn6nw+3/qzPXcSV5Zoid6or8F6trRC5Ig4YjGrrcvM4GaBE73y3K68WEvWADKOQePIgqCwIldWctK4IwAxgMYYpEQX6vKexhlZAgA5c2ZgFaaqcqP3+8pLczhWjbnbFSvlTiywShQbCyKQl2MGYS3t7qSBay64FXM2xVmpgzoTPmY+Ph13j5d8Y744f+wT3/MH/ujxk2/7mj/31f8gHu3Zu44E4l3B+7Sf9bf+52+98oOn1/OL3vzM595m959/441/+o/+D/7YH/+DwXc8u8wnd/d0i+fHY6xYsDtX7pmMpc5aBbXjRA2mkwq+G4MR4fCV10lWu9bangTlCFYJgpI81tSYvzQC5nQyYVzHVDKgEGzQwmDk5XI5n4e5kT3ppNycwW2AspMky5sbzcYsjkgPR8zbL3X6Vgfqtb5Ibz73zu1YJ2lmDHeSs+XN8kY/a1/XrCgPBsh2Z16Vm/TmVjrpIDm67F9e0KTpEiRP5worLnMdK+TRFRycTqfLmvf390pDc3PVQGaefFTNrCtYMyMj1eGqCDBubMoYvnCTUjXBIVezWnr0uso4aaS538QT2WH1JljuQppZ9cUWhLjMUvU3tjZH/Zj+4JrZGEHy7u4OHQ8JF2LJFSm9y1hXGs6Oiqj2Ps1XvMnY0L451lVhOLuGjRXoILG4LTfkEbbHvkaUqpQjEwHQCIq3SVyOR7OiBe7QR1ayoi5eTyO67r4jP5I032sixol2rQZzlsCNqT980MWEWt0VRrKabmsrAYDWImjkZc0MKJVfuM5+ST1Nk8VwG6JthFyiCy+xPHQXpCNpkF+fsZyxlmWx5U11kTSsMIC0EFe5dCvTaYwU+imNTpILy2F79Nv2vvpUyre8qG28Ei9pZrbZ+70OsTKwwsJXTE5wuIZ9M410qR3uA5ytscNI1Q5nYxI6Cecn/vnPf/ZHf/yvfu4zHzgujHc8/+TPvPG1v/Hrn/yiV58E/5P/7D/6THzk9ddf+ezDJ89f4o843I/7dzz97Buf+g++832//3/4rm/81vPf+o8/fv/6q6+87e14M/7uP/rE7/rH3vOOX+bf/u3f/u5f/kX/1U/86MrAcwJ088Bca2qa8owSJ7AHoeJp7pFhNM2bgfbHykzdVQZcMd9OhqILau5GXrkFIQ15GkQH2oB8aHR3BzIrakpgBV64Fgma2xMRWAuEmTWuUC2hmTWSeYtUX9YSTRU3bVTo8z90+Fv0OI0ZYaVgVbIhmcnEjMWd+67rlnH4ELSmCJ6EZDzWopkUbCLifD6fxkjkFO1hrlwNUqqp7+QPlzDnWm/cnd7+Ux/6vu//gX/voz/1xk/8rk/G58d8ZeJN4E3wGfKcy5ctf/yWF2//8dfmxy8PD8/HU3v3r3rvzz556zOf/uR4RpAPXE9RM1LjOd1PiVQzZ+7GXBbAjj2yk93R69U9laEyX/FtUhr1reGIHYjc6BIKPpO4tt3GpFuEoFGusga8ktpkfoHYStQffetDmRkrdN6oKc4/+bHLvqv7Jdx9JAXR6MrNKAnG1Wk1WY1JUodQVCh/Ka98HIeDcLvm1j2jMDN37mI29nGKCA0qKdOgeKDZm9HDhkkmQvpTj8d0DbQxP5/Pc04B9LppJ7sybnDDTro5vjgkquJlwrZavX5M4zZLyjFr/ZOGm3eBxmQqRzd6TxbSezk45xR1NrpTkLttw4CZl8vF3f1czdOWNTD4Fhup3Se08e6uWuYOkE+nU4/TWFBHLHWp+AWPrCvKnlFaJtUqeK9vWuFvZUFGyTryZnhD6a50cnz7LpbQPLPrayaVQmEDLZQ3NGuO0uYka0lJPhwX/Uwnf6nGGH3429mC9WiRUVJB3EtXIU6zl5VYqByeVH8XdmPG4zwEQFUzW6pZxVfEZU0hVCdzuAmDNdysZPcw7H+eaFNatccCQLdcwRUJddjH3d0dUPo4+vzo5D6zo4qIkdxE8b1rkRV13TrgTbyoG30cMNLHjgJJWuLAEl+m9y4va855OWHQEpbuJ9jZ7dx3oeJpvZ0c8O70yExNw9yH7cnT+w9+4Eff//4//cM//YPf8dEfS+B8unvve3/hSnzop38qY2kiAgqfaGg9YM63v/3p295+/thHP395zNPdQLj5fMcv8Kf37331ldeViaALVeUCu0H85aYSoL0ddolAIVffZvbfZJNaAf6c3/6539Fr1E7UP1j/Q39DP05+wSsUI+eGdnvz2hXJ7493m1TdfN08xfW3N+kd6I/xc1ZjE4uwRX73R+J+HG1INr+wn/sKBb70irfPl+A1wcCnPvXxT33iU8ex8pdM3iPvkokRlpnTEwk8km+QHzNAPAP7yq/8pfdPnqwZbH+k0CGKUXl99peWRYkxOuK4WfC8/ffLpSLuPOzlhcV1d+uVc2emWWu1l+W6AL2w+9f2G+oMZOb/8bf++1/82i+2cap45TaY0qsS1X9tPVkwbicUGU0KI52pDHNvgIIv8bPNpF3WIcb+q8wcJeOZt8UMWglI7aRnJ0DYilQVfUfW4Ewvf+A2M9I4bESEiNl5Aw3u9qy94HbDjuYOhXg16BUE9K5cbd/LzmY/4A5s90OxI6JiS0YNcTI3EmtORmbcjMuOEP4crYJ2zdvEQmdaSzHPCCelXhT9pPrAZoa1juPA6WTNfGZHhWYW3ZWUXf+riLuZrtmOTdOQjLWh3IMXM7gW/SWkdK8zdJRYCWJLT2ILzeu/b2nbe0fkIzOvZ2P/jLzLWmsPTdonSh9AiAVubVjmKo1IsUljVzEBi5hOUx+d3uIcUJBhu/lYLTo9K8kUgUdETQ25AQO6jr4PhrsvhOX1VqYRwYxVQho61ekAlHCjnKtU/OoM5LEASjyekZlLNxFd/L7e4pdXrCCzm4HwEFtH87OZkaF6NsmTnWIduWbGjDwZj2Vr+Ol8vi81p26EBeAoLohe82R+O9k6jsunP/sPf/rD7/+S1971S//Gl3/ssw///W//p37FL/mmD3z4g//B9/255298+u50yoVxNjN7842HcUck1vJ5vPUrv/l3/p7f96X/+Uf+2t/+rhdv/wWvXC7zyatP/rl/8Xf/5v/WH372bPqZx4Gze0bMtbYku51srlVDgbIL8HLwJGdkxCpXjcomAWUzY4zqsXFn5GpBWY3yhHQOVAwCXNYpU39aERISMncYRYM6FSsqjZ632e96aXxkEPrbjC6K5YLVUUxCfe3rdgh6FhevLLztUDMxl2qiLJZLGTRjJdNCPrLrRNo7aXpnW4OMwmOTFhkqmct8ZV4rXKVc1O0nQuOr8DPnsdaTJ29/43PP/s1//X91+cn3/ebf9tv/3jd9z6df/9mH9zxH8u7zZ38Sbzy55AvYz/rpu87nv3l/RN4/Ob/15uOv/ad+wx/+I//8em5255d5nGc+nIgV4+6cK6qE15okEVFR6jDEOhV6B2XAmY3Hmwkk0BQ7NBKGngHlYiwCbkP04IrRSXMnTbMs0eP4zudTWfvLccxJsoZz7ItPh6ByeTGaGe/H0y++/2JVMDXuYKyVWmtYGInOcuTg89qQfgXcrDs1Z8Q6akx3s+qv+1rtv6WrN3T4bi3vToA61xVVialwbF0bNDMrrTEbpN5oCYdIxPl83qY8MzUNAijSkHwbh6tl0Ttu2i9bVikrwy6tzkz5fiSYG1vomhC+kJNVKbINTUJBF5OwIqXvjz0wEbkCNCLdeByTt1laO6GThsMfEyr8NHEJSJh5w5B1aSM4TAVmFZ/GyYiTxdwLrseRkpaDIE1FlK4YCUiXhBC7vHoyj3HVhApSKjBBqGok/jGbArZQNYWcCyQgdCZ1Y9K4btIXfaqN/WoXtgWXLVDZ28zUx6z+rjlna+gybo5cXUiWqv42Q0AyckYojBaRSh2BTNC4Wehx1KlT+3ufgbwcBwB3lTmU+Fpqiqz0he0l13vr8ySWLj84a5fTzsMS8p/rWHubtmLXF1Q9VgSNSEtkocpgGmMV2oybr6xORM9MusifoQ5Xa5hKua9uXSj1TDPjzHXMS+JCuwB3eUzm3WLASotjH+w2f1d/XyYgEsiPffKzn33j++aciVd/0bse/dmX/aJ3fM14620f+vsf/OyPf+7tr94P2uVxreER+YTn9eyUOCyPU7z6D77nb7/ntfd80zfd/8h3z/Pje77uG37Ft3zL7/5Nv/m3nU9vf7z7PPMVMrlnl1Vxok6UawF77sX1/M9rRX8HtXocHdpt3zbSU8FKEw/NGXMdc51OJzdbKu0LvJGKQPfd6eJUObmE4q/xbt7EmvFzErByD63wgVZo8duEj5l97g/A0EzPjaMmEUcZN/Md+lsioqqEWwpJvyhzvQ1FGnVBTla7fK0Gik7RzeLufmWWGJHh65T2eP/q+d/68//Oj//dn/ryr/myL3316/7W3/6e/Cc5Tqf1+nz27kcqVf4Zw9vSvtcuH3043T3FZyM+/+x93/u9b//n/idf9qVf+4k33rx7dfjKi+VCnlBaimyVuhYeMQcfY8Y87k9nbZl0sNdKP99lJkNZgdhnw8wOzGowWS1d52ZmcwZQ+ZvyPTuNMmidXO2DR3K8fj6OozikEWkU+ddBaZ4IsdOmRIQzQvpR0qUQf2+PhwyNNZwLo7LznSaqc+42J8tIQZQr4v7Jk7UWsrgGOrw9xQHQ69wUF2kEbFUHRWSmQPbz+U77GgjLq57RVaiyuGpnR0aEQMtrh0mnzoMc7tm/q7TW3Y8IjVTqPK89cewpH1fMJ7uGl43T1pCA1vh7CSAyp1muuWNVMxOnCZnHDTdVXP1tW927S+FyMTONyMhMulrF8vHxEbN4ZGe6yIrutntPzYxjxFw2CMrXhCXoHqOKuLf3PDOPy+HuGqqIqC4T9oBYWWoNRdY5uxwHlfsiaKYZfIoAlG8mrglrShZ3FYNfipg0o53IyLSXZHX7C12/PJnb6URZk1FDQbaQlozjWlXKyhtlXZLqTo8WmYDOFmFkrMjGUQljNUHpvIeZOS0thg2DB5YZ6+CVfGvpHO2VrJPc3NF8ORfXD4lhezJ344w15zEzznS4ieU1GnrZ0i5lgvvkVzx3Gnm1mCByRawI1li8l7y1PthQ2dgrKDB5FgETRixoU9KI1mlySr/+OOZbHhg+M0+RM3OO02txIwem6bDo0QKZyRvHBuCNN38G8Tk6PvCTn/66r3/lbePXfcmXvecH/5v3ff/3/Z23v/q2nM9jzCAxT4h1d5czH8iMC8fIh7fiQx/89Df/pm/4lV/3zv/2b/k9/9i3ffvT1+/fems9PMy1Bjnv7lbmnbs/Xh6MOsg+53Q3I9ZauuLRfLG1lsa4Z/fe6M6TXFpKVLSNlttEpsydEKa5jpOd3H2civU6zLyirkSrm5Vvi7jM5ZJ0FkVjzjmnIU+n0/ATKh4oeUi6WUlxqSc7KLXKzETp6nM7vGFuzh5cfRrG9hbyT0mLWJ7JzaAEDGV7V+v4ZvezqF98tbRtaIqxlFeghj5xLxjIGkJj1NDDjJgZlm1Oj5XGNf2V18bf//s/8D3/6f8r8Ln3vPsbP/rJn3njr3zGftsFB/AC/roxbX067IX7D493/eSXzNcuX/KVX/313/irPvyB9yd+6m/+pf/n7/i2/9GXvee9l+Px4R73iweCM4aPRVSDDiGwIZNJDhuPx0UZ12XNO7s7jROLrLYBy+LDH8eRA9JXOJ3PAI5YuVZs/FpVbafRMzJi2WlsDFWc5lQLhayBV0IghYY554mmGeSn85nqJARsuGyOKsCDxt/1e/8sxeQEinKV1NgFfRglfkYr6f6CU2SztQbJlGgjVak1FB4BlAA26DNm0evAzHAiM0Cj9QzVFIa/oCbFLeoSBBAyvgg3y0g3I5girCLVwcgi/SZQtaDusell1W2RD8QVm4dC1KI3t+wQUJ/sWigQPB96oqrR9xsAAE3DyYlkT99TsiqlFqh7xnplhI8VYKs3qCrCzWvDbt5Gbz8BRPjWpkkuL9URRMrZSWAKliJ1Zd3Dygrp5j6MNoxjVMODmc3+YNaPFYAY89diSjMO0DXL6+5l4RI0y/4Z+Y0+DASbrmNEwgrgV0LQ6v+1mlV5iqqGlfqDzB52cHTzO19Q9wqt8f4UkTf/hcxWYovM4ksgMyIDcMlnq/81KoYgVuyHqvCrpLwREb1qAhRAsPj/GezZ2omMTEdNGS70RPoqQMSU3JbKe9o5AKtwmvYThBkj0kCgeswAYx+dffeATLIAsdR1jbUq0JxrQd8MjRm0FdM0q1O3v7o7gka3wuTnnBoMVUcLIKtfobcg8yp5zzodsR1cfTvNEjgj5ww16V3mBKGQ1CBsAY2M9CY3Qyqp2buq/AWKC9WHV43+4q6RVgetBzbrNmKfXrZQlUYQ8DTGMS8BmPE0xvFwCSvbYl0H1IwLJdrVSWlASuPAksoubChWXkGzlTnIlZFy+bAVaXoKC4NJn0/1nnnMoS502UezpeObGDQxy4KwyIlsmRHOSDciCArbiDKyZmosuS4kCDBimVlmjCYK2PUt9VMZWadauqUgvSqiiDoKasNoaD3CylYhzaim8u00QsOoxNBk9jwbkf0zLgFpg9DaHkJPwNsLXlNGWNTIlLY8CbexYpHCMqMLYfVbllDBrt1tGQ61/dYPluJgkmBaxCqnENdnBNLsmlL2NFFYVxyErkXfBAMCm7VXrzaASFgVCQo5S7SxNY0gA2amYB/CJLcn77utTO9pXcCr/8iMTGvDaqAZaneSYGYZCXRO2QJbXUlPVRIzhzHSOnpIZvqwy5waK6i92AmttUKG7A6tNDeuzhgQQFq6dCW3Rxrilhcnxb6QFZG5MyJCgVgmd+GfAKvbRIMvuiasNpUyQ/v4RHaFWpcetTlZDbs3LIA+HvIMofbWtMMC4Ej18O33EkhAQZ+eXk1TN4Lw18/CZk6a2gDtlsCxt+B6GXtP9zduS+FZ/839Ite/3BeAlcH1aYYuZVoKYN3bltSgtdv9wl5HfcCuMNdf34QtrFgnQ367qCV6o+wfFmX1hhhQvEBZEFMVLYG++ZHhzAgGTAErbKlxSUdVRvmqWlG/T0l+glILdB18kpJcKKYkEmnUULX2DalToZVIlTR7PZW73jq63Mh16MNATew7yiw3KIsfgHfzdBW7bzZZNHz9sw4ygETkCiRpKyJj+XACkSnMXyWAChFobXgTibA+7/36ESCxMiVfqifKRMygZDvr4BREwqqcuLyu2plRkY1VFrHXDJTIUu/Gy6EZkC1CSTUmFpW1D0SZ0ezmAmzToZ8tClPdo/1krHVHSiNV+UxkSvfAy8YZlNpiGU2mz1UFMhAeiAxahaCSj7O4OsTKtpNpKR8MFZQisiYblz3psx6Iki+re1nCAACtVBy6h8UwuOYCTKHyjqpA7ia+1KaiNlpYEpBmQ+1aAQggs0hRSOrKa3uYYHqxliITpAUCGlmNXb2vfcwAYZlXRyozotb4FUtr2Iz3sOrW7TnPN1F3CJ+TNVeETjWzCLfNDvMSWSaffStLaLZbECudBSC/JijCKjNmyRiC4Ep1lsqUWd/Hl6c9/PzXz3/9/NfPf/38189//fzX/3++BgAEwgBgRW7XXag0gJo4JNknGqFkUkBmqBAlWQ9ckYrOY7Ky0o6VBBxW+bV4eptmzAqiOq1SAKeYyaR/oHzaQBsRseYc1IfVIPMUmzMVNGYqcd1tAMJ6d1rG+i0AiCywPDuqgxBL84wGbTqPIqUmiduXUno5EUwYzOyamlg9WdUjEYChgIbs5G3ju7h2uFYilIJbIDjRAkug/4KTkyhMJQE1XpNzHVJqsmqZKw3m26S0YlFCCZzd0Ig6bIa9lOJev3YikPlzfqKw9c4nXko8GhypJCW7X4GIRGm25U2msV+ynr8zFmzEPrsd4OW3aainSvqbbQeE9eI2fxIJSUVquLQ+IlFlpkozN2JQiWEIUCpB0y94+luQipGJVoOOIJEnH8eaymIK7bHG5RNmlEori3hI6XUisWvuDfhydQqBSnuEfBg6b71qnYjsnwJRuZAGmHkgIibSgqjmcYRVha+oGJUxxRSYW9eG8OEA1gqhrLHCJGnJLc7VRKiuD0VhD0LuMzMbZqwSlxKOQrl0JpM0qqs1ZqlWGZoOpjS3XrIWv9FPlDlROirjU+ewtxYFxG1Ux4wZa8ail4r6sYJmyKVX28yuTjJ10oqEiKYC6MOoGbkRIAJXnbWs+i6IKD1pNVUDoiIr8VpI6adn4VsqcITyXUPCYOQEajoHbFsVFLZXKH2ycPiCZFW6D52V6CsR6yKJur5jNGQkyK6XEQm7WkO0JQA4Y0WkzgMCRmbV1ovDYHVduFDAopLmsuENOxcLU2WVqq0kJFlTCnaoDYgg6MOnlPyByFxzmblYV5Wv14vbrBOZlqzaGhoBrUJ+lT0EbajMpVxcNRenxZo6rFWvidCoWBGZhWfqz556ah5MGrG2AUwTZ8FqQCxFaREQj93ypCUu5pEGCPVsGp08k7KBemdCvqCNsshWyEwXGHDT6ImyGWxg5Op5qb+4uRWkzbkAjJODXD3krnHbxiUis4X8BBrq+y3WkAne/p/9/4jAjSZGkXdrJvkGPepPWUhgfX9bedvS0BsSjoiIKe6coDj5yqjXkUncjn+/9XWFsqKSOrWJ1OzCiGWYGap1UZymmtdUrE43S0uYWhxsewrWZjdgX16UsKySZl89cC/FS//frvzmo0mvU9FQ2f9dj2Rd8QyI+a+jEhEyA9GgWEb1ZsBQami7gvIyXNNRYtbpwUsl+dSlslpMWXlWeGN1onXRy2cW4FcbaPUkeROz0KQ4psisfgm7bN+02Zuv6PhJF2Z1hTnbCPUNq+cxFrndSSICa80VKzIyBUpCwuQAa8yoRveUidOGiBm6b9m10r3/cgOm1qTKPtL6jrHFBaRhnZr/UUUsRMnXRK5AqDbKTJhbRJzcLLHmXLHUBBOwWW+4xzcZrEbOQjVm6BZFWXyVWgtFzRoUUIdLJiTciz+yXlbD5l7PfRzqO7QbfZtEtgxOHR6VdOX8cONE5Wprd2vdy8D02gJkVoxR3EBZ3oUa9chApErutiIuc3azU7Va1AY2uNyPsDtfqU/CJhpkRWVyXSrc6qwhqlAhy5lV4lIcVVdun45IpkqVqDACVIMZIjKySx6dEpTQI0FNIpXJlZyidlOckj2GzAEP+ExLpNkyhDNUwE2dHAKeaVA3Ti264HFpzcqG5HB79dVX1wppHIq2eDoPGqpM2JnWGG5iqVbRvA8Ndmsqg1gGAJZV3NbV33Wctob7uvS5kfnW6pdrr78W4WBlwLgyV2S6rQTdqtdPwbvIJhkjIoFFeiYEXgc0BKZCN31dWUkKvasG0FPHI7ipH6iaBlBYuX5+X45EIGyD34rLRfYsR1b2KdsVqXkG5gZCEoxGGj0zFm4y7P5iMcNgHeYBWrWylaqG3Tzf9dOxpqoHmrykf++wVzWxCuuyjyT7wZIVT0UCdAkdRAXg15RHL8Yu/yJfrnWx9Q2rpKvH6Dp9yfmO81mJSahan5FEzJDIorpdA3LPpulxUIIHy8ho7Y06a1Y5HjsJv2kt3mev/5D9ECp+9gFlh1SL3YZbmQZJEa633+0lB1m6uy+pCggmwBe+8z6QN+sIGYjtYmBgbXp9DEOTIHh9Lcpm3jSH04hAMhAikcr1oZ1DaFVoCp+JAKVc1Qyj7Og2xWQ5In2zvQFzS8TCrE9/Q1xoSstV0sQMESDo7lutotGlyIp1b0K3L1ijzqs6om+f3JTClLx/xQMVclV7lfp6oCom4irdR0QywiFaewkAiMemW7ViSV4nsiroRJGGeu9St6WxkjZfomRW4J0iWNX2RFzWrBirIj9GrMiaioErk6OYl5WYteOoe9qKDtj10V7RxnL23cQ+//0K3vqq0eVC2ZJryLwPcB3lHXtm81Ep1gPdHBmx1Npdv6zE3ZBWUUiRXKuaLZyIqIrofp8IyaOKR1Rkj9toNFPyo9ig4o0kbfF+5IuNBvg4zTlNmoHR8E+9CMoAVg1etysBWiAy5HZnrK0PhSBlBMi4vhZc/JqEWGAoVDUaMwBrbI409qW/lJ/+zKfOp3MttTLz0nXPymwoVVoE0ksmJ6LGi5n6O5ROaid7c6kDvM0ZKuSh2gdsm0NRQcwOXdV2vqRmjSq61HdapaAogrLQRaYEI1cMM48IujOWImJFoxoe10c4s9tYK3Mo8lIRXyPFbDUAZeh7bzNTzlbCtWJjxtWiJ8227TZ0c+9ttsNSKJT7N/UcC3mwhiPLIZTjIujOHmmKHpyKNhNK/gLXO4Yr9snKA25XsLclGm6BiRNRl/bqgMRGqQOhjGkHX70w3DEly4cX8Nu0Br1uYrN8cx8KJywxDQEMMIDZyZTZQAaHr5jerVaXdUFv3vU5sfEzdsJx7dnXJ8wb5snthb59setXpQi9DO3HUYc80Y0u0G244gc6dFxi0ORGWgAweoxxfGH622u+s/c+bLfRfT1KB136VHkNgXdcX5tYFCptYNO7N0RRHzbC0BxvABUL2hToGleyXYVoRGRQGQIsJPCjBLD2gpWgE2heJXRfEoIT5wwbVwMQKop0gIHK3xDN3WyWTu9UsUyRxY6pYk223rWOpNXBrKYXkYzWitIslnEq1NHA1AkrPWrrbICYuSsAoslJJa4AiltClN7YqImZgUgqbWGauTDB2NumP9Dq5pJzTl16jVysd/w5Z/N6YiKvbrfBw67LNBSUtBKIrfgIVWpyxWpmhaLVmoiQWbWYKgI0oJME1LwhqZNUzKE/CYgexXsVMkhTTc66CQ1gmEyrpnleI19IliXIAZ+WWBkZu9p1m5NUYKLaYh36huBgrPBd+ZSwwJmxLE8iKr90V5RmwLKrd2VEU9EpIzNnnIZ3NzsVJk6kp1tqjAoDySICkoR5YZQakFKJm9J2fVKmKOLn81mVjib+8vHhoQZ8EkCMbi8sBqHRwm5xBL01wVK7phITAtXGoOUp60VKPYB5fQXIAsx1RdjaXBqBgJsraoAyIjBm1Blhv0gaGEPwTsbSbkQsnVRFWFV7yjpeZS/KzAkXqnJnzOx7RZ3czoWuWWY5kwSQKzrw3K23BV0zVfapoeaVBwTWGGMYVyy0EQDIPVVwxy4ZlIzHS7evGlc3MteYSjbQXamIrIC5F5p9Y9BBw9X0gdl9MnUyM7Fl2Co+QbsfQ8MgpGUPLCk06WpeRFwtv3O1Frk/c8QK4zCzsMc4ukG2SoYqLJnZikVgRUdFxd176SIVyF6gVCTqGmhmI/uNC0UNhZf9QUxJO7e/IW681C4E01oBPcURRANbnQPH0G8sgH2JJP6+z1N7F32iG09cWJF2oLSdetGsme+RL2HT+xOiQiKN0ZCfqHMfMCQjVx1IKnBTOtixQ99DPdf2K0pWqoZDjArARI5nrDD6NU1OdHm6viS4kV33MCuTHFMXQYU6xVsGpEpK2X6xI81y7Tq/VniMDrMC/e40KYMoR/aSQkWm+gOKZ6xGRG2OrNGMFfMY5mOMOQ8zEjjmLO7u9RlVKmu4DFXm3aGmogFczxZIaBQf9z4Zhw+ozFxiYWUWkan+sapvXq+LIJHs4ky/3zU21AZseI5XqyDl+AhAeqWZ1YlWqe0NamHl4Kqkb40FMprHXaoZNMqPSIZBBTtYIoa7ux0xsXs1+hxLrHb/qJuAPQTRI8TQHT8LSNKEoGcfe3XuNoSR1ZCBCm1IguHmknOSpV+RPk6zOoO3MkJ1yqkOwQIRWyo4sUB3ywgQPgZnzHkBbBgCmEuXpAKXIJAWWFbbw45BCiqRO7EmXaDcUDaXwMjMSDO6j0apGMHLnHUvmYydYlFjaZ2WNT0Ge9wPJOlvQKeR6NVBNztlk8ZVB19cNnyPd2ClviFcGLUMABhYZlLmNYXcazsUsxEBH7bmolHDDoafqrWuOt3KvokMxS5/aWx3W75s65lqOWOj7YKXt5e6oo8M0GTVGazoh1Vhsjq6vRLIYR5zCchAUbEskDZM2bC0IO36K9igUhd/lcsYOlTYRTvFvTXxSbHnyr0BdYt7E+RfVvemFru+y2MeujSCRcCVXFm1WHTeyStoPsyiO8Wo+6we5jKLZRJ34mH0mTEBDlMLIcxypY+RGXMeJFN9JtriTooqiy5CxLZiAbScG6HOfaaKwbLFigGTeQNbFHHDwGRUTN8Grp1TZSlXl6c/qAweKr4Jx9INF+BiDL1lUxhw20FQAc3m0VSFYLt+FZWsmj5RSlWsTIuV7LRVLz+NyiWQEUU20c4O82jQRAJtKIahOZlJlXhAJGGhuwmCzlzF6wJiatLqlFgSOIZ37bvbVbZLCtAtViAx3KLUjkBzU9Onmt1TMnCRaGPSq8y24ExAqUDpMmomSvU/AhkzO5XU8mktma3YEaEJK2qi6QbR9tuggQESNagAwxgRJ3dLm7EQoVkykViYMxN06AB2HYC91tnoSxRWVN0c23gajTDNszF4IleujRZkdVGvTkEbu7J9UkCRmOR6hacauxOw64O0JIyuD+BuCO4YonMybVwz6DpRQp9zshIXSVDKRjiIlTPTvX1xVPqpKz/nZJ1OM69hkNoaBUNWPZyMOZUGRYSy+JnL1PqTXLEMQ2to3J+PHXbUo+xUTuObIqeZrRT5DpmYRfxD4cTy6rFxaJkjImvUGEmHYcl64OHhwWigybIYOXR4iJUp7YyVMDtlZgCxAvSGuiY6XREBMIFAeA51FOtw7kB8tsDiEtfRncZYKyDB+2CiBJEKWKtmzmtiRXonw+j0EWXy5R0omq7QEWa1azcUrDVOAGYMICONQFznRkPFFTXvNUDkNgaNuUKBFao5T534ZMJFVszVRBiXP1ZYrrRyA7UxYwwvw0YiFt1tAiaCZW6WS8XlQcTqR8Ld/f3DwwMw3FIj5dVCaZB56xJlB5cATM1hVRTR1aUe1digmXw9IBEgFoKkG7MAmp9iBVaYwwohr+hlZQ5d0Zt4PBDBOKfLQ0Y0iy0YkcvSzarwH0kHHZHBUDe6yx7Si8sn1pohDDbL3UVYezspNlV4GAxkhNNyIpBoL5pU5oTz/WnNWCsSFolqiduoMrF7/2jVPOcEYrlGGAnrMkwVorDhfQSVvO4jCyXccKA1RnV8s5xwOc9OAHu6H3JmRq6KB9wjYy7Y2RKBVYIy2mtpterlrKNRyGdXWyT351Hs5pUEa0xwofwR1YEXebWi2MW/xv/NmGmdWiESNmzOVMd6wcvRPKJCGndoIcDYVk3HsggkbKDEeGhDPzinQsooMlUCRNTYsUSaIY1pASBXChmI7d/rHqXiBYSNiEXbNysQSIqCP5WQVc6GjIVMivYJhpnRcFymBnPUsAeEhCAUKKghGnKkyIx0YPVWDB8rYpV8Ac0cyODaVKKyRLDaNKAUPwC6IRR0V+vnXNNtZIZp+k2FUYaSd52QGlpOAGPjBqq2I3Sv7893x7xEI96RKI5LV1zEx9g3NzMrlJHrjAws6vXlGpQ2kqcVYVwqJwQHkImVLS8t4xLwYYHAXCljTIIZuYbbCb4SRl9r0ap9lnoPeuXnwRlKUJOZbphLTbSM0qwbVonMQlgUKF6Apc5G9cAXHl+Ox4C8IemnheoxWhflKZrjYmbNM6yAXRc+CmbaFT056cIBDSsBupr5bRNTAgZamPhMOfRJSwVi3Z3Pcx4p/mXCMlYXHAARVIiIQQsTgTjEUqrqbckI1FHItUhgGVIDcuRGwwidZRi8yyBmuuVdXaUhFxHqf+5Af21pjQCi2U7IHerWWyMlakZOnf3AzRQfUmlmaj6uuDg5Yw9REeWncgWg4Sd51uyekkZgtwDCym2hW900IgG3ofpQuC47sCe1Uahc5cKy6ef7O/G42br1sVZZHveUSWXncVX9QDnEWn2XPdWQSgzbGUFYZjCJAMYu2JjKr2gFhGu1qR/UemebiYM+5fL7WRwaQAKwdj6fjjV7QZ2jXTZ2lbpC/EgViaNyCcl/3AbkrAnOEau8GJHAoK/MhZCENiFXUys/ZylebTaBcdQH0DUSDJZi99RNDTNtnmdXX02/UFjZQjBRClHoHawuFaVbjQwXclaZgJKNACJyZUasJRJwe8y1VkWdxwTNRgDMnrOMW295dXXb7uL6V/V4N3+NBhzk4YrM2T/TudXO2AurF0oouQrhUkp2BdG3fml064axNk2WKRv7pfyLNNmzBVRoksWQeqq4CMHIDGpas2SJ5CzVoMfS+FFspgOdCsjqs0drMYEynQpBFcHd1DAyGpOqsQ5aeDMv4uCNDIccPOqJNyAmfKsWr0IEEV4DWNLbqU4pdseUFDaCtGTuuncgmUGo50cXbFW2QGakGWYrPPimkmTRGcu8VfEo9CSeoNnj5VHvr50aQPAUKwAY7Xw6XY6LsrswRCzdamkn6cCaERG5AINZ0RcjJCTSRrJV7sWJyc3vMKylCIYV+Ncxk30nmCtW1oAEndGm8HFfnyRtUDX7Dv5khjq97lvYVNn2QB2Sqh6aIHfm8BJHo8syNxyKAoc2LwJVRLwpNMV+HLT4Wnb4AehYtq5tZvYc7mkc3LyAvrBmiJVrzlQoJIRDQaQ+b0UKEBNCTTtzLisuVfcT7qxAxWMAKhW2s6tXUzxnJiIxDRkhBZIEYy23EQknYX6JWfl6ZIOJ/S6sf65eFXQoHxG4vid7wSiEHaj2i5U4kUkmcrBdL5p6BoUidX9Vf0X36ulQVvhPVudOVjLWjorouSNQqK7t0fkVlhJEZpgAN2AeKzM06hWVsG5qZqKSOdOfTFMbG2CWkHZExgKZYxAccVyp4fveVBJdomMouRZZTFqB6bw9zWUsbjfA0Lg6isRwJSWZym5a7x3MRCdMWgUKUQsVr0Sd7phVNr2hgtbUwb6c5UIMpijISSNXSfxCmVJ0fYq1q0hkCkOoPCaCVRezgAFcsRzLMMp0WOWyvacRkSUozcQKs4GQ0F/FInWf+x9tzhU8yZ1UyUqXox2maUPKdCjXYTEgyZu2bUC0x9qaW8cMlG95aSJCsWo6Nb/elzJEpO1ARIjxNqNmGVSWJZUcjqrt1pAVUL/STfOhHI9p9HqOBAJh9Vu1Hex8qVWYJCUsExZI5Moeiy5O0s29L5vWuLzRqFzfd/sAIGZy9s9vISztPG9U+Hflhtsco7Pl62h2qxgPlR1bL+3Smc606s3CjggVP+Yq4s92mlmIYmUvqRRhC4oSwvjVUjL6SMsLdYiBAbYAXX1cEycLi7UaHt3hU+1JNCNixeU4qiXaak6q7Pgwz7VUvRFrIB2DdCKTs5iAZf/UVJwarlp/UdrpAATkgiBLJHPv3T60RWvIm24Q5ZW7fFAqUJHAsl1ASfQyURFo8bOAZm1HwhtqDyC7zRpAFB2qK3GVDfdeFGpXLcIdB7TbvtrFjPY6fWV3CHv15dW8Xl/VBMVkRATrI8UWk4pyLjcBi4DWcmTDLSUyddMYse92dvjcEwuBoCe7lCwK8LZQMSN8j4MzkRuC7hNB2kRihnWZUNxH1u5uV5ALTJW/UJfLKpiqBm1r6nJ9ykAYxqY5C3uowCRRhIPKjsqiJlKiWkqFFB0hKyBFiLHKSFHaTJZf3S8rFnkNxaMNoKLiELlbFw4w2rGmDqV1UcqrgiVu8HVrUeeA6iEpbojWpTLrJNSxXscor/YF2xrXz1eHUzNEMpEsIkUiItSP9fL7F6QAseqLeogVsS4Xh5l7cpfjOznkKu+f1bYhyNHM0fZHWym6jLqhmMUk2o5kinYrc2RU7mJFc1SnU+X4ethugGoizgZQsyKi6NJQynkbkAIuOxIW/B3dw6o+VBWgkKDudS1w05sL+NRWRv2ewuEmorNfm5KJQKv11jHQHbsGN7WBV/G2bN41cCWrX6N5mQ+FbMktx5iNIBFgdU8ykUZ2tUHWGvCKiOQJU1mkzoOx+tGiPsMwn7nkmcUKSgIix1mfr6vhghc+pviDJacPjOotUGZFtRqRgEp6YkKKtNlxACqcwclHHUgAUjzY9L4OZvQRzHYx4ioZUyxwfaiKRFOSGjrvpfbSZ7UnNFe9uYJOcQlU3E+U4RJfJFSvhzqNtYO1yTtYBzbJeSl1NhI8nWwewu6LpZ3amm1/KxaC69U1UcCoapIRmWLZ5HmMuZYiryI8h46/RoJiRjo1lC2Ozvh3f2qhHFHxi9UayrYViFYHA47sYEmsKy0y/Yb4Zrh2i5sOfmrEl7yhbG5xNORphbiYlVvpCE/jrXCtZO47g52OVSJVAS+JHePJmVQZpG9Tlnh+OUhCSUvw5jSjX0v3up9FksPl5DJDlVpr8ZMVy8zcbIcQnVLrObebxU7L1wpGurGrE9GfUKa4IbFyi2oopbkhVW6ruKdUUCKEdhSsFxJtNek10Noa6Cejoh4WOq0deekrKvM11y27IoGlp44uGou2p7r+uI1TdhzTL09F27ahCCI1H3a7MgAsZ0p0flKnkNU+WGFd32MgNS7ePSL30JLa+KpVWr/G/u+2JZSEbJIi1QpPbRBAy8MdevRHxM6B+oiiTE3Fj9G1MYWNyrbb8fLlxS4nYlVcRqAGmoAZs4ugYPHdSkTlZquqZGpXrKJi+f2Zo6LY8pPYNDLui6ELhIiprICFClR9JLsaq9bC/kgJtc0ojMgEuBhqBDnv8k4vkXoJVHKSnYIOPkGEgbF07jq8LIpdoJAVNYPVfCtUM1p98kqyM2kWkWF6D0g7p13mNiAvfeWVZ546XO0ty6zLCPZHzoVUt6hYRmCxLpsnVo6elJ8ilCAlpKdTf0/pohUDVCnN5hNXuFHvWaH3blS4XjEZXasSjwHSwJUuxbZb7GOR14ev6ngW/42IJLwr5XAfiFgxh4/LPJrgU2u4qysOuMyoWfSMjsjcRu0KTxTKa5X3bNZ5Xj9abXMD1qCIGNWfCexcH0LgpHCSuPqgigUqMyi0OetqJbXVOVDZjtbzJpZWiB9pSDNP8oigQ+wwJ0GpLsN7sFvOuePiwqNKeCUjYshAIRMYsIxYWfyuThI4ux5fjGCrp0BEf/iKLnTSOntK0nKFyiysm9LMehMeBpUhrZmQdGP76MoMGq/bZ0s5t/D8trHsSnAB0eX9O4/W9683qm/bbTagwL5zlvq9myZXYTLCnMpJ6Lazcm1lsZHJ4WNHiygao96wYIDmpVXsIY8QGQbT7NrGM8TVkqEKqvFjP0MpHURDNfugau+ILA5ouaxMAvd354fHB81ZNxg9czs8de7uy5hdbejEDAAFz1ifSKWAdeJr2TRCbiIMcBBuFiAwFG5vqGG/kxGrQAkabqEwi0xIErHkONClMWTTJYFtCGFK0VB+EQFmgBaRInYWtzLTzaRIJ90+7toPWyJBVjt2Rp3SeSollEqt6D6OmGyyVS2XkL99dW/BSWDt5hGk+BxEUc62CdwPVie+rGmZUuqAt6bKhr+KR9W0YNV8bhztcpqk1qDIC42F110pn2a1hKqVIFMjGQABxlnGiFSXqo5yH+dqAK94WlYjIQ0c6V8ljGtXXW5AZcVylSWkfpQeDHh0XefqYbo9UILn3amPSrF33b66rG5+j8zAQsjekwCdYFSOWcvVAN1tpaDObcU6DbRXV8ON8FpUplLsm70XMlZsn2PqPMwkTHVOyaxaKflYue4bTCiBXBXdKsxlTQarpnPIyti1Kljt9s031zI256DeohCBvne4GQ6Bqk9U4jzcAMw11woa5pzXnh+IuZMVesvqqvKqzcriE1RYWyegTgLBzIAGcaodRphVOSEACtCrgoMVaRhj2KpXh8HMZgTMEhn1GRoP1QpkAREqeQth0chrTQh4XBcZuDRYEeX7A4JgiLVBJGFuXGuCtiJcSFJHG0xcouQJ63BHJhOFT+naptXdpxBtrLDciraRuGpk1Fck1NHQqA9AYMF0IiLpDGkWCqSkUkaNBq89r4Spojhdf6KumRxmqkONia2CBDmcClg0hA1NTt7X6/amVODbXyJQt4fNvGZMu/UVAJiIKhDIBieY1HS7KhMXbi7hnYgA0w0RFhHX9AtgroyAnW58Bap2odtYj9WfNrq4Aur8RSx3FIUtNR6nsrJdSASoiKZgO7VIB7zI84Gm58hQh1UkpwWqH89wG0rKomDLBq5FXFdMJqaLjuMK842X9F7oV1hVwoUE4eC4klxu1rqWZJfvwZYFBKvTq5T7oretVjyk3CqBJaENKMSIQF6BAjNTH31GuFt2AQ9EXqvACkPQFKksVJ1IpPVOd8xWamgRsdYctpV32E23LVArGRLdPSEUbcsrZdTGKZ7CbQqB6AAwUPPFuKOXemk9NM0LWSVgxlW5mJ4UFW5n1Mnf4Z/YXC+Rj25KNVRa1xyHFWL1qIxcssNZToFoLZrMdj1NF8oYYYsIq7Ys1y7GVomouDfamFAmuiqJai3MwEIBEn17u9B7G+YoBFBrh5rZ+kPqgYq3FxZVyyxYoxLM269ranljU/YypUSxiXaRWTXlOtwZvWPVIG0bu95GE0QD6EbKUaqp1xgzqHbh7A6HXQBvgCgXOmmTs0YHZr2VQCBHq1jWkUMkOBEsrRfWGCgCsOzCNtUkQESXDGiIDPMBYKqZ0Gwdx+l0musgrD/AdamOTFuSfmSBF5lQ88dLa62LX2GbUwkaEkFzo401c7ONHWJlBYAZSgki4oa6EdhiC6iIWqGLpJ0I9myYmjwzO8pyM/nxREA83RIBsxsGDpG5Vg4Po81VV0+6ZthhMcr/R8HHpBmq81CyHqBkPlVKWGkyIGYemYZZ0EdVIyPh3OOSCp+7iZ5vAvjKEkEaWBHxmmHWaGkJoJpML0r2DofoPoouwBYn71huT2Wqe/VSFrsrOB2Rc1OnsiqBQDXm2K3PzqrgJHv4Z9c/u6P86s9V7uyIuE22WK6hzLtobrFKx4ZW4m7Fa4zOjHYqUS+25TbIVd5SUE1FjFHWBwKGtxBh4Wfev91nSbGdoFzJviZ4zGnuWEvWMLBQfelMM1mNykpTdSszclZdoOB3rb3yH5rFmlCw0hMzM9v/qDKVqgp3ytfBi+mFmvfbebygQ9CWkndjJND6A2ulDa2XDB8buRV/dNawp1SX+CKjG/avELTeRi8YoHVDsc6wwJz6CWFlaRozXD2COhTFkdbCy/r0mUNlqblpEVUKRabV93epTPevFMh4jakUDgBEWImgFbzDMiR68IIkaJkpy9iHdhXgZCZhQkRRx4t6DIpBGg3rERQaYXRzxkyDwblyRfXLhspA3T8go9tnmUA0I7I+hZqlQtrPgVxWV7X4YGFgBpmAuKE7e0YnHyqR16BgFVoFBjbwcVPmrZ0tA92OJ2JVgKJ7kOrCDYg6WxLbCsaxAXWUebnqAzQ2QaC7J9BgTGRE1hXSS9I6mld1Cr1hWmE0ZliDOFW/zFgOmttaQRHE+rh2+Kc31adW5h8stqBWwhTzqddyIkVSWJltKDBRYzoL96smwJRBr9KKws+KRRkIGh8vFz2EdIJoyFh7smHnJ3UNTmLtCkLsJNCkUdMpSiNa2uzYnduyP5mYir2twmFUvxINwBizOVCW0qiiBPcNLS8IvalsFoXnuYl83s8GCK0VteaIMAPYUwpLa1QRE3Z8EVLqMVfcb2nbU5kxZkAkIIP6CEnkDHeb2XRP84qojRkLTbdlD78OwMvMWjLKXgiZq9kbzAxToKz4lzoH+tAWCUOaD4mHlMKfUO2ydabumsw8wSKjuGodh3UpqqJ5kMVqUmIOMX3r7qOQR+ykioDBrhBqZyClBHAlVZT2i8oQfYz6VJGiiK9ye2g4Q4+gxdV1jlGup7BDZA3+ESLbuj+NqVg1aFFUtTaMwoTBFPPfh69IE4dHD1Oi1sqdK+2N5pfpyleCbZaJuWKMMdfiqhDOKXXIZYSZrxlsrsM2LHNOWfAqK2xPrIDyZIRhIhFwpxmwruUppEnCIhGBseOZst0hEd8ARl/GakNSN6rgHxOkA3UlMgPn03h4uCgPiChljWE+92QMRFnhLCUwKIUARZnOpLsHokDE5oCWXG+nGBVcZ4TmWlQQN2t4hw1MFg/NfKnNgLVwOhqmDImkXxuqQRX2k5mZpsnwgZoeS0f3kBqqpBNqOK4SS/Oeh1oHwMfLxWlYLGnXAICVS9tUdbAo4p+VtMjw4RExjwPeEu3lm1lXP1T+CSSGrH4B3ZFmcVQPt5tx5hIjD8BVJS97NULJk4Icp3GmucFyrrABSw26CNVMpgq5gcxwd1MOgSlHOHxA7cdV+FdRqEDIJspl0SYEXiUHPFbp17rXSUwJBIZmxAqOvpFlecmhsINK7sqCidkr9t5cBFdMQF2z5o5YoKWile24pYMjl5uKJGwi3IkDOZaJDLcgtYxIiH8g+2mJmAE1BlRDWRs20av6rpLdXS1EYsZUKBby9gKV2r52T0Fa1yK2CJQsawDSLKtGBtrlODJy2BDtI9iktcxtNzvVz537WpmOuQjCHcxEMMQWSjccMRMYlvVQWYIlsjqpavlWAam8Rq5ok2aHLpT5bA5ExCKoxZFUgsh+trkZRqTLxxrVm8lCxK1UVtDwNcibwL201CMzudYKsyF8x9JAOEZasGsJC2lmCHHQu8ga6TbEvY2MCRjNc0sJSEKnMgKV4Ws95WaZ0xABS9cTAopHYhS1J0QpchpBM1zW4d33H+yecpSHUuNKzkp9loZWoV1XN0Io7eyqYdKRq0KWbIwwMt09lXpRRIfEsQiRcjICAxYRJ7M6qLDhDBaHfZhlRV1qTE5kkCMi3AcsVkiIz5UTzDWVDlam5z3ZPa8dF8NGrCCvemcowURDBtXMZiX3a7BoCmSoepGJhKPq+ZT4azZsZpYDl4gBpeMzQ/3BcTLPzAwLxBqZU+9uwnekxkODZZEQprgzsYFPJHIU9hDHAck+FApyBK1JEmlgG2wLIAcK/KkeDFbS1oBDdqU0UzX/q6ZB1HcUBpWSC0TBKA7znBObj65EwMAonqNILpF5dz5H5FoZcRDeBWxKaacKj8L3ncKxUeTyataPrc8SAYsOCdOFxUtAh14BVRVOKyok4Vn52gQ0jiKAkRitXLlWtBNrkVBBaFeguDxDdF3RWIKuTbVucl4Hm5WLo0ifgUTMuERxXAvJUrlts6aL5agwtm+8loPH40UdxUmsuXwnQNKjKSWgK7wTAXObK1wiOCAWxMsOZf1KbSM3zoMufBW/0cdcE1jH6qJuyulk2dYC/QKZM2Miz1AtM7KbBgJJYhV5AxaRm5iJVhHesEXn3/trwy3KfqMi05hzCUWc4rtmqfWJHKxs3qxoLMMMRJAjM4GLmweRNo/DzRcncy6cNWr8ZgOrYlZujazIUfe9PlMT4lR4FihdyZaCN/YVQyJK7KBzARqcNsiHuQTV1luj/pyVuN4kRMaknIZAtqITZqvm4P/XVwllyW9NwFQowZx0YyKXEmBW9M4m0/boKMUNM2OYYIPmX3XLpgFzzs5vRcDOXKHJNXMWCh5AanQebrLbypNYF/D2DLz8g/uH9EcZQ/l0klDHhy0U15KFYmUANGdVd8qFBSqCqjOTmR33Lr2fRZh5SEJRQoRAJldpRCoHyybE0ejATYeZcUVYYgJmQ1hjZMYMd9G3q9InZyztd6+yRvtflITAldPQy5TdjWNmK5ecSlWQ9AAz4aYu0EBiLaVjsc816jgrHair1Ite1t2YE8NBQdl6cas40s3J/TsC6jclY4PbGappoklcaO9rKM23rKdaEtAIuNk1g2e9loKVVYUH8gblNoC0tSaQwz26rIlMDrNVAOUqaWuweKmmSluIlYVszoTcvD5AkUcRNoDlVy0kTyximCTwypTpY41N7dETyPpFCIssB8su0Pr1FMrxMiIippmtOZt3lhDtu7OWanfbQLl6k4T/u0mbQapMFPcv86oJoNy3gtqEcu5sOEKIYx+BzNBtA9NszGNWvVSQy7VJlNlqcIUT1weqS0ygmt6bbpFKWWhAehNoAaC7fm/LewgxeLPRtKyLIQXlLoPV7QPnpklnZuRiJjlQePuy2BM0AS7GdcyI/Fgy1RakCVG7nlKkJ6scuNpWgQ1IKUqobDFTd1IJzP7YeihCYmhlTtvrxGq4OHNfJIPwhIScXVYIysyTscqwqKE7FT+y1zKxAlhh5T6y4e6uuVU0eG32fYnEkOHK2CO4YrhfjoMr3EdFfcIOhA4XqYdD4DCJyAuAjNMFhyHyUey56TEwxqwVzECkyB1o41+IqdCq3h61sDZFsfaiiii7VN7eiMBiAu7IK86RkRMi6qgip06JAOA+1ppNSauLRlQXXcYs3qkuLErnMSuAziv6eA3iYviIJcTLbLMdxXMnxB6aanu1DtAUtGtGQtaNiooutEPWETwzlguXAnz4cRyoOYMVGNOt1k0yNCrsVKipk75PBItIK49zjSt6YgqyeQAoqmz3rV2JcnoCBeSqKmdmhncIGJFj+IoAKMboDncEKsgjaixiESgS1TJuBpU83TWBBATdaMyV2452RGzmnMdxHqeIjJwa6ldxdzsXK3OjOgSye24aa7ZsUpciMiVUMGYwM6ret2MFs8w1aCox1Nkza7AqMtXWXGd0bXQL7b+zXPDJfA3CrM2OEAkFnnD3uSah2gfozLg+CzrCEEWkr4N2qokB9YNloXWuFeu0vbMOkFLqtpuCBDElEhIcCiA11ipl6qJE5eY04F3vfOenP/0ZuCWYsZiQjFrUcWPbeYot3ziNplInEmcgJQuq985cRCKnlF7kLrKqqUNHDv1oIuPBrLgO2eM/OkqISLfdCApzI3LFUoy8VCGW9aBu1qp70WQp9cvQPXJlJGiXOU/DCUbM6DEzrFuMZKqWrafBlV2sgKagYNkUlqJstPZNm2YU/r7U7FFdipUtJ5nGQRuodFWbvFrmTi9jhQgULJBdmG73QRY3rWR9geIXim9SVL59TAQttlepcacm0QOV9LPaEdtnG26oObWX7OE+NnxEzFzB4Sf3NSe6zRxXsZ7sfpkgqYpmaKKczNiMGEzN9663SgvMDKOt6vmpX+8wtgh6KAYWgVCEDsPKLKBYD7jNcj9GFEfP2qyFROBJCy5z189eve9N+NKkOvkxpTEprseCdrmcvK51JCLXDavfZNS8mLy0AMjHUak0sS50mwxLuMV6wfSynFHxVVV3XlLm0nmrFhWd4go1BB/fuCeIXJqmuGqu2cUsG+0hEvCqklf9hT2DWkvfx7zA+jIo3d/aAZt8kmp6JZC0VZIgupohJZXQUSiMQTCq5wMqlwDV+L+JC7l5XmFso0hsx9gUg2J/A0U3rE2UFyk8uzVVFLVls5lKGiGtQOKbtb6a6+t/6FbpygEwFQ6EBBYVILrsy+52zIrEbuiTQNFwWLMBaus2+jtW5gqjwE8DlqCmGdXfAUTkMliCM2Jsi5QVGhFUu5rD1GCfsIhwswUk0hrxCkBDx6Ouckew25Kg1IVuQAIShKUsum3KGBMIVuRBo4xfhSO0TjoUZ9QBuh6X+gNRqigygxFVQm7jBLFiLZBwt0SuiOtHw45B9b3dYVzVJW4LThpWglI9ReZwQ5Uvbw5Cg8LZnO0COEAwQ8Lmxb7SaMlqBSClXB0f/8Qnx/kU3cxD6qN0xIrNB8oDiUjLBgGIxSpwJrPFzcLTNDljXWv1ay61BRRzyqKE7VJXMnM5vdICSsdP8wVY6CGr6RgRS7n4SjMz80Y8yjJaZYkhuqHQggxgFGXaaAGjVA+y7qddqSsV2un2laY2KlbaW3jzL1PBIFAhi+6q05tfHnX0K2dphgxNwUJBLzQ3AzPWggYLZhk+8e+3sAPZ955sDKRC29J4UUQjFUiU5+lLTJVpvfKGaqW4kZZCn/OyLLehwPXxEzR78fBimJ3GuBxHzGVE1qie2BmAma1rx0JGqAcX5tBjTksHRrJnUeUKpWaNfxIk11qEiWKWOx4gTS3HiwurGqfKlZXNLRLETRhBFYn7QSLh0JzUqJPJ5ubVhaB11/+NEa50Z0UkYiFWxpxLWcBlzeLi6jgxI9Kvi6fH0twKWuQJufLIIxFhIz09kQsPJ/NYfar3iWsCaNUTZMWbC9Ya9zp6kcUK7t/rfd7mf4BBCsJTywBRdZsxxpwx11QeM2PKEGem19lgwfZVgDJI23VHiqpRtwPtyLs+qfqXdPjnmoNF9SwSZQeObnT6SgAtB3hNplU5vaq57a+SvOiMPyMAJ9ol09w9o4IvRYjobLWyhratumFfAKUn8tqpqOSrDgvAJpvU7ZdMV7vRjow67scqsPc6rHAHG4Q1ebvOb0ZEW2ArB8XoiWYqy+bWowASmoiliyNfWmxeJt0sM9aqICAiODSfRAbgZatw8+xIw/UivvR3isOQGOM057zpHi60RrGzmeWK6sFDSKSqfFc5wcpAK8GuhoWiTWYiV5iZ9zSC7PoMW/VCgYLaNkvPvCGMBiYrnNX8DyGGddM0q55lT2rd0TLvRIdQG9RJbyOtbIbXmymrYmCuWAJes44I7DxCxQgggcBysUUig9miRzESMFvIVOexckOouy5sSUKaME6kJ1ddk7zVUwhgoJLxKEJJZkITCSNVqGhLl6kPme4nAGsuIlwthAKwru25gSYPiXq3je72RxmLu45rnLGIcD8xaor4rlfqpOh3LSsY17oK0pAsf8OtAmyqvBSBzDS7duJaWjB3yUThtdXH7aiFpZY2yEkLCrBSuqPA3FqaYZuLSlPJHSKxnO4+BLschGbTRLRrKp995Vq098pKj/XAyiolzYHbvHDO+fTpE0Qej4/nuxMy1wzAIpNWAgi5wn1kHnEtHVbrF1INdjngRLkxQI2QsIAE4tGiclYATOH1GRvRFjEt1lDX6jLQUGcxUvJZGRqvygTgaGGaWhDh36EbtjKoqKtqATIZ1+h+uxCtEEXCWmEa7VchZ+33hn9Ulo6w0/BlEYAHPC0tL5Y2Vy67wI6nOF1iHuv+dJ4x52Tl21fXlW0Xr9qbVXjorvSC1BSXZUZHJDum3n4rIipMsPYV4JaR2k79al0JGZ9syyu8suxOJw9FNbg6rSaC7qLmjXPSSg6z7CjCIL2O9KRqEU2S7p/P2+AQxI33ze6MUFlrTXePCJqZ2ZyH1VtHliGs5uyo5Arbql4DzsjuzhCElEaLNbMiFbQBkVguaZniA3VR19SuTG3dDpXqxTIWhpvZnEsWkbSAVO2xl1sYYjbZR6jSLtKzTRBrP21GmHE0By3zqqVUAUcbrmNN0nz4movqSCaSsDAdXFQxA6nPEiylzk4GrCyNoHEzk7561Q0bR+8yGkUVXMiCs2YAlkOLp2eTQavTvl2yYI6KSUqCzMAlG1mJkNuQoVurPkPdiYRy6+6oZzelXHsZOs5NA8OAzJEMMLojdJjP3YyD2HVPIHff+fWrKq8lFY0+ElU0TISCiBRsqUMoOmFVetlhRewrlgX/CMeTTmHfPSJD3snTjs7utA/qPx+17rzmSab12iVy4HQaEVmjgsFYE1KPQaWFPpxml8vBTJJN9a62zw0xVWCkADQ0qzEyl/G0Eb0hhnbbyE1U0CxJPTu6qmmq5GUWSaucWgYy5gSKa6fEqEpw15K/3oK7A76D2gpsJ0IDOjOvsUBfsKxgJfUDveXlpFRcLnhJZY2Gu4pAVWBDhvTq+tZanaOrkKoafa1ve+6aNCBetlxL0rki4pggTuO05oy+cr0TiQSOiw44Nnkn95QqAzgzbLXMSCKL7atZOEFwJTRIJ/T2REq3HuXlMgKIkSMTUc8n+quldHRBCT8UHuLWSJNCxJB+ceiS9N+xy0GtrmyqBfAlpCCDWKKmsvPvYsPJZ15/WlVvTM6TjQI6S43x2Qnn+yfnyFc/9tF48vSNtz998fzBeQfOjIyMmutULVftwXYm2N9JoIaqSpJVnCg9hWJgMUFWYLcuCaa6EkaYyCPl+iZLKaIzt46cdVokqcuEa8sr5gTRLoLsQ7OR871yCSTMlV6MMeaaytXYZlDYYiAZ08wrQcy+G9q+uqJZ2L/k3VP+HxpxJqe1YpoN3A5ZAc1FW02gX6Dxcx2O8iFlxmpHi7ZSbTjIDopS7jOqoq5MqJPCUBsAAE3XMYGpCBpC/pwEKJVc96b/AmCRIYMJmPfyzgUrj5IpuV8p9cYELA2BxJpG9mCauA2GDDXzRHMwI3E6jbVWnZaX8lurZj0IpfTEVXz4GqFulSoz1+ATQa8sBi1hQFhijBFrwhCZK1ZxgLGLmK39qSBOIZT0cSJE3AE00Suw1Jli5iNyIYqHWOWyQmEREa4G2QJ5EzvNkA/RkVaz57WHs85Glb1akyHbl+8osE0Nek6YflWBAtKYbb5kNmCKc4ZEi2bdjUhUd4xyM/ESIxmWFlXIiT6T8tElIhPdq04sqn5hUO3covLb5DCkn9zpDw+Pque5jYfLwzBnTRYKjjMxA4ow+9rt66iqkWbUDo9YQsl0qsqwJbBPUKrtjak8wKra0Him1rJO/+4Gaz66Th8aQItWJtsmQKUsG2ZTk+RA7ga+hAGeyCpVcZTVrYtugEYJKtoLBqNuFOlm4qdUTl8fNcCtkiESPyrPdVCjsiv67pxoOwBB93ntjWubKEqLFjAyGC1b6TOqRihnU6eNMHDFIuG0Fy+em9kY47KWZVkHurvZvFyGD0QVAVM18arA0mixNPeyOsJT4iqavhyQRvhcSawMuHsiSommHyAzpBYFWhpgHrlyzbOZ70CjQvUUrhfiP5o4z8GE2YBhRgwfEaFVNha7AoW3pRoS6mIKawuwyvNL8JWqoZVxbiCi5FNxmAxMTmRYBHl3me95EU8/8cOv/Vf/5eW9X3xcHn7BO7/kQ7/mV+PypvmTY12iHE3euvTsTrlEVPCsw4FiIkTCCRS0L39jRJjbXFNzMKUiGvroAMzcZMIzjVU0qbeXQ7fM5fBqWMoCnoOMWIirEH9Xq4ulVf6rc6DKureF7xurn1wRwxjIyAWaJxIMpqt4SKWE1UYvo6lZKzWdUJJ7w+cRSYxhl8vSiVJrQK4YpxOBFSsLe8c1uGKjnrjyi0iLGRpsw5KaK1C0Nqby2mobdHp0HyGYgaAjMscWAmgqT8CAKYhY5su2XQWsqZGFlKHkAySnJXiyIgHQjCu7njXGZU2iqsiszWchKEslwFhSYlC12uw41slsoR6nSF6Skdiq4NkFMlnaMlEFyepC1sNpDBqWACWJn2TiTDuP8/M5YxPlpaY5FE9vpI1aEEcRjkjJxuTUO6dlhFeJDQiJeEo9vc4Y1XdULUZZxDHhwhXL1WXBvrAGgZyskBkZMaoQuS4A0bRE9aFn8WbU2xaylNVuQDBWzOyG4FR5kYboqgFtlRsiwcExExUXG3OPEUqJ3gnKrti7xNKResgay0A6sNDHkqCZj1LUGIAdK2dOTQcx5LwsmJV0htl5jGNelMxxiaKgZAlBwkJII8zcUoV+o2MnjZmZRayjYG/FFRp8WiTnWmlFUq6WZLFR2rE6dKZaQwAacKaE0qgouI6eEVgxT+fTcVnulC9UV6S2NlCdwFEaNEUfbBWEMquDAL3Ya9c0gzWMVu9eE3WEdfO4rGZi5TJxwdngleDQMNoY4/FyABDRhkAyC4ToiUZVb1IHGQMJj6AXPAJgxooG6WYcd/BlFhN+4onjMo/h50mcAzMuaVhzALEADZK9qhV2/hkrxrAVK1Y150WsyEyar6nihArq4tvLZLiNWAuI0zhn5hGZBR7qepbIkSqyZsTO77fpJJIm6pDD3O2YM9KTyOPwnv1pw1WMMXAVQ/9ac6+00xAzzGwlUPos4XpxqyEjouxGhI2TLSaaS3bE6f7p2z70/i/9Bz/4/PLGs6/9JvzO3/OZD/3QO/7O958RzxdzzeTVrQvHliMEOyeQ+2JdtjRnhg43iVSYERkR7ozE5eEimyt+w8ywZIBmxsCKpcvT03/q88tMlouK7EZ7ENXQxoBbns+n5w8PNtTun5aMVBP/iOZzoWJ8VWYlACmdABCwQFiFE6pXuQ9zu8xZEDY7cdmgjcIkWvWUIGkMo0SWL9WauDMMc4UgtUCE9HiJMCnFlcSHC+w1m027aYFCmyuSGsoYdhrzWK451xE2LKZFgtzMOrZHWxKlVD1JrjJyk6SqplXNWLPy3iKYEhFVel8m5BuOxrgTwZhrmXtGOJlrnsGIDDVoa2Bz0N1WxJMn94+XR8C4IiPvzndu9vzhuZktZQ2KvXI5zUb5G4n1FEwi9yScyTIi3LxLv2OtKVxyapp4Apn3fnqYj8PHmnj+8FxgCqLr46VgzeEu0Kdq2CtnqiOua7ZCwQR1dQ4b4JwXMyMq0kEsB4bbMQXSmHKfGUG42RLi6SMPhaxKm51JzJjDTCxEs3HgCMMKUNwV2f+6Atdyub7nUu8EkupCLiswAxp53jifhGdTI9uxlsBThTSKPKpxJkMclIbzUCx4JzIsE/Qs9E+gdeO11SkOI2EOQ2QMWYUCgBSA0KyiwQZSYdIVS1JwjU4/EWpM2hjqTuEU4Bs593d3CUrAR3YLkQiy5QyCLYiQjUuZGZzzcpjMtZgyNLETK26vigo7OQFpa60xao4VDNI3YcN03WLWX+ao7qKdKMHM5mUqsqifsmEGUayVi9w2o4RkSZAS3GAUfroz9PJziDmniq8z0jS6GKCpDcwjVmHHqQBD8EEhOInUaJHiRIEGnDCAGQEMy4UcjzZeRTw/c8457s0vR4Iv0kfMh8h7871N+3OJESL6M2YsNFiZEYcg4EQCk0kmIxFxOp+XKKNpx7yQLP1FIxOG9LLCOo1SduziqPAAQUGRmRBNcal9LmhAmh1zupkNj6ojECrqM2/PlagNKiqsuSKWhiUCGG5FHDMjuWIRNNfU99TU1zmnGV/w8ReO1yLWw+/61jd++de/Eo/nOfPpU5zO9vji4IVhEGC8lmQvVW7jbpQUSEQStMSKVAk7opj58p00myvVF9ERtHT1opY8lyG3NEd2gVCNgqKvk5kro9XoVYFZpJFOAnnMkBkycpMPgkAsKuYwo/laS8zKQUdgYuXMkxFmU/YtiFgwpnEiMeewsVbj/IkGPxQEoYHL1MNZJGZle9adf+z7R7NcS1x9KhqTLk3SdA1UBFdwUyWRKzSNfefr+qu+Lr9l9ao7SdmfFBxgJFY1elQlz9qgV76Dyn0TMcaYc7qNRKxqc2dsaSJZgMJfZM/MAgtYoCfADMNAzoA7hJatFeZYcyJyqTROHvMym+p0LRQX7ipyFswKJszmHOjeqR5ktBXLzZO5akJ5zIDBjgxNRbjEMvqU8P5eQnWiqrquiEw8rF68balv0J8KO9UHoixCAOj5dIqM4zJPMycwLQeNyKXDDCPdaCvCqg7BiB67bDSj9G3EOsyi0EciPTHKTyAYjTMrRoKBDs6ScIM1Mi0YeHOgClrt/4CEPqpII1YCosuIQt7Coo+ZYKmWrkTmkafhdJutceCslnPpdtViKVpoJE6ibNeFbDgVw8d23/ICqaTHSoC8apOq01WnY7YMogBGBFbdKEB9k3K7hfK2w8fNV2SsKDRRpyIiYsYYCkzLbURES1uE2EOlSxAELEtaSq+DMRywiGXm5lK2oLRUMluJO8TZ2pG5/jvGcOTGYzMyjmPtj6bPbrunvkOtRAaSSCvHWahnFCgmUwvASOaKmEv8MkQg0lUXLVxn747ORdH1xEu37jE3NeVamE3kXCtmvsjAczyxt73+4tXT5W2vTifgk+fTaExP6VoTJaMWNqPuuZK4sigunl4mM1j9RjbnLJkOg7kVJMk0MIlluFgchjCEFMJNuVtd6azYTSVkZCACK2KF0sScUZWGOWeUSF4gY8VcsVasiFj6hUh9X6dckutaornmzEWvnN9Z1MHI9GVIPC5EMAP+1uNPf+m7n/+iL7//2CdeHX4gf/a/+HvzK77qrcfnmJlKBokJiKN5ohlM3xYqaQEPY1rSZsFeVdo10orclEW8Amqps6iwERYwcjAdGEiLsEyLjNPpfHd/l4k5g4Q5V6w5sN3RMqZhJH0BmSsxY9XcW+k+ElmdHn2gonL1rvVmML0yegtZyYRBl4ixhGRyLeUSBpr4BEGqeEGqgRVVpq/9RWW4Cp/Ue9pXL0UuzGyJF9lEaS9fIVBjV5/E7hefNCOrCYpIxkxK/0hmdzOesvKZBrHQTKZuGAOat6/sI8qkqV5jXECQC5J2YQocHn717Mqbsyg4g2Op3hg5WU2fCxJaiIrWkJl5zEPIpN49QqQxZNJuRqQL548MMAK5UJOSk+08b0xp0f5VpyBapEH9aVlHThcEHCh7WM7VkI4h86KrLdyqqSRarWgLAlwpGgYq1szIOS8xp5s9Imz4wOnh8RIaE5CNXZUJT9X+11qCiwTZlmdNAJaxmGFrT0UQ1NYeJNv0Vgoueq+xnDKi9lRvFb1jiRSv10Cr0prRxkjdjy4wiwUV6ufupVakop945ekTwuZcnjjR7sdJAa4Zl24gq0KvpzOD0UZvXPaB7JCWBa4WfU48ryzeLDelUAgzCeROaIr2Lh6iAbwpXGEn26wkr7NQefQuJaL4AqHDGmZ+66mHO8jjmCUSWbhDEet1JHRe3QjQnaHYpeKDxu4lsmnSB+NWF9A4+Awhw7OXpj6BjzHXVOof2QEFJEMoJ9vMoewHrdyg9mDzthYlzRQrc0Wcz+e5VpFNcgOroOh4hGWaIaqRo5pDScvgPJ1tLcwDp9OEjWXr6elLXjy+60d+5PzWxy+vf9GHvvTLngXvLZhYO6kXIJC41lMTVZzrLF8eMygdqLRMZTJh9KsmBrs4raJ7oWTbLBQuYdbPlNXZASOxtvZyS9Ao+y6zEREZw9SAVIJW9aaoLLROkdmcK2KNMVZwzQXBoUxlLcziWqu6vNJsHu6ZZi8QT4IPkx/4xq//ir/21+eHPmDf+u13v+bXfuSdX8Tj8chgcIoyEGnAypTX2NXTQE/KCGybpzNvZnGTNdSHrS5tM7PzGJM1uDQrvlQnDMw8Eg8PD2qBdfe1ZswJcPSYdQAWScrEtkEq8EpLWSU9V51YyXqGhai2WFnlSUWpK0NVUnM7DqVPcHh1UrHYEqVZlCAai6Aqk4Ei0SuJTESYV2UjmT6GbMWaRQ4ScI92YOUIY8rWyHGLFpI15rQHBqDaU6guqxQs17kaKyFnI81gEDZVHOkNKXIckqXM3UV+pbokA4OGgEOmPlXAXHsN5BawC4j0zGVCrDORs4pWnlPJg5mHCrTuHiu2woEZVqRlSpA9kde2TLL5D/3GRPPGC4mDkn6ZD0KTVpGYxFAAQmPmYnIt5SHZOIacaQLFNVQx8YpfbrtxJcMJe64trhq28F4gwwg/j3mZA76nD5AU14H1vt25VCMVPbG6N0dUDwAcLLr3jExDZjroKD5shbVKVGRom4fV5RFEhb9asStaXY4vUoRtqxZWme+CNdQ3bA1OsNVQjRXTrJhN44j7p08vx/G4Do2c21FC71zZw0EgjZ5EYiGAEGN9rZXFNirebT2aoF7BZSiJnqjDLzaA8hrF/GUGhMhVk09WILpNEfsC7ORctTUWg4/QWLrUXJTUUXfz02msVfwdqcjq88mInM/ny+USsdTuXJ1KNMFLdb+vUh1aoHKTbMgUiPP5bs6lmxorzOxyzN1n4e4ZNaWrzmWqOs2sQJzsWl3W52jAXb1Y4iqRhA1Y5FScWcyuJtXq1mt3lLPaaj6QlKzXYUGMkStPyPXk6de8//3n9/8IPM/n+/GR7//Gn/nIP/j1v+mtNU/sndvPfbV40sMyyJT1X4qtUIhh++hEUqWmuoa10dqja6ZV55VJLHWa7uYG3VpW5oDMQLJQay0WIpYCyYjoiobee4dkjUcCgRjul8h5rKr6RALpw+BeZdJGVhIZvKTjtOY0H7Fmnnh5/nD39BPf9Gvf+eZnHl49x7N3redvAX4yzMq/0aYKUYhoBS6KKDK5feA+XlGcadS5qhFSEspgxLoIozb5tDQzo2Y/VP7nwwHUsHYzqJktw25QSmWEZmYYiZmBjDQzMASGKwZguctuq2e1q3iAUOGZDDg4EWOGuwkduT/fqWXosmbNaswbsDQzq9ZVZ117JPswrGVkKlKvLg43amCGHkuYTGQOmHeEnoV1iRZb31ROHN3Z34p7yixLYd6QhCX7Rl9tT7mv7acLIkeJ0IUiSQVPYp106rd7mmk8YotUXBOLRFoiudgdhKjocpsdRGAMK95TZMFNUoDbpXUiYhUHrDCiOvZRU5gAiGxUDf16PIIr1hinjFw9CeZ8HiuxHi80ozPmch+ILDU1WtagITDAzJVFI0ftpKxlJ2DllYtmK66Te5MtkAm62guJcQlBcwwYbEI6oA5kRrptY6f4wuZcJIPAUg99RgTdJsolqToQ5FVwsXHm/UVQdSV3zxWojC40QGMHw3opI7P60a0JeaIG+ywpbaUpxc/unxBSj2H+/OFh+LBEGCLw7Pnz0MAB5e5kiWogsvQYEjUCsb1/N6tkhbDV9ZRtQ2jCs/sgZ/m0dumCz7PCH7Dm6Vinu3blAAtMutrOPqXYsBjSKrvMBPD0yVP3Zh+YJXDMOWfJQVSWUZlo0hAZj5dHFHs4MuP+7l7v2o9QD1DKhdvmtyXrS6WCHZS9265SRYhZ7pSphGxszQBCxU9R7xJXk51qu1b4IhXJnGp6HfZiXgJSPQB7yazVTIXWKVQ0bKMi+3WMjBwxMc+Rbz05felHf/qdH/iRV1+/H3dPnv8z//hP/Jrf8AxmJx+4m0rTvvDIsiNqnbCoa6a/M1imJ0bqsBCBU2JFt9wDPtzMit6fABDGZTmtxNgqhqwF6qhCEW5ubKijvIBlUfr1CxEx1xIGVBWCqENbSwzQbGUjihU3gIYpBUX9OBAZc86Yi8ZcBj9jxgKXSLCPx0e+6D2f+82/dbzz1fM9HzHv7KzfVXDBMSLS6RYwsyBVv6hCjZ4dNUVzw0GFUkOFuoJG2XBJBoweBSzasLPZIM3SIhKCAFdD/8X4zbSSUFNaqNJmz11S/hmNv+AlVkiGgQP1USXBoKrU1dQzDTlRRcphDrMj1oo1oIYCcTFU7wdRylzyXuX2dk2o2Cjl98sCaiyGNeWhrYNsSDZg1wel740OCRqwTiQ0YEM5jO4mGwa4tWHXqM3k6rtVdGWUxoBICDcXQ2UzRhqJFYiwhFet0Upuo9yAyltmSvHaoOnMS9GvBW0iYnb51mZpCLL4a7py9apbRl65b11cEl69txUsGIEro9WAJOleCf1ci2vR3d21lRU/9mVhKVq0ZVYDUMUXXNUqGnsR+wjuLBzJqAJcJlDGITImwmwgQjVTp3nlQPtyV7s7E6bRXOxwzSCXhEgLFPF61zGBhdT/9RiaUWdAxDydhjrfqPJFpt3Uv9Bem711ulu16TphUsFqq1XfL/KDSExK48yHaus4n07n0ykTYwy1hrNmIlWHOm9O4VDABr1B5+Jl3NUZr7+kuqpp5Ooga4tZsB3wtaNVHD3EqMIA0JIPdQ7LKfdKJNQ3RZa4thKqXYV8/tZb5j7GkEameMaR1WRWL918XgKmZrV2+XPNUvlJFeRUHaljDRWRCigqypOMFaH+cW7kZq1w964+FbOmlnW3E5VCcvnwBNw4126lquCGTIZ0ViyUygMawEIW5rztUv1DAqs6/SVpBZDmIy5ID4Y9MJ+u03s/9uE3fH5kji//db8mXsTT19/9ka+wF5a+Mof6pDohqYOrjCxV2rDbcAQAmVbD0opBUcuUEhxAaKZCLCGNgCFZCt5N19WF66wwqgcU2x0TuxlGjYoEOE4jIiKWAlg1dW5VBB2iAMSbMEiqjGvORI7hNoZKbmstJM0sVrj7+XSas+bmxULyPAIHJk93Mdf94+OnPvkJfHzeTbvzV494sQKwKaEQTo2ZqkFoah6sjrtOsgrQzD4BXbWRyhHMRYoQypdCDyTnIGGFdRS2XGUf/bZVrhSpsVGnYEfR8EASq2sXJqQhoWYYI27ktHUNI2pegmH3oSJZNV0k80TOVNzNFWs+PCRi2MAV82RzHzu7ZJUD65kAEUfnPMY4qUaYpoTe5pzVcVdiBH09wKWFgp5FFU155gIcahnYiyT1KKj4DINJWg4V9XX0X8iD7Ao6YlYmmQAmNY4zbsJTBkg3c4tcUeLSuTLNnLkU6PTStm2mWWAiEzHCFjJMqGU5yOwk5yq5oJsdbRNld6rQCOXF1V6KluYtzKl0Wpy2DMgQxxDIMTyOAG2uZQlzi1gzVgJrBX0P1at3ECagRnyXUa0BX0k1P9luA6ijVA1ytIhwKWZnmFuKKgi7DERczuZJroxXnzx5/vz5bQN4r5uCY5irFwheICqF2Wy6QbA6l1oFt/xnOY9eS8V5a80aIFRqBKngvmOLLLuqv6gmLgIri8tmAIr5zMpblGWWvIzVrMwV83S+rz6dzBkL7pl5rLmLktf4D6DZQEuuZaWqTNQpES9dsYHMFpDHnClXhUTC3UprIhStmgxhVoJuJbRWoxn1GZQLhV2PHRIpbqwi2thaCr3BHXKIDccC5Td+VChMEswAEz78Nsdykelb9LH/SjFcpacKPCI1KZZChlKD6DIpwaZqo8yqi+7iYwdFReZHQW9SuxABppXdtocJNcmphyIZGWnuSxOOo2IuFVJAI6VW1a9AtWEXqJoMunHGeYwHw6sPb96/8WB5f//s0/GD/+D+81/18LYnn3n3e+3hcvFkeBT6sWURlY2go0jcnm2wr3vdM5FqUmZsxXKJC6Q8HFauk5Iy9q+r5CXeDRVsX6PoonFlR6OZABdiwQAcczJzuAWqniIdAXmOKiakXDZmFO9mx/4xpw3PBcALUOnjlIkVYaeJwOB9Ance69GnEeMEPv3Ef/mffcUXvefNr/7ah2fzdL7LWeV7kZtKNicSbiW6lZIHgJ599x93BpMChG2MY0YDXYic8r0RQfg+tVEBOwurbai1SqJgRD5gWlQ1TnJ3VrV8QmCwsTRqYlVHS3Wmi4pKI2PBWPJsgVxUpz6YGU4LJjkzIuHk4JgzzG0nBWXHuggj6Zma6uQsSAMwkyTF0F/Pecj8dlmg6h3VsYrw1SQpAKV9ARAuHcEqI6ranABsMQlzNxvzckEj3vo1LeEVnqq9YFFL1PFhXJr5yGtFUYYbBGJl9B9j7bZ1kzBtahhOZwAJSMRBEkLDrPksQHkPdxczvzNkXb3SpLOtEFwfMErhSB02Uh7OIOlGRtFO3eDGDMtWQ58zI8EMafrkimJCZoabaL6yKSxQIK3LE9ceGpaXdDMx64PciWQ7N0jgSZBmFJa+IvjURticsZSevvHWWzS63fI9Kp4vQnauRL2aCSGYYSdfiYVFwmCjdnEZ7AqhZHd7w/xkj5cHurn60RXDlpZL0a7qzSiUQ0P8OpA0O41xzItAdQMT1AjIEOJmGD5S5AMlFrQjJiIj0txjrTGG7ofTZkoyQSQIAWTG3/Wtf9ZAM1xiLeSAZZNNsb+sYLIEVswBzy6nutHgKwLcYgDXpFaPR1A9wyiag7KbghYNVc2vu6F+iehpRf0VKA6G6hn78iEhSpL70JmPIgLEGGNGcFhGrLVOPoSVRxvoirBR8ryKjPdlyPJEtSGyMdGlK+nBd30kxZImiNY6T+WKrPqG0WCumhwMGXX4FXC0oksAUu9KQVQqtwJAVeuyyuPlJ6vuCnBiukY/5DDaw8leifiST3z6VffPfeLDr33Zlzz7Be/+wBsvTrw7/IJIM+PKhPRn1WCmhyqD1ah63T+CM0qFeJjrxgU0k1jK9URA86ccRclDpPfgM6BVnFTJo7CWHbGpe2TqYXv1PSM5ECk2LyMwHCumc+TLflyhb6iNp/rFYe7INHCuVmMFAFQnkqkdUYGz6tdcEZmBZbgfePaZ97zvx+y3/o4PfvIzT+9tHkYPRpiNNOQKcbqzRkqJmaM2VTFZsms81o8foqGttRqvvYbwSDWhRW8rmCnimo41Urr8UWOr5TgapE0k6Wo0tXZdevGIIOgiG7LqyNx92IgVKe6pgBClkqUyCAslNKVbhFyVvUhmUoecpXGIaFntSiIbLXSjlTojaBrIQ/G8Mqulcjcf1iFBnRKVaPQjoDuLeinvLqJZsyWohtfs8Hx3oYgfNGO1I6sLC6XeLRAhzUh9zjFOM1YGzFwavdb7GAK9ZQFgqpsoAxP9SZ+YbaxQRM/CISLSfEQ27KcnruXqwFf5cIabsafbqSQlWi5bw7Wg/uEEck7wmmbcdo0SNKspPejKRP07CxLcJSWaOarTLWSXAKxl5ql8pdSWxNQq1AQrnJBuIt2rraTLCL0V2JciSvENEUERFQ3iRe8ErWgjpRyyjKYJqpKQI2HmbP23KJNc/Zu8SnwIlmDXwMKcM5alIWNwLOUkUpwurYBciDFOug9WJ6lZIInTaUCa81bKowV3miHW3ktzrw5jqMJbhzWSA5qlHBg18CRhcLOlAlKVnjUlDkjATLPKFJatyMRMNAq2Ma4rrU62bceSZWpYCTH3OVsaf5EwOryDxU6RbFS/pNgQlScVeKBYKeqIy6e7r/bEmRg+VmwbsWMloXsVtdXz7hOSmUgPTAOZ1qOoE1B/RmEmFH2qiqaK4FmhnK6BgUizymkLpFZvMqFQjxzD51oJiSFUchexKlZL/WehPld0uxK5PGME5vRhCVsPT6etMd7/pe8YuJ/vevWXvfcd73zXF332pz74+c88Ow3PkrUi0Lcx02hDT1kY2hWCJhCI+/v7mDNA9Ug04w5BDNCAZUbECVyi02Yrn4BAjjHO5/OzZ8/MmrovFLqUDrS8kpfZMIFAVJVvQdBKiKXEEphpPZ2ol6R8sWZ9MAOpUYq6wtVmpvIKSY2j0KvdsM6RI9bDW+PVd7/x+EO/8KMfe/Xtr7y4XE4+iAyzABhQT63Kr9vGXFlpCTn1FUEKg0kYC7/ScNDmi+q72ogKeOrVKEhGaRfMQrS9ki7fqJVW2USJhNDOvCpd6aVAQFebUEksKv+sZkTlwImkGRExJTS4uZsp2rZZASKprFLHuq97i7QIB8ASV0Lgeb3INb4vFhVJ3hw4xZpLLKxKcHmdQ67ZpQAEhokMphyGeg/RrVVYLRsTxZ5Qs01khOSuMiJiyPQLQjAzTanLkP5ue4o6lAV0V7SNsNBwcS/MSka8SDtZt7UuUpXFU5+od1a9rWB0u3dm0YMtCfMCF2NfiwDgVeVuJVmA1c7TyU+DE2XOrIkWTevT2rhkhRp8UPkdRa3qKhMCK8zMxumIxWrjVDyHxI6csoB8My2sNv+6AmgDJicpZJQk0r19hHT3FJvGlhGUdke6eRKHmptrxkxERBNKNw0dm+izAahaCHXtEwho1mvSIjfbsauaNBs2bMzj2OUjqPLKVBPKrHmg9G4arUQglkycykrV/oRFoBRhq2M3jUuYXTZsZwA4lygGVym7UrGr9ZMSbGQ/JK5x6zXaqb/SqSKuHCe1BbDvvSUs4AmLzDU1TC6W0uqy9SXpXOV9tew220Wg/OxQsPIB85QqJ2yUjZeHlf4AswQTKtOIjClebBMVtaBhGtnIyej+cSTD3CjooPNYGmBUITeAUPMrsNQ0EUg1t67Z2rMlFFw6VKkYmpZGIJc4UE3ZQMRaTRCoT3ctoKdcGWzN08L0cTGcZzx9se4enp+Tn/rU8+Oty9OH5zyd11I8V77cEmrnTBFqb5EP2ZiKIxMhqdrl7j5c5foSJQeXAqHMrCiusltZc4CXy+WNN94wc1TVpSIJXZDNKmcTvzIRuWRGFVStaJG4AAoj1Snt7oOVGdXBLDu3Vqwl7kjsXIEdYYhjfP2SQyqcZBLmIy9f/hXrR3/ktfMTA09YrMJT41S8boOiznKwfReTOJ1PFdoraKmej0zk1UpLxqiQxvo0OrMbdzTokoBJC/MwiUVt0Kwg/KxW/gJmhS1uluA1RKmjHxtjYQ13U02RMD8NdlpMo5mtWHfnc1fs9fAF+8V1Gfro7KHiiYwcVhTGSC75w9jjIpUHdt0c1aUazbRD29MQgEbYGKyBKxGxGgepDY0o1anM2nFe+ydptGaNkVVozN2vZbCunVjbAxSmYxZd7BUKnnu5wSTSxLULK/aooDXRmUT+TONAO1T1SwCRmWHaKXjCQYkIROtrRktMyASZjAxyMVbBUakhYNnk2comuleJwDBzd7ehYqqDA16YH5tg2r63Ppber7pEaf4F3hS1eVn+xt2ze7RQzIXugkLKqffxyY6plsQNxLhUmFCZptsYThCxWtpBwWeVgzNvipvKLxFufnc+lceQRWMzoLJqMxYsTcCUSmJKTVQ1DOUEERFrtRvMrE6GtJK9TENkRhOl0OYlb+1DMXR1M6vDSzmXOFZFys1CKORgqiWkFBrqAArnJ1estWbF0MioPof+odbnU1hUrKSyfmVZCGQya4Jr1tYEEf7SvqJZxPWJsDsE92XX9l+9Rt3DnEvjGqslIkLEX9t4nQxKLaltdvf1ddgXdUHDpK5NO5ZYa9Ylb8PRNeniAuwDomKlmjqGu5MWIf+kCday3FPFdfRgWDIDXdsIsxEZEstVd40SEKvbSPJk4GvnQc4B8zxfzGz4sjGSb8z5kz/6Q8ff+O53ffZTON/ZrBtIwHrURLx0N0gzkJspTWDOWQdcucyKJINh6l1Brlh1StnHUehiBIxjjDFOiSLaWWUaRiomVZRv7DqFfMTKQ/lWVGE+Y3XRkEgiMjV/NWsYnUL4rJeGXpbWAxmvO6x9UybY+3Ql445B+Hr+nF/6Cz//5vOnH/rA+f7Vx3nImpgybIKhHpdN1d3IzQ5dsR+yjm4UB6I+BAzY1wCC1xTriq/EducuHQbEjAVDGKaJ+RzSi6ao4Zpav4+xCl5qu4pAkRhqh1jEQW2zmpVj07wQ6YVe0XqUb+xUMdtOo45/O36w9MCQRUbTFMcy6LKM9UcThT3aGbMTalJjGSObHivNnBTeG9IEMW78QA/sbgUGRkUatba9uXUK5HQBBxzGqH5KghGxVqlVsx1e/WJUOclMuFTZdvWYgA1JtaxExRZV4g5uH8T04eZom2MkdggTZrGdoSLtOjaRuefTVNxmADMQteZVpNshBJAC+pTyRaRY3OR5DAEGoQ+EYr3DxN4PD1hS2jgKYI+5nl8uI4srINmWsovaXrVpIEDuy50Jle1ub1/Z7c6vsk10xAQyYunnnebmqnfY+QTXgGRY6TJjpEXLLZiZ4gRUj2GHf7yGUYqwJjOYvvIUVO++8nDldmgZxv7xKhi70eq6IptQbFs0RAIj1vm9TGUzUmwTdKNygXrk6ZbVG0smYq5Exskq3705B9WCoi3vhNYqBygGoD6Z3Hd/BnTcBwONA1fiYV1C1uvIE6n8720R0CaR2f73hqB/BRaG6DA6qQGsSOTwEYlZ9aW9dtdXun4V4LSyZJUC2+Pt3IJWcQDoAr/KC0izAxuPuy6cCm3N/DLU9MoMZNZIoowreqBwPgOkzbWm6iKFBRkgsYLue9ABTrO0ZY+ZfH7gQqSTGZqsIO7/CZxPX7ev/qq3feoT57MfdlhWBWgCq+G1inTbZGiLpLzjZjCb/x+y/m3Jsiy7DsTGHGvtfY4f9/C4ZGRkVlZmVqKQqCoULgRBCqRIGsWWqDbKpBb7TQ96kOldX6MvkFmbyWTqNumh2SY11WQ3mwSbgIEgCBJAXRNZWZlReY2M8HA/fs7ea42phznX8SgyjCxExsXj+N5rzcuYY4ypXmuNXB36LnaJkER5i22u7nfWQpYls3ps5/WBLkfl6wYrJFlsIAF399QGiVHdzWPsZ4ZaK+BisJzQXE3eQ+ViRlqpLCUXjkTl3vvoYkYIsFGBRlBzv8Os4lT3BhZar6jl6ptv60/+9U69TWfy8COJucKoBEfTmmhblCzMCmldVu9ioCWKraNIzHnQFUEL6wo4kCuxs5KLz9bCfityh4FAhdeRJE5t/S/9SFqKnxRA+avjuHH8rUhRXaGlD+72EMkG8k+o9fhUy3Iczn+4+z93/6g48n8AAvEmDeip9Y0aDnetpJ0MwR0+RD0Dks9ReIy7FD93yNQEeQ+zTyPiQiUErVrCUR5mCAXzHazlgfzGv6HQBTnR0XGyrzbBPEecOaMcvqanbzSaDaTHmBmKW/GgRqZl7wC3FD6AkZSkdkrOuovmJUh5qew4Je+7Fv6Xrkb+j79SVdwdx3ysWSbFd5x/BihFQO+Bekol0ZH/4K9jEGTiy4dAlgMOiQIaDo3zGbivTjLRUwOIAcLg7qNGkeXutBLlV0lrXCMCwB64i8fAQTGVSG1kOFMG+8EiXlGOroAcrMuX1hOp8qSIjxbQEGQXRzM0go75l6/PqQk5PQvEtxF47VCBxTHy4VuCBFV1GvuMJCfAoq7NbzFfvSP474MA4DLl1Yy0H865qZ3IlkGuWkqtBQmXmZH9NCG++xGpl2PUGj6GJ4ISsswFg3PnTiDX0HepRas3pGillld67FNpcrpW+dUMPvztnKWYI/YoBON/hJpXzmICK1HinwyKT8N2GF1MFWDECxu8DrKGBi/fWD6xcRkG/nyqLMLleFFvkhudJqCruVSKkSXGHoGYONR6nzczLKAnpjPpXc19F/mi2i6+uptYJ8ylGWjqq1cutGpwb1br83ffXb948eiDj8vuvBFRvTLrxjtaYIItr7xNt8DOW5QgURjFw55TkWKVZSJRrRPFgmyOMG+LV2ChVkvDxSgcRsILqWLEp2IMI+PBRim1xL+WIQkdJjrQZHAKBbEyCHS01ntraZDp2f+WUjKan/CPrAA0Ok8koycgN7KiyuDWtHT71W9psfuff1rmiVm7xYE2B07r4vyu1ucgs42OLzrjyGAZ1xNvtJMsLlhhTIFAHNZA8OJr9UFUqjBIJqfHbkaLw+kAPOaRd6dcSQsdQXbweE/TJQy8zGg+DOHgsVKOyAgIwAtTBT2ILoir5yO1cdyrfoLTPEv5pEgzS5/TDQz4nCy1njrZ2DfTXzmAisk/MJjbHMVo6K+j1cku0hO8G5VQLSXnxydkIOuPPOxxDEuOUhOHSJOyUWEFpzfu/OjxYn4JGxhllEejeM1gkMIhH2HC4mV5a+vQXNFDvDsAgzjJQcbQacJqUZKenokFIaAH5oQeCTV6n1OFDkSBHyczQVW4CllZYtuWjeJ7ZJjEdTpPpDLPaaxUhH5KZZ6ZLO7MVOugZQXqkbN7vxtz4JVPn7asHoO2GCmWkgGdBFBYDHZaQK210RNQiU8sqGGs5sjlFNlSD0HHqdk79bRyQEwrtyI3sxaUthPhlAkkOwKUIcbCpfy+g3rOkiMGjPY+KsjRe73yI0mGedEy6hoMLB2psYucnf4rgWgJgTRGXQ7v5oB1eWvZ8rYWYusMNjnXjVZ8YLHjEVAZizLv5mMxxPRCYDewljyIQ0o4WugeFLE4ktIYpNEGSj66CUMP1BrpsxGBZ2TP/Dj8JWQpqvV84omueAdQAdHdvBrqaJwLuLTWTq4IKZyHJbxsJliu9UNJ+UtHySFYoDqJ0hhqqbUSwUdgjOEJ9+12O5XplKsC/TOMUZ5FM+My75DzrNSidhCWlerwYsXF2inICrXcHub55q/8+u7nHz16/gyVAz2PPb3E4GIgi2un20B04pTZZt6ciu7gSjQTuiRvMadqObXoPb0mMr2552wkw7eHL3fcpsG0CBF40DwDDoJZcSmWL/h4MRrFZ1hARDUaUbewjk7ekDsTmryXk5XpAL6Yj/8/ahzjT9EA2URbVju72L/1Fj/42Xk/slSBwsgi2QflsCw49Om1Mtgw6b8IwCw+hmdQy048/nZ8d0kPgQaiHudZRXkZHN7MF+pYsFQqePXjOzv1Ma7Bo4tTaGbBDE987K7Cin/CgQJMpWabTsq9jcVDae3Zo5aKXBZHkJEFT/V+HIw7TGEUzNGNh1Z6DE1BWkziNdpbjPtp+WjGYx5T1PiiPUAqd7MgY/jdBwvD7fwV2iiTT3jUqzxLSxoTDV5ZKBXlB1SirOOjWliGWFbIiVY4kJacAnoyUcxgdJPU1SP/BSLcpaaQKqAPZ5b4p+QqYPCAnEm4oaHancY37rxGAKjG4jwBpPG/U9SyPvxWhp9gRlLWYiU2EqzHBa3HbBXmd7Dk+N8TSMiUG5MsU6n99IpPRRgAoRaSVO/uMmNhxQCYENPG0/5UOOA9lTTIN2VovZ+kj/EBEiIDSpTFU8DmicNLgnlXc3Xkkr7Aee+Agqxb8qcAQLfiZgbRw2YsC0dzpp1blhVRI3d1ue60BlE9hk4np3Y2nncWMz5wJgt31KgOPdnxA5QCBLoFO9cm2BRALECW2D8a1TKj3nfEsuUogaOMNtJY7FV9fPaEJoe8h9TYYw2qinuk4VGVmHkm5ixYFHr16JGVZnBqgjtho5RFpKtaR10f6EeWo3SguQBsNxtz99xPbJzH8ObV6t+HGihoFHfVed4zi82+hSxReMNxCgfZjKbzl3s2NfTocTVqF5Lp6+SRedwQzpqIdq01waIhgKBSyvXV9fF4rLVG1xiaTN599lG4mivlfqqkixSp3qxDDusNZFODTZ37h0+W978xP/1ky1oRTHtvnqtGoShQQuhgxU5lUGaT9XDU2rt7c3d3OpqL5ER2aTFU2BYFtDLVUxUeQuq8FDnKNam1XEGKMSDJOz16pOAohH1Q4g5A+NqgEyrstMXj/qmRLdzL/cS7wKDk9Cal167B7IQkjHnowMZOw9OCY/XqjlareX/5/lvt4493z154TXP8gJKJsF/27JmQagSckBmLoSlKrcEsIlNPF8dv/EpOy5e2yn1tDQOIq7VGUYgg0ovootM6pgaAhaWa1eGvmoPwE7h9OucDxoo7FYBztEtJPJR6CxIWT0NQJWmRa1vjHGJgCYmiRykxAvZg4TqGP1HC9cwxV/CCGRWHPNr9GLvK5YoR0OgYT58/uc+e/xE8bSKQALgszM7ymeYkqLcecyWc+L3jSxrZiQZvtFWtw1e1QCsMp/0KlhwiS3PA3nsfHyOGeRkks3PNVbRRKAIxNMmqEqNM70LcLVpxKcBgy43Lv9SMIlhPo4SwOyQaAOLYwwhaED9BoJghiUCn7zZasm6Q+Zowrjm8TqXWKXpGTzVdzlfcskmqyDFuj9/1tALt5lFzxAWzruPxaHlobXAaWIwZVP2Oq+N3+T1jv5KZ7KBVM7hY2YAmmZVwnWuutfXTvTAlH7KEGkwwiIMCctIow+/QofjvUAcEoYGenNnojpjZEtk3+gCUDdE0DSe2WJTQPFui+OJ3o8bECHygp/GbDhvtaBQwMd5QlMsr0Ib6E6nsROimgxmUI+HcyJoVdOwxgImM/brRzdQSxCZVCEQlCgsFmSd704yK2ORexUks0XBn98/42nI1l1iE0i0XuvcQwMFbaPVKjWbLXOHDV40VheDtcWk0N1pHZZ4IBTLqCoU6S8BjsccG4TJRjBi/sS3VhSY0OcFCNnSDQ50ArZLcbjcFRiuOEpuiCN/OU0krN2ve4aAVEVILdKc4N5wVnqWVAOghlC8ArLLUqiBIyPPQexbVEQfiDlYEIa+H1QLQETSMMABE68BWk0PXN8+Xb/1ancvZzz/Fbra1FeuzhdmhYDnDNcDg6j0G72Q9KY5QrNaS+cZBqzLrFgtBKbKbhRI4R5y04CvBnDRWJBvVIWBi+Ld50ZhAF4NZKaVWOjoJd6xNvYezXcsI1wR1uhcXvRegqhcpV9n2sNwyhWkHLAcCwwsuGPItbcwYSAcgs2KsAhqm2NJWnb7fl9fevX790b1PPgKsaakGqAQ2SxQqafrI9tFG1vBgmbMQLhqGGmbQjWO8Cjk6wu8dp/UWojnQ27oGs9m6o3tHbAFToYzKEefQxMeLi7GPw0uGSwe8ACG2CShb7k52ububVFwNArS4KD8v07bWCpdls1nAWsjK5pIJpBu6urlqYOkpkwmlrw3YBmbWtKYnLSEGeWdsihzwGMDELGGnxjm0SQKNkRSdMemLIJWLSTxGJDmgyaaUA7HN8oqgYM09cSv5hDpxgrw6K4o7rLCW+INA1OMJ7Fo0/+pewjLFPSEJjZFkVw5K8vOxQ52IuiFqi+qFzmpUbBaBGMOnICRmjjIoV3naK51voHlJ+48JRRBLBcKqsRAmtOMqu+vgYWZWHAWq1YG09I9wySasCtFFwFj5yAtQ3UC0OBVjXujqMLDSXZQIlVAns/SJyu2FicwB7uiLtVEd5Nw36hqzohwWeIDZLWApmMGK0RwzOLNGSSBvmWuTWkCHm5NBpGNFOXFlQJjJiXRGEcJquAQi1Kloim3sxGGAVGADetBzLRQyaWNzUlpIidh1ScHdgmWHonZ2NkstyNQ9ZiPmQoc7eu9MlZk7ZHQWBypeoWcgkZZ8R6diMfHxU0k/GnDLeXhIavxsLlpE4givqISrepMCeVXLpdAyC0qNBQDho3pAOMtHMx1CuxqAj+Rk9ewPaTT3nlWHJ8k//lhzR2wO8qjjknrW4BKiJ3T1qU69Bzmj1c3G3a15Mv7h8bdqPi01WUgu89YjRz8l34raqtbl6oWFjHVj3dLIJiuxnZcFavDY/CVDg+CoaURDKW3bLOe+QiqFR6cbIcpAUt3NrPeWAq3/CFuLYaRBQoEA2tLXqVrZ7r66uvnm4yfnH/5sffLgZpoLcCy9wM2LvHoW+4HwmlzdfbyohEsxdD5Jo5fIgvA3yNou6rN0aBrQlvkg8Q9HGLTenKR5qSU8nKPH9xAk1Jy3RRCyvMgkKY9yI3wJ0GMMn4RdFNbelSJjd1gOxySRNU5w4qNRent4Lyi09IUALV6iQ6ujFNc33/Uf/OjsV6/7vG2I7dRGq4LPxiZZMUqAqcX6LA/ERPIaW8CBAOdpBViC2TvVWdLaWjSUaq1W0qp6kwOMQ1yFPg6CmSMbpqiM78BkeQCGSYO9GxhmxgKQA1mvLKH6gAGu7jJDL5wEmS9q1tEMZgjHkFNLShAdvTenGa2kpcZdvJjq1NUHuORAGAYF/p0XuPdO2tJaLfTeY96czN0TBJKNi3JSHOBTfFdkZCPBa63BcIluJii6+V29EtYi0DBH0IZsu4YmCx5AFoAaVmsKXwGfphpenh1uhU2dhkBGi7G15l0Y+GLabwmAQuuYuux4/uaCh/lJGyvuw7sRJ9Myd5i5Yej6elQCgYj6iVhC6xgrPQYKCIOhBDOGNJfB0Hqa3gTRJtcwxbugj9MTkSpHkfJQ2L5ikZWXTnJh+BRE03N39MLJ09B7C7soJkMqKWVmhkQNzMGKkg03ks0aX66HO45bM4eFVRmbd8aqXIMD3U4oL0yp3HMfpYIppMSBP1XGBtheaK47Hvmo9HJB+KAdjxl+4jhuA9My2FRLhBG4jBm0pfxOb25uaTWaGJJ29+ZdNrzBUz0/xpc+SsSgEpjTnESFFaVCl2CF01ArK1HdC1BN1bwKFVYJok7LAsF6pbA612aUT3TSC3olLwp30gRN4AxUWjVMQHVU+QTMjhle4DRM8GooZLX4MEFeTHog4bVY0ja6NAayZiWQ8iEkTs52HGiptbYuBlvX3rsIkrUtq/dx2k80BM+hDtLZihj8REVPlfLLfMbhFYMYqbLG52y9hSjQodVCsGYqIT5LXK6ZRGZZe/cNp0Ynv34KZLwOUngseQ0SL0sCJyeU5RXskRYueDArEWZV5rNfoPD2ePHsc5sp5xkcQTIpciQN3YZlRCmFg+qlQfkBLMSaHd3hTQ0GFgoo29l5+gwcIE7iYAPM9lMqyRA7IB4EAwVmidj7HTs6xxvh3+Qh6Mw7YineS64EzcO7G6fNV6SVlNjnBzKDlaRX9oCEVlenq0CuRghu6huRh+P+nXf2aJtPPprqFp5ynA7LgjabEofLwMpQnwORfcfoBwCthnJPEmDLsrSWsTh6tiEMpEDJWnSsY1Al04nEy9gbbScidJyPYWgUegfFxYm6KPyh3MBSTo1rPG9mVwfIEDBrz1yHmB+3mIbB3dDHYCV4R6GfJgYnKztZOwHycRXi7cgVRVydavIYgj0ZzU2ODTA0r2M8kNsdShJkYgn1nX7cwhQlml9ZLmyuEfHiyaekJNLCIHtIg/0NuS9NAKTO4XPXlbC67p33TAABAABJREFUyeBeS01oEeiu0+YPwYPy6WPynqzBcE2JKtAgV1OzofgirPWWfv/xOiwATyIEbg6Mlbd3VKZYCeqnaU609YHIjsFX5nzYCQ43i+Y4Qdk4uVkfj3l03FRIQmqhHDmXs2iMQqx1x9cc/0cRsnJkUUpcNw/ClGcVZchGwcNJ21hBc7XwPQilDBg01UjYjuEUGA/BB8I+8laqfU4fJ54M4BzbMFEkVwDTBoWhr5AatMF9Hz9i9O+BM5shNo9DssE/OlGd40mZxbwVPSStQcW6e5ocY22esHCTirxG5s7/Nz5/T3y8RDMYLoFxdOXFjGBBzn0pD6/i6mIzimwLajuzPodtPW27Sp2Uqyl0ReWinsMLvDoKbHbMjiJM7hNQ3OleQigcjC6O0j8GlINiagCz0z8R/puC/RRh22NpeySO+O7NlKGhnoipMIuVMTHuiH/AB6c5n2psbKfHtY+DGyVNGIMZYxqVlKIEPj228bgbi4NSeIoVY4Wxqcg5pCkI71WzKJ4BOMONpYTZcosQD0vhrAOW5o7IMfjgoeUrB+FNUsDUBpB9WfjoweH1Jxcf/eLBeiB97UDdVIi9UT5FMpFXo8GtB+IYBUHWyNGy1MJqNXX9YMhyU09wRzKND5JR8jTE9qja3b1L3Zd1OTEdFCQ7JET1SoV4+r6cRpPBVVEKCA8z7OguKPUYGQcmllrHeJtSC8DiTioYSlNsSi1AgaHDXVWwFrbJ1NKX893y7ltnH300tVsvEwOKeWU04CGId5h5GHqfiBvrsm7PthfnF8FNE6RuloVaPCCv1eAtavKmaAuY9g2JJHOwQ06olaXkFH6X9oAYcfldwI5jHMuFLGwzuhpcva+9t6jwJiuz8p7H8GVqQMuy1+zuWMGy9YnE6e4nIRaSGgNgyGlgcoTP0e5sG/ErAnGYKRrJ0xrTLCF99K9KiYdlTYZIyX5HBmm9pbjJ4YaejYePXX1YDY3WzJuhGVZDg69IOftoelQCfRpnJphULJCae89X0FMeIqBJS2uO0fsCiK2pp7ibZlAKdn+8lHgyuUIt4MtEfm1wl+9Ao1BcvUoU9Oy/8idJsn/lPXvKxog0blQpJf4hndoxZN7yhJbjK4s46TgMJ56nIcuAnpZlxN0kWin6jAYl358Ze2sxc+Ev8Z/k8JIq0/A/sQa5OYPEEHlTHkh79eiR3Rwl06xbGgeNWsqh/A+i0JnkJyW8pWjeBC8swQ8BgNMGKwS0Zga6ldMSkYgJsTO11FJC1RZ75+C11M08YwCsyaoIPNhVxoEQFGo2gkFoTRlpSZKd0mYuaeuO3ETtAqux2EyrtGKsxuqsQ5RcDUH7qDFaktOpqSwAd8XmeRW1LTSrosyK5QCuGDbEtD/cwCZ4Ma9ABWe36h7dMGETQLMJPrtK0jjc5Bbcrt5kRrU7iUshC2ses2E9lnl0/DzbyXhD7lIDTV2J3SSAAjc0806Yo0a2HU1U3lQAoZUkfUCyGI8mNrLUwlQzWwEKvJSoypmV7JF+oHfCaT7wF8jNne4cZlIZlizrB6TM3lO3VIKI4sPMD4OmMTDrOIpk9FuxzM6gdTkevvv+8cXV5U8+ZLVSWc0hdhrNWmuBMEsqxlqqayzmiQuYpwWAGyko7GFb6wTXtY38EPMgAMx8G92vBt6V8JQDKbNMjMs95rxu6G5Ip0tYmmAE4jDKykF48YQKMv0AaR4UJyRyuY2QYoMb1YFm3oEmrLBuENCBCpZIvSiLOWhs6/6db+Hmevf5J17nLgUMkEZflgSLmHY5IHhXbsYslfub/fX1dWFp6vGRs7EtJbCspCONSGqWjI9gyLfgtNiJ9RqleJO9mo4By+XSKByNX+rsA7jkmAtI/U6tkk0QAHTCjd19NQDmpAC31CgasjoueezdXadO1OMo+shq8bUjU+a06fRjEMYC2hpdmUtSU5jGIQU08bgGipx+H0F5FYDworBsEhwpRdIo/uJXGX/CQckjYLkh7OaSnoqAX+Sa5tmD0GmcpikZcoRMy7ootqRLk7Hgzi1krvX0arp7k4cgZFVT77WUWqimWkstxWMXuFRLiRtC74iFuaBBQYUWkv0fN86DcSM0YdgVyxgSTPco9zNuhJUOE883t9QXJcJnDipxj0CnMhFHfo4qdLRyMd62kSGgJC/GENoAgpbk3m6mk+VT1GdMetM4JEpAIOeaQY6Q5A2g4ozFOzUUgf10xH2ElLtPW4eTYkEG6yDhFGNlhTsdc62baSogZGSxk/zBOch5jsj7iLxWgbxBykrQBe9S6IxbckuMLD0MDWmpix5dSny/NioeAnQv8HgF0WPX6FTCKMVPAKNZa8oiAGVshqUDYZQImvKxRtRzQ5GqqX54o93Z/fvz/NGzr7739rlaud7va5l9haE2WDPWcjGKxrv6K24yfMq7DJh3VzMr5j0AIKATReylUJZlHGFdnQVghSkD3OiX481xgLrLusTgMk6Zx4wkYgQZTvcNoEQwaxsaTvy2DF4K+RNhgSNFcw0MwCXxH+dQEA5TuySCUorGnj3+XUTWSvTPvYY3hSc8Fv2QacwnLNWiclWWLD1HqMPoGGGCEZKxNrRtnVeHW6td1+T867/64E9/8OitN764fDgdW7OpU0GjKyxG9tazv20Jg8fljqcSLaSojIOBqeaTjCdyasZdHuM2DHcMOmBSqIXINBHDGPcF5uUJvseBHtuZzFyxXt4w7G9ZC4Ae0ddidCpIpZRsTHND+11KiCBVZBabClGaVphE0GqYk8hAQRSs8HDbHr12vLjcffJ0fvu9hQiWR+QNs2AhJJjFkogus3uDI6SUoyaoamszKz5Qi9a81hLkBotP6d2TVSfmTTHFEH1QvU5kzxE7/QRnMbfIYWwFcuSoLjFsASVG3VYCJEixObIVCgFyZQRNuGXjMPKhjbsV/zQllUjYLrIiix7L6TvK4fbI8QeQHUNCIXls7no9hbx2QJw+dEoeoLK8D7whhn8hObbc95dSxlDT2i/1iFGt0ZkcxdQYj4vttKJkPTptdKhIsVP8hWA1h0L1jiyTPWu8ltir0eUKTYFa8FEJj/DtSDdvi1PEwLZOypyMKQTaqKDs7kbF0kjPTzP6/4ycUdRGjOlqduoccHoj8UfjMuYDHzS+0+/lDYhHaAMSVFRPngXfkHxHiRXT6gDY4zHE+hAPBkkBXRC6mTX0imKgS909JHqEWn6CAVkxx3hhzjG4+wNxiVl3hmnQzL2HG05Xr3UCumRqWpYFjEoxuvqo5CPsjMY3s+FprYADNTkuaJEGQiDemxui6kHsGpN64fD/ufO4OZU01ix5S5ZFC8y9evR+OSQfOxU8hawcGTq+V4uRj8hcAcbYdyI0+nHtux+9nJ+h2vP1V588+vZ7lxvTF1e3V+0+Uc/n44ZAr+pVbkSxSGEhsYCMQTpshHWtgBzdUQskXw3uaC7Igv9sUKwBeNUK0GGgmcyLU8PXOE51utmaFVqptZC3xwMHHjKUA2aOMoqsgC+Rt9Hy4UVoM4MPSAwAvKs7UFE9p0dCDB4Jd/VK9TzvhayCoOa55OVu0KVI96bghKUt5QBOpLCy7a2bWeutsngsonnlJOUrNDNjkwi6ukzrsnZOgGop2+Ph+t33+fOnlz/96fPf+73lYHVasUAlWC3uXUaTtD+sJEt4BbgioJwcLRhiFfUAoSGlBp6wnF9gKGI9M0NWbXl8Y9E01FlZSvHWo1c+EXGipSVozijXOxCfzchCE3K0XMjgOtgw/fB0oPHY+RS2OBEjC82llUa4FxDm8mLRb0UUUOnNAaM1eJFvbLp99/3thz/ePf/iePkaW5tgi7NbSzMxG2tqMjhZlyOyUXzdZKeBrlpq62KhuQtWS1CTIhpnfurqIUmqkMPEUAAiYIEMPyN4IHaaumeNNHLoXVxOmJM5XowkwJJaaka9lpv7EBZpco7QbkkAzndShlNUhFofVSiNUv4xG4simJGvdM/ZfCmlt15LGRauYwpzRwvKY5P4bDCa3KdSe4hIkVdTDrgInvwFQsvgwUMKfeIQwmVIVExQE4YxFpq5YmENeusW5FND6y0edCygqLWuXXKZsXsv8VV8VMo4BQlIndmzRoT1GE1K6q6SBetYhHBHGcunMVoEV4jiB7Q15rFJZ0RiOaNyQotRRVSzuPM+yjHBL0ey+LiUB21KUDGau7JzyW4ibFyB5HDwVAeYRwwAzLx3S2V/D2pSYZnnqS3LgKhz2tDkhNUSRHo5UMw2pcq9BYErQQUAQUdwomaEjLDDqpQ42wkRCTp3cOLhqvMkeRMAI6sNLRnjkIaPt1U/VS6eXyjIavnvYDiUDy8OMd9LoPMulVK658ruVObYaIXiPhIOL+KJkRc/c3hV/mNkTrrjb4cenZGDI3bCCdQgEsVg3mEF5t6EejM9+dSneT6+xX5Y/ME8f3lV/vCza+L+/ma52re6vXj3wfzdx3XmcsudKQqHmF5puPqrsJVKtEW+yBuwoMB7pS2G4mhR06o3WonihxZsSwMEGSELPMTC+NzCaWXtzTtKcs3Um8rJRVsWVJzYbVEBxsajDFGR2c1PFr7RjkolAu442KejHFS3QIPI0tdGkzGldgJadCUNxhrjQ4xJPMla6u3hINJibusWFW8PYh9QKtV7PXkqRYWBqMkiHrsneaw4vcob5KwACmsnSu8w3vzO7+7+9E9e+8sPvnrv2zocrFYzb61VFiPVZVGzY8wYs60GT88hOPlj4wcLmvd0VB+dbizwTmw5z7rDrBT6aSErXK2tcAwjheAORXdg6b0VGsrsDTgq8dDrB1gUiuPeesyfJIXdR2+dpBVE2USzUtjUikzeomO30W/BRaux3Aq0CVZ6b7W2dji+9+7mB392+cEn17/7WMAtZdIEhIOtBZWaDPMQdcHM3VKk7hELrPfuVjy6GHkPhqc3K4bYRwskRRl0gZWtrwYSBZ41uDPcixN6zLeREIIHJgtGoYMTITkqA7j1CKjyeZra2uC5Kps52XUAxczMOnq4BUAZfErQW3KDOKR0kQsykbsGxQzTPC3Lks+zaWDdbixyL6WcRgk5SHNIni4qo7XycbBjYNG9AynELIwylV3KDji8Azg6aEjR7AKepOGY6ytiadAtJHU3gxuLneaftNabkTFLNIIsXT3hmRjQkN6jj0BXNuVRUrs7zRLkiVYQgHthabmfkD2brzAzHwbTScIyc6d3WXoqZ5AJjGfU+FFq5/AVTlBpCmagCSgs0TRGPiswT4JaHIYsTOpU16UJThR5S2mAEbAU6wEG61KpZbAOQjBiYYcTZXpTo5VSKxzr2oIkUQvllnSBBOfQkGYRhdbkh3W1mNR63mIZ4GGqUlDMWzeGyRNrmVrvmXpZUoMOIJluBnRrvTeUQgddOZwLCQSGitLu6sdXaAXo8JptaqInwZlNHaOEBllgAumRHkOqxhK8EJOnaX98DRM6Q7KdYSB6+4qcS8bHIDyMCWNnWY1D415oNU06rS7E5GSRNazErb356e38iy9e+u3LptL89o1LfvVs+bOnV9xePpjK5aNHr7+1/fpZ++Dz9tlh91feuni03e9lrOEs0DZO9YqODqxyyY3VZHRzs947jYLB1/AGNw+lbFg3NplHKavQ5HmVy4rTraK4+rytt8djteoytyZ4H/ovRKhDBEjRES2UA2ZsHt2uADdyqiVMM8zgaAP0PwH9mWByIjtKzNW7KiOJRg0uRFcKkCUGZgyGQWxRaeu6WK0WSCM4aHoOWLXQX5g8uNAOd7OShobeI4lXFqmjd5AurQ6iehLF4E1rZV2v8PDhfntx/4c/Or725rOz7W5ZG0tjdXS4G00+wY6wUtNqFZvNfFyXiEi1mjoMpp48XjNWY+zpjIAhV1oHNofBaRBI856rSEJggPg2BWarPdCx7vHXW5i/hF2ilBUSiik4adFfK0IjLYoht/hfmCoTdwTcfHX1RdVitWLu4pDyw7rlmok4Jt3NjQZv62rnl4e33z7/xcfbq/dvdjObVSav0mC9hYeURqnuF+fnt7eH1lrQcJhjtQBz3YzeRSvzVFtvGUGyHSTMzD06dRsdTbYDlQphaNiUxtPKERgVoqVYXegWYt9oMAUICrcwAYSta/MwawvC2gjNHl0Zzax406ayzPX29oBS2phHjAQQDmCg0YXw1KdAcj0sMXte1w7aRHpTgupRE8STTxgsYLgBh1oxi9zpnq6c6YhoZFRqAcGiRHfTY5Sm6LERXSMNuas06AvhhhLgrcbIgzDnqeFM48zCCvraOoIELkcMvoSpFg+g0uVWpAazs3mj1iJn95BmWdgtmpsJnaDMltbCi0WuSvbezWwmJRgtTkGhh71aN5bUCiXyYCwhm4kCYpTukDcrtcndUcdxaYCIQjur88u20MNxg2ZxfgJLojmXpTkctO5LZfHuwWCfptrRpSiGfJ5ntWaJ75gnncl6a5gYxIhaixm6mlG99wJrvaWNjINpSmL0LjcYc3gW/mvZAQNk74oXSpd1gtXGgpulr2R1dfMCQezBUK4QfFI5bHXmU4OziShrIbxXQzeUo2mDeeZ0XFafIMyQ3I4FxcCgTyI93c1dRFGiQYhNBojd2WJDh5kTpqi3wm7A583m9nAI1FBSiX3AQ2cND0i0uFCTezUWRiUtK8Kh0a26FfciK3QSxpV169Zmb6vq+TM9+PjZ+sXN14CXzbnRuPTHF/UX16uVbV25yJ/9Yn92f/urb799dvbVJ4v/0Uv93pOL1+bDzbpfeWYsqwNNFGqz3g2LYZldMAS+uCCDf/BKJV/GdfViJWZMQRiV2gDfw/2rG9FaMzPLPccnkDauaJRuqkCagCCbPE8Gp2qlO3rvrUWlzuguaeYxrxE6dbIcjxB0qhmjwo3HGyhgCC9GyUpl1rTAsqLpPdEphQ4VEOodtCYEow+5Ot5pRa6SJUB2cLEgKIjACXzEbwy70Bo18XF98Zu/dvFPPr33lx9c/fZfPS6Lmdg6po3Y2AzWSULeEDNXb62FSBcurR1Ea63UE60x6o+sRgmMRbAxWnGKgnfALHxVXCxyVI5qM0AHy5ofhTY2wmLQTWupcg/BSbymAekoKA6GaMtOcgGvIoyy5OdEY94MSnjfJUUdEzRKWQ8oIsjEYzQDLLe3776zfPiXF19+evur35lwPDSfK9gZ1uiMgwQ0CcDV1ctsUFy0cIofEmSz4Zij1ls0lIIPg+E4bD6cXk/gG/NkWJLLxvKkQAjCNq+UFIAN6l5CwckrG3U9MECJ6OEsNn+kPtjC4GOuU2dzmNqgbTIWwXJ8gfiZ0QiKY3jfII/aJjS18NbbVGuTEv0yjzsbE+6xHA1uSAa7nSZomXzN4BmGo5OPKaXTT7YbA2sYU4+wCjoNZwN/jxs5ZNBJcQg1QsCqw+tCKaQxnCifcatj9VeAtNElL63VYG2ShPUwJLdTKIkBRCrQetTjClgmB8kun+c5Z0yhb5GH5CKq1/iuDQgPJ3cEilBY4Fhbq7XGgY3vg4lJWOuawVDSAGDEqIDkTsQFMgVy7qT1wD3boKmG6UmLUmb04EO0XWqQhNyBde2Dm2A0imaxFXvYNcQko8ELOZ4JlEBRBJCaNyG70upCqoKiwrLJBXLqshno3onSa4PXGav6enu4vdlv759v5wlq07LWmV0+N9rUBeL6sNRpUidM3SrMSiwy5wZw804WGntvgFwCa+Ll5oKpd4Q5TBKrQ16f05PjcozDQ+NUKPXKqgEY2kgVsBCdupHVpWKT5LQKD2+fCsyGAhRiDg4dWNRmtus6v/Wz6+1ffHklWK2P6gxb1tv9YVsvNyjP90fvXGnres5z3Zp+8MXHb7338OGyfq3DH+3b//xR3RpRjUY1oZtLWr30qqP8FjhWLBWQqwKLDf6BmYZpcYOhAEjdfLQHCtYnQTNJnUZpaCWjyD2xJu5+WLP/6BfH2ovTdDVy5th/lgYFKObm1Rl8iqF48uSHIAnSyn47G8OEIwe6jBNzJlEPDEw7YblwbqFZQw7F6JZ+pDbAqDEgGpyWvKwMN6lg1LhDaUagwrYuvLj/5fvvvfmDHzx6650vn7xWrq6xnZpYxQbQOmQ9XI0s7QYKS3BTDFBXISM4BTA1TTWoLDEYG+0EYCaJVHQ4xjAGTkcOgA65bDR/iVYN8DaDoku9t1duZkxcUIzmahkbskHz6JhDduOe/3RAfGlpMFidARhWqCM0+QHzNl+SIqAe9V9rx/7ocXvy+OyDH89vv3dTrajB0b1V1nVdYCylrq25j49JIh2ycz/8uMU0MyP9FUnUEIJEAE2uRgwgEBMQxUsIctigqJ3ISwmYeGDZuDtJ+SOO4p15x+mwA4VV/kqOMdBq7721xR0mimFzgWInaeO4Haf/cKze5zr11g2oha23ELKG9YfFLvEQ2bt5Vxos4LQIaWgOEBh6WFTEOBWl0jsincddHksP4qDc/c28Pkjng/i+7z4pNML5XXl695SyHFSgCwaDY57rsiwhP19aI2ya5h5sAVoHpNZIuas1jTp+wJYcnKwsTJGAQQLMcSd7oL3yJoX/JCmgpI4W3eFEydIjUhIskOE4n5KSNHXyInGH+VhtMSq1RIJtnC8vZI+5iZAzLbjDVogGOgtM5s1VBrwXQSaQkhCuG6wEJ9TdwkA3tMmSeiPTY0xmbqDKOISubOQ5TgB7PPjRM8dljW/WQcMUVGpHF+YyqWDX2vXViz2mzeeHJzT84jDbYfu93fNH8/6iujSJFVadXLFwM3c1w2zO4sdq22aeCmBAwavJtrwazdWjQm69mWF7drEsB6DCh196sGiBecy/PdWPlDC+g4IR/uVutAoLWDB8LCvgwMbdZBUo5jNtxhAIOWoAr9vNN354fPgXz17M9eFKtvW4W7mrbWV568m9l37QcYHtTFvV2c8X1Obz9PHh6zff3rV9v5n1E86/9XhX1KxKnbVTDb6qrQ0LsYXfEitwoB8qUQyMUglYgHqyppIaAFppfQVA1tZaEERjDndXKhu62ol0PiIWxh+I8HFH58Johl29h3YlBzwex7Q62tiGGyTGLG7yr+cpHHnVE/g3nDgQNLwiLB9+C4ZE5mKQZjGU88KgNRps+B7EDFs9SsuALhxh/Zb5O1igARURFs2ZBYnapsrWDkv77vdufv7RvX//b/Z/73+5lDnUL2wgvbit0bUPBT6GPD63tQ2BUvxOqTX8TwqsJbU92ZcchZMBafIX9mdmDFKrDQgHGiqGqB6ioIHBs55IWooH24lZGGTSDZq00dy9nPC6eA2hGI0KlMECjNccAS3CQ8b0zPBKFofLWxMB3+L52+9u/vhfnn326f6b7xY/HHop4LIsU60OX9cVjNQICRF6gijnIytEtmtSPEEz1lJq5XFZ8UryGKPRPKhB5k8SswOGudS1te4jGCKyq534QKdRCCPh+Z2GzKKviYIAopPGrgYP5+ogdtraOkOTZRaEm+bhLsi4Cz4aaslpKLWsba2F6motKEQhTTWRS2u5Kmtkv2DJamiiQnEYzyjKbSi5pcjohSF9hiX44ULYn4amNK4pzGC5wCmyXraZ+VhSMwoE+pTFtgNZp8llCcm7C+od4aoROD+89R5/mmMxNJLM53CEqVX6f79CnFBTMO0s6JlBrHSEOKi1Nu7TGAp4G3BdQVKFTgyPmCnkeY661TwOeWz3VYznOnLwXczieMgSROT45km21lhrVww+It0FBOYNQLLIkoOcUAAS6EtoMKDbfAfp5OdBJA50I2Y0FpI6DYqCG6agUCBminID6TXCu51GtvmPFjNrvdc6OevN1fVXz37y9Oc/myGevfF0/w6fPLi4nAn82xeXZ7ad69l7l/3JfNUOQi3EOZoVbMHFjcB5G9yyCBNmNtavxaeWcQ6CNllBLcvRE1sMNnHAEsaAvnjilgOOOVCrmLQFZdqjDEZV3jqStYm0Kq9AJQjMskm2ldM0G8yqYeMo7QfH8qPn1/MlxT7JsNbrXg8ibK5L+cWzK/gGZaMZ3DbOtc2wCzn5eWuvv31vbfuvJqyPZuooOrmxo7CiLLUdG1agGibHMSWgXM7Q3XLzW4Ml0BO0YNfavMOdLGSFqUs1NGTDb8gDGk1hSN6wcayj/DcXNdBaWSbp4nmIYswfOENGg6nMslXdw9jPwJ4HbtAu46cBrwknJ9BRiEc6GFHkFD0R1D4i7X6yGEsx3oDoToHhJHHOWRAspH6J30mijVbl1CnJCe822dRbLxe3v/Gb87/6lw8++Mln739H17eFrRUyqzubnW2oLXI8xzLgFPqQxDgQ5veJLCFRiFEqycxOvSSA4giZhxeaW52qmS3L6iFPikZIDniJL95WwMASyV4Rbu/w3hNU+0pxdUpkPjSfQgEZ+8tDsxLJxHIn2qig/BW7n6xsLMwaD4f+5rt992fbn3+4+davCKrcSq3Ewu6c08bn91P7Q0PrnqBFzjL95J05iFdACgnB0c354JAjJDKGYiWqMUm9NQwWvSwgDg+630mqhMzjltS8ccizWjyRz8wAL3Vy9dYCTWDvKjVmY/FCU3h1ekqFVZkqzNExZuCty2i1FrU0nFrkrDUSfg6YgUou6lFVWR4hD2i0dM8awRiEJuR6GMtv2UyGHtkPIQEMmOeV/t6j3MtrGQciOfhjUBxXKzU+QyznyVvOJxoejFE2Rzo2D9YKMCzXLchx49CMri52wQY+G9i7LLBNY6DpGEscWJO8Rhse3GFXknK2IDfnYjGD9d5LLXDEDGhp63azQevNe++5mLlY6d6VBrun1mPcEjeUGGW73MnYKaLcMnBqcj0WOolmsTw01UB5ueKxp59r3jpP/kzPxp3Bu7ewNAmqD5m4rxW5txZNBSUniOj1YV1Wai0tXxRYejeH17KB9OzTZ8fleW/13ffen1/7tQ++5uXhuLx8eXi5nx/eO7vctGWDpfzgZd2L7+32y+Kx0I68lGZphRUrFrQCeQcC919cACfXajbF0EXZEkiOOoQzbidqOsxRhSABKY4EgMImTYR7H1eNLLGvPdSMRoCGAtsAxTEBBpvpW/hsRtsaqvkEsNw7m+vXzS+4nBU6m9bpsDjKgrnu1TgtbUcSW2IrbRu2hoveqrjZtHN83Q/zm/NhuX2x88cXZW1eCRzcF+hg01r8Fqrme0eFBQMDwH6LGPOlIWgAwFGnFKCDRWrL0hXVthxmyUGH885R0gdMNdrEcYbG2NGBnDoG5prs8LEfNKx44ULrjQkGCU63Mfu1hLBsOK4IZFWXqyWubfQmd4Hh4pSbMTwhVRfQm9JBIria2Xm7u4c5S1tXRgMYjaQ7zDpOALdlgXsXi5Iu6w4avTTIrBTsr27efnfzzqf3/uIvzt948vX5Bfd7n+cu0Es1V3fOtbdkZrnC3sPglMkK3fNbUe9hbH5ngpHZ1taoYE023CXdLIyOGPVRlw35acAE0UW4o9SoTmvc7R69QLyiV7Itx/B+OKeEniQitgx0i41yGJhHFCsG8+iVAunohuBme3L1Q4vtZuaC+truXVx/453HP/5J/fKz/aN75aaRPm+2t4dbg5U6rW2tqJF5AOSI9xWVVDbIdprBph0jXukmkXWb7jJKJLpcpgUAvXcfjQjTjjHMKLzWEBnHvG7wZE/QfQI/afYCWPfOUjIxMr8Ia7HezbwAlnJnRMfYkI43GaYtaxfWqsNtDTBgaZVjRFtrSrHlm+1ksONykBrDrjzTQiqekDPHeKvx8QPVDOophrQ+3KfcDB1uv3Qc7k5FcMpeKWsSJgHvtK1DWzNkan76xpCD6VyHDADBTY4+OD5bXKukZZxAhvyuDOmWgzFWyKw2fu427j/uasGMM5YbK6Qx2Q29aJShnplSwUoZbKlTkwxZMEVQnQ25XIE5tkd39NZpNk+b43IAbFmWUkrUCXKPwiEGvAIUg6SohNwtiHJGo63LitPSz7sfioGFvMO9GB1eSuk97BMyW0eXQysOGKu7hRey3EIrb9oUmItRP4fHZZ13V8+vXlwfHj/6rnSr7fynH52tm81ZWeujh02HdkC/7mcXm1lnB7cf7S+49Lfuv1SvjnlVK5wnr603VdEL4AYJCyDX4oPEBjR4R2q7F8Dm+QzrCnSNsxP6FodQS1iZ4uQ40EWP/iuORUB/kKMSFWCxWYJxIye5Qa+OAmzN57KlbxxbagYms3rcb6YvO32aWRZgQdu2ZUu2vl/OL+c6l+X5S1+23E7awXYb7VZubXc5Hc66znSst21GO5+ena9PnsBacbg12BE4Om4dt7Br+Ay7BSaLCgENWOZ4owYHGiBz1mmzttW9uHeixu92eVbJSegBo0gd/q5Brxq4qcGxnopnBG0z0JHQJiM7ztS/pMdgU/gglSzqDdXYFYCaEssegTJvt3GEghFpNXreu6uKQOyEZpFSIIiBspKQGBCAIhCNARIwhqeR9gAEIMcwbfeonSM7dvhG1smqkGTr5a9/Z/rF0wc//NHhr/7OUqZZfgQLQjYf2mgbZFcgRnOGMNYvtTY1cppmrsvR5WCBh5w3UWfSBJ10EIh9ODRzqMMMrQkmGivDgS7EZYSrDaIvYjgsKOLl+OqM+GCJZ8YfOxmkJHAVfbAgQ0/CDTrzRRhUYkIjWVTsLBhGloEmSJ116rB5ORzeeef2w7989OnT69e+X/1YbG7LyjQtVy0ViLSORAAMJbFyeWZEwGWwxAnSNvkEhPjATzNB0sxKNXVJDTLSSsnWaSQADJA7ki2GecnI4JHWxg7zHNrmyFzuva2JzXrShQaOk3ZF0erlE4n27iQk8hAuytWmeepN4Z+qHkAqgKxCvHpTLzH2KmCa6HqgDAEGREeLsEs68X4AlhIn3BmGNiNrWoh2TphFFmGe/bSf8K4A58nx4vMqDkb36RdtjDfzWqL3xlLgStMIeOut1Bq4QmVRb8UQ6CpCujTyNQadLDkiXXDvCpFZEtJg3rqfSvfgPssFjrFBrmIKxmx3lFQ9xbRVqLX2tZFEaGrkFrasIYjyUwKI8tYC3QvR0rIs8UDqVMOvNSFT5bxJgdMEKTE0gGYBzgkJXKQSOum+8bxtU+raWjaJTPzOE9vP0ChHZSWppuawXLIc6P5sqNIMg6u6z5YPiUs7u9q3i4tv3Bx8Umn1MfyS6yJoyyKYn8F6bdelk128PNv9pJ053njjwbPaWebtaovowBbW1AERLU5eoy2w7lqAY++tsMFMauQG6MvSKk0xPrIYnRGUjblaplkDzVrs1YXFhp4o7WKhUqVVdxqKsQCFtoFPsInaoM5+z/s5sDGcATMwi/PcN7hWrZ0AZWe19X4U12oXeLm2ui72+J43+WTcdFwc7ZLcQRewB5t61nB+tp0XAtvN/vG8X2oVTar7i0l91gq9BHZm18De/Qoe0ECHrgrbHIkR3qL2U5d5n7dn6/FwahOKmXvLLcZhmt+7w2jljnLh42IEWtITGI66ePQc47y+QnLJP2QhXaAlLJxGyTZAmCCFBP0UYek+4E3FkQudmJAraSKjpQgjXTaRq6YoVyzwCs1lU2fzEEEFhbikZg9egnOUQ80gjyUxCch8DVX37lZLXbXCJ+z3fnFx9f6vPP7xDx+89e0v33ri+2uiNC4wUsUXhXMX4G4ELf2A1Ad5skhdSxvrR1wIFkWgzihWIHeTwSL/JV2oRv0YBU7qUDOgI2dTo2eNmuKUy0cNM7hUcpTcqztgOo518V0gZIGEWRiYic7U3UoSw4GE8HDCS7NJE7oJpXCe56v9oZK+HNprD67fuP/6x08v3nn/+RnOjhJy17G8uxuBUii51EkzlN5bTNyiEhpU4uhulDouuFuSui1pBAFRmtyhTomlMtYhBDlh9J75B7PP9bW3OBMETs5BkhieGXZKzAZ30YoHJxnex9Ygh7uUd6SH9cQ0zUrBlDFkM8xZa6H1hhAsrmjwEuhMtXQyoqP1ZrWsrTmqlNQVnthwnviMcpoywNagg8tZzIuhK4efsQMxthwou113HxOkRH3uOvVRkkUNPchvDpzmwfk0M135oHg5YGy9F2OhwTty1UQaOZKwBlYqJg0KWUQO/m284vh8rbVc6hCKhtFY5zvqie7GF1f3UZg3ZiVMEl3xzKlwteSY/gBIQTBKKa3lBGXJdbnpKBJWJoXsPc6eIylDMLAEJZm5oJSAOUgu3oYHzymODm4Dy4lFmbiCZOSi1npjLd4VxEvrqtEBVXZ35R1kzptUWdgVTcRsmonZxU6a7WhzYNjGelyq6Cwbrn3a1A+uLtu83drcWJsEFT9SDNzFWXfXh7PpXD8um1LuvfPwpnufdrX3pYjutRehA7eOlVgqlmrovRlrIY8OwkFOwhHywklYYEYU8wDscweme2cJpn2UTaox9U2DCB9tmJGsAsDSje4TsDHsHFtD7RP8QvUic2ffdttamX3d9stHD2fjtQ6VEFxH1FvrHZu23D5fvrpt9YlwNaMa77HdK7hY7N68LwfMx419dfHlh0/0ObfY1t988GTd8XjQ3MADd3vsDmV7vd1pA2zBK6BALIBjMTbT3tBm92ZW3KsLwkJWtUbW3lt8Ww5ZzA29J5+GNEBoPCHDCPlhZyksbL3F+QMZNAczuzP6c1ePeegw4AzHYnM31FIUJnZBq2J6sjOTu8Wk/hWwCsgo66pBe+zJSfCWvqmJRpY7CSNi4W6vrBA6vHCCnFG0WTeHdRtUECC+l4GwxdDL3dUbgGqEo61HI0ytF2rp/p3fWD/94vwn//7w+G9fk+aaMTc0Z6LkOdyWYCgBmNHUey21jy3qlQwihQ10jyi4683MXWWMIQlR4ZwSchQTkYJfFEbl6EonBbJF00NH7N5R8kQ7crLbvSMQA7Pee2VtrgKSk48+8CQ84jCUKE6SS4vW0BiPHeaIFj4yka/74wyiWy9u7sdvvrc+/YPLz55ev/eusFghFrA2Uc0nM6tNDlTS3bqjcHJrrvTsCZhVyV8tkBcLL1C4g0jPbcFhHtm6hkxo2AQZWAVZEGowyDdsamRlwVzKclicwYBCd5HWilWhuElALQC8tUI2ryXQjQKHF3g3KWgNrsBYaMV7LBs1Rx/ItofAOsZ669rcrGJGwq1yC72LKStUJyhvThbWWITjaRR1YjS5meW6ZhtIUGCVcthofSOxgYSVAne01koppRZ1772VUqMnCzRBlnZ+rSlwzyDu+auYcVJqEgSD5UpOOsLJxeFWUvLkjgJIWBbB0FvY6riZGS2XBAdVwnNhcJNVlpT1GnvvBjhh4RrhKrWEb8yqrt4NdO8xnQlbRPcUQ8ODE4MT2yB0MkFSDM9jea+luqP05ASENOoEzaVnAAiE5yLW1shSi7c4nJWAdbm3VmJCHCN5OVLMjw6VHNkPFGJQQDoMNPReyPCFXXsHDGwmGoxW3L17b2ZAAWEWa8Kre4XNsg1tMmDBPKFanVBXVtzq9uLyqnHWQQvb4XaBtkubC3iwFb4ha+SAWs4wt3rWfTttz44/nDb1vD+6r8lhuli5L9ZKn1yuvfut20o/QAeaiuPgZu7VjESLPWzw1bhxNPcWFtCAF+DEE7IMNyagR+3lUgtktIcWS4ZayywRPhkmYIY2jombonPZznXpunBelrIjdvCtaXO4/97F4+n62RfCFrNBK2zfsRyO1zPOLurTZ+3zmx2Oh/11Y+GZdlovt+3i9e27l+2N7dU5rn7j7Yt62P83f/Qvn7zz3pP6bIFd8WzVvRVnV9je8PLZg0fX261mWKwTc1gbleTLCZqBOco8dwnLQMFgCB8UR85pk590N0RLvC04/rmuJJahnn6Yjcv9CkgVQVO5xyVZLw4fG0V/ieCUBbUH14+VXNYGuzv5qdWLwjXmfeYc1KpQlLryhg+STKQw62qAqTvHlgWWILbkXgcgsc3T0K7EzF9alsXlQdlQArZpUVrgMDz77vuv/8G/3n3w0+vvfY/X12tltPkCspXEaJ0Yg1oLosGpDXMY6MXtDvwdYIIHOtMBoJYaZXzM4pMAEk85lgOOyseKFVpvuZFGJX1a82W5eBc98wPFZzRD720zbdbeSmVbvVaurQ+pE08NUPqG3GFi8fXSRwE5/XWDtQrKq2zZL4fXX192l+XjD+d331qACm8TzapJG6Gz+ZCYRCI5qXpbVy30k7/x6QWfjhsQMKkCw0FE2EA+oa4wKKSVqdbDejgBqfM8H24PdZpbV+W0X1qtk7lpXUGjkw2qlm8ulwl6KbU1zNW9LwaiY9rM3lvEi9iiyhxA2PBkDjQmLktiGMHwspInY7Bl853kbRpzTAzmnnJ2a5kn5SGYhsXuhBjgu6iwImjD1Cnf1emcGN01z3PvPSDped4sy2Isp3TwysPO6YDdnem83qUUjTfjuLOI7IkUGORM+bHT2KK38SQxTEkgV+sqRp3mxsbWu7lz0KFLYW8NZC3VAIR9B+DqbkGH9uisBsodI+vE32qAImGpMb4pD2jKVVl61+16W0pprcUIIzFtGIuFRU+TKi08hXqXhTUGMfpw9+RR2sDt87adYoEHomDFTzTSPI0WJJowxgzuQbg+hQdoz+8ECDMQK/IwXKoSpUJuzGbY1n3rNldUbYvNZlVlrm27sV07HGjF+s2hbi947958nOseyzL5Ymfz1NRAsRQvDQV+Dm1d2z6d1Z/wwV+999mm+u2MuekWdWqybtiaHRwL7AC/dhw5H3fb+fJweNFlZgugWktrQF9LYfBhIuF4+CIOb1C5mMvH4PB5moPi7gCQO5pqZRWKVIUKn8HJKnUmbMEL8wvvD8AHsHP4OXFB1Hmdrv76d+pnL55tzmbry6HUtptvZLZs8cEH3/nGZ/e//Xh3qOd4G9+cLt59/Q//8l/89u9997J99biuvHrxt37ze9urp/U+fnrxg91a39xda8VzbRdcH1gvdPnCD4Qw33/54CL0DtaAI2wNMT/8JpRRHWDxQGjpcLA6BDRDGV6JMSWV+UiRzOuaIoXojEP/jbsfMf4ZfUoOarO2c3hTS5VniYv7yoG0QfUyAOrpaprezp7khcC/YQEwneZPYCb0HFmfJnhxnH1YUiR3FrAEyhLHHlNPj9MAA3qMHtGWJf6im6k1kLEYj4w5Kzo6XHrn3f0HHzz42Yf7t755tZ2nJg9GVU7RR+waZKkOJcuFyWCLHaMjCWb+dQwCd9fEktTQniaeHtrqfDED0TKz05Ql0Gw/iRszBLuNziz/tV5LFRwN7oi+vPeVQFtTQjBVtCb1Nm+3Ll/7aqMZ4N18Ig8B4yTE24ppYpNqdbE0rQ/u3Xzzm69/8KOzZ88Oj5/wcKhkE2A8VhGqPT0NEu9EEk3tjmEa/06ycThORkLPaWnijuQfrW2Nw1DGfqe1Hc2sJFAKuE11nuZZx4Nan0p1l1ozxl4jdwfUo4N0X0uETLHOM7zRYNXUe1sOAGuZurtaCxoF3E9T6eCNe04RM4ieKLaBagPeY6Wop72gWbjI3x2OoA7l8HvwGXI8NLj9yCVO8JSKB4rl7lDaVboc5j1yMFlaW8kC9FyLPirwE2np7n2bM20ugt9gsdzGggsND9p+aHeTJRD3GAG3ynw8lBO/XTDjXNlbh5lZ6erpl2JpkuuAdyPD6TUF3Zn2FYCQs1ihrSfml2dzkBP1aE9jaJ+3x6GUy4/YBHnk21RTDp/XnEkDCPONkwdqxMxXGM7ZMhjQ5YYWhgYe2wMtF2MjiKKpssz3NwilqfEdZIB44DGxKWaxeTbEsiSqY5ImV5XN8C1sa7bVbO2iYDbN4kXXbAc1zleFatrjpbS7bC92tXXfH7E3O+DAA83qll680yn0qfW51YvSt33ZTj+fX/utx8+KlqZyJmt0b/Br+a3jOFyvDlgnYUWzbUcnZKhLW4Kd6+gJlhjNe6o80zwRUVXAe6xLU++hSTNjHEtzVaE6KlihSTazTL4TdqjnwAPTI5QHxkdmF1a260W5uVyfffXZ8nd/6/1nD59+erNu2Q+8eCkc/eJmu/ZHL3/3b/2tRxffOny6LF+2i3d3Hz/7+PIbb63Pvvj46Z/Nl+sb09UP/sUffOex6dkv3jJdvOQ7j/TVoW94f4/Dje6dYXHp1stKeS3X93bWYEfqRrh1m2AF7hUwD4oAg7zdbOQo6CT4jhylu1UHZup+Un3koTaCbs6sVDLW+4AQRmJA+C7FXk9niW5bQBB2Qp4kKIwJkQHFw1m3Bb8fp9RiQRs294ie2TD7yNyDCnz345T0ggqRNpo9vlunDIhQEWxeD5pROIfFDDqu6SmABplFsAq4obtT3tp6+I3fPvzzf/bgxz/e/87vaFk0y5a0JniVNz4cYJD8rrvZ+n/IRA16uZFwLxaTUcUIOT58RoOkvSC96OAxNwnGI3It+d24LCFtT3PnrIPUs9tiWjOoa7PduPtyXPpd71jb2uQaTfern9cxhDI40aI8s8aGZVnUawEaDjcvv/nNy7/84Pzp0+snT5pThKQ5VkSB0bqF5AgEPTVIya6KpjBkLoDfhbJEUzxqkZw1gidKj1xpZwUlzSgeOZdlBbDe7j22jYd+tUI+1qqRIRw3g+TretzUSaA3oFYrbGns5ADUVtUM2B60Ig77l6D6weHZE6eAx/OYBcHxJKqGy8MwFRH+LW8VDK5CIj2uO2JTvZUY6riBGEwIC5lPHuNU075CLwrBMAtYK9zbaf8VBvkHQ7ae2QI4ZfPYvGUspp6UDZThfzl2eIyhPYfa+E5rl+EnPIGGaUxnLWSubYqqWB4Gsd7U5zqH53FvK2sJtkclW3g3DAlkIB8eBZy9evoHoSSEuA6arcqIF38kONVdKQiOnRGWBVNcrQh9v3TqHMNWEacRevxggHbw8aZHxtUA5U+S7azXGGOCXN0ZDEohtlGdJlMFqFKJYysVeDHfCjtOs50TZ9CuTxe0Ldp572fbz6/s4rxpM1dyo83nL5fGG1+bbWfs6FeNu9q98Sxc0b2ylM7j1HnRuJun7dc/a/Oj892TzfVxsVYlgQJ2hmvgAGyB2X3vVnG42tdpKr6jqRb2JhaskKMH1hhXJPxFcqnDaHxjemIhzU/tqCfx1lDJIkxmc6lnwLlvzS/M7lm9sPZAegx75OWxXeDqnl3d8+dvX1z/6ZdX5Vr/p99e/8vf/0tW3rbdntujrvb1+oU+bvaNn3zZnn/w8YUuf/KDD7/ze+++9xj15bP3vnnvdfvqra0OP396sWB7Uefl8PQXX/T739gtz7BdS+UZlj3OZFxtBouwW853bSH24Ba+gc/A7FYNrRp4WgHp4Z0dmzPyuzYLB9bR89456rySQ5KQOtLHiTcBhhBlWG8AYT/rqUwJYCgHvVAuBotn/kpnYyFviuiFBKYVJaS8o+fdPO00S5f0UdtqBFyDCbLQn8NP9enAAFPqE4ZLgMVIDemZADPUWqX4RkP7hNEcJOPMCII6Hg8PH+/f+ZVHH3/44BtvfvHkiZbbmVOaSZ5K4/wft7RuflXT4a/cyoyWBisYRlB5jw3BbQk5rI+Q7Tkq98zcsO5hbwiz7imMHTCoeTJv8u9GUg/CSGtrmCOv6xqrWFrvpRQDmnophSgjCWR/e3c0AARG7TZgNZNrkVeUJjlZ22oPHixvvb17+vT8V95/drFDU6VTqqAcDWmWEu4Zcg+jZjINMBMVTQ5LekDG5CLx2nyWSJzPTj1fdoY0tKTZIDJrJKJSCrw3NZARQzfTpi3rKBI7UNVQvFC+v7k6u3fRDsv++uX24vz8/N6y9u5OwmLrQ7DHXdQgedLQLRLG8K8Nzm0bUPNpfpNs5LsleBgdfrzCoLLTlMfJzUyI9UYooLua0hCjwJrkSRy2kKHnE4wzk3bnylIwu7GRIP2V9ntwvJRjhvjIOWRKN1UrQ0QfqwmT/xvD6lia9arw1xhQgaSeLm0O9T46e48v2VsP48ygnkxTcad6yxo7OXjZfePUv3ty1gKxTxBo/F6PBTApE+e6HDdn29aV2E/MtBhSdZfSh7vUqob+S3OcDIZZDKapkZuZFWMwRmOV78i0MUrr3tzhA/8bZaWPhwMAsXYmh4luo4qLsGBgASY1AhNsC2xRJ+yIc8PO6yX6vYYz1kte1flqW2fWWuHA9dKmXVM5Fjvz5/LZpplt1whpUuvNC3s/osG2c7vo3DVtbbOzH6zHe2/MRb2Xhl4gs9l8cjsa5hj7o9BM1fZurUjT0htYV7WKaibHKhjQjBa7Fs1hCJwHkCxXDsQ8FIPtFzAA6lw2KFvYBth4mXBufiE7N3sAvCY8MT72x/jygX11yZcP+tfv1Nsn7y4/+cEf/q//zjvl29e//6PP1u29pd+7dlvw5PPd8ki/uF5eHnZ9Pixvf+fRly8/e3z92d/9jbc/+sM/OvinX/sX/+Bv/NqP/8c/f/Lu+3V5/vPPrnTRqpXl3ny2Xabzr2ceYWXlhdnWcd2x/eryPm4dV9QWdnBVswmmAquA4JNyGWbLVoXhONyy0x31SRDV8uolJc3SUCn1xGDIYoLWiIjkMZgdAXH4pjrpPXGGtBIMTxSiZI2a+cAwlAmInJxGTommSiSLxiYZi+SUCHq6FMXM0jJRuKOSCrZnKBCY4nzzX37JBqkxeCi954RpdBCZ7JFFdXHKMGNe1uPtr3//+vOPHvzgL14+un+DqQ93a3sFm4p/Jq9OenGd/gyCwBIV7knaYY6e8qXhSTJ+OwC6PhaPj6bWYo4YXKxBKM2WBaPr8hQBICRrrcldXWKxgPLgyPnyaNfCoaUEbwfDDxoWvLLxITDMcEZkMnT0Wu3+2cXNfln7weRXb76x/fCDs08+nn/j+357qFVLNYi6Yw4FRT6tbuP9nsS9/KWiJAmAyiItQ6zGUw0U8QQkAuqueL9AUDYZDtxBEYjJbVVoRbogl+Za1uMRfmtobVnkOrzcqy+t3+p2ffbs8+XR44vHT9IBLKYCUSTZyR4lIYF4kdE7JpZEutK0AQg/EACKEpijl7qDzAGjrUqh5FSncElKOd8rQ4EYP7v56Sq5w+Wx9sAQROvstq0w7NYtHQFxgpbis+PkoRBU6JjX6LQzKuAz773nayp0+bSZeqzLdDf17TRJWlrsUTqB5nlQa9rExReMDdiEoctslGVxTbtUGStMaPCQjSL4i5IQRKaIAyZPhlrzHrBaQMHD1SeKSZVal+MioJSythWp7OpDVmVmBnnz/sorCUbCkCxhsJkzFSMqglNDbDj9izhR1/KiDMEngjEZvJaSxxuOagxDHgPdqkSgGopxIidgJ82yWTvHhXBJXKI+JO6jb1Ef15dLa5jvbet0eAbw6kDb1Oli6kud7i3rl70tzgsKsA2sFE7VVln35uDF9jA3XZT7U9tNWtv+yeW+Lc2nWaxXux2u4Xu3GahADX5ZEWTd634XOqxKNB3N5UHsBYGGYbNgNISLg/yXWj7IPRIEoW5mlWUmN7Azacam8B5x4X4pv2+bh9Ue48H89RO8eA1fP+TV4+nZg+MXv/V4Ot/vP//RT//+Ny83z9qffPJJv3/vBc+POpTKJ+vF01/86OzsV5/X89/9K9//N//T/+fNx3zrbJ1eP/v+69++POqH/+wPHvtrP/uX//bm8y9dr8+P34NZBZYDKV5eHOvuWnZNbLvfrtjfbO4t96qdw/buR+POuAB9K+8O73nDwzmlGWBB8mGlAVQOKtzhXWBvQkBPIZplIECJ1aRuOoJmxLxiLKUEfBNrKd0hr5uptbW1SDOchoNlVAEclIf4O6OZc09eQ1CIA0TOZfJSP91+OZi7wJIrmQkY6K7iqKVqLIax2G0QAxbCQ2YbHZwba1WYd3jSXCKHRe0hgOZGMzEWEwiaOm43m/6d71786V88/OCn/Tvfb8tCyx0AWc8gabiBt5RSowkO767TLDDB9fj/aX86+jp3REGe43cfxDUUWA6ezc1ytevwL7hrm5AIeq7+hQ9rhtgT1WMpqSTUWgXRSotFLoCHh2JvZgRtdJVhD4h4XQM2P9UsEGzmvPZ2c7s30UrVYVlee+3w4LX500+27713XaupO21S+NEh2mipgaCNxcAKz6BT8IqHSXmH2SmdGcDYtR5vM7dvw+FdHVn8xflwxNK3GGpaViXuzQzbeXNc1tbWOlNd62HfDvvnX395uxyk7qsKJ76s3Y/3tuda5GqVRV2DgZ+taxZZbmH9G5R4nMA2mIVFQ2wqg929pdO4NVKbDXkA3GCKfZ6EORV0IkchvXXBnAK8JqcyCfMxV0x7FA/eqRMFctLk2s7b43JUd+8pE4olyZH5xqn0vI3w4Zea8BkAP61IYchT0NUnTMHvCqlcdqJp4WFgiCMSwW1q8cWmqb464zCwpOwiq4veOoqzBlHfWoxoBeSeLbew8MsNzsgbMVYsEp7GGiRZ5S3sYB1Os1ySqNFORyEaDnnImUHM9Bmrm4JqFzxRZYk9wK3A/Vp+BYvqPSCHJOiN1CtPRE4lQmkohofhtwejXrlglZyASV69F9rO/VxG7OSX5o8cD8T7pd9fy+PqF3a5vSoffvre5tE3rv9yN73Yoi6b+WraHuv1FS6fPbo/nZ8vh9XPfZrrjINrmWxdUA6Y3actrt6e1wf16w0P1nx3sO9eXl3R6CZNV3b/6mJ3fXGx3N9o66rSzP6VrACgu/n+zCWYZDJfgGrs5kEGNcAbwsIsFec9t+ehFnSZh40WQrBgtdQtbDabrZzZpfGcuHR7gPWBT4+42+0f48U36/PX9PyxvnrEry+W/l//X//L3/utv/b4m3/l08/2f23+1nTv6R9++PnD167w+GILr18tf++73/nzffsM1//iH/8//zd/+9df/uS////+P/6L3337/Mcffzrvr9ZP2y8+vb3p9w7Lt16///Z82BzXBajby2pH+IT58rDgsGC5xfFayw7Htp1wxrKFn5ndGs/gC20p0sFsld0gJkFYPJKPp1QbGPtwHDG+NRaJ7m0QPGDGEgfcGHAT/e56Vithk1sqLVqNOF8SyWliRPlS0iu/1Ky4y8g+bpAxjISQiHb0y3RPawoBHOi4YA0qSk6Oe0y7LJoRosRGLtqp+uWiFsvoR8obkzbLUtdHuxWmdC4P879YkUUBYSni9LK4aj3s9a3vPvvZ08cffvzyrW/p8owrfKzzBDDAOJTCru4x+IpKhiad5rJRFGbczkZNXkkrBXA1GU/dvY3IoAgDYSkg7zF0iqqhm9NjfJ7/YJCbzMBci23dO2OvOGy73YR1vnq6YuFUxBtfUaKO/t5OP+8nJ4sILiTYAJs7WinNUdmh7Xb/5psXP/p32y+vrt5+gkMvKIp1cvCSntkAYhcThpVCWrW4BMEKg+9qxgBNAlRheoON0P0f/IgJX1MphhxcK1xa5V5hKHXx9rzdznOdZP365X5/db1/dvXsOZpWwWGtrfCX2+0M1C8Ozy8vH212F4f97cQNSHkrdmLXBHCYfi7JGWZxz2oMAEtRGxCjO1J5/wpqghMEnL9YUxAukt5VSHU3BvEaBWzeGpyCPGwNFCln7NwYiIgSc6bZ8XCQFI5PzRvNUq+AhFM1jB6AV217nbBVHmsy4pGmk6RZLTwcDinXLjTHzeFAs1Jrjj3T7vFUmHqpU+yJMbPcy8sQT4RarMO91lprDX32CCxFdw7zHEzDBMzsROXQXQjLRxwnx5GGemGMZbGCKIQVMQzj3bUEitGdCIETfFU3xK4QT8r0AAodyeoHzL1FB0uW+GB3DgsZdBLwcCM6mPkoKkhrEHvuI/GwCwBiEmzcwraYV9wzu4Tfc79veM37E7PL9pq++iY+58XVZx//6fff7NvyEm354kZqb73V1zfnm6uZfznfbs7Pz/Bi224mHbbVqw4L5gXbRZuL8vW3d1fvXzyz/XXXcrW8dqnbR1qMdcXmuV+f495LXDzfPHj++JJh/XwQO7gDjm5Lpc6bRDSieqgCYbCalm22xjWnUbH10eDw2FV6d4etuLFOdRI2ZptSC7amc8MFeAm7BB/0+9P1Y795wpeP8OL1ejNftbMrf+vyr/+3/8Uf/YO/f/He27/2+Yur33zy1uM353/64ceHm8OTx/XDD/58/fTZD2+/sefZbNt/9D/86eN59+TR3/jh1Wdvok5mDx5uCqqez2jPL7g9X9BW2jJPS1uPsAIsON8uM1rRQtOOuJ6IamHbxUsLZN2ualnutXZrZuAtsTp8yHusVEgr8rgE1ziPp9SBOVCRoKSa2YZT8FRdcvUk5sQGvTEChHshB3UoL63cKwoQm0QJA2tJ3yAbF+RE5UpWTfxHwMCDepOjXScwsaJn65upNIMVO0JtHD0Hw1J4y21o2BOB81wHDXjs5bChRWsNXeppa4rR98XcpjdvVQS1qG3QD7/+6+sf/qvXfvLTp7/7m8uqOtNbK6hAW0zk7GhjoI0MLJn4o1qX0WAysxD7T7W01rOej2NbnCXBA2XSOXVJ8D7KCYJmrXeaVYtVcDEmGI5XNJc31+5sc1hXb2CtJNWbvJMe1lkdPbyg5jJJ6l3VwgBcgzGE0EnGlp5haQrAJyuSrGALPwJC3cIau7fD9bfeufjwx9unH27fftLRrRc4S+3eiqzDSFJdhaUHa4gyoCK2LmebzVIlyHuJcajAWvrw0HFTtPqhpIyJSZcKjETrDiCchGnuJhCr24ReZVPZ+nJz/fwXN88+b+tyfcSzm5t5mnbz9nY5dmizmQ9rM8G5Xt8+56e8ub5+9PjNJ9/89rFXMy+wHEDGbjEa1ECqt9CYxvCzaWEL2SvUUSb2vga2G6bdvJNH5mse/hnMeT8pwIkusQBDPlBZss+W1aTZm7nZYLWQbOiFsaMSXSopHGx1GFCqdzI5gMXyrJ4qAXexMCysu8JI2ejevY27mwB7Ibu7OYpVj248s3+x0PyYkWayUqvaEqWk4D4m1qXUti4GY63uTtZasR7WMrHBhV5YehMLm8K6xQBvrcfDlAUbq6Q2jJYVdVYVCjtAMxRjz+ToNYc5sQvBHBbyYk61L40s6r11gTB4QdieuoVXq2etD8FKcH1rVFZLa8gdrAbBqrsrDnyDgUTvSk6ZsuISiNqDBgFSUCmwyX3DdTJu+9S1kW81XRbct/5a8ye8OD+8jS8v9cWb+KxMFxfnV9vnP7igvcRjtc2Ot+/Xn+957/P12NoFNV/iy4tJWK+2fdlhv8f5tZ0BvvXjm8v14cvl0vYPN/sH7dl/cn3z8cVG3hc7v4eXF7p3g8c73KLq+aPL3oA1dJiyxbB6vy7AbFqFQhbBkf6MMku/jaChaJW7U6BZ3UztuIYGcJWskFBlnYpms41vaTsrW/jOcWHTBddLPvD9I96+tlw/mW+21/v6NfpX82tny9vvfv/3/9F/e/1X+f4bv7p/fnj85qN/+J2Lf/KjD75a1kdv/8rH+Mb2/JuPbD0WbXj59f76fG735odvf/6jw/X58/3GPrmqS8Xt7aP7j19+fawXD3Q4LDOIyrrgOJfzZdva5G1rTb5nfaTacOmobtcFBQTd5DfO2y161N/FSCDcrZshl756zmCUzFsaUYVm0XlFsRa88ezD5MbuDUIp0QBZIAYjj5ocpUZECEeLu+YwoozRLEfIp2pfp6uev5LpNitRnfgKWR9pzGpz8gnAPIxwTrjuaelNMBbHMiYfVr8WbSvM0Ht0qIUepbi/wuVCVgm0Bnpz1M16c1zefPLi7bde++hnl289vnrr7fXmeuLOe0NR7XMAs7H8ONtKD8t1QOgwlprkv9gOEs/ILceZUaePyXa0GwZzdysWAHLu7xvju1F9B1rtQ+edoELUHy1vO3pvACA0CIYaCB5Hg2JhW2OUOe8gk0qGDTKmfOCMHR/xz4S5cuGZpnijHn6559vrJ2++9uWn58+/fn55n4tsbt4IOsHtdns4HGIaWMYHBhBmBAXeIci1toCmEVabzFY4Iqa7q58IpkFMjYbJwUE0lE91CgvDpla7tWo2gYerF5/9fH/zQo79Aniv5t766ktf1zLVvmg5rtvdbJxevrhu+3Uzbz779OnZvfuXD1/v6iYK7urhkOVKNzJOU+9dZnDRMNcqaZWmUmmo4BQK+MII+cPWkBzfFMMn1dGHOCeKyJJqqTHVNQBBCdNpApwEiGh+hZKLmwf+FFu9gFyuyDB3cHXBRbKl2CEneAG1M/1DPbH9WAWhxPxhLGbeW+XU1b1YCGssJqpSESrNvfQud++9l6TgRBRKxp+8I69nByDlotmmHh12V2ctkuY5POTHswqwZ6zxaL2Tpt5YanJAoN5Uaz272F1f3wA43+5u9vtap9ZWIWgDXmpJIzZDby0mYCyFpNF66zQotiUCjjsXPAzGuJAYdFBokHIm5O1rmlgkdPdY3BanOtRMQIE7fTIrbpWocqNTcGNtkG/Ae+TD0i96eWjbt7Zl8/JN++rN/vQRnr2Fp4fjcmmH+rw9vxZQHj92bn5mzud65P1mg8el+K4/v7Qj8fzCly3319q0crb45QM8542E467c2gue1d3hg9//G995+99cvvlGffHwbH/Oy2vdTHx8YJHhxYMHtgAdaIaD4WB+lK2To5hVee5osBiKA0CLGU2Xy4RgK8IpxQKG1jtrgXvrqrCdcQKJiZiBDezMfAdd9Ad9/wDLA39xb3p+drv3K+jFZJ+X5Yft/e3Xf8zv/eS/+cP7f+f8weMn63pTHuB/+/63/39PP/rF888eXW4mPNt56wtvidduav/40+2b1w+ffcLDkxe3j4o261Flz2/cv3j204/ePnuB77+xLFWUboCj1+PVdn6w8Udsx424sPGBcyPM8Coj0BVXspDYbyEUFrKAFSiuxbAWAWgtyc+ykz6IgiaiGDVmOLJqUnet3j2c5BA+bWuzGurAbHoLawjXo8w1BqkvOAgp1LHAZsiMjAA02DY+rBZHIsZIKfbqL5YyIMdf6pstdl+N28z0NXDk9DK+cloiRAaKPpvs7mPrjisChEYmPn2k4hLprVu1acXNd76/fvq0fPjz+cGTOm1blyocREVVA0okICF4cDghLHQMfSTdBFpXzN0jrzk8wtZgd0UyTnvLjK2I0VGEr9PT8RzgKX/xVNk4zJZIYyV87LxOBZ4epKE4Df7tyXC4woJzGdSTCH+jjnCSBvZIPCVsK9SIKgSyyeZaVpvL4a23vvrk6fL555sHDxc0kzEeR3BrSSMK2VobAu7wpSIRWjEnYHWsY83lKFaMpdZlOVqWIKcTMViwr4Baseo5ZKwEVbuzsB2++vTDr5993kiy7l9eq5Yy7273+7X1BrWbQyE287yu61Gt1uK02/W4Pdtev3xx794jmIEFkuXGv/SINoioPQn48TEI1zTNrS20aVlaVoeGoRsl8vif6JBeY2B4N3wdKCdE98BXLdU2GfbNYeaxBhwAc5ctTwMXBwRVctitsNBO98hha8xQDEGE8DjA48dwlco6Nm4IkxigSON5E81YmABtou7xwiEhZVJ3w6lAf0IKJLJGupIckEwEQzVkuTybBpd3sywRWuuxy69UNnWzNHBVb2SROyvLPK+9+/EgGly369ItNhTnj4gkw9zeY6Nr+HVM86a1FvUxe0Ae0cbATVEiVYyZSkScTMOIPYIjNIklnEKCGx1vKoGbvK810naTVUOZuF01y2ZOqPemZdf71HhJXJrPh4f66vXyxT17/sg/el2ff3l1efXl3F5+861PP/tPN//qn3167y8vvjs/ro/PPsamzexnODzQp7vb22mFHdbDTXlt2/rD21scLvbXZT2yVSzorZe5/lQPfuXPPnj43dcPM3Z89trcWKCyu27Xq51fXzzwK/jWvMIm2ARWw1rBaQwxYChphw0wjhJwYqgFALC0Vsw2m3lb6vX+Jggw1XwnEjNZgQrfABvYBn1XduV6Z88f9Jf36jN/SXwx7176Rz++/eM/vlyXR74s7779/n3WP/mffvLdv/7NMy8vj/hPv/Urf7A8/Xe3Tx+cb3i4nasJ5cW9bb93cf/5h7d6fHv55vRsWW8rX7Rf++bjJx0f39r+s492n34w/Wd/53h9qMbDy2P9xkV/+UL9UmUueP4m8Px8t+x2rPQil3tzwErNhQQ8nJGVnICDZ1Qylwk1ODC9xPmT5MWcwVFlBVQqXWptcckHVUFCU+uS5e7GEEtUOlFBFA9bokEIHL7ljrFpxMKeIq0hE4aOVHkSdP7yD7eToHOMNx13+tpx6FML6ZbDWyRrKzNbfi2PeszD7Ssa/ZivxlMolKTebZC5khoQfAFCrFXLgfcevPjN3/n8q59sD5+/d+/d53Y9i6tVt3W1XgJz9/+wewdC3BRqnZDiaJQiRI5A87NjlAAxxmdB72JI6ow6yRCTJpNuRpbU5UHWtKB0WabbWmJsNof4yjJLpP9yIqD5CYLCygxxcIOAGgCG3MjJqluimjCrctKFXqXGssyioT558uE337rh1986XKPOcGAiCmuXt15js488YDoHnISH4dJQB47n4Ymd5g6mcLKNmSsiW7/inGjAYLHBwNZbenQbINvAP/3kZ19+/hRCePU3almb1iOA1sRat9udSa31zmVbz0KJFh34868+u7h4cO/RG+sSJEfG4vd4gTIo7abzR1N3Q3GQFcbmrZbijt6axUpGgzvdw9ox6rBXxeUBb+TmQTqTKp74jiIL+jgyHAhBPJbkZfvYuwxoKD/y60YbyuKIP3Q3hTlVoNnIFuuSy0vhuvbeWinFBHkD6FBBavrRXBY5keEAFufNc18TYkDN3LQBM1t7Y9ClStEga+oEy+e3zKEPbnEoNboCssKxhmbJ0UMglHEjTUD62sBi9C7BG2Ea4+xAVmK7otG8h4u7G6zUcjweSymlsudUIyJS3vGhvxzj5LEeSmGQAutdrDHLtrW3KJxSGBvlNEIb4gZf1SbSWXtYDImw2jDVGUeuPsN2tHvG+/YQzx/z+QN9/rY+eQNf9k+rnk7t01vcTF9+9uRD3v4f3/z5nzz95//44/eWd157/CvPBL2BZ/al7a/Zluovp+3LZXfvq8v7L8/u7e9/cazrra/07lj50ZUu/85f2//k2a/wi3/7jTdrO148ue4Vi9cL7e5j99LuXZ3f8z0wGyZDdZvNbwM3iUK5AH0MMwIoZaoKg/4bK59rgXxtvTh8GDlUe1C9jl4g8NZc32WUKhpcdc9ZqOX64882P/jxdWtb326l9Y8/2Iv9u6/zT37/g/d/753Xv7u9+eL4t//Kt86/fvrHf/QLHS955suu39veYt73l49+VrcPD5PmFeiXD/13v/NGe9k+//BfX/ze3zz88/8K//XL5e//zbqq+vbqkw+Xx78jHR4cfj7j5iXOtvXxng9fPHptnaq8ozlVzchmFCtqDfA5QMdISrk6i5BAxRNxg0ExIHHA0Qx0b2zu6JIgCr1JkrlpMkpa2lpLDb51aw3WaqlOFVZLcCZyUEJDPv57oKevRJg0gPzlXweAaKWj02F20ohG7i4BhUwqfl0+lqGnBcuAaOMuxl8LeN1g4WUfkUYd4UVqclen1CWT3M2NDpa5oZVq/XZ/8ca7f/7g2c2DL7eHy0vfKr0gaW4qKqcqgOZAUP7IRNZzOjV8NgZS5wMgR7YwyRoLdwgFQzsamqxFHGZg7HkbcMB4iA7zygJzGkupnmByAVBZvNwhmVGGBG8uGHejZrHTDHIUtZB7qawsigqmmpSbqBrUCT/IgBnEsZtVvfeNX+x+dlaff2f+1qHdgmjqCvNIh0xqrU5zTLLdFfM5DzwOHpozY5KNgqXlcvUWPG3P1AzgbrPG3Tg1Tpyj1EKEBnqzP3z1/Osv2eR1asT1Yc+GJrXWCmthJctc522t++XAptnZBW52EtoiYHn+7OW9174hrSwVXg3NSElTqY6mnmoyY471jSXOQO+dLE0ibLvdSq7WDOljZaMQCsOKkTvzKLhFpZlwRXpxDi7FMKjSNG96b2bW1Ush3TAWMtZAvaAmsZSgSseAw7sCLmxx0uR4tSCmUXR5LUWmdW3TVOe53u5vo79nYSkFyQILqkM4LcbVyro7G3kHYYLP83w8LsEiJGtUB5HkgihJlubwFjz8zJSSF9qw7rLe+wm6UQPT+o6xo6JLFgbvvZU6AbFoiz1JVXFvYu4TwD+CRakuFgqQvBY6ssKPBjoKrjhwDGRP8mDzpm1d/m60+vGmYnEqGHCFAWFXzlMMhEcDXg3VWAxVYaoH+MxeG7e1XlLnfZ4Pj/Tl6/ziCb58Z/5KT5f9R+vyk509n+35gj3/h+tf+9NPH/7v3/rk/zL/9L/74Ks/vX3r8tvL7dMdPjvce3nz4Oqr19frXWn29d52rI9q/9L67TyZLTd+xvX9uurrzb36dv1kwQRv6FN59PCg+ep5uTr282e+v9rdw87szLA128CrWxWWCqNZcXSPygmRbQUIKc/J++FI22PBujTN4ayAqkeoFai5KSO0NwKKrSi1dfJ83qgun+IXT+tPn96+Pr14+OUf/2D/QK9/6/Pt2b/8uR599+z7709/+m/+/IV/59f/2oNnL59/j092j+q/+uOPD9yU86LzxasBF/PV8eU1+lG8PvzNv/tdbOteU+tt93j+4rWLdw5f+4P7x28+3L7evvz0y/JH//fv/Obvvnzw5lf6+toePOe6x2Gy9Yvto/3l5Hsv6mioO1K1gjykqZtj6zhA7qzosPTORs/t627uXkNj0aWKEO3MxdvapdYb3Gi1EhabviF175nXYXEDY/smxTL4y4YTEpeZkBETMzfil0bAI08CHu2rhe8rTmOwux+J7kV4GktYI+XlutpcaQbjyNSWS0nNvNAcRjjlysGqW9zwKDQkU+/h44Tqah00ls6VawW/vXv3Xz348Afr53/ji3fdZ7ch4XNz76F/GKkxm/ciMysge2uOyHomR7UhKDmBexGqUokZPCOdGnFkgxtEm5hth7ALpzxcjLUw5bHhOxQrTIAQV8RqtvFiAJiizcqGPPpI3j1l5N/Mn+QHQa1VLdS0bvJ1xKBjX4rVh7sHx9c++8v64t2v3WzuAA18xYi/TjMCnAcAlBgHBMHGPBrE0GnSggANkK3D4BjTjFPZETqYbNMTN8kIGww3buzlp1/1pansluVo6Fx8Jej1wYP7y+E4zzOIw/W1z/PuYtdiECBN88a87KZpPRwPVy9ubvbbzXnYboROlUNcFAYjcdBoKqQJDWAheqoJ5NaWJQpJMzD8sIyFQE4ZIp0Bw6oR8NweOlAjj7cQpMPxdlrvHo4HZOploowKw+pg/bjMy11BnCsNABeHzXbWumbyziGSOVlVtJZbFFsA+65qVWtDrWGO7SUalleKQkfotMjYYzacrUIl1dPYKxJVU6ext3CFRZdKqSlEAzA+JJlMrqhQOXrQgWlFcw8FdtU7S+lq3UUWuVCIlh5b7l5Y4/CWWqKwGLbkGM6RQ8MXoItZmJ9I2XHQM+X6yUolnm5ib6fr48VM7gVFmaLC/xSFNcy4JlS3CqtEqaWoqJzVXqUZ9bJc4Pq+Xb2Gr17D5+3zG/+F6rOL9pTH58vmhbUVFS/31/Z/+/zd333t4T/89U/+Z+0H/+LHF1/89PatZ7ePiF3b+qHusZm5ubl3XG5VPyf2XNrhHi5uDnhW8f73+r0ffv6TN97hs7Wo+OxCv3jy7JFd3pbLXd+XWdqYT2bFvMCLoyDNf/OADsV3BjUMnmzYTdx1W2QxwLvLVWuteCgVoEKRzkfP0dmLLfMO+NEPn+0//vef3D//dNFev/ha33vtyd+4+fDrrz9/d7f755/rB5v3f+e9t/7e3/7eP/2Tv/gKD//6+fvHL/p76+uXD3f/4198cF3p97eYVs1q+2lu2/b09rfefffJcVq++vInP/33s75sjRO3zw6f1D/47/Wf/efXa//Wd3/nJz/8aPeP/quHf/V33/jbf/ej50/PaS/ZKujmn16+tiyVgDVYJxuw0CaaJrMVrFIttZpVSb2p947YYp6mAiIgbwKaN4O8yPsiN0IVBqyECLlaz5GTq0P9aCwUvcurG1iK00+DvNwDSguJ0B36ZX6HeOZE85Rt+MutMDPLnupye+V3fZST+YITPHslbQwByOlrjuEWfLhYRuBOnwGRWZiJlFyrt9jOa90WWmE9YH2yPnp7f/XR45c/u3327WdP9vCKdmSlMu+fqFBIEN37WP0e+wyKhQjrJGnWq6B17DUGbKzKQEy0B0QY+sexATLGV/FtkpUh1a6M7GsgS5jM0sZ00oxBUjHG8Pk0ID8BqDQGoTQmgRNLlPD5KYsZEC1IA7pc7qKpw7sgrP1wD9s32uNPHn319Ob5t9bH3XpVAzEW1zgLl6Uh6qZB/zGlMdnJnrwEWusQ5LDCNNH1dOKPQTVj9VBQXsdzNLi6uruRbN6//vrLm5c3S6+oflbnmdpUlB3betxWAnrx4roYXTgcG1aTVjQ09tb612Td7S52UPda5qUpkMjuvZYqz7Q0MJ6elikQSxnr9hwYm+3cwgOXhp62EhSk6M9SOIwUDI86IuuT0enLoVRtA0Dra+RtknK3UpPgYN4djm7GmrhC4gPG8BI57VoIFAapjfWc4qXP68lM5gT4O2C2LMvEGm1h6jppjlJZTkUtje3kUGBoa4NR6ERJ96YSnpQGodayNvkrFIRiVBcY1jQxRYzRVdQSY2GYB5/LAKsTY5TO1orReyvhjG3Ybra9tdu+KK+pj249lMYOC8J2Ozs721/fuKOFEZmDNq6bOwOPGHJknMzSc7zuiKeZPjaJPZtVhM4uQO14wlaaWqmVYAGWYSLKQlbXBKvCZKJmLBtbi447HNoB7bZeXN+eHab9XnbkSxZos+MG1B/f9MuPpv/Fr+3/D99Yr744e/p1/fzr9uULXXFFweNpNzcUV7kqum4Hrz86Prvdv/yds/L9P/zXH28315f3N3DBitTDExNcPLVSEU2Vnj1ZpUWA8KTi558aJb0i9cqVzu1SwmmkmVWjpOrnfd24F3AGyfRObai8OL74+It//v9+56N/stnZ5ZP/lc1bff3psxfLH321+97rb53huGB9tDytn13Pl839t//h3//13//pj/7d/+tP3rv32Oqjx237v3vvvX/65599cXW7OeP24ho3/vDw6fn18sYPPvr0z/afX3/20WefXrz19u73/7uLw8flPvnJT/qf//vDvde/mm7O6rcOH39w+PLfvvnGbz/4/hsfXn12RZ85Odm0/fzRa5NKUSle2WlHmMyW4lbgBtSz7a7W2juW43JcjgB9iKANKvDmMQBt7gK1dbZCFfqs3g8wSQ2+TmoWMBNysp58anlhcdE6SZZCOGUqXkSvWY1nSIGd1CwDNMy0M+IOXpkBAq7ByH4lO/u4/6MNusu5Zqe/m73J+L3AVUNql3/GAVqSwwtHPZ1xQ6VzoczaYjg7thV2pMPtOy+ffPTg9oPHV2/tL+e1LpVFLOhhPKhhdxQGky7FepVEmk2BmjpgiikmcRpc5lQg8qHJvZQaYxMpVurIR3leSINVEiyCF7IMQXRM1WrAZCCAWgjLHOGE+Su019N7iazmDiP9TqgnwUpQqOLzyQTK19ah5q350qDWljVxWINty9vH+x/r2acPn//qVw/XakVuqNFHtNbWw2LRT8Dg3kNY7NE4lJAtu0HCBNRaVzUBrNPsUNTMQ25pCGtVCCJL+nKkHGUKu9Rq2zfe/5XDFrqG9sfjsU9le2wv2RsJmlprPmHeblhKOZunWttmts2mcFvnyt1urttHFxf37XVoMhMLuvdqcj9OdW69K1H7Bo8tVxa4pRH91K1LFq8BKaj1tGtQuLGN8Uju2KahEKakTRpyyH06A5EP1VudJvUeVsy1TrQAT4fFRHeYVih23hmDD+Xu3eQFPKq75zboGBFjSM5Gm51MJXUJTqGQHS7SKgMOYUcIYSE1V0WNUa0N9s1mmtd18WxkqcAnPIGPaLZZiJaTqag85b7ZzreHAyzTGVzRlLrckT9nsXmel2VBuGUVK6V0ne6jQDb15ebajOC47aV09WKstfTeSXRXWxrJ/fVtQAk0eE+c6SSZYNqhldQbKo3rYpoVpOogZ5iHqBMsXNOjM5x8SKtwGCuc4CxBoBxW6chF03IvM8MfesZadZytEQceSl3Wm72u99up1RfEy9Z8ua77j783P/v2W+0Z9GflrV9/dvP0Ry92h0e/98I+nl9cd3zYjvv15cWX/eppa/u2qHkt71zWR0/Ot4f27z81/oPfWXjNYz1W26FbJ1rr5KR64qwplsYHrmkW9LmM15YYDgEUhidRuAlJQiUMPnxQeu+1lMA/aru89d3c5rah3e6qLX0Clnn3iw9ffsz6m//5//nwj///VP3rkyTZdR8I/s651z08PCIjIyMflZVVXV1dXWg0GkCj8SBIQiAHgkhK5Oo5K9NqaWv6vrb7r6zZ2uynXdtd08h2bbQajh4zFKWhSIiEQBAEgUaj0Wg0qqurq+uRlZWPyMjICA8P93vP2Q/nelarP1SXVWVlRHq433PO7/weK/7gf9mc3TsdfGHhVlV7tlw8/2XY/FzZjnrF527dHHofLx+efSQX/Rvf+Ppb7UcnP/mzH3/yzgMeDrb6/df6xZcKcqGlHFkgqXVVLS7mOK+bZ21zGQdDPxxd3y1uv1Yfvu2mC/r3f/osXLroCy6zPNOid/r9n107uPVSuT6RZcB8gbLhVeXRjjIfQC1TxZoBLenaqdi+r1hUABqARJx3A6gXZvOGYxGlqKokyNBAG1UNPvPex+hJg2fnWRVR4lo0iLYiIhrUKFlJ89I2MYDIe868VzCLY5eRROdUnJMQcueRWnYlzzGI64S69gu7ZMf8ApxOVpXG8zSuxJXraxLr2O8JafakbghRVTv7DFMCDOUiMdaD8YoVZhtEjqHi2EuIYBUTZjkGC6kEYW85pSJZ5MDrMpSfPR882F3+cnv6xaN9keDpUxKZ1CwY50IcUVCwRTSpWcMTE9iltRyIzKBCVcAIUIcXR4357xCUr6w1jeTGtoVy3jmBZM4RsSNyzpullpGfU9oIpyuUSBGSlCagK/mVIp0WHehvnax0h7whu0apFZEoIhI0SBukjU3bNqEJMULhnc97Huxu6NZodXpcXix67XY7WHiiGEHMITAz5w7RbCoEDqyI1g5b6QE4Khje5wppVfK8R6AogYlDBIMbt5RIHDwjsHeBlRSijaMSNhixU/jMI4uFuMKPm5d2NhS+bYLWoUHtQg2ExrWZKhDyft7EEEJoVHKf5djwyg0zwCGidYMq+JHf9sT9Xqhj8BRENCXOQzwRmw8rE7FTURZImnxC4sZBffJcpMCEpM8jdeQo02i58mKOZMYPtnM4yQackyhCRk4GBSHnNEbH3lmLRuSIk9GG0VuIbekrIo4doI4pzzJRiRZ8a6biICISCdrp2I0XxmzxyyATaofUKypb9EtwwqYag0YLoo6cFJDmWc3mhwuw90FaMGkM/X6/bVtRUSG2JhVEKgysVitiIseQqMnMjdZNy+xEpEUgMJGHbcu8sHpEk2JrbBsrD6qAaNDAesXJgoj9WJz4UwBUyYyDiIJGgRA8MbFGExebiQcDgQTEUe3yBlVhzkTMBcxGWxjLlAQ5s7CoebQp8rzXNAFJzuU9sUjMszzL+peLVZ73osCz12imfvDMxK5tmfMsaIRH9CCvXoLnNiPJKFLjQ9PmAbNFGS7q/rrqX3yyOVgfHj9ol3X58gHXw8HQn1fzH08v3z1chaOq5bJXFmWZV7ncRLM/dLvsn/fqftZfFeXb04vvPKO72eitN16rq+gHeSiVQ6jAhWHMFIitPxMGHMiMSdlRipIwAIsAsCcSIe84AI69Com5T7C3TQuYmtA679WU+gqo+sVu6/NV3NjIi9CbHfYn2yHsHk7X+9fKm9duH37w79zR6V4+6B+/7W/elInXURUm69Zf5uNx07S7zsFhuZdL83BYyfxo44Mfvvf00emzIOu6pdnZHmeTvDfey3MupBGZh9JNBl+68/yjB8Xpqcv967ffzG4fzG+6cPQwP58Vy3wzFIF6PratD66U9f2L9aM67vDOPq1iveKLy1AOqF6UpSyUvFDG5JFM6pVFeiaNdOxEyPs8NKHDK72Lwo5CWHkCO2k1Yx5IU7PPWDKPoAgRK0UkCawEakgcUytCShzR2jRswJSqtk1apTgGbNbzuQ/BETdxzewZEM9oAvQFZb/LXJCOApTYhkqiwZAaI5R14mO9WnlSB0MZ/0KuOJCfYgu/+La4Wssm9+mu/qdpAuwcLP8mSNIlG0McBOIQonSsl1curx1tfPJ4c3HtcrG3GC2yZS/2lc1bjoBkXKeAOsrEhRDg2TmOIm0I7BjJo5yiiCM2vYdFLbyAzD/djnQr3DSzEpjYMTvnYVbdYMfkvadETmM1VlxXaQlmI5BQyxfoAH1qO9BBj1dOxXixeAZg+jRbZkhoG4kSQggxaBRPzJlzLvMFQ7nU/G69/Xa5/Hhwtr8Y9SQq+6BBMp8rRDU4zgCNUTqbP7a3mVIoyRMT1GXe/EmYmaknqpkTlZBLzyvQQ1Bi8X1oZN9jtNxpkhoOyANkFbhY5JeeLwtkIp4dchYIch8ELHXghWaYnc1Ii2uD69v57kZ/p8h36/rnhX+lkc3j1cWT6n7dy8p8Qpq30ngKkApYCTSEJoMSq1CAc6JiyWzsmdpQ9oumacT0acyROUrI4RNTSZRJRTQGSdpuSkd1B/qklTAoeUlqEGIkODYmEW0M0Vb/NtnGtCs14+sEk0aJGXvDqGGdmArUTOi0yzZIsiLPGSAxCdbR9b2wVB8jDHKCfABEpLik5IaqyayTLNeKmGPqihVK67oVDRZ1TESUOQs6BDFCkGDuhmqbwM4pA1ApXN7N/7aycjDJr3cRSgJ2zhaKEiM5FlVKAUeSCAUGt2gH5yCZzwnSEgMm6HfOExkbSwDPLgjMpDpCmBFCpM6Y82rFe2Wo3S2MOIq0rSYFlhIlqwrOsh7AKRWGmJF1YBgDLEIgr6xZ37cUFEKOPYtH47TOUWeNUE1auXFbffnZ9z44fjba39q5+Rr8wYOPP14ImhYyC7Hy96brcpnPPD+HPqn0vGnq9WKLN/tx9X/ax8FkfF6H/++H5+dBmGY7124thsPmYu1KyZJCQaJjYWfXzXYkyiwOZsMtpJSKa6fEMMGZ9wJlhO6YZv6UPZhnjsauZwoixur1/cGll7B9/uHuo3v9bHT66lsX7dNvv7aF4+nZv/5Jdfhzlw9PZbLXm7vmF8XBK/EjcU2xjlLvRd8wqrgacrnjueD5/Udlv//O278Is3Xo9+dBMl+eUja/XG+Q/72/841e35dup57JX/3wRyfTarPIX335Lc23T54eFz3H+XZzcq+4CIX4OVEDFJGrYWCdymHVRorMW5P1pSw3fXUWqnk+0h6rk7QyMRVgJOJc4ZhdFE+sa8TBeORd4IwuV60nbtqmVw7bOqzbRrTHSuzJSV+pFm4IawdWWYNZiFi9oOl4fmBWQhBWCRFEKhJVYxNdYOfFe2UmNAgEz56JhRswy8rsUQC9IrLClgXa2delU6irkFdG0JaAY2OZWSCZhAMwbwsTC6YhOGkqrG4QotjC1aAu6V6gG5gT5at7N1YJkqNlcr1wIFPut8z9mu5Oxz8+OL2/M9tZ9srWNyw5SMhOyiQDJIJTEojzLBpCA+fZZSwqIUlxkLOVRRIxSmqHnH8KPicoEXnHieZGYGaXNokEJuccETGxdy7xdZCO8k/v7Mxw57+G7dNFIFxdsuRgm6hzXU6OqkA1hqAioQ0hBIltiLIOjYp6Jnbs8xzswD4HNHevyt679eGD4vkXm5f64muAmYjIWSqOXRxiMROoVHSE0sfHxOS6jXZyFLddKRBb55mFo0jwyDNfqF83VVzXrT3muVc0ed97xWQ43Clbff6scgcbIQhEWrRQgVRCS9fzdZWf36++euutQTbpu8mozE8refLo2WB463Iui8XF1sa1r7/xGz+4+I/HRX19uM9N7SsOVQO5cHKZI0RUjVRCYnwH5oQjiEMIjYjYDiiKHbHeDCfsRjc9b+cbQ51GvluH216RDChKrHhKBnC42tMakMTExBRj9Jlvm1ZVo0QFTERkyxUSlk6TpGqLDgEzw4lEUx6qUrCpnROzXzrabjAGPmtas7ASZ3azWiRiTg6MoGr2OeYvE0Jw3l/J3SVE9tzhV05VmDiIxDZ0PM4raV4XqUEg029QtOwhY2+JCFh8locQGCDiGINEgZIDtR0LRDWxq4jUeach7QLMvkBT/CIACd25Y0JlQUJ9SJJozjOz486njrvjKyltTMCRmNVEal0OOSXjcpFjHyHLqoXGLOsrSJRFcmavysy5wqLcRQJkLRzBgdGigV+hWFPRUCklZyNCEd3eZPDawa+ONt+bnjWn87vl6Pr1G9vMyDQWgUu//+rB2dHCfzDbywofV7vgS8eKC9JF3Qzefjp/or3r/fFNNM+a1Z39m0w5DZosz8JGixFrH9KTdSjXvifig+ZCOa+jrlXEswJNUGGFxBC85xDMp927tBd21pcY11MQEpwJgXaMToaZsPjh4qPbsni5mvZ3cbS3t+uevfVaf/Xnf1B//8+38+tT3jwLMedBFobF4uN85yW+lg0LLM7i5TDsMuYVsr5vy4o9D8Sf3X84cZvHGyFAV2EdVXNSHsgytP/2X/67v/33fzcfNe9876/f/fAXd1++sxm0avKLJ09DsVpGfxO75eXGfNYOe+XZahFJgvps7ck34VgkR8zq0cSvji/z7WHpqr40C5dRRuokQMjkC01kl6sT8hHUqNPesP/w6P4P/vI7TWj+ye//s5/f//CHf/EXr9/9/K99479ZzRszTAvBW3a6WJKBOaYSgSDRvHcyspKBGDRtR+TKv0IRgyUzk/ckrYjzQRtvPldGFTUvmFSASc2YoKuw+BRNLg2mppX79J+AXGfklAIQzQogiTS6TAlA9copia70s1ffpyv2NgSwWtiqXJU+M59LM7cjKJGy5jGsWW/NJ09G9fPR4v7k4o2zSYOrnaTKi/YBEsXyXJiIPYlEpBVQUHh0nFfKnBjd1XAcVe34HWZjwkw+UVuSA6iVJSJ68RX2wwAwYrakgSSdFd2U+yl2c3cJ7M1Kx4y2C5eW1kDauKqIxDZIlBDb0LYxhCgCUe+cd857531GzBnn7DV42dXx3bD3AR49z+afjXtBgmMn0CjCjlkECnjmKOiE4+aPRKCOvccg8kTMzm4gBRrRYa9chwZCPitrwuXzY5k3bsDlcDwuDgD0GqV6wedRZsdy8oFGp7vcvr61zXkltQbnqz5LJsjrxezsF5ff/vrvvLx36z9//7v1/OcD7i1l1O+PpzM/KnaKzRzXqX+j2L9+O2SLbMPHuaAG1z4cD2TmgEWEEsODBbVIw2QyH4H3IYS0sDQmla0kO5eajquvhiGndsnu+k7HewWigqCijo36QEpqIihbJ1twjzTRe2+Wxd1C5IWfMzFMi2oy1C7B0KzUJF4RAJDiIPnTD6N8ijagygzutplMyuRhlmqaaMS+uwdBYHYxmKmAMrPPsyBRRIk1hpagWZYzo7HXEbhk/0JKXYAdw6lvNVJX9QwCUIbChSYA4jMvUZidRGXbEOBqLWBEExYVCUJpajXGUCenB8DkFap8xfJiNValiAoZGxHk2IemYcdX5C0k+z47K5EuIHsyVawKlD2TKLUhMjvmHOAoBPUgr8gEGSMX9aCeae8hkYTIjOMbSHRNVrQoaxRVXvQGC55w1uh0Mtiq6q8VBx8tjsvh5rgoectzVvtJpAJUYevAu3lxOQ/rupYmLClsKr20ufVxlp2J5L1yj/MmLK7f/eyr9w97y+nZb//aenhBm9oOg8/zjVFxoRsXUsyUG851FTRwjIpGOBDAJJHAQC5BPOfE5Dh6M0WEMiLM8jNJRAmicNyd0vYwCBH7b7797yYXT3de/czyy2/63r09hMs/+P7kw1/68d60OSqkel7u5dMTwWTs6yI/5YOsIQQ052XYnYz4dInNmgeQKbch9uL6ZqbzVg/rdQxBiqxuqjLPsFy99NJr8x89+cWT7wzu3n1jd38/1OuNOwsOguDK3q2dreo0zuKg1OPTaq6TEcrRxZOjzdph2cbpQjY3tWizwMePHzw7qkdfuVufnwntgFMOJYkxQIBeAw+wcA/C6I16b3//LxfZXJx88OynH3zyYGN/46h6/KMPvvf1r/2N+ckFeUJ0jRduMg6sqsrOlutONZjKXCOpA2LKYCPLx5NE2bTEZ5EQWgiC907FsW8gufOybgIzWmHHHeSsVjyiyAvrDOrwNyMLqpEQE9Sc6rhVbzZZf/JpBOhqShCBptfQ/7qE23TRSZno6nefYiSl/9uPkmiN9sOLqlJUdi34ldn4pJx/vD2/fjnoh14w2aoSJ/8Ec/dVZg+xykuAc8RKYoorR45MqZI8ciNZxDcxoFdNi3POOZcERc7Z5IsOlDbg8UoplMJXupklnaBy5eL9qQYkwfLpmmunoHhhgZJs9tTQ9xBDiCGGICGGEEJomLiX5eyYPVsVzryH97mxcT1/sb55Lxy933v+xvp6DoDgRMmzAl5UEh8tMWzBFp1inkaU6Lip23DErHAK6rGL69oXZegVl0+fnj9+PL62f+ulXZ23+uGH1dMfALiomh5vrKssH9+Qu7sHv/Nb5dN3j/TR7/3jf/aLn33447OfoVk38zKvBpef8Es3d2/devPw0aPrB9ewv+fFFZt7jQ7W4rJ279SdP5XZrb0Ve0Upw0lRn15iLriECyyr3rqNXkASGC2ByXmXgaAhNCTkORcNVwLT5Gio8N6HIObYJSKdcs0Ssa7KcNrO6hXh6lMNqrEKzO2LVILYjUQhhBCCVWWkSmBhAum5M/PLFzJ9YgJiFLNwT2ws7qr+i23FC6ErM19RNoBPrTASpT25MUtUdJKhzLsQA3uSKOumZe/g4IhDbIi5aRuYtk2EPcNQ4pSSQGbCIgq23YpJ/iw4BUQwAMiF0GrywrTjRZ1nx14EIsHOMUa6wtJRpwGyTgKAKpGtorrjzBJbiNkzNyEwkQrapklsYBaCRQzYt1NoIOaYBmIh8gQBOcvGJSLvchBLZNKMOQdlioy4B8pEM0iOjCgn9IQcwyQpa1BDvMLaFUsqFjyspCgH63xvcPbwg58dvb8j7rO9rYN62HJo9rKmaItcwihmE3YevCm7t7a2L3ljWR3PL/OmvuF7/eFw5UQom4emX9Sbo8lw0dDyaW/abn0YTv/OrxS7mYybxbA9Xvs5ZRWGDY8q5NxyWIu24nJHJcUmuABdOG4KhYIQYxiUw6ZZgALDOUegIDCyG0HJenkDCbz3IUZWBxE/Wh2OBuf9D/7VzXv/PBuMF4vZS8RNf9hK24u56qw5vzzJb8SwUa2f8/GsPNibhXNs8lRis1dzX0I/40FwocnGRXsZtg42v3nc7vdmD9crlowd90OVD3kU6uXxdLe3EZ8939/sVdc+g+H1oa92D3aWQ2maajgsioMbfH40Lgp/2T6ZHvYgHtp4rz4XR7nPLpfzl16+9fRJHiUPsV2tl1hlVKnW4Ia5YSpAJWsOzji4UIyKZ/Xhorzsj8pI+s7Rj7Gd99wwhnBv9sFB/dL4xq5UQaogAVhDK9JVH4pEWYOa9C5oFG2TKZUSkxOIN6qnGmJsW1hEFW1a+EzREDh4bdpWSFJTqd1Nbrhx0iGhWwG/qBbUjW+adpNp4POOCZyeSjU7DpPfRrXFl4qaHOFTR0X6X4d+mzDJ9q+2OkoEWkpDSqevMBqHiiqJ60WpvO4s8juz7Y92Tj4eX7x1vB84efgoyPj6VgFj02TeO5dSgkUlavTsjCrFhBTxK0og79noj5zmQCJig2EpKXvT7+0qWwXu/I66V7ez81MnJF7YiBFw5ZL3qb9/4RKisMEapCpmzisxiEhomhBjaFsRiSHCe2bOfQYm8s5n3pFj9uKkdr6veSOym48nzcZpcXHolvtuVEtggrcf1kMtPCG3DEoFElcOiUPe/Z4sQIsEAHtZRz/cxrJa/sX3NzbHtz771vqXvzj/0Y9VWgdsfuFXASwWbrDz2eEbX3E7fCnHi/35+NqmPMcfv/8vfvNv/t7p4Z2PP3mvPMnacxpdzw/fPTl8cnbj2v5oMbpYzU+a6ezyEqplb4evuclouL8/fj5++nzn47Mnx3kYXn/9perJMp4HtIJKeFrEJjp4Qga0MYQQG2ZlaIQyIwZ1zqwk1XUCODJntmQ+RgREKCfIxrQsCblIcFGa0EyflgJKfOYlBBWw516eN02jkCzLJcQUjWBTNjMBDKcaJbmGp8J89RQwESlrykBU64wlGTYTrlzLTArLTgUgoS5GM/0jUjjqHi9lR7Yv7kSdSkTsyJMnphCjUAATUjueaBMkwmYPrkpRo1NVYUUE2Cw4lTv9HhhkPBSFMHGkmOe9JkTnOEj0hI6xEAHizh/3066lQCdQBZzFuDJI4RSOXGCYz6VEizK8ajjIObZAEQYY7DzHKBItElmN/KgAk09GYEoEp4AqE+ckXtWJmo9jTpoT55IL96B9IQ/KIR4sLAEUmAPWVK5QLjWv14PxAf/we392+sGDclQ+OTm/sbmZ9bnRpphkWhKK3I25LYNWQXq8LlqpZFTQiLaO1yFyPG7rUPGi8FyMFrJwxdbo0VHjV2ebvdH5R4Mfn/7FzWLn5cn4ldvr7Zdml0XgohLONSyGLQdmZSEh4Ty4EIIEldoDGbuo5OeLCgjeq+FApIiSfENVYyL3AaJqynIQsXc+3N0bfu7N3vFp8/Yvwv17m3kRcnWLS8/Vzohr7DjX+qZ5jFGG7R6aekFne7fKi8drqk62etf2erXEDLkM/WJY51uibt1m/o2LrZsYuwhPfBEuvducnl+MCh9IueeExsVLN0Ybl1Sv2/phgcXy0fNr42v+9hjvURGlVi53x7I7Ch/cL/OJZIhoGuFMqG2wt3/zaL4ebd0+nl64WmgNWoNqZgZyQk4olEsXe+DN5udvvz16dbBYr9u4dhmKopAosZZci7cPf7JXHdy6frvoe5lHJdIWaMF1Bm2VOJBnMa83D2QKEWnSLkkTjVKhph9g4zGCEYWBpm29UtNA2LSvMLlKN5xJYlWlSt/xsF7MYQY2WZopk+lb2QW765m9c51RkCLZyaoVFbPuNyROXjw9HRxna2CiVMMkqlLoRsRugZX8pRPcJYpADQAOqwy3Z7uHo8tHO/ODajSqcu34pxFKmupcf9BvVmtAzDtTYJgtO2IbOkWk84kEoN57dFpqplRtmVlt78v/9bzbaQ47KWYqsZ2qJC0GrmqxmHcikqxXP/13sZNIGeyZ1FiQ2IYYYwhtsBk4ACBH3nvHnn3GzM6zzzLHTsG5kyBQICBucP4Wbn5HfvE+PTnQz3swWAksJEpETHDpTVvuQwcXdp1MgviIKYMau9YXo43VLz5evv3dm1/++jqfPPuPfzLM/OatL/vXrnM5lPF1APjze5ff+U5v9nwxvuyXT+tbdXNn8uv/mzd+/uf/8e37F+OXPz+T4Ld99thrlo9l9zu//PObRzuv7r45zg+IxxiWzDthLzS36nC9vbx+Nsvfv7G13Pz4J4tHj1766j994Plyh8UJArx3cjSUEASRqWHuUSKL2lKCyZm/YDTwQmMkxzFGYtPhqmfqalYCeoioy1pINafbTKQeSxChkGAkIIQQ7NN07JumccQiEkU54cwJbTKLUvu9zSJGQI2peCZrC8ACD4D0JjpdqyHjiSBt96AXRFXHJJ3rs6qoZxbAZV6jNG0LZo2S5b0QWij1cr9eN56dYdQhBmsTYKEvsavYAtGIhG5REsFTWqR0/qwdoEXUNmvvs/V6zc5bNkPbtta+O7bKZ/jKizVLOmNMHk0E55JRO6VHwTEpM6LAOcRoCfKqYM9RQ1LGKoNIIpk+iyKRjX5qq3KjwUJCuoFFwPDQHqEHeEYp0XOftRQUQEmSqxsCGeC6bPYKssByVJzzMIvj6zvuj9//90u5726W0+MaRaYTj2VTOMgY+ZDdCDrkuF9G31ArOTOPfLOU+izwk1XN5DmTkUdgJ03Tz7FclvN5PurVJS1e2phsyBt+/e8ePVk+vXzjtXDti7+Cs+PgY466QHWytVP7whGrQ6PqhBHhm9xLXtcBlLETQFSCS7tF9WKyXjYv2RAjU9I0smOFKJz/xq/eKaKfO5+/9Yrc/Orsj/90dHrih8VCljLGweRZcP0qD6M7X7y48y0tytM//n9frHAy2J5I9f1L+fJ4ForJpH48KGuUYT30HnCLdR3JzyG9pobE07jIp3XBPsBH4iD45b0Cc92p+wcjXxSOlpOhq44ee1yrJru9+Wziy6oN9fGScwllj72HCw3TsD9+9tHjeOvlCOdpczzePP3kAbfsAlEQ6oNKYMhSCPfXMsxXvfkxHxKTDLP+ZrleXzYOw4ybJRx8aOvD5UN/wXdvfbaOtSeHFhQoNEDINUaiYJao5tOkICLnvT38jUgUjVc3t9rAEiGARGFy0W5SlSQIs/BqkYSmJmdmNo1dMoK+KsBEEjrfHxuAHWumUeBFuRugBRBVZpYYrCSRply/hJVDXtBL1fBb83dXKBxz27bOuTZE512nP+5CFT7FRYpAAHwg7wpfr+6ebr93/fkvd45+5dFtIjjuqE+U1MBNa34/FEW97wHwtj8jqCMxLx5LH4CAnUurN7oadylRRWCcpKutrrxAlK/GXrOShiqiGTPZINX94NzRzVLZle5SkTEiEtKgYsOSAGjNFq1tJUYJwZogn3nnvXOenc+9Z1OAMSsRxHsIEJi50uYOX/th++FHveNvhM96IjMsJjiIuqDiXQd0AmTa6DQNe7gmRICZXBQmzskXUfniP/7n3icf3/69f3z04LF88L2b/+gfDj9z/eEPfh7+P/+/sswgGwByeoW3+xo/GA5Ivjj6zFt7eflecf+Hv/3Wznd/8P+YfrR1B689fvnzg9u7pEVRFwXf2MiH718+CCHslSPGcLy/bK71ef8yvBwq/OXfGC/K5Qdt9d5a872zXolXHvjxg9u3fS0IQjXr8VC4AdUWKWd8BG/9JUEkkncgCkHYmWyNmLjVYB1lG4OyrW47CFqsn6W05lEBkQUtiHS2hsabUHXe2X0QDHBWS2Sx5E3Dh4mMTMTW6Vq7bKsCihbayQDSS4CoFcmIr/hhQsKAM6IkeShA0RydHDvHbLSRQGBGzr4K9bppqCMJEzuxnF3RpglETBZU5XzuMhVLroLB4BFXngHqRZFsNUmVryRx5gxpPloWt2SiXkqxYubt7A3hN1q4oQ2ikeFswaswmxeFEDsjUaqRs6OdPiakBosG53yUZNthA3uiab4ALLrDhSyG1WvCzJnIMTtVr8oML+IdFaC+iEfuuSAekhSCIWmpUgiPHHIFEWfEnok4LCTM4vne/kae/dWjH5+8N71RvPbKnSdhz6+OQjVpRsFX3md7eaMLbOar3E95b2/yiIMs+jxcgFdBMxlNs53GTdkthHxPRX0uPD5f5FLxRs+VKq5eboS7+eYXaxzifPnuH1d4Wt798htN9QSXp6g95Hi0X4UeReJG41p4zXIZ1hWA3EEcIBKcz4x9D1FTjimJqBcSLwQSS6UUiSCQitcn/L2/Onr/p3VW42uv79z52u+f/Mc/2Lr/CTxrxbPxzugrt0Zf+OZE7n4sdETji7u/df7uX877L8141fPueDH7bHgy9L3hCNk4R7NYZdLP+uqlQQ2vtOB+4aPwQlFj5dgVVSuxzXubWleR0T8om/m5eAcG5k8GvbotxYGz9aVcLuoNFMNMB96pBARlDtK896O/3P3GVxfrqsh3tvduXj55pOpjgXyLMGIdifTX617s7RSL2Yx3mmIoRb0SnQ5665fGYTDMn+Pg+aKUMA1nYVoe8+gOAhoXPURalsC8iBx8y+zgRG1vYtWDYWHVlAfUXVRwZPOAVSJWUoXG1M4av4bNwIig6h2zOdA6YniRaNtkcmwVEZaFAoChTF1FEK/EIo5NO0/RXBnSOBlNy9LLe8vFgj0xawypPTebPKM6iYDNGBaBBJEZKrFtiTk2Ma13FOw9TEQfAUZUqAirNM5zrIIvbs35ycbZdCM8HU9fme8ItCEx/wRIwagCyDsHEXhihs+8RlEVBTs1OX+q9J49256b0m6arByDDG9Mh0Wqtd3EZFM+wewFrv6OzOUsVTd9IfUy/wcA6cdPtThY9FFa/KqKRoSE4IUQY9Bk/+s9MznOfM6OvXPsmIyGDWZzaGJRZY7SEG35/q3lznvl4Qfh0dfdZy7DWpwicqa8zlpWhqgJZoiSzptZRTiKqvMUKaiD5AqSpwv9i7/aaNfl3/8/H/3wZ8PP3p78/X98+vYvTv/Ff3GLw9HoZkANKQEgd7Ll+aVe/OLWtX9y9+XJ+ebD78X6Ty+/t/q8LLO/94X7y+ft9xYf97+2sZ70hyWGDpN+zrVr8y9uvdmT4fHz97lZTm7dDTeni2fTm+ufF6e/DMcf9d8aHBQ/XRyvF7JXUXE03sNc+JQp40wL4lykUTgHhTZCCksHY4eoSsoWGO9cjBJVGA6qaiVTTb6Uxi8wiBxUzG/YOY4hEFETGlP0qYXUEpk0iMieLAelYIQXlbJXEGNV14YSC9Dzvl2vXeYFULDFRflIXcBjwlaMYWGrEBHxRog2syPrBlQBckRRfZRg+AsnvQHXoXU+izHaEcBMROrIhRDMhSO9mpKImCkbWUQKzPk1qPFkDTRmFcv3NKmQiALsnECZHDQygZ0ToaBqhmtGLBAFaYLlDGeDwqkXCszesbOAYGYSiET4KAyASVTZLDOZIRIpmXFCQro25k3dGfvYxk0obZi9KlSAwOSMVh3UYis9CRPl4FyRK3p+6CQX3nBh0OZDF4aEAcmQQp982ZLjXq+/4gZhgTkGl9yrphvzozh/9szfFFyElR/mT4sDOsrnN3b223WNfiv58NwP5jI4qTdFwuTak7JsY+3aR5GyGEqt6na1Et8va8e8qq9lef/y9KzQvM+rnZ6483A8ck/WX/Plv9WTXPKz6sNrWxuL5Sev7H3Rex+jVA7N5u24lnztY9W2NbSARiDkSiFIQ8hCaNnB1kYqyDzHaGs6TpHJaiijNzDC/5vvHE0PtSd+Pcd/+aPTp3erL7zxd2aH/7I3O2zeeHPn7/6jGk1sFsfhk956i3vDcPs3l/cfzpryebmXV9PNcmNZbx3Ws18bzl69M1pu7uJsjlnb9qXOWl8rLWIICL436g98BV9gclwVYQW60IkgHjYXh6TSRORF3jw9pSzLhiFkoWyziya4oZcJaIg4at3YXfpek2/XOfPmXrXiMFsMswltyfTsSTbyNHI0EQxAW8VglFF2/uzBD6/zUVGHHACqGyN/c49O5dbpaTVEHV0+eXOXdKMZr0OMDl7Wir5II5yrBC/iIcRwjAiwKhM7iDAoRGhQ8uyYYwiGytgwmpZdBiYSG8/K+EMpKQWdqknVSjgzOfJKBoKRZxeMeqgWTieqFFU0WiusTYicRmo2uYK5CK3XNRjMZEGkikTGuipbCaq23AM2E4gEmBhiLSLOeXPnaUNg74jI51lso6o4CLyDtD5mr1/uf7949PH26npdF2GjkLbRxpMnHz28846sXWYSkIiQWnYqVMXZhJts7ij5bBCz891BiAQtJPdQXAFo1nVH7X4itmQFm5BwFVKoHS/bzIOSO3wH82r6yg717V5BRWIMCkQRjVHVBh3H3nvvXacQcszkku2+XTgza3IKJS8c1xpe9/vvNUf3+OQr4WXPLsaG2avCq0NHUe0YYPZuDbzPSMEoIAo4icPwy7cHoRj95j87/MlP/cURerenj86aH/64nB1732vcBlOZBvtC/Dg0k9z9g2+88voRf/d/mhz/hdCu8rR6e771t+Jb325nfn751w8fPavKarJ9fXS4eyQbUsRh6GP56EnTX4yK3mz59NbJ/Qndu3n5k8vvz/zP4+jv3cyn1c352+vB5y9kcrS3G88VQ2AqVHMy3Yco28bE/FLN+zOxvM2cmZN1ZnLAsJgEY0tdsZ7M6Z+IPJMEIUBiHA6Gy2UVVLzzIUoUtYE19V5Q0QhVxw7ger0iZzIBW+hCRb33xnU285MXCd6G81zxL2ANMzHIMHPvvFW/JBZEsonuksBUKMUXqiJK7Jh+hv1CycIxoaq2EKJkP2q3H7MRH4igFIhIQIJgwJBCnCAleduawl5LMu/bYLYQ6hmG+potLhNCECGFWbxqygIhm4Bh+bUpy5SUxMZwpFdRtUdLnVKW5U3beJ+HGMyvJkJYWDqMjJFixiQJKUxP75gY6kXBlAMZ2EXJoAXQRw9SKIYI47UvB2G8kpHnoi1HvBg2fitXjbE63+Bsb3KggyHPZ8337p8dTW9de+XWsr0HHzOX1X6cu8PmfFiUk3J02OQrGUZsnsugyjdq7tWt39mcDv00FNpkggH7hgfgqayzlctJ8t5o8tWvLUsJb76084VeJSQBJ//j/3jL4Q5vPIDKJxd/43fuzHbo9P0/8699XcrP5/VUfDHdPqiaVit1K6AAGsCzBA945kAcVdjiRLstCQPKJswmZn4hGwbgFz/5Udl7o61HOJnLyi8eLKpJ4W9/PfvRv8fPft68/aXms+OcdcgXFxiEarVzsHPvpb+FX/zF+dYrOe+fHv/I3ZyU5e/+8OIHveHTG9eC+ixuNmEs+ajQ00Cu14fQmTRNNSw2RvWiqBb1UPj8Xj7MUbS+IxSgod6YV9slndR9CtpIMRqTXIR+CNtCI8KWP1zy+JWvvfby7uGKQ8ix4vXpYpBvt5txmT13Q4lDuD3WstkswuzBO8Xp+/tuVWCVwSNevBRo2x88Op3toirq4Y3bn+Fx9t2PFrsHO14kxhZLkQqSQZyCRRrOOFNEkQA4JC6ihSUFZadqtH9ndy07qzpkZJ/EzbdnwFzJACRrUUqnLzkk+FZsqczMQSW5ZkjHzkViJkKiY4LGbsllD5qyZ2bVEM0QlxTJCtkSHux0IenIJcrsbUELCwrodDmZs9w5COB84oWKRM6YgushKnPwGtTfqCe357OHW7P7u4OvPx81zIwicJbLOuY+i6wq7NJKMyXGJB5UYqJ2x55CiH2yaE80UOOYiJGE5YUlQud/gqTfMY6DiI1c+gIW676bmG8KiK4o6KmWQ5Nzkznnk62AFaLd4ATPznvP3jtm57333oqvqVaujiurMqSILCzOi9RoD3p71+rR8+HsvkzfoP1LDmn6ZnJq4ljV1I/Z97KPS1jzJoev8rVsbA5vbv3Tt9ZHF4ff+083//E38Lm/d/jP/9Xwoz8bXuPV7pYsIpatNIXDGgAKsBf52hu3v5S3f/UXs7f/p1t3Xp2/1xzwAaNpf1n3Pqdv/cb27FeuH/0vm9W/mDX+cnR9TDey3rBZTCq9nenlZPpG/0Zvujh/unNydvHD2erDOP7Ky17KW4s9DPhwfbqZz3OKdS+nXNizgpwSKH18SmB1ikhIic4gS3oGRWHPkWG7mBg1cywiKRfnKtMyrTIgIaqqkeGrZWX7CWO1iAgzmEmIvWMAGtWDLeUs72VRU7ho3stj1LSIiSaG4e6id/dKYn7ZAiiRL67Mba4I1enzTgQNe6wMC08tGLNLqQbayQuI0oDOCF2iOHUrkm7lb3VciYkiNDXTrOgM0rovNZ2aZ6cSjTUFsldIb06UJUrGbCohujqJoJqyWzQGQ/dNuauKqMmUQ6GUApgVEEQoqxgobSCeA0myTyclUhMbmqpalBgEl3QIdsUjhcRocwoH5NxzUiqGKkPBRha3a9dXbLWyxbrlbsXl9ic/z+SyfPXNjVfGuHiw/P6P6l/e88XOWU73zwaT7E7V8Ec8GvqtaaxzbP3ho/CNuy/NAs3bPGBc86jiXt24Gplw6fOqNwnDto8QKZOQt6M511J4V+W7Ob761lxmy0KQX8cshlmuxc3Vh48+P96/vz5C1vveH/zZb//+35189ov3P/rR9m13MdwYhvXMV76foWDJVXPAKzlC682VRgBSdr5QNVGz3W5BVboYKSKK5lCviJ5PK5x93/k3ctl//QCv7JfrabXcvDMvXimWvwzvvNe/81sxhr6fImyePfyw2H9jfP0l/DmPmufPb3+dDyZnzSfDUaDdb70bf9E2PxmOfLHV+p4Pl+vL6rKdNYiZz7J8FtqiLuqah8K5dwMPz5j0642mV4zyzbx5MutToxcXsu1XMfSJy1KnQHYt92OpN6RyOzPdvMBWnV07b3Kp4da8jm0zuxzfuO5yrfLjbK+gUbVdT7eaJa8/YjzeYUi4yLTeKNzr+y8/Xzzdryhk44MvjELz4fff+8nN8ZuXM78x2ln7xhU+5Eo52JHZJTStEAd2YMA7D2nALmogcUwaFCFGz8wgUXGcyCQW8N1tj5PxPnWtcbKa1HTqiqaIzSR2ZDhlQ0SNOkREnTRGY2yT9pUdsUMXDUQhOnbeFqGi7JzxDq9qDiFxSg305I62yURMzuRD9lLEzN6nwgK2IAFHBO/hScAFsVP1gV9vXzqsZ4+K2e2Nyc6q8J4bAVEvM10UpTlAPiU6tCNFVKFBwaSpnJltm0JVhLp5wuihUESk4CFoyi1+oRjpbPU1zbF27ncCWzW4wY4vmMBb0wyj6SXQfSaw87fjXRt51WXsHDM79pwcLgn/1X+WfAOyrGJEqxLR8efl+kk4eY+e3pUdBZPGFuqEJf2ASbCaTn8A8B6+QeFrXVTZePdWvrlVnT2PT3+49/tvTXWK7/ygGD3FuFjnvd7RIvRi3i9jKOWJA4A81Dl4pzz+kz8e/eX/7eW2J58s3GPF0O/43Uc/et772iQefzS58+rof/eF+PUz9847k8cPdt87bl1/tvWfjjduPOvt3/3he/v8ZGt6L8yPaCSj//21Mr/+xQeTWzuvNnfd8Xz2k9MGuXI0rq9CBCaNNFcjpc4pRq+ujgl8LMyImKJGaw9jDFYhiFiTeFW7OcxYWSRJG94NyqYO9z7zGaBtaO3OyrMsNIE9i6CxMFEAQGwDse0GiMACtUeVQMpKqilsqVMBWuPaSgDghR07k/IYHIwXdzKlkFtKqVYmc6IUhZPkfFc3pk2VBKhK1KQ/sx2EWVYBUDZQVwWaMau9bcCiNXDFzAQluNjIkpQ2x3YXiiJKNI6lyqeMdlRtqBdVJm/12giMUYQJ5tcsKva3RAyNQcSxjzE4581C50qxaD1EwtNgPBe1ZZIooMzk1JFGEiVJzGevWaSSeUg0Zt5iLUNz07txNq7PXv/k3VvbLh8jjPY271bxz/85fvQ99sN5MbrE3MfyWEZVdnM/v/Oz5nkh5fWd4cDj2dFHTx60r9x4NXB/JcM6G3rkK99rxI3KwqOabN+bH59qAb/fa8uoRchmfvPmqN7rnzUPNveLBau++xHP6/Z81HefWS4ebnI9qf15KY9/8fj/9X/9v7/5u5//2m99pfnx87Prx2eDnWGzOvc5e6hTsCopu+QBZJebNQtt9N7ZLe8YxPm6WQGE1HbbAQ4S9Vj5duXax+8cvPXrNw7eODx53ifuCYXrd9uPP9JP7hfn3z5dL/Ld08vjjY3hloSmX241uR/cO1qHh/LGnYs8HoVZi7ZXfsW148340xu0Hg+P8q3+7u1+4xarp1W7qEefuTnywX88l5zzwseNoCPxOTSjtdRFX8O2RERfZGi4Vmly9VIxr8u7W3GXa2zNsDnH4FKHZ03ecs/VwFq4yXrjTLfCZPcmQmjK012cj3B+0F/uDhZHeD7Udc6XX3jltRt7B6CsPDkdbm/eutF+/OTtdz9Z3L311cPmSZiF3sivRgVWIQyAStg5ZMS1cAtmOBA5UqHEiQQrxWjBH4AonCMGa2oDDYbrKEKGrnZuE6mXBcEMzJEmQRuITd/acU1IlDlF2XefrnPGj7JUCU07GLAyROCdaDS/RhMnmRZDTXRJfHUsmIChczrtqjTUsXfO2WbTuC2eHUDMiHCOgQgmHzJZe70l26+vrr+bPX5/cPTb+sZaV4XXJmTQSGbNj8SsYTbys1rxpa48gkWVFdKKGuVKYuiWtqnxl9R8oCvlNmWIqWbN1bITgCYCGmz7JaBuhpCU3959N0n5axaEQwAJeXYWaAjHntiiWZxzzEa4YWYyUPXqWLu6cqZApghBECIvXLf1Lb9btv3j8vxkORvzaC3RM9oojvjKmMtGdmPDiiLAgz1ktL2zn29s1dOj5p0/3HgFq4eHIR7JuCj2C63W2lSBfXFrL9bDfnNzXh4CiGf3s95o8d7bpfuR13a7Evl4PvvB8e3bX3wWAg7l8l88vfZae/7g8WTn4Wg/fu7v9rZovf/4sJ4ujx8uxod7WfWZW/zRa5vv572yeGs83D+4FvY/d/8VNz85nf+0/8YXr1+/u8/7P5uuQT1nTg0xKtRxcvkhOKMGEiUluoga6hY9JIoX9laniIKxgIDOhow6WrvNlAm0EBHvnUaBKgOiUZRjaI0d7zg5fjifBYnKgEie5W27NsW5bTJSy2m9knb9LyUjUJBxnYlUo0QjXzOzYVYhRoOjUq+WPjuJ0Vw+2HVuqQSybIYYRBlmTRKT3Ig6xVu6P5GSugid72z6Q1Wxui4iEIpgR1cGbZKigOGYJQoREZsTbwroStI2SViCbWsd7NrCQhk0LV5grpyiKmQLBE7WOtYP2OfBJBKYuRWxFTl3JAo1pZaqu/IJS+0MiBzgQJnjXmgZyJBDe6Ch6gZok3QUws18283ufvD+9em91/Fo4xeH89de7998U/+H/8vg8GFRFAtsn8h0S/KZlBvYPGrxxWz3l/XmIY9OjulLb71xUo3uzy8/eFLe3rru4YplT2K73N4hDn7eLsNWwMHmKzH6NWZN7tui8P5W4fdy3S3arD7tN/JhPZvFDVwvFsL5TnWRb9WrUeandfDjgUb/7p+/9/D86Jvf/juHZ0e526d8S7JG8hxeTIyl0OQxTID0mAkIKkzsPBPQighTL2pgAjNibFQCMSnYx9DQyuU8fPtHf+WHm9e3R029oGrRbt4o/U48P2pOHsb9YcY8GA2vDTaeh6i9zPtiyKuDj35+VDr+3Odm2Yx5N4TZbDC+MWup/jG4HA7medPSy8Vgazs7pWUIo2qGl3OKdchD/lIh4ybs4tTvRPhReznazCUDLmOuYFHy7O3cv9VbFntPq+ICk2NsznhnThNckFwoL8Eibs8t+bL22cHnPhPOLvP58/1isRfPn5y8d52O/Gz18sHtonrpv/wvz3su3L493m0fPnr6Mwzyb3/+8/fmj6vV+ZKQrYabo71Fk/s1h0XUQrWFrKTMcqdB24rgFK2AKbaW8qXqVKM9RWzPHhRmi/Fppq4miUNaClOSFVph7bYp6V8xO3vqXEJyruhFHS3TuBjW3oIUcGRW61b5u5w9EdstdYAQIJQ8eqyFRrJsT0knIHT7KGMUE6HIcis8UA3EjsRFlgyI4sWDpMqbL8udx+vzk3L6UX34htycy8J7WQXKhK78eFMwAlLPnCB4M2kWaSUyqDMPYonB3nHyCMAV0fLKYkRV0YYWRN6xCtR1BVglhGgHakh8Q+ZOo8UJJ7ZROHFELSfcs3NMZm1FjonIgc2Di9I87Jg7eXQHXV55XIqqEmkUUg4uOPGNBHAopXcLe+/Ts5/5o281BZRFAtTVFHwHhiSXB3F2/dnl0+fTycat3uZgenrkP/7B4GDV9ELcqPj61hDtUM6aka/yrd7m3Rgn8aPFWXGT9m8DaP7n+3ndYCFHQ/c69oV/Pnj9jRvtqMxo84Jee2mnuD1sXt55lr30pdP89UcfvPTdJ2VB6/yLuC2335iH35n+zOkrbjT88Gv5hz082Jr8h+LlfoXh0eparH/8w8nf/cKTFW/t3eaqCO0Fx75lEgI9kEKDarCGTST5O6VKBctCAhOLwJuHasrHZHTr2PRrQmUpigjgmBgc2uAS5wjMMI04jIPY2WrbNG7gCwgEZxWdExJiuYQMMe8TeyLTh/BiXgUi1CkBFCQmFD1BLUrJIdaeF9PxpRsCADsWEU8cQjCf9tRJJETa/L6JKc2malnBfIW528MCMygxHyUo2EHTDt0uoHRHQtcOaNdGk5oXlcQU44IuqcUmZPPB7nzRNfX/bMlRJArvXAhRGCRdnJ6KsVuAlIlypdWWhNGp3QTCPjUVyiBO3tDIozJzAeqhT1IqSgp90YH2b/WL+aON2QcRx8f5s+ny6a8NLr716D8s7/2r5SIUcFW9mIxOtiQ/wXjb+Se6oyqzZvnN4Ut/sMjjk5oPenfH3/iLe99vm/Y+H90cbpGnvACJzrdGwJZwTVDeGu/1H5VNjQou+Fh7leXGr+ysTi/7z0q/gZEfNdM4Gm4eNroxGF3OT/eK3YfNmZvlAYH7o8XD0++8/cdf+Dv/x3feezS5ffdZIyWFxoZgpxHmeS3Qvh3yKoESF6cl05irALlogBgq6kVUNXq/Se18xY3Pz3HvnbdvfvubvdaHofgyD3t7Xo5W08P93/ybMd/cGG4veML9DR5uhqxAWBxMiX/67iFn49c+i81J3V9m+TJOJo8ftvXp9w8GOkLjfSst5GZfq/Vw3kge1hBPwB6yHT6SyUz2zrXYzKuNUBWDy+1hbFAL+0yExa9kp538ylm197j26/L6lLbOaLdeZJiSTFUk5Pv53F1kpfM7PL98dmc82MqH/pOfTbZQ51UdC6zz+aP2Ekf9MNDL5qMfTod7/vqNfWS8mN53i+39SX7YLOqT42F/MC+9lOA+oQ8KQEGsTK2DeNIAmBexh7aARY2aCogUoiLsfeepkHZIXREmDxfMNxXKEAIb+dETYpTEAE7ifjB7I4lQN2GpSEcTZkB7ea9tWoF2/A0wlPUFocnce0yQ1k2SL7hMyWKY6OrY6+axpLj13oHMmx3MLKLeZKyWpASFgD3V1Ix5/NXVy9/pffBu+fjWYpKjCKj7QiGRwlPfbeM4iNkRIyF/IioxhGBeSVCN5qDJFthnfUGHoumVRLfj6yigkYkRha7gPvNIgg3TJrZmUoEzyaNNvZ0xDa4Ex46dc8477xw5u87ewHEy9yPtzj2BfUN6sYzWpHESpKhUkWCIoMqrsvNBc/wJnxzJeNiMBY34XpC2C+P5lO80odfzJ588X8/7wzfG1dlq9eyX27/1K4vLrJ9/uL3htsPDnpwOYxW3Xr7c2Zzl8XAyCa++cXFYuL4C8DffaM/e9dVkNtxaYaMecl9ONz57c358Vk4Gfj9MXhvfx/gC41u948/6k4N5cfxeXnw8kAFlBxi84W/82pxmN+J3svg2Rs+1n62byWLjG6559rOsOJ7O57OdyazJDkZ3nq1/gT5ownQ8RDIeXStUVB2roc1IfafxzRgSmSlCgxUGIepYUpJmUurWogTAOw7JZQbeO4jwlQGGSFQjEZpkCSFGpCW+gNhsGkMEOw6h7W57IGU2WNPzacWvEQlg1D+RqJ0gyjERUxsjfeohsvsUV3ZsClUll1pkAM5xG8W+CCka4UXZpCuEPk3dCiMchyhGPzNRIROLGuFASY0v4jr6liQHAYAEkA5oQ+rn9QWGBEWkZFtNTNaTkGnwCDEKkQGitghK18raAeON2IumXrzbnRgmZTYmiZQOl5Y97FSI4MFMkjHn6l3MohaQPnQI3nJNM8vu/3g0Xm/M7y2bT4Cjd86mD+bu94rRTsWnx8fsSYbUH6z3BodNuV3VbQ2cl73Xw/Sz5fVfDvH8/aOt0cEXJ28eHj6dPjr5JU72y/rGS9u9wldFjt4eI4I5yGnoofBVUS4Lv2bSydOTemuwUQ2CazzleV5QqKYP742u7eHm7ct3jiZFQ0L1RSOl+kWdTYbV4fR7f/qnp+2NWT2+/sbfPXlyDs6EEmmdlEhLZqhIo8Kcq90J5ICgCODCOjKJkTkHgkgAMk/rmGdlzRj2i+r86PTekztfvBPWs6wYrifDfIF89owbVKOtYnRwcaSHf/Wn50/rzbOl51JCc3Du/Q/fPaybnbe+RrlU/eGsLN/48v+h/eXw9Oj7bnPd374s9mNZu/HDcxQBueSs2qNmgGPsnWJ/qnsLDC+b2YCbocMZzbVdl5wRhxb88Wi7GX5u5ffbrZ3jdT53O+cz5+eBL52CaEuiD7ypugUfjnZ17qvF9VE/urp478+3VuFklpd1hiXtDHk2nyP2i92dqMtHv7gQbuWANw+ey6Jf+OFq6vv7k9z3F0XuBowFdB3znJtq7YXIu8jBgyWCHUUwaxCJTOS9NwcbNmJO4m5c3f3GcyW1FDZTIsLMu21hIkzk87xt2m5VaY8MgdJDk7pzMTc66RxxrIE2H8w095qPMIicY5Eoogzf9eCpHHbHQHr0r/6JRkGXTR4l5rknUpdlUDjvogQfYVn0IAIFEBfkG6le8ddfunz+ydb0R83Dv7m8uwwUKSZVD1RC9OzseCGCc16TxbKKmLmjWDseY2Q7OK4WJVdkJ1ttG76sooo8z1VEJSUimu7TIs0lpeJcMbdMLmS2A9y1IY6Znfekys45712i54BUzUXY/BpsEr9qA8y6S0FQ6QYnA7UBFaFI6gLBiwalpcdm29+ry+PR4lF1/kYznmdNXgMIbUeqVYDIRRGC9w7L2t16841QD6Zv/8noy9vuzf3DR82vzB7fxXQvPBjkzcbNnVV5Omf55M7tsOt/foazJ8/rcwC4+cUv8V/ex7N5GEw+Gt4tdPZGedqbzFc77UZfsY17DX0w/MzDcPsr8vbNeMnTzYOI2dl52459ljePqtFOsYJbz2MJ9SNZrqrdYq+ZHrnmyeP9G7NHPr+e99Ynt8eb1beuz9859t5DIEcDILAvbGQLoTHzJLUpyYAHBYzC0/3MBsgm2w4bAw07pW6to/BEUYiYWSOc6yikHmqmzaZFFXYMVTWXYe8lmo2Fi6pQZOwU0obgO0hZ0/6d2KRBXcqoYTAaRKBM6Ll83TZCYGXryqzP7izlRBSOnM2x5tPOL3jXQrYndmxNBCHZjAQJzI5ME80mEzDMjAILA6QcWNho8fYjU6eXjuKcj0iu1iqWNJpYDaokQpCmC2EhR2z2dtqBcKaWt8YdyrZbz5wPohLRNI3N8WD2L7J87J/b2kaNA528axLZPRmHmGM71AGO2EGdCBP3VLx65ZIxYOlHHWhvO49H7+4MVjvNY5EneX60N6/5tLe+0D+4nP7DfDCpR6erprxexNk5hgGjZ8PXvjD+wm/w3W+/86//09+cXn40zj85fPr8wclXX/vKnezVnZ1rjx4/fPbkcrVorzWjkS/n46IqD4L25iu/dmXfN7KabfXCzbY6qnW8bMYDptWjvmbzD56Ux7IVNp9/chghxJg0Yafnpj3xDO6D+nB9Pnx2cupHH529vzv4wt7w1vzZJa5Qx74qJVogwUVz+xUC2ii1clAEaPBcKDVWo8HMLL7ZEKrF9wMqX2blg6Nf3nzjJg9Y87bdnnCN2KzzjbCYXz7+yR8tflH1wv6k2WewtK2Pnue0E9B/+/1nNcubXxqyHhfjjVyuv/6P59ffmH30g9vVg4P6yV5Y6E5TK0Isa5er8DnvzXTjSLYr3jnGJPOTPuqhSo9WWV9DUw8JAfirmeA//1CvvRb3v56/9kY775Wr2CyCxMaPtR1EHcRiKOV6Osmnm1QPl2d5oXlfiycf7FZ7ax5XT49zf/PhtF+de6xW+PAcI1/eyDZ3R2fTuhxzU06HVenzMMDNARZVua19pVJRQXJmL1gTwTE8pGWwneSAaWYECk/uyuoh9bxdjWNmSaZ67NXmg6t1kRJrhD090XlWEVISO65SVh2nymGbUxEBK3C5rKxWEJHZwJH37DmIeCZvlNQ0T1iWoEANwureG17ASrZK5kToYM/MnkHp1LGoEwIH0qARKmojdNQQhSjEiC/h5SfrxYPy+PZ653q7XdG545wkIjKDwa1HRuwdQhBhwBNadMsmgoRoGgZJPoJsci2RkHJMFYYCxyayYxUEacmkxgSfgDK2ADixkAMJjpnZdUAdJ/Tb0EImJicKIpdnuaipPQXwIBabTKMKQuK8iBBAimCWBUytiGfWIMQUJRIQDLSgCNFABMf1qgX1bi3GR+P1/cHs5nSaB9e4GoHghSUGYs+OhWsJG3mhdW84GY3GO7Of/6yJR/Jr3zht3r8+e2cfH7/qjm/5p73VrDf6nTnPT2/fqjerk+c/bU+u++sH/acVgAVdayZ3J8/fwyh/MLhdIizCo5evF6xtFdbn/a2H8aUHi+tF2W75Op/XPB3UP28frjDc8NnxfEsW8zs3m4Om55m0jlH9KOeiOf3udzfeWtzU2a0P/7D/hY0JbT5sKz/5zA9fG0FqNCpVhrokVEDG3Kg4a0kh5LsFrQLkGID9SVLhhNiRlRgvlvRgZpJoWaxElqLg0rBpVYSoA2lZhIJEFTLD59g2TKxkZjhEkaIDouZJt0PETAqnEp0gCiWOpBkFAgTyjkPw5IWIve8kRMQ247FHRx1IASKi5E3xf2XVZj2GEnGIwSh9KmqKJsc5oM659JXJo5kFMfmhsbgrKy4F+yu/WcC5tltLsQnsABIlMCWqGjHnUaKkYReCxIB2ZC2QFVVnWsm8l/Wy8nI+N6YIZSwQ8w4QkcGoXC6rNAuDYgjMCvJRQhq9RaFwHUof1eKYTaBg8E6mwuwzFFGLIP2ADXab7IbozR7uNYcFnizcyU7VxtP1+lD81HONP1hc/JPR3l7IT1eL3rB/uTPWN798+9c+w2FQVkej117B9++/Ve7+aIDGh3sP778++QKO5y/1DtbbzcPjh4Fkul7svbTZ3y0ej67vDrdiPHbS7G2EE7SXx7/cB7KzB2526JbRVdvZaOTRyrNmnJcuNgHIOW5CzwhUIEAkNlG9+B58z6H46Ts//vVX+ll/s+VaIrhgHoiQthIcsxdisLk0UeOpGbJIlDVRG0LLTOS8ytruQS8O7CEZkEvR7y/qy8PTw5fuXhOvvszQY8b56b//75uFG2BvGy+fckHCFFmiQCEzQSM7ftR/74Pp8eP5ay8vbm41u6uny09Gs8Nbs7XUHPze05AplxWXOVArNVSeyeaFHy10fC4b5zxyMsk8l7L0Te1jVEY/VOvXvjFrZP3gg/ZJRfe/W3/vvbJ8pcyuF34bt4Zxy7mdQZEvtrHckmokF9s4H7gTfvIR3v6jybT36Hi1qPNisYFqloUwDgd91nw8DJ7r8/p8WTcDbqT2B81br8rkM7c/qObnUubDcTN0riKpVBfRlxmWIJici53zIbbEbORDtqwCMkthuMTHUQLQ5QwaKmxaMLOHSaEwqTiI3fqqmghWBjqJaBRRQNT0uiBm9k2IdiKAbDROxnuWPdLVXSCxFTv7ZBO2pqPByFm+45R0RwZfNbvWyzlK7iJph8RXGx+RaIcmg4G1ryZN77X5zoeTo7cHT769LopQRl6rEjx550QcAc6zgH2KpYNTgEkZHEIkCtJxRKNY0l8ak8yE0ogzqt5dZQcLumwXU29Z28O2YTHmDSzr1EDCZPeQLMc0yZ6VUK/rPM9Nww2iEGP6jDrowe705BbCtIZQUBY0SSJFXY9jUz41TUNM2oKZq7CaSFZWrirjYX+xfzmouc2FpQVAMUMIPUgAYVCO8/72QMtmyfOP7vEwzt/+EykevjxZUGjq9bpfqM6r5oN3mn/4Txvmh+/fO/ev7VwbH36Cvd0DAGW5UckWP2Of+yrivTuv7cne05p9T8rcTWl8pDvzaVbIelnkcSNvhnU1aO/Eg16oL7g6vbZz+uEPxn9x8plf/Vu5FP3pYlhg+vCPh3sLFwo9auTkLHzu8uBWkOKjOh++vP/qJ6fMJ8i38vY5FDkjAKwIzB7aUtLpkjOJDgOAsy2KJYU4B4WYQUWCjMg6oURQICXAgeCZiTw7YROrGwAEc9ASo8iLRKh3LsRoAGBeFKENoWkdkYgzOMp6KTZ5gvnQWZpmF5pFIGIfIAiSZ541xXmRJMoW8MJkzX6RRJ8ye0h062FEiY5dlnkQtU0LG4Ip0ZvU/O+8Kf/sfiPLGYkda8F87agjeEaJKVVCubOb6UDj7heD0p0RfoyuoJGIYtTUw5CZU7KIhKZt12sY5MQUYgCQOW+d92pZ2aoMpEpgECtCDKwEZx8oRZHAHRsJLyZtIiLyIAf2mkc41Z5HIYPN3iJfjouGm+OhW8z0ZK86xzm3p8pHEqcR4ntS/uHx8X+bjydFeHI9n3zz95vQhCdSDu83sX/r5is/y37yG7L1oI9pmZ8fH/+Xe39yd/x6GcqnT575wi/PJS9o5UMvuHapRxv9Zu9uATmu558cPfjbdHMPD9bni42Xr+PBE3YBWVOsL7lRXB5T1ahH7PMoZ5SBGZxRkJY5j1EChFRI9Ud//dff/My3hdl7lkKCg88wLAaL+UqgDHHitBFqCWtq64imh8Dp8xJSRINRPO94EDjPNJNWW8A9p6ObO/taCsTJJdyojVVV57cu9NpJ3FjIABXJGtRwXIlTLla8enLmJ70Dvdib/7B91G/3+mVR7RerPD84itmpLjbzYS80jfiVZw0+cLHAxqK4Nr3MG5r4ubR1Aw6znufrd5og5WL2dO+z69tv1iHn4TfW734PR4/KZo7ZT2fVezrJ4oPYO+hnG8xyuMZlLWdDOWnkNIsno/WTQejPmQ5R17NYNBNQ5qvjDNP++FePzi6ansYCOuzt3ejffeuV4V1+1NSPzz5B/5U+vBfPeR5YsowjNyLKIGKvWGd5FtuVYxctktqGtbS31bR7udpidSKctGqlq664W3Zxgq3T15iqw0q1SgKHzazSkDGRGMSzT//W9H2kJioybybDbkW140IqJJpG84qxkUQhafOY3lnSDF2RMo2emUocmbElDIMzjzu1EkgMcopVbD4fDp42s0Vvfb93/Hq4HqHecQFaO8rgEv/JFA7K7ACCRgiLT2bBKiIJEEAy1vDeGc6fctQB7xxUlLv3+KLDYMvY6QapNEuA2TA6JuoIaC6NHR05xfwCbW0gGmDi7rRIv5pDpDMasA6FHUiihhgS7VURtRNQQVlJVGKMSlRIcW3e+6RcPN2YTy76HGTtI8CZOmlbB6xB2bLmwa2QU2/Ay59/JOdnxbCV0ye9L4x6fDLIWw6X63WdF5Pw4B7ee2d++/ZOtukPNmKe08sH/PQIwNkf/aH/yT0py/yoOW9QNvnxeOtotBX2x97leRzUH81oqvrrxbwOs/q4x/PetQMKJ4t186DV9oPv33l0//lx8+Tp5Prr13t3qurdvx7lT+VWr37YFsfFuq70nSpIfvP1o7ls3fC7R/tjHAd9ruQ8NCNxgPcsEmoAzIiqWZ45dlGEzXRGiZRNCESOmaiVgC7+Om3TVRgUNDqBMtS5zHou06gzRzWPp443BSiUGL28aNZrG1md93Vd2xMmSk3bOOccOzLDbyt/pKoWE2FvTVkpkDqCV5esp0nBbD6ajszTC3QlcyCz97CClbpGZlUlgmmUtW2DkQmgcOw6+Zt6Z0wFw3e7iq6sCmNBXXXQZMiBFW/bfURR422m8yf13PZtVEjVBIqmNbL23B4yWNvOxJ6NB5rEQypCiizP7OowXFTJUj6XofQAwOyTQFkQVFTEibmdRTYeFj4FWiBTZXGgwiEXzbF2jRuzr4+HmM/pfNROZapyvM7OnEyZjqM0GsPsUos/kNnvb+8MP5zN/tUfj3/7d5dyQXeHy4uPb929+8ErN7MHs98c3/q304Y382Im9x/dw5S5Yt5hJ+KHg4VDWNdU4qyerYdRSwpRxlvDYc61K/TiOc9ivkGr40dy0qDOm+USa83Y64hbkrLH0g9c+MZHLv1l4JZdo9SSz3uFML337jtvHXx9FpZaEHkI66K3loJZ1LHTStFA10AP6DFWwMpj7VU9UUMgSAuC530OPWAALqEKzvLzchauB7fdlxVkzsti45yuHYXdM4zn2GqagmuHimQRqeW4lljLcNyr57ES5Drqz7Mh1rozfCyOeFWybrrJ1Dc+k7gMK4GM9xtQMwuraeEqbmazfMbaL+iV2+ePHt7+2//g6N6D9f0/ae58Zv4EEk7L9d7W3u9VeFB98AuZPumV4gvCAC5OR7PTHVwWfL4jxzeGYaN52p9fZOdlWNdnw/EXf/O3/ux/+J+n1bT0G2Wx2cwvitn9jeGNOPHFuL89zjd2qsvlRydP6+za7dGwfxEA9h7cREEQVWbvCWDvRBrHCEEkinNCBJKu5bMZ1BaGyeKX/uvcEUkMR6XUbhMlA4ZkSqydqE6ZiL1HUgWkXACjxxqvP1l5GBuLE2jL9mddKUVHwOjeRHpuqGuWrRR3bl1QTpMidVNI9zVdX83QlESqKh1xOu2qRVu/8mHYuM9c7Px458mDjdmtMCp1yBrUORc1ldugzqd1ODR5PouocIyBvEiQK38BBjNIxYQsdt4ZmwUkSKmO3K2dTOOoifCtBErV0mZoStsqe88WDmMUVEBJOEpL7OB9aBr7UdMbU9WrQn11FTNPIcbQtJ5Z7HOXBKSasx/B0MXM+bYNBAjTtWrwSXs5H9TzYj2pnAjEK+pAuat1zZqXJ8d0TaigOA/Td/8a1XPk18jn2qxbymrna7cxC2f7vSwflv6TH++/9da0OODRLje99vvfXfzrHwDoP2h8LKC5exjcQmLVYBRltuTX9mgVV8uTrM4iuH1cP7p5a7L+5I3Xj6T45dNFXIVY+otXj3lTXmK3an/23vns/uCbQ7k7rXg0ml54CCiQV15MfT7xQeBJyGfcq5u11BFqcGxM+YM+LSFz9kVeMHNdrxLZCmZFnJhHAqZUiCnG2LG2mKBe2Sqx61pBd8W1s+cGai7FqXqRNk0tKfQwMMFleYzBYkygL27wdHN3/WciKzIBYJCNluIIytZ/g3EVeIbEpE+V7yrlwMBeRpIVd9IClRhT1SQOMTjnmZ1oMO62KYCccwq9ct2wm5btZjczGhUiYmFiMp6Udl1+2qhb92yK3nTSmJO8iZbJJgRj/HURGJI4Z0yiQpxGZ4hKjOy8BPG5ixDHRCKeOTLFGAMsXtmahc63TrQD4FNIsHWwoOgojxSV1IGdp4DWeUIIp9KOpR0HCRK9ICicsnhB3Q439/oxPr8MP2kWvzruz3/+k/mX7uRfem0jTi+eflDufHV86/UHH3x/J8/fdO27a8odMu+VBdka8z4Jz5/MRnErcO/48RH6cHNHfQplPhzLjBDjcIjNJw8+PqBn/RHXzDzVwmXrShrPKnBAb0Ox0WDPy5bGsT/D3lS3ZjyeYbx4dvn69hen7epJ9fHenVvVeu17HD0chOE9wyk3VeCG41JQc6yi9sAFcw2tc6pzcG1X0csOUxG1p36UQRGccMFyLfZ2OFT5/JPrCy6P4+Ycm5c0Psc2LhFnkRbMa0YNEoeWmrk4gQ8KqeroUTOv5r4fpMwvh3tzF4oNJ6zCHmEVZj3fNIu5Q63FYl1+/huznz8fDjZG3/oH4d7T+VHOx4zzzXo1oakUUq6bi8hhNH5972tvzl47nLUf1PokFqc7OBvhdISzIaY7WGwtng4XMRwrz+SEhxuTN3b99QHcIqzquiGOlA33Bmf94WnM+kcX4cFsjbP1zV//3O2XP/Pcb6SICp8jCLzmuQshpGPEJlTRKMFcWdkZ4RIxlSQ1wiyspjLMLubqcbeh6cqwhu3JVIDElBhRIrpkUwnBFmGmOHLOE6iNHYTsXFLSmKWAqRAImnrcVNyuDgVKDhvMSIbu9qxqpxKwo8ycahNxOj1d6FhMGi0fyKjKKRfdDiTjXwaIW0j7anv98fr4pKze709/c7m5chAi70klRIInG21sCE+nglkkkY9NVLCnENCKU5CIJ4cg8C6VWOJPmVJ2o3t3Yr1oLNiWIwo2X+0kRtLuYEtkH0pb8KZphsNh0zR1XXvvrcOJIRA7+8HROSsYvMyAHXIsEEuYAMXUdsH2fOmlgMx5jSH6sNuOdpYXJ5P1yWgxqTYVLm+kyRhgT+wFWeR8b7I6PAyPjr0GQol6jaYNIWsLF0Me0ZvnE26r0X5RX57Lo0P+wleqd947+/F38GEzanIAMhqGUnX6vM/qj8eXC9koevknMntwPLq2j6WGSvw+5JCPi7175VeFyht7H77yrftLQfmTMns+Oj1faG80KvKdJmzufCX/2//oL1ajXz3+X9t7y/Xbj7PDxx7nVeEbbtfi1uw4MBpzJoQIeedFGmcoKMPsw+rQKoQcO0IbQpSUSWX/iUY24o6os8SRxLnVtmlVAVUJqizJvYbM0tzSklINT4laUIDZIcTAjiUKAQwWVrM4tR5BNdEatfP/7kom2U3PJkkXUUcCUiYW5OCAFwyurlW1Oy492mw85A6UppS2kh4z55k46xRxdlOLuUdlPosS2xDSHJ3Y+aqCaDe7aYOZo3RZJEm8fNVJW6Oc9BhMgMW9aCdyUHuTKtbQpIeFYG/SNi8MgEOIYAaE2KmqaHQ21zp2QAgxSy+YyruClKBEDpxaGgKURIUZRAgSOfUgEiAREhtQjy+JhvWaAB+Vfc9nro4rkehzrhZVpYHV/bRubrCf8OD5X/xp8Su3jqdH+SCfnp6P7nwxjH52djr9ik6O4+VRDD5kCEDbiGcsciJZ+dXls0s/zGITwxq9dQaE23Ou8oJ5Z6rV0K1m4MnOse87+Bi8czUrEBGEQ2+Y+9K5m15yPpOdGSYz3pnLuJaCLsPHTz/aurF7vLNq9OnetQl5jjHoIC+iSpQ6BPQdWpUCtAIVcDXLQiQn8hBHvOyDoQj+STuaDJqyqMIiOOfZcaX1SX760v7u8cNxKzuN9qcyPuXxlMZaDXjZaAVdiGu9NLqugg+q4gCfNwEBaOuwRLakMCrdzMlAer28Pqk1y2O7Es7yupV1s/urv9ccvPb83/7hrfyz/sa4+skno59qeDzb/tpr9XvPVv2XwlMqamkyda2Li4vpetFu7g/fuDW89Qpdb3v0cFw/mMw/9POPJ/P7wyYOn4+rauGXkt361g6PyyDhUVvWvQWCIFs3i0xqwnbbtKFtGo9BMfzm7/7uch9LmTNJo3nue2yoaoQAWZ5rbNP0Cesb2dzngjTMadhVVev/vSZHHEICyq6qb/KKQcLNLCQJiRrVORh3mDXZ+tglGq5EUZBEuao51OVr2ybMtmaf6u1ZO0apqvrMB7GHxcAhWxxfaXORGlV7qEXhbY0jpCISU7cvCXg2GZA9nqpIazNqGATvvNNfq+7+B//+g+Hp7XbyUhy3KnCiAQCELJddkvdtujKGs1EWIEBIkDFElB0A9kS2faOUsaidjwGlqSQdRqkcd2ohghhLAZwESLaCT1OtXTQRyXvFYlnlmWciibGbJdL3vfoQjY8KILQBjsh79+mOKoWMSeb91eQtCgJCxhk0E39zMZoNZ+ejupqVed1vKDATrdfcL+XoaSEZFZj+5O2DzfFZUfYXZ3Hls0rDolkM8opHF2Gu60HlWFCuOJ796Bez9+PZaaa4JU3uWg9Ajxqd1/AhcFvoLMxy4TwH55+cnr+cDzYHVDfRD90hYs4Pbt86hzzkyTi7+SV/b3NX5HQxGpQlgznEsT+Wpazml7tfmx/I1pvLef7T9k8eZzsZj2jBg5b7kQsvzrwlQQK2K5wFbTLOAYEEqDhNDjCkygIkVAEmK2LA5Q4ghRgpInmkiBBzZvFWNnyCxcANEUGHh9pIChAh2v7G1MaxYwEQI8l2bO9PRJyIBp0i4FPFLH3WkUSBnDOIOd2ggToxybGtRDtJOCFKpJQRlHKdbCjsVhWsFvFJRAqJLciDhJ0DGIIo0rSNRDFMCGxiOVGhzkRVoUTOpcPBcLfuzdLVZUDqyQlqulxDjqxA25GQHjvrRp1jx2kMT+lVafhWiCg5RwQ4sAQxHqKKOmZmiiASJgmRFKpOOVJnDZbMhPgKbiMjqRLWJMTM6suieHb4frtqfE7WeTVti2UTSXpw0pCE2rkeUwvGT+v6t8u8N70IJw/Hn92Kxd2qHZGo7r/UHp9Wsv6mz/9jaBaAB7PPEBeMfnPu9zdHrqHqaIVe7A3yehI2vO4v/SoPoRj2eS8PDbNvHI3G014ZdMzU5BQaFo0U+xvs++4k4znvn8r4CHtnunXOW/E0ZqusydfHZw95TUde69fvvvblN0lE1lX0PhPXCHl2YSE6UF2EbO3lIiAHKlVP5KEEqgpC8HHn9aPZ8SivivEi86xc1IGf8nXim89bFWxf6nBOm1PdmWvJ80amgjmo5lBFauADiaxZPS9iLDyVw/XW9ubdzyw++kHxbCHF2p/LvIdeXgDr8tZnBn//vz36s+/rD75TPvexHN382j9qaipW2bK+n7d19cffnf2v/z7zrvkb34rPtVFmL1yD2r54WYYpNUxN34Vsd5DvDG9uTsp9v78td4fhiJ4sxk/D7GHlnymO67zsMfdYhqimPKS8HLWLOjp1G9lkQo9n09FgyxfDNc994SHDgHIN37CPkmci2rIECsQFs/e8bkLuWYIQQUhVNYh0bkvJtceeAUfpP3QwUer0kRQMqhBOR7ZaALil/qqGNtg2F1ANArv72ZwxmIBoJ49ZN6E7P1SEGKJgpc4ujzo6h40LCTFWdI6LVxtQSDfvpiPKiC0xRvvGkZNNTwxi6kh0gwCUBI5Z2feAKFpLPa43X/Z7H20dvzM83J/lcH1qoxBBOSAExJ56088mr0dyEdEW3RolHRJq9DYxDnkaUIxvw2RVmJJQ0QwDrrwFUpW+YlBZhy4kUJK0H1cRAWmMIgGthBBFNZi9AwDvs+7YS3Q6Tgc7FOK8I9UAMz0mgQqBo0SCAxxz07Tk2JyDFPDgSFJz2KkHZV0thquLsr5W5chJ1w0VeWyryf2PeuMbTZCgYT7co6MzcJYREMgXGyuKS0ymRZCAtumvNLi8PKrz03o99y/JeozzqV7mAFpxBWdRF5BlLtUaQcQT5yOfXT5+fklbo3LHHTvKHUHaBU7G148mO/tFfxSPRsN7/WvDYsmLc6KNFd25cTLGIpQ//KjeyBef2zku6qkfkxxs0DDMw+bC9yst0BAC8rzHfW2bPEpNFHuOJfV8LDHYnCSi0rQBqkwhiEnJM08iEiGUPB7sxk5AtQOiIxeZAIsM8xFRDZFNWHSXlEWq8OxU1FwjjP4IM0oDiyg7iyWwPXLaRZhNdXIEJVg7HBgEeJAXBFFhYXYsRr2OXVet0qHPliji2CVan1VfImaEaDgwiGldr51jcpY4bKQqhoNngqjzrDBbMFz1z0ACi2wwFlGz/YLjEKLrusOEJ9n7l06cpZRoh5wo48ZKTE28acCiBZNaRioHhIQcizpPEgM587ERhheFiuberzV4mEOKz6LZn8CJaTHtFdLJlBR8MUAMTPRqhEwJTx49uMlGbaEWwSsLQ6N4X4SikVWRZVRVwj1+CjnNqWAJj5+Uv/q6zkMxKmZF1n/j87N3/rNv1qVmv079/xRXrH3EwCwSFmXRr2andaVBZO/mwbQ6jj15dVjkS6pJdGfzLA89X3mNAdJq3/XmG+WSVCgqqQc78jxtdo958xzjc4ymPDnH1uqC+BLRRR0iG5fohSILJ6c/57988JUvvD4ZD2fLRpGrd4F781ERCq85OLB4Fh9sMjOxGgVGU/jl+HOrZnK+PNzskWj0nM8byXCT5eazekFy7SLfXMdiqls6pThjt4BWCItIS6IVWDTPNEhNbuj/3j/1meYlLep6fRI81TLcD7Pp5H/7T+qNyeJf/ncbX3/j+fcejfd/bdp7snjn3sbuFx7/mz+5/at/Y3F62vvg8dnH/91YuRfXize+crHIs7DUvMdzkLI04E0JEi9nJ8PtcRbLul5Uq+MRXQSc1+F0gOeyzOIyFDEPiwVFkpjHtdy5/pXpyfHetb0nJ0/8sDwarDcc5nV9kTd9X0VeDHf8YSxmflhLsUKxQi8uBTVkHdGQb2KoSZrG4BzytssVMyJXBItYYJs66SqcO2n0uw6QAGg0oofRGQDz44FoUOrs46znFFWB5swSuuIjlhnOTJysnKz5tl0yE8z3gK6G7qQ6hNFQrzT5XRnukOBuVYVuoauIwaZQOLJNKicFZ+zOkrSLTcszx4B3FJQ8IFktl1+o9x63p9Nsfq93/qWmPHfcC9qKVU+JMELKlUpXbeYQJpVkka1Q71yM0Xzwo1oAmoDJMdufO5dZ86AKOIUoEaLN1CJqSYxk/FgC2LFDF7MjgMSoUQlo2uCcmfunAHMRYXZG8MKn2g0iMDn7sTNAiYwA7RXiUmRb0zTGoRM12g0JwOqVQ9n29hf5B4Pq2WYzOQsScoZGzXl6Orq8qDfGw4Yf5nRjNuvPHiOUWjFNORy1jeRPrx3M1zxDLy8EYVn66zOhJ2HcnOV4OuUz18xqAGWzGfJ1rEPsoagXbjLZuv365cNH1fTJFujRs4v8RjEq+nK6DaBchOVQLm+u6bWbx/TGdOf5OJzVPNIK2NHet97wO8NHza053/rri6MlD7++/SPczujVweP8pUNsn8r1mWzQZevWmVQiobYORsULgrGBjKZEojEEu81CjE0Tm7Zl5oydz1yEkqgjthkLane1MKAgZ8BJkjEhELOKhUrZrhNEDizp7wHDRcDaqcrYM4ONtq9Xpe2qM7ZGjQWglDitkkVWz0FjiI33HqosmjOvbeFs9b5T4jKxJxaNEqNtbh2xAjFJ6pSZvfetGWcyhxjBnMytIBrh2Po3AKxG0pTOLLgLWSCQxGh7a595EQvd7KjXysbr1+7hNws8MoqIJqjeLg5gTC6EGDwMYFJ2LkhkxxJsxNc2tDnnIgLPcF4VrAzmoJKZ3MCeNTJVtEZKln9K2pmTKUFB0YuTwNKqCy5WTUH5s0ePTxb1Xjk4a/MJbYzHl1JFXhDvcX1cc8HwIqEuB4xNCqPmw9HwrbxoisrvF4t868mTcHj/nerxcqPhUPNs0V7b3P+ts+WftWfiyAcIlky+GPncxZOT1eLwoil1p8her4rF8QKBmePsYDcfjsK8t0J/k7cqrTbiRS+sFQiQ3BeBikfizvzmPI4uMH4eJ/N25GbqHNGY3QaQVWOZl3U9KoKvq+c/es8f7N+88xlIHgVBe2MaLPKN+c5otQZ5cMZSKJaAhwAIoFD4v3rMG7SXO5wj5txbVAFl+fr2l0+LG5frY9D4LGyvJMcs87Mas1zmLAvxVY/XbWzZh8tFWHgOfmvPbY6Wjw5ds+ztb639weitb7svv/74r95zej1ctIu531lsD9m1p5e7/80/PPzT744+eNT/6OniR//Ppo19CeqzjJl9Ps933SwwMggCK4sgF1E454X1cnW+vLgYbjfsuY0aWbJCehirtk0QF1C3fv3s0fXXvrBatrev320evDweXx+98vL9D/76oq12vvg5v99/jWXw5H0/qOfD3XqGBZUVNheysdSSl8BCsIY2qi2TGSNKaENN3DBHggAhbU9FOSUKQWw93IX/WfG4mjKJlQQMjhKVAhxLVHYODGJ2GTVtywpVeGYHFyQKILANro0FNqJxCFEodIbvIFXnIIwEzlnZcCxQjiKszN7iSmzmjDGIWkRWEgGbFSDBgl9IVTWKagCnmJQYJPFdFDBjBO8SYMZeQMGrD9KKNJwXdfj8+e23dz55b/j81nTUD5s111Fqdn2OagQyWEBhwr8lWlqaaDo+hbrkmNRFW1MdREIQgESdSmvNQJ77EIL3HgALAoLCCTQ2kT0BcM5HCIl1PAqFAJJeEM6REa2tskLVeU7YhMLIptCkmUq+RB2ondg6IhAhQZRABGGGKBORKDOx81HXFFRc3J9v3J+cn/bCxWC1PUPwWVCMjqdwjmYXXoKwa977L9ewfZkDz8DKyg2v/GLOl+Obj4c3ENQjaF0Mai/P6uak9s+dPPN+BgBSfaJS5b/zW2Fzs/6D//7WG2/ufOMrzw5vz++9Sw8+9Gcn09mT4UFJUDotm4s+D9Dzvir5nb0bkC/dmDx5efyoHOXl7u2mj6NwJ9z5tl/encvk/fYRlh/0kVH42rH/leN646m7qU+Un6I3z0Jb59wIYlQBgkqw7X5QbUVjiHnu66oKojHEKMETQ6iNsW2X3ns48oRMTDhLimj6vbSeBale+atEeAeBhsDElPs2RHNiylwW1MgTRuZnqDpAheAt9TrY4BukRVrFcNoDCZxHG6MqiLklMea08z4qSBlKTdCILtEhLWINLJKQxm1NdH22Dhu2tVbVJgSJClCIwWj8KXEMECRH+Rglcx2Z4SqCTIiBwOmeEwndOkjAHC1wIoIBcmSJiewZISppDKoWV0okJKAUpkDE0q2QrRGPRIjKSHmdzqDnGCIiKyGAWYhZNDjvQ4h0ZQ5HEGZjRye1EljVCUAQp1ElBo1Clxw2ea1SN2GgpeTPHzwNbjSTy5EOZ1T2s6I/rmWNnDP4KFWQDfExx1riduSy92RSf2bIflPvffjo8J0fLJ7yGjeBA9SUrUnEz6fP9rH5LRq9HU6mtGKNRR8l1k3Ra1G3a78H9xulD7O1BulDmoic4vG1vJHtNWdzaTa5KjHhvMnLflu1mUcL9yDL5mG0dBvncbBcl3SiTE62FJsywqIMi7Ff7O/xevZk2FxsYqUf/0I2T167+Zl5FVvtrXS0QH/Im1VvNPeTuszjNGimYOYIqQMC/FO67lfVuNzW9WWeF/1J+eUvfHX98o2f3H/y9GhxO95uGrexaP1c18eeK/As0qxtK8mrQL6cv3an3Mo3Dm6e/PTHzR/98/Kz36h9nEyun8vj6gLFE79/8/Pnv3i2uVM24284v3H6H/5o8PFD3H1z88HD6X/6qw3vMs+ZbzjESCT1crF/a00RqyZGzXwB1II8L4vIMUaLiqPQhunF7MauG5VZWecuINQrqYXgVSTv9ZePPjk5n02++ptVxEuv/8aHP/03X/6nf++bv/OrH3xw34+wd3f/8R/9wWAi7e3yPLgpepe0OcfGggZ120OtqAkr0BpsNAJ7DsBJwQIme4LU8q0dVEMI9lSg869JQFUyn0K35SJiZzzbTnoE0zAy4Jk16Ruv1osWIKmec0DZOQlmN6QiwWqGqoSYvBPBLA50lUDA5JgljYoSQ6SOuSRmuZiML4wTbObUBvOKJHjXHBU1mXiQiUccs7MSrKpszBMGA41I7XG3Lj9e9c/7i3fL599cjBsIIdeYbG2vWN8G62oCEgEGgkI1SnKN997FoAS2uRaqxBxF29Ays2MnZChEInxaJ6FADLbT6jQYIoEASUpOURIkJSkrbN4lIEbpXFIAWy1qx/BKIw9e1IYrC0l0fkFMHZpgCmoSgKM6doGx1FAGmiyK493mcHu9Pe2pc/1798rnU/U5LZfUTG/vjHNpV2WVBQlgXJReoU0TdqCF0KYHUYNcqjYT5IuMTwNf5Hy+CosLAHXhire+5q9tC/Jmo1+2ix/c//5nxwev/s7vHH9/p/jJ2z+bHZ6Uw/2dm004x3pb2mF81MzqxXSWHU5e2ZP8DoZ3d17aOx+cvVefXufni8v5O9+rXttu7r75o+YHw3wiw28t5G4zF52Cj4Bjly2KwJdNrNhHiqKtMiM0bYgtiNum9Z6bplmt6mBTGSgokk0ptAmBBWCBOGZYsAGZd41jgFTNYywSkcl7tUs6sp0FMamQaGSL3jVFmqYB2allsqYPzu4i0W7Bn/jTlk9v7874zHDMjonMuiIFiapRLJ13Kt3iqSMlJApCArgIRAjBOnG7f5xZ5qkyO72yFScab47n83mrbSTmK3scAjGlkGWiDoVOImMD6olYRMizrXGdd7D3alfRR43oHEvgXRZfjMPJctYaEYVSwrZYyZA2wHmYvbnZh9nuKYi1wkTd46GwodcunBKAQMgBg6NEEJzTUIcsZzScB14czy+ezfhGXkl/jnIu5ZBH+bByNUNUgsgAaDnUQgE6AUptN6LfLuTZB/9/qv79Sa4rvw8EP9/vOffcmzezsrIeKAAFEARBEGSDaDabzWY/1Gq1pJYsWTPWwx7PrNezs+GYjZiI/R/2p/0HdtexP8xu7HrC3gjvjGK0Y8u2xpJbcqvVD4rNZpNsPkC8H4VCoR5ZWZk3b557zve7P5yTxTaC0YFGAVVZWeee7+Pzmj32jC22L3RYR1tJJ7zoeG7Fm8lkcs7a7xp7B/ae7wLms8CFXetLe73qvyQVZnEm0cJ58QyNFFnidGW1HawPMDuRaQ8npSzkpBd6ppwujqvRg0gLHk5iQQ3TvtCU9KzyiAd6NMJ4xLPaP7s8Ort9/bL1hwM/7tf2yBw/+tEff+mNr3c82G+PB3Z1IPOxzkh9qNbDes8wSQzsC+2MBrHy0GK4uecb06+Lrv+rr3+jLft/9oN7H/z0L+1Cbnb99mh6ztOvjFs7oTDugqwxx+rr3xh/+NFwe7jxrW8e3Xo/PH0Q9h6e+41vHftnwRfjt/+U7302uvH7hx99Uq8O5aNbcVSZR8+O/+k/2zg8KBnykx+hpBULcZ0N86kNli3HBkyTF88tFkc9jbEoSFprWVBKJ5J7tDSbUFHwk937w6FfrxqETr04ZxOLJ4gvpmPZu7v77NGlb/+XxbmL1y7+V7d/8OeDezzhcfXNVxc8FLcvg/W23Dya2taunXS9OdVTDNBAWyJPCOAOpmOKZAu2hSMSFZFoFbnSZ3NzIoVaa61hazi72pzCM0umMUMtWRCHHBJJDDLWdiFAIBAjatikXnVpSJtUwEvVDci5om0X8JAc05lrT1o5ceZ5LgU6yDsgkexDmXQ1CaJOA3rmZ7JRRBK1xobTKFOFprTurAEhypkE+ZdhImYrEAOJImA2MBq9oTpWr7abP3DtrXp8OT7bXqw3JhCBl+QQxVKGmQk5DI2qEBEisoZAHGMXfAdiItZsSS1RNCbryqT7YsQgKcIF0KhL3IwZjBgiGCFEqOQLJUPKhOyHjTSyJsScAcMW4CUlNq/HVZdtA38e45g0YKe7TEFe9TOBmBKhnQjC6XbjQsFcPDce7A/3JmU3XTdndtvFvc/c6pnYIYR28cnN+s4OjMbYOVgXWhlXhqtZH7rnbaFyjIQ86oJaLzYU2KcwDrw4kQvnAFTf+pZbHc33dlbXyll/8xPb3Lx3uHllOHv0k/DOT89KfHkwPK5k3DystEJZxijVeHCGHYVBM3Ht1nM7N9YXs8mHjx/58urKs8v8yZOLn0X/aFzcn07uuQkuVQ838Zh5D9J43rNmn08OJ6hmzEGkldgCXdctVDqJMcQAwnTaMCP5NWYx2PItTaANabIaigDYcEpdJlAIIZGIMkCTfaBTE8ggChLTLhhAjOkAAsoCkSwbIk2eiTmCSyWFXUq2oz6laCR2MeWUXJMpiWnaY455qZUeFiaQsSaEgNTBSkwubMm9LWnP8wMpSsxdCEnHb4zRdGhEDRMRqeh0Og0xEJt8gtK9kfvdhJoYSqIuk9Mec/8HTpi0QiBA0IwNKUsUUcUpi4tYcqzJ58v6018GpMSJ7p34p8tIY6uqMfu2gxlRhNksS/iSfb18ojg9BSnoBZKCylmgsTNGZEGxCVXsj/d2w9TXi3ruVqcymdCoJ42zWN/c76InIvagDrpQBKWhom9kKLyKA9k4Kc5Oq+f3TtYntsKksYtKvOE5TIN2MBi3h2Vob3D9Smnb6XQylcL6VWet06ad+iOynQHE+IDAFAwFhNa1TecHfXYrXJ0pvUjlOuEVE+/D7rYzboAG2giNibc59MNAjjbMZEUPR2a6xWN/847fo9rNVKQLRTg4qDp/7/DR9a++vr7xwl47m+l0hQasc4N46EbNaNWKRVSagwZkhSWMp+7M1vmz59pp+Ov/+W+COJ02I5Ql3OJwsXg2f6I0Gb249ui+ldXR3/tvP/vjv3jh6o29R7ea/X0zDXowIWKVcPiT9+wbr9e2dOcudXceN+++i/HRdDyrinmYxSF6HbyrJIYqWmF0AVF8bOFL1AFt6Dx/5VuHJcp2AZZEqAsoIRI7YWEJQkKxjeRpEUBV/2B6WC3GK5v99U0+8TOpgl3hOISOih6qRdvc+/7/eOnXf3fv5OagDoPJkR8s7KWN8uXes7fr1W//w5ty9nHbju3mHjbGujZb1HoMTIEG3DB5aAdDCgoqnq2wIWscMn4bQJxt/dM2l0klLTBBxDkXIU2NmTVColqQM5bBQBQQu8IliEYk6eiFmI1hgGJymuPTDMFkgKxMCDGKaBdC6uUpTXBMuuQDJ7U9QGxYU2QcTu8+XXKQT5/E7MKDZY3MHrUAsQFnzzxeFuDTLAcQhCHpJmMwU6ligLawV7uLu7PDOyuTn/X2Lsp6FUlAaapeWngtGaiJVaXJpscGCaqA5lkBRKLQmC5rTq0HgckaASDETMQ25nV8isTRlEVDbKxlicLGpUFVQIrkRs9QZaa0l+PUXVh7+i4JlmOWfs47TZ7PqdOhRNRasqSzYSbAxpySc9IdFQAyVArPGWfmg34zmY3oqDe/8NGtKRQdI4opBtMfvt1Z2+vVPkaJ3rrSSyOxLp6xqtfKaBFjJ8bABOPbEGDtpJCwL298tX7jGwCMyONbd9WGte3KV2uPuxNMcfvZ01cXRtrFkY9nzl+RwebR/lOEw6oAhYkcbuh8zYirZQN2gPeN3r6DhS3aZtK838d6u6P2ubX57rNq1+PcJXo86o4Ch8KNa16g3X9C7R6ZJmgTeUFxTnGhKq2PQFRi7wMxdSEYaxOTPtMMlZKTBC9pt0t2u4YQhNkQF6ULnYdCoNZaVaF0FPOpJQIbQ1GUSMAcMi9RYrKwSFoBAeWdcCRiZpPCCTVrhIiZjbExMQvytJjm8CUonMlNQqCisEQcJTjrgkjqYtPEe0pLRo4uAifvaOTlCpEmCYAEMSZbkQBI+rfsIK0gJGdrqGrSRy8f0M/tenLPpwImjQmNkhDEMGfTkJTbCFqamOc0qNSPLDmcSzEVACLlzIlK+jpZRnyKqE0+1Mnmi+jUcg9LpeLn3T4SxzS5dUZW4VTQtZOFwnMZ7OTJoZxEmeKorKxZ5zhj9hKsZ2xeOEQTpCXpxHiKAvQVNXw12MParl/bj6P9mZliEI7ZTaxMrDnxEhbi2bbM3kdZjK04FtF2U70IdcbNpvvMleUV22jgDrFI/boJGubTarX0s9KahRQ8L7gLbaF2pnyXF2icXUAWkKmoVbZsK1tbqShUXbNi5hWaofM82acmdGOZt2J7jk0PjXzw52+/+V333JlzT2aeYxMtIAWgqHtNcDwDKqBiK8O4efFy4zZ3nZSo/PbW6mR8gv3pdMrzdRGhGZ2ptl7+u//o5u6fjGx1QOj23pXJ1229hfZZuVqZ7Yt133TBbl6/EuCn9w+0VxSjorv5Q+uMCZUfrhe68F1DhmPnowmskWXRFYY8Ktv56Y5nt/E7f/dutSlP7qGqPaSIwtYFSAVaAOoDApuEMQRF0VsEkqKexdndp494qNuDvtasPV3ZXjn71lef/fjfjHxZy9Hef/yXvOnDiGdnet2gqkZh75j8uW8/3rjx8FlzVJ3fjxtj2jwMA52AJqBjpRlTA/LMkQ17Y3QZDWszLVcgeeFqNVuvpeWQ8rJLz3f6Mk3AgKJEBpFZftwiStqJpudp6aOU4Mjc0FPykV4ecRSFZWYrwXchXQBRRESNTT4ABAipSeRQVpUoy7smK6NEREXML3mF5Gk4lw3C6ZBLTMYYNglvJiJKcVDL2w1EQbOrvVpYkVAYp0RCMPS6f/GB/8WBG39U7rzeXh1LYwqhLgkYkheRJMLo6ZYeDAQkvJnBbEzXBWZmyyLZxscYNtYEVSjnPJcEawkUathCRFgRYQtrmEPwJImenrytQUg2+aJCNr1RSwswFSFjsnHBsjnJziZ5y54qQmqz0lAMkJCavIlL7tewDGZKac4MoLOEEAtTXJgNPxkePj0j5/wR1MbRqNhvWlO3ri2tDUomFjA2UCjqbj59xFKxlkLWukKDRhUWhDhfuPlK0Tvxvv/cyynUJ4Y5USm2jIHLpqFpN21OHn/anZx7ce3iK2t3fj54cnNK7Zmrb8jbfxGak27zopFj6Zh2Vo2a2Kn7+aPquJwzcduaxtpuipMuHDyzpW2cGb72Nf/M2WkL1zFXYdGGdqFCXccKjhBI9L7tRAnqfWC2XeeNscQURQ3bZOeYpqbEVwLBsonCOTQ4yQkUEUJdF2IGaxIGQSY/UOmkmuQKlwY2Ups9QZWFdEmcJtEliyLVWhYRMkYk6YTTVjn7W6Vu1vJp6kOOC+PM7kUIkVmYuWnbLMgJgZhTirH+khowk/FT65zVUZrTTij1eURESlq4QlVPn16FCJv0PbGKJPuR1J5w4n6m1o4iCZNBTDIIhgGyUVewxoiCIvIbJ4FJlG1e+vyybj5h10A2rMloc1oF5C+eLo7Trd5yQYb0PTNxCoVkZiWSpBVTARJpvBOxIi24grfdZHH4cN+ULEeBC3MwGpb2jBON7BZiW7G9atqrwLEpEIhlitVprAOP9rG6z9Ueto7K7cVsBQfeTEWmLc9Ep9a2TBPPJK0Rlta3c+JuAuUgFYaGFfBA5xFtWyF6qzaoRDKOB9x2XMxhWVwIfbf6d/5o78//1zPOTNSZ/UlsJXo4cWEUYowKRQyGvSPhMLNh4tzcibd2xTianExVKGhkw2z57T/9/ktfv3H19dfuHo4XnV13VSe2kf60PoMeTJ+0gb24veqd/+bl+eHe0U0/uXZl69GTinmwXhUwpd7zYUO2TqbTvWf13/01BJ2//c6ghh1wNTprH33c/Pyn/ODWyXRq924fHe+4Ky/warH60pmduz3HC8s9qRbF8V4kTwQrJlLkxACzzkgLiZPW8+UXtr77e43rP33nR0Nng8yMMQoXJRRcg8QGkC186LCARsBjHotaXRsLob7wcHeyY8OzzfVLYWGbptt445Xy/Nr0o3cWD+8XIK09D5wv51pGb3niw9NWHu7LAW9P/eiYBmMZyFgxJpqApoQTpQWxJwMmDmzUWuQKlc4+W9YgmnKQWEEqSDOj5NTrTPWlU8tnkF1qC3JEIJOhjIaqajLVoWVFTDGhzJTIU0C2zWJmNsHIckIl7jqfqxkkImlmk31OWlD7pWIHp1kM+WZQzZA1GeS9dFy2DUycKohB2pcnpnR+gXnUhqpTDlFY0DHl7TWzIi44bmH9ZX/mI/vwA96/zGdHtt/GEE3M9hiy9IUXIHlPhpBuLSbDpCoSYmBD2XUfbJaueEQcQsjRrsjx4imeJQRNPwZmtswKuMJxkogkHcYpAQaqGjVK2h7nJoCZjUkfy0ntvLxymIiJifMKNd/pULWJ3UUGjJRNA2KTV9pgJhYNAmONjcDF6ehWO1mMcP+1C194Z6eo6okatKHgQfSgqk/OAUY8fL0K33AApBNEK0rSQVRhmapFkLquDQ/sk8P5xkUA3WFz9oUXhoPy5OmzeTgTfdVbecOtnD+extkIB699qWz2v3T9pfD2fyh8h/WrX/jtP7z5V/9hJE2D4J6sbBzOBvtH3sUi9ESJTXuMk5o2yHEcofrON7pvPQ9/Yoo+ddLs7lku/aGH3xA362atURKwoFZpiVFVbrFoq7JWQMWkFk41pE1yyrpK9camdOzUI+aBGCISQqAUnWutqCyfprT/56wEVjUEGI6JeZ4OJ6fTrblwLTlH6fBmJbykhwtRJPok3FNOlpin7SozmHOQiUJzIHEQUcOGmFVikhEmPAVMZPRzmoXm4qUhEpPmSqc4zbZUUslL5dQL5BTAJeSUXy7xf1IwEwYiMb1SBmm2BuCgkZlMVE6iAJBQ1r0ETVoBMGsSQyfONpDjPzmTVBJeRgikOajYJNV9SklKjhq6tOFkMsh7O5NgbU68lLTNQBelUA4MCKIJbrx7OH5yVF1wchTVqKLYG211gobrE6qOYz2y3gZfGoG0rNqgN0XNcbDLw9soj+TcvF2Tfe8WKzr1duyptdIoeZBtQ2iZggOLIeJYRPLwwmNB5SJ5MyHUvABHJ4WzEtrFwh57P+z7Udlxef53f/9nf/P9kb28eFqMr17/wvNX3735P81mcGq0FMMcEa2xUFjSCr4nfuBQy8y2ZrZ/ImMYz0YgLCIkhotVd/fHHz3defTGd75RYti2z87YsgtHHfemq8PFuLOltW7Q7/YPhvP2rVeG4YfT6U57ZZV2WlnUUjSdrhieVZdJ2ve/P/iN/6y79ai6/U5duckP/rV9cOT8JPzgP1jfWguxtr7yii+l27+7+973Bg8fwZVBZprs+ohhsQhsDIgr6bxfTKEB2xdHv/rr9vkX5ofT3U8/rkipjKYTS3XybQHUy6IydQgKC+0UgSSoVxY78Dqbx6aRQWFHLZ2M/d7Fy1d8wc3xeDi6uPHiFd80i/CsbZ+Ys4P+unz26fet1Ctb17s3L4+Ltd2wNZFh8FU8ZjqOOhZMWE9ADWHO7Nk47wpL5NNjQ6TGUDI0FkmS289JHalwprPNzGSW5CQyyQSXmROkwpYVKhIlObHnlvn0Wk+1nBMNi23S0qdOnUQihVSh0yzHAGIM6cBrWt0ibcIIApM/P4sKoiyBm6zUy6rejKJFAAmaQt6ip6/BSzYqlGQpeM7MI4YJiBxEDCnIBhbSgMiMCc1fD889CONj1/y0e/Cb/EWIz0pjFUBT2sRye5cMGFShcZn0d3rvJJJXthXiZLCQzIRyio1mQgxZm4xQCFCQEFFhneFCU+Z4kk7lWwyqRkQkhiAiEgBNiZFLkk4KulUsreUpA/rLpUb6QiRCdunDl6wAobBZsGZCZIvgCpEI6izcOGweYXeIk1fPT97bXbu3K1WflU2AmF5opKicwgrgHrVkykAGZGEkAFoYKtgYJpKguqi1wqiNx2UvUd91fDT/xb3u/qFtX/0vmNnJNCymZlU6iBleOOzNuzFfpK1zcq+mVf/hznM7J65tA8eidWJOqKhEnFgfQudQAoN4behXm+JrV4v//IuxN63qAj0zv7WrQ8Fx0e7sy7Syfk1QqbaqYLFlUakKM2x/AJBoNIZit4AxIsVypwvL1lomRtd2S3EQmFhVg0RRKXuVinrvJWV8FRagz83WoUScFeEMFnCUpI4LRKppICbh7JecjrGIpCYuMd0NEQwnaf2yfuPUTFxEKBuA5+MVJSbXLsoBWSzJVV/zJE6Rl4KgTCxMyoIuBGNZRZlMcuAiUIyBiXOGpkaNyyDOrDRI2xdeZjQoIZveZQIzs8So4JRIqrmvRrTGxxTXCIrKIEtGsh1OvmOIlHL2dyIW5KU0G874twUkYnniE9MlXwfIcTB6yj6ETTY7nLoKNYIAZShFeBEYYYGrdeXxoz3M1DZGmYITZfVsj0bb4+7wbH+96Q732mNntMcAeyc4QTUV16fBQ6l2Zdi1fRzOcRj4gOOs06nYCdu5oSAUFt513DUzFaDVXuGks8FYsGhgal1gdSzSNh1Xh6XvrRbf+fWTx5+W21fXX3/503/xzzYmZ5+7+g/0ppe28s0wfDb/2iu/9c73/uPcdVRqCCHd6fDd5np/1FU09jY0lQQ0QMNVw2jgfTQgCREFQxhex+3+reojd/nw0sWv3Js8HXHZYGW2OuIBY0rWTp6tYfzuB4+r8Nx3Xt/6iw93xs+KsxtuNsN+x7Luh/vdqi3j3q3mn/9fMfaVcCgZOztWNYh1XHWlgS4Anv7oL/z0sJCmZ0NBvTnNKy0Ck9rShijRd2ERgwqTDDfcpRcGb32lGm7Onu7u/st/sfmF63ud71ciXRRTLGRRo1RygWJhaKFe50xMFEhaoIUuqKmKivvHPDNYEPoTrNv6+N7kfev7lSlH62uT8Zgr7lfnh6PnZRPnXqHjl+q73q3Y3th3C3aNuHZe8YFwAxqTTKBToCVaEAUGdZBWojB3xMKsxCIQRn4gkB4UIk1kSc2GssnKmLJ7Iac/yftdNgClTFlTFKwx3QtZdar5VKfqYw0lPqVC2BhIzlGxIJGIALFagogQAocYEIUEIcU0CZIIVWPU5UY1SMrsSxVGOMGouftWAowxp5JB0uU8klHlZGStp5Hd+UFFYFCAIELIsDKgrMIttc4P1b0+u/DX7tad8tkL7YMr2J5oK7JkehIlQ9q0yosiKpFOt+6fU2SANAmleQIIIVi2koWglHw9NXPPJYpYZsPWGDaFJbAxHNKeOe0hsXyXFZYgZBGCwEqyHRMBkyED8Oc8k9yzaEwiGTLLvoHBbMHCnO1xiQkm+60kAxNlG+yCW6DQEnLw9NLu4cHz682mmz637u8yt1bAno1EsrZEK+QMowgOcMRMwSYDssiOxQAmR9H6MlblZL3XPSwYwE/iynQmXlBvbtr2SBrMozKVtGgF3Daz9X7ViL954w/a/qUv3/mP5c6jljYbx1WUWJdMG1gw2S52szoaz4X7zlcnb20Pv7QVvmDXB+NB0QxLnhxOmm3a5/M8ocMfPLq4dQWgdr9maiO3yoHg2ChB2SbhuwGCLSsoqw2UjKkkWGPTQhiuEBFdwpXpKKZ5i5D6WCZijULE4M8jJY21kvzZRYOKJRJSCBlVBgmDcnitMhvDnPT0bEwyZOx8R4YYkChJrpAIwFHEGuMKF0JIQ2k6mkmlboiI7TKkm5ar53xOY9aap00QsniXEnhMKmBlMSKiiTKSvucuhsRY0izzZ+Ik1mdK0Y5JykhImUhLbmeyHqPEk0jGNVAlJZt7CVHSTgNi+uysdLp5WNKzQFYQKd1raoHkfxkIAFljYxTDlhgSJdG/TXa+B053Sek3JslGEImR/eMFBGuATiyTxPnu3R1XVu2BtwGmKMQoVKbT9vmvvG5XzN0P314rV0U6J2KtVMCxlhMxZ3m0H7ibWDkJ5cT6GVUzY8eLbkqx4cKT13llO4S42D5ff+1rBQnMdPyTt+39Rx5VCT4ajrhar/b2YrU+/N/9t+O335X33lt//qvli1/b/fiDlXutaepw58Hhp3fXr74Sj1dCHMnhoalGN976zs/f/0sffeWqAAmdWFftHz4GZmcKB3DsUDAHCaaoogQGqSgHhcTFSQdjrHP3P7ot48/Kidl+7bfHk8DiQZGNwogNwVcUxOEnnz24+LT6jRs3Pnrq3729fxLqgLp0Fy5feYne/xHIueilrHwXorHOivEqHCFqOCqThQ3tcd1fYS3bMOsghsEiEuaQ6UQsWNz2ufILX3Jn1tzWtgQZ3/pk/90/NfuPLr/5rb2NVXv7jvZriYHFMFFkBSLHoBwIHrFCIHhQC54DU5q6FQmBXGRYCCqKTFhbeRbak6Y5grUbL27FucDCrgWshJ0Z3T5AO1r3tOptOeHVVkY0g0xgjzjOhSZEE5aJYk5GArgVeJGoWIDRxWhEmEPyF0jmGcImefBnhT6n2xvpgQCAJKWAUM7ozbMXMhJjFMjS29MFFGviSqQxN/m6Jek9JThGNX9iS4QOKJhAhmIXQggMStZSQSOIjLJC2HCabRMiVFhrrIves8HnY51i6RIFA40SMs4Z5XMiKSEZUvLyn0iyoxC1zEAMUZTT/GG7zk/hX8ToZrP2ZHj0bnh4cb7JQgJWRFYJeR+fcnRVSSPUWRu9T7ZTnMmVSe3PAFRFNA2nyJIhDUwwTKqUiNSW2Rg2xjAbSn5gkIIzMJ/XbprylNN1I2KMQBHAyTgQrKyqcdklcN4UEEWQIZPqMpMBKWCULZSXUUiJHW1S3BvHiqK03HFnQZHnpQ1+/fZ05YgPV/nkK1fM7Y905WzojExDZXsRBsZBSrJsnESGOIgRVzhvIheBLCfKOVtrrIo9987Fq+8ctgDc0LoVX3WYd8ckVn3btcEIbGQqjG+7uXHG1ZjPdi5/e3/t6hufvb89/ZjFSOnEWmgTKDCj2jq3YNYXbsy/88K9O//LxddvvFKXr4Z7q3bRe7ofSae9M7uz/V/UL3TVLTt6fjpHPOhxNGJ7hYlAtIaIRJGWCizJaFwjJVMqIthCJKZZitMaAQaK5FNBqlaNiASko5a5drQkMllwII0hQFRZWcSKVepaU7JjhGgXwRSJ0qQ+dK5woRNBYhUBYKMsFLsuOmYLDipMOdSEIUzsg0/ciC4KI38wVeskdshjK+kpTwoJ206lPOPUUGjUaNmoUqqIABnSbLIhqpQzR5Z4c/6YkgKCCFYDEmYOwTNzemysLSV6BkCqohHZMpdBkTON0EjyryHhZDMilEYFQs6GVKjSggODVWIisjEToloCLEvoLBuCaETyrSTioKe3GCEbe+dtmZAhWySILa+uMz4cXUXjyYE/PuGVAkpKpouxO2mrNffK73xDBJ9878du9cxMlYv0LAUX4alq2+nLi2F33PiJryfVfNzatoq+6iatmRF5ZdPYMEOYtiZs/cE/OXz4qBtP2sVYnu7EL1yji1ee/uX3t/7eH9jRlQf/9P/83I1rizaMrl69/+mHW4f3D/ebC9duQMbwjsds3/lo969/1PuV35wfNdbXvvGrF1a+/vVf++D+ewfNXhEsi5nGcsj9TnsLOQnsomHjAIfYxeiCSGAUatUUtlcXC/YBalxRVObB3Zs3j+25N/+AxbSLUBW9yMGWBYfZdOvMoJn7h/t+58cfvHj5+e+8fundnebOgziZzD9Y9LYuXt/86MPO9E2ITiK0oKIWaQUSHJEaRJCNHUozm7HOWTsP7zl4NzQXr1Sbm4MrV7H9Ah8/mx4dNvd2Dv7s3xTT4zLEui67stZXrz17clCVFMKMqeREw4AYRlFQt+iIWNXBM+bQmWitchxANFtfc0EIAkjPSKFQ0s2tQ+ursd+bTPcH5bCVrgh0tC8nk7VHc9MfbS50MBHXYCBzxlS4gZ8IHys1RDPQnBA7oZbVq0aRwPCqBMSoIYbAnFmHbK0gpNzvFNWglHwt2FhO/AXRkIUrUQgJvcGS/0uqYEMxtf1Aptmm4sCJ0auApMXpEi/VZd5mquFMaWFFEin144gSktZQ04aKWUUoo2gMaBTRrksiJ2JIiiqGJmm/LqWTLKA0dmDJe0lBxSIhTwDJK5cBLJI6U8ECVW04lkEbQ1D/5enZg+r4aIAPFo++1D03xkIQLKlEQDhgYYUiICGKijKYrUpSHObZnYD8yrBc8dHyLyg0hw8mymV+N7PTr+box4SjSbIjzsy35JklSY2MlKCULQZENUVX8CmtJkkqlx6iAJnM+kqXOpk0ziR3rMQYI5hIUCosnBQIxHbehgdPykU493B6vLZxcK5+uNV/4TB4NpZLoIjiCE6doFS1Sj2GAxNQB7AVtNXKaBE9ownWmrD4+et/7+P6/Kg5ASAhdHDifdlWnQRxrnYIM4nzEj5wjH4xZxia92w38atb3/v6b13aufjW7APpFtweheFa9dYbTdOuXLq+vxgHYsUzrg/dvb+4uL3+oru1zuOBVKGuZoe/2Bpc3fnw00tXhk2feK/zG2qPeqVGGGHynEzT88qzS9jBaZZgej8lx2DLcumCGDPznA157xmGCUw2xo6gEgMbS5zUr1BlkSiINrBIIRyDtZu+vfTZnelgePfc+eC9ZQuQYyuLmHhEgLDGEELHzDAlTAwBjMJaMrzw3qSfYD5+uYQmdY1I/GVsKGY28n9KaELeBacdiyRSQe7q8hImIkue0lmDcNJn5bgVTTRjztvenAcGQCxbETGGlThKXO7jc3BhdjjnJVODRFijACBOWy6TxQuJ1yaqMaVBaBL0Q3Wpi07fBqVcqYRMWRFNqmzK1ZWTB2BGZsQQFUQcozKZfHWRJeKS2SOaKjy4eTOGA3Tr0kLmCxrI5tqlC1959fH7n+3fve2GJabEDsLKlgJXsRCaB56a50yxOPHVxMWxiBSDmeueHhatQJ3IbBqOxWr1/BUsjsY/+qvq3NZC2kvfePPjbmf98mvVlWuzOABcO9sTDnTlBWn23bnt4o0vSHgy3719cP+d6tor69M7kz/+f6x1gS5ebupamv2SWWk0ORoXQ/eVL//KTnjw2fSj+WRab1VBylkszo7OhLaZt5PhiNHKZDo9s7k5OZrqPBHqOxGTRgSRKEHrnpstmtu/eH/ttUu1Kby0rGSL0vXntV/4Gxe3buvuzty+88l9rp6trW29cX3b78bppMLhgp0txbjOdo2qodi3/liqIH7uVT3IL7wn4ljWvq7Lc5v9l69trg0iJA5Ww87T6Yfv48O37V4D3xbTSZ9auB5qt5jOyldeXaxs6sPHtnKVwAtSFIk1tihst1ic2Tqzvz9l6uB70orOgSnMCksBNXo4WBVSYVMxmFiDKqhXL9xAoeHYH2rhjnQwNaNFdW7M+55WwetH0sxlICeCOXQKN6cwgc4UcyERUAME4kAUoD7GEEWMEWsEGhKBCAAHHyGkCFEYCBKJExsLp9REw6zEWQaQ5L2ntGcGFFFOAUteUoMTJpRzg3C68c5sXCTV3fLeWmJUAmsMREKURJ9WgDjtotKiHCqwlpmt7zxoOa4BEEGKMNWEcC3h3WU9Syia6DKqLQVLpOplOMn/M38qmeSArGinGoS9dKPgXpqu/2L98JPe3vk4WG2qOVEkGImdUe7I54QcZsD7kJFay9nOL13jurQewikNMxkN5ZuM8hY6rRfyraVIuux8KWU22tLlJHU0xKCgDIpLZnP6d9kV8fSWVQUyKqBMAkrOSAyjykoplQogJiUNSVBmBQFEDGM7WFf7/R03E8XWCx9M77xybtIrjt66du5Pd6r+qF2EKNZWFXociiBOyBEqlUJRwLtgaqi4pmqsBrFw1Oyxezg4GAwGYj2AyM50MS5sa1qwoKUoTuF5EGQuphj0Vurgu+DbJmi1wLCyN1+5fsjX/uittSf//J+d/+KXcOOVkycPnlLb+K6qisPpAzvyw/YX1Xu7W9dfpHk1OWghU9rUYbF3tV8/IXd4aYhxrFgkElmoxuXxXh4esoZDlJh4BNmAIq2MBGmUDDGCiBhd1xGRtUXyg0niLxUVRKTwIE6PG4dUYoCWFRAWDNvutZ+9GxazIe+sNtP3L77YKnOcq7WMSEQiJBEFFWAW9QS2zMocotjk9cGwhrPKJlOa81MLQeQU+5Nq5vJ4paYrWwJwZtmrikrmTmlyzDiNitB0K6d/KVlBvmSk/SelPD/+BkmWS7CcJEwMItFuCegu8ZzMPkmWq0ocSYAUgJGOb3p1nNZvnBOyhdimT5KxoSVupiIRkltzDcwsCpHIKU5JKfFNcxyyGlVmsFn6VpIxEpnYttC6Kg7GR2azNjsG0taD9dHzl4YXNkLV3f7XP/HtxPUKmYv0SCyMtS0HloVxRbfgS7HoLWbHDZcztLO2ntezyYn62jiILqRP9bd/L6Cthlvzn/6QNbiKQ2j33r+pn92yV7+2f/Pe2S9cffTJh5eeu2xfeaU+d3b3e3/W3rLrZy/t/dW/OwOrh+N4+2fWUEU+GkwvrYdw4BA7wKivUPtOJ+Nm/eK5r72ytW93H0xutu0hqsHRyW4h2rN1Gw6ZrKn4eDoRKDnNWbKhk6hLJg3apr1w7eIjHbz94x8NbvznLA4GNvrpDLE4Dg/D0dXtczIOj09i0xU3H52YvccD3nrx8N7o3nuNDW7qm4bhOTZznTE8+QBe3yy2Nsv1GgPjNs/J1ipDFnc/jrOjvYeP6MHtHi14dT224bjn9gb16rXXz3/6IT26R3DKDDTVjS8fTg6dtdaZrkWS7ZjCQSWGDsStb5hFEWP0WFizYGmF58wFddIZ5slgQyiRXKSDBDKF+qLregVR0bErJr6axMrL6ECwd0hnLo4OnOtPjUwjN+CW2za6YLEQhIXynBCIAiAiXiWAglJQSdb8nbGsEAaFmNlXBE0oESQ/M8kog5OOiTPBIT3PaeGcqqICqpLiT9hy8l+UKIa5k2CI8/T5+TWQC0teeolIYjKpKDSEyMZYohAiGIUtVDNZSaIYw8awRBFoUThNHh8MMKfQs6z9zfAOE2c9Uoa6kMfE5ctZFv4kYU5M0aVnAhgSJLCK6hzSSXxpuvGgPz3ph/fD7q/ML0G5U7GAjUGFl15YCizDSpEyIpjwebHUZJxPdPo+gIWyFReU+NSCZCm/XtZO0QjJIyxIk/iESFVi0g+pJk9cpJtl6eiZ627iwJFFTjVPwFuaK4yQZaQcWAKY1KhaTdgvCqgVNWJVDQp28mAMlFRX/ceLi49w63K5f3lwVO2vmwo2KhBdRCFSqx1YqUQduCTukZRGehqgxkGrGouWyd/bXOeXXuqOp75mANKR1YWd2YVD2bc0Y6mD6eoI01MEg2YRSIw2hY0CliYu1tizAA/H/RdfmuzdG3/SRsM66HMl3oXh89tY++LZvXvV4Qfv/4ufnNv+1ubmK8FNXRzo5AG/++Dsmd86qMizd1yAy+BPyBIANUAUaAALE0SDSBBQFsImpiClOOsgHXjJjFJVFV2EBRQ+htNyJFGIOUhAx4Y4MFSjAAQLRKcy61Wv3L0T5hNxPbXav3N3Y7i6s75hoCJshEFiChvUhy6QMWAnKl3ypMuUaTAYUZZ8umwPt+R4hXQYMkEhpSOoUOq8s01NevxToUtkal2mMyDBHwoyKf8M2Z/u9HvMzR5rPse5W6fEkpCoKsJgDRIlEpvkcaWkpDDMgCZINsX8JhJ/wpcUAJPlzOkPUE6vShWqERKjEBHMUjmdRR0co4hKepEhRhFY69IDmxtaWJHEiSxEIGqhjsAKAzIKa5glcM/Vj/7m5/Lc8MqbXzNROg1hOr/3N7+YTvZNH7G2dma4VJRSGl5w57SrRoOuRTef3jAjaYJpZd6gayteNPWb35zN2o7bwYuXHnzvz25cvLLz0Xtx/Lf+9ge9qy/s7+w4loFtqt6wHNnxD3+yyU13+/12cVj56f6f/X+LW59a0cA/3hB0YHJVZQch+rBo4rkL4/WRbQ5EKjUVq7RNlCJSkMUkUk2bly9uXt0+flQ3j94ZmDbaeSPB8aQsvR2YEDrrCmnFlgWA4AJ6whVThY6duJVb9x+F8+fOXXrp/v7eWtgsn+/bjbr10Q5Lms8OPvhsvL1xduPC+t6UdxfVzrE5mS3OfOs1un45PD7G0ymHmn1V6cCWZxCrXgzqj7xG3/mwc9///GeTp3dc8LUzMyx668OTrc2fTg+n+/sTg7A3gz95a7AxnIQGcPCYLtqz58PW2dm9h0VFRsDOBfXMFsoAiQRrqqaZADah/ewdLRhNwBgIMLXlALRohsOd0s60nPGgwaii1haEMC8oxI48D8axt5DNJ3Zlth/v/fDRYHSp2AtxwjgRmqFqrTSAF6R4F12IdKoiCJYjNIp2ktyeKKTefikJRYhd6Uoffbq1mZJxFVnLIhqCRy50+suVcznTsjEcI6IEEk5LLQnCBLY2SkSiLqbKndas+WFOD6wul3hIXyVIYOLCuQTxGF4ydU02yWKb1k2izDmeG5ochLLDBhOJgJdkaGB512SsLq9ucwYcJ3NQAbE1id7FBBWNDEdF1CR0Dq6pvnC0/u7m3m7V3K1PLh2veCsMCrDRKjOSPkUUp6LnJYj2udY/K0AplVThfKHk1Xpa2C0tprFc0SegV5WW2g/kXgJLYwgVFVVLnBjMy0uUgEyxphQRm+l1FulFKotSqvoCXhZmpNVcSksUMQU4CNlpF3pWDqd23Np6hQKJyNlPJ48ubR/1eHx1c/PDhgc9dUoVtFYaULFezblBBXEiJUIN1+dqUId2JmjMwJ4A0ytX7FrV0hG0AGAX2uzD9L0AAQAASURBVAWIZTcNHSH6GOcd+0YQfQcrYcVZBfueTJvCSbQrpnX12vTp3vf+RF+80V6/tKidg1MEZRSBn/7i3atvyvlrL1+2v43wSPYXoTrsbV88erzjP/t5iQKjsrMaEwu/DYHFCokoBSEEkIA6IGbjNlbNGEcAYAyLAhoELEFsSk2Iy5OVFx15xZOAED31sFzy7oSURSNrP8jqcUsGAmkvXXb99WnULgIdibYAiYpoVJBhw0pRolGSBLISdxJSIQ4AS0jQTAYulIgVKeUw1UtKdpOpuDJU0+iZCm2OK6P06CFKWuFyPpbIQROCzDXIwDEgpMlFLQHJ6SEQgBWd71zhUsYUMVmbyOTWx5BMIhOlK90IMCxRUhoG6XKLZPLyXD9XEGQSo4pko6DTTRFIVSSCCFGhiijRFYXrVfN5l5ihRDYFgCkMwFCnSmXR9x2gDrAq1jgbogwGgye7O7snJ/bD6cTuszFtMxP1zN7aYZgXtlOxMdQoOl4gFOAFuzqwb2fXpLehNJ637Ln65m+tjLZu/fH/59WvvPb43/3bzaENi9aGtmv9Ikw2qpXF5Quoef3S1XA8bxdPe83k6E/+p/XJbPej9y/Atffu9MEA1mwvjDZ0vO+roYxGbn8vxAmMLeAnz62rn4vtTGeJOHSLYAwvDJdMAbGVZn9q2G6+/M3Vi2cPP/nLZ/sz41Aa6q3vCTe2MtKKeEUSmhpQDxiABnSC4YTXxmFl597BC1/fuLC+PW6mTN76qTfaTOfd2TV3HvUnT+9iv5XV4Zl+XB+dvXblSzXVzeaF4cXIE44Ttk+97O35u5/5ncl050iePvInO05b6jlqxs+5unv1+g/mB8fz5veufeOdT99uFdfPXmyLwftH33eD4dbAhpMDMvA20lyqV683UhC6oqgggSOYXNfBGCR2PmdfOSGItQyx6mG8k3nKgc5R9uioW1s5HA4Ex16HBfmChYtIYR5FWho2VLey/qjbt9Pm3MJNRTAlO2WZSvBEDagDc6caFREUgQAIcSAIKJCqJoyGEfKGNu1uRWJcSLs0qJFUL5LEEIhLwV8O/Uvr20RoXD6wYDYJ5I05K0CT7VvOC8cveScDaSGMJOBNBq25kc6YjbV20XrDbI21RRF8V5ZORUIUa1KLL9mtIkJz8meytuKU9ymMPH9CzXIRzsyS0N7MzE7BQipRiUlVJUr2HElEG0ggFZUiIhozsf5CM9qZT/Z681v9gzNNjwUzGwBXRM/CwmA2EtM0D2uL5fYdKVglsZaX+mNwYXKFPJUnp5BlXnKzcneRsDFJHZMud/pLiwQkSBvL6ZuXautc95PRMCfSl82DjDKr0TQwKSckHUKAhaa4eIgyqAA4B0pbo2UPDx9qF2w5krqI4lZ/cbzxtUtPR3b3tQtbn9yujKpT1EQDwgC+8lyzVEIOqMFVlKElG3gA9u3AEmNRrFVUH5qCWUsAMUTXsk4QCh66xXbNg+2qx1T3qNc3g6qu2Hhp4tQc7cYPHx4+OJi6kWu2SvvGP5pWUgR2mCuLBqHChUZ1uj9/sHv04CfN8G61OGcV093H0/t3xO1W56aEK+htauCysEyIWKhlCV6ybwtUhEgFksI9SAkaEkMnnab0k0xecl2IEryx6T1MhN7s7pnOYpBorSVQkJhot6wCCqLwTBenrR3vdgiMiqeRpvdfKcvP+MJTB2UTotpobJekeIjgwriIkOPLRBQUQrRgtlYRiYSILZu0TgaSPicTkpMBdNKrJaLvqZddIlkkZj5pFktkM7wsPuYliqIEUk5PuUCRg0LTQy4JVoISLLgsKjIcxNuEywRlBoxJEzsoW38Jpcg1YLn6AiU7DyVFBAipWhKBlSBEgBYKZVaRGISSgR+ylCqVfABMxncSo1dhIbLGUC69htlBrYiNkcVWUI1ihdj0WR0xmAb6i/c/KTd6RGijlF10vb7MS15Ej3kpoM6KV20RKljnQieuiONJc07pS6Zo5rNex4jh5OP7w9+6Ut54bTFt+bMfD/7uH03NXPvo6jDYPMuTR7456X3pevTTxeyw/+L1vaefrH96p+ZBWbkgpjR16Lyq8xpo8kTYFG0TJ21EK1QV825+ZujPni2a48iWLXzwhkqm0JM6dLGbB25tsQCmevL0xKyvXX7jN+z+uf2Pf0DzFmiHQ7jah4k3gUMICBpdpAGjksb0Zxg04jz3PLvb9+5ubR76vR0lsbGbYb4Y1LyYnkQrX3nx+YeTcHc8OToYr26Vg/X+yZPOetDEaIzHf/Xn/OOf2UbsROwE3LCzXl0VuFxZHeilK/frwQ/uvdccPji3vd3u3vlqN7fH4zP16l+1RyGEq89f23zyyPvjajgIHVoNvZWNNowDS0UUyKByTqI1JgRwYQALGGjebxhLIiJdxYHhVSgysxCiRA0p/Rwnw62Taq2AtxKsemOli7HVQSulbRwOJsV+S6uuWEAnGqeKE+LjaFqr6pmDSABLevyyrVsMIBhDyc4fEBVDy+i0ECNA80Vrrc0cD0kQLLKyIs9bKqnwqsYUTJRLLzGTtWA2KohLIaxJ2UVL4amoxOWaN29XKbXhS0QNCckkCSFqKKyx1qS/Ya2NMTJT4Wx6CamzT3CoyikzC8kkJ9f8/KUpQ8jEZBlB89dBRnpF1bilS85y+ZyiyQs4FgQyiVAMYkRcPV5/Vu3uu+ntlaPX9kfRkmVVMiKaAgDZcHJjVmiiLGcFtCBbdyxxstQyIO/Hl/swwHKemk6vvDxMC36JA516f2aGFRWQGkpQHijpRrFMk1PNLZWlJDCGobTrziACq1oIS7J4Ypudq5VBjsEwLJ3TAoZNuz+5/NVfPXi0R0/uVsVoELD58WLnV9an53l8Ze9SKKaY2VoxYB1ocN6uGCkiDZT6sKYb0IkN01DVLJOzYfF0e/NM3AUPhooFZgDaouyM9SXr0/Dt19avnBlOd0+ak+losD6ZtcaFBzsPK67q0fDcwL5wefvJ8ex//fjw0PZOqrBiWl+wKarOkOkCO9cu9qVdtFyp9JpZqI4/kf1WFoX2unpULEx9bNZnWxft1LIXMMgRtIJli5DswWKUhAsKWZLIpESOODKbfPkTJLEXUxdDWcoFRggeRMm6EvmtpqR0ZyCwWlhiGymaSE4xszK/+GJ9+CxYW8mEx7O4tn5258Ozhk/OrJ+srE4Gqy1bCa0VzxqQchVSnqiIsUZERIEQ2VIK7EtCoMQ0ON0HseFkeXXqT05KSlEiMwPmtIySplDCpbUdsso2Oc7mpjrnaSFTMFP3qEtmV3Lm6USMKkViESYIlJwJIohh6Z8jEtOqXw0zgig05ZAAyXE7G7TSMqOT8jygUZKmgymvxBhJ908C4syFVJWY/i8BBkpQS2QAQ3BMDrCiheXSeyvKqIASWhMq7ffru49uzXiyslWjixI6CcIxwqi3DieipY/UxEgF98zUEztFEFtcqfpvHE3VzjtR0dYg4OH73Lxy9bfevP8n/6qWtjm4F5p268nj5p//3xeTJyGGIWIcODq/UVaM1cp1QxESu6AWkUXaztoYxEdLHI1qF63ExrJzFkG1jc+/GrwwhCRE4/uV8423qDUGaRVzDhOxjskQ93hcW7B7bvT8tW8Mpw/eHz96v53vlJgO1r2RVuYCAVUcbK/VstVqrCsNDSZaW2vMs/evbL/KW6Li7VefG82ms6eH+93Joi26hdgr25tnR3z3KFz70itNjOSgJnZtsNLHaGOAruqvNjGwcmTxGsJ8Mdg8e/u5Fz7Y/XTv1vs9tIPR5uaZSzjYNXc+KF19t+y/98Hf9Efrr/QG4YO3XVU/ef56fetmefVK+fyVvce3C1eSFs56FgSQtUk/awGSqExW08RCHXMAAd5iJlBDIHQqlUFAVNFWMUesybuiY1WTwkFIp6pNBCA7cXrzcOXiejFg3wifgGdGPcMr0AIBCARhw4zApAJhwyIxAY2ABZJ5TmLLAkhhdpyaR2Ps8jlNzCnOLInl45CkfEsIEks5YJIDJPGwIc60rHSLqTCxpGQGCTHpLtL8lshfid4lKsYYa21KN4PAWoNEHiaiJPCFWsNZsJzpIjDWLodzMsZoelABcPbESjwLAKfOtJq2W3QK5GW/amQCpVq2HcNJ5JRTr8FGGwrZkjPPn0xurk8e1ntXB2uDtm7Ik62c9UsZxXKsTY145pvJaQFOhn0EVWElUaRFSFpccwbgE0DMoBQxQSC2DKHkTkIQYuKY1JNWJPAyjDYjCxnlS5HpomC2SSOauOeEIqlGmYyqTe+rKKsyUKSkchhLalUAYeHCFlSpC82iunjh2t/7nY//+E8Ob3+4UsmZZ08H1fmm1r03N7e+/0DOGC0hdcSA7Krtet6skO1pT8YDzGrTlhdf3Hzj6735yfHdj6pzzYOP3g318CQ0I14FsA+C1L5cebxmzIZ5NH68c/8eHGZ775vChalf39zc27+388m9y2de9Y1+7Y3XN2bF0WH7mHtfvrDS8qKSkjmwcOGqpgkMmjeje9X2Fk7Wtt8zazU7xwUWRf+eXni2eu1weKV65MRbu4ixGPnYFERZPKcCqlS9IhmGOo3BWDCMtUXyR1QoEJ0tVDVGAXGUlGMEstxzVee7LnRMHFWSQ1mmUaSVqxoTC2+Cg5w4986Vy6NL11obQ+vZEovohdjb2x89fbj6eAfOtRe2D9bWp3YQQAuJRfAQDRLBqXOFklhiZpMjB5Ydb2p4Q+wUysaG0OXu0xoNSdDGxphlpy3JhDQF92JJdUwrE5GgafrMBrEKwCYaP2m6+DRDTZLOP0FDVECM4ST5qAqH0HXem6QjVGgicxIh2dMvBRWSO2vmz8EdgElBECGQY+M1GKiCkotQSDoxZglqDC8WnoitdV0XYgLLmWJOpCLLDNgoToSJHFuLUlFTLFX6Si52vfbJ+E4xksa2ItF4iSJxHsUIKdZWNks3enrnZs+K12NnjNcpC14IxZcmk9ZpMKjmc0NkyLrF7uLf/48T63o7n/Sd9T/+K2goGGHWDbi0zkxjO7j+lXY+iQ8/mXz4/xruPuJqAN8KF1yzFeOnYq1HgLA1xEaIahSVmx0+K974SnzuUjjeL3nVagRxlBCsBc19JF1YuwAJh0bUsqkLFDxdW33a+pa7c5df39g+V0z35rs3Z3sPG5y4XkMaF1ospNdq6bmeoj/RGsA27yM0Rze//403X28nY/vcuULn9KWrV2ZN++GD2aOW3/t0d+3s1h/+ne/cnQ4b78Ww6ZityjzyaL0FIXrpAi+YolotREQGm3PfvV6vPnrh+kf336kav17XfP+TCNDVL/507yliePmVG/0Hd81w9N5wc3q4/5Z2g7e+fezbMF/YuqcRCiIrVhiE5BWlSmwIiARiFMYkTUhUKIITDwAQScENBiKdqFfTshiBEZAVK7716kFTYgUfmq2LN1zg9tBbD0zBLUtLhEY5iCyYO0AgHVgAtQATbGG6GIhIJBASaVNSnyoqSR8nopYJGkDGWhtjIMNRlRgEImElYRApmBEAkUiZbwRjmAwbNqno5uY3DV5EsJRo7Mn5WSSk32o2ScyfxRARJOM9AmGVZWFkIolLApVIMpASTR49JqmmJPG/JDJIl/MjL83rOWGhnO8RMhnGJkp8jc/HUqR/rkpQYi4yn5Rh4GCY4mvN5d3qo2lF7w+ffhvPKxWiBONcNCkaMC+QkxtR8jcxWCqGPs+Sg6Hk+Z7FIrR07ksc1uxoItnFUwGY5L+VcT3lzPs0ghiQLjYYsgbBU0x3UXoTDATMRhWAJTDUEBliEyKILFknwlCGFoSCYFXZwMECFoHBNkrlBKEaxgc//JP+5NGL//jvzY6+efzgQ/vJndHhbnflzOT62cNPds5Y39VGhuARwkpHfVg720RbVe2Im/W3vvbug09v/fn/5WtffGP1gi32736B/WuXrs7YvX3rEMDlwdqkneyEJkTXG63NQ2jPy6rr16PewJ6vSh6Px8OXBmeOL88Oxu2T8UE5Xr/MqKyM2najrNiGKpByjLaoxI9nsi465v3rV++Om8rMXD/0gVb6LdZ2urWdc9+O7RD7nqeQqIU6YmYUwgtgoSCG51w0RRHZuCgdU861pSz/ZSbWlMCRQYBcZgWqrGxZBEuncghggCKKEjGrULCqQchGUIgTzDWQsZxDiZ2ZPX9+/9JWr1mU+wfDx0/OfvbZc716PjpzfGZzv+q1pNwRYkDUgm2nUsEECsFEJrKwOZSDEwmaRaVbeGI2xCDtJFpQsm1RkbIqZ7NZURQMYuWQkkNTDRUYZgkCTi1fgmDTyWVDnGxRmRKdaqnbSiBX9qezqYJaw37hFXDOxpiTiQTwIsxsRWI2ryRhShYFqZ+OrKSa2/sEq6uqilGGgiEM4myCm1hvUMCYQgKETUKVma1yoWIJzpgKUnmxZGu2TiqKhdoVkirEWl2/MAM+XpNCN+tZr4TRIN1Jq62UvboerJvGeK4O/+ZT1NVc4KJt2F8mvMGmkG6GBVNJLnXOcdFObeF0714VVVS9bbmwldqgDSDooZ34Hsv4f/7voTQgjERhe6IK5wQwLTfG91yMXLEEJyTRB5XYtJOwWP2NXy+uffnhR7/o1ZUGD1NEaaMscXn1iBznhiZItmvxMBBD2O6NtjzX8+ZwxG403Dy3ff3k5of3P/nxirMheJSD6aIL3PNwB1jrIW6bZ0M5KovONCfrE2exsH/99t9YlhrFte3117Y3aU/c9vbVazeOJk3ACrOFIqogiIlwKzXcENNgQ7aUa8O8qm37+NblR5PR9uVntuIAX8yqyLLYXx3UO323c/NWPRhebEJ8+rhaHY1D97yguvgctrdnt3ZdWaALcMZGgxxAkO7VtBo9/U+YlSkCERQVBQeTBLO6tI6SwOJFvKQTKSqeAsPEJqJRgG3jprsnW5vnwxyxk76vfBu8n1QMDR7cCUcmsSSESCTCSiqKpOoMadyUGNImM4SQ16OazCMJxM45IkJiPZ1KTjmL4ZO+NPE1iJbGxJRM5onT8os5DbW5eQWJCAuLBFUNkQUhJHKi0jKeNq9EJZtViQak6dSQiTkLCcnNJyFDibqZMsokhlOE1EtMbjvMHCUykYHJJDDK3w1l1/ZEGc5d9XL0x9LJK7cCGaBC8i/BgMrr7daPq8f77uSJm57DVqdTp5XYDJ8ni4Bky8uJsUJ5tEiEElFAhWB06apHbDRLptSmOTYV4ISRQ0+bCgYop8QBGYlcqogzv0s5Yb2J/iIMZlUmGAKDDVEBTZJfa00halQsw4IKopK4EDBZFQexgFXDgDNMjX/wcDDwZDf98c9u/+lHg2++vvF71+3v36imi39l35tuVk+/ur7+8U5Yd6glVNH2qbaTddeuuKYfDoZ6PPjBe9909YN2r7fLBcvGYDxr7p7xF19cf+6lGwygHOGf/eVJU1/2pui1+5uXV1/7wtWetYf7fhoOR4PtydlzFmiolq7gdtHOwmg4Kbr2+ptng07LSlXmJbMPbPsId0+Ks4CKHw/vu6uGK26ainuNK1oaHZj12H8Ft7R4yhQ41gGGeWE1gJFMxChH8gBAUCEiyQqXRI/TAMBqlpJnv3MBGQZUVUPoEp+Rs9lUtqUx1iYtWMpFYbCxEIkpOswmQrKAVQKBomrgzvXnl1aay1fcdFYdPq2f7p57fHuzqtrRmeMzZ4/Lcu64UzGLzm1UMiYPtZYCKzSAbZBQw/oQxeY+IAJWYZSiFRFKnetkemKsTaKiGAOSvHdJjFbNHuggxM/zvilZb6ooWwYtCZ6USfvEZLM4HYmokSZdBrEiSFBZPl/MUIQlCXGZBYEMORsmTbgvCCAVo1CkQEeDpSwsi/qRSq9l5hi8AHHhlQxTQbAQIzCkDloJV0w1OysD4QoYcKgDquhWDa+oGdGt+x8U11bXMOhZywmdEJZ53H98OD98fHz/yDiYcyZMjU5Lltl2oZgddVaBGfxJr2Vm8YySoI6Nh6jCEJxFCDG0gFd13Aa2pOwGgYU5FAwiG6OALMMEo76pbIhCIl0AT501gw1eW6GX3jh34xUK5v6nH7AllQBmUCC2hKBQkbkqiISaAVlNDWLC8EMINvB8tD7jqqHpiUyfHp6cufStIq5//On7dWW7ULTEge0i6Bo369jfosk6HRZxZjH396ZbmxftAD3j4rOd+3XzZDgYbPTc5av/eGaraRMWHDuKRowhVmYKYnqDOVM9sL4NmEd07LiA72ylfuq9rcbzI0gY9Dd6bHUeZpdfe/v+XRH92itfX7v5YWtEubeKlcWze8Pv/ub9B7sn7YGrjWXLsSVbxuw0l5Uo+fCmHVDyiiAAQhRUA4S1tcRQBxWVoGSFC5GZBBIltcQhKqKSZ7RirGl3W/9oZzi1tjrLLQcORZwL4kJmhXpoAJRIgEBpYYxAhCiBCJwYRwCyl17aTnFKFjKWRdQaE1VMKqpZp0OAMrGeTmgQFU3fIyXYkzml6xo2IBg2yzRyAFDBkkJtRaK1JEQUY4xRsrI/ER5zYnzi4YKRNIuSk8j01OYyhQ/lfNZT4SxzWpeJarpNUmkTkkSlTiR0ygYB+VZhUKAMj+UfWcZMlyX4VN6bvxkEK1/0z92bHu4N2veq3d/364oKsAZCtGwoQEjG+5pJoipJ28gsSUeEhFRhCdymLy6aoIJMISWlJYSry5/FkhWd8UeAhDlxvHMRP3WKACBCp2QTgJkLgWHjICxiQIVRp2DAiRTElhzBiq0MSqJS1SIg1LYcnrt0uBhPd5tBf15uDnpVN93/8ckPfhircuvV7166fPZesz97c/twZ3e9J34YdY2GZjrA5MTvBn84QjvkvU052qhXbvB42Nz8ucdGPbz4/Pm3v/+/yCv/cKsGgMm9o9oUW3jKcNtmZY3njz67szsen//sLz57MSzc1Rv1/H68WrvNJ/vN2Lz88mvXLTV9PjpcyI2tVpqmZ0W7NsAVqI+bWx09s6a/UB637n1ctaSEfqdsJ2C3XR+PZKcrCqsDJYIUYMPSVBCfoUYFNCZcQlmAwOR46aQEtRkJ5tycqeYmTECkypqGseycmtbBZhkvli3h8p6GI4LmYTQLkPNvVGGJSWxciNfG2cmly3xhuz9rV/YPh3tPzu7eO2/rdnVr9+z6bKU+PFlIxVVUiDKsAjEKK7cQA0L2eEq+kqoUSJCNOaDOFjFGgEPmVOfoolP5oCQcJP39fAQlNbPG5FtFIbI8wrRsw1PetRARxCrLKWFhaaAhKbU3Eb54aTeGLAqwhvPNyaflFZrX1VkPka8zZnCOW+hCIqtbltxzi7BhJ2QVjuAAB+6Rs6ZPOuDYF14lDJh7BTZgN+3Tk4dHJ3eKuT1hjcF7MHmynkMbpQU6w5slsygHY8Vre663ff33f/+TP/+T+pP3hrbwHFvrXQisgeBiOxMR6yxbkhgQAiDRFsZytyAiMIQtWbY+CuI8eXMHRSATDPNwy527IKMNjKr1rSu8uU4uqLcn77xzcvsz/vJX0DUCgQYgpV/GLogKKxZExNTSrKcAQtL8gyMx2DeeVtx4Zb0pBrUdTXwwz32b5qO7j+6wdYEYsT1vDtbC/sWV9gydVJN9nUf2NH40Dq6zh82EF/HCxXPbPXitpBpSeUZUXG9IwXZtF9uOO2bP1htT19Jf1buPTONSAFWwGryYGIWgFOdxIbBbm5v1vXfKrfNvV27v3m49OjMqa2nHZSz3xw8vbV5+4b/53+8IP3tw5+xmPROILUExQAs1mvQHmV+TRkgBhFJSPXlNVFfyQAQKKEtrsWAuSZN8yYBJARtCZ4yJiw4BNOdoIk94vbpw5tyrdx89c7aDXxDPjQYiCAUmMSokQTiAkvWjgCBRUs0FZYDxlDlbuUIkhhBVcoaoaHKDhaikfjIl/SZaLTNpVinQcjpWTbVridDIMsfllzyYAGbDoAiRiJyXl5nWaflKSJsrSbLBNLAmPJc46REUn8+pSpkADLLJlD3XTD4tT6kLIihDCGYpQ1oG2WedrE0/rfR55Zfq3JK5rbmLOq1pwZTu6+Hqny4+elZPPgn7X+TtuUQsg24YREg5u5RKeBqXkmm8sqpyIkXnLX36q8sg1ZBgLzLJUvj0yyY/MSVJHt6a7fglRgGsiNDSA4tQaFJPQaEGZCQxnEFEBZNjWLJOhUUsc4+4jMGoJXLgkqUQ7gEFxApKVP1R8I2X8dV//GuHv/bGg5/9q6K9F0cydLFkW9iT8f6PXv7q794rHk1fHE5e7q1PpjSkvmlHOOZiPOwmKxgL9iFH6k+Odo57Xk7GDyeXfnf2V99/460v3sDh+x+/O73yEoAu7p9z9aQDS7XV25jd+lu/v9t3g/We/zuXf3VycnChuzc7Ogzrb3JJz+79qB0ebg+GF4v9vZ3Zbtu+fk5kPimNBjHaDdaaBxaHUSaBKoUJqLzWom1nh9SG4tJFqYAVRJuWmMnkSUkIjVMJCotsTG5STiCzJQSAs5iOU6VF1sUgpHxbyR2n8vLcKGn+gRKlTVNybWYQhERiTLnYJvuVZnMVBSfaMmMhUsCQsw7s2hAYJ7WbXr24e+lcfdKOTqb1s52r79/lXv/ozNZ8fWs6HMxhWxE2YrsOgHDRMdciCyukHsrRWBc55JFSBVDRqqxjDDHJEjh3rEyULe5EhWLiGKfHIjvJA1GFwUppYbzsMRILMIokgmFUsEZDCrWaogBJGKyMZahXKupLw9oMwQjEsFHVvE4CSeolVCAkeSQgMjnBTUCAGjYiMXSB2YgYY5xqSXBMVlCRVko9OEsr0IHyKnhku37AishAZAOjtWb3k7dfcofCti6t922jHKuej8YN1vdniAOPcVBrUThYtW2oh84v1i79yv/25KXX97//x8PjvZoRHCDkY2vVJ1EKgsSwIIghmI4Q5kZIpfNgIYHOwdaMNtuVFazY3ubz7uI1NxzJgNkJPIepLI534wfv+507cuuebcfDL3/9aRBChEI0cOr3YoQYlagc0t5CFTSrsWRpcmDxYoc2zgKf2FBX46oUUjJ84ct/fy/++N7dT7dW/FndH3TP1nl/0OxXfkK7FKdipZBJmLQntvX6xtd+c7TCB+/929JNq83roXS+kQiGcaWpiCVANCK0naCAGSAi2sKrd9KRbywoLtpRb3jbWB+9BQ8H58zxOG5dGE/Hg9X165dfMQ/unfhgty/VN167+OU3fvzhO+On0y9e2NgPC+MqExbWOYIIB2g6rjGzWqFEChJVISx75+SuDAt0IEMwINbWkhgyrKQMkqgGRiQ4KbTrdA6ysI3d+eidsLdTv/Jq8A1sIPioAUaMRiCqRtUAREDBSiohAoiy/MoxUZlBqTAsfKcQZy2zSVthGEpWyTGk9VmCGhVIxsJYXiKUV6tpaSzKnO2gs2Ap2TItbbNSB0oEoszBYl5W06zZh56KOzSTMBWSsdH81VKi0nLfmqq3CoSC5FXW6dKQU1XTZVnltAT7fBud/LHMLxU5peVnJZLlcpqW2+j0Vli4xuASr11pt26WT37uHl0JW7UtfAqXyViu5k91Kmxik0pt6m4UbJJRNDhpk7JImEyR+LTL9VsiVOfXn96QfMEl5+2QEmpFQvLTExEmFQ3Lnw4TuUSzUrXMBaGIaoksmUrUEpVAqU64AtUMBy4UpWil5JhrG0o/+9t3pvfuTI5ubP7Kt774f/pHenQvfPwj/uxv3XjP+WpFnvh7Fzdf25rszfZ/7bmL/+ETNzQroQnh6aA72MLxFg6HPLbNlI9EO27brl29OO+e4yft5E5T2431vfemvArAbKyOMLPVgdDKWRlfeW1zgDoovPmddgodrk78pbeu1g0GDQ3feKPyk3FP9z+sd57J1LfuDFqRQ6MCLlt/vBmeAYcCK9rzsMI1jPhoa9jDi5v26tm4CFhBkIAO6BidqFVlgBU+J04Rp0eVFIoYQVH0cwZjsnjSpX0iZyO51Bx+LkRf/ijzQTaGiTkBMEk2EKKwNZRWOpTPsBKxaIBSiNZaqyTQgI4tGOwEaCWym/Vds7E+uH7NP9jZODhcebKz8vDuOaqb7XPjM5sn/V7Xr9vFghWIXQOywjHt3TRGS6xGoGCjIRJz27VV1TOFbRcLSwaf+8HkzWWS2dMpFILcpCac3KQnXCTPIEiePmIiiCiwMLhIJtGE5F3HS5ETKwvyfjuEaA2DWaOwIcM2iFi2lO0A0mwTFUosqssNVeKBAJQWCTESUNc97yM4RVEZQiFqWa3CwTiuSfuQVdgNxiq6EWjdoJZtNx0e3To4fK+sOEhwc7HazamcSQm3eny8G2J/srbRObBlgMW54MPV119VG6eHs3LrUv/v/3eH731v/t4Py1YdOssAs4Vw8BDP8AHiBUTCxnjXD4N+de4ij867jTN2uI7hsF9bazS04o/m8wefdA/uyMEYs32JzM3YKlfKtXq/dXZ3+7nojwsuNN2CjG6hqmCuBWkk6xSLBIly02MGsQ2qLKoL4R5zR7FRKaK1Vkie7Dy9uvbqfDaL4/cL48+uD8/Q1B48iNOIiXLHfh60UbNg+/U/+O9Wi/7x8e59vgRxr73w7b1uALFTWzXBoRUOXESiSKLRqpHRaC7BdZ2LFggK9iwq5GvXOnfSjouNQc3azYNOJ6+71fq5lcoMm5fWtn/vD7BVHz+b/vUP3rt965Pf/+a3jp/s2Qtb6Fp1FAI7awGhjLLkWSqZLsjni8T0ywOS7B9YrSACNtnPSjQkhABEJQJFhC6wknZCFBbt+NzVK5fffO3unQdlKSLeWgoUkJ0YJUWWmSztk0BiJW1xl0rc9NiL5NJIYDJBlBENWwGQ8k9yYEjSuKfYsmV0CZY3S4IzOT17KWRAsmAQyzK4fC9oGUWQADFKgFiyrkkW0OkvMqc+IMNOxHnPipwjlL4JkyyrksWeZlVF2kvJMus37aYScgXNEcZE2UdgmWWQLJnzsJrvSv7855T+5Jcn0cjWqu9gv8mX7ze7J1XzbrzzHb4REJbf8+knShAiAxDNnu/43HMDS4oAliwBqBLZxJnRX/qa6YJLQJfgdDVKJBps0idx+upJyiykIYmcNXGek3hSLHGhUhh2CgdYQz3VEpWaynBFUgNOuc9wihJSC2rbHU3i9BFveTx75/G/eXfv0Y2rX99+8atfPvN3Xtp9997ev/4XfT4XPnzv8rU//Jmf+qsrh59VV9sj02swmwxl5nBoecx+bOfOLnphv2WvB73zK9300nMv3nv37ouvXTuP3i9+9iMA9vo3ZNTrnT2oOJw8vX1r56k/nDcRjQ+tFl5My1yharkWN+zcysWRApORb/o1uvE0jmVryN53DO/ErMTjiCm4FNHIdiHgnmsioZ1U127EM3194tWCjBjDwQpMhDPapDOcAGCSxLcnRT5yeSGk+bIXQHAqg8snORlMLdc/n8vkUivGSI9SWv8Qk7GqQYlJhAWR8wOknAu9gEyIgVWIOaQpKW2wA0sXobFpJtMJD4c7o2H50iW7f7xulT/97PzDhxfLqlnfHJ87M+vV86JsKSCK82AwWWOIoWIsC6JkcxxtTmZsGNl4IyPVSOmlTGSMSrDGJAeeLgYAzGTYhCxwzql/pyRpEkQCVDlCRaITVeUuR4UAmS+jhJRCHmO3zHdRImjKLkxaJMrO9aTKQgmyye7op08rQVWZNGFPXReYi6UVkokBioLUgpxUyjVhABkAqyTDyOsoB4t+2HvOLWZPf3ZBHzh2JKHgoBJaLRdahnBSw/XKdQo4GGxwYBWtENqK+ufPdidwFfOJ8daO3vwuXv7S9O7PZs9ummcPaNbEGATKruDeiAZDWl2zo1XeulSfveQGbMkHON9Cp+P57Q/kcB97k+7pw/7GwNcr3vu4Qmv9c3rzZlHXrYgTmgZMX/1K16GUHiW2HwHKKYglG8ggEoKqVxgmqyCe98iAI2kQ07faSZh33LfWmaDBGmbQwvkvvfH1/ZtjPLovftYsjtetOBSWre88Bw5tYE+2G1yYqexPd978u//Vwdg2bnPSOXXVPDppgpyIdkyByBvpovXQepPm7JhbiLEgcNDOQnEyOcfyKytbqyNXzI7aa9f7569sbQxcvSq2HNXx4b1nT9/56O13v//aG29+57f/4PH3/tx96bpGkOXCVZ0PnUjlbOJALgk8Apg8znESpgUmQjLZSb0KJaVLIDVJ2qkCkIBEQuxVvabrOvEqHWDLCouT8aO3/6a+crnzbWmgiJbUShCOYAhJUnHq0ihOwCFEtgyChMjJhzVd9pnb8zmBhLJxYrLaS815SJEC2fCOloQMSeQuGGgMwqwhuSFK3uaGZTGibHN3urDWVPjTfcVJP5troyrAUeTzzjpxlE/DhDLaQwQ2p3wqpLVechYCMrs4zZaiEgKsYdVgLCuSUYdJe6/k3qhLDwwk9wEAORMmL73zLJ87lqCwc4SRHXyxu/iu3P+0OHzB713gjS471qvmH21icCfL2bSPzIw8IhOJIJwsMyjHExGUY8aqTwtzWl7n65sAyib5UFLWCBViITWq6WFL58oSpTQkJlgVQ2wS8zOyZa6QADBUKAkVqE/aU5RCfTY1oxSpgYqkj/WXrg6/8k92f/6OHNxZnz5b3PvJ4f09xmzxypUrf/Td6c83/YOJLHr23Z/ya1f313zxxujSX912crhh/WBE9d7Jhsww6enE+mnhx/M6YHbML3bNa935m7949+3d6R/+F7/VdR8AuPXeT8zVr1IsNi8sbn1yx8wieaMGhdPIxD2uMA2YzHl9OhM1e+0j37fz0WAF/l5nsX/rzhvffv1gfFIUKyeLWTXbNSaILAKChzWQMBdn+r46s/XK5QMDrgsTFV5YWFQ5MJRQWxFBB6ADOsACMdXg5DksEpc71mwbrks5QMKDRbI9Bae2NfXg6Syl/2WTm7plU8wEkQhCACCIhKjRREBJAEgUkAgsK5Q6A1VxICkKFg0Ca0uNwYgPPnjiyWhFXR2/PNqfjuu9vdW9p1s7D1C7uH7mYGtjOjrT2CJEXyGgsBzZxEhQZ20IAWBXGja2C92y/csNSeYyRBTWJIDHGCZTQDXG1DUnS1mkUF7Jju+ImXWigRRK1EUoIlOagVPZlCUALBDLJCnZGpnYkdy1BGmvQ0pZnshkBAB1UOjnXI5MYGRrVYTYQEEpbVkTJYKVCrBFoVIpBsBQw4hkA4NVf8Y/WcHeRTl5ePTzAd2vg4EEgyBhUQ7Pjr2dYjp0A9s2ZKWEfbpRKsw0+JdvvLh6bnM6bbk2XehsgIwnVBTutV8t8SaFg4WfUUpyK5nKmhyDhYn9NPjxfvhsNz65pSeHFjTZe1Z6z5BBPVxcf/0nz/Zm09mxbzCW7SvXrr/xev/dd21VB+n4a7/a9PtlEDYxKhEbhsYAWzBA7aJjmzRbkRABz+BkbsaTnu3Bew1thFN2zDPALTH5LYqCxrdffv3LB7jnH/24X3W1WARUXM+nbZwG2xppxOqDR+GVa7tdhX0J0ne6MVGV1rrAK1Jxj6Ii+Bh88I2YRYzliFryfio+BHjlTrlb1OjOX7K1ufK1t/jMc7xaWOO858O9/bA7q9f1//lP/2/bF89vDy6uXdz++lu/uv9v/93g+ef9aMuenLTWFQ3BWga8l7RqSEoZUSUEQ8I5yy+NcFmEqQlhUpu6xuTNkAz0OTF6ODbNCSDMMbI3tjefH26sDVY3R+P22Fk1bKOGSKl7VYJaZSVoCvdVhWjQuAR5JOGUIcT89Kf4ESCb+jATkSHEGGMaQpN3g7GGWaIg+UchATsZJJWgyukFRGstIMkXV7K0Ni2EhJNhRq4kGTzKjWuOzl2W9uwhkh6iVJfSi8y3Qc73MYkAAluYjAupcqpklPoPKBBVhbJoOUUeIPszalJVxbTxo+XA8ksgAVJua56oKdU9YbCogT2h5k26cq/d36+7H4Vb/wCblF7kKWMLSU9FedKlZL5DAKky6+cMeVXW9HvmjB7n85Aik1K2MZNCEQjJFChNF5EZQGQW1bisvvk/SoFqsMyG4MBG1RE5EQsqDPfUMErlAaOn6LP0CCustWifaWirrcoOC+Yoc/uN33/94FPWH0/PDE3bzNanc/fx2+5n565evHR3+mCloW3etA9OZNHz1y8//evvnw3TPiajvd0RzxbjzrYVnk1lj+o5xNuI+eCijn+008Mb4u/+4N+/3ZoTANQ0Wn3cuRdsD6vBda2jiQJQSysuxvuP19zCD9YORoejoUA74xbSMM8OK0tYHUwffCx79vLWC7N2vpg/Wwm7lmih/YhQSBERgrCIH730BTozaI66sNLjELrICLDCNiJGoYKlpwgKKfO1pVANiuRQAhFhhSTPRxBbSm7JCXcXIJOaRAw4SEijMevnqX/C2bQVmrThqXPSkMqPUMeIGpPplgLWAEQSERWRAjPbqGpNBAXSgkEaPaknZltykJ6XeTu21k6Hq8365uSq74/Hxd7e8ODZuQePQl2ErXOTrfMnK0PjWRBDSuZIblkMMtzFIKf4CWmCbjTxPAjGGogmURPnrVea5ilFH0uyNmUS4RgDshaAUiJ3hBLDgthaSR4cqglZT0TrImXCpAVXpnKkxBLDgFEIREgTVGdBQQjL2BFdgj9EHKJYY1WU4FSZyRJZVSdiBYYKgYPUygPCADIUuyLrYe8MdjZ4/4Lfi/Ob7XRuPEggAeIJw4NhFevaDOwaY+hEiUNHPNl8zk+mmxdX7JlCjkSfhbIofOxELHe+OBx3VkSstUMYBD/pDp9hEeNi7Ce7NG3x5GEpXXn+8lO2Xb0p1l3cfk7e/2k12npw9cXv/+1PNnu9X7n+5R/d+cXB/rPjh7fLixeAwvu5e/3r0xde5KePYuGgBXEUVXAWcVnLWAjQqWoKWmFKqFgURNEYG+bGoQSVHFm0AIzAAZtq2AiTGplNj9947bUdf5v277W+i4fd9FFTodLWy1RX0LNHf/G9/ffv2G+8Wa1t7s1d8GxOYqV2Mt67d3tn/Gxva+Xi5nCzjBsrcdVYdf31Z1dekXlkBzscytlhfzikulxZN4IwP+kOnxzt3XmmnX146xcPHt96/fW33O66tb1vfuu7pR1e37u48//+76v+mfLqt2bTXSoKKxotAIlgQicgm6czhvjkgCMQRmAIJX5vptayKgtFhlmismnKjGBwDFEFkCCBIITAoNKFp7f+VsNL1flznaY3N7AqbAosjcnvQdNmLPlSqYCp64IqWVc0XQeNltM+i4lJU8tIENUQhBnLTKMEgNES0pJTuyhlSrmnIhI0WtiUPJigMrZWVCgkIiUUif6Uq3zGezPvSohgUpPNpwNelOU2OW/BMzCWZkMSFbIsEYZNMroIyb1LNdt7EmmMhvMKMapGaAGOVpPZVwQzOF0TGUnWtB9fTp2pvRDkBXnSAqVqGTiYQGpFpLTure7Kv+8+2Hfd+37nDXNuGmFUQEHBTC7kqs45+UDT3M+ggoWS3Z6CQZZ+qRgTGckGRsvFZR6WmMjmvUNad1OXIwQ1MFg1Kgkgoh2rUeRhWmF1+fkZluAIpahVp9QDeipDQs9zvx8GczNgs15514zf/fHANnVRbL98efbxT6c/fvvCtVfO7z/tY7zoYcOLfu//Vw8G57du9C693h42Z6pLdvB66cfdr/9O/51/WR9PKm3sfOombrHfxuPCTRBnXbdypel/ye+d8Hgh/PrJxJw8+qEd9QHoupQPP5a6Flf4RnTu9IQZxmE81J03v3ypGm5Ppkc/+fTm4qUXm67ETF2QwNJUNJhHszv/2Z/9xR/+k/+mruzkZKfG1KmrOAbLC+8XruwG4iY0uHLtIEyqYjgHYV6UHWkfGqCl2I4RYIOgMvBOEHNZzJWTgAWzUxVWC5Lsnc2JK2gBsaIipEgKJirILgHgdIwTmymyKhQhBmQuOyhGa51ICFAjipAEsEYBYkNg50iCWFhOMLOgZOHCdgufFK+O2EfJ8ArbALDv2IdWtF0dyfr6Xoyj4/nwaM8c7NaPHk9Hq4+unbObo2Goq2ClA4BopYneEYNYIqzJciAiFoWzzocYQ2BbKFuTBEwksEaCRBaWlD6omognAiJSUkkydsNWBJaMqCtd14VkGMfMXehUlEFQ6SAEZkHwkZnJcIZxQijqWkNAgBiiqJZMjBGkzEYgEWqQ6Rvxc1t7m2dozdOOUQ6RxQIVoYi2X0gf2tNhOBjg8AyfnOfjYffY707tUycU4QlB2FOYdPVWLSGw23VDMNfiyw6rXg51e52e3Nn58H8YvPCd0FsPc3Ha62QmnNaPLbMG3/WHg6e3PzU//Hc9O9Aw6zNYtL54+c6Fiz+/c08Z05OJtO2lG6/duPzivBz8+MP30fkvvPyync98UGF96crL7tOPOkQenZPt5yZPH7mirIxtEW12tU/OszEsxDkbwBYqEGGIBsstxJzCj6LBLQYyZ1SIFgyYEUdhQIqgIRLYhqeH31k/D3/xwfhmW9uijt20ReVEukqNdVhpDk7Obl54Og71YKDR+XlDIpiYD//2venuo9v6s9Hw+auXXl8xw/1PHlzZuLL1O3+/psBFaNspFkG0CV5++Bd/s79ze7B25tHjvebw6Vvf+s2qt7E5xGtv/kYbDq9f/j9O73/c/fx7R83e9td/q9k4czielM506kzsVMQSk8m6kRCUSJiZ2KYIr+RhlBzCKdmi52k4ZC+kNKQm0QoiVJUjiyB4SxwRhSOxb+eTK299qa4Gx603DEjM8XnSiYY0UabCu7ygoZrQJlZg0fpEBQidGNYYYzJxywofBVQ7UVJYMgYQUWKoSljeIcbaEIKGTLi11gIUQlgGhSoppAtsGJq1rwnZTq7Y0CwForRVWtaYbJCsv1x1lxASERL5EmKYQOQKJyK8PEWiao1NOLOomvTp2KT5IYOrokLKoBCCtcmPNlpr9HRV/MuoL5Z0rSUIq6crYCCtFU30xlRTnV9xm5fna7eGx5/g3jU5Y1GogQaTehRmUuTiSnn/bJf8MAuwKAM2l2FYgJXMslhSTl5blmAsm4RkQ5SmW2TsORFYKCPBhOTll3M3MorNIAu1ylZhYZULaMWxp2qFew59YFDqsJMNOfjhDwY//3cFYoVx+BmXK+e++90vbTrZG5brP9tfwcnMLWTjavP6W/v28kEzaAcVtjcfHe2sH09eWNs+/xt/cOa9P97eeeBl+2nztBxLPPThwMa5dtb6E78/mg4G/fHuY1x8q9q5FXkPAFC1tWJnTw7rsHrWzryOibkMUzl/ZX0lbNz/8O5LN64Ow+Hj+wZG2LOcGGdYK530g93jpw/2/+x/+Dd/9F//wzqgCpO6sAGDIFOGMVwfNs/OvfZNe3nYNK0Ug1AYaQEPdIQaEhgdKIC8ILAKWIOqA3VAQQrkIxclPRAk2fNUYiLsqYIYaaEtmhQEyX80/9DSiY/Za0UMLfNLVEEcJYoKkoYAiYYsAAefDbnTPklAbMDEUWCCBMpm0wuJpBohdBoOmFWzRFEQona6Mxwcbq6VV14oDo6nx/t7ONwZ7LvBaCv01+b9tZNy0FqHSlUWLATtNCbD8ChgFTgaOBuikoIkgDkwRyHVaEhrZQ/tWAtiqwgaNJ9aoSTOzJHeREySLdNtjFGVTHINSTbRxoiIJosigmhWLjlrNYQYExytYO4gSspsk3TfKhEnvBkWBOVT0EfAoiyqUFKxyhaOUKr0tCs89bhn2lWM1+VgRfY2yn3sTcLjrh7Xbddxi7iIBVlTMTrFKgvLwI1H1npnPW8ctdxubJ2rtunT9w7v/PHGd/4PndO5j2VRcRciushG4MkGpRaGLHPP2oVdRZjyc5ff2zj/3t/+5NqlS1++8oW//Pjdgza0e4d8+eKt3ad+Mlvf3F4p6r2FPz44vnDp6rX9MR9389XNjX/wv3m6P6naEBUhCMwc6C8NuqOIwiggLGBDKqTwyO178mED2HIIrXpiZ9uCYaUkMjRwbjr3QUI59YYbO5sujmcvba5/rb7wr4+fHI7YWYSJMOvMezs/8vGl5wXl0x/8h83dw/prvz3cemHS6PmzG5uDzUnY7VVrz1187kxv8Mk77958+8MH9Z1/8Lv/9b3H9+7ffl/DdPfZrbY5/O53/+H7P/1RiP4/e+M3Zifvv/TSV66+/toVGa349ujBHX/rI75zSxAGr1yvr/9BA3c8Pi63hoWc+C6lS8YYlU1HREZz0I1mYFEpMwwy6x6Iy+VrYkonM5jEcpAM3ebrNQIhqYcIHdQCMn2wM7hyTRHIcIQSR6saNIniUu0KywARARA1cLKbTtI6YqgkXFY0aowpyzPVYKhGwBILpUhtSWQMXsIryW8jaACRiBjRwAhJ4wJAlKyJEEkco9Q7J7tYhhCyk7Mq5+Q8SiGdDIGwZB62JrfMbH0VRRLLiiHKElXEp8KfZ2n9XGdriU5vvCRmSJ0Cg4QQQkhelelD2f02s+VS+V/Ov0vzDV5u2pd1GR5SwIqyMjiQZ/46v/TQ//TQNT9pb/0mv3oSO4uStBM2CYJdrpoLEAE2/YnCgtKHrC7/EMl9Cvz5PzodyXMPBA255ibBtyKAApCUBgEIyGE4y4/mT7G8iYgBB0uooD3VHqgHHTIPgVp5fW5rLrvJy196YfvV36t2bi0+eve4v/mFV6+VmO0+eLDf8ifP///5+rcmObIrPRT81trbd3h4REZGBjITicSlUCiwWDcWi8Xmpclusu+6taTWZTSyoyON2ZnHmYeZnzHzMM/zdMwkkx2TnSPT9LRarT4tdTebosgiu7pYJIt1RaFQKCCRyEtkZISHh/v2vdeah+2RAFuySUsDEgkgMjPCt6+1vvVdXrm9PPr6/MP5wff8RLZfubY3PGtH1+OwebzXn59vDWm+6Yob/+TvDX9/dvPO4Zs3v3Jv7CwdhtVJgeBpA/NZzsutzdw9rDwyuf1b8eTfAwBaMRvXt5ur+ydv/PGBty879GOBga/PpndXBzt5GJ6/fzj49I69MallMy8pNk3dJ4uQT5vVo0O2Lm8cW5ofH7rIDuxcVUo25MG8qSZm1H/hxaWE3Eob1FqOjuGADGQhrvNuJ6NqFGwEZk0p0A4kggGUxUjH/FWiTvbf0fUEytr5fivAT9mfXQi4E2mIOGWBdawhaOfmpomMaBJ9MwXOY32ciaFQURKNlo2IGk070UhRABgkRjEUmmDHxCHQKGJlWNe1r0GIk1G2u/2FEPZn9ZFMD0flg+2Z28m2w/jqfGNjbovKMriWIBxqeEc2kuE6BCsQJwZEyiK8Jv4RrAUkxogLa2wYsHZBUDCWNACm89AKIQC29aFLDE1iTVFiE72IhH7Ra32QGGzmIGrZCCHlnLJhbcUYE2K0xkIERJICwzto3wiZjkBB0M63g1WNCosyeoIc1GPuk+SRCmzobCTTCU4nerTR1qf3G3mkvGReEtUgD2ddvr1xdHpsLrEZ21rr0TOHNbh2k30MRjsFFo/qAjsvfNXsbvj5zLTkgyfLhjKoT6GLEmyxMSGBSilgJneyd/ntH/9VsTG5fXmvPHnklzbC3NjeyWopRSE07A+HOnzj4bvcc1/e2ik/uHdvsPnS176lNF7N71kXrNhAPdc1iIkjrsoCGBLhxEY1aacWrHUhxBBLhovBWrYsBK0FOWvOIQ8iVVVbx1yGIs42bAW1DQ+OqvMNuN99ZutH7fKDem42SUSCYVs1NJzcGPnB8aPZ6PHj6n/7X9qtG+bVb6z2bj7/wldRVo5Hv/SVb80+qe5//ECCDLPis0fv/u+//6+UmxeefaEoRjdvvAQ7uvG5z7/wyq/u7l39djEqzPbRd36E05Py7LzXrHLOwqVr4fTYff03Vqzx/qndua7Bt2idIdFaNKQ4Z0VgCLPp6AXd1jEpANdriiQ61+7OqGmfiW4L0v0DaSVIiFHQihCn6iQ+L7JM2uPP7o6ffab0q15yhSRlTT24KqJiHb0DVYlEkva5hmGtDSEmxnKWGY2d2YauZzwlcCQhESE2kiqc6XgmzEwxCBEbY0RUFK33ChjudAWphhMYUQiIFzkpmliUlBZdDGFiBicDPO1uLSLa+TSKiKbNEJFGVWhEtGxDCNuXLnnfeO+NYVWNsbN0ZmNCiCoCw4gCUVawSJdzTMScjBFYNdnYrkPjLijQa+Lqeo2bNtgX5iDrATjh8dbG6JlNHduJvfSFsPemO3rPPXoxbF+hKwt4S8YQU7TaGbOkFsWmcquaqq8FXPpA1ZJhMtCs+zQSbaCTw3TfG7XQJ2FXDO/QOoYKWoHnzgw8EPlUetff+0UBtt27Vc4gGSgHCvCQtGhpwuKcceWOq6+OyJwPP3CjR7uvjTeLn01PezjtO2tz3rZ6H7de+ejwdhPks7euvfrKaeVO3v3h49Lncbs1Y7f8FO3D8+Kwvzw6mj++1Wbv7f99LhyNZ8fH572qFbEHR9fK6rzuLbk55uGI5esA4P/U9iZVdb5XbPzzv2P//D++8eCdEfMzyxeu3T8LL83pxu7+vffem5VXfDN2iyCVaM35gnxRbISTLVNsXb10e++lMKX60cK2rGrJ+hxtsGJD7Z5/bby7G6vARJqpVRFjOpMSS5yWZwxloUS67UD79NQZgBWdJzGvyUMgVV271KSkBQBIlkNCAAuJKCR2jnPrXk4IPlXpRAuJSimGHp30J0VsogPQLrrzTj8clTqWtAgMSRQWCMMQi+H0wPykzosSqVAEO2aQxCDR12C+JHZSX7t1JlWvvjc6Pxo+Phg+wFaxHUdXyvHWzBalLbwgN8IkLXkWyaJVWKWEnWeRg8aAqInGAgodDN+5oYuo6aKsGQxOKRAKoTWOlRhWElyvV61WDDBzbONaYiE2y2IUEDUhGJueGEKUzNrWt4YtExGxMCBilZVM7DiaBHDS/pEQiSVkggwWapT7Sn3SAjaPQ5QbOp/QfAszmg2W9xc85XAWsRStNefetFq4wwWPWSNRS845mdaTa2cLOd3F8HXMZ4tpee2yfumr9aMqG+bqhb3zvg7w1mrGJkTLcCIxAIYL8SWu7p9kw2f3n7k1vOK499b0aDY/2b3x7DPUOytXDw5m29vXv7J9/f2z+fRs9sKrX5xMz97d3jKD0fD2F4+OHilzK3nOrOqFuitHO6SFkC4mhXTrLoA0ihdEJgvxGbeCjBSEvrCoBCjEw9Xi5uXQn9utcz+oa0u1ZILijHsbefbt7WKX+bsPZsPdQV0Gu/C8c+P27N6j/OCE3WbOEu7ere/cLS/tb1998ZnXvtUUV+dHKzbx67/8G/NZvV/s7mwXv/0P/z7HGgZb1m7sPVN6/pXqi/Xjewdvv92/96AM7Bz7PORbI1qszLf/VvGVLx3+m3+PFT34D3+4/zd/V3QY6llvNLSiyQSdOZIaqKxtY5KPTdLcJ4+kbl2UdP3pFCYgIDGIsJ6AAQCBOqQrMWvSKjkwy9nJ4c2XXgqxMSHAMifXcw4iUIkJx0XnYQ4lIK69akHMViAiypxp59SUNC0djT8xCTUVZTLccZESc6kLMmAmwCRehYhktCZopHQeUYIaZi+xIwSjU/VrhzGv5fQdQrqucWkMWN+eYucSSxAIhAzHEKy1s9l50jxIylODptsLg1PcQxdxGCKBQrpFAiAKoXUuCyFYNlAVEctZAsg6XmX3Rli73OLpz61/N92qPmbgwK2LbiHVa/zcx/XZWZ++Hz/+J/Zq1phIZGJ6aE7bfYVN4y/Bgax0ZdYRLCzDAbbLIU2fg3uyAAZABqrrjaTvZl0EaA0IwTu0FgikHvDp1Vg//0mBdTEBW2sAS9JT9MnkpIX6XHhCceD3trBlQzaf/uCtu8ePDyeDuD2RXX/o3DyfhVBLNED0m9K8pfu3Zx/u5yfzf/3/yrGxiYJksqAtQ5dEl4Ij6GHEg9oUw8PPTPPeQbnJjysznX9h+ADLF468vcf9MNnYQW4z0+w+A8Cc7Kkdx/Z2dXh/azj+rW9dP3up/fmHb3/47ge+ufqHH5zs35RZvlOOn+FTT6WnynCwQURm75/O3/nm37u+sZtt2p2Ddz5dfXK4MzBV8NaTc/AaCpP1X30pBB8FmSWSwEkjZi4im2kt4kjojHROGiksI7nGdHT8TkR0IWLrMF/pXM4YULkYdKnDWNBFXzMhhCCagu5JJCa6vKCjC2qnkEts4k7spwJKicTJOBYUEKEIJBQQRMBsBNHAJJIeAVAEgXSxiAqwgbCyCBFZw6S6hBp4W/Oozl+fF7a4elAsHmycH9mTk9GJHfVGMrw8748XdnQOFZsrB4rCIoYtsShaiVEjQ6OSJPpzFAaH9TYkIemAmpTZxbxeU8YkGk7OPTZFp0hnVu9TqAqxABFqMnacBZUgMd0cGCy+FUYSXrJAWZQpwYkaha37RfjIMEOFiYkMJFMYUqNq2aEu2Pc15GhiJabm+aMZ1xwWrVYSmYvJZrlabbNDLRRIWyVPPfQ5VKY9ffVrv11NmxNyO7/zt6sTr3Wdo1AGYHPXFxEvTZRoNHjbRl9bYiMGyOVsdXv1Qb9eFoH+irfvH51fK3Z+qeZz1/5sXrlevjvebIN///TIwm26UTl7aMndfP2LPph6PiWy1uSt1hqjcJYplLs9JneyDRXDBFjDGjXEhmyWQL3MwofWkKrpBVEWiVBDnK3CMMzy8/N8c+Fz1964tVI7ny3mvHDYmIVVcb145XPbvd3Dj2t///0HtnHbo/7Wh29/f2uBxsS2jQ6jQkQ+PTr7+cHUI8+LMNyxbrLff/Zq7K8+fTR//3Q7Y8Razk8rbR//4R+77evIx27/yigssTmWvUm5mF75H//J6d0D28zdczfqBx8Md4uj//gv977wreXGVX10nG2MnW1jaAjMMIRWgzIpKF38QrDJ3HR9l4/r/B7pmD+pCOl64mJZR8hFRRsRJLYSoqgGgqhkQuX8bLuwoa69s9KDNIGtDagRsEataS1UTyzCNcmZiYkb3wCwNvXEQEIq00HFunZz6pwSN5cABZOuG3drk3OUMCdToFTCu/yhdKeJIorOjySRylRIuu13au9JjUI0IqYldbr7dI59ApFk8LSujoBGsZYliECcy6JIQpcMk/dRREXa9JMyEzMH6VA36JOIhBgjI5nuGjCpimpSJeOCBP0L0y4AgNE5+aa/CNCMIEJqlZWFVduQ29GX/fU/ix8cZvEn4eBLfG0mtSZLM33CsUofKyyeOOHZThD0332n9QKXu2UFAhAJyXXUAx6wyXsO7AneIXLnpSkXt57wNATNsGKUepTKfMwjcso2KLrs1jZ/+t5f/eCdA6XF7kCe2Yu75jyPpa1rTBHmTDUogG0u8Cc8ul9tXqmmmPCg1z6Mam1r4VcwlQwaX3jbC6GQugkcQlCtVryqrwxCruWXzM8j88Pp8ebu9ZPD83k5Gu8/A6C88evVsF9OP/vu9xbN8ZzIDm9t7N3e/e1X0Z48eO+dD++8Hazf59uXYp45WF5U1cf32B3v3c6/9FvP2FHWnI02r22d3nsYT88rhfRcHqnmsKHhTKSAXaJxZC0kSzTyp/3akxvq0y0XPUUP0DUYsrZFpTW8kKAtSmcPnaMidcEkyeA5FWWosmqIAKsxIXawTZa1batEmk4xcVIBEChdpd20vZ5qRKU7RNoN3+sowc5O2aQtKXHaszJRF83NApG8tUJWmFO+rhMTVYNRQfCKPPT3pxu3FuPzXnua1Q/6J6fD6XSb3aQ3avO95XA4tVs1k2dpyFuoFaLIKUaayTJDEDoO2pruwUydEbShdVJwFFhrQggdSUZVoeViAUodiVrKgigUJrMxxCy3ANoYeq4X0PoQAUA0OeyJRmG2Hc+ElMmA0wZdLg50ehWYjZBy0nMkjAKAAIFUhMgwWLUs50ScfNiJ2fV6o81RKMt84CIiABUNgkiZ6/HzX/72h3q72F+g3ukjrPJsNa2KmCPdiESdyURbiELFcA61Bm2wRVYuAb0fslngx2X591740vCnPwm2rK/tnx0+LrJ8b7wvLOG8vPTM7WfOF1RszdDuq8ynJ+dltXl526+qHC5YdoDvODOi61tAWkSqIKIlSv2HMBSGRD1ZqxBLgoSbSttvKzcPeTt1RRV6nI2eM5evP5a+llMXK9sLLNn1Z4rp3tbVzd4VyL9bTa0rnsE5yTufblS57zk7LUVEWFDx1kvfqirhN/9rfvJZWd4Pqx/rEr3ge2jm3DgRRe6Lncs3X9/4lb99PlttXh7enR7f+Nu/7V/ctY8ren4Di8Oit3v0J/8yrxc2YPjstflrr6guMDEiKD87HT97qa4XCssaYEN6BQEBCXWi0KQEbaXzZO9KHSfCUHfQO0m6KlSCqIgEQgREk6cVIBIB9aG++Y1fns9nMbSWjNjYIBhhS3HNkoUqMckFgTaSsOX0WSNJVyfGcJftRWyZ044q2YaKhCQpkKT5TVW589cka01aySYrD+oCH0SZL9y/rLUSIgUFp5NFyqQxzamdQySpKimJBqjRqCnfVzSJEmSdZZt6WWtNStvOrAUQQgSDhQGN0DYE6vSCGqNKAIx0GuiO1UWsAjIqCssXOceiQokHffFkXbCukkxKk7NeEpWt781EPoaMe1FWgDWksGYZ6xftjQ/rBweFvCl3r2OroMyT6Wz9u0Vvt+7FehQGW13LceGgnTqXqAfqQ9xTdRPo4LwG6gEHBMCDPMgC6VdLSorGUkxzv3asacXaFZEBtsK1U2TqLMNpm4MH5Aa4tIe/fOvtOx+e3byU7fTzsU7H7Zlr51xHu8h4oe1MuBIANULmQuD+YX312upRi6VutMPeKo+oIvJgKtps46qRWMNmNkSrbWjVDWQwHjmPE4mQvsf1yZWG2/2ivjqsiuwYQHS9KubE4XxoPOthkIMHD+/d5Z+N7DPjyZd+Y/JrcA8Pzt5/5/4YW/VcFsvl7/zzS1vZ85cn+f3lkg9G1y5/iUtt7ldUAuMc0YZW+qCIkO9d4qHj0BoSEwNM4sFjPZ7+tQbsKeV1IkdAmUg1Bdo+BYpQ58uouLiIaG3h3UVwqRJf7ImVRZWsYSKJAvukLKUYwKe6QRVJ29EIQILA8vrhFSSkJFCTrmMyrBo6SwFgna6VFPwUoqR7LxCByJIEQyHx+YwCzMmsKrQBWkdvS9rnwbVZr83io6I6zGfHo/lyXDdjHgUzqQa7s3w4Z16JkERrYSypGCUiFgsYttpZRZt1ICIzIZEhk6uXb4lJRA0bUkgUaywARMnzvK69ZWYmjcJsfN0GKwQKMazxVSai3Lo2+Khph5VQn9hxOBJItx6CmTofoeTaY7KkNk6Mi1Q0IkzMjF2dl029MmREhI1pIaFtJ1tbZbUKbTC03j9w1KZ+/evfkjb68yq/+UJ8txKT9XrkCz47LQeQLDNijQhItFXqBdf6wGRiGJJ4XwymL37luz/+ES9OvnX9q8OfvhP7A7bDWeuk8p7jwmfvPLg/2n32m1df4u//+czZF1579cbNz//bP/z9F77wKvmQWwcIMbt+0SzmzArpFhainbiclKAsFBLKqiAgkjH9Xl6vGo2tUSbypg6DqiyYRWpwIJlko8tBcnXjpd0odbe+dmtR3Xtsw3h0NUx4NnvfXbV2uLdXHpW9nx2gyOPCqyeWEJiyKvi7n23/H/6HO4fVxvz4+j/954//5L/Y+Yx3N6rv/9nml76yoiGKyXC6bGzdVkech+PleTZp5dpk9uB+jqPD7xzy/HR29Gg4hvOGh1emr/+q2MKUlR0bfz47/uSnuy/8DfGtZza+hYWIUwnEyiTQVpOtMYTIqLadkhXd7Nn5vFIX956GY1FRDSrS+lYkRsQYhTgdwmgt14Lcba6qk6xv1mRyXafjrBv0ZPaZSljSqoM0SGYzIFo2mTVpN8NMySUxdqvhDq1K0b5MbAjGEJLoPiXCJ3EexXQ7EdLkm2hTsLbCOudF2hiMpEiIRAlJlhm0ZmuB17g3wElp2aWtqCggKiopoNuEEFL/mlBo33qT2dSRoHP2SKQwEJGwSkweWGRAUSUktxQlS50kXxUiwbIVDVZcWgJ0d0+9AADTIUu3O13fFcmKCBkvrYOLFCOMhUYKDZtfCa/+u/pHy1x+svzs2+bVSusicrAsYCIDNR3KTA4oiFhzcA7JgaffHdCH5qAcai5qsCavUDSi7Xr2raEeXENWyg2hBgAYoLbiewztwmworSrTKG29U8csrI2Npm/6Q0d9afL29//so7YMz35usi2P97jqhdVYaluxLEjOhUsj89iWSmALKLEz8aQuwlKEesb7fCd6Lm2UDe7PYWsMvKnqeJ7nTdMzRjUDma1eHiseuXquFBqNpHUIPdvfGGqfAYgN/eAJ9RWqT3xYeQmcN9zmpZycPfj+HYwuZ59/Zufrr199/8MJI/vSN+fV6nx+ePTZ3Xht//r23st1NOfT8+M77/e8sZWnE81ytQ03O8GONvvjweJMkCWv1eRb9aTt4jVHA93Z0bW9Bq3V20/K9MW0nBz/kljnyd8y0Tq+ueN9rMODrGUSxCgwpATblQcLgSWrKjF2PXeUdTpnELaGOe2lu42RqiYvFw9hYmWNgAYR2wVJJARLSbVj6IGTCRwxhBCUIcTkWTkQU4ykNmkjjUnRaYHbGEgb3lsNrmWjeioPNhan/cVZvjgfLu6O7VCKy/Ph5WleLICmZcNefOc3KZwOMnd2JN3uxjBikhKqgCgGSTX4wng9xXsZl6lvwCqAiFhrmCxBDCi0UTuUS9RwtapMnpnEWOUkEqAk1A7JSrN7Saljs4oGAgg2y0IW1EAZDLUQy0QaMzLHJ0fRtxZWQ0yi2mI4nC2r0eZm6WeGjSAS82rVvPLKy5/75W/8xXFQ10Q/y3hIMagiN5nZGDbns9bXlsVaFtuzjSXODPIVGesk1hi+/OV3PruPKN987bdumOLe5Wvx2ZuXPvno+sbozs7NsFh+dHh8ZbT1+f44/OUP58/dvvGrv3MC+dPv/dVwNBz2RrNmSq5H0lrI+aLsyM3K0ChM6U7OolBECSnPjlQSSVw0hMW54Vwsx6CDatk/r+yigTi3aWTJ0nKoJBzNaXm8svuz69ftfr65HEt1L+iWMbtbu5v5lG08aUL5MFvUIVqpWuXMSLAQI/nyk3uz/++f73/96+Ltwz/7bv3OW8//T/+Xg/vv0u7uxm/9rnyykB6dn/z5lttquWLnImZZPZ2/+W/k9F4YIO/nmcmabSZ20GHztW9UstOXeRTkxejh/bf7I6KNjdAse37UZrVRAwaRB0mEJ1iGUGdwmqw2QuqXiZLiNo02KTqFEFSUOhWvJklC1BCog2GjSFQRx+K5iRyqmCBFw6Shk9ESQCqyhqeEmTlxgpnBBirWWmcTsQfWGGIyRKkfiAIGxPCF8RJzYmN2AQbcpRkkJN0QSEUgUZST/R6DRaUsSwEYJiQB+IWPBBidlRZzQgAMM0FjYGtbicScTKtFRKFsWIMIJLMmhlYAEcQQQNaHLu8IgMbuJ01nNX2bCUwwWRY9kFAYxCAgIaPShkDsUsZEgJikiSICENO0yIzEYkWHQqW+oPPq7XJwZO3CCUPGSztxo5fba3+Fo5/lj55rr+zR9aUpe8gEGalVGKu9oD2xQ86i5IqctAByoADSB32gDy2AHlAk3k96p9a2FAg1oQZaSANqQUtITVpBVsqZqoVUIMCETBE1aTXQIDZEJGQCGGxsofmQeOzqgSzE330s7z0Il4Y71yeZbQ5jbFZYDXmhvpbKYim6pLAQmpMtFRwFEcxs42nYkDK3uvCZjT6KqQtytfNcxRkXhfYtxpM+oX/SFpbmUN9a761VdtL44FYBFIP1YavMtgsAnKvMnJQ4aT3yMPD+IIRTMUPwtil6Jpgz+uzxSWWn0nt8reD7P6uPlvb5K8NXX32mP7hZhzG7+g/+/e8P4/3dawPb9v39uRbW1G68T//5zgffOFtJb68NuQgEHKkjNiXbEknLxggEUCS6QJ8pdbKxk9Sg20d04GVi7XcQMXXG3ujI9QlTJlUmIrZxHZeU+BNMKZKS2LEKDCTESMqp49QgzCSi0rOIsCl7kjXJ36OmPVd3gUhIzbRd04ApMqBqjfXeM8Qa9q10MgaoQpKHC0vaepsEiSmrSkihLBAiCEFrS4BYj5vHG9d55HM5z5cPN87PitnHg+mn48FmO9haZduzzUEp/aUqQXKqjRCQtYSMEhU3xWSmZCRHFFVDZk1UjVFSV8+GgkLk/Pzc9fKkinDWSGiJo1orUKRFshLIiApnGUcR5gh0frPaRd+QxAsHPSbqqB0My6wgimBNtp4IoKDWEyJ6nNmD6T12toFcv70/OzxZzKq97XE5O93b2/nwuIpZQ0UmOSMTmOLcZ1EEdmjbvgQEBolQhKqzzkqrTVu2IbC1GRuLgR2NeuL6dYy3Xv6vj47PDo8dFT9+++03XF+y/ucrXJ1FO33312++3AwWzjkHq4Ph9v/p/+4m/bvvfPCj7/3RN3/t2z33uWVds+1BIkcHCcZCQogJ51IljZZYmJJDWdJfpWgNgSoCI2OwNz7zGJTLYr50rYeAeFdq4/uZqyzPagwLxjZ29o72c5st1PiMKh9GubsKmg9vfsWGnz+4fz6/yePerIbhEENLQp5bir0ib97/fn33HQR2s3nB7uTtN8OHPy+Gk+lHs3p66HpAQc3L13rXr9DQhr+6m9tTV83zS3k9NnBRhQo7rnx9Ohrm13ZxNMtcUdssrKrHd/7qC8+8rEVtnY0ABxMjONkpw6uY1CenXD3RCBEioQ7WXfe2UOKUayndWVZRCBGxQYyppkg3a0ok1roqoygkMgyBIKGLAu/y+IjXwXy0doF8whUxhrqOMjEeUtwJACgjMZIlBqzXx0SckFhdO6unMOB0jEhBposTFAERYrrnd0QW0uRPgI7MmMhORIAEYcvMhlkkCkNDICKJUXFBzVAw2LBEjSHGpGzq7LAE1KVKdLdI1WTzwZ35RiQiNmY92XBKCRQJUQiwnL6uEHdW02nTyhdAYdeC/CI22d1W8QufTIChKtlIlQtf0Fsf1dOqsG80n/xDu09iBclHoCcwwhnQh43sSArq6u4Qv/BBqsd95LSyCIaUIUyRRTWzPsvrDdMEww3Ys/QUjZqM4Cg4wwYMEUiQyMtemwxHKNg8A+nAcE9M6MnDkt87rue5hD7Px6RX7MYVY2QRqgWr76Hs6bIPTyXJeYOSdE4613guVGMdUI9om1XMytCX1dSXNQxYZexkHno5uJaiRt6gf1g1zw5d3LAsUldLmhRYbQQ3t56lgaq4fEBjCkUAwMPc1gg9S/WEl/Xm6Oi6x6RUeFEJNey0ws5oc5wxehu5W4wYm1v2pS/cHI2fL5fjYiz3Dg9Pjh/vf/GG3eL+vCgeA8Zb4bcfVtdujwbBn+a+1aGYTHTNDkrchPSu6xd9jdSsB07qelJacwGeev3/GmuA1gfq4l90Ir7kOSOJcEkpM0m0o/Eri0aYjGOUPHOhDWKz1rfKCCJJBZEmxJSPlLHpmJbrO4l2XBMYQwpKkoJUy0UQJTKxigpi5wDL3F38THk/994DnWUmFBBiSIRGIquafPu8IReVKtmpNm6cbC7z9mC0OB0up/nstAh3i8dDGV2qhpeqfHwm44pDZoTUA7AskKhq2YBJJPGSrUUUVgNLosIBIUYDVnZZT0KHGIYovTzr1IZEnXE0EgrR7QM6pUfKwVAVFYCVOL1gjMgUQBYgWc/kJMRB4Vk8KhSV5nMuKgwXdFq75sZrN+7O7izC4ku/8Ut1JUU+KO7b4fXhsNezEzc3FU/Q28t/+PHJt7+pJW8vdRhXDZd5tiStmTwsYq9fZAP2oWh8u2qXITTBCtcZcy9sXz5+/uXyrTev3/6Cy3KrnHuZBDs8rsva2b1b2fj6pWcvr/pbO9d2W40f//zjt//Nv93cH734wi9f8uMTESO5Ah4rRyzs1M8VWQf5ISbvYNIggBUyXXS6tAqrMMSRtc7VrcLGvOJlnZeeBJEL4hiiNQsfzzyvCtZttY6qUJT9Yzcss17j4MxWMVw+XJ4Mt25a4/I7xcaHO7ee9w+eaadDX0mMtaLmDHXoDYqwImaPbevsVvnWX+Q17HGY3/vXdizBtZsvfc5ctYuDN+nwo6E/1r2i2qKcgi0q3uRQFPMV5mUV9qHj+TDP2XOeI8x5fG1Ht60Uph2IsTareisFiQUqSIAaIKqkzW5qoZMep8uWVwnrEI/upk5MnaI1rotuIvKvrX9TNCYzd66/XayCqgoZk8Lb0ZnbielYyyqidj3yJoIScyLCkrGG1hmC4JR0J4azp+8u1AX4dCbywIU9BcNARZioQ7yTFVfS/IAMJyWworN5vaBJR7LWsgG0Dq0BWeZGA4PjmrGMNLMGuWgPDDMUqVEWFe5c79PejdYjydrrD53wK4SQfHYgiXAFAokIkyTOl0TpuHBrttMaFteuLF8U3iexMOtP6cWXZFVVG6LaTTN8Pd78i/DZUeHfmz98OX++DC2sg2SZ5i1bayA5oa+ag4aEIX7hvQANtUA10EWhK4tgujTFaI1KpFp6Nfdrk9fDfi25OOYlxILPJYNEVVFwJKnZDXQQnCGqW996Lmt7p9SjxWqmbj4Cxs5mglyKEaOn8DV0Zah18D1IX70LFdfQJeJcZSFYEEporZFT5gcTokpv7t1mXa/Go3Dzmh9Et9kv/VDqyXIuMz+ELAfWTc1WGETOLDQ/j8uBnbMaW8E7r7B2k7QnvOUAsLZg6g/z6KWdW1sVQ56KPQ2+Lag4ma2GagcSy3m9vetGeTEZ5+bW5w7uLqcfH934pe1gwHkmaO6Ws92t7SKsXMahoFmYf27kr7/0xU/6RROtahaUamNDzKhN5F26sK4BrU1HuzOQhEICdHnV9BRZa72t6IzKtDvS1IEnirXBzpOeLYWJiYI7skwHvaiKsEBgWJLyPgHlIoKQ/L4FUCYjRCIS5MJtPe380J3llHbIiMmFquNqdK2DggSwlNifCiCJmep61Xmzo1tfMVPs4kw7R7jOYB5gphZty+IqPFNtXOdBncvpKDwczqq8+qQ4+3Qj29ge7vjheJFvn5thndXwYsU4IxAEtpqpaKSWmYg0QwxQ5Qyc2ShiYmxD2t4pKRvTyxygoW7jWpslEIoAEHn9wmlKce2G4LUDt4iapCgzrKTCiawta8leo1hp9FzaotR8qoPd3rjO/cHJw3y/f/bg7GePfvYbv/l3Ht9/PMXZS8++MhoMett2enZuNrPWbR6X/F/eeu/S179RHmeytLZWWUbxjIC6WpydP3r04O72lcvjrdHAjaMGNyjqbHMhPUxPBm/+6Jt2QxY+V/HFxG2MXP9y/syLuLKXO+OrZjqfbl6a/Nl3/vjk8GBSFBhe+vav/O7hH/zxKW+1+zuo5o6dNRliC23VFIhtEo6KkGorokngGg1xG5REDBNbBQeAYrCVz8s6n8/hRbgAlMUHrFgU58wDyKfnNnOhiDoUsWTVVVo8GD7vkA9djTgezee22hF7qS+D0fsbg498c7ku9+vjSX2+Fau4RKgqt4T3rEvU1amd5FwFVG5UCDYdBlzP78l379pNtiOzGm24bDkYKHLTv36FY3X04E5OBY1i/7UbYXcEWD0LOG9jhv2/+y2czXQE8WLnIYgwMa1yhRd16KylfFdT13DUOtcP6IL2ui1IytlNA7CoRImhs0hdM6sicLE+1Q7CEo0AGcPO9VZ1lcpVFEEXWpSAH147mz8hZQjUUpp/Oxg1kThJeZ0ND3QpQxDWVLeIYAxfdN2KLr8vJeKprCVNyScnBhAZIrYsMf2lKIEzw6pRIlm2gchyZLKSMrM59fep/5AonLE1NoQ2+eeYZB4bJeW/dSgfd7SVtEKnbnjvsBgDZmbRqKRp6I8qDDFgJUQVUqYUgpgepLtzPgkz/v/zponilRTfZCm4BTfPZ7fuzE8O++UP7b1n2ysu26oDszUsjtQgV+4bGQbkwAAYAiNg1H2Q82oDiyGWAyyGVHYTsCpBnIRIvLJFhV6Jvqe85v5ssFH1hzZjISjEwGTGcqYZxdkRf3LkP5u104pXtYbQKhPMRrbJzgk5TxkE8BBYDNBarTOqnS57WuVac01StqiYa8ZStVReAjWki5YQMK0QfIUQREbPXf32310M2mLHlPW204l691mcnB2/XXznfy3YlmYzvwR4euzdjQbiaqwGYVmxiG6pFkQTAiCzYJ2FlxArY51pLOpLWch7dm7a8vmt4VyKFQbSDyvr/Wi3blTuNp/8lx8+d/mqfP0FZ7Kjg0ewWLTl/KyyhwiBRj3+Fy+NJq+P33r+1SWGLK7NjAZiYQEj+eIEUGIUJOebbtkr2kn01qNmujxSQ33B16MnBZifTM2p1nZH7iLVowsMSCko6fynJjvxMg0kBgJLiNaaENS6LIq4rpVWH9ogsCnay1ofAnAR6ZXgqY5/lcBy7e4ZpASRuM4QZQFUdL3y5qhiYY0xneskQIZFYIjAlJziI0lyk2oNrBIJK3hphThwEK7s1WVx1blQ8LRffTaYzgazc3fGl3rDnXy3Hm/P7GhmsTBqwBbB+pClrFHOkq+J0Z6yNwHwEDZsSDWKsGGFlNXSsiE2JjHKFZEQWUlgUhfRZUx1Riga0WF0AGm6WtNzrEoxMbYlQDxkpVqr1qiGxSIMSupVPMy3r5TTe/lW7hqcr87+w3f+XW4dJu3u5/ffOPzB7es3+4O+35Ij9Ja9K3/+xk+/FN/kL/0jx62sQt0aU9e52/roox/97K3vBpbi3nB3a+P5F78WHfzhvSt7z2z/k/9rrE9YLLN1bEKxtb15wwxs3Zrzs+nJ3R/7+vQn77xDw/gPf+f/eOezt1//0utuPHmRt2ff+YPhlXHz/M326Dy3Q1GPWIUEF2okztLLzQyRKOoBYTZeRR2sslVWZlayPmjTDmbz3vwkUyEaAkEs21bqcE6IfO1zPLlWn9a2d8q7eQgkhdGEaVammkvjRG0xm3o7s6Eca5HPXcFq8dBNDmgyUEvzs0vzxYbHcO55Pi+OV9l5207n3BhmHzJhG9zQYQfoWRk7DDAYi2xdyq5N+jeuD7Y3w8/+0/UH90xvfOKFP/yT/WuTgwrV5u55aNrGDvqb/UHW8Nz0OfqgYBWNtSCyrlU7QXRtqYTY8Qm64PQUhbMO8iGkstO5MQEpRKXzRe7g0HTk2Vpf10FiYi9DNcTQtN6wTcpDSQldIpR8JrkTHZlu+aMiQsRdAhJS4j11HuZPELWkmlgn30GsNSLSZfylfFvpBE6J6Slpgl4XsBgFhi+UG0gDMBFUAmCZk4MziVCA0DqkYQ38pkVsqo1pRxVCTPZAJj27etHornVc60Y//WhsrURIghNUiSmqskQGiaqKIAZmNpwIKrwGrtYxbP9tudVfqMrreZsVABsbERAjGYfsq3j+351+X/b6Pyo//Y3sas2tlSwC5BTWcC5xQDQgDFL11VSDN2mxifkQ8w0shlSOMLfJ1wXKKoYoKDWaN1Ss1C2lv8Kgj/BY/WK81bPkCg6nev6w+eyRPDiIs8cZ5sztMISltWDrLVtENCzBC3swWKyITeF6jeOA1jsTLXmHSjykIQ7CNUkjUkE9qAaxmrRlgzibcekjU6hjexztcjVrYq9PTD2KPBzuVKPnp9If2mKqk6FpJ3vL4/O8bPsucFX52AeL+AHMJstWBECVCyZE1OQyOM+zugiSWc5ku2d2phQrB98IBNVi9LOzkyvFKCtmzz73ZbdZAKjr87feeYOLzDCkZ/IbfcraW7stXzHvfe5b09GzwZsAFqWS+hAXlShAg6YyjHa9D1YgOUKi23igK2kXs2y39E2Xxbp5pTWKnXCvrkZ39ThVxrVGkDq3gJRV0q13mIgpU1HrWLpfhUUyazVIlAgmKyJBwIatASgR/buEsYSVQ6FqM2tt1rYhSEjaPHSe6520IB0wVUEUkAkJdCNxmevlblWt2BhEElIwG8U6ywWsFBmUYndBDrkaiT0EAoS5op3l5u7JZlO0j4fnR8Vi1qvm+fmdvWy4O7jcbFxe9IfnxtbkyASWwK0akzJ1ffDCcNqP2sKo9+tVNNhaq+mrr59SEjBIkvctlAmGmIiU09adALVqBQBHIQMK6VbIiQ8cMgSFB2pFBapQbgz72CyxPAqr4bNfOT9+KCqxbSejye5o9523f/b8V1+UPTd4bhTGYXdv961702pwbanjZXbt0Zs/xU9Oimu/2+s9I7HBqm3a+kvf+qVPjn66KsU6Zwfbo/H4e9/5Trk8oi+G27/0NVndKGNtheEKF+2HH909OfnE5u6nH//wyrXLtz7/fDMqv/KNr96v72987vLtX/saDs6Wf/KHxWRcv/5665tinIcGaFgBqOdQi3UkrWoAJeid18+WWhUWi5SREcRIMMu5m83zap55BOuYPEnkkEls2Q2wMdBbV4IbYWbZjFEhLE4cD1FlyoShyapFc3jX9alZzu3sxsj1M93wphiC/SB6w7ykgO1NCVcOy2AqK4v4yvaeW7Q8Fz2s4tFJXmjNi8Bnw53M9+rimVG1mccReiM3HPGwPrw8/bQYVid4kIXZmHOZlf35O8btP1rMlmZkrg4Hq/7R3U/3b94OtahnDQqnakWbBIEke39NeiQkZvx6w6qQC0cc7vjPyaVCL5gfqSClNWfaYKahOsusb7vaqdKZrLJlEUmxPaJiwIASmdRcp3qsmuDlLg4wpgqdVFLdF1Rdo2fcOdd2SzAFQozrJQsAZTAZo90altadA6+hWRjDSlBIFE69uU3VkuDIWJfVTWMBEVUmBkVJuaosidWpujboW3PHNW3KU7MriRCFRERJEwZ3MqduC94FmXXQmqb/9Qu1EyqISFT1ZMhFjKTK+G/LLy6epl+syh2CKATLKkxtaPb7+y9UN+5Mjz4Yls9XJ9eHN2atZuDYY+TQgkwPKKBD6BAYE2+EMWYTnY9ovoH5COcjzEeYZxosQtpVGq2FbI3hCsOF5n3JV1xkXA/7O+fR3s2H7x609+/T2aHVumdZZOStkKkktsZHhoiSF2nUu6xQsVRFscEYb0IdAmceLGS9sFf2nDPNOWOxCBzgSHOC1+gjszJDEMUSS+sKjUJ20/JQAbZFP8a89oeBRxG9o5NgcekYcpLtL0MpYHd1+6A6fl4+q+ZePVSgQ/giD8wA8lFdSGEL67kWRu4oPzdtoGVTLZeBTOE091QBLrPIjUoOm91ye0ITb7fpo/sHYbS0k16cANsIQxX4s2vup1//2pRejWU+LwYrv3nCGyvamGKkc8WKUAMrRQO0QL1mmIsmklBn+9nl/ooiUuJhKdbQZzq2igtI5qkL7KL6XrRuRASzPiTobg+JSkBp2cwgWIJYQuQOOWqzyEJODFSj1RgDVJ3LkntrFEmAWxdyTRSDCGKMHdMzGdSkPO/1Uuzp712ZSSQYa6LERVkx4SKHG0yqaiMHEoAyJa9wYsFJMRGE4CKE2cKJ+jZrM1BW4mZ56abZmvf90ebyxC0W/dnH/dOP82x4aXO3GU8W2faiV7QsypFJDIGMlRjVkzXG2FVoVWJmjSXr2DJzjEEIASKAU7CShwbptki8poSkYw+loBFgFmaGgRApKIoJJKzaasWcAyuWpSBDyPl0sNVTz7W/ORkuL30S6b3xFh/Pp9vP7P7j3/ln5yfVbLy8/JX9D+9/duuF33h878dV3H6ouwd2u42jX74zffy9f10MX+g9/2t6fZRJ9uGHfznDnHP85u/8zRvXv/KTH//FcXlAcOO9a5++/+EPv/+no81eaPOz6fnv/dN//N03/93Nl65vX7uMOX/x1786k8Xz37r93G98A2F1+5euHX33j+vTT/b+5q+VH97x4yVLDyVxUC2JV8OmqXu507ZqtYRaJe1uZjCJNiugCCGxgLCv+vPzwWzK1RIMcT1mixgj1EBlY2TGN3RjLNRKecICW20106UJldgqhAJosWjleGqOzoVDlrNdDJcy7k0K9PxBZmurYJOZzDZiF1Q1ozxIuL2/X4QYoo1ExBs0uoJRVvbmh3rK273hrV5t4oQe3LB+uzffK2cWx1cn2fkP/u1NPlX2gfNFfc998B/MF/7BUmF7tOwVfoDBs/1V4UPd0opscpGFBDWaOs6kAScwJAXvKCR0/hKSdEgpXoi141GKSjpR6ReoMneRmYkPqdAYYwghhGjYcrcZDUQ2lYGOsQtNZjMJj2Bmotg9ZtoldyXJYO2ZzF0VW3f4aZMsaXMvieaQ4grTY3UPkgL9ujTdLmMhQphMVy3XFVDWZcyAvASpkx4cECVRmI4AJYlmkbghZFTVuqypm8YHY5jZJpNdWm+8NFnArmleCmXYNQ1GWRVExlhVCSG5zqbdkIA5RiEWBmuKs0kLuTXyTuuynzg06T7a1fqnSVgdtI+WTE9BYgJbT+2vjl69P/0LP5Ef1p9c8/vR5pklYyG5as4mV+krBqAR0QhbON+S2QRnY50NaTHGbAtnG2GRvK6SIzi3mRifD46G7mTTjVo3WUh8VMe//Cy8PVu9N98+w7bro7/lY/ChYWmkthBDbBm1JZu1EHB0EssAU0mRmyBt20pOPVFE6gm7OnBAFjTjDGQRlcRGMMMyWZCFsMBCoMFltp4Vslr2hbcK5DZk1jezEB753i+f1BuwfHJUTvjygtsj2S7sCKGXhbiov+iKht1KrAfFxg1XUowsALjJw8gCG1S97Ts5CzxGPfXm2I7UnLQ+9OEMrKr3frK5NS5L+fitj66/3PvwT5771f179QNMYMbAWCT35aZ74fdevfbCN5ZVcViqtbGyxcxuzsPGuR2Y86ALg1K1UqxADdBAW6VA4pXhgUCkqrKW40d0K17BU2+cYrPT2Vtzn5P5WLKxSQW483LRXyjGqrrmYBDQRQx0O2ZmQA0ZkAolFRkkBAmRDRnLELWqCeAJIhJjkNhh4arSGYCsJ3doZm0bY/KW6uzlkgMsASohRGtN27bWWijDcogwrCykBkqsVklYgUhwArFgMYElIGYKJbIqYgQZO2ZWrm1oEFwIxZKfnY1u2s2yiKfj1fFwPrdnd3un94ZZf3t0uR7srgbjOXoramFaw8FE00YfItZ07USs6m5GqdEQbdNTK8rJRV7X9I+08SYBhEUFRhKKZpIPTiCpVQCw+h7VhKV2TuAz9a44c2OnrQ1NfvNrnx5NMWxRND8+vtts8Yu3Xz7nrJRr758f7Y4+X48Wd8tiZoctTT48k9tlsVtxee+d6b33s+dfy1/+8u1vv77/6o17H7yf792sHD+cH8RCRo43Jtt/9Id/JH5+/cZLzRxbL+28d//90bZ97dd+Swb0e996YePWtf1ezy4eHr7/PX9wL56ebP7SN4ev/Hr19v2Tx9PxtSKcS8gDSnKcRfKsNngGe2jW7UYobVNMciJjpCTT1tVVcXaWz89tW4MR2VFYJYqoIqjJ6PI+NsfCFm1tJW9np7WvlYfO5XHO4udFW9bVCcpz1hitkFWb5W1v+pf2pNoZ5i7PhRmtcCV9K2iKRkfDvRtuHBbzkpDzlMxyZVjmpX1wdMdeLkbDDP5suze9OWi3pSxWjzM+fbZox1XZX3wy1KUP8xLhKoaHpx8sPvqPk+yZ0TXbjLbmoT17+bn5wWO2mfSDD+DaaI9NA61Tyk06hqxKuvZj1+Q6ngoBc3JrFU1x19KdIxFAVSJU2HBcky0IMIZTpkJKEmRAJBKRy1wrIcR4AcAma+gk29VkRsEkIYYUoJR0eEBsRVWZ2RqbfFw1EbGf5BGlK592drfn84X33trMMHcgM7T7ctyphEGxG8SjwHRZPF3R6tasmhFrQrETFwUKFZLO1N5aG0NMUICqxhDZMNJDx2iYmKhztSEocTIGMpYBxBAT6SshZyCEIJwctBQMtobR5ZQlRIufTLEJPH8yHa/zGdKgvcYR5Yl8ef2qwEA146CwChhCHfx2b/eV/PM/4vnD4eqd88MXN1+pTEk90hwmD7Fgs0G6ARphhPmWziZ0tq0nW3S+oWdjzHrLBjPArwtwCx8a52gwsTTimS8PqvqdafHhcuszicHics4Z9ITHwbP2WXM1uYUNyCKcmJrgSThGtrVoT5gE3gf2TJF9E3OXNYR5HQrrPJnzshlmaBtvjXHOegoB0VijjsAgQ9awZ4ytuHw5zTC6PlmWZSmfZL1FtfnlDz99uHnz5jmy8/l0pls1UNpxCQmGC2RheJXK6U370PuglCEWjdmo/RmAGLeujudi1fVyDBszyJr7sWdyzoLr0RZlUG480DNDl+WmVx18cHu+Wr7863de+D9/+NknZ/5evt8f7A1OcXL1xVf2XvxbOrx695PHZRzMn3/Z331v8MUvHLtxiwGV8KU1paAkqiAVdKW6Wk/AMQh5aMtrw09+wpO+qL5PynCHheJpnXDiZD25SpSe1glfZMc/oVArCCRdq3oBgiU827ARAYGsNcyQFMmhHEVYNIXuMiOkHlxiEOZkg5W6Z00GW5qGxdQcdLB1gpSIoBJj4k+IovUx+b2r6fTjKbElxYcJS3LzyJRZWa0hTRG9UMMQlbZ21gZBZIPMCAXxwc7oxmL4TDaqiuZoc3nUrxbu5G5/enfgejvFleXwWlkUC7ux7AUE1aCdgghd+BqRiSrpbiLSAiRq0q0GShcTDbOg23FzB8gF051ujcqqgVGDAZ/p0ih1e2+yBOB8d4ic63p+Y+crfvf03ZOPXR6LfPfgzvyj+uhLv/o3Pjn85AGuzjael30+vHPY8o3ywRIndFLJdjDhhb2t86P2wZvlo7fKqzf7L7z2+a+9EGRcSfzWP/lH5clpcxSouPSt3/yb9z76wPQ2rr0yeebLr7b95htX//Y8BtBjtOXpG38Qp3ebzPefu2Zf28ppP/vtr82+/6P+gx9sfeH51WWFbe2SlQQUVDga8ExsmwuCSFSNxtq0yxMVgoKFfd2bl+7sxK3mBgFsRRClccgFNSzZ0Z4Xzvq5DCyvoJnQIDcnkdtKrl9rVx7Hc7sq6+kBsDRoTcbiVDPY20PJi02U83z5jpmXygTuM0wlGNmtyfiZIh8uan/eG9u6skRwxnA2L+fF9nj03DhuhUERt8Vn9UmO073e6kbPj/ik38Lbl3Dvze1f+eVNH++9+ycuHE6mH60wXvzsqr/6jY0v/h0z+NzJZiZlMCuhUpGzy2JrGTAGlsmSGtUIsLLR5EJFRkEqMTnEQZiMGGOeMrxDEIlBNJIqJApRMo4xyiZEuJ5b1U2SLSZJIsjU3pMIJ8GuwmYmhdNxZq1QoLTzXHNLBL5tlZnUpH8P0SDKnOyhIZ3KkEJo014pSjyZzqBpaRtAFh1GHEk4QgKBrKEQk+uHSGRK8zCriJKkRCWltNrl1jfWmg64ZooiNsVFMUjSKUsOB8m9g1PvYtAZCuCJSLObHiSAGJatMIgNkgWoUlJxJEciSQUfkG6bqwA42X8QQBBhg7U94QWHdc0XTX9kfYpmwxc3z7SxdwCLjblk8yBfLT5/59EPy2cGfzW/95xcp0E/ZK3LouSOBh4Fa4EBVxPMJjSb6OnEnI3jyYSn2XEIi56cRV4ieDFsC5VM3bRpP/2o/jjKoSEZGmzV207Z0DQYEm1EvGJRbEo/xNyKCyGPhTctsuiU60y15ujRulbUBMQg8NbWglDXYgcqv/rC6LO7i/OK//Frl/Pz8t1j/w++du3tHx188fUb//k/P3hQV7bIVXLjgkKY7bA60yyE3LqN/kk47OVxufnaOx8/dvnevGlqGFpUVZP7zE1lImxjKDLxyDDF12N4M8taaaPwiMmuacPVgHm87UNRWpNXZdMC1NLK1/XCZ2ztcCS5Nc6Jc2bx2M2bqhheefC9n9/4O2/KLc5nIfwwjotvfP3vjm9+/aNH/pMf38k//9XZldc//u6/f6a3sRxcmtejbB5iLaggS1ANqolrRU2UgOgajKDJ6lNbUFIpJaZT7LgM6Y/pako+J6nIpt+e8KmfNu8goaev2Kd+V+1KMjOSmdMFc2RNn+hoDSnGWpNNbLqjdDiVFbHWxSBJHywiDEo6WlUQm6ZtGUmIiyAx5bJ1LMsQDbMorLG+DbTmaplU6ild6MSg5F6QUonSLEpESM1sZjNGVCXDbLMQgmpkJokKAXrMUZRjE4Obm1uLyW23O9ssjwbV415Z8exef3pvWIwvbe6GYnRKw3mWVaoQtUYcHBOLerasohoEwpY1JFkEQ4TAfdtrvLeKwMwESepgKADDrBJBNkWHJckka61VXxmUsS6EDLEEMe5si9vREKGyz//GhyfLsWatrIYFtW3+g3//o5N5uHLr19/81M/yWzzekQfLUVX4St/1/uYeuwlXGVyWj7xIedf/6O6RuDiamHzD55fc6ApPdurVcv/LL9z8whd8E+Hq8/NPsrt37ryzsP2Fbx/ZIYZf/ZK/fWNv/vjmP/vd6fFH9Z2H8p/+1ZVPP5BrV968Zq9d4QrBFM70mPoQCpYNAuu8zyGgFy1RaFMYLhNzbGpbV73F2WB2wvWSWFVCMoHLRDP1K8sKkcsTysZBhNsaganpcTNtubVbYzV1uzg2B8eympuy0czGvpUYjTPixE74fmHq0SUZx6GTLDGDVWQ0LDZvPLfKJrPIM+GZMWeXLpkxxxMKj3X1GHYMz5566Meziat3bH3VNns827LT3qyVeb63+/K7339zeL+txuOm3N6dbO9i1oazRzRRtxQ6dbSzwdVyknHd+ibvC5pa7MpQQdzkzGAESYYYGkEsZEWjrI9dt/uhTt6TjlLCVaLEBIUKdV2cQtJ2vVu70rpPTjBN8vxHNzayCK3pHkJdCGLi5CdndgBtFFbpfK3AabdHzKIIUciQqsYYDXPbtsTsmyaZY1lroRJCZylAyett7bi6piCnjVSXD5FILB0XtItk4yAx2dWysBFc/ETd5ja5yqXV65Px4SKkl0wimjEpKZOhdNQBBwYQVNZPbxe2yMqcjLwSITzFOEAutL+cokr5AstK/SO6SSX1LkD3cl0A0evvSwBGa02vDhRyA1+rG34je/UPZ3dksv1G9cFv4qvzXqW93PYReozcmg0ZUjXAfIDZhOaT+HibZjjheJy3M89H1A9UcL+tm49P5L275VlN9TDDtgx32TQSY3STx8GiBVdRPVELO3d9DJxUtVk5k6NsWnaAGPK9RpeFsvfCjaEcVq0E+MCxtdSawXiwtUsfvIcXdt0Lt4qf/ujjr39pWzO31ABnv/rq5qOjxxZGohcbPXuxdltOna24bzG8PNg1G9u37h7Mbtx6adq7Vbqrj48f5EsJZU7AWbu1Qs9rlkXKLTeTa9W91QvDxwE2IBuKingAzu1PcRak2XYyradtGVAF8RwlIHdNMJZccHx2cjwYb+3MKgsvVcgwgSxXbd17/tsD3pvN/vAw9Bs/LAs3+cprP5/lP/mjP/zaoL0zL69NXeYDV8Yt0CwVNVEFpPcVUDO8Aq3CA612469IF4iSrlG5eO2JoGs5QFcudd2oXXzQndhOUPDU7vWpN+om3Scfrx8vdYmJ1bou1d1SB6rJEEWoUyvFZMUoCb5GCF4SUQMiITgyAYgxGMN27S5nDHc7FmYChyBIQebEqinQeI1SpS/OYEtrTlrKNNLuHAkkKZaYQgyiktkshNSZQ5TJ2BBD3nfB+8ASgx+fbFw6KT7f252P2kcbZ0f2fE4nyx6119xY8nFd7Mzy0Vk0raVgvAtW6hakZDJYCtxEr6TEgpC13HoWbwVMQgFqVTNAjJJR5M55VR+j5SSuMJBWKSNVblhKZSLKDBsSVg60qvVeUexvvyT7Rx8f3Mv7vYNy+fndvd72uN8UUzf4T9+/8zvf/j1+668Wn8wvDTfbjViO8NOCv2kPTm/2fRPZWf/M83r3/Y0lpHpcl4c0/6R8P/ga+QzTOcyKY5TekONL1+dXxpPnblf5fPzF35yb+fVXb372g+88/+XPhzf+190er959q1+ej4rNN3ReTz8avvaFCKtzBAtm2OgCgkbRFnrGlpzt9xrfmGAViHFZ+Do/m7nzw8w30SRjJaMSrI2eTQrsggRLzMOhrEoJtRqnNJesZ7cH0QWcP3SzKaaHwlGJWQhLJRgE6ErtNuqhzkY62+LFRs8EZL5dboyLz1/bquzq0C/6GQqVgbjhxta7ZTuvllrDMHPONODNvN1BHKHcQjmW2cjOMfXtMXqNOXzzk3zpwmJTvf7Sa/+Cb7qjw58en9zJb155+aXPnfZwqIe7lj8uRnY0tBANMMueLYi7zb8Q+oq1PYVooGQuE1W6bBJNfjiAJuM5kRhSEu46z4hxEZCSqsYTPPqiUKRDyx2olTzc19QgDdC1mrY74FgnMaRoQAKEhGIy30jLa0iryRG+bnw6ZxwjmKJo1w6oGGPZcqqZF6pcJlrzqaGkXdOvF6swBAZpZCIJwikti6SjoKwLGxOBSZKbQEobTI1894N3PTm443J3RZKUmcO6agJYWwiCUoOSdl8pKaRjUitDeR3d/IsEq/XqV7XbMXcu+6R08S87EJEAijBMUaTHeROiY15pfG5w48bx4YPPyXty9oX2cNNdamzTkDWOxUmO4FBmWvW0cbzMEVBRKANKHdXK4sqpvn94fu/ITk91mPUt2sIFKalG4G1ijjY3/cF5Tv0i2DPOrYQcvrJkMhKO5Ix1krNt20Ax7rr2wNcbrtjeohOpG+/I10NYjvC+Pa7s0cwJ9Ww+PqjEZ3uyNROB27IyhNulbJtbMYYjmG0cbmzytXpewfZf3uNbgxjpuLLSv47erRqbvtg8ef+AVyHE3J2oGbc+3zmxpjB0XC7gRseXfm1x/B9ujoZlcFu5T8HNpA7IQnuGWPaGxo7Vemtz9oUPMw7HK1podVZvu9z4ql2cTIbcOtuMvIyCHajHA+xf3771P81KH5oxbd98487srR/+4e/duhEmu8O7q1jWLY2obmUFNI6qiBraKDxRQwhAUCBoylOhtKZJFTf1kbK+mpP4KFGQsSZRJqC0s03vMJy1Dji9XTRvT11lqcReNNTpKK0JrNAkTJCn/0Pnpg6TDoGSALHzn49GyIfIBJtZiRJ9MARi4yVCtZfnrfdBY2fPrNAYYVi6eGnNbEZEAg0iButoxOSUSx1RgiXJp6AiMYmJiVQlhgQOMDE5zrxvACiEyZoUzEKmDUImC1Dbo0pqy2pht86yvdl+7O0d9aujfnnk5vNsOuvNPtsrelfcflvsHufDZZ77npVY2bCywQlIQgSpEInPOPerVo0oO5LEiRQDCHNgXoSVgbFsg3g2jBgBw+xVLTU5d/cujbVyJAqGV0BfZrEo9n/15weRla3jg7vn127tfeOXfuenb7zZPviYHppLfueQPjvvL3XCbgP3Cr7UNF/Sut7AHHz977/++OjG7A/+cLj3bO/yc8s33nS3RvjwhIemJ0WYjYvcBP9o73f+VnVzWM/eE6qGLwxvLqvw0fde3Tob3H3P/dVfbBIFFIWlI14dNUfFtLdZvWz742M3VpOS9oDIiKKNtCsrdQhtTezU+iyG3vnMLU7dfMpG1dmMufUNHLgJFB0y9hYOhuso5Sxs74qzXC4pY8sWg6GyRonZsJAbvbA4t9PHbAwptMdSCwUmNtbW93KUhcx6kKAmxnjr2u7NvUshnM7Kxaf35dLtF4cZSTY6Kk9L5G6zCFVwsDw0MW85rCyvCtvkxg/RYFnp0nLLUraY1v54dfhf/2z8yusH07MHf/ajqlfuXB0MUJ5MF9Wl1za/8j+cE43nFoVtF0y5cObYCQdGkzwzDIQBVknSe1KmLqsaChVVCRoAihIJiCIhxFTHOEgq0d0hFbAoS0qXSojp04umRJJiTRksHXNBNCL5zqT8hOQageSrt5bGaXLHTIGZgGEOIQIIodVuj6AAokhKd0lemUQUNXCEIU5urk/KFjFrZ0YPUk1J2d2NKrGrVZhiKn5Igz2RoQ7JS/ZclObqjl8qXautRBfmWus9cHenSpZX66DWtRV2QsQvtubJF2ytWkqSowQfXxhwaGcRTOm2omuFyZPyzE8wRlrj1EkIzUoZBIZtgJEoKxd+ffjq//bZ2/6V4XdO3v9H9MsrC3ICC3XR0sqK9OEL1IWsCq7DkkyVDZgPp/TOW+X9E/Z17kIoWkWzCN418M44siIVRy/e+P4wGqlyHvUYudQ5QmkKgti+aY7q9lC+/eXi7K48uBtefm7jsx8uRxvjieWW+WFT59HZyPAiNR8z5siD23i4wsq4uRbzwDe2IbvRTyQElgkZsCUKLKFnMn8y2iznmeSvvbAYaeW35vlY7HbZTqp297w3PD4+vr6EBM7Ow/BoVrprtcvq8Phz9rP+7qs/W+3d9S8MyiPHWwd2mbJuvCdVGOuh7nJutWhL21hBltvhds7OxYpGGBln7e5o43d/5+zNPx0fflTt5rIhGAKjvOblgb8x2Z2ImDufnb3zkx/+3gs37GAUTsTxpKmdEcOVsCepgtZEK8IK6pUioYUmd4aOzixMyeZcu+v4Yk+kT6Ei6fLrtrVPXSbUpRV1bjZr6gD9tQL8196e3hQ/YWtd0A6e5GYq1rImRbJ9I0UkkFAGihI0spBkfdc0XkWskDBCaCkZBpMQUwwxxVVLR5JI17GwYevS/AoQdSZclLyUQlpVJaZT4ot1IbQaLbsQQpQwLIrRaHRyOmVjiLv8IGezNqUDMYXgnVrDmclstFKKN8KTeTE5LW73L53mzVn//HA4X6K8//jBg9FwVBSTbHtUuY0pDysjiDCGVWvLDhbREyVHLXHWtAHKbAVBVSSwcSICCY4phPriFVKtFSK1o8Aa1BQco2hJ2ofZ4GpabV/duYZn7334wXDrsldz588/bN6Ry8PJ1698s56ZrZd2red81/Xj6UBWNlQNNdL6XaNjEfvOH736+ld/vptd+x//1qc/eAOfm+z8vX/x3v/z/33zuV/xgxv4aFa+/34+mZzLwergqNbp5Fo2uP+WPXx35/jnk8X9neX9LUdRfF/ozAze8I/3Y1G44nK4P7c1o51ubYuxwSSRC1OLrDZtLTa3Nogu573l4+H0BGGJ3LY+9iiB8kYlIHOx2CDbq33JIRgJdD4jrXmQ67w1qEKrWM6pLDPnUBTt0OrI0mktTAHBehiQmExV7I6pNmJZRD9/NC96+Usvfn5/c4xpU0p77+Gdza1nxrwqxdZZfX4SNwdXFxaw0AyaRdO3hcXQos/RSMlhkbc21EFKaU4l374x3FnOzz85PmkM5nYqL7zyQukf9sTT4Uf+cObHL9KLv+KaULXI+oYrss6KFbYMA4FNoyMJKXXxBiRM66KR3kIIaaqkLswg4dCdqDbVNSaoSf+va4hpzc3VdS3gdVWmTry0luCmvEDpGEWJoaDMLB1X66+hYgk7UhVhDjGmB0ojc5BASHaQxMwaIhHZTlLc8UrWhlndhCmikmhSnaC4Uy111puaJHuc0hJh0n0teUei8xXqgpFI14IkuijSyRWrcypRQEVhjBVIFFHRtayZCGxAhg2z6RRWopyoXQx0DkDc3fIS1bWjzCXOV0dqpYvkJL3YQydppSpzFBiTOpUsiM0AH6pLo5uvHB7+qJodTOoPFp++dOX2VCprKRhyaHJID95R0yNB07LPevBv/dS8/Z7VhbGl2ajbJoZllBYul2BLC7uC6QXvf/s3io3r9G8+Ph3sTWa+lnKuo6GEyqrzeV6fLF641EevHlgbJ71Hf3n+eb8x7GlZB2PzLLCrjWmoPJc2ar5v2NuHdWb6m8er1SmNlv3tg/ZkzxS+cPYSAeBLRFnjlYxxwdibjx7wpKKNYv7em6cfvntG42V+7XTz5vn2C9PJK+e96dZHj1EXUoLOaNTnT3Ily/vF5q/8yjNN7U4PTx7KNz679/vXRiV5c3xpA4BH46Qp6hnxsM8bl69qT9CylIf+rKwCvIvZaPMSj/KN28+0e9v1pZgFksvjcDkrhtKMUcpoaeXxlG6Wh5/cfX+nXu67m0dNqCevhfx6WKlr61BlsvQUHGpFC2qpkx6pUIKdJRAFkCiSt/867yj51aSXWzWlz+saAnqCSj3Riz/BSeipbfB/p+xe0AD/+/V57d+Bi/PedYcKMJMSqyalWVTAWKIA2HRT4BhjDDE9dJSO+axKSRcgqtw517K1aQ2TrHQSnq1ppZeOKJlkGS0xGc53o3836pMxyX7AGruqa98GJrLGpPpuTSYihsAWEsSZ3EsMwRsNzMYgg1JLbeiF2PClc7tjd24Wl+b9ZipH05PZkS6mxRTbw2J3uF0Nds4Hwynlq5hHWag3QytBOUjLIkEMOWFpo6R9GYmQ4eRcxIZEoqpfC8dEokftEDIEkCdacbaR5WQXWM0W8+c3Xjk5P4rLEKPkdfHok/unxeEr33rV7dmllf627IR7Q1Q5yl6YjVF/1kOI7nX105//cX9PfvWf/vpnP/r9rf/6X2782t+ayUzsyfALN+6/fVCsSqeLcnE62dmm3at7l67J9/+Xrc9mo+kH+zgbjbDTW2ysDsXSKW3+PJ6MVDN3Odf2Bp8dsDFR2fDR9i5EEIgrxAq2T97JqBjVDx4XZZmXK+tjdM6IIFRsradgNWTW+WLEk4myM49qCit1gtXSrmrqj1YSyCsaj4efxfM5xmOSmPX6nCPk6jSCAkIU42zbBg72Sl4XLddT2nfb+5d23RlOy1kx7t/98DHn9sZtI5gFMo/uf6L+aivTOo4MM7NGgqWMYwVdxjjL3WqQtf6oNefIVpZaAzt5QGOMXt7fv1UuppMXXrrx/NVyuJRr4exgSj85KH/wB/nOzd7wxqrKxbWZ6SEDG8NsyIA1WY8SMSEmM0TtKmxnCNuBWukkxBjTUY0xUpfrnQjMUKUENjwF6HbrzafJmAQwsenwIu4qQ0Kb0RGfFaLUBTB0s99TbwSkKBGiLqpBDUuUtMZtQ5ITC8DCqqrGcqCO2mEMra0u0ckNRQjSYe3gFOKbrKcgwkSsqfISDIOI15qp1F2IqqryejQV5SRKThUaqkTMaS4nSJSukWei5DoigvW+fb34fQo4Zuqc67rnIXHAac3x+sVR5GLj+/Qz1f2FavKnhShLlOjYhqAZibBjyU/C4it7X7jz6E/nXyjeaO7e8td7YxtZrDFWwFhZlhxtjiWWyEHvvu/fepAVzHEGrfx5y4EpqKnFN5xv1qIr9vMw3raXs0I0fPNm8acPptvbxZdfuPYvfzLPe8Pf/a3b//O/OXjpxuh3didv/eTMsRsPnYK++OzGh/dOT0PtKx7l5nC1It+zXlh8VqPnsocn9Mrl3ZN701kYlthohOaUldn2zGwU2wvZFjYmD0017G+X8y/kHy0HtCTbYKsNfcikbiguTv3sYTU/aOthfg6uWarANQ0PzlBEK9oUxeztsJFNX0T2+LRe1K815VuFHZ2JB5DtDkopT2RExm+RLAI2L8tg2N/ezv3JLJwFxxvecugNenuTmX+/0EPas+UlawcSxtEKDTEbSZw687gahOnHvd6Wkaan2zwaYrJlZ1lVBVOyrQ1qoZpoBW1AAWiRPPkBSdDUE/URImlUiaLxiTy+qz8EjRcniahDcVLFfBLmkFrhrgdeIytPXUv0CxfV0zWYuk7vr+HW1MWOpgP+FCoEIgohwsIyjHBbe8cmWPIiFka8Z8Op6We2mpz5NQkQOtl95qwCUSXPeyGE2PkDcQLOhNWk3F1c3Fw0ytqONrXmIjF4D78xHFWr2ho4cBuCMjti18unfu4QgsDCMCmRCEeQqkQIhIPPOUgUT3v1YC9/KWTt3Jw9rB+f3y1nPJ0Xbra7y5cHo6a3N2d+nLsziRRiARL0rK1jzeBgTIzBJSeiKGRtYpgLWlUhkERRDRArEATwwsU65uI0aFWv2EGskLcvXP7im298tyj6UhuzYf0w/OXdH5nyL5+50nsmn/XLBxM772s11nIcSgmVuv62DbcW2Sd/8PFi/Gz/bHUVveWj94XtKG9mMs/3C2YrPctXnvPPXvc6zabvXp59NMbJxJ4O5GS7Lvvz6qgc3YEcmYqJ+y4bTg6yZpCHg2u544BAbgV7PhrTPGouWnDjapdhdfez8fzM1jPSRhmtrzOBcaYNrWUOmeNL27x1id2AJPSAnkhrWP0qlnO7dYmCyNkRi2A6y9oQegjYZUIgb6UN4mENLERWYnPjvV08PPQLd3ty7ep4DF9X81pc72fvflxW7e7zo21CsOXhiW/Px5ktyGeecgRZ1eipk3IRaAZ7NhqGLW5WpytXZYXv+UWsZ839Nz+Gtdf3b00fzMcDd8ltHs3PuMcyq2++9KV6/7XH3/tp9c6PBr/y/AItSUawYA9YQbLC6C5pFZEYk1VyOj6c3Ey77ZECnegnldxErEy/Gr0QwAiLpsi9NGCmDu4ie4VUIAzuXJdTsU3gqXZu812PzQkl5ifHOrX5qXyCYZgNc4hijVFm60wIMah0VnWdJYZ2xvCMgBRjxtqBu2SIySA5ciW2ZkybGQEn99lE+0jYM3PCsdEV4DQEw6CbllW7Ze262SCmRFlmpMdL+HmSYIkmlxPhZL4NhRrDul7qdvKGC4S5E1Bhve66uBkySNdR6x3qmKbp/3ZESbC1gYkEJCMaZRgCLJFybr8ebv/J9KPFzd4Pyp/9+q2vnfHCGrEqjlYZvIU3uuLg/Ny/dc/YaFfHTVzKitBkAh98QGBZhipzbrDgoE0xlsXj+j/+6af/7P/2+XfOHnx6vvzctuxm4aRUa7Qwy5v7ez99/+S7f3G2na9+97VtaPjstLm0oQ/vByjbyNb0Vk1tPccKUmmEGN+ryB7U/ZpHZrTFy2xm3YNF/xuT8ft3Zmf9yZbzZb65rPW3pj87M2bVXpqb3glNSh2UdnTCRY2dedgUKmzlYQupG7fUOsjodGHHTFZO5+EP7stOebci6V2+1dob92f3X9qVzdwBOKymlPdJJmMKR6EBb8SszLOpFn3aDxu7fXiEmT8aXr9/9v7LVzd6BUBauUJWLBFwYns2Hy5O5/Ha5Pbo1vbdj4/K2WbYu2rGQ/ExFEoLpqaNFUtj7Up4RfAEjy5guVNet8lzA5A0ukoydhcRTZ8HeL1ETZdMoj6tLcOfvkLSMUVHqfqFRu7pSvzkf6VLcc20V3oKd8YaekmB90/makIyYlQGI7NQIe9F2NgiRwha+z4gbL33EsVmWQgBIi7LIlpphdiytcayIWKw8hMDHOoYkelbFRFCUIAtsybf2DQEk6bdcAzpJFoAVVWBOQS4nm3bJcOEaJp2CaYQg7VMYqJScmNLaeCGHAkFWWWWW4nnLMHXgyrbtBv7w51z18x5ebY6nt09neqD2Wb/YDTIXxyNm+LSjDenLN5qgGGJZEnJgsQHzozJer71BjCgJqGASiKtiFMNnW6YhL0Jc8/OYsXiWleY5bTaHl+/sfHc/U/vuP1cBkpj6u3leT6TsztjzLfN4wnORloPdVqYMHTD6fTRnYF73YZvwjyeLk54e7Zz8+yDH8QPPgy8/+DP/hVPHZ9EqQejV36rOnx31zyefPTdGyi3zfxGeLzDi8UUb0/zB9OKLWdgcWJsi5rG4/nsw+8/+5Wx5xAor6XX2mK1kVHJdo4iA9pyUM+y1dIQpMtkoNCz0nphda5Pu5fD1qa7NAoRVJZpJFQyrIGXU1lOuC7D6ePM9AQhslC/n092EVEvPkVcgojJRPHCLMZr8PZXP/fitrlkSzN/NJc2tyH/+TsfBKt5bsfIzSJW8XhxYnK1hS5zqcQK52xrDhpHGUZ5Mc6KnGahrYfWWmA6L8Ms3n/nk6Etnr167bw8zTeywaXJfL7KxtZ6Qu7ms+PJ5dcnr4w+/P4P8NIh7DWFDwgSM46BY1p6JGZijCJBYgytduTcCIBSl61JhmtSFEnyqrTMIcTAHZ8KUAgJU2COybqZSRWxg5W7A2/5wte9O6d4whVak5S7PKqU1mVoPWETsSHuChhLz7lrV68+ePiwjcEYC1FnLYmkxN/QRtFEfjboqNbpMZgYSIzkpPSltIFOrUjik3UGV7ZjHFNaJ5HtjNPW1Te5VjKlOLS11d4TLlmnXlz/hNzxOVWFbbfz5nUejUrkRJW2hp6y2OwQfWvT7J26gbVA8wnYQE/Pzt3Xpgte6xqESIm7Ju3h1DCptUGFA2t+Hla3L9/8+dGDR8/T+3L4henD4XjPYwauGX2jkaGs1lpzeFKvAnqiJJR28i6Szwutq7b1RC5UZZYXq8A9YzY3cPv5nRbm739t///x+4ujsr4xHv/sk7P7x4tbu5eODsrXb4/e2S93nNnddbsjfnDkt7cL+iQ8Pm1s34ZGlRQZwRKXsCyLI8n3+yfZ/v/8xuLLu9vZSn76xklVPiM/Dp980t/suyYL1cr91mffl7C6R3s2w4mMKuk1tHkaRpXdncf+fJX1VopFrYNtCpDVnH0+Pm+yWRA2IyetHRyPfsmoxWzOOerhFz6+96fP3coB7AxHdcA58yNf+VCqLFeynasUvdVwmDUis6OTyee+eHvnxUWzooc/q6tqZDfPZAMlbN/4oDnRvMX13H/jVf2DN/e3zcGAy0U+6denlodBN1qt1TCL2mXQmrUmNKrqAQ+KIE/qQUIUtGNgiUJEQnrFO/iqK3gXF7YqMUOeGMUBXTFOx7djL/Oa0/DXa/Bfg1cuCrGknVMn6gf0yfpKO0bmkzWx4iIKgpQ5cz2JIUaxNpPCVHUtQfI8DyGIqAEBJG20xsC50DW3XchncqyR2C2YteMxdpREFRAkarfpEQIIzjlfe5Cm1IY1jEXJ0b5sPCgjUEAEwQBKBt23oQFi2TBYhaMgM4Ftr/SrIffrEAcG3rWe4qryiNhAfqn3bF340q5m/nR2bzrNzioTj/d2MHaX0L90bDfLoucBRrAIPRaNrq1ZWDV4ImITu3tiEiUCJGwotGKyTEOLkKPucW6kjlYzX69u7t96cHZfhuARYUNc3o4xv8KLXZzv0/kGn2zo0p9E8m44HNaPyiqr3rD2K072dqciIZ4uB5jkGDAWfetOB2NaevHUfOff5vso9OEuHo/M2TbV4trvT/nRcSvH3s7BgFhDWQwxZGHYhhrDB6N4vIG41GGto5VU1cZEp544Ol/l8zNbnUc2ioxsX4zJWjbtKkbmyzckH8Zx3/aMV876uTQCZmWRzJpG9GQWzANZHFFsojZsLXlVq1LOw7ykswdCNRsnrSdojsDn9cmtPXv3xx98WuY9Ka7kk9Uq3Ht0Uq5C3s+2Crcz3FJRPzvPvAzdaoZy0N8eOTYyNCDesP2NBjr3kco27G7kfjGbznyowsnDg+GG2+/vndWV3SiGk8Ei1MUoZxt9r7boRZvPT+fDm8+Hd8uskYZC1og0lmovDcFz8AJUioYQ2tC9iXhmy8wSAxImnCynUmSYJgNISSCrSfNwDNaYhBw7EEFZQTEaEkYCqwGwoXTHJiVSiUVRJLcsTQwKIkhMU2fSD1tlIo1ta4xNY6FCyFgQsXLT+AcHj4KIMRYgJmVnEFsohxBS6nMKGkrcKsOd62Qy5+r2SAknjl3TbhMtOiT7aFZOmRAwbMgaSdm8xAo2hokZmoZlZgEISnKh7EDazF7cLtZmeybBwd1uDrKG72ENiEwy6mIGEJVUlUHMRiC87mmw3t5dyI0u6Ffxwm963c5w+j8KBSsxK4DAsNCUlhYCu3RPyzxxi29uvvS/3v9+eH3yRvnh78puq5loLxgNMID1ilEW5gIyzik37HNmFVqEUFWenMt6kDpazl0vuEZvXskrYTey3/nhwS//9uXf/NUr379Tvf7VV/wEdmfDXG3/P395tNsb/oPfevbT98//6HuH7XD0k3sV2SobF49OGzatcVA3jKvKORZnwfHkoP2zWaTt3p02e3h0OrLDLaBv4+NPz3fyjNSvysVvPnxzq52/H3ccm9DyuckjNk7sdhkHc1vUbc+sIpXKTa6PH3NJ0dtQo/D11ml5cGnblpHYZ0IqC/QySOB889z+8k8f/ATA1TjFpmKkfVe4UGy5YS+TQes2WaiidjZ3dmPjxsvnZ1W7CPWdD/fyfvSDFW848RzIEqqVx7L5+t/YW5wsP6muPvPKTpz+aOyn5Qz15c97bVkaH4xFZtKNfwWitqu+6qFeJRAnHXCHP0OVQaIi8Oli1BiTmVpX+QxDRYQ5aeg64kDq5FIiKSUhYQoJkQuVb+I94UK2tK69ctHVrst5QogvYBtJxhiJ3oCOirwGwQ0bVokkZK1S0CjWmiLv1W2QKAQWkSjsQzBM1rlVvTLGMGATn4KZFBkb0UjCCrHW1L4RsCqIsYp1pj1DYGsQRSQqMUTIskYhqLEGytpt3TSZyyZsPNlwIW24CKmCG7adq4GxMbSGXJTAQktpDHNDTAKwWjGtwQqhrltX0Zj7I3dzv7i5sLMl+wff+enw5t61V69+ls0f8nK4iGYhVxcbw2UWHAsQGGyA4JNBkZLx0bKGFtwLCBItiKIlZGxbRSOVYXKiIqPG7W0Mt7fa/lJHIWxhzKe7mF7W4119vBvv43EbS8JUtcJhfSQWTI4ZP+/xQ7h8cx57vGCeaVYiP0b/Xn/gt3JuJBvlW73qTIw1Wpn2IDzGUSmPFcfqZg5ztDGQiQC5fh645gAt5JM3/vzGL//Npp6XOBlaXvCIyGf+xJyduNqHrYGurC4qa5SjEdgwKNSTDsd2/4rzS/GVVcDl1A/gPAizeBg27UoO7meRUx0K0nJmaDYTfMinZ3ZxKq6noY4md1KTt4tcVq8/bx88OPOnsb/M3z35uLDuS6+/bPdzgniHTz58ZMtePZTdsa1j3NAwWy1RT5er6EJWT8M8VtATR9OqOqntyfWsatq6nM7Gm6PtS9uL45oyk28Naq3yYggOTah7XFiLBhBiYeteujGdz3WwV7a1a1sWpsYki9LEqIzaRAkxya00ITjoiIgCY9hLTMyKtIVJNGGFMhuwGmtTeUaKOQIJU0h1jYnYQgHRoGrTalUVhEVVGQAKa2zylErsEeogcSQ+ZGZM50PJJCqI8cJNxrdtZjOFWGakbEFDEiWlgktn5RjIkE0h9YSL6mvYAGBroACEyEaSrq2+8N5gVoDBhkiDdH701HGvSDUJotK+mQhE/BSPtAP/qLMHgKoaY9ZTMncZEpK+eUXyteVU0LtbWnpGmMmwTcPKRWBUkoWoyAXjunva1oSsNVTYeXUpJRIdA3SBFiYjFIBUgnH9s1Bd3rrypenOj317t1i9d3D39qXP1XIuQg25BllkJ5kHSXAaXOAeI+eB8JVh3N7u3/30/INz9JxDEE8+UGX6ozd/fvwhDG7i8Adz98z2ncP20x8c+a1rP/wvx3ICNy7+0/emvWVbnZGc59YbCwd4oM6oH8AUbG9eBnDjauUgrVrbA2tzJNlQ2smVEgtB0ee6j6zGPPPyuwdvjdvVT2SXWNoozMOSRrMIz1tzybVkWxopRVaIC7GV0ZBv7eyevnd/1MQrDx8eul2NIpwb9hH9+sy7kWzkev25Pdl9FsCDxffYrcxwsit/ST2F4bha9Vzm2DdBaLix7Z3+p/+w9+Lni8t7J7XPlvFksDGlIkdTRzUcvnF7rG4w3MiOp6Enq7vDl07NzV+t/urg2s1Vr0+hgrKIQOOKnBNhkEoLtAl/7gopknyNNZWcDh2FgkWCSkhudCKRuhYxEhEzkrpHAEYSTKauE0ydF9762r0YY7u8nr++1OC/9ue0+Ohwma7uAsIMVdYUj5Em4tR+andqAEs2IKT/56wVkkgcVYyItTaEUNd1OgLohO/roVDEQ41hVohEZiNBSSE+DJ0LTGfz6aquLu9cdsYF3/pYw1isuV5P/0gMQCVETS07AFYK6q21TwECmtpfwyYt7AybjkoqyZEHnoUFPQGIg1GvQevWQDeRb2XF7mu/ZnPDh/yS3TWOjux5sdc/u9oeeL99jNG5yYJpULEpKssumqDIEdmwE16pBzgQWeps8JUaYsvqVMfc59ovG63NkGOOwoaBLvs6H1LZ90dDdld3br13911X92UaaUWcQUjRs5XT0tWIAndybvkR9Q/i/ISLR3a4GA1kHmBl01f7bvasWd5AuRdLrsmsQN6EuZcZsSWwMFMILfWhTqWSgzuf5dfeGl3726hqp62pZ7Zc2ZNZ7n0YFWH72d4Jx9VZ4xcML1ljL7+gcaYZI7dAzm0F72MbyDB6WcZWAjhzQYKxELQSDDg4ZF6Fq3ksZ4BK1msp9KmnUgtzkKr86peakbGsGxsZosi4KF578RWLEM+rCH7v4490x2CKclTZbTlyB4/jtROez42exW27yNkbY9qCm2VPi2LDSr1aHS6Xs83R8JId+6PaZGYw7AX1tlc0WlmrbjMPRbC5c2aska3NxlvP3X/vI75yU+Yaq+ArEt9ywzZApAHaGLxIrfBsVMCsGqMgxjR3+jZy8mNf+y6rJlqtkgGAuq4NkRIr1BhDnW1cou91esTuErfsvScma4xJ5EY2a+vn7jJPIfYEIAhIjbUhhigiKmxYRYNEZmMAUggnuxs13ZKUzbr8hhDZMbUd8CwiDLbWpnUqmy60nVLWWlr1dukpzJySObs/JNtLqCDRKtPkK5LSkCgxpdfeA139BXUjRuKVq9IaOk6RLgRD0ETzXpOwuqeVmXQdVkWKi104rfF6WodLpJ4gOWLJRbHtGoCn7oxrqDDRsBUKJBdWQCMQwdyGQEpL3375+pc/+un/Xv3m8B6VzzWRXc+TEXUtuFWGZcnA7OGyNkPPyQ3TTjb13TuzF25v2Dsnd+fWZb5CThP64x9+Zq9O+s9RHLfnyvc/qrm4/MmMDk/rudsM3vVDO95zi0OX1aEXWGvVnoQIC4Bqpl7DuVSxsM2tS8OZrwLy00+W9QaynQEFDXXVjLKqGBUhI+1v6OV/8PD3B1XzNu/lxD4yQG2WLaUIvY3lysgy2tqEElKCK1BJWkOq5vzRg16FpZjb8w/enzzDo9GGL5dillX12ueL/x9Z//4kR3bld4LnnHv8uodHZGTkA4kECkChUA+iqsDis9kkm6TYLUqipNasVrMjk2k1M7a/rOmH/U/WbH9Ys11b2djKbGbWZsZ2tbbd6pnu3pbEJtlsssRHVbFYBdYDhcIjkUgkMiMjIzw83K+fe87+cD1QLVv8hKpCRSYAv37P4/v9fC9c9J9oqP3G4nwGAJefHn15VMrZx1e6k7GHQRF44gXyUK82Cs6nYaNl2520Z2fHDx/4IIg85W1wwBFqoeu7/ndvjB80cP/RdPfS6NoE3quOPuGXZu4PXx6PYtMCRI4C6kJEjkGNMBIYA4ChI4gKokoKHfXT07QaTHIJjAoawQySnBERDCNBvz2xGC3Vn4iqCJCOezLIEayfRftMtrFGaK21xPRsJbxmavU1ZX+19rIPhP/EWJyGQp+tkhH1mWEPgIiYOf0XFVVURxrVOukQgLzPmDtVVXWOsbf6gqmCo4I4iCR5CaghkBEIQasULbz/zi+lqasr119+5RZxptBFiSmp7G949tP3wNvbWwcHBz7P+987KqPrJwW0zoMCQwBHlLbKjiglf8MaBNY7LRP61oCMgCCqGnETOz+FTjsZuGHeVQXs0/CVeO1Pul99PL27LPbt1mBcZRdOy+ECylXsMJDzQuSdAGrmCpWAzhMpAhiIASGxGalTHmQhNMYGI6Ixj/0yrxcbUPk4vTCIfJrdf3A/q71OI8wQG1QUn7sOOvLoc6cZQEkb2/XS6prCyuqBVDVvOw8WdcBuIMwiBJKzb7vGs++0AyESMFEkBI8qkQNjpHpa5znf/fW7r178+jjbaU5PJ1Wsq9ajthnT1St+80bsztURZwOY7AA2sL0bqbCTYzbWca5ScQi6qogzzVxQ8cSGpGoUREFZzQg7UVeMYlfnGgTRXD6MJNZlGUszry9fkhvPleRYq5A3QA1/7ytfqRciUmhmP/vlhwHafFxYq5t+iKyXN0vO9sj2Gyg12w1OQMkXfuS7jFttptOqzlS29rdHzWh5LN5n+ahooePcz+vTYtOv2rZ6eP+151+X1h0/ee9/+WC+/3UuLnwDVhCWtWXDpq25RmoQWgyNqbYALUDnHJDzbZgTrZOzHEcVkY4Q1UxUkCh5nEMIyRITQouEzLxOCsJoGlVTjnCSG1uv7TIAkCjPusZOlJlVNUY1NIuG6awqGIEBCCgYrFbN2n6TfigiiUqE6NgBBHYOuZ+XOeJ1OiEwohmCc2CmyWGbRrNqBGaUsM7pptRnVxdiojf3aigEJICYJtJpswQJzaVGpGkivs5MpH5Vjeu31TpyTP8TWQsRfZZ49IwTmVQysDY8f9ZGf/bS6iWc/RJ4/Tbrf8OfadV6DJnBs5CM/z8b12dXcv+PnUJuDjl0zUjzb5df+A+nd+5fmh5Uh6/sTqL6DliNJRI5g5wgJ2qpQ70wgbCID479l69t/cW7x1ev79LxSTYqo1vxyEk5BlT0yMbMuWMWcpTnud8sQ/KQx6dnnqJkQJWAxQCrFmMNqOUgHy8O96tjHY1e+ua3C+6kHFPe1VwczWaHdw5Pn78cR4VrtC2WXXlh3y2+cfSXXbt8113i6DsU0qzhjIAEClhECs5m0C46vzJqWBdGDbrWwSraKlqDnXDp57//4C9+fOmbx9vP6VLfuLm1e43/8qMgk7D74Tvb4zsAcHmnsMPD8fiUXTWpnz5nJxvucFI2RTXHOQ2K5+omSPNYhhcAyAUdcPm0vADBKVNW4MFM/+Rn0y994cL1C5NQbI5oGtSVfv7O7MLZ02Jvq5oZKyIARlli9CAecoCIIBlGjiDp8lCNSQyY0qnTdkgNVfpyUQ3UYlrOkgqtazVCYk4iPFBHFJWQknJJ+8QhQwDF9VW8fub6r9u3vn9zj5yeQXq2JabPqORoMSoR0LPQRERANFNah58YQOLwIDCzoqpIyhojhxKjJUOeqMY1it3WadwGnYkpODMi6siiKgGUuVeljz/4bZn77UsXI7hOIvOz/cx/chzSTRwkHB0/YZ9xxm3TOuoDXUCSPaHnE/UfYP19qya0ZlWnVXRyLSBhCEKEoEbsECiiMbGgOZ87IqrMNybU/mrwyZDxi4+K2aX64aOTeADHb0w2LmxshOFk5vKFYpAuow4aZmX0ZsFMzClB4dQ7LZS8FkCFe3LwGJxwWQYvha5G3I60nlgl09X8YAUnBDPQqbpz1kUE7wJFIIxeoUTKSZdARVUMhgWtBlqXGGYQOnZIqGCaQFYU27oFgbgSXUZoAGsgT+bMWqPMSYhQg9/MOBuJtb/59c+ufW5Sn8CyaaKOxdR8geMRS9fMz8gxTHa6K/tuNmcI5AvJcmg7n3GX6If1CqTypimjRjSksAADSC92IEOrEaMAAXFSqCsBNbUSV196fVnIzr0pf/v3v7aDm2XNJ4+WP/3offYFMLrdjc3RBZ10cTts7PjzbBaMz5sw00o8h1YoEHeMgaY8GsgiNGXQ0cBfvrQLzZO554KGrp22g43B2fJcR3H3ua233vuLdjTVB1rh/juzJowuPT3Viy9sNZs3ZCl2urAVaENUK9YAoSPqmXaqyomibF0yDUgUAE0gxmRciFFVwzMcRNTkXDfOM2kDIkazjDMCoswpglFPfkrZCQbgDKNGcNSZElInHWFyuvY4WCFISsXkhFWCmO5K0ESPS45fpAShFMg8WO/tIfeZ8UANPvNKIaiqQ1LoQR+qCNJvw1L/qmbRtO9TU3yTRHIULUGrMKokWQclGCYikSGhihH17UV6u/QskGT6SJGFfYYbrDMT0i9L61zCZ/ZjSJc/WFKX2lofDWuQ1VoiDtDzjRL4t7/EtX+3GFAyYiYJGJqtsRzOkNaILERQQwWLCuJJZSVqBuyWq8Xzl57/wjL8DD99Gw+uhGJsLEgtcm1s2GEG5pAcgpPxZHS+Wly7ODg+13E5mE7r3PsYKmaSKtq4oAE0jWiE6WypcKHBJlh17hbzzsOs0waoqaECmIfNjjZynmzhte3Rlb2t//GP/vWNJt6az57MSjh+bV6OoVH1job565fGkyfvLn78y9lLr7eTHU/hJv5md3m74eax3yoIG4VonR8ObSHqCqvMBdJGdY5ce6yjteBW1gKTDnnRaBANgM1cSndRj/7RJ//zB09fOhpdvdhsfPTnR7fy6vrseH+7OsISAAI3uEUIGYhZZlFkKGE4X0CjTrg+uO9hVFgp3Fb3Hm4wLUM+H+xuQqhCN/CeNX78yenzVwdbu2OQ2bTVMRfHSxj6+MEDACtL7FoJLnTERTS1XCzp3QKgEAQCZVMxoAjgyHpAkqqBpMWLqqT8IQBASs+VxRidcwZ9iHDS0pM5sn5Is54/96Wd4jq865msIT1l+mzJkm6vtJsCBOopcZhQOAAIRGRRKWW9WO9OT4vh5LHv9VT6N78SuIxB1EzROWKOncQonklAUhr2+ha2KOIUxKBDSKi4jG1RVcfToxEVb9x6/fKVK0VZSCP37j5opHUOrS8A+gbYzBQUAE0NCSVG6DqXMaZN3FpoTQkQ8WwY1ZPkk9gj8WhBVdmhIoAqKzkgIIqgDsiTmUjHadgvZE69AyIAGi5pCFvw0qURtvvdohqe3pfl4u1z287u3yyHcXDpfHNjxkVN0iqhdGwA5AwIGYAVSBWNADyczc94yymLWeO6qnShkGpgyyx4XFmYdTQnrrhd2lzF1TIuR2VeMkCzXOkswsgwg+FgWeiigEFBIYdGihKQ2rAyigTIJi6aimIHZTZYyUoFHAAQoAdTxQAYkS2TVUdjnR0+2vEf7MKVpzQ0x46UwChqAyvLgC9dkzFm41yla2PNWuogh6ZGVmSOGGg209OnsKxIQT0RgooAUe7zRgMIeADtApJT4owYQ2MI5NQqqb59q9kZbS5WxQ9+xlu7pc6m01X28/fehwJrazyDLzItNB8XdGEAeZzsXo58ZUD7pV4G2PHLkfNoVYQKq3LjafW0bQr2ews/fNIuLu2AX4UAq3JYns6f6rB7/vrld+/8dHjRfe13vveDe9Pbs+PJla9889bff8SXz2w0ssHiSYVhHKpAKxAFUlDoSFvCyBk5BESIMTI7U4jaYZq6RjE1UEn6Yec4pQUnNSUzdxJDK5DkxtAHBrDjNH9OY1E07LV8YGmpgwAKvdwx9vkniim4bx0HGtMzzZxygrzLUnWtMabwJTUlIgVKv4yM1CKz+xsFsgL2I19LEUp9MlIfegiQXBsKBGqmMeo6nRR6+cm68zYQFdC0QkphCo4UkVQsIZr7SZth76FCAibX18xrah+sqVSpT088rtS2/qeG6V4LY6bW87bWHM/+k1JSeurTEbQvI9Z2S4P1TIwMzMiQwCKQw+QZ7e1dGYAauMaWQAQdaGXsdTo7ezW7+vh4du9a9WE7K3GYuYJiKTSeUODdJm6jDqLvYHu8WlA2lebtu/Z7b+TzpZ6B87uDWJzHUt2khkG8siu0f+Xa9la2tXdI+6e6d9cmswMHI6K5wUjLgBs6zGosGkHwjZYdNJ+/9tzkg7vHULZB6KM3iy/+A60bVTCIUwC++c3Nj/7bm7d/1JWWl9wyVhmQ52xgkTUAEuXdaeMGpYrmgWRlVAOvIrWqDVmjsBSvbPUqBtNGMoKuJAmLZjyajMdfrD610+P6x821MefbUKN7apznEQDGLdZRC2RE9EqBSHjUQcNQQ9AiZzmba31OTx+PKC81fLB7a5qVQ603C/ov/uByUMi3rRvBoun+p7fnR/nzWgTQzVayJeovj+hbeRtbQ0GsGiMWjmAKHSGvxfoCBgRKZmDOVCOhmiXls6paEFUN6YJFBYA14CJFCfUPIgIg6ZodvX7msRdE9nPmv2kuor7s7pfE/Ql5djyQ1vXlusVc41oxBQWteV3Q3/1gieT8WSeqhpgcFskb2OsbHCGwqKRXR18H9LgAbdOFnM4zKiHdfuedaj79z/7pP7126dqqDU3dzk6mdVO7wqvFVOz3bsF13OGzapUdaEw3LhI5keAcY0IDJT2IgUKfWKGma+dGOnLaOyQQxAwJTI0Aosaopo5JlckBEEhUjixslHWupUjdYjYO3OV+0z+/+1RlPLs3mi+8LMPp0faKd3m3K/dmm5M5FauBQWbkowFQBASwzGVl6EIHwuxSPhhqBOmIIEO0zspsQOjaNoBAq3GwtX1xc5QRZ+SGPp/qUS21J26sNRCy6DNmTUoBjo1ce/VVPKpDgwFdxwreInQ+H/DARy/GgA7RE2UoPpqzOtbUEijTsHzz0ePP7+1BzGI+wrziaGDMGxPdYY1j8jXHZsVA5NF7kIKCaBdUOj2ZZk+PdDVnI3PciVGvslfpOm9oRIyuw6yTjlVMBS0i5jSfn9+8Nrt5bUvJ/eg3hTasEHg4/I9335nBshyP0DT3mVmn2BjnYkiZa4XOpJuDVAytReg01mALtQJgAMduXIwuh3yrwpNzN8i5KPLjyTWeHiyqvPriF1579+5b5/7k6298/U/fu/fYT2597Z/w1iv3muKEs5xc/PRDN98Moy1uDaLQqo+ATkWrmkYI1nWeKUqAfkzamRqSS4+cc05iDNIQUVmUZto0jYBEUWaXmj5H1KxqjQJr5T/YM1gjAAA4iqouTaEBJIS+eFZI7sAIYGgpxih9YLpaUiuZXgrppgREJAgirGSO1MAJmaNkg0zVa3qbxBiZOPF3AJGSCiR9wz16pj+IEkUlGXM1RSQ5dpg24tgv1UysP589YBbMjNmtQRr9jC35laNJWiF9lkHz2fuqf+M925GnaqD3bq4XuevEYvyb/88zWMJnr7uUv679C+5ZDUHrGAwAUiCADoDXuXUMENPXj4RZV0vMNILLjDJtPPxOcW02v/ve9skLcF20cDIwKgc6ihjyS/Nm7lnM7+GDY/3O6+XFLjz/+eGf/cdH2eWB7lhX+GxDmrj85teyV7754mG7fQLbd9vxFMu5K50UV4amjZogD3zsYrOS1TlMz5uizBU0HwEfHrj5cetGAz9ob7/dvPoNdhum0UJnGkbD3SdXXj298y5v7zazKRSUsTFl2kaSzq7f2Pnn/+Xdf/PHk4/eQeFaqABPNWmNIgg1QSRuuOvASaRaspwCBopBIHDTzexYbeQ554KWDs5bzZom6yLMMwBoLwgrB+cMuYuUaZbMAgwAaIIRPJANui4gMsXy9u4r7KVTKUd8upgXW+X7d47Hl7deeH1IxUaHvigKiEXXRWI/m+ujorgCs2VHTFnLjccMIoIaxv6vmNKVailNKNFdDNdW1xglxmgGKTJs/Vis7wjskWwJG97XoKDUp4b0B9OexZasNc62FjHoOtb22eP7TPUAfYUJPQ8vPbXrh7nXBq7TCzNymtSca72gJmqHmfRlASIApoC0lI77THykAAhRIwJ6AOmTwiIjzabTJjRXnr9WFKOmDQ4InA4nQ79chE49udifnb7qpWc/M0NHquDIxajEDsCG5WhZ131hktbpakkL6RhjkJ5DnQ6dSzo2QABK32M/TkvLNWUg1Ri4A0A2VohKYkpogpytSE3FB+JgRbn9umxdv7s62pifDsI5xyN3cnRhRrvjvdV4Upe7i/FolUHMAqpAw+i6RauiZuQiRYAAeaO+Ae4od35lHiAzZXVML167VikYsPe5hm4+m011al618QQEoH4wbBoI5AS9CliAp1Uolce0MZfB3mBSbNftsq26ioYEHRgbeOpIgDTb9RuXN2Y8p01egT9Z+Pv5RqejCZXxaOHPW+hKWTaMLRkINcygBI45Q7AcyAqLCzubyuyMZk+7ZuYoGckoyXcRCUyJ1NRZjB1GJXCgSS8rwKQSBuPlzWuUefvFJ8ODezze4tGe//EPPjyTpd8pYpA8z9TbsCw7ABiiG6GU0pFvzUX0AllEr61gIApAtYsL1cm4KfIKzsaZLdgBwLjAav7I8fnL33j1V3c/WClcePlrP35w0mxev/nq91q//2CZNZMrYTG8+0f/rnxwwvmOGOkKoQKLILFxGDDZ2buOSB2l1AVUi31tl1IMVB2ixAgARM7UqqpK000RIeIkOWYmA2Nmck4JI0BQdc9uHARAyAyiGrCz9Qg2nVrtr4y0l+ybwmR8BxVEIqKo/c54vfRKqX/aRfV5KaFLomtI3huC2CVqM3ifhxBSLpsjJ6ZgRuQIoO2numkajJbclKLJ5Y+E1qlGNVWJ4hxbP2IyQFRQU0385hAUYY1sTho0hPSd9PrttTS0t1SuF2HpMiVKylbr/8eeP5JekPbspk2yZ0ur47U0JsnREe1Zs67Q/+eeFwIGRoaJP00AAsBgPpn6LbHLFM1FbUvKocsZ5tC52QZv3BiNb49PHuT0wqI4LjZjtyqkCyJPja9sVy7TbNPrBah26Fv/cPyTnx/PJxueDQYKI4IR5yA71y589CQ7geIojo4JT2xwBqTTenUGeso0F50aLFhayxozQW+s2BlIsNoggmmnK1CiT38Br3zP1YHY60D0nDYuvdF+en+C+4vz2aACKGPgjCsyFNnMdCZ0KOEYxt/7vmg2+4u/YAlcmWuMm4DqIZCFsBJx41JM7ex8gCvORiAdA6hWDBRWTq3FEgHYsA+AhOgAhJVdZJdlgSMEYvBAQTECgRITimW2Lc3tvc9P81Eeayz901r//bvH/+QPb17Wcv+Ku/2wmgY3KEfCRVit/stvfe6/+cliTvTpib/kc5+bdgCOBKKioayFyaQAREJgpgoMIOsuUlUkxh6/lmJDkvI98RxihD5JLK030gNhKZMWmdcuf6R036blR1ocm6nFtHkxtc8UVs80DD1RDiHpGIDWOblGQPCMbIu4NhRaTGjY9bE3BDNFJewbSQeA1uMnkZA4CY17lSIRu35YpcpIgBRUlCDzXrp4/eq1vcl2I6maho3x5g0/fHD30w7EqVuXBPYMmQmqeT6Q3khtnjmN6dtmlVLRsR88J4eIARCDBwBmtvUOnMkBKCPFGM0l8CZojEAEjGYoqmCONQdQilHBMGaETrBhVSRn4BQCAKxUs5ANgD5X7UXmebmcjbuH+XKZLY+L6qgo8q3RVru7v9Tx+bho8iIOD86OQYEUu07jymC84W0krRdgYJvVM0Z2OV28ug9nmhFtjje6sJrPp9uj4pXr17tdWe22s2Kxvbt9b67GHo1VUYOw0MnxfL/YCDSqoayhzIcVjXFAZb1agRFmpiTj7QmwrYpVXaxohJo3Z27L3Xh5o3j1Pdj+cj3Oq6kVF+DCDsxirJ4aenVKxpE8oEZEWNUuSNcu+dFDWp7lGXfpLgBwYOlpMHTgnIAqdBlAJPJAKhRJ2QCcUiR6+RJs7W8dnA3e+i2PyhgDv/f0wYP68fDSOKsiW67MXZQ6b5gZJxmPqfGjyjaCjlY0DFo05kdcNrLSaNqQa1ym2YwGXvEIRZEj+JNZKJrJC1eufDBdtNnuVOcPHlZL2n7h1t+bw+4yDuuN64d3Hs9+9FeljT2Nw937dv2i1JGkgNiAiaEgpETMNIIyBVWLDp1pR4AhBHbMffgtgCkpATkFUQRAI2QV8czsuQnBkZMgakaQnHrr2SsqozdQMyHqb1nCz+Y/CACIpuAwjXBAVRGjGZoBuTRtilEiKJKpYA9ZjjGCo2XdqIgjij03w6CH6hkQRUALUQkIKIZWwZAZYiAFdBQTokLUESUUZacdA2qMhC4V/9FiOSzrumbyts5awkTy6j1EQEhEqF0KUONUNIOLIAaqjthAESla/1rrhdnkVKOZMTMiNV1I02voPZsEgKqR1k2FmqGt4+MAksB6jSeAHp6tiqpIROQUTKMSMRKqAjrWoIUfttpEJQJmykUjgGakBhY7BmhRgTN3BouvFM/TBv/F9q9+p7zypbqstTDItSvnbvuePf7iftNurmAf8oucD6h8qfCHAkXeFa2NKHoi3TuOe4+Mp5ZP1U11MHeubkTnQHOiSmRONlPXtFI7j8Ozd3+2/dWvyGikQUdXb1WP/v0A1CkoUf3RB6MXvwI6CKK48hTno8nlY9io3nnXOd/slnwyz30UHzVocXULn3Azzy79k/897l86/qM/K597bet3f//R//Vfbe5dWLWFfPyxk1VmWf73fo+fewGD2OzB4pOP/O0PMp6ANkCDYMoAEakzQydon901oqDgNMtaBafcMQVVr8aOlIwYgDVXF/3uOxc+RywkBCSQw7e+vK+2fLrQ2x/O3j1nyK/zJp7M7PrzO2fSBvAx0KIOh2FjP3sqhQNQxMwUNHTpPa4QEyNM03pCFKFPGYlRk1gotb2AEC0SmqGBWBIEgcZ0h5lGBYiqXSr32k5jRKQEcUUAZxABEp0YENSsHxoZphsnEVTZ9eAOicLOgQFzFlVgPY5WAgdA5NRMU3WqaWuYdiyoMfrMW9KUUOp3LSNGBDVw5ABMRSNZqlVBIwB0oSOiPpwBVFUIEaNuboy/9rtf52Jwcj4D0yzjrc3Jycnp0eGTsiy11UgAppljkYCOCCnltiy72jMzO9VIa7Oec167DpB6mIgpEznHEi2EJmPWhPoxA4CokZFUDckhoMtYRRxSNEnuauc4z/NquWDHkfrcVrDAxN5zs2oQCFIwJwCwRKAFRK+wMcu3ZvnlYhIKPhrNzwbxNOuO8qMjrvjC3qSeXDdXPVnhdKXexxFs5MPalrPIYy6azo888cjDTLlwWe5G2xubVHjvRxf2tm99/tWbn7N9CDtRr0Kz3d6tju7+6ujuE2lRgyEoaQ3U8BnxSHnbT2a6zImKCTcaYAIKkQunADbWfKsIPgK3bkKnNBm++sbBzD96cPjAnO8GX/Nbi/EVHV+kuITlwEB812hUJeWMpGni9IlbnHNXoxmrWNuoZklRrkBGEbBfZWaYdYRGysHEWuWMIgcOFjrb2tkYbhV3j6u33xuxLsllmvG7T6rieok1yBDBwDllD2AQPehWrP3wLE7msDnDC6dxPM+2aUbhaeCGUbGrImbgBqQQn4zHoQ2hq6dtyMPOxfHlA6lPD0+2tl86srN5YW+88d0TP2l4d9pkD/7qR9mdk9FqpCfz5unp3it/e2EbZ9UCgqi1hB2AqAphZ9CBJZCzEoKZqOmg8DdefP7OnY+iaJZ7jR25XLQDFSBWaXyWW9Qi95S63tBSb+cBIjOIzhERWn+RqKmSc0kmqGpRDfsqXOlZp7weZPXrIwClfrgGQKrO+uK9v1whSaDA+s8EBSQE0xjXeAzVphVQMoJOMa2boxCRRuBI4IAdNdJFQzCIpi7nEKWHNQIQGIGtqqUjJ1Eyx8mQFUSIHIJZTMdPMu9jTEIYJaIY1WWpg0CR8Oy3ZgDc374sEtI6rW0DEQHR+j7tM4x63VXfjpAleWvfwmBMGow0f1FQSuM/MlVa+5LNFDD2yZIYMLoQ5gYMLkOToEJcpt24gYoyEiOBcKcKD/GoHPtsPHx4dLgJW7ubE2pnJs8dM4yCLLlZlGdnG/BubIfHs1dulVXZPJq2xSRrmJ+GMsv8ofAjGZ5DPsNypsXUnM4CzYDOCWbazW3Q5M1cIvnm3r2yekj7vy8njWEYPH9t+qYUTkJHxI6rB6uD3wxe/GZe1yoDDgjMxfWv1p/c293cYLogK7b5jHIPrdhR0x10N77zn4VPHs7/z/9HCv7yv/w/PPrpb6iKO/+7/+3xh/e2X79lKgd//m8/9/qrpx8e1ofvDsrdkjiqEneqnFEuAsHEAzlFAXLSb+gtemY2nIt1EbBTbBCiy0Wb3Gtso9NCqd3M+D/sfLH2jlWigqcMVt1c6uaI/vqTWfH8hAZDdJEC75akRh/cqXbLix7qx9PsUygmgw3N5oNmA6GLjUCBBGAhEgMEFVCMRui7rmIGIscMIq2mujM1DUxRBJK4Aixq4ksoEhJQmkg59tqEqLKeVasjAlEAFSTFfm+RTE19GFq/n0o2IkNgSxroNXFSNKpqT+FASyfdkSamjKiCGpDTKIaY+9wMgnR9GAsiM4Napx2RS+IyR5RkiUnYgQQGfS54sgJq0pEZkHNRZHt729ROHh9HlUFZ+MzPZuc/+OEPvvHNb17c35udzzPHBuozLzGmz8zSqkkiAKQNtKg6JO+yupMMiQGIuVNRIEy2ZseqikjJ9VXmOftsUS2Y2BKcTOSZgEvXu6qmaQDQDGIUIk7GRJEubTHSCC/tnEyACDIw1dAxGTkS8TN9Ybb1YpEtSj3y9bHUFR+e5GfT4Zy/Pi6/+np3fMLNvDqaj3ehYa7cRp1vAs1gKDKU8WBzlO8sHtbfevWlzd29s8XckM5i16xarxkEY/bPv/bFv3N5a/rjD+5+tDQlaBVatlrrslzx5Fxmm35rgXM/PtMguEeUo7FxxguYr6ihDYJczyD3L37+cGoPD1ang+dWuPHBw7NbL30hz55rPw2hcwVn0sybauZ9gd6LKDW1HD2l6hGgxS5ltjJCB+gUzJFqNEREF0XNCB2hCiBn5hy1sfSi2tWaDy8/B6Pd5s5dXi5CkTslg45P3HgcC/KzyUBiVCEoi0JB2Wvtt+awNaPNmreP6+GKtxbdQJcQqi6rHdUEjLYCWUQ1RYTzwVZThQzKUZZZWGzvXB1d3/vo/r3s0peuXrl5NwTR3cODavXLH+Un56i79rhqGj95/Vv+ypfx4xMLTjQ66BDFQDDhdUDFlFBd0kylZjHK+fmZAWR5Jl3HnAGZinrvNWoGPsaI5EJU6BpV9bmXqJEgJRj1NI9kT4LezJoGpEkvhGuVkPVmHVsbBnveE4BJ7IgcIAA4VQVTIkLHBrHHwBqwkoFFACHDCAZma9p8usb6PjUqpAMDCDGmRMQuiGOqm5aTLZiADKTr2AjIgaohKAI6UjAxdeiSgizFEmsaCaQDAxBCQOvXaSLiHIv0gg6JMTVQRIwITei8977IQ9VpjEldKRIF5NnYAPFv9LUJhmq9fBrXDTgxaa+8UUbqST22nlemVy+AQkx/A448mK5X2krgHVEXAgIq1OQGYpEaAlaYm6pJx3U2L0nCyzt35vUw7h7hrhqcUlkpnOTNPR0t/Nl9jXXo6rrVXaqpm+Ggi4MpZGajzZhP1Z/qZEEb5zCRWYSZ6czonOzccIn1vKUaicX/6q9H3/7d2BFpWIUlb0zsyiV9dKJ5zhEKoNVv3yyuvbrMXGa1QS7V2WTnpafbL4XDT5rpDF2XUeGCGhXy5juLT47rvPAP7jry+//1P5vP6if/9k9e+cP/VfVoQYf3Kwfhyd2Lt1769Idvbtj8wqtfrk5Pn/74F6PJBOaNo65TIS2JhpHACFE0qiYFkFdPAVorGspbKzrKY1d0ZTE3G1PtEQRkM+CH26/d3b5cQs3BwcCtiuryjY39K/kP7i+K5zeX+XjWjOp8pxL/yrULS78/0En2UXVji7jDe4+q+zh4bSzGnTaEBNqBqYEHU8AOwAMGMlHmQiGoBgnii0GUYKkhNRURJo4ae+64pZsUASD2CyAgiEakQEQkMQKgqGYFp6yHfrajYGAuqYv6VGBT6DUfWZaJRo2xV1mZ9QU3JQkkkgExIWKMPUgOklmI0Mza0KRjB2o+9yKiEhHJokYM6BwgRBFKZkJTQkpbsARkNwNKPBKm5JZMZXPUiN5lyKGThw8eFnn+3e985zfvvTss/PXnrx8+eqRRlQCJMqYklUICUfO516hBJPmSQwgFZ4lLoJoywcEA0GE0ddgnpSjCZGc7NA2nEYJZIvE5IjMwNNBo69jxFB/pmWNU1zcJGGMkpLWmTcHAGEwN1QAwA1I1NRMmgCgtDlb8Mly4kWWnJTzRZraihs9me95/dZ/3nxs057PmePTgpK7dDPyouLB96RSsGxb5yPt/+E/+3uH988fnx7xfbGxsQu6GV0dxEukSypa7d+674dXPfe3GDw5+1B0FrwPoSGqBGpZlsYDx06bK3ASibO+cAwJ6MNLotBjmxXgwk1lNE9u5Rvnu4cdPG7+/CmUmFpr4V7dv/8MvXmtCS2fn0FbOLZ0IRW3qOVfzMD92swNtWhqWwKu0j3MAEaGvAIkNjLVFdYAMogbQaRwD75dD1RokP791czreyeoqnhxx4RQjokVRPgqTCuXK9t50cexyG4yyJ42iFaR6LpvnsaziYOnyUyyfSrE6D3DuuHZaKdbmvIMaIIvOwECwyk7NQzl5zgNcufbB7OnHH73/ha99v4bRx+etFruz396lX78zbja7+VaYneD4pb0vf4f8bpiq55I7ZyhAghgAAiGkZwZBUxqCWkxzTIn65PiYOQMzYk4ZAqQgTSDuLebJh+OQmKlfySBJjESMhtEADYk4ybAQXTqk2rNbe1vOM6t/el7TUAgMNIL3rGoiEVCJnJmpqpp45w0tjcskpRkDYJIggcEa9NgDMgA1RnYsqsGUnMt8YaoiwkyqSfitiBRjmo5hdC7N2DhJVqJ64r7oR0BHKekMDclRtJRRAQRIjmMUZgZCA0VLfAJ1PVQLiICI0VHUWFVVEkyp6nAwWK1WZJETamDNAUx8ASDqk5KfbdOSnAb7JZopfWYtRkxfF9aLKwJIC7wokjFnGcXUAakCgCMDUNNoFgC8dIFXTEy6UmXaeDK4Oj2/P65mqPebcGF4eeW609az+hl1B/XZ7uUNpdWHs+b8qHaglLtFzJe+bIiwy6pBsYQLs4oq2IQ50hxgblYZ1UQdhSawcBxvT978adGdi/cQtVMBNTTKn7sqBw8LzEFrUGqn9fz0E9p7DaQxSn+zg40vf/n8wUcXfR4kjxqAHAN4KPXh8Y4CcHHus+ZhO/3Zv95/7ZXRV148+MWvc2ri6Yl89Jb//j+4oE3g67C1Pf/wl8V3/+DKd//Wx3/6w+LxveLqzeWdw8GsbuuaCTgfCnDhNwAgrpZxXkMGi9Eg140StzJY2Wo1wk3zPIDqwp4c85WfDV8ts0oC1KXmGQ7yQZiEP/4QT2nCZTGvR+fZxtNluXTbn97Brj7+4huyNe4ezAfXr/MXXy0+vNd9vBpc36wkU5+T1skMCxGU1aGhqjLkUQwoIvo0FCakAISGgA5MvS/asAIzQHP9/hIIyFQdAKbCDpQQRoOyXi5NzWVeNDp2Fg0RQA0JSBW4L5+VAAEZ17dzjJC8eUmYj6RgfXpYYtaBSyDjRFBPydupjiSipP8CSxAvS6V5OpKY1kCO0lch6De3zmEES5D1tJZXsJQVrGpJVum9V41gRo4BoGnb8WTy+TfeeO/2e2ezs+euXNWooRNRTaSw9BrKHGmXGNRgIo5cApiIiXMcRZLvKCahFWIUyb0XESA4evJYJXrH1tc/2BstTJHSBjOmqiEJSYk4mmqUJI/TZxv73sQNERQNSBGYGDCopvlUiAFQNGONSmG40eRbvEs8eSLnZ2EVINYDCS9vwv5o5sbFJ5PyI4ITKptQbDeDreH1V2/+9N23yo6G13Y2t7ccZ0rabQfdVtmk43b7Cew8OM/c5PrmlacHd9+DFqw1q4EaqspR7XeXKqciETFYvrsz42EAAmIO3gv7efvcWce7l177zcPqHLaWOKzQ43nMeXxw5/gteOtLV7/z9O4ZR+GtzTairaZ+dhKnhzQ7cuMS9vfg8JgJhIzUjLxCNJ+pmFdnKB0iOiZkgqgxOOLtwkO91IvbkI2jLyZg1Zs/y0bogLELih1xwfneTcZl56ETlNA+rUgdeCvFeaHtxm83MFpq2diEaLcw7WqhhiAYNGhi7EEdaie2cufu6SI2z2+E8TBUM7a4cpe++8FiG1QzP1n96pf+9ruF7q1msyh+87V/5PdegjNtjmf18fTyxisnODB7TBTAhEgdqUE0UEeKZNY/CEm+ZD7zyaQDhKGpc1/63BPAqgnpoDGhrJWNaX5CBmWWp14h3Zc96g4R0NAACB08M7r2wfJmRASOuJ/DAKTjFjvpcRlGagaomc8cZVXTMpIzYACNqo6M0AC434cZOaeqBmhqQOgdg+j+7l4j3dPpSUFORHuRJvXizDXpBogIJFIiNiJGjUTUQSRm71zbBVElJHYudl2fs9aLrQCQYtJJrWF8mC6/Hr6TbtXE20WXOVUlJBGpqirz3kMvXrGevJP6fE2L9P5DUJMCLhUEBCldCtCS9QkRzKVEZQDrF2lIwAhWjvImBANiNAAjdkCkombRMUft2JGBw867lsCRtuCQLm9dPTi7v7rAJ6vF5dXWeblzTGOCk6cqEbHlzeV83vr4nW+P3v9k+vZHjQwGK8kWNfuiOIj5LG4t2ohLpIpsprgkWiG1BA1kUtqALr39Xn7w0QKUzg7ohRsqlWXUNYvNV7548tbPi2a64NK/+Mru61+GYrdZzSH3FhtAbprz0eX95utfn7/5w3KwoYoAgWAllgFmAYNCHNbN8k/+1aZBtPDgf/zXw71rw1tvHP3sYOOr36njPCyI2vvz936CVXXtn/5X5wfN5u7e+Mtf5r39+9Wf2cnJ6Lt/gPuT9q0fZM15HQgAQGDAID5KPprzKtPM+4sajjrkuqFJVoqFf5u/8sbXLtwa05OlzA8OP1Z/VDs99yEfNDQGs4p25m6jwZ3TpuQsjAaBq3Bzc6MAKfIOyp2LV/I3313dvFBUuIo+eckQAUlQOnOM5kFMtSPUjJwgOI0CBsx5lAjWEbnUXyKSQcS1hn6tcuoZcoQKgNWyckDkegeR9bMiAwTXy/f6+jZB7vqMEDBKAipESwpVSLJNcegSxM0gkd0+cxInjQNhbztOox1mbkNrBs6xQwXoIz5FBCE5/G0NnbO0G7KYBA89SAQQmVM6uHYS0mcCgog6l61W9Wi08fqtz//2vffPZucvvfhSmrupKq1de6kvX9Ne+zpXUZmQ+0gp60ds6XQRtRLSQB4VCTDESACqhqhJo6pgEBXM0mtGui7p46K0SeyWfl+9GhMB+g7EXD9ck9h1Ctihc4auQwMxl7tIHAGgA6ZW6wzK7EF3/JOPdm7uTr5Y1B22hPPnyvzWteLmRGaH+YP3Nm9/sM/hZDJ94Zsvl1nB6DsRUY0Msi22SU/C9hS262JrBZOFDp8ezSkQrKybB8rRltaUfp5tkNYATQTuwIty6WsgH8x1jSEXc8lx+9LTbvT0fL70exVuUfDagFVdjvzWr96/VrxSlAWwi4W3M6FHx7Q4onoeGip+/1vLh/fQDoGUiIWQMbgOwTuB2EBARIKcDcAiMinQAIExmgQX+WxrmEXY/PU7ocBljIVB5EwBWZSf0u4Ll25++PC9r7/x3Y8++OTovB5wqTF48K2OZyGvqGh5fBbLcmky77B2WhnVqI1FUSKnIaqPgc6XppcG9Ny8Q78aUldNNnhyuXtKzOXynZ8Ujz4q2t2mmvLFW5Pr32Z19cOjcb733i/e/ej9N7/79X/M0HXQOQQDSzoATAcHyFQM0u4QUkGaikoip9KNN8ahS2kNRo4ckYgGEU5ZvKkvUxOT4WjkGNgziGlK/zEliMkISMCAhKimPf6GADV1yeuGeC2+FHBe+5VnOg7OokU1VCMHgKi9PARpLYeitDPudV09wKcj7FTm9TLPc0YnIsRsGpNDABDLoqyWKwB0jmKU1G1n7EWE2UeV3OehC21UZkaDaCqxAwRCwx50pVFBLTrX73EdEiKqJqa0pUrf9TEsCK5nc6lqxuyYEugnaVSpx14lrGef3AKYwmSod4ukmx9Bk0NCAYlSwFVaixsmAYMSEROooEjHzMkC7ZANTaR2WBA5AGHKgGJeZE0dMAyYSQJADDotXvvL0VtvTGd7o5NqOdRJE2jlxgfMC/CLhXzztefe/bj+b346v3Zh/xEpYFETV74cZXGGOJ+BrzKtDCrDc3IrhKXBUrF1jv3FNz/OP/plU2YaurA8oeU8Gnl0oathM29ffkm6MPmd7/Fwr1tF1zmfNaqdyxyAkkl9Ul/4ypdPqpPVe78cDTYlxmCKKKiBHSgEx3mOmcUOT++NTkzvf3D4kz8q3vjChb/13YP3D/LNsyHywePVi3/wvU8/vnvhuf3BtSv1VOPTj9p3f73/D/7pcv/y5NrF80/eg7P5+Pv/DADO2+PTv/rT3W99ZTn9RLfHhZ/MDt6NOy/Z4qjDkXSzZv/a69/81n6sb3/4QKcPBg/vPkeD6o3//CAWjfASxjHAyk0qnRj63ezcY+0x/voO/a0vuVd26XC++OTnxy9+9XNxEO9CdmUcQhUzTTkalhXUdWYdGKBEpcyZqEYkIHCMqFGCARoQE0m01F72YUXEYBJNIW0twNLACR1YTEoGAFByLgkdOo0WLW00TdP932dspUNJROQcqK7rbFW1Z7GZRJactpDU0wpgSmuGRnKWWD9f7EtTxy5GSRaAtOpCg8EgF5He2a9p39yDu1JJKhr7ix8pXaiqYASdxvSNadc64qZeZZx9/o03fnv79k/+6sc3Xnzp8pUrphEM1RSQikFRr1YA4MgBWXIaMiI513Wdpb2aKhMl2zVETUOBXqSGqKrJ55DMETHG/qWWduQQnxmsTXV90yegOyWqgammTBdRTbjcpNV26W0MApA5RTJAsEiASXRJkbBgzU8/OhrzaEMm4+lw55u7dmXQZPem27s4uVnf2i7eOfqD6y+XzN00tlojgIKi51AWU9s+4wt+tFM35YqG954udGG0ctCAi05rdQXihjstBgZjBInkg+UB8hJWAiwGXBRB4Bz8xb2bd05WZzo+s83ThvGktjm5KbJyWMrPfvKTf/TG36lkFZaVPnoATx4IN447nvD5j/48U6Bh6VZVpzUBBfBe1Zw5BRTxvuyMu7bymQuNmKNhztg2QkLHB76ee/DSVkuisiNhozYCsSPgg+XG7FAub9385UFVTl5WnXajkYZuEaDm8UKHUYdVW8gSZk9WNAWYqVsQLFErBVEjAi/qwnxVX2se3HztpdX4ajc9qNif799snsCglfjBj8vzB7QadVIVt74z2v9qmDXNrBrR1uq4Pbp/11vx85/8+bUbz+9f3OpghRgRDUARLV0DZpo2Ksnn4ygBLjIVBbCu06TPIHIGKgrFwNdtKxozRxrNJaEjwNn83NRCCBrFrM/RTWeeiaEPxlubECG5FiDFHkIiQZkZoFoaz3Zp1pWIs9KpmlDmEhIvofXSIU/zNDBDeJbEtzbrRCi8r6pqVS0zphT37YjWWCxb1Y33GQK1ofE+A0TpYui6PM9FAgGpChokUEASmLBjjWnMlfyKyUaZfOaZ56zrgqa5ccrzNVhHChr0uavppgREsNg7otNfR/ImppEz2NqngYD2WWAr9UnBzhGqQdQk+jCHaXOUZNOJG0SWvEiJ/0NEierliDOf6iyNbYIPmDaOHGK0leeAuuFp1m2V2+NZc7odTkS3TrQM1ACHQeH2L7z5cFUXebXMLl3de/ekPiwoEsQAXQVZHdxGNlx0sIBuHnWuWAHWBg1ADU7d6N6x+/itedFAaEaTcVU3yqROAsQMvZ6vLn/5D4xJY7Y6PUH2xBwjORV0ZFiKSu7z9qzd+VvfPc20+fVPM3LMm0S0hFOAkhRWeuoRFUmdESGbTbYnAu3DH72Zjzbyy5sP33xnu1mtHh+3v3m73PuHH73548996x+8/5c/v/HP/6vi5VfO374bdkrrxC5f9hcuAcBolZ9fvTl+41sPfvj0C//sP18cf1C9s3Xj1o2zf/OvNn05Ut25eLN+MvvFX/2AYYEOBXe2v/D1125dPXrv7JHs5UqV26q0yGVVwnRAwtSWoMWoeOfde3Wb/eG3bpRNu6oOLjhdtLu0QygxKkBQ8GADI1FQjGrZgCyqBec4Z3Zts8i8Q3QIZMpJ95ewEkhkILDOHExjriS4LH3RNCuTmOe5c1xXNfHaNN9Xlv2PNDvVNfQ8Bf2BJJs+AGB/O/Y0Oks1unOEmN4kvYyjL0bXRb5zjhwnf13XdQTkHMWoIpIszKHrNCboHkZTRFBYA9jNAEk1ppJdoxBiIhWyspoAGhCKqqgSYiMBFF597dYnd+48uH9vZ2fb+qPkoIurrnYAWea7KAm5kc5uBOtMKZmW1USjgqFzpkqAElWp12Rwb1sAMIkASRMKAGCgGtUgGSnTn+yaBWZgBsi9ulIjJK61M+06AzQiJWQwJiIG1MxIQQNhjg4RHJkStJxDW1WXvviCe2Eiy9ny3pmfnw+uTvTGC3jpueXmlVX5kV0ZfyzXB1oNxmc5b4XQOSJ0+XHcmsIYN6/86v2PaGdH96/W9x6Pwih0G/OTGZ6TU0p0Jgru6Xh3NRyfdGdjWo2gGkBQJCNC8EElDMbR3/jw9C76S2Cj12ljcmV7+9pzcIbF2fJ4Y/7Dv3zvrfLjN1672c0rtzfRWQ4SgmJmUg7H1qnGRrNciS0GnxXQ1F29Yucwz5ex4yhM1GjMM9+pLVU3qWA2JB0wgKyeste2DhmTgI4yJWyXwp/M2FXZ3am+cHFva1B0288FcgdnT8AB2vZCc6sxC8yzyMssBrRatYa4EFgBizMEwTitZnv7myN//eTd+5lXHWw9ubSjD7oihPb2jzbrpkWnZsUbfxv4xe7OyQe3f3n39kd//3v/Yn50hA384//1v/y3/8//03x59MLwQj1b+ZzRpfOQHgglgmj9cpAQLNEfpfM+F7VWVqDIjsDQgI2k7oIjSkpFcNTGiIAOgckBuigKiIjOFA3TQxt5wKqa0MqJWAdruysiOUYi7EKXEhwcZdE6hUiMacODvXBrrUdlUlMyUBVMegW37p9TmW/rNlFNydhnaIoZ6xpGRSnrCACdqaiBEKHrpRXmHLdt6xwZWCeC6yE1MqFaRq5LrT8hmhFTWhADQJTYxlTtptUXsOMYe6btsyFXmp5hMhWBEdFnFMn+NdfX+mmaDYhmz7bbhik1zda8Z0gtBSJSYnCmJXsSz+jafdz/4SMhQhQpSq8CQYWdVwve51V1Pt7YCV3XhEBWQi0k3Cm9erj/ttx9cjmDg4fsdhS5KoSH1NwPW7uj3Xzjp2+t6q7gXK1WDQi1DTzHYtnOEeYGDcASqQZogFrUFYBB+cE7wdUoJLDoVllz977/3BfyCxexni+9lIIxNlorsPeFA2miuswNBMki5RSETKAFouZ8sfvt35tfGK9++OeT5pgG48J5EommzKqCZC1BFNIQFCa7o69+3WOJTz51O5/b4N9SJfO//veXwZ389//d3mjj8Z//L7vZRj09PPy//HjypS+Ot16+U+ul7/+9498+AoCycK98/x9/8tMf7NCwmXHHL+1+5/LhJ29OYLIil413P3r/vWmoSxzwzgt08YXy+Rdl/9rd6dPJLm7Mxh+tJpuxLmjuqSmhLbXZgEYxcCwGeXns7Ce//Hg0Ht7Y237XskVcCRsWJCGSNyhIJJIH6pA9mZgvfNOsCLIoHRKpCqxbrDV/FJDQLLLjTkLK5zKNAMSEMWrVrEzFses66YIQUySTqGw9kl1V7NmdaWZmaeuE/RgYwBJSug8/S+2dKGQZA1gy0Kd9aJSU75LKfQRQ77OEoosaU+1sCl0nyeOXZJxt1yAgWcrV1GdyzrQU78F8/coFJca03WpMmFG1N0ZEESSnKgoUV/W1688z028/+ODKlStlOUyXNAFmzqGj2KkREqEhRTWQyOCkDxY2UGVikU7TNonIoiEhIUqShkAP84FeQAQpAQIBYu/aJlUhx6kOt/5Eg6m6tNpmiqBKqgBFookBGjMQI0Ukh8qOMgVTbZlzcEAEm5PNruke/Nu/9pNcN0X3VN+T8bUxjfKta3TlxVfmGy88HF/KpM6bnawcGQki5MX4uNuoYFCvyv/2T3/58tf2vjPxZeXlqY5kXC3mUBMogBgGhAB6rvMxb1y8URdqzXSEXQRQBScUVCc712fL4dN699p49L0v/d2q2qJ5Pj/pGFfh+OPLw8tDfHD747euXCo3dyZLN4aS4aQeMIhh19ZA0XcWXPABAFjjXMhl2RAlqjpyorYiLCArqG6J8VyikBtznitFGs2aJ3XQAkjUyLlgxmLggPl4gKXWXt+eN1eu7ZYevCPMrixDsCXDKmADbd3hykGd4XnUWYRK41IHlqnGsIiz0/Nia9TOs49wbzwY7509rulSWO4Wxyfw4Q9HmEdk5rH70tfRLk9m+vbb7997/z0P7qd/9kfo9OrlK5NSv/iVr8+XjwYDvwVF2wZVJdIkkiUAjQLU+3BtfZFplMl4fD4/FxUgUuv9eybmnZMYAXOyqCpIzlQdAgEVWYYIISpicIjdKlx57vKF3e3fvPdRXnokJVBSJHSKGiECKBCIIFKvNCQHMUZTJUVVAwQHZAYKKZoJGdFiB4hJxsBEGMVFioSApFEsJcEgqqNo5tKcB8HpWs5hvYWS2PU0LFDOfCvdGmAFLiWnQL/BRSQATSCOTqM56l91BmA9ZwN7OajCWiEVwbQTS0usnkNrzEwAKQ7ZMYGCqjrSTiM7R2k3vEZp9omF1tcUyaYVQQlAVMgIDIgoxohICRCdBC1ELlqSwaJDjJAckJ0xqBEAhdWKXa4hiIuIWV0vAFy1PAfwBDnFoDUrCFW6AaOL1eh+WT95eZN/s/Lgp4cRdnNu9Avb5f/9T5/M3bgYmSwCNsRdlEUHw6gFuZnGQLAQaH1oNAuqlRWcyZMZzGfio3WNN+usZtT5r//y8t/9L1akg86iI6cIHkE1RjAHBKgamEABFZ0aOYjmnOswnM233/hce+PK9Ad/7u58uGvOBgUQkUQTjVQrEyFlZRHufXr63/1rHBTFzuXFT98sQjvcv6wnPsqi8APtuvLgjlpWf3p7n0fn/+H4+Ox4JIBVV73zMwDIvvoq2MXzN995+V/+1+/8xU9vfvHaIUz9f/iZFFefapTFabb1wvbeC/HaNdjeBeeD0WxeH53EbmPvymjGXX2gk6GKt2ZghqxKqzwgAcxjPRCqaPvkOMygFRRrBy2UjhslVeUMgMg4LVsYDayVgOz6cY4CE4mBagTtEugCMFl+1UQkKiEkjgxAYmuYQ6cRHLkOokRxSmSUZVkTVhQBkNKIFhQEIXnueG2QJ8JOBIlClMSm7bou44yQYtS2DUn7J9olcfSz2BAi0vRdheTtJFDVqIB936kYNZ0cSMfPRM17Lyoa1czSDrvrAhilxt4516kQgqOEwlAx6j9MDQGiSGJF5kWxrKr9y8+xz+fzOaFlWZYXZaJhL+uaHPVrOOqlIAkR8Oy1ETSQ9mO7aMnYkWZSaBhRk8KiTwk3BSKOGr3jJnbc04LYOnHsDZ/1DEBIhhCjgmmalTEhELnUrlDCmyAQJWE5RUzWb7Uw8r7cG83uPZ1sjBaduYb8DFaq9ZFQ2cyncnDvbEjivxi//91vV48fbvNeBHC+e/PHP7l48wvF7qtPGzmGvYsP5g/8k6OP5tu0P13e2xs+d/T4wDVoLWFjqDjhyezRrFt2OrAO8zAaqgh5Z5JFq/fh6uHbn8AJTQ+qQzhohGjalLwFgYUvcqtXxvzh0eM7H793q3ydupWAK4kCBVIii6CoGZqwkpl2CMSQQ9eqmtMOoxp4uHSBzuaRnZrlDjpon9RgqH65sNx5cgICYGRYdCgqwMw6E9cQF8OizE8/mFYlX9m/OFCcjLYPjo6pYa0h6wha0lmEM3FLWE1XQxo5FedDtWr2dnIBf/5gtr09kGV5NHnBQ0mfPHb3flUCAyFsXYSXv+FwMxzOf/KbX4Ywv7TzytMnt1f6WOrsxkvfOzl9fOXqlbK8UVWHly5dfPjoUII4VFMxAIRIlIxAQJQCGPqYsCdPniCaI7feHmGfEm/g2QUVSSQwEwfg82Jez99+79dMPouaey8aofCns9mimlOOhMTAYoJMCgqqDA4BogBigrNTNOuiRFXsNHMce+KqAa41nEhgmhA5aXcSTZ1jTaYj6YjInimsJJ1CcKgOe3lh0lkjEBCICBFlzGCQZWxRowNIib+I2m+UkiEymcHX+u31YG79L/vNcyLRIVgURUQi0pS1kN5HIuCwC9ILO8C6IAjA7IIIgqmaEqioS3xpJpWY+awLktgdAOl7RohAhApKjuN6RmiqxNyF9tq1axf399+//du6WTnO0kxATck5FSWCFOEp0vliqEpg6ggaadffqgvSFFRQO6gkkDafG1w+mx1WeTeszRo/ny340lCO4U///eL3X7zw0w+qp7PIPoOg1ilVfqxKWd3NCVYKrXLdZIE0wEjoQa17jw4NKo5diGLea1QApMNPwuHHbu9G01WEAuoMc+Pgg6pj1RgZUIGYRLpILo/QovLQNIRP/+iPX/ru98v/zT+p7j58+uZfF4d3fTBgx3mOuJ1LE5xXZTegEbLrKDw89IhcbFbz1keJaqKdIxdZHWVDP5R8NJw18tY7Ozmf/uv/6XIZAKA+eXr8zrvXazv+f/3P+8uT6sPfCK/qwYV7xdZob2dyaa/Y26qZRU1XM85GnLv5vSc2HpSus0X45kZ1QsvfnGWIxk3NMWRRnDatBW+FukkGUno+edLmg9EihOU82/UCkIdcY2cEoI7JKQD4wocmqKppFGm8JyCVEAnJ0BloVAETA8VUZ/d8GzIDItRoaRRDzqmaI4oCohFNQ9cxoSBQmrIiEBgqRkBCiKpRlYkMKGqkXo6Q9I/YiRChSEzRgaICfdWpziWaL4hEADPqt6qwhrgamAAS9IYDUkDo71dzFFSiCDOrqWpcc6F7smwnHTmXRmLMHKKY6drmCAqfRRVnmfd5oaq7u7uz2ezs7HxV13sXdidbu2pGnAFAVGNm6q9vVUAjEBERSeFv6fQnR+LfoGmqU1CHikgGrKb9lM/YOYkxY04Ky051XA7rpgH3TKIJEBWSlZ/IASWOQkpEdewQ0dA5dIiuJxkhAaT1aCwm3h00dTX1uv0SSSd6t9Hdhm/VFDf4vZGeiS5Yf3q7vf6Ni364+e7hg+Ojk+/9ve/+1eHPXtorXxvv1E9O7bEuW4mbMHvn8PrG+M7ds/3JS2X3tJ41PKBYQ9ZAqBpy3BwHVyCURAUVxaiq5szs2MWi03viG1/NG/Urdedynm/yIs7mtNIm0+sv7X98eOfw5NHOQ3/j0t6ZNgJixKRdiMEhRnS5I8pcaCIiGghoJKDOJbmpyZMTBlAH1EXsiHKPpefc6+JEVSOhUzSIAVtAJnKAyhehPHhS+bGHusqQZU6fHD66uDuhvN5pR+cnVThtqvN5Dn4I2/NH9Ys7fnB5swndydN5Xc9WjTULzIrJoOQOMWvaZupldnf3+J1RPpLYdJdvZC++4Wk0vXP37vvvzqtHKvH7//CffXC7vvfpB1/73d8tCgrdUjXWq4DEt3/7blGUKbYgJX4oWIzqKEsH1RH3kWfOmVqSDjA5NUxkZgCIIiGjDKkzI2IFAcfVqrm8t/f04eFgY7K1u9upIBgjq+pKokM0NEXIKO9CQw6RSGJEdIl3nE6mA0JFVIgZGYCIOXYYEx5TGShqVFACkhhTeFFajPZZCwamZgSZc7GTVG6nlSkmlqwBaWp8+/GuRgUCNOha0aiOKIIJGFhEAyZS7DsASpyvRAXHtVy5XzX3BzFBf6xvsXWtWjGlSOTM1CKuR8Q90Kp/K6XsYTSNgEjRIpiZEpouqw4IEEgkEAI5J0HYMcQIACGs0tg9GcYYoFNd1stVs+pCwGgK4pAUMYokVKEqO0cACoiqHVFW1y1gIPKqHQCJCFG50hY7tY5WqgPwu7PN88nTAK1Ww0jYzuGlYvDee/XywH7nC+Ons9VPby+YCxaAszAcanUyx6aItRmQLiMEFZMz9XcO+fnlU+MmmBNQGnOoahQbCc5v/8etqzfaFZSUebZgHUQyz6aJewoxUegJcwJRUBH2xcl//IudO+8dHxwOv/nt8stfyv/Fv2jvP2p++xu9c2cwnxuhSkMloyOIhQ3HLYCtKlY0CSBVVMKihAZQldibgYY6NnWJI+JC0DjLBAoA8LM5VZVsE/32fjkptdSz4dj93t/d29vmTOIATuOSm07znEcv+k6mP/qTa5+7LBukzVlGIoPxXt58vlveOSVHlEk3tKBgwMAKBsFpRmpZJqQhVx8kii/UBY8ZRUMHSqBGgDF0nQGQZ5XO5wVBCGFF6AC6Z3b4BIkBjS6NMRUgLeyAABSRknlOJJKC5yyqJQlxSgtWAEVaZxH0o23VuO59EdHFqEQWEycSgB3F+FnSKHESSqOp9EVscjoQETsCVBGBRFNNLt71CP1ZXC/0s28VQXw22u3TNrGn1STsTJr7RBEldtCLSCIQQoQEpxaNJ9MpO05a0+3tHeZsWT04fHTg83xr+8KqDeQoFeJApFEBQUHFNB8Um0UxPZlmzL31Q9dpDGkkTyganREnoQcDATKgKigkDY16zqJEhyQSkz4cwMQMAJgpMeTTFpDJERElfFi/NiJHDEgKREAJXSuKSFYQd2GVF1Gq2ZYf3ZYWC/taXv5MZl7oS5b/cCX5JDtfnN79xYOXPn+rmp/94mc/+fY3/8HFva+t7rc2jnDGcM5tqLa+UJ4cTG9+/nk6l6PF3c9/+Wv3P7l9/OgUyYlJDMobmWZkQSk6XcTgOzav0g63J+3jpjms2RVwTr/96OGt53fOKnw6P7g8vLzKY4jL/d290YgW1dPTamtvNWGiDiWREzKCCApBxGdx0RCnSaVESOHoxGaSOe5Se6LeF6ptbOcuUlepA+LMB1IQh+hMQ56RRiDy/NWrt2D50cPHM97w5tSReiqreZ1vcVzFTR25FqAOXR2auhrHbIAeXch861xdnc/IeeKcWBxAs2hadpsPHm2fP8xw6EJVX7up+1/DoEcP7qymD7/29W/99Cd/ruGEvH75S19/9eatyVZZr6bOMaJIDOVgOBqWUVNPRqZsIKaaca6mmKLuDQCAHFlUcmQa1RQtPTRkaYFKLkrsTICyECV3ZBHYF8eLR1/9xtdOjqehEUeIyMaI4AwjRYwaFSJFIkCIiAToECQFICQKh4U+CREQKHRiCBq1yHzT1EQEaA6JKNP+SIOqUgKpA4qBARRF3olI6NKRKzx3EgEMkc0EIKEjnarheiC25sMqOuqisiOihLZIagng3j0FCXqbtj4O0SEKpdSi/6Q5NoPY+xWAmFQVAFOMBKChGlqfBpHIu0jARhFAknjKmWg07aNUE50HQX3mNUaN5jPfxI4JQXVQ5C++cOPho0dnsxlxpqreuenp9Gw6U1PnODED1BQBssx1XTQNTQzoWMRCEGa/OdlczOvQrpxTRANlAUUgVIzEVnsJ9fO0eTR8Gmnm5ruVuun9zld4bZD/3vPF229VL27758kdHAZl1hrgRIvxcDaN3JhoKCALK9kbubeegISQQy2hRXIeNExnpIIQIhbd0WN8crA5uVaHioBABSk3EyAEBQZDn8XQMrNTW2nMirw6uQe/+eXAj7NYL3/wx6t3f1V+5Tujm6+M//73dPEHq8Oz9sH77YMHOJvr4rQkR54JWMERoUQix8DaBQJbSXKwgXcADlQtBAQn3i9ECgIALTwTu0WTFbsndZgdrtptd2mGFs5DkcPI82gzFlmn8/Dp/aNf/cmNz1278NyVJ4/e9RmpzstYzBscDSLLmWta9iQFUAwcvEBwGTgB0sL76aKBohh97sbmyZMFOTZDyCx2iKDApmrsnFLi45LPcNXUzFkS2KqCofWZXIZJ3YiAxAQAznGCWBFCVDEi5gwkEjtQ7dbUNgJUMF274AzQAUaN3mcxSqLXIkKWcYxCmEDmiOgQwXvfhrC2NmCSO2ifswTPQh9SbolL1kfrnRTJ4qT9twAKfVODgM451diPttJtbP1OmYgAMaoiMpFLsypL0SzrGzxlJRZFEbVXmdVNMypH165fPz588OToCYAbjkYGFjshR6qaZb4TIYIsw6i6qhtiZ/2VC4hrbgElQqcRZw4QjRTVCB30xU7XG59TTgwiWJDAzGBAjtQUHTkkQmTnABLOkqjXsPZFBhFjDy6BZ7d/QvUJhRy75WpFDJUsX8GsCXLncX02dOPArI4LDcJA7uDNj27s3boML19y7z9+e75HVx49uK0XHVUwCpsnj+fVw7nWMD+Lk0b/0I8+ePDpKy9cPXp4UISJGMROnRiwmkesFMiMkZyTNlzYu9wcLfVYlTQXfzYP+aTxzUanI11NaTK2arpa6Buv3PjJW7+ow/T0WC7Pj1tSB33IlQOLDizGrPAxhKSzNzBCp2agIEmFrsB+IIYammLvctze7uoqHk8JRGNnoEiUUa5dRGKxwM0T+cpzr0z0wZ3DY819UbDFQASnT+Y5Y5aNfO0H7USq+fnT+fbV7dxr07R5IRsjXFSFQKMKVXPEtlFYHD94d0c0Mos8no1vwMVLI1/NHn+6ePLgK1//O0TB08n+K68VLrZNNRjQajV3CBoDOWEC0JZcLnGViseEhMTE4XNkpo5Sa5jSpVVVE3pGoiA5IIyqGXPbtoNBDipN6MhhgqsB2Hxxhl1sV40fDDuLYMbkMCoqdc4gJi00KGjThr3N3c3xxt2797PMq5pZCnJBcmxmJkroFExibGKD7NKg1fUXEjqiLkpfCwNCj6fEtmmAiDNO4uQs8yYBCI0AumTvS+AqQEdR1ukOpoacQgxpLZVKkYIaI6CLDtDAqTlKpD4ANOldv333m37Wv2EQgJxG7TkDiAm29yxVLYEEiNIrMvUAlORmMRqRUzIm14XOUvYDUdeFtAmSKAyIBlE1gpWbo6vuWr1aoREQqkqKOE31RoyRHav1XQ2YpfdLfAbU1K5tmr29HRGcns7MYjQlMfA5dC0DkFgkgxN5Ebdu7y6yuXrQw4+6wQR3WN76iyPYHwcOW1n+oKmdJ6fkCOqm9cwhJxcsRCyYPpoXhwtmH0HzSEULAuQBagUFLP1gqPXZ2Vu/3Pre82RsUZCGmc9CqMiMHUvXkKBnp7FTX+TG2Yif/vsfTkAabQCsKDbo9FH97/6H6heXNm+90V27UTx/dePmxRBimC7k4b3qySHdu0eLp1mXRfZQeFNmVCCALIsdSFDKGofUKYOBy8hARDgGAoAcPdZzvHrlnmg9n+sIRpf3i3yrVXFBwuy4fvA0Vqc6P8j09JWvfWnv5kvtyYM86wYqeZ4XZdGsThS4VDMS19RZnSLVo1ARBBoEBoK40Xqu2D097tiJc4OOY4rRQHIRBV1CU6CpgWHTtmugRMKwOwMzcmCRiACYehoLIRh+hnUB51hiJEJFlCCRjJkTGDECgEJy8gKAUwAyBErK6iQKBgAVeXYZJt+tGQSRRNYAxbTWTcAZ6O286/sjwSoI+/ThZ5udlEhqqexP9W5a9xgRRYngqAe+ijA757DrhIiYMk1KUktMmiRkhD4XGyyBHELdIiECsXNBwrAcXr1+49NPP737yZ3JZHzh4sXxeDMaAHIEI0dd1yGYIxSVzGemEEWwf2lYrwJBQEBSEzRAY6AMMP0pGSo7UgN2qOl9CwbsCNEQiZB7S5dDROov4GSYRqIE+eqb/l6bjsnDbWZKBI6AHY1yRqs90B2Ir3TWmD9ZwWWfTRv+5YnCpodKs9Hw41/c+cIrhy/euHytvHH4m/t7V16oVtv1wRKk2MWt+09Op5/Oro+u5TOeasQ4/fpUPri25YoOoNIVO8y0UZc7IAMyZBch9tyVGbePGz73YIgRqmU4Hp9s7Gfzehm2HUw/AM/gRhcu7XmKT+4duJeenzAMWo3Okwtq6eoEBPDMrYghKDEGIda0maDOhJR9LqGybDB45Vbx+isuH43FwuJU2647etzd/RSbeeDOZVmOYGoMM13N6hvD/c1Low/vHc2Pm2LgHTIChCAriiVk4SzYfJlJDRHQCgTppC5KKQpogkIMLiP0q737t0dFmFUzAN9dvolXXh3lBjK99/Cnb7z2u8D1wcEHNB7ffOVm3S68e8Z7SodINYKxG/gNVVQLAMSOYwxJ3mcp/M/6AU+MkZxLSh9VI2IzExEi14TgiJoQGIgALRoQdQpOusl4MhgMYvKYm2XkQIEcq1PSgOzVQDphhu3t8dHjo5Pjk6wsAEjX2l2NQuAQAJmlDZD0B0Ca5NFE6YQnGSQ8AzSm9bsCRXCO1WGIMWcvIvWqSfsDjdbLqA0YHNB6dgw9VwtMzNAhRTUDIwDXT5YJnWOIaYJmYJSWTzGVpp/BrC1dpQAIiVuvLjl6nUtuCugdR8kCqCkxKdXyiWxL1puOXDItkQGBqjnn1CxjjhLZcXpdmUXmTCXevfPp9vZ2PiiaVQsAncTNzXE5KI+Pn/Q0hlQ8ApopORLpUvk1Hm145+eLajQqr127ev/eASKU5aCqGgPDqITkOOuciZnKanNR7D0nD7erCWUHoF+9yh/cX+7fGqPIAfFRW+XXBiqrXGD3Zvn0ZFYouQazJkMEWfBH07FxiG6z1u0CH3aW5yDkSLRVy5pamMf14aP53duDG78Tl1Ok/Ojg7oUr2wMa102D3oOokCJDWK1G26PpR2/nh3eZfYzkHGJoALPSe52frH78Zx2XUo7q6y/5F27g1avjL94qsze0puZkCp982Bzct7NFMTvrUBgzcnkOrNsjqaoIESgCO4dBbZBT6JoIABZX9edvHu/sre79crjpW1d1h/cO/91/X+vKe6aR0oBxZ3jx1ku7r33fNeft9CTCiimqxHxnRzdL/XTaKbRUDtkErcNVptRgbDkLmrMfBSy6bKelUVPDvMv2ymFolwQZA6iARHWRVVVFo8QMXDKWAqiqIEQAwTSsIQPt0RKOEl1d0TlLgUaaInXNIcYY2TlLpSlRTMho6+NSKNWSZADIzpHDEAK5VJ5DqtcRktk4Ha7eRISIhJgWzGnyjCmYQWMaIUGfvWLWY61MwHolIwIZGBhp/yGQ5uYKRiTJTI/AjkTk4sWLT5+epsp1rQthSvkN/YVOaeMTYzQzn2UxJtckFUUeQmdA16+/cHR4eHR0WC+ray/cGG9ui/bwSe+9aRSJnrMgYp8lflpvykBESO8scIBExI6dS4LVnvPVB6llLum7iQk1pcekEDXHzqXkt8T7XH8JAOjjxgEAgdflBfTmCFMidBYUhE0i1S/CmLEplT6HiFWx28j71GmIec6wghbl//N/+x9eff2N3YuXpw+rKxPaLfbDofiSttz+vdkdmnXN0yZcar4+Lib18rGn39z7tclS2ACIMA+tPf/cSw/uPTRkRSQ0cARCOKPlwwqXmHkTi6TVB4/vfOfahGgBfrMoJ6HrQntWbk32diePjw9OZqN7Jl/oYJWJRgcGSkoKkbSpV0lraBIQQVQdkRAwJDRshO2d8ubr5eXnO88A4EiKre3IhbtwkTcmzcN7eVPHxblqQCSOtfi8qE6bzWL05etXHj6ZPXqyaE2HOUPIquVqvMOjDSBfVnPa2MjFBMggQsG0PfHHJ03AjvOhOzsI9cHUec9++drflnKXuqWYLo5OVudPeTQ+fnzvgw/e+dY3vqsyZ+vAmDhb63EdQOp7cu93z84b9gxAZkrEnTSOUGPLro/8Y3YJpKlr718Xghl47zXFI5mRohICZ6hiRhlRxtQEeevtt69efaFeNebQCIidM3RRgVzbCRADqvf+jVuv3bt3UDdhNp0SM2NyxIM5EgBVAVVylMjLIFr4vItinVDG0RSJYnKvmxIiJJg7OUKQKIqEhlEEVZVsjQpRcAhqFi3hajUasQPt04cSN0pUyRJJAzoTA2RHjiiaAhoZYR+gaIAY0VKsyXoF3I/7DMw5F9OlC32lkMp/wl6LmiRRoj1N8zONaIInmJqBdtpzuhDRjJlVIxISUQOCSg6ADBez8/l0lkQyhpixWy3rZVWxz5BYRATUIwEpAIqIGWaZHxUlAGo05kFtkzf5AAEAAElEQVS1qH/72ztnZ+fODaQjAK/GSMzZCGnIKQK+RHXxxXa4eF7CeRZ99nTo8Ird+mLxybxersKXL05+/Ms5+YLirB43mFNnhVWhXWkWmwcysYLyXa013mmvf7m638Q2UI3dANmDmoJXpU3i85//vNz/XKTxqPTNcvrH/48//tZ3//ELr7x8OpsVVITYsGfPJnHRvP3mnnJDELF2kgXGiOZD49hxURbgrV6s3v+5vftm3Jgstvf8pcv+2hujy7v8+78zgN9r5oGPTsJsEU+P6scPNbSUqztr2BRVrAtgWY1VcBv+4mUAuHtjvPrS6/mf//WYQ4Qy37lCV/fdBR6NB+X+RR0x7xW0PR5ysMWT8/d+c+lLr02nC2ZUcBqa5ryNCI5CB76LiNG1EiHDgD42RISNuRqhXlZWFgCDvZ3OZtE57lpjkaBE5ihEU5RWSJ0D10jjfUJLYkx5eX1qR3rO0gq0lxqk0Skk92y6mcxiDJ2pYQ+4sNQsq6a8aNdnLPUXTNoBJ0Le+mY1S85FU7KU3dWb0dPwumdPJ3N/ooiqCkSHRI5MDdccqNT6rtM9+wu65032fXPsIZpEGo1UPWdPjo4IeT26056zldzDBtgzvxIfnQiQkMhBQkrHGPPcS1QwuPbCC1nGDw8e3Pn4o+svvHj5uatBuhA6JDRAcq6T6JKMgxAJnBE5p5L4Nwqmxi4zJHKpoHgWyN1zN5N0hRhEMXNk2Cuc17ou6sMhWdcssBQ7s56XISggkK6v+1QaqUUjyQYQpS6w/DDOMANTwUgclt/LL95myZC0kes3X3p4cqd52v3qP/wy6duOPn14fHB6Y+/K9//wD7/x+jee3L5bT2OR42J1rJubDuTd+eEnJ1PPpUhd+BFCDF1z/94HnvMQOzNABRXgzJO0zfxsNCol1Hnmspzmp0eoq/Fk8uDw6NqukJ/gxjZIfe3i+OCpZo3w6y+c3H04XFXGDM6RdurAxWhM2onLUvKvi6pOAYgFIkft0Iavvl6++LKomqAJCBEq+DZApvnVK/7SvoK0Dx6sbn/g64rffPOD37n52mRcns0qdPzixt7FbHz38cl8LgzgyKrVtCwGqtrJKi+cQgAUJBBrfKm+ILUgnY1PHgwsOon1lVcXFHn2Cbtx5/mkOjRo7r77w2j0rW98hzwHCcgjoFQd+CiUAmM1ErEncERjBI0myfrtOBXRZkYIChC67llMN5qSdGH/4v6iqpqmISICTGxIRSAJoWs4HyloVEmF5/l8lhdlxhyTspdQ0DRi8iP6jKtq+dY7v/HsRaKYQh+aBABAgGiaERtR6m3VzAiDCDKhcUocFQVCAlACQqIYlSD5+YAzNqSo4pCMkQiDCBMxUTRDtMwlUxMCwToOAQGAiRQgI5YokcwRopFDUtM6NOkSJwBMUWhgz2zM/QgK+mYkeXvjWiCKCFE18wyAnXRkkHnvyK2aVQoZ70UrquAIkTy4TjqkpDJdK71VnXMhhFRzqEGhpMlqhaAEyCCdEJP1UhYdjUbRtG1C31OsB1lFWYqI52I8Hk+n56PRpmM9n1dNV483L9SrUNXBuRLJo7GTYuWBM8AcY5llA8As7G/EO96VQz1g83vFYhI+OKheeW3H73V6bEyQo9M9BwFiW4NXUM7qURaCIWNFxbI72Jrc2h3StCv2b3YH91QaQ8dITtGYxkGqH//Fxvf/xbyZHh4do7q/+uH/2xf/fP/ajWpWMxWhafy4rB98Wjw9gbyE2AAVqopCnhmZLJBx07I5HuRUIg2GGlb377gnR+E37zai8erN7MLlwfNXsouX/Q0P/gtjEKk9TrumPrPpI5mfc6ftuCzBZ5c+99sHTwDg8VZY+kfXw4k6ERc2b9zafONGw4FHHDaUcw55LKopFlx/+OHw8R15edtMCDFqg5ppi6YQgSLBMvelaa5b2lXQOWGqkQSEoKQiF/Ir4Hm9O6bjuDKKTrVwQagxUdNgBKQhNo0yk2owDQjRenyGGqCaWG/zcdCDk02jOmaRvv+LEiGpDp8BZQEVCQAlmc8VI5hZRERjTjf7Wv3UD42xD43rCane51EjAYhID680c85BKigVHDtLuUmg6DwQaDRK4yJz2C+DMPWWCsBglMSSEgkpweCeUeEMgLNMY4/WInAKBpj8P0SOPPuomoCVMaYYGHDOxxhTzCIgZI5TGNTzN27kZXnv7p2PP/pAu27v8pWMuYsCSICYec6IASxITJC/XiVFCOZcmjyQ6/E7AOQIkNSM1CJixs7ITC0r8whGBgl3RQkI4Ny6fXeoCkCpIOnlcIl/3VfxKegMEq4LTLVjFYEMeUSDBligoHZ7sL2h7nZYxk65y6LTe++8B5lnlxEyOdc0zdnd2fZ49/2f/pqb7NLF57ZhL9RPvWfm7mSD/82nn96VxgGqth5908x9MRyN8tBJpMYpatrCEfuCzVZEQZU8q8QWkATCww/ev3Dri81kCBBdc+xo0sT5C8+/+NZv78yqw9n57nhzsrlYivfMrm2WGM2cU+mIfW9PVWPypsCjUVjVuqrzS7vF7iUQ5eSTyCiaU+6CEkFmBTIAAPBLJZWT5Z3b3IT6R++89bnn967vb6v4KjTeu5tX96dPpwenx02MYd417dx7tzECnwmYAlmERiTmGe5v6j3Ns+ODvDtBgNV452R7i5qKfekpoiMnDVhTbm68/MpXuthoFKbSqycogsNScyLtiNm8oag6pjJz82gVAAMAgSCEDlpQDVEcYxREIItJl0uGEkXyghyPDh7OB3mZ0g9CB7Fdbm6Uk+39k+kZZT4E8X7wzW98893bd1ChkcBGJgoMYNjnIiCDAnO+rJu5rQDBY5ZGTBKVmNgRAieKlQIQkkMVNSLUtHoRBUfckwZA0CglSSARQkakouSoA1OQNLZy1GeUO0eaTI2oPR4vuTTUkHpyVsbkOevazoDAorlkxiUw9bnvuk5RzcyiEVFKRCBDMTUAUiNGSSM2UQRKLxKHBArOoSIBUQgtITqiqAZIQSKnrhbQTAUBmVSNkMwM2SWABliyaScqIIFLRZX2rA1CcqwaVS1zJADSdV3ogNCjE+wX1DHqoPDeFdWyevLkBJGn0zNVJCq8Y7QMBBx5xAKV1ViHvhiQ5qIeqOxar9lQtgZ1OdhsBhEzmIO80xjc8G/NToslw+WsjW3uHOxH1yg2RBsZ1SZjisFTmHWFZ+cC0nR8YburJJwJej/Z6+ZzJQHVTnVQjMLxrP35/5de/cbh/YecjTyFd3/+Q8/lxu52rGrPPppWv/irXZfVMZSaA7kAjQAxe2XurMmMRVvUgpQ6O+bBOH/jy/dGI6ltl4fl9BG9//PFL3/uBiMpME62y/0XaPtStr1Z7OzC1SucqdUrmbYhhieL1dRVAPB0ty5h1F3ZcyfHS/bFxlazmMIokxAoeMkjW3RoJcMsnBeTjfrBnfLabtRGAfMi19Bi5jCyaRI+Fx0JEEkxFvJGg86NwEZCeUcMmtVQlwEBEESggRjBgKAzVLNIaISYamhFMIWIFskpOLAYU9ingYp2jC6xDOBv/EgyRgWIqs6lIEIAAHZsIqSqjiANTYiT+jBlcZoBcg+QwYwgmgMEAkeuW3t1NCqnVXRKCAUlRxBVzUgVwDw77/OmacAUASjL0hWeqNdpzMtpvQRghrpeEhMgoUsihlT+AhqzpUBxRWByKnL5ytXj46dgyhlCTOg8RFJH/T2XUbauZdOMHaOaGly5ctURfXLnzp1PP2lCc+XadSansQPnRLEoPHTBMRGRigJBNsjMDMFSYmmPc8d+5EAAjC6yZoCUblHG9IvT3U+YZm2UxFVJtSXgCCGicnIFExBA7BMonCkCOXSkahbBDBShjpDBUNRuUTmiUDt3Fpe3mzDIxpmpqBRQrFqXeSyGWbVcKUTibHH3ZOu1C1ks3vrhz5HArPn866/feOnl4yf3h6TvNDWXBYaVYJCUPqmhsw7AUCkFqjsE0booR/XilKSW/x9X//5k2XXdd4Lftfba+5z7yJuPysp6oFAoFEAABEGQoiiKoiialmVZlt3yo3tmuifGHv8wPTF/wPwpE+GZXzwRPdMdPW7HtEMt2zRFqyValiWKoviEQBAoFgqFemRlZd28eR/n7rP2WvPDPlmkphCBQKCybt6bdc7Z6/H9fr5qklLWjKIs7f3549dFN+jDODSYFN1uzhfU+N509mhxhrWu9g7LdO3dMueNUwiBOApCMuRgUKcUg5VsATx/KhLwxifaV17nprVhEksgAyG4EKEQkTkVM1UwRjeuTo4OJet8p23vfHjv+OTJyy9evrS/l/tMfXdwMJ7uHNy7//h82VVV8GjUSYymGottAxOTWZFJutTDnmbHVhG3BzcY61ZEbdsVt+748MbNG7dePNy/tFkvhNogCSEppimIuCiI0ASNRgUhUBGSCEy1LxzZfPupT775wZ33FvPHu7M9Zl0uz5gj0NdIH1hxRjNu793/mJ3GbdtbIXPAGsju4dG6W3KVIWiZjMavfemL6z6HRrIVQwGJO6DWq4pINROTE4BGGmJs+2zuHHi73V462GdguTwnGTjGILvQDQ5yDXeXNvnghWUHAlVrESewm/VW4F7xrRVAXdWZdR9UtDAPo6iq7nD3wIEAllBKYcK260VCO0rdpuNQKysGWdU+UAVSgoi4ajutHm30/LlWLRSDzxeEEMXq0qmoAbE4hVAIqIqbeg3BLnRYdQMUquDCzYpb4AAfgNLVlW/u5p4kAjTMEyt8g5hgbh4Cd10nIbAEVeMUq+MsBDFDTIFQgxAFoCDRLXBoHcFgwi1zayRG6KUvVHYOdlTKNnSyKz6LvKeNaZlSDCWQLvv1NOneeJ26TCwFrpt+h7WfWh5NViTNsvz4oTyZTWO3kJwLzjXtPlrs39h++OysixF5s9BkHFqIcd+WruxND8/f/fG1o2u//Y//29//vX/5v/lv/uk3//g/Lp4tZodX20laBX/ynX8zPn1qEW1pOoDNG5EG7Uo7qAjIC7FTm4qFwC+9cXcyfu/+cb5/Z7lYQuLe/tH09pW3r15LX/t6swSO/8re/1ZvpQNsPKO0Q9nXauW1NzeHt8bp8NbkKoDzH783ux2f/sLV0e8/OLh6W3YmWlYjSZrMyDrhlHgawvrk/vT8STObtoe7fa9W8gjUJDrvMpmTkzKrERuyw503uu2l2fahiHekytJDM2P+WG/uhPOsvVFQUFf/QIRZ6ZU9EFWkRjHLZj2zufVDjBsK4HALIUgMXpiFCVzcihuHin0Ah1DMS7FhsgUnJpZACI76/6tXjivwVaLUVGEqDrg5JIT6agQQR4NRRbQSEYe60h1KWBluSTNvm2Y8mWy33Xg87fsMQCSKBKCCKQf9lF+km1T8HRNfcOLIQiAf5C0Y6PWwoSPn1XIVRYhQjQAVyMUcq/Qp8sCwqPdscSNitmJmWfXajRsxpffe+/H9u3e3XXfj5u1mMtZeo4SuW1MIjUQAlORirk9MsGIpJvqZlmzQZxJRhWoEErqAHYFAg/osXEzPng8VqKYRRpPatrDDwEHF2GqsIzi6k8ELeQFni7YuyjKy9s/zximhZ5h+Me1wxp9yMUA5R05d11vu6qMQUSz3+dlJimZJA1Pf5eX8wUu3f/Xl25f/8A/+jbGYJlUVRE4oKK4ds5BEq2IY0lyKg8bT9OzkoSHPprPl+QL9ljmA08nZ/IM7765zf++nZydPni66pZArmTSzyM3jJ6cPl8vQ6W2ZLqcii3MJjebOcicSHUVYTXsAnEtJk/bNT40+8YqMxqVoVQ9UaR4GCR/F4r2pEUhYS5EQMG7l9tXpxw/mltrTfrv+6enRyezF69dGI9F8ysw3b+x//GCV1Rebs6OdxNgaigeiIeSuALq7l9b3MnxbZger3ZltszK4BaCRR01sYmzXmZs4S3GqHkKYRE1d0TaMuVFuUaggWODkIE6tryR0owDJGr/3vQ+uXT/sNKckQCFbMXunOUWpUkkzywamwMO96MQE5UnbjsfjJ6fHq3XXpJaAYvbOO++8/QufzblrWFg4ZyVmL6VNTVYFU41ooAHZU3tHhUttcF977bV333mnU4UICMKh1MRAJi0GwIvVOXNgAZOX0ucegEQhYitm5AzmUqqWX9kcqAnb7ia1c3YTcK4xn6AwmHyo7quYqNdei9aNeAjDOpwJxRXV4F/FoVbxTDbIroYT+CIwYfi6encS4OQcCEXARAkoaiwEQjEQU6BhZ+wDnICoclZtcDOz06Ctxs/x3wfIwKBQg5mIlDpXF5EQOAgF7t2YmZlhHFNcLTeT6cwMZuQIRCnG8XqVu24rMlKFbnM7asLYaUqjvdEaKxOfHk110usEcUY7rW6szHQlWI1HvVg38m2hfpZoU/rO9QUuS/jWd6424+/JlZPReFK0K2xb9BZB+dH168vzd4KvwYHJkxOgCkTlsvVuqTu89/ibf7r7m3/vv/yn/9f1uvutv/+P/uPXf+/b3/rGb//O/250+cqTdccQ86YnNE0AQp+JqDRxQk7WbePlq4+vX/3Jw4/54PCjZ+d+fP+zn3p9vti8+6PvAfnk8U9feeVK+90/YWyRSE0g1GCGvo/r7XbT5Zdekzc/T2ncdqxdTqMdALu5XT98IrcvnVyfXX/hZeLCbbP1QgzisDdu1j/5waYBn96Vh+9PXv7Vbpy2eT0mQWINoiQIqQcDnBkBQT0TWOKsQ9pyazzuMIWMnWddHnebcR4tLbvkAHXz4GroMjKxs6ub93CDq5oSw1BQClNxKACqQiSjbrsVZtdayFUGLWOQD3q4mJqiSq6Y6nTX3GuaUrWhGtw9oDgzilrbNLX6DGCrrtQqGveKSqWBzg5U3GolqDORajErDiwWi7p8aZpGVauNCsDFkV81RlXzSBWNWRFRz2+uv3baOYYDmODGxbRpG6ZantalthM8iJgbUwBVfxS5eSBo0fqptVCvenB4+GZK77/37sNHD3qzF2/d3pnOuBiYLwbDCIFDEIeBWJir/wuoxLpaN4CYQLXEHxRWldsz2LZqBY6Lm3g4fwlS5+9s7ObgAiawgC2Zm7sQYEYVCFfMJLspNW2LdveK+lvcftiXI9nZWP8d1iY0XqQvCJ6bJG5MIQRVN4ZDV95O95aLtTFc2p9+/Oxbf/IdIH/3uz8WbqmoSEJRkDhlh3IT1LvcdQk1TBrm1rSmecmiy+WJEyz0bRPUt53hWz/4PqDmFtpJM94hI2IOSBzLdqUxjLcHh7x3Nd6/Cw1baLhxI0K2J49ZtwgkVDKUd9p089boU68jtdZnv1A61J8bXdjHi9WLFXAPIXCKqkXefuvmJ1+/+uOf3P/4eGHSPJovzpbnV67uXzvYd+4067Vrk7v3H5vZzjRB3aneQwpWNqhmHsVwadIefeoML6qqc+cci1m0tEWUNgntAO6a83qV0r6K8V7am+3xNCkyxFNDcHYTAEF4mmcnj5YxRXKNmKxWajZ+ejqXUByxbdP1wxt3776XYgIyMbUcVLWQOSEQGORRzrv1/ON5MxrVTZMDWfv5fC6BS9bp3oxbOV6epNS6+eH+wYOHj6jeRYMp3upyKIVYVFOKy+X5D3/0w7oUwfMNipVaqA5Gw+rDczI3MxTV2y/dUtV79+9pS9HB4GAwJmVrjATkRkSkfc8iFHjbbyWEDC82kKrUigM51zJczI0Kxdi6W6+5adgLAomRqZchhAhkgFtx+HPBZX2D7j6kRFzkO2ruqZblNa3JrTgyLLUpBek2XWAmYVMjZmEGQ0T6XgeF5HPNM0AcHG4EY5ZKoq8BFFQH3XBiRZ1tYBhzOZjRMhdHYAYH7fvK2eEQVWtrLW4UYxOCaB/G4+mlg+uny3lp1VvQCKlNcTflNpdJwQG1h/FGfoQlZtwlO2+tb0oXad56wJamPa/s/JKVgwTn1cf52mq9PEzd+d44EOvTjKOxHOvZfjq5cv2Fxx8+420kyURiEHds2Jn5pRtrk/To3tM//g8Hv74vh0e/+y//xfHxXaD/+r//1//wH/6Tl/7mf3188PXuT/54h9uSLgV1o4WUCQVSzb5/efv2L/zZ976/fnr8mUtHv7J3sJl98vHDu+/9+D0TamdXv/rlt67/6Hv50SnaqEXFI3elt3WY7T177Va++UY3mlG39q5jG8uozU/PADQTHH9mmtv+6POvTOK0Ey9ikhiMME6bxVN/dmKUJxGTGy/jxWv56SNi7okji3u72c4hqRTuiKVQD46cYsCzLBmzjUwzZM3tmuIGaazlzQPo8szXHLeBmZfrpXRgE+sdhd0UsKJboA8SimWqYr0QSp9rBEglr1aYg5mb60BXAvvPwsqqXbjynKt7LlDNiA8h1EMjkJZCxlXmq9xLEi0aWAJL6XMQGZDm7ubOHGpyyQWAsqJYmQEJzEkAELiUIemobVsAgS8GzRfo9eHJ6oM4ETU4/OLM5Z87gCv0HQCIJAS7iG0SYcAlxsDSax5ep86HmWsUipbSpJSzqmo93ovZdGf22iffunfnvUcPH3Rdd/v2a4eXDsyMzEMciBnEqHCMgbrFIIcPvkiqxqd64F58pkEUAoQB7F5NjARHAJwuEB/sbmJsTBacGebZC3sEBMzOyQAHq1l2FTBUdAXddEcN/2mnv9YevN8tf2KhGe+VbXHqPZqxKCyKuBqPqZQC4vny7PDFF4BU5QOc+Aff/eGmW6Q0UjBUwb1EKW5wBiNvO0XGsBRQNZtOp0U32/U8paR5wxJrcI1QHxiBxyGYVU0MWrCQGrvkAHGxhc0P2slnP3O+6drA8vLVcPlI4qRZnbFlaNbVIo0kzXYsMEjQZwsBZfCLD+k+F1F6hS8soDUcWi2A5cfvfGe2c/gLb9761Gv9u+9/+ODpsgPde7RZLufXD2d7swj4jav7x08eNdypkou5O6gIwYMJBzPdfenG+t5Hz86e0f7+pLTZR0khkwNxDfc+omffCedLdXNv+5BCY7HdX77ycvrE9fbVV+Vo19Yr3lovOZIhTFod45yzZ5qybXSxVEds5YCCKi0MoVsPKUBgtqLmAgjB3HIBSMiBOE4NkjBv82DMZ+ZGmur2O5vPNXiSaFYYuPfTuyElN7AwCG5eFc5mBlUCXI2DdEWZmSFspKbEw0C3ig4GZkUIpSZmB9Lett22154poBhVgiyTg50qRZJL1S6IEHOvGaACa1JiveDwVEUKc5Dg1bvP3Gtv5iGKllJZ8FxrB2ZzB5woeKVJBzb3C7MeUUVNDRw61CN5mE9XXiQzuSeO2qubsXAVk1Q2Ci7MG/X2JKIQ2Kx+++FB417tkQgh1CVWZVISOEZR1zoPZGaA64SQQG1Kqr2qEzEHcSNiZ6LJZG+7VS01ZzKaUpvGB0cHK16voXFHSiztpTbtp963zWHUHWvDs6vtCgsn70ayGut27OsRrZq46dys+ITpitBB2NzRaw+enR+xrmUmy/liclh658U5H05UcOfohaPlfZ62nrtoEd73hVJUW+Z05fr0M597+N/9i6N1fvb1/++N//qfXrvx2vGDexyar/6Nv7NNTTrfvvjl3z7euz3/g39zsHhGvBsx8xRL96z50lf/gtNPvvlNy+u3PveVz4+nD7rFN7/7J96t02z2+TfePFg8G//Jn+lm6WmKbUYTxcpaePrFX5/ffHV5vkHuabkoHJgTc0JKerYEEO7dkS99Yu7a3Rxtzp3dpBWIEgvD+uVy/61XJpbT8vHs4FbWrnCQNuWzdbs3UcPWOEKWhm1JykFK7NmRy5rHLnHDaYux6qQLzVnX3ECen29m2yhZbZV1G8ZplhdrzSolJUjG1tEzk7v5IGM0JmeG8UUbC6u4m3rc1rkrEXFA1kLCQqEGIkgIzAQaMEu14A1ciajVLcfONQ/NRYLDhISJmZmpqS1dXRLVHYwRS+KqjoYZD4ciRAZXPBMzk5u3bauq5sbhwiaMCrfC4F8iZmZDqdrl581vpck+/yO1u2eCG0vAAMOq7K2qyhweU/J85utmFDgxq2o1+3qNTi1eXPcms/a1TzGFR48+fu8nP+z629ev3Qgc+qKJYqhlbAi1/KUBJFkno3xRGVdpdwCAAVcy3ORDesxFFVEZ20MNwaFmzEQjo5iZyagFFyJCMASYoGrBXahAQ7tg6andCS2rEOHjAmrHX+BwXNYP9kPLjQbqexU2tRwSB4muxc3AlBv1MUIQ3chXLh28MT341w/eP+7WomsSlD4omwSAk0EBieYgLyDmaMVSmhYNwmNAApubJZFVp5JCoCYE8dIRRcCttOTB2c04QGTcLBfLH79/9xc//2uXf/U3bbuR/R1zFVc5uGrYEjjZFkzqvfSaVJVhhiGiYrBiDs0JmMRgDpFAEAe0KDPJ0wf3H4UHT+ePLu3uvfna1Rc33d2PHj05XZ6v7c79ZzevX7160ETaXD3aMVqGIJHYYYkJ1m/JCMTuxjHdvHnlaTmdW6EYgm5pgp/8eHb6wRhJQ6uzW5NrL6edkTEY8255TGffX3/3O+370/i5z7Wf+6LIqCwX7MHZsANri4NtC3LmwN6ZK5dSEEbL1flysU6pBZt5TmG07TccmAwcBFz54W7mgQMMkbkmBnAINeKAAhNzkDqvtWImbSrVrGMOK4QBYY6admsQDlY5knAza1ioohmdilbYzWCPqwnEVYXRxvT09KmqSoxsBmKDMXMAAqCosd2AKQBo9a0zmZdOjUFMF0YrMHHpFQAHKaqDZMIDE5n1TYpZHUNi71Dr1jJYYtRSzLQOn9wc1UpUp8huYC7mTKRuzGyBuBjUE4sBRpZiYqe+bIbxVaVWOYg8hFBtCHZR6lW7RS3Aw5CA5iCAKRBVWqcTQpD6EGIQS+j7Hn0GwBzcSEQqJh4UzMBBUkhW2Dxxm3r19+++H6YSx5FHjAk0qbLKbuQ93mnXe766IavMp2uVGZ6OsZlw19pCuLgRUlh1mp5spi9MH5yuroenE203uU8yknx/Mbv+zEFPnjYH+w/06mJ1bX9z76wHrLQOy8G6AAPfur5cLM9Yd3YP22ePHvyr/8/n/w//7QZ0dSoy3flf/vt/fjA9evMXv/zqW5+d3/jEgz/8/fF77+4AAbE0R/n7d37h6uEnfukLz3J8+PTet7a03C4jh46nt2/evrFVe/fHOZJ4EkO4/kJ+eG+ZKL/9WXnp9vLxQ/EE2oGUkbEiqfPY09KWAMZny6sP+/NPT055cTpZH4z2ObgmtAxjO7h2edoUXs/B2aRdLo+LQJRzaGPa6SAdGuboZBuJ0cLWezJRKOIOaLTRSZdG2qQ1T3jtb9++ZKc9Nmc5u+XAKzLtAiSokFpebZ2K+2D8Nc9khdhqS8cX1lsHAg3plhU8BQy8tiChGv/Jq7Kpdmp1ml5VVxx4ON8Ch1CnL4AXq1tYJg7gYiZxIGMMib9ONY8EVigENjaYBKmBobjgR9bZy/M3IyRDFzn0ifVMrU4bZ+bgF7Punx25dZs62Azd7CJrbEjQdqrkRrZitQ6vc6oLzQb5gJTy6v0zc7hZsSHq2LU4vfbmZ1KK9+59cPeD9/Mmv3zrdmyTE9emkM2dqgIyqBmYqji4vjx5lVbRhU8i0EVTfNHD/8yB+PxTGTFz5KKLsul8WZuU4OKBATHzYsFdQAyXrRt6C2hGiNnipfHOvq6exH4R/CmXc4TDqzOFrnIpOQsHcdaaT2popE1tiynCbuCCty/N3kizsj75u+Ojf8ebZ82IXAXerx/nbs62dqq27gSqIgEBNLa7kcZWRCQZGQFZy2h2ULpNiJFErHC3KSFEUIIxS4D6KKbc6TjtrtfLd374o9/+7b9/vIypRHf0ZkFgCEBPxlzxQYLO2VCkqBMbXVRcg9OEwEMsNSoUnyEpmZu8/NrNbLjz/g8/+nDx4Pj2dHr46VdfOzmd3/n4waYvH9y/m7u9q4czom2npt4FZWUTJyOFBQAcWLfZIvYuNR3l8/UoSaKPH98cb8vs1Tkdja59Kh59Qo7GccRhYmjzdJTy6kE+vnN+58/Dh9/cLN47+tJvxxsvlvmGpUgQ3olF3YJKJFs5EG2thBZOKRW4mC1NM3NryMTJoTFUzLBRJDcXlpqLkKJse61g52FHQgxiLSqOING4lHpKENUoslBdv+4hirubFzMwh9xnDsKMvnLe8dzzbjWLyM1ijKWYWqnhucTMIoPTDkg2aEmqrpAMtRQetW3O25qM6PAQqBowOAqIcs4gXBjeCWGAY9SBcpTYay8sdfJcy9dSioPCgMuukUkXlsdKocIF7dnNh5PVQSTFDGSRtcKlHd1mMyQ60M+aYFxkp/OFBhUgqb7n+tku3PnCVN0LAMyUwTGleiFWJ6KWMhqN9ma78/l82xUQuVtMo5TablNKUfOYUlQKbdwRmZzO17FlJFgyaintJ+xCLgvtEbXnh7I+yGdHMsd08eDUDspignXA1lb9eAtlmGVG6R70H4b2UD7u8rOk+ye8usQ7qlPLD2znxrKE8uRJmr7w/Zde++rDB+yRunWHhrsOgTL44Pqs34zf+Gf/J7Sj4//hfz649/5H/+M//9xv/Jej20f/8eu/u93mZVy89+63Hzx69IVf/sorv/m/X37moyff/nb705+MValf4F43vWe70/ELX/rSv/rGH4xhZs3e/rTZv6J90ThtHWmveXSwe6LdjVc+Q59+fUuNPTkZteOAYECfyVIwJYZkVzx7BoCFx3dO6NNpK3p3ena9m60JwqFPsEZTUTfSkwdToRIsu7kJmbtxwQzdWhE75Q14a0kpMDcgKGlnyaL0MlIbZWslR1/n9+6umiVeDIK+cKGglNfoNzrS6IUd6ijmloThQQsHIbdtFW0QXyhUyM2tyu3gF9zWcuHud3JY4IEHUXtQJkp18HNhzyMK9XAtXlBl0qUgMLkHluEwYXv+9RjibYeDkZjZ62/WsfigcqjhIlZKVScMw/CfHa7P9zqoF/uF+BpDyiYuNBG1s3Q4sw8LoqrJqPvZ2lk617kU8VAmE+rtXOCuBcRqGQARRQm9qrl1BifOfb55+9WY0t2f/vT+vQ9L7l954/U2NQBpr5KEaVjkDjveeu9TGN7hUEcE/MysWBlA1WxFPOS3DL/lgLho0flmcX/5cGPbyFIQzAIjEII5MyXihhBBogVjmRUvQXbyWL9HuWtMg+1BbkpZpHJ3eQJmZuNp69YZO3s0MlWLLZa6PGhHmNDU0y/utEvY00u3NvvXr8phkHFQT9RvNsvzB3dkfaLLR5v5A+o7rmGPxPBQEMejXVDKPR9eOlLV+emzgBQIZrASqKQ2JVNWSk7Uyogin6/WAQ2Tc4wPH63VWuGQBZKjc2vYAlLFsoXU4GxFqnpW1FSZqJIT66Vby0cjRqC6k0eFOKrJlZduNW5XDvYeHj/6+N5PLK///C9O3n77jTdfvnrv8ePjZ9vHp/NLBzuMnjV7YCUz985J3IO5ilnfMUfuqYgdHUw925k2s/MTk/Lw5hdpdmt6sMfjdWdrpsZhlMhGGl+8OvnCjV36/NkH39v+8D8++Pa/OPz8320/80t5kWUKOkXZFNtS6cCRfW0emFZknRt6lgJOBAM0O6cgVop6Gbx3qiGGQKFaVK1WdPWIFeEhGZdEJBTyYiBnZjcvpXLpqJJhKITaULIEApsWATEw4NRRzXBGqEYGIoYbrNSbh+sR1RflUMdiUpGrpTJxDG0Q603ZCOhzfm5jMCYzBLAb1Pq6cxZm8youLtV8IUQgq7RXAhezIML1YOYhNNncrM9VoxKYHTbMkAmBuFI8zSxcpJiS47lSg+GB4AS4UwhehhPXh4PYCWRkqlrhQYEhKXbdhpmdPHAI4AGsw1InDcxhb293nbfWo573s/Ekl3J4sP98TRAkEUnfK3NJKWlhptAXcw9qTh5kFOM0elswg02dp4wZeMa8hwPbXsXyUtsdNZvu0bxHt+sdr7WcdXIW++w9WEAsvpQ0uttPpt7OnrWiKS+foLPQh8Sa76/3rltP+uDO8dEL78nLb8zvnrRIalbLBytP//TfHnzmby9+8rD/0bdlmTefeC395IOT3/sf0me/8sVf+03P/WL+5Mbh7e/+6Nt37tz5r37n/9xcfuWNf/L6/FG/+MG38vvfb0+eJrfx7bf++K/uiuYOzdGtV796+43Nn/5xWM/BY9lt/nhvdsX9UzdvbF66vVzPJ31n45FrMAiIwzhoJmYyExOEfgtAUrLj48ubw4c77RM5XY6vpRCVgzAilBJseRYXj9Kn3lyv5haiuHfcQ7Bcd13pehMF55C2FIOXArPCcN765HwbEds1RshiS5oY7t/Tty410quuyJCKdTEj9iGrc2fuvbm6ZXODlyDkMKDiqGrJR/XxVPNp4S5BULOGAAB9GYRCdQsbIl9A5YgDU6kTncqtgMPNwG5gDkTOQeHErGYQRrUqXJydzMSQWnGaGYYHZNVIDOIvLyYibiaxShycmXlYrVwwrIbszRr9N0ytUWNXiKziGGujWduf6q+oySpuPpDeXbUQqBTVIeHTaq+uZsRUX1dVQaTW1wUxM8OpGIQK3NzkxkuvxTS+88GP7z/6cFvKq6+8enCwr1pgThe5g0zPFc3hec9Lwwe+aHkvDlpgGEvAL1bfxJVJoqqP1ifH26fq20ZiQfCMlFJ1F7sxKBKF6nLiwLCWSc7b3EKWst0PeLNNLrjnfkyOsYzZqU2r0klMZChmAcyErWcJbKnwhN986bWP927fSQcZ47UZMqetFSuKVqaYvfpWZKwefcgPfszLR9164WZsJYUgaXJ6ck48IuDZ2dLNU2wXi3XgQBIYJH0yHmdqpCGLyMwinkZtD4MhqjxZzh+fLPeOrm+XPagPVBwTtq3Qlss2CzOJlTWzspm6cGCQVYdnFarCAHcqSknUTQxs5sU4BPna73/rxZs3bl8/evXWp2699OYHH7z7k/fe+dG7cvvqay+9eJPL8fHp48fz5eGlkEubrDMwhuxZGBUvTghgglCjUYWu3dhpTsYGnqeXbHyzbUTTNjQks2R7VPaaMEWYaRlvNxNNu2HvrV+xv/32yR997cH7XzvcO9/7wt/Sp+5PGStt11E7j0tWIRHk0l29fGTbvePjeymRAWZdJeUyg6HMAHogEIhcHVyKo056neFoid04gOtSzJkCsRPX29BIhYOVYkAVYqDviyNJq6pg8xCKMzHYixP11XJHzCFU3RsLC2LWvq6GiCpixGlA3AEwImfi4kWiGGnN+eoHFC2Y4WrEXGjQaDJAHEKK0GKmIlJ0GOCZ+bgdqfbFjBEIVB1wZkYchk6bBKaQYERUjIislvdel1T1YHZmqswfgCtbB6Dixk6BmIoZBcCLlxrpDYADjZrRcrWuIxY3bLutQAigYSddVdZMcDPszmZHl49Ywr1798yMgwiH9XYL4OHxCQ2mDg7Co3Y8ny9Ui0gNdaJAUQtrNtMsbRjttH3MpTWZMM/YdopNfIrlYVxNsdwpy6vNOY9Olg8yVo6V+4pt04ftVJCZPHGD4N66rxWdtXuPp7bXs/XkndNMDtdl2c3GygdYPPzujesH7frS9v751nmNsloJtbZ48PQP/l/jNYrZ6Nd+a/KFX37wz/+fh/fv2rf+4NmD93/1q79x/+TR3bsPD/bfuvXalXv3v/+d77/z8u3br7715Zf+zq/2f/tX1z89OfnL/7h8ur4dJvu3Pvlkvf3MzTfyH/z+RBrCuM9n59Mb0+OTlz7z2bOXXtwuHo9k7I0KyMJFnaZecYwELZ31yyUAhrWj2StPrjyePlwlvl9O31hf15grOX8bxpbPRldvcZge61aYxhS23hk2cXy0PD1dwwTNRn1RmDkZk5qDLWO6ljGvXTsLpvrMX5yNFyV3x7lvGWumrL6Olotn9m5LroQeyMwGV2YD3GHMwVHcvTJQuSZpBjHtUZPHUK28Nsx366YDbHBVZRFmFCvrrqueNybiQcsMZirEKG7Q4aSvfEoAF6zE2oz6BQWyBokMy1p4eH5EEygweS0cBwdBFSzVJVT1IPGF+JJ/NrPF8zkRD2tUqzeADYHcQ5QvjBjsBisFblqq5Kx4hQg5VAtzcC2gKqhEKYWJ1bSopSgiknMPMMekqtp3169fTzG895MfP310X7fLN9586+DwyMyoMq6rVtydKKBSMsyY4B7cjDh4sWHGRsSAUzAneAGcSWDujkKkRg/Wj07XpwaVkAzizhIFzkCCIZIASU2YI9AwCALZb9Macc9vKI2TnEvJ0t3n2EaOVKyh116//Vfvv08J3iO4q2jSZGJF+47Lla/+xvryp/5qfu6dce7EiEAWvRYlksGqG2i22By+0e9db589Kqcn5l3pctvun8wfUgmIAgsi0cp2Ot3tNuvIEjgps01ClOJTjq0QWfFSrKipkMQQ+4Ud4/61qy+sTpG2bd8X6sEUiotxYMuOTDwx7oEMy6DANcJh2AnyRaxf8V6JyaiSySDFxEw+uPvg/v2T60d7169f/cQbn7969NJfvfMX73/03tXt9Zs3Lq1LXiw2++Mktu5DCAPKdZikDGMWQCzkhNQ3LLx3ff/R+0fiIySW2GtMMk1xx2hWfEp8mMqMm5HZrlGTZ5snaYSrv/M37v1p3Hz363ms0y//HX6k2tK6JV4zkoGLk7BJx9myMo3d1wZBSEJg1ou7yYAwXMEV+gSY1o6UzG3bZ+I6/BQOVYfkDgPMg3hBX5SGzaVp3185Okokj548hdSUX0cxZlKUon7l6tH8bE5EMHIydy9amJlr/NkwZYUbQAUBlSAbQqjRK4OiYVBVEgBzrSj62vJqGcJeAlPR4labXTIrgYNZGY9G225bIRkXkQ9MAXh+dntNVKDqYqohq1TMyQNHh9ftT50XD3+XdCGRhD8HBFakX7VFmV1krhmtVqvnc7nawA5dS/25lmLm+/s7k8nk4wcfc+Aud3nZ17YDQM59CFzLuV41paaO8efzs8E8Z16dJkQcYypFOAREZM8I4JZ5zDximlK7YwfY7vj6AKurtN63OdT2SNZdtI3SgnnptjAOrABHAoqJYq9IJjOfzuZGtinIaDvOC+vQpC0p7Yy33frbVw+/uj5r+83ZGU+YMmeWNo2a8vS8fftLe1/5wkf/4/9iywf6W7/V/dX7zYfvnvy//7vDz3/u8POfbq6+enL85N/87v8DbJu4+3Dxg2/97kcv33rl8MYrt/+P/9vtk/P+7p3D48XrWbu//G7WtNUcRty8+kt++fLt2UfzM+eHj5v9HXAfkJihBUwh9wqOMLNSppOprjar5QoAjek8pJfzC7P505N2czfNX6XrWCeHQbhfbzdwPnhluTzbyLThtM69hHa5LGWeu7jXuTJLTrISc43ZKBCrw7eSex2Z7K7SctvRmcTUvzCNq8erktWXTArKgo6sc3Z1ZHDProAC6ihEhWHmxS3XK1XNJICZdZtZWEsBkESIeLA4BmZnew43JqrqfUlBta+WHhTjIMO9owqpC8uabFijEvxCn4GLze7PHZVemdBDf4efP0oHf3CV8A8Pu1p30l87butvXCyoMSiGn7/GxesPvMj6QgN3HShWSrEaKtNrj+chQgMcX+tBbkCxUu+auj7XUrzXASg7oEWKWbly7Vo7Gr37zg9Ons6/993vf+rtt164fr0oAHYrRMJU4bBuVtzrmWtWvYbVrFiMWJjh7uJBnbz+hRTimDpdPHj24HR9nJqWSUzryErISMDZ2QCQwANTNBNGMCkSbHk+10TRfG86UWyR7M12el/XqzEHUM/l3Xvv2DQUZGmb4iSl6ERFUVKcfvoXdm++cf/JUyQOVpUxRBFhS4ChZs36JPXbrDBIeuHVTtGfzps4LV0HtJJmoOxOcNbCAe1WoSSpCGgkl0InHY+ZG9/SGonHs8nu3mzvYP/+Bx91ZyuL/PH6wafbEqbUt/BMWLmVEelQvREJcTbUMY8ZbKjs6q7DKyUGRKyqQYSGoGVXzQKZ7s+Sqd07zseL+4c7J6+/dOMLX/zb3//+f1ZjOXnnxrS9fz7ru2KpNfKAAtiQNkLDDgYIhcGWrGHdhmh8cOPms7Ox8Do3Ijs9T6K14nscZsRToz0v43yJ11M934tb7tadtp/7ypt3u+Pt9/8nkvPx5Ze7ENpGVQChTJzAbDSfL1puQxi7d0BgSkDvDqJAXC56LjIrzGxw6wt5IRAnckIhGKPACMNkeljkiGjX706mbdM+OjkOQaLVwYKtbWPQyBEFmjWEWO3rIuHk5Gmltw8eVncYeq/R9OwEwAuqJpgFXFet9flSnYjFys8JKyt1B1QJtIYLSrTDyVTrza59LyLFCjNr6UNFEAwq0iGClIjNS6BhOl7Vn3AiJrdKlx8EAhXkU9dfVe8GFDisHudU36djQHMBQExxu91KqEM80GBvxBDFDBjXyaGzMDOt1uvVZh1T2t3ff/z4sam5e9u2fd8fHOzn3C8WZwCYQ1FzIOfCHJiFOPS9xpgY3HVdjEkk9m5BmCNbY/UAxghhJ+yGzcw3u7Y8wmaPViPt2qb1B+d62sQu+MJ4rmHLRs6O1FT6kHvWbeeNMKvt7c0zybqcjXgy5dk0HxtrNi3tpM/le3nyy/HJ/mi6YE+BlTsralPh4/dP/9Dkvb+89Jv/xeiVX1jnAz+8mh69l9/77vrOd+zq1aO3v/zP/i//7MGi3zs6+sbv/ovF6bOHZ+//snzpBz9YXXnp5uUXblx++5KUbf+VXyIOslgul9qP4vw/fWPapaUuD197CXDjLbuBLARzp0HWgACYQzerc8oFAIk0YUJh59bm+tPFe4uD80f56Q2+tuYcJFBYNZCtTRb9OjttorB4Yu4Wz+Z5nY+um6tsjENL27zZNkCxXHtsjhmhC1vjsGRbhw+X4VeuT7Q786XJNpVefV2CUrENk0IU3teHEbieYRU/TiVXTVDNEWQbghqKcCCg13rksMOsaAzJmOsQBeZeoK5D9JtXQWJgeC5axZJsGCJQ3N2GhIahwL5YfdZ8zeGEHQB0VIX6dSdycXr+/PPtwulQG9+fnd+owhGqL2nDEf9zB/BFkNLzA78qzpiKajFzRzFT7c1MtRSzIAyDWRGJ7mZmZqxWmAnVNOyIMQFQ7d0MhBjFDSIBhKJ2dHRlPB6/884Pj4+Pv/sX3+27/qVbNyst270ajg3E5sQUQFyH2z7kE5uDA8g8gFAIHKIZWKBMz9aLx8uP5/kphcaRvG7xvJRi6pF5BHIQmwsQ4MHA1qq1rjvZd0srQcf4tizalvaSM3dfmezcbe29fpPaae8bCy4pwIzNDElcvRnvvfGV5sYrp/NN2fXYs/dOmXhr3kHZIeBcY9U8k9l6BVD5iLvHC2w6253xGBvLMo6aPLWx32qI0rtGD+NmunVrx+5tGY1lm7Y6Cy+8dntydQ/sqr0kuXblZnE6/fDR+6cf6G4Oo5Y3yBvlxLQE+hbb4AiE3swNBhcmMvQXzhirVsxh8Qe/2AZXaiACizBkPrco7Sgx3I7nPj+/d/P6pc9+9jfuPHrwV8fr14+SdCJxqcyNkTOhZuT6kItT40KMm1ZSWWfIQdnk3Vu34wpPzfKErfEyLfES2RQ4ID3UPZ4f4vyTL2h5dor1fMyWTfJT2/3SJz4++fb5d/7V4S/9XZu+1I/HMm7yk9yy1RJQiuSiFNm3EkITOMMd5ExVR1C7XjYvpopKKq53Sr2WCVCwI1QV4mCXZnjoWTnGrt8SExEXgCQ8fXYaKMwmO5tu48TcihXzYgGGIESoASYMUlPAHWReqn9pkD4NUiNUhQVzICIfdE+44KnWW5gGVDyomF8YguAEWKmmherncbOKi3MrtVWA1WlkrcedCDyIoNGbc8X/DMMBApMQuSNwAPkQyUDEVNOjqC6uhvlBHXYTqumZQW6DOrR2wwYI2IUcYDMnMiMBVaPnoH0DYpRnz56hzhWJc86575fLpZnnnC8dXEopPT2dp9SYQbUQcykZHuFqRkADuKpRGxFhAZQYCWjAY5bWRr6cYrlD6ynP9+jcjnV/276Y4w9PetbiJ6EshNcIDCfnlthhHKz3CM6caQ/BeWd/Pg3TeTm/RA9Ka6KmNLZ+2bVt187+fHHlM+tnhwe2AFFIwcR8w5v55p1vyec+OfnSLzz4+rdaKXbrZjfJ+gDXf+OrJ/fvPvjOv5L3Ztd/4XNrpC//w79z94Pj69du3L/znbuPfvjTj//i13/9t07fvfNXP3znrTc/e7ZYL8/ntPWdH/3VG5/5tbund3ev7rI5OIxl3OUN3CpPEZDAoU3p/Dyv+tX22ZyQAJjJzuUr27y9WvbHklZtfy8c39DLbcfrvOZnp7NbNxfzczMacdP1W4kxB44r2ZX22TrYRgMlmDcrXy2pIc4ZRoHWKpq2XR+6PlHszza/9tbR6eO15C5AvIdlZcSaD39x/QQmB2K12BDAcHKHxGJq5lIdrqYgqpOfULUXVEdIqBva553r8/WlWl3OGGqC9YUvH1XlcHH4VVP7cxlznec8DyDC0P7W03L4n1ZpGvWLB88uD+T0iwO8lhIX32N4pTrYru+zehae19R/vVl2s+rJsiEt0U2tmLuZq/YFKNkYNc+01JwiJh80z3UARigXkEtmcUOFa4pIfQOqOp5O3377c++++869u3d/+IPvduv16298iupqaIgQNxCrWVENzLkvDKrzAwZAod7WkuJkNIos6609efbw47MPl7rhMI2UcGEjgVFiYUpqHiEF3JXqRuHYckmG5HkceMSrftVMUyvQZI9G4UT83WZzs41S+jxSB0JiblMw3lhOvXYmh5/9Srjy4rNulVnbUdGGRJm3hIYg4MTo3CLKug8xKHJO3Xg208UcvOAp96FIE7bIna7RAg1iEkMRowIvbFG9b5Vnknk9ubl/5Uuvr9end+69A2RupLMtF2pDM/v0y5inYzq+tH+jj9ZOxM4KgvjW3CNyPWsjoRAlQg7sbsW91Ej3ykmzodELMB9CM5lEgjhNZuOJWW8gOI8bMeQ7H2+W8zufePnmw7B8/wxtkxH2xHIfVWpnZwBpTZ0F4MZJA9hcRgwpoe1WJvshIKF12kHYQ7gUaN/tkl9Kyxfb9aW0Hp3Pp/n+lLsEtTatMbadvPvFtz/4vd/d9WNLs3W3mk9mjDFTQC5cOGeTqZga940XNSeWCBRQANzRuxvczYyLVzTHxWDo4t8MJwaz07AHrfdhCvJs/gxADIJhf8mtNA7uTZsUVd0cRq4M4wAzIqbAXopaQVViAEI0pDYNlHI4c6/KTlwTlYjdLUgoZsyE4kG4lIE75zVqcJilXdzsdX3EZABX7mNltg7q5vrJyJ+f5KA6sauc+lJqLjBbbRRqlgzgMCKuMpb6YzC3MDxbhmDE59/frcY64XkrPBz3QM2fqpqDavKoXEAC1ZAJA7Qvi7xIKYUQVIuIjCdRs3ZdV72bxNQ0SbX0WpiCFSWSGjNMHkqBqpkVTn3wYMjCQsJIoJZGlMfYjGkz4/WEO+lyXE76U7qW6J2zbchNtwAvbIFOhFmllGQmeTkfHxFMCe6JcluanfVYFnvpcKynxYTcc+hkkharZe4bnU2+P949Wh6/cJC3lrNBSgyUG0+ru3c++rf/086Nt/TpKn/07Smt9bOfOjEb/9qXp3/jC9uP3r/3p1+fvven7Us3f/HtL/d719fl0YvB3n7lrUf3P/rWX/znmy+8Nr4cl/3qU9PL3R/+4e1f+9vf+eH7e9PdeHQ1FxXhTrOZc0g5b6wU80KI25LNNHlY9+u6WFnnddOnpGWK8UvdwTvrR49GZ8/o/DIuFV2JTLen3dKeyXgSoxAjb9UiUkcYc7csjSIgsXb7hZ4se4WpkvROW6hphPhIF0v7xbdm3z8+2UmjwwOxpTGIk/jaHfCtELkXJR42p4CTOxOYUCxLiAQ37yuStBQDkwQys9rqhsDE5EbMbGrDBWZGBuFwMbux+soDzYKriIpKvard6QKpg8rrIKpQD3p+Zrq52VAo81CqwquPiapAbHAYGTBkFV/4SYbBzzCbGmxLPjxdfm7MTRen+zDDdqtv2CsRvVjptaj2NZO7mFNgBklgZtYL39Tzr8ZFCWGu8CoWRQjibnwhFK/oLje0bfv2228n4Q8+uPOTn/wkq/7Kl36lbWfr9Xq97rSaEs2SpPF4ouo5a5+zg2LbRkn1dE9pFGOTtX+8fPTw7MHGS0pjWGKRbMXVYZx41HJkBzgUGxkxEydp0Tgl98atNWk57EZILBPmKDJGTNg05SjSpWm820xiznkUmbfC2UpuaNxrnr31pfHrr+tmKUu2CGxDyYo+IAEKJKIlwIZcH5MupjoN8cola8/wRBGSxaIEcEay0eG41xyYUX2Yau4mU9GJmSz33n7h+ts379774VoXcjUhskcbS6NGmv345H2B37f7L9x+aflILRMFBIEvAXWHUG55kN+5ubEBrnVi4iCwVt17YLJKaBoqPrNCAjRdDqlJDLBLVg0xTaPMc/ejD4+vHd4Yoyy7xyHpRpuRU6GhRHPEC2McA0EB6yRxUGay5GNWKjv7UoKUVnWkOrLRYXxhkg/XD6bvfzM8+i6Wd8xOW1+SBx7HiYzj5Vs3f/Wr5e1rj7sPb2HykHdYwtOdkBEaC9oXUdGsMhask1iZ7czOVk+BYDXb3QmoERxcZ6KD9QaINPDsyKqhFzBQqRa44qbEMh6P3NyyhiBOjufkcniPizQiszZEc1dXsxooxKmR3G3rl9fg4kpgroU5wVgNEsw8StSiIdTzaWDggfhCTMLPVRqguklgrVm5Zj6g6RCkttQOOIuo1mjyevjWnEAiYi1qpQABTEkSg7p+CzMh1AQFM6PBYFCfG3VsR5XWYbgIWyUioLqEq4dxkIC5BwleTAniNTySGJUTTbH2373W+TwTiOXibVd9DYuElFLO+ezs7NmzZyKJWdpm1GuB1u0vtjkzOKXxdtu7x4TY9zmhqQkQHBhMgS3AE0pka4qGLUq/zZ1cTqN2u/WOOMuzhovsYdNJXq0WD0eyfvPWdevmdzfs66ILjeOGFI1sJc8nQbe9BUZvO5YpxdQRlrpCOri/99Zj7T6pd1N3Km1reRRivjYbr+68u7pzTFcPbbdZHBwevHGj257mJ+/a4aGOn+1dTmOSxfzO5g/f49ml66++/uY/+A2k/fGt2Zu/9avjhZ1+/KRdjfKf/Kerr97+9kfvTKc4ePMLj+bvtu2EMjIjxqaUrRkkxrzti/dmAYAFoMuSCwBN4DgiJ7XuZrn2/vJRN7a7OLlSdre6adrd03s/pWsHebPlzs17T8nXnW+K9ZEZvvW15pZ85hyWFplKBoJ7AgmKcYiSGl4H3bk02mutn+fpwVRXXlbDxIQ5+IqCkPt2OKi4UoEI7iTCMOZYQObZaKCimkP4Z4egWbkAJw+VMGqsnGk92pgwZBTUO64OVS+KVq8ed8BAUnlIwypniEkb1H4EWHH7a0vdobccvnVldhDq6YthXjaMmYfhNIgIQyEPuhh4/8wzC3reBjv8ot2FailFrRTToqVUa5a5ichAIwENIx8ftF5wdjeqYzY4zJjE3UVC5WwwQftcd0OqmRm/+PkvHBxe/fa3/+wn7/+47+0rX/kb0+lOzn23ynA3K7uzg+l018wrZgskbdsyixUHQmA57/Kd43vH5x8jFtKkGW2DbBzAszSNnIyDqWmfrXjHHblwGFvrMgkWwaMYRp52wvTyeOFn2OHSGO3A0PNOetzkl1NIusSeTnMeeedAkODbY7v6yauv3Mjl48ycZ6IjUW91o7YhdI41wF7YKSJsAYEyqXDKk3B5rNblCSdTRDGGxhJauXRw6cnxo6zb50P4qNBUuC07nzw6/MUX3vnBn8cD7Oy2UpY7UlrfpGAq4znnOJ2ed/qdB9/59Bc/2xwKNm5CSoWrkYwIJq7iECADDGeiWEfQPhhk6mOWgZ+Z4IkCQKLUtpyM2BjCIhgXNWUWGa/6zcnJemcSJ6O9rCq0UG+IthguTbsY+QpRNAtGIXNi5S0stebi1m6a6Wx7aH5J5Mb+Lh6mb//bnfe+cV3vHlG33xzTsdJJ2drWmEOSrvl+/5//5Eu/81vf7XrpPqR4MCk5sT2c7uqGSIP1BVNAjVvWVTrf9A4BInl5Pn8mYmKuDWmVPVxofWGl9G518+QEZ+cLADtM81oBG7WjeoB5nWqBUQHuVdgbRd1yLoOeAiCCqYLqYIGY0evFfUcX97UwmzGHmMS3xsRalGu6tZNdRJI6QBSIansKGkxOg7vX3YgCYFpq/BGYxXR4XgCB3Go5VD977UHdUUrZlhxqxrhDi7pbjGnwYNSSHxdi0frBanXgPyvno0gpWvfrUaRXrWEPgTgMK7CLTzusx1CKTiaTEMJqta55ZVZ/Ru6q1m26pm1rhGpxkyBajFwp9G48Ho/m8+Xu7Ijj6Oysc18TjQDOXc8trDibu7oVowJFcJCxGNgEISCzwxiyVk7UXhovHq2fnWxP7l9qV9PD8eGbL+9MLv/VX/5Jnp/YW79Oytd3D5+sT5E5tmWP1yir63uz87N15xvvx3OihG7aTqzXw3D6aHrzm+HobX3vqLvryYq2C9U4mu4vT3Oa6SvX09FsSWeYsWJz9XOX3//Gtw8/d+v0yb0EZ0+iz5Z3/+z0zp8kGYcbb55r3OrKjud7x8vmlcM7P/0gNfsHX/ovTu4/TTZVgC2zhG2/DQynkLVHJfPDwKFYlouiuuVxszMyxpr1wPeu6qWP8rOH0/Pz1Uk7Gy0XK2/ZRETc+6oX4H6+3EV0NLx1LpE6mNAuW0rYMoUxIFw4BlGwOjcp9c+4uxmn/XYrM16vNzwKDAEXJzfzOBHk5E5ehiaSmAgKZwnJLMOVmcwD3IkKodQziYwvxEdWkRvEYKvIl7ox8gpSNRAHsepZcgvEDq/T1GFr42bwgGDmgFFdGPGwlHt+SVeNVRUXOi7m1X7Be8KF38P9wtL7//+L6pk7CK2AYWF8QenwoWH2QYtTu3bUpUxgLqpMJEGyVwpN7dkJQCDSUuDOxL2VwRx8sYdyKwS4qyrMWERUEZOk1LqXRmKUicHayeSLX/zC/t7BH/7hH9354Cfdtv/KV75yeOlyalabTXbzKG0p7gRJjaQWzqjiZ0Ypfu/0/qPTR8+6eQE8o1iOIl2haWhuXX7p+t4LQqNsaq5Z1/Nlt+g0qy61W9lmXTpEk0BWMrz1XbM14lRCQ22rNiJq+t69wdkXffWjspywJS8JW/S6GU9fePvNEFfbTS6BVsqr0Cjn8zTiSMwwqQFDMHdlF+YUwLENNsXY4qU2HO346Sk1DGGQO/PJ6llpPUCYudO+NTZWbbW9PL722Vt3fvTd5oAmuz71k4R1m8+n0nO3KtyMLbiP9ka7j+bvbfqPpi++0T/uxblXY4fXHLctWU6wLbFQHSGSE5mbwQtQt5yVpgIKof7tcQggEpqysTbjmcJctbAVRyBIwU4ZbTYqoP1dMSPzCWNVjJjrNT+8LsA1td2taA9hQkIWs2hgi7N+nUI/De3xj6bf/9dXF++8OFleb9ezxf18Ktxck0+8PIt78WBc2iRRTu59+/g/fOvT/+TvnL93LEhBOOtIuXm02/rGrQWSIbEFM+asHCq4/PnEiwA3N/MLw28YKGxAxefUttbMoG5OFIiYiLf99qUbLz57dtptc4oBxasnPgBM7GQEKjLoe1sRM1UbxGjmLiEYzApQB/8hVOVwTfpzd2cy1+VyWXvflJLVZAL3UpvyQT48uCGGpVeNNnKKUVQ1MJdB7wEaVjVEzIbi5gyrgnetai5nEe7NxYI5FCa1VA/chNCr1XSj2k9wtQ7XAVyVlZhfLOHc65OA6jqbzRGC1K0wiFKhHm4EMRhMGbGwkYUgN27eXK9X56sVHGalci/rdHE8Hm+3Xe57jhGAlgIicu42nYS29hh932k25tg07WbTu2uSMWrrY2ZmpRA5g2AUDAyCe1SDUESxlGZvyXfmP/oDOTvbHyX/xU/Obrylm3zy/k//+Lt/Jim9fvWVx+vc7km36koy7pBGmxlOPfSh204jOKfOy06JapQ1d+JGabc/3k6OvnX1c4d0460P391bH2cnm+zNIXtffHP6iVunD9+bfuIKH+0++O//b0t6f3ZruveVXzm+//KatdWw+u5f7qy3B7/6m8cfvDee7S+//WeXPv1lPf2oPYr3HtxNt144eOvvWSZaPcXBNHJT+kxoib14qQ938ypFMCYJqpvVQtADsMsv8SiWraZJU9xu48q9/Hhpy3uy+OTm+kk5T4cHWXNAII+9UWtsal5sDc65R4dIomI7R75T4nHW2UwyS196keBkvW1GI7xyMN2uRdbKSaRBWZnBIhMJZyq2MgC0TcTmbsXUYMJcbb7MrBC3HIiJuZgWINDwQLnYAQuAUixGqTxUJxis6grYQfXpU+qQadjrBuYLBBsMRsbOVmUJQ9Mz7FP8otyFWWFiNwIKDBABuE6VvRqSieEV1DXQL2u9OnxLv8jaHu4Q++sYqQFkUVfQQx9LFEIIZr31Q4Fba1yHxOjkzJQk5j5rKRJTirFbb8ysTQ0zdV2nqsRcUSJJZDQeV/acuzcxjcfj1DQ1CjSIFMdyk19/47XRePyNr/+HBx/f/4Nv/MGXvvzlWy/dXjcdwET1I9c8ZhiYEYhZi50vV7r1m4ev3rSyXG9BwdwVUNWD2eHNwxuM1BdLwQBvZLbTiHsi5g0tT8vTEzpdhlXXdufWXbq815g/Whz3s/7aOL42Tmuaj8Om1c1O2Zym/vK2G6dzoX7MujHcfPHN2Y4u8v1JdPO0S7ak0domDSarNNrstdQ5CVlwRI8rLyOodTxOHSfanI+OdvKj3aJjJKsoA2cEiWLIuTO2FrFbd4dXDk/L6dVfurlYP8iHemWyveSPpnY2xWZM5xPkVrqNMqeZjqeb9dPI4SB/sDe78qAfQxCEmMnUzUCFg0ZsJ07V2VVXn05s5NULWukQVh90gdlB9T8kHXAB5XEmKuxCTg2TgHNvbDEOMotEWBPMPTAzLDuCoxD64YwwA0c3NvOtOZISwdmMNEg/3WlovMWffP1w/WB3zGn7aMxzfuuLB7ufln5XTwxLsLorG9nNz/zmgwffXX7/w8PDadb1tEhrS8FOSrtZygu3r6+wXJwtUkiIBEOvW9+W1IReEdwpoHhguMLYnQnEwTB490x9kCAQ3GicIhOttz3DI8ezxQIEIzNyCJhYhhIXHMQcBC/KWowDA4wqlQI5yLQAEOFsJMJc+ZJEDi4oYITCzKylu3Z0tLu3d+fOHYkJZmyo+REXs9kyHILVS1QLfC+mDqCHBQYVsENRIAFq5Cg1I8ysjW0ppdcNyFjCtig7EbGAwRU47uQwBxMosEgoagQzKxUACYd6qUtkIYajmFGd3tW5PcSGnwDqlLpUQoGbM8EsBQF7KcXgH93/aLvNqHxKd/cKF4CZE3Fq2lIsBimmBcbERW08mnTbslguSaKat6PGLWbtg8Q+q5mqGitXKAo5BGSFKj2+GDMVZipJjWLrfPP20X4Mve9/sMCH9++u//Jr+fR4PJn8+t/9nfd+/P3Hd/5qPHtxlafrpxu6AjOa8CrZ1hXUaZui0KiltJW2g7OlkXZMZwvlKadtosf7B0/8yy/Jg9c+fnf/+GyyE06/9Xv66Pr+59/Cbjn76Z9cvTLx/u7R8db+1Z/eaiWPx5geGE7zjnX5vUlar+jx3ozjX/67/vCFx8/W7Rc/t3f9F2RNxz+4068/2rv6dr9UxhiwYMgKIaoBBI7sbG0SPy82fxZIAKSdndDsFMow9PADOdw7lfmse9jmV7aZhbe5VGxFDxUjU5NCDXibkYLwzFXM2Gy33UP3ZAGagbtuxGxBG2dLjdj2z9f99dZeE92yVsw6sWEdjIzV2YNvDBnwEEgcnFJr2tU5jheIA8TDBoHEVBEY7AEMtyhSDz8m9NqD3GprTGKlgCjEtM0ZoDpYJuLeSuCgpszUq9JFzjxdjIaAisWwohaimBcQzIxBFNiLuZEkaZo2Rem6vO3WZkbERjVGydwqh2sIAg+BQwjPGUfPsZpWrFTp8kDgAPGgl6nSSyIuRR3GIVRNrANtbA4PL03G423uiSjGeH5+vt50+/t7bdsuV0sGjdsRgNV6lXMOIXAIANqmEZEQpLi5G4GYAzOp1SFUzSXDctXdvHnzH/zDf/C1f/+1R48efPMPvrn+pfzGp17PSlpAzkzizOQkREZshRpusZMOdq8RCQ0aUgYGBypzcjMFURDDhfKc2ANBMJ7MxpOdG9OXLMHG1kl3+dbu9979dv/ge9O9vbuSH9PjndJNfD3C6nrcrsv2RruNvL3UhPX5CU8PD1/eM/9ohGQ9G9nWOflsbCvhWYPRiifdeLSWCAbDAqiwQtlJW469d2iLX2mwAYRBxRkgMgJL8I6JjcwlNV1cH7x2ha+l4/sfH01WV8rxZRzvYz71xQ4tJ7ZsuV8jWBnpctRJGz3hwz+9/srtDpP54VUFzNjWQG+uTlvynAgNE6OKYp0dwYlB9TJCTcWpFi8QcWB3yPYQs51UMfgcnLUHxMGpCBA2J3kaU5ylfKZiwbxH2RI7IQDqXqsiMzCsNwvwWJVBRkbMk/29TkrY0QTstHG8me/YYsqb2Zd/Gzsv9h9s7cEcz5rSZ0okSSyW5Rkd3HzlpPtgt1sueb5EfPXazqgfnzzt0mxydjovfeEYiliUmJf9znQ8O5o+eHQ3xmCqxWuofGyZc15KCMPNNnhjCpt3pgdhxFvFKJQq/BNm5+VyKUxtEKgbjFMyWLFS0zppeGogAH2fhQKDacC7u9XLARAAalYXAXyxGoNTEnKDhU3OL8xmTEzg3opUkRz9zL1Q/yuwmCmI6yXvBg4M5lakR3Z3NodpHajFYTfGq9Wq3of1xbgSU+rNj4q+qk+koce9aAyIq2iLzIZdb9Vo1ck0wb1g4JoCRkLFCvnPVfg0lDXErKqBuG3bXnW5XAYWM5MQMOybrRjAtFiet03a3dvd5r7f9iCe7kzPz9ZdtzUQPFjRzXbV91SMmUfT8V5XzLo+jqP2KpZQiOpjnOFuvRMxCoLCZcuM0vX2n/703f50NbafPOiWgfNbn31jdvW3Uzt79uDu3Q8fHYR29vQvdq588pyuhJxLX8pZMs3MTBDbltgsU8uCKfkkMGuLY/ax0bpTdKuQO8fop7Or9/j61ebRS3bvppw29uDsnQfr+aiV1TQsWuYotqML69bJqDsla2ZWuPvLrycg83i1d/S9q2+/v73yW18Y8+h2Pl2v5quT9/7o6PXPbxIhlmQouUThUWo2ZZUti5GZpRS5aU/+/Hs7WtZcr2IyDxQdAYoyxc51XJ7Pf3p6fX086sYaV1YkRdUMMgEs93q2CeNoM/RsMRoY1oRutu3OyiRRk5/uipoFKQ5Jak8DIkN30lSnoEAkgNSrqQCoDNwEUTXaNg4LlMx61FOaDEEI6sYg9kHli8HBwR4CV6Wju4FY3QEEkVq9iQRT86J1H8uABAFAF2kiDBeJ5mbmUUJlLEuouFOtsOicM9xZQsVMWq9wa1K7O9tNTeNuUZKZqqoWcytQSKjp9GxmMUpKKVyYj//akgZArPP0Un9FETev1MwQAhGDyaxor9przjlJbNtmPB5LSsycGnN3M9/d3dvb57osnM1mNDwBfEdmBGJhwoUSvM43veZ2kxUrxZxIJLjBzGJKfV/W6+3eweE//Ef/+Ov/7ps//em73/yPf7hc9Z/7/C8SvM9kLGziIAejhBBEDVGSF/EhuUEABocBGUAEcYQhcsD0YroQYNE9GkUgAWOWXW6atsw8HTSYQtvlbwTc35xdle0OTk96/SrrCZ49QJmW5cww1SftS68dTvzM5w6C+7ZgbUm4JIyC6QqTiH6NzHGyHo9g0Km3yj1bAdMOZGfXck9Ts8skKSiMC8OrSoUO2v1Vd6ZdTpQ2m/Vkd29Rnk3k/IhOD/34Kh5cwum4zG/uj9dP+vXp+mCWCi+pYeUUwvTk3W8efvWrS961Ep/MDkoHjIEMyu4b9+TYirnC2AbpAhOLe3EzRxnWmhigDOTkcGmvji2RSMPiRfuEJCVtN12Xdaz55U8c7rftZnEqO2wbtuxUGgfcsoGYa99lICYNQHSEWjtCUELOBZbQWEgptVcutafd2OaztkTb23ywxrzYdpTWbpsgKZYxEbNvjRcpyd5yeXx4mJd5xXF7qUE82XRxkto4vrL74PGjKE22LCww7bocSERiD4eZW86Wk/B4NOr7bQ0LA1BMCa5urZHBNbGtNwQoAszEkVKqKrnaKNatEihoVgYBysR52916+dbp09Pj+VmUWGpyA4gBYVFVE7IaCsYEc6qUVVBxC0Spaddd9xd/+ZcpxL4omK2GsNjP2wWHqRSqg5irKlKtGLltVMlATCShlEIGNytV3D0YDwf5lxeXwOYVb+nEFKrdF25uqEC8Yu4AkzuhdsZDpWZ1j+H1H3didoeE4ObuFpjNCjkHrtB8qyttNw/EZkYhtFG6roM7M5dSCGAmYdE+cwgcgpmv12u4RwrG2Ky7OtwLVbZKdunSpdWqb5txjJPlcgMeC0vdf2tWLswWLJdt4Z7FQlSSvnhsEpqttiINfe7zO711B7PdzDeWbPOFvv+tb7//nY9sfZZS24CV1tfoZHH6Yxx9MZrk0y5RU0JPlQs09mCQ8ZodHXm2VUzTRB4bSe20S5CswRaW7f7ewYO96z+a6Y3mw5t05yW9v58XLbbBWHbBiyc7UgKXMI6F1tvCneAktXcwey9MH4HQzPXGCymvddF9/J3f3X/hqhzu910XY1to5etxqJvNQq1zcVMCqS2fzd+dn74hNkp7AKa3X3XdBhCMUmJb55f4yrunH3R7i7ty8lm5CTdkqGniaNutTYC29IdjnVoURguHJuilom/sLX+0sglbYysOTfFC3o9ox8oqt+XWaJlB3d64YlzVdDIaN9vmtHs2Go/cXVSYWHMB1E3BYp5RjMng7GUALhLHGl7iQ3IqYcj5YBBGJKUoO4KkXlU4pOl4vV4HCVaKucGKaqlRCsw0Ho1yzv02BwmVPsPupqocAFfVGMVKqbAsM9eibdOOJ+PBxkMgp5TS3sFB1Tz2vVoxIsSYUopqRVhC4L/mJPbBLuXD5c0IwcTrZe9uogXMgQMAYpiFNiar1hVikQAmM1PV4YNXaHPg4UsAI5TK5GF2914LE6FGNVXXx4Uwu264CeiziqQQRNWjRHNsszZp9vd+57f+8H+d/fAHP/j2t//zet1/4Ze/2LTtVkEIZoFYAHYTBIEFJ4KLI1AkBHBgBDjXc5/A5kIwkNEQbeoAuwegISRQa2iYpizJ0thojJmblOWhrWZUPl+WfxK6R0VfDatl3kyll8WibePlS23Uh+6BlHLuYCbcRuQVZoACRmzBFDCL1O0lAtSZ3JgtZEEDzqOxXTnDh6qdRCkKBsNhwTfojeEj7re5uMZDCeHZLh5d1ZNDfvACHk27U1rg9G7n57Dzgl2nSCUaTTYvXtWH83dOf/SNV9/+jXzelNScHcywcldHJu7Ytoac3MxhBHUwjJyIWYisGMz1olobwhoIEFzu+xhSG9pRo9vWCus2H432ru3tHVDiJS8X5+ZGiQpKKMlKMlWzAHa4gULdq2AQ9hJLtGBgcEwlYDzBswc/fGX31t61g/a97iBu0vGj1bf+qr35y93J03SS+lOUkhAV54WahsTKGO3BzLqP253ucJzvP/3wad/tNy8/FOrOtt2ykzYU9M6exm1ez8+WZ6PUlLw1YkIIzEaiJYuk4eNWxW/dErlLijE1Xc4sgZiTc8nZBFYxdnAMIhDqTcuF5QEAsxXg7of3SlFBgFngUGetRKTam1vScGFocAcqJ97UhIOT96aRJTZSLsDrNig6f9b/Vj+R+XAmwlGJ8A4HkxMHZrj3dnEqIoCpmJJ7GAa8xiwFpmbCg0jTUYO+ATcrzhzgsLpOBteCupLxHW7mHAiAVUAdEdUPm/valMCMwbdfeeX4yZPT09OY0s+WbIAEWZyf37xxg5mXi3PmECVkVTObjcdrWM59PYxzb0yIMWrfC0vgUKfT7j6dTF+9/fL9B6cnJ4ummbRtkzMIhEKRI5mxMRshs3rK1GSkNcad7GrqwkRl5Ja3lz/3IlAe/sXpR9+5f/+xLh4sdNkfSCPTmaqWZvPSZz97NtmMz59q/os8fytFNt7E87FGM2IucDAY49EKBMF00i/Pw0y8a2Fd2rWDAAb1HfcLid121r539MkP8879VfN2//5NPb+uJ9P5aly2LfcWbK7NOTdPbPqRXHrSXH0apm3b3JT88Fm3tNXhwc57v/svX3jjejx4u18vwzzAclyPzLz0LdwDjxWcrSNVCTzvzjL5D8bpWmQAl/rWe/bM3mpZthmLfY6vp5s/Pj5+vLda63alZTTm1AbeIdpLFhXc61RsDLBNg8PVbDOOfRjpA1/MGKmsbXsmSaaT9nT9sfC4TdurweY8QqHtbOzs0WU9X2+0a/dbXxG0eKXWIDm2gMALcYiBc+7BzkmsuNqWYAio45o6QaoK/GFrC4QgF1c+1Ip2azBUewBRRIJICBLTbHfWjkYphGfP5uv1OqYkIqNRS8za55SSxFSKBmbVst1u+15zztN2p03NdDr26jTiaqeDiNQruWnr46OWxZZiU5v9IUOwGn9rhTtgFxwVnjk0u1WpHeqExqwmFnqSWNmUqKEplZjHwascGqgWZwMCB4cRh0rMGTIdBjKIXcgvqyzAvZoMwYDFwFV9y8TmZAYCb7caovz6b/z6dLb37T/91nf/8i+2nf3qV77cjnfz1omFuQVYjQPEjFFtfgQI0MBgYHJ2YqrdsgcblLhemSsAGA3QEFpHizIya61rI3bTrnRtyGqbV5vl/f7Zfiwv9Mca+HZZzHnJkm2Zk7/Yn6zL/KPR/k5gbV1HzAXjDpbQN5zHZB3ZEn0wA2G3bu9AXJDNckq5LeelNDd30vjV7v4PLDkpXE3AVCeCGswVHSOR7CY+W+xgPcX5DIupnjbLRAvKx5k3gddJlz2P2VvnFUGwv7t48IP/9dVPvX0pNBufrcYT3WFsgDW8cSR4AjIThFhgUqw3t8BWUZQYvHl/7ZfkPfDI+1Y3UGtwebbz+o0XX5juhQ2fPu0+fu/Zdnu2d7nlpRJBAZunoiWwgLMVAxmzD7QZHuJxh7EmvBRbl9hev2qbDV3dy9eu270fx7iz/N5/CnYtjm9mOxNM3FQUABsKHCVbO5o2XdNnTTvcQkIZUFBGEAlMTjBwyFn7Pl+5eqXbnC6XS7ASVPvOSFlkvVnHWNffwy6mmMG8cxXtY5AeiqwjGRkhOisGIrPX4lMLtECqrA01xLuYFyvMoXoFixoxM2rgDzNY4cFJqjXQQeQKN/Y46J/kos0dIiIGYpfVIxuDoa8usYjqCJpAJFWI4pGDE4oamUUJmdXM2Ab0s3oJHMzhKCEE02EWwkNXWo/1wRZZ52Z+YXr0QbrlTm71iXKha6vRxWZOHJjIijFzKfrw4cPqV2BmtwrAZyKyYjHG4ycnqllYYpTtNrMwsyzPziVKG9N4Mum6DqYpivYqIqZG4BBYYnJnZl5vutoqLZeL6fRS04zPznVEqWRNraCHdR4KSNFJs/bUoV1jssxhf0ds38xKqzf+4H/5s/e/+QEtUthgfzbdNKvRaHy+XE6m6RNf/OUn/vjx2cdyc9qun12V03uLQzTSQorm4PACJ+IAZxqPuzE2LfKh5GK60M54htLDgk9amjR+yXtZ7WzuXo7Ldm/3Ubm61PTxZm+HTsa2SLwJqdlies6pb/cZu5dYxmi3dj5PpJdm4/XiwZ/93tFrN3df/PLypx/30nhWltCzRQP1CJYAL1BGMmYTymdnW6wj5FQA4A//4o9fu3Xz6pVXY2zRo49dbuXy5Ma7yzubw/GH+uzl9mgbO6TQedc2SSmPdmI6nAqpoE/oWnYu8xHyhx/Np9aOF4/G4gxqOIzRmm7B/SXIAXtvMcQ8D3EzETdESlxT/woEjbqiA4PLWmJsmYL2K3NlJytwK4BTscpetUBwDzwgBSrOryYaBQ69ZhE5OjxMTZu7ztwkJTgkhBRjNbIHiTW07NLhpQM/qLRXljCcUwOpI5kVkTSdTlULEepUmWjI5b3gvA7tbPX0Eep3ICbWUi7ifmmw+12UzIPXF4N4q8AuGFhD0oOTVUuTBLLBMH+xHkbwqsSkGqQKqtTKisoEX+RT/IwKwBfZUHSx5Q5D7esDTbP2CxwBMoNIBAjgUkKBfelXvzSbXPrjP/qjH7/37nKT/+bf/M39S0fbDoykoMCJhbwFxBHJg7u4p2oxcSdQqAGjgzuqohEHYyfI2dG4t6AW1IDHMMHexKa2eGkU8/mTV2n5ed4c2dO/xaukejXkvU13ulA5pfH1y3yWuvMz0QmnhtQAiWMdXzpLlheuLXTtmW2srgkdwOQoPMRgLIAcxnl5n9rDvSly22u3CMx9IAtkoUVgWE59n0eRm6C8HZflNNmorPawtrnRArKJ/bK3Z4Y1LDlnQkM04iyamvb0wx/Y/KeX9w6fdosxzRbtlMaEBp7cgiOAEJ2q1Ig5RLLBnsMsTlUUXX5OUe8y2zsfRfTb9TTqm5997caNa8bj40X3/vHx/HRdmHcOYNUAW9zcXBGWY+t7V2dOtb0MRL0Nl497iakJLfWcOfi4Tef98uTRg0+8+Ob4c19eHX/rynw1Lbz5xv88/qV/lMY37GRbAmthDlxypparxe2l67fv9HdbEd4aDImJiCBQG67Q+p5CbB89PmliD5hpBvqD/b2cu+VmzZWAMWTThmIGYmXnAivWW2lDmEyny3VGDNs+B5ZgcK1pBW5wCCcJpVgpZqbmwzHs5k4wNw5UdUUpyGCfACptkuqeykHFInOBiTOIihkxRSYzkyb1RdkqePZnZVEdmw8qLPPAXIpxYHKU0geiAEBIJJiqDebD4e60urUxN1NhqXvrOoTnQbcM4gGs4ReEoYvwQMAGj6PVTd3FteLPUX4EYjJCEDlfrgBvmqTFnlseOQTtFSAtPQepE7wqTDErHOXg8JCYHz9+FGMi5q7vRQRmItKkce4158whuedHjx6dr3LgNqVR161FpG3HEeJkDGFnKlT55/2ozTze0mhd2k062KGPMXM2zvPV7MpL0xuPxz574dK1oqLam+sLQWKSj9f3TnkxubmztZ704O1PHtyKz771n9LSual5zESITitxALDxuEu27XPX01po3XJexURsjCIjwkRkMtnFYuZ5r5xcjeujCJ4yeDalIIsDODep7EbK5WwjK8vtQmwJpmWXWsMPv3Pz0kH3xb/x7L1j3yttB17Hnq1RswzL5iWoU+DYuPUB6Lf6wf0ry8X68rVu0wHIdv/u/e3JfHHj5o29q3vKeevmDxazG5Nz2T4Zz6/RTMm5pdCwJ1uvl9PdIK1NtptYujF6IU1eDri/PtMH6yeXJsacYxAzzavV1XZ8tn60u067l0Yhjp85b7OWuKdTMTNkWGumgGsf+tFOuxf3Unc5NdnKZv7s8Xk3BwusBAmRpdua99a0MTURhBBCirEUY6odKZVSSjHAZ7Pd6XRCoOl4XKtwmNWzsHJ3fDADgzlU+XJl8VZoFMzNaiAmuVsp4BoPyhSYTY2HrsF8CCessMBabqJOsotbCOHiLLyAYlQyBy7q2QvHVCWq4+dVzgM0uAbyEqpD2odpNjMFCsWViZ1rc0s8pCnh58XV9jwyBWwD8YCfI0Dqkc+g4sPNzhw51A8OtxCESgnrlb319qf2di9/7Wtfu3fvwb//t9/4ta/+xgvXb+UMBPboSJRZY8PUEAlRIk9w8gvAj4EBqRMAAkCF3AF1YvLsFY9DLWEMnmCU+uko7yVt+0WU9ffzkx0+u6ynO7SZbumd8866JCXynMIL11s/6J4uuvNj1VX39CPVjMO92duvTq4fJNFz7wEzbOHmvDCwO7KhBXZTUkfhx+sXmrljxHklR3mJrtOsZdltzDKHVnXZe96A+yZMm5KoG5XlxBdTO+d1zE9186RLy9R27fLJKoyDr4DWaUwiATvWhu69//y1t37n9Wk3XWO5mE6xBFogoQYwYstuNRIKTEws8AJUhbwZqKrjf2ZVv0yPyvz0rWuHX/7F2zszm28++uHd1Y8fnJ5jyntHqLmrIGNWMgpuGQTyhXjfEDmgXgzBJRSzTBTcYbmUjBJNIFvN4yvXru/FzbO57o3iV//x2e/+3yfO7Ln7d/92+rm/n3ZurE/XSZCDEadQVCMv16v58d30hsw1C2OnbaxzJtdSI9xFSXnALXEK3G/7IJQkbbu8Wndu6qYcGI5AdQHpgBHBak6De3Im8Lrk3pX7crC3dzZfGNipygiNwWS81Z6ZWdgG1NVwR7G6BDZzDBAUIAQrhcF0wd4JQcCsVlg41IKamAIPyWpWF1JVxcRDCQuyarO3IdCXuUowKhEHIQwzYnWo9dBCTMakIJgFgNUribp3U5i4MwIu4Hx43vwOJsbnhqfh+xsZDVtw8xrd5mBHcSNmJ2NAUiJHMa2hFs+fSubGxDlnkaBW0ykUgRfni7ZtS9/XJ8nyfJH7XkhK1vF0rNrnnKc7O9r3q/WKWYLEWlN0OdfQMNXM3JhpSgw1Ng7ObIIC27p3vp1JV9IKzYZ35uWspZ3d8dx6ShKe+pPP/vZXHnz/3g/e+2HbNs14ZzKedOvN/PFTvoLp1fGaF1jKDk8Wm/PD/dUXPr394/8UlVuJAWzGXjlMHLmd9hNsRqYtWWOZ85J4hkD9DDZpUsjT7Xzmp1M/3QunUzsVnY98G85J11k3IW1Zk5qAxmUnuctJsRPGSORIu7x3/eXXfuGN9x7/9LH1zY3L8lDX0z5po0mphWemDFIhL54ppOa8X39g6zbFo3Xma58AMO8WyvLo9HRZurgIs8NJv03t8YMXJvGd6/np/nq+nB/FQx6jj15aQ9+nsu4Wxw3yRFx4E00b2LicHEhZt6td6LRfdFtLzCYto0tsn32xObg2+3iJEeHg0vSMpk/7MR822yfbPMrjfhyWQZu+zeMZ72DupitqJCba05kEZeoJhdhVt6odw1KSQcQjoYoq3Asz9zX0N7CZVQOWWkW0wxzVd8AD8LxerCjFqhJwWEle0HcGfpzUHXCREGBQ1TDEVKPKi+pStZQhPpAIdcgHUGDxC3/wIEb0gRTLxAM55CL/tTa7uKAAAT5UpwYrRj9DMdQngbkT2JhZiwXi2gDUXGGqYYsXlK4KeK2VPl04kOF0IQczghjTBfSazCvQzjlEgGBCZhxkvcH1my/9w3/833zta197+PD4G7//R1/6Vbz2xutr69FQCcYpuBglQzMwXwmDZckjDd+enYzICQ4qQCECcwJaoCW0hJHRiInPDkdy1HqD5Zg2b6Zyq1srd5+wvdP5073N+ION3es23M1s3YZTzNL18yePusWZqSZmWYS0iGVszXSpCT3cPLP3ZlwAmPVMU/D1OIqkfXdvufva+/1YSrd/NJPLqVMgNOvcb9V2p7P1evnd//y1cWrPDdwtkp5NudujNZ0Xmxs/ozAXX1A/V9fGljlNBA3KyllAYyBId3xn3J/OaLrGMkbtR4IWaBkJSO7JQk7g1tF7bck4VPD/RYgghjKpMjT25z/+lc+8/MVPHyae/+T+vXfvPl2scSNeLrEswM9GUxm3AExdTLRkTGkIv1uMrSgTi4hpD2IhBkIBzBTGEtlRtr3GOP7wJz8IO9KnsR0chr/198/v/e5enGVeL77+e3uf++3xrZvds1XsyRmUQpM1yOQsSUAzStCNZmwZBivC4gy1uiDhwFSsS4HHk/HZfLmzOwa61WYp5EG4qAbhUpRZzKz0SkBwCLFqcYAYk5ioUEjtqG1PMScWXCw+rR6lleZZTEIwL1VOoaWgFbeC59bDYkQcBpsxg+BsLAww5Z5RLBDCQK5wM4VJFO37Gg3p7sMEuEZEwAdMkDuBTA1MA5XZgzEbDHArjhCZ2YoGMDP3RY2HzLVGUumVf5ayBjNn0MATqrPmiykaoabb/f/I+tMmSZIjSxB8zCIqqqZ2uPkRHh5HRkRGJhKJRCIBJLJRqCoABVSjj6qu6e2eHdrZOZZoP+yH/VdL1EQ9O7RTVDu03V1TjUIdOBr3kcgbeURGRsbh4eFubm6HmqqoCPN8EFX3wKx/yHT3MDdVMxMRZn78+D0kO8Ok9awEJUGCsRkiMT2ZxuCcg0/aJBq6N4FYiRSc6FrMZG0IQUTyvLh+/fpysVguV433ObGIWjYiEtqQuCghBO+9tXk3s2SsCjNB+2JlNBqGYEPwDgUTJ+CLhVlYg4pX7/KayxVWY909Q124isfLydZuPgo/euOvR3FkLxeBJGBxWp8ww15x2Ip+uJqYS6ujdSO1Wxer43Zk9SufWf7ily4bWmIIWrYCJ7DMwVsLi7rgamCnI7E1ENQP8kEYViOcjuhsSqf7OtvHeipHZQ1ZBF7BVWRrD+8tQ0wIlsyQwhC7l7x3YRnLUFdbhbfr6fGvf3P5S9+alVwPLTbSos1t3rY+y1gtFJlI9DZjttVps65CKEod5jg5ArC/e1CH4MpByMmNB2YyjKxw4fb+C3eW79V7/t5Otd9igc3O9tiWaI7OJmOUU+tCGNmYWZdHZDq7MRm65YPF8aMpfles3pqk+UWe0OSgOZPdl197bv+KKfN9U55EMzFuHIuVmcpEZFfsymIOKjnOYphHhRIspCW2RTGCVMwCIGqwzrpiJBIYIQFOQfs9B44gtik6JhYCYhCbEBpNZZ90iC0YgDUcY+w6IB1/iXqSfnIa0CQ/yZTCPNKwPlHfM1NiItWE4qp2mHGaCJAood9GqbKl5DGcpvWJ0JuKobt6pwt0AVNz2mSAqiSguIOxe31M0S7sp+8ShytZICe9D3TaHmkykqlr/HYTFEwEten+mEmEOfE4yABGBGwsIluTg4yQ2TSyvXvp3/yb/+573/3HT+48/Icf/GCF+stf/WKNKI7YAo40h+YCBziQJbKEZDxIgIFCNWgXgEHqlQBphXMmh9QGLrkZSTMtZLvwRVVt0ebVuHgiiy+vinfXm/fnKGv55sr4hZlNnx20O81xhKWBL+OsQChCWGjThFmQvJWog/ECmQA6oFU3voEYoisN70ReCjHz0K/360OL4GxgaSrJ1IyGhTOuUFm9/PL1SXXrN7/+TT7aneLMixgNrBHJS09A4FAH8hLIWIJEIYEKNIKiOFscPjg8vH83v/68NiAitqxGNWHyIEIS+k2jryYNdqb2vPZcIkUvukaw//d/dvPFayO/fvjr37798eHZqJhMyks1Sy35lmspbvJiF3kRWrAIomUfGEaiwCpHy+wMiXWZjzXYImlDCSdNdhHN1Yn3V2+9VFC98Uf1cp5fu2n+9N+s/uf/dZTnKGn+3b/KX/n64KuvBhKmEBhckJj12lYutm3YbY2hBkHFQzhE9sSRodAQCuMqCFRiCCLBEGxmOSR3AlHDdWhKm0OEwGQYMaho1HarGG02dVvF/WvPHJ8dL5erT+eLzDnRwMQ2kQ+7sRkDYs5IRMfTLQItF6s8dxGC2A31GEFABBtDaKNnY1OTKwQAgawJUERYBUGE05bhoIhsVMBEImoMhyiiQiKOk4ECVAnWsGEVIUIXqCVyn1YLooR2Z2trsa5CjCaN54oQqAk+taUhYGYhIcsSIoEjhEUFwViLzr4t8Y/BygptVVnJORtCAHX0j3S4MJGo1t4DqTfcCVInuZJumDn1vJL8p6pKPHp8BKgrckBz51rvg7RgBAkhRmuthFAUhcsHrZfNpmFGNsh8Cw2xyIfj0VYIHIJYayEKD2TENbDRuIpUkBY42d5iaZmDlSi8a4ChU1vi9ne+8On8sKpqNxZrRoY0C5mCBeIn0WXuX/7hf/vXf/k/LR/OVxuzfQne6+Vn4rXHZw9ObJYJrBOGzTlaAbsQWNiYrMzMwDdGKYewm+bOiWvaUhYuLBhLlz2x9UbOPJYsS+HGoGKFMwMrGoy00oBiDKayEyqK2WhwyXk7/+nfXb31+XYyOm4X1jkuXLNovfeRoipBhINIUGYqc18OF6+88szhw9XsZEnUAlgsFoN8NNm7WuRYns3z3YPC2XCpuP7Sqwf3Z/fC4Xw829l/5bK75C7ZYRZXd+qRc8/d2Bv6GpkfqVosXXBXR5vffu8Xo9U95z4uwMWoqKs1ySGdHW1lxY//052tnYPJzksb75kixDMHVt8qCxQsIAZESGHAlhAN1AAmiGdI0qhPp4+ECAmSPLhSZNMuxnYqNAQldPTODiFSJZMy1C5ypswVTJyoT4mZpNzlrNQP2T9FXk7gj57jP+d9007loxfsAVI8TjrqHVAkCnRyC8kD7bxRk+6jD63MnO6ll9np55XO5xRSPUt9DpymaVWVktYr+lw+3VgvsUUdfySB0+fQWXJFTNMLmnBOTW1b1vS9AklrFpbVgqxvOS+nf/Zv/uvv/+M/fPjR2z/99Q9Xtv7at77KRYxQLq24gIIpF81BrLAkVtkomMWSGrAwx0TdATyJQKPQRmBtYMMUWSuroTQysI2GRZBVxVWs6r9fYbuKCKaqcBgwqJ3Zf84wQp1ZDm3gEALJjg+WFvNs5ct2FDfRDNlYv0MLm1T1JdbW2iggriuQZp5GNVbOthn8iGttJZw+zBtWW0peBC7r+u5/9199tWyO339wONm+8ulDDoRAZAgCTUmGLbOwEm3FEqtRZbIZRSNiKHMKptmqHli0lUST+M3omDKdJ5wi+QEnyav06Uoq1xX9/DcDRtm+enmD1ZM3f/Izf1bdLJ3m7VqCx2BFe6totpnYZN6By5xK2Mb4RRCrwsqO4HOgiRpIPZNNWkqdbFQLqoFAbavZnNeXpmPyWhQthU04mr5yrV5+e/Gfvj/NJpnL6rv/GMKd/OtfLa7fsCPOruuHv/kH95nybLzzeMEnNp/ZUUXjsFDbEFogKoQy6zI2tuYQJKxXmc1OFguJlc1IoQSD6K8dXDk6emLYhNZLCMrcRlSb5rnnduvDR6LtvQefClMbUZRlkDTClTjQhlRDjJZMElxV1vVqzUTGkKpaANZYphgkQqzNosRW1FobgzhXeO+To2eWOVWBIkDASIacMXGkiZOYViJ7sOldiJiSBhYbTlOAxKxACCHPyIfgk6ehgAGBrupKYpdWU+o3aU/HSEdYsl/sfddYEFht59+r0rWsgKjJzSlVDFFiAgBBJDGyMUlkzFoDaIyRiJK/U9sGY9ka66VNmvrBt6FtmYnYJGWAxWI5GBS7ly7Fto0Src1iDNbYzNq2TWau5Fvvm+TuwptqI8oMF4NfrZaqTDRgFmZlsdIGeFBDshbNlDNWi9Px1IkSgmiMolMMThbz3du3/uB//MMHv/z0zvsfensEHkAEUawxGKBo89+88QOIeL9uZz7egC2lrsrnP9Mcn6287pmiHhQjO2jWRjaiLQaR8k2DhiFitBZlszR+SE1ZSAFbZpjEplCfwUV1CmuZETy8j7Wn5UqolYHjgaJwPCwt3NDyPPqzanH75rMyzI/CYpJd5q3JMB+1LtSmLgZuFVYsxvos1PV4kj189MbDwwd7u5Mv/cGzdz4+fHgvApAwCFwfre5CYHYtzeLZ0dk3/uJbo6uDP3IvP14cbnJ/jx//ye0vNdLmODaoJuPRpVJ8qAcGeWiYuXCV47pefJrLI9ciVLKu1600EBmNyiLPqV4XBCGfwTsKGYJD4ORwZDT5sxCnqRXpi0AFlJmTqIZSL57MRMSS0N7OyT5Vn0JEXXOnU2TueEuJIa+4GINFciXRpK6T4iIl8Y0+rvVkwj7Id1UsUUdFZFBn5prCOElHv0qTUeiIzV2cTk7eiZ2YiplwwarpPc0STwqceGCdfnp3pfMb1+6Gzl9E1y7uvnr8Wi9C9PnjASTRzHQ+AOhNwC06Msp50qBJoFdAgEkhRZRFicCtoHD223/+rdFb4/de/9Vbb/+ozlff/Kffcjta8SYb5JqHdmCzPMCxQDRjUJRMkBMzIXbhJnXOuDExOBmDJcCJyzDQKLIsirBd8KJeFW5zTxZfL64uKx/X9fUNWd/MF+3Hwey3mawctx4CV3NpSx+LF17Apdvtp+50ttgaF66tvMuF6ogmEkOslq2XTttAXC5s14w1qctQj6Myrdv6qDk5bojbIN5z2N4zr+z/8z/+wt1/98aw2cnCig2rGhGBpVSZWGTFIINE5QhDnBEsyHa5lQBRYIxNNvVJ+p9ianhQ0uXW3lkrlS1d/qTK1KdJCiEC1O40y+9+7/VmVr18cP2DR6f5pWZYftrwpZJiwSSRFXYZyQ8LqRV1tIUVq+oUNp3wJnUGuFNBJdagsIiMCG6VNm3wVKttVB6tvJsUYx6O7cPBN74ow8H8f/nr6YDp9gThcP6T/2lz+bJev4a7c1vfoT/45lImvhiJuTyrbG2H1htshKMlD/EIdVw1a5MDEBgUxeDG1Ztvvvdba8kGihBrzMnxzLCZTLaWZ2cxStuGwSDPi+LjO59YlzFnIURYdpllJWIrEI1CzDFE6to4gdlKFGKyhru+jVIntiXoqYhCoqnNGkUyQDs/E05AkxCMwIJgWKBGqAPEwAEiJEjCdorOnIgNADaGexsJleTNABGQMhF1lQKZUIuSGLbdKtBOPyitAQGJihVW0eQmwxArUFZPYtikho4qIpL8XkeZigJns5iIYKZTFzKpgd31nyhNcIgIq4Qo1hqJEkIkazhJ76oOy2FdNwB2d/dA9Ojx41u3bjL48PAQkDwvSAGmEFolti4jMDRYQ8YWmc1FUDcVw7qiIA6iHt6y4VgLlkIWsCyZMFFk+2Qy5ihEVtisZDlkd/8xPfPyle2rq90f31g9JHix1rrMhrhwvj6+v5jd/aWtCkvm4ZOHl+xVaxbe+nzKn3tp9cb9HVhUtKIIOygiFyHKRqRiXkZ4dhApMqMulNE7bIwsHNeO2oE0cuz1cKOrJs69LBR+INH4YS7DYRY1BlBgqjSc1sw8HmWLUO3tlsX2DvNwa3LFtztmzpIBDm7OdRZoEqh2Vuxq/fCD3z2WcPnO8aYsZwc3tq8e7AD44P35yaIaTkufBTcoFlg+/9LtP/7qV47Q3P7Ms7u/O3hYHr9ff/Q1PF9a9WczambT7eu2qciGLDSOg5V2J5fV0aELi52R5coURSY+zNGCrW1dfbK8/czlS5Ph46bK1GVoMgSLkHEwmdNcuSFk6A6sNDkKKAzIQoN0uFKKKdzZenQ4aiqjEiEqRU/ukGTtxnhUARGTZQnBuxCBQaqIQei9udA1gEXPSUp9w1T7xBQX5MPzsHdupdBJJWj3DZFKGswnMhfiH1AgAb24aOqkUQPqst+u9qaOCaVPBdA+qvaOwr15YqI39d9zx4x8Ksh3FTt3ysNIbxYpcWdxhkTF7MjKSGNDYCajaogswZEycQ5mz4EL+7U/+cPR1dEbP//B+x/9qsqX3/mX/7S8OgrwOmA7DFQYsREWasEWLngrDUMkMwLTZpmSExUMVSNRw7IxsErsTagLUhv9TlFsZDVx3lf2H3UTZhtqWRrJRc2i5f3PlcVVOw8LDZKhPq14rZStfRUGXLx4aXbow0eLK6NiRGeCdS2RFeTALXESX4IyBuTKkJfzkTqHxtHGtovBwTQ+s1PTIAA+mLz1bn148/L1L71w5Xf3P9xxLF7ABAMCrLVixUOYlEXhYC0jY2GBEQHAVsDWuaphJZvg3s42rjMYkD5LOv8tABFVSwo2yaZQqZtGsb/+h7v3fnpvOtq58+BUjEr0bsfyZDHI68I4L454ADEblOsiZwcMmAtSx2mbScvMTMkCBwCECRIYUdGStmRqCh6m4iOg2Jo24k8l7Lnl0K8mr77QjraO/+o/5o8Oi50rVIwiKnnyO4T58NXn7u09f3zmJreeP15NquWgpQFVgT1RowYZxSBerCHvK6PirKvq6u0P3iuL3CDW8BlMExtrEBp/VNXFqIwqltkSWeaDy/tPTmaZzSjx00RgbMKUQgwSxFqrCo0xs5YpcZRZUpcnLW9KA76ROtdQsdZGkVaDtdb7JoW+INFaQ0SIIoaCNZaAqCCElBmpiEoH8RL60qCTnU1d4RTtUoYbJIiKpTSFLVAYTv2wjoGZdCY5wVMdNpcmO1I7ol8qlknBUQyYU0eVEmdekjImSCVEL0hjGFEkscfS5D9zooJJG2MInGVpvKrT4+1Y2CpMcC73TSMixnC9qcA8Ho2bTb2pa2sNgXzjFWrYjEbD9aYhgmX2TXCu2NnZca4UobqJoZUo3LbBGi1Kp2Lb4GMtXDMVRtcKFljyPDrKZUMQyIjNac1vPgjf+eza7sRn//nzb/7g8NZn972Cvd+eV3ZW3xitZqPZwzfv3H7hljyo3nn9o1e+ecWKb2t7cFsP+ehwdckNorgs5H4jU1uOqHVt4ECZjxrq4ArWzGeymoTquVGU44dOjnR5YmeOWo3BkZ1ax+wpBEITCaH1ZKIhERRkLHTux3Zxto57u/Hg5j5XW6c2m9UmMsFCEITBFrYYNpUvLH7+s59DbQhxVYXF0h7NF9dubgMY7V16XD2WnHlYSG43m+MvvPqyLxCC+ByvXn3hPh0f5bMni0+/fHnv4XK+k/NkKC6uDVpngtUqUxlSU82faLVwFhqtbPyl6XRHykVTr5pQV/X+dYtYFcWWayRDNAgWwSDCEhiSUnx0xF/qmmOmg3Y09SuS72zHuu8MfbUzmUZnqclpQYuqiHS/TcLsne7EhQwkAQl87krlhAJ1xa10pQnw1OAQ+nKbLn7Rx/7ziQLpBvSoj5sseIo30Udx6iedUpWTInAHTctTD+32d3KI1d+7jdRdwvl4MYF7ZL0Prt0N9nXwU7/AeSpxPjxIZIiQzNoVpnsIGSUmslBLnBnKiDItVMoorKLtF772hemN0a9++Df3H77zH38Sv/Vnf3rphe1GIpcoijoTIUS2oWhqazSz0WoIYN9pH7tWRcBNVjRZ6XPLXkysmVCE2krYntgniFn0NA9FzRC32SxplVWLDUt2dXLFVWG53rBhE7WYHoTpVvDGog7+3vZ68dmD0xHF904uh2pURIOW2MY2iCXDymBVhjqVMWgIZxv2oEC+dr5wsK5wSwxiyLcKrvdogbD4869/6f7/699TyBvKvGbqgBJUgoZMG0FgBGgBnwWTW80FAzFju0E92rt+4/mX3q4RKVPfqYOgFURFgIYkoR9Tj6X/fJSAKELUf8B948H++i9/PRlPZLWA2stb+650R9UZJiVPV8Xl05JylqJlM0PJowHmLCaQA2VIY09oWWFUW0MMBKgm2SVEiCeqlYMtxEm1aaejKvrgJg3LsatcxlQvixd2n/l//t/mP/3Vyds/zERslolrcLB1WOycxmGTbb35YPXET5pyElcaa+VgoFyvGmrIELy0rBI5SqgziLGmCTVzZHCMMcsyZinHk2IwmC3OmNmymZ2cee+rasVGI/y4HBXlYHZ8yizM1IbIzKQoy3J2OnOZIyRXAuklLy6Gd0m6iQIDigJllZiiJFRiT6igZMlniElgY1J5RnJco2Q2L2BoVBWCqDoYBgtgrCGAGVB2eR7aNkShpN1BEO2H/1SEYNPB1OXdSOUFG5uybwZCSo21M4ixAmaOhNgLWjIxx5gq73T4JGeW5MFqmUOIzMSg9I2xmTWIIQCIMTGmIhuTjFvQSQqgHAzm8zMRGQyKxXKZ9OjX60okZM6VZdm2oa7rQTkYjUZgbtsY2zZzdjqdlGUuAmYe2RwwolkIVpFlmYutzaxDJmA2MGkcRILIxgc7qfPJcTBuuPfG3cMP/O6Xam6LMA7Z2/OH0+3pcMtPcX/42JX2GpvlZLSzN7jxwc9++9nJzvHdh8efWV597tLipKrr+MVXlut3dU1X3aD1xrZSLGptqFDkIRphw0pVs94B53LmeLNane2XboxBHi5pkYW6NWqoanWFdkPWt1BiMwza0JKwqQFVCI1ysC1y88nH9z9/80WHiZGGrKohgrjcBQ7Epmk3g+Hg3gef3rlzZ3/voFovQG3INnt7l+8f3wNAJrv90mdQspRy++Xnayx3rl+qRLnkAL1149r44aQtj948/OU3rnwrro5Rn+1kWpDnuCngGd4ZodAMC+9w5vhyPnRR+eP7DwuQNQk8zUMwHDajUC1oYCE5wgbCqbPFJKyctBoSO6BTOMW5d0hXmApAyslDWiIoOXASOvm4RIJi6pk2Ca5OTKfzhu5FgOq+NM3QUTrkVIiIic/bv/1h2A3aPfV3CXrqilLtTX77OJe6Nz0CrX0uQN0TqXaMrb7o7ZJoUaEUCZFk5npcW5FkCNNPqX1IRPp0uNaLG+jQazx1e/3r6E0eUk0AJWG2KqyqRCYhz9DzuV1WYSIWZVJDsJIJLJAbzqElbdDceuXZwfV/++aP/vHO/MO//uniWzv/7PZL11xdDXBm0RqEQQwmDyb4IrQZWs8W1sJaL4ZhWnALX2ld5UNPAycYUMhq70y9VYrjzdC0HlwtvJ5ynKuTcOMzr4y4rE7qJvhKWxudWXPMajEmkh4vMJ1t75TNyWG4emNdXH3nnV9fWx1fGrpRkEzsJiLLEkzBkBLwKjVAgCfyJCEEJ2Ounpm8EdbF/fiyK8N2qBv/eLK39Rff+PL/+t0fsdtay2BjitHES63waiIrAxmQk2Yas4ASPGHaYrc3yvdubbK9ZVVuzJBawCt50siJspBIeeg+laQrSMnTNgq4pxyoJnUZ2Ndeff727o29fKfexJZjHKovY100c2xOaDYLruAtT6OxlXXr46CkArCAU1iBJQUlFxAhJY5EgSgqWrSOAySQ1tHPW8PRTrbqfDTLhDWUYVogK4c2w2pQ8s5ffG38rz7vP/14Pbs3vfHMcWUePtRlfnCyGZxgry4mZyGnhdja6FriSoZ2SJn4dgUOIMqiRoLXNrbecsfiYAOCGhAZni8WSVAnSHSlY8sb76NKZvNVtV77TVS1rRCxy2zwntiID0WWi0hAPynEbIkI1E/qQ0Mk0/mdKnGP30JEjOVuZqEzC4fNbGhDJEn2LwgCUGuSzLkyGAQxSWKSnTEb7wlgIsud3VzHlQZT+gsRIosup+7EBDpMujtf0jFEfWUBYmhIHTkWgqhQEscSFVUYUG5iI2zAzCGEiGTcAWYTQstsGHDOTSaDENrVai0SkyReURST8SjL3PHxMUSyLCsyJyK+9YvFcjKZFEVRlqWI+KZuGi8qLi+n06nLnap67xHVOjfJMiglFrq1TjRK95opSZpnLgOYSDiDowIpo2iBGrCQSpDlozx6DvXurYd+8f2jKnfFXd+WhV/b2F5/ceX2ZH1/YqbGRZSNaUdO7YHLq5PZ+3fe//Lnbv3d//b6lZeOv/FffXZ+VgvLy1+hn3/cyKhYt7bFcIFyhcLbQRDDPkoT3cRlwTMVXiUgsNRGFk0dpaoyn4UAYwvDXoL6DbNqLpXL1Y/VuowcIktsTNbCUTidSWk5ybaJUNTWEUmMwpllzazhiA8+fDt4f+/uPVeUTTDj6db29k6jFYA//MafulERCrFj8lmlXObF0Fs4mE2sd/LRZ92NN3H6iGeHy3mzWRWjUWEGQWvHViRY60JTZ1t87/6jVvLZ8liWtkRxaXvn63/25z/51U+P33m7HAxGk8wU5QmsFxPYBrat2tjJLSXTD6G+6OzqMxKQGHCKfCqsFLuqDpqSTPRBkQkKJkLsB4nSs/Zht6MBAudRj4DO5KgPXheArZ6juoQuOl9EXj1vwKIPb2n7iChpL64BSZym86L16ZCf2tL9idBBV+mRiT8l/awU47zNnShg51VQSibOMXDt9OUJlNC2zoPt4i3tEG0knVh0o8iaKLiJzE2aUAZKMZgVtpN0hgWswlAOzZQcwYgUQoXh0s21ufT8wWs3/qz48XfvH3/4jz/4yzJ89auff8a0K+H1FtT6YKQm04yKOGBpa65XMfoWEtYqhbroHUsGcVYKb4fZaDEeiW08Gyl1LQtCLWEVZB2uXrm5v3Vz9vHh0Z1ju/tidcXWfqRYkbFFRblF5lSrYnYPz9w4m9J8Psum0+yPDh795F47+/TqbpltMmeQuDUEJZTMjWqtRGRq4rYxjcUAbVavqugLXpl6hwuay2TYrBaPv/O1z7/39m8/fDCLxSRm+5jcZ0+AESPCoFyNI3YcnPJIZQK7bR9t+MvPvrKQUcWjhkpsCI2qJwpQZY4AWPn8UwIgBE0DSGwtIIkYlAT2AdhvfuZLjx9Udz6d2xaTLXYmd0VRRppsZ9f3JjT3x6gKqvPQFNyuClDGsCpWYAlMKobYAFY1QIhMACJR1AB4oCZaEXJEhoz0eDAcGc2sOVYEt5jIAHwycMvSttGN+MofZPiGjviNv/q+HnzmUz+eY7jkyTJu8QKdTEmT+WW7XU4qXVa+4kwYUSyFyk/LQt3g5PSoSJpXYEgUcFVVCliTSZRBUTCjrusvfeGL773/u9jKoMibULvcSRQQB5EAZUJmyDiLGCVqlGCtYeK6aZiYjdHObKKjXEpa6oqISETGWO9rCeJcHqVDfyUGhWiEIQYkQBhko4ZON4C4I49q0CAxZsZYY5jIWhOlk98zhkNoTTfH1FlMMDGfz+mrdN7jyf9JAUqDvcJpYJJZRVJkTgRsZRZWhRqFFagBCG1oVbQjkogoZFyW0+l0OBpZaw0b79vF4my9WivTsBwOysF4OIwxEsMQl8PSuUJFGt+I6GBQ9D1j6GiE1GQGGWvS+VYWg3RQGgMi5ow1qSiogmE6I/XUzYtAFKlJIWBuXJJchSorE4gQfZQwtDuT7Lu/vP/AHpS+vR8OJrQZufzh/GR2Essr5Vmw+eCMeWxzcCm5G1SjzUwXvzi6y9v20YPV3/+nt77yr17SLewO6s+4419/+nw1mGxC7nlUBxds2UpZSu5taHNsbL0lfkSY2Ayeox1kVq1TYcmN+HpOXnQTrm9tH4f1xrIdOCs1WqEIsHIm0SArsrtH1YcfHY9uXT2uEEA2YSEiJCpRndXDT47eeuPN69cnqhKjsaXbvXo5hEG+2QYw3d0V67Xkx8vDd+78Znp567VvfqXZNFpahtl4vDq9/c7snU0hv53d245k83GwTkPLMGQ1+ObSVvnO797/3j/+ZMtNA29s2VTz0yXMb99/44+/+Y2r1/Z+/NO/X/gl25FvysC5p8zDtci8ZvCKmtAqWtVACNBWKSSUODJiGrNNykmkna88VHqH0PMoFlP/hElSL1RwHlLPS1fqg2pPqdIkFJGKDT2PSxBJIFIfap8ufqlvBxNRp8/bRdpzolRXimuCmhMvq7uu9nMJCatOTeiLoT8wqKd/dbB8V+KmOQgi7e/0HDm+uKgmpF6SIG26WX06fei6VBbpNYL6CS7COacyIbNgJSYyqgxygGW2YIMM7BgFuKSYCRyCk7zIVrwproxe/u//9eQnfzt74/u//Mf/MKk++/XXnisEqDeubEc2IDRy/1F874367iexWigMq90aXG22JoEHlG3T9May3KsX95Z3fsvh4eTG9PKkeLx9y9RrsstinF29fKuOxft3Kj+XwtO+hipUjbEDsswIRcwyO1Cg5PnKfXJ/evtmKEYnZoYtlj+8+eSXq/bk9EZeuC5NSq83QroRaEFjtInRG7sx3g0el5/XUIKz6ThzrfEnTb5rbKxeuLn/6MHDiHwuI+OK4VZNqoZgGFqQOMRMTGExCHYv80W+WBejq59bymipZSUFGmij1IoGRoBEsAqoW7JAIEpm0toj0hetB7Ksovb//e9++ujR3HrsFKPaYefG9PoL0yu3d0yWBdc+d2nUrjeLsBprvaRmYYQyUavKRBmRY0l8YzIqHX+QKEBblUy8RQ1pwOt2ur8zn6srZDHeM+qMjZWWLVW1HYywKaWpkYUziMn8Mn56Mpi88vWjWTizk3nYb2feLliWgSv2Zy1He//jh3bld3Yns+UTgiAGJgSNCMGkApVgwGTQhmAS4MVElmPlq2W9s7X93rvvkiED8Zs6kgyLYjgpPr1/vyxLA9re2vJN03pl4iCtMUYkGSawqEi4mPATkTLPBSoxmqQDS+yb5tr1a7FtHzw4NFlmjW1jW3tvmIXVMIe2ZbBCo6phTvaunGwrmXp3zhQ+NSYFMhECdTQQNgJhNiRpU3KIwiSSyNbcgWgGJs1vCCNKsKA039BNA1NizEPalhTWmlb8JoSyLI21jfdFUeTOZda6PLeZnZbjzDkwYohgKgqXu0uX9i7F/mYTT213Z4c5caQlQjOXJ8QuHUyhDWytAmA2KQdUTX1wEHeWTSpBArNlJpHYi/EFQmqj+ERtgwbVWhru5eG74wyREEwR6fCtJ2/91o6umvUqfHT34Is71bEJYTg4WdMNmUh96t1wM2ADB244+GJrSBNZ53WxPfChPV6E7//d69/4H1/whd1/wZZV8+Q0q7KilqLJtk6l3EjJK5FKeIcdG4JlcWBWZwji4OHZhyCeLbtyWFQxHNWxZbYxSFW3Q0tG2DgyrNSiJSnz1hbvf3D40nOfa2NgNgSV1oCD0SiqNrPvvPvOq6++9vjxb/I8A1t1enYyX1cLkwcAP/zhd82g2L22P9xna+vb1z5voDHaTEU0q5pmd7JzcLb3GGe/C2cvVeHG3v7GZeRzQ1LHdrucfPTozl/9p++Ni8vi/GLdjKy9fPvS6WL5zns//92d1//0O9/6r//7f6vltQWVldqG8kZtrc4ja9WxVwRCoyokrcBDvXKg1CVTFUAI0uWFib9PIDYaleiiW4ZzAnNXUz5FWlJIon0mHI8g2kuppsGlKMSkSMizgIgspRn3897sRQzjTi8yHZAX8zzUDSN1ZyVTl+AmqeceKe5EKbtWsnTQ91P3mhBJ7dMK7p+e9WL2qa/BLyIqIekmabekcTGo1L8/KeUgTo5SQEKb0zMxsyiA3+sBpKoXysSZiDGUq1Mkz6IMUgCjTIuYjTSOmYdOMt2e8NU/+4N5efr4F39350dvjNcvfPsb35xOfVjN8et3wnu/ze+/W2Kzz5mxI51cCtOJ7Jbh4OrZ+ODM7XhMNzQq2nwzmUze+rv6nd9cHcWvOPNmkZnRJSfu6OFsdRTGmHJQsO5sHrrTwm8/wzQwUudcmsiWfcvB5e7R8TamcvPq0s6aJ4/i1Xzw7RdO3n7Adz+5WtOoKEz3eRnlDcMKvDEtG5/bJnOSicRYD7gScWu7U8h6ZLPML9UW/rWXnvn5j38UxC58ubTb2eg0M7WysGMdAE4zx8FGO4JO9bAZrd2Wd5eOm7G3E1qDW1ZP0ioLpdFX0QCN0KAa0lGsqqklrCrGJJUVEXTjxXZ9fzkyhgLiMRfbmD9cz6v6o4fHN1+cXH1130xWJsBBHc8LKdkFsRRJyDIskiINM5NS0rsMITD7zBYaavYjbECOaeAW9+e8PT2pN7WoXN/K0HqpxK6GMtzwxsG34MCs5ej07r2zuKXjm/eOn0jY4bPIZ8A6mDMjC+WG5Sxww2xhHbOKUjAa1aBuvaw3uXWRvE2CE2L29/ZOZ7NBMSoKd+Tvu3IgvW7zrZs3T05OFssVFKtqlTEOLu2t11VellVVi4rJjPfemiQYS6KIIbI13aYhSeln07TOOZGQjCmUAOWz0wUz2cwaw6LiTNYidBKPMRBINCqRMkQCE2fOgqiNkbsvSp3aEKK1YGYNGiSAKEqgbow7SXUAFI2lwrrMOSZUm421xtqsLAchhPWqEhF2hQIhBAnBZTbPs5TGV9Vmd3fqnKvrxhjO86IocmsMG5tZa2zykmARFZWYfJfQdzk4be6umE4SAaIIMUJVRdPcU/JYMgllZE6yPkzUdbYSnEig5APRaw2pJG92FohoS2BFm05s0aQKLpnmKptQ5xwLgbgWGo0ECa1MLf3dT2at7pSP4kCzd/9Ls1VMbn9pcfsz1zaL49MgY5lOUFVDY5elzde+cKObud7hbJgdXH1uFU5Xs8dt4Nd/evjSv/78fD7YvzV4czZe87TC0OsgchFrQctsDYMCR0RuKXgfMkSnXgLECrGBNcKyXK9l2aKJNCDkxg4LGTrYCCZrOJDXLNIm5JPy13cWt+fiipKrIFBD0QtzVGez04dPbt/8TD0/+9mPl5PJ3qo+o8LmpQ+oKbcALo/2iwF/dOcdPtJ/+W//7Oqzz63XMXMSQRSjDaYBvjr4/P93fed+eVaY+oXiWiO54VCTVx2vwuLf/fu/QiBY2tva39rbfvTJu5ivKSt4a+B9/A/f/cFf/Df/za1bL95fcG3KDZWNDBq4mgaiVr3CK7WEjZAHWlAkBKTiVFRMZ2uQiBNJ3CkSdd3VxI1IzVFOlkl9b7afhe3kNWI//EqSPPFIkzEQlNh0ShapaauqdK7y2sVWIFGTO0C8a6me1yaAcFKE7GU0pIuSyr3UAvpBASSaxzkyfG6MSAAllIvO4WJoz45NJXl/V4kBrcpE1MnqdQPRXf+qv7Ne4gNIBzuCKkSlG0FRgFgCLkI9oNQpVWlUMEtQIhM5wqILwDk4Yy1VS0IJjBRDpTLkfjHlxc1vv7Tcmi3/y39ufvP9+fKTvUnOb/06W306YF/aIfMUW0PensrO/mIysXtX12WWx2azOBJZFVJ6DOnWZfPZ/2v8xdi/97c3WopN/Yto6lVFS88alosF6jCxrjBcrB/XsJvhXnRObASZCqXCUwa4bFZfLj6VO68LrfBPXzh0bvnqlZO9fP7OhwfHT7ZcsWdK0SZDHqU2UqmNrm2mHKIVFu9qrOLRHKGeuUf1tddKd5Mt8QZ333hjr7SrdkHOneLSWsajYrF1bVWEBWoyA9NqyIc7y4DHYfsE+8v80lF29Ui213VBx9C58ppQKdaqFTgwm14kXNJSFyJNCSYJogQk9VDtPnsLmxmP2LrGYhe6Nxqu87Cqw7jE/sgd+QUDhWmobcGGVSInAyRRhXXWuAwStOMAe4KqNDFUzCXIa1PoSltTG6HBcBQMeN7WdjO7vi+uDvBjWp3JxiK2gkiudPbt3/2S9r64yZ+RurWV1POQLQ1vmCpCzWEZuUFhbAz+6PGJzYwiKomI3Lxx/Wx+fHY2A3UMSJV4MpuphMzZ4bAwllfLJTN53wwH5b1790TUGCOqEsLpfLa7t9d4vzWdzubzIndVVaWR/TRTzwQkkffUTlKE1mdZRtC29akFy2yiwjm7WJwx83A0Wq1WWZapwrIJMY3LEQA2HKMQU2ZN27Y7O5dWVaW+UekKVQV88Hs7O9Pp1FizqerT01nj23JQOOuIYK0bDIrkv81MZTFgNkQIIbBhZs6sDSK+8RLFGFYiiTFKNETGWmstgRaLhSvy0XAkKjFI5jJSJUpeNCqiQaSbozpXJ6B+vrjf4+gmJrveFCMRYbXT6e064yCAu+qkI76KaKeMyt28J3WdEXSmsN0fp2upgoE2HZksoiBhhgpiMMuiySQLrBtM1L1358k7Hw3GOyYsqjBxtjQ//Mer7z90r31BVvfvvnJr4qZ+Vk3KYoORtYt9njzY+1rl3nINNrJrD8ZX7x7nq6Plg1M9kO0zze1g24yGVVWu3WCDUkKR1ZCGWtbMsQWbzm3DIDBgPQsEHFT9igIzG1sM4IwWjFJggVAJM2JofAAciMyAC+dauA/vH40+e1uCgXooOZN5aSCtirv78Vtv/uZHW9NRDLEc5cKxHDJlu2u/BFD7anm0+uoff/Xe8b0UJ9omGGM0KFogo1C3V/avXP7p1NZSbzKeWoitQnFWrZ85mP7t3/zdSUO7gyurOHtwuKFnxs+/9PUnH78xWy2sc6PJ1sTlf/lXf/0XxY3iyis+lrW6GkWDwmsmjcADHtooC2urFFUSR5Q9NABROthZO1E3SBdHzoHY8z5rz2Ppv9eL2k8VpFHT1mQg6bInravYs5qSxrJ2API5nQnSi16dX6K7Cj2FHWuK5udjS0/dSQrY6ZfSxXHqhOK6GCldu7kTS74I7p2CVcLUn5LRSjU5JZXYjuHVBXIVRde86R5+jpmnP2BikOl0tRJ8zhBRJjBbgAUGSP48TpARW8Aig1qljFIA1jwiIyoQR4Qx2aKdYDXRxSgcb8v8mT+4FY4vX/31b93vPjLRE4n1hYQcLfNkzNsv1vsHi8FQyuFsHjdHZ4Pi9LPD6WnJYWSNKxbzw8cPV+vj01XrG2yuw9+LdGjVZjE6mJylsaLEjtCur6w+cc1RCxtMvrGDZliEzIkrgxdZy537U5k7u1yfyUz9QFbFaCxffe3hw+P13Q9XZw+H42JYBIKnUNVhtgyh8WGCQqWIWVkU5V7t27a6I9UCAwO7QZXNH5362fFkOmHTNlLPzfRUd49RFbwuylo480Joh2vhM9peFVfzg+er8QvzkxHPgLnKqciSeE2ogRoaauG06EOi8KdsLzVGDLMiKS11xQcA601wzrHywXRUk3+4qQdTlxX4/EtXZIe8l+Cdh1Eug3CImnPBjiWLtTTihcHOsbXDanMmkZmVWUXqpE2IQKhzWGSDsc5hW8nzzDBVcVONqRyXw2ExNFJoCCow5sHKPPp4vv/Vrx9+uGgeeojNWjfSAQdanC2xJt5AawRek9ZsVKQGB+IAkk8/vctGhDoxdhIloCwH061pDLK1NXnm+rXXX/9tOShf/dKrm01VVRUzny0Xi8VqNBptb08ePHjonHtyfGwsL5aLy/sHm7parlbGmhiixMhkbN9vJeZMjUgUoHMOBjbSdgLUho2xm0116dKeKk5npyLSzSpACRTaAEJs1UOZ+fDw0Lk8SnAuZ6D1rbH28qVLly5dci4T0dzlo2EpSkXhzkcX2CStPk3K9SBWiMnsebhjorIsRdV0WuApaddzCfnpzjYThxgAMpZDSEivJHerjniaTiJJ/M2kS9sfLdyfLz2BBaCnuJnaHU7UJS3d8HmPMHZAe3+0dsck9RVKgikVSSaJYZ5qzRGpBSUDOMNoNQqTxbKQPKjEn/58kRcTzNa8ZXgl5FAMFif3xn+7GO2Ppv/z9979o1vll19A4CfLyXE5CjNX7Y8uZ597tHh7c9yGcvR8GbYeykSKRQyF3R59eJgdhnFdjJcyWnEZa3ANWhPGlMFaMoBjNcQ2WgfkhQ0YaCwBDJQBiIZAVdDWax3VqnWZyQPnlsthm7VtBh8sMm+Ge+/dPfvjLxgCacsE07Yti3HOns7mv/nNr29de+7Jk8dt3DiTZ5ldLRpXwuYMwNm8LOyjhw/vP374dfdHEsAwLExIvXxSrzm5S3qzffvTsLr3OuTmn11tRLb3rn56/8Fxtfryv/ianLrFB+/OVw9X92aL0dkXX/naZLZ8573fLs/a0WhQ7t4IdlKb0SoUGxQ1FR7OB4saKQAjgAMnQQyGKkciKEmqYdN4W7dQNM2qQhH7BSRMvXPAeUVK3fLTPrHuPOig52CwUleScifoik7JFSZpn59ni+fL9KlfqPaDuOmnhP/q/3FqqQufneABuCPbUFfSn8/m9s+TtKH7H7qq/ZxtRpSGD89fJ8OCE3LUezp0u6JjPWu3NTpWdZra4iR9pyrnU7/KTFBIFGbDxMpGhSSNC8BRllSLRXOCg+aqBUkuxrEM1GRaohphPck2o80qvP5bevdn1x+8NRk29QZ5cFqrrTJFK37oHx/j/s/rL7zmbz2/erwoIJemWT4tJ5dkh09md+8cv/NQDufj1VKQi5UVyY7yFnAoDBZoTEJ6zpiCM1Ej0nKIBUAeIyvcENhwY5ugsTZYIDvFahlOPsoW7f7JfTPdoUvXNtuXm92v3jn6ZHH2ZpDDYlRMEerVop7VXiCT0ajgAtNiePXq48bv3LC2NdgYcowKtw+ef+vtd+Fhs1XOLsNgpaMndK2g2mkTNBPm4LnhbGN3H63c5y+/UrXbOG5pxbqArAQrwZpRMTw6EjZ5IJAGIgViSi8ZiOlDYlCaX1FVVSsFEEBZeLiYlcNy75msKoKbFrO6qRdNXRbldG+vvCn2GuRyIZfYZK7M6qI5Wh75lS8nxXg8Kktu2uHZ2dHpaSWxZipEGrCBZlwbttZWIx8CtxGaUw32oCr6lQ0jrcuSS0dVNdwdf/KDH1ZzmxW35f5sDzu7xdQVrhiVgdvJavnoySOtUObGZbGqgjNinfW+8aEucp6Mtg+PHhSFY1hh2ZlsFcVgOCrLsmx9Oyqz+XwoMRjLReHywm1Np1BkuauqjW99llnn7MHBwbAcqcTFYgGQBDFsrLXj0bBwxenpvGnqFFyvXrta5sVsPvcxWGOoN/Xd1BUpxuORy4u8yAeDQWjDoCgODx+FEJJFqHPZ1nCSQnGROwKrRO/9aLw3mUxC2wbfsrXTrQkA74M1zEQuL5IrQzeAAEiQjmaVsirWXptPmahTsEplAIE6cdxkU9opb4DpPNYmP5fzxhcTkqZLd1R1Gx1dE6wPrin6prMqCQppX6b0oRfo5OTTGRtFFZ2/eFcA4PzSSufxnBJVn6SDujvr0Zi+JxJAjGmjQCQDh0x548Nunv/6rQcP52ZvIl5YnGaKekVqCzIBQU8rG8ON/+2nj998L/zpNy49e3nZmNnmzIVNdfXLX3zn7Xd9u+vcfuOm1s3uxD/9yx+d7B/Ydx5cfyJXKhouMakrSxVoBV7DOaYay3JYUL7Q0mIyoM0Z+enejDwoSpAadQBHzlUtcck0sDxgOI5FiKW0ruEhKh0tdXi8LlZcHh7h+ZMVy0SjDU1Sfo0a9PTkoWE8fvwYCHk+aivfqi+nvLtXZIMSwGyxYI/j0+PR7tbu6PJy0RTjPDZRjCTGrIpqiV2Tvf7wzo298p13P/4nX/vK9tbOk+Pjv//pD1/+Z9eZfFhUIi9UH5JsHsx8+4Nf/u7Z25958bXv3L13d//G9e/803++0q0nbelNucGkxmijI25Ya9Va4YEGoYnwCg+0AIJqgAo0gGOqS0n1ov5ELxfZEVdiD7B0WWYXKymtjc54l8CahK+I+vpP+aIF2zGf+gq7t9JFt6ihuGgz98GYemIXdd93JLGnYjbQDwc/TUhOUpOMi0eDunH6foYYvT5Dt7lU4oWVQt8Qlj7QEy72XfIk7RVLOh53F7LJdj9o2sUp2TUgBpjUqhp0dGhLnCUtDhiFVbVgp3CMAlqoDGGHoAFGWE9kNXFVUT1++Lf/vxv+YWYX5bbwY7NTq19pvTHrgHE9sW3Nnuvjs8GjH5WvSPnSLbc/GVjb3lv4n9+Jh29M/H3mCfO0yXdOaOjV1j5w1u6QMGxgdlbFijqG07qIzkOFoojNRI2F4eACA5bNIFPxgVbiN7Vv8fijqUy33Lhdb+Tsva3iAbb2xjsHYf9fPa4ePzp+b3HyIQc/WkaJiqpuqlDxGc8fHO5+2Vzd2zeLy5EFbFDKWz97j6tMbXCTMKA8E1ewGfDwBPtVyIIaUVabN0INbc98/OJmSw5BM9CKMY9myVqpVqCNAk0KvdAABEVQBCBCIzRq0mKgjgFwfsra6V5RV8Rz/eM/unFcrw5DbQdWCvvdN95/+atXbrzweeKpYG/EOyPsbdbbnAsInJmDSwewyDdszAZoTFYWxZ4xYXZ8FKMHQWIEKdS75gALh6wpkCEwNTCtsfMsjpAVJnK1odl498qjN+4u/uPfT595XlfT1evvXrt5c9fucM3iyfrMuYwmFMp6b3dgTVNVmbWRDVXrs/nixNeVxObKlcvj4SCzGRkq8gJA1Lipa0MsqkkxTkWjSIdpgsajye3btyXG0PprV68PiqIsByI6Go1DCNPplojkeW6tFZGyHIDIOgfowOWZsWVZ9kK0BFAbQpSQWWuM7TqgoomtVAyK1XI53dparVeTrWmR5z60RJRlmcQES6NruIZIoCjSTz9RGoQUiX2ZSKIRCmNtMjmmvhJN3C7TuZZ2v+rHNTQRMxOBRYLazIokuQwOUZKWSB+eU6yN/VYnSZpCnYRRjw1KNynCRD0Z9GkySXeMdDTPblqj43um9wdQgIn/D/IGROgTfpBq0rtLCp6UGA1BhBkSQ+/05KpQTUtezhc/f6Mud7Y3VZs5K7U0KuogC7XSMrJ66kI53M2nh+vwv/zH5bP7cbRb/+Erw5it22s7n/mL4Z13lncOq3ffese5nfq50ay6/ub7uRkXZNzZZqfRQXamdslxDamh0YYG0nDjppV6J2GFdR6WObgoV1RHB6OOdJxhDamltVFsi4KynLTMsSU8hbh8g8mK8w3G3o6eVHa24h1HVRtYKW7IqGigex8/1hDERsBU69Xevnv+czvBbM6W67xwAHYdrys5Odq8+gevkgpa+HXggigjJSEyzCaucOuZF378o++tqfBif/LLt/7iz77zdz/78aXXLs03RkK2NQlyxduTy0frZS2+sPT6h4e7e/vGTm9/4etntD3z+ZpGC4wqKldStDVoo+SJWtJaKZC0SsKUFOmpT9o60YxAKqKBqNM/pYSrnhPyushIBDJMHcn4XBUKXeujzxrT1F+kRC/Q35OL6mOvgqlXupJOGepC+aoPgL/31Y0OJc077TjPvSZX38o9X+LJGxwduNX9nilZeSfHpD7A9p2ZLpp2ruDaa2B1c9J0AQGky1/U5x1Sn1KL1F7vdMXOD/WEMCT+cxIqMCDDMKIGFmRVjGqmYpkLUE5mAIwsjznLqoLWY6ymZlV98Mb+8snVz03Kjf/lJxnfr7eDWVRuJnbdkNvY69Xos816u9yqmxC++4PJvaP4+S9sHnwS7r2B4sjskEzzcruZSjPXWdmKJwpiPWdj2jgOwWUhAA2zYVYYjoBmUMNMZFP+wFwwGBQEISxttgyx5pXQbDUPWTkZTDHgTE3t6+re+NH9uDfJbl67fu1rR8OXn3xyZxHvxXmNmlejYXZw2dy8UV6+vDtpPmsWu+KCy83Zw9Oju48tW0GIQLa1LMkF5LVUHFzgvZoncx0HyWLQrMrMrNrRXX+kNCdeQxZARVST1gppiVpQAAQk/SJJKma/p2n2dCMfqrberIQtRq51bVkU8/vV9LrVzI8mk9svPlNbGyX3bCvhChyjaBRphCOXgxIbIHiNURNHGNl0a9tZVsV63SzW63zgjBQK365rGINIKMS0lgNLBixUMrWZ2t291Rufnv3Nfyg3OHj1qw9/eW+0zA/fPaRS98aXXbCh1azhne0hGydShbgeDi0RibaTyTDPNXf7qtHYcxEJEYnadSE7+w7tRFNTGyZlwZI5m+dbqjBMIhJCTLKLST0jdzkR2NgYQhSZTrcp4fgECiL9SCKBQkxBgrIso16CEUyiKiG6LBuNR5PxGNByOASRqDjnVCRKkgsgYooinUuGClsjCdOXDlDrNIZS7pDUXwWUsDaCEpKnd1fXamefSD3oJVB0ZoNC2snWq4KZobDMIKNQZk7mZ91IMbj7vmd9nqf/0vkd/37Zeg6PE0s/TAH0CFwCpvlpXmf6vM5H56SvY3rB+vPbvzgcA9QakqieTEahCdIyCjcuV0cP/uGd0zB8xtVNtCZuIhANWl6xgJkHrQ2BIFKc2QkyGDt8+2RYPNj69O76G18bHlwJ5XNX5vP8nfceI7vqbembHV9secmqOPAoPZVYKq3AK9YK4kGedC2cY527XJ3FYMFDx5MJmnI7wAZZtXEWYwjCSgXxgIqcTMFt6VrbuonBRGMxrutiQ9OVjmsuanHzedi7pKFWF5giWNjX/tH9R5nlwhWL1fzFL+ztX3YPP5WTU9MImXwNgKwZTMo8q7fKKVqSJhpj0UIrYWa0FElqtKPxdH/rxsnJcTnZuvdg8aNf3fW7Fm5nUa8HzqyQV9lR664s/Z2Xv/ja7Ojj2dn6wSJ43/xpeTCL4zPYmopKJyst6tZppahANaEBBaKWOAIenUowCZEkuIUZik6ZKoHIRLELtkQEVhbtrD1UcWHmx08FTJU0KayJ6Idu4FhFpIuO/YpPzoCkEO1BIwWRoHfhffqra4P0iWJanufJaOJGJUci7qwO+g2hFNNUb/93Qv0TJmib+kWcxpL6nXC+0EU01dWdnEaHJ1EPOSWntb6/c/7udP3iJHyd8OdOtkQ1iYWlmQlKnmKixGRgGAy2IobgoKxqVBzBAAaFiiOfU+2kOXtw78aN3SzM33v7gzuPH4fgsnZgJWNvtQlNjV834XFjv7Jp9oZZJty886vwuzehTV5gte/E51ypoCkmlYMppD4xW2vKFrDDkQxrOvHRBejAxAgRygorW4FXpEWmFMAkFuwEpDogsDFGNAMaa3xA5WfhoXdL5qwo7Gh3L2PUi7Vvy0cz68t8/Ozk8390eu2fbFqSYRhJyAdSZrMMD2+UB8/TQGNoRkP3szc+WC3Oyp1hgClcNtoan604xggDYzolXYXKWvVM4yaMdHS1vBGOgQVJJVyTVEAFCgAHqBfxhEAcqMNpOnXxHpGJF5hOn1NZuZnZMEQdvn/nntsfF7eyyXU7uco7V6ef+hq8cxy2Z7w3p91VGGEZdMU2WA2QSlCDNYAg0YNaplgMbDGYMuzWVphUzXC0nXP54YenMa4NDbnOIBo5qBJMdEWQ6cjq6Ognb61+/QNXrfjGLW+vvvujv/njL33Z5sOitXZjEMBBFDVzK+qBxjn2bQ0Ea03UkA+cioBMCCHlrJYTGqvGGGOSiAQxUWiTvReriBKszULbMiJAkcDGJG5UskOQDhRFCK1ltmwB9K5kRMqiIh1bEjFZm0SJgOVOf0o6QwUTQgR3dApmDiLEnMaBDBMTS4xQZiQ5PTbGJOPCjr9JiLGLQFEkUbpAKYL2SUCSDaKu+fR006s7ovqfGUSEqF3A09g/qDN+6dtSSQeAKbkUpvOsL1p7OPmpSPl7sJ/oxYzm759xZLg/WdOJkrBH6fBmJN8I1ov4Sx2+2PV/038DwKBAamGiIZsZfPrROx//7uSh+wxjAxS5iG9Ahp1xYsOqClC1qvAKQT0uvQ0OtsiHvpivqun/5+9XlwbNaV0Es2PKF/zsNETEVb3ae7FRRmSprawjLbldQlbKS+WWUAmKiFxrZ+euZKlLlFkomPIodsusTOkZ7ErHU0veqoM4tA7qfFFkGMmcJ7Uva5psTNlK7uG8nSxmNU0EwhRhEERNvWy2RnueV9Vq/tIXJsUQP/r7+xILV9gAsdECmO5NygJFsX/0YPG5l4gDqRdiqyx+FRiW2UgdUOBg99Y7Hz6cjrYOH5zZq+8++5Vr8+XaZmMnxVL9fLUJ0a1Q8t5zsmxPjj7MsuzZF1/C1vXTSrwtF1JUPNpoyTW0VtRIYVgboFH2hJCGj1LXQEGafOhJFdzP7CCmTdrpxXQ9C0pC9Qkb6TPOniOliSwtXUGZGh/MIIoq4ORlL1000vNQiT4k4+nqkjqFVyRpdTylEd01fLs2Tbej9HwfacdMUIUkk4kkhkP94G/XGgbQ2fGi2279nXR5RspWtUeMSC/CbHoo9zX3U9uo3zvoTPBIE4kt/bOoUsLAjIJVjSgnFpZ0+vMg7jQ5lFWMilFmDYYz8oU0pRM5eZyFKjf8wXuvf/TwNIuTSascKPhItepauTHw/Gg9/B7V32zluispwrKnomxCxLI1dhMEklmmKicmZoNyrYOzII7Xu05mUwMmKphsaFvxYzFlgCPJ4ABxLaxltsaSFK2IaqDMZTnixKqWReEsypztqMjYbtpNdTYuyyKnUiWsTNa4COJmuqzL03tlvipHGI6L7NZnbtncBzA5bnz92zd+Y0snRtVSJKxXdZCCTNZGeJFgOJKJShJ14Eq/9I4y1xaLYzEVyyqgZl0pQiT2QA00QKNoAVFNQHRURE58BVI6J6Pq+YKGbUZRxMsk5PvjzCkmLV8dX/vSlTWbjbtR686MdxYyPZMprWCXnGK+VsKBIRD1Kp65HwGHMEOCt9ZORoOidGfHj1erzWh7q27n0ReZTISJjRaDifhQv3H/5P2f69FxWSBUuPz17zx6bz5e6fWdZ0LIRAMaCuqd1C0CcyD2osllKDKrogWLSASTaLRMAhFoG6LhNByWmITopNyp2zAJhY4xMHPXDaXEqwXbzsOAmFNQM2m5iwLodKlSDk7Mva6rtUYUNhk1ddaBSCcCkrlQ2jUdHpEYVJR8UqBKaRaWiYlJOfGqACSTrD4+qogmKUeoqiRNDwBimYIocS9eoHqhEtKfMqJgUuJO/ZqJocLMlKQeKKk3azI6ZWYJopAEjiVjta6g7e6/0xt66mzgpNaVzoGE2PVvzzlk1/nPJP+Wpw3O06mcnofo6fMq1SVCXRs4AFYVqh4GEmoeGG3cL9762frjj5utV5ltLnIcGqllIqPAbUhwYiscOMRWlZUDWonTouKiMDAoTVHlGK/FxtJSxiJaD18ycbNendih5cZKiG0TsiXzGWQNWQgviC2JJ62Zq6gDWWYDi9KhcHZcUmgt1xgPos9G67gKoYjaNGQAp2QRLZsCaykWNK50stCtuXezlla5Dcy+jhQMghdPaEKm2f1P7y9ms8Lh1nMFuPrFj4+cnRZ5FkJ88aWrt164BUCEYXnlj8/WHz+6e/Pyrau1DyAhZmtIPQRiJ9n62Eu0Yzc5vj+/9kc3b37l4HS2sOWuK2gmwuRX7d6jB+/L4OCHv/hNDPPJzo3jJ0/+5KWvrs2okuBlUvFoJaxrYAOqCR7SKFpQQ9QCdWJEJ45cSNopqkIsSBNDEKDfIxdEaCg0dUi69mmCV4Be/Pm8Pcvo5sahIiFtHGb09INzXZokYtXFeDr/dYfZUFfHJn0QPSdJJaYUUVLY6cGyCBhCKlO7RyReviqnKShNTWzR1DainpJxnkoA6JWpCV3MTJK0KXlVIWbivlODruF83lHqeRRpv3RWhMwUo0JAbPp/7mfi9dykuEt609B0Sq1hiByxVUZakAL2rt6UhV8+uGfb5Qcff3Tv6NOxm+iZR8vBF6hsU3u7Rqwj1ygWtS/cj7n6+nq1X5rGMM1DGAWyiEMrVsOm5XU2GFRWipzDTEdOaWD9sFxnBWBUl61y9D7fTGh3Y4OzrQ0Cqy4qKzhQBhooLZlqCbZllmGbCQlJ2GwW2RDVBou23R5syWp5eP/TB23c2S22eXX0u0U7uLq+NxisysEk3xq5F28840bWG8+WyRIyM1s9QTkAGZgQTVAeirAPiMTKWQAHAUwGCSoSW3n+xc+ghUZECVZYqgRd1yoNyDPVTLFf22mII40iCXqaC+nFx59Wtf3c16+tZ36zbmy006vu5mcPtvb37i2tjJzbv3G4ni7MpRkmjTdmRboUbIANuGF4IASGdJJnnVQEgyNZkFCkaItwdO9O/fqd4rXMuK3chpZXZhnr03bz6PWzww/K1VFhLOXD9enZ8HN/bPKDeOeNV3eu6Uq1aQxEOBDVykLiVTzQGhJRzxyZIBKZRDV2csopPqUJ9bRzQuRzPpFYlQCFSNcrYpBKVCZR4aTwrGlOhohNmmTt+lTd8GJquKbrpsYsiA1UFMSkSmwoHQvQxPLsqEopGWflrn0FFQXrueRAOoy6nyKeUuLpkmXSRBwEU4dyccKzCMKqgnS353xSBhMbgoioaGefhC7MAiws563a1GyzbASUHt/nECQi1E1ZRE5D36mFDLDQU8SSdM0OXxEigkn/ZIgUlGBApqTHBQkp9kMgTJwcGfsUsT85+wKo438iDVqnY0kMmZaoKHl2cvrGL75Pdf3Fr778nz6aNH5TB/PSHn3mYOfv3lvHusggIuDCtdpkMAEaI4xnjcwDtIght2JHjRFmq3Dq2QhLu4/pS/79/2xX74adP+DlmmLkVYaziIqpCtIYJ6atm1CzdYRKbMa+3Ko0VEKzqBpk0rYla0m2LOtixLohJUslBFY0nPH4jPbmPjsLrrFuOr1068qzPNlZNNNJzMNcba0a0Tb5MGJi2beng9KMJvz26ytrTZTKRPvq166GUP/0H94BMNzaWlSLzOVUeAqvX7tyFY0mQ3uGEdEYWljeLNbZhp/ZefGhu/Psi1fm90/hBnYVQmV4ivmRvvWr+TP7z3386XsmK1584TU7GsfBB8Prr35SW7EcMKpCgVXgNWSpWCkq4gpaAZWiJtSkdRI99aQBFBSiFFRjMo6RxKfrbYlUYyolU2DsFka/YPSi56sKYgV16JRe6FMKBGKtkaSCpNJVwMSJd5WwnZiG4nr2oHQ7MQV3lRSMRSEg07dJUrAiUtaoSQ+g38tdOzZFQQuVTgu2K61JoNwFWoVq2jqQ3sE+2UgQwdD5/JGKkPZbo+sCd6jTBY5FqoTUseoKZ8MQTiIlBOpmlZQVSYUv8SWZYNgyOWgG5V5RmpQyqOMStQu1zYWDXz/6dPPk4yo8LGVCa4M2E2+pEl95rhkbDZtoK64k5BWtefBLxrekHVlaKFyQyrauisRZqKQoBCwDW9e8YR3OaeS0FW5tvgkZx4zYkVbUlF62clkFNVaI1BiypBwDQDlTINnAFDbkPq/ROicspaifn6zWyzIbnp4uZ/NTq800z3Q+OPmBu1cV7jP7bIYrWx0Uk1vPPJsbaULFha0g+wX/5oO3t59/YfHwnpLnzCrFINSAO+t4YVWrbNsoVmyICL66des2mAwiQCEkF8QItEiiM5pQQhbxIEk20h3/LqnQMBIsyomvQKSq9rU/+bwzoV4KiCPbs1A+0sG9qiknlxH2jnV6LFurUGKm8STSknQFbIQ2RA2BQiJ9EQVhQSo4IZBIYEOiwZ/e+2Qw/yj8/aHYwcLZVhzVAhEmu0O2dRPxrKtVNp6Obr9YH2+2Hi5sWRM2nEkMEshn2kYGI+HPHqSMIBqTmHuqRLtBZ+6qSXQeeYGY07bqYmLaEBckNBi2QSQZwktawAnGSUxLRSfYiASKKqVXKJJEVpNLWrczqKMNMdIEftoGiUylAu0LVkpluf19dInOWUtAshPsJh37QiGdBCk8defOU6+mrycStbivABTMHHv0uR9j0P5J0qtIHJPUs0qVhEjfo0jupoAyG8iFYH2islA6sC4oX+nSxAQmElERYaaUFen5VTq+taSKpgu151VLT5hOl1aVRALtKVzKhmMQ43I29N7bb9/56KNRMfqjb71298icLOvnr9sXdvzEjna2zMEo3F0AxODY1mopNiwE2Gii1iRs1pKVmVQiJDHXCDKiKhBr/IyK9SM7+vbm/b8tb95s2h32IdSeK5PViBvQRgPFtpLMQi1rQa3NGhUuCqMD2EkOb/MssG/4TEV9WJlJG1tXSWBXtuLWtS7ioBhObt86GB9ci8WlmR89xkRWqFehHnleQSvQWSX5wMIW+VhlUbjrf/xHX/ru9/6mHE5eebU8nR9+8JYW+RiARN8EP96fBG/ef+vjz7/08Nqta5X3xOxDMCWREDuq50sTiisH+/HqWf2wziQvJ9btZGTMfHbyzn98sB92bAY7uHr15Vdlf1S5wxee+z8tsoNVIxaMWsLa28rKWrFSXQOV6lqlVt6w1uANkQfRptuwaBUBEKBVFaKeqQBNtPYUOHtwJSEeqVylPgdNoshdP6bvDRMAY4yeP5ecAzCdNXbafjinNfS7rGuqmMSx6rIAXDguoSNQ9Ffpfq8daKOd7MV5dZ6OHJCycqeomS7XL+VuM1KCqVOa0ENBaYP0TOauu41uCFBFtJPq1B4JS3fUm3hLPMetu/aPCIhsxzgj9M8s3WtPlhCGYAEDtRozWCZGZAojA//wk8P33/ay2HEsjYdnEyB1QMVoVDYt1WxqqaNpTKExRLSHXt6Q4jVZWZZGIY3BCmwVRRZqQgnD6zyUQLXQycSWFj6Qr3IeIQTWqGHlPJcDsCVSYahVYjHp8A4Aiyk4lMoDKw0ywRgmSpsxl+OJD3JUVaNBNhiPx9ZyEAt77cpOo/n89KhYrvZu3XJ5bAVgF1hKw97gV7/4od9y1//wi/d+8xPLJXHWBJ+RVWQ11PejmI4sWQ6rMBlNJqNpVUdWkghrLZBUTrnLxLQf/TBWxItKwoMJFhpS5tQ9DDhfG/ZevKWtjxygjWBYcf6be/XjRXx+bw9y6Zi3Fn6EmWAOnEGXSmtGBdRACKpe0QKtagAkCWKqJu+wwAb1ahEe3pts7dbrjZUVAkqUypZNAbY+IgvHwmHD9uCb/5JQCdcSHtndLc7rellZ5oJFgicgTRcCkoYNmZPBU+z5GCkesJImiZkYhRSZs74NIpJ4jSHE1reGKEI5Yc5IxvVk2Ma+Zy4qKe0VFUpJZBdvut1njYWC+Xz+Jy1z7htawO+F1oRnd814OiedoMew5Jw4oh1s+7QWn9LvP1cfkdOW1nMhoQuE7fdieW9KqNLHPwUlP0qQqGoSBzeMpBGmKSnvGsx6TsUy6HlUqU8L06MDXWOjv+FUr8YY0g2I9ApCBGYS7WvdRCFJSGI6L9PTXXgzpqMxzWWIiFrLMUjrQ164er15/be/Xi6q27dvPP/cZ4vM/uLnT5jHr+5jMJw+eVKVA9MGH+CHYdBWMnAheGejV88ovUZjnKJgExitUGbFChM4UhQVhjNfqT/5L7vDGNyzm/fe4St/whVxZVCbUDdZXcBLmwW0jIBYi1SSWYmWVuWkUFmIEEvtV4X4MVDxeixD5rbhjHi68VK1uLJbPnf9erm9c6bTJ+3kbFGs2GEWXGXCXIIHS64hssm5NseHqyxj59xovLOcr0Dh9gvRe3z0NsoyF6kANHVhbbaYnbCFJX3jV28+c+UaWo1obWGkZgQYh3oWcRSOzN3hpQwzHd/Y3qznb3zv07rSZnV6VSblnrtzf/Hat/5kUOQmi8V4tJ3dbB4LCyOytB6VjetgNhaVUkWooDV4TdqAalUfqWuG1apJEytl6qIUoEIk52spCY12+6tr0EoX0xKGjUSC6lyS0AfY/pFMTD2ztC9aE2bTiywnwZc+LCckO4kR6XngSvNCibaFC34+niJMk+3War/RUgWuqqBe1urinEjNbu1bNug5Y0ysT3krpct3SQBzgibTlukNjvU8tz5nMqY93BEkkdITApFqP+TSpS+GyUrihCZeJOP3Zo+ZiclYaCaFhoJiJutHv/zZojrKJxKrwL6wkWJlwypYH+KSjafQEElRUbUhDho4asv2PR/2vb0BrZzYtWhGKNm2zL4KK2Qu2sHQXPlCwGj+4IMJog925Vrk6xHXgcMTg6tbEUMu21hbA1ZlUUtsGGeIVjkjzQklhUpMFa1QlMgSxdiVw8CWEUStbEL0bIIHbfygeVw38xu7B5Pplg0EK5nVqJEH9ujw05PHx3GNvYOt669+4e4Hbw5olLlR25KIsnFgKwZKrN5q1Ax06+r1nenO/DBaGI4S6mCEu3ZvGvaFQoXSIHy/qrpjmJgJgqhQ6jUB0wKz37sTdieTcWZE6sNl88GD5bp1//LPv72y2w/rcuFHvDRYCVcUN0qeUSsa1hbd0B9aRQsEC4FGSt7IhBhD4dzpfBZXZ3EkhMjReIhww8SG2rY9lWxkKFb1cu+b/6YdTwbGm8jA2m5djm0NaYQJIsqpsg2gABWRCESmNFEQ+wyzH+/vGrowxGy4bVvLJogykW/8lcuXy7KQ3vFTRJhNyn2JiaTbYN2/ps5wP3LTkR3Omzr9dQViwAp9KkyeRyLgqZkc6PlGSoSsiyZnl8ymTiczdWSm/iA4H7jVzkiNmSRJ54iiQwC6AfxUk3fUaL24V5wnBR1dpE/gFQoY7Xuv/WtU7TMP6l9OP8Rxnvn3PVw8VXMngA1MTBefiZxH6dR9Phfb6o+S9BgmouQpfv5+EshYbr1YYyQGYlO47GQ2+/XPX4fF51/+wsHBVTcw7703exLstERZlNW6dU6EFpmLPPctI0SWaCjb0NLqQDSw8SpltLXGTKDElo0hMoQIFgSNBLbTb588fA/Hx8Z72zyQ4gq3EZ555TiwBiG2IUeovGGClUYCCyx4XjjY0kEJWXAxApZ211Q7BM/wKzsZZ1955fJkZ2se8o/XWU2jCvnKjcIqy8Vy3W7O4mK+2h/asBZZB6Ks9pvhEDHIx3c/XC6q69e3t7bo7d/My2Eh0ohkAIqC2RpAmorzsnz/zd9d2bvylT/44qrSEAKVnqzRJepZPTt5ePlZm60GxZ59//sfv/uTB4gqsbl+/bnJ3vaP3/jlN//8z/fjdHHUwp2V7Y5SFkMAiQRDwfLa8IZ1BdSMSskT16SVolYVD/WgNAic7NFS+6vjZCUBRVAiZ1EXczq28DlE9NSa/f1N1QezZEetzJ1VUYqg/eJEZ3hO6N0ZeoCmOylBF3ksoUe5L5jH6EjUiZScfuxoJCQ9Zx/8FF+h41z1Qwf9Nk//PwedOkoHd9Tl/nKJjEZ9QptiMCX6CCUHbuqT1C4lvtjd6RYScJQ44kxAEOkZKQn1RIQASoaSmjYIYgQWBDUUbfTjQaw//fTT370RRrolnrxSq7EyoarZQxZcRBMbbjxqrTfKtWTRWBOkUFlY/DY2W3GQe47VJpaki1os+0HJl27yl19wN768U171h6vZ/TmbVqSZo/Q8XGfzoVtKK3Pa7G9vrSQShC2IWVjIKzmCQ2zV5BQK5RFZIW0By96j0rBqsGibpdKQHVtiIDIUoRU/HUxufv7Lw9EWfARzSzFQNijx4Hf3Ims52rrz3nsvfOfLB1946dG999102MyhbI21CEC0EaxtYMrWi7Pps1sKStWKRmWYJP3cH+AxqZ0rhKCK2CGBHczTCfslTDIdayoKgv3Ln63cYJ5nJlcT2KGYfPal5x/n146Wtg0lLwkL8IqwYuOBDaQhbIDo+1GDSNCe9yUpVU0ymMbIcnaaCWlVGcMMdURGokq10VBuX47Ozh9/sP3Vf+5euMrVSb1SW5i6Pi0ngxAqqx6iwpGFIwmTaJduCBBFhCm1D1N/J5F6nmL1CNrg2bCkAkuVgXIwqKpqf3+/bZoQg7VZWsWi0q9/ViQaUwITjMSQEs8gQVMjJ5kopEnGLmj0hXTaEUzJ0j5tqnPctWtGU+ruaNqDTMn8N7UJVCEpWJn/v1OoaydcyOydi2n00lKaYjYU2vPtkJ45ZeLMnN4xAEyIEgGY5KjYEZ2615B2bULyu1jemc0hcVqQ+sAXmUh6E7rqHkTQ2Mdv6rF6JVIQDBOgzCTCCmF6aiwkJQQ9gTRVKjEIMWKU3GUAf/jhh2+99falvd0vvPqVUTluvSJs3nmwKka78OsaQy8sHK1F8HFSitcl4sD6JjRDKoSjl8yKV/IkFDkjNQLTE7MTJyaGEI2yt9nLiNY//nEhC1/eWB2tWU2Zj2wb6yDRSVZBrISVOETDqpZr8cVBuTJOoh3aPEflzM0ytpYqB60a+ernt29cvnIa9P4CFUa1KVc8qttcz9Ru+MEH999/ezm7096eDv8v3971DSRKAFarmW9nozEdPppduz4cDKy1m8m2X5xZl9nt3S0A87MnKjmRMRk7O5yOJqePTk4eLNxW5mzerjkbSrtY1o+fTKajeCqD/fjWDz55/8ePxoNhsAJyTz48PH144urcPw61U8Sa16Fc7mc5ayBRoBWqWTeqXrBhVLiQ4PAC1EDNFMFJBrojQxMFUEBXdPZsdgUQRTt5U+1SvD5iddG5qw7PV0iSukrxNW05kXghtXYRorqYCzpXXiMGCyF1ydDZH2mnqpXuqevMSfp77eUvuMOYO9pDj5xxBzk+dXvAhRui6FPlaId1XzyO+sB/ztQ6F+zqGJdR2DARKyUGogI9iIWuJUbdSH467QlgEJNy+lGVickQM1tjbQy9mM35jQg68x7lQBC2j+48vK+YmlyaUxhyJYXKkItgYWdJItls0EggcBaK1kporSVugwk4RXHE4TYHKUid0v51fuV5fPlWcXVHLhuPzNfiJavEzTH0ynWsDmoppVDLMyMfqh+NglpuPRMbY7MgmBQrFWGwFClpA1mGg9aiDRWBmiClZ7I5CxiwzA6UEahth4NMptdO2sEui92L3gK52iLqAL/66Fe8yzIS47KP3n/9s9/6mt/++q9+e39td5tsdOZNxUOP0qPQVtpV64Sff/azzUoQIHWkAAQlVSAqQmrpnwOQmibwVDWmECGcVJA6s3hKYkoiwkQ2XPtcCFrbNpdoinElLmw/f7zZ8auAFUxFshBZgjeQhdCKuCYJodOdI08UgYjEMiYRiIqY9PEK12dzYMnY9lDmjcCoUQpgRQizeLYcXbuVvfBiffyosJYL29Syc3Ur2xk0dZWxAmokKFtR3+OUsRtsgCQxts4cVCMn9FY5VZ5KMMxQbOqayTA7HwIxD0ejxEtgY7SbYFdKYSmN2otYY0MMna33BXWS0hCREiwSkwvUKVtQLxiXZlr7FLjffv3+1PPEuhMh4J4DkoCm86L4KT2C30efu7q2/9c+6nfiPgooMRgGdAEQd/sfv/cl6NL1c2Cvr/RJ+xDNnDylL5q/aXSqO9eA1Ni+wM/TSaoaRaRPDw33AbXrbYk8JYPVvy+dSU7fiu7ivZJoABGYqCizs7PV66+/fnp69sILz33mxRfBzjdtWQxOnszur2U8lcCY5pmH/fBodlafPFi0RZ7bCNb6n39p+69/etJIkQurBIpsNkEyhoVaEpY0iqnCyW7YBfIgrZdF/nwws3pxMK1O//DVS1rFv3390zM7zG2ulbQCqOVxrNk//+zVx+sF1POKPfKN2xdZ1Tyybay5sTKxXC/V3m2mhvfOfBTHKww2OtAV87q1NcsC14dXb7yis6n/9Y/u3b1zdn0w8atiYzcIUgxsUVZX+JYxS7ZHH38Qd3d3ZidzEVs9WQMQsdZahjU2Bn+6qtZyda/dtNWmcqPBZG/0wW/f+Ju//c+TncnX//U/qesVV/ajHz4cZBNr3Pr4SZ6XJIg14OPO5NQ/2TdFzmfkeFgv2xiCZUshoob1JtakNVBLJ0IZg6oHamIPRJEu9DIiECQpYUGB1NwRgAUxxRS5kF48Xw+Kp1ZNt3P6OrJL7IztPHC6irabAAaBLiiMXZQ5TxaJmcDKvV/uxVbt00ruJ3n7v7rAr5i4Q7dVejPCLnftdxddtIy0L8S7/DIl+B3cfg5H9cmrdvGZ+k0kqU3c8amT6KpKoj4/3fXtSv6uAu4w9/S2pY2jXScYxhrh2G/+vjYLSiCJCmujlzuPDptBKVGIyGYOsGKjsAXrdAdDlgcfLL0pCuGVt2BTcMWeRWQ82dm9MX2wOt07erzleJ5p+bVvZq+9ACyCMMeNj+RpS20Gy1UYEjLX2gHO9qajJ1U9j1I3xq3dM7vjWqARVhxYLaEcr7sjTtgyYBk5zDFDJGRSeFpxGBhnnIXCZKS+1bYtrGnz/Vm5d7Ss64V8dmcwnObe1tOd/I33fzUPi8HuMObelFbK4hc/+s3Oa9++9vU/Of31p4tKN1npMVjDBYELXFWbF2/cvnJw8+R+YyWLsTXKKiIagaDJZ5AASDrYu0QqUdGTHW3n7NEVUgnMsMwALMKlk0UVbVEM2a6az17dv5LvLO4GDmQqjotADZE3cRl1raYibECd0FwKw21St1HToUqdBTWTAtZk4FzyNobWaaGGiGqBtYUNi4fYuzL5+jd8fSyGl+18kO3E+nhYIFpPCB4N2DhFi2i0jSKGDSEBnIp+YB/aTbYkmm/XXb3gPmg5KEKQKOLy/M233nn2+ReJmRhJ1lG0d73tW0WJ6JicylKSkrSiyHblXxrV/f2O61OJLXfqj0/L66Rxvk5uXbo7JwJEE5KcOCDnQnkpBDFzp5v3VIKddqOez95312bR7t0/b0FBkSC0BBAkLl6y/r3Y6+hmgQxTio1dfs3n/d4uKBL1ar797u8KjESVQtdv65tYkZkT2JJYVf1hpwD6qafuwBM9P0GFtDN8UOrbfwAAY8y9ew9/+atfWmtfe+21g4PLQUR8CyKXyRt3FsgmEts24L3Hy+NleOtuPSpHQzcgWjTW1AuxvP8n/2Tvr//LocZpEUBOYSw1EOeZKKbKXYnQaX6FyCKtU7teSOFe/tMXt17+3EGMQqLPXtZ/93d356vtYZG3jQdV3hgW8/7rhzRGtmPXKtjAbmPuhlIMM0cDqUmbDPs0CH9/V2RvK8u4adl6m9WCSqhxcSlShWoldmF3suw7X3mxOlnHS1FAjlGWurnPe/sHXKw2q7zmzA2wXtV7+/Twk8blOYDJeFiO4Yqz8aSY7piP3m8/vXv4+Ze8y8pqflbXD+aPq7CKC1m/96v3br58/e5Pj82m2B0clK4Y7+zMnjyo65C7dnq9LIZcb46s4bKeQggBRjNtFQppRWpFS9oq1YAHiSi1RB4aoEGgqlEpMtIhFZHkgTQ5w4SukdKjHdTZ7eJ8tST24UXDJnGg+12WiEapk5soq4b5KdoEel1I9AIg3K2vPqj2s314+qsjZ2iHPJ+3fi8u2gdP5o5jiH7n0+891XnGkPa5dIdVv4u530B6ToTuu1XoybHdEwkEkmT1uQfQzw1we6rH+U+EdOpL2vLcHxIAICrntkrdGINAo6qoRlYFbDY/Xt2ZnU5NHsIi2BxZK+yZM818zGyFza3rTuvw0e+qz17JRpXeOa4IMG5y+fbWzuXtMBht6tuP9c0hPmTVuJiRX7CDNb71TaOlZAWxDeAltpWbh6HkYd48M5w/mM1nC4KVM9OU23lhRJWFSo6Gyeaa85ptEtEkWBEBDRAbaSkKxEE268pbW2S2sC43NhbW5G42vgYe5IXc2cw4TF6eZOyijOSdw99gatstEcd15tZSiM3e+tXvspvF5T/8k+rB+tEHpws1m8BZFZq1opKXnns5eiCwVG2mVgOkjR3szEEgpNJ5v7EwEbTLL8mgJ9d356OcQzMpDH/6dp0PnHUNqoGV7LnPHVT32a40BkglvCbyHBuhFXMN3kClTkAT4KFBNRK68T5ocsyxKqwkQrYcTVSsw5bEMy8+ggtjBQKDmGW7r/6RF5XgDZOBdSSz1ezGZw5iCBy84xgiwGSEEQJxGrJB55SpQsSWO8vbFFPT3GvCeS/cvkDMhoii6HAybtsW3eoEAGutxNjP7hOghlkkWjbnDEbSbmiVWJlS34ekG4xV5m6uqQ9L6dLaI7HaRaxu8jWdOaoQhqGuU3seJrnj/Wq/j3GeSXTfikg6PeQ8/wclcKZL0LXnQZ2fB9ojW6l31Hem0uxjL2PZVRx6nr6g29QdCQpq0iUSzi8KkCES0Q7VTpkFcX/ywDCp9ETQ/uYEHTVaRZL+V5qUTnzypEP/dPi31ratf/fddz/44INLly596UtfHJSDuqkZlgExplrP7sx4UBZBW+v4p++dTQf033599+2P1h8cyyDPoBHM946Onr+y+z984+D7b84enIkpGDlnFmjBymD2iMxqAAkkzASUsPU8XC3W/+d/8dwg31os1yRBEIbl8P/x57f//V+/96Q+sNwGdbY2zJKxi00IKzXRCkRV2FHmbHC0zGLBW2c22lrE829en/+LV2/WVSsriRXCBtrANhg0mUquXG9OEDY112Z5FkdONPovvPL8/Ycfvv/eR87Szu7Oau6KUc1cTYbFcqtR1ADGu48HA1NvzMlRNSiLlz73bL2+BfJs3N5g9wc/+tmb775Xjst2HT766eHd1x/6gLxwbtu2Ne+VB/n+5O4Hb2wW8avffi5f5bBn4mMxex6ABksiYI0CRNYG7JHGf0lbUGBqAQFFVVES6njCnQpB2oZCTwGg51z3RLzv+yTnHUuGTf2g3wtsClUYNh3RQ8+RHVII/V5E7dutHe7UZ4xPY8X9f5IAQKpOn8p107RIPw6QMN3UJBLiNOCnYoxBL6XRU676IHdR6HY3kjZm55jUA2Np33GfuJ/veiKWjuTRiY1oYmhoz2eWvuOT0gMSgCgZMKQZJPQuh2BNRZsIAjgQArEASpasKCjCWnPn08N5LVuOmW2wA+HA7JKjEudmfprfv9e89FKxmNWKzWefL45njej04HPTyfWrdbNTi/UDt3jmVnv8yNp5/fDDkX+2nWR1jtg0prAcqbbsuWjFgsZrqh9sBsMTCtZG5xbCC4/FKV872E4F3A6qhAqWROPtxpkYVbCBGGqoDSxixHOgIBIQHUpiF5FZO2VGJetAm8x6V9HQfVjJpK1evD06WT0+9PODF3cerM6i3aqj1Xxy+fpnTu6efPLJ2frw3eELr1z/xqvxyBcPVx6tBLrx/N6NS7eqM2VvrEJq4WiNdueeklLqBif3BYmK1B5VEHpphaTmy90qpi5BU1GbL4FFKMbqwC+9sLe1LpbH3iJJXOICZaoVNak0QhV0Q2gBr2gT8phG2IDASX4FRMqI7C5dVS5C8NaO67YyWRGiqm1oVWUvvMyXr/uzhXVOEVS4CWGrcOXejq89rHice7Z7WIPOxy+JACemEqcCFjhvd59HHk2ZoSorI0okynxTB9+g3+dJOkMkgtC1ikUT6QKKThMyKbwz9V3UbreIagjBWNNHYigpKUM1iBhmwyZhUyCSvsJGYk9oGrHlFIdwMTikKvjf2fq7JsmOKzsUXHu7Hz8nTkRGRmZlZWV9oAAUCmARAEGQRJMUxf5St9RSt3TV0h3Z2J0xm+f5J/M8z2MzTzNzNWMaXUlXV5K1eqi+3RRFsdkkGwTRYBEoFAr1mZWVGRkZceIcP+57z4P7iUxQU0ajFbIiIyIj3ffH2mutvVlGrrkuzoOfYZ6FoTfP3WH2hVSYvKpo0wOnGJBs3DVh2RmrZwaUs0HHEBrA6TWTenfQSCAj1KycJvvIJkbD5Iygcr55nJJfhyT5pkjSoCtxXh4uIsTMlpHH1UmtTYOdnrIxOUwARLCF9ev1j3/84xcvXrz19tu3br0GUO+DNVbAbfS7dfXxr45PEGe2LYM0nq/vFN95lYzi8q788rCFhF5sWdKP7i1++NGL3/raS//gOwefPlvETn70UStVaYyi78GWrYEPpuSKZLFgqsPyNLyzZ/7gd1/veTRfnBVOIvsCsgzryo7+h79/5//6r3656l9Gs+ACCLwOHYRtdAieQAwLRnDROFPYKnIoDEGNDfz8WP9s/nTdNmFFq4UsF8JnUsDOlK3iSlXdnFXbND2TsFo0kytuve6m0+m3v/P2Lz6Yd0tdnnrmsHiO8dZ4d0Zf+brtug7ActVO6q1rV0rriqM5P33Or9zcuf/JL2a7V1rB7du3H33+8MXxWTktHbhfWVdLWPvli2Y2c51vtqaTUaz3b1fXX949mXdjbM/sLYfdoJ4lgAABY0C+AtRHQlR0RFHSxDe1uQgggUYllWwnLkndPtSSuWhG/jehQZWa+Bx5qSBiyi0XuIRpWAxj7CbRErId9IYCAvx6AXo+Ihq+JiosDE60FYiCFWmepMNuTcmlc5qqhAHHJmJEkZwXk7tXUhJdbJsTq5AHS5EMm6mqxkFzN/x0SRRAgKTOn4mESVVY08ApwdQkA4d2gL3Ox9NDka2KmMw0LwD6kogNnLz2EIlJVPqgVqxEMQIl20p48GgOGCHj2Rl2zNIZLQoybMHhpZc4zuPZKd68Y3/6vj8YFbdu+I8/Xq+fLGU6KbemjHXNzdODS/v60jV/3J4+aY+fmBuvEnWB3ZmvTxFZShYBwpL3e23uSzX27PZEu+np+oyMWfflcrk1G9mSAsNadlZtx1Z1tTOexxXgWEoJBdQKj9lpYcSLi5ZsIFbxxk553dSf3d+6dPN4NNXC1EbJL99/6G/uVWcvXsgy+nlbou+tLmCXPGlP+qO+iKPLTaye/vzhfNTWu69Wk73ZaNSY+c04qavt5fPgAnkRDqy9RAmIntkDQRPrK/Hl0sFJjicixljRSDL0qLnDIQYlWr+tXhh2VHP94tGj2c3L8oxxChHDSV68Vm0JXuBF0Sl1RK2ig6ZbmPcF5JEiWLJjG2uUvpd6vB3rWgFVZ0UYLmhb0LhH3Lv9btuKNRNI74HacvDNZNvAOGibWMkqITnXJQA0lZ8D7oxh81g6YrmKTFxaiVEVYBIVyyZCQghb06mISAy2gDQSKTKB2YjEgXAESBrSDL4budNTDAMmHay1i8ICuZhND0h9K2eX5oE/TCmxpQiQuBlJlKMQlSi522MkHHpInBjkfkM0OW+HkR5PQ2+8ge+SEHGgHiN/TLnFzNi8ZM8LZLx+yOx0Yaik52jV8AFLfhspHnEuuSEiyfUzaZ9zYb7RZeuwRSIhYCl0DfVSFjmlkl6YrUnmXalPYTbMfPjs8Jd/81GU8Ju//Vt7l/a87/u+T8E3kDhyEv2vPn9RV1cKH3s2EdHYophMHz89OTxKBBYtuJXeuhooq+/9l48Wb+7dunHTzsjdfXx8NmaJzlXMwmuG4XXfrZhGzM1x886u/cPfe2Xhjcjz0rkYlYwXDQW07dp6MvnD7x78v/7kodu7EVcLVKVVyxy9tBrZ+VLWUavC2F5ZxUJZyaa2UDji06edepYGFXBQVAf7dj5f3n8M2/Pzs8XHtJ7h5J3bl8stH9poTBu9QbCjSUu8YtefnoQoQcUcvij1mPveAmCZPWu71p+w7vjO1/Wv7n/62XIp7Wr10rUvvfqlmy+9ui+K+TxGbpjHJjJU+nnwhoX8qPV7B9e+8c3Z6hnGZv8ybhuZBGqIbNJZZKqwJC1jsCxAL9JDQtp6RCSEze4jyUAnkgBOwJKr5DTsVxkauAzY5v3zuRPNphkX9XW5k85h7nwIlAdsNKTbL1yV4XGZInF+m3IPKgBSHuO0hTqZU23kgoS0C5FBMmTKc6UAIGR4aE2HYbaqqDDSPgZsqncZmCYZcju/ekjML4iCNGaqdErK2aguAe6yIWFlkD5hgcRsAE77jmK64xnzl6EvT379BDAUpMzpM46igSC8OOuPjo+ZKUSgKJRtK5UzoWdfVCwWkeK7X5+gOavZXHncx9X65lVz/9Nu/eyYzEf4yh03qq15uleHs4NdeVxXtGwfPqS3Xlm3J0stTnqPGfOy8X7Z66xXW4X6fVeWi3hr3/rLI/vQnrI9je50oZd0vO90XBbHzBL6bTPuYqcssBrY931ofBPbQEvmwLUt61Af977UdTG77Lbf6M1zN7p/CfOHciN68qe4PH26+rx9uj+5+9MP/WK9OHIYl0V1WhvTrBcvVmJ4vyG3pHFXjL0v1h89GGP74ePjb/LsxrtfCgEBpgpie4YwBEDMqxcghII4pgXcAEMtUVAloixSTyyHwTGCCTkaArD9o3WEf9E8+q3vvHXVXj37vGO11LOGCA9tFUGhHeBBa6gHBWiXlPUJckb2kEHenZ5qOLYiqKvK7e/19+7DzchVEHFce3+G3Zf6yS63bQQrcSHWVkXXNJODbQGLpKSV2rIsvGOTaopzUgSyBJajwppsvJx/ToBMMljWKKKAsbb33vsAphiQHHJEVCQwERNnqj4P0WDYxKJJHJR1u6nhJwChD8ZwVssrYZizMnH+vqR3TZlMNEIS5XkTFvLYc8h7Kbzp0HZeRIL1YvU+ZMYN6y4JOTYVQx4wXYDfMkxyXq3kcMS86a+TKWaafyfrnPPAN0iWJYsXdbPPN6H90KQ94tQQ57qAsRll5WVqaRIggwuHqsQoGGrGGENRuuR/4pyTGO/e/eWDh58fXN6/8+U7VVU161ZUisIBEFGHyIVrzpa/OnPltOzD3Eg9svrw2enjPTNfeuNsKMKaS+uN2F6Coeb499/bO9jfWi5PxZjf+uru8TLsbm397OOnn79wpmAVOFAgrLr1jeLsD/7gzrLz0M6qRmlAosEHaMFiebRaLF6+efnbb5/+4KPn9WTLL1sKJbSwNmw5u1546ZgKr5aVoaxsGQm9iApBEXW3wsv746vTSQWuA59h8vTDp6YoKbjGh0bah//57rtvzH73vf21j2272tvfnUz+uG0XbNu2Wf7y7i/PlqtJPelD1fQnAKzr6lHVBWzvLK8djOZnC9v+Rr115Ud/+cN//A//3qJbnzk7+zL7hV0+Xzy8d9w3EtZRbeCJTrarwk72JBzPjy/VbxzYNz0C6NRGJ9wDoFxhIlN3VKJ4w2COyZAOLCJBJQAhERWIguqQg1NVO+z03dxjHYYsuT1IHMUBud1QkYeDnQ7UudbnAuExT0+/OI7Nd4dBSpscnf47qwnOUW4alh0inV3d1Ad5BxEnuiVtKlQaSk5cTP+kqRYWkWR/sXlPlGzkkBRSeVa2CQBfuOeEVPEqCfi8nDgHrgk6bFHTtM4hEyuJ2XDWGtKmUCBSkchqVFQjCGTI5E01CgjNl/F40ezZohenVrx2sWcteuNYLGMsRyfyy8/jN94cOR9u3yk5oPL9bCZNVL/6NHwGfPmtupaZe/pictDEl6z/G2oPWc9U+xMUJ03vrlSNX7LaQK4Vmi1pRNXnJW099PTKDrbL7tTP7QQez08szfqyhA/BWqm5b6NrZOTsKlrBSEfTMqjppO+WvvGt89XU1eWla+b6awueuNOHfiXrwxaXxXRBjItSX548+9XPf/T4iLktw6JjAo1QlW2NUXS+C57a5aScdhAv5KRYzJfXeXKr2qoObvgmqmevTEE5UgxaAJKwDTggEDit9YWqkhBZ0qAkQzUYIEByiDyXpYIAS0txat++9dp7t14/eSwQoaBGJHglAcEDXskTAlEPksGOKmE6nI8zQqr2QBawEBAVAAHVpS+99/Te0QwBMm3tuogli5hqanjUQaxlCAvJOnIZ4LYP+sAKmxzXgXB+k0gMUcLAkmtdVE37RYzhRIyCIkZh5qhR+gjAWsODs3/XttbaGPqNFZRIRDIuSUShTcKj8ypXKUuBL7agmiQ9A3g16A7yKHNznXHe3CJGVRbOL6L5ehHLwDlO8DaxpKhyYRaVa/ZcKec3kDHfhD4l8t2FEDV0x8PfEw0q/0DDv2XrPFFmTmuIUqrlIWZkNkpCyQahhw44fPKM3iBfKVCdU1ZVh7EcDT8DJFM7B52TxM3PaYtCRJm5LNzZ2fL9n/0MzO+8/c61a9dCkLYN1joiTtIpMPfQsXUPnzeTUdWGs4LKSBKC//1vTmutvvTS7NHh6YefL+tRITaysJf1735979J0+mJ98l/++ujlly+/Npvu7Iyu70x/ce+JakvEjCBaAXDrk9/7h6/0yiGeOS5641XJ9B3bVBtGgifm+Zn/ra8ffHLvF89CUVkKHUSEq2J9on2BwjKTDW2AAQyBB88JIVK0Da6+Ur61v/fiED6sl12sy8luhWcnvVWx0Ahx2/jJz+/d3vM3b81az66Cq6tdrkIIztnbb7y5OO0Q+no2+eCXHwAQtM8efn57/6rvl6rh+MV4vXzOpy92X9r5l//uX7z77jtwxXS7Pp28ONitb7y91yx9s5gfPQim7Q8fPpofH914/fpXJt/a5pudnCiNIOqxNGpy1smnKwoiNEBjiAoEiZ4NW0uEAAoZwKHk+Cr5B04I8ZBuzj3dNsL7xBPU4RgTMNSy+RYMS7cG7EdV8yaR4eHn5S0u1K+QXAunznN4vBKTyLD+IV1q2jTkw7dKzp6GKRlupDT+hdfSTOk/t0vPGqns1JevxxeFCHquP0CGoi+MkVPKzJqAPFEXzf70JJq1VUNDIEqGNL9ZlSg02E+SVSiTEAlYEUFgDYoA7VWNwpOsoSvMF7oIRe3qJcUKtoje8YS3gjOeOnAPW/Ln8373hd653s9ucb/m2GB03e9Maqr7j+99bhZudf21vuJuVM1ltLtAnLVSl766xbK37qzhyRJmSZOey9j4urfTtT5wdLLCngXvzfbU94f+qI3HVoKrjCupqiqYOrSGdyn0lyYdeaEozhajSTmeij8L8bQ3XVHby/7S7U6nIoooQDChRRfEOGKZd3FrW+FfcG3sylhGDxfCWl3LrBBYxyOunvuolq2AvEig10ZbPN6R6SwchqIrQqcUwMl0CoGIiexQK0ZNBQ2Sj1dMvytoVAXBEqXJPSuyXXBi9dsquvbMH4wuxWOVhVrjSELUHlBFT4hAIATAqyZf9ZDRTKLcGqaNfJrU3RYwgIVakA3BXn3ta2e/u7v4q+/Vi4UdjTWOyHI/F6wLpplI6EMYuQJx7QrnymnTemamRO8iaBYzJJavDPOSTWqhpAgASCExKoFiDERsSPKgKNWjIoW1tXPrtk2eVKKaUR2R5ICR0GVRPV/QMHxMv/aH03qP9NpMDB68JrCZEg25OveLho0O3OiBTHFhUJM92YeKXjZJ/QL+vMHNhpdBhuJTmwsawL0LcHLyCqLN91J27h7C0Pk+hQ1sfbEiP+dj6pCSkQfGuZw/r+UwvL2B8J1dAbB5JyIh0a8UQNqONjhjK3M6vubkZPHTn/xkVFVf+/p75ajyPgAAGxG1BUNg2EYRllAV9PHT2MgYLiiUhRxD18xl83/5F7/4p7//+lYpa2jpfWtQ23BlVi3mR32o3ruzMx2VbiKLp+1/+vThJ8eds5WQqMDZ0CwW33lrcuVgOj9pKifRdCrMMUREhgF3CKyhsdWkDy2qyd9+7/K//PMX2N1RtATHvQunkSorABuCpt6XwJBkliZQQYHibz5sX648daJksBYbww03OV4vbG2dkxh8j8iT+qMHj9/48vTF0fLex4+B9uHnj9/5yp3lslmtF2+/9bYbV3/27/7041/8DYD9KwefP3p2ehCJadWooBU+2eeDbdSfzR/+5D9/b7Lz8lvvvPnyletPjj/zpun98uBgV84WP/5P3y9L892/9Rtf+Y1vQ+tVmJdcmLD2rIWykB9EN2l7oDJUSchoDF4lgKJqiAJVMcnME6LDfAaAilJaiIRBlr8p5vJXztuC88udVxRdKDyhuLDHns7P8YZpmJMZNsgNMITFgcQ8VKKbl6JBGJDnJrlk1+EFQeenOLMrL8j6NlaR+QpvIKi0QvQcHdcBb9/I94enGPr4dB0VA9eKh7IWm7oWhpkGAzxOsQKZt5hWPaY9LmminbCHqJrESAWUEIkShOEVhrhn3yoa+HlsxKwwGhsslRw8URc01NViMvMQkhCh+skJXbuJ8Z7FSXATw/thvCPVDtuzddvfN91uPLgWJmFF9ibb+YRXPG3ttb51W7u7p+VsHnyQaq1j00A9Lp3i8zE/tBXeb3df5XKHX9uqd6vw6LBtj+J9Mt5H2iomZiIhiGwZdDvTIwT0JFyACsvGOJ5wrPmzdfnZ++SKvauvirUBQn4xmA2w9P3l8f4iHr0I3u295NtnpL5yxUpIGD2krlwDx14hLNZ4lpnS/lnnXr/lGtu2HXq1rcBDe2XEwLBiU5IYxvA9lC84UnDaCpc6NUp7BwCCGaiIIIWtEKTsP/ro02t7IwcTIjH1xKqSs28aMiNvWUqr7NORzIzb4SQakIMStCByqhZiSd3aL8vtW5Pfv3361/8rPvl5ZUpw1fslrVW2p7T245HRkW3vfr57c09QA2CGRg/4jLfk3GYEQsP8Qwb2bupPu9YXhbVskLiYIRbWiIgxrIoYg2HXNM3pYr63u9v3AZl0PIgRsyXyIP4fKss0zMzOWXldZ6rrWfRCp7u52ILBxWoAfzfoLZNKdnvSVM1TAoCSQkc1u3xkNEsx/HKHYJFej3VoHQaS9ab1pFxqKzYxizZeIRk+5gzT5RxLabg1vFD2sqeNv8+FPwPbEsPFB5BG8jRk+iGKIHG0N/zqi0/BbAQRSBk3f3Ka/EfAGuTJk6cHB9def+M2lLvOq8AYJjJKGnqATIyJejdbLZrHiygVVTqBBua+l/o//vT4j3/v4J/+3u1CgzKA0Ntgw9apP3lwfHKwt2fPWtZRx/T+3YcffLCUwtSTEZNvJLrS+D7e3A7f/Y2D1XxZuiKEVe9RWMOIwhSkdyLCEEcWwVpZLBav3d6/+eHR88ZXjnvxEmGdk5ZiFDG9YYJN3QiI0wBJRbQkNIt28chf26kXy95o7AVXdm38dBk8VqvOCJuCUIZHC/nJX/7ZJw/uni2fTrdmVeU++tXjEP3x8dGTZz+JcDx//uaBAnDy9Nq1kuSkovEq9JUQ6xaz+dXTX+1Pxq4p967auij2ZzvXLl9Zzv10Mnn+/Nlf/fLfgpo/+KP/7p2335nPVXBqWCU0jLHBWsnhvBZMZzD5OasgEse8YkDSlg+JssGckxpV0985Q8pZorr5s2mFU9Y5z6nIw5IvzF++MDLefG0z3uXhMV84eBe72mGh0PCec35Nd5CgGlVZBV/opXPFDKQ1CQSoJAORvMPhi3clY1jnWBeQ8fHN+zmHrnOcoGHpS/b1SpaSecGwDDvbktEzBspi1ieqqpL0AgM1w0UMUFYSpJFj/il60jLJVqAgASIhmOCj7YEW62A7nnbWriAV1pa3SukdBJN5aIN4R4z5aXvv2L715ZbUmJ5ffttN9+LRqbfTAuV6vfjImUncnjR96dfuDHUn1Zrc6Xh6uiiO/+Zh+ORxYEutRE/a634stpaYWw6w9hM/2Q2udpeDFME8OPOfW16sOhWzPRvDrIpYUihZq+lkiRb9mYTWh7XUQNUGK6i3SoQ+PH8oiyNBUJ4IGYh3UszXq6ePH02v2fFk7HbfOjz+ZXP6V6U3Uu+A2Kh9cXrWmBpmFHpxzAHhphlRUdW3bslCWFgACAwoGuVgWaJISG0DkYIM5SkAE6sKq4S8dATMNPDo8hHZ5GC1y8XnKAvmztrT1sMYYiBoIFbKrhfY3BkihghhULGD0gMYVsBQAxQgR+QIhWhBVDu44Odcud3v/pPF1VfnP/mzHS/W7J0eNzs7L3nbBhXrsT5t3f4NCY5Yock9RwbHWFKNyV5qgKc0NU2kiFEsc+EKBm18/IvCJlN9iWqNMcaKikJevfXq1tb0IozLYKG8y1N0AGFz45hnpJul9BuKm6Y7wVCBaExBIhXCUS9qDPNnzpzWAaUWiJDScDJJJwKRDut+mSlmICkVAvmGDSypTcOp2WAjx640efoCfnYRkt6UA2ltmjEmf1YMJLvPDBFL9r2ijX9WuupKwxPqBUiAzkUauPjSRJydcHMdwSn3w1gMqg+T2+P8gTMJMSuZq1evWeu6NojA2GTZwUScsUoFYBRaVjg5DPOuntQjH3yl3AVrC+bJ9Ps/f/rNl3Y/enR4vMR06j3ipFoGdn/6s6Nr9dM339gbuzpGzI8Wt29v39wZ/endw8JwDRtUXXPyR3/0ahNi5OiMakuFCQIJEiyZzDTgwChZ2k8fPO788uDajXffGP2bHy/Hdgz0VNpe1PiyiOgTLmqgZtPiCQIYMEbQVw/uLV76CkkgNr36vhr5W1e5rArxwbd+0YTD5eKEq8MmXN67dOPqrb5viELX9eye3bz5uoTCS6h3X4X7BIC3Ty1WDPN80TQrrbiuqpZMQzdWCx9HGKEaL548WnWLejJ+9ZWX7v7qx//qX/3r0PVvvPHGnTduH53MFVoQQSwoKp2RFqJdYucSJa7lEPLzVsGYeWXSA8KWVGJeEwZB7nV1k++Gs4gLKIxiMAYfZj4p4Gg6IBf633wFIhSDa2VCjs9P+AY0GkKWpgS8OZmbHvU839HwD5lqlY54HtUMjo+5NkUmialk+xDVbCxDdD6ghSidz60yyCSabTiYMHiP5LedPlMeClwQwwwfVWI6M5HmKLHxTteNnIWMiAoiZRJYVtIn8+1UUQDMbCkZokSgVzUAm7COgZQn4ABquZlNlyCRvlBvpSt5j3sQx629ObeteKMWz8G+DO4qt03/0oEtKz28F3buiCm3nh4tV/7Q3bgcpDw+mpz144b3ltXe/Gk8/OH325OF8qU1dsPK21a8L2YtX239aW1bLj9edlfndju0GvjzCfy12cvXXmlt8/nRvS2R2zu7anqjp31ACGICEGAjWbaWnVutq6POVogM2d3m44UBonOtUcvE0GbdHrf2kuyXjN7ZS2++F++te3+XbYhRSIlspcQlF5PJ5Oik25rUr6wcXd6vqnp1IkUwAYAjEKRTcsS+Em6zyWK+3IrMt6XBtncjAOfBZ3DjaJ6XZNl6PF4uwzvfuWm4FA6MVoQ0GwNtJiyaGYpIiwc4B+IcXNMVcqqWUBJK0cJQCTiBPWpbHlc8ZgnHe197K06q1Q/+pKpgRhEF2LC1kzA/ml66Vu7srU6X1pSqBERiVvIgQIOIqkTkzV3IjSgTEjdfITGmXh8QIopRyDBxwmQoagBZY/nDD39x4+YrX//6NzovCXxOdhwbL6eL/nOJpaEhGGuQP1NKm8IS30FENLkuG9KBJ6ybAjeBT4PuOo2SB470OScqdXOKpLhPPNG8kmEDlCXycNZbAQM/NPXZw8Bok2gvpt30DJI5lhtPSpJBzLDBxM+ppqpKwzNj426yYWblaHo+S5Zc09Pmm5mYBwFwDnCaBxWb0V/mdUITWAnLLMqA1nWyKoOxho2RzP3KdpjpIEoUR/x43rCtWInItSQFLKsXEfY82Xa/s/+64/sfPJcpm6Adh+LqrtzZn9ZVZdCr0G+993Lp6HDu0S9LM5Mytifz/91vXR1dmiwWx67c8r6RUgzICkVjoF5D8BLbxdqV4zAaXd2ZLTp08eTmte3dyQkMG3W9b4uiC1wquVJcVNEABKNgBqmE3Bra4FA8W71YS2lJmEIgFWn/1p2dEMjYQhh96GI3+tnHL5Zz1gq+7RaLo739nb296yfzErFsmmXFrqfTk6MOAMRNJvWqORvVPZPM1/3E6Nl8HqPZv2RePD/S8GjCH95/aHen335w/4MffP9/dW6yvz/53/zTP259XxF6BA8tSFRETGQEDBDH0G/FdBxSvoGERKhljtDIsCnup6OdLyrAJMgbe5ExlJSfJO2Pz3ToBLKI5glngnUGxzTN60GVhZUG7kU6n4nbtMnhQ+Ibsq3+WtLNB50HBgOyOiCHu8QuTveGh3/dbJFLbz6tEUuIL51/OOcJO2YL2wE7TgY4nBUiw928cFNzWBNVEOsmQqRhj55jXMPFJjsAYJmzYVLPraIIAEM3BZNQSsYaIF57R72gAAVCIGlE2UgL9rDBBF8sy0owLSk4FpbjzkwRI9C5uisdFKtTBD/ZJtc/nHf7M1dMUN2013f56dwjKvGD02eT/mi9bffW3dbxx/fnP/t0/vhFCEZwdVmMcBZ47dCKbRCi3FzTcYPjykbmzzpyvfNlmO3fuPnKK/PTw5OzJ1uVv784nml/aRsV2QJAzOCIsLAhu+on85ZVfXcmpuDFUXf2lKhqXQUhQ+J7UOi267qc2O5FgFcimr769unjFxqW1jJICzJNLzGGNjaM0cwUJaN6/TasWiFUxBJtRBBVC4gGRzY4IGT74IxKpPCc5hipp0j6zYDcUiVGam7lALIvX3vls88eA7MOFcNDC6GeWZOf4GY/KylUo+YDFgf8l9K1UCkEjmEJpaJgU0ZyqA2NMGrdsVvCxMlsW6t+6439p79yZWHW68euegWWjY/9rB7vfb1dWacTQasQRUHaM1kRSRPspOGQtOg4LcoWAGqIQx+stTo4H4YQE5c59Z4pTapQ7yNgt3d2wqabRxCJxOfUjA1RkgGVmKYreZCTbLBoQMHTM5jUECf9Yuabb0AzTWEod7lpDJj5n9m+RoigEpSZ2NiE6A/kYxBBZaBlqKbCPAxRg4aMmn8PxNkQbegaOBfyLKpsrIio9ABZZ/N4S7M2io1JEcAYm7elDWFB0kJfggFpkmhgU9OnCJXiJW8AcWJOY2AaenjC5vFCYE4blFMtqAQFg3WAEDT1jGSYkrAMEVEldQSU+AAwpbA+fMHBToIIoCxCYELV+uXbd658fPf5g0P/nW8efPTkaTt2pS8WIX79yuTmzcnR83XTxmpaPTp8UVbmBx88LmxJNviz9bfesLdvXzo8WVtjtW8JsAm3twzpJDu2RDawBVHwwch0OiNQNdl689rJzx43zvqGJ6rE6KG+5wlJb00h6hPaYJiCCEHbGJ0NZ8tu0aympQ19D1Kn4bSVqEv4StFZ1tLQb37j1Y/vvjien+5dKtheqqri6ORuuw7OzZrmtNrZMqbb238OwHI1cfuL7rAqx0BVuYm1Jbu1CFRke9eVdgYw9i/Pqr3/8Z//26//xo0nj/zVazc/P/oo9Fvj0YRZq7KWGJTUiIiykrIGRZFtX0hyC4jIQVWJrCQZLhkCAlFaIAcoKyLlLZKiIsSiA44TY0yreNIRVgVp3hYKTZvKRFSJVMTkHEwqKmzBIfk6gZFYWnHIp0kEkZY0ZEIhBoPnoXIfzhEwaNpB+XjnILBJ0gxQWhHGRMRKw44QOc+ZmwJluDGgYdYiWcKIPGXKWHBSzX+BgpWjEQbO4uBZMwSCC55b0KigvGWbQFbzxufh5hOYWQQ0DKtEk3RMAPTSOrbwJE7Je0/SHza4uW068Jp5Wco0Los6srGxVxFBVwssBcO9hnZa6iu33nxw7+eP48o1/Jcfhzu2fGXWvny7fDRfH/7Ehp16KXjxq7s7oV7w7pzr5Ycftyh73lli0lJVrDgulQKkNdIF7vVSb64v4lEtYMO274LeePfOlRs3P/r4Z409xj6c5Wmw07OjWbesZ205skWoySKUYMfWY3R0LIeHdGatGm9HOHrKfSvGtXXVsXVsDc0L3372fBUrr6NrLWnoUe3uOX3dH31UsAudeg6FUrAcRMS4nZMz2j6YvXprfRJpxOoVQcMIbNIGQrAPEll6YraAsHI60sib9KwoyIpIn2HFYVSi57MSKGC36r03bl+yZkRapaKJTdH3LQhMFpB0+EUDFGyMSMgz2UTxZRAKhbFUQgvmCeACgWo2NZ35+afHjycH10ZbHGMM6N3E8OWSpFkvHu6apty/EZY+Lis3svW0bOZCWkJFJShFkEl4Y8IviQJSd6UB+R4QlIrCpqTBJi2/S3rzfOxFpLA2xnjjxvWDg4NRNQp9r5CowmwAAZOECAgzITlLAyAGSW74L0yENoZ4iqEB1XSrktQhpTXS8w7z3GkqPwNy7T98NeXlJJclQ5Qa+hijKQo+Z2CnrlR4E0KQ9NyatBIb1ljerHpRAJXCgEgKTJvRU6Z2SH6Bi+bMGe84xwQ1xjg0w+ffO/TxumFZqw701xQRRGJMKx/MpiXJJ5JZJe17sSLJCIEHcQgTGDBpxAxigmNChBCZlKXR0+lZqGwp0hMDbKNASQ1NHh/rOy9fP7gSmzPfw22Lay0XvHg6X759dY8rfPyre/uXty9Nx//LDz9jNy5L9j5cn/R/5ztfOlqGopQoSUWD/IkKMYEts2EOQcQQhJitY1L1vZ8v+rffmP3o40dtvWO5YS4gvWpt0IJEsnsLAAblcsyIF2WluDhrdkdjzz0ZqxEKX2hF0gAATAhuvuhfvf2VO/T64mxO7GJYz6bTtl2rkLO2WZ/5lk5ObgAoXFytHhJNgmegD/Ki99E6T6zWxp29amdmiWXk9n75/n86uDb6vT+a/J//Tx9sTXfu3797797jr73zHedG42kJuLreEomlcyKCWIA0hpCmvWkpH6DBBk3TG4WiV9FELLLpJKDPx4QywAyR1D0iEaM150MRca7o+x5RiDg1mmwsJ9u3rPKnRGWRMKymzjks0wIx+HAQITE/hpPM2aRgeNzwa9W8HSRd64EUSUTn0G7OjenYn5swY4PDpwHTFzO3ptycTSXPSZS0+f8NZYw2L3LOd94AWMOuhwEYz0+UJgHpQakWZ4VCTAJD80HLdDIgWwoJMQSt4xqIqia0obB1+OzZsl1Mb8z8KrqiqtzMr44YvJqUBiOLNct2WqfMKirranz5lXf+tlQv3T/83ivXz4rLW+8/tgunX/v66MWiOIaD1gI+s1sjni6l8FIvHOocOwABAABJREFU7WwFeyaThsfwTEulFlgF03FcB9uWffCvqp4em/sjw8rbB7NXb7zx4d331+GIDyyUX27lWxpehu40Z9PlfHt8VhZhbSyXXEPK5dqeLcjZWMCGyLKWoKymIBSuLIgNiY/LMIqr3hwuqJ5t+3VbB5FiOr526/jscNkFLmYBUFgJKAszm8ymhydbd94qXNkXnrdYe9GeqANsZhiDGYa4M+gNRCN6hRUFIJnxAQsEYsfomYEMSwiGJZLJP8OGYCVEppqoSnRE79fGjIiVSERC2nLFyRZOIkDGQiVmq3JRIsM8UjEF100rrmY7NT33o5k5ezr/rz/5d+Mbu6N66xvf/K2Dvctr8KXf+b3VD/5dVcvJ049mL+2ilr169/Tx/eNHqzvvvLs69kxqTMJde8kaVlX1qZ48x5wuYj5pbdfmokJZkKAcZm7bth7XT548ffr06en85MrBVR8iDQ50GjRfekmbDDih2irISSKRMnRIgtjoDXVIhQQMy08yepS7u7zve6CS5EGRpOs7lM5Dp5j639TvioiRzbBnA6D9WtmcX0jOcyHOnzKpTsFDkYCUZdMISkXSykDQ0GALFBupSR6J5fbkwrvNlMxNnEhGH9gg4pqNwTYVRoZNNPNXZBMfldjmSQlbIYbSMFcwyCvTEjFNoFahgAVZQAtjmlW7aEu7XcZIRilqBCRGGZfV+0+7iruDHXf34WJcVUFgpePJ1r3n/k/lybdv73zza68dN6s//dH9UI9rbn2sbZj/oz9448x3iUPBCrZpfBNTy5PmakwqBFcYEBJqIKIECX2c7GztT+Ozds2WCTYiEpoIC2VCBOXPOn14UaRiDhSY9Xi1vl1U0nlmjRBnuXJWdAIo1Kj4eSMzdmzd9u6IoIWzhkkkNs3yQMUVrNL2AQCMsWXJZTkKsfetF227NqzX0ix906xXzerk8GjdNJHuPX92apj+x//bPe9lb2/n9VffffVmWJy16/Z4Pm/myw+mk/39nW+Jcr1VWMOj0YS4E2VWF0PyABAToiBImtAjfc2m3Y+DKjcV7wMbnhKQrMPMggHVGJm573tjTOIqhmTALmI4w71JuRZC2KgPMthMuTD/4qUgDI/IxuubAvp8GqyUfp0Di2m4m5RKduRLDmYMefYL2TfdqCEla/5XGmYyF8ZAQ97PfycgbmhlOjxZLlUSW+08CQtApElGtWm583hK2BhOw6i0BymhZUypOklXLGTGKgAIabo+sfNalIg9Tv78hzt3bjHgz2R3Z+tg6+CT508YlqCnky0SjnTaAzC0XDZv33n3K19973F/uvf2dz/+sT8p/nO33T97NvVLmR6bk960zjWtERkdYbtGseByqeVCqpbHcy29jsYraCPaCK8IK7Heyip4b8a9/XpHddd8VODWl77y9Mnp4ePHuMYj779yJm/O2AkvQlFRVQWSU1/yvFp6PWX7AmaZ7gqLBAnM0nMACxXVttY741K1atrFodkWU7Hb3wnbo/7F4eK4qV57s7g0leW78sndzk27WIdQt9VW249wdDK7em3nu19ehWgLlShJjase5Jk6QqdoCQ3IE1rIuqJYEnuIV3DilwNelYGQJgsDQJ0aoBQchcBWqoBCeILghKmgSDYYZlEJqhGJiiRBFURBYhLIyBDMITCiBdQwnPcsACYSHbQSO8ODX9wv9rd5ahf6/E/f/9d3bt+5/srtnbenZ7+0e7PZ4tln7S/t/m//0fH9F3/+0x+8dflAa9UFIVREKhqR3gAxYAc2sGxQ0KSpIhAxi4gxRmKUGA2bEGIiVTAxM5WlA0DMVw4ORqM6xXhiZrCKxBgs25Rc0x00IFECy4UpEQ0UDx3a4Fzd02YtRC6wN9koZ9XMX8w3NPM10iyTEkNaMLjJ5uzJxpjN9zP4/A5n45uLuQ1DcX0hz2ZoV5LlSgaG2VrLzMmAk9nQBTXIhT8bcHkocDJV9fxBF/9rgN8pGXki437nug9rLXLgzZUJDRsVB6yPmU3qdCGJxz/8TwGyDBFlVRZEJhal0rlHp6uWpyOwwrKSqGHN+tSa47WdcTUqvvOVl//kLx+1jD6W0sbRKDx4Vnz6+YPf/NrutUsTkVChY+Z+Of/Db+3V29X8rGUCgmMraVCXfSFSs6ZRJIBhDacBokjSZVoRWJZX9ujh/WArK6EzYpXDgElwAiLzZ5bFIwyIMXG+XgttMZi1FBvI0/d+9rkpqrGlakuvXZpe3q6k9Q1akIp2gEqI6/WpKSSEnslWZdnLKYAY4YpRXY8lBmttWZZb2/VsZ2SMYcPeB+dIxATPXdsszg4///zpl+546OjHf/U9tq6s5oXdfuXGN6Znu4eHx2H2+aOj719p/9BW5eHh08mknkx32/WJKaiwzlpAC6YoMqgkFGySVlBS7TvgsQPoOtwPzWSLSKCUvFURYyRiSKZBqUiURHvLp5yZoCISUw89VN4D52LQ+13YypCvoUo2Tx5633zIM7zyhcOfHzZ0vZsiMvm2Sr6eoE0uH7CnZIk5tOQX8u7F7Dv8w4XX+sK9yvrDFBmGJYqbV8inJ/UbeYEbKM+pU4WXXDTJ5Eemjz87FYohCfAWpqCSpFr99Jd4MdfJJJxpNSoWj5eHnzwuqlIWhD4a4ZN6HDn0bDtvb+4fHMruZ2trMH74V5++eNx8Y3q5rfwp7ayaeCNEjKmZumM/jYQjqg+oXnQ819GSSy/jpjfWs1kjNqJrlkZoTbEL5OEa9F6oL95mHIw4PHl4dPbwerG42pgb1kzYLTyYtYBtufRm6uGbGCbVkbZBJsREQoAIRQoKm8hZPvT7uyc3JmrJlTB9WNLZ3v5eebDTT5wJJpTt/KMf8MtfxcvvNPOqmx+2Ui/NyLcU6pntj/f+7pvhlRrHQWZp70HKwZAW1AINdK2wqh2BFYawJgoV1BJY2RI8QIokAmaiOJzK8w4nVWq2HJVRezUCl9xrlAjSM7OhfJqF2CYOIxGzWiAw80A5ZsNjEScoqCyrseokSgWemDDB1beu4+FHvKtlXVk2dw9/cv/4o/G0uvKbtw+fHIXRtoT5j/78/z1zozf+1u2xHdkKGAMda1sSFJzoQCkLimpMq0UotSaZuixpcZCoMBEZG2NgyyrD1nrRKCoK3/so0rZtlJwMBCIiRWGJqI+RQEPeSdMohkgimqtuMNjNvaTc8tGFe0YJZLzgIZ/qT4Vi4HErAJhN2U6sGmNUY/gCs0rTQCvFigsKoOyQoVBK5DslZtIMfA963/zUQzMKhSpxVqNqli5hw+rYEDJzd5KPRzo8SpvtS78WSvIh0gEBTxmLByibL7BGNbNJsjVlknmYKERgJhYhTQZqWa9joZwahqhKsAALCLAAx4jCFCdL6XU8ho1Jp2EYsWMYUGG76qgt1qfdl25Mt7ZGfQOEOK60CUVXtNu1u3al/JM//5XylmOzWPp3X7Zvf3n3cLEeGeol7TbhQW6uF4oepbzMGKoBMEm0klxcBO7Oa9vf/+Q5Yxo0MlOnzPC5+cu8xUytYeYgYIa1YbHmvi8sl0AhyoXjk1CsvbN975/LBx8v9rfDt756UKINfRSF955B1o2sCctlr7LoexekA9C2fjzxRKQabTSiFbEQ1szUdv74aDHZmtbVDCYAYXt25er1axI4BBV86exsyUZXq1XTrsC4dHl3FX6yszdazZcTi/n86IOff26L0dtfeXM2Gy0WK8NuNKptUTArICxWSQCRuFlZnbOvZkBHzDnBXok0SfNSgrHWSIwJRFYghuCcY7YxRmiyFjovhVW/kCCHvL7JVkOm4uE2bbJgEtulBcR6Xnj+N8DSZuT0xWzJPNCXkcvadLOIN1YeFyLBF580A+bDygj9wrMPDlnQC9K9AY4W/PofhuT6jygVpsIgZqtghYBM6vAlyZtIABINgdQRe6md5fWj5fFfvv90ZG3bbq0JBe599Pnx0eFkr4ohsmoQYWA12V23i4PJ1ru/8/u+mT9tj9BWP7/3mTTyZbk558ULsZcr62v7eN4+OJoqu0Dc9XVk1wSs2J1h2qvlVmxv0QRtoA1Ry9oyOkHg0HtaoxAODnsCfHz32paY3YqDDdIvfQMPKcrW9K1UjZZrrixq5npUNxQRRNBD1mS1sH2HSCGY2pnn1/fXlwx74a2tnUu3rVA9MrEeL9k2/kXsD4tr+/P5akWP3StfbR8/X99/uHP9cjxdL9sHN3fHr70y6uVYKrMsyr4W6oAe5Ek76AooQZaICUXebqSq1BNaCy0v2L30RCCK6Xc2BJNcFAIMFrvuO0EoxyUAsFhn/dJbU/iuc4VhsiF0hlmhEjOJ17CNGlVgjFW1URgo2ZVSQeuAMdGUsUXdOF79ynX3gZSXZSUd11sV1RA+7V6sxLudsOJ+FIt20VRbNz87eXrt9Xd1F9qIGoIY7itJSzFFIGytEYGSsUYBkrRd2rLECKgmyUpicJgkg1CRyFSIRlUlxmxndz6f13WdTIkS2dIYBtD3PQyLgqEySGlTngppoElUFAXS7moBVDJCiyyWlwFyvrCCBQlASlgVbXgWeWJKFx+WXSE30iGCRDUmAU8iCh5gtNyUSzLDVuZMg0/1d7r0OXWkRaCcLfGGQAgCGTYxCjE4lc8ZHZUUARhpJfAgaFbZnKiLNUSKEYnsIiqiajauYTIA1ch2Y+epF7kD1k3XnjC3jLwlUNqmyJIZbcpEhmFASnBEYHKnTWmohBAQkOzCDSOqwqOi7/+NDy8WZ8d+azb65Wfz0VZZcKysm5/Mf/s3D370/vFh5+pR0fT9rGx/99u3Fo1x1HdCliGQQqwa2RB3EritymwAmOTpSoAxAJJVr1l62b+yfefyo4/n3hXcaWuN8wGWhgXKSS5AWaKiZAVSFJO+iz4UhkdRCb239WjbjCPVbiSu98r88NRvfbj46pvUrL0AIWhhaL30xAHsjLL3XYwAUNpx8P1Kz0AyqcfCoghRgkDatnVlWZY2xFZCYLZNPGvWAWLZhhDIcgWW2fYIIhJhLfr+7wWRtW2Zm9s7t2698spHd3++Xh1x3Ds8ujvZux9kz9A+8yVrdpnH1qIouCiqGNvUBw+/XGZYNhANqsBQlmVcR5WyTW6yf5cY+62tyXK1kuCrqhJVY+yAPyf9PWc0WS8UptnGMlnDpsOe0/M5YpRXlQj9enLEr+fadIEuDIaRTOpSx5tQnqRX0mw9iQvp/7999g2eBZz33PqFh1IagSFvLc0vmrmKUMAg19rpvxOLAiJgNiAeyB8FYBIFg/NmB1ZlUlIUnUhh4b1f/9cfnRpe2XH7+fH2bczn3cfvf1TBYCFUIQbhiSWwb5pie7L35jc+etEfXL7WHFcffPDDJtrJ5OZJdXbqzAuuxeMw6CFmC+u8TE58c0W3JJZPgVZq7dE30ayZ2yiN6Ep5zbwmXZOF6ztxvvIxBu8h7Nm6Ebxn7lWahhyYBYGCHTfBNzxu0ZwFp3DAuKyClUDKCuEANsoeMbINCPXWo1cvY9uVMfpRoHI2Gn9Z5NRvV169nXG9c20xubl4sTr6xT3/+r6985vF6i/2/JPJlI4PX7x37c7re/F48TDYaqplY0o/KsK4bFFpRzgDLUEOVBAaZWK2pIVSB2FgXaoAaFPtlArFYYioGVODKEI6nVYgVeWsMyEIW27O1n3rt+qiXXcqbjSyLGZQ8PEmfWjayAXLXIk4MIUy2ImRmrBFsiU0Jd43Ae1ydLwGX65DQQ+rQGQo1h3Wj3S0617d4+Bw3C6WR1geX7nzOy2TmRluSER0aRAs4DgbUBJxJCQfMC8iRAIha0zfB7akghiCTZOkPIoUYmVmWGbwk0ePDw4Odvf2ut4TQaIMDbSSMSCiND/P9OJcwEOhkDAIsoiTFMkky2QeqmdW+oJhwCYxbxBsbOr7jFyDMlBMQ7N7Tv9SIgMyfAHvvzDcBaW+U9MU8vxmnwNsuc5ikKoBiE0KJnmVoWrqKKIKZfpYgppTOklRLK9bhYCZgkQMPdwmUF1smBOcmD/8wetDkVFuDNtUiYh5Q5qzEBYBc8EgoMjtL1lFQSBVw4Y4WpBRMqRE5AybGMJRU7pyR8mzImVBYwUiQgL1k4l965XpTlXtXy4Otmb/4a8PGx4v58d/+I1X50f+7iM/3SqDeOnj3/nmfjGZdM9BTtkEhXVwIl3sM4OXmY3hvg8h9CzsHDEnAy/RZMIKBqSAD6F6782Dj/78yWiyI13gAGstp72VoCCWyakSUKSfEQIytSCsWrc72Qq9MFfClsupNCJ9JVIBKMu+CZGlQiyYpCpGVcEhVkAAR5CHTME+Rfi+b0R6EZrPu6qW2WyLBVGCZY4afd+WrjJwfWgJViFEPkaRwMEu0ViPyFxYp300ZP3Y2q165uNUtOGievedb7XdEaKtqtsoTAwnQT4J4a9F1fCMcNnyri22J8UeGzbGETNIVKOiFwjUbEY65yrzZGUAMFMIwVq7t7P9/s8/XC6Wnz948JV33rl1+/Xl2ZlNHuAb1Y3mS5EpgprAMN0YRxMNgmLKGNIGxt1k/c2NSwd08/fNNkylROI452AOZzt3skMvnF8xtb1fyK8XQaMEGF8AyLOST/ND000UHqZClF1slQA16WprZrElfIhjfjYDcHL6ZM4jc4JJq5V0cIExQkrMRhYf3Ts+vl9ceuWAhJ/N3enZw2dPm6eHbmYFTEHgrIhQCD11X3v726/tf/WTw3sL4p//+O76ZF6XrzZ01ozrVb08Cq6qzaIyd++2D1ajWDrR3ZdRr/rGe6m8+i5KJ1VLaKIsYsJvueOwForRCrRoDVCwDb2wX4fWaAG/FONEe+LWUqPryjo7WcXlispSRhbBQU7Rz6p5ASExplehENWEYEqPJ7Pp/PLYjghiqIyxCN2WK0ZXxPZ11dlbbz9e8+MPP17JxN68s4661/xy7ys3j99/cKPvivDk3Vvv7raPnfZexp5dy3WrzsO1qFbl+Kwca5EQusxGF1Yw1CSzOCHvBjQwndEwhP00GkhmHTaVnRaEejIiYiWRKK60VTFCj3qy5btWojJZ0TD80pVZRfIegtNFY21RV5VUSjVi5VGzmRpMlS6p7vTPjx/+H/6H37n3wY8PP/75pCLHpotrp5MrB5NnzdFZs2zdHnbte7/znR03K80kHK8xsQqgFQ2M1YhpWB6ASJQuYT9s42aAVKKxnCFZ5NVgkqqMZN0gKkFU+cre3mf3Pj06Orpx42YyvASQ9cRIi4mIcL5oTAfKFYiJ05Nn+S9l2CoZGw/spJy4aJMKE/Caym4emJbIde3Az2Kkadn57RWoamb7pscjc7N56MuJkLKdDAXxxpUeecSfCiziCzwTGvL4BivLCTX7bCiQaOQ5gCSP97SLcbMcVS+07wpoztdJZpWXHFEmfig2TTM21HAaPuAkVbTMvGl8BxPTAnAKIwCoSAbjbAqgVzY0Mj2vj+3aXrok6ZcSwQztxVpbQM+a4tWq+s239+4+bLoVffrs1Jpa2EZbAaOPHy+onkDgg31pdvbl128cz0NZMwSiVkgjOrWmAMvwhw0n3tzw+cTBLizjSFCwLRq/fvnm7Pbu44+XccsZYXBYAhNCCbYEa20lgRQFYJXZSmF0FMQverk8sqg8YMuJnR7w08csFSBkQG1TrispRnUVDCgCvTEKcSLeWmUOITRMBkBZWOKtrm0UQRCYkWjMRAUzNU0rQb165gAWkFiqAAnBg4IE8dJYC+aaaQREoFj3PZHPrhC2Jbgtd6AUCBzjgVFEjSH2vp8rjhSLrn20bu42KIlGlrcLu1u5mSsrY5xlkIGqSBwM3olEJPmDE5GCxnW9bps//dP/VNf1u+9+9f79X+3v70nobVGkTVmqmrakJLHDOQeCN1k2JzrdHPOsD8b5TCcnu3SJzrvenMnTBU+ZckO9TIgQZxF8Tq8ywNCcr2q6+blpHhApGizqkEdHSRp1nqQzoyIhYLKRMWXTK+ahwVbkUciF9t2aQrMtEjMbgFTYJPQoS4HTqMoQTIxgV/qVPbz3INhq2R3vLheX5u2z/zy5d3xqfAiNQ1CQ0AgUsF40t978St3s/+R7P7tx5+bnH947evh8VO0c+XhtUjQGj705dvXtm+XDtdw9kaWtmGQShJs2tD33hLX4Xqkj1yOsgi7BnrGGWInbkb0qAoTVUwwhBmJvU8NbSAEf1QMuxg7cu4bDmCbz2BJXworggYll1NXScVAYNYoQKIC0fHRlS6+4MvJaWl9GVxoes5YwZUGVbVwhPB1/efdsDjsbXZ2fTU6fmqK8cmPWHX4yrZbv3ZqyPK1JBYtWyiXXrZZeixajmiclpovt7VBYsWkVkYpoEroD0AhVxTrJ9hRQEEQDEDkRI8BAXoLHbC0oVrWFIUSBZe0DEITIFKaiUSJCA5QG+6oSwaYoJbaGbFVNmUeoiCcUSuG6oi0NWz3vUrFfvDj94PBv/vn+9Vu//fZifbU7/PTo6LDbm11eLg+nYVxVs8fzIy2aByft54/cnX/8f2weRYlsIyCkniFAD+2dQpJhpyKALJMQF6pKmvyJbGIpK4SsiapJbsWGlUyUtBMNpHy2bG7denW6tRUlAhJCtNakO0HEnLch5CF5lMhMNDiZpLqSgGFhbiYeG8sxBhCLJB3AhVkUshVFMtJKVweZJnHOKqYoOV2pDvgvUorWgXyRBY4KgaR+NDWvm/SmAoFQXid6XpGzDpOnpOXKJtjId9qem9SpKjMHEQMCksf9ID4GooLV4EKxkTI3M5Fm2ouC0oYlZqtpMKURw4eQP4e0L2so5kGWiQELMiQGZFUdYCEOsCDHbIPCOgeCjBLoolxj3WhTVZMZQt9HZYCtBokOfYhRCuZjy//xo+Of/MXDr33lyueH0tJkIm3N04+O/JGYkkpfdHEZvvH1S+tQGVqHEJldHvcjEjSlBjAxcwhRAVtYZhN6n11QrSEYhXBClWMUjmtf/NZv7H/6vzzX+nLwQTFhKWAKwAFG1QlbFWNROVCoy66MbLktsHW1CEu/1rAaSVUxdsCF5eCDqFjDtt+9NhstfN/bbrWU0BFCadcRAWLHda3qAdgCIm01Tpy5GGK37qK12fwyCdGieMOWiGBtpMYwE8OCReC4NGxURWJHTL33RFw4y6qpAAbFLiyTV1qUACY2piq4rPaIrqiI1hFAG45DWMZ45vsHzeoTLF1lty0qV01cVVuumB2IiRSIxpC1Bgrv/eefP/js/r03Xn99b+/S//P/8X//9t/+7vZs92y5ZLb5VlHWQRAPW4SSeiCFPzl3qsro33AXUm4bwOQ0Xzq3rtzks4FyqMlcJodXKOd3C8rLGBV5uy/pINREYpcNEmEFmXzvLiDPw2VMhXqW8mbciwdX+3zDBotPM8SULMiP+aWYlZVoAJwNwAwGG4AiMSfmhLAFS1JZsw2xDMHwaPS8Xa8W7cskno/uffCzxXTCdoRVCME4i95EimE0mr50cKtyo91Q3/vxBw+e3CuNiVARnV623ZofPquBkbX29IVvjn0Aj1RuL3i3i9yTSPBtxZ2vIvVtoI65syCWHQgHBPSzSxGFDWLVxWdP7BmxI+kKNqJ9kEDcs3aK0tC6C7Y8K2sTd1fauWCIW5bggMgyLc/KqRqIiEPAMVfL126ZmV01c9+iqB1NmAvBOMJRZ6eraJcY99PZ1piq9RGap4U7c2erUlw8uPzOW5dubPmnp8cHzAutXNHZEFoatVQVKiwqoACeVzOUghpoQR0QoAkRcwSvMCqRCMl+JzJbSEjjmORRKiqp77NuaicHW5EjOUYPMEG5X/tCrC1tWAdjK1IE6dloAtwkBsOVqjg3YR4HF+FgZ8Sz6McROxp2/NU9//TnHy4/ePD5g0/a+vi7b1/57nv6y/dP7917dG1vtLf18qI/2hrLmaKe2evXJ2Fxj3duIUYJCsmUM2qhPQNsqYCygFIcUBWGEJFNA05OJSenm4VMGkouOWndQlTo4eFh71tjTOwDM9vCBu9tYUOIheEocVPBbmpSzdImXOAgJY2fkiVVCUGYEyCMRDORjZFWou1kBnG2vNChp9ZkA6XAuTwlA0+aJ4UYCJASQgbWmNMANaFoIB7K7USAvHDZcyIfEjCdC6KQ3w8oCfiH0ZuKbrbBIIeFgd7JzEMe1QvtfeKy5kRFwGCRm51LNuaYKXzk+Z9YyrUBAxDlgW/FROd9sFIJLciQrYzagIJjCWONQOsJPpuf+i0rWxE9G056UVbE4MWQmcX49ChcKekP/9mtWTX5BvP/+leP7j23dREePltbmlju214vV6tbL7/SdJ5BRJYoq055GNyngir5dJrCqqpIZGPTY1I05kE2KrFXZ5bSH1y58e4ry7963FbjquidcCFaiBqmKkanaolKLSmMGNzZymJs767Dve8/WGsXsJa+KEYcatPCa21LYdeS4Vju2FUUp45cjbbyrWcaTUe2axc6LA0TCVDHWahLriyYQrIACCEApIgp40Klj56yzJ9M3u2lCekRDaxsC5YoofciYgtrYaLEPKQACEGUNWpI1BAFG6uIgI7cLpX7nKf+3kvj/UJC24bjxfEhAMBa66wtGbZtu8Xp6enp2dOnT6fT6Zfu3Dk+Pvn+93/wO7/zd26/cevkZMnGYtgxxswiuqE9b5JnRns2Z+0C0pv92PMt2OiOcgUIgDLD7tfmR5svbHDsxHhSzk50GFAwztdk0Fedj4KS4o/yTTyvFTb5GAPaDNUUkZPdCVFihaQyncnIcO80s5qZwEpJqmcG1YCV9HVhY62KAciSBbGSNWojuNfCWubKHLdnrx/sbp8cn27Vz0Y1EUsQFi4MRRHh6KFfuvXmWKZH95/t3bh+9+HH8WhR7W5LiF17NrlpPvqlf/wLevN1R0fNk4fGn2xV8G+ssB+7rifnmVCv1xgHy8GKZ2phtfe2Z/TMpXz399wrb8F31rrw+Nj/6b8p1qcarWGDYLXzruFgAwpbtLb3kBUaM6ssW+kIJyJjZRYttrRUlNNqVRVt7ONI9cH1G+1rO27tl4Txti2ntoW3Y/Z2vJCi59E6jBbmUtH7Xbt2o9bNYHxThHXbPpzy5PLO7rRbBGZGKHTU+ZHj0CBU6BzVhgAYge21PBtV1BMqUEcIEFGU4EjwQA9EoxpFVYgNgcBEqZayBFH0qRGyl27uuCl5L8rgio23fduXhQtNiBSYiZVX86UGGk+qtvWAVJWLoQWcKosRVMCYpCSpAm8RzYrJFOXywfMP/+wPvvGKWT0Nh599/J/e//o7o1cnonxmF9Icfjg5eOON2dVPn59Ky26++/LkreeYH0/H1JMGcAO0UKdgQbBkRGFJOU9GEsBCChjmlEo0ikCUCURsmJB6VkKIQUS7rr9167W//PF/ffTw4Z0331w2rWHYwkoIzBxC2Nw8zms6cylr2WyyjgwUNhA0Zt84ZpvsKSVIlMj58TjHnDQXR5kzMgSHVD5TwoiQm2cdquPNFIiENjpFnDe4eSOCDjrpEANn1Qxp8o7IQRkXRLo5wKhqCD0Zk9B7TauUE4yczTTS55txP00uJTmIpdxLiqFuGDic+aljerec7XkIACOtoFAGMxOLpgUFFpTAlQKwqqkDdiAHFHBQp+rAVbJZi1qQKPMkPgqdbo8xFg7WWPQiCIbEiwP5vilKVzdvf+VltOH50+XE2oPL5uPnPZWjghCDWIt4HL7yzl5V8mItrrCqMRUTGUIQHUQmlIDmYdzNSfPGxuAC74YIpigTzbHx+NbXr3/4+X3FDI4lGGZHUrIZiVgyBg5SgmtYx+oEYHa4OaPZ7i67UMH2Nqzb0Cz8k2U4nXsvMBMTK9aJIYmucIFld7zV+9iuj6azPd8uo1gAMTZga61K6KwlQWA2EnsAhS1m29ttt/a+U8S0m5nYEGfvl9T7B+kJnEWmLN57EIKIIws4AAoedMAwhR2KUgBgY11hQdyH3loJIRCzKjGPtuopACaO0YOkj20MIUrs+9i2XtTMZns7O3tdtz58+nSyNfnHf/yPy6o8njfOuRAkbx4TBbBZA7ihqdNgznKe+XCejBN8hQF20g06lBFq3QgtMNzB4R+HdYCbXJ0HzMMTbprrXGduioHc6ib6pA4OrJsMT5mQeVFdlNX5g+kVYTMuzrwKlqTxTZMqbFKvBWj4CwNWQWBLQlGNpYKpCDAKg4KVjPQxjjB9+fpvrA/HcoIyPNrePrIlIxgxKhKCt8yykBu33tgZ77lo9orrH/zwg+OHD6qS/Ys1jKsKOw7y9AODOR/9Kj74gNtW90P/Wu93QhTpC2+NurOuLbyYwAhRAlGIS0fObMOQXJrwnbf93OPJw0C0/MlP3epEYgEofOMFZAGppQks6NVbIMwQSeZbhUoZMIlU9TIPQORRJxSs2WIbi6avZotXb8kOSdltsyPLHUKg6qwaL/qSeOojGjurZTHidhvtyK7He1U3v7R81OBoxTN5esgnthlNQLBltbTOW0iFfq2lVU8aFBLIeCr7SR2UxQs8WJgBScsCK9JAFER7CxRAr7CEoJLXshOl5ikqsR3vVR49RjCGgxdVGDYSJfgAGIlakLqJU08iZG1FCCLCbFUtUaUl1CmPqDGNKys7Y5321+r5wx//5yv2ZLw6Xdz/4Y26XS67j/59O9t2l0fbW+Ws2tqay9zoYYfWUdU8+uDZ+39x7b3LTT3pPetaUIMaUqdagAKrMrMVFEnFLKBE/wOEE8AWk6cSG06ywqROEgGKouhVmLlwBRS7u7uphE+THmarQN4clS6Zgi9IBYatR3kbX776RDIMP0ViGpIZwzFKbgM3G09zmNZsYrwpzNMdFD6XuKhuNJGbTJlysL0QdeT80m5CDGgzLEre2MluJSHEkvhQgx7pPAowAzFt5N0sNBVJRpKkw0ok2kyUaQho50zvjQgrBxjlQQk1xI8Baqc8ImcogwyBVRM/04ItUJIawBEVghLWwgElUAKV9EVgx1RHNUwM2ZZHNhTXCxSBIqtRlagCDkoRsed41uDa+F998HS8PLl56dL9RfvpU9R7NixiFHbFlg+rseM3Xr18tq6sTYt9kNXOWWg+BGtKvjYDfztPbvhCOM0LyEjZx1DZuu1kd+/yt96Y/9mvYjUpBc5gBJQxOpTMFcQpTYgdY8R9GYjBZfj2794MvfZqYD0JiB1z/BpiWIR7D5cvFke0yyYtj1v62Wzr6aePfvgXf+nP+i9/6bW33nqjXZ8BsNZFaYBgHUsc9l6DrWHDzJys1433fUohzMYYLgoHlRglYTFRYgzROdfHINo5V2roY9SAkJxIVAUqUSSokILAyewM5GPlClvYooAKTDo7ClBMLHmJxhoGFUVdOoDYGL5y+RqxEBJXH8ayCNp12zSdK4oYY4JWVDXdr4R3nCdaHkTwenFTKW1O7IXUmDvW4S/Z3Z0GoAkD5jHMmC4UF+dz1+F0/9oV/IKxZP67KNK6sFQjyyD1T+XOr91iEEElcyIBUEKI7PCEnC33lQGjwpopQEwwRCa1vykxExcSiNkSnMBqASZEKz4oVdy76O684p/+VXn8/GS3vs/MFaOPEYoIVm6b9uD69du335xM6vXz5pcPHjx7+kuGD96xCb30k6l59rHOnxrbuuBD5enVZnE1UFD2impyEELXzk+UR9P9l5uluKs36Fe/ondfrl65HWa161arH37fvP+B279sr15FtcUfPxi/9CamV1bf/6+2dPXB7W7+uH/wg9HLL8cvv8HNs3Dygf3qN+X21eUv/oKrcdyb4umHEYhwQU622YlwRAWp29lXHm7dmDcyrrYKKwiYB4abBF8vtejdqNdqFo8m1MyMd7og38czrrspxjcWz7r4pJk7/MI371yrrY1+RWa6mpRrxsRybdAzqYJ7uJZGTVgsRlMesbQSfGDHcEwlqAUVIMeqTFIqEUPz+qLk6ZzOGDEgtqi57dvCOWExBmoR2wiGmxbih1OSDBUFaNmwE3hViLJQYMuoEJ1Uu5XZKXQSd7jZpeMP7v7ldv/wMty1KZYP2smLcsdty6kxy9EEB5fG05ktWg1Xbrtj+Mdherp+uIujI+HjrQM0hCVQAQ5UMSLEG4m6mZYQGyClWpLgmYmtBZFIDInhY1mDnGcMpqKwq6ZZrxtjk780RYkm2fEkyloWamKjoNmsABvK59xcIsFdOcEhxigSkRy4+CLGtRmZ0kbST1+8urk7zPE+UUJymjSDb8PgypMus26EQDKIKlJ+M2QHpnEyb09pY5ANp0iD7GZLRNZy0jvkZ5OIzCXRNLeVmL5n0/puGvvNJolEw04057waOgcbynyxVBsktFo0cgbNKOUthQVZFUeUsq8Dai4ZFVBCS9VKuRKui+CgFbOzrsJROz8d2eoyUYAygohCOUbuGQHaguoyLMMre/j9d96ZBPOjn312dxFKYSMSG5WAtrNv7k4vXdp9dtyWzgmCNSQSksMZNKbfWO6GE75eWAyenRfiu0ZNfAruQcbWEMsGiyV//e1XPvj0swZjsItSMFfihGtoDYwIY5KRwMGMnHFYqz/idrTrVn0LZmYv8CLMzlQT/tL+vsi0tT0j+jbOdrfuvf/JD/7rX/yzf/pPntyf/+qDX37VftWHFYCqqkgUFCV6VxYinUrHieBPvWo0xtZ1XY8QYgghDgdSibhwJhGJCy7Sj1mgqKqKCDFE7733fXI0NIaT5UYfAlPa9ZmEf1g3rbehsB5ErijS7gwV8bGzNiNJoolTwCLBdwGAihhbQDXEbH3DzNkHngjMGmOa7CZKZt5ocgF+Pj+e55XiecP5hXr2XN59kbdI57n54rVE7n15KL7l/AxcyJtfzL6b2TMRIJwXjuYqIUfgC1Lj/DLJLoyGQXUUTZJ6ERBbpIDNRoWJWIihTCBoIuBS7oOJQVaECcbCReVYgC0Zg047Yfi6sjA0M/z1d/s/f/hsymeVMyFqaSRGCWyJJ+Pptdde80X34NnhbOvK88/uh/WyHNngRWFNGZZPzOctVG3he+tkf9HuLk0LQAIf3JLf+HuLH/6AlydX//4/a4+betLym7cXL47Hb7wbnZXjo+UnHxRXdujSNPi2mGyvP/1YrCnfencZyL7zjr10g6fj+L0jV1+3v/kPzLX99eNP5Oi+u/q23Lzu1y2/8VI76rv/+fD6b/1R25/JRz9ieipPBWYZ7OVrv/s7713a+vDBycPj0yDOwoutA08XUolxIboJjifUTrmtwoJ9oAZxhablkbtE10fr0NGx/7hRrPuvXa6rKclpkBp1vbTwSiLEHq5BW+q65rFH37oCBbhijqwFIoQNsSUqQBESkvcCJVnLgEOGYVUGWWVRAzHCliEwylqo9gLLLEZtVIEa7dZdgaJwRWgDENkapqKNvipGtjLBBapUnKqT9vizVfNYVk+39Ozk/ok786v73Uv1DbuuH372+Y3rs8MX79/7iUxvHJhdG6cN7+nh8YdX33ulhLeyNC7EitURlQQHsgQLDUbFEFuVCIRUrYr0gBpm0ZBpjmCwiCJKQgRIRDIWzTg6OrLWgpJVjzJlFmVq+y5e0AvYKSHbECZkmDSmnlgsGyJEVeZkw01JHpod9fKlSnV5xqo2rWSe+SbfnNxsDWmbBqbIhWt+DoWBRJW+cOGRGtaIAIDBaVlyqrEpp/VNVBmuqiJ1vSqkg+PuYI6f30SCz3jAtXOwuUAfy2l3MLTauEykDVDC2X0+MT9FGEqSwn2aIICJGWqBAXlGBQc4RUWoQTXxiDCC1tHVjNq26rcvlz/96Mzvj7auRI1ITUMSO8MzWqVWi6CdhO0b1f3j+Z/86d2yms52R74JQYRDEQlYrN5761rri7IQlQBAECQttiIwjKBHHnzr5peiLCIZQ09gtaZqBCzKAi4ii8KyC1LYyfTbd07/7QftZHsniEENU7HW0Bo0Zh0p1aS1oVpQIQY+mypvCxthMQIrFi6AEb2Hb9tp5YR1tFNqxx/86K8/vvfxP/rf/+PZZPrv//R7r77yKgrDXAOIwWtaus4SxBsqyKhq0OwWsNk3rYYt2bywllOZxSQi1piEmibSOxEMG7YM1d4HEBXWJEW+MRZtAwWRFNaWVRlDXLfrKOJ9YLa+89a6uq6iCigE6Q25tCMo/X8IPUAiEkJkDnVd27x9EslZdpMEYUyyMQ8BzOmtZo9SlbQqDJvdpRdTY74d5+xofBGphiYVYqZh5IuxMQHH5ptS9kVSNXxBNJhJGIPMPfOlNzQxGkpw6PD4bFTwRYONzY02qeFPliGaLF05fRSUMLvMliDDCXNWo5p637QP2JISyIrYaAUlYCI5g7aXwvHEIAClTL50+/jR7cf9k74m6yPBcFRDrm/We1ev7r91s2JeLye/+vC+l9OirPpeil4ksjpnNdz5UqA+/PhvQnFcTfpoA/cUrHC4cSALdevtvTf/WI9X4d7P7D/8+8e/et/t2H6vkuNDloWcfWJefctemYqX9cmj9hd/Pn7znWYW+LDhmwfSITx/4h/fn/z27zYtuwfHtjNNO+WF7z6f11e/DJLjP/kPozffO7v1G271rBtN4vFn86dHp5Ev/d2/P3/pzdrr7Vf2Xf30Z4eNJW7tpBXjUQJ2Sqe7tJzq2VTPTCvaGn8a7ZJ1JWcQExwL69xYo/ePVnwSf+PmxGxzEFYJznmu5qQxAA2XY1QdRo0UTbnFI9ZOQxHIchqcSVBZp57HAgr4VFkNJKx0VJkgdtk009l261tSYWIhZWNE1MAKC7MaTohHFxELFF3nq8r4tmXrprtbTVyriHFGLLjSSGFivS7XYf5k/2C1NxNmHr998OJXT+J68uat+uTomPsxXrTP+4+rtSuDG7n6629cvf3unU+b06nbXsD3poLVPOawgAUpq1KaAUOZNq5+0JjpGVmzSQNHI/G9CSQSY4wiWhZ2a2srhLAhGiEz+3kY5WGw19jcveTiiLQgjxPhIr2gIdHsD6Z6XmbLoIcfAMvzwVKm9mzc6AmZwbRhTxM2/aXmxDogaWl2QBAV3QSR/E1Dq7npUZEJ0ol18oWKffiPwa4rr45htkRJgkWZgZWGoYlKndaE0xefJTGrTfKXkFy8SM78IUQefPCZLYOUmIjihgumDDGAIRjAAYUSqwONFCPVGjyB1owpY6SoRUoUNUIdPm7a6WXawZw4CiHCKBWqGhytxrV61mVXuOKFhDduuD/+p+9YH//Fv//cVROOwbDxx3pjWuxd2fPrwDYmY06RJNhIb40BFgmbD0sl2anpANSnED3UUsIAO5APIGYHG8Us1/zGW68e3H9w2huuWUrhmrVWGauZMo+IpxIq2NqgYqvQ7f7aa3W7bNUGExgWkYT6sOZptxTfLhoOh4f+5z/64PDjR//kH/13+9s79//m8alffvnrX14sVlxYALGHtapEqpLs0wEa7JRtFJ96S6gnJpt3YORIgOQzkho6GujBadWOMRZuVENErEmseyGFK1z+vJidKwMHYhKRoijY2M531hpnbSCUphTAkAnBEwEwIrHt1pspDwkvl4GZq6pkNswENkmtkZRgxuSCYJP4MgsxTU43eezXsOH8Rfo1lPi8SR0Ap/PREJT+G3h4uEME4uStzhe+nMt9wqBtHoiVep7TNycrfX+6gHRBLp8+csplOgHEZDRn4kT0S1orKLIEFbAKq4lFoTaNgQmWYKOyFIKSbUFSQMYUTk5DUdnRKMTIE1OPyu5vv3vy/twxZKR9Hww4+G7/2tXZ3uXPju+/tH/16fz53Yc/K8dRBNTbSKCo0sq49K8W1eG6nZ64NwIuWdd7YXGEWMnelu50b7/l7/3EP/jx9B/+9/2NHfnF0fT3vtpfs90koLc27MmBxaU1irGbFO3J5fF3v3b2eD65VrePl+XYnS1PZr/zbXvzlj1cyH6lbWsnu7661N07nL5zvbn3uCr2yjvffPZXDyav705feW8595Ob39759lv+2vXTpp9LtK7fu7r7ZjX/2YPjx7ES5xD4Cs9rzEsst3QpZ6oroInV0vqlyBIuUNDAvReyVYmG4r2Fr0Pz9quT2AfqwSM4hGm9ilo0WLaYtGgqKawtpaqoJhIiT+oJPcirWtEAimnOaBks2RMUGP6iEFu4Qgl9jGqJDRMRDCy72AhbMs70q16CuMo5OIpUlC7GABCDgkQ4RI7GGa5YbZwUcmtv/Mn3Pri5b779zsvPPvylK0bd4+6me+PeRw8a8lVVVa668frLk5e2H7afLuFHbvqd77x74mT97NTOlgV5KVxqfGFyu5QSV+LZDysUBlEB5/0yMQql3X+sacSa1asQNqxQNvbk+Dh1mMzMZMCZ5CwSedibltpB5MuZq/CUgEHnwt8QB9g5dRwpKlA2fuIsbKJNtEhYnyh4WNYtqpl/RUOqSsEeSsqS3a0uBAaVhL9LnhLniRIASrvHNKuDMGCnqbwYoPj8ToaYlMI0pWVviQOS6KwDuJ1eNm9FVR0IYkNPkNSFmgUfiZcyxBNKcYIEFGNQJWPy3NdkDwo7QGcmGVMwlzoCTYAJYaJSKcaKLZGJmC0jY5GJTEbRP/zMNaf7u2d1v4RBCFHYIFoBB4ORTpqybqvKnNHK62oc16t2sWjvfMk9eBh9DIWiY//221tVOTn2c6cV4JkV0jGXIq1qTJsF0jEZ3DShiUgGBjSNMPKYgpNY2YYIW5RWrVdWa23HdrT9zS9f/Tc/bSZ7U6mVathtE0aCCXgMGVvsiBrIdseIh2fP608/W76IHk0vPFa11kynbmt799LuwaPDxYf3Pjw9jOq66SuT/89//J/KrvZn+O2/+x07tevGF7UFYLtaIqnCWiPSQAWIqlGS1TgbRZDkci7CnMcLeePyMLMYUk4+DDGKcACzcy4jJ6qWrQKMIqn3AITQg8i5go0FaYixqkpmlhBtUYR8a6QorAiMgTEj58p2vW67lmEBFIUrSweCxCAaLAprbbqe1trsp2Z4OKr5UnzBJOM8X57/XaAYQB3azJN1CIPpyxvLMyJizizCCy3zBX5VpjQkvWJK5MkgLWMJJpfFUcUMUlDkCXXuvEU3hnfZOCA9vQiZJCmUaKxDRiJYyKZIJIk2IUxsUiAhYsApGaKSyJJaMHMhYsGOUBvmIA60y4t7RzZGe/mKBOZaOsbJpGtnKKreelJW8fDL7uCdG3feeOf02Unv6dHyvtnulBx7QdvJyFBgiO5cLhfc/vVd7DR8IA1pFUwctevORn3/+2dHH8ZwTHxsb8zCJY2f/aDeOmmna20f2D2KLdu/+5vVl27EJ0/kZLn4/C8nU+nm9/Ds0bqchM+X5vJNllN77cbpT/5DvPdg9uXvtgZ2eh3PPX/w03j8hJsX8M/aw4dh+eD09O/wb70zeuPO+JvvdBM0TWutWOkYplGpt7fv3N47feiftmaXn4/gK6jhNTzgiXuSVkITtSPbMffw60hcBReb3ggR1N8l3p6Gg4LVAkbgYV0ora8QHHqHvuJQMbclR45qlS2TJS3AjqkiCYogEhQgJpvAURUhTts+owpsVVVRwmjkYIEePrTBixVr2UoPAkWN1hWFtdKKahSItTa0LMIao61cKHphUQZVxhmPrl3PH/9v//7vfPK9//DB957zSVWd0DsHO8sn97z3vl9Mph7Nzt1PPziSk93b9e7+fvM8Ftfb/R320BH8WcVwHDlSQVQgqhhjSayIMBk2RrRjptwJcq488zJRm4JExkrBQrCWxVmeHx+NRuXu7pUYAoNjjApJAxrLhohERIkYnCr9kKyKhUUCooAQolhr2VioeN9XVRVCSPfZWqMZKU6egxwVbFlFSGDYiEiSDmZLUIZms1YgqXspixNBnEhiqnQ+piJQQgWzQJBAkDQSSwnwfFadLeOVCMSqkk0xmECUlk6EBLtJQkWQtN7MlFXQkvB8EhFiJHcwEEQ0+1RGTYLmPAtNP4OCMCw2Tk4mKX6wS0PfZHgkxCl2MVkip+oEFrDCkRyRY64VNdEWaEKYQsdKk96VYUuOrxj5/mefbDscSFOhY+kBG0CeDQmFaCZo5qg62u6m4xcN/CjMDqqrl2bcre49eWS2tnrt92bt2+/cXizFsjWcdxcrK3EPLlJ5opJoQSGRytPIgzlXP5rofZRX/BhYVQaxRIlsoMYGB2uXZ3Lnzq2fPfrZQ4eq1jiJqC2PjUxC2Cl4om4Gq13NfsvOZb56+PysdsGRsdz3XnyPkxe+D5N6cu+bX79R3rqxvFkcPV7qPL71xnYlo23e3S5my+frYlqhUSQ0IxRAkKDMBSARkQygPashaNAYKTq2gABRMw8xpxtio3mNs+YDJmDDKip51H3eszFIkctSJiKGYe4lSAwMNpTOj4IoimYaclrkzQTVEAKYylFdj+rAGn1PIOusRLHkCIjI6xkSNp5VvEKqQTKuEzEU4XpxwjLojjZjEU1bvDWNS84nKptGV3OzmnmHg3Zwswcx8/6H9HteyaZzPDAthjY2F6iZWpLa1jwGSug0mDhdSkr+AcljgInSymFRIAbApaSLPCpKpSAzF1CjWgCGkHTzFmTVWC2AUsUU5Lo44sKor6xW62pCEp7q8bHYb2BKsNI5efrRIx0HbFXSixEbuu7GrduPFi/Ko0+uXDn46Z//+MXqYTGz8IAVATGs9EG8zC7zfInFwuzUGpaB1fNKQwk7tuqO0Ry7idOdCpOl/OJ/IqtaF/79fykOFVoH3fr6t8qnC1+E/s7LeGLw2Wf93c9sQ7okbgv/9APbo7mrxTqWltc/+Z+1Mbwzkvd/aIsz//gTM4pSBbu0toL1beUqO3ttLo1v1iDHIgXBiF8yUIg1O//gteNPn91dnD7Z1s7hdCY9+ajRxg7ixYFjE0PHaKMGFI51LQFirSWRcNbcfWx3JuORo9gjBIwCsw2G2kp7A+84FBTWBuQMexWrQpFAEQwoWyLDBFZtIxQhZs/ixDMiUDJZTUYI6Zq5qnSGQhcQIBALrid1bGPbthY29B7M1lqUDobJog++D95yZUoSEwvtpFm+efuVq5fs//fuve3RFjXs++WPf/DnriudKTQK1li+OPbFero7Cctw94MP3vmDO4TOQRx6i8zmI0vJX8QULCvJey1JNgpVSs6J+VKIYavZ/zlZDathEmiUAGERtc4ZY0IIqtLHaNhYYzOuKLnkj0PxnDjSMQqZQRBkLOf9SFAg7VBTVWtt7hYNq4hhSutkkRijCW6KIesnNuwLzcimTYuATP5CuqUM6CAz+v9X4QuS0wBlq8jNoIryJ6Iby4GsO6ShKMFGHK0J+2ImQxnS19zWpd2im8UDct5oaLYg2MQgPcfXFAoZlpxv+gdJU6tEQ8hiCRrY00aVCU4LRg0dQWuRCqjBY+gW0ZR0RiPTzsJiwmf18tnq6PHLldsLZxWtLLywC2yh5Nm0xNtxMtatuXbruMM2VPvTJw/bh0+Pnz2IdKnSVWwW4e985ZKbFeu2N9ZFCUyFUlRERUDKR2wNCwExjfSAtD5LBUGDAqob4bMZoHkmtaxWQYoC7ABnrZOKv/OdvX/+k5anldSI23BbUXY4TKKZxBktamom5MdhMXGrrerMCZhbChpLE200MI2ND4+OX+LqjTs3j9fu2Y2rGuvlo8Z1lk759Pi0qEpVoR4AtCDqmcQBEbBsVDWABGqIlcAsnBx10jKVvCdiQEiS2JaH1JWWBSlRpgbQME0ZfrubkbIkKoHmr2xoyRhQkWxCtXFQywVkHt9aBltIcgshYmMApYEMeX68NOefPGS9gDZvWt7sS5PTaPLYGab1yAr+DWJNQ/sO0KD9xvATZUcqzlsgcmGSJg8ybCBKhWficWo2xkmwlOTAcqEZzwTJvHBhIH8OP6BmFj4rqTFEZGhjaCXpnjPAqlaVhslcoVoABZHTgtUqKpCDuh41rKW+IrhVuTWZHz60hx+OLIfVfX7pNVhtzhbHfFRfERva4NhLvPrqS7/1+3/vFz/5+dOnT9xe+WT9md2NHEtpW+kYlZN1YICnlndw+Ji39q6+/uYb+MmHePgxFWwq17vWlRVPWKdRtwJqyFZBJUyJitjatu57+/qXtl65Rhz60q6e/TI8v1di2UxmjWVwr0YLY3QpzGTJiCsiBac9FovoiCaVaUGlcb5qj5fy3e++8pu/185Dv+zsVjUvCraGWCV4Q8qhH4fuhj3Zsg/jR//6ar012tsuw4ksDK8ga7XCwVO/VNvZsA79qTfGUAAFsGEhYaiyPXm++GgiXx3vWhZ1iDZMKr9QgXpLwcJb7dROKPkGOaUSshZYFVaFGmPYsooDAtTmHm0zZgSsYQqQZOoUokgUTctQBWyZySznywIFMzPQrlsJsDUni38GO+dQCDNrVCJyzkgIdWl+/vP3l4vlVKcxCNRVlRop+i5e3rt+48bN4xfzZVy3zSlPUNnJbLp3HDix/EIImYcPYraC9I6IoYAgeUblTCy5fZNgjO29B2CtDTEaNhniYSJm3wUwWeu2trejBJM25BFE04CJkr2wtTbdEmZWETYco6Swkqrj5AidpEDDrDfV6SSa2I6k2Y4HIhqkZ2YiFoGqUDakzAEghaOYkuXgTpXC1mZOutmNoiBFdtNKVZQZJsdpZWnUZBdLREqD8kgya/o8tCg2pM2cXEPEEAmHKJbzbgbuLn6raJoJnI/BzsPZedjVlNuz8CivF6S0M5w0re9iwIoYwIEtKqAASqAGamACmQJTxbbOcDrF2Qwnr07OPv3wbtU2e3XYxaLEwiLtH7OebFD2ahc0HcGbvmmLNZvpj3788bOwa9iVsxjBneDGpfD2ewfLF4EsYEu0GhAITGmQBlZNEKgYBgYj0cH+HwSOKmDLKX+QJTIAiTKDiZ3CGnaAE6ngqKXw2pdv3nr2s88diu1Kp16mzDNXl82uLmYyn5qzCVZOmik3E2lt74XEQEwAVHoLLKsbCNfKvX7tFBNT7x4GN7056194Y41jivMgUahIYKiwZfhk5xk1h+xhx1RyK0wu6KzJxgbDqGI4ldnyYiAe6AY+1dSD5jVopJvpaxJHp29IzKONDWk624yM8RLSBh8dYF1VVeYQomUmaLzAk2KbymLJNXHaXJ20OF9IvRfqv7zKV9PFTxIlyizAX1MKpU5WhrxKF28AE2RzZUTTg/K0STVzSzZvIH0G52h4Rp3t4F2TPhdNwSp/DjSojNUkgnXidiTWm7GqUM3ZNyv3wJrWKiTnOBSEQmFVC4KDTfI20kpRwpbcVZGdovTlzriZnyz+y38cT8TbxnSPsf0aShw9f1D5x5fKhjRGO2pCe9VdfvHxj1+5sVu8fv3HP/0JjddcOgTAMXuEVpy1aoINkaZm8aC9cef6zpfuNLvXVj8aVR/+TUCgolKH3gSClFzAUk+9YYIG5oKtE8PWVv39j/3pE+6Bx0/K0Isrg3YMl1jcor1YgZTBAL61EQwj3ihgFiJTwVPy9fLkzXceLrj4yZOXXrsi0NBGrjlvorOVWOWJKcJybNsX9x8++fDuzr65VN9e+S0XCukCR6BRdEY99U3vT1vu2BoOXeDk6RkCKSlzcPzgcTutl6/erGkVUDCHvix8ha6i4DQUHAvWWLH0Cso728jCONYIiZpKNiZSgoJJk4OKAhYQKxgShoopjEL7rnfGgSEiy+U6R2pR733vQ+kq59x8Po9w27vTPvRlWUWJi8Wi3h0/Xx5eGcUQ4rOnj9LIli159Mzu9PisnrivvfOVs/WR758UdSu2atar3YmZjOsjEbXeeyHLCThOEYCZYBkFw6fGjXVYtMKU1ZnMTNlCXUUk3XeGhhDJMoiKwjXN+rXbr73/s5+enS33Ll3yMc2GlMDGsO/8IJM4B680O5sLG04sI4EyNMYE86q1BaDJ0lIVKmBLGjJYl0y0JAGVw6wnZbEM8YKYSTayiBwXkpB3wJNB54X3MIXFJqVKwq9T+ZwYanKxOaAkBxLoJmFrnooNXk6cPGvT9+Y3cIHXcqGCp3S+z9nOGUo/fzHioaFITKVzjx5Or6UpI6NgFIAFShEHx3BADR2pVooJ8v+mmGGxh5NJf7hbNJfax3/20f2XajuTs0lo0UCDWg5SIJRgSGCuuJ3rity06RfOxKrermh50pWh3gIU8+a996ZhTHKmVBk0Ecai6/NonQmctpobUEg4syqUhAfYQlQNMYiR/IkGCnTy5UzONrk7saROxcm6oO98a/bPP5zTdmUqJzOM7HybFrvhxWV7us3rCa8rPa1lMbWH051PrJaCFRAomhDoWy994+ho67IeB1Na8SToDY4dm22HCOrBwWhUDgxAOslmdmIVIpt12jmCZ3xFOZUUG4kdyHD2TdvoU88tXzbzy5zYRFhJCWo4Cd/zcwyXMXfVBCDTuVLGzdbsuZLJz5zx3iFXDfT75FNvTZqwnB8wXEyiQ+6jYeaSYfg0YWXeLO5S3aDKG46kJqJm4rUPCBANr5MxY9XBnllzM0vnj8llhibaWq5ZL3a8eekZ5Zu8uZJDyM1MnKTUAHHy0EtVayJ8gFjJUHZ7JlVStUQWMAoLcsSODGsJdaARqCYpNIwCj4z8/8j61yc7juxOEPyd4x4eceM+8oFEIgmCIAmCjyIpFkWV2KWaMrVebSNppttmxmZsZ8z2w/5X+2Vt9+OOjbWtWbdpu3slbUsqlaR6k8VisUiQBEG8CCSAzJv3ETfCw/2c/eAeN7NsYWUsVgHIvDdvuJ9zfuf3GMGN0Fl//C//qZSHennGBcdHv6yf7FcvH+H+J4d4eKAiRvr+7Pmd3dotv/nlD268+TbvHDR3fjGpyPMoeKAEWuss1Psg/Py+1hMVOzq8fk0MeGJn3/uTvt7DrV+QtKKojBHLDUdnURgSy5YNjJBlY6x8+rMQ1hU3UZjtDtsiBLagyEbADOptb9siaM+sVlmZo1UqwI2aCYenrbt6efK9vyivXVk9vPsvf/OT5dM333jrZmhFGokSyRAK0cvk0NamqWTxkx/9YGTbt65Nnn72wVl7effyO7QyFHs0wJr7RaenkddcEIdOjDXKCgkchGBtSaEhMH/xoNmduYMD7gKsV2N9hb7QrlBfSGuw6U3NBZEzVBI6FadIRHUDONWQFvap3UpuZenxZQtiywBhtV4766qisk4ZLFZMYZRUgxpn1Er0uru7U5qyWa6ZeTbZbX3b8qbAjg/9dDI+Xcwth2p3fOfOXb7/sCpLv2qdjKI3RSjefGf36LlJ54/bZr6/O+53Z/0kfHXW7O88LxFkvGGxhSFAogCsTDEECkTK0vesgYlUJe0uDRuQxCgmawA0iXGtNaqSzBSYIcniuO/HdfHFF19+8+hRPapEVaKwYSYyzCLiXDGwk1I0wvYYpdZfMcjyiIgZMUko85XExhhwds7CYLszMDnTvpDMgGaJpBkid+QsJMjWU0hZgYBmjVIGw9JLyzvXIf7l/JwP18LA6soAAghpw01bpypNxniZ6Z1MNJF9RxSSVmAIMftga45HVEApOXsO2zAAKXz0t8jRw6/kapnTafJLtUDisRODlYioAAyn8bcCRkBNUhNqlYnyDBNe7WI+o/kuzV9yq5Pbt2I7f24GOUFckW1AgdSBLBxLsKSlXBqfVlUzQrfkXRYjstmELtqDk52i86MXrskb3762Og6YSOmLduZpoeCCEIgCUa9I9gWqsCRIQZ6ULG7iUJmS05mykkBtbn2YNLJSmgYt4FApVUQ1N9xde/PqSyeL2xxGl9yoWExptR+eHpj5JX46QzOTxUQXRReKJtazhnUVNLAwW9v6s4PJ3e+/996iXqzgoBsQh2iV7elkt29JPHFv4IUCA9CN6kbJEnyh6AlMZHXwriHNs15i50vyYEm7KMnQ6eC6nLiIg28PD4tfTamWeTSOUSQpd1MgDKUdCqV5enjkBqT2vIgmpZFA8uFiw3mnviVDJSPlmNYspMNYSReXG6nsp4Z0eO4AGihRudYqaMsU+61hGUqJlIHzpckw/NN2R6JsmCVBb6mdRu7RM/xEqflA/kmm46I6HMZhiZNORLohBNgO8SISY0ybXWYWIVVhpvRDTy9HKbHT0yonR5gkOJoMawFYhYOWhApaqIyEa2bH/Z4NX91ym0fFgQuu5SpM2q9Gv9bYvczzWwdmUQMMv/Th915/96U33lotuier9gc/+s+zsKxqtxL1ReWLkZheiIK4vaP2W9+yT+739dEL+8/vx2WwFQMw77/fXDvUL37M/psgHdy4tDDcSwmAWb0FVcWIjUpZkfNo62gLq+I1klWJDAFxFNZCWG1wgcWStymnhVSlYNOdrvm5l/b//C/d1cubfvPa4YtVufPpjz9t5/6d995So2xZIXoEFHDSHk3kix/9S3Ny58WJfH3r7mW7Vzx42MTn4KeBAy8EC8habM8cuG8jrHFewBR9r8QYEdawDqGSVaO37y9nO5cQOg1UoYP6gqMjKUisBhiBYTUpT14FCkPEokzMRCbvp4ZpBJnAimhFRAgWXFhLNisfIyIxgVHXtVdPoCgaQzDk+j6kzWXTNMXY7u7uBcRqPIrUi8jB/szy2fzpYzx9tk9kXSEe4zq8/3sFFsWvP1icHJ+QFrPxXrtodVfdrL75yg2JKmrYuhhVOLlJZvYyOOGkQoBybretSdc+MXGMAYgApUmUmXzIMDXbvLC1xhg2UeTg4EBEoLLd4yTYJ4Q+22oMThrbY8wJ4VVVkqHLJmOsiIQQtutSiIBYUtrFcCEkN8eoMTMxIJQTc7MEE9Aoen6tJJIVcsjhwCYhbAfS9Adzq5BJQBg8ZoHzFbOoQIkp35cZ3R5IvayMrWoiLSVo4P1ut2JMqSSnbz7Aihcw52HDdWFeTv/YXpDpgbMETpeTgiA0+A8pQLACC7XEllCCxsCYzJhK52dY72CxK4tDt9hZ3f2Hn3982b3oH/lJa8Jp0DOosHFQC7VghqmgE613l0XtRxQsNoauwDoGB0Vn/J/+yfWWSByMRVuKrhSsag3DEYIIJ2CAmUVYwcy5gImE1BExc6LjDhe9Zm2f2jxVpeprhRzEKVfEFYdp8e33Zl/cauIUs7jY1dPLmF/h45mc7GA1lZbXgjV45bBywiv0JasReDZ7d9t71yZv7bz4tBxZaCCqwC7EKpCbT6YUCB7YkLYAQAXBgYTUA2LArMoXhlrLJJo95NKQR8NnJpINLjIKkn+bc/eVnlsZPtT0uYcYSZU5B4BuR7pzV4tUAPM5yqkoF/bAw2QtooBJ/aCKgoxhUoQYiFj54uN0/gXzM5hp9zKARbk6DkjS+Z+VJNlmGuolBlXv+YMLSjCXYDB7VpxXcNLB3W7bhJJcOMs0jP1J8kmpa89Wdxm8UmQ4TGUI/iXibTc/vNTUhxMy0zFh0QVR0s0XyVFc1MIBDlwTasgIOlIeMU/AFYexiI3tw88m+yaOMIkri2ZS9/buR0/mv66tr2npEKrQvHD16untDw5tO7185Se/+nkxv3dUjU+jLahtdKdH19TFxtSW46tvYOP7x6f9c6+9YncMYt/6qv34x1VbTn/nve7GVf/4Vnf8axO+YQnEBQvBtqAgAqPG9h6xtSEw9+AIcY44BAW8ukpaUVW1lgOr4xA6V6hY1cpp471fu6tvXf53f6HleHPcl65Uyy+NuL78+ucff9U8Xr3//e/AIezFwho4lNzH9uTTjz+8Mik3T589fto+aze2tfLklweX31k5RyuhJnBbwiO2XoIrREIQL75ypXVl3wsK67teOrJVvHOiV55uro9NDNYiutiStoSOTbQqXBAMKwuMRkpCmNRCiYBYE7GHhkcn1y8o2TTeiaCsKoX2XQCU2eQIXJVRVbWLzsJWo5Ffdw6OmJ2z3oslG3xAD91IsVce7h56fnLa6qNV3He7Onvivd+/Xnz3zy9//sOzz34q0sf6kCDh0dmDUe12nh9feuHgwy8/Hb+/G6++d9q5jalacdqKNpBW2YOFEcRxIRBFBCKpgBBCx3mGA0AisSisMdaHkE6CcdncjpNQz9i+7bquG9e1AoUtJK+PRSHJVQv5AA98XRURyeYMbNLZS5MQDVkoGa+WFH2ohIHkDMr/LyeAHEFiqqvJ916gibdCNiv7MvCsEJJz1tO2yx8mAwx0mBSEti18iSiU0wZV072luewjWzwPoBgRUlDR+fyqqkCMgZkTxpr0VflyoqFnFyZGJidZ5gSnXDAVyvyvdMVm/nRq+kwy6gYzwDK0FwNErWopewkUihIOmxFtxtROYnNol1/fvbtZ7dUEWUi/6DB33DAkMUBFnTombnMkkCmjLZYlcxlaG1bTqjo97v7wrb3D63snt7tiZE3DvRFjSnAUFo2sSjJ0ZcOcSKop+0SZ2XChGlWZODGCzdaPN6VksXGASzxIOJABW6KCbS2N9K+8+dz1xW9aKUpd7fGzWhbTfrHPp1Xw1FA8I21UzorWurpQIyQsZIqZK5exmR8/2d29ujOa94oO9Qp1bTYtquVoJiuBY5SEZKjqOK0Ok1nV8LnytoVL70vEpMJzvqOkLYaa8haJiNKnldwRZatRS2VPlUA2GWek50I0bZQvFpL0PKStZzqtqnoBh9YULZRABVWQimGOhAjdVi/E1GkPT5UORhgXHrkt4TlX81yIs19A1GHPo9jC4tDMOqOhBwXAwxOv+eFPbLTk5sx8/raGAwNoNuBJLBXddseJ6oyB95gRhsyOTN6cwswJlYQgx5mxuUB4RKJIiuSBfHCsTvsORgEUgIM4kCOMlGpCBa5YprHadfP7X9vFI2NXOya4uBr5zdituA63jeygq+zSaeNEvnPz956t+n5xp+MlvvnoOUKLjWg9IleSbXUjjQPOrr195ayVe7fYzS4/f+M5CTHul+HT+3znx1jIZn5i/uj3Jt9+N1RvhPltWd3p5InBchIah01FvTxdw0TE3kGAOIZrCLDOcKwgUXtYshVC3zKx71GKo3UI3qOV3k13/vhPdt/5femCLrUoOfpYo7SjUg6oKMqv73/1d//5B3/w3/2ruh5JFTgud+r41ce/8avTerZ89dWq3t/RxnerdtaHp92a4YIDW6TdvGgnXTAGKG1VVgaWgEIQioiKbcGw2rP98nR9+dqssggwYBIYQSIvJ5RUgMQiZDGKbUPIpFCRMBwf3TIGBNaKSFUViWSiCjaGFDHEpI+PIYhP0liSGJ1zGpht7jrXpyvnKtMz9SRN0DGwd/Dk+KunbXm4dz1udH+6+c633Id/+/j2HZldmzCK1bKbTIrf+6Od599+LcyasHvSlPHvf/Wzbx293xQ7q7Dj7UxWalviYLSPCEAA0AMBGpNzDih0rS8snHPGsDEmBPbehxCMtcjLHmjOaoBG0SjOub29vcLZtu1TC2ytjSFy9tRJ94gkntQA0qb6m7ko5y2qiDGmKAoRjbG3ho01UBVVYwaHemKVQLkzVxCJCmu230ohC6R55ExpSTB58zYwJFPVFdULkuSkgk44dNoagRIxjJQCBMMFitQOMJ03Xbm6AAI2nNjaSdua3hozVHK82rBLy9bWZFiH+pqsTYiJjdmqnraXYb5e08irihxImNbgJl+Kmj0pE9ACCyWlklCBKoKTEptCVk4XO+P15v7X//izJ5fKq/5pR3OK85Ibo3NRQSxUCrEWajVUYjRGQwKpD/ugTYuTqavX6+XNS/ij77z58CRWdSmrXhllYXvutTQmsAYGjDFF5CjSxcyGS8MVZ0/fYS9BbFNSDRMlsuPQQYCoULJAwQ4ogApaQEvLZbCT6jvvjn768wc703Xtw5TPpli4rpclsBJaASuWk0JshZnTCKiSNa3xOvWLB8dx/4Vy0k5G6xXWI2qKuHRcVbppXCmFwmjagBhjhQVI0GdyRStI+2QKIBpJJD02lHaieUO75eGmWqwD0gOirdBHiZLwL3OZsjujQCX7RwL5GmJjdKh1+dlTVeLsx4WMzyipqrKKzfCLAiCmRPKy1kgIlN1B018akJ9hD5u/Ui6WWY3EZghR0GStw0xK2xZXQWmSTeSr/M6zmv2CG3iSEybXHMmuzumwUcbx8zZX86mFnr/G9BWJWXKh3TalUBqc8fiiaklzYUUWgjGTwEChyoZYwaIKIQUj52cbSnyDBHsWQElwKqVyaWgmXz96QL/4yTWzAK2tj5UuC7epZdGAImEnruvYOlm98/a3Xzqavsj2pMEvfvHBns6ldKytjWHu605CaScv7ZsXX9tp7eLvfuZ43755/fVib4JNiMfP5Nf/7IqWa9d/8zP87R28945578367bcxeTNU3oQTd/ag8KdWuyqsaXNGcYX12nXr1rfaE28CswlsohRquTOCopQQjUFbsTnat/YIBy9cOrhej2Zx2RUN9yPRXgnk295G3jU75bSka7j16PN//pd/ef/y+zvVtCBfW3/85SeVzGl13MbN4v4zOTMuTp8+mi/mH8zefp+ntUhIabVsuBhbZ1kcG3Av0Vq2wp7VpnEEBVt57MODtX+NWdSIYZIhkGPAMNOAs82UzPeGJOpE4qYmGDVdzYZykg+xiITQG8MMZuI2dk6NKKxzfddbW1APYt4sNkaNK0zTnMVox9NdAAhYz1ejac0Rm9a46nmZvXjcz8eTyze+Fb/8+uvbxzp7fYKlbZaLN78zufnG5WZx9f7Cf3Nyb1P1s+v7D0L18X/50e/+xbsNj9vWmk7QAm0kr+SNCit7iIgGSExKh7quFb2oiCbPIokxGGOttUPitxjiPgRmIyxdj+euPf/FF7dW69YamxnIfUxXkCD9TDTlnfEARIOJyfS9T/U1ynYpyBJjDDFNtHGoZAms2v5KFU+3ziHZ+TIKwRpGJMOUIU1JCuJhzbUFphhRhJOpSPqIOa1mE+SJDBEmkaQKCJR2VpoPtWbDS9IBaFOBMFESDGUXsC1CRspDZ7+9ePMlJBmgjwqFYSJV5M2oSrLm3UIsmt+OIvN6Em0nqTEl2/4bEY4UrbXCgiIEwwYESyU2Y3QT9Xu232mf/O2nD8fusn+4kcZipbSIvCpoIVAqVPyIxBZiNuQ0ioEJXDBO4uzKqo1uLKuyk7/81y+ueuVSA3s4wFKMgZKGnITBmtnC1haQ2CiS39G5z69iQOtFOAWvghI8SSghRYhs2DAXmV5mwdngi0JFDcV3r+8ff/gr0/mZmU9pM9NlnMMsiVfEG2MWfXcSpaggqsIGpJYNIrQ6LU+XJ02x6+rqbCKjhsdTmna6cdQ1dckNiVNJLGgrsKQ2MW6JhRUC5sTkZTbZJYYpxl4VyWY1PbBZijrcBqlmRCiYBpeZBMZHYjaGRRMUAzYpL1iJYNmIikgiCg/7zxgV5JwZjKIkihDDEAeNPgSkIEQiMAcZ4ghEwJTtcUSgEIkJPRo6YQUGe3jKhzU/8VmPNyxZKJfPVDs1t6BgFQIUxETCmsTGKcOLQPnY0hYvpMxUTFHc5wz/YTecRYe5R2emdCiGCEUkLpjmQG8yMLmRUagFhEEMtQmuijF5EBmFRFgiS2nqFSaxAMOCDQsHYaHCBiNkpagslyx1LCbu9M7Dl/ypNWez2FgE1vlIFvvinzFPyc90U9PG2cXy0a3FzBwe3rjz6a313Z9N7Giz0Qk5VP65WVseuHK34Xo3WvzTL5a1P3r+9erSK0fUcVD2t35h40MeuaBchDL4E/PJP7Tzj/m1l4s3XzQ3j8b7e9XVmeOFE5lSa0KwFDi0HHvbR9tJ17PBtLc1ZLwOlWmFG2sWTMIlldqXdKa18tijX7TaU6eBNkzEUgAGvY+wKK07mO1j98UvVw9+8Iuf/N7zv/PtqxbL45OHd//dH7178suH9341p4elLKPtzoywmy/lwZ39t7+z3rVqDBvT2o0R26sWQkpqU8i8ITZkGGrQuFhZMZa/ni+f987ssPSFsAW5mNZWiW+TZlvKDFeBwICJVZDGZDY238eiADHEusKFGIipcEXyewoxOC6kD8kP3RqDTvo+yEZMYTlys16LCkikFw5MgUuquC3CPEQbn8I0fOmpn75+c/KwO3v0aDK9obrwm+jf/7PDK0fm7//6wWr+YHKtWrlVNTv6al59tXEP4qK4f8bPvyYrj43VJnKn0pG2kXxSKAgBIQZmAWKyqQt913atMVvFrXZtS8SusFHEh8CGkXiOhNK5w8tXqrL0fZ/II0SawoLYGhVECdkJaFuAFV58OrdRFIAxSXYSMfyUOeNddrilsT3qAAuyFzTzFroFqcS8ocrGwnnoSmDy9q7XxF8fEDPoxR3teZ1HZkoPjGpsqSLp7tHhhsp/Ls3c20ZBVQd3Z4Fe+Lv4rX/JK3NgEIASZZA/jRMJP6fhm6QWRySV9jQC5O/BSI4d+RYSCCyIrSWSGlTRWBSymdbtjpz8p7/7tFtWdoW4Ul2IXURaGpxp1zIDHNlu+t54Y01fgTiwK6LpFEVR6WTm752c/OX7s6OD+nazMWaKMq/NUAFGBRGEmI2FOZVdJguNgFGNQ35VAilYQRkXIKbkg58QBpDlkmA1GXgYIkuxADlw1VHtpNS9iX7nNfubjx9Ndhczf4JWsYKcRaxZlpAzhIWKWiiMcHKZgiVnxVvfn/r+mXVTMxs3K25raUY0rrBRO4NVWCQZkiS7TwYZot7kj1i2nyNn/oGG4WGwiYBMBGN4oN4Pi1JNjzmiZFsVAMZaDPArDU9bRnjShgUMTqIayWeASJPflioRJ38ZgLbqnhCS9sOeUxiApEEYJoyBt5jPhLDm31QmycQXFZxj4IlqtiV0bPkOifw4sLGS9U1qbgePOVEBGcOaGGJDvDc4e8wNlEVVaIyat0Msw+YiES01JUkQZfmR6rC9Th35QFRDCpQa5nBkVWE6PazZnwB5O5KaHDYprDNnAFQcjNjaahWkglRxsufurp7NP/3g0LWjpnGyMLoaYzWJKzXdpijKdVPyyvWrwofls88+u/vlw4Ojebu6Ws1HdbW3i53nJnG0+aYdPTzZfXDHP15iFcOm3d+fPHnl8uvlZD869J99aR79mmv0zEUbxLJ1IGeK/iR+feznP6fb+2a3NLPaTeuijOS8VE4qy+TsyLItpdxB5QLVdTdCNW67Ao2xa0KlWPT9/Wf0YLF/6bByUy/K1mTjWnjAIDA8lBUWvenr56qjg+cqO/t8dfsnP/3Rwe8+P6mXVWluf/wRffNNoSMLgStiFwoP77n96iu58mL14uW+CWxD6Yz33hinCmFi4fR4q0NXACZYpsDEFZ+Iv7/xzwkCs6R8aKIgaagxaSaSIKTMOXmVND0FxhJGRGm7GJgZGqDBSgyFK4QFQO/7AoVlDl6MsejhN95pYYxVCdYZS7Z5tt60TV0zCKENpjHcMXvLXmWx0QJ05eC4L+bt3mY0vvWk0FGY2vvRH7/xJ3X9Uvsf/uqYa+dmTo56V99cmN3TODOz61YuffpN+9KlCitG423v/FIKgYpK7MGBTYaF2CjDioS+64rCEpEOWYSZSaLSbFqbZlGmtO6KITw7OdEo3vs+9IYNgBhj2kmRkAzpSdkPmRLnU9hyujt4SB4G0vcaqiQRnYeVkmIrpcyqhORkkISjQ4ec1MCsA8UqFemt+DCJF4c/mvv3vFy9cPWluyZ9bZFz843tDZHr7gCNZX0wBgPcoaBeUBYN/554Z5ope+klbevxVhq1xS0B2ho4pAk4827JseVhrWWYbB6wDKsmbZym+AupyBawFfrCW7RHExn5xX/8h0+4Mzse/VLN3MSlD0szmpv1pm+Mg4ozgUWNN6VvxQdrC3ZqmEIZdWK7uPjjV+r33tr/9Gw54lmJ0DgrLAmdhSMOiK0ohr1DmrvAKsRmy1eUAaHVZFwy/KAoUXfBrDCGbdpIqwUXiRqmcISS1fkx9/1m8+3r5aNfH48CZrSQhaVnWrejwvPZs45XqJZFhA0lCgGzteBYiLFopO1Pfb87QsPVuK3RVNiUaCrdlGhbV8GBHQHQArDIUi8QEUv+xAzIKKJms/+t0EWH/ouzXBdJCCRbH46tJj190Im+MDylw+efsV4MVL/8GBnKIEtyTcfAZx62sJKmXmJWQYxCDB6M2VN7un2Gt98we8eySALRRRMrXfJAfA6nD0vuXPlyv7ztPNNknM+LMpFKUgLpNnpyu6tD1uvl30L6CSuBlYGYoflBkkc0AOkDWXoYo5NFt3AWHhBlIbaopsEpya+2P2tiO5B3TAoiJLCqUauSOKpWqSQzMlIJjVgqcbOCxvjw737QzL+WWTW1QGjHerrD/W48exgil/y7Rye7la96V6klMV3Te75//Tma7dnpjhRjedqf/PMv66+PsRbeYLdwTU0E6/en1w53nwsUFs083vmnehKidUWATCgoOI6sUtCgSg7KqydmtVRqoW10hVgpnAWitTYU7GkiXDc9L9W21X4jEwkFGqJF3y96+WaOJR98/0+LvVm/6NUrWgdJo1enMKSksEYtMXNBEmJpyoNdF3ZfuB/w01/e0udlcnT0+UcfvuKm1UTKXbc+acQpheBm0/2DanHymT+q7GTShd45Y2AEkUAGrFaDQpm0SFHLaplDwQy0ZO80m0krdmQoc/VMHjZUaeDaGGKkD1OQLdZhbSJpq88tITHAVoJEeLLElitXSS+ILKFP24Z6VIdV6DtvjWVl7dUWhentullVo2o2cREkG+GKZS2Vq0KHCRf28KVe22826LvOt5t60918eXLlffrZv3TP//7rfbc6efpk8sKbx6vi8cacyR7VV5+s6vaJfsub5XxjVmV/FkxE3LDxlk0XpcvOG4TgO2ZhliiBghaFkaCGraiEmFF5awuVYKxV0SCRmauy8q2vKpco/oOqPp/s8xgTHparyeyIWdONnKfT3ypxmbiypVRyup62KloiIhVR0uRQneQWW0R2cGzP1tPnhlb5SiMmSt6hqmKMkfMVEwZkF8QZ2FLJBlrbqyd1zfmrDRV4yyFlupA3fn7D0XBnZoM9oswZ2A6/dKG08zYZly5setP9muVYlMJckrgzeacQ2+F6oqI0YiEsDAkVSx8LUx0U80cPv/mrD76Y4fDV6is6bW0DDpaiRaAYexbD2gZDbWAGdlkRUcZJgLZhYzhYrpYL/9ar+Fd/cOPLU/UWERzAGkGSHB6UBBAyZISJWQSsogQhCDHl1GMSJU0alPSBZucyBYZsgNQheRVSoVzhKPVLDEi0hCjoRcOl3ekLe1W3noOseDHGbrrer9WyY4iPHmwEiCBKQ5sHAhQqEmMvEkQCUSEMNSQMsUpsznnCbDnto9PDqbRlFdG2u4uq2SQxEbwRkcIVMjw7oDiZ5T08axKJCMRBAg9C1cRgyt0ZAQO7OAuOzzNOeCvZx/AHctKnqoow2226SmLvpy1o9l1HHjmtNQDFGEDJ/12QmmuiZLqRwAjKe6kUkJDldLkEpjcGpIwDybKlYZJPrqu5DVOk9f5v2X5QgrEoDcZDa5D2U2k0T2JnztHXQIYeB9fS7cIL+RAlI24Vobzaopx3qpwVF4OCINMlyAJWDcgxFSwcI4IxFlalUFtbM+b/8Ld/c3bn4+nUPIS/bn3Bm4p0oqsirmYv6b/7Xb46krO77sMfzjdzt5hzkJKqvqjZ1izGN514FDzDXtlVpFag/ezyoVkRz668crBXPlkfx5/8qMaTfjImWK1b9cQFS4xiwEU27+xMWVBvg7e7+6dXb/5m8U0VmpLEaXR9CBNZb+bF6OWaC719B+x0JXaF2DpZeGee2/sf/7vy0vPdcU9qTIAA6KESAAGCZtWmBchYC4j2yj1dvXIZ0EXV33n08c3Z1Vff/ZOzT/5f1XQV52zHppfYtv71t/HdP/resgkPV+buQhmdN0ac40hIwkqTc2ENiFnFkDBglEWLonjW9Q+WfrcyITWqqaGPLEFUWTPAARWRKCSkULLMcBL77LtABE2CfbYxirE2RaOICBNLiMkZqO+DtlqgALH0IqKIKIrCucI3yQvLh8aYylBHuiE1JnInc+xXR6cH8rB5Vo/Xp0SHs/HsLfroYfxGw+dP5hrr2eTmV4/ds75uzay+8q2vlmZeHLZ35r8Mv/zOy98+W8a4CtwBG9u1HXMLCCiIRpUgEkR6IFrDIXSpK9ffShQXY4itDTFaY9JhiCqudGU1GhpbykyHrVukInGXosa8NocKlESNMcj2FBkg3sp5AKhGETUmRw+BksrnApB7wZBOAclCfDUwaVWWLyzWC+60GY0mVRlYTkyQNBZcrJqaq2sS++YLNEMombFMyHvcC39JkIgAlPHqxPQE0iAyoGbDGx64XOlN0xAbNHQjOYhYc4XP4l/aqrHT6m5AHaEKNlaFiagPUYUMc4So5/0dM2+X//EX9+bH6+vV0RhfRoRAtijQM4xlQDwI0ECWESaOQt9HMdawgReGdQS2reD5Sf8X//rlrzorzOCRj4iABskO2BezcUAiUZH667RrTO1EzLqwdIGnzaIm8wgQsrlUXu4lJitEIxA5nUIFg2FgCQIhtbQ8vuOKmsbWIABMhhVRRSkI2LJNu3RlaMjNFdkE/uQ6OrzmrIZKtLZc85K8LhdEIhFc/NTTCCh6/jRoBnE57aNINUYRCLNJ7m9KyYnTDJDp0LLlzxYXNLh5vwDAZO7WhW/NlIDUTIIeOrjEbgohEJNhc868T73mhfk3AbaclXLDt8yrF1B+9DWzG0k1WWOmJffwSpIt1tAuQAcvdJyTl5HuE8IQ05lO0UBgZSJjhnDuZIOTZId5xZLhgbQIT6oHSpw9KAYLWbbpMGk2dSWALJMRMMEQM2AEhFx6efsf1bzvIiYYRApsuSgLKaJa2JGlgv76H/7m4WcfXR2j9uu7WL1WhjeKzvZnY78aX+5ufr9EswwnRCu/R/Ty1WJVnz1dNZevugf34OdFX2Dqit6Ib1bG9SEUlejRC8ZMumeL164/f9htFsXHX+w9+XBe7trAgXsyUhS2s8EIhwAIq4gadupd7Pnw2t29/U/uf6qrrydFOR0faWzVAPPVKe++cHmPTxaBHMMprILFL4rrrz33h3+uvCdPuiICPYegHIVEkh+SkgcYSaQQST1pUOoJUTnwc4dXRnvYPTKrOx/ulpOb3/6TZ7/8L7HcUG8d2T/8bw/jSfGzX9/+1rfffu05t7rdPA1TFKDec+Rk8MRQCBlSriClyoikEjgNE6NliGy+XOKlXSu28lJ42B4WERwhPUjYZUNWhgEsokY4YWYEQwIKTIggI9IzyDrrFPCtt4UVFQ0aQ2BlCJjZFtZ7zwoQhT4wDKtUdQ0OhY3QUHAhHrpRsQoDY1nm8I914+396d7LzysfPLeQjx8bc+uL9Xrdgq5A25f2X9k5uLFTX/3xJ5/fW5gzunT2xclz7ujX//jJ6lf+/dd+n7wNy0gdGY4KD/X5YmOoSSEtIYWSdl1nbaEiGEzUDbP3vnDWmLSC5ShRVdquZWN6H2IQsmJMInREACqw1oQQADLGIvnZC5hNRlZVmZMYOubLggY8KvneabKP5oQmDxksw6lOFI2MGA+tsQgRWwLl0WGIL0x41HDFnF+XaclKqdBejGQcakLGrtNfPL/+Buzt/J4kcLK/puFPpqYtzy3neHOG2Uk1qZzzvncY0wehaPqKKZc1wwmJRMaZjY1cliXGNLzEaLgiQ8RkK9OFbmzLou5//OGzn66X+664Odmp/HFM2KEEUUOh52hF2bIECoDpxVXV6r2XZrfuLM68ZccuSoCIHVU0/+//zbW1nfgQwUZ6I8ZG2GR1r4FY0qyrSCtJEUp+C5w+67RUSDV16DLy1A4lM+wELDQqIpHY9DNTUeR6qQIVQAICMxMHimr+9fdv/vMPvgilWLBGygUjMcIFig2AKNJLNCALYsCwhaIoLHNGI0QimBhqEnlvqINZS8NpCzuUFB0egPQsZBruFoJOxVoJ+SwgGdxITLGAOdzZmPzlKe+Gc9neno7hG+WudAtT57q8xX3TxoYw7GtAJBgMI9NskLHjVDcptYaaOhvD4NxZCBMTJftVgUZSiDIrD3mfmi1Itl0tpbSD4YXgfOLdnpftqyYkKx2opq6XDA9MLspkq2zVgUTGTH3NEFiZHgVJNl80aEBTfAWLKEz6n9sORpI+HqDzLUf+mWWtHnFqqpAp1lQ4G1mEVYyyM1yZ//rDv/vNvU+vzlwdj0vtrLQraSfiRTqjC3+pf3Af+4bCWfnFxyGcjqZd0R5Prl1zbRNWz8A1hVbrGa5epmLXFQfx3rON2yv73bNPPt996a03Zgf08Pghbn1Y0aaS3dZILDo1HEotluKtsDJ6KWobRFHtrqaHX5Zy794nrjk5nD33ezdf29t46RsD6drQhFIefrk6WUWzp33Rh6V4e/D2v5589193TeSzjZDhnkxEIUSBBWE4kh4oQJEREQ1roRI0EoKIBwVzeO3a4os71994q/1qvtm4N373j+79+Ocb/uZP//jqpz9f3flRWx8tX6WXfvib26unwOGbmEjRcEy9ryorwCoCVCwTYAqaGlS9TIRrafjoyWbEjZvuz9owa1E3oTSNoGNtxfQ2tIEVGAEGGBH3gCcKUE8Iqh20t4gF0CsKm/J02bBGNWzati1soUFDiEZMeoass8EHQ8YoB4kMqarKmhiChxLaUqyALYxC2TuNJ8KQDfj2yezykc5G339i755Nn7R8iW1sVqvHD/y0j2tddKMXgep3dm7uXN2dhLLZ819+8PkXH355fe+lWguPDWwrEiBGpGMS0SASjDGGOMTAZKy1qkJMhm2QEKM466zhEIO1Nt0R1hgCX7v2QrNem4Rf5wh6Y4xBBkgxqD+FiW2CSROvnNLRUYUkYVJG0n5rDpastNna5XBOEwKQTBwTrI2sduAgkVSiMmUgL8VQJGZmPq9Zj3l+M2D736m0pfrIpNuaeXH0SOPvtsAOF02+bHjwob1IqbkwVySQVXXrl6DKW6g5OaTknJl0MwMZh7fbH4iSgSKqcEqiJZMS42OkqEHRGzJd200ulavm5K//6/qrmb38yt5+3HRhI8ZWUSmR6IIix3Sw8AZaWCaJ4dGKfvGwFVjLwZoi2CjWrudP/9f/9lpdz572wgrPNpAKrApRzP0RgiIJf4Oq9IwoEpDSjCkhrpoTLzmJNJE2FcQmASciYAqUyi0LS6+w6X2zpmEtYfI2oFWxyn2z4atXD/Zmn2uwsJ7YgjIIy0wCMrYHNEJYojJZslAQ2BlXOiMQpa2xBjMbA5GL9hbpaUkUeJWtT0u+yJNUnTgFjSDRhimzSJLIiAwZUIxxyAFKp0PYZGqwymBqlffDlCGYbeNH214uFfdMSlLK25pkGg8g5t0s87D6gWSdffbEyU9urvyZF0EUEyE4KiUnVwYELNsjkRlnRNuPLT/fafkK0PkaJe+4U8XbCo14S6WGakoTN5wtb3VYtST6FqCpC92yzJiJQWxtfuOiySmI0t3B2Y8usy6JAU5fidmkuKgkOBgyK7YHlxWG2CqTsYBBJKGCyJEUUs2KX3722cdffHpwqXLhKYk3vBzJ5jisVxRe4p6dX5OpRI7vYnUc50/o5Cv5/GmjwY6/lGWPYK0ZWSVZPvNnT+zR6/b5HT8by2K1/vIuXX/t3Rdfvnaybsxntyb+cWN2EFaBCjKKktFodFysiHqo137TFiMXxlfvjGh+8nUgh8ml2f6Lnz2Lq2fHQqEup6/NnpdHt9cheHuorekXS+MOj/78z6trL8eTvlig74zdEFqNrWqw3EE5AAEaVAToiQzQgUhaS7WyJ/HKfdGt/Khx/58ffvjO9f2/eO+7y1v6xdMPrr39wmsvTT/52cPbT8Peu64N4e8//+HzL5U3X7sSEG4/q5ulV1IosSqpxjQm1YKaTE26o1La6LDBbKGzMxnfOrMvzUYNz1qZmNZIB7SgwFyA90FCCBCv8Eoe8KStIkA9xCq8UiB4g2AsKamqhVUSDeKsI6UgIR24EERC1F4tmSgiUQCBRpEYtM++DrGklsj2gQsW2BrxNO7ujNXEe78O+7/n2ivV3/98/vqrV7/5vF2vV5efe2WzXCzj7moFavT9d9657I7a4w4bdZvilcPXHn390Ud3Pn3tuX+1uzNq2x4AeM0AIDF6NhAJbdsSo7BsbZFMKDG0/yIRzNmghygpGFBgfnI6rut8fyXTaGSrjeEvKlRy3GtW+6ViyprMFzRfZKICzfNuquWDkYGQDs7BF0Ct8xlENcbszpFu6AGD4nN2CAEEjQk9o+HCVSbehiNju4JMr3MoxcNvnU+9GYrD0LKnziEnHeVXRUMvn1cXrOecFclRNgJY5oGSdGEVfbE1uOicOXxLyfMzskdhst0kEFlY0wc/2xl99fX9v/oqmherg12DvunRF0xRJEAVsKBexUQW9Vw4G8oAjjE6VquuWcUJCmOZo1Qj87QN77xdP/fc/qJri9E+uIRasUVAoR0QlAOl7BoSYpCkhEjWLYacrCfT9JqklyAQQ+WcRke8HdGgiARJ1uSKqGIYREERgF4kErON0rN1BdB7SFBjVWMgKVhEBTEIhFWU0afRS1lVyUNKMASVK4vCqrQSARZGhASgj9Lnj2G7dt2Om0wJulDNH1rKWAQlcCJhyEKK5DFqmIVIYgRgbZEmP6gakBrKIjTOlX9oQSLYpDkyr3Nz/keeQElZE/xKAMGSSRQtZhJVjZoMWpMCcOAaIpVM1WiMTbEo+ZvmIwZLLNCYh5WMXCinVY9km9dERVMoYBiJSZECFHnoFPNSacu8TjatlL+jpm6ZGaCYpFOU1kJEeWpXApGhqMqGUouNYeamwbx1AAnyghgJ0pB0q0Tks2CQ2RKcKXJIMmFmFKKsaiSRFVMvnG4UCypMQChGdrFufvLBT6tJXXBnOJQk4xiY+jas7mD5Esi6frxTfPWJ75+yNMtHnxWyqNG05HnZwlaugNImiIOyaTfhzu3waGX9qCKO451yrxLbLe3S8r2PHDqh8cQEHzZLMzMmUMqWthpErUdx+WZzaVqfrG9G8QdXWzncY7M2m48f3JK2iRpev3RzEa2EUcNsFxu/ovKN95///X8jvfWPOm4ltiW3LH2PIAgFBxLeECLQg4U0Ii20IKQhaqRe4kao5bAWMyrivL/xyjuffPkLFzd/+vvfXXF5584/uJMb93pX3DzetM0G8vt/+OKbN15/eLv5+B9/YfZfdFdvhGajKUNToUZICCUwRZyQsdK7el2Uizha6bjl+nhNdUtcVz44E1iAUEVXGHjhCSNCexhPslF0Cg+ypEHRgQ3BEiIJK3lYFSXmtm0tW2awsARhIWYbQiAlx0XajhEsGDZ56FAABaZI4BgaNKPEDA5tP56MDouD33x6+7t/9t6TzQ+/+EF4/bvL0Ppf/kJ2LttHtyfrNi43WrM9Go3ILzdf37+3ebrnrt+99fDhx3dL2S1DqM3tz35z/Dtv/bmrNYhPtyFBmCESYvCFs6n0JmljJomkBZihXDuTpB9QIIQwqmtNKeScDZnTuU7QYggYYhKS0JC3aFgqGJrLPNKKMyFYxANKl1prZgZrbqsFgwOdJmHl8Hok7YI5Vbv0nbJ5MinSjGKMVRVR2eLPw5qWhhQXHWbu5CKEcz+AYehJVTTPuanC5sFMw5bhsv3FAMGk7DYdLA4wTBWMIApVCyKwMFRpK8nEhW+aBhvNM1LaXGV0NtHYVVgNGVAncmmv+vCzh399r9198ZJw6H00XAbhKBQDe3DLtjZRa+gIJjD6qJXaIOPAnbKj6EiUhSzzSFqLGbo/eP/ayiiPXGReax1ggpQejiNRBAIogpUlcZ6FYCnjxSqQoNRTHu8klxJBGmIsc2JxJ5oQoIAYpNlJQKKqLEQCCaJBSUm8t96AqBc5Fbx86fDqYX18fDIpSlgKJsI5a6WoxW2U7cIICwXLzgaG1bVZ7db7k9kYo6iOURQBLpANarxQUIMApGIPpMCQzC+SAEBJkBcJiVEQoEIm7SCGtgsgQWquVQY6OxGT0WTqAjDbPImyJjSIAJuMo5O8TkFsUkiwDiz7pA3gLOfVVJW2pCRj8pNGaVmau1FNdtM6zK+pieBhhTy84kSS09xtp2UCAUTKgCCpFrN3VxJJbCUIwyohAgoxmoo7ZVoga0p8St9I0kFXzq9LVABjGMlaezhlms2wMjqtiigCzWwsTlzMTP3k3gcVFNYyWzCJJEG5SXtNAitZkGVyGhlk2VQQFrEibGwp2difAFEK1klRFf/fn/x82a53D0oTViWFSegtpNamZv8odJ/I2feOph/e0+ZpOBxXv/pgFFp2vWhrYyATmUDiRQvSLprScE1ccjh1hsWWLXB294sPAurdF97c+867Tz+4RYuV42KkaMsQ+mSeJ4GdtC1efOVT2rn36MF0Zqwxbxxc3Xv0sLsy/ujxcRMcYOud/cPdl/pPfgEPCZW79saiq47e+450JjzrJYAbgzaijWgELauP6JVIID0QwR7oAVUKQBAByJJ3Kqo9qIVptTnZuK7ef+7Vf/zgb3Zn/vXxFZLrP7u/PHz57cXtLxf4+k/+8ubxfPrD//2T/uyzvRL1vN29siOzSes9obBirAjAYcQ8Dt5ZT+ONVus4XqFeyWhOs+Mwkafu5rWxQOM0cFU44aBwESqgCOoELaMk6cAe1DG1QCEoCIWIV2sYnmzbtPW41iDRBssuhBCClFxKiEbJEItEKEIf14tmb3+HlfsQmECkIn0UiUGssdpUEgM53jztb1555dYnHz+785vXjib37y/u/MC++u6bT9crPNzMfLO45V1pr15rsJzPv+npyeJgPJt37of/6e8Pi/2739y1Xt57v+/608X6i6Ppdd+vGaoaQFFjYGKYNA8rg8AcQhAR55wO410qe2xM7Pu8hGVaLBbG8NBfp+O2tbXLeHL2kNIsBc6N+ZaojPMFp0l6jDRh5FFSc5BLshUgPh97Fcn5gZitZdWsVGI2aZrOnfiw8c2BgJTi1BLJ5wKrSzk5H6VlkGbEMdNRCOcQIIbXvRVnUK6VxDyMvLlk5+FOhsE9qShpwL9jUB3McLfMsKHV2P78aJBCZS+utEtLLYJoBES1Zwaj6kN/aTr56ONv/svdsP/CJVkHHQkajRusiqpCXfGkpp1am8n0uNiAG2VLsRA2pBWKRaj7wCW4rLjwoTLi7EKf/s//w7XJtelZ1cXR9ER2lzxbYKelSYsxNUQd0GseIAPQQ3oFBZBaonR1qjIQsB3H0jtRyrweGpIJKLGe0/uXARqIKko95XE6gKXs2obiuHEzh1UTq7nYFe9P9le6AghwASRxaRDieBRskSobQ1ULjVOZHe1UBxbTgAktMFthssa04Wkj4w1N0Cp1hDQJB0iv8KkeiyBAY3opipiIVIpohMBCTAwDxGF6JqPJiTNndg1Meh7aKpw/gclcLgY21lrLKSgrP1qsOuAyBqrpjkxri0wgUBUBGxrqdfq6A5TCDAFIs/JYNbepICRxW2IBbjGeTPVLkZ7pKUz6Nr2All9sSzU3npxyQgd/Wc1G7jnNLBH6Acl9LpnBBhxbhd7Q1WY0PjW6Oa+COAkjRQOSpomQeEPZ+BYsIbKxCecn5agEMCWes5IoCJZQiLCiABXMFg5UsFgVhhIJh3o8unX7648//Xjy8oRkbdWPqBXeFNKU1NVoKmqfWv+LhW0e6Qs7u5992PSrceV7PnNhHW3P4noEIoYpSZgRwUJkoUWjjSirX8zDRvZr4ZGtXrxR77zRfPwh7j+yfs22MrUjJ8ICbiqePR1funX3U+bNct0dvP4qHq06DZ9s5MFi6UZlH8zVq2/Lw5MwD7bF9MY79+z13eZk4md+5bmDa9i3wq2iBVrAq3qk/2J4oFMJRKnfDEBPzAIv3nHP2qk2qg1b6775/NGTeDzH/m8en+GlB/vF5f3y6PbDb9zs9Xf/7A/+66e/uv3hN5NKDycvrbRrZOUffTJ5+T23uxtkQaIhMkyAdQvMVlxF1B3Vjbq1jta00/Bs0Y/Cxt6QfuICIDAcBZGNqAnp0W8JraJVbBSd0VaoYJTErcJxfndMti5rRIxcpdDgg7UFQdtNZ3qyUjSL1mkBr9LLdDrp+269nNdjZ4z23jP3gDonUVpDQO8kmnCiblb++ff+/Ac/+yuu4sHBlTjpw2M6mhbPjsPN/Utr1xmO6/utX8n1ywfTEqd3vyrwymU6CieLK5O9cd23zSO2TVVL7wOkFwXIq/aagloVbFhEQ4jMbF0RAomqsVYlhBCZIUIiaowVic65EGI1qkZVlRzgGBcjU/IFcz5rJtuprI/X85VrIkjCDEcfyJIU2vIrmcBZ3pcN4jXXq20HPtwJqlDmbZneTompDGZOVS7E2z+i2y+Q6+45BKyiSeq7nUnP6VdbjFm3t+D2C9FFkpduv93FrwRQhirPX1X6BoNIaYDQB2ljGoQIlkBKieDDSPbKlqUL9bi+fe+bv/5kPbm+0/rOliw9qCNtZL0zHslkhVkdNzWmlW3qS6vowbWiUnaEUmiE2Wi8bPtgg51wDLTq5//Tvz168e3Z3LV2d/RMxidmt9F6QdOFVNICjWIDdEAHBFAaAZMaCVsIGonKOvQ1SCah2fZbc+BP/iCHFFyoJoQGgA6ll4QokHZSiItN11hbyXgpM7d7uHryVHYs7QoscwlKhFx4moWgcIVREbVgB0ywf/Uy7avuwlflmqaNzjY03dCk5Yl6y14pkPYKgLrcKGSFDguQZk6oREkjX1qARgEJmJP/eG7dcuGgbSBYSmncVrGtTj09TUlVo3lbnDCf9CXOH66k9E4FSEXSoKmixAIaAlzTlLvtcdPqIlW/YUMUVWiocZLSBQ0ASBQRSQI83tKNt6c2r2wzETqP/JTXLkRZRJ+Mlkk5sacSGZOtMWxySBk0WZtnvofq+ZkEBhZFgrUHMwBookoZsuktByS7bII1JAknsJEYNNjEZdg5hZdks3GFAVuIEU2hv+ARq4taKBfEBa82m3/5yU/qnZqcmNhVHI22jvuJSCX9SJsxGt/Zh3OVU3vyRd8/HRuvbcOmDbRBCIE92AssqCfjTIpv0w68YTgO6EX4/X/z3StXrz5en9ajA1zeid/7Q39/gU/v4PhMfQO2tioFKvuzeVBZdvWlERXFqzuH+08fPz3cf/DwEYl0S9ofja8vGrl7X9yYr731sbfLn/zH1/7d/+KFQ0POk3hwz8l6GEHhwegl/Q8NqgL2qoB6DFYrDKFQYeVgemNsOOn3xqPVvbNn84fTFy9/9ajYeXH24bP5+5cn49nOvdP7608m67M3ZXJvIQvRzZjbkmsrLGdzWx6uaFwiGhODCd5MfBytxAWMPIoWdUvjhU7nsfaoqvYkzNvDSy6osKpw4QUC65XBNlRlU9XSEjloG9UoWUabmstzF3/rV96WNrTRGgOFl96xo2g4EiI7LqWJDs4660NrrNpCFJ6NVe8JwTD1cRWjpVKIgmqprWl8W+/vvXLpD3/005895GNbi6dm51L5wos7Nc8cVn7lDM6ms7WcPj5rSo7Xyuny/d+fjnGwahaLs2d1ebAJj0QDcQjiywIhhBh9YY0oQpTSWiCyNaqSQRBAIUEkHQDDqUIH54oQoqpMpzPVYb3LpKJpFN7a7wwNt+YbMYkq2Vyom6nSydDwntc5ypcQiwgGKwLeyicS+2KwyBkOMSAShj+QrKbSGAs+t8o4/87nsyq2ZtC5MKchTWUQvxBSuUv3RvpTyX46OxtfLOQ4N57HBT4V/dY3v+jAsLU9ylClbr8SJZWJ5H1kGrv1XONBykaCiBu79dmzv/rZxhzuownsGK3SRnRNUqovzcJWjuoSdYEdi64o/Wi/w0rJAU6oglnLPHQYgyu0LNKv/uc/vXr19clpiX6vetaPl8WlhUzmOl3YcYMJGqCFblRb1Q7wgAc6pFmY0SsCECllNWUl8zDW5Y+FeAi30a3vHAQaB52nci7X4MiICZYW9oTeet71tF6Zeh52z8gvYHZmT2AIFSVdKxctzzSoERYWCk64gJtWe1f3dS/Gms90dqbTJdVLjNc6blCjgTbARqWNANARPKGHhlSz4jCJx1w9iECMGCQHYGr69EihKnHQ6WRrZQBMQsm3ljhHcSN9vmCybEVigqMlK7KG4pl1ADIAxiwpdleFBsGbyJBVlFYyg5XN9nGXIAnZYuYYBGnhkXbTqRsggMiyVWgUgSgTE7OeP+CpuIEuUsEH9w0oBlNopFVVeqZNInuI9tKnqddyYS0LNFGwz+Vg2/E39WbCF05s0iJqZnQPfa6oUpCMuyPz0ih3EEZzc88pmYTIAEbVKiw5ggUctFAuSQoVK1VRfvDxB6eni3pWBulhOYpEhSE2bEiMAJHEsQ0dQnQuaOWKuGkLsUIdyJioXLAS1GjPKQyCU8ciAmYXRL79u7/38qtv/ud/+Ju7Tzpz5ebOC78/vvZ6fePm5vCd4qn3n3zK7Z3+ZMEM2Ha/purS3sI/qlF1y9XjndnnS0+yuO52d6vp4f4VN5u5P3pptHv92cY++3/+399/4+bs+o3mpGcmBAvpNBpKEXeBgEAULA1kQ5WUYy8IpCmex4AQtUHDVHBgYUPLx+vVo/Wlg2vcoXsii2e780v+/7h19u/+/L954Y3vfPz3f3V5Nj689s7Dex8vQoXyrAujK7Mj79v20cPy5Xced95KX2ux6orAZk2TjqpWit6MNjReBOcjLtuVqkfrL8H2EGUXlcDkxQbmAOu1MOg3Vd06hwZkSDdgS5okLD4pHcmGpdieQ/BgLQoXW99TcKaI3rfrxonjQCFsvF9731R1NZmOob2EzhU2Bg/uDdmiYtUOwqREUhVm3B5vXtg55Hfe/vyLT09O5m+99W0huvVPn7x4w5aVm81sizLMe/GOQz111erR8WJ+cvuzk6ePT6Y77g9+/w+nswNr6ijeFYVqZMNsit531hprqQ/BWps8sGKM2/MARTbW0YiBWpVq3mq1nM1m2yOTElZ02y8Pc+526uMkgRhsKSl7YwUdqmQ+ZulSG6jO6WYBgxM/BTo4EWxB7Px6tqLGBLJRmj6SW+y2Cl6okjivc3kwJtrelNv6d+47H1TzLaDYaj/yn6PhhsrQdC7k6S0rbV3z88tILKzE6JEsP8kzYJadg5lM/llpirrM8N2AA6rCAvAQFa6x/Pc/f8buKoLAO22icMRGMQZalZUuZ/WIJ43pVjE4dFb90eyYy8hrQkUYwZQUVVFzE5Rk8b/9ydXDF3ZOnMRpear1ylyZh50FZguMG5n4xnEraAFP0hG8Up/3djmZCQkLTUbGvWpgEqLzdSblf0ZFMpzTNPhmhYlKXsBCCFGDzaNYgPYsLaMT3VBjxmfcf7PC2u7PhVy5rGwrbdpvEY8bqYNqqnmESrz0B1efGx1UsuOXdLCi3ZVOz3RnicmKRr41aMAdwQOeACCAY4I3RSHM6QHIOI7mhA/JNh/DI5Xnwhz5Q7o9CcgzaPJuOlf8IhMeJLsn5ydI8o5/qGbJGCaDQIkomXsyw5R+sJqrFLCt3xl3SP8qycGDFIaZmcIFuiVyI5CMpYjJiESBDBaACf7V/PSee6P+lrNXfjJFt6crmWDT8DYjSCWG0IfQW1fkZRHOiWM5sOF8kzX8dJRTWGrUFI5i07tPjZCmZDBw4nIQiMgm8lYEUaaAk6bAI2WyzBXDijhopVQRV+CaGt18dvsLa1liIGGFVYIq96AeKLkgjCQ0sEyV5R6h9CEQSsNGYEspRAliQQ7ExAXIQC3EkhTqKiMuWqeR+OzMP3j04GTd+TY862bhuNu98bvFbFa+cBivXMONpvv53e7+r0bL00Mc/86rV+4tJj35vtrZXL361m59af/PuLJGAlc7anV9sv7xx785PGtvOnP0/vdD21vv1XOM4GgwrIcQBOhVg2qPRIHOC3lz4UIECGSCaktNLYAd8dM7D+McRRXbpz0f1nf+efXad2f3+9WXZw/np7j2/BtP+7DQ1cG3vv/kqw8ftm6fu3/+4tHOdPbayweWJmzdwnfL0PeoN1z2Wm60iuw2Wq77AiIzWk3UK3vT2R2xQiLRCTiQAmUAB6WNliPqVuoLdeuq8mxhYK1lCzHQTRKoqOUV+tZbtt6HgNZaVgm9BmKSlXShI5HK0WhkAaocNetTQCoHEe+cDaHxXhwLkwOiNTbGTfCFs5Vty9ePbr56eH3VtUL22dmz4rA8ufcEE//owQoeq7NaYeOm/eKXv7x589r73/3Lo93j23c/qqvq6rWrvm9HVR2lFfG2QBQhCFsSFWsNA30fkvmbs4VAY0iXDkfVhC0lLyfJCTA6mUzrepQ3xOdszSSnSQQOZK3DUNSYznURqjkgiLIhzvAEZL4XEm7H2y4+5RNR1i5slcHZaHcwtWJCuhNUAQgpJ8bI8PuE7eu56NRxoSSfY9Cg1BsMcB5dxL23Y0Eq8vk2GG6jc1AkzUMX0UYeoLsEsqWRSBUweQWdbKIJUNKs6kgnhARCeaBMll0iIVyeyH/50YNH7aXd3SC+CralwBCIVzQqVuFULC/ryYh8FVurrUNv2VdlOyka44UqYCQetmm6Kzv+3/7x9f2ruwvfST1eyu4ae3PMTmi2ot0V7y5CxY2ElaABd4weFAkRFHI3RBRAScii+a5OZryJ657xhZha8OSjMvQyBiwMIUocpagI0IBo8yXSgbxhr9oG6sTXu6vo64PDxfHJwo0rzIK19WyRY2eplSJGMcYyVGhEfdsfPHege7IwuwvaX2JnidkK0zXNVjrhDWMDaYQ2gAcAeEgUdIB60fNrDIhp7WiJlVgRE1VJttvZtDkZOrDzjx6ARCVK7lk0tIWJ2ZiRZebtw5J6yiRz2npMnFc5HZQF2yKWnkDBQKvOqh02SchjUx3MTQAbyxZQyQliAEEkxiCaTXdTwytBlLYMZNEBdD6n7GP7RnD+a4sRDIcF287b8G+rrdKhpmwpli6cC2xnJLecJNmjrCDSGISTYy6B86o42ZsYKGsQ2vbJakUJMGAiWKYiy40smRGpE6lUnIz2yk8/+/JZ+3R8WEsRKNooCCABQvrBEASVRWXIG2YYjcWIHYSDjJQ6MR1DBRawxKxkUj4AyACWAolhY5259dXHfuforW9//we/+o0rDnxZ3739yfzWrbf/5P+Mg4PN0yb25eR73y713dXp/ceffx6bZT0JfrJT7l9+4dqNTtbHpwuqMJ1O51/d6fvu64e35KOPXrj2+8//9/+b3d+PJ73CUGSn2noyMY2/AHrVnqhX9JCkVRBWKxDAACH1VIjCBWkM6DyiMyMs78/lRJTt0dGluw8eoywfVZvvvrHnusXP7rpXXz18RXDv148eXnb7z7/T3//q7upRVU1HO+VdP8cXP8DsrX7/W11Ya3RLGQWuNihDMCIYY+O4r6irqauNx6YPTXE0rYIwmBtFwa6DiaANlS15p96JZa0bW7ezKY2ANTFr/iEr7OL+vJpUo2pshFQ1kBhG27RlVVWolH0X1l0nxghzBHd1VTFH7xvnHHGw1vV9A/EoWERiaAs7s0WMsn56+uzky9OPP/iEeXx4eFCNKu9p8TDMtd2/dDguxlPXj2dVVY/Qhfe+++7VFyfSuLL2Dx/efvzkiytXDh7cP7l27crGB2aE0Bmj1rKEc51FqjYhRmYuChtCuMi2sNaISMo4SuPoYrGczXbTURIJQ6hARlQvnM9cHNPox8PmaVh85qxDulgdoUkXGM8n3QjAGmZjBJrkjnlhTNlzY4uGE3F20ItKIGU2vMU/L4gUt93/cH2ct/Oa916qaQTJffSgfQBt0fXBjABpJkn7Xs2Lu+FHsnXYTDC62e7OMIiVc4FXJFWwgKCMXLsHt2ElZagSaUh74Vldf3H/4QcPsXOJ27Z1OqImqDW8ZiKNLMqqFmAsrEMxCfAbRIF45RrdEuuibGrXKK/36/V3X6q/8/abK3KPOoR6tpLZQnbnmC2pPjOzp7q7wC43LCvhhqklakk71U7h0wmPxJGG7iGNX5wXpcP/ceGJIIIFq7KAgChCpEHIMAKYoIzEzOyFe4aHdMLrIE64cGJVuG1m4189cit7eMIWghqrEeqd8Wo06qhocqpOumGsatDZC88d035vLp2EnQVfeqZ7c9o9o1lcG1oDG0JL5IlTeHeilUVhFki6xkQ0qopoTH0HkQytV1p7UFqaUH5oB+5xXnAPbRtBkyArF+EheQ0DbSHvb879zC/+4NJKgpDXPefmGGndkgIqUxxR8nJEIlFaEU14fwhRglprVJXJZBcRImZDnP9uplsnKR3UJEkCiSRxYO4/hzE9hzVJxsNT9UzYmGZ8LMnVABhmIoQoQ6QxTA5lSD+MXJwTYVwHwDnHMQ27o3SSJAaGTWFJTGzIAAZEAhKYxMBiYs36LSME40gd1AoctARGjErMmIPTO8d37C7TRHREXAYHzyAVZmYh9kQd2NvSWYkdojHOSWiiWjWWgg1irRMnxitDClDJYpSssoUtGDUFQ7G0QZuPP/vozff+9C/+9P/0VVPcPV41h6Pazp48W/36o/9ycuvOqzd/L1bF6fz+6fzJSy+/euX5dz78wX/C6dfz/t6NNw4/+ulP73z5s8JNXFlJT2+99d8cPFxVYXLplecvXb20edgZzyYUXS++CSZYbYVaICiSayOIyAIKjQQCwsC6MKpCJLASNHfDvfccxqvjdfOsdZbf/7NvNz/+wXwen348ujRu2dpa7T/87UeLt1/99l/8T9/83X89bvzsxh9W68/YHYPpRGMRNlX32PH1YxxuuAyKRmovVOt6R1c7vLHcV2jHHEZonawfP9Eb1a4zphOZGeejmbLtyTRartFb7UoalUZbxkq4sXUw9vxSj7C1RWiajU/IqgHUMFiFgwhWzAFoVXuRCJZ1453lKC0Q+jaE2BpikKwXLWgT+qgSYyjZctMsV0tl2t3df7y7e9na0DSr1ebRweWaeTfIrfvPnlEw/V37wovXK9d9+E8//PSDisnO9icvPH/t889vLZfH8/liZ/b+5aNRCIQ2hOAH5EySfXwMwVprLQFI/y6iIcYB11UA1loRCX1fjyprbQg5CiZZN2cj9FRzMpJE2zpHBMt5rZuPzOBKkQtXHl6TzGDrg5MmXRaJfR+Mgq1JSsq0/iUgyRpTyxyjDKk7yEYGKgm4kvMKyxd4ucM/L7Kd82r3HB9WDGTrbfnVbbHNUz8pJavqBKblwSa9kNz+J6INJLnwJPt5MChpTjhKTDk2qpw8MPNeMb9g4TyXm/Szjb3/64+fjupr2p0Z2YX0pFVsU8wzYDSlnCZK+GpnwhYCFiHPZRX9TJtCmhbtX/4rd/P5ma3dr9cQspFtCG7F0wVPT7j2snsaZ8/MzMxZzySsDK+F19BGpRG0oJZIYuYNs4emhW3eGG4/XzYGRNCYdL6DwS8sAzAh781jdmZKPS0JNEhnyRActIO0TjbMJaSn+/cXHz3ZOdirC9gAHqGqRBqsKpxd2S0qGltYz7AwohCartzrC60DnpvLeMX7JzQ7of3QFLRQrEBLsGd0Sh0AoIf2oCS0opAXAkSD+UhMNmBKQ4sG3Sp/mClBpdimBg7UqvNN+LZogiyrig6x89AB2iWgl0ggw5S3NokwwdlxGhcfVxCT0DbCIQHRxIlKHUnBGXYqbBElptykqIHBzAYDDpVAdUkJhmmOFESNTDJARYMOQBMqlE0vNf+GDgxtQjJCz6A52BgG0kFOQj0RBQtJkWp9mnGjJKuNpGseThHDsgEAZVVYm6jdGHYeQLbVlJRemTxbBYZgoRBNnhCkEtgwLLhiFNBCqaZiYk82p/ef3HMzlkq45JEsJ7waSVNQhNhA1sGoamACODq2tvcoyKl1QWBd4YKVHq04ZkvEapiIRRjiIKUpatNXrVCwdve0lZ/94L++sP/K3o13qzffPCyOPB189ai9v4r7b79947XX//GH/2nR3DOg117900erR8yt1t2Lr9/Y2PbR2a2DGy9ePXx1/nR1fbaz2wX//Buzd75/eHl/c9yjU12Lb4QaIbHoQUSwgEDFqESkOD9Em+RhZAaCewYOSSVtARkizLqOtdbFmlYPmwcf+3df/t0fffzTxbz98J/cze/S9atdPb78zfGzsx/85M2DqxTk4df3rl47rEaVt8f7dahGB8Di6elXka/NZSbRBgoTLGbWj9FVsig1jo2foh2hta5dN0HO2r39UQvE6DyXyc21QFUgOPQF9Ra6SgR+lUW5I7VJ3j4U2Nb1LEgQSN9Ha6GqMfQAr1Ynwg8FzyRsouioOiStNt2CsQYvRBbWQiR43zJc5aZN/MYaFu7UklCJwk2nrxdmf3d3L/ROVep6fyZS2F2DWR+al148suWx0AnifX9Zjh+vmqb1MTw9cc69HMPq6RNf15PPPv3iVx8vx3X5+us3dvcmvkv6hxgl9L53rjSWo/RAqVEzsiuSwCvDJkoUFQWste2mrevamKQCyvMsEavGJDxIu9Nh36eikjXByKBxYuXkOyQphoaNlckPbxyEg6nG21T1JIq1ZjtDi8KQqlI2m01+win8INXN5O1HFgRJGzgIJFm1Uw42ADBYDQyuOTgvx9st7rASzCZJCaSjAfJOI2q+VaHJLSi9v8EhUYGkOky3G5KLniIoISmf1ZBQGmTSLQpKM3IkYwNgowV5j3BQmx/+7NGqrUeTNvQcjSqvEAqsxlIHMLNFbwFGkXyqxC13po1DYKPkrIlziVfrJ//rn11zLLebvlsRWRdhe0EANzpd03QZJgtM15jwnHQBXVJxprIm3QBrzdXXEyQAXsSL9MxdgmqJE/gllIyx8medo51SqgZIFIagyZolPzKhVzCzVxTMgaSUoPAq3hof0Wqz0Kuz4qdfPT31V2rSGLsNuMZkhNUakxEM8eVRgeBjr3BUtv3qsLp+bK+dURlweGana53MZRbXjDV0DV2qaYAVpBFpAIA9Q5Q4MgIziQrRoCOXPPamHkIRtnA6QKqx76UsS2i2ehx4UWTSrZf2I8RQRI0JlQeDk6XlVuqtAKEwJqrGFIKb6IFQRKHBz3LAigkqQZG+KeUlcIKT049eQWCT7Dt0eCwzXziLgrJuUIlSUHaShg1NAdKuHjmRlzgRnlVkm0qSIKu8uqZzUT40G9RlRS+nx16TfFljzEsba1mFYEKMxBxCMIOqWLMQP/f4KRpDVJJVHLElZVVOHY6CjLGJ0gtmNkxcAIWkvGkIGGSTlIVRiB3r/XuPNqbd2dsJpp/ibGLWozivsZ7JakIrUhVYgQ1iPdvKajJ3EJZIxE5lI1oqWWtZxYgWiEVUmwZyiISm78zIwaIDIpuFLf3T4+cf/e3mF7c3b39vffRGtXP1d7/zffgWXfOv3n9nPd+vGn/kmsd3P3mDH88uvfTyK9eirP/iu38w3d3tg9nM6vknH7fg2Uvvr+WZXnoOJ70QODJ5jZYZBOklsKZl78bmAE0KMUQhwwyJIcXkJoojawR6hlERYTEkvgvXn78xtf9cTtWfPRjN6PvvvfnJ3c96tt98NIevL12lw+v7rTxpL+3uupf00fyLk3r/0uH+/uX77QM/71t/APDBtbLzk9isdu1qFps6tLs43bEr5jCRdsbNWFojPTX6ydeyK4e7E3i7KKTuGSLUolpobxEs96SB0FsNFlNRXY53BCw+mkqtUjAGTEVSralqYZ2oGjOTqCHsGYu+X1Vm3HkfuvX8NCyXK+/bcb0TegbFyXR05/bnh1eu37t7u+uCc6Pet9dfvPnqq7MHD++NqnrTbs4WJ0B1/YWXROx6s/a9n5SzpyfHQZu6bhWxKkfW8O6BBXBy+qv9w8nIHn19/5eueO7pk+ax+r5fXb58NKqr6WwyqmdGSuKWmWMKskZ0RdnHJjkZD8st3Z6CKNL3IY2AfYiqYoxVEQzbobTxGaiSNLRXMjTmidqUA9IyWCmJwGzSDKGJwUP5ryXNEqUEX9UYAm0vpLxnEkAlRmYWwbA5S7eQBhHLAjDniZxBMhB/cof9/wf3De0+Bh4JaIBxgAFEzpZ+AyangwNf/lspQkkSHJLu67TXTuTSVK23oUdpg56Kt003vSZiTSyAzpDVGGBFA48r9/Bp88MH7aSuKtsDxdovVQq1tF+ExcoGUSCSAGAxAhJIVNEwrVezuo3THSvx7OT771x6EA56vyqYo+EoEHAQCmoamq6kbmga1iTriCV4Y3hNuoRZQddQT+QJAdAgFIh6Q8LZdUEVUSWmYTHF6RBn5vp2QygZZU0hT0n2JWnCTx+oqodYUEfBkWdsIAbK6mDDSfebXy2M2ztdw9ndzpS1bkY8OY1xt9yI7lNnDUkvVNpRh8108u5DPVpxJdidy6TVCc5EFsBasCFaE22gDailvAPuAfi0OQN61YEUpknsK8OMl7qurUsNEbExHGNMj2he36qmLK4txDI8SwPkrBoR0zBLQ7yRMTY/xlmjpHnSZY4Ss5mWAJzCKJlFDdNgDZscMCioqqjhrd0j0vcY+ASSDkvmG4pqrlrMyT12kCUMmNE5CTnjTDr8vQs7HIAkaow9K2xRMBtRGU6lJUKMcp7yKwIRIu47bywDcIULIThrZZDJa1RhMLNlVk3bYUkx1JpW3/n4mYS4J4ZJnkbVxKhEliuSQuAUTsQyl0CFWERxZh7mNGGYboL1lFa1LmusJmhmdDbWFUMMZfy/F3bcskM0AgsuGEa10BQjDQN2EAZsSt8bIpcsEwcqNLJVISX3rN7fvfle5Y4W80V8Ou8fbcLTH+3deMWw7Nz5pZl/w761t//2jwMbE3T9m8UPH4/Kyabzq5YiSn75xcMbV9znv/71x//H8oU3vzV9i1oblEKIoMBsxBOg7FkCCEwi8GnhxdYy2EtwBEb0RCwKlYaIoxKzgr1CQNYHmdaTl1862sijZ4+/fLaspPTVperw8t5zZeX5RLyd33tiStcuHs3b+4cv3rxRH3754YcnE7d7dMNX83pmd3cmi7NPX5Z9mV5frZtLpikxH3E3QlvH1YTaUViVgYOQzmnRxrld7O1NxZqee2OYjUyq1jpfUl9pa+EdRyvCUIEIzKKuNRBUbYxJ9IYQeqgyW4lSFEXXh1G9o1Kp9EVB1chax9Xo8IVr12wRDWPTbJarBcgXRbG7e+j9xhYvMBVB16Awm0kTbpGNi9Xi4OBKWc0EQc19yEGIzc5OXdgn1w+exb4msEgHiA/r9VL7PraN1Adl4+Ps0u6ly83R9ZmTV1u/jhFPn548fXo6Go9m092yqqrKGOsAbts1hlUUkw0izhljTQwSYiysjVGqUSUibCz6fpAeZQQpmzTn/VZe7WS6Fm0JoQMqnfQoyMQrwm95euTarEgiRmQ8OVlOcip7tPXeG26DXKoHpCx10AM1OlfVdM0MPJbkAoKBowvJQQn5yCHdtJTykXOa+VCUMxFmkD9m1mn6HzrgjQplMjoU4NzN51QWIEW1qBLbYZhIOmGbF+psLJwIcWYEU8Xt33/whMuZNUIaH651XE4sU/SbU4kkZWgtsxjmaDPYrZ1GEedts+ntZDLvzNUJl9ev3VpRxRsLVTIB3EdlIFDRaB08YwE0Qg2hIW1UGjVr1jV0rWiTVkcEHuQVgXKErND5YlsBEps4b0PaASCqydVLwYpIwgKBilIgEGABIgSQIQqqgYJFx1SAOyMNSofTu2cPvzb2eRMldNNqM61rdI48qwb3RPi5EAxTwvCLIN3Ls3fvxCN2lddZWME2wJqxVLSkDXQh0gAb0kbRAgC8DuTRHuKJA5FkaXjuLmPCgXVQvSN7RDBRsoBWIhXhhBsPdMJ0IrbtHpEOySd5v5umUMkKusyHzp2aDinU21Ch4ZFOEAoRSKIQwRTJgCgbZkoU5PYzPc6Z+TCcLxCpxkHkllYdWRKYzwsApgFuT89oXgLTtje9QHQnsCKm2V8Ge5wUzSlDOkXGrm2ag9NXSU9FyjoaWn9mzmphURl+SAZJhMVpvCaymtOaCMQiIKU4vGZVS4UIE4zCAY7VQUulSqVSqTS6UIxlRgsXFxMsZ7yZYD6hzURPp7ogCGssEA1FVWrZ1lMPFSqg6V1Yooq0z0WXUwEuQAVQAxNgrGZKi2J8htlKpy3Vc2/Xx5sX3z4srn27eTC3H/3nm+9/1xwg+lPMVvvXnuORlY8X/skDltjbvXJ1oifL8sa7s/0X4/SAyt3Vh7+4tzl5EOIrB6XsFdKvTZq4DbOxoQ3OlrH1MIKNSVchvMtzVARTkMjGkggTWoNKNQAthAECCmaJsjDsxtXRVx+dENsn6xMeC0/a6OajfaD2btftHtX1LuzE9Vaezk8nd9sXGvPorGlX1u1e+fXDz5/Rw1nV/l/+h3fqEb5oV4irkppxWEzY12hqXfWt2FUFH93KxBD1ySZSVTCLDZGZDHSk1WzDlaoE5czdVIJX7tQFYFWP0cMmZ5YQPBOIbSLy9n1vC9q0DVFnWEOMIYAtfC/L9QrSbtpVovsXjn3vL126ZAu9ceNVQJaLpULremxdaA5C5fYWq2eGJs2mXTYPoAtruydPHhir680DZ2Y+zK0NrnD11JYje3BlXJYjiWeIa5Vi4xeWDseT8uTRz4OfTMYvHD13hVhWK9/MjwtTM51WlatGhTUOZLvWRxFQCNGGEKy1TNS1vq5Hx8fdaTO/fHiY0CRkSoayYU16isETYyi6qgoQpwVRhiM1+dtlLlMqmbL9vYSv5VyjLVa97chpuD5y/0vEhS1UJQ6saM0EEE5Oc4oAYmbWC4Pz9jb57V+63T1hGBpU82xO+RdrpiVjIHHnWqxpLzbsj9MLFzAJKwyDEy0z2x8k3UfiDSuIrcpwnbLd/vWIQkVVJUbereXnnzy+t9y5NDPzTbxahfeu+F/fndvZTmCYGFQkhMoGy5vkQMACUE0QCmV0e8b0aBaL3/s3R6fLWRujq3ZEgwSwsiRjZyVdA41QS9QYaRQNsvy3EW6YPGun0qmSJ/KqAdoLoohPRsiAaM7mAUFUZeiHhslNkuYl/8x48ItI6HsSdQMsapA2U12JktM7qmt8+OmpbCbVEt6zBCCYUJatLby1rpxYfnnNK0XBQkEigxp349SPdvvKPmMsJSwFDbilbKOT3x2xh/j0ibeE9NZSlFNQDdDMxqLB1lRUEyM4pcarZrqZNbx9kgfZUC5+23/ZPl3Y8gsy9WAYmmNkohyRqVmiJFGhYq3ViwdlyDJJwX55Rzsg1JY5aegHD43Ml05/f+iVh9OQorqEMWgQhg8uT9903kVhW6NZWZMgd9hdMZLLXhqQ0zvP2+l0aQwzOrbkK2NYmaDqvTfGhNAbY6y1Ibl34cKaOVtepkRI0KCBBOW1DhODDBLOxGzZwbJYEYatWCoJNsIaLkUrkUrNzJZxUZM4XdW0Lvv51DRTXc14NcGSJBr0jIA+UfFITFFMrNi0OWdYCAt66G8NvkBBNCKdaZhw69wGrsW0pdmay85WT54+ffLPP3nlpXdHp/dGl0aTa5f9w19dvjLjq4f1ft3euSUTM3vrj3wXeTbltV989Pf1tRfa9lQ//JfTZTxx+6dvv1/fvvV8JRO7Pq7ZhaRatGSJnQgCWatIfIHUQ4l2EiNYmeHAnQ9qGIQSHEQCGCItYEWVhcm4TedfeuXyan3p6OiVf/zxPx9e348WYvHo7CFJpezuP10dXBm1enb40tXju5198bDa5dfs7ItbXzaef+ed9+yR/e57N44qofn98Lh9GkNJYaJNLQunK2yqcVuFTUsdb5qwKzAP/+mkfW3/4B3DrWdhS6QEq5Y3E6uq3JMNsKLcwW1Q9bCdqUJlLdSLcAo8ieJFxLDto0cIxrLGtpdo2ApC8B1ImUPbtb3vmbXtNrOdsbO8Xs/7Xspy48NKgpRl3bXOVaOdHQp9fO5ov/fY2yNrrwXvFb73vg3i29eCD5t20bc4nR9/c2fR+02zecrWu3IE+/To6uTgoPbePeu+evk1nK3u6+ro9he3VuGzvclbL1y7cTI/Kdg9fvSMuHXlaHfnsqvGRdGHYCQIEXsfQADD+75pmv39/RDT1mnYVxJF0XRURbZtPm9r8LlCV5O3RVYf5qEvF+wEv5GI/naUWD5fFwDhHJGbyjcYiiSTSrcPMbMoUpSTqKqKSZbUua3fntr863z3djE4HLr9x1B6KYUHZjnUsCA+Z3JCk7lESqYQpHdrVEnVKDGooGTNk/Lf1aYarMQEQ0QCYRgIIWVXGNuHwBxI2VmaL87+8ZarJlUbgnPybLX8X/7wUmGPf3x3vV+51kcrLrDHxogkLouGEEmN7Q36nqOeOXNzZl/bu3zywFOhoQhsGTHjfBQRoySec65PLagZpsMGoRXeMKIQeYIHApGHRlAAb2POBCqqQpC0AEyjo55f6IkMH9MolYpyekyII7MRCQRR9SBKAlZdFgRDhsKz5stbnrmWU6EJk4e0KiMhV3K5Xo37oPuNqThaC2n69kp10MWDft5wBQ7QFWGtuoFulDxRC9owddAWyIQy6GAgxBSFg0gkCHHK10owjYgGa+yA1tBg6gQoQsxkQyJmNmnJkHQEwort6RgkaxkBJt0+SDqodfLjM1iDpSlUotAQ5JBWGJornSaWYhYW06DnG0CmVN+zEarCsB30b7ncCiTEYI1Fso9ISQyUe4PBOz1/Qc2trRqwJqAIqSOlLXsZOM9okIE1KdAQA+c41MjJEXpwFMkrPNGIaAqbCW6S4QEZmqqtXUmyaM0QAEjUgAyzgVpRQ6keOoaDrSFWuOJixLEKqNhMuMHmyf1bu7at42ZqVpeKdhIb1x7PTDuLc7fxJNCQ/iPqAY1BlSqQY9TJzxJUgHqIRUJwkvqACtAENOPoRguplma8CtVKx2sp1xh5rucBV5u715/86qDaFL/SrltM6Eq8++Xu6y82x7/euX7DuPny4adFu4vpUWnm5U/+b4sQ5sE+qG90v/PWRJa7iyeT0eYgzj3Gy5mjSmyLuPK2LXrbm5aJiSydLwjUFMIiIhKYmGJB3ISgbdNNZ5X61ppUwiBqRGLsFpUZsdpmdbZTzZrj5vmXXzo+W8iZvPPq7y665evfe+Pq0cF/+H//+3CPv/dnf/7zD35gKmumerRfzrm5ezZ/5+bVOx98+IOvPnrzyB6OqytVq+18BysT1rQBNqFt+sudPdsYOy9u8K9q9/Xx8XV7o9k5dOxFSTiQBIGgHHdSrqJCQAE8gptyKcqtVn05sURBIWxSuyFEShxcCUQD0qgBFARdCOT7LgYxLIVlO6l8v6nYGAPR4AorCG27ZmYgLNcnXbfpwkgC9bFxxXQyrovCtq0yLBsDlKORTCYTBhfusgox3QQFABKwXi/73t+7++DsdPXxndtHR5Or1w8++TBM98Y1ja8eHYJvPD25v141Xbu0dbxydd83e23bPnz4FbOr6tnu7mxST7z3IuRDZ60FhJl2d3dCCCnkwBorKgQSEWOGxO3hA0+WcgAoZchw8gLOQHUCjbfePSLJanGwp7qwS95OyQCQL/VMepLMvpChTqfdkiZfwmQDBEA4pYhSbpuJtt33hXo7hCzgXD2U2/whXCGPHOdrL8Ugek59ZtoGIjUs+ZYlVaswqgYwClZYgKGsxKombY0UBpp8w9I6nACocMUIiCJ+NuL//Z9XfXkw47WXAtCey//rXz2bjVFnWvqISCh0AEMrQmSFAUGCVCxBuCs0nPzRe68u7/cEYsfCqhYslCKsNNFtW6XA2oi2IE/Uka5UO0VrZBM1ptLbAz3UM4JhiUiRS6IaFJHSJhhqtkhpLl8DhpmX9JLlWPn/jsMP1xAHSPLWB9AVPfmlOriTk/benVi9ZGUl6kUrcG3gOZLh8VOu2rAsAENWoJBWLl0+whNDc8IU1IEaQ62ihbaKDdADm1R9ARHiHgBpTHZ9RIEBUAQJZ/PklJggAERjIvrmuTbxpEitMUNpHDKoodu3rL8VbJ+e5lxicyWGDNPmMNFSrmRpIZw9s0QzaXB48EFkDFMgDBGZaft8/nhn9v4gUY5JXztIjQlM7Jw7H9+3vLA8KA9g1fnpoHwACFuiBw3fOn/QQ7ucuhCJmZK51SaliT8tqxSJraZgCiF477OIOZ11TQprgnICUUADMgYiWAVlw66Ei8EANpMgLWmpXBupBKWi4uB6Oymmtdt3vsN6Qs0Mq13jx3E5seuRnNmVlwU4ABEUSIW5BwXEgL4MtrRcGTGiNdgBflj9MmCIWOFUavKVO41VQ5MlJgszWdC4o9GmL1uMa3r67HQe7aqe36rnvyopmC+ITVud1vtxZZsvVieP9tpTC16wOTDVU1M+sMWxjGkvjNa/6W/d2R1XJ23z9MndWX0VElZV0boacGoDUdWjj12kVtmyWk1AGytpKyQm8gLoSCh43zWN40Y0ip4AbG115+6v7tz98mD/+snJvbZp2vu6O7u2t3d1c/b15T0dVbszt1zM73XH9tcPP6m65dGZfPH/+PczsMKcXno0uXrw0r/9/mjq73z645s7uN4uDj5/etCHxY39sGuKfiVzkDe2CdyUpw3Z3l3f3N+jX3bt0fHD9uOf/tUf//F/c+na1RA6TXoIBQmVWE/LxIljD+fFeZgaVWcqG+LKWE6sHGvJ+/SBAKTed4pQOCPRe9+pqjEk0msEVAwzG0cEy9wGTyTWqgglvbz3m+VqGSVM6lpFVZtxvWsLJkN99IYRetv3q77zSesBDL4YxhAX1aT81rtvM1MM34GIRCDsz88ePmw+m00PGdW1a9cfP7k/G1958uzzrx7++PLOu7vTm9cPXl2tTudnza3ju6NqdvngYDqbjes6LUEXi9XTpyeXLx/QsI7igXCFCxYBeZilbX3Nwfd5H5wOqugFsG44y4OYmIbSu0WiExScih8NLFACKSSd2yTDSBMKM1lrQpCcWZiSeTStoy4U3W3KzVCDcfHXMOKGOCyS88vii7+fHffB6ZaAIJFMBsw5+TMYhdWY6isTWyILGEKRrlJVZhTDIc5wN5iCaIyxHpcf/ObeV8+mswOWMAJ79gJXeFSnm2BN41Us+QiMTBHE9JHVsxomw+zFizC51en6e2/OrlTTZyfBlQatEhARsnIjZIdRdIidmJ7RQTrRTrlleOhGrALsFUG1h3poUPgoogiESBygQjqYjGbv3vRzpgF0zp/3sDLcmpgmFhsjZyAkVyprmDKfq9dKqh/96iljTCtWB/YqQhJUNwwTKjPHHAGtK1ygIAxZ6Wyy75/2tEAMygHSRLTEPdBCNsL5PSqHtPf1AECRKAAxLUnSMCoac4eRUFAa9GwDAIrskCKJaqhD2FEioKbnPxWvRO/fAtE0hBwMjUpS1xLIJPDmwoOWv5lcoD2KKCMVex4kAMPJAW9ld0Mvm98O8l/JL15VYkotMCZvrJUGj9kkRch8L4UmpVzCetMWSVKxT6FPyqmXyzpgQowqGTo2xESibE2KsuQs30qWdpy2SGwtALYsIhJiOknpp8QgmLSeUKSWKdtjpvUgAyA2KWIRzAQGc5pKxSgXgCVURl0wtalmZZg/iutnExtmvKnCmpvTEvMxFtx5biyWgl4kxWSF7MVilNEqnKJWKgCrMIQSPEbOjykAghYI1jRSeRq1OvGh9jTxKDbMHragZh+dbZ59TYtrFfa7ZYF2hM0otnwS1Bs8vltaXvJsVVXtpavHMbQnj2G7A4e4szPvTqw8rumwvXv7dDR/4ZVHdSAvlwLQVrPYt0rQRFZnYmUIkzAEJCSIEtrgrbQvqf20sCuuwknbiHpozzQK7dmmH9+8/n1moXDFHtmjw9e+efRgb/cScbx3/9lrb22enT6+snuFNm1oTt759httv9y9/pCdF2dlf9a6u+2k2rv0ztH41c2dHx29/Nz18mDxzd/U/tjhmu8UnkJrfWPcyh20m8Pul9f634i0y81zx1+dPvrm08/Kne/9xfOIOR2P0lrd0qjYBC6DcEtlC+fJVhiVurHEbdeGwllEYiZrAYiKEKMoo6qItMZw6AXSE7NSSIWEU56bahBOCUUhCoDC2tIVSr7vLBeRYFQEKl2/6nqeTEqyrut9t1mF0DMiYGzBlp11TFREDYBEb9vWKzyphRZs9Oq1566/fCiR2/b/R9a/Ptl1XfmB4G+tvc8+5z7yZiKRBEAAJMGHKIqiHkVLKpWqVA+7LNfDdle33R12z0zMRMf8PzMR82VmYj5MdHQ4OtzT5bK7qizbKrkeLImlkiiKRVEU3wRBEEwAicybN+89Z5+915oPa++bkJshBR8AMm/ee/Zea/3W77H59PCjw8ND9rra3Hnqxldv3Xo8OLp558+awyuPXf3i3oKuPXpwtunv3T+8d/8ulA4ODvYu7JuI0I6Ec5RTtkgg8+sAHjbiOK9iUoKJyMI6CxpZO9W6Kt5CalId9cqFveVamYSfqncBkcW+bWVOWiBoR1BNKTH5869R7hUrkaCCX9fryf5WQLayvaylWcv4Uhyq1dXuwMo/AJS1rqUhOVVix/ZjK3zNZgnOexVWZUIAGOqVGPBQBnnz7SGyJtr4OdILT9ivV+u/fkv2dx/ph9Mxh0BN4t5nEU6QIWcPTpkiZd1bXFyv+6OYWHbGDVJGF1ybaDiTi637xlOPP/hobHzjNKUGxjKHQFXYJJ1ZKTNFIMMyODFAR6WByJgaiEQJlECJkFREJIITlUFFKzQvAOS82ylM3oK/MteZEVUhyyq2QrYAnETMImumIJKEhODzGjc/6tkv6JilSa5h9MLBU8DImyasNYXMIzNJImoYG3R7k7xJbk0qpJGpFx0kRfAIbCBJMAIpKZLCvK3BNMICF5FURzJP8aLDoToaiqnXSkw9FU6SqCLnLXJLVc7+8BNlCbdFUWvEwv+dsWNK2fnzcGuU0lkPFDOxrXzBXBpAOxL2jQqxkR/6o2XeLi+lbgbL35xzKiKSk4iveZx1gFdRzSmreVMSnR8YgUHqlQpNID5XJsJ+PkIhOxTxoVbEyznOqoA65pwzzIAvC4HGnKDqvZeURZTZe09ETusag5nMtkbELEcs3MOVCCZyTE7hRRmuLGU5uOwSAlzwNGWa4vjTmz/4T/9WlrcvTIdpOt3ls12sF7Jq1kmWwBHwAFrczUHJsg1EBeSRQ5YgPHUcWEh4xhDQDqhDDK2Ak6KXbkWzJfbWfmfl56fj9Ay7GwTWcVfPZrSeNat9OTnjFRAbymNs+n6uic5yt3I7KbTrnXnfdtHP06dvyNHZdO5Tc5eOfujTzn3c9XHw95b3+yfu/zzRrJPdnNAu4/CAp3HlcCp0gnwk8bDv70esSM4gg4axi6sUnLu0t/jok9FxFDkzQxRPTZIjduFrv/R7H908GeNJN9nbn137u1feuLh/7Y1Xb7fd7OrVz73zg3euXX0+SXAicnzv0xPsPf6ll/7zv7l4CfKIn+WzOINsPtiLJ88cPHX1+pPLw5/g2vTz1z6z/vilLHqyuRZX0Z8N++uT3eHehc2tnXyaT1k3z7x3sz96521Obr3keC+CBKnUBhIjpep8sRzBPbpe26hh4oZOe6+5hyaI941POaWU264VySqAZrFyKMJOhASUGhARi2ZVdVx0hYIcvGNwHJPznpmZp9A4jpmcHSBmaJK4WqXFwsXNKsZBReAcIMOg4iWrC0EJ0Axy4hlAq6AsY8q6Xo92RL3zj117hhRjSqLSj6udPQzDeu/SmvtwdO94Ex98fPvj55975tLBJUBF8/H9o49vvcPUIwsBnv2YU4ZCEoHJOSHxttdio59w4dVQcsLMbCQjgopkESGGwrHZUJNznnOOrAz1qud2tcSFxWlU6XoBmFMmV8IkAdiqLVWhpmvZphRWryADWQ1Ys1Nb9I51NKhkZgW21r3l6tMKfRsKJ1lVs/fOkTOmGUrSLTRDMxOxGi2SAxAsjpTgiYKAoI4RCF4JvoEEoBFRkHcDcsssnOGgA8+m8sev3Fnvz3dy3HGzS92aor59D810Oq5Pk5tBN5wgDLC7szxRbTvPkjY7frpeC2JIU8Lq+J/8/lNx6VKk4IeRHRXjRIYi5QSBY0cgjcqZJQlGbdBoL5qSWvAC90A0qJlUwIlYFLYozdBUzK8IakIoK8TF8Pd8j1+Afi2IJsiS6l0pEhrZMjKJRY1t2rNvPjk8vL1Oe1OXliN3EAcZhBuK3LjuVrMT02loPSeXnSZRdanpjieZPY0bnwISNAoSXCSjb+sIIBIiWFQHzT0AoQyMzDlhhAo7M0IxeEbKE2XEX4J3rrLoVUW5Zv2g8pi2jpslDRBUcJ+yU2WW8jQasaBUTLadKJklM4pBunEcpPzS1qXSYTsrF1sYKKBUch4riq21LbIp2TKcQOYgQiDPXkUSki1cXN00s2OIAYFb0dE5bGQuWbbrLuZcVrbpYfZWOVeiYGc2GiYQLl5pPjQlmhOSU2JoSjmJWvJpShEI3jsQQA4CFS6h38RSdj8MVUlS8DJiteengTpQcORHbpinXkLiiQzcf+dP/iisbj865Ymup7SZYT3X026IsgSdMI4FS9DAEEWEpoQEyqw5U+fIMwVCBFrhhpFL4KICvunPeOeUd9cSVpivsTiT+RmmS0zPaJIEl/h4R0/mdH9f1rt6P8Xjn/K+m1/BzkJOETfiVSBN5yeyidg4HN+SO3c8PNbghbr4/vxgX+fT1PencT1100l75cP7fHqYPj1bn6ZOdtpTt3d6P+IIfMLXpo8+/tj+g4+O/aRpqV3dXyKtqJfbt94aVi6OTRybLKNvmLDmJj5y4fpy+f5k98EOXX/jjVfWw71nnnlqvV4N6c1H9p513cdPPPHEmI7PVvH2/ZMXvvKlj48+xPw7z31BxXnZFQ5tF+CvhT3+SJY/37n87JOTJ6bL93NcT45Dv/7J5eHNgzTZobWmE9ePutHYN3yy9/aH09vvfJj7NXeLJy99IX7qlXKrxM72Q7MccmgSWkybvsfpSkJHaMau46nPOarKEJNIA6bGNyV0E8a6YOeM+Gc+UykOEcg2SYpkQLlpmF1KKdsylcp9DoLznhyPcQyOU8qhCyml5fEJziNtidns8DWlpCLMjomYPIjMjaewDkGjZOviY4ymCgghdO1iNlkQcUrX1uvhbH28N320mbjvv/yjL33py1euPXa2Wu3tX9/bu358cvfo7PDk5vLi3v58Og0+kPoxp3EcAIqUPBElBTGYhBIkezTZxiECoCnZlsubKQcysUIkqjrvWoiKjqIFeC6LWhsYdIsRSwW6C0BXPKKr4LhcLNu+n0iLNsjwNFdHCdTfWC7AyqTRh9e8KMi5bgtz+aM2alTlFJG1DgyAHStY4Zga0UZzA2oddwpHZg3PrKzwltGivecu+BSysJJo43zx98n5wq68c+vwp+tusR+Gfp3TeHeEDI0gDHEUdCqZNDqnpMuk7Jq2iylKz+yP0zKE0Aif3Ox/5+t7j0wnZ0cxsI/cBqQMp964a1sZswJAghbYjVK23NDILCKxInHKlOzzIAgxXHk/SDWV0UiBylkFPB7e+uFhvRmbhKuk/tjcZfpayuWdpiSjzhfh50dLiIKjZpYNUUMOARoh1M2PdBnYQeCFiaEE8Zmavh2TNEJMQBYMhAREaFJN6TytTROQyFnTIEZ4BtRCBEAixVwTxW2GapgztrwpGIojKpXvTSpaQ/ZMegti9sySJUku9dTaSuMZlTUw6iLFNDllR2vvcfHtUNVswzeXRqd6T6K8HiMel8i/optCKfzO2a5XtCae2TxOTA5ea/hEPTtAQZwr6v4QHMXOVIJqj721vwUI04fUAPbSKncKei5isgamrCTKVomYSVXGUZi5CUFt2GUy3bAh4aJC5JkZYBGCgtnZEkCVHXOGEJg8JRmZiTySRA4MR9//87+VfrUzn3A+dUgeiZFYTT5Vugs2knM0SxUCq9FsBcLsyBNYzXpLWEryoQdIs1IG1pgu+cIyT1ey06NbyjS66R6OO/RTOmsldnw2QXJjGM8ejPfj9MJTPLnoBkGfNaEfYqIUHLhX9AmUiVvuPRr18+t7ly7l+w/c/Y/j/Z9ff/r6N/7BVz86Go97d7jhw767dTa/vZ/S3dR/0p8+uJ9jnyhN2+l0Z3b98ef8yPFBDOov7k+aFm1Lfb8+Ob6X0pFvdH02Lk8/mYaDfpM+/4Uvg3Dn8N58Pnvi8b93evYgHf98ffzJlSufg4LEvfnGa5cev/rxzdt+lzGJyMQe3Q7HlfOL4cJ0dXb8N7uTqz6u0+Hh41dudAuW+A7u3cU9jBNJPSCz++vLd98OH7zznspKEb72xd989ODqsj8JTZNP/XQ2nXV+oEFHpB40iPeJs3be9dIETh4bn1LxtcmS29A59gr1JgZUy7WCSCLxdua6rlOVrNmsHCWLSBZJYBd8SCnWyHrPjlNOksR7z+amqnDMChHREEIckx0M75jZVVkdRAU5sW9EoTlZHAK2G1EATI1riDhJSmnN7Blg7qZTN5lNcs6PP7H36COPH9775O6nhyenNyf7r+7OD9hdbYa909V69WDdtdPdvW5nMZ10e8FPBDGLiDFTSDwYCaJNJmYXRcrlVaJSRezfJGfv/SR0m6FPeRRF8cYCtvtgrdZZ1efE7vKyMC5hTTCbgXLCt3SrrZSiMDPt2mGFWtxg2VhvB+WHYb/zIkzYcrsBlOa7rqa0anzLF4FX9ib8VQ3QINkzt0QTRRAGAigQe2hD6hUN4CFBAlNyAtLMJb1A2Oc8/tX7afcp361SZt6sc58dNdl1Lg0JmLBGplbJk6aGJKWztcycH0mEPUPwYLn6B1++8OXnHj29L0xeXCXHct6G87BJuO2SFkgUIJNm1VE1A1EhOfce2UhJCoEmMsVRCfEV1awKIjHf/DKsWTPD4CLgVlRN68PXc327VSUrDE0d66TMwhDp37/zIIR90Q0pO7ToIZG1bRwfU78U8UQxk2cvmkihDRq3bsY+sWdmlagkhASIkCawpSxkQMQMvMoAmu1nAZkLtNr2zLjIZo+SpeIm9mMQHEo6rRU2038Ydcl+tiQCC8FWVMtlk80UDfV5pbJ3ht3Wk1VEzMqNHWnedp+13NojaRPw+TNaVu4Z4rZljyhL1izKZgjMXFoKAQDZusCWl274eXHjKpgQofpBi5hLa6rfVFhrA7GFkQrQXT9hUWxDorUYXpZYrPNewgS89dmkghCKCisTOYXtnupcLgI4Aik7mAJCAOQMhS+7LR9cYiUSH9BMm5df/ek7b//08bkb4xk5JQizsgggEKHCXWMoMUjZuGoEIZEsksmRZFswFnoKOXOxABgJTsCZGiHOcL2brTFfS9vzpNM+oA8YvAxz7hsdfB60J4zE/ToNn2AK9buUPM4iOfFe0xAZE+KZplORmPreO+T7J67dm853w5yOlzJm3fXMly9ekvaq7NxL8+vSHeWd5bEbbvdnN8+Ge0M/7U8PVx/evvXhcId77nI3LPsH9+88+uj+wcHupUsXGs9Nt3Nhd3f/Ipx/QiSpOslOMGrmYQB7lsT9RpxrxjHFvfZRT6t0Ml/sSv+P1+OKJxTjoKvx3p0zXsoxn9yPn+6On3w8+/CpsHyBce+N1/YvXY3yNVndQbqHlfQns6Nbs9sfLNcfvO+V1jE9/dlfevozz5ze+WB6cCmxOhd+9MNXTvnOr3zrKzuLvdDNB4ZrEssgeZVkwj6JimemlJL3DQE5RXBi5xVwzouoc5Q1qYCJU06q2vgGgKZBy04EzOza1vmGiSjCMVQ0STY9nO0gu9A6587O1jFG3/jpZJJz9oKcE7MPIdjLKAYxIBHknEUKz6UOjVq9LDSj6IG8n4gMYJdkjRzYOWbJI9q2feLxJyXjynAxjpeG8YNufitN3mx391K81Pfp8PDs8M5p1x3PF+18MZnPdhr2cKTIQxqZHXswRlW26iuiTJ4YqpkJ/ZgXO+369Pj2raOr154QqFK2U2SYs2KrGC1HuIQ6lF78nHlFWqZm+89cBblFy08EkHM1clSIWQDejrwlhsguPzmvtRX602J4VKZw8x4R4oZMHVK8NawSO6gHGoBVG1HPPAFa1aAdxAsFQgcKRAEUIA5NgPgcWVNr/hN5ujONGOct/eDVT47mWDAPObOHg4KzjAQZCaJjoFHAbdLkMResPbX78/XReoowIrayufcHX7n4wmcfOVrfZzRAAMB5E9Vslsquvb4P9i/JO4hGkQwdiZJoAhQ0KrJqgklgkUmTCcegafshKZlU2zI7z6NptdIASqDe1sbQ3nbodtiyxxRFaC2i2Tc+DqeHyzF0KlgTBVXxvmVPm820ae/pWdLeKzOcwAllN+ZhHlqcOV2PFJiZ00apEKwESBbkZMEPbFN/MfMShYCKmIqp2jxohtERivckbx/LLSNA1Z6xCghYmVCFwptFrSJnUQgpC5s06BdIgVo07PTQ/thgaNaSj4CqiVPVwmCi6v4mFdPnSnBwzCpKipSz6ZScY1Bx7QBzTuemIjln856zJrZo3/lhtKmsgYouCOVwqW51ClR22mUfDBPN16ertrpWpc9/dAsPozoeg5gcEdnDJ5mZrXswUFpVU05EzrEX9QCV+FQpPEjzrzU8vgapaBO86+iv//LHf/vO9/YPAnQzYfU6eoYTZdKGktn0QIwQRppZxSwFGGTEPOVAymWHkJOQrymiXPET8kKsykok5CO6NeYsMkGcIHYYpjwE3QSKGhVrdanTmOLxfZ8H3n1KfKA4KBry5INAna5d6qPGjg8uSWasZs1RyG3D84ODS2E+QbP+ZMI7GXP2sWt4Vzy3zk33pYMuBMcqxyrLPJ7l8UGflhlndHp3eXbpYhxO7x4e3rl9kzjtLNr5Ttd1wXmaTNr5dCJC5I351sToY5TQXIDqtN2Z7Uwy+8vzG9H3V/YazHKz09K+9/uaD5jn2i42s3zngj6YxyPf39w5fCu89yCyHN6P3fJqv9x78PHRg1ur/oP3sFqDsVnH/Us3vvq131h/cnd1+IlGzG/cuHd09Nor3+O99Wy/czcPD54NBzdu+HwQdl7Y6Vp2fr3mKbPPIs77LKMoA05Z4npjzAFAnPM5RyWxSANijnGwS4+Z1RzDCs9HlRCaYBxhT42qhrZ1oJSSiIqMIQTnOKus+w2Du65lntoR6vu+j0NomknXOedTSuMYxzE1jSeilLJzTiv0pIDzbEbnKan3XoWZHSuP6UzIe0c5p5xZwU3XtpPPz/ILSeImHia5E8LtyfRuWjQx7m76nXv3p8dHm3a6nE6bndl0vrM37aYClTRadmqSzEzsISKOiUBDjFcvLd58482XX35ZEr74pfVzX3hhtRqdb6mSpre9e72WC1yMh2BM1W0MqvXvUndUVQlCJhepdFOi0vdsIVEbta2slin2F4ez7RatLKZNcMYqmcgTuaJ1IBYhwEMcswe8aEPoiKfkgrSCDtwwJuCW0ao2Si04kDriRrIDN1mSTBez4+O7KUb42Q/vLSf7V4bNOql3bfYeibM7YwmiZrGZGWCGZ4bGuLfTHSzip+tlPsuTZviXv/vc/v7e0dnSk4DbTIOKemYQszgzMULpLKjWgAyBagISe4KODklVmJPpc2r6r1lcCVSqlZPqQz7fQB0FK1AArQ4rdP676o27/RxgdcMaRhERjRPyJycP+oTWScyRSUBeXPLOQ1M3Oe4m3K+iTSkMJrBGmc/ndMa6yR4saVBNoKwqTLnolVGKMQFKmajEIZENwVYXrKhpxSVhCdmUy5BbqseW/H/+g2mJ07Y3lV3x07CcXaMccHXteLgBsodz24xs1UxFWXC+1rXO1AyzuOgLqBwaVaBYoFjqp020AtjeWcqLzWK59gYdi4h5faAeMaUSB147qdJdoWQDl5KL4h9fdsNc0KVqkFb3tOenaZtlUpAnxda5urYu5SeQ0n9YOLH5AuWcJalzjgiuhJyWtwpgghdbyTIRKRxEpGEW6F9990d/98EPZlcCSc9IisGTNJIapEDZkVY0ByQkSTjXlYAIWffoGarkQZ7FBPwsWcRxUydgr8SJGqEg3IqyqAM3E5xOZd2hn2Do0Acd5m4lPfFAtIm5JyRPw0pWb+bJo5O9S+InMUafoZo7ni8W1D3KaRK43fEOYfM2uDs729nofMU+Xz7Zm6kXFuUUnQADyIF6N3OBxKt45Sk5cQGzzJJZps2UDq6EIENcjnGtskoprfujOAza57PVyX3Fhb2FgB2HtgtN2PGNEx0Jfh1X0o+umfWyoc73OHMp5P5MB/GxpT7LAbs+HbjonHTCi7C4eOPpxYFbHb69vH3r9uHts5u3x8Oelgwe2M1G4knovv7Lv72+e9S/8/N27wBdA80/+Ku/TusHj1x99P7h7f3pweqTvXdv/uTg2Ys7T4RXbt7xu1+48Mw34+a+L7ZrpCCJKXlmQGMcvHfMlNIgmpmQUiQiFXLMglyOmiV7VekGwylJssUwMREZjme5JbXSGHUGnW+YXc4pZzvq2jjXeH+ukyHy3lkroKrMLo59yuK9Y3Y5Z4gwM3MWcfaEi0gI7TiMSaPzQTSpapSGdKMUXfCzcKXVx0dJSdcx3kvpk93F0Tp+erYO/dlOjNO7d4+mk3vTmdvfX3g37cLCjnESSSkxu3HMTLiwt3jllVdf/fEr//yf/Td/+Id/tP/IQU7cNG3W6NDUo4l6F5zjdOWmqG245TdsbwdbOtagJDV0uvBtoUWjyTVh3RQdWkJZpWSVP1x4qVRthdqlU2AnI7EUI3g1ySsRkVdtgEbFgzxzq+jIBXSwQiyN8IQxAQLQAhOgIW0oO+W2VfShC8Pq/g//8H+MOS4/84+6gyfTapw0nqd8dtI/uhdufiDUQUroqRDAQ/AkktW17ZFu7t7xw4a/dg2/8Ss3snPHJ/dcE4S85uQ5KCQNIzsPZgPzQCVhphRKpJRHZq2GI5nLOjYREljqlFMWpfXSItVcCDiKqjUz2/5tP/RwmdlqWG3Lb59lrcmF61TyABynwwcnEdJxTzmrjkxtypDUAcmFIxIAPZx9TUfsVM92Og+cQpZNE0RBbDizrTTE9Mow6y5JJcsOQC3PREIFhpUiQdM6k2I7uJLtWesO46H/236DAGtSspiJ0/ljpYCZYGgdomE7YSv5qBt0qp6O5JiLtZgqsRG+bDhkqFBF9rdFX+tmlYgaDqMk7z2IVe20q6hJBKUEX1a1mOnwC8FYoDmLMrZhv8WrVe3IGfHdqp+1vyIAZSKjTTtArXd+aClMxSqNSnJjTf8tbYq1YsLqyNypt29IWULVTEYVSUDDngkMOBWnKuwbgFMaPTtyIM9N47/z59/7u1s/XlydZhImdi5yEtZMlBjCEIgWKXtpMtnARMn2X6SYf5ffSWACQ6BgTVLkfGCf0ABOwGI1mYhUJxzb3Le6bmndoZ9x5DP2kZGz9Oqzh/g8iMY1P7jj7p10+7PptBlTGuMwlZOpX6WPhyFmdKHpuNvz88Wi40/73Vn0n/XrvcVuGNPxPAvQRMSQVlM/j7PFuMoawB1LUu5cjuK61iVrcSRjHcLMe04jhdBPp5fAOcZBcp9S7GPvXUcYj48iOPkmECXnibEjqR96zb3wTFye5HEtHh2HNB14Fvzajx0iXNS8SkMn+dinqW8uXXo035i+ff+t5nLcrJYnwzH1U6GeNLz41d+bt+0nr/+kc769cnF66dEf/M0PDm+9Nr0Ulsuje31ayepRf725+tjF6ZP3H/zx81+il19rlrcf+2iVPCErQdVsYClnuKKoywDV0FwR0YJEGWEBykRiakxR0zGY5TCbF3XZOalv3DimWn21DWGU7L1Hyd+2I8YhBCJyzqNCRiGEegDJavl8PnfOE3PJUEsiklPKcYx2OAVujBpap+DCUwUzItQ7aiQ6xfoMm9BwQBOm18k9IRLnwyl2zpabQ48O2t7+9NO79+XeyfFisdf6ezvT2Xy+E3zr/VREptNJHMZXfvQ3y9MH/+Jf/vd/8iff3r989erj15enayixC7Whpf+y9Na7r3Bh6kBKjrWYAgIl9FC0WP2j3G1k1EzVGnNWCkDdnhHJ9n74hb8VDth2auP6QrjkDBrlV5ngiT0okDrVAPVEE0IrjWACnjGmQAuZCneMKdCRdtCg8Np0jhxJ56dT97f/9ofdlekS0+NHL/vxdJzkdMYYkCTcXo60r7JWXkkZf5QhLFEVyedmzNTGB//1Lx989tn9B8uYUt81LVQjg32vOTEF7zTlTRbvmARkBoEPDf3Zs8J8hyTZ+2gZK5oF0BKyXAbfrY/3FlMuhZSLKwMEpEJF+8sAzHNSt59n/b5SpqRCSJdyOAjscXQ2CnvR6JynnDH26r3o6MP9hLtpHUAq8AyvMoJHaL/bzVU2TEPjARXSpCq6LbQlKkoBgWaFWDQ82P6hdAfMDmWno0wkYsR+3e47YRpgouoIrqWEaCnB1n5INjNoSxuymc4S4YxGWThKBHOlgSKLZKP4EbFVbFE1W/JSAgt3CtBk1Kz6Tup27UKOoUSixGBlQiGTgUyRXNcOBGNfkNrK2WiUZDsfs38U0Ux5u2soTFG1wlrY3zYu149QiqyZLRZQt2aW278IrKz/5YETLUszZkjhORfPEyIRJTjnfUW8iLmoFsy6E+RFBCztpB0lMXOYuJde/tFrb/1o8cR8VCiYdE1CnhPLyGK0+LTFdMpmWYFMWht9+xGVmJwIC0iZnLCqCIEEGVCQChjswE7F2+8ToEFsEAMNHfUBMaAPWGOATz6NEKGgPsesg3fjhCPOTpehP512OqyPV4MscwcZWQOaDp0IxzuBfSfR99P5Bp+cPv4IuivPzhmagvCmw2rH+42cdbyRSScbwQDuIUjcutwnQBkOLJKEvTL71rWqmZlSiuxCHCS07CN57wCvmtMoYzSLYk+SPXcCylkEommtG24WYXiwZo9M3VQxnfueUoRG1l6zSl7ntMPuypV9evbZ/sJjt/OHy/tvBMh6iM995tcef/Kp+++93SG31x+dPvrYm2+888aPX3KzDN25cun6mZw8OLkbP3hnEffXj+5d+9yvvfnh+nOPffUvfvrK5ed/2wtG73xK4hwzs2ZJafTee+9zjsww+xcPWHiJZyeSwcxMmhJVwoUVBecoSZas3jsIHHvLPxARgnp2KSXnOKfsHBs50MHjfOVp/+C2xwZbPqpp+RRZCpmJBMzsnaaElJLzDoBvnW86KGtKKZMLDPWifRohGn3jPXuRlHUkTZwcO/h2Idg/mDyx2SybgMe77nR1b7M+2xx/crTWs90Lqp+0XQeCZFktTw8PD6H0+GNX/92/++Nr165/9WtfXy3XNg1Q1opFUr2jDV5jsPkbnP+iqYHtP1Ex4DNnC9LzsYO3HMuyJ9aHzzvKCst25aUuFKhbz/vxSpe2q8tYoDZnWNaCKXrhAa9oBJ7QAQFTRSfUMe8gT4QmRHOiCXQCnSsFoo4okPjY5bg7i++9+ebN43f4xsG9Iyz2pB/ErTk54V59gxgcr2Jm3yoxU88iQhDOkhrulsfyxPz4n/7OZ/2u3F72LQszpTwKpTAGdZxdyppsmIGLrA0A1VSRQJtySnFliBIcmT8zFCZer1ITG0NIARaREnKBQkwrliTbt4+Jmcn8sar/yvb3P/SXFLsj4rK6o6yqDaflau39AuiHnruG2YdEWbL6cJ84O6+KHLM0nODhmRlpGlrknnnw7ASiMtRiqVRaASlAek6w2gwDTA0yMf9nex4SKbbMqi1br/KMKtlIUayjzBh5C1MTee+K3Ie9Hb5qzFq+pkCQC7hr1z3Oke36jhFEMqpId1twRUoTuIW+7NURIeXEIC4JKyW6m0tCKLaDb/mPlotiubwwLpRo9bMz6Nm+gZSNr9a9LVkKHG/FS8xZJVl8GdvSiR7i20vF/Or7xef4wnZFUfZlAmJ473OSnJP3nuDImM/lPdEsiZi8b40Kx0wgHnNCg9C4l//mb//mjR8tru6kUXRKTcsNT3Q8FucTcwJnYSUITEho21yFJxA0gxtAgGwiSFJHHJy12eTBvlGfORA8hDQKJ24STwUhic/sRZyn1CB55AapRR+0pyRJc94InzWcvEShtVKGxI0MpIr1Og4rT3xhfzosQjy624QwoKGTPs06P+N4fNqz28kh6yfrt77/xo2rlxePyADHvltgKojJc8rp1At3TD3QEYvTEdbXml0uc8jj2tb5FgTJFELTGFo4DW0aBxn9fD4V8XGAgofovQ9JwDJRHn0DaRJ3XhGdnwRPcJwlrU5j6jc+RHYShs3QpTidrHI/CatLl+cxLDDgwa3juydvXb3x7Be+8sLRa+9qf0bXLi4ev377/uGrP/xTdqud3avr5uzowc2rT9+QPJ6ko3h0q083Dq5845lL+8fJf/PK858OU89IhdZraxQTyGPMKdlhECizseSzkmRWZzOxEjlmrdWkonDOvA/FLjy1k+ULOYPIsSicM2uZOo4VN0cAyGV0NiTLQu5rww5kKDE7lSxVre/YN8E5tvRfzSI0sneuYde0tpnW5IHkiEmgkmAzExv3W0gESFGlbYJkN2t3FrPHwEmk7/tlTnRyfNL3fYrJh3D16pWnn3l6TKNIfurZZy9c2HvwYEXMDk6sHdZzjIsdM1ghmiVHURHnPTFLIVkAgMmkH64ilsFmYh6pjve1eaetcSQUTC5JMs8fR0VJTJbcUN6xuh+um7JKX2I18YE6pgYUCI2CVRpGgHjiRhtoAKaEHchUaA7MCXNgAp4Tz8BBOh68DMENHeIknaRbrz4xlzVuL+ZhHG8ew8fOr6cXx2NJnBwLey+rFBM8kR/ZzyUxgGZz6+yXHsO3/tEL/arvl67xGwUoN4rI0ORGgJAdleLGpAyqHD1z/rd6aaOnAiiPNFHKomyJ9DX/1lQoKGzaMvpVnyWgLCZLhGxdWloMMue6vz9vhmziEVVkqCMIE6skYjgHYmELSkvpmcvTO/dTVBZkUuVwjyWp9iDx5InUwQ1pnDVh4bphPG06cBPTkLhhlSSSkbONg4aYECs52spwq3gomxpGJTMr4ERyNjYQwMooLqrGr98uuEl1+9DUrac9nKgPlEjhBxYkpsyRpEzO3kHUIbWMhlzkN1Zrrb4mLeYwcJ7LF95S0CtzqujBqk8IqLjXlQ6pgkuGgps1pScHou06tjpg2jXi6qesdidwmd2LHQ1t/dy3BtFMZoNtTTUzC3JO4rlGoZHC3GVFyrEsYaGoxdiaoAIhMCCSDQ9gdlBSSVDvnIqkHMcsI3uGa6FMyJMuvPKjn778wx/PrrY5qWSlCCSOoYnUJcQknaDL2o45iA9oemkzJ9aNai8QJiIoIykUyKIyUkdoSIOgI2qhrNoxdaydbrQ9y2EFt4LvuRu5G6WNmHSyTipZLSs7iAYhphwb7TLGlEakDpI4Q0Wdekmpa5y4tqfkBz9vsX85SkbM8vQlN1soghwn/ujTfNpDu9ntd4/f+MkHv/zbX93rAEGCjE5WEhsd2vlCRqSzzJ1DAgXlQAikEc47GcX5IIgeUGXihqB5HBlQB2bnmznUqbKqI6c5uSyJkabd3LETbpNP2pgKK7AD2Ie2cVOnU0mhS2Nej5u137mbNrpS+KYNTDMEyOUbu+/9PHTLiy/+2m/qasz+VKdx8cy1FevLr387dqsvfOObF6899vr7P/C7/Z31rYtPH2w2/RrHd88Oj3tdZlnTdOCQ2z1LPDbpnvrGm8A3Z8EWFVKIsBEsmZyK2mqArSs0KkO1hrPOZFtRHJutf2k5TXhTdypaBTaKSjk1o9RqPVNs5Mp1abeDqMWr+ZKTy4C0XeuMkZOqJh6wxQagkrMC7NkVRWX1g5VtxjdBlZiTJCAJhjFCFc6FSXeVOO3uPcLMNouDnQhE4SDDGI9Pzgz9Tjk7dkQ1WqHixoWYqmAmLaPUecEtlwHOaVnlHS07ROWH/6OWbJaC+ZEtAvg8R0kKjmUcDlT+UAWxy9xknTsDQo6IAU9FBtgQeaLGU4uGMYFOgDnpDHkqPAUvOE+FFggLnsrplPogm45Sl8+avN4L+MHhG1d918sktbQ6/ut298VTbTlGt39wvPbDOjYEFzl1iV2DODgKqwFY3f/9r196/oVHTk96VU9NTzl4DEISHbwokB6CmaXahwFQcxHOFjSBYndsBB/L9BXJzMrkhBTm+Afj0wOi9ibj/C/acqkcs+g5Qk1WH4gcXGWvi/GEWJmIqtbUNsrbxxAypllAzkPg5re/vP+vv3NzqQiOoWvv16pRVVQTcQsAmofxbG/yaNNyv46NZ1E4LwoGkmMLTBTVnCWb5tVQkvre2A8BBVSSBdBy/cvOl1huZYXQtQ7CxhIoimY7xcU62d6P7QL0oU2tzZ9a/vlcRgitS8iyYEKBuIBqFW6rYa1ZzLr9gLe6usrVVojJu5iowsJmXSdELCW4Scu2tfa+9rPp9ms/hHBscZItHl7hY+tFhNgaXrKkbzKPNKg5kyjBsVNolqrO14ox1dOF2imTme3BGAUMhgqcgYiqzI3znuCzuaBm0iSikQmTZvLKD1576fXvz/Y6EUjMPJJGjWcjPHXwSZoI16MZ0DToOmy6doOWMCpNCBGGpEHEJmCbEzUAjSAALSGAnKIj7WLyzQC/ET4bZSVp7WnDTY9uEB8K/9Pe1AwIUWTno4xQk1ElqLCGEeywgSBiMo7xkUafvjy0nD98b/j4bjM/wFl0+mlGwzx3ExfVhdk0b4K+8cN3b3zuMwef2TmNE+/mrcaOxinnicowC3zGmoBIGgQNxAl50qhMXjB6dkwBagp4dQolzimmnNjAMO6c8433ObnQqCkpHQdyE7QqXpMbk0t2W+Y+y1q4Y+46P7/YgFncJASXw6a/cz+e7rS9z97vh+e+8fyLL/7ajBebe6n9yiUkavcvv/Tdf7NKN7/yO7//3HNf/ODWRytZPX7toF8dno6rS1cufrhcfnx09mTv8nS+TmElzRnYFws0I8KyE1UVMVt2V8V8D19PKioQIjv6ZaMpkP/deStl1Vwez2UPVlWr0zKqHsFwWq6J3KUylpFSH6Zo1rXx9msa41+Y2XufcpHCEVjVkFkSyX3fB9/YXtn+lGMmppQ0Z5M2NsTGnxFyZq0uQ1orxLGXrOX1cR7z6JxjgMDOORCllLxzoC3BCtvXp9a7u3LjcYkMP7/oUeVIlS8K2z+JpZdTuRe4ig1NbVi5LWq7JpQzX1PjRFEc37diTtQ7aCv8NTGPR7W8U/Ugz2i18WihQTFR6ghz4gWwgMyFFgjTPM/HCz2Z8mbOvZe4cOupj4jH//J3nnvp5Z+8e/P1+fzqgQ8ffPDBpWf+q4+H1Es8k+kw3UOCSFJIPEthNrm/PHvUxT/4589eaHeOPjn1riHe2H1lHyiZ7zIVc7GisqYMVD/D4rG9JcFUkFns4hGihLoHBcz9j5wzFSZtPZ6qPkfV/KChnou0095c47ArabX8LHCFGokWwmQzGm35tKqAygi/Ow2UV5t04f/9n95j0anzcUzMA7tTKDNUEAEkYWbkvLk428u5Fwzem3NoyoAjKJlmPDOTY2NZSU5piyURshlFMcxLF1rpaPbs2WnVnLX2defHkqAPr0i2JQvISY3ra3+Galtoz6Mx0NT4gtjym1FPa+2VFFmEGOCaCAQQE1v6rZ1a3maK1EmVt1/SvpaUG4mIzKRd7acnsoCkglaUT4hQfM1qphlUy05BpHitb9OWHppeS+GnigiakPoX+5LyBlnmlaEE57LDAqfUe4yhQuwdYOwOdc6pehWMMREJUQCEKbBnkdhNpq/9+K3v/vlfzK/OIKAonEgyWEhHTclN5ouGOW3Oxuyi8ggetAnsOCgHSAfqqTjpmblBVrMgVS/qbY4UNFAHDSI+9dL14F78AN+LGxJFjx48CgSUTQGu2fY7pFD1QpnJicBJJiLV6MYxi1N0NKRnH+8/ezXud56xN3OzPOjh8frozikFEHtMGp5pWECafOEZN907vfmzm5ee/FrHfSfcIzY0sKZG4+Bb7pyslQOJU2GwJ3auIH7ijRHMTCJklENnjsoZMFNCyVmiFQLfBOYgJplhBhheffDis2292TMHFo+UYwpNpqnwZiXDtNkJLmlMLPdU05iGxcFcVjPAd8mL7HWz+Y/+9qV7q49+8x//n65cv/5g/eCUj4Z2fWf98f71y3dW96aL6czvfXy0uXXn/u4zz/ToErcjOm8Jesb8TOMIAjsLLBLvPRFyFjAce9uyZUkNexByJYhyYeFTrSr1GBBU1ciHVNqoLbBFxLWwPmSaWN6UOhEaSqiESss4V03gIep/uXQtUk5FBU5LGSJz5ckl6gxVw0NExOwdA8g5Z1Wk0QZUi4aQLESOAQu4Zac2lzuGeRJYG27sMNtL5Vy4Zrblom2TUTZlSgQpXXS5kmAdM1E1q6rHulCWt+urSoEmAGyzLnMFG8xqpy53pbLbbI8OpodyZYpn5UPRhbwVATO8akjE8EIB2gETyFRoSrzDvOC0k7pJ3NHlLpYX+Hgi6zCeLKbcjfd3fP/j1/5/P/jee124cgnr9YPDzz335QWnD+9/+2D+K3dSexA2LoXTaecBik1L/uT+ydeea/7+5z63PgtHdyL7OemKxIMlQVzo0tg35MRQQUpmq1AAX2jdS5QBDKCtdaIR9Klc3yxQQSZ2qgyVLCogxw68jf4FKaMSatTKaoExqabiaKEHPRQIWQuY2oXLRHZJb1lQqkhZL18Kszc2bRjHpKGjYZMIrff3mDcibXGc0gjAIZCmg9lezBvm0TnJCURmgmrYj6qB41Rgd1fyl20HDNVEQsXfkQsITFVGY8mA5WTWNYUBvecJlbWxLcIhIgv2MQzq/Fki+3ZFDiaqRFx0upJruEdZ6EqtQ8XnRMTcw7aZCnUpvB2Fy6dSv5lu52siKuJarQepgNa07ScKbaLcSFanoapGBiOQlA+WHnJN326LSUFWsGtO2jlGQgRR0xwTmQ1x6Q/UQhtJraMzAZZtwInJjmcGDK6o7JZiVynsEuDhKes4me58cPP297/348Xegfo0puzFpClZR0IiFdIwJ0bq2xFhpHbQOGjTUjvpRAQYM6b2qcCSOAz9UVUEokAwtmVQsKIDui5iGjEXmidajNgZaLaWyVq8AuoKCGqV2BDbYuAK8USAk6SaU4NJTNrR+oufj48fsKT5Rzfnn37k37k3cDzl6DpqRBmcPIkMTmNaLf3qPdl/apT4fn/vmcnBxSafBucDYoPYUERQeAgnYu+nIa2TrJAkM1iSGWtT+fTYGylQlZldKMt4L+JEDPywe9s+ySwysgSrucIuUQZUkugITtxwq5NWBH0aNjocp43StAkXOsHUr507o4Z+eusnbb//3NWnLhzsv/vWW4erW7/93/33+3v7sT9T4jzJu9dm0uaBhvklv0ynmF48W8Xj1AR0a2nPNAzkvfc+jdGucue8iHjHKafgG+8dQCAx7q7tYpmDMws6AoEcmCwV9iHZnIEy5Uibb0aBe8UiVLJmV74aAVTsVc8raz2WlbRLxdDWHHjONzei20gye9zBzGAybNCxk5RVhR3vzBfmxSMiTfCOmGw9qOqcdwzNMedxHMXlxjlXIwrKUMts04dqcWZWkcxMKPwdiEhjcaSMX6i+9TLDQ1jneUA4VZ1IWXZhO8sS2R1FBVwVVRXnOIvZLFSLuTrc2MVjb13JdANEhSxC0ZBqFVUmJtFqMA8z6HGkthX22gFB0RE68AwyJUyBHZVFmnX9Lq/29HhXjy7gJMjJlV1Z37/z/T/7w19+cWf64OaBrBfN4fIMl3cmy3f/sptef3bOP7v1v15dfNVf+twbS13Pro69DzM+OTr69S8t/v7nnv709kbjyCFTjLaSUs2eg6REBIFjzgCpAGTm9dnGXSWGGviLIhjSap+AeuWiJmbUSUq1uAFmSdvGxwDKUphsGWggvql+qktopTk/DFmXP2kDuKBy/W07SkxMQ6ILewchHI8gL361VnHis0qzFDP8QIJa5KSMkM75RTeXPIYgofE5JeehueDKFeFUFZN5WqnY1k7lbY9LrAw1++ba69lCR6QOleegS+k2BCLbbrrC/fkcXT4v0kwMVpE6y0IVknKpfNu3xm4ArhxruzQs6wGoppha7wlUZjJte1D7YamwzAqM5GATd8V7BHBcceDqrlngbIN+7djailyVCwurfFoP40+GgpTICmYQl7yz8pvrKKBAFhD5kmZmJGxUX1K7k7auahDJVLjk9otOITkTEfuGifyYEihNZ/NbH915553DX/6Vb1x/+uprH7z66s9fDTtNjpk7lihIpFEPl+teVvugiDBSm3To0QUaQxghI0fCaDcTHnJ7A4GoBTWEAHilADiVifa8SJgnzCPmvUwHbddoB/jErXEPx3KreIITseSIZDZrIBEVYseNX29kl8evvpiuXp7eeb97883TmzePVv1pZOccTzm0TumsaRrOQpgyBh+SpN7fv83N/PSzXz7a2Q+NnwSZBYotxY5SR2nTePECzoaR+ODRiY4QOgcvBMJsdkb2eZlik4zI0TRMFLQmTSGZ9Xc217g8iIpSIBJiYckqUSkSBsR2KmEk0pwkkh8196yOu9kkhHn/zAvX//zfv7RaLh+9dP2Vn//1cy9+fv/G/mq1TFM0octrimtdXA4n49HB5Yu3H0jklhcXuv3ry8gbhEhdlMarSNt2IuI8p5QbHwCE4LlOYFtncxsRiE3BpsaPMtsfR2wZYCjbOGuNC56lhBoagO1FUF2uitXxlqy4PbbnZ2N7lPUX775C8GXdukUzGJ5qWmABLO2uKFaYaNtQGZXlolEVZIACewmO4phUsm8gmhUZ8AQWEITYO4WqiuHSxippfGPVEUDOUpdt2/HWDmHNLyp9BD0U25uJXL026vABlaxUkAkQkdnoGFBox1hEgaSqzjm2zLgSjmZlfOtsb+ZPRY3p2JvmgcgpmMiZ4E+pYTTwjlpgAm0VrUrHvCAsFHMNbdzl1b7c28NyF8e7cu/KPN774I1Xvve9xxbr47fuvf+9e4uFk/vHC4/04LgNOI39bG9+meXmnb9I6/cv4kqix5e0J8ujZx+Z/9av/reHHw2OvXRwvc/GxGGBENSTJpAr21/bZdQ9lJIxhhIA2XoB2udyDrTURwJkvYbWze92G1rDj7RU6ZrhZ5tENWiatz7cpR485GJRoE4ttcMO//YhNla2F9GmcQcLd3sFH+j6rLl1OvSU99waQhkZqgTPJA4ah7gX9jy369hPZx7m1wSCQEkgxU+ZCMpl4CMleQjiMIH1tgbaQFnzhEhURKoIB/WnoKo1VzNrrpiUlCPL1VwGFRqWrEK6hbWYSeDqzGuGU+UNAgCw2uyebXvEREWvVE3M7d4o2LWWkmsfHxOjSHJVBYWuXGdme6fVZvFCvahIEYoSWjVr2RarmASZTBfNBa8zRops37Iq1a0bNNhYUowPyLhuAJByZhJyjhjOWHpVeSgwwJzqxn2LzsB5EslQRywQpGKZHRqP9fLsR3/z6hM3XpjPJ+MGHBunwkJZOEcRr83ISOglNGh68ZFDROjReQy9BM/ttEuIilTqLunWpVQF4MDwQIBNlvAkodlo6Knr0a019Oh6ChFuLUEzyMNQxEwsag4zVMG4c0qNYxLxV3bxtc/7zuWX/0I+ePN03cfUKE/amCJGSYizbjENDbLm1RrShRCwadqZB42f3owfvH34hetXO2DgGBA77RsMDeImeA7edyxrmFENsxOXXWM3sIgMItYEFdN+Kyoi4pntH4hGoAEEktk7p6zqVFUt4oeJhWQQJCASJ+LEMkrfdj3FlY6h2R3Z9yl5UebQcMPT9fXn915YPvjLP/qTD29NNn589ebJiT/97HPPp82YJbULwUlsL+5zrw9i6Kk7jq1OH1lL1/e8RrOEHCXxp6fL2c58Op1mkbYLYxq9c1vQ2J7C6qRh774wO2YoQ0UMeaESaG8r4HO1DNkjVs86qgzfcK3yqzbcbJFZgB+6P+yqqE2lGnGqLLdsEioKSMvrFIsqIhhgDOfYSldWJSXnnNnpGRNbtbw65vp5QIBRQYUhzI0tGEDl8JuJLLPbiiLM56tQTL0rxjr2ercH3G5F8/FRFRNQgM7hu1ot7I6jcm0WG/ktTTPnbLcXak9TbjHr7QtJpNBHTbmVkwU50XasAEBacgZBjuFQ0nwDPMEJB5IgOQh1oAljBp6mmT5YyMlcjvbo5MAdz9PhvsY//uP/Ma2mePRqUkzOwvFJms5kiNp0Ct9Od5dnH/ykpcuPTC+eyf2+Xy/COmP/BPPf+b1/ev800gScmKOiUT/xsmZJiRRwQg4qxDpWsjsRCVHl31qhsXkFUh4T0vrRwwCXyk5itduOSqdENWCKKiZfoehSvhk+i1TxlpEWAPuktp2iCZnZUeG0mfSLiWzXTNXUm5p25+n92cdLaUK3zNwFuCFziKoNpLxcYhLWKHFvugDAGKfBiSQIMiEwR8nOXhpyncmlLmDrVvIcR7ZSUUZyq5X1zauRRrVLKT915fGecxPqL6VsYA8V4c2WfVmiBbYeMKWPoeILoMUDtQ6kttxB6dSpOD2AmIoQiCpL0UxoSPl8sWv3g60asjKTq3ut8qVqv1D7960Gv5zBLKoQ77x1VUVwj/OTdx4HVdf4omrC50KnwNZMS7dAfZZctl/nzpzEjh25YpVDBCVLUto+mbbsUmUBrLQDCN7/1fd/EJruxpPXH5z0m7P+6O59ijKOwhHawCVOg6Y++Y6TbwaabBDXaIHkKXnKHpmYZvMVUAdfLToIc5rRBtRAG9UG8JTQrDE908lSZ2eY9jTteR5pp9f5IB1WSnOKoUvURQ1RuacmchsRQogUsnYOROyDLN1il7/xhRCcvPTdo4/f6x3JopuvZFhu+ul0duMzz9+4/swUTKvjEPHp6Z2bJ5+s4kayYCPd2Gkb7z5YKkDIAla4BC8GjIJDcBiIvVbFOFX3b6PFeIaHZClU1tpxqulmvcjDMZo5p8E7x1wF0wAyNAOZEOGTg6AEn/S6mXQNx6UOkOz9XqPMskJGgiqvnvnS0+/dfPbw3VtTNz3dnL39yd8MfPblF39ZJE3bvXbzCHb39y5/5jjxaby73PBicS36xVrCSea+6XpM/HQ2Xa/X/TDs7u6CYToqu98K/diuG1QxS114KEDMjlgF4zg6tkmFq9lDgVqY3PYsKyrHAqpKosas5jp5KJGFn3Ap1bRdpuD8sq22+BU5I4CoNMDFz3ZrokrEOafKmcI4Jluj1muKlZULfjSSIqcMYSJHAiaWnEGQtEWHbQlpXgPGqFJRMaGk5Fx8V4GSLAbL9y7HkAlqk6vU0cNuovIu0xY7s0bG9tkWkJPFljnk2NZsRWrqHUuWQuIqhsAMVBmI1suV2LEXQcqJELwvngYKBrySI23ABA9uwC1h6jADpqRTyI7sYLmrDxZyvJCjfb/cGQ+vTddyv//Kjb/3n/7kz5Znlz5z7Ym9R9vvvvzTtae9/QV62nB0PV99hvP60ysHOz8+PJqHJ47TWnv83h98a3rt4sl7QzsPeUgamDuWU1XOjkVTLqaYmiQzfL1Ut8MFjKZH9edTsiIrpk+tg5sKyZY7BDEBG9VRieyZEyYj6heg0a5je4qt3mP7KQHnhtAoQLCIEqmS4y3Xl7yQANZsgYHVyFev741v3D/y3kFYpnBHDWs2HwcKWQeItxKyNz0QcWwBI55TiqqwmGmFppRgbaWRtJHtOdo+0NtCpXqeCVCfLyMSO5Pz2NayaNPr/ltstquLNXuzVArv0X5AEJEii6qehybbclchJJW5L3puPH2OahksbPOu3RSFiGzfoUDfYNbq+FZ+kjLM169SOu9SB5m4IlLlAamjMBFKvmhpQMnyK0PjRerIbM1uUWSBqbQbKefSv3N5PsoXLy4FwmapsYWwpVhmKkAsDJYsYCF4GBHMnhyBFtZqyZdhx10Xfv7mzR//6JVf/tXfTLk/vHcIXd66+UFYdOgleyBAe5CXJrAGbBbTllKDsdEezA17FpZMg7SZm/lixcVqxgQB1ggxtRB2EWFUN2hI8D26Jc2X2FthvtSdU1qc4OIaEywFKyBw6rpBpz3Wa52sYf9rJnNPZ0iR4ZMM6nX9/Jcm08XyL757cusIYQ/ct+uT40Dd3/vSb9z4zPOzxd7cBz06zMHPLy0uyVPP8erm+tbSp90b8/ty9M6dN48e3N6Mspm2m+x7NJl8ohCptXCzHMWNxSvE7MokqXOigGRhhvcs6gkJ8GbfIpKzREAZDRHSOBKT8yEne6ZHGxdNCunUA5CUOAE9IwAB8BhDt/HwJAzLj1RtWpEuyiqlsDe78OxXvnLr9rugYTJtNKZbp6/O7118/vOfXxw0ON15++jBlccf03CBdy+sh8PW78VwkPx+lnb0ezywzyJt589O1/fj5uLFK77xsFUtqwDkuMBM3llpdEqCTN4WOpxzCoEWe1NWnK7HZAc+qSOtxJRyeVHZFm+HQ84iZGwIS26xla89Mob0gADlc1ivINW5+mcRSHISyeyc887YR8wlT75cu41LIsyOgBAaIsrZ6qZsD70U9BbEJCmzJ2KfUioWBI5zzia1MpCZt1OtgokkmcjSIauQvQADyNSzM4qLZKnDdEE9FcJMusXuKipoN5QatwsQkZzNvIaIVMgWUQXnz0mraoKFRIugy4gXpV+xSUQkMzcoocMgeCJnSbxQp3DkgAB0JA3QEc987jKm0vlhqssF9Xs43uezLh1em68fvHXn+9/+m0s7e7/0xOM/eenvnp1cl7j4p9/8J3/6H/6klyjq2POwGIZ37+5c8vduvXuhvXS6HH/txX/w9Df/2VHz+IPl2ExDWotrvbiEsnMnkobdBOhVs0KUPRsKzQxlazsMYJGHYb0yghSQU4sGphaH+vCoWFpGZesQUKTqZfqxyYeIRsmmtrWBj83WAaiOJ/YnoOIM4OSCczhVi81mEJx6VQirDjzvuumUkmPJo2jywAgVzB1iVhGmxNKlxme/P70e02o68dz5uLH+QEZmZ3o2hmoec/LkmZmy9a0o8Kmp+JiKNVppNdQV/sUWEK1aWGIjYasNe8UiUcy7lJihlHMmb9pALqXPjq8vLHEUGXahPBRjWNtAWaHS+r259k9a2Itk/E+FkbU1F4pysbww+ygwnX+KBJA6AMijiKhnR4Q8Zst9MdoEavyg1VSbCmyHYZw+8lQAa2wreimwun2nKsnRKNBWoA1vcrbKIK8qCmXyRteyDSNZMoQYRxoELvxnURV4R2q/WUg0s6OU0AV/+/bRKz9648WvfWUymb73/u3V6eqTm4cYR8qTnEQGdT2xI+kha0VLxFgtpoHGlUQhF0KXk+sFUx6i+BGObVSAgOGc6b00cRfVJ3WR20Q+quu1XdLuiS7OsLPk3aXMT1Ora6EVdPAcWaIMLvToIk968WcjTWky9XG+GMPoJabIuPKof+Lx4da9y/cH8d19TtO+P730+Gde/KVf3997LMV+6COH1F09ON5sXr/z0eGDW9Ksu91m/+nLT73w3BevTx+/+9Rbn75+/3Sk2TxyO2gXdbLOPjasI3SQJiONKqPmMTk4YxYSkWYpTy1EkGElRtUxs3NQSC5xrk3wAAkkNMFCuhpPImCBROha4MGBdQBFSC/q4Zjh0U8nIbBDy5lFqI+bGdOe9ypICTuPf3nxzAcfvvPazIekjkP/+s03Ztcfu3D9+oUnv/Lea28erkaZTfL+oyyP/Oyj+8vFO5/56u8MQ9PHLqj3p8tTkfHSpUvrMzk+PpxM55PpAhQdfDG9cSwqmg34lYTkOcioIJc1zXe6fn3ynX//Z+zD177+a+as6ryzpfEWjq5Lpy3AhWrHWuR9SsZuL7u4X7w5iSvT2mbxAtSqqlFSK+HQyldKGVscm2Dc6MpxpawCJsceApEsuTjUmvp5izHmnFUlxpJCISLmx1PZjeWHKd4lqJSwIrfX7c+6ddIw4aAjribDduzNdOMc96szvd0dUgDqMlzVXga1UtfO226QUmUkO+cKG4XY1Nuor8oRK3m1/lutB6+bYDPC8kBQ9VCvNCGeuimv5zJOaTVBCvn06hx33vngtT//wYtfXvzr/+dffPGzz37uySe++799Z28+/6/+2X999cLTt++9vbh4YbVeoVPOPvVpvtOus14+CN/6R7/xXu+HGEEBJNCUEzyHJIkbVvPG0voRk3lcS2G6lf9DaWvshTqzcn0iCj5ayN42yVBFG6xpqlezve2MwkIiw28KwkVZspHXtukLRYamKtuNKbHF4qmNWWCAFM74zw7e7sDGh7RpJQb4lpWhM+ePlQJnb0NKSCJe1zIuuoMu7I2x7zqW5JmyfSxQBqVSWJglpTQm3/jiBlVHVtkizGVbpEDxKdmWFTE117n5Zllvq1VSQXVhJBjHzZ4lUUHSKhckJmeYw/lIi7Jwr/1JebyL6QVtQYaK9xh6vT3pYGLh8yKILYJTDFHwUO8ACw73jiQXEmLK2dsX5vr5UjklD3ViYLLIC/PPoipftnHZMHzd3juFSw9WIkeUy3pcUJOUQN7kYIBhyzazl9lb6hyTx5HYe9eUSkHIlnFMLMJtF2KMf/PyD689dumXv/a1GDmjUZn85+X3jm/fy+OokdAgD0aDB09YN6qM1IWlnzFFEZbNupN2SntR+o4aUU+AXZqOhECOMoCMJlIT0SQ0ESGR77lb6mKJxQrzU1mcpZaWymvQGQSQPinnzaINCD75Bl1H057Tceq7dvDznmNoHGaX+nG66xbPXHpsevP+UZ/Onnr+xa9/6R96msi6B/HOYt7H/pVXfnjz5quZV83CrcZTOfV74fJqd3WZH7/y1JW0379/58G1Ky6KG+FH12buOPkcRUfR5CBa1khi20IBMjsCmOGg0dguKpIlkS9ZlkV6p8UMjL2TNJYVjkQiIhcgrEmlF985OIgXQ7WzZBFx4JWfClOmDOcFvehqHFcL1wzU73bd89/4vffuDp+ePfAuE3ZlXP/gzY9+af+FJfNdub3u5+2kXTvm3SeG9eSlV991V48Prj0bNkk34vcu7G7Okgo4HAWa9+uU09F8Z08JIhJCIwrRYicJQMnHmCA5xfHg0v7t27f+45/+8Te+/vVXX3vtx6/84Fd+9ddPzwbVTMyGcZ1jVNjyHcrqytSDgpq7wnV0tHGjFLvCGSmDXWV01oOm5Oz6k5zEed5+JaDMLNYqbSuhgqoikQDyjkQppTzGsRqwezVHWedUchx6FIGyGok2ay5MyO29D1jXwA9xybZiR9T5X8SyQiuSim0DcY6vEm2XuOUr/SJlpn41W7/b7tkqjt2vduR8U7LMKvkeBWETokDk1D5TuxmVQQ5sBZjQAC1oCkwgrUiTO1nNuV9gmOjJlWnC6a1v/+v/7dlLV/7qjz44aK6+8hcf/NavPb+80C/85b/7wd92Sn7UeDwKpMk+9/DgEMbx+P5v/MPfhyKPMTTcNy6l6D0Li8KgPIEj07iiEgClMGXYYLvttrfCkXX1WdUsJrxSQEmLs1HBL00zUuUfDwUkl6FQ6BwNBUDkHvo9VbpmH7gDlIrPhGNi+1TrRoph3YyKwDFscO1WGzekruF5yhsBsZM2dxGWKoHEwkqa0oXFVeYJI09ar8kRxTKqazZ8XdTkjxAROBAXYkElatfrBgCkGACXlsUqyjmrWxUWnGlto20wrBhXfKXQjH3R+qsxtGDfXRRFoqPn7dD24aeHil45+WLjKROxmTxXDzJA5RyvUJGtjnj7xNvkWwo3scUSeybKKsU/IBtou/MAAQAASURBVBePERZUCRnXbWBB5WtHVTgW0HOeowKsABMpaXn6iqaxBFIQs/dQm6RJTAdichDy5akzKWDt68RCD+qNYB+E9cQQKCVQa2f2zTff+fTOPRfmtz8+/uT2vdnuwrm9D26+100biGOBJugocHDiKLOOOQ0ZPfqdbk2z0kJCGSzU5KJKAUOYhRSu2AFoRojwkUKCT/CZ/Ibmp7R3hvkaO71MeZOxBjaCNeCZR5YREjU20+TiiBgx9FgHP4kAh6MoMbSTtY4r3/q9i91iox5Xbzzz9a//XmBeL1eN5851tz68/cO/++5y/V674y9cvaQeOVHsovjNrcO3PhreGt9M2J0ueb+58fXp1cdk5RO5hMAZmqCJ05gd/JY2z0U3qDln4qIvVREq+/RMIMmiCqZkMmubw0QSkxdAVVIyFBrMgdgDJBb1OQC9oGEGc3K6EfFyNu0Eo4ISeSEW5Zz6jnmT1xevPPvib/zBn/7pHwUekFx2TX9y8v5//A9Hq00vGmi6N297nSQ3by92J/c/+PPv/+h3f+tam7u8ET+dLNKw+vTerfne0rdLErdadfePHly7em2xu5dzgkhogmSxKjYOMcboma9cOnj99de//ad//C/+xX/31DNPvvLqq9euXk2jWCssKgryTJJs4qinGZU/44iEmSpTUbcYGNe5V4tqq86TxrraaljNQqtAvWWpdX7cYfhzaVrLIZDyL1SHRRVTkHlXLgkFRNn5tg0gxKhCWyMhu8+lcDh1y9y2KZ6UKuD+EFouWtMDbZiFqGHCxBYkYAtIrZujSiLY0gO28/CW+UKF16rnP6kppJwjUdacf9Hpg7ZXs6qzt5fACqewTCGnwtooe4IHdaxBxAs60FSntJ7QeqqnHW12NE/kwb/6f/1P4734zPMvPvLM6d/e+gEG/OSlW19+7okfvfTuY27n4oWn+/nmw8P3dEqyZO6adJoHvfMrv/wPv/j5L76zlgCwJmF1bSPeJDLCwmJGZQ8PUNuhH1YOthxvuyhhnVW9fLQ+WgVhVtsR14euEuW0fP4o9QYFbTRyrwBgV/jQdZda3Qpx7s1AtnGw0BhbZxIznCqBPAOijmDvNnOgVQpDXjiwufCw85kmoo6RSWzHS0pub3pVUmhD47hLEHJQE3LWdahFpDAzcyM14Q6V9quoygwucb6oZv8gWKgYtOrPasGzN0ur/LzgyeWiI4Xl1xaNgSqKkw6RMtvcJ6TbT0FhImVbbxodQRRgx1S82JRAuS5ESSmrSeQLmFFyFVRzNkjaPohz7AeFGCEpwfa3KB7RhbFcjlWpfqXrUoGQosqZ1MgkVE9WIZURWTwWbACwOR/Gu7SrrALhXM4+jHhW2wStMLigyA0AxwwgF6N4VtWmcSmLSOq69tatO6+/9jORmKSfzcKdTz56dveFPEbBhjRoDNSMNCI7qEADsFExaYUHPNbdVADhkLXJ2gQdI4VRg1Jxq3EQUjBImErdRROptX8eMFnShSUtUgx0qjgjPU04Y6zBcydDUgIajmHWs0Qd1tqvtZ8Qn4w9tdwEyDrdPtbZkVzZW+9f353sX/nSN341XEBcxjCf+ihv/OiNH77yp9SedYsZGne0foBWtREKWOcTikQjZ5/OTtMxh3/9h3/4+W/87vUX/9FqScn5cTX66DRBEyQKBFyGHfsMc+nLxJK/TVNgNGFSERj3FGJtpFYEgkkBKgx3HaHEg+fWYVQwOEB7mC8q1iBmddCsm9lOYh+1iWimHKa+H1I38M7ZZr3z1N976ivxb1/+7iQ4iGzUeT/3B1cP9h698sRzxz2vR78c3N3+LPm9e+9/uv7CZnexN/Tw7OXq9YPJsb9z+47M497e/sGFxfL0OHRdfeZLRdEs/aYnzhf3L4xD/O5//u6777z5f/g//osnbtx4+fs/Orx/7/rjj/d9ZG7MBZDJGWt3O7Nu71Z96G6khxwTDc0rwBG2uCoZXKplV1QgRzAMJVNVvyUZUlUioWpa6rcAkYWDmwVhYYRuDdObBoV8mdl7730co612DAhlZuccrLISOWJnQ23RKJN13rVb2KqZC3TmmS1dQauEUczSpz5M1qKI2FBEtSqXjtqqbhniCaSkrACy3bjVtowJGZrG0bjrujXJgzA3aurhYurlAIb4mjumcISgGYlb5o4liARMaNihYcqpG48f3Vt/79/+0dGto//mN//gyctP/9/+P/+P1b0489PVYXw7fviZG3vrVfvOx28+9sxTZ/2pm3aXnp0++pV0Enrau3onrg4/udk+suslMRIzhCBJ2HsQhtw3FCp9rxYGVS1jnN1uBTcRyaJihBqm4ol6rr2sYtDSxpUqDtG8XQecfxcCTErLYDKlYXnYdfsyyrNDhcRaRjZbvNvH0hA5KABnLY6AQca2ZbiGvfajB08bdKpOpQOQdVJthCGUMwQ6vTi/lkaaX5iMiURFMyuUysKAFMrkoMLsmZFS3Lac9SgZIajgTA/9kOW3MaC/eB4LI5lVQZK1wPVgsD3MIqLOrECqJ92W2CZjPq+yDFPT2QagdES6hZTrHWLtz1YoJKpQ5xhUvU5QO1ZR71zl3VXCpf13dmV1YAlLFTEzdX1BGolsE7F1GTrniz3U1KHsn+pTAs1ZybMKTCJepfasqsyFT2kyQoJJIVhYoQwoF1SugOCeOSHVl2bEDsO4zbCam4DVev2Tn7w55iyI+3sXplP/rW/9hiD8+2//ZfAKTawjBnMkIvWip1mZQHDMuSdZYWSf2kWSdQeOFFrZDJj0mBASEXGRUMCRKigiJPjMTUJjBTjyZIkL6cxhrTgjOoGcMHp1yWkU6pUdNCKNtGmaNbUTDhuZnQ5D48PE7ztE5o2E6Vsfn2g83GkvXH3qxuUnrnLvXQc4fe31t179yb9zs+xmjTaZnMArvLqZxzSF3RY7wFxTN2FepNQ8WPWvvP72/hd/X9xkjHDiZIREkRGclDJpUkmKbA4zDsj28DCTgFVyNQ3UaosEwLzTHQHsSFRIs4EhWwstyVHWzjsnKuTgnANji99qEu3g1KfJdNVOE9YR3VrOJn4esfKYO9anv/oP37s3vPfe652fchSoD7v7e1de4Is3Ou2uT/bas3jzxz/v7378zJWnLnYX0nGmDfnQdDENi8XOxf39LDJGMOdLB3sZEmNkdkxIKTsisxQnDu++9fZLL/3l3t78//w//A/DEO/dW/7lX/z1b/z23/c+pHTmPItmIx6LEJ1TqX/xr+Kven4bqpkriBhGrdjK93Uryaf6NyKQnIvcyma2Aldip6W4JWmBK7c6A81ZbAa1imzcxczsvHdZmAjjmFJKBHau0EK888ysxf3KRN825qo53RvNMldCTL12itQC1RNCQUxltjeSVbmRiq7SYi5sJ7kdfOtG3VghWqG7Umce8t8uQhCyKyNntchVBScRqAORAWWqFhTBBKeOyvbXgzuggQRBR6FzE6SQh1bOrl6Q9/7u5R+/9JPPP/Xl2+/cfeXf/H/Tcdxr99JqI6s4mT7Vfxqf+kJ37/5Hr7/y09n+ZLNe+b0+3A7TJ/2Fy+vTk+PQbEaQ59EhQ4WFfQgJKUGo9TgTLe3sOaWXzJ+ECcSkZGuRImKh8gwZ7lDdEVEu4nN3CpRHyMplcUOyYavs+7IkNkSzWkOTwpR1la+lZR0iTMSCsjtkgNmDyP4RCERQZSav5AFWdSLsuY3jPXaO0lSIlTtpQOjILM5YhFXSesYX99pLcRy6bppSruw9VkRQgEYVu+eL2BGAbzy2moBCzuVKQ9DqxK7nTyNt/2jZZJw/qlr2oQyQY4KzpGo2FhUpqRZvtVKKwXyuHjReqlVdG79RcB/rAQ2kkbq7KfXQflvOWzb19nwzs6aUt5Y1CpBFs/iCgRu1qvj3KBcOCJ2Pp0UdXF5D6YO3BZLsVZCV7erBqWYbCVXzMSwKaQUX3Vppt4s0jbSo6rd04zIv2JurzBY6YzM6FS9urdGQofM/f/Pm3cN77EgkvffOhwd7j6aI1994+97R3eAbyVBEnxsdAWeyQkKE9qIe5OG8Uy+adN1Os2+SbkbXJI2j+i0zDwSG2Esw2DnDZwqZfEQzYJKjow10Q7QGRdaoGkFgjyZlpCGiBW9onMx6WZ+OoQEank74YJlOEnfBty6cOV7dPH5/geWN55/mCz6t4mQePvlw+eqH3/EXE7kOHbsZRk7UCk9UmiRTlk54rtI1S5mcyESmjyHs3VnKO7eO+Op1v/ZIoiMcvJlaawYSKIMF7HPZchKELMXDIpqJoFmSPTrEYBLAQbOSEgJIqOwmRHW0XRMzy8iyEQ1CjsVlzXDkpTguko4iECTwSH03TaGb+kmSfhAOhJzipPXP/co/efPO8WpYBp6kEfHe2af46POLJ6YX91ZuurNz6ctPTY5eu/OFZ36pk+705KwZvVdkoMnCOUYVZidAiGktws57Cyh35LIk5928m9+9d++d9965fv3a51/40vIkEvs/+86fXrqy//kXvni66r1vwHDwaqbrxYr8v6y95/9oV6uB0DkXtNoOYTmrWs6koppZWOtqPXU152Vy26ZdraDWqUCVHZtZL9mUY8faGuQtzklQIEk2Kg9UvfMlxalSXcRopeXl1rnIfgHC7KiwacsxPh/xaTsB2G3EVEEwM7e0Or21EQZI6ysmG1MEwsompUCugL5Fvlqdtn2Veu/ZsSF/7Ey1WZklhG2dNrZrMQ3evpemSyJlx/DseeQUGWMbdHn/+I//3f96cbH7W7/59f/p//4/H7+77jScnR5z7/cvXIpy8t47d5sLj+3t79x5cC+thr0rk7tHx8dv7k/O0v3XD7/5z/6ve5du3Fv6kZuRGlYvSSRmFrDzZY9QbqdESIbzA5RzKrvyWhy3K4GigUatp+c/4jk3DYbXK865tAVuBGBRBAW3LAaK9akrvlgoq7v6ODkiJrWyR4BXZRUGmBDADUDMjRZdNTNcFmYNw9ors0w551kaNj730vkgjERADgl96i/vP6m603UKNIpRwYTEcAIRTcxBMAKqYBURE5ZDRc5jbotPexk3a158bQSNzvuQREArPFDOo2Muw2s1cSuP8zYAOcv2WNK2GhXouJAJC5JfekfzpSGqWQRGVtCs229LZJlhW2xXRQxVtqTTUsltw2tttVX2+iwbgZIMTkBdHVi9tE+RjYqIrTWsufSUH8Ex1evE/rTjYu3BxdgFXqFZzGiToRBlqJKWCZi9aTvIGgzmYn6QTXzBrBU1JRKCsEMaUzfpHhwNb731kW/Cer2cz+ff/PWvXNg7uPPpyf3jB84Ls0hKQCtRxTTuxIigSNqzQMBqAW8UwBFj1wzBNYzEsdFN5XMSUL1nBYkbASV4QZO0gTJ6wgq0JlqDVkRrcO90UGKW3rynHAXOSAnj8XzCvOd1EPHIKVPq0TfomhSm7Q7zpydHq2vXr+gBoQtA+ujNN3BhzRc6SUkbrxNQUIQmeYQJp53Eexgn02WenGFxoovNGGR2cOcwfe+1D75+7VdkM8hZ5kjSKycLPiajIookHSMoMatIAkSpkDFIhZCLbzuySgPWasgrQIIySIDE7FUFyOYQ3GiTByVil3xcRYlCChnK3l0aJ1nQIQdFJ6nlZddR1zU8C8gJfSO+e/Tg2hd/72+/9x8mbZd9u8opPsj00dlTgqmHUDzg3d988bcuLx5ND0Y3BOnhVRsAzCKizouKT9ozdY6l8oohJMxOSbLIlUuXfv3XfwtMq9VaBMHzF1748sWDvWEYzZS7oFjMopnB513h9v4rLSWLefiwmtERO3LOiakTszkLWX3eQlrlS6C67RS6ofmhQem8whjHov6LVcpCVbJphkSUVbckV3PJgZi4CQBZrmK1wSgpEc4XuoWg5ACU1SXZmqdEbPM5E7KwmNOWxGyvW7VgyaAtFkDlWq8V2DZZZFFoZTqWLXmUaIuxqEJBZI5DVUwCkHPOPCEEJgpxYjRXrWW7SJQItt4sHkqmXMpAJk8huEnj/+h/+XcJs3a++6/+1b8dsy4O9uLJigfeyIM2U9fu/+4f/M5//MtvNwvvZ83+1YWGRNMmtbHdmX7phRcfe/bZ9459bHzUea/TPIgmYFQeiQa4kXMWZBAlUAagkCxZkb3zqr3pVW1AtUV9Vq2UdC4gx0PI8bnHb3Htofo8gEFSPSytjXLOKXLO2TmPaloJ2s55TiuKryBWT8Rg74TJMGfxarCaOMAzB7Dx2QJ5dk1Ci9RltzfDIum6ubgXn3ryuZ9+/JY05CKrIKUgvX9875kx+dlsIuLYM4lnDExEkKQkkghOkUGuNl8CqHNORDVn2PNUHBy1Nhl2B7Ma56j0KNbTF3SoHEmqKC9VC1itDxLbJlmriLq8y+wtH7B+NZC1AI7ZXGtwzn0kJi58LyYoObtxzOkCZpJugggyvpeUjFQj4NleHrbXRdbCtpNas0uMIG05WGI9VyFwwsBELl4FhQU+xkSsbJYO5fEy0ZRg6wlSUDPrDAq2RORsGiYFlI26T+RLXGqRJ9nIq7ZlKhtjcs6TKkKrCnr9tTeXy4FY4qDf+JUXd6Z7D46PLl05uLC/9+DoNpjJpwwhtBididOF1EiKBDI+JwtzoORHDMQtp4D1fAfcmcHWNsvVyC6iDFEdlQTIYAUiyRrujHCmciZ8xrRmiuBAqY9gEWRwVsncIHXNMQeRbvTkKQXyPaJHmnLXJ6GJm1w6en/53nV+5sL1xUdvHf7s01d4D0ICDmiEWlGnCMl1HH32c1r7sMqLpUxWmK95fhx9mnS8M3/jg3vXfn772vzROA4sTkahESQsUWgkHaG28UVSTTUKiEyYTgobgUgI5loqoxQxCIPEEVRH1aRluyUAgz1JpOy190kTPFhYBOhEwYjgqUOEz5z6rGvSTjUodxx9E4MTapFo3fKTX/zWj94++uTBzS7M47oP4g/yfrPiMY2ao56lXb8rxyoQbBwG54FsVAUqIV/ZsxfNdTawLQuyZX6BUxYfAoDdxUJE2OHxGzcAJEllL5NBlGE5viRsPgC65SMySJmrRsKxdaZmNa2iRl2zi5a1yEIqn5NsKVWt4lDZE9vKXHg6pXEmGIAQJaEwPcmZsTDKhkpFncVMwBcjizIdGfQEqlKfMmdIWVczkTgmgoi44lYv4IK75WJjglrdjUBqizSUoaHsz6RkB9bR1H4e51w59lZdsYVYAdSSo0JUlt+s5hQFJmRRm+eUXfWJcCqU0wh4UXKegUYBImXKpjxJkpmckBDUMRMyoGeny1fe/8mfv/Wf6e7qs1evX9lbHveajp2c5qadjmn1wrNfi8dnR3fu/+zdN0bXi3b7j4fFwd7t40NuRVwcffelr33rXu7OeJa03WgYydMGiNBIEsEjJClGS/HJIok4qyalDNIs0QTThtMzJXhGYcCxiGQVNnRSFSBlhglpzkn4KiLknd2JTG4Lo9h1bORcqA3B9plbPS+iQvtzIEC9gKBs9yzgS8Uln8UbK0bQsDTUMBrKnDkgBflEst8R6mJO7Wl7vA6aZsEzq08izHHs0t58cQWb5Nu5anRwSQawCkbVxpXsge2YZmO8g8Is6U1yYV5AgBAsqrvACsxKoExb8+TyVYjYk2F7wuyyZGtgs1gvS0bofdiHA0Cdh0mSzcOsELOkLkeEACl1vTSOxASlaohKoJSNVU5ce+XypakaRDJ5ZhFN9aKwwwCxXkIF4hyr6YlViazwl51N+Z7bL1lM08mM7LQcW1d+EOsuBGwZwnZIhcmgdTUfaVI2Jy+CeGuB6oTiiJwS4AJUk4DhrCQzpWxptPYc2tMlGlp+660P33v3Vgh+vUo7s4sHF6//x2//yYWDS1/60q+slp82jlR9lsjUqI7IhIFYIEIosvSi71eBNErBIUIGRUDqRwpgYQWE2eRRnCEMDx/HiKxkLx7AmHDKtIGuBGeERBLho1MRiDKrpFEkGalAVGRvHrwGXq/hj2gVPLzEtcSOo4rfd+Fsc+cnh699ae/5H996edg5nc5D40OKMTHQMUjRgDpWzycyPXPTNe+vsHMi/kT8MnuNLS+uLD8e33/jvcdeeJQjyyb7MYzjSL2wMDIcOdew2tqEzPI8Q5It1QAIVyW4KECOQISUE8DkDJFkJSSNTELwDEbuwXCeRZJsPLcMAgQkTkQ4MWJG0DQIPKgl9MyNqAe1rN5WT5I92q756rNf/85/OGYPrBCm0+dvfD6gu/fx3fXxqtVOs957cO/qwaMhUb9MHltnoFrFpHbE5d9VsmrxfOcKpILYE2+t2Ika761H3W56ij/rQ2wQFLKDjYKKOm5w+T4oyrnidmkaUDW2sJnImw01eyq5YDVtCWWPi7otLiffFbQMqpKhRGqJJCQKVQcCQXIhPgFbAHJ7QZfV0ENYnsJ8MAroS/Wgg+q61RY9xe7n/G0sc7adZwCqKpoITDYD17vJqrGIqumd7OarbThK+XcKIWVRcdsF2raMb6H4ZF7KlfxMTlC2mYqB2ZsDoCqpJO+9qOhIwZMgvvnGW313Fm/9ON3+8UE8+tzBnvBp6MKVx8MLN+bdOnz3D988PfZHy08CuzDt3v34591+t87j3tULB08M7/xtevTK5dlj3Yu/+1Xe3VuddiP7VXI9+3FgDII1MAADMBKiWaOPgBAZym/eIzZfmWtKNkWm/TsTWby5rcbF4p8JJf6dihW2QO03KGDBssIFmrSPRsWsnFmMFifCTCA2qabhMICtMJiIbbkL9Vr2vl7VQ4OjIPAqnhxLAJxwx+QJLYvXB6sjzDRPd5su+sXtn68edIuZIMlaAL/uh2cvf3bWTDdYsm/GSJoSwaIzmcuZ9MQCOFIUO0MIzC6tntatSj2r1JQO59iJiAUDw8bGEgFupdi4bAyo2wrntnsVsJnAW36BqJZUAy3wcnFkozqSERNxlgzYUTUfCgY0a/bMRbFtV4411aIPAzkPY9qAaYnY6m0BNGyuVdSMCa1LhnMK5DkQZhoLyfZ9ySb1kmxVONIKhTluV49nZmfjghrREVxoY0LMrvSB9hiY5ZmRnFCHhXoYVSHm11HaEqMCSdtO7t9f/viVn6Ws7CildOHSwWQ6++av/8b+wcHfvf7Opj+bdp1KZPIAiJLC9MSskGJpoMX/FABS+R8lQgS8akdVu1XM4WzKG9PgiUQdCXlRCCh6rCFrcA4NGlllXokHoqTkMvqsXplIGdmJnzeSdNPtcnZes2Nap9GjmXLXSzRdwSzozz48/vTey8v+MDyi0kuilIOYt5QLPmmzyi5K0/PsROZnudtQOMUU88eRJvd6N9ubN3L69ms///KVL0wxRwKiUmIWaFSLNGXOqgm2JyJFidHLIgKy/zFREklEvtADDRpMo3NeVE3+AuSqkKCcIxFADRNhbEAVwIdqUgmCAApEHdFACKoB8JCNmOCfQOpkoOHZRz9z96k7P3z5ezthMuHp8tbp/jyEsRk3DXl88NYHL33npS985sVvfvXXJiyeanNYHkctT3BRfTAxM0EtMlqxJVQC1VTIgN7t7qyKL6kcjlKCtnXBUFg9p1fUZGB7sAF4bxbgRQOKSpOutb6QoW0MLQvbh6o8ChW0cCHq+qNMSAV5ZIYFvInmlBw78lvP+u11BlWAXWFlgAolikvbXFk8qAOB1GNeNEi1tzGRaCnRqNwzra/S7i/d+suSHWMD+x7G0VG/HdiV99/eUrs5jClZun9b6JUzajcIg2w5bG9JAzjL8CKmyj+i+cw9WB3+1UsvHzyz/8PXvvvCJTefuxefewaHbxzePJN7m3jnTO/ffvqRyW/+3uPf+85by6PTp64//nfvvtVMm+x1sk/v3VwePHf5a7+9ePtw7ZxML167t+l69jHvRr8YMKVENBBGaFTTv1MkHQEkZsscTYBAy0BXZiQRVCZdtUq0Ho5KvB2L+Z6qKjSXt9dufGv6iiEplX0iLPFIyqawBGPbGy620tzuKUvWgtoW0FswIpMHtdBG1EMDu6BB1SsaIEAaES9h3q6WdzZnfyejl2GeZZPPxm5nmueg4DsOi/neO/0HTzz9TN5IOIAykbCmBkYmQCRuCBBSUYZmwnYzysaLkMJEqk8dpDzKCsmZnSOuLqUVZMFWZ1VckcvOohwoq30FzjZJnNTaUrIfCFxzKQwwKoc3S1LYCbNyVVS3TIb8AwRS1mopK4ZPVJbC9kknQhLCFhquD75hRtZJ2As4p4YVyAgFp7LHg8l4jtuvXS4A1KFDC925OHZxKd0gb2QDFUpKqqiutYXrTuQAD7CzA0tOq0e0PYPk4OChXjU5RyoOlB1D4H72xjt9nwCKkdhNHhyt7t47u3Txkbffef8nr73Stt68bh1LztGE+9AE8RBvvYER9KzuqlcNauXB7JwkGrUBLFvRM4kmB4IwhEmdSiZiGtgnlh5jn9Z3T9uhWfB8tV6uaNWl4MilxIZmgzkfZQeOSjLb845Fl54kUF5L7lgZTebNyM0ybo6XQ+MeaYmZU5DezcIAn8BAN1A3QAa4Ic/Wbm+p4XgMmF+//pnfbMfw7ptv4aj/e5/9Ek6lX25m3SIojzFxBGVT8xKxJBkJQhizjswC5MK0YaBas9lH7pyNZ0mFnGMtV65AtH7kBDiDOQAxY2jRAX3LsbG+gQNTqldWr+q1fLBe4eG7BqRZM3mGSjzRF65+8U5389YHH/Q05BcSEnXDjOGO7xw/eG8pR/Enf/XSg/cO/8Fv/LYnLufBHvwijwe2hszmmFqo3UWzUZGobYSqWhxAER0KlIQsLmlbM1ApIaX6SOE3Udks0ba8cl2+FqdUKAFZtSSbmohaxXwzmLaHtlAfbVy1S0qqHaaUNQxJliSJmdl74280TaC66y048flIgW0NrG6xtg0zMRPXmV+9ZxT8Q223RVvScpnOiUtXatXEuuXqSVQX2hVUt+1vmUgqeo9KYlXJQsQJxr4Gey56a/ttJbEBMP6jhVYxCGxLzfo2KZCsuDA14xgDh7t3Pn73/vvvvPnWe0fpl771td14uHzn7oc3V7/7qzeaZ9yr3759YeFZJm++9eDwI/f3//FzP3jp7dde/9n80d3cpzGMYdq6Tl594/63/vmLJ9M3Z9cPuotXV8t2dHtRmg3CBp2ZvVEEjaSRJIkmRVbizCXJKhnhWCSDpIj2bPGv1aYJIGYVZUJKqdh2qnrj1Bgbo864KkqOyudYAuEFiiTFufihBq6UHU2ytUaxlkiV1fxKyDlqFKxic7AHOmWPVs+TVgMQIE4n+/KDn77Rz9zVZw4O75+wE+4nq+XAS258Qifro9vXDw7O0kr16NmdRbY0wEiI3i5aKQ5sYlAUSGzdqCXvxpOkumTUgrRyuU6yJAgsPaVsfKG2liwLdTO+2FKSiwzovPKBQDUtxNppKeXF4s6YTPRfA4KMn7xNIKsPf4VLpWaC1G7StD1aN7xUH/qt/qjasQAVKSqL3bKBLuVyy+0gMxFFeUu2H2xZFNsPouWllp2uHTU1or09NFy/ogeD1ZxQScnkeo2oVWwm8iqoVbk6iNhbkdW7Jme4xqvaPB2bpvvZGzffe/8THyb9egQkiTzz9FN9P976+N7R0RIQdgqF80b9Mutj0yALiaAP1m6Z9yIy4IBGqSENSp5SSNQYGlQvahRXImgjADMkZ4A9+xzT8v4xrflCd+ELzz1z4/K1S/ODe0fHr/zstbdu/tQl184njWtyP8JDGuiJOvZpzA8u7CXyHpk1BdaAlMStcHrGvmvGRoYG/YQmLq8Cb1R45FbgYvYjmgFO0Gx0fpq7nrqlm3fTG/3kus6mU16e3Pp47/riqeeeSkdpWEY5jp20Lvk0ZEpEIkB2DMOfnSNNGUimCd52WuesQAjAomb35L1zWRKzJ1bYphWs0CwaGhZNsE+x+Jpl6T3HpjTWHgggJg0KB2qImTVoXiaFsHc+OAEQMJf57/zqP31r7415t/NIuJzuRYj65B/pHrn04qUnd5788+98++ZP3/zOA/IiZgxULdfrhGtcJBKyR9d+pBq+a4J8e9a2uA+KiV1RStcjsD1plnnEZLTlEjFf0GeUE6hQ4jEnR+zYWQJBUfiU5VxVyXMZMLe4Wbkohc9rp3X0AECuqARB7JGgImwSWqiyk19g8Jz326Xa1osZMHlQaSmNjFp2XVIuK1TK5zmoX76ilgNvYxRTkUhYg1OGjfNxtxjGKqjoSaCidbVNRfaQbXvHhahFgIIZJSRdTYdORGz7AzNIKDMIBEASJcpIkDHNFh4cT26fnh6fPHX9+jf/6a+/ffTBa2+//vhk8eHhvf/5f7nzm1/jf/R/+aVXv/3qOuaDZ68M94dv/+UH//B3bqzG948+WYWJdruzFFK7F9xO990fvnnGt3//d//l7c3eCrsnsneE3VNM08B0prJR3hAGQlREYAQwkgg42fRJNqc73vZthiMXxllVEnH56JlK7KPkspTg+kgqwWyNbacjxda3oB1UZWz2RNuZJQYlduWBLP5PVMF8B3UKBjXEHWmr2sE7mpAEkUb8zFNLBli5zuV5fu/so+lj3bNfe/L4ldcyWiTx8MEzpKHI+1g8deOpH3/vh24M3H3h2aeez5QosPaqo6cMMUYSHIq2JKfSvTEs6aSQpqCogdwgYSHzltNzBIXBWTL9QltcfoVdMSawOqj1+UfFsawXt7pazFmZoULEjjiTpJRRmptKAKmRLVRYk6zWR9lAhe27Wj4rAIUxYk+v97X9PWdOwBh2hEJ5qBcQgbSqA7doGbZYbenldXtGYRqjcz8NIlWI8SO97R1UbYHqCA0VgIQBVmqKDJ+YKEhZCtQvRQCc3QM5M3snklSYCKGl4wfDj3743tA3zALpkg4HFx/9tW9+K40pxri3f+Xmrdvr9YMQOMXI8IArr0y9Iqkyicpg/w1QkII8kAgjKAFeEQlN6enLu5PsE3Wm5YAjD6SYTjengfxTV57+4jOfffyRK0FCPMPYx6uXr1y/ceWdjz7z59//y+Oj44Vf5JyFBMY2I/DUCeN0vuAGpNI58jKk4OfSDTJ3svbpZBqm+/NLafkx0kqEBU0vnKgT5givmDR715Y9jmM6k+mML03TdCLtLh/cP/zgvZ+8uxcvTDGTZU9rXferFrMJ2hAwyCBZxzwSCTlK48gYqyzceKQlMJT//2T9+5Nc13UuCH5r7X0emZWV9UDhQbwIkqBIUZBIUdT7acqWZNn30TP3unt+mb6/9N80ETPRMREzExPdPW23R6Hr8bVlX1tXkmWaoiiK4psgCIIAWCgUsrIyT548Z++15oe19ynodoUfAFGVlXnO2evxre/7FnOUGETYNMFJl6KJdYXsWJ5CR+j7VuGY1ecyzToBKGHtEo4vUG+TLaVIQYKrnCucgiloXEcl2PB95MZfeu7LJGiOegqeIiRECoUnvfrk1a36v/3Hv/3bpx9/wufsYNwi2wtkj2qa3iaNqfV+krZhJ2JpZmql7GeTp9TJITXJJ4kojVzyKIYAmPIoC17tAA7nbbBNGDoRO1JKlPxsVBGjJLjbJKG5a06J2Njp9rlA1qR77/pezMoqipKFEuSVMvkrz2VPZELACR7m2Jsrlg7DKLuCSf2XoE4zhDRuPCWTnWEwnL45/0LNXFIQITKpzaeRYQZL/hkUVYhzFgpVYvDO5SCccMgUbeyX2dA7PXtR1TH7GKPnGqAYu41qdHj/we9+/dpRWI4vjr747Gdf/eXvfn3711efu8yyvzlBv9/8wy8OVvP6j/70sy//+HeLG119BoefNG9+dPz8n+z+7K+aupZG2tH2pNgq+7I9Wh88961/O7rw7IfNeOF2jqVuilETp27F6IA10Ck6sewrvbCIoDPwOQVWFYKcdP/22YiJNMaETthkgRN5hvNTqkCwH7Ioz8l9jIw4YzAGEYiHhSEWMFOujdHWXTibL6UdmMSgQuFUWNUzF8yVUkWFxxiogRrsGWNFTfZf1Is/U22cL/fv3Pwvb/xsfGYS2paCE16LgNR1pd5d3u9uH595fOvosDkIR9dOYdUJB4YjWQnWjuMoe2FaP9gplDgpsIA4zB0VYWjo7TmwXU+pwFU4TpMmZA/1PEA9KaNTAfJ7eZEyKpS0tRbdJFWwsF0N6lhVRYSJJZjHnME6TACT8UisY05UkVw/2axgOBVpmGqJ1px2DChKHS7ByHdAqqUyOmWTs/Thh71MlnNTHDNVp70MuRRFNJ1egFRJRMymhigN+xUKZbCHQuFJmbg0VrxqQY4Br7bVV222AWJWEoYXDYBn9mAR5pd/96v5+kE9GnvyIuiWseuKn/7jq2f29i4++sg777y1mHd1vdl3K5fcd6OqAp7SztYIBPTFUI4oQB7koWWSplHtSEABYqM+BQkcEFVBwaOQpS6bZqP2X/jUp5+99rm9rZ0wV1mjWQasoWhXbXB9eeXRx/7d2TO/fPml199+rd4ZwbM2ClJycJ61JZCqY3iet8GPJ227XkMLwaOPnNrUHd8txnvnPu6KxYMP63K8jkA1radnZ7PDLvbkth85/7l+fz4/OGjdeBRHNIeKbNK0iuM77398sPHY2amPx32tdb/sm8Xhce9e/9Vr29uja5+96kj72BMiIAJxQEKPQUwsiIa5EDtbg+MdW7uTE5pI8leBUgCYmSUa4S/EvJyabISOnpkgDkISEupAzlh7DCD0AUmUr4Ay92C/7kKPCCEWLtTFdceRNErbaYH+9Nb2f/Nv/r1z8DQ895R614yxWkrTfGoMyLVlPEizn9QYp25iwMGQJ8oGFA7kijx0AZBWlJjCY5jTprdBef8BMRHlRHiSIPNhQaZmpvyUkGmQpkfR4EdrTsWk2slbyzmBKsFq++x8k0VAavVxYmgClJW+bHfNMOikJmSCOTOQhTxKfTMRM6umWYO90cSfUCRcgQYPDdXc3qUYSCdLHWxI5thcIEREoTGXQUlXE2PMJFerC8yzAUEjyGyfbWurZRyN2rH3EjpV3pjUNz/84Cc/+7tyd/OJF/aeunbtP//8Z/fDg9Pnzi8XAubxaHrxsed33OFrb/y24OrL3/nMP//oVc/bOxv6zsf3rnz+0vnnmtsfFNVWoRuYXBy/+cHhtS/9q6e+9a9vLsZz3nkg28d+upQdbgtZRDRAC6wJa0IERWVhoIcaaSKQ0YZUYL5diVqUNS3W0jKskRIVtoVSpLDtqmJHSdmmqLkagapB78l6WqECl+Ypht+kB+qh/pBIOfts2K9jIs9UEpVRHMihFK5Za+UJUwUdKcbCNWGs4pV3UZ0tSyrHO2NGG7o1kXo4XcfIoCZoKY0c12V59+Z73/jMV/sReNejZVoaVEroHHUVcUJHKA/A81HNciOAElELooGYE2M/TT2NKmrWFlkRngubJPzNZmrpqbNHKB9PRvIzjzEyk/c+whKuZoNMB0J2ExuwHCuXDLbJ2kG1zZuZ22ixIXMgEtygqZfUREhPXTGnHUonDCRFOhKcOTn509kIDSftrj0KYr6jyHIsTimbHRGLUsq+YMBbxQ4lokLFqTLBAwSUBE/glJgJKG1GASLAQdn28wRmYfZBuqoq337r5jt33il3CwgJBRGUZTnvZnff+ejRxZMXr1z1flqW24qOmMEh9j1zr3CAAC6PqIhIEUoLNLBthw4INpIm6gEPwGQFABJo4AsnXd8083G58cWnnnvu+Wt7pzbaZWzurdGxdOx6T+gABUnXtauDrhj5733zD/Z2tv/zz/+hmJS8zRCJfVivxK08jRlEKODrouJytPuE25BRgQtPnZN7H9z/8M1Jea64uHPUjo76Vas63Xq8Pvupg6PXmzjnYlf73XtSLptlGSmEGAtRUN2Pqr5e3Z+1B02QsDqcV7Xvj8Nv/uk3l85dnGxWP/3p3546VT965ZyokjMLFmh2cHCOTXQDEFiIPJu6PUOnSllDDoUDG8NTlKHeF6o2eA2qxCzgkh2pBLOlQ/BEnhyRkBpQAqAAOwYQ2mBIiv3Vw2sfGIQgfa+A84IowYdKO6c+RG37EEw/k6X3FotsMEac5pL2LCdEPU1B03FCmssmbVCC9hJh8SGYK/8pf3CCjVs4pafs2WKrglSiAae5P86jUEUejiKlXxrq5VTsG8+YmSgma2nYLREj+6IngopjZiWNwgywEyBr6SGp3DXmTfKaFs1rzO3BTtvWYALq9M1DSMsBMqVV++eYk0dKtFa5Zwoa8oTNynFRMMxgkohijDHqScwFoMpEg78xmymmCUQFvx9wPaewBIOgNWHZHGIH+Kr0t+988Nprv/jWdz5z8+DBVnX13t379+7cPf/0lTBuxYWljv3W9lG7f/ODt7ZH41feOj61Oz7/7MV3Xz48dbqOYXbrePHol6rr945k6i9f/fQbNz+59q1/+8Vv//DmcnzkNw/7rSO38SCMl8HzvJek+id0sP/RzhrWaBokRXAUcQIvBs5wiA6aLJhJJaWBpgXyhHgm4MRweWtuErpPRODk05LwKNKgnMXgAlF1yQsqMfw9sQd5hVMhVePalCqeuGCuacw6Ui1Ex6AxYQSMCBPFWDFhLtHUqxnd89WCj+6W2tb12LNDdF0pinI1qbpJhRYfHtz5zDevffrzjz046HnK8KRmPAlIEMBHLaAdyHhz0bYvOeeCMYkTXCR5tuqISBCQmXpWf4nE5PySV3KZJRAx2BYYA5mKaOd9KLsp95HJYjVxQYR9BrWyYt7mBTYQFZE4GLolMS9ATJp2HoKJs+4wa/vzk26kYU2p2IrNJBFO0LWmGABrZWNSGmmuVNgcvOxYqRoYnhwzrS5PfUXKwUoQJc9elUQMSy8YJJbi1DN5go+RFSWRI8fKKqXAgz07T/BQSgWbLQcXBZg947hZ3F0+oB2OIQAsoYUUfaejrUm9Wx01y+t3rt97MGtbjMcToFVZgxwI0IiTCxdOjI2ix5ohoEDKQK/kiRzxWsTbAyFsO1cZYFp80njPzz1z7fkXru3t7i4W6/1bq4IL6jx1qn0fNQA90Kuq57oW3y9D04cXPv/5yXTr7//zTzDr3Firjc3tvV1suOClHtW+8peuXpnsTQ7Xx1p289XxwXrSojmUO+t5nJx5VM5t3P7gLWE9iufacHYf97tY0rKaHk9k/yge9LFzMhUdAww6dnVXz+83BzfubcddH8Dgo7uLSbF59YnLzsk777wSpQUJsUjsmQF4hSOOjjwlu7GeSAmFmYcm3wQ2z0lDYNN5MW2rs3JQI0GBtJlbJKhVe+KZCxOhGXSjawYcPDGT9gLH7GFuezYYCKHz7EmIFBpBQioiwoRCeIkS6yAlBBLTjiPnTKKQntIgUgybRRLRNN33BNmRPQ4WIoUJNp80YQ6yXomS9Qslt/KURkFp97ykvlmz0lCTVTGMkOgzl1oT7W/IxFA18YKc9IyGcllFS2reMdbOMBE7hYqIiUjJQChv1IuUKc2+nzOvRFRZjKOSVbl5AJm72Nxe5y/JTLBhZGXgp82IzSQwxTgiD04tnflZKpDXs9hrm80NElaoMQozHDMxi8QQYlF48wwCEXNigBANemZFVJHel3UUCVGYPZEQmXwkEBXOo18vjmZv7my5V37x+gt/dP7Vd392bfvbf/z9P/31u6+c37nUlqu37r7RXzl//a3XHz/zqXVzYzFvf/6b7k//6NH5a4v5ka9HV9/5ZHXu06eb0eq5r33/7nx99YvPfubrP3hnziu3eyTbRzw5xrShbV4oN6CWdKWyEloxdUBv/bmoWPsrUJEQwb0lCiUWe88AuDjBpNOTYatBAZCYZgZEUJ91qwpjX5yMOIzVnsfHUE78O8CIa5Ss2iGAU04b8hhM7AmFooB45hIoBEJOacQ0YYxdHK/8xMuYeUoyprgRNjaYlgfXrsyvXqwX++0nN8OtG9cVVTnaALxAG95cBK/be6uIrUtT2tPYivcMqAZFJBVwYADSFOxqpMlISCeH2BGreDXIXSESYJWwSB7cJgCLrVIx777cfxovz9SyNgmnhNQIDzC0YXX2fxXsPEGJnIhkCCn5p5prekznmkxnjLT912ZF5sWqnilIFjadfNnJSbiyEGkUgjo4MwBId5oMg1K7GqrZaXJo7iXx/iXxyRJgJlBR5WhTIZ+mNSYzg5IwETN7EWJ2jj1sK6dClFVL4kLBQMXeRxUUyqVSBTiGh5boWUDiS08MLQBC8AHiC4gr+JfvfnxcVmcev/TJrevkA6ILS71w6fyXvvpl6YrVbF44X2/4esN/fP2WUyLiiBbqQB0jiAZK0F+vRpZXcPQQLyxkM00PcixEUpIXEgDsClDTNtKtr37q0a+98NVzF0+vF/Hw7tIFNyIJsVdxikCk4MgIGtfsWNC12oWeXShmt5vz1c6LFz9F4bByfX3tGj96+qBdzhZzdq7X/s7bd+Tt9dpJLFqu3ZXJWb+ou/UEjpqDpq4faehBOz+a9l1HvT8q1vfVF0UxgR6CD0qJGroW9Yqrmo4gi5oXjpvY3FlMx2MiH5atUPvWW7/b37/1la988fKVS11vPv1eEcgkhOyM8MosTIhRVEwgYIxLtjicJjQQy5nJsNF5wIz4SSQQMRCDWIPkmSlCHHtmRBvns1MJJE4DAYxEAYJtuwPIwxNIgkZRRWQGEyICQzQGRPEOoiLc+wyT5sELkWExKprniKpZU2ngrLUhqWswdFCRF1pbFhkOlR31k9yZf2iAicCExNg9+R5Wc08zzVGiJib75Yc8rqyXSxBujMGaP06MGz450Qqz5OL/HcJo3aY90EhtUiqukbnKwxR7mAqnykNTv2ovbJlBJGmvTgQJqdJOUqTcKasBqWm5Zea5WFOSUzgGFY19KFvBTiKDWaBV+XZ9rZETGfoh45tAJAqEnE320jpdciSRSs/Xb7zfNLefeurxO59cv/67+8883x/e+6fnHvt3Lzxd/dU//W/bl/euXnmymu5+7lv/9spucefdXx1Xv/nok1vXH5waPbG6+SYmFVpefxRPxz1/s9kKk8lnvvGD92bVuqiOZHPJW8fYmscRjhQL6DHQACtwx2n624p2QdGItCq982J7glViJGGGIqqa1ZDpBazDIU6EI2Ul8DAmTENf8/EyGwVzEHgIoMgjD9VBUZMxA8kQhiNmVSYTK5nLkuUo8ooCVBJKGolW0Fq0EjeRYlqGWmhTdep4Grao3eT5wezvz/GdcKu99mj19ccxn5957ZWjB7NZF0IQWbn12NfHbddX4/HFST9i2qIe0UVCIIhA2UWWKBw8hKEe2iOpS6NIz2wCH8pFiT3SCgzGy4anEFEyuAaBHMcIEVFJJL6Hz0SeIKfvzUJ385HLJyQZhRkKiqSfThIFiZJm5qYUAECckigTIAyGI1aXfEQHDaRm7Dp1pIzEvkiGQCRi65iTGD/dOIjaipUcbm0+k07EcBxOuJGU/HxAxBbKHJRFU+cPZVUmMuGZZzCImQsVM0wn8mSaH3GqZeSStCCQkif1Ag8UDIfSuy6I2yhu337w3t175eb23unTbnkr9GsnDKUnnn1qsjddzvvtcm+9Xl+enirryUcff4ReET1xLdITlKCORElUeoEnoqBrD69OVNZOGOIYjoIPEMeqPSmTU4qQWTM/v7PztRe/+/RTT4R1WB7YjtsRM4cQnVNBhPTEIfTLZnlcMquveyaghPI6xH7ddO9/MP7wYzeSo6mUHy2XKxyERdMt67FXR955lBNxQVvpFl2coTt07WHVzrTFcnr58lT22vtHLR232tAD1gfwFbtFFQ8VC0inXdutR3Fzy9NKeCG8Iqz8YTt775P3Hn/0yqXz55566iKzxHjFF15ERXp2XjWIOHZONaoKNGpqmTIrIpktURLTZb24KBSByCfJjvSqpBpJS1hzhGG3rCg6FRYVqBDMtskrA/B2qKyqTekye2PYw4rM3RI1KpLEGKARYmNS9TmUp6NlSSVnHEI+iil4JWcDe0aHw2Kjl8ThBRLersiI8cMjJ+S0dHKWc6uCNCnVYb8pZf8JqAQhHo5PLoUhqjJATMO/aNb74CHKU/5AJzOz9N9sumXvRoZyOU2xs7nukJNhjRaJmdoZsJ3DCGeedv4VJ/1avtBWv4uoIrH1RMSqC80XAxj2CRJSBXLCvR4IM5J0kEREKtnNw3h9oskVymwsyZYjJcxOk6FlBx/29x9wIavuzueeLXuKzf56fOrwrdf+/sq1L33zC9958+O3tquzq/3uwHez+YPPfepLO6fO/Pyj/+eNB2c2t8OMlxht7FzcOQj97X79yY3DP/sPf/bug0nrS+HpTOpGNle6wUtgCVpCV5BG0AIt0AEtuGfhQCow9iAJkaioatAYmQygtHQiCSZJehlJDoKaROEmAYyaRvWcMWl7Dn1ueS1t29VlYlExgMVQCR0g/lxvWfAlQxWJiUtCAfVaAQWhVpTAiLSKUjFPHLYEU5nq4V7ZrR+8987P/uHoo9kGd4vXZ7ub8fkvPvvvv3f2r//6pbu3Y72xcbAOVbm9Na7W+4eXd8u4EbChrI5B0is60k6jFzhERBKT5TsRB9tOIQwW2LwXeIiLa8OKE9hJBtIVoGLbBpLSwqhcznbcIrnZWxOaBEJ2spIIPtW1Ji6yJwsph1m9KKUvLR8nAZ/BdszMyTZEVYzAYm5xw/NsSVeHWGH0EdU4UCApFwbG+EhibSak7bD8EA1l2HMKGgp6CxDOaOOSlFF0IjuEI/YQD3giDyqgDvAgM/cuAUcVoYArHTloAfGRShIvPHKucPAKBkoKHJiYC1TMLfWvfPiRbJYrXncbOztPPnr7xltjV6AG7bg3br39xm/eeOLCE5fOPXbjxluHt+9JHdmJdtC2YHiLPVVVeo/VeildsMzAIgKJAHFJIgqJYVUVHLjmlRTMTbd00n3rKy+88JUXfO3nR+vIDFkXSqFvpFvGeiPeeyCzQ9A6HM+O7+27nWl7+cyDTsMiHq+axVq6pj833ZpA2q2t6elTdYX9t96XM9v1md12XRzsL7uuD91qLotQakQnXm+/d0+kZ4iAOpKnuRt3O27GCOsW81rr+X2SqpfNiFnALHCAq0lnIWqQRYhHHa3o9nt362ISutXrr786GX9tb2+3C0HIrbtITExOYiCUzCIxEhyxKIQ4GKOWtAchI0M2wjVzBXHOeMRgMrE0ksKE2L5fradSG+kxsydEkSgSQJ6UQSb860VB6tKQUXPzZhMRieAoplcTsT5YiZhi0j2Zp1oqcE2NzqmsTS2cqQzsRW0FJYFtunZyCnJvkEvo5CihECg9ZGM/6D1SRLVEp+YlccICUWjag00JvafMvjKmjeBEp5u+JIG9FosHz5xhFpu6VcOE08tYLj3pbmOKRzIEdGKTGQ94l0mm0+tQssZLIUCh2VEgFRuZ9zP8yvQe2Fav2pjB8Hwd8vtDtPFEJdC80CZRV4bG5AQPHzSgqRE2ESZUzCOAJfnXIV1phvlPeB5J0KeevvK//S839++sT50LGzsyrrff+vXqrRv/9NwBrj5/9Suf+867n7y9cX7cHi7vdA+2di/tjC/epwvX5+7R3fOzainF7t529dEyvHd0+7//P/0Pn/DlB8wtlW03ajDpV0TLnlvHS9ZjwZxoCTSkjXILXUPRAZ2iB0XSCAnKQsmDNPVAZNqCNPwjJltDoBbB7Wk5eR6YkzwGZtZremeNcRCO583uGWMQ2K+j1O4l0ScyV5+gnK12ChVSccrgAjQi1KANkk3VDY0bggncVPb88ag9Ol+tfnv91e6jj3/4lSfcciaL9vaH7/7uJ59cunLu6e2xP9gP/T1gNxBmq/DodPzrf/hffvDf7fH2eQAijE5ICFElCPeMlSJ4IhAJKKhtw9EA4Qx4/NdfVrNhcNd56Mhquj5W5JlAyBgVNnVKsK45PaWqkEybfdJqa8x5K9topEVm6Ynlk6AAIJvpDU932phiASS3vMONGdzX7Qei0axyFjcfdB1OdjrNEBY20VEa/Cig7JIiVsR0iZIYy2CCo+RMmSpfUiawCinYeQeU1u0CJTyTAyqoV6pJPXhM8I5r9KxSRq49vKqDq8ix05ICwqT2b75++3bf8imPfv3At+cfPzdvb4XFylful7/9WWjDYjmrDhgl/+r1f/Yi5dijBTsfIdqpomKialSPKlKNKg1BVDgU0QtK5iCt+Qy5olyoop8XgZfd6tGL5/7oB3987vSZw9Wy/XBVa2iO5iqh2Npp3n0XFYLw7Ppby27edavl6igwy+a0+7Aab+1NxpvjyeTi6e3pxnQ62S58RVS4euJG1U9/hlf+5eVy4kPsyLNAi6qgiedSXcGudt39pS88FN4777C4O6uLwnWlrjs5DuNy061LRMhx5xbw65oi+rbvx53f8MtmsTw6LlD0nfTr+eZk2gd+78btR5/4FNg7LqFRokrskPX8TCYWElXjM1tfyxn7kERoteGHSrQFdNaiJUdvm1Sm3AtRhZHPjR0kCeO05bfmpkAusS+IIT6fEgBOxYoAsbaBc8qIsZeEVYumlSjqmZCMhHOWAwYImShbbQDD6NdS4TB6TfPrlBf05MgNnL10em1mM/TTOccPgYGBZFyZqJ6/138Pcp0MH1qBnoruoUZP5HNzOtFsSGhFAxFy96t0knpziZ/SGmftnMUpdkZVT1mf0m80ID6xSwY04OFXRf5FqaDK/8F6U2u4SHObDjKeF7P5C55QvhmDUwFMISIqRKRs4lcIVGIcIHSIKqu9TTUzTkr4CcMsxoKiAAtx27e8sz05dzG+887HGl+o/MZbN64fLqtxsTW7d7+bXz5a3Do+flCPi09d+PS8O+qa4kazmFz56oH/wIfxclKOz5SHrnjpv/ziOz/8D/3us7dXZc9+HWvp4Vp2x9ClyEp0odSAG+gCZJPgtRICKDCCoPccY3aiYRZjt7mkdrRpOJu3vQ23mVnFJMMGs6cizINU8iY2S90gb2dxMAKlRIlNsg3Ngrpsf0JkR8slF08whEFsRtAKRyW0UCoJNXSkGKnbKngHsimbMh91989Vjd7/4ObLf/fZ83FPPnrztz8/O9HzTDGA7jadFE/tjFSrueff3Xrz4u6Td1v5aH/pFh/snd3d70p0ymPmoOjAPWurVDHWiAbhgokdwws8KFg7BCAfhJMHOB9j/N5fszo+BjPVUWaydT9EabySn3+1LiEd4qQlTwlvMIoZKIqmAwwJDkotgc1Z8jlI7A+jEIqcbENJVWbS+iO7d6VIQkwZTrTePv1vrk1Pbrew0SwIhLxIgWGq6OFIGTIf06YOs+0COYLJzLwIA6xSKljVQwsuGRW0UKpIK7OdUqkZtQSvrnahDMEHVzvlGErl2gWO1Ua1Pzt++c5td2VSKNBx0zfHYzr/3JNv/epXF8+e/fIL31jN2uWDeRnHXtynmqv7N2+vZ60ryrgI2gcmolAgou8kBhO8cAydCBoRREEMIFcWo7Ioi/XyXF1P9nY2ivHuqb0LT1yhew/ufPxJc+8wTKp7VXH0q5f9+fMH77fxvTfb6akIGZWu9L46dfriqSd2plvVaDQ6tT2aTsuy9vCdshIjeIiPcKJBWnz9Cy8c3N2/devmxpndngMg6IUXJAW7ktHCF1UkVYYvEV03u/EJc8HtmKVe3esCLet+Gtfx9vt3u6W4sEVKodVuIUqu7bpInd9w6kgkzkOj6K9//MGzy889sne6Waw8F65gxBKIUfoYg/MVEIHI7JMjBwJISXsbRCA52Rn0xTHakq40b0qu8rBlh5qN5m3woZaw2dZKk2MSVRva9pTYAyBK2pjUkIETgAoxQjVIVNWxbXxhkQBNIxuvghMm00MVq+UASVKdhGhlXHfYDZd/wHp1K6aN5ZvSL+WqGycAdPqBDEsb4Ju7xFzzUu4Hf7/btX8yr30dIkmGixXDlcNJvqScp80PPqt18mvZvNuE9nZEHfMwtg4xUsbYh1RNCaQ2dpoCygNQffJm03wghQljiSvnaTvoZFEyIZVfRInJDgCpnbCRV27sKTkJpeugGXY+KXQIkEQsIqZMfGUAbOY5IQCC0iG4EY9vXP9FOf7wD//oh5cfe+b9d+9O/JXr+6+eefzcD7/9g9fee3N/sR9KHBeLR05d/Pj27fnBg3oy4TDtx6cPcVb3NvaunT3cP37mO4+ff/7LHzYu9MJdwWtBD12CGmDJsQlowA1LI2iJGqYWiB0QiFtCIAGTpOkuJdTQsE4CqUYr2Ngl4aboAACkR3CY7ocsDx2aKrVlFGRXXpI/uV3FxPPK5ROzKucRYlYBaMrBBvAyFUoOHijJtL9aK40pTiJNeYuX27LY6o/PTRe/+se/d/P3r5zevVgWHzWrOB9J0022JzX0aP+e29y+9NjFR07pI7tPV2ee/HDe/vrWbFP2nc6P6+l6MpJW0IBLqCdznQUD4qAOICgJDw0kD6L53KCmZ3EAgZGzshW+UeNw3rNyFhKjBZqThAggj0jsXmRQHw85G5hkj0zYSyBnbmT56aT8QOeRWnobyK27IvtP5WY6ubQhCeiBwZ9ssK96SGKQErS93yFpU37lRE8hHiAx62Yce7ZgqiAoG1c4t1AMFARW8xv0Ci/mMKqVogaNCAVQi5ZArRiDK2c1GXmOJKEKriSu4yu/vt1MebLltQv9El7Dg7i6sLt15uqVsqi2HtmaTKenz+2tZyE2/Qtf/+p707d/+9JrrNAAIi+rKF0vnc7XqxAb0Y5dYA5lXVyqt6rtrd3p7pm90+PtzQ0RunmzXCwWq5Z3JscXd1/9Lz8Ls8Omjt1sWe3t9W3jvYwfHO7tTMbf/vZ0PB6f3a036hIoSlZEMIlKFyCgpg3A2sNHccolGEFlRNAgrhp/7w//8K9+9KPb+/vVdKwiVLCCgK6P4MJTB2Ymx7IORVUxYlDSvowiEI5dz/AIvpFFgZI6lgCNQShI0S/DLPJaC081S1TR4NmFRXvn3p0Ll0+XXEBIegEB4lTU+zJKRyBiB8RU9CECBTQkeh08WQgVUbX1l1b/BWZieBj30yY6iXcAkECJyHGK/aYkUJh6GMJwqsMpS4Qb1bRH20xTzbI4yxMikTLbXgMFIBK9zVFPBo5IPN50VGwgPPhESaqECaSsGbdD7jfYIsOQxi3N5u/CSZohDPzE34OpTjAtsjGl2i6Gh/M0Tkhd6TdliJpzLpLM2U4Zzmga1uBYF27deJKYDr9dVYXActK6AwMkn1t6m/h6dpIpVoaFBonmw/df1xrJFE3JuNlEQ2zLkouE8bk8wkuXLffiD1+fgW6ayy0FcXJ+zg4JBiKmQYBIhhps366oGRWJ974qy7B76vLnxlfffu/WT3/2f9ncOP3stW+eGp+5897tv/h//c9SllK3GEeJZ8+fmz8yOn+4uqtdN7t17/JoVMvpixcuXKwvuquI4IM7YKUiSGw6DiU6yFJ0CbTKLcO63gW0AxrRKNAW2kF65h7oogTRFlDmKCpOJO1NYDU44CFoxTjotvM1VVQW4lWidV5s1wcEUNCoqi65KWanChWNmd2WqOguOW8IJAr7FI5BED3ZZgjvU+ProQ6oQTXRiGhCNbcbstiQ+bmNdnHrrTtv/PLKlixvvf6gufD0uSdvvn4jzL2Hax70rq3Xi8X1++9OLm9cvBbAVRWaz16+8tLf/8N3/+wzE/h+MpaFoCZZKwqoZ/agklgK1aDqBAGSWZFDvhqukBX7zAPhMHlBmz2qpGLO+wLQCDXrSom21ROAVSxI8EPa6SaqqrZNm4mZQ8gLMFKXmctJTUCMqDKpJqxQJbOeUrhQW1wSFWkfsOoJKdoyvc1rk7gQwsTOeXulAVOyfxaB44eekxQgEhaZCNywwbdNbYYVLMzsCF7hFETqhBhcQApjQbPzWgEj4ppQI1ailaIWjMA1aExu7KUCalABLZU8F05K7aYjfPTh/uzWB5d3NyEzeGkrwfq491t35+35T1+++/57f/6f/nxUjMc8evyRx70WZazr7ckSKxcjiZAwgcuRH23UG8Wp8YYbbRQ7pyanz0y3pjW5zvVFI3o8O5y99dqN27e6cd3Cy6LB/du4/sp4e7pxdXenrB+5fJmZp/W43t4VdJ4Rwb10LOSUVnG1XPTOJWCJ4AmeyIuywimb0W3nPffrdenqvl9MJuWf/ukf/fgv/393796fTDdDF9CLeOKSZR1V4QsIRSpIV9qxkIqLDmAJQFARkHApHiLwhJEjEYwFdZi39zASPy57JwyHGBVgpdsP7gT/WZQkIlyydAIBB68BDiNAFX0IHcwZkEvVwPAEAiTRpLNG1XpTaKrtwJp5nQoopaFWJE07rGCbNBXmaGIWyqQM6YlIAJVo40lLJuxyKhSbM0bApqpKoGADQUQAxORBNBCBcTJGHgzQsombsJqSXh+S3uRkogkAPKlkhzRiDJFh8EZEkjHhDAPqsOAWGHpW8yJU4lwV5yZvYCYn2nDKnEjK/FxeG2ybZQ7WYrJB5ppZSKoqDMPdes2bzB/qzJELDYkyvAH76kOkvI7QpMDWvya5sA5XIPPxSEXD4MmcPlcqnATJLsAg1yy3+L2GOykeQTIkZsc84IOJeDYMIpwDECRB6KYqVg1Erix9WRYO8Y23fvOb1949vXee2BPjU4891s7xk5/8+XR67tLuufWxPP35venFeYPFy6/ceFXoG3/w1ddevz1b3n7hm1cunH7i1Okn64lffLzmmrQo4po0Rm3AKEMXpAX3rI3ElfCasYa2yh31jbooTJ1on1TAIkQRFEQEENWo1p+pBkROUnCyihQn9z4PF9gMsMw3CR4cVYQ0OfU7RlCVCO+BE6YeDV6mw021etDAe2ak4QKsaIymaQBpANdKRGYMCw8qFRXEUY12zN2GLHbK41+9/vJu2Vbtfjj0b713vepGesSTQmtxs7vzelKe2tmOoiTxxu/eubN6vd/6dH3h3NnJZKuSWbPy1GtdUAktRApERACsFCPIfCNBIrYGCshJbTCQtC+CDM2lQFQ0gbAEdmypNEZxeds0EatIkEBgLoiS21ZEfrAo9Q0iQZltR2TCIezY2h+McwAom2EW0pDGCqesgRIC28MpIgSnJ1QQsg0OSVcoicClCc6IOUPnijg1y3TClwCI1NhhGZXi3LtoqtXUErvB6k4BiQolZi/qHBcKA6K9OpVCURIq4pp5xDSGjBSVxlJoBJmwVIIR+1JqhAJdJauxl7Bevv3qq3s1KokhhKLe7MqloO+7FepdaW4FfXDuyiUEPr7X7M/u7N8+4JYnfnL+6pnd8VYdqppGk2K6u7EdFzEu+65tF4uDKO39/YMPr8/aZrHql04VsW9Du31+Z9vVu5Od6cUzriw3RqPxqIYDMUmHFYMEbTcXCKsP2nrxwSY+RqAOobTHg0URKYKZI4IQhciefAgA+RWih+/7db05+uG//t5f/OWPDg8fTOutvhfyLq4iCnXM2kaQoCwiASWTKHoREVaWSBBhD5QllSoeUkIih0oWaBZ6LBONpYAVRq4RsHd35vvLcLy1Oe3WidaPAHjlyFDSDhRK7xzIqXQqvSKoFsm+AgCVQAdlsD1dDGdDFLWnThCZAAijUI55CqMEbw6lIIaarjZtNDTUhZQVnYEtRpZm562/S4NePfGEYuZoE2KFSPCOPUDM5rmakFV7ywoQmVTKenFbCaRktkOU00PCro1bm+GcVDkIBOyZnEt+6llnA1W4NLhL4FJOwVGTywclXQ0AZaaQmDJsyBVR3lGffn3+7envDBMuWHVgQ1OjVeHEzsExW2nPac0YQGztxAkOYTtGlTjB8mZ/QWanQ0gvi8y7TjPXh3pXi+qOnELgoGo01ASSJeMeTm6ZJ5QzALldVgFUE2SX9spIGoobXQ0OzNCY5dBJrMaskYmEVYL3FXsluH7d7e+/91c/+um6C1W5/bs7d7/2ze9euvQYkf+f/6f/91e+9vVbt+7d2z/843/94t3F37/9cqgmZ568cOatdz5+ef1S1y2+8dWvTWTy4P2wfnDn7uzOzbdvhSgvfvNrpx+5sFwEEgprlL2XGKVTWhMtIa3QmtAhtAIRQRBtCWsmidJ5UkIPiCfJeVQQBSQ2CwAQY0zD3lRtwVIvsuzKeLiqOe8SwTuRCFHvve3jsymDZkWSAGBEicmaW6AMdkxCBAfiGNNSL4Zn9kIFUUXkhUVJ2QMFoVQpgVJL3xdxVdLR1LdYHBzeem+T5md3x5t7bkO26479spxW1dvvfnTzYI2li9xdunpxUcy2NqtHn/K/25+/+cbPH/vCH1bUei1r1/feoyD1IMB7VSZ1EBKo8WIdJV6YGzpas4YBC2Fo2S2vQa3yH7SCAgKiKDkHKInJHyJAnr2IhD547x0T4G2gkfB/qKqwp6hpgu7Y4pFZc6S4AUEC4DIUraqJhwFVMf2X0ZTF2TojR0ZdT7SstJaYjfltQA7Y2f2i3AA7c00zFj0SzK0WopMbHiiDJFZ6KEBCUCEyoyuD8h0RETlmj+hUWJRB3tcsXrhkFIwihFJQgWvHG05HwChgLFIzj3Sqq1qXzoVSZITFtpeXf/0+FvcujKddO9d61DeHvlnHGEuU041w/eaN77zwpXNPPXvUV9R5zENzPJcj3qByQyfdvJvfna3n0s0XH965udpfhEUnnRB3sW/KEr6icjKu4UPbHs3aa5/57NWrV7wHVLpAUA1dP1+uzQxEkVjCBDiIoiuYlVsGbHclE+rSaWauMYltaATIkxcSoejglHuyJagRErvptP5XP3zxRz/68fHxQV1vhl49vKygLOxZQCiFWKklUUUAhAUET1wXqJlLqGNXw7kg7Dvu5sd3ddTWjlCCEYQpgBHEoVg1zeHiePvMVDQwFxQUAWbVjABbMYC1t9DNzDFIjEtFKLxnOJWeqAYHoFcJqeeFS1ALi2fWKEoapQXI0hxDoVHAEGI2tBiKPiPMGIpfAaVtHwxbI0uZ5zU8mKIq0hkv1LMLGvp18ClFDJ2fkYwp+84aOdLcIQYHduQOMUNcw1zzoeybBjwiwprg16HnU8quEbl8xvCq5iaSnKJsTXpCvqKaOQ2IEmHGUqYVAimR51+eFUwq1qgrFBJFk6mOxaahHUraWyQyDghCiqii5DgPA4mNyiMiAl96sXmijbPIMIZE0D2Jh7mT1kwpITJvLx1alYfmX5T6Y0qzrkQ/QQqixrpSdea5yQSQV5gsweoAlWgBS2NYC1EZnCuJamobXTy4d9y8ulrfaleLTmVn9+q1z1z9zW/fYl4/eHD3zTfe296ePPP0pcW8uXH9w9+98sblxy8+eu7+u++stsen+/t367P61FOf279+0J0K9w+OQqGnH909u3Hmw7dv/sX//Uf//s/+D1vjvXYNr9C1ciRpRTtgBawFPWsPCb3zgbBWCYq1cgSiaAR6xDVM0GtEdLVkrCAiZwPDdJWS/5fdhnzt0sw7VStm6kSekzOOISL0EJkOeTTgPUNUBIJA8DYHMljFrm+eFtiOH28dqBYiDDhBSSjBIx5hNabjGutN7o4+/hCLGxvl7JHpTntfZ3ePmzvS7xcHN+87X2z4Ka3Dnfdmy0OpL29OLmzEunnu6V2educu7fnQ1Vg7WVE91grkSQtlz1LA9jhJQB/Meh9MykxpIR6g6MSIOURGBU80BQiBhiVj9mnsnKhktgbSaQUSrB9FRJJlrCVRK+8ELoFEApEItQVHNvG1QjwZsWd6pA1fyVZ4Gdxt/Sdk+BmrvOwoafrZdGchIcQYmNkV3jsnMbmx6KDEI44q7HLBLvTwGnIhmOWRbS8TsDoCFQQmYccFhEGOqLSWl50X8lDP3sM7rTiWwY8RavIFaMw6VqnXqEgnnsZ+7JcVrTbRlbr02ntdbY/0k5u33v71W9tj79tl5cEB3uvWI5Uj3j6zzaP6+WefL7cuHscjAc3AHbtWmnXo9g+Wq/11XETMKTZwvfrAqAgde/j1ousC5sdHXXvUd4vj+SeM1Te+9Y3Hr5wLXdM2yiBh+IR1DFMy09Alaq5GUQQYEYJtrh9FlJLLouEE4tmJCEMURhw3tY9TDcwO0ncdTp/Z/qPvvfijH/2471fOlyKdWg3YMbM3Fo+kGStQAqXCE2rQCDQCWLlm8SzQlVtK6N10RDKG8wIGmbYIti/zXnfw6Oi8qEIiCkIAR4aotAIGBSIQdYVGaBRRp1QQQcyP5YQRTIBLQ1kSBpktXg4ldsaTBCKBvqb+FLOXTxQjUTMMT5ods00kUF4IQpnxCWYGkUhksimOJrdqCDN8GptqVpEiY9kJ0UngKvK8zOa/Ce3Nxo046VYzDcS0NsMQVhWkiDm9/d6XmgFUmmzntfYJhyZG1n+KZceItCc0Y0knI9V0lu34WfNv8yWDpiQBtZSIN9YWqK2lG9JsXs7INGyEJ5hWFEwO3i4aTjYhpvErJUGm5hKAhtueq5OHY78mUW76CeP0Ui7lzddHVNWYoqn3symvhyUgnJDFVYS9ioo5aQO+LF05Eul5djA/OLjTdjOuZuI+ZHY7W6c+/Znqn/7helUWLzz/hf/4V3996fKjp/cuPXrp4utvvDk+9eHnvuTeee3G1t7eucnZR8912tYvvvCN8WR68OHB1s6uzHC6PtWFVXej29iaXNo8/86d9uW/fvlf/fBPmvu9JydBIIQVOELXrGtrjYLwWkKrCMw9ECltXouwREJRoRpt1bZwIssYqcBSBgEJvgfzwJJNz2CalQiQDktaf6xKljrsUrFmQD//bBayKqBRBEwwerC3IYIqiyop9xDv1aQmKM0PGCihhdboN9CNZb5bN69/8KrO727vXf35//eNjX7XNWW4p1OqLo6e/ODjD8qNVojHk/H8VrvmrpPRwUcz/uDGt/7bP9u6+tSH60XN44oClVBbbmj2Dw5mNcycNpFCO1UVCPFD5H5k/V4iGJ88IPmp5oGelnA20mSFbd9gLJF0agTI+8rTD6bC1zE/zO5XSRa25DjLkpH5XWp8RUmRLF11qxK8AwExmmmltdOJu6AAkhGZLfUiiQIGu1RgUVYdMjOnfd8JH8mkFlYoS8bmgyoicbLYJ2UWG/064gLwDE/wUWuWkgoXS5Wy50q5jFr5YgwZgUbixhQ2CSNx4zD27QSzEcLUNSO0XhYjj/5odv/dl79ymS6cqSbjyWR7WhWoqkkgbVfr2WJ+v2vuLfzNjz9cdDzvaKH1Els9b/ugRVUV2xtVrS21bdscN00369ujdXvYyryXJgpWzF3t0SwOz53f++MffPvs+d3ForFqSQVAgm6Y7CqRqoRgBAAmVk7mrqoaVA1JcoDRh8iluUAgCQo26Cg9DwKyHRPpQMb1url8+dy3vvX1n/zk75yfIOFMzOyi9AQHYcQKhdLYjgyoBEaEMUuhWgoqoHRciJbS+nWxOZHMsycIJMDM7Asc6gw7xCPWAATRXtEDQZVVTS8Q2LFD60nG3jl1TNSJBGhkm8gpoMocB7BUAWN9igopkzlFmzLuZHZp6lARJSBAyfhDcXAzzdeDQI5dcgOxgRpITfJOJooylyRv8xDHzltmHZDO5AqExN7SlOBSrmLyUSU1CPkxz3zmE0DYsmGe3OZMmU88E5llXeq5B9sPBpTNK8cYNJztK+xMsq2ksw3FDE1ddGrfEys2vYvU7WCYPD+UWXN5zemDpYvlTgQRQ/NqA2mLJWZxxQmptiuQMNET4ylONcl/9UXZLCJTNzXlcGR/ysG5K39FyYNy+r3XU4QQnVchIfWUvJwADjEoE4pCnPd9F48XR/du3miWbUHjjemH21vVquuWq42qjL3oE0+P193may+9fbB/78rlJ4+Xh/Py/my2eP7ZZ2fNwfmz56ZVvX+3aY4OH3/iU11bbpfn5ocHcd4vF4s1gqt5d3sqx4vVbO64Po3drz75lcUn6lesMUAdxKyemRDJDGbRC9ZMa1vyRWRLf0Pa+cURpiPlVLGndVZRkpORUJaipchPw3OXmto8RslXyrzEAVvdE9NZ03RdgfyEJ4yImTyYVVgkSfPN1Y0Yqk4BjRoRAIYHlZw4saUW6ArtCm1K6cvQzvdv/Zvvfu/5iy/8X1//v8mhSodu2dUbuxu8I8c3p1vbVHDXtk9fuXi3u1uFUclH25PxZx6/+lG7qHVccajQO+21KOGVSxYWMATCadEfm3WkvVUSu5gARQBEnigDNVCX91IDic88KHwobeMG2KKPIUBIGp90mAlQUWRyZ1pGBIkGDlsxeSLyNYMa1rSrRFXNeZeTUj+N3SlpI1QhJgNiT6DkjM9s635hZC5rJYhiFBHx3lvTYQklvWkFOFO58klJaIrttiKY8zuYoawBa6fMkCjel4QiRsdcqpZMZXReK+KauBAZq9TEJctY/ZiwTbrt3CZxFSfhsAoPNmW2wbHWeY3jMvYcuhGaP/nS5Q3fop3Nl4eHB9eP1qtmvl6s1kDstF66nVBsPzI6pZu7Wp/pi5057bz6zt1bRwftvdAdhG7WYA5aCLXQZaG9+oL9uPBcAWUMi+Xx4Wefu/bii18rSpkvGsCDRaHk0v1IURDWDFkA66FMkgzDTNWnogHRYjKYRKKEwOQL70QIIjEGWztB7IgEysTMXEiw5Q+yaptnrj11NH/wLy+9Mq7HoqIaRJi5ADw5ryW0BCqgFioZNWhMqKElUc1Sgscgz6hBnkSIEOHMeiGJg1SgNc3dUZhG1KZetJ3ZQAcqiTpCK+hEzQJgzdDSagw+aYLZYrR5LikCQEA0dUquU09iMBtTix1EmITIM9nqu8w8ENIE8DNUQrDHmPPOnpiaKJEYJXkAw4RBkWDIZkwyJKLEPEkBLct1LVKJpP6M06LvZEpHSbRnyCullKUPWWLZ58hdb3KyIGsWh9z0EI+DWbOR8YnwVjPMbf8vR82Tf9QUeim345Q7Jvs5OqmKATASQ1hzq5pC0eDH+RDD8gQkT2QWSSqX1HINadjilCTay6AzzmA00dCU549t10uQc3NuyRImT6nMd+RsdUwOXgqwCpg4RnHOW8NXlL4ec+jDwf3DB7P9amO+OO7u3emOj+5u75wpxnsrubls70zGWw6bsRvfvekvXrx0Zu/4Fz/96PbdxcWLT3AhZaGz4wPCk7OD7vS53TPnyrZFDCPy8fBoUVB9evKIr/0iNtF17WwlnSwP2gtPnHv+29fqcjI/DAXAQjGCAQQFByCItEAQ7RSdaFAEhZD9XxUCHGnOlbZDzsBSZcAVHkDMdClDOCgxDImNTSUJUB2Mm+yOpBex2tPICUMpkyFOe2DyqjzJnZ5TwGy1lAtoeoaZXSbV2SCfyBEYTOoRCq814vzB7enYP//553/5F/98cPe+zMI4bJdU3f3wzkfHN0YjJ8cdnIs+hNWqHtXz2QxTufrY0yNXE8gzSILEFhxABQgQW+sEx44cIZKNYgBiZoVLxWE+c8yp4zd6oDlp52X1pJqs+ShxEFI3ykzGNMx1v2U/BInEjLyDwQSGnP2fBylBsmNTIPkBpnPOLiFpqhqDFYtZcDEU3unvVj0xOwMy0tIQGwMbRdK+MQ2QY9QozrNZcsgw9xlObipclQsvZiCkibpFxOzZ5HmkYDEIKdoR7AW+FCpVSsLYuZHzOz5M4TfRjSSWfd88CG0znXA5wZYGH5ezT2669b0qNGiOEGbTcnXY3teudVHJU1HUnv25csyj8WGzWHXtevGxd+srFz8Vy1NH0S8I7Trcfe+Vg1Y8dqnkctMTnCKCERAq8qENyo68b48ble573//e555/vG3n61XH5NkxNABREVWjJd1kEUgwMU1q7DSokjn0JxYBKAYRCcyemWwLRohC7JRUBBQ7JkdQEVIB+SKBnhwVLoaO4L/4pefvHxzcuPFhXY8kgLgSOOYCJVAoFdBSUIJGwJhpBIzAlecxoRbUUE/qwTWL9KmhBKAeqrYTgbxrq3Vfh2pSxFa1E+qhK4LTZAvKSDaUhaooWiK4KETsDBAzAyzVmKaT6pVC/rOAnCk2c6FplTps05cqiGJSJ5KYZCk58ikr2aocESFjWoGYweYaZZh1CPYe2DFLGj2q2kYlMbUP2xICwIT5ompWVgoGSfJ4sB5lSG8GNBO5dCowJMeBEJVcrZAuKpGKWWH+ngoowasmpx2yFmx9iR1zEhG7Oql+59Tv53o9oZB4KPFajWAkkSywUsWwpiulW+8sB2PYy5S+L32axIX+31dJeOh1ACJWztbV9p8NJz5xyDvhKacfZfNKGfSLwz+yeTNKCIGy0smSr91qZiaNEPIF+Rrzo/kH1/fvHxw2TX/p8unF0Wj/TmjX8tjVyx988J7I6Xo8qqpnZofTyRRNdyPGmTSx9Jt/+n98Nq5PFe482IdYgn3XyVY97XoRRV2Fvj+K6xJQosIXZVXXY7dVlVrUJdy4KgpHJCrNTDiycCB4pxJhfIeoCEAAAlEHBEUgCkRCTmByBARAk5NcbnqQkZIokQyVVxGVbBHKfAJBJ9MkszHXGGFRxzh7lJK2II92c0tHGSMhZzNlEgk2slQSz17VKTuyFcICYmVick49lKEu7aqBI0/qWRlUOw7rQLG7d/vgFz/7uQO/8MI3XvvZa91qzWDv/OZkevnKlVt3b33q6jOz1fLimSf25frdcFfWHjE46ZmloOAIBWsngTKDwvAf8iRdTCmTHMCkrMT+oe1D5jsLCCcpkUaJEHDeyZCmI1ncY3WkRHWOlRCDqGRIIHsU2DhABmYUDViUiogNdTUdBBKVQW2Y3qeqKrxLDvNZNjUkVJy426ajyxbgLTwSnORlkYkkqoZfiUgy7jAhHqVhQjqSxgmT1IxHR0XeuAomtjqG2Ad1IM9FxVw5N67GFGuS0jwb2n6+4NVK9peH4XgVDht/LOc3p2c2uvvd4fwDXt08JYuqPZzgkEe8U0lBfbnWcu1H5YVmFVuJTVcsmtXeKdz+8DcHiwM3diuQTi60W9sP+vGRjtvy1L22PDv1xbj6ZIUYlMDSBVQKYQouLKOvPFQeHB6c2dz9/vf++JHLp9rmSMDMXmMnEEgkUnIgZpGgRvwhU6lZBLUbElPxZB61iWpqIXrQGXC6G0TOaRqtIRqnPYY1vAcY4kHRe+7Dynv/3e9+48///GD2oKlHu7FnplKTX42iRtqZPQJtACPGGKgJI+KxC2XgirRk7zqf2e7QADH6PqLzRcetdOtJNxpXoYnoQB2bO42shDpKH8WQSyUIqK+IzC4jqqojUoQYWcxKb+AMmVaGJPVgBCiiaAbblfKoRRJRMfVVySKJIhJbh7L7RmRIbgMszgt7ZkBEYowi6kvv2MUQfRqaGulnEKFm7U7e7Sa5nLQ8nOqTQaXwsEkWIQHogyhiyMikxGwTBOSmmWARD6SCvIbPhD2sJy486ZMkDwrTLqsmiX2GnYemM1V+NFxkG7XaayQWLCVsxrhMdsHsLanKibdWeueZZS25bWbiYdyk2XWTORkHpb5KcyeP9JHTH06cBzSQUd5zpje4XVSh3jlRxMyLEWHnOKoX6Rlcec+1Ozw8XB0uBMt7+/PCV/UG+2LyYH67qrb29nbLavdgtj/dPHv39ofnzpzvmomf3G26gvXiuNqebJeb050YSHzdNI1Q1yxLz+V4KhJ97c6Q5z7oRlnXp8aK2jM7XwUpCN6r91RHlr7vYy9aIAbRDlQF5yDqidaAKnqVSBRBUaUHRccBHAlKJIJeVW2cPbDP1JpgtVslnIH/E65aMmDRdK/xe70PmWjPLibDjAZTLCZkiyxL0eknsz8cMTuyHd8qIYYMTTgRUmFSSV5YeSQJJrAVWAG65tjVdWjbed/OPr758WI2n/KZj9/92AfP4kiVHI4P25fv/gq+2L978Ogz5yeYLo76lhZ722dKD40tOBC0LNJuF2ZlR0KqRoAOtgnTKVy0j2BtYnK6cICHRjM+g/mZsIHVZsAcSch5ziBwEmSJwPq/5PKiPEyekDw3ALV8ljA80cgpQ6ZraBeWszTYxmqDUYa1x0ogHQik6SykMyepU7dMLHnjiKqYfbp3zorQoMpmzMJOCDHtG1YmUhooJlY8p0CZaNcICiYUzJ7Z+bIWePZl0FJ6lpWu53Pq5ySNhia2sxgOe16sfHtUd8eT2G7EtorNXlF+/NHeQXt2wuc3uh3fPL7rr+xevrj3eHN4+zcvvbI5eeKT266ZdfJgDnJRArXH5x7ZuX3zg2Z+f1x7RsG+fexC/fQzpw666pi2H8TxDNMXPv/5V949+E8v/barNzVQOXJh3bEgNFxuFH3brprFtc8+/Z2v/kFdu8Vi7tmLMDu2LWfsECSqMrS30CMcQZzsIxKAxNCBJ2oXWDxRDFEg3pXm9GkTOpHAoGHQqUrOFUTkPEvsiDwYTF40AJBIm1vTH/zgT/7yL/9KApyvxUUtlGqgUtTgmmRMGJGOiDagE6AWGamOSGt4LxuYe2md2B4uhXZWTYkgkO9L7iSgbrG7qaVgLbJSE2+TI7QgIvIkIhCQkjJkDuaKORgkH9KCWi8iZjaYHWw4VR7kbf+cZElqXkBETJJHsoL8PCNbyuctJebVYwknzcIUUI3M5NmpROcShBu6zspYn/jGIPu9nFxCxIZwRKLWCapmnkr+TrLT6hNVSDJQm7OgfSsNJjZysvsWBHLO+g/NWjylNGdN504Ty9XOa5pppPSXgeyHMi+xzZ0kWd0xkKB/mCjQkGYxwCFluhS5rE8dsjy7h3YfmnaMkTksGaYmiEgU9dmeKYoZLPPDM+CMtuVKik4ysU2CIcgGtellNWfoEINNvErvQ5Cu66AMx/XII+q9g/22WXx8a78oR6OJrluljcW5R+PBnXo8unD9/Xu7O+7g3mJ/f/+5L1yrxzvvvPfa1mb3xOlrjPF0e8P7uA7tqlk2jSJ2dVX6cjLdnIxq71zt3YQY5EZMDiDpnRAgvo/iKPQxqusELfUEV8RCnDChc6UyuSCtJw/tiKAaxEjaZHMbI2xHQUBaFqvWmikwuBwmrNmIOExMpJJLweHhEsm1UyribCCipgwWHQJ3Iruz0Tk1P0upF7Y7IgqyDAWAA3LTZs0hYBo6Mk2OcgJnEnBBypACkNAXTo6aWXM8v/HeHUaNgE/273BHXuqw7ufzvgA+/eyj5y+dv3Dhal9JdcX729X+Ox/snT7ftjou+YH0Ia7VB5FO4KGR4JVU2To545DZpRHn0igv42aJ/5zESiJpiR8xO7JVCwBCMLOCE+KkZdlUVCgjzbokdceWfU2pZdiBxakYjTWVoH62klj05GSqIg+bzBEjc99Sl6sp0UMN8LCcoDCv51Spsxm6aRYZs+GDanvBUqsuUUzV+zALgBPCRL708F6ZRZwKhU5CJzg41kWHwwXNW1mEdtGumqZH17jQVKEZodlw7djz3thvj8uzVX1hvHtx85ldvjQOlyY4u4mzG+u9+njazbZ5huP5j3/y8kev3yyubPNql2fBLyT2UUTO7Yzkk3vzu/slE7yThdKYFx8vDq7/bi6TOW93frfHmeNi/mB/MXbHVBYrHYUuYswhaDmR1aohh+/+4YsvPP35Zh6btiMuBB05l4ytRYIEV7qogTVt8tFhzAKwLTyhlFSsyUpXStTEaKpB1Nk5EjEjC2NsOSISlShRoUwuI97GDGCgBPFqFc6fv/DiH3z/r//TP5a1wCvXLIVQIVQzRkQ1dES0oZgAE8Q60gS+wBRhhNW0WIy073tijUpRKToS53yIshZeCYfop2F/inJVoR+P+xpYklakCzHzXcdOg1rfDAWPCKsiCJjhnRdpYzQ+dI68yWlHyHidlgXIEWkyi8hRfCAbMbmEqGW0Bkgep2JCcpB1jzmhiLFHQ+ydpbsUhZIu0rM3rjkZa9wOQPKUSXNeSvFOLTtBxGBkHSQKaYdAsmlOCIb5e9hpsWOS9hMQRMSlEiMRtILJOohNHU3sbCQtolFELc+lGIrB1iMpTIwhBgUDSQOZT3ICM20hgSrEMQ/UPiN/ugS1mU2lgeFpR5vEmIJ4HnI7UFbLCRF7ytZ6YqIxjThZ4UQMsv3nmsQfRJlyMoShXCgN0dApg1iJRdaTjXq9Wtx459aFS2fH4602AFi8+/Yth/kS3f4t99mrj77/0c353b6ux93azw+qu7c+GdeQ/niy/cjexdNbB/V7N6+HdX/1sWfOnz/nCxbplNsYylExquvxub0N9jXBKwHwIRolkqMQYi/S2dTPOLhKpEKk4sh7VApFWCkgjtmcWiCsAupEA6COiTlCeyJ4F0VEk1mrqAROSc9W2OaqLT0Uakk1GoAzcJbTHBhKRLbr1pR/QPbo1xAjiNhxiMIAKbzjYE+OY6gOoKchGzQ010xgFgEldXgmwKlGFSBCg0RXcDGw0NkxnHhWB4x9TzHcP9ifH86O919z6qXrPDw6tItGFvTktXNf/FK94XebxXR+vAxLvbO63/mj82cubY0n7bzViZi6mCQA4stCWZ1nIgkQ44mBEIKYAFfimokB57wdls4I4soBAvKIImpWaJrgYAJF41T1af9t+s8+4Qaas2MivmquUWDGsKwitmOGPPchELF37Ngb9VPJriDspKuqRGUCwyGN5iURKWBeoJLMR83owI4AsYgICymcY7PjMVRaoSwqnjQogqQsHoTIPJDgPcFBvVMiCGKAdk03X8qiDbOFzhsczXV2LMu2XcdFFxchNuJXKFtUa79B03F1aq/aGW8+Mj1zfnv6yNb0wtbGpWlxtubznjd418+2MJusD6puLu1x18z8+Jjb1Y//17+/9d7tqqjb/cPJZGe+pHKl3azf2R759frmR9e9Y/EsEtgXruTDj+/em91alWVbn34QNx+E6aLYOnanx8Vup9bbEaCld8tmtjWZfu+PfnB590Jz0IkoAwQH9oQO6hUdzNUkqgcJSJJdSYYlTlABsZKHiVMiMEYOpaJG04yfmVlOqqRoha25BCHAOLqivYDtgVUwkV824eqTT32jwT/+8z+MxmMpFBVpoVQCI9ExUIublGHcu0lBtdQ+jnU1ofUI64m2I1kKme4mEEVAC3WK2KCoyPVOpnK0rVMKYR07Kccdld5x0n8qC6L2aeSlQckzPHMoobbMgwEPBGVHDCPtK7Ejr9qriq26IRVHFNNCPjXUHbkOtX0MFtFtN0gyj4EaoxFK6ljEnD3TxFcgpuaJIoAws/cFFKLqJcSEB5tSkElVYojOu8x/Mk8Mr1Ad/NNzk6ER5Nh5a63JxstJ50904phof9WUcRxlJpT9tygxigDeOxG1RaIZIbHWOQao957M9mhoMZP60JKnfffg0Ji1E9mC0Q62sS6JnUaxXBijsLUXKiB2jhUUY/ZREtAJipzSApECSbee3OSzsa01CZIVYGRLw5AcuTRXUnmhOlmRoTk4KTTbhrRl4W999MEvf/4vjuiVV3/1re98oZNDkeMujI4Xo6c/NV0eLG7NDk+f3a3K+uO7x7t7a3Tl9vaFnfOjPdq+c/OD/V/fHlejRy9fOPfIbln50An7uiqnjjfgbWeWC0rSqiBaGV2WLNEkC0Xe5c5JIkLexMjesyKIivdOYrQRu9qoNg2cRDWoBHt0o/TQyAzvWNJqqTyVSLN5SZ7bw2XmRDwb2GsGpaaCFMIJBk6yUdG0Sj6KWs0T1eK+sXZ10P9K7n0zDY6JIVFsn7TzzOSgyHumo6pXjarObhVrEfvIgSAkXdSOuceq9GvyDU2aGG7eXUg99ZNjmgXRmiWuFmHnwvi7f3aqkPjqbw4//OhAfbl9ZuPilQt+pzhY3Tv7+OnNM9O7aBqpGimi31j0vncFelBE6ITVsU17BMyAJwKrigqEI3O+7BLYqarEKMQGqPBJaZPdYbx35joiUULonWNXeMlyAwLSHCyPlszmwk5XlsjB6J82Awqqlv4c04m6wRAmWMGjQDB6HTS3ERDRCFVVBptNQXTOQaWTwMyRPalGiQwBUyCoBCccydg/hNIVIAYCc+fBQaSTdtZ2y7kuF7xY0OGhzB+EZd+v2r5dtetVq5iD51yuyAe34evNanK2nuztTM9Mt89t75wbn90sT42KrbLYq2gDMkIca9iWdqxOuWqPRedRFgUvN7mZcLc37jbQ/uTHf3fjtzc2eKSNHDUPqt3FZF3M51xqtenLO9ff5za4wsOR92xSXSmIR74YcVm7ELjvII56B79uHI0dVYFQ1W52/8GVxy//8Gs/HIfRYn/FYHhGQBTJ0njJF5oBjScmQmLsXAtKBMnkHYvikidhJkhhTptVdeCRZ46tAUygBEIx0lzD/lKYX7mqFyGG7zr53Bc+2/rmn3/zUlXUXJF6aAUthMeMMcko8tS7cTdGO6Fuk5oNtBVWm7KsdUVQZS4keI1RI6ABNEYZ4FtH5/yslrpgWlNYaN+UGwtUISqJOarYqBoalJUlKHpAQMEDYgp2VVH0zAxRib1oSCu/E7gZRETT3kCDkNTQHcsCdugI7IgVsDSR8GqDYxhsjQoAGO/QYg1D1RFnRn7KYd4YhjZ2VRLOcS6GYPkjpbWTFo5OOsskFUlTtMRq1wRnWTZMrrxiOPCA+ik7NxAd2Xl2yYcuz4VT9rUEAFECW7dkwLSRkpI/RqqAxAZ+ROAh7VnUIHLkbTodQgQACeydd2xEFFUD0JIxXoYlJaEZSAE7vbOTSX86ATayyIh2ZmaniXZilg7A8lCPUsq6mk0mKNUorFDEyFWNw8PVeLL9w3/zub/561+8+ruXXnjhyuK4OnM6PpjFxezS2b39o7Xsf7yA3vVFuTF5/KhtmubuR795oxB/9vTe17/2pe3NKcGL+qqaoGawjyIClq6nNJkzy7fkGr5eyXhj2vfB5twhRu8dFCrBOUlgLvsokdmJ9oAqIYokhgyZmWq07dP2nAO9RWFRsbVPMIPWdEmTlHOYu6ggmmSPTAg61IHpQtFwJ2x2z5QZP/BkGLc9PTw8/ym7K7I4x9vLZPdjEJkjeyRDg0ihbGWjc46I8kpZNqEZC0GBHtrqeuxbVzT9uHXtJ4vGrcefvlw20oYDXS7Xj35u8gdf33vnnw5e/vsVirHfBtUtJiVve94pLjz6zEfzD68fvD15/IWmHTW0MeuLwBsrrWglLjiOHLqoHSiChZlEEYlEoexBQiJij5ARNAElVscuarBiMB1bVhqKHxvS5BbXDCaNyUUJbIdgqGWHeiXPZVSDuV3YWE0kiii7ovAW2jTD3XaiTYggyogB5pjhXMob7MzxxoGdQVxEzF5EKHapfCDbSURUOHiCQwwUe5G265pVt5jr0ayYLXC86Jp5WBzHdr1et01oFzG04JalhZdq7E6fHU13xpPdi9s7m9u7p6anq8lONd7x5YRQq5ZRvWyIVKylNutenPiCGaab1cih5q7WMHF9Hde1LHZHzSg2//lHf/vWy29OZbNbEDfUL1dHxx/tTh5vG39qo7z/3vVucVSPaulEnESnkJ49oSZeIfgeesgQhuO+JFmUrqxi26HWqpzfP3rms0/94Gt/zHNqPmld4cFmYcCOvWQtGeCQ5gKmEODM08lqFkBhg8V0K9UCWIpESRNGaXAYQQD5PIXTHKocACU1Q0+FQHzSEJOHcpJIRadOv/YHX12X3a/ffnVcjWMRUSlvsowVI/AEvu620Yy52aLVGO0EixGaDaw2aMVkpPTITlTEGA1rVCsugrpt3J9SsSDXSOep9Yie69nmWLxTQnSCCOqIIgHgQOgB81UIXjUyIpQT0RienVnDBVJh9qqByasTpCc41RnMLBKMi5PNeWyGbgpeW3iTZqAmDaAhrtnEFGTyXc5ejCmXgLyNXcFpF70k/+jEYXBpdUMKW8P6IQyjHQxch4GjlPwATLRX+rRQOlNYCdDhtwBGXUyCfQU8ucTCTE0hHMh5Lyk0WOBIFZiKptJt+H7lh7ulvGEuAd32/QoJXXAqXJQAMVOQwHoCc5JddAy0zP/qS5OzykMjLQvzxqMzO8jEg0hDAitHNI2eNX36rIFOODrScg2ICmtoF8W1a1fef/fNmzfuMOJ4vA3lTrqSdi+dk/l8JkyItHW6mp45d+/g1j/98ufarU9vn3n+6c+dOrPpy00ADp7YMRddNGm4iAqReK6GOygSc7UhqhRDJzG262Y8mhSe+75l9iLaxb4oyigSxTG5GHvOrDOG8dBsGCggMCUjQomdSEj6URUmRyxZmWaPjE0ohtLOfFg4918xj2w1Dwg5KwCS7IhtHzNURYNtYrCpv1k3WMYhRJP3CiiR+NLZNBEPs8t2cYEsdOXHnWCuNxjGS9pJ7JQjaxDtIKhXsrlTLGetf/Zrf/Lyj/7HWMv04vjD/Qff/dMvPXpp/6f/6/4Hr3WnHpv2unZVGQgfz2/Lg/i173x9Uc6e2T79Dy/96vndz64nu4uw2WjVaK0tuIWsRBrx0RuII0GgnSIt2JAoKsHKdgDGMGfHBIrSD4CCmg1YftRCjI7IRrXe+yj5PKbmNe3aSrcz/Xgey9uUi5STY0OqhWwOHaMJlYmUKI27LBok5ZjzHkCIokGcOVeJgaUkIlGEvSeTNxBKL52qkkNEt+5Cs9JlE4+XYXaP5w3ms7CYx9Wib9u279cSV0wr6IpZqppGZTU+VW9vTSaT87u748nu1vbOxsZWXY+5KAUE9l2oRHzbsSw6FSgClzXqxKvjkrhi8SJOuSJMaOoXvm+8a5wcV1hu+K7qm//y1z9+/5X3tnkq84jWaQPueHF0WG9Or2w/ce/m9eb+QT2qQ4B4KCs5CCmtiApFBfao6rbkdYmu4s7F1tPKY+ype7BeP//F51788rfbe7HrurIqZa1mFE8OJkQ0R+vEo7UNuOlxz+4ClpshhqYmbioy+gykSWc6WEQpDwAarFtIVBn7XitJ2ZlJRpqhCikY7ElLVe9GPjoRlW//0bdWVfvGB29Mp5OuClQqRuBN8qN+G82WzjbRTdBsotnAYoxmimaMlgFmc92KQGCQMHWo1iiOGuDg7TPn61rcHNEjeBGPCTmZT6adQFk5sAbVoAjgklHnkB4Z4kCeKBgtPxrjiZ2IqJKIQIU9k03LSRLok3CjzDdRNd8oZlsarZScTKw8JUuXw1lDlsVIIiravDlP2gheJKZO13j91jMSPDvTGDgQgbLYDjpIQTA0JIYEI1uvIxFfTG4mwo45u/VY8WX43kPcaSA3u+aTbJMpo3SYVS+JOYG4RGI2dX6GMZPtOlkITfUJ6EQCgYRci1045zjGSNR7X4QYQoyFg4gyO4PBJbPdOPFwTkDobDlpawBw0iFAjZttowCQaaYNVM5Ef9XBhcuC3OC3ggzwpB6Za0BEyu9//3v/8st/WRyOLl+51IXNypeH9xdlgXJPZwdL6dz+fP7qa796ZPuRZz/1zKXLj5Z1HWIIkUUcs/YhCLTwAhXv8pJd1UgBGQ+HOfU59s71XQihY+bSuxDaEAMz+7RtKcZkDyIx9sNoiNiUmqIxGCzpnFHug+EwzJT59GpAKqUCMRcx+R6dPAs56aYS3W4DnXxPqi1hdIRoBE8HTsWnWrGVcH7VPMcAOe9SM6fJr99UeQxiZlKOJuZhDw2qhb0aUQQKsEgQCtAISJo2UQD33BYIZX377nx1qBifavCgHM+vPl89+ZXwl//j7fm8Pvv0ZHHQ+qpaNHGyE//4T69Ozzm3F2bdvNyVbZz+5W/efOa7X1jMfOc2Wx058dJHrIEV9cvOxcKsso2DLBJEelEhFWKOMVgC9h6AxhhFI5tuanAvQboynNEp5NnK4I1j3FgbuQ7erqllSBOoLEww5iTI3E7Ye/u3NIxH6rlzqE/QidVDDhRFYwxwXJZFIBCRFeoEhLbvmmbdtrpY6HxBs3mcz7v5LDTLdbNcti2AY4RjDT1IfIGyrrem1WS6MZ2enW5v7m5vTKfluB5PJmVVs0MQAD4GXnfargP3BPM1cYWqahA29TEKhgOTlEbGUXj4guGSLp2jjn2sdT1Ct1EKt+3f/PjH995+b7ecrO8HXbB2kRpFX/q1zI/vyv0w2993TCGqlMSelexJg45Ea3DvOLJGHblurF0odBSxIiolNvMHL3z5D178wjeb/T5Cy7rUFnDEfqiKTgyMbDCv0MQwN2FFAtgkA5ZJBTxwSK0ZSPTok7Nn8ShH9pynH+5ENNEkHREDSRiQlPZwNmlVh8DynT/89oO/Obw3PxhN6r7sUBHGmHAzltmmX4xjO9FmkxYTaiau3cRiQ1oRgISjspIYW4F0POqEyoL13vu/+cynLm2jYtvSYDgw+V6LfrJBII6M3mpUYA1UQAQLIyi6EgDQE3sAkIjEj2BRhvYOLMmNPgw05oe/jP2c9DoihtaYNQlwouths99Qa6gSzQKicGnCmNidpKpkGILJtk2ag9w+A9AoEgWOnXNsg3slm/4qKVNid6QhQbpPuTsc/HeQYiVOtEpWT6sOit7sopHeXCrZk29kHkqkqGlQSapKLE9mIXB6KA1Xzb/MXs+o45mYY1gAUZCY57jJWEDTIlo8NDUchs46fJbBhcAQMitrBOrTU46Ex8JWEKYX06EMyZcrbWJD1qRplriABaET1OONZ5+/9uqrv713sJyv4uLouNMVa3l4eK8sq73pqeevfnr6/Benu9MQZL3i1SqQ46hKrhdbLwDtYzC8HaIE55ijvd/0W611VWIUhQfEKEghxK5t61HddYu2XZdFVVYVswudiIhzHEIQYiKw8wpl4yxIANjGe0TEPjPbJRBYJQKabyuQTLx/7ylPQ36Jkqn3ZoxmOcFYcqmzgiI3wxJErMBSMU8Jc/4WBYhYyXlvJRWG+QGd/FIbQ9rBcezAJsAQ88oNMQK97fvSICyMCO2SAZ6spas2j0M3Gp++M1t80kip+MxX9s7vHv35n790v+VLV8+O4qiT+0eL42vfnHz+G6euXz9667Vq5n8hW/Hg1SLuXj79zM5srS1vdG7Sh1ob0Jqp19hFaVVboo4IEWRet71Ib45YBvgD8M4TQyUA6p0PsRNEZvbewYYymp1YIeQS/5/A7FhEyNm0KCny85FNRxWpXEq0LAKp6uBNxuyQjXzSk251qCZsy8od7wv2BFJHCnDsw6pd9926WyylWYajeX8064+PpWmaxbJdN53EReiaEDqgKxyqqtydTop6tDU9vbWzvbU12d0eT8aT8bjcqJlKWzUQOg0hhiAhdCGCnWhggJyr2HkDasHOyGLEhmtEIkUB9mDvtVDxqoVKCakVNaEmL51Hx/1yOm5pce8nP/rz7t5b02rS3OmwYr920kRdEnfAgtDKrNvvpC/YOSh1EK+A+qIU7mhENGJ0rK1irWW1Ln2sZFXSRs1o5w++8sXvPP/iN5s7PTyTl2gevQywsidldVqI9gmHzLRFInONGmZaJxC01ZxJAI4hq2qySbDvlnyXbT2lIonnf28OxzD9AZGhqgSnxFAGsTApInmCR+CwsVP/wQ++85d/9aOOOzdxmGjNzTgcbfvjTTnapNVUF1NaTfV4Im3ZBjTEEQnHBUHZRwJExuCy2xtx+8k7/SfvnL14mfs1k3rA+0jCNshcTMcQoAf1xMroQD0hQKGIBCEEBxS2FI4ZmbQcmbKSJbaqAlYbpKSeUIWzOk4TOQvMFCSag0QmNquV86DUf6rCVJAKBYTZSWLAGdIAqPqhtwaljGEiVBVhSnxjVYkR5NiWTiSWr6ZMQ5RkAyrWkGYpnr1TZ3S7iKwNethmgV2ygNbMyTMxQxYNJqT7YYvk1JZmypXRrOwz2rYie944mWqlKVZGrMU+rIg67yCIEr13DBdiNCA1xoefWsoOTEOCUNNfc648HkrNIEoWD5SNMa1BJ2IdJgIP1ZqJG/PQVwLzCawBWnoOXSdb26e/8Y2vvvQvr8iqCaHfqTdP7Z3+9KNPXDh/wVc+CDqR2TyAAQ22i6bgIkQIdybOsksOskUDKgjZXCt/ttSzEHsbk0vXRVUtSx/6jhlAWDVr6DgEEYmbm1uqQiRAjAqNweAGZgcWtVW+RmIIRmGwB2NQmENEUxkvSH7XoJNiTg0SQ8LIRAnJ49+QhFyak2ODbtCHECXU47EIyLPLsUlVKOMhhHS8bYiRlHEpMFHCVcBZDenSWDtZVgToml0NIQRoD+2UWpJG0CDWZVOPxxunX/vg9rTaaXirH8nvrh/ea6qdK5P54v7R3Dfovv3fTc4/Xv/oL28dHPbllLEr5ejco5994ZfvHL7/xkIur/z5U4um0KWgZW01NuKiI7B0omsV7eA6mHeLqkhQRIU6xwCcp+SGz8zMHi5GgRpxMuVGyuVNolhJOg4S7TXz85AsOhSJXAJORgPelH5EHAe2MyhKVDUTWQP3nWewK7wzVAoQ7TS27XJ5f9EcL9aLRZgvuqN5v2xiu1DV1bpdNKsAaVQ6gnrv6noy2pqMNs5Mp1u7O9tbW1ubm5PJpBzX3hUgimLeCAhBl6167XtRAN6nmbgSXKkURJk17UASZ2CZSLAoZi7QXDFKNStxEmGIV5CyA3vAc43OU1tK2Jnw4mD/P//Hv9AHH5wtRut7LS1LNKFvxC1LWYrRArq160hQjlZd5yBVdOgEnoJEFMBauRVulCpCYEZgCk762sV2cfCF57793Le+9slqLcwC9d6JeY+qsGNlNWINyAyCeLibORDFbD+Wu5AMPjKxDpMFSUcjPfycD57Y6E4GqHIgP+a45c3zQomNdUTqQWUUciWo8pEje6KCV9pfeOKRr3zrK3//yt9NJptcrjbQTGgxkeNNzKa+28JiC4uJLHjBuoBbmHOyQ69pjRBBiXkNLUAbLCqH7733zKVpQOnZmy1sgAvwAV6Yl3WFElSTBoUHCqAABCiBAEgB9IwSujaZIaDmoc2MEDrAMSNRD+0SqyTphJphh2HBEBHnCzOCTCtPokoUW/RpySARoQRqRNs8bSGijPipz1SgFPsNs4NtAcoXPROelZnJ5RWKVk2pZgdHAsg5NjKe5Im/iDjnSJ1lJvtFUVWCMDs2T4ABA7GoZ3Qp63xyftLcyhqL2fJJfr7ULDecLW40TnRGUYgSkweaAGuFem9eg2oMI1OwuGxEoooo0U7yYEs5pHm7KCdeYJKnXQlzTl5Nw6OvCjCQDODT58y8LVU56b+t9rS7G3RNqEUIHFdBCj/+4pe/0Lda+drVEVwQ5HjZS4B3gMKDRSJYRES5BAshFFIGEUh0rBIELMxOCUQuSszNEFJ5DDF1lbU1BmYyu7Zt+17KouCyEjFGCsfQsfMWrzhx+iUKokZm05bQQ3UVrOSjh2uO39vLYWP/7OCZLx0RZXuY1IOp2TmL5rrM5gFgZuedI4+YzNokxiDivQchQh1IgiQtSxoXpOczubuoIm2NVNvZ6cjuS1Qh4sLyUtc1pR8jgDp2gaRTWQZUihLLenK4/w5tP1nouOuat/YPJ/rIUSlnz1ftga6x+Hf/4Xkplv/T/+dNlPXm0yNXYL/XydalM0+/+MIV/Md/eutv/vnGl3/4NeVNLAO10DVzZHSsHaQXzyoaRQLQM0dVUY1KVFelaAcgSiRV70gyl9B5VoFpDCwrG8pEBI2RmMj4/yIgSiwNmwzZmY8n5aWwZkmeBWcBEBUgKpyzs1gUzppsk623q0WzXM7n88X8uGkW7XwRmrZrFl3bhtAFCZ3GoCplNd4Yl5OR351OJ5vnp9Pd7d3t6dZ0e7se1XVdGjwWQX2ARGmCoF0LKbk8TwMXCmF4EiIWQWAGixmlqPoIBryDZ7CHswkmkZDCCLSkBMdKigLm6UHJfcTqbImIpHE85nu3Zz/70V9Pu+Nzk3FczAuuwVDmwEIsXDD6qI7AWjofAWbnRTkqPIsLWkTyLAVQEmpYz63CEC9uY7ZYX7n62S9/97v3eg5p2w+kUxKSaG5XAkGM0VtSsApTkSVcQ9xLwFryksmZWdKSC+UEJzGb85EmAI+S9j0hGRjW3+XYbXWfalY9IE0yyLAEEVa2Zp09BQrrGJ974dkbqxvXZ9fPTVBJW6Ir0YyoLdGOsByhQUNomRaqCyuKjdLsjPavUOqISijgXX3w4aw9CJtb3TqMNlD2Qh18h3JN4x6hqWvUQAt1ihJwpqkEUXJkwskGaI3RCg/HMKs40/NqjIEQhh0nIQTvkuMpJYQSAMMcUlWDRCM3xSgq4gpvExqk6tXq11S9cOqk7S6QZxqyylDgKLEZe1tMtEVILkoMEm3jYqKnGJVD8+3NxTLIGNKqQGF9joLJXDXBSYbgJEGdJ2wpUKLqWT+U/8w4SWi59TF2uC0vs50ngA05csepDxUW+WdTcqGcRG3DBTnn+hgMr88oAYPIzIOgyo4H46AokVOpDyIjqZ2Yb0gKfdnTJ+qJMdBg9qEabed8pvYP1G5NJbyTUCVA1Va3rjt2pa+pF+1aAoKqsHW7QgCERKJKQFkWIEgUUrK4bKs9zfAoxN54FNFMdJwjgmi0D0sMpO1B9jZ1vW5FpKpKVQkhiERVp6rNqvHeO2ekY2KGSBTAM2W3NIBYtCMCyEtqvk7QhVQmpqqPh2cPeaxotz5dRsPPaWjRCIwYoQoyyDyCQI4kIHsQgByRSLp3ZjuoUdlbYGIiDJ6qg0MMW8+b5phBwUTOUHaAQuggrB20VXURLfGasQKWJJVg4t+5w/tdQdVZLY/evBO+/Hms3ohvH67Gsvp3/+dHWuz/1V/dw5nTKOMyStByWZ7p6PTfvvzGuae//pmv/uuX3pv93SvvP/fYDrcc5uJar6tO1owOEC/asC3iRBejKIIjhldNZmqw0U3UkF3kbEYVVJMHe5QoqmmzYgYImNN2L2SsxDAtU11kSI2gziijhXPsnWMPl1TSfR/Wq3WzbBaLxfx4vjg+Xi6Wy8Vi3Tbrru3a1nK8nVp2XJZ1PZ1ujTe2trem0+l0c3u6tT2ZTEb1yHlXeAYhRmmDBtXjVS8W9TKTjInUu5RFc3wQwjAUBACJ5sGlBHh4OBEFArjsEYgKKNsiOqMUi0TYMpPorOvnHCXY3HuEtjZHtz746Bc/+otpaOpRIWZ6mnIesXoFwAJPvAaTBhERdaIOIAdlIcdErJ7ZCxcQEngOLAGFcrlomtPnnv7qd78/j+iCeLBEYYGIciCSzAEUMFwIa2YxOoXzdga6IfGKRM52eypihEOXDU5yFhUgufJS1rvDQHkrxswwWIbnpCKYTwOZCZyBfKbfVuuZRYSBoatyLFCUePH737n713elu1+WoQx9SatKVxuyrt2KQ8AKWIgsCQ0j2OzHAWbhpcmotwZ7zz7M9hfN4Woy2hy7446rkfCKVp7GhbYFypJHsa5QaHQRMIoUwGkaSAQVkrwPjX0h0rPjJMSwmiL/jWBeubY3m8UZacVE2MMg0Uy3EqDPtnHQhsGUEo4Ve6YGo/ygUtJtkLcNDfYYnWAYiUxhzTA48Xo52kyYkr8dDYbTSTGWtwVkeecA3OZiDarqcjo0LFcUSXOkdrk5daQD33pgw+f+0e6ISnYnACHvGs+EHs2Dbgxf+TkbPmWy8heREEOyZUNMYCWnbjS/EKIqVBx7HggM5lACNeWX6uCdQnlOSUwshhSSDosW7SKJKiC+KHOJoGKmemRcFSKQGfMSwTkXY4whe3YT7BmNIRIpe280HCQFjlpatkKJwVECwysrQna+VhEJfb92zrN3THCeRYTJJg6BOe13897+yFFDDEos3htKgRA7qJBz3jvvOInZVJxzohFQ53jYfOWYVWhY3JsqNB2wYWguxTkBppZX3cBlGKgAVrI45713IfSGhRI5hTN7JmaOUR4aEqhGo7kn8AYQYpYYmRwTBYnGJxCJzB5qdGkFApMHRWgPKHPpKweKuiZllcIFH9jBj5wcBzele7cO/KknF6s7KtQcd7cb3vwUbr5697vfOdvt6d/86MO7sjOeTlYr6rniUX3YjZ++8pWuPv/GnfVM52cff66bhVtvfHC62CtXo3DcccvaQTrhrgFINaoEYke2FJ2UxayhB2FD9tIjBTkoHJfs82IGa4sZ2dnNZj1RoCJqcr4YwETee6tBfeG80faYwQjBd11o2/Xx/GC9PDo6mh8v5ovFfLlYrtv1umv70EkSP8IxV2U5ntiUdjzd3Z5Ot7a3tzc2NkbjcV2PnCND5kTR9d1aorZ9ooWy8yk0wg3FNzliVjELWYsNMgx1kuu8ESjgUjhSBYTJJJjIvAdhEtEaqYkWYqfw5CPQszgJkDW0ZmhkknpUuBG/+us3fv3T/3gqxo1xLWGmAsfO4B0w4EmNIZpgHIWIA7xlXw84SvsrfeCClQEPOHElt1wfN4HrzRe//4O+Gq3W6OGlU+mUAzs4VUVQCYIAc1JnBmxhF0TEdtNrmtCbJzYk+RgOIcmCEqVQyMmKz94tJ7l4AiNtZZYx8RKhXWMAewvbOjB0yGVtC4NZMmJNzj4p4Gkt3e6ZrW+9+I1f/af/R1mg5rZGP6bViLqaWmoYDfRY9RiYC0Q8HIFZWWPCV1ErdQwRN4Jw395vN6Yb1bQdcRPIN1qN0K7Qluo9Rr33VCi8wBMKQo/8ToAAUkdwBgMJBDDEmDNFzWZQSJyixPVBjMHEwETJz5yTx7iQOcDamEpM2Jn3UefdwKkJNg32SUaCiHh56A7lAZyZIQsRE7HE3lxlvWPvvcRgQpokLDpJb9YKnfSplnFTq5wmFJo7WVJIplDZzreET56glMpGbU2vF7M71e//yoybZ8EP8l5hZAjpIfTETikzG58suT8yICkrkYHC6WtIxSl/i6iyKbPphDoOQy+T9XQXU6GuosyG6SAnFVKjzyW0n8w0AYkQbnZdxMxRAiXWERGlKW5MyL+1JJLOBiFGAUW27TcQEslLglJoUighbTVgq0lFybGKFL4Uka5dGUCpqkVRcsp2hr2CiEU0aATIFQyFaLTLaneNjZerqcsh21MdYtqDZ4MTstowcX8ol2yS4mMa65vfYS6bGEjUZc5yFyvTiG0PQnd4MNucbm5vb7ZtF4KIwBGHEG3TOsFJjKELReE1ioAK76JEI253XVd4D6hEldArM3unxEGC4Ql2z533phE0WWDUjpQhLCS+JCo0egkcOLJOe8yLD/avX3tuu593q0V45/b2569dfPdmVz968aX3rp/5ytUPfto8WEz95jj0/njePv/iD8488aXDOC5vN76vax6Py1rL6JqCG47HXVxR2Y1IwjpAsSZ0lMYaSRDUr9fewxUm4bXzTYpelVK8UAkhwmBV5wBoNIacpAYPlHYBlsFxYRMU5xiKruvabrU8Xi0Wi6Oj2Xw+Xy6b4+Ojrls17ZyCV5Wu7+zceubReLSzPZ1MJtPN6XRre2t7e2trqx6NyrIqy8IU1BI1RBHRpu3trGm2O/+9/YYqLIOk0OK9FRcxu/xxrqcVYKg+HDaHCKEwACZmoYQAzsR44BAFBVUgH6NAe4aHetEeJSvH0vlyVK4pvvXm+2+881J3+7ULGzSqqxiOGGBfxLBiz0rRcHsbyJIDSmhPLiqI2AO2usPygQeX4ILEKxxToeKli9QKv/i9H4629h50EsmrG2mvEIKwdoIIEhrsDa2jcVDAGi4LfpLeiTASIQdIi9lFRZO5lSEjRnEni35D3UDDHNJuB+zKpqrG/s2gSh2AK+O6mCei7dtTVWVlz1RAvHBFTR+fu/Z4896Vw/d+NZqsa+kqbSptsQiy8HzMugCOFQtCb0ZJSI7UgcgDAhKwIHbiyZdtgQXI82hzGcmPtWp0XGFVw5dYN8WGeqCEeGVP8Ektle5OCs/GaHBAqdraVCvCAjt5LpG8sUCSVSsiSsnAleCIk08iAIl5O5JtJRGYNaZmcF6GfJuuYfaNtOXtqTfXdBwBEmhUtZUOueGjhOEYUJl5vilf284yQnZutg0c9lCoEAY8BCAT63DadX8CLlsOI9vqOfSvJ0RKDCazpkBLMMigKLWnJhFsk028jbuSHiKTXNl8GzTnWoLj5FWZX2dI8bmUAJxnEuLEO0/UNTpBL9OH8Ozsc5GzNj3XPsPBAQZPyqTXyPk4tbYMEo4x5N9ijn3wDHiKIVqREGAe9ATrg5358HlmR5wisf1zDGnVgSGPIgJPSIxlA/md8y6GGENvb8M7J+BE+hAr8Snt+zbD5ROjfdgkAqrZ2EskUUbSDhtkcZgJtxLlPRMCLYdnJqHZspLECCJiRlCRZEhuJagoFHGyUb/8Ly/99rXfnNo7fXrv9FPPfHo0mjB720YOaCJoWzAR4zGiD8G63yhBFSEEx9441X3oKJLzXkSdmSwDCqPyWYIIiqDKzlcSOh8qXWkxLrq2o4IUwseFW7hwP545da3dufve/i/lYOJvy+e+98wH8+7nv5h87rnxI1+Uf/jbdntjr5HgxzvV+RduLqb763q/qZtPuoBDXtW75emDGw/ae7PdYs+vfdsvq3bsfa1YAB0pS+xUO3AklrLwokFjBBAtSDuCeEAlSTmNnkymKhSRGILz7J1nR1XpnSMlxBi7Nc8Xy+VicTyfz+ezxXIxPz5eLI67tgtdF0IbQmBmm5aNRnU5rjc2xru7u5vT6cbG5vb2zng8ruuqGo3IAYIgav4PIUi36kijVbWJJUYMkKg4ZiRkSPhkEpdoJOaSa1k5LzJmNb/QdPCMD2B7J4Gs9LHTiUGbiKgCYsNXDWqPjssonQornONCRDT28Kg8/Lg8XM6vf3DznVtv74dPJmfk4vY2x4O+78klZ15RRAlku6s5+Zvaig4qIJG8Lbn0YoQgLQgMLnzwAV65JDgC+0UT//CHPzh35bGbrQTyQmUblCOROOmEg1JPiNnl2I6gRqWQ3O/JAm1EIlKoWeJmHRjMnSkpMIw7K5kfKpkYm05mIlsMFzC7vSaCpIANv6Y0qtAcrDXjUKScMnrKfB5UkdfuD7/11Z/ef51X92puRrqqwlIXnuaiC9CS9JhoroiEqLaDhmzKwIQA7QDh2Ibtvd0JTXQBLqmueymbMUYTrFpadzoq0ZcudKVHyVQqeVJWGBBh4zoZ7PwFUOdE1QHROQ8FYPZTUZWInI0YUozKsHoKgWo3PMlGkf+cZ76AaT1SejJakA4Rk1NvTZ4yfm2NjTlRpfEYMRNzYQKG7KTBmXdlAKtFKeaYyJWRT5g0CcegQfeKlHDNDjqnLT3JellBm3PywNmxPiu35fm7c3Y8AVpy1uGYroRCbQWDQZpCZI5aGXxRzZZXGqOqCtkSCmszErvg/8/WvzZJll3XgeBa+5x7/bqHZ2Tko7IeKBQKhSIIFB4EwacefIqS2BQlU6tHsp4xm4/zh+brPGw+aMxmRmbdY209akkjsdkUm6TEF0gU8SwAhUIhKysrKzMywsP9+r3n7D0f9j43At2TBIGqjAgP93vP3Y+111rbVJ3Da26Yp4Y+9Q1G9peSRjcVNfj6h4VZFcaBFtyFxjr0vQ8urdHA8NVUq5er1zWAtOE22vxdWLXWUlMSCd1ZkHvRKhYQAqlqyUUmpKdtadYtQbaSrFmmaQKQc2eqxYxgyikzV1OYxq7lwDCZfEelX9JYYGcpJ4SFc3w6j9e5Zy1u0iZeg9+4Ya2JbnhAA8d8/Va4aOSc3By41moGJ+5dXO4/99bnVut+PazHcfz+99955ZVXT2/dmUtlSuLSE5WUBMmbeFWtkpOXwVYhKWmtWopqlfYeXDUgYIWKZJ9LmCq86Q4t95xSrmWSeTU+HwViGYl5fDaPT/dyJR+/c/GFX/niX/zN2+Mo59+oZbj3yt2VvNT92z86/+1/+on7X/74ve/d0nW/H+v/7b/72l71cpRX7q9WpV48K+lwkW9/+pt/crF7VD/36ud2j+bd0w9efXD702/8UuqPtYwQAYuwKmotRxcBO1lKBLDiPjwp0cLc0wyWs3QpA6aq0m1qwTiO+/OL8TBeXl48v7jY7S725/vL3W6exlLnaT7UMjMxJ5Fkm/V2s3mw2WzPTm+fnt0+2W5vnZ5ut9vNZuMFpTlPqRYzXF4dEEQVb5SWajV5BaYKU3W9pLRCmz6Wk2WBSmy1MmPsO6KH99ygLIaEJmJjck69+3u3gli8IGyBh77WPA4/O1Xni+dSrOqcU1qdrtDjvR8/evt//tYHz9/f50vexfYTp7mfxvJ844YTnmoVyYwi2vZGkEACKoykUDqgABlMRDJ2MJplzLScRXuVXmZOV2P5zX/4T1/5/OcejTDmYrkw59yDVoqv5BOrwPIfgMunjOWkNcBFcTG2W3UHvBidHBnEKTYya0M6b/bVZjeDr2cKdzDQ1i1JIFKNTKNGqioVIkY1Nac+VauuqqjJILMVfXD/5K3PvvmDP357OJ26etRJZQIOajvYleBA7I2TAaJOpfQdBf5JJ2jSUufTvO2Rx32xlaVtWvfjiseeU4+55zxgzqil6y0bszC7KNmcPR4VnFd7ABxGsurkTi/g4gKqijBJ8uXlwQkgI+l4jKpaq5KURELUmgO3H0+PJLG3jc4TbomuWU3B8jXGG02L+lHvuuwxqzW6MTVy6xA1b6p89yfJ5BtYYuYSra2ZL8ISQGP3eqs/fYbnRCfzFCvCGx3tkpxrzBqaoBNA9RlENFftt0UxZlCCzaKzzYH9qjFJLIHQ8MW065mwe/XJcv6srbbw66lWrrOIoZTa6KL+nepOqxpwGtCmsK2qEFDbWQ7euN8e8a7O2gBbFQgpqveybOYdtWrK4sQxIX0CkGJrRfGewZ1P4vlxXoG3nk7tVq1mpExlhtnJZjPPs6nl3JGstbgt9lyKV85mEBF1o+Y2EkJADRCRokagwqz4gFrcl0pVASulqK/+TkKgqrJlX8eAvBlhlF1+NCMIxAmW5B8liGQOgWitKoL+zZ/+sqn2fVbFPJV5LqnLPtSHQaHTHBw6B48Aqtacmg8lIUw+e87S+a0iZLEFEQpMwtQ6CVnFCORqo+ReJ+Qu4whZybwr/VnPg/Vj/8G3H/7cz371n/yd//o//uUffvTk/Pf/Yvrbv7x58cv94+npf/t7+W//5mfHp8/efzhIlnyyf/Xl4aVJLn98vDyfnz8sL24fHOWZlouvfvGf3B2233n0ztOHZbv+4HL3nbtnn5jKZOK2XHOpU9EJOVtbsli1mtaUU5dzlpRP3EUPZdJ5LruL/fPzi8uLi4/PH+93+8vdxWF/NR3H4/Hgs39QJeehH7Ynm+3Jve329Nbp7Vunt26fna3X22G1Wq/DPU0rStGith+LBLBcQZqpiHQpLcRHH7j4/VS4uCsGUu6aGXZnAZj5YwBt0vp4DjXIGM2n1sOyRAVsi6WPYyveE/sv8hhFhkXREgq8Vy2UjshWtEt5WA+X0/i9t3/49g+/+9Hzh3arDC9uhvXGqDoVXatBFFIsF6NKp8iWTbqEQXAAeliwDoIkDFEkYQZ7IhO9IhszuYGt0N/qR9lzXf7+P/oX9z775ff3GK07slPpR82YgAJxy5fS7nAD4gMElACfKC4KJR2IV5rzW69DGczdgOMl/A74smlrN4uBGTSe4+L00eZ4kcN9MGZhVuKJG2bmy7iaFtSYCEKpKeeaNNmEMv3Cz32x//ivd9//o25QHMWOyiNlhs1mI+wA1kBqjVJhJiqG1YEwlr7MZcZkGAGFFMERaa1dqhnl5n/QgR2dLuWtJJLznWgZVAlcGyAn9UaiVqOCypCvRpAWEQ/dGtYa6iNvAySlNuTzplIslk3HDDWCe7sL2hhSaMoOheXosZq7lTbPpzC4caN3M1hB5D+DW8UJoahu7K0l5xzPWYgmzUfazrrzDlxkedQCBXEw2/d7AGiboVpT7J/YzIfF7Vk134KT4JzZduTj/UV+WDDhNrpo/xVP6pJ143GuN5vOJi8m6DotYxNHewuYfHnDkt79t/skV9rlbnwHhKbbayA6Xd/MvBpPotFcWjwWKcOs1goVSvtLd/KVtjWZZgZJcq2SUhixaMdi3KCiWkspOeeUBGallFrqauhFuN8dupxTShqwledpJaXWMs1TqM4ozR4Eja4cn1wNAkrKFK2lavC/SlXtJIE8TpNN2vd9z54Clw95SyIpBdHU/KVi6TKalBqAxOAD7j4T91V9G6yScjxOQhyniaBISl2QAzXigtVS5jLXY92sN1MpOWczncbDehhArLoESLbOwZ5aSlU1rVUNBtUK60RgJo6OUuYkPVDM3Y8VOGyQoCi2rleP8fOf/7l3v/f++28//Jf/x//HZ7785rwrGDHl/vd+v7z18w/ufUm2V5/6/a/9+K3P35a1bk8mG/XpezI+f3onb1+80336bFUv98enfP3BT58NZ4/ffziw//JbX3r4+D/M05MuvzZrMhTVqnpU1JQIsst97hKAJGZWy1yO+8PT/X6321/tLp+fP7u4uNhfXeyudofDvtbS51RqhWG1Gtbr4e7Z7Vu3Tk9Pt5vTe6enp6e3bw3r9WpY5ezgPKpB1cpcD8eywML+ICD2A6a+X6kGVh/moc65ZRMBAIgt4RZ7qwhD8uUuDXaO7c9NjRt9lqEtIwPMv0czYli8cH0RtqiBsjqdEMawEdUmFfSYoS5V16o2roezMstf/tk3//xvvnZen+Wz1J+t8mqlh2pQ9oKjqiblatKhYDVhvcdBdFwPW5QJs1BhZtwDIzAIR+UImwQF1oMdkKGdIZMrcG1ymxf16d2Xzn7zn/7u8Mpb7+1lh+0oJyNP9toXWetYeUVMwBFWgGKY4A6LKA4n15Yl1NECH/slb2PUc4i6ehstxt4EFCO1EgtkGv6sYc8X/Gj1Ba8OpcTPB5HN5Z2JvvJNDKCLKqvPJ02EWlVLQWVNdpzx4HT76mtvfPOdPwQF7kshBhfbh2TKxU0wqgqX7bIgtRZR3fQrVAe7RVVFAGG4LYBBUl46zdZfoVjY/5ifD8dHi6nvBEvG4hwUUFQApZnVWkip0KXyu06UBrigAA12dm+SYu58RbcyVo1ZO9qaUF/O3ZJT9pzZEP+gLgd3GqbubiGEuVW9b3wTx5DNsPCknOlq8WqtO21rdBt82wh0RM45WmqSpIYiiWqldaZB93UwHGaQmC/CLDHFODMujNqy0QnBiLZm/OuocqAB2lYlO6RFLyCsqcQc9Yo0XrU60yk4CE6zT4ki2V0zG1zmIaCwJjbOZqhhnOPilaUt0AMQIUVrbKOM1Om2jaquFHKuL+hFromw7deAYakYDACTWNHi2HJMxTyxaddnNnmGiCDbPM1K9Kv+cNgPw5Bz5114KUWSWNWcc3GD6IpqVUCEi2m7mzEu0mvi+wIlGADMpVKiXi6lGqYud4jGxp/mWLYEByUZIJe0xb0xe/YdCWZNMxa/izbbLBRRQRIhMwHV0hgB8UDmruv6TlW1aNdlU+ty/sE734Hq9tZWTU9Pz6ZacspZcs7p9PRW7vvUixVMk2pN5KpWm+a56kT1bioD2Zw6qzOvElRBHnW/vX3/v/oH/+g/fe2/vzhe/Of/4ff67f3bL2+1L1rLu3943N7f3r779HMvDeUDfbCBTpwu8FP31sOd0935Bxg3Q33x+Yc/mi563a82r29euvsqNrrfPXq2u9dJn6SQdbXqBao61HKstU7T8Xx/eXFxDuBqt7+8eHpx8Xy/u9rvr8bxqpTiJ3HV96tV//KDFzab9emd+5vN9vTW6fb0dHuyHdaDpOQ4ctGqqkX1eCzHsfilFhVQU0JV5JxVUXVmrJ5BeNCXQopRTJVMEGqtraj1cljonD5/7Fu8FXbxUDhQrSAzTIUJrF5pOoQqPjxSMMzg5SZDK5AjNpA1gDarFSk1rUZY/olRoKiqfZLE4f0f/vgP/uOfPv7oMp+cbO/dZi5UlP0kfqYmzdbVYse+X3E4lOEoJ3s9ZClXWs82hZMQYDHN1XpjIXrY4DZMhgSsiKRIJivKKk1pnrB/65c/+yu/+/eOqxff33XH7mxvm72tR6xHuaUjZEqYwUItVWdH9LwOdRmBClnKJFI80AEVoISSrIAqjkebkXH54qm4FkNGflr+22sd94QDNPwC28xucS2UAPyxBLPlNgQCwYY0OMHYlJKSJKoej3jppfs/3N6dy49WIpr8572uVpgEuF1iXlt94bxPGsy6Lt+/e9crZGhpazIi4URZYe0YZELCkE3VUJxFgMgrFrix4+gw38WnjiNLAHYw02Ww5nGreM5OCUtq84wXhzg2L0skE1U1kkzeFbhZZcw3CWbqIv9URahcPOk61AyD1oUvBa2xc0MaIrL0nDfyugKMwaE15ZizJrwxrorcuntTI5MX84BIcumPQs0kSfZj4cYostRugEKvPYPVi5+Yu1arCy4Nc/GxqcRILPiTZs7risYVMGs+Hg76O2WpTbDVl8JGundimU9kLO6+k3qTznMVYcrZlzZA3YCmurGZRgXgHLSAkYNjsmS4wPG1ob2xs8kLAXrVExYaQTwRH6r5dkxf+CMJQE4SUij/NZL8Gh6ngwD9MMylaFVJqapRoNVCtk4ptQIq3gQ3BIZkdsy8qoA1NGf+nAaUJWAVP1C0JBDOqmU8CsBhYDONF8K9vn0SEfdSfSRDA7QuIINYbRMsr7ak8yZGq0q1nAl/qJI7IIYAwxAnkUlgCqFW++KXvwo1rbUUt04yrWUc91/7i689fvTw/v27prrZnLzw0osnJ3cl98P69qrfiKS+H/JKwKxVahUzlHkulXoUqAx3+nKpp5vTV077N+7kL37+/uOPpqfPr55eTKcvnfb77tObL/7hv/+T9TDeO9188vUX5t3lxdMnu+Mxz+uLi7Uc5OkHPzx/OJddkenrD/rXdMaTj96/f+dBrXzv4eNXP/XmdD4+f7a7unx6fv7xxcXHF7sn4+XF5cXFcRoBt3TQlGWz2aw33f37r56enp3e2p6dnW1vnW5v3epXQ9/3ENdto5Raaj3WanPxbikemajqrHENXWEIg87TlFKsLXI6rK9LVa1utC4REy0k3JF9fdYibf4gbG73WuecOscwXfjQqjQDOphrIZyKQyVTdrq+aAmKfoRURrgjqVBIZ2LwQT5KRlalZctOuRKz1GfVcjlevvPNv/6zbz1S3jq9a8g6HrEKqq8apEpKSShF5xm5QKbUjegGrPdmA6dBpmEzmUI2FEmaFZMxQybWiaaGXi0DonmVLZWL8emLr539nd/9jTd/6TNPyvajY97L+qL0I1YT+5GrCb0UogJVbQaKJPMmGEnFjGazWVGdXLbQ1tPCW16jOmECVhsNPoaTwvhQrU6+OckKu1w1mjlCKqWoqIJJciZQqgotiVSNsXtaojrgiB6qiVIVrDFjcOqn2zgBuUJffunl+/cfzA9/GKHeKU+guL+6OZZnCakuilPWlKTovLnb333prmqSGIZrrR79HTlT98iEz0abWgp+9EQcPVaURQALUFEd1q3aRrjGCKYxYg96nWoVwC0hyjxlySLSzIZMorWNyZ9LjrwhrITbsZEqFEo4PRosB6PVdwcbmjjHPE8IF39qp/42/WADXJcpgLBtxAUsmmLE8gNc/3FScpbsYCWgXs8K3AeglWcCQWJTr3lJYmZtl4c1zR+Se26IQxHeRZrzpkA6Py3kb06CpGjMk8IwyMtDbbxteh1ni6mILYzuFHU3SlVqERFJzuR0kAxEit9XLawzw8vSQKmqFGeTOUQD1SopWfRrCfBZGgiqWi1Kuk28j6JNmCQKrxjRtNkNgRy1rBiDuxtMgHgMPEr66wiThKo7STK1aTr6x/WhvrOpYVpqFZWckqQcA7zl5LrxjfB6pN2gHx8QmYj5wM1pZDQzO46j4+E0CflJDO9xfX6s1duIStH5Nm2CFYW2P2b+z6WUoP1EkbZMi70CtfiSGcjxcAAJNRG6ZyYkn21f+JVf/415OpZpKtP0r//Nf/fH/+mPX3vtjVdefu3tt795enZnu70NyduTO9vt7e329mq17fvtrdMHItuep/0mP/rB9/IgGFaPf7DJj8evfOU3dum/ffCZu2+8+b+ZbHr68eM/+r3fP1F9+rCcl4uT+c3X3/jl7337P6AeHr7zfe7TOh/PTtavv3Dr9qc247PytT/6E9OxlvE9sddef+HJo4f/z//7v9yPF1e7p9NxpzrlhNU6D8P2xVdeOtlsAJzcOj29dXqy3a43wzAMeeiHfhABTEotHkr2x6M/eK2hkXA7WarZOEbtwW43ug2vGknHRwRtPNjKcDVtPgxoM4MGA8H8VTzRh7+CW984P8tLKK3xnJoBCI+tNurxWi259a0PRFQjGCl8kY6LjLwdTgSQpNTai5QyIQ+VumJ3KAer6/H774x//bU9un51Vg0oBYOhQieTQbKKGnQyG5UrzOthtHmw/QH9WtYZuscma5FuGk7N1DhAiuihyixlX8SSzZr6jB7Sy/540Z/I3/l7v/Czf+tnN68Oj/f9x1gf89m+3Lqs/V7WO673uiozuTceiVk4m01qE+GU4OroHBqA7xCxCaNzADT4mKpm1QO2szThiKBhKfQdhrUbrJfWKQV4mJM4cx6lijA7a73UBrFhoUogENb4+7iTIAxWqs7WSW9mCitz6Tbp3oMHP3y3nqZkObmWI5ANhydqlBN+xrwBdmOKzWazGgZLcIMcOAF92bZitWiprBGpmklU8Mi8lXfadwMk42OHbLr1kA6UtH5Scopr562pBjVfzWopAFJy/x5bDjfo5SsaC8kWyE9Nm70f4SSsSLFN1MtFZIPGiovOXkutuZFioAaxNk7m8nb9k/ubsObba2YtKrbBrRsVqhONRcWXHUUijEDgAZdAuJEEbuvPok+ray2ITU2mzmQzLaqduO4ecQVi6m3aHDE9DXuIcFwbpLiJRwiSvKX2uG1qbRTiYwuRBZINuoLFJ045WcDV5oBqUZWcFtmOg9beBDrY0GjSy/Wrquo0dL8PIhSmxagLjcAFM6vq0wtt+LnW0sRYEkmXRDO1AVDmklJOYn1OqiaJyWSeC1Mi7TiO01Rzzggff5hqsdn/uWhxF1n3uwgRYUMWr59kJ8OFlFAEMLJSfVVzrYVJ3GshmJiC8GxG4PXxaEQctyjafYgQl4NunOmgvcPT/kgQSE4Qj8GLClKcQ4aLtwkUSAojTe1wGCki0lsvw2b7X/2L/91ffe2vb29PX3v19Yvnux++96Pd5UWp7PLjMmtKa6Kfi/b9Vk02m7tDd+fh4w/yppdBXn7t1YdPP/7eX/5/apIvfvWVb330dcVYrW7L5uHDw2a1VdW/+L0/vs/NP/57/3jTb589+uH54/N53B0vn8oh7c6PFyMky7jfSy7T8eJvvv5+mcfbd7rbp8PLD167e+f07OxsWHV9fyttcLLZZjcONZRZqxbVAqJMZV/H4OUE3zf5Ll5baOgRcNWRFv+bhiC2xyAiigfVUJCFq0k8QBH+zWBNcYtWEFl78q7nLzHQdahTIj5p9FRkfJYgHGh7NOgyYfeWd49BLz6jAqRr+aHiqvSmH8OskL6KAiuopQ0vPnicfvjR/ODF8f33Bk6aNmoGmVSylISqKIBCi+rRpKcdYUeUGaOkUftRhisrQluzlMTRVNKu2856NFFBL1as2/R1KhkZGVM5juXwxpde+7u//rdeeu2FA6bHU77A9lJP9nUYsdH+zr5u9tiMGHCETWaj4QBOFBUthkqrPhGM2Za2GBaFEQGraub9Tkowy4CDx+q8LDrDQxtPpsKNoTyOibg2EkGItFAMShshe8Mj9F1mBITMvgrJrJoVsoMmbXGG7qAmZOI8TdYlmDH1s8rd+3cfDafzeCnoWq0mFEOCTcaUXGsoPqgwVQULNJXNepOylFoMYcXp2Hr0INbynKrX92II/6qI+h4sADi5xltRWgstcNqwzybjr64pyykltgY1wCLC3NBRQ59THe9UZZAU1CDBpW1NQVVHb4WUvHiT+WMYdazLvCAiy/swL0S0mUcGI0xi6LawG4Cw3SckMeBQmP+ltMQMGqK783PUEu+iJHaMuBVkMATi6M+zxPzTdUkRQ9tzS480AaAzklHrn8zX0EWsiZ4VdBx6qYkkYIiWUJyaQMe7JGVI8J8BuyaIKGDmidObYIF3fnDJUKmlau1ylyiuNYqb5CVby2JeS0oYtba/8U2ubr4DM7PrIxKnxloLGucfcZ+cdoAk9FXnpRQYV6uV1dg9h6rOHwbQ931OWSQVrT5ENEMpcymzSCLCjJPG4/GYmhCqwQQthrONjIgELr264+GhPlTVWkVSEtHauKPRmrVKfKlZbPEXa0N+l8T5gWy3IKwA1Eqt4l/yxGyxNNvfotc3iCcJFEkWGjAC0zjnhF/4xV+ai15cXP6d3/y1zz/5+PzZ+bOnF++//37XdwDmadqe3hJ0KW9q1Y+ePjw7vctUa8kf/eiD9fZkOo698J0/+0YxlVVGwrBd6eVx4PpnvvAL//k//eFQ7na77rA/cHrw13/yrd0Hj6aDlQmCWbA7OZEHL9829udPy/0XNl/96i8+OX//s599oxQlpNZCmed5D6RxOmKa/HOVefLnNhSEICkpSa1eZZvW2nQG9BDpZ6+NBSIPL2n4epTjdV+EisaKuu6Al6N3zZvzjirMClzgFyq8uCmkBBwNWswARSQBVtU32zlq7RpbJ7dkusGgGeiObCGMRMUyBzOm6BtQK9FBrBQYpl7y0/Pjn/5Vf/9sc2c76lxS7Y7HnDeY5oS+liI1UQ2z1qOhMy2CWXQCR0xDP3FV0M/W761spJ/ERj2i1jtb08H0CFkJitpBZZVR5t3x+atvvvyVr/7qZ7/4U0V0Z8c5r/e2OXA7YntVh3062dVusn5iryU58UpH9UVbKIRCCqHLamwFqgfrcLpjwF2IdFIAr8hDmeK5iQQt1rEETBn7sawFryWCLOofLGcFFB/atb/z3kRid6MhOhfHcavPIenTB7cGkpSt6DzVL33prfzknW/88f+0ko4xdVAo3fTY0GwEnMXr2YDQqpvNIGBVjRXgrtM3DZsMiIBexJGofl4icsCqspo7GpLBYNA4gQDcvEoM1Sfa7e9MmpNGC0VoUKlfAIOaVk0Jvu/I2jjNXElJg/dOzi4DXUzvGdQtYMIPIQjI/hvU27OWgXytnZjVGoZvjeTeKmLD9cOI9mwCCCK0mtUa6iCvPJrAWZu5mb+SQiUwwyY1YyvPETXv0lgji2gzu2DzoG9/GQW8u4kFk8kpcL6MOQDiKJ/i9Hk3ZjdzdWDfN6Dp62PogYyEGZdFJVZNGOHeDGjH3lS1VJOEdG3Ge/1KiCNrMVh1SnKTePsF0uofP0pS0ox0poDTE4UJ2Rs/Nd9yQ0FytzXA1fEEWWt1pmut6hsVIJLcSL2hUj4dMFrOPZwdJlxJNqCqppQ8ZzdNURzTKKkRZdbSzWZIcfgxB9qhRlWVCOy2rDrys95Mdxbrl5/gnQU5Q2s1c+ZzaKIBiouLtNbqymkmlwhEEyyh3VKDJUnRIJLmS4FgVvP5+SFlGTa3VPHiy6996lNvqto0Hstcj8f5xw8ff+ub37m4fDLNyHn1ymuf/ujRU0E369zVk/r8vBtEU57GETmX+aCY765f2Q4Pvv/N97579fV0WL379jsv5VeRJe1GuTger44rHPrMLNztL9TWd+/dfvXVVx++9+6f/PH/9+7dfhhO/+ov/+KnPvu5/eGKAiL3g6F5jHjMzXllhlprUGGzOEppzQa1qma3zmtFToPpXAYXFzc8YhbWRHvQwwtFrzfdLVHJwWpH87xv8QG+P+bCxiTw/bXh2ydk9nOnQt9urBBxJmNoI+jmH/7omyZK28bj2ne0ZzMeoxI9SvJHqWRI1YNIL0ox7t9/nJ8+k1fvjR9f2PHYg7dSfa+UIWebCyw501hHlU6kSDmo9Iqe2FsR2ffrjlWIasyqOuWt6In0ausuzemk9KhDVk56eH4h1N/8u7/25a9+Qfr+YtRj7S2f7jDseHqhm6vu7lVdn9ftTs52PN3rynaGHbinHMWb4HqoMgpmsEAKm8w3Tr6IGhSmvqPETN16BNCqlUQQ2wLlbQxFEGCiBPzsYUXDRT8U/najmpeIGnGrg5Glvq7AfTpAgUnb9E2nZ6LCiomlOmnZ5Mlk5jBh9fGuvPfoGdbCSq7JNWw0DMAkXl2gA6oT15SJWEPWZlZXtwdsSAgHYCBWmKQ76mpCP1ma2B2RJ02Yqs4S8i1H7yO3GFQhZlbM1KwYCzCLk9yCbStR36CNoH180qajgYG2+ag/R7IAosJW1QPROrrha7haAkGy8acsY9HDeKHakqt5BdJcp2I1IomUaq0Go8rSBS6kJidfL++zJZIYFsvyrGukd1iNQllI9xlilLHXTHnCgQYNNqQwGkBFm0diida8trLEjUo84oeFaRvMQkQd7zPW58UrRTOtZvBNkQ0naTx8oA0P/as/Cb+iGT0hpqaelX1iKiLBTRXHM8y5hhocRZKoqmombujlE5XYNiGRUL0DjU9s2tDCRR593eNcv63wP6kaa4lEpNbqpd4CbNz448ZrJJiFKcduu8bOw6rPplZKqbW6Mmq5SteaBMYDbG3l3yJFUzNCcoJWt8gQU5ecSavELarjuAMBvAPwF7NFNhBdjwpEDbUWgjl3OWfz1k9VDTks0KBaKRlmSbIr6fwKQKBUEzFSoGvX4egs4DSO42giHWXFvuty99Nf+sKDV195+uxZv1ofxmPu17dffVxQwH7dnSYB0/0q/UBI7orZ5pY8/tEFDCf29OE3HlH17JW3upHH6fmjR0/Ott39uy9P9XhxfDZOj85Upv3Vww/efvedvyil9Ovyp3/yBy++9ODe/ZfK8fL1V1+8OowKPR6LqqP6PuKtjv1QmJLEAxmu+0G5yYsFd+NEXN/u5Zxbq3F9ZLgUms0stuXuG4BLK5sozlA0KgOwEGMsU5AAkiC+9IwQX+GuyFHsGU1FKa05Rmt//Xclg0ATKWBmoORoT5N3HwmgWrViRhXmTjpkQcXcl/nJI3v3fc4TJlk/uH91ZzP/8Ml9IzGJqiZByTYpEy0Tk9gIGLAidj5F455rdKgiW+kNebbLCfmgq6NsOtGVTFkUx4t62L38yqu/+Ru/cu+llx8ea9kReThKrtLvS7eT2zvZPivbKZ8+5/bKTkZd89JkD90DB+AAjMAITsRodlQ9GEaKzN5dGhSoi/QLqLHjLhyhI6O0sAU4vaPZPlyDHGSbl8fQ0r9/KYJv9AmOpkYUN3NVf4VUX8fQaL/RT6KJpub9nG/lCf2IzYbjEcPetuelK7IdTmaMZpNg9rpCzZhMUEA1KwwwcgOuzQyrByueAlDdQLbA1uVbt452MmEzcTXbapbejrBRZRJMZkUxCQvFhx25oBagAMWiSfGprAIqNHf9X4JnYKuxtj2um1nrD5XWvK9IhKf6EnbJNn+H3ViebRqwBCE55WTqCz6parGMN6ZxdDKXG2cgFk15CWzOgJEW8JU/+ThG0HR4JN6u470NuQV8g3Eg6f5/NeWucXAWtxAKG4vIzIKrZkt+obMrgzWWAGgMwzVaWInW1t+JUEJSZRBf+eqzKA9ALSLRYswuvvMnFE1e4wfdOlo0Z4ShAeVJogww919Fszo3oWSh1sVWhmZ1nmdSck4wmlZzy/l8bWCpjcJM76qb6UnARzE6u24OHQYJU9+c0cIng56OxJQSs4gBtVSYy0s0O68SrVMUprDpZq0q0YUj5xwyuCS5fRVA8gfRj6cahMtekKXpzKGSo09CQsYZOrRW8TVKSXTP0ajdsEDj8oT4BEJN0UYvCBtO8w0oQlNXUqmqahW/UgFkFCTxVh5mUBOI758xxt4Iv2R931c1iLAoaALOV89P15t7p3cPowJdQnpx+6oqiB7Sj3M1U9FkMhJ7SUWP/de+8f7TD5++9ML9ff/xg9fu1f3uhz/+q3e++417pyddr/Nx/sVf/sL3v/e9qdx5cv7js9c2r7z0KqyC9dHDR7uPn+8PH1/s9v/+3/+PJyfbk5Ozey+uP/GJV3Pqlj0cAErRlAFYVQ2T+DC78GLZsyyxROs26HEIx6+7LMi8178R1umVZjhVNcuq5Y8A1x5zcROdnUJzNaMXYJKinYKEaZdkQ2x0N5VWmktm1ygm/v0IY19zzC4vPYu6tDw+VHFugqJCK6Gz6GrqD9NuevLj8o23+4vzAurFoZK2WtHKbWEvY9FbpiMFduyZCFKlUkmldQYBc3SH+9OhUop1xWRkN9bdLekrj2Kqh109Xt4/e/BzP/drX/rCT1uWH+5VZVUkTUWY81xZ5NZ5We3znV23vZj6MZ8dp8wrcm/YUfame+AKtjdO5ERMtIPpaOIJDXPViaKSFuGJebEiUgHTWhocYNfGNkstewPk8Pvod8trWe9cHBD0yaVqaeIYN59W0u2VEaFCTTmbkZKhRBEUsFLVODt5O+vRyqRTv9prX/vN+UX+8LKcyHZK52ljHA0FqFAYCsJsvwRNhkIOxo0RHB6suAVBuwU7wRW2e5zssd5zc+Rm4kmxwaY+VTUllVC1Qitmtamo1YVJ3rUC5voOdWtgY4k1YrgmIImItWAfodjbNQuUsiXshvvdoDE5kzr2FAQUxMZqUIDZIsKZqprbTZMWAiI1mDSsWaG1VK9ykzg5OEhYZkCIqbmob8HWOXsCDk09XOpV2q6a9nWjsEtdDXWB5/hGZ7XQJPmn8+osGhsynHJgDYRqcVqY0CC4hY7ZxlrSRBKR1a4H9f59hPg+wsDQNGAKiWIBIJGC2iPRUzjD0Lw5E/P5QDWleg1fTWlIKQPhqykSm2pKQWqLCuDs0IgrC6c3mnVHkGO2bWEVbtTwCvWlAWYGesSlbwlWc/QjqPEWHtFO1IIa3VEuiKlcFG5q6s23kUbzHjo5w1krISllN/n3k1FqncvsIw1XH4Z9lrvF+PeRbIMJDfcAoiEHTlgA6B82QJDGG/SzZBZC91YUiQhLqaa1T8kVGmUuIkiSkvTRuonUWkiU6kMIQVUaWduYwSthIi2fPwGEWo0kkF3xQMkZqMd5LFpKwaR16G5B8rGcl0mS9cOqV61zOY7H86O+//ETffWTp2/+lOz2T/PlrVc++YLV/K2v//ndu7c/+9XDx48f/8G/u3z4wTdOtxsrcv/+7WHq3/6zr+12z+7dX//c3xp0PpT57njY7cf9bvdoHi8uPt7eu90N2y2QcxoACDs3r3BKmiZLbv4FB68y4SczBojLYbsGcNokwIxOZSBBRa0l+C6BJbkZbjBVlxfhcjxbncToZc2UjWuHdnidLJuqkhAyI4iY2Z2LtXg9nSgOOJNMvtoDBiC7iYenfrjyJDk+UwBNKZvUUmbQDtO4e/sbw4/e7epxEkglLp6OH37Yv3B//l53ovWV4+G9ru+Zi6kodFRz8FOADDsoMizTqbwiPN4aTDpFKuwgkvLJ8fDxPO5fuvfSL/3a3//sm6+dDvnZOGEuNffFxJgn5qKq0h3r6iAnO5xe6GafNtM+cQ/uFHvD3rAzXgmOlCKcwQlaSIUIaNVsKnU2lOw4EbwDNrMKGimm5m4zQb9qgc5nsTd7pOuA4HvPAMKpUAuAaM5F0QKtKlIR3E8NUJICiAZxS00L/G0WWLE6qgxIJVkhCqTImFcrdCOHd7//6OOr0m9P9nU6XV/ZxlDACawkqAYxWqGz6CwZV2aDmVg6TbaFkLYV7WSv/R55ktWEYUI/WXdEhwItYIEWiElwf1S1GAvEqtLFvkXUCGVDniN/GNql8kTGql7gekhbfPZb50hJqXW5oLhffqS+6ASC42UKd8cXiR4Tlq0UUAyNRu485MjEsuQkr0VMnEoN+vJhU6aUJPn1l5S1FhiqanZeTlh5sbHnYaC5J2Jr76xlleiLU5DxggNnmiAki5kWjfblBrdWpXU2EpScnxjyxTAXQuhNRVGzCNBmdtiazZgLRtXi4+RSm00HnfYbVAb/gQATGNqYmFs1LqAhJTFzQVeht48wkHWuHhtT32czrU6lizFzKzIhKRc/2VStrnT04kVymDyH+2PbL8bIcUACTdwb4WZpEkVXUwxTciQ3xgjIhK4q9SJQtI3XEhdjI4bSKMJf+w61TJHUq6iaUoPw1vx4gBgVGbOgaAITaAq0/U5+caQ1ZWi1oE9AboDPIkm0KKKZrZQsmaYZiVpVa4U7UKoipygWTZPkVrZprUW6ztSCNuhKGTWam465lU9o4xTQMJM1ST0IVUuCTVrNU03FTEcyr7quz54VVJhPhjvDcG+a3vjki+tSjuN0JeT7Dx/Nu+O9e3cg9o1vff3Jk3tdJ7/6659//NGjaSebExEmpnqyGW7ffvHJh0+fPXtYpserIaOz0w3vPIBhEpTp+PY4baAv+R3sV9ssdxW9j6Q6dsUmF6qg+fQkKtEXK6S4S6jLtt041aAi0GopJa1qtOQIgbMQAoNMbtUbvIxgf5gtGsJaXUpBkSilHDQigM5TqdtkQRKMwt4UZpkUIJu/W8nozCyZkpZS6i2eWhGBipvzimtGvXbMhlktr0TqCiNqPUJE+gxi951vp+8/1Kwwcs6S8nj+/Lb2+srd8eRv1s+fvCLlXZvMMmSqJjL3IJCs0kLKk1BREmRYr3DEjKLrbrdJkldltGe78wenL/7c3/rSV770+WHFj/aHD3dzAlKCQmYkVRqziUzIE7udbva6OeoJJ8l7YAfsIRN0b7rTulffM20T7Agcq02kFKKoVslKgCiqE1BaOWVmCveAcCovdKmMzGdsjYbrT1QgZo6MeHtHJcQlgq708OYuZ4ZbUXSFrFbFy99kyKI+1aoVUDsqB3JC7sEqLAY1TLBRxiGvsL6ox7/+3qMiw5XmZMe+O/a3JgBWhUIU9ZkEARQP0MoTaAcmwSns1Cogt2XHW6NtD3Wzq6sDu4Os9lhNHDBD5gALdDIUokIsJRBUbRCKD9HNJ9WYQQhrg9/cfylbWjBOZ/I4qrgA+VGGLC0wfZF4+BY1eML7QFlysWsqCYGqZYepF9FlIEiNIBo2iDBqGIxLYqmlLm4StSqYnOtRa5mL2y6KBPJZrNlMuj0w4FVVC9gBG0Vcj9paGnGAAKqZVU3ZReha1ByUJpxHjixJGTZJiA2fUd+FcWmgxEtBAMeNzQChUzmi572BFTSYHJIbSuNXqGGqS29NYfI9kFqg/4tJatQVGt7Idcle4uviJSok/4Xe+JYyk13f9zoXM5WUVVUovgHJDKaKhLmoUGot6i4c/lltqWpIwkq1BVFBA6AYk/GgtqmZmTHAFosvRYnBAKTIxitts+bofWLC18prU0BMdOl1ok5pJirRwgqc2Bc1Qa0xmnRXHcfIWkXAawZEVEIxinSTZ+d1qyobqYTiW33Dvk2qPx6tp5UkpHuQVa3emwdsH78eRSsk2PwuJ1OtsAlMBBWTy2C8QkiZPVPLHK6vDFxDtVAwrFOQz7Xkvnvj06/mjHEcv/LVz9X6mctnz548fnRx/nS/u7z4+Pjo0cVLL79kHD549P3XXnv913775Y8v3u36zTQZYPMxSruu20/z4eriM/O0h/QAhs3zvt/lvm42twSrsXbrk7Msa6AaDqo9SEUUbQpAIUnKXETEWGlGiJaZAtUiyd/zrJTkN993lGv1rrcdkNYyewNAVF1Kbp+6Z68X/dq3ElWaLiMDQopZVvOvZmECMgmtkYxVxaCWodmYiOSQaZCFKBST2SpVqh40db32ChFD7tZPvv+9/p0foJdjQVcVaT0r8/xs3h02r947brffevzkna6DqNW96KA6VaiUQQ8akkzGuTSFdEnAMpZ6NWtfn/R6/5OvffGnf/VnP//66a3h8TiWyynzlogmVJopk7rLsIqmHpJH5CsMdgUc1EbgADmABykHxQg5Jk7AERjNRkMBjzQ7VD0KFSyCQlZYhRXSVAt8cxDN1KSReE2bMQMbB2aZ3LvOdcEpBHSTCJiq1doEqbLc4KDcGmBWgN63mpmp1SpSBSk8dr0q87a8iM2w0ZAVg6CglGQn24cfPXr48cVZPr0se5FNRjldX/Y+8EkIfyUVU0ilexBjA1kBgrE/cksSe2522O6wPXA7ya2Dnex1NSJNk3FUHCGTcFIWl/iES1Lrk5rtYPi9iO/QqLHfw9UYFqM0H6O2qW6tFdYKV/jRW+jIS33iX2mJegmkBk8EFsUQmSVLdJON7RWv48WuS5lV4JwO/+HWRTXgm20Q4AERqlYDO42fwsLpMBpoQidKMkoLx5z9G8wW5kWD4eGuU05iblt+w5LUxW1Bf41ZNaKfN2VQpsJPNKDKKGYURiXaIjw6ndzJOFwG6Wq6rOFUNU91BtOWovxmVnOTS9HWOv+v/sTUzUlVzsNywnfY4SbRufoLp5Sq2TRNIuI2LI5MJNKES6OcUoJBslhB1SqIrU9Ls0uhVceL2ECPuH5BDtBI/NcIfUt/0dCjzdni0eX1vW9/vA9qZWKwA4UxD4FXSiElNHGv0AatLHdZUq5aXZa3HDAGZuHcW8dtzH3gGxsLSm2pnICpHx0JYEgN7EkQqmUukt3hQYUiORyenXPgb2ipnm6yk2BuoeNnQhGibSVF1aqBzGQiFSgMSxv67pWiR6Izq2ZpsxFwZaaqZZpKzrrdbrP0n/7UJ0W/PE3HqVzt9082m9PvvfPtH773/c2m/8EPvrM+zbfvnPV52m5FpAKYylGrlBliq5PTi37z7rR/CcDVx2/td6PK0yd6/tKDN1PePz/fiZ4O/ckwrLoh++o/xVQV83Rg6mDFKVxJqMkkJVQn1kqpTLnzytVIN9UJcRkFMRUGEabuanA+YCP/q1ZFGMkEecdrFKftuz0jkMQEzJRMy2aZzGbiXbtkNyoo6FSyqEA6MsGEEINAFlWrGWGaMUwrnVm6OdcES88f/jj/9V9PuGLNadoQqvNUutWaG3zre+987a++9fziort1FA4GwAomx8lVJ5l6EUBNmAoNinU32GU9f/5c+3rvpXufeuOTb771xoM3Xh5O84h6/nxi2jgoJNSkJRHqayMNxmSVVoAJGKPrtcmwR92Do6ISe+hBMcJGcAQmn7kWYM4oQFGdDMVX9CRxDNkUqrUEiVbols7Xcae5lCysXaDhEcsj7I3EcuwVXKgnDAGwiAC5cQK8eCLMezNb6LcErDIGrhVajIUYK4+UYypnmx8+3D0dbT2cXik7WIYJcLo5ZJ2CWqyFEBQJmy8aVmprViuXuJiHvJuHKzu9xMmVbfbYXNpwwGpmP3HDQkzAZDoWmcUmtRE8AsUdv9TfcTR3po6oqaFNnILU5qCaVx4RkoQx7TW415NLWxuNpV0XAG7N1F4zwqo04LHNDw0ws9ysggAAbYuOxuIimGmplWDKDsRQ20J730/gisNlk4FIMjUTTUlqrbXqorz0T2ytH4rhcduhFG+I7gbusTzcrmRJBCJWqy0yxojTqma+Jlli4Ylj/tamztrm3HALbv8I3oWCoFLamjzPRHQll0UP3a4/ETZnManV4P7QdczuXhlWIfHmrjOxkKFKjXzmjLbkVtTqJUSICZBSNmAu85AyGSXMdcfh9k/qBYblnFU0O0wWbF4yvC1Zm9Cei2mKH5F45MwgKbbwBbULsFDf2ULnXlrPGx+M5A26AbzMMropGg3J0QttG1f8J/U6x0tcKr9lzEzWnm9t9wKxhjHkLF51uXUJAJOWEFIS53OKehGkFrBKM00SEXXTB0e0b1xR+GuWUqtqTpJSrss4XE3adLz9qXEWmszMwqkskpEZRDQlARKtajVKhs6O7auh67pVTnOBsajtn53vKKBMXV5v7z4ok33xyz/71he/eLU7f/+9H/3B7/+PV7vLO3fvDuuyvT2f3e22W9meYrPRW7f7Lu1U74z5AwDj+NH6xC6f3df9cH7+I9WzfrvbnL19Od56/OS2Sb51+6zrtqvVybDq1qsTs1KKClcysNSRoNYi7EioWZc4HvciItLHs8OfONLRPxibhI3x+PjoivQZIUzM3LInATRkxvhIgA7IZonoYB2QKRnIdBcdgYpKZuqzQpHJZJZMBchAjjob7shuPm6p2vc6m5hWdOPT59M3v7YqT/Kqw2GG6ow8JEidznX49pOn7wH11j2ZL2nTpJWpT1WqFhGpWgCxOVGIYlKQkQ7Pd3qob37x01/55a+8+MkH/UlnPcbd9Hx/xSGllD1aFLe9YL9wiFEhgBVoURTIUTiCI2ymzcAEHmGzwZPuBFaimBU1TGYTWXwI4IAdRAnVUiG1SW6XPzf/2buEprD3+2ctV1xH5RsmwkQztLJ0bUbhEKEYFZbC91GLoxQx/WVB8xBllTBBmcFJbFT0Zocka714Uv/8W+/vZXuJbgau5/eabp9c5jTDkKJhdd0sDWZr5K2Uff/4mC9weom85/YKty5weuD2gJO9bfbYTCU39jgx0SbYbDabTeAsVoxaDLOILnr2MIQwT2UL9+QmvdACMXCxq4N30aHJTzCK0Wa+gWTLItgJy6lm4eCNpn9zDkHLsnYmcO2kpcLcDVbUrJQqYjktCkJ3YfRY6QQohmrVu9JglVkOfpM66u22RAoThA+3l07Lrhs0W5DrDj7wvIpsFvbK152KE19VVX0IKhAkM6UF8W8Rp/qF8oS9eFSwBU1t++TdbM8xWBdD+1ojDZyczjzR4MQ5jM2UfIdGEEqB5ffFe63OZRep6h1bil5cw2e9lOIbamGN1Cu+H1CqhfRIi8aVhIuIijAVr6GKSi/BEmjwCa69t9rjF1gDkohVVffHb2iKf3wL3rpf7DijGsZwrU32SxRCkaX2jd9o9LE3skFFVQ1aPZ+1R98rJKItpDMY2+pBQ9ijqFkSmN9frSGE83vjRSglgox5NevVmsJcrFidOwY1GnLuGjCTnSvgZiMAQKaUGuMfpRZpXloFi5RMwt26ZaIo1Sm2iHEt0rtZMcskcmalqu5TzqYyTZozVAtoKZNSzT8rqdqVcoRCiKtxEtRuWL31M2+9/uarP/z+Dy6uru7dfXDx/PLRBx88fPdimg73XzjJedK6u3X343svbAG89Mr9acw4u5rwjuaXLz9+Mp5/8GKR0+2TswfQ8slvfm33wktpGJjzy2d3T7th1a02OUmZLDOXGcYiycfcWioyey0F2QvA4FqGjQZlaajY5EzL1JEUqDA4nkLXiUJgmcxAxwCfs6GnZlUBOkNmpqwEgmBAZylQZiKLZd8xp5WWfMGf2yU4GRRkJQx1LnXN3ob9+WX9xp9z/4FuejmO40oFHMpwHMcfzPKtVb4Y0PcYxlI4FJ2yYKoqmI2JVjoJqisKcNS+y+P5ONwdfuPv/fpnvvAp9BgvyuXVEQPQWbdZ6aTB7IbmPhnNvPxUgBCV8JXwtawH2Ag7Gia63MiOwNE4khMwivN1VWZaURSzyVvhyMSEAqmTqPyCX+jFfHVTGW9Sq0P0UfBe55Rrp1HPzE62ctZnq7ElFCqt04njXcPqAGDg3qoswAwFOAHiRGhMQCZ7YBR0xXrrTrofP3ryvfc+vj3cPcduQ4FlZSroRwyT9dvVTlAFTIIMI2qmqfGIvnJ9Tntid57i7s5kZ7d23F7i1oHbC7t1yVuHMmBH7A178EhO1FlRyEpUYFYU865cUUClVZdTO2zAyAXRYogwtmgysHf/04AxmiG27UYZiGBJm2VJgPPHtX2VXFhBN5opAk4IgqGxrdhCoDXuZDxSALD4RMakMWgYaDR3p114wKUkEVmCWvOpZiS35aXkupuNVvgmOuKYpIgUjRfmT3zRvdcDyFSXMYvKjaHkNUAfPLPYruce2l5NVDNEzxQXiDcuduu5o+IuqjSKO294bjJqjV/nBKYbWA8a8GuqJim5RSPCORIkwjRDFZ6GRfqc51JNUcMxkwY697hWFZGqlUDOeZ7nMpWUc+c+fKQFASuq2jbTjGdwyRJxu0AEIEx6XSV0ItqN7tBF2Gq0xSPFIWJVX/mwYNsIORYMbHuLJSVajRVPlCQabbYias+mkXBldxMB+3133IwQgzO5wz6MbGf4ujel+VZmimOdEUIC/FdZPCEovs2QRMqJDeGQUMqgFk0ipjbXOaWsMdWtIvSlf+0Me2dNgqqVbszUCORGNaiYJJG+77UqE/o+TdNoQDF2siEns1lkBRTwIFwZ55wSUQFUw+XVSOk+/dnPazlS7M2fel3ky1M5TJPSBjM7//j5eDy/+8JdAJvhTDs5uzV94iXkPHSC84uLv3z7X13tqmmBfPD5r/y0yePZPhR8/+GPPjuNZ5vbZXOyvf/CAwBX867vBhYljayqKswKyboIEzRJOzBoroStJAMWVg98aaAZolCyTCZhski6HSBEZ+xpQhng0q4V0UF7ZSZ7WjYIci+1VkuWh1ylsiczLQHZ/LB7nwQFFZPpuvazYvzBD6e/+obuPhxOZdrvq0g3pq7WJ1rftu33h02vY49R9kWFRQA9mephAxSIsDrTUgFIzrbJJuPFfnt3+7v/4Hfvvnzn4vFehoTeZEiq6Ieks7ILXDKnpKaS2PhhMOf6qPtCkEYcDQfYZJjBiTgAR5OJmIERelQUhUzALGLhWKNFbYYVolIUVioBc4LuYujkMENjDqGRL6O0ZoNL0R4xf4Tkxr9eh1dtPvkxa6NGuWm17dNVRYGYoDd4ECzAjLnHESDQEUckiB7F9sYDvve1d3Fhx+H2M02TrAq6gtXMYW/rIsMkW5pW0wRdSRWt2UwlHXRQ7Z8BZ/mFp7h7CVzp9kq2z3FrtO2lnRzqwB15ReypR9gRmKATpICFVLMqhgkoZlOtJVEVM+HJuQAV9Lt13c4uKPt1KPdYz/g2a5izBajgYc1KKeJTQ7LJBqBV/TRQFvDeDMjtoltMc9no6V0GXHukEKe/0pMR28+jDVbdvkNp0UH4UxmOleKbjZbCKgpmiyqglWfwIGhLEdIoYd6S9iLFLJ79YAw1vNcNwxJ9sYRWg/jq70ambWnUADedDhZcaH8ZsK5fE8KU6qSCYBg6pBsvFPolNTNz36h2WCXlZssVtwV63S35nNHRMpOAmiV8uH2m7fsNxRsyp+yKv4ghNGgubYVCTTNzKdVztvQrLJxsxOyiUcauE5uTVhBosty4DwAWQ8d2VVq9hIATW/Z2RpXfDdEbz7J/HWaaE73wWlDqnJMCJdTdZkstZWoqvsUISwZvVZ15cyMkpUKrVix6VcDVc3SOAhHiZ0G6LnpUDD7yNQNTglvZkQA1vCgIQKvWuQBY5VXuM9xat92/5i7nUhx3wKe0NZrwdSvNaJEhxynqTTi7OpnARERNm/XrPNciqsLOeCAElkGTpKYyFxXJFmN0ljIrpEzzVC6S9NCcM9T2RH7h5VPJd+dJARTMECOSGg/jOGJeDdvXXv2li9037p9+dipPL6Y/GtKt7ckm9SPqjzM2P3747EfvffDtv3nnzt2z2/fP5mm3GmR9ItNRNutTsAACUcmi6tGjdwKBN0ps7isLtQpIodFjoiRTANkMVgzZDZw7wPPnAGRPybIBeqAHEqwzrMzE0ipVqXmQk5Oh0kadUk7Iil6MaglMgBkKYdCqVrTP+XCYxz/9en3/3dV8qCd1QhFFKYcOeH/MfybD7nRzWpCP/b5WgRQtqodNlzQN43GkKK1POQFKuGV6OV7qsB3+8X/xj+5s7uye7GWTBLCZKNCs02jSER0ki1atVnOWWpUptlxAfYkvzVf3VMEU8CxmYCKP5ASdlDPsCNRiKNTJ2zVKJZSihqpaDEqtcJURq8tKYLASE8fkK+5uQF/+5Ku7OzdWpSHmfa369xqq+QPSrsmV8WC2MnthcdA/GwEjikjyjQi0wilDgKO6/kSypBWevvf823/+nbRK9hxXJydzNxTmytVkqw2GgvUkk4gJTecjdabWLBDIngNk9RTlldXLz3j3EtjLds/NzrZXtpnmFXZmO7M9cQXsIUdgokziS5Tp24/E8SuIKcWoCiitOns87hNVwuQk2oJGbLmOS0ugW6zXFo+rCBAtOLVo5qiyQ4sIzi8CLAx0abFDujHmCUQx+9IoT3uA473+a9x1wZvhoNV4sIwBfmx9MK/MAvKN9JQkBoSLdJ+tOXbUGQ38BOlMKLa6G23qrapZ2v5d/1Ai5v4OQQKGG3f4rNo/x2JdCdMayhgLa6lWsESPFjoLttALp+8rACs3Br2MQmSxA/jJW2Vm03EkhdLFXyy0QpKUzFhILNIrdJrDA8altFoKFDnnaZohBJQiXc7TNPV93/c9l/EblpLLb5VruizyJgAiSSJZq78FwbWdEOHzbDjtVW5e2JRpgeyCWHpJQDIW2Co+rVZIKdWvuaoWrSJONbTWkYOw5IpVU6cMO5HbS0F/U16BSRuNU5iZEFld2lyWBvNtPz6yVXFbPHEX1+hq4+Mz9PMiNBNKUSsoXpQ6NK1qqsWESSSnzgcrKUHIWqosbEQw5cTojJMG4aAC2kxRFGZWCY6OJ5WSvK1XLUmQfQOaoaIYhNAkUpWUSXIWqMNJZhliQJdzUjWoSQYli2xVp3kkZIJkAOSKLKjCdMzSW8qTHV75xBdfPH5hs7HL3cUf/P7F53761a99/Wv9mg8+8XEePvrkT51+phvG/TDuH2+233vy4/vf/s5l7uW119+Y9s+lq9OE3G36YRAgpbxZbUisVoOkIMh58b48OwAECZTmuQFYMgOYVU2YwOwJGMhAb6T1Jj05CHqzbByITGSbMW/P1kWmP//GfxpOt59763MjCnPWXE0gA53K7naDUsVm7bvu4/e+LY/ezsRxkGwFfUFRKendbvufT7OOHCbUalOuaaIrrzK6WlhrleScUyiKSfISa55H0/Tb/+Af3V7duTo/dtuVjWazsiNmyEpsUl15meFiOYEreVQrKjQm3lZg3gQb7GicaL5wcAKLyCxWoEeIKljIIij+M6oTpIrUeO4cTMPiR1Rpod8wA1FVuTzPaBiYWa3FKCJiMGmsWYSBrDlnXdRhTgOdlLpEkuUPAdCn0wIRmmoFZoAmDskKUFA7m5VHukWCpdTf4pMfPd1/tDt5cSiXEy2VIe23d4m+mkzoi+axHDrhrWEYpx10FjFAi8qonXK9t7LvXnhupxdqE052aXuQk2nMPBB72Gg8mI0OIRCjcQIrUIhCs9FYKTUg5/DsgT/LkOIgcqAFBkN1ulRk0MWPQtrlsECNyZtYZuiTGtxrtkxNed3dEO3fDBkO6/pEZxk/OykYoRcyt/QFne/oWnitGgvisKDadNMbNvDamp9lMPHMzFBLMTiVq2mEWsatqm1XzdK5Qtr0n8JUvWQLwnPYk9zIFKoWr6lBXvIG1/0Xw2KcRteZmIFsXubRyCl9rCsNRNNS6uIztYwgU0raBgCoYYQuWRCmWG4I117TrFv1QFMrNcmLEVlS0WKxpccdVD2LqZpVldRl5kSgquWcS5nN6CbMzklPKZtqiTqDIsnzUJvqIrpVL+mSaNXqgyI3HGrHCW19UytDvJpwHIVaa4Oy2VBmA8EmMm6ic/+NxiTNGiaJWSklJ+Sco81dHn3Pk0Q1M9NafDdUBhoOwsbGdJdKEl6jqrlJtiL6eomljUClSSgHRMQCMmAUdk2aBkkwSxK/x4EjQSaYpJt10uhfnDNPE6YuO5rhspxGE4hq0KsKN5Dx0kdMmJxFlgyWXVhMZcwpVJjMipNmDbGFGk6KEIIC13ijb1EAAKxq1QkiIhnZXWr9shYFmBToIKZqCVnnY8q82mvfb377d363y3J2541/92//zaMfy2YzGKdhXV5+VYYNL86P69uPvvyLLw/5jdPTB+fnFzJ8//HDcn6+26yG8/OLV199dRZo1auri1vbU9+X5UI6eh1EUaNItgW+gmt8U5Zuhpaqfe4UvUFo2YQyMPW55mKDYi3oiAzNik7uPOje+e733nn3W/syvvft99/6lc9JydZBVqYGDKlgzppKrTpbX6Uf+vd/9Ijvf2t9lqfjsdTRKnorR5Xv1f5bfTcl3uo5XxmN2aB5ozqbGYmpjBTCOmKiFEg2TAQNHA+Hf/gP/+FrL9272E1MKGVmT+mJDFlBZpREGX0mHWdbgyoRZRgA88JMaRVqJpU2mRVIFRawQseCCtikLEIFimICC1ylCncXQeClokBjVsHlvwvDIlczWoO/BdWa1wRdJOLypMgKanB2qBnMLBJB0+77kcb1J7v+B3H3CSok0RRWaALL0CnlldqMku1oJM2oadbL1aPvfihXtOeQmmsB1ygmz05OD5IHHSdsRuxZ69OLUvNZFktqJ5v8CdPnxyJ2cnelw9lrH8vdK5Ej1lfzWg6oR+XOOAI72GjYw/bGPTGCs+hRWQQwZkGtbmLuYFXRiVbIqlp8gYuPdU3NNXqRfRw1MGhYdsTmPULMnYQAL8oXKDFQNTq7WsnYitHWKAd507vs3PrXGjhfy+emRtDCTFBa0LSYwpo2XDYgCBFpySPylBNjhFyUwGwJHeETW9vfeJr0+k4Dn2yvZEFp5XImAAslq4d9rzdaQ3o9p/6JQ+NfMlusTzwVm/pn18BrITEKcF4ngUb49uW1dP2SX3gCZrWZt5GmllMqtTIg+kB7JCU2fVitcynVTa+qxuAhpQxiLqWG1TMd8ctd9qGA86zbBuygTosQnl4MmUlVYailqu8NhsE3VkeBa21eYa3Ht7iUcdYkCVvd0HxEVF1wJe4hHINjqud77/urquuLpOGQNBcOhcSa4rRzMxe/8xpDdkY/mJKvxaxuFwO2waIXOa7h9ewmcO+QokUVyf0cAJj53oiFPdc8+NDGXP56akFuj5OqZjRrkjm1qqT4K9RqOSc1pJxqqcFRj87ezCC+ntssEhCYEi2U1RBHH/zkwkgNY632/76cWjXqXhEW1yVDGWIQLBIs5+H7VdCQ22ly9xV/ZqOU5cLIaH7ulJyK1nmcR+jp2cn/9n//LwgIU5lsmlUVKUmZ61yu8mB9vlP06u7dF1Rf3L4+Q8rucvfqJ/LJybZWlSz7/UgRybmUAlWRbMJgZqo7OHYeW1QnmAhzUV11a0VXZ2HqAbFO0jpZZ7Ur2IAbqRnIKutyeneNDv/+9//tk91H/+U//+f/6v/9r37zn/ym3Za57Lu8sVW2lawwopYj6yqfpGxS+O1vPXr/j//DV3otazU9rjJkzTqnr986/Y6kfsp92XFzKlOZVlNvuZjKlIxCZEoWVNCA7D11ggj18uKjX//13/jSlz+z210Ie5szq1ApCmTabD6NRvZ13nEfdCHuEVBf0wSooZpWEyZUUMlCzC7oVbPCpMAR5r4QFTabVUINhdTGdq7BOkMY0wGMbrhFzagbA/cK0mUAlHIjKlqwo7Obl1qt7cQGwYIGeGwLyMoDqIhb1bk3cPUjB1SzCaawrHoEaRWYhDCtTCnvnxw/eOchD+QVzfXMk2qFHW2/Hg6rYUrTHhuhQlSg0DkDJ8VewOFeHo6ytdNX5N4bH+vdK8BmcFfKSDtSroCDYFSMwB48uH8n9KiYYe78LNVQiNkw01CtljL7FIFcTKGclsWWEWOPy7UJ3zK/ix7vOk8z6K5OG44XiTREJAnPgFIKzAQpSfJoln0uFb5+bV7pSc0pDiFgEs+oERYdhW5OvQtr5v/fn2WUF+8bpoRoeDqaWo1A6E/wdeqNHGGQZuMAI4N5TAHEi7AYG7ct03FegjSOxsuMtOMLgxpoIITS1BLhxjAh9TKjiP9elAouR7BR3eAxOqKh+FDbYKaTVlXrcxdTZYJEYltt3bi1btIAApLMV0zFDfSBDbqcq2os72sgQXX2sm9Bpqhq12WaUaRWVdWckz8otZSiNackSa7vTAO9/chIo2QEZ5JREcet9BVFAb8HXLPMgW+sn2jlsSfOlm/qDRW2iJjbVgThcBl6xK9SGKtnyOD1sRUJcWTc09ureDOYgmEVGyYzhiWp+XeYRm1SFQbLKUYVNAlDNNPQtgZwRoO5ooaNnCVUrSoi4YqlBkP1gVnzMtUoBKMSrT85fVD42hJrD0mFgUgRLQPJ921uqmrZOV9hI2iI6K055zatoVsJBHgmSCTiCVd1BnOkZCdBmmpNuXPKGUxLyaVWtVm1uKtg3/dVp5T7tNqSMpVKYVGaVko1lbt3XlCtqgaRUrEeNiRLnZOIqWbJ++OUcscyZ2RfpZCkhyXpEpCKwpCOR4oM1TIU6A0raFasNfUovcigwymG0+4Ifuv9b/7523/0hS9/+Ve/+qv/p3/5f/7sW29+5e9/6dlh7pL0+nwto6kNOHaa6jA8uTr/xjfef/e9b7/34cVXN2ueDHxSbJ7kpFwU+bM6vK/c1IJsKsNudyFdNsi+HAQZgEx91UJkIixryDlnoujF+Ye/+iu/8nNf/eJut5N+baWAxbS3KakRxefXyJZRA28k3C6u9Y5uWmWGaqY0Nalut09RsdmoBlRFJd3ZqhIVrE7cp5U2Zy2ONiP0Pf4fi142YMj27AHWVNrR6YKgmwpLQFuAtYiElceDlL0YXV6nDR6V1iJgKAdbqR1rN+ARGgqoiIpYOLpqZmGFZk2PHj5+/N7jbtPbwawiQVpLT0yGAfvNMA6DT7tFlQKp+sl5f95vxiqjbPKtV3TeDhc5F9RJcQCvILPoTnGM3RUYYQfjERghky9wnIHZtPg+QliF1qKTOmVMFSiSsjAJk3sVLPQUUyvQ1Ahufk1dkwMg3egt/1d/4kH1e9AClWVJ7p7L+BtkkG1JpP/c0jW05iRa8PZ6IXlVb3JFPJyZnzTeeAsEkej51sNPdDWijD1YArlmZPvwDQCa7X6QdUOjOQsk5xTWNNd6lp/YmeNHyYJfjiU93HAw9bbPjcSDcW1mUNDX9nkFCAYkmBIQRGu2S9oMnxVhxyVN7uqopDVxgDRX1fbvjBor56xu++GCJoSoW8NtL/w1p0nJMBuJubsZwJQSgC73bNYiXvT61mEP6RnJOzlrF5QQZduzEZ7axvD5iIhBNopTu76etooWoaPydbnSairwO+If8poN3X42MIskKV7Ili/4916Lk6/LRpEguakx0bkCKfvzT21Uhmgw1ECVVrc2y//rW++/sFZ1GrgIm1jOk7EtPQIJSob8xCDfV4XBLKUkOavWuL9WrxktAHi960u8qDYL53dTLGO5UDnUZgBSIY3pFswwfx6jJAo0wjCXWURyK6XN3xXhQjWmwIea1RhgVChMBCxqKAXiRaqYFFMVySJZi5qhFE1dNhZYrzqnnAwb04lJtHZJMM3FzCA0dcBNrYZrG0BVXXW9SK7FjlMhbXf4rsiU5TZ02w+nq+GM3A6nG9UOOCmUkrQ/TbKxvAV78hawsse7x9//3kePnn+wvb/9L/7Z73y8u/i//qv/yy/85s/8rd/4uxdPn9/J6DglGXtUsUMuZXMrP3nv3fN//fv7p4/3ku+e3b/bz5v5+GyLRExnd//sGR4yD1MRRRk1o8+r08Ozsav6wqv3L5+M0/kovdjYkWYovkCq6/I8HQ6Hy1/79V/9xZ//6tX4XNHXCQkZzBQQPVWsJiuGHJ7qzF5PgXOU+3H0NewHfD7gqVNVqTQthiJCYGrj12qYoVVRgFngMIte591YFaCmTnO2ZRKPIG6TUeW2ZoohjnBoJAZsERspQkfsHF91U3u6m0cTyaJRbv0JF4FD2WRjZtEklir5kzSTKSaXc0chJjx699G8L+thqKMCgkPkJSpcvGWKWsIZWFNWpox5fXKrfOWr4+WhT0Penkq5pZfAOKeabMoYDaPiKHKEjcIZOAJFMUNn2KSwAt8IgcrklBGBFlFNgvBN8jJYzGpAC83vz/taiX7UFGQ8RJGeowNWNLjOo1d8tbGbbnxBhNCI7T7+zAE2LLHPotdR1YaiCtgyYTSxkJTaX9CaBMe99v1U+G0LKs0SmZbY7FErOktj7Gy+pgvRSzYsKS8MDm8uYIlCzSdu0SvHbFstrBaXbHDdsCkhEHeRUefL+AY1NjcvH/MqgOzTAA+y3jwDEHj77poXIyChqaFXgeItjOdTlbZ1wDlLuHHvHBm9IW61dsiZU6KIqroJYq21lZ6RLP2JqDUW7sGr3Gs+o48/G+weehz1XjLuAK+f3AX9WLYGoz0gfmgT8oIlYMEVDE2zbgASZTnT8CPkhiFWfeCvgeHc1L3FrbEw1ncgF6QkwiSGi2AYPgelyq01vAhyXNrH+26hItdwCOAZXkgvh83fFKJmjM9CiloNrzSKqjlyUKpmZleZuwyMvgvSdyZpUNaEDd13WVIYtrsViLB5RTUMvFVlwE8Itb1zWdayOpRDIxIAqqnqXCdSck6d5GqmqinlohWlAMgpBbhgcba0FCOytEF3u50p51qKV88iQkotimQCVXMbUWNSLZKyk8bNvNiSGFGkZr+jhAOSVlXVIFmhJ5vP/OEf/scvvHV7e6KPP/wx+CjnNE7W95vcn/an9wv73ZOrZ4ePJk46yBUudnqYUp1kvveJ25Lzf/jT31/f2/zX/4d//uqL2/2z919cSa9jj5Jx2JQqeb/ZlKfvPd3/9/9udfHRq5tbms4uythLOelrLnicbv/13dOPBUN9fvfszmGL6cPzepikiAxAlr7fSD/VpAQl91SoqVJykvHqgqn+9u/81he/8NndbmcmkhB50b2spMB6c6rfnDnRzUUQbgFw1YLHPZ/5qCkqCCShKmjVrJQyApqzAMWc1CmzwEjn3zeBBcrN7Cs0M/ElgO2xb4+lF9V0gMhxPmuTCQBLKjUwTrLTqGIKEqALm7wyVm1Edg4AU5ZA2AKZAFUdE7JCilkBCppg3KZc9/bwBw9zyTrCZ9yqhiK+spAF6GETeDQmKnI35ILu1jzn8UKmkxVX08W+rx0lqUA02dH0UDFBCrE3nYiD2gw5CkY3w1KBgbO60MiKqSpmYEpupCMwgwhy7nPnPdt1W4bABT34WfxRC8f6hY6BBtBHEFyQ+3h6PVC2GXD8hOSOQDVVVYegYQ2jbSNA8zWFDfWLv1zuikiD/RCdmQ/WFgTT4kzEG1rms0sY8DCs7jhlof8VekHdDgkjqQDIObd23g2b3EqHaO6FCizGwg2/vG6LW8W3nBzGIh7f8e4diIU9GNwHDwShWq/7tUCgCerSdlsDmuKbEptiBQBpgljcSHNlpSS/yGpKQJiaeIspZVJVq6pO0TyFdSXbdfYLrsGbUJ9cklKruuja54Wq6h8gyhifgbbJTrPciF5QrzXiETJaX8gYgsPC9YVodMB4Nn1DVZDIzMwHsWiWZh6Nwozn2qST0W3HrzRAsiBGVBIkNW8e/UU0Hgk3OLtGzMHkLsGIUUDjEHgd6dOKGFR71RPIcbT8S61LuvupQZwk4Y5pAcC41ZOPn6lVYUoRieFZI6+1Z9KLhSaQJRCmM4HnL4fMn3G5foA1NllFPXsTzKb4IINQdxRHbHMCMpOPVBolMSzVbsAA7oXeWmNJCKGq9qtcSoH3NJoUJaderYAQ6ySbk9MBuud2Y0+2zY+gWk2SBQS6BM2rQasOq80X3vqly93+9PT1O/e2l7vje+/96Onjj5+fP0q3Hv7Df/bbp/dO7/UP9FH9/qPvbDbb11775HB3NdzfdKf9Fa62D7a/+ODnX9gKy96efXg/z2u9TDoPUrKWPk+383x4/nz/b/6bl66eDKcvvV3mgY9ynqba3Tf7oW6+rvvvP3mY0qneSqPpPI7DWZ9Pht2TC+317PTuxe5wNV1tTjflakYx0y5nrbVcXO5effHeb/2DX7v74PT55XmSTCToRJBMtGpIphMwE4mSKAnsWMXK4m3RLrobQPpTbAZUeCuDCipYKIVQT7cano2AFA+0RAVqW3O0lLzmsy2izbccP2M7VNH4NttEA0V9M4AInZGBKHJjmiySDM0XwXsAbzSk+QF7iWxqSAITZkRrKGRbLqniNYOZmk0w8T1JMO1Wm/Mnu49+9KTPve1hQzRmVFoBC2wCVuARWPlimNSNCZpe1rTVcfdv/lhLhXTyVs/VXZ0AFauWZtERmCATdYLtgRJzXx58zerMkHk5hq9ENRqsGmtKCJ8hV3pqpQgQumonh1obogX66Ah1NaWy2QqgJTtr/V7zNrjBI47FdCEaUtVoEhJzjR12bLnbE240GbQFN1U3CqmNohPZ14NDgyvip68Dig/z/O4328klphAu0QRQPV7EEW7x0xwLiR69kZ3dZwQI+DEil0e+SLI3RBHmq+yXKOfbP3zpjZerpgCqqSBYTV7BqDkE7fu2brxtRz7blvCY//FmHLXWDJHCWss0z7nLdC5j+FHkaBZVpSmSAG/Vkg8dI2ILBEL6rhhzQxKnvLmvllBqVVxvhYI0JMA/99IO+kzfe0rVWun4umMa/s4JYhmBREEV08hmnSJLJ+eImnMw2CShBJmEWpWSPCFK8nmF0tN4Sy2tRiS9GIMJwSA4NT0ivF73EZt4DeTfK54ahfAFmwii+/X5a8HIwQl/GTrtzYFhVJFkBrEK0CKDQZgcgmHyRWyibXtMrSVLJqSUorVIyikJBI1vGJVulGfmtLXr08jgwqmk5JWW1Vj9F09aUArNl8u1H7SF2iYSOjrHgV3NnRgupMEkJAlWK76vOWprCRqsWVFFSp0CZky5V/d40SrST/OURFLOpmpWJZuqmGqiSPK/9F/hhZgmyaaGlEqtYLJae1mXo73x+uu7/XG/Pz599v533/nRxcX44ouffOMLr2xfOLn14K6cZBvk869/+cu3v/zo2WM51VfffHnsq66EtznogePIi6fbPPa5bDBusc/p0GOSMq/yri/lw3/9/3qwf7574d5Zvz/boVyNohW5e3cavlnT7U++8uYlPto93p3evTqcay/bfjuw319BND/fX6R96bf9tJ/yioJUduXi+eXJSfqNX//Vn/2ZL6qN4/5AZlcbmlVDBiuDkZpj6mliVXz7jG/puEaGYDCfF9TokiIjskmDNeWZ0e8W0+rsDkDNqpn6YsBIlzRfLOKwVCBebE8sAQtaBRktuAYo1b6JtFrD7YFEePYxoENxg6A4Ql7fV6vBpI4D7KczCkQfBtMIJjLDlzoji+ttmw4e0JT6Dx6+ezg/DmeragqjFSQTq5RsmMDOdCB68OipnCP1FqezeiyJ9vSjnHsdTjl2cim2N9RqajYDM+AboSZYEZuASTGBpuAMFueak2ZWCFd9qQgSSBG1DCN01koQWud4RGnR/IuIJKs1rpT7QsRYjVbrIhYCfMgOf07DpscCzfXHttSaWm9tIQxinqY555RTxHfzIxKDTJOGR0RSElJya0QM7mvv8g9bIM3WF3oUEripamOMRevrb129bwM0bIbgW9pb+vCCgCS1mnqX2jZx+FmvcMJt4M2mSEKImwYTzWBsyY2+TYIRGUVNg+LrA63qEZLqyqsk0IZq+ibCuH7RzfkGGK84g2erBiLlFNAvRUSG1SrgbSEUtWrViRTJ0j6jtFtlJmYGcRO2JsKJDifm6KhahBJzWTh121k3Ys6Pdoy9+Wt6Y+cDW2vDAUTP1CDPVrPHZWugSbu4S1K31u2br+zwVq6B8DTVUi01Sruqtk0elrOPXQPeafWTX4QgTANu1mlB/5OWodVb24DcoOa1oDReSFwmbwWccgJR789hQiavA6zlfvEhfM2OMTR0bhlz+OxAfG13iryeJfuHzTkpkvl0mQBQqt9iWRh55psheKMQ8JGO+ughZUm+46uqOnEmvsGxQkX06sT1PYNds819VK7wNRwUQkVNrSJs6Hxa5ysrzTvsYE6q1oZyirfFWURrybmq5lImERFZlTIlUpiicAClbbMGIcxaNUlXTSX3WkHlaDXnvBsnyvrBC/fG/Y8Pl1ef+/Rb1m/OXrh1+8FZMYhAVvNB7XBMm7t3P9o/eefhR/ffONOkwzhRd4Odb+y4Loc7Q+nrZV/HDQ49iuSrs47jsyf50dvPP/Hm+a2Tj7/9N8rule39q/nygPzDUvpbm1PuteBKSe7PV2dY6dV4ud/ttDdWZIVarlq7Taf7snv2PBf5ys986Rd/8Wfu3FlfHS61VpGOaqSqjUydqkIlur2GwZLSRCKCMP9yzxjf0VgYo0AvfloVJgaraq7119hNK+6oo77BmRG2GqsO5komNuzGqRge4G8SgdoxjsLazOjPPtzsOCrxCsSGqyj9A2L2mr5Bm1zCnXvKWTgfiZt8qfrmoGAimcT+ZKPXi2Gbpjo+/vDHakdMvZuC+yDbZmMHdMCKUoEimEBAWMYZr8p4T441i6S+TH03nHbpBXmeS6009jPLlUJpZnZUKcIKzrRJaAUyUYthMnNuNmDFUNQqrWromw1WRCCSAS3KAJvdYz8ePFN/qFsHFgNZU10mWAiQD2FnHDLa6MgCuq5WkVL4ZhBgkHA0q1opCtRr0ygzSRKmQoC1yireFUAIRE1jFmEwJTLFVL1ltgUVAapqygkWgmYLFRoFUNWcMyhWNQWpVRkR9fpEOSPJU4sBWgoJpuT5TjSkOE6qT5JMYGoxS4xj07ACOP9anIHqVaNbtjnmgobAx/mjQDRJuD4tl1sAgehCADOfHzdkFFCtCDPiIHd5ZYlG2s0pm6kVl91o6OvRsGYhtOGfFEjUsFGhAPAarsGXvL6nCMPkgDrRbL8ILoLN2HXlH8ahJza01Ck2cXWcVI9lciVxZYJ3bLEKWkLQ5aW5AARqVFT0stpxyzIXZw9ISO3inNDX+Tr06uY5ZlqKEFWh6vaqJGlUTzsNcrCiVWJ+4fhwjYxnen0AAKuQRpOSkB4hUcJMxuNdXFAS4vHJivsNiThVW8Q9Q7z3F5GcUgSs5vXqtpUgkvi0zAsLEWMWlrZzxksPhT8ycSqqamp2MWZwh944SIw9l3odCiQqIy7jKmsYvttZpxihJyw/o7EMhiCyc6Td5Ua1RmpfUWAQVVMdhU4XAxgFYGAziALLEf6ErK5MTDkjWUkiK2jaXc0vvfL6f/nPfupks316dTx2x+60k9OMDWToZAtsoav64it3j3l6On58X3Cbc18v+nKB+bzHfl3KOpdtnjayy2XqRNc27p//yf5Otnl6AR/YCeaL8zPIKp3M7E8Mu+nJ4eMp2+kG2ayugauTrZEoEE2osAm5kzSk3eMLOern3/rML3zx5144vX+Ydue7PUFATGeKGgjpzSYxiHTw4Q6VzBpQYhYmmBhQS3PpcbsVqIj7WbgjXZN4qJIqVLXirZavns/ZUX1F7Pw2wiSpakEUzTHM8YLMavBp2xoXoIGYwOIYsSCSpkHl8ZGM1uqkZRGB1YokBfTyzgUesKxholVL1SCgSAayk2DF6Ls0zJJqgiZJedYEE0mdKoQZlHmSRx89ZVJFoSbs0W3yfDWlXsqsKWfUWgX9IZe+mJCKl+7f/dTxonu6r5sexVI6ppdfybapO80qKNAC0WTF6gTMqqVKpVQmVvCoOgNFWJBqncs8l5xBp1yGiKtaVdANdYyQ7Pbbar6cBwbnQBNgvqasee0DSA43wpjGqhVTODpFh2sXSJh0U3wDnFclFDhNRJH7LiNmuh5bnHyEKNajf1oA5xj44Vqx5ElliXfL3/hKL81JDFZNwwNTfdLMampqEAO04XJRZEd89ykGDRYoSG0OVqq1luJGgLnLDmrGYFUVMT30Ika4UEnjKlpzyGiVwjWJus0s26eA2eKWvAT0JVcRjEExSZqa7zOXKIiocNwUBmUSUSBFU+UvJBazhOVNxPBaq2lVETanYUgTqwTEKjFF9+832DK3bDVEXAdtuHFT7cQfv+MwqtPRYAifNoms33Y6GBQVTevj8GgQvTxVe1hhStE+kiknqlvkIOfsqYVgztmXawWRIWxJFAamm3X8kuXJsBNxhY1FEvVC3KXP/tSYUiAivnGhyWT9xgbqXF0FfuO3I4JV6+aXmwpYrTV+S3MrO3BHAABdzUlEQVRCszgwrpdW1VqLj4n9sy/ECBKllFprztmqIZ6tWEICczrNMkIC2nkSi50ofqF9NhKFUUMfrH0kVZdRJdU4Q/6u0PoYbV6+IkSYjrmwUBhzkuvxXnFuR3Y2UWuVzdQUJeA4L5iaGM2WHsD8Cb32t5KUh6oZ0gukzDDg+HyXbw1pu+EGWIsNZmvjCW1tshFsMWz7OzrK/snx8sNVOoiNL6zsNF+dyXFVxjPZbYQ5HXKRx4/++u3/+fc+/EF/enuby/bB2XYt5enu2Z2zdL7fMetcUE1ytQ3WFf2MPCPN6zUnYFL2kgcZd+O033/q9U/97Z/9pVfuvFwudHc+EuhkBZhqAUyLgtXvkhDOew8XeU6t8a1qVSRRciJckmtqxevIa6Kft8AtIJjBjaGTBg6lxVBJEkrx7rZW82VmBNWNt3W54iBzhlnIwxgVW6jsImZ4FPfHydcGagBCIiISTFGXMxQPmASdLobFzhiWBQalabZokRKYYAJ0LoWWlMVyrQITSb1g5WGoW/UfPX12vh+701uQBGFKSakJuah28yBA2WGVMQ5TP9FEu+3mzdMHdz4cy0FRSs1DL/16fTcfs85e09KKWTEUk0rW5IRntaIoZBEppCoVVpg1hYVfAR3eN99V6x2RitK0UX/CCSdCEA1wlnurfmGOwhIQyQu/qa2sdbTVXFjqj6SrZJIv3HMjPq/iDCSyi1ha2rHITeo4yaLrjOlrY+s46SZW2ysgKTTbHsyC5uNLhKpKEgYj10jXHiFYq+JJZQlBfmHMxa90kwcXYhIEqxZnwkCjJIvmxGs3xnzCE1OtanBDREGcUAd1/bxq5BMAqNd8hgh07aQDHsIcTUQUGdeVJhqGLHHxWzy9NuiKTBZOV6qqKjkmBim3OxdBLa66ZDGNylQgWcRa62M3ytpWPfjqJEd2gsqEBF4vuXI+EtuGvlZ7xNiK3repIS2E9yje3JsP6jzHhYKFwMQFNxhbaFG7tmF8u5aNoMQsqW2+ckI2vYpp5daSfuIKhzGXLmJ5eiFkWIBwf1BCUK6mge0r1LSNDxLBAEkQeaXJ6xk0+MDm6fWIow1+mqRVXmYxkZf25RjXLqYoFEkwcyDBaq0S3C0wZsMBLNrCwg7cOY5/SnlhRDZn9bgg7e2isQ+vfen80tRWsgK63KnmTadxIyhu5AMsljVRuQaXkmEonsTZD/ChvJYCYZKO0q5LnHABEtD2HUFUc4BERpG+Vkl5rakW0dxl7RVZ0QEdrDMMsLXkW9Lb7laaTrbs+34o+7NeTu1i2x1PcHWvPw5lfPc73/jmX77z+c+8hPyjj78v5SIfDo/G5yf33vzkW2989mvf/proxeffePNHH43j5b6gHzQr04xxRn+UuWKNjNRLuSrnu93t9elv/PJvvvX6F2Xi/tmxHGtCFiG0QCiSVJtwvI1r1EAUcwliW/ykVolU3bzMOwkJhlLTbQPu+ePZkIBp4zmbaW2wDxDohDp5C3S1fdw/f8pCKmK+v6569R/DuxhF3KCeLlECMcNqt2x5XxSXsyw31J9+x3jCINfFLQDFTICsKpBOzIkpK0hSTUAPdjQYMiRZIlc0Krc8//D5lI/r7Yk5+URUskAMRYlSYJgIlbRX7btM1Oe1/slfpulQthmWOZZ6epaGu7ZXnRrNsJLVUCgqZZ4ROxWK88lrnQBlVkIlCQRVq8HoHHJV+CJ2CSDYm0BHEbzxitrbo2V7TEKBJKaBXLbdcGRrCYjk20tNgtEWrYM6scud5ynB4oDlqMccN6EL9xnHLTwRXMDtDA5PXR42CcDcMs+VsdqSj5kPIigyT1MnfaJU74x9oKuKtv3BKWOmbX2giKk6FuiYeXDpLI6UNjmzzzX91yxHrI11QYZnRYMjFxVvS6OyfJKbZ3T5R8+FZqRoy/QRDU2u5yPXP0MCJkt3yPYtbuzgZYCIlFLiZ5b07f9znf8bOUl87omihXCbqibN9hq6sdb9fgUdvd34NrxVNh47GxHZvy8awUja8MbWm0dZlg15pLaA8duvCDhBAma4LkR+4vKBCHvIYByoqghE40hft4CeulqQYyupoqBUEEaGssJM254PP0TJK1UXU8RPa6ymjMNTK5uZFMmYMSPAA204B264uTpg6H9iuBAGacs7WnKiy4LFIlezDebc8rNVIOLDGtJ04ZdGEG4lBxp4QUIW+7C4pF6CBgRNB4P8f9zrDghwxYd2XD6i5wYR0ASmi6XoUtEQgsxs6sZlgTN5uZySL1OGSFKlutEwk8+b/UHyjb/RESKLZCCL9KYZzMakHdFndKV2lT0xAANwYqUrMqR0SzpenXJ/JrtBr06HaTUfT3i4n6aVXdzuD/nq+J2//JvvfOMv3v3OD9+482adxqtHWAMydkMS/XB/Lqt+3ozHPU8fnab+HDqrbEWKYrBUKDN7yevDdr2/2NVafvYXv/SLn/v5U56Oz+Yy+qoOIMf98LAqIkAfzlNW/SL4SUhJ1fzJUjGhwLEQClTV2bNu/3wDAA5ULJ5zA8XXeWt7dtThQNOq4Q9jzvcHGNS8YIRFHcYbqdYPbwBjUcXGSVlgFoGEuCAYD02nrxUGSPLiK+ZZJqbJT7K76ICJyGSS2OIM1QzJwk6kB3rTTgayM0tWxaRjTcAtfFye4pS85eCSKEx61FJTznMtNKFKUaUKFCPkwXF8YTwUVb1AFhTU/OC+cLBLteK8XNCMCitaUYgCFLKACsxmLvxVLYVSRARuq27mEZwpvCuSX2ItABiLCxg0NzQ/d7O2fUcDrGusGaOkG8b/LT2y1c3emP3ELQq5bIvyZOjKb3BumdgIP9IwVu8cBEIPMMsLWrgNG4z6E78qAFwgxKyx3pnR9Ui8y9bvLGZACBQ3ch8ZdGw3qVBJQq/yKGZaSmGjmXnStcggEUkXZUh0fu1qRbdlN+Joa0T0+gNEcFSIaJBgG3U9PnX8qOfEn8yr0fVyMUMP1phHVefOWPRhYHiiAy0tWdWF/OSUqChvmk/Gcm+bOUf8ZjGCsebYiWvtB9Qrd4PCfLXzAmtaaG8jXjtM7zdnAez92vpnC4zLE4pqG4Wb1qoUSMrJq2ZPcQaoVi+DmIDom/WGDrbtPFvuF7Sh7DcOMEhSRWSRKnmzoY4BmBqcJGyFKu4ZCaOi1ZkOA4Qg2/xJ9ofHz4VqaaVlRKp4O4EFeRlGi3koYkwQOFVoOej3N5YWBbpFSddKhdZ+Rk3gI5SwIFWTdvTQNkoB2a0OYU3sFadOxFeJSLxNNZJZEHtoYQ5lXscXp7bFV/3YejxpKbndYjOY04nM37yPuOKB9Ztn6i40jZ3E7Ao+x7MNAsupT5bBDFmL9YYBXNPWhoGyoWwgHNd6ucHzDXabenGW9qfdVV8uhvr8Xj+uC//d//AH05PpFKuvvvnaS+vP/PmffXd+XDeSC/VqOuzPLz/6+Mkn3nhtwvzonQ+607zBiUln0k+qyl45aKpaLz8ax5dffflXfudvv3bnE8ePysWTw8Ki6LquXBWjT8OBZc4U7AqnUvjwvIJCnzdBwAqDUEHfLFdgvpgXKefrI0rloo93o2bT69/CSA9m6mxnMzW3/6HTIglW+DMaTkgxtQlnDs+nKu05BtpcqVX47ZvMII0gY/R1kT7isuj2DSYArSqZIBQmQMyyMRk7sQw3+bHOtFdmcCVdZ4OyJ3uaWMpi2SQTWzzX57hNuSVFFQLJrOL6mAwFjVI4JctVtGou5dNpl5POIzqF6iRl2996ReakkwHON3TGohmW3teACisuQRYBpLAUWtFqoInAy2ehtlt5HeiDWaG6RCDvRSIQtZ6NATyx/bg2SpMPaNrFd3SvqarNWhBb6Bs39Es52CyBbMRM31RlAcYQtgFBcg8m3P8i3wCmYQjlMY5UQlWZRbWht6ZaFTk5vXsZOYe4EBLyyIC5EWY/TQocULB6dxjO+1bDucBbNH/Nlrhg1aw16E4nCLq0t9vu0HWjj1w8QxpAERsZfvJPNLWAw7Wt30NonOJLdvPqtPEyAGFCTl4xNVMps9YBs5Uj4X5l9PIcrnVVieJBbsh+fGyxsJqAoGHacikoaOPagBNMbcFgydYuASo33q//DRl8tfiC/0LHmoO7Zu08tVmF21ff2BvoLxmd8JKzl6vjRdzyb2LwcpWIBUpeG0AQprvt15EM6a+IGK3Gbg6ahYZbRJI7wAW731RjpErCRbFwyxB4iaFLXMaNtxkfRX0yEiMMqARO5bh0G9UmMt6IIHAFr5IaGW/pgM0J9uF1Hb8HN36rBN1J26FyHAQ3suSCnVx38E4CjzgudFWDj+8sHAeWFn4pS31ijCYijaMukpw9K60tcBDUS3z1sZJPf02ATHYpZbMMW5mKdGQP7Q0ZHKhZpRdvgvNpn4fpBLut7W5xt7Xdlle38PwWLtbp6qwf5bn84Bvfevdrf/Ng+PR6yIOcfuN/evadP320LhutZlJQV91pzjvZP9qfPTi7v7n/dPekXz0daZ3YaT4DDpJPp3qFefqd3/pHP/3mz+McV49nKPOmR1FlgYnBUk5azJCFxSJamCzwv4vS4Ri+P8cAKoy+H1ekqPq+X8nup4dqVtDG9hD1YlGWoB9SCp/XqHNJASUtaCeGBtotAiIaRL2irLpMubwpWICU5W8Qbbi1w+NhGIBD6a3TUtDi0JskDRqeGAQqbZ9TzPjNMpmBTOmFvVlvvsV5ADpFT+nAjpYhg8ycL3DRv9BhCPhIsgAqWWYtnSZg1toJJRfdQz67L59AGbsy5A1BHasOp/L6/T5hopodmzRDDRAWUFULUJxZQRSjKQq0xs5MmzUgphlm8KFcwA/+yAAQxeJgRMCadaEPF5OqVq3e2zTQ35X1MZFt+cPakkL9ieYhoiDpCVIbgijMHgKiZ27OB0aIz4pseZ2YRzBokNdRouWbFhuWjjzuqFHEL5jjZTEtW9ovUKuvejZnB3jZ6EbP3rl4gPbO2BpLKyUh6aSe9g7o0cCNhBw6cOqN+ab21miaaTNkaGlxUZ23582d1vwCMFoXZ6FRfeH4Nda+BGwQQfpvdkveC2ubtSvoVacAdJkTlusV/xPsGYfhWyA0R7CvcdG461zuQvNIM1Wt1UC65bc/hM7Qi5wAU1NGVx90p0DJ/I3cGDI7VN/QCrVmu73UEzdxbCJFWlkw+AbbmtccLniV61dQa0ZR105q6lHCmQTBvXK8AtEveIUU1OcmbnTOXfulakoYSq2wwqCDtXqJAUa12YQXsdZy/wLqLmVp5PtEoBVnuMYQFKBp7PmwOKsoGso/99akOFAQRpv+LmsIjZbyKG5oGJQyYChN2R9Ca1Wqw2haNOe0uC4EpUBj9zAIppR8b3FVp+y4jsiNyRDUbvPsL+0IsE0+Ldxy/F35XYtJlrr9bAvs1xV5jbWDgmRdI2Zlk16wIgagBwagVwwyYFzpeCL7wfZdvdik3Vov1rK/tzp+9O7TP/xv/uz2+tEwHi8+3N1/7ZXL3fe/+efv6ZECm8bd2b2Xu6E/TBfTs2lXno77XXfan65Pz87ywKy7qZTd0G0uDh+Ox81v/84/f+1n3/rgyVhG7ft1zeY5px9W82Gu7scMSSJQWZoWRBpUU2u+hOoAshsSICiVRU1US1wOgiJqc0uINa6hBAXX4Q4ApiVmXfT1bQZoXHgq6ZJ0CdaAOYzhd5lOS4QfBy8Cneda9Lp58paKsc08emeYUNxPN0pDE68l3VEztEbI5nkJ2rzyE0w8+5plgxg6ZmJlMsAyrAc3plRZAT3SSX6+uzyvz2WbdKWJ4kouETGxDEuaRWVUribM0PsFr9uhiMokx1xM+6S5f+3F0xfOpomsSeYVMZlNsAKU0GIHB3gGKlyCGglQHdAkixfedJKD02OpQdpxnMNXNALwa0E0CJbQAvgW1zYiikfEVSGeCdrht3b1iNA1Ne5QdYPrm8HTkHnDsYGeoZ2enJITVHltZIVWjaE5Bt94KbZ/bDnAKdoUmkIDxUnicJmzthuLqpYSE1qyamm0KW9HjBALH0c/ZFKL0he8qxJw5UY1Fe/9xMdRi6CTTlv1q50S2yt7nI6pmFxvqYl8S4PREgNNVvOyxGEjaNFwsXTyiQNJLpm//hPsOVVv7qnqvLOAjZaWosX66z4wymMPeN5ZqxMi2II0m6kiDEZj1eK5SHwyoVZRfJ1zYIwt2bqOzZpltfiAdfldP/kRLPIfjFT1TQE1qsNQBzYfFJ8gUJIktosc/LTI39mtla8/W9AJfEzpBahFRckYcTTozz9yy7emjGo2Dp0ZW56md6QWF1+rVcG1XFyE6jxFVUVAb0tJ2AoapzWAy/ebQq2oiSQ6WzwIpdeNskuwATo3NeVsWilcAhwlmZgWFaZQ1kVG9fLFZ9vLhxLQ0WRrhmbe/TZFOGmqtVY2HqPWGDq0jntZtw4Ik4mab/Kgu0rHpSMRY+OQQXoJ62cyyrqoKZPjlAZpGy0JpDYpTESiZFUkZKO0xtjYQTtjBw7iWKUNEI4Dx42MKxzXPN5Kx5Xutnk8lf13v/7d7/7pN4l3Pv/6p/Th+M53Pqh3Xu/K2RffGL7z9uM6HpOmlQxX54cDRm5Uet0/GzNWd09fzH0+mr5wd3t8rpfHy89+9o3f+spvnb7yuR+dj2anKctci4BiIpKqqqRUWSSJlArzdXVp8egDlomV+2vXJeb67mmDVK1RiIcIwidMSkrKXvJVx5d98kTficoFJWv2Fu4e0NJdPDXamoJr2wexNhRTLYZWNzWdSIP07CfgQMTh9391cmtOYm1orVDVKkhejrolDQk6z1k6WFZLap3DGoaMjtope9iKWFN7TQORWVdqHfIp9v+/tt6uSbLruhJbe5+TN7OyqqsbjcYHQRD8FAlRJEVSpKihpNF4wpIdMyNPeMIO+8m/zQ9+dEz4acLhcEgamdJQQ4mi+AFCBEiCJNBoNIHuQnVVVubNc/byw977ZLZmMoJEd3VW5r33nLM/1l577f3N/nS/WC1QQTW6Ey8guCilSumyWN2wtZmqn75sZ9NV34reTGUpMvdZF9NnXtmvUKzZSqEq80pcbFOEaMa9de+f7nHWnY0p3mVkRPdbd0JMtz2crjsInoH8CIxIIdigUhigrsODtKIYfdceVDFsZMKrB0KGxMy8tKSqyYDzXFXdAXuq6m7A+ytViiqaKTSHXBIAzDF07fFXC3CM7gP9biS/rEIDpnMz7QyD4fWcKe3mr5baW2vAtKiAIDpYAgT3CDGSB5DEorruD0lRb0MSWYgfgy5aDgC1J5yubujpqXnA4w+cXkp3j9dbL6UGBgDxVgxXGQTM5/15LVchqCUeGIzQxogV4tYip0nXlMlSeOzs5nI4MlM3DLUHp7c+JXztLCnJrITeJJpe9bjQAAFQSmSiTmkl+yjSEx6TBCnYLDpknSWkIscSnvnVri8cyDyObkq8DExXzIi8cN/2pRYpScxzuWDx3qbw3cjw3S+yEPCRmKAgLzbEOTSAm/AG6gAH2X0hmeSITinODvbYUf2iCEKLtNYAKUWdKqFFSB4UYjBo5mIe9o3E3SCKGPynGRll9OzMpQIRkVLKSARV0XtT8U5Q06JG2t4iBpiqd/OPiDgRrUjme28oQporiFUMbV4/pgIIjXWqI5r0+q7hSHomFYs8NjKBFEWjQDygJJKyTkgRGhdaPdLyMtIYemKQTnqNQsNjUxBYnIkIirAIlVYFk1FRiApRwSRYiCzoEYVMaIuuqzLJdslNxeYENyfYr2R/rv2szt/+y7958eT8G7/9pesP7149wO3T3RIXP/3J688/e/7xj3xi/dVX/ubP/moh9vjX79myyWrCytoOsjRrfbO52mvbTKvHVk9Pn//GH//JvVe/9HC++/7OpCy0aXeOJ2Hd2LzIJIJi3QHlBjFFd+kMBN0vGQPiQ3+6WQHC0Hsa4KeYINmS1FoEzXd1KdEPTFJrlH1z41lAS4qoOfq0clC1GLtCtUiPBncxs+BXRM3SYSwPW33NrRmLeqUPyNGlku3+uTNAWjNEwgKouo5VqBVlUauKFsFEVJGFypKowAJYlFpkDVuAJ+SSOKVMglOgUibIJLgD2UPviKyAalSjJ0yqUtGrKCjN5KQ3TC+27QunV/bhQhakTxu9VH3h3tmnXqham852AxAwaFtC2K1BKSoVMOyflkg2RtzpPVYkXGhMqpaE99kbA/rykFMjc6GPGhKlmPVs9YWbEpercNnbCGs01DkSywxGs0dhMW8AItabGYuWUg+VjRo5bjjwSLS7RWnLXbX4W5SuswO/OBfWoRhMqUHUOVwnASmltKxzelTtdtRgRVQQpBPgEK+5PyKcJwJNu51WX5jZKQYPUKlB4kkfYyFFbInshhGSrG+NcnM6MElc9FD8JM2663w5fKGacVQcnLhCRoDlMUL2tg6aCw5fJANMgOsoSGs9wCUFes6BAiBSVY4+AsiAIAlvkq7hqYT18Ac5oBvhlUhji+RGg7kTa0CLKXsQx/aP3T8QrHpPqoZJRirI5h3GPxaR0cmGSGvhJYZ4HMNN5YOLqSriwI+TswQezUQKIupjm2HWHOuBQGABJBBiMFeu8ZtNkKVMSZtHurGMcyWpWemwnfJnOH4dZDiPHvLgHXh1biAWh+QDgMDMCSASjYH5stZ17Dn/veTtFZX9vGcUoli0Wnem5tGO9ShaIyCLmpJ3OfvGcFQ/uW0ONMRxSZIjsyQPAIrWOoxakxrky0AVV4EGalGaeqe9HiaHFkUxavAnKN3pIgqpzpwFlFSiqq4oK2HVelKx2K5luwZv6f7U5mW/ONPNrbr/27/4i7ursy997jc39+fNL6a/+r//X7t65zc+9cwv32z3f/r+3cX0sZe/Jr9r3/3299quT6cn+9oJM5ia7neX+0dXVc6vbq5Onnv2T/+Xf7dZ3rv/pF2hNdUGgaFArZvrMaOTnega4jcO77hlTzDFI3hGZjwO9oHr4YT7iNTcPIZOcFQJEgoyES2x22OAjWe0xDAqNDYE5cbLlL6vE6NSOFtYNA09Rig8VN6gYnFMFO6H3aoP+EyizSHaMkkADVZFxVVvBRVaDKostBrdEygiKrIAJhbh0jBBlpAT5VqwNiyBU+ikXKGr2RltZ7xtPHVVRU7sql5MbgW6qytb6v50urXf/qZty6axi9XOJRZbNcjqMy8v7q36pnvXKxnMFrRJQNoEziaLTCxT792lxNQAA118z7d8b0EucTpJrJpPslONDkMDyRyeVkpvzR8aGZJgR73Cbp2O8OAAD9zLoGqNGK13i8SS0l1Lzhu5FNaNRAKFRkpxXcbweBilKSoDZsdRjJ3WhiOXPwziCP/kpdZAJCXy8sEMEkitrmylgcVRgicM723D4AI6IyjAs0iL45O16DBPXq4J4dxMZUCoDvY+hzF17r346FwROCsDSroqcXjl5uUT1eQ9xUnLKUp+p8mPYtpj3xzB/x/HLl6jGur54GC/qIijLMxrN6OqC24cP4SDbx9jHD2n9M+1/LQAGL3aZ5YdAeGmRePMt96AoqVk/IU8exIrfNRomDo/MASLCDgugRzCDmR/znFEoQnyPRXsIa2I777hDkaKb9CsgNAGT8G1L8OjxcoFc9xEtJTIFIMaGh2OVNE2+jVzGSRDnzSBR1vl4GZ9XQmiO6XlOHbL5najmbEUL7ZEWCPC7qMeiAYCVAeogkkjpRZkXy9oMXpINIWm4VuliDCURY5ekutp42FzTOYhfTz4AV/Jo+qA2eHngVUAtJ6wP0RQioJqRgTzU8VlGVAgFShiJYIvAYVDn8OUUmFquqpN22nhCvPCbhbsNm9vneG8tu/91X967s7tr7/6m+//cv/v//f/4+Gbb+tGcaXXp/jtz3/iO9/6xYNfvlPsXtGz5TTVRW2Yu+2tGdoMai0LXZTN7v4nf+urv/PH/6aX6clmZ+UOuTAWg1o3hTqtCBKpkITYIkTgA6HM9iLR89N7h5pqtFr4GUsasdOZ7XC0kQ0Co3Z+CLrVl9S5wP7gLJvJBycmN3DuIROK9GTVFpRQ/Us0kRgd5cNQwGuNni51Mbd7tVYLNRam91VRiIkLVpKa/crhfFQUUo1FWMACFDMVKVJElq4iCazAFWWFslZbwVYmp5AT0ap6Jv26l9VupXPFXsgKq9CFNm/pqpiqTB2Lj2P7kXJ9vdJdFb1SzgYUTidnr37KTtWsKWJKMkxJ0ARWBRRUhkRSiUASGmJLaTCSveyUNgaCGD4tzlL8J7tGPMNUAYmqVSKOMu+B9OQiR94OA5EfJwAzIo8eaqjDY462ksxGweqVWl+THkNd6DNPvWLGnPMaAYLqoF1K7LWnsjSHaINSxYMDGlThpHUGedUzNe9RE0mlNZFo+wTh7ITMwvMWgQN/5GB6NIFfv/jAoUNyy4G2mhlcUvABFyfx8+Y3l91W3uWRlhlRz87JdkGf8XqbaQRFLqw/4qu8MuR3McqmeQ6e+venjlJupEAtAbA7oiAD4HY8n9ka6zSkYy/nRjbjXhUSWoCgcJgQPDLC8E7isLnB+ToOuA7X5zcog6iPJFv6ph6oDGMUk0N6MVxZDrGSb+e46APKnrHF4IIOCyWKqEHkgrsZSoT2EPkkZVdIa8fhSl6h19uCbTdEAzPfHX0DiXsHKD6OGsbHmTFM37ig/DdPRiXeSHpp0CGFMHdeL9fiEsI++EGFzUFLeIImCqEeQjRECHK0bXzvBhohGhod+Suhz+ocv7itcXQgoh52xuWLdzx5xylHbd1zPIqIQyYH/RknymopUsnKKXLf2IQqdYIpZFKrTVdc2G6BeYmbBXf3bhs/3P31f/6zL33mzm+++PL24fzad7/38FcPT3RdFFtrP/3RxbMn79856/OG791/Y7V8eX26tJ08fv/h8l6ty2pm1prqat/a7/7RP//mv/5X79zcebw30TVRRRdmaihKtWYqah3qT8D7N1vIj6iK6qK1PX00vQTd2czMOmFZS3MbVOD2bnQkJE/Hw9n/4tiYCppZF8ujGgTIoSYa7M/EIFzsIRrLnIsLQTZeRn50KC0KgFKFFoY0qaZmpO1bVnB859A/UbWK6BHh2t2Pd3/WbDArKguzShaqyoJlEqzABbgEV4YVsBI9VT1VrGErw4TpdP/Mxc0dPD4TqM0CqsgKVmGK3lHv2GKDetf61+ymWRNdL6bTzd1FuUEzLj7y0cUrz7Yr07UaTC3keKLSMi/UFPReeYsRZCP+dKn3iG4F41lAwGzuY/D+qYkikSbUmOgd3GTnr0qMuEmTnlFV2Ck7Eg6ItkCNeIikhYrtMfnUM+MaWJyid2NSd4zBuwGR4reAT2jKWmzEefAHggzWYehO6oldIVm+hrOpkr+QKGQkbRmYAL77kpMShsyLuCam5oK3EgmKm2wGOU1GvpL5+3gOgWz37ocn8Nn4M2LpJB9ZwNuReHHQzkzTe0M0WqZRigQgr671hqDrZv7kWyIB2eHTwjThAHmmH+NBJsFDB4mB12HQwnKOLtqjgGv8Jo/dQCRB8cvBh4vPoyDmG0axKlhnMMlw3tFgUX8WxIGT6fhtNnrJ8U1k22uSqIyiQd1M5zig6NgqYcxjLOfh54ghModc1NGlyFqQR8Xbn6M9KSo67rsyjmO6qNyx4KIuAgCgCwkJYaIaM3wjwo1pE3FJwRz1zNxrdxa1c8ld7fFvtp8xW4lyz0v8USO87q2ZipYioq23gurcuxIjpNQzKpUYli75RT0xxKOSxVFAdHC0HnFm2u60d+ZlCKRodtMzOfFEwJUFB+K9R9KqIUYYuBGzddHH40jNDGkyq0Blh2kpuhBOUics+3Yp24Xu7k3zT/7+H17/y3+/nn+F917+1i/+w5P7131TVotV2Znd6Eldm/TXvnv/q1/97NtvPbLNQkp59u7HLx49eOH8hftXv6i60OXCdra/mrttYW2edbftKNoa9mhWARSDsnsfkPbebaYTMgQSrFF0jdEICinGPUKST8kWjEoZsbefBhsW4wiG9LXg8dnOc2vViz5eai2K7CpTiwQg2OnOtnLDI+LAjADsJqo9lc4hg/eZGV+KBAKppyQqJbSj6TqbEWqo+IzLeBUJbqCKeFkBDE64ZBvSpCcqk2AlmIgVuaScCE7BtfUTcg0907KyhW3Ppel0/Wy5OkErsld0hS3MJvQi1iCzLc+afAV8TvZX0AnbSzNdYHN6stfl+Vc+J+eqDVQ6mVcITqDRpwFyowApJpzg3CQa6QOJA3VDGAdLk2zeuk9jty4EqijQO0SjjOKWLyzlQTQwj1wWfBIEkwMeHYkDh95CUYhIFHRDyAWpWwUoqhRnuKCoSEQNGKEZkAWGDLMjX0HWn+LNkVCEgc6oPCoNfpKjD0gydTiOIw7JcfXyLA/wa3LBbYAuh2BNRqoKpz4diwqlfQsvbpkokV4DDg8Q2YBflvyTzEB69ssm8hTr4tJd+UvqgvhBWwsk+egfRiacSe/glqfaYALU43ZjqcJJOOh0lO4dckS/2hCYOsjfxddJizf5gvmWSVXSmKA3ENfot4Z6j0Mwc2Hs2eLgH2UKsSN7c/zHEWCkKzhcDtMmgbBuhwp1/GLmlwxiV3qU8JhpB4hBE4FrFKWjCUxBoh5PiyxOxVt7HbaXyJJddHLfm+uq1ujVj2qQGzZxvmoE0+KN44N6HmfahtuOAxIXDRKlaoysABAAY9pmibErcLnHwC3N+826NQKHijsiMDlsTg0KgCBDn0Bv4tdcZStOR8y8FCJEbNw0++q7Uz9KozO9HhmzZ9LZ1gT1bMRjFAEK6e3FIqwi4tqUqEABFiqVWECqyJJcGhaysN1KdpPMZ8X+5i/++rVv/58vnX5wZ2Vv/vD79bqu7Zb0ZlvotmCnfW+ffPnlX7zx4HvffvMLX7336P7lOz/ffPkr33jy4SOd+OqrX169OPF8c6Vv32CeV9jsH2y3TReLPfus1juaGaurAUEg1q1IMTYXuYrSFgh0Q2OfS6hCOUnSWwUS1RugPVwex1ylZQSVB1vmdsh5kkmoNr8IdTqXx2TeuqBwUFM8nxkpVlxwb60WVdUWUW7Eq4N8FTY6hFOzByHz3d6sBMdFUr4pzbaISIV3//lXh+8vpLqqKE1NVKXqpKiQpWCCnAhOUNbgqciZ4FRsTZ5ZmeYz3KxwfW77qpf39KL2bcV+UgJWbL9AX6m1Ou33i09j/xtoH3Y917oCFmqXAKzz059YfeolzF1Pq1fFsQIJNLAJK9Qok7BNsE5RxSIZgTBrPicP4iNQO3Ao21rEw4iD6Q4hRqd4npb21ftXRZKLxzRUkrY3aFxhWL0EifTTRob2GYQCbyIdYLCIiFamoKMF40PzyMXxA9RLj4mXN3FxgQR1PYgOhC5lhAJ89M3o1a7opIOMYQQcySvytzMJih9HNpnFXt8fVFhgcZFThN05uIF42hEBUSLX85N0BGf6ycncnSyafbdMg6vO0+lhlFWdDQ5xRTRk0peKrCH1F/mhf1OMf4xQhgF+HDzVsM+HG5dMcIZCmHM7DKGoJR7apk8CA5cYLbHxJGKMuiEapsJQU4Iv5m+M8mRGUQejTTDkIoLhTM87Bxc/dKjiWWqG4/p0dhvkzoRoHbx/KlQYrhvpbul4Q6I2HElj/M8L2wMB944k76Kx1PpxOzmwKxFxBGrU3H2asirQnKPO3ntdLpsFoSafRWaz3eUUMOoXETYRyTrL2xGC6M3KUA7J2IJZvaD/Mc6iAGitoaPW2nvzDdl6L7Xowb7HEvkdwJtx8zoHMcd75ty+xE/SqHBEfd73D3UkI1hHUUkZFocU0Bqg1ZP13lRLqcuoJgJAhyxgHSDRRIs1g0GayMI1kgUQKejWbbbSvYW0rJbT66+/9a3v/vlnXz45aev5qq5ut1qmqZ/e3FyUUq0q1vvthXGx/IM/+eZ//H/+/GdvXbz6hTuvvfnLn//qx7dfuvfG2z/4whe/cO8zp9vV2y/cu4fztq/TR1/9w3mxejKXnS6aTru22PS61QqD7gUh4k+fIc9ONkoXRBFfUSo5sxui4A1gz+46JtH/hjTVHinKIQg97OFMEvK5+0FzRasB4nWH9ogQW+NhNkuCNJp6N5J6f+KTHywZ70+dI6QP9zqykVBn3lo6DQqc6u+0opAdFUQ27FFD8YS4SDFU6II2EVWWYtW8qK8LYAWsISvihDiDrnW92q94vbYnJ7w+Q1svru7qJdrVstgCTUHFvrJP4LatiujLnG+jLWVxg8XOtOl0jkWr9exTz8vdCZeNc4/4skEaZBKG5pWgUkwEC6Kb7eESBaoqC/dyManND4TGyDzLMPWAErgsRHefNA60C8V2ElKyu9XNJsyOFOmPn79TBUQE0OhJiCjJWx6HZQ4/XUWinykrwTZw4DSD7omC9iKqTHaL+DBzsSwk29gfaf9dNkad6G2wTmoO+Dg2ClG7ZQaK+fKcxnt30qLGIFhLXMGEAcz6SGkAPjLb4BGQ59MQgDrCwtCUKHGh1g2pFom8mFypeOWjgascZBQpFgoMamY+flE1Wl09wjCjwHxrQGTIPBwybRz91W1jBKkjjx8QpyML7pF9bHFE4ozEDBnVAJ73q3sxae54fHe4ohMpfv2IUAui0e/jOa+AOeXAs96nLvnIRSGshiR9VIK0Y9l6yPCZZC5JVGGfclopFQKXpsL4rNBaFU1rxyQMOZbh5C91aRMXm4p3OoDSR5AkSbKIL7KuWnpvXkXyL6paMip9KmhTLQhBGxgjTh2X+bT7Rci7c3TEYW9WtQJsPrYos2EmRqLeDWYmhqJi3dUYosE/DodGhBe3w6MhOYdBEaFg5n514EeOiIu3YxFgc1kN89z46U3JCBKCGIQAcMSMKi1SNZbw+FHPN9L9cd4UXdgPfd8EVRX7ecbCHl3fXF3dx9Xm06++0h/+/MMnp7VgWevetr23siywvTWd6iTbqyft8mJ359WvfvEH//Cf7Gf1a7//uw8fXHzuy5/+1fbNN995482rhpNZb08vff7Fb/53/7LdfvnhvJqx2tndua/netplvbXab0y2gi3VFLOhi3QRI1rAigJzuoA/CLJ3M5Xme8isOTw1YJzYURYia8N2iWRuGwIB45ESiNF0wSoVTZzYigdMGdSMlAPD5rgugkZf22GvqceVhDN2GMBHKRFaZe3AFzCJsn48PJuCmPOFJTjrhqJQsyJStCyApWHBmvMzlpQTsRWwgpwAZ8AZeI6V3pzZk1t6dUuuF/3JHduW8vh5fUz5cKUQ21b2hfSFWLXWuZjL6mfAFfkpw5nUra4nrZeiujpZPr+6qZcXp2tBh1atxXpjA2dKE0wCAw3WujSFqGiBBYc87ksK0JkHBuMIOAIMJmVagcGOPGx+j9aVSljKARkYrKMiwmBlH638weda2Gkf3kKSLN4KEalp6NJV693jUw/qY5e4azFD5KzOBVIVaZ1ClhJAhxR1Vp95A2r4JIpEN4KjcOxGWvV2qKhKp3V00zyIYa7WLQJx5UWBKMHiVw0rWpyhrZkcW29UlaKdXUTEXJQIyPmvkHSH3ocLRHyII/Re/PyZanF5GM3pC75mbkWdAG3mFRpvMgi1iAQmvYWyeD24d2MQVb2izZEuS+RDGJglYhRuqHB4gObeHaVokX1vkrlltETFrwepw4ds09N5MlqwM+ZaCJzaDcIrkqVo5wgUSArp41lghJPyCNeqo1JG9iaAqMAU1ouWiN8DN4iMByJBcYI4e5Cejcal0VEUTTwHYEDzLp3IBM0PSbcEAshGUTMrtXj0oUFYdkZVR/Qcm29FO0zdGFTkAINMoLU6SyLCpcgBKPQFi8QfART7PYYPH5FUhKcZsdEr5yI9xdxNAJpKSa/EEpPS6R3nggjMHAjUyQVInXzpgg8YDeUJGsUFl8hDAQxG57AqOIIJhqehNzg6iODmQ6uaBaXUeX2DhOGREhG96jT0fcNiUagC0jpLdMgq1GCEiRXrrM1JR0DXqpMK5+1OV/z2d777XHn8J19/ZWOPLu4///DR2x9ZnzR9Mp2cYf3ArlRWZrPhRCfUF9cf3V9tX/vZ9+89e/7q17/+w+/+HRYP777y4g/femO6p/V8urTrLaxO+PhvfX66+/yjDbayusFqW+rGlq2c7fpqZwu7MZ2BWbE1aYoG7WqB4YDoIKvAHA0GJFQ11FyYXLyNxLL5iwA6qT7AKsrCASTlO5xd50llCGT4Xg8dlMFGAXp3zYdISKKMCBEtBMxa4oVu3EMo3O1IJk2OJntZGjFMXhx0dEarEMY483oUbLkwlmR5T1WLd6AJK3ulCFDrUrgyrgrX1BOxdcMZ9FbhGXELa92e4uo2rm7bh7fwZMUnz8iT6+v7d+b7K7kpfb+QPQC7MW1FTLjarfSJLeSy65vrW3d6W+8268l0v9u9+OIz5/aoXUppFydnbW4TpnqrtL1hD5iiUxpkAgnsISy9R6ENBqAnqTWZk847kiyuBIYWmJlv+iRbQKA4CGMguEvdeTJI/ZNBrdSs2iPKP8ho/VgnCALasPvNxBOKqlIwQrSE1bwIqUU5QjJXs8tCUURUGqyO+G0LYQrVotkHF5oYjOtRD9bo8251VB+HCQMgx1MjvHKVqIByiNk6P983nUKSOuQ1wKNckonnHL0iKxIZTRfhUM0OBna81V85U4oHa+uhE3q4HnWv6QRd8658N9QOaEgm9MIInuBn56iSPV6ee5Xi9tFab6paS03+HrIBN2yxBwGWE/7Cx6d05RGsTfG5PhYEgZKrGeg1YQZ1bggN0dMZ4yQtM0tnaR2Su6iUhG9z4xAj2QQxbtMdRxbIfWsgi5pM5nGW2eEijkfCb3Ioe/sKDGEZcz6uaoaAHsBJtPwRRinSelfrpZTohM6ML7I3CEj1+T+03lCKqupgTh02hIcqGhk7vdbkVRtJcp9PLx7DoOIIhvwLjVVL1CCCzDXYOgIRhHJk9JO4cTUYsl7p7OloIckLPOoAhOhwv8kfG0fN3GJ7q1603pPRSzggNQ3mvwKdKBEnifn3lCpGqJLO/meDVHW+KCphsFJVrTXpysYC3FzPf/2fv333s9P6pdOPvfTSy3c+8qt3fnXz4NfvX1yhymYP2U1a2+nqmX3bEay23j7aXLXt1778tZ//6B/PzhcPfv3B2enm5PnV2x+8sV082uzmtqirlbSzcvcj9/6bf/svX/rcJ967mXb1fIezHc52OGn1dMtV0yXmIo2cITNsBuamLaFy84fvSEEzdKALjsfLWJ53D7mTuOG8GQsqF6Oaf4iRzKl/BAiTOLJa9QCV5JoDqNUdeVgJLyiVop0uJBjuOyMoBMMEGRR6tQhWtQAo3ozjam80cwzbFzacj59GiCpcU98Jz8FlFEUVcdnnQlQUckGrkBWwEqxpK8MKulacyTTtbsnVGS5v4/KcF7d5dSqX9/Tqx7/43nT59qqeYE/uyb2ha597aQVL49K4kFuTSr98tOgPdLHty6ub7adeunV3tZ13F5VtL/bk1pnpzL3qmaIBnWIKo7UuRWRBm1XUu4GtQwJlHnM6FQh5JRf/PzoO+RABZLN1lJFlpJKHRWLvzWJwgRRRY6h2FMns4GAuBiwVPtMAEfNpeVWj0lMl4axx+sNYVBdZMEdWk60zeMxuYwQ6ZtNh6AGkaLMfc4qnRxaKvh7gOUhoBrJLdCYF0piAD48u/9Bt5BiK98fFF3slEC4x74ckwFX/KDmAOV69ZTbxSeogRJ8lJFmmo6brZjYGQ/gDR60l4lC/XwmzSNBlwkJNItT/4yEAQRNiGrqnDmBmT46eoGTBL42jgSiBS6UAFizJwkVrpLb5uR7lOOR47OAd2T7IsI3VE6GgDANsAWB48t7ZYfThEPFIclO6CXeNgUhmBUxdyUg0jSE3M0oxiIT5sIHi8syLagyeV8aGKhKUKI5SthdcEj6JZxFtHCMYNZeojPZ5C5kbRDyp6vs4HlnWYsDuNisBGn8kHP8/nqhm8zGOwrXw+wdSQ6TF4t11yuDbw9NaOfC3It71QxJuNpaNvvlzDoLBZPxKXMshiD1kyZknj02WtxOoDqMlxs8S44GC3goBMLvEKVH0yR3QLSYNOyvOIM2sEE3rhOyUJ6lQaybFfuerX/zR/X94gvnFM7zxwTvl8VsXv/wRtg+er9PtZ/hbr+gHb87X71wupMqimW7KGgssvv/m9z/1yisn6zt//eDPbPdEl3U13b730ZOP/9b5L97bbnn7+c9+5Bv/8qur588eXuus61nXmzbtMN3IYivTFotZl9phe2Ojj8/hHmjkntKA5gOhLTo2YsEJmoj/fEQ2lAxkecyXCHsXIczADZ1qEZLBET8am1uNgBclbdHhXc4uISAMHaODpk0ySXzdxX1pTnAS0mDWg+Tlq5x5VFhUJVCyjlOgoClQoQALBIT39kjy7DJXXsAqZCFcmFVggq6rnIFr4cpOsFlhs5arU16e6dWtfrHGk1tys3n3vl4LSc4mnbajNkgT21MrdQ0sOlZm13tUrs+5k/deevmLv/eVzz2eL86lVMqVVptOd6w2U3a0SooVLVoVk8IU1XQPoEA6TV0MVWSmw25pqN1zjaEm3j+XRiOaUaJeYM4NGmoqKQrtb4I51N3QvbkfkCy/HmQhhpGUDLRzkzxVs6+9dc/coz7s9QIPxJIRHaYgDOGhMuE2JgyDf2dIfGPA4h7H+cmNgrQx1Z4PNhemLoNPOG8tvy+3miErHWaeFzpBKCZ9ucXyOnlUZ/0+wgzkBWczWFrJg1uPtnQRiAY9NdNThq4QRM0aydaaQ3G+dOEjvdZbIgLo1gVSVMo4LfALkrSQsfLZP5QlOO/3L+q5URZtCBHrHU6Yghu+wfxy9ZLIdyUuKeYf/VdfljMBDy54vJx83wdlFx6BhdYFxAdj5m15speJNwDP8AGvBribTTlot1xBDBzeIjNF+CIOAlfgsl5aJ0cJ3T9GQohLguMj0o867dxjZEu2NOsiQljvMdYitSWQzsMPktMoYOxm3cx1wVIPLSssg842thLHnXtwx2xK0rStfvjMIzOFHQfG3kUYZWR37wGVH+3cqPv7mXA77c9y1IYdPvbH6gSUCELSZUQgmHYh7byKaAYiekAa4NFqdlKZUClOvYjn6hqHKWRLEqpmFFqzHaAo6+ItWta5rJOVBnm4OrHt1fL1139aL//xxZXdPblb5epywyb2pT84mx/M//h3j+YPT5dndcZ2v93T+Mv33lqvz5bPFI15tHjz7Qu7ffLiq+tfvX/zmS98Znl3/cF2Mdfzja2ftNVczzd2eoPTGy53WNgNsAP2kL1gDxjEtM2GjtpS+QICSIsSDLMjzh8nkQLCw6RE6zjoDIujczbQHn/y47znY823WkJPiLeox6dhuAmAZj116pk+PsgAROxwYOQvokprHcaOFoIEaa6j6h9IJX0ervPORBFd21YZ5PUKrUDpHVJES8UkrJSlyIliTaxMz8TWxAlP8eSWXN22i9t6ecsuzuXimXJ1u2zmXz968OOHq+sVNuhbk1m0C/cmTW3utoSeKJbKarLUusZJWdjyyWefufnI4hFps+mknE0u2kKmZ2/WalvKCTCj7zoqdVmtQRdqs8IqYEQTrQJTQWdzxEFgIvGvgw8aO5xeYhoPPI1heN/wjQNqhEIjcHXoGhbsEzdp/jm++scf58GShDkf5ysIAQzNXonhOFCRUOyDDssoGk0TmeYEk0/CRrPUVNhh05L1s5BljkKpqqI6MZcR+nnWTxdOY3x12N+hsSkanR7BJztI+D31EvGAjpmyZyyfHnoIB4zDEhYv9PkiTnW4KcOAAI0zAsquaGQBX7JjyqeXw0E+I4TdXOA5cuWgJsUW8McZd2KQLCMz08gDbTqK4hj8qlF9LNGbNKTxogXfwdB8d+SaPJiUrAhEzUnFOwtD6Juh4ulvMK9ehKmIUDoQC/OLpXOSgAwqnTOm6TQj0404KnfnYSWish60lEwmBvUvNpl3WXs7rCNs6UNytRhtY2N9BxQTgEwGf3BBjFx6h5MjEvbvjH0riCqNguaohtBL//mMQ18oqWHOyDv+/vGhSF9dfDApCPh4xHTYMqImEqkuiKwrHMKWML2h4flUmJUhVX63l48jsCYEAycN/50Li9jYphAf0eghQXyvCCgF8Gb3rlItSLZQiLETXVCdN1C1QtGaVRSzPklR6tvvvH66Ku8/vvjua391+7npzp2X7t379brp9YMnCvzN39389ES/+ZVbf/Sn9Tt/dnH59lTPVnPfVcXcNpeXF3ICnSYoVnXSXfvJz96/vz374//p37zw2Rffb6udrj/s68u+vNLTa1vf4OSGy1nXN7bEzmQrMgv3RANmSBc1dTaUzYQ1oKtayegRgQ0Y2dwfu7KtdwQ4EhX7JPG23FdpfCOJHfG3H/7snwuVnTzuCJUDl5lI5iC7UaUXCyb92Fd56CLMHvlxRk4kLeCsYUATMtTDnGlmRF09l3YJDkFxEhNNSBUWFkoRTsQCMklZiazVVsQa07Kd8maNq1u4OsfVHbm6zQ9v8UqvWntvXlzW64c2tYVuDHtTU9samskOXJlOpqu6nwQrkQ0FZbpz+vjvf/T4Y39753O/d2OFsDPDTlcddbN+RjZSTsRm6dve92bSXeNlxKnqPPYIghTZjpdha1IQ/Uw9fXJEosYo2Vp7/IpjZlCJSAeSIhnZVOYrEE/56cV1+3OItfJMV1VX7U9LgAMNdbT8+rVHLJ/azhIeP7yGG1rHp13fJyB3w4gvUqhAipZu2c/m290vwdSUisBM2Ifvh6syuZ3j6HIbsb/foCU/YfQ5hfBAvOGgWo/BEwJCfc39aByeDAGQUkUjHioi6umCkT7jc+SvAzlXEdSgUTSDZMFmYKojDBur71tjJB++2gH3ZczgRF+EGfU1os+zM+Z834iqh9/J24xDOkJxupIU0kPTvNHY6bAjPIzqV9LmgEBL1JHfohJpuSqC0eC2wxyDsRRP1eCqBxAyzszAWJEzjDl0NG3kfInxDkPmNxNYfFg8HU9KomszoAvkZR/L1Xg+kayKdK4QwSCmAeg0aSiuIK+x67wLjkEaAwMgD11BxzkSIMjFxIguvOcNHg0E00vE2xtwCP6O3HY2JyDDCP+zJu2bKUkztpBHVPCt2Z2+LhmQIvt6CUR5goYcZxnxtfjoL1GDjXpoEFsUMB0gqjsqoGSY1FUnWtNe60Jt32pVNV4+enj94YOfvPv4qiymZ06/8rtff/yzN3d49KWv3Pv+n783zxNWtx9trv7jt65//xt3vvEnJ9/9y3ff/em8uDXtt5u+qVhT68JqAxet7jc2v/DxF//1//o/3vv0c7/eL7Z19cTOr3C2recbO7my5TVObvT0ylZyo9yQW2IL2YFbYIY0ERM2WqN0knuROeT7Y2igl2Asl9FXpNNc887XxY1g1hQPHcVOBvUdlopiQgSDksI0KA5rID6MNNAyDkSI+Fs3sSQPjQNr3jIagdQQqSHggbADZi7JISJAa01VcopimiFIFAgBwNS/21OtjKARVWFncaHbXj2yLlInXchc0ZeYF7qvmCfZn8q+tr1s8OzJM5996VN//dr9aoqtqanNhpnckzvAOBOqrara3PbKq4urCWq3yolyWdppnzc4mVSKirQ9YVK9iYtlKrag3XQf1guJNsSMjTzujPgXIIccHI597n8tbgVGBOVZos+UH9UdpFsVjLyNAUErxtpFJuL22I9y/K7FUaWQrH6Boy2NDi+6KwPFh44BnnfK0RVIADKZFaukroyrqxBwJkhPNg3Fi0U0VY3TPjyihDCbf4iEUQ3WT5Hilx9yYAAGCEi30TJ2H2MJ4j4zZ2A3EKaoTz3x3LgMUPawBIdndshekOkTaOpTeKB+ah2DRvF2vbjcSAoRXXchVRBXdZTMjEsKIAlA1pyiYhn0gRESebkAUTcKz+ZM3sNWkRQTHHGzRGwR2S0FTG0J/16nDmVd08PsoBfBS7lFksrgiKqm7I4g4EpBzI0wl7BQjKF9ApFD0SBYKVFxiUtWSspLAFkhjnw4ygSq0vdNqc5TTUMWlf0QQY6C3vAcHtiy905aKcU1v4zDcPlj8L61Qy7ugaHZCOqYTcGe94pi1PPAaD7JDs5M3T2XPdhohXWzbrX4UJKwozCExLJ7wlFoybyJucsRmzy2ygDzR0jKEUO4c2f2JOCp1lEvkZkR6LWmUG1EgRJaDxnOkIiBkGH4RVQNXjb06zLAVCb4AOxutkddFtj+9ddee+OXP344f8A7i9/65udf/I2XHj26fP2X7yy3eOUT+OI3/9kb//n+g4vv3alLtVt/8Z3tN/jC537/9mX7/vxrfeal524+uKTKft/KtFLienf121//+j//4z/grfKrm8VWn9lhfYXzC55e28lGzy9560pu3cgZ9yvZmtwINsQW2JFbyA7YAlvjDMyANFXHZWPQbOj4y7E9dRkpNT00+iNiHY3dyYzaQ8gi1pG5VuGbc3mHbQlUx8xHSoeuOiGiCvH5zRFQe785SFrvcSKCWnvY6EF6sN4OXxGo4fAyHqz6+EgJ0Q4kCpgiQyIqZQKqKVBNqwY+rTQ0T0UmbleYl9oW3K24XWFbbYMt7MZ0V7GDboFm2EKh2BJNZC99Z9JNDdjTmmHChEkWVetqd6fy/KRgy1ZOp9tbcmX7jZzUYr2qFUJRVLUIJmjL+cl+ktWrh3l3UjXs5li0zEAOL3fXMt6ELCL4iVYpQeVJLk2ApsGfikDZj6rTbx1tjnwBwzoJYWLeBxRCpxVpxzVOPFzKI+BLWu+NpGi4wGB1Bt0pj3+ebbjwk+hAOj2dVdVSDhRZH58p1PEwgjyqEJQ0+lK0dPRQpmZ3BNkfSgkg3QIZdNhcM/F2n+q05dH96VK6rUez9LAtntkZkXzRTBR5uLfEMDN1MOIwwDWNkYDovWv4YK8/iD/hsc4eEYUrdmYQc9kjMhURsZhTMaIcd8weSgclGZmY+35y0W5VV4oYfPboJYmWhoNDEvHJPyWgLM2xjEDqqtK0lGHvLaMzZF1/JND+i3QgRNGNC9WG8b3u6Q6ch4hoXL/SWbiH1N9zNgqyE0wkFbnFH751xqpELWNAvuIn0buvEO4H7jQ9gkyZVpBorWstlk17jiWrim8ZZlDSu2vaDLmYQCk1p4plbEsHpfPshicWSBLyHGEJ1p51a2QpxSQo3NFChiztOoetE5Lc5rDcwwoI7ShspA26uN9yXJyn19FTEW8Fotco4vkjy6xHJA+LKGbcmIsGJzSetizQo1hA76UysE61XF1e/OjN7/3ozb9HnT7E5l/84R/ce/FTH3zw8Nvf/xZu76mr7/zD/N/+ET76+Xvv/eNnri4eoMhKNv/fd/d/+LvPfOJrn/z+X34wd1ndgVGrTsvVycXlB//9v/23v/07X/jgQ7vYnG7qrQ9tfWPrK6635fZlnzY83dbzS7vVt4rrLk8E15CdyCyYiUbbkVvTWaWh9wbutDQVE3SIGRvMRDsiGYi79EVMMECybOzPDIR0RrDos8NCkiAj6gAL04akfckH7/lm0lDiQSa5JJfbd68JQtzliHMrIwtwhypAqTVPKKFeufS0TTL59TNSVCWdrrqVZhgvVdTuyKBAq1g1FP8Du7YCFLYJ86L7bKvdCXaTdduoXVvbdp21X21hyq3tt01ZuYc2wRZtKewARH249mYvFZybXda60WXbTXW961uVzYT1VNcntr+uK53ECvdo6oqSSq2AaouuO4m6AozoquYq1+F+xZ9ECTwvirWOVBiR5cDjV2oLui0Zi0VB7zmunK4xEFbFCU3I2jAiJnYdPoWySNJggApkdj02h8BCEA+gF7koaZWRKb4ZS3U6SWwWGwY0RyiGxxUBYI7GOIk3sytEZA4GTweRKPh0aHYp6mm0GcPcRXrrfk4bfFCgN75R1e2g+gmxcKuRB0KQCXCYe58GikyCiqgDDjxiGSXAdPibu02BHDqFo5199Muj1oqsZxeVnsGVKywa4GC+oKoMsDgaykQ0GIsIFjUAV9DoAufLi1tYg3VTLwTH7D4lzK1oNxTQf1O0RG+MdwS6L9EcWyNjGQEpodwQvgskxBUklK01kkYrRReL2o54T/QmaIMADUyAMh+SDqNhAFSrDr+iqkFPz3DU23gj8RzPIFyZ77FAZ0VIhu2DoZZBKhYBxbFR8Zotkk/nktRlUVzy22hu9Zx/5U4pnPGhOuCl8GgzipgOUWg1JeTgDslgVGgIwImYQw7eh82qaip+4gpozSxmMGAAmh7mivdeewwSPFsg0A16YOG7pZSqkn1FmuEWoT7Dg/7Usk7p9L/ObIx2ddBI3uD63hmkxuaM2AvASBccnvGKcYEYaLSmolSh9ffvv/XDn/ztm+8+6DJZbb/1O1945vbLNtu7b769v/hwNU22Or//6Pr7r+nXvrBeXS7f/2CFWvdcsV3++d8+/uY3X3j+i+X171yvFs+K1lLKzeX113/vf3jhC3/w88fzLMsrPbls62s53/LkiZxt7NYVplnPt3rHNuQG2FA2ghvwxngluhXZieyIPawZ9qaczfZmW60doIfxZl3QgQ50iietSZ8dfhHC0Wmm4n0poyqLdHK0sO6ajU3erh2Iguc9Kori/vNQ5XUjlfp/Dn/BvLGeouqxfkInhwghtl0KBSVXZyxjEIGS4ehBQAHUJHllRghLkCAMRaX4PCszhS7UKmShOmnFbsI8ybzEPNluIbuVXOuWumNvWnbl4p2HvNgCk87GLcCGnc1t6tUWG+k7TqaYZ9sXM9Za8P7jZ+9+9N50atidSNtiXtm+apv6rqjJQqRAK1hcMkRMPDOjQBZ14TIHYU4OztEjfCO7d97gcIo8lPZHkRVPpiUWkCi9Myibia4BRdRFIWjmAKPnyNG4SCdUax6SwBIBIVxtK4rwNY6Q/1PaODmkpglvAtHXmb2tYW0BuJ6AdxmNCDu61US0kGEiRCOjHEp4kEE6ZW658fLIwQJSyZ9JKNkaSS1aSvVRi9FtBxUJhx19nMlBdfGiYHYdJcr/5CU4LswkpHgEGY23ZX5xlAsE4DCkPceTZ1waMr3RNKEw+nA3YFh3b5IdGU24GkPvFs8L3n8W9Xoji/Ogw1LS0CGSSgLMqz2kUEHBsH8i3kQ39xhFfXierWBoQjhV6qieKuOOSoZyg0o/IGAyQQaJcn5qwrvmgEXJISMhOEHzaADDeDQAvAN2XLevJjzEzfM11mQsnYe93k2ZOWmsY4x0tVRjN2aDAcx6kMBR/Nbs8L3/ZAvEfwYpj0GZjdOLsNtSRAmrtSCFQVTTcqpmtwDILDcmp10yVPZ7FQ+ULKm6KXnkd9d79u5lYSK0kkTooLJnZtEnB9Ccb5YCr44u05oPSctCQ37FAbRgh5R4FgKVSqOiP/7w7df+8VtvvvlEVqeoNx956aXnnnnxw4eX77/93k9/8ZPV7RPbNKk611s/+Wm7d+f0ld84vX/fHj2c1tM8ye35evv3r/GrX7uzfkkv7ms9sXmWr3/jjz7/jd/99c4a1ibToz5tZX3F9QZnG66vuL7mauYZroTXlJ3IjdiN4QbYQmfYhtzS9pQmOisxEw1ogJntVTtJwHx4O2lkDxYGvA4TuQQS7TfrTusjnHLCYRtdikccT3E3bA7qmxx08d1B0wEqI73zc2wkkRh3KD78kUPTDIdM+tCXPDAkEWEnlVkFQxYRjhQYPTviKGYNYEeULKqL3s3MdOF5FkWlVO3aIdAiWnVSTugLtCXmSXdLzAvb2XXFNWSL3QU2j27unK/axbx5YrqXSdFRt9g3E6KvZthVlzNoVTYr2zbt+uc+/tk6nWw2N2WxqzKr9gkN1oh9F4vpxoXuFCFUF810zJwgCsO0BDCWFe50OnC2kB/qA3yfxUUAQWFJ3ygjKAn1T/MS3iFUSnUtc5pWSjnBCwThfI76h3xorQkrMghLGT46mjo6g49NjEBIF+45cIlTItFDCybY7Uud9v3IEIdNKJ4ijx8eRdphNEKCIdnBHCGjuRSneq9UUxGzPtJuf5SGzrHJdHSDeGZ3AE4Nh5IbwkAy4cu0/ZKrSeCIwTuKcFEzIRxSdv0uKMzMNdBrrQoTxBQUEcCio8ZcONF/GJGBROVRpBSJ3eBWNas9MQeX5p1XIhnZWDSn+HkaVSjk6eJTD/kAqPj9uGV1CRF/9BKTSZNQAtRaI/Ukes8ZjsARlSMstEdEDNVTcXBGcDA9mcV62vBUlE6DiIeRgyTlhFsdZU45gC4ROMhxz1lCsUxtCpe9iiMVnCmGm4Mi/VYoyB5efmAl+4VdsEAiQEx3fuz0DThSPYvlyj4XBX3uO53NxNS2IIQ0RbIXJcpSUUpAVJoZY62yBhkxn47D6FcQpB2axyRZlUBWRfwJRXTmF986CyE4lkOnmZVExWgmqKIGuD6Dx8ea/sntlJlsaj3fXr3/4N0fvv2LK9hJ4Xyzubl7fu+Dhxe36/nPf/7GcqkTFpdXc1koT/Wx2bf+7vEfrV745NfsB3/29m773Hp6slgu33gwP/v++vanz9+8/7jOp//uf/7Tl1/5+IPLWUtB0ZmLzeLkw7660bOrfnKj6yuc7WzS6yo3xmtoEz6hbIQbYgvbkBvyhrIV7mE2A021u8qMBBDVzBrQxIF0d5FO9oi2tugZgYNxGoziDLrgVl0JhVIikfJNp3KYCZ07xUGo2PTedesMCK+wSCQ/EhXHqIiBoM8SEDIcMzj4EqLp9iEaea0P+HKRCWY/gqX5h7DEpoBCq6H2bpQqUKi5wowqTA0LQSWVLFaxr2hL7JdoK2xXusX1pPvW551dlauHP/vCb3b76EsX714+eHP/9ju7yyfWVGa0Bm1GUz3Xs/3Vdip1O2+/9KUvf+1ffZHPnswbq6u6qm253wJbse2qrifspQqqsQp90mUVrYXFySVFpDvVkgZFNcySQav7TfyTg8p4Wv4mV/sOK3RoQvLGX3ipaxQeBejdCjCKtgBCX9HTxCjKdJ9kmL+ldvCsUEgCshyHOXNXIOu4npAneGUejBc3rKIK60YnZ0s7Jid7inWYQ4BhNgD0Zlmj8icUOqhHZcVMgPxy3C2Gjry41pao9IwIHdY266qlmdVaI7YEYVGT9bBlJH1hrEj6sIGBOTPzYFfwxjFNChJofoAGHFXNTAXjpEAGx8zv2glowPgi3/cZmRAwijpYHsTs/MZY4BRZIkQOup4wxBy9+DYHcGNR8/89LZN0wpJ5/bge916JuwIExdm84s7C80BVjW5WpNsetN0MpDy6Gus43L6K9N69Li0yEBpfl3Qtge+RTM5oakRmt3vAdk+fpEMY6J7NP0pTFSEBCUiEkcdLCXcwGTcMnMnVrNTJqHFAJJ3XIaIUZC9APJAM0TJXBWIqsMQFmvfKUQCXeReoglHASgIlTUY7qko2STizi2ounCciQx6PQabzTZHGJ1jKliPzjk1Q3Geiy6SJBdcxtkCSBgfPE4Sx5RYqErIqnZ5SU7TW7fb6/Uc/vtk8vHwk09o2T24+8rGPnd96Fqfy5k9f2z65Onlm2l1sF2fVbqDSdL3+YHf9ne/v/+D3X7zzmZu3vn9tevdsNfXt/Prbuy9++W470y989V+cvfKV+5veq8d7tetiw+VVWW3kfFtWV1j3G9Ub6BbYgBtgD26oN8prckdswC2xFzRhb0UbbTZr5E5kr9occ4Y2wCShvqiYZNirQmeuRTp5aKwedQMas51y2HxJkRTHCxnyNSo8KBqUMrQLvQM8Em7zSZodQy8lNzFT+U5VJcSenEjomzto7SIU0zTFGvl2RL7dk6HQH6JFM6s7YlRQuxmsF6m+U0XBShTX/NhDu4op+lSKdhOx3naVJx88/tlbP/ubi3/cLjb1ufM7n/pNe+Zjm3fe3b71q/nyCZqpCppidX6mG9h+X1f1xZdemm7dvuZcdg0mxv2iYjJvLg9Q6rB7fUFMo+DrDZG0YV5VK2C0xmiAhNs+d2UFUSQlvbwjyTgBgugf3aQHAJbZCZLsVxsfHNZU0rhIvoEiNNMIVeHCBRFUAUx+3UGt3b8eGsPS3I1HVqAqbjgcMOH4UsZRd0OgKjCadZAael1xzA8NiKNWcsiK/8tXsl4QA5U4XOPY0ICKtt5FrJRqZq03CNq++T8Vp9EnrAowbWgiu9FEcaT+EYhcpAr/RdjEtLKZ4hxSCkT9NYr6Umv1WCnJ24jGNSTCrM6eYuR2I471VNuO2e+IQN2TqShAR/Oq+SinsPCRHIkFHSCj+4Rw5UDRQ7jnIGUcyHCOUzH7QQOBZJ5bwtdbk+yWeRpyrx1WMZPwp0Ch4IMzKgzpOUbxwkOiZj0iU3j1IfJ+5Nvig/NesjUGBxZWBkABYoPqVYzsrk4I4ZDz+eqIA6+IG/UWkdgNI0SJZc+XHm41ww/RDOBIiDOLhUIljd1Ca1MJPH0O+PRfAsI4yAUIBg9oFEzgPsOfDrshEur8RUdNaSJDgS/gKjNTqJkZmrK4hMxBt8a9gVA0mgU8KIvACM2LoYBBWKTsthfz/t2i+2mi9f7c3Y/+s6//4Xay//Bn/5dN29XdhV2bCG3TYaU1VJuxWL53hZ+8defVz37z7fs/+PWF9bXWaXF/e3Fvu/i9P/3fXv7oq7/aoIfqaDEpe8oNzjZlfWUrs6lf0WctcAPZiW5gM7EVuzbeEFvILNJEdsJOyAzsRWaykY3cq7oER8819CJqHxgHIYDD+lnF8nMe210lHybSRjq56djAefEdaWyZfyadP+DDbQBwcFs1SloUwHIxJfs6A9sJZ+/xZsktP/YpRMB+0I/xDe/G6CnmWBD+zOEi33QKIcOmiXeVm5Cgqkkx0QaZiXnfrS6kzmU6LSd2/71f/+AfPnzy1iyXuFXr3Vvl/LmTVz525+zu5vXXP3zwcLuq60Xbf/jwIc+0TJBVPbt3SvjkSlgFdLXrtaHuUBtk7mpmMKipD/ZBA5r5RDYVkn3w/d3iHQ298T4qI7t7j3QKhAOxQa9jmn13yALxKsOwbNQYtEOxkAqAow2eT2csFsFYLoEZYR0qwXWNlUPNqt1hi0i0GME11KIYdfTvAnXYxPE7jXQ7ew3TdgRDWNzFHNt6ePkWDpnnGAMnSfnUGrfNURnNjne3zk7bJNniUan5MB9vWBS4yw+PMzo1IkVzUJN5J3mFQdCKxlM3lCMHHU8xHclgoBydq9HvnNeZ4GA4pqhoMijRDvKT7v3T+Hp+Yk5Xjd6uEQSMRytHE04ki+Ijq47cTpW9WzcUCFIhS8ath1k4ypO9Wyhhl/FRh7wTkh3vWdUAmKcU414PFa1jJ5wHwYnN8UAZqaAeriz2UD5p/2rfTJo0YoteKSC9ZjwXv2956ge+7rl1wQOTEaCTVbK24PMOWFEQ2s45Y5PRBCnQSI6FdA24DJBEXOQ1WhDj1xLmO7LB3moXhT1v/GDI8B7ui5mTJt9P2ZNalfoN8bC8uf/Inh9WWiH/5GfDQhwd7OD0QKOd1yfgSjdU1VJLDd6kmAV6GaiAHxPAlDXW2k9X399s37348P3VdLpazk+u7JOvfJKml+8/XtU6UzCTitLqknW3a6UoN5BJt5w/+PD5Ldbnr7zz/uXmiRVaO7Fn9fzVs5e+/t62s1QDVEujmBnLdIPTy77EXm1juhVsITfCG2IGtsANsRO5AbawOTJgmSE6C2azPdBULVZZRUIN3kSMMLMGmGoBrIdGAiBCM2/tc9TKzMQFDxSOhBaIEVKjQePoOMk4QchmMC+JSWgfSZBWEniynF4U4b4dYmB4FwMTaREYKCFCn/YHQ4/IBd3dcLqF9MAa2YrudsmPgmt6G9gpVUthIUhrxN60KzphEGopxagdCilNptYu534z1ZOr6/nnbz3oLF/66pfbRXv0y4ePHm021/Xsaj57Vk6nUpup2CRSJrRqpdZdn3/8kx/c+cI/r0VxoqzN9rIvtRGoK9hkFBikA83QvOnHDW4wVCWG9kWFxgmtyIKRecFA4CfS8Uivannc7JIYHoIbTEyzXSHCXC99qgZObRjedwB+gtG65lRnJw6IaHH1ZcFT/a6oxsy5XZln9GRmcOUw3SBKw0uEkcaS3UIM4Vj6h5AMnlNZ5BiT9N0WriW1H5DBXG7XdEuMQaWZq4yIIeyHaQkFLt9tZlaqwoTslsllhKeHPNS/buDx4X0Z4iMMlDmB2vH9GFkVDtVgHJyyJ4mZb9FTTimlOE3RT+RAOFWld0vzGc4wGDseQZiZc7NE3RV6jJzdTcNR+fu9wJygKcqoN8TpTVXaofh06A0N/4XW+qHO6oQpj4z9wcS3alYoU7ZMDtZeHMtJHUWJTejWWhKphiTtytLBH4U0kpizj1TzYC52H5DSmCIIITNmiJD3k8HT8OYSEyHS0gAHzGOw0AXsESP6E/T7AdgdhyxBXnTqN48jQjk8xfje/EzfrG7vknFDSUV+ORo0mZ8QUM/hcQR0Rb/fCBv9rgbmnDshGXyQbLVP9k3sM/e1/tCgXiEW8b5ma6TDJpU0ovqAEYGL4QR2huAuMCbCjHGIZkC/2uxutr80a0A9O//Q7G6dVleXm3ff/tXVo6vVnYIZRmMBDGUFY0Hv7E2s/uK11xfL9b2Pns7rxZNy+tJLd1/97KfOP/qxD/piL3vrSwgI7RSUxR4aGpMb6Ky6hV0Te5GtYOesK+UNuUFIcNxQ9gbMsB2wVzVDh3ZBA42YE1L06q+XdcPmAjTrTmA6wHcGAI48ESlsklRTNwj+vKIZiEAiMYOsMCAuscRJ6L0s0U+aGIRE9Ba5RHJgj5rNou54oGn52ZGgvQxIPNDy0B1xNk4mKxJdZB6QEqTQ3a2qFJgaXI7OoMZOMRSiNJ2ManoyrS5rsx+89sMHDx/cefZ0unX2sx/+sM7QqbS9vfuz6/5W3+1xWkvFLMBee5kWps1k+8sHr/92++3bZ89dYVdr2duiscxSe8dMNV1oV+tmjWJBJhagw9gs9CGtQU1BM9OiZBE0EnAsUYuqdrSoMiLpKBDvJnCIAZH+ZCYreWg9Z2qRbWopjODXae5QLW56W2vmhNmiWYOHFscJs5YBAFLNuewBPaY5c2K9n97oqQzuMUJpwZeQZiyQbqyLGowWSTs5qIDuyEUHQMfRKWSpiZY4bqll6EuAB63jyEiQpRct4aHgkanPyERUP82B3mjGHYRkFXTSZ/alx8FA8wdVbdgyCRCeEa6GnMTB0A9amz9hcTLE+NSgKQsynshY1dnx4WpExAWgDF2d6xDfE0hV7w0ZjhUJfpwGBckDLIiqGYsqRDodAoBqzNcNye58kehmDl0Ed0rjhLtg7HBiA2Pp1quUeCKS3jD+6DfL4VyZwQfCu4T5d1h5ACqayk0BaTNcT1FSC6KVw0cvW0a4nhO7I0S0c3vUGLvOqQPI70SsVMz6C5q3BIjnS5fjN0QoVFHPUh2rMTPNgADMOkiayqPG0JH6cgQQyL4yr9IaaNYzU4pA/QAbhL9P+xnfkX/T7M4d25PZCj7WNVjrVCqJQQ2RZLaHRYkkPlsIaQy5eTWa2Sz+SFAcolIsBRYhdQTT6mFkSAgQSVkyALv5AtiI2qPH188/r5O+dH5r/d4H77/z87dWiyXmPasRwo2ArAprDUbO0I62sYtf3nz07gsvrtavfOYzr776+bquT2ZSYK0LpRTCCgzWOhp0FtmJbUz2gh1wbdJUmti1YQ/dq+1MtsSs2BMGXezJRnZBozRwZowabH79Ht47KVJVe+9OI1b1miIwSuSMPiOkURIIYa0heNFmouqdAwqqFtUU64Wzunw95KD0QiL24WHzSM6VVI01cBaV01m8ug86NBoxWoI/ZtnaGkGDJ0L0qN7HWHmiX32jkA2oYFNUshEFMJHq6YxXxjNnMi/JUErHwjqa1NkWOk3v/vr+z371Buv29OzFq+3l1eb9qanOtc3z+a0z5a33Hz1aT4ulclpNtmy3Xrz3wide/HD+gGePf/rGjz959+T2R842KLu6gC2BqVsVrQZlBxvYw/u6FVJoj76YubNVodvQwTdKqMlIa6352DoIfBKgwXvnJP2a45CxxtapRV0D1/9hxEtpJEWSbkxjs1ZyNlopBYdOS1c7cVPE0Wr//wNfoigaFBtyugAAAABJRU5ErkJggg==", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -799,10 +855,11 @@ " cv2.imwrite(file_name, vis_result[:,:,::-1])\n", " display(Image(file_name))\n", "else:\n", - " cv2_imshow(vis_result)" + " cv2_imshow(vis_result[:,:,::-1]) #RGB2BGR to fit cv2" ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": { "id": "42HG6DSNI0Ke" @@ -817,7 +874,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -857,7 +914,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -1003,7 +1060,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -1038,6 +1095,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": { "id": "H-dMbjgnJzbH" @@ -1049,6 +1107,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": { "id": "jCu4npV2rl_Q" @@ -1066,11 +1125,7 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "3I66Pi5Er94J", - "outputId": "5873af68-4090-42bb-e4b2-fe6f94818609" + "id": "3I66Pi5Er94J" }, "outputs": [], "source": [ @@ -1079,7 +1134,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": { "id": "rRNq50dytJki" }, @@ -1144,10 +1199,11 @@ " data_list.append(data_info)\n", " ann_id = ann_id + 1\n", "\n", - " return data_list\n" + " return data_list, None\n" ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": { "id": "UmGitQZkUnom" @@ -1160,7 +1216,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -1441,7 +1497,7 @@ "cfg.val_evaluator = dict(type='PCKAccuracy')\n", "cfg.test_evaluator = cfg.val_evaluator\n", "\n", - "cfg.default_hooks.checkpoint.save_best = 'pck/PCK@0.05'\n", + "cfg.default_hooks.checkpoint.save_best = 'PCK'\n", "cfg.default_hooks.checkpoint.max_keep_ckpts = 1\n", "\n", "print(cfg.pretty_text)\n" @@ -1450,7 +1506,9 @@ { "attachments": {}, "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "UlD8iDZehE2S" + }, "source": [ "or you can create a config file like follows:\n", "```Python3\n", @@ -1607,6 +1665,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": { "id": "ChVqB1oYncmo" @@ -1617,7 +1676,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -3485,8 +3544,11 @@ ] }, { + "attachments": {}, "cell_type": "markdown", - "metadata": {}, + "metadata": { + "id": "sdLwcaojhE2T" + }, "source": [ "#### Note\n", "The recommended best practice is to convert your customized data into COCO format." @@ -3556,28 +3618,6 @@ "value": 132594821 } }, - "13ac80b3ee9d4ce1bc1405a3d69c3c73": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HBoxModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HBoxModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HBoxView", - "box_style": "", - "children": [ - "IPY_MODEL_7abbd13654ff480183deb3d71dddf3e0", - "IPY_MODEL_59c9f043983849e19df8cc2f4253b04a", - "IPY_MODEL_990e4db4f7824bc994eff6ef91d4675b" - ], - "layout": "IPY_MODEL_d227d12439aa449cb267f393e43a1eff" - } - }, "1c1b09d91dec4e3dadefe953daf50745": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", @@ -3630,110 +3670,6 @@ "width": null } }, - "214f964729e140d5b8ab6ca5f342d416": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "21afdf2781cd45c3b541a769bfca494b": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, "2a079d9c0b9845318e6c612ca9601b86": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", @@ -3756,21 +3692,6 @@ "layout": "IPY_MODEL_a9bd3e477f07449788f0e95e3cd13ddc" } }, - "305bb5675d1a4a71ae47614db0c96b67": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, "3554753622334094961a47daf9362c59": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", @@ -3813,30 +3734,6 @@ "value": " 126M/126M [00:14<00:00, 9.32MB/s]" } }, - "59c9f043983849e19df8cc2f4253b04a": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "FloatProgressModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "FloatProgressModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "ProgressView", - "bar_style": "success", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_c06dc4651af24be3ba658102043658f9", - "max": 167287506, - "min": 0, - "orientation": "horizontal", - "style": "IPY_MODEL_7811af5efbc34360b06eb795ff9e7a6c", - "value": 167287506 - } - }, "5b2ee1f3e78d4cd993009d04baf76b24": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", @@ -3889,21 +3786,6 @@ "width": null } }, - "6674d0f99ac94805840a1f7a216606c8": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, "6af448aebdb744b98a2807f66b1d6e5d": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", @@ -3919,64 +3801,6 @@ "description_width": "" } }, - "7811af5efbc34360b06eb795ff9e7a6c": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "ProgressStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "ProgressStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "bar_color": null, - "description_width": "" - } - }, - "7abbd13654ff480183deb3d71dddf3e0": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_21afdf2781cd45c3b541a769bfca494b", - "placeholder": "​", - "style": "IPY_MODEL_305bb5675d1a4a71ae47614db0c96b67", - "value": "100%" - } - }, - "990e4db4f7824bc994eff6ef91d4675b": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_214f964729e140d5b8ab6ca5f342d416", - "placeholder": "​", - "style": "IPY_MODEL_6674d0f99ac94805840a1f7a216606c8", - "value": " 160M/160M [00:18<00:00, 9.52MB/s]" - } - }, "a3e5aa31c3f644b5a677ec49fe2e0832": { "model_module": "@jupyter-widgets/controls", "model_module_version": "1.5.0", @@ -4060,110 +3884,6 @@ "description_width": "" } }, - "c06dc4651af24be3ba658102043658f9": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "d227d12439aa449cb267f393e43a1eff": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, "d2ee56f920a245d9875de8e37596a5c8": { "model_module": "@jupyter-widgets/base", "model_module_version": "1.2.0", diff --git a/demo/body3d_pose_lifter_demo.py b/demo/body3d_pose_lifter_demo.py new file mode 100644 index 0000000000..840cd4edc9 --- /dev/null +++ b/demo/body3d_pose_lifter_demo.py @@ -0,0 +1,481 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import mimetypes +import os +import time +from argparse import ArgumentParser +from functools import partial + +import cv2 +import json_tricks as json +import mmcv +import mmengine +import numpy as np +from mmengine.structures import InstanceData + +from mmpose.apis import (_track_by_iou, _track_by_oks, collect_multi_frames, + convert_keypoint_definition, extract_pose_sequence, + inference_pose_lifter_model, inference_topdown, + init_model) +from mmpose.models.pose_estimators import PoseLifter +from mmpose.models.pose_estimators.topdown import TopdownPoseEstimator +from mmpose.registry import VISUALIZERS +from mmpose.structures import (PoseDataSample, merge_data_samples, + split_instances) +from mmpose.utils import adapt_mmdet_pipeline + +try: + from mmdet.apis import inference_detector, init_detector + has_mmdet = True +except (ImportError, ModuleNotFoundError): + has_mmdet = False + + +def parse_args(): + parser = ArgumentParser() + parser.add_argument('det_config', help='Config file for detection') + parser.add_argument('det_checkpoint', help='Checkpoint file for detection') + parser.add_argument( + 'pose_estimator_config', + type=str, + default=None, + help='Config file for the 1st stage 2D pose estimator') + parser.add_argument( + 'pose_estimator_checkpoint', + type=str, + default=None, + help='Checkpoint file for the 1st stage 2D pose estimator') + parser.add_argument( + 'pose_lifter_config', + help='Config file for the 2nd stage pose lifter model') + parser.add_argument( + 'pose_lifter_checkpoint', + help='Checkpoint file for the 2nd stage pose lifter model') + parser.add_argument('--input', type=str, default='', help='Video path') + parser.add_argument( + '--show', + action='store_true', + default=False, + help='Whether to show visualizations') + parser.add_argument( + '--rebase-keypoint-height', + action='store_true', + help='Rebase the predicted 3D pose so its lowest keypoint has a ' + 'height of 0 (landing on the ground). This is useful for ' + 'visualization when the model do not predict the global position ' + 'of the 3D pose.') + parser.add_argument( + '--norm-pose-2d', + action='store_true', + help='Scale the bbox (along with the 2D pose) to the average bbox ' + 'scale of the dataset, and move the bbox (along with the 2D pose) to ' + 'the average bbox center of the dataset. This is useful when bbox ' + 'is small, especially in multi-person scenarios.') + parser.add_argument( + '--num-instances', + type=int, + default=-1, + help='The number of 3D poses to be visualized in every frame. If ' + 'less than 0, it will be set to the number of pose results in the ' + 'first frame.') + parser.add_argument( + '--output-root', + type=str, + default='', + help='Root of the output video file. ' + 'Default not saving the visualization video.') + parser.add_argument( + '--save-predictions', + action='store_true', + default=False, + help='whether to save predicted results') + parser.add_argument( + '--device', default='cuda:0', help='Device used for inference') + parser.add_argument( + '--det-cat-id', + type=int, + default=0, + help='Category id for bounding box detection model') + parser.add_argument( + '--bbox-thr', + type=float, + default=0.9, + help='Bounding box score threshold') + parser.add_argument('--kpt-thr', type=float, default=0.3) + parser.add_argument( + '--use-oks-tracking', action='store_true', help='Using OKS tracking') + parser.add_argument( + '--tracking-thr', type=float, default=0.3, help='Tracking threshold') + parser.add_argument( + '--show-interval', type=int, default=0, help='Sleep seconds per frame') + parser.add_argument( + '--thickness', + type=int, + default=1, + help='Link thickness for visualization') + parser.add_argument( + '--radius', + type=int, + default=3, + help='Keypoint radius for visualization') + parser.add_argument( + '--use-multi-frames', + action='store_true', + default=False, + help='whether to use multi frames for inference in the 2D pose' + 'detection stage. Default: False.') + + args = parser.parse_args() + return args + + +def get_area(results): + for i, data_sample in enumerate(results): + pred_instance = data_sample.pred_instances.cpu().numpy() + if 'bboxes' in pred_instance: + bboxes = pred_instance.bboxes + results[i].pred_instances.set_field( + np.array([(bbox[2] - bbox[0]) * (bbox[3] - bbox[1]) + for bbox in bboxes]), 'areas') + else: + keypoints = pred_instance.keypoints + areas, bboxes = [], [] + for keypoint in keypoints: + xmin = np.min(keypoint[:, 0][keypoint[:, 0] > 0], initial=1e10) + xmax = np.max(keypoint[:, 0]) + ymin = np.min(keypoint[:, 1][keypoint[:, 1] > 0], initial=1e10) + ymax = np.max(keypoint[:, 1]) + areas.append((xmax - xmin) * (ymax - ymin)) + bboxes.append([xmin, ymin, xmax, ymax]) + results[i].pred_instances.areas = np.array(areas) + results[i].pred_instances.bboxes = np.array(bboxes) + return results + + +def get_pose_est_results(args, pose_estimator, frame, bboxes, + pose_est_results_last, next_id, pose_lift_dataset): + pose_det_dataset = pose_estimator.cfg.test_dataloader.dataset + + # make person results for current image + pose_est_results = inference_topdown(pose_estimator, frame, bboxes) + + pose_est_results = get_area(pose_est_results) + if args.use_oks_tracking: + _track = partial(_track_by_oks) + else: + _track = _track_by_iou + + for i, result in enumerate(pose_est_results): + track_id, pose_est_results_last, match_result = _track( + result, pose_est_results_last, args.tracking_thr) + if track_id == -1: + pred_instances = result.pred_instances.cpu().numpy() + keypoints = pred_instances.keypoints + if np.count_nonzero(keypoints[:, :, 1]) >= 3: + pose_est_results[i].set_field(next_id, 'track_id') + next_id += 1 + else: + # If the number of keypoints detected is small, + # delete that person instance. + keypoints[:, :, 1] = -10 + pose_est_results[i].pred_instances.set_field( + keypoints, 'keypoints') + bboxes = pred_instances.bboxes * 0 + pose_est_results[i].pred_instances.set_field(bboxes, 'bboxes') + pose_est_results[i].set_field(-1, 'track_id') + pose_est_results[i].set_field(pred_instances, 'pred_instances') + else: + pose_est_results[i].set_field(track_id, 'track_id') + + del match_result + + pose_est_results_converted = [] + for pose_est_result in pose_est_results: + pose_est_result_converted = PoseDataSample() + gt_instances = InstanceData() + pred_instances = InstanceData() + for k in pose_est_result.gt_instances.keys(): + gt_instances.set_field(pose_est_result.gt_instances[k], k) + for k in pose_est_result.pred_instances.keys(): + pred_instances.set_field(pose_est_result.pred_instances[k], k) + pose_est_result_converted.gt_instances = gt_instances + pose_est_result_converted.pred_instances = pred_instances + pose_est_result_converted.track_id = pose_est_result.track_id + + keypoints = convert_keypoint_definition(pred_instances.keypoints, + pose_det_dataset['type'], + pose_lift_dataset['type']) + pose_est_result_converted.pred_instances.keypoints = keypoints + pose_est_results_converted.append(pose_est_result_converted) + return pose_est_results, pose_est_results_converted, next_id + + +def get_pose_lift_results(args, visualizer, pose_lifter, pose_est_results_list, + frame, frame_idx, pose_est_results): + pose_lift_dataset = pose_lifter.cfg.test_dataloader.dataset + # extract and pad input pose2d sequence + pose_seq_2d = extract_pose_sequence( + pose_est_results_list, + frame_idx=frame_idx, + causal=pose_lift_dataset.get('causal', False), + seq_len=pose_lift_dataset.get('seq_len', 1), + step=pose_lift_dataset.get('seq_step', 1)) + + # 2D-to-3D pose lifting + width, height = frame.shape[:2] + pose_lift_results = inference_pose_lifter_model( + pose_lifter, + pose_seq_2d, + image_size=(width, height), + norm_pose_2d=args.norm_pose_2d) + + # Pose processing + for idx, pose_lift_res in enumerate(pose_lift_results): + pose_lift_res.track_id = pose_est_results[idx].get('track_id', 1e4) + + pred_instances = pose_lift_res.pred_instances + keypoints = pred_instances.keypoints + keypoint_scores = pred_instances.keypoint_scores + if keypoint_scores.ndim == 3: + keypoint_scores = np.squeeze(keypoint_scores, axis=1) + pose_lift_results[ + idx].pred_instances.keypoint_scores = keypoint_scores + if keypoints.ndim == 4: + keypoints = np.squeeze(keypoints, axis=1) + + keypoints = keypoints[..., [0, 2, 1]] + keypoints[..., 0] = -keypoints[..., 0] + keypoints[..., 2] = -keypoints[..., 2] + + # rebase height (z-axis) + if args.rebase_keypoint_height: + keypoints[..., 2] -= np.min( + keypoints[..., 2], axis=-1, keepdims=True) + + pose_lift_results[idx].pred_instances.keypoints = keypoints + + pose_lift_results = sorted( + pose_lift_results, key=lambda x: x.get('track_id', 1e4)) + + pred_3d_data_samples = merge_data_samples(pose_lift_results) + det_data_sample = merge_data_samples(pose_est_results) + + if args.num_instances < 0: + args.num_instances = len(pose_lift_results) + + # Visualization + if visualizer is not None: + visualizer.add_datasample( + 'result', + frame, + data_sample=pred_3d_data_samples, + det_data_sample=det_data_sample, + draw_gt=False, + show=args.show, + draw_bbox=True, + kpt_thr=args.kpt_thr, + num_instances=args.num_instances, + wait_time=args.show_interval) + + return pred_3d_data_samples.get('pred_instances', None) + + +def get_bbox(args, detector, frame): + det_result = inference_detector(detector, frame) + pred_instance = det_result.pred_instances.cpu().numpy() + + bboxes = pred_instance.bboxes + bboxes = bboxes[np.logical_and(pred_instance.labels == args.det_cat_id, + pred_instance.scores > args.bbox_thr)] + return bboxes + + +def main(): + assert has_mmdet, 'Please install mmdet to run the demo.' + + args = parse_args() + + assert args.show or (args.output_root != '') + assert args.input != '' + assert args.det_config is not None + assert args.det_checkpoint is not None + + detector = init_detector( + args.det_config, args.det_checkpoint, device=args.device.lower()) + detector.cfg = adapt_mmdet_pipeline(detector.cfg) + + pose_estimator = init_model( + args.pose_estimator_config, + args.pose_estimator_checkpoint, + device=args.device.lower()) + + assert isinstance(pose_estimator, TopdownPoseEstimator), 'Only "TopDown"' \ + 'model is supported for the 1st stage (2D pose detection)' + + det_kpt_color = pose_estimator.dataset_meta.get('keypoint_colors', None) + det_dataset_skeleton = pose_estimator.dataset_meta.get( + 'skeleton_links', None) + det_dataset_link_color = pose_estimator.dataset_meta.get( + 'skeleton_link_colors', None) + + # frame index offsets for inference, used in multi-frame inference setting + if args.use_multi_frames: + assert 'frame_indices' in pose_estimator.cfg.test_dataloader.dataset + indices = pose_estimator.cfg.test_dataloader.dataset[ + 'frame_indices_test'] + + pose_lifter = init_model( + args.pose_lifter_config, + args.pose_lifter_checkpoint, + device=args.device.lower()) + + assert isinstance(pose_lifter, PoseLifter), \ + 'Only "PoseLifter" model is supported for the 2nd stage ' \ + '(2D-to-3D lifting)' + pose_lift_dataset = pose_lifter.cfg.test_dataloader.dataset + + pose_lifter.cfg.visualizer.radius = args.radius + pose_lifter.cfg.visualizer.line_width = args.thickness + pose_lifter.cfg.visualizer.det_kpt_color = det_kpt_color + pose_lifter.cfg.visualizer.det_dataset_skeleton = det_dataset_skeleton + pose_lifter.cfg.visualizer.det_dataset_link_color = det_dataset_link_color + visualizer = VISUALIZERS.build(pose_lifter.cfg.visualizer) + + # the dataset_meta is loaded from the checkpoint + visualizer.set_dataset_meta(pose_lifter.dataset_meta) + + if args.input == 'webcam': + input_type = 'webcam' + else: + input_type = mimetypes.guess_type(args.input)[0].split('/')[0] + + if args.output_root == '': + save_output = False + else: + mmengine.mkdir_or_exist(args.output_root) + output_file = os.path.join(args.output_root, + os.path.basename(args.input)) + if args.input == 'webcam': + output_file += '.mp4' + save_output = True + + if args.save_predictions: + assert args.output_root != '' + args.pred_save_path = f'{args.output_root}/results_' \ + f'{os.path.splitext(os.path.basename(args.input))[0]}.json' + + if save_output: + fourcc = cv2.VideoWriter_fourcc(*'mp4v') + + pose_est_results_list = [] + pred_instances_list = [] + if input_type == 'image': + frame = mmcv.imread(args.input, channel_order='rgb') + + # First stage: 2D pose detection + bboxes = get_bbox(args, detector, frame) + pose_est_results, pose_est_results_converted, _ = get_pose_est_results( + args, pose_estimator, frame, bboxes, [], 0, pose_lift_dataset) + pose_est_results_list.append(pose_est_results_converted.copy()) + pred_3d_pred = get_pose_lift_results(args, visualizer, pose_lifter, + pose_est_results_list, frame, 0, + pose_est_results) + + if args.save_predictions: + # save prediction results + pred_instances_list = split_instances(pred_3d_pred) + + if save_output: + frame_vis = visualizer.get_image() + mmcv.imwrite(mmcv.rgb2bgr(frame_vis), output_file) + + elif input_type in ['webcam', 'video']: + next_id = 0 + pose_est_results_converted = [] + + if args.input == 'webcam': + video = cv2.VideoCapture(0) + else: + video = cv2.VideoCapture(args.input) + + (major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.') + if int(major_ver) < 3: + fps = video.get(cv2.cv.CV_CAP_PROP_FPS) + else: + fps = video.get(cv2.CAP_PROP_FPS) + + video_writer = None + frame_idx = 0 + + while video.isOpened(): + success, frame = video.read() + frame_idx += 1 + + if not success: + break + + pose_est_results_last = pose_est_results_converted + + # First stage: 2D pose detection + if args.use_multi_frames: + frames = collect_multi_frames(video, frame_idx, indices, + args.online) + + # make person results for current image + bboxes = get_bbox(args, detector, frame) + pose_est_results, pose_est_results_converted, next_id = get_pose_est_results( # noqa: E501 + args, pose_estimator, + frames if args.use_multi_frames else frame, bboxes, + pose_est_results_last, next_id, pose_lift_dataset) + pose_est_results_list.append(pose_est_results_converted.copy()) + + # Second stage: Pose lifting + pred_3d_pred = get_pose_lift_results(args, visualizer, pose_lifter, + pose_est_results_list, + mmcv.bgr2rgb(frame), + frame_idx, pose_est_results) + + if args.save_predictions: + # save prediction results + pred_instances_list.append( + dict( + frame_id=frame_idx, + instances=split_instances(pred_3d_pred))) + + if save_output: + frame_vis = visualizer.get_image() + if video_writer is None: + # the size of the image with visualization may vary + # depending on the presence of heatmaps + video_writer = cv2.VideoWriter(output_file, fourcc, fps, + (frame_vis.shape[1], + frame_vis.shape[0])) + + video_writer.write(mmcv.rgb2bgr(frame_vis)) + + # press ESC to exit + if cv2.waitKey(5) & 0xFF == 27: + break + time.sleep(args.show_interval) + + video.release() + + if video_writer: + video_writer.release() + else: + args.save_predictions = False + raise ValueError( + f'file {os.path.basename(args.input)} has invalid format.') + + if args.save_predictions: + with open(args.pred_save_path, 'w') as f: + json.dump( + dict( + meta_info=pose_lifter.dataset_meta, + instance_info=pred_instances_list), + f, + indent='\t') + print(f'predictions have been saved at {args.pred_save_path}') + + +if __name__ == '__main__': + main() diff --git a/demo/bottomup_demo.py b/demo/bottomup_demo.py index 8d27a17178..3d6fee7a03 100644 --- a/demo/bottomup_demo.py +++ b/demo/bottomup_demo.py @@ -1,45 +1,49 @@ # Copyright (c) OpenMMLab. All rights reserved. import mimetypes import os -import tempfile +import time from argparse import ArgumentParser +import cv2 import json_tricks as json import mmcv import mmengine +import numpy as np from mmpose.apis import inference_bottomup, init_model from mmpose.registry import VISUALIZERS from mmpose.structures import split_instances -def process_one_image(args, img_path, pose_estimator, visualizer, - show_interval): +def process_one_image(args, + img, + pose_estimator, + visualizer=None, + show_interval=0): """Visualize predicted keypoints (and heatmaps) of one image.""" # inference a single image - batch_results = inference_bottomup(pose_estimator, img_path) + batch_results = inference_bottomup(pose_estimator, img) results = batch_results[0] # show the results - img = mmcv.imread(img_path, channel_order='rgb') - - out_file = None - if args.output_root: - out_file = f'{args.output_root}/{os.path.basename(img_path)}' - - visualizer.add_datasample( - 'result', - img, - data_sample=results, - draw_gt=False, - draw_bbox=False, - draw_heatmap=args.draw_heatmap, - show_kpt_idx=args.show_kpt_idx, - show=args.show, - wait_time=show_interval, - out_file=out_file, - kpt_score_thr=args.kpt_thr) + if isinstance(img, str): + img = mmcv.imread(img, channel_order='rgb') + elif isinstance(img, np.ndarray): + img = mmcv.bgr2rgb(img) + + if visualizer is not None: + visualizer.add_datasample( + 'result', + img, + data_sample=results, + draw_gt=False, + draw_bbox=False, + draw_heatmap=args.draw_heatmap, + show_kpt_idx=args.show_kpt_idx, + show=args.show, + wait_time=show_interval, + kpt_thr=args.kpt_thr) return results.pred_instances @@ -89,6 +93,8 @@ def parse_args(): type=int, default=1, help='Link thickness for visualization') + parser.add_argument( + '--show-interval', type=int, default=0, help='Sleep seconds per frame') args = parser.parse_args() return args @@ -97,8 +103,15 @@ def main(): args = parse_args() assert args.show or (args.output_root != '') assert args.input != '' + + output_file = None if args.output_root: mmengine.mkdir_or_exist(args.output_root) + output_file = os.path.join(args.output_root, + os.path.basename(args.input)) + if args.input == 'webcam': + output_file += '.mp4' + if args.save_predictions: assert args.output_root != '' args.pred_save_path = f'{args.output_root}/results_' \ @@ -116,48 +129,83 @@ def main(): device=args.device, cfg_options=cfg_options) - # init visualizer + # build visualizer model.cfg.visualizer.radius = args.radius model.cfg.visualizer.line_width = args.thickness visualizer = VISUALIZERS.build(model.cfg.visualizer) visualizer.set_dataset_meta(model.dataset_meta) - input_type = mimetypes.guess_type(args.input)[0].split('/')[0] + if args.input == 'webcam': + input_type = 'webcam' + else: + input_type = mimetypes.guess_type(args.input)[0].split('/')[0] + if input_type == 'image': + # inference pred_instances = process_one_image( args, args.input, model, visualizer, show_interval=0) - pred_instances_list = split_instances(pred_instances) - - elif input_type == 'video': - tmp_folder = tempfile.TemporaryDirectory() - video = mmcv.VideoReader(args.input) - progressbar = mmengine.ProgressBar(len(video)) - video.cvt2frames(tmp_folder.name, show_progress=False) - output_root = args.output_root - args.output_root = tmp_folder.name + + if args.save_predictions: + pred_instances_list = split_instances(pred_instances) + + if output_file: + img_vis = visualizer.get_image() + mmcv.imwrite(mmcv.rgb2bgr(img_vis), output_file) + + elif input_type in ['webcam', 'video']: + + if args.input == 'webcam': + cap = cv2.VideoCapture(0) + else: + cap = cv2.VideoCapture(args.input) + + video_writer = None pred_instances_list = [] + frame_idx = 0 - for frame_id, img_fname in enumerate(os.listdir(tmp_folder.name)): - pred_instances = process_one_image( - args, - f'{tmp_folder.name}/{img_fname}', - model, - visualizer, - show_interval=1) - progressbar.update() - pred_instances_list.append( - dict( - frame_id=frame_id, - instances=split_instances(pred_instances))) - - if output_root: - mmcv.frames2video( - tmp_folder.name, - f'{output_root}/{os.path.basename(args.input)}', - fps=video.fps, - fourcc='mp4v', - show_progress=False) - tmp_folder.cleanup() + while cap.isOpened(): + success, frame = cap.read() + frame_idx += 1 + + if not success: + break + + pred_instances = process_one_image(args, frame, model, visualizer, + 0.001) + + if args.save_predictions: + # save prediction results + pred_instances_list.append( + dict( + frame_id=frame_idx, + instances=split_instances(pred_instances))) + + # output videos + if output_file: + frame_vis = visualizer.get_image() + + if video_writer is None: + fourcc = cv2.VideoWriter_fourcc(*'mp4v') + # the size of the image with visualization may vary + # depending on the presence of heatmaps + video_writer = cv2.VideoWriter( + output_file, + fourcc, + 25, # saved fps + (frame_vis.shape[1], frame_vis.shape[0])) + + video_writer.write(mmcv.rgb2bgr(frame_vis)) + + # press ESC to exit + if cv2.waitKey(5) & 0xFF == 27: + break + + time.sleep(args.show_interval) + + if video_writer: + video_writer.release() + + cap.release() else: args.save_predictions = False diff --git a/demo/docs/2d_animal_demo.md b/demo/docs/en/2d_animal_demo.md similarity index 99% rename from demo/docs/2d_animal_demo.md rename to demo/docs/en/2d_animal_demo.md index 997f182087..aa9970395b 100644 --- a/demo/docs/2d_animal_demo.md +++ b/demo/docs/en/2d_animal_demo.md @@ -39,7 +39,7 @@ The augement `--det-cat-id=15` selected detected bounding boxes with label 'cat' **COCO-animals** In COCO dataset, there are 80 object categories, including 10 common `animal` categories (14: 'bird', 15: 'cat', 16: 'dog', 17: 'horse', 18: 'sheep', 19: 'cow', 20: 'elephant', 21: 'bear', 22: 'zebra', 23: 'giraffe'). -For other animals, we have also provided some pre-trained animal detection models (1-class models). Supported models can be found in [detection model zoo](/demo/docs/mmdet_modelzoo.md). +For other animals, we have also provided some pre-trained animal detection models (1-class models). Supported models can be found in [detection model zoo](/demo/docs/en/mmdet_modelzoo.md). To save visualized results on disk: diff --git a/demo/docs/2d_face_demo.md b/demo/docs/en/2d_face_demo.md similarity index 90% rename from demo/docs/2d_face_demo.md rename to demo/docs/en/2d_face_demo.md index e1940cd243..9c60f68487 100644 --- a/demo/docs/2d_face_demo.md +++ b/demo/docs/en/2d_face_demo.md @@ -1,8 +1,8 @@ ## 2D Face Keypoint Demo -We provide a demo script to test a single image or video with hand detectors and top-down pose estimators. Assume that you have already installed [mmdet](https://github.com/open-mmlab/mmdetection) with version >= 3.0. +We provide a demo script to test a single image or video with face detectors and top-down pose estimators. Assume that you have already installed [mmdet](https://github.com/open-mmlab/mmdetection) with version >= 3.0. -**Face Box Model Preparation:** The pre-trained face box estimation model can be found in [mmdet model zoo](/demo/docs/mmdet_modelzoo.md). +**Face Bounding Box Model Preparation:** The pre-trained face box estimation model can be found in [mmdet model zoo](/demo/docs/en/mmdet_modelzoo.md#face-bounding-box-detection-models). ### 2D Face Image Demo @@ -98,4 +98,4 @@ In addition, the Inferencer supports saving predicted poses. For more informatio ### Speed Up Inference -For 2D face keypoint estimation models, try to edit the config file. For example, set `model.test_cfg.flip_test=False` in [aflw_hrnetv2](../../configs/face_2d_keypoint/topdown_heatmap/aflw/td-hm_hrnetv2-w18_8xb64-60e_aflw-256x256.py#90). +For 2D face keypoint estimation models, try to edit the config file. For example, set `model.test_cfg.flip_test=False` in line 90 of [aflw_hrnetv2](../../../configs/face_2d_keypoint/topdown_heatmap/aflw/td-hm_hrnetv2-w18_8xb64-60e_aflw-256x256.py). diff --git a/demo/docs/2d_hand_demo.md b/demo/docs/en/2d_hand_demo.md similarity index 98% rename from demo/docs/2d_hand_demo.md rename to demo/docs/en/2d_hand_demo.md index 63f35de5c6..f47b3695e3 100644 --- a/demo/docs/2d_hand_demo.md +++ b/demo/docs/en/2d_hand_demo.md @@ -2,7 +2,7 @@ We provide a demo script to test a single image or video with hand detectors and top-down pose estimators. Assume that you have already installed [mmdet](https://github.com/open-mmlab/mmdetection) with version >= 3.0. -**Hand Box Model Preparation:** The pre-trained hand box estimation model can be found in [mmdet model zoo](/demo/docs/mmdet_modelzoo.md). +**Hand Box Model Preparation:** The pre-trained hand box estimation model can be found in [mmdet model zoo](/demo/docs/en/mmdet_modelzoo.md#hand-bounding-box-detection-models). ### 2D Hand Image Demo @@ -14,7 +14,6 @@ python demo/topdown_demo_with_mmdet.py \ [--show] [--device ${GPU_ID or CPU}] [--save-predictions] \ [--draw-heatmap ${DRAW_HEATMAP}] [--radius ${KPT_RADIUS}] \ [--kpt-thr ${KPT_SCORE_THR}] [--bbox-thr ${BBOX_SCORE_THR}] - ``` The pre-trained hand pose estimation model can be downloaded from [model zoo](https://mmpose.readthedocs.io/en/latest/model_zoo/hand_2d_keypoint.html). diff --git a/demo/docs/2d_human_pose_demo.md b/demo/docs/en/2d_human_pose_demo.md similarity index 100% rename from demo/docs/2d_human_pose_demo.md rename to demo/docs/en/2d_human_pose_demo.md diff --git a/demo/docs/2d_wholebody_pose_demo.md b/demo/docs/en/2d_wholebody_pose_demo.md similarity index 100% rename from demo/docs/2d_wholebody_pose_demo.md rename to demo/docs/en/2d_wholebody_pose_demo.md diff --git a/demo/docs/en/3d_human_pose_demo.md b/demo/docs/en/3d_human_pose_demo.md new file mode 100644 index 0000000000..367d98c403 --- /dev/null +++ b/demo/docs/en/3d_human_pose_demo.md @@ -0,0 +1,94 @@ +## 3D Human Pose Demo + +
+ +### 3D Human Pose Two-stage Estimation Demo + +#### Using mmdet for human bounding box detection and top-down model for the 1st stage (2D pose detection), and inference the 2nd stage (2D-to-3D lifting) + +Assume that you have already installed [mmdet](https://github.com/open-mmlab/mmdetection). + +```shell +python demo/body3d_pose_lifter_demo.py \ +${MMDET_CONFIG_FILE} \ +${MMDET_CHECKPOINT_FILE} \ +${MMPOSE_CONFIG_FILE_2D} \ +${MMPOSE_CHECKPOINT_FILE_2D} \ +${MMPOSE_CONFIG_FILE_3D} \ +${MMPOSE_CHECKPOINT_FILE_3D} \ +--input ${VIDEO_PATH or IMAGE_PATH or 'webcam'} \ +[--show] \ +[--rebase-keypoint-height] \ +[--norm-pose-2d] \ +[--num-instances] \ +[--output-root ${OUT_VIDEO_ROOT}] \ +[--save-predictions] +[--save-predictions] \ +[--device ${GPU_ID or CPU}] \ +[--det-cat-id DET_CAT_ID] \ +[--bbox-thr BBOX_THR] \ +[--kpt-thr KPT_THR] \ +[--use-oks-tracking] \ +[--tracking-thr TRACKING_THR] \ +[--show-interval INTERVAL] \ +[--thickness THICKNESS] \ +[--radius RADIUS] \ +[--use-multi-frames] [--online] +``` + +Note that + +1. `${VIDEO_PATH}` can be the local path or **URL** link to video file. + +2. You can turn on the `[--use-multi-frames]` option to use multi frames for inference in the 2D pose detection stage. + +3. If the `[--online]` option is set to **True**, future frame information can **not** be used when using multi frames for inference in the 2D pose detection stage. + +Examples: + +During 2D pose detection, for single-frame inference that do not rely on extra frames to get the final results of the current frame and save the prediction results, try this: + +```shell +python demo/body3d_pose_lifter_demo.py \ +demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py \ +https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \ +configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_8xb32-210e_coco-256x192.py \ +https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w48_coco_256x192-b9e0b3ab_20200708.pth \ +configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv-cpn-ft_8xb128-200e_h36m.py \ +https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised_cpn_ft-88f5abbb_20210527.pth \ +--input https://user-images.githubusercontent.com/87690686/164970135-b14e424c-765a-4180-9bc8-fa8d6abc5510.mp4 \ +--output-root vis_results \ +--rebase-keypoint-height --save-predictions +``` + +During 2D pose detection, for multi-frame inference that rely on extra frames to get the final results of the current frame, try this: + +```shell +python demo/body3d_pose_lifter_demo.py \ +demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py \ +https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \ +configs/body_2d_keypoint/topdown_heatmap/posetrack18/td-hm_hrnet-w48_8xb64-20e_posetrack18-384x288.py \ +https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w48_posetrack18_384x288-5fd6d3ff_20211130.pth \ +configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv-cpn-ft_8xb128-200e_h36m.py \ +https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised_cpn_ft-88f5abbb_20210527.pth \ +--input https://user-images.githubusercontent.com/87690686/164970135-b14e424c-765a-4180-9bc8-fa8d6abc5510.mp4 \ +--output-root vis_results \ +--rebase-keypoint-height \ +--use-multi-frames --online +``` + +### 3D Human Pose Demo with Inferencer + +The Inferencer provides a convenient interface for inference, allowing customization using model aliases instead of configuration files and checkpoint paths. It supports various input formats, including image paths, video paths, image folder paths, and webcams. Below is an example command: + +```shell +python demo/inferencer_demo.py tests/data/coco/000000000785.jpg \ + --pose3d human3d --vis-out-dir vis_results/human3d \ + --rebase-keypoint-height +``` + +This command infers the image and saves the visualization results in the `vis_results/human3d` directory. + +Image 1 + +In addition, the Inferencer supports saving predicted poses. For more information, please refer to the [inferencer document](https://mmpose.readthedocs.io/en/latest/user_guides/inference.html#inferencer-a-unified-inference-interface). diff --git a/demo/docs/mmdet_modelzoo.md b/demo/docs/en/mmdet_modelzoo.md similarity index 95% rename from demo/docs/mmdet_modelzoo.md rename to demo/docs/en/mmdet_modelzoo.md index a50be168a5..5383cb953f 100644 --- a/demo/docs/mmdet_modelzoo.md +++ b/demo/docs/en/mmdet_modelzoo.md @@ -7,7 +7,7 @@ MMDetection provides 80-class COCO-pretrained models, which already includes the ### Hand Bounding Box Detection Models -For hand bounding box detection, we simply train our hand box models on onehand10k dataset using MMDetection. +For hand bounding box detection, we simply train our hand box models on OneHand10K dataset using MMDetection. #### Hand detection results on OneHand10K test set @@ -19,7 +19,7 @@ For hand bounding box detection, we simply train our hand box models on onehand1 For face bounding box detection, we train a YOLOX detector on COCO-face data using MMDetection. -#### Hand detection results on OneHand10K test set +#### Face detection results on COCO-face test set | Arch | Box AP | ckpt | | :-------------------------------------------------------------- | :----: | :----------------------------------------------------------------------------------------------------: | @@ -29,8 +29,6 @@ For face bounding box detection, we train a YOLOX detector on COCO-face data usi #### COCO animals - - In COCO dataset, there are 80 object categories, including 10 common `animal` categories (14: 'bird', 15: 'cat', 16: 'dog', 17: 'horse', 18: 'sheep', 19: 'cow', 20: 'elephant', 21: 'bear', 22: 'zebra', 23: 'giraffe') For animals in the categories, please download from [MMDetection Model Zoo](https://mmdetection.readthedocs.io/en/3.x/model_zoo.html). diff --git a/demo/docs/en/webcam_api_demo.md b/demo/docs/en/webcam_api_demo.md new file mode 100644 index 0000000000..9869392171 --- /dev/null +++ b/demo/docs/en/webcam_api_demo.md @@ -0,0 +1,30 @@ +## Webcam Demo + +The original Webcam API has been deprecated starting from version v1.1.0. Users now have the option to utilize either the Inferencer or the demo script for conducting pose estimation using webcam input. + +### Webcam Demo with Inferencer + +Users can utilize the MMPose Inferencer to estimate human poses in webcam inputs by executing the following command: + +```shell +python demo/inferencer_demo.py webcam --pose2d 'human' +``` + +For additional information about the arguments of Inferencer, please refer to the [Inferencer Documentation](/docs/en/user_guides/inference.md). + +### Webcam Demo with Demo Script + +All of the demo scripts, except for `demo/image_demo.py`, support webcam input. + +Take `demo/topdown_demo_with_mmdet.py` as example, users can utilize this script with webcam input by specifying **`--input webcam`** in the command: + +```shell +# inference with webcam +python demo/topdown_demo_with_mmdet.py \ + projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ + projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ + --input webcam \ + --show +``` diff --git a/demo/docs/webcam_api_demo.md b/demo/docs/webcam_api_demo.md deleted file mode 100644 index ffc8922b13..0000000000 --- a/demo/docs/webcam_api_demo.md +++ /dev/null @@ -1,107 +0,0 @@ -## Webcam Demo - -We provide a webcam demo tool which integrartes detection and 2D pose estimation for humans and animals. It can also apply fun effects like putting on sunglasses or enlarging the eyes, based on the pose estimation results. - -
-
-
- -### Get started - -Launch the demo from the mmpose root directory: - -```shell -# Run webcam demo with GPU -python demo/webcam_api_demo.py - -# Run webcam demo with CPU -python demo/webcam_api_demo.py --cpu -``` - -The command above will use the default config file `demo/webcam_cfg/pose_estimation.py`. You can also specify the config file in the command: - -```shell -# Use the config "pose_tracking.py" for higher infererence speed -python demo/webcam_api_demo.py --config demo/webcam_cfg/pose_estimation.py -``` - -### Hotkeys - -| Hotkey | Function | -| ------ | ------------------------------------- | -| v | Toggle the pose visualization on/off. | -| s | Toggle the sunglasses effect on/off. | -| b | Toggle the big-eye effect on/off. | -| h | Show help information. | -| m | Show the monitoring information. | -| q | Exit. | - -Note that the demo will automatically save the output video into a file `webcam_api_demo.mp4`. - -### Usage and configuarations - -Detailed configurations can be found in the config file. - -- **Configure detection models** - Users can choose detection models from the [MMDetection Model Zoo](https://mmdetection.readthedocs.io/en/3.x/model_zoo.html). Just set the `model_config` and `model_checkpoint` in the detector node accordingly, and the model will be automatically downloaded and loaded. - - ```python - # 'DetectorNode': - # This node performs object detection from the frame image using an - # MMDetection model. - dict( - type='DetectorNode', - name='detector', - model_config='demo/mmdetection_cfg/' - 'ssdlite_mobilenetv2-scratch_8xb24-600e_coco.py', - model_checkpoint='https://download.openmmlab.com' - '/mmdetection/v2.0/ssd/' - 'ssdlite_mobilenetv2_scratch_600e_coco/ssdlite_mobilenetv2_' - 'scratch_600e_coco_20210629_110627-974d9307.pth', - input_buffer='_input_', - output_buffer='det_result'), - ``` - -- **Configure pose estimation models** - In this demo we use two [top-down](https://github.com/open-mmlab/mmpose/tree/latest/configs/body_2d_keypoint/topdown_heatmap) pose estimation models for humans and animals respectively. Users can choose models from the [MMPose Model Zoo](https://mmpose.readthedocs.io/en/latest/modelzoo.html). To apply different pose models on different instance types, you can add multiple pose estimator nodes with `cls_names` set accordingly. - - ```python - # 'TopdownPoseEstimatorNode': - # This node performs keypoint detection from the frame image using an - # MMPose top-down model. Detection results is needed. - dict( - type='TopdownPoseEstimatorNode', - name='human pose estimator', - model_config='configs/wholebody_2d_keypoint/' - 'topdown_heatmap/coco-wholebody/' - 'td-hm_vipnas-mbv3_dark-8xb64-210e_coco-wholebody-256x192.py', - model_checkpoint='https://download.openmmlab.com/mmpose/' - 'top_down/vipnas/vipnas_mbv3_coco_wholebody_256x192_dark' - '-e2158108_20211205.pth', - labels=['person'], - input_buffer='det_result', - output_buffer='human_pose'), - dict( - type='TopdownPoseEstimatorNode', - name='animal pose estimator', - model_config='configs/animal_2d_keypoint/topdown_heatmap/' - 'animalpose/td-hm_hrnet-w32_8xb64-210e_animalpose-256x256.py', - model_checkpoint='https://download.openmmlab.com/mmpose/animal/' - 'hrnet/hrnet_w32_animalpose_256x256-1aa7f075_20210426.pth', - labels=['cat', 'dog', 'horse', 'sheep', 'cow'], - input_buffer='human_pose', - output_buffer='animal_pose'), - ``` - -- **Run the demo on a local video file** - You can use local video files as the demo input by set `camera_id` to the file path. - -- **The computer doesn't have a camera?** - A smart phone can serve as a webcam via apps like [Camo](https://reincubate.com/camo/) or [DroidCam](https://www.dev47apps.com/). - -- **Test the camera and display** - Run follow command for a quick test of video capturing and displaying. - - ```shell - python demo/webcam_api_demo.py --config demo/webcam_cfg/test_camera.py - ``` diff --git a/demo/docs/zh_cn/2d_animal_demo.md b/demo/docs/zh_cn/2d_animal_demo.md new file mode 100644 index 0000000000..e49f292f56 --- /dev/null +++ b/demo/docs/zh_cn/2d_animal_demo.md @@ -0,0 +1,124 @@ +## 2D Animal Pose Demo + +本系列文档我们会来介绍如何使用提供了的脚本进行完成基本的推理 demo ,本节先介绍如何对 top-down 结构和动物的 2D 姿态进行单张图片和视频推理,请确保你已经安装了 3.0 以上版本的 [MMDetection](https://github.com/open-mmlab/mmdetection) 。 + +### 2D 动物图片姿态识别推理 + +```shell +python demo/topdown_demo_with_mmdet.py \ + ${MMDET_CONFIG_FILE} ${MMDET_CHECKPOINT_FILE} \ + ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \ + --input ${INPUT_PATH} --det-cat-id ${DET_CAT_ID} \ + [--show] [--output-root ${OUTPUT_DIR}] [--save-predictions] \ + [--draw-heatmap ${DRAW_HEATMAP}] [--radius ${KPT_RADIUS}] \ + [--kpt-thr ${KPT_SCORE_THR}] [--bbox-thr ${BBOX_SCORE_THR}] \ + [--device ${GPU_ID or CPU}] +``` + +用户可以在 [model zoo](https://mmpose.readthedocs.io/zh_CN/dev-1.x/model_zoo/animal_2d_keypoint.html) 获取预训练好的关键点识别模型。 + +这里我们用 [animalpose model](https://download.openmmlab.com/mmpose/animal/hrnet/hrnet_w32_animalpose_256x256-1aa7f075_20210426.pth) 来进行演示: + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py \ + https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \ + configs/animal_2d_keypoint/topdown_heatmap/animalpose/td-hm_hrnet-w32_8xb64-210e_animalpose-256x256.py \ + https://download.openmmlab.com/mmpose/animal/hrnet/hrnet_w32_animalpose_256x256-1aa7f075_20210426.pth \ + --input tests/data/animalpose/ca110.jpeg \ + --show --draw-heatmap --det-cat-id=15 +``` + +可视化结果如下: + +
+ +如果使用了 heatmap-based 模型同时设置了 `--draw-heatmap` ,预测的热图也会跟随关键点一同可视化出来。 + +`--det-cat-id=15` 参数用来指定模型只检测 `cat` 类型,这是基于 COCO 数据集的数据。 + +**COCO 数据集动物信息** + +COCO 数据集共包含 80 个类别,其中有 10 种常见动物,类别如下: + +(14: 'bird', 15: 'cat', 16: 'dog', 17: 'horse', 18: 'sheep', 19: 'cow', 20: 'elephant', 21: 'bear', 22: 'zebra', 23: 'giraffe') + +对于其他类型的动物,我们也提供了一些训练好的动物检测模型,用户可以前往 [detection model zoo](/demo/docs/zh_cn/mmdet_modelzoo.md) 下载。 + +如果想本地保存可视化结果可使用如下命令: + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py \ + https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \ + configs/animal_2d_keypoint/topdown_heatmap/animalpose/td-hm_hrnet-w32_8xb64-210e_animalpose-256x256.py \ + https://download.openmmlab.com/mmpose/animal/hrnet/hrnet_w32_animalpose_256x256-1aa7f075_20210426.pth \ + --input tests/data/animalpose/ca110.jpeg \ + --output-root vis_results --draw-heatmap --det-cat-id=15 +``` + +如果想本地保存预测结果,需要使用 `--save-predictions` 。 + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py \ + https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \ + configs/animal_2d_keypoint/topdown_heatmap/animalpose/td-hm_hrnet-w32_8xb64-210e_animalpose-256x256.py \ + https://download.openmmlab.com/mmpose/animal/hrnet/hrnet_w32_animalpose_256x256-1aa7f075_20210426.pth \ + --input tests/data/animalpose/ca110.jpeg \ + --output-root vis_results --save-predictions --draw-heatmap --det-cat-id=15 +``` + +仅使用 CPU: + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py \ + https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \ + configs/animal_2d_keypoint/topdown_heatmap/animalpose/td-hm_hrnet-w32_8xb64-210e_animalpose-256x256.py \ + https://download.openmmlab.com/mmpose/animal/hrnet/hrnet_w32_animalpose_256x256-1aa7f075_20210426.pth \ + --input tests/data/animalpose/ca110.jpeg \ + --show --draw-heatmap --det-cat-id=15 --device cpu +``` + +### 2D 动物视频姿态识别推理 + +视频和图片使用了同样的接口,区别在于视频推理时 `${INPUT_PATH}` 既可以是本地视频文件的路径也可以是视频文件的 **URL** 地址。 + +例如: + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py \ + https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \ + configs/animal_2d_keypoint/topdown_heatmap/animalpose/td-hm_hrnet-w32_8xb64-210e_animalpose-256x256.py \ + https://download.openmmlab.com/mmpose/animal/hrnet/hrnet_w32_animalpose_256x256-1aa7f075_20210426.pth \ + --input demo/resources/ \ + --output-root vis_results --draw-heatmap --det-cat-id=16 +``` + +
+ +这段视频可以在 [Google Drive](https://drive.google.com/file/d/18d8K3wuUpKiDFHvOx0mh1TEwYwpOc5UO/view?usp=sharing) 下载。 + +### 使用 Inferencer 进行 2D 动物姿态识别推理 + +Inferencer 提供一个更便捷的推理接口,使得用户可以绕过模型的配置文件和 checkpoint 路径直接使用 model aliases ,支持包括图片路径、视频路径、图片文件夹路径和 webcams 在内的多种输入方式,例如可以这样使用: + +```shell +python demo/inferencer_demo.py tests/data/ap10k \ + --pose2d animal --vis-out-dir vis_results/ap10k +``` + +该命令会对输入的 `tests/data/ap10k` 下所有的图片进行推理并且把可视化结果都存入 `vis_results/ap10k` 文件夹下。 + +Image 1 Image 2 + +Inferencer 同样支持保存预测结果,更多的信息可以参考 [Inferencer 文档](https://mmpose.readthedocs.io/en/dev-1.x/user_guides/inference.html#inferencer-a-unified-inference-interface) 。 + +### 加速推理 + +用户可以通过修改配置文件来加速,更多具体例子可以参考: + +1. 设置 `model.test_cfg.flip_test=False`,如 [animalpose_hrnet-w32](../../configs/animal_2d_keypoint/topdown_heatmap/animalpose/td-hm_hrnet-w32_8xb64-210e_animalpose-256x256.py#85) 所示。 +2. 使用更快的 bounding box 检测器,可参考 [MMDetection](https://mmdetection.readthedocs.io/zh_CN/3.x/model_zoo.html) 。 diff --git a/demo/docs/zh_cn/2d_face_demo.md b/demo/docs/zh_cn/2d_face_demo.md new file mode 100644 index 0000000000..e8a4e550db --- /dev/null +++ b/demo/docs/zh_cn/2d_face_demo.md @@ -0,0 +1,88 @@ +## 2D Face Keypoint Demo + +本节我们继续演示如何使用 demo 脚本进行 2D 脸部关键点的识别。同样的,用户仍要确保开发环境已经安装了 3.0 版本以上的 [MMdetection](https://github.com/open-mmlab/mmdetection) 。 + +我们在 [mmdet model zoo](/demo/docs/zh_cn/mmdet_modelzoo.md#脸部-bounding-box-检测模型) 提供了一个预训练好的脸部 Bounding Box 预测模型,用户可以前往下载。 + +### 2D 脸部图片关键点识别推理 + +```shell +python demo/topdown_demo_with_mmdet.py \ + ${MMDET_CONFIG_FILE} ${MMDET_CHECKPOINT_FILE} \ + ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \ + --input ${INPUT_PATH} [--output-root ${OUTPUT_DIR}] \ + [--show] [--device ${GPU_ID or CPU}] [--save-predictions] \ + [--draw-heatmap ${DRAW_HEATMAP}] [--radius ${KPT_RADIUS}] \ + [--kpt-thr ${KPT_SCORE_THR}] [--bbox-thr ${BBOX_SCORE_THR}] +``` + +用户可以在 [model zoo](https://mmpose.readthedocs.io/en/dev-1.x/model_zoo/face_2d_keypoint.html) 获取预训练好的脸部关键点识别模型。 + +这里我们用 [aflw model](https://download.openmmlab.com/mmpose/face/hrnetv2/hrnetv2_w18_aflw_256x256-f2bbc62b_20210125.pth) 来进行演示: + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/yolox-s_8xb8-300e_coco-face.py \ + https://download.openmmlab.com/mmpose/mmdet_pretrained/yolo-x_8xb8-300e_coco-face_13274d7c.pth \ + configs/face_2d_keypoint/topdown_heatmap/aflw/td-hm_hrnetv2-w18_8xb64-60e_aflw-256x256.py \ + https://download.openmmlab.com/mmpose/face/hrnetv2/hrnetv2_w18_aflw_256x256-f2bbc62b_20210125.pth \ + --input tests/data/cofw/001766.jpg \ + --show --draw-heatmap +``` + +可视化结果如下图所示: + +
+ +如果使用了 heatmap-based 模型同时设置了 `--draw-heatmap` ,预测的热图也会跟随关键点一同可视化出来。 + +如果想本地保存可视化结果可使用如下命令: + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/yolox-s_8xb8-300e_coco-face.py \ + https://download.openmmlab.com/mmpose/mmdet_pretrained/yolo-x_8xb8-300e_coco-face_13274d7c.pth \ + configs/face_2d_keypoint/topdown_heatmap/aflw/td-hm_hrnetv2-w18_8xb64-60e_aflw-256x256.py \ + https://download.openmmlab.com/mmpose/face/hrnetv2/hrnetv2_w18_aflw_256x256-f2bbc62b_20210125.pth \ + --input tests/data/cofw/001766.jpg \ + --draw-heatmap --output-root vis_results +``` + +### 2D 脸部视频关键点识别推理 + +视频和图片使用了同样的接口,区别在于视频推理时 `${INPUT_PATH}` 既可以是本地视频文件的路径也可以是视频文件的 **URL** 地址。 + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/yolox-s_8xb8-300e_coco-face.py \ + https://download.openmmlab.com/mmpose/mmdet_pretrained/yolo-x_8xb8-300e_coco-face_13274d7c.pth \ + configs/face_2d_keypoint/topdown_heatmap/aflw/td-hm_hrnetv2-w18_8xb64-60e_aflw-256x256.py \ + https://download.openmmlab.com/mmpose/face/hrnetv2/hrnetv2_w18_aflw_256x256-f2bbc62b_20210125.pth \ + --input demo/resources/ \ + --show --draw-heatmap --output-root vis_results +``` + +
+ +这段视频可以在 [Google Drive](https://drive.google.com/file/d/1kQt80t6w802b_vgVcmiV_QfcSJ3RWzmb/view?usp=sharing) 下载。 + +### 使用 Inferencer 进行 2D 脸部关键点识别推理 + +Inferencer 提供一个更便捷的推理接口,使得用户可以绕过模型的配置文件和 checkpoint 路径直接使用 model aliases ,支持包括图片路径、视频路径、图片文件夹路径和 webcams 在内的多种输入方式,例如可以这样使用: + +```shell +python demo/inferencer_demo.py tests/data/wflw \ + --pose2d face --vis-out-dir vis_results/wflw --radius 1 +``` + +该命令会对输入的 `tests/data/wflw` 下所有的图片进行推理并且把可视化结果都存入 `vis_results/wflw` 文件夹下。 + +Image 1 + +Image 2 + +除此之外, Inferencer 也支持保存预测的姿态结果。具体信息可在 [Inferencer 文档](https://mmpose.readthedocs.io/en/dev-1.x/user_guides/inference.html#inferencer-a-unified-inference-interface) 查看。 + +### 加速推理 + +对于 2D 脸部关键点预测模型,用户可以通过修改配置文件中的 `model.test_cfg.flip_test=False` 来加速,例如 [aflw_hrnetv2](../../../configs/face_2d_keypoint/topdown_heatmap/aflw/td-hm_hrnetv2-w18_8xb64-60e_aflw-256x256.py) 中的第 90 行。 diff --git a/demo/docs/zh_cn/2d_hand_demo.md b/demo/docs/zh_cn/2d_hand_demo.md new file mode 100644 index 0000000000..c2d80edd4e --- /dev/null +++ b/demo/docs/zh_cn/2d_hand_demo.md @@ -0,0 +1,101 @@ +## 2D Hand Keypoint Demo + +本节我们继续通过 demo 脚本演示对单张图片或者视频的 2D 手部关键点的识别。同样的,用户仍要确保开发环境已经安装了 3.0 版本以上的 [MMDetection](https://github.com/open-mmlab/mmdetection) 。 + +我们在 [mmdet model zoo](/demo/docs/zh_cn/mmdet_modelzoo.md#手部-bounding-box-识别模型) 提供了预训练好的手部 Bounding Box 预测模型,用户可以前往下载。 + +### 2D 手部图片关键点识别 + +```shell +python demo/topdown_demo_with_mmdet.py \ + ${MMDET_CONFIG_FILE} ${MMDET_CHECKPOINT_FILE} \ + ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \ + --input ${INPUT_PATH} [--output-root ${OUTPUT_DIR}] \ + [--show] [--device ${GPU_ID or CPU}] [--save-predictions] \ + [--draw-heatmap ${DRAW_HEATMAP}] [--radius ${KPT_RADIUS}] \ + [--kpt-thr ${KPT_SCORE_THR}] [--bbox-thr ${BBOX_SCORE_THR}] +``` + +用户可以在 [model zoo](https://mmpose.readthedocs.io/zh_CN/dev-1.x/model_zoo/hand_2d_keypoint.html) 获取预训练好的关键点识别模型。 + +这里我们用 [onehand10k model](https://download.openmmlab.com/mmpose/hand/hrnetv2/hrnetv2_w18_onehand10k_256x256-30bc9c6b_20210330.pth) 来进行演示: + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/cascade_rcnn_x101_64x4d_fpn_1class.py \ + https://download.openmmlab.com/mmpose/mmdet_pretrained/cascade_rcnn_x101_64x4d_fpn_20e_onehand10k-dac19597_20201030.pth \ + configs/hand_2d_keypoint/topdown_heatmap/onehand10k/td-hm_hrnetv2-w18_8xb64-210e_onehand10k-256x256.py \ + https://download.openmmlab.com/mmpose/hand/hrnetv2/hrnetv2_w18_onehand10k_256x256-30bc9c6b_20210330.pth \ + --input tests/data/onehand10k/9.jpg \ + --show --draw-heatmap +``` + +可视化结果如下: + +
+ +如果使用了 heatmap-based 模型同时设置了 `--draw-heatmap` ,预测的热图也会跟随关键点一同可视化出来。 + +如果想本地保存可视化结果可使用如下命令: + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/cascade_rcnn_x101_64x4d_fpn_1class.py \ + https://download.openmmlab.com/mmpose/mmdet_pretrained/cascade_rcnn_x101_64x4d_fpn_20e_onehand10k-dac19597_20201030.pth \ + configs/hand_2d_keypoint/topdown_heatmap/onehand10k/td-hm_hrnetv2-w18_8xb64-210e_onehand10k-256x256.py \ + https://download.openmmlab.com/mmpose/hand/hrnetv2/hrnetv2_w18_onehand10k_256x256-30bc9c6b_20210330.pth \ + --input tests/data/onehand10k/9.jpg \ + --output-root vis_results --show --draw-heatmap +``` + +如果想本地保存预测结果,需要添加 `--save-predictions` 。 + +如果想用 CPU 进行 demo 需添加 `--device cpu` : + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/cascade_rcnn_x101_64x4d_fpn_1class.py \ + https://download.openmmlab.com/mmpose/mmdet_pretrained/cascade_rcnn_x101_64x4d_fpn_20e_onehand10k-dac19597_20201030.pth \ + configs/hand_2d_keypoint/topdown_heatmap/onehand10k/td-hm_hrnetv2-w18_8xb64-210e_onehand10k-256x256.py \ + https://download.openmmlab.com/mmpose/hand/hrnetv2/hrnetv2_w18_onehand10k_256x256-30bc9c6b_20210330.pth \ + --input tests/data/onehand10k/9.jpg \ + --show --draw-heatmap --device cpu +``` + +### 2D 手部视频关键点识别推理 + +视频和图片使用了同样的接口,区别在于视频推理时 `${INPUT_PATH}` 既可以是本地视频文件的路径也可以是视频文件的 **URL** 地址。 + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/cascade_rcnn_x101_64x4d_fpn_1class.py \ + https://download.openmmlab.com/mmpose/mmdet_pretrained/cascade_rcnn_x101_64x4d_fpn_20e_onehand10k-dac19597_20201030.pth \ + configs/hand_2d_keypoint/topdown_heatmap/onehand10k/td-hm_hrnetv2-w18_8xb64-210e_onehand10k-256x256.py \ + https://download.openmmlab.com/mmpose/hand/hrnetv2/hrnetv2_w18_onehand10k_256x256-30bc9c6b_20210330.pth \ + --input demo/resources/ \ + --output-root vis_results --show --draw-heatmap +``` + +
+ +这段视频可以在 [Google Drive](https://raw.githubusercontent.com/open-mmlab/mmpose/master/tests/data/nvgesture/sk_color.avi) 下载到。 + +### 使用 Inferencer 进行 2D 手部关键点识别推理 + +Inferencer 提供一个更便捷的推理接口,使得用户可以绕过模型的配置文件和 checkpoint 路径直接使用 model aliases ,支持包括图片路径、视频路径、图片文件夹路径和 webcams 在内的多种输入方式,例如可以这样使用: + +```shell +python demo/inferencer_demo.py tests/data/onehand10k \ + --pose2d hand --vis-out-dir vis_results/onehand10k \ + --bbox-thr 0.5 --kpt-thr 0.05 +``` + +该命令会对输入的 `tests/data/onehand10k` 下所有的图片进行推理并且把可视化结果都存入 `vis_results/onehand10k` 文件夹下。 + +Image 1 Image 2 Image 3 Image 4 + +除此之外, Inferencer 也支持保存预测的姿态结果。具体信息可在 [Inferencer 文档](https://mmpose.readthedocs.io/zh_CN/dev-1.x/user_guides/inference.html) 查看。 + +### 加速推理 + +对于 2D 手部关键点预测模型,用户可以通过修改配置文件中的 `model.test_cfg.flip_test=False` 来加速,如 [onehand10k_hrnetv2](../../configs/hand_2d_keypoint/topdown_heatmap/onehand10k/td-hm_hrnetv2-w18_8xb64-210e_onehand10k-256x256.py#90) 所示。 diff --git a/demo/docs/zh_cn/2d_human_pose_demo.md b/demo/docs/zh_cn/2d_human_pose_demo.md new file mode 100644 index 0000000000..ff6484301a --- /dev/null +++ b/demo/docs/zh_cn/2d_human_pose_demo.md @@ -0,0 +1,146 @@ +## 2D Human Pose Demo + +本节我们继续使用 demo 脚本演示 2D 人体关键点的识别。同样的,用户仍要确保开发环境已经安装了 3.0 版本以上的 [mmdet](https://github.com/open-mmlab/mmdetection) 。 + +### 2D 人体姿态 Top-Down 图片检测 + +#### 使用整张图片作为输入进行检测 + +此时输入的整张图片会被当作 bounding box 使用。 + +```shell +python demo/image_demo.py \ + ${IMG_FILE} ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \ + --out-file ${OUTPUT_FILE} \ + [--device ${GPU_ID or CPU}] \ + [--draw_heatmap] +``` + +如果使用了 heatmap-based 模型同时设置了 `--draw-heatmap` ,预测的热图也会跟随关键点一同可视化出来。 + +用户可以在 [model zoo](https://mmpose.readthedocs.io/zh_CN/latest/model_zoo/body_2d_keypoint.html) 获取预训练好的关键点识别模型。 + +这里我们用 [coco model](https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w48_coco_256x192-b9e0b3ab_20200708.pth) 来进行演示: + +```shell +python demo/image_demo.py \ + tests/data/coco/000000000785.jpg \ + configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_8xb32-210e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w48_coco_256x192-b9e0b3ab_20200708.pth \ + --out-file vis_results.jpg \ + --draw-heatmap +``` + +使用 CPU 推理: + +```shell +python demo/image_demo.py \ + tests/data/coco/000000000785.jpg \ + configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_8xb32-210e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w48_coco_256x192-b9e0b3ab_20200708.pth \ + --out-file vis_results.jpg \ + --draw-heatmap \ + --device=cpu +``` + +可视化结果如下: + +
+ +#### 使用 MMDet 做人体 bounding box 检测 + +使用 MMDet 进行识别的命令如下所示: + +```shell +python demo/topdown_demo_with_mmdet.py \ + ${MMDET_CONFIG_FILE} ${MMDET_CHECKPOINT_FILE} \ + ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \ + --input ${INPUT_PATH} \ + [--output-root ${OUTPUT_DIR}] [--save-predictions] \ + [--show] [--draw-heatmap] [--device ${GPU_ID or CPU}] \ + [--bbox-thr ${BBOX_SCORE_THR}] [--kpt-thr ${KPT_SCORE_THR}] +``` + +结合我们的具体例子: + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py \ + https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \ + configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w32_coco_256x192-c78dce93_20200708.pth \ + --input tests/data/coco/000000197388.jpg --show --draw-heatmap \ + --output-root vis_results/ +``` + +可视化结果如下: + +
+ +想要本地保存识别结果,用户需要加上 `--save-predictions` 。 + +### 2D 人体姿态 Top-Down 视频检测 + +我们的脚本同样支持视频作为输入,由 MMDet 完成人体检测后 MMPose 完成 Top-Down 的姿态预估,视频推理时 `${INPUT_PATH}` 既可以是本地视频文件的路径也可以是视频文件的 **URL** 地址。 + +例如: + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py \ + https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \ + configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192-81c58e40_20220909.pth \ + --input tests/data/posetrack18/videos/000001_mpiinew_test/000001_mpiinew_test.mp4 \ + --output-root=vis_results/demo --show --draw-heatmap +``` + +### 2D 人体姿态 Bottom-Up 图片和视频识别检测 + +除了 Top-Down ,我们也支持 Bottom-Up 不依赖人体识别器的人体姿态预估识别,使用方式如下: + +```shell +python demo/bottomup_demo.py \ + ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \ + --input ${INPUT_PATH} \ + [--output-root ${OUTPUT_DIR}] [--save-predictions] \ + [--show] [--device ${GPU_ID or CPU}] \ + [--kpt-thr ${KPT_SCORE_THR}] +``` + +结合具体示例如下: + +```shell +python demo/bottomup_demo.py \ + configs/body_2d_keypoint/dekr/coco/dekr_hrnet-w32_8xb10-140e_coco-512x512.py \ + https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/dekr/coco/dekr_hrnet-w32_8xb10-140e_coco-512x512_ac7c17bf-20221228.pth \ + --input tests/data/coco/000000197388.jpg --output-root=vis_results \ + --show --save-predictions +``` + +其可视化结果如图所示: + +
+ +### 使用 Inferencer 进行 2D 人体姿态识别检测 + +Inferencer 提供一个更便捷的推理接口,使得用户可以绕过模型的配置文件和 checkpoint 路径直接使用 model aliases ,支持包括图片路径、视频路径、图片文件夹路径和 webcams 在内的多种输入方式,例如可以这样使用: + +```shell +python demo/inferencer_demo.py \ + tests/data/posetrack18/videos/000001_mpiinew_test/000001_mpiinew_test.mp4 \ + --pose2d human --vis-out-dir vis_results/posetrack18 +``` + +该命令会对输入的 `tests/data/posetrack18` 下的视频进行推理并且把可视化结果存入 `vis_results/posetrack18` 文件夹下。 + +Image 1 + +Inferencer 支持保存姿态的检测结果,具体的使用可参考 [inferencer document](https://mmpose.readthedocs.io/zh_CN/dev-1.x/user_guides/inference.html) 。 + +### 加速推理 + +对于 top-down 结构的模型,用户可以通过修改配置文件来加速,更多具体例子可以参考: + +1. 设置 `model.test_cfg.flip_test=False`,如 [topdown-res50](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_res50_8xb64-210e_coco-256x192.py#L56) 所示。 +2. 使用更快的人体 bounding box 检测器,可参考 [MMDetection](https://mmdetection.readthedocs.io/zh_CN/3.x/model_zoo.html) 。 diff --git a/demo/docs/zh_cn/2d_wholebody_pose_demo.md b/demo/docs/zh_cn/2d_wholebody_pose_demo.md new file mode 100644 index 0000000000..8c901d47fa --- /dev/null +++ b/demo/docs/zh_cn/2d_wholebody_pose_demo.md @@ -0,0 +1,108 @@ +## 2D Human Whole-Body Pose Demo + +### 2D 人体全身姿态 Top-Down 图片识别 + +#### 使用整张图片作为输入进行检测 + +此时输入的整张图片会被当作 bounding box 使用。 + +```shell +python demo/image_demo.py \ + ${IMG_FILE} ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \ + --out-file ${OUTPUT_FILE} \ + [--device ${GPU_ID or CPU}] \ + [--draw_heatmap] +``` + +用户可以在 [model zoo](https://mmpose.readthedocs.io/zh_CN/dev-1.x/model_zoo/2d_wholebody_keypoint.html) 获取预训练好的关键点识别模型。 + +这里我们用 [coco-wholebody_vipnas_res50_dark](https://download.openmmlab.com/mmpose/top_down/vipnas/vipnas_res50_wholebody_256x192_dark-67c0ce35_20211112.pth) 来进行演示: + +```shell +python demo/image_demo.py \ + tests/data/coco/000000000785.jpg \ + configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/td-hm_vipnas-res50_dark-8xb64-210e_coco-wholebody-256x192.py \ + https://download.openmmlab.com/mmpose/top_down/vipnas/vipnas_res50_wholebody_256x192_dark-67c0ce35_20211112.pth \ + --out-file vis_results.jpg +``` + +使用 CPU 推理: + +```shell +python demo/image_demo.py \ + tests/data/coco/000000000785.jpg \ + configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/td-hm_vipnas-res50_dark-8xb64-210e_coco-wholebody-256x192.py \ + https://download.openmmlab.com/mmpose/top_down/vipnas/vipnas_res50_wholebody_256x192_dark-67c0ce35_20211112.pth \ + --out-file vis_results.jpg \ + --device=cpu +``` + +#### 使用 MMDet 进行人体 bounding box 检测 + +使用 MMDet 进行识别的命令格式如下: + +```shell +python demo/topdown_demo_with_mmdet.py \ + ${MMDET_CONFIG_FILE} ${MMDET_CHECKPOINT_FILE} \ + ${MMPOSE_CONFIG_FILE} ${MMPOSE_CHECKPOINT_FILE} \ + --input ${INPUT_PATH} \ + [--output-root ${OUTPUT_DIR}] [--save-predictions] \ + [--show] [--draw-heatmap] [--device ${GPU_ID or CPU}] \ + [--bbox-thr ${BBOX_SCORE_THR}] [--kpt-thr ${KPT_SCORE_THR}] +``` + +具体可例如: + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py \ + https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \ + configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/td-hm_hrnet-w48_dark-8xb32-210e_coco-wholebody-384x288.py \ + https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w48_coco_wholebody_384x288_dark-f5726563_20200918.pth \ + --input tests/data/coco/000000196141.jpg \ + --output-root vis_results/ --show +``` + +想要本地保存识别结果,用户需要加上 `--save-predictions` 。 + +### 2D 人体全身姿态 Top-Down 视频识别检测 + +我们的脚本同样支持视频作为输入,由 MMDet 完成人体检测后 MMPose 完成 Top-Down 的姿态预估。 + +例如: + +```shell +python demo/topdown_demo_with_mmdet.py \ + demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py \ + https://download.openmmlab.com/mmdetection/v2.0/faster_rcnn/faster_rcnn_r50_fpn_1x_coco/faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth \ + configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/td-hm_hrnet-w48_dark-8xb32-210e_coco-wholebody-384x288.py \ + https://download.openmmlab.com/mmpose/top_down/hrnet/hrnet_w48_coco_wholebody_384x288_dark-f5726563_20200918.pth \ + --input https://user-images.githubusercontent.com/87690686/137440639-fb08603d-9a35-474e-b65f-46b5c06b68d6.mp4 \ + --output-root vis_results/ --show +``` + +可视化结果如下: + +
+ +### 使用 Inferencer 进行 2D 人体全身姿态识别 + +Inferencer 提供一个更便捷的推理接口,使得用户可以绕过模型的配置文件和 checkpoint 路径直接使用 model aliases ,支持包括图片路径、视频路径、图片文件夹路径和 webcams 在内的多种输入方式,例如可以这样使用: + +```shell +python demo/inferencer_demo.py tests/data/crowdpose \ + --pose2d wholebody --vis-out-dir vis_results/crowdpose +``` + +该命令会对输入的 `tests/data/crowdpose` 下所有图片进行推理并且把可视化结果存入 `vis_results/crowdpose` 文件夹下。 + +Image 1 Image 2 + +Inferencer 支持保存姿态的检测结果,具体的使用可参考 [Inferencer 文档](https://mmpose.readthedocs.io/zh_CN/dev-1.x/user_guides/#inferencer-a-unified-inference-interface) 。 + +### 加速推理 + +对于 top-down 结构的模型,用户可以通过修改配置文件来加速,更多具体例子可以参考: + +1. 设置 `model.test_cfg.flip_test=False`,用户可参考 [pose_hrnet_w48_dark+](/configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/td-hm_hrnet-w48_dark-8xb32-210e_coco-wholebody-384x288.py#L90) 。 +2. 使用更快的人体 bounding box 检测器,如 [MMDetection](https://mmdetection.readthedocs.io/zh_CN/3.x/model_zoo.html) 。 diff --git a/demo/docs/zh_cn/3d_human_pose_demo.md b/demo/docs/zh_cn/3d_human_pose_demo.md new file mode 100644 index 0000000000..6ed9dd67de --- /dev/null +++ b/demo/docs/zh_cn/3d_human_pose_demo.md @@ -0,0 +1 @@ +coming soon diff --git a/demo/docs/zh_cn/mmdet_modelzoo.md b/demo/docs/zh_cn/mmdet_modelzoo.md new file mode 100644 index 0000000000..aabfb1768d --- /dev/null +++ b/demo/docs/zh_cn/mmdet_modelzoo.md @@ -0,0 +1,42 @@ +## Pre-trained Detection Models + +### 人体 Bounding Box 检测模型 + +MMDetection 提供了基于 COCO 的包括 `person` 在内的 80 个类别的预训练模型,用户可前往 [MMDetection Model Zoo](https://mmdetection.readthedocs.io/zh_CN/3.x/model_zoo.html) 下载并将其用作人体 bounding box 识别模型。 + +### 手部 Bounding Box 检测模型 + +对于手部 bounding box 检测模型,我们提供了一个通过 MMDetection 基于 OneHand10K 数据库训练的模型。 + +#### 基于 OneHand10K 测试集的测试结果 + +| Arch | Box AP | ckpt | log | +| :---------------------------------------------------------------- | :----: | :---------------------------------------------------------------: | :--------------------------------------------------------------: | +| [Cascade_R-CNN X-101-64x4d-FPN-1class](/demo/mmdetection_cfg/cascade_rcnn_x101_64x4d_fpn_1class.py) | 0.817 | [ckpt](https://download.openmmlab.com/mmpose/mmdet_pretrained/cascade_rcnn_x101_64x4d_fpn_20e_onehand10k-dac19597_20201030.pth) | [log](https://download.openmmlab.com/mmpose/mmdet_pretrained/cascade_rcnn_x101_64x4d_fpn_20e_onehand10k_20201030.log.json) | + +### 脸部 Bounding Box 检测模型 + +对于脸部 bounding box 检测模型,我们提供了一个通过 MMDetection 基于 COCO-Face 数据库训练的 YOLOX 检测器。 + +#### 基于 COCO-face 测试集的测试结果 + +| Arch | Box AP | ckpt | +| :-------------------------------------------------------------- | :----: | :----------------------------------------------------------------------------------------------------: | +| [YOLOX-s](/demo/mmdetection_cfg/yolox-s_8xb8-300e_coco-face.py) | 0.408 | [ckpt](https://download.openmmlab.com/mmpose/mmdet_pretrained/yolo-x_8xb8-300e_coco-face_13274d7c.pth) | + +### 动物 Bounding Box 检测模型 + +#### COCO animals + +COCO 数据集内包括了 10 种常见的 `animal` 类型: + +(14: 'bird', 15: 'cat', 16: 'dog', 17: 'horse', 18: 'sheep', 19: 'cow', 20: 'elephant', 21: 'bear', 22: 'zebra', 23: 'giraffe') 。 + +用户如果需要使用以上类别的动物检测模型,可以前往 [MMDetection Model Zoo](https://mmdetection.readthedocs.io/zh_CN/3.x/model_zoo.html) 下载。 + +#### 基于 MacaquePose 测试集的测试结果 + +| Arch | Box AP | ckpt | log | +| :---------------------------------------------------------------- | :----: | :---------------------------------------------------------------: | :--------------------------------------------------------------: | +| [Faster_R-CNN_Res50-FPN-1class](/demo/mmdetection_cfg/faster_rcnn_r50_fpn_1class.py) | 0.840 | [ckpt](https://download.openmmlab.com/mmpose/mmdet_pretrained/faster_rcnn_r50_fpn_1x_macaque-f64f2812_20210409.pth) | [log](https://download.openmmlab.com/mmpose/mmdet_pretrained/faster_rcnn_r50_fpn_1x_macaque_20210409.log.json) | +| [Cascade_R-CNN X-101-64x4d-FPN-1class](/demo/mmdetection_cfg/cascade_rcnn_x101_64x4d_fpn_1class.py) | 0.879 | [ckpt](https://download.openmmlab.com/mmpose/mmdet_pretrained/cascade_rcnn_x101_64x4d_fpn_20e_macaque-e45e36f5_20210409.pth) | [log](https://download.openmmlab.com/mmpose/mmdet_pretrained/cascade_rcnn_x101_64x4d_fpn_20e_macaque_20210409.log.json) | diff --git a/demo/docs/zh_cn/webcam_api_demo.md b/demo/docs/zh_cn/webcam_api_demo.md new file mode 100644 index 0000000000..66099c9ca6 --- /dev/null +++ b/demo/docs/zh_cn/webcam_api_demo.md @@ -0,0 +1,30 @@ +## 摄像头推理 + +从版本 v1.1.0 开始,原来的摄像头 API 已被弃用。用户现在可以选择使用推理器(Inferencer)或 Demo 脚本从摄像头读取的视频中进行姿势估计。 + +### 使用推理器进行摄像头推理 + +用户可以通过执行以下命令来利用 MMPose Inferencer 对摄像头输入进行人体姿势估计: + +```shell +python demo/inferencer_demo.py webcam --pose2d 'human' +``` + +有关推理器的参数详细信息,请参阅 [推理器文档](/docs/en/user_guides/inference.md)。 + +### 使用 Demo 脚本进行摄像头推理 + +除了 `demo/image_demo.py` 之外,所有的 Demo 脚本都支持摄像头输入。 + +以 `demo/topdown_demo_with_mmdet.py` 为例,用户可以通过在命令中指定 **`--input webcam`** 来使用该脚本对摄像头输入进行推理: + +```shell +# inference with webcam +python demo/topdown_demo_with_mmdet.py \ + projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ + projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ + --input webcam \ + --show +``` diff --git a/demo/inferencer_demo.py b/demo/inferencer_demo.py index e0609596ec..b91e91f74b 100644 --- a/demo/inferencer_demo.py +++ b/demo/inferencer_demo.py @@ -25,6 +25,19 @@ def parse_args(): help='Path to the custom checkpoint file of the selected pose model. ' 'If it is not specified and "pose2d" is a model name of metafile, ' 'the weights will be loaded from metafile.') + parser.add_argument( + '--pose3d', + type=str, + default=None, + help='Pretrained 3D pose estimation algorithm. It\'s the path to the ' + 'config file or the model name defined in metafile.') + parser.add_argument( + '--pose3d-weights', + type=str, + default=None, + help='Path to the custom checkpoint file of the selected pose model. ' + 'If it is not specified and "pose3d" is a model name of metafile, ' + 'the weights will be loaded from metafile.') parser.add_argument( '--det-model', type=str, @@ -60,6 +73,11 @@ def parse_args(): '--draw-bbox', action='store_true', help='Whether to draw the bounding boxes.') + parser.add_argument( + '--draw-heatmap', + action='store_true', + default=False, + help='Whether to draw the predicted heatmaps.') parser.add_argument( '--bbox-thr', type=float, @@ -72,6 +90,26 @@ def parse_args(): help='IoU threshold for bounding box NMS') parser.add_argument( '--kpt-thr', type=float, default=0.3, help='Keypoint score threshold') + parser.add_argument( + '--tracking-thr', type=float, default=0.3, help='Tracking threshold') + parser.add_argument( + '--use-oks-tracking', + action='store_true', + help='Whether to use OKS as similarity in tracking') + parser.add_argument( + '--norm-pose-2d', + action='store_true', + help='Scale the bbox (along with the 2D pose) to the average bbox ' + 'scale of the dataset, and move the bbox (along with the 2D pose) to ' + 'the average bbox center of the dataset. This is useful when bbox ' + 'is small, especially in multi-person scenarios.') + parser.add_argument( + '--rebase-keypoint-height', + action='store_true', + help='Rebase the predicted 3D pose so its lowest keypoint has a ' + 'height of 0 (landing on the ground). This is useful for ' + 'visualization when the model do not predict the global position ' + 'of the 3D pose.') parser.add_argument( '--radius', type=int, @@ -82,6 +120,16 @@ def parse_args(): type=int, default=1, help='Link thickness for visualization.') + parser.add_argument( + '--skeleton-style', + default='mmpose', + type=str, + choices=['mmpose', 'openpose'], + help='Skeleton style selection') + parser.add_argument( + '--black-background', + action='store_true', + help='Plot predictions on a black image') parser.add_argument( '--vis-out-dir', type=str, @@ -101,7 +149,7 @@ def parse_args(): init_kws = [ 'pose2d', 'pose2d_weights', 'scope', 'device', 'det_model', - 'det_weights', 'det_cat_ids' + 'det_weights', 'det_cat_ids', 'pose3d', 'pose3d_weights' ] init_args = {} for init_kw in init_kws: diff --git a/demo/topdown_demo_with_mmdet.py b/demo/topdown_demo_with_mmdet.py index f0938000f1..38f4e92e4e 100644 --- a/demo/topdown_demo_with_mmdet.py +++ b/demo/topdown_demo_with_mmdet.py @@ -1,9 +1,10 @@ # Copyright (c) OpenMMLab. All rights reserved. import mimetypes import os -import tempfile +import time from argparse import ArgumentParser +import cv2 import json_tricks as json import mmcv import mmengine @@ -23,12 +24,16 @@ has_mmdet = False -def process_one_image(args, img_path, detector, pose_estimator, visualizer, - show_interval): +def process_one_image(args, + img, + detector, + pose_estimator, + visualizer=None, + show_interval=0): """Visualize predicted keypoints (and heatmaps) of one image.""" # predict bbox - det_result = inference_detector(detector, img_path) + det_result = inference_detector(detector, img) pred_instance = det_result.pred_instances.cpu().numpy() bboxes = np.concatenate( (pred_instance.bboxes, pred_instance.scores[:, None]), axis=1) @@ -37,29 +42,28 @@ def process_one_image(args, img_path, detector, pose_estimator, visualizer, bboxes = bboxes[nms(bboxes, args.nms_thr), :4] # predict keypoints - pose_results = inference_topdown(pose_estimator, img_path, bboxes) + pose_results = inference_topdown(pose_estimator, img, bboxes) data_samples = merge_data_samples(pose_results) # show the results - img = mmcv.imread(img_path, channel_order='rgb') + if isinstance(img, str): + img = mmcv.imread(img, channel_order='rgb') + elif isinstance(img, np.ndarray): + img = mmcv.bgr2rgb(img) - out_file = None - if args.output_root: - out_file = f'{args.output_root}/{os.path.basename(img_path)}' - - visualizer.add_datasample( - 'result', - img, - data_sample=data_samples, - draw_gt=False, - draw_heatmap=args.draw_heatmap, - draw_bbox=args.draw_bbox, - show_kpt_idx=args.show_kpt_idx, - skeleton_style=args.skeleton_style, - show=args.show, - wait_time=show_interval, - out_file=out_file, - kpt_thr=args.kpt_thr) + if visualizer is not None: + visualizer.add_datasample( + 'result', + img, + data_sample=data_samples, + draw_gt=False, + draw_heatmap=args.draw_heatmap, + draw_bbox=args.draw_bbox, + show_kpt_idx=args.show_kpt_idx, + skeleton_style=args.skeleton_style, + show=args.show, + wait_time=show_interval, + kpt_thr=args.kpt_thr) # if there is no instance detected, return None return data_samples.get('pred_instances', None) @@ -141,6 +145,8 @@ def main(): type=int, default=1, help='Link thickness for visualization') + parser.add_argument( + '--show-interval', type=int, default=0, help='Sleep seconds per frame') parser.add_argument( '--alpha', type=float, default=0.8, help='The transparency of bboxes') parser.add_argument( @@ -154,8 +160,15 @@ def main(): assert args.input != '' assert args.det_config is not None assert args.det_checkpoint is not None + + output_file = None if args.output_root: mmengine.mkdir_or_exist(args.output_root) + output_file = os.path.join(args.output_root, + os.path.basename(args.input)) + if args.input == 'webcam': + output_file += '.mp4' + if args.save_predictions: assert args.output_root != '' args.pred_save_path = f'{args.output_root}/results_' \ @@ -174,60 +187,90 @@ def main(): cfg_options=dict( model=dict(test_cfg=dict(output_heatmaps=args.draw_heatmap)))) - # init visualizer + # build visualizer pose_estimator.cfg.visualizer.radius = args.radius pose_estimator.cfg.visualizer.alpha = args.alpha pose_estimator.cfg.visualizer.line_width = args.thickness - visualizer = VISUALIZERS.build(pose_estimator.cfg.visualizer) # the dataset_meta is loaded from the checkpoint and # then pass to the model in init_pose_estimator visualizer.set_dataset_meta( pose_estimator.dataset_meta, skeleton_style=args.skeleton_style) - input_type = mimetypes.guess_type(args.input)[0].split('/')[0] + if args.input == 'webcam': + input_type = 'webcam' + else: + input_type = mimetypes.guess_type(args.input)[0].split('/')[0] + if input_type == 'image': - pred_instances = process_one_image( - args, - args.input, - detector, - pose_estimator, - visualizer, - show_interval=0) - pred_instances_list = split_instances(pred_instances) - - elif input_type == 'video': - tmp_folder = tempfile.TemporaryDirectory() - video = mmcv.VideoReader(args.input) - progressbar = mmengine.ProgressBar(len(video)) - video.cvt2frames(tmp_folder.name, show_progress=False) - output_root = args.output_root - args.output_root = tmp_folder.name + + # inference + pred_instances = process_one_image(args, args.input, detector, + pose_estimator, visualizer) + + if args.save_predictions: + pred_instances_list = split_instances(pred_instances) + + if output_file: + img_vis = visualizer.get_image() + mmcv.imwrite(mmcv.rgb2bgr(img_vis), output_file) + + elif input_type in ['webcam', 'video']: + + if args.input == 'webcam': + cap = cv2.VideoCapture(0) + else: + cap = cv2.VideoCapture(args.input) + + video_writer = None pred_instances_list = [] + frame_idx = 0 - for frame_id, img_fname in enumerate(os.listdir(tmp_folder.name)): - pred_instances = process_one_image( - args, - f'{tmp_folder.name}/{img_fname}', - detector, - pose_estimator, - visualizer, - show_interval=1) - - progressbar.update() - pred_instances_list.append( - dict( - frame_id=frame_id, - instances=split_instances(pred_instances))) - - if output_root: - mmcv.frames2video( - tmp_folder.name, - f'{output_root}/{os.path.basename(args.input)}', - fps=video.fps, - fourcc='mp4v', - show_progress=False) - tmp_folder.cleanup() + while cap.isOpened(): + success, frame = cap.read() + frame_idx += 1 + + if not success: + break + + # topdown pose estimation + pred_instances = process_one_image(args, frame, detector, + pose_estimator, visualizer, + 0.001) + + if args.save_predictions: + # save prediction results + pred_instances_list.append( + dict( + frame_id=frame_idx, + instances=split_instances(pred_instances))) + + # output videos + if output_file: + frame_vis = visualizer.get_image() + + if video_writer is None: + fourcc = cv2.VideoWriter_fourcc(*'mp4v') + # the size of the image with visualization may vary + # depending on the presence of heatmaps + video_writer = cv2.VideoWriter( + output_file, + fourcc, + 25, # saved fps + (frame_vis.shape[1], frame_vis.shape[0])) + + video_writer.write(mmcv.rgb2bgr(frame_vis)) + + # press ESC to exit + if cv2.waitKey(5) & 0xFF == 27: + break + + time.sleep(args.show_interval) + + if video_writer: + video_writer.release() + + cap.release() else: args.save_predictions = False diff --git a/demo/webcam_api_demo.py b/demo/webcam_api_demo.py deleted file mode 100644 index 7e047ea6b5..0000000000 --- a/demo/webcam_api_demo.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. - -import logging -import warnings -from argparse import ArgumentParser - -from mmengine import Config, DictAction - -from mmpose.apis.webcam import WebcamExecutor -from mmpose.apis.webcam.nodes import model_nodes - - -def parse_args(): - parser = ArgumentParser('Webcam executor configs') - parser.add_argument( - '--config', type=str, default='demo/webcam_cfg/pose_estimation.py') - - parser.add_argument( - '--cfg-options', - nargs='+', - action=DictAction, - default={}, - help='Override settings in the config. The key-value pair ' - 'in xxx=yyy format will be merged into config file. For example, ' - "'--cfg-options executor_cfg.camera_id=1'") - parser.add_argument( - '--debug', action='store_true', help='Show debug information.') - parser.add_argument( - '--cpu', action='store_true', help='Use CPU for model inference.') - parser.add_argument( - '--cuda', action='store_true', help='Use GPU for model inference.') - - return parser.parse_args() - - -def set_device(cfg: Config, device: str): - """Set model device in config. - - Args: - cfg (Config): Webcam config - device (str): device indicator like "cpu" or "cuda:0" - """ - - device = device.lower() - assert device == 'cpu' or device.startswith('cuda:') - - for node_cfg in cfg.executor_cfg.nodes: - if node_cfg.type in model_nodes.__all__: - node_cfg.update(device=device) - - return cfg - - -def run(): - - warnings.warn('The Webcam API will be deprecated in future. ', - DeprecationWarning) - - args = parse_args() - cfg = Config.fromfile(args.config) - cfg.merge_from_dict(args.cfg_options) - - if args.debug: - logging.basicConfig(level=logging.DEBUG) - - if args.cpu: - cfg = set_device(cfg, 'cpu') - - if args.cuda: - cfg = set_device(cfg, 'cuda:0') - - webcam_exe = WebcamExecutor(**cfg.executor_cfg) - webcam_exe.run() - - -if __name__ == '__main__': - run() diff --git a/demo/webcam_cfg/pose_estimation.py b/demo/webcam_cfg/pose_estimation.py deleted file mode 100644 index 5eedc7f216..0000000000 --- a/demo/webcam_cfg/pose_estimation.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -executor_cfg = dict( - # Basic configurations of the executor - name='Pose Estimation', - camera_id=0, - # Define nodes. - # The configuration of a node usually includes: - # 1. 'type': Node class name - # 2. 'name': Node name - # 3. I/O buffers (e.g. 'input_buffer', 'output_buffer'): specify the - # input and output buffer names. This may depend on the node class. - # 4. 'enable_key': assign a hot-key to toggle enable/disable this node. - # This may depend on the node class. - # 5. Other class-specific arguments - nodes=[ - # 'DetectorNode': - # This node performs object detection from the frame image using an - # MMDetection model. - dict( - type='DetectorNode', - name='detector', - model_config='demo/mmdetection_cfg/' - 'ssdlite_mobilenetv2-scratch_8xb24-600e_coco.py', - model_checkpoint='https://download.openmmlab.com' - '/mmdetection/v2.0/ssd/' - 'ssdlite_mobilenetv2_scratch_600e_coco/ssdlite_mobilenetv2_' - 'scratch_600e_coco_20210629_110627-974d9307.pth', - input_buffer='_input_', # `_input_` is an executor-reserved buffer - output_buffer='det_result'), - # 'TopdownPoseEstimatorNode': - # This node performs keypoint detection from the frame image using an - # MMPose top-down model. Detection results is needed. - dict( - type='TopdownPoseEstimatorNode', - name='human pose estimator', - model_config='configs/wholebody_2d_keypoint/' - 'topdown_heatmap/coco-wholebody/' - 'td-hm_vipnas-mbv3_dark-8xb64-210e_coco-wholebody-256x192.py', - model_checkpoint='https://download.openmmlab.com/mmpose/' - 'top_down/vipnas/vipnas_mbv3_coco_wholebody_256x192_dark' - '-e2158108_20211205.pth', - labels=['person'], - input_buffer='det_result', - output_buffer='human_pose'), - dict( - type='TopdownPoseEstimatorNode', - name='animal pose estimator', - model_config='configs/animal_2d_keypoint/topdown_heatmap/' - 'animalpose/td-hm_hrnet-w32_8xb64-210e_animalpose-256x256.py', - model_checkpoint='https://download.openmmlab.com/mmpose/animal/' - 'hrnet/hrnet_w32_animalpose_256x256-1aa7f075_20210426.pth', - labels=['cat', 'dog', 'horse', 'sheep', 'cow'], - input_buffer='human_pose', - output_buffer='animal_pose'), - # 'ObjectAssignerNode': - # This node binds the latest model inference result with the current - # frame. (This means the frame image and inference result may be - # asynchronous). - dict( - type='ObjectAssignerNode', - name='object assigner', - frame_buffer='_frame_', # `_frame_` is an executor-reserved buffer - object_buffer='animal_pose', - output_buffer='frame'), - # 'ObjectVisualizerNode': - # This node draw the pose visualization result in the frame image. - # Pose results is needed. - dict( - type='ObjectVisualizerNode', - name='object visualizer', - enable_key='v', - enable=True, - show_bbox=True, - must_have_keypoint=False, - show_keypoint=True, - input_buffer='frame', - output_buffer='vis'), - # 'SunglassesNode': - # This node draw the sunglasses effect in the frame image. - # Pose results is needed. - dict( - type='SunglassesEffectNode', - name='sunglasses', - enable_key='s', - enable=False, - input_buffer='vis', - output_buffer='vis_sunglasses'), - # 'BigeyeEffectNode': - # This node draw the big-eye effetc in the frame image. - # Pose results is needed. - dict( - type='BigeyeEffectNode', - name='big-eye', - enable_key='b', - enable=False, - input_buffer='vis_sunglasses', - output_buffer='vis_bigeye'), - # 'NoticeBoardNode': - # This node show a notice board with given content, e.g. help - # information. - dict( - type='NoticeBoardNode', - name='instruction', - enable_key='h', - enable=True, - input_buffer='vis_bigeye', - output_buffer='vis_notice', - content_lines=[ - 'This is a demo for pose visualization and simple image ' - 'effects. Have fun!', '', 'Hot-keys:', - '"v": Pose estimation result visualization', - '"s": Sunglasses effect B-)', '"b": Big-eye effect 0_0', - '"h": Show help information', - '"m": Show diagnostic information', '"q": Exit' - ], - ), - # 'MonitorNode': - # This node show diagnostic information in the frame image. It can - # be used for debugging or monitoring system resource status. - dict( - type='MonitorNode', - name='monitor', - enable_key='m', - enable=False, - input_buffer='vis_notice', - output_buffer='display'), - # 'RecorderNode': - # This node save the output video into a file. - dict( - type='RecorderNode', - name='recorder', - out_video_file='webcam_api_demo.mp4', - input_buffer='display', - output_buffer='_display_' - # `_display_` is an executor-reserved buffer - ) - ]) diff --git a/demo/webcam_cfg/test_camera.py b/demo/webcam_cfg/test_camera.py deleted file mode 100644 index e6d79cf6db..0000000000 --- a/demo/webcam_cfg/test_camera.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -executor_cfg = dict( - name='Test Webcam', - camera_id=0, - camera_max_fps=30, - nodes=[ - dict( - type='MonitorNode', - name='monitor', - enable_key='m', - enable=False, - input_buffer='_frame_', - output_buffer='display'), - # 'RecorderNode': - # This node save the output video into a file. - dict( - type='RecorderNode', - name='recorder', - out_video_file='webcam_api_output.mp4', - input_buffer='display', - output_buffer='_display_') - ]) diff --git a/docker/Dockerfile b/docker/Dockerfile index 347af89ca8..064b803979 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -22,7 +22,7 @@ RUN pip install xtcocotools # Install MMEngine and MMCV RUN pip install openmim -RUN mim install mmengine "mmcv>=2.0.0rc1" +RUN mim install mmengine "mmcv>=2.0.0" # Install MMPose RUN conda clean --all diff --git a/docs/en/advanced_guides/customize_datasets.md b/docs/en/advanced_guides/customize_datasets.md index 1829c37a0c..1aac418812 100644 --- a/docs/en/advanced_guides/customize_datasets.md +++ b/docs/en/advanced_guides/customize_datasets.md @@ -1,3 +1,259 @@ # Customize Datasets -Coming soon. +## Customize datasets by reorganizing data to COCO format + +The simplest way to use the custom dataset is to convert your annotation format to COCO dataset format. + +The annotation JSON files in COCO format have the following necessary keys: + +```python +'images': [ + { + 'file_name': '000000001268.jpg', + 'height': 427, + 'width': 640, + 'id': 1268 + }, + ... +], +'annotations': [ + { + 'segmentation': [[426.36, + ... + 424.34, + 223.3]], + 'keypoints': [0,0,0, + 0,0,0, + 0,0,0, + 427,220,2, + 443,222,2, + 414,228,2, + 449,232,2, + 408,248,1, + 454,261,2, + 0,0,0, + 0,0,0, + 411,287,2, + 431,287,2, + 0,0,0, + 458,265,2, + 0,0,0, + 466,300,1], + 'num_keypoints': 10, + 'area': 3894.5826, + 'iscrowd': 0, + 'image_id': 1268, + 'bbox': [402.34, 205.02, 65.26, 88.45], + 'category_id': 1, + 'id': 215218 + }, + ... +], +'categories': [ + {'id': 1, 'name': 'person'}, + ] +``` + +There are three necessary keys in the json file: + +- `images`: contains a list of images with their information like `file_name`, `height`, `width`, and `id`. +- `annotations`: contains the list of instance annotations. +- `categories`: contains the category name ('person') and its ID (1). + +If the annotations have been organized in COCO format, there is no need to create a new dataset class. You can use `CocoDataset` class alternatively. + +## Create a custom dataset_info config file for the dataset + +Add a new dataset info config file that contains the metainfo about the dataset. + +``` +configs/_base_/datasets/custom.py +``` + +An example of the dataset config is as follows. + +`keypoint_info` contains the information about each keypoint. + +1. `name`: the keypoint name. The keypoint name must be unique. +2. `id`: the keypoint id. +3. `color`: (\[B, G, R\]) is used for keypoint visualization. +4. `type`: 'upper' or 'lower', will be used in data augmentation. +5. `swap`: indicates the 'swap pair' (also known as 'flip pair'). When applying image horizontal flip, the left part will become the right part. We need to flip the keypoints accordingly. + +`skeleton_info` contains information about the keypoint connectivity, which is used for visualization. + +`joint_weights` assigns different loss weights to different keypoints. + +`sigmas` is used to calculate the OKS score. You can read [keypoints-eval](https://cocodataset.org/#keypoints-eval) to learn more about it. + +Here is an simplified example of dataset_info config file ([full text](/configs/_base_/datasets/coco.py)). + +``` +dataset_info = dict( + dataset_name='coco', + paper_info=dict( + author='Lin, Tsung-Yi and Maire, Michael and ' + 'Belongie, Serge and Hays, James and ' + 'Perona, Pietro and Ramanan, Deva and ' + r'Doll{\'a}r, Piotr and Zitnick, C Lawrence', + title='Microsoft coco: Common objects in context', + container='European conference on computer vision', + year='2014', + homepage='http://cocodataset.org/', + ), + keypoint_info={ + 0: + dict(name='nose', id=0, color=[51, 153, 255], type='upper', swap=''), + 1: + dict( + name='left_eye', + id=1, + color=[51, 153, 255], + type='upper', + swap='right_eye'), + ... + 16: + dict( + name='right_ankle', + id=16, + color=[255, 128, 0], + type='lower', + swap='left_ankle') + }, + skeleton_info={ + 0: + dict(link=('left_ankle', 'left_knee'), id=0, color=[0, 255, 0]), + ... + 18: + dict( + link=('right_ear', 'right_shoulder'), id=18, color=[51, 153, 255]) + }, + joint_weights=[ + 1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5, + 1.5 + ], + sigmas=[ + 0.026, 0.025, 0.025, 0.035, 0.035, 0.079, 0.079, 0.072, 0.072, 0.062, + 0.062, 0.107, 0.107, 0.087, 0.087, 0.089, 0.089 + ]) +``` + +## Create a custom dataset class + +If the annotations are not organized in COCO format, you need to create a custom dataset class by the following steps: + +1. First create a package inside the `mmpose/datasets/datasets` folder. + +2. Create a class definition of your dataset in the package folder and register it in the registry with a name. Without a name, it will keep giving the error. `KeyError: 'XXXXX is not in the dataset registry'` + + ``` + from mmengine.dataset import BaseDataset + from mmpose.registry import DATASETS + + @DATASETS.register_module(name='MyCustomDataset') + class MyCustomDataset(BaseDataset): + ``` + + You can refer to [this doc](https://mmengine.readthedocs.io/en/latest/advanced_tutorials/basedataset.html) on how to build customed dataset class with `mmengine.BaseDataset`. + +3. Make sure you have updated the `__init__.py` of your package folder + +4. Make sure you have updated the `__init__.py` of the dataset package folder. + +## Create a custom training config file + +Create a custom training config file as per your need and the model/architecture you want to use in the configs folder. You may modify an existing config file to use the new custom dataset. + +In `configs/my_custom_config.py`: + +```python +... +# dataset and dataloader settings +dataset_type = 'MyCustomDataset' # or 'CocoDataset' + +train_dataloader = dict( + batch_size=2, + dataset=dict( + type=dataset_type, + data_root='root/of/your/train/data', + ann_file='path/to/your/train/json', + data_prefix=dict(img='path/to/your/train/img'), + metainfo=dict(from_file='configs/_base_/datasets/custom.py'), + ...), + ) + +val_dataloader = dict( + batch_size=2, + dataset=dict( + type=dataset_type, + data_root='root/of/your/val/data', + ann_file='path/to/your/val/json', + data_prefix=dict(img='path/to/your/val/img'), + metainfo=dict(from_file='configs/_base_/datasets/custom.py'), + ...), + ) + +test_dataloader = dict( + batch_size=2, + dataset=dict( + type=dataset_type, + data_root='root/of/your/test/data', + ann_file='path/to/your/test/json', + data_prefix=dict(img='path/to/your/test/img'), + metainfo=dict(from_file='configs/_base_/datasets/custom.py'), + ...), + ) +... +``` + +Make sure you have provided all the paths correctly. + +## Dataset Wrappers + +The following dataset wrappers are supported in [MMEngine](https://github.com/open-mmlab/mmengine), you can refer to [MMEngine tutorial](https://mmengine.readthedocs.io/en/latest) to learn how to use it. + +- [ConcatDataset](https://mmengine.readthedocs.io/en/latest/advanced_tutorials/basedataset.html#concatdataset) +- [RepeatDataset](https://mmengine.readthedocs.io/en/latest/advanced_tutorials/basedataset.html#repeatdataset) + +### CombinedDataset + +MMPose provides `CombinedDataset` to combine multiple datasets with different annotations. A combined dataset can be defined in config files as: + +```python +dataset_1 = dict( + type='dataset_type_1', + data_root='root/of/your/dataset1', + data_prefix=dict(img_path='path/to/your/img'), + ann_file='annotations/train.json', + pipeline=[ + # the converter transforms convert data into a unified format + converter_transform_1 + ]) + +dataset_2 = dict( + type='dataset_type_2', + data_root='root/of/your/dataset2', + data_prefix=dict(img_path='path/to/your/img'), + ann_file='annotations/train.json', + pipeline=[ + converter_transform_2 + ]) + +shared_pipeline = [ + LoadImage(), + ParseImage(), +] + +combined_dataset = dict( + type='CombinedDataset', + metainfo=dict(from_file='path/to/your/metainfo'), + datasets=[dataset_1, dataset_2], + pipeline=shared_pipeline, +) +``` + +- **MetaInfo of combined dataset** determines the annotation format. Either metainfo of a sub-dataset or a customed dataset metainfo is valid here. To custom a dataset metainfo, please refer to [Create a custom dataset_info config file for the dataset](#create-a-custom-datasetinfo-config-file-for-the-dataset). + +- **Converter transforms of sub-datasets** are applied when there exist mismatches of annotation format between sub-datasets and the combined dataset. For example, the number and order of keypoints might be different in the combined dataset and the sub-datasets. Then `KeypointConverter` can be used to unify the keypoints number and order. + +- More details about `CombinedDataset` and `KeypointConverter` can be found in Advanced Guides-[Training with Mixed Datasets](../user_guides/mixed_datasets.md). diff --git a/docs/en/advanced_guides/model_analysis.md b/docs/en/advanced_guides/model_analysis.md index 4b0528fd74..e10bb634a6 100644 --- a/docs/en/advanced_guides/model_analysis.md +++ b/docs/en/advanced_guides/model_analysis.md @@ -1,3 +1,102 @@ # Model Analysis -Coming soon. +## Get Model Params & FLOPs + +MMPose provides `tools/analysis_tools/get_flops.py` to get model parameters and FLOPs. + +```shell +python tools/analysis_tools/get_flops.py ${CONFIG_FILE} [--shape ${INPUT_SHAPE}] [--cfg-options ${CFG_OPTIONS}] +``` + +Description of all arguments: + +`CONFIG_FILE` : The path of a model config file. + +`--shape`: The input shape to the model. + +`--input-constructor`: If specified as batch, it will generate a batch tensor to calculate FLOPs. + +`--batch-size`:If `--input-constructor` is specified as batch, it will generate a random tensor with shape `(batch_size, 3, **input_shape)` to calculate FLOPs. + +`--cfg-options`: If specified, the key-value pair optional `cfg` will be merged into config file. + +Example: + +```shell +python tools/analysis_tools/get_flops.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192.py +``` + +We will get the following results: + +```text +============================== +Input shape: (1, 3, 256, 192) +Flops: 7.7 GFLOPs +Params: 28.54 M +============================== +``` + +```{note} +This tool is still experimental and we do not guarantee that the number is absolutely correct. Some operators are not counted into FLOPs like GN and custom operators. +``` + +## Log Analysis + +MMPose provides `tools/analysis_tools/analyze_logs.py` to analyze the training log. The log file can be either a json file or a text file. The json file is recommended, because it is more convenient to parse and visualize. + +Currently, the following functions are supported: + +- Plot loss/accuracy curves +- Calculate training time + +### Plot Loss/Accuracy Curves + +The function depends on `seaborn`, please install it first by running `pip install seaborn`. + +![log_curve](https://user-images.githubusercontent.com/87690686/188538215-5d985aaa-59f8-44cf-b6f9-10890d599e9c.png) + +```shell +python tools/analysis_tools/analyze_logs.py plot_curve ${JSON_LOGS} [--keys ${KEYS}] [--title ${TITLE}] [--legend ${LEGEND}] [--backend ${BACKEND}] [--style ${STYLE}] [--out ${OUT_FILE}] +``` + +Examples: + +- Plot loss curve + + ```shell + python tools/analysis_tools/analyze_logs.py plot_curve log.json --keys loss_kpt --legend loss_kpt + ``` + +- Plot accuracy curve and export to PDF file + + ```shell + python tools/analysis_tools/analyze_logs.py plot_curve log.json --keys acc_pose --out results.pdf + ``` + +- Plot multiple log files on the same figure + + ```shell + python tools/analysis_tools/analyze_logs.py plot_curve log1.json log2.json --keys loss_kpt --legend run1 run2 --title loss_kpt --out loss_kpt.png + ``` + +### Calculate Training Time + +```shell +python tools/analysis_tools/analyze_logs.py cal_train_time ${JSON_LOGS} [--include-outliers] +``` + +Examples: + +```shell +python tools/analysis_tools/analyze_logs.py cal_train_time log.json +``` + +The result is as follows: + +```text +-----Analyze train time of hrnet_w32_256x192.json----- +slowest epoch 56, average time is 0.6924 +fastest epoch 1, average time is 0.6502 +time std over epochs is 0.0085 +average iter time: 0.6688 s/iter +``` diff --git a/docs/en/api.rst b/docs/en/api.rst index a75e4a451d..48819a2531 100644 --- a/docs/en/api.rst +++ b/docs/en/api.rst @@ -132,5 +132,3 @@ hooks ^^^^^^^^^^^ .. automodule:: mmpose.engine.hooks :members: - -.. include:: webcam_api.rst diff --git a/docs/en/dataset_zoo/2d_animal_keypoint.md b/docs/en/dataset_zoo/2d_animal_keypoint.md index 86b1b70632..9ef6022ecc 100644 --- a/docs/en/dataset_zoo/2d_animal_keypoint.md +++ b/docs/en/dataset_zoo/2d_animal_keypoint.md @@ -13,6 +13,7 @@ MMPose supported datasets: - [Desert Locust](#desert-locust) \[ [Homepage](https://github.com/jgraving/DeepPoseKit-Data) \] - [Grévy’s Zebra](#grvys-zebra) \[ [Homepage](https://github.com/jgraving/DeepPoseKit-Data) \] - [ATRW](#atrw) \[ [Homepage](https://cvwc2019.github.io/challenge.html) \] +- [Animal Kingdom](#Animal-Kindom) \[ [Homepage](https://openaccess.thecvf.com/content/CVPR2022/html/Ng_Animal_Kingdom_A_Large_and_Diverse_Dataset_for_Animal_Behavior_CVPR_2022_paper.html) \] ## Animal-Pose @@ -94,7 +95,6 @@ mmpose │ │-- dog │ │-- horse │ │-- sheep - ``` The official dataset does not provide the official train/val/test set split. @@ -154,7 +154,6 @@ mmpose │ │-- 000000000001.jpg │ │-- 000000000002.jpg │ │-- ... - ``` The annotation files in 'annotation' folder contains 50 labeled animal species. There are total 10,015 labeled images with 13,028 instances in the AP-10K dataset. We randonly split them into train, val, and test set following the ratio of 7:1:2. @@ -206,7 +205,6 @@ mmpose │ │-- BrownHorseinShadow │ │-- BrownHorseintoshadow │ │-- ... - ``` ## MacaquePose @@ -255,7 +253,6 @@ mmpose │ │-- 020a1c75c8c85238.jpg │ │-- 020b1506eef2557d.jpg │ │-- ... - ``` Since the official dataset does not provide the test set, we randomly select 12500 images for training, and the rest for evaluation (see [code](/tools/dataset/parse_macaquepose_dataset.py)). @@ -308,7 +305,6 @@ mmpose │ │-- 2.jpg │ │-- 3.jpg │ │-- ... - ``` Since the official dataset does not provide the test set, we randomly select 90% images for training, and the rest (10%) for evaluation (see [code](/tools/dataset_converters/parse_deepposekit_dataset.py)). @@ -360,7 +356,6 @@ mmpose │ │-- 2.jpg │ │-- 3.jpg │ │-- ... - ``` Since the official dataset does not provide the test set, we randomly select 90% images for training, and the rest (10%) for evaluation (see [code](/tools/dataset_converters/parse_deepposekit_dataset.py)). @@ -389,7 +384,6 @@ Since the official dataset does not provide the test set, we randomly select 90%
- For [Grévy’s Zebra](https://github.com/jgraving/DeepPoseKit-Data) dataset, images can be downloaded from [zebra_images](https://download.openmmlab.com/mmpose/datasets/zebra_images.tar). Please download the annotation files from [zebra_annotations](https://download.openmmlab.com/mmpose/datasets/zebra_annotations.tar). Extract them under {MMPose}/data, and make them look like this: @@ -412,7 +406,6 @@ mmpose │ │-- 2.jpg │ │-- 3.jpg │ │-- ... - ``` Since the official dataset does not provide the test set, we randomly select 90% images for training, and the rest (10%) for evaluation (see [code](/tools/dataset_converters/parse_deepposekit_dataset.py)). @@ -439,7 +432,6 @@ Since the official dataset does not provide the test set, we randomly select 90%
- ATRW captures images of the Amur tiger (also known as Siberian tiger, Northeast-China tiger) in the wild. For [ATRW](https://cvwc2019.github.io/challenge.html) dataset, please download images from [Pose_train](https://lilablobssc.blob.core.windows.net/cvwc2019/train/atrw_pose_train.tar.gz), @@ -476,5 +468,68 @@ mmpose │ │ │-- 000000.jpg │ │ │-- 000004.jpg │ │ │-- ... +``` + +## Animal Kingdom + +
+Animal Kingdom (CVPR'2022) +
+
+ +
+ +```bibtex +@inproceedings{Ng_2022_CVPR, + author = {Ng, Xun Long and Ong, Kian Eng and Zheng, Qichen and Ni, Yun and Yeo, Si Yong and Liu, Jun}, + title = {Animal Kingdom: A Large and Diverse Dataset for Animal Behavior Understanding}, + booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)}, + month = {June}, + year = {2022}, + pages = {19023-19034} + } +``` +For [Animal Kingdom](https://github.com/sutdcv/Animal-Kingdom) dataset, images can be downloaded from [here](https://forms.office.com/pages/responsepage.aspx?id=drd2NJDpck-5UGJImDFiPVRYpnTEMixKqPJ1FxwK6VZUQkNTSkRISTNORUI2TDBWMUpZTlQ5WUlaSyQlQCN0PWcu). +Please Extract dataset under {MMPose}/data, and make them look like this: + +```text +mmpose +├── mmpose +├── docs +├── tests +├── tools +├── configs +`── data + │── ak + |--annotations + │ │-- ak_P1 + │ │ │-- train.json + │ │ │-- test.json + │ │-- ak_P2 + │ │ │-- train.json + │ │ │-- test.json + │ │-- ak_P3_amphibian + │ │ │-- train.json + │ │ │-- test.json + │ │-- ak_P3_bird + │ │ │-- train.json + │ │ │-- test.json + │ │-- ak_P3_fish + │ │ │-- train.json + │ │ │-- test.json + │ │-- ak_P3_mammal + │ │ │-- train.json + │ │ │-- test.json + │ │-- ak_P3_reptile + │ │-- train.json + │ │-- test.json + │-- images + │ │-- AAACXZTV + │ │ │--AAACXZTV_f000059.jpg + │ │ │--... + │ │-- AAAUILHH + │ │ │--AAAUILHH_f000098.jpg + │ │ │--... + │ │-- ... ``` diff --git a/docs/en/dataset_zoo/2d_body_keypoint.md b/docs/en/dataset_zoo/2d_body_keypoint.md index c5bf70a3f8..4448ebe8f4 100644 --- a/docs/en/dataset_zoo/2d_body_keypoint.md +++ b/docs/en/dataset_zoo/2d_body_keypoint.md @@ -13,6 +13,7 @@ MMPose supported datasets: - [CrowdPose](#crowdpose) \[ [Homepage](https://github.com/Jeff-sjtu/CrowdPose) \] - [OCHuman](#ochuman) \[ [Homepage](https://github.com/liruilong940607/OCHumanApi) \] - [MHP](#mhp) \[ [Homepage](https://lv-mhp.github.io/dataset) \] + - [Human-Art](#humanart) \[ [Homepage](https://idea-research.github.io/HumanArt/) \] - Videos - [PoseTrack18](#posetrack18) \[ [Homepage](https://posetrack.net/users/download.php) \] - [sub-JHMDB](#sub-jhmdb-dataset) \[ [Homepage](http://jhmdb.is.tue.mpg.de/dataset) \] @@ -386,6 +387,57 @@ mmpose │ │ │-- ...~~~~ ``` +## Human-Art dataset + + + +
+Human-Art (CVPR'2023) + +```bibtex +@inproceedings{ju2023humanart, + title={Human-Art: A Versatile Human-Centric Dataset Bridging Natural and Artificial Scenes}, + author={Ju, Xuan and Zeng, Ailing and Jianan, Wang and Qiang, Xu and Lei, Zhang}, + booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), + year={2023}} +``` + +
+ +
+ +
+ +For [Human-Art](https://idea-research.github.io/HumanArt/) data, please download the images and annotation files from [its website](https://idea-research.github.io/HumanArt/). You need to fill in the [data form](https://docs.google.com/forms/d/e/1FAIpQLScroT_jvw6B9U2Qca1_cl5Kmmu1ceKtlh6DJNmWLte8xNEhEw/viewform) to get access to the data. +Move them under $MMPOSE/data, and make them look like this: + +```text +mmpose +├── mmpose +├── docs +├── tests +├── tools +├── configs +|── data + │── HumanArt + │-- images + │ │-- 2D_virtual_human + │ │ |-- cartoon + │ │ | |-- 000000000000.jpg + │ │ | |-- ... + │ │ |-- digital_art + │ │ |-- ... + │ |-- 3D_virtual_human + │ |-- real_human + |-- annotations + │ │-- validation_humanart.json + │ │-- training_humanart_coco.json + |-- person_detection_results + │ │-- HumanArt_validation_detections_AP_H_56_person.json +``` + +You can choose whether to download other annotation files in Human-Art. If you want to use additional annotation files (e.g. validation set of cartoon), you need to edit the corresponding code in config file. + ## PoseTrack18 diff --git a/docs/en/dataset_zoo/2d_face_keypoint.md b/docs/en/dataset_zoo/2d_face_keypoint.md index 17eb823954..62f66bd82b 100644 --- a/docs/en/dataset_zoo/2d_face_keypoint.md +++ b/docs/en/dataset_zoo/2d_face_keypoint.md @@ -10,6 +10,7 @@ MMPose supported datasets: - [AFLW](#aflw-dataset) \[ [Homepage](https://www.tugraz.at/institute/icg/research/team-bischof/lrs/downloads/aflw/) \] - [COFW](#cofw-dataset) \[ [Homepage](http://www.vision.caltech.edu/xpburgos/ICCV13/) \] - [COCO-WholeBody-Face](#coco-wholebody-face) \[ [Homepage](https://github.com/jin-s13/COCO-WholeBody/) \] +- [LaPa](#lapa-dataset) \[ [Homepage](https://github.com/JDAI-CV/lapa-dataset) \] ## 300W Dataset @@ -325,3 +326,59 @@ mmpose Please also install the latest version of [Extended COCO API](https://github.com/jin-s13/xtcocoapi) to support COCO-WholeBody evaluation: `pip install xtcocotools` + +## LaPa + + + +
+LaPa (AAAI'2020) + +```bibtex +@inproceedings{liu2020new, + title={A New Dataset and Boundary-Attention Semantic Segmentation for Face Parsing.}, + author={Liu, Yinglu and Shi, Hailin and Shen, Hao and Si, Yue and Wang, Xiaobo and Mei, Tao}, + booktitle={AAAI}, + pages={11637--11644}, + year={2020} +} +``` + +
+ +
+ +
+ +For [LaPa](https://github.com/JDAI-CV/lapa-dataset) dataset, images can be downloaded from [their github page](https://github.com/JDAI-CV/lapa-dataset). + +Download and extract them under $MMPOSE/data, and use our `tools/dataset_converters/lapa2coco.py` to make them look like this: + +```text +mmpose +├── mmpose +├── docs +├── tests +├── tools +├── configs +`── data + │── LaPa + │-- annotations + │ │-- lapa_train.json + │ |-- lapa_val.json + │ |-- lapa_test.json + | |-- lapa_trainval.json + │-- train + │ │-- images + │ │-- labels + │ │-- landmarks + │-- val + │ │-- images + │ │-- labels + │ │-- landmarks + `-- test + │ │-- images + │ │-- labels + │ │-- landmarks + +``` diff --git a/docs/en/dataset_zoo/2d_fashion_landmark.md b/docs/en/dataset_zoo/2d_fashion_landmark.md index 42f213e40a..b1146b47b6 100644 --- a/docs/en/dataset_zoo/2d_fashion_landmark.md +++ b/docs/en/dataset_zoo/2d_fashion_landmark.md @@ -6,6 +6,7 @@ If your folder structure is different, you may need to change the corresponding MMPose supported datasets: - [DeepFashion](#deepfashion) \[ [Homepage](http://mmlab.ie.cuhk.edu.hk/projects/DeepFashion/LandmarkDetection.html) \] +- [DeepFashion2](#deepfashion2) \[ [Homepage](https://github.com/switchablenorms/DeepFashion2) \] ## DeepFashion (Fashion Landmark Detection, FLD) @@ -78,3 +79,64 @@ mmpose │ │-- img_00000005.jpg │ │-- ... ``` + +## DeepFashion2 + + + +
+DeepFashion2 (CVPR'2019) + +```bibtex +@article{DeepFashion2, + author = {Yuying Ge and Ruimao Zhang and Lingyun Wu and Xiaogang Wang and Xiaoou Tang and Ping Luo}, + title={A Versatile Benchmark for Detection, Pose Estimation, Segmentation and Re-Identification of Clothing Images}, + journal={CVPR}, + year={2019} +} +``` + +
+ + + +For [DeepFashion2](https://github.com/switchablenorms/DeepFashion2) dataset, images can be downloaded from [download](https://drive.google.com/drive/folders/125F48fsMBz2EF0Cpqk6aaHet5VH399Ok?usp=sharing). +Please download the [annotation files](https://drive.google.com/file/d/1RM9l9EaB9ULRXhoCS72PkCXtJ4Cn4i6O/view?usp=share_link). These annotation files are converted by [deepfashion2_to_coco.py](https://github.com/switchablenorms/DeepFashion2/blob/master/evaluation/deepfashion2_to_coco.py). +Extract them under {MMPose}/data, and make them look like this: + +```text +mmpose +├── mmpose +├── docs +├── tests +├── tools +├── configs +`── data + │── deepfashion2 + │── train + │-- deepfashion2_short_sleeved_outwear_train.json + │-- deepfashion2_short_sleeved_dress_train.json + │-- deepfashion2_skirt_train.json + │-- deepfashion2_sling_dress_train.json + │-- ... + │-- image + │ │-- 000001.jpg + │ │-- 000002.jpg + │ │-- 000003.jpg + │ │-- 000004.jpg + │ │-- 000005.jpg + │ │-- ... + │── validation + │-- deepfashion2_short_sleeved_dress_validation.json + │-- deepfashion2_long_sleeved_shirt_validation.json + │-- deepfashion2_trousers_validation.json + │-- deepfashion2_skirt_validation.json + │-- ... + │-- image + │ │-- 000001.jpg + │ │-- 000002.jpg + │ │-- 000003.jpg + │ │-- 000004.jpg + │ │-- 000005.jpg + │ │-- ... +``` diff --git a/docs/en/dataset_zoo/dataset_tools.md b/docs/en/dataset_zoo/dataset_tools.md index 3ff70fc401..44a7c96b2b 100644 --- a/docs/en/dataset_zoo/dataset_tools.md +++ b/docs/en/dataset_zoo/dataset_tools.md @@ -361,3 +361,38 @@ For example, ```shell python tools/dataset/mat2json work_dirs/res50_mpii_256x256/pred.mat data/mpii/annotations/mpii_val.json pred.json ``` + +## Label Studio + +
+Label Studio + +```bibtex +@misc{Label Studio, + title={{Label Studio}: Data labeling software}, + url={https://github.com/heartexlabs/label-studio}, + note={Open source software available from https://github.com/heartexlabs/label-studio}, + author={ + Maxim Tkachenko and + Mikhail Malyuk and + Andrey Holmanyuk and + Nikolai Liubimov}, + year={2020-2022}, +} +``` + +
+ +For users of [Label Studio](https://github.com/heartexlabs/label-studio/), please follow the instructions in the [Label Studio to COCO document](./label_studio.md) to annotate and export the results as a Label Studio `.json` file. And save the `Code` from the `Labeling Interface` as an `.xml` file. + +We provide a script to convert Label Studio `.json` annotation file to COCO `.json` format file. It can be used by running the following command: + +```shell +python tools/dataset_converters/labelstudio2coco.py ${LS_JSON_FILE} ${LS_XML_FILE} ${OUTPUT_COCO_JSON_FILE} +``` + +For example, + +```shell +python tools/dataset_converters/labelstudio2coco.py config.xml project-1-at-2023-05-13-09-22-91b53efa.json output/result.json +``` diff --git a/docs/en/dataset_zoo/label_studio.md b/docs/en/dataset_zoo/label_studio.md new file mode 100644 index 0000000000..3b499e05c6 --- /dev/null +++ b/docs/en/dataset_zoo/label_studio.md @@ -0,0 +1,76 @@ +# Label Studio Annotations to COCO Script + +[Label Studio](https://labelstud.io/) is a popular deep learning annotation tool that can be used for annotating various tasks. However, for keypoint annotation, Label Studio can not directly export to the COCO format required by MMPose. This article will explain how to use Label Studio to annotate keypoint data and convert it into the required COCO format using the [labelstudio2coco.py](../../../tools/dataset_converters/labelstudio2coco.py) tool. + +## Label Studio Annotation Requirements + +According to the COCO format requirements, each annotated instance needs to include information about keypoints, segmentation, and bounding box (bbox). However, Label Studio scatters this information across different instances during annotation. Therefore, certain rules need to be followed during annotation to ensure proper usage with the subsequent scripts. + +1. Label Interface Setup + +For a newly created Label Studio project, the label interface needs to be set up. There should be three types of annotations: `KeyPointLabels`, `PolygonLabels`, and `RectangleLabels`, which correspond to `keypoints`, `segmentation`, and `bbox` in the COCO format, respectively. The following is an example of a label interface. You can find the `Labeling Interface` in the project's `Settings`, click on `Code`, and paste the following example. + +```xml + + + + + + + + + +``` + +2. Annotation Order + +Since it is necessary to combine annotations of different types into one instance, a specific order of annotation is required to determine whether the annotations belong to the same instance. Annotations should be made in the order of `KeyPointLabels` -> `PolygonLabels`/`RectangleLabels`. The order and number of `KeyPointLabels` should match the order and number of keypoints specified in the `dataset_info` in MMPose configuration file. The annotation order of `PolygonLabels` and `RectangleLabels` can be interchangeable, and only one of them needs to be annotated. The annotation should be within one instance starts with keypoints and ends with non-keypoints. The following image shows an annotation example: + +*Note: The bbox and area will be calculated based on the later PolygonLabels/RectangleLabels. If you annotate PolygonLabels first, the bbox will be based on the range of the later RectangleLabels, and the area will be equal to the area of the rectangle. Conversely, they will be based on the minimum bounding rectangle of the polygon and the area of the polygon.* + +![image](https://github.com/open-mmlab/mmpose/assets/15847281/b2d004d0-8361-42c5-9180-cfbac0373a94) + +3. Exporting Annotations + +Once the annotations are completed as described above, they need to be exported. Select the `Export` button on the project interface, choose the `JSON` format, and click `Export` to download the JSON file containing the labels. + +*Note: The exported file only contains the labels and does not include the original images. Therefore, the corresponding annotated images need to be provided separately. It is not recommended to use directly uploaded files because Label Studio truncates long filenames. Instead, use the export COCO format tool available in the `Export` functionality, which includes a folder with the image files within the downloaded compressed package.* + +![image](https://github.com/open-mmlab/mmpose/assets/15847281/9f54ca3d-8cdd-4d7f-8ed6-494badcfeaf2) + +## Usage of the Conversion Tool Script + +The conversion tool script is located at `tools/dataset_converters/labelstudio2coco.py`and can be used as follows: + +```bash +python tools/dataset_converters/labelstudio2coco.py config.xml project-1-at-2023-05-13-09-22-91b53efa.json output/result.json +``` + +Where `config.xml` contains the code from the Labeling Interface mentioned earlier, `project-1-at-2023-05-13-09-22-91b53efa.json` is the JSON file exported from Label Studio, and `output/result.json` is the path to the resulting JSON file in COCO format. If the path does not exist, the script will create it automatically. + +Afterward, place the image folder in the output directory to complete the conversion of the COCO dataset. The directory structure can be as follows: + +```bash +. +├── images +│   ├── 38b480f2.jpg +│   └── aeb26f04.jpg +└── result.json + +``` + +If you want to use this dataset in MMPose, you can make modifications like the following example: + +```python +dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='result.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, +) +``` diff --git a/docs/en/faq.md b/docs/en/faq.md index 40676cbb67..3e81a312ca 100644 --- a/docs/en/faq.md +++ b/docs/en/faq.md @@ -8,12 +8,19 @@ If the contents here do not cover your issue, please create an issue using the [ Compatibility issue between MMCV and MMPose; "AssertionError: MMCV==xxx is used but incompatible. Please install mmcv>=xxx, \<=xxx." -Compatible MMPose and MMCV versions are shown as below. Please choose the correct version of MMCV to avoid installation issues. +Here are the version correspondences between `mmdet`, `mmcv` and `mmpose`: + +- mmdet 2.x \<=> mmpose 0.x \<=> mmcv 1.x +- mmdet 3.x \<=> mmpose 1.x \<=> mmcv 2.x + +Detailed compatible MMPose and MMCV versions are shown as below. Please choose the correct version of MMCV to avoid installation issues. ### MMPose 1.x | MMPose version | MMCV/MMEngine version | | :------------: | :-----------------------------: | +| 1.1.0 | mmcv>=2.0.1, mmengine>=0.8.0 | +| 1.0.0 | mmcv>=2.0.0, mmengine>=0.7.0 | | 1.0.0rc1 | mmcv>=2.0.0rc4, mmengine>=0.6.0 | | 1.0.0rc0 | mmcv>=2.0.0rc0, mmengine>=0.0.1 | | 1.0.0b0 | mmcv>=2.0.0rc0, mmengine>=0.0.1 | @@ -22,7 +29,7 @@ Compatible MMPose and MMCV versions are shown as below. Please choose the correc | MMPose version | MMCV version | | :------------: | :-----------------------: | -| master | mmcv-full>=1.3.8, \<1.8.0 | +| 0.x | mmcv-full>=1.3.8, \<1.8.0 | | 0.29.0 | mmcv-full>=1.3.8, \<1.7.0 | | 0.28.1 | mmcv-full>=1.3.8, \<1.7.0 | | 0.28.0 | mmcv-full>=1.3.8, \<1.6.0 | diff --git a/docs/en/how_to.md b/docs/en/how_to.md deleted file mode 100644 index fe97ee6539..0000000000 --- a/docs/en/how_to.md +++ /dev/null @@ -1,110 +0,0 @@ -# How to - -## Log Analysis - -MMPose provides `tools/analysis_tools/analyze_logs.py` to analyze the training log. The log file can be either a json file or a text file. The json file is recommended, because it is more convenient to parse and visualize. - -Currently, the following functions are supported: - -- Plot loss/accuracy curves -- Calculate training time - -### Plot Loss/Accuracy Curves - -The function depends on `seaborn`, please install it first by running `pip install seaborn`. - -![log_curve](https://user-images.githubusercontent.com/87690686/188538215-5d985aaa-59f8-44cf-b6f9-10890d599e9c.png) - -```shell -python tools/analysis_tools/analyze_logs.py plot_curve ${JSON_LOGS} [--keys ${KEYS}] [--title ${TITLE}] [--legend ${LEGEND}] [--backend ${BACKEND}] [--style ${STYLE}] [--out ${OUT_FILE}] -``` - -Examples: - -- Plot loss curve - - ```shell - python tools/analysis_tools/analyze_logs.py plot_curve log.json --keys loss_kpt --legend loss_kpt - ``` - -- Plot accuracy curve and export to PDF file - - ```shell - python tools/analysis_tools/analyze_logs.py plot_curve log.json --keys acc_pose --out results.pdf - ``` - -- Plot multiple log files on the same figure - - ```shell - python tools/analysis_tools/analyze_logs.py plot_curve log1.json log2.json --keys loss_kpt --legend run1 run2 --title loss_kpt --out loss_kpt.png - ``` - -### Calculate Training Time - -```shell -python tools/analysis_tools/analyze_logs.py cal_train_time ${JSON_LOGS} [--include-outliers] -``` - -Examples: - -```shell -python tools/analysis_tools/analyze_logs.py cal_train_time log.json -``` - -The result is as follows: - -```text ------Analyze train time of hrnet_w32_256x192.json----- -slowest epoch 56, average time is 0.6924 -fastest epoch 1, average time is 0.6502 -time std over epochs is 0.0085 -average iter time: 0.6688 s/iter -``` - -## Get Model Params & FLOPs - -MMPose provides `tools/analysis_tools/get_flops.py` to get model parameters and FLOPs. - -```shell -python tools/analysis_tools/get_flops.py ${CONFIG_FILE} [--shape ${INPUT_SHAPE}] [--cfg-options ${CFG_OPTIONS}] -``` - -Description of all arguments: - -`CONFIG_FILE` : The path of a model config file. - -`--shape`: The input shape to the model. - -`--input-constructor`: If specified as batch, it will generate a batch tensor to calculate FLOPs. - -`--batch-size`:If `--input-constructor` is specified as batch, it will generate a random tensor with shape `(batch_size, 3, **input_shape)` to calculate FLOPs. - -`--cfg-options`: If specified, the key-value pair optional `cfg` will be merged into config file. - -Example: - -```shell -python tools/analysis_tools/get_flops.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192.py -``` - -We will get the following results: - -```text -============================== -Input shape: (1, 3, 256, 192) -Flops: 7.7 GFLOPs -Params: 28.54 M -============================== -``` - -```{note} -This tool is still experimental and we do not guarantee that the number is absolutely correct. Some operators are not counted into FLOPs like GN and custom operators. -``` - -## Print Entire Config - -Officially provided config files inherit multiple config files, which can facilitate management and reduce redundant code. But sometimes we want to know what the default parameter values that are not explicitly written in the configuration file are. MMPose provides `tools/analysis_tools/print_config.py` to print the entire configuration information verbatim. - -```shell -python tools/analysis_tools/print_config.py ${CONFIG} [-h] [--options ${OPTIONS [OPTIONS...]}] -``` diff --git a/docs/en/index.rst b/docs/en/index.rst index 61bc1706b6..044b54be0f 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -51,6 +51,7 @@ You can change the documentation language at the lower-left corner of the page. model_zoo.txt model_zoo/body_2d_keypoint.md + model_zoo/body_3d_keypoint.md model_zoo/face_2d_keypoint.md model_zoo/hand_2d_keypoint.md model_zoo/wholebody_2d_keypoint.md diff --git a/docs/en/installation.md b/docs/en/installation.md index dc4a0ab386..47db25bb5f 100644 --- a/docs/en/installation.md +++ b/docs/en/installation.md @@ -23,7 +23,7 @@ We recommend that users follow our best practices to install MMPose. However, th In this section we demonstrate how to prepare an environment with PyTorch. -MMPose works on Linux, Windows and macOS. It requires Python 3.7+, CUDA 9.2+ and PyTorch 1.6+. +MMPose works on Linux, Windows and macOS. It requires Python 3.7+, CUDA 9.2+ and PyTorch 1.8+. If you are experienced with PyTorch and have already installed it, you can skip this part and jump to the [MMPose Installation](#install-mmpose). Otherwise, you can follow these steps for the preparation. @@ -59,13 +59,13 @@ conda install pytorch torchvision cpuonly -c pytorch ```shell pip install -U openmim mim install mmengine -mim install "mmcv>=2.0.0" +mim install "mmcv>=2.0.1" ``` Note that some of the demo scripts in MMPose require [MMDetection](https://github.com/open-mmlab/mmdetection) (mmdet) for human detection. If you want to run these demo scripts with mmdet, you can easily install mmdet as a dependency by running: ```shell -mim install "mmdet>=3.0.0" +mim install "mmdet>=3.1.0" ``` ## Best Practices @@ -89,7 +89,7 @@ pip install -v -e . To use mmpose as a dependency or third-party package, install it with pip: ```shell -mim install "mmpose>=1.0.0" +mim install "mmpose>=1.1.0" ``` ## Verify the installation @@ -173,7 +173,7 @@ To install MMCV with pip instead of MIM, please follow [MMCV installation guides For example, the following command install mmcv built for PyTorch 1.10.x and CUDA 11.3. ```shell -pip install 'mmcv>=2.0.0' -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.10/index.html +pip install 'mmcv>=2.0.1' -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.10/index.html ``` ### Install on CPU-only platforms @@ -192,7 +192,7 @@ thus we only need to install MMEngine, MMCV and MMPose with the following comman ```shell !pip3 install openmim !mim install mmengine -!mim install "mmcv>=2.0.0" +!mim install "mmcv>=2.0.1" ``` **Step 2.** Install MMPose from the source. @@ -208,7 +208,7 @@ thus we only need to install MMEngine, MMCV and MMPose with the following comman ```python import mmpose print(mmpose.__version__) -# Example output: 1.0.0 +# Example output: 1.1.0 ``` ```{note} @@ -220,7 +220,7 @@ Note that within Jupyter, the exclamation mark `!` is used to call external exec We provide a [Dockerfile](https://github.com/open-mmlab/mmpose/blob/master/docker/Dockerfile) to build an image. Ensure that your [docker version](https://docs.docker.com/engine/install/) >=19.03. ```shell -# build an image with PyTorch 1.6.0, CUDA 10.1, CUDNN 7. +# build an image with PyTorch 1.8.0, CUDA 10.1, CUDNN 7. # If you prefer other versions, just modified the Dockerfile docker build -t mmpose docker/ ``` diff --git a/docs/en/merge_docs.sh b/docs/en/merge_docs.sh index 9dd222d3d0..23af31dd56 100644 --- a/docs/en/merge_docs.sh +++ b/docs/en/merge_docs.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash # Copyright (c) OpenMMLab. All rights reserved. -sed -i '$a\\n' ../../demo/docs/*_demo.md -cat ../../demo/docs/*_demo.md | sed "s/^## 2D\(.*\)Demo/##\1Estimation/" | sed "s/md###t/html#t/g" | sed '1i\# Demos\n' | sed 's=](/docs/en/=](/=g' | sed 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' >demos.md +sed -i '$a\\n' ../../demo/docs/en/*_demo.md +cat ../../demo/docs/en/*_demo.md | sed "s/^## 2D\(.*\)Demo/##\1Estimation/" | sed "s/md###t/html#t/g" | sed '1i\# Demos\n' | sed 's=](/docs/en/=](/=g' | sed 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' >demos.md # remove /docs/ for link used in doc site sed -i 's=](/docs/en/=](=g' overview.md @@ -18,14 +18,14 @@ sed -i 's=](/docs/en/=](=g' ./notes/*.md sed -i 's=](/docs/en/=](=g' ./projects/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' overview.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' installation.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' quick_run.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' migration.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./advanced_guides/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./model_zoo/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./model_zoo_papers/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./user_guides/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./dataset_zoo/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./notes/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./projects/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' overview.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' installation.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' quick_run.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' migration.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./advanced_guides/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./model_zoo/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./model_zoo_papers/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./user_guides/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./dataset_zoo/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./notes/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./projects/*.md diff --git a/docs/en/notes/pytorch_2.md b/docs/en/notes/pytorch_2.md index cd1d73f3fc..4892e554a5 100644 --- a/docs/en/notes/pytorch_2.md +++ b/docs/en/notes/pytorch_2.md @@ -1,3 +1,14 @@ # PyTorch 2.0 Compatibility and Benchmarks -Coming soon. +MMPose 1.0.0 is now compatible with PyTorch 2.0, ensuring that users can leverage the latest features and performance improvements offered by the PyTorch 2.0 framework when using MMPose. With the integration of inductor, users can expect faster model speeds. The table below shows several example models: + +| Model | Training Speed | Memory | +| :-------- | :---------------------: | :-----------: | +| ViTPose-B | 29.6% ↑ (0.931 → 0.655) | 10586 → 10663 | +| ViTPose-S | 33.7% ↑ (0.563 → 0.373) | 6091 → 6170 | +| HRNet-w32 | 12.8% ↑ (0.553 → 0.482) | 9849 → 10145 | +| HRNet-w48 | 37.1% ↑ (0.437 → 0.275) | 7319 → 7394 | +| RTMPose-t | 6.3% ↑ (1.533 → 1.437) | 6292 → 6489 | +| RTMPose-s | 13.1% ↑ (1.645 → 1.430) | 9013 → 9208 | + +- Pytorch 2.0 test, add projects doc and refactor by @LareinaM in [PR#2136](https://github.com/open-mmlab/mmpose/pull/2136) diff --git a/docs/en/stats.py b/docs/en/stats.py index b93be3203d..6d92d744ea 100644 --- a/docs/en/stats.py +++ b/docs/en/stats.py @@ -88,7 +88,7 @@ def anchor(name): * Number of papers: {len(allpapers)} {countstr} -For supported datasets, see [datasets overview](datasets.md). +For supported datasets, see [datasets overview](dataset_zoo.md). {msglist} @@ -167,7 +167,7 @@ def anchor(name): * Number of papers: {len(alldatapapers)} {countstr} -For supported pose algorithms, see [modelzoo overview](modelzoo.md). +For supported pose algorithms, see [modelzoo overview](model_zoo.md). {datamsglist} """ diff --git a/docs/en/user_guides/advanced_training.md b/docs/en/user_guides/advanced_training.md deleted file mode 100644 index ed079d16a5..0000000000 --- a/docs/en/user_guides/advanced_training.md +++ /dev/null @@ -1,96 +0,0 @@ -# Advanced Training - -## Resume Training - -Resume training means to continue training from the state saved from one of the previous trainings, where the state includes the model weights, the state of the optimizer and the optimizer parameter adjustment strategy. - -### Automatically resume training - -Users can add `--resume` to the end of the training command to resume training. The program will automatically load the latest weight file from `work_dirs` to resume training. If there is a latest `checkpoint` in `work_dirs` (e.g. the training was interrupted during the previous training), the training will be resumed from the `checkpoint`. Otherwise (e.g. the previous training did not save `checkpoint` in time or a new training task was started), the training will be restarted. - -Here is an example of resuming training: - -```shell -python tools/train.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_res50_8xb64-210e_coco-256x192.py --resume -``` - -### Specify the checkpoint to resume training - -You can also specify the `checkpoint` path for `--resume`. MMPose will automatically read the `checkpoint` and resume training from it. The command is as follows: - -```shell -python tools/train.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_res50_8xb64-210e_coco-256x192.py \ - --resume work_dirs/td-hm_res50_8xb64-210e_coco-256x192/latest.pth -``` - -If you hope to manually specify the `checkpoint` path in the config file, in addition to setting `resume=True`, you also need to set the `load_from`. - -It should be noted that if only `load_from` is set without setting `resume=True`, only the weights in the `checkpoint` will be loaded and the training will be restarted from scratch, instead of continuing from the previous state. - -The following example is equivalent to the example above that specifies the `--resume` parameter: - -```python -resume = True -load_from = 'work_dirs/td-hm_res50_8xb64-210e_coco-256x192/latest.pth' -# model settings -model = dict( - ## omitted ## - ) -``` - -## Automatic Mixed Precision (AMP) Training - -Mixed precision training can reduce training time and storage requirements without changing the model or reducing the model training accuracy, thus supporting larger batch sizes, larger models, and larger input sizes. - -To enable Automatic Mixing Precision (AMP) training, add `--amp` to the end of the training command, which is as follows: - -```shell -python tools/train.py ${CONFIG_FILE} --amp -``` - -Specific examples are as follows: - -```shell -python tools/train.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_res50_8xb64-210e_coco-256x192.py --amp -``` - -## Set the random seed - -If you want to specify the random seed during training, you can use the following command: - -```shell -python ./tools/train.py \ - ${CONFIG} \ # config file - --cfg-options randomness.seed=2023 \ # set the random seed = 2023 - [randomness.diff_rank_seed=True] \ # Set different seeds according to rank. - [randomness.deterministic=True] # Set the cuDNN backend deterministic option to True -# `[]` stands for optional parameters, when actually entering the command line, you do not need to enter `[]` -``` - -`randomness` has three parameters that can be set, with the following meanings. - -- `randomness.seed=2023`, set the random seed to `2023`. - -- `randomness.diff_rank_seed=True`, set different seeds according to global `rank`. Defaults to `False`. - -- `randomness.deterministic=True`, set the deterministic option for `cuDNN` backend, i.e., set `torch.backends.cudnn.deterministic` to `True` and `torch.backends.cudnn.benchmark` to `False`. Defaults to `False`. See [Pytorch Randomness](https://pytorch.org/docs/stable/notes/randomness.html) for more details. - -## Use Tensorboard to Visualize Training - -Install Tensorboard environment - -```shell -pip install tensorboard -``` - -Enable Tensorboard in the config file - -```python -visualizer = dict(vis_backends=[dict(type='LocalVisBackend'),dict(type='TensorboardVisBackend')]) -``` - -After training, you can use the following command to visualize the training process. - -```shell -tensorboard --logdir work_dir/${CONFIG}/${TIMESTAMP}/vis_data -``` diff --git a/docs/en/user_guides/configs.md b/docs/en/user_guides/configs.md index 6b2e72fbec..9d2c44f7ff 100644 --- a/docs/en/user_guides/configs.md +++ b/docs/en/user_guides/configs.md @@ -36,6 +36,15 @@ Class Loss_A(nn.Module): return x ``` +And import the new module in `__init__.py` in the corresponding directory: + +```Python +# __init__.py of mmpose/models/losses +from .loss_a.py import Loss_A + +__all__ = ['Loss_A'] +``` + Then you can define the module anywhere you want: ```Python @@ -102,7 +111,7 @@ General configuration refers to the necessary configuration non-related to train Here is the description of General configuration: ```Python -# 通用配置 +# General default_scope = 'mmpose' default_hooks = dict( timer=dict(type='IterTimerHook'), # time the data processing and model inference diff --git a/docs/en/user_guides/inference.md b/docs/en/user_guides/inference.md index de61a7b446..fa51aa20fa 100644 --- a/docs/en/user_guides/inference.md +++ b/docs/en/user_guides/inference.md @@ -20,7 +20,7 @@ from mmpose.apis import MMPoseInferencer img_path = 'tests/data/coco/000000000785.jpg' # replace this with your own image path -# create the inferencer using the model alias +# instantiate the inferencer using the model alias inferencer = MMPoseInferencer('human') # The MMPoseInferencer API employs a lazy inference approach, @@ -32,7 +32,46 @@ result = next(result_generator) If everything works fine, you will see the following image in a new window: ![inferencer_result_coco](https://user-images.githubusercontent.com/26127467/220008302-4a57fd44-0978-408e-8351-600e5513316a.jpg) -The variable `result` is a dictionary that contains two keys, `'visualization'` and `'predictions'`. The `'visualization'` key is meant to store visualization results, but since the `return_vis` argument wasn't specified, this list remains empty. The `'predictions'` key, however, holds a list of estimated keypoints for each detected instance. +The `result` variable is a dictionary comprising two keys, `'visualization'` and `'predictions'`. + +- `'visualization'` holds a list which: + + - contains visualization results, such as the input image, markers of the estimated poses, and optional predicted heatmaps. + - remains empty if the `return_vis` argument is not specified. + +- `'predictions'` stores: + + - a list of estimated keypoints for each identified instance. + +The structure of the `result` dictionary is as follows: + +```python +result = { + 'visualization': [ + # number of elements: batch_size (defaults to 1) + vis_image_1, + ... + ], + 'predictions': [ + # pose estimation result of each image + # number of elements: batch_size (defaults to 1) + [ + # pose information of each detected instance + # number of elements: number of detected instances + {'keypoints': ..., # instance 1 + 'keypoint_scores': ..., + ... + }, + {'keypoints': ..., # instance 2 + 'keypoint_scores': ..., + ... + }, + ] + ... + ] +} + +``` A **command-line interface (CLI)** tool for the inferencer is also available: `demo/inferencer_demo.py`. This tool allows users to perform inference using the same model and inputs with the following command: @@ -52,6 +91,17 @@ The inferencer is capable of processing a range of input types, which includes t - A list of image arrays (NA for CLI tool) - A webcam (in which case the `input` parameter should be set to either `'webcam'` or `'webcam:{CAMERA_ID}'`) +Please note that when the input corresponds to multiple images, such as when the input is a video or a folder path, the inference process needs to iterate over the results generator in order to perform inference on all the frames or images within the folder. Here's an example in Python: + +```python +folder_path = 'tests/data/coco' + +result_generator = inferencer(folder_path, show=True) +results = [result for result in result_generator] +``` + +In this example, the `inferencer` takes the `folder_path` as input and returns a generator object (`result_generator`) that produces inference results. By iterating over the `result_generator` and storing each result in the `results` list, you can obtain the inference results for all the frames or images within the folder. + ### Custom Pose Estimation Models The inferencer provides several methods that can be used to customize the models employed: @@ -75,6 +125,8 @@ inferencer = MMPoseInferencer( The complere list of model alias can be found in the [Model Alias](#model-alias) section. +**Custom Object Detector for Top-down Pose Estimation Models** + In addition, top-down pose estimators also require an object detection model. The inferencer is capable of inferring the instance type for models trained with datasets supported in MMPose, and subsequently constructing the necessary object detection model. Alternatively, users may also manually specify the detection model using the following methods: ```python @@ -107,6 +159,8 @@ inferencer = MMPoseInferencer( ) ``` +To perform top-down pose estimation on cropped images containing a single object, users can set `det_model='whole_image'`. This bypasses the object detector initialization, creating a bounding box that matches the input image size and directly sending the entire image to the top-down pose estimator. + ### Dump Results After performing pose estimation, you might want to save the results for further analysis or processing. This section will guide you through saving the predicted keypoints and visualizations to your local machine. @@ -171,28 +225,39 @@ The `MMPoseInferencer` offers a variety of arguments for customizing pose estima | ---------------- | ---------------------------------------------------------------------------------------------------------------- | | `pose2d` | Specifies the model alias, configuration file name, or configuration file path for the 2D pose estimation model. | | `pose2d_weights` | Specifies the URL or local path to the 2D pose estimation model's checkpoint file. | +| `pose3d` | Specifies the model alias, configuration file name, or configuration file path for the 3D pose estimation model. | +| `pose3d_weights` | Specifies the URL or local path to the 3D pose estimation model's checkpoint file. | | `det_model` | Specifies the model alias, configuration file name, or configuration file path for the object detection model. | | `det_weights` | Specifies the URL or local path to the object detection model's checkpoint file. | | `det_cat_ids` | Specifies the list of category IDs corresponding to the object classes to be detected. | | `device` | The device to perform the inference. If left `None`, the Inferencer will select the most suitable one. | | `scope` | The namespace where the model modules are defined. | -The inferencer is designed to handle both visualization and saving of predictions. Here is a list of arguments available when performing inference with the `MMPoseInferencer`: - -| Argument | Description | -| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -| `show` | Determines whether the image or video should be displayed in a pop-up window. | -| `radius` | Sets the keypoint radius for visualization. | -| `thickness` | Sets the link thickness for visualization. | -| `return_vis` | Determines whether visualization images should be included in the results. | -| `vis_out_dir` | Specifies the folder path for saving the visualization images. If not set, the visualization images will not be saved. | -| `return_datasample` | Determines whether to return the prediction in the format of `PoseDataSample`. | -| `pred_out_dir` | Specifies the folder path for saving the predictions. If not set, the predictions will not be saved. | -| `out_dir` | If `vis_out_dir` or `pred_out_dir` is not set, the values will be set to `f'{out_dir}/visualization'` or `f'{out_dir}/predictions'`, respectively. | +The inferencer is designed for both visualization and saving predictions. The table below presents the list of arguments available when using the `MMPoseInferencer` for inference, along with their compatibility with 2D and 3D inferencing: + +| Argument | Description | 2D | 3D | +| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | --- | +| `show` | Controls the display of the image or video in a pop-up window. | ✔️ | ✔️ | +| `radius` | Sets the visualization keypoint radius. | ✔️ | ✔️ | +| `thickness` | Determines the link thickness for visualization. | ✔️ | ✔️ | +| `kpt_thr` | Sets the keypoint score threshold. Keypoints with scores exceeding this threshold will be displayed. | ✔️ | ✔️ | +| `draw_bbox` | Decides whether to display the bounding boxes of instances. | ✔️ | ✔️ | +| `draw_heatmap` | Decides if the predicted heatmaps should be drawn. | ✔️ | ❌ | +| `black_background` | Decides whether the estimated poses should be displayed on a black background. | ✔️ | ❌ | +| `skeleton_style` | Sets the skeleton style. Options include 'mmpose' (default) and 'openpose'. | ✔️ | ❌ | +| `use_oks_tracking` | Decides whether to use OKS as a similarity measure in tracking. | ❌ | ✔️ | +| `tracking_thr` | Sets the similarity threshold for tracking. | ❌ | ✔️ | +| `norm_pose_2d` | Decides whether to scale the bounding box to the dataset's average bounding box scale and relocate the bounding box to the dataset's average bounding box center. | ❌ | ✔️ | +| `rebase_keypoint_height` | Decides whether to set the lowest keypoint with height 0. | ❌ | ✔️ | +| `return_vis` | Decides whether to include visualization images in the results. | ✔️ | ✔️ | +| `vis_out_dir` | Defines the folder path to save the visualization images. If unset, the visualization images will not be saved. | ✔️ | ✔️ | +| `return_datasample` | Determines if the prediction should be returned in the `PoseDataSample` format. | ✔️ | ✔️ | +| `pred_out_dir` | Specifies the folder path to save the predictions. If unset, the predictions will not be saved. | ✔️ | ✔️ | +| `out_dir` | If `vis_out_dir` or `pred_out_dir` is unset, these will be set to `f'{out_dir}/visualization'` or `f'{out_dir}/predictions'`, respectively. | ✔️ | ✔️ | ### Model Alias -MMPose provides a set of pre-defined aliases for commonly used models. These aliases can be used as shorthand when initializing the `MMPoseInferencer` instead of specifying the full model configuration name. Below is a list of the available model aliases and their corresponding configuration names: +The MMPose library has predefined aliases for several frequently used models. These aliases can be utilized as a shortcut when initializing the `MMPoseInferencer`, as an alternative to providing the full model configuration name. Here are the available 2D model aliases and their corresponding configuration names: | Alias | Configuration Name | Task | Pose Estimator | Detector | | --------- | -------------------------------------------------- | ------------------------------- | -------------- | ------------------- | @@ -207,6 +272,12 @@ MMPose provides a set of pre-defined aliases for commonly used models. These ali | vitpose-l | td-hm_ViTPose-large-simple_8xb64-210e_coco-256x192 | Human pose estimation | ViTPose-large | RTMDet-m | | vitpose-h | td-hm_ViTPose-huge-simple_8xb64-210e_coco-256x192 | Human pose estimation | ViTPose-huge | RTMDet-m | +The following table lists the available 3D model aliases and their corresponding configuration names: + +| Alias | Configuration Name | Task | 3D Pose Estimator | 2D Pose Estimator | Detector | +| ------- | --------------------------------------------------------- | ------------------------ | ----------------- | ----------------- | -------- | +| human3d | pose-lift_videopose3d-243frm-supv-cpn-ft_8xb128-200e_h36m | Human 3D pose estimation | VideoPose3D | RTMPose-m | RTMDet-m | + In addition, users can utilize the CLI tool to display all available aliases with the following command: ```shell diff --git a/docs/en/user_guides/prepare_datasets.md b/docs/en/user_guides/prepare_datasets.md index a14a9601cd..2f8ddcbc32 100644 --- a/docs/en/user_guides/prepare_datasets.md +++ b/docs/en/user_guides/prepare_datasets.md @@ -1,271 +1,221 @@ # Prepare Datasets -MMPose supports multiple tasks and corresponding datasets. You can find them in [dataset zoo](https://mmpose.readthedocs.io/en/latest/dataset_zoo.html). Please follow the corresponding guidelines for data preparation. - - - -- [Customize datasets by reorganizing data to COCO format](#customize-datasets-by-reorganizing-data-to-coco-format) -- [Create a custom dataset_info config file for the dataset](#create-a-custom-datasetinfo-config-file-for-the-dataset) -- [Create a custom dataset class](#create-a-custom-dataset-class) -- [Create a custom training config file](#create-a-custom-training-config-file) -- [Dataset Wrappers](#dataset-wrappers) - - - -## Customize datasets by reorganizing data to COCO format - -The simplest way to use the custom dataset is to convert your annotation format to COCO dataset format. - -The annotation JSON files in COCO format have the following necessary keys: - -```python -'images': [ - { - 'file_name': '000000001268.jpg', - 'height': 427, - 'width': 640, - 'id': 1268 - }, - ... -], -'annotations': [ - { - 'segmentation': [[426.36, - ... - 424.34, - 223.3]], - 'keypoints': [0,0,0, - 0,0,0, - 0,0,0, - 427,220,2, - 443,222,2, - 414,228,2, - 449,232,2, - 408,248,1, - 454,261,2, - 0,0,0, - 0,0,0, - 411,287,2, - 431,287,2, - 0,0,0, - 458,265,2, - 0,0,0, - 466,300,1], - 'num_keypoints': 10, - 'area': 3894.5826, - 'iscrowd': 0, - 'image_id': 1268, - 'bbox': [402.34, 205.02, 65.26, 88.45], - 'category_id': 1, - 'id': 215218 - }, - ... -], -'categories': [ - {'id': 1, 'name': 'person'}, - ] +In this document, we will give a guide on the process of preparing datasets for the MMPose. Various aspects of dataset preparation will be discussed, including using built-in datasets, creating custom datasets, combining datasets for training, browsing and downloading the datasets. + +## Use built-in datasets + +**Step 1**: Prepare Data + +MMPose supports multiple tasks and corresponding datasets. You can find them in [dataset zoo](https://mmpose.readthedocs.io/en/latest/dataset_zoo.html). To properly prepare your data, please follow the guidelines associated with your chosen dataset. + +**Step 2**: Configure Dataset Settings in the Config File + +Before training or evaluating models, you must configure the dataset settings. Take [`td-hm_hrnet-w32_8xb64-210e_coco-256x192.py`](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192.py) for example, which can be used to train or evaluate the HRNet pose estimator on COCO dataset. We will go through the dataset configuration. + +- Basic Dataset Arguments + + ```python + # base dataset settings + dataset_type = 'CocoDataset' + data_mode = 'topdown' + data_root = 'data/coco/' + ``` + + - `dataset_type` specifies the class name of the dataset. Users can refer to [Datasets APIs](https://mmpose.readthedocs.io/en/latest/api.html#datasets) to find the class name of their desired dataset. + - `data_mode` determines the output format of the dataset, with two options available: `'topdown'` and `'bottomup'`. If `data_mode='topdown'`, the data element represents a single instance with its pose; otherwise, the data element is an entire image containing multiple instances and poses. + - `data_root` designates the root directory of the dataset. + +- Data Processing Pipelines + + ```python + # pipelines + train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') + ] + val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') + ] + ``` + + The `train_pipeline` and `val_pipeline` define the steps to process data elements during the training and evaluation phases, respectively. In addition to loading images and packing inputs, the `train_pipeline` primarily consists of data augmentation techniques and target generator, while the `val_pipeline` focuses on transforming data elements into a unified format. + +- Data Loaders + + ```python + # data loaders + train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/person_keypoints_train2017.json', + data_prefix=dict(img='train2017/'), + pipeline=train_pipeline, + )) + val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/person_keypoints_val2017.json', + bbox_file='data/coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', + data_prefix=dict(img='val2017/'), + test_mode=True, + pipeline=val_pipeline, + )) + test_dataloader = val_dataloader + ``` + + This section is crucial for configuring the dataset in the config file. In addition to the basic dataset arguments and pipelines discussed earlier, other important parameters are defined here. The `batch_size` determines the batch size per GPU; the `ann_file` indicates the annotation file for the dataset; and `data_prefix` specifies the image folder. The `bbox_file`, which supplies detected bounding box information, is only used in the val/test data loader for top-down datasets. + +We recommend copying the dataset configuration from provided config files that use the same dataset, rather than writing it from scratch, in order to minimize potential errors. By doing so, users can simply make the necessary modifications as needed, ensuring a more reliable and efficient setup process. + +## Use a custom dataset + +The [Customize Datasets](../advanced_guides/customize_datasets.md) guide provides detailed information on how to build a custom dataset. In this section, we will highlight some key tips for using and configuring custom datasets. + +- Determine the dataset class name. If you reorganize your dataset into the COCO format, you can simply use `CocoDataset` as the value for `dataset_type`. Otherwise, you will need to use the name of the custom dataset class you added. + +- Specify the meta information config file. MMPose 1.x employs a different strategy for specifying meta information compared to MMPose 0.x. In MMPose 1.x, users can specify the meta information config file as follows: + + ```python + train_dataloader = dict( + ... + dataset=dict( + type=dataset_type, + data_root='root/of/your/train/data', + ann_file='path/to/your/train/json', + data_prefix=dict(img='path/to/your/train/img'), + # specify dataset meta information + metainfo=dict(from_file='configs/_base_/datasets/custom.py'), + ...), + ) + ``` + + Note that the argument `metainfo` must be specified in the val/test data loaders as well. + +## Use mixed datasets for training + +MMPose offers a convenient and versatile solution for training with mixed datasets. Please refer to [Use Mixed Datasets for Training](./mixed_datasets.md). + +## Browse dataset + +`tools/analysis_tools/browse_dataset.py` helps the user to browse a pose dataset visually, or save the image to a designated directory. + +```shell +python tools/misc/browse_dataset.py ${CONFIG} [-h] [--output-dir ${OUTPUT_DIR}] [--not-show] [--phase ${PHASE}] [--mode ${MODE}] [--show-interval ${SHOW_INTERVAL}] ``` -There are three necessary keys in the json file: +| ARGS | Description | +| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| `CONFIG` | The path to the config file. | +| `--output-dir OUTPUT_DIR` | The target folder to save visualization results. If not specified, the visualization results will not be saved. | +| `--not-show` | Do not show the visualization results in an external window. | +| `--phase {train, val, test}` | Options for dataset. | +| `--mode {original, transformed}` | Specify the type of visualized images. `original` means to show images without pre-processing; `transformed` means to show images are pre-processed. | +| `--show-interval SHOW_INTERVAL` | Time interval between visualizing two images. | -- `images`: contains a list of images with their information like `file_name`, `height`, `width`, and `id`. -- `annotations`: contains the list of instance annotations. -- `categories`: contains the category name ('person') and its ID (1). - -If the annotations have been organized in COCO format, there is no need to create a new dataset class. You can use `CocoDataset` class alternatively. - -## Create a custom dataset_info config file for the dataset - -Add a new dataset info config file that contains the metainfo about the dataset. +For instance, users who want to visualize images and annotations in COCO dataset use: +```shell +python tools/misc/browse_dataset.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-e210_coco-256x192.py --mode original ``` -configs/_base_/datasets/custom.py -``` - -An example of the dataset config is as follows. - -`keypoint_info` contains the information about each keypoint. -1. `name`: the keypoint name. The keypoint name must be unique. -2. `id`: the keypoint id. -3. `color`: (\[B, G, R\]) is used for keypoint visualization. -4. `type`: 'upper' or 'lower', will be used in data augmentation. -5. `swap`: indicates the 'swap pair' (also known as 'flip pair'). When applying image horizontal flip, the left part will become the right part. We need to flip the keypoints accordingly. +The bounding boxes and keypoints will be plotted on the original image. Following is an example: +![original_coco](https://user-images.githubusercontent.com/26127467/187383698-7e518f21-b4cc-4712-9e97-99ddd8f0e437.jpg) -`skeleton_info` contains information about the keypoint connectivity, which is used for visualization. +The original images need to be processed before being fed into models. To visualize pre-processed images and annotations, users need to modify the argument `mode` to `transformed`. For example: -`joint_weights` assigns different loss weights to different keypoints. +```shell +python tools/misc/browse_dataset.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-e210_coco-256x192.py --mode transformed +``` -`sigmas` is used to calculate the OKS score. You can read [keypoints-eval](https://cocodataset.org/#keypoints-eval) to learn more about it. +Here is a processed sample -Here is an simplified example of dataset_info config file ([full text](/configs/_base_/datasets/coco.py)). +![transformed_coco](https://user-images.githubusercontent.com/26127467/187386652-bd47335d-797c-4e8c-b823-2a4915f9812f.jpg) -``` -dataset_info = dict( - dataset_name='coco', - paper_info=dict( - author='Lin, Tsung-Yi and Maire, Michael and ' - 'Belongie, Serge and Hays, James and ' - 'Perona, Pietro and Ramanan, Deva and ' - r'Doll{\'a}r, Piotr and Zitnick, C Lawrence', - title='Microsoft coco: Common objects in context', - container='European conference on computer vision', - year='2014', - homepage='http://cocodataset.org/', - ), - keypoint_info={ - 0: - dict(name='nose', id=0, color=[51, 153, 255], type='upper', swap=''), - 1: - dict( - name='left_eye', - id=1, - color=[51, 153, 255], - type='upper', - swap='right_eye'), - ... - 16: - dict( - name='right_ankle', - id=16, - color=[255, 128, 0], - type='lower', - swap='left_ankle') - }, - skeleton_info={ - 0: - dict(link=('left_ankle', 'left_knee'), id=0, color=[0, 255, 0]), - ... - 18: - dict( - link=('right_ear', 'right_shoulder'), id=18, color=[51, 153, 255]) - }, - joint_weights=[ - 1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5, - 1.5 - ], - sigmas=[ - 0.026, 0.025, 0.025, 0.035, 0.035, 0.079, 0.079, 0.072, 0.072, 0.062, - 0.062, 0.107, 0.107, 0.087, 0.087, 0.089, 0.089 - ]) -``` +The heatmap target will be visualized together if it is generated in the pipeline. -## Create a custom dataset class +## Download dataset via MIM -If the annotations are not organized in COCO format, you need to create a custom dataset class by the following steps: +By using [OpenDataLab](https://opendatalab.com/), you can obtain free formatted datasets in various fields. Through the search function of the platform, you may address the dataset they look for quickly and easily. Using the formatted datasets from the platform, you can efficiently conduct tasks across datasets. -1. First create a package inside the `mmpose/datasets/datasets` folder. +If you use MIM to download, make sure that the version is greater than v0.3.8. You can use the following command to update, install, login and download the dataset: -2. Create a class definition of your dataset in the package folder and register it in the registry with a name. Without a name, it will keep giving the error. `KeyError: 'XXXXX is not in the dataset registry'` +```shell +# upgrade your MIM +pip install -U openmim - ``` - from mmengine.dataset import BaseDataset - from mmpose.registry import DATASETS +# install OpenDataLab CLI tools +pip install -U opendatalab +# log in OpenDataLab, registry +odl login - @DATASETS.register_module(name='MyCustomDataset') - class MyCustomDataset(BaseDataset): - ``` +# download coco2017 and preprocess by MIM +mim download mmpose --dataset coco2017 +``` - You can refer to [this doc](https://mmengine.readthedocs.io/en/latest/advanced_tutorials/basedataset.html) on how to build customed dataset class with `mmengine.BaseDataset`. +### Supported datasets -3. Make sure you have updated the `__init__.py` of your package folder +Here is the list of supported datasets, we will continue to update it in the future. -4. Make sure you have updated the `__init__.py` of the dataset package folder. +#### Body -## Create a custom training config file +| Dataset name | Download command | +| ------------- | ----------------------------------------- | +| COCO 2017 | `mim download mmpose --dataset coco2017` | +| MPII | `mim download mmpose --dataset mpii` | +| AI Challenger | `mim download mmpose --dataset aic` | +| CrowdPose | `mim download mmpose --dataset crowdpose` | -Create a custom training config file as per your need and the model/architecture you want to use in the configs folder. You may modify an existing config file to use the new custom dataset. +#### Face -In `configs/my_custom_config.py`: +| Dataset name | Download command | +| ------------ | ------------------------------------ | +| LaPa | `mim download mmpose --dataset lapa` | +| 300W | `mim download mmpose --dataset 300w` | +| WFLW | `mim download mmpose --dataset wflw` | -```python -... -# dataset and dataloader settings -dataset_type = 'MyCustomDataset' # or 'CocoDataset' +#### Hand -train_dataloader = dict( - batch_size=2, - dataset=dict( - type=dataset_type, - data_root='root/of/your/train/data', - ann_file='path/to/your/train/json', - data_prefix=dict(img='path/to/your/train/img'), - metainfo=dict(from_file='configs/_base_/datasets/custom.py'), - ...), - ) +| Dataset name | Download command | +| ------------ | ------------------------------------------ | +| OneHand10K | `mim download mmpose --dataset onehand10k` | +| FreiHand | `mim download mmpose --dataset freihand` | +| HaGRID | `mim download mmpose --dataset hagrid` | -val_dataloader = dict( - batch_size=2, - dataset=dict( - type=dataset_type, - data_root='root/of/your/val/data', - ann_file='path/to/your/val/json', - data_prefix=dict(img='path/to/your/val/img'), - metainfo=dict(from_file='configs/_base_/datasets/custom.py'), - ...), - ) +#### Whole Body -test_dataloader = dict( - batch_size=2, - dataset=dict( - type=dataset_type, - data_root='root/of/your/test/data', - ann_file='path/to/your/test/json', - data_prefix=dict(img='path/to/your/test/img'), - metainfo=dict(from_file='configs/_base_/datasets/custom.py'), - ...), - ) -... -``` +| Dataset name | Download command | +| ------------ | ------------------------------------- | +| Halpe | `mim download mmpose --dataset halpe` | -Make sure you have provided all the paths correctly. - -## Dataset Wrappers - -The following dataset wrappers are supported in [MMEngine](https://github.com/open-mmlab/mmengine), you can refer to [MMEngine tutorial](https://mmengine.readthedocs.io/en/latest) to learn how to use it. - -- [ConcatDataset](https://mmengine.readthedocs.io/en/latest/advanced_tutorials/basedataset.html#concatdataset) -- [RepeatDataset](https://mmengine.readthedocs.io/en/latest/advanced_tutorials/basedataset.html#repeatdataset) - -### CombinedDataset - -MMPose provides `CombinedDataset` to combine multiple datasets with different annotations. A combined dataset can be defined in config files as: - -```python -dataset_1 = dict( - type='dataset_type_1', - data_root='root/of/your/dataset1', - data_prefix=dict(img_path='path/to/your/img'), - ann_file='annotations/train.json', - pipeline=[ - # the converter transforms convert data into a unified format - converter_transform_1 - ]) - -dataset_2 = dict( - type='dataset_type_2', - data_root='root/of/your/dataset2', - data_prefix=dict(img_path='path/to/your/img'), - ann_file='annotations/train.json', - pipeline=[ - converter_transform_2 - ]) - -shared_pipeline = [ - LoadImage(), - ParseImage(), -] - -combined_dataset = dict( - type='CombinedDataset', - metainfo=dict(from_file='path/to/your/metainfo'), - datasets=[dataset_1, dataset_2], - pipeline=shared_pipeline, -) -``` +#### Animal -- **MetaInfo of combined dataset** determines the annotation format. Either metainfo of a sub-dataset or a customed dataset metainfo is valid here. To custom a dataset metainfo, please refer to [Create a custom dataset_info config file for the dataset](#create-a-custom-datasetinfo-config-file-for-the-dataset). +| Dataset name | Download command | +| ------------ | ------------------------------------- | +| AP-10K | `mim download mmpose --dataset ap10k` | -- **Converter transforms of sub-datasets** are applied when there exist mismatches of annotation format between sub-datasets and the combined dataset. For example, the number and order of keypoints might be different in the combined dataset and the sub-datasets. Then `KeypointConverter` can be used to unify the keypoints number and order. +#### Fashion -- More details about `CombinedDataset` and `KeypointConverter` can be found in Advanced Guides-[Training with Mixed Datasets](../advanced_guides/mixed_datasets.md). +Coming Soon diff --git a/docs/en/user_guides/train_and_test.md b/docs/en/user_guides/train_and_test.md index 95b3540003..6bcc88fc3b 100644 --- a/docs/en/user_guides/train_and_test.md +++ b/docs/en/user_guides/train_and_test.md @@ -1,23 +1,6 @@ -# Train and Test +# Training and Testing - - -- [Train](#train) - - [Train with your PC](#train-with-your-pc) - - [Train with multiple GPUs](#train-with-multiple-gpus) - - [Train with multiple machines](#train-with-multiple-machines) - - [Multiple machines in the same network](#multiple-machines-in-the-same-network) - - [Multiple machines managed with slurm](#multiple-machines-managed-with-slurm) -- [Test](#test) - - [Test with your PC](#test-with-your-pc) - - [Test with multiple GPUs](#test-with-multiple-gpus) - - [Test with multiple machines](#test-with-multiple-machines) - - [Multiple machines in the same network](#multiple-machines-in-the-same-network-1) - - [Multiple machines managed with slurm](#multiple-machines-managed-with-slurm-1) - - - -## Train +## Launch training ### Train with your PC @@ -138,7 +121,133 @@ Here are the environment variables that can be used to configure the slurm job. | `CPUS_PER_TASK` | The number of CPUs to be allocated per task (Usually one GPU corresponds to one task). Defaults to 5. | | `SRUN_ARGS` | The other arguments of `srun`. Available options can be found [here](https://slurm.schedmd.com/srun.html). | -## Test +## Resume training + +Resume training means to continue training from the state saved from one of the previous trainings, where the state includes the model weights, the state of the optimizer and the optimizer parameter adjustment strategy. + +### Automatically resume training + +Users can add `--resume` to the end of the training command to resume training. The program will automatically load the latest weight file from `work_dirs` to resume training. If there is a latest `checkpoint` in `work_dirs` (e.g. the training was interrupted during the previous training), the training will be resumed from the `checkpoint`. Otherwise (e.g. the previous training did not save `checkpoint` in time or a new training task was started), the training will be restarted. + +Here is an example of resuming training: + +```shell +python tools/train.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_res50_8xb64-210e_coco-256x192.py --resume +``` + +### Specify the checkpoint to resume training + +You can also specify the `checkpoint` path for `--resume`. MMPose will automatically read the `checkpoint` and resume training from it. The command is as follows: + +```shell +python tools/train.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_res50_8xb64-210e_coco-256x192.py \ + --resume work_dirs/td-hm_res50_8xb64-210e_coco-256x192/latest.pth +``` + +If you hope to manually specify the `checkpoint` path in the config file, in addition to setting `resume=True`, you also need to set the `load_from`. + +It should be noted that if only `load_from` is set without setting `resume=True`, only the weights in the `checkpoint` will be loaded and the training will be restarted from scratch, instead of continuing from the previous state. + +The following example is equivalent to the example above that specifies the `--resume` parameter: + +```python +resume = True +load_from = 'work_dirs/td-hm_res50_8xb64-210e_coco-256x192/latest.pth' +# model settings +model = dict( + ## omitted ## + ) +``` + +## Freeze partial parameters during training + +In some scenarios, it might be desirable to freeze certain parameters of a model during training to fine-tune specific parts or to prevent overfitting. In MMPose, you can set different hyperparameters for any module in the model by setting custom_keys in `paramwise_cfg`. This allows you to control the learning rate and decay coefficient for specific parts of the model. + +For example, if you want to freeze the parameters in `backbone.layer0` and `backbone.layer1`, you can modify the optimizer wrapper in the config file as: + +```python +optim_wrapper = dict( + optimizer=dict(...), + paramwise_cfg=dict( + custom_keys={ + 'backbone.layer0': dict(lr_mult=0, decay_mult=0), + 'backbone.layer0': dict(lr_mult=0, decay_mult=0), + })) +``` + +This configuration will freeze the parameters in `backbone.layer0` and `backbone.layer1` by setting their learning rate and decay coefficient to 0. By using this approach, you can effectively control the training process and fine-tune specific parts of your model as needed. + +## Automatic Mixed Precision (AMP) training + +Mixed precision training can reduce training time and storage requirements without changing the model or reducing the model training accuracy, thus supporting larger batch sizes, larger models, and larger input sizes. + +To enable Automatic Mixing Precision (AMP) training, add `--amp` to the end of the training command, which is as follows: + +```shell +python tools/train.py ${CONFIG_FILE} --amp +``` + +Specific examples are as follows: + +```shell +python tools/train.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_res50_8xb64-210e_coco-256x192.py --amp +``` + +## Set the random seed + +If you want to specify the random seed during training, you can use the following command: + +```shell +python ./tools/train.py \ + ${CONFIG} \ # config file + --cfg-options randomness.seed=2023 \ # set the random seed = 2023 + [randomness.diff_rank_seed=True] \ # Set different seeds according to rank. + [randomness.deterministic=True] # Set the cuDNN backend deterministic option to True +# `[]` stands for optional parameters, when actually entering the command line, you do not need to enter `[]` +``` + +`randomness` has three parameters that can be set, with the following meanings. + +- `randomness.seed=2023`, set the random seed to `2023`. + +- `randomness.diff_rank_seed=True`, set different seeds according to global `rank`. Defaults to `False`. + +- `randomness.deterministic=True`, set the deterministic option for `cuDNN` backend, i.e., set `torch.backends.cudnn.deterministic` to `True` and `torch.backends.cudnn.benchmark` to `False`. Defaults to `False`. See [Pytorch Randomness](https://pytorch.org/docs/stable/notes/randomness.html) for more details. + +## Visualize training process + +Monitoring the training process is essential for understanding the performance of your model and making necessary adjustments. In this section, we will introduce two methods to visualize the training process of your MMPose model: TensorBoard and the MMEngine Visualizer. + +### TensorBoard + +TensorBoard is a powerful tool that allows you to visualize the changes in losses during training. To enable TensorBoard visualization, you may need to: + +1. Install TensorBoard environment + + ```shell + pip install tensorboard + ``` + +2. Enable TensorBoard in the config file + + ```python + visualizer = dict(vis_backends=[ + dict(type='LocalVisBackend'), + dict(type='TensorboardVisBackend'), + ]) + ``` + +The event file generated by TensorBoard will be save under the experiment log folder `${WORK_DIR}`, which defaults to `work_dir/${CONFIG}` or can be specified using the `--work-dir` option. To visualize the training process, use the following command: + +```shell +tensorboard --logdir ${WORK_DIR}/${TIMESTAMP}/vis_data +``` + +### MMEngine visualizer + +MMPose also supports visualizing model inference results during validation. To activate this function, please use the `--show` option or set `--show-dir` when launching training. This feature provides an effective way to analyze the model's performance on specific examples and make any necessary adjustments. + +## Test your model ### Test with your PC @@ -200,7 +309,7 @@ different port and visible devices. ```shell CUDA_VISIBLE_DEVICES=0,1,2,3 PORT=29500 bash ./tools/dist_test.sh ${CONFIG_FILE1} ${CHECKPOINT_FILE} 4 [PY_ARGS] -CUDA_VISIBLE_DEVICES=4,5,6,7 GPUS=29501 bash ./tools/dist_test.sh ${CONFIG_FILE2} ${CHECKPOINT_FILE} 4 [PY_ARGS] +CUDA_VISIBLE_DEVICES=4,5,6,7 PORT=29501 bash ./tools/dist_test.sh ${CONFIG_FILE2} ${CHECKPOINT_FILE} 4 [PY_ARGS] ``` ### Test with multiple machines diff --git a/docs/en/webcam_api.rst b/docs/en/webcam_api.rst deleted file mode 100644 index ff1c127515..0000000000 --- a/docs/en/webcam_api.rst +++ /dev/null @@ -1,112 +0,0 @@ -mmpose.apis.webcam --------------------- -.. contents:: MMPose Webcam API: Tools to build simple interactive webcam applications and demos - :depth: 2 - :local: - :backlinks: top - -Executor -^^^^^^^^^^^^^^^^^^^^ -.. currentmodule:: mmpose.apis.webcam -.. autosummary:: - :toctree: generated - :nosignatures: - - WebcamExecutor - -Nodes -^^^^^^^^^^^^^^^^^^^^ -.. currentmodule:: mmpose.apis.webcam.nodes - -Base Nodes -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - :template: webcam_node_class.rst - - Node - BaseVisualizerNode - -Model Nodes -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - :template: webcam_node_class.rst - - DetectorNode - TopdownPoseEstimatorNode - -Visualizer Nodes -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - :template: webcam_node_class.rst - - ObjectVisualizerNode - NoticeBoardNode - SunglassesEffectNode - BigeyeEffectNode - -Helper Nodes -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - :template: webcam_node_class.rst - - ObjectAssignerNode - MonitorNode - RecorderNode - -Utils -^^^^^^^^^^^^^^^^^^^^ -.. currentmodule:: mmpose.apis.webcam.utils - -Buffer and Message -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - - BufferManager - Message - FrameMessage - VideoEndingMessage - -Pose -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - - get_eye_keypoint_ids - get_face_keypoint_ids - get_hand_keypoint_ids - get_mouth_keypoint_ids - get_wrist_keypoint_ids - -Event -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - - EventManager - -Misc -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - - copy_and_paste - screen_matting - expand_and_clamp - limit_max_fps - is_image_file - get_cached_file_path - load_image_from_disk_or_url - get_config_path diff --git a/docs/src/papers/algorithms/vitpose.md b/docs/src/papers/algorithms/vitpose.md index 3c74233dfa..dd218a5f98 100644 --- a/docs/src/papers/algorithms/vitpose.md +++ b/docs/src/papers/algorithms/vitpose.md @@ -8,7 +8,7 @@ ```bibtex @inproceedings{ xu2022vitpose, - title={Vi{TP}ose: Simple Vision Transformer Baselines for Human Pose Estimation}, + title={ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation}, author={Yufei Xu and Jing Zhang and Qiming Zhang and Dacheng Tao}, booktitle={Advances in Neural Information Processing Systems}, year={2022}, diff --git a/docs/src/papers/datasets/animalkingdom.md b/docs/src/papers/datasets/animalkingdom.md new file mode 100644 index 0000000000..64b5fe375a --- /dev/null +++ b/docs/src/papers/datasets/animalkingdom.md @@ -0,0 +1,19 @@ +# Animal Kingdom: A Large and Diverse Dataset for Animal Behavior Understanding + + + +
+Animal Kingdom (CVPR'2022) + +```bibtex +@InProceedings{Ng_2022_CVPR, + author = {Ng, Xun Long and Ong, Kian Eng and Zheng, Qichen and Ni, Yun and Yeo, Si Yong and Liu, Jun}, + title = {Animal Kingdom: A Large and Diverse Dataset for Animal Behavior Understanding}, + booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)}, + month = {June}, + year = {2022}, + pages = {19023-19034} + } +``` + +
diff --git a/docs/src/papers/datasets/human_art.md b/docs/src/papers/datasets/human_art.md new file mode 100644 index 0000000000..dc39dabbad --- /dev/null +++ b/docs/src/papers/datasets/human_art.md @@ -0,0 +1,16 @@ +# Human-Art: A Versatile Human-Centric Dataset Bridging Natural and Artificial Scenes + + + +
+Human-Art (CVPR'2023) + +```bibtex +@inproceedings{ju2023humanart, + title={Human-Art: A Versatile Human-Centric Dataset Bridging Natural and Artificial Scenes}, + author={Ju, Xuan and Zeng, Ailing and Jianan, Wang and Qiang, Xu and Lei, Zhang}, + booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), + year={2023}} +``` + +
diff --git a/docs/src/papers/datasets/lapa.md b/docs/src/papers/datasets/lapa.md new file mode 100644 index 0000000000..f82c50ca22 --- /dev/null +++ b/docs/src/papers/datasets/lapa.md @@ -0,0 +1,18 @@ +# A New Dataset and Boundary-Attention Semantic Segmentation for Face Parsing + + + +
+LaPa (AAAI'2020) + +```bibtex +@inproceedings{liu2020new, + title={A New Dataset and Boundary-Attention Semantic Segmentation for Face Parsing.}, + author={Liu, Yinglu and Shi, Hailin and Shen, Hao and Si, Yue and Wang, Xiaobo and Mei, Tao}, + booktitle={AAAI}, + pages={11637--11644}, + year={2020} +} +``` + +
diff --git a/docs/zh_cn/advanced_guides/customize_datasets.md b/docs/zh_cn/advanced_guides/customize_datasets.md index 1829c37a0c..61b58dc929 100644 --- a/docs/zh_cn/advanced_guides/customize_datasets.md +++ b/docs/zh_cn/advanced_guides/customize_datasets.md @@ -1,3 +1,264 @@ -# Customize Datasets +# 自定义数据集 -Coming soon. +MMPose 目前已支持了多个任务和相应的数据集。您可以在 [数据集](https://mmpose.readthedocs.io/zh_CN/latest/dataset_zoo.html) 找到它们。请按照相应的指南准备数据。 + + + +- [自定义数据集-将数据组织为 COCO 格式](#自定义数据集-将数据组织为-coco-格式) +- [创建自定义数据集的元信息文件](#创建自定义数据集的元信息文件) +- [创建自定义数据集类](#创建自定义数据集类) +- [创建自定义配置文件](#创建自定义配置文件) +- [数据集封装](#数据集封装) + + + +## 将数据组织为 COCO 格式 + +最简单的使用自定义数据集的方法是将您的注释格式转换为 COCO 数据集格式。 + +COCO 格式的注释 JSON 文件具有以下必要键: + +```python +'images': [ + { + 'file_name': '000000001268.jpg', + 'height': 427, + 'width': 640, + 'id': 1268 + }, + ... +], +'annotations': [ + { + 'segmentation': [[426.36, + ... + 424.34, + 223.3]], + 'keypoints': [0,0,0, + 0,0,0, + 0,0,0, + 427,220,2, + 443,222,2, + 414,228,2, + 449,232,2, + 408,248,1, + 454,261,2, + 0,0,0, + 0,0,0, + 411,287,2, + 431,287,2, + 0,0,0, + 458,265,2, + 0,0,0, + 466,300,1], + 'num_keypoints': 10, + 'area': 3894.5826, + 'iscrowd': 0, + 'image_id': 1268, + 'bbox': [402.34, 205.02, 65.26, 88.45], + 'category_id': 1, + 'id': 215218 + }, + ... +], +'categories': [ + {'id': 1, 'name': 'person'}, + ] +``` + +JSON 标注文件中有三个关键词是必需的: + +- `images`:包含所有图像信息的列表,每个图像都有一个 `file_name`、`height`、`width` 和 `id` 键。 +- `annotations`:包含所有实例标注信息的列表,每个实例都有一个 `segmentation`、`keypoints`、`num_keypoints`、`area`、`iscrowd`、`image_id`、`bbox`、`category_id` 和 `id` 键。 +- `categories`:包含所有类别信息的列表,每个类别都有一个 `id` 和 `name` 键。以人体姿态估计为例,`id` 为 1,`name` 为 `person`。 + +如果您的数据集已经是 COCO 格式的,那么您可以直接使用 `CocoDataset` 类来读取该数据集。 + +## 创建自定义数据集的元信息文件 + +对于一个新的数据集而言,您需要创建一个新的数据集元信息文件。该文件包含了数据集的基本信息,如关键点个数、排列顺序、可视化颜色、骨架连接关系等。元信息文件通常存放在 `config/_base_/datasets/` 目录下,例如: + +``` +config/_base_/datasets/custom.py +``` + +元信息文件中需要包含以下信息: + +- `keypoint_info`:每个关键点的信息: + 1. `name`: 关键点名称,必须是唯一的,例如 `nose`、`left_eye` 等。 + 2. `id`: 关键点 ID,必须是唯一的,从 0 开始。 + 3. `color`: 关键点可视化时的颜色,以 (\[B, G, R\]) 格式组织起来,用于可视化。 + 4. `type`: 关键点类型,可以是 `upper`、`lower` 或 \`\`,用于数据增强。 + 5. `swap`: 关键点交换关系,用于水平翻转数据增强。 +- `skeleton_info`:骨架连接关系,用于可视化。 +- `joint_weights`:每个关键点的权重,用于损失函数计算。 +- `sigma`:标准差,用于计算 OKS 分数,详细信息请参考 [keypoints-eval](https://cocodataset.org/#keypoints-eval)。 + +下面是一个简化版本的元信息文件([完整版](/configs/_base_/datasets/coco.py)): + +```python +dataset_info = dict( + dataset_name='coco', + paper_info=dict( + author='Lin, Tsung-Yi and Maire, Michael and ' + 'Belongie, Serge and Hays, James and ' + 'Perona, Pietro and Ramanan, Deva and ' + r'Doll{\'a}r, Piotr and Zitnick, C Lawrence', + title='Microsoft coco: Common objects in context', + container='European conference on computer vision', + year='2014', + homepage='http://cocodataset.org/', + ), + keypoint_info={ + 0: + dict(name='nose', id=0, color=[51, 153, 255], type='upper', swap=''), + 1: + dict( + name='left_eye', + id=1, + color=[51, 153, 255], + type='upper', + swap='right_eye'), + ... + 16: + dict( + name='right_ankle', + id=16, + color=[255, 128, 0], + type='lower', + swap='left_ankle') + }, + skeleton_info={ + 0: + dict(link=('left_ankle', 'left_knee'), id=0, color=[0, 255, 0]), + ... + 18: + dict( + link=('right_ear', 'right_shoulder'), id=18, color=[51, 153, 255]) + }, + joint_weights=[ + 1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5, + 1.5 + ], + sigmas=[ + 0.026, 0.025, 0.025, 0.035, 0.035, 0.079, 0.079, 0.072, 0.072, 0.062, + 0.062, 0.107, 0.107, 0.087, 0.087, 0.089, 0.089 + ]) +``` + +## 创建自定义数据集类 + +如果标注信息不是用 COCO 格式存储的,那么您需要创建一个新的数据集类。数据集类需要继承自 `BaseDataset` 类,并且需要按照以下步骤实现: + +1. 在 `mmpose/datasets/datasets` 目录下找到该数据集符合的 package,如果没有符合的,则创建一个新的 package。 + +2. 在该 package 下创建一个新的数据集类,在对应的注册器中进行注册: + + ```python + from mmengine.dataset import BaseDataset + from mmpose.registry import DATASETS + + @DATASETS.register_module(name='MyCustomDataset') + class MyCustomDataset(BaseDataset): + ``` + + 如果未注册,你会在运行时遇到 `KeyError: 'XXXXX is not in the dataset registry'`。 + 关于 `mmengine.BaseDataset` 的更多信息,请参考 [这个文档](https://mmengine.readthedocs.io/en/latest/advanced_tutorials/basedataset.html)。 + +3. 确保你在 package 的 `__init__.py` 中导入了该数据集类。 + +4. 确保你在 `mmpose/datasets/__init__.py` 中导入了该 package。 + +## 创建自定义配置文件 + +在配置文件中,你需要修改跟数据集有关的部分,例如: + +```python +... +# 自定义数据集类 +dataset_type = 'MyCustomDataset' # or 'CocoDataset' + +train_dataloader = dict( + batch_size=2, + dataset=dict( + type=dataset_type, + data_root='root/of/your/train/data', + ann_file='path/to/your/train/json', + data_prefix=dict(img='path/to/your/train/img'), + metainfo=dict(from_file='configs/_base_/datasets/custom.py'), + ...), + ) + +val_dataloader = dict( + batch_size=2, + dataset=dict( + type=dataset_type, + data_root='root/of/your/val/data', + ann_file='path/to/your/val/json', + data_prefix=dict(img='path/to/your/val/img'), + metainfo=dict(from_file='configs/_base_/datasets/custom.py'), + ...), + ) + +test_dataloader = dict( + batch_size=2, + dataset=dict( + type=dataset_type, + data_root='root/of/your/test/data', + ann_file='path/to/your/test/json', + data_prefix=dict(img='path/to/your/test/img'), + metainfo=dict(from_file='configs/_base_/datasets/custom.py'), + ...), + ) +... +``` + +请确保所有的路径都是正确的。 + +## 数据集封装 + +目前 [MMEngine](https://github.com/open-mmlab/mmengine) 支持以下数据集封装: + +- [ConcatDataset](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/basedataset.html#concatdataset) +- [RepeatDataset](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/basedataset.html#repeatdataset) + +### CombinedDataset + +MMPose 提供了一个 `CombinedDataset` 类,它可以将多个数据集封装成一个数据集。它的使用方法如下: + +```python +dataset_1 = dict( + type='dataset_type_1', + data_root='root/of/your/dataset1', + data_prefix=dict(img_path='path/to/your/img'), + ann_file='annotations/train.json', + pipeline=[ + # 使用转换器将标注信息统一为需要的格式 + converter_transform_1 + ]) + +dataset_2 = dict( + type='dataset_type_2', + data_root='root/of/your/dataset2', + data_prefix=dict(img_path='path/to/your/img'), + ann_file='annotations/train.json', + pipeline=[ + converter_transform_2 + ]) + +shared_pipeline = [ + LoadImage(), + ParseImage(), +] + +combined_dataset = dict( + type='CombinedDataset', + metainfo=dict(from_file='path/to/your/metainfo'), + datasets=[dataset_1, dataset_2], + pipeline=shared_pipeline, +) +``` + +- **合并数据集的元信息** 决定了标注格式,可以是子数据集的元信息,也可以是自定义的元信息。如果要自定义元信息,可以参考 [创建自定义数据集的元信息文件](#创建自定义数据集的元信息文件)。 +- **KeypointConverter** 用于将不同的标注格式转换成统一的格式。比如将关键点个数不同、关键点排列顺序不同的数据集进行合并。 +- 更详细的说明请前往[混合数据集训练](../user_guides/mixed_datasets.md)。 diff --git a/docs/zh_cn/advanced_guides/model_analysis.md b/docs/zh_cn/advanced_guides/model_analysis.md index 4b0528fd74..234dc5be85 100644 --- a/docs/zh_cn/advanced_guides/model_analysis.md +++ b/docs/zh_cn/advanced_guides/model_analysis.md @@ -1,3 +1,100 @@ # Model Analysis -Coming soon. +## 统计模型参数量与计算量 + +MMPose 提供了 `tools/analysis_tools/get_flops.py` 来统计模型的参数量与计算量。 + +```shell +python tools/analysis_tools/get_flops.py ${CONFIG_FILE} [--shape ${INPUT_SHAPE}] [--cfg-options ${CFG_OPTIONS}] +``` + +参数说明: + +`CONFIG_FILE` : 模型配置文件的路径。 + +`--shape`: 模型的输入张量形状。 + +`--input-constructor`: 如果指定为 `batch`,将会生成一个 `batch tensor` 来计算 FLOPs。 + +`--batch-size`:如果 `--input-constructor` 指定为 `batch`,将会生成一个随机 `tensor`,形状为 `(batch_size, 3, **input_shape)` 来计算 FLOPs。 + +`--cfg-options`: 如果指定,可选的 `cfg` 的键值对将会被合并到配置文件中。 + +示例: + +```shell +python tools/analysis_tools/get_flops.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192.py +``` + +结果如下: + +```text +============================== +Input shape: (1, 3, 256, 192) +Flops: 7.7 GFLOPs +Params: 28.54 M +============================== +``` + +```{note} +目前该工具仍处于实验阶段,我们不能保证统计结果绝对正确,一些算子(比如 GN 或自定义算子)没有被统计到 FLOPs 中。 +``` + +## 分析训练日志 + +MMPose 提供了 `tools/analysis_tools/analyze_logs.py` 来对训练日志进行简单的分析,包括: + +- 将日志绘制成损失和精度曲线图 +- 统计训练速度 + +### 绘制损失和精度曲线图 + +该功能依赖于 `seaborn`,请先运行 `pip install seaborn` 安装依赖包。 + +![log_curve](https://user-images.githubusercontent.com/87690686/188538215-5d985aaa-59f8-44cf-b6f9-10890d599e9c.png) + +```shell +python tools/analysis_tools/analyze_logs.py plot_curve ${JSON_LOGS} [--keys ${KEYS}] [--title ${TITLE}] [--legend ${LEGEND}] [--backend ${BACKEND}] [--style ${STYLE}] [--out ${OUT_FILE}] +``` + +示例: + +- 绘制损失曲线 + + ```shell + python tools/analysis_tools/analyze_logs.py plot_curve log.json --keys loss_kpt --legend loss_kpt + ``` + +- 绘制精度曲线并导出为 PDF 文件 + + ```shell + python tools/analysis_tools/analyze_logs.py plot_curve log.json --keys acc_pose --out results.pdf + ``` + +- 将多个日志文件绘制在同一张图上 + + ```shell + python tools/analysis_tools/analyze_logs.py plot_curve log1.json log2.json --keys loss_kpt --legend run1 run2 --title loss_kpt --out loss_kpt.png + ``` + +### 统计训练速度 + +```shell +python tools/analysis_tools/analyze_logs.py cal_train_time ${JSON_LOGS} [--include-outliers] +``` + +示例: + +```shell +python tools/analysis_tools/analyze_logs.py cal_train_time log.json +``` + +结果如下: + +```text +-----Analyze train time of hrnet_w32_256x192.json----- +slowest epoch 56, average time is 0.6924 +fastest epoch 1, average time is 0.6502 +time std over epochs is 0.0085 +average iter time: 0.6688 s/iter +``` diff --git a/docs/zh_cn/api.rst b/docs/zh_cn/api.rst index a75e4a451d..48819a2531 100644 --- a/docs/zh_cn/api.rst +++ b/docs/zh_cn/api.rst @@ -132,5 +132,3 @@ hooks ^^^^^^^^^^^ .. automodule:: mmpose.engine.hooks :members: - -.. include:: webcam_api.rst diff --git a/docs/zh_cn/dataset_zoo/2d_animal_keypoint.md b/docs/zh_cn/dataset_zoo/2d_animal_keypoint.md index 2429602537..28b0b726b4 100644 --- a/docs/zh_cn/dataset_zoo/2d_animal_keypoint.md +++ b/docs/zh_cn/dataset_zoo/2d_animal_keypoint.md @@ -13,6 +13,7 @@ MMPose supported datasets: - [Desert Locust](#desert-locust) \[ [Homepage](https://github.com/jgraving/DeepPoseKit-Data) \] - [Grévy’s Zebra](#grvys-zebra) \[ [Homepage](https://github.com/jgraving/DeepPoseKit-Data) \] - [ATRW](#atrw) \[ [Homepage](https://cvwc2019.github.io/challenge.html) \] +- [Animal Kingdom](#Animal-Kindom) \[ [Homepage](https://openaccess.thecvf.com/content/CVPR2022/html/Ng_Animal_Kingdom_A_Large_and_Diverse_Dataset_for_Animal_Behavior_CVPR_2022_paper.html) \] ## Animal-Pose @@ -478,3 +479,67 @@ mmpose │ │ │-- ... ``` + +## Animal Kingdom + +
+Animal Kingdom (CVPR'2022) +
+
+ +
+ +```bibtex +@inproceedings{Ng_2022_CVPR, + author = {Ng, Xun Long and Ong, Kian Eng and Zheng, Qichen and Ni, Yun and Yeo, Si Yong and Liu, Jun}, + title = {Animal Kingdom: A Large and Diverse Dataset for Animal Behavior Understanding}, + booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)}, + month = {June}, + year = {2022}, + pages = {19023-19034} + } +``` + +For [Animal Kingdom](https://github.com/sutdcv/Animal-Kingdom) dataset, images can be downloaded from [here](https://forms.office.com/pages/responsepage.aspx?id=drd2NJDpck-5UGJImDFiPVRYpnTEMixKqPJ1FxwK6VZUQkNTSkRISTNORUI2TDBWMUpZTlQ5WUlaSyQlQCN0PWcu). +Please Extract dataset under {MMPose}/data, and make them look like this: + +```text +mmpose +├── mmpose +├── docs +├── tests +├── tools +├── configs +`── data + │── ak + |--annotations + │ │-- ak_P1 + │ │ │-- train.json + │ │ │-- test.json + │ │-- ak_P2 + │ │ │-- train.json + │ │ │-- test.json + │ │-- ak_P3_amphibian + │ │ │-- train.json + │ │ │-- test.json + │ │-- ak_P3_bird + │ │ │-- train.json + │ │ │-- test.json + │ │-- ak_P3_fish + │ │ │-- train.json + │ │ │-- test.json + │ │-- ak_P3_mammal + │ │ │-- train.json + │ │ │-- test.json + │ │-- ak_P3_reptile + │ │-- train.json + │ │-- test.json + │-- images + │ │-- AAACXZTV + │ │ │--AAACXZTV_f000059.jpg + │ │ │--... + │ │-- AAAUILHH + │ │ │--AAAUILHH_f000098.jpg + │ │ │--... + │ │-- ... +``` diff --git a/docs/zh_cn/dataset_zoo/2d_body_keypoint.md b/docs/zh_cn/dataset_zoo/2d_body_keypoint.md index c5bf70a3f8..4448ebe8f4 100644 --- a/docs/zh_cn/dataset_zoo/2d_body_keypoint.md +++ b/docs/zh_cn/dataset_zoo/2d_body_keypoint.md @@ -13,6 +13,7 @@ MMPose supported datasets: - [CrowdPose](#crowdpose) \[ [Homepage](https://github.com/Jeff-sjtu/CrowdPose) \] - [OCHuman](#ochuman) \[ [Homepage](https://github.com/liruilong940607/OCHumanApi) \] - [MHP](#mhp) \[ [Homepage](https://lv-mhp.github.io/dataset) \] + - [Human-Art](#humanart) \[ [Homepage](https://idea-research.github.io/HumanArt/) \] - Videos - [PoseTrack18](#posetrack18) \[ [Homepage](https://posetrack.net/users/download.php) \] - [sub-JHMDB](#sub-jhmdb-dataset) \[ [Homepage](http://jhmdb.is.tue.mpg.de/dataset) \] @@ -386,6 +387,57 @@ mmpose │ │ │-- ...~~~~ ``` +## Human-Art dataset + + + +
+Human-Art (CVPR'2023) + +```bibtex +@inproceedings{ju2023humanart, + title={Human-Art: A Versatile Human-Centric Dataset Bridging Natural and Artificial Scenes}, + author={Ju, Xuan and Zeng, Ailing and Jianan, Wang and Qiang, Xu and Lei, Zhang}, + booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), + year={2023}} +``` + +
+ +
+ +
+ +For [Human-Art](https://idea-research.github.io/HumanArt/) data, please download the images and annotation files from [its website](https://idea-research.github.io/HumanArt/). You need to fill in the [data form](https://docs.google.com/forms/d/e/1FAIpQLScroT_jvw6B9U2Qca1_cl5Kmmu1ceKtlh6DJNmWLte8xNEhEw/viewform) to get access to the data. +Move them under $MMPOSE/data, and make them look like this: + +```text +mmpose +├── mmpose +├── docs +├── tests +├── tools +├── configs +|── data + │── HumanArt + │-- images + │ │-- 2D_virtual_human + │ │ |-- cartoon + │ │ | |-- 000000000000.jpg + │ │ | |-- ... + │ │ |-- digital_art + │ │ |-- ... + │ |-- 3D_virtual_human + │ |-- real_human + |-- annotations + │ │-- validation_humanart.json + │ │-- training_humanart_coco.json + |-- person_detection_results + │ │-- HumanArt_validation_detections_AP_H_56_person.json +``` + +You can choose whether to download other annotation files in Human-Art. If you want to use additional annotation files (e.g. validation set of cartoon), you need to edit the corresponding code in config file. + ## PoseTrack18 diff --git a/docs/zh_cn/dataset_zoo/2d_face_keypoint.md b/docs/zh_cn/dataset_zoo/2d_face_keypoint.md index 17eb823954..62f66bd82b 100644 --- a/docs/zh_cn/dataset_zoo/2d_face_keypoint.md +++ b/docs/zh_cn/dataset_zoo/2d_face_keypoint.md @@ -10,6 +10,7 @@ MMPose supported datasets: - [AFLW](#aflw-dataset) \[ [Homepage](https://www.tugraz.at/institute/icg/research/team-bischof/lrs/downloads/aflw/) \] - [COFW](#cofw-dataset) \[ [Homepage](http://www.vision.caltech.edu/xpburgos/ICCV13/) \] - [COCO-WholeBody-Face](#coco-wholebody-face) \[ [Homepage](https://github.com/jin-s13/COCO-WholeBody/) \] +- [LaPa](#lapa-dataset) \[ [Homepage](https://github.com/JDAI-CV/lapa-dataset) \] ## 300W Dataset @@ -325,3 +326,59 @@ mmpose Please also install the latest version of [Extended COCO API](https://github.com/jin-s13/xtcocoapi) to support COCO-WholeBody evaluation: `pip install xtcocotools` + +## LaPa + + + +
+LaPa (AAAI'2020) + +```bibtex +@inproceedings{liu2020new, + title={A New Dataset and Boundary-Attention Semantic Segmentation for Face Parsing.}, + author={Liu, Yinglu and Shi, Hailin and Shen, Hao and Si, Yue and Wang, Xiaobo and Mei, Tao}, + booktitle={AAAI}, + pages={11637--11644}, + year={2020} +} +``` + +
+ +
+ +
+ +For [LaPa](https://github.com/JDAI-CV/lapa-dataset) dataset, images can be downloaded from [their github page](https://github.com/JDAI-CV/lapa-dataset). + +Download and extract them under $MMPOSE/data, and use our `tools/dataset_converters/lapa2coco.py` to make them look like this: + +```text +mmpose +├── mmpose +├── docs +├── tests +├── tools +├── configs +`── data + │── LaPa + │-- annotations + │ │-- lapa_train.json + │ |-- lapa_val.json + │ |-- lapa_test.json + | |-- lapa_trainval.json + │-- train + │ │-- images + │ │-- labels + │ │-- landmarks + │-- val + │ │-- images + │ │-- labels + │ │-- landmarks + `-- test + │ │-- images + │ │-- labels + │ │-- landmarks + +``` diff --git a/docs/zh_cn/dataset_zoo/2d_fashion_landmark.md b/docs/zh_cn/dataset_zoo/2d_fashion_landmark.md index 42f213e40a..25b7fd7c64 100644 --- a/docs/zh_cn/dataset_zoo/2d_fashion_landmark.md +++ b/docs/zh_cn/dataset_zoo/2d_fashion_landmark.md @@ -1,80 +1,3 @@ -# 2D Fashion Landmark Dataset +# 2D服装关键点数据集 -It is recommended to symlink the dataset root to `$MMPOSE/data`. -If your folder structure is different, you may need to change the corresponding paths in config files. - -MMPose supported datasets: - -- [DeepFashion](#deepfashion) \[ [Homepage](http://mmlab.ie.cuhk.edu.hk/projects/DeepFashion/LandmarkDetection.html) \] - -## DeepFashion (Fashion Landmark Detection, FLD) - - - -
-DeepFashion (CVPR'2016) - -```bibtex -@inproceedings{liuLQWTcvpr16DeepFashion, - author = {Liu, Ziwei and Luo, Ping and Qiu, Shi and Wang, Xiaogang and Tang, Xiaoou}, - title = {DeepFashion: Powering Robust Clothes Recognition and Retrieval with Rich Annotations}, - booktitle = {Proceedings of IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, - month = {June}, - year = {2016} -} -``` - -
- - - -
-DeepFashion (ECCV'2016) - -```bibtex -@inproceedings{liuYLWTeccv16FashionLandmark, - author = {Liu, Ziwei and Yan, Sijie and Luo, Ping and Wang, Xiaogang and Tang, Xiaoou}, - title = {Fashion Landmark Detection in the Wild}, - booktitle = {European Conference on Computer Vision (ECCV)}, - month = {October}, - year = {2016} - } -``` - -
- -
- -
- -For [DeepFashion](http://mmlab.ie.cuhk.edu.hk/projects/DeepFashion/LandmarkDetection.html) dataset, images can be downloaded from [download](http://mmlab.ie.cuhk.edu.hk/projects/DeepFashion/LandmarkDetection.html). -Please download the annotation files from [fld_annotations](https://download.openmmlab.com/mmpose/datasets/fld_annotations.tar). -Extract them under {MMPose}/data, and make them look like this: - -```text -mmpose -├── mmpose -├── docs -├── tests -├── tools -├── configs -`── data - │── fld - │-- annotations - │ │-- fld_upper_train.json - │ |-- fld_upper_val.json - │ |-- fld_upper_test.json - │ │-- fld_lower_train.json - │ |-- fld_lower_val.json - │ |-- fld_lower_test.json - │ │-- fld_full_train.json - │ |-- fld_full_val.json - │ |-- fld_full_test.json - │-- img - │ │-- img_00000001.jpg - │ │-- img_00000002.jpg - │ │-- img_00000003.jpg - │ │-- img_00000004.jpg - │ │-- img_00000005.jpg - │ │-- ... -``` +内容建设中…… diff --git a/docs/zh_cn/dataset_zoo/dataset_tools.md b/docs/zh_cn/dataset_zoo/dataset_tools.md index ab30fc5604..a2e6d01d97 100644 --- a/docs/zh_cn/dataset_zoo/dataset_tools.md +++ b/docs/zh_cn/dataset_zoo/dataset_tools.md @@ -376,3 +376,38 @@ python tools/dataset_converters/mat2json ${PRED_MAT_FILE} ${GT_JSON_FILE} ${OUTP ```shell python tools/dataset/mat2json work_dirs/res50_mpii_256x256/pred.mat data/mpii/annotations/mpii_val.json pred.json ``` + +## Label Studio 数据集 + +
+Label Studio + +```bibtex +@misc{Label Studio, + title={{Label Studio}: Data labeling software}, + url={https://github.com/heartexlabs/label-studio}, + note={Open source software available from https://github.com/heartexlabs/label-studio}, + author={ + Maxim Tkachenko and + Mikhail Malyuk and + Andrey Holmanyuk and + Nikolai Liubimov}, + year={2020-2022}, +} +``` + +
+ +对于 [Label Studio](https://github.com/heartexlabs/label-studio/) 用户,请依照 [Label Studio 转换工具文档](./label_studio.md) 中的方法进行标注,并将结果导出为 Label Studio 标准的 `.json` 文件,将 `Labeling Interface` 中的 `Code` 保存为 `.xml` 文件。 + +我们提供了一个脚本来将 Label Studio 标准的 `.json` 格式标注文件转换为 COCO 标准的 `.json` 格式。这可以通过运行以下命令完成: + +```shell +python tools/dataset_converters/labelstudio2coco.py ${LS_JSON_FILE} ${LS_XML_FILE} ${OUTPUT_COCO_JSON_FILE} +``` + +例如: + +```shell +python tools/dataset_converters/labelstudio2coco.py config.xml project-1-at-2023-05-13-09-22-91b53efa.json output/result.json +``` diff --git a/docs/zh_cn/dataset_zoo/label_studio.md b/docs/zh_cn/dataset_zoo/label_studio.md new file mode 100644 index 0000000000..94cbd6418c --- /dev/null +++ b/docs/zh_cn/dataset_zoo/label_studio.md @@ -0,0 +1,76 @@ +# Label Studio 标注工具转COCO脚本 + +[Label Studio](https://labelstud.io/) 是一款广受欢迎的深度学习标注工具,可以对多种任务进行标注,然而对于关键点标注,Label Studio 无法直接导出成 MMPose 所需要的 COCO 格式。本文将介绍如何使用Label Studio 标注关键点数据,并利用 [labelstudio2coco.py](../../../tools/dataset_converters/labelstudio2coco.py) 工具将其转换为训练所需的格式。 + +## Label Studio 标注要求 + +根据 COCO 格式的要求,每个标注的实例中都需要包含关键点、分割和 bbox 的信息,然而 Label Studio 在标注时会将这些信息分散在不同的实例中,因此需要按一定规则进行标注,才能正常使用后续的脚本。 + +1. 标签接口设置 + +对于一个新建的 Label Studio 项目,首先要设置它的标签接口。这里需要有三种类型的标注:`KeyPointLabels`、`PolygonLabels`、`RectangleLabels`,分别对应 COCO 格式中的`keypoints`、`segmentation`、`bbox`。以下是一个标签接口的示例,可以在项目的`Settings`中找到`Labeling Interface`,点击`Code`,粘贴使用该示例。 + +```xml + + + + + + + + + +``` + +2. 标注顺序 + +由于需要将多个标注实例中的不同类型标注组合到一个实例中,因此采取了按特定顺序标注的方式,以此来判断各标注是否位于同一个实例。标注时须按照 **KeyPointLabels -> PolygonLabels/RectangleLabels** 的顺序标注,其中 KeyPointLabels 的顺序和数量要与 MMPose 配置文件中的`dataset_info`的关键点顺序和数量一致, PolygonLabels 和 RectangleLabels 的标注顺序可以互换,且可以只标注其中一个,只要保证一个实例的标注中,以关键点开始,以非关键点结束即可。下图为标注的示例: + +*注:bbox 和 area 会根据靠后的 PolygonLabels/RectangleLabels 来计算,如若先标 PolygonLabels,那么bbox会是靠后的 RectangleLabels 的范围,面积为矩形的面积,反之则是多边形外接矩形和多边形的面积* + +![image](https://github.com/open-mmlab/mmpose/assets/15847281/b2d004d0-8361-42c5-9180-cfbac0373a94) + +3. 导出标注 + +上述标注完成后,需要将标注进行导出。选择项目界面的`Export`按钮,选择`JSON`格式,再点击`Export`即可下载包含标签的 JSON 格式文件。 + +*注:上述文件中仅仅包含标签,不包含原始图片,因此需要额外提供标注对应的图片。由于 Label Studio 会对过长的文件名进行截断,因此不建议直接使用上传的文件,而是使用`Export`功能中的导出 COCO 格式工具,使用压缩包内的图片文件夹。* + +![image](https://github.com/open-mmlab/mmpose/assets/15847281/9f54ca3d-8cdd-4d7f-8ed6-494badcfeaf2) + +## 转换工具脚本的使用 + +转换工具脚本位于`tools/dataset_converters/labelstudio2coco.py`,使用方式如下: + +```bash +python tools/dataset_converters/labelstudio2coco.py config.xml project-1-at-2023-05-13-09-22-91b53efa.json output/result.json +``` + +其中`config.xml`的内容为标签接口设置中提到的`Labeling Interface`中的`Code`,`project-1-at-2023-05-13-09-22-91b53efa.json`即为导出标注时导出的 Label Studio 格式的 JSON 文件,`output/result.json`为转换后得到的 COCO 格式的 JSON 文件路径,若路径不存在,该脚本会自动创建路径。 + +随后,将图片的文件夹放置在输出目录下,即可完成 COCO 数据集的转换。目录结构示例如下: + +```bash +. +├── images +│   ├── 38b480f2.jpg +│   └── aeb26f04.jpg +└── result.json + +``` + +若想在 MMPose 中使用该数据集,可以进行类似如下的修改: + +```python +dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='result.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, +) +``` diff --git a/docs/zh_cn/faq.md b/docs/zh_cn/faq.md index 15e3fbb98d..b1e6998396 100644 --- a/docs/zh_cn/faq.md +++ b/docs/zh_cn/faq.md @@ -8,12 +8,19 @@ If the contents here do not cover your issue, please create an issue using the [ Compatibility issue between MMCV and MMPose; "AssertionError: MMCV==xxx is used but incompatible. Please install mmcv>=xxx, \<=xxx." -Compatible MMPose and MMCV versions are shown as below. Please choose the correct version of MMCV to avoid installation issues. +Here are the version correspondences between `mmdet`, `mmcv` and `mmpose`: + +- mmdet 2.x \<=> mmpose 0.x \<=> mmcv 1.x +- mmdet 3.x \<=> mmpose 1.x \<=> mmcv 2.x + +Detailed compatible MMPose and MMCV versions are shown as below. Please choose the correct version of MMCV to avoid installation issues. ### MMPose 1.x | MMPose version | MMCV/MMEngine version | | :------------: | :-----------------------------: | +| 1.1.0 | mmcv>=2.0.1, mmengine>=0.8.0 | +| 1.0.0 | mmcv>=2.0.0, mmengine>=0.7.0 | | 1.0.0rc1 | mmcv>=2.0.0rc4, mmengine>=0.6.0 | | 1.0.0rc0 | mmcv>=2.0.0rc0, mmengine>=0.0.1 | | 1.0.0b0 | mmcv>=2.0.0rc0, mmengine>=0.0.1 | @@ -22,7 +29,7 @@ Compatible MMPose and MMCV versions are shown as below. Please choose the correc | MMPose version | MMCV version | | :------------: | :-----------------------: | -| master | mmcv-full>=1.3.8, \<1.8.0 | +| 0.x | mmcv-full>=1.3.8, \<1.8.0 | | 0.29.0 | mmcv-full>=1.3.8, \<1.7.0 | | 0.28.1 | mmcv-full>=1.3.8, \<1.7.0 | | 0.28.0 | mmcv-full>=1.3.8, \<1.6.0 | diff --git a/docs/zh_cn/how_to.md b/docs/zh_cn/how_to.md deleted file mode 100644 index a2824f977b..0000000000 --- a/docs/zh_cn/how_to.md +++ /dev/null @@ -1,108 +0,0 @@ -# How to - -## 分析训练日志 - -MMPose 提供了 `tools/analysis_tools/analyze_logs.py` 来对训练日志进行简单的分析,包括: - -- 将日志绘制成损失和精度曲线图 -- 统计训练速度 - -### 绘制损失和精度曲线图 - -该功能依赖于 `seaborn`,请先运行 `pip install seaborn` 安装依赖包。 - -![log_curve](https://user-images.githubusercontent.com/87690686/188538215-5d985aaa-59f8-44cf-b6f9-10890d599e9c.png) - -```shell -python tools/analysis_tools/analyze_logs.py plot_curve ${JSON_LOGS} [--keys ${KEYS}] [--title ${TITLE}] [--legend ${LEGEND}] [--backend ${BACKEND}] [--style ${STYLE}] [--out ${OUT_FILE}] -``` - -示例: - -- 绘制损失曲线 - - ```shell - python tools/analysis_tools/analyze_logs.py plot_curve log.json --keys loss_kpt --legend loss_kpt - ``` - -- 绘制精度曲线并导出为 PDF 文件 - - ```shell - python tools/analysis_tools/analyze_logs.py plot_curve log.json --keys acc_pose --out results.pdf - ``` - -- 将多个日志文件绘制在同一张图上 - - ```shell - python tools/analysis_tools/analyze_logs.py plot_curve log1.json log2.json --keys loss_kpt --legend run1 run2 --title loss_kpt --out loss_kpt.png - ``` - -### 统计训练速度 - -```shell -python tools/analysis_tools/analyze_logs.py cal_train_time ${JSON_LOGS} [--include-outliers] -``` - -示例: - -```shell -python tools/analysis_tools/analyze_logs.py cal_train_time log.json -``` - -结果如下: - -```text ------Analyze train time of hrnet_w32_256x192.json----- -slowest epoch 56, average time is 0.6924 -fastest epoch 1, average time is 0.6502 -time std over epochs is 0.0085 -average iter time: 0.6688 s/iter -``` - -## 统计模型参数量与计算量 - -MMPose 提供了 `tools/analysis_tools/get_flops.py` 来统计模型的参数量与计算量。 - -```shell -python tools/analysis_tools/get_flops.py ${CONFIG_FILE} [--shape ${INPUT_SHAPE}] [--cfg-options ${CFG_OPTIONS}] -``` - -参数说明: - -`CONFIG_FILE` : 模型配置文件的路径。 - -`--shape`: 模型的输入张量形状。 - -`--input-constructor`: 如果指定为 `batch`,将会生成一个 `batch tensor` 来计算 FLOPs。 - -`--batch-size`:如果 `--input-constructor` 指定为 `batch`,将会生成一个随机 `tensor`,形状为 `(batch_size, 3, **input_shape)` 来计算 FLOPs。 - -`--cfg-options`: 如果指定,可选的 `cfg` 的键值对将会被合并到配置文件中。 - -示例: - -```shell -python tools/analysis_tools/get_flops.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192.py -``` - -结果如下: - -```text -============================== -Input shape: (1, 3, 256, 192) -Flops: 7.7 GFLOPs -Params: 28.54 M -============================== -``` - -```{note} -目前该工具仍处于实验阶段,我们不能保证统计结果绝对正确,一些算子(比如 GN 或自定义算子)没有被统计到 FLOPs 中。 -``` - -## 打印全部配置信息 - -官方提供的配置文件,有时候继承了多个配置文件,这样做可以方便管理,减少冗余代码。但有时候我们希望知道配置文件中没有写明的默认参数值是什么,MMPose 提供了 `tools/analysis_tools/print_config.py` 来逐字逐句打印全部的配置信息。 - -```shell -python tools/analysis_tools/print_config.py ${CONFIG} [-h] [--options ${OPTIONS [OPTIONS...]}] -``` diff --git a/docs/zh_cn/index.rst b/docs/zh_cn/index.rst index e38ed72df4..2431d82e4d 100644 --- a/docs/zh_cn/index.rst +++ b/docs/zh_cn/index.rst @@ -51,6 +51,7 @@ You can change the documentation language at the lower-left corner of the page. model_zoo.txt model_zoo/body_2d_keypoint.md + model_zoo/body_3d_keypoint.md model_zoo/face_2d_keypoint.md model_zoo/hand_2d_keypoint.md model_zoo/wholebody_2d_keypoint.md diff --git a/docs/zh_cn/installation.md b/docs/zh_cn/installation.md index 1ec42fe78a..ef515c8030 100644 --- a/docs/zh_cn/installation.md +++ b/docs/zh_cn/installation.md @@ -21,7 +21,7 @@ 在本节中,我们将演示如何准备 PyTorch 相关的依赖环境。 -MMPose 适用于 Linux、Windows 和 macOS。它需要 Python 3.7+、CUDA 9.2+ 和 PyTorch 1.6+。 +MMPose 适用于 Linux、Windows 和 macOS。它需要 Python 3.7+、CUDA 9.2+ 和 PyTorch 1.8+。 如果您对配置 PyTorch 环境已经很熟悉,并且已经完成了配置,可以直接进入下一节:[安装](#安装-mmpose)。否则,请依照以下步骤完成配置。 @@ -57,13 +57,13 @@ conda install pytorch torchvision cpuonly -c pytorch ```shell pip install -U openmim mim install mmengine -mim install "mmcv>=2.0.0" +mim install "mmcv>=2.0.1" ``` 请注意,MMPose 中的一些推理示例脚本需要使用 [MMDetection](https://github.com/open-mmlab/mmdetection) (mmdet) 检测人体。如果您想运行这些示例脚本,可以通过运行以下命令安装 mmdet: ```shell -mim install "mmdet>=3.0.0" +mim install "mmdet>=3.1.0" ``` ## 最佳实践 @@ -88,7 +88,7 @@ pip install -v -e . 如果只是希望调用 MMPose 的接口,或者在自己的项目中导入 MMPose 中的模块。直接使用 mim 安装即可。 ```shell -mim install "mmpose>=1.0.0" +mim install "mmpose>=1.1.0" ``` ## 验证安装 @@ -180,7 +180,7 @@ MMCV 包含 C++ 和 CUDA 扩展,因此其对 PyTorch 的依赖比较复杂。M 举个例子,如下命令将会安装基于 PyTorch 1.10.x 和 CUDA 11.3 编译的 mmcv。 ```shell -pip install 'mmcv>=2.0.0' -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.10/index.html +pip install 'mmcv>=2.0.1' -f https://download.openmmlab.com/mmcv/dist/cu113/torch1.10/index.html ``` ### 在 CPU 环境中安装 @@ -198,7 +198,7 @@ MMPose 可以仅在 CPU 环境中安装,在 CPU 模式下,您可以完成训 ```shell !pip3 install openmim !mim install mmengine -!mim install "mmcv>=2.0.0" +!mim install "mmcv>=2.0.1" ``` **第 2 步** 从源码安装 mmpose @@ -214,7 +214,7 @@ MMPose 可以仅在 CPU 环境中安装,在 CPU 模式下,您可以完成训 ```python import mmpose print(mmpose.__version__) -# 预期输出: 1.0.0 +# 预期输出: 1.1.0 ``` ```{note} @@ -227,7 +227,7 @@ MMPose 提供 [Dockerfile](https://github.com/open-mmlab/mmpose/blob/master/dock 用于构建镜像。请确保您的 [Docker 版本](https://docs.docker.com/engine/install/) >=19.03。 ```shell -# 构建默认的 PyTorch 1.6.0,CUDA 10.1 版本镜像 +# 构建默认的 PyTorch 1.8.0,CUDA 10.1 版本镜像 # 如果您希望使用其他版本,请修改 Dockerfile docker build -t mmpose docker/ ``` diff --git a/docs/zh_cn/merge_docs.sh b/docs/zh_cn/merge_docs.sh index 3b9f8f0e1b..258141d5f8 100644 --- a/docs/zh_cn/merge_docs.sh +++ b/docs/zh_cn/merge_docs.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash # Copyright (c) OpenMMLab. All rights reserved. -sed -i '$a\\n' ../../demo/docs/*_demo.md -cat ../../demo/docs/*_demo.md | sed "s/^## 2D\(.*\)Demo/##\1Estimation/" | sed "s/md###t/html#t/g" | sed '1i\# Demos\n' | sed 's=](/docs/en/=](/=g' | sed 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' >demos.md +sed -i '$a\\n' ../../demo/docs/zh_cn/*_demo.md +cat ../../demo/docs/zh_cn/*_demo.md | sed "s/^## 2D\(.*\)Demo/##\1Estimation/" | sed "s/md###t/html#t/g" | sed '1i\# Demos\n' | sed 's=](/docs/en/=](/=g' | sed 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' >demos.md # remove /docs/ for link used in doc site sed -i 's=](/docs/zh_cn/=](=g' overview.md @@ -18,14 +18,14 @@ sed -i 's=](/docs/zh_cn/=](=g' ./notes/*.md sed -i 's=](/docs/zh_cn/=](=g' ./projects/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' overview.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' installation.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' quick_run.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' migration.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./advanced_guides/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./model_zoo/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./model_zoo_papers/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./user_guides/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./dataset_zoo/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./notes/*.md -sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/main/=g' ./projects/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' overview.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' installation.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' quick_run.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' migration.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./advanced_guides/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./model_zoo/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./model_zoo_papers/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./user_guides/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./dataset_zoo/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./notes/*.md +sed -i 's=](/=](https://github.com/open-mmlab/mmpose/tree/dev-1.x/=g' ./projects/*.md diff --git a/docs/zh_cn/notes/changelog.md b/docs/zh_cn/notes/changelog.md index 942d3d515b..68beeeb069 100644 --- a/docs/zh_cn/notes/changelog.md +++ b/docs/zh_cn/notes/changelog.md @@ -1,5 +1,92 @@ # Changelog +## **v1.0.0rc1 (14/10/2022)** + +**Highlights** + +- Release RTMPose, a high-performance real-time pose estimation algorithm with cross-platform deployment and inference support. See details at the [project page](/projects/rtmpose/) +- Support several new algorithms: ViTPose (arXiv'2022), CID (CVPR'2022), DEKR (CVPR'2021) +- Add Inferencer, a convenient inference interface that perform pose estimation and visualization on images, videos and webcam streams with only one line of code +- Introduce *Project*, a new form for rapid and easy implementation of new algorithms and features in MMPose, which is more handy for community contributors + +**New Features** + +- Support RTMPose ([#1971](https://github.com/open-mmlab/mmpose/pull/1971), [#2024](https://github.com/open-mmlab/mmpose/pull/2024), [#2028](https://github.com/open-mmlab/mmpose/pull/2028), [#2030](https://github.com/open-mmlab/mmpose/pull/2030), [#2040](https://github.com/open-mmlab/mmpose/pull/2040), [#2057](https://github.com/open-mmlab/mmpose/pull/2057)) +- Support Inferencer ([#1969](https://github.com/open-mmlab/mmpose/pull/1969)) +- Support ViTPose ([#1876](https://github.com/open-mmlab/mmpose/pull/1876), [#2056](https://github.com/open-mmlab/mmpose/pull/2056), [#2058](https://github.com/open-mmlab/mmpose/pull/2058), [#2065](https://github.com/open-mmlab/mmpose/pull/2065)) +- Support CID ([#1907](https://github.com/open-mmlab/mmpose/pull/1907)) +- Support DEKR ([#1834](https://github.com/open-mmlab/mmpose/pull/1834), [#1901](https://github.com/open-mmlab/mmpose/pull/1901)) +- Support training with multiple datasets ([#1767](https://github.com/open-mmlab/mmpose/pull/1767), [#1930](https://github.com/open-mmlab/mmpose/pull/1930), [#1938](https://github.com/open-mmlab/mmpose/pull/1938), [#2025](https://github.com/open-mmlab/mmpose/pull/2025)) +- Add *project* to allow rapid and easy implementation of new models and features ([#1914](https://github.com/open-mmlab/mmpose/pull/1914)) + +**Improvements** + +- Improve documentation quality ([#1846](https://github.com/open-mmlab/mmpose/pull/1846), [#1858](https://github.com/open-mmlab/mmpose/pull/1858), [#1872](https://github.com/open-mmlab/mmpose/pull/1872), [#1899](https://github.com/open-mmlab/mmpose/pull/1899), [#1925](https://github.com/open-mmlab/mmpose/pull/1925), [#1945](https://github.com/open-mmlab/mmpose/pull/1945), [#1952](https://github.com/open-mmlab/mmpose/pull/1952), [#1990](https://github.com/open-mmlab/mmpose/pull/1990), [#2023](https://github.com/open-mmlab/mmpose/pull/2023), [#2042](https://github.com/open-mmlab/mmpose/pull/2042)) +- Support visualizing keypoint indices ([#2051](https://github.com/open-mmlab/mmpose/pull/2051)) +- Support OpenPose style visualization ([#2055](https://github.com/open-mmlab/mmpose/pull/2055)) +- Accelerate image transpose in data pipelines with tensor operation ([#1976](https://github.com/open-mmlab/mmpose/pull/1976)) +- Support auto-import modules from registry ([#1961](https://github.com/open-mmlab/mmpose/pull/1961)) +- Support keypoint partition metric ([#1944](https://github.com/open-mmlab/mmpose/pull/1944)) +- Support SimCC 1D-heatmap visualization ([#1912](https://github.com/open-mmlab/mmpose/pull/1912)) +- Support saving predictions and data metainfo in demos ([#1814](https://github.com/open-mmlab/mmpose/pull/1814), [#1879](https://github.com/open-mmlab/mmpose/pull/1879)) +- Support SimCC with DARK ([#1870](https://github.com/open-mmlab/mmpose/pull/1870)) +- Remove Gaussian blur for offset maps in UDP-regress ([#1815](https://github.com/open-mmlab/mmpose/pull/1815)) +- Refactor encoding interface of Codec for better extendibility and easier configuration ([#1781](https://github.com/open-mmlab/mmpose/pull/1781)) +- Support evaluating CocoMetric without annotation file ([#1722](https://github.com/open-mmlab/mmpose/pull/1722)) +- Improve unit tests ([#1765](https://github.com/open-mmlab/mmpose/pull/1765)) + +**Bug Fixes** + +- Fix repeated warnings from different ranks ([#2053](https://github.com/open-mmlab/mmpose/pull/2053)) +- Avoid frequent scope switching when using mmdet inference api ([#2039](https://github.com/open-mmlab/mmpose/pull/2039)) +- Remove EMA parameters and message hub data when publishing model checkpoints ([#2036](https://github.com/open-mmlab/mmpose/pull/2036)) +- Fix metainfo copying in dataset class ([#2017](https://github.com/open-mmlab/mmpose/pull/2017)) +- Fix top-down demo bug when there is no object detected ([#2007](https://github.com/open-mmlab/mmpose/pull/2007)) +- Fix config errors ([#1882](https://github.com/open-mmlab/mmpose/pull/1882), [#1906](https://github.com/open-mmlab/mmpose/pull/1906), [#1995](https://github.com/open-mmlab/mmpose/pull/1995)) +- Fix image demo failure when GUI is unavailable ([#1968](https://github.com/open-mmlab/mmpose/pull/1968)) +- Fix bug in AdaptiveWingLoss ([#1953](https://github.com/open-mmlab/mmpose/pull/1953)) +- Fix incorrect importing of RepeatDataset which is deprecated ([#1943](https://github.com/open-mmlab/mmpose/pull/1943)) +- Fix bug in bottom-up datasets that ignores images without instances ([#1752](https://github.com/open-mmlab/mmpose/pull/1752), [#1936](https://github.com/open-mmlab/mmpose/pull/1936)) +- Fix upstream dependency issues ([#1867](https://github.com/open-mmlab/mmpose/pull/1867), [#1921](https://github.com/open-mmlab/mmpose/pull/1921)) +- Fix evaluation issues and update results ([#1763](https://github.com/open-mmlab/mmpose/pull/1763), [#1773](https://github.com/open-mmlab/mmpose/pull/1773), [#1780](https://github.com/open-mmlab/mmpose/pull/1780), [#1850](https://github.com/open-mmlab/mmpose/pull/1850), [#1868](https://github.com/open-mmlab/mmpose/pull/1868)) +- Fix local registry missing warnings ([#1849](https://github.com/open-mmlab/mmpose/pull/1849)) +- Remove deprecated scripts for model deployment ([#1845](https://github.com/open-mmlab/mmpose/pull/1845)) +- Fix a bug in input transformation in BaseHead ([#1843](https://github.com/open-mmlab/mmpose/pull/1843)) +- Fix an interface mismatch with MMDetection in webcam demo ([#1813](https://github.com/open-mmlab/mmpose/pull/1813)) +- Fix a bug in heatmap visualization that causes incorrect scale ([#1800](https://github.com/open-mmlab/mmpose/pull/1800)) +- Add model metafiles ([#1768](https://github.com/open-mmlab/mmpose/pull/1768)) + +## **v1.0.0rc0 (14/10/2022)** + +**New Features** + +- Support 4 light-weight pose estimation algorithms: [SimCC](https://doi.org/10.48550/arxiv.2107.03332) (ECCV'2022), [Debias-IPR](https://openaccess.thecvf.com/content/ICCV2021/papers/Gu_Removing_the_Bias_of_Integral_Pose_Regression_ICCV_2021_paper.pdf) (ICCV'2021), [IPR](https://arxiv.org/abs/1711.08229) (ECCV'2018), and [DSNT](https://arxiv.org/abs/1801.07372v2) (ArXiv'2018) ([#1628](https://github.com/open-mmlab/mmpose/pull/1628)) + +**Migrations** + +- Add Webcam API in MMPose 1.0 ([#1638](https://github.com/open-mmlab/mmpose/pull/1638), [#1662](https://github.com/open-mmlab/mmpose/pull/1662)) @Ben-Louis +- Add codec for Associative Embedding (beta) ([#1603](https://github.com/open-mmlab/mmpose/pull/1603)) @ly015 + +**Improvements** + +- Add a colab tutorial for MMPose 1.0 ([#1660](https://github.com/open-mmlab/mmpose/pull/1660)) @Tau-J +- Add model index in config folder ([#1710](https://github.com/open-mmlab/mmpose/pull/1710), [#1709](https://github.com/open-mmlab/mmpose/pull/1709), [#1627](https://github.com/open-mmlab/mmpose/pull/1627)) @ly015, @Tau-J, @Ben-Louis +- Update and improve documentation ([#1692](https://github.com/open-mmlab/mmpose/pull/1692), [#1656](https://github.com/open-mmlab/mmpose/pull/1656), [#1681](https://github.com/open-mmlab/mmpose/pull/1681), [#1677](https://github.com/open-mmlab/mmpose/pull/1677), [#1664](https://github.com/open-mmlab/mmpose/pull/1664), [#1659](https://github.com/open-mmlab/mmpose/pull/1659)) @Tau-J, @Ben-Louis, @liqikai9 +- Improve config structures and formats ([#1651](https://github.com/open-mmlab/mmpose/pull/1651)) @liqikai9 + +**Bug Fixes** + +- Update mmengine version requirements ([#1715](https://github.com/open-mmlab/mmpose/pull/1715)) @Ben-Louis +- Update dependencies of pre-commit hooks ([#1705](https://github.com/open-mmlab/mmpose/pull/1705)) @Ben-Louis +- Fix mmcv version in DockerFile ([#1704](https://github.com/open-mmlab/mmpose/pull/1704)) +- Fix a bug in setting dataset metainfo in configs ([#1684](https://github.com/open-mmlab/mmpose/pull/1684)) @ly015 +- Fix a bug in UDP training ([#1682](https://github.com/open-mmlab/mmpose/pull/1682)) @liqikai9 +- Fix a bug in Dark decoding ([#1676](https://github.com/open-mmlab/mmpose/pull/1676)) @liqikai9 +- Fix bugs in visualization ([#1671](https://github.com/open-mmlab/mmpose/pull/1671), [#1668](https://github.com/open-mmlab/mmpose/pull/1668), [#1657](https://github.com/open-mmlab/mmpose/pull/1657)) @liqikai9, @Ben-Louis +- Fix incorrect flops calculation ([#1669](https://github.com/open-mmlab/mmpose/pull/1669)) @liqikai9 +- Fix `tensor.tile` compatibility issue for pytorch 1.6 ([#1658](https://github.com/open-mmlab/mmpose/pull/1658)) @ly015 +- Fix compatibility with `MultilevelPixelData` ([#1647](https://github.com/open-mmlab/mmpose/pull/1647)) @liqikai9 + ## **v1.0.0beta (1/09/2022)** We are excited to announce the release of MMPose 1.0.0beta. diff --git a/docs/zh_cn/notes/pytorch_2.md b/docs/zh_cn/notes/pytorch_2.md index cd1d73f3fc..4892e554a5 100644 --- a/docs/zh_cn/notes/pytorch_2.md +++ b/docs/zh_cn/notes/pytorch_2.md @@ -1,3 +1,14 @@ # PyTorch 2.0 Compatibility and Benchmarks -Coming soon. +MMPose 1.0.0 is now compatible with PyTorch 2.0, ensuring that users can leverage the latest features and performance improvements offered by the PyTorch 2.0 framework when using MMPose. With the integration of inductor, users can expect faster model speeds. The table below shows several example models: + +| Model | Training Speed | Memory | +| :-------- | :---------------------: | :-----------: | +| ViTPose-B | 29.6% ↑ (0.931 → 0.655) | 10586 → 10663 | +| ViTPose-S | 33.7% ↑ (0.563 → 0.373) | 6091 → 6170 | +| HRNet-w32 | 12.8% ↑ (0.553 → 0.482) | 9849 → 10145 | +| HRNet-w48 | 37.1% ↑ (0.437 → 0.275) | 7319 → 7394 | +| RTMPose-t | 6.3% ↑ (1.533 → 1.437) | 6292 → 6489 | +| RTMPose-s | 13.1% ↑ (1.645 → 1.430) | 9013 → 9208 | + +- Pytorch 2.0 test, add projects doc and refactor by @LareinaM in [PR#2136](https://github.com/open-mmlab/mmpose/pull/2136) diff --git a/docs/zh_cn/stats.py b/docs/zh_cn/stats.py index 1e7d4ac049..218d23f5b0 100644 --- a/docs/zh_cn/stats.py +++ b/docs/zh_cn/stats.py @@ -88,7 +88,7 @@ def anchor(name): * 论文数量: {len(allpapers)} {countstr} -已支持的数据集详细信息请见 [数据集](datasets.md). +已支持的数据集详细信息请见 [数据集](dataset_zoo.md). {msglist} @@ -167,7 +167,7 @@ def anchor(name): * 论文数量: {len(alldatapapers)} {countstr} -已支持的算法详细信息请见 [模型池](modelzoo.md). +已支持的算法详细信息请见 [模型池](model_zoo.md). {datamsglist} """ diff --git a/docs/zh_cn/user_guides/configs.md b/docs/zh_cn/user_guides/configs.md index b7c0c4cdb6..0bcb7aa1a8 100644 --- a/docs/zh_cn/user_guides/configs.md +++ b/docs/zh_cn/user_guides/configs.md @@ -36,6 +36,15 @@ Class Loss_A(nn.Module): return x ``` +并在对应目录下的 `__init__.py` 中进行 `import`: + +```Python +# __init__.py of mmpose/models/losses +from .loss_a.py import Loss_A + +__all__ = ['Loss_A'] +``` + 我们就可以通过如下方式来从配置文件定义并进行实例化: ```Python diff --git a/docs/zh_cn/user_guides/inference.md b/docs/zh_cn/user_guides/inference.md index d77ff2185c..0844bc611f 100644 --- a/docs/zh_cn/user_guides/inference.md +++ b/docs/zh_cn/user_guides/inference.md @@ -1,3 +1,267 @@ -# 模型推理 +# 使用现有模型进行推理 -中文内容建设中,暂时请查阅[英文版文档](../../en/user_guides/inference.md) +MMPose为姿态估计提供了大量可以从[模型库](https://mmpose.readthedocs.io/en/latest/model_zoo.html)中找到的预测训练模型。本指南将演示**如何执行推理**,或使用训练过的模型对提供的图像或视频运行姿态估计。 + +有关在标准数据集上测试现有模型的说明,请参阅本指南。 + +在MMPose,模型由配置文件定义,而其已计算好的参数存储在权重文件(checkpoint file)中。您可以在[模型库](https://mmpose.readthedocs.io/en/latest/model_zoo.html)中找到模型配置文件和相应的权重文件的URL。我们建议从使用HRNet模型的[配置文件](https://github.com/open-mmlab/mmpose/blob/main/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192.py)和[权重文件](https://download.openmmlab.com/mmpose/v1/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192-81c58e40_20220909.pth)开始。 + +## 推理器:统一的推理接口 + +MMPose提供了一个被称为`MMPoseInferencer`的、全面的推理API。这个API使得用户得以使用所有MMPose支持的模型来对图像和视频进行模型推理。此外,该API可以完成推理结果自动化,并方便用户保存预测结果。 + +### 基本用法 + +`MMPoseInferencer`可以在任何Python程序中被用来执行姿态估计任务。以下是在一个在Python Shell中使用预训练的人体姿态模型对给定图像进行推理的示例。 + +```python +from mmpose.apis import MMPoseInferencer + +img_path = 'tests/data/coco/000000000785.jpg' # 将img_path替换给你自己的路径 + +# 使用模型别名创建推断器 +inferencer = MMPoseInferencer('human') + +# MMPoseInferencer采用了惰性推断方法,在给定输入时创建一个预测生成器 +result_generator = inferencer(img_path, show=True) +result = next(result_generator) +``` + +如果一切正常,你将在一个新窗口中看到下图: + +![inferencer_result_coco](https://user-images.githubusercontent.com/26127467/220008302-4a57fd44-0978-408e-8351-600e5513316a.jpg) + +`result` 变量是一个包含两个键值 `'visualization'` 和 `'predictions'` 的字典。 + +- `'visualization'` 键对应的值是一个列表,该列表: + - 包含可视化结果,例如输入图像、估计姿态的标记,以及可选的预测热图。 + - 如果没有指定 `return_vis` 参数,该列表将保持为空。 +- `'predictions'` 键对应的值是: + - 一个包含每个检测实例的预估关键点的列表。 + +`result` 字典的结构如下所示: + +```python +result = { + 'visualization': [ + # 元素数量:batch_size(默认为1) + vis_image_1, + ... + ], + 'predictions': [ + # 每张图像的姿态估计结果 + # 元素数量:batch_size(默认为1) + [ + # 每个检测到的实例的姿态信息 + # 元素数量:检测到的实例数 + {'keypoints': ..., # 实例 1 + 'keypoint_scores': ..., + ... + }, + {'keypoints': ..., # 实例 2 + 'keypoint_scores': ..., + ... + }, + ] + ... + ] +} +``` + +还可以使用用于用于推断的**命令行界面工具**(CLI, command-line interface): `demo/inferencer_demo.py`。这个工具允许用户使用以下命令使用相同的模型和输入执行推理: + +```python +python demo/inferencer_demo.py 'tests/data/coco/000000000785.jpg' \ + --pose2d 'human' --show --pred-out-dir 'predictions' +``` + +预测结果将被保存在路径`predictions/000000000785.json`。作为一个API,`inferencer_demo.py`的输入参数与`MMPoseInferencer`的相同。前者能够处理一系列输入类型,包括以下内容: + +- 图像路径 + +- 视频路径 + +- 文件夹路径(这会导致该文件夹中的所有图像都被推断出来) + +- 表示图像的 numpy array (在命令行界面工具中未支持) + +- 表示图像的 numpy array 列表 (在命令行界面工具中未支持) + +- 摄像头(在这种情况下,输入参数应该设置为`webcam`或`webcam:{CAMERA_ID}`) + +当输入对应于多个图像时,例如输入为**视频**或**文件夹**路径时,推理生成器必须被遍历,以便推理器对视频/文件夹中的所有帧/图像进行推理。以下是一个示例: + +```python +folder_path = 'tests/data/coco' + +result_generator = inferencer(folder_path, show=True) +results = [result for result in result_generator] +``` + +在这个示例中,`inferencer` 接受 `folder_path` 作为输入,并返回一个生成器对象(`result_generator`),用于生成推理结果。通过遍历 `result_generator` 并将每个结果存储在 `results` 列表中,您可以获得视频/文件夹中所有帧/图像的推理结果。 + +### 自定义姿态估计模型 + +`MMPoseInferencer`提供了几种可用于自定义所使用的模型的方法: + +```python +# 使用模型别名构建推断器 +inferencer = MMPoseInferencer('human') + +# 使用模型配置名构建推断器 +inferencer = MMPoseInferencer('td-hm_hrnet-w32_8xb64-210e_coco-256x192') + +# 使用模型配置文件和权重文件的路径或 URL 构建推断器 +inferencer = MMPoseInferencer( + pose2d='configs/body_2d_keypoint/topdown_heatmap/coco/' \ + 'td-hm_hrnet-w32_8xb64-210e_coco-256x192.py', + pose2d_weights='https://download.openmmlab.com/mmpose/top_down/' \ + 'hrnet/hrnet_w32_coco_256x192-c78dce93_20200708.pth' +) +``` + +模型别名的完整列表可以在模型别名部分中找到。 + +此外,自顶向下的姿态估计器还需要一个对象检测模型。`MMPoseInferencer`能够推断用MMPose支持的数据集训练的模型的实例类型,然后构建必要的对象检测模型。用户也可以通过以下方式手动指定检测模型: + +```python +# 通过别名指定检测模型 +# 可用的别名包括“human”、“hand”、“face”、“animal”、 +# 以及mmdet中定义的任何其他别名 +inferencer = MMPoseInferencer( + # 假设姿态估计器是在自定义数据集上训练的 + pose2d='custom_human_pose_estimator.py', + pose2d_weights='custom_human_pose_estimator.pth', + det_model='human' +) + +# 使用模型配置名称指定检测模型 +inferencer = MMPoseInferencer( + pose2d='human', + det_model='yolox_l_8x8_300e_coco', + det_cat_ids=[0], # 指定'human'类的类别id +) + +# 使用模型配置文件和权重文件的路径或URL构建推断器 +inferencer = MMPoseInferencer( + pose2d='human', + det_model=f'{PATH_TO_MMDET}/configs/yolox/yolox_l_8x8_300e_coco.py', + det_weights='https://download.openmmlab.com/mmdetection/v2.0/' \ + 'yolox/yolox_l_8x8_300e_coco/' \ + 'yolox_l_8x8_300e_coco_20211126_140236-d3bd2b23.pth', + det_cat_ids=[0], # 指定'human'类的类别id +) +``` + +### 转储结果 + +在执行姿态估计推理任务之后,您可能希望保存结果以供进一步分析或处理。本节将指导您将预测的关键点和可视化结果保存到本地。 + +要将预测保存在JSON文件中,在运行`MMPoseInferencer`的实例`inferencer`时使用`pred_out_dir`参数: + +```python +result_generator = inferencer(img_path, pred_out_dir='predictions') +result = next(result_generator) +``` + +预测结果将以JSON格式保存在`predictions/`文件夹中,每个文件以相应的输入图像或视频的名称命名。 + +对于更高级的场景,还可以直接从`inferencer`返回的`result`字典中访问预测结果。其中,`predictions`包含输入图像或视频中每个单独实例的预测关键点列表。然后,您可以使用您喜欢的方法操作或存储这些结果。 + +请记住,如果你想将可视化图像和预测文件保存在一个文件夹中,你可以使用`out_dir`参数: + +```python +result_generator = inferencer(img_path, out_dir='output') +result = next(result_generator) +``` + +在这种情况下,可视化图像将保存在`output/visualization/`文件夹中,而预测将存储在`output/forecasts/`文件夹中。 + +### 可视化 + +推理器`inferencer`可以自动对输入的图像或视频进行预测。可视化结果可以显示在一个新的窗口中,并保存在本地。 + +要在新窗口中查看可视化结果,请使用以下代码: + +请注意: + +- 如果输入视频来自网络摄像头,默认情况下将在新窗口中显示可视化结果,以此让用户看到输入 + +- 如果平台上没有GUI,这个步骤可能会卡住 + +要将可视化结果保存在本地,可以像这样指定`vis_out_dir`参数: + +```python +result_generator = inferencer(img_path, vis_out_dir='vis_results') +result = next(result_generator) +``` + +输入图片或视频的可视化预测结果将保存在`vis_results/`文件夹中 + +在开头展示的滑雪图中,姿态的可视化估计结果由关键点(用实心圆描绘)和骨架(用线条表示)组成。这些视觉元素的默认大小可能不会产生令人满意的结果。用户可以使用`radius`和`thickness`参数来调整圆的大小和线的粗细,如下所示: + +```python +result_generator = inferencer(img_path, show=True, radius=4, thickness=2) +result = next(result_generator) +``` + +### 推理器参数 + +`MMPoseInferencer`提供了各种自定义姿态估计、可视化和保存预测结果的参数。下面是初始化推断器时可用的参数列表及对这些参数的描述: + +| Argument | Description | +| ---------------- | ------------------------------------------------------------ | +| `pose2d` | 指定 2D 姿态估计模型的模型别名、配置文件名称或配置文件路径。 | +| `pose2d_weights` | 指定 2D 姿态估计模型权重文件的URL或本地路径。 | +| `pose3d` | 指定 3D 姿态估计模型的模型别名、配置文件名称或配置文件路径。 | +| `pose3d_weights` | 指定 3D 姿态估计模型权重文件的URL或本地路径。 | +| `det_model` | 指定对象检测模型的模型别名、配置文件名或配置文件路径。 | +| `det_weights` | 指定对象检测模型权重文件的 URL 或本地路径。 | +| `det_cat_ids` | 指定与要检测的对象类对应的类别 id 列表。 | +| `device` | 执行推理的设备。如果为 `None`,推理器将选择最合适的一个。 | +| `scope` | 定义模型模块的名称空间 | + +推理器被设计用于可视化和保存预测。以下表格列出了在使用 `MMPoseInferencer` 进行推断时可用的参数列表,以及它们与 2D 和 3D 推理器的兼容性: + +| 参数 | 描述 | 2D | 3D | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------------- | --- | --- | +| `show` | 控制是否在弹出窗口中显示图像或视频。 | ✔️ | ✔️ | +| `radius` | 设置可视化关键点的半径。 | ✔️ | ✔️ | +| `thickness` | 确定可视化链接的厚度。 | ✔️ | ✔️ | +| `kpt_thr` | 设置关键点分数阈值。分数超过此阈值的关键点将被显示。 | ✔️ | ✔️ | +| `draw_bbox` | 决定是否显示实例的边界框。 | ✔️ | ✔️ | +| `draw_heatmap` | 决定是否绘制预测的热图。 | ✔️ | ❌ | +| `black_background` | 决定是否在黑色背景上显示预估的姿势。 | ✔️ | ❌ | +| `skeleton_style` | 设置骨架样式。可选项包括 'mmpose'(默认)和 'openpose'。 | ✔️ | ❌ | +| `use_oks_tracking` | 决定是否在追踪中使用OKS作为相似度测量。 | ❌ | ✔️ | +| `tracking_thr` | 设置追踪的相似度阈值。 | ❌ | ✔️ | +| `norm_pose_2d` | 决定是否将边界框缩放至数据集的平均边界框尺寸,并将边界框移至数据集的平均边界框中心。 | ❌ | ✔️ | +| `rebase_keypoint_height` | 决定是否将最低关键点的高度置为 0。 | ❌ | ✔️ | +| `return_vis` | 决定是否在结果中包含可视化图像。 | ✔️ | ✔️ | +| `vis_out_dir` | 定义保存可视化图像的文件夹路径。如果未设置,将不保存可视化图像。 | ✔️ | ✔️ | +| `return_datasample` | 决定是否以 `PoseDataSample` 格式返回预测。 | ✔️ | ✔️ | +| `pred_out_dir` | 指定保存预测的文件夹路径。如果未设置,将不保存预测。 | ✔️ | ✔️ | +| `out_dir` | 如果 `vis_out_dir` 或 `pred_out_dir` 未设置,它们将分别设置为 `f'{out_dir}/visualization'` 或 `f'{out_dir}/predictions'`。 | ✔️ | ✔️ | + +### 模型别名 + +MMPose为常用模型提供了一组预定义的别名。在初始化 `MMPoseInferencer` 时,这些别名可以用作简略的表达方式,而不是指定完整的模型配置名称。下面是可用的模型别名及其对应的配置名称的列表: + +| 别名 | 配置文件名称 | 对应任务 | 姿态估计模型 | 检测模型 | +| --------- | -------------------------------------------------- | ------------------------------- | ------------- | ------------------- | +| animal | rtmpose-m_8xb64-210e_ap10k-256x256 | Animal pose estimation | RTMPose-m | RTMDet-m | +| human | rtmpose-m_8xb256-420e_aic-coco-256x192 | Human pose estimation | RTMPose-m | RTMDet-m | +| face | rtmpose-m_8xb64-60e_wflw-256x256 | Face keypoint detection | RTMPose-m | yolox-s | +| hand | rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256 | Hand keypoint detection | RTMPose-m | ssdlite_mobilenetv2 | +| wholebody | rtmpose-m_8xb64-270e_coco-wholebody-256x192 | Human wholebody pose estimation | RTMPose-m | RTMDet-m | +| vitpose | td-hm_ViTPose-base-simple_8xb64-210e_coco-256x192 | Human pose estimation | ViTPose-base | RTMDet-m | +| vitpose-s | td-hm_ViTPose-small-simple_8xb64-210e_coco-256x192 | Human pose estimation | ViTPose-small | RTMDet-m | +| vitpose-b | td-hm_ViTPose-base-simple_8xb64-210e_coco-256x192 | Human pose estimation | ViTPose-base | RTMDet-m | +| vitpose-l | td-hm_ViTPose-large-simple_8xb64-210e_coco-256x192 | Human pose estimation | ViTPose-large | RTMDet-m | +| vitpose-h | td-hm_ViTPose-huge-simple_8xb64-210e_coco-256x192 | Human pose estimation | ViTPose-huge | RTMDet-m | + +此外,用户可以使用命令行界面工具显示所有可用的别名,使用以下命令: + +```shell +python demo/inferencer_demo.py --show-alias +``` diff --git a/docs/zh_cn/user_guides/prepare_datasets.md b/docs/zh_cn/user_guides/prepare_datasets.md index a10a7e4836..8b7d651e88 100644 --- a/docs/zh_cn/user_guides/prepare_datasets.md +++ b/docs/zh_cn/user_guides/prepare_datasets.md @@ -1,264 +1,221 @@ # 准备数据集 -MMPose 目前已支持了多个任务和相应的数据集。您可以在 [数据集](https://mmpose.readthedocs.io/zh_CN/latest/dataset_zoo.html) 找到它们。请按照相应的指南准备数据。 - - - -- [自定义数据集-将数据组织为 COCO 格式](#自定义数据集-将数据组织为-coco-格式) -- [创建自定义数据集的元信息文件](#创建自定义数据集的元信息文件) -- [创建自定义数据集类](#创建自定义数据集类) -- [创建自定义配置文件](#创建自定义配置文件) -- [数据集封装](#数据集封装) - - - -## 自定义数据集-将数据组织为 COCO 格式 - -最简单的使用自定义数据集的方法是将您的注释格式转换为 COCO 数据集格式。 - -COCO 格式的注释 JSON 文件具有以下必要键: - -```python -'images': [ - { - 'file_name': '000000001268.jpg', - 'height': 427, - 'width': 640, - 'id': 1268 - }, - ... -], -'annotations': [ - { - 'segmentation': [[426.36, - ... - 424.34, - 223.3]], - 'keypoints': [0,0,0, - 0,0,0, - 0,0,0, - 427,220,2, - 443,222,2, - 414,228,2, - 449,232,2, - 408,248,1, - 454,261,2, - 0,0,0, - 0,0,0, - 411,287,2, - 431,287,2, - 0,0,0, - 458,265,2, - 0,0,0, - 466,300,1], - 'num_keypoints': 10, - 'area': 3894.5826, - 'iscrowd': 0, - 'image_id': 1268, - 'bbox': [402.34, 205.02, 65.26, 88.45], - 'category_id': 1, - 'id': 215218 - }, - ... -], -'categories': [ - {'id': 1, 'name': 'person'}, - ] +在这份文档将指导如何为 MMPose 准备数据集,包括使用内置数据集、创建自定义数据集、结合数据集进行训练、浏览和下载数据集。 + +## 使用内置数据集 + +**步骤一**: 准备数据 + +MMPose 支持多种任务和相应的数据集。你可以在 [数据集仓库](https://mmpose.readthedocs.io/en/latest/dataset_zoo.html) 中找到它们。为了正确准备你的数据,请按照你选择的数据集的指南进行操作。 + +**步骤二**: 在配置文件中进行数据集设置 + +在开始训练或评估模型之前,你必须配置数据集设置。以 [`td-hm_hrnet-w32_8xb64-210e_coco-256x192.py`](/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-210e_coco-256x192.py) 为例,它可以用于在 COCO 数据集上训练或评估 HRNet 姿态估计器。下面我们浏览一下数据集配置: + +- 基础数据集参数 + + ```python + # base dataset settings + dataset_type = 'CocoDataset' + data_mode = 'topdown' + data_root = 'data/coco/' + ``` + + - `dataset_type` 指定数据集的类名。用户可以参考 [数据集 API](https://mmpose.readthedocs.io/en/latest/api.html#datasets) 来找到他们想要的数据集的类名。 + - `data_mode` 决定了数据集的输出格式,有两个选项可用:`'topdown'` 和 `'bottomup'`。如果 `data_mode='topdown'`,数据元素表示一个实例及其姿态;否则,一个数据元素代表一张图像,包含多个实例和姿态。 + - `data_root` 指定数据集的根目录。 + +- 数据处理流程 + + ```python + # pipelines + train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict(type='RandomBBoxTransform'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') + ] + val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') + ] + ``` + + `train_pipeline` 和 `val_pipeline` 分别定义了训练和评估阶段处理数据元素的步骤。除了加载图像和打包输入之外,`train_pipeline` 主要包含数据增强技术和目标生成器,而 `val_pipeline` 则专注于将数据元素转换为统一的格式。 + +- 数据加载器 + + ```python + # data loaders + train_dataloader = dict( + batch_size=64, + num_workers=2, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/person_keypoints_train2017.json', + data_prefix=dict(img='train2017/'), + pipeline=train_pipeline, + )) + val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/person_keypoints_val2017.json', + bbox_file='data/coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', + data_prefix=dict(img='val2017/'), + test_mode=True, + pipeline=val_pipeline, + )) + test_dataloader = val_dataloader + ``` + + 这个部分是配置数据集的关键。除了前面讨论过的基础数据集参数和数据处理流程之外,这里还定义了其他重要的参数。`batch_size` 决定了每个 GPU 的 batch size;`ann_file` 指定了数据集的注释文件;`data_prefix` 指定了图像文件夹。`bbox_file` 仅在 top-down 数据集的 val/test 数据加载器中使用,用于提供检测到的边界框信息。 + +我们推荐从使用相同数据集的配置文件中复制数据集配置,而不是从头开始编写,以最小化潜在的错误。通过这样做,用户可以根据需要进行必要的修改,从而确保更可靠和高效的设置过程。 + +## 使用自定义数据集 + +[自定义数据集](../advanced_guides/customize_datasets.md) 指南提供了如何构建自定义数据集的详细信息。在本节中,我们将强调一些使用和配置自定义数据集的关键技巧。 + +- 确定数据集类名。如果你将数据集重组为 COCO 格式,你可以简单地使用 `CocoDataset` 作为 `dataset_type` 的值。否则,你将需要使用你添加的自定义数据集类的名称。 + +- 指定元信息配置文件。MMPose 1.x 采用了与 MMPose 0.x 不同的策略来指定元信息。在 MMPose 1.x 中,用户可以按照以下方式指定元信息配置文件: + + ```python + train_dataloader = dict( + ... + dataset=dict( + type=dataset_type, + data_root='root/of/your/train/data', + ann_file='path/to/your/train/json', + data_prefix=dict(img='path/to/your/train/img'), + # specify dataset meta information + metainfo=dict(from_file='configs/_base_/datasets/custom.py'), + ...), + ) + ``` + + 注意,`metainfo` 参数必须在 val/test 数据加载器中指定。 + +## 使用混合数据集进行训练 + +MMPose 提供了一个方便且多功能的解决方案,用于训练混合数据集。请参考[混合数据集训练](./mixed_datasets.md)。 + +## 浏览数据集 + +`tools/analysis_tools/browse_dataset.py` 帮助用户可视化地浏览姿态数据集,或将图像保存到指定的目录。 + +```shell +python tools/misc/browse_dataset.py ${CONFIG} [-h] [--output-dir ${OUTPUT_DIR}] [--not-show] [--phase ${PHASE}] [--mode ${MODE}] [--show-interval ${SHOW_INTERVAL}] ``` -JSON 标注文件中有三个关键词是必需的: +| ARGS | Description | +| -------------------------------- | ---------------------------------------------------------------------------------------------------------- | +| `CONFIG` | 配置文件的路径 | +| `--output-dir OUTPUT_DIR` | 保存可视化结果的目标文件夹。如果不指定,可视化的结果将不会被保存 | +| `--not-show` | 不适用外部窗口显示可视化的结果 | +| `--phase {train, val, test}` | 数据集选项 | +| `--mode {original, transformed}` | 指定可视化图片类型。 `original` 为不使用数据增强的原始图片及标注可视化; `transformed` 为经过增强后的可视化 | +| `--show-interval SHOW_INTERVAL` | 显示图片的时间间隔 | -- `images`:包含所有图像信息的列表,每个图像都有一个 `file_name`、`height`、`width` 和 `id` 键。 -- `annotations`:包含所有实例标注信息的列表,每个实例都有一个 `segmentation`、`keypoints`、`num_keypoints`、`area`、`iscrowd`、`image_id`、`bbox`、`category_id` 和 `id` 键。 -- `categories`:包含所有类别信息的列表,每个类别都有一个 `id` 和 `name` 键。以人体姿态估计为例,`id` 为 1,`name` 为 `person`。 +例如,用户想要可视化 COCO 数据集中的图像和标注,可以使用: -如果您的数据集已经是 COCO 格式的,那么您可以直接使用 `CocoDataset` 类来读取该数据集。 +```shell +python tools/misc/browse_dataset.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-e210_coco-256x192.py --mode original +``` -## 创建自定义数据集的元信息文件 +检测框和关键点将被绘制在原始图像上。下面是一个例子: +![original_coco](https://user-images.githubusercontent.com/26127467/187383698-7e518f21-b4cc-4712-9e97-99ddd8f0e437.jpg) -对于一个新的数据集而言,您需要创建一个新的数据集元信息文件。该文件包含了数据集的基本信息,如关键点个数、排列顺序、可视化颜色、骨架连接关系等。元信息文件通常存放在 `config/_base_/datasets/` 目录下,例如: +原始图像在被输入模型之前需要被处理。为了可视化预处理后的图像和标注,用户需要将参数 `mode` 修改为 `transformed`。例如: -``` -config/_base_/datasets/custom.py +```shell +python tools/misc/browse_dataset.py configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w32_8xb64-e210_coco-256x192.py --mode transformed ``` -元信息文件中需要包含以下信息: - -- `keypoint_info`:每个关键点的信息: - 1. `name`: 关键点名称,必须是唯一的,例如 `nose`、`left_eye` 等。 - 2. `id`: 关键点 ID,必须是唯一的,从 0 开始。 - 3. `color`: 关键点可视化时的颜色,以 (\[B, G, R\]) 格式组织起来,用于可视化。 - 4. `type`: 关键点类型,可以是 `upper`、`lower` 或 \`\`,用于数据增强。 - 5. `swap`: 关键点交换关系,用于水平翻转数据增强。 -- `skeleton_info`:骨架连接关系,用于可视化。 -- `joint_weights`:每个关键点的权重,用于损失函数计算。 -- `sigma`:标准差,用于计算 OKS 分数,详细信息请参考 [keypoints-eval](https://cocodataset.org/#keypoints-eval)。 - -下面是一个简化版本的元信息文件([完整版](/configs/_base_/datasets/coco.py)): - -```python -dataset_info = dict( - dataset_name='coco', - paper_info=dict( - author='Lin, Tsung-Yi and Maire, Michael and ' - 'Belongie, Serge and Hays, James and ' - 'Perona, Pietro and Ramanan, Deva and ' - r'Doll{\'a}r, Piotr and Zitnick, C Lawrence', - title='Microsoft coco: Common objects in context', - container='European conference on computer vision', - year='2014', - homepage='http://cocodataset.org/', - ), - keypoint_info={ - 0: - dict(name='nose', id=0, color=[51, 153, 255], type='upper', swap=''), - 1: - dict( - name='left_eye', - id=1, - color=[51, 153, 255], - type='upper', - swap='right_eye'), - ... - 16: - dict( - name='right_ankle', - id=16, - color=[255, 128, 0], - type='lower', - swap='left_ankle') - }, - skeleton_info={ - 0: - dict(link=('left_ankle', 'left_knee'), id=0, color=[0, 255, 0]), - ... - 18: - dict( - link=('right_ear', 'right_shoulder'), id=18, color=[51, 153, 255]) - }, - joint_weights=[ - 1., 1., 1., 1., 1., 1., 1., 1.2, 1.2, 1.5, 1.5, 1., 1., 1.2, 1.2, 1.5, - 1.5 - ], - sigmas=[ - 0.026, 0.025, 0.025, 0.035, 0.035, 0.079, 0.079, 0.072, 0.072, 0.062, - 0.062, 0.107, 0.107, 0.087, 0.087, 0.089, 0.089 - ]) -``` +这是一个处理后的样本: -## 创建自定义数据集类 - -如果标注信息不是用 COCO 格式存储的,那么您需要创建一个新的数据集类。数据集类需要继承自 `BaseDataset` 类,并且需要按照以下步骤实现: - -1. 在 `mmpose/datasets/datasets` 目录下找到该数据集符合的 package,如果没有符合的,则创建一个新的 package。 - -2. 在该 package 下创建一个新的数据集类,在对应的注册器中进行注册: - - ```python - from mmengine.dataset import BaseDataset - from mmpose.registry import DATASETS - - @DATASETS.register_module(name='MyCustomDataset') - class MyCustomDataset(BaseDataset): - ``` - - 如果未注册,你会在运行时遇到 `KeyError: 'XXXXX is not in the dataset registry'`。 - 关于 `mmengine.BaseDataset` 的更多信息,请参考 [这个文档](https://mmengine.readthedocs.io/en/latest/advanced_tutorials/basedataset.html)。 - -3. 确保你在 package 的 `__init__.py` 中导入了该数据集类。 - -4. 确保你在 `mmpose/datasets/__init__.py` 中导入了该 package。 - -## 创建自定义配置文件 - -在配置文件中,你需要修改跟数据集有关的部分,例如: - -```python -... -# 自定义数据集类 -dataset_type = 'MyCustomDataset' # or 'CocoDataset' - -train_dataloader = dict( - batch_size=2, - dataset=dict( - type=dataset_type, - data_root='root/of/your/train/data', - ann_file='path/to/your/train/json', - data_prefix=dict(img='path/to/your/train/img'), - metainfo=dict(from_file='configs/_base_/datasets/custom.py'), - ...), - ) - -val_dataloader = dict( - batch_size=2, - dataset=dict( - type=dataset_type, - data_root='root/of/your/val/data', - ann_file='path/to/your/val/json', - data_prefix=dict(img='path/to/your/val/img'), - metainfo=dict(from_file='configs/_base_/datasets/custom.py'), - ...), - ) - -test_dataloader = dict( - batch_size=2, - dataset=dict( - type=dataset_type, - data_root='root/of/your/test/data', - ann_file='path/to/your/test/json', - data_prefix=dict(img='path/to/your/test/img'), - metainfo=dict(from_file='configs/_base_/datasets/custom.py'), - ...), - ) -... -``` +![transformed_coco](https://user-images.githubusercontent.com/26127467/187386652-bd47335d-797c-4e8c-b823-2a4915f9812f.jpg) + +热图目标将与之一起可视化,如果它是在 pipeline 中生成的。 + +## 用 MIM 下载数据集 -请确保所有的路径都是正确的。 - -## 数据集封装 - -目前 [MMEngine](https://github.com/open-mmlab/mmengine) 支持以下数据集封装: - -- [ConcatDataset](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/basedataset.html#concatdataset) -- [RepeatDataset](https://mmengine.readthedocs.io/zh_CN/latest/advanced_tutorials/basedataset.html#repeatdataset) - -### CombinedDataset - -MMPose 提供了一个 `CombinedDataset` 类,它可以将多个数据集封装成一个数据集。它的使用方法如下: - -```python -dataset_1 = dict( - type='dataset_type_1', - data_root='root/of/your/dataset1', - data_prefix=dict(img_path='path/to/your/img'), - ann_file='annotations/train.json', - pipeline=[ - # 使用转换器将标注信息统一为需要的格式 - converter_transform_1 - ]) - -dataset_2 = dict( - type='dataset_type_2', - data_root='root/of/your/dataset2', - data_prefix=dict(img_path='path/to/your/img'), - ann_file='annotations/train.json', - pipeline=[ - converter_transform_2 - ]) - -shared_pipeline = [ - LoadImage(), - ParseImage(), -] - -combined_dataset = dict( - type='CombinedDataset', - metainfo=dict(from_file='path/to/your/metainfo'), - datasets=[dataset_1, dataset_2], - pipeline=shared_pipeline, -) +通过使用 [OpenDataLab](https://opendatalab.com/),您可以直接下载开源数据集。通过平台的搜索功能,您可以快速轻松地找到他们正在寻找的数据集。使用平台上的格式化数据集,您可以高效地跨数据集执行任务。 + +如果您使用 MIM 下载,请确保版本大于 v0.3.8。您可以使用以下命令进行更新、安装、登录和数据集下载: + +```shell +# upgrade your MIM +pip install -U openmim + +# install OpenDataLab CLI tools +pip install -U opendatalab +# log in OpenDataLab, registry +odl login + +# download coco2017 and preprocess by MIM +mim download mmpose --dataset coco2017 ``` -- **合并数据集的元信息** 决定了标注格式,可以是子数据集的元信息,也可以是自定义的元信息。如果要自定义元信息,可以参考 [创建自定义数据集的元信息文件](#创建自定义数据集的元信息文件)。 -- **KeypointConverter** 用于将不同的标注格式转换成统一的格式。比如将关键点个数不同、关键点排列顺序不同的数据集进行合并。 -- 更详细的说明请前往进阶教程-[混合数据集训练](../advanced_guides/mixed_datasets.md)。 +### 已支持的数据集 + +下面是支持的数据集列表,更多数据集将在之后持续更新: + +#### 人体数据集 + +| Dataset name | Download command | +| ------------- | ----------------------------------------- | +| COCO 2017 | `mim download mmpose --dataset coco2017` | +| MPII | `mim download mmpose --dataset mpii` | +| AI Challenger | `mim download mmpose --dataset aic` | +| CrowdPose | `mim download mmpose --dataset crowdpose` | + +#### 人脸数据集 + +| Dataset name | Download command | +| ------------ | ------------------------------------ | +| LaPa | `mim download mmpose --dataset lapa` | +| 300W | `mim download mmpose --dataset 300w` | +| WFLW | `mim download mmpose --dataset wflw` | + +#### 手部数据集 + +| Dataset name | Download command | +| ------------ | ------------------------------------------ | +| OneHand10K | `mim download mmpose --dataset onehand10k` | +| FreiHand | `mim download mmpose --dataset freihand` | +| HaGRID | `mim download mmpose --dataset hagrid` | + +#### 全身数据集 + +| Dataset name | Download command | +| ------------ | ------------------------------------- | +| Halpe | `mim download mmpose --dataset halpe` | + +#### 动物数据集 + +| Dataset name | Download command | +| ------------ | ------------------------------------- | +| AP-10K | `mim download mmpose --dataset ap10k` | + +#### 服装数据集 + +Coming Soon diff --git a/docs/zh_cn/user_guides/train_and_test.md b/docs/zh_cn/user_guides/train_and_test.md index 3cddc5c715..452eddc928 100644 --- a/docs/zh_cn/user_guides/train_and_test.md +++ b/docs/zh_cn/user_guides/train_and_test.md @@ -1,3 +1,5 @@ # 训练与测试 中文内容建设中,暂时请查阅[英文版文档](../../en/user_guides/train_and_test.md) + +如果您愿意参与中文文档的翻译与维护,我们团队将十分感谢您的贡献!欢迎加入我们的社区群与我们取得联系,或直接按照 [如何给 MMPose 贡献代码](../contribution_guide.md) 在 GitHub 上提交 Pull Request。 diff --git a/docs/zh_cn/user_guides/useful_tools.md b/docs/zh_cn/user_guides/useful_tools.md index d7e027e609..f2ceb771b7 100644 --- a/docs/zh_cn/user_guides/useful_tools.md +++ b/docs/zh_cn/user_guides/useful_tools.md @@ -1,3 +1,5 @@ # 常用工具 中文内容建设中,暂时请查阅[英文版文档](../../en/user_guides/useful_tools.md) + +如果您愿意参与中文文档的翻译与维护,我们团队将十分感谢您的贡献!欢迎加入我们的社区群与我们取得联系,或直接按照 [如何给 MMPose 贡献代码](../contribution_guide.md) 在 GitHub 上提交 Pull Request。 diff --git a/docs/zh_cn/user_guides/visualization.md b/docs/zh_cn/user_guides/visualization.md index ffd20af99a..a584eb450e 100644 --- a/docs/zh_cn/user_guides/visualization.md +++ b/docs/zh_cn/user_guides/visualization.md @@ -1,3 +1,5 @@ # 可视化 中文内容建设中,暂时请查阅[英文版文档](../../en/user_guides/visualization.md) + +如果您愿意参与中文文档的翻译与维护,我们团队将十分感谢您的贡献!欢迎加入我们的社区群与我们取得联系,或直接按照 [如何给 MMPose 贡献代码](../contribution_guide.md) 在 GitHub 上提交 Pull Request。 diff --git a/docs/zh_cn/webcam_api.rst b/docs/zh_cn/webcam_api.rst deleted file mode 100644 index ff1c127515..0000000000 --- a/docs/zh_cn/webcam_api.rst +++ /dev/null @@ -1,112 +0,0 @@ -mmpose.apis.webcam --------------------- -.. contents:: MMPose Webcam API: Tools to build simple interactive webcam applications and demos - :depth: 2 - :local: - :backlinks: top - -Executor -^^^^^^^^^^^^^^^^^^^^ -.. currentmodule:: mmpose.apis.webcam -.. autosummary:: - :toctree: generated - :nosignatures: - - WebcamExecutor - -Nodes -^^^^^^^^^^^^^^^^^^^^ -.. currentmodule:: mmpose.apis.webcam.nodes - -Base Nodes -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - :template: webcam_node_class.rst - - Node - BaseVisualizerNode - -Model Nodes -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - :template: webcam_node_class.rst - - DetectorNode - TopdownPoseEstimatorNode - -Visualizer Nodes -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - :template: webcam_node_class.rst - - ObjectVisualizerNode - NoticeBoardNode - SunglassesEffectNode - BigeyeEffectNode - -Helper Nodes -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - :template: webcam_node_class.rst - - ObjectAssignerNode - MonitorNode - RecorderNode - -Utils -^^^^^^^^^^^^^^^^^^^^ -.. currentmodule:: mmpose.apis.webcam.utils - -Buffer and Message -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - - BufferManager - Message - FrameMessage - VideoEndingMessage - -Pose -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - - get_eye_keypoint_ids - get_face_keypoint_ids - get_hand_keypoint_ids - get_mouth_keypoint_ids - get_wrist_keypoint_ids - -Event -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - - EventManager - -Misc -"""""""""""""""""""" -.. autosummary:: - :toctree: generated - :nosignatures: - - copy_and_paste - screen_matting - expand_and_clamp - limit_max_fps - is_image_file - get_cached_file_path - load_image_from_disk_or_url - get_config_path diff --git a/mmpose/apis/__init__.py b/mmpose/apis/__init__.py index ff7149e453..0c44f7a3f8 100644 --- a/mmpose/apis/__init__.py +++ b/mmpose/apis/__init__.py @@ -1,8 +1,15 @@ # Copyright (c) OpenMMLab. All rights reserved. -from .inference import inference_bottomup, inference_topdown, init_model +from .inference import (collect_multi_frames, inference_bottomup, + inference_topdown, init_model) +from .inference_3d import (collate_pose_sequence, convert_keypoint_definition, + extract_pose_sequence, inference_pose_lifter_model) +from .inference_tracking import _compute_iou, _track_by_iou, _track_by_oks from .inferencers import MMPoseInferencer, Pose2DInferencer __all__ = [ 'init_model', 'inference_topdown', 'inference_bottomup', - 'Pose2DInferencer', 'MMPoseInferencer' + 'collect_multi_frames', 'Pose2DInferencer', 'MMPoseInferencer', + '_track_by_iou', '_track_by_oks', '_compute_iou', + 'inference_pose_lifter_model', 'extract_pose_sequence', + 'convert_keypoint_definition', 'collate_pose_sequence' ] diff --git a/mmpose/apis/inference.py b/mmpose/apis/inference.py index 6763d318d5..772ef17b7c 100644 --- a/mmpose/apis/inference.py +++ b/mmpose/apis/inference.py @@ -96,7 +96,9 @@ def init_model(config: Union[str, Path, Config], config.model.train_cfg = None # register all modules in mmpose into the registries - init_default_scope(config.get('default_scope', 'mmpose')) + scope = config.get('default_scope', 'mmpose') + if scope is not None: + init_default_scope(scope) model = build_pose_estimator(config.model) model = revert_sync_batchnorm(model) @@ -149,10 +151,12 @@ def inference_topdown(model: nn.Module, ``data_sample.pred_instances.keypoints`` and ``data_sample.pred_instances.keypoint_scores``. """ - init_default_scope(model.cfg.get('default_scope', 'mmpose')) + scope = model.cfg.get('default_scope', 'mmpose') + if scope is not None: + init_default_scope(scope) pipeline = Compose(model.cfg.test_dataloader.dataset.pipeline) - if bboxes is None: + if bboxes is None or len(bboxes) == 0: # get bbox from the image size if isinstance(img, str): w, h = Image.open(img).size @@ -223,3 +227,36 @@ def inference_bottomup(model: nn.Module, img: Union[np.ndarray, str]): results = model.test_step(batch) return results + + +def collect_multi_frames(video, frame_id, indices, online=False): + """Collect multi frames from the video. + + Args: + video (mmcv.VideoReader): A VideoReader of the input video file. + frame_id (int): index of the current frame + indices (list(int)): index offsets of the frames to collect + online (bool): inference mode, if set to True, can not use future + frame information. + + Returns: + list(ndarray): multi frames collected from the input video file. + """ + num_frames = len(video) + frames = [] + # put the current frame at first + frames.append(video[frame_id]) + # use multi frames for inference + for idx in indices: + # skip current frame + if idx == 0: + continue + support_idx = frame_id + idx + # online mode, can not use future frame information + if online: + support_idx = np.clip(support_idx, 0, frame_id) + else: + support_idx = np.clip(support_idx, 0, num_frames - 1) + frames.append(video[support_idx]) + + return frames diff --git a/mmpose/apis/inference_3d.py b/mmpose/apis/inference_3d.py new file mode 100644 index 0000000000..d5bb753945 --- /dev/null +++ b/mmpose/apis/inference_3d.py @@ -0,0 +1,339 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import numpy as np +import torch +from mmengine.dataset import Compose, pseudo_collate +from mmengine.registry import init_default_scope +from mmengine.structures import InstanceData + +from mmpose.structures import PoseDataSample + + +def convert_keypoint_definition(keypoints, pose_det_dataset, + pose_lift_dataset): + """Convert pose det dataset keypoints definition to pose lifter dataset + keypoints definition, so that they are compatible with the definitions + required for 3D pose lifting. + + Args: + keypoints (ndarray[N, K, 2 or 3]): 2D keypoints to be transformed. + pose_det_dataset, (str): Name of the dataset for 2D pose detector. + pose_lift_dataset (str): Name of the dataset for pose lifter model. + + Returns: + ndarray[K, 2 or 3]: the transformed 2D keypoints. + """ + assert pose_lift_dataset in [ + 'Human36mDataset'], '`pose_lift_dataset` should be ' \ + f'`Human36mDataset`, but got {pose_lift_dataset}.' + + coco_style_datasets = [ + 'CocoDataset', 'PoseTrack18VideoDataset', 'PoseTrack18Dataset' + ] + keypoints_new = np.zeros((keypoints.shape[0], 17, keypoints.shape[2]), + dtype=keypoints.dtype) + if pose_lift_dataset == 'Human36mDataset': + if pose_det_dataset in ['Human36mDataset']: + keypoints_new = keypoints + elif pose_det_dataset in coco_style_datasets: + # pelvis (root) is in the middle of l_hip and r_hip + keypoints_new[:, 0] = (keypoints[:, 11] + keypoints[:, 12]) / 2 + # thorax is in the middle of l_shoulder and r_shoulder + keypoints_new[:, 8] = (keypoints[:, 5] + keypoints[:, 6]) / 2 + # spine is in the middle of thorax and pelvis + keypoints_new[:, + 7] = (keypoints_new[:, 0] + keypoints_new[:, 8]) / 2 + # in COCO, head is in the middle of l_eye and r_eye + # in PoseTrack18, head is in the middle of head_bottom and head_top + keypoints_new[:, 10] = (keypoints[:, 1] + keypoints[:, 2]) / 2 + # rearrange other keypoints + keypoints_new[:, [1, 2, 3, 4, 5, 6, 9, 11, 12, 13, 14, 15, 16]] = \ + keypoints[:, [12, 14, 16, 11, 13, 15, 0, 5, 7, 9, 6, 8, 10]] + elif pose_det_dataset in ['AicDataset']: + # pelvis (root) is in the middle of l_hip and r_hip + keypoints_new[:, 0] = (keypoints[:, 9] + keypoints[:, 6]) / 2 + # thorax is in the middle of l_shoulder and r_shoulder + keypoints_new[:, 8] = (keypoints[:, 3] + keypoints[:, 0]) / 2 + # spine is in the middle of thorax and pelvis + keypoints_new[:, + 7] = (keypoints_new[:, 0] + keypoints_new[:, 8]) / 2 + # neck base (top end of neck) is 1/4 the way from + # neck (bottom end of neck) to head top + keypoints_new[:, 9] = (3 * keypoints[:, 13] + keypoints[:, 12]) / 4 + # head (spherical centre of head) is 7/12 the way from + # neck (bottom end of neck) to head top + keypoints_new[:, 10] = (5 * keypoints[:, 13] + + 7 * keypoints[:, 12]) / 12 + + keypoints_new[:, [1, 2, 3, 4, 5, 6, 11, 12, 13, 14, 15, 16]] = \ + keypoints[:, [6, 7, 8, 9, 10, 11, 3, 4, 5, 0, 1, 2]] + elif pose_det_dataset in ['CrowdPoseDataset']: + # pelvis (root) is in the middle of l_hip and r_hip + keypoints_new[:, 0] = (keypoints[:, 6] + keypoints[:, 7]) / 2 + # thorax is in the middle of l_shoulder and r_shoulder + keypoints_new[:, 8] = (keypoints[:, 0] + keypoints[:, 1]) / 2 + # spine is in the middle of thorax and pelvis + keypoints_new[:, + 7] = (keypoints_new[:, 0] + keypoints_new[:, 8]) / 2 + # neck base (top end of neck) is 1/4 the way from + # neck (bottom end of neck) to head top + keypoints_new[:, 9] = (3 * keypoints[:, 13] + keypoints[:, 12]) / 4 + # head (spherical centre of head) is 7/12 the way from + # neck (bottom end of neck) to head top + keypoints_new[:, 10] = (5 * keypoints[:, 13] + + 7 * keypoints[:, 12]) / 12 + + keypoints_new[:, [1, 2, 3, 4, 5, 6, 11, 12, 13, 14, 15, 16]] = \ + keypoints[:, [7, 9, 11, 6, 8, 10, 0, 2, 4, 1, 3, 5]] + else: + raise NotImplementedError( + f'unsupported conversion between {pose_lift_dataset} and ' + f'{pose_det_dataset}') + + return keypoints_new + + +def extract_pose_sequence(pose_results, frame_idx, causal, seq_len, step=1): + """Extract the target frame from 2D pose results, and pad the sequence to a + fixed length. + + Args: + pose_results (List[List[:obj:`PoseDataSample`]]): Multi-frame pose + detection results stored in a list. + frame_idx (int): The index of the frame in the original video. + causal (bool): If True, the target frame is the last frame in + a sequence. Otherwise, the target frame is in the middle of + a sequence. + seq_len (int): The number of frames in the input sequence. + step (int): Step size to extract frames from the video. + + Returns: + List[List[:obj:`PoseDataSample`]]: Multi-frame pose detection results + stored in a nested list with a length of seq_len. + """ + if causal: + frames_left = seq_len - 1 + frames_right = 0 + else: + frames_left = (seq_len - 1) // 2 + frames_right = frames_left + num_frames = len(pose_results) + + # get the padded sequence + pad_left = max(0, frames_left - frame_idx // step) + pad_right = max(0, frames_right - (num_frames - 1 - frame_idx) // step) + start = max(frame_idx % step, frame_idx - frames_left * step) + end = min(num_frames - (num_frames - 1 - frame_idx) % step, + frame_idx + frames_right * step + 1) + pose_results_seq = [pose_results[0]] * pad_left + \ + pose_results[start:end:step] + [pose_results[-1]] * pad_right + return pose_results_seq + + +def collate_pose_sequence(pose_results_2d, + with_track_id=True, + target_frame=-1): + """Reorganize multi-frame pose detection results into individual pose + sequences. + + Note: + - The temporal length of the pose detection results: T + - The number of the person instances: N + - The number of the keypoints: K + - The channel number of each keypoint: C + + Args: + pose_results_2d (List[List[:obj:`PoseDataSample`]]): Multi-frame pose + detection results stored in a nested list. Each element of the + outer list is the pose detection results of a single frame, and + each element of the inner list is the pose information of one + person, which contains: + + - keypoints (ndarray[K, 2 or 3]): x, y, [score] + - track_id (int): unique id of each person, required when + ``with_track_id==True``` + + with_track_id (bool): If True, the element in pose_results is expected + to contain "track_id", which will be used to gather the pose + sequence of a person from multiple frames. Otherwise, the pose + results in each frame are expected to have a consistent number and + order of identities. Default is True. + target_frame (int): The index of the target frame. Default: -1. + + Returns: + List[:obj:`PoseDataSample`]: Indivisual pose sequence in with length N. + """ + T = len(pose_results_2d) + assert T > 0 + + target_frame = (T + target_frame) % T # convert negative index to positive + + N = len( + pose_results_2d[target_frame]) # use identities in the target frame + if N == 0: + return [] + + B, K, C = pose_results_2d[target_frame][0].pred_instances.keypoints.shape + + track_ids = None + if with_track_id: + track_ids = [res.track_id for res in pose_results_2d[target_frame]] + + pose_sequences = [] + for idx in range(N): + pose_seq = PoseDataSample() + gt_instances = InstanceData() + pred_instances = InstanceData() + + for k in pose_results_2d[target_frame][idx].gt_instances.keys(): + gt_instances.set_field( + pose_results_2d[target_frame][idx].gt_instances[k], k) + for k in pose_results_2d[target_frame][idx].pred_instances.keys(): + if k != 'keypoints': + pred_instances.set_field( + pose_results_2d[target_frame][idx].pred_instances[k], k) + pose_seq.pred_instances = pred_instances + pose_seq.gt_instances = gt_instances + + if not with_track_id: + pose_seq.pred_instances.keypoints = np.stack([ + frame[idx].pred_instances.keypoints + for frame in pose_results_2d + ], + axis=1) + else: + keypoints = np.zeros((B, T, K, C), dtype=np.float32) + keypoints[:, target_frame] = pose_results_2d[target_frame][ + idx].pred_instances.keypoints + # find the left most frame containing track_ids[idx] + for frame_idx in range(target_frame - 1, -1, -1): + contains_idx = False + for res in pose_results_2d[frame_idx]: + if res.track_id == track_ids[idx]: + keypoints[:, frame_idx] = res.pred_instances.keypoints + contains_idx = True + break + if not contains_idx: + # replicate the left most frame + keypoints[:, :frame_idx + 1] = keypoints[:, frame_idx + 1] + break + # find the right most frame containing track_idx[idx] + for frame_idx in range(target_frame + 1, T): + contains_idx = False + for res in pose_results_2d[frame_idx]: + if res.track_id == track_ids[idx]: + keypoints[:, frame_idx] = res.pred_instances.keypoints + contains_idx = True + break + if not contains_idx: + # replicate the right most frame + keypoints[:, frame_idx + 1:] = keypoints[:, frame_idx] + break + pose_seq.pred_instances.keypoints = keypoints + pose_sequences.append(pose_seq) + + return pose_sequences + + +def inference_pose_lifter_model(model, + pose_results_2d, + with_track_id=True, + image_size=None, + norm_pose_2d=False): + """Inference 3D pose from 2D pose sequences using a pose lifter model. + + Args: + model (nn.Module): The loaded pose lifter model + pose_results_2d (List[List[:obj:`PoseDataSample`]]): The 2D pose + sequences stored in a nested list. + with_track_id: If True, the element in pose_results_2d is expected to + contain "track_id", which will be used to gather the pose sequence + of a person from multiple frames. Otherwise, the pose results in + each frame are expected to have a consistent number and order of + identities. Default is True. + image_size (tuple|list): image width, image height. If None, image size + will not be contained in dict ``data``. + norm_pose_2d (bool): If True, scale the bbox (along with the 2D + pose) to the average bbox scale of the dataset, and move the bbox + (along with the 2D pose) to the average bbox center of the dataset. + + Returns: + List[:obj:`PoseDataSample`]: 3D pose inference results. Specifically, + the predicted keypoints and scores are saved at + ``data_sample.pred_instances.keypoints_3d``. + """ + init_default_scope(model.cfg.get('default_scope', 'mmpose')) + pipeline = Compose(model.cfg.test_dataloader.dataset.pipeline) + + causal = model.cfg.test_dataloader.dataset.get('causal', False) + target_idx = -1 if causal else len(pose_results_2d) // 2 + + dataset_info = model.dataset_meta + if dataset_info is not None: + if 'stats_info' in dataset_info: + bbox_center = dataset_info['stats_info']['bbox_center'] + bbox_scale = dataset_info['stats_info']['bbox_scale'] + else: + bbox_center = None + bbox_scale = None + + for i, pose_res in enumerate(pose_results_2d): + for j, data_sample in enumerate(pose_res): + kpts = data_sample.pred_instances.keypoints + bboxes = data_sample.pred_instances.bboxes + keypoints = [] + for k in range(len(kpts)): + kpt = kpts[k] + if norm_pose_2d: + bbox = bboxes[k] + center = np.array([[(bbox[0] + bbox[2]) / 2, + (bbox[1] + bbox[3]) / 2]]) + scale = max(bbox[2] - bbox[0], bbox[3] - bbox[1]) + keypoints.append((kpt[:, :2] - center) / scale * + bbox_scale + bbox_center) + else: + keypoints.append(kpt[:, :2]) + pose_results_2d[i][j].pred_instances.keypoints = np.array( + keypoints) + + pose_sequences_2d = collate_pose_sequence(pose_results_2d, with_track_id, + target_idx) + + if not pose_sequences_2d: + return [] + + data_list = [] + for i, pose_seq in enumerate(pose_sequences_2d): + data_info = dict() + + keypoints_2d = pose_seq.pred_instances.keypoints + keypoints_2d = np.squeeze( + keypoints_2d, axis=0) if keypoints_2d.ndim == 4 else keypoints_2d + + T, K, C = keypoints_2d.shape + + data_info['keypoints'] = keypoints_2d + data_info['keypoints_visible'] = np.ones(( + T, + K, + ), dtype=np.float32) + data_info['lifting_target'] = np.zeros((K, 3), dtype=np.float32) + data_info['lifting_target_visible'] = np.ones((K, 1), dtype=np.float32) + + if image_size is not None: + assert len(image_size) == 2 + data_info['camera_param'] = dict(w=image_size[0], h=image_size[1]) + + data_info.update(model.dataset_meta) + data_list.append(pipeline(data_info)) + + if data_list: + # collate data list into a batch, which is a dict with following keys: + # batch['inputs']: a list of input images + # batch['data_samples']: a list of :obj:`PoseDataSample` + batch = pseudo_collate(data_list) + with torch.no_grad(): + results = model.test_step(batch) + else: + results = [] + + return results diff --git a/mmpose/apis/inference_tracking.py b/mmpose/apis/inference_tracking.py new file mode 100644 index 0000000000..c823adcfc7 --- /dev/null +++ b/mmpose/apis/inference_tracking.py @@ -0,0 +1,103 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import warnings + +import numpy as np + +from mmpose.evaluation.functional.nms import oks_iou + + +def _compute_iou(bboxA, bboxB): + """Compute the Intersection over Union (IoU) between two boxes . + + Args: + bboxA (list): The first bbox info (left, top, right, bottom, score). + bboxB (list): The second bbox info (left, top, right, bottom, score). + + Returns: + float: The IoU value. + """ + + x1 = max(bboxA[0], bboxB[0]) + y1 = max(bboxA[1], bboxB[1]) + x2 = min(bboxA[2], bboxB[2]) + y2 = min(bboxA[3], bboxB[3]) + + inter_area = max(0, x2 - x1) * max(0, y2 - y1) + + bboxA_area = (bboxA[2] - bboxA[0]) * (bboxA[3] - bboxA[1]) + bboxB_area = (bboxB[2] - bboxB[0]) * (bboxB[3] - bboxB[1]) + union_area = float(bboxA_area + bboxB_area - inter_area) + if union_area == 0: + union_area = 1e-5 + warnings.warn('union_area=0 is unexpected') + + iou = inter_area / union_area + + return iou + + +def _track_by_iou(res, results_last, thr): + """Get track id using IoU tracking greedily.""" + + bbox = list(np.squeeze(res.pred_instances.bboxes, axis=0)) + + max_iou_score = -1 + max_index = -1 + match_result = {} + for index, res_last in enumerate(results_last): + bbox_last = list(np.squeeze(res_last.pred_instances.bboxes, axis=0)) + + iou_score = _compute_iou(bbox, bbox_last) + if iou_score > max_iou_score: + max_iou_score = iou_score + max_index = index + + if max_iou_score > thr: + track_id = results_last[max_index].track_id + match_result = results_last[max_index] + del results_last[max_index] + else: + track_id = -1 + + return track_id, results_last, match_result + + +def _track_by_oks(res, results_last, thr, sigmas=None): + """Get track id using OKS tracking greedily.""" + keypoint = np.concatenate((res.pred_instances.keypoints, + res.pred_instances.keypoint_scores[:, :, None]), + axis=2) + keypoint = np.squeeze(keypoint, axis=0).reshape((-1)) + area = np.squeeze(res.pred_instances.areas, axis=0) + max_index = -1 + match_result = {} + + if len(results_last) == 0: + return -1, results_last, match_result + + keypoints_last = np.array([ + np.squeeze( + np.concatenate( + (res_last.pred_instances.keypoints, + res_last.pred_instances.keypoint_scores[:, :, None]), + axis=2), + axis=0).reshape((-1)) for res_last in results_last + ]) + area_last = np.array([ + np.squeeze(res_last.pred_instances.areas, axis=0) + for res_last in results_last + ]) + + oks_score = oks_iou( + keypoint, keypoints_last, area, area_last, sigmas=sigmas) + + max_index = np.argmax(oks_score) + + if oks_score[max_index] > thr: + track_id = results_last[max_index].track_id + match_result = results_last[max_index] + del results_last[max_index] + else: + track_id = -1 + + return track_id, results_last, match_result diff --git a/mmpose/apis/inferencers/__init__.py b/mmpose/apis/inferencers/__init__.py index 3db192da73..5955d79da9 100644 --- a/mmpose/apis/inferencers/__init__.py +++ b/mmpose/apis/inferencers/__init__.py @@ -1,6 +1,10 @@ # Copyright (c) OpenMMLab. All rights reserved. from .mmpose_inferencer import MMPoseInferencer from .pose2d_inferencer import Pose2DInferencer +from .pose3d_inferencer import Pose3DInferencer from .utils import get_model_aliases -__all__ = ['Pose2DInferencer', 'MMPoseInferencer', 'get_model_aliases'] +__all__ = [ + 'Pose2DInferencer', 'MMPoseInferencer', 'get_model_aliases', + 'Pose3DInferencer' +] diff --git a/mmpose/apis/inferencers/base_mmpose_inferencer.py b/mmpose/apis/inferencers/base_mmpose_inferencer.py index 29c9ae33fa..bed28b90d7 100644 --- a/mmpose/apis/inferencers/base_mmpose_inferencer.py +++ b/mmpose/apis/inferencers/base_mmpose_inferencer.py @@ -1,12 +1,10 @@ # Copyright (c) OpenMMLab. All rights reserved. import mimetypes import os -import shutil -import tempfile import warnings from collections import defaultdict -from typing import (Any, Callable, Dict, Generator, List, Optional, Sequence, - Union) +from typing import (Callable, Dict, Generator, Iterable, List, Optional, + Sequence, Union) import cv2 import mmcv @@ -18,8 +16,10 @@ from mmengine.fileio import (get_file_backend, isdir, join_path, list_dir_or_file) from mmengine.infer.infer import BaseInferencer +from mmengine.registry import init_default_scope from mmengine.runner.checkpoint import _load_checkpoint_to_model from mmengine.structures import InstanceData +from mmengine.utils import mkdir_or_exist from mmpose.apis.inference import dataset_meta_from_config from mmpose.structures import PoseDataSample, split_instances @@ -36,17 +36,11 @@ class BaseMMPoseInferencer(BaseInferencer): """The base class for MMPose inferencers.""" - preprocess_kwargs: set = {'bbox_thr', 'nms_thr'} + preprocess_kwargs: set = {'bbox_thr', 'nms_thr', 'bboxes'} forward_kwargs: set = set() visualize_kwargs: set = { - 'return_vis', - 'show', - 'wait_time', - 'draw_bbox', - 'radius', - 'thickness', - 'kpt_thr', - 'vis_out_dir', + 'return_vis', 'show', 'wait_time', 'draw_bbox', 'radius', 'thickness', + 'kpt_thr', 'vis_out_dir', 'black_background' } postprocess_kwargs: set = {'pred_out_dir'} @@ -83,7 +77,7 @@ def _load_weights_to_model(self, model: nn.Module, model.dataset_meta = dataset_meta_from_config( cfg, dataset_mode='train') - def _inputs_to_list(self, inputs: InputsType) -> list: + def _inputs_to_list(self, inputs: InputsType) -> Iterable: """Preprocess the inputs to a list. Preprocess inputs to a list according to its type: @@ -126,21 +120,26 @@ def _inputs_to_list(self, inputs: InputsType) -> list: input_type = mimetypes.guess_type(inputs)[0].split('/')[0] if input_type == 'video': self._video_input = True - # split video frames into a temporary folder - frame_folder = tempfile.TemporaryDirectory() video = mmcv.VideoReader(inputs) self.video_info = dict( fps=video.fps, name=os.path.basename(inputs), - frame_folder=frame_folder) - video.cvt2frames(frame_folder.name, show_progress=False) - frames = sorted(list_dir_or_file(frame_folder.name)) - inputs = [join_path(frame_folder.name, f) for f in frames] + writer=None, + width=video.width, + height=video.height, + predictions=[]) + inputs = video + elif input_type == 'image': + inputs = [inputs] + else: + raise ValueError(f'Expected input to be an image, video, ' + f'or folder, but received {inputs} of ' + f'type {input_type}.') - if not isinstance(inputs, (list, tuple)): + elif isinstance(inputs, np.ndarray): inputs = [inputs] - return list(inputs) + return inputs def _get_webcam_inputs(self, inputs: str) -> Generator: """Sets up and returns a generator function that reads frames from a @@ -182,14 +181,26 @@ def _get_webcam_inputs(self, inputs: str) -> Generator: # Set video input flag and metadata. self._video_input = True - self.video_info = dict(fps=10, name='webcam.mp4', frame_folder=None) - - # Set up webcam reader generator function. - self._window_closing = False + (major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.') + if int(major_ver) < 3: + fps = vcap.get(cv2.cv.CV_CAP_PROP_FPS) + width = vcap.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH) + height = vcap.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT) + else: + fps = vcap.get(cv2.CAP_PROP_FPS) + width = vcap.get(cv2.CAP_PROP_FRAME_WIDTH) + height = vcap.get(cv2.CAP_PROP_FRAME_HEIGHT) + self.video_info = dict( + fps=fps, + name='webcam.mp4', + writer=None, + width=width, + height=height, + predictions=[]) def _webcam_reader() -> Generator: while True: - if self._window_closing: + if cv2.waitKey(5) & 0xFF == 27: vcap.release() break @@ -201,9 +212,6 @@ def _webcam_reader() -> Generator: return _webcam_reader() - def _visualization_window_on_close(self, event): - self._window_closing = True - def _init_pipeline(self, cfg: ConfigType) -> Callable: """Initialize the test pipeline. @@ -215,9 +223,22 @@ def _init_pipeline(self, cfg: ConfigType) -> Callable: ``np.ndarray``. The returned pipeline will be used to process a single data. """ + scope = cfg.get('default_scope', 'mmpose') + if scope is not None: + init_default_scope(scope) return Compose(cfg.test_dataloader.dataset.pipeline) - def preprocess(self, inputs: InputsType, batch_size: int = 1, **kwargs): + def update_model_visualizer_settings(self, **kwargs): + """Update the settings of models and visualizer according to inference + arguments.""" + + pass + + def preprocess(self, + inputs: InputsType, + batch_size: int = 1, + bboxes: Optional[List] = None, + **kwargs): """Process the inputs into a model-feedable format. Args: @@ -230,7 +251,9 @@ def preprocess(self, inputs: InputsType, batch_size: int = 1, **kwargs): """ for i, input in enumerate(inputs): - data_infos = self.preprocess_single(input, index=i, **kwargs) + bbox = bboxes[i] if bboxes else [] + data_infos = self.preprocess_single( + input, index=i, bboxes=bbox, **kwargs) # only supports inference with batch size 1 yield self.collate_fn(data_infos), [input] @@ -246,8 +269,8 @@ def visualize(self, kpt_thr: float = 0.3, vis_out_dir: str = '', window_name: str = '', - window_close_event_handler: Optional[Callable] = None - ) -> List[np.ndarray]: + black_background: bool = False, + **kwargs) -> List[np.ndarray]: """Visualize predictions. Args: @@ -267,7 +290,8 @@ def visualize(self, results w/o predictions. If left as empty, no file will be saved. Defaults to ''. window_name (str, optional): Title of display window. - window_close_event_handler (callable, optional): + black_background (bool, optional): Whether to plot keypoints on a + black image instead of the input image. Defaults to False. Returns: List[np.ndarray]: Visualization results. @@ -288,28 +312,21 @@ def visualize(self, if isinstance(single_input, str): img = mmcv.imread(single_input, channel_order='rgb') elif isinstance(single_input, np.ndarray): - img = mmcv.bgr2rgb(single_input.copy()) + img = mmcv.bgr2rgb(single_input) else: raise ValueError('Unsupported input type: ' f'{type(single_input)}') + if black_background: + img = img * 0 img_name = os.path.basename(pred.metainfo['img_path']) - - if vis_out_dir: - if self._video_input: - out_file = join_path(vis_out_dir, 'vis_frames', img_name) - else: - out_file = join_path(vis_out_dir, img_name) - else: - out_file = None + window_name = window_name if window_name else img_name # since visualization and inference utilize the same process, # the wait time is reduced when a video input is utilized, # thereby eliminating the issue of inference getting stuck. wait_time = 1e-5 if self._video_input else wait_time - window_name = window_name if window_name else img_name - visualization = self.visualizer.add_datasample( window_name, img, @@ -318,19 +335,38 @@ def visualize(self, draw_bbox=draw_bbox, show=show, wait_time=wait_time, - out_file=out_file, - kpt_thr=kpt_thr) + kpt_thr=kpt_thr, + **kwargs) results.append(visualization) - if show and not hasattr(self, '_window_close_cid'): - if window_close_event_handler is None: - window_close_event_handler = \ - self._visualization_window_on_close - self._window_close_cid = \ - self.visualizer.manager.canvas.mpl_connect( - 'close_event', - window_close_event_handler - ) + if vis_out_dir: + out_img = mmcv.rgb2bgr(visualization) + _, file_extension = os.path.splitext(vis_out_dir) + if file_extension: + dir_name = os.path.dirname(vis_out_dir) + file_name = os.path.basename(vis_out_dir) + else: + dir_name = vis_out_dir + file_name = None + mkdir_or_exist(dir_name) + + if self._video_input: + + if self.video_info['writer'] is None: + fourcc = cv2.VideoWriter_fourcc(*'mp4v') + if file_name is None: + file_name = os.path.basename( + self.video_info['name']) + out_file = join_path(dir_name, file_name) + self.video_info['writer'] = cv2.VideoWriter( + out_file, fourcc, self.video_info['fps'], + (visualization.shape[1], visualization.shape[0])) + self.video_info['writer'].write(out_img) + + else: + file_name = file_name if file_name else img_name + out_file = join_path(dir_name, file_name) + mmcv.imwrite(out_img, out_file) if return_vis: return results @@ -384,66 +420,50 @@ def postprocess( result_dict['predictions'].append(pred) if pred_out_dir != '': - if self._video_input: - pred_out_dir = join_path(pred_out_dir, 'pred_frames') - for pred, data_sample in zip(result_dict['predictions'], preds): - fname = os.path.splitext( - os.path.basename( - data_sample.metainfo['img_path']))[0] + '.json' - mmengine.dump( - pred, join_path(pred_out_dir, fname), indent=' ') + if self._video_input: + # For video or webcam input, predictions for each frame + # are gathered in the 'predictions' key of 'video_info' + # dictionary. All frame predictions are then stored into + # a single file after processing all frames. + self.video_info['predictions'].append(pred) + else: + # For non-video inputs, predictions are stored in separate + # JSON files. The filename is determined by the basename + # of the input image path with a '.json' extension. The + # predictions are then dumped into this file. + fname = os.path.splitext( + os.path.basename( + data_sample.metainfo['img_path']))[0] + '.json' + mmengine.dump( + pred, join_path(pred_out_dir, fname), indent=' ') return result_dict - def _merge_outputs(self, vis_out_dir: str, pred_out_dir: str, - **kwargs: Dict[str, Any]) -> None: - """Merge the visualized frames and predicted instance outputs and save - them. + def _finalize_video_processing( + self, + pred_out_dir: str = '', + ): + """Finalize video processing by releasing the video writer and saving + predictions to a file. - Args: - vis_out_dir (str): Path to the directory where the visualized - frames are saved. - pred_out_dir (str): Path to the directory where the predicted - instance outputs are saved. - **kwargs: Other arguments that are not used in this method. + This method should be called after completing the video processing. It + releases the video writer, if it exists, and saves the predictions to a + JSON file if a prediction output directory is provided. """ - assert self._video_input - - if vis_out_dir != '': - vis_frame_out_dir = join_path(vis_out_dir, 'vis_frames') - if not isdir(vis_frame_out_dir) or len( - os.listdir(vis_frame_out_dir)) == 0: - warnings.warn( - f'{vis_frame_out_dir} does not exist or is empty.') - else: - mmcv.frames2video( - vis_frame_out_dir, - join_path(vis_out_dir, self.video_info['name']), - fps=self.video_info['fps'], - fourcc='mp4v', - show_progress=False) - shutil.rmtree(vis_frame_out_dir) - if pred_out_dir != '': - pred_frame_out_dir = join_path(pred_out_dir, 'pred_frames') - if not isdir(pred_frame_out_dir) or len( - os.listdir(pred_frame_out_dir)) == 0: - warnings.warn( - f'{pred_frame_out_dir} does not exist or is empty.') - else: - predictions = [] - pred_files = list_dir_or_file(pred_frame_out_dir) - for frame_id, pred_file in enumerate(sorted(pred_files)): - predictions.append({ - 'frame_id': - frame_id, - 'instances': - mmengine.load( - join_path(pred_frame_out_dir, pred_file)) - }) - fname = os.path.splitext( - os.path.basename(self.video_info['name']))[0] + '.json' - mmengine.dump( - predictions, join_path(pred_out_dir, fname), indent=' ') - shutil.rmtree(pred_frame_out_dir) + # Release the video writer if it exists + if self.video_info['writer'] is not None: + self.video_info['writer'].release() + + # Save predictions + if pred_out_dir: + fname = os.path.splitext( + os.path.basename(self.video_info['name']))[0] + '.json' + predictions = [ + dict(frame_id=i, instances=pred) + for i, pred in enumerate(self.video_info['predictions']) + ] + + mmengine.dump( + predictions, join_path(pred_out_dir, fname), indent=' ') diff --git a/mmpose/apis/inferencers/mmpose_inferencer.py b/mmpose/apis/inferencers/mmpose_inferencer.py index ab0aeb9618..b44361bba8 100644 --- a/mmpose/apis/inferencers/mmpose_inferencer.py +++ b/mmpose/apis/inferencers/mmpose_inferencer.py @@ -5,14 +5,12 @@ import numpy as np import torch from mmengine.config import Config, ConfigDict -from mmengine.fileio import join_path from mmengine.infer.infer import ModelType from mmengine.structures import InstanceData -from rich.progress import track -from mmpose.structures import PoseDataSample from .base_mmpose_inferencer import BaseMMPoseInferencer from .pose2d_inferencer import Pose2DInferencer +from .pose3d_inferencer import Pose3DInferencer InstanceList = List[InstanceData] InputType = Union[str, np.ndarray] @@ -51,40 +49,47 @@ class MMPoseInferencer(BaseMMPoseInferencer): model. Defaults to None. det_cat_ids(int or list[int], optional): Category id for detection model. Defaults to None. + output_heatmaps (bool, optional): Flag to visualize predicted + heatmaps. If set to None, the default setting from the model + config will be used. Default is None. """ - preprocess_kwargs: set = {'bbox_thr', 'nms_thr'} - forward_kwargs: set = set() + preprocess_kwargs: set = { + 'bbox_thr', 'nms_thr', 'bboxes', 'use_oks_tracking', 'tracking_thr', + 'norm_pose_2d' + } + forward_kwargs: set = {'rebase_keypoint_height'} visualize_kwargs: set = { - 'return_vis', - 'show', - 'wait_time', - 'draw_bbox', - 'radius', - 'thickness', - 'kpt_thr', - 'vis_out_dir', + 'return_vis', 'show', 'wait_time', 'draw_bbox', 'radius', 'thickness', + 'kpt_thr', 'vis_out_dir', 'skeleton_style', 'draw_heatmap', + 'black_background' } postprocess_kwargs: set = {'pred_out_dir'} def __init__(self, pose2d: Optional[str] = None, pose2d_weights: Optional[str] = None, + pose3d: Optional[str] = None, + pose3d_weights: Optional[str] = None, device: Optional[str] = None, scope: str = 'mmpose', det_model: Optional[Union[ModelType, str]] = None, det_weights: Optional[str] = None, det_cat_ids: Optional[Union[int, List]] = None) -> None: - if pose2d is None: - raise ValueError('2d pose estimation algorithm should provided.') - self.visualizer = None - if pose2d is not None: - self.pose2d_inferencer = Pose2DInferencer(pose2d, pose2d_weights, - device, scope, det_model, - det_weights, det_cat_ids) - self.mode = 'pose2d' + if pose3d is not None: + self.inferencer = Pose3DInferencer(pose3d, pose3d_weights, pose2d, + pose2d_weights, device, scope, + det_model, det_weights, + det_cat_ids) + elif pose2d is not None: + self.inferencer = Pose2DInferencer(pose2d, pose2d_weights, device, + scope, det_model, det_weights, + det_cat_ids) + else: + raise ValueError('Either 2d or 3d pose estimation algorithm ' + 'should be provided.') def preprocess(self, inputs: InputsType, batch_size: int = 1, **kwargs): """Process the inputs into a model-feedable format. @@ -100,11 +105,9 @@ def preprocess(self, inputs: InputsType, batch_size: int = 1, **kwargs): for i, input in enumerate(inputs): data_batch = {} - if 'pose2d' in self.mode: - data_infos = self.pose2d_inferencer.preprocess_single( - input, index=i, **kwargs) - data_batch['pose2d'] = self.pose2d_inferencer.collate_fn( - data_infos) + data_infos = self.inferencer.preprocess_single( + input, index=i, **kwargs) + data_batch = self.inferencer.collate_fn(data_infos) # only supports inference with batch size 1 yield data_batch, [input] @@ -118,13 +121,7 @@ def forward(self, inputs: InputType, **forward_kwargs) -> PredType: Returns: Dict: The prediction results. Possibly with keys "pose2d". """ - result = {} - if self.mode == 'pose2d': - data_samples = self.pose2d_inferencer.forward( - inputs['pose2d'], **forward_kwargs) - result['pose2d'] = data_samples - - return result + return self.inferencer.forward(inputs, **forward_kwargs) def __call__( self, @@ -158,6 +155,15 @@ def __call__( kwargs['vis_out_dir'] = f'{out_dir}/visualizations' if 'pred_out_dir' not in kwargs: kwargs['pred_out_dir'] = f'{out_dir}/predictions' + + kwargs = { + key: value + for key, value in kwargs.items() + if key in set.union(self.inferencer.preprocess_kwargs, + self.inferencer.forward_kwargs, + self.inferencer.visualize_kwargs, + self.inferencer.postprocess_kwargs) + } ( preprocess_kwargs, forward_kwargs, @@ -165,26 +171,30 @@ def __call__( postprocess_kwargs, ) = self._dispatch_kwargs(**kwargs) + self.inferencer.update_model_visualizer_settings(**kwargs) + # preprocessing if isinstance(inputs, str) and inputs.startswith('webcam'): - inputs = self._get_webcam_inputs(inputs) + inputs = self.inferencer._get_webcam_inputs(inputs) batch_size = 1 if not visualize_kwargs.get('show', False): warnings.warn('The display mode is closed when using webcam ' 'input. It will be turned on automatically.') visualize_kwargs['show'] = True else: - inputs = self._inputs_to_list(inputs) + inputs = self.inferencer._inputs_to_list(inputs) + self._video_input = self.inferencer._video_input + if self._video_input: + self.video_info = self.inferencer.video_info inputs = self.preprocess( inputs, batch_size=batch_size, **preprocess_kwargs) - forward_kwargs['bbox_thr'] = preprocess_kwargs.get('bbox_thr', -1) + # forward + if 'bbox_thr' in self.inferencer.forward_kwargs: + forward_kwargs['bbox_thr'] = preprocess_kwargs.get('bbox_thr', -1) preds = [] - if 'pose2d' not in self.mode or not hasattr(self.pose2d_inferencer, - 'detector'): - inputs = track(inputs, description='Inference') for proc_inputs, ori_inputs in inputs: preds = self.forward(proc_inputs, **forward_kwargs) @@ -195,9 +205,9 @@ def __call__( **postprocess_kwargs) yield results - # merge visualization and prediction results if self._video_input: - self._merge_outputs(**visualize_kwargs, **postprocess_kwargs) + self._finalize_video_processing( + postprocess_kwargs.get('pred_out_dir', '')) def visualize(self, inputs: InputsType, preds: PredType, **kwargs) -> List[np.ndarray]: @@ -221,60 +231,9 @@ def visualize(self, inputs: InputsType, preds: PredType, Returns: List[np.ndarray]: Visualization results. """ + window_name = '' + if self.inferencer._video_input: + window_name = self.inferencer.video_info['name'] - if 'pose2d' in self.mode: - window_name = '' - if self._video_input: - window_name = self.video_info['name'] - if kwargs.get('vis_out_dir', ''): - kwargs['vis_out_dir'] = join_path(kwargs['vis_out_dir'], - 'vis_frames') - if kwargs.get('show', False): - kwargs['wait_time'] = 1e-5 - return self.pose2d_inferencer.visualize( - inputs, - preds['pose2d'], - window_name=window_name, - window_close_event_handler=self._visualization_window_on_close, - **kwargs) - - def postprocess( - self, - preds: List[PoseDataSample], - visualization: List[np.ndarray], - return_datasample=False, - pred_out_dir: str = '', - ) -> dict: - """Process the predictions and visualization results from ``forward`` - and ``visualize``. - - This method should be responsible for the following tasks: - - 1. Convert datasamples into a json-serializable dict if needed. - 2. Pack the predictions and visualization results and return them. - 3. Dump or log the predictions. - - Args: - preds (List[Dict]): Predictions of the model. - visualization (np.ndarray): Visualized predictions. - return_datasample (bool): Whether to return results as - datasamples. Defaults to False. - pred_out_dir (str): Directory to save the inference results w/o - visualization. If left as empty, no file will be saved. - Defaults to ''. - - Returns: - dict: Inference and visualization results with key ``predictions`` - and ``visualization`` - - - ``visualization (Any)``: Returned by :meth:`visualize` - - ``predictions`` (dict or DataSample): Returned by - :meth:`forward` and processed in :meth:`postprocess`. - If ``return_datasample=False``, it usually should be a - json-serializable dict containing only basic data elements such - as strings and numbers. - """ - - if 'pose2d' in self.mode: - return super().postprocess(preds['pose2d'], visualization, - return_datasample, pred_out_dir) + return self.inferencer.visualize( + inputs, preds, window_name=window_name, **kwargs) diff --git a/mmpose/apis/inferencers/pose2d_inferencer.py b/mmpose/apis/inferencers/pose2d_inferencer.py index 63244b1f95..3f1f20fdc0 100644 --- a/mmpose/apis/inferencers/pose2d_inferencer.py +++ b/mmpose/apis/inferencers/pose2d_inferencer.py @@ -11,7 +11,6 @@ from mmengine.model import revert_sync_batchnorm from mmengine.registry import init_default_scope from mmengine.structures import InstanceData -from rich.progress import track from mmpose.evaluation.functional import nms from mmpose.registry import DATASETS, INFERENCERS @@ -55,16 +54,16 @@ class Pose2DInferencer(BaseMMPoseInferencer): device (str, optional): Device to run inference. If None, the available device will be automatically used. Defaults to None. scope (str, optional): The scope of the model. Defaults to "mmpose". - det_model(str, optional): Config path or alias of detection model. + det_model (str, optional): Config path or alias of detection model. Defaults to None. - det_weights(str, optional): Path to the checkpoints of detection + det_weights (str, optional): Path to the checkpoints of detection model. Defaults to None. - det_cat_ids(int or list[int], optional): Category id for + det_cat_ids (int or list[int], optional): Category id for detection model. Defaults to None. """ - preprocess_kwargs: set = {'bbox_thr', 'nms_thr'} - forward_kwargs: set = set() + preprocess_kwargs: set = {'bbox_thr', 'nms_thr', 'bboxes'} + forward_kwargs: set = {'merge_results'} visualize_kwargs: set = { 'return_vis', 'show', @@ -74,6 +73,9 @@ class Pose2DInferencer(BaseMMPoseInferencer): 'thickness', 'kpt_thr', 'vis_out_dir', + 'skeleton_style', + 'draw_heatmap', + 'black_background', } postprocess_kwargs: set = {'pred_out_dir'} @@ -96,40 +98,69 @@ def __init__(self, # initialize detector for top-down models if self.cfg.data_mode == 'topdown': - det_scope = 'mmdet' - if det_model is None: - det_model = DATASETS.get( - self.cfg.dataset_type).__module__.split( - 'datasets.')[-1].split('.')[0].lower() - det_info = default_det_models[det_model] - det_model, det_weights, det_cat_ids = det_info[ - 'model'], det_info['weights'], det_info['cat_ids'] - elif os.path.exists(det_model): - det_cfg = Config.fromfile(det_model) - det_scope = det_cfg.default_scope - - if has_mmdet: - self.detector = DetInferencer( - det_model, det_weights, device=device, scope=det_scope) - self.detector.model = revert_sync_batchnorm( - self.detector.model) - else: - raise RuntimeError( - 'MMDetection (v3.0.0rc6 or above) is required to ' - 'build inferencers for top-down pose estimation models.') + object_type = DATASETS.get(self.cfg.dataset_type).__module__.split( + 'datasets.')[-1].split('.')[0].lower() + + if det_model in ('whole_image', 'whole-image') or \ + (det_model is None and + object_type not in default_det_models): + self.detector = None - if isinstance(det_cat_ids, (tuple, list)): - self.det_cat_ids = det_cat_ids else: - self.det_cat_ids = (det_cat_ids, ) + det_scope = 'mmdet' + if det_model is None: + det_info = default_det_models[object_type] + det_model, det_weights, det_cat_ids = det_info[ + 'model'], det_info['weights'], det_info['cat_ids'] + elif os.path.exists(det_model): + det_cfg = Config.fromfile(det_model) + det_scope = det_cfg.default_scope + + if has_mmdet: + self.detector = DetInferencer( + det_model, det_weights, device=device, scope=det_scope) + else: + raise RuntimeError( + 'MMDetection (v3.0.0 or above) is required to build ' + 'inferencers for top-down pose estimation models.') + + if isinstance(det_cat_ids, (tuple, list)): + self.det_cat_ids = det_cat_ids + else: + self.det_cat_ids = (det_cat_ids, ) self._video_input = False + def update_model_visualizer_settings(self, + draw_heatmap: bool = False, + skeleton_style: str = 'mmpose', + **kwargs) -> None: + """Update the settings of models and visualizer according to inference + arguments. + + Args: + draw_heatmaps (bool, optional): Flag to visualize predicted + heatmaps. If not provided, it defaults to False. + skeleton_style (str, optional): Skeleton style selection. Valid + options are 'mmpose' and 'openpose'. Defaults to 'mmpose'. + """ + self.model.test_cfg['output_heatmaps'] = draw_heatmap + + if skeleton_style not in ['mmpose', 'openpose']: + raise ValueError('`skeleton_style` must be either \'mmpose\' ' + 'or \'openpose\'') + + if skeleton_style == 'openpose': + self.visualizer.set_dataset_meta(self.model.dataset_meta, + skeleton_style) + def preprocess_single(self, input: InputType, index: int, bbox_thr: float = 0.3, - nms_thr: float = 0.3): + nms_thr: float = 0.3, + bboxes: Union[List[List], List[np.ndarray], + np.ndarray] = []): """Process a single input into a model-feedable format. Args: @@ -151,20 +182,22 @@ def preprocess_single(self, data_info.update(self.model.dataset_meta) if self.cfg.data_mode == 'topdown': - det_results = self.detector( - input, return_datasample=True)['predictions'] - pred_instance = det_results[0].pred_instances.cpu().numpy() - bboxes = np.concatenate( - (pred_instance.bboxes, pred_instance.scores[:, None]), axis=1) - - label_mask = np.zeros(len(bboxes), dtype=np.uint8) - for cat_id in self.det_cat_ids: - label_mask = np.logical_or(label_mask, - pred_instance.labels == cat_id) - - bboxes = bboxes[np.logical_and(label_mask, - pred_instance.scores > bbox_thr)] - bboxes = bboxes[nms(bboxes, nms_thr)] + if self.detector is not None: + det_results = self.detector( + input, return_datasample=True)['predictions'] + pred_instance = det_results[0].pred_instances.cpu().numpy() + bboxes = np.concatenate( + (pred_instance.bboxes, pred_instance.scores[:, None]), + axis=1) + + label_mask = np.zeros(len(bboxes), dtype=np.uint8) + for cat_id in self.det_cat_ids: + label_mask = np.logical_or(label_mask, + pred_instance.labels == cat_id) + + bboxes = bboxes[np.logical_and( + label_mask, pred_instance.scores > bbox_thr)] + bboxes = bboxes[nms(bboxes, nms_thr)] data_infos = [] if len(bboxes) > 0: @@ -191,9 +224,28 @@ def preprocess_single(self, return data_infos @torch.no_grad() - def forward(self, inputs: Union[dict, tuple], bbox_thr=-1): - data_samples = super().forward(inputs) - if self.cfg.data_mode == 'topdown': + def forward(self, + inputs: Union[dict, tuple], + merge_results: bool = True, + bbox_thr: float = -1): + """Performs a forward pass through the model. + + Args: + inputs (Union[dict, tuple]): The input data to be processed. Can + be either a dictionary or a tuple. + merge_results (bool, optional): Whether to merge data samples, + default to True. This is only applicable when the data_mode + is 'topdown'. + bbox_thr (float, optional): A threshold for the bounding box + scores. Bounding boxes with scores greater than this value + will be retained. Default value is -1 which retains all + bounding boxes. + + Returns: + A list of data samples with prediction instances. + """ + data_samples = self.model.test_step(inputs) + if self.cfg.data_mode == 'topdown' and merge_results: data_samples = [merge_data_samples(data_samples)] if bbox_thr > 0: for ds in data_samples: @@ -242,6 +294,8 @@ def __call__( postprocess_kwargs, ) = self._dispatch_kwargs(**kwargs) + self.update_model_visualizer_settings(**kwargs) + # preprocessing if isinstance(inputs, str) and inputs.startswith('webcam'): inputs = self._get_webcam_inputs(inputs) @@ -258,8 +312,6 @@ def __call__( inputs, batch_size=batch_size, **preprocess_kwargs) preds = [] - if not hasattr(self, 'detector'): - inputs = track(inputs, description='Inference') for proc_inputs, ori_inputs in inputs: preds = self.forward(proc_inputs, **forward_kwargs) @@ -270,6 +322,6 @@ def __call__( **postprocess_kwargs) yield results - # merge visualization and prediction results if self._video_input: - self._merge_outputs(**visualize_kwargs, **postprocess_kwargs) + self._finalize_video_processing( + postprocess_kwargs.get('pred_out_dir', '')) diff --git a/mmpose/apis/inferencers/pose3d_inferencer.py b/mmpose/apis/inferencers/pose3d_inferencer.py new file mode 100644 index 0000000000..0fe66ac72b --- /dev/null +++ b/mmpose/apis/inferencers/pose3d_inferencer.py @@ -0,0 +1,518 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import warnings +from collections import defaultdict +from functools import partial +from typing import Callable, Dict, List, Optional, Sequence, Tuple, Union + +import cv2 +import mmcv +import numpy as np +import torch +from mmengine.config import Config, ConfigDict +from mmengine.fileio import join_path +from mmengine.infer.infer import ModelType +from mmengine.model import revert_sync_batchnorm +from mmengine.registry import init_default_scope +from mmengine.structures import InstanceData +from mmengine.utils import mkdir_or_exist + +from mmpose.apis import (_track_by_iou, _track_by_oks, collate_pose_sequence, + convert_keypoint_definition, extract_pose_sequence) +from mmpose.registry import INFERENCERS +from mmpose.structures import PoseDataSample, merge_data_samples +from .base_mmpose_inferencer import BaseMMPoseInferencer +from .pose2d_inferencer import Pose2DInferencer + +InstanceList = List[InstanceData] +InputType = Union[str, np.ndarray] +InputsType = Union[InputType, Sequence[InputType]] +PredType = Union[InstanceData, InstanceList] +ImgType = Union[np.ndarray, Sequence[np.ndarray]] +ConfigType = Union[Config, ConfigDict] +ResType = Union[Dict, List[Dict], InstanceData, List[InstanceData]] + + +@INFERENCERS.register_module(name='pose-estimation-3d') +@INFERENCERS.register_module() +class Pose3DInferencer(BaseMMPoseInferencer): + """The inferencer for 3D pose estimation. + + Args: + model (str, optional): Pretrained 2D pose estimation algorithm. + It's the path to the config file or the model name defined in + metafile. For example, it could be: + + - model alias, e.g. ``'body'``, + - config name, e.g. ``'simcc_res50_8xb64-210e_coco-256x192'``, + - config path + + Defaults to ``None``. + weights (str, optional): Path to the checkpoint. If it is not + specified and "model" is a model name of metafile, the weights + will be loaded from metafile. Defaults to None. + device (str, optional): Device to run inference. If None, the + available device will be automatically used. Defaults to None. + scope (str, optional): The scope of the model. Defaults to "mmpose". + det_model (str, optional): Config path or alias of detection model. + Defaults to None. + det_weights (str, optional): Path to the checkpoints of detection + model. Defaults to None. + det_cat_ids (int or list[int], optional): Category id for + detection model. Defaults to None. + output_heatmaps (bool, optional): Flag to visualize predicted + heatmaps. If set to None, the default setting from the model + config will be used. Default is None. + """ + + preprocess_kwargs: set = { + 'bbox_thr', 'nms_thr', 'bboxes', 'use_oks_tracking', 'tracking_thr', + 'norm_pose_2d' + } + forward_kwargs: set = {'rebase_keypoint_height'} + visualize_kwargs: set = { + 'return_vis', + 'show', + 'wait_time', + 'draw_bbox', + 'radius', + 'thickness', + 'kpt_thr', + 'vis_out_dir', + } + postprocess_kwargs: set = {'pred_out_dir'} + + def __init__(self, + model: Union[ModelType, str], + weights: Optional[str] = None, + pose2d_model: Optional[Union[ModelType, str]] = None, + pose2d_weights: Optional[str] = None, + device: Optional[str] = None, + scope: Optional[str] = 'mmpose', + det_model: Optional[Union[ModelType, str]] = None, + det_weights: Optional[str] = None, + det_cat_ids: Optional[Union[int, Tuple]] = None) -> None: + + init_default_scope(scope) + super().__init__( + model=model, weights=weights, device=device, scope=scope) + self.model = revert_sync_batchnorm(self.model) + + # assign dataset metainfo to self.visualizer + self.visualizer.set_dataset_meta(self.model.dataset_meta) + + # initialize 2d pose estimator + self.pose2d_model = Pose2DInferencer( + pose2d_model if pose2d_model else 'human', pose2d_weights, device, + scope, det_model, det_weights, det_cat_ids) + + # helper functions + self._keypoint_converter = partial( + convert_keypoint_definition, + pose_det_dataset=self.pose2d_model.cfg.test_dataloader. + dataset['type'], + pose_lift_dataset=self.cfg.test_dataloader.dataset['type'], + ) + + self._pose_seq_extractor = partial( + extract_pose_sequence, + causal=self.cfg.test_dataloader.dataset.get('causal', False), + seq_len=self.cfg.test_dataloader.dataset.get('seq_len', 1), + step=self.cfg.test_dataloader.dataset.get('seq_step', 1)) + + self._video_input = False + self._buffer = defaultdict(list) + + def preprocess_single(self, + input: InputType, + index: int, + bbox_thr: float = 0.3, + nms_thr: float = 0.3, + bboxes: Union[List[List], List[np.ndarray], + np.ndarray] = [], + use_oks_tracking: bool = False, + tracking_thr: float = 0.3, + norm_pose_2d: bool = False): + """Process a single input into a model-feedable format. + + Args: + input (InputType): The input provided by the user. + index (int): The index of the input. + bbox_thr (float, optional): The threshold for bounding box + detection. Defaults to 0.3. + nms_thr (float, optional): The Intersection over Union (IoU) + threshold for bounding box Non-Maximum Suppression (NMS). + Defaults to 0.3. + bboxes (Union[List[List], List[np.ndarray], np.ndarray]): + The bounding boxes to use. Defaults to []. + use_oks_tracking (bool, optional): A flag that indicates + whether OKS-based tracking should be used. Defaults to False. + tracking_thr (float, optional): The threshold for tracking. + Defaults to 0.3. + norm_pose_2d (bool, optional): A flag that indicates whether 2D + pose normalization should be used. Defaults to False. + + Yields: + Any: The data processed by the pipeline and collate_fn. + + This method first calculates 2D keypoints using the provided + pose2d_model. The method also performs instance matching, which + can use either OKS-based tracking or IOU-based tracking. + """ + + # calculate 2d keypoints + results_pose2d = next( + self.pose2d_model( + input, + bbox_thr=bbox_thr, + nms_thr=nms_thr, + bboxes=bboxes, + merge_results=False, + return_datasample=True))['predictions'] + + for ds in results_pose2d: + ds.pred_instances.set_field( + (ds.pred_instances.bboxes[..., 2:] - + ds.pred_instances.bboxes[..., :2]).prod(-1), 'areas') + + if not self._video_input: + height, width = results_pose2d[0].metainfo['ori_shape'] + + # Clear the buffer if inputs are individual images to prevent + # carryover effects from previous images + self._buffer.clear() + + else: + height = self.video_info['height'] + width = self.video_info['width'] + img_path = results_pose2d[0].metainfo['img_path'] + + # instance matching + if use_oks_tracking: + _track = partial(_track_by_oks) + else: + _track = _track_by_iou + + for result in results_pose2d: + track_id, self._buffer['results_pose2d_last'], _ = _track( + result, self._buffer['results_pose2d_last'], tracking_thr) + if track_id == -1: + pred_instances = result.pred_instances.cpu().numpy() + keypoints = pred_instances.keypoints + if np.count_nonzero(keypoints[:, :, 1]) >= 3: + next_id = self._buffer.get('next_id', 0) + result.set_field(next_id, 'track_id') + self._buffer['next_id'] = next_id + 1 + else: + # If the number of keypoints detected is small, + # delete that person instance. + result.pred_instances.keypoints[..., 1] = -10 + result.pred_instances.bboxes *= 0 + result.set_field(-1, 'track_id') + else: + result.set_field(track_id, 'track_id') + self._buffer['pose2d_results'] = merge_data_samples(results_pose2d) + + # convert keypoints + results_pose2d_converted = [ds.cpu().numpy() for ds in results_pose2d] + for ds in results_pose2d_converted: + ds.pred_instances.keypoints = self._keypoint_converter( + ds.pred_instances.keypoints) + self._buffer['pose_est_results_list'].append(results_pose2d_converted) + + # extract and pad input pose2d sequence + pose_results_2d = self._pose_seq_extractor( + self._buffer['pose_est_results_list'], + frame_idx=index if self._video_input else 0) + causal = self.cfg.test_dataloader.dataset.get('causal', False) + target_idx = -1 if causal else len(pose_results_2d) // 2 + + stats_info = self.model.dataset_meta.get('stats_info', {}) + bbox_center = stats_info.get('bbox_center', None) + bbox_scale = stats_info.get('bbox_scale', None) + + for i, pose_res in enumerate(pose_results_2d): + for j, data_sample in enumerate(pose_res): + kpts = data_sample.pred_instances.keypoints + bboxes = data_sample.pred_instances.bboxes + keypoints = [] + for k in range(len(kpts)): + kpt = kpts[k] + if norm_pose_2d: + bbox = bboxes[k] + center = np.array([[(bbox[0] + bbox[2]) / 2, + (bbox[1] + bbox[3]) / 2]]) + scale = max(bbox[2] - bbox[0], bbox[3] - bbox[1]) + keypoints.append((kpt[:, :2] - center) / scale * + bbox_scale + bbox_center) + else: + keypoints.append(kpt[:, :2]) + pose_results_2d[i][j].pred_instances.keypoints = np.array( + keypoints) + pose_sequences_2d = collate_pose_sequence(pose_results_2d, True, + target_idx) + if not pose_sequences_2d: + return [] + + data_list = [] + for i, pose_seq in enumerate(pose_sequences_2d): + data_info = dict() + + keypoints_2d = pose_seq.pred_instances.keypoints + keypoints_2d = np.squeeze( + keypoints_2d, + axis=0) if keypoints_2d.ndim == 4 else keypoints_2d + + T, K, C = keypoints_2d.shape + + data_info['keypoints'] = keypoints_2d + data_info['keypoints_visible'] = np.ones(( + T, + K, + ), + dtype=np.float32) + data_info['lifting_target'] = np.zeros((K, 3), dtype=np.float32) + data_info['lifting_target_visible'] = np.ones((K, 1), + dtype=np.float32) + data_info['camera_param'] = dict(w=width, h=height) + + data_info.update(self.model.dataset_meta) + data_info = self.pipeline(data_info) + data_info['data_samples'].set_field( + img_path, 'img_path', field_type='metainfo') + data_list.append(data_info) + + return data_list + + @torch.no_grad() + def forward(self, + inputs: Union[dict, tuple], + rebase_keypoint_height: bool = False): + """Perform forward pass through the model and process the results. + + Args: + inputs (Union[dict, tuple]): The inputs for the model. + rebase_keypoint_height (bool, optional): Flag to rebase the + height of the keypoints (z-axis). Defaults to False. + + Returns: + list: A list of data samples, each containing the model's output + results. + """ + + pose_lift_results = self.model.test_step(inputs) + + # Post-processing of pose estimation results + pose_est_results_converted = self._buffer['pose_est_results_list'][-1] + for idx, pose_lift_res in enumerate(pose_lift_results): + # Update track_id from the pose estimation results + pose_lift_res.track_id = pose_est_results_converted[idx].get( + 'track_id', 1e4) + + # Invert x and z values of the keypoints + keypoints = pose_lift_res.pred_instances.keypoints + keypoints = keypoints[..., [0, 2, 1]] + keypoints[..., 0] = -keypoints[..., 0] + keypoints[..., 2] = -keypoints[..., 2] + + # If rebase_keypoint_height is True, adjust z-axis values + if rebase_keypoint_height: + keypoints[..., 2] -= np.min( + keypoints[..., 2], axis=-1, keepdims=True) + + pose_lift_results[idx].pred_instances.keypoints = keypoints + + pose_lift_results = sorted( + pose_lift_results, key=lambda x: x.get('track_id', 1e4)) + + data_samples = [merge_data_samples(pose_lift_results)] + return data_samples + + def __call__( + self, + inputs: InputsType, + return_datasample: bool = False, + batch_size: int = 1, + out_dir: Optional[str] = None, + **kwargs, + ) -> dict: + """Call the inferencer. + + Args: + inputs (InputsType): Inputs for the inferencer. + return_datasample (bool): Whether to return results as + :obj:`BaseDataElement`. Defaults to False. + batch_size (int): Batch size. Defaults to 1. + out_dir (str, optional): directory to save visualization + results and predictions. Will be overoden if vis_out_dir or + pred_out_dir are given. Defaults to None + **kwargs: Key words arguments passed to :meth:`preprocess`, + :meth:`forward`, :meth:`visualize` and :meth:`postprocess`. + Each key in kwargs should be in the corresponding set of + ``preprocess_kwargs``, ``forward_kwargs``, + ``visualize_kwargs`` and ``postprocess_kwargs``. + + Returns: + dict: Inference and visualization results. + """ + if out_dir is not None: + if 'vis_out_dir' not in kwargs: + kwargs['vis_out_dir'] = f'{out_dir}/visualizations' + if 'pred_out_dir' not in kwargs: + kwargs['pred_out_dir'] = f'{out_dir}/predictions' + + ( + preprocess_kwargs, + forward_kwargs, + visualize_kwargs, + postprocess_kwargs, + ) = self._dispatch_kwargs(**kwargs) + + self.update_model_visualizer_settings(**kwargs) + + # preprocessing + if isinstance(inputs, str) and inputs.startswith('webcam'): + inputs = self._get_webcam_inputs(inputs) + batch_size = 1 + if not visualize_kwargs.get('show', False): + warnings.warn('The display mode is closed when using webcam ' + 'input. It will be turned on automatically.') + visualize_kwargs['show'] = True + else: + inputs = self._inputs_to_list(inputs) + + inputs = self.preprocess( + inputs, batch_size=batch_size, **preprocess_kwargs) + + preds = [] + + for proc_inputs, ori_inputs in inputs: + preds = self.forward(proc_inputs, **forward_kwargs) + + visualization = self.visualize(ori_inputs, preds, + **visualize_kwargs) + results = self.postprocess(preds, visualization, return_datasample, + **postprocess_kwargs) + yield results + + if self._video_input: + self._finalize_video_processing( + postprocess_kwargs.get('pred_out_dir', '')) + self._buffer.clear() + + def visualize(self, + inputs: list, + preds: List[PoseDataSample], + return_vis: bool = False, + show: bool = False, + draw_bbox: bool = False, + wait_time: float = 0, + radius: int = 3, + thickness: int = 1, + kpt_thr: float = 0.3, + vis_out_dir: str = '', + window_name: str = '', + window_close_event_handler: Optional[Callable] = None + ) -> List[np.ndarray]: + """Visualize predictions. + + Args: + inputs (list): Inputs preprocessed by :meth:`_inputs_to_list`. + preds (Any): Predictions of the model. + return_vis (bool): Whether to return images with predicted results. + show (bool): Whether to display the image in a popup window. + Defaults to False. + wait_time (float): The interval of show (ms). Defaults to 0 + draw_bbox (bool): Whether to draw the bounding boxes. + Defaults to False + radius (int): Keypoint radius for visualization. Defaults to 3 + thickness (int): Link thickness for visualization. Defaults to 1 + kpt_thr (float): The threshold to visualize the keypoints. + Defaults to 0.3 + vis_out_dir (str, optional): Directory to save visualization + results w/o predictions. If left as empty, no file will + be saved. Defaults to ''. + window_name (str, optional): Title of display window. + window_close_event_handler (callable, optional): + + Returns: + List[np.ndarray]: Visualization results. + """ + if (not return_vis) and (not show) and (not vis_out_dir): + return + + if getattr(self, 'visualizer', None) is None: + raise ValueError('Visualization needs the "visualizer" term' + 'defined in the config, but got None.') + + self.visualizer.radius = radius + self.visualizer.line_width = thickness + det_kpt_color = self.pose2d_model.visualizer.kpt_color + det_dataset_skeleton = self.pose2d_model.visualizer.skeleton + det_dataset_link_color = self.pose2d_model.visualizer.link_color + self.visualizer.det_kpt_color = det_kpt_color + self.visualizer.det_dataset_skeleton = det_dataset_skeleton + self.visualizer.det_dataset_link_color = det_dataset_link_color + + results = [] + + for single_input, pred in zip(inputs, preds): + if isinstance(single_input, str): + img = mmcv.imread(single_input, channel_order='rgb') + elif isinstance(single_input, np.ndarray): + img = mmcv.bgr2rgb(single_input) + else: + raise ValueError('Unsupported input type: ' + f'{type(single_input)}') + + # since visualization and inference utilize the same process, + # the wait time is reduced when a video input is utilized, + # thereby eliminating the issue of inference getting stuck. + wait_time = 1e-5 if self._video_input else wait_time + + visualization = self.visualizer.add_datasample( + window_name, + img, + data_sample=pred, + det_data_sample=self._buffer['pose2d_results'], + draw_gt=False, + draw_bbox=draw_bbox, + show=show, + wait_time=wait_time, + kpt_thr=kpt_thr) + results.append(visualization) + + if vis_out_dir: + out_img = mmcv.rgb2bgr(visualization) + _, file_extension = os.path.splitext(vis_out_dir) + if file_extension: + dir_name = os.path.dirname(vis_out_dir) + file_name = os.path.basename(vis_out_dir) + else: + dir_name = vis_out_dir + file_name = None + mkdir_or_exist(dir_name) + + if self._video_input: + + if self.video_info['writer'] is None: + fourcc = cv2.VideoWriter_fourcc(*'mp4v') + if file_name is None: + file_name = os.path.basename( + self.video_info['name']) + out_file = join_path(dir_name, file_name) + self.video_info['writer'] = cv2.VideoWriter( + out_file, fourcc, self.video_info['fps'], + (visualization.shape[1], visualization.shape[0])) + self.video_info['writer'].write(out_img) + + else: + img_name = os.path.basename(pred.metainfo['img_path']) + file_name = file_name if file_name else img_name + out_file = join_path(dir_name, file_name) + mmcv.imwrite(out_img, out_file) + + if return_vis: + return results + else: + return [] diff --git a/mmpose/apis/inferencers/utils/get_model_alias.py b/mmpose/apis/inferencers/utils/get_model_alias.py index 8e8f85910c..49de6528d6 100644 --- a/mmpose/apis/inferencers/utils/get_model_alias.py +++ b/mmpose/apis/inferencers/utils/get_model_alias.py @@ -30,8 +30,8 @@ def get_model_aliases(scope: str = 'mmpose') -> Dict[str, str]: model_alias_dict[alias] = model_cfg['Name'] else: raise ValueError( - 'encounter an unexpected alias type. Please ' - 'raise an issue at https://github.com/open-mmlab/mmpose/issues ' # noqa + 'encounter an unexpected alias type. Please raise an ' + 'issue at https://github.com/open-mmlab/mmpose/issues ' 'to announce us') return model_alias_dict diff --git a/mmpose/apis/webcam/__init__.py b/mmpose/apis/webcam/__init__.py deleted file mode 100644 index 271b238c67..0000000000 --- a/mmpose/apis/webcam/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from .webcam_executor import WebcamExecutor - -__all__ = ['WebcamExecutor'] diff --git a/mmpose/apis/webcam/nodes/__init__.py b/mmpose/apis/webcam/nodes/__init__.py deleted file mode 100644 index 50f7c899d3..0000000000 --- a/mmpose/apis/webcam/nodes/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from .base_visualizer_node import BaseVisualizerNode -from .helper_nodes import MonitorNode, ObjectAssignerNode, RecorderNode -from .model_nodes import DetectorNode, TopdownPoseEstimatorNode -from .node import Node -from .registry import NODES -from .visualizer_nodes import (BigeyeEffectNode, NoticeBoardNode, - ObjectVisualizerNode, SunglassesEffectNode) - -__all__ = [ - 'BaseVisualizerNode', 'NODES', 'MonitorNode', 'ObjectAssignerNode', - 'RecorderNode', 'DetectorNode', 'TopdownPoseEstimatorNode', 'Node', - 'BigeyeEffectNode', 'NoticeBoardNode', 'ObjectVisualizerNode', - 'ObjectAssignerNode', 'SunglassesEffectNode' -] diff --git a/mmpose/apis/webcam/nodes/base_visualizer_node.py b/mmpose/apis/webcam/nodes/base_visualizer_node.py deleted file mode 100644 index 0e0ba397d4..0000000000 --- a/mmpose/apis/webcam/nodes/base_visualizer_node.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from abc import abstractmethod -from typing import Dict, List, Optional, Union - -import numpy as np - -from ..utils import FrameMessage, Message -from .node import Node - - -class BaseVisualizerNode(Node): - """Base class for nodes whose function is to create visual effects, like - visualizing model predictions, showing graphics or showing text messages. - - All subclass should implement the method ``draw()``. - - Args: - name (str): The node name (also thread name) - input_buffer (str): The name of the input buffer - output_buffer (str | list): The name(s) of the output buffer(s). - enable_key (str|int, optional): Set a hot-key to toggle enable/disable - of the node. If an int value is given, it will be treated as an - ascii code of a key. Please note: (1) If ``enable_key`` is set, - the ``bypass()`` method need to be overridden to define the node - behavior when disabled; (2) Some hot-keys are reserved for - particular use. For example: 'q', 'Q' and 27 are used for exiting. - Default: ``None`` - enable (bool): Default enable/disable status. Default: ``True`` - """ - - def __init__(self, - name: str, - input_buffer: str, - output_buffer: Union[str, List[str]], - enable_key: Optional[Union[str, int]] = None, - enable: bool = True): - - super().__init__(name=name, enable_key=enable_key, enable=enable) - - # Register buffers - self.register_input_buffer(input_buffer, 'input', trigger=True) - self.register_output_buffer(output_buffer) - - def process(self, input_msgs: Dict[str, Message]) -> Union[Message, None]: - input_msg = input_msgs['input'] - - img = self.draw(input_msg) - input_msg.set_image(img) - - return input_msg - - def bypass(self, input_msgs: Dict[str, Message]) -> Union[Message, None]: - return input_msgs['input'] - - @abstractmethod - def draw(self, input_msg: FrameMessage) -> np.ndarray: - """Draw on the frame image of the input FrameMessage. - - Args: - input_msg (:obj:`FrameMessage`): The message of the frame to draw - on - - Returns: - np.array: The processed image. - """ diff --git a/mmpose/apis/webcam/nodes/helper_nodes/__init__.py b/mmpose/apis/webcam/nodes/helper_nodes/__init__.py deleted file mode 100644 index 8bb0ed9dd1..0000000000 --- a/mmpose/apis/webcam/nodes/helper_nodes/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from .monitor_node import MonitorNode -from .object_assigner_node import ObjectAssignerNode -from .recorder_node import RecorderNode - -__all__ = ['MonitorNode', 'ObjectAssignerNode', 'RecorderNode'] diff --git a/mmpose/apis/webcam/nodes/helper_nodes/monitor_node.py b/mmpose/apis/webcam/nodes/helper_nodes/monitor_node.py deleted file mode 100644 index 305490dc52..0000000000 --- a/mmpose/apis/webcam/nodes/helper_nodes/monitor_node.py +++ /dev/null @@ -1,167 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from typing import Dict, List, Optional, Union - -import cv2 -import numpy as np -from mmcv import color_val - -from ..node import Node -from ..registry import NODES - -try: - import psutil - psutil_proc = psutil.Process() -except (ImportError, ModuleNotFoundError): - psutil_proc = None - - -@NODES.register_module() -class MonitorNode(Node): - """Show diagnostic information. - - Args: - name (str): The node name (also thread name) - input_buffer (str): The name of the input buffer - output_buffer (str|list): The name(s) of the output buffer(s) - enable_key (str|int, optional): Set a hot-key to toggle enable/disable - of the node. If an int value is given, it will be treated as an - ascii code of a key. Please note: (1) If ``enable_key`` is set, - the ``bypass()`` method need to be overridden to define the node - behavior when disabled; (2) Some hot-keys are reserved for - particular use. For example: 'q', 'Q' and 27 are used for exiting. - Default: ``None`` - enable (bool): Default enable/disable status. Default: ``True`` - x_offset (int): The position of the text box's left border in - pixels. Default: 20 - y_offset (int): The position of the text box's top border in - pixels. Default: 20 - y_delta (int): The line height in pixels. Default: 15 - text_color (str|tuple): The font color represented in a color name or - a BGR tuple. Default: ``'black'`` - backbround_color (str|tuple): The background color represented in a - color name or a BGR tuple. Default: (255, 183, 0) - text_scale (float): The font scale factor that is multiplied by the - base size. Default: 0.4 - ignore_items (list[str], optional): Specify the node information items - that will not be shown. See ``MonitorNode._default_ignore_items`` - for the default setting. - - Example:: - >>> cfg = dict( - ... type='MonitorNode', - ... name='monitor', - ... enable_key='m', - ... enable=False, - ... input_buffer='vis_notice', - ... output_buffer='display') - - >>> from mmpose.apis.webcam.nodes import NODES - >>> node = NODES.build(cfg) - """ - - _default_ignore_items = ['timestamp'] - - def __init__(self, - name: str, - input_buffer: str, - output_buffer: Union[str, List[str]], - enable_key: Optional[Union[str, int]] = None, - enable: bool = False, - x_offset=20, - y_offset=20, - y_delta=15, - text_color='black', - background_color=(255, 183, 0), - text_scale=0.4, - ignore_items: Optional[List[str]] = None): - super().__init__(name=name, enable_key=enable_key, enable=enable) - - self.x_offset = x_offset - self.y_offset = y_offset - self.y_delta = y_delta - self.text_color = color_val(text_color) - self.background_color = color_val(background_color) - self.text_scale = text_scale - if ignore_items is None: - self.ignore_items = self._default_ignore_items - else: - self.ignore_items = ignore_items - - self.register_input_buffer(input_buffer, 'input', trigger=True) - self.register_output_buffer(output_buffer) - - def process(self, input_msgs): - input_msg = input_msgs['input'] - - input_msg.update_route_info( - node_name='System Info', - node_type='none', - info=self._get_system_info()) - - img = input_msg.get_image() - route_info = input_msg.get_route_info() - img = self._show_route_info(img, route_info) - - input_msg.set_image(img) - return input_msg - - def _get_system_info(self): - """Get the system information including CPU and memory usage. - - Returns: - dict: The system information items. - """ - sys_info = {} - if psutil_proc is not None: - sys_info['CPU(%)'] = psutil_proc.cpu_percent() - sys_info['Memory(%)'] = psutil_proc.memory_percent() - return sys_info - - def _show_route_info(self, img: np.ndarray, - route_info: List[Dict]) -> np.ndarray: - """Show the route information in the frame. - - Args: - img (np.ndarray): The frame image. - route_info (list[dict]): The route information of the frame. - - Returns: - np.ndarray: The processed image. - """ - canvas = np.full(img.shape, self.background_color, dtype=img.dtype) - - x = self.x_offset - y = self.y_offset - - max_len = 0 - - def _put_line(line=''): - nonlocal y, max_len - cv2.putText(canvas, line, (x, y), cv2.FONT_HERSHEY_DUPLEX, - self.text_scale, self.text_color, 1) - y += self.y_delta - max_len = max(max_len, len(line)) - - for node_info in route_info: - title = f'{node_info["node"]}({node_info["node_type"]})' - _put_line(title) - for k, v in node_info['info'].items(): - if k in self.ignore_items: - continue - if isinstance(v, float): - v = f'{v:.1f}' - _put_line(f' {k}: {v}') - - x1 = max(0, self.x_offset) - x2 = min(img.shape[1], int(x + max_len * self.text_scale * 20)) - y1 = max(0, self.y_offset - self.y_delta) - y2 = min(img.shape[0], y) - - src1 = canvas[y1:y2, x1:x2] - src2 = img[y1:y2, x1:x2] - img[y1:y2, x1:x2] = cv2.addWeighted(src1, 0.5, src2, 0.5, 0) - - return img - - def bypass(self, input_msgs): - return input_msgs['input'] diff --git a/mmpose/apis/webcam/nodes/helper_nodes/object_assigner_node.py b/mmpose/apis/webcam/nodes/helper_nodes/object_assigner_node.py deleted file mode 100644 index a1a7804ab4..0000000000 --- a/mmpose/apis/webcam/nodes/helper_nodes/object_assigner_node.py +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import time -from typing import List, Union - -from mmpose.utils.timer import RunningAverage -from ..node import Node -from ..registry import NODES - - -@NODES.register_module() -class ObjectAssignerNode(Node): - """Assign the object information to the frame message. - - :class:`ObjectAssignerNode` enables asynchronous processing of model - inference and video I/O, so the video will be captured and displayed - smoothly regardless of the model inference speed. Specifically, - :class:`ObjectAssignerNode` takes messages from both model branch and - video I/O branch as its input, indicated as "object message" and "frame - message" respectively. When an object message arrives it will update the - latest object information; and when a frame message arrives, it will be - assigned with the latest object information and output. - - Specially, if the webcam executor is set to synchrounous mode, the - behavior of :class:`ObjectAssignerNode` will be different: When an object - message arrives, it will trigger an output of itself; and the frame - messages will be ignored. - - Args: - name (str): The node name (also thread name) - frame_buffer (str): Buffer name for frame messages - object_buffer (str): Buffer name for object messages - output_buffer (str): The name(s) of the output buffer(s) - - Example:: - >>> cfg =dict( - ... type='ObjectAssignerNode', - ... name='object assigner', - ... frame_buffer='_frame_', - ... # `_frame_` is an executor-reserved buffer - ... object_buffer='animal_pose', - ... output_buffer='frame') - - >>> from mmpose.apis.webcam.nodes import NODES - >>> node = NODES.build(cfg) - """ - - def __init__(self, name: str, frame_buffer: str, object_buffer: str, - output_buffer: Union[str, List[str]]): - super().__init__(name=name, enable=True) - self.synchronous = None - - # Cache the latest model result - self.last_object_msg = None - self.last_output_msg = None - - # Inference speed analysis - self.frame_fps = RunningAverage(window=10) - self.frame_lag = RunningAverage(window=10) - self.object_fps = RunningAverage(window=10) - self.object_lag = RunningAverage(window=10) - - # Register buffers - # The trigger buffer depends on the executor.synchronous attribute, - # so it will be set later after the executor is assigned in - # ``set_executor``. - self.register_input_buffer(object_buffer, 'object', trigger=False) - self.register_input_buffer(frame_buffer, 'frame', trigger=False) - self.register_output_buffer(output_buffer) - - def set_executor(self, executor): - super().set_executor(executor) - # Set synchronous according to the executor - if executor.synchronous: - self.synchronous = True - trigger = 'object' - else: - self.synchronous = False - trigger = 'frame' - - # Set trigger input buffer according to the synchronous setting - for buffer_info in self._input_buffers: - if buffer_info.input_name == trigger: - buffer_info.trigger = True - - def process(self, input_msgs): - object_msg = input_msgs['object'] - - # Update last result - if object_msg is not None: - # Update result FPS - if self.last_object_msg is not None: - self.object_fps.update( - 1.0 / - (object_msg.timestamp - self.last_object_msg.timestamp)) - # Update inference latency - self.object_lag.update(time.time() - object_msg.timestamp) - # Update last inference result - self.last_object_msg = object_msg - - if not self.synchronous: - # Asynchronous mode: - # Assign the latest object information to the - # current frame. - frame_msg = input_msgs['frame'] - - self.frame_lag.update(time.time() - frame_msg.timestamp) - - # Assign objects to frame - if self.last_object_msg is not None: - frame_msg.update_objects(self.last_object_msg.get_objects()) - frame_msg.merge_route_info( - self.last_object_msg.get_route_info()) - - output_msg = frame_msg - - else: - # Synchronous mode: - # The current frame will be ignored. Instead, - # the frame from which the latest object information is obtained - # will be used. - self.frame_lag.update(time.time() - object_msg.timestamp) - output_msg = object_msg - - # Update frame fps and lag - if self.last_output_msg is not None: - self.frame_lag.update(time.time() - output_msg.timestamp) - self.frame_fps.update( - 1.0 / (output_msg.timestamp - self.last_output_msg.timestamp)) - self.last_output_msg = output_msg - - return output_msg - - def _get_node_info(self): - info = super()._get_node_info() - info['object_fps'] = self.object_fps.average() - info['object_lag (ms)'] = self.object_lag.average() * 1000 - info['frame_fps'] = self.frame_fps.average() - info['frame_lag (ms)'] = self.frame_lag.average() * 1000 - return info diff --git a/mmpose/apis/webcam/nodes/helper_nodes/recorder_node.py b/mmpose/apis/webcam/nodes/helper_nodes/recorder_node.py deleted file mode 100644 index b35a778692..0000000000 --- a/mmpose/apis/webcam/nodes/helper_nodes/recorder_node.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from queue import Full, Queue -from threading import Thread -from typing import List, Union - -import cv2 - -from ..node import Node -from ..registry import NODES - - -@NODES.register_module() -class RecorderNode(Node): - """Record the video frames into a local file. - - :class:`RecorderNode` uses OpenCV backend to record the video. Recording - is performed in a separate thread to avoid blocking the data stream. A - buffer queue is used to cached the arrived frame images. - - Args: - name (str): The node name (also thread name) - input_buffer (str): The name of the input buffer - output_buffer (str|list): The name(s) of the output buffer(s) - out_video_file (str): The path of the output video file - out_video_fps (int): The frame rate of the output video. Default: 30 - out_video_codec (str): The codec of the output video. Default: 'mp4v' - buffer_size (int): Size of the buffer queue that caches the arrived - frame images. - enable (bool): Default enable/disable status. Default: ``True``. - - Example:: - >>> cfg = dict( - ... type='RecorderNode', - ... name='recorder', - ... out_video_file='webcam_demo.mp4', - ... input_buffer='display', - ... output_buffer='_display_' - ... # `_display_` is an executor-reserved buffer - ... ) - - >>> from mmpose.apis.webcam.nodes import NODES - >>> node = NODES.build(cfg) - """ - - def __init__( - self, - name: str, - input_buffer: str, - output_buffer: Union[str, List[str]], - out_video_file: str, - out_video_fps: int = 30, - out_video_codec: str = 'mp4v', - buffer_size: int = 30, - enable: bool = True, - ): - super().__init__(name=name, enable_key=None, enable=enable) - - self.queue = Queue(maxsize=buffer_size) - self.out_video_file = out_video_file - self.out_video_fps = out_video_fps - self.out_video_codec = out_video_codec - self.vwriter = None - - # Register buffers - self.register_input_buffer(input_buffer, 'input', trigger=True) - self.register_output_buffer(output_buffer) - - # Start a new thread to write frame - self.t_record = Thread(target=self._record, args=(), daemon=True) - self.t_record.start() - - def process(self, input_msgs): - - input_msg = input_msgs['input'] - img = input_msg.get_image() if input_msg is not None else None - img_queued = False - - while not img_queued: - try: - self.queue.put(img, timeout=1) - img_queued = True - self.logger.info('Recorder received one frame.') - except Full: - self.logger.warn('Recorder jamed!') - - return input_msg - - def _record(self): - """This method is used to create a thread to get frame images from the - buffer queue and write them into the file.""" - - while True: - - img = self.queue.get() - - if img is None: - break - - if self.vwriter is None: - fourcc = cv2.VideoWriter_fourcc(*self.out_video_codec) - fps = self.out_video_fps - frame_size = (img.shape[1], img.shape[0]) - self.vwriter = cv2.VideoWriter(self.out_video_file, fourcc, - fps, frame_size) - assert self.vwriter.isOpened() - - self.vwriter.write(img) - - self.logger.info('Recorder released.') - if self.vwriter is not None: - self.vwriter.release() - - def on_exit(self): - try: - # Try putting a None into the output queue so the self.vwriter will - # be released after all queue frames have been written to file. - self.queue.put(None, timeout=1) - self.t_record.join(timeout=1) - except Full: - pass - - if self.t_record.is_alive(): - # Force to release self.vwriter - self.logger.warn('Recorder forced release!') - if self.vwriter is not None: - self.vwriter.release() diff --git a/mmpose/apis/webcam/nodes/model_nodes/__init__.py b/mmpose/apis/webcam/nodes/model_nodes/__init__.py deleted file mode 100644 index a9a116bfec..0000000000 --- a/mmpose/apis/webcam/nodes/model_nodes/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from .detector_node import DetectorNode -from .pose_estimator_node import TopdownPoseEstimatorNode - -__all__ = ['DetectorNode', 'TopdownPoseEstimatorNode'] diff --git a/mmpose/apis/webcam/nodes/model_nodes/detector_node.py b/mmpose/apis/webcam/nodes/model_nodes/detector_node.py deleted file mode 100644 index 350831fe62..0000000000 --- a/mmpose/apis/webcam/nodes/model_nodes/detector_node.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from typing import Dict, List, Optional, Union - -import numpy as np - -from mmpose.utils import adapt_mmdet_pipeline -from ...utils import get_config_path -from ..node import Node -from ..registry import NODES - -try: - from mmdet.apis import inference_detector, init_detector - has_mmdet = True -except (ImportError, ModuleNotFoundError): - has_mmdet = False - - -@NODES.register_module() -class DetectorNode(Node): - """Detect objects from the frame image using MMDetection model. - - Note that MMDetection is required for this node. Please refer to - `MMDetection documentation `_ for the installation guide. - - Parameters: - name (str): The node name (also thread name) - model_cfg (str): The model config file - model_checkpoint (str): The model checkpoint file - input_buffer (str): The name of the input buffer - output_buffer (str|list): The name(s) of the output buffer(s) - enable_key (str|int, optional): Set a hot-key to toggle enable/disable - of the node. If an int value is given, it will be treated as an - ascii code of a key. Please note: (1) If ``enable_key`` is set, - the ``bypass()`` method need to be overridden to define the node - behavior when disabled; (2) Some hot-keys are reserved for - particular use. For example: 'q', 'Q' and 27 are used for exiting. - Default: ``None`` - enable (bool): Default enable/disable status. Default: ``True`` - device (str): Specify the device to hold model weights and inference - the model. Default: ``'cuda:0'`` - bbox_thr (float): Set a threshold to filter out objects with low bbox - scores. Default: 0.5 - multi_input (bool): Whether load all frames in input buffer. If True, - all frames in buffer will be loaded and stacked. The latest frame - is used to detect objects of interest. Default: False - - Example:: - >>> cfg = dict( - ... type='DetectorNode', - ... name='detector', - ... model_config='demo/mmdetection_cfg/' - ... 'ssdlite_mobilenetv2_scratch_600e_coco.py', - ... model_checkpoint='https://download.openmmlab.com' - ... '/mmdetection/v2.0/ssd/' - ... 'ssdlite_mobilenetv2_scratch_600e_coco/ssdlite_mobilenetv2_' - ... 'scratch_600e_coco_20210629_110627-974d9307.pth', - ... # `_input_` is an executor-reserved buffer - ... input_buffer='_input_', - ... output_buffer='det_result') - - >>> from mmpose.apis.webcam.nodes import NODES - >>> node = NODES.build(cfg) - """ - - def __init__(self, - name: str, - model_config: str, - model_checkpoint: str, - input_buffer: str, - output_buffer: Union[str, List[str]], - enable_key: Optional[Union[str, int]] = None, - enable: bool = True, - device: str = 'cuda:0', - bbox_thr: float = 0.5, - multi_input: bool = False): - # Check mmdetection is installed - assert has_mmdet, \ - f'MMDetection is required for {self.__class__.__name__}.' - - super().__init__( - name=name, - enable_key=enable_key, - enable=enable, - multi_input=multi_input) - - self.model_config = get_config_path(model_config, 'mmdet') - self.model_checkpoint = model_checkpoint - self.device = device.lower() - self.bbox_thr = bbox_thr - - # Init model - self.model = init_detector( - self.model_config, self.model_checkpoint, device=self.device) - self.model.cfg = adapt_mmdet_pipeline(self.model.cfg) - - # Register buffers - self.register_input_buffer(input_buffer, 'input', trigger=True) - self.register_output_buffer(output_buffer) - - def bypass(self, input_msgs): - return input_msgs['input'] - - def process(self, input_msgs): - input_msg = input_msgs['input'] - - if self.multi_input: - imgs = [frame.get_image() for frame in input_msg] - input_msg = input_msg[-1] - - img = input_msg.get_image() - - preds = inference_detector(self.model, img) - objects = self._post_process(preds) - input_msg.update_objects(objects) - - if self.multi_input: - input_msg.set_image(np.stack(imgs, axis=0)) - - return input_msg - - def _post_process(self, preds) -> List[Dict]: - """Post-process the predictions of MMDetection model.""" - instances = preds.pred_instances.cpu().numpy() - - classes = self.model.dataset_meta['classes'] - if isinstance(classes, str): - classes = (classes, ) - - objects = [] - for i in range(len(instances)): - if instances.scores[i] < self.bbox_thr: - continue - class_id = instances.labels[i] - obj = { - 'class_id': class_id, - 'label': classes[class_id], - 'bbox': instances.bboxes[i], - 'det_model_cfg': self.model.cfg, - 'dataset_meta': self.model.dataset_meta.copy(), - } - objects.append(obj) - return objects diff --git a/mmpose/apis/webcam/nodes/model_nodes/pose_estimator_node.py b/mmpose/apis/webcam/nodes/model_nodes/pose_estimator_node.py deleted file mode 100644 index 64691cf560..0000000000 --- a/mmpose/apis/webcam/nodes/model_nodes/pose_estimator_node.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from dataclasses import dataclass -from typing import List, Optional, Union - -import numpy as np - -from mmpose.apis import inference_topdown, init_model -from ...utils import get_config_path -from ..node import Node -from ..registry import NODES - - -@dataclass -class TrackInfo: - """Dataclass for object tracking information.""" - next_id: int = 0 - last_objects: List = None - - -@NODES.register_module() -class TopdownPoseEstimatorNode(Node): - """Perform top-down pose estimation using MMPose model. - - The node should be placed after an object detection node. - - Parameters: - name (str): The node name (also thread name) - model_cfg (str): The model config file - model_checkpoint (str): The model checkpoint file - input_buffer (str): The name of the input buffer - output_buffer (str|list): The name(s) of the output buffer(s) - enable_key (str|int, optional): Set a hot-key to toggle enable/disable - of the node. If an int value is given, it will be treated as an - ascii code of a key. Please note: (1) If ``enable_key`` is set, - the ``bypass()`` method need to be overridden to define the node - behavior when disabled; (2) Some hot-keys are reserved for - particular use. For example: 'q', 'Q' and 27 are used for exiting. - Default: ``None`` - enable (bool): Default enable/disable status. Default: ``True`` - device (str): Specify the device to hold model weights and inference - the model. Default: ``'cuda:0'`` - class_ids (list[int], optional): Specify the object category indices - to apply pose estimation. If both ``class_ids`` and ``labels`` - are given, ``labels`` will be ignored. If neither is given, pose - estimation will be applied for all objects. Default: ``None`` - labels (list[str], optional): Specify the object category names to - apply pose estimation. See also ``class_ids``. Default: ``None`` - bbox_thr (float): Set a threshold to filter out objects with low bbox - scores. Default: 0.5 - - Example:: - >>> cfg = dict( - ... type='TopdownPoseEstimatorNode', - ... name='human pose estimator', - ... model_config='configs/wholebody/2d_kpt_sview_rgb_img/' - ... 'topdown_heatmap/coco-wholebody/' - ... 'vipnas_mbv3_coco_wholebody_256x192_dark.py', - ... model_checkpoint='https://download.openmmlab.com/mmpose/' - ... 'top_down/vipnas/vipnas_mbv3_coco_wholebody_256x192_dark' - ... '-e2158108_20211205.pth', - ... labels=['person'], - ... input_buffer='det_result', - ... output_buffer='human_pose') - - >>> from mmpose.apis.webcam.nodes import NODES - >>> node = NODES.build(cfg) - """ - - def __init__(self, - name: str, - model_config: str, - model_checkpoint: str, - input_buffer: str, - output_buffer: Union[str, List[str]], - enable_key: Optional[Union[str, int]] = None, - enable: bool = True, - device: str = 'cuda:0', - class_ids: Optional[List[int]] = None, - labels: Optional[List[str]] = None, - bbox_thr: float = 0.5): - super().__init__(name=name, enable_key=enable_key, enable=enable) - - # Init model - self.model_config = get_config_path(model_config, 'mmpose') - self.model_checkpoint = model_checkpoint - self.device = device.lower() - - self.class_ids = class_ids - self.labels = labels - self.bbox_thr = bbox_thr - - # Init model - self.model = init_model( - self.model_config, self.model_checkpoint, device=self.device) - - # Register buffers - self.register_input_buffer(input_buffer, 'input', trigger=True) - self.register_output_buffer(output_buffer) - - def bypass(self, input_msgs): - return input_msgs['input'] - - def process(self, input_msgs): - - input_msg = input_msgs['input'] - img = input_msg.get_image() - - if self.class_ids: - objects = input_msg.get_objects( - lambda x: x.get('class_id') in self.class_ids) - elif self.labels: - objects = input_msg.get_objects( - lambda x: x.get('label') in self.labels) - else: - objects = input_msg.get_objects() - - if len(objects) > 0: - # Inference pose - bboxes = np.stack([object['bbox'] for object in objects]) - pose_results = inference_topdown(self.model, img, bboxes) - - # Update objects - for pose_result, object in zip(pose_results, objects): - pred_instances = pose_result.pred_instances - object['keypoints'] = pred_instances.keypoints[0] - object['keypoint_scores'] = pred_instances.keypoint_scores[0] - - dataset_meta = self.model.dataset_meta.copy() - dataset_meta.update(object.get('dataset_meta', dict())) - object['dataset_meta'] = dataset_meta - object['pose_model_cfg'] = self.model.cfg - - input_msg.update_objects(objects) - - return input_msg diff --git a/mmpose/apis/webcam/nodes/node.py b/mmpose/apis/webcam/nodes/node.py deleted file mode 100644 index 3d34ae1cc0..0000000000 --- a/mmpose/apis/webcam/nodes/node.py +++ /dev/null @@ -1,407 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import logging -import time -from abc import ABCMeta, abstractmethod -from dataclasses import dataclass -from threading import Thread -from typing import Callable, Dict, List, Optional, Tuple, Union - -from mmengine import is_method_overridden - -from mmpose.utils import StopWatch -from ..utils import Message, VideoEndingMessage, limit_max_fps - - -@dataclass -class BufferInfo(): - """Dataclass for buffer information.""" - buffer_name: str - input_name: Optional[str] = None - trigger: bool = False - - -@dataclass -class EventInfo(): - """Dataclass for event handler information.""" - event_name: str - is_keyboard: bool = False - handler_func: Optional[Callable] = None - - -class Node(Thread, metaclass=ABCMeta): - """Base class for node, which is the interface of basic function module. - - :class:`Node` inherits :class:`threading.Thread`. All subclasses should - override following methods: - - - ``process()`` - - ``bypass()`` (optional) - - - Parameters: - name (str): The node name (also thread name) - enable_key (str|int, optional): Set a hot-key to toggle enable/disable - of the node. If an int value is given, it will be treated as an - ascii code of a key. Please note: (1) If ``enable_key`` is set, - the ``bypass()`` method need to be overridden to define the node - behavior when disabled; (2) Some hot-keys are reserved for - particular use. For example: 'q', 'Q' and 27 are used for exiting. - Default: ``None`` - max_fps (int): Maximum FPS of the node. This is to avoid the node - running unrestrictedly and causing large resource consuming. - Default: 30 - input_check_interval (float): Minimum interval (in millisecond) between - checking if input is ready. Default: 0.001 - enable (bool): Default enable/disable status. Default: ``True`` - daemon (bool): Whether node is a daemon. Default: ``True`` - multi_input (bool): Whether load all messages in buffer. If False, - only one message will be loaded each time. Default: ``False`` - """ - - def __init__(self, - name: str, - enable_key: Optional[Union[str, int]] = None, - max_fps: int = 30, - input_check_interval: float = 0.01, - enable: bool = True, - daemon: bool = False, - multi_input: bool = False): - super().__init__(name=name, daemon=daemon) - self._executor = None - self._enabled = enable - self.enable_key = enable_key - self.max_fps = max_fps - self.input_check_interval = input_check_interval - self.multi_input = multi_input - - # A partitioned buffer manager the executor's buffer manager that - # only accesses the buffers related to the node - self._buffer_manager = None - - # Input/output buffers are a list of registered buffers' information - self._input_buffers = [] - self._output_buffers = [] - - # Event manager is a copy of assigned executor's event manager - self._event_manager = None - - # A list of registered event information - # See register_event() for more information - # Note that we recommend to handle events in nodes by registering - # handlers, but one can still access the raw event by _event_manager - self._registered_events = [] - - # A list of (listener_threads, event_info) - # See set_executor() for more information - self._event_listener_threads = [] - - # A timer to calculate node FPS - self._timer = StopWatch(window=10) - - # Register enable toggle key - if self.enable_key: - # If the node allows toggling enable, it should override the - # `bypass` method to define the node behavior when disabled. - if not is_method_overridden('bypass', Node, self.__class__): - raise NotImplementedError( - f'The node {self.__class__} does not support toggling' - 'enable but got argument `enable_key`. To support toggling' - 'enable, please override the `bypass` method of the node.') - - self.register_event( - event_name=self.enable_key, - is_keyboard=True, - handler_func=self._toggle_enable, - ) - - # Logger - self.logger = logging.getLogger(f'Node "{self.name}"') - - @property - def registered_buffers(self): - return self._input_buffers + self._output_buffers - - @property - def registered_events(self): - return self._registered_events.copy() - - def _toggle_enable(self): - self._enabled = not self._enabled - - def register_input_buffer(self, - buffer_name: str, - input_name: str, - trigger: bool = False): - """Register an input buffer, so that Node can automatically check if - data is ready, fetch data from the buffers and format the inputs to - feed into `process` method. - - The subclass of Node should invoke `register_input_buffer` in its - `__init__` method. This method can be invoked multiple times to - register multiple input buffers. - - Args: - buffer_name (str): The name of the buffer - input_name (str): The name of the fetched message from the - corresponding buffer - trigger (bool): An trigger input means the node will wait - until the input is ready before processing. Otherwise, an - inessential input will not block the processing, instead - a None will be fetched if the buffer is not ready. - """ - buffer_info = BufferInfo(buffer_name, input_name, trigger) - self._input_buffers.append(buffer_info) - - def register_output_buffer(self, buffer_name: Union[str, List[str]]): - """Register one or multiple output buffers, so that the Node can - automatically send the output of the `process` method to these buffers. - - The subclass of Node should invoke `register_output_buffer` in its - `__init__` method. - - Args: - buffer_name (str|list): The name(s) of the output buffer(s). - """ - - if not isinstance(buffer_name, list): - buffer_name = [buffer_name] - - for name in buffer_name: - buffer_info = BufferInfo(name) - self._output_buffers.append(buffer_info) - - def register_event(self, - event_name: str, - is_keyboard: bool = False, - handler_func: Optional[Callable] = None): - """Register an event. All events used in the node need to be registered - in __init__(). If a callable handler is given, a thread will be create - to listen and handle the event when the node starts. - - Args: - Args: - event_name (str|int): The event name. If is_keyboard==True, - event_name should be a str (as char) or an int (as ascii) - is_keyboard (bool): Indicate whether it is an keyboard - event. If True, the argument event_name will be regarded as a - key indicator. - handler_func (callable, optional): The event handler function, - which should be a collable object with no arguments or - return values. Default: ``None``. - """ - event_info = EventInfo(event_name, is_keyboard, handler_func) - self._registered_events.append(event_info) - - def set_executor(self, executor): - """Assign the node to an executor so the node can access the buffers - and event manager of the executor. - - This method should be invoked by the executor instance. - - Args: - executor (:obj:`WebcamExecutor`): The executor to hold the node - """ - # Get partitioned buffer manager - buffer_names = [ - buffer.buffer_name - for buffer in self._input_buffers + self._output_buffers - ] - self._buffer_manager = executor.buffer_manager.get_sub_manager( - buffer_names) - - # Get event manager - self._event_manager = executor.event_manager - - def _get_input_from_buffer(self) -> Tuple[bool, Optional[Dict]]: - """Get and pack input data. - - The function returns a tuple (status, data). If the trigger buffers - are ready, the status flag will be True, and the packed data is a dict - whose items are buffer names and corresponding messages (unready - non-trigger buffers will give a `None`). Otherwise, the status flag is - False and the packed data is None. - - Returns: - tuple[bool, dict]: The first item is a bool value indicating - whether input is ready (i.e., all tirgger buffers are ready). The - second value is a dict of buffer names and messages. - """ - buffer_manager = self._buffer_manager - - if buffer_manager is None: - raise ValueError(f'Node "{self.name}": not set to an executor.') - - # Check that trigger buffers are ready - for buffer_info in self._input_buffers: - if buffer_info.trigger and buffer_manager.is_empty( - buffer_info.buffer_name): - return False, None - - # Default input - result = { - buffer_info.input_name: None - for buffer_info in self._input_buffers - } - - for buffer_info in self._input_buffers: - - while not buffer_manager.is_empty(buffer_info.buffer_name): - msg = buffer_manager.get(buffer_info.buffer_name, block=False) - if self.multi_input: - if result[buffer_info.input_name] is None: - result[buffer_info.input_name] = [] - result[buffer_info.input_name].append(msg) - else: - result[buffer_info.input_name] = msg - break - - # Return unsuccessful flag if any trigger input is unready - if buffer_info.trigger and result[buffer_info.input_name] is None: - return False, None - - return True, result - - def _send_output_to_buffers(self, output_msg): - """Send output of ``process()`` to the registered output buffers. - - Args: - output_msg (Message): output message - """ - for buffer_info in self._output_buffers: - buffer_name = buffer_info.buffer_name - self._buffer_manager.put_force(buffer_name, output_msg) - - @abstractmethod - def process(self, input_msgs: Dict[str, Message]) -> Union[Message, None]: - """The method that implements the function of the node. - - This method will be invoked when the node is enabled and the input - data is ready. All subclasses of Node should override this method. - - Args: - input_msgs (dict[str, :obj:`Message`]): The input data collected - from the buffers. For each item, the key is the `input_name` - of the registered input buffer, and the value is a Message - instance fetched from the buffer (or None if the buffer is - non-trigger and not ready). - - Returns: - Message: The output message of the node which will be send to all - registered output buffers. - """ - - def bypass(self, input_msgs: Dict[str, Message]) -> Union[Message, None]: - """The method that defines the node behavior when disabled. - - Note that a node must override this method if it has `enable_key`. - This method has the same signature as ``process()``. - - Args: - input_msgs (dict[str, :obj:`Message`]): The input data collected - from the buffers. For each item, the key is the `input_name` - of the registered input buffer, and the value is a Message - instance fetched from the buffer (or None if the buffer is - non-trigger and not ready). - - Returns: - Message: The output message of the node which will be send to all - registered output buffers. - """ - raise NotImplementedError - - def _get_node_info(self) -> Dict: - """Get route information of the node. - - Default information includes: - - ``'fps'``: The processing speed of the node - - ``'timestamp'``: The time that this method is invoked - - Subclasses can override this method to customize the node information. - - Returns: - dict: The items of node information - """ - info = {'fps': self._timer.report('_FPS_'), 'timestamp': time.time()} - return info - - def on_exit(self): - """This method will be invoked on event `_exit_`. - - Subclasses should override this method to specifying the exiting - behavior. - """ - - def run(self): - """Method representing the Node's activity. - - This method override the standard ``run()`` method of Thread. - Subclasses of :class:`Node` should not override this method in - subclasses. - """ - - self.logger.info('Process starts.') - - # Create event listener threads - for event_info in self._registered_events: - - if event_info.handler_func is None: - continue - - def event_listener(): - while True: - with self._event_manager.wait_and_handle( - event_info.event_name, event_info.is_keyboard): - event_info.handler_func() - - t_listener = Thread(target=event_listener, args=(), daemon=True) - t_listener.start() - self._event_listener_threads.append(t_listener) - - # Loop - while True: - # Exit - if self._event_manager.is_set('_exit_'): - self.on_exit() - break - - # Check if input is ready - input_status, input_msgs = self._get_input_from_buffer() - - # Input is not ready - if not input_status: - time.sleep(self.input_check_interval) - continue - - # If a VideoEndingMessage is received, broadcast the signal - # without invoking process() or bypass() - video_ending = False - for _, msg in input_msgs.items(): - if isinstance(msg, VideoEndingMessage): - self._send_output_to_buffers(msg) - video_ending = True - break - - if video_ending: - self.on_exit() - break - - # Check if enabled - if not self._enabled: - # Override bypass method to define node behavior when disabled - output_msg = self.bypass(input_msgs) - else: - with self._timer.timeit(): - with limit_max_fps(self.max_fps): - # Process - output_msg = self.process(input_msgs) - - if output_msg: - # Update route information - node_info = self._get_node_info() - output_msg.update_route_info(node=self, info=node_info) - - # Send output message - if output_msg is not None: - self._send_output_to_buffers(output_msg) - - self.logger.info('Process ends.') diff --git a/mmpose/apis/webcam/nodes/registry.py b/mmpose/apis/webcam/nodes/registry.py deleted file mode 100644 index 06d39fed63..0000000000 --- a/mmpose/apis/webcam/nodes/registry.py +++ /dev/null @@ -1,4 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from mmengine.registry import Registry - -NODES = Registry('node') diff --git a/mmpose/apis/webcam/nodes/visualizer_nodes/__init__.py b/mmpose/apis/webcam/nodes/visualizer_nodes/__init__.py deleted file mode 100644 index fad7e30376..0000000000 --- a/mmpose/apis/webcam/nodes/visualizer_nodes/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from .bigeye_effect_node import BigeyeEffectNode -from .notice_board_node import NoticeBoardNode -from .object_visualizer_node import ObjectVisualizerNode -from .sunglasses_effect_node import SunglassesEffectNode - -__all__ = [ - 'ObjectVisualizerNode', 'NoticeBoardNode', 'SunglassesEffectNode', - 'BigeyeEffectNode' -] diff --git a/mmpose/apis/webcam/nodes/visualizer_nodes/bigeye_effect_node.py b/mmpose/apis/webcam/nodes/visualizer_nodes/bigeye_effect_node.py deleted file mode 100644 index 3bbec3d670..0000000000 --- a/mmpose/apis/webcam/nodes/visualizer_nodes/bigeye_effect_node.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from itertools import groupby -from typing import Dict, List, Optional, Union - -import cv2 -import numpy as np - -from ...utils import get_eye_keypoint_ids -from ..base_visualizer_node import BaseVisualizerNode -from ..registry import NODES - - -@NODES.register_module() -class BigeyeEffectNode(BaseVisualizerNode): - """Apply big-eye effect to the objects with eye keypoints in the frame. - - Args: - name (str): The node name (also thread name) - input_buffer (str): The name of the input buffer - output_buffer (str|list): The name(s) of the output buffer(s) - enable_key (str|int, optional): Set a hot-key to toggle enable/disable - of the node. If an int value is given, it will be treated as an - ascii code of a key. Please note: (1) If ``enable_key`` is set, - the ``bypass()`` method need to be overridden to define the node - behavior when disabled; (2) Some hot-keys are reserved for - particular use. For example: 'q', 'Q' and 27 are used for exiting. - Default: ``None`` - enable (bool): Default enable/disable status. Default: ``True`` - kpt_thr (float): The score threshold of valid keypoints. Default: 0.5 - - Example:: - >>> cfg = dict( - ... type='SunglassesEffectNode', - ... name='sunglasses', - ... enable_key='s', - ... enable=False, - ... input_buffer='vis', - ... output_buffer='vis_sunglasses') - - >>> from mmpose.apis.webcam.nodes import NODES - >>> node = NODES.build(cfg) - """ - - def __init__(self, - name: str, - input_buffer: str, - output_buffer: Union[str, List[str]], - enable_key: Optional[Union[str, int]] = None, - enable: bool = True, - kpt_thr: float = 0.5): - - super().__init__( - name=name, - input_buffer=input_buffer, - output_buffer=output_buffer, - enable_key=enable_key, - enable=enable) - self.kpt_thr = kpt_thr - - def draw(self, input_msg): - canvas = input_msg.get_image() - - objects = input_msg.get_objects(lambda x: - ('keypoints' in x and 'bbox' in x)) - - for dataset_meta, group in groupby(objects, - lambda x: x['dataset_meta']): - left_eye_index, right_eye_index = get_eye_keypoint_ids( - dataset_meta) - canvas = self.apply_bigeye_effect(canvas, group, left_eye_index, - right_eye_index) - return canvas - - def apply_bigeye_effect(self, canvas: np.ndarray, objects: List[Dict], - left_eye_index: int, - right_eye_index: int) -> np.ndarray: - """Apply big-eye effect. - - Args: - canvas (np.ndarray): The image to apply the effect - objects (list[dict]): The object list with bbox and keypoints - - "bbox" ([K, 4(or 5)]): bbox in [x1, y1, x2, y2, (score)] - - "keypoints" ([K,3]): keypoints in [x, y, score] - left_eye_index (int): Keypoint index of left eye - right_eye_index (int): Keypoint index of right eye - - Returns: - np.ndarray: Processed image. - """ - - xx, yy = np.meshgrid( - np.arange(canvas.shape[1]), np.arange(canvas.shape[0])) - xx = xx.astype(np.float32) - yy = yy.astype(np.float32) - - for obj in objects: - bbox = obj['bbox'] - kpts = obj['keypoints'] - kpt_scores = obj['keypoint_scores'] - - if kpt_scores[left_eye_index] < self.kpt_thr or kpt_scores[ - right_eye_index] < self.kpt_thr: - continue - - kpt_leye = kpts[left_eye_index, :2] - kpt_reye = kpts[right_eye_index, :2] - for xc, yc in [kpt_leye, kpt_reye]: - - # distortion parameters - k1 = 0.001 - epe = 1e-5 - - scale = (bbox[2] - bbox[0])**2 + (bbox[3] - bbox[1])**2 - r2 = ((xx - xc)**2 + (yy - yc)**2) - r2 = (r2 + epe) / scale # normalized by bbox scale - - xx = (xx - xc) / (1 + k1 / r2) + xc - yy = (yy - yc) / (1 + k1 / r2) + yc - - canvas = cv2.remap( - canvas, - xx, - yy, - interpolation=cv2.INTER_AREA, - borderMode=cv2.BORDER_REPLICATE) - - return canvas diff --git a/mmpose/apis/webcam/nodes/visualizer_nodes/notice_board_node.py b/mmpose/apis/webcam/nodes/visualizer_nodes/notice_board_node.py deleted file mode 100644 index 0578ec38eb..0000000000 --- a/mmpose/apis/webcam/nodes/visualizer_nodes/notice_board_node.py +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from typing import List, Optional, Tuple, Union - -import cv2 -import numpy as np -from mmcv import color_val - -from ...utils import FrameMessage -from ..base_visualizer_node import BaseVisualizerNode -from ..registry import NODES - - -@NODES.register_module() -class NoticeBoardNode(BaseVisualizerNode): - """Show text messages in the frame. - - Args: - name (str): The node name (also thread name) - input_buffer (str): The name of the input buffer - output_buffer (str|list): The name(s) of the output buffer(s) - enable_key (str|int, optional): Set a hot-key to toggle enable/disable - of the node. If an int value is given, it will be treated as an - ascii code of a key. Please note: (1) If ``enable_key`` is set, - the ``bypass()`` method need to be overridden to define the node - behavior when disabled; (2) Some hot-keys are reserved for - particular use. For example: 'q', 'Q' and 27 are used for exiting. - Default: ``None`` - enable (bool): Default enable/disable status. Default: ``True`` - content_lines (list[str], optional): The lines of text message to show - in the frame. If not given, a default message will be shown. - Default: ``None`` - x_offset (int): The position of the notice board's left border in - pixels. Default: 20 - y_offset (int): The position of the notice board's top border in - pixels. Default: 20 - y_delta (int): The line height in pixels. Default: 15 - text_color (str|tuple): The font color represented in a color name or - a BGR tuple. Default: ``'black'`` - backbround_color (str|tuple): The background color represented in a - color name or a BGR tuple. Default: (255, 183, 0) - text_scale (float): The font scale factor that is multiplied by the - base size. Default: 0.4 - - Example:: - >>> cfg = dict( - ... type='NoticeBoardNode', - ... name='instruction', - ... enable_key='h', - ... enable=True, - ... input_buffer='vis_bigeye', - ... output_buffer='vis_notice', - ... content_lines=[ - ... 'This is a demo for pose visualization and simple image ' - ... 'effects. Have fun!', '', 'Hot-keys:', - ... '"v": Pose estimation result visualization', - ... '"s": Sunglasses effect B-)', '"b": Big-eye effect 0_0', - ... '"h": Show help information', - ... '"m": Show diagnostic information', '"q": Exit' - ... ], - ... ) - - >>> from mmpose.apis.webcam.nodes import NODES - >>> node = NODES.build(cfg) - """ - - default_content_lines = ['This is a notice board!'] - - def __init__(self, - name: str, - input_buffer: str, - output_buffer: Union[str, List[str]], - enable_key: Optional[Union[str, int]] = None, - enable: bool = True, - content_lines: Optional[List[str]] = None, - x_offset: int = 20, - y_offset: int = 20, - y_delta: int = 15, - text_color: Union[str, Tuple[int, int, int]] = 'black', - background_color: Union[str, Tuple[int, int, - int]] = (255, 183, 0), - text_scale: float = 0.4): - super().__init__( - name=name, - input_buffer=input_buffer, - output_buffer=output_buffer, - enable_key=enable_key, - enable=enable) - - self.x_offset = x_offset - self.y_offset = y_offset - self.y_delta = y_delta - self.text_color = color_val(text_color) - self.background_color = color_val(background_color) - self.text_scale = text_scale - - if content_lines: - self.content_lines = content_lines - else: - self.content_lines = self.default_content_lines - - def draw(self, input_msg: FrameMessage) -> np.ndarray: - img = input_msg.get_image() - canvas = np.full(img.shape, self.background_color, dtype=img.dtype) - - x = self.x_offset - y = self.y_offset - - max_len = max([len(line) for line in self.content_lines]) - - def _put_line(line=''): - nonlocal y - cv2.putText(canvas, line, (x, y), cv2.FONT_HERSHEY_DUPLEX, - self.text_scale, self.text_color, 1) - y += self.y_delta - - for line in self.content_lines: - _put_line(line) - - x1 = max(0, self.x_offset) - x2 = min(img.shape[1], int(x + max_len * self.text_scale * 20)) - y1 = max(0, self.y_offset - self.y_delta) - y2 = min(img.shape[0], y) - - src1 = canvas[y1:y2, x1:x2] - src2 = img[y1:y2, x1:x2] - img[y1:y2, x1:x2] = cv2.addWeighted(src1, 0.5, src2, 0.5, 0) - - return img diff --git a/mmpose/apis/webcam/nodes/visualizer_nodes/object_visualizer_node.py b/mmpose/apis/webcam/nodes/visualizer_nodes/object_visualizer_node.py deleted file mode 100644 index ef28a0804c..0000000000 --- a/mmpose/apis/webcam/nodes/visualizer_nodes/object_visualizer_node.py +++ /dev/null @@ -1,341 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import math -from itertools import groupby -from typing import Dict, List, Optional, Tuple, Union - -import cv2 -import mmcv -import numpy as np - -from ...utils import FrameMessage -from ..base_visualizer_node import BaseVisualizerNode -from ..registry import NODES - - -def imshow_bboxes(img, - bboxes, - labels=None, - colors='green', - text_color='white', - thickness=1, - font_scale=0.5): - """Draw bboxes with labels (optional) on an image. This is a wrapper of - mmcv.imshow_bboxes. - - Args: - img (str or ndarray): The image to be displayed. - bboxes (ndarray): ndarray of shape (k, 4), each row is a bbox in - format [x1, y1, x2, y2]. - labels (str or list[str], optional): labels of each bbox. - colors (list[str or tuple or :obj:`Color`]): A list of colors. - text_color (str or tuple or :obj:`Color`): Color of texts. - thickness (int): Thickness of lines. - font_scale (float): Font scales of texts. - - Returns: - ndarray: The image with bboxes drawn on it. - """ - - # adapt to mmcv.imshow_bboxes input format - bboxes = np.split( - bboxes, bboxes.shape[0], axis=0) if bboxes.shape[0] > 0 else [] - if not isinstance(colors, list): - colors = [colors for _ in range(len(bboxes))] - colors = [mmcv.color_val(c) for c in colors] - assert len(bboxes) == len(colors) - - img = mmcv.imshow_bboxes( - img, - bboxes, - colors, - top_k=-1, - thickness=thickness, - show=False, - out_file=None) - - if labels is not None: - if not isinstance(labels, list): - labels = [labels for _ in range(len(bboxes))] - assert len(labels) == len(bboxes) - - for bbox, label, color in zip(bboxes, labels, colors): - if label is None: - continue - bbox_int = bbox[0, :4].astype(np.int32) - # roughly estimate the proper font size - text_size, text_baseline = cv2.getTextSize(label, - cv2.FONT_HERSHEY_DUPLEX, - font_scale, thickness) - text_x1 = bbox_int[0] - text_y1 = max(0, bbox_int[1] - text_size[1] - text_baseline) - text_x2 = bbox_int[0] + text_size[0] - text_y2 = text_y1 + text_size[1] + text_baseline - cv2.rectangle(img, (text_x1, text_y1), (text_x2, text_y2), color, - cv2.FILLED) - cv2.putText(img, label, (text_x1, text_y2 - text_baseline), - cv2.FONT_HERSHEY_DUPLEX, font_scale, - mmcv.color_val(text_color), thickness) - - return img - - -def imshow_keypoints(img, - pose_result, - skeleton=None, - kpt_score_thr=0.3, - pose_kpt_color=None, - pose_link_color=None, - radius=4, - thickness=1, - show_keypoint_weight=False): - """Draw keypoints and links on an image. - - Args: - img (str or Tensor): The image to draw poses on. If an image array - is given, id will be modified in-place. - pose_result (list[kpts]): The poses to draw. Each element kpts is - a set of K keypoints as an Kx3 numpy.ndarray, where each - keypoint is represented as x, y, score. - kpt_score_thr (float, optional): Minimum score of keypoints - to be shown. Default: 0.3. - pose_kpt_color (np.array[Nx3]`): Color of N keypoints. If None, - the keypoint will not be drawn. - pose_link_color (np.array[Mx3]): Color of M links. If None, the - links will not be drawn. - thickness (int): Thickness of lines. - """ - - img = mmcv.imread(img) - img_h, img_w, _ = img.shape - - for kpts in pose_result: - - kpts = np.array(kpts, copy=False) - - # draw each point on image - if pose_kpt_color is not None: - assert len(pose_kpt_color) == len(kpts) - - for kid, kpt in enumerate(kpts): - x_coord, y_coord, kpt_score = int(kpt[0]), int(kpt[1]), kpt[2] - - if kpt_score < kpt_score_thr or pose_kpt_color[kid] is None: - # skip the point that should not be drawn - continue - - color = tuple(int(c) for c in pose_kpt_color[kid]) - if show_keypoint_weight: - img_copy = img.copy() - cv2.circle(img_copy, (int(x_coord), int(y_coord)), radius, - color, -1) - transparency = max(0, min(1, kpt_score)) - cv2.addWeighted( - img_copy, - transparency, - img, - 1 - transparency, - 0, - dst=img) - else: - cv2.circle(img, (int(x_coord), int(y_coord)), radius, - color, -1) - - # draw links - if skeleton is not None and pose_link_color is not None: - assert len(pose_link_color) == len(skeleton) - - for sk_id, sk in enumerate(skeleton): - pos1 = (int(kpts[sk[0], 0]), int(kpts[sk[0], 1])) - pos2 = (int(kpts[sk[1], 0]), int(kpts[sk[1], 1])) - - if (pos1[0] <= 0 or pos1[0] >= img_w or pos1[1] <= 0 - or pos1[1] >= img_h or pos2[0] <= 0 or pos2[0] >= img_w - or pos2[1] <= 0 or pos2[1] >= img_h - or kpts[sk[0], 2] < kpt_score_thr - or kpts[sk[1], 2] < kpt_score_thr - or pose_link_color[sk_id] is None): - # skip the link that should not be drawn - continue - color = tuple(int(c) for c in pose_link_color[sk_id]) - if show_keypoint_weight: - img_copy = img.copy() - X = (pos1[0], pos2[0]) - Y = (pos1[1], pos2[1]) - mX = np.mean(X) - mY = np.mean(Y) - length = ((Y[0] - Y[1])**2 + (X[0] - X[1])**2)**0.5 - angle = math.degrees(math.atan2(Y[0] - Y[1], X[0] - X[1])) - stickwidth = 2 - polygon = cv2.ellipse2Poly( - (int(mX), int(mY)), (int(length / 2), int(stickwidth)), - int(angle), 0, 360, 1) - cv2.fillConvexPoly(img_copy, polygon, color) - transparency = max( - 0, min(1, 0.5 * (kpts[sk[0], 2] + kpts[sk[1], 2]))) - cv2.addWeighted( - img_copy, - transparency, - img, - 1 - transparency, - 0, - dst=img) - else: - cv2.line(img, pos1, pos2, color, thickness=thickness) - - return img - - -@NODES.register_module() -class ObjectVisualizerNode(BaseVisualizerNode): - """Visualize the bounding box and keypoints of objects. - - Args: - name (str): The node name (also thread name) - input_buffer (str): The name of the input buffer - output_buffer (str|list): The name(s) of the output buffer(s) - enable_key (str|int, optional): Set a hot-key to toggle enable/disable - of the node. If an int value is given, it will be treated as an - ascii code of a key. Please note: (1) If ``enable_key`` is set, - the ``bypass()`` method need to be overridden to define the node - behavior when disabled; (2) Some hot-keys are reserved for - particular use. For example: 'q', 'Q' and 27 are used for exiting. - Default: ``None`` - enable (bool): Default enable/disable status. Default: ``True`` - show_bbox (bool): Set ``True`` to show the bboxes of detection - objects. Default: ``True`` - show_keypoint (bool): Set ``True`` to show the pose estimation - results. Default: ``True`` - must_have_bbox (bool): Only show objects with keypoints. - Default: ``False`` - kpt_thr (float): The threshold of keypoint score. Default: 0.3 - radius (int): The radius of keypoint. Default: 4 - thickness (int): The thickness of skeleton. Default: 2 - bbox_color (str|tuple|dict): The color of bboxes. If a single color is - given (a str like 'green' or a BGR tuple like (0, 255, 0)), it - will be used for all bboxes. If a dict is given, it will be used - as a map from class labels to bbox colors. If not given, a default - color map will be used. Default: ``None`` - - Example:: - >>> cfg = dict( - ... type='ObjectVisualizerNode', - ... name='object visualizer', - ... enable_key='v', - ... enable=True, - ... show_bbox=True, - ... must_have_keypoint=False, - ... show_keypoint=True, - ... input_buffer='frame', - ... output_buffer='vis') - - >>> from mmpose.apis.webcam.nodes import NODES - >>> node = NODES.build(cfg) - """ - - default_bbox_color = { - 'person': (148, 139, 255), - 'cat': (255, 255, 0), - 'dog': (255, 255, 0), - } - - def __init__(self, - name: str, - input_buffer: str, - output_buffer: Union[str, List[str]], - enable_key: Optional[Union[str, int]] = None, - enable: bool = True, - show_bbox: bool = True, - show_keypoint: bool = True, - must_have_keypoint: bool = False, - kpt_thr: float = 0.3, - radius: int = 4, - thickness: int = 2, - bbox_color: Optional[Union[str, Tuple, Dict]] = 'green'): - - super().__init__( - name=name, - input_buffer=input_buffer, - output_buffer=output_buffer, - enable_key=enable_key, - enable=enable) - - self.kpt_thr = kpt_thr - self.bbox_color = bbox_color - self.show_bbox = show_bbox - self.show_keypoint = show_keypoint - self.must_have_keypoint = must_have_keypoint - self.radius = radius - self.thickness = thickness - - def _draw_bbox(self, canvas: np.ndarray, input_msg: FrameMessage): - """Draw object bboxes.""" - - if self.must_have_keypoint: - objects = input_msg.get_objects( - lambda x: 'bbox' in x and 'keypoints' in x) - else: - objects = input_msg.get_objects(lambda x: 'bbox' in x) - # return if there is no detected objects - if not objects: - return canvas - - bboxes = [obj['bbox'] for obj in objects] - labels = [obj.get('label', None) for obj in objects] - default_color = (0, 255, 0) - - # Get bbox colors - if isinstance(self.bbox_color, dict): - colors = [ - self.bbox_color.get(label, default_color) for label in labels - ] - else: - colors = self.bbox_color - - imshow_bboxes( - canvas, - np.vstack(bboxes), - labels=labels, - colors=colors, - text_color='white', - font_scale=0.5) - - return canvas - - def _draw_keypoint(self, canvas: np.ndarray, input_msg: FrameMessage): - """Draw object keypoints.""" - objects = input_msg.get_objects(lambda x: 'pose_model_cfg' in x) - - # return if there is no object with keypoints - if not objects: - return canvas - - for model_cfg, group in groupby(objects, - lambda x: x['pose_model_cfg']): - dataset_info = objects[0]['dataset_meta'] - keypoints = [ - np.concatenate( - (obj['keypoints'], obj['keypoint_scores'][:, None]), - axis=1) for obj in group - ] - imshow_keypoints( - canvas, - keypoints, - skeleton=dataset_info['skeleton_links'], - kpt_score_thr=self.kpt_thr, - pose_kpt_color=dataset_info['keypoint_colors'], - pose_link_color=dataset_info['skeleton_link_colors'], - radius=self.radius, - thickness=self.thickness) - - return canvas - - def draw(self, input_msg: FrameMessage) -> np.ndarray: - canvas = input_msg.get_image() - - if self.show_bbox: - canvas = self._draw_bbox(canvas, input_msg) - - if self.show_keypoint: - canvas = self._draw_keypoint(canvas, input_msg) - - return canvas diff --git a/mmpose/apis/webcam/nodes/visualizer_nodes/sunglasses_effect_node.py b/mmpose/apis/webcam/nodes/visualizer_nodes/sunglasses_effect_node.py deleted file mode 100644 index 7c011177f5..0000000000 --- a/mmpose/apis/webcam/nodes/visualizer_nodes/sunglasses_effect_node.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from itertools import groupby -from typing import Dict, List, Optional, Union - -import cv2 -import numpy as np - -from ...utils import get_eye_keypoint_ids, load_image_from_disk_or_url -from ..base_visualizer_node import BaseVisualizerNode -from ..registry import NODES - - -@NODES.register_module() -class SunglassesEffectNode(BaseVisualizerNode): - """Apply sunglasses effect (draw sunglasses at the facial area)to the - objects with eye keypoints in the frame. - - Args: - name (str): The node name (also thread name) - input_buffer (str): The name of the input buffer - output_buffer (str|list): The name(s) of the output buffer(s) - enable_key (str|int, optional): Set a hot-key to toggle enable/disable - of the node. If an int value is given, it will be treated as an - ascii code of a key. Please note: - 1. If enable_key is set, the bypass method need to be - overridden to define the node behavior when disabled - 2. Some hot-key has been use for particular use. For example: - 'q', 'Q' and 27 are used for quit - Default: ``None`` - enable (bool): Default enable/disable status. Default: ``True``. - kpt_thr (float): The score threshold of valid keypoints. Default: 0.5 - resource_img_path (str, optional): The resource image path or url. - The image should be a pair of sunglasses with white background. - If not specified, the url of a default image will be used. See - ``SunglassesNode.default_resource_img_path``. Default: ``None`` - - Example:: - >>> cfg = dict( - ... type='SunglassesEffectNode', - ... name='sunglasses', - ... enable_key='s', - ... enable=False, - ... input_buffer='vis', - ... output_buffer='vis_sunglasses') - - >>> from mmpose.apis.webcam.nodes import NODES - >>> node = NODES.build(cfg) - """ - - # The image attributes to: - # "https://www.vecteezy.com/vector-art/1932353-summer-sunglasses- - # accessory-isolated-icon" by Vecteezy - default_resource_img_path = ( - 'https://user-images.githubusercontent.com/15977946/' - '170850839-acc59e26-c6b3-48c9-a9ec-87556edb99ed.jpg') - - def __init__(self, - name: str, - input_buffer: str, - output_buffer: Union[str, List[str]], - enable_key: Optional[Union[str, int]] = None, - enable: bool = True, - kpt_thr: float = 0.5, - resource_img_path: Optional[str] = None): - - super().__init__( - name=name, - input_buffer=input_buffer, - output_buffer=output_buffer, - enable_key=enable_key, - enable=enable) - - if resource_img_path is None: - resource_img_path = self.default_resource_img_path - - self.resource_img = load_image_from_disk_or_url(resource_img_path) - self.kpt_thr = kpt_thr - - def draw(self, input_msg): - canvas = input_msg.get_image() - - objects = input_msg.get_objects(lambda x: 'keypoints' in x) - - for dataset_meta, group in groupby(objects, - lambda x: x['dataset_meta']): - left_eye_index, right_eye_index = get_eye_keypoint_ids( - dataset_meta) - canvas = self.apply_sunglasses_effect(canvas, group, - left_eye_index, - right_eye_index) - return canvas - - def apply_sunglasses_effect(self, canvas: np.ndarray, objects: List[Dict], - left_eye_index: int, - right_eye_index: int) -> np.ndarray: - """Apply sunglasses effect. - - Args: - canvas (np.ndarray): The image to apply the effect - objects (list[dict]): The object list with keypoints - - "keypoints" ([K,3]): keypoints in [x, y, score] - left_eye_index (int): Keypoint index of the left eye - right_eye_index (int): Keypoint index of the right eye - - Returns: - np.ndarray: Processed image - """ - - hm, wm = self.resource_img.shape[:2] - # anchor points in the sunglasses image - pts_src = np.array([[0.3 * wm, 0.3 * hm], [0.3 * wm, 0.7 * hm], - [0.7 * wm, 0.3 * hm], [0.7 * wm, 0.7 * hm]], - dtype=np.float32) - - for obj in objects: - kpts = obj['keypoints'] - kpt_scores = obj['keypoint_scores'] - - if kpt_scores[left_eye_index] < self.kpt_thr or kpt_scores[ - right_eye_index] < self.kpt_thr: - continue - - kpt_leye = kpts[left_eye_index, :2] - kpt_reye = kpts[right_eye_index, :2] - # orthogonal vector to the left-to-right eyes - vo = 0.5 * (kpt_reye - kpt_leye)[::-1] * [-1, 1] - - # anchor points in the image by eye positions - pts_tar = np.vstack( - [kpt_reye + vo, kpt_reye - vo, kpt_leye + vo, kpt_leye - vo]) - - h_mat, _ = cv2.findHomography(pts_src, pts_tar) - patch = cv2.warpPerspective( - self.resource_img, - h_mat, - dsize=(canvas.shape[1], canvas.shape[0]), - borderValue=(255, 255, 255)) - # mask the white background area in the patch with a threshold 200 - mask = cv2.cvtColor(patch, cv2.COLOR_BGR2GRAY) - mask = (mask < 200).astype(np.uint8) - canvas = cv2.copyTo(patch, mask, canvas) - - return canvas diff --git a/mmpose/apis/webcam/utils/__init__.py b/mmpose/apis/webcam/utils/__init__.py deleted file mode 100644 index 2911bcd5bf..0000000000 --- a/mmpose/apis/webcam/utils/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from .buffer import BufferManager -from .event import EventManager -from .image_capture import ImageCapture -from .message import FrameMessage, Message, VideoEndingMessage -from .misc import (copy_and_paste, expand_and_clamp, get_cached_file_path, - get_config_path, is_image_file, limit_max_fps, - load_image_from_disk_or_url, screen_matting) -from .pose import (get_eye_keypoint_ids, get_face_keypoint_ids, - get_hand_keypoint_ids, get_mouth_keypoint_ids, - get_wrist_keypoint_ids) - -__all__ = [ - 'BufferManager', 'EventManager', 'FrameMessage', 'Message', - 'limit_max_fps', 'VideoEndingMessage', 'load_image_from_disk_or_url', - 'get_cached_file_path', 'screen_matting', 'get_config_path', - 'expand_and_clamp', 'copy_and_paste', 'is_image_file', 'ImageCapture', - 'get_eye_keypoint_ids', 'get_face_keypoint_ids', 'get_wrist_keypoint_ids', - 'get_mouth_keypoint_ids', 'get_hand_keypoint_ids' -] diff --git a/mmpose/apis/webcam/utils/buffer.py b/mmpose/apis/webcam/utils/buffer.py deleted file mode 100644 index f7f8b9864e..0000000000 --- a/mmpose/apis/webcam/utils/buffer.py +++ /dev/null @@ -1,203 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from functools import wraps -from queue import Queue -from typing import Any, Dict, List, Optional - -from mmengine import is_seq_of - -__all__ = ['BufferManager'] - - -def check_buffer_registered(exist=True): - """A function wrapper to check the buffer existence before it is being used - by the wrapped function. - - Args: - exist (bool): If set to ``True``, assert the buffer exists; if set to - ``False``, assert the buffer does not exist. Default: ``True`` - """ - - def wrapper(func): - - @wraps(func) - def wrapped(manager, name, *args, **kwargs): - if exist: - # Assert buffer exist - if name not in manager: - raise ValueError(f'Fail to call {func.__name__}: ' - f'buffer "{name}" is not registered.') - else: - # Assert buffer not exist - if name in manager: - raise ValueError(f'Fail to call {func.__name__}: ' - f'buffer "{name}" is already registered.') - return func(manager, name, *args, **kwargs) - - return wrapped - - return wrapper - - -class Buffer(Queue): - - def put_force(self, item: Any): - """Force to put an item into the buffer. - - If the buffer is already full, the earliest item in the buffer will be - remove to make room for the incoming item. - - Args: - item (any): The item to put into the buffer - """ - with self.mutex: - if self.maxsize > 0: - while self._qsize() >= self.maxsize: - _ = self._get() - self.unfinished_tasks -= 1 - - self._put(item) - self.unfinished_tasks += 1 - self.not_empty.notify() - - -class BufferManager(): - """A helper class to manage multiple buffers. - - Parameters: - buffer_type (type): The class to build buffer instances. Default: - :class:`mmpose.apis.webcam.utils.buffer.Buffer`. - buffers (dict, optional): Create :class:`BufferManager` from existing - buffers. Each item should a buffer name and the buffer. If not - given, an empty buffer manager will be create. Default: ``None`` - """ - - def __init__(self, - buffer_type: type = Buffer, - buffers: Optional[Dict] = None): - self.buffer_type = buffer_type - if buffers is None: - self._buffers = {} - else: - if is_seq_of(list(buffers.values()), buffer_type): - self._buffers = buffers.copy() - else: - raise ValueError('The values of buffers should be instance ' - f'of {buffer_type}') - - def __contains__(self, name): - return name in self._buffers - - @check_buffer_registered(False) - def register_buffer(self, name, maxsize: int = 0): - """Register a buffer. - - If the buffer already exists, an ValueError will be raised. - - Args: - name (any): The buffer name - maxsize (int): The capacity of the buffer. If set to 0, the - capacity is unlimited. Default: 0 - """ - self._buffers[name] = self.buffer_type(maxsize) - - @check_buffer_registered() - def put(self, name, item, block: bool = True, timeout: float = None): - """Put an item into specified buffer. - - Args: - name (any): The buffer name - item (any): The item to put into the buffer - block (bool): If set to ``True``, block if necessary util a free - slot is available in the target buffer. It blocks at most - ``timeout`` seconds and raises the ``Full`` exception. - Otherwise, put an item on the queue if a free slot is - immediately available, else raise the ``Full`` exception. - Default: ``True`` - timeout (float, optional): The most waiting time in seconds if - ``block`` is ``True``. Default: ``None`` - """ - self._buffers[name].put(item, block, timeout) - - @check_buffer_registered() - def put_force(self, name, item): - """Force to put an item into specified buffer. If the buffer was full, - the earliest item within the buffer will be popped out to make a free - slot. - - Args: - name (any): The buffer name - item (any): The item to put into the buffer - """ - self._buffers[name].put_force(item) - - @check_buffer_registered() - def get(self, name, block: bool = True, timeout: float = None) -> Any: - """Remove an return an item from the specified buffer. - - Args: - name (any): The buffer name - block (bool): If set to ``True``, block if necessary until an item - is available in the target buffer. It blocks at most - ``timeout`` seconds and raises the ``Empty`` exception. - Otherwise, return an item if one is immediately available, - else raise the ``Empty`` exception. Default: ``True`` - timeout (float, optional): The most waiting time in seconds if - ``block`` is ``True``. Default: ``None`` - - Returns: - any: The returned item. - """ - return self._buffers[name].get(block, timeout) - - @check_buffer_registered() - def is_empty(self, name) -> bool: - """Check if a buffer is empty. - - Args: - name (any): The buffer name - - Returns: - bool: Weather the buffer is empty. - """ - return self._buffers[name].empty() - - @check_buffer_registered() - def is_full(self, name): - """Check if a buffer is full. - - Args: - name (any): The buffer name - - Returns: - bool: Weather the buffer is full. - """ - return self._buffers[name].full() - - def get_sub_manager(self, buffer_names: List[str]) -> 'BufferManager': - """Return a :class:`BufferManager` instance that covers a subset of the - buffers in the parent. The is usually used to partially share the - buffers of the executor to the node. - - Args: - buffer_names (list): The list of buffers to create the sub manager - - Returns: - BufferManager: The created sub buffer manager. - """ - buffers = {name: self._buffers[name] for name in buffer_names} - return BufferManager(self.buffer_type, buffers) - - def get_info(self): - """Returns the information of all buffers in the manager. - - Returns: - dict[any, dict]: Each item is a buffer name and the information - dict of that buffer. - """ - buffer_info = {} - for name, buffer in self._buffers.items(): - buffer_info[name] = { - 'size': buffer.qsize(), - 'maxsize': buffer.maxsize - } - return buffer_info diff --git a/mmpose/apis/webcam/utils/event.py b/mmpose/apis/webcam/utils/event.py deleted file mode 100644 index b8e88e1d8b..0000000000 --- a/mmpose/apis/webcam/utils/event.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import logging -from collections import defaultdict -from contextlib import contextmanager -from threading import Event -from typing import Optional - -logger = logging.getLogger('Event') - - -class EventManager(): - """A helper class to manage events. - - :class:`EventManager` provides interfaces to register, set, clear and - check events by name. - """ - - def __init__(self): - self._events = defaultdict(Event) - - def register_event(self, event_name: str, is_keyboard: bool = False): - """Register an event. A event must be registered first before being - set, cleared or checked. - - Args: - event_name (str): The indicator of the event. The name should be - unique in one :class:`EventManager` instance - is_keyboard (bool): Specify weather it is a keyboard event. If so, - the ``event_name`` should be the key value, and the indicator - will be set as ``'_keyboard_{event_name}'``. Otherwise, the - ``event_name`` will be directly used as the indicator. - Default: ``False`` - """ - if is_keyboard: - event_name = self._get_keyboard_event_name(event_name) - self._events[event_name] = Event() - - def set(self, event_name: str, is_keyboard: bool = False): - """Set the internal flag of an event to ``True``. - - Args: - event_name (str): The indicator of the event - is_keyboard (bool): Specify weather it is a keyboard event. See - ``register_event()`` for details. Default: False - """ - if is_keyboard: - event_name = self._get_keyboard_event_name(event_name) - self._events[event_name].set() - logger.info(f'Event {event_name} is set.') - - def wait(self, - event_name: str = None, - is_keyboard: bool = False, - timeout: Optional[float] = None) -> bool: - """Block until the internal flag of an event is ``True``. - - Args: - event_name (str): The indicator of the event - is_keyboard (bool): Specify weather it is a keyboard event. See - ``register_event()`` for details. Default: False - timeout (float, optional): The optional maximum blocking time in - seconds. Default: ``None`` - - Returns: - bool: The internal event flag on exit. - """ - if is_keyboard: - event_name = self._get_keyboard_event_name(event_name) - return self._events[event_name].wait(timeout) - - def is_set(self, - event_name: str = None, - is_keyboard: Optional[bool] = False) -> bool: - """Check weather the internal flag of an event is ``True``. - - Args: - event_name (str): The indicator of the event - is_keyboard (bool): Specify weather it is a keyboard event. See - ``register_event()`` for details. Default: False - Returns: - bool: The internal event flag. - """ - if is_keyboard: - event_name = self._get_keyboard_event_name(event_name) - return self._events[event_name].is_set() - - def clear(self, - event_name: str = None, - is_keyboard: Optional[bool] = False): - """Reset the internal flag of en event to False. - - Args: - event_name (str): The indicator of the event - is_keyboard (bool): Specify weather it is a keyboard event. See - ``register_event()`` for details. Default: False - """ - if is_keyboard: - event_name = self._get_keyboard_event_name(event_name) - self._events[event_name].clear() - logger.info(f'Event {event_name} is cleared.') - - @staticmethod - def _get_keyboard_event_name(key): - """Get keyboard event name from the key value.""" - return f'_keyboard_{chr(key) if isinstance(key,int) else key}' - - @contextmanager - def wait_and_handle(self, - event_name: str = None, - is_keyboard: Optional[bool] = False): - """Context manager that blocks until an evenet is set ``True`` and then - goes into the context. - - The internal event flag will be reset ``False`` automatically before - entering the context. - - Args: - event_name (str): The indicator of the event - is_keyboard (bool): Specify weather it is a keyboard event. See - ``register_event()`` for details. Default: False - - Example:: - >>> from mmpose.apis.webcam.utils import EventManager - >>> manager = EventManager() - >>> manager.register_event('q', is_keybard=True) - - >>> # Once the keyboard event `q` is set, ``wait_and_handle`` - >>> # will reset the event and enter the context to invoke - >>> # ``foo()`` - >>> with manager.wait_and_handle('q', is_keybard=True): - ... foo() - """ - self.wait(event_name, is_keyboard) - try: - yield - finally: - self.clear(event_name, is_keyboard) diff --git a/mmpose/apis/webcam/utils/image_capture.py b/mmpose/apis/webcam/utils/image_capture.py deleted file mode 100644 index fb28acff94..0000000000 --- a/mmpose/apis/webcam/utils/image_capture.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from typing import Union - -import cv2 -import numpy as np - -from .misc import load_image_from_disk_or_url - - -class ImageCapture: - """A mock-up of cv2.VideoCapture that always return a const image. - - Args: - image (str | ndarray): The image path or image data - """ - - def __init__(self, image: Union[str, np.ndarray]): - if isinstance(image, str): - self.image = load_image_from_disk_or_url(image) - else: - self.image = image - - def isOpened(self): - return (self.image is not None) - - def read(self): - return True, self.image.copy() - - def release(self): - pass - - def get(self, propId): - if propId == cv2.CAP_PROP_FRAME_WIDTH: - return self.image.shape[1] - elif propId == cv2.CAP_PROP_FRAME_HEIGHT: - return self.image.shape[0] - elif propId == cv2.CAP_PROP_FPS: - return np.nan - else: - raise NotImplementedError() diff --git a/mmpose/apis/webcam/utils/message.py b/mmpose/apis/webcam/utils/message.py deleted file mode 100644 index 8961ea39c2..0000000000 --- a/mmpose/apis/webcam/utils/message.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import time -import uuid -import warnings -from typing import Callable, Dict, List, Optional - -import numpy as np - -Filter = Callable[[Dict], bool] - - -class Message(): - """Message base class. - - All message class should inherit this class. The basic use of a Message - instance is to carray a piece of text message (self.msg) and a dict that - stores structured data (self.data), e.g. frame image, model prediction, - et al. - - A message may also hold route information, which is composed of - information of all nodes the message has passed through. - - Parameters: - msg (str): The text message. - data (dict, optional): The structured data. - """ - - def __init__(self, msg: str = '', data: Optional[Dict] = None): - self.msg = msg - self.data = data if data else {} - self.route_info = [] - self.timestamp = time.time() - self.id = uuid.uuid1() - - def update_route_info(self, - node=None, - node_name: Optional[str] = None, - node_type: Optional[str] = None, - info: Optional[Dict] = None): - """Append new node information to the route information. - - Args: - node (Node, optional): An instance of Node that provides basic - information like the node name and type. Default: ``None``. - node_name (str, optional): The node name. If node is given, - node_name will be ignored. Default: ``None``. - node_type (str, optional): The class name of the node. If node - is given, node_type will be ignored. Default: ``None``. - info (dict, optional): The node information, which is usually - given by node.get_node_info(). Default: ``None``. - """ - if node is not None: - if node_name is not None or node_type is not None: - warnings.warn( - '`node_name` and `node_type` will be overridden if node ' - 'is provided.') - node_name = node.name - node_type = node.__class__.__name__ - - node_info = {'node': node_name, 'node_type': node_type, 'info': info} - self.route_info.append(node_info) - - def set_route_info(self, route_info: List[Dict]): - """Directly set the entire route information. - - Args: - route_info (list): route information to set to the message. - """ - self.route_info = route_info - - def merge_route_info(self, route_info: List[Dict]): - """Merge the given route information into the original one of the - message. This is used for combining route information from multiple - messages. The node information in the route will be reordered according - to their timestamps. - - Args: - route_info (list): route information to merge. - """ - self.route_info += route_info - self.route_info.sort(key=lambda x: x.get('timestamp', np.inf)) - - def get_route_info(self) -> List: - return self.route_info.copy() - - -class VideoEndingMessage(Message): - """The special message to indicate the ending of the input video.""" - - -class FrameMessage(Message): - """The message to store information of a video frame.""" - - def __init__(self, img): - super().__init__(data=dict(image=img, objects={}, model_cfgs={})) - - def get_image(self) -> np.ndarray: - """Get the frame image. - - Returns: - np.ndarray: The frame image. - """ - return self.data.get('image', None) - - def set_image(self, img): - """Set the frame image to the message. - - Args: - img (np.ndarray): The frame image. - """ - self.data['image'] = img - - def set_objects(self, objects: List[Dict]): - """Set the object information. The old object information will be - cleared. - - Args: - objects (list[dict]): A list of object information - - See also :func:`update_objects`. - """ - self.data['objects'] = {} - self.update_objects(objects) - - def update_objects(self, objects: List[Dict]): - """Update object information. - - Each object will be assigned an unique ID if it does not has one. If - an object's ID already exists in ``self.data['objects']``, the object - information will be updated; otherwise it will be added as a new - object. - - Args: - objects (list[dict]): A list of object information - """ - for obj in objects: - if '_id_' in obj: - # get the object id if it exists - obj_id = obj['_id_'] - else: - # otherwise assign a new object id - obj_id = uuid.uuid1() - obj['_id_'] = obj_id - self.data['objects'][obj_id] = obj - - def get_objects(self, obj_filter: Optional[Filter] = None) -> List[Dict]: - """Get object information from the frame data. - - Default to return all objects in the frame data. Optionally, filters - can be set to retrieve objects with specific keys and values. The - filters are represented as a dict. Each key in the filters specifies a - required key of the object. Each value in the filters is a tuple that - enumerate the required values of the corresponding key in the object. - - Args: - obj_filter (callable, optional): A filter function that returns a - bool value from a object (dict). If provided, only objects - that return True will be retrieved. Otherwise all objects will - be retrieved. Default: ``None``. - - Returns: - list[dict]: A list of object information. - - - Example:: - >>> objects = [ - ... {'_id_': 2, 'label': 'dog'} - ... {'_id_': 1, 'label': 'cat'}, - ... ] - >>> frame = FrameMessage(img) - >>> frame.set_objects(objects) - >>> frame.get_objects() - [ - {'_id_': 1, 'label': 'cat'}, - {'_id_': 2, 'label': 'dog'} - ] - >>> frame.get_objects(obj_filter=lambda x:x['label'] == 'cat') - [{'_id_': 1, 'label': 'cat'}] - """ - - objects = [ - obj.copy() - for obj in filter(obj_filter, self.data['objects'].values()) - ] - - return objects diff --git a/mmpose/apis/webcam/utils/misc.py b/mmpose/apis/webcam/utils/misc.py deleted file mode 100644 index 6c6f5417ae..0000000000 --- a/mmpose/apis/webcam/utils/misc.py +++ /dev/null @@ -1,367 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import importlib -import os -import os.path as osp -import sys -import time -from contextlib import contextmanager -from typing import List, Optional, Tuple -from urllib.parse import urlparse -from urllib.request import urlopen - -import cv2 -import numpy as np -from mmengine import mkdir_or_exist -from torch.hub import HASH_REGEX, download_url_to_file - - -@contextmanager -def limit_max_fps(fps: float): - """A context manager to limit maximum frequence of entering the context. - - Args: - fps (float): The maximum frequence of entering the context - - Example:: - >>> from mmpose.apis.webcam.utils import limit_max_fps - >>> import cv2 - - >>> while True: - ... with limit_max_fps(20): - ... cv2.imshow(img) # display image at most 20 fps - """ - t_start = time.time() - try: - yield - finally: - t_end = time.time() - if fps is not None: - t_sleep = 1.0 / fps - t_end + t_start - if t_sleep > 0: - time.sleep(t_sleep) - - -def _is_url(filename: str) -> bool: - """Check if the file is a url link. - - Args: - filename (str): the file name or url link - - Returns: - bool: is url or not. - """ - prefixes = ['http://', 'https://'] - for p in prefixes: - if filename.startswith(p): - return True - return False - - -def load_image_from_disk_or_url(filename: str, - readFlag: int = cv2.IMREAD_COLOR - ) -> np.ndarray: - """Load an image file, from disk or url. - - Args: - filename (str): file name on the disk or url link - readFlag (int): readFlag for imdecode. Default: cv2.IMREAD_COLOR - - Returns: - np.ndarray: A loaded image - """ - if _is_url(filename): - # download the image, convert it to a NumPy array, and then read - # it into OpenCV format - resp = urlopen(filename) - image = np.asarray(bytearray(resp.read()), dtype='uint8') - image = cv2.imdecode(image, readFlag) - return image - else: - image = cv2.imread(filename, readFlag) - return image - - -def get_cached_file_path(url: str, - save_dir: str, - progress: bool = True, - check_hash: bool = False, - file_name: Optional[str] = None) -> str: - r"""Loads the Torch serialized object at the given URL. - - If downloaded file is a zip file, it will be automatically decompressed - - If the object is already present in `model_dir`, it's deserialized and - returned. - The default value of ``model_dir`` is ``/checkpoints`` where - ``hub_dir`` is the directory returned by :func:`~torch.hub.get_dir`. - - Args: - url (str): URL of the object to download - save_dir (str): directory in which to save the object - progress (bool): whether or not to display a progress bar - to stderr. Default: ``True`` - check_hash(bool): If True, the filename part of the URL - should follow the naming convention ``filename-.ext`` - where ```` is the first eight or more digits of the - SHA256 hash of the contents of the file. The hash is used to - ensure unique names and to verify the contents of the file. - Default: ``False`` - file_name (str, optional): name for the downloaded file. Filename - from ``url`` will be used if not set. Default: ``None``. - - Returns: - str: The path to the cached file. - """ - - mkdir_or_exist(save_dir) - - parts = urlparse(url) - filename = os.path.basename(parts.path) - if file_name is not None: - filename = file_name - cached_file = os.path.join(save_dir, filename) - if not os.path.exists(cached_file): - sys.stderr.write('Downloading: "{}" to {}\n'.format(url, cached_file)) - hash_prefix = None - if check_hash: - r = HASH_REGEX.search(filename) # r is Optional[Match[str]] - hash_prefix = r.group(1) if r else None - download_url_to_file(url, cached_file, hash_prefix, progress=progress) - return cached_file - - -def screen_matting(img: np.ndarray, - color_low: Optional[Tuple] = None, - color_high: Optional[Tuple] = None, - color: Optional[str] = None) -> np.ndarray: - """Get screen matting mask. - - Args: - img (np.ndarray): Image data. - color_low (tuple): Lower limit (b, g, r). - color_high (tuple): Higher limit (b, g, r). - color (str): Support colors include: - - - 'green' or 'g' - - 'blue' or 'b' - - 'black' or 'k' - - 'white' or 'w' - - Returns: - np.ndarray: A mask with the same shape of the input image. The value - is 0 at the pixels in the matting color range, and 1 everywhere else. - """ - - if color_high is None or color_low is None: - if color is not None: - if color.lower() == 'g' or color.lower() == 'green': - color_low = (0, 200, 0) - color_high = (60, 255, 60) - elif color.lower() == 'b' or color.lower() == 'blue': - color_low = (230, 0, 0) - color_high = (255, 40, 40) - elif color.lower() == 'k' or color.lower() == 'black': - color_low = (0, 0, 0) - color_high = (40, 40, 40) - elif color.lower() == 'w' or color.lower() == 'white': - color_low = (230, 230, 230) - color_high = (255, 255, 255) - else: - raise NotImplementedError(f'Not supported color: {color}.') - else: - raise ValueError( - 'color or color_high | color_low should be given.') - - mask = cv2.inRange(img, np.array(color_low), np.array(color_high)) == 0 - - return mask.astype(np.uint8) - - -def expand_and_clamp(box: List, im_shape: Tuple, scale: float = 1.25) -> List: - """Expand the bbox and clip it to fit the image shape. - - Args: - box (list): x1, y1, x2, y2 - im_shape (tuple): image shape (h, w, c) - scale (float): expand ratio - - Returns: - list: x1, y1, x2, y2 - """ - - x1, y1, x2, y2 = box[:4] - w = x2 - x1 - h = y2 - y1 - deta_w = w * (scale - 1) / 2 - deta_h = h * (scale - 1) / 2 - - x1, y1, x2, y2 = x1 - deta_w, y1 - deta_h, x2 + deta_w, y2 + deta_h - - img_h, img_w = im_shape[:2] - - x1 = min(max(0, int(x1)), img_w - 1) - y1 = min(max(0, int(y1)), img_h - 1) - x2 = min(max(0, int(x2)), img_w - 1) - y2 = min(max(0, int(y2)), img_h - 1) - - return [x1, y1, x2, y2] - - -def _find_bbox(mask): - """Find the bounding box for the mask. - - Args: - mask (ndarray): Mask. - - Returns: - list(4, ): Returned box (x1, y1, x2, y2). - """ - mask_shape = mask.shape - if len(mask_shape) == 3: - assert mask_shape[-1] == 1, 'the channel of the mask should be 1.' - elif len(mask_shape) == 2: - pass - else: - NotImplementedError() - - h, w = mask_shape[:2] - mask_w = mask.sum(0) - mask_h = mask.sum(1) - - left = 0 - right = w - 1 - up = 0 - down = h - 1 - - for i in range(w): - if mask_w[i] > 0: - break - left += 1 - - for i in range(w - 1, left, -1): - if mask_w[i] > 0: - break - right -= 1 - - for i in range(h): - if mask_h[i] > 0: - break - up += 1 - - for i in range(h - 1, up, -1): - if mask_h[i] > 0: - break - down -= 1 - - return [left, up, right, down] - - -def copy_and_paste( - img: np.ndarray, - background_img: np.ndarray, - mask: np.ndarray, - bbox: Optional[List] = None, - effect_region: Tuple = (0.2, 0.2, 0.8, 0.8), - min_size: Tuple = (20, 20) -) -> np.ndarray: - """Copy the image region and paste to the background. - - Args: - img (np.ndarray): Image data. - background_img (np.ndarray): Background image data. - mask (ndarray): instance segmentation result. - bbox (list, optional): instance bbox in (x1, y1, x2, y2). If not - given, the bbox will be obtained by ``_find_bbox()``. Default: - ``None`` - effect_region (tuple): The region to apply mask, the coordinates - are normalized (x1, y1, x2, y2). Default: (0.2, 0.2, 0.8, 0.8) - min_size (tuple): The minimum region size (w, h) in pixels. - Default: (20, 20) - - Returns: - np.ndarray: The background with pasted image region. - """ - background_img = background_img.copy() - background_h, background_w = background_img.shape[:2] - region_h = (effect_region[3] - effect_region[1]) * background_h - region_w = (effect_region[2] - effect_region[0]) * background_w - region_aspect_ratio = region_w / region_h - - if bbox is None: - bbox = _find_bbox(mask) - instance_w = bbox[2] - bbox[0] - instance_h = bbox[3] - bbox[1] - - if instance_w > min_size[0] and instance_h > min_size[1]: - aspect_ratio = instance_w / instance_h - if region_aspect_ratio > aspect_ratio: - resize_rate = region_h / instance_h - else: - resize_rate = region_w / instance_w - - mask_inst = mask[int(bbox[1]):int(bbox[3]), int(bbox[0]):int(bbox[2])] - img_inst = img[int(bbox[1]):int(bbox[3]), int(bbox[0]):int(bbox[2])] - img_inst = cv2.resize( - img_inst.astype('float32'), - (int(resize_rate * instance_w), int(resize_rate * instance_h))) - img_inst = img_inst.astype(background_img.dtype) - mask_inst = cv2.resize( - mask_inst.astype('float32'), - (int(resize_rate * instance_w), int(resize_rate * instance_h)), - interpolation=cv2.INTER_NEAREST) - - mask_ids = list(np.where(mask_inst == 1)) - mask_ids[1] += int(effect_region[0] * background_w) - mask_ids[0] += int(effect_region[1] * background_h) - - background_img[tuple(mask_ids)] = img_inst[np.where(mask_inst == 1)] - - return background_img - - -def is_image_file(path: str) -> bool: - """Check if a path is an image file by its extension. - - Args: - path (str): The image path. - - Returns: - bool: Weather the path is an image file. - """ - if isinstance(path, str): - if path.lower().endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp')): - return True - return False - - -def get_config_path(path: str, module_name: str): - """Get config path from an OpenMMLab codebase. - - If the path is an existing file, it will be directly returned. If the file - doesn't exist, it will be searched in the 'configs' folder of the - specified module. - - Args: - path (str): the path of the config file - module_name (str): The module name of an OpenMMLab codebase - - Returns: - str: The config file path. - - Example:: - >>> path = 'configs/_base_/filters/one_euro.py' - >>> get_config_path(path, 'mmpose') - '/home/mmpose/configs/_base_/filters/one_euro.py' - """ - - if osp.isfile(path): - return path - - module = importlib.import_module(module_name) - module_dir = osp.dirname(module.__file__) - path_in_module = osp.join(module_dir, '.mim', path) - - if not osp.isfile(path_in_module): - raise FileNotFoundError(f'Can not find the config file "{path}"') - - return path_in_module diff --git a/mmpose/apis/webcam/utils/pose.py b/mmpose/apis/webcam/utils/pose.py deleted file mode 100644 index 8ff32f9e16..0000000000 --- a/mmpose/apis/webcam/utils/pose.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -from typing import Dict, List, Tuple - - -def get_eye_keypoint_ids(dataset_meta: Dict) -> Tuple[int, int]: - """A helper function to get the keypoint indices of left and right eyes - from the dataset meta information. - - Args: - dataset_meta (dict): dataset meta information. - - Returns: - tuple[int, int]: The keypoint indices of left eye and right eye. - """ - left_eye_idx = None - right_eye_idx = None - - # try obtaining eye point ids from dataset_meta - keypoint_name2id = dataset_meta.get('keypoint_name2id', {}) - left_eye_idx = keypoint_name2id.get('left_eye', None) - right_eye_idx = keypoint_name2id.get('right_eye', None) - - if left_eye_idx is None or right_eye_idx is None: - # Fall back to hard coded keypoint id - dataset_name = dataset_meta.get('dataset_name', 'unknown dataset') - if dataset_name in {'coco', 'coco_wholebody'}: - left_eye_idx = 1 - right_eye_idx = 2 - elif dataset_name in {'animalpose', 'ap10k'}: - left_eye_idx = 0 - right_eye_idx = 1 - else: - raise ValueError('Can not determine the eye keypoint id of ' - f'{dataset_name}') - - return left_eye_idx, right_eye_idx - - -def get_face_keypoint_ids(dataset_meta: Dict) -> List: - """A helper function to get the keypoint indices of the face from the - dataset meta information. - - Args: - dataset_meta (dict): dataset meta information. - - Returns: - list[int]: face keypoint indices. The length depends on the dataset. - """ - face_indices = [] - - # try obtaining nose point ids from dataset_meta - keypoint_name2id = dataset_meta.get('keypoint_name2id', {}) - for id in range(68): - face_indices.append(keypoint_name2id.get(f'face-{id}', None)) - - if None in face_indices: - # Fall back to hard coded keypoint id - dataset_name = dataset_meta.get('dataset_name', 'unknown dataset') - if dataset_name in {'coco_wholebody'}: - face_indices = list(range(23, 91)) - else: - raise ValueError('Can not determine the face id of ' - f'{dataset_name}') - - return face_indices - - -def get_wrist_keypoint_ids(dataset_meta: Dict) -> Tuple[int, int]: - """A helper function to get the keypoint indices of left and right wrists - from the dataset meta information. - - Args: - dataset_meta (dict): dataset meta information. - Returns: - tuple[int, int]: The keypoint indices of left and right wrists. - """ - - # try obtaining wrist point ids from dataset_meta - keypoint_name2id = dataset_meta.get('keypoint_name2id', {}) - left_wrist_idx = keypoint_name2id.get('left_wrist', None) - right_wrist_idx = keypoint_name2id.get('right_wrist', None) - - if left_wrist_idx is None or right_wrist_idx is None: - # Fall back to hard coded keypoint id - dataset_name = dataset_meta.get('dataset_name', 'unknown dataset') - if dataset_name in {'coco', 'coco_wholebody'}: - left_wrist_idx = 9 - right_wrist_idx = 10 - elif dataset_name == 'animalpose': - left_wrist_idx = 16 - right_wrist_idx = 17 - elif dataset_name == 'ap10k': - left_wrist_idx = 7 - right_wrist_idx = 10 - else: - raise ValueError('Can not determine the eye keypoint id of ' - f'{dataset_name}') - - return left_wrist_idx, right_wrist_idx - - -def get_mouth_keypoint_ids(dataset_meta: Dict) -> int: - """A helper function to get the mouth keypoint index from the dataset meta - information. - - Args: - dataset_meta (dict): dataset meta information. - Returns: - int: The mouth keypoint index - """ - # try obtaining mouth point ids from dataset_info - keypoint_name2id = dataset_meta.get('keypoint_name2id', {}) - mouth_index = keypoint_name2id.get('face-62', None) - - if mouth_index is None: - # Fall back to hard coded keypoint id - dataset_name = dataset_meta.get('dataset_name', 'unknown dataset') - if dataset_name == 'coco_wholebody': - mouth_index = 85 - else: - raise ValueError('Can not determine the eye keypoint id of ' - f'{dataset_name}') - - return mouth_index - - -def get_hand_keypoint_ids(dataset_meta: Dict) -> List[int]: - """A helper function to get the keypoint indices of left and right hand - from the dataset meta information. - - Args: - dataset_meta (dict): dataset meta information. - Returns: - list[int]: hand keypoint indices. The length depends on the dataset. - """ - # try obtaining hand keypoint ids from dataset_meta - keypoint_name2id = dataset_meta.get('keypoint_name2id', {}) - hand_indices = [] - hand_indices.append(keypoint_name2id.get('left_hand_root', None)) - - for id in range(1, 5): - hand_indices.append(keypoint_name2id.get(f'left_thumb{id}', None)) - for id in range(1, 5): - hand_indices.append(keypoint_name2id.get(f'left_forefinger{id}', None)) - for id in range(1, 5): - hand_indices.append( - keypoint_name2id.get(f'left_middle_finger{id}', None)) - for id in range(1, 5): - hand_indices.append( - keypoint_name2id.get(f'left_ring_finger{id}', None)) - for id in range(1, 5): - hand_indices.append( - keypoint_name2id.get(f'left_pinky_finger{id}', None)) - - hand_indices.append(keypoint_name2id.get('right_hand_root', None)) - - for id in range(1, 5): - hand_indices.append(keypoint_name2id.get(f'right_thumb{id}', None)) - for id in range(1, 5): - hand_indices.append( - keypoint_name2id.get(f'right_forefinger{id}', None)) - for id in range(1, 5): - hand_indices.append( - keypoint_name2id.get(f'right_middle_finger{id}', None)) - for id in range(1, 5): - hand_indices.append( - keypoint_name2id.get(f'right_ring_finger{id}', None)) - for id in range(1, 5): - hand_indices.append( - keypoint_name2id.get(f'right_pinky_finger{id}', None)) - - if None in hand_indices: - # Fall back to hard coded keypoint id - dataset_name = dataset_meta.get('dataset_name', 'unknown dataset') - if dataset_name in {'coco_wholebody'}: - hand_indices = list(range(91, 133)) - else: - raise ValueError('Can not determine the hand id of ' - f'{dataset_name}') - - return hand_indices diff --git a/mmpose/apis/webcam/webcam_executor.py b/mmpose/apis/webcam/webcam_executor.py deleted file mode 100644 index f39aa4b847..0000000000 --- a/mmpose/apis/webcam/webcam_executor.py +++ /dev/null @@ -1,329 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import logging -import sys -import time -import warnings -from threading import Thread -from typing import Dict, List, Optional, Tuple, Union - -import cv2 - -from .nodes import NODES -from .utils import (BufferManager, EventManager, FrameMessage, ImageCapture, - VideoEndingMessage, is_image_file, limit_max_fps) - -try: - from contextlib import nullcontext -except ImportError: - # compatible with python3.6 - from contextlib import contextmanager - - @contextmanager - def nullcontext(enter_result=None): - yield enter_result - - -DEFAULT_FRAME_BUFFER_SIZE = 1 -DEFAULT_INPUT_BUFFER_SIZE = 1 -DEFAULT_DISPLAY_BUFFER_SIZE = 0 -DEFAULT_USER_BUFFER_SIZE = 1 - -logger = logging.getLogger('Executor') - - -class WebcamExecutor(): - """The interface to build and execute webcam applications from configs. - - Parameters: - nodes (list[dict]): Node configs. See :class:`webcam.nodes.Node` for - details - name (str): Executor name. Default: 'MMPose Webcam App'. - camera_id (int | str): The camera ID (usually the ID of the default - camera is 0). Alternatively a file path or a URL can be given - to load from a video or image file. - camera_frame_shape (tuple, optional): Set the frame shape of the - camera in (width, height). If not given, the default frame shape - will be used. This argument is only valid when using a camera - as the input source. Default: ``None`` - camera_max_fps (int): Video reading maximum FPS. Default: 30 - buffer_sizes (dict, optional): A dict to specify buffer sizes. The - key is the buffer name and the value is the buffer size. - Default: ``None`` - - Example:: - >>> cfg = dict( - >>> name='Test Webcam', - >>> camera_id=0, - >>> camera_max_fps=30, - >>> nodes=[ - >>> dict( - >>> type='MonitorNode', - >>> name='monitor', - >>> enable_key='m', - >>> enable=False, - >>> input_buffer='_frame_', - >>> output_buffer='display'), - >>> dict( - >>> type='RecorderNode', - >>> name='recorder', - >>> out_video_file='webcam_output.mp4', - >>> input_buffer='display', - >>> output_buffer='_display_') - >>> ]) - - >>> executor = WebcamExecutor(**cfg) - """ - - def __init__(self, - nodes: List[Dict], - name: str = 'MMPose Webcam App', - camera_id: Union[int, str] = 0, - camera_max_fps: int = 30, - camera_frame_shape: Optional[Tuple[int, int]] = None, - synchronous: bool = False, - buffer_sizes: Optional[Dict[str, int]] = None): - - # Basic parameters - self.name = name - self.camera_id = camera_id - self.camera_max_fps = camera_max_fps - self.camera_frame_shape = camera_frame_shape - self.synchronous = synchronous - - # self.buffer_manager manages data flow between executor and nodes - self.buffer_manager = BufferManager() - # self.event_manager manages event-based asynchronous communication - self.event_manager = EventManager() - # self.node_list holds all node instance - self.node_list = [] - # self.vcap is used to read camera frames. It will be built when the - # executor starts running - self.vcap = None - - # Register executor events - self.event_manager.register_event('_exit_', is_keyboard=False) - if self.synchronous: - self.event_manager.register_event('_idle_', is_keyboard=False) - - # Register nodes - if not nodes: - raise ValueError('No node is registered to the executor.') - - # Register default buffers - if buffer_sizes is None: - buffer_sizes = {} - # _frame_ buffer - frame_buffer_size = buffer_sizes.get('_frame_', - DEFAULT_FRAME_BUFFER_SIZE) - self.buffer_manager.register_buffer('_frame_', frame_buffer_size) - # _input_ buffer - input_buffer_size = buffer_sizes.get('_input_', - DEFAULT_INPUT_BUFFER_SIZE) - self.buffer_manager.register_buffer('_input_', input_buffer_size) - # _display_ buffer - display_buffer_size = buffer_sizes.get('_display_', - DEFAULT_DISPLAY_BUFFER_SIZE) - self.buffer_manager.register_buffer('_display_', display_buffer_size) - - # Build all nodes: - for node_cfg in nodes: - logger.info(f'Create node: {node_cfg.name}({node_cfg.type})') - node = NODES.build(node_cfg) - - # Register node - self.node_list.append(node) - - # Register buffers - for buffer_info in node.registered_buffers: - buffer_name = buffer_info.buffer_name - if buffer_name in self.buffer_manager: - continue - buffer_size = buffer_sizes.get(buffer_name, - DEFAULT_USER_BUFFER_SIZE) - self.buffer_manager.register_buffer(buffer_name, buffer_size) - logger.info( - f'Register user buffer: {buffer_name}({buffer_size})') - - # Register events - for event_info in node.registered_events: - self.event_manager.register_event( - event_name=event_info.event_name, - is_keyboard=event_info.is_keyboard) - logger.info(f'Register event: {event_info.event_name}') - - # Set executor for nodes - # This step is performed after node building when the executor has - # create full buffer/event managers and can - for node in self.node_list: - logger.info(f'Set executor for node: {node.name})') - node.set_executor(self) - - def _read_camera(self): - """Read video frames from the caemra (or the source video/image) and - put them into input buffers.""" - - camera_id = self.camera_id - fps = self.camera_max_fps - - # Build video capture - if is_image_file(camera_id): - self.vcap = ImageCapture(camera_id) - else: - self.vcap = cv2.VideoCapture(camera_id) - if self.camera_frame_shape is not None: - width, height = self.camera_frame_shape - self.vcap.set(cv2.CAP_PROP_FRAME_WIDTH, width) - self.vcap.set(cv2.CAP_PROP_FRAME_HEIGHT, height) - - if not self.vcap.isOpened(): - warnings.warn(f'Cannot open camera (ID={camera_id})') - sys.exit() - - # Read video frames in a loop - first_frame = True - while not self.event_manager.is_set('_exit_'): - if self.synchronous: - if first_frame: - cm = nullcontext() - else: - # Read a new frame until the last frame has been processed - cm = self.event_manager.wait_and_handle('_idle_') - else: - # Read frames with a maximum FPS - cm = limit_max_fps(fps) - - first_frame = False - - with cm: - # Read a frame - ret_val, frame = self.vcap.read() - if ret_val: - # Put frame message (for display) into buffer `_frame_` - frame_msg = FrameMessage(frame) - self.buffer_manager.put('_frame_', frame_msg) - - # Put input message (for model inference or other use) - # into buffer `_input_` - input_msg = FrameMessage(frame.copy()) - input_msg.update_route_info( - node_name='Camera Info', - node_type='none', - info=self._get_camera_info()) - self.buffer_manager.put_force('_input_', input_msg) - logger.info('Read one frame.') - else: - logger.info('Reached the end of the video.') - # Put a video ending signal - self.buffer_manager.put_force('_frame_', - VideoEndingMessage()) - self.buffer_manager.put_force('_input_', - VideoEndingMessage()) - # Wait for `_exit_` event util a timeout occurs - if not self.event_manager.wait('_exit_', timeout=5.0): - break - - self.vcap.release() - - def _display(self): - """Receive processed frames from the output buffer and display on - screen.""" - - output_msg = None - - while not self.event_manager.is_set('_exit_'): - while self.buffer_manager.is_empty('_display_'): - time.sleep(0.001) - - # Set _idle_ to allow reading next frame - if self.synchronous: - self.event_manager.set('_idle_') - - # acquire output from buffer - output_msg = self.buffer_manager.get('_display_') - - # None indicates input stream ends - if isinstance(output_msg, VideoEndingMessage): - self.event_manager.set('_exit_') - break - - img = output_msg.get_image() - - # show in a window - cv2.imshow(self.name, img) - - # handle keyboard input - key = cv2.waitKey(1) - if key != -1: - self._on_keyboard_input(key) - - cv2.destroyAllWindows() - - # Avoid dead lock - if self.synchronous: - self.event_manager.set('_idle_') - - def _on_keyboard_input(self, key): - """Handle the keyboard input. - - The key 'Q' and `ESC` will trigger an '_exit_' event, which will be - responded by all nodes and the executor itself to exit. Other keys will - trigger keyboard event to be responded by the nodes which has - registered corresponding event. See :class:`webcam.utils.EventManager` - for details. - """ - - if key in (27, ord('q'), ord('Q')): - logger.info(f'Exit event captured: {key}') - self.event_manager.set('_exit_') - else: - logger.info(f'Keyboard event captured: {key}') - self.event_manager.set(key, is_keyboard=True) - - def _get_camera_info(self): - """Return the camera information in a dict.""" - - frame_width = self.vcap.get(cv2.CAP_PROP_FRAME_WIDTH) - frame_height = self.vcap.get(cv2.CAP_PROP_FRAME_HEIGHT) - frame_rate = self.vcap.get(cv2.CAP_PROP_FPS) - - cam_info = { - 'Camera ID': self.camera_id, - 'Camera resolution': f'{frame_width}x{frame_height}', - 'Camera FPS': frame_rate, - } - - return cam_info - - def run(self): - """Start the executor. - - This method starts all nodes as well as video I/O in separate threads. - """ - - try: - # Start node threads - non_daemon_nodes = [] - for node in self.node_list: - node.start() - if not node.daemon: - non_daemon_nodes.append(node) - - # Create a thread to read video frames - t_read = Thread(target=self._read_camera, args=()) - t_read.start() - - # Run display in the main thread - self._display() - logger.info('Display has stopped.') - - # joint non-daemon nodes and executor threads - logger.info('Camera reading is about to join.') - t_read.join() - - for node in non_daemon_nodes: - logger.info(f'Node {node.name} is about to join.') - node.join() - logger.info('All nodes jointed successfully.') - - except KeyboardInterrupt: - pass diff --git a/mmpose/codecs/__init__.py b/mmpose/codecs/__init__.py index a88ebac701..cdbd8feb0c 100644 --- a/mmpose/codecs/__init__.py +++ b/mmpose/codecs/__init__.py @@ -1,6 +1,7 @@ # Copyright (c) OpenMMLab. All rights reserved. from .associative_embedding import AssociativeEmbedding from .decoupled_heatmap import DecoupledHeatmap +from .image_pose_lifting import ImagePoseLifting from .integral_regression_label import IntegralRegressionLabel from .megvii_heatmap import MegviiHeatmap from .msra_heatmap import MSRAHeatmap @@ -8,9 +9,10 @@ from .simcc_label import SimCCLabel from .spr import SPR from .udp_heatmap import UDPHeatmap +from .video_pose_lifting import VideoPoseLifting __all__ = [ 'MSRAHeatmap', 'MegviiHeatmap', 'UDPHeatmap', 'RegressionLabel', 'SimCCLabel', 'IntegralRegressionLabel', 'AssociativeEmbedding', 'SPR', - 'DecoupledHeatmap' + 'DecoupledHeatmap', 'VideoPoseLifting', 'ImagePoseLifting' ] diff --git a/mmpose/codecs/image_pose_lifting.py b/mmpose/codecs/image_pose_lifting.py new file mode 100644 index 0000000000..64bf925997 --- /dev/null +++ b/mmpose/codecs/image_pose_lifting.py @@ -0,0 +1,203 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Optional, Tuple + +import numpy as np + +from mmpose.registry import KEYPOINT_CODECS +from .base import BaseKeypointCodec + + +@KEYPOINT_CODECS.register_module() +class ImagePoseLifting(BaseKeypointCodec): + r"""Generate keypoint coordinates for pose lifter. + + Note: + + - instance number: N + - keypoint number: K + - keypoint dimension: D + - pose-lifitng target dimension: C + + Args: + num_keypoints (int): The number of keypoints in the dataset. + root_index (int): Root keypoint index in the pose. + remove_root (bool): If true, remove the root keypoint from the pose. + Default: ``False``. + save_index (bool): If true, store the root position separated from the + original pose. Default: ``False``. + keypoints_mean (np.ndarray, optional): Mean values of keypoints + coordinates in shape (K, D). + keypoints_std (np.ndarray, optional): Std values of keypoints + coordinates in shape (K, D). + target_mean (np.ndarray, optional): Mean values of pose-lifitng target + coordinates in shape (K, C). + target_std (np.ndarray, optional): Std values of pose-lifitng target + coordinates in shape (K, C). + """ + + auxiliary_encode_keys = {'lifting_target', 'lifting_target_visible'} + + def __init__(self, + num_keypoints: int, + root_index: int, + remove_root: bool = False, + save_index: bool = False, + keypoints_mean: Optional[np.ndarray] = None, + keypoints_std: Optional[np.ndarray] = None, + target_mean: Optional[np.ndarray] = None, + target_std: Optional[np.ndarray] = None): + super().__init__() + + self.num_keypoints = num_keypoints + self.root_index = root_index + self.remove_root = remove_root + self.save_index = save_index + if keypoints_mean is not None and keypoints_std is not None: + assert keypoints_mean.shape == keypoints_std.shape + if target_mean is not None and target_std is not None: + assert target_mean.shape == target_std.shape + self.keypoints_mean = keypoints_mean + self.keypoints_std = keypoints_std + self.target_mean = target_mean + self.target_std = target_std + + def encode(self, + keypoints: np.ndarray, + keypoints_visible: Optional[np.ndarray] = None, + lifting_target: Optional[np.ndarray] = None, + lifting_target_visible: Optional[np.ndarray] = None) -> dict: + """Encoding keypoints from input image space to normalized space. + + Args: + keypoints (np.ndarray): Keypoint coordinates in shape (N, K, D). + keypoints_visible (np.ndarray, optional): Keypoint visibilities in + shape (N, K). + lifting_target (np.ndarray, optional): 3d target coordinate in + shape (K, C). + lifting_target_visible (np.ndarray, optional): Target coordinate in + shape (K, ). + + Returns: + encoded (dict): Contains the following items: + + - keypoint_labels (np.ndarray): The processed keypoints in + shape (K * D, N) where D is 2 for 2d coordinates. + - lifting_target_label: The processed target coordinate in + shape (K, C) or (K-1, C). + - lifting_target_weights (np.ndarray): The target weights in + shape (K, ) or (K-1, ). + - trajectory_weights (np.ndarray): The trajectory weights in + shape (K, ). + - target_root (np.ndarray): The root coordinate of target in + shape (C, ). + + In addition, there are some optional items it may contain: + + - target_root_removed (bool): Indicate whether the root of + pose lifting target is removed. Added if ``self.remove_root`` + is ``True``. + - target_root_index (int): An integer indicating the index of + root. Added if ``self.remove_root`` and ``self.save_index`` + are ``True``. + """ + if keypoints_visible is None: + keypoints_visible = np.ones(keypoints.shape[:2], dtype=np.float32) + + if lifting_target is None: + lifting_target = keypoints[0] + + # set initial value for `lifting_target_weights` + # and `trajectory_weights` + if lifting_target_visible is None: + lifting_target_visible = np.ones( + lifting_target.shape[:-1], dtype=np.float32) + lifting_target_weights = lifting_target_visible + trajectory_weights = (1 / lifting_target[:, 2]) + else: + valid = lifting_target_visible > 0.5 + lifting_target_weights = np.where(valid, 1., 0.).astype(np.float32) + trajectory_weights = lifting_target_weights + + encoded = dict() + + # Zero-center the target pose around a given root keypoint + assert (lifting_target.ndim >= 2 and + lifting_target.shape[-2] > self.root_index), \ + f'Got invalid joint shape {lifting_target.shape}' + + root = lifting_target[..., self.root_index, :] + lifting_target_label = lifting_target - root + + if self.remove_root: + lifting_target_label = np.delete( + lifting_target_label, self.root_index, axis=-2) + assert lifting_target_weights.ndim in {1, 2} + axis_to_remove = -2 if lifting_target_weights.ndim == 2 else -1 + lifting_target_weights = np.delete( + lifting_target_weights, self.root_index, axis=axis_to_remove) + # Add a flag to avoid latter transforms that rely on the root + # joint or the original joint index + encoded['target_root_removed'] = True + + # Save the root index which is necessary to restore the global pose + if self.save_index: + encoded['target_root_index'] = self.root_index + + # Normalize the 2D keypoint coordinate with mean and std + keypoint_labels = keypoints.copy() + if self.keypoints_mean is not None and self.keypoints_std is not None: + keypoints_shape = keypoints.shape + assert self.keypoints_mean.shape == keypoints_shape[1:] + + keypoint_labels = (keypoint_labels - + self.keypoints_mean) / self.keypoints_std + if self.target_mean is not None and self.target_std is not None: + target_shape = lifting_target_label.shape + assert self.target_mean.shape == target_shape + + lifting_target_label = (lifting_target_label - + self.target_mean) / self.target_std + + # Generate reshaped keypoint coordinates + assert keypoint_labels.ndim in {2, 3} + if keypoint_labels.ndim == 2: + keypoint_labels = keypoint_labels[None, ...] + + encoded['keypoint_labels'] = keypoint_labels + encoded['lifting_target_label'] = lifting_target_label + encoded['lifting_target_weights'] = lifting_target_weights + encoded['trajectory_weights'] = trajectory_weights + encoded['target_root'] = root + + return encoded + + def decode(self, + encoded: np.ndarray, + target_root: Optional[np.ndarray] = None + ) -> Tuple[np.ndarray, np.ndarray]: + """Decode keypoint coordinates from normalized space to input image + space. + + Args: + encoded (np.ndarray): Coordinates in shape (N, K, C). + target_root (np.ndarray, optional): The target root coordinate. + Default: ``None``. + + Returns: + keypoints (np.ndarray): Decoded coordinates in shape (N, K, C). + scores (np.ndarray): The keypoint scores in shape (N, K). + """ + keypoints = encoded.copy() + + if self.target_mean is not None and self.target_std is not None: + assert self.target_mean.shape == keypoints.shape[1:] + keypoints = keypoints * self.target_std + self.target_mean + + if target_root.size > 0: + keypoints = keypoints + np.expand_dims(target_root, axis=0) + if self.remove_root: + keypoints = np.insert( + keypoints, self.root_index, target_root, axis=1) + scores = np.ones(keypoints.shape[:-1], dtype=np.float32) + + return keypoints, scores diff --git a/mmpose/codecs/regression_label.py b/mmpose/codecs/regression_label.py index 9ae385d2d9..f79195beb4 100644 --- a/mmpose/codecs/regression_label.py +++ b/mmpose/codecs/regression_label.py @@ -78,7 +78,7 @@ def decode(self, encoded: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: Returns: tuple: - keypoints (np.ndarray): Decoded coordinates in shape (N, K, D) - - socres (np.ndarray): The keypoint scores in shape (N, K). + - scores (np.ndarray): The keypoint scores in shape (N, K). It usually represents the confidence of the keypoint prediction """ diff --git a/mmpose/codecs/video_pose_lifting.py b/mmpose/codecs/video_pose_lifting.py new file mode 100644 index 0000000000..56cf35fa2d --- /dev/null +++ b/mmpose/codecs/video_pose_lifting.py @@ -0,0 +1,202 @@ +# Copyright (c) OpenMMLab. All rights reserved. + +from copy import deepcopy +from typing import Optional, Tuple + +import numpy as np + +from mmpose.registry import KEYPOINT_CODECS +from .base import BaseKeypointCodec + + +@KEYPOINT_CODECS.register_module() +class VideoPoseLifting(BaseKeypointCodec): + r"""Generate keypoint coordinates for pose lifter. + + Note: + + - instance number: N + - keypoint number: K + - keypoint dimension: D + - pose-lifitng target dimension: C + + Args: + num_keypoints (int): The number of keypoints in the dataset. + zero_center: Whether to zero-center the target around root. Default: + ``True``. + root_index (int): Root keypoint index in the pose. Default: 0. + remove_root (bool): If true, remove the root keypoint from the pose. + Default: ``False``. + save_index (bool): If true, store the root position separated from the + original pose, only takes effect if ``remove_root`` is ``True``. + Default: ``False``. + normalize_camera (bool): Whether to normalize camera intrinsics. + Default: ``False``. + """ + + auxiliary_encode_keys = { + 'lifting_target', 'lifting_target_visible', 'camera_param' + } + + def __init__(self, + num_keypoints: int, + zero_center: bool = True, + root_index: int = 0, + remove_root: bool = False, + save_index: bool = False, + normalize_camera: bool = False): + super().__init__() + + self.num_keypoints = num_keypoints + self.zero_center = zero_center + self.root_index = root_index + self.remove_root = remove_root + self.save_index = save_index + self.normalize_camera = normalize_camera + + def encode(self, + keypoints: np.ndarray, + keypoints_visible: Optional[np.ndarray] = None, + lifting_target: Optional[np.ndarray] = None, + lifting_target_visible: Optional[np.ndarray] = None, + camera_param: Optional[dict] = None) -> dict: + """Encoding keypoints from input image space to normalized space. + + Args: + keypoints (np.ndarray): Keypoint coordinates in shape (N, K, D). + keypoints_visible (np.ndarray, optional): Keypoint visibilities in + shape (N, K). + lifting_target (np.ndarray, optional): 3d target coordinate in + shape (K, C). + lifting_target_visible (np.ndarray, optional): Target coordinate in + shape (K, ). + camera_param (dict, optional): The camera parameter dictionary. + + Returns: + encoded (dict): Contains the following items: + + - keypoint_labels (np.ndarray): The processed keypoints in + shape (K * D, N) where D is 2 for 2d coordinates. + - lifting_target_label: The processed target coordinate in + shape (K, C) or (K-1, C). + - lifting_target_weights (np.ndarray): The target weights in + shape (K, ) or (K-1, ). + - trajectory_weights (np.ndarray): The trajectory weights in + shape (K, ). + + In addition, there are some optional items it may contain: + + - target_root (np.ndarray): The root coordinate of target in + shape (C, ). Exists if ``self.zero_center`` is ``True``. + - target_root_removed (bool): Indicate whether the root of + pose-lifitng target is removed. Exists if + ``self.remove_root`` is ``True``. + - target_root_index (int): An integer indicating the index of + root. Exists if ``self.remove_root`` and ``self.save_index`` + are ``True``. + - camera_param (dict): The updated camera parameter dictionary. + Exists if ``self.normalize_camera`` is ``True``. + """ + if keypoints_visible is None: + keypoints_visible = np.ones(keypoints.shape[:2], dtype=np.float32) + + if lifting_target is None: + lifting_target = keypoints[0] + + # set initial value for `lifting_target_weights` + # and `trajectory_weights` + if lifting_target_visible is None: + lifting_target_visible = np.ones( + lifting_target.shape[:-1], dtype=np.float32) + lifting_target_weights = lifting_target_visible + trajectory_weights = (1 / lifting_target[:, 2]) + else: + valid = lifting_target_visible > 0.5 + lifting_target_weights = np.where(valid, 1., 0.).astype(np.float32) + trajectory_weights = lifting_target_weights + + if camera_param is None: + camera_param = dict() + + encoded = dict() + + lifting_target_label = lifting_target.copy() + # Zero-center the target pose around a given root keypoint + if self.zero_center: + assert (lifting_target.ndim >= 2 and + lifting_target.shape[-2] > self.root_index), \ + f'Got invalid joint shape {lifting_target.shape}' + + root = lifting_target[..., self.root_index, :] + lifting_target_label = lifting_target_label - root + encoded['target_root'] = root + + if self.remove_root: + lifting_target_label = np.delete( + lifting_target_label, self.root_index, axis=-2) + assert lifting_target_weights.ndim in {1, 2} + axis_to_remove = -2 if lifting_target_weights.ndim == 2 else -1 + lifting_target_weights = np.delete( + lifting_target_weights, + self.root_index, + axis=axis_to_remove) + # Add a flag to avoid latter transforms that rely on the root + # joint or the original joint index + encoded['target_root_removed'] = True + + # Save the root index for restoring the global pose + if self.save_index: + encoded['target_root_index'] = self.root_index + + # Normalize the 2D keypoint coordinate with image width and height + _camera_param = deepcopy(camera_param) + assert 'w' in _camera_param and 'h' in _camera_param + center = np.array([0.5 * _camera_param['w'], 0.5 * _camera_param['h']], + dtype=np.float32) + scale = np.array(0.5 * _camera_param['w'], dtype=np.float32) + + keypoint_labels = (keypoints - center) / scale + + assert keypoint_labels.ndim in {2, 3} + if keypoint_labels.ndim == 2: + keypoint_labels = keypoint_labels[None, ...] + + if self.normalize_camera: + assert 'f' in _camera_param and 'c' in _camera_param + _camera_param['f'] = _camera_param['f'] / scale + _camera_param['c'] = (_camera_param['c'] - center[:, None]) / scale + encoded['camera_param'] = _camera_param + + encoded['keypoint_labels'] = keypoint_labels + encoded['lifting_target_label'] = lifting_target_label + encoded['lifting_target_weights'] = lifting_target_weights + encoded['trajectory_weights'] = trajectory_weights + + return encoded + + def decode(self, + encoded: np.ndarray, + target_root: Optional[np.ndarray] = None + ) -> Tuple[np.ndarray, np.ndarray]: + """Decode keypoint coordinates from normalized space to input image + space. + + Args: + encoded (np.ndarray): Coordinates in shape (N, K, C). + target_root (np.ndarray, optional): The pose-lifitng target root + coordinate. Default: ``None``. + + Returns: + keypoints (np.ndarray): Decoded coordinates in shape (N, K, C). + scores (np.ndarray): The keypoint scores in shape (N, K). + """ + keypoints = encoded.copy() + + if target_root.size > 0: + keypoints = keypoints + np.expand_dims(target_root, axis=0) + if self.remove_root: + keypoints = np.insert( + keypoints, self.root_index, target_root, axis=1) + scores = np.ones(keypoints.shape[:-1], dtype=np.float32) + + return keypoints, scores diff --git a/mmpose/configs/_base_/default_runtime.py b/mmpose/configs/_base_/default_runtime.py new file mode 100644 index 0000000000..349ecf4b17 --- /dev/null +++ b/mmpose/configs/_base_/default_runtime.py @@ -0,0 +1,54 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook, + LoggerHook, ParamSchedulerHook, SyncBuffersHook) +from mmengine.runner import LogProcessor +from mmengine.visualization import LocalVisBackend + +from mmpose.engine.hooks import PoseVisualizationHook +from mmpose.visualization import PoseLocalVisualizer + +default_scope = None + +# hooks +default_hooks = dict( + timer=dict(type=IterTimerHook), + logger=dict(type=LoggerHook, interval=50), + param_scheduler=dict(type=ParamSchedulerHook), + checkpoint=dict(type=CheckpointHook, interval=10), + sampler_seed=dict(type=DistSamplerSeedHook), + visualization=dict(type=PoseVisualizationHook, enable=False), +) + +# custom hooks +custom_hooks = [ + # Synchronize model buffers such as running_mean and running_var in BN + # at the end of each epoch + dict(type=SyncBuffersHook) +] + +# multi-processing backend +env_cfg = dict( + cudnn_benchmark=False, + mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), + dist_cfg=dict(backend='nccl'), +) + +# visualizer +vis_backends = [dict(type=LocalVisBackend)] +visualizer = dict( + type=PoseLocalVisualizer, vis_backends=vis_backends, name='visualizer') + +# logger +log_processor = dict( + type=LogProcessor, window_size=50, by_epoch=True, num_digits=6) +log_level = 'INFO' +load_from = None +resume = False + +# file I/O backend +backend_args = dict(backend='local') + +# training/validation/testing progress +train_cfg = dict(by_epoch=True) +val_cfg = dict() +test_cfg = dict() diff --git a/mmpose/configs/body_2d_keypoint/rtmpose/coco/rtmpose_m_8xb256-420e_coco-256x192.py b/mmpose/configs/body_2d_keypoint/rtmpose/coco/rtmpose_m_8xb256-420e_coco-256x192.py new file mode 100644 index 0000000000..af102ec20e --- /dev/null +++ b/mmpose/configs/body_2d_keypoint/rtmpose/coco/rtmpose_m_8xb256-420e_coco-256x192.py @@ -0,0 +1,253 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmengine.config import read_base + +with read_base(): + from mmpose.configs._base_.default_runtime import * + +from albumentations.augmentations import Blur, CoarseDropout, MedianBlur +from mmdet.datasets.transforms import YOLOXHSVRandomAug +from mmdet.engine.hooks import PipelineSwitchHook +from mmdet.models import CSPNeXt +from mmengine.dataset import DefaultSampler +from mmengine.hooks import EMAHook +from mmengine.model import PretrainedInit +from mmengine.optim import CosineAnnealingLR, LinearLR, OptimWrapper +from torch.nn import SiLU, SyncBatchNorm +from torch.optim import AdamW + +from mmpose.codecs import SimCCLabel +from mmpose.datasets import (CocoDataset, GenerateTarget, GetBBoxCenterScale, + LoadImage, PackPoseInputs, RandomFlip, + RandomHalfBody, TopdownAffine) +from mmpose.datasets.transforms.common_transforms import (Albumentation, + RandomBBoxTransform) +from mmpose.engine.hooks import ExpMomentumEMA +from mmpose.evaluation import CocoMetric +from mmpose.models import (KLDiscretLoss, PoseDataPreprocessor, RTMCCHead, + TopdownPoseEstimator) + +# runtime +max_epochs = 420 +stage2_num_epochs = 30 +base_lr = 4e-3 + +train_cfg.update(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type=OptimWrapper, + optimizer=dict(type=AdamW, lr=base_lr, weight_decay=0.05), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type=LinearLR, start_factor=1.0e-5, by_epoch=False, begin=0, end=1000), + dict( + # use cosine lr from 210 to 420 epoch + type=CosineAnnealingLR, + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type=SimCCLabel, + input_size=(192, 256), + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type=TopdownPoseEstimator, + data_preprocessor=dict( + type=PoseDataPreprocessor, + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type=CSPNeXt, + arch='P5', + expand_ratio=0.5, + deepen_factor=0.67, + widen_factor=0.75, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type=SyncBatchNorm), + act_cfg=dict(type=SiLU), + init_cfg=dict( + type=PretrainedInit, + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + )), + head=dict( + type=RTMCCHead, + in_channels=768, + out_channels=17, + input_size=codec['input_size'], + in_featuremap_size=(6, 8), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type=KLDiscretLoss, + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = CocoDataset +data_mode = 'topdown' +data_root = 'data/coco/' + +backend_args = dict(backend='local') +# backend_args = dict( +# backend='petrel', +# path_mapping=dict({ +# f'{data_root}': 's3://openmmlab/datasets/detection/coco/', +# f'{data_root}': 's3://openmmlab/datasets/detection/coco/' +# })) + +# pipelines +train_pipeline = [ + dict(type=LoadImage, backend_args=backend_args), + dict(type=GetBBoxCenterScale), + dict(type=RandomFlip, direction='horizontal'), + dict(type=RandomHalfBody), + dict(type=RandomBBoxTransform, scale_factor=[0.6, 1.4], rotate_factor=80), + dict(type=TopdownAffine, input_size=codec['input_size']), + dict(type=YOLOXHSVRandomAug), + dict( + type=Albumentation, + transforms=[ + dict(type=Blur, p=0.1), + dict(type=MedianBlur, p=0.1), + dict( + type=CoarseDropout, + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.), + ]), + dict(type=GenerateTarget, encoder=codec), + dict(type=PackPoseInputs) +] +val_pipeline = [ + dict(type=LoadImage, backend_args=backend_args), + dict(type=GetBBoxCenterScale), + dict(type=TopdownAffine, input_size=codec['input_size']), + dict(type=PackPoseInputs) +] + +train_pipeline_stage2 = [ + dict(type=LoadImage, backend_args=backend_args), + dict(type=GetBBoxCenterScale), + dict(type=RandomFlip, direction='horizontal'), + dict(type=RandomHalfBody), + dict( + type=RandomBBoxTransform, + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type=TopdownAffine, input_size=codec['input_size']), + dict(type=YOLOXHSVRandomAug), + dict( + type=Albumentation, + transforms=[ + dict(type=Blur, p=0.1), + dict(type=MedianBlur, p=0.1), + dict( + type=CoarseDropout, + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type=GenerateTarget, encoder=codec), + dict(type=PackPoseInputs) +] + +# data loaders +train_dataloader = dict( + batch_size=256, + num_workers=10, + persistent_workers=True, + drop_last=True, + sampler=dict(type=DefaultSampler, shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/person_keypoints_train2017.json', + data_prefix=dict(img='train2017/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type=DefaultSampler, shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/person_keypoints_val2017.json', + # bbox_file=f'{data_root}person_detection_results/' + # 'COCO_val2017_detections_AP_H_56_person.json', + data_prefix=dict(img='val2017/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# hooks +default_hooks.update( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type=EMAHook, + ema_type=ExpMomentumEMA, + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type=PipelineSwitchHook, + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type=CocoMetric, + ann_file=data_root + 'annotations/person_keypoints_val2017.json') +test_evaluator = val_evaluator diff --git a/mmpose/configs/body_2d_keypoint/rtmpose/coco/rtmpose_s_8xb256_420e_aic_coco_256x192.py b/mmpose/configs/body_2d_keypoint/rtmpose/coco/rtmpose_s_8xb256_420e_aic_coco_256x192.py new file mode 100644 index 0000000000..6fc5ec0abe --- /dev/null +++ b/mmpose/configs/body_2d_keypoint/rtmpose/coco/rtmpose_s_8xb256_420e_aic_coco_256x192.py @@ -0,0 +1,294 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmengine.config import read_base + +with read_base(): + from mmpose.configs._base_.default_runtime import * + +from albumentations.augmentations import Blur, CoarseDropout, MedianBlur +from mmdet.datasets.transforms import YOLOXHSVRandomAug +from mmdet.engine.hooks import PipelineSwitchHook +from mmdet.models import CSPNeXt +from mmengine.dataset import DefaultSampler, RepeatDataset +from mmengine.hooks import EMAHook +from mmengine.model import PretrainedInit +from mmengine.optim import CosineAnnealingLR, LinearLR, OptimWrapper +from torch.nn import SiLU, SyncBatchNorm +from torch.optim import AdamW + +from mmpose.codecs import SimCCLabel +from mmpose.datasets import (AicDataset, CocoDataset, CombinedDataset, + GenerateTarget, GetBBoxCenterScale, + KeypointConverter, LoadImage, PackPoseInputs, + RandomFlip, RandomHalfBody, TopdownAffine) +from mmpose.datasets.transforms.common_transforms import (Albumentation, + RandomBBoxTransform) +from mmpose.engine.hooks import ExpMomentumEMA +from mmpose.evaluation import CocoMetric +from mmpose.models import (KLDiscretLoss, PoseDataPreprocessor, RTMCCHead, + TopdownPoseEstimator) + +# runtime +max_epochs = 420 +stage2_num_epochs = 30 +base_lr = 4e-3 + +train_cfg.update(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type=OptimWrapper, + optimizer=dict(type=AdamW, lr=base_lr, weight_decay=0.0), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type=LinearLR, start_factor=1.0e-5, by_epoch=False, begin=0, end=1000), + dict( + # use cosine lr from 210 to 420 epoch + type=CosineAnnealingLR, + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type=SimCCLabel, + input_size=(192, 256), + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type=TopdownPoseEstimator, + data_preprocessor=dict( + type=PoseDataPreprocessor, + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type=CSPNeXt, + arch='P5', + expand_ratio=0.5, + deepen_factor=0.33, + widen_factor=0.5, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type=SyncBatchNorm), + act_cfg=dict(type=SiLU), + init_cfg=dict( + type=PretrainedInit, + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth' # noqa + )), + head=dict( + type=RTMCCHead, + in_channels=512, + out_channels=17, + input_size=codec['input_size'], + in_featuremap_size=(6, 8), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type=KLDiscretLoss, + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True, )) + +# base dataset settings +dataset_type = CocoDataset +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') +# backend_args = dict( +# backend='petrel', +# path_mapping=dict({ +# f'{data_root}': 's3://openmmlab/datasets/', +# f'{data_root}': 's3://openmmlab/datasets/' +# })) + +# pipelines +train_pipeline = [ + dict(type=LoadImage, backend_args=backend_args), + dict(type=GetBBoxCenterScale), + dict(type=RandomFlip, direction='horizontal'), + dict(type=RandomHalfBody), + dict(type=RandomBBoxTransform, scale_factor=[0.6, 1.4], rotate_factor=80), + dict(type=TopdownAffine, input_size=codec['input_size']), + dict(type=YOLOXHSVRandomAug), + dict( + type=Albumentation, + transforms=[ + dict(type=Blur, p=0.1), + dict(type=MedianBlur, p=0.1), + dict( + type=CoarseDropout, + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type=GenerateTarget, encoder=codec), + dict(type=PackPoseInputs) +] +val_pipeline = [ + dict(type=LoadImage, backend_args=backend_args), + dict(type=GetBBoxCenterScale), + dict(type=TopdownAffine, input_size=codec['input_size']), + dict(type=PackPoseInputs) +] + +train_pipeline_stage2 = [ + dict(type=LoadImage, backend_args=backend_args), + dict(type=GetBBoxCenterScale), + dict(type=RandomFlip, direction='horizontal'), + dict(type=RandomHalfBody), + dict( + type=RandomBBoxTransform, + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type=TopdownAffine, input_size=codec['input_size']), + dict(type=YOLOXHSVRandomAug), + dict( + type=Albumentation, + transforms=[ + dict(type=Blur, p=0.1), + dict(type=MedianBlur, p=0.1), + dict( + type=CoarseDropout, + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type=GenerateTarget, encoder=codec), + dict(type=PackPoseInputs) +] + +# train datasets +dataset_coco = dict( + type=RepeatDataset, + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_train2017.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[], + ), + times=3) + +dataset_aic = dict( + type=AicDataset, + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type=KeypointConverter, + num_keypoints=17, + mapping=[ + (0, 6), + (1, 8), + (2, 10), + (3, 5), + (4, 7), + (5, 9), + (6, 12), + (7, 14), + (8, 16), + (9, 11), + (10, 13), + (11, 15), + ]) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=128 * 2, + num_workers=10, + persistent_workers=True, + sampler=dict(type=DefaultSampler, shuffle=True), + dataset=dict( + type=CombinedDataset, + metainfo=dict(from_file='configs/_base_/datasets/coco.py'), + datasets=[dataset_coco, dataset_aic], + pipeline=train_pipeline, + test_mode=False, + )) +val_dataloader = dict( + batch_size=64, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type=DefaultSampler, shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/person_keypoints_val2017.json', + # bbox_file='data/coco/person_detection_results/' + # 'COCO_val2017_detections_AP_H_56_person.json', + data_prefix=dict(img='detection/coco/val2017/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# hooks +default_hooks.update( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type=EMAHook, + ema_type=ExpMomentumEMA, + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type=PipelineSwitchHook, + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type=CocoMetric, + ann_file=data_root + 'coco/annotations/person_keypoints_val2017.json') +test_evaluator = val_evaluator diff --git a/mmpose/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_udp-8xb32-210e_coco-256x192.py b/mmpose/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_udp-8xb32-210e_coco-256x192.py new file mode 100644 index 0000000000..1ecf3a704e --- /dev/null +++ b/mmpose/configs/body_2d_keypoint/topdown_heatmap/coco/td-hm_hrnet-w48_udp-8xb32-210e_coco-256x192.py @@ -0,0 +1,169 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmengine.config import read_base + +with read_base(): + from mmpose.configs._base_.default_runtime import * + +from mmengine.dataset import DefaultSampler +from mmengine.model import PretrainedInit +from mmengine.optim import LinearLR, MultiStepLR +from torch.optim import Adam + +from mmpose.codecs import UDPHeatmap +from mmpose.datasets import (CocoDataset, GenerateTarget, GetBBoxCenterScale, + LoadImage, PackPoseInputs, RandomFlip, + RandomHalfBody, TopdownAffine) +from mmpose.datasets.transforms.common_transforms import RandomBBoxTransform +from mmpose.evaluation import CocoMetric +from mmpose.models import (HeatmapHead, HRNet, KeypointMSELoss, + PoseDataPreprocessor, TopdownPoseEstimator) + +# runtime +train_cfg.update(max_epochs=210, val_interval=10) + +# optimizer +optim_wrapper = dict(optimizer=dict( + type=Adam, + lr=5e-4, +)) + +# learning policy +param_scheduler = [ + dict(type=LinearLR, begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type=MultiStepLR, + begin=0, + end=210, + milestones=[170, 200], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks.update(checkpoint=dict(save_best='coco/AP', rule='greater')) + +# codec settings +codec = dict( + type=UDPHeatmap, input_size=(192, 256), heatmap_size=(48, 64), sigma=2) + +# model settings +model = dict( + type=TopdownPoseEstimator, + data_preprocessor=dict( + type=PoseDataPreprocessor, + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type=HRNet, + in_channels=3, + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(48, 96)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(48, 96, 192)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(48, 96, 192, 384))), + init_cfg=dict( + type=PretrainedInit, + checkpoint='https://download.openmmlab.com/mmpose/' + 'pretrain_models/hrnet_w48-8ef0771d.pth'), + ), + head=dict( + type=HeatmapHead, + in_channels=48, + out_channels=17, + deconv_out_channels=None, + loss=dict(type=KeypointMSELoss, use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=False, + )) + +# base dataset settings +dataset_type = CocoDataset +data_mode = 'topdown' +data_root = 'data/coco/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type=LoadImage, backend_args=backend_args), + dict(type=GetBBoxCenterScale), + dict(type=RandomFlip, direction='horizontal'), + dict(type=RandomHalfBody), + dict(type=RandomBBoxTransform), + dict(type=TopdownAffine, input_size=codec['input_size'], use_udp=True), + dict(type=GenerateTarget, encoder=codec), + dict(type=PackPoseInputs) +] +val_pipeline = [ + dict(type=LoadImage, backend_args=backend_args), + dict(type=GetBBoxCenterScale), + dict(type=TopdownAffine, input_size=codec['input_size'], use_udp=True), + dict(type=PackPoseInputs) +] + +# data loaders +train_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + sampler=dict(type=DefaultSampler, shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/person_keypoints_train2017.json', + data_prefix=dict(img='train2017/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=2, + persistent_workers=True, + drop_last=False, + sampler=dict(type=DefaultSampler, shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/person_keypoints_val2017.json', + bbox_file='data/coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', + data_prefix=dict(img='val2017/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = dict( + type=CocoMetric, + ann_file=data_root + 'annotations/person_keypoints_val2017.json') +test_evaluator = val_evaluator diff --git a/mmpose/datasets/datasets/__init__.py b/mmpose/datasets/datasets/__init__.py index 03a0f493ca..9f5801753f 100644 --- a/mmpose/datasets/datasets/__init__.py +++ b/mmpose/datasets/datasets/__init__.py @@ -2,6 +2,7 @@ from .animal import * # noqa: F401, F403 from .base import * # noqa: F401, F403 from .body import * # noqa: F401, F403 +from .body3d import * # noqa: F401, F403 from .face import * # noqa: F401, F403 from .fashion import * # noqa: F401, F403 from .hand import * # noqa: F401, F403 diff --git a/mmpose/datasets/datasets/animal/__init__.py b/mmpose/datasets/datasets/animal/__init__.py index dfe9b5938c..669f08cddd 100644 --- a/mmpose/datasets/datasets/animal/__init__.py +++ b/mmpose/datasets/datasets/animal/__init__.py @@ -1,4 +1,5 @@ # Copyright (c) OpenMMLab. All rights reserved. +from .animalkingdom_dataset import AnimalKingdomDataset from .animalpose_dataset import AnimalPoseDataset from .ap10k_dataset import AP10KDataset from .atrw_dataset import ATRWDataset @@ -10,5 +11,6 @@ __all__ = [ 'AnimalPoseDataset', 'AP10KDataset', 'Horse10Dataset', 'MacaqueDataset', - 'FlyDataset', 'LocustDataset', 'ZebraDataset', 'ATRWDataset' + 'FlyDataset', 'LocustDataset', 'ZebraDataset', 'ATRWDataset', + 'AnimalKingdomDataset' ] diff --git a/mmpose/datasets/datasets/animal/animalkingdom_dataset.py b/mmpose/datasets/datasets/animal/animalkingdom_dataset.py new file mode 100644 index 0000000000..35ccb8b67a --- /dev/null +++ b/mmpose/datasets/datasets/animal/animalkingdom_dataset.py @@ -0,0 +1,86 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmpose.registry import DATASETS +from ..base import BaseCocoStyleDataset + + +@DATASETS.register_module() +class AnimalKingdomDataset(BaseCocoStyleDataset): + """Animal Kingdom dataset for animal pose estimation. + + "[CVPR2022] Animal Kingdom: + A Large and Diverse Dataset for Animal Behavior Understanding" + More details can be found in the `paper + `__ . + + Website: + + The dataset loads raw features and apply specified transforms + to return a dict containing the image tensors and other information. + + Animal Kingdom keypoint indexes:: + + 0: 'Head_Mid_Top', + 1: 'Eye_Left', + 2: 'Eye_Right', + 3: 'Mouth_Front_Top', + 4: 'Mouth_Back_Left', + 5: 'Mouth_Back_Right', + 6: 'Mouth_Front_Bottom', + 7: 'Shoulder_Left', + 8: 'Shoulder_Right', + 9: 'Elbow_Left', + 10: 'Elbow_Right', + 11: 'Wrist_Left', + 12: 'Wrist_Right', + 13: 'Torso_Mid_Back', + 14: 'Hip_Left', + 15: 'Hip_Right', + 16: 'Knee_Left', + 17: 'Knee_Right', + 18: 'Ankle_Left ', + 19: 'Ankle_Right', + 20: 'Tail_Top_Back', + 21: 'Tail_Mid_Back', + 22: 'Tail_End_Back + + Args: + ann_file (str): Annotation file path. Default: ''. + bbox_file (str, optional): Detection result file path. If + ``bbox_file`` is set, detected bboxes loaded from this file will + be used instead of ground-truth bboxes. This setting is only for + evaluation, i.e., ignored when ``test_mode`` is ``False``. + Default: ``None``. + data_mode (str): Specifies the mode of data samples: ``'topdown'`` or + ``'bottomup'``. In ``'topdown'`` mode, each data sample contains + one instance; while in ``'bottomup'`` mode, each data sample + contains all instances in a image. Default: ``'topdown'`` + metainfo (dict, optional): Meta information for dataset, such as class + information. Default: ``None``. + data_root (str, optional): The root directory for ``data_prefix`` and + ``ann_file``. Default: ``None``. + data_prefix (dict, optional): Prefix for training data. Default: + ``dict(img=None, ann=None)``. + filter_cfg (dict, optional): Config for filter data. Default: `None`. + indices (int or Sequence[int], optional): Support using first few + data in annotation file to facilitate training/testing on a smaller + dataset. Default: ``None`` which means using all ``data_infos``. + serialize_data (bool, optional): Whether to hold memory using + serialized objects, when enabled, data loader workers can use + shared RAM from master process instead of making a copy. + Default: ``True``. + pipeline (list, optional): Processing pipeline. Default: []. + test_mode (bool, optional): ``test_mode=True`` means in test phase. + Default: ``False``. + lazy_init (bool, optional): Whether to load annotation during + instantiation. In some cases, such as visualization, only the meta + information of the dataset is needed, which is not necessary to + load annotation file. ``Basedataset`` can skip load annotations to + save time by set ``lazy_init=False``. Default: ``False``. + max_refetch (int, optional): If ``Basedataset.prepare_data`` get a + None img. The maximum extra number of cycles to get a valid + image. Default: 1000. + """ + + METAINFO: dict = dict(from_file='configs/_base_/datasets/ak.py') diff --git a/mmpose/datasets/datasets/base/__init__.py b/mmpose/datasets/datasets/base/__init__.py index 23bb4efb48..810440530e 100644 --- a/mmpose/datasets/datasets/base/__init__.py +++ b/mmpose/datasets/datasets/base/__init__.py @@ -1,4 +1,5 @@ # Copyright (c) OpenMMLab. All rights reserved. from .base_coco_style_dataset import BaseCocoStyleDataset +from .base_mocap_dataset import BaseMocapDataset -__all__ = ['BaseCocoStyleDataset'] +__all__ = ['BaseCocoStyleDataset', 'BaseMocapDataset'] diff --git a/mmpose/datasets/datasets/base/base_mocap_dataset.py b/mmpose/datasets/datasets/base/base_mocap_dataset.py new file mode 100644 index 0000000000..d671a6ae94 --- /dev/null +++ b/mmpose/datasets/datasets/base/base_mocap_dataset.py @@ -0,0 +1,403 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os.path as osp +from copy import deepcopy +from itertools import filterfalse, groupby +from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union + +import numpy as np +from mmengine.dataset import BaseDataset, force_full_init +from mmengine.fileio import exists, get_local_path, load +from mmengine.utils import is_abs +from PIL import Image + +from mmpose.registry import DATASETS +from ..utils import parse_pose_metainfo + + +@DATASETS.register_module() +class BaseMocapDataset(BaseDataset): + """Base class for 3d body datasets. + + Args: + ann_file (str): Annotation file path. Default: ''. + seq_len (int): Number of frames in a sequence. Default: 1. + causal (bool): If set to ``True``, the rightmost input frame will be + the target frame. Otherwise, the middle input frame will be the + target frame. Default: ``True``. + subset_frac (float): The fraction to reduce dataset size. If set to 1, + the dataset size is not reduced. Default: 1. + camera_param_file (str): Cameras' parameters file. Default: ``None``. + data_mode (str): Specifies the mode of data samples: ``'topdown'`` or + ``'bottomup'``. In ``'topdown'`` mode, each data sample contains + one instance; while in ``'bottomup'`` mode, each data sample + contains all instances in a image. Default: ``'topdown'`` + metainfo (dict, optional): Meta information for dataset, such as class + information. Default: ``None``. + data_root (str, optional): The root directory for ``data_prefix`` and + ``ann_file``. Default: ``None``. + data_prefix (dict, optional): Prefix for training data. + Default: ``dict(img='')``. + filter_cfg (dict, optional): Config for filter data. Default: `None`. + indices (int or Sequence[int], optional): Support using first few + data in annotation file to facilitate training/testing on a smaller + dataset. Default: ``None`` which means using all ``data_infos``. + serialize_data (bool, optional): Whether to hold memory using + serialized objects, when enabled, data loader workers can use + shared RAM from master process instead of making a copy. + Default: ``True``. + pipeline (list, optional): Processing pipeline. Default: []. + test_mode (bool, optional): ``test_mode=True`` means in test phase. + Default: ``False``. + lazy_init (bool, optional): Whether to load annotation during + instantiation. In some cases, such as visualization, only the meta + information of the dataset is needed, which is not necessary to + load annotation file. ``Basedataset`` can skip load annotations to + save time by set ``lazy_init=False``. Default: ``False``. + max_refetch (int, optional): If ``Basedataset.prepare_data`` get a + None img. The maximum extra number of cycles to get a valid + image. Default: 1000. + """ + + METAINFO: dict = dict() + + def __init__(self, + ann_file: str = '', + seq_len: int = 1, + causal: bool = True, + subset_frac: float = 1.0, + camera_param_file: Optional[str] = None, + data_mode: str = 'topdown', + metainfo: Optional[dict] = None, + data_root: Optional[str] = None, + data_prefix: dict = dict(img=''), + filter_cfg: Optional[dict] = None, + indices: Optional[Union[int, Sequence[int]]] = None, + serialize_data: bool = True, + pipeline: List[Union[dict, Callable]] = [], + test_mode: bool = False, + lazy_init: bool = False, + max_refetch: int = 1000): + + if data_mode not in {'topdown', 'bottomup'}: + raise ValueError( + f'{self.__class__.__name__} got invalid data_mode: ' + f'{data_mode}. Should be "topdown" or "bottomup".') + self.data_mode = data_mode + + _ann_file = ann_file + if not is_abs(_ann_file): + _ann_file = osp.join(data_root, _ann_file) + assert exists(_ann_file), 'Annotation file does not exist.' + with get_local_path(_ann_file) as local_path: + self.ann_data = np.load(local_path) + + self.camera_param_file = camera_param_file + if self.camera_param_file: + if not is_abs(self.camera_param_file): + self.camera_param_file = osp.join(data_root, + self.camera_param_file) + assert exists(self.camera_param_file) + self.camera_param = load(self.camera_param_file) + + self.seq_len = seq_len + self.causal = causal + + assert 0 < subset_frac <= 1, ( + f'Unsupported `subset_frac` {subset_frac}. Supported range ' + 'is (0, 1].') + self.subset_frac = subset_frac + + self.sequence_indices = self.get_sequence_indices() + + super().__init__( + ann_file=ann_file, + metainfo=metainfo, + data_root=data_root, + data_prefix=data_prefix, + filter_cfg=filter_cfg, + indices=indices, + serialize_data=serialize_data, + pipeline=pipeline, + test_mode=test_mode, + lazy_init=lazy_init, + max_refetch=max_refetch) + + @classmethod + def _load_metainfo(cls, metainfo: dict = None) -> dict: + """Collect meta information from the dictionary of meta. + + Args: + metainfo (dict): Raw data of pose meta information. + + Returns: + dict: Parsed meta information. + """ + + if metainfo is None: + metainfo = deepcopy(cls.METAINFO) + + if not isinstance(metainfo, dict): + raise TypeError( + f'metainfo should be a dict, but got {type(metainfo)}') + + # parse pose metainfo if it has been assigned + if metainfo: + metainfo = parse_pose_metainfo(metainfo) + return metainfo + + @force_full_init + def prepare_data(self, idx) -> Any: + """Get data processed by ``self.pipeline``. + + :class:`BaseCocoStyleDataset` overrides this method from + :class:`mmengine.dataset.BaseDataset` to add the metainfo into + the ``data_info`` before it is passed to the pipeline. + + Args: + idx (int): The index of ``data_info``. + + Returns: + Any: Depends on ``self.pipeline``. + """ + data_info = self.get_data_info(idx) + + return self.pipeline(data_info) + + def get_data_info(self, idx: int) -> dict: + """Get data info by index. + + Args: + idx (int): Index of data info. + + Returns: + dict: Data info. + """ + data_info = super().get_data_info(idx) + + # Add metainfo items that are required in the pipeline and the model + metainfo_keys = [ + 'upper_body_ids', 'lower_body_ids', 'flip_pairs', + 'dataset_keypoint_weights', 'flip_indices', 'skeleton_links' + ] + + for key in metainfo_keys: + assert key not in data_info, ( + f'"{key}" is a reserved key for `metainfo`, but already ' + 'exists in the `data_info`.') + + data_info[key] = deepcopy(self._metainfo[key]) + + return data_info + + def load_data_list(self) -> List[dict]: + """Load data list from COCO annotation file or person detection result + file.""" + + instance_list, image_list = self._load_annotations() + + if self.data_mode == 'topdown': + data_list = self._get_topdown_data_infos(instance_list) + else: + data_list = self._get_bottomup_data_infos(instance_list, + image_list) + + return data_list + + def get_img_info(self, img_idx, img_name): + try: + with get_local_path(osp.join(self.data_prefix['img'], + img_name)) as local_path: + im = Image.open(local_path) + w, h = im.size + im.close() + except: # noqa: E722 + return None + + img = { + 'file_name': img_name, + 'height': h, + 'width': w, + 'id': img_idx, + 'img_id': img_idx, + 'img_path': osp.join(self.data_prefix['img'], img_name), + } + return img + + def get_sequence_indices(self) -> List[List[int]]: + """Build sequence indices. + + The default method creates sample indices that each sample is a single + frame (i.e. seq_len=1). Override this method in the subclass to define + how frames are sampled to form data samples. + + Outputs: + sample_indices: the frame indices of each sample. + For a sample, all frames will be treated as an input sequence, + and the ground-truth pose of the last frame will be the target. + """ + sequence_indices = [] + if self.seq_len == 1: + num_imgs = len(self.ann_data['imgname']) + sequence_indices = [[idx] for idx in range(num_imgs)] + else: + raise NotImplementedError('Multi-frame data sample unsupported!') + return sequence_indices + + def _load_annotations(self) -> Tuple[List[dict], List[dict]]: + """Load data from annotations in COCO format.""" + num_keypoints = self.metainfo['num_keypoints'] + + img_names = self.ann_data['imgname'] + num_imgs = len(img_names) + + if 'S' in self.ann_data.keys(): + kpts_3d = self.ann_data['S'] + else: + kpts_3d = np.zeros((num_imgs, num_keypoints, 4), dtype=np.float32) + + if 'part' in self.ann_data.keys(): + kpts_2d = self.ann_data['part'] + else: + kpts_2d = np.zeros((num_imgs, num_keypoints, 3), dtype=np.float32) + + if 'center' in self.ann_data.keys(): + centers = self.ann_data['center'] + else: + centers = np.zeros((num_imgs, 2), dtype=np.float32) + + if 'scale' in self.ann_data.keys(): + scales = self.ann_data['scale'].astype(np.float32) + else: + scales = np.zeros(num_imgs, dtype=np.float32) + + instance_list = [] + image_list = [] + + for idx, frame_ids in enumerate(self.sequence_indices): + assert len(frame_ids) == self.seq_len + + _img_names = img_names[frame_ids] + + _keypoints = kpts_2d[frame_ids].astype(np.float32) + keypoints = _keypoints[..., :2] + keypoints_visible = _keypoints[..., 2] + + _keypoints_3d = kpts_3d[frame_ids].astype(np.float32) + keypoints_3d = _keypoints_3d[..., :3] + keypoints_3d_visible = _keypoints_3d[..., 3] + + target_idx = -1 if self.causal else int(self.seq_len) // 2 + + instance_info = { + 'num_keypoints': num_keypoints, + 'keypoints': keypoints, + 'keypoints_visible': keypoints_visible, + 'keypoints_3d': keypoints_3d, + 'keypoints_3d_visible': keypoints_3d_visible, + 'scale': scales[idx], + 'center': centers[idx].astype(np.float32).reshape(1, -1), + 'id': idx, + 'category_id': 1, + 'iscrowd': 0, + 'img_paths': list(_img_names), + 'img_ids': frame_ids, + 'lifting_target': keypoints_3d[target_idx], + 'lifting_target_visible': keypoints_3d_visible[target_idx], + 'target_img_path': _img_names[target_idx], + } + + if self.camera_param_file: + _cam_param = self.get_camera_param(_img_names[0]) + instance_info['camera_param'] = _cam_param + + instance_list.append(instance_info) + + for idx, imgname in enumerate(img_names): + img_info = self.get_img_info(idx, imgname) + image_list.append(img_info) + + return instance_list, image_list + + def get_camera_param(self, imgname): + """Get camera parameters of a frame by its image name. + + Override this method to specify how to get camera parameters. + """ + raise NotImplementedError + + @staticmethod + def _is_valid_instance(data_info: Dict) -> bool: + """Check a data info is an instance with valid bbox and keypoint + annotations.""" + # crowd annotation + if 'iscrowd' in data_info and data_info['iscrowd']: + return False + # invalid keypoints + if 'num_keypoints' in data_info and data_info['num_keypoints'] == 0: + return False + # invalid keypoints + if 'keypoints' in data_info: + if np.max(data_info['keypoints']) <= 0: + return False + return True + + def _get_topdown_data_infos(self, instance_list: List[Dict]) -> List[Dict]: + """Organize the data list in top-down mode.""" + # sanitize data samples + data_list_tp = list(filter(self._is_valid_instance, instance_list)) + + return data_list_tp + + def _get_bottomup_data_infos(self, instance_list: List[Dict], + image_list: List[Dict]) -> List[Dict]: + """Organize the data list in bottom-up mode.""" + + # bottom-up data list + data_list_bu = [] + + used_img_ids = set() + + # group instances by img_id + for img_ids, data_infos in groupby(instance_list, + lambda x: x['img_ids']): + for img_id in img_ids: + used_img_ids.add(img_id) + data_infos = list(data_infos) + + # image data + img_paths = data_infos[0]['img_paths'] + data_info_bu = { + 'img_ids': img_ids, + 'img_paths': img_paths, + } + + for key in data_infos[0].keys(): + if key not in data_info_bu: + seq = [d[key] for d in data_infos] + if isinstance(seq[0], np.ndarray): + seq = np.concatenate(seq, axis=0) + data_info_bu[key] = seq + + # The segmentation annotation of invalid objects will be used + # to generate valid region mask in the pipeline. + invalid_segs = [] + for data_info_invalid in filterfalse(self._is_valid_instance, + data_infos): + if 'segmentation' in data_info_invalid: + invalid_segs.append(data_info_invalid['segmentation']) + data_info_bu['invalid_segs'] = invalid_segs + + data_list_bu.append(data_info_bu) + + # add images without instance for evaluation + if self.test_mode: + for img_info in image_list: + if img_info['img_id'] not in used_img_ids: + data_info_bu = { + 'img_ids': [img_info['img_id']], + 'img_path': [img_info['img_path']], + 'id': list(), + } + data_list_bu.append(data_info_bu) + + return data_list_bu diff --git a/mmpose/datasets/datasets/body/__init__.py b/mmpose/datasets/datasets/body/__init__.py index a4aeef8519..1405b0d675 100644 --- a/mmpose/datasets/datasets/body/__init__.py +++ b/mmpose/datasets/datasets/body/__init__.py @@ -2,6 +2,7 @@ from .aic_dataset import AicDataset from .coco_dataset import CocoDataset from .crowdpose_dataset import CrowdPoseDataset +from .humanart_dataset import HumanArtDataset from .jhmdb_dataset import JhmdbDataset from .mhp_dataset import MhpDataset from .mpii_dataset import MpiiDataset @@ -13,5 +14,5 @@ __all__ = [ 'CocoDataset', 'MpiiDataset', 'MpiiTrbDataset', 'AicDataset', 'CrowdPoseDataset', 'OCHumanDataset', 'MhpDataset', 'PoseTrack18Dataset', - 'JhmdbDataset', 'PoseTrack18VideoDataset' + 'JhmdbDataset', 'PoseTrack18VideoDataset', 'HumanArtDataset' ] diff --git a/mmpose/datasets/datasets/body/humanart_dataset.py b/mmpose/datasets/datasets/body/humanart_dataset.py new file mode 100644 index 0000000000..719f35fc9e --- /dev/null +++ b/mmpose/datasets/datasets/body/humanart_dataset.py @@ -0,0 +1,73 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmpose.registry import DATASETS +from ..base import BaseCocoStyleDataset + + +@DATASETS.register_module() +class HumanArtDataset(BaseCocoStyleDataset): + """Human-Art dataset for pose estimation. + + "Human-Art: A Versatile Human-Centric Dataset + Bridging Natural and Artificial Scenes", CVPR'2023. + More details can be found in the `paper + `__ . + + Human-Art keypoints:: + + 0: 'nose', + 1: 'left_eye', + 2: 'right_eye', + 3: 'left_ear', + 4: 'right_ear', + 5: 'left_shoulder', + 6: 'right_shoulder', + 7: 'left_elbow', + 8: 'right_elbow', + 9: 'left_wrist', + 10: 'right_wrist', + 11: 'left_hip', + 12: 'right_hip', + 13: 'left_knee', + 14: 'right_knee', + 15: 'left_ankle', + 16: 'right_ankle' + + Args: + ann_file (str): Annotation file path. Default: ''. + bbox_file (str, optional): Detection result file path. If + ``bbox_file`` is set, detected bboxes loaded from this file will + be used instead of ground-truth bboxes. This setting is only for + evaluation, i.e., ignored when ``test_mode`` is ``False``. + Default: ``None``. + data_mode (str): Specifies the mode of data samples: ``'topdown'`` or + ``'bottomup'``. In ``'topdown'`` mode, each data sample contains + one instance; while in ``'bottomup'`` mode, each data sample + contains all instances in a image. Default: ``'topdown'`` + metainfo (dict, optional): Meta information for dataset, such as class + information. Default: ``None``. + data_root (str, optional): The root directory for ``data_prefix`` and + ``ann_file``. Default: ``None``. + data_prefix (dict, optional): Prefix for training data. Default: + ``dict(img=None, ann=None)``. + filter_cfg (dict, optional): Config for filter data. Default: `None`. + indices (int or Sequence[int], optional): Support using first few + data in annotation file to facilitate training/testing on a smaller + dataset. Default: ``None`` which means using all ``data_infos``. + serialize_data (bool, optional): Whether to hold memory using + serialized objects, when enabled, data loader workers can use + shared RAM from master process instead of making a copy. + Default: ``True``. + pipeline (list, optional): Processing pipeline. Default: []. + test_mode (bool, optional): ``test_mode=True`` means in test phase. + Default: ``False``. + lazy_init (bool, optional): Whether to load annotation during + instantiation. In some cases, such as visualization, only the meta + information of the dataset is needed, which is not necessary to + load annotation file. ``Basedataset`` can skip load annotations to + save time by set ``lazy_init=False``. Default: ``False``. + max_refetch (int, optional): If ``Basedataset.prepare_data`` get a + None img. The maximum extra number of cycles to get a valid + image. Default: 1000. + """ + + METAINFO: dict = dict(from_file='configs/_base_/datasets/humanart.py') diff --git a/mmpose/datasets/datasets/body3d/__init__.py b/mmpose/datasets/datasets/body3d/__init__.py new file mode 100644 index 0000000000..d5afeca578 --- /dev/null +++ b/mmpose/datasets/datasets/body3d/__init__.py @@ -0,0 +1,4 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from .h36m_dataset import Human36mDataset + +__all__ = ['Human36mDataset'] diff --git a/mmpose/datasets/datasets/body3d/h36m_dataset.py b/mmpose/datasets/datasets/body3d/h36m_dataset.py new file mode 100644 index 0000000000..60094aa254 --- /dev/null +++ b/mmpose/datasets/datasets/body3d/h36m_dataset.py @@ -0,0 +1,259 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os.path as osp +from collections import defaultdict +from typing import Callable, List, Optional, Sequence, Tuple, Union + +import numpy as np +from mmengine.fileio import exists, get_local_path +from mmengine.utils import is_abs + +from mmpose.datasets.datasets import BaseMocapDataset +from mmpose.registry import DATASETS + + +@DATASETS.register_module() +class Human36mDataset(BaseMocapDataset): + """Human3.6M dataset for 3D human pose estimation. + + "Human3.6M: Large Scale Datasets and Predictive Methods for 3D Human + Sensing in Natural Environments", TPAMI`2014. + More details can be found in the `paper + `__. + + Human3.6M keypoint indexes:: + + 0: 'root (pelvis)', + 1: 'right_hip', + 2: 'right_knee', + 3: 'right_foot', + 4: 'left_hip', + 5: 'left_knee', + 6: 'left_foot', + 7: 'spine', + 8: 'thorax', + 9: 'neck_base', + 10: 'head', + 11: 'left_shoulder', + 12: 'left_elbow', + 13: 'left_wrist', + 14: 'right_shoulder', + 15: 'right_elbow', + 16: 'right_wrist' + + Args: + ann_file (str): Annotation file path. Default: ''. + seq_len (int): Number of frames in a sequence. Default: 1. + seq_step (int): The interval for extracting frames from the video. + Default: 1. + pad_video_seq (bool): Whether to pad the video so that poses will be + predicted for every frame in the video. Default: ``False``. + causal (bool): If set to ``True``, the rightmost input frame will be + the target frame. Otherwise, the middle input frame will be the + target frame. Default: ``True``. + subset_frac (float): The fraction to reduce dataset size. If set to 1, + the dataset size is not reduced. Default: 1. + keypoint_2d_src (str): Specifies 2D keypoint information options, which + should be one of the following options: + + - ``'gt'``: load from the annotation file + - ``'detection'``: load from a detection + result file of 2D keypoint + - 'pipeline': the information will be generated by the pipeline + + Default: ``'gt'``. + keypoint_2d_det_file (str, optional): The 2D keypoint detection file. + If set, 2d keypoint loaded from this file will be used instead of + ground-truth keypoints. This setting is only when + ``keypoint_2d_src`` is ``'detection'``. Default: ``None``. + camera_param_file (str): Cameras' parameters file. Default: ``None``. + data_mode (str): Specifies the mode of data samples: ``'topdown'`` or + ``'bottomup'``. In ``'topdown'`` mode, each data sample contains + one instance; while in ``'bottomup'`` mode, each data sample + contains all instances in a image. Default: ``'topdown'`` + metainfo (dict, optional): Meta information for dataset, such as class + information. Default: ``None``. + data_root (str, optional): The root directory for ``data_prefix`` and + ``ann_file``. Default: ``None``. + data_prefix (dict, optional): Prefix for training data. + Default: ``dict(img='')``. + filter_cfg (dict, optional): Config for filter data. Default: `None`. + indices (int or Sequence[int], optional): Support using first few + data in annotation file to facilitate training/testing on a smaller + dataset. Default: ``None`` which means using all ``data_infos``. + serialize_data (bool, optional): Whether to hold memory using + serialized objects, when enabled, data loader workers can use + shared RAM from master process instead of making a copy. + Default: ``True``. + pipeline (list, optional): Processing pipeline. Default: []. + test_mode (bool, optional): ``test_mode=True`` means in test phase. + Default: ``False``. + lazy_init (bool, optional): Whether to load annotation during + instantiation. In some cases, such as visualization, only the meta + information of the dataset is needed, which is not necessary to + load annotation file. ``Basedataset`` can skip load annotations to + save time by set ``lazy_init=False``. Default: ``False``. + max_refetch (int, optional): If ``Basedataset.prepare_data`` get a + None img. The maximum extra number of cycles to get a valid + image. Default: 1000. + """ + + METAINFO: dict = dict(from_file='configs/_base_/datasets/h36m.py') + SUPPORTED_keypoint_2d_src = {'gt', 'detection', 'pipeline'} + + def __init__(self, + ann_file: str = '', + seq_len: int = 1, + seq_step: int = 1, + pad_video_seq: bool = False, + causal: bool = True, + subset_frac: float = 1.0, + keypoint_2d_src: str = 'gt', + keypoint_2d_det_file: Optional[str] = None, + camera_param_file: Optional[str] = None, + data_mode: str = 'topdown', + metainfo: Optional[dict] = None, + data_root: Optional[str] = None, + data_prefix: dict = dict(img=''), + filter_cfg: Optional[dict] = None, + indices: Optional[Union[int, Sequence[int]]] = None, + serialize_data: bool = True, + pipeline: List[Union[dict, Callable]] = [], + test_mode: bool = False, + lazy_init: bool = False, + max_refetch: int = 1000): + # check keypoint_2d_src + self.keypoint_2d_src = keypoint_2d_src + if self.keypoint_2d_src not in self.SUPPORTED_keypoint_2d_src: + raise ValueError( + f'Unsupported `keypoint_2d_src` "{self.keypoint_2d_src}". ' + f'Supported options are {self.SUPPORTED_keypoint_2d_src}') + + if keypoint_2d_det_file: + if not is_abs(keypoint_2d_det_file): + self.keypoint_2d_det_file = osp.join(data_root, + keypoint_2d_det_file) + else: + self.keypoint_2d_det_file = keypoint_2d_det_file + + self.seq_step = seq_step + self.pad_video_seq = pad_video_seq + + super().__init__( + ann_file=ann_file, + seq_len=seq_len, + causal=causal, + subset_frac=subset_frac, + camera_param_file=camera_param_file, + data_mode=data_mode, + metainfo=metainfo, + data_root=data_root, + data_prefix=data_prefix, + filter_cfg=filter_cfg, + indices=indices, + serialize_data=serialize_data, + pipeline=pipeline, + test_mode=test_mode, + lazy_init=lazy_init, + max_refetch=max_refetch) + + def get_sequence_indices(self) -> List[List[int]]: + """Split original videos into sequences and build frame indices. + + This method overrides the default one in the base class. + """ + imgnames = self.ann_data['imgname'] + video_frames = defaultdict(list) + for idx, imgname in enumerate(imgnames): + subj, action, camera = self._parse_h36m_imgname(imgname) + video_frames[(subj, action, camera)].append(idx) + + # build sample indices + sequence_indices = [] + _len = (self.seq_len - 1) * self.seq_step + 1 + _step = self.seq_step + for _, _indices in sorted(video_frames.items()): + n_frame = len(_indices) + + if self.pad_video_seq: + # Pad the sequence so that every frame in the sequence will be + # predicted. + if self.causal: + frames_left = self.seq_len - 1 + frames_right = 0 + else: + frames_left = (self.seq_len - 1) // 2 + frames_right = frames_left + for i in range(n_frame): + pad_left = max(0, frames_left - i // _step) + pad_right = max(0, + frames_right - (n_frame - 1 - i) // _step) + start = max(i % _step, i - frames_left * _step) + end = min(n_frame - (n_frame - 1 - i) % _step, + i + frames_right * _step + 1) + sequence_indices.append([_indices[0]] * pad_left + + _indices[start:end:_step] + + [_indices[-1]] * pad_right) + else: + seqs_from_video = [ + _indices[i:(i + _len):_step] + for i in range(0, n_frame - _len + 1) + ] + sequence_indices.extend(seqs_from_video) + + # reduce dataset size if needed + subset_size = int(len(sequence_indices) * self.subset_frac) + start = np.random.randint(0, len(sequence_indices) - subset_size + 1) + end = start + subset_size + + return sequence_indices[start:end] + + def _load_annotations(self) -> Tuple[List[dict], List[dict]]: + instance_list, image_list = super()._load_annotations() + + h36m_data = self.ann_data + kpts_3d = h36m_data['S'] + + if self.keypoint_2d_src == 'detection': + assert exists(self.keypoint_2d_det_file) + kpts_2d = self._load_keypoint_2d_detection( + self.keypoint_2d_det_file) + assert kpts_2d.shape[0] == kpts_3d.shape[0] + assert kpts_2d.shape[2] == 3 + + for idx, frame_ids in enumerate(self.sequence_indices): + kpt_2d = kpts_2d[frame_ids].astype(np.float32) + keypoints = kpt_2d[..., :2] + keypoints_visible = kpt_2d[..., 2] + instance_list[idx].update({ + 'keypoints': + keypoints, + 'keypoints_visible': + keypoints_visible + }) + + return instance_list, image_list + + @staticmethod + def _parse_h36m_imgname(imgname) -> Tuple[str, str, str]: + """Parse imgname to get information of subject, action and camera. + + A typical h36m image filename is like: + S1_Directions_1.54138969_000001.jpg + """ + subj, rest = osp.basename(imgname).split('_', 1) + action, rest = rest.split('.', 1) + camera, rest = rest.split('_', 1) + return subj, action, camera + + def get_camera_param(self, imgname) -> dict: + """Get camera parameters of a frame by its image name.""" + assert hasattr(self, 'camera_param') + subj, _, camera = self._parse_h36m_imgname(imgname) + return self.camera_param[(subj, camera)] + + def _load_keypoint_2d_detection(self, det_file): + """"Load 2D joint detection results from file.""" + with get_local_path(det_file) as local_path: + kpts_2d = np.load(local_path).astype(np.float32) + + return kpts_2d diff --git a/mmpose/datasets/datasets/face/__init__.py b/mmpose/datasets/datasets/face/__init__.py index e0a725cd0e..700cb605f7 100644 --- a/mmpose/datasets/datasets/face/__init__.py +++ b/mmpose/datasets/datasets/face/__init__.py @@ -3,9 +3,10 @@ from .coco_wholebody_face_dataset import CocoWholeBodyFaceDataset from .cofw_dataset import COFWDataset from .face_300w_dataset import Face300WDataset +from .lapa_dataset import LapaDataset from .wflw_dataset import WFLWDataset __all__ = [ 'Face300WDataset', 'WFLWDataset', 'AFLWDataset', 'COFWDataset', - 'CocoWholeBodyFaceDataset' + 'CocoWholeBodyFaceDataset', 'LapaDataset' ] diff --git a/mmpose/datasets/datasets/face/lapa_dataset.py b/mmpose/datasets/datasets/face/lapa_dataset.py new file mode 100644 index 0000000000..1a5bdc4ec0 --- /dev/null +++ b/mmpose/datasets/datasets/face/lapa_dataset.py @@ -0,0 +1,54 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmpose.registry import DATASETS +from ..base import BaseCocoStyleDataset + + +@DATASETS.register_module() +class LapaDataset(BaseCocoStyleDataset): + """LaPa dataset for face keypoint localization. + + "A New Dataset and Boundary-Attention Semantic Segmentation + for Face Parsing", AAAI'2020. + + The landmark annotations follow the 106 points mark-up. The definition + can be found in `https://github.com/JDAI-CV/lapa-dataset/`__ . + + Args: + ann_file (str): Annotation file path. Default: ''. + bbox_file (str, optional): Detection result file path. If + ``bbox_file`` is set, detected bboxes loaded from this file will + be used instead of ground-truth bboxes. This setting is only for + evaluation, i.e., ignored when ``test_mode`` is ``False``. + Default: ``None``. + data_mode (str): Specifies the mode of data samples: ``'topdown'`` or + ``'bottomup'``. In ``'topdown'`` mode, each data sample contains + one instance; while in ``'bottomup'`` mode, each data sample + contains all instances in a image. Default: ``'topdown'`` + metainfo (dict, optional): Meta information for dataset, such as class + information. Default: ``None``. + data_root (str, optional): The root directory for ``data_prefix`` and + ``ann_file``. Default: ``None``. + data_prefix (dict, optional): Prefix for training data. Default: + ``dict(img=None, ann=None)``. + filter_cfg (dict, optional): Config for filter data. Default: `None`. + indices (int or Sequence[int], optional): Support using first few + data in annotation file to facilitate training/testing on a smaller + dataset. Default: ``None`` which means using all ``data_infos``. + serialize_data (bool, optional): Whether to hold memory using + serialized objects, when enabled, data loader workers can use + shared RAM from master process instead of making a copy. + Default: ``True``. + pipeline (list, optional): Processing pipeline. Default: []. + test_mode (bool, optional): ``test_mode=True`` means in test phase. + Default: ``False``. + lazy_init (bool, optional): Whether to load annotation during + instantiation. In some cases, such as visualization, only the meta + information of the dataset is needed, which is not necessary to + load annotation file. ``Basedataset`` can skip load annotations to + save time by set ``lazy_init=False``. Default: ``False``. + max_refetch (int, optional): If ``Basedataset.prepare_data`` get a + None img. The maximum extra number of cycles to get a valid + image. Default: 1000. + """ + + METAINFO: dict = dict(from_file='configs/_base_/datasets/lapa.py') diff --git a/mmpose/datasets/datasets/fashion/__init__.py b/mmpose/datasets/datasets/fashion/__init__.py index 575d6ed4af..8be25dede3 100644 --- a/mmpose/datasets/datasets/fashion/__init__.py +++ b/mmpose/datasets/datasets/fashion/__init__.py @@ -1,4 +1,5 @@ # Copyright (c) OpenMMLab. All rights reserved. +from .deepfashion2_dataset import DeepFashion2Dataset from .deepfashion_dataset import DeepFashionDataset -__all__ = ['DeepFashionDataset'] +__all__ = ['DeepFashionDataset', 'DeepFashion2Dataset'] diff --git a/mmpose/datasets/datasets/fashion/deepfashion2_dataset.py b/mmpose/datasets/datasets/fashion/deepfashion2_dataset.py new file mode 100644 index 0000000000..c3cde9bf97 --- /dev/null +++ b/mmpose/datasets/datasets/fashion/deepfashion2_dataset.py @@ -0,0 +1,10 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from mmpose.registry import DATASETS +from ..base import BaseCocoStyleDataset + + +@DATASETS.register_module(name='DeepFashion2Dataset') +class DeepFashion2Dataset(BaseCocoStyleDataset): + """DeepFashion2 dataset for fashion landmark detection.""" + + METAINFO: dict = dict(from_file='configs/_base_/datasets/deepfashion2.py') diff --git a/mmpose/datasets/datasets/utils.py b/mmpose/datasets/datasets/utils.py index 5140126163..7433a168b9 100644 --- a/mmpose/datasets/datasets/utils.py +++ b/mmpose/datasets/datasets/utils.py @@ -174,6 +174,11 @@ def parse_pose_metainfo(metainfo: dict): metainfo['joint_weights'], dtype=np.float32) parsed['sigmas'] = np.array(metainfo['sigmas'], dtype=np.float32) + if 'stats_info' in metainfo: + parsed['stats_info'] = {} + for name, val in metainfo['stats_info'].items(): + parsed['stats_info'][name] = np.array(val, dtype=np.float32) + # formatting def _map(src, mapping: dict): if isinstance(src, (list, tuple)): diff --git a/mmpose/datasets/transforms/__init__.py b/mmpose/datasets/transforms/__init__.py index 61dae74b8c..7ccbf7dac2 100644 --- a/mmpose/datasets/transforms/__init__.py +++ b/mmpose/datasets/transforms/__init__.py @@ -8,6 +8,7 @@ from .converting import KeypointConverter from .formatting import PackPoseInputs from .loading import LoadImage +from .pose3d_transforms import RandomFlipAroundRoot from .topdown_transforms import TopdownAffine __all__ = [ @@ -15,5 +16,5 @@ 'RandomHalfBody', 'TopdownAffine', 'Albumentation', 'PhotometricDistortion', 'PackPoseInputs', 'LoadImage', 'BottomupGetHeatmapMask', 'BottomupRandomAffine', 'BottomupResize', - 'GenerateTarget', 'KeypointConverter' + 'GenerateTarget', 'KeypointConverter', 'RandomFlipAroundRoot' ] diff --git a/mmpose/datasets/transforms/common_transforms.py b/mmpose/datasets/transforms/common_transforms.py index 8db0ff37c7..87068246f8 100644 --- a/mmpose/datasets/transforms/common_transforms.py +++ b/mmpose/datasets/transforms/common_transforms.py @@ -649,6 +649,8 @@ def albu_builder(self, cfg: dict) -> albumentations: f'{obj_type} is not pixel-level transformations. ' 'Please use with caution.') obj_cls = getattr(albumentations, obj_type) + elif isinstance(obj_type, type): + obj_cls = obj_type else: raise TypeError(f'type must be a str, but got {type(obj_type)}') @@ -1029,6 +1031,16 @@ def transform(self, results: Dict) -> Optional[dict]: results.update(encoded) + if results.get('keypoint_weights', None) is not None: + results['transformed_keypoints_visible'] = results[ + 'keypoint_weights'] + elif results.get('keypoints', None) is not None: + results['transformed_keypoints_visible'] = results[ + 'keypoints_visible'] + else: + raise ValueError('GenerateTarget requires \'keypoint_weights\' or' + ' \'keypoints_visible\' in the results.') + return results def __repr__(self) -> str: diff --git a/mmpose/datasets/transforms/converting.py b/mmpose/datasets/transforms/converting.py index 0730808967..38dcea0994 100644 --- a/mmpose/datasets/transforms/converting.py +++ b/mmpose/datasets/transforms/converting.py @@ -1,5 +1,5 @@ # Copyright (c) OpenMMLab. All rights reserved. -from typing import List, Tuple +from typing import List, Tuple, Union import numpy as np from mmcv.transforms import BaseTransform @@ -25,11 +25,66 @@ class KeypointConverter(BaseTransform): num_keypoints (int): The number of keypoints in target dataset. mapping (list): A list containing mapping indexes. Each element has format (source_index, target_index) + + Example: + >>> import numpy as np + >>> # case 1: 1-to-1 mapping + >>> # (0, 0) means target[0] = source[0] + >>> self = KeypointConverter( + >>> num_keypoints=3, + >>> mapping=[ + >>> (0, 0), (1, 1), (2, 2), (3, 3) + >>> ]) + >>> results = dict( + >>> keypoints=np.arange(34).reshape(2, 3, 2), + >>> keypoints_visible=np.arange(34).reshape(2, 3, 2) % 2) + >>> results = self(results) + >>> assert np.equal(results['keypoints'], + >>> np.arange(34).reshape(2, 3, 2)).all() + >>> assert np.equal(results['keypoints_visible'], + >>> np.arange(34).reshape(2, 3, 2) % 2).all() + >>> + >>> # case 2: 2-to-1 mapping + >>> # ((1, 2), 0) means target[0] = (source[1] + source[2]) / 2 + >>> self = KeypointConverter( + >>> num_keypoints=3, + >>> mapping=[ + >>> ((1, 2), 0), (1, 1), (2, 2) + >>> ]) + >>> results = dict( + >>> keypoints=np.arange(34).reshape(2, 3, 2), + >>> keypoints_visible=np.arange(34).reshape(2, 3, 2) % 2) + >>> results = self(results) """ - def __init__(self, num_keypoints: int, mapping: List[Tuple[int, int]]): + def __init__(self, num_keypoints: int, + mapping: Union[List[Tuple[int, int]], List[Tuple[Tuple, + int]]]): self.num_keypoints = num_keypoints self.mapping = mapping + source_index, target_index = zip(*mapping) + + src1, src2 = [], [] + interpolation = False + for x in source_index: + if isinstance(x, (list, tuple)): + assert len(x) == 2, 'source_index should be a list/tuple of ' \ + 'length 2' + src1.append(x[0]) + src2.append(x[1]) + interpolation = True + else: + src1.append(x) + src2.append(x) + + # When paired source_indexes are input, + # keep a self.source_index2 for interpolation + if interpolation: + self.source_index2 = src2 + + self.source_index = src1 + self.target_index = target_index + self.interpolation = interpolation def transform(self, results: dict) -> dict: num_instances = results['keypoints'].shape[0] @@ -37,10 +92,22 @@ def transform(self, results: dict) -> dict: keypoints = np.zeros((num_instances, self.num_keypoints, 2)) keypoints_visible = np.zeros((num_instances, self.num_keypoints)) - source_index, target_index = zip(*self.mapping) - keypoints[:, target_index] = results['keypoints'][:, source_index] - keypoints_visible[:, target_index] = results[ - 'keypoints_visible'][:, source_index] + # When paired source_indexes are input, + # perform interpolation with self.source_index and self.source_index2 + if self.interpolation: + keypoints[:, self.target_index] = 0.5 * ( + results['keypoints'][:, self.source_index] + + results['keypoints'][:, self.source_index2]) + + keypoints_visible[:, self.target_index] = results[ + 'keypoints_visible'][:, self.source_index] * \ + results['keypoints_visible'][:, self.source_index2] + else: + keypoints[:, + self.target_index] = results['keypoints'][:, self. + source_index] + keypoints_visible[:, self.target_index] = results[ + 'keypoints_visible'][:, self.source_index] results['keypoints'] = keypoints results['keypoints_visible'] = keypoints_visible diff --git a/mmpose/datasets/transforms/formatting.py b/mmpose/datasets/transforms/formatting.py index dd9ad522f2..05aeef179f 100644 --- a/mmpose/datasets/transforms/formatting.py +++ b/mmpose/datasets/transforms/formatting.py @@ -37,6 +37,31 @@ def image_to_tensor(img: Union[np.ndarray, return tensor +def keypoints_to_tensor(keypoints: Union[np.ndarray, Sequence[np.ndarray]] + ) -> torch.torch.Tensor: + """Translate keypoints or sequence of keypoints to tensor. Multiple + keypoints tensors will be stacked. + + Args: + keypoints (np.ndarray | Sequence[np.ndarray]): The keypoints or + keypoints sequence. + + Returns: + torch.Tensor: The output tensor. + """ + if isinstance(keypoints, np.ndarray): + keypoints = np.ascontiguousarray(keypoints) + N = keypoints.shape[0] + keypoints = keypoints.transpose(1, 2, 0).reshape(-1, N) + tensor = torch.from_numpy(keypoints).contiguous() + else: + assert is_seq_of(keypoints, np.ndarray) + tensor = torch.stack( + [keypoints_to_tensor(_keypoints) for _keypoints in keypoints]) + + return tensor + + @TRANSFORMS.register_module() class PackPoseInputs(BaseTransform): """Pack the inputs data for pose estimation. @@ -89,6 +114,8 @@ class PackPoseInputs(BaseTransform): 'bbox_score': 'bbox_scores', 'keypoints': 'keypoints', 'keypoints_visible': 'keypoints_visible', + 'lifting_target': 'lifting_target', + 'lifting_target_visible': 'lifting_target_visible', } # items in `label_mapping_table` will be packed into @@ -96,10 +123,14 @@ class PackPoseInputs(BaseTransform): # will be used for computing losses label_mapping_table = { 'keypoint_labels': 'keypoint_labels', + 'lifting_target_label': 'lifting_target_label', + 'lifting_target_weights': 'lifting_target_weights', + 'trajectory_weights': 'trajectory_weights', 'keypoint_x_labels': 'keypoint_x_labels', 'keypoint_y_labels': 'keypoint_y_labels', 'keypoint_weights': 'keypoint_weights', - 'instance_coords': 'instance_coords' + 'instance_coords': 'instance_coords', + 'transformed_keypoints_visible': 'keypoints_visible', } # items in `field_mapping_table` will be packed into @@ -137,10 +168,17 @@ def transform(self, results: dict) -> dict: - 'data_samples' (obj:`PoseDataSample`): The annotation info of the sample. """ - # Pack image(s) + # Pack image(s) for 2d pose estimation if 'img' in results: img = results['img'] - img_tensor = image_to_tensor(img) + inputs_tensor = image_to_tensor(img) + # Pack keypoints for 3d pose-lifting + elif 'lifting_target' in results and 'keypoints' in results: + if 'keypoint_labels' in results: + keypoints = results['keypoint_labels'] + else: + keypoints = results['keypoints'] + inputs_tensor = keypoints_to_tensor(keypoints) data_sample = PoseDataSample() @@ -148,6 +186,10 @@ def transform(self, results: dict) -> dict: gt_instances = InstanceData() for key, packed_key in self.instance_mapping_table.items(): if key in results: + if 'lifting_target' in results and key in { + 'keypoints', 'keypoints_visible' + }: + continue gt_instances.set_field(results[key], packed_key) # pack `transformed_keypoints` for visualizing data transform @@ -155,6 +197,10 @@ def transform(self, results: dict) -> dict: if self.pack_transformed and 'transformed_keypoints' in results: gt_instances.set_field(results['transformed_keypoints'], 'transformed_keypoints') + if self.pack_transformed and \ + 'transformed_keypoints_visible' in results: + gt_instances.set_field(results['transformed_keypoints_visible'], + 'transformed_keypoints_visible') data_sample.gt_instances = gt_instances @@ -162,6 +208,12 @@ def transform(self, results: dict) -> dict: gt_instance_labels = InstanceData() for key, packed_key in self.label_mapping_table.items(): if key in results: + # For pose-lifting, store only target-related fields + if 'lifting_target_label' in results and key in { + 'keypoint_labels', 'keypoint_weights', + 'transformed_keypoints_visible' + }: + continue if isinstance(results[key], list): # A list of labels is usually generated by combined # multiple encoders (See ``GenerateTarget`` in @@ -202,7 +254,7 @@ def transform(self, results: dict) -> dict: data_sample.set_metainfo(img_meta) packed_results = dict() - packed_results['inputs'] = img_tensor + packed_results['inputs'] = inputs_tensor packed_results['data_samples'] = data_sample return packed_results diff --git a/mmpose/datasets/transforms/pose3d_transforms.py b/mmpose/datasets/transforms/pose3d_transforms.py new file mode 100644 index 0000000000..e6559fa398 --- /dev/null +++ b/mmpose/datasets/transforms/pose3d_transforms.py @@ -0,0 +1,105 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from copy import deepcopy +from typing import Dict + +import numpy as np +from mmcv.transforms import BaseTransform + +from mmpose.registry import TRANSFORMS +from mmpose.structures.keypoint import flip_keypoints_custom_center + + +@TRANSFORMS.register_module() +class RandomFlipAroundRoot(BaseTransform): + """Data augmentation with random horizontal joint flip around a root joint. + + Args: + keypoints_flip_cfg (dict): Configurations of the + ``flip_keypoints_custom_center`` function for ``keypoints``. Please + refer to the docstring of the ``flip_keypoints_custom_center`` + function for more details. + target_flip_cfg (dict): Configurations of the + ``flip_keypoints_custom_center`` function for ``lifting_target``. + Please refer to the docstring of the + ``flip_keypoints_custom_center`` function for more details. + flip_prob (float): Probability of flip. Default: 0.5. + flip_camera (bool): Whether to flip horizontal distortion coefficients. + Default: ``False``. + + Required keys: + keypoints + lifting_target + + Modified keys: + (keypoints, keypoints_visible, lifting_target, lifting_target_visible, + camera_param) + """ + + def __init__(self, + keypoints_flip_cfg, + target_flip_cfg, + flip_prob=0.5, + flip_camera=False): + self.keypoints_flip_cfg = keypoints_flip_cfg + self.target_flip_cfg = target_flip_cfg + self.flip_prob = flip_prob + self.flip_camera = flip_camera + + def transform(self, results: Dict) -> dict: + """The transform function of :class:`ZeroCenterPose`. + + See ``transform()`` method of :class:`BaseTransform` for details. + + Args: + results (dict): The result dict + + Returns: + dict: The result dict. + """ + + keypoints = results['keypoints'] + if 'keypoints_visible' in results: + keypoints_visible = results['keypoints_visible'] + else: + keypoints_visible = np.ones(keypoints.shape[:-1], dtype=np.float32) + lifting_target = results['lifting_target'] + if 'lifting_target_visible' in results: + lifting_target_visible = results['lifting_target_visible'] + else: + lifting_target_visible = np.ones( + lifting_target.shape[:-1], dtype=np.float32) + + if np.random.rand() <= self.flip_prob: + if 'flip_indices' not in results: + flip_indices = list(range(self.num_keypoints)) + else: + flip_indices = results['flip_indices'] + + # flip joint coordinates + keypoints, keypoints_visible = flip_keypoints_custom_center( + keypoints, keypoints_visible, flip_indices, + **self.keypoints_flip_cfg) + lifting_target, lifting_target_visible = flip_keypoints_custom_center( # noqa + lifting_target, lifting_target_visible, flip_indices, + **self.target_flip_cfg) + + results['keypoints'] = keypoints + results['keypoints_visible'] = keypoints_visible + results['lifting_target'] = lifting_target + results['lifting_target_visible'] = lifting_target_visible + + # flip horizontal distortion coefficients + if self.flip_camera: + assert 'camera_param' in results, \ + 'Camera parameters are missing.' + _camera_param = deepcopy(results['camera_param']) + + assert 'c' in _camera_param + _camera_param['c'][0] *= -1 + + if 'p' in _camera_param: + _camera_param['p'][0] *= -1 + + results['camera_param'].update(_camera_param) + + return results diff --git a/mmpose/evaluation/functional/__init__.py b/mmpose/evaluation/functional/__init__.py index 2c4a8b5d1e..49f243163c 100644 --- a/mmpose/evaluation/functional/__init__.py +++ b/mmpose/evaluation/functional/__init__.py @@ -1,6 +1,6 @@ # Copyright (c) OpenMMLab. All rights reserved. -from .keypoint_eval import (keypoint_auc, keypoint_epe, keypoint_nme, - keypoint_pck_accuracy, +from .keypoint_eval import (keypoint_auc, keypoint_epe, keypoint_mpjpe, + keypoint_nme, keypoint_pck_accuracy, multilabel_classification_accuracy, pose_pck_accuracy, simcc_pck_accuracy) from .nms import nms, oks_nms, soft_oks_nms @@ -8,5 +8,5 @@ __all__ = [ 'keypoint_pck_accuracy', 'keypoint_auc', 'keypoint_nme', 'keypoint_epe', 'pose_pck_accuracy', 'multilabel_classification_accuracy', - 'simcc_pck_accuracy', 'nms', 'oks_nms', 'soft_oks_nms' + 'simcc_pck_accuracy', 'nms', 'oks_nms', 'soft_oks_nms', 'keypoint_mpjpe' ] diff --git a/mmpose/evaluation/functional/keypoint_eval.py b/mmpose/evaluation/functional/keypoint_eval.py index 060243357b..847faaf6d8 100644 --- a/mmpose/evaluation/functional/keypoint_eval.py +++ b/mmpose/evaluation/functional/keypoint_eval.py @@ -4,6 +4,7 @@ import numpy as np from mmpose.codecs.utils import get_heatmap_maximum, get_simcc_maximum +from .mesh_eval import compute_similarity_transform def _calc_distances(preds: np.ndarray, gts: np.ndarray, mask: np.ndarray, @@ -98,7 +99,7 @@ def keypoint_pck_accuracy(pred: np.ndarray, gt: np.ndarray, mask: np.ndarray, acc = np.array([_distance_acc(d, thr) for d in distances]) valid_acc = acc[acc >= 0] cnt = len(valid_acc) - avg_acc = valid_acc.mean() if cnt > 0 else 0 + avg_acc = valid_acc.mean() if cnt > 0 else 0.0 return acc, avg_acc, cnt @@ -318,3 +319,57 @@ def multilabel_classification_accuracy(pred: np.ndarray, # only if it's correct for all labels. acc = (((pred - thr) * (gt - thr)) > 0).all(axis=1).mean() return acc + + +def keypoint_mpjpe(pred: np.ndarray, + gt: np.ndarray, + mask: np.ndarray, + alignment: str = 'none'): + """Calculate the mean per-joint position error (MPJPE) and the error after + rigid alignment with the ground truth (P-MPJPE). + + Note: + - batch_size: N + - num_keypoints: K + - keypoint_dims: C + + Args: + pred (np.ndarray): Predicted keypoint location with shape [N, K, C]. + gt (np.ndarray): Groundtruth keypoint location with shape [N, K, C]. + mask (np.ndarray): Visibility of the target with shape [N, K]. + False for invisible joints, and True for visible. + Invisible joints will be ignored for accuracy calculation. + alignment (str, optional): method to align the prediction with the + groundtruth. Supported options are: + + - ``'none'``: no alignment will be applied + - ``'scale'``: align in the least-square sense in scale + - ``'procrustes'``: align in the least-square sense in + scale, rotation and translation. + + Returns: + tuple: A tuple containing joint position errors + + - (float | np.ndarray): mean per-joint position error (mpjpe). + - (float | np.ndarray): mpjpe after rigid alignment with the + ground truth (p-mpjpe). + """ + assert mask.any() + + if alignment == 'none': + pass + elif alignment == 'procrustes': + pred = np.stack([ + compute_similarity_transform(pred_i, gt_i) + for pred_i, gt_i in zip(pred, gt) + ]) + elif alignment == 'scale': + pred_dot_pred = np.einsum('nkc,nkc->n', pred, pred) + pred_dot_gt = np.einsum('nkc,nkc->n', pred, gt) + scale_factor = pred_dot_gt / pred_dot_pred + pred = pred * scale_factor[:, None, None] + else: + raise ValueError(f'Invalid value for alignment: {alignment}') + error = np.linalg.norm(pred - gt, ord=2, axis=-1)[mask].mean() + + return error diff --git a/mmpose/evaluation/functional/mesh_eval.py b/mmpose/evaluation/functional/mesh_eval.py new file mode 100644 index 0000000000..683b4539b2 --- /dev/null +++ b/mmpose/evaluation/functional/mesh_eval.py @@ -0,0 +1,66 @@ +# ------------------------------------------------------------------------------ +# Adapted from https://github.com/akanazawa/hmr +# Original licence: Copyright (c) 2018 akanazawa, under the MIT License. +# ------------------------------------------------------------------------------ + +import numpy as np + + +def compute_similarity_transform(source_points, target_points): + """Computes a similarity transform (sR, t) that takes a set of 3D points + source_points (N x 3) closest to a set of 3D points target_points, where R + is an 3x3 rotation matrix, t 3x1 translation, s scale. And return the + transformed 3D points source_points_hat (N x 3). i.e. solves the orthogonal + Procrutes problem. + + Note: + Points number: N + + Args: + source_points (np.ndarray): Source point set with shape [N, 3]. + target_points (np.ndarray): Target point set with shape [N, 3]. + + Returns: + np.ndarray: Transformed source point set with shape [N, 3]. + """ + + assert target_points.shape[0] == source_points.shape[0] + assert target_points.shape[1] == 3 and source_points.shape[1] == 3 + + source_points = source_points.T + target_points = target_points.T + + # 1. Remove mean. + mu1 = source_points.mean(axis=1, keepdims=True) + mu2 = target_points.mean(axis=1, keepdims=True) + X1 = source_points - mu1 + X2 = target_points - mu2 + + # 2. Compute variance of X1 used for scale. + var1 = np.sum(X1**2) + + # 3. The outer product of X1 and X2. + K = X1.dot(X2.T) + + # 4. Solution that Maximizes trace(R'K) is R=U*V', where U, V are + # singular vectors of K. + U, _, Vh = np.linalg.svd(K) + V = Vh.T + # Construct Z that fixes the orientation of R to get det(R)=1. + Z = np.eye(U.shape[0]) + Z[-1, -1] *= np.sign(np.linalg.det(U.dot(V.T))) + # Construct R. + R = V.dot(Z.dot(U.T)) + + # 5. Recover scale. + scale = np.trace(R.dot(K)) / var1 + + # 6. Recover translation. + t = mu2 - scale * (R.dot(mu1)) + + # 7. Transform the source points: + source_points_hat = scale * R.dot(source_points) + t + + source_points_hat = source_points_hat.T + + return source_points_hat diff --git a/mmpose/evaluation/functional/nms.py b/mmpose/evaluation/functional/nms.py index 50bbe1550b..eed4e5cf73 100644 --- a/mmpose/evaluation/functional/nms.py +++ b/mmpose/evaluation/functional/nms.py @@ -102,7 +102,7 @@ def oks_iou(g: np.ndarray, dy = yd - yg e = (dx**2 + dy**2) / vars / ((a_g + a_d[n_d]) / 2 + np.spacing(1)) / 2 if vis_thr is not None: - ind = list(vg > vis_thr) and list(vd > vis_thr) + ind = list((vg > vis_thr) & (vd > vis_thr)) e = e[ind] ious[n_d] = np.sum(np.exp(-e)) / len(e) if len(e) != 0 else 0.0 return ious diff --git a/mmpose/evaluation/metrics/__init__.py b/mmpose/evaluation/metrics/__init__.py index f02c353ef7..ac7e21b5cc 100644 --- a/mmpose/evaluation/metrics/__init__.py +++ b/mmpose/evaluation/metrics/__init__.py @@ -3,11 +3,12 @@ from .coco_wholebody_metric import CocoWholeBodyMetric from .keypoint_2d_metrics import (AUC, EPE, NME, JhmdbPCKAccuracy, MpiiPCKAccuracy, PCKAccuracy) +from .keypoint_3d_metrics import MPJPE from .keypoint_partition_metric import KeypointPartitionMetric from .posetrack18_metric import PoseTrack18Metric __all__ = [ 'CocoMetric', 'PCKAccuracy', 'MpiiPCKAccuracy', 'JhmdbPCKAccuracy', 'AUC', 'EPE', 'NME', 'PoseTrack18Metric', 'CocoWholeBodyMetric', - 'KeypointPartitionMetric' + 'KeypointPartitionMetric', 'MPJPE' ] diff --git a/mmpose/evaluation/metrics/keypoint_2d_metrics.py b/mmpose/evaluation/metrics/keypoint_2d_metrics.py index c6a63f1e51..5c8d23ac08 100644 --- a/mmpose/evaluation/metrics/keypoint_2d_metrics.py +++ b/mmpose/evaluation/metrics/keypoint_2d_metrics.py @@ -760,6 +760,8 @@ class NME(BaseMetric): 'cofw': [8, 9], # wflw: corresponding to `right-most` and `left-most` eye keypoints 'wflw': [60, 72], + # lapa: corresponding to `right-most` and `left-most` eye keypoints + 'lapa': [66, 79], } def __init__(self, diff --git a/mmpose/evaluation/metrics/keypoint_3d_metrics.py b/mmpose/evaluation/metrics/keypoint_3d_metrics.py new file mode 100644 index 0000000000..e945650c30 --- /dev/null +++ b/mmpose/evaluation/metrics/keypoint_3d_metrics.py @@ -0,0 +1,131 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from collections import defaultdict +from os import path as osp +from typing import Dict, Optional, Sequence + +import numpy as np +from mmengine.evaluator import BaseMetric +from mmengine.logging import MMLogger + +from mmpose.registry import METRICS +from ..functional import keypoint_mpjpe + + +@METRICS.register_module() +class MPJPE(BaseMetric): + """MPJPE evaluation metric. + + Calculate the mean per-joint position error (MPJPE) of keypoints. + + Note: + - length of dataset: N + - num_keypoints: K + - number of keypoint dimensions: D (typically D = 2) + + Args: + mode (str): Method to align the prediction with the + ground truth. Supported options are: + + - ``'mpjpe'``: no alignment will be applied + - ``'p-mpjpe'``: align in the least-square sense in scale + - ``'n-mpjpe'``: align in the least-square sense in + scale, rotation, and translation. + + collect_device (str): Device name used for collecting results from + different ranks during distributed training. Must be ``'cpu'`` or + ``'gpu'``. Default: ``'cpu'``. + prefix (str, optional): The prefix that will be added in the metric + names to disambiguate homonymous metrics of different evaluators. + If prefix is not provided in the argument, ``self.default_prefix`` + will be used instead. Default: ``None``. + """ + + ALIGNMENT = {'mpjpe': 'none', 'p-mpjpe': 'procrustes', 'n-mpjpe': 'scale'} + + def __init__(self, + mode: str = 'mpjpe', + collect_device: str = 'cpu', + prefix: Optional[str] = None) -> None: + super().__init__(collect_device=collect_device, prefix=prefix) + allowed_modes = self.ALIGNMENT.keys() + if mode not in allowed_modes: + raise KeyError("`mode` should be 'mpjpe', 'p-mpjpe', or " + f"'n-mpjpe', but got '{mode}'.") + + self.mode = mode + + def process(self, data_batch: Sequence[dict], + data_samples: Sequence[dict]) -> None: + """Process one batch of data samples and predictions. The processed + results should be stored in ``self.results``, which will be used to + compute the metrics when all batches have been processed. + + Args: + data_batch (Sequence[dict]): A batch of data + from the dataloader. + data_samples (Sequence[dict]): A batch of outputs from + the model. + """ + for data_sample in data_samples: + # predicted keypoints coordinates, [1, K, D] + pred_coords = data_sample['pred_instances']['keypoints'] + # ground truth data_info + gt = data_sample['gt_instances'] + # ground truth keypoints coordinates, [1, K, D] + gt_coords = gt['lifting_target'] + # ground truth keypoints_visible, [1, K, 1] + mask = gt['lifting_target_visible'].astype(bool).reshape(1, -1) + # instance action + img_path = data_sample['target_img_path'] + _, rest = osp.basename(img_path).split('_', 1) + action, _ = rest.split('.', 1) + + result = { + 'pred_coords': pred_coords, + 'gt_coords': gt_coords, + 'mask': mask, + 'action': action + } + + self.results.append(result) + + def compute_metrics(self, results: list) -> Dict[str, float]: + """Compute the metrics from processed results. + + Args: + results (list): The processed results of each batch. + + Returns: + Dict[str, float]: The computed metrics. The keys are the names of + the metrics, and the values are the corresponding results. + """ + logger: MMLogger = MMLogger.get_current_instance() + + # pred_coords: [N, K, D] + pred_coords = np.concatenate( + [result['pred_coords'] for result in results]) + if pred_coords.ndim == 4 and pred_coords.shape[1] == 1: + pred_coords = np.squeeze(pred_coords, axis=1) + # gt_coords: [N, K, D] + gt_coords = np.stack([result['gt_coords'] for result in results]) + # mask: [N, K] + mask = np.concatenate([result['mask'] for result in results]) + # action_category_indices: Dict[List[int]] + action_category_indices = defaultdict(list) + for idx, result in enumerate(results): + action_category = result['action'].split('_')[0] + action_category_indices[action_category].append(idx) + + error_name = self.mode.upper() + + logger.info(f'Evaluating {self.mode.upper()}...') + metrics = dict() + + metrics[error_name] = keypoint_mpjpe(pred_coords, gt_coords, mask, + self.ALIGNMENT[self.mode]) + + for action_category, indices in action_category_indices.items(): + metrics[f'{error_name}_{action_category}'] = keypoint_mpjpe( + pred_coords[indices], gt_coords[indices], mask[indices]) + + return metrics diff --git a/mmpose/models/backbones/hrformer.py b/mmpose/models/backbones/hrformer.py index 4712cfdfb5..0b86617f14 100644 --- a/mmpose/models/backbones/hrformer.py +++ b/mmpose/models/backbones/hrformer.py @@ -299,17 +299,12 @@ def __init__(self, self.act3 = build_activation_layer(act_cfg) self.norm3 = build_norm_layer(norm_cfg, out_features)[1] - # put the modules togather - self.layers = [ - self.fc1, self.norm1, self.act1, self.dw3x3, self.norm2, self.act2, - self.fc2, self.norm3, self.act3 - ] - def forward(self, x, H, W): """Forward function.""" x = nlc_to_nchw(x, (H, W)) - for layer in self.layers: - x = layer(x) + x = self.act1(self.norm1(self.fc1(x))) + x = self.act2(self.norm2(self.dw3x3(x))) + x = self.act3(self.norm3(self.fc2(x))) x = nchw_to_nlc(x) return x diff --git a/mmpose/models/heads/__init__.py b/mmpose/models/heads/__init__.py index 8b4d988a5f..e01f2269e3 100644 --- a/mmpose/models/heads/__init__.py +++ b/mmpose/models/heads/__init__.py @@ -3,12 +3,15 @@ from .coord_cls_heads import RTMCCHead, SimCCHead from .heatmap_heads import (AssociativeEmbeddingHead, CIDHead, CPMHead, HeatmapHead, MSPNHead, ViPNASHead) -from .hybrid_heads import DEKRHead +from .hybrid_heads import DEKRHead, VisPredictHead from .regression_heads import (DSNTHead, IntegralRegressionHead, - RegressionHead, RLEHead) + RegressionHead, RLEHead, TemporalRegressionHead, + TrajectoryRegressionHead) __all__ = [ 'BaseHead', 'HeatmapHead', 'CPMHead', 'MSPNHead', 'ViPNASHead', 'RegressionHead', 'IntegralRegressionHead', 'SimCCHead', 'RLEHead', - 'DSNTHead', 'AssociativeEmbeddingHead', 'DEKRHead', 'CIDHead', 'RTMCCHead' + 'DSNTHead', 'AssociativeEmbeddingHead', 'DEKRHead', 'VisPredictHead', + 'CIDHead', 'RTMCCHead', 'TemporalRegressionHead', + 'TrajectoryRegressionHead' ] diff --git a/mmpose/models/heads/coord_cls_heads/rtmcc_head.py b/mmpose/models/heads/coord_cls_heads/rtmcc_head.py index 94d613192c..5df0733c48 100644 --- a/mmpose/models/heads/coord_cls_heads/rtmcc_head.py +++ b/mmpose/models/heads/coord_cls_heads/rtmcc_head.py @@ -134,8 +134,8 @@ def __init__( def forward(self, feats: Tuple[Tensor]) -> Tuple[Tensor, Tensor]: """Forward the network. - The input is multi scale feature maps and the - output is the heatmap. + The input is the featuremap extracted by backbone and the + output is the simcc representation. Args: feats (Tuple[Tensor]): Multi scale feature maps. diff --git a/mmpose/models/heads/coord_cls_heads/simcc_head.py b/mmpose/models/heads/coord_cls_heads/simcc_head.py index b9287b7204..d9e7001cbc 100644 --- a/mmpose/models/heads/coord_cls_heads/simcc_head.py +++ b/mmpose/models/heads/coord_cls_heads/simcc_head.py @@ -198,8 +198,10 @@ def _make_deconv_head( return deconv_head def forward(self, feats: Tuple[Tensor]) -> Tuple[Tensor, Tensor]: - """Forward the network. The input is multi scale feature maps and the - output is the heatmap. + """Forward the network. + + The input is the featuremap extracted by backbone and the + output is the simcc representation. Args: feats (Tuple[Tensor]): Multi scale feature maps. diff --git a/mmpose/models/heads/hybrid_heads/__init__.py b/mmpose/models/heads/hybrid_heads/__init__.py index 55d5a211c1..6431b6a2c2 100644 --- a/mmpose/models/heads/hybrid_heads/__init__.py +++ b/mmpose/models/heads/hybrid_heads/__init__.py @@ -1,6 +1,5 @@ # Copyright (c) OpenMMLab. All rights reserved. from .dekr_head import DEKRHead +from .vis_head import VisPredictHead -__all__ = [ - 'DEKRHead', -] +__all__ = ['DEKRHead', 'VisPredictHead'] diff --git a/mmpose/models/heads/hybrid_heads/vis_head.py b/mmpose/models/heads/hybrid_heads/vis_head.py new file mode 100644 index 0000000000..e9ea271ac5 --- /dev/null +++ b/mmpose/models/heads/hybrid_heads/vis_head.py @@ -0,0 +1,229 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Tuple, Union + +import torch +from torch import Tensor, nn + +from mmpose.models.utils.tta import flip_visibility +from mmpose.registry import MODELS +from mmpose.utils.tensor_utils import to_numpy +from mmpose.utils.typing import (ConfigType, InstanceList, OptConfigType, + OptSampleList, Predictions) +from ..base_head import BaseHead + + +@MODELS.register_module() +class VisPredictHead(BaseHead): + """VisPredictHead must be used together with other heads. It can predict + keypoints coordinates of and their visibility simultaneously. In the + current version, it only supports top-down approaches. + + Args: + pose_cfg (Config): Config to construct keypoints prediction head + loss (Config): Config for visibility loss. Defaults to use + :class:`BCELoss` + use_sigmoid (bool): Whether to use sigmoid activation function + init_cfg (Config, optional): Config to control the initialization. See + :attr:`default_init_cfg` for default settings + """ + + def __init__(self, + pose_cfg: ConfigType, + loss: ConfigType = dict( + type='BCELoss', use_target_weight=False, + with_logits=True), + use_sigmoid: bool = False, + init_cfg: OptConfigType = None): + + if init_cfg is None: + init_cfg = self.default_init_cfg + + super().__init__(init_cfg) + + self.in_channels = pose_cfg['in_channels'] + if pose_cfg.get('num_joints', None) is not None: + self.out_channels = pose_cfg['num_joints'] + elif pose_cfg.get('out_channels', None) is not None: + self.out_channels = pose_cfg['out_channels'] + else: + raise ValueError('VisPredictHead requires \'num_joints\' or' + ' \'out_channels\' in the pose_cfg.') + + self.loss_module = MODELS.build(loss) + + self.pose_head = MODELS.build(pose_cfg) + self.pose_cfg = pose_cfg + + self.use_sigmoid = use_sigmoid + + modules = [ + nn.AdaptiveAvgPool2d(1), + nn.Flatten(), + nn.Linear(self.in_channels, self.out_channels) + ] + if use_sigmoid: + modules.append(nn.Sigmoid()) + + self.vis_head = nn.Sequential(*modules) + + def vis_forward(self, feats: Tuple[Tensor]): + """Forward the vis_head. The input is multi scale feature maps and the + output is coordinates visibility. + + Args: + feats (Tuple[Tensor]): Multi scale feature maps. + + Returns: + Tensor: output coordinates visibility. + """ + x = feats[-1] + while len(x.shape) < 4: + x.unsqueeze_(-1) + x = self.vis_head(x) + return x.reshape(-1, self.out_channels) + + def forward(self, feats: Tuple[Tensor]): + """Forward the network. The input is multi scale feature maps and the + output is coordinates and coordinates visibility. + + Args: + feats (Tuple[Tensor]): Multi scale feature maps. + + Returns: + Tuple[Tensor]: output coordinates and coordinates visibility. + """ + x_pose = self.pose_head.forward(feats) + x_vis = self.vis_forward(feats) + + return x_pose, x_vis + + def integrate(self, batch_vis: Tensor, + pose_preds: Union[Tuple, Predictions]) -> InstanceList: + """Add keypoints visibility prediction to pose prediction. + + Overwrite the original keypoint_scores. + """ + if isinstance(pose_preds, tuple): + pose_pred_instances, pose_pred_fields = pose_preds + else: + pose_pred_instances = pose_preds + pose_pred_fields = None + + batch_vis_np = to_numpy(batch_vis, unzip=True) + + assert len(pose_pred_instances) == len(batch_vis_np) + for index, _ in enumerate(pose_pred_instances): + pose_pred_instances[index].keypoint_scores = batch_vis_np[index] + + return pose_pred_instances, pose_pred_fields + + def predict(self, + feats: Tuple[Tensor], + batch_data_samples: OptSampleList, + test_cfg: ConfigType = {}) -> Predictions: + """Predict results from features. + + Args: + feats (Tuple[Tensor] | List[Tuple[Tensor]]): The multi-stage + features (or multiple multi-stage features in TTA) + batch_data_samples (List[:obj:`PoseDataSample`]): The batch + data samples + test_cfg (dict): The runtime config for testing process. Defaults + to {} + + Returns: + Union[InstanceList | Tuple[InstanceList | PixelDataList]]: If + posehead's ``test_cfg['output_heatmap']==True``, return both + pose and heatmap prediction; otherwise only return the pose + prediction. + + The pose prediction is a list of ``InstanceData``, each contains + the following fields: + + - keypoints (np.ndarray): predicted keypoint coordinates in + shape (num_instances, K, D) where K is the keypoint number + and D is the keypoint dimension + - keypoint_scores (np.ndarray): predicted keypoint scores in + shape (num_instances, K) + - keypoint_visibility (np.ndarray): predicted keypoints + visibility in shape (num_instances, K) + + The heatmap prediction is a list of ``PixelData``, each contains + the following fields: + + - heatmaps (Tensor): The predicted heatmaps in shape (K, h, w) + """ + if test_cfg.get('flip_test', False): + # TTA: flip test -> feats = [orig, flipped] + assert isinstance(feats, list) and len(feats) == 2 + flip_indices = batch_data_samples[0].metainfo['flip_indices'] + _feats, _feats_flip = feats + + _batch_vis = self.vis_forward(_feats) + _batch_vis_flip = flip_visibility( + self.vis_forward(_feats_flip), flip_indices=flip_indices) + batch_vis = (_batch_vis + _batch_vis_flip) * 0.5 + else: + batch_vis = self.vis_forward(feats) # (B, K, D) + + batch_vis.unsqueeze_(dim=1) # (B, N, K, D) + + if not self.use_sigmoid: + batch_vis = torch.sigmoid(batch_vis) + + batch_pose = self.pose_head.predict(feats, batch_data_samples, + test_cfg) + + return self.integrate(batch_vis, batch_pose) + + def vis_accuracy(self, vis_pred_outputs, vis_labels): + """Calculate visibility prediction accuracy.""" + probabilities = torch.sigmoid(torch.flatten(vis_pred_outputs)) + threshold = 0.5 + predictions = (probabilities >= threshold).int() + labels = torch.flatten(vis_labels) + correct = torch.sum(predictions == labels).item() + accuracy = correct / len(labels) + return torch.tensor(accuracy) + + def loss(self, + feats: Tuple[Tensor], + batch_data_samples: OptSampleList, + train_cfg: OptConfigType = {}) -> dict: + """Calculate losses from a batch of inputs and data samples. + + Args: + feats (Tuple[Tensor]): The multi-stage features + batch_data_samples (List[:obj:`PoseDataSample`]): The batch + data samples + train_cfg (dict): The runtime config for training process. + Defaults to {} + + Returns: + dict: A dictionary of losses. + """ + vis_pred_outputs = self.vis_forward(feats) + vis_labels = torch.cat([ + d.gt_instance_labels.keypoint_weights for d in batch_data_samples + ]) + + # calculate vis losses + losses = dict() + loss_vis = self.loss_module(vis_pred_outputs, vis_labels) + + losses.update(loss_vis=loss_vis) + + # calculate vis accuracy + acc_vis = self.vis_accuracy(vis_pred_outputs, vis_labels) + losses.update(acc_vis=acc_vis) + + # calculate keypoints losses + loss_kpt = self.pose_head.loss(feats, batch_data_samples) + losses.update(loss_kpt) + + return losses + + @property + def default_init_cfg(self): + init_cfg = [dict(type='Normal', layer=['Linear'], std=0.01, bias=0)] + return init_cfg diff --git a/mmpose/models/heads/regression_heads/__init__.py b/mmpose/models/heads/regression_heads/__init__.py index f2a5027b1b..ce9cd5e1b0 100644 --- a/mmpose/models/heads/regression_heads/__init__.py +++ b/mmpose/models/heads/regression_heads/__init__.py @@ -3,10 +3,14 @@ from .integral_regression_head import IntegralRegressionHead from .regression_head import RegressionHead from .rle_head import RLEHead +from .temporal_regression_head import TemporalRegressionHead +from .trajectory_regression_head import TrajectoryRegressionHead __all__ = [ 'RegressionHead', 'IntegralRegressionHead', 'DSNTHead', 'RLEHead', + 'TemporalRegressionHead', + 'TrajectoryRegressionHead', ] diff --git a/mmpose/models/heads/regression_heads/temporal_regression_head.py b/mmpose/models/heads/regression_heads/temporal_regression_head.py new file mode 100644 index 0000000000..ac76316842 --- /dev/null +++ b/mmpose/models/heads/regression_heads/temporal_regression_head.py @@ -0,0 +1,151 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Optional, Sequence, Tuple, Union + +import numpy as np +import torch +from torch import Tensor, nn + +from mmpose.evaluation.functional import keypoint_pck_accuracy +from mmpose.registry import KEYPOINT_CODECS, MODELS +from mmpose.utils.tensor_utils import to_numpy +from mmpose.utils.typing import (ConfigType, OptConfigType, OptSampleList, + Predictions) +from ..base_head import BaseHead + +OptIntSeq = Optional[Sequence[int]] + + +@MODELS.register_module() +class TemporalRegressionHead(BaseHead): + """Temporal Regression head of `VideoPose3D`_ by Dario et al (CVPR'2019). + + Args: + in_channels (int | sequence[int]): Number of input channels + num_joints (int): Number of joints + loss (Config): Config for keypoint loss. Defaults to use + :class:`SmoothL1Loss` + decoder (Config, optional): The decoder config that controls decoding + keypoint coordinates from the network output. Defaults to ``None`` + init_cfg (Config, optional): Config to control the initialization. See + :attr:`default_init_cfg` for default settings + + .. _`VideoPose3D`: https://arxiv.org/abs/1811.11742 + """ + + _version = 2 + + def __init__(self, + in_channels: Union[int, Sequence[int]], + num_joints: int, + loss: ConfigType = dict( + type='MSELoss', use_target_weight=True), + decoder: OptConfigType = None, + init_cfg: OptConfigType = None): + + if init_cfg is None: + init_cfg = self.default_init_cfg + + super().__init__(init_cfg) + + self.in_channels = in_channels + self.num_joints = num_joints + self.loss_module = MODELS.build(loss) + if decoder is not None: + self.decoder = KEYPOINT_CODECS.build(decoder) + else: + self.decoder = None + + # Define fully-connected layers + self.conv = nn.Conv1d(in_channels, self.num_joints * 3, 1) + + def forward(self, feats: Tuple[Tensor]) -> Tensor: + """Forward the network. The input is multi scale feature maps and the + output is the coordinates. + + Args: + feats (Tuple[Tensor]): Multi scale feature maps. + + Returns: + Tensor: Output coordinates (and sigmas[optional]). + """ + x = feats[-1] + + x = self.conv(x) + + return x.reshape(-1, self.num_joints, 3) + + def predict(self, + feats: Tuple[Tensor], + batch_data_samples: OptSampleList, + test_cfg: ConfigType = {}) -> Predictions: + """Predict results from outputs. + + Returns: + preds (sequence[InstanceData]): Prediction results. + Each contains the following fields: + + - keypoints: Predicted keypoints of shape (B, N, K, D). + - keypoint_scores: Scores of predicted keypoints of shape + (B, N, K). + """ + + batch_coords = self.forward(feats) # (B, K, D) + + # Restore global position with target_root + target_root = batch_data_samples[0].metainfo.get('target_root', None) + if target_root is not None: + target_root = torch.stack([ + torch.from_numpy(b.metainfo['target_root']) + for b in batch_data_samples + ]) + else: + target_root = torch.stack([ + torch.empty((0), dtype=torch.float32) + for _ in batch_data_samples[0].metainfo + ]) + + preds = self.decode((batch_coords, target_root)) + + return preds + + def loss(self, + inputs: Tuple[Tensor], + batch_data_samples: OptSampleList, + train_cfg: ConfigType = {}) -> dict: + """Calculate losses from a batch of inputs and data samples.""" + + pred_outputs = self.forward(inputs) + + lifting_target_label = torch.cat([ + d.gt_instance_labels.lifting_target_label + for d in batch_data_samples + ]) + lifting_target_weights = torch.cat([ + d.gt_instance_labels.lifting_target_weights + for d in batch_data_samples + ]) + + # calculate losses + losses = dict() + loss = self.loss_module(pred_outputs, lifting_target_label, + lifting_target_weights.unsqueeze(-1)) + + losses.update(loss_pose3d=loss) + + # calculate accuracy + _, avg_acc, _ = keypoint_pck_accuracy( + pred=to_numpy(pred_outputs), + gt=to_numpy(lifting_target_label), + mask=to_numpy(lifting_target_weights) > 0, + thr=0.05, + norm_factor=np.ones((pred_outputs.size(0), 3), dtype=np.float32)) + + mpjpe_pose = torch.tensor(avg_acc, device=lifting_target_label.device) + losses.update(mpjpe=mpjpe_pose) + + return losses + + @property + def default_init_cfg(self): + init_cfg = [dict(type='Normal', layer=['Linear'], std=0.01, bias=0)] + return init_cfg diff --git a/mmpose/models/heads/regression_heads/trajectory_regression_head.py b/mmpose/models/heads/regression_heads/trajectory_regression_head.py new file mode 100644 index 0000000000..adfd7353d3 --- /dev/null +++ b/mmpose/models/heads/regression_heads/trajectory_regression_head.py @@ -0,0 +1,150 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Optional, Sequence, Tuple, Union + +import numpy as np +import torch +from torch import Tensor, nn + +from mmpose.evaluation.functional import keypoint_pck_accuracy +from mmpose.registry import KEYPOINT_CODECS, MODELS +from mmpose.utils.tensor_utils import to_numpy +from mmpose.utils.typing import (ConfigType, OptConfigType, OptSampleList, + Predictions) +from ..base_head import BaseHead + +OptIntSeq = Optional[Sequence[int]] + + +@MODELS.register_module() +class TrajectoryRegressionHead(BaseHead): + """Trajectory Regression head of `VideoPose3D`_ by Dario et al (CVPR'2019). + + Args: + in_channels (int | sequence[int]): Number of input channels + num_joints (int): Number of joints + loss (Config): Config for trajectory loss. Defaults to use + :class:`MPJPELoss` + decoder (Config, optional): The decoder config that controls decoding + keypoint coordinates from the network output. Defaults to ``None`` + init_cfg (Config, optional): Config to control the initialization. See + :attr:`default_init_cfg` for default settings + + .. _`VideoPose3D`: https://arxiv.org/abs/1811.11742 + """ + + _version = 2 + + def __init__(self, + in_channels: Union[int, Sequence[int]], + num_joints: int, + loss: ConfigType = dict( + type='MPJPELoss', use_target_weight=True), + decoder: OptConfigType = None, + init_cfg: OptConfigType = None): + + if init_cfg is None: + init_cfg = self.default_init_cfg + + super().__init__(init_cfg) + + self.in_channels = in_channels + self.num_joints = num_joints + self.loss_module = MODELS.build(loss) + if decoder is not None: + self.decoder = KEYPOINT_CODECS.build(decoder) + else: + self.decoder = None + + # Define fully-connected layers + self.conv = nn.Conv1d(in_channels, self.num_joints * 3, 1) + + def forward(self, feats: Tuple[Tensor]) -> Tensor: + """Forward the network. The input is multi scale feature maps and the + output is the coordinates. + + Args: + feats (Tuple[Tensor]): Multi scale feature maps. + + Returns: + Tensor: output coordinates(and sigmas[optional]). + """ + x = feats[-1] + + x = self.conv(x) + + return x.reshape(-1, self.num_joints, 3) + + def predict(self, + feats: Tuple[Tensor], + batch_data_samples: OptSampleList, + test_cfg: ConfigType = {}) -> Predictions: + """Predict results from outputs. + + Returns: + preds (sequence[InstanceData]): Prediction results. + Each contains the following fields: + + - keypoints: Predicted keypoints of shape (B, N, K, D). + - keypoint_scores: Scores of predicted keypoints of shape + (B, N, K). + """ + + batch_coords = self.forward(feats) # (B, K, D) + + # Restore global position with target_root + target_root = batch_data_samples[0].metainfo.get('target_root', None) + if target_root is not None: + target_root = torch.stack([ + torch.from_numpy(b.metainfo['target_root']) + for b in batch_data_samples + ]) + else: + target_root = torch.stack([ + torch.empty((0), dtype=torch.float32) + for _ in batch_data_samples[0].metainfo + ]) + + preds = self.decode((batch_coords, target_root)) + + return preds + + def loss(self, + inputs: Union[Tensor, Tuple[Tensor]], + batch_data_samples: OptSampleList, + train_cfg: ConfigType = {}) -> dict: + """Calculate losses from a batch of inputs and data samples.""" + + pred_outputs = self.forward(inputs) + + lifting_target_label = torch.cat([ + d.gt_instance_labels.lifting_target_label + for d in batch_data_samples + ]) + trajectory_weights = torch.cat([ + d.gt_instance_labels.trajectory_weights for d in batch_data_samples + ]) + + # calculate losses + losses = dict() + loss = self.loss_module(pred_outputs, lifting_target_label, + trajectory_weights.unsqueeze(-1)) + + losses.update(loss_traj=loss) + + # calculate accuracy + _, avg_acc, _ = keypoint_pck_accuracy( + pred=to_numpy(pred_outputs), + gt=to_numpy(lifting_target_label), + mask=to_numpy(trajectory_weights) > 0, + thr=0.05, + norm_factor=np.ones((pred_outputs.size(0), 3), dtype=np.float32)) + + mpjpe_traj = torch.tensor(avg_acc, device=lifting_target_label.device) + losses.update(mpjpe_traj=mpjpe_traj) + + return losses + + @property + def default_init_cfg(self): + init_cfg = [dict(type='Normal', layer=['Linear'], std=0.01, bias=0)] + return init_cfg diff --git a/mmpose/models/losses/classification_loss.py b/mmpose/models/losses/classification_loss.py index 5755edd4c1..4605acabd3 100644 --- a/mmpose/models/losses/classification_loss.py +++ b/mmpose/models/losses/classification_loss.py @@ -14,11 +14,16 @@ class BCELoss(nn.Module): use_target_weight (bool): Option to use weighted loss. Different joint types may have different target weights. loss_weight (float): Weight of the loss. Default: 1.0. + with_logits (bool): Whether to use BCEWithLogitsLoss. Default: False. """ - def __init__(self, use_target_weight=False, loss_weight=1.): + def __init__(self, + use_target_weight=False, + loss_weight=1., + with_logits=False): super().__init__() - self.criterion = F.binary_cross_entropy + self.criterion = F.binary_cross_entropy if not with_logits\ + else F.binary_cross_entropy_with_logits self.use_target_weight = use_target_weight self.loss_weight = loss_weight @@ -139,11 +144,10 @@ def __init__(self, beta=1.0, label_softmax=False, use_target_weight=True): def criterion(self, dec_outs, labels): """Criterion function.""" - - scores = self.log_softmax(dec_outs * self.beta) + log_pt = self.log_softmax(dec_outs * self.beta) if self.label_softmax: labels = F.softmax(labels * self.beta, dim=1) - loss = torch.mean(self.kl_loss(scores, labels), dim=1) + loss = torch.mean(self.kl_loss(log_pt, labels), dim=1) return loss def forward(self, pred_simcc, gt_simcc, target_weight): @@ -156,26 +160,19 @@ def forward(self, pred_simcc, gt_simcc, target_weight): target_weight (torch.Tensor[N, K] or torch.Tensor[N]): Weights across different labels. """ - output_x, output_y = pred_simcc - target_x, target_y = gt_simcc - num_joints = output_x.size(1) + num_joints = pred_simcc[0].size(1) loss = 0 - for idx in range(num_joints): - coord_x_pred = output_x[:, idx].squeeze() - coord_y_pred = output_y[:, idx].squeeze() - coord_x_gt = target_x[:, idx].squeeze() - coord_y_gt = target_y[:, idx].squeeze() - - if self.use_target_weight: - weight = target_weight[:, idx].squeeze() - else: - weight = 1. - - loss += ( - self.criterion(coord_x_pred, coord_x_gt).mul(weight).sum()) - loss += ( - self.criterion(coord_y_pred, coord_y_gt).mul(weight).sum()) + if self.use_target_weight: + weight = target_weight.reshape(-1) + else: + weight = 1. + + for pred, target in zip(pred_simcc, gt_simcc): + pred = pred.reshape(-1, pred.size(-1)) + target = target.reshape(-1, target.size(-1)) + + loss += self.criterion(pred, target).mul(weight).sum() return loss / num_joints diff --git a/mmpose/models/losses/heatmap_loss.py b/mmpose/models/losses/heatmap_loss.py index a105149468..ffe5cd1e80 100644 --- a/mmpose/models/losses/heatmap_loss.py +++ b/mmpose/models/losses/heatmap_loss.py @@ -106,7 +106,7 @@ def _get_mask(self, target: Tensor, target_weights: Optional[Tensor], # Mask by ``skip_empty_channel`` if self.skip_empty_channel: - _mask = (target != 0).flatten(2).any() + _mask = (target != 0).flatten(2).any(dim=2) ndim_pad = target.ndim - _mask.ndim _mask = _mask.view(_mask.shape + (1, ) * ndim_pad) diff --git a/mmpose/models/pose_estimators/__init__.py b/mmpose/models/pose_estimators/__init__.py index 6ead1a979e..c5287e0c2c 100644 --- a/mmpose/models/pose_estimators/__init__.py +++ b/mmpose/models/pose_estimators/__init__.py @@ -1,5 +1,6 @@ # Copyright (c) OpenMMLab. All rights reserved. from .bottomup import BottomupPoseEstimator +from .pose_lifter import PoseLifter from .topdown import TopdownPoseEstimator -__all__ = ['TopdownPoseEstimator', 'BottomupPoseEstimator'] +__all__ = ['TopdownPoseEstimator', 'BottomupPoseEstimator', 'PoseLifter'] diff --git a/mmpose/models/pose_estimators/base.py b/mmpose/models/pose_estimators/base.py index 73d60de93a..0ae921d0ec 100644 --- a/mmpose/models/pose_estimators/base.py +++ b/mmpose/models/pose_estimators/base.py @@ -130,6 +130,8 @@ def forward(self, - If ``mode='loss'``, return a dict of tensor(s) which is the loss function value """ + if isinstance(inputs, list): + inputs = torch.stack(inputs) if mode == 'loss': return self.loss(inputs, data_samples) elif mode == 'predict': diff --git a/mmpose/models/pose_estimators/pose_lifter.py b/mmpose/models/pose_estimators/pose_lifter.py new file mode 100644 index 0000000000..5bad3dde3c --- /dev/null +++ b/mmpose/models/pose_estimators/pose_lifter.py @@ -0,0 +1,340 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from itertools import zip_longest +from typing import Tuple, Union + +from torch import Tensor + +from mmpose.models.utils import check_and_update_config +from mmpose.registry import MODELS +from mmpose.utils.typing import (ConfigType, InstanceList, OptConfigType, + Optional, OptMultiConfig, OptSampleList, + PixelDataList, SampleList) +from .base import BasePoseEstimator + + +@MODELS.register_module() +class PoseLifter(BasePoseEstimator): + """Base class for pose lifter. + + Args: + backbone (dict): The backbone config + neck (dict, optional): The neck config. Defaults to ``None`` + head (dict, optional): The head config. Defaults to ``None`` + traj_backbone (dict, optional): The backbone config for trajectory + model. Defaults to ``None`` + traj_neck (dict, optional): The neck config for trajectory model. + Defaults to ``None`` + traj_head (dict, optional): The head config for trajectory model. + Defaults to ``None`` + semi_loss (dict, optional): The semi-supervised loss config. + Defaults to ``None`` + train_cfg (dict, optional): The runtime config for training process. + Defaults to ``None`` + test_cfg (dict, optional): The runtime config for testing process. + Defaults to ``None`` + data_preprocessor (dict, optional): The data preprocessing config to + build the instance of :class:`BaseDataPreprocessor`. Defaults to + ``None`` + init_cfg (dict, optional): The config to control the initialization. + Defaults to ``None`` + metainfo (dict): Meta information for dataset, such as keypoints + definition and properties. If set, the metainfo of the input data + batch will be overridden. For more details, please refer to + https://mmpose.readthedocs.io/en/latest/user_guides/ + prepare_datasets.html#create-a-custom-dataset-info- + config-file-for-the-dataset. Defaults to ``None`` + """ + + def __init__(self, + backbone: ConfigType, + neck: OptConfigType = None, + head: OptConfigType = None, + traj_backbone: OptConfigType = None, + traj_neck: OptConfigType = None, + traj_head: OptConfigType = None, + semi_loss: OptConfigType = None, + train_cfg: OptConfigType = None, + test_cfg: OptConfigType = None, + data_preprocessor: OptConfigType = None, + init_cfg: OptMultiConfig = None, + metainfo: Optional[dict] = None): + super().__init__( + backbone=backbone, + neck=neck, + head=head, + train_cfg=train_cfg, + test_cfg=test_cfg, + data_preprocessor=data_preprocessor, + init_cfg=init_cfg, + metainfo=metainfo) + + # trajectory model + self.share_backbone = False + if traj_head is not None: + if traj_backbone is not None: + self.traj_backbone = MODELS.build(traj_backbone) + else: + self.share_backbone = True + + # the PR #2108 and #2126 modified the interface of neck and head. + # The following function automatically detects outdated + # configurations and updates them accordingly, while also providing + # clear and concise information on the changes made. + traj_neck, traj_head = check_and_update_config( + traj_neck, traj_head) + + if traj_neck is not None: + self.traj_neck = MODELS.build(traj_neck) + + self.traj_head = MODELS.build(traj_head) + + # semi-supervised loss + self.semi_supervised = semi_loss is not None + if self.semi_supervised: + assert any([head, traj_head]) + self.semi_loss = MODELS.build(semi_loss) + + @property + def with_traj_backbone(self): + """bool: Whether the pose lifter has trajectory backbone.""" + return hasattr(self, 'traj_backbone') and \ + self.traj_backbone is not None + + @property + def with_traj_neck(self): + """bool: Whether the pose lifter has trajectory neck.""" + return hasattr(self, 'traj_neck') and self.traj_neck is not None + + @property + def with_traj(self): + """bool: Whether the pose lifter has trajectory head.""" + return hasattr(self, 'traj_head') + + @property + def causal(self): + """bool: Whether the pose lifter is causal.""" + if hasattr(self.backbone, 'causal'): + return self.backbone.causal + else: + raise AttributeError('A PoseLifter\'s backbone should have ' + 'the bool attribute "causal" to indicate if' + 'it performs causal inference.') + + def extract_feat(self, inputs: Tensor) -> Tuple[Tensor]: + """Extract features. + + Args: + inputs (Tensor): Image tensor with shape (N, K, C, T). + + Returns: + tuple[Tensor]: Multi-level features that may have various + resolutions. + """ + # supervised learning + # pose model + feats = self.backbone(inputs) + if self.with_neck: + feats = self.neck(feats) + + # trajectory model + if self.with_traj: + if self.share_backbone: + traj_x = feats + else: + traj_x = self.traj_backbone(inputs) + + if self.with_traj_neck: + traj_x = self.traj_neck(traj_x) + return feats, traj_x + else: + return feats + + def _forward(self, + inputs: Tensor, + data_samples: OptSampleList = None + ) -> Union[Tensor, Tuple[Tensor]]: + """Network forward process. Usually includes backbone, neck and head + forward without any post-processing. + + Args: + inputs (Tensor): Inputs with shape (N, K, C, T). + + Returns: + Union[Tensor | Tuple[Tensor]]: forward output of the network. + """ + feats = self.extract_feat(inputs) + + if self.with_traj: + # forward with trajectory model + x, traj_x = feats + if self.with_head: + x = self.head.forward(x) + + traj_x = self.traj_head.forward(traj_x) + return x, traj_x + else: + # forward without trajectory model + x = feats + if self.with_head: + x = self.head.forward(x) + return x + + def loss(self, inputs: Tensor, data_samples: SampleList) -> dict: + """Calculate losses from a batch of inputs and data samples. + + Args: + inputs (Tensor): Inputs with shape (N, K, C, T). + data_samples (List[:obj:`PoseDataSample`]): The batch + data samples. + + Returns: + dict: A dictionary of losses. + """ + feats = self.extract_feat(inputs) + + losses = {} + + if self.with_traj: + x, traj_x = feats + # loss of trajectory model + losses.update( + self.traj_head.loss( + traj_x, data_samples, train_cfg=self.train_cfg)) + else: + x = feats + + if self.with_head: + # loss of pose model + losses.update( + self.head.loss(x, data_samples, train_cfg=self.train_cfg)) + + # TODO: support semi-supervised learning + if self.semi_supervised: + losses.update(semi_loss=self.semi_loss(inputs, data_samples)) + + return losses + + def predict(self, inputs: Tensor, data_samples: SampleList) -> SampleList: + """Predict results from a batch of inputs and data samples with post- + processing. + + Note: + - batch_size: B + - num_input_keypoints: K + - input_keypoint_dim: C + - input_sequence_len: T + + Args: + inputs (Tensor): Inputs with shape like (B, K, C, T). + data_samples (List[:obj:`PoseDataSample`]): The batch + data samples + + Returns: + list[:obj:`PoseDataSample`]: The pose estimation results of the + input images. The return value is `PoseDataSample` instances with + ``pred_instances`` and ``pred_fields``(optional) field , and + ``pred_instances`` usually contains the following keys: + + - keypoints (Tensor): predicted keypoint coordinates in shape + (num_instances, K, D) where K is the keypoint number and D + is the keypoint dimension + - keypoint_scores (Tensor): predicted keypoint scores in shape + (num_instances, K) + """ + assert self.with_head, ( + 'The model must have head to perform prediction.') + + feats = self.extract_feat(inputs) + + pose_preds, batch_pred_instances, batch_pred_fields = None, None, None + traj_preds, batch_traj_instances, batch_traj_fields = None, None, None + if self.with_traj: + x, traj_x = feats + traj_preds = self.traj_head.predict( + traj_x, data_samples, test_cfg=self.test_cfg) + else: + x = feats + + if self.with_head: + pose_preds = self.head.predict( + x, data_samples, test_cfg=self.test_cfg) + + if isinstance(pose_preds, tuple): + batch_pred_instances, batch_pred_fields = pose_preds + else: + batch_pred_instances = pose_preds + + if isinstance(traj_preds, tuple): + batch_traj_instances, batch_traj_fields = traj_preds + else: + batch_traj_instances = traj_preds + + results = self.add_pred_to_datasample(batch_pred_instances, + batch_pred_fields, + batch_traj_instances, + batch_traj_fields, data_samples) + + return results + + def add_pred_to_datasample( + self, + batch_pred_instances: InstanceList, + batch_pred_fields: Optional[PixelDataList], + batch_traj_instances: InstanceList, + batch_traj_fields: Optional[PixelDataList], + batch_data_samples: SampleList, + ) -> SampleList: + """Add predictions into data samples. + + Args: + batch_pred_instances (List[InstanceData]): The predicted instances + of the input data batch + batch_pred_fields (List[PixelData], optional): The predicted + fields (e.g. heatmaps) of the input batch + batch_traj_instances (List[InstanceData]): The predicted instances + of the input data batch + batch_traj_fields (List[PixelData], optional): The predicted + fields (e.g. heatmaps) of the input batch + batch_data_samples (List[PoseDataSample]): The input data batch + + Returns: + List[PoseDataSample]: A list of data samples where the predictions + are stored in the ``pred_instances`` field of each data sample. + """ + assert len(batch_pred_instances) == len(batch_data_samples) + if batch_pred_fields is None: + batch_pred_fields, batch_traj_fields = [], [] + if batch_traj_instances is None: + batch_traj_instances = [] + output_keypoint_indices = self.test_cfg.get('output_keypoint_indices', + None) + + for (pred_instances, pred_fields, traj_instances, traj_fields, + data_sample) in zip_longest(batch_pred_instances, + batch_pred_fields, + batch_traj_instances, + batch_traj_fields, + batch_data_samples): + + if output_keypoint_indices is not None: + # select output keypoints with given indices + num_keypoints = pred_instances.keypoints.shape[1] + for key, value in pred_instances.all_items(): + if key.startswith('keypoint'): + pred_instances.set_field( + value[:, output_keypoint_indices], key) + + data_sample.pred_instances = pred_instances + + if pred_fields is not None: + if output_keypoint_indices is not None: + # select output heatmap channels with keypoint indices + # when the number of heatmap channel matches num_keypoints + for key, value in pred_fields.all_items(): + if value.shape[0] != num_keypoints: + continue + pred_fields.set_field(value[output_keypoint_indices], + key) + data_sample.pred_fields = pred_fields + + return batch_data_samples diff --git a/mmpose/models/utils/rtmcc_block.py b/mmpose/models/utils/rtmcc_block.py index 0e317376b2..bd4929454c 100644 --- a/mmpose/models/utils/rtmcc_block.py +++ b/mmpose/models/utils/rtmcc_block.py @@ -105,7 +105,7 @@ def forward(self, x): torch.Tensor: The tensor after applying scale norm. """ - norm = torch.norm(x, dim=-1, keepdim=True) * self.scale + norm = torch.norm(x, dim=2, keepdim=True) * self.scale return x / norm.clamp(min=self.eps) * self.g @@ -243,29 +243,34 @@ def _forward(self, inputs): x = self.ln(x) + # [B, K, in_token_dims] -> [B, K, e + e + s] uv = self.uv(x) + uv = self.act_fn(uv) if self.attn_type == 'self-attn': - u, v, base = torch.split( - self.act_fn(uv), [self.e, self.e, self.s], dim=-1) - + # [B, K, e + e + s] -> [B, K, e], [B, K, e], [B, K, s] + u, v, base = torch.split(uv, [self.e, self.e, self.s], dim=2) + # [B, K, 1, s] * [1, 1, 2, s] + [2, s] -> [B, K, 2, s] base = base.unsqueeze(2) * self.gamma[None, None, :] + self.beta if self.pos_enc: base = rope(base, dim=1) - - q, k = torch.unbind(base, dim=-2) + # [B, K, 2, s] -> [B, K, s], [B, K, s] + q, k = torch.unbind(base, dim=2) else: - u, q = torch.split(self.act_fn(uv), [self.e, self.s], dim=-1) + # [B, K, e + s] -> [B, K, e], [B, K, s] + u, q = torch.split(uv, [self.e, self.s], dim=2) - k = self.k_fc(k) - v = self.v_fc(v) + k = self.k_fc(k) # -> [B, K, s] + v = self.v_fc(v) # -> [B, K, e] if self.pos_enc: q = rope(q, 1) k = rope(k, 1) + # [B, K, s].permute() -> [B, s, K] + # [B, K, s] x [B, s, K] -> [B, K, K] qk = torch.bmm(q, k.permute(0, 2, 1)) if self.use_rel_bias: @@ -274,13 +279,14 @@ def _forward(self, inputs): else: bias = self.rel_pos_bias(q.size(1), k.size(1)) qk += bias[:, :q.size(1), :k.size(1)] - + # [B, K, K] kernel = torch.square(F.relu(qk / self.sqrt_s)) if self.dropout_rate > 0.: kernel = self.dropout(kernel) - + # [B, K, K] x [B, K, e] -> [B, K, e] x = u * torch.bmm(kernel, v) + # [B, K, e] -> [B, K, out_token_dims] x = self.o(x) return x diff --git a/mmpose/models/utils/tta.py b/mmpose/models/utils/tta.py index 0add48a422..41d2f2fd47 100644 --- a/mmpose/models/utils/tta.py +++ b/mmpose/models/utils/tta.py @@ -114,6 +114,21 @@ def flip_coordinates(coords: Tensor, flip_indices: List[int], return coords +def flip_visibility(vis: Tensor, flip_indices: List[int]): + """Flip keypoints visibility for test-time augmentation. + + Args: + vis (Tensor): The keypoints visibility to flip. Should be a tensor + in shape [B, K] + flip_indices (List[int]): The indices of each keypoint's symmetric + keypoint + """ + assert vis.ndim == 2 + + vis = vis[:, flip_indices] + return vis + + def aggregate_heatmaps(heatmaps: List[Tensor], size: Optional[Tuple[int, int]], align_corners: bool = False, diff --git a/mmpose/structures/bbox/transforms.py b/mmpose/structures/bbox/transforms.py index 027ac0717b..c0c8e73395 100644 --- a/mmpose/structures/bbox/transforms.py +++ b/mmpose/structures/bbox/transforms.py @@ -111,7 +111,7 @@ def bbox_xywh2cs(bbox: np.ndarray, def bbox_cs2xyxy(center: np.ndarray, scale: np.ndarray, padding: float = 1.) -> np.ndarray: - """Transform the bbox format from (center, scale) to (x,y,w,h). + """Transform the bbox format from (center, scale) to (x1,y1,x2,y2). Args: center (ndarray): BBox center (x, y) in shape (2,) or (n, 2) @@ -120,7 +120,7 @@ def bbox_cs2xyxy(center: np.ndarray, Default: 1.0 Returns: - ndarray[float32]: BBox (x, y, w, h) in shape (4, ) or (n, 4) + ndarray[float32]: BBox (x1, y1, x2, y2) in shape (4, ) or (n, 4) """ dim = center.ndim diff --git a/mmpose/structures/keypoint/__init__.py b/mmpose/structures/keypoint/__init__.py index b8d5a24c7a..12ee96cf7c 100644 --- a/mmpose/structures/keypoint/__init__.py +++ b/mmpose/structures/keypoint/__init__.py @@ -1,5 +1,5 @@ # Copyright (c) OpenMMLab. All rights reserved. -from .transforms import flip_keypoints +from .transforms import flip_keypoints, flip_keypoints_custom_center -__all__ = ['flip_keypoints'] +__all__ = ['flip_keypoints', 'flip_keypoints_custom_center'] diff --git a/mmpose/structures/keypoint/transforms.py b/mmpose/structures/keypoint/transforms.py index 99adaa1306..b50da4f8fe 100644 --- a/mmpose/structures/keypoint/transforms.py +++ b/mmpose/structures/keypoint/transforms.py @@ -62,3 +62,60 @@ def flip_keypoints(keypoints: np.ndarray, keypoints = [w, h] - keypoints - 1 return keypoints, keypoints_visible + + +def flip_keypoints_custom_center(keypoints: np.ndarray, + keypoints_visible: np.ndarray, + flip_indices: List[int], + center_mode: str = 'static', + center_x: float = 0.5, + center_index: int = 0): + """Flip human joints horizontally. + + Note: + - num_keypoint: K + - dimension: D + + Args: + keypoints (np.ndarray([..., K, D])): Coordinates of keypoints. + keypoints_visible (np.ndarray([..., K])): Visibility item of keypoints. + flip_indices (list[int]): The indices to flip the keypoints. + center_mode (str): The mode to set the center location on the x-axis + to flip around. Options are: + + - static: use a static x value (see center_x also) + - root: use a root joint (see center_index also) + + Defaults: ``'static'``. + center_x (float): Set the x-axis location of the flip center. Only used + when ``center_mode`` is ``'static'``. Defaults: 0.5. + center_index (int): Set the index of the root joint, whose x location + will be used as the flip center. Only used when ``center_mode`` is + ``'root'``. Defaults: 0. + + Returns: + np.ndarray([..., K, C]): Flipped joints. + """ + + assert keypoints.ndim >= 2, f'Invalid pose shape {keypoints.shape}' + + allowed_center_mode = {'static', 'root'} + assert center_mode in allowed_center_mode, 'Get invalid center_mode ' \ + f'{center_mode}, allowed choices are {allowed_center_mode}' + + if center_mode == 'static': + x_c = center_x + elif center_mode == 'root': + assert keypoints.shape[-2] > center_index + x_c = keypoints[..., center_index, 0] + + keypoints_flipped = keypoints.copy() + keypoints_visible_flipped = keypoints_visible.copy() + # Swap left-right parts + for left, right in enumerate(flip_indices): + keypoints_flipped[..., left, :] = keypoints[..., right, :] + keypoints_visible_flipped[..., left] = keypoints_visible[..., right] + + # Flip horizontally + keypoints_flipped[..., 0] = x_c * 2 - keypoints_flipped[..., 0] + return keypoints_flipped, keypoints_visible_flipped diff --git a/mmpose/version.py b/mmpose/version.py index 73312cc28d..bf58664b39 100644 --- a/mmpose/version.py +++ b/mmpose/version.py @@ -1,6 +1,6 @@ # Copyright (c) Open-MMLab. All rights reserved. -__version__ = '1.0.0' +__version__ = '1.1.0' short_version = __version__ diff --git a/mmpose/visualization/__init__.py b/mmpose/visualization/__init__.py index 357d40a707..4a18e8bc5b 100644 --- a/mmpose/visualization/__init__.py +++ b/mmpose/visualization/__init__.py @@ -1,4 +1,6 @@ # Copyright (c) OpenMMLab. All rights reserved. +from .fast_visualizer import FastVisualizer from .local_visualizer import PoseLocalVisualizer +from .local_visualizer_3d import Pose3dLocalVisualizer -__all__ = ['PoseLocalVisualizer'] +__all__ = ['PoseLocalVisualizer', 'FastVisualizer', 'Pose3dLocalVisualizer'] diff --git a/mmpose/visualization/fast_visualizer.py b/mmpose/visualization/fast_visualizer.py new file mode 100644 index 0000000000..fa0cb38527 --- /dev/null +++ b/mmpose/visualization/fast_visualizer.py @@ -0,0 +1,78 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import cv2 + + +class FastVisualizer: + """MMPose Fast Visualizer. + + A simple yet fast visualizer for video/webcam inference. + + Args: + metainfo (dict): pose meta information + radius (int, optional)): Keypoint radius for visualization. + Defaults to 6. + line_width (int, optional): Link width for visualization. + Defaults to 3. + kpt_thr (float, optional): Threshold for keypoints' confidence score, + keypoints with score below this value will not be drawn. + Defaults to 0.3. + """ + + def __init__(self, metainfo, radius=6, line_width=3, kpt_thr=0.3): + self.radius = radius + self.line_width = line_width + self.kpt_thr = kpt_thr + + self.keypoint_id2name = metainfo['keypoint_id2name'] + self.keypoint_name2id = metainfo['keypoint_name2id'] + self.keypoint_colors = metainfo['keypoint_colors'] + self.skeleton_links = metainfo['skeleton_links'] + self.skeleton_link_colors = metainfo['skeleton_link_colors'] + + def draw_pose(self, img, instances): + """Draw pose estimations on the given image. + + This method draws keypoints and skeleton links on the input image + using the provided instances. + + Args: + img (numpy.ndarray): The input image on which to + draw the pose estimations. + instances (object): An object containing detected instances' + information, including keypoints and keypoint_scores. + + Returns: + None: The input image will be modified in place. + """ + + if instances is None: + print('no instance detected') + return + + keypoints = instances.keypoints + scores = instances.keypoint_scores + + for kpts, score in zip(keypoints, scores): + for sk_id, sk in enumerate(self.skeleton_links): + if score[sk[0]] < self.kpt_thr or score[sk[1]] < self.kpt_thr: + # skip the link that should not be drawn + continue + + pos1 = (int(kpts[sk[0], 0]), int(kpts[sk[0], 1])) + pos2 = (int(kpts[sk[1], 0]), int(kpts[sk[1], 1])) + + color = self.skeleton_link_colors[sk_id].tolist() + cv2.line(img, pos1, pos2, color, thickness=self.line_width) + + for kid, kpt in enumerate(kpts): + if score[kid] < self.kpt_thr: + # skip the point that should not be drawn + continue + + x_coord, y_coord = int(kpt[0]), int(kpt[1]) + + color = self.keypoint_colors[kid].tolist() + cv2.circle(img, (int(x_coord), int(y_coord)), self.radius, + color, -1) + cv2.circle(img, (int(x_coord), int(y_coord)), self.radius, + (255, 255, 255)) diff --git a/mmpose/visualization/local_visualizer.py b/mmpose/visualization/local_visualizer.py index 0d6fcc61f4..080e628e33 100644 --- a/mmpose/visualization/local_visualizer.py +++ b/mmpose/visualization/local_visualizer.py @@ -8,11 +8,11 @@ import torch from mmengine.dist import master_only from mmengine.structures import InstanceData, PixelData -from mmengine.visualization import Visualizer from mmpose.datasets.datasets.utils import parse_pose_metainfo from mmpose.registry import VISUALIZERS from mmpose.structures import PoseDataSample +from .opencv_backend_visualizer import OpencvBackendVisualizer from .simcc_vis import SimCCVisualizer @@ -42,7 +42,7 @@ def _get_adaptive_scales(areas: np.ndarray, @VISUALIZERS.register_module() -class PoseLocalVisualizer(Visualizer): +class PoseLocalVisualizer(OpencvBackendVisualizer): """MMPose Local Visualizer. Args: @@ -64,7 +64,7 @@ class PoseLocalVisualizer(Visualizer): radius (int, float): The radius of keypoints. Defaults to 4 show_keypoint_weight (bool): Whether to adjust the transparency of keypoints according to their score. Defaults to ``False`` - alpha (int, float): The transparency of bboxes. Defaults to ``0.8`` + alpha (int, float): The transparency of bboxes. Defaults to ``1.0`` Examples: >>> import numpy as np @@ -115,8 +115,15 @@ def __init__(self, line_width: Union[int, float] = 1, radius: Union[int, float] = 3, show_keypoint_weight: bool = False, - alpha: float = 0.8): - super().__init__(name, image, vis_backends, save_dir) + backend: str = 'opencv', + alpha: float = 1.0): + super().__init__( + name=name, + image=image, + vis_backends=vis_backends, + save_dir=save_dir, + backend=backend) + self.bbox_color = bbox_color self.kpt_color = kpt_color self.link_color = link_color @@ -265,8 +272,8 @@ def _draw_instances_kpts(self, neck = np.mean(keypoints_info[:, [5, 6]], axis=1) # neck score when visualizing pred neck[:, 2:4] = np.logical_and( - keypoints_info[:, 5, 2:4] < kpt_thr, - keypoints_info[:, 6, 2:4] < kpt_thr).astype(int) + keypoints_info[:, 5, 2:4] > kpt_thr, + keypoints_info[:, 6, 2:4] > kpt_thr).astype(int) new_keypoints_info = np.insert( keypoints_info, 17, neck, axis=1) @@ -297,35 +304,6 @@ def _draw_instances_kpts(self, f'({len(self.kpt_color)}) does not matches ' f'that of keypoints ({len(kpts)})') - # draw each point on image - for kid, kpt in enumerate(kpts): - if score[kid] < kpt_thr or not visible[ - kid] or kpt_color[kid] is None: - # skip the point that should not be drawn - continue - - color = kpt_color[kid] - if not isinstance(color, str): - color = tuple(int(c) for c in color) - transparency = self.alpha - if self.show_keypoint_weight: - transparency *= max(0, min(1, score[kid])) - self.draw_circles( - kpt, - radius=np.array([self.radius]), - face_colors=color, - edge_colors=color, - alpha=transparency, - line_widths=self.radius) - if show_kpt_idx: - self.draw_texts( - str(kid), - kpt, - colors=color, - font_sizes=self.radius * 3, - vertical_alignments='bottom', - horizontal_alignments='center') - # draw links if self.skeleton is not None and self.link_color is not None: if self.link_color is None or isinstance( @@ -367,13 +345,13 @@ def _draw_instances_kpts(self, mX = np.mean(X) mY = np.mean(Y) length = ((Y[0] - Y[1])**2 + (X[0] - X[1])**2)**0.5 + transparency = 0.6 angle = math.degrees( math.atan2(Y[0] - Y[1], X[0] - X[1])) - stickwidth = 2 polygons = cv2.ellipse2Poly( (int(mX), int(mY)), - (int(length / 2), int(stickwidth)), int(angle), - 0, 360, 1) + (int(length / 2), int(self.line_width)), + int(angle), 0, 360, 1) self.draw_polygons( polygons, @@ -385,6 +363,37 @@ def _draw_instances_kpts(self, self.draw_lines( X, Y, color, line_widths=self.line_width) + # draw each point on image + for kid, kpt in enumerate(kpts): + if score[kid] < kpt_thr or not visible[ + kid] or kpt_color[kid] is None: + # skip the point that should not be drawn + continue + + color = kpt_color[kid] + if not isinstance(color, str): + color = tuple(int(c) for c in color) + transparency = self.alpha + if self.show_keypoint_weight: + transparency *= max(0, min(1, score[kid])) + self.draw_circles( + kpt, + radius=np.array([self.radius]), + face_colors=color, + edge_colors=color, + alpha=transparency, + line_widths=self.radius) + if show_kpt_idx: + kpt[0] += self.radius + kpt[1] -= self.radius + self.draw_texts( + str(kid), + kpt, + colors=color, + font_sizes=self.radius * 3, + vertical_alignments='bottom', + horizontal_alignments='center') + return self.get_image() def _draw_instance_heatmap( diff --git a/mmpose/visualization/local_visualizer_3d.py b/mmpose/visualization/local_visualizer_3d.py new file mode 100644 index 0000000000..7e3462ce79 --- /dev/null +++ b/mmpose/visualization/local_visualizer_3d.py @@ -0,0 +1,564 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import math +from typing import Dict, List, Optional, Tuple, Union + +import cv2 +import mmcv +import numpy as np +from matplotlib import pyplot as plt +from mmengine.dist import master_only +from mmengine.structures import InstanceData + +from mmpose.registry import VISUALIZERS +from mmpose.structures import PoseDataSample +from . import PoseLocalVisualizer + + +@VISUALIZERS.register_module() +class Pose3dLocalVisualizer(PoseLocalVisualizer): + """MMPose 3d Local Visualizer. + + Args: + name (str): Name of the instance. Defaults to 'visualizer'. + image (np.ndarray, optional): the origin image to draw. The format + should be RGB. Defaults to ``None`` + vis_backends (list, optional): Visual backend config list. Defaults to + ``None`` + save_dir (str, optional): Save file dir for all storage backends. + If it is ``None``, the backend storage will not save any data. + Defaults to ``None`` + bbox_color (str, tuple(int), optional): Color of bbox lines. + The tuple of color should be in BGR order. Defaults to ``'green'`` + kpt_color (str, tuple(tuple(int)), optional): Color of keypoints. + The tuple of color should be in BGR order. Defaults to ``'red'`` + link_color (str, tuple(tuple(int)), optional): Color of skeleton. + The tuple of color should be in BGR order. Defaults to ``None`` + line_width (int, float): The width of lines. Defaults to 1 + radius (int, float): The radius of keypoints. Defaults to 4 + show_keypoint_weight (bool): Whether to adjust the transparency + of keypoints according to their score. Defaults to ``False`` + alpha (int, float): The transparency of bboxes. Defaults to ``0.8`` + det_kpt_color (str, tuple(tuple(int)), optional): Keypoints color + info for detection. Defaults to ``None`` + det_dataset_skeleton (list): Skeleton info for detection. Defaults to + ``None`` + det_dataset_link_color (list): Link color for detection. Defaults to + ``None`` + """ + + def __init__( + self, + name: str = 'visualizer', + image: Optional[np.ndarray] = None, + vis_backends: Optional[Dict] = None, + save_dir: Optional[str] = None, + bbox_color: Optional[Union[str, Tuple[int]]] = 'green', + kpt_color: Optional[Union[str, Tuple[Tuple[int]]]] = 'red', + link_color: Optional[Union[str, Tuple[Tuple[int]]]] = None, + text_color: Optional[Union[str, Tuple[int]]] = (255, 255, 255), + skeleton: Optional[Union[List, Tuple]] = None, + line_width: Union[int, float] = 1, + radius: Union[int, float] = 3, + show_keypoint_weight: bool = False, + backend: str = 'opencv', + alpha: float = 0.8, + det_kpt_color: Optional[Union[str, Tuple[Tuple[int]]]] = None, + det_dataset_skeleton: Optional[Union[str, + Tuple[Tuple[int]]]] = None, + det_dataset_link_color: Optional[np.ndarray] = None): + super().__init__(name, image, vis_backends, save_dir, bbox_color, + kpt_color, link_color, text_color, skeleton, + line_width, radius, show_keypoint_weight, backend, + alpha) + self.det_kpt_color = det_kpt_color + self.det_dataset_skeleton = det_dataset_skeleton + self.det_dataset_link_color = det_dataset_link_color + + def _draw_3d_data_samples( + self, + image: np.ndarray, + pose_samples: PoseDataSample, + draw_gt: bool = True, + kpt_thr: float = 0.3, + num_instances=-1, + axis_azimuth: float = 70, + axis_limit: float = 1.7, + axis_dist: float = 10.0, + axis_elev: float = 15.0, + ): + """Draw keypoints and skeletons (optional) of GT or prediction. + + Args: + image (np.ndarray): The image to draw. + instances (:obj:`InstanceData`): Data structure for + instance-level annotations or predictions. + draw_gt (bool): Whether to draw GT PoseDataSample. Default to + ``True`` + kpt_thr (float, optional): Minimum threshold of keypoints + to be shown. Default: 0.3. + num_instances (int): Number of instances to be shown in 3D. If + smaller than 0, all the instances in the pose_result will be + shown. Otherwise, pad or truncate the pose_result to a length + of num_instances. + axis_azimuth (float): axis azimuth angle for 3D visualizations. + axis_dist (float): axis distance for 3D visualizations. + axis_elev (float): axis elevation view angle for 3D visualizations. + axis_limit (float): The axis limit to visualize 3d pose. The xyz + range will be set as: + - x: [x_c - axis_limit/2, x_c + axis_limit/2] + - y: [y_c - axis_limit/2, y_c + axis_limit/2] + - z: [0, axis_limit] + Where x_c, y_c is the mean value of x and y coordinates + + Returns: + Tuple(np.ndarray): the drawn image which channel is RGB. + """ + vis_height, vis_width, _ = image.shape + + if 'pred_instances' in pose_samples: + pred_instances = pose_samples.pred_instances + else: + pred_instances = InstanceData() + if num_instances < 0: + if 'keypoints' in pred_instances: + num_instances = len(pred_instances) + else: + num_instances = 0 + else: + if len(pred_instances) > num_instances: + pred_instances_ = InstanceData() + for k in pred_instances.keys(): + new_val = pred_instances[k][:num_instances] + pred_instances_.set_field(new_val, k) + pred_instances = pred_instances_ + elif num_instances < len(pred_instances): + num_instances = len(pred_instances) + + num_fig = num_instances + if draw_gt: + vis_width *= 2 + num_fig *= 2 + + plt.ioff() + fig = plt.figure( + figsize=(vis_width * num_instances * 0.01, vis_height * 0.01)) + + def _draw_3d_instances_kpts(keypoints, + scores, + keypoints_visible, + fig_idx, + title=None): + + for idx, (kpts, score, visible) in enumerate( + zip(keypoints, scores, keypoints_visible)): + + valid = np.logical_and(score >= kpt_thr, + np.any(~np.isnan(kpts), axis=-1)) + + ax = fig.add_subplot( + 1, num_fig, fig_idx * (idx + 1), projection='3d') + ax.view_init(elev=axis_elev, azim=axis_azimuth) + ax.set_zlim3d([0, axis_limit]) + ax.set_aspect('auto') + ax.set_xticks([]) + ax.set_yticks([]) + ax.set_zticks([]) + ax.set_xticklabels([]) + ax.set_yticklabels([]) + ax.set_zticklabels([]) + ax.scatter([0], [0], [0], marker='o', color='red') + if title: + ax.set_title(f'{title} ({idx})') + ax.dist = axis_dist + + x_c = np.mean(kpts[valid, 0]) if valid.any() else 0 + y_c = np.mean(kpts[valid, 1]) if valid.any() else 0 + + ax.set_xlim3d([x_c - axis_limit / 2, x_c + axis_limit / 2]) + ax.set_ylim3d([y_c - axis_limit / 2, y_c + axis_limit / 2]) + + kpts = np.array(kpts, copy=False) + + if self.kpt_color is None or isinstance(self.kpt_color, str): + kpt_color = [self.kpt_color] * len(kpts) + elif len(self.kpt_color) == len(kpts): + kpt_color = self.kpt_color + else: + raise ValueError( + f'the length of kpt_color ' + f'({len(self.kpt_color)}) does not matches ' + f'that of keypoints ({len(kpts)})') + + kpts = kpts[valid] + x_3d, y_3d, z_3d = np.split(kpts[:, :3], [1, 2], axis=1) + + kpt_color = kpt_color[valid][..., ::-1] / 255. + + ax.scatter(x_3d, y_3d, z_3d, marker='o', color=kpt_color) + + for kpt_idx in range(len(x_3d)): + ax.text(x_3d[kpt_idx][0], y_3d[kpt_idx][0], + z_3d[kpt_idx][0], str(kpt_idx)) + + if self.skeleton is not None and self.link_color is not None: + if self.link_color is None or isinstance( + self.link_color, str): + link_color = [self.link_color] * len(self.skeleton) + elif len(self.link_color) == len(self.skeleton): + link_color = self.link_color + else: + raise ValueError( + f'the length of link_color ' + f'({len(self.link_color)}) does not matches ' + f'that of skeleton ({len(self.skeleton)})') + + for sk_id, sk in enumerate(self.skeleton): + sk_indices = [_i for _i in sk] + xs_3d = kpts[sk_indices, 0] + ys_3d = kpts[sk_indices, 1] + zs_3d = kpts[sk_indices, 2] + kpt_score = score[sk_indices] + if kpt_score.min() > kpt_thr: + # matplotlib uses RGB color in [0, 1] value range + _color = link_color[sk_id][::-1] / 255. + ax.plot( + xs_3d, ys_3d, zs_3d, color=_color, zdir='z') + + if 'keypoints' in pred_instances: + keypoints = pred_instances.get('keypoints', + pred_instances.keypoints) + + if 'keypoint_scores' in pred_instances: + scores = pred_instances.keypoint_scores + else: + scores = np.ones(keypoints.shape[:-1]) + + if 'keypoints_visible' in pred_instances: + keypoints_visible = pred_instances.keypoints_visible + else: + keypoints_visible = np.ones(keypoints.shape[:-1]) + + _draw_3d_instances_kpts(keypoints, scores, keypoints_visible, 1, + 'Prediction') + + if draw_gt and 'gt_instances' in pose_samples: + gt_instances = pose_samples.gt_instances + if 'lifting_target' in gt_instances: + keypoints = gt_instances.get('lifting_target', + gt_instances.lifting_target) + scores = np.ones(keypoints.shape[:-1]) + + if 'lifting_target_visible' in gt_instances: + keypoints_visible = gt_instances.lifting_target_visible + else: + keypoints_visible = np.ones(keypoints.shape[:-1]) + + _draw_3d_instances_kpts(keypoints, scores, keypoints_visible, + 2, 'Ground Truth') + + # convert figure to numpy array + fig.tight_layout() + fig.canvas.draw() + + pred_img_data = fig.canvas.tostring_rgb() + pred_img_data = np.frombuffer( + fig.canvas.tostring_rgb(), dtype=np.uint8) + + if not pred_img_data.any(): + pred_img_data = np.full((vis_height, vis_width, 3), 255) + else: + pred_img_data = pred_img_data.reshape(vis_height, + vis_width * num_instances, + -1) + + plt.close(fig) + + return pred_img_data + + def _draw_instances_kpts(self, + image: np.ndarray, + instances: InstanceData, + kpt_thr: float = 0.3, + show_kpt_idx: bool = False, + skeleton_style: str = 'mmpose'): + """Draw keypoints and skeletons (optional) of GT or prediction. + + Args: + image (np.ndarray): The image to draw. + instances (:obj:`InstanceData`): Data structure for + instance-level annotations or predictions. + kpt_thr (float, optional): Minimum threshold of keypoints + to be shown. Default: 0.3. + show_kpt_idx (bool): Whether to show the index of keypoints. + Defaults to ``False`` + skeleton_style (str): Skeleton style selection. Defaults to + ``'mmpose'`` + + Returns: + np.ndarray: the drawn image which channel is RGB. + """ + + self.set_image(image) + img_h, img_w, _ = image.shape + + if 'keypoints' in instances: + keypoints = instances.get('transformed_keypoints', + instances.keypoints) + + if 'keypoint_scores' in instances: + scores = instances.keypoint_scores + else: + scores = np.ones(keypoints.shape[:-1]) + + if 'keypoints_visible' in instances: + keypoints_visible = instances.keypoints_visible + else: + keypoints_visible = np.ones(keypoints.shape[:-1]) + + if skeleton_style == 'openpose': + keypoints_info = np.concatenate( + (keypoints, scores[..., None], keypoints_visible[..., + None]), + axis=-1) + # compute neck joint + neck = np.mean(keypoints_info[:, [5, 6]], axis=1) + # neck score when visualizing pred + neck[:, 2:4] = np.logical_and( + keypoints_info[:, 5, 2:4] > kpt_thr, + keypoints_info[:, 6, 2:4] > kpt_thr).astype(int) + new_keypoints_info = np.insert( + keypoints_info, 17, neck, axis=1) + + mmpose_idx = [ + 17, 6, 8, 10, 7, 9, 12, 14, 16, 13, 15, 2, 1, 4, 3 + ] + openpose_idx = [ + 1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17 + ] + new_keypoints_info[:, openpose_idx] = \ + new_keypoints_info[:, mmpose_idx] + keypoints_info = new_keypoints_info + + keypoints, scores, keypoints_visible = keypoints_info[ + ..., :2], keypoints_info[..., 2], keypoints_info[..., 3] + + kpt_color = self.kpt_color + if self.det_kpt_color is not None: + kpt_color = self.det_kpt_color + + for kpts, score, visible in zip(keypoints, scores, + keypoints_visible): + kpts = np.array(kpts, copy=False) + + if kpt_color is None or isinstance(kpt_color, str): + kpt_color = [kpt_color] * len(kpts) + elif len(kpt_color) == len(kpts): + kpt_color = kpt_color + else: + raise ValueError(f'the length of kpt_color ' + f'({len(kpt_color)}) does not matches ' + f'that of keypoints ({len(kpts)})') + + # draw each point on image + for kid, kpt in enumerate(kpts): + if score[kid] < kpt_thr or not visible[ + kid] or kpt_color[kid] is None: + # skip the point that should not be drawn + continue + + color = kpt_color[kid] + if not isinstance(color, str): + color = tuple(int(c) for c in color) + transparency = self.alpha + if self.show_keypoint_weight: + transparency *= max(0, min(1, score[kid])) + self.draw_circles( + kpt, + radius=np.array([self.radius]), + face_colors=color, + edge_colors=color, + alpha=transparency, + line_widths=self.radius) + if show_kpt_idx: + self.draw_texts( + str(kid), + kpt, + colors=color, + font_sizes=self.radius * 3, + vertical_alignments='bottom', + horizontal_alignments='center') + + # draw links + skeleton = self.skeleton + if self.det_dataset_skeleton is not None: + skeleton = self.det_dataset_skeleton + link_color = self.link_color + if self.det_dataset_link_color is not None: + link_color = self.det_dataset_link_color + if skeleton is not None and link_color is not None: + if link_color is None or isinstance(link_color, str): + link_color = [link_color] * len(skeleton) + elif len(link_color) == len(skeleton): + link_color = link_color + else: + raise ValueError( + f'the length of link_color ' + f'({len(link_color)}) does not matches ' + f'that of skeleton ({len(skeleton)})') + + for sk_id, sk in enumerate(skeleton): + pos1 = (int(kpts[sk[0], 0]), int(kpts[sk[0], 1])) + pos2 = (int(kpts[sk[1], 0]), int(kpts[sk[1], 1])) + if not (visible[sk[0]] and visible[sk[1]]): + continue + + if (pos1[0] <= 0 or pos1[0] >= img_w or pos1[1] <= 0 + or pos1[1] >= img_h or pos2[0] <= 0 + or pos2[0] >= img_w or pos2[1] <= 0 + or pos2[1] >= img_h or score[sk[0]] < kpt_thr + or score[sk[1]] < kpt_thr + or link_color[sk_id] is None): + # skip the link that should not be drawn + continue + X = np.array((pos1[0], pos2[0])) + Y = np.array((pos1[1], pos2[1])) + color = link_color[sk_id] + if not isinstance(color, str): + color = tuple(int(c) for c in color) + transparency = self.alpha + if self.show_keypoint_weight: + transparency *= max( + 0, min(1, 0.5 * (score[sk[0]] + score[sk[1]]))) + + if skeleton_style == 'openpose': + mX = np.mean(X) + mY = np.mean(Y) + length = ((Y[0] - Y[1])**2 + (X[0] - X[1])**2)**0.5 + angle = math.degrees( + math.atan2(Y[0] - Y[1], X[0] - X[1])) + stickwidth = 2 + polygons = cv2.ellipse2Poly( + (int(mX), int(mY)), + (int(length / 2), int(stickwidth)), int(angle), + 0, 360, 1) + + self.draw_polygons( + polygons, + edge_colors=color, + face_colors=color, + alpha=transparency) + + else: + self.draw_lines( + X, Y, color, line_widths=self.line_width) + + return self.get_image() + + @master_only + def add_datasample(self, + name: str, + image: np.ndarray, + data_sample: PoseDataSample, + det_data_sample: Optional[PoseDataSample] = None, + draw_gt: bool = True, + draw_pred: bool = True, + draw_2d: bool = True, + draw_bbox: bool = False, + show_kpt_idx: bool = False, + skeleton_style: str = 'mmpose', + num_instances: int = -1, + show: bool = False, + wait_time: float = 0, + out_file: Optional[str] = None, + kpt_thr: float = 0.3, + step: int = 0) -> None: + """Draw datasample and save to all backends. + + - If GT and prediction are plotted at the same time, they are + displayed in a stitched image where the left image is the + ground truth and the right image is the prediction. + - If ``show`` is True, all storage backends are ignored, and + the images will be displayed in a local window. + - If ``out_file`` is specified, the drawn image will be + saved to ``out_file``. t is usually used when the display + is not available. + + Args: + name (str): The image identifier + image (np.ndarray): The image to draw + data_sample (:obj:`PoseDataSample`): The 3d data sample + to visualize + det_data_sample (:obj:`PoseDataSample`, optional): The 2d detection + data sample to visualize + draw_gt (bool): Whether to draw GT PoseDataSample. Default to + ``True`` + draw_pred (bool): Whether to draw Prediction PoseDataSample. + Defaults to ``True`` + draw_2d (bool): Whether to draw 2d detection results. Defaults to + ``True`` + draw_bbox (bool): Whether to draw bounding boxes. Default to + ``False`` + show_kpt_idx (bool): Whether to show the index of keypoints. + Defaults to ``False`` + skeleton_style (str): Skeleton style selection. Defaults to + ``'mmpose'`` + num_instances (int): Number of instances to be shown in 3D. If + smaller than 0, all the instances in the pose_result will be + shown. Otherwise, pad or truncate the pose_result to a length + of num_instances. Defaults to -1 + show (bool): Whether to display the drawn image. Default to + ``False`` + wait_time (float): The interval of show (s). Defaults to 0 + out_file (str): Path to output file. Defaults to ``None`` + kpt_thr (float, optional): Minimum threshold of keypoints + to be shown. Default: 0.3. + step (int): Global step value to record. Defaults to 0 + """ + + det_img_data = None + gt_img_data = None + + if draw_2d: + det_img_data = image.copy() + + # draw bboxes & keypoints + if 'pred_instances' in det_data_sample: + det_img_data = self._draw_instances_kpts( + det_img_data, det_data_sample.pred_instances, kpt_thr, + show_kpt_idx, skeleton_style) + if draw_bbox: + det_img_data = self._draw_instances_bbox( + det_img_data, det_data_sample.pred_instances) + + pred_img_data = self._draw_3d_data_samples( + image.copy(), + data_sample, + draw_gt=draw_gt, + num_instances=num_instances) + + # merge visualization results + if det_img_data is not None and gt_img_data is not None: + drawn_img = np.concatenate( + (det_img_data, pred_img_data, gt_img_data), axis=1) + elif det_img_data is not None: + drawn_img = np.concatenate((det_img_data, pred_img_data), axis=1) + elif gt_img_data is not None: + drawn_img = np.concatenate((det_img_data, gt_img_data), axis=1) + else: + drawn_img = pred_img_data + + # It is convenient for users to obtain the drawn image. + # For example, the user wants to obtain the drawn image and + # save it as a video during video inference. + self.set_image(drawn_img) + + if show: + self.show(drawn_img, win_name=name, wait_time=wait_time) + + if out_file is not None: + mmcv.imwrite(drawn_img[..., ::-1], out_file) + else: + # save drawn_img to backends + self.add_image(name, drawn_img, step) + + return self.get_image() diff --git a/mmpose/visualization/opencv_backend_visualizer.py b/mmpose/visualization/opencv_backend_visualizer.py new file mode 100644 index 0000000000..1c17506640 --- /dev/null +++ b/mmpose/visualization/opencv_backend_visualizer.py @@ -0,0 +1,464 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import List, Optional, Union + +import cv2 +import mmcv +import numpy as np +import torch +from mmengine.dist import master_only +from mmengine.visualization import Visualizer + + +class OpencvBackendVisualizer(Visualizer): + """Base visualizer with opencv backend support. + + Args: + name (str): Name of the instance. Defaults to 'visualizer'. + image (np.ndarray, optional): the origin image to draw. The format + should be RGB. Defaults to None. + vis_backends (list, optional): Visual backend config list. + Defaults to None. + save_dir (str, optional): Save file dir for all storage backends. + If it is None, the backend storage will not save any data. + fig_save_cfg (dict): Keyword parameters of figure for saving. + Defaults to empty dict. + fig_show_cfg (dict): Keyword parameters of figure for showing. + Defaults to empty dict. + backend (str): Backend used to draw elements on the image and display + the image. Defaults to 'matplotlib'. + alpha (int, float): The transparency of bboxes. Defaults to ``1.0`` + """ + + def __init__(self, + name='visualizer', + backend: str = 'matplotlib', + *args, + **kwargs): + super().__init__(name, *args, **kwargs) + assert backend in ('opencv', 'matplotlib'), f'the argument ' \ + f'\'backend\' must be either \'opencv\' or \'matplotlib\', ' \ + f'but got \'{backend}\'.' + self.backend = backend + + @master_only + def set_image(self, image: np.ndarray) -> None: + """Set the image to draw. + + Args: + image (np.ndarray): The image to draw. + backend (str): The backend to save the image. + """ + assert image is not None + image = image.astype('uint8') + self._image = image + self.width, self.height = image.shape[1], image.shape[0] + self._default_font_size = max( + np.sqrt(self.height * self.width) // 90, 10) + + if self.backend == 'matplotlib': + # add a small 1e-2 to avoid precision lost due to matplotlib's + # truncation (https://github.com/matplotlib/matplotlib/issues/15363) # noqa + self.fig_save.set_size_inches( # type: ignore + (self.width + 1e-2) / self.dpi, + (self.height + 1e-2) / self.dpi) + # self.canvas = mpl.backends.backend_cairo.FigureCanvasCairo(fig) + self.ax_save.cla() + self.ax_save.axis(False) + self.ax_save.imshow( + image, + extent=(0, self.width, self.height, 0), + interpolation='none') + + @master_only + def get_image(self) -> np.ndarray: + """Get the drawn image. The format is RGB. + + Returns: + np.ndarray: the drawn image which channel is RGB. + """ + assert self._image is not None, 'Please set image using `set_image`' + if self.backend == 'matplotlib': + return super().get_image() + else: + return self._image + + @master_only + def draw_circles(self, + center: Union[np.ndarray, torch.Tensor], + radius: Union[np.ndarray, torch.Tensor], + face_colors: Union[str, tuple, List[str], + List[tuple]] = 'none', + alpha: float = 1.0, + **kwargs) -> 'Visualizer': + """Draw single or multiple circles. + + Args: + center (Union[np.ndarray, torch.Tensor]): The x coordinate of + each line' start and end points. + radius (Union[np.ndarray, torch.Tensor]): The y coordinate of + each line' start and end points. + edge_colors (Union[str, tuple, List[str], List[tuple]]): The + colors of circles. ``colors`` can have the same length with + lines or just single value. If ``colors`` is single value, + all the lines will have the same colors. Reference to + https://matplotlib.org/stable/gallery/color/named_colors.html + for more details. Defaults to 'g. + line_styles (Union[str, List[str]]): The linestyle + of lines. ``line_styles`` can have the same length with + texts or just single value. If ``line_styles`` is single + value, all the lines will have the same linestyle. + Reference to + https://matplotlib.org/stable/api/collections_api.html?highlight=collection#matplotlib.collections.AsteriskPolygonCollection.set_linestyle + for more details. Defaults to '-'. + line_widths (Union[Union[int, float], List[Union[int, float]]]): + The linewidth of lines. ``line_widths`` can have + the same length with lines or just single value. + If ``line_widths`` is single value, all the lines will + have the same linewidth. Defaults to 2. + face_colors (Union[str, tuple, List[str], List[tuple]]): + The face colors. Defaults to None. + alpha (Union[int, float]): The transparency of circles. + Defaults to 0.8. + """ + if self.backend == 'matplotlib': + super().draw_circles( + center=center, + radius=radius, + face_colors=face_colors, + alpha=alpha, + **kwargs) + elif self.backend == 'opencv': + if isinstance(face_colors, str): + face_colors = mmcv.color_val(face_colors) + + if alpha == 1.0: + self._image = cv2.circle(self._image, + (int(center[0]), int(center[1])), + int(radius), face_colors, -1) + else: + img = cv2.circle(self._image.copy(), + (int(center[0]), int(center[1])), int(radius), + face_colors, -1) + self._image = cv2.addWeighted(self._image, 1 - alpha, img, + alpha, 0) + else: + raise ValueError(f'got unsupported backend {self.backend}') + + @master_only + def draw_texts( + self, + texts: Union[str, List[str]], + positions: Union[np.ndarray, torch.Tensor], + font_sizes: Optional[Union[int, List[int]]] = None, + colors: Union[str, tuple, List[str], List[tuple]] = 'g', + vertical_alignments: Union[str, List[str]] = 'top', + horizontal_alignments: Union[str, List[str]] = 'left', + bboxes: Optional[Union[dict, List[dict]]] = None, + **kwargs, + ) -> 'Visualizer': + """Draw single or multiple text boxes. + + Args: + texts (Union[str, List[str]]): Texts to draw. + positions (Union[np.ndarray, torch.Tensor]): The position to draw + the texts, which should have the same length with texts and + each dim contain x and y. + font_sizes (Union[int, List[int]], optional): The font size of + texts. ``font_sizes`` can have the same length with texts or + just single value. If ``font_sizes`` is single value, all the + texts will have the same font size. Defaults to None. + colors (Union[str, tuple, List[str], List[tuple]]): The colors + of texts. ``colors`` can have the same length with texts or + just single value. If ``colors`` is single value, all the + texts will have the same colors. Reference to + https://matplotlib.org/stable/gallery/color/named_colors.html + for more details. Defaults to 'g. + vertical_alignments (Union[str, List[str]]): The verticalalignment + of texts. verticalalignment controls whether the y positional + argument for the text indicates the bottom, center or top side + of the text bounding box. + ``vertical_alignments`` can have the same length with + texts or just single value. If ``vertical_alignments`` is + single value, all the texts will have the same + verticalalignment. verticalalignment can be 'center' or + 'top', 'bottom' or 'baseline'. Defaults to 'top'. + horizontal_alignments (Union[str, List[str]]): The + horizontalalignment of texts. Horizontalalignment controls + whether the x positional argument for the text indicates the + left, center or right side of the text bounding box. + ``horizontal_alignments`` can have + the same length with texts or just single value. + If ``horizontal_alignments`` is single value, all the texts + will have the same horizontalalignment. Horizontalalignment + can be 'center','right' or 'left'. Defaults to 'left'. + font_families (Union[str, List[str]]): The font family of + texts. ``font_families`` can have the same length with texts or + just single value. If ``font_families`` is single value, all + the texts will have the same font family. + font_familiy can be 'serif', 'sans-serif', 'cursive', 'fantasy' + or 'monospace'. Defaults to 'sans-serif'. + bboxes (Union[dict, List[dict]], optional): The bounding box of the + texts. If bboxes is None, there are no bounding box around + texts. ``bboxes`` can have the same length with texts or + just single value. If ``bboxes`` is single value, all + the texts will have the same bbox. Reference to + https://matplotlib.org/stable/api/_as_gen/matplotlib.patches.FancyBboxPatch.html#matplotlib.patches.FancyBboxPatch + for more details. Defaults to None. + font_properties (Union[FontProperties, List[FontProperties]], optional): + The font properties of texts. FontProperties is + a ``font_manager.FontProperties()`` object. + If you want to draw Chinese texts, you need to prepare + a font file that can show Chinese characters properly. + For example: `simhei.ttf`, `simsun.ttc`, `simkai.ttf` and so on. + Then set ``font_properties=matplotlib.font_manager.FontProperties(fname='path/to/font_file')`` + ``font_properties`` can have the same length with texts or + just single value. If ``font_properties`` is single value, + all the texts will have the same font properties. + Defaults to None. + `New in version 0.6.0.` + """ # noqa: E501 + + if self.backend == 'matplotlib': + super().draw_texts( + texts=texts, + positions=positions, + font_sizes=font_sizes, + colors=colors, + vertical_alignments=vertical_alignments, + horizontal_alignments=horizontal_alignments, + bboxes=bboxes, + **kwargs) + + elif self.backend == 'opencv': + font_scale = max(0.1, font_sizes / 30) + thickness = max(1, font_sizes // 15) + + text_size, text_baseline = cv2.getTextSize(texts, + cv2.FONT_HERSHEY_DUPLEX, + font_scale, thickness) + + x = int(positions[0]) + if horizontal_alignments == 'right': + x = max(0, x - text_size[0]) + y = int(positions[1]) + if vertical_alignments == 'top': + y = min(self.height, y + text_size[1]) + + if bboxes is not None: + bbox_color = bboxes[0]['facecolor'] + if isinstance(bbox_color, str): + bbox_color = mmcv.color_val(bbox_color) + + y = y - text_baseline // 2 + self._image = cv2.rectangle( + self._image, (x, y - text_size[1] - text_baseline // 2), + (x + text_size[0], y + text_baseline // 2), bbox_color, + cv2.FILLED) + + self._image = cv2.putText(self._image, texts, (x, y), + cv2.FONT_HERSHEY_SIMPLEX, font_scale, + colors, thickness - 1) + else: + raise ValueError(f'got unsupported backend {self.backend}') + + @master_only + def draw_bboxes(self, + bboxes: Union[np.ndarray, torch.Tensor], + edge_colors: Union[str, tuple, List[str], + List[tuple]] = 'g', + line_widths: Union[Union[int, float], + List[Union[int, float]]] = 2, + **kwargs) -> 'Visualizer': + """Draw single or multiple bboxes. + + Args: + bboxes (Union[np.ndarray, torch.Tensor]): The bboxes to draw with + the format of(x1,y1,x2,y2). + edge_colors (Union[str, tuple, List[str], List[tuple]]): The + colors of bboxes. ``colors`` can have the same length with + lines or just single value. If ``colors`` is single value, all + the lines will have the same colors. Refer to `matplotlib. + colors` for full list of formats that are accepted. + Defaults to 'g'. + line_styles (Union[str, List[str]]): The linestyle + of lines. ``line_styles`` can have the same length with + texts or just single value. If ``line_styles`` is single + value, all the lines will have the same linestyle. + Reference to + https://matplotlib.org/stable/api/collections_api.html?highlight=collection#matplotlib.collections.AsteriskPolygonCollection.set_linestyle + for more details. Defaults to '-'. + line_widths (Union[Union[int, float], List[Union[int, float]]]): + The linewidth of lines. ``line_widths`` can have + the same length with lines or just single value. + If ``line_widths`` is single value, all the lines will + have the same linewidth. Defaults to 2. + face_colors (Union[str, tuple, List[str], List[tuple]]): + The face colors. Defaults to None. + alpha (Union[int, float]): The transparency of bboxes. + Defaults to 0.8. + """ + if self.backend == 'matplotlib': + super().draw_bboxes( + bboxes=bboxes, + edge_colors=edge_colors, + line_widths=line_widths, + **kwargs) + + elif self.backend == 'opencv': + self._image = mmcv.imshow_bboxes( + self._image, + bboxes, + edge_colors, + top_k=-1, + thickness=line_widths, + show=False) + else: + raise ValueError(f'got unsupported backend {self.backend}') + + @master_only + def draw_lines(self, + x_datas: Union[np.ndarray, torch.Tensor], + y_datas: Union[np.ndarray, torch.Tensor], + colors: Union[str, tuple, List[str], List[tuple]] = 'g', + line_widths: Union[Union[int, float], + List[Union[int, float]]] = 2, + **kwargs) -> 'Visualizer': + """Draw single or multiple line segments. + + Args: + x_datas (Union[np.ndarray, torch.Tensor]): The x coordinate of + each line' start and end points. + y_datas (Union[np.ndarray, torch.Tensor]): The y coordinate of + each line' start and end points. + colors (Union[str, tuple, List[str], List[tuple]]): The colors of + lines. ``colors`` can have the same length with lines or just + single value. If ``colors`` is single value, all the lines + will have the same colors. Reference to + https://matplotlib.org/stable/gallery/color/named_colors.html + for more details. Defaults to 'g'. + line_styles (Union[str, List[str]]): The linestyle + of lines. ``line_styles`` can have the same length with + texts or just single value. If ``line_styles`` is single + value, all the lines will have the same linestyle. + Reference to + https://matplotlib.org/stable/api/collections_api.html?highlight=collection#matplotlib.collections.AsteriskPolygonCollection.set_linestyle + for more details. Defaults to '-'. + line_widths (Union[Union[int, float], List[Union[int, float]]]): + The linewidth of lines. ``line_widths`` can have + the same length with lines or just single value. + If ``line_widths`` is single value, all the lines will + have the same linewidth. Defaults to 2. + """ + if self.backend == 'matplotlib': + super().draw_lines( + x_datas=x_datas, + y_datas=y_datas, + colors=colors, + line_widths=line_widths, + **kwargs) + + elif self.backend == 'opencv': + + self._image = cv2.line( + self._image, (x_datas[0], y_datas[0]), + (x_datas[1], y_datas[1]), + colors, + thickness=line_widths) + else: + raise ValueError(f'got unsupported backend {self.backend}') + + @master_only + def draw_polygons(self, + polygons: Union[Union[np.ndarray, torch.Tensor], + List[Union[np.ndarray, torch.Tensor]]], + edge_colors: Union[str, tuple, List[str], + List[tuple]] = 'g', + alpha: float = 1.0, + **kwargs) -> 'Visualizer': + """Draw single or multiple bboxes. + + Args: + polygons (Union[Union[np.ndarray, torch.Tensor],\ + List[Union[np.ndarray, torch.Tensor]]]): The polygons to draw + with the format of (x1,y1,x2,y2,...,xn,yn). + edge_colors (Union[str, tuple, List[str], List[tuple]]): The + colors of polygons. ``colors`` can have the same length with + lines or just single value. If ``colors`` is single value, + all the lines will have the same colors. Refer to + `matplotlib.colors` for full list of formats that are accepted. + Defaults to 'g. + line_styles (Union[str, List[str]]): The linestyle + of lines. ``line_styles`` can have the same length with + texts or just single value. If ``line_styles`` is single + value, all the lines will have the same linestyle. + Reference to + https://matplotlib.org/stable/api/collections_api.html?highlight=collection#matplotlib.collections.AsteriskPolygonCollection.set_linestyle + for more details. Defaults to '-'. + line_widths (Union[Union[int, float], List[Union[int, float]]]): + The linewidth of lines. ``line_widths`` can have + the same length with lines or just single value. + If ``line_widths`` is single value, all the lines will + have the same linewidth. Defaults to 2. + face_colors (Union[str, tuple, List[str], List[tuple]]): + The face colors. Defaults to None. + alpha (Union[int, float]): The transparency of polygons. + Defaults to 0.8. + """ + if self.backend == 'matplotlib': + super().draw_polygons( + polygons=polygons, + edge_colors=edge_colors, + alpha=alpha, + **kwargs) + + elif self.backend == 'opencv': + if alpha == 1.0: + self._image = cv2.fillConvexPoly(self._image, polygons, + edge_colors) + else: + img = cv2.fillConvexPoly(self._image.copy(), polygons, + edge_colors) + self._image = cv2.addWeighted(self._image, 1 - alpha, img, + alpha, 0) + else: + raise ValueError(f'got unsupported backend {self.backend}') + + @master_only + def show(self, + drawn_img: Optional[np.ndarray] = None, + win_name: str = 'image', + wait_time: float = 0., + continue_key=' ') -> None: + """Show the drawn image. + + Args: + drawn_img (np.ndarray, optional): The image to show. If drawn_img + is None, it will show the image got by Visualizer. Defaults + to None. + win_name (str): The image title. Defaults to 'image'. + wait_time (float): Delay in seconds. 0 is the special + value that means "forever". Defaults to 0. + continue_key (str): The key for users to continue. Defaults to + the space key. + """ + if self.backend == 'matplotlib': + super().show( + drawn_img=drawn_img, + win_name=win_name, + wait_time=wait_time, + continue_key=continue_key) + + elif self.backend == 'opencv': + # Keep images are shown in the same window, and the title of window + # will be updated with `win_name`. + if not hasattr(self, win_name): + self._cv_win_name = win_name + cv2.namedWindow(winname=f'{id(self)}') + cv2.setWindowTitle(f'{id(self)}', win_name) + else: + cv2.setWindowTitle(f'{id(self)}', win_name) + shown_img = self.get_image() if drawn_img is None else drawn_img + cv2.imshow(str(id(self)), mmcv.bgr2rgb(shown_img)) + cv2.waitKey(int(np.ceil(wait_time * 1000))) + else: + raise ValueError(f'got unsupported backend {self.backend}') diff --git a/model-index.yml b/model-index.yml index d5cb0e28d4..498e5bc743 100644 --- a/model-index.yml +++ b/model-index.yml @@ -74,6 +74,7 @@ Import: - configs/body_2d_keypoint/topdown_regression/coco/mobilenetv2_rle_coco.yml - configs/body_2d_keypoint/topdown_regression/mpii/resnet_mpii.yml - configs/body_2d_keypoint/topdown_regression/mpii/resnet_rle_mpii.yml +- configs/body_3d_keypoint/pose_lift/h36m/videopose3d_h36m.yml - configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose_coco_wholebody_face.yml - configs/face_2d_keypoint/rtmpose/wflw/rtmpose_wflw.yml - configs/face_2d_keypoint/topdown_heatmap/300w/hrnetv2_300w.yml @@ -117,3 +118,4 @@ Import: - configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/vipnas_coco-wholebody.yml - configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/vipnas_dark_coco-wholebody.yml - configs/wholebody_2d_keypoint/topdown_heatmap/coco-wholebody/cspnext_udp_coco-wholebody.yml +- configs/fashion_2d_keypoint/topdown_heatmap/deepfashion2/res50_deepfasion2.yml diff --git a/projects/README.md b/projects/README.md index 3505f96f41..a10ccad65a 100644 --- a/projects/README.md +++ b/projects/README.md @@ -33,7 +33,7 @@ We also provide some documentation listed below to help you get started: - **[:zap:RTMPose](./rtmpose)**: Real-Time Multi-Person Pose Estimation toolkit based on MMPose
- +

- **[:art:MMPose4AIGC](./mmpose4aigc)**: Guide AI image generation with MMPose @@ -48,4 +48,10 @@ We also provide some documentation listed below to help you get started:

+- **[📖Awesome MMPose](./awesome-mmpose/)**: A list of Tutorials, Papers, Datasets related to MMPose + +
+ +

+ - **What's next? Join the rank of *MMPose contributors* by creating a new project**! diff --git a/projects/awesome-mmpose/README.md b/projects/awesome-mmpose/README.md new file mode 100644 index 0000000000..99a6472269 --- /dev/null +++ b/projects/awesome-mmpose/README.md @@ -0,0 +1,80 @@ +# Awesome MMPose + +A list of resources related to MMPose. Feel free to contribute! + +
+ +

+ +## Contents + +- [Tutorials](#tutorials) +- [Papers](#papers) +- [Datasets](#datasets) +- [Projects](#projects) + +## Tutorials + +- [MMPose Tutorial (Chinese)](https://github.com/TommyZihao/MMPose_Tutorials) + + MMPose 中文视频代码教程,from 同济子豪兄 + +
+ +

+ +- [OpenMMLab Course](https://github.com/open-mmlab/OpenMMLabCourse) + + This repository hosts articles, lectures and tutorials on computer vision and OpenMMLab, helping learners to understand algorithms and master our toolboxes in a systematical way. + +## Papers + +- [\[paper\]](https://arxiv.org/abs/2207.10387) [\[code\]](https://github.com/luminxu/Pose-for-Everything) + + ECCV 2022, Pose for Everything: Towards Category-Agnostic Pose Estimation + +- [\[paper\]](https://arxiv.org/abs/2201.04676) [\[code\]](https://github.com/Sense-X/UniFormer) + + ICLR 2022, UniFormer: Unified Transformer for Efficient Spatiotemporal Representation Learning + +- [\[paper\]](https://arxiv.org/abs/2201.07412) [\[code\]](https://github.com/aim-uofa/Poseur) + + ECCV 2022, Poseur:Direct Human Pose Regression with Transformers + +- [\[paper\]](https://arxiv.org/abs/2106.03348) [\[code\]](https://github.com/ViTAE-Transformer/ViTAE-Transformer) + + NeurIPS 2022, ViTAEv2: Vision Transformer Advanced by Exploring Inductive Bias for Image Recognition and Beyond + +- [\[paper\]](https://arxiv.org/abs/2204.10762) [\[code\]](https://github.com/ZiyiZhang27/Dite-HRNet) + + IJCAI-ECAI 2021, Dite-HRNet:Dynamic Lightweight High-Resolution Network for Human Pose Estimation + +- [\[paper\]](https://arxiv.org/abs/2302.08453) [\[code\]](https://github.com/TencentARC/T2I-Adapter) + + T2I-Adapter: Learning Adapters to Dig out More Controllable Ability for Text-to-Image Diffusion Models + +- [\[paper\]](https://arxiv.org/pdf/2303.11638.pdf) [\[code\]](https://github.com/Gengzigang/PCT) + + CVPR 2023, Human Pose as Compositional Tokens + +## Datasets + +- [\[github\]](https://github.com/luminxu/Pose-for-Everything) **MP-100** + + Multi-category Pose (MP-100) dataset, which is a 2D pose dataset of 100 object categories containing over 20K instances and is well-designed for developing CAPE algorithms. + +
+ +

+ +- [\[github\]](https://github.com/facebookresearch/Ego4d/) **Ego4D** + + EGO4D is the world's largest egocentric (first person) video ML dataset and benchmark suite, with 3,600 hrs (and counting) of densely narrated video and a wide range of annotations across five new benchmark tasks. It covers hundreds of scenarios (household, outdoor, workplace, leisure, etc.) of daily life activity captured in-the-wild by 926 unique camera wearers from 74 worldwide locations and 9 different countries. + +
+ +

+ +## Projects + +Waiting for your contribution! diff --git a/projects/mmpose4aigc/README.md b/projects/mmpose4aigc/README.md index 1c9d268093..c3759d846c 100644 --- a/projects/mmpose4aigc/README.md +++ b/projects/mmpose4aigc/README.md @@ -67,8 +67,8 @@ bash install_posetracker_linux.sh After installation, files are organized as follows: ```shell -|----mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1 -| |----sdk +|----mmdeploy-1.0.0-linux-x86_64-cxx11abi +| |----README.md | |----rtmpose-ort | | |----rtmdet-nano | | |----rtmpose-m @@ -83,7 +83,7 @@ Run the following command to generate a skeleton image: ```shell # generate a skeleton image bash mmpose_style_skeleton.sh \ - mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1/rtmpose-ort/000000147979.jpg + mmdeploy-1.0.0-linux-x86_64-cxx11abi/rtmpose-ort/000000147979.jpg ``` For more details, you can refer to [RTMPose](../rtmpose/README.md). diff --git a/projects/mmpose4aigc/README_CN.md b/projects/mmpose4aigc/README_CN.md index bdb943ec17..44bbe2d459 100644 --- a/projects/mmpose4aigc/README_CN.md +++ b/projects/mmpose4aigc/README_CN.md @@ -66,8 +66,8 @@ bash install_posetracker_linux.sh 最终的文件结构如下: ```shell -|----mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1 -| |----sdk +|----mmdeploy-1.0.0-linux-x86_64-cxx11abi +| |----README.md | |----rtmpose-ort | | |----rtmdet-nano | | |----rtmpose-m @@ -82,7 +82,7 @@ bash install_posetracker_linux.sh ```shell # 生成骨架图片 bash mmpose_style_skeleton.sh \ - mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1/rtmpose-ort/000000147979.jpg + mmdeploy-1.0.0-linux-x86_64-cxx11abi/rtmpose-ort/000000147979.jpg ``` 更多详细信息可以查看 [RTMPose](../rtmpose/README_CN.md)。 diff --git a/projects/mmpose4aigc/download_models.sh b/projects/mmpose4aigc/download_models.sh index d883c190f6..c26a3c833f 100644 --- a/projects/mmpose4aigc/download_models.sh +++ b/projects/mmpose4aigc/download_models.sh @@ -11,7 +11,7 @@ cd models wget https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth # Download pose model -wget https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth +wget https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth # Go back mmpose4aigc cd .. diff --git a/projects/mmpose4aigc/install_posetracker_linux.sh b/projects/mmpose4aigc/install_posetracker_linux.sh index 3b91409b16..09c91ce9d1 100644 --- a/projects/mmpose4aigc/install_posetracker_linux.sh +++ b/projects/mmpose4aigc/install_posetracker_linux.sh @@ -2,26 +2,23 @@ # Copyright (c) OpenMMLab. All rights reserved. # Download pre-compiled files -wget https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0rc3/mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1.tar.gz +wget https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64-cxx11abi.tar.gz # Unzip files -tar -xzvf mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1.tar.gz +tar -xzvf mmdeploy-1.0.0-linux-x86_64-cxx11abi.tar.gz # Go to the sdk folder -cd mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1/sdk +cd mmdeploy-1.0.0-linux-x86_64-cxx11abi # Init environment -source env.sh +source set_env.sh # If opencv 3+ is not installed on your system, execute the following command. # If it is installed, skip this command -bash opencv.sh +bash install_opencv.sh # Compile executable programs -bash build.sh - -# Go to mmdeploy folder -cd ../ +bash build_sdk.sh # Download models wget https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-cpu.zip diff --git a/projects/mmpose4aigc/mmpose_style_skeleton.sh b/projects/mmpose4aigc/mmpose_style_skeleton.sh index e8c07bef70..afb03ecfc7 100644 --- a/projects/mmpose4aigc/mmpose_style_skeleton.sh +++ b/projects/mmpose4aigc/mmpose_style_skeleton.sh @@ -1,17 +1,17 @@ #!/bin/bash # Copyright (c) OpenMMLab. All rights reserved. -WORKSPACE=mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1/sdk/ +WORKSPACE=mmdeploy-1.0.0-linux-x86_64-cxx11abi export LD_LIBRARY_PATH=${WORKSPACE}/lib:${WORKSPACE}/thirdparty/onnxruntime/lib:$LD_LIBRARY_PATH INPUT_IMAGE=$1 -mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1/sdk/bin/pose_tracker \ - mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1//rtmpose-ort/rtmdet-nano \ - mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1//rtmpose-ort/rtmpose-m \ +${WORKSPACE}/bin/pose_tracker \ + ${WORKSPACE}/rtmpose-ort/rtmdet-nano \ + ${WORKSPACE}/rtmpose-ort/rtmpose-m \ $INPUT_IMAGE \ --background black \ - --skeleton mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1//rtmpose-ort/t2i-adapter_skeleton.txt \ + --skeleton ${WORKSPACE}/rtmpose-ort/t2i-adapter_skeleton.txt \ --output ./skeleton_res.jpg \ --pose_kpt_thr 0.4 \ --show -1 diff --git a/projects/mmpose4aigc/openpose_visualization.py b/projects/mmpose4aigc/openpose_visualization.py index b7fde6eae0..b634d07757 100644 --- a/projects/mmpose4aigc/openpose_visualization.py +++ b/projects/mmpose4aigc/openpose_visualization.py @@ -43,7 +43,9 @@ def mmpose_to_openpose_visualization(args, img_path, detector, pose_estimator): """Visualize predicted keypoints of one image in openpose format.""" # predict bbox - init_default_scope(detector.cfg.get('default_scope', 'mmdet')) + scope = detector.cfg.get('default_scope', 'mmdet') + if scope is not None: + init_default_scope(scope) det_result = inference_detector(detector, img_path) pred_instance = det_result.pred_instances.cpu().numpy() bboxes = np.concatenate( diff --git a/projects/rtmpose/README.md b/projects/rtmpose/README.md index cd1477643b..dc5b0dbe23 100644 --- a/projects/rtmpose/README.md +++ b/projects/rtmpose/README.md @@ -1,5 +1,5 @@
- +
# RTMPose: Real-Time Multi-Person Pose Estimation toolkit based on MMPose @@ -8,12 +8,6 @@
-[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/rtmpose-real-time-multi-person-pose/2d-human-pose-estimation-on-coco-wholebody-1)](https://paperswithcode.com/sota/2d-human-pose-estimation-on-coco-wholebody-1?p=rtmpose-real-time-multi-person-pose) - -
- -
- English | [简体中文](README_CN.md)
@@ -24,7 +18,7 @@ ______________________________________________________________________ Recent studies on 2D pose estimation have achieved excellent performance on public benchmarks, yet its application in the industrial community still suffers from heavy model parameters and high latency. In order to bridge this gap, we empirically study five aspects that affect the performance of multi-person pose estimation algorithms: paradigm, backbone network, localization algorithm, training strategy, and deployment inference, and present a high-performance real-time multi-person pose estimation framework, **RTMPose**, based on MMPose. -Our RTMPose-m achieves **75.8% AP** on COCO with **90+ FPS** on an Intel i7-11700 CPU and **430+ FPS** on an NVIDIA GTX 1660 Ti GPU, and RTMPose-l achieves **67.0% AP** on COCO-WholeBody with **130+ FPS**. +Our RTMPose-m achieves **75.8% AP** on COCO with **90+ FPS** on an Intel i7-11700 CPU and **430+ FPS** on an NVIDIA GTX 1660 Ti GPU. To further evaluate RTMPose's capability in critical real-time applications, we also report the performance after deploying on the mobile device. Our RTMPose-s achieves **72.2% AP** on COCO with **70+ FPS** on a Snapdragon 865 chip, outperforming existing open-source libraries. With the help of MMDeploy, our project supports various platforms like CPU, GPU, NVIDIA Jetson, and mobile devices and multiple inference backends such as ONNXRuntime, TensorRT, ncnn, etc. @@ -50,6 +44,11 @@ ______________________________________________________________________ ## 🥳 🚀 What's New [🔝](#-table-of-contents) +- Jun. 2023: + - Release 26-keypoint Body models trained on combined datasets. +- May. 2023: + - Add [code examples](./examples/) of RTMPose. + - Release Hand, Face, Body models trained on combined datasets. - Mar. 2023: RTMPose is released. RTMPose-m runs at 430+ FPS and achieves 75.8 mAP on COCO val set. ## 📖 Introduction [🔝](#-table-of-contents) @@ -59,10 +58,10 @@ ______________________________________________________________________
- +
- +
### ✨ Major Features @@ -136,14 +135,14 @@ Feel free to join our community group for more help: - cuDNN 8.3.2 - CUDA 11.3 -| Detection Config | Pose Config | Input Size
(Det/Pose) | Model AP
(COCO) | Pipeline AP
(COCO) | Params (M)
(Det/Pose) | Flops (G)
(Det/Pose) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | Download | -| :------------------------------------------------------------------ | :---------------------------------------------------------------------------- | :---------------------------: | :---------------------: | :------------------------: | :---------------------------: | :--------------------------: | :--------------------------------: | :---------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-t](./rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
67.1 | 64.4 | 0.99
3.34 | 0.31
0.36 | 12.403 | 2.467 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth) | -| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-s](./rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
71.1 | 68.5 | 0.99
5.47 | 0.31
0.68 | 16.658 | 2.730 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth) | -| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
75.3 | 73.2 | 0.99
13.59 | 0.31
1.93 | 26.613 | 4.312 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | -| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
76.3 | 74.2 | 0.99
27.66 | 0.31
4.16 | 36.311 | 4.644 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | -| [RTMDet-m](./rtmdet/person/rtmdet_m_640-8xb32_coco-person.py) | [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 640x640
256x192 | 62.5
75.3 | 75.7 | 24.66
13.59 | 38.95
1.93 | - | 6.923 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_m_8xb32-100e_coco-obj365-person-235e8209.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | -| [RTMDet-m](./rtmdet/person/rtmdet_m_640-8xb32_coco-person.py) | [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 640x640
256x192 | 62.5
76.3 | 76.6 | 24.66
27.66 | 38.95
4.16 | - | 7.204 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_m_8xb32-100e_coco-obj365-person-235e8209.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | +| Detection Config | Pose Config | Input Size
(Det/Pose) | Model AP
(COCO) | Pipeline AP
(COCO) | Params (M)
(Det/Pose) | Flops (G)
(Det/Pose) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | Download | +| :------------------------------------------------------------------ | :---------------------------------------------------------------------------- | :---------------------------: | :---------------------: | :------------------------: | :---------------------------: | :--------------------------: | :--------------------------------: | :---------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-t](./rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
67.1 | 64.4 | 0.99
3.34 | 0.31
0.36 | 12.403 | 2.467 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth) | +| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-s](./rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
71.1 | 68.5 | 0.99
5.47 | 0.31
0.68 | 16.658 | 2.730 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth) | +| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
75.3 | 73.2 | 0.99
13.59 | 0.31
1.93 | 26.613 | 4.312 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | +| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
76.3 | 74.2 | 0.99
27.66 | 0.31
4.16 | 36.311 | 4.644 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | +| [RTMDet-m](./rtmdet/person/rtmdet_m_640-8xb32_coco-person.py) | [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 640x640
256x192 | 62.5
75.3 | 75.7 | 24.66
13.59 | 38.95
1.93 | - | 6.923 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_m_8xb32-100e_coco-obj365-person-235e8209.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | +| [RTMDet-m](./rtmdet/person/rtmdet_m_640-8xb32_coco-person.py) | [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 640x640
256x192 | 62.5
76.3 | 76.6 | 24.66
27.66 | 38.95
4.16 | - | 7.204 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_m_8xb32-100e_coco-obj365-person-235e8209.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | ## 📊 Model Zoo [🔝](#-table-of-contents) @@ -155,16 +154,67 @@ Feel free to join our community group for more help: - Inference speed measured on more hardware platforms can refer to [Benchmark](./benchmark/README.md) - If you have datasets you would like us to support, feel free to [contact us](https://docs.google.com/forms/d/e/1FAIpQLSfzwWr3eNlDzhU98qzk2Eph44Zio6hi5r0iSwfO9wSARkHdWg/viewform?usp=sf_link)/[联系我们](https://uua478.fanqier.cn/f/xxmynrki). -### Body 2d (17 Keypoints) - -| Config | Input Size | AP
(COCO) | Params(M) | FLOPS(G) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | ncnn-FP16-Latency(ms)
(Snapdragon 865) | Logs | Download | -| :---------: | :--------: | :---------------: | :-------: | :------: | :--------------------------------: | :---------------------------------------: | :--------------------------------------------: | :--------: | :------------: | -| [RTMPose-t](./rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py) | 256x192 | 68.5 | 3.34 | 0.36 | 3.20 | 1.06 | 9.02 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth) | -| [RTMPose-s](./rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py) | 256x192 | 72.2 | 5.47 | 0.68 | 4.48 | 1.39 | 13.89 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth) | -| [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 256x192 | 75.8 | 13.59 | 1.93 | 11.06 | 2.29 | 26.44 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | -| [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 256x192 | 76.5 | 27.66 | 4.16 | 18.85 | 3.46 | 45.37 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | -| [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-384x288.py) | 384x288 | 77.0 | 13.72 | 4.33 | 24.78 | 3.66 | - | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-384x288-a62a0b32_20230228.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-384x288-a62a0b32_20230228.pth) | -| [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-384x288.py) | 384x288 | 77.3 | 27.79 | 9.35 | - | 6.05 | - | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-384x288-97d6cb0f_20230228.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-384x288-97d6cb0f_20230228.pth) | +### Body 2d + +#### 17 Keypoints + +- Keypoints are defined as [COCO](http://cocodataset.org/). For details please refer to the [meta info](/configs/_base_/datasets/coco.py). +- + +
+AIC+COCO + +| Config | Input Size | AP
(COCO) | PCK@0.1
(Body8) | AUC
(Body8) | Params
(M) | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | ncnn-FP16-Latency
(ms)
(Snapdragon 865) | Download | +| :---------------------------------------------------------------------------: | :--------: | :---------------: | :---------------------: | :-----------------: | :----------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :-----------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------: | +| [RTMPose-t](./rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py) | 256x192 | 68.5 | 91.28 | 63.38 | 3.34 | 0.36 | 3.20 | 1.06 | 9.02 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth) | +| [RTMPose-s](./rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py) | 256x192 | 72.2 | 92.95 | 66.19 | 5.47 | 0.68 | 4.48 | 1.39 | 13.89 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth) | +| [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 256x192 | 75.8 | 94.13 | 68.53 | 13.59 | 1.93 | 11.06 | 2.29 | 26.44 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | +| [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 256x192 | 76.5 | 94.35 | 68.98 | 27.66 | 4.16 | 18.85 | 3.46 | 45.37 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | +| [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-384x288.py) | 384x288 | 77.0 | 94.32 | 69.85 | 13.72 | 4.33 | 24.78 | 3.66 | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-384x288-a62a0b32_20230228.pth) | +| [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-384x288.py) | 384x288 | 77.3 | 94.54 | 70.14 | 27.79 | 9.35 | - | 6.05 | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-384x288-97d6cb0f_20230228.pth) | + +
+ +
+Body8 + +- `*` denotes model trained on 7 public datasets: + - [AI Challenger](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#aic) + - [MS COCO](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#coco) + - [CrowdPose](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#crowdpose) + - [MPII](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#mpii) + - [sub-JHMDB](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#sub-jhmdb-dataset) + - [Halpe](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_wholebody_keypoint.html#halpe) + - [PoseTrack18](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#posetrack18) +- `Body8` denotes the addition of the [OCHuman](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#ochuman) dataset, in addition to the 7 datasets mentioned above, for evaluation. + +| Config | Input Size | AP
(COCO) | PCK@0.1
(Body8) | AUC
(Body8) | Params
(M) | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | ncnn-FP16-Latency
(ms)
(Snapdragon 865) | Download | +| :-----------------------------------------------------------------------------: | :--------: | :---------------: | :---------------------: | :-----------------: | :----------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :-----------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------: | +| [RTMPose-t\*](./rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py) | 256x192 | 65.9 | 91.44 | 63.18 | 3.34 | 0.36 | 3.20 | 1.06 | 9.02 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_simcc-body7_pt-body7_420e-256x192-026a1439_20230504.pth) | +| [RTMPose-s\*](./rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py) | 256x192 | 69.7 | 92.45 | 65.15 | 5.47 | 0.68 | 4.48 | 1.39 | 13.89 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-body7_pt-body7_420e-256x192-acd4a1ef_20230504.pth) | +| [RTMPose-m\*](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 256x192 | 74.9 | 94.25 | 68.59 | 13.59 | 1.93 | 11.06 | 2.29 | 26.44 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7_420e-256x192-e48f03d0_20230504.pth) | +| [RTMPose-l\*](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 256x192 | 76.7 | 95.08 | 70.14 | 27.66 | 4.16 | 18.85 | 3.46 | 45.37 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-256x192-4dba18fc_20230504.pth) | +| [RTMPose-m\*](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-384x288.py) | 384x288 | 76.6 | 94.64 | 70.38 | 13.72 | 4.33 | 24.78 | 3.66 | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7_420e-384x288-65e718c4_20230504.pth) | +| [RTMPose-l\*](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-384x288.py) | 384x288 | 78.3 | 95.36 | 71.58 | 27.79 | 9.35 | - | 6.05 | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-384x288-3f5a1437_20230504.pth) | +| [RTMPose-x\*](./rtmpose/body_2d_keypoint/rtmpose-x_8xb256-700e_coco-384x288.py) | 384x288 | 78.8 | - | - | 49.43 | 17.22 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-x_simcc-body7_pt-body7_700e-384x288-71d7b7e9_20230629.pth) | + +
+ +#### 26 Keypoints + +- Keypoints are defined as [Halpe26](https://github.com/Fang-Haoshu/Halpe-FullBody/). For details please refer to the [meta info](/configs/_base_/datasets/halpe26.py). +- +- Models are trained and evaluated on `Body8`. + +| Config | Input Size | PCK@0.1
(Body8) | AUC
(Body8) | Params(M) | FLOPS(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | ncnn-FP16-Latency
(ms)
(Snapdragon 865) | Download | +| :---------------------------------------------------------------------------------------: | :--------: | :---------------------: | :-----------------: | :-------: | :------: | :-----------------------------------------: | :------------------------------------------------: | :-----------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------: | +| [RTMPose-t\*](./rtmpose/body_2d_keypoint/rtmpose-t_8xb1024-700e_body8-halpe26-256x192.py) | 256x192 | 91.89 | 66.35 | 3.51 | 0.37 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_simcc-body7_pt-body7-halpe26_700e-256x192-6020f8a6_20230605.pth) | +| [RTMPose-s\*](./rtmpose/body_2d_keypoint/rtmpose-s_8xb1024-700e_body8-halpe26-256x192.py) | 256x192 | 93.01 | 68.62 | 5.70 | 0.70 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-body7_pt-body7-halpe26_700e-256x192-7f134165_20230605.pth) | +| [RTMPose-m\*](./rtmpose/body_2d_keypoint/rtmpose-m_8xb512-700e_body8-halpe26-256x192.py) | 256x192 | 94.75 | 71.91 | 13.93 | 1.95 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7-halpe26_700e-256x192-4d3e73dd_20230605.pth) | +| [RTMPose-l\*](./rtmpose/body_2d_keypoint/rtmpose-l_8xb512-700e_body8-halpe26-256x192.py) | 256x192 | 95.37 | 73.19 | 28.11 | 4.19 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7-halpe26_700e-256x192-2abb7558_20230605.pth) | +| [RTMPose-m\*](./rtmpose/body_2d_keypoint/rtmpose-m_8xb512-700e_body8-halpe26-384x288.py) | 384x288 | 95.15 | 73.56 | 14.06 | 4.37 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7-halpe26_700e-384x288-89e6428b_20230605.pth) | +| [RTMPose-l\*](./rtmpose/body_2d_keypoint/rtmpose-l_8xb512-700e_body8-halpe26-384x288.py) | 384x288 | 95.56 | 74.38 | 28.24 | 9.40 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7-halpe26_700e-384x288-734182ce_20230605.pth) | +| [RTMPose-x\*](./rtmpose/body_2d_keypoint/rtmpose-x_8xb256-700e_body8-halpe26-384x288.py) | 384x288 | 95.74 | 74.82 | 50.00 | 17.29 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-x_simcc-body7_pt-body7-halpe26_700e-384x288-7fb6e239_20230606.pth) | #### Model Pruning @@ -172,53 +222,134 @@ Feel free to join our community group for more help: - Model pruning is supported by [MMRazor](https://github.com/open-mmlab/mmrazor) -| Config | Input Size | AP
(COCO) | Params(M) | FLOPS(G) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | ncnn-FP16-Latency(ms)
(Snapdragon 865) | Logs | Download | -| :---------: | :--------: | :---------------: | :-------: | :------: | :--------------------------------: | :---------------------------------------: | :--------------------------------------------: | :--------: | :------------: | -| RTMPose-s-aic-coco-pruned | 256x192 | 69.4 | 3.43 | 0.35 | - | - | - | [log](https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.json) | [model](https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.pth) | +| Config | Input Size | AP
(COCO) | Params
(M) | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | ncnn-FP16-Latency
(ms)
(Snapdragon 865) | Download | +| :-----------------------: | :--------: | :---------------: | :----------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :-----------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------: | +| RTMPose-s-aic-coco-pruned | 256x192 | 69.4 | 3.43 | 0.35 | - | - | - | [Model](https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.pth) | For more details, please refer to [GroupFisher Pruning for RTMPose](./rtmpose/pruning/README.md). ### WholeBody 2d (133 Keypoints) -| Config | Input Size | Whole AP | Whole AR | FLOPS(G) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | Logs | Download | -| :----------------------------- | :--------: | :------: | :------: | :------: | :--------------------------------: | :---------------------------------------: | :--------------------------: | :-------------------------------: | -| [RTMPose-m](./rtmpose/wholebody_2d_keypoint/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py) | 256x192 | 60.4 | 66.7 | 2.22 | 13.50 | 4.00 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.pth) | -| [RTMPose-l](./rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py) | 256x192 | 63.2 | 69.4 | 4.52 | 23.41 | 5.67 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-256x192-6f206314_20230124.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-256x192-6f206314_20230124.pth) | -| [RTMPose-l](./rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py) | 384x288 | 67.0 | 72.3 | 10.07 | 44.58 | 7.68 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.pth) | +- Keypoints are defined as [COCO-WholeBody](https://github.com/jin-s13/COCO-WholeBody/). For details please refer to the [meta info](/configs/_base_/datasets/coco_wholebody.py). +- + +| Config | Input Size | Whole AP | Whole AR | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | Download | +| :------------------------------ | :--------: | :------: | :------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :-------------------------------: | +| [RTMPose-m](./rtmpose/wholebody_2d_keypoint/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py) | 256x192 | 58.2 | 67.4 | 2.22 | 13.50 | 4.00 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.pth) | +| [RTMPose-l](./rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py) | 256x192 | 61.1 | 70.0 | 4.52 | 23.41 | 5.67 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-256x192-6f206314_20230124.pth) | +| [RTMPose-l](./rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py) | 384x288 | 64.8 | 73.0 | 10.07 | 44.58 | 7.68 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.pth) | +| [RTMPose-x](./rtmpose/wholebody_2d_keypoint/rtmpose-x_8xb32-270e_coco-wholebody-384x288.py) | 384x288 | 65.3 | 73.3 | 18.1 | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-x_simcc-coco-wholebody_pt-body7_270e-384x288-401dfc90_20230629.pth) | ### Animal 2d (17 Keypoints) -| Config | Input Size | AP
(AP10K) | FLOPS(G) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | Logs | Download | -| :---------------------------: | :--------: | :----------------: | :------: | :--------------------------------: | :---------------------------------------: | :--------------------------: | :------------------------------: | -| [RTMPose-m](./rtmpose/animal_2d_keypoint/rtmpose-m_8xb64-210e_ap10k-256x256.py) | 256x256 | 72.2 | 2.57 | 14.157 | 2.404 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-ap10k_pt-aic-coco_210e-256x256-7a041aa1_20230206.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-ap10k_pt-aic-coco_210e-256x256-7a041aa1_20230206.pth) | +- Keypoints are defined as [AP-10K](https://github.com/AlexTheBad/AP-10K/). For details please refer to the [meta info](/configs/_base_/datasets/ap10k.py). +- -### Face 2d +| Config | Input Size | AP
(AP10K) | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | Download | +| :----------------------------: | :--------: | :----------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :------------------------------: | +| [RTMPose-m](./rtmpose/animal_2d_keypoint/rtmpose-m_8xb64-210e_ap10k-256x256.py) | 256x256 | 72.2 | 2.57 | 14.157 | 2.404 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-ap10k_pt-aic-coco_210e-256x256-7a041aa1_20230206.pth) | -Coming soon +### Face 2d (106 Keypoints) -### Hand 2d +- Keypoints are defined as [LaPa](https://github.com/JDAI-CV/lapa-dataset). For details please refer to the [meta info](/configs/_base_/datasets/lapa.py). +- -Coming soon +
+Face6 -### Pretrained Models +- `Face6` and `*` denote model trained on 6 public datasets: + - [COCO-Wholebody-Face](https://github.com/jin-s13/COCO-WholeBody/) + - [WFLW](https://wywu.github.io/projects/LAB/WFLW.html) + - [300W](https://ibug.doc.ic.ac.uk/resources/300-W/) + - [COFW](http://www.vision.caltech.edu/xpburgos/ICCV13/) + - [Halpe](https://github.com/Fang-Haoshu/Halpe-FullBody/) + - [LaPa](https://github.com/JDAI-CV/lapa-dataset) -We provide the UDP pretraining configs of the CSPNeXt backbone. Find more details in the [pretrain_cspnext_udp folder](./rtmpose/pretrain_cspnext_udp/). +| Config | Input Size | NME
(LaPa) | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | Download | +| :----------------------------: | :--------: | :----------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :------------------------------: | +| [RTMPose-t\*](./rtmpose/face_2d_keypoint/rtmpose-t_8xb256-120e_lapa-256x256.py) | 256x256 | 1.67 | 0.652 | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_simcc-face6_pt-in1k_120e-256x256-df79d9a5_20230529.pth) | +| [RTMPose-s\*](./rtmpose/face_2d_keypoint/rtmpose-s_8xb256-120e_lapa-256x256.py) | 256x256 | 1.59 | 1.119 | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-face6_pt-in1k_120e-256x256-d779fdef_20230529.pth) | +| [RTMPose-m\*](./rtmpose/face_2d_keypoint/rtmpose-m_8xb256-120e_lapa-256x256.py) | 256x256 | 1.44 | 2.852 | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-face6_pt-in1k_120e-256x256-72a37400_20230529.pth) | + +
+ +### Hand 2d (21 Keypoints) + +- Keypoints are defined as [COCO-WholeBody](https://github.com/jin-s13/COCO-WholeBody/). For details please refer to the [meta info](/configs/_base_/datasets/coco_wholebody_hand.py). +- -| Model | Input Size | Params(M) | Flops(G) | AP
(GT) | AR
(GT) | Download | -| :----------: | :--------: | :-------: | :------: | :-------------: | :-------------: | :-----------------------------------------------------------------------------------------------------------------------------: | -| CSPNeXt-tiny | 256x192 | 6.03 | 1.43 | 65.5 | 68.9 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth) | -| CSPNeXt-s | 256x192 | 8.58 | 1.78 | 70.0 | 73.3 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth) | -| CSPNeXt-m | 256x192 | 13.05 | 3.06 | 74.8 | 77.7 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth) | -| CSPNeXt-l | 256x192 | 32.44 | 5.33 | 77.2 | 79.9 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth) | +| Detection Config | Input Size | Model AP
(OneHand10K) | Flops
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | Download | +| :---------------------------: | :--------: | :---------------------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :--------------------: | +| [RTMDet-nano
(alpha version)](./rtmdet/hand/rtmdet_nano_320-8xb32_hand.py) | 320x320 | 76.0 | 0.31 | - | - | [Det Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmdet_nano_8xb32-300e_hand-267f9c8f.pth) | -We also provide the ImageNet classification pre-trained weights of the CSPNeXt backbone. Find more details in [RTMDet](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/rtmdet/README.md#classification). +
+Hand5 -| Model | Input Size | Params(M) | Flops(G) | Top-1 (%) | Top-5 (%) | Download | -| :----------: | :--------: | :-------: | :------: | :-------: | :-------: | :---------------------------------------------------------------------------------------------------------------------------------: | -| CSPNeXt-tiny | 224x224 | 2.73 | 0.34 | 69.44 | 89.45 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-tiny_imagenet_600e-3a2dd350.pth) | -| CSPNeXt-s | 224x224 | 4.89 | 0.66 | 74.41 | 92.23 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-s_imagenet_600e-ea671761.pth) | -| CSPNeXt-m | 224x224 | 13.05 | 1.93 | 79.27 | 94.79 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-m_8xb256-rsb-a1-600e_in1k-ecb3bbd9.pth) | -| CSPNeXt-l | 224x224 | 27.16 | 4.19 | 81.30 | 95.62 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-l_8xb256-rsb-a1-600e_in1k-6a760974.pth) | +- `Hand5` and `*` denote model trained on 5 public datasets: + - [COCO-Wholebody-Hand](https://github.com/jin-s13/COCO-WholeBody/) + - [OneHand10K](https://www.yangangwang.com/papers/WANG-MCC-2018-10.html) + - [FreiHand2d](https://lmb.informatik.uni-freiburg.de/projects/freihand/) + - [RHD2d](https://lmb.informatik.uni-freiburg.de/resources/datasets/RenderedHandposeDataset.en.html) + - [Halpe](https://github.com/Fang-Haoshu/Halpe-FullBody/) + +| Config | Input Size | PCK@0.2
(COCO-Wholebody-Hand) | PCK@0.2
(Hand5) | AUC
(Hand5) | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | Download | +| :-------------------------------------------------------------------------------------------------------------------: | :--------: | :-----------------------------------: | :---------------------: | :-----------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------: | +| [RTMPose-m\*
(alpha version)](./rtmpose/hand_2d_keypoint/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py) | 256x256 | 81.5 | 96.4 | 83.9 | 2.581 | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-hand5_pt-aic-coco_210e-256x256-74fb594_20230320.pth) | + +
+ +### Pretrained Models + +We provide the UDP pretraining configs of the CSPNeXt backbone. Find more details in the [pretrain_cspnext_udp folder](./rtmpose/pretrain_cspnext_udp/). + +
+AIC+COCO + +| Model | Input Size | Params
(M) | Flops
(G) | AP
(GT) | AR
(GT) | Download | +| :----------: | :--------: | :----------------: | :---------------: | :-------------: | :-------------: | :---------------------------------------------------------------------------------------------------------------: | +| CSPNeXt-tiny | 256x192 | 6.03 | 1.43 | 65.5 | 68.9 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth) | +| CSPNeXt-s | 256x192 | 8.58 | 1.78 | 70.0 | 73.3 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth) | +| CSPNeXt-m | 256x192 | 17.53 | 3.05 | 74.8 | 77.7 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth) | +| CSPNeXt-l | 256x192 | 32.44 | 5.32 | 77.2 | 79.9 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth) | + +
+ +
+Body8 + +- `*` denotes model trained on 7 public datasets: + - [AI Challenger](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#aic) + - [MS COCO](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#coco) + - [CrowdPose](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#crowdpose) + - [MPII](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#mpii) + - [sub-JHMDB](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#sub-jhmdb-dataset) + - [Halpe](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_wholebody_keypoint.html#halpe) + - [PoseTrack18](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#posetrack18) +- `Body8` denotes the addition of the [OCHuman](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#ochuman) dataset, in addition to the 7 datasets mentioned above, for evaluation. + +| Model | Input Size | Params
(M) | Flops
(G) | AP
(COCO) | PCK@0.2
(Body8) | AUC
(Body8) | Download | +| :------------: | :--------: | :----------------: | :---------------: | :---------------: | :---------------------: | :-----------------: | :--------------------------------------------------------------------------------: | +| CSPNeXt-tiny\* | 256x192 | 6.03 | 1.43 | 65.9 | 96.34 | 63.80 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-tiny_udp-body7_210e-256x192-a3775292_20230504.pth) | +| CSPNeXt-s\* | 256x192 | 8.58 | 1.78 | 68.7 | 96.59 | 64.92 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-s_udp-body7_210e-256x192-8c9ccbdb_20230504.pth) | +| CSPNeXt-m\* | 256x192 | 17.53 | 3.05 | 73.7 | 97.42 | 68.19 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-body7_210e-256x192-e0c9327b_20230504.pth) | +| CSPNeXt-l\* | 256x192 | 32.44 | 5.32 | 75.7 | 97.76 | 69.57 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-l_udp-body7_210e-256x192-5e9558ef_20230504.pth) | +| CSPNeXt-m\* | 384x288 | 17.53 | 6.86 | 75.8 | 97.60 | 70.18 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-body7_210e-384x288-b9bc2b57_20230504.pth) | +| CSPNeXt-l\* | 384x288 | 32.44 | 11.96 | 77.2 | 97.89 | 71.23 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-l_udp-body7_210e-384x288-b15bc30d_20230504.pth) | +| CSPNeXt-x\* | 384x288 | 54.92 | 19.96 | 78.1 | 98.00 | 71.79 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-x_udp-body7_210e-384x288-d28b58e6_20230529.pth) | + +
+ +#### ImageNet + +We also provide the ImageNet classification pre-trained weights of the CSPNeXt backbone. Find more details in [RTMDet](https://github.com/open-mmlab/mmdetection/blob/latest/configs/rtmdet/README.md#classification). + +| Model | Input Size | Params
(M) | Flops
(G) | Top-1 (%) | Top-5 (%) | Download | +| :----------: | :--------: | :----------------: | :---------------: | :-------: | :-------: | :---------------------------------------------------------------------------------------------------------------------------: | +| CSPNeXt-tiny | 224x224 | 2.73 | 0.34 | 69.44 | 89.45 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-tiny_imagenet_600e-3a2dd350.pth) | +| CSPNeXt-s | 224x224 | 4.89 | 0.66 | 74.41 | 92.23 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-s_imagenet_600e-ea671761.pth) | +| CSPNeXt-m | 224x224 | 13.05 | 1.93 | 79.27 | 94.79 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-m_8xb256-rsb-a1-600e_in1k-ecb3bbd9.pth) | +| CSPNeXt-l | 224x224 | 27.16 | 4.19 | 81.30 | 95.62 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-l_8xb256-rsb-a1-600e_in1k-6a760974.pth) | +| CSPNeXt-x | 224x224 | 48.85 | 7.76 | 82.10 | 95.69 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-x_8xb256-rsb-a1-600e_in1k-b3f78edd.pth) | ## 👀 Visualization [🔝](#-table-of-contents) @@ -231,12 +362,53 @@ We also provide the ImageNet classification pre-trained weights of the CSPNeXt b We provide two appoaches to try RTMPose: -- Pre-compiled MMDeploy SDK (Recommended) - MMPose demo scripts +- Pre-compiled MMDeploy SDK (Recommend, 6-10 times faster) + +### MMPose demo scripts + +MMPose provides demo scripts to conduct [inference with existing models](https://mmpose.readthedocs.io/en/latest/user_guides/inference.html). + +**Note:** + +- Inferencing with Pytorch can not reach the maximum speed of RTMPose, just for verification. +- Model file can be either a local path or a download link + +```shell +# go to the mmpose folder +cd ${PATH_TO_MMPOSE} + +# inference with rtmdet +python demo/topdown_demo_with_mmdet.py \ + projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ + projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ + --input {YOUR_TEST_IMG_or_VIDEO} \ + --show + +# inference with webcam +python demo/topdown_demo_with_mmdet.py \ + projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ + projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ + --input webcam \ + --show +``` + +Result is as follows: + +![topdown_inference_with_rtmdet](https://user-images.githubusercontent.com/13503330/220005020-06bdf37f-6817-4681-a2c8-9dd55e4fbf1e.png) ### Pre-compiled MMDeploy SDK (Recommended) -MMDeploy provides a precompiled SDK for Pipeline reasoning on RTMPose projects, where the model used for reasoning is the SDK version. For the tutorial of exporting the SDK version model, see [SDK Reasoning](#%EF%B8%8F-step3-inference-with-sdk), and for detailed parameter settings of inference, see [Pipeline Reasoning](#-step4-pipeline-inference). +MMDeploy provides a precompiled SDK for Pipeline reasoning on RTMPose projects, where the model used for reasoning is the SDK version. + +- All models must by exported by `tools/deploy.py` before PoseTracker can be used for inference. +- For the tutorial of exporting the SDK version model, see [SDK Reasoning](#%EF%B8%8F-step3-inference-with-sdk), and for detailed parameter settings of inference, see [Pipeline Reasoning](#-step4-pipeline-inference). +- Exported SDK models (ONNX, TRT, ncnn, etc.) can be downloaded from [OpenMMLab Deploee](https://platform.openmmlab.com/deploee). +- You can also convert `.pth` models into SDK [online](https://platform.openmmlab.com/deploee/task-convert-list). #### Linux @@ -245,62 +417,133 @@ Env Requirements: - GCC >= 7.5 - cmake >= 3.20 +##### Python Inference + +1. Install mmdeploy_runtime or mmdeploy_runtime_gpu + +```shell +# for onnxruntime +pip install mmdeploy-runtime + +# for onnxruntime-gpu / tensorrt +pip install mmdeploy-runtime-gpu +``` + +2. Download Pre-compiled files. + +```shell +# onnxruntime +# for ubuntu +wget -c https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64-cxx11abi.tar.gz +# unzip then add third party runtime libraries to the PATH + +# for centos7 and lower +wget -c https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64.tar.gz +# unzip then add third party runtime libraries to the PATH + +# onnxruntime-gpu / tensorrt +# for ubuntu +wget -c https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64-cxx11abi-cuda11.3.tar.gz +# unzip then add third party runtime libraries to the PATH + +# for centos7 and lower +wget -c https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64-cuda11.3.tar.gz +# unzip then add third party runtime libraries to the PATH +``` + +3. Download the sdk models and unzip to `./example/python`. (If you need other models, please export sdk models refer to [SDK Reasoning](#%EF%B8%8F-step3-inference-with-sdk)) + +```shell +# rtmdet-nano + rtmpose-m for cpu sdk +wget https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-cpu.zip + +unzip rtmpose-cpu.zip +``` + +4. Inference with `pose_tracker.py`: + +```shell +# go to ./example/python + +# Please pass the folder of the model, not the model file +# Format: +# python pose_tracker.py cpu {det work-dir} {pose work-dir} {your_video.mp4} + +# Example: +python pose_tracker.py cpu rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_video.mp4 + +# webcam +python pose_tracker.py cpu rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ 0 +``` + ##### ONNX ```shell # Download pre-compiled files -wget https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0rc3/mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1.tar.gz +wget https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64-cxx11abi.tar.gz # Unzip files -tar -xzvf mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1.tar.gz +tar -xzvf mmdeploy-1.0.0-linux-x86_64-cxx11abi.tar.gz # Go to the sdk folder -cd mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1/sdk +cd mmdeploy-1.0.0-linux-x86_64-cxx11abi # Init environment -source env.sh +source set_env.sh # If opencv 3+ is not installed on your system, execute the following command. # If it is installed, skip this command -bash opencv.sh +bash install_opencv.sh # Compile executable programs -bash build.sh +bash build_sdk.sh -# inference for an image -./bin/det_pose {det work-dir} {pose work-dir} {your_img.jpg} --device cpu +# Inference for an image +# Please pass the folder of the model, not the model file +./bin/det_pose rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_img.jpg --device cpu -# inference for a video -./bin/pose_tracker {det work-dir} {pose work-dir} {your_video.mp4} --device cpu +# Inference for a video +# Please pass the folder of the model, not the model file +./bin/pose_tracker rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_video.mp4 --device cpu + +# Inference using webcam +# Please pass the folder of the model, not the model file +./bin/pose_tracker rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ 0 --device cpu ``` ##### TensorRT ```shell # Download pre-compiled files -wget https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0rc3/mmdeploy-1.0.0rc3-linux-x86_64-cuda11.1-tensorrt8.2.3.0.tar.gz +wget https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64-cxx11abi-cuda11.3.tar.gz # Unzip files -tar -xzvf mmdeploy-1.0.0rc3-linux-x86_64-cuda11.1-tensorrt8.2.3.0.tar.gz +tar -xzvf mmdeploy-1.0.0-linux-x86_64-cxx11abi-cuda11.3.tar.gz # Go to the sdk folder -cd mmdeploy-1.0.0rc3-linux-x86_64-cuda11.1-tensorrt8.2.3.0/sdk +cd mmdeploy-1.0.0-linux-x86_64-cxx11abi-cuda11.3 # Init environment -source env.sh +source set_env.sh # If opencv 3+ is not installed on your system, execute the following command. # If it is installed, skip this command -bash opencv.sh +bash install_opencv.sh # Compile executable programs -bash build.sh +bash build_sdk.sh -# inference for an image -./bin/det_pose {det work-dir} {pose work-dir} {your_img.jpg} --device cuda +# Inference for an image +# Please pass the folder of the model, not the model file +./bin/det_pose rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_img.jpg --device cuda -# inference for a video -./bin/pose_tracker {det work-dir} {pose work-dir} {your_video.mp4} --device cuda +# Inference for a video +# Please pass the folder of the model, not the model file +./bin/pose_tracker rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_video.mp4 --device cuda + +# Inference using webcam +# Please pass the folder of the model, not the model file +./bin/pose_tracker rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ 0 --device cuda ``` For details, see [Pipeline Inference](#-step4-pipeline-inference). @@ -309,15 +552,37 @@ For details, see [Pipeline Inference](#-step4-pipeline-inference). ##### Python Inference -1. Download the [pre-compiled SDK](https://github.com/open-mmlab/mmdeploy/releases). -2. Unzip the SDK and go to the `sdk/python` folder. -3. Install `mmdeploy_python` via `.whl` file. -4. Download the [sdk models](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-cpu.zip) and unzip. -5. Inference with `pose_tracker.py`: +1. Install mmdeploy_runtime or mmdeploy_runtime_gpu + +```shell +# for onnxruntime +pip install mmdeploy-runtime +# download [sdk](https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-windows-amd64.zip) add third party runtime libraries to the PATH + +# for onnxruntime-gpu / tensorrt +pip install mmdeploy-runtime-gpu +# download [sdk](https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-windows-amd64-cuda11.3.zip) add third party runtime libraries to the PATH +``` + +2. Download the sdk models and unzip to `./example/python`. (If you need other models, please export sdk models refer to [SDK Reasoning](#%EF%B8%8F-step3-inference-with-sdk)) + +```shell +# rtmdet-nano + rtmpose-m for cpu sdk +wget https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-cpu.zip + +unzip rtmpose-cpu.zip +``` + +3. Inference with `pose_tracker.py`: ```shell -# go to ./sdk/example/python -python pose_tracker.py cpu {det work-dir} {pose work-dir} {your_video.mp4} +# go to ./example/python +# Please pass the folder of the model, not the model file +python pose_tracker.py cpu rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_video.mp4 + +# Inference using webcam +# Please pass the folder of the model, not the model file +python pose_tracker.py cpu rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ 0 ``` ##### Executable Inference @@ -335,14 +600,14 @@ set-ExecutionPolicy RemoteSigned ```shell # in sdk folder: -.\opencv.ps1 +.\install_opencv.ps1 ``` 6. Set environment variables: ```shell # in sdk folder: -.\env.ps1 +. .\set_env.ps1 ``` 7. Compile the SDK: @@ -350,7 +615,7 @@ set-ExecutionPolicy RemoteSigned ```shell # in sdk folder: # (if you installed opencv by .\install_opencv.ps1) -.\build.ps1 +.\build_sdk.ps1 # (if you installed opencv yourself) .\build_sdk.ps1 "path/to/folder/of/OpenCVConfig.cmake" ``` @@ -363,7 +628,11 @@ example\cpp\build\Release ### MMPose demo scripts -MMPose provides demo scripts to conduct [inference with existing models](https://mmpose.readthedocs.io/en/1.x/user_guides/inference.html). +MMPose provides demo scripts to conduct [inference with existing models](https://mmpose.readthedocs.io/en/latest/user_guides/inference.html). + +**Note:** + +- Inferencing with Pytorch can not reach the maximum speed of RTMPose, just for verification. ```shell # go to the mmpose folder @@ -375,7 +644,16 @@ python demo/topdown_demo_with_mmdet.py \ {PATH_TO_CHECKPOINT}/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ {PATH_TO_CHECKPOINT}/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ - --input {YOUR_TEST_IMG_OR_VIDEO} + --input {YOUR_TEST_IMG_or_VIDEO} \ + --show + +# inference with webcam +python demo/topdown_demo_with_mmdet.py \ + projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + {PATH_TO_CHECKPOINT}/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ + projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + {PATH_TO_CHECKPOINT}/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ + --input webcam \ --show ``` @@ -389,7 +667,7 @@ Please refer to [Train and Test](https://mmpose.readthedocs.io/en/latest/user_gu **Tips**: -- RTMPose has `drop_last=True` enabled by default, please accordinally reduce `batch_size` and `base_lr` when your dataset is small. +- Please accordinally reduce `batch_size` and `base_lr` when your dataset is small. - Guidelines to choose a model - m: Recommended and Preferred Use - t/s: For mobile devices with extremely low computing power, or scenarios with stringent inference speed requirements @@ -397,49 +675,48 @@ Please refer to [Train and Test](https://mmpose.readthedocs.io/en/latest/user_gu ## 🏗️ How to Deploy [🔝](#-table-of-contents) -Here is a basic example of deploy RTMPose with [MMDeploy-1.x](https://github.com/open-mmlab/mmdeploy/tree/1.x). +Here is a basic example of deploy RTMPose with [MMDeploy](https://github.com/open-mmlab/mmdeploy/tree/main). + +- Exported SDK models (ONNX, TRT, ncnn, etc.) can be downloaded from [OpenMMLab Deploee](https://platform.openmmlab.com/deploee). +- You can also convert `.pth` models into SDK [online](https://platform.openmmlab.com/deploee/task-convert-list). ### 🧩 Step1. Install MMDeploy -Before starting the deployment, please make sure you install MMPose-1.x and MMDeploy-1.x correctly. +Before starting the deployment, please make sure you install MMPose and MMDeploy correctly. -- Install MMPose-1.x, please refer to the [MMPose-1.x installation guide](https://mmpose.readthedocs.io/en/latest/installation.html). -- Install MMDeploy-1.x, please refer to the [MMDeploy-1.x installation guide](https://mmdeploy.readthedocs.io/en/1.x/get_started.html#installation). +- Install MMPose, please refer to the [MMPose installation guide](https://mmpose.readthedocs.io/en/latest/installation.html). +- Install MMDeploy, please refer to the [MMDeploy installation guide](https://mmdeploy.readthedocs.io/en/latest/get_started.html#installation). Depending on the deployment backend, some backends require compilation of custom operators, so please refer to the corresponding document to ensure the environment is built correctly according to your needs: -- [ONNX RUNTIME SUPPORT](https://mmdeploy.readthedocs.io/en/1.x/05-supported-backends/onnxruntime.html) -- [TENSORRT SUPPORT](https://mmdeploy.readthedocs.io/en/1.x/05-supported-backends/tensorrt.html) -- [OPENVINO SUPPORT](https://mmdeploy.readthedocs.io/en/1.x/05-supported-backends/openvino.html) -- [More](https://github.com/open-mmlab/mmdeploy/tree/1.x/docs/en/05-supported-backends) +- [ONNX RUNTIME SUPPORT](https://mmdeploy.readthedocs.io/en/latest/05-supported-backends/onnxruntime.html) +- [TENSORRT SUPPORT](https://mmdeploy.readthedocs.io/en/latest/05-supported-backends/tensorrt.html) +- [OPENVINO SUPPORT](https://mmdeploy.readthedocs.io/en/latest/05-supported-backends/openvino.html) +- [More](https://github.com/open-mmlab/mmdeploy/tree/main/docs/en/05-supported-backends) ### 🛠️ Step2. Convert Model After the installation, you can enjoy the model deployment journey starting from converting PyTorch model to backend model by running MMDeploy's `tools/deploy.py`. -The detailed model conversion tutorial please refer to the [MMDeploy document](https://mmdeploy.readthedocs.io/en/1.x/02-how-to-run/convert_model.html). Here we only give the example of converting RTMPose. +The detailed model conversion tutorial please refer to the [MMDeploy document](https://mmdeploy.readthedocs.io/en/latest/02-how-to-run/convert_model.html). Here we only give the example of converting RTMPose. Here we take converting RTMDet-nano and RTMPose-m to ONNX/TensorRT as an example. - If you only want to use ONNX, please use: - - [`detection_onnxruntime_static.py`](https://github.com/open-mmlab/mmdeploy/blob/1.x/configs/mmdet/detection/detection_onnxruntime_static.py) for RTMDet. - - [`pose-detection_simcc_onnxruntime_dynamic.py`](https://github.com/open-mmlab/mmdeploy/blob/1.x/configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py) for RTMPose. + - [`detection_onnxruntime_static.py`](https://github.com/open-mmlab/mmdeploy/blob/main/configs/mmdet/detection/detection_onnxruntime_static.py) for RTMDet. + - [`pose-detection_simcc_onnxruntime_dynamic.py`](https://github.com/open-mmlab/mmdeploy/blob/main/configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py) for RTMPose. - If you want to use TensorRT, please use: - - [`detection_tensorrt_static-320x320.py`](https://github.com/open-mmlab/mmdeploy/blob/1.x/configs/mmdet/detection/detection_tensorrt_static-320x320.py) for RTMDet. - - [`pose-detection_simcc_tensorrt_dynamic-256x192.py`](https://github.com/open-mmlab/mmdeploy/blob/1.x/configs/mmpose/pose-detection_simcc_tensorrt_dynamic-256x192.py) for RTMPose. + - [`detection_tensorrt_static-320x320.py`](https://github.com/open-mmlab/mmdeploy/blob/main/configs/mmdet/detection/detection_tensorrt_static-320x320.py) for RTMDet. + - [`pose-detection_simcc_tensorrt_dynamic-256x192.py`](https://github.com/open-mmlab/mmdeploy/blob/main/configs/mmpose/pose-detection_simcc_tensorrt_dynamic-256x192.py) for RTMPose. -If you want to customize the settings in the deployment config for your requirements, please refer to [MMDeploy config tutorial](https://mmdeploy.readthedocs.io/en/1.x/02-how-to-run/write_config.html). +If you want to customize the settings in the deployment config for your requirements, please refer to [MMDeploy config tutorial](https://mmdeploy.readthedocs.io/en/latest/02-how-to-run/write_config.html). In this tutorial, we organize files as follows: -``` +```shell |----mmdeploy |----mmdetection |----mmpose -|----rtmdet_nano -| |----rtmdet_nano.pth -|----rtmpose_m - |----rtmpose_m.pth ``` #### ONNX @@ -449,24 +726,28 @@ In this tutorial, we organize files as follows: cd ${PATH_TO_MMDEPLOY} # run the command to convert RTMDet +# Model file can be either a local path or a download link python tools/deploy.py \ configs/mmdet/detection/detection_onnxruntime_static.py \ - {RTMPOSE_PROJECT}/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ - ../rtmdet_nano/rtmdet_nano.pth \ + ../mmpose/projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ demo/resources/human-pose.jpg \ - --work-dir mmdeploy_models/mmdet/ort \ + --work-dir rtmpose-ort/rtmdet-nano \ --device cpu \ - --show + --show \ + --dump-info # dump sdk info # run the command to convert RTMPose +# Model file can be either a local path or a download link python tools/deploy.py \ configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py \ - {RTMPOSE_PROJECT}/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ - ../rtmpose_m/rtmpose_m.pth \ + ../mmpose/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ demo/resources/human-pose.jpg \ - --work-dir mmdeploy_models/mmpose/ort \ + --work-dir rtmpose-ort/rtmpose-m \ --device cpu \ - --show + --show \ + --dump-info # dump sdk info ``` The converted model file is `{work-dir}/end2end.onnx` by defaults. @@ -478,24 +759,28 @@ The converted model file is `{work-dir}/end2end.onnx` by defaults. cd ${PATH_TO_MMDEPLOY} # run the command to convert RTMDet +# Model file can be either a local path or a download link python tools/deploy.py \ configs/mmdet/detection/detection_tensorrt_static-320x320.py \ - {RTMPOSE_PROJECT}/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ - ../rtmdet_nano/rtmdet_nano.pth \ + ../mmpose/projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ demo/resources/human-pose.jpg \ - --work-dir mmdeploy_models/mmdet/trt \ + --work-dir rtmpose-trt/rtmdet-nano \ --device cuda:0 \ - --show + --show \ + --dump-info # dump sdk info # run the command to convert RTMPose +# Model file can be either a local path or a download link python tools/deploy.py \ configs/mmpose/pose-detection_simcc_tensorrt_dynamic-256x192.py \ - {RTMPOSE_PROJECT}/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ - ../rtmpose_m/rtmpose_m.pth \ + ../mmpose/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ demo/resources/human-pose.jpg \ - --work-dir mmdeploy_models/mmpose/trt \ + --work-dir rtmpose-trt/rtmpose-m \ --device cuda:0 \ - --show + --show \ + --dump-info # dump sdk info ``` The converted model file is `{work-dir}/end2end.engine` by defaults. @@ -521,27 +806,29 @@ backend_config = dict( We provide both Python and C++ inference API with MMDeploy SDK. -To use SDK, you need to dump the required info during converting the model. Just add --dump-info to the model conversion command: +To use SDK, you need to dump the required info during converting the model. Just add --dump-info to the model conversion command. ```shell # RTMDet +# Model file can be either a local path or a download link python tools/deploy.py \ configs/mmdet/detection/detection_onnxruntime_dynamic.py \ - {RTMPOSE_PROJECT}/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ - ../rtmdet_nano/rtmdet_nano.pth \ + ../mmpose/projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ demo/resources/human-pose.jpg \ - --work-dir mmdeploy_models/mmdet/sdk \ + --work-dir rtmpose-ort/rtmdet-nano \ --device cpu \ --show \ --dump-info # dump sdk info # RTMPose +# Model file can be either a local path or a download link python tools/deploy.py \ configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py \ - {RTMPOSE_PROJECT}/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ - ../rtmpose_m/rtmpose_m.pth \ + ../mmpose/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ demo/resources/human-pose.jpg \ - --work-dir mmdeploy_models/mmpose/sdk \ + --work-dir rtmpose-ort/rtmpose-m \ --device cpu \ --show \ --dump-info # dump sdk info @@ -549,8 +836,8 @@ python tools/deploy.py \ After running the command, it will dump 3 json files additionally for the SDK: -``` -|----sdk +```shell +|----{work-dir} |----end2end.onnx # ONNX model |----end2end.engine # TensorRT engine file @@ -569,7 +856,7 @@ import argparse import cv2 import numpy as np -from mmdeploy_python import PoseDetector +from mmdeploy_runtime import PoseDetector def parse_args(): @@ -683,8 +970,8 @@ target_link_libraries(${name} PRIVATE mmdeploy ${OpenCV_LIBS}) #### Other languages -- [C# API Examples](https://github.com/open-mmlab/mmdeploy/tree/1.x/demo/csharp) -- [JAVA API Examples](https://github.com/open-mmlab/mmdeploy/tree/1.x/demo/java) +- [C# API Examples](https://github.com/open-mmlab/mmdeploy/tree/main/demo/csharp) +- [JAVA API Examples](https://github.com/open-mmlab/mmdeploy/tree/main/demo/java) ## 🚀 Step4. Pipeline Inference @@ -697,7 +984,7 @@ If the user has MMDeploy compiled correctly, you will see the `det_pose` executa cd ${PATH_TO_MMDEPLOY}/build/bin/ # inference for an image -./det_pose {det work-dir} {pose work-dir} {your_img.jpg} --device cpu +./det_pose rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_img.jpg --device cpu required arguments: det_model Object detection model path [string] @@ -718,19 +1005,21 @@ optional arguments: #### API Example -- [`det_pose.py`](https://github.com/open-mmlab/mmdeploy/blob/dev-1.x/demo/python/det_pose.py) -- [`det_pose.cxx`](https://github.com/open-mmlab/mmdeploy/blob/dev-1.x/demo/csrc/cpp/det_pose.cxx) +- [`det_pose.py`](https://github.com/open-mmlab/mmdeploy/blob/main/demo/python/det_pose.py) +- [`det_pose.cxx`](https://github.com/open-mmlab/mmdeploy/blob/main/demo/csrc/cpp/det_pose.cxx) ### Inference for a video If the user has MMDeploy compiled correctly, you will see the `pose_tracker` executable under the `mmdeploy/build/bin/`. +- pass `0` to `input` can inference from a webcam + ```shell # go to the mmdeploy folder cd ${PATH_TO_MMDEPLOY}/build/bin/ # inference for a video -./pose_tracker {det work-dir} {pose work-dir} {your_video.mp4} --device cpu +./pose_tracker rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_video.mp4 --device cpu required arguments: det_model Object detection model path [string] @@ -774,8 +1063,8 @@ optional arguments: #### API Example -- [`pose_tracker.py`](https://github.com/open-mmlab/mmdeploy/blob/dev-1.x/demo/python/pose_tracker.py) -- [`pose_tracker.cxx`](https://github.com/open-mmlab/mmdeploy/blob/dev-1.x/demo/csrc/cpp/pose_tracker.cxx) +- [`pose_tracker.py`](https://github.com/open-mmlab/mmdeploy/blob/main/demo/python/pose_tracker.py) +- [`pose_tracker.cxx`](https://github.com/open-mmlab/mmdeploy/blob/main/demo/csrc/cpp/pose_tracker.cxx) ## 📚 Common Usage [🔝](#-table-of-contents) @@ -828,7 +1117,7 @@ The result is as follows: +--------+------------+---------+ ``` -If you want to learn more details of profiler, you can refer to the [Profiler Docs](https://mmdeploy.readthedocs.io/en/1.x/02-how-to-run/useful_tools.html#profiler). +If you want to learn more details of profiler, you can refer to the [Profiler Docs](https://mmdeploy.readthedocs.io/en/latest/02-how-to-run/useful_tools.html#profiler). ### 📊 Model Test [🔝](#-table-of-contents) @@ -842,7 +1131,7 @@ python tools/test.py \ --device cpu ``` -You can also refer to [MMDeploy Docs](https://github.com/open-mmlab/mmdeploy/blob/dev-1.x/docs/en/02-how-to-run/profile_model.md) for more details. +You can also refer to [MMDeploy Docs](https://github.com/open-mmlab/mmdeploy/blob/main/docs/en/02-how-to-run/profile_model.md) for more details. ## 📜 Citation [🔝](#-table-of-contents) diff --git a/projects/rtmpose/README_CN.md b/projects/rtmpose/README_CN.md index f22787a2a3..30bddf9ecd 100644 --- a/projects/rtmpose/README_CN.md +++ b/projects/rtmpose/README_CN.md @@ -1,5 +1,5 @@
- +
# RTMPose: Real-Time Multi-Person Pose Estimation toolkit based on MMPose @@ -8,12 +8,6 @@
-[![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/rtmpose-real-time-multi-person-pose/2d-human-pose-estimation-on-coco-wholebody-1)](https://paperswithcode.com/sota/2d-human-pose-estimation-on-coco-wholebody-1?p=rtmpose-real-time-multi-person-pose) - -
- -
- [English](README.md) | 简体中文
@@ -22,7 +16,7 @@ ______________________________________________________________________ ## Abstract -近年来,2D 姿态估计的研究在公开数据集上取得了出色的成绩,但是它在工业界的应用仍然受到笨重的模型参数和高推理延迟的影响。为了让前沿姿态估计算法在工业界落地,我们通过实验研究了多人姿态估计算法的五个方面:范式、骨干网络、定位算法、训练策略和部署推理,基于 MMPose 提出了一个高性能的实时多人姿态估计框架 **RTMPose**。我们的 RTMPose-m 模型在 COCO 上取得 **75.8%AP**,在 Intel i7-11700 CPU 上达到 **90+FPS**,在 NVIDIA GTX 1660 Ti GPU 上达到 **430+FPS**,RTMPose-l 在 COCO-WholeBody 上达到 **67.0%AP**,**130+FPS**。我们同样验证了在算力有限的设备上做实时姿态估计,RTMPose-s 在移动端骁龙865芯片上可以达到 **COCO 72.2%AP**,**70+FPS**。在 MMDeploy 的帮助下,我们的项目支持 CPU、GPU、Jetson、移动端等多种部署环境。 +近年来,2D 姿态估计的研究在公开数据集上取得了出色的成绩,但是它在工业界的应用仍然受到笨重的模型参数和高推理延迟的影响。为了让前沿姿态估计算法在工业界落地,我们通过实验研究了多人姿态估计算法的五个方面:范式、骨干网络、定位算法、训练策略和部署推理,基于 MMPose 提出了一个高性能的实时多人姿态估计框架 **RTMPose**。我们的 RTMPose-m 模型在 COCO 上取得 **75.8%AP**,在 Intel i7-11700 CPU 上达到 **90+FPS**,在 NVIDIA GTX 1660 Ti GPU 上达到 **430+FPS**。我们同样验证了在算力有限的设备上做实时姿态估计,RTMPose-s 在移动端骁龙865芯片上可以达到 **COCO 72.2%AP**,**70+FPS**。在 MMDeploy 的帮助下,我们的项目支持 CPU、GPU、Jetson、移动端等多种部署环境。 ![rtmpose_intro](https://user-images.githubusercontent.com/13503330/219269619-935499e5-bdd9-49ea-8104-3c7796dbd862.png) @@ -46,6 +40,11 @@ ______________________________________________________________________ ## 🥳 最新进展 [🔝](#-table-of-contents) +- 2023 年 6 月: + - 发布混合数据集训练的 26 点 Body 模型。 +- 2023 年 5 月: + - 添加 [代码示例](./examples/) + - 发布混合数据集训练的 Hand, Face, Body 模型。 - 2023 年 3 月:发布 RTMPose。RTMPose-m 取得 COCO 验证集 75.8 mAP,推理速度达到 430+ FPS 。 ## 📖 简介 [🔝](#-table-of-contents) @@ -55,10 +54,10 @@ ______________________________________________________________________
- +
- +
### ✨ 主要特性 @@ -127,14 +126,14 @@ RTMPose 是一个长期优化迭代的项目,致力于业务场景下的高性 - cuDNN 8.3.2 - CUDA 11.3 -| Detection Config | Pose Config | Input Size
(Det/Pose) | Model AP
(COCO) | Pipeline AP
(COCO) | Params (M)
(Det/Pose) | Flops (G)
(Det/Pose) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | Download | -| :------------------------------------------------------------------ | :---------------------------------------------------------------------------- | :---------------------------: | :---------------------: | :------------------------: | :---------------------------: | :--------------------------: | :--------------------------------: | :---------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | -| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-t](./rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
67.1 | 64.4 | 0.99
3.34 | 0.31
0.36 | 12.403 | 2.467 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth) | -| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-s](./rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
71.1 | 68.5 | 0.99
5.47 | 0.31
0.68 | 16.658 | 2.730 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth) | -| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
75.3 | 73.2 | 0.99
13.59 | 0.31
1.93 | 26.613 | 4.312 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | -| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
76.3 | 74.2 | 0.99
27.66 | 0.31
4.16 | 36.311 | 4.644 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | -| [RTMDet-m](./rtmdet/person/rtmdet_m_640-8xb32_coco-person.py) | [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 640x640
256x192 | 62.5
75.3 | 75.7 | 24.66
13.59 | 38.95
1.93 | - | 6.923 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_m_8xb32-100e_coco-obj365-person-235e8209.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | -| [RTMDet-m](./rtmdet/person/rtmdet_m_640-8xb32_coco-person.py) | [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 640x640
256x192 | 62.5
76.3 | 76.6 | 24.66
27.66 | 38.95
4.16 | - | 7.204 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_m_8xb32-100e_coco-obj365-person-235e8209.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | +| Detection Config | Pose Config | Input Size
(Det/Pose) | Model AP
(COCO) | Pipeline AP
(COCO) | Params (M)
(Det/Pose) | Flops (G)
(Det/Pose) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | Download | +| :------------------------------------------------------------------ | :---------------------------------------------------------------------------- | :---------------------------: | :---------------------: | :------------------------: | :---------------------------: | :--------------------------: | :--------------------------------: | :---------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-t](./rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
67.1 | 64.4 | 0.99
3.34 | 0.31
0.36 | 12.403 | 2.467 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth) | +| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-s](./rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
71.1 | 68.5 | 0.99
5.47 | 0.31
0.68 | 16.658 | 2.730 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth) | +| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
75.3 | 73.2 | 0.99
13.59 | 0.31
1.93 | 26.613 | 4.312 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | +| [RTMDet-nano](./rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py) | [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 320x320
256x192 | 40.3
76.3 | 74.2 | 0.99
27.66 | 0.31
4.16 | 36.311 | 4.644 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | +| [RTMDet-m](./rtmdet/person/rtmdet_m_640-8xb32_coco-person.py) | [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 640x640
256x192 | 62.5
75.3 | 75.7 | 24.66
13.59 | 38.95
1.93 | - | 6.923 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_m_8xb32-100e_coco-obj365-person-235e8209.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | +| [RTMDet-m](./rtmdet/person/rtmdet_m_640-8xb32_coco-person.py) | [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 640x640
256x192 | 62.5
76.3 | 76.6 | 24.66
27.66 | 38.95
4.16 | - | 7.204 | [det](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_m_8xb32-100e_coco-obj365-person-235e8209.pth)
[pose](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | ## 📊 模型库 [🔝](#-table-of-contents) @@ -146,16 +145,67 @@ RTMPose 是一个长期优化迭代的项目,致力于业务场景下的高性 - RTMPose 在更多硬件平台上的推理速度可以前往 [Benchmark](./benchmark/README_CN.md) 查看。 - 如果你有希望我们支持的数据集,欢迎[联系我们](https://uua478.fanqier.cn/f/xxmynrki)/[Google Questionnaire](https://docs.google.com/forms/d/e/1FAIpQLSfzwWr3eNlDzhU98qzk2Eph44Zio6hi5r0iSwfO9wSARkHdWg/viewform?usp=sf_link)! -### 人体 2d 关键点 (17 Keypoints) - -| Config | Input Size | AP
(COCO) | Params(M) | FLOPS(G) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | ncnn-FP16-Latency(ms)
(Snapdragon 865) | Logs | Download | -| :---------: | :--------: | :---------------: | :-------: | :------: | :--------------------------------: | :---------------------------------------: | :--------------------------------------------: | :--------: | :------------: | -| [RTMPose-t](./rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py) | 256x192 | 68.5 | 3.34 | 0.36 | 3.20 | 1.06 | 9.02 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth) | -| [RTMPose-s](./rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py) | 256x192 | 72.2 | 5.47 | 0.68 | 4.48 | 1.39 | 13.89 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth) | -| [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 256x192 | 75.8 | 13.59 | 1.93 | 11.06 | 2.29 | 26.44 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | -| [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 256x192 | 76.5 | 27.66 | 4.16 | 18.85 | 3.46 | 45.37 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | -| [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-384x288.py) | 384x288 | 77.0 | 13.72 | 4.33 | 24.78 | 3.66 | - | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-384x288-a62a0b32_20230228.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-384x288-a62a0b32_20230228.pth) | -| [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-384x288.py) | 384x288 | 77.3 | 27.79 | 9.35 | - | 6.05 | - | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-384x288-97d6cb0f_20230228.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-384x288-97d6cb0f_20230228.pth) | +### 人体 2d 关键点 + +#### 17 Keypoints + +- 关键点骨架定义遵循 [COCO](http://cocodataset.org/). 详情见 [meta info](/configs/_base_/datasets/coco.py). +- + +
+AIC+COCO + +| Config | Input Size | AP
(COCO) | PCK@0.1
(Body8) | AUC
(Body8) | Params
(M) | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | ncnn-FP16-Latency
(ms)
(Snapdragon 865) | Download | +| :---------------------------------------------------------------------------: | :--------: | :---------------: | :---------------------: | :-----------------: | :----------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :-----------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------: | +| [RTMPose-t](./rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py) | 256x192 | 68.5 | 91.28 | 63.38 | 3.34 | 0.36 | 3.20 | 1.06 | 9.02 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth) | +| [RTMPose-s](./rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py) | 256x192 | 72.2 | 92.95 | 66.19 | 5.47 | 0.68 | 4.48 | 1.39 | 13.89 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-aic-coco_pt-aic-coco_420e-256x192-fcb2599b_20230126.pth) | +| [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 256x192 | 75.8 | 94.13 | 68.53 | 13.59 | 1.93 | 11.06 | 2.29 | 26.44 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth) | +| [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 256x192 | 76.5 | 94.35 | 68.98 | 27.66 | 4.16 | 18.85 | 3.46 | 45.37 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-256x192-f016ffe0_20230126.pth) | +| [RTMPose-m](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-384x288.py) | 384x288 | 77.0 | 94.32 | 69.85 | 13.72 | 4.33 | 24.78 | 3.66 | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-384x288-a62a0b32_20230228.pth) | +| [RTMPose-l](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-384x288.py) | 384x288 | 77.3 | 94.54 | 70.14 | 27.79 | 9.35 | - | 6.05 | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-aic-coco_pt-aic-coco_420e-384x288-97d6cb0f_20230228.pth) | + +
+ +
+Body8 + +- `*` 代表模型在 7 个开源数据集上训练得到: + - [AI Challenger](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#aic) + - [MS COCO](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#coco) + - [CrowdPose](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#crowdpose) + - [MPII](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#mpii) + - [sub-JHMDB](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#sub-jhmdb-dataset) + - [Halpe](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_wholebody_keypoint.html#halpe) + - [PoseTrack18](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#posetrack18) +- `Body8` 代表除了以上提到的 7 个数据集,再加上 [OCHuman](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#ochuman) 合并后一起进行评测得到的指标。 + +| Config | Input Size | AP
(COCO) | PCK@0.1
(Body8) | AUC
(Body8) | Params
(M) | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | ncnn-FP16-Latency
(ms)
(Snapdragon 865) | Download | +| :-----------------------------------------------------------------------------: | :--------: | :---------------: | :---------------------: | :-----------------: | :----------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :-----------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------: | +| [RTMPose-t\*](./rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py) | 256x192 | 65.9 | 91.44 | 63.18 | 3.34 | 0.36 | 3.20 | 1.06 | 9.02 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_simcc-body7_pt-body7_420e-256x192-026a1439_20230504.pth) | +| [RTMPose-s\*](./rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py) | 256x192 | 69.7 | 92.45 | 65.15 | 5.47 | 0.68 | 4.48 | 1.39 | 13.89 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-body7_pt-body7_420e-256x192-acd4a1ef_20230504.pth) | +| [RTMPose-m\*](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py) | 256x192 | 74.9 | 94.25 | 68.59 | 13.59 | 1.93 | 11.06 | 2.29 | 26.44 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7_420e-256x192-e48f03d0_20230504.pth) | +| [RTMPose-l\*](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py) | 256x192 | 76.7 | 95.08 | 70.14 | 27.66 | 4.16 | 18.85 | 3.46 | 45.37 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-256x192-4dba18fc_20230504.pth) | +| [RTMPose-m\*](./rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-384x288.py) | 384x288 | 76.6 | 94.64 | 70.38 | 13.72 | 4.33 | 24.78 | 3.66 | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7_420e-384x288-65e718c4_20230504.pth) | +| [RTMPose-l\*](./rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-384x288.py) | 384x288 | 78.3 | 95.36 | 71.58 | 27.79 | 9.35 | - | 6.05 | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-384x288-3f5a1437_20230504.pth) | +| [RTMPose-x\*](./rtmpose/body_2d_keypoint/rtmpose-x_8xb256-700e_coco-384x288.py) | 384x288 | 78.8 | - | - | 49.43 | 17.22 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-x_simcc-body7_pt-body7_700e-384x288-71d7b7e9_20230629.pth) | + +
+ +#### 26 Keypoints + +- 关键点骨架定义遵循 [Halpe26](https://github.com/Fang-Haoshu/Halpe-FullBody/),详情见 [meta info](/configs/_base_/datasets/halpe26.py)。 +- +- 模型在 `Body8` 上进行训练和评估。 + +| Config | Input Size | PCK@0.1
(Body8) | AUC
(Body8) | Params(M) | FLOPS(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | ncnn-FP16-Latency
(ms)
(Snapdragon 865) | Download | +| :---------------------------------------------------------------------------------------: | :--------: | :---------------------: | :-----------------: | :-------: | :------: | :-----------------------------------------: | :------------------------------------------------: | :-----------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------: | +| [RTMPose-t\*](./rtmpose/body_2d_keypoint/rtmpose-t_8xb1024-700e_body8-halpe26-256x192.py) | 256x192 | 91.89 | 66.35 | 3.51 | 0.37 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_simcc-body7_pt-body7-halpe26_700e-256x192-6020f8a6_20230605.pth) | +| [RTMPose-s\*](./rtmpose/body_2d_keypoint/rtmpose-s_8xb1024-700e_body8-halpe26-256x192.py) | 256x192 | 93.01 | 68.62 | 5.70 | 0.70 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-body7_pt-body7-halpe26_700e-256x192-7f134165_20230605.pth) | +| [RTMPose-m\*](./rtmpose/body_2d_keypoint/rtmpose-m_8xb512-700e_body8-halpe26-256x192.py) | 256x192 | 94.75 | 71.91 | 13.93 | 1.95 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7-halpe26_700e-256x192-4d3e73dd_20230605.pth) | +| [RTMPose-l\*](./rtmpose/body_2d_keypoint/rtmpose-l_8xb512-700e_body8-halpe26-256x192.py) | 256x192 | 95.37 | 73.19 | 28.11 | 4.19 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7-halpe26_700e-256x192-2abb7558_20230605.pth) | +| [RTMPose-m\*](./rtmpose/body_2d_keypoint/rtmpose-m_8xb512-700e_body8-halpe26-384x288.py) | 384x288 | 95.15 | 73.56 | 14.06 | 4.37 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-body7_pt-body7-halpe26_700e-384x288-89e6428b_20230605.pth) | +| [RTMPose-l\*](./rtmpose/body_2d_keypoint/rtmpose-l_8xb512-700e_body8-halpe26-384x288.py) | 384x288 | 95.56 | 74.38 | 28.24 | 9.40 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-body7_pt-body7-halpe26_700e-384x288-734182ce_20230605.pth) | +| [RTMPose-x\*](./rtmpose/body_2d_keypoint/rtmpose-x_8xb256-700e_body8-halpe26-384x288.py) | 384x288 | 95.74 | 74.82 | 50.00 | 17.29 | - | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-x_simcc-body7_pt-body7-halpe26_700e-384x288-7fb6e239_20230606.pth) | #### 模型剪枝 @@ -163,57 +213,134 @@ RTMPose 是一个长期优化迭代的项目,致力于业务场景下的高性 - 模型剪枝由 [MMRazor](https://github.com/open-mmlab/mmrazor) 提供 -| Config | Input Size | AP
(COCO) | Params(M) | FLOPS(G) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | ncnn-FP16-Latency(ms)
(Snapdragon 865) | Logs | Download | -| :---------: | :--------: | :---------------: | :-------: | :------: | :--------------------------------: | :---------------------------------------: | :--------------------------------------------: | :--------: | :------------: | -| RTMPose-s-aic-coco-pruned | 256x192 | 69.4 | 3.43 | 0.35 | - | - | - | [log](https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.json) | [model](https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.pth) | +| Config | Input Size | AP
(COCO) | Params
(M) | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | ncnn-FP16-Latency
(ms)
(Snapdragon 865) | Download | +| :-----------------------: | :--------: | :---------------: | :----------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :-----------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------: | +| RTMPose-s-aic-coco-pruned | 256x192 | 69.4 | 3.43 | 0.35 | - | - | - | [Model](https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.pth) | 更多信息,请参考 [GroupFisher Pruning for RTMPose](./rtmpose/pruning/README.md). ### 人体全身 2d 关键点 (133 Keypoints) -| Config | Input Size | Whole AP | Whole AR | FLOPS(G) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | Logs | Download | -| :----------------------------- | :--------: | :------: | :------: | :------: | :--------------------------------: | :---------------------------------------: | :--------------------------: | :-------------------------------: | -| [RTMPose-m](./rtmpose/wholebody_2d_keypoint/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py) | 256x192 | 60.4 | 66.7 | 2.22 | 13.50 | 4.00 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.pth) | -| [RTMPose-l](./rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py) | 256x192 | 63.2 | 69.4 | 4.52 | 23.41 | 5.67 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-256x192-6f206314_20230124.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-256x192-6f206314_20230124.pth) | -| [RTMPose-l](./rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py) | 384x288 | 67.0 | 72.3 | 10.07 | 44.58 | 7.68 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.pth) | +- 关键点骨架定义遵循 [COCO-WholeBody](https://github.com/jin-s13/COCO-WholeBody/),详情见 [meta info](/configs/_base_/datasets/coco_wholebody.py)。 +- + +| Config | Input Size | Whole AP | Whole AR | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | Download | +| :------------------------------ | :--------: | :------: | :------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :-------------------------------: | +| [RTMPose-m](./rtmpose/wholebody_2d_keypoint/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py) | 256x192 | 58.2 | 67.4 | 2.22 | 13.50 | 4.00 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.pth) | +| [RTMPose-l](./rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py) | 256x192 | 61.1 | 70.0 | 4.52 | 23.41 | 5.67 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-256x192-6f206314_20230124.pth) | +| [RTMPose-l](./rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py) | 384x288 | 64.8 | 73.0 | 10.07 | 44.58 | 7.68 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-l_simcc-coco-wholebody_pt-aic-coco_270e-384x288-eaeb96c8_20230125.pth) | +| [RTMPose-x](./rtmpose/wholebody_2d_keypoint/rtmpose-x_8xb32-270e_coco-wholebody-384x288.py) | 384x288 | 65.3 | 73.3 | 18.1 | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-x_simcc-coco-wholebody_pt-body7_270e-384x288-401dfc90_20230629.pth) | ### 动物 2d 关键点 (17 Keypoints) -| Config | Input Size | AP
(AP10K) | FLOPS(G) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | Logs | Download | -| :---------------------------: | :--------: | :----------------: | :------: | :--------------------------------: | :---------------------------------------: | :--------------------------: | :------------------------------: | -| [RTMPose-m](./rtmpose/animal_2d_keypoint/rtmpose-m_8xb64-210e_ap10k-256x256.py) | 256x256 | 72.2 | 2.57 | 14.157 | 2.404 | [Log](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-ap10k_pt-aic-coco_210e-256x256-7a041aa1_20230206.json) | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-m_simcc-ap10k_pt-aic-coco_210e-256x256-7a041aa1_20230206.pth) | +- 关键点骨架定义遵循 [AP-10K](https://github.com/AlexTheBad/AP-10K/),详情见 [meta info](/configs/_base_/datasets/ap10k.py)。 +- -### 脸部 2d 关键点 +| Config | Input Size | AP
(AP10K) | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | Download | +| :----------------------------: | :--------: | :----------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :------------------------------: | +| [RTMPose-m](./rtmpose/animal_2d_keypoint/rtmpose-m_8xb64-210e_ap10k-256x256.py) | 256x256 | 72.2 | 2.57 | 14.157 | 2.404 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-ap10k_pt-aic-coco_210e-256x256-7a041aa1_20230206.pth) | -| Config | Input Size | NME
(COCO-WholeBody-Face) | FLOPS(G) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | Logs | Download | -| :--------------------------------------------------: | :--------: | :-------------------------------: | :------: | :--------------------------------: | :---------------------------------------: | :---------: | :---------: | -| [RTMPose-m](./rtmpose/face_2d_keypoint/wflw/rtmpose-m_8xb64-60e_coco-wholebody-face-256x256.py) | 256x256 | 4.57 | - | - | - | Coming soon | Coming soon | +### 脸部 2d 关键点 (106 Keypoints) -### 手部 2d 关键点 +- 关键点骨架定义遵循 [LaPa](https://github.com/JDAI-CV/lapa-dataset),详情见 [meta info](/configs/_base_/datasets/lapa.py)。 +- -| Config | Input Size | PCK
(COCO-WholeBody-Hand) | FLOPS(G) | ORT-Latency(ms)
(i7-11700) | TRT-FP16-Latency(ms)
(GTX 1660Ti) | Logs | Download | -| :--------------------------------------------------: | :--------: | :-------------------------------: | :------: | :--------------------------------: | :---------------------------------------: | :---------: | :---------: | -| [RTMPose-m](./rtmpose/hand_2d_keypoint/coco_wholebody_hand/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py) | 256x256 | 81.5 | - | - | - | Coming soon | Coming soon | +
+Face6 -### 预训练模型 +- `Face6` and `*` 代表模型在 6 个开源数据集上训练得到: + - [COCO-Wholebody-Face](https://github.com/jin-s13/COCO-WholeBody/) + - [WFLW](https://wywu.github.io/projects/LAB/WFLW.html) + - [300W](https://ibug.doc.ic.ac.uk/resources/300-W/) + - [COFW](http://www.vision.caltech.edu/xpburgos/ICCV13/) + - [Halpe](https://github.com/Fang-Haoshu/Halpe-FullBody/) + - [LaPa](https://github.com/JDAI-CV/lapa-dataset) -我们提供了 UDP 预训练的 CSPNeXt 模型参数,训练配置请参考 [pretrain_cspnext_udp folder](./rtmpose/pretrain_cspnext_udp/)。 +| Config | Input Size | NME
(LaPa) | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | Download | +| :----------------------------: | :--------: | :----------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :------------------------------: | +| [RTMPose-t\*](./rtmpose/face_2d_keypoint/rtmpose-t_8xb256-120e_lapa-256x256.py) | 256x256 | 1.67 | 0.652 | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-t_simcc-face6_pt-in1k_120e-256x256-df79d9a5_20230529.pth) | +| [RTMPose-s\*](./rtmpose/face_2d_keypoint/rtmpose-s_8xb256-120e_lapa-256x256.py) | 256x256 | 1.59 | 1.119 | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-s_simcc-face6_pt-in1k_120e-256x256-d779fdef_20230529.pth) | +| [RTMPose-m\*](./rtmpose/face_2d_keypoint/rtmpose-m_8xb256-120e_lapa-256x256.py) | 256x256 | 1.44 | 2.852 | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-face6_pt-in1k_120e-256x256-72a37400_20230529.pth) | + +
+ +### 手部 2d 关键点 (21 Keypoints) + +- 关键点骨架定义遵循 [COCO-WholeBody](https://github.com/jin-s13/COCO-WholeBody/),详情见 [meta info](/configs/_base_/datasets/coco_wholebody_hand.py)。 +- + +| Detection Config | Input Size | Model AP
(OneHand10K) | Flops
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | Download | +| :---------------------------: | :--------: | :---------------------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :--------------------: | +| [RTMDet-nano (试用)](./rtmdet/hand/rtmdet_nano_320-8xb32_hand.py) | 320x320 | 76.0 | 0.31 | - | - | [Det Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmdet_nano_8xb32-300e_hand-267f9c8f.pth) | + +
+Hand5 -| Model | Input Size | Params(M) | Flops(G) | AP
(GT) | AR
(GT) | Download | -| :-------: | :--------: | :-------: | :------: | :-------------: | :-------------: | :-----------------------------------------------------------------------------------------------------------------------------: | -| CSPNeXt-t | 256x192 | 6.03 | 1.43 | 65.5 | 68.9 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth) | -| CSPNeXt-s | 256x192 | 8.58 | 1.78 | 70.0 | 73.3 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth) | -| CSPNeXt-m | 256x192 | 13.05 | 3.06 | 74.8 | 77.7 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth) | -| CSPNeXt-l | 256x192 | 32.44 | 5.33 | 77.2 | 79.9 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth) | +- `Hand5` and `*` 代表模型在 5 个开源数据集上训练得到: + - [COCO-Wholebody-Hand](https://github.com/jin-s13/COCO-WholeBody/) + - [OneHand10K](https://www.yangangwang.com/papers/WANG-MCC-2018-10.html) + - [FreiHand2d](https://lmb.informatik.uni-freiburg.de/projects/freihand/) + - [RHD2d](https://lmb.informatik.uni-freiburg.de/resources/datasets/RenderedHandposeDataset.en.html) + - [Halpe](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_wholebody_keypoint.html#halpe) -我们提供了 ImageNet 分类训练的 CSPNeXt 模型参数,更多细节请参考 [RTMDet](https://github.com/open-mmlab/mmdetection/blob/dev-3.x/configs/rtmdet/README.md#classification)。 +| Config | Input Size | PCK@0.2
(COCO-Wholebody-Hand) | PCK@0.2
(Hand5) | AUC
(Hand5) | FLOPS
(G) | ORT-Latency
(ms)
(i7-11700) | TRT-FP16-Latency
(ms)
(GTX 1660Ti) | Download | +| :----------------------------------------------------------------------------------------------------------: | :--------: | :-----------------------------------: | :---------------------: | :-----------------: | :---------------: | :-----------------------------------------: | :------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------: | +| [RTMPose-m\*
(试用)](./rtmpose/hand_2d_keypoint/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py) | 256x256 | 81.5 | 96.4 | 83.9 | 2.581 | - | - | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-hand5_pt-aic-coco_210e-256x256-74fb594_20230320.pth) | -| Model | Input Size | Params(M) | Flops(G) | Top-1 (%) | Top-5 (%) | Download | -| :----------: | :--------: | :-------: | :------: | :-------: | :-------: | :---------------------------------------------------------------------------------------------------------------------------------: | -| CSPNeXt-tiny | 224x224 | 2.73 | 0.34 | 69.44 | 89.45 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-tiny_imagenet_600e-3a2dd350.pth) | -| CSPNeXt-s | 224x224 | 4.89 | 0.66 | 74.41 | 92.23 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-s_imagenet_600e-ea671761.pth) | -| CSPNeXt-m | 224x224 | 13.05 | 1.93 | 79.27 | 94.79 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-m_8xb256-rsb-a1-600e_in1k-ecb3bbd9.pth) | -| CSPNeXt-l | 224x224 | 27.16 | 4.19 | 81.30 | 95.62 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-l_8xb256-rsb-a1-600e_in1k-6a760974.pth) | +
+ +### 预训练模型 + +我们提供了 UDP 预训练的 CSPNeXt 模型参数,训练配置请参考 [pretrain_cspnext_udp folder](./rtmpose/pretrain_cspnext_udp/)。 + +
+AIC+COCO + +| Model | Input Size | Params
(M) | Flops
(G) | AP
(GT) | AR
(GT) | Download | +| :----------: | :--------: | :----------------: | :---------------: | :-------------: | :-------------: | :---------------------------------------------------------------------------------------------------------------: | +| CSPNeXt-tiny | 256x192 | 6.03 | 1.43 | 65.5 | 68.9 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth) | +| CSPNeXt-s | 256x192 | 8.58 | 1.78 | 70.0 | 73.3 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth) | +| CSPNeXt-m | 256x192 | 17.53 | 3.05 | 74.8 | 77.7 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth) | +| CSPNeXt-l | 256x192 | 32.44 | 5.32 | 77.2 | 79.9 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth) | + +
+ +
+Body8 + +- `*` 代表模型在 7 个开源数据集上训练得到: + - [AI Challenger](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#aic) + - [MS COCO](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#coco) + - [CrowdPose](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#crowdpose) + - [MPII](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#mpii) + - [sub-JHMDB](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#sub-jhmdb-dataset) + - [Halpe](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_wholebody_keypoint.html#halpe) + - [PoseTrack18](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#posetrack18) +- `Body8` 代表除了以上提到的 7 个数据集,再加上 [OCHuman](https://mmpose.readthedocs.io/en/latest/dataset_zoo/2d_body_keypoint.html#ochuman) 合并后一起进行评测得到的指标。 + +| Model | Input Size | Params
(M) | Flops
(G) | AP
(COCO) | PCK@0.2
(Body8) | AUC
(Body8) | Download | +| :------------: | :--------: | :----------------: | :---------------: | :---------------: | :---------------------: | :-----------------: | :--------------------------------------------------------------------------------: | +| CSPNeXt-tiny\* | 256x192 | 6.03 | 1.43 | 65.9 | 96.34 | 63.80 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-tiny_udp-body7_210e-256x192-a3775292_20230504.pth) | +| CSPNeXt-s\* | 256x192 | 8.58 | 1.78 | 68.7 | 96.59 | 64.92 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-s_udp-body7_210e-256x192-8c9ccbdb_20230504.pth) | +| CSPNeXt-m\* | 256x192 | 17.53 | 3.05 | 73.7 | 97.42 | 68.19 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-body7_210e-256x192-e0c9327b_20230504.pth) | +| CSPNeXt-l\* | 256x192 | 32.44 | 5.32 | 75.7 | 97.76 | 69.57 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-l_udp-body7_210e-256x192-5e9558ef_20230504.pth) | +| CSPNeXt-m\* | 384x288 | 17.53 | 6.86 | 75.8 | 97.60 | 70.18 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-m_udp-body7_210e-384x288-b9bc2b57_20230504.pth) | +| CSPNeXt-l\* | 384x288 | 32.44 | 11.96 | 77.2 | 97.89 | 71.23 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-l_udp-body7_210e-384x288-b15bc30d_20230504.pth) | +| CSPNeXt-x\* | 384x288 | 54.92 | 19.96 | 78.1 | 98.00 | 71.79 | [Model](https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/cspnext-x_udp-body7_210e-384x288-d28b58e6_20230529.pth) | + +
+ +#### ImageNet + +我们提供了 ImageNet 分类训练的 CSPNeXt 模型参数,更多细节请参考 [RTMDet](https://github.com/open-mmlab/mmdetection/blob/latest/configs/rtmdet/README.md#classification)。 + +| Model | Input Size | Params
(M) | Flops
(G) | Top-1 (%) | Top-5 (%) | Download | +| :----------: | :--------: | :----------------: | :---------------: | :-------: | :-------: | :---------------------------------------------------------------------------------------------------------------------------: | +| CSPNeXt-tiny | 224x224 | 2.73 | 0.34 | 69.44 | 89.45 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-tiny_imagenet_600e-3a2dd350.pth) | +| CSPNeXt-s | 224x224 | 4.89 | 0.66 | 74.41 | 92.23 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-s_imagenet_600e-ea671761.pth) | +| CSPNeXt-m | 224x224 | 13.05 | 1.93 | 79.27 | 94.79 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-m_8xb256-rsb-a1-600e_in1k-ecb3bbd9.pth) | +| CSPNeXt-l | 224x224 | 27.16 | 4.19 | 81.30 | 95.62 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-l_8xb256-rsb-a1-600e_in1k-6a760974.pth) | +| CSPNeXt-x | 224x224 | 48.85 | 7.76 | 82.10 | 95.69 | [Model](https://download.openmmlab.com/mmdetection/v3.0/rtmdet/cspnext_rsb_pretrain/cspnext-x_8xb256-rsb-a1-600e_in1k-b3f78edd.pth) | ## 👀 可视化 [🔝](#-table-of-contents) @@ -226,12 +353,55 @@ RTMPose 是一个长期优化迭代的项目,致力于业务场景下的高性 我们提供了两种途径来让用户尝试 RTMPose 模型: -- MMDeploy SDK 预编译包 (推荐) - MMPose demo 脚本 +- MMDeploy SDK 预编译包 (推荐,速度提升6-10倍) + +### MMPose demo 脚本 + +通过 MMPose 提供的 demo 脚本可以基于 Pytorch 快速进行[模型推理](https://mmpose.readthedocs.io/en/latest/user_guides/inference.html)和效果验证。 + +**提示:** + +- 基于 Pytorch 推理并不能达到 RTMPose 模型的最大推理速度,只用于模型效果验证。 +- 输入模型路径可以是本地路径,也可以是下载链接。 + +```shell +# 前往 mmpose 目录 +cd ${PATH_TO_MMPOSE} + +# RTMDet 与 RTMPose 联合推理 +# 输入模型路径可以是本地路径,也可以是下载链接。 +python demo/topdown_demo_with_mmdet.py \ + projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ + projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ + --input {YOUR_TEST_IMG_or_VIDEO} \ + --show + +# 摄像头推理 +# 输入模型路径可以是本地路径,也可以是下载链接。 +python demo/topdown_demo_with_mmdet.py \ + projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ + projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ + --input webcam \ + --show +``` + +效果展示: + +![topdown_inference_with_rtmdet](https://user-images.githubusercontent.com/13503330/220005020-06bdf37f-6817-4681-a2c8-9dd55e4fbf1e.png) ### MMDeploy SDK 预编译包 (推荐) -MMDeploy 提供了预编译的 SDK,用于对 RTMPose 项目进行 Pipeline 推理,其中推理所用的模型为 SDK 版本。导出 SDK 版模型的教程见 [SDK 推理](#%EF%B8%8F-sdk-推理),推理的详细参数设置见 [Pipeline 推理](#-pipeline-推理)。 +MMDeploy 提供了预编译的 SDK,用于对 RTMPose 项目进行 Pipeline 推理,其中推理所用的模型为 SDK 版本。 + +- 所有的模型必须经过 `tools/deploy.py` 导出后才能使用 PoseTracker 进行推理。 +- 导出 SDK 版模型的教程见 [SDK 推理](#%EF%B8%8F-sdk-推理),推理的详细参数设置见 [Pipeline 推理](#-pipeline-推理)。 +- 你可以从 [硬件模型库](https://platform.openmmlab.com/deploee) 直接下载 SDK 版模型(ONNX、 TRT、ncnn 等)。 +- 同时我们也支持 [在线模型转换](https://platform.openmmlab.com/deploee/task-convert-list)。 #### Linux\\ @@ -240,60 +410,131 @@ MMDeploy 提供了预编译的 SDK,用于对 RTMPose 项目进行 Pipeline 推 - GCC 版本需大于 7.5 - cmake 版本需大于 3.20 +##### Python 推理 + +1. 安装 mmdeploy_runtime 或者 mmdeploy_runtime_gpu + +```shell +# for onnxruntime +pip install mmdeploy-runtime + +# for onnxruntime-gpu / tensorrt +pip install mmdeploy-runtime-gpu +``` + +2. 下载预编译包: + +```shell +# onnxruntime +# for ubuntu +wget -c https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64-cxx11abi.tar.gz +# 解压并将 third_party 中第三方推理库的动态库添加到 PATH + +# for centos7 and lower +wget -c https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64.tar.gz +# 解压并将 third_party 中第三方推理库的动态库添加到 PATH + +# onnxruntime-gpu / tensorrt +# for ubuntu +wget -c https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64-cxx11abi-cuda11.3.tar.gz +# 解压并将 third_party 中第三方推理库的动态库添加到 PATH + +# for centos7 and lower +wget -c https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64-cuda11.3.tar.gz +# 解压并将 third_party 中第三方推理库的动态库添加到 PATH +``` + +3. 下载 sdk 模型并解压到 `./example/python` 下。(该模型只用于演示,如需其他模型,请参考 [SDK 推理](#%EF%B8%8F-sdk-推理)) + +```shell +# rtmdet-nano + rtmpose-m for cpu sdk +wget https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-cpu.zip + +unzip rtmpose-cpu.zip +``` + +4. 使用 `pose_tracker.py` 进行推理: + +```shell +# 进入 ./example/python + +# 请传入模型目录,而不是模型文件 +# 格式: +# python pose_tracker.py cpu {det work-dir} {pose work-dir} {your_video.mp4} + +# 示例: +python pose_tracker.py cpu rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_video.mp4 + +# 摄像头 +python pose_tracker.py cpu rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ 0 +``` + ##### ONNX ```shell # 下载预编译包 -wget https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0rc3/mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1.tar.gz +wget https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64-cxx11abi.tar.gz # 解压文件 -tar -xzvf mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1.tar.gz +tar -xzvf mmdeploy-1.0.0-linux-x86_64-cxx11abi.tar.gz # 切换到 sdk 目录 -cd mmdeploy-1.0.0rc3-linux-x86_64-onnxruntime1.8.1/sdk +cd mmdeploy-1.0.0-linux-x86_64-cxx11abi # 设置环境变量 -source env.sh +source set_env.sh # 如果系统中没有安装 opencv 3+,请执行以下命令。如果已安装,可略过 -bash opencv.sh +bash install_opencv.sh # 编译可执行程序 -bash build.sh +bash build_sdk.sh # 图片推理 -./bin/det_pose {det work-dir} {pose work-dir} {your_img.jpg} --device cpu +# 请传入模型目录,而不是模型文件 +./bin/det_pose rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_img.jpg --device cpu # 视频推理 -./bin/pose_tracker {det work-dir} {pose work-dir} {your_video.mp4} --device cpu +# 请传入模型目录,而不是模型文件 +./bin/pose_tracker rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_video.mp4 --device cpu + +# 摄像头推理 +# 请传入模型目录,而不是模型文件 +./bin/pose_tracker rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ 0 --device cpu ``` ##### TensorRT ```shell # 下载预编译包 -wget https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0rc3/mmdeploy-1.0.0rc3-linux-x86_64-cuda11.1-tensorrt8.2.3.0.tar.gz +wget https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-linux-x86_64-cxx11abi-cuda11.3.tar.gz # 解压文件 -tar -xzvf mmdeploy-1.0.0rc3-linux-x86_64-cuda11.1-tensorrt8.2.3.0.tar.gz +tar -xzvf mmdeploy-1.0.0-linux-x86_64-cxx11abi-cuda11.3.tar.gz # 切换到 sdk 目录 -cd mmdeploy-1.0.0rc3-linux-x86_64-cuda11.1-tensorrt8.2.3.0/sdk +cd mmdeploy-1.0.0-linux-x86_64-cxx11abi-cuda11.3 # 设置环境变量 -source env.sh +source set_env.sh # 如果系统中没有安装 opencv 3+,请执行以下命令。如果已安装,可略过 -bash opencv.sh +bash install_opencv.sh # 编译可执行程序 -bash build.sh +bash build_sdk.sh # 图片推理 -./bin/det_pose {det work-dir} {pose work-dir} {your_img.jpg} --device cuda +# 请传入模型目录,而不是模型文件 +./bin/det_pose rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_img.jpg --device cuda # 视频推理 -./bin/pose_tracker {det work-dir} {pose work-dir} {your_video.mp4} --device cuda +# 请传入模型目录,而不是模型文件 +./bin/pose_tracker rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_video.mp4 --device cuda + +# 摄像头推理 +# 请传入模型目录,而不是模型文件 +./bin/pose_tracker rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ 0 --device cuda ``` 详细参数设置见 [Pipeline 推理](#-pipeline-推理)。 @@ -302,20 +543,37 @@ bash build.sh ##### Python 推理 -1. 下载 [预编译包](https://github.com/open-mmlab/mmdeploy/releases)。 -2. 解压文件,进入 `sdk/python` 目录。 -3. 用 `whl` 安装 `mmdeploy_python`。 +1. 安装 mmdeploy_runtime 或者 mmdeploy_runtime_gpu ```shell -pip install {file_name}.whl +# for onnxruntime +pip install mmdeploy-runtime +# 下载 [sdk](https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-windows-amd64.zip) 并将 third_party 中第三方推理库的动态库添加到 PATH + +# for onnxruntime-gpu / tensorrt +pip install mmdeploy-runtime-gpu +# 下载 [sdk](https://github.com/open-mmlab/mmdeploy/releases/download/v1.0.0/mmdeploy-1.0.0-windows-amd64-cuda11.3.zip) 并将 third_party 中第三方推理库的动态库添加到 PATH ``` -4. 下载 [sdk 模型](https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-cpu.zip)并解压。 -5. 使用 `pose_tracker.py` 进行推理: +2. 下载 sdk 模型并解压到 `./example/python` 下。(该模型只用于演示,如需其他模型,请参考 [SDK 推理](#%EF%B8%8F-sdk-推理)) ```shell -# 进入 ./sdk/example/python -python pose_tracker.py cpu {det work-dir} {pose work-dir} {your_video.mp4} +# rtmdet-nano + rtmpose-m for cpu sdk +wget https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmpose-cpu.zip + +unzip rtmpose-cpu.zip +``` + +3. 使用 `pose_tracker.py` 进行推理: + +```shell +# 进入 ./example/python +# 请传入模型目录,而不是模型文件 +python pose_tracker.py cpu rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_video.mp4 + +# 摄像头 +# 请传入模型目录,而不是模型文件 +python pose_tracker.py cpu rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ 0 ``` ##### 可执行文件推理 @@ -333,14 +591,14 @@ set-ExecutionPolicy RemoteSigned ```shell # in sdk folder: -.\opencv.ps1 +.\install_opencv.ps1 ``` 6. 配置环境变量: ```shell # in sdk folder: -.\set_env.ps1 +. .\set_env.ps1 ``` 7. 编译 sdk: @@ -363,6 +621,10 @@ example\cpp\build\Release 通过 MMPose 提供的 demo 脚本可以基于 Pytorch 快速进行[模型推理](https://mmpose.readthedocs.io/en/latest/user_guides/inference.html)和效果验证。 +**提示:** + +- 基于 Pytorch 推理并不能达到 RTMPose 模型的真实推理速度,只用于模型效果验证。 + ```shell # 前往 mmpose 目录 cd ${PATH_TO_MMPOSE} @@ -373,7 +635,16 @@ python demo/topdown_demo_with_mmdet.py \ {PATH_TO_CHECKPOINT}/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ {PATH_TO_CHECKPOINT}/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ - --input {YOUR_TEST_IMG} + --input {YOUR_TEST_IMG_or_VIDEO} \ + --show + +# 摄像头推理 +python demo/topdown_demo_with_mmdet.py \ + projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + {PATH_TO_CHECKPOINT}/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ + projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + {PATH_TO_CHECKPOINT}/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ + --input webcam \ --show ``` @@ -387,7 +658,7 @@ python demo/topdown_demo_with_mmdet.py \ **提示**: -- RTMPose 默认开启了 `drop_last=True`,当用户的数据集较小时请根据情况缩小 `batch_size` 和 `base_lr`。 +- 当用户的数据集较小时请根据情况缩小 `batch_size` 和 `base_lr`。 - 模型选择 - m:推荐首选使用 - t/s:适用于极端低算力的移动设备,或对推理速度要求严格的场景 @@ -395,52 +666,51 @@ python demo/topdown_demo_with_mmdet.py \ ## 🏗️ 部署教程 [🔝](#-table-of-contents) -本教程将展示如何通过 [MMDeploy-1.x](https://github.com/open-mmlab/mmdeploy/tree/1.x) 部署 RTMPose 项目。 +本教程将展示如何通过 [MMDeploy](https://github.com/open-mmlab/mmdeploy/tree/main) 部署 RTMPose 项目。 + +- 你可以从 [硬件模型库](https://platform.openmmlab.com/deploee) 直接下载 SDK 版模型(ONNX、 TRT、ncnn 等)。 +- 同时我们也支持 [在线模型转换](https://platform.openmmlab.com/deploee/task-convert-list)。 ### 🧩 安装 在开始部署之前,首先你需要确保正确安装了 MMPose, MMDetection, MMDeploy,相关安装教程如下: - [安装 MMPose 与 MMDetection](https://mmpose.readthedocs.io/zh_CN/latest/installation.html) -- [安装 MMDeploy](https://mmdeploy.readthedocs.io/zh_CN/1.x/04-supported-codebases/mmpose.html) +- [安装 MMDeploy](https://mmdeploy.readthedocs.io/zh_CN/latest/04-supported-codebases/mmpose.html) 根据部署后端的不同,有的后端需要对自定义算子进行编译,请根据需求前往对应的文档确保环境搭建正确: -- [ONNX](https://mmdeploy.readthedocs.io/zh_CN/1.x/05-supported-backends/onnxruntime.html) -- [TensorRT](https://mmdeploy.readthedocs.io/zh_CN/1.x/05-supported-backends/tensorrt.html) -- [OpenVINO](https://mmdeploy.readthedocs.io/zh_CN/1.x/05-supported-backends/openvino.html) -- [更多](https://github.com/open-mmlab/mmdeploy/tree/1.x/docs/en/05-supported-backends) +- [ONNX](https://mmdeploy.readthedocs.io/zh_CN/latest/05-supported-backends/onnxruntime.html) +- [TensorRT](https://mmdeploy.readthedocs.io/zh_CN/latest/05-supported-backends/tensorrt.html) +- [OpenVINO](https://mmdeploy.readthedocs.io/zh_CN/latest/05-supported-backends/openvino.html) +- [更多](https://github.com/open-mmlab/mmdeploy/tree/main/docs/en/05-supported-backends) ### 🛠️ 模型转换 在完成安装之后,你就可以开始模型部署了。通过 MMDeploy 提供的 `tools/deploy.py` 可以方便地将 Pytorch 模型转换到不同的部署后端。 -我们本节演示将 RTMDet 和 RTMPose 模型导出为 ONNX 和 TensorRT 格式,如果你希望了解更多内容请前往 [MMDeploy 文档](https://mmdeploy.readthedocs.io/zh_CN/1.x/02-how-to-run/convert_model.html)。 +我们本节演示将 RTMDet 和 RTMPose 模型导出为 ONNX 和 TensorRT 格式,如果你希望了解更多内容请前往 [MMDeploy 文档](https://mmdeploy.readthedocs.io/zh_CN/latest/02-how-to-run/convert_model.html)。 - ONNX 配置 - \- RTMDet:[`detection_onnxruntime_static.py`](https://github.com/open-mmlab/mmdeploy/blob/1.x/configs/mmdet/detection/detection_onnxruntime_static.py) + \- RTMDet:[`detection_onnxruntime_static.py`](https://github.com/open-mmlab/mmdeploy/blob/main/configs/mmdet/detection/detection_onnxruntime_static.py) - \- RTMPose:[`pose-detection_simcc_onnxruntime_dynamic.py`](https://github.com/open-mmlab/mmdeploy/blob/1.x/configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py) + \- RTMPose:[`pose-detection_simcc_onnxruntime_dynamic.py`](https://github.com/open-mmlab/mmdeploy/blob/main/configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py) - TensorRT 配置 - \- RTMDet:[`detection_tensorrt_static-320x320.py`](https://github.com/open-mmlab/mmdeploy/blob/1.x/configs/mmdet/detection/detection_tensorrt_static-320x320.py) + \- RTMDet:[`detection_tensorrt_static-320x320.py`](https://github.com/open-mmlab/mmdeploy/blob/main/configs/mmdet/detection/detection_tensorrt_static-320x320.py) - \- RTMPose:[`pose-detection_simcc_tensorrt_dynamic-256x192.py`](https://github.com/open-mmlab/mmdeploy/blob/1.x/configs/mmpose/pose-detection_simcc_tensorrt_dynamic-256x192.py) + \- RTMPose:[`pose-detection_simcc_tensorrt_dynamic-256x192.py`](https://github.com/open-mmlab/mmdeploy/blob/main/configs/mmpose/pose-detection_simcc_tensorrt_dynamic-256x192.py) -如果你需要对部署配置进行修改,请参考 [MMDeploy config tutorial](https://mmdeploy.readthedocs.io/zh_CN/1.x/02-how-to-run/write_config.html). +如果你需要对部署配置进行修改,请参考 [MMDeploy config tutorial](https://mmdeploy.readthedocs.io/zh_CN/latest/02-how-to-run/write_config.html). 本教程中使用的文件结构如下: -```Python +```shell |----mmdeploy |----mmdetection |----mmpose -|----rtmdet_nano -| |----rtmdet_nano.pth -|----rtmpose_m - |----rtmpose_m.pth ``` #### ONNX @@ -452,24 +722,28 @@ python demo/topdown_demo_with_mmdet.py \ cd ${PATH_TO_MMDEPLOY} # 转换 RTMDet +# 输入模型路径可以是本地路径,也可以是下载链接。 python tools/deploy.py \ configs/mmdet/detection/detection_onnxruntime_static.py \ - {RTMPOSE_PROJECT}/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ - ../rtmdet_nano/rtmdet_nano.pth \ + ../mmpose/projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ demo/resources/human-pose.jpg \ - --work-dir mmdeploy_models/mmdet/ort \ + --work-dir rtmpose-ort/rtmdet-nano \ --device cpu \ - --show + --show \ + --dump-info # 导出 sdk info # 转换 RTMPose +# 输入模型路径可以是本地路径,也可以是下载链接。 python tools/deploy.py \ configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py \ - {RTMPOSE_PROJECT}/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ - ../rtmpose_m/rtmpose_m.pth \ + ../mmpose/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ demo/resources/human-pose.jpg \ - --work-dir mmdeploy_models/mmpose/ort \ + --work-dir rtmpose-ort/rtmpose-m \ --device cpu \ - --show + --show \ + --dump-info # 导出 sdk info ``` 默认导出模型文件为 `{work-dir}/end2end.onnx` @@ -483,24 +757,28 @@ python tools/deploy.py \ cd ${PATH_TO_MMDEPLOY} # 转换 RTMDet +# 输入模型路径可以是本地路径,也可以是下载链接。 python tools/deploy.py \ configs/mmdet/detection/detection_tensorrt_static-320x320.py \ - {RTMPOSE_PROJECT}/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ - ../rtmdet_nano/rtmdet_nano.pth \ + ../mmpose/projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ demo/resources/human-pose.jpg \ - --work-dir mmdeploy_models/mmdet/trt \ + --work-dir rtmpose-trt/rtmdet-nano \ --device cuda:0 \ - --show + --show \ + --dump-info # 导出 sdk info # 转换 RTMPose +# 输入模型路径可以是本地路径,也可以是下载链接。 python tools/deploy.py \ configs/mmpose/pose-detection_simcc_tensorrt_dynamic-256x192.py \ - {RTMPOSE_PROJECT}/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ - ../rtmpose_m/rtmpose_m.pth \ + ../mmpose/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ demo/resources/human-pose.jpg \ - --work-dir mmdeploy_models/mmpose/trt \ + --work-dir rtmpose-trt/rtmpose-m \ --device cuda:0 \ - --show + --show \ + --dump-info # 导出 sdk info ``` 默认导出模型文件为 `{work-dir}/end2end.engine` @@ -530,23 +808,25 @@ backend_config = dict( ```shell # RTMDet +# 输入模型路径可以是本地路径,也可以是下载链接。 python tools/deploy.py \ configs/mmdet/detection/detection_onnxruntime_dynamic.py \ - {RTMPOSE_PROJECT}/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ - ../rtmdet_nano/rtmdet_nano.pth \ + ../mmpose/projects/rtmpose/rtmdet/person/rtmdet_nano_320-8xb32_coco-person.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmpose/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth \ demo/resources/human-pose.jpg \ - --work-dir mmdeploy_models/mmdet/sdk \ + --work-dir rtmpose-ort/rtmdet-nano \ --device cpu \ --show \ - --dump-info # 导出 sdk info + --dump-info # 导出 sdk info # RTMPose +# 输入模型路径可以是本地路径,也可以是下载链接。 python tools/deploy.py \ configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py \ - {RTMPOSE_PROJECT}/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ - ../rtmpose_m/rtmpose_m.pth \ + ../mmpose/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py \ + https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/rtmpose-m_simcc-aic-coco_pt-aic-coco_420e-256x192-63eb25f7_20230126.pth \ demo/resources/human-pose.jpg \ - --work-dir mmdeploy_models/mmpose/sdk \ + --work-dir rtmpose-ort/rtmpose-m \ --device cpu \ --show \ --dump-info # 导出 sdk info @@ -554,7 +834,7 @@ python tools/deploy.py \ 默认会导出三个 json 文件: -``` +```shell |----sdk |----end2end.onnx # ONNX model |----end2end.engine # TensorRT engine file @@ -572,7 +852,7 @@ import argparse import cv2 import numpy as np -from mmdeploy_python import PoseDetector +from mmdeploy_runtime import PoseDetector def parse_args(): parser = argparse.ArgumentParser( @@ -681,8 +961,8 @@ target_link_libraries(${name} PRIVATE mmdeploy ${OpenCV_LIBS}) #### 其他语言 -- [C# API 示例](https://github.com/open-mmlab/mmdeploy/tree/1.x/demo/csharp) -- [JAVA API 示例](https://github.com/open-mmlab/mmdeploy/tree/1.x/demo/java) +- [C# API 示例](https://github.com/open-mmlab/mmdeploy/tree/main/demo/csharp) +- [JAVA API 示例](https://github.com/open-mmlab/mmdeploy/tree/main/demo/java) ### 🚀 Pipeline 推理 @@ -695,7 +975,7 @@ target_link_libraries(${name} PRIVATE mmdeploy ${OpenCV_LIBS}) cd ${PATH_TO_MMDEPLOY}/build/bin/ # 单张图片推理 -./det_pose {det work-dir} {pose work-dir} {your_img.jpg} --device cpu +./det_pose rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_img.jpg --device cpu required arguments: det_model Detection 模型路径 [string] @@ -716,20 +996,22 @@ optional arguments: **API** **示例** -\- [`det_pose.py`](https://github.com/open-mmlab/mmdeploy/blob/dev-1.x/demo/python/det_pose.py) +\- [`det_pose.py`](https://github.com/open-mmlab/mmdeploy/blob/main/demo/python/det_pose.py) -\- [`det_pose.cxx`](https://github.com/open-mmlab/mmdeploy/blob/dev-1.x/demo/csrc/cpp/det_pose.cxx) +\- [`det_pose.cxx`](https://github.com/open-mmlab/mmdeploy/blob/main/demo/csrc/cpp/det_pose.cxx) #### 视频推理 如果用户有跟随 MMDeploy 安装教程进行正确编译,在 `mmdeploy/build/bin/` 路径下会看到 `pose_tracker` 的可执行文件。 +- 将 `input` 输入 `0` 可以使用摄像头推理 + ```shell # 前往 mmdeploy 目录 cd ${PATH_TO_MMDEPLOY}/build/bin/ # 视频推理 -./pose_tracker {det work-dir} {pose work-dir} {your_video.mp4} --device cpu +./pose_tracker rtmpose-ort/rtmdet-nano/ rtmpose-ort/rtmpose-m/ your_video.mp4 --device cpu required arguments: det_model Detection 模型路径 [string] @@ -768,9 +1050,9 @@ optional arguments: **API** **示例** -\- [`pose_tracker.py`](https://github.com/open-mmlab/mmdeploy/blob/dev-1.x/demo/python/pose_tracker.py) +\- [`pose_tracker.py`](https://github.com/open-mmlab/mmdeploy/blob/main/demo/python/pose_tracker.py) -\- [`pose_tracker.cxx`](https://github.com/open-mmlab/mmdeploy/blob/dev-1.x/demo/csrc/cpp/pose_tracker.cxx) +\- [`pose_tracker.cxx`](https://github.com/open-mmlab/mmdeploy/blob/main/demo/csrc/cpp/pose_tracker.cxx) ## 📚 常用功能 [🔝](#-table-of-contents) @@ -823,7 +1105,7 @@ python tools/profiler.py \ +--------+------------+---------+ ``` -如果你希望详细了解 profiler 的更多参数设置与功能,可以前往 [Profiler Docs](https://mmdeploy.readthedocs.io/en/1.x/02-how-to-run/useful_tools.html#profiler) +如果你希望详细了解 profiler 的更多参数设置与功能,可以前往 [Profiler Docs](https://mmdeploy.readthedocs.io/en/main/02-how-to-run/useful_tools.html#profiler) ### 📊 精度验证 [🔝](#-table-of-contents) @@ -837,7 +1119,7 @@ python tools/test.py \ --device cpu ``` -详细内容请参考 [MMDeploys Docs](https://github.com/open-mmlab/mmdeploy/blob/dev-1.x/docs/zh_cn/02-how-to-run/profile_model.md) +详细内容请参考 [MMDeploys Docs](https://github.com/open-mmlab/mmdeploy/blob/main/docs/zh_cn/02-how-to-run/profile_model.md) ## 📜 引用 [🔝](#-table-of-contents) diff --git a/projects/rtmpose/benchmark/README.md b/projects/rtmpose/benchmark/README.md index 13fe9c183f..46c036273c 100644 --- a/projects/rtmpose/benchmark/README.md +++ b/projects/rtmpose/benchmark/README.md @@ -113,4 +113,4 @@ The result is as follows: +--------+------------+---------+ ``` -If you want to learn more details of profiler, you can refer to the [Profiler Docs](https://mmdeploy.readthedocs.io/en/1.x/02-how-to-run/useful_tools.html#profiler). +If you want to learn more details of profiler, you can refer to the [Profiler Docs](https://mmdeploy.readthedocs.io/en/latest/02-how-to-run/useful_tools.html#profiler). diff --git a/projects/rtmpose/benchmark/README_CN.md b/projects/rtmpose/benchmark/README_CN.md index 08578f44f5..e1824d12b7 100644 --- a/projects/rtmpose/benchmark/README_CN.md +++ b/projects/rtmpose/benchmark/README_CN.md @@ -113,4 +113,4 @@ The result is as follows: +--------+------------+---------+ ``` -If you want to learn more details of profiler, you can refer to the [Profiler Docs](https://mmdeploy.readthedocs.io/en/1.x/02-how-to-run/useful_tools.html#profiler). +If you want to learn more details of profiler, you can refer to the [Profiler Docs](https://mmdeploy.readthedocs.io/en/latest/02-how-to-run/useful_tools.html#profiler). diff --git a/projects/rtmpose/examples/PoseTracker-Android-Prototype/README.md b/projects/rtmpose/examples/PoseTracker-Android-Prototype/README.md new file mode 100644 index 0000000000..edce803106 --- /dev/null +++ b/projects/rtmpose/examples/PoseTracker-Android-Prototype/README.md @@ -0,0 +1,5 @@ +# PoseTracker-Android-Prototype + +PoseTracker Android Demo Prototype, which is based on [mmdeploy](https://github.com/open-mmlab/mmdeploy/tree/dev-1.x) + +Please refer to [Original Repository](https://github.com/hanrui1sensetime/PoseTracker-Android-Prototype). diff --git a/projects/rtmpose/examples/README.md b/projects/rtmpose/examples/README.md new file mode 100644 index 0000000000..5846f039e7 --- /dev/null +++ b/projects/rtmpose/examples/README.md @@ -0,0 +1,18 @@ +## List of examples + +### 1. RTMPose-Deploy + +RTMPose-Deploy is a C++ code example for RTMPose localized deployment. + +- [ONNXRuntime-CPU](https://github.com/HW140701/RTMPose-Deploy) +- [TensorRT](https://github.com/Dominic23331/rtmpose_tensorrt) + +### 2. RTMPose inference with ONNXRuntime (Python) + +This example shows how to run RTMPose inference with ONNXRuntime in Python. + +### 3. PoseTracker Android Demo + +PoseTracker Android Demo Prototype based on mmdeploy. + +- [Original Repository](https://github.com/hanrui1sensetime/PoseTracker-Android-Prototype) diff --git a/projects/rtmpose/examples/RTMPose-Deploy/README.md b/projects/rtmpose/examples/RTMPose-Deploy/README.md new file mode 100644 index 0000000000..c4fce9a4df --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/README.md @@ -0,0 +1,12 @@ +# RTMPose-Deploy + +[中文说明](./README_CN.md) + +RTMPose-Deploy is a C ++ code example for RTMPose localized deployment. + +At present, RTMPose-Deploy has completed to use ONNXRuntime-CPU and TensorRT to deploy the RTMDet and RTMPose on the Windows system. + +| Deployment Framework | Repo | +| -------------------- | -------------------------------------------------------------------- | +| ONNXRuntime-CPU | [RTMPose-Deploy](https://github.com/HW140701/RTMPose-Deploy) | +| TensorRT | [rtmpose_tensorrt](https://github.com/Dominic23331/rtmpose_tensorrt) | diff --git a/projects/rtmpose/examples/RTMPose-Deploy/README_CN.md b/projects/rtmpose/examples/RTMPose-Deploy/README_CN.md new file mode 100644 index 0000000000..82ee093658 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/README_CN.md @@ -0,0 +1,10 @@ +# RTMPose-Deploy + +RTMPose-Deploy 是一个进行 RTMPose 本地化部署的 C++ 代码示例。 + +目前,RTMPose-Deploy 已完成在 Windows 系统上使用 OnnxRuntime CPU 和TensorRT 对 RTMDet 和 RTMPose 完成了部署。 + +| 部署框架 | 仓库 | +| --------------- | -------------------------------------------------------------------- | +| ONNXRuntime-CPU | [RTMPose-Deploy](https://github.com/HW140701/RTMPose-Deploy) | +| TensorRT | [rtmpose_tensorrt](https://github.com/Dominic23331/rtmpose_tensorrt) | diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/characterset_convert.h b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/characterset_convert.h new file mode 100644 index 0000000000..fe586e2356 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/characterset_convert.h @@ -0,0 +1,151 @@ +#ifndef _CHARACTERSET_CONVERT_H_ +#define _CHARACTERSET_CONVERT_H_ + +#include + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) + +#include + +#elif defined(linux) || defined(__linux) + +#include +#include + +#endif + +namespace stubbornhuang +{ + class CharactersetConvert + { + public: +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) + static std::wstring string_to_wstring(const std::string& str) + { + std::wstring result; + int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0); + wchar_t* wstr = new wchar_t[len + 1]; + memset(wstr, 0, len + 1); + MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, wstr, len); + wstr[len] = '\0'; + result.append(wstr); + delete[] wstr; + return result; + } + + static std::string gbk_to_utf8(const std::string& gbk_str) + { + int len = MultiByteToWideChar(CP_ACP, 0, gbk_str.c_str(), -1, NULL, 0); + wchar_t* wstr = new wchar_t[len + 1]; + memset(wstr, 0, len + 1); + MultiByteToWideChar(CP_ACP, 0, gbk_str.c_str(), -1, wstr, len); + len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); + char* str = new char[len + 1]; + memset(str, 0, len + 1); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL); + std::string strTemp = str; + if (wstr) delete[] wstr; + if (str) delete[] str; + return strTemp; + } + + static std::string utf8_to_gbk(const std::string& utf8_str) + { + int len = MultiByteToWideChar(CP_UTF8, 0, utf8_str.c_str(), -1, NULL, 0); + wchar_t* wszGBK = new wchar_t[len + 1]; + memset(wszGBK, 0, len * 2 + 2); + MultiByteToWideChar(CP_UTF8, 0, utf8_str.c_str(), -1, wszGBK, len); + len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL); + char* szGBK = new char[len + 1]; + memset(szGBK, 0, len + 1); + WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL); + std::string strTemp(szGBK); + if (wszGBK) delete[] wszGBK; + if (szGBK) delete[] szGBK; + return strTemp; + } + +#elif defined(linux) || defined(__linux) + static int code_convert( + const char* from_charset, + const char* to_charset, + char* inbuf, size_t inlen, + char* outbuf, size_t outlen + ) { + iconv_t cd; + char** pin = &inbuf; + char** pout = &outbuf; + + cd = iconv_open(to_charset, from_charset); + if (cd == 0) + return -1; + + memset(outbuf, 0, outlen); + + if ((int)iconv(cd, pin, &inlen, pout, &outlen) == -1) + { + iconv_close(cd); + return -1; + } + iconv_close(cd); + *pout = '\0'; + + return 0; + } + + static int u2g(char* inbuf, size_t inlen, char* outbuf, size_t outlen) { + return code_convert("utf-8", "gb2312", inbuf, inlen, outbuf, outlen); + } + + static int g2u(char* inbuf, size_t inlen, char* outbuf, size_t outlen) { + return code_convert("gb2312", "utf-8", inbuf, inlen, outbuf, outlen); + } + + + static std::string gbk_to_utf8(const std::string& gbk_str) + { + int length = gbk_str.size() * 2 + 1; + + char* temp = (char*)malloc(sizeof(char) * length); + + if (g2u((char*)gbk_str.c_str(), gbk_str.size(), temp, length) >= 0) + { + std::string str_result; + str_result.append(temp); + free(temp); + return str_result; + } + else + { + free(temp); + return ""; + } + } + + static std::string utf8_to_gbk(const std::string& utf8_str) + { + int length = strlen(utf8_str); + + char* temp = (char*)malloc(sizeof(char) * length); + + if (u2g((char*)utf8_str, length, temp, length) >= 0) + { + std::string str_result; + str_result.append(temp); + free(temp); + + return str_result; + } + else + { + free(temp); + return ""; + } + } + +#endif + + }; +} + +#endif // !_CHARACTERSET_CONVERT_H_ diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/main.cpp b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/main.cpp new file mode 100644 index 0000000000..b2175047a2 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/main.cpp @@ -0,0 +1,75 @@ +#include + +#include "opencv2/opencv.hpp" + +#include "rtmpose_utils.h" +#include "rtmpose_onnxruntime.h" +#include "rtmdet_onnxruntime.h" +#include "rtmpose_tracker_onnxruntime.h" + +std::vector> coco_17_joint_links = { + {0,1},{0,2},{1,3},{2,4},{5,7},{7,9},{6,8},{8,10},{5,6},{5,11},{6,12},{11,12},{11,13},{13,15},{12,14},{14,16} +}; + +int main() +{ + std::string rtm_detnano_onnx_path = ""; + std::string rtm_pose_onnx_path = ""; +#ifdef _DEBUG + rtm_detnano_onnx_path = "../../resource/model/rtmpose-cpu/rtmpose-ort/rtmdet-nano/end2end.onnx"; + rtm_pose_onnx_path = "../../resource/model/rtmpose-cpu/rtmpose-ort/rtmpose-m/end2end.onnx"; +#else + rtm_detnano_onnx_path = "./resource/model/rtmpose-cpu/rtmpose-ort/rtmdet-nano/end2end.onnx"; + rtm_pose_onnx_path = "./resource/model/rtmpose-cpu/rtmpose-ort/rtmpose-m/end2end.onnx"; +#endif + + RTMPoseTrackerOnnxruntime rtmpose_tracker_onnxruntime(rtm_detnano_onnx_path, rtm_pose_onnx_path); + + cv::VideoCapture video_reader(0); + int frame_num = 0; + DetectBox detect_box; + while (video_reader.isOpened()) + { + cv::Mat frame; + video_reader >> frame; + + if (frame.empty()) + break; + + std::pair> inference_box= rtmpose_tracker_onnxruntime.Inference(frame); + DetectBox detect_box = inference_box.first; + std::vector pose_result = inference_box.second; + + cv::rectangle( + frame, + cv::Point(detect_box.left, detect_box.top), + cv::Point(detect_box.right, detect_box.bottom), + cv::Scalar{ 255, 0, 0 }, + 2); + + for (int i = 0; i < pose_result.size(); ++i) + { + cv::circle(frame, cv::Point(pose_result[i].x, pose_result[i].y), 1, cv::Scalar{ 0, 0, 255 }, 5, cv::LINE_AA); + } + + for (int i = 0; i < coco_17_joint_links.size(); ++i) + { + std::pair joint_links = coco_17_joint_links[i]; + cv::line( + frame, + cv::Point(pose_result[joint_links.first].x, pose_result[joint_links.first].y), + cv::Point(pose_result[joint_links.second].x, pose_result[joint_links.second].y), + cv::Scalar{ 0, 255, 0 }, + 2, + cv::LINE_AA); + } + + imshow("RTMPose", frame); + cv::waitKey(1); + } + + video_reader.release(); + cv::destroyAllWindows(); + + return 0; +} diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmdet_onnxruntime.cpp b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmdet_onnxruntime.cpp new file mode 100644 index 0000000000..85e111b2f6 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmdet_onnxruntime.cpp @@ -0,0 +1,174 @@ +#include "rtmdet_onnxruntime.h" + +#include +#include + +#include "characterset_convert.h" + + +RTMDetOnnxruntime::RTMDetOnnxruntime(const std::string& onnx_model_path) + :m_session(nullptr), + m_env(nullptr) +{ + std::wstring onnx_model_path_wstr = stubbornhuang::CharactersetConvert::string_to_wstring(onnx_model_path); + + m_env = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "rtmdet_onnxruntime_cpu"); + + int cpu_processor_num = std::thread::hardware_concurrency(); + cpu_processor_num /= 2; + + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(cpu_processor_num); + session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); + session_options.SetLogSeverityLevel(4); + + OrtSessionOptionsAppendExecutionProvider_CPU(session_options, 0); + m_session = Ort::Session(m_env, onnx_model_path_wstr.c_str(), session_options); + + PrintModelInfo(m_session); +} + +RTMDetOnnxruntime::~RTMDetOnnxruntime() +{ +} + +DetectBox RTMDetOnnxruntime::Inference(const cv::Mat& input_mat) +{ + // Deep copy + cv::Mat input_mat_copy; + input_mat.copyTo(input_mat_copy); + + // BGR to RGB + cv::Mat input_mat_copy_rgb; + cv::cvtColor(input_mat_copy, input_mat_copy_rgb, CV_BGR2RGB); + + // image data, HWC->CHW, image_data - mean / std normalize + int image_height = input_mat_copy_rgb.rows; + int image_width = input_mat_copy_rgb.cols; + int image_channels = input_mat_copy_rgb.channels(); + + std::vector input_image_array; + input_image_array.resize(1 * image_channels * image_height * image_width); + + float* input_image = input_image_array.data(); + for (int h = 0; h < image_height; ++h) + { + for (int w = 0; w < image_width; ++w) + { + for (int c = 0; c < image_channels; ++c) + { + int chw_index = c * image_height * image_width + h * image_width + w; + + float tmp = input_mat_copy_rgb.ptr(h)[w * 3 + c]; + + input_image[chw_index] = (tmp - IMAGE_MEAN[c]) / IMAGE_STD[c]; + } + } + } + + // inference + std::vector m_onnx_input_names{ "input" }; + std::vector m_onnx_output_names{ "dets","labels"}; + std::array input_shape{ 1, image_channels, image_height, image_width }; + + auto memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); + Ort::Value input_tensor = Ort::Value::CreateTensor( + memory_info, + input_image_array.data(), + input_image_array.size(), + input_shape.data(), + input_shape.size() + ); + + assert(input_tensor.IsTensor()); + + auto output_tensors = m_session.Run( + Ort::RunOptions{ nullptr }, + m_onnx_input_names.data(), + &input_tensor, + 1, + m_onnx_output_names.data(), + m_onnx_output_names.size() + ); + + // pose process + std::vector det_result_dims = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape(); + std::vector label_result_dims = output_tensors[1].GetTensorTypeAndShapeInfo().GetShape(); + + assert(det_result_dims.size() == 3 && label_result_dims.size() == 2); + + int batch_size = det_result_dims[0] == label_result_dims[0] ? det_result_dims[0] : 0; + int num_dets = det_result_dims[1] == label_result_dims[1] ? det_result_dims[1] : 0; + int reshap_dims = det_result_dims[2]; + + float* det_result = output_tensors[0].GetTensorMutableData(); + int* label_result = output_tensors[1].GetTensorMutableData(); + + std::vector all_box; + for (int i = 0; i < num_dets; ++i) + { + int classes = label_result[i]; + if (classes != 0) + continue; + + DetectBox temp_box; + temp_box.left = int(det_result[i * reshap_dims]); + temp_box.top = int(det_result[i * reshap_dims + 1]); + temp_box.right = int(det_result[i * reshap_dims + 2]); + temp_box.bottom = int(det_result[i * reshap_dims + 3]); + temp_box.score = det_result[i * reshap_dims + 4]; + temp_box.label = label_result[i]; + + all_box.emplace_back(temp_box); + } + + // descending sort + std::sort(all_box.begin(), all_box.end(), BoxCompare); + + //cv::rectangle(input_mat_copy, cv::Point{ all_box[0].left, all_box[0].top }, cv::Point{ all_box[0].right, all_box[0].bottom }, cv::Scalar{ 0, 255, 0 }); + + //cv::imwrite("detect.jpg", input_mat_copy); + + DetectBox result_box; + + if (!all_box.empty()) + { + result_box = all_box[0]; + } + + return result_box; +} + +void RTMDetOnnxruntime::PrintModelInfo(Ort::Session& session) +{ + // print the number of model input nodes + size_t num_input_nodes = session.GetInputCount(); + size_t num_output_nodes = session.GetOutputCount(); + std::cout << "Number of input node is:" << num_input_nodes << std::endl; + std::cout << "Number of output node is:" << num_output_nodes << std::endl; + + // print node name + Ort::AllocatorWithDefaultOptions allocator; + std::cout << std::endl; + for (auto i = 0; i < num_input_nodes; i++) + std::cout << "The input op-name " << i << " is:" << session.GetInputNameAllocated(i, allocator) << std::endl; + for (auto i = 0; i < num_output_nodes; i++) + std::cout << "The output op-name " << i << " is:" << session.GetOutputNameAllocated(i, allocator) << std::endl; + + + // print input and output dims + for (auto i = 0; i < num_input_nodes; i++) + { + std::vector input_dims = session.GetInputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape(); + std::cout << std::endl << "input " << i << " dim is: "; + for (auto j = 0; j < input_dims.size(); j++) + std::cout << input_dims[j] << " "; + } + for (auto i = 0; i < num_output_nodes; i++) + { + std::vector output_dims = session.GetOutputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape(); + std::cout << std::endl << "output " << i << " dim is: "; + for (auto j = 0; j < output_dims.size(); j++) + std::cout << output_dims[j] << " "; + } +} diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmdet_onnxruntime.h b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmdet_onnxruntime.h new file mode 100644 index 0000000000..72500bc9c1 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmdet_onnxruntime.h @@ -0,0 +1,32 @@ +#ifndef _RTM_DET_ONNX_RUNTIME_H_ +#define _RTM_DET_ONNX_RUNTIME_H_ + +#include + +#include "opencv2/opencv.hpp" + +#include "onnxruntime_cxx_api.h" +#include "cpu_provider_factory.h" +#include "rtmpose_utils.h" + + +class RTMDetOnnxruntime +{ +public: + RTMDetOnnxruntime() = delete; + RTMDetOnnxruntime(const std::string& onnx_model_path); + virtual~RTMDetOnnxruntime(); + +public: + DetectBox Inference(const cv::Mat& input_mat); + +private: + void PrintModelInfo(Ort::Session& session); + +private: + Ort::Env m_env; + Ort::Session m_session; + +}; + +#endif // !_RTM_DET_ONNX_RUNTIME_H_ diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_onnxruntime.cpp b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_onnxruntime.cpp new file mode 100644 index 0000000000..debdda570b --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_onnxruntime.cpp @@ -0,0 +1,261 @@ +#include "rtmpose_onnxruntime.h" + +#include +#include + +#include "characterset_convert.h" +#include "rtmpose_utils.h" + +#undef max + + +RTMPoseOnnxruntime::RTMPoseOnnxruntime(const std::string& onnx_model_path) + :m_session(nullptr) +{ + std::wstring onnx_model_path_wstr = stubbornhuang::CharactersetConvert::string_to_wstring(onnx_model_path); + + m_env = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "rtmpose_onnxruntime_cpu"); + + int cpu_processor_num = std::thread::hardware_concurrency(); + cpu_processor_num /= 2; + + Ort::SessionOptions session_options; + session_options.SetIntraOpNumThreads(cpu_processor_num); + session_options.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_ALL); + session_options.SetLogSeverityLevel(4); + + OrtSessionOptionsAppendExecutionProvider_CPU(session_options, 0); + m_session = Ort::Session(m_env, onnx_model_path_wstr.c_str(), session_options); + + PrintModelInfo(m_session); +} + +RTMPoseOnnxruntime::~RTMPoseOnnxruntime() +{ +} + +std::vector RTMPoseOnnxruntime::Inference(const cv::Mat& input_mat, const DetectBox& box) +{ + std::vector pose_result; + + if (!box.IsValid()) + return pose_result; + + std::pair crop_result_pair = CropImageByDetectBox(input_mat, box); + + cv::Mat crop_mat = crop_result_pair.first; + cv::Mat affine_transform_reverse = crop_result_pair.second; + + // deep copy + cv::Mat crop_mat_copy; + crop_mat.copyTo(crop_mat_copy); + + // BGR to RGB + cv::Mat input_mat_copy_rgb; + cv::cvtColor(crop_mat, input_mat_copy_rgb, CV_BGR2RGB); + + // image data, HWC->CHW, image_data - mean / std normalize + int image_height = input_mat_copy_rgb.rows; + int image_width = input_mat_copy_rgb.cols; + int image_channels = input_mat_copy_rgb.channels(); + + std::vector input_image_array; + input_image_array.resize(1 * image_channels * image_height * image_width); + + float* input_image = input_image_array.data(); + for (int h = 0; h < image_height; ++h) + { + for (int w = 0; w < image_width; ++w) + { + for (int c = 0; c < image_channels; ++c) + { + int chw_index = c * image_height * image_width + h * image_width + w; + + float tmp = input_mat_copy_rgb.ptr(h)[w * 3 + c]; + + input_image[chw_index] = (tmp - IMAGE_MEAN[c]) / IMAGE_STD[c]; + } + } + } + + // inference + std::vector m_onnx_input_names{ "input" }; + std::vector m_onnx_output_names{ "simcc_x","simcc_y" }; + std::array input_shape{ 1, image_channels, image_height, image_width }; + + auto memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); + Ort::Value input_tensor = Ort::Value::CreateTensor( + memory_info, + input_image_array.data(), + input_image_array.size(), + input_shape.data(), + input_shape.size() + ); + + assert(input_tensor.IsTensor()); + + auto output_tensors = m_session.Run( + Ort::RunOptions{ nullptr }, + m_onnx_input_names.data(), + &input_tensor, + 1, + m_onnx_output_names.data(), + m_onnx_output_names.size() + ); + + // pose process + std::vector simcc_x_dims = output_tensors[0].GetTensorTypeAndShapeInfo().GetShape(); + std::vector simcc_y_dims = output_tensors[1].GetTensorTypeAndShapeInfo().GetShape(); + + assert(simcc_x_dims.size() == 3 && simcc_y_dims.size() == 3); + + int batch_size = simcc_x_dims[0] == simcc_y_dims[0] ? simcc_x_dims[0] : 0; + int joint_num = simcc_x_dims[1] == simcc_y_dims[1] ? simcc_x_dims[1] : 0; + int extend_width = simcc_x_dims[2]; + int extend_height = simcc_y_dims[2]; + + float* simcc_x_result = output_tensors[0].GetTensorMutableData(); + float* simcc_y_result = output_tensors[1].GetTensorMutableData(); + + + for (int i = 0; i < joint_num; ++i) + { + // find the maximum and maximum indexes in the value of each Extend_width length + auto x_biggest_iter = std::max_element(simcc_x_result + i * extend_width, simcc_x_result + i * extend_width + extend_width); + int max_x_pos = std::distance(simcc_x_result + i * extend_width, x_biggest_iter); + int pose_x = max_x_pos / 2; + float score_x = *x_biggest_iter; + + // find the maximum and maximum indexes in the value of each exten_height length + auto y_biggest_iter = std::max_element(simcc_y_result + i * extend_height, simcc_y_result + i * extend_height + extend_height); + int max_y_pos = std::distance(simcc_y_result + i * extend_height, y_biggest_iter); + int pose_y = max_y_pos / 2; + float score_y = *y_biggest_iter; + + //float score = (score_x + score_y) / 2; + float score = std::max(score_x, score_y); + + PosePoint temp_point; + temp_point.x = int(pose_x); + temp_point.y = int(pose_y); + temp_point.score = score; + pose_result.emplace_back(temp_point); + } + + // anti affine transformation to obtain the coordinates on the original picture + for (int i = 0; i < pose_result.size(); ++i) + { + cv::Mat origin_point_Mat = cv::Mat::ones(3, 1, CV_64FC1); + origin_point_Mat.at(0, 0) = pose_result[i].x; + origin_point_Mat.at(1, 0) = pose_result[i].y; + + cv::Mat temp_result_mat = affine_transform_reverse * origin_point_Mat; + + pose_result[i].x = temp_result_mat.at(0, 0); + pose_result[i].y = temp_result_mat.at(1, 0); + } + + return pose_result; +} + +std::pair RTMPoseOnnxruntime::CropImageByDetectBox(const cv::Mat& input_image, const DetectBox& box) +{ + std::pair result_pair; + + if (!input_image.data) + { + return result_pair; + } + + if (!box.IsValid()) + { + return result_pair; + } + + // deep copy + cv::Mat input_mat_copy; + input_image.copyTo(input_mat_copy); + + // calculate the width, height and center points of the human detection box + int box_width = box.right - box.left; + int box_height = box.bottom - box.top; + int box_center_x = box.left + box_width / 2; + int box_center_y = box.top + box_height / 2; + + float aspect_ratio = 192.0 / 256.0; + + // adjust the width and height ratio of the size of the picture in the RTMPOSE input + if (box_width > (aspect_ratio * box_height)) + { + box_height = box_width / aspect_ratio; + } + else if (box_width < (aspect_ratio * box_height)) + { + box_width = box_height * aspect_ratio; + } + + float scale_image_width = box_width * 1.2; + float scale_image_height = box_height * 1.2; + + // get the affine matrix + cv::Mat affine_transform = GetAffineTransform( + box_center_x, + box_center_y, + scale_image_width, + scale_image_height, + 192, + 256 + ); + + cv::Mat affine_transform_reverse = GetAffineTransform( + box_center_x, + box_center_y, + scale_image_width, + scale_image_height, + 192, + 256, + true + ); + + // affine transform + cv::Mat affine_image; + cv::warpAffine(input_mat_copy, affine_image, affine_transform, cv::Size(192, 256), cv::INTER_LINEAR); + //cv::imwrite("affine_img.jpg", affine_image); + + result_pair = std::make_pair(affine_image, affine_transform_reverse); + + return result_pair; +} + +void RTMPoseOnnxruntime::PrintModelInfo(Ort::Session& session) +{ + // print the number of model input nodes + size_t num_input_nodes = session.GetInputCount(); + size_t num_output_nodes = session.GetOutputCount(); + std::cout << "Number of input node is:" << num_input_nodes << std::endl; + std::cout << "Number of output node is:" << num_output_nodes << std::endl; + + // print node name + Ort::AllocatorWithDefaultOptions allocator; + std::cout << std::endl; + for (auto i = 0; i < num_input_nodes; i++) + std::cout << "The input op-name " << i << " is:" << session.GetInputNameAllocated(i, allocator) << std::endl; + for (auto i = 0; i < num_output_nodes; i++) + std::cout << "The output op-name " << i << " is:" << session.GetOutputNameAllocated(i, allocator) << std::endl; + + // print input and output dims + for (auto i = 0; i < num_input_nodes; i++) + { + std::vector input_dims = session.GetInputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape(); + std::cout << std::endl << "input " << i << " dim is: "; + for (auto j = 0; j < input_dims.size(); j++) + std::cout << input_dims[j] << " "; + } + for (auto i = 0; i < num_output_nodes; i++) + { + std::vector output_dims = session.GetOutputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape(); + std::cout << std::endl << "output " << i << " dim is: "; + for (auto j = 0; j < output_dims.size(); j++) + std::cout << output_dims[j] << " "; + } +} diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_onnxruntime.h b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_onnxruntime.h new file mode 100644 index 0000000000..f23adacb34 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_onnxruntime.h @@ -0,0 +1,34 @@ +#ifndef _RTM_POSE_ONNXRUNTIME_H_ +#define _RTM_POSE_ONNXRUNTIME_H_ + +#include + +#include "onnxruntime_cxx_api.h" +#include "cpu_provider_factory.h" +#include "opencv2/opencv.hpp" + +#include "rtmdet_onnxruntime.h" +#include "rtmpose_utils.h" + +class RTMPoseOnnxruntime +{ +public: + RTMPoseOnnxruntime() = delete; + RTMPoseOnnxruntime(const std::string& onnx_model_path); + virtual~RTMPoseOnnxruntime(); + +public: + std::vector Inference(const cv::Mat& input_mat, const DetectBox& box); + +private: + std::pair CropImageByDetectBox(const cv::Mat& input_image, const DetectBox& box); + +private: + void PrintModelInfo(Ort::Session& session); + +private: + Ort::Env m_env; + Ort::Session m_session; +}; + +#endif // !_RTM_POSE_ONNXRUNTIME_H_ diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_tracker_onnxruntime.cpp b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_tracker_onnxruntime.cpp new file mode 100644 index 0000000000..4ad83ada47 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_tracker_onnxruntime.cpp @@ -0,0 +1,34 @@ +#include "rtmpose_tracker_onnxruntime.h" + +RTMPoseTrackerOnnxruntime::RTMPoseTrackerOnnxruntime(const std::string& det_model_path, const std::string& pose_model_path, int dectect_interval) + :m_rtm_det_ptr(nullptr), + m_rtm_pose_ptr(nullptr), + m_frame_num(0), + m_dectect_interval(dectect_interval) +{ + m_rtm_det_ptr = std::make_unique(det_model_path); + m_rtm_pose_ptr = std::make_unique(pose_model_path); +} + +RTMPoseTrackerOnnxruntime::~RTMPoseTrackerOnnxruntime() +{ +} + +std::pair> RTMPoseTrackerOnnxruntime::Inference(const cv::Mat& input_mat) +{ + std::pair> result; + + if (m_rtm_det_ptr == nullptr || m_rtm_pose_ptr == nullptr) + return result; + + if (m_frame_num % m_dectect_interval == 0) + { + m_detect_box = m_rtm_det_ptr->Inference(input_mat); + } + + std::vector pose_result = m_rtm_pose_ptr->Inference(input_mat, m_detect_box); + + m_frame_num += 1; + + return std::make_pair(m_detect_box, pose_result); +} diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_tracker_onnxruntime.h b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_tracker_onnxruntime.h new file mode 100644 index 0000000000..76cb8a261b --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_tracker_onnxruntime.h @@ -0,0 +1,32 @@ +#ifndef _RTM_POSE_TRACKER_ONNXRUNTIME_H_ +#define _RTM_POSE_TRACKER_ONNXRUNTIME_H_ + +#include "rtmdet_onnxruntime.h" +#include "rtmpose_onnxruntime.h" + +#include +#include + +class RTMPoseTrackerOnnxruntime +{ +public: + RTMPoseTrackerOnnxruntime() = delete; + RTMPoseTrackerOnnxruntime( + const std::string& det_model_path, + const std::string& pose_model_path, + int dectect_interval = 10 + ); + virtual~RTMPoseTrackerOnnxruntime(); + +public: + std::pair> Inference(const cv::Mat& input_mat); + +private: + std::unique_ptr m_rtm_det_ptr; + std::unique_ptr m_rtm_pose_ptr; + unsigned int m_frame_num; + DetectBox m_detect_box; + int m_dectect_interval; +}; + +#endif // !_RTM_POSE_TRACKER_ONNXRUNTIME_H_ diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_utils.h b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_utils.h new file mode 100644 index 0000000000..6ecb9ccd1b --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/OnnxRumtime-CPU/src/RTMPoseOnnxRuntime/rtmpose_utils.h @@ -0,0 +1,115 @@ +#ifndef _RTM_POSE_UTILS_H_ +#define _RTM_POSE_UTILS_H_ + +#include "opencv2/opencv.hpp" + +const std::vector IMAGE_MEAN{ 123.675, 116.28, 103.53 }; +const std::vector IMAGE_STD{ 58.395, 57.12, 57.375 }; + +struct DetectBox +{ + int left; + int top; + int right; + int bottom; + float score; + int label; + + DetectBox() + { + left = -1; + top = -1; + right = -1; + bottom = -1; + score = -1.0; + label = -1; + } + + bool IsValid() const + { + return left != -1 && top != -1 && right != -1 && bottom != -1 && score != -1.0 && label != -1; + } +}; + +static bool BoxCompare( + const DetectBox& a, + const DetectBox& b) { + return a.score > b.score; +} + +struct PosePoint +{ + int x; + int y; + float score; + + PosePoint() + { + x = 0; + y = 0; + score = 0.0; + } +}; + +typedef PosePoint Vector2D; + + +static cv::Mat GetAffineTransform(float center_x, float center_y, float scale_width, float scale_height, int output_image_width, int output_image_height, bool inverse = false) +{ + // solve the affine transformation matrix + + // get the three points corresponding to the source picture and the target picture + cv::Point2f src_point_1; + src_point_1.x = center_x; + src_point_1.y = center_y; + + cv::Point2f src_point_2; + src_point_2.x = center_x; + src_point_2.y = center_y - scale_width * 0.5; + + cv::Point2f src_point_3; + src_point_3.x = src_point_2.x - (src_point_1.y - src_point_2.y); + src_point_3.y = src_point_2.y + (src_point_1.x - src_point_2.x); + + + float alphapose_image_center_x = output_image_width / 2; + float alphapose_image_center_y = output_image_height / 2; + + cv::Point2f dst_point_1; + dst_point_1.x = alphapose_image_center_x; + dst_point_1.y = alphapose_image_center_y; + + cv::Point2f dst_point_2; + dst_point_2.x = alphapose_image_center_x; + dst_point_2.y = alphapose_image_center_y - output_image_width * 0.5; + + cv::Point2f dst_point_3; + dst_point_3.x = dst_point_2.x - (dst_point_1.y - dst_point_2.y); + dst_point_3.y = dst_point_2.y + (dst_point_1.x - dst_point_2.x); + + + cv::Point2f srcPoints[3]; + srcPoints[0] = src_point_1; + srcPoints[1] = src_point_2; + srcPoints[2] = src_point_3; + + cv::Point2f dstPoints[3]; + dstPoints[0] = dst_point_1; + dstPoints[1] = dst_point_2; + dstPoints[2] = dst_point_3; + + // get affine matrix + cv::Mat affineTransform; + if (inverse) + { + affineTransform = cv::getAffineTransform(dstPoints, srcPoints); + } + else + { + affineTransform = cv::getAffineTransform(srcPoints, dstPoints); + } + + return affineTransform; +} + +#endif // !_RTM_POSE_UTILS_H_ diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/README.md b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/README.md new file mode 100644 index 0000000000..c9615d89d3 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/README.md @@ -0,0 +1,73 @@ +# rtmpose_tensorrt + +## Description + +This repository is use the TensorRT to deploy RTMDet and RTMPose. Your computer should have these components: + +- NVIDIA GPU +- CUDA +- cudnn +- TensorRT 8.x +- OPENCV +- VS2019 + +The effect of the code is as follows: + +![mabaoguo](https://github.com/Dominic23331/rtmpose_tensorrt/assets/53283758/568563be-a31d-4d03-9629-842dad3745e2) + +## Get Started + +### I. Convert Model + +#### 1. RTMDet + +When you start to convert a RTMDet model, you can use **convert_rtmdet.py** to convert pth file to onnx. + +```shell +python convert_rtmdet.py --config --checkpoint --output +``` + +Note that RTMDet should be the mmdetection version, and the conversion of mmyolo is not supported. + +#### 2. RTMPose + +You can use mmdeploy to convert RTMPose. The mmdeploy config file should use **configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py**. The convert command as follow: + +```shell +python tools/deploy.py +``` + +#### 3. Convert to TensorRT engine file + +You can use trtexec to convert an ONNX file to engine file. The command as follow: + +``` +trtexec --onnx= --saveEngine= +``` + +**Note that the engine files included in the project are only for storing examples. As the engine files generated by TensorRT are related to hardware, it is necessary to regenerate the engine files on the computer where the code needs to be run.** + +### II. Run + +At first, you should fill in the model locations for RTMDet and RTMPose as follows: + +```c++ +// set engine file path +string detEngineFile = "./model/rtmdet.engine"; +string poseEngineFile = "./model/rtmpose_m.engine"; +``` + +Then, you can set the cap to video file or camera. + +``` +// open cap +cv::VideoCapture cap(0); +``` + +If you want to change iou threshold or confidence threshold, you can change them when you initialize RTMDet model. + +``` +RTMDet det_model(detEngineFile, logger, 0.5, 0.65); +``` + +Finally, you can run the **main.cpp** file to get result. diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/python/convert_rtmdet.py b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/python/convert_rtmdet.py new file mode 100644 index 0000000000..81196413dd --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/python/convert_rtmdet.py @@ -0,0 +1,115 @@ +import argparse + +import torch +import torch.nn.functional as F +from mmdet.apis import init_detector +from torch import nn + + +def build_model_from_cfg(config_path: str, checkpoint_path: str, device): + model = init_detector(config_path, checkpoint_path, device=device) + model.eval() + return model + + +class RTMDet(nn.Module): + """Load RTMDet model and add postprocess. + + Args: + model (nn.Module): The RTMDet model. + """ + + def __init__(self, model: nn.Module) -> None: + super().__init__() + self.model = model + self.stage = [80, 40, 20] + self.input_shape = 640 + + def forward(self, inputs): + """model forward function.""" + boxes = [] + neck_outputs = self.model(inputs) + for i, (cls, box) in enumerate(zip(*neck_outputs)): + cls = cls.permute(0, 2, 3, 1) + box = box.permute(0, 2, 3, 1) + box = self.decode(box, cls, i) + boxes.append(box) + result_box = torch.cat(boxes, dim=1) + return result_box + + def decode(self, box: torch.Tensor, cls: torch.Tensor, stage: int): + """RTMDet postprocess function. + + Args: + box (torch.Tensor): output boxes. + cls (torch.Tensor): output cls. + stage (int): RTMDet output stage. + + Returns: + torch.Tensor: The decode boxes. + Format is [x1, y1, x2, y2, class, confidence] + """ + cls = F.sigmoid(cls) + conf = torch.max(cls, dim=3, keepdim=True)[0] + cls = torch.argmax(cls, dim=3, keepdim=True).to(torch.float32) + + box = torch.cat([box, cls, conf], dim=-1) + + step = self.input_shape // self.stage[stage] + + block_step = torch.linspace( + 0, self.stage[stage] - 1, steps=self.stage[stage], + device='cuda') * step + block_x = torch.broadcast_to(block_step, + [self.stage[stage], self.stage[stage]]) + block_y = torch.transpose(block_x, 1, 0) + block_x = torch.unsqueeze(block_x, 0) + block_y = torch.unsqueeze(block_y, 0) + block = torch.stack([block_x, block_y], -1) + + box[..., :2] = block - box[..., :2] + box[..., 2:4] = block + box[..., 2:4] + box = box.reshape(1, -1, 6) + return box + + +def parse_args(): + parser = argparse.ArgumentParser( + description='convert rtmdet model to ONNX.') + parser.add_argument( + '--config', type=str, help='rtmdet config file path from mmdetection.') + parser.add_argument( + '--checkpoint', + type=str, + help='rtmdet checkpoint path from mmdetection.') + parser.add_argument('--output', type=str, help='output filename.') + parser.add_argument( + '--device', + type=str, + default='cuda:0', + help='Device used for inference') + parser.add_argument( + '--input-name', type=str, default='image', help='ONNX input name.') + parser.add_argument( + '--output-name', type=str, default='output', help='ONNX output name.') + parser.add_argument( + '--opset', type=int, default=11, help='ONNX opset version.') + args = parser.parse_args() + return args + + +if __name__ == '__main__': + args = parse_args() + + model = build_model_from_cfg(args.config, args.checkpoint, args.device) + rtmdet = RTMDet(model) + rtmdet.eval() + x = torch.randn((1, 3, 640, 640), device=args.device) + + torch.onnx.export( + rtmdet, + x, + args.output, + input_names=[args.input_name], + output_names=[args.output_name], + opset_version=args.opset) diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/inference.cpp b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/inference.cpp new file mode 100644 index 0000000000..bc4e8449a7 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/inference.cpp @@ -0,0 +1,38 @@ +#include "inference.h" + + +/** + * @brief Inference network + * @param image Input image + * @param detect_model RTMDet model + * @param pose_model RTMPose model + * @return Inference result +*/ +std::vector> inference(cv::Mat& image, RTMDet& detect_model, RTMPose& pose_model) +{ + cv::Mat im0; + image.copyTo(im0); + + // inference detection model + std::vector det_result = detect_model.predict(image); + std::vector> result; + for (int i = 0; i < det_result.size(); i++) + { + // Select the detection box labeled as human + if (!isEqual(det_result[i].cls, 0.0)) + continue; + + // cut image to input the pose model + cv::Mat person_image = img_cut(im0, det_result[i].x1, det_result[i].y1, det_result[i].x2, det_result[i].y2); + std::vector pose_result = pose_model.predict(person_image); + + // Restore points to original image + for (int j = 0; j < pose_result.size(); j++) + { + pose_result[j].x += det_result[i].x1; + pose_result[j].y += det_result[i].y1; + } + result.push_back(pose_result); + } + return result; +} diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/inference.h b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/inference.h new file mode 100644 index 0000000000..8f603ffc1c --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/inference.h @@ -0,0 +1,14 @@ +#pragma once +#include +#include + +#include +#include + +#include "rtmdet.h" +#include "rtmpose.h" +#include "utils.h" + + + +std::vector> inference(cv::Mat& image, RTMDet& detect_model, RTMPose& pose_model); diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/main.cpp b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/main.cpp new file mode 100644 index 0000000000..3799bca896 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/main.cpp @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include + +#include "rtmdet.h" +#include "rtmpose.h" +#include "utils.h" +#include "inference.h" + + +using namespace std; + +/** + * @brief Setting up Tensorrt logger +*/ +class Logger : public nvinfer1::ILogger +{ + void log(Severity severity, const char* msg) noexcept override + { + // Only output logs with severity greater than warning + if (severity <= Severity::kWARNING) + std::cout << msg << std::endl; + } +}logger; + + +int main() +{ + // set engine file path + string detEngineFile = "./model/rtmdet.engine"; + string poseEngineFile = "./model/rtmpose_m.engine"; + + // init model + RTMDet det_model(detEngineFile, logger); + RTMPose pose_model(poseEngineFile, logger); + + // open cap + cv::VideoCapture cap(0); + + while (cap.isOpened()) + { + cv::Mat frame; + cv::Mat show_frame; + cap >> frame; + + if (frame.empty()) + break; + + frame.copyTo(show_frame); + auto result = inference(frame, det_model, pose_model); + draw_pose(show_frame, result); + + cv::imshow("result", show_frame); + if (cv::waitKey(1) == 'q') + break; + } + cv::destroyAllWindows(); + cap.release(); + + return 0; +} diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/rtmdet.cpp b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/rtmdet.cpp new file mode 100644 index 0000000000..abc8ebd32d --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/rtmdet.cpp @@ -0,0 +1,198 @@ +#include "rtmdet.h" + + +// set network params +float RTMDet::input_h = 640; +float RTMDet::input_w = 640; +float RTMDet::mean[3] = { 123.675, 116.28, 103.53 }; +float RTMDet::std[3] = { 58.395, 57.12, 57.375 }; + +/** + * @brief RTMDet`s constructor + * @param model_path RTMDet engine file path + * @param logger Nvinfer ILogger + * @param conf_thre The confidence threshold + * @param iou_thre The iou threshold of nms +*/ +RTMDet::RTMDet(std::string model_path, nvinfer1::ILogger& logger, float conf_thre, float iou_thre) : conf_thre(conf_thre), iou_thre(iou_thre) +{ + // read the engine file + std::ifstream engineStream(model_path, std::ios::binary); + engineStream.seekg(0, std::ios::end); + const size_t modelSize = engineStream.tellg(); + engineStream.seekg(0, std::ios::beg); + std::unique_ptr engineData(new char[modelSize]); + engineStream.read(engineData.get(), modelSize); + engineStream.close(); + + // create tensorrt model + runtime = nvinfer1::createInferRuntime(logger); + engine = runtime->deserializeCudaEngine(engineData.get(), modelSize); + context = engine->createExecutionContext(); + + // Define input dimensions + context->setBindingDimensions(0, nvinfer1::Dims4(1, 3, input_h, input_w)); + + // create CUDA stream + cudaStreamCreate(&stream); + + // Initialize offset + offset.push_back(0); + offset.push_back(0); +} + + +/** + * @brief RTMDet`s destructor +*/ +RTMDet::~RTMDet() +{ + cudaFree(stream); + cudaFree(buffer[0]); + cudaFree(buffer[1]); +} + + +/** + * @brief Display network input and output parameters +*/ +void RTMDet::show() +{ + for (int i = 0; i < engine->getNbBindings(); i++) + { + std::cout << "node: " << engine->getBindingName(i) << ", "; + if (engine->bindingIsInput(i)) + { + std::cout << "type: input" << ", "; + } + else + { + std::cout << "type: output" << ", "; + } + nvinfer1::Dims dim = engine->getBindingDimensions(i); + std::cout << "dimensions: "; + for (int d = 0; d < dim.nbDims; d++) + { + std::cout << dim.d[d] << " "; + } + std::cout << "\n"; + } +} + + +/** + * @brief Network preprocessing function + * @param image Input image + * @return Processed Tensor +*/ +std::vector RTMDet::preprocess(cv::Mat& image) +{ + // resize image + std::tuple resized = resize(image, input_w, input_h); + cv::Mat resized_image = std::get<0>(resized); + offset[0] = std::get<1>(resized); + offset[1] = std::get<2>(resized); + + // BGR2RGB + cv::cvtColor(resized_image, resized_image, cv::COLOR_BGR2RGB); + + // subtract mean and divide variance + std::vector input_tensor; + for (int k = 0; k < 3; k++) + { + for (int i = 0; i < resized_image.rows; i++) + { + for (int j = 0; j < resized_image.cols; j++) + { + input_tensor.emplace_back(((float)resized_image.at(i, j)[k] - mean[k]) / std[k]); + } + } + } + + return input_tensor; +} + + +/** + * @brief Network post-processing function + * @param boxes_result The result of rtmdet + * @param img_w The width of input image + * @param img_h The height of input image + * @return Detect boxes +*/ +std::vector RTMDet::postprocess(std::vector boxes_result, int img_w, int img_h) +{ + std::vector result; + std::vector buff; + for (int i = 0; i < 8400; i++) + { + // x1, y1, x2, y2, class, confidence + buff.insert(buff.end(), boxes_result.begin() + i * 6, boxes_result.begin() + i * 6 + 6); + // drop the box which confidence less than threshold + if (buff[5] < conf_thre) + { + buff.clear(); + continue; + } + + Box box; + box.x1 = buff[0]; + box.y1 = buff[1]; + box.x2 = buff[2]; + box.y2 = buff[3]; + box.cls = buff[4]; + box.conf = buff[5]; + result.emplace_back(box); + buff.clear(); + } + + // nms + result = non_maximum_suppression(result, iou_thre); + + // return the box to real image + for (int i = 0; i < result.size(); i++) + { + result[i].x1 = MAX((result[i].x1 - offset[0]) * img_w / (input_w - 2 * offset[0]), 0); + result[i].y1 = MAX((result[i].y1 - offset[1]) * img_h / (input_h - 2 * offset[1]), 0); + result[i].x2 = MIN((result[i].x2 - offset[0]) * img_w / (input_w - 2 * offset[0]), img_w); + result[i].y2 = MIN((result[i].y2 - offset[1]) * img_h / (input_h - 2 * offset[1]), img_h); + } + + return result; +} + + +/** + * @brief Predict function + * @param image Input image + * @return Predict results +*/ +std::vector RTMDet::predict(cv::Mat& image) +{ + // get input image size + int img_w = image.cols; + int img_h = image.rows; + std::vector input = preprocess(image); + + // apply for GPU space + cudaMalloc(&buffer[0], 3 * input_h * input_w * sizeof(float)); + cudaMalloc(&buffer[1], 8400 * 6 * sizeof(float)); + + // copy data to GPU + cudaMemcpyAsync(buffer[0], input.data(), 3 * input_h * input_w * sizeof(float), cudaMemcpyHostToDevice, stream); + + // network inference + context->enqueueV2(buffer, stream, nullptr); + cudaStreamSynchronize(stream); + + // get result from GPU + std::vector boxes_result(8400 * 6); + cudaMemcpyAsync(boxes_result.data(), buffer[1], 8400 * 6 * sizeof(float), cudaMemcpyDeviceToHost); + + std::vector result = postprocess(boxes_result, img_w, img_h); + + cudaFree(buffer[0]); + cudaFree(buffer[1]); + + return result; +} diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/rtmdet.h b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/rtmdet.h new file mode 100644 index 0000000000..7a30a9d48e --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/rtmdet.h @@ -0,0 +1,40 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +#include "utils.h" + + + +class RTMDet +{ +public: + RTMDet(std::string model_path, nvinfer1::ILogger& logger, float conf_thre=0.5, float iou_thre=0.65); + void show(); + std::vector predict(cv::Mat& image); + ~RTMDet(); + +private: + static float input_w; + static float input_h; + static float mean[3]; + static float std[3]; + + float conf_thre; + float iou_thre; + std::vector offset; + + nvinfer1::IRuntime* runtime; + nvinfer1::ICudaEngine* engine; + nvinfer1::IExecutionContext* context; + + void* buffer[2]; + cudaStream_t stream; + + std::vector preprocess(cv::Mat& image); + std::vector postprocess(std::vector boxes_result, int img_w, int img_h); +}; diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/rtmpose.cpp b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/rtmpose.cpp new file mode 100644 index 0000000000..1a190ceda2 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/rtmpose.cpp @@ -0,0 +1,193 @@ +#include "rtmpose.h" + + +// set network params +float RTMPose::input_h = 256; +float RTMPose::input_w = 192; +int RTMPose::extend_width = 384; +int RTMPose::extend_height = 512; +int RTMPose::num_points = 17; +float RTMPose::mean[3] = { 123.675, 116.28, 103.53 }; +float RTMPose::std[3] = { 58.395, 57.12, 57.375 }; + +/** + * @brief RTMPose`s constructor + * @param model_path RTMPose engine file path + * @param logger Nvinfer ILogger +*/ +RTMPose::RTMPose(std::string model_path, nvinfer1::ILogger& logger) +{ + // read the engine file + std::ifstream engineStream(model_path, std::ios::binary); + engineStream.seekg(0, std::ios::end); + const size_t modelSize = engineStream.tellg(); + engineStream.seekg(0, std::ios::beg); + std::unique_ptr engineData(new char[modelSize]); + engineStream.read(engineData.get(), modelSize); + engineStream.close(); + + // create tensorrt model + runtime = nvinfer1::createInferRuntime(logger); + engine = runtime->deserializeCudaEngine(engineData.get(), modelSize); + context = engine->createExecutionContext(); + + // Define input dimensions + context->setBindingDimensions(0, nvinfer1::Dims4(1, 3, input_h, input_w)); + + // create CUDA stream + cudaStreamCreate(&stream); + + // Initialize offset + offset.push_back(0); + offset.push_back(0); +} + +/** + * @brief RTMPose`s destructor +*/ +RTMPose::~RTMPose() +{ + cudaFree(stream); + cudaFree(buffer[0]); + cudaFree(buffer[1]); + cudaFree(buffer[2]); +} + + +/** + * @brief Display network input and output parameters +*/ +void RTMPose::show() +{ + for (int i = 0; i < engine->getNbBindings(); i++) + { + std::cout << "node: " << engine->getBindingName(i) << ", "; + if (engine->bindingIsInput(i)) + { + std::cout << "type: input" << ", "; + } + else + { + std::cout << "type: output" << ", "; + } + nvinfer1::Dims dim = engine->getBindingDimensions(i); + std::cout << "dimensions: "; + for (int d = 0; d < dim.nbDims; d++) + { + std::cout << dim.d[d] << " "; + } + std::cout << "\n"; + } +} + + +/** + * @brief Network preprocessing function + * @param image Input image + * @return Processed Tensor +*/ +std::vector RTMPose::preprocess(cv::Mat& image) +{ + // resize image + std::tuple resized = resize(image, input_w, input_h); + cv::Mat resized_image = std::get<0>(resized); + offset[0] = std::get<1>(resized); + offset[1] = std::get<2>(resized); + + // BGR2RGB + cv::cvtColor(resized_image, resized_image, cv::COLOR_BGR2RGB); + + // subtract mean and divide variance + std::vector input_tensor; + for (int k = 0; k < 3; k++) + { + for (int i = 0; i < resized_image.rows; i++) + { + for (int j = 0; j < resized_image.cols; j++) + { + input_tensor.emplace_back(((float)resized_image.at(i, j)[k] - mean[k]) / std[k]); + } + } + } + + return input_tensor; +} + + +/** + * @brief Network post-processing function + * @param simcc_x_result SimCC x dimension output + * @param simcc_y_result SimCC y dimension output + * @param img_w The width of input image + * @param img_h The height of input image + * @return +*/ +std::vector RTMPose::postprocess(std::vector simcc_x_result, std::vector simcc_y_result, int img_w, int img_h) +{ + std::vector pose_result; + for (int i = 0; i < num_points; ++i) + { + // find the maximum and maximum indexes in the value of each Extend_width length + auto x_biggest_iter = std::max_element(simcc_x_result.begin() + i * extend_width, simcc_x_result.begin() + i * extend_width + extend_width); + int max_x_pos = std::distance(simcc_x_result.begin() + i * extend_width, x_biggest_iter); + int pose_x = max_x_pos / 2; + float score_x = *x_biggest_iter; + + // find the maximum and maximum indexes in the value of each exten_height length + auto y_biggest_iter = std::max_element(simcc_y_result.begin() + i * extend_height, simcc_y_result.begin() + i * extend_height + extend_height); + int max_y_pos = std::distance(simcc_y_result.begin() + i * extend_height, y_biggest_iter); + int pose_y = max_y_pos / 2; + float score_y = *y_biggest_iter; + + // get point confidence + float score = MAX(score_x, score_y); + + PosePoint temp_point; + temp_point.x = (pose_x - offset[0]) * img_w / (input_w - 2 * offset[0]); + temp_point.y = (pose_y - offset[1]) * img_h / (input_h - 2 * offset[1]); + temp_point.score = score; + pose_result.emplace_back(temp_point); + } + + return pose_result; +} + + +/** + * @brief Predict function + * @param image Input image + * @return Predict results +*/ +std::vector RTMPose::predict(cv::Mat& image) +{ + // get input image size + int img_w = image.cols; + int img_h = image.rows; + std::vector input = preprocess(image); + + // apply for GPU space + cudaMalloc(&buffer[0], 3 * input_h * input_w * sizeof(float)); + cudaMalloc(&buffer[1], num_points * extend_width * sizeof(float)); + cudaMalloc(&buffer[2], num_points * extend_height * sizeof(float)); + + // copy data to GPU + cudaMemcpyAsync(buffer[0], input.data(), 3 * input_h * input_w * sizeof(float), cudaMemcpyHostToDevice, stream); + + // network inference + context->enqueueV2(buffer, stream, nullptr); + cudaStreamSynchronize(stream); + + // get result from GPU + std::vector simcc_x_result(num_points * extend_width); + std::vector simcc_y_result(num_points * extend_height); + cudaMemcpyAsync(simcc_x_result.data(), buffer[1], num_points * extend_width * sizeof(float), cudaMemcpyDeviceToHost); + cudaMemcpyAsync(simcc_y_result.data(), buffer[2], num_points * extend_height * sizeof(float), cudaMemcpyDeviceToHost); + + std::vector pose_result = postprocess(simcc_x_result, simcc_y_result, img_w, img_h); + + cudaFree(buffer[0]); + cudaFree(buffer[1]); + cudaFree(buffer[2]); + + return pose_result; +} diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/rtmpose.h b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/rtmpose.h new file mode 100644 index 0000000000..0b1bca4924 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/rtmpose.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + + + +class RTMPose +{ +public: + RTMPose(std::string model_path, nvinfer1::ILogger &logger); + void show(); + std::vector predict(cv::Mat& image); + ~RTMPose(); + +private: + static float input_w; + static float input_h; + static int extend_width; + static int extend_height; + static float mean[3]; + static float std[3]; + static int num_points; + + std::vector offset; + + nvinfer1::IRuntime* runtime; + nvinfer1::ICudaEngine* engine; + nvinfer1::IExecutionContext* context; + + void* buffer[3]; + cudaStream_t stream; + + std::vector preprocess(cv::Mat& image); + std::vector postprocess(std::vector simcc_x_result, std::vector simcc_y_result, int img_w, int img_h); +}; diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/utils.cpp b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/utils.cpp new file mode 100644 index 0000000000..053b9e5a58 --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/utils.cpp @@ -0,0 +1,212 @@ +#include "utils.h" + + +// set points links +std::vector> coco_17_joint_links = { + {0,1},{0,2},{1,3},{2,4},{5,7},{7,9},{6,8},{8,10},{5,6}, + {5,11},{6,12},{11,12},{11,13},{13,15},{12,14},{14,16} +}; + + +/** + * @brief Mix two images + * @param srcImage Original image + * @param mixImage Past image + * @param startPoint Start point + * @return Success or not +*/ +bool MixImage(cv::Mat& srcImage, cv::Mat mixImage, cv::Point startPoint) +{ + + if (!srcImage.data || !mixImage.data) + { + return false; + } + + int addCols = startPoint.x + mixImage.cols > srcImage.cols ? 0 : mixImage.cols; + int addRows = startPoint.y + mixImage.rows > srcImage.rows ? 0 : mixImage.rows; + if (addCols == 0 || addRows == 0) + { + return false; + } + + cv::Mat roiImage = srcImage(cv::Rect(startPoint.x, startPoint.y, addCols, addRows)); + + mixImage.copyTo(roiImage, mixImage); + return true; +} + + +/** + * @brief Resize image + * @param img Input image + * @param w Resized width + * @param h Resized height + * @return Resized image and offset +*/ +std::tuple resize(cv::Mat& img, int w, int h) +{ + cv::Mat result; + + int ih = img.rows; + int iw = img.cols; + + float scale = MIN(float(w) / float(iw), float(h) / float(ih)); + int nw = iw * scale; + int nh = ih * scale; + + cv::resize(img, img, cv::Size(nw, nh)); + result = cv::Mat::ones(cv::Size(w, h), CV_8UC1) * 128; + cv::cvtColor(result, result, cv::COLOR_GRAY2RGB); + cv::cvtColor(img, img, cv::COLOR_BGR2RGB); + + bool ifg = MixImage(result, img, cv::Point((w - nw) / 2, (h - nh) / 2)); + if (!ifg) + { + std::cerr << "MixImage failed" << std::endl; + abort(); + } + + std::tuple res_tuple = std::make_tuple(result, (w - nw) / 2, (h - nh) / 2); + + return res_tuple; +} + + +/** + * @brief Compare two boxes + * @param b1 Box1 + * @param b2 Box2 + * @return Compare result +*/ +bool compare_boxes(const Box& b1, const Box& b2) +{ + return b1.conf < b2.conf; +} + + +/** + * @brief Iou function + * @param b1 Box1 + * @param b2 Box2 + * @return Iou +*/ +float intersection_over_union(const Box& b1, const Box& b2) +{ + float x1 = std::max(b1.x1, b2.x1); + float y1 = std::max(b1.y1, b2.y1); + float x2 = std::min(b1.x2, b2.x2); + float y2 = std::min(b1.y2, b2.y2); + + // get intersection + float box_intersection = std::max((float)0, x2 - x1) * std::max((float)0, y2 - y1); + + // get union + float area1 = (b1.x2 - b1.x1) * (b1.y2 - b1.y1); + float area2 = (b2.x2 - b2.x1) * (b2.y2 - b2.y1); + float box_union = area1 + area2 - box_intersection; + + // To prevent the denominator from being zero, add a very small numerical value to the denominator + float iou = box_intersection / (box_union + 0.0001); + + return iou; +} + + +/** + * @brief Non-Maximum Suppression function + * @param boxes Input boxes + * @param iou_thre Iou threshold + * @return Boxes after nms +*/ +std::vector non_maximum_suppression(std::vector boxes, float iou_thre) +{ + // Sort boxes based on confidence + std::sort(boxes.begin(), boxes.end(), compare_boxes); + + std::vector result; + std::vector temp; + while (!boxes.empty()) + { + temp.clear(); + + Box chosen_box = boxes.back(); + boxes.pop_back(); + for (int i = 0; i < boxes.size(); i++) + { + if (boxes[i].cls != chosen_box.cls || intersection_over_union(boxes[i], chosen_box) < iou_thre) + temp.push_back(boxes[i]); + } + + boxes = temp; + result.push_back(chosen_box); + } + return result; +} + + +/** + * @brief Cut image + * @param image Input image + * @param x1 The left coordinate of cut box + * @param y1 The top coordinate of cut box + * @param x2 The right coordinate of cut box + * @param y2 The bottom coordinate of cut box + * @return Cut image +*/ +cv::Mat img_cut(cv::Mat& image, int x1, int y1, int x2, int y2) +{ + cv::Rect roi(x1, y1, x2 - x1, y2 - y1); + cv::Mat croppedImage = image(roi); + return croppedImage; +} + + +/** + * @brief Judge whether two floating point numbers are equal + * @param a Number a + * @param b Number b + * @return Result +*/ +bool isEqual(float a, float b) +{ + return std::fabs(a - b) < 1e-5; +} + + +/** + * @brief Draw detection result to image + * @param image Input image + * @param points Detection result +*/ +void draw_pose(cv::Mat& image, std::vector> points) +{ + for (int p = 0; p < points.size(); p++) + { + // draw points links + for (int i = 0; i < coco_17_joint_links.size(); i++) + { + std::pair joint_link = coco_17_joint_links[i]; + cv::line( + image, + cv::Point(points[p][joint_link.first].x, points[p][joint_link.first].y), + cv::Point(points[p][joint_link.second].x, points[p][joint_link.second].y), + cv::Scalar{ 0, 255, 0 }, + 2, + cv::LINE_AA + ); + } + //draw points + for (int i = 0; i < points[p].size(); i++) + { + cv::circle( + image, + cv::Point(points[p][i].x, points[p][i].y), + 1, + cv::Scalar{ 0, 0, 255 }, + 5, + cv::LINE_AA + ); + } + } +} diff --git a/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/utils.h b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/utils.h new file mode 100644 index 0000000000..fa165c03ec --- /dev/null +++ b/projects/rtmpose/examples/RTMPose-Deploy/Windows/TensorRT/src/RTMPoseTensorRT/utils.h @@ -0,0 +1,56 @@ +#pragma once +#include +#include +#include +#include +#include + + +/** + * @brief Key point structure +*/ +struct PosePoint +{ + int x; + int y; + float score; + + PosePoint() + { + x = 0; + y = 0; + score = 0.0; + } +}; + +/** + * @brief Detection box structure +*/ +struct Box +{ + float x1; + float y1; + float x2; + float y2; + int cls; + float conf; + + Box() + { + x1 = 0; + y1 = 0; + x2 = 0; + y2 = 0; + cls = 0; + conf = 0; + } +}; + +bool MixImage(cv::Mat& srcImage, cv::Mat mixImage, cv::Point startPoint); +std::tuple resize(cv::Mat& img, int w, int h); +bool compare_boxes(const Box& b1, const Box& b2); +float intersection_over_union(const Box& b1, const Box& b2); +std::vector non_maximum_suppression(std::vector boxes, float iou_thre); +cv::Mat img_cut(cv::Mat& image, int x1, int y1, int x2, int y2); +bool isEqual(float a, float b); +void draw_pose(cv::Mat& image, std::vector> points); diff --git a/projects/rtmpose/examples/onnxruntime/README.md b/projects/rtmpose/examples/onnxruntime/README.md new file mode 100644 index 0000000000..0e0f8b7f63 --- /dev/null +++ b/projects/rtmpose/examples/onnxruntime/README.md @@ -0,0 +1,87 @@ +# RTMPose inference with ONNXRuntime + +This example shows how to run RTMPose inference with ONNXRuntime in Python. + +## Prerequisites + +### 1. Install onnxruntime inference engine. + +Choose one of the following ways to install onnxruntime. + +- CPU version + +```bash +wget https://github.com/microsoft/onnxruntime/releases/download/v1.8.1/onnxruntime-linux-x64-1.8.1.tgz +tar -zxvf onnxruntime-linux-x64-1.8.1.tgz +export ONNXRUNTIME_DIR=$(pwd)/onnxruntime-linux-x64-1.8.1 +export LD_LIBRARY_PATH=$ONNXRUNTIME_DIR/lib:$LD_LIBRARY_PATH +``` + +- GPU version + +```bash +pip install onnxruntime-gpu==1.8.1 +wget https://github.com/microsoft/onnxruntime/releases/download/v1.8.1/onnxruntime-linux-x64-gpu-1.8.1.tgz +tar -zxvf onnxruntime-linux-x64-gpu-1.8.1.tgz +export ONNXRUNTIME_DIR=$(pwd)/onnxruntime-linux-x64-gpu-1.8.1 +export LD_LIBRARY_PATH=$ONNXRUNTIME_DIR/lib:$LD_LIBRARY_PATH +``` + +### 2. Convert model to onnx files + +- Install `mim` tool. + +```bash +pip install -U openmim +``` + +- Download `mmpose` model. + +```bash +# choose one rtmpose model +mim download mmpose --config rtmpose-m_8xb64-270e_coco-wholebody-256x192 --dest . +``` + +- Clone `mmdeploy` repo. + +```bash +git clone https://github.com/open-mmlab/mmdeploy.git +``` + +- Convert model to onnx files. + +```bash +python mmdeploy/tools/deploy.py \ + mmdeploy/configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py \ + mmpose/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py \ + mmpose/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.pth \ + mmdeploy/demo/resources/human-pose.jpg \ + --work-dir mmdeploy_model/mmpose/ort \ + --device cuda \ + --dump-info +``` + +## Run demo + +### Install dependencies + +```bash +pip install -r requirements.txt +``` + +### Usage: + +```bash +python main.py \ + {ONNX_FILE} \ + {IMAGE_FILE} \ + --device {DEVICE} \ + --save-path {SAVE_PATH} +``` + +### Description of all arguments + +- `ONNX_FILE`: The path of onnx file +- `IMAGE_FILE`: The path of image file +- `DEVICE`: The device to run the model, default is `cpu` +- `SAVE_PATH`: The path to save the output image, default is `output.jpg` diff --git a/projects/rtmpose/examples/onnxruntime/README_CN.md b/projects/rtmpose/examples/onnxruntime/README_CN.md new file mode 100644 index 0000000000..684d42d5ff --- /dev/null +++ b/projects/rtmpose/examples/onnxruntime/README_CN.md @@ -0,0 +1,87 @@ +# 使用ONNXRuntime进行RTMPose推理 + +本示例展示了如何在Python中用ONNXRuntime推理RTMPose模型。 + +## 准备 + +### 1. 安装onnxruntime推理引擎. + +选择以下方式之一来安装onnxruntime。 + +- CPU版本 + +```bash +wget https://github.com/microsoft/onnxruntime/releases/download/v1.8.1/onnxruntime-linux-x64-1.8.1.tgz +tar -zxvf onnxruntime-linux-x64-1.8.1.tgz +export ONNXRUNTIME_DIR=$(pwd)/onnxruntime-linux-x64-1.8.1 +export LD_LIBRARY_PATH=$ONNXRUNTIME_DIR/lib:$LD_LIBRARY_PATH +``` + +- GPU版本 + +```bash +pip install onnxruntime-gpu==1.8.1 +wget https://github.com/microsoft/onnxruntime/releases/download/v1.8.1/onnxruntime-linux-x64-gpu-1.8.1.tgz +tar -zxvf onnxruntime-linux-x64-gpu-1.8.1.tgz +export ONNXRUNTIME_DIR=$(pwd)/onnxruntime-linux-x64-gpu-1.8.1 +export LD_LIBRARY_PATH=$ONNXRUNTIME_DIR/lib:$LD_LIBRARY_PATH +``` + +### 2. 将模型转换为onnx文件 + +- 安装`mim`工具 + +```bash +pip install -U openmim +``` + +- 下载`mmpose`模型 + +```bash +# choose one rtmpose model +mim download mmpose --config rtmpose-m_8xb64-270e_coco-wholebody-256x192 --dest . +``` + +- 克隆`mmdeploy`仓库 + +```bash +git clone https://github.com/open-mmlab/mmdeploy.git +``` + +- 将模型转换为onnx文件 + +```bash +python mmdeploy/tools/deploy.py \ + mmdeploy/configs/mmpose/pose-detection_simcc_onnxruntime_dynamic.py \ + mmpose/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py \ + mmpose/rtmpose-m_simcc-coco-wholebody_pt-aic-coco_270e-256x192-cd5e845c_20230123.pth \ + mmdeploy/demo/resources/human-pose.jpg \ + --work-dir mmdeploy_model/mmpose/ort \ + --device cuda \ + --dump-info +``` + +## 运行 + +### 安装依赖 + +```bash +pip install -r requirements.txt +``` + +### 用法: + +```bash +python main.py \ + {ONNX_FILE} \ + {IMAGE_FILE} \ + --device {DEVICE} \ + --save-path {SAVE_PATH} +``` + +### 参数解释 + +- `ONNX_FILE`: onnx文件的路径 +- `IMAGE_FILE`: 图像文件的路径 +- `DEVICE`: 运行模型的设备,默认为\`cpu' +- `SAVE_PATH`: 保存输出图像的路径,默认为 "output.jpg" diff --git a/projects/rtmpose/examples/onnxruntime/human-pose.jpeg b/projects/rtmpose/examples/onnxruntime/human-pose.jpeg new file mode 100644 index 0000000000..8de401563e Binary files /dev/null and b/projects/rtmpose/examples/onnxruntime/human-pose.jpeg differ diff --git a/projects/rtmpose/examples/onnxruntime/main.py b/projects/rtmpose/examples/onnxruntime/main.py new file mode 100644 index 0000000000..df4858c8dd --- /dev/null +++ b/projects/rtmpose/examples/onnxruntime/main.py @@ -0,0 +1,472 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import argparse +import time +from typing import List, Tuple + +import cv2 +import loguru +import numpy as np +import onnxruntime as ort + +logger = loguru.logger + + +def parse_args(): + parser = argparse.ArgumentParser( + description='RTMPose ONNX inference demo.') + parser.add_argument('onnx_file', help='ONNX file path') + parser.add_argument('image_file', help='Input image file path') + parser.add_argument( + '--device', help='device type for inference', default='cpu') + parser.add_argument( + '--save-path', + help='path to save the output image', + default='output.jpg') + args = parser.parse_args() + return args + + +def preprocess( + img: np.ndarray, input_size: Tuple[int, int] = (192, 256) +) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + """Do preprocessing for RTMPose model inference. + + Args: + img (np.ndarray): Input image in shape. + input_size (tuple): Input image size in shape (w, h). + + Returns: + tuple: + - resized_img (np.ndarray): Preprocessed image. + - center (np.ndarray): Center of image. + - scale (np.ndarray): Scale of image. + """ + # get shape of image + img_shape = img.shape[:2] + bbox = np.array([0, 0, img_shape[1], img_shape[0]]) + + # get center and scale + center, scale = bbox_xyxy2cs(bbox, padding=1.25) + + # do affine transformation + resized_img, scale = top_down_affine(input_size, scale, center, img) + + # normalize image + mean = np.array([123.675, 116.28, 103.53]) + std = np.array([58.395, 57.12, 57.375]) + resized_img = (resized_img - mean) / std + + return resized_img, center, scale + + +def build_session(onnx_file: str, device: str = 'cpu') -> ort.InferenceSession: + """Build onnxruntime session. + + Args: + onnx_file (str): ONNX file path. + device (str): Device type for inference. + + Returns: + sess (ort.InferenceSession): ONNXRuntime session. + """ + providers = ['CPUExecutionProvider' + ] if device == 'cpu' else ['CUDAExecutionProvider'] + sess = ort.InferenceSession(path_or_bytes=onnx_file, providers=providers) + + return sess + + +def inference(sess: ort.InferenceSession, img: np.ndarray) -> np.ndarray: + """Inference RTMPose model. + + Args: + sess (ort.InferenceSession): ONNXRuntime session. + img (np.ndarray): Input image in shape. + + Returns: + outputs (np.ndarray): Output of RTMPose model. + """ + # build input + input = [img.transpose(2, 0, 1)] + + # build output + sess_input = {sess.get_inputs()[0].name: input} + sess_output = [] + for out in sess.get_outputs(): + sess_output.append(out.name) + + # run model + outputs = sess.run(sess_output, sess_input) + + return outputs + + +def postprocess(outputs: List[np.ndarray], + model_input_size: Tuple[int, int], + center: Tuple[int, int], + scale: Tuple[int, int], + simcc_split_ratio: float = 2.0 + ) -> Tuple[np.ndarray, np.ndarray]: + """Postprocess for RTMPose model output. + + Args: + outputs (np.ndarray): Output of RTMPose model. + model_input_size (tuple): RTMPose model Input image size. + center (tuple): Center of bbox in shape (x, y). + scale (tuple): Scale of bbox in shape (w, h). + simcc_split_ratio (float): Split ratio of simcc. + + Returns: + tuple: + - keypoints (np.ndarray): Rescaled keypoints. + - scores (np.ndarray): Model predict scores. + """ + # use simcc to decode + simcc_x, simcc_y = outputs + keypoints, scores = decode(simcc_x, simcc_y, simcc_split_ratio) + + # rescale keypoints + keypoints = keypoints / model_input_size * scale + center - scale / 2 + + return keypoints, scores + + +def visualize(img: np.ndarray, + keypoints: np.ndarray, + scores: np.ndarray, + filename: str = 'output.jpg', + thr=0.3) -> np.ndarray: + """Visualize the keypoints and skeleton on image. + + Args: + img (np.ndarray): Input image in shape. + keypoints (np.ndarray): Keypoints in image. + scores (np.ndarray): Model predict scores. + thr (float): Threshold for visualize. + + Returns: + img (np.ndarray): Visualized image. + """ + # default color + skeleton = [(15, 13), (13, 11), (16, 14), (14, 12), (11, 12), (5, 11), + (6, 12), (5, 6), (5, 7), (6, 8), (7, 9), (8, 10), (1, 2), + (0, 1), (0, 2), (1, 3), (2, 4), (3, 5), (4, 6), (15, 17), + (15, 18), (15, 19), (16, 20), (16, 21), (16, 22), (91, 92), + (92, 93), (93, 94), (94, 95), (91, 96), (96, 97), (97, 98), + (98, 99), (91, 100), (100, 101), (101, 102), (102, 103), + (91, 104), (104, 105), (105, 106), (106, 107), (91, 108), + (108, 109), (109, 110), (110, 111), (112, 113), (113, 114), + (114, 115), (115, 116), (112, 117), (117, 118), (118, 119), + (119, 120), (112, 121), (121, 122), (122, 123), (123, 124), + (112, 125), (125, 126), (126, 127), (127, 128), (112, 129), + (129, 130), (130, 131), (131, 132)] + palette = [[51, 153, 255], [0, 255, 0], [255, 128, 0], [255, 255, 255], + [255, 153, 255], [102, 178, 255], [255, 51, 51]] + link_color = [ + 1, 1, 2, 2, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 1, 1, 1, 1, 2, 2, 2, + 2, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 1, 1, 1, 1 + ] + point_color = [ + 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, + 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 1, 1, 1, 1, 3, 2, 2, 2, 2, 4, 4, 4, + 4, 5, 5, 5, 5, 6, 6, 6, 6, 1, 1, 1, 1 + ] + + # draw keypoints and skeleton + for kpts, score in zip(keypoints, scores): + for kpt, color in zip(kpts, point_color): + cv2.circle(img, tuple(kpt.astype(np.int32)), 1, palette[color], 1, + cv2.LINE_AA) + for (u, v), color in zip(skeleton, link_color): + if score[u] > thr and score[v] > thr: + cv2.line(img, tuple(kpts[u].astype(np.int32)), + tuple(kpts[v].astype(np.int32)), palette[color], 2, + cv2.LINE_AA) + + # save to local + cv2.imwrite(filename, img) + + return img + + +def bbox_xyxy2cs(bbox: np.ndarray, + padding: float = 1.) -> Tuple[np.ndarray, np.ndarray]: + """Transform the bbox format from (x,y,w,h) into (center, scale) + + Args: + bbox (ndarray): Bounding box(es) in shape (4,) or (n, 4), formatted + as (left, top, right, bottom) + padding (float): BBox padding factor that will be multilied to scale. + Default: 1.0 + + Returns: + tuple: A tuple containing center and scale. + - np.ndarray[float32]: Center (x, y) of the bbox in shape (2,) or + (n, 2) + - np.ndarray[float32]: Scale (w, h) of the bbox in shape (2,) or + (n, 2) + """ + # convert single bbox from (4, ) to (1, 4) + dim = bbox.ndim + if dim == 1: + bbox = bbox[None, :] + + # get bbox center and scale + x1, y1, x2, y2 = np.hsplit(bbox, [1, 2, 3]) + center = np.hstack([x1 + x2, y1 + y2]) * 0.5 + scale = np.hstack([x2 - x1, y2 - y1]) * padding + + if dim == 1: + center = center[0] + scale = scale[0] + + return center, scale + + +def _fix_aspect_ratio(bbox_scale: np.ndarray, + aspect_ratio: float) -> np.ndarray: + """Extend the scale to match the given aspect ratio. + + Args: + scale (np.ndarray): The image scale (w, h) in shape (2, ) + aspect_ratio (float): The ratio of ``w/h`` + + Returns: + np.ndarray: The reshaped image scale in (2, ) + """ + w, h = np.hsplit(bbox_scale, [1]) + bbox_scale = np.where(w > h * aspect_ratio, + np.hstack([w, w / aspect_ratio]), + np.hstack([h * aspect_ratio, h])) + return bbox_scale + + +def _rotate_point(pt: np.ndarray, angle_rad: float) -> np.ndarray: + """Rotate a point by an angle. + + Args: + pt (np.ndarray): 2D point coordinates (x, y) in shape (2, ) + angle_rad (float): rotation angle in radian + + Returns: + np.ndarray: Rotated point in shape (2, ) + """ + sn, cs = np.sin(angle_rad), np.cos(angle_rad) + rot_mat = np.array([[cs, -sn], [sn, cs]]) + return rot_mat @ pt + + +def _get_3rd_point(a: np.ndarray, b: np.ndarray) -> np.ndarray: + """To calculate the affine matrix, three pairs of points are required. This + function is used to get the 3rd point, given 2D points a & b. + + The 3rd point is defined by rotating vector `a - b` by 90 degrees + anticlockwise, using b as the rotation center. + + Args: + a (np.ndarray): The 1st point (x,y) in shape (2, ) + b (np.ndarray): The 2nd point (x,y) in shape (2, ) + + Returns: + np.ndarray: The 3rd point. + """ + direction = a - b + c = b + np.r_[-direction[1], direction[0]] + return c + + +def get_warp_matrix(center: np.ndarray, + scale: np.ndarray, + rot: float, + output_size: Tuple[int, int], + shift: Tuple[float, float] = (0., 0.), + inv: bool = False) -> np.ndarray: + """Calculate the affine transformation matrix that can warp the bbox area + in the input image to the output size. + + Args: + center (np.ndarray[2, ]): Center of the bounding box (x, y). + scale (np.ndarray[2, ]): Scale of the bounding box + wrt [width, height]. + rot (float): Rotation angle (degree). + output_size (np.ndarray[2, ] | list(2,)): Size of the + destination heatmaps. + shift (0-100%): Shift translation ratio wrt the width/height. + Default (0., 0.). + inv (bool): Option to inverse the affine transform direction. + (inv=False: src->dst or inv=True: dst->src) + + Returns: + np.ndarray: A 2x3 transformation matrix + """ + shift = np.array(shift) + src_w = scale[0] + dst_w = output_size[0] + dst_h = output_size[1] + + # compute transformation matrix + rot_rad = np.deg2rad(rot) + src_dir = _rotate_point(np.array([0., src_w * -0.5]), rot_rad) + dst_dir = np.array([0., dst_w * -0.5]) + + # get four corners of the src rectangle in the original image + src = np.zeros((3, 2), dtype=np.float32) + src[0, :] = center + scale * shift + src[1, :] = center + src_dir + scale * shift + src[2, :] = _get_3rd_point(src[0, :], src[1, :]) + + # get four corners of the dst rectangle in the input image + dst = np.zeros((3, 2), dtype=np.float32) + dst[0, :] = [dst_w * 0.5, dst_h * 0.5] + dst[1, :] = np.array([dst_w * 0.5, dst_h * 0.5]) + dst_dir + dst[2, :] = _get_3rd_point(dst[0, :], dst[1, :]) + + if inv: + warp_mat = cv2.getAffineTransform(np.float32(dst), np.float32(src)) + else: + warp_mat = cv2.getAffineTransform(np.float32(src), np.float32(dst)) + + return warp_mat + + +def top_down_affine(input_size: dict, bbox_scale: dict, bbox_center: dict, + img: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: + """Get the bbox image as the model input by affine transform. + + Args: + input_size (dict): The input size of the model. + bbox_scale (dict): The bbox scale of the img. + bbox_center (dict): The bbox center of the img. + img (np.ndarray): The original image. + + Returns: + tuple: A tuple containing center and scale. + - np.ndarray[float32]: img after affine transform. + - np.ndarray[float32]: bbox scale after affine transform. + """ + w, h = input_size + warp_size = (int(w), int(h)) + + # reshape bbox to fixed aspect ratio + bbox_scale = _fix_aspect_ratio(bbox_scale, aspect_ratio=w / h) + + # get the affine matrix + center = bbox_center + scale = bbox_scale + rot = 0 + warp_mat = get_warp_matrix(center, scale, rot, output_size=(w, h)) + + # do affine transform + img = cv2.warpAffine(img, warp_mat, warp_size, flags=cv2.INTER_LINEAR) + + return img, bbox_scale + + +def get_simcc_maximum(simcc_x: np.ndarray, + simcc_y: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: + """Get maximum response location and value from simcc representations. + + Note: + instance number: N + num_keypoints: K + heatmap height: H + heatmap width: W + + Args: + simcc_x (np.ndarray): x-axis SimCC in shape (K, Wx) or (N, K, Wx) + simcc_y (np.ndarray): y-axis SimCC in shape (K, Wy) or (N, K, Wy) + + Returns: + tuple: + - locs (np.ndarray): locations of maximum heatmap responses in shape + (K, 2) or (N, K, 2) + - vals (np.ndarray): values of maximum heatmap responses in shape + (K,) or (N, K) + """ + N, K, Wx = simcc_x.shape + simcc_x = simcc_x.reshape(N * K, -1) + simcc_y = simcc_y.reshape(N * K, -1) + + # get maximum value locations + x_locs = np.argmax(simcc_x, axis=1) + y_locs = np.argmax(simcc_y, axis=1) + locs = np.stack((x_locs, y_locs), axis=-1).astype(np.float32) + max_val_x = np.amax(simcc_x, axis=1) + max_val_y = np.amax(simcc_y, axis=1) + + # get maximum value across x and y axis + mask = max_val_x > max_val_y + max_val_x[mask] = max_val_y[mask] + vals = max_val_x + locs[vals <= 0.] = -1 + + # reshape + locs = locs.reshape(N, K, 2) + vals = vals.reshape(N, K) + + return locs, vals + + +def decode(simcc_x: np.ndarray, simcc_y: np.ndarray, + simcc_split_ratio) -> Tuple[np.ndarray, np.ndarray]: + """Modulate simcc distribution with Gaussian. + + Args: + simcc_x (np.ndarray[K, Wx]): model predicted simcc in x. + simcc_y (np.ndarray[K, Wy]): model predicted simcc in y. + simcc_split_ratio (int): The split ratio of simcc. + + Returns: + tuple: A tuple containing center and scale. + - np.ndarray[float32]: keypoints in shape (K, 2) or (n, K, 2) + - np.ndarray[float32]: scores in shape (K,) or (n, K) + """ + keypoints, scores = get_simcc_maximum(simcc_x, simcc_y) + keypoints /= simcc_split_ratio + + return keypoints, scores + + +def main(): + args = parse_args() + logger.info('Start running model on RTMPose...') + + # read image from file + logger.info('1. Read image from {}...'.format(args.image_file)) + img = cv2.imread(args.image_file) + + # build onnx model + logger.info('2. Build onnx model from {}...'.format(args.onnx_file)) + sess = build_session(args.onnx_file, args.device) + h, w = sess.get_inputs()[0].shape[2:] + model_input_size = (w, h) + + # preprocessing + logger.info('3. Preprocess image...') + resized_img, center, scale = preprocess(img, model_input_size) + + # inference + logger.info('4. Inference...') + start_time = time.time() + outputs = inference(sess, resized_img) + end_time = time.time() + logger.info('4. Inference done, time cost: {:.4f}s'.format(end_time - + start_time)) + + # postprocessing + logger.info('5. Postprocess...') + keypoints, scores = postprocess(outputs, model_input_size, center, scale) + + # visualize inference result + logger.info('6. Visualize inference result...') + visualize(img, keypoints, scores, args.save_path) + + logger.info('Done...') + + +if __name__ == '__main__': + main() diff --git a/projects/rtmpose/examples/onnxruntime/requirements.txt b/projects/rtmpose/examples/onnxruntime/requirements.txt new file mode 100644 index 0000000000..88548c0203 --- /dev/null +++ b/projects/rtmpose/examples/onnxruntime/requirements.txt @@ -0,0 +1,4 @@ +loguru==0.6.0 +numpy==1.21.6 +onnxruntime==1.14.1 +onnxruntime-gpu==1.8.1 diff --git a/projects/rtmpose/rtmdet/hand/rtmdet_nano_320-8xb32_hand.py b/projects/rtmpose/rtmdet/hand/rtmdet_nano_320-8xb32_hand.py new file mode 100644 index 0000000000..278cc0bfe8 --- /dev/null +++ b/projects/rtmpose/rtmdet/hand/rtmdet_nano_320-8xb32_hand.py @@ -0,0 +1,171 @@ +_base_ = 'mmdet::rtmdet/rtmdet_l_8xb32-300e_coco.py' + +input_shape = 320 + +model = dict( + backbone=dict( + deepen_factor=0.33, + widen_factor=0.25, + use_depthwise=True, + ), + neck=dict( + in_channels=[64, 128, 256], + out_channels=64, + num_csp_blocks=1, + use_depthwise=True, + ), + bbox_head=dict( + in_channels=64, + feat_channels=64, + share_conv=False, + exp_on_reg=False, + use_depthwise=True, + num_classes=1), + test_cfg=dict( + nms_pre=1000, + min_bbox_size=0, + score_thr=0.05, + nms=dict(type='nms', iou_threshold=0.6), + max_per_img=100)) + +# file_client_args = dict( +# backend='petrel', +# path_mapping=dict({'data/': 's3://openmmlab/datasets/'})) + +train_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='CachedMosaic', + img_scale=(input_shape, input_shape), + pad_val=114.0, + max_cached_images=20, + random_pop=False), + dict( + type='RandomResize', + scale=(input_shape * 2, input_shape * 2), + ratio_range=(0.5, 1.5), + keep_ratio=True), + dict(type='RandomCrop', crop_size=(input_shape, input_shape)), + dict(type='YOLOXHSVRandomAug'), + dict(type='RandomFlip', prob=0.5), + dict( + type='Pad', + size=(input_shape, input_shape), + pad_val=dict(img=(114, 114, 114))), + dict(type='PackDetInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImageFromFile'), + dict(type='LoadAnnotations', with_bbox=True), + dict( + type='RandomResize', + scale=(input_shape, input_shape), + ratio_range=(0.5, 1.5), + keep_ratio=True), + dict(type='RandomCrop', crop_size=(input_shape, input_shape)), + dict(type='YOLOXHSVRandomAug'), + dict(type='RandomFlip', prob=0.5), + dict( + type='Pad', + size=(input_shape, input_shape), + pad_val=dict(img=(114, 114, 114))), + dict(type='PackDetInputs') +] + +test_pipeline = [ + dict(type='LoadImageFromFile'), + dict(type='Resize', scale=(input_shape, input_shape), keep_ratio=True), + dict( + type='Pad', + size=(input_shape, input_shape), + pad_val=dict(img=(114, 114, 114))), + dict( + type='PackDetInputs', + meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape', + 'scale_factor')) +] + +data_mode = 'topdown' +data_root = 'data/' + +train_dataset = dict( + _delete_=True, + type='ConcatDataset', + datasets=[ + dict( + type='mmpose.OneHand10KDataset', + data_root=data_root, + data_mode=data_mode, + pipeline=train_pipeline, + ann_file='onehand10k/annotations/onehand10k_train.json', + data_prefix=dict(img='pose/OneHand10K/')), + dict( + type='mmpose.FreiHandDataset', + data_root=data_root, + data_mode=data_mode, + pipeline=train_pipeline, + ann_file='freihand/annotations/freihand_train.json', + data_prefix=dict(img='pose/FreiHand/')), + dict( + type='mmpose.Rhd2DDataset', + data_root=data_root, + data_mode=data_mode, + pipeline=train_pipeline, + ann_file='rhd/annotations/rhd_train.json', + data_prefix=dict(img='pose/RHD/')), + dict( + type='mmpose.HalpeHandDataset', + data_root=data_root, + data_mode=data_mode, + pipeline=train_pipeline, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict( + img='pose/Halpe/hico_20160224_det/images/train2015/') # noqa + ) + ], + ignore_keys=[ + 'CLASSES', 'dataset_keypoint_weights', 'dataset_name', 'flip_indices', + 'flip_pairs', 'keypoint_colors', 'keypoint_id2name', + 'keypoint_name2id', 'lower_body_ids', 'num_keypoints', + 'num_skeleton_links', 'sigmas', 'skeleton_link_colors', + 'skeleton_links', 'upper_body_ids' + ], +) + +test_dataset = dict( + _delete_=True, + type='mmpose.OneHand10KDataset', + data_root=data_root, + data_mode=data_mode, + pipeline=test_pipeline, + ann_file='onehand10k/annotations/onehand10k_test.json', + data_prefix=dict(img='pose/OneHand10K/'), +) + +train_dataloader = dict(dataset=train_dataset) +val_dataloader = dict(dataset=test_dataset) +test_dataloader = val_dataloader + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='PipelineSwitchHook', + switch_epoch=280, + switch_pipeline=train_pipeline_stage2) +] + +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'onehand10k/annotations/onehand10k_test.json', + metric='bbox', + format_only=False) +test_evaluator = val_evaluator + +train_cfg = dict(val_interval=1) diff --git a/projects/rtmpose/rtmpose/animal_2d_keypoint/rtmpose-m_8xb64-210e_ap10k-256x256.py b/projects/rtmpose/rtmpose/animal_2d_keypoint/rtmpose-m_8xb64-210e_ap10k-256x256.py index f3372b5ba3..d25fd13e70 100644 --- a/projects/rtmpose/rtmpose/animal_2d_keypoint/rtmpose-m_8xb64-210e_ap10k-256x256.py +++ b/projects/rtmpose/rtmpose/animal_2d_keypoint/rtmpose-m_8xb64-210e_ap10k-256x256.py @@ -1,9 +1,15 @@ _base_ = ['mmpose::_base_/default_runtime.py'] +# common setting +num_keypoints = 17 +input_size = (256, 256) + # runtime max_epochs = 210 stage2_num_epochs = 30 base_lr = 4e-3 +train_batch_size = 64 +val_batch_size = 32 train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) @@ -12,6 +18,7 @@ optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), paramwise_cfg=dict( norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) @@ -24,7 +31,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -40,7 +46,7 @@ # codec settings codec = dict( type='SimCCLabel', - input_size=(256, 256), + input_size=input_size, sigma=(5.66, 5.66), simcc_split_ratio=2.0, normalize=False, @@ -69,14 +75,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, - out_channels=17, + out_channels=num_keypoints, input_size=codec['input_size'], - in_featuremap_size=(8, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -102,12 +108,6 @@ data_root = 'data/ap10k/' backend_args = dict(backend='local') -# backend_args = dict( -# backend='petrel', -# path_mapping=dict({ -# f'{data_root}': 's3://openmmlab/datasets/pose/ap10k/', -# f'{data_root}': 's3://openmmlab/datasets/pose/ap10k/' -# })) # pipelines train_pipeline = [ @@ -177,7 +177,7 @@ # data loaders train_dataloader = dict( - batch_size=64, + batch_size=train_batch_size, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), @@ -190,7 +190,7 @@ pipeline=train_pipeline, )) val_dataloader = dict( - batch_size=32, + batch_size=val_batch_size, num_workers=10, persistent_workers=True, drop_last=False, @@ -205,7 +205,7 @@ pipeline=val_pipeline, )) test_dataloader = dict( - batch_size=32, + batch_size=val_batch_size, num_workers=10, persistent_workers=True, drop_last=False, diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py index 5cbfd209f3..c472cac1fb 100644 --- a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-256x192.py @@ -1,9 +1,15 @@ _base_ = ['mmpose::_base_/default_runtime.py'] +# common setting +num_keypoints = 17 +input_size = (192, 256) + # runtime max_epochs = 420 stage2_num_epochs = 30 base_lr = 4e-3 +train_batch_size = 256 +val_batch_size = 64 train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) @@ -12,6 +18,7 @@ optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), paramwise_cfg=dict( norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) @@ -24,7 +31,6 @@ begin=0, end=1000), dict( - # use cosine lr from 210 to 420 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -40,7 +46,7 @@ # codec settings codec = dict( type='SimCCLabel', - input_size=(192, 256), + input_size=input_size, sigma=(4.9, 5.66), simcc_split_ratio=2.0, normalize=False, @@ -69,14 +75,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa + 'rtmposev1/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=1024, - out_channels=17, + out_channels=num_keypoints, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -177,7 +183,7 @@ # data loaders train_dataloader = dict( - batch_size=256, + batch_size=train_batch_size, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), @@ -190,7 +196,7 @@ pipeline=train_pipeline, )) val_dataloader = dict( - batch_size=64, + batch_size=val_batch_size, num_workers=10, persistent_workers=True, drop_last=False, diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-384x288.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-384x288.py index bf16ee33a6..47697078d5 100644 --- a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-384x288.py +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb256-420e_coco-384x288.py @@ -1,9 +1,15 @@ _base_ = ['mmpose::_base_/default_runtime.py'] +# common setting +num_keypoints = 17 +input_size = (288, 384) + # runtime max_epochs = 420 stage2_num_epochs = 30 base_lr = 4e-3 +train_batch_size = 256 +val_batch_size = 64 train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) @@ -12,6 +18,7 @@ optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), paramwise_cfg=dict( norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) @@ -24,7 +31,6 @@ begin=0, end=1000), dict( - # use cosine lr from 210 to 420 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -40,7 +46,7 @@ # codec settings codec = dict( type='SimCCLabel', - input_size=(288, 384), + input_size=input_size, sigma=(6., 6.93), simcc_split_ratio=2.0, normalize=False, @@ -69,14 +75,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa + 'rtmposev1/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=1024, - out_channels=17, + out_channels=num_keypoints, input_size=codec['input_size'], - in_featuremap_size=(9, 12), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -177,7 +183,7 @@ # data loaders train_dataloader = dict( - batch_size=256, + batch_size=train_batch_size, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), @@ -190,7 +196,7 @@ pipeline=train_pipeline, )) val_dataloader = dict( - batch_size=64, + batch_size=val_batch_size, num_workers=10, persistent_workers=True, drop_last=False, diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb512-700e_body8-halpe26-256x192.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb512-700e_body8-halpe26-256x192.py new file mode 100644 index 0000000000..fe19d45af9 --- /dev/null +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb512-700e_body8-halpe26-256x192.py @@ -0,0 +1,535 @@ +_base_ = ['mmpose::_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (192, 256) + +# runtime +max_epochs = 700 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 512 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=1., + widen_factor=1., + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-256x192-4dba18fc_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=1024, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=5, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=5, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb512-700e_body8-halpe26-384x288.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb512-700e_body8-halpe26-384x288.py new file mode 100644 index 0000000000..bec4fcb924 --- /dev/null +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-l_8xb512-700e_body8-halpe26-384x288.py @@ -0,0 +1,535 @@ +_base_ = ['mmpose::_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (288, 384) + +# runtime +max_epochs = 700 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 512 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(6., 6.93), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=1., + widen_factor=1., + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/rtmpose-l_simcc-body7_pt-body7_420e-384x288-3f5a1437_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=1024, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py index 0725b4800f..97e70667e6 100644 --- a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-256x192.py @@ -1,9 +1,15 @@ _base_ = ['mmpose::_base_/default_runtime.py'] +# common setting +num_keypoints = 17 +input_size = (192, 256) + # runtime max_epochs = 420 stage2_num_epochs = 30 base_lr = 4e-3 +train_batch_size = 256 +val_batch_size = 64 train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) @@ -12,6 +18,7 @@ optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), paramwise_cfg=dict( norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) @@ -24,7 +31,6 @@ begin=0, end=1000), dict( - # use cosine lr from 210 to 420 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -40,7 +46,7 @@ # codec settings codec = dict( type='SimCCLabel', - input_size=(192, 256), + input_size=input_size, sigma=(4.9, 5.66), simcc_split_ratio=2.0, normalize=False, @@ -69,14 +75,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, - out_channels=17, + out_channels=num_keypoints, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -102,12 +108,6 @@ data_root = 'data/coco/' backend_args = dict(backend='local') -# backend_args = dict( -# backend='petrel', -# path_mapping=dict({ -# f'{data_root}': 's3://openmmlab/datasets/detection/coco/', -# f'{data_root}': 's3://openmmlab/datasets/detection/coco/' -# })) # pipelines train_pipeline = [ @@ -177,7 +177,7 @@ # data loaders train_dataloader = dict( - batch_size=256, + batch_size=train_batch_size, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), @@ -190,7 +190,7 @@ pipeline=train_pipeline, )) val_dataloader = dict( - batch_size=64, + batch_size=val_batch_size, num_workers=10, persistent_workers=True, drop_last=False, diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-384x288.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-384x288.py index 4a9e72fab3..5216cf1b44 100644 --- a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-384x288.py +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb256-420e_coco-384x288.py @@ -1,9 +1,15 @@ _base_ = ['mmpose::_base_/default_runtime.py'] +# common setting +num_keypoints = 17 +input_size = (288, 384) + # runtime max_epochs = 420 stage2_num_epochs = 30 base_lr = 4e-3 +train_batch_size = 256 +val_batch_size = 64 train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) @@ -12,6 +18,7 @@ optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), paramwise_cfg=dict( norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) @@ -24,7 +31,6 @@ begin=0, end=1000), dict( - # use cosine lr from 210 to 420 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -40,7 +46,7 @@ # codec settings codec = dict( type='SimCCLabel', - input_size=(288, 384), + input_size=input_size, sigma=(6., 6.93), simcc_split_ratio=2.0, normalize=False, @@ -69,14 +75,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, - out_channels=17, + out_channels=num_keypoints, input_size=codec['input_size'], - in_featuremap_size=(9, 12), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -102,12 +108,6 @@ data_root = 'data/coco/' backend_args = dict(backend='local') -# backend_args = dict( -# backend='petrel', -# path_mapping=dict({ -# f'{data_root}': 's3://openmmlab/datasets/detection/coco/', -# f'{data_root}': 's3://openmmlab/datasets/detection/coco/' -# })) # pipelines train_pipeline = [ @@ -177,7 +177,7 @@ # data loaders train_dataloader = dict( - batch_size=256, + batch_size=train_batch_size, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), @@ -190,7 +190,7 @@ pipeline=train_pipeline, )) val_dataloader = dict( - batch_size=64, + batch_size=val_batch_size, num_workers=10, persistent_workers=True, drop_last=False, diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb512-700e_body8-halpe26-256x192.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb512-700e_body8-halpe26-256x192.py new file mode 100644 index 0000000000..6391044c87 --- /dev/null +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb512-700e_body8-halpe26-256x192.py @@ -0,0 +1,529 @@ +_base_ = ['mmpose::_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (192, 256) + +# runtime +max_epochs = 700 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 512 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.67, + widen_factor=0.75, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/rtmpose-m_simcc-body7_pt-body7_420e-256x192-e48f03d0_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=768, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb512-700e_body8-halpe26-384x288.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb512-700e_body8-halpe26-384x288.py new file mode 100644 index 0000000000..2944058bd1 --- /dev/null +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-m_8xb512-700e_body8-halpe26-384x288.py @@ -0,0 +1,542 @@ +_base_ = ['mmpose::_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (288, 384) + +# runtime +max_epochs = 700 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 512 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(6., 6.93), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.67, + widen_factor=0.75, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/rtmpose-m_simcc-body7_pt-body7_420e-384x288-65e718c4_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=768, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +# backend_args = dict(backend='local') +backend_args = dict( + backend='petrel', + path_mapping=dict({ + f'{data_root}': 's3://openmmlab/datasets/', + f'{data_root}': 's3://openmmlab/datasets/' + })) + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +# default_hooks = dict( +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-s_8xb1024-700e_body8-halpe26-256x192.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-s_8xb1024-700e_body8-halpe26-256x192.py new file mode 100644 index 0000000000..3f7d985079 --- /dev/null +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-s_8xb1024-700e_body8-halpe26-256x192.py @@ -0,0 +1,535 @@ +_base_ = ['mmpose::_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (192, 256) + +# runtime +max_epochs = 700 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 1024 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.0), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.33, + widen_factor=0.5, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/rtmpose-s_simcc-body7_pt-body7_420e-256x192-acd4a1ef_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=512, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.6, 1.4], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.6, 1.4], + rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py index 01176e0ddc..dd854f10f0 100644 --- a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-s_8xb256-420e_coco-256x192.py @@ -1,9 +1,15 @@ _base_ = ['mmpose::_base_/default_runtime.py'] +# common setting +num_keypoints = 17 +input_size = (192, 256) + # runtime max_epochs = 420 stage2_num_epochs = 30 base_lr = 4e-3 +train_batch_size = 256 +val_batch_size = 64 train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) @@ -12,6 +18,7 @@ optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.), + clip_grad=dict(max_norm=35, norm_type=2), paramwise_cfg=dict( norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) @@ -24,7 +31,6 @@ begin=0, end=1000), dict( - # use cosine lr from 210 to 420 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -40,7 +46,7 @@ # codec settings codec = dict( type='SimCCLabel', - input_size=(192, 256), + input_size=input_size, sigma=(4.9, 5.66), simcc_split_ratio=2.0, normalize=False, @@ -69,14 +75,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth' # noqa + 'rtmposev1/cspnext-s_udp-aic-coco_210e-256x192-92f5a029_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=512, - out_channels=17, + out_channels=num_keypoints, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -177,7 +183,7 @@ # data loaders train_dataloader = dict( - batch_size=256, + batch_size=train_batch_size, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), @@ -190,7 +196,7 @@ pipeline=train_pipeline, )) val_dataloader = dict( - batch_size=64, + batch_size=val_batch_size, num_workers=10, persistent_workers=True, drop_last=False, diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-t_8xb1024-700e_body8-halpe26-256x192.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-t_8xb1024-700e_body8-halpe26-256x192.py new file mode 100644 index 0000000000..69100b6cdc --- /dev/null +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-t_8xb1024-700e_body8-halpe26-256x192.py @@ -0,0 +1,536 @@ +_base_ = ['mmpose::_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (192, 256) + +# runtime +max_epochs = 700 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 1024 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(4.9, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.167, + widen_factor=0.375, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-tiny_udp-body7_210e-256x192-a3775292_20230504.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=384, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.6, 1.4], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.6, 1.4], + rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + # dict( + # type='EMAHook', + # ema_type='ExpMomentumEMA', + # momentum=0.0002, + # update_buffers=True, + # priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py index 14eb50f11a..1f344c72d1 100644 --- a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-t_8xb256-420e_coco-256x192.py @@ -1,9 +1,15 @@ _base_ = ['mmpose::_base_/default_runtime.py'] +# common setting +num_keypoints = 17 +input_size = (192, 256) + # runtime max_epochs = 420 stage2_num_epochs = 30 base_lr = 4e-3 +train_batch_size = 256 +val_batch_size = 64 train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) @@ -12,6 +18,7 @@ optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.), + clip_grad=dict(max_norm=35, norm_type=2), paramwise_cfg=dict( norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) @@ -24,7 +31,6 @@ begin=0, end=1000), dict( - # use cosine lr from 210 to 420 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -40,7 +46,7 @@ # codec settings codec = dict( type='SimCCLabel', - input_size=(192, 256), + input_size=input_size, sigma=(4.9, 5.66), simcc_split_ratio=2.0, normalize=False, @@ -69,14 +75,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth' # noqa + 'rtmposev1/cspnext-tiny_udp-aic-coco_210e-256x192-cbed682d_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=384, - out_channels=17, + out_channels=num_keypoints, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -177,7 +183,7 @@ # data loaders train_dataloader = dict( - batch_size=256, + batch_size=train_batch_size, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), @@ -190,7 +196,7 @@ pipeline=train_pipeline, )) val_dataloader = dict( - batch_size=64, + batch_size=val_batch_size, num_workers=10, persistent_workers=True, drop_last=False, diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-x_8xb256-700e_body8-halpe26-384x288.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-x_8xb256-700e_body8-halpe26-384x288.py new file mode 100644 index 0000000000..e0ad3aeb9d --- /dev/null +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-x_8xb256-700e_body8-halpe26-384x288.py @@ -0,0 +1,535 @@ +_base_ = ['mmpose::_base_/default_runtime.py'] + +# common setting +num_keypoints = 26 +input_size = (288, 384) + +# runtime +max_epochs = 700 +stage2_num_epochs = 20 +base_lr = 4e-3 +train_batch_size = 256 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(6., 6.93), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=1.33, + widen_factor=1.25, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-x_udp-body7_210e-384x288-d28b58e6_20230529.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=1280, + out_channels=num_keypoints, + input_size=input_size, + in_featuremap_size=tuple([s // 32 for s in input_size]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict( + type='GenerateTarget', + encoder=codec, + use_dataset_keypoint_weights=True), + dict(type='PackPoseInputs') +] + +# mapping +coco_halpe26 = [(i, i) for i in range(17)] + [(17, 20), (18, 22), (19, 24), + (20, 21), (21, 23), (22, 25)] + +aic_halpe26 = [(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), + (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15), + (12, 17), (13, 18)] + +crowdpose_halpe26 = [(0, 5), (1, 6), (2, 7), (3, 8), (4, 9), (5, 10), (6, 11), + (7, 12), (8, 13), (9, 14), (10, 15), (11, 16), (12, 17), + (13, 18)] + +mpii_halpe26 = [ + (0, 16), + (1, 14), + (2, 12), + (3, 11), + (4, 13), + (5, 15), + (8, 18), + (9, 17), + (10, 10), + (11, 8), + (12, 6), + (13, 5), + (14, 7), + (15, 9), +] + +jhmdb_halpe26 = [ + (0, 18), + (2, 17), + (3, 6), + (4, 5), + (5, 12), + (6, 11), + (7, 8), + (8, 7), + (9, 14), + (10, 13), + (11, 10), + (12, 9), + (13, 16), + (14, 15), +] + +halpe_halpe26 = [(i, i) for i in range(26)] + +ochuman_halpe26 = [(i, i) for i in range(17)] + +posetrack_halpe26 = [ + (0, 0), + (2, 17), + (3, 3), + (4, 4), + (5, 5), + (6, 6), + (7, 7), + (8, 8), + (9, 9), + (10, 10), + (11, 11), + (12, 12), + (13, 13), + (14, 14), + (15, 15), + (16, 16), +] + +# train datasets +dataset_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='detection/coco/train2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +dataset_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_train.json', + data_prefix=dict(img='pose/ai_challenge/ai_challenger_keypoint' + '_train_20170902/keypoint_train_images_20170902/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +dataset_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_trainval.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +dataset_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_train.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +dataset_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_train.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +dataset_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_train_v1.json', + data_prefix=dict(img='pose/Halpe/hico_20160224_det/images/train2015'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +dataset_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_train.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + pin_memory=True, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + dataset_coco, + dataset_aic, + dataset_crowdpose, + dataset_mpii, + dataset_jhmdb, + dataset_halpe, + dataset_posetrack, + ], + pipeline=train_pipeline, + test_mode=False, + )) + +# val datasets +val_coco = dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='coco/annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=coco_halpe26) + ], +) + +val_aic = dict( + type='AicDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='aic/annotations/aic_val.json', + data_prefix=dict( + img='pose/ai_challenge/ai_challenger_keypoint' + '_validation_20170911/keypoint_validation_images_20170911/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=aic_halpe26) + ], +) + +val_crowdpose = dict( + type='CrowdPoseDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='crowdpose/annotations/mmpose_crowdpose_test.json', + data_prefix=dict(img='pose/CrowdPose/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=crowdpose_halpe26) + ], +) + +val_mpii = dict( + type='MpiiDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='mpii/annotations/mpii_val.json', + data_prefix=dict(img='pose/MPI/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=mpii_halpe26) + ], +) + +val_jhmdb = dict( + type='JhmdbDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='jhmdb/annotations/Sub1_test.json', + data_prefix=dict(img='pose/JHMDB/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=jhmdb_halpe26) + ], +) + +val_halpe = dict( + type='HalpeDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='halpe/annotations/halpe_val_v1.json', + data_prefix=dict(img='detection/coco/val2017/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=halpe_halpe26) + ], +) + +val_ochuman = dict( + type='OCHumanDataset', + data_root=data_root, + data_mode=data_mode, + ann_file='ochuman/annotations/' + 'ochuman_coco_format_val_range_0.00_1.00.json', + data_prefix=dict(img='pose/OCHuman/images/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=ochuman_halpe26) + ], +) + +val_posetrack = dict( + type='PoseTrack18Dataset', + data_root=data_root, + data_mode=data_mode, + ann_file='posetrack18/annotations/posetrack18_val.json', + data_prefix=dict(img='pose/PoseChallenge2018/'), + pipeline=[ + dict( + type='KeypointConverter', + num_keypoints=num_keypoints, + mapping=posetrack_halpe26) + ], +) + +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type='CombinedDataset', + metainfo=dict(from_file='configs/_base_/datasets/halpe26.py'), + datasets=[ + val_coco, + val_aic, + val_crowdpose, + val_mpii, + val_jhmdb, + val_halpe, + val_ochuman, + val_posetrack, + ], + pipeline=val_pipeline, + test_mode=True, + )) + +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='AUC', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +test_evaluator = [dict(type='PCKAccuracy', thr=0.1), dict(type='AUC')] +val_evaluator = test_evaluator diff --git a/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-x_8xb256-700e_coco-384x288.py b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-x_8xb256-700e_coco-384x288.py new file mode 100644 index 0000000000..1441e07791 --- /dev/null +++ b/projects/rtmpose/rtmpose/body_2d_keypoint/rtmpose-x_8xb256-700e_coco-384x288.py @@ -0,0 +1,238 @@ +_base_ = ['mmpose::_base_/default_runtime.py'] + +# common setting +num_keypoints = 17 +input_size = (288, 384) + +# runtime +max_epochs = 700 +stage2_num_epochs = 20 +base_lr = 4e-3 +train_batch_size = 256 +val_batch_size = 64 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=1024) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(6., 6.93), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=1.33, + widen_factor=1.28, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-x_udp-body7_210e-384x288-d28b58e6_20230529.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=1280, + out_channels=num_keypoints, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True)) + +# base dataset settings +dataset_type = 'CocoDataset' +data_mode = 'topdown' +data_root = 'data/coco/' + +backend_args = dict(backend='local') +# backend_args = dict( +# backend='petrel', +# path_mapping=dict({ +# f'{data_root}': 's3://openmmlab/datasets/detection/coco/', +# f'{data_root}': 's3://openmmlab/datasets/detection/coco/' +# })) + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PhotometricDistortion'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/person_keypoints_train2017.json', + data_prefix=dict(img='train2017/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/person_keypoints_val2017.json', + bbox_file=f'{data_root}person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', + data_prefix=dict(img='val2017/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='CocoMetric', + ann_file=data_root + 'annotations/person_keypoints_val2017.json') +test_evaluator = val_evaluator diff --git a/projects/rtmpose/rtmpose/face_2d_keypoint/rtmpose-m_8xb256-120e_lapa-256x256.py b/projects/rtmpose/rtmpose/face_2d_keypoint/rtmpose-m_8xb256-120e_lapa-256x256.py new file mode 100644 index 0000000000..5490074a4d --- /dev/null +++ b/projects/rtmpose/rtmpose/face_2d_keypoint/rtmpose-m_8xb256-120e_lapa-256x256.py @@ -0,0 +1,246 @@ +_base_ = ['mmpose::_base_/default_runtime.py'] + +# common setting +num_keypoints = 106 +input_size = (256, 256) + +# runtime +max_epochs = 120 +stage2_num_epochs = 10 +base_lr = 4e-3 +train_batch_size = 256 +val_batch_size = 32 + +train_cfg = dict(max_epochs=max_epochs, val_interval=1) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.005, + begin=30, + end=max_epochs, + T_max=max_epochs - 30, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(5.66, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.67, + widen_factor=0.75, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmdetection/v3.0/' + 'rtmdet/cspnext_rsb_pretrain/cspnext-m_8xb256-rsb-a1-600e_in1k-ecb3bbd9.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=768, + out_channels=num_keypoints, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True, )) + +# base dataset settings +dataset_type = 'LapaDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.2), + dict(type='MedianBlur', p=0.2), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/lapa_trainval.json', + data_prefix=dict(img='LaPa/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=4, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/lapa_test.json', + data_prefix=dict(img='LaPa/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = dict( + batch_size=val_batch_size, + num_workers=4, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/lapa_test.json', + data_prefix=dict(img='LaPa/'), + test_mode=True, + pipeline=val_pipeline, + )) + +# hooks +default_hooks = dict( + checkpoint=dict( + save_best='NME', rule='less', max_keep_ckpts=3, interval=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='NME', + norm_mode='keypoint_distance', +) +test_evaluator = val_evaluator diff --git a/projects/rtmpose/rtmpose/face_2d_keypoint/rtmpose-s_8xb256-120e_lapa-256x256.py b/projects/rtmpose/rtmpose/face_2d_keypoint/rtmpose-s_8xb256-120e_lapa-256x256.py new file mode 100644 index 0000000000..2763ecd927 --- /dev/null +++ b/projects/rtmpose/rtmpose/face_2d_keypoint/rtmpose-s_8xb256-120e_lapa-256x256.py @@ -0,0 +1,246 @@ +_base_ = ['mmpose::_base_/default_runtime.py'] + +# common setting +num_keypoints = 106 +input_size = (256, 256) + +# runtime +max_epochs = 120 +stage2_num_epochs = 10 +base_lr = 4e-3 +train_batch_size = 256 +val_batch_size = 32 + +train_cfg = dict(max_epochs=max_epochs, val_interval=1) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.005, + begin=30, + end=max_epochs, + T_max=max_epochs - 30, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(5.66, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.33, + widen_factor=0.5, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmdetection/v3.0/' + 'rtmdet/cspnext_rsb_pretrain/cspnext-s_imagenet_600e-ea671761.pth') + ), + head=dict( + type='RTMCCHead', + in_channels=512, + out_channels=num_keypoints, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True, )) + +# base dataset settings +dataset_type = 'LapaDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.2), + dict(type='MedianBlur', p=0.2), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/lapa_trainval.json', + data_prefix=dict(img='LaPa/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=4, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/lapa_test.json', + data_prefix=dict(img='LaPa/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = dict( + batch_size=val_batch_size, + num_workers=4, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/lapa_test.json', + data_prefix=dict(img='LaPa/'), + test_mode=True, + pipeline=val_pipeline, + )) + +# hooks +default_hooks = dict( + checkpoint=dict( + save_best='NME', rule='less', max_keep_ckpts=3, interval=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='NME', + norm_mode='keypoint_distance', +) +test_evaluator = val_evaluator diff --git a/projects/rtmpose/rtmpose/face_2d_keypoint/rtmpose-t_8xb256-120e_lapa-256x256.py b/projects/rtmpose/rtmpose/face_2d_keypoint/rtmpose-t_8xb256-120e_lapa-256x256.py new file mode 100644 index 0000000000..ad6e4b212f --- /dev/null +++ b/projects/rtmpose/rtmpose/face_2d_keypoint/rtmpose-t_8xb256-120e_lapa-256x256.py @@ -0,0 +1,246 @@ +_base_ = ['mmpose::_base_/default_runtime.py'] + +# common setting +num_keypoints = 106 +input_size = (256, 256) + +# runtime +max_epochs = 120 +stage2_num_epochs = 10 +base_lr = 4e-3 +train_batch_size = 256 +val_batch_size = 32 + +train_cfg = dict(max_epochs=max_epochs, val_interval=1) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.005, + begin=30, + end=max_epochs, + T_max=max_epochs - 30, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(5.66, 5.66), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=0.167, + widen_factor=0.375, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmdetection/v3.0/' + 'rtmdet/cspnext_rsb_pretrain/cspnext-tiny_imagenet_600e-3a2dd350.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=384, + out_channels=num_keypoints, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True, )) + +# base dataset settings +dataset_type = 'LapaDataset' +data_mode = 'topdown' +data_root = 'data/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=80), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.2), + dict(type='MedianBlur', p=0.2), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.75, 1.25], + rotate_factor=60), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/lapa_trainval.json', + data_prefix=dict(img='LaPa/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=4, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/lapa_test.json', + data_prefix=dict(img='LaPa/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = dict( + batch_size=val_batch_size, + num_workers=4, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/lapa_test.json', + data_prefix=dict(img='LaPa/'), + test_mode=True, + pipeline=val_pipeline, + )) + +# hooks +default_hooks = dict( + checkpoint=dict( + save_best='NME', rule='less', max_keep_ckpts=3, interval=1)) + +custom_hooks = [ + # dict( + # type='EMAHook', + # ema_type='ExpMomentumEMA', + # momentum=0.0002, + # update_buffers=True, + # priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='NME', + norm_mode='keypoint_distance', +) +test_evaluator = val_evaluator diff --git a/projects/rtmpose/rtmpose/hand_2d_keypoint/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py b/projects/rtmpose/rtmpose/hand_2d_keypoint/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py index 3ce8021045..fc96cf7e67 100644 --- a/projects/rtmpose/rtmpose/hand_2d_keypoint/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py +++ b/projects/rtmpose/rtmpose/hand_2d_keypoint/rtmpose-m_8xb32-210e_coco-wholebody-hand-256x256.py @@ -1,9 +1,15 @@ _base_ = ['mmpose::_base_/default_runtime.py'] +# common setting +num_keypoints = 21 +input_size = (256, 256) + # runtime max_epochs = 210 stage2_num_epochs = 30 base_lr = 4e-3 +train_batch_size = 32 +val_batch_size = 32 train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) @@ -12,6 +18,7 @@ optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), paramwise_cfg=dict( norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) @@ -24,7 +31,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -40,7 +46,7 @@ # codec settings codec = dict( type='SimCCLabel', - input_size=(256, 256), + input_size=input_size, sigma=(5.66, 5.66), simcc_split_ratio=2.0, normalize=False, @@ -69,14 +75,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, - out_channels=21, + out_channels=num_keypoints, input_size=codec['input_size'], - in_featuremap_size=(8, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -102,12 +108,6 @@ data_root = 'data/coco/' backend_args = dict(backend='local') -# backend_args = dict( -# backend='petrel', -# path_mapping=dict({ -# f'{data_root}': 's3://openmmlab/datasets/detection/coco/', -# f'{data_root}': 's3://openmmlab/datasets/detection/coco/' -# })) # pipelines train_pipeline = [ @@ -178,7 +178,7 @@ # data loaders train_dataloader = dict( - batch_size=32, + batch_size=train_batch_size, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), @@ -191,7 +191,7 @@ pipeline=train_pipeline, )) val_dataloader = dict( - batch_size=32, + batch_size=val_batch_size, num_workers=10, persistent_workers=True, drop_last=False, diff --git a/projects/rtmpose/rtmpose/pruning/README.md b/projects/rtmpose/rtmpose/pruning/README.md index 28be530cc1..0d10a89509 100644 --- a/projects/rtmpose/rtmpose/pruning/README.md +++ b/projects/rtmpose/rtmpose/pruning/README.md @@ -82,7 +82,7 @@ CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 PORT=29500 ./tools/dist_test.sh \ ### Deploy -For a pruned model, you only need to use the pruning deploy config to instead the pretrain config to deploy the pruned version of your model. If you are not familiar with mmdeploy, it's recommended to refer to [MMDeploy document](https://mmdeploy.readthedocs.io/en/1.x/02-how-to-run/convert_model.html). +For a pruned model, you only need to use the pruning deploy config to instead the pretrain config to deploy the pruned version of your model. If you are not familiar with mmdeploy, it's recommended to refer to [MMDeploy document](https://mmdeploy.readthedocs.io/en/latest/02-how-to-run/convert_model.html). ```bash python {mmdeploy}/tools/deploy.py \ @@ -107,7 +107,7 @@ The divisor is important for the actual inference speed, and we suggest you to t ## Reference -[GroupFisher in MMRazor](https://github.com/open-mmlab/mmrazor/tree/dev-1.x/configs/pruning/base/group_fisher) +[GroupFisher in MMRazor](https://github.com/open-mmlab/mmrazor/tree/main/configs/pruning/base/group_fisher) [rp_sa_f]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.pth [rp_sa_l]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.json diff --git a/projects/rtmpose/rtmpose/pruning/README_CN.md b/projects/rtmpose/rtmpose/pruning/README_CN.md index 945160b246..f3da9ef5c7 100644 --- a/projects/rtmpose/rtmpose/pruning/README_CN.md +++ b/projects/rtmpose/rtmpose/pruning/README_CN.md @@ -81,7 +81,7 @@ CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 PORT=29500 ./tools/dist_test.sh \ ### Deploy -对于剪枝模型,你只需要使用剪枝部署 config 来代替预训练 config 来部署模型的剪枝版本。如果你不熟悉 MMDeploy,请参看[MMDeploy document](https://mmdeploy.readthedocs.io/en/1.x/02-how-to-run/convert_model.html)。 +对于剪枝模型,你只需要使用剪枝部署 config 来代替预训练 config 来部署模型的剪枝版本。如果你不熟悉 MMDeploy,请参看[MMDeploy document](https://mmdeploy.readthedocs.io/en/latest/02-how-to-run/convert_model.html)。 ```bash python {mmdeploy}/tools/deploy.py \ @@ -106,7 +106,7 @@ divisor 设置十分重要,我们建议你在尝试 \[1,2,4,8,16,32\],以找 ## Reference -[GroupFisher in MMRazor](https://github.com/open-mmlab/mmrazor/tree/dev-1.x/configs/pruning/base/group_fisher) +[GroupFisher in MMRazor](https://github.com/open-mmlab/mmrazor/tree/main/configs/pruning/base/group_fisher) [rp_sa_f]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.pth [rp_sa_l]: https://download.openmmlab.com/mmrazor/v1/pruning/group_fisher/rtmpose-s/group_fisher_finetune_rtmpose-s_8xb256-420e_aic-coco-256x192.json diff --git a/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py b/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py index 38f2a34312..5fd8ce8e1e 100644 --- a/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py +++ b/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb32-270e_coco-wholebody-384x288.py @@ -1,9 +1,15 @@ _base_ = ['mmpose::_base_/default_runtime.py'] +# common setting +num_keypoints = 133 +input_size = (288, 384) + # runtime max_epochs = 270 stage2_num_epochs = 30 base_lr = 4e-3 +train_batch_size = 32 +val_batch_size = 32 train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) @@ -12,6 +18,7 @@ optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), paramwise_cfg=dict( norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) @@ -24,7 +31,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -40,7 +46,7 @@ # codec settings codec = dict( type='SimCCLabel', - input_size=(288, 384), + input_size=input_size, sigma=(6., 6.93), simcc_split_ratio=2.0, normalize=False, @@ -69,14 +75,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa + 'rtmposev1/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=1024, - out_channels=133, + out_channels=num_keypoints, input_size=codec['input_size'], - in_featuremap_size=(9, 12), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -102,12 +108,6 @@ data_root = 'data/coco/' backend_args = dict(backend='local') -# backend_args = dict( -# backend='petrel', -# path_mapping=dict({ -# f'{data_root}': 's3://openmmlab/datasets/detection/coco/', -# f'{data_root}': 's3://openmmlab/datasets/detection/coco/' -# })) # pipelines train_pipeline = [ @@ -177,7 +177,7 @@ # data loaders train_dataloader = dict( - batch_size=32, + batch_size=train_batch_size, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), @@ -190,7 +190,7 @@ pipeline=train_pipeline, )) val_dataloader = dict( - batch_size=32, + batch_size=val_batch_size, num_workers=10, persistent_workers=True, drop_last=False, @@ -202,6 +202,8 @@ ann_file='annotations/coco_wholebody_val_v1.0.json', data_prefix=dict(img='val2017/'), test_mode=True, + bbox_file='data/coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', pipeline=val_pipeline, )) test_dataloader = val_dataloader diff --git a/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py b/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py index 599b3f445f..f4005028b6 100644 --- a/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py +++ b/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-l_8xb64-270e_coco-wholebody-256x192.py @@ -1,9 +1,15 @@ _base_ = ['mmpose::_base_/default_runtime.py'] +# common setting +num_keypoints = 133 +input_size = (192, 256) + # runtime max_epochs = 270 stage2_num_epochs = 30 base_lr = 4e-3 +train_batch_size = 64 +val_batch_size = 32 train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) @@ -12,6 +18,7 @@ optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), paramwise_cfg=dict( norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) @@ -24,7 +31,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -40,7 +46,7 @@ # codec settings codec = dict( type='SimCCLabel', - input_size=(192, 256), + input_size=input_size, sigma=(4.9, 5.66), simcc_split_ratio=2.0, normalize=False, @@ -69,14 +75,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa + 'rtmposev1/cspnext-l_udp-aic-coco_210e-256x192-273b7631_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=1024, - out_channels=133, + out_channels=num_keypoints, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -102,12 +108,6 @@ data_root = 'data/coco/' backend_args = dict(backend='local') -# backend_args = dict( -# backend='petrel', -# path_mapping=dict({ -# f'{data_root}': 's3://openmmlab/datasets/detection/coco/', -# f'{data_root}': 's3://openmmlab/datasets/detection/coco/' -# })) # pipelines train_pipeline = [ @@ -177,7 +177,7 @@ # data loaders train_dataloader = dict( - batch_size=64, + batch_size=train_batch_size, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), @@ -190,7 +190,7 @@ pipeline=train_pipeline, )) val_dataloader = dict( - batch_size=32, + batch_size=val_batch_size, num_workers=10, persistent_workers=True, drop_last=False, @@ -202,6 +202,8 @@ ann_file='annotations/coco_wholebody_val_v1.0.json', data_prefix=dict(img='val2017/'), test_mode=True, + bbox_file='data/coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', pipeline=val_pipeline, )) test_dataloader = val_dataloader diff --git a/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py b/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py index 9a57231f86..d0096056a4 100644 --- a/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py +++ b/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-m_8xb64-270e_coco-wholebody-256x192.py @@ -1,9 +1,15 @@ _base_ = ['mmpose::_base_/default_runtime.py'] +# common setting +num_keypoints = 133 +input_size = (192, 256) + # runtime max_epochs = 270 stage2_num_epochs = 30 base_lr = 4e-3 +train_batch_size = 64 +val_batch_size = 32 train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) @@ -12,6 +18,7 @@ optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), paramwise_cfg=dict( norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) @@ -24,7 +31,6 @@ begin=0, end=1000), dict( - # use cosine lr from 150 to 300 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, @@ -40,7 +46,7 @@ # codec settings codec = dict( type='SimCCLabel', - input_size=(192, 256), + input_size=input_size, sigma=(4.9, 5.66), simcc_split_ratio=2.0, normalize=False, @@ -69,14 +75,14 @@ type='Pretrained', prefix='backbone.', checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' - 'rtmpose/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa + 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' # noqa )), head=dict( type='RTMCCHead', in_channels=768, - out_channels=133, + out_channels=num_keypoints, input_size=codec['input_size'], - in_featuremap_size=(6, 8), + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( @@ -102,12 +108,6 @@ data_root = 'data/coco/' backend_args = dict(backend='local') -# backend_args = dict( -# backend='petrel', -# path_mapping=dict({ -# f'{data_root}': 's3://openmmlab/datasets/detection/coco/', -# f'{data_root}': 's3://openmmlab/datasets/detection/coco/' -# })) # pipelines train_pipeline = [ @@ -177,7 +177,7 @@ # data loaders train_dataloader = dict( - batch_size=64, + batch_size=train_batch_size, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), @@ -190,7 +190,7 @@ pipeline=train_pipeline, )) val_dataloader = dict( - batch_size=32, + batch_size=val_batch_size, num_workers=10, persistent_workers=True, drop_last=False, @@ -202,6 +202,8 @@ ann_file='annotations/coco_wholebody_val_v1.0.json', data_prefix=dict(img='val2017/'), test_mode=True, + bbox_file='data/coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', pipeline=val_pipeline, )) test_dataloader = val_dataloader diff --git a/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-x_8xb32-270e_coco-wholebody-384x288.py b/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-x_8xb32-270e_coco-wholebody-384x288.py new file mode 100644 index 0000000000..429016e825 --- /dev/null +++ b/projects/rtmpose/rtmpose/wholebody_2d_keypoint/rtmpose-x_8xb32-270e_coco-wholebody-384x288.py @@ -0,0 +1,233 @@ +_base_ = ['mmpose::_base_/default_runtime.py'] + +# common setting +num_keypoints = 133 +input_size = (288, 384) + +# runtime +max_epochs = 270 +stage2_num_epochs = 30 +base_lr = 4e-3 +train_batch_size = 32 +val_batch_size = 32 + +train_cfg = dict(max_epochs=max_epochs, val_interval=10) +randomness = dict(seed=21) + +# optimizer +optim_wrapper = dict( + type='OptimWrapper', + optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), + clip_grad=dict(max_norm=35, norm_type=2), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +# learning rate +param_scheduler = [ + dict( + type='LinearLR', + start_factor=1.0e-5, + by_epoch=False, + begin=0, + end=1000), + dict( + type='CosineAnnealingLR', + eta_min=base_lr * 0.05, + begin=max_epochs // 2, + end=max_epochs, + T_max=max_epochs // 2, + by_epoch=True, + convert_to_iter_based=True), +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# codec settings +codec = dict( + type='SimCCLabel', + input_size=input_size, + sigma=(6., 6.93), + simcc_split_ratio=2.0, + normalize=False, + use_dark=False) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + _scope_='mmdet', + type='CSPNeXt', + arch='P5', + expand_ratio=0.5, + deepen_factor=1.33, + widen_factor=1.25, + out_indices=(4, ), + channel_attention=True, + norm_cfg=dict(type='SyncBN'), + act_cfg=dict(type='SiLU'), + init_cfg=dict( + type='Pretrained', + prefix='backbone.', + checkpoint='https://download.openmmlab.com/mmpose/v1/projects/' + 'rtmposev1/cspnext-x_udp-body7_210e-384x288-d28b58e6_20230529.pth' # noqa + )), + head=dict( + type='RTMCCHead', + in_channels=1280, + out_channels=num_keypoints, + input_size=codec['input_size'], + in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), + simcc_split_ratio=codec['simcc_split_ratio'], + final_layer_kernel_size=7, + gau_cfg=dict( + hidden_dims=256, + s=128, + expansion_factor=2, + dropout_rate=0., + drop_path=0., + act_fn='SiLU', + use_rel_bias=False, + pos_enc=False), + loss=dict( + type='KLDiscretLoss', + use_target_weight=True, + beta=10., + label_softmax=True), + decoder=codec), + test_cfg=dict(flip_test=True, )) + +# base dataset settings +dataset_type = 'CocoWholeBodyDataset' +data_mode = 'topdown' +data_root = 'data/coco/' + +backend_args = dict(backend='local') + +# pipelines +train_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', scale_factor=[0.5, 1.5], rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=1.0), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +train_pipeline_stage2 = [ + dict(type='LoadImage', backend_args=backend_args), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict(type='RandomHalfBody'), + dict( + type='RandomBBoxTransform', + shift_factor=0., + scale_factor=[0.5, 1.5], + rotate_factor=90), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='mmdet.YOLOXHSVRandomAug'), + dict( + type='Albumentation', + transforms=[ + dict(type='Blur', p=0.1), + dict(type='MedianBlur', p=0.1), + dict( + type='CoarseDropout', + max_holes=1, + max_height=0.4, + max_width=0.4, + min_holes=1, + min_height=0.2, + min_width=0.2, + p=0.5), + ]), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=train_batch_size, + num_workers=10, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/coco_wholebody_train_v1.0.json', + data_prefix=dict(img='train2017/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=val_batch_size, + num_workers=10, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/coco_wholebody_val_v1.0.json', + data_prefix=dict(img='val2017/'), + test_mode=True, + bbox_file='data/coco/person_detection_results/' + 'COCO_val2017_detections_AP_H_56_person.json', + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# hooks +default_hooks = dict( + checkpoint=dict( + save_best='coco-wholebody/AP', rule='greater', max_keep_ckpts=1)) + +custom_hooks = [ + dict( + type='EMAHook', + ema_type='ExpMomentumEMA', + momentum=0.0002, + update_buffers=True, + priority=49), + dict( + type='mmdet.PipelineSwitchHook', + switch_epoch=max_epochs - stage2_num_epochs, + switch_pipeline=train_pipeline_stage2) +] + +# evaluators +val_evaluator = dict( + type='CocoWholeBodyMetric', + ann_file=data_root + 'annotations/coco_wholebody_val_v1.0.json') +test_evaluator = val_evaluator diff --git a/projects/skps/README.md b/projects/skps/README.md new file mode 100644 index 0000000000..13e8c4a7ab --- /dev/null +++ b/projects/skps/README.md @@ -0,0 +1,83 @@ +# Simple Keypoints + +## Description + +Author: @2120140200@mail.nankai.edu.cn + +It is a simple keypoints detector model. The model predict a score heatmap and an encoded location map. +The result in wflw achieves 3.94 NME. + +## Usage + +### Prerequisites + +- Python 3.7 +- PyTorch 1.6 or higher +- [MIM](https://github.com/open-mmlab/mim) v0.33 or higher +- [MMPose](https://github.com/open-mmlab/mmpose) v1.0.0rc0 or higher + +All the commands below rely on the correct configuration of `PYTHONPATH`, which should point to the project's directory so that Python can locate the module files. In `example_project/` root directory, run the following line to add the current directory to `PYTHONPATH`: + +```shell +export PYTHONPATH=`pwd`:$PYTHONPATH +``` + +### Data Preparation + +Prepare the COCO dataset according to the [instruction](https://mmpose.readthedocs.io/en/dev-1.x/dataset_zoo/2d_body_keypoint.html#coco). + +### Training commands + +**To train with single GPU:** + +```shell +mim train mmpose configs/td-hm_hrnetv2-w18_skps-1xb64-80e_wflw-256x256.py +``` + +**To train with multiple GPUs:** + +```shell +mim train mmpose configs/td-hm_hrnetv2-w18_skps-1xb64-80e_wflw-256x256.py --launcher pytorch --gpus 8 +``` + +**To train with multiple GPUs by slurm:** + +```shell +mim train mmpose configs/td-hm_hrnetv2-w18_skps-1xb64-80e_wflw-256x256.py --launcher slurm \ + --gpus 16 --gpus-per-node 8 --partition $PARTITION +``` + +### Testing commands + +**To test with single GPU:** + +```shell +mim test mmpose configs/td-hm_hrnetv2-w18_skps-1xb64-80e_wflw-256x256.py -C $CHECKPOINT +``` + +**To test with multiple GPUs:** + +```shell +mim test mmpose configs/td-hm_hrnetv2-w18_skps-1xb64-80e_wflw-256x256.py -C $CHECKPOINT --launcher pytorch --gpus 8 +``` + +**To test with multiple GPUs by slurm:** + +```shell +mim test mmpose configs/td-hm_hrnetv2-w18_skps-1xb64-80e_wflw-256x256.py -C $CHECKPOINT --launcher slurm \ + --gpus 16 --gpus-per-node 8 --partition $PARTITION +``` + +## Results + +WFLW + +| Arch | Input Size | NME*test* | NME*pose* | NME*illumination* | NME*occlusion* | NME*blur* | NME*makeup* | NME*expression* | ckpt | log | +| :--------- | :--------: | :------------------: | :------------------: | :--------------------------: | :-----------------------: | :------------------: | :--------------------: | :------------------------: | :--------: | :-------: | +| [skps](./configs/td-hm_hrnetv2-w18_skps-1xb64-80e_wflw-256x256.py) | 256x256 | 3.88 | 6.60 | 3.81 | 4.57 | 4.44 | 3.75 | 4.13 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/skps/best_NME_epoch_80.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/skps/20230522_142437.log) | + +COFW + +| Arch | Input Size | NME | ckpt | log | +| :------------------------------------------------------------- | :--------: | :--: | :------------------------------------------------------------: | :------------------------------------------------------------: | +| [skps](./configs/td-hm_hrnetv2-w18_skps-1xb16-160e_cofw-256x256.py) | 256x256 | 3.20 | [ckpt](https://download.openmmlab.com/mmpose/v1/projects/skps/best_NME_epoch_113.pth) | [log](https://download.openmmlab.com/mmpose/v1/projects/skps/20230524_074949.log) | diff --git a/projects/skps/configs/td-hm_hrnetv2-w18_skps-1xb16-160e_cofw-256x256.py b/projects/skps/configs/td-hm_hrnetv2-w18_skps-1xb16-160e_cofw-256x256.py new file mode 100644 index 0000000000..494c4325df --- /dev/null +++ b/projects/skps/configs/td-hm_hrnetv2-w18_skps-1xb16-160e_cofw-256x256.py @@ -0,0 +1,176 @@ +custom_imports = dict(imports=['custom_codecs', 'models']) + +_base_ = ['mmpose::_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=160, val_interval=1) + +# optimizer +optim_wrapper = dict( + optimizer=dict(type='AdamW', lr=2e-3, weight_decay=0.0005)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=160, + milestones=[80, 120], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict(checkpoint=dict(save_best='NME', rule='less', interval=1)) + +# codec settings +codec = dict( + type='SKPSHeatmap', input_size=(256, 256), heatmap_size=(64, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='HRNet', + in_channels=3, + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(18, 36)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(18, 36, 72)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(18, 36, 72, 144), + multiscale_output=True), + upsample=dict(mode='bilinear', align_corners=False)), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w18'), + ), + neck=dict( + type='FeatureMapProcessor', + concat=True, + ), + head=dict( + type='SKPSHead', + in_channels=270, + out_channels=29, + conv_out_channels=(270, ), + conv_kernel_sizes=(1, ), + heatmap_loss=dict(type='AdaptiveWingLoss', use_target_weight=True), + offside_loss=dict(type='AdaptiveWingLoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'COFWDataset' +data_mode = 'topdown' +data_root = 'data/cofw/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale', padding=1), + dict(type='RandomFlip', direction='horizontal'), + dict( + type='Albumentation', + transforms=[ + dict(type='RandomBrightnessContrast', p=0.5), + dict(type='HueSaturationValue', p=0.5), + dict(type='GaussianBlur', p=0.5), + dict(type='GaussNoise', p=0.1), + dict( + type='CoarseDropout', + max_holes=8, + max_height=0.2, + max_width=0.2, + min_holes=1, + min_height=0.1, + min_width=0.1, + p=0.5), + ]), + dict( + type='RandomBBoxTransform', + shift_prob=0., + rotate_factor=45, + scale_factor=(0.75, 1.25), + scale_prob=0), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale', padding=1), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=16, + num_workers=4, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/cofw_train.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=4, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/cofw_test.json', + data_prefix=dict(img='images/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = dict( + type='NME', + norm_mode='keypoint_distance', +) +test_evaluator = val_evaluator diff --git a/projects/skps/configs/td-hm_hrnetv2-w18_skps-1xb64-80e_wflw-256x256.py b/projects/skps/configs/td-hm_hrnetv2-w18_skps-1xb64-80e_wflw-256x256.py new file mode 100644 index 0000000000..0547ebcff2 --- /dev/null +++ b/projects/skps/configs/td-hm_hrnetv2-w18_skps-1xb64-80e_wflw-256x256.py @@ -0,0 +1,176 @@ +custom_imports = dict(imports=['custom_codecs', 'models']) + +_base_ = ['mmpose::_base_/default_runtime.py'] + +# runtime +train_cfg = dict(max_epochs=80, val_interval=1) + +# optimizer +optim_wrapper = dict( + optimizer=dict(type='AdamW', lr=2e-3, weight_decay=0.0005)) + +# learning policy +param_scheduler = [ + dict( + type='LinearLR', begin=0, end=500, start_factor=0.001, + by_epoch=False), # warm-up + dict( + type='MultiStepLR', + begin=0, + end=80, + milestones=[40, 60], + gamma=0.1, + by_epoch=True) +] + +# automatically scaling LR based on the actual training batch size +auto_scale_lr = dict(base_batch_size=512) + +# hooks +default_hooks = dict(checkpoint=dict(save_best='NME', rule='less', interval=1)) + +# codec settings +codec = dict( + type='SKPSHeatmap', input_size=(256, 256), heatmap_size=(64, 64), sigma=2) + +# model settings +model = dict( + type='TopdownPoseEstimator', + data_preprocessor=dict( + type='PoseDataPreprocessor', + mean=[123.675, 116.28, 103.53], + std=[58.395, 57.12, 57.375], + bgr_to_rgb=True), + backbone=dict( + type='HRNet', + in_channels=3, + extra=dict( + stage1=dict( + num_modules=1, + num_branches=1, + block='BOTTLENECK', + num_blocks=(4, ), + num_channels=(64, )), + stage2=dict( + num_modules=1, + num_branches=2, + block='BASIC', + num_blocks=(4, 4), + num_channels=(18, 36)), + stage3=dict( + num_modules=4, + num_branches=3, + block='BASIC', + num_blocks=(4, 4, 4), + num_channels=(18, 36, 72)), + stage4=dict( + num_modules=3, + num_branches=4, + block='BASIC', + num_blocks=(4, 4, 4, 4), + num_channels=(18, 36, 72, 144), + multiscale_output=True), + upsample=dict(mode='bilinear', align_corners=False)), + init_cfg=dict( + type='Pretrained', checkpoint='open-mmlab://msra/hrnetv2_w18'), + ), + neck=dict( + type='FeatureMapProcessor', + concat=True, + ), + head=dict( + type='SKPSHead', + in_channels=270, + out_channels=98, + conv_out_channels=(270, ), + conv_kernel_sizes=(1, ), + heatmap_loss=dict(type='AdaptiveWingLoss', use_target_weight=True), + offside_loss=dict(type='AdaptiveWingLoss', use_target_weight=True), + decoder=codec), + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + +# base dataset settings +dataset_type = 'WFLWDataset' +data_mode = 'topdown' +data_root = './data/wflw/' + +# pipelines +train_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='RandomFlip', direction='horizontal'), + dict( + type='Albumentation', + transforms=[ + dict(type='RandomBrightnessContrast', p=0.5), + dict(type='HueSaturationValue', p=0.5), + dict(type='GaussianBlur', p=0.5), + dict(type='GaussNoise', p=0.1), + dict( + type='CoarseDropout', + max_holes=8, + max_height=0.2, + max_width=0.2, + min_holes=1, + min_height=0.1, + min_width=0.1, + p=0.5), + ]), + dict( + type='RandomBBoxTransform', + shift_prob=0.0, + rotate_factor=45, + scale_factor=(0.75, 1.25), + scale_prob=1.), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='GenerateTarget', encoder=codec), + dict(type='PackPoseInputs') +] +val_pipeline = [ + dict(type='LoadImage'), + dict(type='GetBBoxCenterScale'), + dict(type='TopdownAffine', input_size=codec['input_size']), + dict(type='PackPoseInputs') +] + +# data loaders +train_dataloader = dict( + batch_size=64, + num_workers=4, + persistent_workers=True, + sampler=dict(type='DefaultSampler', shuffle=True), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/face_landmarks_wflw_train.json', + data_prefix=dict(img='images/'), + pipeline=train_pipeline, + )) +val_dataloader = dict( + batch_size=32, + num_workers=4, + persistent_workers=True, + drop_last=False, + sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), + dataset=dict( + type=dataset_type, + data_root=data_root, + data_mode=data_mode, + ann_file='annotations/face_landmarks_wflw_test.json', + data_prefix=dict(img='images/'), + test_mode=True, + pipeline=val_pipeline, + )) +test_dataloader = val_dataloader + +# evaluators +val_evaluator = dict( + type='NME', + norm_mode='keypoint_distance', +) +test_evaluator = val_evaluator diff --git a/projects/skps/custom_codecs/__init__.py b/projects/skps/custom_codecs/__init__.py new file mode 100644 index 0000000000..b346b55de6 --- /dev/null +++ b/projects/skps/custom_codecs/__init__.py @@ -0,0 +1,3 @@ +from .skps_heatmap import SKPSHeatmap + +__all__ = ['SKPSHeatmap'] diff --git a/projects/skps/custom_codecs/skps_heatmap.py b/projects/skps/custom_codecs/skps_heatmap.py new file mode 100644 index 0000000000..f542ff2970 --- /dev/null +++ b/projects/skps/custom_codecs/skps_heatmap.py @@ -0,0 +1,164 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from typing import Optional, Tuple + +import numpy as np + +from mmpose.codecs.base import BaseKeypointCodec +from mmpose.codecs.utils.gaussian_heatmap import \ + generate_unbiased_gaussian_heatmaps +from mmpose.codecs.utils.post_processing import get_heatmap_maximum +from mmpose.registry import KEYPOINT_CODECS + + +@KEYPOINT_CODECS.register_module() +class SKPSHeatmap(BaseKeypointCodec): + """Generate heatmap the same with MSRAHeatmap, and produce offset map + within x and y directions. + + Note: + + - instance number: N + - keypoint number: K + - keypoint dimension: D + - image size: [w, h] + - heatmap size: [W, H] + - offset_map size: [W, H] + + Encoded: + + - heatmaps (np.ndarray): The generated heatmap in shape (K, H, W) + where [W, H] is the `heatmap_size` + - offset_maps (np.ndarray): The generated offset map in x and y + direction in shape (2K, H, W) where [W, H] is the + `offset_map_size` + - keypoint_weights (np.ndarray): The target weights in shape (N, K) + + Args: + input_size (tuple): Image size in [w, h] + heatmap_size (tuple): Heatmap size in [W, H] + sigma (float): The sigma value of the Gaussian heatmap + """ + + def __init__(self, input_size: Tuple[int, int], + heatmap_size: Tuple[int, int], sigma: float) -> None: + super().__init__() + self.input_size = input_size + self.heatmap_size = heatmap_size + self.sigma = sigma + self.scale_factor = (np.array(input_size) / + heatmap_size).astype(np.float32) + + self.y_range, self.x_range = np.meshgrid( + np.arange(0, self.heatmap_size[1]), + np.arange(0, self.heatmap_size[0]), + indexing='ij') + + def encode(self, + keypoints: np.ndarray, + keypoints_visible: Optional[np.ndarray] = None) -> dict: + """Encode keypoints into heatmaps. Note that the original keypoint + coordinates should be in the input image space. + + Args: + keypoints (np.ndarray): Keypoint coordinates in shape (N, K, D) + keypoints_visible (np.ndarray): Keypoint visibilities in shape + (N, K) + + Returns: + dict: + - heatmaps (np.ndarray): The generated heatmap in shape + (K, H, W) where [W, H] is the `heatmap_size` + - offset_maps (np.ndarray): The generated offset maps in x and y + directions in shape (2*K, H, W) where [W, H] is the + `offset_map_size` + - keypoint_weights (np.ndarray): The target weights in shape + (N, K) + """ + + assert keypoints.shape[0] == 1, ( + f'{self.__class__.__name__} only support single-instance ' + 'keypoint encoding') + + if keypoints_visible is None: + keypoints_visible = np.ones(keypoints.shape[:2], dtype=np.float32) + + heatmaps, keypoint_weights = generate_unbiased_gaussian_heatmaps( + heatmap_size=self.heatmap_size, + keypoints=keypoints / self.scale_factor, + keypoints_visible=keypoints_visible, + sigma=self.sigma) + + offset_maps = self.generate_offset_map( + heatmap_size=self.heatmap_size, + keypoints=keypoints / self.scale_factor, + ) + + encoded = dict( + heatmaps=heatmaps, + keypoint_weights=keypoint_weights[0], + displacements=offset_maps) + + return encoded + + def generate_offset_map(self, heatmap_size: Tuple[int, int], + keypoints: np.ndarray): + + N, K, _ = keypoints.shape + + # batchsize 1 + keypoints = keypoints[0] + + # caution: there will be a broadcast which produce + # offside_x and offside_y with shape 64x64x98 + + offset_x = keypoints[:, 0] - np.expand_dims(self.x_range, axis=-1) + offset_y = keypoints[:, 1] - np.expand_dims(self.y_range, axis=-1) + + offset_map = np.concatenate([offset_x, offset_y], axis=-1) + + offset_map = np.transpose(offset_map, axes=[2, 0, 1]) + + return offset_map + + def decode(self, encoded: np.ndarray, + offset_maps: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: + """Decode keypoint coordinates from heatmaps. The decoded keypoint + coordinates are in the input image space. + + Args: + encoded (np.ndarray): Heatmaps in shape (K, H, W) + + Returns: + tuple: + - keypoints (np.ndarray): Decoded keypoint coordinates in shape + (N, K, D) + - scores (np.ndarray): The keypoint scores in shape (N, K). It + usually represents the confidence of the keypoint prediction + """ + heatmaps = encoded.copy() + + offset_maps = offset_maps.copy() + + K, H, W = heatmaps.shape + + keypoints, scores = get_heatmap_maximum(heatmaps) + + offset_x = offset_maps[:K, ...] + offset_y = offset_maps[K:, ...] + + keypoints_interger = keypoints.astype(np.int32) + keypoints_decimal = np.zeros_like(keypoints) + + for i in range(K): + [x, y] = keypoints_interger[i] + if x < 0 or y < 0: + x = y = 0 + + # caution: torch tensor shape is nchw, so index should be i,y,x + keypoints_decimal[i][0] = x + offset_x[i, y, x] + keypoints_decimal[i][1] = y + offset_y[i, y, x] + + # Restore the keypoint scale + keypoints_decimal = keypoints_decimal * self.scale_factor + + return keypoints_decimal[None], scores[None] diff --git a/projects/skps/models/__init__.py b/projects/skps/models/__init__.py new file mode 100644 index 0000000000..55377c089c --- /dev/null +++ b/projects/skps/models/__init__.py @@ -0,0 +1,3 @@ +from .skps_head import SKPSHead + +__all__ = ['SKPSHead'] diff --git a/projects/skps/models/skps_head.py b/projects/skps/models/skps_head.py new file mode 100644 index 0000000000..73f84dc443 --- /dev/null +++ b/projects/skps/models/skps_head.py @@ -0,0 +1,399 @@ +# Copyright (c) OpenMMLab. All rights reserved. + +from typing import Optional, Sequence, Tuple, Union + +import torch +import torch.nn as nn +from mmcv.cnn import build_conv_layer +from mmengine.model import ModuleDict +from mmengine.structures import InstanceData +from torch import Tensor + +from mmpose.evaluation.functional import pose_pck_accuracy +from mmpose.models.heads.base_head import BaseHead +from mmpose.models.utils.tta import flip_coordinates +from mmpose.registry import KEYPOINT_CODECS, MODELS +from mmpose.utils.tensor_utils import to_numpy +from mmpose.utils.typing import (ConfigType, Features, InstanceList, + OptConfigType, OptSampleList, Predictions) + +OptIntSeq = Optional[Sequence[int]] + + +@MODELS.register_module() +class SKPSHead(BaseHead): + """DisEntangled Keypoint Regression head introduced in `Bottom-up human + pose estimation via disentangled keypoint regression`_ by Geng et al + (2021). The head is composed of a heatmap branch and a displacement branch. + + Args: + in_channels (int | Sequence[int]): Number of channels in the input + feature map + out_channels (int): Number of channels in the output heatmap + conv_out_channels (Sequence[int], optional): The output channel number + of each intermediate conv layer. ``None`` means no intermediate + conv layer between deconv layers and the final conv layer. + Defaults to ``None`` + conv_kernel_sizes (Sequence[int | tuple], optional): The kernel size + of each intermediate conv layer. Defaults to ``None`` + final_layer (dict): Arguments of the final Conv2d layer. + Defaults to ``dict(kernel_size=1)`` + loss (Config): Config of the keypoint loss. Defaults to use + :class:`KeypointMSELoss` + decoder (Config, optional): The decoder config that controls decoding + keypoint coordinates from the network output. Defaults to ``None`` + init_cfg (Config, optional): Config to control the initialization. See + :attr:`default_init_cfg` for default settings + + + .. _`Bottom-up human pose estimation via disentangled keypoint regression`: + https://arxiv.org/abs/2104.02300 + """ + + _version = 2 + + def __init__(self, + in_channels: Union[int, Sequence[int]], + out_channels: int, + conv_out_channels: OptIntSeq = None, + conv_kernel_sizes: OptIntSeq = None, + final_layer: dict = dict(kernel_size=1), + heatmap_loss: ConfigType = dict( + type='AdaptiveWingLoss', use_target_weight=True), + offside_loss: ConfigType = dict( + type='AdaptiveWingLoss', use_target_weight=True), + decoder: OptConfigType = None, + init_cfg: OptConfigType = None): + + if init_cfg is None: + init_cfg = self.default_init_cfg + + super().__init__(init_cfg) + + self.in_channels = in_channels + self.out_channels = out_channels + + if conv_out_channels: + if conv_kernel_sizes is None or len(conv_out_channels) != len( + conv_kernel_sizes): + raise ValueError( + '"conv_out_channels" and "conv_kernel_sizes" should ' + 'be integer sequences with the same length. Got ' + f'mismatched lengths {conv_out_channels} and ' + f'{conv_kernel_sizes}') + + self.conv_layers = self._make_conv_layers( + in_channels=in_channels, + layer_out_channels=conv_out_channels, + layer_kernel_sizes=conv_kernel_sizes) + in_channels = conv_out_channels[-1] + else: + self.conv_layers = nn.Identity() + + if final_layer is not None: + cfg = dict( + type='Conv2d', + in_channels=in_channels, + out_channels=self.out_channels * 3, + kernel_size=1, + bias=True) + cfg.update(final_layer) + self.final_layer = build_conv_layer(cfg) + else: + self.final_layer = nn.Identity() + + # build losses + self.loss_module = ModuleDict( + dict( + heatmap=MODELS.build(heatmap_loss), + offside=MODELS.build(offside_loss), + )) + + # build decoder + if decoder is not None: + self.decoder = KEYPOINT_CODECS.build(decoder) + else: + self.decoder = None + + # Register the hook to automatically convert old version state dicts + self._register_load_state_dict_pre_hook(self._load_state_dict_pre_hook) + + @property + def default_init_cfg(self): + init_cfg = [ + dict(type='Normal', layer=['Conv2d', 'ConvTranspose2d'], std=0.01), + dict(type='Constant', layer='BatchNorm2d', val=1) + ] + return init_cfg + + def _make_conv_layers(self, in_channels: int, + layer_out_channels: Sequence[int], + layer_kernel_sizes: Sequence[int]) -> nn.Module: + """Create convolutional layers by given parameters.""" + + layers = [] + for out_channels, kernel_size in zip(layer_out_channels, + layer_kernel_sizes): + padding = (kernel_size - 1) // 2 + cfg = dict( + type='Conv2d', + in_channels=in_channels, + out_channels=out_channels, + kernel_size=kernel_size, + stride=1, + padding=padding) + layers.append(build_conv_layer(cfg)) + layers.append(nn.BatchNorm2d(num_features=out_channels)) + layers.append(nn.ReLU(inplace=True)) + in_channels = out_channels + + return nn.Sequential(*layers) + + def forward(self, feats: Tuple[Tensor]) -> Tensor: + """Forward the network. The input is multi scale feature maps and the + output is a tuple of heatmap and displacement. + + Args: + feats (Tuple[Tensor]): Multi scale feature maps. + + Returns: + Tuple[Tensor]: output heatmap and displacement. + """ + x = feats[-1] + + x = self.conv_layers(x) + x = self.final_layer(x) + heatmaps = x[:, :self.out_channels, ...] + offside = x[:, self.out_channels:, ...] + return heatmaps, offside + + def loss(self, + feats: Tuple[Tensor], + batch_data_samples: OptSampleList, + train_cfg: ConfigType = {}) -> dict: + """Calculate losses from a batch of inputs and data samples. + + Args: + feats (Tuple[Tensor]): The multi-stage features + batch_data_samples (List[:obj:`PoseDataSample`]): The batch + data samples + train_cfg (dict): The runtime config for training process. + Defaults to {} + + Returns: + dict: A dictionary of losses. + """ + pred_heatmaps, pred_offside = self.forward(feats) + gt_heatmaps = torch.stack( + [d.gt_fields.heatmaps for d in batch_data_samples]) + keypoint_weights = torch.stack([ + d.gt_instance_labels.keypoint_weights for d in batch_data_samples + ]) + gt_offside = torch.stack( + [d.gt_fields.displacements for d in batch_data_samples]) + + # calculate losses + losses = dict() + heatmap_loss = self.loss_module['heatmap'](pred_heatmaps, gt_heatmaps, + keypoint_weights) + + n, c, h, w = pred_offside.size() + offside_loss_x = self.loss_module['offside'](pred_offside[:, :c // 2], + gt_offside[:, :c // 2], + gt_heatmaps) + + offside_loss_y = self.loss_module['offside'](pred_offside[:, c // 2:], + gt_offside[:, c // 2:], + gt_heatmaps) + + offside_loss = (offside_loss_x + offside_loss_y) / 2. + + losses.update({ + 'loss/heatmap': heatmap_loss, + 'loss/offside': offside_loss, + }) + # calculate accuracy + if train_cfg.get('compute_acc', True): + _, avg_acc, _ = pose_pck_accuracy( + output=to_numpy(pred_heatmaps), + target=to_numpy(gt_heatmaps), + mask=to_numpy(keypoint_weights) > 0) + + acc_pose = torch.tensor(avg_acc, device=gt_heatmaps.device) + losses.update(acc_pose=acc_pose) + + return losses + + def predict(self, + feats: Features, + batch_data_samples: OptSampleList, + test_cfg: ConfigType = {}) -> Predictions: + """Predict results from features. + + Args: + feats (Tuple[Tensor] | List[Tuple[Tensor]]): The multi-stage + features (or multiple multi-scale features in TTA) + batch_data_samples (List[:obj:`PoseDataSample`]): The batch + data samples + test_cfg (dict): The runtime config for testing process. Defaults + to {} + + Returns: + Union[InstanceList | Tuple[InstanceList | PixelDataList]]: If + ``test_cfg['output_heatmap']==True``, return both pose and heatmap + prediction; otherwise only return the pose prediction. + + The pose prediction is a list of ``InstanceData``, each contains + the following fields: + + - keypoints (np.ndarray): predicted keypoint coordinates in + shape (num_instances, K, D) where K is the keypoint number + and D is the keypoint dimension + - keypoint_scores (np.ndarray): predicted keypoint scores in + shape (num_instances, K) + """ + + flip_test = test_cfg.get('flip_test', False) + metainfo = batch_data_samples[0].metainfo + + if flip_test: + assert isinstance(feats, list) and len(feats) == 2 + flip_indices = metainfo['flip_indices'] + _feat, _feat_flip = feats + _heatmaps, _displacements = self.forward(_feat) + _heatmaps_flip, _displacements_flip = self.forward(_feat_flip) + + batch_size = _heatmaps.shape[0] + + _heatmaps = to_numpy(_heatmaps) + _displacements = to_numpy(_displacements) + + _heatmaps_flip = to_numpy(_heatmaps_flip) + _displacements_flip = to_numpy(_displacements_flip) + preds = [] + for b in range(batch_size): + _keypoints, _keypoint_scores = self.decoder.decode( + _heatmaps[b], _displacements[b]) + + _keypoints_flip, _keypoint_scores_flip = self.decoder.decode( + _heatmaps_flip[b], _displacements_flip[b]) + + # flip the kps coords + real_w = self.decoder.input_size[0] + real_h = self.decoder.input_size[1] + + # the coordinate range is 0-255 for 256x256 input size + _keypoints_flip /= (real_w - 1) + _keypoints_flip = flip_coordinates( + _keypoints_flip, + flip_indices=flip_indices, + shift_coords=False, + input_size=((real_w - 1), (real_h - 1))) + _keypoints_flip *= (real_w - 1) + + _keypoints = (_keypoints + _keypoints_flip) / 2. + # pack outputs + preds.append(InstanceData(keypoints=_keypoints)) + return preds + + else: + batch_heatmaps, batch_displacements = self.forward(feats) + + preds = self.decode(batch_heatmaps, batch_displacements, test_cfg, + metainfo) + + return preds + + def decode(self, + heatmaps: Tuple[Tensor], + offside: Tuple[Tensor], + test_cfg: ConfigType = {}, + metainfo: dict = {}) -> InstanceList: + """Decode keypoints from outputs. + + Args: + heatmaps (Tuple[Tensor]): The output heatmaps inferred from one + image or multi-scale images. + offside (Tuple[Tensor]): The output displacement fields + inferred from one image or multi-scale images. + test_cfg (dict): The runtime config for testing process. Defaults + to {} + metainfo (dict): The metainfo of test dataset. Defaults to {} + + Returns: + List[InstanceData]: A list of InstanceData, each contains the + decoded pose information of the instances of one data sample. + """ + + if self.decoder is None: + raise RuntimeError( + f'The decoder has not been set in {self.__class__.__name__}. ' + 'Please set the decoder configs in the init parameters to ' + 'enable head methods `head.predict()` and `head.decode()`') + + preds = [] + batch_size = heatmaps.shape[0] + + heatmaps = to_numpy(heatmaps) + offside = to_numpy(offside) + + for b in range(batch_size): + keypoints, keypoint_scores = self.decoder.decode( + heatmaps[b], offside[b]) + + # pack outputs + preds.append( + InstanceData( + keypoints=keypoints, keypoint_scores=keypoint_scores)) + + return preds + + def _load_state_dict_pre_hook(self, state_dict, prefix, local_meta, *args, + **kwargs): + """A hook function to convert old-version state dict of + :class:`DeepposeRegressionHead` (before MMPose v1.0.0) to a + compatible format of :class:`RegressionHead`. + + The hook will be automatically registered during initialization. + """ + version = local_meta.get('version', None) + if version and version >= self._version: + return + + # convert old-version state dict + keys = list(state_dict.keys()) + for _k in keys: + if not _k.startswith(prefix): + continue + v = state_dict.pop(_k) + k = _k[len(prefix):] + # In old version, "final_layer" includes both intermediate + # conv layers (new "conv_layers") and final conv layers (new + # "final_layer"). + # + # If there is no intermediate conv layer, old "final_layer" will + # have keys like "final_layer.xxx", which should be still + # named "final_layer.xxx"; + # + # If there are intermediate conv layers, old "final_layer" will + # have keys like "final_layer.n.xxx", where the weights of the last + # one should be renamed "final_layer.xxx", and others should be + # renamed "conv_layers.n.xxx" + k_parts = k.split('.') + if k_parts[0] == 'final_layer': + if len(k_parts) == 3: + assert isinstance(self.conv_layers, nn.Sequential) + idx = int(k_parts[1]) + if idx < len(self.conv_layers): + # final_layer.n.xxx -> conv_layers.n.xxx + k_new = 'conv_layers.' + '.'.join(k_parts[1:]) + else: + # final_layer.n.xxx -> final_layer.xxx + k_new = 'final_layer.' + k_parts[2] + else: + # final_layer.xxx remains final_layer.xxx + k_new = k + else: + k_new = k + + state_dict[prefix + k_new] = v diff --git a/projects/yolox-pose/configs/_base_/datasets b/projects/yolox-pose/configs/_base_/datasets deleted file mode 120000 index 8feca66d56..0000000000 --- a/projects/yolox-pose/configs/_base_/datasets +++ /dev/null @@ -1 +0,0 @@ -../../../../configs/_base_/datasets \ No newline at end of file diff --git a/projects/yolox-pose/demo b/projects/yolox-pose/demo deleted file mode 120000 index bf71256cd3..0000000000 --- a/projects/yolox-pose/demo +++ /dev/null @@ -1 +0,0 @@ -../../demo \ No newline at end of file diff --git a/projects/yolox-pose/tools b/projects/yolox-pose/tools deleted file mode 120000 index 31941e941d..0000000000 --- a/projects/yolox-pose/tools +++ /dev/null @@ -1 +0,0 @@ -../../tools \ No newline at end of file diff --git a/projects/yolox-pose/README.md b/projects/yolox_pose/README.md similarity index 63% rename from projects/yolox-pose/README.md rename to projects/yolox_pose/README.md index e880301ae6..264b65fe9f 100644 --- a/projects/yolox-pose/README.md +++ b/projects/yolox_pose/README.md @@ -16,7 +16,7 @@ This project implements a YOLOX-based human pose estimator, utilizing the approa - [MMYOLO](https://github.com/open-mmlab/mmyolo) v0.5.0 or higher - [MMPose](https://github.com/open-mmlab/mmpose) v1.0.0rc1 or higher -All the commands below rely on the correct configuration of `PYTHONPATH`, which should point to the project's directory so that Python can locate the module files. In `yolox-pose/` root directory, run the following line to add the current directory to `PYTHONPATH`: +All the commands below rely on the correct configuration of `PYTHONPATH`, which should point to the project's directory so that Python can locate the module files. **In `yolox-pose/` root directory**, run the following line to add the current directory to `PYTHONPATH`: ```shell export PYTHONPATH=`pwd`:$PYTHONPATH @@ -91,16 +91,27 @@ Results on COCO val2017 | Model | Input Size | AP | AP50 | AP75 | AR | AR50 | Download | | :-------------------------------------------------------------: | :--------: | :---: | :-------------: | :-------------: | :---: | :-------------: | :----------------------------------------------------------------------: | -| [YOLOX-tiny-Pose](./configs/yolox-pose_tiny_4xb64-300e_coco.py) | 640 | 0.518 | 0.799 | 0.545 | 0.566 | 0.841 | [model](https://download.openmmlab.com/mmpose/v1/projects/yolox-pose/yolox-pose_tiny_4xb64-300e_coco-c47dd83b_20230321.pth) \| [log](https://download.openmmlab.com/mmpose/v1/projects/yolox-pose/yolox-pose_tiny_4xb64-300e_coco_20230321.json) | +| [YOLOX-tiny-Pose](./configs/yolox-pose_tiny_4xb64-300e_coco.py) | 416 | 0.518 | 0.799 | 0.545 | 0.566 | 0.841 | [model](https://download.openmmlab.com/mmpose/v1/projects/yolox-pose/yolox-pose_tiny_4xb64-300e_coco-c47dd83b_20230321.pth) \| [log](https://download.openmmlab.com/mmpose/v1/projects/yolox-pose/yolox-pose_tiny_4xb64-300e_coco_20230321.json) | | [YOLOX-s-Pose](./configs/yolox-pose_s_8xb32-300e_coco.py) | 640 | 0.632 | 0.875 | 0.692 | 0.676 | 0.907 | [model](https://download.openmmlab.com/mmpose/v1/projects/yolox-pose/yolox-pose_s_8xb32-300e_coco-9f5e3924_20230321.pth) \| [log](https://download.openmmlab.com/mmpose/v1/projects/yolox-pose/yolox-pose_s_8xb32-300e_coco_20230321.json) | | [YOLOX-m-Pose](./configs/yolox-pose_m_4xb64-300e_coco.py) | 640 | 0.685 | 0.897 | 0.753 | 0.727 | 0.925 | [model](https://download.openmmlab.com/mmpose/v1/projects/yolox-pose/yolox-pose_m_4xb64-300e_coco-cbd11d30_20230321.pth) \| [log](https://download.openmmlab.com/mmpose/v1/projects/yolox-pose/yolox-pose_m_4xb64-300e_coco_20230321.json) | | [YOLOX-l-Pose](./configs/yolox-pose_l_4xb64-300e_coco.py) | 640 | 0.706 | 0.907 | 0.775 | 0.747 | 0.934 | [model](https://download.openmmlab.com/mmpose/v1/projects/yolox-pose/yolox-pose_l_4xb64-300e_coco-122e4cf8_20230321.pth) \| [log](https://download.openmmlab.com/mmpose/v1/projects/yolox-pose/yolox-pose_l_4xb64-300e_coco_20230321.json) | We have only trained models with an input size of 640, as we couldn't replicate the performance enhancement mentioned in the paper when increasing the input size from 640 to 960. We warmly welcome any contributions if you can successfully reproduce the results from the paper! +**NEW!** + +[MMYOLO](https://github.com/open-mmlab/mmyolo/blob/dev/configs/yolox/README.md#yolox-pose) also supports YOLOX-Pose and achieves better performance. Their models are fully compatible with this project. Here are their results on COCO val2017: + +| Backbone | Size | Batch Size | AMP | RTMDet-Hyp | Mem (GB) | AP | Config | Download | +| :--------: | :--: | :--------: | :-: | :--------: | :------: | :--: | :------------------------------------------------------------------------: | :---------------------------------------------------------------------------: | +| YOLOX-tiny | 416 | 8xb32 | Yes | Yes | 5.3 | 52.8 | [config](https://github.com/open-mmlab/mmyolo/blob/dev/configs/yolox/pose/yolox-pose_tiny_8xb32-300e-rtmdet-hyp_coco.py) | [model](https://download.openmmlab.com/mmyolo/v0/yolox/pose/yolox-pose_tiny_8xb32-300e-rtmdet-hyp_coco/yolox-pose_tiny_8xb32-300e-rtmdet-hyp_coco_20230427_080351-2117af67.pth) \| [log](https://download.openmmlab.com/mmyolo/v0/yolox/pose/yolox-pose_tiny_8xb32-300e-rtmdet-hyp_coco/yolox-pose_tiny_8xb32-300e-rtmdet-hyp_coco_20230427_080351.log.json) | +| YOLOX-s | 640 | 8xb32 | Yes | Yes | 10.7 | 63.7 | [config](https://github.com/open-mmlab/mmyolo/blob/dev/configs/yolox/pose/yolox-pose_s_8xb32-300e-rtmdet-hyp_coco.py) | [model](https://download.openmmlab.com/mmyolo/v0/yolox/pose/yolox-pose_s_8xb32-300e-rtmdet-hyp_coco/yolox-pose_s_8xb32-300e-rtmdet-hyp_coco_20230427_005150-e87d843a.pth) \| [log](https://download.openmmlab.com/mmyolo/v0/yolox/pose/yolox-pose_s_8xb32-300e-rtmdet-hyp_coco/yolox-pose_s_8xb32-300e-rtmdet-hyp_coco_20230427_005150.log.json) | +| YOLOX-m | 640 | 8xb32 | Yes | Yes | 19.2 | 69.3 | [config](https://github.com/open-mmlab/mmyolo/blob/dev/configs/yolox/pose/yolox-pose_m_8xb32-300e-rtmdet-hyp_coco.py) | [model](https://download.openmmlab.com/mmyolo/v0/yolox/pose/yolox-pose_m_8xb32-300e-rtmdet-hyp_coco/yolox-pose_m_8xb32-300e-rtmdet-hyp_coco_20230427_094024-bbeacc1c.pth) \| [log](https://download.openmmlab.com/mmyolo/v0/yolox/pose/yolox-pose_m_8xb32-300e-rtmdet-hyp_coco/yolox-pose_m_8xb32-300e-rtmdet-hyp_coco_20230427_094024.log.json) | +| YOLOX-l | 640 | 8xb32 | Yes | Yes | 30.3 | 71.1 | [config](https://github.com/open-mmlab/mmyolo/blob/dev/configs/yolox/pose/yolox-pose_l_8xb32-300e-rtmdet-hyp_coco.py) | [model](https://download.openmmlab.com/mmyolo/v0/yolox/pose/yolox-pose_l_8xb32-300e-rtmdet-hyp_coco/yolox-pose_l_8xb32-300e-rtmdet-hyp_coco_20230427_041140-82d65ac8.pth) \| [log](https://download.openmmlab.com/mmyolo/v0/yolox/pose/yolox-pose_l_8xb32-300e-rtmdet-hyp_coco/yolox-pose_l_8xb32-300e-rtmdet-hyp_coco_20230427_041140.log.json) | + ## Citation -If this project benefits your work, please kindly consider citing the original paper: +If this project benefits your work, please kindly consider citing the original papers: ```bibtex @inproceedings{maji2022yolo, @@ -112,6 +123,15 @@ If this project benefits your work, please kindly consider citing the original p } ``` +```bibtex +@article{yolox2021, + title={{YOLOX}: Exceeding YOLO Series in 2021}, + author={Ge, Zheng and Liu, Songtao and Wang, Feng and Li, Zeming and Sun, Jian}, + journal={arXiv preprint arXiv:2107.08430}, + year={2021} +} +``` + Additionally, please cite our work as well: ```bibtex diff --git a/projects/yolox_pose/configs/_base_/datasets b/projects/yolox_pose/configs/_base_/datasets new file mode 120000 index 0000000000..bc9c713221 --- /dev/null +++ b/projects/yolox_pose/configs/_base_/datasets @@ -0,0 +1 @@ +../../../../configs/_base_/datasets diff --git a/projects/yolox-pose/configs/_base_/default_runtime.py b/projects/yolox_pose/configs/_base_/default_runtime.py similarity index 96% rename from projects/yolox-pose/configs/_base_/default_runtime.py rename to projects/yolox_pose/configs/_base_/default_runtime.py index 1f12ce3564..7057585015 100644 --- a/projects/yolox-pose/configs/_base_/default_runtime.py +++ b/projects/yolox_pose/configs/_base_/default_runtime.py @@ -33,7 +33,7 @@ resume = False # file I/O backend -file_client_args = dict(backend='disk') +backend_args = dict(backend='local') # training/validation/testing progress train_cfg = dict() diff --git a/projects/yolox_pose/configs/_base_/py_default_runtime.py b/projects/yolox_pose/configs/_base_/py_default_runtime.py new file mode 100644 index 0000000000..354d96ad0d --- /dev/null +++ b/projects/yolox_pose/configs/_base_/py_default_runtime.py @@ -0,0 +1,45 @@ +from mmengine.hooks import (CheckpointHook, DistSamplerSeedHook, IterTimerHook, + LoggerHook, ParamSchedulerHook) +from mmengine.runner import LogProcessor, TestLoop, ValLoop +from mmengine.visualization import LocalVisBackend + +from mmpose.engine.hooks import PoseVisualizationHook +from mmpose.visualization import PoseLocalVisualizer + +default_scope = None +# hooks +default_hooks = dict( + timer=dict(type=IterTimerHook), + logger=dict(type=LoggerHook, interval=50), + param_scheduler=dict(type=ParamSchedulerHook), + checkpoint=dict(type=CheckpointHook, interval=10, max_keep_ckpts=3), + sampler_seed=dict(type=DistSamplerSeedHook), + visualization=dict(type=PoseVisualizationHook, enable=False), +) + +# multi-processing backend +env_cfg = dict( + cudnn_benchmark=False, + mp_cfg=dict(mp_start_method='fork', opencv_num_threads=0), + dist_cfg=dict(backend='nccl'), +) + +# visualizer +vis_backends = [dict(type=LocalVisBackend)] +visualizer = dict( + type=PoseLocalVisualizer, vis_backends=vis_backends, name='visualizer') + +# logger +log_processor = dict( + type=LogProcessor, window_size=50, by_epoch=True, num_digits=6) +log_level = 'INFO' +load_from = None +resume = False + +# file I/O backend +backend_args = dict(backend='local') + +# training/validation/testing progress +train_cfg = dict() +val_cfg = dict(type=ValLoop) +test_cfg = dict(type=TestLoop) diff --git a/projects/yolox_pose/configs/py_yolox_pose_s_8xb32_300e_coco.py b/projects/yolox_pose/configs/py_yolox_pose_s_8xb32_300e_coco.py new file mode 100644 index 0000000000..9a75e35e8d --- /dev/null +++ b/projects/yolox_pose/configs/py_yolox_pose_s_8xb32_300e_coco.py @@ -0,0 +1,283 @@ +from mmengine.config import read_base + +with read_base(): + from ._base_.py_default_runtime import * + +from datasets import (CocoDataset, FilterDetPoseAnnotations, PackDetPoseInputs, + PoseToDetConverter) +from mmcv.ops import nms +from mmdet.datasets.transforms import (Pad, RandomAffine, RandomFlip, Resize, + YOLOXHSVRandomAug) +from mmdet.engine.hooks import SyncNormHook +from mmdet.engine.schedulers import QuadraticWarmupLR +from mmdet.models import CrossEntropyLoss, DetDataPreprocessor, IoULoss, L1Loss +from mmdet.models.task_modules import BboxOverlaps2D +from mmengine.dataset import DefaultSampler +from mmengine.hooks import EMAHook +from mmengine.model import PretrainedInit +from mmengine.optim import ConstantLR, CosineAnnealingLR, OptimWrapper +from mmengine.runner import EpochBasedTrainLoop +from mmyolo.datasets.transforms import Mosaic, YOLOXMixUp +from mmyolo.engine.hooks import YOLOXModeSwitchHook +from mmyolo.models import (YOLOXPAFPN, ExpMomentumEMA, YOLODetector, + YOLOXCSPDarknet) +from models import (OksLoss, PoseBatchSyncRandomResize, PoseSimOTAAssigner, + YOLOXPoseHead, YOLOXPoseHeadModule) +from torch.nn import BatchNorm2d, SiLU +from torch.optim import AdamW + +from mmpose.datasets.transforms import LoadImage +from mmpose.evaluation import CocoMetric + +# model settings +model = dict( + type=YOLODetector, + use_syncbn=False, + init_cfg=dict( + type=PretrainedInit, + checkpoint='https://download.openmmlab.com/mmyolo/v0/yolox/' + 'yolox_s_fast_8xb32-300e-rtmdet-hyp_coco/yolox_s_fast_' + '8xb32-300e-rtmdet-hyp_coco_20230210_134645-3a8dfbd7.pth'), + data_preprocessor=dict( + type=DetDataPreprocessor, + pad_size_divisor=32, + batch_augments=[ + dict( + type=PoseBatchSyncRandomResize, + random_size_range=(480, 800), + size_divisor=32, + interval=1) + ]), + backbone=dict( + type=YOLOXCSPDarknet, + deepen_factor=0.33, + widen_factor=0.5, + out_indices=(2, 3, 4), + spp_kernal_sizes=(5, 9, 13), + norm_cfg=dict(type=BatchNorm2d, momentum=0.03, eps=0.001), + act_cfg=dict(type=SiLU, inplace=True), + ), + neck=dict( + type=YOLOXPAFPN, + deepen_factor=0.33, + widen_factor=0.5, + in_channels=[256, 512, 1024], + out_channels=256, + norm_cfg=dict(type=BatchNorm2d, momentum=0.03, eps=0.001), + act_cfg=dict(type=SiLU, inplace=True)), + bbox_head=dict( + type=YOLOXPoseHead, + head_module=dict( + type=YOLOXPoseHeadModule, + num_classes=1, + in_channels=256, + feat_channels=256, + widen_factor=0.5, + stacked_convs=2, + num_keypoints=17, + featmap_strides=(8, 16, 32), + use_depthwise=False, + norm_cfg=dict(type=BatchNorm2d, momentum=0.03, eps=0.001), + act_cfg=dict(type=SiLU, inplace=True), + ), + loss_cls=dict( + type=CrossEntropyLoss, + use_sigmoid=True, + reduction='sum', + loss_weight=1.0), + loss_bbox=dict( + type=IoULoss, + mode='square', + eps=1e-16, + reduction='sum', + loss_weight=5.0), + loss_obj=dict( + type=CrossEntropyLoss, + use_sigmoid=True, + reduction='sum', + loss_weight=1.0), + loss_pose=dict( + type=OksLoss, + metainfo='configs/_base_/datasets/coco.py', + loss_weight=30.0), + loss_bbox_aux=dict(type=L1Loss, reduction='sum', loss_weight=1.0)), + train_cfg=dict( + assigner=dict( + type=PoseSimOTAAssigner, + center_radius=2.5, + iou_calculator=dict(type=BboxOverlaps2D), + oks_calculator=dict( + type=OksLoss, metainfo='configs/_base_/datasets/coco.py'))), + test_cfg=dict( + yolox_style=True, + multi_label=False, + score_thr=0.001, + max_per_img=300, + nms=dict(type=nms, iou_threshold=0.65))) + +# data related +img_scale = (640, 640) + +# pipelines +pre_transform = [ + dict(type=LoadImage, backend_args=backend_args), + dict(type=PoseToDetConverter) +] + +train_pipeline_stage1 = [ + *pre_transform, + dict( + type=Mosaic, + img_scale=img_scale, + pad_val=114.0, + pre_transform=pre_transform), + dict( + type=RandomAffine, + scaling_ratio_range=(0.75, 1.0), + border=(-img_scale[0] // 2, -img_scale[1] // 2)), + dict( + type=YOLOXMixUp, + img_scale=img_scale, + ratio_range=(0.8, 1.6), + pad_val=114.0, + pre_transform=pre_transform), + dict(type=YOLOXHSVRandomAug), + dict(type=RandomFlip, prob=0.5), + dict(type=FilterDetPoseAnnotations, keep_empty=False), + dict( + type=PackDetPoseInputs, + meta_keys=('img_id', 'img_path', 'ori_shape', 'img_shape')) +] + +train_pipeline_stage2 = [ + *pre_transform, + dict(type=Resize, scale=img_scale, keep_ratio=True), + dict( + type=Pad, pad_to_square=True, pad_val=dict(img=(114.0, 114.0, 114.0))), + dict(type=YOLOXHSVRandomAug), + dict(type=RandomFlip, prob=0.5), + dict(type=FilterDetPoseAnnotations, keep_empty=False), + dict(type=PackDetPoseInputs) +] + +test_pipeline = [ + *pre_transform, + dict(type=Resize, scale=img_scale, keep_ratio=True), + dict( + type=Pad, pad_to_square=True, pad_val=dict(img=(114.0, 114.0, 114.0))), + dict( + type=PackDetPoseInputs, + meta_keys=('id', 'img_id', 'img_path', 'ori_shape', 'img_shape', + 'scale_factor', 'flip_indices')) +] + +# dataset settings +dataset_type = CocoDataset +data_mode = 'bottomup' +data_root = 'data/coco/' + +train_dataloader = dict( + batch_size=32, + num_workers=8, + persistent_workers=True, + pin_memory=True, + sampler=dict(type=DefaultSampler, shuffle=True), + dataset=dict( + type=dataset_type, + data_mode=data_mode, + data_root=data_root, + ann_file='annotations/person_keypoints_train2017.json', + data_prefix=dict(img='train2017/'), + filter_cfg=dict(filter_empty_gt=False, min_size=32), + pipeline=train_pipeline_stage1)) + +val_dataloader = dict( + batch_size=1, + num_workers=2, + persistent_workers=True, + pin_memory=True, + drop_last=False, + sampler=dict(type=DefaultSampler, shuffle=False), + dataset=dict( + type=dataset_type, + data_mode=data_mode, + data_root=data_root, + ann_file='annotations/person_keypoints_val2017.json', + data_prefix=dict(img='val2017/'), + test_mode=True, + pipeline=test_pipeline)) + +test_dataloader = val_dataloader + +# evaluators +val_evaluator = dict( + type=CocoMetric, + ann_file=data_root + 'annotations/person_keypoints_val2017.json', + score_mode='bbox') +test_evaluator = val_evaluator + +default_hooks.update( + dict(checkpoint=dict(save_best='coco/AP', rule='greater'))) + +# optimizer +base_lr = 0.004 +max_epochs = 300 +num_last_epochs = 20 +optim_wrapper = dict( + type=OptimWrapper, + optimizer=dict(type=AdamW, lr=base_lr, weight_decay=0.05), + paramwise_cfg=dict( + norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True)) + +param_scheduler = [ + dict( + # use quadratic formula to warm up 5 epochs + # and lr is updated by iteration + type=QuadraticWarmupLR, + by_epoch=True, + begin=0, + end=5, + convert_to_iter_based=True), + dict( + # use cosine lr from 5 to 285 epoch + type=CosineAnnealingLR, + eta_min=base_lr * 0.05, + begin=5, + T_max=max_epochs - num_last_epochs, + end=max_epochs - num_last_epochs, + by_epoch=True, + convert_to_iter_based=True), + dict( + # use fixed lr during last num_last_epochs epochs + type=ConstantLR, + by_epoch=True, + factor=1, + begin=max_epochs - num_last_epochs, + end=max_epochs, + ) +] + +# runtime +custom_hooks = [ + dict( + type=YOLOXModeSwitchHook, + num_last_epochs=num_last_epochs, + new_train_pipeline=train_pipeline_stage2, + priority=48), + dict(type=SyncNormHook, priority=48), + dict( + type=EMAHook, + ema_type=ExpMomentumEMA, + momentum=0.0002, + update_buffers=True, + strict_load=False, + priority=49) +] + +train_cfg = dict( + type=EpochBasedTrainLoop, + max_epochs=max_epochs, + val_interval=10, + dynamic_intervals=[(max_epochs - num_last_epochs, 1)]) + +auto_scale_lr = dict(base_batch_size=256) diff --git a/projects/yolox-pose/configs/yolox-pose_l_4xb64-300e_coco.py b/projects/yolox_pose/configs/yolox-pose_l_4xb64-300e_coco.py similarity index 100% rename from projects/yolox-pose/configs/yolox-pose_l_4xb64-300e_coco.py rename to projects/yolox_pose/configs/yolox-pose_l_4xb64-300e_coco.py diff --git a/projects/yolox-pose/configs/yolox-pose_m_4xb64-300e_coco.py b/projects/yolox_pose/configs/yolox-pose_m_4xb64-300e_coco.py similarity index 100% rename from projects/yolox-pose/configs/yolox-pose_m_4xb64-300e_coco.py rename to projects/yolox_pose/configs/yolox-pose_m_4xb64-300e_coco.py diff --git a/projects/yolox-pose/configs/yolox-pose_s_8xb32-300e_coco.py b/projects/yolox_pose/configs/yolox-pose_s_8xb32-300e_coco.py similarity index 98% rename from projects/yolox-pose/configs/yolox-pose_s_8xb32-300e_coco.py rename to projects/yolox_pose/configs/yolox-pose_s_8xb32-300e_coco.py index f0cda72544..1854e51e1d 100644 --- a/projects/yolox-pose/configs/yolox-pose_s_8xb32-300e_coco.py +++ b/projects/yolox_pose/configs/yolox-pose_s_8xb32-300e_coco.py @@ -92,7 +92,7 @@ # pipelines pre_transform = [ - dict(type='LoadImageFromFile', file_client_args=_base_.file_client_args), + dict(type='mmpose.LoadImage', backend_args=_base_.backend_args), dict(type='PoseToDetConverter') ] diff --git a/projects/yolox-pose/configs/yolox-pose_tiny_4xb64-300e_coco.py b/projects/yolox_pose/configs/yolox-pose_tiny_4xb64-300e_coco.py similarity index 100% rename from projects/yolox-pose/configs/yolox-pose_tiny_4xb64-300e_coco.py rename to projects/yolox_pose/configs/yolox-pose_tiny_4xb64-300e_coco.py diff --git a/projects/yolox-pose/datasets/__init__.py b/projects/yolox_pose/datasets/__init__.py similarity index 100% rename from projects/yolox-pose/datasets/__init__.py rename to projects/yolox_pose/datasets/__init__.py diff --git a/projects/yolox-pose/datasets/bbox_keypoint_structure.py b/projects/yolox_pose/datasets/bbox_keypoint_structure.py similarity index 100% rename from projects/yolox-pose/datasets/bbox_keypoint_structure.py rename to projects/yolox_pose/datasets/bbox_keypoint_structure.py diff --git a/projects/yolox-pose/datasets/coco_dataset.py b/projects/yolox_pose/datasets/coco_dataset.py similarity index 100% rename from projects/yolox-pose/datasets/coco_dataset.py rename to projects/yolox_pose/datasets/coco_dataset.py diff --git a/projects/yolox-pose/datasets/transforms.py b/projects/yolox_pose/datasets/transforms.py similarity index 100% rename from projects/yolox-pose/datasets/transforms.py rename to projects/yolox_pose/datasets/transforms.py diff --git a/projects/yolox_pose/demo b/projects/yolox_pose/demo new file mode 120000 index 0000000000..14e5d68e95 --- /dev/null +++ b/projects/yolox_pose/demo @@ -0,0 +1 @@ +../../demo diff --git a/projects/yolox-pose/models/__init__.py b/projects/yolox_pose/models/__init__.py similarity index 100% rename from projects/yolox-pose/models/__init__.py rename to projects/yolox_pose/models/__init__.py diff --git a/projects/yolox-pose/models/assigner.py b/projects/yolox_pose/models/assigner.py similarity index 100% rename from projects/yolox-pose/models/assigner.py rename to projects/yolox_pose/models/assigner.py diff --git a/projects/yolox-pose/models/data_preprocessor.py b/projects/yolox_pose/models/data_preprocessor.py similarity index 100% rename from projects/yolox-pose/models/data_preprocessor.py rename to projects/yolox_pose/models/data_preprocessor.py diff --git a/projects/yolox-pose/models/oks_loss.py b/projects/yolox_pose/models/oks_loss.py similarity index 100% rename from projects/yolox-pose/models/oks_loss.py rename to projects/yolox_pose/models/oks_loss.py diff --git a/projects/yolox-pose/models/utils.py b/projects/yolox_pose/models/utils.py similarity index 100% rename from projects/yolox-pose/models/utils.py rename to projects/yolox_pose/models/utils.py diff --git a/projects/yolox-pose/models/yolox_pose_head.py b/projects/yolox_pose/models/yolox_pose_head.py similarity index 100% rename from projects/yolox-pose/models/yolox_pose_head.py rename to projects/yolox_pose/models/yolox_pose_head.py diff --git a/projects/yolox_pose/tools b/projects/yolox_pose/tools new file mode 120000 index 0000000000..682f2b4528 --- /dev/null +++ b/projects/yolox_pose/tools @@ -0,0 +1 @@ +../../tools diff --git a/requirements/build.txt b/requirements/build.txt index aa617a4ec0..fb44aadd43 100644 --- a/requirements/build.txt +++ b/requirements/build.txt @@ -1,3 +1,3 @@ # These must be installed before building mmpose numpy -torch>=1.6 +torch>=1.8 diff --git a/requirements/docs.txt b/requirements/docs.txt index 29f15667c7..d278090dbb 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -5,3 +5,4 @@ myst-parser sphinx==4.5.0 sphinx_copybutton sphinx_markdown_tables +urllib3<2.0.0 diff --git a/requirements/mminstall.txt b/requirements/mminstall.txt index fb0519c072..30d8402a42 100644 --- a/requirements/mminstall.txt +++ b/requirements/mminstall.txt @@ -1,3 +1,3 @@ -mmcv>=2.0.0rc1,<2.1.0 -mmdet>=3.0.0rc6,<3.1.0 +mmcv>=2.0.0,<2.1.0 +mmdet>=3.0.0,<3.2.0 mmengine>=0.4.0,<1.0.0 diff --git a/setup.cfg b/setup.cfg index 06067ee873..e3a37d1b6d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -19,3 +19,8 @@ known_first_party = mmpose known_third_party = PIL,cv2,h5py,json_tricks,matplotlib,mmcv,munkres,numpy,pytest,pytorch_sphinx_theme,requests,scipy,seaborn,spacepy,titlecase,torch,torchvision,webcam_apis,xmltodict,xtcocotools no_lines_before = STDLIB,LOCALFOLDER default_section = THIRDPARTY + +[flake8] +per-file-ignores = + mmpose/configs/*: F401,F403,F405 + projects/*/configs/*: F401,F403,F405 diff --git a/setup.py b/setup.py index 7222188e2f..8b3265fb70 100644 --- a/setup.py +++ b/setup.py @@ -6,6 +6,12 @@ import warnings from setuptools import find_packages, setup +try: + import google.colab # noqa + ON_COLAB = True +except ImportError: + ON_COLAB = False + def readme(): with open('README.md', encoding='utf-8') as f: @@ -78,6 +84,16 @@ def parse_line(line): else: version = rest # NOQA info['version'] = (op, version) + + if ON_COLAB and info['package'] == 'xtcocotools': + # Due to an incompatibility between the Colab platform and the + # pre-built xtcocotools PyPI package, it is necessary to + # compile xtcocotools from source on Colab. + info = dict( + line=info['line'], + package='xtcocotools@' + 'git+https://github.com/jin-s13/xtcocoapi') + yield info def parse_require_file(fpath): @@ -128,7 +144,9 @@ def add_mim_extension(): else: return - filenames = ['tools', 'configs', 'demo', 'model-index.yml'] + filenames = [ + 'tools', 'configs', 'demo', 'model-index.yml', 'dataset-index.yml' + ] repo_path = osp.dirname(__file__) mim_path = osp.join(repo_path, 'mmpose', '.mim') os.makedirs(mim_path, exist_ok=True) diff --git a/tests/data/ak/AAOYRUDX/AAOYRUDX_f000027.jpg b/tests/data/ak/AAOYRUDX/AAOYRUDX_f000027.jpg new file mode 100644 index 0000000000..0698935984 Binary files /dev/null and b/tests/data/ak/AAOYRUDX/AAOYRUDX_f000027.jpg differ diff --git a/tests/data/ak/AAOYRUDX/AAOYRUDX_f000028.jpg b/tests/data/ak/AAOYRUDX/AAOYRUDX_f000028.jpg new file mode 100644 index 0000000000..a560fe797a Binary files /dev/null and b/tests/data/ak/AAOYRUDX/AAOYRUDX_f000028.jpg differ diff --git a/tests/data/ak/test_animalkingdom.json b/tests/data/ak/test_animalkingdom.json new file mode 100644 index 0000000000..02aaf9f57a --- /dev/null +++ b/tests/data/ak/test_animalkingdom.json @@ -0,0 +1,589 @@ +{ + "info": { + "description": "[CVPR 2022] Animal Kingdom", + "url": "https://sutdcv.github.io/Animal-Kingdom", + "version": "1.0 (2022-06)", + "year": 2022, + "contributor": "Singapore University of Technology and Design, Singapore. Xun Long Ng, Kian Eng Ong, Qichen Zheng, Yun Ni, Si Yong Yeo, Jun Liu.", + "date_created": "2022-06" + }, + "licenses": [ + { + "url": "", + "id": 1, + "name": "" + } + ], + "images": [ + { + "id": 1, + "file_name": "AAOYRUDX/AAOYRUDX_f000027.jpg", + "width": 640, + "height": 360 + }, + { + "id": 2, + "file_name": "AAOYRUDX/AAOYRUDX_f000028.jpg", + "width": 640, + "height": 360 + } + ], + "categories": [ + { + "supercategory": "AK_Animal", + "id": 1, + "name": "Amphibian", + "keypoints": [ + "Head_Mid_Top", + "Eye_Left", + "Eye_Right", + "Mouth_Front_Top", + "Mouth_Back_Left", + "Mouth_Back_Right", + "Mouth_Front_Bottom", + "Shoulder_Left", + "Shoulder_Right", + "Elbow_Left", + "Elbow_Right", + "Wrist_Left", + "Wrist_Right", + "Torso_Mid_Back", + "Hip_Left", + "Hip_Right", + "Knee_Left", + "Knee_Right", + "Ankle_Left ", + "Ankle_Right", + "Tail_Top_Back", + "Tail_Mid_Back", + "Tail_End_Back" + ], + "skeleton": [ + [ + 1, + 0 + ], + [ + 2, + 0 + ], + [ + 3, + 4 + ], + [ + 3, + 5 + ], + [ + 4, + 6 + ], + [ + 5, + 6 + ], + [ + 0, + 7 + ], + [ + 0, + 8 + ], + [ + 7, + 9 + ], + [ + 8, + 10 + ], + [ + 9, + 11 + ], + [ + 10, + 12 + ], + [ + 0, + 13 + ], + [ + 13, + 20 + ], + [ + 20, + 14 + ], + [ + 20, + 15 + ], + [ + 14, + 16 + ], + [ + 15, + 17 + ], + [ + 16, + 18 + ], + [ + 17, + 19 + ], + [ + 20, + 21 + ], + [ + 21, + 22 + ] + ], + "flip_pairs": [ + [ + 1, + 2 + ], + [ + 4, + 5 + ], + [ + 7, + 8 + ], + [ + 9, + 10 + ], + [ + 11, + 12 + ], + [ + 14, + 15 + ], + [ + 16, + 17 + ], + [ + 18, + 19 + ] + ], + "upper_body_ids": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13 + ], + "lower_body_ids": [ + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22 + ] + }, + { + "supercategory": "AK_Animal", + "id": 2, + "name": "Bird", + "keypoints": [ + "Head_Mid_Top", + "Eye_Left", + "Eye_Right", + "Mouth_Front_Top", + "Mouth_Back_Left", + "Mouth_Back_Right", + "Mouth_Front_Bottom", + "Shoulder_Left", + "Shoulder_Right", + "Elbow_Left", + "Elbow_Right", + "Wrist_Left", + "Wrist_Right", + "Torso_Mid_Back", + "Hip_Left", + "Hip_Right", + "Knee_Left", + "Knee_Right", + "Ankle_Left ", + "Ankle_Right", + "Tail_Top_Back", + "Tail_Mid_Back", + "Tail_End_Back" + ], + "skeleton": [ + [ + 1, + 0 + ], + [ + 2, + 0 + ], + [ + 3, + 4 + ], + [ + 3, + 5 + ], + [ + 4, + 6 + ], + [ + 5, + 6 + ], + [ + 0, + 7 + ], + [ + 0, + 8 + ], + [ + 7, + 9 + ], + [ + 8, + 10 + ], + [ + 9, + 11 + ], + [ + 10, + 12 + ], + [ + 0, + 13 + ], + [ + 13, + 20 + ], + [ + 20, + 14 + ], + [ + 20, + 15 + ], + [ + 14, + 16 + ], + [ + 15, + 17 + ], + [ + 16, + 18 + ], + [ + 17, + 19 + ], + [ + 20, + 21 + ], + [ + 21, + 22 + ] + ], + "flip_pairs": [ + [ + 1, + 2 + ], + [ + 4, + 5 + ], + [ + 7, + 8 + ], + [ + 9, + 10 + ], + [ + 11, + 12 + ], + [ + 14, + 15 + ], + [ + 16, + 17 + ], + [ + 18, + 19 + ] + ], + "upper_body_ids": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13 + ], + "lower_body_ids": [ + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22 + ] + } + ], + "annotations": [ + { + "id": 1, + "image_id": 1, + "category_id": 4, + "animal_parent_class": "Mammal", + "animal_class": "Mammal", + "animal_subclass": "Elephant", + "animal": "Elephant", + "protocol": "ak_P1", + "train_test": "test", + "area": 7984.8320733706605, + "scale": 0.6674772036000001, + "center": [ + 229.7435897436, + 202.4316109422 + ], + "bbox": [ + 199.6111111111, + 136.1838905775, + 60.26495726500002, + 132.4954407295 + ], + "iscrowd": 0, + "num_keypoints": 6, + "keypoints": [ + 220.9914529915, + 135.6838905775, + 1.0, + 238.4957264957, + 151.0030395137, + 1.0, + 199.1111111111, + 153.1914893617, + 1.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + 260.3760683761, + 154.2857142857, + 1.0, + -1.0, + -1.0, + 0.0, + 250.5299145299, + 195.8662613982, + 1.0, + -1.0, + -1.0, + 0.0, + 251.6239316239, + 269.179331307, + 1.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0 + ] + }, + { + "id": 2, + "image_id": 2, + "category_id": 4, + "animal_parent_class": "Mammal", + "animal_class": "Mammal", + "animal_subclass": "Elephant", + "animal": "Elephant", + "protocol": "ak_P1", + "train_test": "test", + "area": 7984.8320733706605, + "scale": 0.6674772036000001, + "center": [ + 229.7435897436, + 202.4316109422 + ], + "bbox": [ + 199.6111111111, + 136.1838905775, + 60.26495726500002, + 132.4954407295 + ], + "iscrowd": 0, + "num_keypoints": 6, + "keypoints": [ + 220.9914529915, + 135.6838905775, + 1.0, + 238.4957264957, + 151.0030395137, + 1.0, + 199.1111111111, + 153.1914893617, + 1.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + 260.3760683761, + 154.2857142857, + 1.0, + -1.0, + -1.0, + 0.0, + 250.5299145299, + 195.8662613982, + 1.0, + -1.0, + -1.0, + 0.0, + 251.6239316239, + 269.179331307, + 1.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0, + -1.0, + -1.0, + 0.0 + ] + } + ] +} \ No newline at end of file diff --git a/tests/data/deepfasion2/000264.jpg b/tests/data/deepfasion2/000264.jpg new file mode 100644 index 0000000000..2bf7429024 Binary files /dev/null and b/tests/data/deepfasion2/000264.jpg differ diff --git a/tests/data/deepfasion2/000265.jpg b/tests/data/deepfasion2/000265.jpg new file mode 100644 index 0000000000..add65b956d Binary files /dev/null and b/tests/data/deepfasion2/000265.jpg differ diff --git a/tests/data/deepfasion2/deepfasion2.json b/tests/data/deepfasion2/deepfasion2.json new file mode 100644 index 0000000000..b3a25a6dca --- /dev/null +++ b/tests/data/deepfasion2/deepfasion2.json @@ -0,0 +1,2404 @@ +{ + "info": "", + "licenses": "", + "images": [ + { + "coco_url": "", + "date_captured": "", + "file_name": "000264.jpg", + "flickr_url": "", + "id": 264, + "license": 0, + "width": 750, + "height": 750 + }, + { + "coco_url": "", + "date_captured": "", + "file_name": "000265.jpg", + "flickr_url": "", + "id": 265, + "license": 0, + "width": 750, + "height": 750 + } + ], + "annotations": [ + { + "area": 402069, + "bbox": [ + 103, + 80, + 601, + 669 + ], + "category_id": 11, + "id": 429, + "pair_id": 22, + "image_id": 264, + "iscrowd": 0, + "style": 1, + "num_keypoints": 28, + "keypoints": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 417.0, + 107.0, + 1.0, + 307.0, + 87.0, + 2.0, + 349.0, + 118.0, + 2.0, + 405.0, + 131.0, + 2.0, + 461.0, + 133.0, + 2.0, + 504.0, + 116.0, + 2.0, + 242.0, + 112.0, + 2.0, + 209.0, + 208.0, + 2.0, + 182.0, + 284.0, + 2.0, + 142.0, + 331.0, + 2.0, + 121.0, + 376.0, + 2.0, + 274.0, + 440.0, + 2.0, + 277.0, + 388.0, + 2.0, + 259.0, + 345.0, + 2.0, + 263.0, + 282.0, + 1.0, + 266.0, + 222.0, + 1.0, + 258.0, + 246.0, + 2.0, + 259.0, + 318.0, + 2.0, + 249.0, + 412.0, + 1.0, + 202.0, + 579.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 566.0, + 593.0, + 2.0, + 532.0, + 435.0, + 2.0, + 527.0, + 355.0, + 2.0, + 540.0, + 289.0, + 2.0, + 542.0, + 271.0, + 2.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 573.0, + 479.0, + 2.0, + 698.0, + 403.0, + 2.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 594.0, + 151.0, + 2.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "segmentation": [ + [ + 345.05, + 120.04, + 321.68, + 101.99, + 308.4, + 87.04, + 295.88, + 91.41, + 267.98, + 97.61, + 250.24, + 109.15, + 234.6, + 130.26, + 224.23, + 161.09, + 212.72, + 198.51, + 193.23, + 252.37, + 183.68, + 279.52, + 164.61, + 297.25, + 133.78, + 341.78, + 118.78, + 373.07, + 120.42, + 381.12, + 142.25, + 390.36, + 147.3, + 396.65, + 166.82, + 412.43, + 186.56, + 425.17, + 206.63, + 432.42, + 206.48, + 422.24, + 272.85, + 442.95, + 230.31, + 484.86, + 202.28, + 579.98, + 198.77, + 649.55, + 195.22, + 697.46, + 196.55, + 740.97, + 208.78, + 750.0, + 310.72, + 749.0, + 439.41, + 749.2, + 562.85, + 749.18, + 578.32, + 739.97, + 574.34, + 685.58, + 562.73, + 564.57, + 545.52, + 474.66, + 536.85, + 436.58, + 546.89, + 450.73, + 559.79, + 470.3, + 564.49, + 478.28, + 571.67, + 479.65, + 579.75, + 484.9, + 611.0, + 467.77, + 640.13, + 458.35, + 635.77, + 445.53, + 671.39, + 430.58, + 697.71, + 414.0, + 697.93, + 397.2, + 691.25, + 349.8, + 680.6, + 307.09, + 664.02, + 293.31, + 645.57, + 286.35, + 619.11, + 282.39, + 620.03, + 237.9, + 611.34, + 191.23, + 602.52, + 164.16, + 590.09, + 149.08, + 553.5, + 136.68, + 523.0, + 129.71, + 512.15, + 122.14, + 502.99, + 116.17, + 473.33, + 129.07, + 412.19, + 129.14, + 403.58, + 124.73, + 386.42, + 126.75 + ] + ] + }, + { + "area": 288806, + "bbox": [ + 178, + 62, + 421, + 686 + ], + "category_id": 11, + "id": 430, + "pair_id": 22, + "image_id": 265, + "iscrowd": 0, + "style": 2, + "num_keypoints": 31, + "keypoints": [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 361.0, + 71.0, + 1.0, + 282.0, + 74.0, + 2.0, + 316.0, + 90.0, + 2.0, + 361.0, + 96.0, + 2.0, + 406.0, + 98.0, + 2.0, + 438.0, + 77.0, + 2.0, + 231.0, + 100.0, + 2.0, + 210.0, + 184.0, + 2.0, + 200.0, + 252.0, + 2.0, + 186.0, + 297.0, + 2.0, + 178.0, + 331.0, + 2.0, + 264.0, + 361.0, + 1.0, + 275.0, + 311.0, + 1.0, + 272.0, + 269.0, + 1.0, + 268.0, + 228.0, + 1.0, + 263.0, + 188.0, + 1.0, + 247.0, + 209.0, + 2.0, + 258.0, + 265.0, + 2.0, + 273.0, + 320.0, + 2.0, + 256.0, + 517.0, + 1.0, + 273.0, + 710.0, + 2.0, + 384.0, + 731.0, + 2.0, + 506.0, + 713.0, + 2.0, + 496.0, + 510.0, + 2.0, + 453.0, + 318.0, + 2.0, + 471.0, + 268.0, + 2.0, + 477.0, + 213.0, + 2.0, + 456.0, + 181.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 508.0, + 342.0, + 2.0, + 596.0, + 267.0, + 2.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 489.0, + 75.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ], + "segmentation": [ + [ + 438, + 77, + 406, + 98, + 361, + 96, + 316, + 90, + 282, + 74, + 231, + 100, + 210, + 184, + 200, + 252, + 186, + 297, + 178, + 331, + 264, + 361, + 275, + 311, + 272, + 269, + 268, + 228, + 263, + 188, + 247, + 209, + 258, + 265, + 273, + 320, + 256, + 517, + 273, + 710, + 384, + 731, + 506, + 713, + 496, + 510, + 453, + 318, + 471, + 268, + 477, + 213, + 456, + 181, + 508, + 342, + 596, + 267, + 489, + 75, + 438, + 77 + ], + [ + 231, + 100, + 210, + 184, + 200, + 252, + 186, + 297, + 178, + 331, + 264, + 361, + 275, + 311, + 272, + 269, + 268, + 228, + 263, + 188, + 231, + 100 + ], + [ + 456, + 181, + 508, + 342, + 596, + 267, + 489, + 75, + 456, + 181 + ], + [ + 200, + 252, + 186, + 297, + 178, + 331, + 264, + 361, + 275, + 311, + 272, + 269, + 200, + 252 + ] + ], + "images": [ + { + "coco_url": "", + "date_captured": "", + "file_name": "000264.jpg", + "flickr_url": "", + "id": 264, + "license": 0, + "width": 750, + "height": 750 + }, + { + "coco_url": "", + "date_captured": "", + "file_name": "000265.jpg", + "flickr_url": "", + "id": 265, + "license": 0, + "width": 750, + "height": 750 + } + ] + } + ], + "categories": [ + { + "id": 11, + "name": "long_sleeved_dress", + "supercategory": "clothes", + "keypoints": [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "30", + "31", + "32", + "33", + "34", + "35", + "36", + "37", + "38", + "39", + "40", + "41", + "42", + "43", + "44", + "45", + "46", + "47", + "48", + "49", + "50", + "51", + "52", + "53", + "54", + "55", + "56", + "57", + "58", + "59", + "60", + "61", + "62", + "63", + "64", + "65", + "66", + "67", + "68", + "69", + "70", + "71", + "72", + "73", + "74", + "75", + "76", + "77", + "78", + "79", + "80", + "81", + "82", + "83", + "84", + "85", + "86", + "87", + "88", + "89", + "90", + "91", + "92", + "93", + "94", + "95", + "96", + "97", + "98", + "99", + "100", + "101", + "102", + "103", + "104", + "105", + "106", + "107", + "108", + "109", + "110", + "111", + "112", + "113", + "114", + "115", + "116", + "117", + "118", + "119", + "120", + "121", + "122", + "123", + "124", + "125", + "126", + "127", + "128", + "129", + "130", + "131", + "132", + "133", + "134", + "135", + "136", + "137", + "138", + "139", + "140", + "141", + "142", + "143", + "144", + "145", + "146", + "147", + "148", + "149", + "150", + "151", + "152", + "153", + "154", + "155", + "156", + "157", + "158", + "159", + "160", + "161", + "162", + "163", + "164", + "165", + "166", + "167", + "168", + "169", + "170", + "171", + "172", + "173", + "174", + "175", + "176", + "177", + "178", + "179", + "180", + "181", + "182", + "183", + "184", + "185", + "186", + "187", + "188", + "189", + "190", + "191", + "192", + "193", + "194", + "195", + "196", + "197", + "198", + "199", + "200", + "201", + "202", + "203", + "204", + "205", + "206", + "207", + "208", + "209", + "210", + "211", + "212", + "213", + "214", + "215", + "216", + "217", + "218", + "219", + "220", + "221", + "222", + "223", + "224", + "225", + "226", + "227", + "228", + "229", + "230", + "231", + "232", + "233", + "234", + "235", + "236", + "237", + "238", + "239", + "240", + "241", + "242", + "243", + "244", + "245", + "246", + "247", + "248", + "249", + "250", + "251", + "252", + "253", + "254", + "255", + "256", + "257", + "258", + "259", + "260", + "261", + "262", + "263", + "264", + "265", + "266", + "267", + "268", + "269", + "270", + "271", + "272", + "273", + "274", + "275", + "276", + "277", + "278", + "279", + "280", + "281", + "282", + "283", + "284", + "285", + "286", + "287", + "288", + "289", + "290", + "291", + "292", + "293", + "294" + ], + "skeleton": [] + } + ] +} \ No newline at end of file diff --git a/tests/data/h36m/S1_Directions_1.54138969_000001.jpg b/tests/data/h36m/S1/S1_Directions_1.54138969/S1_Directions_1.54138969_000001.jpg similarity index 100% rename from tests/data/h36m/S1_Directions_1.54138969_000001.jpg rename to tests/data/h36m/S1/S1_Directions_1.54138969/S1_Directions_1.54138969_000001.jpg diff --git a/tests/data/h36m/S5_SittingDown.54138969_002061.jpg b/tests/data/h36m/S5/S5_SittingDown.54138969/S5_SittingDown.54138969_002061.jpg similarity index 100% rename from tests/data/h36m/S5_SittingDown.54138969_002061.jpg rename to tests/data/h36m/S5/S5_SittingDown.54138969/S5_SittingDown.54138969_002061.jpg diff --git a/tests/data/h36m/S7_Greeting.55011271_000396.jpg b/tests/data/h36m/S7/S7_Greeting.55011271/S7_Greeting.55011271_000396.jpg similarity index 100% rename from tests/data/h36m/S7_Greeting.55011271_000396.jpg rename to tests/data/h36m/S7/S7_Greeting.55011271/S7_Greeting.55011271_000396.jpg diff --git a/tests/data/h36m/S8_WalkDog_1.55011271_000026.jpg b/tests/data/h36m/S8/S8_WalkDog_1.55011271/S8_WalkDog_1.55011271_000026.jpg similarity index 100% rename from tests/data/h36m/S8_WalkDog_1.55011271_000026.jpg rename to tests/data/h36m/S8/S8_WalkDog_1.55011271/S8_WalkDog_1.55011271_000026.jpg diff --git a/tests/data/humanart/2D_virtual_human/digital_art/000000001648.jpg b/tests/data/humanart/2D_virtual_human/digital_art/000000001648.jpg new file mode 100644 index 0000000000..8f2202760b Binary files /dev/null and b/tests/data/humanart/2D_virtual_human/digital_art/000000001648.jpg differ diff --git a/tests/data/humanart/3D_virtual_human/garage_kits/000000005603.jpg b/tests/data/humanart/3D_virtual_human/garage_kits/000000005603.jpg new file mode 100644 index 0000000000..21f551c324 Binary files /dev/null and b/tests/data/humanart/3D_virtual_human/garage_kits/000000005603.jpg differ diff --git a/tests/data/humanart/real_human/acrobatics/000000000590.jpg b/tests/data/humanart/real_human/acrobatics/000000000590.jpg new file mode 100644 index 0000000000..15efbec533 Binary files /dev/null and b/tests/data/humanart/real_human/acrobatics/000000000590.jpg differ diff --git a/tests/data/humanart/test_humanart.json b/tests/data/humanart/test_humanart.json new file mode 100644 index 0000000000..8cf13e3530 --- /dev/null +++ b/tests/data/humanart/test_humanart.json @@ -0,0 +1,716 @@ +{ + "info": { + "description": "For testing Human-Art dataset only.", + "year": 2023, + "date_created": "2023/06/12" + }, + "images": [ + { + "file_name": "HumanArt/images/2D_virtual_human/digital_art/000000001648.jpg", + "height": 1750, + "width": 1280, + "id": 2000000001648, + "page_url": "https://www.deviantart.com/endemilk/art/Autumn-Mood-857953165", + "image_url": "https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/cef0f0b2-832e-4f53-95c6-32f822f796ac/de6swwd-8ae0bba7-f879-43db-9f34-33d067ea3683.png/v1/fill/w_1280,h_1750,q_80,strp/autumn_mood_by_endemilk_de6swwd-fullview.jpg?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7ImhlaWdodCI6Ijw9MTc1MCIsInBhdGgiOiJcL2ZcL2NlZjBmMGIyLTgzMmUtNGY1My05NWM2LTMyZjgyMmY3OTZhY1wvZGU2c3d3ZC04YWUwYmJhNy1mODc5LTQzZGItOWYzNC0zM2QwNjdlYTM2ODMucG5nIiwid2lkdGgiOiI8PTEyODAifV1dLCJhdWQiOlsidXJuOnNlcnZpY2U6aW1hZ2Uub3BlcmF0aW9ucyJdfQ.u2McWPeJ1MDJokGkVa3qnJlYJFoldamHt9B6rGtSf9Y", + "picture_name": "Autumn Mood", + "author": "Endemilk", + "description": "digital_art, a girl in a white dress standing under a tree with autumn leaves", + "category": "digital art" + }, + { + "file_name": "HumanArt/images/3D_virtual_human/garage_kits/000000005603.jpg", + "height": 600, + "width": 700, + "id": 12000000005603, + "page_url": "https://www.goodsmile.info/ja/product/6010/%E3%81%AD%E3%82%93%E3%81%A9%E3%82%8D%E3%81%84%E3%81%A9+%E3%82%A8%E3%83%83%E3%82%AF%E3%82%B9+%E3%83%95%E3%83%AB%E3%82%A2%E3%83%BC%E3%83%9E%E3%83%BC.html", + "image_url": "https://images.goodsmile.info/cgm/images/product/20161014/6010/41809/large/7b2d02a6a8a8d89af3a34f70942fdcc7.jpg", + "picture_name": "Irregular hunter who wants peace", + "author": "None", + "description": "garage_kits, a figurine of a character holding a gun", + "category": "garage kits" + }, + { + "file_name": "HumanArt/images/real_human/acrobatics/000000000590.jpg", + "height": 612, + "width": 589, + "id": 15000000000590, + "page_url": "https://www.istockphoto.com/hk/search/2/image?phrase=acrobatics&page=", + "image_url": "https://media.istockphoto.com/photos/women-couple-of-dancers-acrobats-picture-id494524123?k=20&m=494524123&s=612x612&w=0&h=Mt-1N5a2aCS3n6spX_Fw8JRmf3zAO2VnvB4T0mGCN4s=", + "picture_name": "None", + "author": "None", + "description": "acrobatics, two women in green and white performing acrobatics", + "category": "acrobatics" + } + ], + "annotations": [ + { + "keypoints": [ + 715.4305, + 970.0197, + 2, + 698.8416, + 942.6802, + 2, + 679.6984, + 941.7231, + 2, + 644.7338, + 948.259, + 2, + 611.9386, + 946.367, + 2, + 518.0118, + 1122.8295, + 2, + 656.3654, + 1106.6009, + 2, + 529.2618, + 1364.4753, + 2, + 589.2787, + 1375.8299, + 2, + 687.9009, + 1377.9864, + 2, + 744.6238, + 1409.0027, + 2, + 557.0198, + 1505.5454, + 2, + 680.6947, + 1499.8197, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "keypoints_21": [ + 715.4305, + 970.0197, + 2, + 698.8416, + 942.6802, + 2, + 679.6984, + 941.7231, + 2, + 644.7338, + 948.259, + 2, + 611.9386, + 946.367, + 2, + 518.0118, + 1122.8295, + 2, + 656.3654, + 1106.6009, + 2, + 529.2618, + 1364.4753, + 2, + 589.2787, + 1375.8299, + 2, + 687.9009, + 1377.9864, + 2, + 744.6238, + 1409.0027, + 2, + 557.0198, + 1505.5454, + 2, + 680.6947, + 1499.8197, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 711.6695, + 1391.3213, + 2, + 764.9766, + 1420.8272, + 2, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "self_contact": [], + "num_keypoints": 13, + "num_keypoints_21": 15, + "iscrowd": 0, + "image_id": 2000000001648, + "area": 288736.90076053096, + "bbox": [ + 468.61884, + 828.9586400000001, + 355.629312, + 811.9041119999999 + ], + "category_id": 1, + "id": 2000000006746, + "annotator": 67037 + }, + { + "keypoints": [ + 313.972, + 252.666, + 2, + 333.8015, + 228.7117, + 2, + 272.5658, + 207.7711, + 2, + 342.3681, + 227.4426, + 2, + 200.6833, + 204.2117, + 2, + 0, + 0, + 0, + 251.3643, + 302.7895, + 2, + 0, + 0, + 0, + 275.9871, + 312.5822, + 2, + 0, + 0, + 0, + 292.1347, + 313.8643, + 2, + 304.7952, + 403.3614, + 2, + 286.269, + 402.473, + 2, + 330.7358, + 441.4618, + 2, + 260.2096, + 441.0565, + 2, + 321.9826, + 495.339, + 2, + 222.4324, + 493.9369, + 2 + ], + "keypoints_21": [ + 313.972, + 252.666, + 2, + 333.8015, + 228.7117, + 2, + 272.5658, + 207.7711, + 2, + 342.3681, + 227.4426, + 2, + 200.6833, + 204.2117, + 2, + 0, + 0, + 0, + 251.3643, + 302.7895, + 2, + 0, + 0, + 0, + 275.9871, + 312.5822, + 2, + 0, + 0, + 0, + 292.1347, + 313.8643, + 2, + 304.7952, + 403.3614, + 2, + 286.269, + 402.473, + 2, + 330.7358, + 441.4618, + 2, + 260.2096, + 441.0565, + 2, + 321.9826, + 495.339, + 2, + 222.4324, + 493.9369, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 398.5162, + 556.9002, + 2, + 212.5182, + 563.4001, + 2 + ], + "self_contact": [], + "num_keypoints": 14, + "num_keypoints_21": 16, + "iscrowd": 0, + "image_id": 12000000005603, + "area": 132932.1180077885, + "bbox": [ + 161.11672, + 132.37402000000003, + 284.87937600000004, + 466.62597999999997 + ], + "category_id": 1, + "id": 12000000076660, + "annotator": 66991 + }, + { + "keypoints": [ + 319.2161, + 546.3765, + 2, + 317.6563, + 536.4973, + 2, + 315.5024, + 536.8374, + 2, + 295.7777, + 539.4827, + 2, + 290.2372, + 538.9287, + 2, + 260.5583, + 539.1473, + 2, + 252.989, + 559.7042, + 2, + 222.0985, + 494.5581, + 2, + 204.3461, + 496.7641, + 2, + 229.7767, + 555.3691, + 2, + 203.9402, + 564.1676, + 2, + 254.6329, + 440.3163, + 2, + 252.7878, + 421.1483, + 2, + 351.9561, + 400.9315, + 2, + 368.0247, + 412.8534, + 2, + 347.6211, + 500.3006, + 2, + 367.0544, + 542.1705, + 2 + ], + "keypoints_21": [ + 319.2161, + 546.3765, + 2, + 317.6563, + 536.4973, + 2, + 315.5024, + 536.8374, + 2, + 295.7777, + 539.4827, + 2, + 290.2372, + 538.9287, + 2, + 260.5583, + 539.1473, + 2, + 252.989, + 559.7042, + 2, + 222.0985, + 494.5581, + 2, + 204.3461, + 496.7641, + 2, + 229.7767, + 555.3691, + 2, + 203.9402, + 564.1676, + 2, + 254.6329, + 440.3163, + 2, + 252.7878, + 421.1483, + 2, + 351.9561, + 400.9315, + 2, + 368.0247, + 412.8534, + 2, + 347.6211, + 500.3006, + 2, + 367.0544, + 542.1705, + 2, + 248.5114, + 559.976, + 2, + 253.5939, + 575.1541, + 2, + 357.1097, + 548.0375, + 2, + 379.7624, + 573.8666, + 2 + ], + "self_contact": [ + [ + 245.1376, + 570.4875 + ] + ], + "num_keypoints": 17, + "num_keypoints_21": 21, + "iscrowd": 0, + "image_id": 15000000000590, + "area": 62008.05021846336, + "bbox": [ + 168.77576, + 366.08698000000004, + 253.18396800000005, + 244.91301999999996 + ], + "category_id": 1, + "id": 15000000092347, + "annotator": 66705 + }, + { + "keypoints": [ + 233.1389, + 406.6037, + 2, + 243.5176, + 397.9166, + 2, + 243.0948, + 396.1787, + 2, + 235.8086, + 380.0257, + 2, + 233.4394, + 371.1951, + 2, + 200.7799, + 367.2566, + 2, + 222.3385, + 339.9251, + 2, + 218.5684, + 431.6162, + 2, + 216.3631, + 433.129, + 2, + 238.3363, + 495.4999, + 2, + 240.2118, + 500.6888, + 2, + 253.2291, + 222.9011, + 2, + 270.424, + 250.1, + 2, + 192.7242, + 138.9058, + 2, + 372.9364, + 324.4092, + 2, + 148.4319, + 79.9982, + 2, + 444.6949, + 407.9868, + 2 + ], + "keypoints_21": [ + 233.1389, + 406.6037, + 2, + 243.5176, + 397.9166, + 2, + 243.0948, + 396.1787, + 2, + 235.8086, + 380.0257, + 2, + 233.4394, + 371.1951, + 2, + 200.7799, + 367.2566, + 2, + 222.3385, + 339.9251, + 2, + 218.5684, + 431.6162, + 2, + 216.3631, + 433.129, + 2, + 238.3363, + 495.4999, + 2, + 240.2118, + 500.6888, + 2, + 253.2291, + 222.9011, + 2, + 270.424, + 250.1, + 2, + 192.7242, + 138.9058, + 2, + 372.9364, + 324.4092, + 2, + 148.4319, + 79.9982, + 2, + 444.6949, + 407.9868, + 2, + 245.196, + 517.5082, + 2, + 238.3205, + 541.3807, + 2, + 113.9739, + 40.4267, + 2, + 501.7295, + 448.3217, + 2 + ], + "self_contact": [], + "num_keypoints": 17, + "num_keypoints_21": 21, + "iscrowd": 0, + "image_id": 15000000000590, + "area": 337013.68142, + "bbox": [ + 36.42278, + 0, + 551.57722, + 611 + ], + "category_id": 1, + "id": 15000000092348, + "annotator": 66705 + } + ], + "categories": [ + { + "supercategory": "person", + "id": 1, + "name": "person", + "keypoints": [ + "nose", + "left_eye", + "right_eye", + "left_ear", + "right_ear", + "left_shoulder", + "right_shoulder", + "left_elbow", + "right_elbow", + "left_wrist", + "right_wrist", + "left_hip", + "right_hip", + "left_knee", + "right_knee", + "left_ankle", + "right_ankle", + "left_finger", + "right_finger", + "left_toe", + "right_toe" + ], + "skeleton": [ + [ + 20, + 16 + ], + [ + 16, + 14 + ], + [ + 14, + 12 + ], + [ + 21, + 17 + ], + [ + 17, + 15 + ], + [ + 15, + 13 + ], + [ + 12, + 13 + ], + [ + 6, + 12 + ], + [ + 7, + 13 + ], + [ + 6, + 7 + ], + [ + 6, + 8 + ], + [ + 7, + 9 + ], + [ + 10, + 18 + ], + [ + 8, + 10 + ], + [ + 11, + 19 + ], + [ + 9, + 11 + ], + [ + 2, + 3 + ], + [ + 1, + 2 + ], + [ + 1, + 3 + ], + [ + 2, + 4 + ], + [ + 3, + 5 + ], + [ + 4, + 6 + ], + [ + 5, + 7 + ] + ] + } + ] +} \ No newline at end of file diff --git a/tests/data/humanart/test_humanart_det_AP_H_56.json b/tests/data/humanart/test_humanart_det_AP_H_56.json new file mode 100644 index 0000000000..753caa0c07 --- /dev/null +++ b/tests/data/humanart/test_humanart_det_AP_H_56.json @@ -0,0 +1,145 @@ +[ + { + "bbox": [ + 411.55450439453125, + 773.5175170898438, + 925.8963623046875, + 1736.38623046875 + ], + "category_id": 1, + "image_id": 2000000001648, + "score": 0.9018925428390503 + }, + { + "bbox": [ + 23.97265625, + 19.622175216674805, + 1121.828369140625, + 1269.2109375 + ], + "category_id": 1, + "image_id": 2000000001648, + "score": 0.4558742344379425 + }, + { + "bbox": [ + 82.678466796875, + 475.8934020996094, + 1093.4742431640625, + 1717.331298828125 + ], + "category_id": 1, + "image_id": 2000000001648, + "score": 0.37606894969940186 + }, + { + "bbox": [ + 393.59222412109375, + 125.75264739990234, + 895.0135498046875, + 1201.154296875 + ], + "category_id": 1, + "image_id": 2000000001648, + "score": 0.08204865455627441 + }, + { + "bbox": [ + 75.03559875488281, + 52.54023742675781, + 759.2489624023438, + 974.7556762695312 + ], + "category_id": 1, + "image_id": 2000000001648, + "score": 0.07333727180957794 + }, + { + "bbox": [ + 197.08047485351562, + 139.95877075195312, + 402.2601318359375, + 591.4268188476562 + ], + "category_id": 1, + "image_id": 12000000005603, + "score": 0.9604519009590149 + }, + { + "bbox": [ + 67.07928466796875, + 132.88070678710938, + 535.9130249023438, + 600.0 + ], + "category_id": 1, + "image_id": 12000000005603, + "score": 0.10827567428350449 + }, + { + "bbox": [ + 21.64974594116211, + 0.0, + 564.9321899414062, + 592.8584594726562 + ], + "category_id": 1, + "image_id": 15000000000590, + "score": 0.9986042380332947 + }, + { + "bbox": [ + 158.69786071777344, + 249.30482482910156, + 410.9751281738281, + 608.938720703125 + ], + "category_id": 1, + "image_id": 15000000000590, + "score": 0.7594972252845764 + }, + { + "bbox": [ + 184.25045776367188, + 370.5571594238281, + 361.1768493652344, + 601.1585083007812 + ], + "category_id": 1, + "image_id": 15000000000590, + "score": 0.26641231775283813 + }, + { + "bbox": [ + 129.24253845214844, + 251.26560974121094, + 552.2449951171875, + 517.3319702148438 + ], + "category_id": 1, + "image_id": 15000000000590, + "score": 0.05408962443470955 + }, + { + "bbox": [ + 168.77576, + 366.08698000000004, + 421.95972800000004, + 611.0 + ], + "category_id": 1, + "image_id": 15000000000590, + "score": 0.6465661513194214 + }, + { + "bbox": [ + 36.42278, + 0.0, + 588.0, + 611.0 + ], + "category_id": 1, + "image_id": 15000000000590, + "score": 0.844070429325392 + } +] \ No newline at end of file diff --git a/tests/data/lapa/10773046825_0.jpg b/tests/data/lapa/10773046825_0.jpg new file mode 100644 index 0000000000..ebbc0a3bc5 Binary files /dev/null and b/tests/data/lapa/10773046825_0.jpg differ diff --git a/tests/data/lapa/13609937564_5.jpg b/tests/data/lapa/13609937564_5.jpg new file mode 100644 index 0000000000..d9c2c08682 Binary files /dev/null and b/tests/data/lapa/13609937564_5.jpg differ diff --git a/tests/data/lapa/test_lapa.json b/tests/data/lapa/test_lapa.json new file mode 100644 index 0000000000..0484f08c06 --- /dev/null +++ b/tests/data/lapa/test_lapa.json @@ -0,0 +1,39 @@ +{ + "categories": [ + { + "supercategory": "person", + "id": 1, + "name": "face", + "keypoints": [], + "skeleton": [] + } + ], + "images": [ + {"id": 40, "file_name": "10773046825_0.jpg", "height": 1494, "width": 1424}, + {"id": 41, "file_name": "13609937564_5.jpg", "height": 496, "width": 486} + ], + "annotations": [ + { + "keypoints": [ + 406.0, 644.0, 2.0, 402.0, 682.0, 2.0, 397.0, 719.0, 2.0, 391.0, 757.0, 2.0, 388.0, 795.0, 2.0, 389.0, 834.0, 2.0, 394.0, 874.0, 2.0, 402.0, 913.0, 2.0, 413.0, 952.0, 2.0, 426.0, 989.0, 2.0, 443.0, 1025.0, 2.0, 461.0, 1059.0, 2.0, 481.0, 1092.0, 2.0, 502.0, 1126.0, 2.0, 527.0, 1156.0, 2.0, 559.0, 1180.0, 2.0, 603.0, 1193.0, 2.0, 658.0, 1195.0, 2.0, 713.0, 1187.0, 2.0, 766.0, 1172.0, 2.0, 816.0, 1151.0, 2.0, 863.0, 1128.0, 2.0, 907.0, 1101.0, 2.0, 945.0, 1067.0, 2.0, 978.0, 1029.0, 2.0, 1003.0, 986.0, 2.0, 1019.0, 938.0, 2.0, 1030.0, 888.0, 2.0, 1037.0, 838.0, 2.0, 1040.0, 788.0, 2.0, 1040.0, 739.0, 2.0, 1037.0, 689.0, 2.0, 1033.0, 640.0, 2.0, 417.0, 595.0, 2.0, 445.0, 559.0, 2.0, 488.0, 548.0, 2.0, 535.0, 558.0, 2.0, 569.0, 579.0, 2.0, 562.0, 604.0, 2.0, 526.0, 588.0, 2.0, 487.0, 579.0, 2.0, 451.0, 581.0, 2.0, 662.0, 566.0, 2.0, 713.0, 545.0, 2.0, 777.0, 541.0, 2.0, 839.0, 558.0, 2.0, 887.0, 600.0, 2.0, 832.0, 581.0, 2.0, 777.0, 572.0, 2.0, 721.0, 578.0, 2.0, 669.0, 593.0, 2.0, 614.0, 654.0, 2.0, 602.0, 704.0, 2.0, 590.0, 755.0, 2.0, 577.0, 807.0, 2.0, 573.0, 678.0, 2.0, 540.0, 778.0, 2.0, 518.0, 826.0, 2.0, 538.0, 846.0, 2.0, 562.0, 855.0, 2.0, 592.0, 866.0, 2.0, 632.0, 856.0, 2.0, 668.0, 848.0, 2.0, 703.0, 827.0, 2.0, 681.0, 778.0, 2.0, 667.0, 676.0, 2.0, 447.0, 672.0, 2.0, 472.0, 662.0, 2.0, 499.0, 658.0, 2.0, 526.0, 662.0, 2.0, 550.0, 675.0, 2.0, 524.0, 674.0, 2.0, 498.0, 673.0, 2.0, 472.0, 673.0, 2.0, 501.0, 666.0, 2.0, 701.0, 673.0, 2.0, 729.0, 658.0, 2.0, 760.0, 654.0, 2.0, 792.0, 659.0, 2.0, 822.0, 671.0, 2.0, 791.0, 672.0, 2.0, 761.0, 672.0, 2.0, 731.0, 672.0, 2.0, 762.0, 663.0, 2.0, 503.0, 940.0, 2.0, 532.0, 923.0, 2.0, 575.0, 921.0, 2.0, 602.0, 927.0, 2.0, 631.0, 922.0, 2.0, 704.0, 930.0, 2.0, 775.0, 951.0, 2.0, 735.0, 1001.0, 2.0, 680.0, 1032.0, 2.0, 608.0, 1040.0, 2.0, 553.0, 1023.0, 2.0, 522.0, 987.0, 2.0, 519.0, 945.0, 2.0, 549.0, 937.0, 2.0, 604.0, 944.0, 2.0, 687.0, 942.0, 2.0, 751.0, 955.0, 2.0, 700.0, 996.0, 2.0, 609.0, 1007.0, 2.0, 546.0, 987.0, 2.0, 501.0, 666.0, 2.0, 762.0, 663.0, 2.0], + "image_id": 40, + "id": 40, + "num_keypoints": 106, + "bbox": [388.0, 541.0, 652.0, 654.0], + "iscrowd": 0, + "area": 426408, + "category_id": 1 + }, + { + "keypoints": [ + 179.0, 213.0, 2.0, 176.0, 225.0, 2.0, 173.0, 237.0, 2.0, 170.0, 249.0, 2.0, 167.0, 261.0, 2.0, 166.0, 273.0, 2.0, 165.0, 286.0, 2.0, 166.0, 299.0, 2.0, 170.0, 311.0, 2.0, 176.0, 322.0, 2.0, 184.0, 331.0, 2.0, 194.0, 340.0, 2.0, 206.0, 347.0, 2.0, 218.0, 353.0, 2.0, 231.0, 358.0, 2.0, 244.0, 362.0, 2.0, 258.0, 365.0, 2.0, 269.0, 364.0, 2.0, 278.0, 361.0, 2.0, 286.0, 355.0, 2.0, 293.0, 349.0, 2.0, 300.0, 342.0, 2.0, 306.0, 334.0, 2.0, 311.0, 326.0, 2.0, 315.0, 317.0, 2.0, 318.0, 307.0, 2.0, 321.0, 298.0, 2.0, 323.0, 288.0, 2.0, 323.0, 279.0, 2.0, 323.0, 269.0, 2.0, 322.0, 260.0, 2.0, 321.0, 251.0, 2.0, 322.0, 242.0, 2.0, 207.0, 214.0, 2.0, 220.0, 206.0, 2.0, 236.0, 204.0, 2.0, 253.0, 208.0, 2.0, 266.0, 214.0, 2.0, 263.0, 221.0, 2.0, 250.0, 216.0, 2.0, 235.0, 212.0, 2.0, 221.0, 212.0, 2.0, 293.0, 223.0, 2.0, 302.0, 221.0, 2.0, 313.0, 221.0, 2.0, 321.0, 225.0, 2.0, 325.0, 233.0, 2.0, 318.0, 230.0, 2.0, 311.0, 228.0, 2.0, 302.0, 227.0, 2.0, 293.0, 228.0, 2.0, 277.0, 234.0, 2.0, 280.0, 244.0, 2.0, 283.0, 254.0, 2.0, 285.0, 265.0, 2.0, 261.0, 238.0, 2.0, 256.0, 257.0, 2.0, 248.0, 269.0, 2.0, 256.0, 275.0, 2.0, 266.0, 278.0, 2.0, 275.0, 282.0, 2.0, 282.0, 281.0, 2.0, 288.0, 281.0, 2.0, 293.0, 277.0, 2.0, 291.0, 263.0, 2.0, 285.0, 243.0, 2.0, 220.0, 228.0, 2.0, 228.0, 224.0, 2.0, 237.0, 224.0, 2.0, 245.0, 228.0, 2.0, 251.0, 235.0, 2.0, 243.0, 234.0, 2.0, 234.0, 234.0, 2.0, 226.0, 231.0, 2.0, 232.0, 228.0, 2.0, 287.0, 242.0, 2.0, 293.0, 238.0, 2.0, 301.0, 237.0, 2.0, 307.0, 241.0, 2.0, 311.0, 246.0, 2.0, 306.0, 247.0, 2.0, 299.0, 246.0, 2.0, 293.0, 245.0, 2.0, 297.0, 241.0, 2.0, 222.0, 299.0, 2.0, 242.0, 293.0, 2.0, 263.0, 292.0, 2.0, 271.0, 295.0, 2.0, 279.0, 295.0, 2.0, 288.0, 302.0, 2.0, 292.0, 310.0, 2.0, 286.0, 318.0, 2.0, 277.0, 324.0, 2.0, 263.0, 325.0, 2.0, 246.0, 320.0, 2.0, 233.0, 310.0, 2.0, 229.0, 300.0, 2.0, 246.0, 298.0, 2.0, 269.0, 302.0, 2.0, 282.0, 305.0, 2.0, 289.0, 310.0, 2.0, 280.0, 313.0, 2.0, 265.0, 313.0, 2.0, 243.0, 307.0, 2.0, 232.0, 228.0, 2.0, 297.0, 241.0, 2.0], + "image_id": 41, + "id": 41, + "num_keypoints": 106, + "bbox": [165.0, 204.0, 160.0, 161.0], + "iscrowd": 0, + "area": 25760, + "category_id": 1 + } + ] +} diff --git a/tests/test_apis/test_inferencers/test_mmpose_inferencer.py b/tests/test_apis/test_inferencers/test_mmpose_inferencer.py index af48bc2129..8b8a4744b8 100644 --- a/tests/test_apis/test_inferencers/test_mmpose_inferencer.py +++ b/tests/test_apis/test_inferencers/test_mmpose_inferencer.py @@ -11,11 +11,16 @@ from mmpose.apis.inferencers import MMPoseInferencer from mmpose.structures import PoseDataSample +from mmpose.utils import register_all_modules class TestMMPoseInferencer(TestCase): - def test_call(self): + def tearDown(self) -> None: + register_all_modules(init_default_scope=True) + return super().tearDown() + + def test_pose2d_call(self): try: from mmdet.apis.det_inferencer import DetInferencer # noqa: F401 except (ImportError, ModuleNotFoundError): @@ -88,3 +93,37 @@ def test_call(self): os.listdir(f'{tmp_dir}/predictions')) self.assertTrue(inferencer._video_input) self.assertIn(len(results['predictions']), (4, 5)) + + def test_pose3d_call(self): + try: + from mmdet.apis.det_inferencer import DetInferencer # noqa: F401 + except (ImportError, ModuleNotFoundError): + return unittest.skip('mmdet is not installed') + + # top-down model + if platform.system().lower() == 'windows': + # the default human pose estimator utilizes rtmdet-m detector + # through alias, which seems not compatible with windows + det_model = 'demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py' + det_weights = 'https://download.openmmlab.com/mmdetection/v2.0/' \ + 'faster_rcnn/faster_rcnn_r50_fpn_1x_coco/' \ + 'faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth' + else: + det_model, det_weights = None, None + inferencer = MMPoseInferencer( + pose3d='human3d', det_model=det_model, det_weights=det_weights) + + # `inputs` is path to a video + inputs = 'https://user-images.githubusercontent.com/87690686/' \ + '164970135-b14e424c-765a-4180-9bc8-fa8d6abc5510.mp4' + with TemporaryDirectory() as tmp_dir: + results = defaultdict(list) + for res in inferencer(inputs, out_dir=tmp_dir): + for key in res: + results[key].extend(res[key]) + self.assertIn('164970135-b14e424c-765a-4180-9bc8-fa8d6abc5510.mp4', + os.listdir(f'{tmp_dir}/visualizations')) + self.assertIn( + '164970135-b14e424c-765a-4180-9bc8-fa8d6abc5510.json', + os.listdir(f'{tmp_dir}/predictions')) + self.assertTrue(inferencer._video_input) diff --git a/tests/test_apis/test_inferencers/test_pose2d_inferencer.py b/tests/test_apis/test_inferencers/test_pose2d_inferencer.py index 63206631ba..b59232efac 100644 --- a/tests/test_apis/test_inferencers/test_pose2d_inferencer.py +++ b/tests/test_apis/test_inferencers/test_pose2d_inferencer.py @@ -13,10 +13,15 @@ from mmpose.apis.inferencers import Pose2DInferencer from mmpose.structures import PoseDataSample +from mmpose.utils import register_all_modules class TestPose2DInferencer(TestCase): + def tearDown(self) -> None: + register_all_modules(init_default_scope=True) + return super().tearDown() + def _get_det_model_weights(self): if platform.system().lower() == 'windows': # the default human/animal pose estimator utilizes rtmdet-m diff --git a/tests/test_apis/test_inferencers/test_pose3d_inferencer.py b/tests/test_apis/test_inferencers/test_pose3d_inferencer.py new file mode 100644 index 0000000000..da4a34b160 --- /dev/null +++ b/tests/test_apis/test_inferencers/test_pose3d_inferencer.py @@ -0,0 +1,152 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os +import os.path as osp +import platform +import unittest +from collections import defaultdict +from tempfile import TemporaryDirectory +from unittest import TestCase + +import mmcv +import torch + +from mmpose.apis.inferencers import Pose2DInferencer, Pose3DInferencer +from mmpose.structures import PoseDataSample +from mmpose.utils import register_all_modules + + +class TestPose3DInferencer(TestCase): + + def tearDown(self) -> None: + register_all_modules(init_default_scope=True) + return super().tearDown() + + def _get_det_model_weights(self): + if platform.system().lower() == 'windows': + # the default human/animal pose estimator utilizes rtmdet-m + # detector through alias, which seems not compatible with windows + det_model = 'demo/mmdetection_cfg/faster_rcnn_r50_fpn_coco.py' + det_weights = 'https://download.openmmlab.com/mmdetection/v2.0/' \ + 'faster_rcnn/faster_rcnn_r50_fpn_1x_coco/' \ + 'faster_rcnn_r50_fpn_1x_coco_20200130-047c8118.pth' + else: + det_model, det_weights = None, None + + return det_model, det_weights + + def test_init(self): + + try: + from mmdet.apis.det_inferencer import DetInferencer # noqa: F401 + except (ImportError, ModuleNotFoundError): + return unittest.skip('mmdet is not installed') + + det_model, det_weights = self._get_det_model_weights() + + # 1. init with config path and checkpoint + inferencer = Pose3DInferencer( + model= # noqa + 'configs/body_3d_keypoint/pose_lift/h36m/pose-lift_videopose3d-243frm-supv-cpn-ft_8xb128-200e_h36m.py', # noqa + weights= # noqa + 'https://download.openmmlab.com/mmpose/body3d/videopose/videopose_h36m_243frames_fullconv_supervised_cpn_ft-88f5abbb_20210527.pth', # noqa + pose2d_model='configs/body_2d_keypoint/simcc/coco/' + 'simcc_res50_8xb64-210e_coco-256x192.py', + pose2d_weights='https://download.openmmlab.com/mmpose/' + 'v1/body_2d_keypoint/simcc/coco/' + 'simcc_res50_8xb64-210e_coco-256x192-8e0f5b59_20220919.pth', + det_model=det_model, + det_weights=det_weights, + det_cat_ids=0 if det_model else None) + self.assertIsInstance(inferencer.model, torch.nn.Module) + self.assertIsInstance(inferencer.pose2d_model, Pose2DInferencer) + + # 2. init with config name + inferencer = Pose3DInferencer( + model='configs/body_3d_keypoint/pose_lift/h36m/pose-lift_' + 'videopose3d-243frm-supv-cpn-ft_8xb128-200e_h36m.py', + pose2d_model='configs/body_2d_keypoint/simcc/coco/' + 'simcc_res50_8xb64-210e_coco-256x192.py', + det_model=det_model, + det_weights=det_weights, + det_cat_ids=0 if det_model else None) + self.assertIsInstance(inferencer.model, torch.nn.Module) + self.assertIsInstance(inferencer.pose2d_model, Pose2DInferencer) + + # 3. init with alias + inferencer = Pose3DInferencer( + model='human3d', + det_model=det_model, + det_weights=det_weights, + det_cat_ids=0 if det_model else None) + self.assertIsInstance(inferencer.model, torch.nn.Module) + self.assertIsInstance(inferencer.pose2d_model, Pose2DInferencer) + + def test_call(self): + + try: + from mmdet.apis.det_inferencer import DetInferencer # noqa: F401 + except (ImportError, ModuleNotFoundError): + return unittest.skip('mmdet is not installed') + + # top-down model + det_model, det_weights = self._get_det_model_weights() + inferencer = Pose3DInferencer( + model='human3d', + det_model=det_model, + det_weights=det_weights, + det_cat_ids=0 if det_model else None) + + img_path = 'tests/data/coco/000000197388.jpg' + img = mmcv.imread(img_path) + + # `inputs` is path to an image + inputs = img_path + results1 = next(inferencer(inputs, return_vis=True)) + self.assertIn('visualization', results1) + self.assertIn('predictions', results1) + self.assertIn('keypoints', results1['predictions'][0][0]) + self.assertEqual(len(results1['predictions'][0][0]['keypoints']), 17) + + # `inputs` is an image array + inputs = img + results2 = next(inferencer(inputs)) + self.assertEqual( + len(results1['predictions'][0]), len(results2['predictions'][0])) + self.assertSequenceEqual(results1['predictions'][0][0]['keypoints'], + results2['predictions'][0][0]['keypoints']) + results2 = next(inferencer(inputs, return_datasample=True)) + self.assertIsInstance(results2['predictions'][0], PoseDataSample) + + # `inputs` is path to a directory + inputs = osp.dirname(img_path) + + with TemporaryDirectory() as tmp_dir: + # only save visualizations + for res in inferencer(inputs, vis_out_dir=tmp_dir): + pass + self.assertEqual(len(os.listdir(tmp_dir)), 4) + # save both visualizations and predictions + results3 = defaultdict(list) + for res in inferencer(inputs, out_dir=tmp_dir): + for key in res: + results3[key].extend(res[key]) + self.assertEqual(len(os.listdir(f'{tmp_dir}/visualizations')), 4) + self.assertEqual(len(os.listdir(f'{tmp_dir}/predictions')), 4) + self.assertEqual(len(results3['predictions']), 4) + self.assertSequenceEqual(results1['predictions'][0][0]['keypoints'], + results3['predictions'][3][0]['keypoints']) + + # `inputs` is path to a video + inputs = 'https://user-images.githubusercontent.com/87690686/' \ + '164970135-b14e424c-765a-4180-9bc8-fa8d6abc5510.mp4' + with TemporaryDirectory() as tmp_dir: + results = defaultdict(list) + for res in inferencer(inputs, out_dir=tmp_dir): + for key in res: + results[key].extend(res[key]) + self.assertIn('164970135-b14e424c-765a-4180-9bc8-fa8d6abc5510.mp4', + os.listdir(f'{tmp_dir}/visualizations')) + self.assertIn( + '164970135-b14e424c-765a-4180-9bc8-fa8d6abc5510.json', + os.listdir(f'{tmp_dir}/predictions')) + self.assertTrue(inferencer._video_input) diff --git a/tests/test_apis/test_webcam/test_nodes/test_big_eye_effect_node.py b/tests/test_apis/test_webcam/test_nodes/test_big_eye_effect_node.py deleted file mode 100644 index b5a8ee8f72..0000000000 --- a/tests/test_apis/test_webcam/test_nodes/test_big_eye_effect_node.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest - -import mmcv -import numpy as np -from mmengine import Config - -from mmpose.apis.webcam.nodes import BigeyeEffectNode -from mmpose.apis.webcam.utils.message import FrameMessage -from mmpose.datasets.datasets.utils import parse_pose_metainfo - - -class TestBigeyeEffectNode(unittest.TestCase): - - def setUp(self) -> None: - self.node = BigeyeEffectNode( - name='big-eye', input_buffer='vis', output_buffer='vis_bigeye') - - def _get_input_msg(self): - - msg = FrameMessage(None) - - image_path = 'tests/data/coco/000000000785.jpg' - image = mmcv.imread(image_path) - h, w = image.shape[:2] - msg.set_image(image) - - objects = [ - dict( - bbox=np.array([285.1, 44.4, 510.2, 387.7]), - keypoints=np.stack((np.random.rand(17) * - (w - 1), np.random.rand(17) * (h - 1)), - axis=1), - keypoint_scores=np.ones(17), - dataset_meta=parse_pose_metainfo( - Config.fromfile('configs/_base_/datasets/coco.py') - ['dataset_info'])) - ] - msg.update_objects(objects) - - return msg - - def test_process(self): - input_msg = self._get_input_msg() - img_h, img_w = input_msg.get_image().shape[:2] - self.assertEqual(len(input_msg.get_objects()), 1) - - output_msg = self.node.process(dict(input=input_msg)) - canvas = output_msg.get_image() - self.assertIsInstance(canvas, np.ndarray) - self.assertEqual(canvas.shape[0], img_h) - self.assertEqual(canvas.shape[1], img_w) - - def test_bypass(self): - input_msg = self._get_input_msg() - img = input_msg.get_image().copy() - output_msg = self.node.bypass(dict(input=input_msg)) - self.assertTrue((img == output_msg.get_image()).all()) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_nodes/test_detector_node.py b/tests/test_apis/test_webcam/test_nodes/test_detector_node.py deleted file mode 100644 index b519744fee..0000000000 --- a/tests/test_apis/test_webcam/test_nodes/test_detector_node.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest - -import mmcv - -from mmpose.apis.webcam.nodes import DetectorNode -from mmpose.apis.webcam.utils.message import FrameMessage - - -class TestDetectorNode(unittest.TestCase): - model_config = dict( - name='detector', - model_config='demo/mmdetection_cfg/' - 'ssdlite_mobilenetv2-scratch_8xb24-600e_coco.py', - model_checkpoint='https://download.openmmlab.com' - '/mmdetection/v2.0/ssd/' - 'ssdlite_mobilenetv2_scratch_600e_coco/ssdlite_mobilenetv2_' - 'scratch_600e_coco_20210629_110627-974d9307.pth', - device='cpu', - input_buffer='_input_', - output_buffer='det_result') - - def setUp(self) -> None: - self._has_mmdet = True - try: - from mmdet.apis import init_detector # noqa: F401 - except (ImportError, ModuleNotFoundError): - self._has_mmdet = False - - def _get_input_msg(self): - - msg = FrameMessage(None) - - image_path = 'tests/data/coco/000000000785.jpg' - image = mmcv.imread(image_path) - msg.set_image(image) - - return msg - - def test_init(self): - - if not self._has_mmdet: - return unittest.skip('mmdet is not installed') - - node = DetectorNode(**self.model_config) - - self.assertEqual(len(node._input_buffers), 1) - self.assertEqual(len(node._output_buffers), 1) - self.assertEqual(node._input_buffers[0].buffer_name, '_input_') - self.assertEqual(node._output_buffers[0].buffer_name, 'det_result') - self.assertEqual(node.device, 'cpu') - - def test_process(self): - - if not self._has_mmdet: - return unittest.skip('mmdet is not installed') - - node = DetectorNode(**self.model_config) - - input_msg = self._get_input_msg() - self.assertEqual(len(input_msg.get_objects()), 0) - - output_msg = node.process(dict(input=input_msg)) - objects = output_msg.get_objects() - # there is a person in the image - self.assertGreaterEqual(len(objects), 1) - self.assertIn('person', [obj['label'] for obj in objects]) - self.assertEqual(objects[0]['bbox'].shape, (4, )) - - def test_bypass(self): - - if not self._has_mmdet: - return unittest.skip('mmdet is not installed') - - node = DetectorNode(**self.model_config) - - input_msg = self._get_input_msg() - self.assertEqual(len(input_msg.get_objects()), 0) - - output_msg = node.bypass(dict(input=input_msg)) - self.assertEqual(len(output_msg.get_objects()), 0) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_nodes/test_monitor_node.py b/tests/test_apis/test_webcam/test_nodes/test_monitor_node.py deleted file mode 100644 index d71654cc39..0000000000 --- a/tests/test_apis/test_webcam/test_nodes/test_monitor_node.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest - -import mmcv - -from mmpose.apis.webcam.nodes import MonitorNode -from mmpose.apis.webcam.utils.message import FrameMessage - - -class TestMonitorNode(unittest.TestCase): - - def _get_input_msg(self): - - msg = FrameMessage(None) - - image_path = 'tests/data/coco/000000000785.jpg' - image = mmcv.imread(image_path) - msg.set_image(image) - - objects = [dict(label='human')] - msg.update_objects(objects) - - return msg - - def test_init(self): - node = MonitorNode( - name='monitor', input_buffer='_frame_', output_buffer='display') - self.assertEqual(len(node._input_buffers), 1) - self.assertEqual(len(node._output_buffers), 1) - self.assertEqual(node._input_buffers[0].buffer_name, '_frame_') - self.assertEqual(node._output_buffers[0].buffer_name, 'display') - - # test initialization with given ignore_items - node = MonitorNode( - name='monitor', - input_buffer='_frame_', - output_buffer='display', - ignore_items=['ignore_item']) - self.assertEqual(len(node.ignore_items), 1) - self.assertEqual(node.ignore_items[0], 'ignore_item') - - def test_process(self): - node = MonitorNode( - name='monitor', input_buffer='_frame_', output_buffer='display') - - input_msg = self._get_input_msg() - self.assertEqual(len(input_msg.get_route_info()), 0) - img_shape = input_msg.get_image().shape - - output_msg = node.process(dict(input=input_msg)) - # 'System Info' will be added into route_info - self.assertEqual(len(output_msg.get_route_info()), 1) - self.assertEqual(output_msg.get_image().shape, img_shape) - - def test_bypass(self): - node = MonitorNode( - name='monitor', input_buffer='_frame_', output_buffer='display') - input_msg = self._get_input_msg() - self.assertEqual(len(input_msg.get_route_info()), 0) - - output_msg = node.bypass(dict(input=input_msg)) - # output_msg should be identity with input_msg - self.assertEqual(len(output_msg.get_route_info()), 0) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_nodes/test_notice_board_node.py b/tests/test_apis/test_webcam/test_nodes/test_notice_board_node.py deleted file mode 100644 index 31583bf815..0000000000 --- a/tests/test_apis/test_webcam/test_nodes/test_notice_board_node.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest - -import mmcv -import numpy as np - -from mmpose.apis.webcam.nodes import NoticeBoardNode -from mmpose.apis.webcam.utils.message import FrameMessage - - -class TestNoticeBoardNode(unittest.TestCase): - - def _get_input_msg(self): - - msg = FrameMessage(None) - - image_path = 'tests/data/coco/000000000785.jpg' - image = mmcv.imread(image_path) - h, w = image.shape[:2] - msg.set_image(image) - - return msg - - def test_init(self): - node = NoticeBoardNode( - name='instruction', input_buffer='vis', output_buffer='vis_notice') - - self.assertEqual(len(node._input_buffers), 1) - self.assertEqual(len(node._output_buffers), 1) - self.assertEqual(node._input_buffers[0].buffer_name, 'vis') - self.assertEqual(node._output_buffers[0].buffer_name, 'vis_notice') - self.assertEqual(len(node.content_lines), 1) - - node = NoticeBoardNode( - name='instruction', - input_buffer='vis', - output_buffer='vis_notice', - content_lines=[ - 'This is a demo for pose visualization and simple image ' - 'effects. Have fun!', '', 'Hot-keys:', - '"v": Pose estimation result visualization', - '"s": Sunglasses effect B-)', '"b": Big-eye effect 0_0', - '"h": Show help information', - '"m": Show diagnostic information', '"q": Exit' - ]) - self.assertEqual(len(node.content_lines), 9) - - def test_draw(self): - node = NoticeBoardNode( - name='instruction', input_buffer='vis', output_buffer='vis_notice') - input_msg = self._get_input_msg() - img_h, img_w = input_msg.get_image().shape[:2] - - canvas = node.draw(input_msg) - self.assertIsInstance(canvas, np.ndarray) - self.assertEqual(canvas.shape[0], img_h) - self.assertEqual(canvas.shape[1], img_w) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_nodes/test_object_assigner_node.py b/tests/test_apis/test_webcam/test_nodes/test_object_assigner_node.py deleted file mode 100644 index 0405c885d7..0000000000 --- a/tests/test_apis/test_webcam/test_nodes/test_object_assigner_node.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import time -import unittest - -import mmcv -import numpy as np - -from mmpose.apis.webcam.nodes import ObjectAssignerNode -from mmpose.apis.webcam.utils.message import FrameMessage - - -class TestObjectAssignerNode(unittest.TestCase): - - def _get_input_msg(self, with_object: bool = False): - - msg = FrameMessage(None) - - image_path = 'tests/data/coco/000000000785.jpg' - image = mmcv.imread(image_path) - msg.set_image(image) - - if with_object: - objects = [ - dict( - label='person', - class_id=0, - bbox=np.array([285.1, 44.4, 510.2, 387.7])) - ] - msg.update_objects(objects) - - return msg - - def test_init(self): - node = ObjectAssignerNode( - name='object assigner', - frame_buffer='_frame_', - object_buffer='pred_result', - output_buffer='frame') - - self.assertEqual(len(node._input_buffers), 2) - self.assertEqual(len(node._output_buffers), 1) - self.assertEqual(node._input_buffers[0].buffer_name, 'pred_result') - self.assertEqual(node._input_buffers[1].buffer_name, '_frame_') - self.assertEqual(node._output_buffers[0].buffer_name, 'frame') - - def test_process(self): - node = ObjectAssignerNode( - name='object assigner', - frame_buffer='_frame_', - object_buffer='pred_result', - output_buffer='frame') - - frame_msg = self._get_input_msg() - object_msg = self._get_input_msg(with_object=True) - self.assertEqual(len(frame_msg.get_objects()), 0) - self.assertEqual(len(object_msg.get_objects()), 1) - - # node.synchronous is False - output_msg = node.process(dict(frame=frame_msg, object=object_msg)) - objects = output_msg.get_objects() - self.assertEqual(id(frame_msg), id(output_msg)) - self.assertEqual(objects[0]['_id_'], - object_msg.get_objects()[0]['_id_']) - - # object_message is None - # take a pause to increase the interval of messages' timestamp - # to avoid ZeroDivisionError when computing fps in `process` - time.sleep(1 / 30.0) - frame_msg = self._get_input_msg() - output_msg = node.process(dict(frame=frame_msg, object=None)) - objects = output_msg.get_objects() - self.assertEqual(objects[0]['_id_'], - object_msg.get_objects()[0]['_id_']) - - # node.synchronous is True - node.synchronous = True - time.sleep(1 / 30.0) - frame_msg = self._get_input_msg() - object_msg = self._get_input_msg(with_object=True) - output_msg = node.process(dict(frame=frame_msg, object=object_msg)) - self.assertEqual(len(frame_msg.get_objects()), 0) - self.assertEqual(id(object_msg), id(output_msg)) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_nodes/test_object_visualizer_node.py b/tests/test_apis/test_webcam/test_nodes/test_object_visualizer_node.py deleted file mode 100644 index c55bc1eb8d..0000000000 --- a/tests/test_apis/test_webcam/test_nodes/test_object_visualizer_node.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest - -import mmcv -import numpy as np -from mmengine import Config - -from mmpose.apis.webcam.nodes import ObjectVisualizerNode -from mmpose.apis.webcam.utils.message import FrameMessage -from mmpose.datasets.datasets.utils import parse_pose_metainfo - - -class TestObjectVisualizerNode(unittest.TestCase): - - def _get_input_msg(self): - - msg = FrameMessage(None) - - image_path = 'tests/data/coco/000000000785.jpg' - image = mmcv.imread(image_path) - h, w = image.shape[:2] - msg.set_image(image) - - objects = [ - dict( - label='person', - class_id=0, - bbox=np.array([285.1, 44.4, 510.2, 387.7]), - keypoints=np.stack((np.random.rand(17) * - (w - 1), np.random.rand(17) * (h - 1)), - axis=1), - keypoint_scores=np.ones(17), - dataset_meta=parse_pose_metainfo( - Config.fromfile('configs/_base_/datasets/coco.py') - ['dataset_info'])) - ] - msg.update_objects(objects) - - return msg - - def test_init(self): - node = ObjectVisualizerNode( - name='object visualizer', - input_buffer='frame', - output_buffer='vis') - - self.assertEqual(len(node._input_buffers), 1) - self.assertEqual(len(node._output_buffers), 1) - self.assertEqual(node._input_buffers[0].buffer_name, 'frame') - self.assertEqual(node._output_buffers[0].buffer_name, 'vis') - - def test_draw(self): - # draw all objects with bounding box - node = ObjectVisualizerNode( - name='object visualizer', - input_buffer='frame', - output_buffer='vis') - input_msg = self._get_input_msg() - img_h, img_w = input_msg.get_image().shape[:2] - self.assertEqual(len(input_msg.get_objects()), 1) - - canvas = node.draw(input_msg) - self.assertIsInstance(canvas, np.ndarray) - self.assertEqual(canvas.shape[0], img_h) - self.assertEqual(canvas.shape[1], img_w) - - # draw all objects with keypoints - node = ObjectVisualizerNode( - name='object visualizer', - input_buffer='frame', - output_buffer='vis', - must_have_keypoint=True) - canvas = node.draw(input_msg) - self.assertIsInstance(canvas, np.ndarray) - self.assertEqual(canvas.shape[0], img_h) - self.assertEqual(canvas.shape[1], img_w) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_nodes/test_pose_estimator_node.py b/tests/test_apis/test_webcam/test_nodes/test_pose_estimator_node.py deleted file mode 100644 index 43345d116a..0000000000 --- a/tests/test_apis/test_webcam/test_nodes/test_pose_estimator_node.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest -from copy import deepcopy - -import mmcv -import numpy as np - -from mmpose.apis.webcam.nodes import TopdownPoseEstimatorNode -from mmpose.apis.webcam.utils.message import FrameMessage - - -class TestTopdownPoseEstimatorNode(unittest.TestCase): - model_config = dict( - name='human pose estimator', - model_config='configs/wholebody_2d_keypoint/' - 'topdown_heatmap/coco-wholebody/' - 'td-hm_vipnas-mbv3_dark-8xb64-210e_coco-wholebody-256x192.py', - model_checkpoint='https://download.openmmlab.com/mmpose/' - 'top_down/vipnas/vipnas_mbv3_coco_wholebody_256x192_dark' - '-e2158108_20211205.pth', - device='cpu', - input_buffer='det_result', - output_buffer='human_pose') - - def _get_input_msg(self): - - msg = FrameMessage(None) - - image_path = 'tests/data/coco/000000000785.jpg' - image = mmcv.imread(image_path) - msg.set_image(image) - - objects = [ - dict( - label='person', - class_id=0, - bbox=np.array([285.1, 44.4, 510.2, 387.7])) - ] - msg.update_objects(objects) - - return msg - - def test_init(self): - node = TopdownPoseEstimatorNode(**self.model_config) - - self.assertEqual(len(node._input_buffers), 1) - self.assertEqual(len(node._output_buffers), 1) - self.assertEqual(node._input_buffers[0].buffer_name, 'det_result') - self.assertEqual(node._output_buffers[0].buffer_name, 'human_pose') - self.assertEqual(node.device, 'cpu') - - def test_process(self): - node = TopdownPoseEstimatorNode(**self.model_config) - - input_msg = self._get_input_msg() - self.assertEqual(len(input_msg.get_objects()), 1) - - # run inference on all objects - output_msg = node.process(dict(input=input_msg)) - objects = output_msg.get_objects() - - # there is a person in the image - self.assertGreaterEqual(len(objects), 1) - self.assertIn('person', [obj['label'] for obj in objects]) - self.assertEqual(objects[0]['keypoints'].shape, (133, 2)) - self.assertEqual(objects[0]['keypoint_scores'].shape, (133, )) - - # select objects by class_id - model_config = self.model_config.copy() - model_config['class_ids'] = [0] - node = TopdownPoseEstimatorNode(**model_config) - output_msg = node.process(dict(input=input_msg)) - self.assertGreaterEqual(len(objects), 1) - - # select objects by label - model_config = self.model_config.copy() - model_config['labels'] = ['cat'] - node = TopdownPoseEstimatorNode(**model_config) - output_msg = node.process(dict(input=input_msg)) - self.assertGreaterEqual(len(objects), 0) - - def test_bypass(self): - node = TopdownPoseEstimatorNode(**self.model_config) - - input_msg = self._get_input_msg() - input_objects = input_msg.get_objects() - - output_msg = node.bypass(dict(input=deepcopy(input_msg))) - output_objects = output_msg.get_objects() - self.assertEqual(len(input_objects), len(output_objects)) - self.assertListEqual( - list(input_objects[0].keys()), list(output_objects[0].keys())) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_nodes/test_recorder_node.py b/tests/test_apis/test_webcam/test_nodes/test_recorder_node.py deleted file mode 100644 index a646abb430..0000000000 --- a/tests/test_apis/test_webcam/test_nodes/test_recorder_node.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import os -import unittest - -import mmcv - -from mmpose.apis.webcam.nodes import RecorderNode -from mmpose.apis.webcam.utils.message import FrameMessage - - -class TestMonitorNode(unittest.TestCase): - - def _get_input_msg(self): - - msg = FrameMessage(None) - - image_path = 'tests/data/coco/000000000785.jpg' - image = mmcv.imread(image_path) - msg.set_image(image) - - objects = [dict(label='human')] - msg.update_objects(objects) - - return msg - - def test_init(self): - node = RecorderNode( - name='recorder', - out_video_file='webcam_output.mp4', - input_buffer='display', - output_buffer='_display_') - self.assertEqual(len(node._input_buffers), 1) - self.assertEqual(len(node._output_buffers), 1) - self.assertEqual(node._input_buffers[0].buffer_name, 'display') - self.assertEqual(node._output_buffers[0].buffer_name, '_display_') - self.assertTrue(node.t_record.is_alive()) - - def test_process(self): - node = RecorderNode( - name='recorder', - out_video_file='webcam_output.mp4', - input_buffer='display', - output_buffer='_display_', - buffer_size=1) - - if os.path.exists('webcam_output.mp4'): - os.remove('webcam_output.mp4') - - input_msg = self._get_input_msg() - node.process(dict(input=input_msg)) - self.assertEqual(node.queue.qsize(), 1) - - # process 5 frames in total. - # the first frame has been processed above - for _ in range(4): - node.process(dict(input=input_msg)) - node.on_exit() - - # check the properties of output video - self.assertTrue(os.path.exists('webcam_output.mp4')) - video = mmcv.VideoReader('webcam_output.mp4') - self.assertEqual(video.frame_cnt, 5) - self.assertEqual(video.fps, 30) - video.vcap.release() - os.remove('webcam_output.mp4') - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_nodes/test_sunglasses_effect_node.py b/tests/test_apis/test_webcam/test_nodes/test_sunglasses_effect_node.py deleted file mode 100644 index 1bf1c8199d..0000000000 --- a/tests/test_apis/test_webcam/test_nodes/test_sunglasses_effect_node.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest - -import mmcv -import numpy as np -from mmengine import Config - -from mmpose.apis.webcam.nodes import SunglassesEffectNode -from mmpose.apis.webcam.utils.message import FrameMessage -from mmpose.datasets.datasets.utils import parse_pose_metainfo - - -class TestSunglassesEffectNode(unittest.TestCase): - - def setUp(self) -> None: - self.node = SunglassesEffectNode( - name='sunglasses', - input_buffer='vis', - output_buffer='vis_sunglasses') - - def _get_input_msg(self): - - msg = FrameMessage(None) - - image_path = 'tests/data/coco/000000000785.jpg' - image = mmcv.imread(image_path) - h, w = image.shape[:2] - msg.set_image(image) - - objects = [ - dict( - keypoints=np.stack((np.random.rand(17) * - (w - 1), np.random.rand(17) * (h - 1)), - axis=1), - keypoint_scores=np.ones(17), - dataset_meta=parse_pose_metainfo( - Config.fromfile('configs/_base_/datasets/coco.py') - ['dataset_info'])) - ] - msg.update_objects(objects) - - return msg - - def test_process(self): - input_msg = self._get_input_msg() - img_h, img_w = input_msg.get_image().shape[:2] - self.assertEqual(len(input_msg.get_objects()), 1) - - output_msg = self.node.process(dict(input=input_msg)) - canvas = output_msg.get_image() - self.assertIsInstance(canvas, np.ndarray) - self.assertEqual(canvas.shape[0], img_h) - self.assertEqual(canvas.shape[1], img_w) - - def test_bypass(self): - input_msg = self._get_input_msg() - img = input_msg.get_image().copy() - output_msg = self.node.bypass(dict(input=input_msg)) - self.assertTrue((img == output_msg.get_image()).all()) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_utils/test_buffer.py b/tests/test_apis/test_webcam/test_utils/test_buffer.py deleted file mode 100644 index 2708433ac1..0000000000 --- a/tests/test_apis/test_webcam/test_utils/test_buffer.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest -from queue import Queue - -from mmpose.apis.webcam.utils.buffer import Buffer, BufferManager - - -class TestBuffer(unittest.TestCase): - - def test_buffer(self): - - buffer = Buffer(maxsize=1) - for i in range(3): - buffer.put_force(i) - item = buffer.get() - self.assertEqual(item, 2) - - -class TestBufferManager(unittest.TestCase): - - def _get_buffer_dict(self): - return dict(example_buffer=Buffer()) - - def test_init(self): - - # test default initialization - buffer_manager = BufferManager() - self.assertIn('_buffers', dir(buffer_manager)) - self.assertIsInstance(buffer_manager._buffers, dict) - - # test initialization with given buffers - buffers = self._get_buffer_dict() - buffer_manager = BufferManager(buffers=buffers) - self.assertIn('_buffers', dir(buffer_manager)) - self.assertIsInstance(buffer_manager._buffers, dict) - self.assertIn('example_buffer', buffer_manager._buffers.keys()) - # test __contains__ - self.assertIn('example_buffer', buffer_manager) - - # test initialization with incorrect buffers - buffers['incorrect_buffer'] = Queue() - with self.assertRaises(ValueError): - buffer_manager = BufferManager(buffers=buffers) - - def test_buffer_operations(self): - buffer_manager = BufferManager() - - # test register_buffer - buffer_manager.register_buffer('example_buffer', 1) - self.assertIn('example_buffer', buffer_manager) - self.assertEqual(buffer_manager._buffers['example_buffer'].maxsize, 1) - - # test buffer operations - buffer_manager.put('example_buffer', 0) - item = buffer_manager.get('example_buffer') - self.assertEqual(item, 0) - - buffer_manager.put('example_buffer', 0) - self.assertTrue(buffer_manager.is_full('example_buffer')) - buffer_manager.put_force('example_buffer', 1) - item = buffer_manager.get('example_buffer') - self.assertEqual(item, 1) - self.assertTrue(buffer_manager.is_empty('example_buffer')) - - # test get_info - buffer_info = buffer_manager.get_info() - self.assertIn('example_buffer', buffer_info) - self.assertEqual(buffer_info['example_buffer']['size'], 0) - self.assertEqual(buffer_info['example_buffer']['maxsize'], 1) - - # test get_sub_manager - buffer_manager = buffer_manager.get_sub_manager(['example_buffer']) - self.assertIsInstance(buffer_manager, BufferManager) - self.assertIn('example_buffer', buffer_manager) - self.assertEqual(buffer_manager._buffers['example_buffer'].maxsize, 1) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_utils/test_event.py b/tests/test_apis/test_webcam/test_utils/test_event.py deleted file mode 100644 index 7ff4b234bd..0000000000 --- a/tests/test_apis/test_webcam/test_utils/test_event.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest -from threading import Event - -from mmpose.apis.webcam.utils.event import EventManager - - -class TestEventManager(unittest.TestCase): - - def test_event_manager(self): - event_manager = EventManager() - - # test register_event - event_manager.register_event('example_event') - self.assertIn('example_event', event_manager._events) - self.assertIsInstance(event_manager._events['example_event'], Event) - self.assertFalse(event_manager.is_set('example_event')) - - # test event operations - event_manager.set('q', is_keyboard=True) - self.assertIn('_keyboard_q', event_manager._events) - self.assertTrue(event_manager.is_set('q', is_keyboard=True)) - - flag = event_manager.wait('q', is_keyboard=True) - self.assertTrue(flag) - - event_manager.wait_and_handle('q', is_keyboard=True) - event_manager.clear('q', is_keyboard=True) - self.assertFalse(event_manager._events['_keyboard_q']._flag) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_utils/test_image_capture.py b/tests/test_apis/test_webcam/test_utils/test_image_capture.py deleted file mode 100644 index 8165299b89..0000000000 --- a/tests/test_apis/test_webcam/test_utils/test_image_capture.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest - -import cv2 -import numpy as np - -from mmpose.apis.webcam.utils.image_capture import ImageCapture - - -class TestImageCapture(unittest.TestCase): - - def setUp(self): - self.image_path = 'tests/data/coco/000000000785.jpg' - self.image = cv2.imread(self.image_path) - - def test_init(self): - image_cap = ImageCapture(self.image_path) - self.assertIsInstance(image_cap.image, np.ndarray) - - image_cap = ImageCapture(self.image) - self.assertTrue((self.image == image_cap.image).all()) - - def test_image_capture(self): - image_cap = ImageCapture(self.image_path) - - # test operations - self.assertTrue(image_cap.isOpened()) - - flag, image_ = image_cap.read() - self.assertTrue(flag) - self.assertTrue((self.image == image_).all()) - - image_cap.release() - self.assertIsInstance(image_cap.image, np.ndarray) - - img_h = image_cap.get(cv2.CAP_PROP_FRAME_HEIGHT) - self.assertAlmostEqual(img_h, self.image.shape[0]) - img_w = image_cap.get(cv2.CAP_PROP_FRAME_WIDTH) - self.assertAlmostEqual(img_w, self.image.shape[1]) - fps = image_cap.get(cv2.CAP_PROP_FPS) - self.assertTrue(np.isnan(fps)) - - with self.assertRaises(NotImplementedError): - _ = image_cap.get(-1) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_utils/test_message.py b/tests/test_apis/test_webcam/test_utils/test_message.py deleted file mode 100644 index 536b672e78..0000000000 --- a/tests/test_apis/test_webcam/test_utils/test_message.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest - -import mmcv -import numpy as np - -from mmpose.apis.webcam.nodes import MonitorNode -from mmpose.apis.webcam.utils.message import FrameMessage, Message - - -class TestMessage(unittest.TestCase): - - def _get_monitor_node(self): - return MonitorNode( - name='monitor', input_buffer='_frame_', output_buffer='display') - - def _get_image(self): - image_path = 'tests/data/coco/000000000785.jpg' - image = mmcv.imread(image_path) - return image - - def test_message(self): - msg = Message() - - with self.assertWarnsRegex( - Warning, '`node_name` and `node_type` will be ' - 'overridden if node is provided.'): - node = self._get_monitor_node() - msg.update_route_info(node=node, node_name='monitor') - - route_info = msg.get_route_info() - self.assertEqual(len(route_info), 1) - self.assertEqual(route_info[0]['node'], 'monitor') - - msg.set_route_info([dict(node='recorder', node_type='RecorderNode')]) - msg.merge_route_info(route_info) - route_info = msg.get_route_info() - self.assertEqual(len(route_info), 2) - self.assertEqual(route_info[1]['node'], 'monitor') - - def test_frame_message(self): - msg = FrameMessage(None) - - # test set/get image - self.assertIsInstance(msg.data, dict) - self.assertIsNone(msg.get_image()) - - msg.set_image(self._get_image()) - self.assertIsInstance(msg.get_image(), np.ndarray) - - # test set/get objects - objects = msg.get_objects() - self.assertEqual(len(objects), 0) - - objects = [dict(label='cat'), dict(label='dog')] - msg.update_objects(objects) - dog_objects = msg.get_objects(lambda x: x['label'] == 'dog') - self.assertEqual(len(dog_objects), 1) - - msg.set_objects(objects[:1]) - dog_objects = msg.get_objects(lambda x: x['label'] == 'dog') - self.assertEqual(len(dog_objects), 0) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_utils/test_misc.py b/tests/test_apis/test_webcam/test_utils/test_misc.py deleted file mode 100644 index d60fdaa002..0000000000 --- a/tests/test_apis/test_webcam/test_utils/test_misc.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import os -import tempfile -import unittest - -import mmcv -import numpy as np - -from mmpose.apis.webcam.utils.misc import (copy_and_paste, expand_and_clamp, - get_cached_file_path, - get_config_path, is_image_file, - screen_matting) - - -class TestMISC(unittest.TestCase): - - def test_get_cached_file_path(self): - url = 'https://user-images.githubusercontent.com/15977946/' \ - '170850839-acc59e26-c6b3-48c9-a9ec-87556edb99ed.jpg' - with tempfile.TemporaryDirectory() as tmpdir: - cached_file = get_cached_file_path( - url, save_dir=tmpdir, file_name='sunglasses.jpg') - self.assertTrue(os.path.exists(cached_file)) - # check if image is successfully cached - img = mmcv.imread(cached_file) - self.assertIsNotNone(img) - - def test_get_config_path(self): - cfg_path = 'configs/_base_/datasets/coco.py' - path_in_module = get_config_path(cfg_path, 'mmpose') - self.assertEqual(cfg_path, path_in_module) - - cfg_path = '_base_/datasets/coco.py' - with self.assertRaises(FileNotFoundError): - _ = get_config_path(cfg_path, 'mmpose') - - def test_is_image_file(self): - self.assertTrue(is_image_file('example.png')) - self.assertFalse(is_image_file('example.mp4')) - - def test_expand_and_clamp(self): - img_shape = [125, 125, 3] - bbox = [0, 0, 40, 40] # [x1, y1, x2, y2] - - expanded_bbox = expand_and_clamp(bbox, img_shape) - self.assertListEqual(expanded_bbox, [0, 0, 45, 45]) - - def test_screen_matting(self): - img = np.random.randint(0, 256, size=(100, 100, 3)) - - # test with supported colors - for color in 'gbkw': - img_mat = screen_matting(img, color=color) - self.assertEqual(len(img_mat.shape), 2) - self.assertTupleEqual(img_mat.shape, img.shape[:2]) - - # test with unsupported arguments - with self.assertRaises(ValueError): - screen_matting(img) - - with self.assertRaises(NotImplementedError): - screen_matting(img, color='r') - - def test_copy_and_paste(self): - img = np.random.randint(0, 256, size=(50, 50, 3)) - background_img = np.random.randint(0, 256, size=(200, 200, 3)) - mask = screen_matting(background_img, color='b') - - output_img = copy_and_paste(img, background_img, mask) - self.assertTupleEqual(output_img.shape, background_img.shape) diff --git a/tests/test_apis/test_webcam/test_utils/test_pose.py b/tests/test_apis/test_webcam/test_utils/test_pose.py deleted file mode 100644 index 06f4fc0e41..0000000000 --- a/tests/test_apis/test_webcam/test_utils/test_pose.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest - -from mmengine import Config - -from mmpose.apis.webcam.utils.pose import (get_eye_keypoint_ids, - get_face_keypoint_ids, - get_hand_keypoint_ids, - get_mouth_keypoint_ids, - get_wrist_keypoint_ids) -from mmpose.datasets.datasets.utils import parse_pose_metainfo - - -class TestGetKeypointIds(unittest.TestCase): - - def setUp(self) -> None: - datasets_meta = dict( - coco=Config.fromfile('configs/_base_/datasets/coco.py'), - coco_wholebody=Config.fromfile( - 'configs/_base_/datasets/coco_wholebody.py'), - animalpose=Config.fromfile( - 'configs/_base_/datasets/animalpose.py'), - ap10k=Config.fromfile('configs/_base_/datasets/ap10k.py'), - wflw=Config.fromfile('configs/_base_/datasets/wflw.py'), - ) - self.datasets_meta = { - key: parse_pose_metainfo(value['dataset_info']) - for key, value in datasets_meta.items() - } - - def test_get_eye_keypoint_ids(self): - - # coco dataset - coco_dataset_meta = self.datasets_meta['coco'].copy() - left_eye_idx, right_eye_idx = get_eye_keypoint_ids(coco_dataset_meta) - self.assertEqual(left_eye_idx, 1) - self.assertEqual(right_eye_idx, 2) - - del coco_dataset_meta['keypoint_name2id']['left_eye'] - left_eye_idx, right_eye_idx = get_eye_keypoint_ids(coco_dataset_meta) - self.assertEqual(left_eye_idx, 1) - self.assertEqual(right_eye_idx, 2) - - # animalpose dataset - animalpose_dataset_meta = self.datasets_meta['animalpose'].copy() - left_eye_idx, right_eye_idx = get_eye_keypoint_ids( - animalpose_dataset_meta) - self.assertEqual(left_eye_idx, 0) - self.assertEqual(right_eye_idx, 1) - - # dataset without keys `'left_eye'` or `'right_eye'` - wflw_dataset_meta = self.datasets_meta['wflw'].copy() - with self.assertRaises(ValueError): - _ = get_eye_keypoint_ids(wflw_dataset_meta) - - def test_get_face_keypoint_ids(self): - - # coco_wholebody dataset - wholebody_dataset_meta = self.datasets_meta['coco_wholebody'].copy() - face_indices = get_face_keypoint_ids(wholebody_dataset_meta) - for i, ind in enumerate(range(23, 91)): - self.assertEqual(face_indices[i], ind) - - del wholebody_dataset_meta['keypoint_name2id']['face-0'] - face_indices = get_face_keypoint_ids(wholebody_dataset_meta) - for i, ind in enumerate(range(23, 91)): - self.assertEqual(face_indices[i], ind) - - # dataset without keys `'face-x'` - wflw_dataset_meta = self.datasets_meta['wflw'].copy() - with self.assertRaises(ValueError): - _ = get_face_keypoint_ids(wflw_dataset_meta) - - def test_get_wrist_keypoint_ids(self): - - # coco dataset - coco_dataset_meta = self.datasets_meta['coco'].copy() - left_wrist_idx, right_wrist_idx = get_wrist_keypoint_ids( - coco_dataset_meta) - self.assertEqual(left_wrist_idx, 9) - self.assertEqual(right_wrist_idx, 10) - - del coco_dataset_meta['keypoint_name2id']['left_wrist'] - left_wrist_idx, right_wrist_idx = get_wrist_keypoint_ids( - coco_dataset_meta) - self.assertEqual(left_wrist_idx, 9) - self.assertEqual(right_wrist_idx, 10) - - # animalpose dataset - animalpose_dataset_meta = self.datasets_meta['animalpose'].copy() - left_wrist_idx, right_wrist_idx = get_wrist_keypoint_ids( - animalpose_dataset_meta) - self.assertEqual(left_wrist_idx, 16) - self.assertEqual(right_wrist_idx, 17) - - # ap10k - ap10k_dataset_meta = self.datasets_meta['ap10k'].copy() - left_wrist_idx, right_wrist_idx = get_wrist_keypoint_ids( - ap10k_dataset_meta) - self.assertEqual(left_wrist_idx, 7) - self.assertEqual(right_wrist_idx, 10) - - # dataset without keys `'left_wrist'` or `'right_wrist'` - wflw_dataset_meta = self.datasets_meta['wflw'].copy() - with self.assertRaises(ValueError): - _ = get_wrist_keypoint_ids(wflw_dataset_meta) - - def test_get_mouth_keypoint_ids(self): - - # coco_wholebody dataset - wholebody_dataset_meta = self.datasets_meta['coco_wholebody'].copy() - mouth_index = get_mouth_keypoint_ids(wholebody_dataset_meta) - self.assertEqual(mouth_index, 85) - - del wholebody_dataset_meta['keypoint_name2id']['face-62'] - mouth_index = get_mouth_keypoint_ids(wholebody_dataset_meta) - self.assertEqual(mouth_index, 85) - - # dataset without keys `'face-62'` - wflw_dataset_meta = self.datasets_meta['wflw'].copy() - with self.assertRaises(ValueError): - _ = get_mouth_keypoint_ids(wflw_dataset_meta) - - def test_get_hand_keypoint_ids(self): - - # coco_wholebody dataset - wholebody_dataset_meta = self.datasets_meta['coco_wholebody'].copy() - hand_indices = get_hand_keypoint_ids(wholebody_dataset_meta) - for i, ind in enumerate(range(91, 133)): - self.assertEqual(hand_indices[i], ind) - - del wholebody_dataset_meta['keypoint_name2id']['left_hand_root'] - hand_indices = get_hand_keypoint_ids(wholebody_dataset_meta) - for i, ind in enumerate(range(91, 133)): - self.assertEqual(hand_indices[i], ind) - - # dataset without hand keys - wflw_dataset_meta = self.datasets_meta['wflw'].copy() - with self.assertRaises(ValueError): - _ = get_hand_keypoint_ids(wflw_dataset_meta) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_apis/test_webcam/test_webcam_executor.py b/tests/test_apis/test_webcam/test_webcam_executor.py deleted file mode 100644 index 0436308869..0000000000 --- a/tests/test_apis/test_webcam/test_webcam_executor.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) OpenMMLab. All rights reserved. -import unittest - -from mmengine import Config - -from mmpose.apis.webcam import WebcamExecutor - - -class TestWebcamExecutor(unittest.TestCase): - - def setUp(self) -> None: - config = Config.fromfile('demo/webcam_cfg/test_camera.py').executor_cfg - config.camera_id = 'tests/data/posetrack18/videos/' \ - '000001_mpiinew_test/000001_mpiinew_test.mp4' - self.executor = WebcamExecutor(**config) - - def test_init(self): - - self.assertEqual(len(self.executor.node_list), 2) - self.assertEqual(self.executor.node_list[0].name, 'monitor') - self.assertEqual(self.executor.node_list[1].name, 'recorder') - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_codecs/test_image_pose_lifting.py b/tests/test_codecs/test_image_pose_lifting.py new file mode 100644 index 0000000000..bb94786c32 --- /dev/null +++ b/tests/test_codecs/test_image_pose_lifting.py @@ -0,0 +1,150 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import numpy as np + +from mmpose.codecs import ImagePoseLifting +from mmpose.registry import KEYPOINT_CODECS + + +class TestImagePoseLifting(TestCase): + + def setUp(self) -> None: + keypoints = (0.1 + 0.8 * np.random.rand(1, 17, 2)) * [192, 256] + keypoints = np.round(keypoints).astype(np.float32) + keypoints_visible = np.random.randint(2, size=(1, 17)) + lifting_target = (0.1 + 0.8 * np.random.rand(17, 3)) + lifting_target_visible = np.random.randint(2, size=(17, )) + encoded_wo_sigma = np.random.rand(1, 17, 3) + + self.keypoints_mean = np.random.rand(17, 2).astype(np.float32) + self.keypoints_std = np.random.rand(17, 2).astype(np.float32) + 1e-6 + self.target_mean = np.random.rand(17, 3).astype(np.float32) + self.target_std = np.random.rand(17, 3).astype(np.float32) + 1e-6 + + self.data = dict( + keypoints=keypoints, + keypoints_visible=keypoints_visible, + lifting_target=lifting_target, + lifting_target_visible=lifting_target_visible, + encoded_wo_sigma=encoded_wo_sigma) + + def build_pose_lifting_label(self, **kwargs): + cfg = dict(type='ImagePoseLifting', num_keypoints=17, root_index=0) + cfg.update(kwargs) + return KEYPOINT_CODECS.build(cfg) + + def test_build(self): + codec = self.build_pose_lifting_label() + self.assertIsInstance(codec, ImagePoseLifting) + + def test_encode(self): + keypoints = self.data['keypoints'] + keypoints_visible = self.data['keypoints_visible'] + lifting_target = self.data['lifting_target'] + lifting_target_visible = self.data['lifting_target_visible'] + + # test default settings + codec = self.build_pose_lifting_label() + encoded = codec.encode(keypoints, keypoints_visible, lifting_target, + lifting_target_visible) + + self.assertEqual(encoded['keypoint_labels'].shape, (1, 17, 2)) + self.assertEqual(encoded['lifting_target_label'].shape, (17, 3)) + self.assertEqual(encoded['lifting_target_weights'].shape, (17, )) + self.assertEqual(encoded['trajectory_weights'].shape, (17, )) + self.assertEqual(encoded['target_root'].shape, (3, )) + + # test removing root + codec = self.build_pose_lifting_label( + remove_root=True, save_index=True) + encoded = codec.encode(keypoints, keypoints_visible, lifting_target, + lifting_target_visible) + + self.assertTrue('target_root_removed' in encoded + and 'target_root_index' in encoded) + self.assertEqual(encoded['lifting_target_weights'].shape, (16, )) + self.assertEqual(encoded['keypoint_labels'].shape, (1, 17, 2)) + self.assertEqual(encoded['lifting_target_label'].shape, (16, 3)) + self.assertEqual(encoded['target_root'].shape, (3, )) + + # test normalization + codec = self.build_pose_lifting_label( + keypoints_mean=self.keypoints_mean, + keypoints_std=self.keypoints_std, + target_mean=self.target_mean, + target_std=self.target_std) + encoded = codec.encode(keypoints, keypoints_visible, lifting_target, + lifting_target_visible) + + self.assertEqual(encoded['keypoint_labels'].shape, (1, 17, 2)) + self.assertEqual(encoded['lifting_target_label'].shape, (17, 3)) + + def test_decode(self): + lifting_target = self.data['lifting_target'] + encoded_wo_sigma = self.data['encoded_wo_sigma'] + + codec = self.build_pose_lifting_label() + + decoded, scores = codec.decode( + encoded_wo_sigma, target_root=lifting_target[..., 0, :]) + + self.assertEqual(decoded.shape, (1, 17, 3)) + self.assertEqual(scores.shape, (1, 17)) + + codec = self.build_pose_lifting_label(remove_root=True) + + decoded, scores = codec.decode( + encoded_wo_sigma, target_root=lifting_target[..., 0, :]) + + self.assertEqual(decoded.shape, (1, 18, 3)) + self.assertEqual(scores.shape, (1, 18)) + + def test_cicular_verification(self): + keypoints = self.data['keypoints'] + keypoints_visible = self.data['keypoints_visible'] + lifting_target = self.data['lifting_target'] + lifting_target_visible = self.data['lifting_target_visible'] + + # test default settings + codec = self.build_pose_lifting_label() + encoded = codec.encode(keypoints, keypoints_visible, lifting_target, + lifting_target_visible) + + _keypoints, _ = codec.decode( + np.expand_dims(encoded['lifting_target_label'], axis=0), + target_root=lifting_target[..., 0, :]) + + self.assertTrue( + np.allclose( + np.expand_dims(lifting_target, axis=0), _keypoints, atol=5.)) + + # test removing root + codec = self.build_pose_lifting_label(remove_root=True) + encoded = codec.encode(keypoints, keypoints_visible, lifting_target, + lifting_target_visible) + + _keypoints, _ = codec.decode( + np.expand_dims(encoded['lifting_target_label'], axis=0), + target_root=lifting_target[..., 0, :]) + + self.assertTrue( + np.allclose( + np.expand_dims(lifting_target, axis=0), _keypoints, atol=5.)) + + # test normalization + codec = self.build_pose_lifting_label( + keypoints_mean=self.keypoints_mean, + keypoints_std=self.keypoints_std, + target_mean=self.target_mean, + target_std=self.target_std) + encoded = codec.encode(keypoints, keypoints_visible, lifting_target, + lifting_target_visible) + + _keypoints, _ = codec.decode( + np.expand_dims(encoded['lifting_target_label'], axis=0), + target_root=lifting_target[..., 0, :]) + + self.assertTrue( + np.allclose( + np.expand_dims(lifting_target, axis=0), _keypoints, atol=5.)) diff --git a/tests/test_codecs/test_video_pose_lifting.py b/tests/test_codecs/test_video_pose_lifting.py new file mode 100644 index 0000000000..cc58292d0c --- /dev/null +++ b/tests/test_codecs/test_video_pose_lifting.py @@ -0,0 +1,156 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os.path as osp +from unittest import TestCase + +import numpy as np +from mmengine.fileio import load + +from mmpose.codecs import VideoPoseLifting +from mmpose.registry import KEYPOINT_CODECS + + +class TestVideoPoseLifting(TestCase): + + def get_camera_param(self, imgname, camera_param) -> dict: + """Get camera parameters of a frame by its image name.""" + subj, rest = osp.basename(imgname).split('_', 1) + action, rest = rest.split('.', 1) + camera, rest = rest.split('_', 1) + return camera_param[(subj, camera)] + + def build_pose_lifting_label(self, **kwargs): + cfg = dict(type='VideoPoseLifting', num_keypoints=17) + cfg.update(kwargs) + return KEYPOINT_CODECS.build(cfg) + + def setUp(self) -> None: + keypoints = (0.1 + 0.8 * np.random.rand(1, 17, 2)) * [192, 256] + keypoints = np.round(keypoints).astype(np.float32) + keypoints_visible = np.random.randint(2, size=(1, 17)) + lifting_target = (0.1 + 0.8 * np.random.rand(17, 3)) + lifting_target_visible = np.random.randint(2, size=(17, )) + encoded_wo_sigma = np.random.rand(1, 17, 3) + + camera_param = load('tests/data/h36m/cameras.pkl') + camera_param = self.get_camera_param( + 'S1/S1_Directions_1.54138969/S1_Directions_1.54138969_000001.jpg', + camera_param) + + self.data = dict( + keypoints=keypoints, + keypoints_visible=keypoints_visible, + lifting_target=lifting_target, + lifting_target_visible=lifting_target_visible, + camera_param=camera_param, + encoded_wo_sigma=encoded_wo_sigma) + + def test_build(self): + codec = self.build_pose_lifting_label() + self.assertIsInstance(codec, VideoPoseLifting) + + def test_encode(self): + keypoints = self.data['keypoints'] + keypoints_visible = self.data['keypoints_visible'] + lifting_target = self.data['lifting_target'] + lifting_target_visible = self.data['lifting_target_visible'] + camera_param = self.data['camera_param'] + + # test default settings + codec = self.build_pose_lifting_label() + encoded = codec.encode(keypoints, keypoints_visible, lifting_target, + lifting_target_visible, camera_param) + + self.assertEqual(encoded['keypoint_labels'].shape, (1, 17, 2)) + self.assertEqual(encoded['lifting_target_label'].shape, (17, 3)) + self.assertEqual(encoded['lifting_target_weights'].shape, (17, )) + self.assertEqual(encoded['trajectory_weights'].shape, (17, )) + self.assertEqual(encoded['target_root'].shape, (3, )) + + # test not zero-centering + codec = self.build_pose_lifting_label(zero_center=False) + encoded = codec.encode(keypoints, keypoints_visible, lifting_target, + lifting_target_visible, camera_param) + + self.assertEqual(encoded['keypoint_labels'].shape, (1, 17, 2)) + self.assertEqual(encoded['lifting_target_label'].shape, (17, 3)) + self.assertEqual(encoded['lifting_target_weights'].shape, (17, )) + self.assertEqual(encoded['trajectory_weights'].shape, (17, )) + + # test removing root + codec = self.build_pose_lifting_label( + remove_root=True, save_index=True) + encoded = codec.encode(keypoints, keypoints_visible, lifting_target, + lifting_target_visible, camera_param) + + self.assertTrue('target_root_removed' in encoded + and 'target_root_index' in encoded) + self.assertEqual(encoded['lifting_target_weights'].shape, (16, )) + self.assertEqual(encoded['keypoint_labels'].shape, (1, 17, 2)) + self.assertEqual(encoded['lifting_target_label'].shape, (16, 3)) + self.assertEqual(encoded['target_root'].shape, (3, )) + + # test normalizing camera + codec = self.build_pose_lifting_label(normalize_camera=True) + encoded = codec.encode(keypoints, keypoints_visible, lifting_target, + lifting_target_visible, camera_param) + + self.assertTrue('camera_param' in encoded) + scale = np.array(0.5 * camera_param['w'], dtype=np.float32) + self.assertTrue( + np.allclose( + camera_param['f'] / scale, + encoded['camera_param']['f'], + atol=4.)) + + def test_decode(self): + lifting_target = self.data['lifting_target'] + encoded_wo_sigma = self.data['encoded_wo_sigma'] + + codec = self.build_pose_lifting_label() + + decoded, scores = codec.decode( + encoded_wo_sigma, target_root=lifting_target[..., 0, :]) + + self.assertEqual(decoded.shape, (1, 17, 3)) + self.assertEqual(scores.shape, (1, 17)) + + codec = self.build_pose_lifting_label(remove_root=True) + + decoded, scores = codec.decode( + encoded_wo_sigma, target_root=lifting_target[..., 0, :]) + + self.assertEqual(decoded.shape, (1, 18, 3)) + self.assertEqual(scores.shape, (1, 18)) + + def test_cicular_verification(self): + keypoints = self.data['keypoints'] + keypoints_visible = self.data['keypoints_visible'] + lifting_target = self.data['lifting_target'] + lifting_target_visible = self.data['lifting_target_visible'] + camera_param = self.data['camera_param'] + + # test default settings + codec = self.build_pose_lifting_label() + encoded = codec.encode(keypoints, keypoints_visible, lifting_target, + lifting_target_visible, camera_param) + + _keypoints, _ = codec.decode( + np.expand_dims(encoded['lifting_target_label'], axis=0), + target_root=lifting_target[..., 0, :]) + + self.assertTrue( + np.allclose( + np.expand_dims(lifting_target, axis=0), _keypoints, atol=5.)) + + # test removing root + codec = self.build_pose_lifting_label(remove_root=True) + encoded = codec.encode(keypoints, keypoints_visible, lifting_target, + lifting_target_visible, camera_param) + + _keypoints, _ = codec.decode( + np.expand_dims(encoded['lifting_target_label'], axis=0), + target_root=lifting_target[..., 0, :]) + + self.assertTrue( + np.allclose( + np.expand_dims(lifting_target, axis=0), _keypoints, atol=5.)) diff --git a/tests/test_datasets/test_datasets/test_animal_datasets/test_animalkingdom_dataset.py b/tests/test_datasets/test_datasets/test_animal_datasets/test_animalkingdom_dataset.py new file mode 100644 index 0000000000..cc5e42ffbb --- /dev/null +++ b/tests/test_datasets/test_datasets/test_animal_datasets/test_animalkingdom_dataset.py @@ -0,0 +1,146 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import numpy as np + +from mmpose.datasets.datasets.animal import AnimalKingdomDataset + + +class TestAnimalKingdomDataset(TestCase): + + def build_ak_dataset(self, **kwargs): + + cfg = dict( + ann_file='test_animalkingdom.json', + bbox_file=None, + data_mode='topdown', + data_root='tests/data/ak', + pipeline=[], + test_mode=False) + + cfg.update(kwargs) + return AnimalKingdomDataset(**cfg) + + def check_data_info_keys(self, + data_info: dict, + data_mode: str = 'topdown'): + if data_mode == 'topdown': + expected_keys = dict( + img_id=int, + img_path=str, + bbox=np.ndarray, + bbox_score=np.ndarray, + keypoints=np.ndarray, + keypoints_visible=np.ndarray, + id=int) + elif data_mode == 'bottomup': + expected_keys = dict( + img_id=int, + img_path=str, + bbox=np.ndarray, + bbox_score=np.ndarray, + keypoints=np.ndarray, + keypoints_visible=np.ndarray, + invalid_segs=list, + id=list) + else: + raise ValueError(f'Invalid data_mode {data_mode}') + + for key, type_ in expected_keys.items(): + self.assertIn(key, data_info) + self.assertIsInstance(data_info[key], type_, key) + + def check_metainfo_keys(self, metainfo: dict): + expected_keys = dict( + dataset_name=str, + num_keypoints=int, + keypoint_id2name=dict, + keypoint_name2id=dict, + upper_body_ids=list, + lower_body_ids=list, + flip_indices=list, + flip_pairs=list, + keypoint_colors=np.ndarray, + num_skeleton_links=int, + skeleton_links=list, + skeleton_link_colors=np.ndarray, + dataset_keypoint_weights=np.ndarray) + + for key, type_ in expected_keys.items(): + self.assertIn(key, metainfo) + self.assertIsInstance(metainfo[key], type_, key) + + def test_metainfo(self): + dataset = self.build_ak_dataset() + self.check_metainfo_keys(dataset.metainfo) + # test dataset_name + self.assertEqual(dataset.metainfo['dataset_name'], 'Animal Kingdom') + + # test number of keypoints + num_keypoints = 23 + self.assertEqual(dataset.metainfo['num_keypoints'], num_keypoints) + self.assertEqual( + len(dataset.metainfo['keypoint_colors']), num_keypoints) + self.assertEqual( + len(dataset.metainfo['dataset_keypoint_weights']), num_keypoints) + # note that len(sigmas) may be zero if dataset.metainfo['sigmas'] = [] + self.assertEqual(len(dataset.metainfo['sigmas']), num_keypoints) + + # test some extra metainfo + self.assertEqual( + len(dataset.metainfo['skeleton_links']), + len(dataset.metainfo['skeleton_link_colors'])) + + def test_topdown(self): + # test topdown training + dataset = self.build_ak_dataset(data_mode='topdown') + self.assertEqual(dataset.data_mode, 'topdown') + self.assertEqual(dataset.bbox_file, None) + self.assertEqual(len(dataset), 2) + self.check_data_info_keys(dataset[0]) + + # test topdown testing + dataset = self.build_ak_dataset(data_mode='topdown', test_mode=True) + self.assertEqual(dataset.data_mode, 'topdown') + self.assertEqual(dataset.bbox_file, None) + self.assertEqual(len(dataset), 2) + self.check_data_info_keys(dataset[0]) + + def test_bottomup(self): + # test bottomup training + dataset = self.build_ak_dataset(data_mode='bottomup') + self.assertEqual(len(dataset), 2) + self.check_data_info_keys(dataset[0], data_mode='bottomup') + + # test bottomup testing + dataset = self.build_ak_dataset(data_mode='bottomup', test_mode=True) + self.assertEqual(len(dataset), 2) + self.check_data_info_keys(dataset[0], data_mode='bottomup') + + def test_exceptions_and_warnings(self): + + with self.assertRaisesRegex(ValueError, 'got invalid data_mode'): + _ = self.build_ak_dataset(data_mode='invalid') + + with self.assertRaisesRegex( + ValueError, + '"bbox_file" is only supported when `test_mode==True`'): + _ = self.build_ak_dataset( + data_mode='topdown', + test_mode=False, + bbox_file='temp_bbox_file.json') + + with self.assertRaisesRegex( + ValueError, '"bbox_file" is only supported in topdown mode'): + _ = self.build_ak_dataset( + data_mode='bottomup', + test_mode=True, + bbox_file='temp_bbox_file.json') + + with self.assertRaisesRegex( + ValueError, + '"bbox_score_thr" is only supported in topdown mode'): + _ = self.build_ak_dataset( + data_mode='bottomup', + test_mode=True, + filter_cfg=dict(bbox_score_thr=0.3)) diff --git a/tests/test_datasets/test_datasets/test_body_datasets/test_h36m_dataset.py b/tests/test_datasets/test_datasets/test_body_datasets/test_h36m_dataset.py new file mode 100644 index 0000000000..88944dc11f --- /dev/null +++ b/tests/test_datasets/test_datasets/test_body_datasets/test_h36m_dataset.py @@ -0,0 +1,175 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import numpy as np + +from mmpose.datasets.datasets.body3d import Human36mDataset + + +class TestH36MDataset(TestCase): + + def build_h36m_dataset(self, **kwargs): + + cfg = dict( + ann_file='test_h36m_body3d.npz', + data_mode='topdown', + data_root='tests/data/h36m', + pipeline=[], + test_mode=False) + + cfg.update(kwargs) + return Human36mDataset(**cfg) + + def check_data_info_keys(self, + data_info: dict, + data_mode: str = 'topdown'): + if data_mode == 'topdown': + expected_keys = dict( + img_ids=list, + img_paths=list, + keypoints=np.ndarray, + keypoints_3d=np.ndarray, + scale=np.float32, + center=np.ndarray, + id=int) + elif data_mode == 'bottomup': + expected_keys = dict( + img_ids=list, + img_paths=list, + keypoints=np.ndarray, + keypoints_3d=np.ndarray, + scale=list, + center=np.ndarray, + invalid_segs=list, + id=list) + else: + raise ValueError(f'Invalid data_mode {data_mode}') + + for key, type_ in expected_keys.items(): + self.assertIn(key, data_info) + self.assertIsInstance(data_info[key], type_, key) + + def check_metainfo_keys(self, metainfo: dict): + expected_keys = dict( + dataset_name=str, + num_keypoints=int, + keypoint_id2name=dict, + keypoint_name2id=dict, + upper_body_ids=list, + lower_body_ids=list, + flip_indices=list, + flip_pairs=list, + keypoint_colors=np.ndarray, + num_skeleton_links=int, + skeleton_links=list, + skeleton_link_colors=np.ndarray, + dataset_keypoint_weights=np.ndarray) + + for key, type_ in expected_keys.items(): + self.assertIn(key, metainfo) + self.assertIsInstance(metainfo[key], type_, key) + + def test_metainfo(self): + dataset = self.build_h36m_dataset() + self.check_metainfo_keys(dataset.metainfo) + # test dataset_name + self.assertEqual(dataset.metainfo['dataset_name'], 'h36m') + + # test number of keypoints + num_keypoints = 17 + self.assertEqual(dataset.metainfo['num_keypoints'], num_keypoints) + self.assertEqual( + len(dataset.metainfo['keypoint_colors']), num_keypoints) + self.assertEqual( + len(dataset.metainfo['dataset_keypoint_weights']), num_keypoints) + + # test some extra metainfo + self.assertEqual( + len(dataset.metainfo['skeleton_links']), + len(dataset.metainfo['skeleton_link_colors'])) + + def test_topdown(self): + # test topdown training + dataset = self.build_h36m_dataset(data_mode='topdown') + self.assertEqual(len(dataset), 4) + self.check_data_info_keys(dataset[0]) + + # test topdown testing + dataset = self.build_h36m_dataset(data_mode='topdown', test_mode=True) + self.assertEqual(len(dataset), 4) + self.check_data_info_keys(dataset[0]) + + # test topdown training with camera file + dataset = self.build_h36m_dataset( + data_mode='topdown', camera_param_file='cameras.pkl') + self.assertEqual(len(dataset), 4) + self.check_data_info_keys(dataset[0]) + + # test topdown training with sequence config + dataset = self.build_h36m_dataset( + data_mode='topdown', + seq_len=27, + seq_step=1, + causal=False, + pad_video_seq=True, + camera_param_file='cameras.pkl') + self.assertEqual(len(dataset), 4) + self.check_data_info_keys(dataset[0]) + + # test topdown testing with 2d keypoint detection file and + # sequence config + dataset = self.build_h36m_dataset( + data_mode='topdown', + seq_len=27, + seq_step=1, + causal=False, + pad_video_seq=True, + test_mode=True, + keypoint_2d_src='detection', + keypoint_2d_det_file='test_h36m_2d_detection.npy') + self.assertEqual(len(dataset), 4) + self.check_data_info_keys(dataset[0]) + + def test_bottomup(self): + # test bottomup training + dataset = self.build_h36m_dataset(data_mode='bottomup') + self.assertEqual(len(dataset), 4) + self.check_data_info_keys(dataset[0], data_mode='bottomup') + + # test bottomup training + dataset = self.build_h36m_dataset( + data_mode='bottomup', + seq_len=27, + seq_step=1, + causal=False, + pad_video_seq=True) + self.assertEqual(len(dataset), 4) + self.check_data_info_keys(dataset[0], data_mode='bottomup') + + # test bottomup testing + dataset = self.build_h36m_dataset(data_mode='bottomup', test_mode=True) + self.assertEqual(len(dataset), 4) + self.check_data_info_keys(dataset[0], data_mode='bottomup') + + def test_exceptions_and_warnings(self): + + with self.assertRaisesRegex(ValueError, 'got invalid data_mode'): + _ = self.build_h36m_dataset(data_mode='invalid') + + SUPPORTED_keypoint_2d_src = {'gt', 'detection', 'pipeline'} + with self.assertRaisesRegex( + ValueError, 'Unsupported `keypoint_2d_src` "invalid". ' + f'Supported options are {SUPPORTED_keypoint_2d_src}'): + _ = self.build_h36m_dataset( + data_mode='topdown', + test_mode=False, + keypoint_2d_src='invalid') + + with self.assertRaisesRegex(AssertionError, + 'Annotation file does not exist'): + _ = self.build_h36m_dataset( + data_mode='topdown', test_mode=False, ann_file='invalid') + + with self.assertRaisesRegex(AssertionError, + 'Unsupported `subset_frac` 2.'): + _ = self.build_h36m_dataset(data_mode='topdown', subset_frac=2) diff --git a/tests/test_datasets/test_datasets/test_body_datasets/test_humanart_dataset.py b/tests/test_datasets/test_datasets/test_body_datasets/test_humanart_dataset.py new file mode 100644 index 0000000000..dcf29ab692 --- /dev/null +++ b/tests/test_datasets/test_datasets/test_body_datasets/test_humanart_dataset.py @@ -0,0 +1,160 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import numpy as np + +from mmpose.datasets.datasets.body import HumanArtDataset + + +class TestHumanartDataset(TestCase): + + def build_humanart_dataset(self, **kwargs): + + cfg = dict( + ann_file='test_humanart.json', + bbox_file=None, + data_mode='topdown', + data_root='tests/data/humanart', + pipeline=[], + test_mode=False) + + cfg.update(kwargs) + return HumanArtDataset(**cfg) + + def check_data_info_keys(self, + data_info: dict, + data_mode: str = 'topdown'): + if data_mode == 'topdown': + expected_keys = dict( + img_id=int, + img_path=str, + bbox=np.ndarray, + bbox_score=np.ndarray, + keypoints=np.ndarray, + keypoints_visible=np.ndarray, + id=int) + elif data_mode == 'bottomup': + expected_keys = dict( + img_id=int, + img_path=str, + bbox=np.ndarray, + bbox_score=np.ndarray, + keypoints=np.ndarray, + keypoints_visible=np.ndarray, + invalid_segs=list, + id=list) + else: + raise ValueError(f'Invalid data_mode {data_mode}') + + for key, type_ in expected_keys.items(): + self.assertIn(key, data_info) + self.assertIsInstance(data_info[key], type_, key) + + def check_metainfo_keys(self, metainfo: dict): + expected_keys = dict( + dataset_name=str, + num_keypoints=int, + keypoint_id2name=dict, + keypoint_name2id=dict, + upper_body_ids=list, + lower_body_ids=list, + flip_indices=list, + flip_pairs=list, + keypoint_colors=np.ndarray, + num_skeleton_links=int, + skeleton_links=list, + skeleton_link_colors=np.ndarray, + dataset_keypoint_weights=np.ndarray) + + for key, type_ in expected_keys.items(): + self.assertIn(key, metainfo) + self.assertIsInstance(metainfo[key], type_, key) + + def test_metainfo(self): + dataset = self.build_humanart_dataset() + self.check_metainfo_keys(dataset.metainfo) + # test dataset_name + self.assertEqual(dataset.metainfo['dataset_name'], 'Human-Art') + + # test number of keypoints + num_keypoints = 17 + self.assertEqual(dataset.metainfo['num_keypoints'], num_keypoints) + self.assertEqual( + len(dataset.metainfo['keypoint_colors']), num_keypoints) + self.assertEqual( + len(dataset.metainfo['dataset_keypoint_weights']), num_keypoints) + # note that len(sigmas) may be zero if dataset.metainfo['sigmas'] = [] + self.assertEqual(len(dataset.metainfo['sigmas']), num_keypoints) + + # test some extra metainfo + self.assertEqual( + len(dataset.metainfo['skeleton_links']), + len(dataset.metainfo['skeleton_link_colors'])) + + def test_topdown(self): + # test topdown training + dataset = self.build_humanart_dataset(data_mode='topdown') + self.assertEqual(len(dataset), 4) + self.check_data_info_keys(dataset[0], data_mode='topdown') + + # test topdown testing + dataset = self.build_humanart_dataset( + data_mode='topdown', test_mode=True) + self.assertEqual(len(dataset), 4) + self.check_data_info_keys(dataset[0], data_mode='topdown') + + # test topdown testing with bbox file + dataset = self.build_humanart_dataset( + data_mode='topdown', + test_mode=True, + bbox_file='tests/data/humanart/test_humanart_det_AP_H_56.json') + self.assertEqual(len(dataset), 13) + self.check_data_info_keys(dataset[0], data_mode='topdown') + + # test topdown testing with filter config + dataset = self.build_humanart_dataset( + data_mode='topdown', + test_mode=True, + bbox_file='tests/data/humanart/test_humanart_det_AP_H_56.json', + filter_cfg=dict(bbox_score_thr=0.3)) + self.assertEqual(len(dataset), 8) + + def test_bottomup(self): + # test bottomup training + dataset = self.build_humanart_dataset(data_mode='bottomup') + self.assertEqual(len(dataset), 3) + self.check_data_info_keys(dataset[0], data_mode='bottomup') + + # test bottomup testing + dataset = self.build_humanart_dataset( + data_mode='bottomup', test_mode=True) + self.assertEqual(len(dataset), 3) + self.check_data_info_keys(dataset[0], data_mode='bottomup') + + def test_exceptions_and_warnings(self): + + with self.assertRaisesRegex(ValueError, 'got invalid data_mode'): + _ = self.build_humanart_dataset(data_mode='invalid') + + with self.assertRaisesRegex( + ValueError, + '"bbox_file" is only supported when `test_mode==True`'): + _ = self.build_humanart_dataset( + data_mode='topdown', + test_mode=False, + bbox_file='tests/data/humanart/test_humanart_det_AP_H_56.json') + + with self.assertRaisesRegex( + ValueError, '"bbox_file" is only supported in topdown mode'): + _ = self.build_humanart_dataset( + data_mode='bottomup', + test_mode=True, + bbox_file='tests/data/humanart/test_humanart_det_AP_H_56.json') + + with self.assertRaisesRegex( + ValueError, + '"bbox_score_thr" is only supported in topdown mode'): + _ = self.build_humanart_dataset( + data_mode='bottomup', + test_mode=True, + filter_cfg=dict(bbox_score_thr=0.3)) diff --git a/tests/test_datasets/test_datasets/test_face_datasets/test_lapa_dataset.py b/tests/test_datasets/test_datasets/test_face_datasets/test_lapa_dataset.py new file mode 100644 index 0000000000..991f285476 --- /dev/null +++ b/tests/test_datasets/test_datasets/test_face_datasets/test_lapa_dataset.py @@ -0,0 +1,93 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import numpy as np + +from mmpose.datasets.datasets.face import LapaDataset + + +class TestLaPaDataset(TestCase): + + def build_lapa_dataset(self, **kwargs): + + cfg = dict( + ann_file='test_lapa.json', + bbox_file=None, + data_mode='topdown', + data_root='tests/data/lapa', + pipeline=[], + test_mode=False) + + cfg.update(kwargs) + return LapaDataset(**cfg) + + def check_data_info_keys(self, + data_info: dict, + data_mode: str = 'topdown'): + if data_mode == 'topdown': + expected_keys = dict( + img_id=int, + img_path=str, + bbox=np.ndarray, + bbox_score=np.ndarray, + keypoints=np.ndarray, + keypoints_visible=np.ndarray, + id=int) + else: + raise ValueError(f'Invalid data_mode {data_mode}') + + for key, type_ in expected_keys.items(): + self.assertIn(key, data_info) + self.assertIsInstance(data_info[key], type_, key) + + def check_metainfo_keys(self, metainfo: dict): + expected_keys = dict( + dataset_name=str, + num_keypoints=int, + keypoint_id2name=dict, + keypoint_name2id=dict, + upper_body_ids=list, + lower_body_ids=list, + flip_indices=list, + flip_pairs=list, + keypoint_colors=np.ndarray, + num_skeleton_links=int, + skeleton_links=list, + skeleton_link_colors=np.ndarray, + dataset_keypoint_weights=np.ndarray) + + for key, type_ in expected_keys.items(): + self.assertIn(key, metainfo) + self.assertIsInstance(metainfo[key], type_, key) + + def test_metainfo(self): + dataset = self.build_lapa_dataset() + self.check_metainfo_keys(dataset.metainfo) + # test dataset_name + self.assertEqual(dataset.metainfo['dataset_name'], 'lapa') + + # test number of keypoints + num_keypoints = 106 + self.assertEqual(dataset.metainfo['num_keypoints'], num_keypoints) + self.assertEqual( + len(dataset.metainfo['keypoint_colors']), num_keypoints) + self.assertEqual( + len(dataset.metainfo['dataset_keypoint_weights']), num_keypoints) + # note that len(sigmas) may be zero if dataset.metainfo['sigmas'] = [] + self.assertEqual(len(dataset.metainfo['sigmas']), 0) + + def test_topdown(self): + # test topdown training + dataset = self.build_lapa_dataset(data_mode='topdown') + self.assertEqual(dataset.data_mode, 'topdown') + self.assertEqual(dataset.bbox_file, None) + # filter invalid insances due to face_valid = false + self.assertEqual(len(dataset), 2) + self.check_data_info_keys(dataset[0]) + + # test topdown testing + dataset = self.build_lapa_dataset(data_mode='topdown', test_mode=True) + self.assertEqual(dataset.data_mode, 'topdown') + self.assertEqual(dataset.bbox_file, None) + self.assertEqual(len(dataset), 2) + self.check_data_info_keys(dataset[0]) diff --git a/tests/test_datasets/test_transforms/test_converting.py b/tests/test_datasets/test_transforms/test_converting.py index f345a44063..09f06e1e65 100644 --- a/tests/test_datasets/test_transforms/test_converting.py +++ b/tests/test_datasets/test_transforms/test_converting.py @@ -13,6 +13,7 @@ def setUp(self): img_shape=(240, 320), num_instances=4, with_bbox_cs=True) def test_transform(self): + # 1-to-1 mapping mapping = [(3, 0), (6, 1), (16, 2), (5, 3)] transform = KeypointConverter(num_keypoints=5, mapping=mapping) results = transform(self.data_info.copy()) @@ -34,3 +35,39 @@ def test_transform(self): self.assertTrue( (results['keypoints_visible'][:, target_index] == self.data_info['keypoints_visible'][:, source_index]).all()) + + # 2-to-1 mapping + mapping = [((3, 5), 0), (6, 1), (16, 2), (5, 3)] + transform = KeypointConverter(num_keypoints=5, mapping=mapping) + results = transform(self.data_info.copy()) + + # check shape + self.assertEqual(results['keypoints'].shape[0], + self.data_info['keypoints'].shape[0]) + self.assertEqual(results['keypoints'].shape[1], 5) + self.assertEqual(results['keypoints'].shape[2], 2) + self.assertEqual(results['keypoints_visible'].shape[0], + self.data_info['keypoints_visible'].shape[0]) + self.assertEqual(results['keypoints_visible'].shape[1], 5) + + # check value + for source_index, target_index in mapping: + if isinstance(source_index, tuple): + source_index, source_index2 = source_index + self.assertTrue( + (results['keypoints'][:, target_index] == 0.5 * + (self.data_info['keypoints'][:, source_index] + + self.data_info['keypoints'][:, source_index2])).all()) + self.assertTrue( + (results['keypoints_visible'][:, target_index] == + self.data_info['keypoints_visible'][:, source_index] * + self.data_info['keypoints_visible'][:, + source_index2]).all()) + else: + self.assertTrue( + (results['keypoints'][:, target_index] == + self.data_info['keypoints'][:, source_index]).all()) + self.assertTrue( + (results['keypoints_visible'][:, target_index] == + self.data_info['keypoints_visible'][:, + source_index]).all()) diff --git a/tests/test_datasets/test_transforms/test_pose3d_transforms.py b/tests/test_datasets/test_transforms/test_pose3d_transforms.py new file mode 100644 index 0000000000..5f5d5aa096 --- /dev/null +++ b/tests/test_datasets/test_transforms/test_pose3d_transforms.py @@ -0,0 +1,150 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import os.path as osp +from copy import deepcopy +from unittest import TestCase + +import numpy as np +from mmengine.fileio import load + +from mmpose.datasets.transforms import RandomFlipAroundRoot + + +def get_h36m_sample(): + + def _parse_h36m_imgname(imgname): + """Parse imgname to get information of subject, action and camera. + + A typical h36m image filename is like: + S1_Directions_1.54138969_000001.jpg + """ + subj, rest = osp.basename(imgname).split('_', 1) + action, rest = rest.split('.', 1) + camera, rest = rest.split('_', 1) + return subj, action, camera + + ann_flle = 'tests/data/h36m/test_h36m_body3d.npz' + camera_param_file = 'tests/data/h36m/cameras.pkl' + + data = np.load(ann_flle) + cameras = load(camera_param_file) + + imgnames = data['imgname'] + keypoints = data['part'].astype(np.float32) + keypoints_3d = data['S'].astype(np.float32) + centers = data['center'].astype(np.float32) + scales = data['scale'].astype(np.float32) + + idx = 0 + target_idx = 0 + + data_info = { + 'keypoints': keypoints[idx, :, :2].reshape(1, -1, 2), + 'keypoints_visible': keypoints[idx, :, 2].reshape(1, -1), + 'keypoints_3d': keypoints_3d[idx, :, :3].reshape(1, -1, 3), + 'keypoints_3d_visible': keypoints_3d[idx, :, 3].reshape(1, -1), + 'scale': scales[idx], + 'center': centers[idx].astype(np.float32).reshape(1, -1), + 'id': idx, + 'img_ids': [idx], + 'img_paths': [imgnames[idx]], + 'category_id': 1, + 'iscrowd': 0, + 'sample_idx': idx, + 'lifting_target': keypoints_3d[target_idx, :, :3], + 'lifting_target_visible': keypoints_3d[target_idx, :, 3], + 'target_img_path': osp.join('tests/data/h36m', imgnames[target_idx]), + } + + # add camera parameters + subj, _, camera = _parse_h36m_imgname(imgnames[idx]) + data_info['camera_param'] = cameras[(subj, camera)] + + # add ann_info + ann_info = {} + ann_info['num_keypoints'] = 17 + ann_info['dataset_keypoint_weights'] = np.full(17, 1.0, dtype=np.float32) + ann_info['flip_pairs'] = [[1, 4], [2, 5], [3, 6], [11, 14], [12, 15], + [13, 16]] + ann_info['skeleton_links'] = [] + ann_info['upper_body_ids'] = (0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) + ann_info['lower_body_ids'] = (1, 2, 3, 4, 5, 6) + ann_info['flip_indices'] = [ + 0, 4, 5, 6, 1, 2, 3, 7, 8, 9, 10, 14, 15, 16, 11, 12, 13 + ] + + data_info.update(ann_info) + + return data_info + + +class TestRandomFlipAroundRoot(TestCase): + + def setUp(self): + self.data_info = get_h36m_sample() + self.keypoints_flip_cfg = dict(center_mode='static', center_x=0.) + self.target_flip_cfg = dict(center_mode='root', center_index=0) + + def test_init(self): + _ = RandomFlipAroundRoot( + self.keypoints_flip_cfg, + self.target_flip_cfg, + flip_prob=0.5, + flip_camera=False) + + def test_transform(self): + kpts1 = self.data_info['keypoints'] + kpts_vis1 = self.data_info['keypoints_visible'] + tar1 = self.data_info['lifting_target'] + tar_vis1 = self.data_info['lifting_target_visible'] + + transform = RandomFlipAroundRoot( + self.keypoints_flip_cfg, self.target_flip_cfg, flip_prob=1) + results = deepcopy(self.data_info) + results = transform(results) + + kpts2 = results['keypoints'] + kpts_vis2 = results['keypoints_visible'] + tar2 = results['lifting_target'] + tar_vis2 = results['lifting_target_visible'] + + self.assertEqual(kpts_vis2.shape, (1, 17)) + self.assertEqual(tar_vis2.shape, (17, )) + self.assertEqual(kpts2.shape, (1, 17, 2)) + self.assertEqual(tar2.shape, (17, 3)) + + flip_indices = [ + 0, 4, 5, 6, 1, 2, 3, 7, 8, 9, 10, 14, 15, 16, 11, 12, 13 + ] + for left, right in enumerate(flip_indices): + self.assertTrue( + np.allclose(-kpts1[0][left][:1], kpts2[0][right][:1], atol=4.)) + self.assertTrue( + np.allclose(kpts1[0][left][1:], kpts2[0][right][1:], atol=4.)) + self.assertTrue( + np.allclose(tar1[left][1:], tar2[right][1:], atol=4.)) + + self.assertTrue( + np.allclose(kpts_vis1[0][left], kpts_vis2[0][right], atol=4.)) + self.assertTrue( + np.allclose(tar_vis1[left], tar_vis2[right], atol=4.)) + + # test camera flipping + transform = RandomFlipAroundRoot( + self.keypoints_flip_cfg, + self.target_flip_cfg, + flip_prob=1, + flip_camera=True) + results = deepcopy(self.data_info) + results = transform(results) + + camera2 = results['camera_param'] + self.assertTrue( + np.allclose( + -self.data_info['camera_param']['c'][0], + camera2['c'][0], + atol=4.)) + self.assertTrue( + np.allclose( + -self.data_info['camera_param']['p'][0], + camera2['p'][0], + atol=4.)) diff --git a/tests/test_evaluation/test_functional/test_keypoint_eval.py b/tests/test_evaluation/test_functional/test_keypoint_eval.py index 2234c8e547..47ede83921 100644 --- a/tests/test_evaluation/test_functional/test_keypoint_eval.py +++ b/tests/test_evaluation/test_functional/test_keypoint_eval.py @@ -1,163 +1,212 @@ # Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + import numpy as np from numpy.testing import assert_array_almost_equal from mmpose.evaluation.functional import (keypoint_auc, keypoint_epe, - keypoint_nme, keypoint_pck_accuracy, + keypoint_mpjpe, keypoint_nme, + keypoint_pck_accuracy, multilabel_classification_accuracy, pose_pck_accuracy) -def test_keypoint_pck_accuracy(): - output = np.zeros((2, 5, 2)) - target = np.zeros((2, 5, 2)) - mask = np.array([[True, True, False, True, True], - [True, True, False, True, True]]) - thr = np.full((2, 2), 10, dtype=np.float32) - # first channel - output[0, 0] = [10, 0] - target[0, 0] = [10, 0] - # second channel - output[0, 1] = [20, 20] - target[0, 1] = [10, 10] - # third channel - output[0, 2] = [0, 0] - target[0, 2] = [-1, 0] - # fourth channel - output[0, 3] = [30, 30] - target[0, 3] = [30, 30] - # fifth channel - output[0, 4] = [0, 10] - target[0, 4] = [0, 10] - - acc, avg_acc, cnt = keypoint_pck_accuracy(output, target, mask, 0.5, thr) - - assert_array_almost_equal(acc, np.array([1, 0.5, -1, 1, 1]), decimal=4) - assert abs(avg_acc - 0.875) < 1e-4 - assert abs(cnt - 4) < 1e-4 - - acc, avg_acc, cnt = keypoint_pck_accuracy(output, target, mask, 0.5, - np.zeros((2, 2))) - assert_array_almost_equal(acc, np.array([-1, -1, -1, -1, -1]), decimal=4) - assert abs(avg_acc) < 1e-4 - assert abs(cnt) < 1e-4 - - acc, avg_acc, cnt = keypoint_pck_accuracy(output, target, mask, 0.5, - np.array([[0, 0], [10, 10]])) - assert_array_almost_equal(acc, np.array([1, 1, -1, 1, 1]), decimal=4) - assert abs(avg_acc - 1) < 1e-4 - assert abs(cnt - 4) < 1e-4 - - -def test_keypoint_auc(): - output = np.zeros((1, 5, 2)) - target = np.zeros((1, 5, 2)) - mask = np.array([[True, True, False, True, True]]) - # first channel - output[0, 0] = [10, 4] - target[0, 0] = [10, 0] - # second channel - output[0, 1] = [10, 18] - target[0, 1] = [10, 10] - # third channel - output[0, 2] = [0, 0] - target[0, 2] = [0, -1] - # fourth channel - output[0, 3] = [40, 40] - target[0, 3] = [30, 30] - # fifth channel - output[0, 4] = [20, 10] - target[0, 4] = [0, 10] - - auc = keypoint_auc(output, target, mask, 20, 4) - assert abs(auc - 0.375) < 1e-4 - - -def test_keypoint_epe(): - output = np.zeros((1, 5, 2)) - target = np.zeros((1, 5, 2)) - mask = np.array([[True, True, False, True, True]]) - # first channel - output[0, 0] = [10, 4] - target[0, 0] = [10, 0] - # second channel - output[0, 1] = [10, 18] - target[0, 1] = [10, 10] - # third channel - output[0, 2] = [0, 0] - target[0, 2] = [-1, -1] - # fourth channel - output[0, 3] = [40, 40] - target[0, 3] = [30, 30] - # fifth channel - output[0, 4] = [20, 10] - target[0, 4] = [0, 10] - - epe = keypoint_epe(output, target, mask) - assert abs(epe - 11.5355339) < 1e-4 - - -def test_keypoint_nme(): - output = np.zeros((1, 5, 2)) - target = np.zeros((1, 5, 2)) - mask = np.array([[True, True, False, True, True]]) - # first channel - output[0, 0] = [10, 4] - target[0, 0] = [10, 0] - # second channel - output[0, 1] = [10, 18] - target[0, 1] = [10, 10] - # third channel - output[0, 2] = [0, 0] - target[0, 2] = [-1, -1] - # fourth channel - output[0, 3] = [40, 40] - target[0, 3] = [30, 30] - # fifth channel - output[0, 4] = [20, 10] - target[0, 4] = [0, 10] - - normalize_factor = np.ones((output.shape[0], output.shape[2])) - - nme = keypoint_nme(output, target, mask, normalize_factor) - assert abs(nme - 11.5355339) < 1e-4 - - -def test_pose_pck_accuracy(): - output = np.zeros((1, 5, 64, 64), dtype=np.float32) - target = np.zeros((1, 5, 64, 64), dtype=np.float32) - mask = np.array([[True, True, False, False, False]]) - # first channel - output[0, 0, 20, 20] = 1 - target[0, 0, 10, 10] = 1 - # second channel - output[0, 1, 30, 30] = 1 - target[0, 1, 30, 30] = 1 - - acc, avg_acc, cnt = pose_pck_accuracy(output, target, mask) - - assert_array_almost_equal(acc, np.array([0, 1, -1, -1, -1]), decimal=4) - assert abs(avg_acc - 0.5) < 1e-4 - assert abs(cnt - 2) < 1e-4 - - -def test_multilabel_classification_accuracy(): - output = np.array([[0.7, 0.8, 0.4], [0.8, 0.1, 0.1]]) - target = np.array([[1, 0, 0], [1, 0, 1]]) - mask = np.array([[True, True, True], [True, True, True]]) - thr = 0.5 - acc = multilabel_classification_accuracy(output, target, mask, thr) - assert acc == 0 - - output = np.array([[0.7, 0.2, 0.4], [0.8, 0.1, 0.9]]) - thr = 0.5 - acc = multilabel_classification_accuracy(output, target, mask, thr) - assert acc == 1 - - thr = 0.3 - acc = multilabel_classification_accuracy(output, target, mask, thr) - assert acc == 0.5 - - mask = np.array([[True, True, False], [True, True, True]]) - acc = multilabel_classification_accuracy(output, target, mask, thr) - assert acc == 1 +class TestKeypointEval(TestCase): + + def test_keypoint_pck_accuracy(self): + + output = np.zeros((2, 5, 2)) + target = np.zeros((2, 5, 2)) + mask = np.array([[True, True, False, True, True], + [True, True, False, True, True]]) + + # first channel + output[0, 0] = [10, 0] + target[0, 0] = [10, 0] + # second channel + output[0, 1] = [20, 20] + target[0, 1] = [10, 10] + # third channel + output[0, 2] = [0, 0] + target[0, 2] = [-1, 0] + # fourth channel + output[0, 3] = [30, 30] + target[0, 3] = [30, 30] + # fifth channel + output[0, 4] = [0, 10] + target[0, 4] = [0, 10] + + thr = np.full((2, 2), 10, dtype=np.float32) + + acc, avg_acc, cnt = keypoint_pck_accuracy(output, target, mask, 0.5, + thr) + + assert_array_almost_equal(acc, np.array([1, 0.5, -1, 1, 1]), decimal=4) + self.assertAlmostEqual(avg_acc, 0.875, delta=1e-4) + self.assertAlmostEqual(cnt, 4, delta=1e-4) + + acc, avg_acc, cnt = keypoint_pck_accuracy(output, target, mask, 0.5, + np.zeros((2, 2))) + assert_array_almost_equal( + acc, np.array([-1, -1, -1, -1, -1]), decimal=4) + self.assertAlmostEqual(avg_acc, 0, delta=1e-4) + self.assertAlmostEqual(cnt, 0, delta=1e-4) + + acc, avg_acc, cnt = keypoint_pck_accuracy(output, target, mask, 0.5, + np.array([[0, 0], [10, 10]])) + assert_array_almost_equal(acc, np.array([1, 1, -1, 1, 1]), decimal=4) + self.assertAlmostEqual(avg_acc, 1, delta=1e-4) + self.assertAlmostEqual(cnt, 4, delta=1e-4) + + def test_keypoint_auc(self): + output = np.zeros((1, 5, 2)) + target = np.zeros((1, 5, 2)) + mask = np.array([[True, True, False, True, True]]) + # first channel + output[0, 0] = [10, 4] + target[0, 0] = [10, 0] + # second channel + output[0, 1] = [10, 18] + target[0, 1] = [10, 10] + # third channel + output[0, 2] = [0, 0] + target[0, 2] = [0, -1] + # fourth channel + output[0, 3] = [40, 40] + target[0, 3] = [30, 30] + # fifth channel + output[0, 4] = [20, 10] + target[0, 4] = [0, 10] + + auc = keypoint_auc(output, target, mask, 20, 4) + self.assertAlmostEqual(auc, 0.375, delta=1e-4) + + def test_keypoint_epe(self): + output = np.zeros((1, 5, 2)) + target = np.zeros((1, 5, 2)) + mask = np.array([[True, True, False, True, True]]) + # first channel + output[0, 0] = [10, 4] + target[0, 0] = [10, 0] + # second channel + output[0, 1] = [10, 18] + target[0, 1] = [10, 10] + # third channel + output[0, 2] = [0, 0] + target[0, 2] = [-1, -1] + # fourth channel + output[0, 3] = [40, 40] + target[0, 3] = [30, 30] + # fifth channel + output[0, 4] = [20, 10] + target[0, 4] = [0, 10] + + epe = keypoint_epe(output, target, mask) + self.assertAlmostEqual(epe, 11.5355339, delta=1e-4) + + def test_keypoint_nme(self): + output = np.zeros((1, 5, 2)) + target = np.zeros((1, 5, 2)) + mask = np.array([[True, True, False, True, True]]) + # first channel + output[0, 0] = [10, 4] + target[0, 0] = [10, 0] + # second channel + output[0, 1] = [10, 18] + target[0, 1] = [10, 10] + # third channel + output[0, 2] = [0, 0] + target[0, 2] = [-1, -1] + # fourth channel + output[0, 3] = [40, 40] + target[0, 3] = [30, 30] + # fifth channel + output[0, 4] = [20, 10] + target[0, 4] = [0, 10] + + normalize_factor = np.ones((output.shape[0], output.shape[2])) + + nme = keypoint_nme(output, target, mask, normalize_factor) + self.assertAlmostEqual(nme, 11.5355339, delta=1e-4) + + def test_pose_pck_accuracy(self): + output = np.zeros((1, 5, 64, 64), dtype=np.float32) + target = np.zeros((1, 5, 64, 64), dtype=np.float32) + mask = np.array([[True, True, False, False, False]]) + # first channel + output[0, 0, 20, 20] = 1 + target[0, 0, 10, 10] = 1 + # second channel + output[0, 1, 30, 30] = 1 + target[0, 1, 30, 30] = 1 + + acc, avg_acc, cnt = pose_pck_accuracy(output, target, mask) + + assert_array_almost_equal(acc, np.array([0, 1, -1, -1, -1]), decimal=4) + self.assertAlmostEqual(avg_acc, 0.5, delta=1e-4) + self.assertAlmostEqual(cnt, 2, delta=1e-4) + + def test_multilabel_classification_accuracy(self): + output = np.array([[0.7, 0.8, 0.4], [0.8, 0.1, 0.1]]) + target = np.array([[1, 0, 0], [1, 0, 1]]) + mask = np.array([[True, True, True], [True, True, True]]) + thr = 0.5 + acc = multilabel_classification_accuracy(output, target, mask, thr) + self.assertEqual(acc, 0) + + output = np.array([[0.7, 0.2, 0.4], [0.8, 0.1, 0.9]]) + thr = 0.5 + acc = multilabel_classification_accuracy(output, target, mask, thr) + self.assertEqual(acc, 1) + + thr = 0.3 + acc = multilabel_classification_accuracy(output, target, mask, thr) + self.assertEqual(acc, 0.5) + + mask = np.array([[True, True, False], [True, True, True]]) + acc = multilabel_classification_accuracy(output, target, mask, thr) + self.assertEqual(acc, 1) + + def test_keypoint_mpjpe(self): + output = np.zeros((2, 5, 3)) + target = np.zeros((2, 5, 3)) + mask = np.array([[True, True, False, True, True], + [True, True, False, True, True]]) + + # first channel + output[0, 0] = [1, 0, 0] + target[0, 0] = [1, 0, 0] + output[1, 0] = [1, 0, 0] + target[1, 0] = [1, 1, 0] + # second channel + output[0, 1] = [2, 2, 0] + target[0, 1] = [1, 1, 1] + output[1, 1] = [2, 2, 1] + target[1, 1] = [1, 0, 1] + # third channel + output[0, 2] = [0, 0, -1] + target[0, 2] = [-1, 0, 0] + output[1, 2] = [-1, 0, 0] + target[1, 2] = [-1, 0, 0] + # fourth channel + output[0, 3] = [3, 3, 1] + target[0, 3] = [3, 3, 1] + output[1, 3] = [0, 0, 3] + target[1, 3] = [0, 0, 3] + # fifth channel + output[0, 4] = [0, 1, 1] + target[0, 4] = [0, 1, 0] + output[1, 4] = [0, 0, 1] + target[1, 4] = [1, 1, 0] + + mpjpe = keypoint_mpjpe(output, target, mask) + self.assertAlmostEqual(mpjpe, 0.9625211990796929, delta=1e-4) + + p_mpjpe = keypoint_mpjpe(output, target, mask, 'procrustes') + self.assertAlmostEqual(p_mpjpe, 1.0047897634604497, delta=1e-4) + + s_mpjpe = keypoint_mpjpe(output, target, mask, 'scale') + self.assertAlmostEqual(s_mpjpe, 1.0277129678465953, delta=1e-4) + + with self.assertRaises(ValueError): + _ = keypoint_mpjpe(output, target, mask, 'alignment') diff --git a/tests/test_evaluation/test_metrics/test_keypoint_3d_metrics.py b/tests/test_evaluation/test_metrics/test_keypoint_3d_metrics.py new file mode 100644 index 0000000000..8289b09d0f --- /dev/null +++ b/tests/test_evaluation/test_metrics/test_keypoint_3d_metrics.py @@ -0,0 +1,70 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import numpy as np +from mmengine.structures import InstanceData + +from mmpose.evaluation import MPJPE +from mmpose.structures import PoseDataSample + + +class TestMPJPE(TestCase): + + def setUp(self): + """Setup variables used in every test method.""" + self.batch_size = 8 + num_keypoints = 15 + self.data_batch = [] + self.data_samples = [] + + for i in range(self.batch_size): + gt_instances = InstanceData() + keypoints = np.random.random((1, num_keypoints, 3)) + gt_instances.lifting_target = np.random.random((num_keypoints, 3)) + gt_instances.lifting_target_visible = np.ones( + (num_keypoints, 1)).astype(bool) + + pred_instances = InstanceData() + pred_instances.keypoints = keypoints + np.random.normal( + 0, 0.01, keypoints.shape) + + data = {'inputs': None} + data_sample = PoseDataSample( + gt_instances=gt_instances, pred_instances=pred_instances) + data_sample.set_metainfo( + dict(target_img_path='tests/data/h36m/S7/' + 'S7_Greeting.55011271/S7_Greeting.55011271_000396.jpg')) + + self.data_batch.append(data) + self.data_samples.append(data_sample.to_dict()) + + def test_init(self): + """Test metric init method.""" + # Test invalid mode + with self.assertRaisesRegex( + KeyError, "`mode` should be 'mpjpe', 'p-mpjpe', or 'n-mpjpe', " + "but got 'invalid'."): + MPJPE(mode='invalid') + + def test_evaluate(self): + """Test MPJPE evaluation metric.""" + mpjpe_metric = MPJPE(mode='mpjpe') + mpjpe_metric.process(self.data_batch, self.data_samples) + mpjpe = mpjpe_metric.evaluate(self.batch_size) + self.assertIsInstance(mpjpe, dict) + self.assertIn('MPJPE', mpjpe) + self.assertTrue(mpjpe['MPJPE'] >= 0) + + p_mpjpe_metric = MPJPE(mode='p-mpjpe') + p_mpjpe_metric.process(self.data_batch, self.data_samples) + p_mpjpe = p_mpjpe_metric.evaluate(self.batch_size) + self.assertIsInstance(p_mpjpe, dict) + self.assertIn('P-MPJPE', p_mpjpe) + self.assertTrue(p_mpjpe['P-MPJPE'] >= 0) + + n_mpjpe_metric = MPJPE(mode='n-mpjpe') + n_mpjpe_metric.process(self.data_batch, self.data_samples) + n_mpjpe = n_mpjpe_metric.evaluate(self.batch_size) + self.assertIsInstance(n_mpjpe, dict) + self.assertIn('N-MPJPE', n_mpjpe) + self.assertTrue(n_mpjpe['N-MPJPE'] >= 0) diff --git a/tests/test_models/test_heads/test_hybrid_heads/test_vis_head.py b/tests/test_models/test_heads/test_hybrid_heads/test_vis_head.py new file mode 100644 index 0000000000..a6aecc2852 --- /dev/null +++ b/tests/test_models/test_heads/test_hybrid_heads/test_vis_head.py @@ -0,0 +1,190 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import unittest +from typing import List, Tuple +from unittest import TestCase + +import torch +from mmengine.structures import InstanceData, PixelData +from torch import nn + +from mmpose.models.heads import VisPredictHead +from mmpose.testing import get_packed_inputs + + +class TestVisPredictHead(TestCase): + + def _get_feats( + self, + batch_size: int = 2, + feat_shapes: List[Tuple[int, int, int]] = [(32, 8, 6)], + ): + feats = [ + torch.rand((batch_size, ) + shape, dtype=torch.float32) + for shape in feat_shapes + ] + return feats + + def test_init(self): + codec = dict( + type='MSRAHeatmap', + input_size=(192, 256), + heatmap_size=(48, 64), + sigma=2.) + + head = VisPredictHead( + pose_cfg=dict( + type='HeatmapHead', + in_channels=32, + out_channels=17, + deconv_out_channels=None, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec)) + + self.assertTrue(isinstance(head.vis_head, nn.Sequential)) + self.assertEqual(head.vis_head[2].weight.shape, (17, 32)) + self.assertIsNotNone(head.pose_head) + + def test_forward(self): + + codec = dict( + type='MSRAHeatmap', + input_size=(192, 256), + heatmap_size=(48, 64), + sigma=2) + + head = VisPredictHead( + pose_cfg=dict( + type='HeatmapHead', + in_channels=32, + out_channels=17, + deconv_out_channels=None, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec)) + + feats = [torch.rand(1, 32, 128, 128)] + output_pose, output_vis = head.forward(feats) + + self.assertIsInstance(output_pose, torch.Tensor) + self.assertEqual(output_pose.shape, (1, 17, 128, 128)) + + self.assertIsInstance(output_vis, torch.Tensor) + self.assertEqual(output_vis.shape, (1, 17)) + + def test_predict(self): + + codec = dict( + type='MSRAHeatmap', + input_size=(192, 256), + heatmap_size=(48, 64), + sigma=2.) + + head = VisPredictHead( + pose_cfg=dict( + type='HeatmapHead', + in_channels=32, + out_channels=17, + deconv_out_channels=None, + loss=dict(type='KeypointMSELoss', use_target_weight=True), + decoder=codec)) + + feats = self._get_feats(batch_size=2, feat_shapes=[(32, 128, 128)]) + batch_data_samples = get_packed_inputs(batch_size=2)['data_samples'] + + preds, _ = head.predict(feats, batch_data_samples) + + self.assertTrue(len(preds), 2) + self.assertIsInstance(preds[0], InstanceData) + self.assertEqual(preds[0].keypoints.shape, + batch_data_samples[0].gt_instances.keypoints.shape) + self.assertEqual( + preds[0].keypoint_scores.shape, + batch_data_samples[0].gt_instance_labels.keypoint_weights.shape) + + # output heatmap + head = VisPredictHead( + pose_cfg=dict( + type='HeatmapHead', + in_channels=32, + out_channels=17, + decoder=codec)) + feats = self._get_feats(batch_size=2, feat_shapes=[(32, 8, 6)]) + batch_data_samples = get_packed_inputs(batch_size=2)['data_samples'] + _, pred_heatmaps = head.predict( + feats, batch_data_samples, test_cfg=dict(output_heatmaps=True)) + + self.assertIsInstance(pred_heatmaps[0], PixelData) + self.assertEqual(pred_heatmaps[0].heatmaps.shape, (17, 64, 48)) + + def test_tta(self): + # flip test: vis and heatmap + decoder_cfg = dict( + type='MSRAHeatmap', + input_size=(192, 256), + heatmap_size=(48, 64), + sigma=2.) + + head = VisPredictHead( + pose_cfg=dict( + type='HeatmapHead', + in_channels=32, + out_channels=17, + decoder=decoder_cfg)) + + feats = self._get_feats(batch_size=2, feat_shapes=[(32, 8, 6)]) + batch_data_samples = get_packed_inputs(batch_size=2)['data_samples'] + preds, _ = head.predict([feats, feats], + batch_data_samples, + test_cfg=dict( + flip_test=True, + flip_mode='heatmap', + shift_heatmap=True, + )) + + self.assertTrue(len(preds), 2) + self.assertIsInstance(preds[0], InstanceData) + self.assertEqual(preds[0].keypoints.shape, + batch_data_samples[0].gt_instances.keypoints.shape) + self.assertEqual( + preds[0].keypoint_scores.shape, + batch_data_samples[0].gt_instance_labels.keypoint_weights.shape) + + def test_loss(self): + head = VisPredictHead( + pose_cfg=dict( + type='HeatmapHead', + in_channels=32, + out_channels=17, + )) + + feats = self._get_feats(batch_size=2, feat_shapes=[(32, 8, 6)]) + batch_data_samples = get_packed_inputs(batch_size=2)['data_samples'] + losses = head.loss(feats, batch_data_samples) + self.assertIsInstance(losses['loss_kpt'], torch.Tensor) + self.assertEqual(losses['loss_kpt'].shape, torch.Size(())) + self.assertIsInstance(losses['acc_pose'], torch.Tensor) + + self.assertIsInstance(losses['loss_vis'], torch.Tensor) + self.assertEqual(losses['loss_vis'].shape, torch.Size(())) + self.assertIsInstance(losses['acc_vis'], torch.Tensor) + + head = VisPredictHead( + pose_cfg=dict( + type='HeatmapHead', + in_channels=32, + out_channels=17, + )) + + feats = self._get_feats(batch_size=2, feat_shapes=[(32, 8, 6)]) + batch_data_samples = get_packed_inputs(batch_size=2)['data_samples'] + losses = head.loss(feats, batch_data_samples) + self.assertIsInstance(losses['loss_kpt'], torch.Tensor) + self.assertEqual(losses['loss_kpt'].shape, torch.Size(())) + self.assertIsInstance(losses['acc_pose'], torch.Tensor) + + self.assertIsInstance(losses['loss_vis'], torch.Tensor) + self.assertEqual(losses['loss_vis'].shape, torch.Size(())) + self.assertIsInstance(losses['acc_vis'], torch.Tensor) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_models/test_losses/test_heatmap_losses.py b/tests/test_models/test_losses/test_heatmap_losses.py index bfabc84749..00da170389 100644 --- a/tests/test_models/test_losses/test_heatmap_losses.py +++ b/tests/test_models/test_losses/test_heatmap_losses.py @@ -4,7 +4,8 @@ import torch from mmpose.models.losses.heatmap_loss import (AdaptiveWingLoss, - FocalHeatmapLoss) + FocalHeatmapLoss, + KeypointMSELoss) class TestAdaptiveWingLoss(TestCase): @@ -63,3 +64,56 @@ def test_loss(self): loss(fake_pred, fake_label, fake_weight), torch.tensor(5.8062), atol=1e-4)) + + +class TestKeypointMSELoss(TestCase): + + def test_loss(self): + + # test loss w/o target_weight and without mask + loss = KeypointMSELoss( + use_target_weight=False, skip_empty_channel=False) + + fake_pred = torch.zeros((1, 4, 4, 4)) + fake_label = torch.zeros((1, 4, 4, 4)) + + self.assertTrue( + torch.allclose(loss(fake_pred, fake_label), torch.tensor(0.))) + + fake_pred = torch.ones((1, 4, 4, 4)) * 0.5 + fake_label = torch.ones((1, 4, 4, 4)) * 0.5 + self.assertTrue( + torch.allclose( + loss(fake_pred, fake_label), torch.tensor(0.), atol=1e-4)) + + # test loss w/ target_weight and without mask + loss = KeypointMSELoss( + use_target_weight=True, skip_empty_channel=False) + + fake_weight = torch.ones((1, 4)).float() + self.assertTrue( + torch.allclose( + loss(fake_pred, fake_label, fake_weight), + torch.tensor(0.), + atol=1e-4)) + + # test loss w/ target_weight and with mask + loss = KeypointMSELoss( + use_target_weight=True, skip_empty_channel=False) + + fake_mask = torch.ones((1, 1, 4, 4)).float() + self.assertTrue( + torch.allclose( + loss(fake_pred, fake_label, fake_weight, fake_mask), + torch.tensor(0.), + atol=1e-4)) + + # test loss w/ target_weight and skip empty channels + loss = KeypointMSELoss(use_target_weight=True, skip_empty_channel=True) + + fake_mask = torch.ones((1, 1, 4, 4)).float() + self.assertTrue( + torch.allclose( + loss(fake_pred, fake_label, fake_weight, fake_mask), + torch.tensor(0.), + atol=1e-4)) diff --git a/tests/test_visualization/test_fast_visualizer.py b/tests/test_visualization/test_fast_visualizer.py new file mode 100644 index 0000000000..f4a24ca1f9 --- /dev/null +++ b/tests/test_visualization/test_fast_visualizer.py @@ -0,0 +1,71 @@ +# Copyright (c) OpenMMLab. All rights reserved. +from unittest import TestCase + +import numpy as np + +from mmpose.visualization import FastVisualizer + + +class TestFastVisualizer(TestCase): + + def setUp(self): + self.metainfo = { + 'keypoint_id2name': { + 0: 'nose', + 1: 'left_eye', + 2: 'right_eye' + }, + 'keypoint_name2id': { + 'nose': 0, + 'left_eye': 1, + 'right_eye': 2 + }, + 'keypoint_colors': np.array([[255, 0, 0], [0, 255, 0], [0, 0, + 255]]), + 'skeleton_links': [(0, 1), (1, 2)], + 'skeleton_link_colors': np.array([[255, 255, 0], [255, 0, 255]]) + } + self.visualizer = FastVisualizer(self.metainfo) + + def test_init(self): + self.assertEqual(self.visualizer.radius, 6) + self.assertEqual(self.visualizer.line_width, 3) + self.assertEqual(self.visualizer.kpt_thr, 0.3) + self.assertEqual(self.visualizer.keypoint_id2name, + self.metainfo['keypoint_id2name']) + self.assertEqual(self.visualizer.keypoint_name2id, + self.metainfo['keypoint_name2id']) + np.testing.assert_array_equal(self.visualizer.keypoint_colors, + self.metainfo['keypoint_colors']) + self.assertEqual(self.visualizer.skeleton_links, + self.metainfo['skeleton_links']) + np.testing.assert_array_equal(self.visualizer.skeleton_link_colors, + self.metainfo['skeleton_link_colors']) + + def test_draw_pose(self): + img = np.zeros((480, 640, 3), dtype=np.uint8) + instances = type('Instances', (object, ), {})() + instances.keypoints = np.array([[[100, 100], [200, 200], [300, 300]]], + dtype=np.float32) + instances.keypoint_scores = np.array([[0.5, 0.5, 0.5]], + dtype=np.float32) + + self.visualizer.draw_pose(img, instances) + + # Check if keypoints are drawn + self.assertNotEqual(img[100, 100].tolist(), [0, 0, 0]) + self.assertNotEqual(img[200, 200].tolist(), [0, 0, 0]) + self.assertNotEqual(img[300, 300].tolist(), [0, 0, 0]) + + # Check if skeleton links are drawn + self.assertNotEqual(img[150, 150].tolist(), [0, 0, 0]) + self.assertNotEqual(img[250, 250].tolist(), [0, 0, 0]) + + def test_draw_pose_with_none_instances(self): + img = np.zeros((480, 640, 3), dtype=np.uint8) + instances = None + + self.visualizer.draw_pose(img, instances) + + # Check if the image is still empty (black) + self.assertEqual(np.count_nonzero(img), 0) diff --git a/tools/analysis_tools/get_flops.py b/tools/analysis_tools/get_flops.py index 9325037699..bb0d65d62a 100644 --- a/tools/analysis_tools/get_flops.py +++ b/tools/analysis_tools/get_flops.py @@ -1,25 +1,26 @@ # Copyright (c) OpenMMLab. All rights reserved. import argparse -from functools import partial +import numpy as np import torch from mmengine.config import DictAction +from mmengine.logging import MMLogger from mmpose.apis.inference import init_model try: - from mmcv.cnn import get_model_complexity_info + from mmengine.analysis import get_model_complexity_info + from mmengine.analysis.print_helper import _format_size except ImportError: - raise ImportError('Please upgrade mmcv to >0.6.2') + raise ImportError('Please upgrade mmengine >= 0.6.0') def parse_args(): - parser = argparse.ArgumentParser(description='Train a recognizer') + parser = argparse.ArgumentParser( + description='Get complexity information from a model config') parser.add_argument('config', help='train config file path') parser.add_argument( - '--device', - default='cuda:0', - help='Device used for model initialization') + '--device', default='cpu', help='Device used for model initialization') parser.add_argument( '--cfg-options', nargs='+', @@ -29,28 +30,24 @@ def parse_args(): 'in xxx=yyy format will be merged into config file. For example, ' "'--cfg-options model.backbone.depth=18 model.backbone.with_cp=True'") parser.add_argument( - '--shape', + '--input-shape', type=int, nargs='+', default=[256, 192], help='input image size') parser.add_argument( - '--input-constructor', - '-c', - type=str, - choices=['none', 'batch'], - default='none', - help='If specified, it takes a callable method that generates ' - 'input. Otherwise, it will generate a random tensor with ' - 'input shape to calculate FLOPs.') - parser.add_argument( - '--batch-size', '-b', type=int, default=1, help='input batch size') + '--batch-size', + '-b', + type=int, + default=1, + help='Input batch size. If specified and greater than 1, it takes a ' + 'callable method that generates a batch input. Otherwise, it will ' + 'generate a random tensor with input shape to calculate FLOPs.') parser.add_argument( - '--not-print-per-layer-stat', - '-n', + '--show-arch-info', + '-s', action='store_true', - help='Whether to print complexity information' - 'for each layer in a model') + help='Whether to show model arch information') args = parser.parse_args() return args @@ -59,7 +56,7 @@ def batch_constructor(flops_model, batch_size, input_shape): """Generate a batch of tensors to the model.""" batch = {} - inputs = torch.ones(()).new_empty( + inputs = torch.randn(batch_size, *input_shape).new_empty( (batch_size, *input_shape), dtype=next(flops_model.parameters()).dtype, device=next(flops_model.parameters()).device) @@ -68,28 +65,13 @@ def batch_constructor(flops_model, batch_size, input_shape): return batch -def main(): - - args = parse_args() - - if len(args.shape) == 1: - input_shape = (3, args.shape[0], args.shape[0]) - elif len(args.shape) == 2: - input_shape = (3, ) + tuple(args.shape) - else: - raise ValueError('invalid input shape') - +def inference(args, input_shape, logger): model = init_model( args.config, checkpoint=None, device=args.device, cfg_options=args.cfg_options) - if args.input_constructor == 'batch': - input_constructor = partial(batch_constructor, model, args.batch_size) - else: - input_constructor = None - if hasattr(model, '_forward'): model.forward = model._forward else: @@ -97,15 +79,60 @@ def main(): 'FLOPs counter is currently not currently supported with {}'. format(model.__class__.__name__)) - flops, params = get_model_complexity_info( - model, - input_shape, - input_constructor=input_constructor, - print_per_layer_stat=(not args.not_print_per_layer_stat)) + if args.batch_size > 1: + outputs = {} + avg_flops = [] + logger.info('Running get_flops with batch size specified as {}'.format( + args.batch_size)) + batch = batch_constructor(model, args.batch_size, input_shape) + for i in range(args.batch_size): + result = get_model_complexity_info( + model, + input_shape, + inputs=batch['inputs'], + show_table=True, + show_arch=args.show_arch_info) + avg_flops.append(result['flops']) + mean_flops = _format_size(int(np.average(avg_flops))) + outputs['flops_str'] = mean_flops + outputs['params_str'] = result['params_str'] + outputs['out_table'] = result['out_table'] + outputs['out_arch'] = result['out_arch'] + else: + outputs = get_model_complexity_info( + model, + input_shape, + inputs=None, + show_table=True, + show_arch=args.show_arch_info) + return outputs + + +def main(): + args = parse_args() + logger = MMLogger.get_instance(name='MMLogger') + + if len(args.input_shape) == 1: + input_shape = (3, args.input_shape[0], args.input_shape[0]) + elif len(args.input_shape) == 2: + input_shape = (3, ) + tuple(args.input_shape) + else: + raise ValueError('invalid input shape') + + if args.device == 'cuda:0': + assert torch.cuda.is_available( + ), 'No valid cuda device detected, please double check...' + + outputs = inference(args, input_shape, logger) + flops = outputs['flops_str'] + params = outputs['params_str'] split_line = '=' * 30 input_shape = (args.batch_size, ) + input_shape print(f'{split_line}\nInput shape: {input_shape}\n' f'Flops: {flops}\nParams: {params}\n{split_line}') + print(outputs['out_table']) + if args.show_arch_info: + print(outputs['out_arch']) print('!!!Please be cautious if you use the results in papers. ' 'You may need to check if all ops are supported and verify that the ' 'flops computation is correct.') diff --git a/tools/dataset_converters/labelstudio2coco.py b/tools/dataset_converters/labelstudio2coco.py new file mode 100755 index 0000000000..12f4c61851 --- /dev/null +++ b/tools/dataset_converters/labelstudio2coco.py @@ -0,0 +1,249 @@ +# ----------------------------------------------------------------------------- +# Based on https://github.com/heartexlabs/label-studio-converter +# Original license: Copyright (c) Heartex, under the Apache 2.0 License. +# ----------------------------------------------------------------------------- + +import argparse +import io +import json +import logging +import pathlib +import xml.etree.ElementTree as ET +from datetime import datetime + +import numpy as np + +logger = logging.getLogger(__name__) + + +def parse_args(): + parser = argparse.ArgumentParser( + description='Convert Label Studio JSON file to COCO format JSON File') + parser.add_argument('config', help='Labeling Interface xml code file path') + parser.add_argument('input', help='Label Studio format JSON file path') + parser.add_argument('output', help='The output COCO format JSON file path') + args = parser.parse_args() + return args + + +class LSConverter: + + def __init__(self, config: str): + """Convert the Label Studio Format JSON file to COCO format JSON file + which is needed by mmpose. + + The annotations in label studio must follow the order: + keypoint 1, keypoint 2... keypoint n, rect of the instance, + polygon of the instance, + then annotations of the next instance. + Where the order of rect and polygon can be switched, + the bbox and area of the instance will be calculated with + the data behind. + + Only annotating one of rect and polygon is also acceptable. + Args: + config (str): The annotations config xml file. + The xml content is from Project Setting -> + Label Interface -> Code. + Example: + ``` + + + + + + + + + + ``` + """ + # get label info from config file + tree = ET.parse(config) + root = tree.getroot() + labels = root.findall('.//KeyPointLabels/Label') + label_values = [label.get('value') for label in labels] + + self.categories = list() + self.category_name_to_id = dict() + for i, value in enumerate(label_values): + # category id start with 1 + self.categories.append({'id': i + 1, 'name': value}) + self.category_name_to_id[value] = i + 1 + + def convert_to_coco(self, input_json: str, output_json: str): + """Convert `input_json` to COCO format and save in `output_json`. + + Args: + input_json (str): The path of Label Studio format JSON file. + output_json (str): The path of the output COCO JSON file. + """ + + def add_image(images, width, height, image_id, image_path): + images.append({ + 'width': width, + 'height': height, + 'id': image_id, + 'file_name': image_path, + }) + return images + + output_path = pathlib.Path(output_json) + output_path.parent.mkdir(parents=True, exist_ok=True) + + images = list() + annotations = list() + + with open(input_json, 'r') as f: + ann_list = json.load(f) + + for item_idx, item in enumerate(ann_list): + # each image is an item + image_name = item['file_upload'] + image_id = len(images) + width, height = None, None + + # skip tasks without annotations + if not item['annotations']: + logger.warning('No annotations found for item #' + + str(item_idx)) + continue + + kp_num = 0 + for i, label in enumerate(item['annotations'][0]['result']): + category_name = None + + # valid label + for key in [ + 'rectanglelabels', 'polygonlabels', 'labels', + 'keypointlabels' + ]: + if key == label['type'] and len(label['value'][key]) > 0: + category_name = label['value'][key][0] + break + + if category_name is None: + logger.warning('Unknown label type or labels are empty') + continue + + if not height or not width: + if 'original_width' not in label or \ + 'original_height' not in label: + logger.debug( + f'original_width or original_height not found' + f'in {image_name}') + continue + + # get height and width info from annotations + width, height = label['original_width'], label[ + 'original_height'] + images = add_image(images, width, height, image_id, + image_name) + + category_id = self.category_name_to_id[category_name] + + annotation_id = len(annotations) + + if 'rectanglelabels' == label['type'] or 'labels' == label[ + 'type']: + + x = label['value']['x'] + y = label['value']['y'] + w = label['value']['width'] + h = label['value']['height'] + + x = x * label['original_width'] / 100 + y = y * label['original_height'] / 100 + w = w * label['original_width'] / 100 + h = h * label['original_height'] / 100 + + # rect annotation should be later than keypoints + annotations[-1]['bbox'] = [x, y, w, h] + annotations[-1]['area'] = w * h + annotations[-1]['num_keypoints'] = kp_num + + elif 'polygonlabels' == label['type']: + points_abs = [(x / 100 * width, y / 100 * height) + for x, y in label['value']['points']] + x, y = zip(*points_abs) + + x1, y1, x2, y2 = min(x), min(y), max(x), max(y) + + # calculate bbox and area from polygon's points + # which may be different with rect annotation + bbox = [x1, y1, x2 - x1, y2 - y1] + area = float(0.5 * np.abs( + np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1)))) + + # polygon label should be later than keypoints + annotations[-1]['segmentation'] = [[ + coord for point in points_abs for coord in point + ]] + annotations[-1]['bbox'] = bbox + annotations[-1]['area'] = area + annotations[-1]['num_keypoints'] = kp_num + + elif 'keypointlabels' == label['type']: + x = label['value']['x'] * label['original_width'] / 100 + y = label['value']['y'] * label['original_height'] / 100 + + # there is no method to annotate visible in Label Studio + # so the keypoints' visible code will be 2 except (0,0) + if x == y == 0: + current_kp = [x, y, 0] + kp_num_change = 0 + else: + current_kp = [x, y, 2] + kp_num_change = 1 + + # create new annotation in coco + # when the keypoint is the first point of an instance + if i == 0 or item['annotations'][0]['result'][ + i - 1]['type'] != 'keypointlabels': + annotations.append({ + 'id': annotation_id, + 'image_id': image_id, + 'category_id': category_id, + 'keypoints': current_kp, + 'ignore': 0, + 'iscrowd': 0, + }) + kp_num = kp_num_change + else: + annotations[-1]['keypoints'].extend(current_kp) + kp_num += kp_num_change + + with io.open(output_json, mode='w', encoding='utf8') as fout: + json.dump( + { + 'images': images, + 'categories': self.categories, + 'annotations': annotations, + 'info': { + 'year': datetime.now().year, + 'version': '1.0', + 'description': '', + 'contributor': 'Label Studio', + 'url': '', + 'date_created': str(datetime.now()), + }, + }, + fout, + indent=2, + ) + + +def main(): + args = parse_args() + config = args.config + input_json = args.input + output_json = args.output + converter = LSConverter(config) + converter.convert_to_coco(input_json, output_json) + + +if __name__ == '__main__': + main() diff --git a/tools/dataset_converters/lapa2coco.py b/tools/dataset_converters/lapa2coco.py new file mode 100644 index 0000000000..1e679b6365 --- /dev/null +++ b/tools/dataset_converters/lapa2coco.py @@ -0,0 +1,111 @@ +# Copyright (c) OpenMMLab. All rights reserved. +import json +import os +import os.path as osp +import time + +import cv2 +import mmengine +import numpy as np + + +def default_dump(obj): + """Convert numpy classes to JSON serializable objects.""" + if isinstance(obj, (np.integer, np.floating, np.bool_)): + return obj.item() + elif isinstance(obj, np.ndarray): + return obj.tolist() + else: + return obj + + +def convert_labpa_to_coco(ann_dir, out_file): + annotations = [] + images = [] + cnt = 0 + + if 'trainval' in ann_dir: + ann_dir_list = ['train', 'val'] + else: + ann_dir_list = [ann_dir] + + for tv in ann_dir_list: + ann_dir = 'data/LaPa/' + tv + landmark_dir = osp.join(ann_dir, 'landmarks') + ann_list = os.listdir(landmark_dir) + + img_dir = osp.join(ann_dir, 'images') + + for idx, ann_file in enumerate(mmengine.track_iter_progress(ann_list)): + cnt += 1 + ann_path = osp.join(landmark_dir, ann_file) + file_name = ann_file[:-4] + '.jpg' + img_path = osp.join(img_dir, file_name) + data_info = open(ann_path).readlines() + + img = cv2.imread(img_path) + + keypoints = [] + for line in data_info[1:]: + x, y = line.strip().split(' ') + x, y = float(x), float(y) + keypoints.append([x, y, 2]) + keypoints = np.array(keypoints) + + x1, y1, _ = np.amin(keypoints, axis=0) + x2, y2, _ = np.amax(keypoints, axis=0) + w, h = x2 - x1, y2 - y1 + bbox = [x1, y1, w, h] + + image = {} + image['id'] = cnt + image['file_name'] = f'{tv}/images/{file_name}' + image['height'] = img.shape[0] + image['width'] = img.shape[1] + images.append(image) + + ann = {} + ann['keypoints'] = keypoints.reshape(-1).tolist() + ann['image_id'] = cnt + ann['id'] = cnt + ann['num_keypoints'] = len(keypoints) + ann['bbox'] = bbox + ann['iscrowd'] = 0 + ann['area'] = int(ann['bbox'][2] * ann['bbox'][3]) + ann['category_id'] = 1 + + annotations.append(ann) + + cocotype = {} + + cocotype['info'] = {} + cocotype['info']['description'] = 'LaPa Generated by MMPose Team' + cocotype['info']['version'] = 1.0 + cocotype['info']['year'] = time.strftime('%Y', time.localtime()) + cocotype['info']['date_created'] = time.strftime('%Y/%m/%d', + time.localtime()) + + cocotype['images'] = images + cocotype['annotations'] = annotations + cocotype['categories'] = [{ + 'supercategory': 'person', + 'id': 1, + 'name': 'face', + 'keypoints': [], + 'skeleton': [] + }] + + json.dump( + cocotype, + open(out_file, 'w'), + ensure_ascii=False, + default=default_dump) + print(f'done {out_file}') + + +if __name__ == '__main__': + if not osp.exists('data/LaPa/annotations'): + os.makedirs('data/LaPa/annotations') + for tv in ['val', 'test', 'train', 'trainval']: + print(f'processing {tv}') + convert_labpa_to_coco(tv, f'data/LaPa/annotations/lapa_{tv}.json') diff --git a/tools/dataset_converters/scripts/preprocess_300w.sh b/tools/dataset_converters/scripts/preprocess_300w.sh new file mode 100644 index 0000000000..bf405b5cc7 --- /dev/null +++ b/tools/dataset_converters/scripts/preprocess_300w.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +DOWNLOAD_DIR=$1 +DATA_ROOT=$2 + +tar -zxvf $DOWNLOAD_DIR/300w/raw/300w.tar.gz.00 -C $DOWNLOAD_DIR/ +tar -xvf $DOWNLOAD_DIR/300w/300w.tar.00 -C $DATA_ROOT/ +rm -rf $DOWNLOAD_DIR/300w diff --git a/tools/dataset_converters/scripts/preprocess_aic.sh b/tools/dataset_converters/scripts/preprocess_aic.sh new file mode 100644 index 0000000000..726a61ca26 --- /dev/null +++ b/tools/dataset_converters/scripts/preprocess_aic.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +DOWNLOAD_DIR=$1 +DATA_ROOT=$2 + +tar -zxvf $DOWNLOAD_DIR/AI_Challenger/raw/AI_Challenger.tar.gz -C $DATA_ROOT +rm -rf $DOWNLOAD_DIR/AI_Challenger diff --git a/tools/dataset_converters/scripts/preprocess_ap10k.sh b/tools/dataset_converters/scripts/preprocess_ap10k.sh new file mode 100644 index 0000000000..a4c330157b --- /dev/null +++ b/tools/dataset_converters/scripts/preprocess_ap10k.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +DOWNLOAD_DIR=$1 +DATA_ROOT=$2 + +tar -zxvf $DOWNLOAD_DIR/AP-10K/raw/AP-10K.tar.gz.00 -C $DOWNLOAD_DIR/ +tar -xvf $DOWNLOAD_DIR/AP-10K/AP-10K.tar.00 -C $DATA_ROOT/ +rm -rf $DOWNLOAD_DIR/AP-10K diff --git a/tools/dataset_converters/scripts/preprocess_coco2017.sh b/tools/dataset_converters/scripts/preprocess_coco2017.sh new file mode 100644 index 0000000000..853975e26b --- /dev/null +++ b/tools/dataset_converters/scripts/preprocess_coco2017.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +DOWNLOAD_DIR=$1 +DATA_ROOT=$2 + +unzip $DOWNLOAD_DIR/COCO_2017/raw/Images/val2017.zip -d $DATA_ROOT +unzip $DOWNLOAD_DIR/COCO_2017/raw/Images/train2017.zip -d $DATA_ROOT +unzip $DOWNLOAD_DIR/COCO_2017/raw/Annotations/annotations_trainval2017.zip -d $DATA_ROOT +rm -rf $DOWNLOAD_DIR/COCO_2017 diff --git a/tools/dataset_converters/scripts/preprocess_crowdpose.sh b/tools/dataset_converters/scripts/preprocess_crowdpose.sh new file mode 100644 index 0000000000..3215239585 --- /dev/null +++ b/tools/dataset_converters/scripts/preprocess_crowdpose.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +DOWNLOAD_DIR=$1 +DATA_ROOT=$2 + +tar -zxvf $DOWNLOAD_DIR/CrowdPose/raw/CrowdPose.tar.gz -C $DATA_ROOT +rm -rf $DOWNLOAD_DIR/CrowdPose diff --git a/tools/dataset_converters/scripts/preprocess_freihand.sh b/tools/dataset_converters/scripts/preprocess_freihand.sh new file mode 100644 index 0000000000..b3567cb5d7 --- /dev/null +++ b/tools/dataset_converters/scripts/preprocess_freihand.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +DOWNLOAD_DIR=$1 +DATA_ROOT=$2 + +tar -zxvf $DOWNLOAD_DIR/FreiHAND/raw/FreiHAND.tar.gz -C $DATA_ROOT +rm -rf $DOWNLOAD_DIR/FreiHAND diff --git a/tools/dataset_converters/scripts/preprocess_hagrid.sh b/tools/dataset_converters/scripts/preprocess_hagrid.sh new file mode 100644 index 0000000000..de2356541c --- /dev/null +++ b/tools/dataset_converters/scripts/preprocess_hagrid.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +DOWNLOAD_DIR=$1 +DATA_ROOT=$2 + +cat $DOWNLOAD_DIR/HaGRID/raw/*.tar.gz.* | tar -xvz -C $DATA_ROOT/.. +tar -xvf $DATA_ROOT/HaGRID.tar -C $DATA_ROOT/.. +rm -rf $DOWNLOAD_DIR/HaGRID diff --git a/tools/dataset_converters/scripts/preprocess_halpe.sh b/tools/dataset_converters/scripts/preprocess_halpe.sh new file mode 100644 index 0000000000..103d6202f9 --- /dev/null +++ b/tools/dataset_converters/scripts/preprocess_halpe.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +DOWNLOAD_DIR=$1 +DATA_ROOT=$2 + +tar -zxvf $DOWNLOAD_DIR/Halpe/raw/Halpe.tar.gz.00 -C $DOWNLOAD_DIR/ +tar -xvf $DOWNLOAD_DIR/Halpe/Halpe.tar.00 -C $DATA_ROOT/ +rm -rf $DOWNLOAD_DIR/Halpe diff --git a/tools/dataset_converters/scripts/preprocess_lapa.sh b/tools/dataset_converters/scripts/preprocess_lapa.sh new file mode 100644 index 0000000000..977442c1b8 --- /dev/null +++ b/tools/dataset_converters/scripts/preprocess_lapa.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +DOWNLOAD_DIR=$1 +DATA_ROOT=$2 + +tar -zxvf $DOWNLOAD_DIR/LaPa/raw/LaPa.tar.gz -C $DATA_ROOT +rm -rf $DOWNLOAD_DIR/LaPa diff --git a/tools/dataset_converters/scripts/preprocess_mpii.sh b/tools/dataset_converters/scripts/preprocess_mpii.sh new file mode 100644 index 0000000000..287b431897 --- /dev/null +++ b/tools/dataset_converters/scripts/preprocess_mpii.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +DOWNLOAD_DIR=$1 +DATA_ROOT=$2 + +tar -zxvf $DOWNLOAD_DIR/MPII_Human_Pose/raw/MPII_Human_Pose.tar.gz -C $DATA_ROOT +rm -rf $DOWNLOAD_DIR/MPII_Human_Pose diff --git a/tools/dataset_converters/scripts/preprocess_onehand10k.sh b/tools/dataset_converters/scripts/preprocess_onehand10k.sh new file mode 100644 index 0000000000..47f6e8942c --- /dev/null +++ b/tools/dataset_converters/scripts/preprocess_onehand10k.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +DOWNLOAD_DIR=$1 +DATA_ROOT=$2 + +tar -zxvf $DOWNLOAD_DIR/OneHand10K/raw/OneHand10K.tar.gz.00 -C $DOWNLOAD_DIR/ +tar -xvf $DOWNLOAD_DIR/OneHand10K/OneHand10K.tar.00 -C $DATA_ROOT/ +rm -rf $DOWNLOAD_DIR/OneHand10K diff --git a/tools/dataset_converters/scripts/preprocess_wflw.sh b/tools/dataset_converters/scripts/preprocess_wflw.sh new file mode 100644 index 0000000000..723d1d158e --- /dev/null +++ b/tools/dataset_converters/scripts/preprocess_wflw.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +DOWNLOAD_DIR=$1 +DATA_ROOT=$2 + +tar -zxvf $DOWNLOAD_DIR/WFLW/raw/WFLW.tar.gz.00 -C $DOWNLOAD_DIR/ +tar -xvf $DOWNLOAD_DIR/WFLW/WFLW.tar.00 -C $DATA_ROOT/ +rm -rf $DOWNLOAD_DIR/WFLW diff --git a/tools/dist_train.sh b/tools/dist_train.sh old mode 100644 new mode 100755 diff --git a/tools/misc/browse_dataset.py b/tools/misc/browse_dataset.py index 2ac50e1167..5a914476ee 100644 --- a/tools/misc/browse_dataset.py +++ b/tools/misc/browse_dataset.py @@ -83,7 +83,9 @@ def main(): backend_args = cfg.get('backend_args', dict(backend='local')) # register all modules in mmpose into the registries - init_default_scope(cfg.get('default_scope', 'mmpose')) + scope = cfg.get('default_scope', 'mmpose') + if scope is not None: + init_default_scope(scope) if args.mode == 'original': cfg[f'{args.phase}_dataloader'].dataset.pipeline = [] diff --git a/tools/misc/publish_model.py b/tools/misc/publish_model.py index 4a8338fdbd..addf4cca64 100644 --- a/tools/misc/publish_model.py +++ b/tools/misc/publish_model.py @@ -41,7 +41,7 @@ def process_checkpoint(in_file, out_file, save_keys=['meta', 'state_dict']): # if it is necessary to remove some sensitive data in checkpoint['meta'], # add the code here. - if digit_version(TORCH_VERSION) >= digit_version('1.6.0'): + if digit_version(TORCH_VERSION) >= digit_version('1.8.0'): torch.save(checkpoint, out_file, _use_new_zipfile_serialization=False) else: torch.save(checkpoint, out_file) diff --git a/tools/test.py b/tools/test.py index 3a22ae78c5..5dc0110260 100644 --- a/tools/test.py +++ b/tools/test.py @@ -60,6 +60,20 @@ def parse_args(): def merge_args(cfg, args): """Merge CLI arguments to config.""" + + cfg.launcher = args.launcher + cfg.load_from = args.checkpoint + + # -------------------- work directory -------------------- + # work_dir is determined in this priority: CLI > segment in file > filename + if args.work_dir is not None: + # update configs according to CLI args if args.work_dir is not None + cfg.work_dir = args.work_dir + elif cfg.get('work_dir', None) is None: + # use config filename as default work_dir if cfg.work_dir is None + cfg.work_dir = osp.join('./work_dirs', + osp.splitext(osp.basename(args.config))[0]) + # -------------------- visualization -------------------- if args.show or (args.show_dir is not None): assert 'visualization' in cfg.default_hooks, \ @@ -80,10 +94,14 @@ def merge_args(cfg, args): 'The dump file must be a pkl file.' dump_metric = dict(type='DumpResults', out_file_path=args.dump) if isinstance(cfg.test_evaluator, (list, tuple)): - cfg.test_evaluator = list(cfg.test_evaluator).append(dump_metric) + cfg.test_evaluator = [*cfg.test_evaluator, dump_metric] else: cfg.test_evaluator = [cfg.test_evaluator, dump_metric] + # -------------------- Other arguments -------------------- + if args.cfg_options is not None: + cfg.merge_from_dict(args.cfg_options) + return cfg @@ -93,20 +111,6 @@ def main(): # load config cfg = Config.fromfile(args.config) cfg = merge_args(cfg, args) - cfg.launcher = args.launcher - if args.cfg_options is not None: - cfg.merge_from_dict(args.cfg_options) - - # work_dir is determined in this priority: CLI > segment in file > filename - if args.work_dir is not None: - # update configs according to CLI args if args.work_dir is not None - cfg.work_dir = args.work_dir - elif cfg.get('work_dir', None) is None: - # use config filename as default work_dir if cfg.work_dir is None - cfg.work_dir = osp.join('./work_dirs', - osp.splitext(osp.basename(args.config))[0]) - - cfg.load_from = args.checkpoint # build the runner from config runner = Runner.from_cfg(cfg) diff --git a/tools/train.py b/tools/train.py index e086d95d73..1fd423ad3f 100644 --- a/tools/train.py +++ b/tools/train.py @@ -96,8 +96,9 @@ def merge_args(cfg, args): # enable automatic-mixed-precision training if args.amp is True: - optim_wrapper = cfg.optim_wrapper.get('type', 'OptimWrapper') - assert optim_wrapper in ['OptimWrapper', 'AmpOptimWrapper'], \ + from mmengine.optim import AmpOptimWrapper, OptimWrapper + optim_wrapper = cfg.optim_wrapper.get('type', OptimWrapper) + assert optim_wrapper in (OptimWrapper, AmpOptimWrapper), \ '`--amp` is not supported custom optimizer wrapper type ' \ f'`{optim_wrapper}.' cfg.optim_wrapper.type = 'AmpOptimWrapper' @@ -115,7 +116,7 @@ def merge_args(cfg, args): if args.auto_scale_lr: cfg.auto_scale_lr.enable = True - # visualization- + # visualization if args.show or (args.show_dir is not None): assert 'visualization' in cfg.default_hooks, \ 'PoseVisualizationHook is not set in the ' \